All of lore.kernel.org
 help / color / mirror / Atom feed
From: Satya Priya <quic_c_skakit@quicinc.com>
To: Bjorn Andersson <bjorn.andersson@linaro.org>,
	Rob Herring <robh+dt@kernel.org>
Cc: Lee Jones <lee.jones@linaro.org>,
	Liam Girdwood <lgirdwood@gmail.com>,
	Mark Brown <broonie@kernel.org>, <linux-arm-msm@vger.kernel.org>,
	<devicetree@vger.kernel.org>, <linux-kernel@vger.kernel.org>,
	<swboyd@chromium.org>, <quic_collinsd@quicinc.com>,
	<quic_subbaram@quicinc.com>, <quic_jprakash@quicinc.com>,
	Satya Priya <quic_c_skakit@quicinc.com>
Subject: [PATCH V15 7/9] regulator: Add a regulator driver for the PM8008 PMIC
Date: Tue, 14 Jun 2022 15:18:29 +0530	[thread overview]
Message-ID: <1655200111-18357-8-git-send-email-quic_c_skakit@quicinc.com> (raw)
In-Reply-To: <1655200111-18357-1-git-send-email-quic_c_skakit@quicinc.com>

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

Signed-off-by: Satya Priya <quic_c_skakit@quicinc.com>
Reported-by: kernel test robot <lkp@intel.com>
Reported-by: Dan Carpenter <dan.carpenter@oracle.com>
---
Changes in V15:
 - Removed unused variables from pm8008_regulator struct.
 - Replaced static_assert with BUILD_BUG_ON.

Changes in V14:
 - Remove unused headers and debug prints.
 - Remove min_uv and max_uv from reg_data[] and set the min/max based
   on the voltage_range pointer.
 - In get_voltage_sel read voltage from hw and calculate selector instead
   of using selector from set_voltage.
 - Add errro check after regulator_list_voltage_linear_range().
 - Use static_assert to make sure nldo_ranges & pldo_ranges doesn't become
   larger and we forget to update the pm8008_reg->rdesc.n_linear_ranges

Changes in V13:
 - Added if check to avoid buffer overflow warnings.
   for (i = 0; i < ARRAY_SIZE(reg_data); i++)
     if (strstr(name, reg_data[i].name))
       break;
   if (i == ARRAY_SIZE(reg_data)) {
     dev_err(dev, "Invalid regulator name %s\n", name);
     return -EINVAL;
   }
 - Removed unused headers.

 drivers/regulator/Kconfig                 |   9 ++
 drivers/regulator/Makefile                |   1 +
 drivers/regulator/qcom-pm8008-regulator.c | 242 ++++++++++++++++++++++++++++++
 3 files changed, 252 insertions(+)
 create mode 100644 drivers/regulator/qcom-pm8008-regulator.c

diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index cbe0f96..2c6d9c2 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -925,6 +925,15 @@ 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 get support for the voltage regulators
+	  of Qualcomm Technologies, Inc. PM8008 PMIC chip. PM8008 has 7 LDO
+	  regulators. This driver provides support for basic operations like
+	  set/get voltage and enable/disable.
+
 config REGULATOR_QCOM_RPM
 	tristate "Qualcomm RPM regulator driver"
 	depends on MFD_QCOM_RPM
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 8d3ee8b..169e686 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -101,6 +101,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_RPM) += qcom_rpm-regulator.o
 obj-$(CONFIG_REGULATOR_QCOM_RPMH) += qcom-rpmh-regulator.o
 obj-$(CONFIG_REGULATOR_QCOM_SMD_RPM) += qcom_smd-regulator.o
diff --git a/drivers/regulator/qcom-pm8008-regulator.c b/drivers/regulator/qcom-pm8008-regulator.c
new file mode 100644
index 0000000..c999a7c
--- /dev/null
+++ b/drivers/regulator/qcom-pm8008-regulator.c
@@ -0,0 +1,242 @@
+// 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/mfd/qcom_pm8008.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;
+	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       headroom_uv voltage_range */
+	{ "ldo1", "vdd_l1_l2", 225000, nldo_ranges, },
+	{ "ldo2", "vdd_l1_l2", 225000, nldo_ranges, },
+	{ "ldo3", "vdd_l3_l4", 300000, pldo_ranges, },
+	{ "ldo4", "vdd_l3_l4", 300000, pldo_ranges, },
+	{ "ldo5", "vdd_l5",    200000, pldo_ranges, },
+	{ "ldo6", "vdd_l6",    200000, pldo_ranges, },
+	{ "ldo7", "vdd_l7",    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)
+{
+	int rc, i;
+	u32 base;
+	unsigned int reg;
+	const char *name;
+	struct device *dev = &pdev->dev;
+	struct regulator_config reg_config = {};
+	struct regulator_dev    *rdev;
+	const struct pm8008_data *chip = dev_get_drvdata(pdev->dev.parent);
+	struct pm8008_regulator *pm8008_reg;
+
+	pm8008_reg = devm_kzalloc(dev, sizeof(*pm8008_reg), GFP_KERNEL);
+	if (!pm8008_reg)
+		return -ENOMEM;
+
+	pm8008_reg->regmap = pm8008_get_regmap(chip);
+	if (!pm8008_reg->regmap) {
+		dev_err(dev, "parent regmap is missing\n");
+		return -EINVAL;
+	}
+
+	rc = of_property_read_string(dev->of_node, "regulator-name", &name);
+	if (rc)
+		return rc;
+
+	/* get the required regulator data */
+	for (i = 0; i < ARRAY_SIZE(reg_data); i++)
+		if (strstr(name, reg_data[i].name))
+			break;
+
+	if (i == ARRAY_SIZE(reg_data)) {
+		dev_err(dev, "Invalid regulator name %s\n", name);
+		return -EINVAL;
+	}
+
+	rc = of_property_read_u32_index(dev->of_node, "reg", 1, &base);
+	if (rc < 0) {
+		dev_err(dev, "%s: failed to get regulator base rc=%d\n", name, rc);
+		return rc;
+	}
+	pm8008_reg->base = base;
+
+	/* get slew rate */
+	rc = regmap_bulk_read(pm8008_reg->regmap,
+			LDO_STEPPER_CTL_REG(pm8008_reg->base), &reg, 1);
+	if (rc < 0) {
+		dev_err(dev, "failed to read step rate configuration rc=%d\n", rc);
+		return rc;
+	}
+	reg &= STEP_RATE_MASK;
+	pm8008_reg->step_rate = DEFAULT_VOLTAGE_STEPPER_RATE >> reg;
+
+	pm8008_reg->rdesc.type = REGULATOR_VOLTAGE;
+	pm8008_reg->rdesc.ops = &pm8008_regulator_ops;
+	pm8008_reg->rdesc.name = reg_data[i].name;
+	pm8008_reg->rdesc.supply_name = reg_data[i].supply_name;
+	pm8008_reg->rdesc.of_match = reg_data[i].name;
+	pm8008_reg->rdesc.uV_step = VSET_STEP_UV;
+	pm8008_reg->rdesc.linear_ranges = reg_data[i].voltage_range;
+	pm8008_reg->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) {
+		pm8008_reg->rdesc.min_uV = NLDO_MIN_UV;
+		pm8008_reg->rdesc.n_voltages
+				= ((NLDO_MAX_UV - NLDO_MIN_UV)
+					/ pm8008_reg->rdesc.uV_step) + 1;
+	} else {
+		pm8008_reg->rdesc.min_uV = PLDO_MIN_UV;
+		pm8008_reg->rdesc.n_voltages
+				= ((PLDO_MAX_UV - PLDO_MIN_UV)
+					/ pm8008_reg->rdesc.uV_step) + 1;
+	}
+
+	pm8008_reg->rdesc.enable_reg = LDO_ENABLE_REG(pm8008_reg->base);
+	pm8008_reg->rdesc.enable_mask = ENABLE_BIT;
+	pm8008_reg->rdesc.min_dropout_uV = reg_data[i].min_dropout_uv;
+
+	reg_config.dev = dev->parent;
+	reg_config.driver_data = pm8008_reg;
+	reg_config.regmap = pm8008_reg->regmap;
+
+	rdev = devm_regulator_register(dev, &pm8008_reg->rdesc, &reg_config);
+	if (IS_ERR(rdev)) {
+		rc = PTR_ERR(rdev);
+		dev_err(dev, "%s: failed to register regulator rc=%d\n",
+				reg_data[i].name, rc);
+		return rc;
+	}
+
+	return 0;
+}
+
+static const struct of_device_id pm8008_regulator_match_table[] = {
+	{ .compatible = "qcom,pm8008-regulator", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, pm8008_regulator_match_table);
+
+static struct platform_driver pm8008_regulator_driver = {
+	.driver	= {
+		.name		= "qcom-pm8008-regulator",
+		.of_match_table	= pm8008_regulator_match_table,
+	},
+	.probe	= pm8008_regulator_probe,
+};
+
+module_platform_driver(pm8008_regulator_driver);
+
+MODULE_DESCRIPTION("Qualcomm Technologies, Inc. PM8008 PMIC Regulator Driver");
+MODULE_LICENSE("GPL");
-- 
2.7.4


  parent reply	other threads:[~2022-06-14  9:49 UTC|newest]

Thread overview: 54+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-06-14  9:48 [PATCH V15 0/9] Add Qualcomm Technologies, Inc. PM8008 regulator driver Satya Priya
2022-06-14  9:48 ` [PATCH V15 1/9] dt-bindings: mfd: pm8008: Add reset-gpios Satya Priya
2022-06-16 20:58   ` Lee Jones
2022-06-14  9:48 ` [PATCH V15 2/9] dt-bindings: mfd: pm8008: Change the address cells Satya Priya
2022-06-16 20:59   ` Lee Jones
2022-06-17 16:34     ` Lee Jones
2022-06-14  9:48 ` [PATCH V15 3/9] dt-bindings: mfd: pm8008: Add regulators for pm8008 Satya Priya
2022-06-16 20:58   ` Lee Jones
2022-06-14  9:48 ` [PATCH V15 4/9] mfd: pm8008: Add reset-gpios Satya Priya
2022-06-16 20:58   ` Lee Jones
2022-06-17 16:34     ` Lee Jones
2022-06-29 18:36   ` Guru Das Srinagesh
2022-06-14  9:48 ` [PATCH V15 5/9] mfd: pm8008: Remove the regmap member from pm8008_data struct Satya Priya
2022-06-16 20:58   ` Lee Jones
2022-06-29 18:35   ` Guru Das Srinagesh
2022-06-14  9:48 ` [PATCH V15 6/9] mfd: pm8008: Use i2c_new_dummy_device() API Satya Priya
2022-06-16 20:57   ` Lee Jones
2022-06-20  5:28     ` Satya Priya Kakitapalli (Temp)
2022-06-20  8:20       ` Lee Jones
2022-06-20 11:07         ` Satya Priya Kakitapalli (Temp)
2022-06-27  5:07           ` Satya Priya Kakitapalli (Temp)
2022-06-27  7:41             ` Lee Jones
2022-06-28  4:53               ` Satya Priya Kakitapalli (Temp)
2022-06-28  7:42                 ` Lee Jones
2022-06-29 10:36                   ` Satya Priya Kakitapalli (Temp)
2022-06-29 15:18                     ` Lee Jones
2022-06-30  9:37                       ` Satya Priya Kakitapalli (Temp)
2022-06-30 10:34                         ` Lee Jones
2022-07-01  6:46                           ` Satya Priya Kakitapalli (Temp)
2022-07-01  7:54                             ` Lee Jones
2022-07-01  8:47                               ` Satya Priya Kakitapalli (Temp)
2022-07-01  9:12                                 ` Lee Jones
     [not found]                                   ` <0481d3cc-4bb9-4969-0232-76ba57ff260d@quicinc.com>
2022-07-04 12:49                                     ` Lee Jones
2022-07-04 12:59                                       ` Satya Priya Kakitapalli (Temp)
2022-07-11 10:31                                       ` Satya Priya Kakitapalli (Temp)
2022-07-12 12:47                                         ` Lee Jones
2022-07-13  5:50                                           ` Satya Priya Kakitapalli (Temp)
2022-07-13 13:14                                             ` Mark Brown
2022-07-22  6:31                                           ` Satya Priya Kakitapalli (Temp)
2022-07-27  1:19                                             ` Stephen Boyd
     [not found]                                               ` <52039cd1-4390-7abb-d296-0eb7ac0c3b15@quicinc.com>
2022-08-05 10:51                                                 ` Lee Jones
2022-08-08 19:09                                                   ` Stephen Boyd
2022-08-16  3:41                                                     ` Satya Priya Kakitapalli (Temp)
2022-09-28 10:20                                                     ` Lee Jones
2022-09-29  1:20                                                       ` Stephen Boyd
2022-09-29 18:01                                                         ` Lee Jones
2022-10-03 18:47                                                           ` Stephen Boyd
2022-10-04 11:41                                                             ` Lee Jones
2022-06-14  9:48 ` Satya Priya [this message]
2022-06-14 20:36   ` [PATCH V15 7/9] regulator: Add a regulator driver for the PM8008 PMIC Stephen Boyd
2022-06-14  9:48 ` [PATCH V15 8/9] arm64: dts: qcom: pm8008: Add base dts file Satya Priya
2022-06-14  9:48 ` [PATCH V15 9/9] arm64: dts: qcom: sc7280: Add pm8008 support for sc7280-idp Satya Priya
2023-03-17  8:06 ` [PATCH V15 0/9] Add Qualcomm Technologies, Inc. PM8008 regulator driver Luca Weiss
2023-07-07  8:54   ` Luca Weiss

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=1655200111-18357-8-git-send-email-quic_c_skakit@quicinc.com \
    --to=quic_c_skakit@quicinc.com \
    --cc=bjorn.andersson@linaro.org \
    --cc=broonie@kernel.org \
    --cc=devicetree@vger.kernel.org \
    --cc=lee.jones@linaro.org \
    --cc=lgirdwood@gmail.com \
    --cc=linux-arm-msm@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=quic_collinsd@quicinc.com \
    --cc=quic_jprakash@quicinc.com \
    --cc=quic_subbaram@quicinc.com \
    --cc=robh+dt@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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.