diff options
-rw-r--r-- | Documentation/devicetree/bindings/regulator/mt6315-regulator.yaml | 6 | ||||
-rw-r--r-- | Documentation/devicetree/bindings/regulator/nxp,pca9450-regulator.yaml | 1 | ||||
-rw-r--r-- | Documentation/devicetree/bindings/regulator/regulator.yaml | 3 | ||||
-rw-r--r-- | drivers/regulator/bd96801-regulator.c | 130 | ||||
-rw-r--r-- | drivers/regulator/core.c | 153 | ||||
-rw-r--r-- | drivers/regulator/of_regulator.c | 17 | ||||
-rw-r--r-- | drivers/regulator/pca9450-regulator.c | 111 | ||||
-rw-r--r-- | drivers/regulator/tps65219-regulator.c | 39 | ||||
-rw-r--r-- | include/linux/regulator/consumer.h | 21 | ||||
-rw-r--r-- | include/linux/regulator/driver.h | 2 | ||||
-rw-r--r-- | include/linux/regulator/machine.h | 2 | ||||
-rw-r--r-- | include/linux/regulator/pca9450.h | 1 |
12 files changed, 373 insertions, 113 deletions
diff --git a/Documentation/devicetree/bindings/regulator/mt6315-regulator.yaml b/Documentation/devicetree/bindings/regulator/mt6315-regulator.yaml index cd4aa27218a1..fa6743bb269d 100644 --- a/Documentation/devicetree/bindings/regulator/mt6315-regulator.yaml +++ b/Documentation/devicetree/bindings/regulator/mt6315-regulator.yaml @@ -35,10 +35,6 @@ properties: $ref: regulator.yaml# unevaluatedProperties: false - properties: - regulator-compatible: - pattern: "^vbuck[1-4]$" - additionalProperties: false required: @@ -56,7 +52,6 @@ examples: regulators { vbuck1 { - regulator-compatible = "vbuck1"; regulator-min-microvolt = <300000>; regulator-max-microvolt = <1193750>; regulator-enable-ramp-delay = <256>; @@ -64,7 +59,6 @@ examples: }; vbuck3 { - regulator-compatible = "vbuck3"; regulator-min-microvolt = <300000>; regulator-max-microvolt = <1193750>; regulator-enable-ramp-delay = <256>; diff --git a/Documentation/devicetree/bindings/regulator/nxp,pca9450-regulator.yaml b/Documentation/devicetree/bindings/regulator/nxp,pca9450-regulator.yaml index f8057bba747a..68709a7dc43f 100644 --- a/Documentation/devicetree/bindings/regulator/nxp,pca9450-regulator.yaml +++ b/Documentation/devicetree/bindings/regulator/nxp,pca9450-regulator.yaml @@ -29,6 +29,7 @@ properties: - nxp,pca9450b - nxp,pca9450c - nxp,pca9451a + - nxp,pca9452 reg: maxItems: 1 diff --git a/Documentation/devicetree/bindings/regulator/regulator.yaml b/Documentation/devicetree/bindings/regulator/regulator.yaml index 1ef380d1515e..77573bcb6b79 100644 --- a/Documentation/devicetree/bindings/regulator/regulator.yaml +++ b/Documentation/devicetree/bindings/regulator/regulator.yaml @@ -34,6 +34,9 @@ properties: regulator-input-current-limit-microamp: description: maximum input current regulator allows + regulator-power-budget-milliwatt: + description: power budget of the regulator + regulator-always-on: description: boolean, regulator should never be disabled type: boolean diff --git a/drivers/regulator/bd96801-regulator.c b/drivers/regulator/bd96801-regulator.c index 9876cc05867e..3a9d772491a8 100644 --- a/drivers/regulator/bd96801-regulator.c +++ b/drivers/regulator/bd96801-regulator.c @@ -5,12 +5,7 @@ /* * This version of the "BD86801 scalable PMIC"'s driver supports only very * basic set of the PMIC features. Most notably, there is no support for - * the ERRB interrupt and the configurations which should be done when the - * PMIC is in STBY mode. - * - * Supporting the ERRB interrupt would require dropping the regmap-IRQ - * usage or working around (or accepting a presense of) a naming conflict - * in debugFS IRQs. + * the configurations which should be done when the PMIC is in STBY mode. * * Being able to reliably do the configurations like changing the * regulator safety limits (like limits for the over/under -voltages, over @@ -22,16 +17,14 @@ * be the need to configure these safety limits. Hence it's not simple to * come up with a generic solution. * - * Users who require the ERRB handling and STBY state configurations can - * have a look at the original RFC: + * Users who require the STBY state configurations can have a look at the + * original RFC: * https://lore.kernel.org/all/cover.1712920132.git.mazziesaccount@gmail.com/ - * which implements a workaround to debugFS naming conflict and some of - * the safety limit configurations - but leaves the state change handling - * and synchronization to be implemented. + * which implements some of the safety limit configurations - but leaves the + * state change handling and synchronization to be implemented. * * It would be great to hear (and receive a patch!) if you implement the - * STBY configuration support or a proper fix to the debugFS naming - * conflict in your downstream driver ;) + * STBY configuration support in your downstream driver ;) */ #include <linux/cleanup.h> @@ -728,6 +721,95 @@ static int initialize_pmic_data(struct device *dev, return 0; } +static int bd96801_map_event_all(int irq, struct regulator_irq_data *rid, + unsigned long *dev_mask) +{ + int i; + + for (i = 0; i < rid->num_states; i++) { + rid->states[i].notifs = REGULATOR_EVENT_FAIL; + rid->states[i].errors = REGULATOR_ERROR_FAIL; + *dev_mask |= BIT(i); + } + + return 0; +} + +static int bd96801_rdev_errb_irqs(struct platform_device *pdev, + struct regulator_dev *rdev) +{ + int i; + void *retp; + static const char * const single_out_errb_irqs[] = { + "bd96801-%s-pvin-err", "bd96801-%s-ovp-err", + "bd96801-%s-uvp-err", "bd96801-%s-shdn-err", + }; + + for (i = 0; i < ARRAY_SIZE(single_out_errb_irqs); i++) { + struct regulator_irq_desc id = { + .map_event = bd96801_map_event_all, + .irq_off_ms = 1000, + }; + struct regulator_dev *rdev_arr[1]; + char tmp[255]; + int irq; + + snprintf(tmp, 255, single_out_errb_irqs[i], rdev->desc->name); + tmp[254] = 0; + id.name = tmp; + + irq = platform_get_irq_byname(pdev, tmp); + if (irq < 0) + continue; + + rdev_arr[0] = rdev; + retp = devm_regulator_irq_helper(&pdev->dev, &id, irq, 0, + REGULATOR_ERROR_FAIL, NULL, + rdev_arr, 1); + if (IS_ERR(retp)) + return PTR_ERR(retp); + + } + return 0; +} + +static int bd96801_global_errb_irqs(struct platform_device *pdev, + struct regulator_dev **rdev, int num_rdev) +{ + int i, num_irqs; + void *retp; + static const char * const global_errb_irqs[] = { + "bd96801-otp-err", "bd96801-dbist-err", "bd96801-eep-err", + "bd96801-abist-err", "bd96801-prstb-err", "bd96801-drmoserr1", + "bd96801-drmoserr2", "bd96801-slave-err", "bd96801-vref-err", + "bd96801-tsd", "bd96801-uvlo-err", "bd96801-ovlo-err", + "bd96801-osc-err", "bd96801-pon-err", "bd96801-poff-err", + "bd96801-cmd-shdn-err", "bd96801-int-shdn-err" + }; + + num_irqs = ARRAY_SIZE(global_errb_irqs); + for (i = 0; i < num_irqs; i++) { + int irq; + struct regulator_irq_desc id = { + .name = global_errb_irqs[i], + .map_event = bd96801_map_event_all, + .irq_off_ms = 1000, + }; + + irq = platform_get_irq_byname(pdev, global_errb_irqs[i]); + if (irq < 0) + continue; + + retp = devm_regulator_irq_helper(&pdev->dev, &id, irq, 0, + REGULATOR_ERROR_FAIL, NULL, + rdev, num_rdev); + if (IS_ERR(retp)) + return PTR_ERR(retp); + } + + return 0; +} + static int bd96801_rdev_intb_irqs(struct platform_device *pdev, struct bd96801_pmic_data *pdata, struct bd96801_irqinfo *iinfo, @@ -783,11 +865,10 @@ static int bd96801_rdev_intb_irqs(struct platform_device *pdev, return 0; } - - static int bd96801_probe(struct platform_device *pdev) { struct regulator_dev *ldo_errs_rdev_arr[BD96801_NUM_LDOS]; + struct regulator_dev *all_rdevs[BD96801_NUM_REGULATORS]; struct bd96801_regulator_data *rdesc; struct regulator_config config = {}; int ldo_errs_arr[BD96801_NUM_LDOS]; @@ -795,6 +876,7 @@ static int bd96801_probe(struct platform_device *pdev) int temp_notif_ldos = 0; struct device *parent; int i, ret; + bool use_errb; void *retp; parent = pdev->dev.parent; @@ -819,6 +901,13 @@ static int bd96801_probe(struct platform_device *pdev) config.regmap = pdata->regmap; config.dev = parent; + ret = of_property_match_string(pdev->dev.parent->of_node, + "interrupt-names", "errb"); + if (ret < 0) + use_errb = false; + else + use_errb = true; + ret = bd96801_walk_regulator_dt(&pdev->dev, pdata->regmap, rdesc, BD96801_NUM_REGULATORS); if (ret) @@ -837,6 +926,7 @@ static int bd96801_probe(struct platform_device *pdev) rdesc[i].desc.name); return PTR_ERR(rdev); } + all_rdevs[i] = rdev; /* * LDOs don't have own temperature monitoring. If temperature * notification was requested for this LDO from DT then we will @@ -856,6 +946,12 @@ static int bd96801_probe(struct platform_device *pdev) if (ret) return ret; } + /* Register per regulator ERRB notifiers */ + if (use_errb) { + ret = bd96801_rdev_errb_irqs(pdev, rdev); + if (ret) + return ret; + } } if (temp_notif_ldos) { int irq; @@ -877,6 +973,10 @@ static int bd96801_probe(struct platform_device *pdev) return PTR_ERR(retp); } + if (use_errb) + return bd96801_global_errb_irqs(pdev, all_rdevs, + ARRAY_SIZE(all_rdevs)); + return 0; } diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 8cb948a91e60..6c0ef1182248 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -917,6 +917,26 @@ static ssize_t bypass_show(struct device *dev, } static DEVICE_ATTR_RO(bypass); +static ssize_t power_budget_milliwatt_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct regulator_dev *rdev = dev_get_drvdata(dev); + + return sprintf(buf, "%d\n", rdev->constraints->pw_budget_mW); +} +static DEVICE_ATTR_RO(power_budget_milliwatt); + +static ssize_t power_requested_milliwatt_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct regulator_dev *rdev = dev_get_drvdata(dev); + + return sprintf(buf, "%d\n", rdev->pw_requested_mW); +} +static DEVICE_ATTR_RO(power_requested_milliwatt); + #define REGULATOR_ERROR_ATTR(name, bit) \ static ssize_t name##_show(struct device *dev, struct device_attribute *attr, \ char *buf) \ @@ -1149,6 +1169,10 @@ static void print_constraints_debug(struct regulator_dev *rdev) if (constraints->valid_modes_mask & REGULATOR_MODE_STANDBY) count += scnprintf(buf + count, len - count, "standby "); + if (constraints->pw_budget_mW) + count += scnprintf(buf + count, len - count, "%d mW budget", + constraints->pw_budget_mW); + if (!count) count = scnprintf(buf, len, "no parameters"); else @@ -1627,6 +1651,9 @@ static int set_machine_constraints(struct regulator_dev *rdev) rdev->last_off = ktime_get(); } + if (!rdev->constraints->pw_budget_mW) + rdev->constraints->pw_budget_mW = INT_MAX; + print_constraints(rdev); return 0; } @@ -1936,6 +1963,20 @@ static struct regulator_dev *regulator_lookup_by_name(const char *name) return dev ? dev_to_rdev(dev) : NULL; } +static struct regulator_dev *regulator_dt_lookup(struct device *dev, + const char *supply) +{ + struct regulator_dev *r = NULL; + + if (dev_of_node(dev)) { + r = of_regulator_dev_lookup(dev, dev_of_node(dev), supply); + if (PTR_ERR(r) == -ENODEV) + r = NULL; + } + + return r; +} + /** * regulator_dev_lookup - lookup a regulator device. * @dev: device for regulator "consumer". @@ -1960,16 +2001,9 @@ static struct regulator_dev *regulator_dev_lookup(struct device *dev, regulator_supply_alias(&dev, &supply); /* first do a dt based lookup */ - if (dev_of_node(dev)) { - r = of_regulator_dev_lookup(dev, dev_of_node(dev), supply); - if (!IS_ERR(r)) - return r; - if (PTR_ERR(r) == -EPROBE_DEFER) - return r; - - if (PTR_ERR(r) == -ENODEV) - r = NULL; - } + r = regulator_dt_lookup(dev, supply); + if (r) + return r; /* if not found, try doing it non-dt way */ if (dev) @@ -2015,7 +2049,17 @@ static int regulator_resolve_supply(struct regulator_dev *rdev) if (rdev->supply) return 0; - r = regulator_dev_lookup(dev, rdev->supply_name); + /* first do a dt based lookup on the node described in the virtual + * device. + */ + r = regulator_dt_lookup(&rdev->dev, rdev->supply_name); + + /* If regulator not found use usual search path in the parent + * device. + */ + if (!r) + r = regulator_dev_lookup(dev, rdev->supply_name); + if (IS_ERR(r)) { ret = PTR_ERR(r); @@ -4585,6 +4629,87 @@ int regulator_get_current_limit(struct regulator *regulator) EXPORT_SYMBOL_GPL(regulator_get_current_limit); /** + * regulator_get_unclaimed_power_budget - get regulator unclaimed power budget + * @regulator: regulator source + * + * Return: Unclaimed power budget of the regulator in mW. + */ +int regulator_get_unclaimed_power_budget(struct regulator *regulator) +{ + return regulator->rdev->constraints->pw_budget_mW - + regulator->rdev->pw_requested_mW; +} +EXPORT_SYMBOL_GPL(regulator_get_unclaimed_power_budget); + +/** + * regulator_request_power_budget - request power budget on a regulator + * @regulator: regulator source + * @pw_req: Power requested + * + * Return: 0 on success or a negative error number on failure. + */ +int regulator_request_power_budget(struct regulator *regulator, + unsigned int pw_req) +{ + struct regulator_dev *rdev = regulator->rdev; + int ret = 0, pw_tot_req; + + regulator_lock(rdev); + if (rdev->supply) { + ret = regulator_request_power_budget(rdev->supply, pw_req); + if (ret < 0) + goto out; + } + + pw_tot_req = rdev->pw_requested_mW + pw_req; + if (pw_tot_req > rdev->constraints->pw_budget_mW) { + rdev_warn(rdev, "power requested %d mW out of budget %d mW", + pw_req, + rdev->constraints->pw_budget_mW - rdev->pw_requested_mW); + regulator_notifier_call_chain(rdev, + REGULATOR_EVENT_OVER_CURRENT_WARN, + NULL); + ret = -ERANGE; + goto out; + } + + rdev->pw_requested_mW = pw_tot_req; +out: + regulator_unlock(rdev); + return ret; +} +EXPORT_SYMBOL_GPL(regulator_request_power_budget); + +/** + * regulator_free_power_budget - free power budget on a regulator + * @regulator: regulator source + * @pw: Power to be released. + * + * Return: Power budget of the regulator in mW. + */ +void regulator_free_power_budget(struct regulator *regulator, + unsigned int pw) +{ + struct regulator_dev *rdev = regulator->rdev; + int pw_tot_req; + + regulator_lock(rdev); + if (rdev->supply) + regulator_free_power_budget(rdev->supply, pw); + + pw_tot_req = rdev->pw_requested_mW - pw; + if (pw_tot_req >= 0) + rdev->pw_requested_mW = pw_tot_req; + else + rdev_warn(rdev, + "too much power freed %d mW (already requested %d mW)", + pw, rdev->pw_requested_mW); + + regulator_unlock(rdev); +} +EXPORT_SYMBOL_GPL(regulator_free_power_budget); + +/** * regulator_set_mode - set regulator operating mode * @regulator: regulator source * @mode: operating mode - one of the REGULATOR_MODE constants @@ -5222,6 +5347,8 @@ static struct attribute *regulator_dev_attrs[] = { &dev_attr_suspend_standby_mode.attr, &dev_attr_suspend_mem_mode.attr, &dev_attr_suspend_disk_mode.attr, + &dev_attr_power_budget_milliwatt.attr, + &dev_attr_power_requested_milliwatt.attr, NULL }; @@ -5303,6 +5430,10 @@ static umode_t regulator_attr_is_visible(struct kobject *kobj, attr == &dev_attr_suspend_disk_mode.attr) return ops->set_suspend_mode ? mode : 0; + if (attr == &dev_attr_power_budget_milliwatt.attr || + attr == &dev_attr_power_requested_milliwatt.attr) + return rdev->constraints->pw_budget_mW != INT_MAX ? mode : 0; + return mode; } diff --git a/drivers/regulator/of_regulator.c b/drivers/regulator/of_regulator.c index e5b4b93c07e3..011088c57891 100644 --- a/drivers/regulator/of_regulator.c +++ b/drivers/regulator/of_regulator.c @@ -125,6 +125,9 @@ static int of_get_regulation_constraints(struct device *dev, if (constraints->min_uA != constraints->max_uA) constraints->valid_ops_mask |= REGULATOR_CHANGE_CURRENT; + if (!of_property_read_u32(np, "regulator-power-budget-milliwatt", &pval)) + constraints->pw_budget_mW = pval; + constraints->boot_on = of_property_read_bool(np, "regulator-boot-on"); constraints->always_on = of_property_read_bool(np, "regulator-always-on"); if (!constraints->always_on) /* status change should be possible. */ @@ -446,7 +449,7 @@ int of_regulator_match(struct device *dev, struct device_node *node, "failed to parse DT for regulator %pOFn\n", child); of_node_put(child); - return -EINVAL; + goto err_put; } match->of_node = of_node_get(child); count++; @@ -455,6 +458,18 @@ int of_regulator_match(struct device *dev, struct device_node *node, } return count; + +err_put: + for (i = 0; i < num_matches; i++) { + struct of_regulator_match *match = &matches[i]; + + match->init_data = NULL; + if (match->of_node) { + of_node_put(match->of_node); + match->of_node = NULL; + } + } + return -EINVAL; } EXPORT_SYMBOL_GPL(of_regulator_match); diff --git a/drivers/regulator/pca9450-regulator.c b/drivers/regulator/pca9450-regulator.c index 9714afe347dc..faa6b79c27d7 100644 --- a/drivers/regulator/pca9450-regulator.c +++ b/drivers/regulator/pca9450-regulator.c @@ -247,6 +247,7 @@ static const struct pca9450_regulator_desc pca9450a_regulators[] = { .ramp_mask = BUCK1_RAMP_MASK, .ramp_delay_table = pca9450_dvs_buck_ramp_table, .n_ramp_values = ARRAY_SIZE(pca9450_dvs_buck_ramp_table), + .enable_val = BUCK_ENMODE_ONREQ, .owner = THIS_MODULE, .of_parse_cb = pca9450_set_dvs_levels, }, @@ -272,6 +273,7 @@ static const struct pca9450_regulator_desc pca9450a_regulators[] = { .vsel_mask = BUCK2OUT_DVS0_MASK, .enable_reg = PCA9450_REG_BUCK2CTRL, .enable_mask = BUCK2_ENMODE_MASK, + .enable_val = BUCK_ENMODE_ONREQ_STBYREQ, .ramp_reg = PCA9450_REG_BUCK2CTRL, .ramp_mask = BUCK2_RAMP_MASK, .ramp_delay_table = pca9450_dvs_buck_ramp_table, @@ -301,6 +303,7 @@ static const struct pca9450_regulator_desc pca9450a_regulators[] = { .vsel_mask = BUCK3OUT_DVS0_MASK, .enable_reg = PCA9450_REG_BUCK3CTRL, .enable_mask = BUCK3_ENMODE_MASK, + .enable_val = BUCK_ENMODE_ONREQ, .ramp_reg = PCA9450_REG_BUCK3CTRL, .ramp_mask = BUCK3_RAMP_MASK, .ramp_delay_table = pca9450_dvs_buck_ramp_table, @@ -330,6 +333,7 @@ static const struct pca9450_regulator_desc pca9450a_regulators[] = { .vsel_mask = BUCK4OUT_MASK, .enable_reg = PCA9450_REG_BUCK4CTRL, .enable_mask = BUCK4_ENMODE_MASK, + .enable_val = BUCK_ENMODE_ONREQ, .owner = THIS_MODULE, }, }, @@ -348,6 +352,7 @@ static const struct pca9450_regulator_desc pca9450a_regulators[] = { .vsel_mask = BUCK5OUT_MASK, .enable_reg = PCA9450_REG_BUCK5CTRL, .enable_mask = BUCK5_ENMODE_MASK, + .enable_val = BUCK_ENMODE_ONREQ, .owner = THIS_MODULE, }, }, @@ -366,6 +371,7 @@ static const struct pca9450_regulator_desc pca9450a_regulators[] = { .vsel_mask = BUCK6OUT_MASK, .enable_reg = PCA9450_REG_BUCK6CTRL, .enable_mask = BUCK6_ENMODE_MASK, + .enable_val = BUCK_ENMODE_ONREQ, .owner = THIS_MODULE, }, }, @@ -481,6 +487,7 @@ static const struct pca9450_regulator_desc pca9450bc_regulators[] = { .vsel_mask = BUCK1OUT_DVS0_MASK, .enable_reg = PCA9450_REG_BUCK1CTRL, .enable_mask = BUCK1_ENMODE_MASK, + .enable_val = BUCK_ENMODE_ONREQ, .ramp_reg = PCA9450_REG_BUCK1CTRL, .ramp_mask = BUCK1_RAMP_MASK, .ramp_delay_table = pca9450_dvs_buck_ramp_table, @@ -510,6 +517,7 @@ static const struct pca9450_regulator_desc pca9450bc_regulators[] = { .vsel_mask = BUCK2OUT_DVS0_MASK, .enable_reg = PCA9450_REG_BUCK2CTRL, .enable_mask = BUCK2_ENMODE_MASK, + .enable_val = BUCK_ENMODE_ONREQ_STBYREQ, .ramp_reg = PCA9450_REG_BUCK2CTRL, .ramp_mask = BUCK2_RAMP_MASK, .ramp_delay_table = pca9450_dvs_buck_ramp_table, @@ -539,6 +547,7 @@ static const struct pca9450_regulator_desc pca9450bc_regulators[] = { .vsel_mask = BUCK4OUT_MASK, .enable_reg = PCA9450_REG_BUCK4CTRL, .enable_mask = BUCK4_ENMODE_MASK, + .enable_val = BUCK_ENMODE_ONREQ, .owner = THIS_MODULE, }, }, @@ -557,6 +566,7 @@ static const struct pca9450_regulator_desc pca9450bc_regulators[] = { .vsel_mask = BUCK5OUT_MASK, .enable_reg = PCA9450_REG_BUCK5CTRL, .enable_mask = BUCK5_ENMODE_MASK, + .enable_val = BUCK_ENMODE_ONREQ, .owner = THIS_MODULE, }, }, @@ -575,6 +585,7 @@ static const struct pca9450_regulator_desc pca9450bc_regulators[] = { .vsel_mask = BUCK6OUT_MASK, .enable_reg = PCA9450_REG_BUCK6CTRL, .enable_mask = BUCK6_ENMODE_MASK, + .enable_val = BUCK_ENMODE_ONREQ, .owner = THIS_MODULE, }, }, @@ -806,6 +817,24 @@ static const struct pca9450_regulator_desc pca9451a_regulators[] = { }, { .desc = { + .name = "ldo3", + .of_match = of_match_ptr("LDO3"), + .regulators_node = of_match_ptr("regulators"), + .id = PCA9450_LDO3, + .ops = &pca9450_ldo_regulator_ops, + .type = REGULATOR_VOLTAGE, + .n_voltages = PCA9450_LDO3_VOLTAGE_NUM, + .linear_ranges = pca9450_ldo34_volts, + .n_linear_ranges = ARRAY_SIZE(pca9450_ldo34_volts), + .vsel_reg = PCA9450_REG_LDO3CTRL, + .vsel_mask = LDO3OUT_MASK, + .enable_reg = PCA9450_REG_LDO3CTRL, + .enable_mask = LDO3_EN_MASK, + .owner = THIS_MODULE, + }, + }, + { + .desc = { .name = "ldo4", .of_match = of_match_ptr("LDO4"), .regulators_node = of_match_ptr("regulators"), @@ -905,6 +934,7 @@ static int pca9450_i2c_probe(struct i2c_client *i2c) pca9450->rcnt = ARRAY_SIZE(pca9450bc_regulators); break; case PCA9450_TYPE_PCA9451A: + case PCA9450_TYPE_PCA9452: regulator_desc = pca9451a_regulators; pca9450->rcnt = ARRAY_SIZE(pca9451a_regulators); break; @@ -921,25 +951,21 @@ static int pca9450_i2c_probe(struct i2c_client *i2c) pca9450->regmap = devm_regmap_init_i2c(i2c, &pca9450_regmap_config); - if (IS_ERR(pca9450->regmap)) { - dev_err(&i2c->dev, "regmap initialization failed\n"); - return PTR_ERR(pca9450->regmap); - } + if (IS_ERR(pca9450->regmap)) + return dev_err_probe(&i2c->dev, PTR_ERR(pca9450->regmap), + "regmap initialization failed\n"); ret = regmap_read(pca9450->regmap, PCA9450_REG_DEV_ID, &device_id); - if (ret) { - dev_err(&i2c->dev, "Read device id error\n"); - return ret; - } + if (ret) + return dev_err_probe(&i2c->dev, ret, "Read device id error\n"); /* Check your board and dts for match the right pmic */ if (((device_id >> 4) != 0x1 && type == PCA9450_TYPE_PCA9450A) || ((device_id >> 4) != 0x3 && type == PCA9450_TYPE_PCA9450BC) || - ((device_id >> 4) != 0x9 && type == PCA9450_TYPE_PCA9451A)) { - dev_err(&i2c->dev, "Device id(%x) mismatched\n", - device_id >> 4); - return -EINVAL; - } + ((device_id >> 4) != 0x9 && type == PCA9450_TYPE_PCA9451A) || + ((device_id >> 4) != 0x9 && type == PCA9450_TYPE_PCA9452)) + return dev_err_probe(&i2c->dev, -EINVAL, + "Device id(%x) mismatched\n", device_id >> 4); for (i = 0; i < pca9450->rcnt; i++) { const struct regulator_desc *desc; @@ -949,17 +975,16 @@ static int pca9450_i2c_probe(struct i2c_client *i2c) r = ®ulator_desc[i]; desc = &r->desc; + if (type == PCA9450_TYPE_PCA9451A && !strcmp(desc->name, "ldo3")) + continue; + config.regmap = pca9450->regmap; config.dev = pca9450->dev; rdev = devm_regulator_register(pca9450->dev, desc, &config); - if (IS_ERR(rdev)) { - ret = PTR_ERR(rdev); - dev_err(pca9450->dev, - "Failed to register regulator(%s): %d\n", - desc->name, ret); - return ret; - } + if (IS_ERR(rdev)) + return dev_err_probe(pca9450->dev, PTR_ERR(rdev), + "Failed to register regulator(%s)\n", desc->name); } if (pca9450->irq) { @@ -967,29 +992,24 @@ static int pca9450_i2c_probe(struct i2c_client *i2c) pca9450_irq_handler, (IRQF_TRIGGER_FALLING | IRQF_ONESHOT), "pca9450-irq", pca9450); - if (ret != 0) { - dev_err(pca9450->dev, "Failed to request IRQ: %d\n", - pca9450->irq); - return ret; - } + if (ret != 0) + return dev_err_probe(pca9450->dev, ret, "Failed to request IRQ: %d\n", + pca9450->irq); + /* Unmask all interrupt except PWRON/WDOG/RSVD */ ret = regmap_update_bits(pca9450->regmap, PCA9450_REG_INT1_MSK, IRQ_VR_FLT1 | IRQ_VR_FLT2 | IRQ_LOWVSYS | IRQ_THERM_105 | IRQ_THERM_125, IRQ_PWRON | IRQ_WDOGB | IRQ_RSVD); - if (ret) { - dev_err(&i2c->dev, "Unmask irq error\n"); - return ret; - } + if (ret) + return dev_err_probe(&i2c->dev, ret, "Unmask irq error\n"); } /* Clear PRESET_EN bit in BUCK123_DVS to use DVS registers */ ret = regmap_clear_bits(pca9450->regmap, PCA9450_REG_BUCK123_DVS, BUCK123_PRESET_EN); - if (ret) { - dev_err(&i2c->dev, "Failed to clear PRESET_EN bit: %d\n", ret); - return ret; - } + if (ret) + return dev_err_probe(&i2c->dev, ret, "Failed to clear PRESET_EN bit\n"); if (of_property_read_bool(i2c->dev.of_node, "nxp,wdog_b-warm-reset")) reset_ctrl = WDOG_B_CFG_WARM; @@ -999,20 +1019,16 @@ static int pca9450_i2c_probe(struct i2c_client *i2c) /* Set reset behavior on assertion of WDOG_B signal */ ret = regmap_update_bits(pca9450->regmap, PCA9450_REG_RESET_CTRL, WDOG_B_CFG_MASK, reset_ctrl); - if (ret) { - dev_err(&i2c->dev, "Failed to set WDOG_B reset behavior\n"); - return ret; - } + if (ret) + return dev_err_probe(&i2c->dev, ret, "Failed to set WDOG_B reset behavior\n"); if (of_property_read_bool(i2c->dev.of_node, "nxp,i2c-lt-enable")) { /* Enable I2C Level Translator */ ret = regmap_update_bits(pca9450->regmap, PCA9450_REG_CONFIG2, I2C_LT_MASK, I2C_LT_ON_STANDBY_RUN); - if (ret) { - dev_err(&i2c->dev, - "Failed to enable I2C level translator\n"); - return ret; - } + if (ret) + return dev_err_probe(&i2c->dev, ret, + "Failed to enable I2C level translator\n"); } /* @@ -1022,10 +1038,9 @@ static int pca9450_i2c_probe(struct i2c_client *i2c) */ pca9450->sd_vsel_gpio = gpiod_get_optional(pca9450->dev, "sd-vsel", GPIOD_OUT_HIGH); - if (IS_ERR(pca9450->sd_vsel_gpio)) { - dev_err(&i2c->dev, "Failed to get SD_VSEL GPIO\n"); - return PTR_ERR(pca9450->sd_vsel_gpio); - } + if (IS_ERR(pca9450->sd_vsel_gpio)) + return dev_err_probe(&i2c->dev, PTR_ERR(pca9450->sd_vsel_gpio), + "Failed to get SD_VSEL GPIO\n"); dev_info(&i2c->dev, "%s probed.\n", type == PCA9450_TYPE_PCA9450A ? "pca9450a" : @@ -1051,6 +1066,10 @@ static const struct of_device_id pca9450_of_match[] = { .compatible = "nxp,pca9451a", .data = (void *)PCA9450_TYPE_PCA9451A, }, + { + .compatible = "nxp,pca9452", + .data = (void *)PCA9450_TYPE_PCA9452, + }, { } }; MODULE_DEVICE_TABLE(of, pca9450_of_match); diff --git a/drivers/regulator/tps65219-regulator.c b/drivers/regulator/tps65219-regulator.c index b4065356392f..aa65077f9d41 100644 --- a/drivers/regulator/tps65219-regulator.c +++ b/drivers/regulator/tps65219-regulator.c @@ -287,21 +287,6 @@ static irqreturn_t tps65219_regulator_irq_handler(int irq, void *data) return IRQ_HANDLED; } -static int tps65219_get_rdev_by_name(const char *regulator_name, - struct regulator_dev *rdevtbl[7], - struct regulator_dev **dev) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(regulators); i++) { - if (strcmp(regulator_name, regulators[i].name) == 0) { - *dev = rdevtbl[i]; - return 0; - } - } - return -EINVAL; -} - static int tps65219_regulator_probe(struct platform_device *pdev) { struct tps65219 *tps = dev_get_drvdata(pdev->dev.parent); @@ -312,23 +297,18 @@ static int tps65219_regulator_probe(struct platform_device *pdev) int irq; struct tps65219_regulator_irq_data *irq_data; struct tps65219_regulator_irq_type *irq_type; - struct regulator_dev *rdevtbl[7]; config.dev = tps->dev; config.driver_data = tps; config.regmap = tps->regmap; for (i = 0; i < ARRAY_SIZE(regulators); i++) { - dev_dbg(tps->dev, "%s regul i= %d START", __func__, i); rdev = devm_regulator_register(&pdev->dev, ®ulators[i], &config); - if (IS_ERR(rdev)) { - dev_err(tps->dev, "failed to register %s regulator\n", - regulators[i].name); - return PTR_ERR(rdev); - } - rdevtbl[i] = rdev; - dev_dbg(tps->dev, "%s regul i= %d COMPLETED", __func__, i); + if (IS_ERR(rdev)) + return dev_err_probe(tps->dev, PTR_ERR(rdev), + "Failed to register %s regulator\n", + regulators[i].name); } irq_data = devm_kmalloc(tps->dev, @@ -348,14 +328,6 @@ static int tps65219_regulator_probe(struct platform_device *pdev) irq_data[i].dev = tps->dev; irq_data[i].type = irq_type; - tps65219_get_rdev_by_name(irq_type->regulator_name, rdevtbl, &rdev); - if (IS_ERR(rdev)) { - dev_err(tps->dev, "Failed to get rdev for %s\n", - irq_type->regulator_name); - return -EINVAL; - } - irq_data[i].rdev = rdev; - error = devm_request_threaded_irq(tps->dev, irq, NULL, tps65219_regulator_irq_handler, IRQF_ONESHOT, @@ -379,7 +351,7 @@ MODULE_DEVICE_TABLE(platform, tps65219_regulator_id_table); static struct platform_driver tps65219_regulator_driver = { .driver = { - .name = "tps65219-pmic", + .name = "tps65219-regulator", .probe_type = PROBE_PREFER_ASYNCHRONOUS, }, .probe = tps65219_regulator_probe, @@ -390,5 +362,4 @@ module_platform_driver(tps65219_regulator_driver); MODULE_AUTHOR("Jerome Neanne <j-neanne@baylibre.com>"); MODULE_DESCRIPTION("TPS65219 voltage regulator driver"); -MODULE_ALIAS("platform:tps65219-pmic"); MODULE_LICENSE("GPL"); diff --git a/include/linux/regulator/consumer.h b/include/linux/regulator/consumer.h index bcba3935c6f9..ffe912f345ae 100644 --- a/include/linux/regulator/consumer.h +++ b/include/linux/regulator/consumer.h @@ -233,6 +233,11 @@ int regulator_sync_voltage(struct regulator *regulator); int regulator_set_current_limit(struct regulator *regulator, int min_uA, int max_uA); int regulator_get_current_limit(struct regulator *regulator); +int regulator_get_unclaimed_power_budget(struct regulator *regulator); +int regulator_request_power_budget(struct regulator *regulator, + unsigned int pw_req); +void regulator_free_power_budget(struct regulator *regulator, + unsigned int pw); int regulator_set_mode(struct regulator *regulator, unsigned int mode); unsigned int regulator_get_mode(struct regulator *regulator); @@ -526,6 +531,22 @@ static inline int regulator_get_current_limit(struct regulator *regulator) return 0; } +static inline int regulator_get_unclaimed_power_budget(struct regulator *regulator) +{ + return INT_MAX; +} + +static inline int regulator_request_power_budget(struct regulator *regulator, + unsigned int pw_req) +{ + return -EOPNOTSUPP; +} + +static inline void regulator_free_power_budget(struct regulator *regulator, + unsigned int pw) +{ +} + static inline int regulator_set_mode(struct regulator *regulator, unsigned int mode) { diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h index 5b66caf1695d..4a216fdba354 100644 --- a/include/linux/regulator/driver.h +++ b/include/linux/regulator/driver.h @@ -656,6 +656,8 @@ struct regulator_dev { int cached_err; bool use_cached_err; spinlock_t err_lock; + + int pw_requested_mW; }; /* diff --git a/include/linux/regulator/machine.h b/include/linux/regulator/machine.h index b3db09a7429b..1fc440c5c4c7 100644 --- a/include/linux/regulator/machine.h +++ b/include/linux/regulator/machine.h @@ -113,6 +113,7 @@ struct notification_limit { * @min_uA: Smallest current consumers may set. * @max_uA: Largest current consumers may set. * @ilim_uA: Maximum input curr |