diff --git a/Documentation/devicetree/bindings/regulator/regulator-max77620.txt b/Documentation/devicetree/bindings/regulator/regulator-max77620.txt new file mode 100644 index 000000000000..b3c8ca672024 --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/regulator-max77620.txt @@ -0,0 +1,200 @@ +Regulator DT binding for MAX77620 Power management IC from Maxim Semiconductor. + +Device has multiple DCDC(sd[0-3] and LDOs(ldo[0-8]). The input supply +of these regulators are defined under parent device node. +Details of regulator properties are defined as child node under +sub-node "regulators" which is child node of device node. + +Please refer file +for common regulator bindings used by client. + +Following are properties of parent node related to regulators. + +Optional properties: +------------------- +The input supply of regulators are the optional properties on the +parent device node. The input supply of these regulators are provided +through following properties: +in-sd0-supply: Input supply for SD0, INA-SD0 or INB-SD0 pins. +in-sd1-supply: Input supply for SD1. +in-sd2-supply: Input supply for SD2. +in-sd3-supply: Input supply for SD3. +in-ldo0-1-supply: Input supply for LDO0 and LDO1. +in-ldo2-supply: Input supply for LDO2. +in-ldo3-5-supply: Input supply for LDO3 and LDO5 +in-ldo4-6-supply: Input supply for LDO4 and LDO6. +in-ldo7-8-supply: Input supply for LDO7 and LDO8. + +Optional sub nodes for regulators under "regulators" subnode: +------------------------------------------------------------ +The subnodes name is the name of regulator and it must be one of: + sd[0-3], ldo[0-8] + +Each sub-node should contain the constraints and initialization +information for that regulator. The definition for each of these +nodes is defined using the standard binding for regulators found at +. + +Theres are also additional properties for SD/LDOs. These additional properties +are required to configure FPS configuration parameters for SDs and LDOs. +Please refer for more detail of Flexible +Power Sequence (FPS). +Following are additional properties: + +- maxim,active-fps-source: FPS source for the regulators to get + enabled/disabled when system is in + active state. Valid values are: + - MAX77620_FPS_SRC_0, + FPS source is FPS0. + - MAX77620_FPS_SRC_1, + FPS source is FPS1 + - MAX77620_FPS_SRC_2 and + FPS source is FPS2 + - MAX77620_FPS_SRC_NONE. + Regulator is not controlled + by FPS events and it gets + enabled/disabled by register + access. + Absence of this property will leave + the FPS configuration register for that + regulator to default configuration. + +- maxim,active-fps-power-up-slot: Sequencing event slot number on which + the regulator get enabled when + master FPS input event set to HIGH. + Valid values are 0 to 7. + This is applicable if FPS source is + selected as FPS0, FPS1 or FPS2. + +- maxim,active-fps-power-down-slot: Sequencing event slot number on which + the regulator get disabled when master + FPS input event set to LOW. + Valid values are 0 to 7. + This is applicable if FPS source is + selected as FPS0, FPS1 or FPS2. + +- maxim,suspend-fps-source: This is same as property + "maxim,active-fps-source" but value + get configured when system enters in + to suspend state. + +- maxim,suspend-fps-power-up-slot: This is same as property + "maxim,active-fps-power-up-slot" but + this value get configured into FPS + configuration register when system + enters into suspend. + This is applicable if suspend state + FPS source is selected as FPS0, FPS1 or + +- maxim,suspend-fps-power-down-slot: This is same as property + "maxim,active-fps-power-down-slot" but + this value get configured into FPS + configuration register when system + enters into suspend. + This is applicable if suspend state + FPS source is selected as FPS0, FPS1 or + FPS2. + +Example: +-------- +#include +... +max77620@3c { + in-ldo0-1-supply = <&max77620_sd2>; + in-ldo7-8-supply = <&max77620_sd2>; + regulators { + sd0 { + regulator-name = "vdd-core"; + regulator-min-microvolt = <600000>; + regulator-max-microvolt = <1400000>; + regulator-boot-on; + regulator-always-on; + maxim,active-fps-source = ; + }; + + sd1 { + regulator-name = "vddio-ddr"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-always-on; + regulator-boot-on; + maxim,active-fps-source = ; + }; + + sd2 { + regulator-name = "vdd-pre-reg"; + regulator-min-microvolt = <1350000>; + regulator-max-microvolt = <1350000>; + }; + + sd3 { + regulator-name = "vdd-1v8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + regulator-boot-on; + }; + + ldo0 { + regulator-name = "avdd-sys"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-always-on; + regulator-boot-on; + }; + + ldo1 { + regulator-name = "vdd-pex"; + regulator-min-microvolt = <1050000>; + regulator-max-microvolt = <1050000>; + }; + + ldo2 { + regulator-name = "vddio-sdmmc3"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + }; + + ldo3 { + regulator-name = "vdd-cam-hv"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + }; + + ldo4 { + regulator-name = "vdd-rtc"; + regulator-min-microvolt = <1250000>; + regulator-max-microvolt = <1250000>; + regulator-always-on; + regulator-boot-on; + }; + + ldo5 { + regulator-name = "avdd-ts-hv"; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3000000>; + }; + + ldo6 { + regulator-name = "vdd-ts"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + regulator-boot-on; + }; + + ldo7 { + regulator-name = "vdd-gen-pll-edp"; + regulator-min-microvolt = <1050000>; + regulator-max-microvolt = <1050000>; + regulator-always-on; + regulator-boot-on; + }; + + ldo8 { + regulator-name = "vdd-hdmi-dp"; + regulator-min-microvolt = <1050000>; + regulator-max-microvolt = <1050000>; + }; + }; +}; diff --git a/MAINTAINERS b/MAINTAINERS index f5e6a535bc34..a915a32be22b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6899,7 +6899,7 @@ MAXIM MAX77802 MULTIFUNCTION PMIC DEVICE DRIVERS M: Javier Martinez Canillas L: linux-kernel@vger.kernel.org S: Supported -F: drivers/*/*max77802.c +F: drivers/*/*max77802*.c F: Documentation/devicetree/bindings/*/*max77802.txt F: include/dt-bindings/*/*max77802.h @@ -6909,7 +6909,7 @@ M: Krzysztof Kozlowski L: linux-kernel@vger.kernel.org S: Supported F: drivers/*/max14577.c -F: drivers/*/max77686.c +F: drivers/*/max77686*.c F: drivers/*/max77693.c F: drivers/extcon/extcon-max14577.c F: drivers/extcon/extcon-max77693.c diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 39b422b97ec0..91040ec8e242 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -360,6 +360,15 @@ config REGULATOR_MAX1586 regulator via I2C bus. The provided regulator is suitable for PXA27x chips to control VCC_CORE and VCC_USIM voltages. +config REGULATOR_MAX77620 + tristate "Maxim 77620/MAX20024 voltage regulator" + depends on MFD_MAX77620 + help + This driver controls Maxim MAX77620 voltage output regulator + via I2C bus. The provided regulator is suitable for Tegra + chip to control Step-Down DC-DC and LDOs. Say Y here to + enable the regulator driver. + config REGULATOR_MAX8649 tristate "Maxim 8649 voltage regulator" depends on I2C diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index bba7b7093bac..a78d8bf27358 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -48,6 +48,7 @@ obj-$(CONFIG_REGULATOR_LP8755) += lp8755.o obj-$(CONFIG_REGULATOR_LTC3589) += ltc3589.o obj-$(CONFIG_REGULATOR_MAX14577) += max14577.o obj-$(CONFIG_REGULATOR_MAX1586) += max1586.o +obj-$(CONFIG_REGULATOR_MAX77620) += max77620-regulator.o obj-$(CONFIG_REGULATOR_MAX8649) += max8649.o obj-$(CONFIG_REGULATOR_MAX8660) += max8660.o obj-$(CONFIG_REGULATOR_MAX8907) += max8907-regulator.o @@ -56,9 +57,9 @@ obj-$(CONFIG_REGULATOR_MAX8952) += max8952.o obj-$(CONFIG_REGULATOR_MAX8973) += max8973-regulator.o obj-$(CONFIG_REGULATOR_MAX8997) += max8997.o obj-$(CONFIG_REGULATOR_MAX8998) += max8998.o -obj-$(CONFIG_REGULATOR_MAX77686) += max77686.o +obj-$(CONFIG_REGULATOR_MAX77686) += max77686-regulator.o obj-$(CONFIG_REGULATOR_MAX77693) += max77693.o -obj-$(CONFIG_REGULATOR_MAX77802) += max77802.o +obj-$(CONFIG_REGULATOR_MAX77802) += max77802-regulator.o obj-$(CONFIG_REGULATOR_MC13783) += mc13783-regulator.o obj-$(CONFIG_REGULATOR_MC13892) += mc13892-regulator.o obj-$(CONFIG_REGULATOR_MC13XXX_CORE) += mc13xxx-regulator-core.o diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 1cff11205642..e0b764284773 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -1150,6 +1150,17 @@ static int set_machine_constraints(struct regulator_dev *rdev, } } + if (rdev->constraints->active_discharge && ops->set_active_discharge) { + bool ad_state = (rdev->constraints->active_discharge == + REGULATOR_ACTIVE_DISCHARGE_ENABLE) ? true : false; + + ret = ops->set_active_discharge(rdev, ad_state); + if (ret < 0) { + rdev_err(rdev, "failed to set active discharge\n"); + return ret; + } + } + print_constraints(rdev); return 0; } diff --git a/drivers/regulator/ltc3589.c b/drivers/regulator/ltc3589.c index 972c386b2690..47bef328fb58 100644 --- a/drivers/regulator/ltc3589.c +++ b/drivers/regulator/ltc3589.c @@ -520,12 +520,15 @@ static int ltc3589_probe(struct i2c_client *client, } } - ret = devm_request_threaded_irq(dev, client->irq, NULL, ltc3589_isr, - IRQF_TRIGGER_LOW | IRQF_ONESHOT, - client->name, ltc3589); - if (ret) { - dev_err(dev, "Failed to request IRQ: %d\n", ret); - return ret; + if (client->irq) { + ret = devm_request_threaded_irq(dev, client->irq, NULL, + ltc3589_isr, + IRQF_TRIGGER_LOW | IRQF_ONESHOT, + client->name, ltc3589); + if (ret) { + dev_err(dev, "Failed to request IRQ: %d\n", ret); + return ret; + } } return 0; diff --git a/drivers/regulator/max77620-regulator.c b/drivers/regulator/max77620-regulator.c new file mode 100644 index 000000000000..73a3356a5c19 --- /dev/null +++ b/drivers/regulator/max77620-regulator.c @@ -0,0 +1,813 @@ +/* + * Maxim MAX77620 Regulator driver + * + * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved. + * + * Author: Mallikarjun Kasoju + * Laxman Dewangan + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define max77620_rails(_name) "max77620-"#_name + +/* Power Mode */ +#define MAX77620_POWER_MODE_NORMAL 3 +#define MAX77620_POWER_MODE_LPM 2 +#define MAX77620_POWER_MODE_GLPM 1 +#define MAX77620_POWER_MODE_DISABLE 0 + +/* SD Slew Rate */ +#define MAX77620_SD_SR_13_75 0 +#define MAX77620_SD_SR_27_5 1 +#define MAX77620_SD_SR_55 2 +#define MAX77620_SD_SR_100 3 + +enum max77620_regulators { + MAX77620_REGULATOR_ID_SD0, + MAX77620_REGULATOR_ID_SD1, + MAX77620_REGULATOR_ID_SD2, + MAX77620_REGULATOR_ID_SD3, + MAX77620_REGULATOR_ID_SD4, + MAX77620_REGULATOR_ID_LDO0, + MAX77620_REGULATOR_ID_LDO1, + MAX77620_REGULATOR_ID_LDO2, + MAX77620_REGULATOR_ID_LDO3, + MAX77620_REGULATOR_ID_LDO4, + MAX77620_REGULATOR_ID_LDO5, + MAX77620_REGULATOR_ID_LDO6, + MAX77620_REGULATOR_ID_LDO7, + MAX77620_REGULATOR_ID_LDO8, + MAX77620_NUM_REGS, +}; + +/* Regulator types */ +enum max77620_regulator_type { + MAX77620_REGULATOR_TYPE_SD, + MAX77620_REGULATOR_TYPE_LDO_N, + MAX77620_REGULATOR_TYPE_LDO_P, +}; + +struct max77620_regulator_info { + u8 type; + u8 fps_addr; + u8 volt_addr; + u8 cfg_addr; + u8 power_mode_mask; + u8 power_mode_shift; + u8 remote_sense_addr; + u8 remote_sense_mask; + struct regulator_desc desc; +}; + +struct max77620_regulator_pdata { + struct regulator_init_data *reg_idata; + int active_fps_src; + int active_fps_pd_slot; + int active_fps_pu_slot; + int suspend_fps_src; + int suspend_fps_pd_slot; + int suspend_fps_pu_slot; + int current_mode; +}; + +struct max77620_regulator { + struct device *dev; + struct regmap *rmap; + struct max77620_regulator_info *rinfo[MAX77620_NUM_REGS]; + struct max77620_regulator_pdata reg_pdata[MAX77620_NUM_REGS]; + int enable_power_mode[MAX77620_NUM_REGS]; + int current_power_mode[MAX77620_NUM_REGS]; + int active_fps_src[MAX77620_NUM_REGS]; +}; + +#define fps_src_name(fps_src) \ + (fps_src == MAX77620_FPS_SRC_0 ? "FPS_SRC_0" : \ + fps_src == MAX77620_FPS_SRC_1 ? "FPS_SRC_1" : \ + fps_src == MAX77620_FPS_SRC_2 ? "FPS_SRC_2" : "FPS_SRC_NONE") + +static int max77620_regulator_get_fps_src(struct max77620_regulator *pmic, + int id) +{ + struct max77620_regulator_info *rinfo = pmic->rinfo[id]; + unsigned int val; + int ret; + + ret = regmap_read(pmic->rmap, rinfo->fps_addr, &val); + if (ret < 0) { + dev_err(pmic->dev, "Reg 0x%02x read failed %d\n", + rinfo->fps_addr, ret); + return ret; + } + + return (val & MAX77620_FPS_SRC_MASK) >> MAX77620_FPS_SRC_SHIFT; +} + +static int max77620_regulator_set_fps_src(struct max77620_regulator *pmic, + int fps_src, int id) +{ + struct max77620_regulator_info *rinfo = pmic->rinfo[id]; + unsigned int val; + int ret; + + switch (fps_src) { + case MAX77620_FPS_SRC_0: + case MAX77620_FPS_SRC_1: + case MAX77620_FPS_SRC_2: + case MAX77620_FPS_SRC_NONE: + break; + + case MAX77620_FPS_SRC_DEF: + ret = regmap_read(pmic->rmap, rinfo->fps_addr, &val); + if (ret < 0) { + dev_err(pmic->dev, "Reg 0x%02x read failed %d\n", + rinfo->fps_addr, ret); + return ret; + } + ret = (val & MAX77620_FPS_SRC_MASK) >> MAX77620_FPS_SRC_SHIFT; + pmic->active_fps_src[id] = ret; + return 0; + + default: + dev_err(pmic->dev, "Invalid FPS %d for regulator %d\n", + fps_src, id); + return -EINVAL; + } + + ret = regmap_update_bits(pmic->rmap, rinfo->fps_addr, + MAX77620_FPS_SRC_MASK, + fps_src << MAX77620_FPS_SRC_SHIFT); + if (ret < 0) { + dev_err(pmic->dev, "Reg 0x%02x update failed %d\n", + rinfo->fps_addr, ret); + return ret; + } + pmic->active_fps_src[id] = fps_src; + + return 0; +} + +static int max77620_regulator_set_fps_slots(struct max77620_regulator *pmic, + int id, bool is_suspend) +{ + struct max77620_regulator_pdata *rpdata = &pmic->reg_pdata[id]; + struct max77620_regulator_info *rinfo = pmic->rinfo[id]; + unsigned int val = 0; + unsigned int mask = 0; + int pu = rpdata->active_fps_pu_slot; + int pd = rpdata->active_fps_pd_slot; + int ret = 0; + + if (is_suspend) { + pu = rpdata->suspend_fps_pu_slot; + pd = rpdata->suspend_fps_pd_slot; + } + + /* FPS power up period setting */ + if (pu >= 0) { + val |= (pu << MAX77620_FPS_PU_PERIOD_SHIFT); + mask |= MAX77620_FPS_PU_PERIOD_MASK; + } + + /* FPS power down period setting */ + if (pd >= 0) { + val |= (pd << MAX77620_FPS_PD_PERIOD_SHIFT); + mask |= MAX77620_FPS_PD_PERIOD_MASK; + } + + if (mask) { + ret = regmap_update_bits(pmic->rmap, rinfo->fps_addr, + mask, val); + if (ret < 0) { + dev_err(pmic->dev, "Reg 0x%02x update failed: %d\n", + rinfo->fps_addr, ret); + return ret; + } + } + + return ret; +} + +static int max77620_regulator_set_power_mode(struct max77620_regulator *pmic, + int power_mode, int id) +{ + struct max77620_regulator_info *rinfo = pmic->rinfo[id]; + u8 mask = rinfo->power_mode_mask; + u8 shift = rinfo->power_mode_shift; + u8 addr; + int ret; + + switch (rinfo->type) { + case MAX77620_REGULATOR_TYPE_SD: + addr = rinfo->cfg_addr; + break; + default: + addr = rinfo->volt_addr; + break; + } + + ret = regmap_update_bits(pmic->rmap, addr, mask, power_mode << shift); + if (ret < 0) { + dev_err(pmic->dev, "Regulator %d mode set failed: %d\n", + id, ret); + return ret; + } + pmic->current_power_mode[id] = power_mode; + + return ret; +} + +static int max77620_regulator_get_power_mode(struct max77620_regulator *pmic, + int id) +{ + struct max77620_regulator_info *rinfo = pmic->rinfo[id]; + unsigned int val, addr; + u8 mask = rinfo->power_mode_mask; + u8 shift = rinfo->power_mode_shift; + int ret; + + switch (rinfo->type) { + case MAX77620_REGULATOR_TYPE_SD: + addr = rinfo->cfg_addr; + break; + default: + addr = rinfo->volt_addr; + break; + } + + ret = regmap_read(pmic->rmap, addr, &val); + if (ret < 0) { + dev_err(pmic->dev, "Regulator %d: Reg 0x%02x read failed: %d\n", + id, addr, ret); + return ret; + } + + return (val & mask) >> shift; +} + +static int max77620_read_slew_rate(struct max77620_regulator *pmic, int id) +{ + struct max77620_regulator_info *rinfo = pmic->rinfo[id]; + unsigned int rval; + int slew_rate; + int ret; + + ret = regmap_read(pmic->rmap, rinfo->cfg_addr, &rval); + if (ret < 0) { + dev_err(pmic->dev, "Register 0x%02x read failed: %d\n", + rinfo->cfg_addr, ret); + return ret; + } + + switch (rinfo->type) { + case MAX77620_REGULATOR_TYPE_SD: + slew_rate = (rval >> MAX77620_SD_SR_SHIFT) & 0x3; + switch (slew_rate) { + case 0: + slew_rate = 13750; + break; + case 1: + slew_rate = 27500; + break; + case 2: + slew_rate = 55000; + break; + case 3: + slew_rate = 100000; + break; + } + rinfo->desc.ramp_delay = slew_rate; + break; + default: + slew_rate = rval & 0x1; + switch (slew_rate) { + case 0: + slew_rate = 100000; + break; + case 1: + slew_rate = 5000; + break; + } + rinfo->desc.ramp_delay = slew_rate; + break; + } + + return 0; +} + +static int max77620_init_pmic(struct max77620_regulator *pmic, int id) +{ + struct max77620_regulator_pdata *rpdata = &pmic->reg_pdata[id]; + int ret; + + /* Update power mode */ + ret = max77620_regulator_get_power_mode(pmic, id); + if (ret < 0) + return ret; + + pmic->current_power_mode[id] = ret; + pmic->enable_power_mode[id] = MAX77620_POWER_MODE_NORMAL; + + if (rpdata->active_fps_src == MAX77620_FPS_SRC_DEF) { + ret = max77620_regulator_get_fps_src(pmic, id); + if (ret < 0) + return ret; + rpdata->active_fps_src = ret; + } + + /* If rails are externally control of FPS then enable it always. */ + if (rpdata->active_fps_src == MAX77620_FPS_SRC_NONE) { + ret = max77620_regulator_set_power_mode(pmic, + pmic->enable_power_mode[id], id); + if (ret < 0) + return ret; + } else { + if (pmic->current_power_mode[id] != + pmic->enable_power_mode[id]) { + ret = max77620_regulator_set_power_mode(pmic, + pmic->enable_power_mode[id], id); + if (ret < 0) + return ret; + } + } + + ret = max77620_regulator_set_fps_src(pmic, rpdata->active_fps_src, id); + if (ret < 0) + return ret; + + ret = max77620_regulator_set_fps_slots(pmic, id, false); + if (ret < 0) + return ret; + + return 0; +} + +static int max77620_regulator_enable(struct regulator_dev *rdev) +{ + struct max77620_regulator *pmic = rdev_get_drvdata(rdev); + int id = rdev_get_id(rdev); + + if (pmic->active_fps_src[id] != MAX77620_FPS_SRC_NONE) + return 0; + + return max77620_regulator_set_power_mode(pmic, + pmic->enable_power_mode[id], id); +} + +static int max77620_regulator_disable(struct regulator_dev *rdev) +{ + struct max77620_regulator *pmic = rdev_get_drvdata(rdev); + int id = rdev_get_id(rdev); + + if (pmic->active_fps_src[id] != MAX77620_FPS_SRC_NONE) + return 0; + + return max77620_regulator_set_power_mode(pmic, + MAX77620_POWER_MODE_DISABLE, id); +} + +static int max77620_regulator_is_enabled(struct regulator_dev *rdev) +{ + struct max77620_regulator *pmic = rdev_get_drvdata(rdev); + int id = rdev_get_id(rdev); + int ret = 1; + + if (pmic->active_fps_src[id] != MAX77620_FPS_SRC_NONE) + return 1; + + ret = max77620_regulator_get_power_mode(pmic, id); + if (ret < 0) + return ret; + + if (ret != MAX77620_POWER_MODE_DISABLE) + return 1; + + return 0; +} + +static int max77620_regulator_set_mode(struct regulator_dev *rdev, + unsigned int mode) +{ + struct max77620_regulator *pmic = rdev_get_drvdata(rdev); + int id = rdev_get_id(rdev); + struct max77620_regulator_info *rinfo = pmic->rinfo[id]; + struct max77620_regulator_pdata *rpdata = &pmic->reg_pdata[id]; + bool fpwm = false; + int power_mode; + int ret; + u8 val; + + switch (mode) { + case REGULATOR_MODE_FAST: + fpwm = true; + power_mode = MAX77620_POWER_MODE_NORMAL; + break; + + case REGULATOR_MODE_NORMAL: + power_mode = MAX77620_POWER_MODE_NORMAL; + break; + + case REGULATOR_MODE_IDLE: + power_mode = MAX77620_POWER_MODE_LPM; + break; + + default: + dev_err(pmic->dev, "Regulator %d mode %d is invalid\n", + id, mode); + return -EINVAL; + } + + if (rinfo->type != MAX77620_REGULATOR_TYPE_SD) + goto skip_fpwm; + + val = (fpwm) ? MAX77620_SD_FPWM_MASK : 0; + ret = regmap_update_bits(pmic->rmap, rinfo->cfg_addr, + MAX77620_SD_FPWM_MASK, val); + if (ret < 0) { + dev_err(pmic->dev, "Reg 0x%02x update failed: %d\n", + rinfo->cfg_addr, ret); + return ret; + } + rpdata->current_mode = mode; + +skip_fpwm: + ret = max77620_regulator_set_power_mode(pmic, power_mode, id); + if (ret < 0) + return ret; + + pmic->enable_power_mode[id] = power_mode; + + return 0; +} + +static unsigned int max77620_regulator_get_mode(struct regulator_dev *rdev) +{ + struct max77620_regulator *pmic = rdev_get_drvdata(rdev); + int id = rdev_get_id(rdev); + struct max77620_regulator_info *rinfo = pmic->rinfo[id]; + int fpwm = 0; + int ret; + int pm_mode, reg_mode; + unsigned int val; + + ret = max77620_regulator_get_power_mode(pmic, id); + if (ret < 0) + return 0; + + pm_mode = ret; + + if (rinfo->type == MAX77620_REGULATOR_TYPE_SD) { + ret = regmap_read(pmic->rmap, rinfo->cfg_addr, &val); + if (ret < 0) { + dev_err(pmic->dev, "Reg 0x%02x read failed: %d\n", + rinfo->cfg_addr, ret); + return ret; + } + fpwm = !!(val & MAX77620_SD_FPWM_MASK); + } + + switch (pm_mode) { + case MAX77620_POWER_MODE_NORMAL: + case MAX77620_POWER_MODE_DISABLE: + if (fpwm) + reg_mode = REGULATOR_MODE_FAST; + else + reg_mode = REGULATOR_MODE_NORMAL; + break; + case MAX77620_POWER_MODE_LPM: + case MAX77620_POWER_MODE_GLPM: + reg_mode = REGULATOR_MODE_IDLE; + break; + default: + return 0; + } + + return reg_mode; +} + +static int max77620_regulator_set_ramp_delay(struct regulator_dev *rdev, + int ramp_delay) +{ + struct max77620_regulator *pmic = rdev_get_drvdata(rdev); + int id = rdev_get_id(rdev); + struct max77620_regulator_info *rinfo = pmic->rinfo[id]; + int ret, val; + u8 mask; + + if (rinfo->type == MAX77620_REGULATOR_TYPE_SD) { + if (ramp_delay <= 13750) + val = 0; + else if (ramp_delay <= 27500) + val = 1; + else if (ramp_delay <= 55000) + val = 2; + else + val = 3; + val <<= MAX77620_SD_SR_SHIFT; + mask = MAX77620_SD_SR_MASK; + } else { + if (ramp_delay <= 5000) + val = 1; + else + val = 0; + mask = MAX77620_LDO_SLEW_RATE_MASK; + } + + ret = regmap_update_bits(pmic->rmap, rinfo->cfg_addr, mask, val); + if (ret < 0) + dev_err(pmic->dev, "Reg 0x%02x update failed: %d\n", + rinfo->cfg_addr, ret); + + return ret; +} + +static int max77620_of_parse_cb(struct device_node *np, + const struct regulator_desc *desc, + struct regulator_config *config) +{ + struct max77620_regulator *pmic = config->driver_data; + struct max77620_regulator_pdata *rpdata = &pmic->reg_pdata[desc->id]; + u32 pval; + int ret; + + ret = of_property_read_u32(np, "maxim,active-fps-source", &pval); + rpdata->active_fps_src = (!ret) ? pval : MAX77620_FPS_SRC_DEF; + + ret = of_property_read_u32(np, "maxim,active-fps-power-up-slot", &pval); + rpdata->active_fps_pu_slot = (!ret) ? pval : -1; + + ret = of_property_read_u32( + np, "maxim,active-fps-power-down-slot", &pval); + rpdata->active_fps_pd_slot = (!ret) ? pval : -1; + + ret = of_property_read_u32(np, "maxim,suspend-fps-source", &pval); + rpdata->suspend_fps_src = (!ret) ? pval : -1; + + ret = of_property_read_u32( + np, "maxim,suspend-fps-power-up-slot", &pval); + rpdata->suspend_fps_pu_slot = (!ret) ? pval : -1; + + ret = of_property_read_u32( + np, "maxim,suspend-fps-power-down-slot", &pval); + rpdata->suspend_fps_pd_slot = (!ret) ? pval : -1; + + return max77620_init_pmic(pmic, desc->id); +} + +static struct regulator_ops max77620_regulator_ops = { + .is_enabled = max77620_regulator_is_enabled, + .enable = max77620_regulator_enable, + .disable = max77620_regulator_disable, + .list_voltage = regulator_list_voltage_linear, + .map_voltage = regulator_map_voltage_linear, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .set_mode = max77620_regulator_set_mode, + .get_mode = max77620_regulator_get_mode, + .set_ramp_delay = max77620_regulator_set_ramp_delay, + .set_voltage_time_sel = regulator_set_voltage_time_sel, + .set_active_discharge = regulator_set_active_discharge_regmap, +}; + +#define MAX77620_SD_CNF2_ROVS_EN_NONE 0 +#define RAIL_SD(_id, _name, _sname, _volt_mask, _min_uV, _max_uV, \ + _step_uV, _rs_add, _rs_mask) \ + [MAX77620_REGULATOR_ID_##_id] = { \ + .type = MAX77620_REGULATOR_TYPE_SD, \ + .volt_addr = MAX77620_REG_##_id, \ + .cfg_addr = MAX77620_REG_##_id##_CFG, \ + .fps_addr = MAX77620_REG_FPS_##_id, \ + .remote_sense_addr = _rs_add, \ + .remote_sense_mask = MAX77620_SD_CNF2_ROVS_EN_##_rs_mask, \ + .power_mode_mask = MAX77620_SD_POWER_MODE_MASK, \ + .power_mode_shift = MAX77620_SD_POWER_MODE_SHIFT, \ + .desc = { \ + .name = max77620_rails(_name), \ + .of_match = of_match_ptr(#_name), \ + .regulators_node = of_match_ptr("regulators"), \ + .of_parse_cb = max77620_of_parse_cb, \ + .supply_name = _sname, \ + .id = MAX77620_REGULATOR_ID_##_id, \ + .ops = &max77620_regulator_ops, \ + .n_voltages = ((_max_uV - _min_uV) / _step_uV) + 1, \ + .min_uV = _min_uV, \ + .uV_step = _step_uV, \ + .enable_time = 500, \ + .vsel_mask = MAX77620_##_volt_mask##_VOLT_MASK, \ + .vsel_reg = MAX77620_REG_##_id, \ + .active_discharge_off = 0, \ + .active_discharge_on = MAX77620_SD_CFG1_ADE_ENABLE, \ + .active_discharge_mask = MAX77620_SD_CFG1_ADE_MASK, \ + .active_discharge_reg = MAX77620_REG_##_id##_CFG, \ + .type = REGULATOR_VOLTAGE, \ + }, \ + } + +#define RAIL_LDO(_id, _name, _sname, _type, _min_uV, _max_uV, _step_uV) \ + [MAX77620_REGULATOR_ID_##_id] = { \ + .type = MAX77620_REGULATOR_TYPE_LDO_##_type, \ + .volt_addr = MAX77620_REG_##_id##_CFG, \ + .cfg_addr = MAX77620_REG_##_id##_CFG2, \ + .fps_addr = MAX77620_REG_FPS_##_id, \ + .remote_sense_addr = 0xFF, \ + .power_mode_mask = MAX77620_LDO_POWER_MODE_MASK, \ + .power_mode_shift = MAX77620_LDO_POWER_MODE_SHIFT, \ + .desc = { \ + .name = max77620_rails(_name), \ + .of_match = of_match_ptr(#_name), \ + .regulators_node = of_match_ptr("regulators"), \ + .of_parse_cb = max77620_of_parse_cb, \ + .supply_name = _sname, \ + .id = MAX77620_REGULATOR_ID_##_id, \ + .ops = &max77620_regulator_ops, \ + .n_voltages = ((_max_uV - _min_uV) / _step_uV) + 1, \ + .min_uV = _min_uV, \ + .uV_step = _step_uV, \ + .enable_time = 500, \ + .vsel_mask = MAX77620_LDO_VOLT_MASK, \ + .vsel_reg = MAX77620_REG_##_id##_CFG, \ + .active_discharge_off = 0, \ + .active_discharge_on = MAX77620_LDO_CFG2_ADE_ENABLE, \ + .active_discharge_mask = MAX77620_LDO_CFG2_ADE_MASK, \ + .active_discharge_reg = MAX77620_REG_##_id##_CFG2, \ + .type = REGULATOR_VOLTAGE, \ + }, \ + } + +static struct max77620_regulator_info max77620_regs_info[MAX77620_NUM_REGS] = { + RAIL_SD(SD0, sd0, "in-sd0", SD0, 600000, 1400000, 12500, 0x22, SD0), + RAIL_SD(SD1, sd1, "in-sd1", SD1, 600000, 1550000, 12500, 0x22, SD1), + RAIL_SD(SD2, sd2, "in-sd2", SDX, 600000, 3787500, 12500, 0xFF, NONE), + RAIL_SD(SD3, sd3, "in-sd3", SDX, 600000, 3787500, 12500, 0xFF, NONE), + RAIL_SD(SD4, sd4, "in-sd4", SDX, 600000, 3787500, 12500, 0xFF, NONE), + + RAIL_LDO(LDO0, ldo0, "in-ldo0-1", N, 800000, 2375000, 25000), + RAIL_LDO(LDO1, ldo1, "in-ldo0-1", N, 800000, 2375000, 25000), + RAIL_LDO(LDO2, ldo2, "in-ldo2", P, 800000, 3950000, 50000), + RAIL_LDO(LDO3, ldo3, "in-ldo3-5", P, 800000, 3950000, 50000), + RAIL_LDO(LDO4, ldo4, "in-ldo4-6", P, 800000, 1587500, 12500), + RAIL_LDO(LDO5, ldo5, "in-ldo3-5", P, 800000, 3950000, 50000), + RAIL_LDO(LDO6, ldo6, "in-ldo4-6", P, 800000, 3950000, 50000), + RAIL_LDO(LDO7, ldo7, "in-ldo7-8", N, 800000, 3950000, 50000), + RAIL_LDO(LDO8, ldo8, "in-ldo7-8", N, 800000, 3950000, 50000), +}; + +static struct max77620_regulator_info max20024_regs_info[MAX77620_NUM_REGS] = { + RAIL_SD(SD0, sd0, "in-sd0", SD0, 800000, 1587500, 12500, 0x22, SD0), + RAIL_SD(SD1, sd1, "in-sd1", SD1, 600000, 3387500, 12500, 0x22, SD1), + RAIL_SD(SD2, sd2, "in-sd2", SDX, 600000, 3787500, 12500, 0xFF, NONE), + RAIL_SD(SD3, sd3, "in-sd3", SDX, 600000, 3787500, 12500, 0xFF, NONE), + RAIL_SD(SD4, sd4, "in-sd4", SDX, 600000, 3787500, 12500, 0xFF, NONE), + + RAIL_LDO(LDO0, ldo0, "in-ldo0-1", N, 800000, 2375000, 25000), + RAIL_LDO(LDO1, ldo1, "in-ldo0-1", N, 800000, 2375000, 25000), + RAIL_LDO(LDO2, ldo2, "in-ldo2", P, 800000, 3950000, 50000), + RAIL_LDO(LDO3, ldo3, "in-ldo3-5", P, 800000, 3950000, 50000), + RAIL_LDO(LDO4, ldo4, "in-ldo4-6", P, 800000, 1587500, 12500), + RAIL_LDO(LDO5, ldo5, "in-ldo3-5", P, 800000, 3950000, 50000), + RAIL_LDO(LDO6, ldo6, "in-ldo4-6", P, 800000, 3950000, 50000), + RAIL_LDO(LDO7, ldo7, "in-ldo7-8", N, 800000, 3950000, 50000), + RAIL_LDO(LDO8, ldo8, "in-ldo7-8", N, 800000, 3950000, 50000), +}; + +static int max77620_regulator_probe(struct platform_device *pdev) +{ + struct max77620_chip *max77620_chip = dev_get_drvdata(pdev->dev.parent); + struct max77620_regulator_info *rinfo; + struct device *dev = &pdev->dev; + struct regulator_config config = { }; + struct max77620_regulator *pmic; + int ret = 0; + int id; + + pmic = devm_kzalloc(dev, sizeof(*pmic), GFP_KERNEL); + if (!pmic) + return -ENOMEM; + + platform_set_drvdata(pdev, pmic); + pmic->dev = dev; + pmic->rmap = max77620_chip->rmap; + if (!dev->of_node) + dev->of_node = pdev->dev.parent->of_node; + + switch (max77620_chip->chip_id) { + case MAX77620: + rinfo = max77620_regs_info; + break; + default: + rinfo = max20024_regs_info; + break; + } + + config.regmap = pmic->rmap; + config.dev = dev; + config.driver_data = pmic; + + for (id = 0; id < MAX77620_NUM_REGS; id++) { + struct regulator_dev *rdev; + struct regulator_desc *rdesc; + + if ((max77620_chip->chip_id == MAX77620) && + (id == MAX77620_REGULATOR_ID_SD4)) + continue; + + rdesc = &rinfo[id].desc; + pmic->rinfo[id] = &max77620_regs_info[id]; + pmic->enable_power_mode[id] = MAX77620_POWER_MODE_NORMAL; + + ret = max77620_read_slew_rate(pmic, id); + if (ret < 0) + return ret; + + rdev = devm_regulator_register(dev, rdesc, &config); + if (IS_ERR(rdev)) { + ret = PTR_ERR(rdev); + dev_err(dev, "Regulator registration %s failed: %d\n", + rdesc->name, ret); + return ret; + } + } + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int max77620_regulator_suspend(struct device *dev) +{ + struct max77620_regulator *pmic = dev_get_drvdata(dev); + struct max77620_regulator_pdata *reg_pdata; + int id; + + for (id = 0; id < MAX77620_NUM_REGS; id++) { + reg_pdata = &pmic->reg_pdata[id]; + + max77620_regulator_set_fps_slots(pmic, id, true); + if (reg_pdata->suspend_fps_src < 0) + continue; + + max77620_regulator_set_fps_src(pmic, reg_pdata->suspend_fps_src, + id); + } + + return 0; +} + +static int max77620_regulator_resume(struct device *dev) +{ + struct max77620_regulator *pmic = dev_get_drvdata(dev); + struct max77620_regulator_pdata *reg_pdata; + int id; + + for (id = 0; id < MAX77620_NUM_REGS; id++) { + reg_pdata = &pmic->reg_pdata[id]; + + max77620_regulator_set_fps_slots(pmic, id, false); + if (reg_pdata->active_fps_src < 0) + continue; + max77620_regulator_set_fps_src(pmic, reg_pdata->active_fps_src, + id); + } + + return 0; +} +#endif + +static const struct dev_pm_ops max77620_regulator_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(max77620_regulator_suspend, + max77620_regulator_resume) +}; + +static const struct platform_device_id max77620_regulator_devtype[] = { + { .name = "max77620-pmic", }, + { .name = "max20024-pmic", }, + {}, +}; +MODULE_DEVICE_TABLE(platform, max77620_regulator_devtype); + +static struct platform_driver max77620_regulator_driver = { + .probe = max77620_regulator_probe, + .id_table = max77620_regulator_devtype, + .driver = { + .name = "max77620-pmic", + .pm = &max77620_regulator_pm_ops, + }, +}; + +module_platform_driver(max77620_regulator_driver); + +MODULE_DESCRIPTION("MAX77620/MAX20024 regulator driver"); +MODULE_AUTHOR("Mallikarjun Kasoju "); +MODULE_AUTHOR("Laxman Dewangan "); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/regulator/max77686.c b/drivers/regulator/max77686-regulator.c similarity index 100% rename from drivers/regulator/max77686.c rename to drivers/regulator/max77686-regulator.c diff --git a/drivers/regulator/max77802.c b/drivers/regulator/max77802-regulator.c similarity index 100% rename from drivers/regulator/max77802.c rename to drivers/regulator/max77802-regulator.c