2020-07-03 08:06:15

by Robin Gong

[permalink] [raw]
Subject: [PATCH v2 0/4] Add pca9450 driver

Add pca9450 driver for i.mx8mn-evk board. PCA9450A/B/C supported now.
Please refer to below link for PCA9450 datasheet:
https://www.nxp.com/docs/en/data-sheet/PCA9450DS.pdf

v2:
1. rebase with the latest code to use linear_ranges helper instead.
2. address Frieder's comments, such as dulipcated buck4 description,
debug info added etc.

Robin Gong (4):
regulator: pca9450: add pca9450 pmic driver
dt-bindings: regulator: add pca9450 regulator yaml
arm64: dts: imx8mn-evk: add pca9450 for i.mx8mn-evk board
arm64: configs: add pca9450 pmic driver

.../bindings/regulator/nxp,pca9450-regulator.yaml | 190 +++++
arch/arm64/boot/dts/freescale/imx8mn-evk.dts | 96 +++
arch/arm64/boot/dts/freescale/imx8mn-evk.dtsi | 6 +
arch/arm64/configs/defconfig | 1 +
drivers/regulator/Kconfig | 8 +
drivers/regulator/Makefile | 1 +
drivers/regulator/pca9450-regulator.c | 859 +++++++++++++++++++++
include/linux/regulator/pca9450.h | 219 ++++++
8 files changed, 1380 insertions(+)
create mode 100644 Documentation/devicetree/bindings/regulator/nxp,pca9450-regulator.yaml
create mode 100644 drivers/regulator/pca9450-regulator.c
create mode 100644 include/linux/regulator/pca9450.h

--
2.7.4


2020-07-03 08:06:47

by Robin Gong

[permalink] [raw]
Subject: [PATCH v2 2/4] dt-bindings: regulator: add pca9450 regulator yaml

Add device binding doc for pca9450 pmic driver.

Signed-off-by: Robin Gong <[email protected]>
Reviewed-by: Rob Herring <[email protected]>
---
.../bindings/regulator/nxp,pca9450-regulator.yaml | 190 +++++++++++++++++++++
1 file changed, 190 insertions(+)
create mode 100644 Documentation/devicetree/bindings/regulator/nxp,pca9450-regulator.yaml

diff --git a/Documentation/devicetree/bindings/regulator/nxp,pca9450-regulator.yaml b/Documentation/devicetree/bindings/regulator/nxp,pca9450-regulator.yaml
new file mode 100644
index 00000000..c2b0a8b
--- /dev/null
+++ b/Documentation/devicetree/bindings/regulator/nxp,pca9450-regulator.yaml
@@ -0,0 +1,190 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/regulator/nxp,pca9450-regulator.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: NXP PCA9450A/B/C Power Management Integrated Circuit regulators
+
+maintainers:
+ - Robin Gong <[email protected]>
+
+description: |
+ Regulator nodes should be named to BUCK_<number> and LDO_<number>. The
+ definition for each of these nodes is defined using the standard
+ binding for regulators at
+ Documentation/devicetree/bindings/regulator/regulator.txt.
+ Datasheet is available at
+ https://www.nxp.com/docs/en/data-sheet/PCA9450DS.pdf
+
+#The valid names for PCA9450 regulator nodes are:
+#BUCK1, BUCK2, BUCK3, BUCK4, BUCK5, BUCK6,
+#LDO1, LDO2, LDO3, LDO4, LDO5
+#Note: Buck3 removed on PCA9450B and connect with Buck1 on PCA9450C.
+
+properties:
+ compatible:
+ enum:
+ - nxp,pca9450a
+ - nxp,pca9450b
+ - nxp,pca9450c
+
+ reg:
+ maxItems: 1
+
+ interrupts:
+ maxItems: 1
+
+ regulators:
+ type: object
+ description: |
+ list of regulators provided by this controller
+
+ patternProperties:
+ "^LDO[1-5]$":
+ type: object
+ $ref: regulator.yaml#
+ description:
+ Properties for single LDO regulator.
+
+ properties:
+ regulator-name:
+ pattern: "^LDO[1-5]$"
+ description:
+ should be "LDO1", ..., "LDO5"
+
+ unevaluatedProperties: false
+
+ "^BUCK[1-6]$":
+ type: object
+ $ref: regulator.yaml#
+ description:
+ Properties for single BUCK regulator.
+
+ properties:
+ regulator-name:
+ pattern: "^BUCK[1-6]$"
+ description:
+ should be "BUCK1", ..., "BUCK6"
+
+ nxp,dvs-run-voltage:
+ $ref: "/schemas/types.yaml#/definitions/uint32"
+ minimum: 600000
+ maximum: 2187500
+ description:
+ PMIC default "RUN" state voltage in uV. Only Buck1~3 have such
+ dvs(dynamic voltage scaling) property.
+
+ nxp,dvs-standby-voltage:
+ $ref: "/schemas/types.yaml#/definitions/uint32"
+ minimum: 600000
+ maximum: 2187500
+ description:
+ PMIC default "STANDBY" state voltage in uV. Only Buck1~3 have such
+ dvs(dynamic voltage scaling) property.
+
+ unevaluatedProperties: false
+
+ additionalProperties: false
+
+required:
+ - compatible
+ - reg
+ - interrupts
+ - regulators
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/interrupt-controller/irq.h>
+
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ pmic: pmic@25 {
+ compatible = "nxp,pca9450b";
+ reg = <0x25>;
+ pinctrl-0 = <&pinctrl_pmic>;
+ interrupt-parent = <&gpio1>;
+ interrupts = <3 IRQ_TYPE_LEVEL_LOW>;
+
+ regulators {
+ buck1: BUCK1 {
+ regulator-name = "BUCK1";
+ regulator-min-microvolt = <600000>;
+ regulator-max-microvolt = <2187500>;
+ regulator-boot-on;
+ regulator-always-on;
+ regulator-ramp-delay = <3125>;
+ };
+ buck2: BUCK2 {
+ regulator-name = "BUCK2";
+ regulator-min-microvolt = <600000>;
+ regulator-max-microvolt = <2187500>;
+ regulator-boot-on;
+ regulator-always-on;
+ regulator-ramp-delay = <3125>;
+ nxp,dvs-run-voltage = <950000>;
+ nxp,dvs-standby-voltage = <850000>;
+ };
+ buck4: BUCK4 {
+ regulator-name = "BUCK4";
+ regulator-min-microvolt = <600000>;
+ regulator-max-microvolt = <3400000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+ buck5: BUCK5 {
+ regulator-name = "BUCK5";
+ regulator-min-microvolt = <600000>;
+ regulator-max-microvolt = <3400000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+ buck6: BUCK6 {
+ regulator-name = "BUCK6";
+ regulator-min-microvolt = <600000>;
+ regulator-max-microvolt = <3400000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ ldo1: LDO1 {
+ regulator-name = "LDO1";
+ regulator-min-microvolt = <1600000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+ ldo2: LDO2 {
+ regulator-name = "LDO2";
+ regulator-min-microvolt = <800000>;
+ regulator-max-microvolt = <1150000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+ ldo3: LDO3 {
+ regulator-name = "LDO3";
+ regulator-min-microvolt = <800000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+ ldo4: LDO4 {
+ regulator-name = "LDO4";
+ regulator-min-microvolt = <800000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+ ldo5: LDO5 {
+ regulator-name = "LDO5";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+ };
+ };
+ };
--
2.7.4

2020-07-03 08:07:23

by Robin Gong

[permalink] [raw]
Subject: [PATCH v2 3/4] arm64: dts: imx8mn-evk: add pca9450 for i.mx8mn-evk board

Add pca9450 pmic driver for i.mx8mn-evk board.

Signed-off-by: Robin Gong <[email protected]>
---
arch/arm64/boot/dts/freescale/imx8mn-evk.dts | 96 +++++++++++++++++++++++++++
arch/arm64/boot/dts/freescale/imx8mn-evk.dtsi | 6 ++
2 files changed, 102 insertions(+)

diff --git a/arch/arm64/boot/dts/freescale/imx8mn-evk.dts b/arch/arm64/boot/dts/freescale/imx8mn-evk.dts
index 61f3519..b846526 100644
--- a/arch/arm64/boot/dts/freescale/imx8mn-evk.dts
+++ b/arch/arm64/boot/dts/freescale/imx8mn-evk.dts
@@ -13,6 +13,102 @@
compatible = "fsl,imx8mn-evk", "fsl,imx8mn";
};

+&i2c1 {
+ pmic: pmic@25 {
+ compatible = "nxp,pca9450b";
+ reg = <0x25>;
+ pinctrl-0 = <&pinctrl_pmic>;
+ interrupt-parent = <&gpio1>;
+ interrupts = <3 GPIO_ACTIVE_LOW>;
+
+ regulators {
+ buck1: BUCK1{
+ regulator-name = "BUCK1";
+ regulator-min-microvolt = <600000>;
+ regulator-max-microvolt = <2187500>;
+ regulator-boot-on;
+ regulator-always-on;
+ regulator-ramp-delay = <3125>;
+ };
+
+ buck2: BUCK2 {
+ regulator-name = "BUCK2";
+ regulator-min-microvolt = <600000>;
+ regulator-max-microvolt = <2187500>;
+ regulator-boot-on;
+ regulator-always-on;
+ regulator-ramp-delay = <3125>;
+ nxp,dvs-run-voltage = <950000>;
+ nxp,dvs-standby-voltage = <850000>;
+ };
+
+ buck4: BUCK4{
+ regulator-name = "BUCK4";
+ regulator-min-microvolt = <600000>;
+ regulator-max-microvolt = <3400000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ buck5: BUCK5{
+ regulator-name = "BUCK5";
+ regulator-min-microvolt = <600000>;
+ regulator-max-microvolt = <3400000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ buck6: BUCK6 {
+ regulator-name = "BUCK6";
+ regulator-min-microvolt = <600000>;
+ regulator-max-microvolt = <3400000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ ldo1: LDO1 {
+ regulator-name = "LDO1";
+ regulator-min-microvolt = <1600000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ ldo2: LDO2 {
+ regulator-name = "LDO2";
+ regulator-min-microvolt = <800000>;
+ regulator-max-microvolt = <1150000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ ldo3: LDO3 {
+ regulator-name = "LDO3";
+ regulator-min-microvolt = <800000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ ldo4: LDO4 {
+ regulator-name = "LDO4";
+ regulator-min-microvolt = <800000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ ldo5: LDO5 {
+ regulator-name = "LDO5";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+ };
+ };
+};
+
&A53_0 {
/delete-property/operating-points-v2;
};
diff --git a/arch/arm64/boot/dts/freescale/imx8mn-evk.dtsi b/arch/arm64/boot/dts/freescale/imx8mn-evk.dtsi
index 85fc0aa..98f5324 100644
--- a/arch/arm64/boot/dts/freescale/imx8mn-evk.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mn-evk.dtsi
@@ -223,6 +223,12 @@
>;
};

+ pinctrl_pmic: pmicirq {
+ fsl,pins = <
+ MX8MN_IOMUXC_GPIO1_IO03_GPIO1_IO3 0x41
+ >;
+ };
+
pinctrl_reg_usdhc2_vmmc: regusdhc2vmmc {
fsl,pins = <
MX8MN_IOMUXC_SD2_RESET_B_GPIO2_IO19 0x41
--
2.7.4

2020-07-03 08:08:16

by Robin Gong

[permalink] [raw]
Subject: [PATCH v2 4/4] arm64: configs: add pca9450 pmic driver

Add pca9450 pmic driver.

Signed-off-by: Robin Gong <[email protected]>
---
arch/arm64/configs/defconfig | 1 +
1 file changed, 1 insertion(+)

diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
index d786bd9..abd0438 100644
--- a/arch/arm64/configs/defconfig
+++ b/arch/arm64/configs/defconfig
@@ -557,6 +557,7 @@ CONFIG_REGULATOR_HI6421V530=y
CONFIG_REGULATOR_HI655X=y
CONFIG_REGULATOR_MAX77620=y
CONFIG_REGULATOR_MAX8973=y
+CONFIG_REGULATOR_PCA9450=y
CONFIG_REGULATOR_PFUZE100=y
CONFIG_REGULATOR_PWM=y
CONFIG_REGULATOR_QCOM_RPMH=y
--
2.7.4

2020-07-03 08:10:30

by Robin Gong

[permalink] [raw]
Subject: [PATCH v2 1/4] regulator: pca9450: add pca9450 pmic driver

Add NXP pca9450 pmic driver.

Signed-off-by: Robin Gong <[email protected]>
---
drivers/regulator/Kconfig | 8 +
drivers/regulator/Makefile | 1 +
drivers/regulator/pca9450-regulator.c | 843 ++++++++++++++++++++++++++++++++++
include/linux/regulator/pca9450.h | 219 +++++++++
4 files changed, 1071 insertions(+)
create mode 100644 drivers/regulator/pca9450-regulator.c
create mode 100644 include/linux/regulator/pca9450.h

diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index f60eeaa..f992a17 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -740,6 +740,14 @@ config REGULATOR_PBIAS
This driver provides support for OMAP pbias modelled
regulators.

+config REGULATOR_PCA9450
+ tristate "NXP PCA9450A/PCA9450B/PCA9450C regulator driver"
+ depends on I2C
+ select REGMAP_I2C
+ help
+ Say y here to support the NXP PCA9450A/PCA9450B/PCA9450C PMIC
+ regulator driver.
+
config REGULATOR_PCAP
tristate "Motorola PCAP2 regulator driver"
depends on EZX_PCAP
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 5ce7350..ff524922 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -94,6 +94,7 @@ obj-$(CONFIG_REGULATOR_QCOM_RPMH) += qcom-rpmh-regulator.o
obj-$(CONFIG_REGULATOR_QCOM_SMD_RPM) += qcom_smd-regulator.o
obj-$(CONFIG_REGULATOR_QCOM_SPMI) += qcom_spmi-regulator.o
obj-$(CONFIG_REGULATOR_PALMAS) += palmas-regulator.o
+obj-$(CONFIG_REGULATOR_PCA9450) += pca9450-regulator.o
obj-$(CONFIG_REGULATOR_PFUZE100) += pfuze100-regulator.o
obj-$(CONFIG_REGULATOR_PV88060) += pv88060-regulator.o
obj-$(CONFIG_REGULATOR_PV88080) += pv88080-regulator.o
diff --git a/drivers/regulator/pca9450-regulator.c b/drivers/regulator/pca9450-regulator.c
new file mode 100644
index 00000000..0225045
--- /dev/null
+++ b/drivers/regulator/pca9450-regulator.c
@@ -0,0 +1,843 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2020 NXP.
+ * NXP PCA9450 pmic driver
+ */
+
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
+#include <linux/regulator/pca9450.h>
+
+struct pc9450_dvs_config {
+ unsigned int run_reg; /* dvs0 */
+ unsigned int run_mask;
+ unsigned int standby_reg; /* dvs1 */
+ unsigned int standby_mask;
+};
+
+struct pca9450_regulator_desc {
+ struct regulator_desc desc;
+ const struct pc9450_dvs_config dvs;
+};
+
+struct pca9450 {
+ struct device *dev;
+ struct regmap *regmap;
+ enum pca9450_chip_type type;
+ unsigned int rcnt;
+ int irq;
+};
+
+static const struct regmap_range pca9450_status_range = {
+ .range_min = PCA9450_REG_INT1,
+ .range_max = PCA9450_REG_PWRON_STAT,
+};
+
+static const struct regmap_access_table pca9450_volatile_regs = {
+ .yes_ranges = &pca9450_status_range,
+ .n_yes_ranges = 1,
+};
+
+static const struct regmap_config pca9450_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .volatile_table = &pca9450_volatile_regs,
+ .max_register = PCA9450_MAX_REGISTER - 1,
+ .cache_type = REGCACHE_RBTREE,
+};
+
+/*
+ * BUCK1/2/3
+ * BUCK1RAM[1:0] BUCK1 DVS ramp rate setting
+ * 00: 25mV/1usec
+ * 01: 25mV/2usec
+ * 10: 25mV/4usec
+ * 11: 25mV/8usec
+ */
+static int pca9450_dvs_set_ramp_delay(struct regulator_dev *rdev,
+ int ramp_delay)
+{
+ int id = rdev_get_id(rdev);
+ unsigned int ramp_value;
+
+ switch (ramp_delay) {
+ case 1 ... 3125:
+ ramp_value = BUCK1_RAMP_3P125MV;
+ break;
+ case 3126 ... 6250:
+ ramp_value = BUCK1_RAMP_6P25MV;
+ break;
+ case 6251 ... 12500:
+ ramp_value = BUCK1_RAMP_12P5MV;
+ break;
+ case 12501 ... 25000:
+ ramp_value = BUCK1_RAMP_25MV;
+ break;
+ default:
+ ramp_value = BUCK1_RAMP_25MV;
+ }
+
+ return regmap_update_bits(rdev->regmap, PCA9450_REG_BUCK1CTRL + id * 3,
+ BUCK1_RAMP_MASK, ramp_value << 6);
+}
+
+static struct regulator_ops pca9450_dvs_buck_regulator_ops = {
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+ .list_voltage = regulator_list_voltage_linear_range,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_voltage_time_sel = regulator_set_voltage_time_sel,
+ .set_ramp_delay = pca9450_dvs_set_ramp_delay,
+};
+
+static struct regulator_ops pca9450_buck_regulator_ops = {
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+ .list_voltage = regulator_list_voltage_linear_range,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_voltage_time_sel = regulator_set_voltage_time_sel,
+};
+
+static struct regulator_ops pca9450_ldo_regulator_ops = {
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+ .list_voltage = regulator_list_voltage_linear_range,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+};
+
+/*
+ * BUCK1/2/3
+ * 0.60 to 2.1875V (12.5mV step)
+ */
+static const struct linear_range pca9450_dvs_buck_volts[] = {
+ REGULATOR_LINEAR_RANGE(600000, 0x00, 0x7F, 12500),
+};
+
+/*
+ * BUCK4/5/6
+ * 0.6V to 3.4V (25mV step)
+ */
+static const struct linear_range pca9450_buck_volts[] = {
+ REGULATOR_LINEAR_RANGE(600000, 0x00, 0x70, 25000),
+ REGULATOR_LINEAR_RANGE(3400000, 0x71, 0x7F, 0),
+};
+
+/*
+ * LDO1
+ * 1.6 to 3.3V ()
+ */
+static const struct linear_range pca9450_ldo1_volts[] = {
+ REGULATOR_LINEAR_RANGE(1600000, 0x00, 0x03, 100000),
+ REGULATOR_LINEAR_RANGE(3000000, 0x04, 0x07, 100000),
+};
+
+/*
+ * LDO2
+ * 0.8 to 1.15V (50mV step)
+ */
+static const struct linear_range pca9450_ldo2_volts[] = {
+ REGULATOR_LINEAR_RANGE(800000, 0x00, 0x07, 50000),
+};
+
+/*
+ * LDO3/4
+ * 0.8 to 3.3V (100mV step)
+ */
+static const struct linear_range pca9450_ldo34_volts[] = {
+ REGULATOR_LINEAR_RANGE(800000, 0x00, 0x19, 100000),
+ REGULATOR_LINEAR_RANGE(3300000, 0x1A, 0x1F, 0),
+};
+
+/*
+ * LDO5
+ * 1.8 to 3.3V (100mV step)
+ */
+static const struct linear_range pca9450_ldo5_volts[] = {
+ REGULATOR_LINEAR_RANGE(1800000, 0x00, 0x0F, 100000),
+};
+
+static int buck_set_dvs(const struct regulator_desc *desc,
+ struct device_node *np, struct regmap *regmap,
+ char *prop, unsigned int reg, unsigned int mask)
+{
+ int ret, i;
+ uint32_t uv;
+
+ ret = of_property_read_u32(np, prop, &uv);
+ if (ret == -EINVAL)
+ return 0;
+ else if (ret)
+ return ret;
+
+ for (i = 0; i < desc->n_voltages; i++) {
+ ret = regulator_desc_list_voltage_linear_range(desc, i);
+ if (ret < 0)
+ continue;
+ if (ret == uv) {
+ i <<= ffs(desc->vsel_mask) - 1;
+ ret = regmap_update_bits(regmap, reg, mask, i);
+ break;
+ }
+ }
+
+ return ret;
+}
+
+static int pca9450_set_dvs_levels(struct device_node *np,
+ const struct regulator_desc *desc,
+ struct regulator_config *cfg)
+{
+ struct pca9450_regulator_desc *data = container_of(desc,
+ struct pca9450_regulator_desc, desc);
+ const struct pc9450_dvs_config *dvs = &data->dvs;
+ unsigned int reg, mask;
+ char *prop;
+ int i, ret = 0;
+
+ for (i = 0; i < PCA9450_DVS_LEVEL_MAX; i++) {
+ switch (i) {
+ case PCA9450_DVS_LEVEL_RUN:
+ prop = "nxp,dvs-run-voltage";
+ reg = dvs->run_reg;
+ mask = dvs->run_mask;
+ break;
+ case PCA9450_DVS_LEVEL_STANDBY:
+ prop = "nxp,dvs-standby-voltage";
+ reg = dvs->standby_reg;
+ mask = dvs->standby_mask;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = buck_set_dvs(desc, np, cfg->regmap, prop, reg, mask);
+ if (ret)
+ break;
+ }
+
+ return ret;
+}
+
+static const struct pca9450_regulator_desc pca9450a_regulators[] = {
+ {
+ .desc = {
+ .name = "buck1",
+ .of_match = of_match_ptr("BUCK1"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = PCA9450_BUCK1,
+ .ops = &pca9450_dvs_buck_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = PCA9450_BUCK1_VOLTAGE_NUM,
+ .linear_ranges = pca9450_dvs_buck_volts,
+ .n_linear_ranges = ARRAY_SIZE(pca9450_dvs_buck_volts),
+ .vsel_reg = PCA9450_REG_BUCK1OUT_DVS0,
+ .vsel_mask = BUCK1OUT_DVS0_MASK,
+ .enable_reg = PCA9450_REG_BUCK1CTRL,
+ .enable_mask = BUCK1_ENMODE_MASK,
+ .owner = THIS_MODULE,
+ .of_parse_cb = pca9450_set_dvs_levels,
+ },
+ .dvs = {
+ .run_reg = PCA9450_REG_BUCK1OUT_DVS0,
+ .run_mask = BUCK1OUT_DVS0_MASK,
+ .standby_reg = PCA9450_REG_BUCK1OUT_DVS1,
+ .standby_mask = BUCK1OUT_DVS1_MASK,
+ },
+ },
+ {
+ .desc = {
+ .name = "buck2",
+ .of_match = of_match_ptr("BUCK2"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = PCA9450_BUCK2,
+ .ops = &pca9450_dvs_buck_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = PCA9450_BUCK2_VOLTAGE_NUM,
+ .linear_ranges = pca9450_dvs_buck_volts,
+ .n_linear_ranges = ARRAY_SIZE(pca9450_dvs_buck_volts),
+ .vsel_reg = PCA9450_REG_BUCK2OUT_DVS0,
+ .vsel_mask = BUCK2OUT_DVS0_MASK,
+ .enable_reg = PCA9450_REG_BUCK2CTRL,
+ .enable_mask = BUCK1_ENMODE_MASK,
+ .owner = THIS_MODULE,
+ .of_parse_cb = pca9450_set_dvs_levels,
+ },
+ .dvs = {
+ .run_reg = PCA9450_REG_BUCK2OUT_DVS0,
+ .run_mask = BUCK2OUT_DVS0_MASK,
+ .standby_reg = PCA9450_REG_BUCK2OUT_DVS1,
+ .standby_mask = BUCK2OUT_DVS1_MASK,
+ },
+ },
+ {
+ .desc = {
+ .name = "buck3",
+ .of_match = of_match_ptr("BUCK3"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = PCA9450_BUCK3,
+ .ops = &pca9450_dvs_buck_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = PCA9450_BUCK3_VOLTAGE_NUM,
+ .linear_ranges = pca9450_dvs_buck_volts,
+ .n_linear_ranges = ARRAY_SIZE(pca9450_dvs_buck_volts),
+ .vsel_reg = PCA9450_REG_BUCK3OUT_DVS0,
+ .vsel_mask = BUCK3OUT_DVS0_MASK,
+ .enable_reg = PCA9450_REG_BUCK3CTRL,
+ .enable_mask = BUCK3_ENMODE_MASK,
+ .owner = THIS_MODULE,
+ .of_parse_cb = pca9450_set_dvs_levels,
+ },
+ .dvs = {
+ .run_reg = PCA9450_REG_BUCK3OUT_DVS0,
+ .run_mask = BUCK3OUT_DVS0_MASK,
+ .standby_reg = PCA9450_REG_BUCK3OUT_DVS1,
+ .standby_mask = BUCK3OUT_DVS1_MASK,
+ },
+ },
+ {
+ .desc = {
+ .name = "buck4",
+ .of_match = of_match_ptr("BUCK4"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = PCA9450_BUCK4,
+ .ops = &pca9450_buck_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = PCA9450_BUCK4_VOLTAGE_NUM,
+ .linear_ranges = pca9450_buck_volts,
+ .n_linear_ranges = ARRAY_SIZE(pca9450_buck_volts),
+ .vsel_reg = PCA9450_REG_BUCK4OUT,
+ .vsel_mask = BUCK4OUT_MASK,
+ .enable_reg = PCA9450_REG_BUCK4CTRL,
+ .enable_mask = BUCK4_ENMODE_MASK,
+ .owner = THIS_MODULE,
+ },
+ },
+ {
+ .desc = {
+ .name = "buck5",
+ .of_match = of_match_ptr("BUCK5"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = PCA9450_BUCK5,
+ .ops = &pca9450_buck_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = PCA9450_BUCK5_VOLTAGE_NUM,
+ .linear_ranges = pca9450_buck_volts,
+ .n_linear_ranges = ARRAY_SIZE(pca9450_buck_volts),
+ .vsel_reg = PCA9450_REG_BUCK5OUT,
+ .vsel_mask = BUCK5OUT_MASK,
+ .enable_reg = PCA9450_REG_BUCK5CTRL,
+ .enable_mask = BUCK5_ENMODE_MASK,
+ .owner = THIS_MODULE,
+ },
+ },
+ {
+ .desc = {
+ .name = "buck6",
+ .of_match = of_match_ptr("BUCK6"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = PCA9450_BUCK6,
+ .ops = &pca9450_buck_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = PCA9450_BUCK6_VOLTAGE_NUM,
+ .linear_ranges = pca9450_buck_volts,
+ .n_linear_ranges = ARRAY_SIZE(pca9450_buck_volts),
+ .vsel_reg = PCA9450_REG_BUCK6OUT,
+ .vsel_mask = BUCK6OUT_MASK,
+ .enable_reg = PCA9450_REG_BUCK6CTRL,
+ .enable_mask = BUCK6_ENMODE_MASK,
+ .owner = THIS_MODULE,
+ },
+ },
+ {
+ .desc = {
+ .name = "ldo1",
+ .of_match = of_match_ptr("LDO1"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = PCA9450_LDO1,
+ .ops = &pca9450_ldo_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = PCA9450_LDO1_VOLTAGE_NUM,
+ .linear_ranges = pca9450_ldo1_volts,
+ .n_linear_ranges = ARRAY_SIZE(pca9450_ldo1_volts),
+ .vsel_reg = PCA9450_REG_LDO1CTRL,
+ .vsel_mask = LDO1OUT_MASK,
+ .enable_reg = PCA9450_REG_LDO1CTRL,
+ .enable_mask = LDO1_EN_MASK,
+ .owner = THIS_MODULE,
+ },
+ },
+ {
+ .desc = {
+ .name = "ldo2",
+ .of_match = of_match_ptr("LDO2"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = PCA9450_LDO2,
+ .ops = &pca9450_ldo_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = PCA9450_LDO2_VOLTAGE_NUM,
+ .linear_ranges = pca9450_ldo2_volts,
+ .n_linear_ranges = ARRAY_SIZE(pca9450_ldo2_volts),
+ .vsel_reg = PCA9450_REG_LDO2CTRL,
+ .vsel_mask = LDO2OUT_MASK,
+ .enable_reg = PCA9450_REG_LDO2CTRL,
+ .enable_mask = LDO2_EN_MASK,
+ .owner = THIS_MODULE,
+ },
+ },
+ {
+ .desc = {
+ .name = "ldo3",
+ .of_match = of_match_ptr("LDO3"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = PCA9450_LDO3,
+ .ops = &pca9450_ldo_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = PCA9450_LDO3_VOLTAGE_NUM,
+ .linear_ranges = pca9450_ldo34_volts,
+ .n_linear_ranges = ARRAY_SIZE(pca9450_ldo34_volts),
+ .vsel_reg = PCA9450_REG_LDO3CTRL,
+ .vsel_mask = LDO3OUT_MASK,
+ .enable_reg = PCA9450_REG_LDO3CTRL,
+ .enable_mask = LDO3_EN_MASK,
+ .owner = THIS_MODULE,
+ },
+ },
+ {
+ .desc = {
+ .name = "ldo4",
+ .of_match = of_match_ptr("LDO4"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = PCA9450_LDO4,
+ .ops = &pca9450_ldo_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = PCA9450_LDO4_VOLTAGE_NUM,
+ .linear_ranges = pca9450_ldo34_volts,
+ .n_linear_ranges = ARRAY_SIZE(pca9450_ldo34_volts),
+ .vsel_reg = PCA9450_REG_LDO4CTRL,
+ .vsel_mask = LDO4OUT_MASK,
+ .enable_reg = PCA9450_REG_LDO4CTRL,
+ .enable_mask = LDO4_EN_MASK,
+ .owner = THIS_MODULE,
+ },
+ },
+ {
+ .desc = {
+ .name = "ldo5",
+ .of_match = of_match_ptr("LDO5"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = PCA9450_LDO5,
+ .ops = &pca9450_ldo_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = PCA9450_LDO5_VOLTAGE_NUM,
+ .linear_ranges = pca9450_ldo5_volts,
+ .n_linear_ranges = ARRAY_SIZE(pca9450_ldo5_volts),
+ .vsel_reg = PCA9450_REG_LDO5CTRL_H,
+ .vsel_mask = LDO5HOUT_MASK,
+ .enable_reg = PCA9450_REG_LDO5CTRL_H,
+ .enable_mask = LDO5H_EN_MASK,
+ .owner = THIS_MODULE,
+ },
+ },
+};
+
+/*
+ * Buck3 removed on PCA9450B and connected with Buck1 internal for dual phase
+ * on PCA9450C as no Buck3.
+ */
+static const struct pca9450_regulator_desc pca9450bc_regulators[] = {
+ {
+ .desc = {
+ .name = "buck1",
+ .of_match = of_match_ptr("BUCK1"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = PCA9450_BUCK1,
+ .ops = &pca9450_dvs_buck_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = PCA9450_BUCK1_VOLTAGE_NUM,
+ .linear_ranges = pca9450_dvs_buck_volts,
+ .n_linear_ranges = ARRAY_SIZE(pca9450_dvs_buck_volts),
+ .vsel_reg = PCA9450_REG_BUCK1OUT_DVS0,
+ .vsel_mask = BUCK1OUT_DVS0_MASK,
+ .enable_reg = PCA9450_REG_BUCK1CTRL,
+ .enable_mask = BUCK1_ENMODE_MASK,
+ .owner = THIS_MODULE,
+ .of_parse_cb = pca9450_set_dvs_levels,
+ },
+ .dvs = {
+ .run_reg = PCA9450_REG_BUCK1OUT_DVS0,
+ .run_mask = BUCK1OUT_DVS0_MASK,
+ .standby_reg = PCA9450_REG_BUCK1OUT_DVS1,
+ .standby_mask = BUCK1OUT_DVS1_MASK,
+ },
+ },
+ {
+ .desc = {
+ .name = "buck2",
+ .of_match = of_match_ptr("BUCK2"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = PCA9450_BUCK2,
+ .ops = &pca9450_dvs_buck_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = PCA9450_BUCK2_VOLTAGE_NUM,
+ .linear_ranges = pca9450_dvs_buck_volts,
+ .n_linear_ranges = ARRAY_SIZE(pca9450_dvs_buck_volts),
+ .vsel_reg = PCA9450_REG_BUCK2OUT_DVS0,
+ .vsel_mask = BUCK2OUT_DVS0_MASK,
+ .enable_reg = PCA9450_REG_BUCK2CTRL,
+ .enable_mask = BUCK1_ENMODE_MASK,
+ .owner = THIS_MODULE,
+ .of_parse_cb = pca9450_set_dvs_levels,
+ },
+ .dvs = {
+ .run_reg = PCA9450_REG_BUCK2OUT_DVS0,
+ .run_mask = BUCK2OUT_DVS0_MASK,
+ .standby_reg = PCA9450_REG_BUCK2OUT_DVS1,
+ .standby_mask = BUCK2OUT_DVS1_MASK,
+ },
+ },
+ {
+ .desc = {
+ .name = "buck4",
+ .of_match = of_match_ptr("BUCK4"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = PCA9450_BUCK4,
+ .ops = &pca9450_buck_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = PCA9450_BUCK4_VOLTAGE_NUM,
+ .linear_ranges = pca9450_buck_volts,
+ .n_linear_ranges = ARRAY_SIZE(pca9450_buck_volts),
+ .vsel_reg = PCA9450_REG_BUCK4OUT,
+ .vsel_mask = BUCK4OUT_MASK,
+ .enable_reg = PCA9450_REG_BUCK4CTRL,
+ .enable_mask = BUCK4_ENMODE_MASK,
+ .owner = THIS_MODULE,
+ },
+ },
+ {
+ .desc = {
+ .name = "buck5",
+ .of_match = of_match_ptr("BUCK5"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = PCA9450_BUCK5,
+ .ops = &pca9450_buck_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = PCA9450_BUCK5_VOLTAGE_NUM,
+ .linear_ranges = pca9450_buck_volts,
+ .n_linear_ranges = ARRAY_SIZE(pca9450_buck_volts),
+ .vsel_reg = PCA9450_REG_BUCK5OUT,
+ .vsel_mask = BUCK5OUT_MASK,
+ .enable_reg = PCA9450_REG_BUCK5CTRL,
+ .enable_mask = BUCK5_ENMODE_MASK,
+ .owner = THIS_MODULE,
+ },
+ },
+ {
+ .desc = {
+ .name = "buck6",
+ .of_match = of_match_ptr("BUCK6"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = PCA9450_BUCK6,
+ .ops = &pca9450_buck_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = PCA9450_BUCK6_VOLTAGE_NUM,
+ .linear_ranges = pca9450_buck_volts,
+ .n_linear_ranges = ARRAY_SIZE(pca9450_buck_volts),
+ .vsel_reg = PCA9450_REG_BUCK6OUT,
+ .vsel_mask = BUCK6OUT_MASK,
+ .enable_reg = PCA9450_REG_BUCK6CTRL,
+ .enable_mask = BUCK6_ENMODE_MASK,
+ .owner = THIS_MODULE,
+ },
+ },
+ {
+ .desc = {
+ .name = "ldo1",
+ .of_match = of_match_ptr("LDO1"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = PCA9450_LDO1,
+ .ops = &pca9450_ldo_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = PCA9450_LDO1_VOLTAGE_NUM,
+ .linear_ranges = pca9450_ldo1_volts,
+ .n_linear_ranges = ARRAY_SIZE(pca9450_ldo1_volts),
+ .vsel_reg = PCA9450_REG_LDO1CTRL,
+ .vsel_mask = LDO1OUT_MASK,
+ .enable_reg = PCA9450_REG_LDO1CTRL,
+ .enable_mask = LDO1_EN_MASK,
+ .owner = THIS_MODULE,
+ },
+ },
+ {
+ .desc = {
+ .name = "ldo2",
+ .of_match = of_match_ptr("LDO2"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = PCA9450_LDO2,
+ .ops = &pca9450_ldo_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = PCA9450_LDO2_VOLTAGE_NUM,
+ .linear_ranges = pca9450_ldo2_volts,
+ .n_linear_ranges = ARRAY_SIZE(pca9450_ldo2_volts),
+ .vsel_reg = PCA9450_REG_LDO2CTRL,
+ .vsel_mask = LDO2OUT_MASK,
+ .enable_reg = PCA9450_REG_LDO2CTRL,
+ .enable_mask = LDO2_EN_MASK,
+ .owner = THIS_MODULE,
+ },
+ },
+ {
+ .desc = {
+ .name = "ldo3",
+ .of_match = of_match_ptr("LDO3"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = PCA9450_LDO3,
+ .ops = &pca9450_ldo_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = PCA9450_LDO3_VOLTAGE_NUM,
+ .linear_ranges = pca9450_ldo34_volts,
+ .n_linear_ranges = ARRAY_SIZE(pca9450_ldo34_volts),
+ .vsel_reg = PCA9450_REG_LDO3CTRL,
+ .vsel_mask = LDO3OUT_MASK,
+ .enable_reg = PCA9450_REG_LDO3CTRL,
+ .enable_mask = LDO3_EN_MASK,
+ .owner = THIS_MODULE,
+ },
+ },
+ {
+ .desc = {
+ .name = "ldo4",
+ .of_match = of_match_ptr("LDO4"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = PCA9450_LDO4,
+ .ops = &pca9450_ldo_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = PCA9450_LDO4_VOLTAGE_NUM,
+ .linear_ranges = pca9450_ldo34_volts,
+ .n_linear_ranges = ARRAY_SIZE(pca9450_ldo34_volts),
+ .vsel_reg = PCA9450_REG_LDO4CTRL,
+ .vsel_mask = LDO4OUT_MASK,
+ .enable_reg = PCA9450_REG_LDO4CTRL,
+ .enable_mask = LDO4_EN_MASK,
+ .owner = THIS_MODULE,
+ },
+ },
+ {
+ .desc = {
+ .name = "ldo5",
+ .of_match = of_match_ptr("LDO5"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = PCA9450_LDO5,
+ .ops = &pca9450_ldo_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = PCA9450_LDO5_VOLTAGE_NUM,
+ .linear_ranges = pca9450_ldo5_volts,
+ .n_linear_ranges = ARRAY_SIZE(pca9450_ldo5_volts),
+ .vsel_reg = PCA9450_REG_LDO5CTRL_H,
+ .vsel_mask = LDO5HOUT_MASK,
+ .enable_reg = PCA9450_REG_LDO5CTRL_H,
+ .enable_mask = LDO5H_EN_MASK,
+ .owner = THIS_MODULE,
+ },
+ },
+};
+
+static irqreturn_t pca9450_irq_handler(int irq, void *data)
+{
+ struct pca9450 *pca9450 = data;
+ struct regmap *regmap = pca9450->regmap;
+ unsigned int status;
+ int ret;
+
+ ret = regmap_read(regmap, PCA9450_REG_INT1, &status);
+ if (ret < 0) {
+ dev_err(pca9450->dev,
+ "Failed to read INT1(%d)\n", ret);
+ return IRQ_NONE;
+ }
+
+ if (status & IRQ_PWRON)
+ dev_warn(pca9450->dev, "PWRON interrupt.\n");
+
+ if (status & IRQ_WDOGB)
+ dev_warn(pca9450->dev, "WDOGB interrupt.\n");
+
+ if (status & IRQ_VR_FLT1)
+ dev_warn(pca9450->dev, "VRFLT1 interrupt.\n");
+
+ if (status & IRQ_VR_FLT2)
+ dev_warn(pca9450->dev, "VRFLT2 interrupt.\n");
+
+ if (status & IRQ_LOWVSYS)
+ dev_warn(pca9450->dev, "LOWVSYS interrupt.\n");
+
+ if (status & IRQ_THERM_105)
+ dev_warn(pca9450->dev, "IRQ_THERM_105 interrupt.\n");
+
+ if (status & IRQ_THERM_125)
+ dev_warn(pca9450->dev, "IRQ_THERM_125 interrupt.\n");
+
+ return IRQ_HANDLED;
+}
+
+static int pca9450_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ enum pca9450_chip_type type = (unsigned int)(uintptr_t)
+ of_device_get_match_data(&i2c->dev);
+ const struct pca9450_regulator_desc *regulator_desc;
+ struct regulator_config config = { };
+ struct pca9450 *pca9450;
+ unsigned int device_id, i;
+ int ret;
+
+ if (!i2c->irq) {
+ dev_err(&i2c->dev, "No IRQ configured?\n");
+ return -EINVAL;
+ }
+
+ pca9450 = devm_kzalloc(&i2c->dev, sizeof(struct pca9450), GFP_KERNEL);
+ if (!pca9450)
+ return -ENOMEM;
+
+ switch (type) {
+ case PCA9450_TYPE_PCA9450A:
+ regulator_desc = pca9450a_regulators;
+ pca9450->rcnt = ARRAY_SIZE(pca9450a_regulators);
+ break;
+ case PCA9450_TYPE_PCA9450BC:
+ regulator_desc = pca9450bc_regulators;
+ pca9450->rcnt = ARRAY_SIZE(pca9450bc_regulators);
+ break;
+ default:
+ dev_err(&i2c->dev, "Unknown device type");
+ return -EINVAL;
+ }
+
+ pca9450->irq = i2c->irq;
+ pca9450->type = type;
+ pca9450->dev = &i2c->dev;
+
+ dev_set_drvdata(&i2c->dev, pca9450);
+
+ pca9450->regmap = devm_regmap_init_i2c(i2c,
+ &pca9450_regmap_config);
+ if (IS_ERR(pca9450->regmap)) {
+ dev_err(&i2c->dev, "regmap initialization failed\n");
+ return PTR_ERR(pca9450->regmap);
+ }
+
+ ret = regmap_read(pca9450->regmap, PCA9450_REG_DEV_ID, &device_id);
+ if (ret) {
+ dev_err(&i2c->dev, "Read device id error\n");
+ return ret;
+ }
+
+ /* Check your board and dts for match the right pmic */
+ if (((device_id >> 4) != 0x1 && type == PCA9450_TYPE_PCA9450A) ||
+ ((device_id >> 4) != 0x3 && type == PCA9450_TYPE_PCA9450BC)) {
+ dev_err(&i2c->dev, "Device id(%x) mismatched\n",
+ device_id >> 4);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < pca9450->rcnt; i++) {
+ const struct regulator_desc *desc;
+ struct regulator_dev *rdev;
+ const struct pca9450_regulator_desc *r;
+
+ r = &regulator_desc[i];
+ desc = &r->desc;
+
+ config.regmap = pca9450->regmap;
+ config.dev = pca9450->dev;
+
+ rdev = devm_regulator_register(pca9450->dev, desc, &config);
+ if (IS_ERR(rdev)) {
+ ret = PTR_ERR(rdev);
+ dev_err(pca9450->dev,
+ "Failed to register regulator(%s): %d\n",
+ desc->name, ret);
+ return ret;
+ }
+ }
+
+ ret = devm_request_threaded_irq(pca9450->dev, pca9450->irq, NULL,
+ pca9450_irq_handler,
+ (IRQF_TRIGGER_FALLING | IRQF_ONESHOT),
+ "pca9450-irq", pca9450);
+ if (ret != 0) {
+ dev_err(pca9450->dev, "Failed to request IRQ: %d\n",
+ pca9450->irq);
+ return ret;
+ }
+ /* Unmask all interrupt except PWRON/WDOG/RSVD */
+ ret = regmap_update_bits(pca9450->regmap, PCA9450_REG_INT1_MSK,
+ IRQ_VR_FLT1 | IRQ_VR_FLT2 | IRQ_LOWVSYS |
+ IRQ_THERM_105 | IRQ_THERM_125,
+ IRQ_PWRON | IRQ_WDOGB | IRQ_RSVD);
+ if (ret) {
+ dev_err(&i2c->dev, "Unmask irq error\n");
+ return ret;
+ }
+
+ dev_info(&i2c->dev, "%s probed.\n",
+ type == PCA9450_TYPE_PCA9450A ? "pca9450a" : "pca9450bc");
+
+ return 0;
+}
+
+static const struct of_device_id pca9450_of_match[] = {
+ {
+ .compatible = "nxp,pca9450a",
+ .data = (void *)PCA9450_TYPE_PCA9450A,
+ },
+ {
+ .compatible = "nxp,pca9450b",
+ .data = (void *)PCA9450_TYPE_PCA9450BC,
+ },
+ {
+ .compatible = "nxp,pca9450c",
+ .data = (void *)PCA9450_TYPE_PCA9450BC,
+ },
+ { }
+};
+MODULE_DEVICE_TABLE(of, pca9450_of_match);
+
+static struct i2c_driver pca9450_i2c_driver = {
+ .driver = {
+ .name = "nxp-pca9450",
+ .of_match_table = pca9450_of_match,
+ },
+ .probe = pca9450_i2c_probe,
+};
+
+static int __init pca9450_i2c_init(void)
+{
+ return i2c_add_driver(&pca9450_i2c_driver);
+}
+module_init(pca9450_i2c_init);
+
+static void __exit pca9450_i2c_exit(void)
+{
+ i2c_del_driver(&pca9450_i2c_driver);
+}
+module_exit(pca9450_i2c_exit);
+
+MODULE_AUTHOR("Robin Gong <[email protected]>");
+MODULE_DESCRIPTION("NXP PCA9450 Power Management IC driver");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/regulator/pca9450.h b/include/linux/regulator/pca9450.h
new file mode 100644
index 00000000..1bbd301
--- /dev/null
+++ b/include/linux/regulator/pca9450.h
@@ -0,0 +1,219 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/* Copyright 2020 NXP. */
+
+#ifndef __LINUX_REG_PCA9450_H__
+#define __LINUX_REG_PCA9450_H__
+
+#include <linux/regmap.h>
+
+enum pca9450_chip_type {
+ PCA9450_TYPE_PCA9450A = 0,
+ PCA9450_TYPE_PCA9450BC,
+ PCA9450_TYPE_AMOUNT,
+};
+
+enum {
+ PCA9450_BUCK1 = 0,
+ PCA9450_BUCK2,
+ PCA9450_BUCK3,
+ PCA9450_BUCK4,
+ PCA9450_BUCK5,
+ PCA9450_BUCK6,
+ PCA9450_LDO1,
+ PCA9450_LDO2,
+ PCA9450_LDO3,
+ PCA9450_LDO4,
+ PCA9450_LDO5,
+ PCA9450_REGULATOR_CNT,
+};
+
+enum {
+ PCA9450_DVS_LEVEL_RUN = 0,
+ PCA9450_DVS_LEVEL_STANDBY,
+ PCA9450_DVS_LEVEL_MAX,
+};
+
+#define PCA9450_BUCK1_VOLTAGE_NUM 0x80
+#define PCA9450_BUCK2_VOLTAGE_NUM 0x80
+#define PCA9450_BUCK3_VOLTAGE_NUM 0x80
+#define PCA9450_BUCK4_VOLTAGE_NUM 0x80
+
+#define PCA9450_BUCK5_VOLTAGE_NUM 0x80
+#define PCA9450_BUCK6_VOLTAGE_NUM 0x80
+
+#define PCA9450_LDO1_VOLTAGE_NUM 0x08
+#define PCA9450_LDO2_VOLTAGE_NUM 0x08
+#define PCA9450_LDO3_VOLTAGE_NUM 0x20
+#define PCA9450_LDO4_VOLTAGE_NUM 0x20
+#define PCA9450_LDO5_VOLTAGE_NUM 0x10
+
+enum {
+ PCA9450_REG_DEV_ID = 0x00,
+ PCA9450_REG_INT1 = 0x01,
+ PCA9450_REG_INT1_MSK = 0x02,
+ PCA9450_REG_STATUS1 = 0x03,
+ PCA9450_REG_STATUS2 = 0x04,
+ PCA9450_REG_PWRON_STAT = 0x05,
+ PCA9450_REG_SWRST = 0x06,
+ PCA9450_REG_PWRCTRL = 0x07,
+ PCA9450_REG_RESET_CTRL = 0x08,
+ PCA9450_REG_CONFIG1 = 0x09,
+ PCA9450_REG_CONFIG2 = 0x0A,
+ PCA9450_REG_BUCK123_DVS = 0x0C,
+ PCA9450_REG_BUCK1OUT_LIMIT = 0x0D,
+ PCA9450_REG_BUCK2OUT_LIMIT = 0x0E,
+ PCA9450_REG_BUCK3OUT_LIMIT = 0x0F,
+ PCA9450_REG_BUCK1CTRL = 0x10,
+ PCA9450_REG_BUCK1OUT_DVS0 = 0x11,
+ PCA9450_REG_BUCK1OUT_DVS1 = 0x12,
+ PCA9450_REG_BUCK2CTRL = 0x13,
+ PCA9450_REG_BUCK2OUT_DVS0 = 0x14,
+ PCA9450_REG_BUCK2OUT_DVS1 = 0x15,
+ PCA9450_REG_BUCK3CTRL = 0x16,
+ PCA9450_REG_BUCK3OUT_DVS0 = 0x17,
+ PCA9450_REG_BUCK3OUT_DVS1 = 0x18,
+ PCA9450_REG_BUCK4CTRL = 0x19,
+ PCA9450_REG_BUCK4OUT = 0x1A,
+ PCA9450_REG_BUCK5CTRL = 0x1B,
+ PCA9450_REG_BUCK5OUT = 0x1C,
+ PCA9450_REG_BUCK6CTRL = 0x1D,
+ PCA9450_REG_BUCK6OUT = 0x1E,
+ PCA9450_REG_LDO_AD_CTRL = 0x20,
+ PCA9450_REG_LDO1CTRL = 0x21,
+ PCA9450_REG_LDO2CTRL = 0x22,
+ PCA9450_REG_LDO3CTRL = 0x23,
+ PCA9450_REG_LDO4CTRL = 0x24,
+ PCA9450_REG_LDO5CTRL_L = 0x25,
+ PCA9450_REG_LDO5CTRL_H = 0x26,
+ PCA9450_REG_LOADSW_CTRL = 0x2A,
+ PCA9450_REG_VRFLT1_STS = 0x2B,
+ PCA9450_REG_VRFLT2_STS = 0x2C,
+ PCA9450_REG_VRFLT1_MASK = 0x2D,
+ PCA9450_REG_VRFLT2_MASK = 0x2E,
+ PCA9450_MAX_REGISTER = 0x2F,
+};
+
+/* PCA9450 BUCK ENMODE bits */
+#define BUCK_ENMODE_OFF 0x00
+#define BUCK_ENMODE_ONREQ 0x01
+#define BUCK_ENMODE_ONREQ_STBYREQ 0x02
+#define BUCK_ENMODE_ON 0x03
+
+/* PCA9450_REG_BUCK1_CTRL bits */
+#define BUCK1_RAMP_MASK 0xC0
+#define BUCK1_RAMP_25MV 0x0
+#define BUCK1_RAMP_12P5MV 0x1
+#define BUCK1_RAMP_6P25MV 0x2
+#define BUCK1_RAMP_3P125MV 0x3
+#define BUCK1_DVS_CTRL 0x10
+#define BUCK1_AD 0x08
+#define BUCK1_FPWM 0x04
+#define BUCK1_ENMODE_MASK 0x03
+
+/* PCA9450_REG_BUCK2_CTRL bits */
+#define BUCK2_RAMP_MASK 0xC0
+#define BUCK2_RAMP_25MV 0x0
+#define BUCK2_RAMP_12P5MV 0x1
+#define BUCK2_RAMP_6P25MV 0x2
+#define BUCK2_RAMP_3P125MV 0x3
+#define BUCK2_DVS_CTRL 0x10
+#define BUCK2_AD 0x08
+#define BUCK2_FPWM 0x04
+#define BUCK2_ENMODE_MASK 0x03
+
+/* PCA9450_REG_BUCK3_CTRL bits */
+#define BUCK3_RAMP_MASK 0xC0
+#define BUCK3_RAMP_25MV 0x0
+#define BUCK3_RAMP_12P5MV 0x1
+#define BUCK3_RAMP_6P25MV 0x2
+#define BUCK3_RAMP_3P125MV 0x3
+#define BUCK3_DVS_CTRL 0x10
+#define BUCK3_AD 0x08
+#define BUCK3_FPWM 0x04
+#define BUCK3_ENMODE_MASK 0x03
+
+/* PCA9450_REG_BUCK4_CTRL bits */
+#define BUCK4_AD 0x08
+#define BUCK4_FPWM 0x04
+#define BUCK4_ENMODE_MASK 0x03
+
+/* PCA9450_REG_BUCK5_CTRL bits */
+#define BUCK5_AD 0x08
+#define BUCK5_FPWM 0x04
+#define BUCK5_ENMODE_MASK 0x03
+
+/* PCA9450_REG_BUCK6_CTRL bits */
+#define BUCK6_AD 0x08
+#define BUCK6_FPWM 0x04
+#define BUCK6_ENMODE_MASK 0x03
+
+/* PCA9450_BUCK1OUT_DVS0 bits */
+#define BUCK1OUT_DVS0_MASK 0x7F
+#define BUCK1OUT_DVS0_DEFAULT 0x14
+
+/* PCA9450_BUCK1OUT_DVS1 bits */
+#define BUCK1OUT_DVS1_MASK 0x7F
+#define BUCK1OUT_DVS1_DEFAULT 0x14
+
+/* PCA9450_BUCK2OUT_DVS0 bits */
+#define BUCK2OUT_DVS0_MASK 0x7F
+#define BUCK2OUT_DVS0_DEFAULT 0x14
+
+/* PCA9450_BUCK2OUT_DVS1 bits */
+#define BUCK2OUT_DVS1_MASK 0x7F
+#define BUCK2OUT_DVS1_DEFAULT 0x14
+
+/* PCA9450_BUCK3OUT_DVS0 bits */
+#define BUCK3OUT_DVS0_MASK 0x7F
+#define BUCK3OUT_DVS0_DEFAULT 0x14
+
+/* PCA9450_BUCK3OUT_DVS1 bits */
+#define BUCK3OUT_DVS1_MASK 0x7F
+#define BUCK3OUT_DVS1_DEFAULT 0x14
+
+/* PCA9450_REG_BUCK4OUT bits */
+#define BUCK4OUT_MASK 0x7F
+#define BUCK4OUT_DEFAULT 0x6C
+
+/* PCA9450_REG_BUCK5OUT bits */
+#define BUCK5OUT_MASK 0x7F
+#define BUCK5OUT_DEFAULT 0x30
+
+/* PCA9450_REG_BUCK6OUT bits */
+#define BUCK6OUT_MASK 0x7F
+#define BUCK6OUT_DEFAULT 0x14
+
+/* PCA9450_REG_LDO1_VOLT bits */
+#define LDO1_EN_MASK 0xC0
+#define LDO1OUT_MASK 0x07
+
+/* PCA9450_REG_LDO2_VOLT bits */
+#define LDO2_EN_MASK 0xC0
+#define LDO2OUT_MASK 0x07
+
+/* PCA9450_REG_LDO3_VOLT bits */
+#define LDO3_EN_MASK 0xC0
+#define LDO3OUT_MASK 0x0F
+
+/* PCA9450_REG_LDO4_VOLT bits */
+#define LDO4_EN_MASK 0xC0
+#define LDO4OUT_MASK 0x0F
+
+/* PCA9450_REG_LDO5_VOLT bits */
+#define LDO5L_EN_MASK 0xC0
+#define LDO5LOUT_MASK 0x0F
+
+#define LDO5H_EN_MASK 0xC0
+#define LDO5HOUT_MASK 0x0F
+
+/* PCA9450_REG_IRQ bits */
+#define IRQ_PWRON 0x80
+#define IRQ_WDOGB 0x40
+#define IRQ_RSVD 0x20
+#define IRQ_VR_FLT1 0x10
+#define IRQ_VR_FLT2 0x08
+#define IRQ_LOWVSYS 0x04
+#define IRQ_THERM_105 0x02
+#define IRQ_THERM_125 0x01
+
+#endif /* __LINUX_REG_PCA9450_H__ */
--
2.7.4

2020-07-06 08:03:39

by Frieder Schrempf

[permalink] [raw]
Subject: Re: [PATCH v2 1/4] regulator: pca9450: add pca9450 pmic driver

On 03.07.20 18:19, Robin Gong wrote:
> Add NXP pca9450 pmic driver.
>
> Signed-off-by: Robin Gong <[email protected]>

Reviewed-by: Frieder Schrempf <[email protected]>

> ---
> drivers/regulator/Kconfig | 8 +
> drivers/regulator/Makefile | 1 +
> drivers/regulator/pca9450-regulator.c | 843 ++++++++++++++++++++++++++++++++++
> include/linux/regulator/pca9450.h | 219 +++++++++
> 4 files changed, 1071 insertions(+)
> create mode 100644 drivers/regulator/pca9450-regulator.c
> create mode 100644 include/linux/regulator/pca9450.h
>
> diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
> index f60eeaa..f992a17 100644
> --- a/drivers/regulator/Kconfig
> +++ b/drivers/regulator/Kconfig
> @@ -740,6 +740,14 @@ config REGULATOR_PBIAS
> This driver provides support for OMAP pbias modelled
> regulators.
>
> +config REGULATOR_PCA9450
> + tristate "NXP PCA9450A/PCA9450B/PCA9450C regulator driver"
> + depends on I2C
> + select REGMAP_I2C
> + help
> + Say y here to support the NXP PCA9450A/PCA9450B/PCA9450C PMIC
> + regulator driver.
> +
> config REGULATOR_PCAP
> tristate "Motorola PCAP2 regulator driver"
> depends on EZX_PCAP
> diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
> index 5ce7350..ff524922 100644
> --- a/drivers/regulator/Makefile
> +++ b/drivers/regulator/Makefile
> @@ -94,6 +94,7 @@ obj-$(CONFIG_REGULATOR_QCOM_RPMH) += qcom-rpmh-regulator.o
> obj-$(CONFIG_REGULATOR_QCOM_SMD_RPM) += qcom_smd-regulator.o
> obj-$(CONFIG_REGULATOR_QCOM_SPMI) += qcom_spmi-regulator.o
> obj-$(CONFIG_REGULATOR_PALMAS) += palmas-regulator.o
> +obj-$(CONFIG_REGULATOR_PCA9450) += pca9450-regulator.o
> obj-$(CONFIG_REGULATOR_PFUZE100) += pfuze100-regulator.o
> obj-$(CONFIG_REGULATOR_PV88060) += pv88060-regulator.o
> obj-$(CONFIG_REGULATOR_PV88080) += pv88080-regulator.o
> diff --git a/drivers/regulator/pca9450-regulator.c b/drivers/regulator/pca9450-regulator.c
> new file mode 100644
> index 00000000..0225045
> --- /dev/null
> +++ b/drivers/regulator/pca9450-regulator.c
> @@ -0,0 +1,843 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright 2020 NXP.
> + * NXP PCA9450 pmic driver
> + */
> +
> +#include <linux/err.h>
> +#include <linux/i2c.h>
> +#include <linux/interrupt.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/of_device.h>
> +#include <linux/platform_device.h>
> +#include <linux/regulator/driver.h>
> +#include <linux/regulator/machine.h>
> +#include <linux/regulator/of_regulator.h>
> +#include <linux/regulator/pca9450.h>
> +
> +struct pc9450_dvs_config {
> + unsigned int run_reg; /* dvs0 */
> + unsigned int run_mask;
> + unsigned int standby_reg; /* dvs1 */
> + unsigned int standby_mask;
> +};
> +
> +struct pca9450_regulator_desc {
> + struct regulator_desc desc;
> + const struct pc9450_dvs_config dvs;
> +};
> +
> +struct pca9450 {
> + struct device *dev;
> + struct regmap *regmap;
> + enum pca9450_chip_type type;
> + unsigned int rcnt;
> + int irq;
> +};
> +
> +static const struct regmap_range pca9450_status_range = {
> + .range_min = PCA9450_REG_INT1,
> + .range_max = PCA9450_REG_PWRON_STAT,
> +};
> +
> +static const struct regmap_access_table pca9450_volatile_regs = {
> + .yes_ranges = &pca9450_status_range,
> + .n_yes_ranges = 1,
> +};
> +
> +static const struct regmap_config pca9450_regmap_config = {
> + .reg_bits = 8,
> + .val_bits = 8,
> + .volatile_table = &pca9450_volatile_regs,
> + .max_register = PCA9450_MAX_REGISTER - 1,
> + .cache_type = REGCACHE_RBTREE,
> +};
> +
> +/*
> + * BUCK1/2/3
> + * BUCK1RAM[1:0] BUCK1 DVS ramp rate setting
> + * 00: 25mV/1usec
> + * 01: 25mV/2usec
> + * 10: 25mV/4usec
> + * 11: 25mV/8usec
> + */
> +static int pca9450_dvs_set_ramp_delay(struct regulator_dev *rdev,
> + int ramp_delay)
> +{
> + int id = rdev_get_id(rdev);
> + unsigned int ramp_value;
> +
> + switch (ramp_delay) {
> + case 1 ... 3125:
> + ramp_value = BUCK1_RAMP_3P125MV;
> + break;
> + case 3126 ... 6250:
> + ramp_value = BUCK1_RAMP_6P25MV;
> + break;
> + case 6251 ... 12500:
> + ramp_value = BUCK1_RAMP_12P5MV;
> + break;
> + case 12501 ... 25000:
> + ramp_value = BUCK1_RAMP_25MV;
> + break;
> + default:
> + ramp_value = BUCK1_RAMP_25MV;
> + }
> +
> + return regmap_update_bits(rdev->regmap, PCA9450_REG_BUCK1CTRL + id * 3,
> + BUCK1_RAMP_MASK, ramp_value << 6);
> +}
> +
> +static struct regulator_ops pca9450_dvs_buck_regulator_ops = {
> + .enable = regulator_enable_regmap,
> + .disable = regulator_disable_regmap,
> + .is_enabled = regulator_is_enabled_regmap,
> + .list_voltage = regulator_list_voltage_linear_range,
> + .set_voltage_sel = regulator_set_voltage_sel_regmap,
> + .get_voltage_sel = regulator_get_voltage_sel_regmap,
> + .set_voltage_time_sel = regulator_set_voltage_time_sel,
> + .set_ramp_delay = pca9450_dvs_set_ramp_delay,
> +};
> +
> +static struct regulator_ops pca9450_buck_regulator_ops = {
> + .enable = regulator_enable_regmap,
> + .disable = regulator_disable_regmap,
> + .is_enabled = regulator_is_enabled_regmap,
> + .list_voltage = regulator_list_voltage_linear_range,
> + .set_voltage_sel = regulator_set_voltage_sel_regmap,
> + .get_voltage_sel = regulator_get_voltage_sel_regmap,
> + .set_voltage_time_sel = regulator_set_voltage_time_sel,
> +};
> +
> +static struct regulator_ops pca9450_ldo_regulator_ops = {
> + .enable = regulator_enable_regmap,
> + .disable = regulator_disable_regmap,
> + .is_enabled = regulator_is_enabled_regmap,
> + .list_voltage = regulator_list_voltage_linear_range,
> + .set_voltage_sel = regulator_set_voltage_sel_regmap,
> + .get_voltage_sel = regulator_get_voltage_sel_regmap,
> +};
> +
> +/*
> + * BUCK1/2/3
> + * 0.60 to 2.1875V (12.5mV step)
> + */
> +static const struct linear_range pca9450_dvs_buck_volts[] = {
> + REGULATOR_LINEAR_RANGE(600000, 0x00, 0x7F, 12500),
> +};
> +
> +/*
> + * BUCK4/5/6
> + * 0.6V to 3.4V (25mV step)
> + */
> +static const struct linear_range pca9450_buck_volts[] = {
> + REGULATOR_LINEAR_RANGE(600000, 0x00, 0x70, 25000),
> + REGULATOR_LINEAR_RANGE(3400000, 0x71, 0x7F, 0),
> +};
> +
> +/*
> + * LDO1
> + * 1.6 to 3.3V ()
> + */
> +static const struct linear_range pca9450_ldo1_volts[] = {
> + REGULATOR_LINEAR_RANGE(1600000, 0x00, 0x03, 100000),
> + REGULATOR_LINEAR_RANGE(3000000, 0x04, 0x07, 100000),
> +};
> +
> +/*
> + * LDO2
> + * 0.8 to 1.15V (50mV step)
> + */
> +static const struct linear_range pca9450_ldo2_volts[] = {
> + REGULATOR_LINEAR_RANGE(800000, 0x00, 0x07, 50000),
> +};
> +
> +/*
> + * LDO3/4
> + * 0.8 to 3.3V (100mV step)
> + */
> +static const struct linear_range pca9450_ldo34_volts[] = {
> + REGULATOR_LINEAR_RANGE(800000, 0x00, 0x19, 100000),
> + REGULATOR_LINEAR_RANGE(3300000, 0x1A, 0x1F, 0),
> +};
> +
> +/*
> + * LDO5
> + * 1.8 to 3.3V (100mV step)
> + */
> +static const struct linear_range pca9450_ldo5_volts[] = {
> + REGULATOR_LINEAR_RANGE(1800000, 0x00, 0x0F, 100000),
> +};
> +
> +static int buck_set_dvs(const struct regulator_desc *desc,
> + struct device_node *np, struct regmap *regmap,
> + char *prop, unsigned int reg, unsigned int mask)
> +{
> + int ret, i;
> + uint32_t uv;
> +
> + ret = of_property_read_u32(np, prop, &uv);
> + if (ret == -EINVAL)
> + return 0;
> + else if (ret)
> + return ret;
> +
> + for (i = 0; i < desc->n_voltages; i++) {
> + ret = regulator_desc_list_voltage_linear_range(desc, i);
> + if (ret < 0)
> + continue;
> + if (ret == uv) {
> + i <<= ffs(desc->vsel_mask) - 1;
> + ret = regmap_update_bits(regmap, reg, mask, i);
> + break;
> + }
> + }
> +
> + return ret;
> +}
> +
> +static int pca9450_set_dvs_levels(struct device_node *np,
> + const struct regulator_desc *desc,
> + struct regulator_config *cfg)
> +{
> + struct pca9450_regulator_desc *data = container_of(desc,
> + struct pca9450_regulator_desc, desc);
> + const struct pc9450_dvs_config *dvs = &data->dvs;
> + unsigned int reg, mask;
> + char *prop;
> + int i, ret = 0;
> +
> + for (i = 0; i < PCA9450_DVS_LEVEL_MAX; i++) {
> + switch (i) {
> + case PCA9450_DVS_LEVEL_RUN:
> + prop = "nxp,dvs-run-voltage";
> + reg = dvs->run_reg;
> + mask = dvs->run_mask;
> + break;
> + case PCA9450_DVS_LEVEL_STANDBY:
> + prop = "nxp,dvs-standby-voltage";
> + reg = dvs->standby_reg;
> + mask = dvs->standby_mask;
> + break;
> + default:
> + return -EINVAL;
> + }
> +
> + ret = buck_set_dvs(desc, np, cfg->regmap, prop, reg, mask);
> + if (ret)
> + break;
> + }
> +
> + return ret;
> +}
> +
> +static const struct pca9450_regulator_desc pca9450a_regulators[] = {
> + {
> + .desc = {
> + .name = "buck1",
> + .of_match = of_match_ptr("BUCK1"),
> + .regulators_node = of_match_ptr("regulators"),
> + .id = PCA9450_BUCK1,
> + .ops = &pca9450_dvs_buck_regulator_ops,
> + .type = REGULATOR_VOLTAGE,
> + .n_voltages = PCA9450_BUCK1_VOLTAGE_NUM,
> + .linear_ranges = pca9450_dvs_buck_volts,
> + .n_linear_ranges = ARRAY_SIZE(pca9450_dvs_buck_volts),
> + .vsel_reg = PCA9450_REG_BUCK1OUT_DVS0,
> + .vsel_mask = BUCK1OUT_DVS0_MASK,
> + .enable_reg = PCA9450_REG_BUCK1CTRL,
> + .enable_mask = BUCK1_ENMODE_MASK,
> + .owner = THIS_MODULE,
> + .of_parse_cb = pca9450_set_dvs_levels,
> + },
> + .dvs = {
> + .run_reg = PCA9450_REG_BUCK1OUT_DVS0,
> + .run_mask = BUCK1OUT_DVS0_MASK,
> + .standby_reg = PCA9450_REG_BUCK1OUT_DVS1,
> + .standby_mask = BUCK1OUT_DVS1_MASK,
> + },
> + },
> + {
> + .desc = {
> + .name = "buck2",
> + .of_match = of_match_ptr("BUCK2"),
> + .regulators_node = of_match_ptr("regulators"),
> + .id = PCA9450_BUCK2,
> + .ops = &pca9450_dvs_buck_regulator_ops,
> + .type = REGULATOR_VOLTAGE,
> + .n_voltages = PCA9450_BUCK2_VOLTAGE_NUM,
> + .linear_ranges = pca9450_dvs_buck_volts,
> + .n_linear_ranges = ARRAY_SIZE(pca9450_dvs_buck_volts),
> + .vsel_reg = PCA9450_REG_BUCK2OUT_DVS0,
> + .vsel_mask = BUCK2OUT_DVS0_MASK,
> + .enable_reg = PCA9450_REG_BUCK2CTRL,
> + .enable_mask = BUCK1_ENMODE_MASK,
> + .owner = THIS_MODULE,
> + .of_parse_cb = pca9450_set_dvs_levels,
> + },
> + .dvs = {
> + .run_reg = PCA9450_REG_BUCK2OUT_DVS0,
> + .run_mask = BUCK2OUT_DVS0_MASK,
> + .standby_reg = PCA9450_REG_BUCK2OUT_DVS1,
> + .standby_mask = BUCK2OUT_DVS1_MASK,
> + },
> + },
> + {
> + .desc = {
> + .name = "buck3",
> + .of_match = of_match_ptr("BUCK3"),
> + .regulators_node = of_match_ptr("regulators"),
> + .id = PCA9450_BUCK3,
> + .ops = &pca9450_dvs_buck_regulator_ops,
> + .type = REGULATOR_VOLTAGE,
> + .n_voltages = PCA9450_BUCK3_VOLTAGE_NUM,
> + .linear_ranges = pca9450_dvs_buck_volts,
> + .n_linear_ranges = ARRAY_SIZE(pca9450_dvs_buck_volts),
> + .vsel_reg = PCA9450_REG_BUCK3OUT_DVS0,
> + .vsel_mask = BUCK3OUT_DVS0_MASK,
> + .enable_reg = PCA9450_REG_BUCK3CTRL,
> + .enable_mask = BUCK3_ENMODE_MASK,
> + .owner = THIS_MODULE,
> + .of_parse_cb = pca9450_set_dvs_levels,
> + },
> + .dvs = {
> + .run_reg = PCA9450_REG_BUCK3OUT_DVS0,
> + .run_mask = BUCK3OUT_DVS0_MASK,
> + .standby_reg = PCA9450_REG_BUCK3OUT_DVS1,
> + .standby_mask = BUCK3OUT_DVS1_MASK,
> + },
> + },
> + {
> + .desc = {
> + .name = "buck4",
> + .of_match = of_match_ptr("BUCK4"),
> + .regulators_node = of_match_ptr("regulators"),
> + .id = PCA9450_BUCK4,
> + .ops = &pca9450_buck_regulator_ops,
> + .type = REGULATOR_VOLTAGE,
> + .n_voltages = PCA9450_BUCK4_VOLTAGE_NUM,
> + .linear_ranges = pca9450_buck_volts,
> + .n_linear_ranges = ARRAY_SIZE(pca9450_buck_volts),
> + .vsel_reg = PCA9450_REG_BUCK4OUT,
> + .vsel_mask = BUCK4OUT_MASK,
> + .enable_reg = PCA9450_REG_BUCK4CTRL,
> + .enable_mask = BUCK4_ENMODE_MASK,
> + .owner = THIS_MODULE,
> + },
> + },
> + {
> + .desc = {
> + .name = "buck5",
> + .of_match = of_match_ptr("BUCK5"),
> + .regulators_node = of_match_ptr("regulators"),
> + .id = PCA9450_BUCK5,
> + .ops = &pca9450_buck_regulator_ops,
> + .type = REGULATOR_VOLTAGE,
> + .n_voltages = PCA9450_BUCK5_VOLTAGE_NUM,
> + .linear_ranges = pca9450_buck_volts,
> + .n_linear_ranges = ARRAY_SIZE(pca9450_buck_volts),
> + .vsel_reg = PCA9450_REG_BUCK5OUT,
> + .vsel_mask = BUCK5OUT_MASK,
> + .enable_reg = PCA9450_REG_BUCK5CTRL,
> + .enable_mask = BUCK5_ENMODE_MASK,
> + .owner = THIS_MODULE,
> + },
> + },
> + {
> + .desc = {
> + .name = "buck6",
> + .of_match = of_match_ptr("BUCK6"),
> + .regulators_node = of_match_ptr("regulators"),
> + .id = PCA9450_BUCK6,
> + .ops = &pca9450_buck_regulator_ops,
> + .type = REGULATOR_VOLTAGE,
> + .n_voltages = PCA9450_BUCK6_VOLTAGE_NUM,
> + .linear_ranges = pca9450_buck_volts,
> + .n_linear_ranges = ARRAY_SIZE(pca9450_buck_volts),
> + .vsel_reg = PCA9450_REG_BUCK6OUT,
> + .vsel_mask = BUCK6OUT_MASK,
> + .enable_reg = PCA9450_REG_BUCK6CTRL,
> + .enable_mask = BUCK6_ENMODE_MASK,
> + .owner = THIS_MODULE,
> + },
> + },
> + {
> + .desc = {
> + .name = "ldo1",
> + .of_match = of_match_ptr("LDO1"),
> + .regulators_node = of_match_ptr("regulators"),
> + .id = PCA9450_LDO1,
> + .ops = &pca9450_ldo_regulator_ops,
> + .type = REGULATOR_VOLTAGE,
> + .n_voltages = PCA9450_LDO1_VOLTAGE_NUM,
> + .linear_ranges = pca9450_ldo1_volts,
> + .n_linear_ranges = ARRAY_SIZE(pca9450_ldo1_volts),
> + .vsel_reg = PCA9450_REG_LDO1CTRL,
> + .vsel_mask = LDO1OUT_MASK,
> + .enable_reg = PCA9450_REG_LDO1CTRL,
> + .enable_mask = LDO1_EN_MASK,
> + .owner = THIS_MODULE,
> + },
> + },
> + {
> + .desc = {
> + .name = "ldo2",
> + .of_match = of_match_ptr("LDO2"),
> + .regulators_node = of_match_ptr("regulators"),
> + .id = PCA9450_LDO2,
> + .ops = &pca9450_ldo_regulator_ops,
> + .type = REGULATOR_VOLTAGE,
> + .n_voltages = PCA9450_LDO2_VOLTAGE_NUM,
> + .linear_ranges = pca9450_ldo2_volts,
> + .n_linear_ranges = ARRAY_SIZE(pca9450_ldo2_volts),
> + .vsel_reg = PCA9450_REG_LDO2CTRL,
> + .vsel_mask = LDO2OUT_MASK,
> + .enable_reg = PCA9450_REG_LDO2CTRL,
> + .enable_mask = LDO2_EN_MASK,
> + .owner = THIS_MODULE,
> + },
> + },
> + {
> + .desc = {
> + .name = "ldo3",
> + .of_match = of_match_ptr("LDO3"),
> + .regulators_node = of_match_ptr("regulators"),
> + .id = PCA9450_LDO3,
> + .ops = &pca9450_ldo_regulator_ops,
> + .type = REGULATOR_VOLTAGE,
> + .n_voltages = PCA9450_LDO3_VOLTAGE_NUM,
> + .linear_ranges = pca9450_ldo34_volts,
> + .n_linear_ranges = ARRAY_SIZE(pca9450_ldo34_volts),
> + .vsel_reg = PCA9450_REG_LDO3CTRL,
> + .vsel_mask = LDO3OUT_MASK,
> + .enable_reg = PCA9450_REG_LDO3CTRL,
> + .enable_mask = LDO3_EN_MASK,
> + .owner = THIS_MODULE,
> + },
> + },
> + {
> + .desc = {
> + .name = "ldo4",
> + .of_match = of_match_ptr("LDO4"),
> + .regulators_node = of_match_ptr("regulators"),
> + .id = PCA9450_LDO4,
> + .ops = &pca9450_ldo_regulator_ops,
> + .type = REGULATOR_VOLTAGE,
> + .n_voltages = PCA9450_LDO4_VOLTAGE_NUM,
> + .linear_ranges = pca9450_ldo34_volts,
> + .n_linear_ranges = ARRAY_SIZE(pca9450_ldo34_volts),
> + .vsel_reg = PCA9450_REG_LDO4CTRL,
> + .vsel_mask = LDO4OUT_MASK,
> + .enable_reg = PCA9450_REG_LDO4CTRL,
> + .enable_mask = LDO4_EN_MASK,
> + .owner = THIS_MODULE,
> + },
> + },
> + {
> + .desc = {
> + .name = "ldo5",
> + .of_match = of_match_ptr("LDO5"),
> + .regulators_node = of_match_ptr("regulators"),
> + .id = PCA9450_LDO5,
> + .ops = &pca9450_ldo_regulator_ops,
> + .type = REGULATOR_VOLTAGE,
> + .n_voltages = PCA9450_LDO5_VOLTAGE_NUM,
> + .linear_ranges = pca9450_ldo5_volts,
> + .n_linear_ranges = ARRAY_SIZE(pca9450_ldo5_volts),
> + .vsel_reg = PCA9450_REG_LDO5CTRL_H,
> + .vsel_mask = LDO5HOUT_MASK,
> + .enable_reg = PCA9450_REG_LDO5CTRL_H,
> + .enable_mask = LDO5H_EN_MASK,
> + .owner = THIS_MODULE,
> + },
> + },
> +};
> +
> +/*
> + * Buck3 removed on PCA9450B and connected with Buck1 internal for dual phase
> + * on PCA9450C as no Buck3.
> + */
> +static const struct pca9450_regulator_desc pca9450bc_regulators[] = {
> + {
> + .desc = {
> + .name = "buck1",
> + .of_match = of_match_ptr("BUCK1"),
> + .regulators_node = of_match_ptr("regulators"),
> + .id = PCA9450_BUCK1,
> + .ops = &pca9450_dvs_buck_regulator_ops,
> + .type = REGULATOR_VOLTAGE,
> + .n_voltages = PCA9450_BUCK1_VOLTAGE_NUM,
> + .linear_ranges = pca9450_dvs_buck_volts,
> + .n_linear_ranges = ARRAY_SIZE(pca9450_dvs_buck_volts),
> + .vsel_reg = PCA9450_REG_BUCK1OUT_DVS0,
> + .vsel_mask = BUCK1OUT_DVS0_MASK,
> + .enable_reg = PCA9450_REG_BUCK1CTRL,
> + .enable_mask = BUCK1_ENMODE_MASK,
> + .owner = THIS_MODULE,
> + .of_parse_cb = pca9450_set_dvs_levels,
> + },
> + .dvs = {
> + .run_reg = PCA9450_REG_BUCK1OUT_DVS0,
> + .run_mask = BUCK1OUT_DVS0_MASK,
> + .standby_reg = PCA9450_REG_BUCK1OUT_DVS1,
> + .standby_mask = BUCK1OUT_DVS1_MASK,
> + },
> + },
> + {
> + .desc = {
> + .name = "buck2",
> + .of_match = of_match_ptr("BUCK2"),
> + .regulators_node = of_match_ptr("regulators"),
> + .id = PCA9450_BUCK2,
> + .ops = &pca9450_dvs_buck_regulator_ops,
> + .type = REGULATOR_VOLTAGE,
> + .n_voltages = PCA9450_BUCK2_VOLTAGE_NUM,
> + .linear_ranges = pca9450_dvs_buck_volts,
> + .n_linear_ranges = ARRAY_SIZE(pca9450_dvs_buck_volts),
> + .vsel_reg = PCA9450_REG_BUCK2OUT_DVS0,
> + .vsel_mask = BUCK2OUT_DVS0_MASK,
> + .enable_reg = PCA9450_REG_BUCK2CTRL,
> + .enable_mask = BUCK1_ENMODE_MASK,
> + .owner = THIS_MODULE,
> + .of_parse_cb = pca9450_set_dvs_levels,
> + },
> + .dvs = {
> + .run_reg = PCA9450_REG_BUCK2OUT_DVS0,
> + .run_mask = BUCK2OUT_DVS0_MASK,
> + .standby_reg = PCA9450_REG_BUCK2OUT_DVS1,
> + .standby_mask = BUCK2OUT_DVS1_MASK,
> + },
> + },
> + {
> + .desc = {
> + .name = "buck4",
> + .of_match = of_match_ptr("BUCK4"),
> + .regulators_node = of_match_ptr("regulators"),
> + .id = PCA9450_BUCK4,
> + .ops = &pca9450_buck_regulator_ops,
> + .type = REGULATOR_VOLTAGE,
> + .n_voltages = PCA9450_BUCK4_VOLTAGE_NUM,
> + .linear_ranges = pca9450_buck_volts,
> + .n_linear_ranges = ARRAY_SIZE(pca9450_buck_volts),
> + .vsel_reg = PCA9450_REG_BUCK4OUT,
> + .vsel_mask = BUCK4OUT_MASK,
> + .enable_reg = PCA9450_REG_BUCK4CTRL,
> + .enable_mask = BUCK4_ENMODE_MASK,
> + .owner = THIS_MODULE,
> + },
> + },
> + {
> + .desc = {
> + .name = "buck5",
> + .of_match = of_match_ptr("BUCK5"),
> + .regulators_node = of_match_ptr("regulators"),
> + .id = PCA9450_BUCK5,
> + .ops = &pca9450_buck_regulator_ops,
> + .type = REGULATOR_VOLTAGE,
> + .n_voltages = PCA9450_BUCK5_VOLTAGE_NUM,
> + .linear_ranges = pca9450_buck_volts,
> + .n_linear_ranges = ARRAY_SIZE(pca9450_buck_volts),
> + .vsel_reg = PCA9450_REG_BUCK5OUT,
> + .vsel_mask = BUCK5OUT_MASK,
> + .enable_reg = PCA9450_REG_BUCK5CTRL,
> + .enable_mask = BUCK5_ENMODE_MASK,
> + .owner = THIS_MODULE,
> + },
> + },
> + {
> + .desc = {
> + .name = "buck6",
> + .of_match = of_match_ptr("BUCK6"),
> + .regulators_node = of_match_ptr("regulators"),
> + .id = PCA9450_BUCK6,
> + .ops = &pca9450_buck_regulator_ops,
> + .type = REGULATOR_VOLTAGE,
> + .n_voltages = PCA9450_BUCK6_VOLTAGE_NUM,
> + .linear_ranges = pca9450_buck_volts,
> + .n_linear_ranges = ARRAY_SIZE(pca9450_buck_volts),
> + .vsel_reg = PCA9450_REG_BUCK6OUT,
> + .vsel_mask = BUCK6OUT_MASK,
> + .enable_reg = PCA9450_REG_BUCK6CTRL,
> + .enable_mask = BUCK6_ENMODE_MASK,
> + .owner = THIS_MODULE,
> + },
> + },
> + {
> + .desc = {
> + .name = "ldo1",
> + .of_match = of_match_ptr("LDO1"),
> + .regulators_node = of_match_ptr("regulators"),
> + .id = PCA9450_LDO1,
> + .ops = &pca9450_ldo_regulator_ops,
> + .type = REGULATOR_VOLTAGE,
> + .n_voltages = PCA9450_LDO1_VOLTAGE_NUM,
> + .linear_ranges = pca9450_ldo1_volts,
> + .n_linear_ranges = ARRAY_SIZE(pca9450_ldo1_volts),
> + .vsel_reg = PCA9450_REG_LDO1CTRL,
> + .vsel_mask = LDO1OUT_MASK,
> + .enable_reg = PCA9450_REG_LDO1CTRL,
> + .enable_mask = LDO1_EN_MASK,
> + .owner = THIS_MODULE,
> + },
> + },
> + {
> + .desc = {
> + .name = "ldo2",
> + .of_match = of_match_ptr("LDO2"),
> + .regulators_node = of_match_ptr("regulators"),
> + .id = PCA9450_LDO2,
> + .ops = &pca9450_ldo_regulator_ops,
> + .type = REGULATOR_VOLTAGE,
> + .n_voltages = PCA9450_LDO2_VOLTAGE_NUM,
> + .linear_ranges = pca9450_ldo2_volts,
> + .n_linear_ranges = ARRAY_SIZE(pca9450_ldo2_volts),
> + .vsel_reg = PCA9450_REG_LDO2CTRL,
> + .vsel_mask = LDO2OUT_MASK,
> + .enable_reg = PCA9450_REG_LDO2CTRL,
> + .enable_mask = LDO2_EN_MASK,
> + .owner = THIS_MODULE,
> + },
> + },
> + {
> + .desc = {
> + .name = "ldo3",
> + .of_match = of_match_ptr("LDO3"),
> + .regulators_node = of_match_ptr("regulators"),
> + .id = PCA9450_LDO3,
> + .ops = &pca9450_ldo_regulator_ops,
> + .type = REGULATOR_VOLTAGE,
> + .n_voltages = PCA9450_LDO3_VOLTAGE_NUM,
> + .linear_ranges = pca9450_ldo34_volts,
> + .n_linear_ranges = ARRAY_SIZE(pca9450_ldo34_volts),
> + .vsel_reg = PCA9450_REG_LDO3CTRL,
> + .vsel_mask = LDO3OUT_MASK,
> + .enable_reg = PCA9450_REG_LDO3CTRL,
> + .enable_mask = LDO3_EN_MASK,
> + .owner = THIS_MODULE,
> + },
> + },
> + {
> + .desc = {
> + .name = "ldo4",
> + .of_match = of_match_ptr("LDO4"),
> + .regulators_node = of_match_ptr("regulators"),
> + .id = PCA9450_LDO4,
> + .ops = &pca9450_ldo_regulator_ops,
> + .type = REGULATOR_VOLTAGE,
> + .n_voltages = PCA9450_LDO4_VOLTAGE_NUM,
> + .linear_ranges = pca9450_ldo34_volts,
> + .n_linear_ranges = ARRAY_SIZE(pca9450_ldo34_volts),
> + .vsel_reg = PCA9450_REG_LDO4CTRL,
> + .vsel_mask = LDO4OUT_MASK,
> + .enable_reg = PCA9450_REG_LDO4CTRL,
> + .enable_mask = LDO4_EN_MASK,
> + .owner = THIS_MODULE,
> + },
> + },
> + {
> + .desc = {
> + .name = "ldo5",
> + .of_match = of_match_ptr("LDO5"),
> + .regulators_node = of_match_ptr("regulators"),
> + .id = PCA9450_LDO5,
> + .ops = &pca9450_ldo_regulator_ops,
> + .type = REGULATOR_VOLTAGE,
> + .n_voltages = PCA9450_LDO5_VOLTAGE_NUM,
> + .linear_ranges = pca9450_ldo5_volts,
> + .n_linear_ranges = ARRAY_SIZE(pca9450_ldo5_volts),
> + .vsel_reg = PCA9450_REG_LDO5CTRL_H,
> + .vsel_mask = LDO5HOUT_MASK,
> + .enable_reg = PCA9450_REG_LDO5CTRL_H,
> + .enable_mask = LDO5H_EN_MASK,
> + .owner = THIS_MODULE,
> + },
> + },
> +};
> +
> +static irqreturn_t pca9450_irq_handler(int irq, void *data)
> +{
> + struct pca9450 *pca9450 = data;
> + struct regmap *regmap = pca9450->regmap;
> + unsigned int status;
> + int ret;
> +
> + ret = regmap_read(regmap, PCA9450_REG_INT1, &status);
> + if (ret < 0) {
> + dev_err(pca9450->dev,
> + "Failed to read INT1(%d)\n", ret);
> + return IRQ_NONE;
> + }
> +
> + if (status & IRQ_PWRON)
> + dev_warn(pca9450->dev, "PWRON interrupt.\n");
> +
> + if (status & IRQ_WDOGB)
> + dev_warn(pca9450->dev, "WDOGB interrupt.\n");
> +
> + if (status & IRQ_VR_FLT1)
> + dev_warn(pca9450->dev, "VRFLT1 interrupt.\n");
> +
> + if (status & IRQ_VR_FLT2)
> + dev_warn(pca9450->dev, "VRFLT2 interrupt.\n");
> +
> + if (status & IRQ_LOWVSYS)
> + dev_warn(pca9450->dev, "LOWVSYS interrupt.\n");
> +
> + if (status & IRQ_THERM_105)
> + dev_warn(pca9450->dev, "IRQ_THERM_105 interrupt.\n");
> +
> + if (status & IRQ_THERM_125)
> + dev_warn(pca9450->dev, "IRQ_THERM_125 interrupt.\n");
> +
> + return IRQ_HANDLED;
> +}
> +
> +static int pca9450_i2c_probe(struct i2c_client *i2c,
> + const struct i2c_device_id *id)
> +{
> + enum pca9450_chip_type type = (unsigned int)(uintptr_t)
> + of_device_get_match_data(&i2c->dev);
> + const struct pca9450_regulator_desc *regulator_desc;
> + struct regulator_config config = { };
> + struct pca9450 *pca9450;
> + unsigned int device_id, i;
> + int ret;
> +
> + if (!i2c->irq) {
> + dev_err(&i2c->dev, "No IRQ configured?\n");
> + return -EINVAL;
> + }
> +
> + pca9450 = devm_kzalloc(&i2c->dev, sizeof(struct pca9450), GFP_KERNEL);
> + if (!pca9450)
> + return -ENOMEM;
> +
> + switch (type) {
> + case PCA9450_TYPE_PCA9450A:
> + regulator_desc = pca9450a_regulators;
> + pca9450->rcnt = ARRAY_SIZE(pca9450a_regulators);
> + break;
> + case PCA9450_TYPE_PCA9450BC:
> + regulator_desc = pca9450bc_regulators;
> + pca9450->rcnt = ARRAY_SIZE(pca9450bc_regulators);
> + break;
> + default:
> + dev_err(&i2c->dev, "Unknown device type");
> + return -EINVAL;
> + }
> +
> + pca9450->irq = i2c->irq;
> + pca9450->type = type;
> + pca9450->dev = &i2c->dev;
> +
> + dev_set_drvdata(&i2c->dev, pca9450);
> +
> + pca9450->regmap = devm_regmap_init_i2c(i2c,
> + &pca9450_regmap_config);
> + if (IS_ERR(pca9450->regmap)) {
> + dev_err(&i2c->dev, "regmap initialization failed\n");
> + return PTR_ERR(pca9450->regmap);
> + }
> +
> + ret = regmap_read(pca9450->regmap, PCA9450_REG_DEV_ID, &device_id);
> + if (ret) {
> + dev_err(&i2c->dev, "Read device id error\n");
> + return ret;
> + }
> +
> + /* Check your board and dts for match the right pmic */
> + if (((device_id >> 4) != 0x1 && type == PCA9450_TYPE_PCA9450A) ||
> + ((device_id >> 4) != 0x3 && type == PCA9450_TYPE_PCA9450BC)) {
> + dev_err(&i2c->dev, "Device id(%x) mismatched\n",
> + device_id >> 4);
> + return -EINVAL;
> + }
> +
> + for (i = 0; i < pca9450->rcnt; i++) {
> + const struct regulator_desc *desc;
> + struct regulator_dev *rdev;
> + const struct pca9450_regulator_desc *r;
> +
> + r = &regulator_desc[i];
> + desc = &r->desc;
> +
> + config.regmap = pca9450->regmap;
> + config.dev = pca9450->dev;
> +
> + rdev = devm_regulator_register(pca9450->dev, desc, &config);
> + if (IS_ERR(rdev)) {
> + ret = PTR_ERR(rdev);
> + dev_err(pca9450->dev,
> + "Failed to register regulator(%s): %d\n",
> + desc->name, ret);
> + return ret;
> + }
> + }
> +
> + ret = devm_request_threaded_irq(pca9450->dev, pca9450->irq, NULL,
> + pca9450_irq_handler,
> + (IRQF_TRIGGER_FALLING | IRQF_ONESHOT),
> + "pca9450-irq", pca9450);
> + if (ret != 0) {
> + dev_err(pca9450->dev, "Failed to request IRQ: %d\n",
> + pca9450->irq);
> + return ret;
> + }
> + /* Unmask all interrupt except PWRON/WDOG/RSVD */
> + ret = regmap_update_bits(pca9450->regmap, PCA9450_REG_INT1_MSK,
> + IRQ_VR_FLT1 | IRQ_VR_FLT2 | IRQ_LOWVSYS |
> + IRQ_THERM_105 | IRQ_THERM_125,
> + IRQ_PWRON | IRQ_WDOGB | IRQ_RSVD);
> + if (ret) {
> + dev_err(&i2c->dev, "Unmask irq error\n");
> + return ret;
> + }
> +
> + dev_info(&i2c->dev, "%s probed.\n",
> + type == PCA9450_TYPE_PCA9450A ? "pca9450a" : "pca9450bc");
> +
> + return 0;
> +}
> +
> +static const struct of_device_id pca9450_of_match[] = {
> + {
> + .compatible = "nxp,pca9450a",
> + .data = (void *)PCA9450_TYPE_PCA9450A,
> + },
> + {
> + .compatible = "nxp,pca9450b",
> + .data = (void *)PCA9450_TYPE_PCA9450BC,
> + },
> + {
> + .compatible = "nxp,pca9450c",
> + .data = (void *)PCA9450_TYPE_PCA9450BC,
> + },
> + { }
> +};
> +MODULE_DEVICE_TABLE(of, pca9450_of_match);
> +
> +static struct i2c_driver pca9450_i2c_driver = {
> + .driver = {
> + .name = "nxp-pca9450",
> + .of_match_table = pca9450_of_match,
> + },
> + .probe = pca9450_i2c_probe,
> +};
> +
> +static int __init pca9450_i2c_init(void)
> +{
> + return i2c_add_driver(&pca9450_i2c_driver);
> +}
> +module_init(pca9450_i2c_init);
> +
> +static void __exit pca9450_i2c_exit(void)
> +{
> + i2c_del_driver(&pca9450_i2c_driver);
> +}
> +module_exit(pca9450_i2c_exit);
> +
> +MODULE_AUTHOR("Robin Gong <[email protected]>");
> +MODULE_DESCRIPTION("NXP PCA9450 Power Management IC driver");
> +MODULE_LICENSE("GPL");
> diff --git a/include/linux/regulator/pca9450.h b/include/linux/regulator/pca9450.h
> new file mode 100644
> index 00000000..1bbd301
> --- /dev/null
> +++ b/include/linux/regulator/pca9450.h
> @@ -0,0 +1,219 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +/* Copyright 2020 NXP. */
> +
> +#ifndef __LINUX_REG_PCA9450_H__
> +#define __LINUX_REG_PCA9450_H__
> +
> +#include <linux/regmap.h>
> +
> +enum pca9450_chip_type {
> + PCA9450_TYPE_PCA9450A = 0,
> + PCA9450_TYPE_PCA9450BC,
> + PCA9450_TYPE_AMOUNT,
> +};
> +
> +enum {
> + PCA9450_BUCK1 = 0,
> + PCA9450_BUCK2,
> + PCA9450_BUCK3,
> + PCA9450_BUCK4,
> + PCA9450_BUCK5,
> + PCA9450_BUCK6,
> + PCA9450_LDO1,
> + PCA9450_LDO2,
> + PCA9450_LDO3,
> + PCA9450_LDO4,
> + PCA9450_LDO5,
> + PCA9450_REGULATOR_CNT,
> +};
> +
> +enum {
> + PCA9450_DVS_LEVEL_RUN = 0,
> + PCA9450_DVS_LEVEL_STANDBY,
> + PCA9450_DVS_LEVEL_MAX,
> +};
> +
> +#define PCA9450_BUCK1_VOLTAGE_NUM 0x80
> +#define PCA9450_BUCK2_VOLTAGE_NUM 0x80
> +#define PCA9450_BUCK3_VOLTAGE_NUM 0x80
> +#define PCA9450_BUCK4_VOLTAGE_NUM 0x80
> +
> +#define PCA9450_BUCK5_VOLTAGE_NUM 0x80
> +#define PCA9450_BUCK6_VOLTAGE_NUM 0x80
> +
> +#define PCA9450_LDO1_VOLTAGE_NUM 0x08
> +#define PCA9450_LDO2_VOLTAGE_NUM 0x08
> +#define PCA9450_LDO3_VOLTAGE_NUM 0x20
> +#define PCA9450_LDO4_VOLTAGE_NUM 0x20
> +#define PCA9450_LDO5_VOLTAGE_NUM 0x10
> +
> +enum {
> + PCA9450_REG_DEV_ID = 0x00,
> + PCA9450_REG_INT1 = 0x01,
> + PCA9450_REG_INT1_MSK = 0x02,
> + PCA9450_REG_STATUS1 = 0x03,
> + PCA9450_REG_STATUS2 = 0x04,
> + PCA9450_REG_PWRON_STAT = 0x05,
> + PCA9450_REG_SWRST = 0x06,
> + PCA9450_REG_PWRCTRL = 0x07,
> + PCA9450_REG_RESET_CTRL = 0x08,
> + PCA9450_REG_CONFIG1 = 0x09,
> + PCA9450_REG_CONFIG2 = 0x0A,
> + PCA9450_REG_BUCK123_DVS = 0x0C,
> + PCA9450_REG_BUCK1OUT_LIMIT = 0x0D,
> + PCA9450_REG_BUCK2OUT_LIMIT = 0x0E,
> + PCA9450_REG_BUCK3OUT_LIMIT = 0x0F,
> + PCA9450_REG_BUCK1CTRL = 0x10,
> + PCA9450_REG_BUCK1OUT_DVS0 = 0x11,
> + PCA9450_REG_BUCK1OUT_DVS1 = 0x12,
> + PCA9450_REG_BUCK2CTRL = 0x13,
> + PCA9450_REG_BUCK2OUT_DVS0 = 0x14,
> + PCA9450_REG_BUCK2OUT_DVS1 = 0x15,
> + PCA9450_REG_BUCK3CTRL = 0x16,
> + PCA9450_REG_BUCK3OUT_DVS0 = 0x17,
> + PCA9450_REG_BUCK3OUT_DVS1 = 0x18,
> + PCA9450_REG_BUCK4CTRL = 0x19,
> + PCA9450_REG_BUCK4OUT = 0x1A,
> + PCA9450_REG_BUCK5CTRL = 0x1B,
> + PCA9450_REG_BUCK5OUT = 0x1C,
> + PCA9450_REG_BUCK6CTRL = 0x1D,
> + PCA9450_REG_BUCK6OUT = 0x1E,
> + PCA9450_REG_LDO_AD_CTRL = 0x20,
> + PCA9450_REG_LDO1CTRL = 0x21,
> + PCA9450_REG_LDO2CTRL = 0x22,
> + PCA9450_REG_LDO3CTRL = 0x23,
> + PCA9450_REG_LDO4CTRL = 0x24,
> + PCA9450_REG_LDO5CTRL_L = 0x25,
> + PCA9450_REG_LDO5CTRL_H = 0x26,
> + PCA9450_REG_LOADSW_CTRL = 0x2A,
> + PCA9450_REG_VRFLT1_STS = 0x2B,
> + PCA9450_REG_VRFLT2_STS = 0x2C,
> + PCA9450_REG_VRFLT1_MASK = 0x2D,
> + PCA9450_REG_VRFLT2_MASK = 0x2E,
> + PCA9450_MAX_REGISTER = 0x2F,
> +};
> +
> +/* PCA9450 BUCK ENMODE bits */
> +#define BUCK_ENMODE_OFF 0x00
> +#define BUCK_ENMODE_ONREQ 0x01
> +#define BUCK_ENMODE_ONREQ_STBYREQ 0x02
> +#define BUCK_ENMODE_ON 0x03
> +
> +/* PCA9450_REG_BUCK1_CTRL bits */
> +#define BUCK1_RAMP_MASK 0xC0
> +#define BUCK1_RAMP_25MV 0x0
> +#define BUCK1_RAMP_12P5MV 0x1
> +#define BUCK1_RAMP_6P25MV 0x2
> +#define BUCK1_RAMP_3P125MV 0x3
> +#define BUCK1_DVS_CTRL 0x10
> +#define BUCK1_AD 0x08
> +#define BUCK1_FPWM 0x04
> +#define BUCK1_ENMODE_MASK 0x03
> +
> +/* PCA9450_REG_BUCK2_CTRL bits */
> +#define BUCK2_RAMP_MASK 0xC0
> +#define BUCK2_RAMP_25MV 0x0
> +#define BUCK2_RAMP_12P5MV 0x1
> +#define BUCK2_RAMP_6P25MV 0x2
> +#define BUCK2_RAMP_3P125MV 0x3
> +#define BUCK2_DVS_CTRL 0x10
> +#define BUCK2_AD 0x08
> +#define BUCK2_FPWM 0x04
> +#define BUCK2_ENMODE_MASK 0x03
> +
> +/* PCA9450_REG_BUCK3_CTRL bits */
> +#define BUCK3_RAMP_MASK 0xC0
> +#define BUCK3_RAMP_25MV 0x0
> +#define BUCK3_RAMP_12P5MV 0x1
> +#define BUCK3_RAMP_6P25MV 0x2
> +#define BUCK3_RAMP_3P125MV 0x3
> +#define BUCK3_DVS_CTRL 0x10
> +#define BUCK3_AD 0x08
> +#define BUCK3_FPWM 0x04
> +#define BUCK3_ENMODE_MASK 0x03
> +
> +/* PCA9450_REG_BUCK4_CTRL bits */
> +#define BUCK4_AD 0x08
> +#define BUCK4_FPWM 0x04
> +#define BUCK4_ENMODE_MASK 0x03
> +
> +/* PCA9450_REG_BUCK5_CTRL bits */
> +#define BUCK5_AD 0x08
> +#define BUCK5_FPWM 0x04
> +#define BUCK5_ENMODE_MASK 0x03
> +
> +/* PCA9450_REG_BUCK6_CTRL bits */
> +#define BUCK6_AD 0x08
> +#define BUCK6_FPWM 0x04
> +#define BUCK6_ENMODE_MASK 0x03
> +
> +/* PCA9450_BUCK1OUT_DVS0 bits */
> +#define BUCK1OUT_DVS0_MASK 0x7F
> +#define BUCK1OUT_DVS0_DEFAULT 0x14
> +
> +/* PCA9450_BUCK1OUT_DVS1 bits */
> +#define BUCK1OUT_DVS1_MASK 0x7F
> +#define BUCK1OUT_DVS1_DEFAULT 0x14
> +
> +/* PCA9450_BUCK2OUT_DVS0 bits */
> +#define BUCK2OUT_DVS0_MASK 0x7F
> +#define BUCK2OUT_DVS0_DEFAULT 0x14
> +
> +/* PCA9450_BUCK2OUT_DVS1 bits */
> +#define BUCK2OUT_DVS1_MASK 0x7F
> +#define BUCK2OUT_DVS1_DEFAULT 0x14
> +
> +/* PCA9450_BUCK3OUT_DVS0 bits */
> +#define BUCK3OUT_DVS0_MASK 0x7F
> +#define BUCK3OUT_DVS0_DEFAULT 0x14
> +
> +/* PCA9450_BUCK3OUT_DVS1 bits */
> +#define BUCK3OUT_DVS1_MASK 0x7F
> +#define BUCK3OUT_DVS1_DEFAULT 0x14
> +
> +/* PCA9450_REG_BUCK4OUT bits */
> +#define BUCK4OUT_MASK 0x7F
> +#define BUCK4OUT_DEFAULT 0x6C
> +
> +/* PCA9450_REG_BUCK5OUT bits */
> +#define BUCK5OUT_MASK 0x7F
> +#define BUCK5OUT_DEFAULT 0x30
> +
> +/* PCA9450_REG_BUCK6OUT bits */
> +#define BUCK6OUT_MASK 0x7F
> +#define BUCK6OUT_DEFAULT 0x14
> +
> +/* PCA9450_REG_LDO1_VOLT bits */
> +#define LDO1_EN_MASK 0xC0
> +#define LDO1OUT_MASK 0x07
> +
> +/* PCA9450_REG_LDO2_VOLT bits */
> +#define LDO2_EN_MASK 0xC0
> +#define LDO2OUT_MASK 0x07
> +
> +/* PCA9450_REG_LDO3_VOLT bits */
> +#define LDO3_EN_MASK 0xC0
> +#define LDO3OUT_MASK 0x0F
> +
> +/* PCA9450_REG_LDO4_VOLT bits */
> +#define LDO4_EN_MASK 0xC0
> +#define LDO4OUT_MASK 0x0F
> +
> +/* PCA9450_REG_LDO5_VOLT bits */
> +#define LDO5L_EN_MASK 0xC0
> +#define LDO5LOUT_MASK 0x0F
> +
> +#define LDO5H_EN_MASK 0xC0
> +#define LDO5HOUT_MASK 0x0F
> +
> +/* PCA9450_REG_IRQ bits */
> +#define IRQ_PWRON 0x80
> +#define IRQ_WDOGB 0x40
> +#define IRQ_RSVD 0x20
> +#define IRQ_VR_FLT1 0x10
> +#define IRQ_VR_FLT2 0x08
> +#define IRQ_LOWVSYS 0x04
> +#define IRQ_THERM_105 0x02
> +#define IRQ_THERM_125 0x01
> +
> +#endif /* __LINUX_REG_PCA9450_H__ */
>

2020-07-06 14:45:15

by Mark Brown

[permalink] [raw]
Subject: Re: [PATCH v2 0/4] Add pca9450 driver

On Sat, 4 Jul 2020 00:19:34 +0800, Robin Gong wrote:
> Add pca9450 driver for i.mx8mn-evk board. PCA9450A/B/C supported now.
> Please refer to below link for PCA9450 datasheet:
> https://www.nxp.com/docs/en/data-sheet/PCA9450DS.pdf
>
> v2:
> 1. rebase with the latest code to use linear_ranges helper instead.
> 2. address Frieder's comments, such as dulipcated buck4 description,
> debug info added etc.
>
> [...]

Applied to

https://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator.git for-next

Thanks!

[1/2] regulator: pca9450: add pca9450 pmic driver
commit: 0935ff5f1f0a44f66a13e075ed49f97ad99d2fdc
[2/2] dt-bindings: regulator: add pca9450 regulator yaml
commit: 7ae9e3a6bf3fb1b5a35a15d8a6e78fc42bed0867

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark

2020-07-13 04:11:05

by Shawn Guo

[permalink] [raw]
Subject: Re: [PATCH v2 3/4] arm64: dts: imx8mn-evk: add pca9450 for i.mx8mn-evk board

On Sat, Jul 04, 2020 at 12:19:37AM +0800, Robin Gong wrote:
> Add pca9450 pmic driver for i.mx8mn-evk board.
>
> Signed-off-by: Robin Gong <[email protected]>

Applied, thanks.

2020-07-13 04:13:34

by Shawn Guo

[permalink] [raw]
Subject: Re: [PATCH v2 4/4] arm64: configs: add pca9450 pmic driver

On Sat, Jul 04, 2020 at 12:19:38AM +0800, Robin Gong wrote:
> Add pca9450 pmic driver.
>
> Signed-off-by: Robin Gong <[email protected]>

Updated subject prefix like 'arm64: defconfig: ...' and applied patch.

Shawn