diff options
Diffstat (limited to 'drivers/regulator')
36 files changed, 539 insertions, 272 deletions
diff --git a/drivers/regulator/88pm8607.c b/drivers/regulator/88pm8607.c index 6d77dcd..3fe47bd 100644 --- a/drivers/regulator/88pm8607.c +++ b/drivers/regulator/88pm8607.c @@ -330,7 +330,8 @@ static int pm8607_regulator_dt_init(struct platform_device *pdev, for_each_child_of_node(nproot, np) { if (!of_node_cmp(np->name, info->desc.name)) { config->init_data = - of_get_regulator_init_data(&pdev->dev, np); + of_get_regulator_init_data(&pdev->dev, np, + &info->desc); config->of_node = np; break; } diff --git a/drivers/regulator/act8865-regulator.c b/drivers/regulator/act8865-regulator.c index afd06f9..9eec453 100644 --- a/drivers/regulator/act8865-regulator.c +++ b/drivers/regulator/act8865-regulator.c @@ -61,6 +61,8 @@ #define ACT8846_REG12_VSET 0xa0 #define ACT8846_REG12_CTRL 0xa1 #define ACT8846_REG13_CTRL 0xb1 +#define ACT8846_GLB_OFF_CTRL 0xc3 +#define ACT8846_OFF_SYSMASK 0x18 /* * ACT8865 Global Register Map. @@ -84,6 +86,7 @@ #define ACT8865_LDO3_CTRL 0x61 #define ACT8865_LDO4_VSET 0x64 #define ACT8865_LDO4_CTRL 0x65 +#define ACT8865_MSTROFF 0x20 /* * Field Definitions. @@ -98,6 +101,8 @@ struct act8865 { struct regmap *regmap; + int off_reg; + int off_mask; }; static const struct regmap_config act8865_regmap_config = { @@ -275,6 +280,16 @@ static struct regulator_init_data return NULL; } +static struct i2c_client *act8865_i2c_client; +static void act8865_power_off(void) +{ + struct act8865 *act8865; + + act8865 = i2c_get_clientdata(act8865_i2c_client); + regmap_write(act8865->regmap, act8865->off_reg, act8865->off_mask); + while (1); +} + static int act8865_pmic_probe(struct i2c_client *client, const struct i2c_device_id *i2c_id) { @@ -285,6 +300,7 @@ static int act8865_pmic_probe(struct i2c_client *client, int i, ret, num_regulators; struct act8865 *act8865; unsigned long type; + int off_reg, off_mask; pdata = dev_get_platdata(dev); @@ -304,10 +320,14 @@ static int act8865_pmic_probe(struct i2c_client *client, case ACT8846: regulators = act8846_regulators; num_regulators = ARRAY_SIZE(act8846_regulators); + off_reg = ACT8846_GLB_OFF_CTRL; + off_mask = ACT8846_OFF_SYSMASK; break; case ACT8865: regulators = act8865_regulators; num_regulators = ARRAY_SIZE(act8865_regulators); + off_reg = ACT8865_SYS_CTRL; + off_mask = ACT8865_MSTROFF; break; default: dev_err(dev, "invalid device id %lu\n", type); @@ -345,6 +365,17 @@ static int act8865_pmic_probe(struct i2c_client *client, return ret; } + if (of_device_is_system_power_controller(dev->of_node)) { + if (!pm_power_off) { + act8865_i2c_client = client; + act8865->off_reg = off_reg; + act8865->off_mask = off_mask; + pm_power_off = act8865_power_off; + } else { + dev_err(dev, "Failed to set poweroff capability, already defined\n"); + } + } + /* Finally register devices */ for (i = 0; i < num_regulators; i++) { const struct regulator_desc *desc = ®ulators[i]; diff --git a/drivers/regulator/anatop-regulator.c b/drivers/regulator/anatop-regulator.c index 4f730af..3586571 100644 --- a/drivers/regulator/anatop-regulator.c +++ b/drivers/regulator/anatop-regulator.c @@ -189,17 +189,18 @@ static int anatop_regulator_probe(struct platform_device *pdev) int ret = 0; u32 val; - initdata = of_get_regulator_init_data(dev, np); sreg = devm_kzalloc(dev, sizeof(*sreg), GFP_KERNEL); if (!sreg) return -ENOMEM; - sreg->initdata = initdata; sreg->name = of_get_property(np, "regulator-name", NULL); rdesc = &sreg->rdesc; rdesc->name = sreg->name; rdesc->type = REGULATOR_VOLTAGE; rdesc->owner = THIS_MODULE; + initdata = of_get_regulator_init_data(dev, np, rdesc); + sreg->initdata = initdata; + anatop_np = of_get_parent(np); if (!anatop_np) return -ENODEV; @@ -283,6 +284,19 @@ static int anatop_regulator_probe(struct platform_device *pdev) sreg->sel = 0; sreg->bypass = true; } + + /* + * In case vddpu was disabled by the bootloader, we need to set + * a sane default until imx6-cpufreq was probed and changes the + * voltage to the correct value. In this case we set 1.25V. + */ + if (!sreg->sel && !strcmp(sreg->name, "vddpu")) + sreg->sel = 22; + + if (!sreg->sel) { + dev_err(&pdev->dev, "Failed to read a valid default voltage selector.\n"); + return -EINVAL; + } } else { rdesc->ops = &anatop_rops; } diff --git a/drivers/regulator/arizona-ldo1.c b/drivers/regulator/arizona-ldo1.c index 4c9db58..d071b21 100644 --- a/drivers/regulator/arizona-ldo1.c +++ b/drivers/regulator/arizona-ldo1.c @@ -179,7 +179,8 @@ static const struct regulator_init_data arizona_ldo1_default = { }; static int arizona_ldo1_of_get_pdata(struct arizona *arizona, - struct regulator_config *config) + struct regulator_config *config, + const struct regulator_desc *desc) { struct arizona_pdata *pdata = &arizona->pdata; struct arizona_ldo1 *ldo1 = config->driver_data; @@ -194,7 +195,8 @@ static int arizona_ldo1_of_get_pdata(struct arizona *arizona, if (init_node) { config->of_node = init_node; - init_data = of_get_regulator_init_data(arizona->dev, init_node); + init_data = of_get_regulator_init_data(arizona->dev, init_node, + desc); if (init_data) { init_data->consumer_supplies = &ldo1->supply; @@ -257,9 +259,11 @@ static int arizona_ldo1_probe(struct platform_device *pdev) if (IS_ENABLED(CONFIG_OF)) { if (!dev_get_platdata(arizona->dev)) { - ret = arizona_ldo1_of_get_pdata(arizona, &config); + ret = arizona_ldo1_of_get_pdata(arizona, &config, desc); if (ret < 0) return ret; + + config.ena_gpio_initialized = true; } } diff --git a/drivers/regulator/arizona-micsupp.c b/drivers/regulator/arizona-micsupp.c index ce9aca5..c313ef4 100644 --- a/drivers/regulator/arizona-micsupp.c +++ b/drivers/regulator/arizona-micsupp.c @@ -198,7 +198,8 @@ static const struct regulator_init_data arizona_micsupp_ext_default = { }; static int arizona_micsupp_of_get_pdata(struct arizona *arizona, - struct regulator_config *config) + struct regulator_config *config, + const struct regulator_desc *desc) { struct arizona_pdata *pdata = &arizona->pdata; struct arizona_micsupp *micsupp = config->driver_data; @@ -210,7 +211,7 @@ static int arizona_micsupp_of_get_pdata(struct arizona *arizona, if (np) { config->of_node = np; - init_data = of_get_regulator_init_data(arizona->dev, np); + init_data = of_get_regulator_init_data(arizona->dev, np, desc); if (init_data) { init_data->consumer_supplies = &micsupp->supply; @@ -264,7 +265,8 @@ static int arizona_micsupp_probe(struct platform_device *pdev) if (IS_ENABLED(CONFIG_OF)) { if (!dev_get_platdata(arizona->dev)) { - ret = arizona_micsupp_of_get_pdata(arizona, &config); + ret = arizona_micsupp_of_get_pdata(arizona, &config, + desc); if (ret < 0) return ret; } diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index cd87c0c..e225711 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -828,7 +828,7 @@ static void print_constraints(struct regulator_dev *rdev) if (!count) sprintf(buf, "no parameters"); - rdev_info(rdev, "%s\n", buf); + rdev_dbg(rdev, "%s\n", buf); if ((constraints->min_uV != constraints->max_uV) && !(constraints->valid_ops_mask & REGULATOR_CHANGE_VOLTAGE)) @@ -1713,6 +1713,8 @@ static void regulator_ena_gpio_free(struct regulator_dev *rdev) gpiod_put(pin->gpiod); list_del(&pin->list); kfree(pin); + rdev->ena_pin = NULL; + return; } else { pin->request_count--; } @@ -1976,9 +1978,18 @@ static int _regulator_disable(struct regulator_dev *rdev) /* we are last user */ if (_regulator_can_change_status(rdev)) { + ret = _notifier_call_chain(rdev, + REGULATOR_EVENT_PRE_DISABLE, + NULL); + if (ret & NOTIFY_STOP_MASK) + return -EINVAL; + ret = _regulator_do_disable(rdev); if (ret < 0) { rdev_err(rdev, "failed to disable\n"); + _notifier_call_chain(rdev, + REGULATOR_EVENT_ABORT_DISABLE, + NULL); return ret; } _notifier_call_chain(rdev, REGULATOR_EVENT_DISABLE, @@ -2035,9 +2046,16 @@ static int _regulator_force_disable(struct regulator_dev *rdev) { int ret = 0; + ret = _notifier_call_chain(rdev, REGULATOR_EVENT_FORCE_DISABLE | + REGULATOR_EVENT_PRE_DISABLE, NULL); + if (ret & NOTIFY_STOP_MASK) + return -EINVAL; + ret = _regulator_do_disable(rdev); if (ret < 0) { rdev_err(rdev, "failed to force disable\n"); + _notifier_call_chain(rdev, REGULATOR_EVENT_FORCE_DISABLE | + REGULATOR_EVENT_ABORT_DISABLE, NULL); return ret; } @@ -3650,7 +3668,8 @@ regulator_register(const struct regulator_desc *regulator_desc, dev_set_drvdata(&rdev->dev, rdev); - if (config->ena_gpio && gpio_is_valid(config->ena_gpio)) { + if ((config->ena_gpio || config->ena_gpio_initialized) && + gpio_is_valid(config->ena_gpio)) { ret = regulator_ena_gpio_request(rdev, config); if (ret != 0) { rdev_err(rdev, "Failed to request enable GPIO%d: %d\n", diff --git a/drivers/regulator/da9052-regulator.c b/drivers/regulator/da9052-regulator.c index 0003362..3945f10 100644 --- a/drivers/regulator/da9052-regulator.c +++ b/drivers/regulator/da9052-regulator.c @@ -436,7 +436,8 @@ static int da9052_regulator_probe(struct platform_device *pdev) if (!of_node_cmp(np->name, regulator->info->reg_desc.name)) { config.init_data = of_get_regulator_init_data( - &pdev->dev, np); + &pdev->dev, np, + ®ulator->info->reg_desc); config.of_node = np; break; } diff --git a/drivers/regulator/da9063-regulator.c b/drivers/regulator/da9063-regulator.c index 7c9461d..37dd427 100644 --- a/drivers/regulator/da9063-regulator.c +++ b/drivers/regulator/da9063-regulator.c @@ -867,17 +867,14 @@ static int da9063_regulator_probe(struct platform_device *pdev) return irq; } - regulators->irq_ldo_lim = regmap_irq_get_virq(da9063->regmap_irq, irq); - if (regulators->irq_ldo_lim >= 0) { - ret = request_threaded_irq(regulators->irq_ldo_lim, - NULL, da9063_ldo_lim_event, - IRQF_TRIGGER_LOW | IRQF_ONESHOT, - "LDO_LIM", regulators); - if (ret) { - dev_err(&pdev->dev, - "Failed to request LDO_LIM IRQ.\n"); - regulators->irq_ldo_lim = -ENXIO; - } + ret = request_threaded_irq(irq, + NULL, da9063_ldo_lim_event, + IRQF_TRIGGER_LOW | IRQF_ONESHOT, + "LDO_LIM", regulators); + if (ret) { + dev_err(&pdev->dev, + "Failed to request LDO_LIM IRQ.\n"); + regulators->irq_ldo_lim = -ENXIO; } return 0; diff --git a/drivers/regulator/da9210-regulator.c b/drivers/regulator/da9210-regulator.c index 7a320dd..bc61001 100644 --- a/drivers/regulator/da9210-regulator.c +++ b/drivers/regulator/da9210-regulator.c @@ -147,7 +147,7 @@ static int da9210_i2c_probe(struct i2c_client *i2c, config.dev = &i2c->dev; config.init_data = pdata ? &pdata->da9210_constraints : - of_get_regulator_init_data(dev, dev->of_node); + of_get_regulator_init_data(dev, dev->of_node, &da9210_reg); config.driver_data = chip; config.regmap = chip->regmap; config.of_node = dev->of_node; diff --git a/drivers/regulator/dummy.c b/drivers/regulator/dummy.c index 2436db9..7aef9e4 100644 --- a/drivers/regulator/dummy.c +++ b/drivers/regulator/dummy.c @@ -33,7 +33,7 @@ static struct regulator_init_data dummy_initdata = { static struct regulator_ops dummy_ops; -static struct regulator_desc dummy_desc = { +static const struct regulator_desc dummy_desc = { .name = "regulator-dummy", .id = -1, .type = REGULATOR_VOLTAGE, diff --git a/drivers/regulator/fan53555.c b/drivers/regulator/fan53555.c index f8e4257..6c43ab2 100644 --- a/drivers/regulator/fan53555.c +++ b/drivers/regulator/fan53555.c @@ -302,7 +302,8 @@ static struct regmap_config fan53555_regmap_config = { }; static struct fan53555_platform_data *fan53555_parse_dt(struct device *dev, - struct device_node *np) + struct device_node *np, + const struct regulator_desc *desc) { struct fan53555_platform_data *pdata; int ret; @@ -312,7 +313,7 @@ static struct fan53555_platform_data *fan53555_parse_dt(struct device *dev, if (!pdata) return NULL; - pdata->regulator = of_get_regulator_init_data(dev, np); + pdata->regulator = of_get_regulator_init_data(dev, np, desc); ret = of_property_read_u32(np, "fcs,suspend-voltage-selector", &tmp); @@ -347,20 +348,20 @@ static int fan53555_regulator_probe(struct i2c_client *client, unsigned int val; int ret; + di = devm_kzalloc(&client->dev, sizeof(struct fan53555_device_info), + GFP_KERNEL); + if (!di) + return -ENOMEM; + pdata = dev_get_platdata(&client->dev); if (!pdata) - pdata = fan53555_parse_dt(&client->dev, np); + pdata = fan53555_parse_dt(&client->dev, np, &di->desc); if (!pdata || !pdata->regulator) { dev_err(&client->dev, "Platform data not found!\n"); return -ENODEV; } - di = devm_kzalloc(&client->dev, sizeof(struct fan53555_device_info), - GFP_KERNEL); - if (!di) - return -ENOMEM; - di->regulator = pdata->regulator; if (client->dev.of_node) { const struct of_device_id *match; diff --git a/drivers/regulator/fixed.c b/drivers/regulator/fixed.c index 354105e..d21da27 100644 --- a/drivers/regulator/fixed.c +++ b/drivers/regulator/fixed.c @@ -40,13 +40,15 @@ struct fixed_voltage_data { /** * of_get_fixed_voltage_config - extract fixed_voltage_config structure info * @dev: device requesting for fixed_voltage_config + * @desc: regulator description * * Populates fixed_voltage_config structure by extracting data from device * tree node, returns a pointer to the populated structure of NULL if memory * alloc fails. */ static struct fixed_voltage_config * -of_get_fixed_voltage_config(struct device *dev) +of_get_fixed_voltage_config(struct device *dev, + const struct regulator_desc *desc) { struct fixed_voltage_config *config; struct device_node *np = dev->of_node; @@ -57,7 +59,7 @@ of_get_fixed_voltage_config(struct device *dev) if (!config) return ERR_PTR(-ENOMEM); - config->init_data = of_get_regulator_init_data(dev, dev->of_node); + config->init_data = of_get_regulator_init_data(dev, dev->of_node, desc); if (!config->init_data) return ERR_PTR(-EINVAL); @@ -112,8 +114,14 @@ static int reg_fixed_voltage_probe(struct platform_device *pdev) struct regulator_config cfg = { }; int ret; + drvdata = devm_kzalloc(&pdev->dev, sizeof(struct fixed_voltage_data), + GFP_KERNEL); + if (!drvdata) + return -ENOMEM; + if (pdev->dev.of_node) { - config = of_get_fixed_voltage_config(&pdev->dev); + config = of_get_fixed_voltage_config(&pdev->dev, + &drvdata->desc); if (IS_ERR(config)) return PTR_ERR(config); } else { @@ -123,11 +131,6 @@ static int reg_fixed_voltage_probe(struct platform_device *pdev) if (!config) return -ENOMEM; - drvdata = devm_kzalloc(&pdev->dev, sizeof(struct fixed_voltage_data), - GFP_KERNEL); - if (!drvdata) - return -ENOMEM; - drvdata->desc.name = devm_kstrdup(&pdev->dev, config->supply_name, GFP_KERNEL); @@ -157,8 +160,11 @@ static int reg_fixed_voltage_probe(struct platform_device *pdev) drvdata->desc.fixed_uV = config->microvolts; - if (config->gpio >= 0) + if (gpio_is_valid(config->gpio)) { cfg.ena_gpio = config->gpio; + if (pdev->dev.of_node) + cfg.ena_gpio_initialized = true; + } cfg.ena_gpio_invert = !config->enable_high; if (config->enabled_at_boot) { if (config->enable_high) diff --git a/drivers/regulator/gpio-regulator.c b/drivers/regulator/gpio-regulator.c index 989b23b..c888a9a 100644 --- a/drivers/regulator/gpio-regulator.c +++ b/drivers/regulator/gpio-regulator.c @@ -133,7 +133,8 @@ static struct regulator_ops gpio_regulator_voltage_ops = { }; static struct gpio_regulator_config * -of_get_gpio_regulator_config(struct device *dev, struct device_node *np) +of_get_gpio_regulator_config(struct device *dev, struct device_node *np, + const struct regulator_desc *desc) { struct gpio_regulator_config *config; const char *regtype; @@ -146,7 +147,7 @@ of_get_gpio_regulator_config(struct device *dev, struct device_node *np) if (!config) return ERR_PTR(-ENOMEM); - config->init_data = of_get_regulator_init_data(dev, np); + config->init_data = of_get_regulator_init_data(dev, np, desc); if (!config->init_data) return ERR_PTR(-EINVAL); @@ -162,34 +163,41 @@ of_get_gpio_regulator_config(struct device *dev, struct device_node *np) config->enable_gpio = of_get_named_gpio(np, "enable-gpio", 0); - /* Fetch GPIOs. */ - config->nr_gpios = of_gpio_count(np); - - config->gpios = devm_kzalloc(dev, - sizeof(struct gpio) * config->nr_gpios, - GFP_KERNEL); - if (!config->gpios) - return ERR_PTR(-ENOMEM); - - proplen = of_property_count_u32_elems(np, "gpios-states"); - /* optional property */ - if (proplen < 0) - proplen = 0; - - if (proplen > 0 && proplen != config->nr_gpios) { - dev_warn(dev, "gpios <-> gpios-states mismatch\n"); - proplen = 0; - } + /* Fetch GPIOs. - optional property*/ + ret = of_gpio_count(np); + if ((ret < 0) && (ret != -ENOENT)) + return ERR_PTR(ret); + + if (ret > 0) { + config->nr_gpios = ret; + config->gpios = devm_kzalloc(dev, + sizeof(struct gpio) * config->nr_gpios, + GFP_KERNEL); + if (!config->gpios) + return ERR_PTR(-ENOMEM); + + proplen = of_property_count_u32_elems(np, "gpios-states"); + /* optional property */ + if (proplen < 0) + proplen = 0; + + if (proplen > 0 && proplen != config->nr_gpios) { + dev_warn(dev, "gpios <-> gpios-states mismatch\n"); + proplen = 0; + } - for (i = 0; i < config->nr_gpios; i++) { - gpio = of_get_named_gpio(np, "gpios", i); - if (gpio < 0) - break; - config->gpios[i].gpio = gpio; - if (proplen > 0) { - of_property_read_u32_index(np, "gpios-states", i, &ret); - if (ret) - config->gpios[i].flags = GPIOF_OUT_INIT_HIGH; + for (i = 0; i < config->nr_gpios; i++) { + gpio = of_get_named_gpio(np, "gpios", i); + if (gpio < 0) + break; + config->gpios[i].gpio = gpio; + if (proplen > 0) { + of_property_read_u32_index(np, "gpios-states", + i, &ret); + if (ret) + config->gpios[i].flags = + GPIOF_OUT_INIT_HIGH; + } } } @@ -243,17 +251,18 @@ static int gpio_regulator_probe(struct platform_device *pdev) struct regulator_config cfg = { }; int ptr, ret, state; - if (np) { - config = of_get_gpio_regulator_config(&pdev->dev, np); - if (IS_ERR(config)) - return PTR_ERR(config); - } - drvdata = devm_kzalloc(&pdev->dev, sizeof(struct gpio_regulator_data), GFP_KERNEL); if (drvdata == NULL) return -ENOMEM; + if (np) { + config = of_get_gpio_regulator_config(&pdev->dev, np, + &drvdata->desc); + if (IS_ERR(config)) + return PTR_ERR(config); + } + drvdata->desc.name = kstrdup(config->supply_name, GFP_KERNEL); if (drvdata->desc.name == NULL) { dev_err(&pdev->dev, "Failed to allocate supply name\n"); @@ -261,13 +270,23 @@ static int gpio_regulator_probe(struct platform_device *pdev) goto err; } - drvdata->gpios = kmemdup(config->gpios, - config->nr_gpios * sizeof(struct gpio), - GFP_KERNEL); - if (drvdata->gpios == NULL) { - dev_err(&pdev->dev, "Failed to allocate gpio data\n"); - ret = -ENOMEM; - goto err_name; + if (config->nr_gpios != 0) { + drvdata->gpios = kmemdup(config->gpios, + config->nr_gpios * sizeof(struct gpio), + GFP_KERNEL); + if (drvdata->gpios == NULL) { + dev_err(&pdev->dev, "Failed to allocate gpio data\n"); + ret = -ENOMEM; + goto err_name; + } + + drvdata->nr_gpios = config->nr_gpios; + ret = gpio_request_array(drvdata->gpios, drvdata->nr_gpios); + if (ret) { + dev_err(&pdev->dev, + "Could not obtain regulator setting GPIOs: %d\n", ret); + goto err_memstate; + } } drvdata->states = kmemdup(config->states, @@ -301,14 +320,6 @@ static int gpio_regulator_probe(struct platform_device *pdev) goto err_memgpio; } - drvdata->nr_gpios = config->nr_gpios; - ret = gpio_request_array(drvdata->gpios, drvdata->nr_gpios); - if (ret) { - dev_err(&pdev->dev, - "Could not obtain regulator setting GPIOs: %d\n", ret); - goto err_memstate; - } - /* build initial state from gpio init data. */ state = 0; for (ptr = 0; ptr < drvdata->nr_gpios; ptr++) { @@ -322,8 +333,10 @@ static int gpio_regulator_probe(struct platform_device *pdev) cfg.driver_data = drvdata; cfg.of_node = np; - if (config->enable_gpio >= 0) + if (gpio_is_valid(config->enable_gpio)) { cfg.ena_gpio = config->enable_gpio; + cfg.ena_gpio_initialized = true; + } cfg.ena_gpio_invert = !config->enable_high; if (config->enabled_at_boot) { if (config->enable_high) diff --git a/drivers/regulator/max77693.c b/drivers/regulator/max77693.c index d158f71..7b9755a 100644 --- a/drivers/regulator/max77693.c +++ b/drivers/regulator/max77693.c @@ -139,7 +139,7 @@ static struct regulator_ops max77693_charger_ops = { .enable_mask = SAFEOUT_CTRL_ENSAFEOUT##_num##_MASK , \ } -static struct regulator_desc regulators[] = { +static const struct regulator_desc regulators[] = { regulator_desc_esafeout(1), regulator_desc_esafeout(2), { diff --git a/drivers/regulator/max77802.c b/drivers/regulator/max77802.c index 45fa240..0766615 100644 --- a/drivers/regulator/max77802.c +++ b/drivers/regulator/max77802.c @@ -33,6 +33,7 @@ #include <linux/regulator/of_regulator.h> #include <linux/mfd/max77686.h> #include <linux/mfd/max77686-private.h> +#include <dt-bindings/regulator/maxim,max77802.h> /* Default ramp delay in case it is not manually set */ #define MAX77802_RAMP_DELAY 100000 /* uV/us */ @@ -49,6 +50,10 @@ #define MAX77802_RAMP_RATE_MASK_4BIT 0xF0 #define MAX77802_RAMP_RATE_SHIFT_4BIT 4 +#define MAX77802_STATUS_OFF 0x0 +#define MAX77802_OFF_PWRREQ 0x1 +#define MAX77802_LP_PWRREQ 0x2 + /* MAX77802 has two register formats: 2-bit and 4-bit */ static const unsigned int ramp_table_77802_2bit[] = { 12500, @@ -65,9 +70,16 @@ static unsigned int ramp_table_77802_4bit[] = { }; struct max77802_regulator_prv { + /* Array indexed by regulator id */ unsigned int opmode[MAX77802_REG_MAX]; }; +static inline unsigned int max77802_map_mode(unsigned int mode) +{ + return mode == MAX77802_OPMODE_NORMAL ? + REGULATOR_MODE_NORMAL : REGULATOR_MODE_STANDBY; +} + static int max77802_get_opmode_shift(int id) { if (id == MAX77802_BUCK1 || (id >= MAX77802_BUCK5 && @@ -83,17 +95,16 @@ static int max77802_get_opmode_shift(int id) return -EINVAL; } -/* - * Some BUCKS supports Normal[ON/OFF] mode during suspend +/** + * max77802_set_suspend_disable - Disable the regulator during system suspend + * @rdev: regulator to mark as disabled * - * BUCK 1, 6, 2-4, 5, 7-10 (all) - * - * The other mode (0x02) will make PWRREQ switch between normal - * and low power. + * All regulators expect LDO 1, 3, 20 and 21 support OFF by PWRREQ. + * Configure the regulator so the PMIC will turn it OFF during system suspend. */ -static int max77802_buck_set_suspend_disable(struct regulator_dev *rdev) +static int max77802_set_suspend_disable(struct regulator_dev *rdev) { - unsigned int val = MAX77802_OPMODE_STANDBY; + unsigned int val = MAX77802_OFF_PWRREQ; struct max77802_regulator_prv *max77802 = rdev_get_drvdata(rdev); int id = rdev_get_id(rdev); int shift = max77802_get_opmode_shift(id); @@ -104,14 +115,11 @@ static int max77802_buck_set_suspend_disable(struct regulator_dev *rdev) } /* - * Some LDOs supports LPM-ON/OFF/Normal-ON mode during suspend state - * (Enable Control Logic1 by PWRREQ) - * - * LDOs 2, 4-19, 22-35. + * Some LDOs support Low Power Mode while the system is running. * + * LDOs 1, 3, 20, 21. */ -static int max77802_ldo_set_suspend_mode_logic1(struct regulator_dev *rdev, - unsigned int mode) +static int max77802_set_mode(struct regulator_dev *rdev, unsigned int mode) { struct max77802_regulator_prv *max77802 = rdev_get_drvdata(rdev); int id = rdev_get_id(rdev); @@ -119,14 +127,11 @@ static int max77802_ldo_set_suspend_mode_logic1(struct regulator_dev *rdev, int shift = max77802_get_opmode_shift(id); switch (mode) { - case REGULATOR_MODE_IDLE: /* ON in LP Mode */ - val = MAX77802_OPMODE_LP; + case REGULATOR_MODE_STANDBY: + val = MAX77802_OPMODE_LP; /* ON in Low Power Mode */ break; - case REGULATOR_MODE_NORMAL: /* ON in Normal Mode */ - val = MAX77802_OPMODE_NORMAL; - break; - case REGULATOR_MODE_STANDBY: /* ON/OFF by PWRREQ */ - val = MAX77802_OPMODE_STANDBY; + case REGULATOR_MODE_NORMAL: + val = MAX77802_OPMODE_NORMAL; /* ON in Normal Mode */ break; default: dev_warn(&rdev->dev, "%s: regulator mode: 0x%x not supported\n", @@ -139,35 +144,76 @@ static int max77802_ldo_set_suspend_mode_logic1(struct regulator_dev *rdev, rdev->desc->enable_mask, val << shift); } -/* - * Mode 1 (Output[ON/OFF] by PWRREQ) is not supported on some LDOs - * (Enable Control Logic2 by PWRREQ) +static unsigned max77802_get_mode(struct regulator_dev *rdev) +{ + struct max77802_regulator_prv *max77802 = rdev_get_drvdata(rdev); + int id = rdev_get_id(rdev); + + return max77802_map_mode(max77802->opmode[id]); +} + +/** + * max77802_set_suspend_mode - set regulator opmode when the system is suspended + * @rdev: regulator to change mode + * @mode: operating mode to be set * - * LDOs 1, 20, 21, and 3, + * Will set the operating mode for the regulators during system suspend. + * This function is valid for the three different enable control logics: * + * Enable Control Logic1 by PWRREQ (BUCK 2-4 and LDOs 2, 4-19, 22-35) + * Enable Control Logic2 by PWRREQ (LDOs 1, 20, 21) + * Enable Control Logic3 by PWRREQ (LDO 3) + * + * If setting the regulator mode fails, the function only warns but does + * not return an error code to avoid the regulator core to stop setting + * the operating mode for the remaining regulators. */ -static int max77802_ldo_set_suspend_mode_logic2(struct regulator_dev *rdev, - unsigned int mode) +static int max77802_set_suspend_mode(struct regulator_dev *rdev, + unsigned int mode) { struct max77802_regulator_prv *max77802 = rdev_get_drvdata(rdev); int id = rdev_get_id(rdev); unsigned int val; int shift = max77802_get_opmode_shift(id); + /* + * If the regulator has been disabled for suspend + * then is invalid to try setting a suspend mode. + */ + if (max77802->opmode[id] == MAX77802_OFF_PWRREQ) { + dev_warn(&rdev->dev, "%s: is disabled, mode: 0x%x not set\n", + rdev->desc->name, mode); + return 0; + } + switch (mode) { - case REGULATOR_MODE_IDLE: /* ON in LP Mode */ - val = MAX77802_OPMODE_LP; - break; - case REGULATOR_MODE_NORMAL: /* ON in Normal Mode */ - val = MAX77802_OPMODE_NORMAL; + case REGULATOR_MODE_STANDBY: + /* + * If the regulator opmode is normal then enable + * ON in Low Power Mode by PWRREQ. If the mode is + * already Low Power then no action is required. + */ + if (max77802->opmode[id] == MAX77802_OPMODE_NORMAL) + val = MAX77802_LP_PWRREQ; + else + return 0; break; + case REGULATOR_MODE_NORMAL: + /* + * If the regulator operating mode is Low Power then + * normal is not a valid opmode in suspend. If the + * mode is already normal then no action is required. + */ + if (max77802->opmode[id] == MAX77802_OPMODE_LP) + dev_warn(&rdev->dev, "%s: in Low Power: 0x%x invalid\n", + rdev->desc->name, mode); + return 0; default: dev_warn(&rdev->dev, "%s: regulator mode: 0x%x not supported\n", rdev->desc->name, mode); return -EINVAL; } - max77802->opmode[id] = val; return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, rdev->desc->enable_mask, val << shift); } @@ -178,6 +224,9 @@ static int max77802_enable(struct regulator_dev *rdev) int id = rdev_get_id(rdev); int shift = max77802_get_opmode_shift(id); + if (max77802->opmode[id] == MAX77802_OFF_PWRREQ) + max77802->opmode[id] = MAX77802_OPMODE_NORMAL; + return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, rdev->desc->enable_mask, max77802->opmode[id] << shift); @@ -247,7 +296,8 @@ static struct regulator_ops max77802_ldo_ops_logic1 = { .get_voltage_sel = regulator_get_voltage_sel_regmap, .set_voltage_sel = regulator_set_voltage_sel_regmap, .set_voltage_time_sel = regulator_set_voltage_time_sel, - .set_suspend_mode = max77802_ldo_set_suspend_mode_logic1, + .set_suspend_disable = max77802_set_suspend_disable, + .set_suspend_mode = max77802_set_suspend_mode, }; /* @@ -262,7 +312,9 @@ static struct regulator_ops max77802_ldo_ops_logic2 = { .get_voltage_sel = regulator_get_voltage_sel_regmap, .set_voltage_sel = regulator_set_voltage_sel_regmap, .set_voltage_time_sel = regulator_set_voltage_time_sel, - .set_suspend_mode = max77802_ldo_set_suspend_mode_logic2, + .set_mode = max77802_set_mode, + .get_mode = max77802_get_mode, + .set_suspend_mode = max77802_set_suspend_mode, }; /* BUCKS 1, 6 */ @@ -276,10 +328,25 @@ static struct regulator_ops max77802_buck_16_dvs_ops = { .set_voltage_sel = regulator_set_voltage_sel_regmap, .set_voltage_time_sel = regulator_set_voltage_time_sel, .set_ramp_delay = max77802_set_ramp_delay_4bit, - .set_suspend_disable = max77802_buck_set_suspend_disable, + .set_suspend_disable = max77802_set_suspend_disable, }; -/* BUCKs 2-4, 5, 7-10 */ +/* BUCKs 2-4 */ +static struct regulator_ops max77802_buck_234_ops = { + .list_voltage = regulator_list_voltage_linear, + .map_voltage = regulator_map_voltage_linear, + .is_enabled = regulator_is_enabled_regmap, + .enable = max77802_enable, + .disable = regulator_disable_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .set_voltage_time_sel = regulator_set_voltage_time_sel, + .set_ramp_delay = max77802_set_ramp_delay_2bit, + .set_suspend_disable = max77802_set_suspend_disable, + .set_suspend_mode = max77802_set_suspend_mode, +}; + +/* BUCKs 5, 7-10 */ static struct regulator_ops max77802_buck_dvs_ops = { .list_voltage = regulator_list_voltage_linear, .map_voltage = regulator_map_voltage_linear, @@ -290,12 +357,14 @@ static struct regulator_ops max77802_buck_dvs_ops = { .set_voltage_sel = regulator_set_voltage_sel_regmap, .set_voltage_time_sel = regulator_set_voltage_time_sel, .set_ramp_delay = max77802_set_ramp_delay_2bit, - .set_suspend_disable = max77802_buck_set_suspend_disable, + .set_suspend_disable = max77802_set_suspend_disable, }; /* LDOs 3-7, 9-14, 18-26, 28, 29, 32-34 */ #define regulator_77802_desc_p_ldo(num, supply, log) { \ .name = "LDO"#num, \ + .of_match = of_match_ptr("LDO"#num), \ + .regulators_node = of_match_ptr("regulators"), \ .id = MAX77802_LDO##num, \ .supply_name = "inl"#supply, \ .ops = &max77802_ldo_ops_logic##log, \ @@ -309,11 +378,14 @@ static struct regulator_ops max77802_buck_dvs_ops = { .vsel_mask = MAX77802_VSEL_MASK, \ .enable_reg = MAX77802_REG_LDO1CTRL1 + num - 1, \ .enable_mask = MAX77802_OPMODE_MASK << MAX77802_OPMODE_SHIFT_LDO, \ + .of_map_mode = max77802_map_mode, \ } /* LDOs 1, 2, 8, 15, 17, 27, 30, 35 */ #define regulator_77802_desc_n_ldo(num, supply, log) { \ .name = "LDO"#num, \ + .of_match = of_match_ptr("LDO"#num), \ + .regulators_node = of_match_ptr("regulators"), \ .id = MAX77802_LDO##num, \ .supply_name = "inl"#supply, \ .ops = &max77802_ldo_ops_logic##log, \ @@ -327,11 +399,14 @@ static struct regulator_ops max77802_buck_dvs_ops = { .vsel_mask = MAX77802_VSEL_MASK, \ .enable_reg = MAX77802_REG_LDO1CTRL1 + num - 1, \ .enable_mask = MAX77802_OPMODE_MASK << MAX77802_OPMODE_SHIFT_LDO, \ + .of_map_mode = max77802_map_mode, \ } /* BUCKs 1, 6 */ #define regulator_77802_desc_16_buck(num) { \ .name = "BUCK"#num, \ + .of_match = of_match_ptr("BUCK"#num), \ + .regulators_node = of_match_ptr("regulators"), \ .id = MAX77802_BUCK##num, \ .supply_name = "inb"#num, \ .ops = &max77802_buck_16_dvs_ops, \ @@ -345,14 +420,17 @@ static struct regulator_ops max77802_buck_dvs_ops = { .vsel_mask = MAX77802_DVS_VSEL_MASK, \ .enable_reg = MAX77802_REG_BUCK ## num ## CTRL, \ .enable_mask = MAX77802_OPMODE_MASK, \ + .of_map_mode = max77802_map_mode, \ } /* BUCKS 2-4 */ #define regulator_77802_desc_234_buck(num) { \ .name = "BUCK"#num, \ + .of_match = of_match_ptr("BUCK"#num), \ + .regulators_node = of_match_ptr("regulators"), \ .id = MAX77802_BUCK##num, \ .supply_name = "inb"#num, \ - .ops = &max77802_buck_dvs_ops, \ + .ops = &max77802_buck_234_ops, \ .type = REGULATOR_VOLTAGE, \ .owner = THIS_MODULE, \ .min_uV = 600000, \ @@ -364,11 +442,14 @@ static struct regulator_ops max77802_buck_dvs_ops = { .enable_reg = MAX77802_REG_BUCK ## num ## CTRL1, \ .enable_mask = MAX77802_OPMODE_MASK << \ MAX77802_OPMODE_BUCK234_SHIFT, \ + .of_map_mode = max77802_map_mode, \ } /* BUCK 5 */ #define regulator_77802_desc_buck5(num) { \ .name = "BUCK"#num, \ + .of_match = of_match_ptr("BUCK"#num), \ + .regulators_node = of_match_ptr("regulators"), \ .id = MAX77802_BUCK##num, \ .supply_name = "inb"#num, \ .ops = &max77802_buck_dvs_ops, \ @@ -382,11 +463,14 @@ static struct regulator_ops max77802_buck_dvs_ops = { .vsel_mask = MAX77802_VSEL_MASK, \ .enable_reg = MAX77802_REG_BUCK5CTRL, \ .enable_mask = MAX77802_OPMODE_MASK, \ + .of_map_mode = max77802_map_mode, \ } /* BUCKs 7-10 */ #define regulator_77802_desc_buck7_10(num) { \ .name = "BUCK"#num, \ + .of_match = of_match_ptr("BUCK"#num), \ + .regulators_node = of_match_ptr("regulators"), \ .id = MAX77802_BUCK##num, \ .supply_name = "inb"#num, \ .ops = &max77802_buck_dvs_ops, \ @@ -400,9 +484,10 @@ static struct regulator_ops max77802_buck_dvs_ops = { .vsel_mask = MAX77802_VSEL_MASK, \ .enable_reg = MAX77802_REG_BUCK7CTRL + (num - 7) * 3, \ .enable_mask = MAX77802_OPMODE_MASK, \ + .of_map_mode = max77802_map_mode, \ } -static struct regulator_desc regulators[] = { +static const struct regulator_desc regulators[] = { regulator_77802_desc_16_buck(1), regulator_77802_desc_234_buck(2), regulator_77802_desc_234_buck(3), @@ -447,85 +532,19 @@ static struct regulator_desc regulators[] = { regulator_77802_desc_n_ldo(35, 2, 1), }; -#ifdef CONFIG_OF -static int max77802_pmic_dt_parse_pdata(struct platform_device *pdev, - struct max77686_platform_data *pdata) -{ - struct max77686_dev *iodev = dev_get_drvdata(pdev->dev.parent); - struct device_node *pmic_np, *regulators_np; - struct max77686_regulator_data *rdata; - struct of_regulator_match rmatch = { }; - unsigned int i; - - pmic_np = iodev->dev->of_node; - 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; - } - - pdata->num_regulators = ARRAY_SIZE(regulators); - rdata = devm_kzalloc(&pdev->dev, sizeof(*rdata) * - pdata->num_regulators, GFP_KERNEL); - if (!rdata) { - of_node_put(regulators_np); - return -ENOMEM; - } - - for (i = 0; i < pdata->num_regulators; i++) { - rmatch.name = regulators[i].name; - rmatch.init_data = NULL; - rmatch.of_node = NULL; - if (of_regulator_match(&pdev->dev, regulators_np, &rmatch, - 1) != 1) { - dev_warn(&pdev->dev, "No matching regulator for '%s'\n", - rmatch.name); - continue; - } - rdata[i].initdata = rmatch.init_data; - rdata[i].of_node = rmatch.of_node; - rdata[i].id = regulators[i].id; - } - - pdata->regulators = rdata; - of_node_put(regulators_np); - - return 0; -} -#else -static int max77802_pmic_dt_parse_pdata(struct platform_device *pdev, - struct max77686_platform_data *pdata) -{ - return 0; -} -#endif /* CONFIG_OF */ - static int max77802_pmic_probe(struct platform_device *pdev) { struct max77686_dev *iodev = dev_get_drvdata(pdev->dev.parent); - struct max77686_platform_data *pdata = dev_get_platdata(iodev->dev); struct max77802_regulator_prv *max77802; - int i, ret = 0, val; + int i, val; struct regulator_config config = { }; - /* This is allocated by the MFD driver */ - if (!pdata) { - dev_err(&pdev->dev, "no platform data found for regulator\n"); - return -ENODEV; - } - max77802 = devm_kzalloc(&pdev->dev, sizeof(struct max77802_regulator_prv), GFP_KERNEL); if (!max77802) return -ENOMEM; - if (iodev->dev->of_node) { - ret = max77802_pmic_dt_parse_pdata(pdev, pdata); - if (ret) - return ret; - } - config.dev = iodev->dev; config.regmap = iodev->regmap; config.driver_data = max77802; @@ -533,21 +552,25 @@ static int max77802_pmic_probe(struct platform_device *pdev) for (i = 0; i < MAX77802_REG_MAX; i++) { struct regulator_dev *rdev; - int id = pdata->regulators[i].id; + int id = regulators[i].id; int shift = max77802_get_opmode_shift(id); - - config.init_data = pdata->regulators[i].initdata; - config.of_node = pdata->regulators[i].of_node; + int ret; ret = regmap_read(iodev->regmap, regulators[i].enable_reg, &val); - val = val >> shift & MAX77802_OPMODE_MASK; + if (ret < 0) { + dev_warn(&pdev->dev, + "cannot read current mode for %d\n", i); + val = MAX77802_OPMODE_NORMAL; + } else { + val = val >> shift & MAX77802_OPMODE_MASK; + } /* * If the regulator is disabled and the system warm rebooted, * the hardware reports OFF as the regulator operating mode. * Default to operating mode NORMAL in that case. */ - if (val == MAX77802_OPMODE_OFF) + if (val == MAX77802_STATUS_OFF) max77802->opmode[id] = MAX77802_OPMODE_NORMAL; else max77802->opmode[id] = val; @@ -555,9 +578,10 @@ static int max77802_pmic_probe(struct platform_device *pdev) rdev = devm_regulator_register(&pdev->dev, ®ulators[i], &config); if (IS_ERR(rdev)) { + ret = PTR_ERR(rdev); dev_err(&pdev->dev, - "regulator init failed for %d\n", i); - return PTR_ERR(rdev); + "regulator init failed for %d: %d\n", i, ret); + return ret; } } diff --git a/drivers/regulator/max8952.c b/drivers/regulator/max8952.c index f7f9efc..1af8f4a 100644 --- a/drivers/regulator/max8952.c +++ b/drivers/regulator/max8952.c @@ -174,7 +174,7 @@ static struct max8952_platform_data *max8952_parse_dt(struct device *dev) if (of_property_read_u32(np, "max8952,ramp-speed", &pd->ramp_speed)) dev_warn(dev, "max8952,ramp-speed property not specified, defaulting to 32mV/us\n"); - pd->reg_data = of_get_regulator_init_data(dev, np); + pd->reg_data = of_get_regulator_init_data(dev, np, ®ulator); if (!pd->reg_data) { dev_err(dev, "Failed to parse regulator init data\n"); return NULL; @@ -225,6 +225,8 @@ static int max8952_pmic_probe(struct i2c_client *client, config.of_node = client->dev.of_node; config.ena_gpio = pdata->gpio_en; + if (client->dev.of_node) + config.ena_gpio_initialized = true; if (pdata->reg_data->constraints.boot_on) config.ena_gpio_flags |= GPIOF_OUT_INIT_HIGH; diff --git a/drivers/regulator/max8973-regulator.c b/drivers/regulator/max8973-regulator.c index dbedf17..c3d55c2 100644 --- a/drivers/regulator/max8973-regulator.c +++ b/drivers/regulator/max8973-regulator.c @@ -458,7 +458,8 @@ static int max8973_probe(struct i2c_client *client, config.dev = &client->dev; config.init_data = pdata ? pdata->reg_init_data : - of_get_regulator_init_data(&client->dev, client->dev.of_node); + of_get_regulator_init_data(&client->dev, client->dev.of_node, + &max->desc); config.driver_data = max; config.of_node = client->dev.of_node; config.regmap = max->regmap; diff --git a/drivers/regulator/max8997.c b/drivers/regulator/max8997.c index 9c31e21..726fde1 100644 --- a/drivers/regulator/max8997.c +++ b/drivers/regulator/max8997.c @@ -953,7 +953,8 @@ static int max8997_pmic_dt_parse_pdata(struct platform_device *pdev, rdata->id = i; rdata->initdata = of_get_regulator_init_data(&pdev->dev, - reg_np); + reg_np, + ®ulators[i]); rdata->reg_node = reg_np; rdata++; } diff --git a/drivers/regulator/max8998.c b/drivers/regulator/max8998.c index 961091b..59e34a0 100644 --- a/drivers/regulator/max8998.c +++ b/drivers/regulator/max8998.c @@ -686,8 +686,9 @@ static int max8998_pmic_dt_parse_pdata(struct max8998_dev *iodev, continue; rdata->id = regulators[i].id; - rdata->initdata = of_get_regulator_init_data( - iodev->dev, reg_np); + rdata->initdata = of_get_regulator_init_data(iodev->dev, + reg_np, + ®ulators[i]); rdata->reg_node = reg_np; ++rdata; } diff --git a/drivers/regulator/mc13xxx-regulator-core.c b/drivers/regulator/mc13xxx-regulator-core.c index afba024..0281c31 100644 --- a/drivers/regulator/mc13xxx-regulator-core.c +++ b/drivers/regulator/mc13xxx-regulator-core.c @@ -194,7 +194,8 @@ struct mc13xxx_regulator_init_data *mc13xxx_parse_regulators_dt( regulators[i].desc.name)) { p->id = i; p->init_data = of_get_regulator_init_data( - &pdev->dev, child); + &pdev->dev, child, + ®ulators[i].desc); p->node = child; p++; diff --git a/drivers/regulator/of_regulator.c b/drivers/regulator/of_regulator.c index 5a1d4af..91eaaf0 100644 --- a/drivers/regulator/of_regulator.c +++ b/drivers/regulator/of_regulator.c @@ -19,12 +19,20 @@ #include "internal.h" +static const char *const regulator_states[PM_SUSPEND_MAX + 1] = { + [PM_SUSPEND_MEM] = "regulator-state-mem", + [PM_SUSPEND_MAX] = "regulator-state-disk", +}; + static void of_get_regulation_constraints(struct device_node *np, - struct regulator_init_data **init_data) + struct regulator_init_data **init_data, + const struct regulator_desc *desc) { const __be32 *min_uV, *max_uV; struct regulation_constraints *constraints = &(*init_data)->constraints; - int ret; + struct regulator_state *suspend_state; + struct device_node *suspend_np; + int ret, i; u32 pval; constraints->name = of_get_property(np, "regulator-name", NULL); @@ -73,18 +81,84 @@ static void of_get_regulation_constraints(struct device_node *np, ret = of_property_read_u32(np, "regulator-enable-ramp-delay", &pval); if (!ret) constraints->enable_time = pval; + + if (!of_property_read_u32(np, "regulator-initial-mode", &pval)) { + if (desc && desc->of_map_mode) { + ret = desc->of_map_mode(pval); + if (ret == -EINVAL) + pr_err("%s: invalid mode %u\n", np->name, pval); + else + constraints->initial_mode = ret; + } else { + pr_warn("%s: mapping for mode %d not defined\n", + np->name, pval); + } + } + + for (i = 0; i < ARRAY_SIZE(regulator_states); i++) { + switch (i) { + case PM_SUSPEND_MEM: + suspend_state = &constraints->state_mem; + break; + case PM_SUSPEND_MAX: + suspend_state = &constraints->state_disk; + break; + case PM_SUSPEND_ON: + case PM_SUSPEND_FREEZE: + case PM_SUSPEND_STANDBY: + default: + continue; + }; + + suspend_np = of_get_child_by_name(np, regulator_states[i]); + if (!suspend_np || !suspend_state) + continue; + + if (!of_property_read_u32(suspend_np, "regulator-mode", + &pval)) { + if (desc && desc->of_map_mode) { + ret = desc->of_map_mode(pval); + if (ret == -EINVAL) + pr_err("%s: invalid mode %u\n", + np->name, pval); + else + suspend_state->mode = ret; + } else { + pr_warn("%s: mapping for mode %d not defined\n", + np->name, pval); + } + } + + if (of_property_read_bool(suspend_np, + "regulator-on-in-suspend")) + suspend_state->enabled = true; + else if (of_property_read_bool(suspend_np, + "regulator-off-in-suspend")) + suspend_state->disabled = true; + + if (!of_property_read_u32(suspend_np, + "regulator-suspend-microvolt", &pval)) + suspend_state->uV = pval; + + of_node_put(suspend_np); + suspend_state = NULL; + suspend_np = NULL; + } } /** * of_get_regulator_init_data - extract regulator_init_data structure info * @dev: device requesting for regulator_init_data + * @node: regulator device node + * @desc: regulator description * * Populates regulator_init_data structure by extracting data from device * tree node, returns a pointer to the populated struture or NULL if memory * alloc fails. */ struct regulator_init_data *of_get_regulator_init_data(struct device *dev, - struct device_node *node) + struct device_node *node, + const struct regulator_desc *desc) { struct regulator_init_data *init_data; @@ -95,7 +169,7 @@ struct regulator_init_data *of_get_regulator_init_data(struct device *dev, if (!init_data) return NULL; /* Out of memory? */ - of_get_regulation_constraints(node, &init_data); + of_get_regulation_constraints(node, &init_data, desc); return init_data; } EXPORT_SYMBOL_GPL(of_get_regulator_init_data); @@ -176,7 +250,8 @@ int of_regulator_match(struct device *dev, struct device_node *node, continue; match->init_data = - of_get_regulator_init_data(dev, child); + of_get_regulator_init_data(dev, child, + match->desc); if (!match->init_data) { dev_err(dev, "failed to parse DT for regulator %s\n", @@ -224,7 +299,7 @@ struct regulator_init_data *regulator_of_get_init_data(struct device *dev, if (strcmp(desc->of_match, name)) continue; - init_data = of_get_regulator_init_data(dev, child); + init_data = of_get_regulator_init_data(dev, child, desc); if (!init_data) { dev_err(dev, "failed to parse DT for regulator %s\n", diff --git a/drivers/regulator/pwm-regulator.c b/drivers/regulator/pwm-regulator.c index d3f55ea..91f34ca 100644 --- a/drivers/regulator/pwm-regulator.c +++ b/drivers/regulator/pwm-regulator.c @@ -149,7 +149,8 @@ static int pwm_regulator_probe(struct platform_device *pdev) return ret; } - config.init_data = of_get_regulator_init_data(&pdev->dev, np); + config.init_data = of_get_regulator_init_data(&pdev->dev, np, + &drvdata->desc); if (!config.init_data) return -ENOMEM; diff --git a/drivers/regulator/qcom_rpm-regulator.c b/drivers/regulator/qcom_rpm-regulator.c index b55cd5b..dabd28a 100644 --- a/drivers/regulator/qcom_rpm-regulator.c +++ b/drivers/regulator/qcom_rpm-regulator.c @@ -643,10 +643,6 @@ static int rpm_reg_probe(struct platform_device *pdev) match = of_match_device(rpm_of_match, &pdev->dev); template = match->data; - initdata = of_get_regulator_init_data(&pdev->dev, pdev->dev.of_node); - if (!initdata) - return -EINVAL; - vreg = devm_kmalloc(&pdev->dev, sizeof(*vreg), GFP_KERNEL); if (!vreg) { dev_err(&pdev->dev, "failed to allocate vreg\n"); @@ -666,6 +662,11 @@ static int rpm_reg_probe(struct platform_device *pdev) return -ENODEV; } + initdata = of_get_regulator_init_data(&pdev->dev, pdev->dev.of_node, + &vreg->desc); + if (!initdata) + return -EINVAL; + key = "reg"; ret = of_property_read_u32(pdev->dev.of_node, key, &val); if (ret) { diff --git a/drivers/regulator/rk808-regulator.c b/drivers/regulator/rk808-regulator.c index 196a5c8..ea9d05e 100644 --- a/drivers/regulator/rk808-regulator.c +++ b/drivers/regulator/rk808-regulator.c @@ -36,6 +36,12 @@ #define RK808_RAMP_RATE_6MV_PER_US (2 << RK808_RAMP_RATE_OFFSET) #define RK808_RAMP_RATE_10MV_PER_US (3 << RK808_RAMP_RATE_OFFSET) +/* Offset from XXX_ON_VSEL to XXX_SLP_VSEL */ +#define RK808_SLP_REG_OFFSET 1 + +/* Offset from XXX_EN_REG to SLEEP_SET_OFF_XXX */ +#define RK808_SLP_SET_OFF_REG_OFFSET 2 + static const int rk808_buck_config_regs[] = { RK808_BUCK1_CONFIG_REG, RK808_BUCK2_CONFIG_REG, @@ -91,6 +97,43 @@ static int rk808_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay) RK808_RAMP_RATE_MASK, ramp_value); } +int rk808_set_suspend_voltage(struct regulator_dev *rdev, int uv) +{ + unsigned int reg; + int sel = regulator_map_voltage_linear_range(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); +} + +int rk808_set_suspend_enable(struct regulator_dev *rdev) +{ + unsigned int reg; + + reg = rdev->desc->enable_reg + RK808_SLP_SET_OFF_REG_OFFSET; + + return regmap_update_bits(rdev->regmap, reg, + rdev->desc->enable_mask, + 0); +} + +int rk808_set_suspend_disable(struct regulator_dev *rdev) +{ + unsigned int reg; + + reg = rdev->desc->enable_reg + RK808_SLP_SET_OFF_REG_OFFSET; + + return regmap_update_bits(rdev->regmap, reg, + rdev->desc->enable_mask, + rdev->desc->enable_mask); +} + static struct regulator_ops rk808_buck1_2_ops = { .list_voltage = regulator_list_voltage_linear_range, .map_voltage = regulator_map_voltage_linear_range, @@ -100,6 +143,9 @@ static struct regulator_ops rk808_buck1_2_ops = { .disable = regulator_disable_regmap, .is_enabled = regulator_is_enabled_regmap, .set_ramp_delay = rk808_set_ramp_delay, + .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 = { @@ -110,12 +156,17 @@ 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_enable = rk808_set_suspend_enable, + .set_suspend_disable = rk808_set_suspend_disable, }; static struct regulator_ops rk808_switch_ops = { - .enable = regulator_enable_regmap, - .disable = regulator_disable_regmap, - .is_enabled = regulator_is_enabled_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .set_suspend_enable = rk808_set_suspend_enable, + .set_suspend_disable = rk808_set_suspend_disable, }; static const struct regulator_desc rk808_reg[] = { diff --git a/drivers/regulator/s2mps11.c b/drivers/regulator/s2mps11.c index adab82d..b4ae022 100644 --- a/drivers/regulator/s2mps11.c +++ b/drivers/regulator/s2mps11.c @@ -886,6 +886,7 @@ common_reg: config.regmap = iodev->regmap_pmic; config.driver_data = s2mps11; config.ena_gpio_flags = GPIOF_OUT_INIT_HIGH; + config.ena_gpio_initialized = true; for (i = 0; i < s2mps11->rdev_num; i++) { struct regulator_dev *regulator; diff --git a/drivers/regulator/s5m8767.c b/drivers/regulator/s5m8767.c index 0ab5cbe..dc1328c 100644 --- a/drivers/regulator/s5m8767.c +++ b/drivers/regulator/s5m8767.c @@ -581,7 +581,8 @@ static int s5m8767_pmic_dt_parse_pdata(struct platform_device *pdev, rdata->id = i; rdata->initdata = of_get_regulator_init_data( - &pdev->dev, reg_np); + &pdev->dev, reg_np, + ®ulators[i]); rdata->reg_node = reg_np; rdata++; rmode->id = i; @@ -950,6 +951,7 @@ static int s5m8767_pmic_probe(struct platform_device *pdev) config.of_node = pdata->regulators[i].reg_node; config.ena_gpio = -EINVAL; config.ena_gpio_flags = 0; + config.ena_gpio_initialized = true; if (gpio_is_valid(pdata->regulators[i].ext_control_gpio)) s5m8767_regulator_config_ext_control(s5m8767, &pdata->regulators[i], &config); diff --git a/drivers/regulator/sky81452-regulator.c b/drivers/regulator/sky81452-regulator.c index 97aff0c..75deae7 100644 --- a/drivers/regulator/sky81452-regulator.c +++ b/drivers/regulator/sky81452-regulator.c @@ -76,7 +76,7 @@ static struct regulator_init_data *sky81452_reg_parse_dt(struct device *dev) return NULL; } - init_data = of_get_regulator_init_data(dev, np); + init_data = of_get_regulator_init_data(dev, np, &sky81452_reg); of_node_put(np); return init_data; diff --git a/drivers/regulator/stw481x-vmmc.c b/drivers/regulator/stw481x-vmmc.c index a7e1526..b4f1696 100644 --- a/drivers/regulator/stw481x-vmmc.c +++ b/drivers/regulator/stw481x-vmmc.c @@ -72,7 +72,8 @@ static int stw481x_vmmc_regulator_probe(struct platform_device *pdev) config.regmap = stw481x->map; config.of_node = pdev->dev.of_node; config.init_data = of_get_regulator_init_data(&pdev->dev, - pdev->dev.of_node); + pdev->dev.of_node, + &vmmc_regulator); stw481x->vmmc_regulator = devm_regulator_register(&pdev->dev, &vmmc_regulator, &config); diff --git a/drivers/regulator/ti-abb-regulator.c b/drivers/regulator/ti-abb-regulator.c index a2dabb5..1ef5aba 100644 --- a/drivers/regulator/ti-abb-regulator.c +++ b/drivers/regulator/ti-abb-regulator.c @@ -837,7 +837,8 @@ skip_opt: return -EINVAL; } - initdata = of_get_regulator_init_data(dev, pdev->dev.of_node); + initdata = of_get_regulator_init_data(dev, pdev->dev.of_node, + &abb->rdesc); if (!initdata) { dev_err(dev, "%s: Unable to alloc regulator init data\n", __func__); diff --git a/drivers/regulator/tps51632-regulator.c b/drivers/regulator/tps51632-regulator.c index f31f22e..c213e37 100644 --- a/drivers/regulator/tps51632-regulator.c +++ b/drivers/regulator/tps51632-regulator.c @@ -221,7 +221,8 @@ static const struct of_device_id tps51632_of_match[] = { MODULE_DEVICE_TABLE(of, tps51632_of_match); static struct tps51632_regulator_platform_data * - of_get_tps51632_platform_data(struct device *dev) + of_get_tps51632_platform_data(struct device *dev, + const struct regulator_desc *desc) { struct tps51632_regulator_platform_data *pdata; struct device_node *np = dev->of_node; @@ -230,7 +231,8 @@ static struct tps51632_regulator_platform_data * if (!pdata) return NULL; - pdata->reg_init_data = of_get_regulator_init_data(dev, dev->of_node); + pdata->reg_init_data = of_get_regulator_init_data(dev, dev->of_node, + desc); if (!pdata->reg_init_data) { dev_err(dev, "Not able to get OF regulator init data\n"); return NULL; @@ -248,7 +250,8 @@ static struct tps51632_regulator_platform_data * } #else static struct tps51632_regulator_platform_data * - of_get_tps51632_platform_data(struct device *dev) + of_get_tps51632_platform_data(struct device *dev, + const struct regulator_desc *desc) { return NULL; } @@ -273,9 +276,25 @@ static int tps51632_probe(struct i2c_client *client, } } + tps = devm_kzalloc(&client->dev, sizeof(*tps), GFP_KERNEL); + if (!tps) + return -ENOMEM; + + tps->dev = &client->dev; + tps->desc.name = client->name; + tps->desc.id = 0; + tps->desc.ramp_delay = TPS51632_DEFAULT_RAMP_DELAY; + tps->desc.min_uV = TPS51632_MIN_VOLTAGE; + tps->desc.uV_step = TPS51632_VOLTAGE_STEP_10mV; + tps->desc.linear_min_sel = TPS51632_MIN_VSEL; + tps->desc.n_voltages = TPS51632_MAX_VSEL + 1; + tps->desc.ops = &tps51632_dcdc_ops; + tps->desc.type = REGULATOR_VOLTAGE; + tps->desc.owner = THIS_MODULE; + pdata = dev_get_platdata(&client->dev); if (!pdata && client->dev.of_node) - pdata = of_get_tps51632_platform_data(&client->dev); + pdata = of_get_tps51632_platform_data(&client->dev, &tps->desc); if (!pdata) { dev_err(&client->dev, "No Platform data\n"); return -EINVAL; @@ -296,22 +315,6 @@ static int tps51632_probe(struct i2c_client *client, } } - tps = devm_kzalloc(&client->dev, sizeof(*tps), GFP_KERNEL); - if (!tps) - return -ENOMEM; - - tps->dev = &client->dev; - tps->desc.name = client->name; - tps->desc.id = 0; - tps->desc.ramp_delay = TPS51632_DEFAULT_RAMP_DELAY; - tps->desc.min_uV = TPS51632_MIN_VOLTAGE; - tps->desc.uV_step = TPS51632_VOLTAGE_STEP_10mV; - tps->desc.linear_min_sel = TPS51632_MIN_VSEL; - tps->desc.n_voltages = TPS51632_MAX_VSEL + 1; - tps->desc.ops = &tps51632_dcdc_ops; - tps->desc.type = REGULATOR_VOLTAGE; - tps->desc.owner = THIS_MODULE; - if (pdata->enable_pwm_dvfs) tps->desc.vsel_reg = TPS51632_VOLTAGE_BASE_REG; else diff --git a/drivers/regulator/tps62360-regulator.c b/drivers/regulator/tps62360-regulator.c index a167204..a1fd626 100644 --- a/drivers/regulator/tps62360-regulator.c +++ b/drivers/regulator/tps62360-regulator.c @@ -293,7 +293,8 @@ static const struct regmap_config tps62360_regmap_config = { }; static struct tps62360_regulator_platform_data * - of_get_tps62360_platform_data(struct device *dev) + of_get_tps62360_platform_data(struct device *dev, + const struct regulator_desc *desc) { struct tps62360_regulator_platform_data *pdata; struct device_node *np = dev->of_node; @@ -302,7 +303,8 @@ static struct tps62360_regulator_platform_data * if (!pdata) return NULL; - pdata->reg_init_data = of_get_regulator_init_data(dev, dev->of_node); + pdata->reg_init_data = of_get_regulator_init_data(dev, dev->of_node, + desc); if (!pdata->reg_init_data) { dev_err(dev, "Not able to get OF regulator init data\n"); return NULL; @@ -350,6 +352,17 @@ static int tps62360_probe(struct i2c_client *client, pdata = dev_get_platdata(&client->dev); + tps = devm_kzalloc(&client->dev, sizeof(*tps), GFP_KERNEL); + if (!tps) + return -ENOMEM; + + tps->desc.name = client->name; + tps->desc.id = 0; + tps->desc.ops = &tps62360_dcdc_ops; + tps->desc.type = REGULATOR_VOLTAGE; + tps->desc.owner = THIS_MODULE; + tps->desc.uV_step = 10000; + if (client->dev.of_node) { const struct of_device_id *match; match = of_match_device(of_match_ptr(tps62360_of_match), @@ -360,7 +373,8 @@ static int tps62360_probe(struct i2c_client *client, } chip_id = (int)(long)match->data; if (!pdata) - pdata = of_get_tps62360_platform_data(&client->dev); + pdata = of_get_tps62360_platform_data(&client->dev, + &tps->desc); } else if (id) { chip_id = id->driver_data; } else { @@ -374,10 +388,6 @@ static int tps62360_probe(struct i2c_client *client, return -EIO; } - tps = devm_kzalloc(&client->dev, sizeof(*tps), GFP_KERNEL); - if (!tps) - return -ENOMEM; - tps->en_discharge = pdata->en_discharge; tps->en_internal_pulldn = pdata->en_internal_pulldn; tps->vsel0_gpio = pdata->vsel0_gpio; @@ -401,13 +411,6 @@ static int tps62360_probe(struct i2c_client *client, return -ENODEV; } - tps->desc.name = client->name; - tps->desc.id = 0; - tps->desc.ops = &tps62360_dcdc_ops; - tps->desc.type = REGULATOR_VOLTAGE; - tps->desc.owner = THIS_MODULE; - tps->desc.uV_step = 10000; - tps->regmap = devm_regmap_init_i2c(client, &tps62360_regmap_config); if (IS_ERR(tps->regmap)) { ret = PTR_ERR(tps->regmap); diff --git a/drivers/regulator/tps65090-regulator.c b/drivers/regulator/tps65090-regulator.c index d5df1e9..f1df442 100644 --- a/drivers/regulator/tps65090-regulator.c +++ b/drivers/regulator/tps65090-regulator.c @@ -312,7 +312,11 @@ static void tps65090_configure_regulator_config( gpio_flag = GPIOF_OUT_INIT_HIGH; config->ena_gpio = tps_pdata->gpio; + config->ena_gpio_initialized = true; config->ena_gpio_flags = gpio_flag; + } else { + config->ena_gpio = -EINVAL; + config->ena_gpio_initialized = false; } } diff --git a/drivers/regulator/tps65218-regulator.c b/drivers/regulator/tps65218-regulator.c index f0a4028..263cc85 100644 --- a/drivers/regulator/tps65218-regulator.c +++ b/drivers/regulator/tps65218-regulator.c @@ -231,7 +231,8 @@ static int tps65218_regulator_probe(struct platform_device *pdev) template = match->data; id = template->id; - init_data = of_get_regulator_init_data(&pdev->dev, pdev->dev.of_node); + init_data = of_get_regulator_init_data(&pdev->dev, pdev->dev.of_node, + ®ulators[id]); platform_set_drvdata(pdev, tps); diff --git a/drivers/regulator/twl-regulator.c b/drivers/regulator/twl-regulator.c index 0b4f866..dd727bc 100644 --- a/drivers/regulator/twl-regulator.c +++ b/drivers/regulator/twl-regulator.c @@ -1104,7 +1104,8 @@ static int twlreg_probe(struct platform_device *pdev) template = match->data; id = template->desc.id; initdata = of_get_regulator_init_data(&pdev->dev, - pdev->dev.of_node); + pdev->dev.of_node, + &template->desc); drvdata = NULL; } else { id = pdev->id; diff --git a/drivers/regulator/vexpress.c b/drivers/regulator/vexpress.c index 02e7267..5e7c789 100644 --- a/drivers/regulator/vexpress.c +++ b/drivers/regulator/vexpress.c @@ -74,7 +74,8 @@ static int vexpress_regulator_probe(struct platform_device *pdev) reg->desc.owner = THIS_MODULE; reg->desc.continuous_voltage_range = true; - init_data = of_get_regulator_init_data(&pdev->dev, pdev->dev.of_node); + init_data = of_get_regulator_init_data(&pdev->dev, pdev->dev.of_node, + ®->desc); if (!init_data) return -EINVAL; diff --git a/drivers/regulator/wm8994-regulator.c b/drivers/regulator/wm8994-regulator.c index c24346d..88f5064 100644 --- a/drivers/regulator/wm8994-regulator.c +++ b/drivers/regulator/wm8994-regulator.c @@ -145,10 +145,12 @@ static int wm8994_ldo_probe(struct platform_device *pdev) config.driver_data = ldo; config.regmap = wm8994->regmap; config.init_data = &ldo->init_data; - if (pdata) + if (pdata) { config.ena_gpio = pdata->ldo[id].enable; - else if (wm8994->dev->of_node) + } else if (wm8994->dev->of_node) { config.ena_gpio = wm8994->pdata.ldo[id].enable; + config.ena_gpio_initialized = true; + } /* Use default constraints if none set up */ if (!pdata || !pdata->ldo[id].init_data || wm8994->dev->of_node) { |