From 4950486cd86f450baa847bfc13557244d834526c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 16 Nov 2021 12:09:51 +0100 Subject: regulator: da9121: Emit only one error message in .remove() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When an i2c remove callback fails, the i2c core emits a generic error message and still removes the device. Apart from the message there the return value isn't further used. So don't return an error code after having already emitted a driver specific warning about the problem to prevent two messages about the same issue. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20211116110951.1213566-1-u.kleine-koenig@pengutronix.de Signed-off-by: Mark Brown --- drivers/regulator/da9121-regulator.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/regulator/da9121-regulator.c b/drivers/regulator/da9121-regulator.c index e66925090258..a5a83b772a85 100644 --- a/drivers/regulator/da9121-regulator.c +++ b/drivers/regulator/da9121-regulator.c @@ -1065,7 +1065,7 @@ static int da9121_i2c_remove(struct i2c_client *i2c) { struct da9121 *chip = i2c_get_clientdata(i2c); const int mask_all[4] = { 0xFF, 0xFF, 0xFF, 0xFF }; - int ret = 0; + int ret; free_irq(chip->chip_irq, chip); cancel_delayed_work_sync(&chip->work); @@ -1073,7 +1073,7 @@ static int da9121_i2c_remove(struct i2c_client *i2c) ret = regmap_bulk_write(chip->regmap, DA9121_REG_SYS_MASK_0, mask_all, 4); if (ret != 0) dev_err(chip->dev, "Failed to set IRQ masks: %d\n", ret); - return ret; + return 0; } static const struct i2c_device_id da9121_i2c_id[] = { -- cgit v1.2.3 From 8b6e88555971eac384b89fb0bd6c72ee4e1e6a6a Mon Sep 17 00:00:00 2001 From: Matti Vaittinen Date: Thu, 18 Nov 2021 13:48:47 +0200 Subject: regulator: rohm-regulator: add helper for restricted voltage setting Few ROHM PMICs have regulators where voltage setting can be done only when regulator is disabled. Add helper for those PMICs. Signed-off-by: Matti Vaittinen Link: https://lore.kernel.org/r/6f51871e9fea611d133b5dd2560f4a7ee1ede9cd.1637233864.git.matti.vaittinen@fi.rohmeurope.com Signed-off-by: Mark Brown --- drivers/regulator/rohm-regulator.c | 16 ++++++++++++++++ include/linux/mfd/rohm-generic.h | 7 +++++++ 2 files changed, 23 insertions(+) diff --git a/drivers/regulator/rohm-regulator.c b/drivers/regulator/rohm-regulator.c index 6e0d9c08ec1c..f97a9a51ee76 100644 --- a/drivers/regulator/rohm-regulator.c +++ b/drivers/regulator/rohm-regulator.c @@ -112,6 +112,22 @@ int rohm_regulator_set_dvs_levels(const struct rohm_dvs_config *dvs, } EXPORT_SYMBOL(rohm_regulator_set_dvs_levels); +/* + * Few ROHM PMIC ICs have constrains on voltage changing: + * BD71837 - only buck 1-4 voltages can be changed when they are enabled. + * Other bucks and all LDOs must be disabled when voltage is changed. + * BD96801 - LDO voltage levels can be changed when LDOs are disabled. + */ +int rohm_regulator_set_voltage_sel_restricted(struct regulator_dev *rdev, + unsigned int sel) +{ + if (rdev->desc->ops->is_enabled(rdev)) + return -EBUSY; + + return regulator_set_voltage_sel_regmap(rdev, sel); +} +EXPORT_SYMBOL_GPL(rohm_regulator_set_voltage_sel_restricted); + MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Matti Vaittinen "); MODULE_DESCRIPTION("Generic helpers for ROHM PMIC regulator drivers"); diff --git a/include/linux/mfd/rohm-generic.h b/include/linux/mfd/rohm-generic.h index 35b392a0d73a..35c5866f48b7 100644 --- a/include/linux/mfd/rohm-generic.h +++ b/include/linux/mfd/rohm-generic.h @@ -80,6 +80,8 @@ int rohm_regulator_set_dvs_levels(const struct rohm_dvs_config *dvs, const struct regulator_desc *desc, struct regmap *regmap); +int rohm_regulator_set_voltage_sel_restricted(struct regulator_dev *rdev, + unsigned int sel); #else static inline int rohm_regulator_set_dvs_levels(const struct rohm_dvs_config *dvs, struct device_node *np, @@ -88,6 +90,11 @@ static inline int rohm_regulator_set_dvs_levels(const struct rohm_dvs_config *dv { return 0; } +static int rohm_regulator_set_voltage_sel_restricted(struct regulator_dev *rdev, + unsigned int sel) +{ + return 0; +} #endif #endif -- cgit v1.2.3 From e7543e199591c24175c4a06beec15611ce4b5a5b Mon Sep 17 00:00:00 2001 From: Matti Vaittinen Date: Thu, 18 Nov 2021 13:49:08 +0200 Subject: regulator: bd718x7: Use rohm generic restricted voltage setting Use common restricted voltage setting instead of implementing own. Signed-off-by: Matti Vaittinen Link: https://lore.kernel.org/r/5a0ee14852802690241568a29ed19ff9550b0b08.1637233864.git.matti.vaittinen@fi.rohmeurope.com Signed-off-by: Mark Brown --- drivers/regulator/bd718x7-regulator.c | 29 ++++------------------------- 1 file changed, 4 insertions(+), 25 deletions(-) diff --git a/drivers/regulator/bd718x7-regulator.c b/drivers/regulator/bd718x7-regulator.c index d60fccedb250..00efb18a836c 100644 --- a/drivers/regulator/bd718x7-regulator.c +++ b/drivers/regulator/bd718x7-regulator.c @@ -125,27 +125,6 @@ static int bd71837_get_buck34_enable_hwctrl(struct regulator_dev *rdev) return !!(BD718XX_BUCK_RUN_ON & val); } -/* - * On BD71837 (not on BD71847, BD71850, ...) - * Bucks 1 to 4 support DVS. PWM mode is used when voltage is changed. - * Bucks 5 to 8 and LDOs can use PFM and must be disabled when voltage - * is changed. Hence we return -EBUSY for these if voltage is changed - * when BUCK/LDO is enabled. - * - * On BD71847, BD71850, ... The LDO voltage can be changed when LDO is - * enabled. But if voltage is increased the LDO power-good monitoring - * must be disabled for the duration of changing + 1mS to ensure voltage - * has reached the higher level before HW does next under voltage detection - * cycle. - */ -static int bd71837_set_voltage_sel_restricted(struct regulator_dev *rdev, - unsigned int sel) -{ - if (rdev->desc->ops->is_enabled(rdev)) - return -EBUSY; - - return regulator_set_voltage_sel_regmap(rdev, sel); -} static void voltage_change_done(struct regulator_dev *rdev, unsigned int sel, unsigned int *mask) @@ -642,22 +621,22 @@ BD718XX_OPS(bd71837_pickable_range_buck_ops, bd718x7_set_buck_ovp); BD718XX_OPS(bd71837_ldo_regulator_ops, regulator_list_voltage_linear_range, - NULL, bd71837_set_voltage_sel_restricted, + NULL, rohm_regulator_set_voltage_sel_restricted, regulator_get_voltage_sel_regmap, NULL, NULL, bd718x7_set_ldo_uvp, NULL); BD718XX_OPS(bd71837_ldo_regulator_nolinear_ops, regulator_list_voltage_table, - NULL, bd71837_set_voltage_sel_restricted, + NULL, rohm_regulator_set_voltage_sel_restricted, regulator_get_voltage_sel_regmap, NULL, NULL, bd718x7_set_ldo_uvp, NULL); BD718XX_OPS(bd71837_buck_regulator_ops, regulator_list_voltage_linear_range, - NULL, bd71837_set_voltage_sel_restricted, + NULL, rohm_regulator_set_voltage_sel_restricted, regulator_get_voltage_sel_regmap, regulator_set_voltage_time_sel, NULL, bd718x7_set_buck_uvp, bd718x7_set_buck_ovp); BD718XX_OPS(bd71837_buck_regulator_nolinear_ops, regulator_list_voltage_table, - regulator_map_voltage_ascend, bd71837_set_voltage_sel_restricted, + regulator_map_voltage_ascend, rohm_regulator_set_voltage_sel_restricted, regulator_get_voltage_sel_regmap, regulator_set_voltage_time_sel, NULL, bd718x7_set_buck_uvp, bd718x7_set_buck_ovp); /* -- cgit v1.2.3 From 92b1348277f8893671e5354adde64fe3cf462821 Mon Sep 17 00:00:00 2001 From: Matti Vaittinen Date: Thu, 18 Nov 2021 13:49:30 +0200 Subject: regulator: Add units to limit documentation The documentation for limits used at protection level setting did not mention the units. Fix the units in documentation to match values passed in from device-tree (uV, uA, Kelvin) to avoid confusion. Signed-off-by: Matti Vaittinen Link: https://lore.kernel.org/r/111114aca991e41e49a32f89b74e95285f07c1e3.1637233864.git.matti.vaittinen@fi.rohmeurope.com Signed-off-by: Mark Brown --- include/linux/regulator/driver.h | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h index bd7a73db2e66..1cb8071fee34 100644 --- a/include/linux/regulator/driver.h +++ b/include/linux/regulator/driver.h @@ -101,11 +101,13 @@ enum regulator_detection_severity { * is requested. * @set_over_voltage_protection: Support enabling of and setting limits for over * voltage situation detection. Detection can be configured for same - * severities as over current protection. + * severities as over current protection. Units of uV. * @set_under_voltage_protection: Support enabling of and setting limits for - * under situation detection. + * under voltage situation detection. Detection can be configured for same + * severities as over current protection. Units of uV. * @set_thermal_protection: Support enabling of and setting limits for over - * temperature situation detection. + * temperature situation detection.Detection can be configured for same + * severities as over current protection. Units of degree Kelvin. * * @set_active_discharge: Set active discharge enable/disable of regulators. * -- cgit v1.2.3 From cff6f593251cdf5398dc3c57f7032b8e9dcb633e Mon Sep 17 00:00:00 2001 From: Matti Vaittinen Date: Tue, 23 Nov 2021 12:36:47 +0200 Subject: regulator: rohm-generic: iniline stub function The function rohm_regulator_set_voltage_sel_restricted() has a stub implementation. Linux-next testing spot following: include/linux/mfd/rohm-generic.h:93:12: error: 'rohm_regulator_set_voltage_sel_restricted' defined but not used Fix this by inlining the stub. Fixes: 8b6e88555971 ("regulator: rohm-regulator: add helper for restricted voltage setting") Signed-off-by: Matti Vaittinen Link: https://lore.kernel.org/r/YZzEP3S7U15bTDAI@fedora Signed-off-by: Mark Brown --- include/linux/mfd/rohm-generic.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/linux/mfd/rohm-generic.h b/include/linux/mfd/rohm-generic.h index 35c5866f48b7..080d60adcd5f 100644 --- a/include/linux/mfd/rohm-generic.h +++ b/include/linux/mfd/rohm-generic.h @@ -90,7 +90,8 @@ static inline int rohm_regulator_set_dvs_levels(const struct rohm_dvs_config *dv { return 0; } -static int rohm_regulator_set_voltage_sel_restricted(struct regulator_dev *rdev, + +static inline int rohm_regulator_set_voltage_sel_restricted(struct regulator_dev *rdev, unsigned int sel) { return 0; -- cgit v1.2.3 From 1b6ed6bf32fb22ef8e3572fc9c0f6454adf1ca40 Mon Sep 17 00:00:00 2001 From: Matti Vaittinen Date: Wed, 24 Nov 2021 09:17:37 +0200 Subject: regulator: Drop unnecessary struct member The irq_flags from the regulator IRQ helper description struct was never used. The IRQ flags are passed as parameters to helper registration instead. Remove the unnecessary struct field. Fixes: 7111c6d1b31b ("regulator: IRQ based event/error notification helpers") Signed-off-by: Matti Vaittinen Link: https://lore.kernel.org/r/5f6371e178453fa2b165da50452f7db4e986debb.1637736436.git.matti.vaittinen@fi.rohmeurope.com Signed-off-by: Mark Brown --- include/linux/regulator/driver.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h index 1cb8071fee34..53b25cd7ead0 100644 --- a/include/linux/regulator/driver.h +++ b/include/linux/regulator/driver.h @@ -554,7 +554,6 @@ struct regulator_irq_data { */ struct regulator_irq_desc { const char *name; - int irq_flags; int fatal_cnt; int reread_ms; int irq_off_ms; -- cgit v1.2.3 From 6fadec4c5561e2fbe1dfa8a7da9bc58d094a8f04 Mon Sep 17 00:00:00 2001 From: Matti Vaittinen Date: Wed, 24 Nov 2021 09:16:45 +0200 Subject: regulator: Add regulator_err2notif() helper Help drivers avoid storing both supported notification and supported error flags by supporting conversion from regulator error to notification. This may help saving some bytes. Add helper for finding the regulator notification corresponding to a regulator error. Signed-off-by: Matti Vaittinen Link: https://lore.kernel.org/r/eb1755ac0569ff07ffa466cf8912c6fd50e7c7c6.1637736436.git.matti.vaittinen@fi.rohmeurope.com Signed-off-by: Mark Brown --- include/linux/regulator/driver.h | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h index 53b25cd7ead0..6c6ec9658c30 100644 --- a/include/linux/regulator/driver.h +++ b/include/linux/regulator/driver.h @@ -645,6 +645,40 @@ struct regulator_dev { spinlock_t err_lock; }; +/* + * Convert error flags to corresponding notifications. + * + * Can be used by drivers which use the notification helpers to + * find out correct notification flags based on the error flags. Drivers + * can avoid storing both supported notification and error flags which + * may save few bytes. + */ +static inline int regulator_err2notif(int err) +{ + switch (err) { + case REGULATOR_ERROR_UNDER_VOLTAGE: + return REGULATOR_EVENT_UNDER_VOLTAGE; + case REGULATOR_ERROR_OVER_CURRENT: + return REGULATOR_EVENT_OVER_CURRENT; + case REGULATOR_ERROR_REGULATION_OUT: + return REGULATOR_EVENT_REGULATION_OUT; + case REGULATOR_ERROR_FAIL: + return REGULATOR_EVENT_FAIL; + case REGULATOR_ERROR_OVER_TEMP: + return REGULATOR_EVENT_OVER_TEMP; + case REGULATOR_ERROR_UNDER_VOLTAGE_WARN: + return REGULATOR_EVENT_UNDER_VOLTAGE_WARN; + case REGULATOR_ERROR_OVER_CURRENT_WARN: + return REGULATOR_EVENT_OVER_CURRENT_WARN; + case REGULATOR_ERROR_OVER_VOLTAGE_WARN: + return REGULATOR_EVENT_OVER_VOLTAGE_WARN; + case REGULATOR_ERROR_OVER_TEMP_WARN: + return REGULATOR_EVENT_OVER_TEMP_WARN; + } + return 0; +} + + struct regulator_dev * regulator_register(const struct regulator_desc *regulator_desc, const struct regulator_config *config); -- cgit v1.2.3 From a764ff77d697a4a13e69b3379cc613f7409c6b9a Mon Sep 17 00:00:00 2001 From: Matti Vaittinen Date: Wed, 24 Nov 2021 09:17:13 +0200 Subject: regulator: irq_helper: Provide helper for trivial IRQ notifications Provide a generic map_event helper for regulators which have a notification IRQ with single, well defined purpose. Eg, IRQ always indicates exactly one event for exactly one regulator device. For such IRQs the mapping is trivial. Signed-off-by: Matti Vaittinen Link: https://lore.kernel.org/r/603b7ed1938013a00371c1e7ccc63dfb16982b87.1637736436.git.matti.vaittinen@fi.rohmeurope.com Signed-off-by: Mark Brown --- drivers/regulator/irq_helpers.c | 41 +++++++++++++++++++++++++++++++++++++++- include/linux/regulator/driver.h | 2 ++ 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/drivers/regulator/irq_helpers.c b/drivers/regulator/irq_helpers.c index 522764435575..fe7ae0f3f46a 100644 --- a/drivers/regulator/irq_helpers.c +++ b/drivers/regulator/irq_helpers.c @@ -320,7 +320,9 @@ static void init_rdev_errors(struct regulator_irq *h) * IRQF_ONESHOT when requesting the (threaded) irq. * @common_errs: Errors which can be flagged by this IRQ for all rdevs. * When IRQ is re-enabled these errors will be cleared - * from all associated regulators + * from all associated regulators. Use this instead of the + * per_rdev_errs if you use + * regulator_irq_map_event_simple() for event mapping. * @per_rdev_errs: Optional error flag array describing errors specific * for only some of the regulators. These errors will be * or'ed with common errors. If this is given the array @@ -395,3 +397,40 @@ void regulator_irq_helper_cancel(void **handle) } } EXPORT_SYMBOL_GPL(regulator_irq_helper_cancel); + +/** + * regulator_irq_map_event_simple - regulator IRQ notification for trivial IRQs + * + * @irq: Number of IRQ that occurred + * @rid: Information about the event IRQ indicates + * @dev_mask: mask indicating the regulator originating the IRQ + * + * Regulators whose IRQ has single, well defined purpose (always indicate + * exactly one event, and are relevant to exactly one regulator device) can + * use this function as their map_event callbac for their regulator IRQ + * notification helperk. Exactly one rdev and exactly one error (in + * "common_errs"-field) can be given at IRQ helper registration for + * regulator_irq_map_event_simple() to be viable. + */ +int regulator_irq_map_event_simple(int irq, struct regulator_irq_data *rid, + unsigned long *dev_mask) +{ + int err = rid->states[0].possible_errs; + + *dev_mask = 1; + /* + * This helper should only be used in a situation where the IRQ + * can indicate only one type of problem for one specific rdev. + * Something fishy is going on if we are having multiple rdevs or ERROR + * flags here. + */ + if (WARN_ON(rid->num_states != 1 || hweight32(err) != 1)) + return 0; + + rid->states[0].errors = err; + rid->states[0].notifs = regulator_err2notif(err); + + return 0; +} +EXPORT_SYMBOL_GPL(regulator_irq_map_event_simple); + diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h index 6c6ec9658c30..4078c7776453 100644 --- a/include/linux/regulator/driver.h +++ b/include/linux/regulator/driver.h @@ -700,6 +700,8 @@ void *regulator_irq_helper(struct device *dev, int irq_flags, int common_errs, int *per_rdev_errs, struct regulator_dev **rdev, int rdev_amount); void regulator_irq_helper_cancel(void **handle); +int regulator_irq_map_event_simple(int irq, struct regulator_irq_data *rid, + unsigned long *dev_mask); void *rdev_get_drvdata(struct regulator_dev *rdev); struct device *rdev_get_dev(struct regulator_dev *rdev); -- cgit v1.2.3 From 432dd1fc134ef902b049b26839edfd3fdc1f8dc0 Mon Sep 17 00:00:00 2001 From: Matti Vaittinen Date: Wed, 24 Nov 2021 07:57:49 +0200 Subject: regulator: rohm-generic: remove unused dummies Function rohm_regulator_set_voltage_sel_restricted() and rohm_regulator_set_dvs_levels() had inlined dummy implementations for cases when the real implementation was not configured in. All of the drivers who issue the call to these functions do SELECT the real implementation from the Kconfig. There should be no cases where the real implementation was not selected by the drivers using these functions - such a situation is likely to be an error which deserves to be noticed at compile-time. These dummies could in theory be used for compile-testing the drivers only (without the generic rohm regulator pieces). However, for such compile testing we should manually drop the selection from KConfig - and I guess that if it does not work out-of-the-box, then it is not going to happen. Especially when there should be no reason to omit compile-testing the generic rohm_regulator part. Crash test dummies. Signed-off-by: Matti Vaittinen Link: https://lore.kernel.org/r/YZ3UXXrk/Efe7Scj@fedora Signed-off-by: Mark Brown --- include/linux/mfd/rohm-generic.h | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/include/linux/mfd/rohm-generic.h b/include/linux/mfd/rohm-generic.h index 080d60adcd5f..5ed97a1d0908 100644 --- a/include/linux/mfd/rohm-generic.h +++ b/include/linux/mfd/rohm-generic.h @@ -82,20 +82,6 @@ int rohm_regulator_set_dvs_levels(const struct rohm_dvs_config *dvs, int rohm_regulator_set_voltage_sel_restricted(struct regulator_dev *rdev, unsigned int sel); -#else -static inline int rohm_regulator_set_dvs_levels(const struct rohm_dvs_config *dvs, - struct device_node *np, - const struct regulator_desc *desc, - struct regmap *regmap) -{ - return 0; -} - -static inline int rohm_regulator_set_voltage_sel_restricted(struct regulator_dev *rdev, - unsigned int sel) -{ - return 0; -} #endif #endif -- cgit v1.2.3 From 76e95f331be09bac8764e971613439d294422d6e Mon Sep 17 00:00:00 2001 From: Dominik Kobinski Date: Tue, 23 Nov 2021 19:08:16 +0100 Subject: dt-bindings: regulator: qcom: spmi-regulator: Document pm8226 compatible Suggested-by: Ivaylo Ivanov Signed-off-by: Dominik Kobinski Link: https://lore.kernel.org/r/20211123180816.2835-1-dominikkobinski314@gmail.com Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/regulator/qcom,spmi-regulator.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/regulator/qcom,spmi-regulator.txt b/Documentation/devicetree/bindings/regulator/qcom,spmi-regulator.txt index 2b544059e029..c2a39b121b1b 100644 --- a/Documentation/devicetree/bindings/regulator/qcom,spmi-regulator.txt +++ b/Documentation/devicetree/bindings/regulator/qcom,spmi-regulator.txt @@ -6,6 +6,7 @@ Qualcomm SPMI Regulators Definition: must be one of: "qcom,pm8004-regulators" "qcom,pm8005-regulators" + "qcom,pm8226-regulators" "qcom,pm8841-regulators" "qcom,pm8916-regulators" "qcom,pm8941-regulators" -- cgit v1.2.3 From f8843e5e2dc85dc6a546ec130d76be66e62abed6 Mon Sep 17 00:00:00 2001 From: Dominik Kobinski Date: Tue, 23 Nov 2021 19:11:19 +0100 Subject: regulator: qcom_spmi: Add pm8226 regulators The PM8226 PMIC is very often seen on MSM8x26 boards. Suggested-by: Ivaylo Ivanov Signed-off-by: Dominik Kobinski Reviewed-by: Bjorn Andersson Link: https://lore.kernel.org/r/20211123181119.2897-1-dominikkobinski314@gmail.com Signed-off-by: Mark Brown --- drivers/regulator/qcom_spmi-regulator.c | 39 +++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/drivers/regulator/qcom_spmi-regulator.c b/drivers/regulator/qcom_spmi-regulator.c index 41424a3366d0..02bfce981150 100644 --- a/drivers/regulator/qcom_spmi-regulator.c +++ b/drivers/regulator/qcom_spmi-regulator.c @@ -1895,6 +1895,44 @@ static const struct spmi_regulator_data pm8941_regulators[] = { { } }; +static const struct spmi_regulator_data pm8226_regulators[] = { + { "s1", 0x1400, "vdd_s1", }, + { "s2", 0x1700, "vdd_s2", }, + { "s3", 0x1a00, "vdd_s3", }, + { "s4", 0x1d00, "vdd_s4", }, + { "s5", 0x2000, "vdd_s5", }, + { "l1", 0x4000, "vdd_l1_l2_l4_l5", }, + { "l2", 0x4100, "vdd_l1_l2_l4_l5", }, + { "l3", 0x4200, "vdd_l3_l24_l26", }, + { "l4", 0x4300, "vdd_l1_l2_l4_l5", }, + { "l5", 0x4400, "vdd_l1_l2_l4_l5", }, + { "l6", 0x4500, "vdd_l6_l7_l8_l9_l27", }, + { "l7", 0x4600, "vdd_l6_l7_l8_l9_l27", }, + { "l8", 0x4700, "vdd_l6_l7_l8_l9_l27", }, + { "l9", 0x4800, "vdd_l6_l7_l8_l9_l27", }, + { "l10", 0x4900, "vdd_l10_l11_l13", }, + { "l11", 0x4a00, "vdd_l10_l11_l13", }, + { "l12", 0x4b00, "vdd_l12_l14", }, + { "l13", 0x4c00, "vdd_l10_l11_l13", }, + { "l14", 0x4d00, "vdd_l12_l14", }, + { "l15", 0x4e00, "vdd_l15_l16_l17_l18", }, + { "l16", 0x4f00, "vdd_l15_l16_l17_l18", }, + { "l17", 0x5000, "vdd_l15_l16_l17_l18", }, + { "l18", 0x5100, "vdd_l15_l16_l17_l18", }, + { "l19", 0x5200, "vdd_l19_l20_l21_l22_l23_l28", }, + { "l20", 0x5300, "vdd_l19_l20_l21_l22_l23_l28", }, + { "l21", 0x5400, "vdd_l19_l20_l21_l22_l23_l28", }, + { "l22", 0x5500, "vdd_l19_l20_l21_l22_l23_l28", }, + { "l23", 0x5600, "vdd_l19_l20_l21_l22_l23_l28", }, + { "l24", 0x5700, "vdd_l3_l24_l26", }, + { "l25", 0x5800, "vdd_l25", }, + { "l26", 0x5900, "vdd_l3_l24_l26", }, + { "l27", 0x5a00, "vdd_l6_l7_l8_l9_l27", }, + { "l28", 0x5b00, "vdd_l19_l20_l21_l22_l23_l28", }, + { "lvs1", 0x8000, "vdd_lvs1", }, + { } +}; + static const struct spmi_regulator_data pm8841_regulators[] = { { "s1", 0x1400, "vdd_s1", }, { "s2", 0x1700, "vdd_s2", NULL, 0x1c08 }, @@ -2095,6 +2133,7 @@ static const struct spmi_regulator_data pms405_regulators[] = { static const struct of_device_id qcom_spmi_regulator_match[] = { { .compatible = "qcom,pm8004-regulators", .data = &pm8004_regulators }, { .compatible = "qcom,pm8005-regulators", .data = &pm8005_regulators }, + { .compatible = "qcom,pm8226-regulators", .data = &pm8226_regulators }, { .compatible = "qcom,pm8841-regulators", .data = &pm8841_regulators }, { .compatible = "qcom,pm8916-regulators", .data = &pm8916_regulators }, { .compatible = "qcom,pm8941-regulators", .data = &pm8941_regulators }, -- cgit v1.2.3 From ac88e9526d68f2532be3b4b439d45c0c8de7e170 Mon Sep 17 00:00:00 2001 From: Satya Priya Date: Tue, 23 Nov 2021 17:19:25 +0530 Subject: dt-bindings: regulator: Add compatible for pmg1110 Add compatible string for pmg1110 pmic. Signed-off-by: Satya Priya Link: https://lore.kernel.org/r/1637668167-31325-2-git-send-email-quic_c_skakit@quicinc.com Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/regulator/qcom,rpmh-regulator.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/regulator/qcom,rpmh-regulator.yaml b/Documentation/devicetree/bindings/regulator/qcom,rpmh-regulator.yaml index b959504e0ea4..c02f08a7014c 100644 --- a/Documentation/devicetree/bindings/regulator/qcom,rpmh-regulator.yaml +++ b/Documentation/devicetree/bindings/regulator/qcom,rpmh-regulator.yaml @@ -63,6 +63,7 @@ properties: - qcom,pm8350-rpmh-regulators - qcom,pm8350c-rpmh-regulators - qcom,pm8998-rpmh-regulators + - qcom,pmg1110-rpmh-regulators - qcom,pmi8998-rpmh-regulators - qcom,pmm8155au-rpmh-regulators - qcom,pmr735a-rpmh-regulators -- cgit v1.2.3 From 59eadd2af3f717f2ff70dbb6c153757dc1650651 Mon Sep 17 00:00:00 2001 From: Satya Priya Date: Tue, 23 Nov 2021 17:19:26 +0530 Subject: regulator: qcom-rpmh: Add PMG1110 regulators Add support for PMG1110 regulators. Signed-off-by: Satya Priya Link: https://lore.kernel.org/r/1637668167-31325-3-git-send-email-quic_c_skakit@quicinc.com Signed-off-by: Mark Brown --- drivers/regulator/qcom-rpmh-regulator.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/regulator/qcom-rpmh-regulator.c b/drivers/regulator/qcom-rpmh-regulator.c index 12425f667c00..684143c828a5 100644 --- a/drivers/regulator/qcom-rpmh-regulator.c +++ b/drivers/regulator/qcom-rpmh-regulator.c @@ -814,6 +814,11 @@ static const struct rpmh_vreg_init_data pm8998_vreg_data[] = { {} }; +static const struct rpmh_vreg_init_data pmg1110_vreg_data[] = { + RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps510, "vdd-s1"), + {} +}; + static const struct rpmh_vreg_init_data pmi8998_vreg_data[] = { RPMH_VREG("bob", "bob%s1", &pmic4_bob, "vdd-bob"), {} @@ -1217,6 +1222,10 @@ static const struct of_device_id __maybe_unused rpmh_regulator_match_table[] = { .compatible = "qcom,pm8998-rpmh-regulators", .data = pm8998_vreg_data, }, + { + .compatible = "qcom,pmg1110-rpmh-regulators", + .data = pmg1110_vreg_data, + }, { .compatible = "qcom,pmi8998-rpmh-regulators", .data = pmi8998_vreg_data, -- cgit v1.2.3 From 24f0853228f3b98f1ef08d5824376c69bb8124d2 Mon Sep 17 00:00:00 2001 From: Adam Ward Date: Mon, 29 Nov 2021 22:10:12 +0000 Subject: regulator: da9121: Prevent current limit change when enabled Prevent changing current limit when enabled as a precaution against possibile instability due to tight integration with switching cycle Signed-off-by: Adam Ward Link: https://lore.kernel.org/r/52ee682476004a1736c1e0293358987319c1c415.1638223185.git.Adam.Ward.opensource@diasemi.com Signed-off-by: Mark Brown --- drivers/regulator/da9121-regulator.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/regulator/da9121-regulator.c b/drivers/regulator/da9121-regulator.c index a5a83b772a85..86149170bf6c 100644 --- a/drivers/regulator/da9121-regulator.c +++ b/drivers/regulator/da9121-regulator.c @@ -253,6 +253,11 @@ static int da9121_set_current_limit(struct regulator_dev *rdev, goto error; } + if (rdev->desc->ops->is_enabled(rdev)) { + ret = -EBUSY; + goto error; + } + ret = da9121_ceiling_selector(rdev, min_ua, max_ua, &sel); if (ret < 0) goto error; -- cgit v1.2.3 From c5187a245e9bb0af2da8d37ede191569c824c66b Mon Sep 17 00:00:00 2001 From: Adam Ward Date: Mon, 29 Nov 2021 22:10:13 +0000 Subject: regulator: da9121: Add DA914x support Add the DA9141 and DA9142 regulators device recognition data and operational parameters. Signed-off-by: Adam Ward Link: https://lore.kernel.org/r/5f5b9b02f07578cd36c6bc266349a56efc9b08d1.1638223185.git.Adam.Ward.opensource@diasemi.com Signed-off-by: Mark Brown --- drivers/regulator/da9121-regulator.c | 108 ++++++++++++++++++++++++++++++++++- drivers/regulator/da9121-regulator.h | 21 ++++++- 2 files changed, 124 insertions(+), 5 deletions(-) diff --git a/drivers/regulator/da9121-regulator.c b/drivers/regulator/da9121-regulator.c index 86149170bf6c..6f21223a488e 100644 --- a/drivers/regulator/da9121-regulator.c +++ b/drivers/regulator/da9121-regulator.c @@ -86,6 +86,22 @@ static struct da9121_range da9121_3A_1phase_current = { .reg_max = 6, }; +static struct da9121_range da914x_40A_4phase_current = { + .val_min = 14000000, + .val_max = 80000000, + .val_stp = 2000000, + .reg_min = 1, + .reg_max = 14, +}; + +static struct da9121_range da914x_20A_2phase_current = { + .val_min = 7000000, + .val_max = 40000000, + .val_stp = 2000000, + .reg_min = 1, + .reg_max = 14, +}; + struct da9121_variant_info { int num_bucks; int num_phases; @@ -97,6 +113,8 @@ static const struct da9121_variant_info variant_parameters[] = { { 2, 1, &da9121_3A_1phase_current }, //DA9121_TYPE_DA9220_DA9132 { 2, 1, &da9121_5A_1phase_current }, //DA9121_TYPE_DA9122_DA9131 { 1, 2, &da9121_6A_2phase_current }, //DA9121_TYPE_DA9217 + { 1, 4, &da914x_40A_4phase_current }, //DA9121_TYPE_DA9141 + { 1, 2, &da914x_20A_2phase_current }, //DA9121_TYPE_DA9142 }; struct da9121_field { @@ -542,11 +560,65 @@ static const struct regulator_desc da9217_reg = { .vsel_mask = DA9121_MASK_BUCK_BUCKx_5_CHx_A_VOUT, }; +#define DA914X_MIN_MV 500 +#define DA914X_MAX_MV 1000 +#define DA914X_STEP_MV 10 +#define DA914X_MIN_SEL (DA914X_MIN_MV / DA914X_STEP_MV) +#define DA914X_N_VOLTAGES (((DA914X_MAX_MV - DA914X_MIN_MV) / DA914X_STEP_MV) \ + + 1 + DA914X_MIN_SEL) + +static const struct regulator_desc da9141_reg = { + .id = DA9121_IDX_BUCK1, + .name = "DA9141", + .of_match = "buck1", + .of_parse_cb = da9121_of_parse_cb, + .owner = THIS_MODULE, + .regulators_node = of_match_ptr("regulators"), + .of_map_mode = da9121_map_mode, + .ops = &da9121_buck_ops, + .type = REGULATOR_VOLTAGE, + .n_voltages = DA914X_N_VOLTAGES, + .min_uV = DA914X_MIN_MV * 1000, + .uV_step = DA914X_STEP_MV * 1000, + .linear_min_sel = DA914X_MIN_SEL, + .vsel_reg = DA9121_REG_BUCK_BUCK1_5, + .vsel_mask = DA9121_MASK_BUCK_BUCKx_5_CHx_A_VOUT, + .enable_reg = DA9121_REG_BUCK_BUCK1_0, + .enable_mask = DA9121_MASK_BUCK_BUCKx_0_CHx_EN, + /* Default value of BUCK_BUCK1_0.CH1_SRC_DVC_UP */ + .ramp_delay = 20000, + /* tBUCK_EN */ + .enable_time = 20, +}; + +static const struct regulator_desc da9142_reg = { + .id = DA9121_IDX_BUCK1, + .name = "DA9142 BUCK1", + .of_match = "buck1", + .of_parse_cb = da9121_of_parse_cb, + .owner = THIS_MODULE, + .regulators_node = of_match_ptr("regulators"), + .of_map_mode = da9121_map_mode, + .ops = &da9121_buck_ops, + .type = REGULATOR_VOLTAGE, + .n_voltages = DA914X_N_VOLTAGES, + .min_uV = DA914X_MIN_MV * 1000, + .uV_step = DA914X_STEP_MV * 1000, + .linear_min_sel = DA914X_MIN_SEL, + .enable_reg = DA9121_REG_BUCK_BUCK1_0, + .enable_mask = DA9121_MASK_BUCK_BUCKx_0_CHx_EN, + .vsel_reg = DA9121_REG_BUCK_BUCK1_5, + .vsel_mask = DA9121_MASK_BUCK_BUCKx_5_CHx_A_VOUT, +}; + + static const struct regulator_desc *local_da9121_regulators[][DA9121_IDX_MAX] = { [DA9121_TYPE_DA9121_DA9130] = { &da9121_reg, NULL }, [DA9121_TYPE_DA9220_DA9132] = { &da9220_reg[0], &da9220_reg[1] }, [DA9121_TYPE_DA9122_DA9131] = { &da9122_reg[0], &da9122_reg[1] }, [DA9121_TYPE_DA9217] = { &da9217_reg, NULL }, + [DA9121_TYPE_DA9141] = { &da9141_reg, NULL }, + [DA9121_TYPE_DA9142] = { &da9142_reg, NULL }, }; static void da9121_status_poll_on(struct work_struct *work) @@ -840,7 +912,7 @@ static int da9121_check_device_type(struct i2c_client *i2c, struct da9121 *chip) goto error; } - if (device_id != DA9121_DEVICE_ID) { + if ((device_id != DA9121_DEVICE_ID) && (device_id != DA914x_DEVICE_ID)) { dev_err(chip->dev, "Invalid device ID: 0x%02x\n", device_id); ret = -ENODEV; goto error; @@ -882,6 +954,22 @@ static int da9121_check_device_type(struct i2c_client *i2c, struct da9121 *chip) break; } + if (device_id == DA914x_DEVICE_ID) { + switch (chip->subvariant_id) { + case DA9121_SUBTYPE_DA9141: + type = "DA9141"; + config_match = (variant_vrc == DA9141_VARIANT_VRC); + break; + case DA9121_SUBTYPE_DA9142: + type = "DA9142"; + config_match = (variant_vrc == DA9142_VARIANT_VRC); + break; + default: + type = "Unknown"; + break; + } + } + dev_info(chip->dev, "Device detected (device-ID: 0x%02X, var-ID: 0x%02X, %s)\n", device_id, variant_id, type); @@ -895,8 +983,10 @@ static int da9121_check_device_type(struct i2c_client *i2c, struct da9121 *chip) variant_mrc = (variant_id & DA9121_MASK_OTP_VARIANT_ID_MRC) >> DA9121_SHIFT_OTP_VARIANT_ID_MRC; - if ((device_id == DA9121_DEVICE_ID) && - (variant_mrc < DA9121_VARIANT_MRC_BASE)) { + if (((device_id == DA9121_DEVICE_ID) && + (variant_mrc < DA9121_VARIANT_MRC_BASE)) || + ((device_id == DA914x_DEVICE_ID) && + (variant_mrc != DA914x_VARIANT_MRC_BASE))) { dev_err(chip->dev, "Cannot support variant MRC: 0x%02X\n", variant_mrc); ret = -EINVAL; @@ -936,6 +1026,14 @@ static int da9121_assign_chip_model(struct i2c_client *i2c, chip->variant_id = DA9121_TYPE_DA9220_DA9132; regmap = &da9121_2ch_regmap_config; break; + case DA9121_SUBTYPE_DA9141: + chip->variant_id = DA9121_TYPE_DA9141; + regmap = &da9121_1ch_regmap_config; + break; + case DA9121_SUBTYPE_DA9142: + chip->variant_id = DA9121_TYPE_DA9142; + regmap = &da9121_2ch_regmap_config; + break; } /* Set these up for of_regulator_match call which may want .of_map_modes */ @@ -1015,6 +1113,8 @@ static const struct of_device_id da9121_dt_ids[] = { { .compatible = "dlg,da9131", .data = (void *) DA9121_SUBTYPE_DA9131 }, { .compatible = "dlg,da9220", .data = (void *) DA9121_SUBTYPE_DA9220 }, { .compatible = "dlg,da9132", .data = (void *) DA9121_SUBTYPE_DA9132 }, + { .compatible = "dlg,da9141", .data = (void *) DA9121_SUBTYPE_DA9141 }, + { .compatible = "dlg,da9142", .data = (void *) DA9121_SUBTYPE_DA9142 }, { } }; MODULE_DEVICE_TABLE(of, da9121_dt_ids); @@ -1089,6 +1189,8 @@ static const struct i2c_device_id da9121_i2c_id[] = { {"da9131", DA9121_TYPE_DA9122_DA9131}, {"da9220", DA9121_TYPE_DA9220_DA9132}, {"da9132", DA9121_TYPE_DA9220_DA9132}, + {"da9141", DA9121_TYPE_DA9141}, + {"da9142", DA9121_TYPE_DA9142}, {}, }; MODULE_DEVICE_TABLE(i2c, da9121_i2c_id); diff --git a/drivers/regulator/da9121-regulator.h b/drivers/regulator/da9121-regulator.h index 357f416e17c1..a328a0bdfa29 100644 --- a/drivers/regulator/da9121-regulator.h +++ b/drivers/regulator/da9121-regulator.h @@ -26,7 +26,9 @@ enum da9121_variant { DA9121_TYPE_DA9121_DA9130, DA9121_TYPE_DA9220_DA9132, DA9121_TYPE_DA9122_DA9131, - DA9121_TYPE_DA9217 + DA9121_TYPE_DA9217, + DA9121_TYPE_DA9141, + DA9121_TYPE_DA9142 }; enum da9121_subvariant { @@ -36,7 +38,9 @@ enum da9121_subvariant { DA9121_SUBTYPE_DA9132, DA9121_SUBTYPE_DA9122, DA9121_SUBTYPE_DA9131, - DA9121_SUBTYPE_DA9217 + DA9121_SUBTYPE_DA9217, + DA9121_SUBTYPE_DA9141, + DA9121_SUBTYPE_DA9142 }; /* Minimum, maximum and default polling millisecond periods are provided @@ -70,6 +74,14 @@ enum da9121_subvariant { #define DA9121_REG_SYS_GPIO1_1 0x13 #define DA9121_REG_SYS_GPIO2_0 0x14 #define DA9121_REG_SYS_GPIO2_1 0x15 +#define DA914x_REG_SYS_GPIO3_0 0x16 +#define DA914x_REG_SYS_GPIO3_1 0x17 +#define DA914x_REG_SYS_GPIO4_0 0x18 +#define DA914x_REG_SYS_GPIO4_1 0x19 +#define DA914x_REG_SYS_ADMUX1_0 0x1A +#define DA914x_REG_SYS_ADMUX1_1 0x1B +#define DA914x_REG_SYS_ADMUX2_0 0x1C +#define DA914x_REG_SYS_ADMUX2_1 0x1D #define DA9121_REG_BUCK_BUCK1_0 0x20 #define DA9121_REG_BUCK_BUCK1_1 0x21 #define DA9121_REG_BUCK_BUCK1_2 0x22 @@ -276,6 +288,7 @@ enum da9121_subvariant { #define DA9121_MASK_OTP_DEVICE_ID_DEV_ID 0xFF #define DA9121_DEVICE_ID 0x05 +#define DA914x_DEVICE_ID 0x26 /* DA9121_REG_OTP_VARIANT_ID */ @@ -293,6 +306,10 @@ enum da9121_subvariant { #define DA9131_VARIANT_VRC 0x1 #define DA9132_VARIANT_VRC 0x2 +#define DA914x_VARIANT_MRC_BASE 0x0 +#define DA9141_VARIANT_VRC 0x1 +#define DA9142_VARIANT_VRC 0x2 + /* DA9121_REG_OTP_CUSTOMER_ID */ #define DA9121_MASK_OTP_CUSTOMER_ID_CUST_ID 0xFF -- cgit v1.2.3 From b9c044b7d63b2ffae9664349721c80c4ab3e56c9 Mon Sep 17 00:00:00 2001 From: Adam Ward Date: Mon, 29 Nov 2021 22:10:10 +0000 Subject: regulator: da9121: Remove erroneous compatible from binding Clean away information from a test that was included accidentally Signed-off-by: Adam Ward Acked-by: Rob Herring Link: https://lore.kernel.org/r/530a626cee6bc12ff5b4ab16319ac7a1fac6e306.1638223185.git.Adam.Ward.opensource@diasemi.com Signed-off-by: Mark Brown --- .../devicetree/bindings/regulator/dlg,da9121.yaml | 25 +++++++++++----------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/Documentation/devicetree/bindings/regulator/dlg,da9121.yaml b/Documentation/devicetree/bindings/regulator/dlg,da9121.yaml index 228018c87bea..0aee5fcd6093 100644 --- a/Documentation/devicetree/bindings/regulator/dlg,da9121.yaml +++ b/Documentation/devicetree/bindings/regulator/dlg,da9121.yaml @@ -25,19 +25,19 @@ description: | the rated current, this translates across the device range to per channel figures as so... - | DA9121 DA9122 DA9220 DA9217 DA9140 + | DA9121 DA9122 DA9220 DA9217 | /DA9130 /DA9131 /DA9132 - ----------------------------------------------------------------------------- - Output current / channel | 10000000 5000000 3000000 6000000 40000000 - Output current / phase | 5000000 5000000 3000000 3000000 9500000 - ----------------------------------------------------------------------------- - Min regulator-min-microvolt| 300000 300000 300000 300000 500000 - Max regulator-max-microvolt| 1900000 1900000 1900000 1900000 1000000 - Device hardware default | 1000000 1000000 1000000 1000000 1000000 - ----------------------------------------------------------------------------- - Min regulator-min-microamp | 7000000 3500000 3500000 7000000 26000000 - Max regulator-max-microamp | 20000000 10000000 6000000 12000000 78000000 - Device hardware default | 15000000 7500000 5500000 11000000 58000000 + ------------------------------------------------------------------- + Output current / channel | 10000000 5000000 3000000 6000000 + Output current / phase | 5000000 5000000 3000000 3000000 + ------------------------------------------------------------------- + Min regulator-min-microvolt| 300000 300000 300000 300000 + Max regulator-max-microvolt| 1900000 1900000 1900000 1900000 + Device hardware default | 1000000 1000000 1000000 1000000 + ------------------------------------------------------------------- + Min regulator-min-microamp | 7000000 3500000 3500000 7000000 + Max regulator-max-microamp | 20000000 10000000 6000000 12000000 + Device hardware default | 15000000 7500000 5500000 11000000 properties: $nodename: @@ -51,7 +51,6 @@ properties: - dlg,da9130 - dlg,da9131 - dlg,da9132 - - dlg,da9140 reg: maxItems: 1 -- cgit v1.2.3 From d07fef2fcd4d79198a700f4b4d2ca4670649c9ff Mon Sep 17 00:00:00 2001 From: Adam Ward Date: Mon, 29 Nov 2021 22:10:11 +0000 Subject: regulator: da9121: Add DA914x binding info Add the configuration for the DA9141 and DA9142 regulators. Also tidy the table, cleaning away superfluous information. Signed-off-by: Adam Ward Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/9293e3ae4ff8776704257085df65516b81209b87.1638223185.git.Adam.Ward.opensource@diasemi.com Signed-off-by: Mark Brown --- .../devicetree/bindings/regulator/dlg,da9121.yaml | 75 +++++++++++++--------- 1 file changed, 44 insertions(+), 31 deletions(-) diff --git a/Documentation/devicetree/bindings/regulator/dlg,da9121.yaml b/Documentation/devicetree/bindings/regulator/dlg,da9121.yaml index 0aee5fcd6093..24ace6e1e5ec 100644 --- a/Documentation/devicetree/bindings/regulator/dlg,da9121.yaml +++ b/Documentation/devicetree/bindings/regulator/dlg,da9121.yaml @@ -17,27 +17,39 @@ description: | Dialog Semiconductor DA9130 Single-channel 10A double-phase buck converter Dialog Semiconductor DA9131 Double-channel 5A single-phase buck converter Dialog Semiconductor DA9132 Double-channel 3A single-phase buck converter - - Current limits - - This is PER PHASE, and the current limit setting in the devices reflect - that with a maximum 10A limit. Allowing for transients at/near double - the rated current, this translates across the device range to per - channel figures as so... - - | DA9121 DA9122 DA9220 DA9217 - | /DA9130 /DA9131 /DA9132 - ------------------------------------------------------------------- - Output current / channel | 10000000 5000000 3000000 6000000 - Output current / phase | 5000000 5000000 3000000 3000000 - ------------------------------------------------------------------- - Min regulator-min-microvolt| 300000 300000 300000 300000 - Max regulator-max-microvolt| 1900000 1900000 1900000 1900000 - Device hardware default | 1000000 1000000 1000000 1000000 - ------------------------------------------------------------------- - Min regulator-min-microamp | 7000000 3500000 3500000 7000000 - Max regulator-max-microamp | 20000000 10000000 6000000 12000000 - Device hardware default | 15000000 7500000 5500000 11000000 + Dialog Semiconductor DA9141 Single-channel 40A quad-phase buck converter + Dialog Semiconductor DA9142 Single-channel 20A double-phase buck converter + + Device parameter ranges + + The current limits can be set to at/near double the rated current per channel + to allow for transient peaks. + Current limit changes when the output is enabled are not supported, as a + precaution against undefined behaviour. + + |----------------------------------------------| + | | range & reset default value | + | Device |------------------------------| + | | microvolt | microamp | + |----------------------------------------------| + | DA9121/DA9130 | Min: 300000 | Min: 7000000 | + | | Max: 1900000 | Max: 20000000 | + |----------------------------------------------| + | DA9121/DA9131 | Min: 300000 | Min: 3500000 | + | | Max: 1900000 | Max: 10000000 | + |----------------------------------------------| + | DA9121/DA9131 | Min: 300000 | Min: 3500000 | + | | Max: 1900000 | Max: 6000000 | + |----------------------------------------------| + | DA9217 | Min: 300000 | Min: 7000000 | + | | Max: 1900000 | Max: 12000000 | + |----------------------------------------------| + | DA9141 | Min: 300000 | Min: 26000000 | + | | Max: 1300000 | Max: 78000000 | + |----------------------------------------------| + | DA9142 | Min: 300000 | Min: 13000000 | + | | Max: 1300000 | Max: 39000000 | + |----------------------------------------------| properties: $nodename: @@ -51,6 +63,8 @@ properties: - dlg,da9130 - dlg,da9131 - dlg,da9132 + - dlg,da9141 + - dlg,da9142 reg: maxItems: 1 @@ -69,26 +83,24 @@ properties: regulators: type: object - $ref: regulator.yaml# description: | - This node defines the settings for the BUCK. The content of the - sub-node is defined by the standard binding for regulators; see regulator.yaml. - The DA9121 regulator is bound using their names listed below - buck1 - BUCK1 - buck2 - BUCK2 //DA9122, DA9220, DA9131, DA9132 only + List of regulators provided by the device patternProperties: "^buck([1-2])$": type: object $ref: regulator.yaml# + description: | + Properties for a single BUCK regulator properties: - regulator-mode: - maxItems: 1 - description: Defined in include/dt-bindings/regulator/dlg,da9121-regulator.h + regulator-name: + pattern: "^BUCK([1-2])$" + description: | + BUCK2 present in DA9122, DA9220, DA9131, DA9132 only regulator-initial-mode: - maxItems: 1 + enum: [ 0, 1, 2, 3 ] description: Defined in include/dt-bindings/regulator/dlg,da9121-regulator.h enable-gpios: @@ -97,6 +109,7 @@ properties: dlg,ripple-cancel: $ref: "/schemas/types.yaml#/definitions/uint32" + enum: [ 0, 1, 2, 3 ] description: | Defined in include/dt-bindings/regulator/dlg,da9121-regulator.h Only present on multi-channel devices (DA9122, DA9220, DA9131, DA9132) -- cgit v1.2.3 From fa3b06f59a03a3a4639755478e0cf5b508a1b454 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Wed, 1 Dec 2021 12:55:14 +0530 Subject: regulator: qcom,rpmh: Add compatible for PM8450 Add compatible string for PM8450 used in SM8450 boards. Signed-off-by: Vinod Koul Link: https://lore.kernel.org/r/20211201072515.3968843-2-vkoul@kernel.org Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/regulator/qcom,rpmh-regulator.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/regulator/qcom,rpmh-regulator.yaml b/Documentation/devicetree/bindings/regulator/qcom,rpmh-regulator.yaml index c02f08a7014c..5c73d3f639c7 100644 --- a/Documentation/devicetree/bindings/regulator/qcom,rpmh-regulator.yaml +++ b/Documentation/devicetree/bindings/regulator/qcom,rpmh-regulator.yaml @@ -43,6 +43,7 @@ description: | For PM8150L, smps1 - smps8, ldo1 - ldo11, bob, flash, rgb For PM8350, smps1 - smps12, ldo1 - ldo10 For PM8350C, smps1 - smps10, ldo1 - ldo13, bob + For PM8450, smps1 - smps6, ldo1 - ldo4 For PM8998, smps1 - smps13, ldo1 - ldo28, lvs1 - lvs2 For PMI8998, bob For PMR735A, smps1 - smps3, ldo1 - ldo7 @@ -62,6 +63,7 @@ properties: - qcom,pm8150l-rpmh-regulators - qcom,pm8350-rpmh-regulators - qcom,pm8350c-rpmh-regulators + - qcom,pm8450-rpmh-regulators - qcom,pm8998-rpmh-regulators - qcom,pmg1110-rpmh-regulators - qcom,pmi8998-rpmh-regulators -- cgit v1.2.3 From d69e19723f88a3ba6d4e0e52f51dd4c59cc2ae93 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Wed, 1 Dec 2021 12:55:15 +0530 Subject: regulator: qcom-rpmh: Add support for PM8450 regulators Add the rpmh regulators found in PM8450 PMIC Signed-off-by: Vinod Koul Tested-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20211201072515.3968843-3-vkoul@kernel.org Signed-off-by: Mark Brown --- drivers/regulator/qcom-rpmh-regulator.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/drivers/regulator/qcom-rpmh-regulator.c b/drivers/regulator/qcom-rpmh-regulator.c index 684143c828a5..a3bc0eb6ceb8 100644 --- a/drivers/regulator/qcom-rpmh-regulator.c +++ b/drivers/regulator/qcom-rpmh-regulator.c @@ -974,6 +974,20 @@ static const struct rpmh_vreg_init_data pm8350c_vreg_data[] = { {} }; +static const struct rpmh_vreg_init_data pm8450_vreg_data[] = { + RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps520, "vdd-s1"), + RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps520, "vdd-s2"), + RPMH_VREG("smps3", "smp%s3", &pmic5_ftsmps520, "vdd-s3"), + RPMH_VREG("smps4", "smp%s4", &pmic5_ftsmps520, "vdd-s4"), + RPMH_VREG("smps5", "smp%s5", &pmic5_ftsmps520, "vdd-s5"), + RPMH_VREG("smps6", "smp%s6", &pmic5_ftsmps520, "vdd-s6"), + RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo, "vdd-l1"), + RPMH_VREG("ldo2", "ldo%s2", &pmic5_nldo, "vdd-l2"), + RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo, "vdd-l3"), + RPMH_VREG("ldo4", "ldo%s4", &pmic5_pldo_lv, "vdd-l4"), + {} +}; + static const struct rpmh_vreg_init_data pm8009_vreg_data[] = { RPMH_VREG("smps1", "smp%s1", &pmic5_hfsmps510, "vdd-s1"), RPMH_VREG("smps2", "smp%s2", &pmic5_hfsmps515, "vdd-s2"), @@ -1218,6 +1232,10 @@ static const struct of_device_id __maybe_unused rpmh_regulator_match_table[] = { .compatible = "qcom,pm8350c-rpmh-regulators", .data = pm8350c_vreg_data, }, + { + .compatible = "qcom,pm8450-rpmh-regulators", + .data = pm8450_vreg_data, + }, { .compatible = "qcom,pm8998-rpmh-regulators", .data = pm8998_vreg_data, -- cgit v1.2.3 From 4aafc5c61b4c2be920b8a56b11279c5fadb8a6bf Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Mon, 6 Dec 2021 16:34:32 +0100 Subject: regulator: maxim,max8973: Document interrupts property One of the examples in the bindings has an interrupts property and the Linux kernel driver has support for requesting an interrupt as well. It looks like the absence from the bindings was just an oversight. Add the property to make sure the examples can be validated. Signed-off-by: Thierry Reding Acked-by: Rob Herring Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20211206153432.226963-1-thierry.reding@gmail.com Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/regulator/maxim,max8973.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/devicetree/bindings/regulator/maxim,max8973.yaml b/Documentation/devicetree/bindings/regulator/maxim,max8973.yaml index 54522827265b..35c53e27f78c 100644 --- a/Documentation/devicetree/bindings/regulator/maxim,max8973.yaml +++ b/Documentation/devicetree/bindings/regulator/maxim,max8973.yaml @@ -86,6 +86,9 @@ properties: reg: maxItems: 1 + interrupts: + maxItems: 1 + required: - compatible - reg -- cgit v1.2.3 From 8d2de3a548ad05fe09bca58f09ff1ab2e69cf40a Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Mon, 6 Dec 2021 16:37:26 +0100 Subject: regulator: Fix type of regulator-coupled-max-spread property According to the description and the various uses of this property it is meant to be an array of unsigned 32-bit values, so fixup the type to match that. Signed-off-by: Thierry Reding Acked-by: Rob Herring Link: https://lore.kernel.org/r/20211206153726.227464-1-thierry.reding@gmail.com Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/regulator/regulator.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/regulator/regulator.yaml b/Documentation/devicetree/bindings/regulator/regulator.yaml index a6ae9ecae5cc..ed560ee8714e 100644 --- a/Documentation/devicetree/bindings/regulator/regulator.yaml +++ b/Documentation/devicetree/bindings/regulator/regulator.yaml @@ -218,7 +218,7 @@ properties: description: Array of maximum spread between voltages of coupled regulators in microvolts, each value in the array relates to the corresponding couple specified by the regulator-coupled-with property. - $ref: "/schemas/types.yaml#/definitions/uint32" + $ref: "/schemas/types.yaml#/definitions/uint32-array" regulator-max-step-microvolt: description: Maximum difference between current and target voltages -- cgit v1.2.3 From 8d9f738f16a3ee9f2341578873c542ddd9802fe4 Mon Sep 17 00:00:00 2001 From: Yanteng Si Date: Tue, 7 Dec 2021 20:32:30 +0800 Subject: regulator: fix bullet lists of regulator_ops comment Since 89a6a5e56c82("regulator: add property parsing and callbacks to set protection limits") which introduced a warning: Documentation/driver-api/regulator:166: ./include/linux/regulator/driver.h:96: WARNING: Unexpected indentation. Documentation/driver-api/regulator:166: ./include/linux/regulator/driver.h:98: WARNING: Block quote ends without a blank line; unexpected unindent. Let's fix them. Signed-off-by: Yanteng Si Link: https://lore.kernel.org/r/20211207123230.2262047-1-siyanteng@loongson.cn Signed-off-by: Mark Brown --- include/linux/regulator/driver.h | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h index 4078c7776453..720684995a77 100644 --- a/include/linux/regulator/driver.h +++ b/include/linux/regulator/driver.h @@ -90,15 +90,19 @@ enum regulator_detection_severity { * @set_over_current_protection: Support enabling of and setting limits for over * current situation detection. Detection can be configured for three * levels of severity. - * REGULATOR_SEVERITY_PROT should automatically shut down the regulator(s). - * REGULATOR_SEVERITY_ERR should indicate that over-current situation is - * caused by an unrecoverable error but HW does not perform - * automatic shut down. - * REGULATOR_SEVERITY_WARN should indicate situation where hardware is - * still believed to not be damaged but that a board sepcific - * recovery action is needed. If lim_uA is 0 the limit should not - * be changed but the detection should just be enabled/disabled as - * is requested. + * + * - REGULATOR_SEVERITY_PROT should automatically shut down the regulator(s). + * + * - REGULATOR_SEVERITY_ERR should indicate that over-current situation is + * caused by an unrecoverable error but HW does not perform + * automatic shut down. + * + * - REGULATOR_SEVERITY_WARN should indicate situation where hardware is + * still believed to not be damaged but that a board sepcific + * recovery action is needed. If lim_uA is 0 the limit should not + * be changed but the detection should just be enabled/disabled as + * is requested. + * * @set_over_voltage_protection: Support enabling of and setting limits for over * voltage situation detection. Detection can be configured for same * severities as over current protection. Units of uV. -- cgit v1.2.3 From c57dbcab04449ec869561a9056d0de1a07cbb863 Mon Sep 17 00:00:00 2001 From: Minghao Chi Date: Mon, 13 Dec 2021 02:16:55 +0000 Subject: drivers/regulator: remove redundant ret variable Return value from twlreg_write() directly instead of taking this in another redundant variable. Reported-by: Zeal Robot Signed-off-by: Minghao Chi Link: https://lore.kernel.org/r/20211213021655.435423-1-chi.minghao@zte.com.cn Signed-off-by: Mark Brown --- drivers/regulator/twl-regulator.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/drivers/regulator/twl-regulator.c b/drivers/regulator/twl-regulator.c index 4a51cfea45ac..e2a20d512152 100644 --- a/drivers/regulator/twl-regulator.c +++ b/drivers/regulator/twl-regulator.c @@ -196,7 +196,6 @@ static int twl4030reg_enable(struct regulator_dev *rdev) { struct twlreg_info *info = rdev_get_drvdata(rdev); int grp; - int ret; grp = twlreg_grp(rdev); if (grp < 0) @@ -204,16 +203,13 @@ static int twl4030reg_enable(struct regulator_dev *rdev) grp |= P1_GRP_4030; - ret = twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_GRP, grp); - - return ret; + return twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_GRP, grp); } static int twl4030reg_disable(struct regulator_dev *rdev) { struct twlreg_info *info = rdev_get_drvdata(rdev); int grp; - int ret; grp = twlreg_grp(rdev); if (grp < 0) @@ -221,9 +217,7 @@ static int twl4030reg_disable(struct regulator_dev *rdev) grp &= ~(P1_GRP_4030 | P2_GRP_4030 | P3_GRP_4030); - ret = twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_GRP, grp); - - return ret; + return twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_GRP, grp); } static int twl4030reg_get_status(struct regulator_dev *rdev) -- cgit v1.2.3 From 0fc31d8f1a8ad17224f6423e3ed6234507375d48 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 3 Dec 2021 11:28:48 +0100 Subject: regulator: Introduce tps68470-regulator driver The TPS68470 PMIC provides Clocks, GPIOs and Regulators. At present in the kernel the Regulators and Clocks are controlled by an OpRegion driver designed to work with power control methods defined in ACPI, but some platforms lack those methods, meaning drivers need to be able to consume the resources of these chips through the usual frameworks. This commit adds a driver for the regulators provided by the tps68470, and is designed to bind to the platform_device registered by the intel_skl_int3472 module. This is based on this out of tree driver written by Intel: https://github.com/intel/linux-intel-lts/blob/4.14/base/drivers/regulator/tps68470-regulator.c with various cleanups added. Reviewed-by: Andy Shevchenko Signed-off-by: Hans de Goede Link: https://lore.kernel.org/r/20211203102857.44539-6-hdegoede@redhat.com Signed-off-by: Mark Brown --- drivers/regulator/Kconfig | 9 ++ drivers/regulator/Makefile | 1 + drivers/regulator/tps68470-regulator.c | 201 +++++++++++++++++++++++++++++++++ 3 files changed, 211 insertions(+) create mode 100644 drivers/regulator/tps68470-regulator.c diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 6be9b1c8a615..ebe46e09510e 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -1339,6 +1339,15 @@ config REGULATOR_TPS65912 help This driver supports TPS65912 voltage regulator chip. +config REGULATOR_TPS68470 + tristate "TI TPS68470 PMIC Regulators Driver" + depends on INTEL_SKL_INT3472 || COMPILE_TEST + help + This driver adds support for the TPS68470 PMIC to register + regulators against the usual framework. + + The module will be called "tps68470-regulator". + config REGULATOR_TWL4030 tristate "TI TWL4030/TWL5030/TWL6030/TPS659x0 PMIC" depends on TWL4030_CORE diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index b07d2a22df0b..257331d2caed 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -159,6 +159,7 @@ obj-$(CONFIG_REGULATOR_TPS6586X) += tps6586x-regulator.o obj-$(CONFIG_REGULATOR_TPS65910) += tps65910-regulator.o obj-$(CONFIG_REGULATOR_TPS65912) += tps65912-regulator.o obj-$(CONFIG_REGULATOR_TPS65132) += tps65132-regulator.o +obj-$(CONFIG_REGULATOR_TPS68470) += tps68470-regulator.o obj-$(CONFIG_REGULATOR_TWL4030) += twl-regulator.o twl6030-regulator.o obj-$(CONFIG_REGULATOR_UNIPHIER) += uniphier-regulator.o obj-$(CONFIG_REGULATOR_VCTRL) += vctrl-regulator.o diff --git a/drivers/regulator/tps68470-regulator.c b/drivers/regulator/tps68470-regulator.c new file mode 100644 index 000000000000..4bca7c4128ab --- /dev/null +++ b/drivers/regulator/tps68470-regulator.c @@ -0,0 +1,201 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Regulator driver for TPS68470 PMIC +// +// Copyright (c) 2021 Red Hat Inc. +// Copyright (C) 2018 Intel Corporation +// +// Authors: +// Hans de Goede +// Zaikuo Wang +// Tianshu Qiu +// Jian Xu Zheng +// Yuning Pu +// Rajmohan Mani + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct tps68470_regulator_data { + struct clk *clk; +}; + +#define TPS68470_REGULATOR(_name, _id, _ops, _n, \ + _vr, _vm, _er, _em, _lr, _nlr) \ + [TPS68470_ ## _name] = { \ + .name = # _name, \ + .id = _id, \ + .ops = &_ops, \ + .n_voltages = _n, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + .vsel_reg = _vr, \ + .vsel_mask = _vm, \ + .enable_reg = _er, \ + .enable_mask = _em, \ + .linear_ranges = _lr, \ + .n_linear_ranges = _nlr, \ + } + +static const struct linear_range tps68470_ldo_ranges[] = { + REGULATOR_LINEAR_RANGE(875000, 0, 125, 17800), +}; + +static const struct linear_range tps68470_core_ranges[] = { + REGULATOR_LINEAR_RANGE(900000, 0, 42, 25000), +}; + +static int tps68470_regulator_enable(struct regulator_dev *rdev) +{ + struct tps68470_regulator_data *data = rdev->reg_data; + int ret; + + /* The Core buck regulator needs the PMIC's PLL to be enabled */ + if (rdev->desc->id == TPS68470_CORE) { + ret = clk_prepare_enable(data->clk); + if (ret) { + dev_err(&rdev->dev, "Error enabling TPS68470 clock\n"); + return ret; + } + } + + return regulator_enable_regmap(rdev); +} + +static int tps68470_regulator_disable(struct regulator_dev *rdev) +{ + struct tps68470_regulator_data *data = rdev->reg_data; + + if (rdev->desc->id == TPS68470_CORE) + clk_disable_unprepare(data->clk); + + return regulator_disable_regmap(rdev); +} + +/* Operations permitted on DCDCx, LDO2, LDO3 and LDO4 */ +static const struct regulator_ops tps68470_regulator_ops = { + .is_enabled = regulator_is_enabled_regmap, + .enable = tps68470_regulator_enable, + .disable = tps68470_regulator_disable, + .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 regulator_ops tps68470_always_on_reg_ops = { + .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 regulator_desc regulators[] = { + TPS68470_REGULATOR(CORE, TPS68470_CORE, tps68470_regulator_ops, 43, + TPS68470_REG_VDVAL, TPS68470_VDVAL_DVOLT_MASK, + TPS68470_REG_VDCTL, TPS68470_VDCTL_EN_MASK, + tps68470_core_ranges, ARRAY_SIZE(tps68470_core_ranges)), + TPS68470_REGULATOR(ANA, TPS68470_ANA, tps68470_regulator_ops, 126, + TPS68470_REG_VAVAL, TPS68470_VAVAL_AVOLT_MASK, + TPS68470_REG_VACTL, TPS68470_VACTL_EN_MASK, + tps68470_ldo_ranges, ARRAY_SIZE(tps68470_ldo_ranges)), + TPS68470_REGULATOR(VCM, TPS68470_VCM, tps68470_regulator_ops, 126, + TPS68470_REG_VCMVAL, TPS68470_VCMVAL_VCVOLT_MASK, + TPS68470_REG_VCMCTL, TPS68470_VCMCTL_EN_MASK, + tps68470_ldo_ranges, ARRAY_SIZE(tps68470_ldo_ranges)), + TPS68470_REGULATOR(VIO, TPS68470_VIO, tps68470_always_on_reg_ops, 126, + TPS68470_REG_VIOVAL, TPS68470_VIOVAL_IOVOLT_MASK, + 0, 0, + tps68470_ldo_ranges, ARRAY_SIZE(tps68470_ldo_ranges)), +/* + * (1) This regulator must have the same voltage as VIO if S_IO LDO is used to + * power a sensor/VCM which I2C is daisy chained behind the PMIC. + * (2) If there is no I2C daisy chain it can be set freely. + */ + TPS68470_REGULATOR(VSIO, TPS68470_VSIO, tps68470_regulator_ops, 126, + TPS68470_REG_VSIOVAL, TPS68470_VSIOVAL_IOVOLT_MASK, + TPS68470_REG_S_I2C_CTL, TPS68470_S_I2C_CTL_EN_MASK, + tps68470_ldo_ranges, ARRAY_SIZE(tps68470_ldo_ranges)), + TPS68470_REGULATOR(AUX1, TPS68470_AUX1, tps68470_regulator_ops, 126, + TPS68470_REG_VAUX1VAL, TPS68470_VAUX1VAL_AUX1VOLT_MASK, + TPS68470_REG_VAUX1CTL, TPS68470_VAUX1CTL_EN_MASK, + tps68470_ldo_ranges, ARRAY_SIZE(tps68470_ldo_ranges)), + TPS68470_REGULATOR(AUX2, TPS68470_AUX2, tps68470_regulator_ops, 126, + TPS68470_REG_VAUX2VAL, TPS68470_VAUX2VAL_AUX2VOLT_MASK, + TPS68470_REG_VAUX2CTL, TPS68470_VAUX2CTL_EN_MASK, + tps68470_ldo_ranges, ARRAY_SIZE(tps68470_ldo_ranges)), +}; + +static int tps68470_regulator_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct tps68470_regulator_platform_data *pdata = dev_get_platdata(dev); + struct tps68470_regulator_data *data; + struct regulator_config config = { }; + struct regulator_dev *rdev; + int i; + + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->clk = devm_clk_get(dev, "tps68470-clk"); + if (IS_ERR(data->clk)) + return dev_err_probe(dev, PTR_ERR(data->clk), "getting tps68470-clk\n"); + + config.dev = dev->parent; + config.regmap = dev_get_drvdata(dev->parent); + config.driver_data = data; + + for (i = 0; i < TPS68470_NUM_REGULATORS; i++) { + if (pdata) + config.init_data = pdata->reg_init_data[i]; + else + config.init_data = NULL; + + rdev = devm_regulator_register(dev, ®ulators[i], &config); + if (IS_ERR(rdev)) + return dev_err_probe(dev, PTR_ERR(rdev), + "registering %s regulator\n", + regulators[i].name); + } + + return 0; +} + +static struct platform_driver tps68470_regulator_driver = { + .driver = { + .name = "tps68470-regulator", + }, + .probe = tps68470_regulator_probe, +}; + +/* + * The ACPI tps68470 probe-ordering depends on the clk/gpio/regulator drivers + * registering before the drivers for the camera-sensors which use them bind. + * subsys_initcall() ensures this when the drivers are builtin. + */ +static int __init tps68470_regulator_init(void) +{ + return platform_driver_register(&tps68470_regulator_driver); +} +subsys_initcall(tps68470_regulator_init); + +static void __exit tps68470_regulator_exit(void) +{ + platform_driver_unregister(&tps68470_regulator_driver); +} +module_exit(tps68470_regulator_exit); + +MODULE_ALIAS("platform:tps68470-regulator"); +MODULE_DESCRIPTION("TPS68470 voltage regulator driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 5d55cbc720cc3650aafed6c1f5dbcf7e3f276312 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 21 Dec 2021 08:07:43 -0400 Subject: regulator: dt-bindings: samsung,s5m8767: Move fixed string BUCK9 to 'properties' There's no need for a fixed string like 'BUCK9' to be under 'patternProperties', so move it under 'properties' instead. Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/20211221120744.1118518-1-robh@kernel.org Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/regulator/samsung,s5m8767.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/regulator/samsung,s5m8767.yaml b/Documentation/devicetree/bindings/regulator/samsung,s5m8767.yaml index 80a63d47790a..6c8ad82bd69c 100644 --- a/Documentation/devicetree/bindings/regulator/samsung,s5m8767.yaml +++ b/Documentation/devicetree/bindings/regulator/samsung,s5m8767.yaml @@ -54,8 +54,9 @@ patternProperties: required: - regulator-name +properties: # 9 buck - "^BUCK9$": + BUCK9: type: object $ref: regulator.yaml# unevaluatedProperties: false -- cgit v1.2.3 From d27bb69dc83f00f86a830298c967052cded6e784 Mon Sep 17 00:00:00 2001 From: Marijn Suijten Date: Fri, 24 Dec 2021 12:34:50 +0100 Subject: regulator: qcom-labibb: OCP interrupts are not a failure while disabled Receiving the Over-Current Protection interrupt while the regulator is disabled does not count as unhandled/failure (IRQ_NONE, or 0 as it were) but a "fake event", usually due to inrush as the is regulator about to be enabled. Fixes: 390af53e0411 ("regulator: qcom-labibb: Implement short-circuit and over-current IRQs") Signed-off-by: Marijn Suijten Reviewed-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20211224113450.107958-1-marijn.suijten@somainline.org Signed-off-by: Mark Brown --- drivers/regulator/qcom-labibb-regulator.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/regulator/qcom-labibb-regulator.c b/drivers/regulator/qcom-labibb-regulator.c index b3da0dc58782..639b71eb41ff 100644 --- a/drivers/regulator/qcom-labibb-regulator.c +++ b/drivers/regulator/qcom-labibb-regulator.c @@ -260,7 +260,7 @@ static irqreturn_t qcom_labibb_ocp_isr(int irq, void *chip) /* If the regulator is not enabled, this is a fake event */ if (!ops->is_enabled(vreg->rdev)) - return 0; + return IRQ_HANDLED; /* If we tried to recover for too many times it's not getting better */ if (vreg->ocp_irq_count > LABIBB_MAX_OCP_COUNT) -- cgit v1.2.3 From 1f156b4285865dc2eb66e7a78c7ba80c17bb2b0a Mon Sep 17 00:00:00 2001 From: Minghao Chi Date: Tue, 4 Jan 2022 10:41:39 +0000 Subject: regulator: remove redundant ret variable Return value from regmap_update_bits() directly instead of taking this in another redundant variable. Reported-by: Zeal Robot Signed-off-by: Minghao Chi Signed-off-by: CGEL ZTE Link: https://lore.kernel.org/r/20220104104139.601031-1-chi.minghao@zte.com.cn Signed-off-by: Mark Brown --- drivers/regulator/mt6380-regulator.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/regulator/mt6380-regulator.c b/drivers/regulator/mt6380-regulator.c index 9efd8710a6f3..2e6b61d3b0cf 100644 --- a/drivers/regulator/mt6380-regulator.c +++ b/drivers/regulator/mt6380-regulator.c @@ -183,7 +183,7 @@ static const unsigned int ldo_volt_table4[] = { static int mt6380_regulator_set_mode(struct regulator_dev *rdev, unsigned int mode) { - int ret, val = 0; + int val = 0; struct mt6380_regulator_info *info = rdev_get_drvdata(rdev); switch (mode) { @@ -199,10 +199,8 @@ static int mt6380_regulator_set_mode(struct regulator_dev *rdev, val <<= ffs(info->modeset_mask) - 1; - ret = regmap_update_bits(rdev->regmap, info->modeset_reg, + return regmap_update_bits(rdev->regmap, info->modeset_reg, info->modeset_mask, val); - - return ret; } static unsigned int mt6380_regulator_get_mode(struct regulator_dev *rdev) -- cgit v1.2.3 From 14e2976fbabdacb01335d7f91eeebbc89c67ddb1 Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Thu, 30 Dec 2021 03:34:42 +0100 Subject: regulator: qcom_smd: Align probe function with rpmh-regulator The RPMh regulator driver is much newer and gets more attention, which in consequence makes it do a few things better. Update qcom_smd-regulator's probe function to mimic what rpmh-regulator does to address a couple of issues: - Probe defer now works correctly, before it used to, well, kinda just die.. This fixes reliable probing on (at least) PM8994, because Linux apparently cannot deal with supply map dependencies yet.. - Regulator data is now matched more sanely: regulator data is matched against each individual regulator node name and throwing an -EINVAL if data is missing, instead of just assuming everything is fine and iterating over all subsequent array members. - status = "disabled" will now work for disabling individual regulators in DT. Previously it didn't seem to do much if anything at all. Signed-off-by: Konrad Dybcio Link: https://lore.kernel.org/r/20211230023442.1123424-1-konrad.dybcio@somainline.org Signed-off-by: Mark Brown --- drivers/regulator/qcom_smd-regulator.c | 100 +++++++++++++++++++++++---------- 1 file changed, 70 insertions(+), 30 deletions(-) diff --git a/drivers/regulator/qcom_smd-regulator.c b/drivers/regulator/qcom_smd-regulator.c index 8bac024dde8b..9fc666107a06 100644 --- a/drivers/regulator/qcom_smd-regulator.c +++ b/drivers/regulator/qcom_smd-regulator.c @@ -9,6 +9,7 @@ #include #include #include +#include #include struct qcom_rpm_reg { @@ -1239,52 +1240,91 @@ static const struct of_device_id rpm_of_match[] = { }; MODULE_DEVICE_TABLE(of, rpm_of_match); -static int rpm_reg_probe(struct platform_device *pdev) +/** + * rpm_regulator_init_vreg() - initialize all attributes of a qcom_smd-regulator + * @vreg: Pointer to the individual qcom_smd-regulator resource + * @dev: Pointer to the top level qcom_smd-regulator PMIC device + * @node: Pointer to the individual qcom_smd-regulator resource + * device node + * @rpm: Pointer to the rpm bus node + * @pmic_rpm_data: Pointer to a null-terminated array of qcom_smd-regulator + * resources defined for the top level PMIC device + * + * Return: 0 on success, errno on failure + */ +static int rpm_regulator_init_vreg(struct qcom_rpm_reg *vreg, struct device *dev, + struct device_node *node, struct qcom_smd_rpm *rpm, + const struct rpm_regulator_data *pmic_rpm_data) { - const struct rpm_regulator_data *reg; - const struct of_device_id *match; - struct regulator_config config = { }; + struct regulator_config config = {}; + const struct rpm_regulator_data *rpm_data; struct regulator_dev *rdev; + int ret; + + for (rpm_data = pmic_rpm_data; rpm_data->name; rpm_data++) + if (of_node_name_eq(node, rpm_data->name)) + break; + + if (!rpm_data->name) { + dev_err(dev, "Unknown regulator %pOFn\n", node); + return -EINVAL; + } + + vreg->dev = dev; + vreg->rpm = rpm; + vreg->type = rpm_data->type; + vreg->id = rpm_data->id; + + memcpy(&vreg->desc, rpm_data->desc, sizeof(vreg->desc)); + vreg->desc.name = rpm_data->name; + vreg->desc.supply_name = rpm_data->supply; + vreg->desc.owner = THIS_MODULE; + vreg->desc.type = REGULATOR_VOLTAGE; + vreg->desc.of_match = rpm_data->name; + + config.dev = dev; + config.of_node = node; + config.driver_data = vreg; + + rdev = devm_regulator_register(dev, &vreg->desc, &config); + if (IS_ERR(rdev)) { + ret = PTR_ERR(rdev); + dev_err(dev, "%pOFn: devm_regulator_register() failed, ret=%d\n", node, ret); + return ret; + } + + return 0; +} + +static int rpm_reg_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + const struct rpm_regulator_data *vreg_data; + struct device_node *node; struct qcom_rpm_reg *vreg; struct qcom_smd_rpm *rpm; + int ret; rpm = dev_get_drvdata(pdev->dev.parent); if (!rpm) { - dev_err(&pdev->dev, "unable to retrieve handle to rpm\n"); + dev_err(&pdev->dev, "Unable to retrieve handle to rpm\n"); return -ENODEV; } - match = of_match_device(rpm_of_match, &pdev->dev); - if (!match) { - dev_err(&pdev->dev, "failed to match device\n"); + vreg_data = of_device_get_match_data(dev); + if (!vreg_data) return -ENODEV; - } - for (reg = match->data; reg->name; reg++) { + for_each_available_child_of_node(dev->of_node, node) { vreg = devm_kzalloc(&pdev->dev, sizeof(*vreg), GFP_KERNEL); if (!vreg) return -ENOMEM; - vreg->dev = &pdev->dev; - vreg->type = reg->type; - vreg->id = reg->id; - vreg->rpm = rpm; - - memcpy(&vreg->desc, reg->desc, sizeof(vreg->desc)); - - vreg->desc.id = -1; - vreg->desc.owner = THIS_MODULE; - vreg->desc.type = REGULATOR_VOLTAGE; - vreg->desc.name = reg->name; - vreg->desc.supply_name = reg->supply; - vreg->desc.of_match = reg->name; - - config.dev = &pdev->dev; - config.driver_data = vreg; - rdev = devm_regulator_register(&pdev->dev, &vreg->desc, &config); - if (IS_ERR(rdev)) { - dev_err(&pdev->dev, "failed to register %s\n", reg->name); - return PTR_ERR(rdev); + ret = rpm_regulator_init_vreg(vreg, dev, node, rpm, vreg_data); + + if (ret < 0) { + of_node_put(node); + return ret; } } -- cgit v1.2.3 From 764aaa4e031a9acd26babc622cabe652f57bbb04 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 7 Jan 2022 00:43:49 +0200 Subject: dt-bindings: regulators: Add bindings for Maxim MAX20086-MAX20089 The MAX20086-MAX20089 are dual/quad power protectors for cameras. Add corresponding DT bindings. Signed-off-by: Laurent Pinchart Link: https://lore.kernel.org/r/20220106224350.16957-2-laurent.pinchart+renesas@ideasonboard.com Signed-off-by: Mark Brown --- .../bindings/regulator/maxim,max20086.yaml | 106 +++++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 Documentation/devicetree/bindings/regulator/maxim,max20086.yaml diff --git a/Documentation/devicetree/bindings/regulator/maxim,max20086.yaml b/Documentation/devicetree/bindings/regulator/maxim,max20086.yaml new file mode 100644 index 000000000000..05f72391185e --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/maxim,max20086.yaml @@ -0,0 +1,106 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/regulator/maxim,max20086.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Maxim Integrated MAX20086-MAX20089 Camera Power Protector + +maintainers: + - Laurent Pinchart + +description: | + The MAX20086-MAX20089 are dual/quad camera power protectors, designed to + deliver power over coax for radar and camera modules. They support + software-configurable output switching and monitoring. The output voltage and + current limit are fixed by the hardware design. + +properties: + compatible: + enum: + - maxim,max20086 + - maxim,max20087 + - maxim,max20088 + - maxim,max20089 + + reg: + maxItems: 1 + + enable-gpios: + maxItems: 1 + description: GPIO connected to the EN pin, active high + + in-supply: + description: Input supply for the camera outputs (IN pin, 3.0V to 15.0V) + + vdd-supply: + description: Input supply for the device (VDD pin, 3.0V to 5.5V) + + regulators: + type: object + + patternProperties: + "^OUT[1-4]$": + type: object + $ref: regulator.yaml# + + additionalProperties: false + +required: + - compatible + - reg + - in-supply + - vdd-supply + - regulators + +allOf: + - if: + properties: + compatible: + contains: + enum: + - maxim,max20088 + - maxim,max20089 + then: + properties: + regulators: + properties: + OUT3: false + OUT4: false + +additionalProperties: false + +examples: + - | + #include + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + regulator@28 { + compatible = "maxim,max20087"; + reg = <0x28>; + + in-supply = <®_12v0>; + vdd-supply = <®_3v3>; + + enable-gpios = <&gpio 108 GPIO_ACTIVE_HIGH>; + + regulators { + OUT1 { + regulator-name = "VOUT1"; + }; + OUT2 { + regulator-name = "VOUT2"; + }; + OUT3 { + regulator-name = "VOUT3"; + }; + OUT4 { + regulator-name = "VOUT4"; + }; + }; + }; + }; +... -- cgit v1.2.3 From bfff546aae50ae68ed395bf0e0848188d27b0ba3 Mon Sep 17 00:00:00 2001 From: Watson Chow Date: Fri, 7 Jan 2022 00:43:50 +0200 Subject: regulator: Add MAX20086-MAX20089 driver The MAX20086-MAX20089 are dual/quad power protectors for cameras. Add a driver that supports controlling the outputs individually. Additional features, such as overcurrent detection, may be added later if needed. Signed-off-by: Watson Chow Signed-off-by: Laurent Pinchart Link: https://lore.kernel.org/r/20220106224350.16957-3-laurent.pinchart+renesas@ideasonboard.com Signed-off-by: Mark Brown --- MAINTAINERS | 7 + drivers/regulator/Kconfig | 10 +- drivers/regulator/Makefile | 1 + drivers/regulator/max20086-regulator.c | 332 +++++++++++++++++++++++++++++++++ 4 files changed, 349 insertions(+), 1 deletion(-) create mode 100644 drivers/regulator/max20086-regulator.c diff --git a/MAINTAINERS b/MAINTAINERS index 7a2345ce8521..d15a92b45e75 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -11558,6 +11558,13 @@ S: Maintained F: Documentation/devicetree/bindings/power/supply/maxim,max17042.yaml F: drivers/power/supply/max17042_battery.c +MAXIM MAX20086 CAMERA POWER PROTECTOR DRIVER +M: Laurent Pinchart +L: linux-kernel@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/regulator/maxim,max20086.yaml +F: drivers/regulator/max20086-regulator.c + MAXIM MAX77650 PMIC MFD DRIVER M: Bartosz Golaszewski L: linux-kernel@vger.kernel.org diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index ebe46e09510e..1c35fed20d34 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -636,6 +636,15 @@ config REGULATOR_MAX8998 via I2C bus. The provided regulator is suitable for S3C6410 and S5PC1XX chips to control VCC_CORE and VCC_USIM voltages. +config REGULATOR_MAX20086 + tristate "Maxim MAX20086-MAX20089 Camera Power Protectors" + depends on I2C + select REGMAP_I2C + help + This driver controls a Maxim MAX20086-MAX20089 camera power + protectorvia I2C bus. The regulator has 2 or 4 outputs depending on + the device model. This driver is only capable to turn on/off them. + config REGULATOR_MAX77686 tristate "Maxim 77686 regulator" depends on MFD_MAX77686 || COMPILE_TEST @@ -1424,4 +1433,3 @@ config REGULATOR_QCOM_LABIBB for LCD display panel. endif - diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index 257331d2caed..2e1b087489fa 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -78,6 +78,7 @@ obj-$(CONFIG_REGULATOR_MAX8952) += max8952.o obj-$(CONFIG_REGULATOR_MAX8973) += max8973-regulator.o obj-$(CONFIG_REGULATOR_MAX8997) += max8997-regulator.o obj-$(CONFIG_REGULATOR_MAX8998) += max8998.o +obj-$(CONFIG_REGULATOR_MAX20086) += max20086-regulator.o obj-$(CONFIG_REGULATOR_MAX77686) += max77686-regulator.o obj-$(CONFIG_REGULATOR_MAX77693) += max77693-regulator.o obj-$(CONFIG_REGULATOR_MAX77802) += max77802-regulator.o diff --git a/drivers/regulator/max20086-regulator.c b/drivers/regulator/max20086-regulator.c new file mode 100644 index 000000000000..fbc56b043071 --- /dev/null +++ b/drivers/regulator/max20086-regulator.c @@ -0,0 +1,332 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// +// max20086-regulator.c - MAX20086-MAX20089 camera power protector driver +// +// Copyright (C) 2022 Laurent Pinchart +// Copyright (C) 2018 Avnet, Inc. + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Register Offset */ +#define MAX20086_REG_MASK 0x00 +#define MAX20086_REG_CONFIG 0x01 +#define MAX20086_REG_ID 0x02 +#define MAX20086_REG_STAT1 0x03 +#define MAX20086_REG_STAT2_L 0x04 +#define MAX20086_REG_STAT2_H 0x05 +#define MAX20086_REG_ADC1 0x06 +#define MAX20086_REG_ADC2 0x07 +#define MAX20086_REG_ADC3 0x08 +#define MAX20086_REG_ADC4 0x09 + +/* DEVICE IDs */ +#define MAX20086_DEVICE_ID_MAX20086 0x40 +#define MAX20086_DEVICE_ID_MAX20087 0x20 +#define MAX20086_DEVICE_ID_MAX20088 0x10 +#define MAX20086_DEVICE_ID_MAX20089 0x00 +#define DEVICE_ID_MASK 0xf0 + +/* Register bits */ +#define MAX20086_EN_MASK 0x0f +#define MAX20086_EN_OUT1 0x01 +#define MAX20086_EN_OUT2 0x02 +#define MAX20086_EN_OUT3 0x04 +#define MAX20086_EN_OUT4 0x08 +#define MAX20086_INT_DISABLE_ALL 0x3f + +#define MAX20086_MAX_REGULATORS 4 + +struct max20086_chip_info { + u8 id; + unsigned int num_outputs; +}; + +struct max20086_regulator { + struct device_node *of_node; + struct regulator_init_data *init_data; + const struct regulator_desc *desc; + struct regulator_dev *rdev; +}; + +struct max20086 { + struct device *dev; + struct regmap *regmap; + struct gpio_desc *ena_gpiod; + + const struct max20086_chip_info *info; + + struct max20086_regulator regulators[MAX20086_MAX_REGULATORS]; +}; + +static const struct regulator_ops max20086_buck_ops = { + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, +}; + +#define MAX20086_REGULATOR_DESC(n) \ +{ \ + .name = "OUT"#n, \ + .supply_name = "in", \ + .id = (n) - 1, \ + .ops = &max20086_buck_ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + .enable_reg = MAX20086_REG_CONFIG, \ + .enable_mask = 1 << ((n) - 1), \ + .enable_val = 1 << ((n) - 1), \ + .disable_val = 0, \ +} + +static const char * const max20086_output_names[] = { + "OUT1", + "OUT2", + "OUT3", + "OUT4", +}; + +static const struct regulator_desc max20086_regulators[] = { + MAX20086_REGULATOR_DESC(1), + MAX20086_REGULATOR_DESC(2), + MAX20086_REGULATOR_DESC(3), + MAX20086_REGULATOR_DESC(4), +}; + +static int max20086_regulators_register(struct max20086 *chip) +{ + unsigned int i; + + for (i = 0; i < chip->info->num_outputs; i++) { + struct max20086_regulator *reg = &chip->regulators[i]; + struct regulator_config config = { }; + struct regulator_dev *rdev; + + config.dev = chip->dev; + config.init_data = reg->init_data; + config.driver_data = chip; + config.of_node = reg->of_node; + config.regmap = chip->regmap; + config.ena_gpiod = chip->ena_gpiod; + + rdev = devm_regulator_register(chip->dev, reg->desc, &config); + if (IS_ERR(rdev)) { + dev_err(chip->dev, + "Failed to register regulator output %s\n", + reg->desc->name); + return PTR_ERR(rdev); + } + + reg->rdev = rdev; + } + + return 0; +} + +static int max20086_parse_regulators_dt(struct max20086 *chip, bool *boot_on) +{ + struct of_regulator_match matches[MAX20086_MAX_REGULATORS] = { }; + struct device_node *node; + unsigned int i; + int ret; + + node = of_get_child_by_name(chip->dev->of_node, "regulators"); + if (!node) { + dev_err(chip->dev, "regulators node not found\n"); + return PTR_ERR(node); + } + + for (i = 0; i < chip->info->num_outputs; ++i) + matches[i].name = max20086_output_names[i]; + + ret = of_regulator_match(chip->dev, node, matches, + chip->info->num_outputs); + of_node_put(node); + if (ret < 0) { + dev_err(chip->dev, "Failed to match regulators\n"); + return -EINVAL; + } + + *boot_on = false; + + for (i = 0; i < chip->info->num_outputs; i++) { + struct max20086_regulator *reg = &chip->regulators[i]; + + reg->init_data = matches[i].init_data; + reg->of_node = matches[i].of_node; + reg->desc = &max20086_regulators[i]; + + if (reg->init_data) { + if (reg->init_data->constraints.always_on || + reg->init_data->constraints.boot_on) + *boot_on = true; + } + } + + return 0; +} + +static int max20086_detect(struct max20086 *chip) +{ + unsigned int data; + int ret; + + ret = regmap_read(chip->regmap, MAX20086_REG_ID, &data); + if (ret < 0) { + dev_err(chip->dev, "Failed to read DEVICE_ID reg: %d\n", ret); + return ret; + } + + if ((data & DEVICE_ID_MASK) != chip->info->id) { + dev_err(chip->dev, "Invalid device ID 0x%02x\n", data); + return -ENXIO; + } + + return 0; +} + +static bool max20086_gen_is_writeable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case MAX20086_REG_MASK: + case MAX20086_REG_CONFIG: + return true; + default: + return false; + } +} + +static const struct regmap_config max20086_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .writeable_reg = max20086_gen_is_writeable_reg, + .max_register = 0x9, + .cache_type = REGCACHE_NONE, +}; + +static int max20086_i2c_probe(struct i2c_client *i2c) +{ + struct max20086 *chip; + enum gpiod_flags flags; + bool boot_on; + int ret; + + chip = devm_kzalloc(&i2c->dev, sizeof(*chip), GFP_KERNEL); + if (!chip) + return -ENOMEM; + + chip->dev = &i2c->dev; + chip->info = device_get_match_data(chip->dev); + + i2c_set_clientdata(i2c, chip); + + chip->regmap = devm_regmap_init_i2c(i2c, &max20086_regmap_config); + if (IS_ERR(chip->regmap)) { + ret = PTR_ERR(chip->regmap); + dev_err(chip->dev, "Failed to allocate register map: %d\n", ret); + return ret; + } + + ret = max20086_parse_regulators_dt(chip, &boot_on); + if (ret < 0) + return ret; + + ret = max20086_detect(chip); + if (ret < 0) + return ret; + + /* Until IRQ support is added, just disable all interrupts. */ + ret = regmap_update_bits(chip->regmap, MAX20086_REG_MASK, + MAX20086_INT_DISABLE_ALL, + MAX20086_INT_DISABLE_ALL); + if (ret < 0) { + dev_err(chip->dev, "Failed to disable interrupts: %d\n", ret); + return ret; + } + + /* + * Get the enable GPIO. If any of the outputs is marked as being + * enabled at boot, request the GPIO with an initial high state to + * avoid disabling outputs that may have been turned on by the boot + * loader. Otherwise, request it with a low state to enter lower-power + * shutdown. + */ + flags = boot_on ? GPIOD_OUT_HIGH : GPIOD_OUT_LOW; + chip->ena_gpiod = devm_gpiod_get(chip->dev, "enable", flags); + if (IS_ERR(chip->ena_gpiod)) { + ret = PTR_ERR(chip->ena_gpiod); + dev_err(chip->dev, "Failed to get enable GPIO: %d\n", ret); + return ret; + } + + ret = max20086_regulators_register(chip); + if (ret < 0) { + dev_err(chip->dev, "Failed to register regulators: %d\n", ret); + return ret; + } + + return 0; +} + +static const struct i2c_device_id max20086_i2c_id[] = { + { "max20086" }, + { "max20087" }, + { "max20088" }, + { "max20089" }, + { /* Sentinel */ }, +}; + +MODULE_DEVICE_TABLE(i2c, max20086_i2c_id); + +static const struct of_device_id max20086_dt_ids[] = { + { + .compatible = "maxim,max20086", + .data = &(const struct max20086_chip_info) { + .id = MAX20086_DEVICE_ID_MAX20086, + .num_outputs = 4, + } + }, { + .compatible = "maxim,max20087", + .data = &(const struct max20086_chip_info) { + .id = MAX20086_DEVICE_ID_MAX20087, + .num_outputs = 4, + } + }, { + .compatible = "maxim,max20088", + .data = &(const struct max20086_chip_info) { + .id = MAX20086_DEVICE_ID_MAX20088, + .num_outputs = 2, + } + }, { + .compatible = "maxim,max20089", + .data = &(const struct max20086_chip_info) { + .id = MAX20086_DEVICE_ID_MAX20089, + .num_outputs = 2, + } + }, + { /* Sentinel */ }, +}; + +MODULE_DEVICE_TABLE(of, max20086_dt_ids); + +static struct i2c_driver max20086_regulator_driver = { + .driver = { + .name = "max20086", + .of_match_table = of_match_ptr(max20086_dt_ids), + }, + .probe_new = max20086_i2c_probe, + .id_table = max20086_i2c_id, +}; + +module_i2c_driver(max20086_regulator_driver); + +MODULE_AUTHOR("Watson Chow "); +MODULE_DESCRIPTION("MAX20086-MAX20089 Camera Power Protector Driver"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3