2022-05-11 18:48:45

by Satya Priya

[permalink] [raw]
Subject: [PATCH V12 0/9] Add Qualcomm Technologies, Inc. PM8008 regulator driver

Satya Priya (9):
dt-bindings: mfd: pm8008: Add reset-gpios
dt-bindings: mfd: pm8008: Change the address cells
dt-bindings: mfd: pm8008: Add regulators for pm8008
mfd: pm8008: Add reset-gpios
mfd: pm8008: Remove the regmap member from pm8008_data struct
mfd: pm8008: Use i2c_new_dummy_device() API
regulator: Add a regulator driver for the PM8008 PMIC
arm64: dts: qcom: pm8008: Add base dts file
arm64: dts: qcom: sc7280: Add pm8008 support for sc7280-idp

.../devicetree/bindings/mfd/qcom,pm8008.yaml | 69 ++++++-
arch/arm64/boot/dts/qcom/pm8008.dtsi | 54 +++++
arch/arm64/boot/dts/qcom/sc7280-idp.dtsi | 66 ++++++
drivers/mfd/qcom-pm8008.c | 60 ++++--
drivers/regulator/Kconfig | 9 +
drivers/regulator/Makefile | 1 +
drivers/regulator/qcom-pm8008-regulator.c | 221 +++++++++++++++++++++
include/linux/mfd/qcom_pm8008.h | 8 +
8 files changed, 470 insertions(+), 18 deletions(-)
create mode 100644 arch/arm64/boot/dts/qcom/pm8008.dtsi
create mode 100644 drivers/regulator/qcom-pm8008-regulator.c
create mode 100644 include/linux/mfd/qcom_pm8008.h

--
2.7.4



2022-05-11 19:27:23

by Satya Priya

[permalink] [raw]
Subject: [PATCH V12 7/9] regulator: Add a regulator driver for the PM8008 PMIC

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 <[email protected]>
---
Changes in V12:
- Get base from reg property in DT node.

Changes in V11:
- Added of_device_id table and compatible to register the ldos.

Changes in V10:
- Changed the driver name.
- Removed unused header.
- Use get_voltage_sel.

Changes in V9:
- Nothing has changed.

Changes in V8:
- Changed the regulators_data struct name to pm8008_regulator_data

drivers/regulator/Kconfig | 9 ++
drivers/regulator/Makefile | 1 +
drivers/regulator/qcom-pm8008-regulator.c | 221 ++++++++++++++++++++++++++++++
3 files changed, 231 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..0361f02
--- /dev/null
+++ b/drivers/regulator/qcom-pm8008-regulator.c
@@ -0,0 +1,221 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright (c) 2022, The Linux Foundation. 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/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/of_regulator.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)
+
+struct pm8008_regulator_data {
+ const char *name;
+ const char *supply_name;
+ int min_uv;
+ int max_uv;
+ int min_dropout_uv;
+ const struct linear_range *voltage_range;
+};
+
+struct pm8008_regulator {
+ struct device *dev;
+ struct regmap *regmap;
+ struct regulator_desc rdesc;
+ u16 base;
+ int step_rate;
+ int voltage_selector;
+};
+
+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 min_uv max_uv headroom_uv voltage_range */
+ { "ldo1", "vdd_l1_l2", 528000, 1504000, 225000, nldo_ranges, },
+ { "ldo2", "vdd_l1_l2", 528000, 1504000, 225000, nldo_ranges, },
+ { "ldo3", "vdd_l3_l4", 1504000, 3400000, 300000, pldo_ranges, },
+ { "ldo4", "vdd_l3_l4", 1504000, 3400000, 300000, pldo_ranges, },
+ { "ldo5", "vdd_l5", 1504000, 3400000, 200000, pldo_ranges, },
+ { "ldo6", "vdd_l6", 1504000, 3400000, 200000, pldo_ranges, },
+ { "ldo7", "vdd_l7", 1504000, 3400000, 200000, pldo_ranges, },
+};
+
+static int pm8008_regulator_get_voltage(struct regulator_dev *rdev)
+{
+ struct pm8008_regulator *pm8008_reg = rdev_get_drvdata(rdev);
+
+ return pm8008_reg->voltage_selector;
+}
+
+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;
+
+ /* voltage control register is set with voltage in millivolts */
+ mV = DIV_ROUND_UP(regulator_list_voltage_linear_range(rdev, selector),
+ 1000);
+ if (mV < 0)
+ return mV;
+
+ rc = pm8008_write_voltage(pm8008_reg, mV);
+ if (rc < 0)
+ return rc;
+
+ pm8008_reg->voltage_selector = selector;
+ dev_dbg(&rdev->dev, "voltage set to %d\n", mV * 1000);
+ 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;
+ }
+
+ pm8008_reg->dev = dev;
+
+ 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;
+
+ 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.min_uV = reg_data[i].min_uv;
+ pm8008_reg->rdesc.n_voltages
+ = ((reg_data[i].max_uv - reg_data[i].min_uv)
+ / pm8008_reg->rdesc.uV_step) + 1;
+ pm8008_reg->rdesc.linear_ranges = reg_data[i].voltage_range;
+ pm8008_reg->rdesc.n_linear_ranges = 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;
+ pm8008_reg->voltage_selector = -ENOTRECOVERABLE;
+
+ 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 PM8008 PMIC Regulator Driver");
+MODULE_LICENSE("GPL");
--
2.7.4


2022-05-11 20:18:22

by Satya Priya

[permalink] [raw]
Subject: [PATCH V12 6/9] mfd: pm8008: Use i2c_new_dummy_device() API

Use i2c_new_dummy_device() to register pm8008-regulator
client present at a different address space, instead of
defining a separate DT node. This avoids calling the probe
twice for the same chip, once for each client pm8008-infra
and pm8008-regulator.

As a part of this define pm8008_regmap_init() to do regmap
init for both the clients and define pm8008_get_regmap() to
pass the regmap to the regulator driver.

Signed-off-by: Satya Priya <[email protected]>
---
Changes in V12:
- Make chip as const in pm8008_get_regmap() definition.
- Use EXPORT_SYMBOL_GPL() for pm8008_get_regmap.
- Add linux/mfd/qcom_pm8008.h to avoid error.

Changes in V11:
- Remove the for loop and register dummy directly as there are
only 2 clients.
- Define pm8008_regmap_init() API to do the redundant init part.

Changes in V10:
- Implement i2c_new_dummy_device to register extra clients.

drivers/mfd/qcom-pm8008.c | 34 ++++++++++++++++++++++++++++++++--
include/linux/mfd/qcom_pm8008.h | 8 ++++++++
2 files changed, 40 insertions(+), 2 deletions(-)
create mode 100644 include/linux/mfd/qcom_pm8008.h

diff --git a/drivers/mfd/qcom-pm8008.c b/drivers/mfd/qcom-pm8008.c
index 569ffd50..55e2a8e 100644
--- a/drivers/mfd/qcom-pm8008.c
+++ b/drivers/mfd/qcom-pm8008.c
@@ -9,6 +9,7 @@
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/irqdomain.h>
+#include <linux/mfd/qcom_pm8008.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/of_platform.h>
@@ -57,6 +58,7 @@ enum {

struct pm8008_data {
struct device *dev;
+ struct regmap *regulators_regmap;
int irq;
struct regmap_irq_chip_data *irq_data;
};
@@ -150,6 +152,12 @@ static struct regmap_config qcom_mfd_regmap_cfg = {
.max_register = 0xFFFF,
};

+struct regmap *pm8008_get_regmap(const struct pm8008_data *chip)
+{
+ return chip->regulators_regmap;
+}
+EXPORT_SYMBOL_GPL(pm8008_get_regmap);
+
static int pm8008_init(struct regmap *regmap)
{
int rc;
@@ -217,11 +225,25 @@ static int pm8008_probe_irq_peripherals(struct pm8008_data *chip,
return 0;
}

+static struct regmap *pm8008_regmap_init(struct i2c_client *client,
+ struct pm8008_data *chip)
+{
+ struct regmap *regmap;
+
+ regmap = devm_regmap_init_i2c(client, &qcom_mfd_regmap_cfg);
+ if (!regmap)
+ return NULL;
+
+ i2c_set_clientdata(client, chip);
+ return regmap;
+}
+
static int pm8008_probe(struct i2c_client *client)
{
int rc;
struct pm8008_data *chip;
struct gpio_desc *reset_gpio;
+ struct i2c_client *regulators_client;
struct regmap *regmap;

chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
@@ -229,11 +251,19 @@ static int pm8008_probe(struct i2c_client *client)
return -ENOMEM;

chip->dev = &client->dev;
- regmap = devm_regmap_init_i2c(client, &qcom_mfd_regmap_cfg);
+ regmap = pm8008_regmap_init(client, chip);
if (!regmap)
return -ENODEV;

- i2c_set_clientdata(client, chip);
+ regulators_client = i2c_new_dummy_device(client->adapter, client->addr + 1);
+ if (IS_ERR(regulators_client)) {
+ dev_err(&client->dev, "can't attach client\n");
+ return PTR_ERR(regulators_client);
+ }
+
+ chip->regulators_regmap = pm8008_regmap_init(regulators_client, chip);
+ if (!chip->regulators_regmap)
+ return -ENODEV;

reset_gpio = devm_gpiod_get(chip->dev, "reset", GPIOD_OUT_LOW);
if (IS_ERR(reset_gpio))
diff --git a/include/linux/mfd/qcom_pm8008.h b/include/linux/mfd/qcom_pm8008.h
new file mode 100644
index 0000000..d5db9a2
--- /dev/null
+++ b/include/linux/mfd/qcom_pm8008.h
@@ -0,0 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __QCOM_PM8008_H__
+#define __QCOM_PM8008_H__
+
+struct pm8008_data;
+struct regmap *pm8008_get_regmap(const struct pm8008_data *chip);
+
+#endif
--
2.7.4


2022-05-11 20:23:45

by Satya Priya

[permalink] [raw]
Subject: [PATCH V12 8/9] arm64: dts: qcom: pm8008: Add base dts file

Add base DTS file for pm8008.

Signed-off-by: Satya Priya <[email protected]>
Reviewed-by: Stephen Boyd <[email protected]>
---
Changes in V12:
- None.

Changes in V11:
- Remove intermediate regulators node and add the ldos under
pm8008@8 node.
- change the address cells as 2 for pm8008 parent mfd node.
- add compatible to register the ldos.
- add reg with i2c client offset and address.

Changes in V10:
- Add regulators under pm8008@8 i.e main mfd node.

Changes in V9:
- Add single dt file for pm8008 instead of adding files like in V8.

arch/arm64/boot/dts/qcom/pm8008.dtsi | 54 ++++++++++++++++++++++++++++++++++++
1 file changed, 54 insertions(+)
create mode 100644 arch/arm64/boot/dts/qcom/pm8008.dtsi

diff --git a/arch/arm64/boot/dts/qcom/pm8008.dtsi b/arch/arm64/boot/dts/qcom/pm8008.dtsi
new file mode 100644
index 0000000..5606344
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/pm8008.dtsi
@@ -0,0 +1,54 @@
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright (c) 2022, The Linux Foundation. All rights reserved.
+
+&pm8008_bus {
+ pm8008: pmic@8 {
+ compatible = "qcom,pm8008";
+ reg = <0x8>;
+ #address-cells = <2>;
+ #size-cells = <0>;
+ #interrupt-cells = <2>;
+
+ pm8008_l1: ldo1@1,4000 {
+ compatible = "qcom,pm8008-regulator";
+ reg = <0x1 0x4000>;
+ regulator-name = "pm8008_ldo1";
+ };
+
+ pm8008_l2: ldo2@1,4100 {
+ compatible = "qcom,pm8008-regulator";
+ reg = <0x1 0x4100>;
+ regulator-name = "pm8008_ldo2";
+ };
+
+ pm8008_l3: ldo3@1,4200 {
+ compatible = "qcom,pm8008-regulator";
+ reg = <0x1 0x4200>;
+ regulator-name = "pm8008_ldo3";
+ };
+
+ pm8008_l4: ldo4@1,4300 {
+ compatible = "qcom,pm8008-regulator";
+ reg = <0x1 0x4300>;
+ regulator-name = "pm8008_ldo4";
+ };
+
+ pm8008_l5: ldo5@1,4400 {
+ compatible = "qcom,pm8008-regulator";
+ reg = <0x1 0x4400>;
+ regulator-name = "pm8008_ldo5";
+ };
+
+ pm8008_l6: ldo6@1,4500 {
+ compatible = "qcom,pm8008-regulator";
+ reg = <0x1 0x4500>;
+ regulator-name = "pm8008_ldo6";
+ };
+
+ pm8008_l7: ldo7@1,4600 {
+ compatible = "qcom,pm8008-regulator";
+ reg = <0x1 0x4600>;
+ regulator-name = "pm8008_ldo7";
+ };
+ };
+};
--
2.7.4


2022-05-11 22:51:09

by Satya Priya

[permalink] [raw]
Subject: [PATCH V12 9/9] arm64: dts: qcom: sc7280: Add pm8008 support for sc7280-idp

Add pm8008 infra and regulators support for sc7280 idp.

Signed-off-by: Satya Priya <[email protected]>
Reviewed-by: Stephen Boyd <[email protected]>
---
Changes in V12:
- None.

Changes in V11:
- Add ldos and parent supplies directly under pm8008@8 node.

Changes in V10:
- None.

Changes in V9:
- Added interrupts properties.

Changes in V8:
- Add an extra phandle "pm8008_bus" and then include pm8008 dtsi files inside it.
- Remove output-high from pm8008_active node.

arch/arm64/boot/dts/qcom/sc7280-idp.dtsi | 66 ++++++++++++++++++++++++++++++++
1 file changed, 66 insertions(+)

diff --git a/arch/arm64/boot/dts/qcom/sc7280-idp.dtsi b/arch/arm64/boot/dts/qcom/sc7280-idp.dtsi
index 5eb6689..166812e 100644
--- a/arch/arm64/boot/dts/qcom/sc7280-idp.dtsi
+++ b/arch/arm64/boot/dts/qcom/sc7280-idp.dtsi
@@ -271,6 +271,63 @@
};
};

+pm8008_bus: &i2c1 {
+ status = "okay";
+};
+
+#include "pm8008.dtsi"
+
+&pm8008 {
+ interrupt-parent = <&tlmm>;
+ interrupts = <24 IRQ_TYPE_EDGE_RISING>;
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&pm8008_active>;
+
+ reset-gpios = <&pm8350c_gpios 4 GPIO_ACTIVE_LOW>;
+
+ vdd_l1_l2-supply = <&vreg_s8b_1p2>;
+ vdd_l3_l4-supply = <&vreg_s1b_1p8>;
+ vdd_l5-supply = <&vreg_bob>;
+ vdd_l6-supply = <&vreg_bob>;
+ vdd_l7-supply = <&vreg_bob>;
+};
+
+&pm8008_l1 {
+ regulator-min-microvolt = <950000>;
+ regulator-max-microvolt = <1300000>;
+};
+
+&pm8008_l2 {
+ regulator-min-microvolt = <950000>;
+ regulator-max-microvolt = <1250000>;
+};
+
+&pm8008_l3 {
+ regulator-min-microvolt = <1650000>;
+ regulator-max-microvolt = <3000000>;
+};
+
+&pm8008_l4 {
+ regulator-min-microvolt = <1504000>;
+ regulator-max-microvolt = <1600000>;
+};
+
+&pm8008_l5 {
+ regulator-min-microvolt = <2600000>;
+ regulator-max-microvolt = <3000000>;
+};
+
+&pm8008_l6 {
+ regulator-min-microvolt = <2600000>;
+ regulator-max-microvolt = <3000000>;
+};
+
+&pm8008_l7 {
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3544000>;
+};
+
&qfprom {
vcc-supply = <&vreg_l1c_1p8>;
};
@@ -383,6 +440,15 @@
drive-strength = <2>;
};

+&pm8350c_gpios {
+ pm8008_active: pm8008-active {
+ pins = "gpio4";
+ function = "normal";
+ bias-disable;
+ power-source = <0>;
+ };
+};
+
&qspi_cs0 {
bias-disable;
};
--
2.7.4


2022-05-12 03:13:34

by Satya Priya

[permalink] [raw]
Subject: [PATCH V12 2/9] dt-bindings: mfd: pm8008: Change the address cells

Change the address cells as '2' so that the first cell
describes the i2c address offset of the clients.
This helps us to define the child nodes of all
clients under the same parent mfd node, instead of
adding separate mfd DT nodes.

Change the gpios reg value accordingly.

Signed-off-by: Satya Priya <[email protected]>
Reviewed-by: Stephen Boyd <[email protected]>
---
Changes in V12:
- None.

Changes in V11:
- New patch added from V11.

Documentation/devicetree/bindings/mfd/qcom,pm8008.yaml | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/Documentation/devicetree/bindings/mfd/qcom,pm8008.yaml b/Documentation/devicetree/bindings/mfd/qcom,pm8008.yaml
index a89649c..a41618e 100644
--- a/Documentation/devicetree/bindings/mfd/qcom,pm8008.yaml
+++ b/Documentation/devicetree/bindings/mfd/qcom,pm8008.yaml
@@ -39,7 +39,7 @@ properties:
interrupt-controller: true

"#address-cells":
- const: 1
+ const: 2

"#size-cells":
const: 0
@@ -48,7 +48,7 @@ properties:
maxItems: 1

patternProperties:
- "^gpio@[0-9a-f]+$":
+ "^gpio@[0],[0-9a-f]+$":
type: object

description: |
@@ -61,7 +61,7 @@ patternProperties:
- const: qcom,spmi-gpio

reg:
- description: Peripheral address of one of the two GPIO peripherals.
+ description: Peripheral offset and address of one of the two GPIO peripherals.
maxItems: 1

gpio-controller: true
@@ -110,7 +110,7 @@ examples:
pm8008i@8 {
compatible = "qcom,pm8008";
reg = <0x8>;
- #address-cells = <1>;
+ #address-cells = <2>;
#size-cells = <0>;
interrupt-controller;
#interrupt-cells = <2>;
@@ -120,9 +120,9 @@ examples:

reset-gpios = <&pm8350c_gpios 4 GPIO_ACTIVE_LOW>;

- pm8008_gpios: gpio@c000 {
+ pm8008_gpios: gpio@0,c000 {
compatible = "qcom,pm8008-gpio", "qcom,spmi-gpio";
- reg = <0xc000>;
+ reg = <0x0 0xc000>;
gpio-controller;
gpio-ranges = <&pm8008_gpios 0 0 2>;
#gpio-cells = <2>;
--
2.7.4


2022-05-12 16:17:46

by Satya Priya

[permalink] [raw]
Subject: [PATCH V12 5/9] mfd: pm8008: Remove the regmap member from pm8008_data struct

Remove the regmap member from pm8008_data struct as it is
not used outside of probe. Add a local variable for regmap
and pass it to the pm8008_probe_irq_peripherals()
API in pm8008_probe.

Signed-off-by: Satya Priya <[email protected]>
Reviewed-by: Stephen Boyd <[email protected]>
---
Changes in V12:
- None.

Changes in V11:
- New patch added from V11.

drivers/mfd/qcom-pm8008.c | 22 +++++++++++-----------
1 file changed, 11 insertions(+), 11 deletions(-)

diff --git a/drivers/mfd/qcom-pm8008.c b/drivers/mfd/qcom-pm8008.c
index 5a670b0..569ffd50 100644
--- a/drivers/mfd/qcom-pm8008.c
+++ b/drivers/mfd/qcom-pm8008.c
@@ -57,7 +57,6 @@ enum {

struct pm8008_data {
struct device *dev;
- struct regmap *regmap;
int irq;
struct regmap_irq_chip_data *irq_data;
};
@@ -151,7 +150,7 @@ static struct regmap_config qcom_mfd_regmap_cfg = {
.max_register = 0xFFFF,
};

-static int pm8008_init(struct pm8008_data *chip)
+static int pm8008_init(struct regmap *regmap)
{
int rc;

@@ -161,32 +160,32 @@ static int pm8008_init(struct pm8008_data *chip)
* This is required to enable the writing of TYPE registers in
* regmap_irq_sync_unlock().
*/
- rc = regmap_write(chip->regmap,
+ rc = regmap_write(regmap,
(PM8008_TEMP_ALARM_ADDR | INT_SET_TYPE_OFFSET),
BIT(0));
if (rc)
return rc;

/* Do the same for GPIO1 and GPIO2 peripherals */
- rc = regmap_write(chip->regmap,
+ rc = regmap_write(regmap,
(PM8008_GPIO1_ADDR | INT_SET_TYPE_OFFSET), BIT(0));
if (rc)
return rc;

- rc = regmap_write(chip->regmap,
+ rc = regmap_write(regmap,
(PM8008_GPIO2_ADDR | INT_SET_TYPE_OFFSET), BIT(0));

return rc;
}

static int pm8008_probe_irq_peripherals(struct pm8008_data *chip,
- int client_irq)
+ struct regmap *regmap, int client_irq)
{
int rc, i;
struct regmap_irq_type *type;
struct regmap_irq_chip_data *irq_data;

- rc = pm8008_init(chip);
+ rc = pm8008_init(regmap);
if (rc) {
dev_err(chip->dev, "Init failed: %d\n", rc);
return rc;
@@ -208,7 +207,7 @@ static int pm8008_probe_irq_peripherals(struct pm8008_data *chip,
IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW);
}

- rc = devm_regmap_add_irq_chip(chip->dev, chip->regmap, client_irq,
+ rc = devm_regmap_add_irq_chip(chip->dev, regmap, client_irq,
IRQF_SHARED, 0, &pm8008_irq_chip, &irq_data);
if (rc) {
dev_err(chip->dev, "Failed to add IRQ chip: %d\n", rc);
@@ -223,14 +222,15 @@ static int pm8008_probe(struct i2c_client *client)
int rc;
struct pm8008_data *chip;
struct gpio_desc *reset_gpio;
+ struct regmap *regmap;

chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
if (!chip)
return -ENOMEM;

chip->dev = &client->dev;
- chip->regmap = devm_regmap_init_i2c(client, &qcom_mfd_regmap_cfg);
- if (!chip->regmap)
+ regmap = devm_regmap_init_i2c(client, &qcom_mfd_regmap_cfg);
+ if (!regmap)
return -ENODEV;

i2c_set_clientdata(client, chip);
@@ -240,7 +240,7 @@ static int pm8008_probe(struct i2c_client *client)
return PTR_ERR(reset_gpio);

if (of_property_read_bool(chip->dev->of_node, "interrupt-controller")) {
- rc = pm8008_probe_irq_peripherals(chip, client->irq);
+ rc = pm8008_probe_irq_peripherals(chip, regmap, client->irq);
if (rc)
dev_err(chip->dev, "Failed to probe irq periphs: %d\n", rc);
}
--
2.7.4


2022-05-17 00:52:43

by Stephen Boyd

[permalink] [raw]
Subject: Re: [PATCH V12 7/9] regulator: Add a regulator driver for the PM8008 PMIC

Quoting Satya Priya (2022-05-11 06:18:31)
> diff --git a/drivers/regulator/qcom-pm8008-regulator.c b/drivers/regulator/qcom-pm8008-regulator.c
> new file mode 100644
> index 0000000..0361f02
> --- /dev/null
> +++ b/drivers/regulator/qcom-pm8008-regulator.c
> @@ -0,0 +1,221 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/* Copyright (c) 2022, The Linux Foundation. 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>

Is this include used?

> +#include <linux/of_device.h>
> +#include <linux/platform_device.h>
> +#include <linux/regmap.h>
> +#include <linux/regulator/driver.h>
> +#include <linux/regulator/of_regulator.h>

Is this include used?

> +
> +#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)
> +
> +struct pm8008_regulator_data {
> + const char *name;
> + const char *supply_name;
> + int min_uv;
> + int max_uv;
> + int min_dropout_uv;
> + const struct linear_range *voltage_range;
> +};
> +
> +struct pm8008_regulator {
> + struct device *dev;
> + struct regmap *regmap;
> + struct regulator_desc rdesc;
> + u16 base;
> + int step_rate;
> + int voltage_selector;
> +};
> +
> +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 min_uv max_uv headroom_uv voltage_range */
> + { "ldo1", "vdd_l1_l2", 528000, 1504000, 225000, nldo_ranges, },
> + { "ldo2", "vdd_l1_l2", 528000, 1504000, 225000, nldo_ranges, },
> + { "ldo3", "vdd_l3_l4", 1504000, 3400000, 300000, pldo_ranges, },
> + { "ldo4", "vdd_l3_l4", 1504000, 3400000, 300000, pldo_ranges, },
> + { "ldo5", "vdd_l5", 1504000, 3400000, 200000, pldo_ranges, },
> + { "ldo6", "vdd_l6", 1504000, 3400000, 200000, pldo_ranges, },
> + { "ldo7", "vdd_l7", 1504000, 3400000, 200000, pldo_ranges, },
> +};
> +
> +static int pm8008_regulator_get_voltage(struct regulator_dev *rdev)
> +{
> + struct pm8008_regulator *pm8008_reg = rdev_get_drvdata(rdev);
> +
> + return pm8008_reg->voltage_selector;
> +}
> +
> +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));

Does sparse complain about casting away __le16?

> +}
> +
> +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);
> +}
> +

2022-05-17 00:56:01

by Dan Carpenter

[permalink] [raw]
Subject: Re: [PATCH V12 7/9] regulator: Add a regulator driver for the PM8008 PMIC

Hi Satya,

url: https://github.com/intel-lab-lkp/linux/commits/Satya-Priya/Add-Qualcomm-Technologies-Inc-PM8008-regulator-driver/20220511-212136
base: https://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd.git for-mfd-next
config: nios2-randconfig-m031-20220512 (https://download.01.org/0day-ci/archive/20220513/[email protected]/config)
compiler: nios2-linux-gcc (GCC) 11.3.0

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <[email protected]>
Reported-by: Dan Carpenter <[email protected]>

New smatch warnings:
drivers/regulator/qcom-pm8008-regulator.c:174 pm8008_regulator_probe() error: buffer overflow 'reg_data' 7 <= 7 (assuming for loop doesn't break)

Old smatch warnings:
drivers/regulator/qcom-pm8008-regulator.c:175 pm8008_regulator_probe() error: buffer overflow 'reg_data' 7 <= 7 (assuming for loop doesn't break)
drivers/regulator/qcom-pm8008-regulator.c:176 pm8008_regulator_probe() error: buffer overflow 'reg_data' 7 <= 7 (assuming for loop doesn't break)
drivers/regulator/qcom-pm8008-regulator.c:178 pm8008_regulator_probe() error: buffer overflow 'reg_data' 7 <= 7 (assuming for loop doesn't break)
drivers/regulator/qcom-pm8008-regulator.c:180 pm8008_regulator_probe() error: buffer overflow 'reg_data' 7 <= 7 (assuming for loop doesn't break)
drivers/regulator/qcom-pm8008-regulator.c:180 pm8008_regulator_probe() error: buffer overflow 'reg_data' 7 <= 7 (assuming for loop doesn't break)
drivers/regulator/qcom-pm8008-regulator.c:182 pm8008_regulator_probe() error: buffer overflow 'reg_data' 7 <= 7 (assuming for loop doesn't break)
drivers/regulator/qcom-pm8008-regulator.c:186 pm8008_regulator_probe() error: buffer overflow 'reg_data' 7 <= 7 (assuming for loop doesn't break)
drivers/regulator/qcom-pm8008-regulator.c:196 pm8008_regulator_probe() error: buffer overflow 'reg_data' 7 <= 7 (assuming for loop doesn't break)

vim +174 drivers/regulator/qcom-pm8008-regulator.c

3337142527c77d Satya Priya 2022-05-11 122 static int pm8008_regulator_probe(struct platform_device *pdev)
3337142527c77d Satya Priya 2022-05-11 123 {
3337142527c77d Satya Priya 2022-05-11 124 int rc, i;
3337142527c77d Satya Priya 2022-05-11 125 u32 base;
3337142527c77d Satya Priya 2022-05-11 126 unsigned int reg;
3337142527c77d Satya Priya 2022-05-11 127 const char *name;
3337142527c77d Satya Priya 2022-05-11 128 struct device *dev = &pdev->dev;
3337142527c77d Satya Priya 2022-05-11 129 struct regulator_config reg_config = {};
3337142527c77d Satya Priya 2022-05-11 130 struct regulator_dev *rdev;
3337142527c77d Satya Priya 2022-05-11 131 const struct pm8008_data *chip = dev_get_drvdata(pdev->dev.parent);
3337142527c77d Satya Priya 2022-05-11 132 struct pm8008_regulator *pm8008_reg;
3337142527c77d Satya Priya 2022-05-11 133
3337142527c77d Satya Priya 2022-05-11 134 pm8008_reg = devm_kzalloc(dev, sizeof(*pm8008_reg), GFP_KERNEL);
3337142527c77d Satya Priya 2022-05-11 135 if (!pm8008_reg)
3337142527c77d Satya Priya 2022-05-11 136 return -ENOMEM;
3337142527c77d Satya Priya 2022-05-11 137
3337142527c77d Satya Priya 2022-05-11 138 pm8008_reg->regmap = pm8008_get_regmap(chip);
3337142527c77d Satya Priya 2022-05-11 139 if (!pm8008_reg->regmap) {
3337142527c77d Satya Priya 2022-05-11 140 dev_err(dev, "parent regmap is missing\n");
3337142527c77d Satya Priya 2022-05-11 141 return -EINVAL;
3337142527c77d Satya Priya 2022-05-11 142 }
3337142527c77d Satya Priya 2022-05-11 143
3337142527c77d Satya Priya 2022-05-11 144 pm8008_reg->dev = dev;
3337142527c77d Satya Priya 2022-05-11 145
3337142527c77d Satya Priya 2022-05-11 146 rc = of_property_read_string(dev->of_node, "regulator-name", &name);
3337142527c77d Satya Priya 2022-05-11 147 if (rc)
3337142527c77d Satya Priya 2022-05-11 148 return rc;
3337142527c77d Satya Priya 2022-05-11 149
3337142527c77d Satya Priya 2022-05-11 150 /* get the required regulator data */
3337142527c77d Satya Priya 2022-05-11 151 for (i = 0; i < ARRAY_SIZE(reg_data); i++)
3337142527c77d Satya Priya 2022-05-11 152 if (strstr(name, reg_data[i].name))
3337142527c77d Satya Priya 2022-05-11 153 break;

This code assumes that we will find a match but it would be more robust
to add a check.

if (i == ARRAY_SIZE(reg_data))
return -ENODEV;

3337142527c77d Satya Priya 2022-05-11 154
3337142527c77d Satya Priya 2022-05-11 155 rc = of_property_read_u32_index(dev->of_node, "reg", 1, &base);
3337142527c77d Satya Priya 2022-05-11 156 if (rc < 0) {
3337142527c77d Satya Priya 2022-05-11 157 dev_err(dev, "%s: failed to get regulator base rc=%d\n", name, rc);
3337142527c77d Satya Priya 2022-05-11 158 return rc;
3337142527c77d Satya Priya 2022-05-11 159 }
3337142527c77d Satya Priya 2022-05-11 160 pm8008_reg->base = base;
3337142527c77d Satya Priya 2022-05-11 161
3337142527c77d Satya Priya 2022-05-11 162 /* get slew rate */
3337142527c77d Satya Priya 2022-05-11 163 rc = regmap_bulk_read(pm8008_reg->regmap,
3337142527c77d Satya Priya 2022-05-11 164 LDO_STEPPER_CTL_REG(pm8008_reg->base), &reg, 1);
3337142527c77d Satya Priya 2022-05-11 165 if (rc < 0) {
3337142527c77d Satya Priya 2022-05-11 166 dev_err(dev, "failed to read step rate configuration rc=%d\n", rc);
3337142527c77d Satya Priya 2022-05-11 167 return rc;
3337142527c77d Satya Priya 2022-05-11 168 }
3337142527c77d Satya Priya 2022-05-11 169 reg &= STEP_RATE_MASK;
3337142527c77d Satya Priya 2022-05-11 170 pm8008_reg->step_rate = DEFAULT_VOLTAGE_STEPPER_RATE >> reg;
3337142527c77d Satya Priya 2022-05-11 171
3337142527c77d Satya Priya 2022-05-11 172 pm8008_reg->rdesc.type = REGULATOR_VOLTAGE;
3337142527c77d Satya Priya 2022-05-11 173 pm8008_reg->rdesc.ops = &pm8008_regulator_ops;
3337142527c77d Satya Priya 2022-05-11 @174 pm8008_reg->rdesc.name = reg_data[i].name;
3337142527c77d Satya Priya 2022-05-11 175 pm8008_reg->rdesc.supply_name = reg_data[i].supply_name;
3337142527c77d Satya Priya 2022-05-11 176 pm8008_reg->rdesc.of_match = reg_data[i].name;
3337142527c77d Satya Priya 2022-05-11 177 pm8008_reg->rdesc.uV_step = VSET_STEP_UV;
3337142527c77d Satya Priya 2022-05-11 178 pm8008_reg->rdesc.min_uV = reg_data[i].min_uv;
3337142527c77d Satya Priya 2022-05-11 179 pm8008_reg->rdesc.n_voltages
3337142527c77d Satya Priya 2022-05-11 180 = ((reg_data[i].max_uv - reg_data[i].min_uv)
3337142527c77d Satya Priya 2022-05-11 181 / pm8008_reg->rdesc.uV_step) + 1;
3337142527c77d Satya Priya 2022-05-11 182 pm8008_reg->rdesc.linear_ranges = reg_data[i].voltage_range;
3337142527c77d Satya Priya 2022-05-11 183 pm8008_reg->rdesc.n_linear_ranges = 1;
3337142527c77d Satya Priya 2022-05-11 184 pm8008_reg->rdesc.enable_reg = LDO_ENABLE_REG(pm8008_reg->base);
3337142527c77d Satya Priya 2022-05-11 185 pm8008_reg->rdesc.enable_mask = ENABLE_BIT;
3337142527c77d Satya Priya 2022-05-11 186 pm8008_reg->rdesc.min_dropout_uV = reg_data[i].min_dropout_uv;
3337142527c77d Satya Priya 2022-05-11 187 pm8008_reg->voltage_selector = -ENOTRECOVERABLE;
3337142527c77d Satya Priya 2022-05-11 188
3337142527c77d Satya Priya 2022-05-11 189 reg_config.dev = dev->parent;
3337142527c77d Satya Priya 2022-05-11 190 reg_config.driver_data = pm8008_reg;
3337142527c77d Satya Priya 2022-05-11 191 reg_config.regmap = pm8008_reg->regmap;
3337142527c77d Satya Priya 2022-05-11 192
3337142527c77d Satya Priya 2022-05-11 193 rdev = devm_regulator_register(dev, &pm8008_reg->rdesc, &reg_config);
3337142527c77d Satya Priya 2022-05-11 194 if (IS_ERR(rdev)) {
3337142527c77d Satya Priya 2022-05-11 195 rc = PTR_ERR(rdev);
3337142527c77d Satya Priya 2022-05-11 196 dev_err(dev, "%s: failed to register regulator rc=%d\n",
3337142527c77d Satya Priya 2022-05-11 197 reg_data[i].name, rc);
3337142527c77d Satya Priya 2022-05-11 198 return rc;
3337142527c77d Satya Priya 2022-05-11 199 }
3337142527c77d Satya Priya 2022-05-11 200
3337142527c77d Satya Priya 2022-05-11 201 return 0;
3337142527c77d Satya Priya 2022-05-11 202 }

--
0-DAY CI Kernel Test Service
https://01.org/lkp


2022-05-17 02:26:20

by Stephen Boyd

[permalink] [raw]
Subject: Re: [PATCH V12 6/9] mfd: pm8008: Use i2c_new_dummy_device() API

Quoting Satya Priya (2022-05-11 06:18:30)
> Use i2c_new_dummy_device() to register pm8008-regulator
> client present at a different address space, instead of
> defining a separate DT node. This avoids calling the probe
> twice for the same chip, once for each client pm8008-infra
> and pm8008-regulator.
>
> As a part of this define pm8008_regmap_init() to do regmap
> init for both the clients and define pm8008_get_regmap() to
> pass the regmap to the regulator driver.
>
> Signed-off-by: Satya Priya <[email protected]>
> ---

Reviewed-by: Stephen Boyd <[email protected]>

2022-05-18 03:21:12

by Rob Herring (Arm)

[permalink] [raw]
Subject: Re: [PATCH V12 2/9] dt-bindings: mfd: pm8008: Change the address cells

On Wed, 11 May 2022 18:48:26 +0530, Satya Priya wrote:
> Change the address cells as '2' so that the first cell
> describes the i2c address offset of the clients.
> This helps us to define the child nodes of all
> clients under the same parent mfd node, instead of
> adding separate mfd DT nodes.
>
> Change the gpios reg value accordingly.
>
> Signed-off-by: Satya Priya <[email protected]>
> Reviewed-by: Stephen Boyd <[email protected]>
> ---
> Changes in V12:
> - None.
>
> Changes in V11:
> - New patch added from V11.
>
> Documentation/devicetree/bindings/mfd/qcom,pm8008.yaml | 12 ++++++------
> 1 file changed, 6 insertions(+), 6 deletions(-)
>

Reviewed-by: Rob Herring <[email protected]>

2022-05-20 01:10:11

by Satya Priya

[permalink] [raw]
Subject: Re: [PATCH V12 7/9] regulator: Add a regulator driver for the PM8008 PMIC


On 5/17/2022 12:33 AM, Stephen Boyd wrote:
> Quoting Satya Priya (2022-05-11 06:18:31)
>> diff --git a/drivers/regulator/qcom-pm8008-regulator.c b/drivers/regulator/qcom-pm8008-regulator.c
>> new file mode 100644
>> index 0000000..0361f02
>> --- /dev/null
>> +++ b/drivers/regulator/qcom-pm8008-regulator.c
>> @@ -0,0 +1,221 @@
>> +// SPDX-License-Identifier: GPL-2.0-only
>> +/* Copyright (c) 2022, The Linux Foundation. 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>
> Is this include used?


This is used for of_property_read_* APIs.


>> +#include <linux/of_device.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/regmap.h>
>> +#include <linux/regulator/driver.h>
>> +#include <linux/regulator/of_regulator.h>
> Is this include used?


This is not required, I will remove this.


>> +
>> +#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)
>> +
>> +struct pm8008_regulator_data {
>> + const char *name;
>> + const char *supply_name;
>> + int min_uv;
>> + int max_uv;
>> + int min_dropout_uv;
>> + const struct linear_range *voltage_range;
>> +};
>> +
>> +struct pm8008_regulator {
>> + struct device *dev;
>> + struct regmap *regmap;
>> + struct regulator_desc rdesc;
>> + u16 base;
>> + int step_rate;
>> + int voltage_selector;
>> +};
>> +
>> +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 min_uv max_uv headroom_uv voltage_range */
>> + { "ldo1", "vdd_l1_l2", 528000, 1504000, 225000, nldo_ranges, },
>> + { "ldo2", "vdd_l1_l2", 528000, 1504000, 225000, nldo_ranges, },
>> + { "ldo3", "vdd_l3_l4", 1504000, 3400000, 300000, pldo_ranges, },
>> + { "ldo4", "vdd_l3_l4", 1504000, 3400000, 300000, pldo_ranges, },
>> + { "ldo5", "vdd_l5", 1504000, 3400000, 200000, pldo_ranges, },
>> + { "ldo6", "vdd_l6", 1504000, 3400000, 200000, pldo_ranges, },
>> + { "ldo7", "vdd_l7", 1504000, 3400000, 200000, pldo_ranges, },
>> +};
>> +
>> +static int pm8008_regulator_get_voltage(struct regulator_dev *rdev)
>> +{
>> + struct pm8008_regulator *pm8008_reg = rdev_get_drvdata(rdev);
>> +
>> + return pm8008_reg->voltage_selector;
>> +}
>> +
>> +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));
> Does sparse complain about casting away __le16?


No.


>> +}
>> +
>> +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);
>> +}
>> +