From 863981e96738983919de841ec669e157e6bdaeb0 Mon Sep 17 00:00:00 2001 From: AndrĂ© Fabian Silva Delgado Date: Sun, 11 Sep 2016 04:34:46 -0300 Subject: Linux-libre 4.7.1-gnu --- drivers/regulator/Kconfig | 17 + drivers/regulator/Makefile | 8 +- drivers/regulator/act8865-regulator.c | 113 ++- drivers/regulator/anatop-regulator.c | 2 +- drivers/regulator/as3722-regulator.c | 65 +- drivers/regulator/core.c | 268 ++++--- drivers/regulator/fan53555.c | 24 + drivers/regulator/helpers.c | 2 +- drivers/regulator/lp3971.c | 2 +- drivers/regulator/lp3972.c | 2 +- drivers/regulator/lp873x-regulator.c | 241 ++++++ drivers/regulator/max14577-regulator.c | 337 +++++++++ drivers/regulator/max14577.c | 337 --------- drivers/regulator/max77620-regulator.c | 90 ++- drivers/regulator/max77686-regulator.c | 17 +- drivers/regulator/max77693-regulator.c | 318 ++++++++ drivers/regulator/max77693.c | 318 -------- drivers/regulator/max77802-regulator.c | 2 +- drivers/regulator/max8973-regulator.c | 97 +++ drivers/regulator/max8997-regulator.c | 1241 +++++++++++++++++++++++++++++++ drivers/regulator/max8997.c | 1241 ------------------------------- drivers/regulator/of_regulator.c | 6 +- drivers/regulator/palmas-regulator.c | 67 +- drivers/regulator/pv88080-regulator.c | 419 +++++++++++ drivers/regulator/pv88080-regulator.h | 92 +++ drivers/regulator/pwm-regulator.c | 78 +- drivers/regulator/qcom_spmi-regulator.c | 275 ++++--- drivers/regulator/rk808-regulator.c | 310 +++----- drivers/regulator/s2mps11.c | 13 +- drivers/regulator/tps51632-regulator.c | 9 +- drivers/regulator/tps6524x-regulator.c | 2 +- drivers/regulator/twl-regulator.c | 106 ++- 32 files changed, 3659 insertions(+), 2460 deletions(-) create mode 100644 drivers/regulator/lp873x-regulator.c 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 create mode 100644 drivers/regulator/pv88080-regulator.c create mode 100644 drivers/regulator/pv88080-regulator.h (limited to 'drivers/regulator') diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index c77dc08b1..144cbf5b3 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -321,6 +321,15 @@ config REGULATOR_LP872X help This driver supports LP8720/LP8725 PMIC +config REGULATOR_LP873X + tristate "TI LP873X Power regulators" + depends on MFD_LP873X && OF + help + This driver supports LP873X voltage regulator chips. LP873X + provides two step-down converters and two general-purpose LDO + voltage regulators. It supports software based voltage control + for different voltage domains + config REGULATOR_LP8755 tristate "TI LP8755 High Performance PMU driver" depends on I2C @@ -409,6 +418,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 @@ -548,6 +558,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 61bfbb9d4..85a1d44a3 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -42,11 +42,12 @@ obj-$(CONFIG_REGULATOR_LM363X) += lm363x-regulator.o obj-$(CONFIG_REGULATOR_LP3971) += lp3971.o obj-$(CONFIG_REGULATOR_LP3972) += lp3972.o obj-$(CONFIG_REGULATOR_LP872X) += lp872x.o +obj-$(CONFIG_REGULATOR_LP873X) += lp873x-regulator.o 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 +56,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 @@ -71,6 +72,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/act8865-regulator.c b/drivers/regulator/act8865-regulator.c index 000d566e3..a1cd0d4f8 100644 --- a/drivers/regulator/act8865-regulator.c +++ b/drivers/regulator/act8865-regulator.c @@ -139,6 +139,74 @@ struct act8865 { int off_mask; }; +static const struct regmap_range act8600_reg_ranges[] = { + regmap_reg_range(0x00, 0x01), + regmap_reg_range(0x10, 0x10), + regmap_reg_range(0x12, 0x12), + regmap_reg_range(0x20, 0x20), + regmap_reg_range(0x22, 0x22), + regmap_reg_range(0x30, 0x30), + regmap_reg_range(0x32, 0x32), + regmap_reg_range(0x40, 0x41), + regmap_reg_range(0x50, 0x51), + regmap_reg_range(0x60, 0x61), + regmap_reg_range(0x70, 0x71), + regmap_reg_range(0x80, 0x81), + regmap_reg_range(0x91, 0x91), + regmap_reg_range(0xA1, 0xA1), + regmap_reg_range(0xA8, 0xAA), + regmap_reg_range(0xB0, 0xB0), + regmap_reg_range(0xB2, 0xB2), + regmap_reg_range(0xC1, 0xC1), +}; + +static const struct regmap_range act8600_reg_ro_ranges[] = { + regmap_reg_range(0xAA, 0xAA), + regmap_reg_range(0xC1, 0xC1), +}; + +static const struct regmap_range act8600_reg_volatile_ranges[] = { + regmap_reg_range(0x00, 0x01), + regmap_reg_range(0x12, 0x12), + regmap_reg_range(0x22, 0x22), + regmap_reg_range(0x32, 0x32), + regmap_reg_range(0x41, 0x41), + regmap_reg_range(0x51, 0x51), + regmap_reg_range(0x61, 0x61), + regmap_reg_range(0x71, 0x71), + regmap_reg_range(0x81, 0x81), + regmap_reg_range(0xA8, 0xA8), + regmap_reg_range(0xAA, 0xAA), + regmap_reg_range(0xB0, 0xB0), + regmap_reg_range(0xC1, 0xC1), +}; + +static const struct regmap_access_table act8600_write_ranges_table = { + .yes_ranges = act8600_reg_ranges, + .n_yes_ranges = ARRAY_SIZE(act8600_reg_ranges), + .no_ranges = act8600_reg_ro_ranges, + .n_no_ranges = ARRAY_SIZE(act8600_reg_ro_ranges), +}; + +static const struct regmap_access_table act8600_read_ranges_table = { + .yes_ranges = act8600_reg_ranges, + .n_yes_ranges = ARRAY_SIZE(act8600_reg_ranges), +}; + +static const struct regmap_access_table act8600_volatile_ranges_table = { + .yes_ranges = act8600_reg_volatile_ranges, + .n_yes_ranges = ARRAY_SIZE(act8600_reg_volatile_ranges), +}; + +static const struct regmap_config act8600_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = 0xFF, + .wr_table = &act8600_write_ranges_table, + .rd_table = &act8600_read_ranges_table, + .volatile_table = &act8600_volatile_ranges_table, +}; + static const struct regmap_config act8865_regmap_config = { .reg_bits = 8, .val_bits = 8, @@ -319,7 +387,6 @@ static struct of_regulator_match act8600_matches[] = { }; static int act8865_pdata_from_dt(struct device *dev, - struct device_node **of_node, struct act8865_platform_data *pdata, unsigned long type) { @@ -370,7 +437,7 @@ static int act8865_pdata_from_dt(struct device *dev, regulator->id = i; regulator->name = matches[i].name; regulator->init_data = matches[i].init_data; - of_node[i] = matches[i].of_node; + regulator->of_node = matches[i].of_node; regulator++; } @@ -378,7 +445,6 @@ static int act8865_pdata_from_dt(struct device *dev, } #else static inline int act8865_pdata_from_dt(struct device *dev, - struct device_node **of_node, struct act8865_platform_data *pdata, unsigned long type) { @@ -386,8 +452,8 @@ static inline int act8865_pdata_from_dt(struct device *dev, } #endif -static struct regulator_init_data -*act8865_get_init_data(int id, struct act8865_platform_data *pdata) +static struct act8865_regulator_data *act8865_get_regulator_data( + int id, struct act8865_platform_data *pdata) { int i; @@ -396,7 +462,7 @@ static struct regulator_init_data for (i = 0; i < pdata->num_regulators; i++) { if (pdata->regulators[i].id == id) - return pdata->regulators[i].init_data; + return &pdata->regulators[i]; } return NULL; @@ -418,9 +484,9 @@ static int act8865_pmic_probe(struct i2c_client *client, const struct regulator_desc *regulators; struct act8865_platform_data pdata_of, *pdata; struct device *dev = &client->dev; - struct device_node **of_node; int i, ret, num_regulators; struct act8865 *act8865; + const struct regmap_config *regmap_config; unsigned long type; int off_reg, off_mask; int voltage_select = 0; @@ -447,12 +513,14 @@ static int act8865_pmic_probe(struct i2c_client *client, case ACT8600: regulators = act8600_regulators; num_regulators = ARRAY_SIZE(act8600_regulators); + regmap_config = &act8600_regmap_config; off_reg = -1; off_mask = -1; break; case ACT8846: regulators = act8846_regulators; num_regulators = ARRAY_SIZE(act8846_regulators); + regmap_config = &act8865_regmap_config; off_reg = ACT8846_GLB_OFF_CTRL; off_mask = ACT8846_OFF_SYSMASK; break; @@ -464,6 +532,7 @@ static int act8865_pmic_probe(struct i2c_client *client, regulators = act8865_regulators; num_regulators = ARRAY_SIZE(act8865_regulators); } + regmap_config = &act8865_regmap_config; off_reg = ACT8865_SYS_CTRL; off_mask = ACT8865_MSTROFF; break; @@ -472,34 +541,22 @@ static int act8865_pmic_probe(struct i2c_client *client, return -EINVAL; } - of_node = devm_kzalloc(dev, sizeof(struct device_node *) * - num_regulators, GFP_KERNEL); - if (!of_node) - return -ENOMEM; - if (dev->of_node && !pdata) { - ret = act8865_pdata_from_dt(dev, of_node, &pdata_of, type); + ret = act8865_pdata_from_dt(dev, &pdata_of, type); if (ret < 0) return ret; pdata = &pdata_of; } - if (pdata->num_regulators > num_regulators) { - dev_err(dev, "too many regulators: %d\n", - pdata->num_regulators); - return -EINVAL; - } - act8865 = devm_kzalloc(dev, sizeof(struct act8865), GFP_KERNEL); if (!act8865) return -ENOMEM; - act8865->regmap = devm_regmap_init_i2c(client, &act8865_regmap_config); + act8865->regmap = devm_regmap_init_i2c(client, regmap_config); if (IS_ERR(act8865->regmap)) { ret = PTR_ERR(act8865->regmap); - dev_err(&client->dev, "Failed to allocate register map: %d\n", - ret); + dev_err(dev, "Failed to allocate register map: %d\n", ret); return ret; } @@ -518,15 +575,20 @@ static int act8865_pmic_probe(struct i2c_client *client, for (i = 0; i < num_regulators; i++) { const struct regulator_desc *desc = ®ulators[i]; struct regulator_config config = { }; + struct act8865_regulator_data *rdata; struct regulator_dev *rdev; config.dev = dev; - config.init_data = act8865_get_init_data(desc->id, pdata); - config.of_node = of_node[i]; config.driver_data = act8865; config.regmap = act8865->regmap; - rdev = devm_regulator_register(&client->dev, desc, &config); + rdata = act8865_get_regulator_data(desc->id, pdata); + if (rdata) { + config.init_data = rdata->init_data; + config.of_node = rdata->of_node; + } + + rdev = devm_regulator_register(dev, desc, &config); if (IS_ERR(rdev)) { dev_err(dev, "failed to register %s\n", desc->name); return PTR_ERR(rdev); @@ -534,7 +596,6 @@ static int act8865_pmic_probe(struct i2c_client *client, } i2c_set_clientdata(client, act8865); - devm_kfree(dev, of_node); return 0; } diff --git a/drivers/regulator/anatop-regulator.c b/drivers/regulator/anatop-regulator.c index 63cd5e68c..3a6d0290c 100644 --- a/drivers/regulator/anatop-regulator.c +++ b/drivers/regulator/anatop-regulator.c @@ -296,7 +296,7 @@ static int anatop_regulator_probe(struct platform_device *pdev) if (!sreg->sel && !strcmp(sreg->name, "vddpu")) sreg->sel = 22; - if (!sreg->sel) { + if (!sreg->bypass && !sreg->sel) { dev_err(&pdev->dev, "Failed to read a valid default voltage selector.\n"); return -EINVAL; } diff --git a/drivers/regulator/as3722-regulator.c b/drivers/regulator/as3722-regulator.c index 8b046eec6..66337e127 100644 --- a/drivers/regulator/as3722-regulator.c +++ b/drivers/regulator/as3722-regulator.c @@ -372,7 +372,7 @@ static int as3722_ldo_set_current_limit(struct regulator_dev *rdev, AS3722_LDO_ILIMIT_MASK, reg); } -static struct regulator_ops as3722_ldo0_ops = { +static const struct regulator_ops as3722_ldo0_ops = { .is_enabled = regulator_is_enabled_regmap, .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, @@ -383,7 +383,7 @@ static struct regulator_ops as3722_ldo0_ops = { .set_current_limit = as3722_ldo_set_current_limit, }; -static struct regulator_ops as3722_ldo0_extcntrl_ops = { +static const struct regulator_ops as3722_ldo0_extcntrl_ops = { .list_voltage = regulator_list_voltage_linear, .get_voltage_sel = regulator_get_voltage_sel_regmap, .set_voltage_sel = regulator_set_voltage_sel_regmap, @@ -415,7 +415,7 @@ static int as3722_ldo3_get_current_limit(struct regulator_dev *rdev) return 150000; } -static struct regulator_ops as3722_ldo3_ops = { +static const struct regulator_ops as3722_ldo3_ops = { .is_enabled = regulator_is_enabled_regmap, .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, @@ -425,20 +425,45 @@ static struct regulator_ops as3722_ldo3_ops = { .get_current_limit = as3722_ldo3_get_current_limit, }; -static struct regulator_ops as3722_ldo3_extcntrl_ops = { +static const struct regulator_ops as3722_ldo3_extcntrl_ops = { .list_voltage = regulator_list_voltage_linear, .get_voltage_sel = regulator_get_voltage_sel_regmap, .set_voltage_sel = regulator_set_voltage_sel_regmap, .get_current_limit = as3722_ldo3_get_current_limit, }; +static const struct regulator_ops as3722_ldo6_ops = { + .is_enabled = regulator_is_enabled_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .map_voltage = regulator_map_voltage_linear_range, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .list_voltage = regulator_list_voltage_linear_range, + .get_current_limit = as3722_ldo_get_current_limit, + .set_current_limit = as3722_ldo_set_current_limit, + .get_bypass = regulator_get_bypass_regmap, + .set_bypass = regulator_set_bypass_regmap, +}; + +static const struct regulator_ops as3722_ldo6_extcntrl_ops = { + .map_voltage = regulator_map_voltage_linear_range, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .list_voltage = regulator_list_voltage_linear_range, + .get_current_limit = as3722_ldo_get_current_limit, + .set_current_limit = as3722_ldo_set_current_limit, + .get_bypass = regulator_get_bypass_regmap, + .set_bypass = regulator_set_bypass_regmap, +}; + static const struct regulator_linear_range as3722_ldo_ranges[] = { REGULATOR_LINEAR_RANGE(0, 0x00, 0x00, 0), REGULATOR_LINEAR_RANGE(825000, 0x01, 0x24, 25000), REGULATOR_LINEAR_RANGE(1725000, 0x40, 0x7F, 25000), }; -static struct regulator_ops as3722_ldo_ops = { +static const struct regulator_ops as3722_ldo_ops = { .is_enabled = regulator_is_enabled_regmap, .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, @@ -450,7 +475,7 @@ static struct regulator_ops as3722_ldo_ops = { .set_current_limit = as3722_ldo_set_current_limit, }; -static struct regulator_ops as3722_ldo_extcntrl_ops = { +static const struct regulator_ops as3722_ldo_extcntrl_ops = { .map_voltage = regulator_map_voltage_linear_range, .set_voltage_sel = regulator_set_voltage_sel_regmap, .get_voltage_sel = regulator_get_voltage_sel_regmap, @@ -616,7 +641,7 @@ static const struct regulator_linear_range as3722_sd2345_ranges[] = { REGULATOR_LINEAR_RANGE(2650000, 0x71, 0x7F, 50000), }; -static struct regulator_ops as3722_sd016_ops = { +static const struct regulator_ops as3722_sd016_ops = { .is_enabled = regulator_is_enabled_regmap, .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, @@ -630,7 +655,7 @@ static struct regulator_ops as3722_sd016_ops = { .set_mode = as3722_sd_set_mode, }; -static struct regulator_ops as3722_sd016_extcntrl_ops = { +static const struct regulator_ops as3722_sd016_extcntrl_ops = { .list_voltage = regulator_list_voltage_linear, .map_voltage = regulator_map_voltage_linear, .get_voltage_sel = regulator_get_voltage_sel_regmap, @@ -641,7 +666,7 @@ static struct regulator_ops as3722_sd016_extcntrl_ops = { .set_mode = as3722_sd_set_mode, }; -static struct regulator_ops as3722_sd2345_ops = { +static const struct regulator_ops as3722_sd2345_ops = { .is_enabled = regulator_is_enabled_regmap, .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, @@ -653,7 +678,7 @@ static struct regulator_ops as3722_sd2345_ops = { .set_mode = as3722_sd_set_mode, }; -static struct regulator_ops as3722_sd2345_extcntrl_ops = { +static const struct regulator_ops as3722_sd2345_extcntrl_ops = { .list_voltage = regulator_list_voltage_linear_range, .map_voltage = regulator_map_voltage_linear_range, .set_voltage_sel = regulator_set_voltage_sel_regmap, @@ -760,7 +785,7 @@ static int as3722_regulator_probe(struct platform_device *pdev) struct as3722_regulator_config_data *reg_config; struct regulator_dev *rdev; struct regulator_config config = { }; - struct regulator_ops *ops; + const struct regulator_ops *ops; int id; int ret; @@ -829,6 +854,24 @@ static int as3722_regulator_probe(struct platform_device *pdev) } } break; + case AS3722_REGULATOR_ID_LDO6: + if (reg_config->ext_control) + ops = &as3722_ldo6_extcntrl_ops; + else + ops = &as3722_ldo6_ops; + as3722_regs->desc[id].enable_time = 500; + as3722_regs->desc[id].bypass_reg = + AS3722_LDO6_VOLTAGE_REG; + as3722_regs->desc[id].bypass_mask = + AS3722_LDO_VSEL_MASK; + as3722_regs->desc[id].bypass_val_on = + AS3722_LDO6_VSEL_BYPASS; + as3722_regs->desc[id].bypass_val_off = + AS3722_LDO6_VSEL_BYPASS; + as3722_regs->desc[id].linear_ranges = as3722_ldo_ranges; + as3722_regs->desc[id].n_linear_ranges = + ARRAY_SIZE(as3722_ldo_ranges); + break; case AS3722_REGULATOR_ID_SD0: case AS3722_REGULATOR_ID_SD1: case AS3722_REGULATOR_ID_SD6: diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index fd0e4e37f..ec8184d53 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -132,6 +132,19 @@ static bool have_full_constraints(void) return has_full_constraints || of_have_populated_dt(); } +static bool regulator_ops_is_valid(struct regulator_dev *rdev, int ops) +{ + if (!rdev->constraints) { + rdev_err(rdev, "no constraints\n"); + return false; + } + + if (rdev->constraints->valid_ops_mask & ops) + return true; + + return false; +} + static inline struct regulator_dev *rdev_get_supply(struct regulator_dev *rdev) { if (rdev && rdev->supply) @@ -198,28 +211,13 @@ static struct device_node *of_get_regulator(struct device *dev, const char *supp return regnode; } -static int _regulator_can_change_status(struct regulator_dev *rdev) -{ - if (!rdev->constraints) - return 0; - - if (rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_STATUS) - return 1; - else - return 0; -} - /* Platform voltage constraint check */ static int regulator_check_voltage(struct regulator_dev *rdev, int *min_uV, int *max_uV) { BUG_ON(*min_uV > *max_uV); - if (!rdev->constraints) { - rdev_err(rdev, "no constraints\n"); - return -ENODEV; - } - if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_VOLTAGE)) { + if (!regulator_ops_is_valid(rdev, REGULATOR_CHANGE_VOLTAGE)) { rdev_err(rdev, "voltage operation not allowed\n"); return -EPERM; } @@ -275,11 +273,7 @@ static int regulator_check_current_limit(struct regulator_dev *rdev, { BUG_ON(*min_uA > *max_uA); - if (!rdev->constraints) { - rdev_err(rdev, "no constraints\n"); - return -ENODEV; - } - if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_CURRENT)) { + if (!regulator_ops_is_valid(rdev, REGULATOR_CHANGE_CURRENT)) { rdev_err(rdev, "current operation not allowed\n"); return -EPERM; } @@ -312,11 +306,7 @@ static int regulator_mode_constrain(struct regulator_dev *rdev, int *mode) return -EINVAL; } - if (!rdev->constraints) { - rdev_err(rdev, "no constraints\n"); - return -ENODEV; - } - if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_MODE)) { + if (!regulator_ops_is_valid(rdev, REGULATOR_CHANGE_MODE)) { rdev_err(rdev, "mode operation not allowed\n"); return -EPERM; } @@ -333,20 +323,6 @@ static int regulator_mode_constrain(struct regulator_dev *rdev, int *mode) return -EINVAL; } -/* dynamic regulator mode switching constraint check */ -static int regulator_check_drms(struct regulator_dev *rdev) -{ - if (!rdev->constraints) { - rdev_err(rdev, "no constraints\n"); - return -ENODEV; - } - if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_DRMS)) { - rdev_dbg(rdev, "drms operation not allowed\n"); - return -EPERM; - } - return 0; -} - static ssize_t regulator_uV_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -692,8 +668,7 @@ static int drms_uA_update(struct regulator_dev *rdev) * first check to see if we can set modes at all, otherwise just * tell the consumer everything is OK. */ - err = regulator_check_drms(rdev); - if (err < 0) + if (!regulator_ops_is_valid(rdev, REGULATOR_CHANGE_DRMS)) return 0; if (!rdev->desc->ops->get_optimum_mode && @@ -808,8 +783,6 @@ static int suspend_set_state(struct regulator_dev *rdev, /* locks held by caller */ static int suspend_prepare(struct regulator_dev *rdev, suspend_state_t state) { - lockdep_assert_held_once(&rdev->mutex); - if (!rdev->constraints) return -EINVAL; @@ -893,7 +866,7 @@ static void print_constraints(struct regulator_dev *rdev) rdev_dbg(rdev, "%s\n", buf); if ((constraints->min_uV != constraints->max_uV) && - !(constraints->valid_ops_mask & REGULATOR_CHANGE_VOLTAGE)) + !regulator_ops_is_valid(rdev, REGULATOR_CHANGE_VOLTAGE)) rdev_warn(rdev, "Voltage range but no REGULATOR_CHANGE_VOLTAGE\n"); } @@ -906,7 +879,8 @@ static int machine_constraints_voltage(struct regulator_dev *rdev, /* do we need to apply the constraint voltage */ if (rdev->constraints->apply_uV && - rdev->constraints->min_uV == rdev->constraints->max_uV) { + rdev->constraints->min_uV && rdev->constraints->max_uV) { + int target_min, target_max; int current_uV = _regulator_get_voltage(rdev); if (current_uV < 0) { rdev_err(rdev, @@ -914,15 +888,34 @@ static int machine_constraints_voltage(struct regulator_dev *rdev, current_uV); return current_uV; } - if (current_uV < rdev->constraints->min_uV || - current_uV > rdev->constraints->max_uV) { + + /* + * If we're below the minimum voltage move up to the + * minimum voltage, if we're above the maximum voltage + * then move down to the maximum. + */ + target_min = current_uV; + target_max = current_uV; + + if (current_uV < rdev->constraints->min_uV) { + target_min = rdev->constraints->min_uV; + target_max = rdev->constraints->min_uV; + } + + if (current_uV > rdev->constraints->max_uV) { + target_min = rdev->constraints->max_uV; + target_max = rdev->constraints->max_uV; + } + + if (target_min != current_uV || target_max != current_uV) { + rdev_info(rdev, "Bringing %duV into %d-%duV\n", + current_uV, target_min, target_max); ret = _regulator_do_set_voltage( - rdev, rdev->constraints->min_uV, - rdev->constraints->max_uV); + rdev, target_min, target_max); if (ret < 0) { rdev_err(rdev, - "failed to apply %duV constraint(%d)\n", - rdev->constraints->min_uV, ret); + "failed to apply %d-%duV constraint(%d)\n", + target_min, target_max, ret); return ret; } } @@ -1150,17 +1143,6 @@ static int set_machine_constraints(struct regulator_dev *rdev, } } - if (rdev->constraints->active_discharge && ops->set_active_discharge) { - bool ad_state = (rdev->constraints->active_discharge == - REGULATOR_ACTIVE_DISCHARGE_ENABLE) ? true : false; - - ret = ops->set_active_discharge(rdev, ad_state); - if (ret < 0) { - rdev_err(rdev, "failed to set active discharge\n"); - return ret; - } - } - print_constraints(rdev); return 0; } @@ -1272,6 +1254,55 @@ static void unset_regulator_supplies(struct regulator_dev *rdev) } } +#ifdef CONFIG_DEBUG_FS +static ssize_t constraint_flags_read_file(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + const struct regulator *regulator = file->private_data; + const struct regulation_constraints *c = regulator->rdev->constraints; + char *buf; + ssize_t ret; + + if (!c) + return 0; + + buf = kmalloc(PAGE_SIZE, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + ret = snprintf(buf, PAGE_SIZE, + "always_on: %u\n" + "boot_on: %u\n" + "apply_uV: %u\n" + "ramp_disable: %u\n" + "soft_start: %u\n" + "pull_down: %u\n" + "over_current_protection: %u\n", + c->always_on, + c->boot_on, + c->apply_uV, + c->ramp_disable, + c->soft_start, + c->pull_down, + c->over_current_protection); + + ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret); + kfree(buf); + + return ret; +} + +#endif + +static const struct file_operations constraint_flags_fops = { +#ifdef CONFIG_DEBUG_FS + .open = simple_open, + .read = constraint_flags_read_file, + .llseek = default_llseek, +#endif +}; + #define REG_STR_SIZE 64 static struct regulator *create_regulator(struct regulator_dev *rdev, @@ -1327,6 +1358,9 @@ static struct regulator *create_regulator(struct regulator_dev *rdev, ®ulator->min_uV); debugfs_create_u32("max_uV", 0444, regulator->debugfs, ®ulator->max_uV); + debugfs_create_file("constraint_flags", 0444, + regulator->debugfs, regulator, + &constraint_flags_fops); } /* @@ -1334,7 +1368,7 @@ static struct regulator *create_regulator(struct regulator_dev *rdev, * it is then we don't need to do nearly so much work for * enable/disable calls. */ - if (!_regulator_can_change_status(rdev) && + if (!regulator_ops_is_valid(rdev, REGULATOR_CHANGE_STATUS) && _regulator_is_enabled(rdev)) regulator->always_on = true; @@ -1532,10 +1566,11 @@ static int regulator_resolve_supply(struct regulator_dev *rdev) } /* Cascade always-on state to supply */ - if (_regulator_is_enabled(rdev) && rdev->supply) { + if (_regulator_is_enabled(rdev)) { ret = regulator_enable(rdev->supply); if (ret < 0) { _regulator_put(rdev->supply); + rdev->supply = NULL; return ret; } } @@ -2111,15 +2146,15 @@ static int _regulator_enable(struct regulator_dev *rdev) lockdep_assert_held_once(&rdev->mutex); /* check voltage and requested load before enabling */ - if (rdev->constraints && - (rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_DRMS)) + if (regulator_ops_is_valid(rdev, REGULATOR_CHANGE_DRMS)) drms_uA_update(rdev); if (rdev->use_count == 0) { /* The regulator may on if it's not switchable or left on */ ret = _regulator_is_enabled(rdev); if (ret == -EINVAL || ret == 0) { - if (!_regulator_can_change_status(rdev)) + if (!regulator_ops_is_valid(rdev, + REGULATOR_CHANGE_STATUS)) return -EPERM; ret = _regulator_do_enable(rdev); @@ -2221,7 +2256,7 @@ static int _regulator_disable(struct regulator_dev *rdev) (rdev->constraints && !rdev->constraints->always_on)) { /* we are last user */ - if (_regulator_can_change_status(rdev)) { + if (regulator_ops_is_valid(rdev, REGULATOR_CHANGE_STATUS)) { ret = _notifier_call_chain(rdev, REGULATOR_EVENT_PRE_DISABLE, NULL); @@ -2242,10 +2277,7 @@ static int _regulator_disable(struct regulator_dev *rdev) rdev->use_count = 0; } else if (rdev->use_count > 1) { - - if (rdev->constraints && - (rdev->constraints->valid_ops_mask & - REGULATOR_CHANGE_DRMS)) + if (regulator_ops_is_valid(rdev, REGULATOR_CHANGE_DRMS)) drms_uA_update(rdev); rdev->use_count--; @@ -2489,8 +2521,7 @@ int regulator_can_change_voltage(struct regulator *regulator) { struct regulator_dev *rdev = regulator->rdev; - if (rdev->constraints && - (rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_VOLTAGE)) { + if (regulator_ops_is_valid(rdev, REGULATOR_CHANGE_VOLTAGE)) { if (rdev->desc->n_voltages - rdev->desc->linear_min_sel > 1) return 1; @@ -2644,7 +2675,7 @@ int regulator_is_supported_voltage(struct regulator *regulator, int i, voltages, ret; /* If we can't change voltage check the current voltage */ - if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_VOLTAGE)) { + if (!regulator_ops_is_valid(rdev, REGULATOR_CHANGE_VOLTAGE)) { ret = regulator_get_voltage(regulator); if (ret >= 0) return min_uV <= ret && ret <= max_uV; @@ -2850,7 +2881,7 @@ static int regulator_set_voltage_unlocked(struct regulator *regulator, * return successfully even though the regulator does not support * changing the voltage. */ - if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_VOLTAGE)) { + if (!regulator_ops_is_valid(rdev, REGULATOR_CHANGE_VOLTAGE)) { current_uV = _regulator_get_voltage(rdev); if (min_uV <= current_uV && current_uV <= max_uV) { regulator->min_uV = min_uV; @@ -3109,6 +3140,23 @@ EXPORT_SYMBOL_GPL(regulator_sync_voltage); static int _regulator_get_voltage(struct regulator_dev *rdev) { int sel, ret; + bool bypassed; + + if (rdev->desc->ops->get_bypass) { + ret = rdev->desc->ops->get_bypass(rdev, &bypassed); + if (ret < 0) + return ret; + if (bypassed) { + /* if bypassed the regulator must have a supply */ + if (!rdev->supply) { + rdev_err(rdev, + "bypassed regulator has no supply!\n"); + return -EPROBE_DEFER; + } + + return _regulator_get_voltage(rdev->supply->rdev); + } + } if (rdev->desc->ops->get_voltage_sel) { sel = rdev->desc->ops->get_voltage_sel(rdev); @@ -3365,8 +3413,7 @@ int regulator_allow_bypass(struct regulator *regulator, bool enable) if (!rdev->desc->ops->set_bypass) return 0; - if (rdev->constraints && - !(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_BYPASS)) + if (!regulator_ops_is_valid(rdev, REGULATOR_CHANGE_BYPASS)) return 0; mutex_lock(&rdev->mutex); @@ -3842,7 +3889,12 @@ static void rdev_init_debugfs(struct regulator_dev *rdev) static int regulator_register_resolve_supply(struct device *dev, void *data) { - return regulator_resolve_supply(dev_to_rdev(dev)); + struct regulator_dev *rdev = dev_to_rdev(dev); + + if (regulator_resolve_supply(rdev)) + rdev_dbg(rdev, "unable to resolve supply\n"); + + return 0; } /** @@ -3916,8 +3968,6 @@ regulator_register(const struct regulator_desc *regulator_desc, rdev->dev.of_node = of_node_get(config->of_node); } - mutex_lock(®ulator_list_mutex); - mutex_init(&rdev->mutex); rdev->reg_data = config->driver_data; rdev->owner = regulator_desc->owner; @@ -3942,7 +3992,9 @@ regulator_register(const struct regulator_desc *regulator_desc, if ((config->ena_gpio || config->ena_gpio_initialized) && gpio_is_valid(config->ena_gpio)) { + mutex_lock(®ulator_list_mutex); ret = regulator_ena_gpio_request(rdev, config); + mutex_unlock(®ulator_list_mutex); if (ret != 0) { rdev_err(rdev, "Failed to request enable GPIO%d: %d\n", config->ena_gpio, ret); @@ -3955,43 +4007,53 @@ regulator_register(const struct regulator_desc *regulator_desc, rdev->dev.parent = dev; dev_set_name(&rdev->dev, "regulator.%lu", (unsigned long) atomic_inc_return(®ulator_no)); - ret = device_register(&rdev->dev); - if (ret != 0) { - put_device(&rdev->dev); - goto wash; - } - - dev_set_drvdata(&rdev->dev, rdev); /* set regulator constraints */ if (init_data) constraints = &init_data->constraints; - ret = set_machine_constraints(rdev, constraints); - if (ret < 0) - goto scrub; - if (init_data && init_data->supply_regulator) rdev->supply_name = init_data->supply_regulator; else if (regulator_desc->supply_name) rdev->supply_name = regulator_desc->supply_name; + /* + * Attempt to resolve the regulator supply, if specified, + * but don't return an error if we fail because we will try + * to resolve it again later as more regulators are added. + */ + if (regulator_resolve_supply(rdev)) + rdev_dbg(rdev, "unable to resolve supply\n"); + + ret = set_machine_constraints(rdev, constraints); + if (ret < 0) + goto wash; + /* add consumers devices */ if (init_data) { + mutex_lock(®ulator_list_mutex); for (i = 0; i < init_data->num_consumer_supplies; i++) { ret = set_consumer_device_supply(rdev, init_data->consumer_supplies[i].dev_name, init_data->consumer_supplies[i].supply); if (ret < 0) { + mutex_unlock(®ulator_list_mutex); dev_err(dev, "Failed to set supply %s\n", init_data->consumer_supplies[i].supply); goto unset_supplies; } } + mutex_unlock(®ulator_list_mutex); } + ret = device_register(&rdev->dev); + if (ret != 0) { + put_device(&rdev->dev); + goto unset_supplies; + } + + dev_set_drvdata(&rdev->dev, rdev); rdev_init_debugfs(rdev); - mutex_unlock(®ulator_list_mutex); /* try to resolve regulators supply since a new one was registered */ class_for_each_device(®ulator_class, NULL, NULL, @@ -4000,20 +4062,16 @@ regulator_register(const struct regulator_desc *regulator_desc, return rdev; unset_supplies: + mutex_lock(®ulator_list_mutex); unset_regulator_supplies(rdev); - -scrub: - regulator_ena_gpio_free(rdev); - device_unregister(&rdev->dev); - /* device core frees rdev */ - goto out; - + mutex_unlock(®ulator_list_mutex); wash: + kfree(rdev->constraints); + mutex_lock(®ulator_list_mutex); regulator_ena_gpio_free(rdev); + mutex_unlock(®ulator_list_mutex); clean: kfree(rdev); -out: - mutex_unlock(®ulator_list_mutex); kfree(config); return ERR_PTR(ret); } @@ -4041,8 +4099,8 @@ void regulator_unregister(struct regulator_dev *rdev) WARN_ON(rdev->open_count); unset_regulator_supplies(rdev); list_del(&rdev->list); - mutex_unlock(®ulator_list_mutex); regulator_ena_gpio_free(rdev); + mutex_unlock(®ulator_list_mutex); device_unregister(&rdev->dev); } EXPORT_SYMBOL_GPL(regulator_unregister); @@ -4395,7 +4453,7 @@ static int __init regulator_late_cleanup(struct device *dev, void *data) if (c && c->always_on) return 0; - if (c && !(c->valid_ops_mask & REGULATOR_CHANGE_STATUS)) + if (!regulator_ops_is_valid(rdev, REGULATOR_CHANGE_STATUS)) return 0; mutex_lock(&rdev->mutex); diff --git a/drivers/regulator/fan53555.c b/drivers/regulator/fan53555.c index 2cb5cc311..d7da81a87 100644 --- a/drivers/regulator/fan53555.c +++ b/drivers/regulator/fan53555.c @@ -65,6 +65,13 @@ enum { FAN53555_CHIP_ID_03, FAN53555_CHIP_ID_04, FAN53555_CHIP_ID_05, + FAN53555_CHIP_ID_08 = 8, +}; + +/* IC mask revision */ +enum { + FAN53555_CHIP_REV_00 = 0x3, + FAN53555_CHIP_REV_13 = 0xf, }; enum { @@ -217,9 +224,26 @@ static int fan53555_voltages_setup_fairchild(struct fan53555_device_info *di) /* Init voltage range and step */ switch (di->chip_id) { case FAN53555_CHIP_ID_00: + switch (di->chip_rev) { + case FAN53555_CHIP_REV_00: + di->vsel_min = 600000; + di->vsel_step = 10000; + break; + case FAN53555_CHIP_REV_13: + di->vsel_min = 800000; + di->vsel_step = 10000; + break; + default: + dev_err(di->dev, + "Chip ID %d with rev %d not supported!\n", + di->chip_id, di->chip_rev); + return -EINVAL; + } + break; case FAN53555_CHIP_ID_01: case FAN53555_CHIP_ID_03: case FAN53555_CHIP_ID_05: + case FAN53555_CHIP_ID_08: di->vsel_min = 600000; di->vsel_step = 10000; break; diff --git a/drivers/regulator/helpers.c b/drivers/regulator/helpers.c index b1e32e748..bcf38fd51 100644 --- a/drivers/regulator/helpers.c +++ b/drivers/regulator/helpers.c @@ -460,7 +460,7 @@ int regulator_get_bypass_regmap(struct regulator_dev *rdev, bool *enable) if (ret != 0) return ret; - *enable = val & rdev->desc->bypass_mask; + *enable = (val & rdev->desc->bypass_mask) == rdev->desc->bypass_val_on; return 0; } diff --git a/drivers/regulator/lp3971.c b/drivers/regulator/lp3971.c index 15c25c622..204b5c527 100644 --- a/drivers/regulator/lp3971.c +++ b/drivers/regulator/lp3971.c @@ -365,8 +365,8 @@ static int lp3971_set_bits(struct lp3971 *lp3971, u8 reg, u16 mask, u16 val) mutex_lock(&lp3971->io_lock); ret = lp3971_i2c_read(lp3971->i2c, reg, 1, &tmp); - tmp = (tmp & ~mask) | val; if (ret == 0) { + tmp = (tmp & ~mask) | val; ret = lp3971_i2c_write(lp3971->i2c, reg, 1, &tmp); dev_dbg(lp3971->dev, "reg write 0x%02x -> 0x%02x\n", (int)reg, (unsigned)val&0xff); diff --git a/drivers/regulator/lp3972.c b/drivers/regulator/lp3972.c index 3a7e96e2c..ff0c275f9 100644 --- a/drivers/regulator/lp3972.c +++ b/drivers/regulator/lp3972.c @@ -211,8 +211,8 @@ static int lp3972_set_bits(struct lp3972 *lp3972, u8 reg, u16 mask, u16 val) mutex_lock(&lp3972->io_lock); ret = lp3972_i2c_read(lp3972->i2c, reg, 1, &tmp); - tmp = (tmp & ~mask) | val; if (ret == 0) { + tmp = (tmp & ~mask) | val; ret = lp3972_i2c_write(lp3972->i2c, reg, 1, &tmp); dev_dbg(lp3972->dev, "reg write 0x%02x -> 0x%02x\n", (int)reg, (unsigned)val & 0xff); diff --git a/drivers/regulator/lp873x-regulator.c b/drivers/regulator/lp873x-regulator.c new file mode 100644 index 000000000..b4ffd113b --- /dev/null +++ b/drivers/regulator/lp873x-regulator.c @@ -0,0 +1,241 @@ +/* + * Regulator driver for LP873X PMIC + * + * Copyright (C) 2016 Texas Instruments Incorporated - http://www.ti.com/ + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether expressed or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License version 2 for more details. + */ + +#include +#include +#include + +#include + +#define LP873X_REGULATOR(_name, _id, _of, _ops, _n, _vr, _vm, _er, _em, \ + _delay, _lr, _nlr, _cr) \ + [_id] = { \ + .desc = { \ + .name = _name, \ + .id = _id, \ + .of_match = of_match_ptr(_of), \ + .regulators_node = of_match_ptr("regulators"),\ + .ops = &_ops, \ + .n_voltages = _n, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + .vsel_reg = _vr, \ + .vsel_mask = _vm, \ + .enable_reg = _er, \ + .enable_mask = _em, \ + .ramp_delay = _delay, \ + .linear_ranges = _lr, \ + .n_linear_ranges = _nlr, \ + }, \ + .ctrl2_reg = _cr, \ + } + +struct lp873x_regulator { + struct regulator_desc desc; + unsigned int ctrl2_reg; +}; + +static const struct lp873x_regulator regulators[]; + +static const struct regulator_linear_range buck0_buck1_ranges[] = { + REGULATOR_LINEAR_RANGE(0, 0x0, 0x13, 0), + REGULATOR_LINEAR_RANGE(700000, 0x14, 0x17, 10000), + REGULATOR_LINEAR_RANGE(735000, 0x18, 0x9d, 5000), + REGULATOR_LINEAR_RANGE(1420000, 0x9e, 0xff, 20000), +}; + +static const struct regulator_linear_range ldo0_ldo1_ranges[] = { + REGULATOR_LINEAR_RANGE(800000, 0x0, 0x19, 100000), +}; + +static unsigned int lp873x_buck_ramp_delay[] = { + 30000, 15000, 10000, 7500, 3800, 1900, 940, 470 +}; + +/* LP873X BUCK current limit */ +static const unsigned int lp873x_buck_uA[] = { + 1500000, 2000000, 2500000, 3000000, 3500000, 4000000, +}; + +static int lp873x_buck_set_ramp_delay(struct regulator_dev *rdev, + int ramp_delay) +{ + int id = rdev_get_id(rdev); + struct lp873x *lp873 = rdev_get_drvdata(rdev); + unsigned int reg; + int ret; + + if (ramp_delay <= 470) + reg = 7; + else if (ramp_delay <= 940) + reg = 6; + else if (ramp_delay <= 1900) + reg = 5; + else if (ramp_delay <= 3800) + reg = 4; + else if (ramp_delay <= 7500) + reg = 3; + else if (ramp_delay <= 10000) + reg = 2; + else if (ramp_delay <= 15000) + reg = 1; + else + reg = 0; + + ret = regmap_update_bits(lp873->regmap, regulators[id].ctrl2_reg, + LP873X_BUCK0_CTRL_2_BUCK0_SLEW_RATE, + reg << __ffs(LP873X_BUCK0_CTRL_2_BUCK0_SLEW_RATE)); + if (ret) { + dev_err(lp873->dev, "SLEW RATE write failed: %d\n", ret); + return ret; + } + + rdev->constraints->ramp_delay = lp873x_buck_ramp_delay[reg]; + + return 0; +} + +static int lp873x_buck_set_current_limit(struct regulator_dev *rdev, + int min_uA, int max_uA) +{ + int id = rdev_get_id(rdev); + struct lp873x *lp873 = rdev_get_drvdata(rdev); + int i; + + for (i = ARRAY_SIZE(lp873x_buck_uA) - 1; i >= 0; i--) { + if (lp873x_buck_uA[i] >= min_uA && + lp873x_buck_uA[i] <= max_uA) + return regmap_update_bits(lp873->regmap, + regulators[id].ctrl2_reg, + LP873X_BUCK0_CTRL_2_BUCK0_ILIM, + i << __ffs(LP873X_BUCK0_CTRL_2_BUCK0_ILIM)); + } + + return -EINVAL; +} + +static int lp873x_buck_get_current_limit(struct regulator_dev *rdev) +{ + int id = rdev_get_id(rdev); + struct lp873x *lp873 = rdev_get_drvdata(rdev); + int ret; + unsigned int val; + + ret = regmap_read(lp873->regmap, regulators[id].ctrl2_reg, &val); + if (ret) + return ret; + + val = (val & LP873X_BUCK0_CTRL_2_BUCK0_ILIM) >> + __ffs(LP873X_BUCK0_CTRL_2_BUCK0_ILIM); + + return (val < ARRAY_SIZE(lp873x_buck_uA)) ? + lp873x_buck_uA[val] : -EINVAL; +} + +/* Operations permitted on BUCK0, BUCK1 */ +static struct regulator_ops lp873x_buck01_ops = { + .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, + .list_voltage = regulator_list_voltage_linear_range, + .map_voltage = regulator_map_voltage_linear_range, + .set_voltage_time_sel = regulator_set_voltage_time_sel, + .set_ramp_delay = lp873x_buck_set_ramp_delay, + .set_current_limit = lp873x_buck_set_current_limit, + .get_current_limit = lp873x_buck_get_current_limit, +}; + +/* Operations permitted on LDO0 and LDO1 */ +static struct regulator_ops lp873x_ldo01_ops = { + .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, + .list_voltage = regulator_list_voltage_linear_range, + .map_voltage = regulator_map_voltage_linear_range, +}; + +static const struct lp873x_regulator regulators[] = { + LP873X_REGULATOR("BUCK0", LP873X_BUCK_0, "buck0", lp873x_buck01_ops, + 256, LP873X_REG_BUCK0_VOUT, + LP873X_BUCK0_VOUT_BUCK0_VSET, LP873X_REG_BUCK0_CTRL_1, + LP873X_BUCK0_CTRL_1_BUCK0_EN, 10000, + buck0_buck1_ranges, 4, LP873X_REG_BUCK0_CTRL_2), + LP873X_REGULATOR("BUCK1", LP873X_BUCK_1, "buck1", lp873x_buck01_ops, + 256, LP873X_REG_BUCK1_VOUT, + LP873X_BUCK1_VOUT_BUCK1_VSET, LP873X_REG_BUCK1_CTRL_1, + LP873X_BUCK1_CTRL_1_BUCK1_EN, 10000, + buck0_buck1_ranges, 4, LP873X_REG_BUCK1_CTRL_2), + LP873X_REGULATOR("LDO0", LP873X_LDO_0, "ldo0", lp873x_ldo01_ops, 26, + LP873X_REG_LDO0_VOUT, LP873X_LDO0_VOUT_LDO0_VSET, + LP873X_REG_LDO0_CTRL, + LP873X_LDO0_CTRL_LDO0_EN, 0, ldo0_ldo1_ranges, 1, + 0xFF), + LP873X_REGULATOR("LDO1", LP873X_LDO_1, "ldo1", lp873x_ldo01_ops, 26, + LP873X_REG_LDO1_VOUT, LP873X_LDO1_VOUT_LDO1_VSET, + LP873X_REG_LDO1_CTRL, + LP873X_LDO1_CTRL_LDO1_EN, 0, ldo0_ldo1_ranges, 1, + 0xFF), +}; + +static int lp873x_regulator_probe(struct platform_device *pdev) +{ + struct lp873x *lp873 = dev_get_drvdata(pdev->dev.parent); + struct regulator_config config = { }; + struct regulator_dev *rdev; + int i; + + platform_set_drvdata(pdev, lp873); + + config.dev = &pdev->dev; + config.dev->of_node = lp873->dev->of_node; + config.driver_data = lp873; + config.regmap = lp873->regmap; + + for (i = 0; i < ARRAY_SIZE(regulators); i++) { + rdev = devm_regulator_register(&pdev->dev, ®ulators[i].desc, + &config); + if (IS_ERR(rdev)) { + dev_err(lp873->dev, "failed to register %s regulator\n", + pdev->name); + return PTR_ERR(rdev); + } + } + + return 0; +} + +static const struct platform_device_id lp873x_regulator_id_table[] = { + { "lp873x-regulator", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(platform, lp873x_regulator_id_table); + +static struct platform_driver lp873x_regulator_driver = { + .driver = { + .name = "lp873x-pmic", + }, + .probe = lp873x_regulator_probe, + .id_table = lp873x_regulator_id_table, +}; +module_platform_driver(lp873x_regulator_driver); + +MODULE_AUTHOR("J Keerthy "); +MODULE_DESCRIPTION("LP873X voltage regulator driver"); +MODULE_ALIAS("platform:lp873x-pmic"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/regulator/max14577-regulator.c b/drivers/regulator/max14577-regulator.c new file mode 100644 index 000000000..b2daa6641 --- /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 b2daa6641..000000000 --- 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/max77620-regulator.c b/drivers/regulator/max77620-regulator.c index 73a3356a5..a1b49a6d5 100644 --- a/drivers/regulator/max77620-regulator.c +++ b/drivers/regulator/max77620-regulator.c @@ -81,6 +81,7 @@ struct max77620_regulator_pdata { int suspend_fps_pd_slot; int suspend_fps_pu_slot; int current_mode; + int ramp_rate_setting; }; struct max77620_regulator { @@ -122,6 +123,9 @@ static int max77620_regulator_set_fps_src(struct max77620_regulator *pmic, unsigned int val; int ret; + if (!rinfo) + return 0; + switch (fps_src) { case MAX77620_FPS_SRC_0: case MAX77620_FPS_SRC_1: @@ -170,6 +174,9 @@ static int max77620_regulator_set_fps_slots(struct max77620_regulator *pmic, int pd = rpdata->active_fps_pd_slot; int ret = 0; + if (!rinfo) + return 0; + if (is_suspend) { pu = rpdata->suspend_fps_pu_slot; pd = rpdata->suspend_fps_pd_slot; @@ -307,6 +314,43 @@ static int max77620_read_slew_rate(struct max77620_regulator *pmic, int id) return 0; } +static int max77620_set_slew_rate(struct max77620_regulator *pmic, int id, + int slew_rate) +{ + struct max77620_regulator_info *rinfo = pmic->rinfo[id]; + unsigned int val; + int ret; + u8 mask; + + if (rinfo->type == MAX77620_REGULATOR_TYPE_SD) { + if (slew_rate <= 13750) + val = 0; + else if (slew_rate <= 27500) + val = 1; + else if (slew_rate <= 55000) + val = 2; + else + val = 3; + val <<= MAX77620_SD_SR_SHIFT; + mask = MAX77620_SD_SR_MASK; + } else { + if (slew_rate <= 5000) + val = 1; + else + val = 0; + mask = MAX77620_LDO_SLEW_RATE_MASK; + } + + ret = regmap_update_bits(pmic->rmap, rinfo->cfg_addr, mask, val); + if (ret < 0) { + dev_err(pmic->dev, "Regulator %d slew rate set failed: %d\n", + id, ret); + return ret; + } + + return 0; +} + static int max77620_init_pmic(struct max77620_regulator *pmic, int id) { struct max77620_regulator_pdata *rpdata = &pmic->reg_pdata[id]; @@ -351,6 +395,13 @@ static int max77620_init_pmic(struct max77620_regulator *pmic, int id) if (ret < 0) return ret; + if (rpdata->ramp_rate_setting) { + ret = max77620_set_slew_rate(pmic, id, + rpdata->ramp_rate_setting); + if (ret < 0) + return ret; + } + return 0; } @@ -502,35 +553,16 @@ static int max77620_regulator_set_ramp_delay(struct regulator_dev *rdev, { struct max77620_regulator *pmic = rdev_get_drvdata(rdev); int id = rdev_get_id(rdev); - struct max77620_regulator_info *rinfo = pmic->rinfo[id]; - int ret, val; - u8 mask; - - if (rinfo->type == MAX77620_REGULATOR_TYPE_SD) { - if (ramp_delay <= 13750) - val = 0; - else if (ramp_delay <= 27500) - val = 1; - else if (ramp_delay <= 55000) - val = 2; - else - val = 3; - val <<= MAX77620_SD_SR_SHIFT; - mask = MAX77620_SD_SR_MASK; - } else { - if (ramp_delay <= 5000) - val = 1; - else - val = 0; - mask = MAX77620_LDO_SLEW_RATE_MASK; - } + struct max77620_regulator_pdata *rpdata = &pmic->reg_pdata[id]; - ret = regmap_update_bits(pmic->rmap, rinfo->cfg_addr, mask, val); - if (ret < 0) - dev_err(pmic->dev, "Reg 0x%02x update failed: %d\n", - rinfo->cfg_addr, ret); + /* Device specific ramp rate setting tells that platform has + * different ramp rate from advertised value. In this case, + * do not configure anything and just return success. + */ + if (rpdata->ramp_rate_setting) + return 0; - return ret; + return max77620_set_slew_rate(pmic, id, ramp_delay); } static int max77620_of_parse_cb(struct device_node *np, @@ -563,6 +595,9 @@ static int max77620_of_parse_cb(struct device_node *np, np, "maxim,suspend-fps-power-down-slot", &pval); rpdata->suspend_fps_pd_slot = (!ret) ? pval : -1; + ret = of_property_read_u32(np, "maxim,ramp-rate-setting", &pval); + rpdata->ramp_rate_setting = (!ret) ? pval : 0; + return max77620_init_pmic(pmic, desc->id); } @@ -651,7 +686,6 @@ static struct max77620_regulator_info max77620_regs_info[MAX77620_NUM_REGS] = { RAIL_SD(SD1, sd1, "in-sd1", SD1, 600000, 1550000, 12500, 0x22, SD1), RAIL_SD(SD2, sd2, "in-sd2", SDX, 600000, 3787500, 12500, 0xFF, NONE), RAIL_SD(SD3, sd3, "in-sd3", SDX, 600000, 3787500, 12500, 0xFF, NONE), - RAIL_SD(SD4, sd4, "in-sd4", SDX, 600000, 3787500, 12500, 0xFF, NONE), RAIL_LDO(LDO0, ldo0, "in-ldo0-1", N, 800000, 2375000, 25000), RAIL_LDO(LDO1, ldo1, "in-ldo0-1", N, 800000, 2375000, 25000), diff --git a/drivers/regulator/max77686-regulator.c b/drivers/regulator/max77686-regulator.c index 17ccf365a..ac4fa581e 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, \ @@ -553,17 +558,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 "); diff --git a/drivers/regulator/max77693-regulator.c b/drivers/regulator/max77693-regulator.c new file mode 100644 index 000000000..de730fd3f --- /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 de730fd3f..000000000 --- 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/max77802-regulator.c b/drivers/regulator/max77802-regulator.c index c07ee13bd..1d3539324 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/max8973-regulator.c b/drivers/regulator/max8973-regulator.c index 5b75b7c2e..08d2f13ec 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/drivers/regulator/max8997-regulator.c b/drivers/regulator/max8997-regulator.c new file mode 100644 index 000000000..efabc0ea0 --- /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 ea0196d44..000000000 --- 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"); diff --git a/drivers/regulator/of_regulator.c b/drivers/regulator/of_regulator.c index 6b0aa80b2..cd828dbf9 100644 --- a/drivers/regulator/of_regulator.c +++ b/drivers/regulator/of_regulator.c @@ -45,9 +45,9 @@ static void of_get_regulation_constraints(struct device_node *np, /* Voltage change possible? */ if (constraints->min_uV != constraints->max_uV) constraints->valid_ops_mask |= REGULATOR_CHANGE_VOLTAGE; - /* Only one voltage? Then make sure it's set. */ - if (constraints->min_uV && constraints->max_uV && - constraints->min_uV == constraints->max_uV) + + /* Do we have a voltage range, if so try to apply it? */ + if (constraints->min_uV && constraints->max_uV) constraints->apply_uV = true; if (!of_property_read_u32(np, "regulator-microvolt-offset", &pval)) diff --git a/drivers/regulator/palmas-regulator.c b/drivers/regulator/palmas-regulator.c index 6efc7ee8a..f11d41dad 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; @@ -1462,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; @@ -1474,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, @@ -1482,25 +1487,29 @@ 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++) { - if (!ddata->palmas_matches[idx].init_data || - !ddata->palmas_matches[idx].of_node) - continue; + static struct of_regulator_match *match; + struct palmas_reg_init *rinit; + struct device_node *np; - pdata->reg_data[idx] = ddata->palmas_matches[idx].init_data; + match = &ddata->palmas_matches[idx]; + np = match->of_node; - pdata->reg_init[idx] = devm_kzalloc(dev, - sizeof(struct palmas_reg_init), GFP_KERNEL); + if (!match->init_data || !np) + continue; + + rinit = devm_kzalloc(dev, sizeof(*rinit), GFP_KERNEL); + if (!rinit) + return -ENOMEM; - pdata->reg_init[idx]->warm_reset = - of_property_read_bool(ddata->palmas_matches[idx].of_node, - "ti,warm-reset"); + pdata->reg_data[idx] = match->init_data; + pdata->reg_init[idx] = rinit; - ret = of_property_read_u32(ddata->palmas_matches[idx].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; @@ -1522,31 +1531,29 @@ 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; + rinit->roof_floor = econtrol; } - ret = of_property_read_u32(ddata->palmas_matches[idx].of_node, - "ti,mode-sleep", &prop); + ret = of_property_read_u32(np, "ti,mode-sleep", &prop); if (!ret) - pdata->reg_init[idx]->mode_sleep = prop; + rinit->mode_sleep = prop; - ret = of_property_read_bool(ddata->palmas_matches[idx].of_node, - "ti,smps-range"); + ret = of_property_read_bool(np, "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( - ddata->palmas_matches[idx].of_node, - "ti,enable-ldo8-tracking"); + np, "ti,enable-ldo8-tracking"); } pdata->ldo6_vibrator = of_property_read_bool(node, "ti,ldo6-vibrator"); + + return 0; } static const struct of_device_id of_palmas_match_tbl[] = { @@ -1628,7 +1635,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) diff --git a/drivers/regulator/pv88080-regulator.c b/drivers/regulator/pv88080-regulator.c new file mode 100644 index 000000000..d7107566c --- /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 000000000..5e9afde60 --- /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__ */ diff --git a/drivers/regulator/pwm-regulator.c b/drivers/regulator/pwm-regulator.c index 4689d62f4..fafa3488e 100644 --- a/drivers/regulator/pwm-regulator.c +++ b/drivers/regulator/pwm-regulator.c @@ -59,18 +59,18 @@ static int pwm_regulator_set_voltage_sel(struct regulator_dev *rdev, unsigned selector) { struct pwm_regulator_data *drvdata = rdev_get_drvdata(rdev); - unsigned int pwm_reg_period; + struct pwm_args pargs; int dutycycle; int ret; - pwm_reg_period = pwm_get_period(drvdata->pwm); + pwm_get_args(drvdata->pwm, &pargs); - dutycycle = (pwm_reg_period * + dutycycle = (pargs.period * drvdata->duty_cycle_table[selector].dutycycle) / 100; - ret = pwm_config(drvdata->pwm, dutycycle, pwm_reg_period); + ret = pwm_config(drvdata->pwm, dutycycle, pargs.period); if (ret) { - dev_err(&rdev->dev, "Failed to configure PWM\n"); + dev_err(&rdev->dev, "Failed to configure PWM: %d\n", ret); return ret; } @@ -113,18 +113,6 @@ static int pwm_regulator_is_enabled(struct regulator_dev *dev) return pwm_is_enabled(drvdata->pwm); } -/** - * Continuous voltage call-backs - */ -static int pwm_voltage_to_duty_cycle_percentage(struct regulator_dev *rdev, int req_uV) -{ - int min_uV = rdev->constraints->min_uV; - int max_uV = rdev->constraints->max_uV; - int diff = max_uV - min_uV; - - return ((req_uV * 100) - (min_uV * 100)) / diff; -} - static int pwm_regulator_get_voltage(struct regulator_dev *rdev) { struct pwm_regulator_data *drvdata = rdev_get_drvdata(rdev); @@ -138,21 +126,42 @@ static int pwm_regulator_set_voltage(struct regulator_dev *rdev, { struct pwm_regulator_data *drvdata = rdev_get_drvdata(rdev); unsigned int ramp_delay = rdev->constraints->ramp_delay; - unsigned int period = pwm_get_period(drvdata->pwm); - int duty_cycle; + struct pwm_args pargs; + unsigned int req_diff = min_uV - rdev->constraints->min_uV; + unsigned int diff; + unsigned int duty_pulse; + u64 req_period; + u32 rem; int ret; - duty_cycle = pwm_voltage_to_duty_cycle_percentage(rdev, min_uV); + pwm_get_args(drvdata->pwm, &pargs); + diff = rdev->constraints->max_uV - rdev->constraints->min_uV; + + /* First try to find out if we get the iduty cycle time which is + * factor of PWM period time. If (request_diff_to_min * pwm_period) + * is perfect divided by voltage_range_diff then it is possible to + * get duty cycle time which is factor of PWM period. This will help + * to get output voltage nearer to requested value as there is no + * calculation loss. + */ + req_period = req_diff * pargs.period; + div_u64_rem(req_period, diff, &rem); + if (!rem) { + do_div(req_period, diff); + duty_pulse = (unsigned int)req_period; + } else { + duty_pulse = (pargs.period / 100) * ((req_diff * 100) / diff); + } - ret = pwm_config(drvdata->pwm, (period / 100) * duty_cycle, period); + ret = pwm_config(drvdata->pwm, duty_pulse, pargs.period); if (ret) { - dev_err(&rdev->dev, "Failed to configure PWM\n"); + dev_err(&rdev->dev, "Failed to configure PWM: %d\n", ret); return ret; } ret = pwm_enable(drvdata->pwm); if (ret) { - dev_err(&rdev->dev, "Failed to enable PWM\n"); + dev_err(&rdev->dev, "Failed to enable PWM: %d\n", ret); return ret; } drvdata->volt_uV = min_uV; @@ -200,8 +209,7 @@ static int pwm_regulator_init_table(struct platform_device *pdev, if ((length < sizeof(*duty_cycle_table)) || (length % sizeof(*duty_cycle_table))) { - dev_err(&pdev->dev, - "voltage-table length(%d) is invalid\n", + dev_err(&pdev->dev, "voltage-table length(%d) is invalid\n", length); return -EINVAL; } @@ -214,7 +222,7 @@ static int pwm_regulator_init_table(struct platform_device *pdev, (u32 *)duty_cycle_table, length / sizeof(u32)); if (ret) { - dev_err(&pdev->dev, "Failed to read voltage-table\n"); + dev_err(&pdev->dev, "Failed to read voltage-table: %d\n", ret); return ret; } @@ -277,16 +285,24 @@ static int pwm_regulator_probe(struct platform_device *pdev) drvdata->pwm = devm_pwm_get(&pdev->dev, NULL); if (IS_ERR(drvdata->pwm)) { - dev_err(&pdev->dev, "Failed to get PWM\n"); - return PTR_ERR(drvdata->pwm); + ret = PTR_ERR(drvdata->pwm); + dev_err(&pdev->dev, "Failed to get PWM: %d\n", ret); + return ret; } + /* + * FIXME: pwm_apply_args() should be removed when switching to the + * atomic PWM API. + */ + pwm_apply_args(drvdata->pwm); + regulator = devm_regulator_register(&pdev->dev, &drvdata->desc, &config); if (IS_ERR(regulator)) { - dev_err(&pdev->dev, "Failed to register regulator %s\n", - drvdata->desc.name); - return PTR_ERR(regulator); + ret = PTR_ERR(regulator); + dev_err(&pdev->dev, "Failed to register regulator %s: %d\n", + drvdata->desc.name, ret); + return ret; } return 0; diff --git a/drivers/regulator/qcom_spmi-regulator.c b/drivers/regulator/qcom_spmi-regulator.c index 88a5dc88b..84cce21e9 100644 --- a/drivers/regulator/qcom_spmi-regulator.c +++ b/drivers/regulator/qcom_spmi-regulator.c @@ -246,6 +246,7 @@ enum spmi_common_control_register_index { /* Minimum voltage stepper delay for each step. */ #define SPMI_FTSMPS_STEP_DELAY 8 +#define SPMI_DEFAULT_STEP_DELAY 20 /* * The ratio SPMI_FTSMPS_STEP_MARGIN_NUM/SPMI_FTSMPS_STEP_MARGIN_DEN is used to @@ -254,13 +255,6 @@ enum spmi_common_control_register_index { #define SPMI_FTSMPS_STEP_MARGIN_NUM 4 #define SPMI_FTSMPS_STEP_MARGIN_DEN 5 -/* - * This voltage in uV is returned by get_voltage functions when there is no way - * to determine the current voltage level. It is needed because the regulator - * framework treats a 0 uV voltage as an error. - */ -#define VOLTAGE_UNKNOWN 1 - /* VSET value to decide the range of ULT SMPS */ #define ULT_SMPS_RANGE_SPLIT 0x60 @@ -539,12 +533,12 @@ static int spmi_regulator_common_disable(struct regulator_dev *rdev) } static int spmi_regulator_select_voltage(struct spmi_regulator *vreg, - int min_uV, int max_uV, u8 *range_sel, u8 *voltage_sel, - unsigned *selector) + int min_uV, int max_uV) { const struct spmi_voltage_range *range; int uV = min_uV; int lim_min_uV, lim_max_uV, i, range_id, range_max_uV; + int selector, voltage_sel; /* Check if request voltage is outside of physically settable range. */ lim_min_uV = vreg->set_points->range[0].set_point_min_uV; @@ -570,14 +564,13 @@ static int spmi_regulator_select_voltage(struct spmi_regulator *vreg, range_id = i; range = &vreg->set_points->range[range_id]; - *range_sel = range->range_sel; /* * Force uV to be an allowed set point by applying a ceiling function to * the uV value. */ - *voltage_sel = DIV_ROUND_UP(uV - range->min_uV, range->step_uV); - uV = *voltage_sel * range->step_uV + range->min_uV; + voltage_sel = DIV_ROUND_UP(uV - range->min_uV, range->step_uV); + uV = voltage_sel * range->step_uV + range->min_uV; if (uV > max_uV) { dev_err(vreg->dev, @@ -587,12 +580,48 @@ static int spmi_regulator_select_voltage(struct spmi_regulator *vreg, return -EINVAL; } - *selector = 0; + selector = 0; for (i = 0; i < range_id; i++) - *selector += vreg->set_points->range[i].n_voltages; - *selector += (uV - range->set_point_min_uV) / range->step_uV; + selector += vreg->set_points->range[i].n_voltages; + selector += (uV - range->set_point_min_uV) / range->step_uV; - return 0; + return selector; +} + +static int spmi_sw_selector_to_hw(struct spmi_regulator *vreg, + unsigned selector, u8 *range_sel, + u8 *voltage_sel) +{ + const struct spmi_voltage_range *range, *end; + + range = vreg->set_points->range; + end = range + vreg->set_points->count; + + for (; range < end; range++) { + if (selector < range->n_voltages) { + *voltage_sel = selector; + *range_sel = range->range_sel; + return 0; + } + + selector -= range->n_voltages; + } + + return -EINVAL; +} + +static int spmi_hw_selector_to_sw(struct spmi_regulator *vreg, u8 hw_sel, + const struct spmi_voltage_range *range) +{ + int sw_sel = hw_sel; + const struct spmi_voltage_range *r = vreg->set_points->range; + + while (r != range) { + sw_sel += r->n_voltages; + r++; + } + + return sw_sel; } static const struct spmi_voltage_range * @@ -614,12 +643,11 @@ spmi_regulator_find_range(struct spmi_regulator *vreg) } static int spmi_regulator_select_voltage_same_range(struct spmi_regulator *vreg, - int min_uV, int max_uV, u8 *range_sel, u8 *voltage_sel, - unsigned *selector) + int min_uV, int max_uV) { const struct spmi_voltage_range *range; int uV = min_uV; - int i; + int i, selector; range = spmi_regulator_find_range(vreg); if (!range) @@ -637,8 +665,8 @@ static int spmi_regulator_select_voltage_same_range(struct spmi_regulator *vreg, * Force uV to be an allowed set point by applying a ceiling function to * the uV value. */ - *voltage_sel = DIV_ROUND_UP(uV - range->min_uV, range->step_uV); - uV = *voltage_sel * range->step_uV + range->min_uV; + uV = DIV_ROUND_UP(uV - range->min_uV, range->step_uV); + uV = uV * range->step_uV + range->min_uV; if (uV > max_uV) { /* @@ -648,43 +676,49 @@ static int spmi_regulator_select_voltage_same_range(struct spmi_regulator *vreg, goto different_range; } - *selector = 0; + selector = 0; for (i = 0; i < vreg->set_points->count; i++) { if (uV >= vreg->set_points->range[i].set_point_min_uV && uV <= vreg->set_points->range[i].set_point_max_uV) { - *selector += + selector += (uV - vreg->set_points->range[i].set_point_min_uV) / vreg->set_points->range[i].step_uV; break; } - *selector += vreg->set_points->range[i].n_voltages; + selector += vreg->set_points->range[i].n_voltages; } - if (*selector >= vreg->set_points->n_voltages) + if (selector >= vreg->set_points->n_voltages) goto different_range; - return 0; + return selector; different_range: - return spmi_regulator_select_voltage(vreg, min_uV, max_uV, - range_sel, voltage_sel, selector); + return spmi_regulator_select_voltage(vreg, min_uV, max_uV); } -static int spmi_regulator_common_set_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV, unsigned *selector) +static int spmi_regulator_common_map_voltage(struct regulator_dev *rdev, + int min_uV, int max_uV) { struct spmi_regulator *vreg = rdev_get_drvdata(rdev); - int ret; - u8 buf[2]; - u8 range_sel, voltage_sel; /* * Favor staying in the current voltage range if possible. This avoids * voltage spikes that occur when changing the voltage range. */ - ret = spmi_regulator_select_voltage_same_range(vreg, min_uV, max_uV, - &range_sel, &voltage_sel, selector); + return spmi_regulator_select_voltage_same_range(vreg, min_uV, max_uV); +} + +static int +spmi_regulator_common_set_voltage(struct regulator_dev *rdev, unsigned selector) +{ + struct spmi_regulator *vreg = rdev_get_drvdata(rdev); + int ret; + u8 buf[2]; + u8 range_sel, voltage_sel; + + ret = spmi_sw_selector_to_hw(vreg, selector, &range_sel, &voltage_sel); if (ret) return ret; @@ -719,24 +753,24 @@ static int spmi_regulator_common_get_voltage(struct regulator_dev *rdev) range = spmi_regulator_find_range(vreg); if (!range) - return VOLTAGE_UNKNOWN; + return -EINVAL; - return range->step_uV * voltage_sel + range->min_uV; + return spmi_hw_selector_to_sw(vreg, voltage_sel, range); } -static int spmi_regulator_single_range_set_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV, unsigned *selector) +static int spmi_regulator_single_map_voltage(struct regulator_dev *rdev, + int min_uV, int max_uV) { struct spmi_regulator *vreg = rdev_get_drvdata(rdev); - int ret; - u8 range_sel, sel; - ret = spmi_regulator_select_voltage(vreg, min_uV, max_uV, &range_sel, - &sel, selector); - if (ret) { - dev_err(vreg->dev, "could not set voltage, ret=%d\n", ret); - return ret; - } + return spmi_regulator_select_voltage(vreg, min_uV, max_uV); +} + +static int spmi_regulator_single_range_set_voltage(struct regulator_dev *rdev, + unsigned selector) +{ + struct spmi_regulator *vreg = rdev_get_drvdata(rdev); + u8 sel = selector; /* * Certain types of regulators do not have a range select register so @@ -748,27 +782,24 @@ static int spmi_regulator_single_range_set_voltage(struct regulator_dev *rdev, static int spmi_regulator_single_range_get_voltage(struct regulator_dev *rdev) { struct spmi_regulator *vreg = rdev_get_drvdata(rdev); - const struct spmi_voltage_range *range = vreg->set_points->range; - u8 voltage_sel; + u8 selector; + int ret; - spmi_vreg_read(vreg, SPMI_COMMON_REG_VOLTAGE_SET, &voltage_sel, 1); + ret = spmi_vreg_read(vreg, SPMI_COMMON_REG_VOLTAGE_SET, &selector, 1); + if (ret) + return ret; - return range->step_uV * voltage_sel + range->min_uV; + return selector; } static int spmi_regulator_ult_lo_smps_set_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV, unsigned *selector) + unsigned selector) { struct spmi_regulator *vreg = rdev_get_drvdata(rdev); int ret; u8 range_sel, voltage_sel; - /* - * Favor staying in the current voltage range if possible. This avoids - * voltage spikes that occur when changing the voltage range. - */ - ret = spmi_regulator_select_voltage_same_range(vreg, min_uV, max_uV, - &range_sel, &voltage_sel, selector); + ret = spmi_sw_selector_to_hw(vreg, selector, &range_sel, &voltage_sel); if (ret) return ret; @@ -783,7 +814,7 @@ static int spmi_regulator_ult_lo_smps_set_voltage(struct regulator_dev *rdev, voltage_sel |= ULT_SMPS_RANGE_SPLIT; return spmi_vreg_update_bits(vreg, SPMI_COMMON_REG_VOLTAGE_SET, - voltage_sel, 0xff); + voltage_sel, 0xff); } static int spmi_regulator_ult_lo_smps_get_voltage(struct regulator_dev *rdev) @@ -796,12 +827,12 @@ static int spmi_regulator_ult_lo_smps_get_voltage(struct regulator_dev *rdev) range = spmi_regulator_find_range(vreg); if (!range) - return VOLTAGE_UNKNOWN; + return -EINVAL; if (range->range_sel == 1) voltage_sel &= ~ULT_SMPS_RANGE_SPLIT; - return range->step_uV * voltage_sel + range->min_uV; + return spmi_hw_selector_to_sw(vreg, voltage_sel, range); } static int spmi_regulator_common_list_voltage(struct regulator_dev *rdev, @@ -1007,8 +1038,10 @@ static struct regulator_ops spmi_smps_ops = { .enable = spmi_regulator_common_enable, .disable = spmi_regulator_common_disable, .is_enabled = spmi_regulator_common_is_enabled, - .set_voltage = spmi_regulator_common_set_voltage, - .get_voltage = spmi_regulator_common_get_voltage, + .set_voltage_sel = spmi_regulator_common_set_voltage, + .set_voltage_time_sel = spmi_regulator_set_voltage_time_sel, + .get_voltage_sel = spmi_regulator_common_get_voltage, + .map_voltage = spmi_regulator_common_map_voltage, .list_voltage = spmi_regulator_common_list_voltage, .set_mode = spmi_regulator_common_set_mode, .get_mode = spmi_regulator_common_get_mode, @@ -1020,8 +1053,9 @@ static struct regulator_ops spmi_ldo_ops = { .enable = spmi_regulator_common_enable, .disable = spmi_regulator_common_disable, .is_enabled = spmi_regulator_common_is_enabled, - .set_voltage = spmi_regulator_common_set_voltage, - .get_voltage = spmi_regulator_common_get_voltage, + .set_voltage_sel = spmi_regulator_common_set_voltage, + .get_voltage_sel = spmi_regulator_common_get_voltage, + .map_voltage = spmi_regulator_common_map_voltage, .list_voltage = spmi_regulator_common_list_voltage, .set_mode = spmi_regulator_common_set_mode, .get_mode = spmi_regulator_common_get_mode, @@ -1036,8 +1070,9 @@ static struct regulator_ops spmi_ln_ldo_ops = { .enable = spmi_regulator_common_enable, .disable = spmi_regulator_common_disable, .is_enabled = spmi_regulator_common_is_enabled, - .set_voltage = spmi_regulator_common_set_voltage, - .get_voltage = spmi_regulator_common_get_voltage, + .set_voltage_sel = spmi_regulator_common_set_voltage, + .get_voltage_sel = spmi_regulator_common_get_voltage, + .map_voltage = spmi_regulator_common_map_voltage, .list_voltage = spmi_regulator_common_list_voltage, .set_bypass = spmi_regulator_common_set_bypass, .get_bypass = spmi_regulator_common_get_bypass, @@ -1056,8 +1091,9 @@ static struct regulator_ops spmi_boost_ops = { .enable = spmi_regulator_common_enable, .disable = spmi_regulator_common_disable, .is_enabled = spmi_regulator_common_is_enabled, - .set_voltage = spmi_regulator_single_range_set_voltage, - .get_voltage = spmi_regulator_single_range_get_voltage, + .set_voltage_sel = spmi_regulator_single_range_set_voltage, + .get_voltage_sel = spmi_regulator_single_range_get_voltage, + .map_voltage = spmi_regulator_single_map_voltage, .list_voltage = spmi_regulator_common_list_voltage, .set_input_current_limit = spmi_regulator_set_ilim, }; @@ -1066,9 +1102,10 @@ static struct regulator_ops spmi_ftsmps_ops = { .enable = spmi_regulator_common_enable, .disable = spmi_regulator_common_disable, .is_enabled = spmi_regulator_common_is_enabled, - .set_voltage = spmi_regulator_common_set_voltage, + .set_voltage_sel = spmi_regulator_common_set_voltage, .set_voltage_time_sel = spmi_regulator_set_voltage_time_sel, - .get_voltage = spmi_regulator_common_get_voltage, + .get_voltage_sel = spmi_regulator_common_get_voltage, + .map_voltage = spmi_regulator_common_map_voltage, .list_voltage = spmi_regulator_common_list_voltage, .set_mode = spmi_regulator_common_set_mode, .get_mode = spmi_regulator_common_get_mode, @@ -1080,8 +1117,9 @@ static struct regulator_ops spmi_ult_lo_smps_ops = { .enable = spmi_regulator_common_enable, .disable = spmi_regulator_common_disable, .is_enabled = spmi_regulator_common_is_enabled, - .set_voltage = spmi_regulator_ult_lo_smps_set_voltage, - .get_voltage = spmi_regulator_ult_lo_smps_get_voltage, + .set_voltage_sel = spmi_regulator_ult_lo_smps_set_voltage, + .set_voltage_time_sel = spmi_regulator_set_voltage_time_sel, + .get_voltage_sel = spmi_regulator_ult_lo_smps_get_voltage, .list_voltage = spmi_regulator_common_list_voltage, .set_mode = spmi_regulator_common_set_mode, .get_mode = spmi_regulator_common_get_mode, @@ -1093,8 +1131,10 @@ static struct regulator_ops spmi_ult_ho_smps_ops = { .enable = spmi_regulator_common_enable, .disable = spmi_regulator_common_disable, .is_enabled = spmi_regulator_common_is_enabled, - .set_voltage = spmi_regulator_single_range_set_voltage, - .get_voltage = spmi_regulator_single_range_get_voltage, + .set_voltage_sel = spmi_regulator_single_range_set_voltage, + .set_voltage_time_sel = spmi_regulator_set_voltage_time_sel, + .get_voltage_sel = spmi_regulator_single_range_get_voltage, + .map_voltage = spmi_regulator_single_map_voltage, .list_voltage = spmi_regulator_common_list_voltage, .set_mode = spmi_regulator_common_set_mode, .get_mode = spmi_regulator_common_get_mode, @@ -1106,8 +1146,9 @@ static struct regulator_ops spmi_ult_ldo_ops = { .enable = spmi_regulator_common_enable, .disable = spmi_regulator_common_disable, .is_enabled = spmi_regulator_common_is_enabled, - .set_voltage = spmi_regulator_single_range_set_voltage, - .get_voltage = spmi_regulator_single_range_get_voltage, + .set_voltage_sel = spmi_regulator_single_range_set_voltage, + .get_voltage_sel = spmi_regulator_single_range_get_voltage, + .map_voltage = spmi_regulator_single_map_voltage, .list_voltage = spmi_regulator_common_list_voltage, .set_mode = spmi_regulator_common_set_mode, .get_mode = spmi_regulator_common_get_mode, @@ -1201,7 +1242,7 @@ static int spmi_regulator_match(struct spmi_regulator *vreg, u16 force_type) ret = spmi_vreg_read(vreg, SPMI_COMMON_REG_DIG_MAJOR_REV, version, ARRAY_SIZE(version)); if (ret) { - dev_err(vreg->dev, "could not read version registers\n"); + dev_dbg(vreg->dev, "could not read version registers\n"); return ret; } dig_major_rev = version[SPMI_COMMON_REG_DIG_MAJOR_REV @@ -1245,11 +1286,11 @@ found: return 0; } -static int spmi_regulator_ftsmps_init_slew_rate(struct spmi_regulator *vreg) +static int spmi_regulator_init_slew_rate(struct spmi_regulator *vreg) { int ret; u8 reg = 0; - int step, delay, slew_rate; + int step, delay, slew_rate, step_delay; const struct spmi_voltage_range *range; ret = spmi_vreg_read(vreg, SPMI_COMMON_REG_STEP_CTRL, ®, 1); @@ -1262,6 +1303,15 @@ static int spmi_regulator_ftsmps_init_slew_rate(struct spmi_regulator *vreg) if (!range) return -EINVAL; + switch (vreg->logical_type) { + case SPMI_REGULATOR_LOGICAL_TYPE_FTSMPS: + step_delay = SPMI_FTSMPS_STEP_DELAY; + break; + default: + step_delay = SPMI_DEFAULT_STEP_DELAY; + break; + } + step = reg & SPMI_FTSMPS_STEP_CTRL_STEP_MASK; step >>= SPMI_FTSMPS_STEP_CTRL_STEP_SHIFT; @@ -1270,7 +1320,7 @@ static int spmi_regulator_ftsmps_init_slew_rate(struct spmi_regulator *vreg) /* slew_rate has units of uV/us */ slew_rate = SPMI_FTSMPS_CLOCK_RATE * range->step_uV * (1 << step); - slew_rate /= 1000 * (SPMI_FTSMPS_STEP_DELAY << delay); + slew_rate /= 1000 * (step_delay << delay); slew_rate *= SPMI_FTSMPS_STEP_MARGIN_NUM; slew_rate /= SPMI_FTSMPS_STEP_MARGIN_DEN; @@ -1411,10 +1461,16 @@ static int spmi_regulator_of_parse(struct device_node *node, return ret; } - if (vreg->logical_type == SPMI_REGULATOR_LOGICAL_TYPE_FTSMPS) { - ret = spmi_regulator_ftsmps_init_slew_rate(vreg); + switch (vreg->logical_type) { + case SPMI_REGULATOR_LOGICAL_TYPE_FTSMPS: + case SPMI_REGULATOR_LOGICAL_TYPE_ULT_LO_SMPS: + case SPMI_REGULATOR_LOGICAL_TYPE_ULT_HO_SMPS: + case SPMI_REGULATOR_LOGICAL_TYPE_SMPS: + ret = spmi_regulator_init_slew_rate(vreg); if (ret) return ret; + default: + break; } if (vreg->logical_type != SPMI_REGULATOR_LOGICAL_TYPE_VS) @@ -1510,10 +1566,61 @@ static const struct spmi_regulator_data pm8916_regulators[] = { { } }; +static const struct spmi_regulator_data pm8994_regulators[] = { + { "s1", 0x1400, "vdd_s1", }, + { "s2", 0x1700, "vdd_s2", }, + { "s3", 0x1a00, "vdd_s3", }, + { "s4", 0x1d00, "vdd_s4", }, + { "s5", 0x2000, "vdd_s5", }, + { "s6", 0x2300, "vdd_s6", }, + { "s7", 0x2600, "vdd_s7", }, + { "s8", 0x2900, "vdd_s8", }, + { "s9", 0x2c00, "vdd_s9", }, + { "s10", 0x2f00, "vdd_s10", }, + { "s11", 0x3200, "vdd_s11", }, + { "s12", 0x3500, "vdd_s12", }, + { "l1", 0x4000, "vdd_l1", }, + { "l2", 0x4100, "vdd_l2_l26_l28", }, + { "l3", 0x4200, "vdd_l3_l11", }, + { "l4", 0x4300, "vdd_l4_l27_l31", }, + { "l5", 0x4400, "vdd_l5_l7", }, + { "l6", 0x4500, "vdd_l6_l12_l32", }, + { "l7", 0x4600, "vdd_l5_l7", }, + { "l8", 0x4700, "vdd_l8_l16_l30", }, + { "l9", 0x4800, "vdd_l9_l10_l18_l22", }, + { "l10", 0x4900, "vdd_l9_l10_l18_l22", }, + { "l11", 0x4a00, "vdd_l3_l11", }, + { "l12", 0x4b00, "vdd_l6_l12_l32", }, + { "l13", 0x4c00, "vdd_l13_l19_l23_l24", }, + { "l14", 0x4d00, "vdd_l14_l15", }, + { "l15", 0x4e00, "vdd_l14_l15", }, + { "l16", 0x4f00, "vdd_l8_l16_l30", }, + { "l17", 0x5000, "vdd_l17_l29", }, + { "l18", 0x5100, "vdd_l9_l10_l18_l22", }, + { "l19", 0x5200, "vdd_l13_l19_l23_l24", }, + { "l20", 0x5300, "vdd_l20_l21", }, + { "l21", 0x5400, "vdd_l20_l21", }, + { "l22", 0x5500, "vdd_l9_l10_l18_l22", }, + { "l23", 0x5600, "vdd_l13_l19_l23_l24", }, + { "l24", 0x5700, "vdd_l13_l19_l23_l24", }, + { "l25", 0x5800, "vdd_l25", }, + { "l26", 0x5900, "vdd_l2_l26_l28", }, + { "l27", 0x5a00, "vdd_l4_l27_l31", }, + { "l28", 0x5b00, "vdd_l2_l26_l28", }, + { "l29", 0x5c00, "vdd_l17_l29", }, + { "l30", 0x5d00, "vdd_l8_l16_l30", }, + { "l31", 0x5e00, "vdd_l4_l27_l31", }, + { "l32", 0x5f00, "vdd_l6_l12_l32", }, + { "lvs1", 0x8000, "vdd_lvs_1_2", }, + { "lvs2", 0x8100, "vdd_lvs_1_2", }, + { } +}; + static const struct of_device_id qcom_spmi_regulator_match[] = { { .compatible = "qcom,pm8841-regulators", .data = &pm8841_regulators }, { .compatible = "qcom,pm8916-regulators", .data = &pm8916_regulators }, { .compatible = "qcom,pm8941-regulators", .data = &pm8941_regulators }, + { .compatible = "qcom,pm8994-regulators", .data = &pm8994_regulators }, { } }; MODULE_DEVICE_TABLE(of, qcom_spmi_regulator_match); @@ -1573,7 +1680,7 @@ static int qcom_spmi_regulator_probe(struct platform_device *pdev) ret = spmi_regulator_match(vreg, reg->force_type); if (ret) - goto err; + continue; config.dev = dev; config.driver_data = vreg; diff --git a/drivers/regulator/rk808-regulator.c b/drivers/regulator/rk808-regulator.c index d86a3dcd6..40d07ba03 100644 --- a/drivers/regulator/rk808-regulator.c +++ b/drivers/regulator/rk808-regulator.c @@ -55,6 +55,42 @@ /* max steps for increase voltage of Buck1/2, equal 100mv*/ #define MAX_STEPS_ONE_TIME 8 +#define RK8XX_DESC(_id, _match, _supply, _min, _max, _step, _vreg, \ + _vmask, _ereg, _emask, _etime) \ + [_id] = { \ + .name = (_match), \ + .supply_name = (_supply), \ + .of_match = of_match_ptr(_match), \ + .regulators_node = of_match_ptr("regulators"), \ + .type = REGULATOR_VOLTAGE, \ + .id = (_id), \ + .n_voltages = (((_max) - (_min)) / (_step) + 1), \ + .owner = THIS_MODULE, \ + .min_uV = (_min) * 1000, \ + .uV_step = (_step) * 1000, \ + .vsel_reg = (_vreg), \ + .vsel_mask = (_vmask), \ + .enable_reg = (_ereg), \ + .enable_mask = (_emask), \ + .enable_time = (_etime), \ + .ops = &rk808_reg_ops, \ + } + +#define RK8XX_DESC_SWITCH(_id, _match, _supply, _ereg, _emask) \ + [_id] = { \ + .name = (_match), \ + .supply_name = (_supply), \ + .of_match = of_match_ptr(_match), \ + .regulators_node = of_match_ptr("regulators"), \ + .type = REGULATOR_VOLTAGE, \ + .id = (_id), \ + .enable_reg = (_ereg), \ + .enable_mask = (_emask), \ + .owner = THIS_MODULE, \ + .ops = &rk808_switch_ops \ + } + + struct rk808_regulator_data { struct gpio_desc *dvs_gpio[2]; }; @@ -66,27 +102,11 @@ static const int rk808_buck_config_regs[] = { RK808_BUCK4_CONFIG_REG, }; -static const struct regulator_linear_range rk808_buck_voltage_ranges[] = { - REGULATOR_LINEAR_RANGE(712500, 0, 63, 12500), -}; - -static const struct regulator_linear_range rk808_buck4_voltage_ranges[] = { - REGULATOR_LINEAR_RANGE(1800000, 0, 15, 100000), -}; - -static const struct regulator_linear_range rk808_ldo_voltage_ranges[] = { - REGULATOR_LINEAR_RANGE(1800000, 0, 16, 100000), -}; - static const struct regulator_linear_range rk808_ldo3_voltage_ranges[] = { REGULATOR_LINEAR_RANGE(800000, 0, 13, 100000), REGULATOR_LINEAR_RANGE(2500000, 15, 15, 0), }; -static const struct regulator_linear_range rk808_ldo6_voltage_ranges[] = { - REGULATOR_LINEAR_RANGE(800000, 0, 17, 100000), -}; - static int rk808_buck1_2_get_voltage_sel_regmap(struct regulator_dev *rdev) { struct rk808_regulator_data *pdata = rdev_get_drvdata(rdev); @@ -240,6 +260,21 @@ static int rk808_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay) } static int rk808_set_suspend_voltage(struct regulator_dev *rdev, int uv) +{ + unsigned int reg; + int sel = regulator_map_voltage_linear(rdev, uv, uv); + + if (sel < 0) + return -EINVAL; + + reg = rdev->desc->vsel_reg + RK808_SLP_REG_OFFSET; + + return regmap_update_bits(rdev->regmap, reg, + rdev->desc->vsel_mask, + sel); +} + +static int rk808_set_suspend_voltage_range(struct regulator_dev *rdev, int uv) { unsigned int reg; int sel = regulator_map_voltage_linear_range(rdev, uv, uv); @@ -277,8 +312,8 @@ static int rk808_set_suspend_disable(struct regulator_dev *rdev) } static struct regulator_ops rk808_buck1_2_ops = { - .list_voltage = regulator_list_voltage_linear_range, - .map_voltage = regulator_map_voltage_linear_range, + .list_voltage = regulator_list_voltage_linear, + .map_voltage = regulator_map_voltage_linear, .get_voltage_sel = rk808_buck1_2_get_voltage_sel_regmap, .set_voltage_sel = rk808_buck1_2_set_voltage_sel, .set_voltage_time_sel = rk808_buck1_2_set_voltage_time_sel, @@ -292,6 +327,19 @@ static struct regulator_ops rk808_buck1_2_ops = { }; static struct regulator_ops rk808_reg_ops = { + .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, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .set_suspend_voltage = rk808_set_suspend_voltage, + .set_suspend_enable = rk808_set_suspend_enable, + .set_suspend_disable = rk808_set_suspend_disable, +}; + +static struct regulator_ops rk808_reg_ops_ranges = { .list_voltage = regulator_list_voltage_linear_range, .map_voltage = regulator_map_voltage_linear_range, .get_voltage_sel = regulator_get_voltage_sel_regmap, @@ -299,7 +347,7 @@ static struct regulator_ops rk808_reg_ops = { .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, .is_enabled = regulator_is_enabled_regmap, - .set_suspend_voltage = rk808_set_suspend_voltage, + .set_suspend_voltage = rk808_set_suspend_voltage_range, .set_suspend_enable = rk808_set_suspend_enable, .set_suspend_disable = rk808_set_suspend_disable, }; @@ -316,12 +364,14 @@ static const struct regulator_desc rk808_reg[] = { { .name = "DCDC_REG1", .supply_name = "vcc1", + .of_match = of_match_ptr("DCDC_REG1"), + .regulators_node = of_match_ptr("regulators"), .id = RK808_ID_DCDC1, .ops = &rk808_buck1_2_ops, .type = REGULATOR_VOLTAGE, + .min_uV = 712500, + .uV_step = 12500, .n_voltages = 64, - .linear_ranges = rk808_buck_voltage_ranges, - .n_linear_ranges = ARRAY_SIZE(rk808_buck_voltage_ranges), .vsel_reg = RK808_BUCK1_ON_VSEL_REG, .vsel_mask = RK808_BUCK_VSEL_MASK, .enable_reg = RK808_DCDC_EN_REG, @@ -330,12 +380,14 @@ static const struct regulator_desc rk808_reg[] = { }, { .name = "DCDC_REG2", .supply_name = "vcc2", + .of_match = of_match_ptr("DCDC_REG2"), + .regulators_node = of_match_ptr("regulators"), .id = RK808_ID_DCDC2, .ops = &rk808_buck1_2_ops, .type = REGULATOR_VOLTAGE, + .min_uV = 712500, + .uV_step = 12500, .n_voltages = 64, - .linear_ranges = rk808_buck_voltage_ranges, - .n_linear_ranges = ARRAY_SIZE(rk808_buck_voltage_ranges), .vsel_reg = RK808_BUCK2_ON_VSEL_REG, .vsel_mask = RK808_BUCK_VSEL_MASK, .enable_reg = RK808_DCDC_EN_REG, @@ -344,6 +396,8 @@ static const struct regulator_desc rk808_reg[] = { }, { .name = "DCDC_REG3", .supply_name = "vcc3", + .of_match = of_match_ptr("DCDC_REG3"), + .regulators_node = of_match_ptr("regulators"), .id = RK808_ID_DCDC3, .ops = &rk808_switch_ops, .type = REGULATOR_VOLTAGE, @@ -351,55 +405,23 @@ static const struct regulator_desc rk808_reg[] = { .enable_reg = RK808_DCDC_EN_REG, .enable_mask = BIT(2), .owner = THIS_MODULE, - }, { - .name = "DCDC_REG4", - .supply_name = "vcc4", - .id = RK808_ID_DCDC4, - .ops = &rk808_reg_ops, - .type = REGULATOR_VOLTAGE, - .n_voltages = 16, - .linear_ranges = rk808_buck4_voltage_ranges, - .n_linear_ranges = ARRAY_SIZE(rk808_buck4_voltage_ranges), - .vsel_reg = RK808_BUCK4_ON_VSEL_REG, - .vsel_mask = RK808_BUCK4_VSEL_MASK, - .enable_reg = RK808_DCDC_EN_REG, - .enable_mask = BIT(3), - .owner = THIS_MODULE, - }, { - .name = "LDO_REG1", - .supply_name = "vcc6", - .id = RK808_ID_LDO1, - .ops = &rk808_reg_ops, - .type = REGULATOR_VOLTAGE, - .n_voltages = 17, - .linear_ranges = rk808_ldo_voltage_ranges, - .n_linear_ranges = ARRAY_SIZE(rk808_ldo_voltage_ranges), - .vsel_reg = RK808_LDO1_ON_VSEL_REG, - .vsel_mask = RK808_LDO_VSEL_MASK, - .enable_reg = RK808_LDO_EN_REG, - .enable_mask = BIT(0), - .enable_time = 400, - .owner = THIS_MODULE, - }, { - .name = "LDO_REG2", - .supply_name = "vcc6", - .id = RK808_ID_LDO2, - .ops = &rk808_reg_ops, - .type = REGULATOR_VOLTAGE, - .n_voltages = 17, - .linear_ranges = rk808_ldo_voltage_ranges, - .n_linear_ranges = ARRAY_SIZE(rk808_ldo_voltage_ranges), - .vsel_reg = RK808_LDO2_ON_VSEL_REG, - .vsel_mask = RK808_LDO_VSEL_MASK, - .enable_reg = RK808_LDO_EN_REG, - .enable_mask = BIT(1), - .enable_time = 400, - .owner = THIS_MODULE, - }, { + }, + RK8XX_DESC(RK808_ID_DCDC4, "DCDC_REG4", "vcc4", 1800, 3300, 100, + RK808_BUCK4_ON_VSEL_REG, RK808_BUCK4_VSEL_MASK, + RK808_DCDC_EN_REG, BIT(3), 0), + RK8XX_DESC(RK808_ID_LDO1, "LDO_REG1", "vcc6", 1800, 3400, 100, + RK808_LDO1_ON_VSEL_REG, RK808_LDO_VSEL_MASK, RK808_LDO_EN_REG, + BIT(0), 400), + RK8XX_DESC(RK808_ID_LDO2, "LDO_REG2", "vcc6", 1800, 3400, 100, + RK808_LDO2_ON_VSEL_REG, RK808_LDO_VSEL_MASK, RK808_LDO_EN_REG, + BIT(1), 400), + { .name = "LDO_REG3", .supply_name = "vcc7", + .of_match = of_match_ptr("LDO_REG3"), + .regulators_node = of_match_ptr("regulators"), .id = RK808_ID_LDO3, - .ops = &rk808_reg_ops, + .ops = &rk808_reg_ops_ranges, .type = REGULATOR_VOLTAGE, .n_voltages = 16, .linear_ranges = rk808_ldo3_voltage_ranges, @@ -410,117 +432,26 @@ static const struct regulator_desc rk808_reg[] = { .enable_mask = BIT(2), .enable_time = 400, .owner = THIS_MODULE, - }, { - .name = "LDO_REG4", - .supply_name = "vcc9", - .id = RK808_ID_LDO4, - .ops = &rk808_reg_ops, - .type = REGULATOR_VOLTAGE, - .n_voltages = 17, - .linear_ranges = rk808_ldo_voltage_ranges, - .n_linear_ranges = ARRAY_SIZE(rk808_ldo_voltage_ranges), - .vsel_reg = RK808_LDO4_ON_VSEL_REG, - .vsel_mask = RK808_LDO_VSEL_MASK, - .enable_reg = RK808_LDO_EN_REG, - .enable_mask = BIT(3), - .enable_time = 400, - .owner = THIS_MODULE, - }, { - .name = "LDO_REG5", - .supply_name = "vcc9", - .id = RK808_ID_LDO5, - .ops = &rk808_reg_ops, - .type = REGULATOR_VOLTAGE, - .n_voltages = 17, - .linear_ranges = rk808_ldo_voltage_ranges, - .n_linear_ranges = ARRAY_SIZE(rk808_ldo_voltage_ranges), - .vsel_reg = RK808_LDO5_ON_VSEL_REG, - .vsel_mask = RK808_LDO_VSEL_MASK, - .enable_reg = RK808_LDO_EN_REG, - .enable_mask = BIT(4), - .enable_time = 400, - .owner = THIS_MODULE, - }, { - .name = "LDO_REG6", - .supply_name = "vcc10", - .id = RK808_ID_LDO6, - .ops = &rk808_reg_ops, - .type = REGULATOR_VOLTAGE, - .n_voltages = 18, - .linear_ranges = rk808_ldo6_voltage_ranges, - .n_linear_ranges = ARRAY_SIZE(rk808_ldo6_voltage_ranges), - .vsel_reg = RK808_LDO6_ON_VSEL_REG, - .vsel_mask = RK808_LDO_VSEL_MASK, - .enable_reg = RK808_LDO_EN_REG, - .enable_mask = BIT(5), - .enable_time = 400, - .owner = THIS_MODULE, - }, { - .name = "LDO_REG7", - .supply_name = "vcc7", - .id = RK808_ID_LDO7, - .ops = &rk808_reg_ops, - .type = REGULATOR_VOLTAGE, - .n_voltages = 18, - .linear_ranges = rk808_ldo6_voltage_ranges, - .n_linear_ranges = ARRAY_SIZE(rk808_ldo6_voltage_ranges), - .vsel_reg = RK808_LDO7_ON_VSEL_REG, - .vsel_mask = RK808_LDO_VSEL_MASK, - .enable_reg = RK808_LDO_EN_REG, - .enable_mask = BIT(6), - .enable_time = 400, - .owner = THIS_MODULE, - }, { - .name = "LDO_REG8", - .supply_name = "vcc11", - .id = RK808_ID_LDO8, - .ops = &rk808_reg_ops, - .type = REGULATOR_VOLTAGE, - .n_voltages = 17, - .linear_ranges = rk808_ldo_voltage_ranges, - .n_linear_ranges = ARRAY_SIZE(rk808_ldo_voltage_ranges), - .vsel_reg = RK808_LDO8_ON_VSEL_REG, - .vsel_mask = RK808_LDO_VSEL_MASK, - .enable_reg = RK808_LDO_EN_REG, - .enable_mask = BIT(7), - .enable_time = 400, - .owner = THIS_MODULE, - }, { - .name = "SWITCH_REG1", - .supply_name = "vcc8", - .id = RK808_ID_SWITCH1, - .ops = &rk808_switch_ops, - .type = REGULATOR_VOLTAGE, - .enable_reg = RK808_DCDC_EN_REG, - .enable_mask = BIT(5), - .owner = THIS_MODULE, - }, { - .name = "SWITCH_REG2", - .supply_name = "vcc12", - .id = RK808_ID_SWITCH2, - .ops = &rk808_switch_ops, - .type = REGULATOR_VOLTAGE, - .enable_reg = RK808_DCDC_EN_REG, - .enable_mask = BIT(6), - .owner = THIS_MODULE, }, -}; - -static struct of_regulator_match rk808_reg_matches[] = { - [RK808_ID_DCDC1] = { .name = "DCDC_REG1" }, - [RK808_ID_DCDC2] = { .name = "DCDC_REG2" }, - [RK808_ID_DCDC3] = { .name = "DCDC_REG3" }, - [RK808_ID_DCDC4] = { .name = "DCDC_REG4" }, - [RK808_ID_LDO1] = { .name = "LDO_REG1" }, - [RK808_ID_LDO2] = { .name = "LDO_REG2" }, - [RK808_ID_LDO3] = { .name = "LDO_REG3" }, - [RK808_ID_LDO4] = { .name = "LDO_REG4" }, - [RK808_ID_LDO5] = { .name = "LDO_REG5" }, - [RK808_ID_LDO6] = { .name = "LDO_REG6" }, - [RK808_ID_LDO7] = { .name = "LDO_REG7" }, - [RK808_ID_LDO8] = { .name = "LDO_REG8" }, - [RK808_ID_SWITCH1] = { .name = "SWITCH_REG1" }, - [RK808_ID_SWITCH2] = { .name = "SWITCH_REG2" }, + RK8XX_DESC(RK808_ID_LDO4, "LDO_REG4", "vcc9", 1800, 3400, 100, + RK808_LDO4_ON_VSEL_REG, RK808_LDO_VSEL_MASK, RK808_LDO_EN_REG, + BIT(3), 400), + RK8XX_DESC(RK808_ID_LDO5, "LDO_REG5", "vcc9", 1800, 3400, 100, + RK808_LDO5_ON_VSEL_REG, RK808_LDO_VSEL_MASK, RK808_LDO_EN_REG, + BIT(4), 400), + RK8XX_DESC(RK808_ID_LDO6, "LDO_REG6", "vcc10", 800, 2500, 100, + RK808_LDO6_ON_VSEL_REG, RK808_LDO_VSEL_MASK, RK808_LDO_EN_REG, + BIT(5), 400), + RK8XX_DESC(RK808_ID_LDO7, "LDO_REG7", "vcc7", 800, 2500, 100, + RK808_LDO7_ON_VSEL_REG, RK808_LDO_VSEL_MASK, RK808_LDO_EN_REG, + BIT(6), 400), + RK8XX_DESC(RK808_ID_LDO8, "LDO_REG8", "vcc11", 1800, 3400, 100, + RK808_LDO8_ON_VSEL_REG, RK808_LDO_VSEL_MASK, RK808_LDO_EN_REG, + BIT(7), 400), + RK8XX_DESC_SWITCH(RK808_ID_SWITCH1, "SWITCH_REG1", "vcc8", + RK808_DCDC_EN_REG, BIT(5)), + RK8XX_DESC_SWITCH(RK808_ID_SWITCH2, "SWITCH_REG2", "vcc12", + RK808_DCDC_EN_REG, BIT(6)), }; static int rk808_regulator_dt_parse_pdata(struct device *dev, @@ -529,17 +460,12 @@ static int rk808_regulator_dt_parse_pdata(struct device *dev, struct rk808_regulator_data *pdata) { struct device_node *np; - int tmp, ret, i; + int tmp, ret = 0, i; np = of_get_child_by_name(client_dev->of_node, "regulators"); if (!np) return -ENXIO; - ret = of_regulator_match(dev, np, rk808_reg_matches, - RK808_NUM_REGULATORS); - if (ret < 0) - goto dt_parse_end; - for (i = 0; i < ARRAY_SIZE(pdata->dvs_gpio); i++) { pdata->dvs_gpio[i] = devm_gpiod_get_index_optional(client_dev, "dvs", i, @@ -586,18 +512,12 @@ static int rk808_regulator_probe(struct platform_device *pdev) platform_set_drvdata(pdev, pdata); + config.dev = &client->dev; + config.driver_data = pdata; + config.regmap = rk808->regmap; + /* Instantiate the regulators */ for (i = 0; i < RK808_NUM_REGULATORS; i++) { - if (!rk808_reg_matches[i].init_data || - !rk808_reg_matches[i].of_node) - continue; - - config.dev = &client->dev; - config.driver_data = pdata; - config.regmap = rk808->regmap; - config.of_node = rk808_reg_matches[i].of_node; - config.init_data = rk808_reg_matches[i].init_data; - rk808_rdev = devm_regulator_register(&pdev->dev, &rk808_reg[i], &config); if (IS_ERR(rk808_rdev)) { diff --git a/drivers/regulator/s2mps11.c b/drivers/regulator/s2mps11.c index 6dfa3502e..02fb6b4ea 100644 --- a/drivers/regulator/s2mps11.c +++ b/drivers/regulator/s2mps11.c @@ -267,6 +267,7 @@ static struct regulator_ops s2mps11_buck_ops = { .ops = &s2mps11_ldo_ops, \ .type = REGULATOR_VOLTAGE, \ .owner = THIS_MODULE, \ + .ramp_delay = RAMP_DELAY_12_MVUS, \ .min_uV = MIN_800_MV, \ .uV_step = step, \ .n_voltages = S2MPS11_LDO_N_VOLTAGES, \ @@ -1237,17 +1238,7 @@ static struct platform_driver s2mps11_pmic_driver = { .id_table = s2mps11_pmic_id, }; -static int __init s2mps11_pmic_init(void) -{ - return platform_driver_register(&s2mps11_pmic_driver); -} -subsys_initcall(s2mps11_pmic_init); - -static void __exit s2mps11_pmic_exit(void) -{ - platform_driver_unregister(&s2mps11_pmic_driver); -} -module_exit(s2mps11_pmic_exit); +module_platform_driver(s2mps11_pmic_driver); /* Module information */ MODULE_AUTHOR("Sangbeom Kim "); diff --git a/drivers/regulator/tps51632-regulator.c b/drivers/regulator/tps51632-regulator.c index 572816e30..c139890c1 100644 --- a/drivers/regulator/tps51632-regulator.c +++ b/drivers/regulator/tps51632-regulator.c @@ -94,11 +94,14 @@ static int tps51632_dcdc_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay) { struct tps51632_chip *tps = rdev_get_drvdata(rdev); - int bit = ramp_delay/6000; + int bit; int ret; - if (bit) - bit--; + if (ramp_delay == 0) + bit = 0; + else + bit = DIV_ROUND_UP(ramp_delay, 6000) - 1; + ret = regmap_write(tps->regmap, TPS51632_SLEW_REGS, BIT(bit)); if (ret < 0) dev_err(tps->dev, "SLEW reg write failed, err %d\n", ret); diff --git a/drivers/regulator/tps6524x-regulator.c b/drivers/regulator/tps6524x-regulator.c index 9d6ea3a4d..67cac2682 100644 --- a/drivers/regulator/tps6524x-regulator.c +++ b/drivers/regulator/tps6524x-regulator.c @@ -600,7 +600,7 @@ static int pmic_probe(struct spi_device *spi) memset(hw, 0, sizeof(struct tps6524x)); hw->dev = dev; - hw->spi = spi_dev_get(spi); + hw->spi = spi; mutex_init(&hw->lock); for (i = 0; i < N_REGULATORS; i++, info++, init_data++) { diff --git a/drivers/regulator/twl-regulator.c b/drivers/regulator/twl-regulator.c index 955a6fb13..faeb5ee92 100644 --- a/drivers/regulator/twl-regulator.c +++ b/drivers/regulator/twl-regulator.c @@ -21,7 +21,7 @@ #include #include #include - +#include /* * The TWL4030/TW5030/TPS659x0/TWL6030 family chips include power management, a @@ -188,6 +188,74 @@ static int twl6030reg_is_enabled(struct regulator_dev *rdev) return grp && (val == TWL6030_CFG_STATE_ON); } +#define PB_I2C_BUSY BIT(0) +#define PB_I2C_BWEN BIT(1) + +/* Wait until buffer empty/ready to send a word on power bus. */ +static int twl4030_wait_pb_ready(void) +{ + + int ret; + int timeout = 10; + u8 val; + + do { + ret = twl_i2c_read_u8(TWL_MODULE_PM_MASTER, &val, + TWL4030_PM_MASTER_PB_CFG); + if (ret < 0) + return ret; + + if (!(val & PB_I2C_BUSY)) + return 0; + + mdelay(1); + timeout--; + } while (timeout); + + return -ETIMEDOUT; +} + +/* Send a word over the powerbus */ +static int twl4030_send_pb_msg(unsigned msg) +{ + u8 val; + int ret; + + /* save powerbus configuration */ + ret = twl_i2c_read_u8(TWL_MODULE_PM_MASTER, &val, + TWL4030_PM_MASTER_PB_CFG); + if (ret < 0) + return ret; + + /* Enable i2c access to powerbus */ + ret = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, val | PB_I2C_BWEN, + TWL4030_PM_MASTER_PB_CFG); + if (ret < 0) + return ret; + + ret = twl4030_wait_pb_ready(); + if (ret < 0) + return ret; + + ret = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, msg >> 8, + TWL4030_PM_MASTER_PB_WORD_MSB); + if (ret < 0) + return ret; + + ret = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, msg & 0xff, + TWL4030_PM_MASTER_PB_WORD_LSB); + if (ret < 0) + return ret; + + ret = twl4030_wait_pb_ready(); + if (ret < 0) + return ret; + + /* Restore powerbus configuration */ + return twl_i2c_write_u8(TWL_MODULE_PM_MASTER, val, + TWL4030_PM_MASTER_PB_CFG); +} + static int twl4030reg_enable(struct regulator_dev *rdev) { struct twlreg_info *info = rdev_get_drvdata(rdev); @@ -303,7 +371,6 @@ static int twl4030reg_set_mode(struct regulator_dev *rdev, unsigned mode) { struct twlreg_info *info = rdev_get_drvdata(rdev); unsigned message; - int status; /* We can only set the mode through state machine commands... */ switch (mode) { @@ -317,20 +384,19 @@ static int twl4030reg_set_mode(struct regulator_dev *rdev, unsigned mode) return -EINVAL; } - /* Ensure the resource is associated with some group */ - status = twlreg_grp(rdev); - if (status < 0) - return status; - if (!(status & (P3_GRP_4030 | P2_GRP_4030 | P1_GRP_4030))) - return -EACCES; - - status = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, - message >> 8, TWL4030_PM_MASTER_PB_WORD_MSB); - if (status < 0) - return status; + return twl4030_send_pb_msg(message); +} - return twl_i2c_write_u8(TWL_MODULE_PM_MASTER, - message & 0xff, TWL4030_PM_MASTER_PB_WORD_LSB); +static inline unsigned int twl4030reg_map_mode(unsigned int mode) +{ + switch (mode) { + case RES_STATE_ACTIVE: + return REGULATOR_MODE_NORMAL; + case RES_STATE_SLEEP: + return REGULATOR_MODE_STANDBY; + default: + return -EINVAL; + } } static int twl6030reg_set_mode(struct regulator_dev *rdev, unsigned mode) @@ -835,10 +901,11 @@ static struct regulator_ops twlsmps_ops = { #define TWL4030_FIXED_LDO(label, offset, mVolts, num, turnon_delay, \ remap_conf) \ TWL_FIXED_LDO(label, offset, mVolts, num, turnon_delay, \ - remap_conf, TWL4030, twl4030fixed_ops) + remap_conf, TWL4030, twl4030fixed_ops, \ + twl4030reg_map_mode) #define TWL6030_FIXED_LDO(label, offset, mVolts, turnon_delay) \ TWL_FIXED_LDO(label, offset, mVolts, 0x0, turnon_delay, \ - 0x0, TWL6030, twl6030fixed_ops) + 0x0, TWL6030, twl6030fixed_ops, 0x0) #define TWL4030_ADJUSTABLE_LDO(label, offset, num, turnon_delay, remap_conf) \ static const struct twlreg_info TWL4030_INFO_##label = { \ @@ -855,6 +922,7 @@ static const struct twlreg_info TWL4030_INFO_##label = { \ .type = REGULATOR_VOLTAGE, \ .owner = THIS_MODULE, \ .enable_time = turnon_delay, \ + .of_map_mode = twl4030reg_map_mode, \ }, \ } @@ -870,6 +938,7 @@ static const struct twlreg_info TWL4030_INFO_##label = { \ .type = REGULATOR_VOLTAGE, \ .owner = THIS_MODULE, \ .enable_time = turnon_delay, \ + .of_map_mode = twl4030reg_map_mode, \ }, \ } @@ -915,7 +984,7 @@ static const struct twlreg_info TWL6032_INFO_##label = { \ } #define TWL_FIXED_LDO(label, offset, mVolts, num, turnon_delay, remap_conf, \ - family, operations) \ + family, operations, map_mode) \ static const struct twlreg_info TWLFIXED_INFO_##label = { \ .base = offset, \ .id = num, \ @@ -930,6 +999,7 @@ static const struct twlreg_info TWLFIXED_INFO_##label = { \ .owner = THIS_MODULE, \ .min_uV = mVolts * 1000, \ .enable_time = turnon_delay, \ + .of_map_mode = map_mode, \ }, \ } -- cgit v1.2.3-54-g00ecf