From be86c3fd26c708da4bef59162efd41ec4f4666c5 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Mon, 15 Feb 2021 11:48:13 +0800 Subject: regulator: mt6315: Return REGULATOR_MODE_INVALID for invalid mode -EINVAL is not a valid return value for .of_map_mode, return REGULATOR_MODE_INVALID instead. Signed-off-by: Axel Lin Link: https://lore.kernel.org/r/20210215034813.45510-1-axel.lin@ingics.com Signed-off-by: Mark Brown --- drivers/regulator/mt6315-regulator.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/mt6315-regulator.c b/drivers/regulator/mt6315-regulator.c index d49a1534d8e9..fc7654624dd6 100644 --- a/drivers/regulator/mt6315-regulator.c +++ b/drivers/regulator/mt6315-regulator.c @@ -69,7 +69,7 @@ static unsigned int mt6315_map_mode(u32 mode) case MT6315_BUCK_MODE_LP: return REGULATOR_MODE_IDLE; default: - return -EINVAL; + return REGULATOR_MODE_INVALID; } } -- cgit v1.2.3 From ef4848a6532ba0b241d3b6cad70378ff2c5615ca Mon Sep 17 00:00:00 2001 From: Frieder Schrempf Date: Mon, 22 Feb 2021 16:08:04 +0100 Subject: regulator: pca9450: Fix return value when failing to get sd-vsel GPIO This fixes the return value of pca9450_i2c_probe() to use the correct error code when getting the sd-vsel GPIO fails. Signed-off-by: Frieder Schrempf Link: https://lore.kernel.org/r/20210222150809.208942-1-frieder.schrempf@kontron.de Signed-off-by: Mark Brown --- drivers/regulator/pca9450-regulator.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/pca9450-regulator.c b/drivers/regulator/pca9450-regulator.c index 833d398c6aa2..89b806be399f 100644 --- a/drivers/regulator/pca9450-regulator.c +++ b/drivers/regulator/pca9450-regulator.c @@ -814,7 +814,7 @@ static int pca9450_i2c_probe(struct i2c_client *i2c, if (IS_ERR(pca9450->sd_vsel_gpio)) { dev_err(&i2c->dev, "Failed to get SD_VSEL GPIO\n"); - return ret; + return PTR_ERR(pca9450->sd_vsel_gpio); } dev_info(&i2c->dev, "%s probed.\n", -- cgit v1.2.3 From 62861a478e06d87dbfbb0ed3684056ba19a9886e Mon Sep 17 00:00:00 2001 From: satya priya Date: Wed, 24 Feb 2021 14:03:08 +0530 Subject: regulator: qcom-rpmh: Correct the pmic5_hfsmps515 buck Correct the REGULATOR_LINEAR_RANGE and n_voltges for pmic5_hfsmps515 buck. Signed-off-by: satya priya Link: https://lore.kernel.org/r/1614155592-14060-4-git-send-email-skakit@codeaurora.org Signed-off-by: Mark Brown --- drivers/regulator/qcom-rpmh-regulator.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/qcom-rpmh-regulator.c b/drivers/regulator/qcom-rpmh-regulator.c index dbad80f904bd..7bc76c5f2b81 100644 --- a/drivers/regulator/qcom-rpmh-regulator.c +++ b/drivers/regulator/qcom-rpmh-regulator.c @@ -726,8 +726,8 @@ static const struct rpmh_vreg_hw_data pmic5_ftsmps510 = { static const struct rpmh_vreg_hw_data pmic5_hfsmps515 = { .regulator_type = VRM, .ops = &rpmh_regulator_vrm_ops, - .voltage_range = REGULATOR_LINEAR_RANGE(2800000, 0, 4, 16000), - .n_voltages = 5, + .voltage_range = REGULATOR_LINEAR_RANGE(320000, 0, 235, 16000), + .n_voltages = 236, .pmic_mode_map = pmic_mode_map_pmic5_smps, .of_map_mode = rpmh_regulator_pmic4_smps_of_map_mode, }; -- cgit v1.2.3 From 8fb4acb880e9467adca913e51adf5c1f96fbbeb9 Mon Sep 17 00:00:00 2001 From: satya priya Date: Wed, 24 Feb 2021 14:03:11 +0530 Subject: regulator: qcom-rpmh: Use correct buck for S1C regulator Use correct buck, that is, pmic5_hfsmps515 for S1C regulator of PM8350C PMIC. Signed-off-by: satya priya Link: https://lore.kernel.org/r/1614155592-14060-7-git-send-email-skakit@codeaurora.org Signed-off-by: Mark Brown --- drivers/regulator/qcom-rpmh-regulator.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/qcom-rpmh-regulator.c b/drivers/regulator/qcom-rpmh-regulator.c index 7bc76c5f2b81..1d07ed0f4ba6 100644 --- a/drivers/regulator/qcom-rpmh-regulator.c +++ b/drivers/regulator/qcom-rpmh-regulator.c @@ -901,7 +901,7 @@ static const struct rpmh_vreg_init_data pm8350_vreg_data[] = { }; static const struct rpmh_vreg_init_data pm8350c_vreg_data[] = { - RPMH_VREG("smps1", "smp%s1", &pmic5_hfsmps510, "vdd-s1"), + RPMH_VREG("smps1", "smp%s1", &pmic5_hfsmps515, "vdd-s1"), RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps510, "vdd-s2"), RPMH_VREG("smps3", "smp%s3", &pmic5_ftsmps510, "vdd-s3"), RPMH_VREG("smps4", "smp%s4", &pmic5_ftsmps510, "vdd-s4"), -- cgit v1.2.3 From 438421b07bf84988a819a635cd8bdf6a4d7f72f2 Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Thu, 25 Feb 2021 22:35:13 +0100 Subject: regulator: spmi: Add support for ULT LV_P50 and ULT P300 The ULT LV_P50 shares the same configuration as the other ULT LV_Pxxx and the ULT P300 shares the same as the other ULT Pxxx. These two regulator types are found on PM8950 and its variants. Signed-off-by: AngeloGioacchino Del Regno Signed-off-by: Konrad Dybcio Link: https://lore.kernel.org/r/20210225213514.117031-1-konrad.dybcio@somainline.org Signed-off-by: Mark Brown --- drivers/regulator/qcom_spmi-regulator.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/regulator') diff --git a/drivers/regulator/qcom_spmi-regulator.c b/drivers/regulator/qcom_spmi-regulator.c index e62e1d72d943..00e1d8e9637e 100644 --- a/drivers/regulator/qcom_spmi-regulator.c +++ b/drivers/regulator/qcom_spmi-regulator.c @@ -1522,10 +1522,12 @@ static const struct spmi_regulator_mapping supported_regulators[] = { SPMI_VREG(ULT_LDO, N600_ST, 0, INF, ULT_LDO, ult_ldo, ult_nldo, 10000), SPMI_VREG(ULT_LDO, N900_ST, 0, INF, ULT_LDO, ult_ldo, ult_nldo, 10000), SPMI_VREG(ULT_LDO, N1200_ST, 0, INF, ULT_LDO, ult_ldo, ult_nldo, 10000), + SPMI_VREG(ULT_LDO, LV_P50, 0, INF, ULT_LDO, ult_ldo, ult_pldo, 10000), SPMI_VREG(ULT_LDO, LV_P150, 0, INF, ULT_LDO, ult_ldo, ult_pldo, 10000), SPMI_VREG(ULT_LDO, LV_P300, 0, INF, ULT_LDO, ult_ldo, ult_pldo, 10000), SPMI_VREG(ULT_LDO, LV_P450, 0, INF, ULT_LDO, ult_ldo, ult_pldo, 10000), SPMI_VREG(ULT_LDO, P600, 0, INF, ULT_LDO, ult_ldo, ult_pldo, 10000), + SPMI_VREG(ULT_LDO, P300, 0, INF, ULT_LDO, ult_ldo, ult_pldo, 10000), SPMI_VREG(ULT_LDO, P150, 0, INF, ULT_LDO, ult_ldo, ult_pldo, 10000), SPMI_VREG(ULT_LDO, P50, 0, INF, ULT_LDO, ult_ldo, ult_pldo, 5000), }; -- cgit v1.2.3 From 1e50433c5705c7e5d6733458e387866289f9b544 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Tue, 16 Feb 2021 14:01:28 +0800 Subject: regulator: pf8x00: Use regulator_map_voltage_ascend for pf8x00_buck7_ops The voltages in pf8x00_sw7_voltages are in ascendant order, so use regulator_map_voltage_ascend. Signed-off-by: Axel Lin Reviewed-by: Jagan Teki Reviewed-by: Adrien Grassein Link: https://lore.kernel.org/r/20210216060128.126938-1-axel.lin@ingics.com Signed-off-by: Mark Brown --- drivers/regulator/pf8x00-regulator.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/regulator') diff --git a/drivers/regulator/pf8x00-regulator.c b/drivers/regulator/pf8x00-regulator.c index 9b28bd63208d..5d319fb81288 100644 --- a/drivers/regulator/pf8x00-regulator.c +++ b/drivers/regulator/pf8x00-regulator.c @@ -359,6 +359,7 @@ static const struct regulator_ops pf8x00_buck7_ops = { .disable = regulator_disable_regmap, .is_enabled = regulator_is_enabled_regmap, .list_voltage = regulator_list_voltage_table, + .map_voltage = regulator_map_voltage_ascend, .set_voltage_sel = regulator_set_voltage_sel_regmap, .get_voltage_sel = regulator_get_voltage_sel_regmap, .get_current_limit = regulator_get_current_limit_regmap, -- cgit v1.2.3 From 45ee8b79d67905ac57408b30314757981531def9 Mon Sep 17 00:00:00 2001 From: Yang Li Date: Fri, 26 Feb 2021 09:39:35 +0800 Subject: regulator: add missing call to of_node_put() In one of the error paths of the for_each_child_of_node() loop, add missing call to of_node_put(). Fix the following coccicheck warning: ./drivers/regulator/scmi-regulator.c:343:1-23: WARNING: Function "for_each_child_of_node" should have of_node_put() before return around line 347. Reported-by: Abaci Robot Signed-off-by: Yang Li Link: https://lore.kernel.org/r/1614303575-27436-1-git-send-email-yang.lee@linux.alibaba.com Signed-off-by: Mark Brown --- drivers/regulator/scmi-regulator.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/scmi-regulator.c b/drivers/regulator/scmi-regulator.c index 0e8b3caa8146..a917c81e99fa 100644 --- a/drivers/regulator/scmi-regulator.c +++ b/drivers/regulator/scmi-regulator.c @@ -343,8 +343,10 @@ static int scmi_regulator_probe(struct scmi_device *sdev) for_each_child_of_node(np, child) { ret = process_scmi_regulator_of_node(sdev, child, rinfo); /* abort on any mem issue */ - if (ret == -ENOMEM) + if (ret == -ENOMEM) { + of_node_put(child); return ret; + } } /* -- cgit v1.2.3 From 320fcd6bbd2b500923db518902c2c640242d2b50 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 12 Mar 2021 10:42:52 +0300 Subject: regulator: bd9576: Fix return from bd957x_probe() The probe() function returns an uninitialized variable in the success path. There is no need for the "err" variable at all, just delete it. Fixes: b014e9fae7e7 ("regulator: Support ROHM BD9576MUF and BD9573MUF") Signed-off-by: Dan Carpenter Reviewed-by: Matti Vaittinen Link: https://lore.kernel.org/r/YEsbfLJfEWtnRpoU@mwanda Signed-off-by: Mark Brown --- drivers/regulator/bd9576-regulator.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/bd9576-regulator.c b/drivers/regulator/bd9576-regulator.c index a8b5832a5a1b..204a2da054f5 100644 --- a/drivers/regulator/bd9576-regulator.c +++ b/drivers/regulator/bd9576-regulator.c @@ -206,7 +206,7 @@ static int bd957x_probe(struct platform_device *pdev) { struct regmap *regmap; struct regulator_config config = { 0 }; - int i, err; + int i; bool vout_mode, ddr_sel; const struct bd957x_regulator_data *reg_data = &bd9576_regulators[0]; unsigned int num_reg_data = ARRAY_SIZE(bd9576_regulators); @@ -279,8 +279,7 @@ static int bd957x_probe(struct platform_device *pdev) break; default: dev_err(&pdev->dev, "Unsupported chip type\n"); - err = -EINVAL; - goto err; + return -EINVAL; } config.dev = pdev->dev.parent; @@ -300,8 +299,7 @@ static int bd957x_probe(struct platform_device *pdev) dev_err(&pdev->dev, "failed to register %s regulator\n", desc->name); - err = PTR_ERR(rdev); - goto err; + return PTR_ERR(rdev); } /* * Clear the VOUT1 GPIO setting - rest of the regulators do not @@ -310,8 +308,7 @@ static int bd957x_probe(struct platform_device *pdev) config.ena_gpiod = NULL; } -err: - return err; + return 0; } static const struct platform_device_id bd957x_pmic_id[] = { -- cgit v1.2.3 From f56f2b953bccabb9bd283a734c7e35a1bb1c1ff8 Mon Sep 17 00:00:00 2001 From: Jian Dong Date: Wed, 24 Mar 2021 11:11:14 +0800 Subject: regulator: mt6360: remove redundant error print fixes coccicheck warning: drivers/regulator/mt6360-regulator.c:384:3-10: line 384 is redundant because platform_get_irq() already prints an error in fact it is not platform_get_irq but platform_get_irq_byname print error Signed-off-by: Jian Dong Link: https://lore.kernel.org/r/1616555474-158789-1-git-send-email-dj0227@163.com Signed-off-by: Mark Brown --- drivers/regulator/mt6360-regulator.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/mt6360-regulator.c b/drivers/regulator/mt6360-regulator.c index 15308ee29c13..4d34be94d166 100644 --- a/drivers/regulator/mt6360-regulator.c +++ b/drivers/regulator/mt6360-regulator.c @@ -380,10 +380,8 @@ static int mt6360_regulator_irq_register(struct platform_device *pdev, const struct mt6360_irq_mapping *irq_desc = tbls + i; irq = platform_get_irq_byname(pdev, irq_desc->name); - if (irq < 0) { - dev_err(&pdev->dev, "Fail to get %s irq\n", irq_desc->name); + if (irq < 0) return irq; - } ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, irq_desc->handler, 0, irq_desc->name, rdev); -- cgit v1.2.3 From 9405b4f7fa78b55fc83e5b5258f00e651aed5734 Mon Sep 17 00:00:00 2001 From: satya priya Date: Wed, 31 Mar 2021 17:35:35 +0530 Subject: regulator: qcom-rpmh: Add pmic5_ftsmps520 buck Add pmic5_ftsmps520 buck as this is required for PM7325 and PMR735A PMICs. Signed-off-by: satya priya Reviewed-by: Matthias Kaehlcke Link: https://lore.kernel.org/r/1617192339-3760-2-git-send-email-skakit@codeaurora.org Signed-off-by: Mark Brown --- drivers/regulator/qcom-rpmh-regulator.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers/regulator') diff --git a/drivers/regulator/qcom-rpmh-regulator.c b/drivers/regulator/qcom-rpmh-regulator.c index 65a108c9121f..2bd2439b2275 100644 --- a/drivers/regulator/qcom-rpmh-regulator.c +++ b/drivers/regulator/qcom-rpmh-regulator.c @@ -723,6 +723,15 @@ static const struct rpmh_vreg_hw_data pmic5_ftsmps510 = { .of_map_mode = rpmh_regulator_pmic4_smps_of_map_mode, }; +static const struct rpmh_vreg_hw_data pmic5_ftsmps520 = { + .regulator_type = VRM, + .ops = &rpmh_regulator_vrm_ops, + .voltage_range = REGULATOR_LINEAR_RANGE(300000, 0, 263, 4000), + .n_voltages = 264, + .pmic_mode_map = pmic_mode_map_pmic5_smps, + .of_map_mode = rpmh_regulator_pmic4_smps_of_map_mode, +}; + static const struct rpmh_vreg_hw_data pmic5_hfsmps515 = { .regulator_type = VRM, .ops = &rpmh_regulator_vrm_ops, -- cgit v1.2.3 From c4e5aa3dbee56bde70dfa03debc49bf9494fb3d9 Mon Sep 17 00:00:00 2001 From: satya priya Date: Wed, 31 Mar 2021 17:35:36 +0530 Subject: regulator: qcom-rpmh: Add PM7325/PMR735A regulator support Add support for PM7325/PMR735A regulators. This ensures that consumers are able to modify the physical state of PMIC regulators. Signed-off-by: satya priya Reviewed-by: Matthias Kaehlcke Link: https://lore.kernel.org/r/1617192339-3760-3-git-send-email-skakit@codeaurora.org Signed-off-by: Mark Brown --- drivers/regulator/qcom-rpmh-regulator.c | 53 ++++++++++++++++++++++++++++++++- 1 file changed, 52 insertions(+), 1 deletion(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/qcom-rpmh-regulator.c b/drivers/regulator/qcom-rpmh-regulator.c index 2bd2439b2275..22fec370fa61 100644 --- a/drivers/regulator/qcom-rpmh-regulator.c +++ b/drivers/regulator/qcom-rpmh-regulator.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0 -// Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. +// Copyright (c) 2018-2021, The Linux Foundation. All rights reserved. #define pr_fmt(fmt) "%s: " fmt, __func__ @@ -1042,6 +1042,49 @@ static const struct rpmh_vreg_init_data pmx55_vreg_data[] = { {}, }; +static const struct rpmh_vreg_init_data pm7325_vreg_data[] = { + RPMH_VREG("smps1", "smp%s1", &pmic5_hfsmps510, "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("smps7", "smp%s7", &pmic5_ftsmps520, "vdd-s7"), + RPMH_VREG("smps8", "smp%s8", &pmic5_hfsmps510, "vdd-s8"), + RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo, "vdd-l1-l4-l12-l15"), + RPMH_VREG("ldo2", "ldo%s2", &pmic5_pldo, "vdd-l2-l7"), + RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo, "vdd-l3"), + RPMH_VREG("ldo4", "ldo%s4", &pmic5_nldo, "vdd-l1-l4-l12-l15"), + RPMH_VREG("ldo5", "ldo%s5", &pmic5_nldo, "vdd-l5"), + RPMH_VREG("ldo6", "ldo%s6", &pmic5_nldo, "vdd-l6-l9-l10"), + RPMH_VREG("ldo7", "ldo%s7", &pmic5_pldo, "vdd-l2-l7"), + RPMH_VREG("ldo8", "ldo%s8", &pmic5_nldo, "vdd-l8"), + RPMH_VREG("ldo9", "ldo%s9", &pmic5_nldo, "vdd-l6-l9-l10"), + RPMH_VREG("ldo10", "ldo%s10", &pmic5_nldo, "vdd-l6-l9-l10"), + RPMH_VREG("ldo11", "ldo%s11", &pmic5_pldo_lv, "vdd-l11-l17-l18-l19"), + RPMH_VREG("ldo12", "ldo%s12", &pmic5_nldo, "vdd-l1-l4-l12-l15"), + RPMH_VREG("ldo13", "ldo%s13", &pmic5_nldo, "vdd-l13"), + RPMH_VREG("ldo14", "ldo%s14", &pmic5_nldo, "vdd-l14-l16"), + RPMH_VREG("ldo15", "ldo%s15", &pmic5_nldo, "vdd-l1-l4-l12-l15"), + RPMH_VREG("ldo16", "ldo%s16", &pmic5_nldo, "vdd-l14-l16"), + RPMH_VREG("ldo17", "ldo%s17", &pmic5_pldo_lv, "vdd-l11-l17-l18-l19"), + RPMH_VREG("ldo18", "ldo%s18", &pmic5_pldo_lv, "vdd-l11-l17-l18-l19"), + RPMH_VREG("ldo19", "ldo%s19", &pmic5_pldo_lv, "vdd-l11-l17-l18-l19"), +}; + +static const struct rpmh_vreg_init_data pmr735a_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_hfsmps510, "vdd-s3"), + RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo, "vdd-l1-l2"), + RPMH_VREG("ldo2", "ldo%s2", &pmic5_nldo, "vdd-l1-l2"), + RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo, "vdd-l3"), + RPMH_VREG("ldo4", "ldo%s4", &pmic5_pldo_lv, "vdd-l4"), + RPMH_VREG("ldo5", "ldo%s5", &pmic5_nldo, "vdd-l5-l6"), + RPMH_VREG("ldo6", "ldo%s6", &pmic5_nldo, "vdd-l5-l6"), + RPMH_VREG("ldo7", "ldo%s7", &pmic5_pldo, "vdd-l7-bob"), +}; + static int rpmh_regulator_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -1136,6 +1179,14 @@ static const struct of_device_id __maybe_unused rpmh_regulator_match_table[] = { .compatible = "qcom,pmx55-rpmh-regulators", .data = pmx55_vreg_data, }, + { + .compatible = "qcom,pm7325-rpmh-regulators", + .data = pm7325_vreg_data, + }, + { + .compatible = "qcom,pmr735a-rpmh-regulators", + .data = pmr735a_vreg_data, + }, {} }; MODULE_DEVICE_TABLE(of, rpmh_regulator_match_table); -- cgit v1.2.3 From e3baacf54275647a018ee35bff3bc775a8a2a01a Mon Sep 17 00:00:00 2001 From: Matti Vaittinen Date: Mon, 29 Mar 2021 15:57:33 +0300 Subject: regulator: helpers: Export helper voltage listing Some drivers need to translate voltage values to selectors prior regulator registration. Currently a regulator_desc based list_voltages helper is only exported for regulators using the linear_ranges. Export similar helper also for regulators using simple linear mapping. Signed-off-by: Matti Vaittinen Link: https://lore.kernel.org/r/1200ef7a50c84327ada019b85f6527b4fc9b5ce1.1617020713.git.matti.vaittinen@fi.rohmeurope.com Signed-off-by: Mark Brown --- drivers/regulator/helpers.c | 36 ++++++++++++++++++++++++++++-------- include/linux/regulator/driver.h | 2 ++ 2 files changed, 30 insertions(+), 8 deletions(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/helpers.c b/drivers/regulator/helpers.c index f42b394a0c46..3e19ecbf7267 100644 --- a/drivers/regulator/helpers.c +++ b/drivers/regulator/helpers.c @@ -508,6 +508,33 @@ int regulator_map_voltage_pickable_linear_range(struct regulator_dev *rdev, } EXPORT_SYMBOL_GPL(regulator_map_voltage_pickable_linear_range); +/** + * regulator_desc_list_voltage_linear - List voltages with simple calculation + * + * @desc: Regulator desc for regulator which volatges are to be listed + * @selector: Selector to convert into a voltage + * + * Regulators with a simple linear mapping between voltages and + * selectors can set min_uV and uV_step in the regulator descriptor + * and then use this function prior regulator registration to list + * the voltages. This is useful when voltages need to be listed during + * device-tree parsing. + */ +int regulator_desc_list_voltage_linear(const struct regulator_desc *desc, + unsigned int selector) +{ + if (selector >= desc->n_voltages) + return -EINVAL; + + if (selector < desc->linear_min_sel) + return 0; + + selector -= desc->linear_min_sel; + + return desc->min_uV + (desc->uV_step * selector); +} +EXPORT_SYMBOL_GPL(regulator_desc_list_voltage_linear); + /** * regulator_list_voltage_linear - List voltages with simple calculation * @@ -521,14 +548,7 @@ EXPORT_SYMBOL_GPL(regulator_map_voltage_pickable_linear_range); int regulator_list_voltage_linear(struct regulator_dev *rdev, unsigned int selector) { - if (selector >= rdev->desc->n_voltages) - return -EINVAL; - if (selector < rdev->desc->linear_min_sel) - return 0; - - selector -= rdev->desc->linear_min_sel; - - return rdev->desc->min_uV + (rdev->desc->uV_step * selector); + return regulator_desc_list_voltage_linear(rdev->desc, selector); } EXPORT_SYMBOL_GPL(regulator_list_voltage_linear); diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h index d7c77ee370f3..39a540111645 100644 --- a/include/linux/regulator/driver.h +++ b/include/linux/regulator/driver.h @@ -543,4 +543,6 @@ void *regulator_get_init_drvdata(struct regulator_init_data *reg_init_data); int regulator_desc_list_voltage_linear_range(const struct regulator_desc *desc, unsigned int selector); +int regulator_desc_list_voltage_linear(const struct regulator_desc *desc, + unsigned int selector); #endif -- cgit v1.2.3 From fb8fee9efdcf084d9e31ba14cc4734d97e5dd972 Mon Sep 17 00:00:00 2001 From: Matti Vaittinen Date: Mon, 29 Mar 2021 15:59:04 +0300 Subject: regulator: Add regmap helper for ramp-delay setting Quite a few regulator ICs do support setting ramp-delay by writing a value matching the delay to a ramp-delay register. Provide a simple helper for table-based delay setting. Signed-off-by: Matti Vaittinen Link: https://lore.kernel.org/r/f101f1db564cf32cb58719c77af0b00d7236bb89.1617020713.git.matti.vaittinen@fi.rohmeurope.com Signed-off-by: Mark Brown --- drivers/regulator/helpers.c | 65 ++++++++++++++++++++++++++++++++++++++++ include/linux/regulator/driver.h | 5 ++++ 2 files changed, 70 insertions(+) (limited to 'drivers/regulator') diff --git a/drivers/regulator/helpers.c b/drivers/regulator/helpers.c index 3e19ecbf7267..0e16e31c968f 100644 --- a/drivers/regulator/helpers.c +++ b/drivers/regulator/helpers.c @@ -901,3 +901,68 @@ bool regulator_is_equal(struct regulator *reg1, struct regulator *reg2) return reg1->rdev == reg2->rdev; } EXPORT_SYMBOL_GPL(regulator_is_equal); + +static int find_closest_bigger(unsigned int target, const unsigned int *table, + unsigned int num_sel, unsigned int *sel) +{ + unsigned int s, tmp, max, maxsel = 0; + bool found = false; + + max = table[0]; + + for (s = 0; s < num_sel; s++) { + if (table[s] > max) { + max = table[s]; + maxsel = s; + } + if (table[s] >= target) { + if (!found || table[s] - target < tmp - target) { + tmp = table[s]; + *sel = s; + found = true; + if (tmp == target) + break; + } + } + } + + if (!found) { + *sel = maxsel; + return -EINVAL; + } + + return 0; +} + +/** + * regulator_set_ramp_delay_regmap - set_ramp_delay() helper + * + * @rdev: regulator to operate on + * + * Regulators that use regmap for their register I/O can set the ramp_reg + * and ramp_mask fields in their descriptor and then use this as their + * set_ramp_delay operation, saving some code. + */ +int regulator_set_ramp_delay_regmap(struct regulator_dev *rdev, int ramp_delay) +{ + int ret; + unsigned int sel; + + if (!rdev->desc->n_ramp_values) + return -EINVAL; + + ret = find_closest_bigger(ramp_delay, rdev->desc->ramp_delay_table, + rdev->desc->n_ramp_values, &sel); + + if (ret) { + dev_warn(rdev_get_dev(rdev), + "Can't set ramp-delay %u, setting %u\n", ramp_delay, + rdev->desc->ramp_delay_table[sel]); + } + + sel <<= ffs(rdev->desc->ramp_mask) - 1; + + return regmap_update_bits(rdev->regmap, rdev->desc->ramp_reg, + rdev->desc->ramp_mask, sel); +} +EXPORT_SYMBOL_GPL(regulator_set_ramp_delay_regmap); diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h index 39a540111645..597ed117086f 100644 --- a/include/linux/regulator/driver.h +++ b/include/linux/regulator/driver.h @@ -373,6 +373,10 @@ struct regulator_desc { unsigned int pull_down_reg; unsigned int pull_down_mask; unsigned int pull_down_val_on; + unsigned int ramp_reg; + unsigned int ramp_mask; + const unsigned int *ramp_delay_table; + unsigned int n_ramp_values; unsigned int enable_time; @@ -535,6 +539,7 @@ int regulator_set_current_limit_regmap(struct regulator_dev *rdev, int min_uA, int max_uA); int regulator_get_current_limit_regmap(struct regulator_dev *rdev); void *regulator_get_init_drvdata(struct regulator_init_data *reg_init_data); +int regulator_set_ramp_delay_regmap(struct regulator_dev *rdev, int ramp_delay); /* * Helper functions intended to be used by regulator drivers prior registering -- cgit v1.2.3 From 013592be146a10d3567c0062cd1416faab060704 Mon Sep 17 00:00:00 2001 From: Adam Ward Date: Wed, 21 Apr 2021 12:03:06 +0000 Subject: regulator: da9121: automotive variants identity fix This patch fixes identification of DA913x parts by the DA9121 driver, where a lack of clarity lead to implementation on the basis that variant IDs were to be identical to the equivalent rated non-automotive parts. There is a new emphasis on the DT identity to cope with overlap in these ID's - this is not considered to be problematic, because projects would be exclusively using automotive or consumer grade parts. Signed-off-by: Adam Ward Link: https://lore.kernel.org/r/20210421120306.DB5B880007F@slsrvapps-01.diasemi.com Signed-off-by: Mark Brown --- drivers/regulator/da9121-regulator.c | 80 +++++++++++++++++++++++------------- drivers/regulator/da9121-regulator.h | 13 ++++++ 2 files changed, 65 insertions(+), 28 deletions(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/da9121-regulator.c b/drivers/regulator/da9121-regulator.c index a2ede7d7897e..08cbf688e14d 100644 --- a/drivers/regulator/da9121-regulator.c +++ b/drivers/regulator/da9121-regulator.c @@ -40,6 +40,7 @@ struct da9121 { unsigned int passive_delay; int chip_irq; int variant_id; + int subvariant_id; }; /* Define ranges for different variants, enabling translation to/from @@ -812,7 +813,6 @@ static struct regmap_config da9121_2ch_regmap_config = { static int da9121_check_device_type(struct i2c_client *i2c, struct da9121 *chip) { u32 device_id; - u8 chip_id = chip->variant_id; u32 variant_id; u8 variant_mrc, variant_vrc; char *type; @@ -839,22 +839,34 @@ static int da9121_check_device_type(struct i2c_client *i2c, struct da9121 *chip) variant_vrc = variant_id & DA9121_MASK_OTP_VARIANT_ID_VRC; - switch (variant_vrc) { - case DA9121_VARIANT_VRC: - type = "DA9121/DA9130"; - config_match = (chip_id == DA9121_TYPE_DA9121_DA9130); + switch (chip->subvariant_id) { + case DA9121_SUBTYPE_DA9121: + type = "DA9121"; + config_match = (variant_vrc == DA9121_VARIANT_VRC); break; - case DA9220_VARIANT_VRC: - type = "DA9220/DA9132"; - config_match = (chip_id == DA9121_TYPE_DA9220_DA9132); + case DA9121_SUBTYPE_DA9130: + type = "DA9130"; + config_match = (variant_vrc == DA9130_VARIANT_VRC); break; - case DA9122_VARIANT_VRC: - type = "DA9122/DA9131"; - config_match = (chip_id == DA9121_TYPE_DA9122_DA9131); + case DA9121_SUBTYPE_DA9220: + type = "DA9220"; + config_match = (variant_vrc == DA9220_VARIANT_VRC); break; - case DA9217_VARIANT_VRC: + case DA9121_SUBTYPE_DA9132: + type = "DA9132"; + config_match = (variant_vrc == DA9132_VARIANT_VRC); + break; + case DA9121_SUBTYPE_DA9122: + type = "DA9122"; + config_match = (variant_vrc == DA9122_VARIANT_VRC); + break; + case DA9121_SUBTYPE_DA9131: + type = "DA9131"; + config_match = (variant_vrc == DA9131_VARIANT_VRC); + break; + case DA9121_SUBTYPE_DA9217: type = "DA9217"; - config_match = (chip_id == DA9121_TYPE_DA9217); + config_match = (variant_vrc == DA9217_VARIANT_VRC); break; default: type = "Unknown"; @@ -892,15 +904,27 @@ static int da9121_assign_chip_model(struct i2c_client *i2c, chip->dev = &i2c->dev; - switch (chip->variant_id) { - case DA9121_TYPE_DA9121_DA9130: - fallthrough; - case DA9121_TYPE_DA9217: + /* Use configured subtype to select the regulator descriptor index and + * register map, common to both consumer and automotive grade variants + */ + switch (chip->subvariant_id) { + case DA9121_SUBTYPE_DA9121: + case DA9121_SUBTYPE_DA9130: + chip->variant_id = DA9121_TYPE_DA9121_DA9130; regmap = &da9121_1ch_regmap_config; break; - case DA9121_TYPE_DA9122_DA9131: - fallthrough; - case DA9121_TYPE_DA9220_DA9132: + case DA9121_SUBTYPE_DA9217: + chip->variant_id = DA9121_TYPE_DA9217; + regmap = &da9121_1ch_regmap_config; + break; + case DA9121_SUBTYPE_DA9122: + case DA9121_SUBTYPE_DA9131: + chip->variant_id = DA9121_TYPE_DA9122_DA9131; + regmap = &da9121_2ch_regmap_config; + break; + case DA9121_SUBTYPE_DA9220: + case DA9121_SUBTYPE_DA9132: + chip->variant_id = DA9121_TYPE_DA9220_DA9132; regmap = &da9121_2ch_regmap_config; break; } @@ -975,13 +999,13 @@ regmap_error: } static const struct of_device_id da9121_dt_ids[] = { - { .compatible = "dlg,da9121", .data = (void *) DA9121_TYPE_DA9121_DA9130 }, - { .compatible = "dlg,da9130", .data = (void *) DA9121_TYPE_DA9121_DA9130 }, - { .compatible = "dlg,da9217", .data = (void *) DA9121_TYPE_DA9217 }, - { .compatible = "dlg,da9122", .data = (void *) DA9121_TYPE_DA9122_DA9131 }, - { .compatible = "dlg,da9131", .data = (void *) DA9121_TYPE_DA9122_DA9131 }, - { .compatible = "dlg,da9220", .data = (void *) DA9121_TYPE_DA9220_DA9132 }, - { .compatible = "dlg,da9132", .data = (void *) DA9121_TYPE_DA9220_DA9132 }, + { .compatible = "dlg,da9121", .data = (void *) DA9121_SUBTYPE_DA9121 }, + { .compatible = "dlg,da9130", .data = (void *) DA9121_SUBTYPE_DA9130 }, + { .compatible = "dlg,da9217", .data = (void *) DA9121_SUBTYPE_DA9217 }, + { .compatible = "dlg,da9122", .data = (void *) DA9121_SUBTYPE_DA9122 }, + { .compatible = "dlg,da9131", .data = (void *) DA9121_SUBTYPE_DA9131 }, + { .compatible = "dlg,da9220", .data = (void *) DA9121_SUBTYPE_DA9220 }, + { .compatible = "dlg,da9132", .data = (void *) DA9121_SUBTYPE_DA9132 }, { } }; MODULE_DEVICE_TABLE(of, da9121_dt_ids); @@ -1011,7 +1035,7 @@ static int da9121_i2c_probe(struct i2c_client *i2c, } chip->pdata = i2c->dev.platform_data; - chip->variant_id = da9121_of_get_id(&i2c->dev); + chip->subvariant_id = da9121_of_get_id(&i2c->dev); ret = da9121_assign_chip_model(i2c, chip); if (ret < 0) diff --git a/drivers/regulator/da9121-regulator.h b/drivers/regulator/da9121-regulator.h index 3c34cb889ca8..357f416e17c1 100644 --- a/drivers/regulator/da9121-regulator.h +++ b/drivers/regulator/da9121-regulator.h @@ -29,6 +29,16 @@ enum da9121_variant { DA9121_TYPE_DA9217 }; +enum da9121_subvariant { + DA9121_SUBTYPE_DA9121, + DA9121_SUBTYPE_DA9130, + DA9121_SUBTYPE_DA9220, + DA9121_SUBTYPE_DA9132, + DA9121_SUBTYPE_DA9122, + DA9121_SUBTYPE_DA9131, + DA9121_SUBTYPE_DA9217 +}; + /* Minimum, maximum and default polling millisecond periods are provided * here as an example. It is expected that any final implementation will * include a modification of these settings to match the required @@ -279,6 +289,9 @@ enum da9121_variant { #define DA9220_VARIANT_VRC 0x0 #define DA9122_VARIANT_VRC 0x2 #define DA9217_VARIANT_VRC 0x7 +#define DA9130_VARIANT_VRC 0x0 +#define DA9131_VARIANT_VRC 0x1 +#define DA9132_VARIANT_VRC 0x2 /* DA9121_REG_OTP_CUSTOMER_ID */ -- cgit v1.2.3 From 378b40ae1a8639f03192711573e478a367ccb6e1 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 20 Apr 2021 19:02:43 +0200 Subject: regulator: s2mpa01: Drop initialization via platform data None of the platforms with S2MPA01 use board files, so any initialization via platform data can be safely removed. Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20210420170244.13467-4-krzysztof.kozlowski@canonical.com Signed-off-by: Mark Brown --- drivers/regulator/s2mpa01.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/s2mpa01.c b/drivers/regulator/s2mpa01.c index 115f59530852..28b424fe7bea 100644 --- a/drivers/regulator/s2mpa01.c +++ b/drivers/regulator/s2mpa01.c @@ -340,7 +340,6 @@ static const struct regulator_desc regulators[] = { static int s2mpa01_pmic_probe(struct platform_device *pdev) { struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent); - struct sec_platform_data *pdata = dev_get_platdata(iodev->dev); struct regulator_config config = { }; struct s2mpa01_info *s2mpa01; int i; @@ -356,9 +355,6 @@ static int s2mpa01_pmic_probe(struct platform_device *pdev) for (i = 0; i < S2MPA01_REGULATOR_MAX; i++) { struct regulator_dev *rdev; - if (pdata) - config.init_data = pdata->regulators[i].initdata; - rdev = devm_regulator_register(&pdev->dev, ®ulators[i], &config); if (IS_ERR(rdev)) { -- cgit v1.2.3 From beeab9bc8e85de6cacbbb2124a464166f2f5043d Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 20 Apr 2021 19:02:44 +0200 Subject: regulator: s2mps11: Drop initialization via platform data None of the platforms with S2MPS11 use board files, so any initialization via platform data can be safely removed. Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20210420170244.13467-5-krzysztof.kozlowski@canonical.com Signed-off-by: Mark Brown --- drivers/regulator/s2mps11.c | 22 ++-------------------- 1 file changed, 2 insertions(+), 20 deletions(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/s2mps11.c b/drivers/regulator/s2mps11.c index 33cf84bce05a..ebc67e3ddd4f 100644 --- a/drivers/regulator/s2mps11.c +++ b/drivers/regulator/s2mps11.c @@ -1120,7 +1120,6 @@ static const struct regulator_desc s2mpu02_regulators[] = { static int s2mps11_pmic_probe(struct platform_device *pdev) { struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent); - struct sec_platform_data *pdata = NULL; struct of_regulator_match *rdata = NULL; struct regulator_config config = { }; struct s2mps11_info *s2mps11; @@ -1171,17 +1170,6 @@ static int s2mps11_pmic_probe(struct platform_device *pdev) if (!s2mps11->ext_control_gpiod) return -ENOMEM; - if (!iodev->dev->of_node) { - if (iodev->pdata) { - pdata = iodev->pdata; - goto common_reg; - } else { - dev_err(pdev->dev.parent, - "Platform data or DT node not supplied\n"); - return -ENODEV; - } - } - rdata = kcalloc(rdev_num, sizeof(*rdata), GFP_KERNEL); if (!rdata) return -ENOMEM; @@ -1193,7 +1181,6 @@ static int s2mps11_pmic_probe(struct platform_device *pdev) if (ret) goto out; -common_reg: platform_set_drvdata(pdev, s2mps11); config.dev = &pdev->dev; @@ -1202,13 +1189,8 @@ common_reg: for (i = 0; i < rdev_num; i++) { struct regulator_dev *regulator; - if (pdata) { - config.init_data = pdata->regulators[i].initdata; - config.of_node = pdata->regulators[i].reg_node; - } else { - config.init_data = rdata[i].init_data; - config.of_node = rdata[i].of_node; - } + config.init_data = rdata[i].init_data; + config.of_node = rdata[i].of_node; config.ena_gpiod = s2mps11->ext_control_gpiod[i]; /* * Hand the GPIO descriptor management over to the regulator -- cgit v1.2.3 From 69b8821e293aa823ba8184c80370e7e21bde81e6 Mon Sep 17 00:00:00 2001 From: Shubhankar Kuranagatti Date: Tue, 20 Apr 2021 09:17:18 +0530 Subject: regulator: core.c: Fix indentation of comment Shifted the closing */ of multiline comment to a new line This is done to maintain code uniformity Signed-off-by: Shubhankar Kuranagatti Link: https://lore.kernel.org/r/20210420034718.t7wudu6xcfpahflv@kewl-virtual-machine Signed-off-by: Mark Brown --- drivers/regulator/core.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 16114aea099a..06fbf18b6524 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -538,7 +538,8 @@ static int regulator_mode_constrain(struct regulator_dev *rdev, /* The modes are bitmasks, the most power hungry modes having * the lowest values. If the requested mode isn't supported - * try higher modes. */ + * try higher modes. + */ while (*mode) { if (rdev->constraints->valid_modes_mask & *mode) return 0; @@ -931,7 +932,8 @@ static DEVICE_ATTR(bypass, 0444, regulator_bypass_show, NULL); /* Calculate the new optimum regulator operating mode based on the new total - * consumer load. All locks held by caller */ + * consumer load. All locks held by caller + */ static int drms_uA_update(struct regulator_dev *rdev) { struct regulator *sibling; @@ -1219,7 +1221,8 @@ static int machine_constraints_voltage(struct regulator_dev *rdev, int cmax = constraints->max_uV; /* it's safe to autoconfigure fixed-voltage supplies - and the constraints are used by list_voltage. */ + * and the constraints are used by list_voltage. + */ if (count == 1 && !cmin) { cmin = 1; cmax = INT_MAX; @@ -2525,7 +2528,8 @@ static int _regulator_do_enable(struct regulator_dev *rdev) /* Allow the regulator to ramp; it would be useful to extend * this for bulk operations so that the regulators can ramp - * together. */ + * together. + */ trace_regulator_enable_delay(rdev_get_name(rdev)); /* If poll_enabled_time is set, poll upto the delay calculated @@ -5337,10 +5341,12 @@ regulator_register(const struct regulator_desc *regulator_desc, ret = set_machine_constraints(rdev); if (ret == -EPROBE_DEFER) { /* Regulator might be in bypass mode and so needs its supply - * to set the constraints */ + * to set the constraints + */ /* FIXME: this currently triggers a chicken-and-egg problem * when creating -SUPPLY symlink in sysfs to a regulator - * that is just being created */ + * that is just being created + */ rdev_dbg(rdev, "will resolve supply early: %s\n", rdev->supply_name); ret = regulator_resolve_supply(rdev); @@ -5899,7 +5905,8 @@ static int regulator_late_cleanup(struct device *dev, void *data) if (have_full_constraints()) { /* We log since this may kill the system if it goes - * wrong. */ + * wrong. + */ rdev_info(rdev, "disabling\n"); ret = _regulator_do_disable(rdev); if (ret != 0) -- cgit v1.2.3 From 8a065ce92b218e453742b745162d75a6f86fb768 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Tue, 20 Apr 2021 21:31:51 +0200 Subject: regulator: Avoid a double 'of_node_get' in 'regulator_of_get_init_node()' 'for_each_available_child_of_node()' already performs an 'of_node_get()' on child, so there is no need to perform another one before returning. Otherwise, a double 'get' is performed and a resource may never be released. Fixes: 925c85e21ed8 ("regulator: Factor out location of init data OF node") Signed-off-by: Christophe JAILLET Acked-by: Charles Keepax Link: https://lore.kernel.org/r/a79f0068812b89ff412d572a1171f22109c24132.1618947049.git.christophe.jaillet@wanadoo.fr Signed-off-by: Mark Brown --- drivers/regulator/of_regulator.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/of_regulator.c b/drivers/regulator/of_regulator.c index 564f928eb1db..49f6c05fee34 100644 --- a/drivers/regulator/of_regulator.c +++ b/drivers/regulator/of_regulator.c @@ -422,7 +422,11 @@ device_node *regulator_of_get_init_node(struct device *dev, if (!strcmp(desc->of_match, name)) { of_node_put(search); - return of_node_get(child); + /* + * 'of_node_get(child)' is already performed by the + * for_each loop. + */ + return child; } } -- cgit v1.2.3 From 72241e3190f2be668d60493cf0343ec535357b5e Mon Sep 17 00:00:00 2001 From: Sebastian Fricke Date: Wed, 21 Apr 2021 05:52:37 +0000 Subject: regulator: core.c: Improve a comment s/regulator may on/regulator may already be enabled/ s/or left on/or was left on/ The aim of this patch is to make the comment more readable and to make it clear, that this is about a regulator, that is already enabled instead of a regulator that may be switched on. Signed-off-by: Sebastian Fricke Link: https://lore.kernel.org/r/20210421055236.13148-1-sebastian.fricke@posteo.net Signed-off-by: Mark Brown --- drivers/regulator/core.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 06fbf18b6524..d31f5c3cd773 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -2654,7 +2654,10 @@ static int _regulator_enable(struct regulator *regulator) goto err_disable_supply; if (rdev->use_count == 0) { - /* The regulator may on if it's not switchable or left on */ + /* + * The regulator may already be enabled if it's not switchable + * or was left on + */ ret = _regulator_is_enabled(rdev); if (ret == -EINVAL || ret == 0) { if (!regulator_ops_is_valid(rdev, -- cgit v1.2.3 From a5ccccb3ec0b052804d03df90c0d08689be54170 Mon Sep 17 00:00:00 2001 From: Vincent Whitchurch Date: Thu, 22 Apr 2021 10:30:44 +0200 Subject: regulator: core: Respect off_on_delay at startup We currently do not respect off_on_delay the first time we turn on a regulator. This is problematic since the regulator could have been turned off by the bootloader, or it could it have been turned off during the probe of the regulator driver (such as when regulator-fixed requests the enable GPIO), either of which could potentially have happened less than off_on_delay microseconds ago before the first time a client requests for the regulator to be turned on. We can't know exactly when the regulator was turned off, but initialise off_on_delay to the current time when registering the regulator, so that we guarantee that we respect the off_on_delay in all cases. Signed-off-by: Vincent Whitchurch Link: https://lore.kernel.org/r/20210422083044.11479-1-vincent.whitchurch@axis.com Signed-off-by: Mark Brown --- drivers/regulator/core.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/regulator') diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 16114aea099a..d6219cb8bd29 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -1439,6 +1439,8 @@ static int set_machine_constraints(struct regulator_dev *rdev) if (rdev->constraints->always_on) rdev->use_count++; + } else if (rdev->desc->off_on_delay) { + rdev->last_off_jiffy = jiffies; } print_constraints(rdev); -- cgit v1.2.3 From a8ce7bd89689997537dd22dcbced46cf23dc19da Mon Sep 17 00:00:00 2001 From: Vincent Whitchurch Date: Fri, 23 Apr 2021 13:45:24 +0200 Subject: regulator: core: Fix off_on_delay handling The jiffies-based off_on_delay implementation has a couple of problems that cause it to sometimes not actually delay for the required time: (1) If, for example, the off_on_delay time is equivalent to one jiffy, and the ->last_off_jiffy is set just before a new jiffy starts, then _regulator_do_enable() does not wait at all since it checks using time_before(). (2) When jiffies overflows, the value of "remaining" becomes higher than "max_delay" and the code simply proceeds without waiting. Fix these problems by changing it to use ktime_t instead. [Note that since jiffies doesn't start at zero but at INITIAL_JIFFIES ("-5 minutes"), (2) above also led to the code not delaying if the first regulator_enable() is called when the ->last_off_jiffy is not initialised, such as for regulators with ->constraints->boot_on set. It's not clear to me if this was intended or not, but I've preserved this behaviour explicitly with the check for a non-zero ->last_off.] Signed-off-by: Vincent Whitchurch Link: https://lore.kernel.org/r/20210423114524.26414-1-vincent.whitchurch@axis.com Signed-off-by: Mark Brown --- drivers/regulator/core.c | 33 ++++++++------------------------- include/linux/regulator/driver.h | 2 +- 2 files changed, 9 insertions(+), 26 deletions(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 504898ba265e..f192bf19492e 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -1443,7 +1443,7 @@ static int set_machine_constraints(struct regulator_dev *rdev) if (rdev->constraints->always_on) rdev->use_count++; } else if (rdev->desc->off_on_delay) { - rdev->last_off_jiffy = jiffies; + rdev->last_off = ktime_get(); } print_constraints(rdev); @@ -2488,29 +2488,15 @@ static int _regulator_do_enable(struct regulator_dev *rdev) trace_regulator_enable(rdev_get_name(rdev)); - if (rdev->desc->off_on_delay) { + if (rdev->desc->off_on_delay && rdev->last_off) { /* if needed, keep a distance of off_on_delay from last time * this regulator was disabled. */ - unsigned long start_jiffy = jiffies; - unsigned long intended, max_delay, remaining; - - max_delay = usecs_to_jiffies(rdev->desc->off_on_delay); - intended = rdev->last_off_jiffy + max_delay; - - if (time_before(start_jiffy, intended)) { - /* calc remaining jiffies to deal with one-time - * timer wrapping. - * in case of multiple timer wrapping, either it can be - * detected by out-of-range remaining, or it cannot be - * detected and we get a penalty of - * _regulator_enable_delay(). - */ - remaining = intended - start_jiffy; - if (remaining <= max_delay) - _regulator_enable_delay( - jiffies_to_usecs(remaining)); - } + ktime_t end = ktime_add_us(rdev->last_off, rdev->desc->off_on_delay); + s64 remaining = ktime_us_delta(end, ktime_get()); + + if (remaining > 0) + _regulator_enable_delay(remaining); } if (rdev->ena_pin) { @@ -2740,11 +2726,8 @@ static int _regulator_do_disable(struct regulator_dev *rdev) return ret; } - /* cares about last_off_jiffy only if off_on_delay is required by - * device. - */ if (rdev->desc->off_on_delay) - rdev->last_off_jiffy = jiffies; + rdev->last_off = ktime_get(); trace_regulator_disable_complete(rdev_get_name(rdev)); diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h index 597ed117086f..4ea520c248e9 100644 --- a/include/linux/regulator/driver.h +++ b/include/linux/regulator/driver.h @@ -476,7 +476,7 @@ struct regulator_dev { unsigned int is_switch:1; /* time when this regulator was disabled last time */ - unsigned long last_off_jiffy; + ktime_t last_off; }; struct regulator_dev * -- cgit v1.2.3 From 914df8faa7d6fdff7afa1fbde888a2bed8d72fa7 Mon Sep 17 00:00:00 2001 From: Joseph Chen Date: Wed, 21 Apr 2021 18:03:38 -0300 Subject: regulator: fan53555: Add TCS4525 DCDC support TCS4525 main features: - 2.7V to 5.5V Input Voltage Range; - 3MHz Constant Switching Frequency; - 5A Available Load Current; - Programmable Output Voltage: 0.6V to 1.4V in 6.25mV Steps; - PFM/PWM Operation for Optimum Increased Efficiency; Signed-off-by: Joseph Chen [Ezequiel: Forward port] Signed-off-by: Ezequiel Garcia Link: https://lore.kernel.org/r/20210421210338.43819-3-ezequiel@collabora.com Signed-off-by: Mark Brown --- drivers/regulator/fan53555.c | 136 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 122 insertions(+), 14 deletions(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/fan53555.c b/drivers/regulator/fan53555.c index aa426183b6a1..f3918f03aaf3 100644 --- a/drivers/regulator/fan53555.c +++ b/drivers/regulator/fan53555.c @@ -24,6 +24,12 @@ /* Voltage setting */ #define FAN53555_VSEL0 0x00 #define FAN53555_VSEL1 0x01 + +#define TCS4525_VSEL0 0x11 +#define TCS4525_VSEL1 0x10 +#define TCS4525_TIME 0x13 +#define TCS4525_COMMAND 0x14 + /* Control register */ #define FAN53555_CONTROL 0x02 /* IC Type */ @@ -49,11 +55,20 @@ #define FAN53555_NVOLTAGES 64 /* Numbers of voltages */ #define FAN53526_NVOLTAGES 128 +#define TCS4525_NVOLTAGES 127 /* Numbers of voltages */ + +#define TCS_VSEL_NSEL_MASK 0x7f +#define TCS_VSEL0_MODE (1 << 7) +#define TCS_VSEL1_MODE (1 << 6) + +#define TCS_SLEW_SHIFT 3 +#define TCS_SLEW_MASK (0x3 < 3) enum fan53555_vendor { FAN53526_VENDOR_FAIRCHILD = 0, FAN53555_VENDOR_FAIRCHILD, FAN53555_VENDOR_SILERGY, + FAN53555_VENDOR_TCS, }; enum { @@ -106,6 +121,11 @@ struct fan53555_device_info { unsigned int mode_mask; /* Sleep voltage cache */ unsigned int sleep_vol_cache; + /* Slew rate */ + unsigned int slew_reg; + unsigned int slew_mask; + unsigned int slew_shift; + unsigned int slew_rate; }; static int fan53555_set_suspend_voltage(struct regulator_dev *rdev, int uV) @@ -189,13 +209,37 @@ static const int slew_rates[] = { 500, }; +static const int tcs_slew_rates[] = { + 18700, + 9300, + 4600, + 2300, +}; + static int fan53555_set_ramp(struct regulator_dev *rdev, int ramp) { struct fan53555_device_info *di = rdev_get_drvdata(rdev); int regval = -1, i; + const int *slew_rate_t; + int slew_rate_n; - for (i = 0; i < ARRAY_SIZE(slew_rates); i++) { - if (ramp <= slew_rates[i]) + switch (di->vendor) { + case FAN53526_VENDOR_FAIRCHILD: + case FAN53555_VENDOR_FAIRCHILD: + case FAN53555_VENDOR_SILERGY: + slew_rate_t = slew_rates; + slew_rate_n = ARRAY_SIZE(slew_rates); + break; + case FAN53555_VENDOR_TCS: + slew_rate_t = tcs_slew_rates; + slew_rate_n = ARRAY_SIZE(tcs_slew_rates); + break; + default: + return -EINVAL; + } + + for (i = 0; i < slew_rate_n; i++) { + if (ramp <= slew_rate_t[i]) regval = i; else break; @@ -206,8 +250,8 @@ static int fan53555_set_ramp(struct regulator_dev *rdev, int ramp) return -EINVAL; } - return regmap_update_bits(rdev->regmap, FAN53555_CONTROL, - CTL_SLEW_MASK, regval << CTL_SLEW_SHIFT); + return regmap_update_bits(rdev->regmap, di->slew_reg, + di->slew_mask, regval << di->slew_shift); } static const struct regulator_ops fan53555_regulator_ops = { @@ -292,7 +336,9 @@ static int fan53555_voltages_setup_fairchild(struct fan53555_device_info *di) "Chip ID %d not supported!\n", di->chip_id); return -EINVAL; } - + di->slew_reg = FAN53555_CONTROL; + di->slew_mask = CTL_SLEW_MASK; + di->slew_shift = CTL_SLEW_SHIFT; di->vsel_count = FAN53555_NVOLTAGES; return 0; @@ -312,12 +358,29 @@ static int fan53555_voltages_setup_silergy(struct fan53555_device_info *di) "Chip ID %d not supported!\n", di->chip_id); return -EINVAL; } - + di->slew_reg = FAN53555_CONTROL; + di->slew_reg = FAN53555_CONTROL; + di->slew_mask = CTL_SLEW_MASK; + di->slew_shift = CTL_SLEW_SHIFT; di->vsel_count = FAN53555_NVOLTAGES; return 0; } +static int fan53555_voltages_setup_tcs(struct fan53555_device_info *di) +{ + di->slew_reg = TCS4525_TIME; + di->slew_mask = TCS_SLEW_MASK; + di->slew_shift = TCS_SLEW_MASK; + + /* Init voltage range and step */ + di->vsel_min = 600000; + di->vsel_step = 6250; + di->vsel_count = TCS4525_NVOLTAGES; + + return 0; +} + /* For 00,01,03,05 options: * VOUT = 0.60V + NSELx * 10mV, from 0.60 to 1.23V. * For 04 option: @@ -329,17 +392,41 @@ static int fan53555_device_setup(struct fan53555_device_info *di, int ret = 0; /* Setup voltage control register */ - switch (pdata->sleep_vsel_id) { - case FAN53555_VSEL_ID_0: - di->sleep_reg = FAN53555_VSEL0; - di->vol_reg = FAN53555_VSEL1; + switch (di->vendor) { + case FAN53526_VENDOR_FAIRCHILD: + case FAN53555_VENDOR_FAIRCHILD: + case FAN53555_VENDOR_SILERGY: + switch (pdata->sleep_vsel_id) { + case FAN53555_VSEL_ID_0: + di->sleep_reg = FAN53555_VSEL0; + di->vol_reg = FAN53555_VSEL1; + break; + case FAN53555_VSEL_ID_1: + di->sleep_reg = FAN53555_VSEL1; + di->vol_reg = FAN53555_VSEL0; + break; + default: + dev_err(di->dev, "Invalid VSEL ID!\n"); + return -EINVAL; + } break; - case FAN53555_VSEL_ID_1: - di->sleep_reg = FAN53555_VSEL1; - di->vol_reg = FAN53555_VSEL0; + case FAN53555_VENDOR_TCS: + switch (pdata->sleep_vsel_id) { + case FAN53555_VSEL_ID_0: + di->sleep_reg = TCS4525_VSEL0; + di->vol_reg = TCS4525_VSEL1; + break; + case FAN53555_VSEL_ID_1: + di->sleep_reg = TCS4525_VSEL1; + di->vol_reg = TCS4525_VSEL0; + break; + default: + dev_err(di->dev, "Invalid VSEL ID!\n"); + return -EINVAL; + } break; default: - dev_err(di->dev, "Invalid VSEL ID!\n"); + dev_err(di->dev, "vendor %d not supported!\n", di->vendor); return -EINVAL; } @@ -362,6 +449,18 @@ static int fan53555_device_setup(struct fan53555_device_info *di, di->mode_reg = di->vol_reg; di->mode_mask = VSEL_MODE; break; + case FAN53555_VENDOR_TCS: + di->mode_reg = TCS4525_COMMAND; + + switch (pdata->sleep_vsel_id) { + case FAN53555_VSEL_ID_0: + di->mode_mask = TCS_VSEL1_MODE; + break; + case FAN53555_VSEL_ID_1: + di->mode_mask = TCS_VSEL0_MODE; + break; + } + break; default: dev_err(di->dev, "vendor %d not supported!\n", di->vendor); return -EINVAL; @@ -378,6 +477,9 @@ static int fan53555_device_setup(struct fan53555_device_info *di, case FAN53555_VENDOR_SILERGY: ret = fan53555_voltages_setup_silergy(di); break; + case FAN53555_VENDOR_TCS: + ret = fan53555_voltages_setup_tcs(di); + break; default: dev_err(di->dev, "vendor %d not supported!\n", di->vendor); return -EINVAL; @@ -449,6 +551,9 @@ static const struct of_device_id __maybe_unused fan53555_dt_ids[] = { }, { .compatible = "silergy,syr828", .data = (void *)FAN53555_VENDOR_SILERGY, + }, { + .compatible = "tcs,tcs4525", + .data = (void *)FAN53555_VENDOR_TCS }, { } }; @@ -554,6 +659,9 @@ static const struct i2c_device_id fan53555_id[] = { }, { .name = "syr828", .driver_data = FAN53555_VENDOR_SILERGY + }, { + .name = "tcs4525", + .driver_data = FAN53555_VENDOR_TCS }, { }, }; -- cgit v1.2.3