Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

regulator: add new PMIC PF0900 support

Merge series from Joy Zou <joy.zou@nxp.com>:

Add binding document and driver.

Signed-off-by: Joy Zou <joy.zou@nxp.com>
---
Changes in v3:

binding part
- change regulator node names into lowercase.
- add more description for nxp,i2c-crc-enable.
- remove the unnecessary nxp,dvs-run/standby-voltage property.
These changes come from review comments:
https://lore.kernel.org/imx/e9f38e38-7df7-4d19-b5c0-2f18aeebcc78@kernel.org/
- add regulator-state-mem property for example.

driver part
- convert to use maple tree register cache.
- change of_match_ptr() name to lowercase since dt-binding changed.
- add more nxp,i2c-crc-enable description for commit message.
- remove the of_parse_cb and dvs from pf0900_regulators since the
unnecessary property nxp,dvs-run/standby-voltage removed.
- 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/
- add bitfield.h header due to build issue.
- correct the sw4 id.
- add PF0900 prefix for short macro define in order to avoid duplication.
- merge the same mask define in order to simplify code.
- Link to v2: https://lore.kernel.org/r/20250721-b4-pf09-v2-v2-0-e2c568548032@nxp.com

Changes in v2:

binding part
- modify the binding file name to match compatible string.
- add one space for dt_binding_check warning.
- remove unnecessary quotes from "VAON".
- remove the unnecessary empty line.
- move unevaluatedProperties after the $ref.
- move additionalProperties after regulator type.
- remove unnecessary regulator description

driver part
- modify the copyright comment block to C++ style.
- add reg_read/write for regmap_bus.
- remove original pf0900_pmic_read/write.
- remove many regulator operations.
- use regmap_read replace pf0900_pmic_read.
- use regmap_update_bits and regmap_write_bits replace pf0900_pmic_write.
- move the code from pf0900.h to pf0900-regulator.c and delete the header file.
- remove unmask status interrupts and add unmask regulator interrupts.
- remove many interrupts check warning print from irq_handler.
- add notifier for regulator event.
- remove unused macro define.
- add PF0900 prefix for IRQ macro define in order to avoid duplication.
- use GENMASK() and BIT() to replace mask marco define
- remove redundant enum pf0900_chip_type.
- remove redundant print info and comments.
- add dvs property present check because this property is optional.
- remove ret == -EINVAL check from sw_set_dvs() function.
- Link to v1: https://lore.kernel.org/imx/20250617102025.3455544-1-joy.zou@nxp.com/

---
Joy Zou (2):
dt-bindings: regulator: add PF0900 regulator yaml
regulator: pf0900: Add PMIC PF0900 support

.../devicetree/bindings/regulator/nxp,pf0900.yaml | 163 ++++
drivers/regulator/Kconfig | 8 +
drivers/regulator/Makefile | 1 +
drivers/regulator/pf0900-regulator.c | 975 +++++++++++++++++++++
4 files changed, 1147 insertions(+)
---
base-commit: 84b92a499e7eca54ba1df6f6c6e01766025943f1
change-id: 20250714-b4-pf09-v2-91cdee6d1272

Best regards,
--
Joy Zou <joy.zou@nxp.com>

+1147
+163
Documentation/devicetree/bindings/regulator/nxp,pf0900.yaml
··· 1 + # SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause 2 + %YAML 1.2 3 + --- 4 + $id: http://devicetree.org/schemas/regulator/nxp,pf0900.yaml# 5 + $schema: http://devicetree.org/meta-schemas/core.yaml# 6 + 7 + title: NXP PF0900 Power Management Integrated Circuit regulators 8 + 9 + maintainers: 10 + - Joy Zou <joy.zou@nxp.com> 11 + 12 + description: 13 + The PF0900 is a power management integrated circuit (PMIC) optimized 14 + for high performance i.MX9x based applications. It features five high 15 + efficiency buck converters, three linear and one vaon regulators. It 16 + provides low quiescent current in Standby and low power off Modes. 17 + 18 + properties: 19 + compatible: 20 + enum: 21 + - nxp,pf0900 22 + 23 + reg: 24 + maxItems: 1 25 + 26 + interrupts: 27 + maxItems: 1 28 + 29 + regulators: 30 + type: object 31 + additionalProperties: false 32 + 33 + properties: 34 + vaon: 35 + type: object 36 + $ref: regulator.yaml# 37 + unevaluatedProperties: false 38 + 39 + patternProperties: 40 + "^ldo[1-3]$": 41 + type: object 42 + $ref: regulator.yaml# 43 + unevaluatedProperties: false 44 + 45 + "^sw[1-5]$": 46 + type: object 47 + $ref: regulator.yaml# 48 + unevaluatedProperties: false 49 + 50 + nxp,i2c-crc-enable: 51 + type: boolean 52 + description: 53 + The CRC enabled during register read/write. Controlled by customer 54 + unviewable fuse bits OTP_I2C_CRC_EN. Check chip part number. 55 + 56 + required: 57 + - compatible 58 + - reg 59 + - interrupts 60 + - regulators 61 + 62 + additionalProperties: false 63 + 64 + examples: 65 + - | 66 + #include <dt-bindings/interrupt-controller/irq.h> 67 + 68 + i2c { 69 + #address-cells = <1>; 70 + #size-cells = <0>; 71 + 72 + pmic@8 { 73 + compatible = "nxp,pf0900"; 74 + reg = <0x08>; 75 + interrupt-parent = <&pcal6524>; 76 + interrupts = <89 IRQ_TYPE_LEVEL_LOW>; 77 + nxp,i2c-crc-enable; 78 + 79 + regulators { 80 + vaon { 81 + regulator-name = "VAON"; 82 + regulator-min-microvolt = <1800000>; 83 + regulator-max-microvolt = <3300000>; 84 + regulator-boot-on; 85 + regulator-always-on; 86 + }; 87 + 88 + sw1 { 89 + regulator-name = "SW1"; 90 + regulator-min-microvolt = <500000>; 91 + regulator-max-microvolt = <3300000>; 92 + regulator-boot-on; 93 + regulator-always-on; 94 + regulator-ramp-delay = <1950>; 95 + regulator-state-mem { 96 + regulator-on-in-suspend; 97 + regulator-suspend-max-microvolt = <650000>; 98 + regulator-suspend-min-microvolt = <650000>; 99 + }; 100 + }; 101 + 102 + sw2 { 103 + regulator-name = "SW2"; 104 + regulator-min-microvolt = <300000>; 105 + regulator-max-microvolt = <3300000>; 106 + regulator-boot-on; 107 + regulator-always-on; 108 + regulator-ramp-delay = <1950>; 109 + }; 110 + 111 + sw3 { 112 + regulator-name = "SW3"; 113 + regulator-min-microvolt = <300000>; 114 + regulator-max-microvolt = <3300000>; 115 + regulator-boot-on; 116 + regulator-always-on; 117 + regulator-ramp-delay = <1950>; 118 + }; 119 + 120 + sw4 { 121 + regulator-name = "SW4"; 122 + regulator-min-microvolt = <300000>; 123 + regulator-max-microvolt = <3300000>; 124 + regulator-boot-on; 125 + regulator-always-on; 126 + regulator-ramp-delay = <1950>; 127 + }; 128 + 129 + sw5 { 130 + regulator-name = "SW5"; 131 + regulator-min-microvolt = <300000>; 132 + regulator-max-microvolt = <3300000>; 133 + regulator-boot-on; 134 + regulator-always-on; 135 + regulator-ramp-delay = <1950>; 136 + }; 137 + 138 + ldo1 { 139 + regulator-name = "LDO1"; 140 + regulator-min-microvolt = <750000>; 141 + regulator-max-microvolt = <3300000>; 142 + regulator-boot-on; 143 + regulator-always-on; 144 + }; 145 + 146 + ldo2 { 147 + regulator-name = "LDO2"; 148 + regulator-min-microvolt = <650000>; 149 + regulator-max-microvolt = <3300000>; 150 + regulator-boot-on; 151 + regulator-always-on; 152 + }; 153 + 154 + ldo3 { 155 + regulator-name = "LDO3"; 156 + regulator-min-microvolt = <650000>; 157 + regulator-max-microvolt = <3300000>; 158 + regulator-boot-on; 159 + regulator-always-on; 160 + }; 161 + }; 162 + }; 163 + };
+8
drivers/regulator/Kconfig
··· 1006 1006 This driver provides support for the voltage regulators of the 1007 1007 PCAP2 PMIC. 1008 1008 1009 + config REGULATOR_PF0900 1010 + tristate "NXP PF0900/PF0901/PF09XX regulator driver" 1011 + depends on I2C 1012 + select REGMAP_I2C 1013 + help 1014 + Say y here to support the NXP PF0900/PF0901/PF09XX PMIC 1015 + regulator driver. 1016 + 1009 1017 config REGULATOR_PF8X00 1010 1018 tristate "NXP PF8100/PF8121A/PF8200 regulator driver" 1011 1019 depends on I2C && OF
+1
drivers/regulator/Makefile
··· 124 124 obj-$(CONFIG_REGULATOR_QCOM_USB_VBUS) += qcom_usb_vbus-regulator.o 125 125 obj-$(CONFIG_REGULATOR_PALMAS) += palmas-regulator.o 126 126 obj-$(CONFIG_REGULATOR_PCA9450) += pca9450-regulator.o 127 + obj-$(CONFIG_REGULATOR_PF0900) += pf0900-regulator.o 127 128 obj-$(CONFIG_REGULATOR_PF9453) += pf9453-regulator.o 128 129 obj-$(CONFIG_REGULATOR_PF8X00) += pf8x00-regulator.o 129 130 obj-$(CONFIG_REGULATOR_PFUZE100) += pfuze100-regulator.o
+975
drivers/regulator/pf0900-regulator.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + // Copyright 2025 NXP. 3 + // NXP PF0900 pmic driver 4 + 5 + #include <linux/bitfield.h> 6 + #include <linux/crc8.h> 7 + #include <linux/err.h> 8 + #include <linux/gpio/consumer.h> 9 + #include <linux/i2c.h> 10 + #include <linux/interrupt.h> 11 + #include <linux/kernel.h> 12 + #include <linux/module.h> 13 + #include <linux/of.h> 14 + #include <linux/of_device.h> 15 + #include <linux/platform_device.h> 16 + #include <linux/regmap.h> 17 + #include <linux/regulator/driver.h> 18 + #include <linux/regulator/machine.h> 19 + #include <linux/regulator/of_regulator.h> 20 + 21 + enum pf0900_regulators { 22 + PF0900_SW1 = 0, 23 + PF0900_SW2, 24 + PF0900_SW3, 25 + PF0900_SW4, 26 + PF0900_SW5, 27 + PF0900_LDO1, 28 + PF0900_LDO2, 29 + PF0900_LDO3, 30 + PF0900_VAON, 31 + PF0900_REGULATOR_CNT, 32 + }; 33 + 34 + enum { 35 + PF0900_DVS_LEVEL_RUN = 0, 36 + PF0900_DVS_LEVEL_STANDBY, 37 + PF0900_DVS_LEVEL_MAX, 38 + }; 39 + 40 + 41 + #define PF0900_VAON_VOLTAGE_NUM 0x03 42 + #define PF0900_SW_VOLTAGE_NUM 0x100 43 + #define PF0900_LDO_VOLTAGE_NUM 0x20 44 + 45 + #define REGU_SW_CNT 0x5 46 + #define REGU_LDO_VAON_CNT 0x4 47 + 48 + enum { 49 + PF0900_REG_DEV_ID = 0x00, 50 + PF0900_REG_DEV_FAM = 0x01, 51 + PF0900_REG_REV_ID = 0x02, 52 + PF0900_REG_PROG_ID1 = 0x03, 53 + PF0900_REG_PROG_ID2 = 0x04, 54 + PF0900_REG_SYSTEM_INT = 0x05, 55 + PF0900_REG_STATUS1_INT = 0x06, 56 + PF0900_REG_STATUS1_MSK = 0x07, 57 + PF0900_REG_STATUS1_SNS = 0x08, 58 + PF0900_REG_STATUS2_INT = 0x09, 59 + PF0900_REG_STATUS2_MSK = 0x0A, 60 + PF0900_REG_STATUS2_SNS = 0x0B, 61 + PF0900_REG_STATUS3_INT = 0x0C, 62 + PF0900_REG_STATUS3_MSK = 0x0D, 63 + PF0900_REG_SW_MODE_INT = 0x0E, 64 + PF0900_REG_SW_MODE_MSK = 0x0F, 65 + PF0900_REG_SW_ILIM_INT = 0x10, 66 + PF0900_REG_SW_ILIM_MSK = 0x11, 67 + PF0900_REG_SW_ILIM_SNS = 0x12, 68 + PF0900_REG_LDO_ILIM_INT = 0x13, 69 + PF0900_REG_LDO_ILIM_MSK = 0x14, 70 + PF0900_REG_LDO_ILIM_SNS = 0x15, 71 + PF0900_REG_SW_UV_INT = 0x16, 72 + PF0900_REG_SW_UV_MSK = 0x17, 73 + PF0900_REG_SW_UV_SNS = 0x18, 74 + PF0900_REG_SW_OV_INT = 0x19, 75 + PF0900_REG_SW_OV_MSK = 0x1A, 76 + PF0900_REG_SW_OV_SNS = 0x1B, 77 + PF0900_REG_LDO_UV_INT = 0x1C, 78 + PF0900_REG_LDO_UV_MSK = 0x1D, 79 + PF0900_REG_LDO_UV_SNS = 0x1E, 80 + PF0900_REG_LDO_OV_INT = 0x1F, 81 + PF0900_REG_LDO_OV_MSK = 0x20, 82 + PF0900_REG_LDO_OV_SNS = 0x21, 83 + PF0900_REG_PWRON_INT = 0x22, 84 + PF0900_REG_IO_INT = 0x24, 85 + PF0900_REG_IO_MSK = 0x25, 86 + PF0900_REG_IO_SNS = 0x26, 87 + PF0900_REG_IOSHORT_SNS = 0x27, 88 + PF0900_REG_ABIST_OV1 = 0x28, 89 + PF0900_REG_ABIST_OV2 = 0x29, 90 + PF0900_REG_ABIST_UV1 = 0x2A, 91 + PF0900_REG_ABIST_UV2 = 0x2B, 92 + PF0900_REG_ABIST_IO = 0x2C, 93 + PF0900_REG_TEST_FLAGS = 0x2D, 94 + PF0900_REG_HFAULT_FLAGS = 0x2E, 95 + PF0900_REG_FAULT_FLAGS = 0x2F, 96 + PF0900_REG_FS0B_CFG = 0x30, 97 + PF0900_REG_FCCU_CFG = 0x31, 98 + PF0900_REG_RSTB_CFG1 = 0x32, 99 + PF0900_REG_SYSTEM_CMD = 0x33, 100 + PF0900_REG_FS0B_CMD = 0x34, 101 + PF0900_REG_SECURE_WR1 = 0x35, 102 + PF0900_REG_SECURE_WR2 = 0x36, 103 + PF0900_REG_VMON_CFG1 = 0x37, 104 + PF0900_REG_SYS_CFG1 = 0x38, 105 + PF0900_REG_GPO_CFG = 0x39, 106 + PF0900_REG_GPO_CTRL = 0x3A, 107 + PF0900_REG_PWRUP_CFG = 0x3B, 108 + PF0900_REG_RSTB_PWRUP = 0x3C, 109 + PF0900_REG_GPIO1_PWRUP = 0x3D, 110 + PF0900_REG_GPIO2_PWRUP = 0x3E, 111 + PF0900_REG_GPIO3_PWRUP = 0x3F, 112 + PF0900_REG_GPIO4_PWRUP = 0x40, 113 + PF0900_REG_VMON1_PWRUP = 0x41, 114 + PF0900_REG_VMON2_PWRUP = 0x42, 115 + PF0900_REG_SW1_PWRUP = 0x43, 116 + PF0900_REG_SW2_PWRUP = 0x44, 117 + PF0900_REG_SW3_PWRUP = 0x45, 118 + PF0900_REG_SW4_PWRUP = 0x46, 119 + PF0900_REG_SW5_PWRUP = 0x47, 120 + PF0900_REG_LDO1_PWRUP = 0x48, 121 + PF0900_REG_LDO2_PWRUP = 0x49, 122 + PF0900_REG_LDO3_PWRUP = 0x4A, 123 + PF0900_REG_VAON_PWRUP = 0x4B, 124 + PF0900_REG_FREQ_CTRL = 0x4C, 125 + PF0900_REG_PWRON_CFG = 0x4D, 126 + PF0900_REG_WD_CTRL1 = 0x4E, 127 + PF0900_REG_WD_CTRL2 = 0x4F, 128 + PF0900_REG_WD_CFG1 = 0x50, 129 + PF0900_REG_WD_CFG2 = 0x51, 130 + PF0900_REG_WD_CNT1 = 0x52, 131 + PF0900_REG_WD_CNT2 = 0x53, 132 + PF0900_REG_FAULT_CFG = 0x54, 133 + PF0900_REG_FAULT_CNT = 0x55, 134 + PF0900_REG_DFS_CNT = 0x56, 135 + PF0900_REG_AMUX_CFG = 0x57, 136 + PF0900_REG_VMON1_RUN_CFG = 0x58, 137 + PF0900_REG_VMON1_STBY_CFG = 0x59, 138 + PF0900_REG_VMON1_CTRL = 0x5A, 139 + PF0900_REG_VMON2_RUN_CFG = 0x5B, 140 + PF0900_REG_VMON2_STBY_CFG = 0x5C, 141 + PF0900_REG_VMON2_CTRL = 0x5D, 142 + PF0900_REG_SW1_VRUN = 0x5E, 143 + PF0900_REG_SW1_VSTBY = 0x5F, 144 + PF0900_REG_SW1_MODE = 0x60, 145 + PF0900_REG_SW1_CFG1 = 0x61, 146 + PF0900_REG_SW1_CFG2 = 0x62, 147 + PF0900_REG_SW2_VRUN = 0x63, 148 + PF0900_REG_SW2_VSTBY = 0x64, 149 + PF0900_REG_SW2_MODE = 0x65, 150 + PF0900_REG_SW2_CFG1 = 0x66, 151 + PF0900_REG_SW2_CFG2 = 0x67, 152 + PF0900_REG_SW3_VRUN = 0x68, 153 + PF0900_REG_SW3_VSTBY = 0x69, 154 + PF0900_REG_SW3_MODE = 0x6A, 155 + PF0900_REG_SW3_CFG1 = 0x6B, 156 + PF0900_REG_SW3_CFG2 = 0x6C, 157 + PF0900_REG_SW4_VRUN = 0x6D, 158 + PF0900_REG_SW4_VSTBY = 0x6E, 159 + PF0900_REG_SW4_MODE = 0x6F, 160 + PF0900_REG_SW4_CFG1 = 0x70, 161 + PF0900_REG_SW4_CFG2 = 0x71, 162 + PF0900_REG_SW5_VRUN = 0x72, 163 + PF0900_REG_SW5_VSTBY = 0x73, 164 + PF0900_REG_SW5_MODE = 0x74, 165 + PF0900_REG_SW5_CFG1 = 0x75, 166 + PF0900_REG_SW5_CFG2 = 0x76, 167 + PF0900_REG_LDO1_RUN = 0x77, 168 + PF0900_REG_LDO1_STBY = 0x78, 169 + PF0900_REG_LDO1_CFG2 = 0x79, 170 + PF0900_REG_LDO2_RUN = 0x7A, 171 + PF0900_REG_LDO2_STBY = 0x7B, 172 + PF0900_REG_LDO2_CFG2 = 0x7C, 173 + PF0900_REG_LDO3_RUN = 0x7D, 174 + PF0900_REG_LDO3_STBY = 0x7E, 175 + PF0900_REG_LDO3_CFG2 = 0x7F, 176 + PF0900_REG_VAON_CFG1 = 0x80, 177 + PF0900_REG_VAON_CFG2 = 0x81, 178 + PF0900_REG_SYS_DIAG = 0x82, 179 + PF0900_MAX_REGISTER, 180 + }; 181 + 182 + /* PF0900 SW MODE */ 183 + #define SW_RUN_MODE_OFF 0x00 184 + #define SW_RUN_MODE_PWM 0x01 185 + #define SW_RUN_MODE_PFM 0x02 186 + #define SW_STBY_MODE_OFF 0x00 187 + #define SW_STBY_MODE_PWM 0x04 188 + #define SW_STBY_MODE_PFM 0x08 189 + 190 + /* PF0900 SW MODE MASK */ 191 + #define SW_RUN_MODE_MASK GENMASK(1, 0) 192 + #define SW_STBY_MODE_MASK GENMASK(3, 2) 193 + 194 + /* PF0900 SW VRUN/VSTBY MASK */ 195 + #define PF0900_SW_VOL_MASK GENMASK(7, 0) 196 + 197 + /* PF0900_REG_VAON_CFG1 bits */ 198 + #define PF0900_VAON_1P8V 0x01 199 + 200 + #define PF0900_VAON_MASK GENMASK(1, 0) 201 + 202 + /* PF0900_REG_SWX_CFG1 MASK */ 203 + #define PF0900_SW_DVS_MASK GENMASK(4, 3) 204 + 205 + /* PF0900_REG_LDO_RUN MASK */ 206 + #define VLDO_RUN_MASK GENMASK(4, 0) 207 + #define LDO_RUN_EN_MASK BIT(5) 208 + 209 + /* PF0900_REG_STATUS1_INT bits */ 210 + #define PF0900_IRQ_PWRUP BIT(3) 211 + 212 + /* PF0900_REG_ILIM_INT bits */ 213 + #define PF0900_IRQ_SW1_IL BIT(0) 214 + #define PF0900_IRQ_SW2_IL BIT(1) 215 + #define PF0900_IRQ_SW3_IL BIT(2) 216 + #define PF0900_IRQ_SW4_IL BIT(3) 217 + #define PF0900_IRQ_SW5_IL BIT(4) 218 + 219 + #define PF0900_IRQ_LDO1_IL BIT(0) 220 + #define PF0900_IRQ_LDO2_IL BIT(1) 221 + #define PF0900_IRQ_LDO3_IL BIT(2) 222 + 223 + /* PF0900_REG_UV_INT bits */ 224 + #define PF0900_IRQ_SW1_UV BIT(0) 225 + #define PF0900_IRQ_SW2_UV BIT(1) 226 + #define PF0900_IRQ_SW3_UV BIT(2) 227 + #define PF0900_IRQ_SW4_UV BIT(3) 228 + #define PF0900_IRQ_SW5_UV BIT(4) 229 + 230 + #define PF0900_IRQ_LDO1_UV BIT(0) 231 + #define PF0900_IRQ_LDO2_UV BIT(1) 232 + #define PF0900_IRQ_LDO3_UV BIT(2) 233 + #define PF0900_IRQ_VAON_UV BIT(3) 234 + 235 + /* PF0900_REG_OV_INT bits */ 236 + #define PF0900_IRQ_SW1_OV BIT(0) 237 + #define PF0900_IRQ_SW2_OV BIT(1) 238 + #define PF0900_IRQ_SW3_OV BIT(2) 239 + #define PF0900_IRQ_SW4_OV BIT(3) 240 + #define PF0900_IRQ_SW5_OV BIT(4) 241 + 242 + #define PF0900_IRQ_LDO1_OV BIT(0) 243 + #define PF0900_IRQ_LDO2_OV BIT(1) 244 + #define PF0900_IRQ_LDO3_OV BIT(2) 245 + #define PF0900_IRQ_VAON_OV BIT(3) 246 + 247 + struct pf0900_regulator_desc { 248 + struct regulator_desc desc; 249 + unsigned int suspend_enable_mask; 250 + unsigned int suspend_voltage_reg; 251 + unsigned int suspend_voltage_cache; 252 + }; 253 + 254 + struct pf0900_drvdata { 255 + const struct pf0900_regulator_desc *desc; 256 + unsigned int rcnt; 257 + }; 258 + 259 + struct pf0900 { 260 + struct device *dev; 261 + struct regmap *regmap; 262 + const struct pf0900_drvdata *drvdata; 263 + struct regulator_dev *rdevs[PF0900_REGULATOR_CNT]; 264 + int irq; 265 + unsigned short addr; 266 + bool crc_en; 267 + }; 268 + 269 + enum pf0900_regulator_type { 270 + PF0900_SW = 0, 271 + PF0900_LDO, 272 + }; 273 + 274 + #define PF0900_REGU_IRQ(_reg, _type, _event) \ 275 + { \ 276 + .reg = _reg, \ 277 + .type = _type, \ 278 + .event = _event, \ 279 + } 280 + 281 + struct pf0900_regulator_irq { 282 + unsigned int reg; 283 + unsigned int type; 284 + unsigned int event; 285 + }; 286 + 287 + static const struct regmap_range pf0900_range = { 288 + .range_min = PF0900_REG_DEV_ID, 289 + .range_max = PF0900_REG_SYS_DIAG, 290 + }; 291 + 292 + static const struct regmap_access_table pf0900_volatile_regs = { 293 + .yes_ranges = &pf0900_range, 294 + .n_yes_ranges = 1, 295 + }; 296 + 297 + static const struct regmap_config pf0900_regmap_config = { 298 + .reg_bits = 8, 299 + .val_bits = 8, 300 + .volatile_table = &pf0900_volatile_regs, 301 + .max_register = PF0900_MAX_REGISTER - 1, 302 + .cache_type = REGCACHE_MAPLE, 303 + }; 304 + 305 + static uint8_t crc8_j1850(unsigned short addr, unsigned int reg, 306 + unsigned int val) 307 + { 308 + uint8_t crcBuf[3]; 309 + uint8_t t_crc; 310 + uint8_t i, j; 311 + 312 + crcBuf[0] = addr; 313 + crcBuf[1] = reg; 314 + crcBuf[2] = val; 315 + t_crc = 0xFF; 316 + 317 + /* 318 + * The CRC calculation is based on the standard CRC-8-SAE as 319 + * defined in the SAE-J1850 specification with the following 320 + * characteristics. 321 + * Polynomial = 0x1D 322 + * Initial Value = 0xFF 323 + * The CRC byte is calculated by shifting 24-bit data through 324 + * the CRC polynomial.The 24-bits package is built as follows: 325 + * DEVICE_ADDR[b8] + REGISTER_ADDR [b8] +DATA[b8] 326 + * The DEVICE_ADDR is calculated as the 7-bit slave address 327 + * shifted left one space plus the corresponding read/write bit. 328 + * (7Bit Address [b7] << 1 ) + R/W = DEVICE_ADDR[b8] 329 + */ 330 + for (i = 0; i < sizeof(crcBuf); i++) { 331 + t_crc ^= crcBuf[i]; 332 + for (j = 0; j < 8; j++) { 333 + if ((t_crc & 0x80) != 0) { 334 + t_crc <<= 1; 335 + t_crc ^= 0x1D; 336 + } else { 337 + t_crc <<= 1; 338 + } 339 + } 340 + } 341 + 342 + return t_crc; 343 + } 344 + 345 + static int pf0900_regmap_read(void *context, unsigned int reg, 346 + unsigned int *val) 347 + { 348 + struct device *dev = context; 349 + struct i2c_client *i2c = to_i2c_client(dev); 350 + struct pf0900 *pf0900 = dev_get_drvdata(dev); 351 + int ret; 352 + u8 crc; 353 + 354 + if (!pf0900 || !pf0900->dev) 355 + return -EINVAL; 356 + 357 + if (reg >= PF0900_MAX_REGISTER) { 358 + dev_err(pf0900->dev, "Invalid register address: 0x%x\n", reg); 359 + return -EINVAL; 360 + } 361 + 362 + if (pf0900->crc_en) { 363 + ret = i2c_smbus_read_word_data(i2c, reg); 364 + if (ret < 0) { 365 + dev_err(pf0900->dev, "Read error at reg=0x%x: %d\n", reg, ret); 366 + return ret; 367 + } 368 + 369 + *val = (u16)ret; 370 + crc = crc8_j1850(pf0900->addr << 1 | 0x1, reg, FIELD_GET(GENMASK(7, 0), *val)); 371 + if (crc != FIELD_GET(GENMASK(15, 8), *val)) { 372 + dev_err(pf0900->dev, "Crc check error!\n"); 373 + return -EINVAL; 374 + } 375 + *val = FIELD_GET(GENMASK(7, 0), *val); 376 + } else { 377 + ret = i2c_smbus_read_byte_data(i2c, reg); 378 + if (ret < 0) { 379 + dev_err(pf0900->dev, "Read error at reg=0x%x: %d\n", reg, ret); 380 + return ret; 381 + } 382 + *val = ret; 383 + } 384 + 385 + return 0; 386 + } 387 + 388 + static int pf0900_regmap_write(void *context, unsigned int reg, 389 + unsigned int val) 390 + { 391 + struct device *dev = context; 392 + struct i2c_client *i2c = to_i2c_client(dev); 393 + struct pf0900 *pf0900 = dev_get_drvdata(dev); 394 + uint8_t data[2]; 395 + int ret; 396 + 397 + if (!pf0900 || !pf0900->dev) 398 + return -EINVAL; 399 + 400 + if (reg >= PF0900_MAX_REGISTER) { 401 + dev_err(pf0900->dev, "Invalid register address: 0x%x\n", reg); 402 + return -EINVAL; 403 + } 404 + 405 + data[0] = val; 406 + if (pf0900->crc_en) { 407 + /* Get CRC */ 408 + data[1] = crc8_j1850(pf0900->addr << 1, reg, data[0]); 409 + val = FIELD_PREP(GENMASK(15, 8), data[1]) | data[0]; 410 + ret = i2c_smbus_write_word_data(i2c, reg, val); 411 + } else { 412 + ret = i2c_smbus_write_byte_data(i2c, reg, data[0]); 413 + } 414 + 415 + if (ret) { 416 + dev_err(pf0900->dev, "Write reg=0x%x error!\n", reg); 417 + return ret; 418 + } 419 + 420 + return 0; 421 + } 422 + 423 + static int pf0900_suspend_enable(struct regulator_dev *rdev) 424 + { 425 + struct pf0900_regulator_desc *rdata = rdev_get_drvdata(rdev); 426 + struct regmap *rmap = rdev_get_regmap(rdev); 427 + 428 + return regmap_update_bits(rmap, rdata->desc.enable_reg, 429 + rdata->suspend_enable_mask, SW_STBY_MODE_PFM); 430 + } 431 + 432 + static int pf0900_suspend_disable(struct regulator_dev *rdev) 433 + { 434 + struct pf0900_regulator_desc *rdata = rdev_get_drvdata(rdev); 435 + struct regmap *rmap = rdev_get_regmap(rdev); 436 + 437 + return regmap_update_bits(rmap, rdata->desc.enable_reg, 438 + rdata->suspend_enable_mask, SW_STBY_MODE_OFF); 439 + } 440 + 441 + static int pf0900_set_suspend_voltage(struct regulator_dev *rdev, int uV) 442 + { 443 + struct pf0900_regulator_desc *rdata = rdev_get_drvdata(rdev); 444 + struct regmap *rmap = rdev_get_regmap(rdev); 445 + int ret; 446 + 447 + if (rdata->suspend_voltage_cache == uV) 448 + return 0; 449 + 450 + ret = regulator_map_voltage_iterate(rdev, uV, uV); 451 + if (ret < 0) { 452 + dev_err(rdev_get_dev(rdev), "failed to map %i uV\n", uV); 453 + return ret; 454 + } 455 + 456 + dev_dbg(rdev_get_dev(rdev), "uV: %i, reg: 0x%x, msk: 0x%x, val: 0x%x\n", 457 + uV, rdata->suspend_voltage_reg, rdata->desc.vsel_mask, ret); 458 + ret = regmap_update_bits(rmap, rdata->suspend_voltage_reg, 459 + rdata->desc.vsel_mask, ret); 460 + if (ret < 0) { 461 + dev_err(rdev_get_dev(rdev), "failed to set %i uV\n", uV); 462 + return ret; 463 + } 464 + 465 + rdata->suspend_voltage_cache = uV; 466 + 467 + return 0; 468 + } 469 + 470 + static const struct regmap_bus pf0900_regmap_bus = { 471 + .reg_read = pf0900_regmap_read, 472 + .reg_write = pf0900_regmap_write, 473 + }; 474 + 475 + static const struct regulator_ops pf0900_avon_regulator_ops = { 476 + .list_voltage = regulator_list_voltage_table, 477 + .set_voltage_sel = regulator_set_voltage_sel_regmap, 478 + .get_voltage_sel = regulator_get_voltage_sel_regmap, 479 + }; 480 + 481 + static const struct regulator_ops pf0900_dvs_sw_regulator_ops = { 482 + .enable = regulator_enable_regmap, 483 + .disable = regulator_disable_regmap, 484 + .is_enabled = regulator_is_enabled_regmap, 485 + .list_voltage = regulator_list_voltage_linear_range, 486 + .set_voltage_sel = regulator_set_voltage_sel_regmap, 487 + .get_voltage_sel = regulator_get_voltage_sel_regmap, 488 + .set_voltage_time_sel = regulator_set_voltage_time_sel, 489 + .set_ramp_delay = regulator_set_ramp_delay_regmap, 490 + .set_suspend_enable = pf0900_suspend_enable, 491 + .set_suspend_disable = pf0900_suspend_disable, 492 + .set_suspend_voltage = pf0900_set_suspend_voltage, 493 + }; 494 + 495 + static const struct regulator_ops pf0900_ldo_regulator_ops = { 496 + .enable = regulator_enable_regmap, 497 + .disable = regulator_disable_regmap, 498 + .is_enabled = regulator_is_enabled_regmap, 499 + .list_voltage = regulator_list_voltage_linear_range, 500 + .set_voltage_sel = regulator_set_voltage_sel_regmap, 501 + .get_voltage_sel = regulator_get_voltage_sel_regmap, 502 + }; 503 + 504 + /* 505 + * SW1/2/3/4/5 506 + * SW1_DVS[1:0] SW1 DVS ramp rate setting 507 + * 00: 15.6mV/8usec 508 + * 01: 15.6mV/4usec 509 + * 10: 15.6mV/2usec 510 + * 11: 15.6mV/1usec 511 + */ 512 + static const unsigned int pf0900_dvs_sw_ramp_table[] = { 513 + 1950, 3900, 7800, 15600 514 + }; 515 + 516 + /* VAON 1.8V, 3.0V, or 3.3V */ 517 + static const int pf0900_vaon_voltages[] = { 518 + 0, 1800000, 3000000, 3300000, 519 + }; 520 + 521 + /* 522 + * SW1 0.5V to 3.3V 523 + * 0.5V to 1.35V (6.25mV step) 524 + * 1.8V to 2.5V (125mV step) 525 + * 2.8V to 3.3V (250mV step) 526 + */ 527 + static const struct linear_range pf0900_dvs_sw1_volts[] = { 528 + REGULATOR_LINEAR_RANGE(0, 0x00, 0x08, 0), 529 + REGULATOR_LINEAR_RANGE(500000, 0x09, 0x91, 6250), 530 + REGULATOR_LINEAR_RANGE(0, 0x92, 0x9E, 0), 531 + REGULATOR_LINEAR_RANGE(1500000, 0x9F, 0x9F, 0), 532 + REGULATOR_LINEAR_RANGE(1800000, 0xA0, 0xD8, 12500), 533 + REGULATOR_LINEAR_RANGE(0, 0xD9, 0xDF, 0), 534 + REGULATOR_LINEAR_RANGE(2800000, 0xE0, 0xF4, 25000), 535 + REGULATOR_LINEAR_RANGE(0, 0xF5, 0xFF, 0), 536 + }; 537 + 538 + /* 539 + * SW2/3/4/5 0.3V to 3.3V 540 + * 0.45V to 1.35V (6.25mV step) 541 + * 1.8V to 2.5V (125mV step) 542 + * 2.8V to 3.3V (250mV step) 543 + */ 544 + static const struct linear_range pf0900_dvs_sw2345_volts[] = { 545 + REGULATOR_LINEAR_RANGE(300000, 0x00, 0x00, 0), 546 + REGULATOR_LINEAR_RANGE(450000, 0x01, 0x91, 6250), 547 + REGULATOR_LINEAR_RANGE(0, 0x92, 0x9E, 0), 548 + REGULATOR_LINEAR_RANGE(1500000, 0x9F, 0x9F, 0), 549 + REGULATOR_LINEAR_RANGE(1800000, 0xA0, 0xD8, 12500), 550 + REGULATOR_LINEAR_RANGE(0, 0xD9, 0xDF, 0), 551 + REGULATOR_LINEAR_RANGE(2800000, 0xE0, 0xF4, 25000), 552 + REGULATOR_LINEAR_RANGE(0, 0xF5, 0xFF, 0), 553 + }; 554 + 555 + /* 556 + * LDO1 557 + * 0.75V to 3.3V 558 + */ 559 + static const struct linear_range pf0900_ldo1_volts[] = { 560 + REGULATOR_LINEAR_RANGE(750000, 0x00, 0x0F, 50000), 561 + REGULATOR_LINEAR_RANGE(1800000, 0x10, 0x1F, 100000), 562 + }; 563 + 564 + /* 565 + * LDO2/3 566 + * 0.65V to 3.3V (50mV step) 567 + */ 568 + static const struct linear_range pf0900_ldo23_volts[] = { 569 + REGULATOR_LINEAR_RANGE(650000, 0x00, 0x0D, 50000), 570 + REGULATOR_LINEAR_RANGE(1400000, 0x0E, 0x0F, 100000), 571 + REGULATOR_LINEAR_RANGE(1800000, 0x10, 0x1F, 100000), 572 + }; 573 + 574 + static const struct pf0900_regulator_desc pf0900_regulators[] = { 575 + { 576 + .desc = { 577 + .name = "sw1", 578 + .of_match = of_match_ptr("sw1"), 579 + .regulators_node = of_match_ptr("regulators"), 580 + .id = PF0900_SW1, 581 + .ops = &pf0900_dvs_sw_regulator_ops, 582 + .type = REGULATOR_VOLTAGE, 583 + .n_voltages = PF0900_SW_VOLTAGE_NUM, 584 + .linear_ranges = pf0900_dvs_sw1_volts, 585 + .n_linear_ranges = ARRAY_SIZE(pf0900_dvs_sw1_volts), 586 + .vsel_reg = PF0900_REG_SW1_VRUN, 587 + .vsel_mask = PF0900_SW_VOL_MASK, 588 + .enable_reg = PF0900_REG_SW1_MODE, 589 + .enable_mask = SW_RUN_MODE_MASK, 590 + .enable_val = SW_RUN_MODE_PWM, 591 + .ramp_reg = PF0900_REG_SW1_CFG1, 592 + .ramp_mask = PF0900_SW_DVS_MASK, 593 + .ramp_delay_table = pf0900_dvs_sw_ramp_table, 594 + .n_ramp_values = ARRAY_SIZE(pf0900_dvs_sw_ramp_table), 595 + .owner = THIS_MODULE, 596 + }, 597 + .suspend_enable_mask = SW_STBY_MODE_MASK, 598 + .suspend_voltage_reg = PF0900_REG_SW1_VSTBY, 599 + }, 600 + { 601 + .desc = { 602 + .name = "sw2", 603 + .of_match = of_match_ptr("sw2"), 604 + .regulators_node = of_match_ptr("regulators"), 605 + .id = PF0900_SW2, 606 + .ops = &pf0900_dvs_sw_regulator_ops, 607 + .type = REGULATOR_VOLTAGE, 608 + .n_voltages = PF0900_SW_VOLTAGE_NUM, 609 + .linear_ranges = pf0900_dvs_sw2345_volts, 610 + .n_linear_ranges = ARRAY_SIZE(pf0900_dvs_sw2345_volts), 611 + .vsel_reg = PF0900_REG_SW2_VRUN, 612 + .vsel_mask = PF0900_SW_VOL_MASK, 613 + .enable_reg = PF0900_REG_SW2_MODE, 614 + .enable_mask = SW_RUN_MODE_MASK, 615 + .enable_val = SW_RUN_MODE_PWM, 616 + .ramp_reg = PF0900_REG_SW2_CFG1, 617 + .ramp_mask = PF0900_SW_DVS_MASK, 618 + .ramp_delay_table = pf0900_dvs_sw_ramp_table, 619 + .n_ramp_values = ARRAY_SIZE(pf0900_dvs_sw_ramp_table), 620 + .owner = THIS_MODULE, 621 + }, 622 + .suspend_enable_mask = SW_STBY_MODE_MASK, 623 + .suspend_voltage_reg = PF0900_REG_SW2_VSTBY, 624 + }, 625 + { 626 + .desc = { 627 + .name = "sw3", 628 + .of_match = of_match_ptr("sw3"), 629 + .regulators_node = of_match_ptr("regulators"), 630 + .id = PF0900_SW3, 631 + .ops = &pf0900_dvs_sw_regulator_ops, 632 + .type = REGULATOR_VOLTAGE, 633 + .n_voltages = PF0900_SW_VOLTAGE_NUM, 634 + .linear_ranges = pf0900_dvs_sw2345_volts, 635 + .n_linear_ranges = ARRAY_SIZE(pf0900_dvs_sw2345_volts), 636 + .vsel_reg = PF0900_REG_SW3_VRUN, 637 + .vsel_mask = PF0900_SW_VOL_MASK, 638 + .enable_reg = PF0900_REG_SW3_MODE, 639 + .enable_mask = SW_RUN_MODE_MASK, 640 + .enable_val = SW_RUN_MODE_PWM, 641 + .ramp_reg = PF0900_REG_SW3_CFG1, 642 + .ramp_mask = PF0900_SW_DVS_MASK, 643 + .ramp_delay_table = pf0900_dvs_sw_ramp_table, 644 + .n_ramp_values = ARRAY_SIZE(pf0900_dvs_sw_ramp_table), 645 + .owner = THIS_MODULE, 646 + }, 647 + .suspend_enable_mask = SW_STBY_MODE_MASK, 648 + .suspend_voltage_reg = PF0900_REG_SW3_VSTBY, 649 + }, 650 + { 651 + .desc = { 652 + .name = "sw4", 653 + .of_match = of_match_ptr("sw4"), 654 + .regulators_node = of_match_ptr("regulators"), 655 + .id = PF0900_SW4, 656 + .ops = &pf0900_dvs_sw_regulator_ops, 657 + .type = REGULATOR_VOLTAGE, 658 + .n_voltages = PF0900_SW_VOLTAGE_NUM, 659 + .linear_ranges = pf0900_dvs_sw2345_volts, 660 + .n_linear_ranges = ARRAY_SIZE(pf0900_dvs_sw2345_volts), 661 + .vsel_reg = PF0900_REG_SW4_VRUN, 662 + .vsel_mask = PF0900_SW_VOL_MASK, 663 + .enable_reg = PF0900_REG_SW4_MODE, 664 + .enable_mask = SW_RUN_MODE_MASK, 665 + .enable_val = SW_RUN_MODE_PWM, 666 + .ramp_reg = PF0900_REG_SW4_CFG1, 667 + .ramp_mask = PF0900_SW_DVS_MASK, 668 + .ramp_delay_table = pf0900_dvs_sw_ramp_table, 669 + .n_ramp_values = ARRAY_SIZE(pf0900_dvs_sw_ramp_table), 670 + .owner = THIS_MODULE, 671 + }, 672 + .suspend_enable_mask = SW_STBY_MODE_MASK, 673 + .suspend_voltage_reg = PF0900_REG_SW4_VSTBY, 674 + }, 675 + { 676 + .desc = { 677 + .name = "sw5", 678 + .of_match = of_match_ptr("sw5"), 679 + .regulators_node = of_match_ptr("regulators"), 680 + .id = PF0900_SW5, 681 + .ops = &pf0900_dvs_sw_regulator_ops, 682 + .type = REGULATOR_VOLTAGE, 683 + .n_voltages = PF0900_SW_VOLTAGE_NUM, 684 + .linear_ranges = pf0900_dvs_sw2345_volts, 685 + .n_linear_ranges = ARRAY_SIZE(pf0900_dvs_sw2345_volts), 686 + .vsel_reg = PF0900_REG_SW5_VRUN, 687 + .vsel_mask = PF0900_SW_VOL_MASK, 688 + .enable_reg = PF0900_REG_SW5_MODE, 689 + .enable_mask = SW_RUN_MODE_MASK, 690 + .enable_val = SW_RUN_MODE_PWM, 691 + .ramp_reg = PF0900_REG_SW5_CFG1, 692 + .ramp_mask = PF0900_SW_DVS_MASK, 693 + .ramp_delay_table = pf0900_dvs_sw_ramp_table, 694 + .n_ramp_values = ARRAY_SIZE(pf0900_dvs_sw_ramp_table), 695 + .owner = THIS_MODULE, 696 + }, 697 + .suspend_enable_mask = SW_STBY_MODE_MASK, 698 + .suspend_voltage_reg = PF0900_REG_SW5_VSTBY, 699 + }, 700 + { 701 + .desc = { 702 + .name = "ldo1", 703 + .of_match = of_match_ptr("ldo1"), 704 + .regulators_node = of_match_ptr("regulators"), 705 + .id = PF0900_LDO1, 706 + .ops = &pf0900_ldo_regulator_ops, 707 + .type = REGULATOR_VOLTAGE, 708 + .n_voltages = PF0900_LDO_VOLTAGE_NUM, 709 + .linear_ranges = pf0900_ldo1_volts, 710 + .n_linear_ranges = ARRAY_SIZE(pf0900_ldo1_volts), 711 + .vsel_reg = PF0900_REG_LDO1_RUN, 712 + .vsel_mask = VLDO_RUN_MASK, 713 + .enable_reg = PF0900_REG_LDO1_RUN, 714 + .enable_mask = LDO_RUN_EN_MASK, 715 + .owner = THIS_MODULE, 716 + }, 717 + }, 718 + { 719 + .desc = { 720 + .name = "ldo2", 721 + .of_match = of_match_ptr("ldo2"), 722 + .regulators_node = of_match_ptr("regulators"), 723 + .id = PF0900_LDO2, 724 + .ops = &pf0900_ldo_regulator_ops, 725 + .type = REGULATOR_VOLTAGE, 726 + .n_voltages = PF0900_LDO_VOLTAGE_NUM, 727 + .linear_ranges = pf0900_ldo23_volts, 728 + .n_linear_ranges = ARRAY_SIZE(pf0900_ldo23_volts), 729 + .vsel_reg = PF0900_REG_LDO2_RUN, 730 + .vsel_mask = VLDO_RUN_MASK, 731 + .enable_reg = PF0900_REG_LDO2_RUN, 732 + .enable_mask = LDO_RUN_EN_MASK, 733 + .owner = THIS_MODULE, 734 + }, 735 + }, 736 + { 737 + .desc = { 738 + .name = "ldo3", 739 + .of_match = of_match_ptr("ldo3"), 740 + .regulators_node = of_match_ptr("regulators"), 741 + .id = PF0900_LDO3, 742 + .ops = &pf0900_ldo_regulator_ops, 743 + .type = REGULATOR_VOLTAGE, 744 + .n_voltages = PF0900_LDO_VOLTAGE_NUM, 745 + .linear_ranges = pf0900_ldo23_volts, 746 + .n_linear_ranges = ARRAY_SIZE(pf0900_ldo23_volts), 747 + .vsel_reg = PF0900_REG_LDO3_RUN, 748 + .vsel_mask = VLDO_RUN_MASK, 749 + .enable_reg = PF0900_REG_LDO3_RUN, 750 + .enable_mask = LDO_RUN_EN_MASK, 751 + .owner = THIS_MODULE, 752 + }, 753 + }, 754 + { 755 + .desc = { 756 + .name = "vaon", 757 + .of_match = of_match_ptr("vaon"), 758 + .regulators_node = of_match_ptr("regulators"), 759 + .id = PF0900_VAON, 760 + .ops = &pf0900_avon_regulator_ops, 761 + .type = REGULATOR_VOLTAGE, 762 + .n_voltages = PF0900_VAON_VOLTAGE_NUM, 763 + .volt_table = pf0900_vaon_voltages, 764 + .enable_reg = PF0900_REG_VAON_CFG1, 765 + .enable_mask = PF0900_VAON_MASK, 766 + .enable_val = PF0900_VAON_1P8V, 767 + .vsel_reg = PF0900_REG_VAON_CFG1, 768 + .vsel_mask = PF0900_VAON_MASK, 769 + .owner = THIS_MODULE, 770 + }, 771 + }, 772 + }; 773 + 774 + struct pf0900_regulator_irq regu_irqs[] = { 775 + PF0900_REGU_IRQ(PF0900_REG_SW_ILIM_INT, PF0900_SW, REGULATOR_ERROR_OVER_CURRENT_WARN), 776 + PF0900_REGU_IRQ(PF0900_REG_LDO_ILIM_INT, PF0900_LDO, REGULATOR_ERROR_OVER_CURRENT_WARN), 777 + PF0900_REGU_IRQ(PF0900_REG_SW_UV_INT, PF0900_SW, REGULATOR_ERROR_UNDER_VOLTAGE_WARN), 778 + PF0900_REGU_IRQ(PF0900_REG_LDO_UV_INT, PF0900_LDO, REGULATOR_ERROR_UNDER_VOLTAGE_WARN), 779 + PF0900_REGU_IRQ(PF0900_REG_SW_OV_INT, PF0900_SW, REGULATOR_ERROR_OVER_VOLTAGE_WARN), 780 + PF0900_REGU_IRQ(PF0900_REG_LDO_OV_INT, PF0900_LDO, REGULATOR_ERROR_OVER_VOLTAGE_WARN), 781 + }; 782 + 783 + static irqreturn_t pf0900_irq_handler(int irq, void *data) 784 + { 785 + unsigned int val, regu, i, index; 786 + struct pf0900 *pf0900 = data; 787 + int ret; 788 + 789 + for (i = 0; i < ARRAY_SIZE(regu_irqs); i++) { 790 + ret = regmap_read(pf0900->regmap, regu_irqs[i].reg, &val); 791 + if (ret < 0) { 792 + dev_err(pf0900->dev, "Failed to read %d\n", ret); 793 + return IRQ_NONE; 794 + } 795 + if (val) { 796 + ret = regmap_write_bits(pf0900->regmap, regu_irqs[i].reg, val, val); 797 + if (ret < 0) { 798 + dev_err(pf0900->dev, "Failed to update %d\n", ret); 799 + return IRQ_NONE; 800 + } 801 + 802 + if (regu_irqs[i].type == PF0900_SW) { 803 + for (index = 0; index < REGU_SW_CNT; index++) { 804 + if (val & BIT(index)) { 805 + regu = (enum pf0900_regulators)index; 806 + regulator_notifier_call_chain(pf0900->rdevs[regu], 807 + regu_irqs[i].event, 808 + NULL); 809 + } 810 + } 811 + } else if (regu_irqs[i].type == PF0900_LDO) { 812 + for (index = 0; index < REGU_LDO_VAON_CNT; index++) { 813 + if (val & BIT(index)) { 814 + regu = (enum pf0900_regulators)index + PF0900_LDO1; 815 + regulator_notifier_call_chain(pf0900->rdevs[regu], 816 + regu_irqs[i].event, 817 + NULL); 818 + } 819 + } 820 + } 821 + } 822 + } 823 + 824 + return IRQ_HANDLED; 825 + } 826 + 827 + static int pf0900_i2c_probe(struct i2c_client *i2c) 828 + { 829 + const struct pf0900_regulator_desc *regulator_desc; 830 + const struct pf0900_drvdata *drvdata = NULL; 831 + struct device_node *np = i2c->dev.of_node; 832 + unsigned int device_id, device_fam, i; 833 + struct regulator_config config = { }; 834 + struct pf0900 *pf0900; 835 + int ret; 836 + 837 + if (!i2c->irq) 838 + return dev_err_probe(&i2c->dev, -EINVAL, "No IRQ configured?\n"); 839 + 840 + pf0900 = devm_kzalloc(&i2c->dev, sizeof(struct pf0900), GFP_KERNEL); 841 + if (!pf0900) 842 + return -ENOMEM; 843 + 844 + drvdata = device_get_match_data(&i2c->dev); 845 + if (!drvdata) 846 + return dev_err_probe(&i2c->dev, -EINVAL, "unable to find driver data\n"); 847 + 848 + regulator_desc = drvdata->desc; 849 + pf0900->drvdata = drvdata; 850 + pf0900->crc_en = of_property_read_bool(np, "nxp,i2c-crc-enable"); 851 + pf0900->irq = i2c->irq; 852 + pf0900->dev = &i2c->dev; 853 + pf0900->addr = i2c->addr; 854 + 855 + dev_set_drvdata(&i2c->dev, pf0900); 856 + 857 + pf0900->regmap = devm_regmap_init(&i2c->dev, &pf0900_regmap_bus, &i2c->dev, 858 + &pf0900_regmap_config); 859 + if (IS_ERR(pf0900->regmap)) 860 + return dev_err_probe(&i2c->dev, PTR_ERR(pf0900->regmap), 861 + "regmap initialization failed\n"); 862 + ret = regmap_read(pf0900->regmap, PF0900_REG_DEV_ID, &device_id); 863 + if (ret) 864 + return dev_err_probe(&i2c->dev, ret, "Read device id error\n"); 865 + 866 + ret = regmap_read(pf0900->regmap, PF0900_REG_DEV_FAM, &device_fam); 867 + if (ret) 868 + return dev_err_probe(&i2c->dev, ret, "Read device fam error\n"); 869 + 870 + /* Check your board and dts for match the right pmic */ 871 + if (device_fam == 0x09 && (device_id & 0x1F) != 0x0) 872 + return dev_err_probe(&i2c->dev, -EINVAL, "Device id(%x) mismatched\n", 873 + device_id >> 4); 874 + 875 + for (i = 0; i < drvdata->rcnt; i++) { 876 + const struct regulator_desc *desc; 877 + const struct pf0900_regulator_desc *r; 878 + 879 + r = &regulator_desc[i]; 880 + desc = &r->desc; 881 + config.regmap = pf0900->regmap; 882 + config.driver_data = (void *)r; 883 + config.dev = pf0900->dev; 884 + 885 + pf0900->rdevs[i] = devm_regulator_register(pf0900->dev, desc, &config); 886 + if (IS_ERR(pf0900->rdevs[i])) 887 + return dev_err_probe(pf0900->dev, PTR_ERR(pf0900->rdevs[i]), 888 + "Failed to register regulator(%s)\n", desc->name); 889 + } 890 + 891 + ret = devm_request_threaded_irq(pf0900->dev, pf0900->irq, NULL, 892 + pf0900_irq_handler, 893 + (IRQF_TRIGGER_FALLING | IRQF_ONESHOT), 894 + "pf0900-irq", pf0900); 895 + 896 + if (ret != 0) 897 + return dev_err_probe(pf0900->dev, ret, "Failed to request IRQ: %d\n", 898 + pf0900->irq); 899 + /* 900 + * The PWRUP_M is unmasked by default. When the device enter in RUN state, 901 + * it will assert the PWRUP_I interrupt and assert the INTB pin to inform 902 + * the MCU that it has finished the power up sequence properly. 903 + */ 904 + ret = regmap_write_bits(pf0900->regmap, PF0900_REG_STATUS1_INT, PF0900_IRQ_PWRUP, 905 + PF0900_IRQ_PWRUP); 906 + if (ret) 907 + return dev_err_probe(&i2c->dev, ret, "Clean PWRUP_I error\n"); 908 + 909 + /* mask interrupt PWRUP */ 910 + ret = regmap_update_bits(pf0900->regmap, PF0900_REG_STATUS1_MSK, PF0900_IRQ_PWRUP, 911 + PF0900_IRQ_PWRUP); 912 + if (ret) 913 + return dev_err_probe(&i2c->dev, ret, "Unmask irq error\n"); 914 + 915 + ret = regmap_update_bits(pf0900->regmap, PF0900_REG_SW_ILIM_MSK, PF0900_IRQ_SW1_IL | 916 + PF0900_IRQ_SW2_IL | PF0900_IRQ_SW3_IL | PF0900_IRQ_SW4_IL | 917 + PF0900_IRQ_SW5_IL, 0); 918 + if (ret) 919 + return dev_err_probe(&i2c->dev, ret, "Unmask irq error\n"); 920 + 921 + ret = regmap_update_bits(pf0900->regmap, PF0900_REG_SW_UV_MSK, PF0900_IRQ_SW1_UV | 922 + PF0900_IRQ_SW2_UV | PF0900_IRQ_SW3_UV | PF0900_IRQ_SW4_UV | 923 + PF0900_IRQ_SW5_UV, 0); 924 + if (ret) 925 + return dev_err_probe(&i2c->dev, ret, "Unmask irq error\n"); 926 + 927 + ret = regmap_update_bits(pf0900->regmap, PF0900_REG_SW_OV_MSK, PF0900_IRQ_SW1_OV | 928 + PF0900_IRQ_SW2_OV | PF0900_IRQ_SW3_OV | PF0900_IRQ_SW4_OV | 929 + PF0900_IRQ_SW5_OV, 0); 930 + if (ret) 931 + return dev_err_probe(&i2c->dev, ret, "Unmask irq error\n"); 932 + 933 + ret = regmap_update_bits(pf0900->regmap, PF0900_REG_LDO_ILIM_MSK, PF0900_IRQ_LDO1_IL | 934 + PF0900_IRQ_LDO2_IL | PF0900_IRQ_LDO3_IL, 0); 935 + if (ret) 936 + return dev_err_probe(&i2c->dev, ret, "Unmask irq error\n"); 937 + 938 + ret = regmap_update_bits(pf0900->regmap, PF0900_REG_LDO_UV_MSK, PF0900_IRQ_LDO1_UV | 939 + PF0900_IRQ_LDO2_UV | PF0900_IRQ_LDO3_UV | PF0900_IRQ_VAON_UV, 0); 940 + if (ret) 941 + return dev_err_probe(&i2c->dev, ret, "Unmask irq error\n"); 942 + 943 + ret = regmap_update_bits(pf0900->regmap, PF0900_REG_LDO_OV_MSK, PF0900_IRQ_LDO1_OV | 944 + PF0900_IRQ_LDO2_OV | PF0900_IRQ_LDO3_OV | PF0900_IRQ_VAON_OV, 0); 945 + if (ret) 946 + return dev_err_probe(&i2c->dev, ret, "Unmask irq error\n"); 947 + 948 + return 0; 949 + } 950 + 951 + static struct pf0900_drvdata pf0900_drvdata = { 952 + .desc = pf0900_regulators, 953 + .rcnt = ARRAY_SIZE(pf0900_regulators), 954 + }; 955 + 956 + static const struct of_device_id pf0900_of_match[] = { 957 + { .compatible = "nxp,pf0900", .data = &pf0900_drvdata}, 958 + { } 959 + }; 960 + 961 + MODULE_DEVICE_TABLE(of, pf0900_of_match); 962 + 963 + static struct i2c_driver pf0900_i2c_driver = { 964 + .driver = { 965 + .name = "nxp-pf0900", 966 + .of_match_table = pf0900_of_match, 967 + }, 968 + .probe = pf0900_i2c_probe, 969 + }; 970 + 971 + module_i2c_driver(pf0900_i2c_driver); 972 + 973 + MODULE_AUTHOR("Joy Zou <joy.zou@nxp.com>"); 974 + MODULE_DESCRIPTION("NXP PF0900 Power Management IC driver"); 975 + MODULE_LICENSE("GPL");