linux-gpio.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Johan Hovold <johan+linaro@kernel.org>
To: Lee Jones <lee@kernel.org>, Mark Brown <broonie@kernel.org>,
	Linus Walleij <linus.walleij@linaro.org>,
	Bjorn Andersson <andersson@kernel.org>
Cc: Konrad Dybcio <konrad.dybcio@linaro.org>,
	Rob Herring <robh@kernel.org>,
	Krzysztof Kozlowski <krzk+dt@kernel.org>,
	Conor Dooley <conor+dt@kernel.org>,
	Liam Girdwood <lgirdwood@gmail.com>,
	Das Srinagesh <quic_gurus@quicinc.com>,
	Satya Priya <quic_c_skakit@quicinc.com>,
	Stephen Boyd <swboyd@chromium.org>,
	linux-arm-msm@vger.kernel.org, devicetree@vger.kernel.org,
	linux-kernel@vger.kernel.org, linux-gpio@vger.kernel.org,
	Johan Hovold <johan+linaro@kernel.org>
Subject: [PATCH 12/13] regulator: add pm8008 pmic regulator driver
Date: Mon,  6 May 2024 17:08:29 +0200	[thread overview]
Message-ID: <20240506150830.23709-13-johan+linaro@kernel.org> (raw)
In-Reply-To: <20240506150830.23709-1-johan+linaro@kernel.org>

From: Satya Priya <quic_c_skakit@quicinc.com>

Qualcomm Technologies, Inc. PM8008 is an I2C-controlled PMIC containing
seven LDO regulators. Add a PM8008 regulator driver to support PMIC
regulator management via the regulator framework.

Note that this driver, originally submitted by Satya Priya [1], has been
reworked to match the new devicetree binding which no longer describes
each regulator as a separate device.

This avoids describing internal details like register offsets in the
devicetree and allows for extending the implementation with features
like over-current protection without having to update the binding.

Specifically note that the regulator interrupts are shared between all
regulators.

Note that the secondary regmap is looked up by name and that if the
driver ever needs to be generalised to support regulators provided by
the primary regmap (I2C address) such information could be added to a
driver lookup table matching on the parent compatible.

This also fixes the original implementation, which looked up regulators
by 'regulator-name' property rather than devicetree node name and which
prevented the regulators from being named to match board schematics.

[1] https://lore.kernel.org/r/1655200111-18357-8-git-send-email-quic_c_skakit@quicinc.com

Signed-off-by: Satya Priya <quic_c_skakit@quicinc.com>
Cc: Stephen Boyd <swboyd@chromium.org>
[ johan: rework probe to match new binding, amend commit message and
         Kconfig entry]
Signed-off-by: Johan Hovold <johan+linaro@kernel.org>
---
 drivers/regulator/Kconfig                 |   7 +
 drivers/regulator/Makefile                |   1 +
 drivers/regulator/qcom-pm8008-regulator.c | 215 ++++++++++++++++++++++
 3 files changed, 223 insertions(+)
 create mode 100644 drivers/regulator/qcom-pm8008-regulator.c

diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 7db0a29b5b8d..d07d034ef1a2 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -1027,6 +1027,13 @@ config REGULATOR_PWM
 	  This driver supports PWM controlled voltage regulators. PWM
 	  duty cycle can increase or decrease the voltage.
 
+config REGULATOR_QCOM_PM8008
+	tristate "Qualcomm Technologies, Inc. PM8008 PMIC regulators"
+	depends on MFD_QCOM_PM8008
+	help
+	  Select this option to enable support for the voltage regulators in
+	  Qualcomm Technologies, Inc. PM8008 PMICs.
+
 config REGULATOR_QCOM_REFGEN
 	tristate "Qualcomm REFGEN regulator driver"
 	depends on ARCH_QCOM || COMPILE_TEST
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 46fb569e6be8..0457b0925b3e 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -112,6 +112,7 @@ obj-$(CONFIG_REGULATOR_MT6380)	+= mt6380-regulator.o
 obj-$(CONFIG_REGULATOR_MT6397)	+= mt6397-regulator.o
 obj-$(CONFIG_REGULATOR_MTK_DVFSRC) += mtk-dvfsrc-regulator.o
 obj-$(CONFIG_REGULATOR_QCOM_LABIBB) += qcom-labibb-regulator.o
+obj-$(CONFIG_REGULATOR_QCOM_PM8008) += qcom-pm8008-regulator.o
 obj-$(CONFIG_REGULATOR_QCOM_REFGEN) += qcom-refgen-regulator.o
 obj-$(CONFIG_REGULATOR_QCOM_RPM) += qcom_rpm-regulator.o
 obj-$(CONFIG_REGULATOR_QCOM_RPMH) += qcom-rpmh-regulator.o
diff --git a/drivers/regulator/qcom-pm8008-regulator.c b/drivers/regulator/qcom-pm8008-regulator.c
new file mode 100644
index 000000000000..51f1ce5e043c
--- /dev/null
+++ b/drivers/regulator/qcom-pm8008-regulator.c
@@ -0,0 +1,215 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/regulator/driver.h>
+
+#define VSET_STEP_MV			8
+#define VSET_STEP_UV			(VSET_STEP_MV * 1000)
+
+#define LDO_ENABLE_REG(base)		((base) + 0x46)
+#define ENABLE_BIT			BIT(7)
+
+#define LDO_VSET_LB_REG(base)		((base) + 0x40)
+
+#define LDO_STEPPER_CTL_REG(base)	((base) + 0x3b)
+#define DEFAULT_VOLTAGE_STEPPER_RATE	38400
+#define STEP_RATE_MASK			GENMASK(1, 0)
+
+#define NLDO_MIN_UV			528000
+#define NLDO_MAX_UV			1504000
+
+#define PLDO_MIN_UV			1504000
+#define PLDO_MAX_UV			3400000
+
+struct pm8008_regulator_data {
+	const char			*name;
+	const char			*supply_name;
+	u16				base;
+	int				min_dropout_uv;
+	const struct linear_range	*voltage_range;
+};
+
+struct pm8008_regulator {
+	struct regmap		*regmap;
+	struct regulator_desc	rdesc;
+	u16			base;
+	int			step_rate;
+};
+
+static const struct linear_range nldo_ranges[] = {
+	REGULATOR_LINEAR_RANGE(528000, 0, 122, 8000),
+};
+
+static const struct linear_range pldo_ranges[] = {
+	REGULATOR_LINEAR_RANGE(1504000, 0, 237, 8000),
+};
+
+static const struct pm8008_regulator_data reg_data[] = {
+	/* name	  parent       base    headroom_uv voltage_range */
+	{ "ldo1", "vdd_l1_l2", 0x4000, 225000, nldo_ranges, },
+	{ "ldo2", "vdd_l1_l2", 0x4100, 225000, nldo_ranges, },
+	{ "ldo3", "vdd_l3_l4", 0x4200, 300000, pldo_ranges, },
+	{ "ldo4", "vdd_l3_l4", 0x4300, 300000, pldo_ranges, },
+	{ "ldo5", "vdd_l5",    0x4400, 200000, pldo_ranges, },
+	{ "ldo6", "vdd_l6",    0x4500, 200000, pldo_ranges, },
+	{ "ldo7", "vdd_l7",    0x4600, 200000, pldo_ranges, },
+};
+
+static int pm8008_regulator_get_voltage(struct regulator_dev *rdev)
+{
+	struct pm8008_regulator *pm8008_reg = rdev_get_drvdata(rdev);
+	__le16 mV;
+	int uV;
+
+	regmap_bulk_read(pm8008_reg->regmap,
+			LDO_VSET_LB_REG(pm8008_reg->base), (void *)&mV, 2);
+
+	uV = le16_to_cpu(mV) * 1000;
+	return (uV - pm8008_reg->rdesc.min_uV) / pm8008_reg->rdesc.uV_step;
+}
+
+static inline int pm8008_write_voltage(struct pm8008_regulator *pm8008_reg,
+							int mV)
+{
+	__le16 vset_raw;
+
+	vset_raw = cpu_to_le16(mV);
+
+	return regmap_bulk_write(pm8008_reg->regmap,
+			LDO_VSET_LB_REG(pm8008_reg->base),
+			(const void *)&vset_raw, sizeof(vset_raw));
+}
+
+static int pm8008_regulator_set_voltage_time(struct regulator_dev *rdev,
+				int old_uV, int new_uv)
+{
+	struct pm8008_regulator *pm8008_reg = rdev_get_drvdata(rdev);
+
+	return DIV_ROUND_UP(abs(new_uv - old_uV), pm8008_reg->step_rate);
+}
+
+static int pm8008_regulator_set_voltage(struct regulator_dev *rdev,
+					unsigned int selector)
+{
+	struct pm8008_regulator *pm8008_reg = rdev_get_drvdata(rdev);
+	int rc, mV;
+
+	rc = regulator_list_voltage_linear_range(rdev, selector);
+	if (rc < 0)
+		return rc;
+
+	/* voltage control register is set with voltage in millivolts */
+	mV = DIV_ROUND_UP(rc, 1000);
+
+	rc = pm8008_write_voltage(pm8008_reg, mV);
+	if (rc < 0)
+		return rc;
+
+	return 0;
+}
+
+static const struct regulator_ops pm8008_regulator_ops = {
+	.enable			= regulator_enable_regmap,
+	.disable		= regulator_disable_regmap,
+	.is_enabled		= regulator_is_enabled_regmap,
+	.set_voltage_sel	= pm8008_regulator_set_voltage,
+	.get_voltage_sel	= pm8008_regulator_get_voltage,
+	.list_voltage		= regulator_list_voltage_linear,
+	.set_voltage_time	= pm8008_regulator_set_voltage_time,
+};
+
+static int pm8008_regulator_probe(struct platform_device *pdev)
+{
+	struct regulator_config reg_config = {};
+	struct pm8008_regulator *pm8008_reg;
+	struct device *dev = &pdev->dev;
+	struct regulator_desc *rdesc;
+	struct regulator_dev *rdev;
+	struct regmap *regmap;
+	unsigned int val;
+	int rc, i;
+
+	regmap = dev_get_regmap(dev->parent, "secondary");
+	if (!regmap)
+		return -EINVAL;
+
+	for (i = 0; i < ARRAY_SIZE(reg_data); i++) {
+		pm8008_reg = devm_kzalloc(dev, sizeof(*pm8008_reg), GFP_KERNEL);
+		if (!pm8008_reg)
+			return -ENOMEM;
+
+		pm8008_reg->regmap = regmap;
+		pm8008_reg->base = reg_data[i].base;
+
+		/* get slew rate */
+		rc = regmap_bulk_read(pm8008_reg->regmap,
+				LDO_STEPPER_CTL_REG(pm8008_reg->base), &val, 1);
+		if (rc < 0) {
+			dev_err(dev, "failed to read step rate: %d\n", rc);
+			return rc;
+		}
+		val &= STEP_RATE_MASK;
+		pm8008_reg->step_rate = DEFAULT_VOLTAGE_STEPPER_RATE >> val;
+
+		rdesc = &pm8008_reg->rdesc;
+		rdesc->type = REGULATOR_VOLTAGE;
+		rdesc->ops = &pm8008_regulator_ops;
+		rdesc->name = reg_data[i].name;
+		rdesc->supply_name = reg_data[i].supply_name;
+		rdesc->of_match = reg_data[i].name;
+		rdesc->uV_step = VSET_STEP_UV;
+		rdesc->linear_ranges = reg_data[i].voltage_range;
+		rdesc->n_linear_ranges = 1;
+		BUILD_BUG_ON((ARRAY_SIZE(pldo_ranges) != 1) ||
+				(ARRAY_SIZE(nldo_ranges) != 1));
+
+		if (reg_data[i].voltage_range == nldo_ranges) {
+			rdesc->min_uV = NLDO_MIN_UV;
+			rdesc->n_voltages = ((NLDO_MAX_UV - NLDO_MIN_UV) / rdesc->uV_step) + 1;
+		} else {
+			rdesc->min_uV = PLDO_MIN_UV;
+			rdesc->n_voltages = ((PLDO_MAX_UV - PLDO_MIN_UV) / rdesc->uV_step) + 1;
+		}
+
+		rdesc->enable_reg = LDO_ENABLE_REG(pm8008_reg->base);
+		rdesc->enable_mask = ENABLE_BIT;
+		rdesc->min_dropout_uV = reg_data[i].min_dropout_uv;
+		rdesc->regulators_node = of_match_ptr("regulators");
+
+		reg_config.dev = dev->parent;
+		reg_config.driver_data = pm8008_reg;
+		reg_config.regmap = pm8008_reg->regmap;
+
+		rdev = devm_regulator_register(dev, rdesc, &reg_config);
+		if (IS_ERR(rdev)) {
+			rc = PTR_ERR(rdev);
+			dev_err(dev, "failed to register regulator %s: %d\n",
+					reg_data[i].name, rc);
+			return rc;
+		}
+	}
+
+	return 0;
+}
+
+static struct platform_driver pm8008_regulator_driver = {
+	.driver	= {
+		.name = "qcom-pm8008-regulator",
+	},
+	.probe = pm8008_regulator_probe,
+};
+
+module_platform_driver(pm8008_regulator_driver);
+
+MODULE_DESCRIPTION("Qualcomm Technologies, Inc. PM8008 PMIC Regulator Driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:qcom-pm8008-regulator");
-- 
2.43.2


  parent reply	other threads:[~2024-05-06 15:10 UTC|newest]

Thread overview: 83+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-05-06 15:08 [PATCH 00/13] arm64: dts: qcom: sc8280xp-x13s: enable pm8008 camera pmic Johan Hovold
2024-05-06 15:08 ` [PATCH 01/13] dt-bindings: mfd: pm8008: add reset gpio Johan Hovold
2024-05-07  6:38   ` Krzysztof Kozlowski
2024-05-08 21:39   ` Stephen Boyd
2024-05-27 13:32   ` Linus Walleij
2024-05-06 15:08 ` [PATCH 02/13] mfd: pm8008: fix regmap irq chip initialisation Johan Hovold
2024-05-06 18:56   ` Andy Shevchenko
2024-05-07 15:01     ` Johan Hovold
2024-05-07 17:16       ` Andy Shevchenko
2024-05-09  8:49         ` Johan Hovold
2024-05-09 13:26           ` Andy Shevchenko
2024-05-06 15:08 ` [PATCH 03/13] mfd: pm8008: deassert reset on probe Johan Hovold
2024-05-06 18:57   ` Andy Shevchenko
2024-05-07 15:15     ` Johan Hovold
2024-05-08 16:12   ` Bryan O'Donoghue
2024-05-09  9:31     ` Johan Hovold
2024-05-29 16:17       ` Johan Hovold
2024-05-29 18:52         ` Bryan O'Donoghue
2024-05-27 13:39   ` Linus Walleij
2024-05-06 15:08 ` [PATCH 04/13] mfd: pm8008: mark regmap structures as const Johan Hovold
2024-05-08 17:37   ` Bryan O'Donoghue
2024-05-08 22:03   ` Stephen Boyd
2024-05-06 15:08 ` [PATCH 05/13] mfd: pm8008: use lower case hex notation Johan Hovold
2024-05-08 17:38   ` Bryan O'Donoghue
2024-05-08 22:03   ` Stephen Boyd
2024-05-06 15:08 ` [PATCH 06/13] mfd: pm8008: rename irq chip Johan Hovold
2024-05-08 17:38   ` Bryan O'Donoghue
2024-05-08 22:04   ` Stephen Boyd
2024-05-06 15:08 ` [PATCH 07/13] mfd: pm8008: drop unused driver data Johan Hovold
2024-05-08 17:40   ` Bryan O'Donoghue
2024-05-08 22:05   ` Stephen Boyd
2024-05-06 15:08 ` [PATCH 08/13] dt-bindings: pinctrl: qcom,pmic-gpio: drop pm8008 Johan Hovold
2024-05-07  6:41   ` Krzysztof Kozlowski
2024-05-08 22:06   ` Stephen Boyd
2024-05-06 15:08 ` [PATCH 09/13] pinctrl: qcom: spmi-gpio: drop broken pm8008 support Johan Hovold
2024-05-08 17:43   ` Bryan O'Donoghue
2024-05-08 22:06   ` Stephen Boyd
2024-05-27 13:35   ` Linus Walleij
2024-05-29 16:12     ` Johan Hovold
2024-05-06 15:08 ` [PATCH 10/13] dt-bindings: mfd: pm8008: rework binding Johan Hovold
2024-05-07  6:43   ` Krzysztof Kozlowski
2024-05-07 15:23     ` Johan Hovold
2024-05-08 22:09       ` Stephen Boyd
2024-05-09  6:57         ` Krzysztof Kozlowski
2024-05-06 15:08 ` [PATCH 11/13] mfd: pm8008: rework driver Johan Hovold
2024-05-06 19:18   ` Andy Shevchenko
2024-05-09  9:42     ` Johan Hovold
2024-05-10 13:15       ` Andy Shevchenko
2024-05-22  6:49         ` Johan Hovold
2024-05-22  7:13           ` Andy Shevchenko
2024-05-22  8:00             ` Johan Hovold
2024-05-08 17:56   ` Bryan O'Donoghue
2024-05-06 15:08 ` Johan Hovold [this message]
2024-05-06 19:09   ` [PATCH 12/13] regulator: add pm8008 pmic regulator driver Andy Shevchenko
2024-05-07 15:44     ` Johan Hovold
2024-05-07 17:22       ` Andy Shevchenko
2024-05-07 18:14         ` Krzysztof Kozlowski
2024-05-09  8:57           ` Johan Hovold
2024-05-09 10:48             ` Krzysztof Kozlowski
2024-05-09 12:26               ` Johan Hovold
2024-05-17  9:15                 ` Krzysztof Kozlowski
2024-05-08 11:41         ` Mark Brown
2024-05-09  8:53         ` Johan Hovold
2024-05-09 13:24           ` Andy Shevchenko
2024-05-14 13:43       ` Satya Priya Kakitapalli
2024-05-14 22:14         ` Konrad Dybcio
2024-05-29 16:04         ` Johan Hovold
2024-05-14 14:04       ` Satya Priya Kakitapalli
2024-05-14 14:18         ` Andy Shevchenko
2024-05-14 15:04           ` Satya Priya Kakitapalli (Temp)
2024-05-14 16:04             ` Andy Shevchenko
2024-05-07 11:48   ` Konrad Dybcio
2024-05-07 15:52     ` Johan Hovold
2024-05-08 17:55   ` Bryan O'Donoghue
2024-05-08 22:37   ` Stephen Boyd
2024-05-09  9:10     ` Johan Hovold
2024-05-29 15:55       ` Johan Hovold
2024-05-09 12:07     ` Andy Shevchenko
2024-05-09 12:20       ` Johan Hovold
2024-05-06 15:08 ` [PATCH 13/13] arm64: dts: qcom: sc8280xp-x13s: enable pm8008 camera pmic Johan Hovold
2024-05-08 17:53   ` Bryan O'Donoghue
2024-05-06 20:40 ` [PATCH 00/13] " Rob Herring (Arm)
2024-05-09  8:42   ` Johan Hovold

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20240506150830.23709-13-johan+linaro@kernel.org \
    --to=johan+linaro@kernel.org \
    --cc=andersson@kernel.org \
    --cc=broonie@kernel.org \
    --cc=conor+dt@kernel.org \
    --cc=devicetree@vger.kernel.org \
    --cc=konrad.dybcio@linaro.org \
    --cc=krzk+dt@kernel.org \
    --cc=lee@kernel.org \
    --cc=lgirdwood@gmail.com \
    --cc=linus.walleij@linaro.org \
    --cc=linux-arm-msm@vger.kernel.org \
    --cc=linux-gpio@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=quic_c_skakit@quicinc.com \
    --cc=quic_gurus@quicinc.com \
    --cc=robh@kernel.org \
    --cc=swboyd@chromium.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).