From 86cf635a316e89ba6ae79f452cedb5acddccf570 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Thu, 17 Mar 2016 14:54:54 -0300 Subject: regulator: Rename files for Maxim PMIC drivers Most Maxim PMIC regulator drivers are for sub-devices of Multi-Function Devices with drivers under drivers/mfd. But for many of these, the same object file name was used for both the MFD and the regulator drivers. Having 2 different drivers with the same name causes a lot of confusion to Kbuild, specially if these are built as module since only one module will be installed and also exported symbols will be undefined due being overwritten by the other module during modpost. For example, it fixes the following issue when both drivers are module: $ make M=drivers/regulator/ ... CC [M] drivers/regulator//max14577.o Building modules, stage 2. MODPOST 1 modules WARNING: "maxim_charger_calc_reg_current" [drivers/regulator//max14577.ko] undefined! WARNING: "maxim_charger_currents" [drivers/regulator//max14577.ko] undefined! Reported-by: Chanwoo Choi Signed-off-by: Javier Martinez Canillas Reviewed-by: Chanwoo Choi Signed-off-by: Mark Brown --- drivers/regulator/Makefile | 6 +- drivers/regulator/max14577-regulator.c | 337 +++++++++ drivers/regulator/max14577.c | 337 --------- drivers/regulator/max77693-regulator.c | 318 ++++++++ drivers/regulator/max77693.c | 318 -------- drivers/regulator/max8997-regulator.c | 1241 ++++++++++++++++++++++++++++++++ drivers/regulator/max8997.c | 1241 -------------------------------- 7 files changed, 1899 insertions(+), 1899 deletions(-) create mode 100644 drivers/regulator/max14577-regulator.c delete mode 100644 drivers/regulator/max14577.c create mode 100644 drivers/regulator/max77693-regulator.c delete mode 100644 drivers/regulator/max77693.c create mode 100644 drivers/regulator/max8997-regulator.c delete mode 100644 drivers/regulator/max8997.c (limited to 'drivers/regulator') diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index 61bfbb9d4a0c..8018b2ef13cb 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -46,7 +46,7 @@ obj-$(CONFIG_REGULATOR_LP8788) += lp8788-buck.o obj-$(CONFIG_REGULATOR_LP8788) += lp8788-ldo.o obj-$(CONFIG_REGULATOR_LP8755) += lp8755.o obj-$(CONFIG_REGULATOR_LTC3589) += ltc3589.o -obj-$(CONFIG_REGULATOR_MAX14577) += max14577.o +obj-$(CONFIG_REGULATOR_MAX14577) += max14577-regulator.o obj-$(CONFIG_REGULATOR_MAX1586) += max1586.o obj-$(CONFIG_REGULATOR_MAX77620) += max77620-regulator.o obj-$(CONFIG_REGULATOR_MAX8649) += max8649.o @@ -55,10 +55,10 @@ obj-$(CONFIG_REGULATOR_MAX8907) += max8907-regulator.o obj-$(CONFIG_REGULATOR_MAX8925) += max8925-regulator.o obj-$(CONFIG_REGULATOR_MAX8952) += max8952.o obj-$(CONFIG_REGULATOR_MAX8973) += max8973-regulator.o -obj-$(CONFIG_REGULATOR_MAX8997) += max8997.o +obj-$(CONFIG_REGULATOR_MAX8997) += max8997-regulator.o obj-$(CONFIG_REGULATOR_MAX8998) += max8998.o obj-$(CONFIG_REGULATOR_MAX77686) += max77686-regulator.o -obj-$(CONFIG_REGULATOR_MAX77693) += max77693.o +obj-$(CONFIG_REGULATOR_MAX77693) += max77693-regulator.o obj-$(CONFIG_REGULATOR_MAX77802) += max77802-regulator.o obj-$(CONFIG_REGULATOR_MC13783) += mc13783-regulator.o obj-$(CONFIG_REGULATOR_MC13892) += mc13892-regulator.o diff --git a/drivers/regulator/max14577-regulator.c b/drivers/regulator/max14577-regulator.c new file mode 100644 index 000000000000..b2daa6641417 --- /dev/null +++ b/drivers/regulator/max14577-regulator.c @@ -0,0 +1,337 @@ +/* + * max14577.c - Regulator driver for the Maxim 14577/77836 + * + * Copyright (C) 2013,2014 Samsung Electronics + * Krzysztof Kozlowski + * + * 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. + */ + +#include +#include +#include +#include +#include +#include + +static int max14577_reg_is_enabled(struct regulator_dev *rdev) +{ + int rid = rdev_get_id(rdev); + struct regmap *rmap = rdev->regmap; + u8 reg_data; + + switch (rid) { + case MAX14577_CHARGER: + max14577_read_reg(rmap, MAX14577_CHG_REG_CHG_CTRL2, ®_data); + if ((reg_data & CHGCTRL2_MBCHOSTEN_MASK) == 0) + return 0; + max14577_read_reg(rmap, MAX14577_CHG_REG_STATUS3, ®_data); + if ((reg_data & STATUS3_CGMBC_MASK) == 0) + return 0; + /* MBCHOSTEN and CGMBC are on */ + return 1; + default: + return -EINVAL; + } +} + +static int max14577_reg_get_current_limit(struct regulator_dev *rdev) +{ + u8 reg_data; + struct regmap *rmap = rdev->regmap; + struct max14577 *max14577 = rdev_get_drvdata(rdev); + const struct maxim_charger_current *limits = + &maxim_charger_currents[max14577->dev_type]; + + if (rdev_get_id(rdev) != MAX14577_CHARGER) + return -EINVAL; + + max14577_read_reg(rmap, MAX14577_CHG_REG_CHG_CTRL4, ®_data); + + if ((reg_data & CHGCTRL4_MBCICHWRCL_MASK) == 0) + return limits->min; + + reg_data = ((reg_data & CHGCTRL4_MBCICHWRCH_MASK) >> + CHGCTRL4_MBCICHWRCH_SHIFT); + return limits->high_start + reg_data * limits->high_step; +} + +static int max14577_reg_set_current_limit(struct regulator_dev *rdev, + int min_uA, int max_uA) +{ + u8 reg_data; + int ret; + struct max14577 *max14577 = rdev_get_drvdata(rdev); + const struct maxim_charger_current *limits = + &maxim_charger_currents[max14577->dev_type]; + + if (rdev_get_id(rdev) != MAX14577_CHARGER) + return -EINVAL; + + ret = maxim_charger_calc_reg_current(limits, min_uA, max_uA, ®_data); + if (ret) + return ret; + + return max14577_update_reg(rdev->regmap, MAX14577_CHG_REG_CHG_CTRL4, + CHGCTRL4_MBCICHWRCL_MASK | CHGCTRL4_MBCICHWRCH_MASK, + reg_data); +} + +static struct regulator_ops max14577_safeout_ops = { + .is_enabled = regulator_is_enabled_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .list_voltage = regulator_list_voltage_linear, +}; + +static struct regulator_ops max14577_charger_ops = { + .is_enabled = max14577_reg_is_enabled, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .get_current_limit = max14577_reg_get_current_limit, + .set_current_limit = max14577_reg_set_current_limit, +}; + +#define MAX14577_SAFEOUT_REG { \ + .name = "SAFEOUT", \ + .of_match = of_match_ptr("SAFEOUT"), \ + .regulators_node = of_match_ptr("regulators"), \ + .id = MAX14577_SAFEOUT, \ + .ops = &max14577_safeout_ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + .n_voltages = 1, \ + .min_uV = MAX14577_REGULATOR_SAFEOUT_VOLTAGE, \ + .enable_reg = MAX14577_REG_CONTROL2, \ + .enable_mask = CTRL2_SFOUTORD_MASK, \ +} +#define MAX14577_CHARGER_REG { \ + .name = "CHARGER", \ + .of_match = of_match_ptr("CHARGER"), \ + .regulators_node = of_match_ptr("regulators"), \ + .id = MAX14577_CHARGER, \ + .ops = &max14577_charger_ops, \ + .type = REGULATOR_CURRENT, \ + .owner = THIS_MODULE, \ + .enable_reg = MAX14577_CHG_REG_CHG_CTRL2, \ + .enable_mask = CHGCTRL2_MBCHOSTEN_MASK, \ +} + +static const struct regulator_desc max14577_supported_regulators[] = { + [MAX14577_SAFEOUT] = MAX14577_SAFEOUT_REG, + [MAX14577_CHARGER] = MAX14577_CHARGER_REG, +}; + +static struct regulator_ops max77836_ldo_ops = { + .is_enabled = regulator_is_enabled_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .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, + /* TODO: add .set_suspend_mode */ +}; + +#define MAX77836_LDO_REG(num) { \ + .name = "LDO" # num, \ + .of_match = of_match_ptr("LDO" # num), \ + .regulators_node = of_match_ptr("regulators"), \ + .id = MAX77836_LDO ## num, \ + .ops = &max77836_ldo_ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + .n_voltages = MAX77836_REGULATOR_LDO_VOLTAGE_STEPS_NUM, \ + .min_uV = MAX77836_REGULATOR_LDO_VOLTAGE_MIN, \ + .uV_step = MAX77836_REGULATOR_LDO_VOLTAGE_STEP, \ + .enable_reg = MAX77836_LDO_REG_CNFG1_LDO ## num, \ + .enable_mask = MAX77836_CNFG1_LDO_PWRMD_MASK, \ + .vsel_reg = MAX77836_LDO_REG_CNFG1_LDO ## num, \ + .vsel_mask = MAX77836_CNFG1_LDO_TV_MASK, \ +} + +static const struct regulator_desc max77836_supported_regulators[] = { + [MAX14577_SAFEOUT] = MAX14577_SAFEOUT_REG, + [MAX14577_CHARGER] = MAX14577_CHARGER_REG, + [MAX77836_LDO1] = MAX77836_LDO_REG(1), + [MAX77836_LDO2] = MAX77836_LDO_REG(2), +}; + +#ifdef CONFIG_OF +static struct of_regulator_match max14577_regulator_matches[] = { + { .name = "SAFEOUT", }, + { .name = "CHARGER", }, +}; + +static struct of_regulator_match max77836_regulator_matches[] = { + { .name = "SAFEOUT", }, + { .name = "CHARGER", }, + { .name = "LDO1", }, + { .name = "LDO2", }, +}; + +static inline struct regulator_init_data *match_init_data(int index, + enum maxim_device_type dev_type) +{ + switch (dev_type) { + case MAXIM_DEVICE_TYPE_MAX77836: + return max77836_regulator_matches[index].init_data; + + case MAXIM_DEVICE_TYPE_MAX14577: + default: + return max14577_regulator_matches[index].init_data; + } +} + +static inline struct device_node *match_of_node(int index, + enum maxim_device_type dev_type) +{ + switch (dev_type) { + case MAXIM_DEVICE_TYPE_MAX77836: + return max77836_regulator_matches[index].of_node; + + case MAXIM_DEVICE_TYPE_MAX14577: + default: + return max14577_regulator_matches[index].of_node; + } +} +#else /* CONFIG_OF */ +static inline struct regulator_init_data *match_init_data(int index, + enum maxim_device_type dev_type) +{ + return NULL; +} + +static inline struct device_node *match_of_node(int index, + enum maxim_device_type dev_type) +{ + return NULL; +} +#endif /* CONFIG_OF */ + +/** + * Registers for regulators of max77836 use different I2C slave addresses so + * different regmaps must be used for them. + * + * Returns proper regmap for accessing regulator passed by id. + */ +static struct regmap *max14577_get_regmap(struct max14577 *max14577, + int reg_id) +{ + switch (max14577->dev_type) { + case MAXIM_DEVICE_TYPE_MAX77836: + switch (reg_id) { + case MAX77836_SAFEOUT ... MAX77836_CHARGER: + return max14577->regmap; + default: + /* MAX77836_LDO1 ... MAX77836_LDO2 */ + return max14577->regmap_pmic; + } + + case MAXIM_DEVICE_TYPE_MAX14577: + default: + return max14577->regmap; + } +} + +static int max14577_regulator_probe(struct platform_device *pdev) +{ + struct max14577 *max14577 = dev_get_drvdata(pdev->dev.parent); + struct max14577_platform_data *pdata = dev_get_platdata(max14577->dev); + int i, ret = 0; + struct regulator_config config = {}; + const struct regulator_desc *supported_regulators; + unsigned int supported_regulators_size; + enum maxim_device_type dev_type = max14577->dev_type; + + switch (dev_type) { + case MAXIM_DEVICE_TYPE_MAX77836: + supported_regulators = max77836_supported_regulators; + supported_regulators_size = ARRAY_SIZE(max77836_supported_regulators); + break; + case MAXIM_DEVICE_TYPE_MAX14577: + default: + supported_regulators = max14577_supported_regulators; + supported_regulators_size = ARRAY_SIZE(max14577_supported_regulators); + } + + config.dev = max14577->dev; + config.driver_data = max14577; + + for (i = 0; i < supported_regulators_size; i++) { + struct regulator_dev *regulator; + /* + * Index of supported_regulators[] is also the id and must + * match index of pdata->regulators[]. + */ + if (pdata && pdata->regulators) { + config.init_data = pdata->regulators[i].initdata; + config.of_node = pdata->regulators[i].of_node; + } else { + config.init_data = match_init_data(i, dev_type); + config.of_node = match_of_node(i, dev_type); + } + config.regmap = max14577_get_regmap(max14577, + supported_regulators[i].id); + + regulator = devm_regulator_register(&pdev->dev, + &supported_regulators[i], &config); + if (IS_ERR(regulator)) { + ret = PTR_ERR(regulator); + dev_err(&pdev->dev, + "Regulator init failed for %d/%s with error: %d\n", + i, supported_regulators[i].name, ret); + return ret; + } + } + + return ret; +} + +static const struct platform_device_id max14577_regulator_id[] = { + { "max14577-regulator", MAXIM_DEVICE_TYPE_MAX14577, }, + { "max77836-regulator", MAXIM_DEVICE_TYPE_MAX77836, }, + { } +}; +MODULE_DEVICE_TABLE(platform, max14577_regulator_id); + +static struct platform_driver max14577_regulator_driver = { + .driver = { + .name = "max14577-regulator", + }, + .probe = max14577_regulator_probe, + .id_table = max14577_regulator_id, +}; + +static int __init max14577_regulator_init(void) +{ + BUILD_BUG_ON(ARRAY_SIZE(max14577_supported_regulators) != MAX14577_REGULATOR_NUM); + BUILD_BUG_ON(ARRAY_SIZE(max77836_supported_regulators) != MAX77836_REGULATOR_NUM); + + BUILD_BUG_ON(MAX77836_REGULATOR_LDO_VOLTAGE_MIN + + (MAX77836_REGULATOR_LDO_VOLTAGE_STEP * + (MAX77836_REGULATOR_LDO_VOLTAGE_STEPS_NUM - 1)) != + MAX77836_REGULATOR_LDO_VOLTAGE_MAX); + + return platform_driver_register(&max14577_regulator_driver); +} +subsys_initcall(max14577_regulator_init); + +static void __exit max14577_regulator_exit(void) +{ + platform_driver_unregister(&max14577_regulator_driver); +} +module_exit(max14577_regulator_exit); + +MODULE_AUTHOR("Krzysztof Kozlowski "); +MODULE_DESCRIPTION("Maxim 14577/77836 regulator driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:max14577-regulator"); diff --git a/drivers/regulator/max14577.c b/drivers/regulator/max14577.c deleted file mode 100644 index b2daa6641417..000000000000 --- a/drivers/regulator/max14577.c +++ /dev/null @@ -1,337 +0,0 @@ -/* - * max14577.c - Regulator driver for the Maxim 14577/77836 - * - * Copyright (C) 2013,2014 Samsung Electronics - * Krzysztof Kozlowski - * - * 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. - */ - -#include -#include -#include -#include -#include -#include - -static int max14577_reg_is_enabled(struct regulator_dev *rdev) -{ - int rid = rdev_get_id(rdev); - struct regmap *rmap = rdev->regmap; - u8 reg_data; - - switch (rid) { - case MAX14577_CHARGER: - max14577_read_reg(rmap, MAX14577_CHG_REG_CHG_CTRL2, ®_data); - if ((reg_data & CHGCTRL2_MBCHOSTEN_MASK) == 0) - return 0; - max14577_read_reg(rmap, MAX14577_CHG_REG_STATUS3, ®_data); - if ((reg_data & STATUS3_CGMBC_MASK) == 0) - return 0; - /* MBCHOSTEN and CGMBC are on */ - return 1; - default: - return -EINVAL; - } -} - -static int max14577_reg_get_current_limit(struct regulator_dev *rdev) -{ - u8 reg_data; - struct regmap *rmap = rdev->regmap; - struct max14577 *max14577 = rdev_get_drvdata(rdev); - const struct maxim_charger_current *limits = - &maxim_charger_currents[max14577->dev_type]; - - if (rdev_get_id(rdev) != MAX14577_CHARGER) - return -EINVAL; - - max14577_read_reg(rmap, MAX14577_CHG_REG_CHG_CTRL4, ®_data); - - if ((reg_data & CHGCTRL4_MBCICHWRCL_MASK) == 0) - return limits->min; - - reg_data = ((reg_data & CHGCTRL4_MBCICHWRCH_MASK) >> - CHGCTRL4_MBCICHWRCH_SHIFT); - return limits->high_start + reg_data * limits->high_step; -} - -static int max14577_reg_set_current_limit(struct regulator_dev *rdev, - int min_uA, int max_uA) -{ - u8 reg_data; - int ret; - struct max14577 *max14577 = rdev_get_drvdata(rdev); - const struct maxim_charger_current *limits = - &maxim_charger_currents[max14577->dev_type]; - - if (rdev_get_id(rdev) != MAX14577_CHARGER) - return -EINVAL; - - ret = maxim_charger_calc_reg_current(limits, min_uA, max_uA, ®_data); - if (ret) - return ret; - - return max14577_update_reg(rdev->regmap, MAX14577_CHG_REG_CHG_CTRL4, - CHGCTRL4_MBCICHWRCL_MASK | CHGCTRL4_MBCICHWRCH_MASK, - reg_data); -} - -static struct regulator_ops max14577_safeout_ops = { - .is_enabled = regulator_is_enabled_regmap, - .enable = regulator_enable_regmap, - .disable = regulator_disable_regmap, - .list_voltage = regulator_list_voltage_linear, -}; - -static struct regulator_ops max14577_charger_ops = { - .is_enabled = max14577_reg_is_enabled, - .enable = regulator_enable_regmap, - .disable = regulator_disable_regmap, - .get_current_limit = max14577_reg_get_current_limit, - .set_current_limit = max14577_reg_set_current_limit, -}; - -#define MAX14577_SAFEOUT_REG { \ - .name = "SAFEOUT", \ - .of_match = of_match_ptr("SAFEOUT"), \ - .regulators_node = of_match_ptr("regulators"), \ - .id = MAX14577_SAFEOUT, \ - .ops = &max14577_safeout_ops, \ - .type = REGULATOR_VOLTAGE, \ - .owner = THIS_MODULE, \ - .n_voltages = 1, \ - .min_uV = MAX14577_REGULATOR_SAFEOUT_VOLTAGE, \ - .enable_reg = MAX14577_REG_CONTROL2, \ - .enable_mask = CTRL2_SFOUTORD_MASK, \ -} -#define MAX14577_CHARGER_REG { \ - .name = "CHARGER", \ - .of_match = of_match_ptr("CHARGER"), \ - .regulators_node = of_match_ptr("regulators"), \ - .id = MAX14577_CHARGER, \ - .ops = &max14577_charger_ops, \ - .type = REGULATOR_CURRENT, \ - .owner = THIS_MODULE, \ - .enable_reg = MAX14577_CHG_REG_CHG_CTRL2, \ - .enable_mask = CHGCTRL2_MBCHOSTEN_MASK, \ -} - -static const struct regulator_desc max14577_supported_regulators[] = { - [MAX14577_SAFEOUT] = MAX14577_SAFEOUT_REG, - [MAX14577_CHARGER] = MAX14577_CHARGER_REG, -}; - -static struct regulator_ops max77836_ldo_ops = { - .is_enabled = regulator_is_enabled_regmap, - .enable = regulator_enable_regmap, - .disable = regulator_disable_regmap, - .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, - /* TODO: add .set_suspend_mode */ -}; - -#define MAX77836_LDO_REG(num) { \ - .name = "LDO" # num, \ - .of_match = of_match_ptr("LDO" # num), \ - .regulators_node = of_match_ptr("regulators"), \ - .id = MAX77836_LDO ## num, \ - .ops = &max77836_ldo_ops, \ - .type = REGULATOR_VOLTAGE, \ - .owner = THIS_MODULE, \ - .n_voltages = MAX77836_REGULATOR_LDO_VOLTAGE_STEPS_NUM, \ - .min_uV = MAX77836_REGULATOR_LDO_VOLTAGE_MIN, \ - .uV_step = MAX77836_REGULATOR_LDO_VOLTAGE_STEP, \ - .enable_reg = MAX77836_LDO_REG_CNFG1_LDO ## num, \ - .enable_mask = MAX77836_CNFG1_LDO_PWRMD_MASK, \ - .vsel_reg = MAX77836_LDO_REG_CNFG1_LDO ## num, \ - .vsel_mask = MAX77836_CNFG1_LDO_TV_MASK, \ -} - -static const struct regulator_desc max77836_supported_regulators[] = { - [MAX14577_SAFEOUT] = MAX14577_SAFEOUT_REG, - [MAX14577_CHARGER] = MAX14577_CHARGER_REG, - [MAX77836_LDO1] = MAX77836_LDO_REG(1), - [MAX77836_LDO2] = MAX77836_LDO_REG(2), -}; - -#ifdef CONFIG_OF -static struct of_regulator_match max14577_regulator_matches[] = { - { .name = "SAFEOUT", }, - { .name = "CHARGER", }, -}; - -static struct of_regulator_match max77836_regulator_matches[] = { - { .name = "SAFEOUT", }, - { .name = "CHARGER", }, - { .name = "LDO1", }, - { .name = "LDO2", }, -}; - -static inline struct regulator_init_data *match_init_data(int index, - enum maxim_device_type dev_type) -{ - switch (dev_type) { - case MAXIM_DEVICE_TYPE_MAX77836: - return max77836_regulator_matches[index].init_data; - - case MAXIM_DEVICE_TYPE_MAX14577: - default: - return max14577_regulator_matches[index].init_data; - } -} - -static inline struct device_node *match_of_node(int index, - enum maxim_device_type dev_type) -{ - switch (dev_type) { - case MAXIM_DEVICE_TYPE_MAX77836: - return max77836_regulator_matches[index].of_node; - - case MAXIM_DEVICE_TYPE_MAX14577: - default: - return max14577_regulator_matches[index].of_node; - } -} -#else /* CONFIG_OF */ -static inline struct regulator_init_data *match_init_data(int index, - enum maxim_device_type dev_type) -{ - return NULL; -} - -static inline struct device_node *match_of_node(int index, - enum maxim_device_type dev_type) -{ - return NULL; -} -#endif /* CONFIG_OF */ - -/** - * Registers for regulators of max77836 use different I2C slave addresses so - * different regmaps must be used for them. - * - * Returns proper regmap for accessing regulator passed by id. - */ -static struct regmap *max14577_get_regmap(struct max14577 *max14577, - int reg_id) -{ - switch (max14577->dev_type) { - case MAXIM_DEVICE_TYPE_MAX77836: - switch (reg_id) { - case MAX77836_SAFEOUT ... MAX77836_CHARGER: - return max14577->regmap; - default: - /* MAX77836_LDO1 ... MAX77836_LDO2 */ - return max14577->regmap_pmic; - } - - case MAXIM_DEVICE_TYPE_MAX14577: - default: - return max14577->regmap; - } -} - -static int max14577_regulator_probe(struct platform_device *pdev) -{ - struct max14577 *max14577 = dev_get_drvdata(pdev->dev.parent); - struct max14577_platform_data *pdata = dev_get_platdata(max14577->dev); - int i, ret = 0; - struct regulator_config config = {}; - const struct regulator_desc *supported_regulators; - unsigned int supported_regulators_size; - enum maxim_device_type dev_type = max14577->dev_type; - - switch (dev_type) { - case MAXIM_DEVICE_TYPE_MAX77836: - supported_regulators = max77836_supported_regulators; - supported_regulators_size = ARRAY_SIZE(max77836_supported_regulators); - break; - case MAXIM_DEVICE_TYPE_MAX14577: - default: - supported_regulators = max14577_supported_regulators; - supported_regulators_size = ARRAY_SIZE(max14577_supported_regulators); - } - - config.dev = max14577->dev; - config.driver_data = max14577; - - for (i = 0; i < supported_regulators_size; i++) { - struct regulator_dev *regulator; - /* - * Index of supported_regulators[] is also the id and must - * match index of pdata->regulators[]. - */ - if (pdata && pdata->regulators) { - config.init_data = pdata->regulators[i].initdata; - config.of_node = pdata->regulators[i].of_node; - } else { - config.init_data = match_init_data(i, dev_type); - config.of_node = match_of_node(i, dev_type); - } - config.regmap = max14577_get_regmap(max14577, - supported_regulators[i].id); - - regulator = devm_regulator_register(&pdev->dev, - &supported_regulators[i], &config); - if (IS_ERR(regulator)) { - ret = PTR_ERR(regulator); - dev_err(&pdev->dev, - "Regulator init failed for %d/%s with error: %d\n", - i, supported_regulators[i].name, ret); - return ret; - } - } - - return ret; -} - -static const struct platform_device_id max14577_regulator_id[] = { - { "max14577-regulator", MAXIM_DEVICE_TYPE_MAX14577, }, - { "max77836-regulator", MAXIM_DEVICE_TYPE_MAX77836, }, - { } -}; -MODULE_DEVICE_TABLE(platform, max14577_regulator_id); - -static struct platform_driver max14577_regulator_driver = { - .driver = { - .name = "max14577-regulator", - }, - .probe = max14577_regulator_probe, - .id_table = max14577_regulator_id, -}; - -static int __init max14577_regulator_init(void) -{ - BUILD_BUG_ON(ARRAY_SIZE(max14577_supported_regulators) != MAX14577_REGULATOR_NUM); - BUILD_BUG_ON(ARRAY_SIZE(max77836_supported_regulators) != MAX77836_REGULATOR_NUM); - - BUILD_BUG_ON(MAX77836_REGULATOR_LDO_VOLTAGE_MIN + - (MAX77836_REGULATOR_LDO_VOLTAGE_STEP * - (MAX77836_REGULATOR_LDO_VOLTAGE_STEPS_NUM - 1)) != - MAX77836_REGULATOR_LDO_VOLTAGE_MAX); - - return platform_driver_register(&max14577_regulator_driver); -} -subsys_initcall(max14577_regulator_init); - -static void __exit max14577_regulator_exit(void) -{ - platform_driver_unregister(&max14577_regulator_driver); -} -module_exit(max14577_regulator_exit); - -MODULE_AUTHOR("Krzysztof Kozlowski "); -MODULE_DESCRIPTION("Maxim 14577/77836 regulator driver"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:max14577-regulator"); diff --git a/drivers/regulator/max77693-regulator.c b/drivers/regulator/max77693-regulator.c new file mode 100644 index 000000000000..de730fd3f8a5 --- /dev/null +++ b/drivers/regulator/max77693-regulator.c @@ -0,0 +1,318 @@ +/* + * max77693.c - Regulator driver for the Maxim 77693 and 77843 + * + * Copyright (C) 2013-2015 Samsung Electronics + * Jonghwa Lee + * Krzysztof Kozlowski + * + * 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 max77686.c + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * ID for MAX77843 regulators. + * There is no need for such for MAX77693. + */ +enum max77843_regulator_type { + MAX77843_SAFEOUT1 = 0, + MAX77843_SAFEOUT2, + MAX77843_CHARGER, + + MAX77843_NUM, +}; + +/* Register differences between chargers: MAX77693 and MAX77843 */ +struct chg_reg_data { + unsigned int linear_reg; + unsigned int linear_mask; + unsigned int uA_step; + unsigned int min_sel; +}; + +/* + * MAX77693 CHARGER regulator - Min : 20mA, Max : 2580mA, step : 20mA + * 0x00, 0x01, 0x2, 0x03 = 60 mA + * 0x04 ~ 0x7E = (60 + (X - 3) * 20) mA + * Actually for MAX77693 the driver manipulates the maximum input current, + * not the fast charge current (output). This should be fixed. + * + * On MAX77843 the calculation formula is the same (except values). + * Fortunately it properly manipulates the fast charge current. + */ +static int max77693_chg_get_current_limit(struct regulator_dev *rdev) +{ + const struct chg_reg_data *reg_data = rdev_get_drvdata(rdev); + unsigned int chg_min_uA = rdev->constraints->min_uA; + unsigned int chg_max_uA = rdev->constraints->max_uA; + unsigned int reg, sel; + unsigned int val; + int ret; + + ret = regmap_read(rdev->regmap, reg_data->linear_reg, ®); + if (ret < 0) + return ret; + + sel = reg & reg_data->linear_mask; + + /* the first four codes for charger current are all 60mA */ + if (sel <= reg_data->min_sel) + sel = 0; + else + sel -= reg_data->min_sel; + + val = chg_min_uA + reg_data->uA_step * sel; + if (val > chg_max_uA) + return -EINVAL; + + return val; +} + +static int max77693_chg_set_current_limit(struct regulator_dev *rdev, + int min_uA, int max_uA) +{ + const struct chg_reg_data *reg_data = rdev_get_drvdata(rdev); + unsigned int chg_min_uA = rdev->constraints->min_uA; + int sel = 0; + + while (chg_min_uA + reg_data->uA_step * sel < min_uA) + sel++; + + if (chg_min_uA + reg_data->uA_step * sel > max_uA) + return -EINVAL; + + /* the first four codes for charger current are all 60mA */ + sel += reg_data->min_sel; + + return regmap_write(rdev->regmap, reg_data->linear_reg, sel); +} +/* end of CHARGER regulator ops */ + +/* Returns regmap suitable for given regulator on chosen device */ +static struct regmap *max77693_get_regmap(enum max77693_types type, + struct max77693_dev *max77693, + int reg_id) +{ + if (type == TYPE_MAX77693) + return max77693->regmap; + + /* Else: TYPE_MAX77843 */ + switch (reg_id) { + case MAX77843_SAFEOUT1: + case MAX77843_SAFEOUT2: + return max77693->regmap; + case MAX77843_CHARGER: + return max77693->regmap_chg; + default: + return max77693->regmap; + } +} + +static const unsigned int max77693_safeout_table[] = { + 4850000, + 4900000, + 4950000, + 3300000, +}; + +static struct regulator_ops max77693_safeout_ops = { + .list_voltage = regulator_list_voltage_table, + .is_enabled = regulator_is_enabled_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, +}; + +static struct regulator_ops max77693_charger_ops = { + .is_enabled = regulator_is_enabled_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .get_current_limit = max77693_chg_get_current_limit, + .set_current_limit = max77693_chg_set_current_limit, +}; + +#define max77693_regulator_desc_esafeout(_num) { \ + .name = "ESAFEOUT"#_num, \ + .id = MAX77693_ESAFEOUT##_num, \ + .of_match = of_match_ptr("ESAFEOUT"#_num), \ + .regulators_node = of_match_ptr("regulators"), \ + .n_voltages = 4, \ + .ops = &max77693_safeout_ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + .volt_table = max77693_safeout_table, \ + .vsel_reg = MAX77693_CHG_REG_SAFEOUT_CTRL, \ + .vsel_mask = SAFEOUT_CTRL_SAFEOUT##_num##_MASK, \ + .enable_reg = MAX77693_CHG_REG_SAFEOUT_CTRL, \ + .enable_mask = SAFEOUT_CTRL_ENSAFEOUT##_num##_MASK , \ +} + +static const struct regulator_desc max77693_supported_regulators[] = { + max77693_regulator_desc_esafeout(1), + max77693_regulator_desc_esafeout(2), + { + .name = "CHARGER", + .id = MAX77693_CHARGER, + .of_match = of_match_ptr("CHARGER"), + .regulators_node = of_match_ptr("regulators"), + .ops = &max77693_charger_ops, + .type = REGULATOR_CURRENT, + .owner = THIS_MODULE, + .enable_reg = MAX77693_CHG_REG_CHG_CNFG_00, + .enable_mask = CHG_CNFG_00_CHG_MASK | + CHG_CNFG_00_BUCK_MASK, + .enable_val = CHG_CNFG_00_CHG_MASK | CHG_CNFG_00_BUCK_MASK, + }, +}; + +static const struct chg_reg_data max77693_chg_reg_data = { + .linear_reg = MAX77693_CHG_REG_CHG_CNFG_09, + .linear_mask = CHG_CNFG_09_CHGIN_ILIM_MASK, + .uA_step = 20000, + .min_sel = 3, +}; + +#define max77843_regulator_desc_esafeout(num) { \ + .name = "SAFEOUT" # num, \ + .id = MAX77843_SAFEOUT ## num, \ + .ops = &max77693_safeout_ops, \ + .of_match = of_match_ptr("SAFEOUT" # num), \ + .regulators_node = of_match_ptr("regulators"), \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + .n_voltages = ARRAY_SIZE(max77693_safeout_table), \ + .volt_table = max77693_safeout_table, \ + .enable_reg = MAX77843_SYS_REG_SAFEOUTCTRL, \ + .enable_mask = MAX77843_REG_SAFEOUTCTRL_ENSAFEOUT ## num, \ + .vsel_reg = MAX77843_SYS_REG_SAFEOUTCTRL, \ + .vsel_mask = MAX77843_REG_SAFEOUTCTRL_SAFEOUT ## num ## _MASK, \ +} + +static const struct regulator_desc max77843_supported_regulators[] = { + [MAX77843_SAFEOUT1] = max77843_regulator_desc_esafeout(1), + [MAX77843_SAFEOUT2] = max77843_regulator_desc_esafeout(2), + [MAX77843_CHARGER] = { + .name = "CHARGER", + .id = MAX77843_CHARGER, + .ops = &max77693_charger_ops, + .of_match = of_match_ptr("CHARGER"), + .regulators_node = of_match_ptr("regulators"), + .type = REGULATOR_CURRENT, + .owner = THIS_MODULE, + .enable_reg = MAX77843_CHG_REG_CHG_CNFG_00, + .enable_mask = MAX77843_CHG_MASK, + .enable_val = MAX77843_CHG_MASK, + }, +}; + +static const struct chg_reg_data max77843_chg_reg_data = { + .linear_reg = MAX77843_CHG_REG_CHG_CNFG_02, + .linear_mask = MAX77843_CHG_FAST_CHG_CURRENT_MASK, + .uA_step = MAX77843_CHG_FAST_CHG_CURRENT_STEP, + .min_sel = 2, +}; + +static int max77693_pmic_probe(struct platform_device *pdev) +{ + enum max77693_types type = platform_get_device_id(pdev)->driver_data; + struct max77693_dev *iodev = dev_get_drvdata(pdev->dev.parent); + const struct regulator_desc *regulators; + unsigned int regulators_size; + int i; + struct regulator_config config = { }; + + config.dev = iodev->dev; + + switch (type) { + case TYPE_MAX77693: + regulators = max77693_supported_regulators; + regulators_size = ARRAY_SIZE(max77693_supported_regulators); + config.driver_data = (void *)&max77693_chg_reg_data; + break; + case TYPE_MAX77843: + regulators = max77843_supported_regulators; + regulators_size = ARRAY_SIZE(max77843_supported_regulators); + config.driver_data = (void *)&max77843_chg_reg_data; + break; + default: + dev_err(&pdev->dev, "Unsupported device type: %u\n", type); + return -ENODEV; + } + + for (i = 0; i < regulators_size; i++) { + struct regulator_dev *rdev; + + config.regmap = max77693_get_regmap(type, iodev, + regulators[i].id); + + rdev = devm_regulator_register(&pdev->dev, + ®ulators[i], &config); + if (IS_ERR(rdev)) { + dev_err(&pdev->dev, + "Failed to initialize regulator-%d\n", i); + return PTR_ERR(rdev); + } + } + + return 0; +} + +static const struct platform_device_id max77693_pmic_id[] = { + { "max77693-pmic", TYPE_MAX77693 }, + { "max77843-regulator", TYPE_MAX77843 }, + {}, +}; + +MODULE_DEVICE_TABLE(platform, max77693_pmic_id); + +static struct platform_driver max77693_pmic_driver = { + .driver = { + .name = "max77693-pmic", + }, + .probe = max77693_pmic_probe, + .id_table = max77693_pmic_id, +}; + +static int __init max77693_pmic_init(void) +{ + return platform_driver_register(&max77693_pmic_driver); +} +subsys_initcall(max77693_pmic_init); + +static void __exit max77693_pmic_cleanup(void) +{ + platform_driver_unregister(&max77693_pmic_driver); +} +module_exit(max77693_pmic_cleanup); + +MODULE_DESCRIPTION("MAXIM 77693/77843 regulator driver"); +MODULE_AUTHOR("Jonghwa Lee "); +MODULE_AUTHOR("Krzysztof Kozlowski "); +MODULE_LICENSE("GPL"); diff --git a/drivers/regulator/max77693.c b/drivers/regulator/max77693.c deleted file mode 100644 index de730fd3f8a5..000000000000 --- a/drivers/regulator/max77693.c +++ /dev/null @@ -1,318 +0,0 @@ -/* - * max77693.c - Regulator driver for the Maxim 77693 and 77843 - * - * Copyright (C) 2013-2015 Samsung Electronics - * Jonghwa Lee - * Krzysztof Kozlowski - * - * 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 max77686.c - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * ID for MAX77843 regulators. - * There is no need for such for MAX77693. - */ -enum max77843_regulator_type { - MAX77843_SAFEOUT1 = 0, - MAX77843_SAFEOUT2, - MAX77843_CHARGER, - - MAX77843_NUM, -}; - -/* Register differences between chargers: MAX77693 and MAX77843 */ -struct chg_reg_data { - unsigned int linear_reg; - unsigned int linear_mask; - unsigned int uA_step; - unsigned int min_sel; -}; - -/* - * MAX77693 CHARGER regulator - Min : 20mA, Max : 2580mA, step : 20mA - * 0x00, 0x01, 0x2, 0x03 = 60 mA - * 0x04 ~ 0x7E = (60 + (X - 3) * 20) mA - * Actually for MAX77693 the driver manipulates the maximum input current, - * not the fast charge current (output). This should be fixed. - * - * On MAX77843 the calculation formula is the same (except values). - * Fortunately it properly manipulates the fast charge current. - */ -static int max77693_chg_get_current_limit(struct regulator_dev *rdev) -{ - const struct chg_reg_data *reg_data = rdev_get_drvdata(rdev); - unsigned int chg_min_uA = rdev->constraints->min_uA; - unsigned int chg_max_uA = rdev->constraints->max_uA; - unsigned int reg, sel; - unsigned int val; - int ret; - - ret = regmap_read(rdev->regmap, reg_data->linear_reg, ®); - if (ret < 0) - return ret; - - sel = reg & reg_data->linear_mask; - - /* the first four codes for charger current are all 60mA */ - if (sel <= reg_data->min_sel) - sel = 0; - else - sel -= reg_data->min_sel; - - val = chg_min_uA + reg_data->uA_step * sel; - if (val > chg_max_uA) - return -EINVAL; - - return val; -} - -static int max77693_chg_set_current_limit(struct regulator_dev *rdev, - int min_uA, int max_uA) -{ - const struct chg_reg_data *reg_data = rdev_get_drvdata(rdev); - unsigned int chg_min_uA = rdev->constraints->min_uA; - int sel = 0; - - while (chg_min_uA + reg_data->uA_step * sel < min_uA) - sel++; - - if (chg_min_uA + reg_data->uA_step * sel > max_uA) - return -EINVAL; - - /* the first four codes for charger current are all 60mA */ - sel += reg_data->min_sel; - - return regmap_write(rdev->regmap, reg_data->linear_reg, sel); -} -/* end of CHARGER regulator ops */ - -/* Returns regmap suitable for given regulator on chosen device */ -static struct regmap *max77693_get_regmap(enum max77693_types type, - struct max77693_dev *max77693, - int reg_id) -{ - if (type == TYPE_MAX77693) - return max77693->regmap; - - /* Else: TYPE_MAX77843 */ - switch (reg_id) { - case MAX77843_SAFEOUT1: - case MAX77843_SAFEOUT2: - return max77693->regmap; - case MAX77843_CHARGER: - return max77693->regmap_chg; - default: - return max77693->regmap; - } -} - -static const unsigned int max77693_safeout_table[] = { - 4850000, - 4900000, - 4950000, - 3300000, -}; - -static struct regulator_ops max77693_safeout_ops = { - .list_voltage = regulator_list_voltage_table, - .is_enabled = regulator_is_enabled_regmap, - .enable = regulator_enable_regmap, - .disable = regulator_disable_regmap, - .get_voltage_sel = regulator_get_voltage_sel_regmap, - .set_voltage_sel = regulator_set_voltage_sel_regmap, -}; - -static struct regulator_ops max77693_charger_ops = { - .is_enabled = regulator_is_enabled_regmap, - .enable = regulator_enable_regmap, - .disable = regulator_disable_regmap, - .get_current_limit = max77693_chg_get_current_limit, - .set_current_limit = max77693_chg_set_current_limit, -}; - -#define max77693_regulator_desc_esafeout(_num) { \ - .name = "ESAFEOUT"#_num, \ - .id = MAX77693_ESAFEOUT##_num, \ - .of_match = of_match_ptr("ESAFEOUT"#_num), \ - .regulators_node = of_match_ptr("regulators"), \ - .n_voltages = 4, \ - .ops = &max77693_safeout_ops, \ - .type = REGULATOR_VOLTAGE, \ - .owner = THIS_MODULE, \ - .volt_table = max77693_safeout_table, \ - .vsel_reg = MAX77693_CHG_REG_SAFEOUT_CTRL, \ - .vsel_mask = SAFEOUT_CTRL_SAFEOUT##_num##_MASK, \ - .enable_reg = MAX77693_CHG_REG_SAFEOUT_CTRL, \ - .enable_mask = SAFEOUT_CTRL_ENSAFEOUT##_num##_MASK , \ -} - -static const struct regulator_desc max77693_supported_regulators[] = { - max77693_regulator_desc_esafeout(1), - max77693_regulator_desc_esafeout(2), - { - .name = "CHARGER", - .id = MAX77693_CHARGER, - .of_match = of_match_ptr("CHARGER"), - .regulators_node = of_match_ptr("regulators"), - .ops = &max77693_charger_ops, - .type = REGULATOR_CURRENT, - .owner = THIS_MODULE, - .enable_reg = MAX77693_CHG_REG_CHG_CNFG_00, - .enable_mask = CHG_CNFG_00_CHG_MASK | - CHG_CNFG_00_BUCK_MASK, - .enable_val = CHG_CNFG_00_CHG_MASK | CHG_CNFG_00_BUCK_MASK, - }, -}; - -static const struct chg_reg_data max77693_chg_reg_data = { - .linear_reg = MAX77693_CHG_REG_CHG_CNFG_09, - .linear_mask = CHG_CNFG_09_CHGIN_ILIM_MASK, - .uA_step = 20000, - .min_sel = 3, -}; - -#define max77843_regulator_desc_esafeout(num) { \ - .name = "SAFEOUT" # num, \ - .id = MAX77843_SAFEOUT ## num, \ - .ops = &max77693_safeout_ops, \ - .of_match = of_match_ptr("SAFEOUT" # num), \ - .regulators_node = of_match_ptr("regulators"), \ - .type = REGULATOR_VOLTAGE, \ - .owner = THIS_MODULE, \ - .n_voltages = ARRAY_SIZE(max77693_safeout_table), \ - .volt_table = max77693_safeout_table, \ - .enable_reg = MAX77843_SYS_REG_SAFEOUTCTRL, \ - .enable_mask = MAX77843_REG_SAFEOUTCTRL_ENSAFEOUT ## num, \ - .vsel_reg = MAX77843_SYS_REG_SAFEOUTCTRL, \ - .vsel_mask = MAX77843_REG_SAFEOUTCTRL_SAFEOUT ## num ## _MASK, \ -} - -static const struct regulator_desc max77843_supported_regulators[] = { - [MAX77843_SAFEOUT1] = max77843_regulator_desc_esafeout(1), - [MAX77843_SAFEOUT2] = max77843_regulator_desc_esafeout(2), - [MAX77843_CHARGER] = { - .name = "CHARGER", - .id = MAX77843_CHARGER, - .ops = &max77693_charger_ops, - .of_match = of_match_ptr("CHARGER"), - .regulators_node = of_match_ptr("regulators"), - .type = REGULATOR_CURRENT, - .owner = THIS_MODULE, - .enable_reg = MAX77843_CHG_REG_CHG_CNFG_00, - .enable_mask = MAX77843_CHG_MASK, - .enable_val = MAX77843_CHG_MASK, - }, -}; - -static const struct chg_reg_data max77843_chg_reg_data = { - .linear_reg = MAX77843_CHG_REG_CHG_CNFG_02, - .linear_mask = MAX77843_CHG_FAST_CHG_CURRENT_MASK, - .uA_step = MAX77843_CHG_FAST_CHG_CURRENT_STEP, - .min_sel = 2, -}; - -static int max77693_pmic_probe(struct platform_device *pdev) -{ - enum max77693_types type = platform_get_device_id(pdev)->driver_data; - struct max77693_dev *iodev = dev_get_drvdata(pdev->dev.parent); - const struct regulator_desc *regulators; - unsigned int regulators_size; - int i; - struct regulator_config config = { }; - - config.dev = iodev->dev; - - switch (type) { - case TYPE_MAX77693: - regulators = max77693_supported_regulators; - regulators_size = ARRAY_SIZE(max77693_supported_regulators); - config.driver_data = (void *)&max77693_chg_reg_data; - break; - case TYPE_MAX77843: - regulators = max77843_supported_regulators; - regulators_size = ARRAY_SIZE(max77843_supported_regulators); - config.driver_data = (void *)&max77843_chg_reg_data; - break; - default: - dev_err(&pdev->dev, "Unsupported device type: %u\n", type); - return -ENODEV; - } - - for (i = 0; i < regulators_size; i++) { - struct regulator_dev *rdev; - - config.regmap = max77693_get_regmap(type, iodev, - regulators[i].id); - - rdev = devm_regulator_register(&pdev->dev, - ®ulators[i], &config); - if (IS_ERR(rdev)) { - dev_err(&pdev->dev, - "Failed to initialize regulator-%d\n", i); - return PTR_ERR(rdev); - } - } - - return 0; -} - -static const struct platform_device_id max77693_pmic_id[] = { - { "max77693-pmic", TYPE_MAX77693 }, - { "max77843-regulator", TYPE_MAX77843 }, - {}, -}; - -MODULE_DEVICE_TABLE(platform, max77693_pmic_id); - -static struct platform_driver max77693_pmic_driver = { - .driver = { - .name = "max77693-pmic", - }, - .probe = max77693_pmic_probe, - .id_table = max77693_pmic_id, -}; - -static int __init max77693_pmic_init(void) -{ - return platform_driver_register(&max77693_pmic_driver); -} -subsys_initcall(max77693_pmic_init); - -static void __exit max77693_pmic_cleanup(void) -{ - platform_driver_unregister(&max77693_pmic_driver); -} -module_exit(max77693_pmic_cleanup); - -MODULE_DESCRIPTION("MAXIM 77693/77843 regulator driver"); -MODULE_AUTHOR("Jonghwa Lee "); -MODULE_AUTHOR("Krzysztof Kozlowski "); -MODULE_LICENSE("GPL"); diff --git a/drivers/regulator/max8997-regulator.c b/drivers/regulator/max8997-regulator.c new file mode 100644 index 000000000000..ea0196d4496b --- /dev/null +++ b/drivers/regulator/max8997-regulator.c @@ -0,0 +1,1241 @@ +/* + * max8997.c - Regulator driver for the Maxim 8997/8966 + * + * Copyright (C) 2011 Samsung Electronics + * MyungJoo Ham + * + * 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 max8998.c + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct max8997_data { + struct device *dev; + struct max8997_dev *iodev; + int num_regulators; + int ramp_delay; /* in mV/us */ + + bool buck1_gpiodvs; + bool buck2_gpiodvs; + bool buck5_gpiodvs; + u8 buck1_vol[8]; + u8 buck2_vol[8]; + u8 buck5_vol[8]; + int buck125_gpios[3]; + int buck125_gpioindex; + bool ignore_gpiodvs_side_effect; + + u8 saved_states[MAX8997_REG_MAX]; +}; + +static const unsigned int safeoutvolt[] = { + 4850000, + 4900000, + 4950000, + 3300000, +}; + +static inline void max8997_set_gpio(struct max8997_data *max8997) +{ + int set3 = (max8997->buck125_gpioindex) & 0x1; + int set2 = ((max8997->buck125_gpioindex) >> 1) & 0x1; + int set1 = ((max8997->buck125_gpioindex) >> 2) & 0x1; + + gpio_set_value(max8997->buck125_gpios[0], set1); + gpio_set_value(max8997->buck125_gpios[1], set2); + gpio_set_value(max8997->buck125_gpios[2], set3); +} + +struct voltage_map_desc { + int min; + int max; + int step; +}; + +/* Voltage maps in uV */ +static const struct voltage_map_desc ldo_voltage_map_desc = { + .min = 800000, .max = 3950000, .step = 50000, +}; /* LDO1 ~ 18, 21 all */ + +static const struct voltage_map_desc buck1245_voltage_map_desc = { + .min = 650000, .max = 2225000, .step = 25000, +}; /* Buck1, 2, 4, 5 */ + +static const struct voltage_map_desc buck37_voltage_map_desc = { + .min = 750000, .max = 3900000, .step = 50000, +}; /* Buck3, 7 */ + +/* current map in uA */ +static const struct voltage_map_desc charger_current_map_desc = { + .min = 200000, .max = 950000, .step = 50000, +}; + +static const struct voltage_map_desc topoff_current_map_desc = { + .min = 50000, .max = 200000, .step = 10000, +}; + +static const struct voltage_map_desc *reg_voltage_map[] = { + [MAX8997_LDO1] = &ldo_voltage_map_desc, + [MAX8997_LDO2] = &ldo_voltage_map_desc, + [MAX8997_LDO3] = &ldo_voltage_map_desc, + [MAX8997_LDO4] = &ldo_voltage_map_desc, + [MAX8997_LDO5] = &ldo_voltage_map_desc, + [MAX8997_LDO6] = &ldo_voltage_map_desc, + [MAX8997_LDO7] = &ldo_voltage_map_desc, + [MAX8997_LDO8] = &ldo_voltage_map_desc, + [MAX8997_LDO9] = &ldo_voltage_map_desc, + [MAX8997_LDO10] = &ldo_voltage_map_desc, + [MAX8997_LDO11] = &ldo_voltage_map_desc, + [MAX8997_LDO12] = &ldo_voltage_map_desc, + [MAX8997_LDO13] = &ldo_voltage_map_desc, + [MAX8997_LDO14] = &ldo_voltage_map_desc, + [MAX8997_LDO15] = &ldo_voltage_map_desc, + [MAX8997_LDO16] = &ldo_voltage_map_desc, + [MAX8997_LDO17] = &ldo_voltage_map_desc, + [MAX8997_LDO18] = &ldo_voltage_map_desc, + [MAX8997_LDO21] = &ldo_voltage_map_desc, + [MAX8997_BUCK1] = &buck1245_voltage_map_desc, + [MAX8997_BUCK2] = &buck1245_voltage_map_desc, + [MAX8997_BUCK3] = &buck37_voltage_map_desc, + [MAX8997_BUCK4] = &buck1245_voltage_map_desc, + [MAX8997_BUCK5] = &buck1245_voltage_map_desc, + [MAX8997_BUCK6] = NULL, + [MAX8997_BUCK7] = &buck37_voltage_map_desc, + [MAX8997_EN32KHZ_AP] = NULL, + [MAX8997_EN32KHZ_CP] = NULL, + [MAX8997_ENVICHG] = NULL, + [MAX8997_ESAFEOUT1] = NULL, + [MAX8997_ESAFEOUT2] = NULL, + [MAX8997_CHARGER_CV] = NULL, + [MAX8997_CHARGER] = &charger_current_map_desc, + [MAX8997_CHARGER_TOPOFF] = &topoff_current_map_desc, +}; + +static int max8997_list_voltage_charger_cv(struct regulator_dev *rdev, + unsigned int selector) +{ + int rid = rdev_get_id(rdev); + + if (rid != MAX8997_CHARGER_CV) + goto err; + + switch (selector) { + case 0x00: + return 4200000; + case 0x01 ... 0x0E: + return 4000000 + 20000 * (selector - 0x01); + case 0x0F: + return 4350000; + default: + return -EINVAL; + } +err: + return -EINVAL; +} + +static int max8997_list_voltage(struct regulator_dev *rdev, + unsigned int selector) +{ + const struct voltage_map_desc *desc; + int rid = rdev_get_id(rdev); + int val; + + if (rid >= ARRAY_SIZE(reg_voltage_map) || + rid < 0) + return -EINVAL; + + desc = reg_voltage_map[rid]; + if (desc == NULL) + return -EINVAL; + + val = desc->min + desc->step * selector; + if (val > desc->max) + return -EINVAL; + + return val; +} + +static int max8997_get_enable_register(struct regulator_dev *rdev, + int *reg, int *mask, int *pattern) +{ + int rid = rdev_get_id(rdev); + + switch (rid) { + case MAX8997_LDO1 ... MAX8997_LDO21: + *reg = MAX8997_REG_LDO1CTRL + (rid - MAX8997_LDO1); + *mask = 0xC0; + *pattern = 0xC0; + break; + case MAX8997_BUCK1: + *reg = MAX8997_REG_BUCK1CTRL; + *mask = 0x01; + *pattern = 0x01; + break; + case MAX8997_BUCK2: + *reg = MAX8997_REG_BUCK2CTRL; + *mask = 0x01; + *pattern = 0x01; + break; + case MAX8997_BUCK3: + *reg = MAX8997_REG_BUCK3CTRL; + *mask = 0x01; + *pattern = 0x01; + break; + case MAX8997_BUCK4: + *reg = MAX8997_REG_BUCK4CTRL; + *mask = 0x01; + *pattern = 0x01; + break; + case MAX8997_BUCK5: + *reg = MAX8997_REG_BUCK5CTRL; + *mask = 0x01; + *pattern = 0x01; + break; + case MAX8997_BUCK6: + *reg = MAX8997_REG_BUCK6CTRL; + *mask = 0x01; + *pattern = 0x01; + break; + case MAX8997_BUCK7: + *reg = MAX8997_REG_BUCK7CTRL; + *mask = 0x01; + *pattern = 0x01; + break; + case MAX8997_EN32KHZ_AP ... MAX8997_EN32KHZ_CP: + *reg = MAX8997_REG_MAINCON1; + *mask = 0x01 << (rid - MAX8997_EN32KHZ_AP); + *pattern = 0x01 << (rid - MAX8997_EN32KHZ_AP); + break; + case MAX8997_ENVICHG: + *reg = MAX8997_REG_MBCCTRL1; + *mask = 0x80; + *pattern = 0x80; + break; + case MAX8997_ESAFEOUT1 ... MAX8997_ESAFEOUT2: + *reg = MAX8997_REG_SAFEOUTCTRL; + *mask = 0x40 << (rid - MAX8997_ESAFEOUT1); + *pattern = 0x40 << (rid - MAX8997_ESAFEOUT1); + break; + case MAX8997_CHARGER: + *reg = MAX8997_REG_MBCCTRL2; + *mask = 0x40; + *pattern = 0x40; + break; + default: + /* Not controllable or not exists */ + return -EINVAL; + } + + return 0; +} + +static int max8997_reg_is_enabled(struct regulator_dev *rdev) +{ + struct max8997_data *max8997 = rdev_get_drvdata(rdev); + struct i2c_client *i2c = max8997->iodev->i2c; + int ret, reg, mask, pattern; + u8 val; + + ret = max8997_get_enable_register(rdev, ®, &mask, &pattern); + if (ret) + return ret; + + ret = max8997_read_reg(i2c, reg, &val); + if (ret) + return ret; + + return (val & mask) == pattern; +} + +static int max8997_reg_enable(struct regulator_dev *rdev) +{ + struct max8997_data *max8997 = rdev_get_drvdata(rdev); + struct i2c_client *i2c = max8997->iodev->i2c; + int ret, reg, mask, pattern; + + ret = max8997_get_enable_register(rdev, ®, &mask, &pattern); + if (ret) + return ret; + + return max8997_update_reg(i2c, reg, pattern, mask); +} + +static int max8997_reg_disable(struct regulator_dev *rdev) +{ + struct max8997_data *max8997 = rdev_get_drvdata(rdev); + struct i2c_client *i2c = max8997->iodev->i2c; + int ret, reg, mask, pattern; + + ret = max8997_get_enable_register(rdev, ®, &mask, &pattern); + if (ret) + return ret; + + return max8997_update_reg(i2c, reg, ~pattern, mask); +} + +static int max8997_get_voltage_register(struct regulator_dev *rdev, + int *_reg, int *_shift, int *_mask) +{ + struct max8997_data *max8997 = rdev_get_drvdata(rdev); + int rid = rdev_get_id(rdev); + int reg, shift = 0, mask = 0x3f; + + switch (rid) { + case MAX8997_LDO1 ... MAX8997_LDO21: + reg = MAX8997_REG_LDO1CTRL + (rid - MAX8997_LDO1); + break; + case MAX8997_BUCK1: + reg = MAX8997_REG_BUCK1DVS1; + if (max8997->buck1_gpiodvs) + reg += max8997->buck125_gpioindex; + break; + case MAX8997_BUCK2: + reg = MAX8997_REG_BUCK2DVS1; + if (max8997->buck2_gpiodvs) + reg += max8997->buck125_gpioindex; + break; + case MAX8997_BUCK3: + reg = MAX8997_REG_BUCK3DVS; + break; + case MAX8997_BUCK4: + reg = MAX8997_REG_BUCK4DVS; + break; + case MAX8997_BUCK5: + reg = MAX8997_REG_BUCK5DVS1; + if (max8997->buck5_gpiodvs) + reg += max8997->buck125_gpioindex; + break; + case MAX8997_BUCK7: + reg = MAX8997_REG_BUCK7DVS; + break; + case MAX8997_ESAFEOUT1 ... MAX8997_ESAFEOUT2: + reg = MAX8997_REG_SAFEOUTCTRL; + shift = (rid == MAX8997_ESAFEOUT2) ? 2 : 0; + mask = 0x3; + break; + case MAX8997_CHARGER_CV: + reg = MAX8997_REG_MBCCTRL3; + shift = 0; + mask = 0xf; + break; + case MAX8997_CHARGER: + reg = MAX8997_REG_MBCCTRL4; + shift = 0; + mask = 0xf; + break; + case MAX8997_CHARGER_TOPOFF: + reg = MAX8997_REG_MBCCTRL5; + shift = 0; + mask = 0xf; + break; + default: + return -EINVAL; + } + + *_reg = reg; + *_shift = shift; + *_mask = mask; + + return 0; +} + +static int max8997_get_voltage_sel(struct regulator_dev *rdev) +{ + struct max8997_data *max8997 = rdev_get_drvdata(rdev); + struct i2c_client *i2c = max8997->iodev->i2c; + int reg, shift, mask, ret; + u8 val; + + ret = max8997_get_voltage_register(rdev, ®, &shift, &mask); + if (ret) + return ret; + + ret = max8997_read_reg(i2c, reg, &val); + if (ret) + return ret; + + val >>= shift; + val &= mask; + + return val; +} + +static inline int max8997_get_voltage_proper_val( + const struct voltage_map_desc *desc, + int min_vol, int max_vol) +{ + int i; + + if (desc == NULL) + return -EINVAL; + + if (max_vol < desc->min || min_vol > desc->max) + return -EINVAL; + + if (min_vol < desc->min) + min_vol = desc->min; + + i = DIV_ROUND_UP(min_vol - desc->min, desc->step); + + if (desc->min + desc->step * i > max_vol) + return -EINVAL; + + return i; +} + +static int max8997_set_voltage_charger_cv(struct regulator_dev *rdev, + int min_uV, int max_uV, unsigned *selector) +{ + struct max8997_data *max8997 = rdev_get_drvdata(rdev); + struct i2c_client *i2c = max8997->iodev->i2c; + int rid = rdev_get_id(rdev); + int lb, ub; + int reg, shift = 0, mask, ret = 0; + u8 val = 0x0; + + if (rid != MAX8997_CHARGER_CV) + return -EINVAL; + + ret = max8997_get_voltage_register(rdev, ®, &shift, &mask); + if (ret) + return ret; + + if (max_uV < 4000000 || min_uV > 4350000) + return -EINVAL; + + if (min_uV <= 4000000) { + if (max_uV >= 4000000) + return -EINVAL; + else + val = 0x1; + } else if (min_uV <= 4200000 && max_uV >= 4200000) + val = 0x0; + else { + lb = (min_uV - 4000001) / 20000 + 2; + ub = (max_uV - 4000000) / 20000 + 1; + + if (lb > ub) + return -EINVAL; + + if (lb < 0xf) + val = lb; + else { + if (ub >= 0xf) + val = 0xf; + else + return -EINVAL; + } + } + + *selector = val; + + ret = max8997_update_reg(i2c, reg, val << shift, mask); + + return ret; +} + +/* + * For LDO1 ~ LDO21, BUCK1~5, BUCK7, CHARGER, CHARGER_TOPOFF + * BUCK1, 2, and 5 are available if they are not controlled by gpio + */ +static int max8997_set_voltage_ldobuck(struct regulator_dev *rdev, + int min_uV, int max_uV, unsigned *selector) +{ + struct max8997_data *max8997 = rdev_get_drvdata(rdev); + struct i2c_client *i2c = max8997->iodev->i2c; + const struct voltage_map_desc *desc; + int rid = rdev_get_id(rdev); + int i, reg, shift, mask, ret; + + switch (rid) { + case MAX8997_LDO1 ... MAX8997_LDO21: + break; + case MAX8997_BUCK1 ... MAX8997_BUCK5: + break; + case MAX8997_BUCK6: + return -EINVAL; + case MAX8997_BUCK7: + break; + case MAX8997_CHARGER: + break; + case MAX8997_CHARGER_TOPOFF: + break; + default: + return -EINVAL; + } + + desc = reg_voltage_map[rid]; + + i = max8997_get_voltage_proper_val(desc, min_uV, max_uV); + if (i < 0) + return i; + + ret = max8997_get_voltage_register(rdev, ®, &shift, &mask); + if (ret) + return ret; + + ret = max8997_update_reg(i2c, reg, i << shift, mask << shift); + *selector = i; + + return ret; +} + +static int max8997_set_voltage_buck_time_sel(struct regulator_dev *rdev, + unsigned int old_selector, + unsigned int new_selector) +{ + struct max8997_data *max8997 = rdev_get_drvdata(rdev); + int rid = rdev_get_id(rdev); + const struct voltage_map_desc *desc = reg_voltage_map[rid]; + + /* Delay is required only if the voltage is increasing */ + if (old_selector >= new_selector) + return 0; + + /* No need to delay if gpio_dvs_mode */ + switch (rid) { + case MAX8997_BUCK1: + if (max8997->buck1_gpiodvs) + return 0; + break; + case MAX8997_BUCK2: + if (max8997->buck2_gpiodvs) + return 0; + break; + case MAX8997_BUCK5: + if (max8997->buck5_gpiodvs) + return 0; + break; + } + + switch (rid) { + case MAX8997_BUCK1: + case MAX8997_BUCK2: + case MAX8997_BUCK4: + case MAX8997_BUCK5: + return DIV_ROUND_UP(desc->step * (new_selector - old_selector), + max8997->ramp_delay * 1000); + } + + return 0; +} + +/* + * Assess the damage on the voltage setting of BUCK1,2,5 by the change. + * + * When GPIO-DVS mode is used for multiple bucks, changing the voltage value + * of one of the bucks may affect that of another buck, which is the side + * effect of the change (set_voltage). This function examines the GPIO-DVS + * configurations and checks whether such side-effect exists. + */ +static int max8997_assess_side_effect(struct regulator_dev *rdev, + u8 new_val, int *best) +{ + struct max8997_data *max8997 = rdev_get_drvdata(rdev); + int rid = rdev_get_id(rdev); + u8 *buckx_val[3]; + bool buckx_gpiodvs[3]; + int side_effect[8]; + int min_side_effect = INT_MAX; + int i; + + *best = -1; + + switch (rid) { + case MAX8997_BUCK1: + rid = 0; + break; + case MAX8997_BUCK2: + rid = 1; + break; + case MAX8997_BUCK5: + rid = 2; + break; + default: + return -EINVAL; + } + + buckx_val[0] = max8997->buck1_vol; + buckx_val[1] = max8997->buck2_vol; + buckx_val[2] = max8997->buck5_vol; + buckx_gpiodvs[0] = max8997->buck1_gpiodvs; + buckx_gpiodvs[1] = max8997->buck2_gpiodvs; + buckx_gpiodvs[2] = max8997->buck5_gpiodvs; + + for (i = 0; i < 8; i++) { + int others; + + if (new_val != (buckx_val[rid])[i]) { + side_effect[i] = -1; + continue; + } + + side_effect[i] = 0; + for (others = 0; others < 3; others++) { + int diff; + + if (others == rid) + continue; + if (buckx_gpiodvs[others] == false) + continue; /* Not affected */ + diff = (buckx_val[others])[i] - + (buckx_val[others])[max8997->buck125_gpioindex]; + if (diff > 0) + side_effect[i] += diff; + else if (diff < 0) + side_effect[i] -= diff; + } + if (side_effect[i] == 0) { + *best = i; + return 0; /* NO SIDE EFFECT! Use This! */ + } + if (side_effect[i] < min_side_effect) { + min_side_effect = side_effect[i]; + *best = i; + } + } + + if (*best == -1) + return -EINVAL; + + return side_effect[*best]; +} + +/* + * For Buck 1 ~ 5 and 7. If it is not controlled by GPIO, this calls + * max8997_set_voltage_ldobuck to do the job. + */ +static int max8997_set_voltage_buck(struct regulator_dev *rdev, + int min_uV, int max_uV, unsigned *selector) +{ + struct max8997_data *max8997 = rdev_get_drvdata(rdev); + int rid = rdev_get_id(rdev); + const struct voltage_map_desc *desc; + int new_val, new_idx, damage, tmp_val, tmp_idx, tmp_dmg; + bool gpio_dvs_mode = false; + + if (rid < MAX8997_BUCK1 || rid > MAX8997_BUCK7) + return -EINVAL; + + switch (rid) { + case MAX8997_BUCK1: + if (max8997->buck1_gpiodvs) + gpio_dvs_mode = true; + break; + case MAX8997_BUCK2: + if (max8997->buck2_gpiodvs) + gpio_dvs_mode = true; + break; + case MAX8997_BUCK5: + if (max8997->buck5_gpiodvs) + gpio_dvs_mode = true; + break; + } + + if (!gpio_dvs_mode) + return max8997_set_voltage_ldobuck(rdev, min_uV, max_uV, + selector); + + desc = reg_voltage_map[rid]; + new_val = max8997_get_voltage_proper_val(desc, min_uV, max_uV); + if (new_val < 0) + return new_val; + + tmp_dmg = INT_MAX; + tmp_idx = -1; + tmp_val = -1; + do { + damage = max8997_assess_side_effect(rdev, new_val, &new_idx); + if (damage == 0) + goto out; + + if (tmp_dmg > damage) { + tmp_idx = new_idx; + tmp_val = new_val; + tmp_dmg = damage; + } + + new_val++; + } while (desc->min + desc->step * new_val <= desc->max); + + new_idx = tmp_idx; + new_val = tmp_val; + + if (max8997->ignore_gpiodvs_side_effect == false) + return -EINVAL; + + dev_warn(&rdev->dev, + "MAX8997 GPIO-DVS Side Effect Warning: GPIO SET: %d -> %d\n", + max8997->buck125_gpioindex, tmp_idx); + +out: + if (new_idx < 0 || new_val < 0) + return -EINVAL; + + max8997->buck125_gpioindex = new_idx; + max8997_set_gpio(max8997); + *selector = new_val; + + return 0; +} + +/* For SAFEOUT1 and SAFEOUT2 */ +static int max8997_set_voltage_safeout_sel(struct regulator_dev *rdev, + unsigned selector) +{ + struct max8997_data *max8997 = rdev_get_drvdata(rdev); + struct i2c_client *i2c = max8997->iodev->i2c; + int rid = rdev_get_id(rdev); + int reg, shift = 0, mask, ret; + + if (rid != MAX8997_ESAFEOUT1 && rid != MAX8997_ESAFEOUT2) + return -EINVAL; + + ret = max8997_get_voltage_register(rdev, ®, &shift, &mask); + if (ret) + return ret; + + return max8997_update_reg(i2c, reg, selector << shift, mask << shift); +} + +static int max8997_reg_disable_suspend(struct regulator_dev *rdev) +{ + struct max8997_data *max8997 = rdev_get_drvdata(rdev); + struct i2c_client *i2c = max8997->iodev->i2c; + int ret, reg, mask, pattern; + int rid = rdev_get_id(rdev); + + ret = max8997_get_enable_register(rdev, ®, &mask, &pattern); + if (ret) + return ret; + + max8997_read_reg(i2c, reg, &max8997->saved_states[rid]); + + if (rid == MAX8997_LDO1 || + rid == MAX8997_LDO10 || + rid == MAX8997_LDO21) { + dev_dbg(&rdev->dev, "Conditional Power-Off for %s\n", + rdev->desc->name); + return max8997_update_reg(i2c, reg, 0x40, mask); + } + + dev_dbg(&rdev->dev, "Full Power-Off for %s (%xh -> %xh)\n", + rdev->desc->name, max8997->saved_states[rid] & mask, + (~pattern) & mask); + return max8997_update_reg(i2c, reg, ~pattern, mask); +} + +static struct regulator_ops max8997_ldo_ops = { + .list_voltage = max8997_list_voltage, + .is_enabled = max8997_reg_is_enabled, + .enable = max8997_reg_enable, + .disable = max8997_reg_disable, + .get_voltage_sel = max8997_get_voltage_sel, + .set_voltage = max8997_set_voltage_ldobuck, + .set_suspend_disable = max8997_reg_disable_suspend, +}; + +static struct regulator_ops max8997_buck_ops = { + .list_voltage = max8997_list_voltage, + .is_enabled = max8997_reg_is_enabled, + .enable = max8997_reg_enable, + .disable = max8997_reg_disable, + .get_voltage_sel = max8997_get_voltage_sel, + .set_voltage = max8997_set_voltage_buck, + .set_voltage_time_sel = max8997_set_voltage_buck_time_sel, + .set_suspend_disable = max8997_reg_disable_suspend, +}; + +static struct regulator_ops max8997_fixedvolt_ops = { + .list_voltage = max8997_list_voltage, + .is_enabled = max8997_reg_is_enabled, + .enable = max8997_reg_enable, + .disable = max8997_reg_disable, + .set_suspend_disable = max8997_reg_disable_suspend, +}; + +static struct regulator_ops max8997_safeout_ops = { + .list_voltage = regulator_list_voltage_table, + .is_enabled = max8997_reg_is_enabled, + .enable = max8997_reg_enable, + .disable = max8997_reg_disable, + .get_voltage_sel = max8997_get_voltage_sel, + .set_voltage_sel = max8997_set_voltage_safeout_sel, + .set_suspend_disable = max8997_reg_disable_suspend, +}; + +static struct regulator_ops max8997_fixedstate_ops = { + .list_voltage = max8997_list_voltage_charger_cv, + .get_voltage_sel = max8997_get_voltage_sel, + .set_voltage = max8997_set_voltage_charger_cv, +}; + +static int max8997_set_current_limit(struct regulator_dev *rdev, + int min_uA, int max_uA) +{ + unsigned dummy; + int rid = rdev_get_id(rdev); + + if (rid != MAX8997_CHARGER && rid != MAX8997_CHARGER_TOPOFF) + return -EINVAL; + + /* Reuse max8997_set_voltage_ldobuck to set current_limit. */ + return max8997_set_voltage_ldobuck(rdev, min_uA, max_uA, &dummy); +} + +static int max8997_get_current_limit(struct regulator_dev *rdev) +{ + int sel, rid = rdev_get_id(rdev); + + if (rid != MAX8997_CHARGER && rid != MAX8997_CHARGER_TOPOFF) + return -EINVAL; + + sel = max8997_get_voltage_sel(rdev); + if (sel < 0) + return sel; + + /* Reuse max8997_list_voltage to get current_limit. */ + return max8997_list_voltage(rdev, sel); +} + +static struct regulator_ops max8997_charger_ops = { + .is_enabled = max8997_reg_is_enabled, + .enable = max8997_reg_enable, + .disable = max8997_reg_disable, + .get_current_limit = max8997_get_current_limit, + .set_current_limit = max8997_set_current_limit, +}; + +static struct regulator_ops max8997_charger_fixedstate_ops = { + .get_current_limit = max8997_get_current_limit, + .set_current_limit = max8997_set_current_limit, +}; + +#define MAX8997_VOLTAGE_REGULATOR(_name, _ops) {\ + .name = #_name, \ + .id = MAX8997_##_name, \ + .ops = &_ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ +} + +#define MAX8997_CURRENT_REGULATOR(_name, _ops) {\ + .name = #_name, \ + .id = MAX8997_##_name, \ + .ops = &_ops, \ + .type = REGULATOR_CURRENT, \ + .owner = THIS_MODULE, \ +} + +static struct regulator_desc regulators[] = { + MAX8997_VOLTAGE_REGULATOR(LDO1, max8997_ldo_ops), + MAX8997_VOLTAGE_REGULATOR(LDO2, max8997_ldo_ops), + MAX8997_VOLTAGE_REGULATOR(LDO3, max8997_ldo_ops), + MAX8997_VOLTAGE_REGULATOR(LDO4, max8997_ldo_ops), + MAX8997_VOLTAGE_REGULATOR(LDO5, max8997_ldo_ops), + MAX8997_VOLTAGE_REGULATOR(LDO6, max8997_ldo_ops), + MAX8997_VOLTAGE_REGULATOR(LDO7, max8997_ldo_ops), + MAX8997_VOLTAGE_REGULATOR(LDO8, max8997_ldo_ops), + MAX8997_VOLTAGE_REGULATOR(LDO9, max8997_ldo_ops), + MAX8997_VOLTAGE_REGULATOR(LDO10, max8997_ldo_ops), + MAX8997_VOLTAGE_REGULATOR(LDO11, max8997_ldo_ops), + MAX8997_VOLTAGE_REGULATOR(LDO12, max8997_ldo_ops), + MAX8997_VOLTAGE_REGULATOR(LDO13, max8997_ldo_ops), + MAX8997_VOLTAGE_REGULATOR(LDO14, max8997_ldo_ops), + MAX8997_VOLTAGE_REGULATOR(LDO15, max8997_ldo_ops), + MAX8997_VOLTAGE_REGULATOR(LDO16, max8997_ldo_ops), + MAX8997_VOLTAGE_REGULATOR(LDO17, max8997_ldo_ops), + MAX8997_VOLTAGE_REGULATOR(LDO18, max8997_ldo_ops), + MAX8997_VOLTAGE_REGULATOR(LDO21, max8997_ldo_ops), + MAX8997_VOLTAGE_REGULATOR(BUCK1, max8997_buck_ops), + MAX8997_VOLTAGE_REGULATOR(BUCK2, max8997_buck_ops), + MAX8997_VOLTAGE_REGULATOR(BUCK3, max8997_buck_ops), + MAX8997_VOLTAGE_REGULATOR(BUCK4, max8997_buck_ops), + MAX8997_VOLTAGE_REGULATOR(BUCK5, max8997_buck_ops), + MAX8997_VOLTAGE_REGULATOR(BUCK6, max8997_fixedvolt_ops), + MAX8997_VOLTAGE_REGULATOR(BUCK7, max8997_buck_ops), + MAX8997_VOLTAGE_REGULATOR(EN32KHZ_AP, max8997_fixedvolt_ops), + MAX8997_VOLTAGE_REGULATOR(EN32KHZ_CP, max8997_fixedvolt_ops), + MAX8997_VOLTAGE_REGULATOR(ENVICHG, max8997_fixedvolt_ops), + MAX8997_VOLTAGE_REGULATOR(ESAFEOUT1, max8997_safeout_ops), + MAX8997_VOLTAGE_REGULATOR(ESAFEOUT2, max8997_safeout_ops), + MAX8997_VOLTAGE_REGULATOR(CHARGER_CV, max8997_fixedstate_ops), + MAX8997_CURRENT_REGULATOR(CHARGER, max8997_charger_ops), + MAX8997_CURRENT_REGULATOR(CHARGER_TOPOFF, + max8997_charger_fixedstate_ops), +}; + +#ifdef CONFIG_OF +static int max8997_pmic_dt_parse_dvs_gpio(struct platform_device *pdev, + struct max8997_platform_data *pdata, + struct device_node *pmic_np) +{ + int i, gpio; + + for (i = 0; i < 3; i++) { + gpio = of_get_named_gpio(pmic_np, + "max8997,pmic-buck125-dvs-gpios", i); + if (!gpio_is_valid(gpio)) { + dev_err(&pdev->dev, "invalid gpio[%d]: %d\n", i, gpio); + return -EINVAL; + } + pdata->buck125_gpios[i] = gpio; + } + return 0; +} + +static int max8997_pmic_dt_parse_pdata(struct platform_device *pdev, + struct max8997_platform_data *pdata) +{ + struct max8997_dev *iodev = dev_get_drvdata(pdev->dev.parent); + struct device_node *pmic_np, *regulators_np, *reg_np; + struct max8997_regulator_data *rdata; + unsigned int i, dvs_voltage_nr = 1, ret; + + pmic_np = iodev->dev->of_node; + if (!pmic_np) { + dev_err(&pdev->dev, "could not find pmic sub-node\n"); + return -ENODEV; + } + + regulators_np = of_get_child_by_name(pmic_np, "regulators"); + if (!regulators_np) { + dev_err(&pdev->dev, "could not find regulators sub-node\n"); + return -EINVAL; + } + + /* count the number of regulators to be supported in pmic */ + pdata->num_regulators = of_get_child_count(regulators_np); + + rdata = devm_kzalloc(&pdev->dev, sizeof(*rdata) * + pdata->num_regulators, GFP_KERNEL); + if (!rdata) { + of_node_put(regulators_np); + return -ENOMEM; + } + + pdata->regulators = rdata; + for_each_child_of_node(regulators_np, reg_np) { + for (i = 0; i < ARRAY_SIZE(regulators); i++) + if (!of_node_cmp(reg_np->name, regulators[i].name)) + break; + + if (i == ARRAY_SIZE(regulators)) { + dev_warn(&pdev->dev, "don't know how to configure regulator %s\n", + reg_np->name); + continue; + } + + rdata->id = i; + rdata->initdata = of_get_regulator_init_data(&pdev->dev, + reg_np, + ®ulators[i]); + rdata->reg_node = reg_np; + rdata++; + } + of_node_put(regulators_np); + + if (of_get_property(pmic_np, "max8997,pmic-buck1-uses-gpio-dvs", NULL)) + pdata->buck1_gpiodvs = true; + + if (of_get_property(pmic_np, "max8997,pmic-buck2-uses-gpio-dvs", NULL)) + pdata->buck2_gpiodvs = true; + + if (of_get_property(pmic_np, "max8997,pmic-buck5-uses-gpio-dvs", NULL)) + pdata->buck5_gpiodvs = true; + + if (pdata->buck1_gpiodvs || pdata->buck2_gpiodvs || + pdata->buck5_gpiodvs) { + ret = max8997_pmic_dt_parse_dvs_gpio(pdev, pdata, pmic_np); + if (ret) + return -EINVAL; + + if (of_property_read_u32(pmic_np, + "max8997,pmic-buck125-default-dvs-idx", + &pdata->buck125_default_idx)) { + pdata->buck125_default_idx = 0; + } else { + if (pdata->buck125_default_idx >= 8) { + pdata->buck125_default_idx = 0; + dev_info(&pdev->dev, "invalid value for default dvs index, using 0 instead\n"); + } + } + + if (of_get_property(pmic_np, + "max8997,pmic-ignore-gpiodvs-side-effect", NULL)) + pdata->ignore_gpiodvs_side_effect = true; + + dvs_voltage_nr = 8; + } + + if (of_property_read_u32_array(pmic_np, + "max8997,pmic-buck1-dvs-voltage", + pdata->buck1_voltage, dvs_voltage_nr)) { + dev_err(&pdev->dev, "buck1 voltages not specified\n"); + return -EINVAL; + } + + if (of_property_read_u32_array(pmic_np, + "max8997,pmic-buck2-dvs-voltage", + pdata->buck2_voltage, dvs_voltage_nr)) { + dev_err(&pdev->dev, "buck2 voltages not specified\n"); + return -EINVAL; + } + + if (of_property_read_u32_array(pmic_np, + "max8997,pmic-buck5-dvs-voltage", + pdata->buck5_voltage, dvs_voltage_nr)) { + dev_err(&pdev->dev, "buck5 voltages not specified\n"); + return -EINVAL; + } + + return 0; +} +#else +static int max8997_pmic_dt_parse_pdata(struct platform_device *pdev, + struct max8997_platform_data *pdata) +{ + return 0; +} +#endif /* CONFIG_OF */ + +static int max8997_pmic_probe(struct platform_device *pdev) +{ + struct max8997_dev *iodev = dev_get_drvdata(pdev->dev.parent); + struct max8997_platform_data *pdata = iodev->pdata; + struct regulator_config config = { }; + struct regulator_dev *rdev; + struct max8997_data *max8997; + struct i2c_client *i2c; + int i, ret, nr_dvs; + u8 max_buck1 = 0, max_buck2 = 0, max_buck5 = 0; + + if (!pdata) { + dev_err(&pdev->dev, "No platform init data supplied.\n"); + return -ENODEV; + } + + if (iodev->dev->of_node) { + ret = max8997_pmic_dt_parse_pdata(pdev, pdata); + if (ret) + return ret; + } + + max8997 = devm_kzalloc(&pdev->dev, sizeof(struct max8997_data), + GFP_KERNEL); + if (!max8997) + return -ENOMEM; + + max8997->dev = &pdev->dev; + max8997->iodev = iodev; + max8997->num_regulators = pdata->num_regulators; + platform_set_drvdata(pdev, max8997); + i2c = max8997->iodev->i2c; + + max8997->buck125_gpioindex = pdata->buck125_default_idx; + max8997->buck1_gpiodvs = pdata->buck1_gpiodvs; + max8997->buck2_gpiodvs = pdata->buck2_gpiodvs; + max8997->buck5_gpiodvs = pdata->buck5_gpiodvs; + memcpy(max8997->buck125_gpios, pdata->buck125_gpios, sizeof(int) * 3); + max8997->ignore_gpiodvs_side_effect = pdata->ignore_gpiodvs_side_effect; + + nr_dvs = (pdata->buck1_gpiodvs || pdata->buck2_gpiodvs || + pdata->buck5_gpiodvs) ? 8 : 1; + + for (i = 0; i < nr_dvs; i++) { + max8997->buck1_vol[i] = ret = + max8997_get_voltage_proper_val( + &buck1245_voltage_map_desc, + pdata->buck1_voltage[i], + pdata->buck1_voltage[i] + + buck1245_voltage_map_desc.step); + if (ret < 0) + return ret; + + max8997->buck2_vol[i] = ret = + max8997_get_voltage_proper_val( + &buck1245_voltage_map_desc, + pdata->buck2_voltage[i], + pdata->buck2_voltage[i] + + buck1245_voltage_map_desc.step); + if (ret < 0) + return ret; + + max8997->buck5_vol[i] = ret = + max8997_get_voltage_proper_val( + &buck1245_voltage_map_desc, + pdata->buck5_voltage[i], + pdata->buck5_voltage[i] + + buck1245_voltage_map_desc.step); + if (ret < 0) + return ret; + + if (max_buck1 < max8997->buck1_vol[i]) + max_buck1 = max8997->buck1_vol[i]; + if (max_buck2 < max8997->buck2_vol[i]) + max_buck2 = max8997->buck2_vol[i]; + if (max_buck5 < max8997->buck5_vol[i]) + max_buck5 = max8997->buck5_vol[i]; + } + + /* For the safety, set max voltage before setting up */ + for (i = 0; i < 8; i++) { + max8997_update_reg(i2c, MAX8997_REG_BUCK1DVS1 + i, + max_buck1, 0x3f); + max8997_update_reg(i2c, MAX8997_REG_BUCK2DVS1 + i, + max_buck2, 0x3f); + max8997_update_reg(i2c, MAX8997_REG_BUCK5DVS1 + i, + max_buck5, 0x3f); + } + + /* Initialize all the DVS related BUCK registers */ + for (i = 0; i < nr_dvs; i++) { + max8997_update_reg(i2c, MAX8997_REG_BUCK1DVS1 + i, + max8997->buck1_vol[i], + 0x3f); + max8997_update_reg(i2c, MAX8997_REG_BUCK2DVS1 + i, + max8997->buck2_vol[i], + 0x3f); + max8997_update_reg(i2c, MAX8997_REG_BUCK5DVS1 + i, + max8997->buck5_vol[i], + 0x3f); + } + + /* + * If buck 1, 2, and 5 do not care DVS GPIO settings, ignore them. + * If at least one of them cares, set gpios. + */ + if (pdata->buck1_gpiodvs || pdata->buck2_gpiodvs || + pdata->buck5_gpiodvs) { + + if (!gpio_is_valid(pdata->buck125_gpios[0]) || + !gpio_is_valid(pdata->buck125_gpios[1]) || + !gpio_is_valid(pdata->buck125_gpios[2])) { + dev_err(&pdev->dev, "GPIO NOT VALID\n"); + return -EINVAL; + } + + ret = devm_gpio_request(&pdev->dev, pdata->buck125_gpios[0], + "MAX8997 SET1"); + if (ret) + return ret; + + ret = devm_gpio_request(&pdev->dev, pdata->buck125_gpios[1], + "MAX8997 SET2"); + if (ret) + return ret; + + ret = devm_gpio_request(&pdev->dev, pdata->buck125_gpios[2], + "MAX8997 SET3"); + if (ret) + return ret; + + gpio_direction_output(pdata->buck125_gpios[0], + (max8997->buck125_gpioindex >> 2) + & 0x1); /* SET1 */ + gpio_direction_output(pdata->buck125_gpios[1], + (max8997->buck125_gpioindex >> 1) + & 0x1); /* SET2 */ + gpio_direction_output(pdata->buck125_gpios[2], + (max8997->buck125_gpioindex >> 0) + & 0x1); /* SET3 */ + } + + /* DVS-GPIO disabled */ + max8997_update_reg(i2c, MAX8997_REG_BUCK1CTRL, (pdata->buck1_gpiodvs) ? + (1 << 1) : (0 << 1), 1 << 1); + max8997_update_reg(i2c, MAX8997_REG_BUCK2CTRL, (pdata->buck2_gpiodvs) ? + (1 << 1) : (0 << 1), 1 << 1); + max8997_update_reg(i2c, MAX8997_REG_BUCK5CTRL, (pdata->buck5_gpiodvs) ? + (1 << 1) : (0 << 1), 1 << 1); + + /* Misc Settings */ + max8997->ramp_delay = 10; /* set 10mV/us, which is the default */ + max8997_write_reg(i2c, MAX8997_REG_BUCKRAMP, (0xf << 4) | 0x9); + + for (i = 0; i < pdata->num_regulators; i++) { + const struct voltage_map_desc *desc; + int id = pdata->regulators[i].id; + + desc = reg_voltage_map[id]; + if (desc) { + regulators[id].n_voltages = + (desc->max - desc->min) / desc->step + 1; + } else if (id == MAX8997_ESAFEOUT1 || id == MAX8997_ESAFEOUT2) { + regulators[id].volt_table = safeoutvolt; + regulators[id].n_voltages = ARRAY_SIZE(safeoutvolt); + } else if (id == MAX8997_CHARGER_CV) { + regulators[id].n_voltages = 16; + } + + config.dev = max8997->dev; + config.init_data = pdata->regulators[i].initdata; + config.driver_data = max8997; + config.of_node = pdata->regulators[i].reg_node; + + rdev = devm_regulator_register(&pdev->dev, ®ulators[id], + &config); + if (IS_ERR(rdev)) { + dev_err(max8997->dev, "regulator init failed for %d\n", + id); + return PTR_ERR(rdev); + } + } + + return 0; +} + +static const struct platform_device_id max8997_pmic_id[] = { + { "max8997-pmic", 0}, + { }, +}; +MODULE_DEVICE_TABLE(platform, max8997_pmic_id); + +static struct platform_driver max8997_pmic_driver = { + .driver = { + .name = "max8997-pmic", + }, + .probe = max8997_pmic_probe, + .id_table = max8997_pmic_id, +}; + +static int __init max8997_pmic_init(void) +{ + return platform_driver_register(&max8997_pmic_driver); +} +subsys_initcall(max8997_pmic_init); + +static void __exit max8997_pmic_cleanup(void) +{ + platform_driver_unregister(&max8997_pmic_driver); +} +module_exit(max8997_pmic_cleanup); + +MODULE_DESCRIPTION("MAXIM 8997/8966 Regulator Driver"); +MODULE_AUTHOR("MyungJoo Ham "); +MODULE_LICENSE("GPL"); diff --git a/drivers/regulator/max8997.c b/drivers/regulator/max8997.c deleted file mode 100644 index ea0196d4496b..000000000000 --- a/drivers/regulator/max8997.c +++ /dev/null @@ -1,1241 +0,0 @@ -/* - * max8997.c - Regulator driver for the Maxim 8997/8966 - * - * Copyright (C) 2011 Samsung Electronics - * MyungJoo Ham - * - * 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 max8998.c - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -struct max8997_data { - struct device *dev; - struct max8997_dev *iodev; - int num_regulators; - int ramp_delay; /* in mV/us */ - - bool buck1_gpiodvs; - bool buck2_gpiodvs; - bool buck5_gpiodvs; - u8 buck1_vol[8]; - u8 buck2_vol[8]; - u8 buck5_vol[8]; - int buck125_gpios[3]; - int buck125_gpioindex; - bool ignore_gpiodvs_side_effect; - - u8 saved_states[MAX8997_REG_MAX]; -}; - -static const unsigned int safeoutvolt[] = { - 4850000, - 4900000, - 4950000, - 3300000, -}; - -static inline void max8997_set_gpio(struct max8997_data *max8997) -{ - int set3 = (max8997->buck125_gpioindex) & 0x1; - int set2 = ((max8997->buck125_gpioindex) >> 1) & 0x1; - int set1 = ((max8997->buck125_gpioindex) >> 2) & 0x1; - - gpio_set_value(max8997->buck125_gpios[0], set1); - gpio_set_value(max8997->buck125_gpios[1], set2); - gpio_set_value(max8997->buck125_gpios[2], set3); -} - -struct voltage_map_desc { - int min; - int max; - int step; -}; - -/* Voltage maps in uV */ -static const struct voltage_map_desc ldo_voltage_map_desc = { - .min = 800000, .max = 3950000, .step = 50000, -}; /* LDO1 ~ 18, 21 all */ - -static const struct voltage_map_desc buck1245_voltage_map_desc = { - .min = 650000, .max = 2225000, .step = 25000, -}; /* Buck1, 2, 4, 5 */ - -static const struct voltage_map_desc buck37_voltage_map_desc = { - .min = 750000, .max = 3900000, .step = 50000, -}; /* Buck3, 7 */ - -/* current map in uA */ -static const struct voltage_map_desc charger_current_map_desc = { - .min = 200000, .max = 950000, .step = 50000, -}; - -static const struct voltage_map_desc topoff_current_map_desc = { - .min = 50000, .max = 200000, .step = 10000, -}; - -static const struct voltage_map_desc *reg_voltage_map[] = { - [MAX8997_LDO1] = &ldo_voltage_map_desc, - [MAX8997_LDO2] = &ldo_voltage_map_desc, - [MAX8997_LDO3] = &ldo_voltage_map_desc, - [MAX8997_LDO4] = &ldo_voltage_map_desc, - [MAX8997_LDO5] = &ldo_voltage_map_desc, - [MAX8997_LDO6] = &ldo_voltage_map_desc, - [MAX8997_LDO7] = &ldo_voltage_map_desc, - [MAX8997_LDO8] = &ldo_voltage_map_desc, - [MAX8997_LDO9] = &ldo_voltage_map_desc, - [MAX8997_LDO10] = &ldo_voltage_map_desc, - [MAX8997_LDO11] = &ldo_voltage_map_desc, - [MAX8997_LDO12] = &ldo_voltage_map_desc, - [MAX8997_LDO13] = &ldo_voltage_map_desc, - [MAX8997_LDO14] = &ldo_voltage_map_desc, - [MAX8997_LDO15] = &ldo_voltage_map_desc, - [MAX8997_LDO16] = &ldo_voltage_map_desc, - [MAX8997_LDO17] = &ldo_voltage_map_desc, - [MAX8997_LDO18] = &ldo_voltage_map_desc, - [MAX8997_LDO21] = &ldo_voltage_map_desc, - [MAX8997_BUCK1] = &buck1245_voltage_map_desc, - [MAX8997_BUCK2] = &buck1245_voltage_map_desc, - [MAX8997_BUCK3] = &buck37_voltage_map_desc, - [MAX8997_BUCK4] = &buck1245_voltage_map_desc, - [MAX8997_BUCK5] = &buck1245_voltage_map_desc, - [MAX8997_BUCK6] = NULL, - [MAX8997_BUCK7] = &buck37_voltage_map_desc, - [MAX8997_EN32KHZ_AP] = NULL, - [MAX8997_EN32KHZ_CP] = NULL, - [MAX8997_ENVICHG] = NULL, - [MAX8997_ESAFEOUT1] = NULL, - [MAX8997_ESAFEOUT2] = NULL, - [MAX8997_CHARGER_CV] = NULL, - [MAX8997_CHARGER] = &charger_current_map_desc, - [MAX8997_CHARGER_TOPOFF] = &topoff_current_map_desc, -}; - -static int max8997_list_voltage_charger_cv(struct regulator_dev *rdev, - unsigned int selector) -{ - int rid = rdev_get_id(rdev); - - if (rid != MAX8997_CHARGER_CV) - goto err; - - switch (selector) { - case 0x00: - return 4200000; - case 0x01 ... 0x0E: - return 4000000 + 20000 * (selector - 0x01); - case 0x0F: - return 4350000; - default: - return -EINVAL; - } -err: - return -EINVAL; -} - -static int max8997_list_voltage(struct regulator_dev *rdev, - unsigned int selector) -{ - const struct voltage_map_desc *desc; - int rid = rdev_get_id(rdev); - int val; - - if (rid >= ARRAY_SIZE(reg_voltage_map) || - rid < 0) - return -EINVAL; - - desc = reg_voltage_map[rid]; - if (desc == NULL) - return -EINVAL; - - val = desc->min + desc->step * selector; - if (val > desc->max) - return -EINVAL; - - return val; -} - -static int max8997_get_enable_register(struct regulator_dev *rdev, - int *reg, int *mask, int *pattern) -{ - int rid = rdev_get_id(rdev); - - switch (rid) { - case MAX8997_LDO1 ... MAX8997_LDO21: - *reg = MAX8997_REG_LDO1CTRL + (rid - MAX8997_LDO1); - *mask = 0xC0; - *pattern = 0xC0; - break; - case MAX8997_BUCK1: - *reg = MAX8997_REG_BUCK1CTRL; - *mask = 0x01; - *pattern = 0x01; - break; - case MAX8997_BUCK2: - *reg = MAX8997_REG_BUCK2CTRL; - *mask = 0x01; - *pattern = 0x01; - break; - case MAX8997_BUCK3: - *reg = MAX8997_REG_BUCK3CTRL; - *mask = 0x01; - *pattern = 0x01; - break; - case MAX8997_BUCK4: - *reg = MAX8997_REG_BUCK4CTRL; - *mask = 0x01; - *pattern = 0x01; - break; - case MAX8997_BUCK5: - *reg = MAX8997_REG_BUCK5CTRL; - *mask = 0x01; - *pattern = 0x01; - break; - case MAX8997_BUCK6: - *reg = MAX8997_REG_BUCK6CTRL; - *mask = 0x01; - *pattern = 0x01; - break; - case MAX8997_BUCK7: - *reg = MAX8997_REG_BUCK7CTRL; - *mask = 0x01; - *pattern = 0x01; - break; - case MAX8997_EN32KHZ_AP ... MAX8997_EN32KHZ_CP: - *reg = MAX8997_REG_MAINCON1; - *mask = 0x01 << (rid - MAX8997_EN32KHZ_AP); - *pattern = 0x01 << (rid - MAX8997_EN32KHZ_AP); - break; - case MAX8997_ENVICHG: - *reg = MAX8997_REG_MBCCTRL1; - *mask = 0x80; - *pattern = 0x80; - break; - case MAX8997_ESAFEOUT1 ... MAX8997_ESAFEOUT2: - *reg = MAX8997_REG_SAFEOUTCTRL; - *mask = 0x40 << (rid - MAX8997_ESAFEOUT1); - *pattern = 0x40 << (rid - MAX8997_ESAFEOUT1); - break; - case MAX8997_CHARGER: - *reg = MAX8997_REG_MBCCTRL2; - *mask = 0x40; - *pattern = 0x40; - break; - default: - /* Not controllable or not exists */ - return -EINVAL; - } - - return 0; -} - -static int max8997_reg_is_enabled(struct regulator_dev *rdev) -{ - struct max8997_data *max8997 = rdev_get_drvdata(rdev); - struct i2c_client *i2c = max8997->iodev->i2c; - int ret, reg, mask, pattern; - u8 val; - - ret = max8997_get_enable_register(rdev, ®, &mask, &pattern); - if (ret) - return ret; - - ret = max8997_read_reg(i2c, reg, &val); - if (ret) - return ret; - - return (val & mask) == pattern; -} - -static int max8997_reg_enable(struct regulator_dev *rdev) -{ - struct max8997_data *max8997 = rdev_get_drvdata(rdev); - struct i2c_client *i2c = max8997->iodev->i2c; - int ret, reg, mask, pattern; - - ret = max8997_get_enable_register(rdev, ®, &mask, &pattern); - if (ret) - return ret; - - return max8997_update_reg(i2c, reg, pattern, mask); -} - -static int max8997_reg_disable(struct regulator_dev *rdev) -{ - struct max8997_data *max8997 = rdev_get_drvdata(rdev); - struct i2c_client *i2c = max8997->iodev->i2c; - int ret, reg, mask, pattern; - - ret = max8997_get_enable_register(rdev, ®, &mask, &pattern); - if (ret) - return ret; - - return max8997_update_reg(i2c, reg, ~pattern, mask); -} - -static int max8997_get_voltage_register(struct regulator_dev *rdev, - int *_reg, int *_shift, int *_mask) -{ - struct max8997_data *max8997 = rdev_get_drvdata(rdev); - int rid = rdev_get_id(rdev); - int reg, shift = 0, mask = 0x3f; - - switch (rid) { - case MAX8997_LDO1 ... MAX8997_LDO21: - reg = MAX8997_REG_LDO1CTRL + (rid - MAX8997_LDO1); - break; - case MAX8997_BUCK1: - reg = MAX8997_REG_BUCK1DVS1; - if (max8997->buck1_gpiodvs) - reg += max8997->buck125_gpioindex; - break; - case MAX8997_BUCK2: - reg = MAX8997_REG_BUCK2DVS1; - if (max8997->buck2_gpiodvs) - reg += max8997->buck125_gpioindex; - break; - case MAX8997_BUCK3: - reg = MAX8997_REG_BUCK3DVS; - break; - case MAX8997_BUCK4: - reg = MAX8997_REG_BUCK4DVS; - break; - case MAX8997_BUCK5: - reg = MAX8997_REG_BUCK5DVS1; - if (max8997->buck5_gpiodvs) - reg += max8997->buck125_gpioindex; - break; - case MAX8997_BUCK7: - reg = MAX8997_REG_BUCK7DVS; - break; - case MAX8997_ESAFEOUT1 ... MAX8997_ESAFEOUT2: - reg = MAX8997_REG_SAFEOUTCTRL; - shift = (rid == MAX8997_ESAFEOUT2) ? 2 : 0; - mask = 0x3; - break; - case MAX8997_CHARGER_CV: - reg = MAX8997_REG_MBCCTRL3; - shift = 0; - mask = 0xf; - break; - case MAX8997_CHARGER: - reg = MAX8997_REG_MBCCTRL4; - shift = 0; - mask = 0xf; - break; - case MAX8997_CHARGER_TOPOFF: - reg = MAX8997_REG_MBCCTRL5; - shift = 0; - mask = 0xf; - break; - default: - return -EINVAL; - } - - *_reg = reg; - *_shift = shift; - *_mask = mask; - - return 0; -} - -static int max8997_get_voltage_sel(struct regulator_dev *rdev) -{ - struct max8997_data *max8997 = rdev_get_drvdata(rdev); - struct i2c_client *i2c = max8997->iodev->i2c; - int reg, shift, mask, ret; - u8 val; - - ret = max8997_get_voltage_register(rdev, ®, &shift, &mask); - if (ret) - return ret; - - ret = max8997_read_reg(i2c, reg, &val); - if (ret) - return ret; - - val >>= shift; - val &= mask; - - return val; -} - -static inline int max8997_get_voltage_proper_val( - const struct voltage_map_desc *desc, - int min_vol, int max_vol) -{ - int i; - - if (desc == NULL) - return -EINVAL; - - if (max_vol < desc->min || min_vol > desc->max) - return -EINVAL; - - if (min_vol < desc->min) - min_vol = desc->min; - - i = DIV_ROUND_UP(min_vol - desc->min, desc->step); - - if (desc->min + desc->step * i > max_vol) - return -EINVAL; - - return i; -} - -static int max8997_set_voltage_charger_cv(struct regulator_dev *rdev, - int min_uV, int max_uV, unsigned *selector) -{ - struct max8997_data *max8997 = rdev_get_drvdata(rdev); - struct i2c_client *i2c = max8997->iodev->i2c; - int rid = rdev_get_id(rdev); - int lb, ub; - int reg, shift = 0, mask, ret = 0; - u8 val = 0x0; - - if (rid != MAX8997_CHARGER_CV) - return -EINVAL; - - ret = max8997_get_voltage_register(rdev, ®, &shift, &mask); - if (ret) - return ret; - - if (max_uV < 4000000 || min_uV > 4350000) - return -EINVAL; - - if (min_uV <= 4000000) { - if (max_uV >= 4000000) - return -EINVAL; - else - val = 0x1; - } else if (min_uV <= 4200000 && max_uV >= 4200000) - val = 0x0; - else { - lb = (min_uV - 4000001) / 20000 + 2; - ub = (max_uV - 4000000) / 20000 + 1; - - if (lb > ub) - return -EINVAL; - - if (lb < 0xf) - val = lb; - else { - if (ub >= 0xf) - val = 0xf; - else - return -EINVAL; - } - } - - *selector = val; - - ret = max8997_update_reg(i2c, reg, val << shift, mask); - - return ret; -} - -/* - * For LDO1 ~ LDO21, BUCK1~5, BUCK7, CHARGER, CHARGER_TOPOFF - * BUCK1, 2, and 5 are available if they are not controlled by gpio - */ -static int max8997_set_voltage_ldobuck(struct regulator_dev *rdev, - int min_uV, int max_uV, unsigned *selector) -{ - struct max8997_data *max8997 = rdev_get_drvdata(rdev); - struct i2c_client *i2c = max8997->iodev->i2c; - const struct voltage_map_desc *desc; - int rid = rdev_get_id(rdev); - int i, reg, shift, mask, ret; - - switch (rid) { - case MAX8997_LDO1 ... MAX8997_LDO21: - break; - case MAX8997_BUCK1 ... MAX8997_BUCK5: - break; - case MAX8997_BUCK6: - return -EINVAL; - case MAX8997_BUCK7: - break; - case MAX8997_CHARGER: - break; - case MAX8997_CHARGER_TOPOFF: - break; - default: - return -EINVAL; - } - - desc = reg_voltage_map[rid]; - - i = max8997_get_voltage_proper_val(desc, min_uV, max_uV); - if (i < 0) - return i; - - ret = max8997_get_voltage_register(rdev, ®, &shift, &mask); - if (ret) - return ret; - - ret = max8997_update_reg(i2c, reg, i << shift, mask << shift); - *selector = i; - - return ret; -} - -static int max8997_set_voltage_buck_time_sel(struct regulator_dev *rdev, - unsigned int old_selector, - unsigned int new_selector) -{ - struct max8997_data *max8997 = rdev_get_drvdata(rdev); - int rid = rdev_get_id(rdev); - const struct voltage_map_desc *desc = reg_voltage_map[rid]; - - /* Delay is required only if the voltage is increasing */ - if (old_selector >= new_selector) - return 0; - - /* No need to delay if gpio_dvs_mode */ - switch (rid) { - case MAX8997_BUCK1: - if (max8997->buck1_gpiodvs) - return 0; - break; - case MAX8997_BUCK2: - if (max8997->buck2_gpiodvs) - return 0; - break; - case MAX8997_BUCK5: - if (max8997->buck5_gpiodvs) - return 0; - break; - } - - switch (rid) { - case MAX8997_BUCK1: - case MAX8997_BUCK2: - case MAX8997_BUCK4: - case MAX8997_BUCK5: - return DIV_ROUND_UP(desc->step * (new_selector - old_selector), - max8997->ramp_delay * 1000); - } - - return 0; -} - -/* - * Assess the damage on the voltage setting of BUCK1,2,5 by the change. - * - * When GPIO-DVS mode is used for multiple bucks, changing the voltage value - * of one of the bucks may affect that of another buck, which is the side - * effect of the change (set_voltage). This function examines the GPIO-DVS - * configurations and checks whether such side-effect exists. - */ -static int max8997_assess_side_effect(struct regulator_dev *rdev, - u8 new_val, int *best) -{ - struct max8997_data *max8997 = rdev_get_drvdata(rdev); - int rid = rdev_get_id(rdev); - u8 *buckx_val[3]; - bool buckx_gpiodvs[3]; - int side_effect[8]; - int min_side_effect = INT_MAX; - int i; - - *best = -1; - - switch (rid) { - case MAX8997_BUCK1: - rid = 0; - break; - case MAX8997_BUCK2: - rid = 1; - break; - case MAX8997_BUCK5: - rid = 2; - break; - default: - return -EINVAL; - } - - buckx_val[0] = max8997->buck1_vol; - buckx_val[1] = max8997->buck2_vol; - buckx_val[2] = max8997->buck5_vol; - buckx_gpiodvs[0] = max8997->buck1_gpiodvs; - buckx_gpiodvs[1] = max8997->buck2_gpiodvs; - buckx_gpiodvs[2] = max8997->buck5_gpiodvs; - - for (i = 0; i < 8; i++) { - int others; - - if (new_val != (buckx_val[rid])[i]) { - side_effect[i] = -1; - continue; - } - - side_effect[i] = 0; - for (others = 0; others < 3; others++) { - int diff; - - if (others == rid) - continue; - if (buckx_gpiodvs[others] == false) - continue; /* Not affected */ - diff = (buckx_val[others])[i] - - (buckx_val[others])[max8997->buck125_gpioindex]; - if (diff > 0) - side_effect[i] += diff; - else if (diff < 0) - side_effect[i] -= diff; - } - if (side_effect[i] == 0) { - *best = i; - return 0; /* NO SIDE EFFECT! Use This! */ - } - if (side_effect[i] < min_side_effect) { - min_side_effect = side_effect[i]; - *best = i; - } - } - - if (*best == -1) - return -EINVAL; - - return side_effect[*best]; -} - -/* - * For Buck 1 ~ 5 and 7. If it is not controlled by GPIO, this calls - * max8997_set_voltage_ldobuck to do the job. - */ -static int max8997_set_voltage_buck(struct regulator_dev *rdev, - int min_uV, int max_uV, unsigned *selector) -{ - struct max8997_data *max8997 = rdev_get_drvdata(rdev); - int rid = rdev_get_id(rdev); - const struct voltage_map_desc *desc; - int new_val, new_idx, damage, tmp_val, tmp_idx, tmp_dmg; - bool gpio_dvs_mode = false; - - if (rid < MAX8997_BUCK1 || rid > MAX8997_BUCK7) - return -EINVAL; - - switch (rid) { - case MAX8997_BUCK1: - if (max8997->buck1_gpiodvs) - gpio_dvs_mode = true; - break; - case MAX8997_BUCK2: - if (max8997->buck2_gpiodvs) - gpio_dvs_mode = true; - break; - case MAX8997_BUCK5: - if (max8997->buck5_gpiodvs) - gpio_dvs_mode = true; - break; - } - - if (!gpio_dvs_mode) - return max8997_set_voltage_ldobuck(rdev, min_uV, max_uV, - selector); - - desc = reg_voltage_map[rid]; - new_val = max8997_get_voltage_proper_val(desc, min_uV, max_uV); - if (new_val < 0) - return new_val; - - tmp_dmg = INT_MAX; - tmp_idx = -1; - tmp_val = -1; - do { - damage = max8997_assess_side_effect(rdev, new_val, &new_idx); - if (damage == 0) - goto out; - - if (tmp_dmg > damage) { - tmp_idx = new_idx; - tmp_val = new_val; - tmp_dmg = damage; - } - - new_val++; - } while (desc->min + desc->step * new_val <= desc->max); - - new_idx = tmp_idx; - new_val = tmp_val; - - if (max8997->ignore_gpiodvs_side_effect == false) - return -EINVAL; - - dev_warn(&rdev->dev, - "MAX8997 GPIO-DVS Side Effect Warning: GPIO SET: %d -> %d\n", - max8997->buck125_gpioindex, tmp_idx); - -out: - if (new_idx < 0 || new_val < 0) - return -EINVAL; - - max8997->buck125_gpioindex = new_idx; - max8997_set_gpio(max8997); - *selector = new_val; - - return 0; -} - -/* For SAFEOUT1 and SAFEOUT2 */ -static int max8997_set_voltage_safeout_sel(struct regulator_dev *rdev, - unsigned selector) -{ - struct max8997_data *max8997 = rdev_get_drvdata(rdev); - struct i2c_client *i2c = max8997->iodev->i2c; - int rid = rdev_get_id(rdev); - int reg, shift = 0, mask, ret; - - if (rid != MAX8997_ESAFEOUT1 && rid != MAX8997_ESAFEOUT2) - return -EINVAL; - - ret = max8997_get_voltage_register(rdev, ®, &shift, &mask); - if (ret) - return ret; - - return max8997_update_reg(i2c, reg, selector << shift, mask << shift); -} - -static int max8997_reg_disable_suspend(struct regulator_dev *rdev) -{ - struct max8997_data *max8997 = rdev_get_drvdata(rdev); - struct i2c_client *i2c = max8997->iodev->i2c; - int ret, reg, mask, pattern; - int rid = rdev_get_id(rdev); - - ret = max8997_get_enable_register(rdev, ®, &mask, &pattern); - if (ret) - return ret; - - max8997_read_reg(i2c, reg, &max8997->saved_states[rid]); - - if (rid == MAX8997_LDO1 || - rid == MAX8997_LDO10 || - rid == MAX8997_LDO21) { - dev_dbg(&rdev->dev, "Conditional Power-Off for %s\n", - rdev->desc->name); - return max8997_update_reg(i2c, reg, 0x40, mask); - } - - dev_dbg(&rdev->dev, "Full Power-Off for %s (%xh -> %xh)\n", - rdev->desc->name, max8997->saved_states[rid] & mask, - (~pattern) & mask); - return max8997_update_reg(i2c, reg, ~pattern, mask); -} - -static struct regulator_ops max8997_ldo_ops = { - .list_voltage = max8997_list_voltage, - .is_enabled = max8997_reg_is_enabled, - .enable = max8997_reg_enable, - .disable = max8997_reg_disable, - .get_voltage_sel = max8997_get_voltage_sel, - .set_voltage = max8997_set_voltage_ldobuck, - .set_suspend_disable = max8997_reg_disable_suspend, -}; - -static struct regulator_ops max8997_buck_ops = { - .list_voltage = max8997_list_voltage, - .is_enabled = max8997_reg_is_enabled, - .enable = max8997_reg_enable, - .disable = max8997_reg_disable, - .get_voltage_sel = max8997_get_voltage_sel, - .set_voltage = max8997_set_voltage_buck, - .set_voltage_time_sel = max8997_set_voltage_buck_time_sel, - .set_suspend_disable = max8997_reg_disable_suspend, -}; - -static struct regulator_ops max8997_fixedvolt_ops = { - .list_voltage = max8997_list_voltage, - .is_enabled = max8997_reg_is_enabled, - .enable = max8997_reg_enable, - .disable = max8997_reg_disable, - .set_suspend_disable = max8997_reg_disable_suspend, -}; - -static struct regulator_ops max8997_safeout_ops = { - .list_voltage = regulator_list_voltage_table, - .is_enabled = max8997_reg_is_enabled, - .enable = max8997_reg_enable, - .disable = max8997_reg_disable, - .get_voltage_sel = max8997_get_voltage_sel, - .set_voltage_sel = max8997_set_voltage_safeout_sel, - .set_suspend_disable = max8997_reg_disable_suspend, -}; - -static struct regulator_ops max8997_fixedstate_ops = { - .list_voltage = max8997_list_voltage_charger_cv, - .get_voltage_sel = max8997_get_voltage_sel, - .set_voltage = max8997_set_voltage_charger_cv, -}; - -static int max8997_set_current_limit(struct regulator_dev *rdev, - int min_uA, int max_uA) -{ - unsigned dummy; - int rid = rdev_get_id(rdev); - - if (rid != MAX8997_CHARGER && rid != MAX8997_CHARGER_TOPOFF) - return -EINVAL; - - /* Reuse max8997_set_voltage_ldobuck to set current_limit. */ - return max8997_set_voltage_ldobuck(rdev, min_uA, max_uA, &dummy); -} - -static int max8997_get_current_limit(struct regulator_dev *rdev) -{ - int sel, rid = rdev_get_id(rdev); - - if (rid != MAX8997_CHARGER && rid != MAX8997_CHARGER_TOPOFF) - return -EINVAL; - - sel = max8997_get_voltage_sel(rdev); - if (sel < 0) - return sel; - - /* Reuse max8997_list_voltage to get current_limit. */ - return max8997_list_voltage(rdev, sel); -} - -static struct regulator_ops max8997_charger_ops = { - .is_enabled = max8997_reg_is_enabled, - .enable = max8997_reg_enable, - .disable = max8997_reg_disable, - .get_current_limit = max8997_get_current_limit, - .set_current_limit = max8997_set_current_limit, -}; - -static struct regulator_ops max8997_charger_fixedstate_ops = { - .get_current_limit = max8997_get_current_limit, - .set_current_limit = max8997_set_current_limit, -}; - -#define MAX8997_VOLTAGE_REGULATOR(_name, _ops) {\ - .name = #_name, \ - .id = MAX8997_##_name, \ - .ops = &_ops, \ - .type = REGULATOR_VOLTAGE, \ - .owner = THIS_MODULE, \ -} - -#define MAX8997_CURRENT_REGULATOR(_name, _ops) {\ - .name = #_name, \ - .id = MAX8997_##_name, \ - .ops = &_ops, \ - .type = REGULATOR_CURRENT, \ - .owner = THIS_MODULE, \ -} - -static struct regulator_desc regulators[] = { - MAX8997_VOLTAGE_REGULATOR(LDO1, max8997_ldo_ops), - MAX8997_VOLTAGE_REGULATOR(LDO2, max8997_ldo_ops), - MAX8997_VOLTAGE_REGULATOR(LDO3, max8997_ldo_ops), - MAX8997_VOLTAGE_REGULATOR(LDO4, max8997_ldo_ops), - MAX8997_VOLTAGE_REGULATOR(LDO5, max8997_ldo_ops), - MAX8997_VOLTAGE_REGULATOR(LDO6, max8997_ldo_ops), - MAX8997_VOLTAGE_REGULATOR(LDO7, max8997_ldo_ops), - MAX8997_VOLTAGE_REGULATOR(LDO8, max8997_ldo_ops), - MAX8997_VOLTAGE_REGULATOR(LDO9, max8997_ldo_ops), - MAX8997_VOLTAGE_REGULATOR(LDO10, max8997_ldo_ops), - MAX8997_VOLTAGE_REGULATOR(LDO11, max8997_ldo_ops), - MAX8997_VOLTAGE_REGULATOR(LDO12, max8997_ldo_ops), - MAX8997_VOLTAGE_REGULATOR(LDO13, max8997_ldo_ops), - MAX8997_VOLTAGE_REGULATOR(LDO14, max8997_ldo_ops), - MAX8997_VOLTAGE_REGULATOR(LDO15, max8997_ldo_ops), - MAX8997_VOLTAGE_REGULATOR(LDO16, max8997_ldo_ops), - MAX8997_VOLTAGE_REGULATOR(LDO17, max8997_ldo_ops), - MAX8997_VOLTAGE_REGULATOR(LDO18, max8997_ldo_ops), - MAX8997_VOLTAGE_REGULATOR(LDO21, max8997_ldo_ops), - MAX8997_VOLTAGE_REGULATOR(BUCK1, max8997_buck_ops), - MAX8997_VOLTAGE_REGULATOR(BUCK2, max8997_buck_ops), - MAX8997_VOLTAGE_REGULATOR(BUCK3, max8997_buck_ops), - MAX8997_VOLTAGE_REGULATOR(BUCK4, max8997_buck_ops), - MAX8997_VOLTAGE_REGULATOR(BUCK5, max8997_buck_ops), - MAX8997_VOLTAGE_REGULATOR(BUCK6, max8997_fixedvolt_ops), - MAX8997_VOLTAGE_REGULATOR(BUCK7, max8997_buck_ops), - MAX8997_VOLTAGE_REGULATOR(EN32KHZ_AP, max8997_fixedvolt_ops), - MAX8997_VOLTAGE_REGULATOR(EN32KHZ_CP, max8997_fixedvolt_ops), - MAX8997_VOLTAGE_REGULATOR(ENVICHG, max8997_fixedvolt_ops), - MAX8997_VOLTAGE_REGULATOR(ESAFEOUT1, max8997_safeout_ops), - MAX8997_VOLTAGE_REGULATOR(ESAFEOUT2, max8997_safeout_ops), - MAX8997_VOLTAGE_REGULATOR(CHARGER_CV, max8997_fixedstate_ops), - MAX8997_CURRENT_REGULATOR(CHARGER, max8997_charger_ops), - MAX8997_CURRENT_REGULATOR(CHARGER_TOPOFF, - max8997_charger_fixedstate_ops), -}; - -#ifdef CONFIG_OF -static int max8997_pmic_dt_parse_dvs_gpio(struct platform_device *pdev, - struct max8997_platform_data *pdata, - struct device_node *pmic_np) -{ - int i, gpio; - - for (i = 0; i < 3; i++) { - gpio = of_get_named_gpio(pmic_np, - "max8997,pmic-buck125-dvs-gpios", i); - if (!gpio_is_valid(gpio)) { - dev_err(&pdev->dev, "invalid gpio[%d]: %d\n", i, gpio); - return -EINVAL; - } - pdata->buck125_gpios[i] = gpio; - } - return 0; -} - -static int max8997_pmic_dt_parse_pdata(struct platform_device *pdev, - struct max8997_platform_data *pdata) -{ - struct max8997_dev *iodev = dev_get_drvdata(pdev->dev.parent); - struct device_node *pmic_np, *regulators_np, *reg_np; - struct max8997_regulator_data *rdata; - unsigned int i, dvs_voltage_nr = 1, ret; - - pmic_np = iodev->dev->of_node; - if (!pmic_np) { - dev_err(&pdev->dev, "could not find pmic sub-node\n"); - return -ENODEV; - } - - regulators_np = of_get_child_by_name(pmic_np, "regulators"); - if (!regulators_np) { - dev_err(&pdev->dev, "could not find regulators sub-node\n"); - return -EINVAL; - } - - /* count the number of regulators to be supported in pmic */ - pdata->num_regulators = of_get_child_count(regulators_np); - - rdata = devm_kzalloc(&pdev->dev, sizeof(*rdata) * - pdata->num_regulators, GFP_KERNEL); - if (!rdata) { - of_node_put(regulators_np); - return -ENOMEM; - } - - pdata->regulators = rdata; - for_each_child_of_node(regulators_np, reg_np) { - for (i = 0; i < ARRAY_SIZE(regulators); i++) - if (!of_node_cmp(reg_np->name, regulators[i].name)) - break; - - if (i == ARRAY_SIZE(regulators)) { - dev_warn(&pdev->dev, "don't know how to configure regulator %s\n", - reg_np->name); - continue; - } - - rdata->id = i; - rdata->initdata = of_get_regulator_init_data(&pdev->dev, - reg_np, - ®ulators[i]); - rdata->reg_node = reg_np; - rdata++; - } - of_node_put(regulators_np); - - if (of_get_property(pmic_np, "max8997,pmic-buck1-uses-gpio-dvs", NULL)) - pdata->buck1_gpiodvs = true; - - if (of_get_property(pmic_np, "max8997,pmic-buck2-uses-gpio-dvs", NULL)) - pdata->buck2_gpiodvs = true; - - if (of_get_property(pmic_np, "max8997,pmic-buck5-uses-gpio-dvs", NULL)) - pdata->buck5_gpiodvs = true; - - if (pdata->buck1_gpiodvs || pdata->buck2_gpiodvs || - pdata->buck5_gpiodvs) { - ret = max8997_pmic_dt_parse_dvs_gpio(pdev, pdata, pmic_np); - if (ret) - return -EINVAL; - - if (of_property_read_u32(pmic_np, - "max8997,pmic-buck125-default-dvs-idx", - &pdata->buck125_default_idx)) { - pdata->buck125_default_idx = 0; - } else { - if (pdata->buck125_default_idx >= 8) { - pdata->buck125_default_idx = 0; - dev_info(&pdev->dev, "invalid value for default dvs index, using 0 instead\n"); - } - } - - if (of_get_property(pmic_np, - "max8997,pmic-ignore-gpiodvs-side-effect", NULL)) - pdata->ignore_gpiodvs_side_effect = true; - - dvs_voltage_nr = 8; - } - - if (of_property_read_u32_array(pmic_np, - "max8997,pmic-buck1-dvs-voltage", - pdata->buck1_voltage, dvs_voltage_nr)) { - dev_err(&pdev->dev, "buck1 voltages not specified\n"); - return -EINVAL; - } - - if (of_property_read_u32_array(pmic_np, - "max8997,pmic-buck2-dvs-voltage", - pdata->buck2_voltage, dvs_voltage_nr)) { - dev_err(&pdev->dev, "buck2 voltages not specified\n"); - return -EINVAL; - } - - if (of_property_read_u32_array(pmic_np, - "max8997,pmic-buck5-dvs-voltage", - pdata->buck5_voltage, dvs_voltage_nr)) { - dev_err(&pdev->dev, "buck5 voltages not specified\n"); - return -EINVAL; - } - - return 0; -} -#else -static int max8997_pmic_dt_parse_pdata(struct platform_device *pdev, - struct max8997_platform_data *pdata) -{ - return 0; -} -#endif /* CONFIG_OF */ - -static int max8997_pmic_probe(struct platform_device *pdev) -{ - struct max8997_dev *iodev = dev_get_drvdata(pdev->dev.parent); - struct max8997_platform_data *pdata = iodev->pdata; - struct regulator_config config = { }; - struct regulator_dev *rdev; - struct max8997_data *max8997; - struct i2c_client *i2c; - int i, ret, nr_dvs; - u8 max_buck1 = 0, max_buck2 = 0, max_buck5 = 0; - - if (!pdata) { - dev_err(&pdev->dev, "No platform init data supplied.\n"); - return -ENODEV; - } - - if (iodev->dev->of_node) { - ret = max8997_pmic_dt_parse_pdata(pdev, pdata); - if (ret) - return ret; - } - - max8997 = devm_kzalloc(&pdev->dev, sizeof(struct max8997_data), - GFP_KERNEL); - if (!max8997) - return -ENOMEM; - - max8997->dev = &pdev->dev; - max8997->iodev = iodev; - max8997->num_regulators = pdata->num_regulators; - platform_set_drvdata(pdev, max8997); - i2c = max8997->iodev->i2c; - - max8997->buck125_gpioindex = pdata->buck125_default_idx; - max8997->buck1_gpiodvs = pdata->buck1_gpiodvs; - max8997->buck2_gpiodvs = pdata->buck2_gpiodvs; - max8997->buck5_gpiodvs = pdata->buck5_gpiodvs; - memcpy(max8997->buck125_gpios, pdata->buck125_gpios, sizeof(int) * 3); - max8997->ignore_gpiodvs_side_effect = pdata->ignore_gpiodvs_side_effect; - - nr_dvs = (pdata->buck1_gpiodvs || pdata->buck2_gpiodvs || - pdata->buck5_gpiodvs) ? 8 : 1; - - for (i = 0; i < nr_dvs; i++) { - max8997->buck1_vol[i] = ret = - max8997_get_voltage_proper_val( - &buck1245_voltage_map_desc, - pdata->buck1_voltage[i], - pdata->buck1_voltage[i] + - buck1245_voltage_map_desc.step); - if (ret < 0) - return ret; - - max8997->buck2_vol[i] = ret = - max8997_get_voltage_proper_val( - &buck1245_voltage_map_desc, - pdata->buck2_voltage[i], - pdata->buck2_voltage[i] + - buck1245_voltage_map_desc.step); - if (ret < 0) - return ret; - - max8997->buck5_vol[i] = ret = - max8997_get_voltage_proper_val( - &buck1245_voltage_map_desc, - pdata->buck5_voltage[i], - pdata->buck5_voltage[i] + - buck1245_voltage_map_desc.step); - if (ret < 0) - return ret; - - if (max_buck1 < max8997->buck1_vol[i]) - max_buck1 = max8997->buck1_vol[i]; - if (max_buck2 < max8997->buck2_vol[i]) - max_buck2 = max8997->buck2_vol[i]; - if (max_buck5 < max8997->buck5_vol[i]) - max_buck5 = max8997->buck5_vol[i]; - } - - /* For the safety, set max voltage before setting up */ - for (i = 0; i < 8; i++) { - max8997_update_reg(i2c, MAX8997_REG_BUCK1DVS1 + i, - max_buck1, 0x3f); - max8997_update_reg(i2c, MAX8997_REG_BUCK2DVS1 + i, - max_buck2, 0x3f); - max8997_update_reg(i2c, MAX8997_REG_BUCK5DVS1 + i, - max_buck5, 0x3f); - } - - /* Initialize all the DVS related BUCK registers */ - for (i = 0; i < nr_dvs; i++) { - max8997_update_reg(i2c, MAX8997_REG_BUCK1DVS1 + i, - max8997->buck1_vol[i], - 0x3f); - max8997_update_reg(i2c, MAX8997_REG_BUCK2DVS1 + i, - max8997->buck2_vol[i], - 0x3f); - max8997_update_reg(i2c, MAX8997_REG_BUCK5DVS1 + i, - max8997->buck5_vol[i], - 0x3f); - } - - /* - * If buck 1, 2, and 5 do not care DVS GPIO settings, ignore them. - * If at least one of them cares, set gpios. - */ - if (pdata->buck1_gpiodvs || pdata->buck2_gpiodvs || - pdata->buck5_gpiodvs) { - - if (!gpio_is_valid(pdata->buck125_gpios[0]) || - !gpio_is_valid(pdata->buck125_gpios[1]) || - !gpio_is_valid(pdata->buck125_gpios[2])) { - dev_err(&pdev->dev, "GPIO NOT VALID\n"); - return -EINVAL; - } - - ret = devm_gpio_request(&pdev->dev, pdata->buck125_gpios[0], - "MAX8997 SET1"); - if (ret) - return ret; - - ret = devm_gpio_request(&pdev->dev, pdata->buck125_gpios[1], - "MAX8997 SET2"); - if (ret) - return ret; - - ret = devm_gpio_request(&pdev->dev, pdata->buck125_gpios[2], - "MAX8997 SET3"); - if (ret) - return ret; - - gpio_direction_output(pdata->buck125_gpios[0], - (max8997->buck125_gpioindex >> 2) - & 0x1); /* SET1 */ - gpio_direction_output(pdata->buck125_gpios[1], - (max8997->buck125_gpioindex >> 1) - & 0x1); /* SET2 */ - gpio_direction_output(pdata->buck125_gpios[2], - (max8997->buck125_gpioindex >> 0) - & 0x1); /* SET3 */ - } - - /* DVS-GPIO disabled */ - max8997_update_reg(i2c, MAX8997_REG_BUCK1CTRL, (pdata->buck1_gpiodvs) ? - (1 << 1) : (0 << 1), 1 << 1); - max8997_update_reg(i2c, MAX8997_REG_BUCK2CTRL, (pdata->buck2_gpiodvs) ? - (1 << 1) : (0 << 1), 1 << 1); - max8997_update_reg(i2c, MAX8997_REG_BUCK5CTRL, (pdata->buck5_gpiodvs) ? - (1 << 1) : (0 << 1), 1 << 1); - - /* Misc Settings */ - max8997->ramp_delay = 10; /* set 10mV/us, which is the default */ - max8997_write_reg(i2c, MAX8997_REG_BUCKRAMP, (0xf << 4) | 0x9); - - for (i = 0; i < pdata->num_regulators; i++) { - const struct voltage_map_desc *desc; - int id = pdata->regulators[i].id; - - desc = reg_voltage_map[id]; - if (desc) { - regulators[id].n_voltages = - (desc->max - desc->min) / desc->step + 1; - } else if (id == MAX8997_ESAFEOUT1 || id == MAX8997_ESAFEOUT2) { - regulators[id].volt_table = safeoutvolt; - regulators[id].n_voltages = ARRAY_SIZE(safeoutvolt); - } else if (id == MAX8997_CHARGER_CV) { - regulators[id].n_voltages = 16; - } - - config.dev = max8997->dev; - config.init_data = pdata->regulators[i].initdata; - config.driver_data = max8997; - config.of_node = pdata->regulators[i].reg_node; - - rdev = devm_regulator_register(&pdev->dev, ®ulators[id], - &config); - if (IS_ERR(rdev)) { - dev_err(max8997->dev, "regulator init failed for %d\n", - id); - return PTR_ERR(rdev); - } - } - - return 0; -} - -static const struct platform_device_id max8997_pmic_id[] = { - { "max8997-pmic", 0}, - { }, -}; -MODULE_DEVICE_TABLE(platform, max8997_pmic_id); - -static struct platform_driver max8997_pmic_driver = { - .driver = { - .name = "max8997-pmic", - }, - .probe = max8997_pmic_probe, - .id_table = max8997_pmic_id, -}; - -static int __init max8997_pmic_init(void) -{ - return platform_driver_register(&max8997_pmic_driver); -} -subsys_initcall(max8997_pmic_init); - -static void __exit max8997_pmic_cleanup(void) -{ - platform_driver_unregister(&max8997_pmic_driver); -} -module_exit(max8997_pmic_cleanup); - -MODULE_DESCRIPTION("MAXIM 8997/8966 Regulator Driver"); -MODULE_AUTHOR("MyungJoo Ham "); -MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 724fef53449d22ed41c99164aff7d7c3654603e2 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 5 Apr 2016 11:05:15 +0900 Subject: regulator: max8997/max77802: Fix misspelled Samsung address Correct smasung.com into samsung.com. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Javier Martinez Canillas Signed-off-by: Mark Brown --- drivers/regulator/max77802-regulator.c | 2 +- drivers/regulator/max8997-regulator.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/max77802-regulator.c b/drivers/regulator/max77802-regulator.c index c07ee13bd470..1d3539324d9a 100644 --- a/drivers/regulator/max77802-regulator.c +++ b/drivers/regulator/max77802-regulator.c @@ -5,7 +5,7 @@ * Simon Glass * * Copyright (C) 2012 Samsung Electronics - * Chiwoong Byun + * Chiwoong Byun * Jonghwa Lee * * This program is free software; you can redistribute it and/or modify diff --git a/drivers/regulator/max8997-regulator.c b/drivers/regulator/max8997-regulator.c index ea0196d4496b..efabc0ea0e96 100644 --- a/drivers/regulator/max8997-regulator.c +++ b/drivers/regulator/max8997-regulator.c @@ -2,7 +2,7 @@ * max8997.c - Regulator driver for the Maxim 8997/8966 * * Copyright (C) 2011 Samsung Electronics - * MyungJoo Ham + * MyungJoo Ham * * 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 -- cgit v1.2.3 From 314a8203b6de2df164399996ece1412ae8f6270d Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Wed, 6 Apr 2016 09:49:47 -0400 Subject: regulator: max77686: Use module_platform_driver() instead subsys initcall The driver's init and exit function don't do anything besides registering and unregistering the platform driver, so the module_platform_driver() macro could just be used instead of having separate functions. Currently the macro is not being used because the driver is initialized at subsys init call level but this isn't necessary since consumer devices are defined in the DT as dependencies so there's no need for init calls order. Signed-off-by: Javier Martinez Canillas Signed-off-by: Mark Brown --- drivers/regulator/max77686-regulator.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/max77686-regulator.c b/drivers/regulator/max77686-regulator.c index 17ccf365a9c0..d1ab6a4da88f 100644 --- a/drivers/regulator/max77686-regulator.c +++ b/drivers/regulator/max77686-regulator.c @@ -553,17 +553,7 @@ static struct platform_driver max77686_pmic_driver = { .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_platform_driver(max77686_pmic_driver); MODULE_DESCRIPTION("MAXIM 77686 Regulator Driver"); MODULE_AUTHOR("Chiwoong Byun "); -- cgit v1.2.3 From d2d5437bdfdde20a75bdf59db1c1a77721613b22 Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Wed, 13 Apr 2016 15:29:45 +0530 Subject: regulator: max8973: add support for junction thermal warning The driver MAX8973 supports the driver for Maxim PMIC MAX77621. MAX77621 supports the junction temp warning at 120 degC and 140 degC which is configurable. It generates alert signal when junction temperature crosses these threshold. MAX77621 does not support the continuous temp monitoring of junction temperature. It just report whether junction temperature crossed the threshold or not. Add support to - Configure junction temp warning threshold via DT property to generate alert when it crosses the threshold. - Add support to interrupt the host from this device when alert occurred. - read the junction temp via thermal framework. Signed-off-by: Laxman Dewangan Signed-off-by: Mark Brown --- drivers/regulator/Kconfig | 1 + drivers/regulator/max8973-regulator.c | 97 +++++++++++++++++++++++++++++ include/linux/regulator/max8973-regulator.h | 5 ++ 3 files changed, 103 insertions(+) (limited to 'drivers/regulator') diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index c77dc08b1202..129359f775d0 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -409,6 +409,7 @@ config REGULATOR_MAX8952 config REGULATOR_MAX8973 tristate "Maxim MAX8973 voltage regulator " depends on I2C + depends on THERMAL && THERMAL_OF select REGMAP_I2C help The MAXIM MAX8973 high-efficiency. three phase, DC-DC step-down diff --git a/drivers/regulator/max8973-regulator.c b/drivers/regulator/max8973-regulator.c index 5b75b7c2e3ea..08d2f13eca00 100644 --- a/drivers/regulator/max8973-regulator.c +++ b/drivers/regulator/max8973-regulator.c @@ -38,6 +38,9 @@ #include #include #include +#include +#include +#include /* Register definitions */ #define MAX8973_VOUT 0x0 @@ -74,6 +77,7 @@ #define MAX8973_WDTMR_ENABLE BIT(6) #define MAX8973_DISCH_ENBABLE BIT(5) #define MAX8973_FT_ENABLE BIT(4) +#define MAX77621_T_JUNCTION_120 BIT(7) #define MAX8973_CKKADV_TRIP_MASK 0xC #define MAX8973_CKKADV_TRIP_DISABLE 0xC @@ -93,6 +97,12 @@ #define MAX8973_VOLATGE_STEP 6250 #define MAX8973_BUCK_N_VOLTAGE 0x80 +#define MAX77621_CHIPID_TJINT_S BIT(0) + +#define MAX77621_NORMAL_OPERATING_TEMP 100000 +#define MAX77621_TJINT_WARNING_TEMP_120 120000 +#define MAX77621_TJINT_WARNING_TEMP_140 140000 + enum device_id { MAX8973, MAX77621 @@ -112,6 +122,9 @@ struct max8973_chip { int curr_gpio_val; struct regulator_ops ops; enum device_id id; + int junction_temp_warning; + int irq; + struct thermal_zone_device *tz_device; }; /* @@ -391,6 +404,10 @@ static int max8973_init_dcdc(struct max8973_chip *max, if (pdata->control_flags & MAX8973_CONTROL_FREQ_SHIFT_9PER_ENABLE) control1 |= MAX8973_FREQSHIFT_9PER; + if ((pdata->junction_temp_warning == MAX77621_TJINT_WARNING_TEMP_120) && + (max->id == MAX77621)) + control2 |= MAX77621_T_JUNCTION_120; + if (!(pdata->control_flags & MAX8973_CONTROL_PULL_DOWN_ENABLE)) control2 |= MAX8973_DISCH_ENBABLE; @@ -457,6 +474,79 @@ static int max8973_init_dcdc(struct max8973_chip *max, return ret; } +static int max8973_thermal_read_temp(void *data, int *temp) +{ + struct max8973_chip *mchip = data; + unsigned int val; + int ret; + + ret = regmap_read(mchip->regmap, MAX8973_CHIPID1, &val); + if (ret < 0) { + dev_err(mchip->dev, "Failed to read register CHIPID1, %d", ret); + return ret; + } + + /* +1 degC to trigger cool devive */ + if (val & MAX77621_CHIPID_TJINT_S) + *temp = mchip->junction_temp_warning + 1000; + else + *temp = MAX77621_NORMAL_OPERATING_TEMP; + + return 0; +} + +static irqreturn_t max8973_thermal_irq(int irq, void *data) +{ + struct max8973_chip *mchip = data; + + thermal_zone_device_update(mchip->tz_device); + + return IRQ_HANDLED; +} + +static const struct thermal_zone_of_device_ops max77621_tz_ops = { + .get_temp = max8973_thermal_read_temp, +}; + +static int max8973_thermal_init(struct max8973_chip *mchip) +{ + struct thermal_zone_device *tzd; + struct irq_data *irq_data; + unsigned long irq_flags = 0; + int ret; + + if (mchip->id != MAX77621) + return 0; + + tzd = devm_thermal_zone_of_sensor_register(mchip->dev, 0, mchip, + &max77621_tz_ops); + if (IS_ERR(tzd)) { + ret = PTR_ERR(tzd); + dev_err(mchip->dev, "Failed to register thermal sensor: %d\n", + ret); + return ret; + } + + if (mchip->irq <= 0) + return 0; + + irq_data = irq_get_irq_data(mchip->irq); + if (irq_data) + irq_flags = irqd_get_trigger_type(irq_data); + + ret = devm_request_threaded_irq(mchip->dev, mchip->irq, NULL, + max8973_thermal_irq, + IRQF_ONESHOT | IRQF_SHARED | irq_flags, + dev_name(mchip->dev), mchip); + if (ret < 0) { + dev_err(mchip->dev, "Failed to request irq %d, %d\n", + mchip->irq, ret); + return ret; + } + + return 0; +} + static const struct regmap_config max8973_regmap_config = { .reg_bits = 8, .val_bits = 8, @@ -521,6 +611,11 @@ static struct max8973_regulator_platform_data *max8973_parse_dt( pdata->control_flags |= MAX8973_CONTROL_CLKADV_TRIP_DISABLED; } + pdata->junction_temp_warning = MAX77621_TJINT_WARNING_TEMP_140; + ret = of_property_read_u32(np, "junction-warn-millicelsius", &pval); + if (!ret && (pval <= MAX77621_TJINT_WARNING_TEMP_120)) + pdata->junction_temp_warning = MAX77621_TJINT_WARNING_TEMP_120; + return pdata; } @@ -608,6 +703,7 @@ static int max8973_probe(struct i2c_client *client, max->enable_external_control = pdata->enable_ext_control; max->curr_gpio_val = pdata->dvs_def_state; max->curr_vout_reg = MAX8973_VOUT + pdata->dvs_def_state; + max->junction_temp_warning = pdata->junction_temp_warning; if (gpio_is_valid(max->enable_gpio)) max->enable_external_control = true; @@ -718,6 +814,7 @@ static int max8973_probe(struct i2c_client *client, return ret; } + max8973_thermal_init(max); return 0; } diff --git a/include/linux/regulator/max8973-regulator.h b/include/linux/regulator/max8973-regulator.h index f6a8a16a0d4d..2fcb9980262a 100644 --- a/include/linux/regulator/max8973-regulator.h +++ b/include/linux/regulator/max8973-regulator.h @@ -54,6 +54,10 @@ * @reg_init_data: The regulator init data. * @control_flags: Control flags which are ORed value of above flags to * configure device. + * @junction_temp_warning: Junction temp in millicelcius on which warning need + * to be set. Thermal functionality is only supported on + * MAX77621. The threshold warning supported by MAX77621 + * are 120C and 140C. * @enable_ext_control: Enable the voltage enable/disable through external * control signal from EN input pin. If it is false then * voltage output will be enabled/disabled through EN bit of @@ -67,6 +71,7 @@ struct max8973_regulator_platform_data { struct regulator_init_data *reg_init_data; unsigned long control_flags; + unsigned long junction_temp_warning; bool enable_ext_control; int enable_gpio; int dvs_gpio; -- cgit v1.2.3 From 99cf3af5e2d5c74e016ae9517a4dced3f1dbcf6a Mon Sep 17 00:00:00 2001 From: James Ban Date: Fri, 15 Apr 2016 13:34:22 +0900 Subject: regulator: pv88080: new regulator driver This is the driver for the Powerventure PV88080 BUCKs regulator. It communicates via an I2C bus to the device. Signed-off-by: James Ban Signed-off-by: Mark Brown --- .../devicetree/bindings/regulator/pv88080.txt | 49 +++ drivers/regulator/Kconfig | 7 + drivers/regulator/Makefile | 1 + drivers/regulator/pv88080-regulator.c | 419 +++++++++++++++++++++ drivers/regulator/pv88080-regulator.h | 92 +++++ 5 files changed, 568 insertions(+) create mode 100644 Documentation/devicetree/bindings/regulator/pv88080.txt create mode 100644 drivers/regulator/pv88080-regulator.c create mode 100644 drivers/regulator/pv88080-regulator.h (limited to 'drivers/regulator') diff --git a/Documentation/devicetree/bindings/regulator/pv88080.txt b/Documentation/devicetree/bindings/regulator/pv88080.txt new file mode 100644 index 000000000000..38a614210dcb --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/pv88080.txt @@ -0,0 +1,49 @@ +* Powerventure Semiconductor PV88080 Voltage Regulator + +Required properties: +- compatible: "pvs,pv88080". +- reg: I2C slave address, usually 0x49. +- interrupts: the interrupt outputs of the controller +- regulators: A node that houses a sub-node for each regulator within the + device. Each sub-node is identified using the node's name, with valid + values listed below. The content of each sub-node is defined by the + standard binding for regulators; see regulator.txt. + BUCK1, BUCK2, and BUCK3. + +Optional properties: +- Any optional property defined in regulator.txt + +Example + + pmic: pv88080@49 { + compatible = "pvs,pv88080"; + reg = <0x49>; + interrupt-parent = <&gpio>; + interrupts = <24 24>; + + regulators { + BUCK1 { + regulator-name = "buck1"; + regulator-min-microvolt = < 600000>; + regulator-max-microvolt = <1393750>; + regulator-min-microamp = < 220000>; + regulator-max-microamp = <7040000>; + }; + + BUCK2 { + regulator-name = "buck2"; + regulator-min-microvolt = < 600000>; + regulator-max-microvolt = <1393750>; + regulator-min-microamp = <1496000>; + regulator-max-microamp = <4189000>; + }; + + BUCK3 { + regulator-name = "buck3"; + regulator-min-microvolt = <1400000>; + regulator-max-microvolt = <2193750>; + regulator-min-microamp = <1496000>; + regulator-max-microamp = <4189000>; + }; + }; + }; diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index c77dc08b1202..0b616e2192cc 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -548,6 +548,13 @@ config REGULATOR_PV88060 Say y here to support the voltage regulators and convertors PV88060 +config REGULATOR_PV88080 + tristate "Powerventure Semiconductor PV88080 regulator" + depends on I2C + select REGMAP_I2C + help + Say y here to support the buck convertors on PV88080 + config REGULATOR_PV88090 tristate "Powerventure Semiconductor PV88090 regulator" depends on I2C diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index 61bfbb9d4a0c..2f6f9f862aea 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -71,6 +71,7 @@ obj-$(CONFIG_REGULATOR_QCOM_SPMI) += qcom_spmi-regulator.o obj-$(CONFIG_REGULATOR_PALMAS) += palmas-regulator.o obj-$(CONFIG_REGULATOR_PFUZE100) += pfuze100-regulator.o obj-$(CONFIG_REGULATOR_PV88060) += pv88060-regulator.o +obj-$(CONFIG_REGULATOR_PV88080) += pv88080-regulator.o obj-$(CONFIG_REGULATOR_PV88090) += pv88090-regulator.o obj-$(CONFIG_REGULATOR_PWM) += pwm-regulator.o obj-$(CONFIG_REGULATOR_TPS51632) += tps51632-regulator.o diff --git a/drivers/regulator/pv88080-regulator.c b/drivers/regulator/pv88080-regulator.c new file mode 100644 index 000000000000..d7107566c429 --- /dev/null +++ b/drivers/regulator/pv88080-regulator.c @@ -0,0 +1,419 @@ +/* + * pv88080-regulator.c - Regulator device driver for PV88080 + * Copyright (C) 2016 Powerventure Semiconductor Ltd. + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "pv88080-regulator.h" + +#define PV88080_MAX_REGULATORS 3 + +/* PV88080 REGULATOR IDs */ +enum { + /* BUCKs */ + PV88080_ID_BUCK1, + PV88080_ID_BUCK2, + PV88080_ID_BUCK3, +}; + +struct pv88080_regulator { + struct regulator_desc desc; + /* Current limiting */ + unsigned int n_current_limits; + const int *current_limits; + unsigned int limit_mask; + unsigned int conf; + unsigned int conf2; + unsigned int conf5; +}; + +struct pv88080 { + struct device *dev; + struct regmap *regmap; + struct regulator_dev *rdev[PV88080_MAX_REGULATORS]; +}; + +struct pv88080_buck_voltage { + int min_uV; + int max_uV; + int uV_step; +}; + +static const struct regmap_config pv88080_regmap_config = { + .reg_bits = 8, + .val_bits = 8, +}; + +/* Current limits array (in uA) for BUCK1, BUCK2, BUCK3. + * Entry indexes corresponds to register values. + */ + +static const int pv88080_buck1_limits[] = { + 3230000, 5130000, 6960000, 8790000 +}; + +static const int pv88080_buck23_limits[] = { + 1496000, 2393000, 3291000, 4189000 +}; + +static const struct pv88080_buck_voltage pv88080_buck_vol[2] = { + { + .min_uV = 600000, + .max_uV = 1393750, + .uV_step = 6250, + }, + { + .min_uV = 1400000, + .max_uV = 2193750, + .uV_step = 6250, + }, +}; + +static unsigned int pv88080_buck_get_mode(struct regulator_dev *rdev) +{ + struct pv88080_regulator *info = rdev_get_drvdata(rdev); + unsigned int data; + int ret, mode = 0; + + ret = regmap_read(rdev->regmap, info->conf, &data); + if (ret < 0) + return ret; + + switch (data & PV88080_BUCK1_MODE_MASK) { + case PV88080_BUCK_MODE_SYNC: + mode = REGULATOR_MODE_FAST; + break; + case PV88080_BUCK_MODE_AUTO: + mode = REGULATOR_MODE_NORMAL; + break; + case PV88080_BUCK_MODE_SLEEP: + mode = REGULATOR_MODE_STANDBY; + break; + default: + return -EINVAL; + } + + return mode; +} + +static int pv88080_buck_set_mode(struct regulator_dev *rdev, + unsigned int mode) +{ + struct pv88080_regulator *info = rdev_get_drvdata(rdev); + int val = 0; + + switch (mode) { + case REGULATOR_MODE_FAST: + val = PV88080_BUCK_MODE_SYNC; + break; + case REGULATOR_MODE_NORMAL: + val = PV88080_BUCK_MODE_AUTO; + break; + case REGULATOR_MODE_STANDBY: + val = PV88080_BUCK_MODE_SLEEP; + break; + default: + return -EINVAL; + } + + return regmap_update_bits(rdev->regmap, info->conf, + PV88080_BUCK1_MODE_MASK, val); +} + +static int pv88080_set_current_limit(struct regulator_dev *rdev, int min, + int max) +{ + struct pv88080_regulator *info = rdev_get_drvdata(rdev); + int i; + + /* search for closest to maximum */ + for (i = info->n_current_limits; i >= 0; i--) { + if (min <= info->current_limits[i] + && max >= info->current_limits[i]) { + return regmap_update_bits(rdev->regmap, + info->conf, + info->limit_mask, + i << PV88080_BUCK1_ILIM_SHIFT); + } + } + + return -EINVAL; +} + +static int pv88080_get_current_limit(struct regulator_dev *rdev) +{ + struct pv88080_regulator *info = rdev_get_drvdata(rdev); + unsigned int data; + int ret; + + ret = regmap_read(rdev->regmap, info->conf, &data); + if (ret < 0) + return ret; + + data = (data & info->limit_mask) >> PV88080_BUCK1_ILIM_SHIFT; + return info->current_limits[data]; +} + +static struct regulator_ops pv88080_buck_ops = { + .get_mode = pv88080_buck_get_mode, + .set_mode = pv88080_buck_set_mode, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .list_voltage = regulator_list_voltage_linear, + .set_current_limit = pv88080_set_current_limit, + .get_current_limit = pv88080_get_current_limit, +}; + +#define PV88080_BUCK(chip, regl_name, min, step, max, limits_array) \ +{\ + .desc = {\ + .id = chip##_ID_##regl_name,\ + .name = __stringify(chip##_##regl_name),\ + .of_match = of_match_ptr(#regl_name),\ + .regulators_node = of_match_ptr("regulators"),\ + .type = REGULATOR_VOLTAGE,\ + .owner = THIS_MODULE,\ + .ops = &pv88080_buck_ops,\ + .min_uV = min, \ + .uV_step = step, \ + .n_voltages = ((max) - (min))/(step) + 1, \ + .enable_reg = PV88080_REG_##regl_name##_CONF0, \ + .enable_mask = PV88080_##regl_name##_EN, \ + .vsel_reg = PV88080_REG_##regl_name##_CONF0, \ + .vsel_mask = PV88080_V##regl_name##_MASK, \ + },\ + .current_limits = limits_array, \ + .n_current_limits = ARRAY_SIZE(limits_array), \ + .limit_mask = PV88080_##regl_name##_ILIM_MASK, \ + .conf = PV88080_REG_##regl_name##_CONF1, \ + .conf2 = PV88080_REG_##regl_name##_CONF2, \ + .conf5 = PV88080_REG_##regl_name##_CONF5, \ +} + +static struct pv88080_regulator pv88080_regulator_info[] = { + PV88080_BUCK(PV88080, BUCK1, 600000, 6250, 1393750, + pv88080_buck1_limits), + PV88080_BUCK(PV88080, BUCK2, 600000, 6250, 1393750, + pv88080_buck23_limits), + PV88080_BUCK(PV88080, BUCK3, 600000, 6250, 1393750, + pv88080_buck23_limits), +}; + +static irqreturn_t pv88080_irq_handler(int irq, void *data) +{ + struct pv88080 *chip = data; + int i, reg_val, err, ret = IRQ_NONE; + + err = regmap_read(chip->regmap, PV88080_REG_EVENT_A, ®_val); + if (err < 0) + goto error_i2c; + + if (reg_val & PV88080_E_VDD_FLT) { + for (i = 0; i < PV88080_MAX_REGULATORS; i++) { + if (chip->rdev[i] != NULL) { + regulator_notifier_call_chain(chip->rdev[i], + REGULATOR_EVENT_UNDER_VOLTAGE, + NULL); + } + } + + err = regmap_write(chip->regmap, PV88080_REG_EVENT_A, + PV88080_E_VDD_FLT); + if (err < 0) + goto error_i2c; + + ret = IRQ_HANDLED; + } + + if (reg_val & PV88080_E_OVER_TEMP) { + for (i = 0; i < PV88080_MAX_REGULATORS; i++) { + if (chip->rdev[i] != NULL) { + regulator_notifier_call_chain(chip->rdev[i], + REGULATOR_EVENT_OVER_TEMP, + NULL); + } + } + + err = regmap_write(chip->regmap, PV88080_REG_EVENT_A, + PV88080_E_OVER_TEMP); + if (err < 0) + goto error_i2c; + + ret = IRQ_HANDLED; + } + + return ret; + +error_i2c: + dev_err(chip->dev, "I2C error : %d\n", err); + return IRQ_NONE; +} + +/* + * I2C driver interface functions + */ +static int pv88080_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct regulator_init_data *init_data = dev_get_platdata(&i2c->dev); + struct pv88080 *chip; + struct regulator_config config = { }; + int i, error, ret; + unsigned int conf2, conf5; + + chip = devm_kzalloc(&i2c->dev, sizeof(struct pv88080), GFP_KERNEL); + if (!chip) + return -ENOMEM; + + chip->dev = &i2c->dev; + chip->regmap = devm_regmap_init_i2c(i2c, &pv88080_regmap_config); + if (IS_ERR(chip->regmap)) { + error = PTR_ERR(chip->regmap); + dev_err(chip->dev, "Failed to allocate register map: %d\n", + error); + return error; + } + + i2c_set_clientdata(i2c, chip); + + if (i2c->irq != 0) { + ret = regmap_write(chip->regmap, PV88080_REG_MASK_A, 0xFF); + if (ret < 0) { + dev_err(chip->dev, + "Failed to mask A reg: %d\n", ret); + return ret; + } + ret = regmap_write(chip->regmap, PV88080_REG_MASK_B, 0xFF); + if (ret < 0) { + dev_err(chip->dev, + "Failed to mask B reg: %d\n", ret); + return ret; + } + ret = regmap_write(chip->regmap, PV88080_REG_MASK_C, 0xFF); + if (ret < 0) { + dev_err(chip->dev, + "Failed to mask C reg: %d\n", ret); + return ret; + } + + ret = devm_request_threaded_irq(&i2c->dev, i2c->irq, NULL, + pv88080_irq_handler, + IRQF_TRIGGER_LOW|IRQF_ONESHOT, + "pv88080", chip); + if (ret != 0) { + dev_err(chip->dev, "Failed to request IRQ: %d\n", + i2c->irq); + return ret; + } + + ret = regmap_update_bits(chip->regmap, PV88080_REG_MASK_A, + PV88080_M_VDD_FLT | PV88080_M_OVER_TEMP, 0); + if (ret < 0) { + dev_err(chip->dev, + "Failed to update mask reg: %d\n", ret); + return ret; + } + + } else { + dev_warn(chip->dev, "No IRQ configured\n"); + } + + config.dev = chip->dev; + config.regmap = chip->regmap; + + for (i = 0; i < PV88080_MAX_REGULATORS; i++) { + if (init_data) + config.init_data = &init_data[i]; + + ret = regmap_read(chip->regmap, + pv88080_regulator_info[i].conf2, &conf2); + if (ret < 0) + return ret; + + conf2 = ((conf2 >> PV88080_BUCK_VDAC_RANGE_SHIFT) & + PV88080_BUCK_VDAC_RANGE_MASK); + + ret = regmap_read(chip->regmap, + pv88080_regulator_info[i].conf5, &conf5); + if (ret < 0) + return ret; + + conf5 = ((conf5 >> PV88080_BUCK_VRANGE_GAIN_SHIFT) & + PV88080_BUCK_VRANGE_GAIN_MASK); + + pv88080_regulator_info[i].desc.min_uV = + pv88080_buck_vol[conf2].min_uV * (conf5+1); + pv88080_regulator_info[i].desc.uV_step = + pv88080_buck_vol[conf2].uV_step * (conf5+1); + pv88080_regulator_info[i].desc.n_voltages = + ((pv88080_buck_vol[conf2].max_uV * (conf5+1)) + - (pv88080_regulator_info[i].desc.min_uV)) + /(pv88080_regulator_info[i].desc.uV_step) + 1; + + config.driver_data = (void *)&pv88080_regulator_info[i]; + chip->rdev[i] = devm_regulator_register(chip->dev, + &pv88080_regulator_info[i].desc, &config); + if (IS_ERR(chip->rdev[i])) { + dev_err(chip->dev, + "Failed to register PV88080 regulator\n"); + return PTR_ERR(chip->rdev[i]); + } + } + + return 0; +} + +static const struct i2c_device_id pv88080_i2c_id[] = { + {"pv88080", 0}, + {}, +}; +MODULE_DEVICE_TABLE(i2c, pv88080_i2c_id); + +#ifdef CONFIG_OF +static const struct of_device_id pv88080_dt_ids[] = { + { .compatible = "pvs,pv88080", .data = &pv88080_i2c_id[0] }, + {}, +}; +MODULE_DEVICE_TABLE(of, pv88080_dt_ids); +#endif + +static struct i2c_driver pv88080_regulator_driver = { + .driver = { + .name = "pv88080", + .of_match_table = of_match_ptr(pv88080_dt_ids), + }, + .probe = pv88080_i2c_probe, + .id_table = pv88080_i2c_id, +}; + +module_i2c_driver(pv88080_regulator_driver); + +MODULE_AUTHOR("James Ban "); +MODULE_DESCRIPTION("Regulator device driver for Powerventure PV88080"); +MODULE_LICENSE("GPL"); diff --git a/drivers/regulator/pv88080-regulator.h b/drivers/regulator/pv88080-regulator.h new file mode 100644 index 000000000000..5e9afde606f4 --- /dev/null +++ b/drivers/regulator/pv88080-regulator.h @@ -0,0 +1,92 @@ +/* + * pv88080-regulator.h - Regulator definitions for PV88080 + * Copyright (C) 2016 Powerventure Semiconductor Ltd. + * + * 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. + */ + +#ifndef __PV88080_REGISTERS_H__ +#define __PV88080_REGISTERS_H__ + +/* System Control and Event Registers */ +#define PV88080_REG_EVENT_A 0x04 +#define PV88080_REG_MASK_A 0x09 +#define PV88080_REG_MASK_B 0x0a +#define PV88080_REG_MASK_C 0x0b + +/* Regulator Registers */ +#define PV88080_REG_BUCK1_CONF0 0x27 +#define PV88080_REG_BUCK1_CONF1 0x28 +#define PV88080_REG_BUCK1_CONF2 0x59 +#define PV88080_REG_BUCK1_CONF5 0x5c +#define PV88080_REG_BUCK2_CONF0 0x29 +#define PV88080_REG_BUCK2_CONF1 0x2a +#define PV88080_REG_BUCK2_CONF2 0x61 +#define PV88080_REG_BUCK2_CONF5 0x64 +#define PV88080_REG_BUCK3_CONF0 0x2b +#define PV88080_REG_BUCK3_CONF1 0x2c +#define PV88080_REG_BUCK3_CONF2 0x69 +#define PV88080_REG_BUCK3_CONF5 0x6c + +/* PV88080_REG_EVENT_A (addr=0x04) */ +#define PV88080_E_VDD_FLT 0x01 +#define PV88080_E_OVER_TEMP 0x02 + +/* PV88080_REG_MASK_A (addr=0x09) */ +#define PV88080_M_VDD_FLT 0x01 +#define PV88080_M_OVER_TEMP 0x02 + +/* PV88080_REG_BUCK1_CONF0 (addr=0x27) */ +#define PV88080_BUCK1_EN 0x80 +#define PV88080_VBUCK1_MASK 0x7F +/* PV88080_REG_BUCK2_CONF0 (addr=0x29) */ +#define PV88080_BUCK2_EN 0x80 +#define PV88080_VBUCK2_MASK 0x7F +/* PV88080_REG_BUCK3_CONF0 (addr=0x2b) */ +#define PV88080_BUCK3_EN 0x80 +#define PV88080_VBUCK3_MASK 0x7F + +/* PV88080_REG_BUCK1_CONF1 (addr=0x28) */ +#define PV88080_BUCK1_ILIM_SHIFT 2 +#define PV88080_BUCK1_ILIM_MASK 0x0C +#define PV88080_BUCK1_MODE_MASK 0x03 + +/* PV88080_REG_BUCK2_CONF1 (addr=0x2a) */ +#define PV88080_BUCK2_ILIM_SHIFT 2 +#define PV88080_BUCK2_ILIM_MASK 0x0C +#define PV88080_BUCK2_MODE_MASK 0x03 + +/* PV88080_REG_BUCK3_CONF1 (addr=0x2c) */ +#define PV88080_BUCK3_ILIM_SHIFT 2 +#define PV88080_BUCK3_ILIM_MASK 0x0C +#define PV88080_BUCK3_MODE_MASK 0x03 + +#define PV88080_BUCK_MODE_SLEEP 0x00 +#define PV88080_BUCK_MODE_AUTO 0x01 +#define PV88080_BUCK_MODE_SYNC 0x02 + +/* PV88080_REG_BUCK2_CONF2 (addr=0x61) */ +/* PV88080_REG_BUCK3_CONF2 (addr=0x69) */ +#define PV88080_BUCK_VDAC_RANGE_SHIFT 7 +#define PV88080_BUCK_VDAC_RANGE_MASK 0x01 + +#define PV88080_BUCK_VDAC_RANGE_1 0x00 +#define PV88080_BUCK_VDAC_RANGE_2 0x01 + +/* PV88080_REG_BUCK2_CONF5 (addr=0x64) */ +/* PV88080_REG_BUCK3_CONF5 (addr=0x6c) */ +#define PV88080_BUCK_VRANGE_GAIN_SHIFT 0 +#define PV88080_BUCK_VRANGE_GAIN_MASK 0x01 + +#define PV88080_BUCK_VRANGE_GAIN_1 0x00 +#define PV88080_BUCK_VRANGE_GAIN_2 0x01 + +#endif /* __PV88080_REGISTERS_H__ */ -- cgit v1.2.3 From e0341f1732237777d65bdda7184ea4b11fb31d53 Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Tue, 26 Apr 2016 11:36:42 -0500 Subject: regulator: tps65917/palmas: Add bypass "On" value When commit b554e1450658 ("regulator: tps65917/palmas: Add bypass ops for LDOs with bypass capability") introduced bypass capability to palmas regulator, it went with the assumption that regulator regmap helpers just check val against the bypass_mask. Unfortunately, this ignored the explicit "on" and "off" values when the register value is masked with bypass_mask in commit ca5d1b3524b4 ("regulator: helpers: Modify helpers enabling multi-bit control"). With the recent commit dd1a571daee7 ("regulator: helpers: Ensure bypass register field matches ON value"), this issue gets highlighted and fails tps65917/palmas based platforms which need regulators/ldos that have bypass capability. Introduce the bypass_on value appropriately for tps65917/palmas regulator. Fixes: b554e1450658 ("regulator: tps65917/palmas: Add bypass ops for LDOs with bypass capability") Cc: Keerthy Cc: Mark Brown Signed-off-by: Nishanth Menon Signed-off-by: Mark Brown --- drivers/regulator/palmas-regulator.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/regulator') diff --git a/drivers/regulator/palmas-regulator.c b/drivers/regulator/palmas-regulator.c index 6efc7ee8aea3..c83e06b2cedb 100644 --- a/drivers/regulator/palmas-regulator.c +++ b/drivers/regulator/palmas-regulator.c @@ -944,6 +944,8 @@ static int palmas_ldo_registration(struct palmas_pmic *pmic, if (id == PALMAS_REG_LDO9) { desc->ops = &palmas_ops_ldo9; desc->bypass_reg = desc->enable_reg; + desc->bypass_val_on = + PALMAS_LDO9_CTRL_LDO_BYPASS_EN; desc->bypass_mask = PALMAS_LDO9_CTRL_LDO_BYPASS_EN; } @@ -1055,6 +1057,8 @@ static int tps65917_ldo_registration(struct palmas_pmic *pmic, id == TPS65917_REG_LDO2) { desc->ops = &tps65917_ops_ldo_1_2; desc->bypass_reg = desc->enable_reg; + desc->bypass_val_on = + TPS65917_LDO1_CTRL_BYPASS_EN; desc->bypass_mask = TPS65917_LDO1_CTRL_BYPASS_EN; } @@ -1206,6 +1210,7 @@ static int palmas_smps_registration(struct palmas_pmic *pmic, desc->enable_mask = SMPS10_BOOST_EN; desc->bypass_reg = PALMAS_BASE_TO_REG(PALMAS_SMPS_BASE, PALMAS_SMPS10_CTRL); + desc->bypass_val_on = SMPS10_BYPASS_EN; desc->bypass_mask = SMPS10_BYPASS_EN; desc->min_uV = 3750000; desc->uV_step = 1250000; -- cgit v1.2.3 From a9597305d97f6cf7c9e89dc1461e834c446d91fd Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 29 Apr 2016 12:59:51 +0200 Subject: regulator: max77686: Configure enable time to properly handle regulator enable The enable time for buck regulators was not configured but actually is essential: consumers, like usb3503, doing hard reset (regulator off/on) should wait for the regulator to settle. Configure the enable time according to datasheet. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Mark Brown --- drivers/regulator/max77686-regulator.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/regulator') diff --git a/drivers/regulator/max77686-regulator.c b/drivers/regulator/max77686-regulator.c index d1ab6a4da88f..ac4fa581e0a5 100644 --- a/drivers/regulator/max77686-regulator.c +++ b/drivers/regulator/max77686-regulator.c @@ -41,6 +41,8 @@ #define MAX77686_LDO_LOW_UVSTEP 25000 #define MAX77686_BUCK_MINUV 750000 #define MAX77686_BUCK_UVSTEP 50000 +#define MAX77686_BUCK_ENABLE_TIME 40 /* us */ +#define MAX77686_DVS_ENABLE_TIME 22 /* us */ #define MAX77686_RAMP_DELAY 100000 /* uV/us */ #define MAX77686_DVS_RAMP_DELAY 27500 /* uV/us */ #define MAX77686_DVS_MINUV 600000 @@ -422,6 +424,7 @@ static struct regulator_ops max77686_buck_dvs_ops = { .min_uV = MAX77686_BUCK_MINUV, \ .uV_step = MAX77686_BUCK_UVSTEP, \ .ramp_delay = MAX77686_RAMP_DELAY, \ + .enable_time = MAX77686_BUCK_ENABLE_TIME, \ .n_voltages = MAX77686_VSEL_MASK + 1, \ .vsel_reg = MAX77686_REG_BUCK5OUT + (num - 5) * 2, \ .vsel_mask = MAX77686_VSEL_MASK, \ @@ -439,6 +442,7 @@ static struct regulator_ops max77686_buck_dvs_ops = { .min_uV = MAX77686_BUCK_MINUV, \ .uV_step = MAX77686_BUCK_UVSTEP, \ .ramp_delay = MAX77686_RAMP_DELAY, \ + .enable_time = MAX77686_BUCK_ENABLE_TIME, \ .n_voltages = MAX77686_VSEL_MASK + 1, \ .vsel_reg = MAX77686_REG_BUCK1OUT, \ .vsel_mask = MAX77686_VSEL_MASK, \ @@ -456,6 +460,7 @@ static struct regulator_ops max77686_buck_dvs_ops = { .min_uV = MAX77686_DVS_MINUV, \ .uV_step = MAX77686_DVS_UVSTEP, \ .ramp_delay = MAX77686_DVS_RAMP_DELAY, \ + .enable_time = MAX77686_DVS_ENABLE_TIME, \ .n_voltages = MAX77686_DVS_VSEL_MASK + 1, \ .vsel_reg = MAX77686_REG_BUCK2DVS1 + (num - 2) * 10, \ .vsel_mask = MAX77686_DVS_VSEL_MASK, \ -- cgit v1.2.3 From 036d193d3337365e0d69cff9bb2593bfc1210e7b Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Thu, 5 May 2016 19:29:49 -0500 Subject: regulator: tps65917/palmas: Simplify multiple dereference of ddata->palmas_matches[idx] Converting dt to platform data logic involves picking up information that is unique per regulator, however we can improve readability of the code by dereferencing ddata->palmas_matches[idx] once in the loop. While at it fix reuse of generic palmas_matches common variable while reporting error for a specific regulator (which may be from 65917/palmas list). Signed-off-by: Nishanth Menon Signed-off-by: Mark Brown --- drivers/regulator/palmas-regulator.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/palmas-regulator.c b/drivers/regulator/palmas-regulator.c index c83e06b2cedb..41b4e94a8d7d 100644 --- a/drivers/regulator/palmas-regulator.c +++ b/drivers/regulator/palmas-regulator.c @@ -1491,21 +1491,23 @@ static void palmas_dt_to_pdata(struct device *dev, } for (idx = 0; idx < ddata->max_reg; idx++) { - if (!ddata->palmas_matches[idx].init_data || - !ddata->palmas_matches[idx].of_node) + static struct of_regulator_match *match; + + match = &ddata->palmas_matches[idx]; + + if (!match->init_data || !match->of_node) continue; - pdata->reg_data[idx] = ddata->palmas_matches[idx].init_data; + pdata->reg_data[idx] = match->init_data; pdata->reg_init[idx] = devm_kzalloc(dev, sizeof(struct palmas_reg_init), GFP_KERNEL); pdata->reg_init[idx]->warm_reset = - of_property_read_bool(ddata->palmas_matches[idx].of_node, - "ti,warm-reset"); + of_property_read_bool(match->of_node, "ti,warm-reset"); - ret = of_property_read_u32(ddata->palmas_matches[idx].of_node, - "ti,roof-floor", &prop); + ret = of_property_read_u32(match->of_node, "ti,roof-floor", + &prop); /* EINVAL: Property not found */ if (ret != -EINVAL) { int econtrol; @@ -1527,27 +1529,26 @@ static void palmas_dt_to_pdata(struct device *dev, WARN_ON(1); dev_warn(dev, "%s: Invalid roof-floor option: %u\n", - palmas_matches[idx].name, prop); + match->name, prop); break; } } pdata->reg_init[idx]->roof_floor = econtrol; } - ret = of_property_read_u32(ddata->palmas_matches[idx].of_node, - "ti,mode-sleep", &prop); + ret = of_property_read_u32(match->of_node, "ti,mode-sleep", + &prop); if (!ret) pdata->reg_init[idx]->mode_sleep = prop; - ret = of_property_read_bool(ddata->palmas_matches[idx].of_node, - "ti,smps-range"); + ret = of_property_read_bool(match->of_node, "ti,smps-range"); if (ret) pdata->reg_init[idx]->vsel = PALMAS_SMPS12_VOLTAGE_RANGE; if (idx == PALMAS_REG_LDO8) pdata->enable_ldo8_tracking = of_property_read_bool( - ddata->palmas_matches[idx].of_node, + match->of_node, "ti,enable-ldo8-tracking"); } -- cgit v1.2.3 From 1b42443db670dde5e3cb4261f77b29010b163fc6 Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Thu, 5 May 2016 19:29:50 -0500 Subject: regulator: tps65917/palmas: Simplify multiple dereference of pdata->reg_init[idx] Converting dt to platform data logic involves picking up information that is unique per regulator, however we can improve readability of the code by allocating and referencing pdata->reg_init[idx] once in the loop. While at it, use sizeof(*pointer) when allocating pointer. This allows for structure name changes with minimal code change. Signed-off-by: Nishanth Menon Signed-off-by: Mark Brown --- drivers/regulator/palmas-regulator.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/palmas-regulator.c b/drivers/regulator/palmas-regulator.c index 41b4e94a8d7d..3b9206224cd1 100644 --- a/drivers/regulator/palmas-regulator.c +++ b/drivers/regulator/palmas-regulator.c @@ -1492,19 +1492,19 @@ static void palmas_dt_to_pdata(struct device *dev, for (idx = 0; idx < ddata->max_reg; idx++) { static struct of_regulator_match *match; + struct palmas_reg_init *rinit; match = &ddata->palmas_matches[idx]; if (!match->init_data || !match->of_node) continue; + rinit = devm_kzalloc(dev, sizeof(*rinit), GFP_KERNEL); pdata->reg_data[idx] = match->init_data; + pdata->reg_init[idx] = rinit; - pdata->reg_init[idx] = devm_kzalloc(dev, - sizeof(struct palmas_reg_init), GFP_KERNEL); - - pdata->reg_init[idx]->warm_reset = - of_property_read_bool(match->of_node, "ti,warm-reset"); + rinit->warm_reset = of_property_read_bool(match->of_node, + "ti,warm-reset"); ret = of_property_read_u32(match->of_node, "ti,roof-floor", &prop); @@ -1533,18 +1533,17 @@ static void palmas_dt_to_pdata(struct device *dev, break; } } - pdata->reg_init[idx]->roof_floor = econtrol; + rinit->roof_floor = econtrol; } ret = of_property_read_u32(match->of_node, "ti,mode-sleep", &prop); if (!ret) - pdata->reg_init[idx]->mode_sleep = prop; + rinit->mode_sleep = prop; ret = of_property_read_bool(match->of_node, "ti,smps-range"); if (ret) - pdata->reg_init[idx]->vsel = - PALMAS_SMPS12_VOLTAGE_RANGE; + rinit->vsel = PALMAS_SMPS12_VOLTAGE_RANGE; if (idx == PALMAS_REG_LDO8) pdata->enable_ldo8_tracking = of_property_read_bool( -- cgit v1.2.3 From 7f091e53c9efc52b2b3a03a8a1d479a47956fecd Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Thu, 5 May 2016 19:29:51 -0500 Subject: regulator: tps65917/palmas: Handle possible memory allocation failure Stop the palmas regulator driver from imagining that the allocations will always succeed. Since regulator dt nodes are optional in nature and can be described in downstream drivers via platform data, continue to maintain code flow as prior when of node is not found. Signed-off-by: Nishanth Menon Signed-off-by: Mark Brown --- drivers/regulator/palmas-regulator.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/palmas-regulator.c b/drivers/regulator/palmas-regulator.c index 3b9206224cd1..faa389be7ca3 100644 --- a/drivers/regulator/palmas-regulator.c +++ b/drivers/regulator/palmas-regulator.c @@ -1467,10 +1467,10 @@ static struct palmas_pmic_driver_data tps65917_ddata = { .ldo_register = tps65917_ldo_registration, }; -static void palmas_dt_to_pdata(struct device *dev, - struct device_node *node, - struct palmas_pmic_platform_data *pdata, - struct palmas_pmic_driver_data *ddata) +static int palmas_dt_to_pdata(struct device *dev, + struct device_node *node, + struct palmas_pmic_platform_data *pdata, + struct palmas_pmic_driver_data *ddata) { struct device_node *regulators; u32 prop; @@ -1479,7 +1479,7 @@ static void palmas_dt_to_pdata(struct device *dev, regulators = of_get_child_by_name(node, "regulators"); if (!regulators) { dev_info(dev, "regulator node not found\n"); - return; + return 0; } ret = of_regulator_match(dev, regulators, ddata->palmas_matches, @@ -1487,7 +1487,7 @@ static void palmas_dt_to_pdata(struct device *dev, of_node_put(regulators); if (ret < 0) { dev_err(dev, "Error parsing regulator init data: %d\n", ret); - return; + return 0; } for (idx = 0; idx < ddata->max_reg; idx++) { @@ -1500,6 +1500,9 @@ static void palmas_dt_to_pdata(struct device *dev, continue; rinit = devm_kzalloc(dev, sizeof(*rinit), GFP_KERNEL); + if (!rinit) + return -ENOMEM; + pdata->reg_data[idx] = match->init_data; pdata->reg_init[idx] = rinit; @@ -1552,6 +1555,8 @@ static void palmas_dt_to_pdata(struct device *dev, } pdata->ldo6_vibrator = of_property_read_bool(node, "ti,ldo6-vibrator"); + + return 0; } static const struct of_device_id of_palmas_match_tbl[] = { @@ -1633,7 +1638,9 @@ static int palmas_regulators_probe(struct platform_device *pdev) platform_set_drvdata(pdev, pmic); pmic->palmas->pmic_ddata = driver_data; - palmas_dt_to_pdata(&pdev->dev, node, pdata, driver_data); + ret = palmas_dt_to_pdata(&pdev->dev, node, pdata, driver_data); + if (ret) + return ret; ret = palmas_smps_read(palmas, PALMAS_SMPS_CTRL, ®); if (ret) -- cgit v1.2.3 From 6c7d614fa22d32d038b5a6e88d71acb2711e7035 Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Thu, 5 May 2016 19:29:52 -0500 Subject: regulator: tps65917/palmas: Simplify multiple dereference of match->of_node Just dereference match->of_node once instead of using match->of_node. Signed-off-by: Nishanth Menon Signed-off-by: Mark Brown --- drivers/regulator/palmas-regulator.c | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/palmas-regulator.c b/drivers/regulator/palmas-regulator.c index faa389be7ca3..f11d41dad9c1 100644 --- a/drivers/regulator/palmas-regulator.c +++ b/drivers/regulator/palmas-regulator.c @@ -1493,10 +1493,12 @@ static int palmas_dt_to_pdata(struct device *dev, for (idx = 0; idx < ddata->max_reg; idx++) { static struct of_regulator_match *match; struct palmas_reg_init *rinit; + struct device_node *np; match = &ddata->palmas_matches[idx]; + np = match->of_node; - if (!match->init_data || !match->of_node) + if (!match->init_data || !np) continue; rinit = devm_kzalloc(dev, sizeof(*rinit), GFP_KERNEL); @@ -1506,11 +1508,8 @@ static int palmas_dt_to_pdata(struct device *dev, pdata->reg_data[idx] = match->init_data; pdata->reg_init[idx] = rinit; - rinit->warm_reset = of_property_read_bool(match->of_node, - "ti,warm-reset"); - - ret = of_property_read_u32(match->of_node, "ti,roof-floor", - &prop); + rinit->warm_reset = of_property_read_bool(np, "ti,warm-reset"); + ret = of_property_read_u32(np, "ti,roof-floor", &prop); /* EINVAL: Property not found */ if (ret != -EINVAL) { int econtrol; @@ -1539,19 +1538,17 @@ static int palmas_dt_to_pdata(struct device *dev, rinit->roof_floor = econtrol; } - ret = of_property_read_u32(match->of_node, "ti,mode-sleep", - &prop); + ret = of_property_read_u32(np, "ti,mode-sleep", &prop); if (!ret) rinit->mode_sleep = prop; - ret = of_property_read_bool(match->of_node, "ti,smps-range"); + ret = of_property_read_bool(np, "ti,smps-range"); if (ret) rinit->vsel = PALMAS_SMPS12_VOLTAGE_RANGE; if (idx == PALMAS_REG_LDO8) pdata->enable_ldo8_tracking = of_property_read_bool( - match->of_node, - "ti,enable-ldo8-tracking"); + np, "ti,enable-ldo8-tracking"); } pdata->ldo6_vibrator = of_property_read_bool(node, "ti,ldo6-vibrator"); -- cgit v1.2.3