From 917e50d6941ed8b2bbde0a066f15f0d19e8f9409 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Fri, 29 Jan 2016 13:09:00 -0300 Subject: regulator: max77802: Fix DT binding document reference The DT binding doc references the max77802 clocks header file which makes no sense since of course it doesn't contain data related to the regulators. It's a copy and paste error, so add a reference to the correct header file. Signed-off-by: Javier Martinez Canillas Reviewed-by: Krzysztof Kozlowski Acked-by: Rob Herring Signed-off-by: Mark Brown diff --git a/Documentation/devicetree/bindings/regulator/max77802.txt b/Documentation/devicetree/bindings/regulator/max77802.txt index 09d796e..879e98d 100644 --- a/Documentation/devicetree/bindings/regulator/max77802.txt +++ b/Documentation/devicetree/bindings/regulator/max77802.txt @@ -60,7 +60,7 @@ The possible values for "regulator-initial-mode" and "regulator-mode" are: 1: Normal regulator voltage output mode. 3: Low Power which reduces the quiescent current down to only 1uA -The list of valid modes are defined in the dt-bindings/clock/maxim,max77802.h +The valid modes list is defined in the dt-bindings/regulator/maxim,max77802.h header and can be included by device tree source files. The standard "regulator-mode" property can only be used for regulators that -- cgit v0.10.2 From 96173cc6a4c4fca5a3a83e942b09474f791c395a Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Fri, 12 Feb 2016 01:14:23 -0300 Subject: regulator: Rename files for max77686 and max77802 drivers The max77686 and max77802 regulator drivers are for sub-devices of a MFD driver for some PMIC blocks. But the same object file name (max77686.o) was used for both the common MFD driver and the max77686 regulator one. This confuses kbuild if both drivers are built as module causing the MFD driver to not be copied when installing the modules. Also, max77{686,802} are a quite generic name for MFD subdevices drivers so it is better to rename them to max77{686,802}-regulator like it's the case for most regulator drivers. Signed-off-by: Javier Martinez Canillas Signed-off-by: Mark Brown diff --git a/MAINTAINERS b/MAINTAINERS index 30aca4a..1d88035 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6903,7 +6903,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 diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index 980b194..a8c07a07 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -54,9 +54,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/max77686-regulator.c b/drivers/regulator/max77686-regulator.c new file mode 100644 index 0000000..17ccf36 --- /dev/null +++ b/drivers/regulator/max77686-regulator.c @@ -0,0 +1,570 @@ +/* + * max77686.c - Regulator driver for the Maxim 77686 + * + * Copyright (C) 2012 Samsung Electronics + * Chiwoong Byun + * Jonghwa Lee + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * This driver is based on max8997.c + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAX77686_LDO_MINUV 800000 +#define MAX77686_LDO_UVSTEP 50000 +#define MAX77686_LDO_LOW_MINUV 800000 +#define MAX77686_LDO_LOW_UVSTEP 25000 +#define MAX77686_BUCK_MINUV 750000 +#define MAX77686_BUCK_UVSTEP 50000 +#define MAX77686_RAMP_DELAY 100000 /* uV/us */ +#define MAX77686_DVS_RAMP_DELAY 27500 /* uV/us */ +#define MAX77686_DVS_MINUV 600000 +#define MAX77686_DVS_UVSTEP 12500 + +/* + * Value for configuring buck[89] and LDO{20,21,22} as GPIO control. + * It is the same as 'off' for other regulators. + */ +#define MAX77686_GPIO_CONTROL 0x0 +/* + * Values used for configuring LDOs and bucks. + * Forcing low power mode: LDO1, 3-5, 9, 13, 17-26 + */ +#define MAX77686_LDO_LOWPOWER 0x1 +/* + * On/off controlled by PWRREQ: + * - LDO2, 6-8, 10-12, 14-16 + * - buck[1234] + */ +#define MAX77686_OFF_PWRREQ 0x1 +/* Low power mode controlled by PWRREQ: All LDOs */ +#define MAX77686_LDO_LOWPOWER_PWRREQ 0x2 +/* Forcing low power mode: buck[234] */ +#define MAX77686_BUCK_LOWPOWER 0x2 +#define MAX77686_NORMAL 0x3 + +#define MAX77686_OPMODE_SHIFT 6 +#define MAX77686_OPMODE_BUCK234_SHIFT 4 +#define MAX77686_OPMODE_MASK 0x3 + +#define MAX77686_VSEL_MASK 0x3F +#define MAX77686_DVS_VSEL_MASK 0xFF + +#define MAX77686_RAMP_RATE_MASK 0xC0 + +#define MAX77686_REGULATORS MAX77686_REG_MAX +#define MAX77686_LDOS 26 + +enum max77686_ramp_rate { + RAMP_RATE_13P75MV, + RAMP_RATE_27P5MV, + RAMP_RATE_55MV, + RAMP_RATE_NO_CTRL, /* 100mV/us */ +}; + +struct max77686_data { + DECLARE_BITMAP(gpio_enabled, MAX77686_REGULATORS); + + /* Array indexed by regulator id */ + unsigned int opmode[MAX77686_REGULATORS]; +}; + +static unsigned int max77686_get_opmode_shift(int id) +{ + switch (id) { + case MAX77686_BUCK1: + case MAX77686_BUCK5 ... MAX77686_BUCK9: + return 0; + case MAX77686_BUCK2 ... MAX77686_BUCK4: + return MAX77686_OPMODE_BUCK234_SHIFT; + default: + /* all LDOs */ + return MAX77686_OPMODE_SHIFT; + } +} + +/* + * When regulator is configured for GPIO control then it + * replaces "normal" mode. Any change from low power mode to normal + * should actually change to GPIO control. + * Map normal mode to proper value for such regulators. + */ +static unsigned int max77686_map_normal_mode(struct max77686_data *max77686, + int id) +{ + switch (id) { + case MAX77686_BUCK8: + case MAX77686_BUCK9: + case MAX77686_LDO20 ... MAX77686_LDO22: + if (test_bit(id, max77686->gpio_enabled)) + return MAX77686_GPIO_CONTROL; + } + + return MAX77686_NORMAL; +} + +/* Some BUCKs and LDOs supports Normal[ON/OFF] mode during suspend */ +static int max77686_set_suspend_disable(struct regulator_dev *rdev) +{ + unsigned int val, shift; + struct max77686_data *max77686 = rdev_get_drvdata(rdev); + int ret, id = rdev_get_id(rdev); + + shift = max77686_get_opmode_shift(id); + val = MAX77686_OFF_PWRREQ; + + ret = regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, + rdev->desc->enable_mask, val << shift); + if (ret) + return ret; + + max77686->opmode[id] = val; + return 0; +} + +/* Some LDOs supports [LPM/Normal]ON mode during suspend state */ +static int max77686_set_suspend_mode(struct regulator_dev *rdev, + unsigned int mode) +{ + struct max77686_data *max77686 = rdev_get_drvdata(rdev); + unsigned int val; + int ret, id = rdev_get_id(rdev); + + /* BUCK[5-9] doesn't support this feature */ + if (id >= MAX77686_BUCK5) + return 0; + + switch (mode) { + case REGULATOR_MODE_IDLE: /* ON in LP Mode */ + val = MAX77686_LDO_LOWPOWER_PWRREQ; + break; + case REGULATOR_MODE_NORMAL: /* ON in Normal Mode */ + val = max77686_map_normal_mode(max77686, id); + break; + default: + pr_warn("%s: regulator_suspend_mode : 0x%x not supported\n", + rdev->desc->name, mode); + return -EINVAL; + } + + ret = regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, + rdev->desc->enable_mask, + val << MAX77686_OPMODE_SHIFT); + if (ret) + return ret; + + max77686->opmode[id] = val; + return 0; +} + +/* Some LDOs supports LPM-ON/OFF/Normal-ON mode during suspend state */ +static int max77686_ldo_set_suspend_mode(struct regulator_dev *rdev, + unsigned int mode) +{ + unsigned int val; + struct max77686_data *max77686 = rdev_get_drvdata(rdev); + int ret, id = rdev_get_id(rdev); + + switch (mode) { + case REGULATOR_MODE_STANDBY: /* switch off */ + val = MAX77686_OFF_PWRREQ; + break; + case REGULATOR_MODE_IDLE: /* ON in LP Mode */ + val = MAX77686_LDO_LOWPOWER_PWRREQ; + break; + case REGULATOR_MODE_NORMAL: /* ON in Normal Mode */ + val = max77686_map_normal_mode(max77686, id); + break; + default: + pr_warn("%s: regulator_suspend_mode : 0x%x not supported\n", + rdev->desc->name, mode); + return -EINVAL; + } + + ret = regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, + rdev->desc->enable_mask, + val << MAX77686_OPMODE_SHIFT); + if (ret) + return ret; + + max77686->opmode[id] = val; + return 0; +} + +static int max77686_enable(struct regulator_dev *rdev) +{ + struct max77686_data *max77686 = rdev_get_drvdata(rdev); + unsigned int shift; + int id = rdev_get_id(rdev); + + shift = max77686_get_opmode_shift(id); + + if (max77686->opmode[id] == MAX77686_OFF_PWRREQ) + max77686->opmode[id] = max77686_map_normal_mode(max77686, id); + + return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, + rdev->desc->enable_mask, + max77686->opmode[id] << shift); +} + +static int max77686_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay) +{ + unsigned int ramp_value = RAMP_RATE_NO_CTRL; + + switch (ramp_delay) { + case 1 ... 13750: + ramp_value = RAMP_RATE_13P75MV; + break; + case 13751 ... 27500: + ramp_value = RAMP_RATE_27P5MV; + break; + case 27501 ... 55000: + ramp_value = RAMP_RATE_55MV; + break; + case 55001 ... 100000: + break; + default: + pr_warn("%s: ramp_delay: %d not supported, setting 100000\n", + rdev->desc->name, ramp_delay); + } + + return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, + MAX77686_RAMP_RATE_MASK, ramp_value << 6); +} + +static int max77686_of_parse_cb(struct device_node *np, + const struct regulator_desc *desc, + struct regulator_config *config) +{ + struct max77686_data *max77686 = config->driver_data; + + switch (desc->id) { + case MAX77686_BUCK8: + case MAX77686_BUCK9: + case MAX77686_LDO20 ... MAX77686_LDO22: + config->ena_gpio = of_get_named_gpio(np, + "maxim,ena-gpios", 0); + config->ena_gpio_flags = GPIOF_OUT_INIT_HIGH; + config->ena_gpio_initialized = true; + break; + default: + return 0; + } + + if (gpio_is_valid(config->ena_gpio)) { + set_bit(desc->id, max77686->gpio_enabled); + + return regmap_update_bits(config->regmap, desc->enable_reg, + desc->enable_mask, + MAX77686_GPIO_CONTROL); + } + + return 0; +} + +static struct regulator_ops max77686_ops = { + .list_voltage = regulator_list_voltage_linear, + .map_voltage = regulator_map_voltage_linear, + .is_enabled = regulator_is_enabled_regmap, + .enable = max77686_enable, + .disable = regulator_disable_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .set_voltage_time_sel = regulator_set_voltage_time_sel, + .set_suspend_mode = max77686_set_suspend_mode, +}; + +static struct regulator_ops max77686_ldo_ops = { + .list_voltage = regulator_list_voltage_linear, + .map_voltage = regulator_map_voltage_linear, + .is_enabled = regulator_is_enabled_regmap, + .enable = max77686_enable, + .disable = regulator_disable_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .set_voltage_time_sel = regulator_set_voltage_time_sel, + .set_suspend_mode = max77686_ldo_set_suspend_mode, + .set_suspend_disable = max77686_set_suspend_disable, +}; + +static struct regulator_ops max77686_buck1_ops = { + .list_voltage = regulator_list_voltage_linear, + .map_voltage = regulator_map_voltage_linear, + .is_enabled = regulator_is_enabled_regmap, + .enable = max77686_enable, + .disable = regulator_disable_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .set_voltage_time_sel = regulator_set_voltage_time_sel, + .set_suspend_disable = max77686_set_suspend_disable, +}; + +static struct regulator_ops max77686_buck_dvs_ops = { + .list_voltage = regulator_list_voltage_linear, + .map_voltage = regulator_map_voltage_linear, + .is_enabled = regulator_is_enabled_regmap, + .enable = max77686_enable, + .disable = regulator_disable_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .set_voltage_time_sel = regulator_set_voltage_time_sel, + .set_ramp_delay = max77686_set_ramp_delay, + .set_suspend_disable = max77686_set_suspend_disable, +}; + +#define regulator_desc_ldo(num) { \ + .name = "LDO"#num, \ + .of_match = of_match_ptr("LDO"#num), \ + .regulators_node = of_match_ptr("voltage-regulators"), \ + .of_parse_cb = max77686_of_parse_cb, \ + .id = MAX77686_LDO##num, \ + .ops = &max77686_ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + .min_uV = MAX77686_LDO_MINUV, \ + .uV_step = MAX77686_LDO_UVSTEP, \ + .ramp_delay = MAX77686_RAMP_DELAY, \ + .n_voltages = MAX77686_VSEL_MASK + 1, \ + .vsel_reg = MAX77686_REG_LDO1CTRL1 + num - 1, \ + .vsel_mask = MAX77686_VSEL_MASK, \ + .enable_reg = MAX77686_REG_LDO1CTRL1 + num - 1, \ + .enable_mask = MAX77686_OPMODE_MASK \ + << MAX77686_OPMODE_SHIFT, \ +} +#define regulator_desc_lpm_ldo(num) { \ + .name = "LDO"#num, \ + .of_match = of_match_ptr("LDO"#num), \ + .regulators_node = of_match_ptr("voltage-regulators"), \ + .id = MAX77686_LDO##num, \ + .ops = &max77686_ldo_ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + .min_uV = MAX77686_LDO_MINUV, \ + .uV_step = MAX77686_LDO_UVSTEP, \ + .ramp_delay = MAX77686_RAMP_DELAY, \ + .n_voltages = MAX77686_VSEL_MASK + 1, \ + .vsel_reg = MAX77686_REG_LDO1CTRL1 + num - 1, \ + .vsel_mask = MAX77686_VSEL_MASK, \ + .enable_reg = MAX77686_REG_LDO1CTRL1 + num - 1, \ + .enable_mask = MAX77686_OPMODE_MASK \ + << MAX77686_OPMODE_SHIFT, \ +} +#define regulator_desc_ldo_low(num) { \ + .name = "LDO"#num, \ + .of_match = of_match_ptr("LDO"#num), \ + .regulators_node = of_match_ptr("voltage-regulators"), \ + .id = MAX77686_LDO##num, \ + .ops = &max77686_ldo_ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + .min_uV = MAX77686_LDO_LOW_MINUV, \ + .uV_step = MAX77686_LDO_LOW_UVSTEP, \ + .ramp_delay = MAX77686_RAMP_DELAY, \ + .n_voltages = MAX77686_VSEL_MASK + 1, \ + .vsel_reg = MAX77686_REG_LDO1CTRL1 + num - 1, \ + .vsel_mask = MAX77686_VSEL_MASK, \ + .enable_reg = MAX77686_REG_LDO1CTRL1 + num - 1, \ + .enable_mask = MAX77686_OPMODE_MASK \ + << MAX77686_OPMODE_SHIFT, \ +} +#define regulator_desc_ldo1_low(num) { \ + .name = "LDO"#num, \ + .of_match = of_match_ptr("LDO"#num), \ + .regulators_node = of_match_ptr("voltage-regulators"), \ + .id = MAX77686_LDO##num, \ + .ops = &max77686_ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + .min_uV = MAX77686_LDO_LOW_MINUV, \ + .uV_step = MAX77686_LDO_LOW_UVSTEP, \ + .ramp_delay = MAX77686_RAMP_DELAY, \ + .n_voltages = MAX77686_VSEL_MASK + 1, \ + .vsel_reg = MAX77686_REG_LDO1CTRL1 + num - 1, \ + .vsel_mask = MAX77686_VSEL_MASK, \ + .enable_reg = MAX77686_REG_LDO1CTRL1 + num - 1, \ + .enable_mask = MAX77686_OPMODE_MASK \ + << MAX77686_OPMODE_SHIFT, \ +} +#define regulator_desc_buck(num) { \ + .name = "BUCK"#num, \ + .of_match = of_match_ptr("BUCK"#num), \ + .regulators_node = of_match_ptr("voltage-regulators"), \ + .of_parse_cb = max77686_of_parse_cb, \ + .id = MAX77686_BUCK##num, \ + .ops = &max77686_ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + .min_uV = MAX77686_BUCK_MINUV, \ + .uV_step = MAX77686_BUCK_UVSTEP, \ + .ramp_delay = MAX77686_RAMP_DELAY, \ + .n_voltages = MAX77686_VSEL_MASK + 1, \ + .vsel_reg = MAX77686_REG_BUCK5OUT + (num - 5) * 2, \ + .vsel_mask = MAX77686_VSEL_MASK, \ + .enable_reg = MAX77686_REG_BUCK5CTRL + (num - 5) * 2, \ + .enable_mask = MAX77686_OPMODE_MASK, \ +} +#define regulator_desc_buck1(num) { \ + .name = "BUCK"#num, \ + .of_match = of_match_ptr("BUCK"#num), \ + .regulators_node = of_match_ptr("voltage-regulators"), \ + .id = MAX77686_BUCK##num, \ + .ops = &max77686_buck1_ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + .min_uV = MAX77686_BUCK_MINUV, \ + .uV_step = MAX77686_BUCK_UVSTEP, \ + .ramp_delay = MAX77686_RAMP_DELAY, \ + .n_voltages = MAX77686_VSEL_MASK + 1, \ + .vsel_reg = MAX77686_REG_BUCK1OUT, \ + .vsel_mask = MAX77686_VSEL_MASK, \ + .enable_reg = MAX77686_REG_BUCK1CTRL, \ + .enable_mask = MAX77686_OPMODE_MASK, \ +} +#define regulator_desc_buck_dvs(num) { \ + .name = "BUCK"#num, \ + .of_match = of_match_ptr("BUCK"#num), \ + .regulators_node = of_match_ptr("voltage-regulators"), \ + .id = MAX77686_BUCK##num, \ + .ops = &max77686_buck_dvs_ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + .min_uV = MAX77686_DVS_MINUV, \ + .uV_step = MAX77686_DVS_UVSTEP, \ + .ramp_delay = MAX77686_DVS_RAMP_DELAY, \ + .n_voltages = MAX77686_DVS_VSEL_MASK + 1, \ + .vsel_reg = MAX77686_REG_BUCK2DVS1 + (num - 2) * 10, \ + .vsel_mask = MAX77686_DVS_VSEL_MASK, \ + .enable_reg = MAX77686_REG_BUCK2CTRL1 + (num - 2) * 10, \ + .enable_mask = MAX77686_OPMODE_MASK \ + << MAX77686_OPMODE_BUCK234_SHIFT, \ +} + +static const struct regulator_desc regulators[] = { + regulator_desc_ldo1_low(1), + regulator_desc_ldo_low(2), + regulator_desc_ldo(3), + regulator_desc_ldo(4), + regulator_desc_ldo(5), + regulator_desc_ldo_low(6), + regulator_desc_ldo_low(7), + regulator_desc_ldo_low(8), + regulator_desc_ldo(9), + regulator_desc_lpm_ldo(10), + regulator_desc_lpm_ldo(11), + regulator_desc_lpm_ldo(12), + regulator_desc_ldo(13), + regulator_desc_lpm_ldo(14), + regulator_desc_ldo_low(15), + regulator_desc_lpm_ldo(16), + regulator_desc_ldo(17), + regulator_desc_ldo(18), + regulator_desc_ldo(19), + regulator_desc_ldo(20), + regulator_desc_ldo(21), + regulator_desc_ldo(22), + regulator_desc_ldo(23), + regulator_desc_ldo(24), + regulator_desc_ldo(25), + regulator_desc_ldo(26), + regulator_desc_buck1(1), + regulator_desc_buck_dvs(2), + regulator_desc_buck_dvs(3), + regulator_desc_buck_dvs(4), + regulator_desc_buck(5), + regulator_desc_buck(6), + regulator_desc_buck(7), + regulator_desc_buck(8), + regulator_desc_buck(9), +}; + +static int max77686_pmic_probe(struct platform_device *pdev) +{ + struct max77686_dev *iodev = dev_get_drvdata(pdev->dev.parent); + struct max77686_data *max77686; + int i; + struct regulator_config config = { }; + + dev_dbg(&pdev->dev, "%s\n", __func__); + + max77686 = devm_kzalloc(&pdev->dev, sizeof(struct max77686_data), + GFP_KERNEL); + if (!max77686) + return -ENOMEM; + + config.dev = iodev->dev; + config.regmap = iodev->regmap; + config.driver_data = max77686; + platform_set_drvdata(pdev, max77686); + + for (i = 0; i < MAX77686_REGULATORS; i++) { + struct regulator_dev *rdev; + int id = regulators[i].id; + + max77686->opmode[id] = MAX77686_NORMAL; + rdev = devm_regulator_register(&pdev->dev, + ®ulators[i], &config); + if (IS_ERR(rdev)) { + int ret = PTR_ERR(rdev); + dev_err(&pdev->dev, + "regulator init failed for %d: %d\n", i, ret); + return ret; + } + } + + return 0; +} + +static const struct platform_device_id max77686_pmic_id[] = { + {"max77686-pmic", 0}, + { }, +}; +MODULE_DEVICE_TABLE(platform, max77686_pmic_id); + +static struct platform_driver max77686_pmic_driver = { + .driver = { + .name = "max77686-pmic", + }, + .probe = max77686_pmic_probe, + .id_table = max77686_pmic_id, +}; + +static int __init max77686_pmic_init(void) +{ + return platform_driver_register(&max77686_pmic_driver); +} +subsys_initcall(max77686_pmic_init); + +static void __exit max77686_pmic_cleanup(void) +{ + platform_driver_unregister(&max77686_pmic_driver); +} +module_exit(max77686_pmic_cleanup); + +MODULE_DESCRIPTION("MAXIM 77686 Regulator Driver"); +MODULE_AUTHOR("Chiwoong Byun "); +MODULE_LICENSE("GPL"); diff --git a/drivers/regulator/max77686.c b/drivers/regulator/max77686.c deleted file mode 100644 index 17ccf36..0000000 --- a/drivers/regulator/max77686.c +++ /dev/null @@ -1,570 +0,0 @@ -/* - * max77686.c - Regulator driver for the Maxim 77686 - * - * Copyright (C) 2012 Samsung Electronics - * Chiwoong Byun - * Jonghwa Lee - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * This driver is based on max8997.c - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define MAX77686_LDO_MINUV 800000 -#define MAX77686_LDO_UVSTEP 50000 -#define MAX77686_LDO_LOW_MINUV 800000 -#define MAX77686_LDO_LOW_UVSTEP 25000 -#define MAX77686_BUCK_MINUV 750000 -#define MAX77686_BUCK_UVSTEP 50000 -#define MAX77686_RAMP_DELAY 100000 /* uV/us */ -#define MAX77686_DVS_RAMP_DELAY 27500 /* uV/us */ -#define MAX77686_DVS_MINUV 600000 -#define MAX77686_DVS_UVSTEP 12500 - -/* - * Value for configuring buck[89] and LDO{20,21,22} as GPIO control. - * It is the same as 'off' for other regulators. - */ -#define MAX77686_GPIO_CONTROL 0x0 -/* - * Values used for configuring LDOs and bucks. - * Forcing low power mode: LDO1, 3-5, 9, 13, 17-26 - */ -#define MAX77686_LDO_LOWPOWER 0x1 -/* - * On/off controlled by PWRREQ: - * - LDO2, 6-8, 10-12, 14-16 - * - buck[1234] - */ -#define MAX77686_OFF_PWRREQ 0x1 -/* Low power mode controlled by PWRREQ: All LDOs */ -#define MAX77686_LDO_LOWPOWER_PWRREQ 0x2 -/* Forcing low power mode: buck[234] */ -#define MAX77686_BUCK_LOWPOWER 0x2 -#define MAX77686_NORMAL 0x3 - -#define MAX77686_OPMODE_SHIFT 6 -#define MAX77686_OPMODE_BUCK234_SHIFT 4 -#define MAX77686_OPMODE_MASK 0x3 - -#define MAX77686_VSEL_MASK 0x3F -#define MAX77686_DVS_VSEL_MASK 0xFF - -#define MAX77686_RAMP_RATE_MASK 0xC0 - -#define MAX77686_REGULATORS MAX77686_REG_MAX -#define MAX77686_LDOS 26 - -enum max77686_ramp_rate { - RAMP_RATE_13P75MV, - RAMP_RATE_27P5MV, - RAMP_RATE_55MV, - RAMP_RATE_NO_CTRL, /* 100mV/us */ -}; - -struct max77686_data { - DECLARE_BITMAP(gpio_enabled, MAX77686_REGULATORS); - - /* Array indexed by regulator id */ - unsigned int opmode[MAX77686_REGULATORS]; -}; - -static unsigned int max77686_get_opmode_shift(int id) -{ - switch (id) { - case MAX77686_BUCK1: - case MAX77686_BUCK5 ... MAX77686_BUCK9: - return 0; - case MAX77686_BUCK2 ... MAX77686_BUCK4: - return MAX77686_OPMODE_BUCK234_SHIFT; - default: - /* all LDOs */ - return MAX77686_OPMODE_SHIFT; - } -} - -/* - * When regulator is configured for GPIO control then it - * replaces "normal" mode. Any change from low power mode to normal - * should actually change to GPIO control. - * Map normal mode to proper value for such regulators. - */ -static unsigned int max77686_map_normal_mode(struct max77686_data *max77686, - int id) -{ - switch (id) { - case MAX77686_BUCK8: - case MAX77686_BUCK9: - case MAX77686_LDO20 ... MAX77686_LDO22: - if (test_bit(id, max77686->gpio_enabled)) - return MAX77686_GPIO_CONTROL; - } - - return MAX77686_NORMAL; -} - -/* Some BUCKs and LDOs supports Normal[ON/OFF] mode during suspend */ -static int max77686_set_suspend_disable(struct regulator_dev *rdev) -{ - unsigned int val, shift; - struct max77686_data *max77686 = rdev_get_drvdata(rdev); - int ret, id = rdev_get_id(rdev); - - shift = max77686_get_opmode_shift(id); - val = MAX77686_OFF_PWRREQ; - - ret = regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, - rdev->desc->enable_mask, val << shift); - if (ret) - return ret; - - max77686->opmode[id] = val; - return 0; -} - -/* Some LDOs supports [LPM/Normal]ON mode during suspend state */ -static int max77686_set_suspend_mode(struct regulator_dev *rdev, - unsigned int mode) -{ - struct max77686_data *max77686 = rdev_get_drvdata(rdev); - unsigned int val; - int ret, id = rdev_get_id(rdev); - - /* BUCK[5-9] doesn't support this feature */ - if (id >= MAX77686_BUCK5) - return 0; - - switch (mode) { - case REGULATOR_MODE_IDLE: /* ON in LP Mode */ - val = MAX77686_LDO_LOWPOWER_PWRREQ; - break; - case REGULATOR_MODE_NORMAL: /* ON in Normal Mode */ - val = max77686_map_normal_mode(max77686, id); - break; - default: - pr_warn("%s: regulator_suspend_mode : 0x%x not supported\n", - rdev->desc->name, mode); - return -EINVAL; - } - - ret = regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, - rdev->desc->enable_mask, - val << MAX77686_OPMODE_SHIFT); - if (ret) - return ret; - - max77686->opmode[id] = val; - return 0; -} - -/* Some LDOs supports LPM-ON/OFF/Normal-ON mode during suspend state */ -static int max77686_ldo_set_suspend_mode(struct regulator_dev *rdev, - unsigned int mode) -{ - unsigned int val; - struct max77686_data *max77686 = rdev_get_drvdata(rdev); - int ret, id = rdev_get_id(rdev); - - switch (mode) { - case REGULATOR_MODE_STANDBY: /* switch off */ - val = MAX77686_OFF_PWRREQ; - break; - case REGULATOR_MODE_IDLE: /* ON in LP Mode */ - val = MAX77686_LDO_LOWPOWER_PWRREQ; - break; - case REGULATOR_MODE_NORMAL: /* ON in Normal Mode */ - val = max77686_map_normal_mode(max77686, id); - break; - default: - pr_warn("%s: regulator_suspend_mode : 0x%x not supported\n", - rdev->desc->name, mode); - return -EINVAL; - } - - ret = regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, - rdev->desc->enable_mask, - val << MAX77686_OPMODE_SHIFT); - if (ret) - return ret; - - max77686->opmode[id] = val; - return 0; -} - -static int max77686_enable(struct regulator_dev *rdev) -{ - struct max77686_data *max77686 = rdev_get_drvdata(rdev); - unsigned int shift; - int id = rdev_get_id(rdev); - - shift = max77686_get_opmode_shift(id); - - if (max77686->opmode[id] == MAX77686_OFF_PWRREQ) - max77686->opmode[id] = max77686_map_normal_mode(max77686, id); - - return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, - rdev->desc->enable_mask, - max77686->opmode[id] << shift); -} - -static int max77686_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay) -{ - unsigned int ramp_value = RAMP_RATE_NO_CTRL; - - switch (ramp_delay) { - case 1 ... 13750: - ramp_value = RAMP_RATE_13P75MV; - break; - case 13751 ... 27500: - ramp_value = RAMP_RATE_27P5MV; - break; - case 27501 ... 55000: - ramp_value = RAMP_RATE_55MV; - break; - case 55001 ... 100000: - break; - default: - pr_warn("%s: ramp_delay: %d not supported, setting 100000\n", - rdev->desc->name, ramp_delay); - } - - return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, - MAX77686_RAMP_RATE_MASK, ramp_value << 6); -} - -static int max77686_of_parse_cb(struct device_node *np, - const struct regulator_desc *desc, - struct regulator_config *config) -{ - struct max77686_data *max77686 = config->driver_data; - - switch (desc->id) { - case MAX77686_BUCK8: - case MAX77686_BUCK9: - case MAX77686_LDO20 ... MAX77686_LDO22: - config->ena_gpio = of_get_named_gpio(np, - "maxim,ena-gpios", 0); - config->ena_gpio_flags = GPIOF_OUT_INIT_HIGH; - config->ena_gpio_initialized = true; - break; - default: - return 0; - } - - if (gpio_is_valid(config->ena_gpio)) { - set_bit(desc->id, max77686->gpio_enabled); - - return regmap_update_bits(config->regmap, desc->enable_reg, - desc->enable_mask, - MAX77686_GPIO_CONTROL); - } - - return 0; -} - -static struct regulator_ops max77686_ops = { - .list_voltage = regulator_list_voltage_linear, - .map_voltage = regulator_map_voltage_linear, - .is_enabled = regulator_is_enabled_regmap, - .enable = max77686_enable, - .disable = regulator_disable_regmap, - .get_voltage_sel = regulator_get_voltage_sel_regmap, - .set_voltage_sel = regulator_set_voltage_sel_regmap, - .set_voltage_time_sel = regulator_set_voltage_time_sel, - .set_suspend_mode = max77686_set_suspend_mode, -}; - -static struct regulator_ops max77686_ldo_ops = { - .list_voltage = regulator_list_voltage_linear, - .map_voltage = regulator_map_voltage_linear, - .is_enabled = regulator_is_enabled_regmap, - .enable = max77686_enable, - .disable = regulator_disable_regmap, - .get_voltage_sel = regulator_get_voltage_sel_regmap, - .set_voltage_sel = regulator_set_voltage_sel_regmap, - .set_voltage_time_sel = regulator_set_voltage_time_sel, - .set_suspend_mode = max77686_ldo_set_suspend_mode, - .set_suspend_disable = max77686_set_suspend_disable, -}; - -static struct regulator_ops max77686_buck1_ops = { - .list_voltage = regulator_list_voltage_linear, - .map_voltage = regulator_map_voltage_linear, - .is_enabled = regulator_is_enabled_regmap, - .enable = max77686_enable, - .disable = regulator_disable_regmap, - .get_voltage_sel = regulator_get_voltage_sel_regmap, - .set_voltage_sel = regulator_set_voltage_sel_regmap, - .set_voltage_time_sel = regulator_set_voltage_time_sel, - .set_suspend_disable = max77686_set_suspend_disable, -}; - -static struct regulator_ops max77686_buck_dvs_ops = { - .list_voltage = regulator_list_voltage_linear, - .map_voltage = regulator_map_voltage_linear, - .is_enabled = regulator_is_enabled_regmap, - .enable = max77686_enable, - .disable = regulator_disable_regmap, - .get_voltage_sel = regulator_get_voltage_sel_regmap, - .set_voltage_sel = regulator_set_voltage_sel_regmap, - .set_voltage_time_sel = regulator_set_voltage_time_sel, - .set_ramp_delay = max77686_set_ramp_delay, - .set_suspend_disable = max77686_set_suspend_disable, -}; - -#define regulator_desc_ldo(num) { \ - .name = "LDO"#num, \ - .of_match = of_match_ptr("LDO"#num), \ - .regulators_node = of_match_ptr("voltage-regulators"), \ - .of_parse_cb = max77686_of_parse_cb, \ - .id = MAX77686_LDO##num, \ - .ops = &max77686_ops, \ - .type = REGULATOR_VOLTAGE, \ - .owner = THIS_MODULE, \ - .min_uV = MAX77686_LDO_MINUV, \ - .uV_step = MAX77686_LDO_UVSTEP, \ - .ramp_delay = MAX77686_RAMP_DELAY, \ - .n_voltages = MAX77686_VSEL_MASK + 1, \ - .vsel_reg = MAX77686_REG_LDO1CTRL1 + num - 1, \ - .vsel_mask = MAX77686_VSEL_MASK, \ - .enable_reg = MAX77686_REG_LDO1CTRL1 + num - 1, \ - .enable_mask = MAX77686_OPMODE_MASK \ - << MAX77686_OPMODE_SHIFT, \ -} -#define regulator_desc_lpm_ldo(num) { \ - .name = "LDO"#num, \ - .of_match = of_match_ptr("LDO"#num), \ - .regulators_node = of_match_ptr("voltage-regulators"), \ - .id = MAX77686_LDO##num, \ - .ops = &max77686_ldo_ops, \ - .type = REGULATOR_VOLTAGE, \ - .owner = THIS_MODULE, \ - .min_uV = MAX77686_LDO_MINUV, \ - .uV_step = MAX77686_LDO_UVSTEP, \ - .ramp_delay = MAX77686_RAMP_DELAY, \ - .n_voltages = MAX77686_VSEL_MASK + 1, \ - .vsel_reg = MAX77686_REG_LDO1CTRL1 + num - 1, \ - .vsel_mask = MAX77686_VSEL_MASK, \ - .enable_reg = MAX77686_REG_LDO1CTRL1 + num - 1, \ - .enable_mask = MAX77686_OPMODE_MASK \ - << MAX77686_OPMODE_SHIFT, \ -} -#define regulator_desc_ldo_low(num) { \ - .name = "LDO"#num, \ - .of_match = of_match_ptr("LDO"#num), \ - .regulators_node = of_match_ptr("voltage-regulators"), \ - .id = MAX77686_LDO##num, \ - .ops = &max77686_ldo_ops, \ - .type = REGULATOR_VOLTAGE, \ - .owner = THIS_MODULE, \ - .min_uV = MAX77686_LDO_LOW_MINUV, \ - .uV_step = MAX77686_LDO_LOW_UVSTEP, \ - .ramp_delay = MAX77686_RAMP_DELAY, \ - .n_voltages = MAX77686_VSEL_MASK + 1, \ - .vsel_reg = MAX77686_REG_LDO1CTRL1 + num - 1, \ - .vsel_mask = MAX77686_VSEL_MASK, \ - .enable_reg = MAX77686_REG_LDO1CTRL1 + num - 1, \ - .enable_mask = MAX77686_OPMODE_MASK \ - << MAX77686_OPMODE_SHIFT, \ -} -#define regulator_desc_ldo1_low(num) { \ - .name = "LDO"#num, \ - .of_match = of_match_ptr("LDO"#num), \ - .regulators_node = of_match_ptr("voltage-regulators"), \ - .id = MAX77686_LDO##num, \ - .ops = &max77686_ops, \ - .type = REGULATOR_VOLTAGE, \ - .owner = THIS_MODULE, \ - .min_uV = MAX77686_LDO_LOW_MINUV, \ - .uV_step = MAX77686_LDO_LOW_UVSTEP, \ - .ramp_delay = MAX77686_RAMP_DELAY, \ - .n_voltages = MAX77686_VSEL_MASK + 1, \ - .vsel_reg = MAX77686_REG_LDO1CTRL1 + num - 1, \ - .vsel_mask = MAX77686_VSEL_MASK, \ - .enable_reg = MAX77686_REG_LDO1CTRL1 + num - 1, \ - .enable_mask = MAX77686_OPMODE_MASK \ - << MAX77686_OPMODE_SHIFT, \ -} -#define regulator_desc_buck(num) { \ - .name = "BUCK"#num, \ - .of_match = of_match_ptr("BUCK"#num), \ - .regulators_node = of_match_ptr("voltage-regulators"), \ - .of_parse_cb = max77686_of_parse_cb, \ - .id = MAX77686_BUCK##num, \ - .ops = &max77686_ops, \ - .type = REGULATOR_VOLTAGE, \ - .owner = THIS_MODULE, \ - .min_uV = MAX77686_BUCK_MINUV, \ - .uV_step = MAX77686_BUCK_UVSTEP, \ - .ramp_delay = MAX77686_RAMP_DELAY, \ - .n_voltages = MAX77686_VSEL_MASK + 1, \ - .vsel_reg = MAX77686_REG_BUCK5OUT + (num - 5) * 2, \ - .vsel_mask = MAX77686_VSEL_MASK, \ - .enable_reg = MAX77686_REG_BUCK5CTRL + (num - 5) * 2, \ - .enable_mask = MAX77686_OPMODE_MASK, \ -} -#define regulator_desc_buck1(num) { \ - .name = "BUCK"#num, \ - .of_match = of_match_ptr("BUCK"#num), \ - .regulators_node = of_match_ptr("voltage-regulators"), \ - .id = MAX77686_BUCK##num, \ - .ops = &max77686_buck1_ops, \ - .type = REGULATOR_VOLTAGE, \ - .owner = THIS_MODULE, \ - .min_uV = MAX77686_BUCK_MINUV, \ - .uV_step = MAX77686_BUCK_UVSTEP, \ - .ramp_delay = MAX77686_RAMP_DELAY, \ - .n_voltages = MAX77686_VSEL_MASK + 1, \ - .vsel_reg = MAX77686_REG_BUCK1OUT, \ - .vsel_mask = MAX77686_VSEL_MASK, \ - .enable_reg = MAX77686_REG_BUCK1CTRL, \ - .enable_mask = MAX77686_OPMODE_MASK, \ -} -#define regulator_desc_buck_dvs(num) { \ - .name = "BUCK"#num, \ - .of_match = of_match_ptr("BUCK"#num), \ - .regulators_node = of_match_ptr("voltage-regulators"), \ - .id = MAX77686_BUCK##num, \ - .ops = &max77686_buck_dvs_ops, \ - .type = REGULATOR_VOLTAGE, \ - .owner = THIS_MODULE, \ - .min_uV = MAX77686_DVS_MINUV, \ - .uV_step = MAX77686_DVS_UVSTEP, \ - .ramp_delay = MAX77686_DVS_RAMP_DELAY, \ - .n_voltages = MAX77686_DVS_VSEL_MASK + 1, \ - .vsel_reg = MAX77686_REG_BUCK2DVS1 + (num - 2) * 10, \ - .vsel_mask = MAX77686_DVS_VSEL_MASK, \ - .enable_reg = MAX77686_REG_BUCK2CTRL1 + (num - 2) * 10, \ - .enable_mask = MAX77686_OPMODE_MASK \ - << MAX77686_OPMODE_BUCK234_SHIFT, \ -} - -static const struct regulator_desc regulators[] = { - regulator_desc_ldo1_low(1), - regulator_desc_ldo_low(2), - regulator_desc_ldo(3), - regulator_desc_ldo(4), - regulator_desc_ldo(5), - regulator_desc_ldo_low(6), - regulator_desc_ldo_low(7), - regulator_desc_ldo_low(8), - regulator_desc_ldo(9), - regulator_desc_lpm_ldo(10), - regulator_desc_lpm_ldo(11), - regulator_desc_lpm_ldo(12), - regulator_desc_ldo(13), - regulator_desc_lpm_ldo(14), - regulator_desc_ldo_low(15), - regulator_desc_lpm_ldo(16), - regulator_desc_ldo(17), - regulator_desc_ldo(18), - regulator_desc_ldo(19), - regulator_desc_ldo(20), - regulator_desc_ldo(21), - regulator_desc_ldo(22), - regulator_desc_ldo(23), - regulator_desc_ldo(24), - regulator_desc_ldo(25), - regulator_desc_ldo(26), - regulator_desc_buck1(1), - regulator_desc_buck_dvs(2), - regulator_desc_buck_dvs(3), - regulator_desc_buck_dvs(4), - regulator_desc_buck(5), - regulator_desc_buck(6), - regulator_desc_buck(7), - regulator_desc_buck(8), - regulator_desc_buck(9), -}; - -static int max77686_pmic_probe(struct platform_device *pdev) -{ - struct max77686_dev *iodev = dev_get_drvdata(pdev->dev.parent); - struct max77686_data *max77686; - int i; - struct regulator_config config = { }; - - dev_dbg(&pdev->dev, "%s\n", __func__); - - max77686 = devm_kzalloc(&pdev->dev, sizeof(struct max77686_data), - GFP_KERNEL); - if (!max77686) - return -ENOMEM; - - config.dev = iodev->dev; - config.regmap = iodev->regmap; - config.driver_data = max77686; - platform_set_drvdata(pdev, max77686); - - for (i = 0; i < MAX77686_REGULATORS; i++) { - struct regulator_dev *rdev; - int id = regulators[i].id; - - max77686->opmode[id] = MAX77686_NORMAL; - rdev = devm_regulator_register(&pdev->dev, - ®ulators[i], &config); - if (IS_ERR(rdev)) { - int ret = PTR_ERR(rdev); - dev_err(&pdev->dev, - "regulator init failed for %d: %d\n", i, ret); - return ret; - } - } - - return 0; -} - -static const struct platform_device_id max77686_pmic_id[] = { - {"max77686-pmic", 0}, - { }, -}; -MODULE_DEVICE_TABLE(platform, max77686_pmic_id); - -static struct platform_driver max77686_pmic_driver = { - .driver = { - .name = "max77686-pmic", - }, - .probe = max77686_pmic_probe, - .id_table = max77686_pmic_id, -}; - -static int __init max77686_pmic_init(void) -{ - return platform_driver_register(&max77686_pmic_driver); -} -subsys_initcall(max77686_pmic_init); - -static void __exit max77686_pmic_cleanup(void) -{ - platform_driver_unregister(&max77686_pmic_driver); -} -module_exit(max77686_pmic_cleanup); - -MODULE_DESCRIPTION("MAXIM 77686 Regulator Driver"); -MODULE_AUTHOR("Chiwoong Byun "); -MODULE_LICENSE("GPL"); diff --git a/drivers/regulator/max77802-regulator.c b/drivers/regulator/max77802-regulator.c new file mode 100644 index 0000000..c07ee13 --- /dev/null +++ b/drivers/regulator/max77802-regulator.c @@ -0,0 +1,610 @@ +/* + * max77802.c - Regulator driver for the Maxim 77802 + * + * Copyright (C) 2013-2014 Google, Inc + * Simon Glass + * + * Copyright (C) 2012 Samsung Electronics + * Chiwoong Byun + * Jonghwa Lee + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * This driver is based on max8997.c + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Default ramp delay in case it is not manually set */ +#define MAX77802_RAMP_DELAY 100000 /* uV/us */ + +#define MAX77802_OPMODE_SHIFT_LDO 6 +#define MAX77802_OPMODE_BUCK234_SHIFT 4 +#define MAX77802_OPMODE_MASK 0x3 + +#define MAX77802_VSEL_MASK 0x3F +#define MAX77802_DVS_VSEL_MASK 0xFF + +#define MAX77802_RAMP_RATE_MASK_2BIT 0xC0 +#define MAX77802_RAMP_RATE_SHIFT_2BIT 6 +#define MAX77802_RAMP_RATE_MASK_4BIT 0xF0 +#define MAX77802_RAMP_RATE_SHIFT_4BIT 4 + +#define MAX77802_STATUS_OFF 0x0 +#define MAX77802_OFF_PWRREQ 0x1 +#define MAX77802_LP_PWRREQ 0x2 + +/* MAX77802 has two register formats: 2-bit and 4-bit */ +static const unsigned int ramp_table_77802_2bit[] = { + 12500, + 25000, + 50000, + 100000, +}; + +static unsigned int ramp_table_77802_4bit[] = { + 1000, 2000, 3030, 4000, + 5000, 5880, 7140, 8330, + 9090, 10000, 11110, 12500, + 16670, 25000, 50000, 100000, +}; + +struct max77802_regulator_prv { + /* Array indexed by regulator id */ + unsigned int opmode[MAX77802_REG_MAX]; +}; + +static inline unsigned int max77802_map_mode(unsigned int mode) +{ + return mode == MAX77802_OPMODE_NORMAL ? + REGULATOR_MODE_NORMAL : REGULATOR_MODE_STANDBY; +} + +static int max77802_get_opmode_shift(int id) +{ + if (id == MAX77802_BUCK1 || (id >= MAX77802_BUCK5 && + id <= MAX77802_BUCK10)) + return 0; + + if (id >= MAX77802_BUCK2 && id <= MAX77802_BUCK4) + return MAX77802_OPMODE_BUCK234_SHIFT; + + if (id >= MAX77802_LDO1 && id <= MAX77802_LDO35) + return MAX77802_OPMODE_SHIFT_LDO; + + return -EINVAL; +} + +/** + * max77802_set_suspend_disable - Disable the regulator during system suspend + * @rdev: regulator to mark as disabled + * + * All regulators expect LDO 1, 3, 20 and 21 support OFF by PWRREQ. + * Configure the regulator so the PMIC will turn it OFF during system suspend. + */ +static int max77802_set_suspend_disable(struct regulator_dev *rdev) +{ + unsigned int val = MAX77802_OFF_PWRREQ; + struct max77802_regulator_prv *max77802 = rdev_get_drvdata(rdev); + int id = rdev_get_id(rdev); + int shift = max77802_get_opmode_shift(id); + + max77802->opmode[id] = val; + return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, + rdev->desc->enable_mask, val << shift); +} + +/* + * Some LDOs support Low Power Mode while the system is running. + * + * LDOs 1, 3, 20, 21. + */ +static int max77802_set_mode(struct regulator_dev *rdev, unsigned int mode) +{ + struct max77802_regulator_prv *max77802 = rdev_get_drvdata(rdev); + int id = rdev_get_id(rdev); + unsigned int val; + int shift = max77802_get_opmode_shift(id); + + switch (mode) { + case REGULATOR_MODE_STANDBY: + val = MAX77802_OPMODE_LP; /* ON in Low Power Mode */ + break; + case REGULATOR_MODE_NORMAL: + val = MAX77802_OPMODE_NORMAL; /* ON in Normal Mode */ + break; + default: + dev_warn(&rdev->dev, "%s: regulator mode: 0x%x not supported\n", + rdev->desc->name, mode); + return -EINVAL; + } + + max77802->opmode[id] = val; + return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, + rdev->desc->enable_mask, val << shift); +} + +static unsigned max77802_get_mode(struct regulator_dev *rdev) +{ + struct max77802_regulator_prv *max77802 = rdev_get_drvdata(rdev); + int id = rdev_get_id(rdev); + + return max77802_map_mode(max77802->opmode[id]); +} + +/** + * max77802_set_suspend_mode - set regulator opmode when the system is suspended + * @rdev: regulator to change mode + * @mode: operating mode to be set + * + * Will set the operating mode for the regulators during system suspend. + * This function is valid for the three different enable control logics: + * + * Enable Control Logic1 by PWRREQ (BUCK 2-4 and LDOs 2, 4-19, 22-35) + * Enable Control Logic2 by PWRREQ (LDOs 1, 20, 21) + * Enable Control Logic3 by PWRREQ (LDO 3) + * + * If setting the regulator mode fails, the function only warns but does + * not return an error code to avoid the regulator core to stop setting + * the operating mode for the remaining regulators. + */ +static int max77802_set_suspend_mode(struct regulator_dev *rdev, + unsigned int mode) +{ + struct max77802_regulator_prv *max77802 = rdev_get_drvdata(rdev); + int id = rdev_get_id(rdev); + unsigned int val; + int shift = max77802_get_opmode_shift(id); + + /* + * If the regulator has been disabled for suspend + * then is invalid to try setting a suspend mode. + */ + if (max77802->opmode[id] == MAX77802_OFF_PWRREQ) { + dev_warn(&rdev->dev, "%s: is disabled, mode: 0x%x not set\n", + rdev->desc->name, mode); + return 0; + } + + switch (mode) { + case REGULATOR_MODE_STANDBY: + /* + * If the regulator opmode is normal then enable + * ON in Low Power Mode by PWRREQ. If the mode is + * already Low Power then no action is required. + */ + if (max77802->opmode[id] == MAX77802_OPMODE_NORMAL) + val = MAX77802_LP_PWRREQ; + else + return 0; + break; + case REGULATOR_MODE_NORMAL: + /* + * If the regulator operating mode is Low Power then + * normal is not a valid opmode in suspend. If the + * mode is already normal then no action is required. + */ + if (max77802->opmode[id] == MAX77802_OPMODE_LP) + dev_warn(&rdev->dev, "%s: in Low Power: 0x%x invalid\n", + rdev->desc->name, mode); + return 0; + default: + dev_warn(&rdev->dev, "%s: regulator mode: 0x%x not supported\n", + rdev->desc->name, mode); + return -EINVAL; + } + + return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, + rdev->desc->enable_mask, val << shift); +} + +static int max77802_enable(struct regulator_dev *rdev) +{ + struct max77802_regulator_prv *max77802 = rdev_get_drvdata(rdev); + int id = rdev_get_id(rdev); + int shift = max77802_get_opmode_shift(id); + + if (max77802->opmode[id] == MAX77802_OFF_PWRREQ) + max77802->opmode[id] = MAX77802_OPMODE_NORMAL; + + return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, + rdev->desc->enable_mask, + max77802->opmode[id] << shift); +} + +static int max77802_find_ramp_value(struct regulator_dev *rdev, + const unsigned int limits[], int size, + unsigned int ramp_delay) +{ + int i; + + for (i = 0; i < size; i++) { + if (ramp_delay <= limits[i]) + return i; + } + + /* Use maximum value for no ramp control */ + dev_warn(&rdev->dev, "%s: ramp_delay: %d not supported, setting 100000\n", + rdev->desc->name, ramp_delay); + return size - 1; +} + +/* Used for BUCKs 2-4 */ +static int max77802_set_ramp_delay_2bit(struct regulator_dev *rdev, + int ramp_delay) +{ + int id = rdev_get_id(rdev); + unsigned int ramp_value; + + if (id > MAX77802_BUCK4) { + dev_warn(&rdev->dev, + "%s: regulator: ramp delay not supported\n", + rdev->desc->name); + return -EINVAL; + } + ramp_value = max77802_find_ramp_value(rdev, ramp_table_77802_2bit, + ARRAY_SIZE(ramp_table_77802_2bit), ramp_delay); + + return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, + MAX77802_RAMP_RATE_MASK_2BIT, + ramp_value << MAX77802_RAMP_RATE_SHIFT_2BIT); +} + +/* For BUCK1, 6 */ +static int max77802_set_ramp_delay_4bit(struct regulator_dev *rdev, + int ramp_delay) +{ + unsigned int ramp_value; + + ramp_value = max77802_find_ramp_value(rdev, ramp_table_77802_4bit, + ARRAY_SIZE(ramp_table_77802_4bit), ramp_delay); + + return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, + MAX77802_RAMP_RATE_MASK_4BIT, + ramp_value << MAX77802_RAMP_RATE_SHIFT_4BIT); +} + +/* + * LDOs 2, 4-19, 22-35 + */ +static struct regulator_ops max77802_ldo_ops_logic1 = { + .list_voltage = regulator_list_voltage_linear, + .map_voltage = regulator_map_voltage_linear, + .is_enabled = regulator_is_enabled_regmap, + .enable = max77802_enable, + .disable = regulator_disable_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .set_voltage_time_sel = regulator_set_voltage_time_sel, + .set_suspend_disable = max77802_set_suspend_disable, + .set_suspend_mode = max77802_set_suspend_mode, +}; + +/* + * LDOs 1, 20, 21, 3 + */ +static struct regulator_ops max77802_ldo_ops_logic2 = { + .list_voltage = regulator_list_voltage_linear, + .map_voltage = regulator_map_voltage_linear, + .is_enabled = regulator_is_enabled_regmap, + .enable = max77802_enable, + .disable = regulator_disable_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .set_voltage_time_sel = regulator_set_voltage_time_sel, + .set_mode = max77802_set_mode, + .get_mode = max77802_get_mode, + .set_suspend_mode = max77802_set_suspend_mode, +}; + +/* BUCKS 1, 6 */ +static struct regulator_ops max77802_buck_16_dvs_ops = { + .list_voltage = regulator_list_voltage_linear, + .map_voltage = regulator_map_voltage_linear, + .is_enabled = regulator_is_enabled_regmap, + .enable = max77802_enable, + .disable = regulator_disable_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .set_voltage_time_sel = regulator_set_voltage_time_sel, + .set_ramp_delay = max77802_set_ramp_delay_4bit, + .set_suspend_disable = max77802_set_suspend_disable, +}; + +/* BUCKs 2-4 */ +static struct regulator_ops max77802_buck_234_ops = { + .list_voltage = regulator_list_voltage_linear, + .map_voltage = regulator_map_voltage_linear, + .is_enabled = regulator_is_enabled_regmap, + .enable = max77802_enable, + .disable = regulator_disable_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .set_voltage_time_sel = regulator_set_voltage_time_sel, + .set_ramp_delay = max77802_set_ramp_delay_2bit, + .set_suspend_disable = max77802_set_suspend_disable, + .set_suspend_mode = max77802_set_suspend_mode, +}; + +/* BUCKs 5, 7-10 */ +static struct regulator_ops max77802_buck_dvs_ops = { + .list_voltage = regulator_list_voltage_linear, + .map_voltage = regulator_map_voltage_linear, + .is_enabled = regulator_is_enabled_regmap, + .enable = max77802_enable, + .disable = regulator_disable_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .set_voltage_time_sel = regulator_set_voltage_time_sel, + .set_ramp_delay = max77802_set_ramp_delay_2bit, + .set_suspend_disable = max77802_set_suspend_disable, +}; + +/* LDOs 3-7, 9-14, 18-26, 28, 29, 32-34 */ +#define regulator_77802_desc_p_ldo(num, supply, log) { \ + .name = "LDO"#num, \ + .of_match = of_match_ptr("LDO"#num), \ + .regulators_node = of_match_ptr("regulators"), \ + .id = MAX77802_LDO##num, \ + .supply_name = "inl"#supply, \ + .ops = &max77802_ldo_ops_logic##log, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + .min_uV = 800000, \ + .uV_step = 50000, \ + .ramp_delay = MAX77802_RAMP_DELAY, \ + .n_voltages = 1 << 6, \ + .vsel_reg = MAX77802_REG_LDO1CTRL1 + num - 1, \ + .vsel_mask = MAX77802_VSEL_MASK, \ + .enable_reg = MAX77802_REG_LDO1CTRL1 + num - 1, \ + .enable_mask = MAX77802_OPMODE_MASK << MAX77802_OPMODE_SHIFT_LDO, \ + .of_map_mode = max77802_map_mode, \ +} + +/* LDOs 1, 2, 8, 15, 17, 27, 30, 35 */ +#define regulator_77802_desc_n_ldo(num, supply, log) { \ + .name = "LDO"#num, \ + .of_match = of_match_ptr("LDO"#num), \ + .regulators_node = of_match_ptr("regulators"), \ + .id = MAX77802_LDO##num, \ + .supply_name = "inl"#supply, \ + .ops = &max77802_ldo_ops_logic##log, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + .min_uV = 800000, \ + .uV_step = 25000, \ + .ramp_delay = MAX77802_RAMP_DELAY, \ + .n_voltages = 1 << 6, \ + .vsel_reg = MAX77802_REG_LDO1CTRL1 + num - 1, \ + .vsel_mask = MAX77802_VSEL_MASK, \ + .enable_reg = MAX77802_REG_LDO1CTRL1 + num - 1, \ + .enable_mask = MAX77802_OPMODE_MASK << MAX77802_OPMODE_SHIFT_LDO, \ + .of_map_mode = max77802_map_mode, \ +} + +/* BUCKs 1, 6 */ +#define regulator_77802_desc_16_buck(num) { \ + .name = "BUCK"#num, \ + .of_match = of_match_ptr("BUCK"#num), \ + .regulators_node = of_match_ptr("regulators"), \ + .id = MAX77802_BUCK##num, \ + .supply_name = "inb"#num, \ + .ops = &max77802_buck_16_dvs_ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + .min_uV = 612500, \ + .uV_step = 6250, \ + .ramp_delay = MAX77802_RAMP_DELAY, \ + .n_voltages = 1 << 8, \ + .vsel_reg = MAX77802_REG_BUCK ## num ## DVS1, \ + .vsel_mask = MAX77802_DVS_VSEL_MASK, \ + .enable_reg = MAX77802_REG_BUCK ## num ## CTRL, \ + .enable_mask = MAX77802_OPMODE_MASK, \ + .of_map_mode = max77802_map_mode, \ +} + +/* BUCKS 2-4 */ +#define regulator_77802_desc_234_buck(num) { \ + .name = "BUCK"#num, \ + .of_match = of_match_ptr("BUCK"#num), \ + .regulators_node = of_match_ptr("regulators"), \ + .id = MAX77802_BUCK##num, \ + .supply_name = "inb"#num, \ + .ops = &max77802_buck_234_ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + .min_uV = 600000, \ + .uV_step = 6250, \ + .ramp_delay = MAX77802_RAMP_DELAY, \ + .n_voltages = 0x91, \ + .vsel_reg = MAX77802_REG_BUCK ## num ## DVS1, \ + .vsel_mask = MAX77802_DVS_VSEL_MASK, \ + .enable_reg = MAX77802_REG_BUCK ## num ## CTRL1, \ + .enable_mask = MAX77802_OPMODE_MASK << \ + MAX77802_OPMODE_BUCK234_SHIFT, \ + .of_map_mode = max77802_map_mode, \ +} + +/* BUCK 5 */ +#define regulator_77802_desc_buck5(num) { \ + .name = "BUCK"#num, \ + .of_match = of_match_ptr("BUCK"#num), \ + .regulators_node = of_match_ptr("regulators"), \ + .id = MAX77802_BUCK##num, \ + .supply_name = "inb"#num, \ + .ops = &max77802_buck_dvs_ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + .min_uV = 750000, \ + .uV_step = 50000, \ + .ramp_delay = MAX77802_RAMP_DELAY, \ + .n_voltages = 1 << 6, \ + .vsel_reg = MAX77802_REG_BUCK5OUT, \ + .vsel_mask = MAX77802_VSEL_MASK, \ + .enable_reg = MAX77802_REG_BUCK5CTRL, \ + .enable_mask = MAX77802_OPMODE_MASK, \ + .of_map_mode = max77802_map_mode, \ +} + +/* BUCKs 7-10 */ +#define regulator_77802_desc_buck7_10(num) { \ + .name = "BUCK"#num, \ + .of_match = of_match_ptr("BUCK"#num), \ + .regulators_node = of_match_ptr("regulators"), \ + .id = MAX77802_BUCK##num, \ + .supply_name = "inb"#num, \ + .ops = &max77802_buck_dvs_ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + .min_uV = 750000, \ + .uV_step = 50000, \ + .ramp_delay = MAX77802_RAMP_DELAY, \ + .n_voltages = 1 << 6, \ + .vsel_reg = MAX77802_REG_BUCK7OUT + (num - 7) * 3, \ + .vsel_mask = MAX77802_VSEL_MASK, \ + .enable_reg = MAX77802_REG_BUCK7CTRL + (num - 7) * 3, \ + .enable_mask = MAX77802_OPMODE_MASK, \ + .of_map_mode = max77802_map_mode, \ +} + +static const struct regulator_desc regulators[] = { + regulator_77802_desc_16_buck(1), + regulator_77802_desc_234_buck(2), + regulator_77802_desc_234_buck(3), + regulator_77802_desc_234_buck(4), + regulator_77802_desc_buck5(5), + regulator_77802_desc_16_buck(6), + regulator_77802_desc_buck7_10(7), + regulator_77802_desc_buck7_10(8), + regulator_77802_desc_buck7_10(9), + regulator_77802_desc_buck7_10(10), + regulator_77802_desc_n_ldo(1, 10, 2), + regulator_77802_desc_n_ldo(2, 10, 1), + regulator_77802_desc_p_ldo(3, 3, 2), + regulator_77802_desc_p_ldo(4, 6, 1), + regulator_77802_desc_p_ldo(5, 3, 1), + regulator_77802_desc_p_ldo(6, 3, 1), + regulator_77802_desc_p_ldo(7, 3, 1), + regulator_77802_desc_n_ldo(8, 1, 1), + regulator_77802_desc_p_ldo(9, 5, 1), + regulator_77802_desc_p_ldo(10, 4, 1), + regulator_77802_desc_p_ldo(11, 4, 1), + regulator_77802_desc_p_ldo(12, 9, 1), + regulator_77802_desc_p_ldo(13, 4, 1), + regulator_77802_desc_p_ldo(14, 4, 1), + regulator_77802_desc_n_ldo(15, 1, 1), + regulator_77802_desc_n_ldo(17, 2, 1), + regulator_77802_desc_p_ldo(18, 7, 1), + regulator_77802_desc_p_ldo(19, 5, 1), + regulator_77802_desc_p_ldo(20, 7, 2), + regulator_77802_desc_p_ldo(21, 6, 2), + regulator_77802_desc_p_ldo(23, 9, 1), + regulator_77802_desc_p_ldo(24, 6, 1), + regulator_77802_desc_p_ldo(25, 9, 1), + regulator_77802_desc_p_ldo(26, 9, 1), + regulator_77802_desc_n_ldo(27, 2, 1), + regulator_77802_desc_p_ldo(28, 7, 1), + regulator_77802_desc_p_ldo(29, 7, 1), + regulator_77802_desc_n_ldo(30, 2, 1), + regulator_77802_desc_p_ldo(32, 9, 1), + regulator_77802_desc_p_ldo(33, 6, 1), + regulator_77802_desc_p_ldo(34, 9, 1), + regulator_77802_desc_n_ldo(35, 2, 1), +}; + +static int max77802_pmic_probe(struct platform_device *pdev) +{ + struct max77686_dev *iodev = dev_get_drvdata(pdev->dev.parent); + struct max77802_regulator_prv *max77802; + int i, val; + struct regulator_config config = { }; + + max77802 = devm_kzalloc(&pdev->dev, + sizeof(struct max77802_regulator_prv), + GFP_KERNEL); + if (!max77802) + return -ENOMEM; + + config.dev = iodev->dev; + config.regmap = iodev->regmap; + config.driver_data = max77802; + platform_set_drvdata(pdev, max77802); + + for (i = 0; i < MAX77802_REG_MAX; i++) { + struct regulator_dev *rdev; + int id = regulators[i].id; + int shift = max77802_get_opmode_shift(id); + int ret; + + ret = regmap_read(iodev->regmap, regulators[i].enable_reg, &val); + if (ret < 0) { + dev_warn(&pdev->dev, + "cannot read current mode for %d\n", i); + val = MAX77802_OPMODE_NORMAL; + } else { + val = val >> shift & MAX77802_OPMODE_MASK; + } + + /* + * If the regulator is disabled and the system warm rebooted, + * the hardware reports OFF as the regulator operating mode. + * Default to operating mode NORMAL in that case. + */ + if (val == MAX77802_STATUS_OFF) + max77802->opmode[id] = MAX77802_OPMODE_NORMAL; + else + max77802->opmode[id] = val; + + rdev = devm_regulator_register(&pdev->dev, + ®ulators[i], &config); + if (IS_ERR(rdev)) { + ret = PTR_ERR(rdev); + dev_err(&pdev->dev, + "regulator init failed for %d: %d\n", i, ret); + return ret; + } + } + + return 0; +} + +static const struct platform_device_id max77802_pmic_id[] = { + {"max77802-pmic", 0}, + { }, +}; +MODULE_DEVICE_TABLE(platform, max77802_pmic_id); + +static struct platform_driver max77802_pmic_driver = { + .driver = { + .name = "max77802-pmic", + }, + .probe = max77802_pmic_probe, + .id_table = max77802_pmic_id, +}; + +module_platform_driver(max77802_pmic_driver); + +MODULE_DESCRIPTION("MAXIM 77802 Regulator Driver"); +MODULE_AUTHOR("Simon Glass "); +MODULE_LICENSE("GPL"); diff --git a/drivers/regulator/max77802.c b/drivers/regulator/max77802.c deleted file mode 100644 index c07ee13..0000000 --- a/drivers/regulator/max77802.c +++ /dev/null @@ -1,610 +0,0 @@ -/* - * max77802.c - Regulator driver for the Maxim 77802 - * - * Copyright (C) 2013-2014 Google, Inc - * Simon Glass - * - * Copyright (C) 2012 Samsung Electronics - * Chiwoong Byun - * Jonghwa Lee - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * This driver is based on max8997.c - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* Default ramp delay in case it is not manually set */ -#define MAX77802_RAMP_DELAY 100000 /* uV/us */ - -#define MAX77802_OPMODE_SHIFT_LDO 6 -#define MAX77802_OPMODE_BUCK234_SHIFT 4 -#define MAX77802_OPMODE_MASK 0x3 - -#define MAX77802_VSEL_MASK 0x3F -#define MAX77802_DVS_VSEL_MASK 0xFF - -#define MAX77802_RAMP_RATE_MASK_2BIT 0xC0 -#define MAX77802_RAMP_RATE_SHIFT_2BIT 6 -#define MAX77802_RAMP_RATE_MASK_4BIT 0xF0 -#define MAX77802_RAMP_RATE_SHIFT_4BIT 4 - -#define MAX77802_STATUS_OFF 0x0 -#define MAX77802_OFF_PWRREQ 0x1 -#define MAX77802_LP_PWRREQ 0x2 - -/* MAX77802 has two register formats: 2-bit and 4-bit */ -static const unsigned int ramp_table_77802_2bit[] = { - 12500, - 25000, - 50000, - 100000, -}; - -static unsigned int ramp_table_77802_4bit[] = { - 1000, 2000, 3030, 4000, - 5000, 5880, 7140, 8330, - 9090, 10000, 11110, 12500, - 16670, 25000, 50000, 100000, -}; - -struct max77802_regulator_prv { - /* Array indexed by regulator id */ - unsigned int opmode[MAX77802_REG_MAX]; -}; - -static inline unsigned int max77802_map_mode(unsigned int mode) -{ - return mode == MAX77802_OPMODE_NORMAL ? - REGULATOR_MODE_NORMAL : REGULATOR_MODE_STANDBY; -} - -static int max77802_get_opmode_shift(int id) -{ - if (id == MAX77802_BUCK1 || (id >= MAX77802_BUCK5 && - id <= MAX77802_BUCK10)) - return 0; - - if (id >= MAX77802_BUCK2 && id <= MAX77802_BUCK4) - return MAX77802_OPMODE_BUCK234_SHIFT; - - if (id >= MAX77802_LDO1 && id <= MAX77802_LDO35) - return MAX77802_OPMODE_SHIFT_LDO; - - return -EINVAL; -} - -/** - * max77802_set_suspend_disable - Disable the regulator during system suspend - * @rdev: regulator to mark as disabled - * - * All regulators expect LDO 1, 3, 20 and 21 support OFF by PWRREQ. - * Configure the regulator so the PMIC will turn it OFF during system suspend. - */ -static int max77802_set_suspend_disable(struct regulator_dev *rdev) -{ - unsigned int val = MAX77802_OFF_PWRREQ; - struct max77802_regulator_prv *max77802 = rdev_get_drvdata(rdev); - int id = rdev_get_id(rdev); - int shift = max77802_get_opmode_shift(id); - - max77802->opmode[id] = val; - return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, - rdev->desc->enable_mask, val << shift); -} - -/* - * Some LDOs support Low Power Mode while the system is running. - * - * LDOs 1, 3, 20, 21. - */ -static int max77802_set_mode(struct regulator_dev *rdev, unsigned int mode) -{ - struct max77802_regulator_prv *max77802 = rdev_get_drvdata(rdev); - int id = rdev_get_id(rdev); - unsigned int val; - int shift = max77802_get_opmode_shift(id); - - switch (mode) { - case REGULATOR_MODE_STANDBY: - val = MAX77802_OPMODE_LP; /* ON in Low Power Mode */ - break; - case REGULATOR_MODE_NORMAL: - val = MAX77802_OPMODE_NORMAL; /* ON in Normal Mode */ - break; - default: - dev_warn(&rdev->dev, "%s: regulator mode: 0x%x not supported\n", - rdev->desc->name, mode); - return -EINVAL; - } - - max77802->opmode[id] = val; - return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, - rdev->desc->enable_mask, val << shift); -} - -static unsigned max77802_get_mode(struct regulator_dev *rdev) -{ - struct max77802_regulator_prv *max77802 = rdev_get_drvdata(rdev); - int id = rdev_get_id(rdev); - - return max77802_map_mode(max77802->opmode[id]); -} - -/** - * max77802_set_suspend_mode - set regulator opmode when the system is suspended - * @rdev: regulator to change mode - * @mode: operating mode to be set - * - * Will set the operating mode for the regulators during system suspend. - * This function is valid for the three different enable control logics: - * - * Enable Control Logic1 by PWRREQ (BUCK 2-4 and LDOs 2, 4-19, 22-35) - * Enable Control Logic2 by PWRREQ (LDOs 1, 20, 21) - * Enable Control Logic3 by PWRREQ (LDO 3) - * - * If setting the regulator mode fails, the function only warns but does - * not return an error code to avoid the regulator core to stop setting - * the operating mode for the remaining regulators. - */ -static int max77802_set_suspend_mode(struct regulator_dev *rdev, - unsigned int mode) -{ - struct max77802_regulator_prv *max77802 = rdev_get_drvdata(rdev); - int id = rdev_get_id(rdev); - unsigned int val; - int shift = max77802_get_opmode_shift(id); - - /* - * If the regulator has been disabled for suspend - * then is invalid to try setting a suspend mode. - */ - if (max77802->opmode[id] == MAX77802_OFF_PWRREQ) { - dev_warn(&rdev->dev, "%s: is disabled, mode: 0x%x not set\n", - rdev->desc->name, mode); - return 0; - } - - switch (mode) { - case REGULATOR_MODE_STANDBY: - /* - * If the regulator opmode is normal then enable - * ON in Low Power Mode by PWRREQ. If the mode is - * already Low Power then no action is required. - */ - if (max77802->opmode[id] == MAX77802_OPMODE_NORMAL) - val = MAX77802_LP_PWRREQ; - else - return 0; - break; - case REGULATOR_MODE_NORMAL: - /* - * If the regulator operating mode is Low Power then - * normal is not a valid opmode in suspend. If the - * mode is already normal then no action is required. - */ - if (max77802->opmode[id] == MAX77802_OPMODE_LP) - dev_warn(&rdev->dev, "%s: in Low Power: 0x%x invalid\n", - rdev->desc->name, mode); - return 0; - default: - dev_warn(&rdev->dev, "%s: regulator mode: 0x%x not supported\n", - rdev->desc->name, mode); - return -EINVAL; - } - - return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, - rdev->desc->enable_mask, val << shift); -} - -static int max77802_enable(struct regulator_dev *rdev) -{ - struct max77802_regulator_prv *max77802 = rdev_get_drvdata(rdev); - int id = rdev_get_id(rdev); - int shift = max77802_get_opmode_shift(id); - - if (max77802->opmode[id] == MAX77802_OFF_PWRREQ) - max77802->opmode[id] = MAX77802_OPMODE_NORMAL; - - return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, - rdev->desc->enable_mask, - max77802->opmode[id] << shift); -} - -static int max77802_find_ramp_value(struct regulator_dev *rdev, - const unsigned int limits[], int size, - unsigned int ramp_delay) -{ - int i; - - for (i = 0; i < size; i++) { - if (ramp_delay <= limits[i]) - return i; - } - - /* Use maximum value for no ramp control */ - dev_warn(&rdev->dev, "%s: ramp_delay: %d not supported, setting 100000\n", - rdev->desc->name, ramp_delay); - return size - 1; -} - -/* Used for BUCKs 2-4 */ -static int max77802_set_ramp_delay_2bit(struct regulator_dev *rdev, - int ramp_delay) -{ - int id = rdev_get_id(rdev); - unsigned int ramp_value; - - if (id > MAX77802_BUCK4) { - dev_warn(&rdev->dev, - "%s: regulator: ramp delay not supported\n", - rdev->desc->name); - return -EINVAL; - } - ramp_value = max77802_find_ramp_value(rdev, ramp_table_77802_2bit, - ARRAY_SIZE(ramp_table_77802_2bit), ramp_delay); - - return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, - MAX77802_RAMP_RATE_MASK_2BIT, - ramp_value << MAX77802_RAMP_RATE_SHIFT_2BIT); -} - -/* For BUCK1, 6 */ -static int max77802_set_ramp_delay_4bit(struct regulator_dev *rdev, - int ramp_delay) -{ - unsigned int ramp_value; - - ramp_value = max77802_find_ramp_value(rdev, ramp_table_77802_4bit, - ARRAY_SIZE(ramp_table_77802_4bit), ramp_delay); - - return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, - MAX77802_RAMP_RATE_MASK_4BIT, - ramp_value << MAX77802_RAMP_RATE_SHIFT_4BIT); -} - -/* - * LDOs 2, 4-19, 22-35 - */ -static struct regulator_ops max77802_ldo_ops_logic1 = { - .list_voltage = regulator_list_voltage_linear, - .map_voltage = regulator_map_voltage_linear, - .is_enabled = regulator_is_enabled_regmap, - .enable = max77802_enable, - .disable = regulator_disable_regmap, - .get_voltage_sel = regulator_get_voltage_sel_regmap, - .set_voltage_sel = regulator_set_voltage_sel_regmap, - .set_voltage_time_sel = regulator_set_voltage_time_sel, - .set_suspend_disable = max77802_set_suspend_disable, - .set_suspend_mode = max77802_set_suspend_mode, -}; - -/* - * LDOs 1, 20, 21, 3 - */ -static struct regulator_ops max77802_ldo_ops_logic2 = { - .list_voltage = regulator_list_voltage_linear, - .map_voltage = regulator_map_voltage_linear, - .is_enabled = regulator_is_enabled_regmap, - .enable = max77802_enable, - .disable = regulator_disable_regmap, - .get_voltage_sel = regulator_get_voltage_sel_regmap, - .set_voltage_sel = regulator_set_voltage_sel_regmap, - .set_voltage_time_sel = regulator_set_voltage_time_sel, - .set_mode = max77802_set_mode, - .get_mode = max77802_get_mode, - .set_suspend_mode = max77802_set_suspend_mode, -}; - -/* BUCKS 1, 6 */ -static struct regulator_ops max77802_buck_16_dvs_ops = { - .list_voltage = regulator_list_voltage_linear, - .map_voltage = regulator_map_voltage_linear, - .is_enabled = regulator_is_enabled_regmap, - .enable = max77802_enable, - .disable = regulator_disable_regmap, - .get_voltage_sel = regulator_get_voltage_sel_regmap, - .set_voltage_sel = regulator_set_voltage_sel_regmap, - .set_voltage_time_sel = regulator_set_voltage_time_sel, - .set_ramp_delay = max77802_set_ramp_delay_4bit, - .set_suspend_disable = max77802_set_suspend_disable, -}; - -/* BUCKs 2-4 */ -static struct regulator_ops max77802_buck_234_ops = { - .list_voltage = regulator_list_voltage_linear, - .map_voltage = regulator_map_voltage_linear, - .is_enabled = regulator_is_enabled_regmap, - .enable = max77802_enable, - .disable = regulator_disable_regmap, - .get_voltage_sel = regulator_get_voltage_sel_regmap, - .set_voltage_sel = regulator_set_voltage_sel_regmap, - .set_voltage_time_sel = regulator_set_voltage_time_sel, - .set_ramp_delay = max77802_set_ramp_delay_2bit, - .set_suspend_disable = max77802_set_suspend_disable, - .set_suspend_mode = max77802_set_suspend_mode, -}; - -/* BUCKs 5, 7-10 */ -static struct regulator_ops max77802_buck_dvs_ops = { - .list_voltage = regulator_list_voltage_linear, - .map_voltage = regulator_map_voltage_linear, - .is_enabled = regulator_is_enabled_regmap, - .enable = max77802_enable, - .disable = regulator_disable_regmap, - .get_voltage_sel = regulator_get_voltage_sel_regmap, - .set_voltage_sel = regulator_set_voltage_sel_regmap, - .set_voltage_time_sel = regulator_set_voltage_time_sel, - .set_ramp_delay = max77802_set_ramp_delay_2bit, - .set_suspend_disable = max77802_set_suspend_disable, -}; - -/* LDOs 3-7, 9-14, 18-26, 28, 29, 32-34 */ -#define regulator_77802_desc_p_ldo(num, supply, log) { \ - .name = "LDO"#num, \ - .of_match = of_match_ptr("LDO"#num), \ - .regulators_node = of_match_ptr("regulators"), \ - .id = MAX77802_LDO##num, \ - .supply_name = "inl"#supply, \ - .ops = &max77802_ldo_ops_logic##log, \ - .type = REGULATOR_VOLTAGE, \ - .owner = THIS_MODULE, \ - .min_uV = 800000, \ - .uV_step = 50000, \ - .ramp_delay = MAX77802_RAMP_DELAY, \ - .n_voltages = 1 << 6, \ - .vsel_reg = MAX77802_REG_LDO1CTRL1 + num - 1, \ - .vsel_mask = MAX77802_VSEL_MASK, \ - .enable_reg = MAX77802_REG_LDO1CTRL1 + num - 1, \ - .enable_mask = MAX77802_OPMODE_MASK << MAX77802_OPMODE_SHIFT_LDO, \ - .of_map_mode = max77802_map_mode, \ -} - -/* LDOs 1, 2, 8, 15, 17, 27, 30, 35 */ -#define regulator_77802_desc_n_ldo(num, supply, log) { \ - .name = "LDO"#num, \ - .of_match = of_match_ptr("LDO"#num), \ - .regulators_node = of_match_ptr("regulators"), \ - .id = MAX77802_LDO##num, \ - .supply_name = "inl"#supply, \ - .ops = &max77802_ldo_ops_logic##log, \ - .type = REGULATOR_VOLTAGE, \ - .owner = THIS_MODULE, \ - .min_uV = 800000, \ - .uV_step = 25000, \ - .ramp_delay = MAX77802_RAMP_DELAY, \ - .n_voltages = 1 << 6, \ - .vsel_reg = MAX77802_REG_LDO1CTRL1 + num - 1, \ - .vsel_mask = MAX77802_VSEL_MASK, \ - .enable_reg = MAX77802_REG_LDO1CTRL1 + num - 1, \ - .enable_mask = MAX77802_OPMODE_MASK << MAX77802_OPMODE_SHIFT_LDO, \ - .of_map_mode = max77802_map_mode, \ -} - -/* BUCKs 1, 6 */ -#define regulator_77802_desc_16_buck(num) { \ - .name = "BUCK"#num, \ - .of_match = of_match_ptr("BUCK"#num), \ - .regulators_node = of_match_ptr("regulators"), \ - .id = MAX77802_BUCK##num, \ - .supply_name = "inb"#num, \ - .ops = &max77802_buck_16_dvs_ops, \ - .type = REGULATOR_VOLTAGE, \ - .owner = THIS_MODULE, \ - .min_uV = 612500, \ - .uV_step = 6250, \ - .ramp_delay = MAX77802_RAMP_DELAY, \ - .n_voltages = 1 << 8, \ - .vsel_reg = MAX77802_REG_BUCK ## num ## DVS1, \ - .vsel_mask = MAX77802_DVS_VSEL_MASK, \ - .enable_reg = MAX77802_REG_BUCK ## num ## CTRL, \ - .enable_mask = MAX77802_OPMODE_MASK, \ - .of_map_mode = max77802_map_mode, \ -} - -/* BUCKS 2-4 */ -#define regulator_77802_desc_234_buck(num) { \ - .name = "BUCK"#num, \ - .of_match = of_match_ptr("BUCK"#num), \ - .regulators_node = of_match_ptr("regulators"), \ - .id = MAX77802_BUCK##num, \ - .supply_name = "inb"#num, \ - .ops = &max77802_buck_234_ops, \ - .type = REGULATOR_VOLTAGE, \ - .owner = THIS_MODULE, \ - .min_uV = 600000, \ - .uV_step = 6250, \ - .ramp_delay = MAX77802_RAMP_DELAY, \ - .n_voltages = 0x91, \ - .vsel_reg = MAX77802_REG_BUCK ## num ## DVS1, \ - .vsel_mask = MAX77802_DVS_VSEL_MASK, \ - .enable_reg = MAX77802_REG_BUCK ## num ## CTRL1, \ - .enable_mask = MAX77802_OPMODE_MASK << \ - MAX77802_OPMODE_BUCK234_SHIFT, \ - .of_map_mode = max77802_map_mode, \ -} - -/* BUCK 5 */ -#define regulator_77802_desc_buck5(num) { \ - .name = "BUCK"#num, \ - .of_match = of_match_ptr("BUCK"#num), \ - .regulators_node = of_match_ptr("regulators"), \ - .id = MAX77802_BUCK##num, \ - .supply_name = "inb"#num, \ - .ops = &max77802_buck_dvs_ops, \ - .type = REGULATOR_VOLTAGE, \ - .owner = THIS_MODULE, \ - .min_uV = 750000, \ - .uV_step = 50000, \ - .ramp_delay = MAX77802_RAMP_DELAY, \ - .n_voltages = 1 << 6, \ - .vsel_reg = MAX77802_REG_BUCK5OUT, \ - .vsel_mask = MAX77802_VSEL_MASK, \ - .enable_reg = MAX77802_REG_BUCK5CTRL, \ - .enable_mask = MAX77802_OPMODE_MASK, \ - .of_map_mode = max77802_map_mode, \ -} - -/* BUCKs 7-10 */ -#define regulator_77802_desc_buck7_10(num) { \ - .name = "BUCK"#num, \ - .of_match = of_match_ptr("BUCK"#num), \ - .regulators_node = of_match_ptr("regulators"), \ - .id = MAX77802_BUCK##num, \ - .supply_name = "inb"#num, \ - .ops = &max77802_buck_dvs_ops, \ - .type = REGULATOR_VOLTAGE, \ - .owner = THIS_MODULE, \ - .min_uV = 750000, \ - .uV_step = 50000, \ - .ramp_delay = MAX77802_RAMP_DELAY, \ - .n_voltages = 1 << 6, \ - .vsel_reg = MAX77802_REG_BUCK7OUT + (num - 7) * 3, \ - .vsel_mask = MAX77802_VSEL_MASK, \ - .enable_reg = MAX77802_REG_BUCK7CTRL + (num - 7) * 3, \ - .enable_mask = MAX77802_OPMODE_MASK, \ - .of_map_mode = max77802_map_mode, \ -} - -static const struct regulator_desc regulators[] = { - regulator_77802_desc_16_buck(1), - regulator_77802_desc_234_buck(2), - regulator_77802_desc_234_buck(3), - regulator_77802_desc_234_buck(4), - regulator_77802_desc_buck5(5), - regulator_77802_desc_16_buck(6), - regulator_77802_desc_buck7_10(7), - regulator_77802_desc_buck7_10(8), - regulator_77802_desc_buck7_10(9), - regulator_77802_desc_buck7_10(10), - regulator_77802_desc_n_ldo(1, 10, 2), - regulator_77802_desc_n_ldo(2, 10, 1), - regulator_77802_desc_p_ldo(3, 3, 2), - regulator_77802_desc_p_ldo(4, 6, 1), - regulator_77802_desc_p_ldo(5, 3, 1), - regulator_77802_desc_p_ldo(6, 3, 1), - regulator_77802_desc_p_ldo(7, 3, 1), - regulator_77802_desc_n_ldo(8, 1, 1), - regulator_77802_desc_p_ldo(9, 5, 1), - regulator_77802_desc_p_ldo(10, 4, 1), - regulator_77802_desc_p_ldo(11, 4, 1), - regulator_77802_desc_p_ldo(12, 9, 1), - regulator_77802_desc_p_ldo(13, 4, 1), - regulator_77802_desc_p_ldo(14, 4, 1), - regulator_77802_desc_n_ldo(15, 1, 1), - regulator_77802_desc_n_ldo(17, 2, 1), - regulator_77802_desc_p_ldo(18, 7, 1), - regulator_77802_desc_p_ldo(19, 5, 1), - regulator_77802_desc_p_ldo(20, 7, 2), - regulator_77802_desc_p_ldo(21, 6, 2), - regulator_77802_desc_p_ldo(23, 9, 1), - regulator_77802_desc_p_ldo(24, 6, 1), - regulator_77802_desc_p_ldo(25, 9, 1), - regulator_77802_desc_p_ldo(26, 9, 1), - regulator_77802_desc_n_ldo(27, 2, 1), - regulator_77802_desc_p_ldo(28, 7, 1), - regulator_77802_desc_p_ldo(29, 7, 1), - regulator_77802_desc_n_ldo(30, 2, 1), - regulator_77802_desc_p_ldo(32, 9, 1), - regulator_77802_desc_p_ldo(33, 6, 1), - regulator_77802_desc_p_ldo(34, 9, 1), - regulator_77802_desc_n_ldo(35, 2, 1), -}; - -static int max77802_pmic_probe(struct platform_device *pdev) -{ - struct max77686_dev *iodev = dev_get_drvdata(pdev->dev.parent); - struct max77802_regulator_prv *max77802; - int i, val; - struct regulator_config config = { }; - - max77802 = devm_kzalloc(&pdev->dev, - sizeof(struct max77802_regulator_prv), - GFP_KERNEL); - if (!max77802) - return -ENOMEM; - - config.dev = iodev->dev; - config.regmap = iodev->regmap; - config.driver_data = max77802; - platform_set_drvdata(pdev, max77802); - - for (i = 0; i < MAX77802_REG_MAX; i++) { - struct regulator_dev *rdev; - int id = regulators[i].id; - int shift = max77802_get_opmode_shift(id); - int ret; - - ret = regmap_read(iodev->regmap, regulators[i].enable_reg, &val); - if (ret < 0) { - dev_warn(&pdev->dev, - "cannot read current mode for %d\n", i); - val = MAX77802_OPMODE_NORMAL; - } else { - val = val >> shift & MAX77802_OPMODE_MASK; - } - - /* - * If the regulator is disabled and the system warm rebooted, - * the hardware reports OFF as the regulator operating mode. - * Default to operating mode NORMAL in that case. - */ - if (val == MAX77802_STATUS_OFF) - max77802->opmode[id] = MAX77802_OPMODE_NORMAL; - else - max77802->opmode[id] = val; - - rdev = devm_regulator_register(&pdev->dev, - ®ulators[i], &config); - if (IS_ERR(rdev)) { - ret = PTR_ERR(rdev); - dev_err(&pdev->dev, - "regulator init failed for %d: %d\n", i, ret); - return ret; - } - } - - return 0; -} - -static const struct platform_device_id max77802_pmic_id[] = { - {"max77802-pmic", 0}, - { }, -}; -MODULE_DEVICE_TABLE(platform, max77802_pmic_id); - -static struct platform_driver max77802_pmic_driver = { - .driver = { - .name = "max77802-pmic", - }, - .probe = max77802_pmic_probe, - .id_table = max77802_pmic_id, -}; - -module_platform_driver(max77802_pmic_driver); - -MODULE_DESCRIPTION("MAXIM 77802 Regulator Driver"); -MODULE_AUTHOR("Simon Glass "); -MODULE_LICENSE("GPL"); -- cgit v0.10.2 From d4930cf0ae33e944427f974f33bc43b8e6c56456 Mon Sep 17 00:00:00 2001 From: Bernhard Walle Date: Wed, 10 Feb 2016 21:37:30 +0100 Subject: regulator: ltc3589: Make IRQ optional It's perfectly valid to use the LTC3589 without an interrupt pin connected to it. Currently, the driver probing fails when client->irq is 0 (which means "no interrupt"). Don't register the interrupt handler in that case but successfully finish the device probing instead. Signed-off-by: Bernhard Walle Signed-off-by: Mark Brown diff --git a/drivers/regulator/ltc3589.c b/drivers/regulator/ltc3589.c index 972c386..47bef32 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; -- cgit v0.10.2 From 0998a436b1c2d8b7037c26736ee92417ca83d361 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Mon, 15 Feb 2016 11:24:58 -0300 Subject: regulator: max77686: Fix MAINTAINER entry to match driver The max77686 regulator driver was recently renamed to max77686-regulator but the entry in the MAINTAINERS file wasn't updated to match the driver. Reported-by: Krzysztof Kozlowski Signed-off-by: Javier Martinez Canillas Signed-off-by: Mark Brown diff --git a/MAINTAINERS b/MAINTAINERS index 30aca4a..b060628 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6913,7 +6913,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 -- cgit v0.10.2 From 004dd4e4c44e55bd41f20aff457c61b5a791818c Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Thu, 11 Feb 2016 17:26:33 +0530 Subject: regulator: add DT binding doc for regulator of PMIC max77620/max20024 Maxim Semiconductor's PMIC MAX77620/MAX20024 has multiple DCDCs and LDOs. Add DT binding document to support these regulators via regulator framework. Signed-off-by: Laxman Dewangan Acked-by: Rob Herring Signed-off-by: Mark Brown diff --git a/Documentation/devicetree/bindings/regulator/regulator-max77620.txt b/Documentation/devicetree/bindings/regulator/regulator-max77620.txt new file mode 100644 index 0000000..b3c8ca6 --- /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>; + }; + }; +}; -- cgit v0.10.2 From 5b1c20286fc962d8c19601b7378a4fc32be8fd9e Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Thu, 11 Feb 2016 17:26:34 +0530 Subject: regulator: max77620: add regulator driver for max77620/max20024 MAXIM Semiconductor's PMIC, MAX77620 and MAX20024 have the multiple DCDC and LDOs. This supplies the power to different components of the system. Also these rails has configuration for ramp time, flexible power sequence, slew rate etc. Add regulator driver to access these rails via regulator APIs. Signed-off-by: Laxman Dewangan Signed-off-by: Mallikarjun Kasoju Reviewed-by: Krzysztof Kozlowski Signed-off-by: Mark Brown diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 8155e80..b92214b 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -343,6 +343,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 980b194..2564c00 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -46,6 +46,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 diff --git a/drivers/regulator/max77620-regulator.c b/drivers/regulator/max77620-regulator.c new file mode 100644 index 0000000..fee8ad9 --- /dev/null +++ b/drivers/regulator/max77620-regulator.c @@ -0,0 +1,825 @@ +/* + * 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; + u32 min_uV; + u32 max_uV; + u32 step_uV; + u8 fps_addr; + u8 volt_addr; + u8 cfg_addr; + u8 volt_mask; + 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]; + struct regulator_desc *rdesc[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; + + switch (rinfo->type) { + case MAX77620_REGULATOR_TYPE_SD: + 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; + } + + 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: + 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; + } + 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, +}; + +#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_mask = MAX77620_##_volt_mask##_VOLT_MASK, \ + .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, \ + .min_uV = _min_uV, \ + .max_uV = _max_uV, \ + .step_uV = _step_uV, \ + .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, \ + .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_mask = MAX77620_LDO_VOLT_MASK, \ + .volt_addr = MAX77620_REG_##_id##_CFG, \ + .cfg_addr = MAX77620_REG_##_id##_CFG2, \ + .fps_addr = MAX77620_REG_FPS_##_id, \ + .remote_sense_addr = 0xFF, \ + .min_uV = _min_uV, \ + .max_uV = _max_uV, \ + .step_uV = _step_uV, \ + .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, \ + .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; + pmic->rdesc[id] = rdesc; + + 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_ALIAS("platform:max77620-pmic"); +MODULE_LICENSE("GPL v2"); -- cgit v0.10.2 From 47dbdbf64fd664eae237ef9b94f4bf89093fa5a3 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 25 Feb 2016 14:39:29 +0800 Subject: regulator: max77620: Remove unused fields These fields are never used and not required at all, remove them. Signed-off-by: Axel Lin Signed-off-by: Mark Brown diff --git a/drivers/regulator/max77620-regulator.c b/drivers/regulator/max77620-regulator.c index fee8ad9..761eb96 100644 --- a/drivers/regulator/max77620-regulator.c +++ b/drivers/regulator/max77620-regulator.c @@ -62,13 +62,9 @@ enum max77620_regulator_type { struct max77620_regulator_info { u8 type; - u32 min_uV; - u32 max_uV; - u32 step_uV; u8 fps_addr; u8 volt_addr; u8 cfg_addr; - u8 volt_mask; u8 power_mode_mask; u8 power_mode_shift; u8 remote_sense_addr; @@ -92,7 +88,6 @@ struct max77620_regulator { struct regmap *rmap; struct max77620_regulator_info *rinfo[MAX77620_NUM_REGS]; struct max77620_regulator_pdata reg_pdata[MAX77620_NUM_REGS]; - struct regulator_desc *rdesc[MAX77620_NUM_REGS]; int enable_power_mode[MAX77620_NUM_REGS]; int current_power_mode[MAX77620_NUM_REGS]; int active_fps_src[MAX77620_NUM_REGS]; @@ -596,15 +591,11 @@ static struct regulator_ops max77620_regulator_ops = { _step_uV, _rs_add, _rs_mask) \ [MAX77620_REGULATOR_ID_##_id] = { \ .type = MAX77620_REGULATOR_TYPE_SD, \ - .volt_mask = MAX77620_##_volt_mask##_VOLT_MASK, \ .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, \ - .min_uV = _min_uV, \ - .max_uV = _max_uV, \ - .step_uV = _step_uV, \ .power_mode_mask = MAX77620_SD_POWER_MODE_MASK, \ .power_mode_shift = MAX77620_SD_POWER_MODE_SHIFT, \ .desc = { \ @@ -628,14 +619,10 @@ static struct regulator_ops max77620_regulator_ops = { #define RAIL_LDO(_id, _name, _sname, _type, _min_uV, _max_uV, _step_uV) \ [MAX77620_REGULATOR_ID_##_id] = { \ .type = MAX77620_REGULATOR_TYPE_LDO_##_type, \ - .volt_mask = MAX77620_LDO_VOLT_MASK, \ .volt_addr = MAX77620_REG_##_id##_CFG, \ .cfg_addr = MAX77620_REG_##_id##_CFG2, \ .fps_addr = MAX77620_REG_FPS_##_id, \ .remote_sense_addr = 0xFF, \ - .min_uV = _min_uV, \ - .max_uV = _max_uV, \ - .step_uV = _step_uV, \ .power_mode_mask = MAX77620_LDO_POWER_MODE_MASK, \ .power_mode_shift = MAX77620_LDO_POWER_MODE_SHIFT, \ .desc = { \ @@ -736,7 +723,6 @@ static int max77620_regulator_probe(struct platform_device *pdev) rdesc = &rinfo[id].desc; pmic->rinfo[id] = &max77620_regs_info[id]; pmic->enable_power_mode[id] = MAX77620_POWER_MODE_NORMAL; - pmic->rdesc[id] = rdesc; ret = max77620_read_slew_rate(pmic, id); if (ret < 0) -- cgit v0.10.2 From aad76f743b040fe1b113691e92a2983b39c1f114 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 25 Feb 2016 14:40:09 +0800 Subject: regulator: max77620: Eliminate duplicate code Signed-off-by: Axel Lin Signed-off-by: Mark Brown diff --git a/drivers/regulator/max77620-regulator.c b/drivers/regulator/max77620-regulator.c index 761eb96..0eb5d18 100644 --- a/drivers/regulator/max77620-regulator.c +++ b/drivers/regulator/max77620-regulator.c @@ -264,15 +264,15 @@ static int max77620_read_slew_rate(struct max77620_regulator *pmic, int id) 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: - 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; - } - slew_rate = (rval >> MAX77620_SD_SR_SHIFT) & 0x3; switch (slew_rate) { case 0: @@ -291,12 +291,6 @@ static int max77620_read_slew_rate(struct max77620_regulator *pmic, int id) rinfo->desc.ramp_delay = slew_rate; break; default: - 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; - } slew_rate = rval & 0x1; switch (slew_rate) { case 0: -- cgit v0.10.2 From 4d92325125e437e46d9198fe7dc0ebdc792ea5e0 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 25 Feb 2016 14:40:50 +0800 Subject: regulator: max77620: Remove duplicate module alias The same alias is already in .id_table. Signed-off-by: Axel Lin Signed-off-by: Mark Brown diff --git a/drivers/regulator/max77620-regulator.c b/drivers/regulator/max77620-regulator.c index 0eb5d18..259e7e1 100644 --- a/drivers/regulator/max77620-regulator.c +++ b/drivers/regulator/max77620-regulator.c @@ -801,5 +801,4 @@ module_platform_driver(max77620_regulator_driver); MODULE_DESCRIPTION("MAX77620/MAX20024 regulator driver"); MODULE_AUTHOR("Mallikarjun Kasoju "); MODULE_AUTHOR("Laxman Dewangan "); -MODULE_ALIAS("platform:max77620-pmic"); MODULE_LICENSE("GPL v2"); -- cgit v0.10.2 From 909f7ee0b5f30f735e16864a7ed18d2e6123e6d9 Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Wed, 2 Mar 2016 16:24:46 +0530 Subject: regulator: core: Add support for active-discharge configuration Add support to enable/disable active discharge of regulator via machine constraints. This configuration is done when setting machine constraint during regulator register and if regulator driver implemented the callback ops. Signed-off-by: Laxman Dewangan Signed-off-by: Mark Brown diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 7ebb7c8..5b1e049 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -1151,6 +1151,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; out: -- cgit v0.10.2 From 51817f468fb1a903d82ff2edd0e611d04910e675 Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Wed, 2 Mar 2016 16:24:48 +0530 Subject: regulator: max77620: Add support to configure active-discharge Add regulator ops callback for configuration of active-discharge and provide necessarily information via regulator descriptor. Signed-off-by: Laxman Dewangan Signed-off-by: Mark Brown diff --git a/drivers/regulator/max77620-regulator.c b/drivers/regulator/max77620-regulator.c index 259e7e1..73a3356 100644 --- a/drivers/regulator/max77620-regulator.c +++ b/drivers/regulator/max77620-regulator.c @@ -578,6 +578,7 @@ static struct regulator_ops max77620_regulator_ops = { .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 @@ -606,6 +607,10 @@ static struct regulator_ops max77620_regulator_ops = { .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, \ }, \ } @@ -633,6 +638,10 @@ static struct regulator_ops max77620_regulator_ops = { .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, \ }, \ } -- cgit v0.10.2