[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20250731-b4-pf09-v2-v3-2-4c2659516582@nxp.com>
Date: Thu, 31 Jul 2025 18:44:42 +0800
From: Joy Zou <joy.zou@....com>
To: Liam Girdwood <lgirdwood@...il.com>, Mark Brown <broonie@...nel.org>,
Rob Herring <robh@...nel.org>, Krzysztof Kozlowski <krzk+dt@...nel.org>,
Conor Dooley <conor+dt@...nel.org>
Cc: linux-kernel@...r.kernel.org, devicetree@...r.kernel.org,
imx@...ts.linux.dev, Frank Li <Frank.Li@....com>, Joy Zou <joy.zou@....com>,
kernel test robot <lkp@...el.com>
Subject: [PATCH v3 2/2] regulator: pf0900: Add PMIC PF0900 support
The PF0900 is a power management integrated circuit (PMIC) optimized
for high performance i.MX9x based applications. It features five high
efficiency buck converters, three linear and one vaon regulators. It
provides low quiescent current in Standby and low power off Modes.
Reported-by: kernel test robot <lkp@...el.com>
Closes: https://lore.kernel.org/oe-kbuild-all/202507221720.jxsGRfcE-lkp@intel.com/
Closes: https://lore.kernel.org/oe-kbuild-all/202506181134.0Hkvy7CK-lkp@intel.com/
Signed-off-by: Joy Zou <joy.zou@....com>
---
Changes for v3:
1. convert to use maple tree register cache.
2. change of_match_ptr() name to lowercase since dt-binding changed.
3. remove the of_parse_cb and dvs from pf0900_regulators since the
unnecessary property nxp,dvs-run/standby-voltage removed.
4. add set_suspend_enable/disable/voltage for the SW regulator_ops.
the run/standby voltage can be adjusted via the API which regulator
driver provides is recommended.
These changes come from binding review comments:
https://lore.kernel.org/imx/e9f38e38-7df7-4d19-b5c0-2f18aeebcc78@kernel.org/
5. add bitfield.h header due to build issue.
6. correct the sw4 id.
7. add PF0900 prefix for shorter macro in order to avoid duplication.
8. merge the same mask in order to simplify code.
Changes for v2:
1. modify the copyright comment block to C++ style.
2. add reg_read/write for regmap_bus.
3. remove original pf0900_pmic_read/write.
4. remove many regulator operations.
5. use regmap_read replace pf0900_pmic_read.
6. use regmap_update_bits and regmap_write_bits replace pf0900_pmic_write.
7. move the code from pf0900.h to pf0900-regulator.c and delete the
header file.
8. remove unmask status interrupts and add unmask regulator interrupts.
9. remove many interrupts check warning print from irq_handler.
10. add notifier for regulator event.
11. remove unused macro define.
12. add PF0900 prefix for IRQ macro define in order to avoid duplication.
13. use GENMASK() and BIT() to replace mask marco define.
14. remove redundant enum pf0900_chip_type.
15. remove redundant print info and comments.
16. add dvs property present check because this property is optional.
17. remove ret == -EINVAL check from sw_set_dvs() function.
---
drivers/regulator/Kconfig | 8 +
drivers/regulator/Makefile | 1 +
drivers/regulator/pf0900-regulator.c | 975 +++++++++++++++++++++++++++++++++++
3 files changed, 984 insertions(+)
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index eaa6df1c9f806652a21942bcb48084ba63f942d9..b474b4bf63b37d374834067caf6166d8b093699b 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -1006,6 +1006,14 @@ config REGULATOR_PCAP
This driver provides support for the voltage regulators of the
PCAP2 PMIC.
+config REGULATOR_PF0900
+ tristate "NXP PF0900/PF0901/PF09XX regulator driver"
+ depends on I2C
+ select REGMAP_I2C
+ help
+ Say y here to support the NXP PF0900/PF0901/PF09XX PMIC
+ regulator driver.
+
config REGULATOR_PF8X00
tristate "NXP PF8100/PF8121A/PF8200 regulator driver"
depends on I2C && OF
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index be98b29d6675d8be1ca984c2d137bdfc4ba2de87..74b029d29a8b7faf79f3f82bb848eab65568753f 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -124,6 +124,7 @@ obj-$(CONFIG_REGULATOR_QCOM_SPMI) += qcom_spmi-regulator.o
obj-$(CONFIG_REGULATOR_QCOM_USB_VBUS) += qcom_usb_vbus-regulator.o
obj-$(CONFIG_REGULATOR_PALMAS) += palmas-regulator.o
obj-$(CONFIG_REGULATOR_PCA9450) += pca9450-regulator.o
+obj-$(CONFIG_REGULATOR_PF0900) += pf0900-regulator.o
obj-$(CONFIG_REGULATOR_PF9453) += pf9453-regulator.o
obj-$(CONFIG_REGULATOR_PF8X00) += pf8x00-regulator.o
obj-$(CONFIG_REGULATOR_PFUZE100) += pfuze100-regulator.o
diff --git a/drivers/regulator/pf0900-regulator.c b/drivers/regulator/pf0900-regulator.c
new file mode 100644
index 0000000000000000000000000000000000000000..b5effee3291724f95ba4c820f6518ee25d8a57e2
--- /dev/null
+++ b/drivers/regulator/pf0900-regulator.c
@@ -0,0 +1,975 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright 2025 NXP.
+// NXP PF0900 pmic driver
+
+#include <linux/bitfield.h>
+#include <linux/crc8.h>
+#include <linux/err.h>
+#include <linux/gpio/consumer.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/regmap.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
+
+enum pf0900_regulators {
+ PF0900_SW1 = 0,
+ PF0900_SW2,
+ PF0900_SW3,
+ PF0900_SW4,
+ PF0900_SW5,
+ PF0900_LDO1,
+ PF0900_LDO2,
+ PF0900_LDO3,
+ PF0900_VAON,
+ PF0900_REGULATOR_CNT,
+};
+
+enum {
+ PF0900_DVS_LEVEL_RUN = 0,
+ PF0900_DVS_LEVEL_STANDBY,
+ PF0900_DVS_LEVEL_MAX,
+};
+
+
+#define PF0900_VAON_VOLTAGE_NUM 0x03
+#define PF0900_SW_VOLTAGE_NUM 0x100
+#define PF0900_LDO_VOLTAGE_NUM 0x20
+
+#define REGU_SW_CNT 0x5
+#define REGU_LDO_VAON_CNT 0x4
+
+enum {
+ PF0900_REG_DEV_ID = 0x00,
+ PF0900_REG_DEV_FAM = 0x01,
+ PF0900_REG_REV_ID = 0x02,
+ PF0900_REG_PROG_ID1 = 0x03,
+ PF0900_REG_PROG_ID2 = 0x04,
+ PF0900_REG_SYSTEM_INT = 0x05,
+ PF0900_REG_STATUS1_INT = 0x06,
+ PF0900_REG_STATUS1_MSK = 0x07,
+ PF0900_REG_STATUS1_SNS = 0x08,
+ PF0900_REG_STATUS2_INT = 0x09,
+ PF0900_REG_STATUS2_MSK = 0x0A,
+ PF0900_REG_STATUS2_SNS = 0x0B,
+ PF0900_REG_STATUS3_INT = 0x0C,
+ PF0900_REG_STATUS3_MSK = 0x0D,
+ PF0900_REG_SW_MODE_INT = 0x0E,
+ PF0900_REG_SW_MODE_MSK = 0x0F,
+ PF0900_REG_SW_ILIM_INT = 0x10,
+ PF0900_REG_SW_ILIM_MSK = 0x11,
+ PF0900_REG_SW_ILIM_SNS = 0x12,
+ PF0900_REG_LDO_ILIM_INT = 0x13,
+ PF0900_REG_LDO_ILIM_MSK = 0x14,
+ PF0900_REG_LDO_ILIM_SNS = 0x15,
+ PF0900_REG_SW_UV_INT = 0x16,
+ PF0900_REG_SW_UV_MSK = 0x17,
+ PF0900_REG_SW_UV_SNS = 0x18,
+ PF0900_REG_SW_OV_INT = 0x19,
+ PF0900_REG_SW_OV_MSK = 0x1A,
+ PF0900_REG_SW_OV_SNS = 0x1B,
+ PF0900_REG_LDO_UV_INT = 0x1C,
+ PF0900_REG_LDO_UV_MSK = 0x1D,
+ PF0900_REG_LDO_UV_SNS = 0x1E,
+ PF0900_REG_LDO_OV_INT = 0x1F,
+ PF0900_REG_LDO_OV_MSK = 0x20,
+ PF0900_REG_LDO_OV_SNS = 0x21,
+ PF0900_REG_PWRON_INT = 0x22,
+ PF0900_REG_IO_INT = 0x24,
+ PF0900_REG_IO_MSK = 0x25,
+ PF0900_REG_IO_SNS = 0x26,
+ PF0900_REG_IOSHORT_SNS = 0x27,
+ PF0900_REG_ABIST_OV1 = 0x28,
+ PF0900_REG_ABIST_OV2 = 0x29,
+ PF0900_REG_ABIST_UV1 = 0x2A,
+ PF0900_REG_ABIST_UV2 = 0x2B,
+ PF0900_REG_ABIST_IO = 0x2C,
+ PF0900_REG_TEST_FLAGS = 0x2D,
+ PF0900_REG_HFAULT_FLAGS = 0x2E,
+ PF0900_REG_FAULT_FLAGS = 0x2F,
+ PF0900_REG_FS0B_CFG = 0x30,
+ PF0900_REG_FCCU_CFG = 0x31,
+ PF0900_REG_RSTB_CFG1 = 0x32,
+ PF0900_REG_SYSTEM_CMD = 0x33,
+ PF0900_REG_FS0B_CMD = 0x34,
+ PF0900_REG_SECURE_WR1 = 0x35,
+ PF0900_REG_SECURE_WR2 = 0x36,
+ PF0900_REG_VMON_CFG1 = 0x37,
+ PF0900_REG_SYS_CFG1 = 0x38,
+ PF0900_REG_GPO_CFG = 0x39,
+ PF0900_REG_GPO_CTRL = 0x3A,
+ PF0900_REG_PWRUP_CFG = 0x3B,
+ PF0900_REG_RSTB_PWRUP = 0x3C,
+ PF0900_REG_GPIO1_PWRUP = 0x3D,
+ PF0900_REG_GPIO2_PWRUP = 0x3E,
+ PF0900_REG_GPIO3_PWRUP = 0x3F,
+ PF0900_REG_GPIO4_PWRUP = 0x40,
+ PF0900_REG_VMON1_PWRUP = 0x41,
+ PF0900_REG_VMON2_PWRUP = 0x42,
+ PF0900_REG_SW1_PWRUP = 0x43,
+ PF0900_REG_SW2_PWRUP = 0x44,
+ PF0900_REG_SW3_PWRUP = 0x45,
+ PF0900_REG_SW4_PWRUP = 0x46,
+ PF0900_REG_SW5_PWRUP = 0x47,
+ PF0900_REG_LDO1_PWRUP = 0x48,
+ PF0900_REG_LDO2_PWRUP = 0x49,
+ PF0900_REG_LDO3_PWRUP = 0x4A,
+ PF0900_REG_VAON_PWRUP = 0x4B,
+ PF0900_REG_FREQ_CTRL = 0x4C,
+ PF0900_REG_PWRON_CFG = 0x4D,
+ PF0900_REG_WD_CTRL1 = 0x4E,
+ PF0900_REG_WD_CTRL2 = 0x4F,
+ PF0900_REG_WD_CFG1 = 0x50,
+ PF0900_REG_WD_CFG2 = 0x51,
+ PF0900_REG_WD_CNT1 = 0x52,
+ PF0900_REG_WD_CNT2 = 0x53,
+ PF0900_REG_FAULT_CFG = 0x54,
+ PF0900_REG_FAULT_CNT = 0x55,
+ PF0900_REG_DFS_CNT = 0x56,
+ PF0900_REG_AMUX_CFG = 0x57,
+ PF0900_REG_VMON1_RUN_CFG = 0x58,
+ PF0900_REG_VMON1_STBY_CFG = 0x59,
+ PF0900_REG_VMON1_CTRL = 0x5A,
+ PF0900_REG_VMON2_RUN_CFG = 0x5B,
+ PF0900_REG_VMON2_STBY_CFG = 0x5C,
+ PF0900_REG_VMON2_CTRL = 0x5D,
+ PF0900_REG_SW1_VRUN = 0x5E,
+ PF0900_REG_SW1_VSTBY = 0x5F,
+ PF0900_REG_SW1_MODE = 0x60,
+ PF0900_REG_SW1_CFG1 = 0x61,
+ PF0900_REG_SW1_CFG2 = 0x62,
+ PF0900_REG_SW2_VRUN = 0x63,
+ PF0900_REG_SW2_VSTBY = 0x64,
+ PF0900_REG_SW2_MODE = 0x65,
+ PF0900_REG_SW2_CFG1 = 0x66,
+ PF0900_REG_SW2_CFG2 = 0x67,
+ PF0900_REG_SW3_VRUN = 0x68,
+ PF0900_REG_SW3_VSTBY = 0x69,
+ PF0900_REG_SW3_MODE = 0x6A,
+ PF0900_REG_SW3_CFG1 = 0x6B,
+ PF0900_REG_SW3_CFG2 = 0x6C,
+ PF0900_REG_SW4_VRUN = 0x6D,
+ PF0900_REG_SW4_VSTBY = 0x6E,
+ PF0900_REG_SW4_MODE = 0x6F,
+ PF0900_REG_SW4_CFG1 = 0x70,
+ PF0900_REG_SW4_CFG2 = 0x71,
+ PF0900_REG_SW5_VRUN = 0x72,
+ PF0900_REG_SW5_VSTBY = 0x73,
+ PF0900_REG_SW5_MODE = 0x74,
+ PF0900_REG_SW5_CFG1 = 0x75,
+ PF0900_REG_SW5_CFG2 = 0x76,
+ PF0900_REG_LDO1_RUN = 0x77,
+ PF0900_REG_LDO1_STBY = 0x78,
+ PF0900_REG_LDO1_CFG2 = 0x79,
+ PF0900_REG_LDO2_RUN = 0x7A,
+ PF0900_REG_LDO2_STBY = 0x7B,
+ PF0900_REG_LDO2_CFG2 = 0x7C,
+ PF0900_REG_LDO3_RUN = 0x7D,
+ PF0900_REG_LDO3_STBY = 0x7E,
+ PF0900_REG_LDO3_CFG2 = 0x7F,
+ PF0900_REG_VAON_CFG1 = 0x80,
+ PF0900_REG_VAON_CFG2 = 0x81,
+ PF0900_REG_SYS_DIAG = 0x82,
+ PF0900_MAX_REGISTER,
+};
+
+/* PF0900 SW MODE */
+#define SW_RUN_MODE_OFF 0x00
+#define SW_RUN_MODE_PWM 0x01
+#define SW_RUN_MODE_PFM 0x02
+#define SW_STBY_MODE_OFF 0x00
+#define SW_STBY_MODE_PWM 0x04
+#define SW_STBY_MODE_PFM 0x08
+
+/* PF0900 SW MODE MASK */
+#define SW_RUN_MODE_MASK GENMASK(1, 0)
+#define SW_STBY_MODE_MASK GENMASK(3, 2)
+
+/* PF0900 SW VRUN/VSTBY MASK */
+#define PF0900_SW_VOL_MASK GENMASK(7, 0)
+
+/* PF0900_REG_VAON_CFG1 bits */
+#define PF0900_VAON_1P8V 0x01
+
+#define PF0900_VAON_MASK GENMASK(1, 0)
+
+/* PF0900_REG_SWX_CFG1 MASK */
+#define PF0900_SW_DVS_MASK GENMASK(4, 3)
+
+/* PF0900_REG_LDO_RUN MASK */
+#define VLDO_RUN_MASK GENMASK(4, 0)
+#define LDO_RUN_EN_MASK BIT(5)
+
+/* PF0900_REG_STATUS1_INT bits */
+#define PF0900_IRQ_PWRUP BIT(3)
+
+/* PF0900_REG_ILIM_INT bits */
+#define PF0900_IRQ_SW1_IL BIT(0)
+#define PF0900_IRQ_SW2_IL BIT(1)
+#define PF0900_IRQ_SW3_IL BIT(2)
+#define PF0900_IRQ_SW4_IL BIT(3)
+#define PF0900_IRQ_SW5_IL BIT(4)
+
+#define PF0900_IRQ_LDO1_IL BIT(0)
+#define PF0900_IRQ_LDO2_IL BIT(1)
+#define PF0900_IRQ_LDO3_IL BIT(2)
+
+/* PF0900_REG_UV_INT bits */
+#define PF0900_IRQ_SW1_UV BIT(0)
+#define PF0900_IRQ_SW2_UV BIT(1)
+#define PF0900_IRQ_SW3_UV BIT(2)
+#define PF0900_IRQ_SW4_UV BIT(3)
+#define PF0900_IRQ_SW5_UV BIT(4)
+
+#define PF0900_IRQ_LDO1_UV BIT(0)
+#define PF0900_IRQ_LDO2_UV BIT(1)
+#define PF0900_IRQ_LDO3_UV BIT(2)
+#define PF0900_IRQ_VAON_UV BIT(3)
+
+/* PF0900_REG_OV_INT bits */
+#define PF0900_IRQ_SW1_OV BIT(0)
+#define PF0900_IRQ_SW2_OV BIT(1)
+#define PF0900_IRQ_SW3_OV BIT(2)
+#define PF0900_IRQ_SW4_OV BIT(3)
+#define PF0900_IRQ_SW5_OV BIT(4)
+
+#define PF0900_IRQ_LDO1_OV BIT(0)
+#define PF0900_IRQ_LDO2_OV BIT(1)
+#define PF0900_IRQ_LDO3_OV BIT(2)
+#define PF0900_IRQ_VAON_OV BIT(3)
+
+struct pf0900_regulator_desc {
+ struct regulator_desc desc;
+ unsigned int suspend_enable_mask;
+ unsigned int suspend_voltage_reg;
+ unsigned int suspend_voltage_cache;
+};
+
+struct pf0900_drvdata {
+ const struct pf0900_regulator_desc *desc;
+ unsigned int rcnt;
+};
+
+struct pf0900 {
+ struct device *dev;
+ struct regmap *regmap;
+ const struct pf0900_drvdata *drvdata;
+ struct regulator_dev *rdevs[PF0900_REGULATOR_CNT];
+ int irq;
+ unsigned short addr;
+ bool crc_en;
+};
+
+enum pf0900_regulator_type {
+ PF0900_SW = 0,
+ PF0900_LDO,
+};
+
+#define PF0900_REGU_IRQ(_reg, _type, _event) \
+ { \
+ .reg = _reg, \
+ .type = _type, \
+ .event = _event, \
+ }
+
+struct pf0900_regulator_irq {
+ unsigned int reg;
+ unsigned int type;
+ unsigned int event;
+};
+
+static const struct regmap_range pf0900_range = {
+ .range_min = PF0900_REG_DEV_ID,
+ .range_max = PF0900_REG_SYS_DIAG,
+};
+
+static const struct regmap_access_table pf0900_volatile_regs = {
+ .yes_ranges = &pf0900_range,
+ .n_yes_ranges = 1,
+};
+
+static const struct regmap_config pf0900_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .volatile_table = &pf0900_volatile_regs,
+ .max_register = PF0900_MAX_REGISTER - 1,
+ .cache_type = REGCACHE_MAPLE,
+};
+
+static uint8_t crc8_j1850(unsigned short addr, unsigned int reg,
+ unsigned int val)
+{
+ uint8_t crcBuf[3];
+ uint8_t t_crc;
+ uint8_t i, j;
+
+ crcBuf[0] = addr;
+ crcBuf[1] = reg;
+ crcBuf[2] = val;
+ t_crc = 0xFF;
+
+ /*
+ * The CRC calculation is based on the standard CRC-8-SAE as
+ * defined in the SAE-J1850 specification with the following
+ * characteristics.
+ * Polynomial = 0x1D
+ * Initial Value = 0xFF
+ * The CRC byte is calculated by shifting 24-bit data through
+ * the CRC polynomial.The 24-bits package is built as follows:
+ * DEVICE_ADDR[b8] + REGISTER_ADDR [b8] +DATA[b8]
+ * The DEVICE_ADDR is calculated as the 7-bit slave address
+ * shifted left one space plus the corresponding read/write bit.
+ * (7Bit Address [b7] << 1 ) + R/W = DEVICE_ADDR[b8]
+ */
+ for (i = 0; i < sizeof(crcBuf); i++) {
+ t_crc ^= crcBuf[i];
+ for (j = 0; j < 8; j++) {
+ if ((t_crc & 0x80) != 0) {
+ t_crc <<= 1;
+ t_crc ^= 0x1D;
+ } else {
+ t_crc <<= 1;
+ }
+ }
+ }
+
+ return t_crc;
+}
+
+static int pf0900_regmap_read(void *context, unsigned int reg,
+ unsigned int *val)
+{
+ struct device *dev = context;
+ struct i2c_client *i2c = to_i2c_client(dev);
+ struct pf0900 *pf0900 = dev_get_drvdata(dev);
+ int ret;
+ u8 crc;
+
+ if (!pf0900 || !pf0900->dev)
+ return -EINVAL;
+
+ if (reg >= PF0900_MAX_REGISTER) {
+ dev_err(pf0900->dev, "Invalid register address: 0x%x\n", reg);
+ return -EINVAL;
+ }
+
+ if (pf0900->crc_en) {
+ ret = i2c_smbus_read_word_data(i2c, reg);
+ if (ret < 0) {
+ dev_err(pf0900->dev, "Read error at reg=0x%x: %d\n", reg, ret);
+ return ret;
+ }
+
+ *val = (u16)ret;
+ crc = crc8_j1850(pf0900->addr << 1 | 0x1, reg, FIELD_GET(GENMASK(7, 0), *val));
+ if (crc != FIELD_GET(GENMASK(15, 8), *val)) {
+ dev_err(pf0900->dev, "Crc check error!\n");
+ return -EINVAL;
+ }
+ *val = FIELD_GET(GENMASK(7, 0), *val);
+ } else {
+ ret = i2c_smbus_read_byte_data(i2c, reg);
+ if (ret < 0) {
+ dev_err(pf0900->dev, "Read error at reg=0x%x: %d\n", reg, ret);
+ return ret;
+ }
+ *val = ret;
+ }
+
+ return 0;
+}
+
+static int pf0900_regmap_write(void *context, unsigned int reg,
+ unsigned int val)
+{
+ struct device *dev = context;
+ struct i2c_client *i2c = to_i2c_client(dev);
+ struct pf0900 *pf0900 = dev_get_drvdata(dev);
+ uint8_t data[2];
+ int ret;
+
+ if (!pf0900 || !pf0900->dev)
+ return -EINVAL;
+
+ if (reg >= PF0900_MAX_REGISTER) {
+ dev_err(pf0900->dev, "Invalid register address: 0x%x\n", reg);
+ return -EINVAL;
+ }
+
+ data[0] = val;
+ if (pf0900->crc_en) {
+ /* Get CRC */
+ data[1] = crc8_j1850(pf0900->addr << 1, reg, data[0]);
+ val = FIELD_PREP(GENMASK(15, 8), data[1]) | data[0];
+ ret = i2c_smbus_write_word_data(i2c, reg, val);
+ } else {
+ ret = i2c_smbus_write_byte_data(i2c, reg, data[0]);
+ }
+
+ if (ret) {
+ dev_err(pf0900->dev, "Write reg=0x%x error!\n", reg);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int pf0900_suspend_enable(struct regulator_dev *rdev)
+{
+ struct pf0900_regulator_desc *rdata = rdev_get_drvdata(rdev);
+ struct regmap *rmap = rdev_get_regmap(rdev);
+
+ return regmap_update_bits(rmap, rdata->desc.enable_reg,
+ rdata->suspend_enable_mask, SW_STBY_MODE_PFM);
+}
+
+static int pf0900_suspend_disable(struct regulator_dev *rdev)
+{
+ struct pf0900_regulator_desc *rdata = rdev_get_drvdata(rdev);
+ struct regmap *rmap = rdev_get_regmap(rdev);
+
+ return regmap_update_bits(rmap, rdata->desc.enable_reg,
+ rdata->suspend_enable_mask, SW_STBY_MODE_OFF);
+}
+
+static int pf0900_set_suspend_voltage(struct regulator_dev *rdev, int uV)
+{
+ struct pf0900_regulator_desc *rdata = rdev_get_drvdata(rdev);
+ struct regmap *rmap = rdev_get_regmap(rdev);
+ int ret;
+
+ if (rdata->suspend_voltage_cache == uV)
+ return 0;
+
+ ret = regulator_map_voltage_iterate(rdev, uV, uV);
+ if (ret < 0) {
+ dev_err(rdev_get_dev(rdev), "failed to map %i uV\n", uV);
+ return ret;
+ }
+
+ dev_dbg(rdev_get_dev(rdev), "uV: %i, reg: 0x%x, msk: 0x%x, val: 0x%x\n",
+ uV, rdata->suspend_voltage_reg, rdata->desc.vsel_mask, ret);
+ ret = regmap_update_bits(rmap, rdata->suspend_voltage_reg,
+ rdata->desc.vsel_mask, ret);
+ if (ret < 0) {
+ dev_err(rdev_get_dev(rdev), "failed to set %i uV\n", uV);
+ return ret;
+ }
+
+ rdata->suspend_voltage_cache = uV;
+
+ return 0;
+}
+
+static const struct regmap_bus pf0900_regmap_bus = {
+ .reg_read = pf0900_regmap_read,
+ .reg_write = pf0900_regmap_write,
+};
+
+static const struct regulator_ops pf0900_avon_regulator_ops = {
+ .list_voltage = regulator_list_voltage_table,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+};
+
+static const struct regulator_ops pf0900_dvs_sw_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 = regulator_set_ramp_delay_regmap,
+ .set_suspend_enable = pf0900_suspend_enable,
+ .set_suspend_disable = pf0900_suspend_disable,
+ .set_suspend_voltage = pf0900_set_suspend_voltage,
+};
+
+static const struct regulator_ops pf0900_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,
+};
+
+/*
+ * SW1/2/3/4/5
+ * SW1_DVS[1:0] SW1 DVS ramp rate setting
+ * 00: 15.6mV/8usec
+ * 01: 15.6mV/4usec
+ * 10: 15.6mV/2usec
+ * 11: 15.6mV/1usec
+ */
+static const unsigned int pf0900_dvs_sw_ramp_table[] = {
+ 1950, 3900, 7800, 15600
+};
+
+/* VAON 1.8V, 3.0V, or 3.3V */
+static const int pf0900_vaon_voltages[] = {
+ 0, 1800000, 3000000, 3300000,
+};
+
+/*
+ * SW1 0.5V to 3.3V
+ * 0.5V to 1.35V (6.25mV step)
+ * 1.8V to 2.5V (125mV step)
+ * 2.8V to 3.3V (250mV step)
+ */
+static const struct linear_range pf0900_dvs_sw1_volts[] = {
+ REGULATOR_LINEAR_RANGE(0, 0x00, 0x08, 0),
+ REGULATOR_LINEAR_RANGE(500000, 0x09, 0x91, 6250),
+ REGULATOR_LINEAR_RANGE(0, 0x92, 0x9E, 0),
+ REGULATOR_LINEAR_RANGE(1500000, 0x9F, 0x9F, 0),
+ REGULATOR_LINEAR_RANGE(1800000, 0xA0, 0xD8, 12500),
+ REGULATOR_LINEAR_RANGE(0, 0xD9, 0xDF, 0),
+ REGULATOR_LINEAR_RANGE(2800000, 0xE0, 0xF4, 25000),
+ REGULATOR_LINEAR_RANGE(0, 0xF5, 0xFF, 0),
+};
+
+/*
+ * SW2/3/4/5 0.3V to 3.3V
+ * 0.45V to 1.35V (6.25mV step)
+ * 1.8V to 2.5V (125mV step)
+ * 2.8V to 3.3V (250mV step)
+ */
+static const struct linear_range pf0900_dvs_sw2345_volts[] = {
+ REGULATOR_LINEAR_RANGE(300000, 0x00, 0x00, 0),
+ REGULATOR_LINEAR_RANGE(450000, 0x01, 0x91, 6250),
+ REGULATOR_LINEAR_RANGE(0, 0x92, 0x9E, 0),
+ REGULATOR_LINEAR_RANGE(1500000, 0x9F, 0x9F, 0),
+ REGULATOR_LINEAR_RANGE(1800000, 0xA0, 0xD8, 12500),
+ REGULATOR_LINEAR_RANGE(0, 0xD9, 0xDF, 0),
+ REGULATOR_LINEAR_RANGE(2800000, 0xE0, 0xF4, 25000),
+ REGULATOR_LINEAR_RANGE(0, 0xF5, 0xFF, 0),
+};
+
+/*
+ * LDO1
+ * 0.75V to 3.3V
+ */
+static const struct linear_range pf0900_ldo1_volts[] = {
+ REGULATOR_LINEAR_RANGE(750000, 0x00, 0x0F, 50000),
+ REGULATOR_LINEAR_RANGE(1800000, 0x10, 0x1F, 100000),
+};
+
+/*
+ * LDO2/3
+ * 0.65V to 3.3V (50mV step)
+ */
+static const struct linear_range pf0900_ldo23_volts[] = {
+ REGULATOR_LINEAR_RANGE(650000, 0x00, 0x0D, 50000),
+ REGULATOR_LINEAR_RANGE(1400000, 0x0E, 0x0F, 100000),
+ REGULATOR_LINEAR_RANGE(1800000, 0x10, 0x1F, 100000),
+};
+
+static const struct pf0900_regulator_desc pf0900_regulators[] = {
+ {
+ .desc = {
+ .name = "sw1",
+ .of_match = of_match_ptr("sw1"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = PF0900_SW1,
+ .ops = &pf0900_dvs_sw_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = PF0900_SW_VOLTAGE_NUM,
+ .linear_ranges = pf0900_dvs_sw1_volts,
+ .n_linear_ranges = ARRAY_SIZE(pf0900_dvs_sw1_volts),
+ .vsel_reg = PF0900_REG_SW1_VRUN,
+ .vsel_mask = PF0900_SW_VOL_MASK,
+ .enable_reg = PF0900_REG_SW1_MODE,
+ .enable_mask = SW_RUN_MODE_MASK,
+ .enable_val = SW_RUN_MODE_PWM,
+ .ramp_reg = PF0900_REG_SW1_CFG1,
+ .ramp_mask = PF0900_SW_DVS_MASK,
+ .ramp_delay_table = pf0900_dvs_sw_ramp_table,
+ .n_ramp_values = ARRAY_SIZE(pf0900_dvs_sw_ramp_table),
+ .owner = THIS_MODULE,
+ },
+ .suspend_enable_mask = SW_STBY_MODE_MASK,
+ .suspend_voltage_reg = PF0900_REG_SW1_VSTBY,
+ },
+ {
+ .desc = {
+ .name = "sw2",
+ .of_match = of_match_ptr("sw2"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = PF0900_SW2,
+ .ops = &pf0900_dvs_sw_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = PF0900_SW_VOLTAGE_NUM,
+ .linear_ranges = pf0900_dvs_sw2345_volts,
+ .n_linear_ranges = ARRAY_SIZE(pf0900_dvs_sw2345_volts),
+ .vsel_reg = PF0900_REG_SW2_VRUN,
+ .vsel_mask = PF0900_SW_VOL_MASK,
+ .enable_reg = PF0900_REG_SW2_MODE,
+ .enable_mask = SW_RUN_MODE_MASK,
+ .enable_val = SW_RUN_MODE_PWM,
+ .ramp_reg = PF0900_REG_SW2_CFG1,
+ .ramp_mask = PF0900_SW_DVS_MASK,
+ .ramp_delay_table = pf0900_dvs_sw_ramp_table,
+ .n_ramp_values = ARRAY_SIZE(pf0900_dvs_sw_ramp_table),
+ .owner = THIS_MODULE,
+ },
+ .suspend_enable_mask = SW_STBY_MODE_MASK,
+ .suspend_voltage_reg = PF0900_REG_SW2_VSTBY,
+ },
+ {
+ .desc = {
+ .name = "sw3",
+ .of_match = of_match_ptr("sw3"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = PF0900_SW3,
+ .ops = &pf0900_dvs_sw_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = PF0900_SW_VOLTAGE_NUM,
+ .linear_ranges = pf0900_dvs_sw2345_volts,
+ .n_linear_ranges = ARRAY_SIZE(pf0900_dvs_sw2345_volts),
+ .vsel_reg = PF0900_REG_SW3_VRUN,
+ .vsel_mask = PF0900_SW_VOL_MASK,
+ .enable_reg = PF0900_REG_SW3_MODE,
+ .enable_mask = SW_RUN_MODE_MASK,
+ .enable_val = SW_RUN_MODE_PWM,
+ .ramp_reg = PF0900_REG_SW3_CFG1,
+ .ramp_mask = PF0900_SW_DVS_MASK,
+ .ramp_delay_table = pf0900_dvs_sw_ramp_table,
+ .n_ramp_values = ARRAY_SIZE(pf0900_dvs_sw_ramp_table),
+ .owner = THIS_MODULE,
+ },
+ .suspend_enable_mask = SW_STBY_MODE_MASK,
+ .suspend_voltage_reg = PF0900_REG_SW3_VSTBY,
+ },
+ {
+ .desc = {
+ .name = "sw4",
+ .of_match = of_match_ptr("sw4"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = PF0900_SW4,
+ .ops = &pf0900_dvs_sw_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = PF0900_SW_VOLTAGE_NUM,
+ .linear_ranges = pf0900_dvs_sw2345_volts,
+ .n_linear_ranges = ARRAY_SIZE(pf0900_dvs_sw2345_volts),
+ .vsel_reg = PF0900_REG_SW4_VRUN,
+ .vsel_mask = PF0900_SW_VOL_MASK,
+ .enable_reg = PF0900_REG_SW4_MODE,
+ .enable_mask = SW_RUN_MODE_MASK,
+ .enable_val = SW_RUN_MODE_PWM,
+ .ramp_reg = PF0900_REG_SW4_CFG1,
+ .ramp_mask = PF0900_SW_DVS_MASK,
+ .ramp_delay_table = pf0900_dvs_sw_ramp_table,
+ .n_ramp_values = ARRAY_SIZE(pf0900_dvs_sw_ramp_table),
+ .owner = THIS_MODULE,
+ },
+ .suspend_enable_mask = SW_STBY_MODE_MASK,
+ .suspend_voltage_reg = PF0900_REG_SW4_VSTBY,
+ },
+ {
+ .desc = {
+ .name = "sw5",
+ .of_match = of_match_ptr("sw5"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = PF0900_SW5,
+ .ops = &pf0900_dvs_sw_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = PF0900_SW_VOLTAGE_NUM,
+ .linear_ranges = pf0900_dvs_sw2345_volts,
+ .n_linear_ranges = ARRAY_SIZE(pf0900_dvs_sw2345_volts),
+ .vsel_reg = PF0900_REG_SW5_VRUN,
+ .vsel_mask = PF0900_SW_VOL_MASK,
+ .enable_reg = PF0900_REG_SW5_MODE,
+ .enable_mask = SW_RUN_MODE_MASK,
+ .enable_val = SW_RUN_MODE_PWM,
+ .ramp_reg = PF0900_REG_SW5_CFG1,
+ .ramp_mask = PF0900_SW_DVS_MASK,
+ .ramp_delay_table = pf0900_dvs_sw_ramp_table,
+ .n_ramp_values = ARRAY_SIZE(pf0900_dvs_sw_ramp_table),
+ .owner = THIS_MODULE,
+ },
+ .suspend_enable_mask = SW_STBY_MODE_MASK,
+ .suspend_voltage_reg = PF0900_REG_SW5_VSTBY,
+ },
+ {
+ .desc = {
+ .name = "ldo1",
+ .of_match = of_match_ptr("ldo1"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = PF0900_LDO1,
+ .ops = &pf0900_ldo_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = PF0900_LDO_VOLTAGE_NUM,
+ .linear_ranges = pf0900_ldo1_volts,
+ .n_linear_ranges = ARRAY_SIZE(pf0900_ldo1_volts),
+ .vsel_reg = PF0900_REG_LDO1_RUN,
+ .vsel_mask = VLDO_RUN_MASK,
+ .enable_reg = PF0900_REG_LDO1_RUN,
+ .enable_mask = LDO_RUN_EN_MASK,
+ .owner = THIS_MODULE,
+ },
+ },
+ {
+ .desc = {
+ .name = "ldo2",
+ .of_match = of_match_ptr("ldo2"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = PF0900_LDO2,
+ .ops = &pf0900_ldo_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = PF0900_LDO_VOLTAGE_NUM,
+ .linear_ranges = pf0900_ldo23_volts,
+ .n_linear_ranges = ARRAY_SIZE(pf0900_ldo23_volts),
+ .vsel_reg = PF0900_REG_LDO2_RUN,
+ .vsel_mask = VLDO_RUN_MASK,
+ .enable_reg = PF0900_REG_LDO2_RUN,
+ .enable_mask = LDO_RUN_EN_MASK,
+ .owner = THIS_MODULE,
+ },
+ },
+ {
+ .desc = {
+ .name = "ldo3",
+ .of_match = of_match_ptr("ldo3"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = PF0900_LDO3,
+ .ops = &pf0900_ldo_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = PF0900_LDO_VOLTAGE_NUM,
+ .linear_ranges = pf0900_ldo23_volts,
+ .n_linear_ranges = ARRAY_SIZE(pf0900_ldo23_volts),
+ .vsel_reg = PF0900_REG_LDO3_RUN,
+ .vsel_mask = VLDO_RUN_MASK,
+ .enable_reg = PF0900_REG_LDO3_RUN,
+ .enable_mask = LDO_RUN_EN_MASK,
+ .owner = THIS_MODULE,
+ },
+ },
+ {
+ .desc = {
+ .name = "vaon",
+ .of_match = of_match_ptr("vaon"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = PF0900_VAON,
+ .ops = &pf0900_avon_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = PF0900_VAON_VOLTAGE_NUM,
+ .volt_table = pf0900_vaon_voltages,
+ .enable_reg = PF0900_REG_VAON_CFG1,
+ .enable_mask = PF0900_VAON_MASK,
+ .enable_val = PF0900_VAON_1P8V,
+ .vsel_reg = PF0900_REG_VAON_CFG1,
+ .vsel_mask = PF0900_VAON_MASK,
+ .owner = THIS_MODULE,
+ },
+ },
+};
+
+struct pf0900_regulator_irq regu_irqs[] = {
+ PF0900_REGU_IRQ(PF0900_REG_SW_ILIM_INT, PF0900_SW, REGULATOR_ERROR_OVER_CURRENT_WARN),
+ PF0900_REGU_IRQ(PF0900_REG_LDO_ILIM_INT, PF0900_LDO, REGULATOR_ERROR_OVER_CURRENT_WARN),
+ PF0900_REGU_IRQ(PF0900_REG_SW_UV_INT, PF0900_SW, REGULATOR_ERROR_UNDER_VOLTAGE_WARN),
+ PF0900_REGU_IRQ(PF0900_REG_LDO_UV_INT, PF0900_LDO, REGULATOR_ERROR_UNDER_VOLTAGE_WARN),
+ PF0900_REGU_IRQ(PF0900_REG_SW_OV_INT, PF0900_SW, REGULATOR_ERROR_OVER_VOLTAGE_WARN),
+ PF0900_REGU_IRQ(PF0900_REG_LDO_OV_INT, PF0900_LDO, REGULATOR_ERROR_OVER_VOLTAGE_WARN),
+};
+
+static irqreturn_t pf0900_irq_handler(int irq, void *data)
+{
+ unsigned int val, regu, i, index;
+ struct pf0900 *pf0900 = data;
+ int ret;
+
+ for (i = 0; i < ARRAY_SIZE(regu_irqs); i++) {
+ ret = regmap_read(pf0900->regmap, regu_irqs[i].reg, &val);
+ if (ret < 0) {
+ dev_err(pf0900->dev, "Failed to read %d\n", ret);
+ return IRQ_NONE;
+ }
+ if (val) {
+ ret = regmap_write_bits(pf0900->regmap, regu_irqs[i].reg, val, val);
+ if (ret < 0) {
+ dev_err(pf0900->dev, "Failed to update %d\n", ret);
+ return IRQ_NONE;
+ }
+
+ if (regu_irqs[i].type == PF0900_SW) {
+ for (index = 0; index < REGU_SW_CNT; index++) {
+ if (val & BIT(index)) {
+ regu = (enum pf0900_regulators)index;
+ regulator_notifier_call_chain(pf0900->rdevs[regu],
+ regu_irqs[i].event,
+ NULL);
+ }
+ }
+ } else if (regu_irqs[i].type == PF0900_LDO) {
+ for (index = 0; index < REGU_LDO_VAON_CNT; index++) {
+ if (val & BIT(index)) {
+ regu = (enum pf0900_regulators)index + PF0900_LDO1;
+ regulator_notifier_call_chain(pf0900->rdevs[regu],
+ regu_irqs[i].event,
+ NULL);
+ }
+ }
+ }
+ }
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int pf0900_i2c_probe(struct i2c_client *i2c)
+{
+ const struct pf0900_regulator_desc *regulator_desc;
+ const struct pf0900_drvdata *drvdata = NULL;
+ struct device_node *np = i2c->dev.of_node;
+ unsigned int device_id, device_fam, i;
+ struct regulator_config config = { };
+ struct pf0900 *pf0900;
+ int ret;
+
+ if (!i2c->irq)
+ return dev_err_probe(&i2c->dev, -EINVAL, "No IRQ configured?\n");
+
+ pf0900 = devm_kzalloc(&i2c->dev, sizeof(struct pf0900), GFP_KERNEL);
+ if (!pf0900)
+ return -ENOMEM;
+
+ drvdata = device_get_match_data(&i2c->dev);
+ if (!drvdata)
+ return dev_err_probe(&i2c->dev, -EINVAL, "unable to find driver data\n");
+
+ regulator_desc = drvdata->desc;
+ pf0900->drvdata = drvdata;
+ pf0900->crc_en = of_property_read_bool(np, "nxp,i2c-crc-enable");
+ pf0900->irq = i2c->irq;
+ pf0900->dev = &i2c->dev;
+ pf0900->addr = i2c->addr;
+
+ dev_set_drvdata(&i2c->dev, pf0900);
+
+ pf0900->regmap = devm_regmap_init(&i2c->dev, &pf0900_regmap_bus, &i2c->dev,
+ &pf0900_regmap_config);
+ if (IS_ERR(pf0900->regmap))
+ return dev_err_probe(&i2c->dev, PTR_ERR(pf0900->regmap),
+ "regmap initialization failed\n");
+ ret = regmap_read(pf0900->regmap, PF0900_REG_DEV_ID, &device_id);
+ if (ret)
+ return dev_err_probe(&i2c->dev, ret, "Read device id error\n");
+
+ ret = regmap_read(pf0900->regmap, PF0900_REG_DEV_FAM, &device_fam);
+ if (ret)
+ return dev_err_probe(&i2c->dev, ret, "Read device fam error\n");
+
+ /* Check your board and dts for match the right pmic */
+ if (device_fam == 0x09 && (device_id & 0x1F) != 0x0)
+ return dev_err_probe(&i2c->dev, -EINVAL, "Device id(%x) mismatched\n",
+ device_id >> 4);
+
+ for (i = 0; i < drvdata->rcnt; i++) {
+ const struct regulator_desc *desc;
+ const struct pf0900_regulator_desc *r;
+
+ r = ®ulator_desc[i];
+ desc = &r->desc;
+ config.regmap = pf0900->regmap;
+ config.driver_data = (void *)r;
+ config.dev = pf0900->dev;
+
+ pf0900->rdevs[i] = devm_regulator_register(pf0900->dev, desc, &config);
+ if (IS_ERR(pf0900->rdevs[i]))
+ return dev_err_probe(pf0900->dev, PTR_ERR(pf0900->rdevs[i]),
+ "Failed to register regulator(%s)\n", desc->name);
+ }
+
+ ret = devm_request_threaded_irq(pf0900->dev, pf0900->irq, NULL,
+ pf0900_irq_handler,
+ (IRQF_TRIGGER_FALLING | IRQF_ONESHOT),
+ "pf0900-irq", pf0900);
+
+ if (ret != 0)
+ return dev_err_probe(pf0900->dev, ret, "Failed to request IRQ: %d\n",
+ pf0900->irq);
+ /*
+ * The PWRUP_M is unmasked by default. When the device enter in RUN state,
+ * it will assert the PWRUP_I interrupt and assert the INTB pin to inform
+ * the MCU that it has finished the power up sequence properly.
+ */
+ ret = regmap_write_bits(pf0900->regmap, PF0900_REG_STATUS1_INT, PF0900_IRQ_PWRUP,
+ PF0900_IRQ_PWRUP);
+ if (ret)
+ return dev_err_probe(&i2c->dev, ret, "Clean PWRUP_I error\n");
+
+ /* mask interrupt PWRUP */
+ ret = regmap_update_bits(pf0900->regmap, PF0900_REG_STATUS1_MSK, PF0900_IRQ_PWRUP,
+ PF0900_IRQ_PWRUP);
+ if (ret)
+ return dev_err_probe(&i2c->dev, ret, "Unmask irq error\n");
+
+ ret = regmap_update_bits(pf0900->regmap, PF0900_REG_SW_ILIM_MSK, PF0900_IRQ_SW1_IL |
+ PF0900_IRQ_SW2_IL | PF0900_IRQ_SW3_IL | PF0900_IRQ_SW4_IL |
+ PF0900_IRQ_SW5_IL, 0);
+ if (ret)
+ return dev_err_probe(&i2c->dev, ret, "Unmask irq error\n");
+
+ ret = regmap_update_bits(pf0900->regmap, PF0900_REG_SW_UV_MSK, PF0900_IRQ_SW1_UV |
+ PF0900_IRQ_SW2_UV | PF0900_IRQ_SW3_UV | PF0900_IRQ_SW4_UV |
+ PF0900_IRQ_SW5_UV, 0);
+ if (ret)
+ return dev_err_probe(&i2c->dev, ret, "Unmask irq error\n");
+
+ ret = regmap_update_bits(pf0900->regmap, PF0900_REG_SW_OV_MSK, PF0900_IRQ_SW1_OV |
+ PF0900_IRQ_SW2_OV | PF0900_IRQ_SW3_OV | PF0900_IRQ_SW4_OV |
+ PF0900_IRQ_SW5_OV, 0);
+ if (ret)
+ return dev_err_probe(&i2c->dev, ret, "Unmask irq error\n");
+
+ ret = regmap_update_bits(pf0900->regmap, PF0900_REG_LDO_ILIM_MSK, PF0900_IRQ_LDO1_IL |
+ PF0900_IRQ_LDO2_IL | PF0900_IRQ_LDO3_IL, 0);
+ if (ret)
+ return dev_err_probe(&i2c->dev, ret, "Unmask irq error\n");
+
+ ret = regmap_update_bits(pf0900->regmap, PF0900_REG_LDO_UV_MSK, PF0900_IRQ_LDO1_UV |
+ PF0900_IRQ_LDO2_UV | PF0900_IRQ_LDO3_UV | PF0900_IRQ_VAON_UV, 0);
+ if (ret)
+ return dev_err_probe(&i2c->dev, ret, "Unmask irq error\n");
+
+ ret = regmap_update_bits(pf0900->regmap, PF0900_REG_LDO_OV_MSK, PF0900_IRQ_LDO1_OV |
+ PF0900_IRQ_LDO2_OV | PF0900_IRQ_LDO3_OV | PF0900_IRQ_VAON_OV, 0);
+ if (ret)
+ return dev_err_probe(&i2c->dev, ret, "Unmask irq error\n");
+
+ return 0;
+}
+
+static struct pf0900_drvdata pf0900_drvdata = {
+ .desc = pf0900_regulators,
+ .rcnt = ARRAY_SIZE(pf0900_regulators),
+};
+
+static const struct of_device_id pf0900_of_match[] = {
+ { .compatible = "nxp,pf0900", .data = &pf0900_drvdata},
+ { }
+};
+
+MODULE_DEVICE_TABLE(of, pf0900_of_match);
+
+static struct i2c_driver pf0900_i2c_driver = {
+ .driver = {
+ .name = "nxp-pf0900",
+ .of_match_table = pf0900_of_match,
+ },
+ .probe = pf0900_i2c_probe,
+};
+
+module_i2c_driver(pf0900_i2c_driver);
+
+MODULE_AUTHOR("Joy Zou <joy.zou@....com>");
+MODULE_DESCRIPTION("NXP PF0900 Power Management IC driver");
+MODULE_LICENSE("GPL");
--
2.37.1
Powered by blists - more mailing lists