1d3795d63SJagan Teki // SPDX-License-Identifier: GPL-2.0+
2d3795d63SJagan Teki /*
3d3795d63SJagan Teki * Copyright (C) 2017 NXP
4d3795d63SJagan Teki * Copyright (C) 2019 Boundary Devices
5d3795d63SJagan Teki * Copyright (C) 2020 Amarula Solutions(India)
6d3795d63SJagan Teki */
7d3795d63SJagan Teki
8d3795d63SJagan Teki #include <linux/delay.h>
9d3795d63SJagan Teki #include <linux/err.h>
10d3795d63SJagan Teki #include <linux/gpio/consumer.h>
11d3795d63SJagan Teki #include <linux/i2c.h>
12d3795d63SJagan Teki #include <linux/module.h>
13d3795d63SJagan Teki #include <linux/regmap.h>
14d3795d63SJagan Teki #include <linux/regulator/driver.h>
15d3795d63SJagan Teki #include <linux/regulator/machine.h>
16d3795d63SJagan Teki
17d3795d63SJagan Teki /* registers */
18d3795d63SJagan Teki #define PF8X00_DEVICEID 0x00
19d3795d63SJagan Teki #define PF8X00_REVID 0x01
20d3795d63SJagan Teki #define PF8X00_EMREV 0x02
21d3795d63SJagan Teki #define PF8X00_PROGID 0x03
22d3795d63SJagan Teki #define PF8X00_IMS_INT 0x04
23d3795d63SJagan Teki #define PF8X00_IMS_THERM 0x07
24d3795d63SJagan Teki #define PF8X00_SW_MODE_INT 0x0a
25d3795d63SJagan Teki #define PF8X00_SW_MODE_MASK 0x0b
26d3795d63SJagan Teki #define PF8X00_IMS_SW_ILIM 0x12
27d3795d63SJagan Teki #define PF8X00_IMS_LDO_ILIM 0x15
28d3795d63SJagan Teki #define PF8X00_IMS_SW_UV 0x18
29d3795d63SJagan Teki #define PF8X00_IMS_SW_OV 0x1b
30d3795d63SJagan Teki #define PF8X00_IMS_LDO_UV 0x1e
31d3795d63SJagan Teki #define PF8X00_IMS_LDO_OV 0x21
32d3795d63SJagan Teki #define PF8X00_IMS_PWRON 0x24
33d3795d63SJagan Teki #define PF8X00_SYS_INT 0x27
34d3795d63SJagan Teki #define PF8X00_HARD_FAULT 0x29
35d3795d63SJagan Teki #define PF8X00_FSOB_FLAGS 0x2a
36d3795d63SJagan Teki #define PF8X00_FSOB_SELECT 0x2b
37d3795d63SJagan Teki #define PF8X00_ABIST_OV1 0x2c
38d3795d63SJagan Teki #define PF8X00_ABIST_OV2 0x2d
39d3795d63SJagan Teki #define PF8X00_ABIST_UV1 0x2e
40d3795d63SJagan Teki #define PF8X00_ABIST_UV2 0x2f
41d3795d63SJagan Teki #define PF8X00_TEST_FLAGS 0x30
42d3795d63SJagan Teki #define PF8X00_ABIST_RUN 0x31
43d3795d63SJagan Teki #define PF8X00_RANDOM_GEN 0x33
44d3795d63SJagan Teki #define PF8X00_RANDOM_CHK 0x34
45d3795d63SJagan Teki #define PF8X00_VMONEN1 0x35
46d3795d63SJagan Teki #define PF8X00_VMONEN2 0x36
47d3795d63SJagan Teki #define PF8X00_CTRL1 0x37
48d3795d63SJagan Teki #define PF8X00_CTRL2 0x38
49d3795d63SJagan Teki #define PF8X00_CTRL3 0x39
50d3795d63SJagan Teki #define PF8X00_PWRUP_CTRL 0x3a
51d3795d63SJagan Teki #define PF8X00_RESETBMCU 0x3c
52d3795d63SJagan Teki #define PF8X00_PGOOD 0x3d
53d3795d63SJagan Teki #define PF8X00_PWRDN_DLY1 0x3e
54d3795d63SJagan Teki #define PF8X00_PWRDN_DLY2 0x3f
55d3795d63SJagan Teki #define PF8X00_FREQ_CTRL 0x40
56d3795d63SJagan Teki #define PF8X00_COINCELL_CTRL 0x41
57d3795d63SJagan Teki #define PF8X00_PWRON 0x42
58d3795d63SJagan Teki #define PF8X00_WD_CONFIG 0x43
59d3795d63SJagan Teki #define PF8X00_WD_CLEAR 0x44
60d3795d63SJagan Teki #define PF8X00_WD_EXPIRE 0x45
61d3795d63SJagan Teki #define PF8X00_WD_COUNTER 0x46
62d3795d63SJagan Teki #define PF8X00_FAULT_COUNTER 0x47
63d3795d63SJagan Teki #define PF8X00_FSAFE_COUNTER 0x48
64d3795d63SJagan Teki #define PF8X00_FAULT_TIMER 0x49
65d3795d63SJagan Teki #define PF8X00_AMUX 0x4a
66d3795d63SJagan Teki #define PF8X00_SW1_CONFIG1 0x4d
67d3795d63SJagan Teki #define PF8X00_LDO1_CONFIG1 0x85
68d3795d63SJagan Teki #define PF8X00_VSNVS_CONFIG1 0x9d
69d3795d63SJagan Teki #define PF8X00_PAGE_SELECT 0x9f
70d3795d63SJagan Teki
71d3795d63SJagan Teki /* regulators */
72d3795d63SJagan Teki enum pf8x00_regulators {
73d3795d63SJagan Teki PF8X00_LDO1,
74d3795d63SJagan Teki PF8X00_LDO2,
75d3795d63SJagan Teki PF8X00_LDO3,
76d3795d63SJagan Teki PF8X00_LDO4,
77d3795d63SJagan Teki PF8X00_BUCK1,
78d3795d63SJagan Teki PF8X00_BUCK2,
79d3795d63SJagan Teki PF8X00_BUCK3,
80d3795d63SJagan Teki PF8X00_BUCK4,
81d3795d63SJagan Teki PF8X00_BUCK5,
82d3795d63SJagan Teki PF8X00_BUCK6,
83d3795d63SJagan Teki PF8X00_BUCK7,
84d3795d63SJagan Teki PF8X00_VSNVS,
85d3795d63SJagan Teki
86d3795d63SJagan Teki PF8X00_MAX_REGULATORS,
87d3795d63SJagan Teki };
88d3795d63SJagan Teki
89d3795d63SJagan Teki enum pf8x00_buck_states {
90d3795d63SJagan Teki SW_CONFIG1,
91d3795d63SJagan Teki SW_CONFIG2,
92d3795d63SJagan Teki SW_PWRUP,
93d3795d63SJagan Teki SW_MODE1,
94d3795d63SJagan Teki SW_RUN_VOLT,
95d3795d63SJagan Teki SW_STBY_VOLT,
96d3795d63SJagan Teki };
97d3795d63SJagan Teki #define PF8X00_SW_BASE(i) (8 * (i - PF8X00_BUCK1) + PF8X00_SW1_CONFIG1)
98d3795d63SJagan Teki
99d3795d63SJagan Teki enum pf8x00_ldo_states {
100d3795d63SJagan Teki LDO_CONFIG1,
101d3795d63SJagan Teki LDO_CONFIG2,
102d3795d63SJagan Teki LDO_PWRUP,
103d3795d63SJagan Teki LDO_RUN_VOLT,
104d3795d63SJagan Teki LDO_STBY_VOLT,
105d3795d63SJagan Teki };
106d3795d63SJagan Teki #define PF8X00_LDO_BASE(i) (6 * (i - PF8X00_LDO1) + PF8X00_LDO1_CONFIG1)
107d3795d63SJagan Teki
108d3795d63SJagan Teki enum swxilim_bits {
109d3795d63SJagan Teki SWXILIM_2100_MA,
110d3795d63SJagan Teki SWXILIM_2600_MA,
111d3795d63SJagan Teki SWXILIM_3000_MA,
112d3795d63SJagan Teki SWXILIM_4500_MA,
113d3795d63SJagan Teki };
114d3795d63SJagan Teki #define PF8X00_SWXILIM_SHIFT 3
115d3795d63SJagan Teki #define PF8X00_SWXILIM_MASK GENMASK(4, 3)
116d3795d63SJagan Teki #define PF8X00_SWXPHASE_MASK GENMASK(2, 0)
117d3795d63SJagan Teki #define PF8X00_SWXPHASE_SHIFT 7
118d3795d63SJagan Teki
119d3795d63SJagan Teki enum pf8x00_devid {
120d3795d63SJagan Teki PF8100 = 0x0,
121d3795d63SJagan Teki PF8121A = BIT(1),
122d3795d63SJagan Teki PF8200 = BIT(3),
123d3795d63SJagan Teki };
124d3795d63SJagan Teki #define PF8X00_FAM BIT(6)
125d3795d63SJagan Teki #define PF8X00_DEVICE_FAM_MASK GENMASK(7, 4)
126d3795d63SJagan Teki #define PF8X00_DEVICE_ID_MASK GENMASK(3, 0)
127d3795d63SJagan Teki
1287fefe72bSChristoph Fritz struct pf8x00_regulator_data {
129d3795d63SJagan Teki struct regulator_desc desc;
1307fefe72bSChristoph Fritz unsigned int suspend_enable_reg;
1317fefe72bSChristoph Fritz unsigned int suspend_enable_mask;
1327fefe72bSChristoph Fritz unsigned int suspend_voltage_reg;
1337fefe72bSChristoph Fritz unsigned int suspend_voltage_cache;
134d3795d63SJagan Teki };
135d3795d63SJagan Teki
136d3795d63SJagan Teki struct pf8x00_chip {
137d3795d63SJagan Teki struct regmap *regmap;
138d3795d63SJagan Teki struct device *dev;
139d3795d63SJagan Teki };
140d3795d63SJagan Teki
141d3795d63SJagan Teki static const struct regmap_config pf8x00_regmap_config = {
142d3795d63SJagan Teki .reg_bits = 8,
143d3795d63SJagan Teki .val_bits = 8,
144d3795d63SJagan Teki .max_register = PF8X00_PAGE_SELECT,
145d3795d63SJagan Teki .cache_type = REGCACHE_RBTREE,
146d3795d63SJagan Teki };
147d3795d63SJagan Teki
148d3795d63SJagan Teki /* VLDOx output: 1.5V to 5.0V */
149d3795d63SJagan Teki static const int pf8x00_ldo_voltages[] = {
150d3795d63SJagan Teki 1500000, 1600000, 1800000, 1850000, 2150000, 2500000, 2800000, 3000000,
151d3795d63SJagan Teki 3100000, 3150000, 3200000, 3300000, 3350000, 1650000, 1700000, 5000000,
152d3795d63SJagan Teki };
153d3795d63SJagan Teki
154245f5f65SAdrien Grassein /* Output: 2.1A to 4.5A */
155245f5f65SAdrien Grassein static const unsigned int pf8x00_sw_current_table[] = {
156245f5f65SAdrien Grassein 2100000, 2600000, 3000000, 4500000,
157245f5f65SAdrien Grassein };
158d3795d63SJagan Teki
159d3795d63SJagan Teki /* Output: 0.4V to 1.8V */
16035a93349SAdrien Grassein #define PF8XOO_SW1_6_VOLTAGE_NUM 0xB2
16135a93349SAdrien Grassein static const struct linear_range pf8x00_sw1_to_6_voltages[] = {
16235a93349SAdrien Grassein REGULATOR_LINEAR_RANGE(400000, 0x00, 0xB0, 6250),
16335a93349SAdrien Grassein REGULATOR_LINEAR_RANGE(1800000, 0xB1, 0xB1, 0),
164d3795d63SJagan Teki };
165d3795d63SJagan Teki
166d3795d63SJagan Teki /* Output: 1.0V to 4.1V */
167d3795d63SJagan Teki static const int pf8x00_sw7_voltages[] = {
168d3795d63SJagan Teki 1000000, 1100000, 1200000, 1250000, 1300000, 1350000, 1500000, 1600000,
169d3795d63SJagan Teki 1800000, 1850000, 2000000, 2100000, 2150000, 2250000, 2300000, 2400000,
170d3795d63SJagan Teki 2500000, 2800000, 3150000, 3200000, 3250000, 3300000, 3350000, 3400000,
171d3795d63SJagan Teki 3500000, 3800000, 4000000, 4100000, 4100000, 4100000, 4100000, 4100000,
172d3795d63SJagan Teki };
173d3795d63SJagan Teki
174d3795d63SJagan Teki /* Output: 1.8V, 3.0V, or 3.3V */
175d3795d63SJagan Teki static const int pf8x00_vsnvs_voltages[] = {
176d3795d63SJagan Teki 0, 1800000, 3000000, 3300000,
177d3795d63SJagan Teki };
178d3795d63SJagan Teki
swxilim_select(struct pf8x00_chip * chip,int id,int ilim)179245f5f65SAdrien Grassein static void swxilim_select(struct pf8x00_chip *chip, int id, int ilim)
180d3795d63SJagan Teki {
181d3795d63SJagan Teki u8 ilim_sel;
182245f5f65SAdrien Grassein u8 reg = PF8X00_SW_BASE(id) + SW_CONFIG2;
183d3795d63SJagan Teki
184d3795d63SJagan Teki switch (ilim) {
185d3795d63SJagan Teki case 2100:
186d3795d63SJagan Teki ilim_sel = SWXILIM_2100_MA;
187d3795d63SJagan Teki break;
188d3795d63SJagan Teki case 2600:
189d3795d63SJagan Teki ilim_sel = SWXILIM_2600_MA;
190d3795d63SJagan Teki break;
191d3795d63SJagan Teki case 3000:
192d3795d63SJagan Teki ilim_sel = SWXILIM_3000_MA;
193d3795d63SJagan Teki break;
194d3795d63SJagan Teki case 4500:
195d3795d63SJagan Teki ilim_sel = SWXILIM_4500_MA;
196d3795d63SJagan Teki break;
197d3795d63SJagan Teki default:
198d3795d63SJagan Teki ilim_sel = SWXILIM_2100_MA;
199d3795d63SJagan Teki break;
200d3795d63SJagan Teki }
201d3795d63SJagan Teki
202245f5f65SAdrien Grassein regmap_update_bits(chip->regmap, reg,
203245f5f65SAdrien Grassein PF8X00_SWXILIM_MASK,
204245f5f65SAdrien Grassein ilim_sel << PF8X00_SWXILIM_SHIFT);
205245f5f65SAdrien Grassein }
206245f5f65SAdrien Grassein
handle_ilim_property(struct device_node * np,const struct regulator_desc * desc,struct regulator_config * config)207245f5f65SAdrien Grassein static void handle_ilim_property(struct device_node *np,
208245f5f65SAdrien Grassein const struct regulator_desc *desc,
209245f5f65SAdrien Grassein struct regulator_config *config)
210245f5f65SAdrien Grassein {
211245f5f65SAdrien Grassein struct pf8x00_chip *chip = config->driver_data;
212245f5f65SAdrien Grassein int ret;
213245f5f65SAdrien Grassein int val;
214245f5f65SAdrien Grassein
215245f5f65SAdrien Grassein if ((desc->id >= PF8X00_BUCK1) && (desc->id <= PF8X00_BUCK7)) {
216245f5f65SAdrien Grassein ret = of_property_read_u32(np, "nxp,ilim-ma", &val);
217245f5f65SAdrien Grassein if (ret) {
218245f5f65SAdrien Grassein dev_dbg(chip->dev, "unspecified ilim for BUCK%d, use value stored in OTP\n",
219245f5f65SAdrien Grassein desc->id - PF8X00_LDO4);
220245f5f65SAdrien Grassein return;
221245f5f65SAdrien Grassein }
222245f5f65SAdrien Grassein
223245f5f65SAdrien Grassein dev_warn(chip->dev, "nxp,ilim-ma is deprecated, please use regulator-max-microamp\n");
224245f5f65SAdrien Grassein swxilim_select(chip, desc->id, val);
225245f5f65SAdrien Grassein
226245f5f65SAdrien Grassein } else
227245f5f65SAdrien Grassein dev_warn(chip->dev, "nxp,ilim-ma used with incorrect regulator (%d)\n", desc->id);
228d3795d63SJagan Teki }
229d3795d63SJagan Teki
handle_shift_property(struct device_node * np,const struct regulator_desc * desc,struct regulator_config * config)230475a5d85SAdrien Grassein static void handle_shift_property(struct device_node *np,
231475a5d85SAdrien Grassein const struct regulator_desc *desc,
232475a5d85SAdrien Grassein struct regulator_config *config)
233475a5d85SAdrien Grassein {
234475a5d85SAdrien Grassein unsigned char id = desc->id - PF8X00_LDO4;
235475a5d85SAdrien Grassein unsigned char reg = PF8X00_SW_BASE(id) + SW_CONFIG2;
236475a5d85SAdrien Grassein struct pf8x00_chip *chip = config->driver_data;
237475a5d85SAdrien Grassein
238475a5d85SAdrien Grassein int phase;
239475a5d85SAdrien Grassein int val;
240475a5d85SAdrien Grassein int ret;
241475a5d85SAdrien Grassein if ((desc->id >= PF8X00_BUCK1) && (desc->id <= PF8X00_BUCK7)) {
242475a5d85SAdrien Grassein ret = of_property_read_u32(np, "nxp,phase-shift", &val);
243475a5d85SAdrien Grassein if (ret) {
244475a5d85SAdrien Grassein dev_dbg(chip->dev,
245475a5d85SAdrien Grassein "unspecified phase-shift for BUCK%d, using OTP configuration\n",
246475a5d85SAdrien Grassein id);
247475a5d85SAdrien Grassein return;
248475a5d85SAdrien Grassein }
249475a5d85SAdrien Grassein
250475a5d85SAdrien Grassein if (val < 0 || val > 315 || val % 45 != 0) {
251475a5d85SAdrien Grassein dev_warn(config->dev,
252475a5d85SAdrien Grassein "invalid phase_shift %d for BUCK%d, using OTP configuration\n",
253475a5d85SAdrien Grassein val, id);
254475a5d85SAdrien Grassein return;
255475a5d85SAdrien Grassein }
256475a5d85SAdrien Grassein
257475a5d85SAdrien Grassein phase = val / 45;
258475a5d85SAdrien Grassein
259475a5d85SAdrien Grassein if (phase >= 1)
260475a5d85SAdrien Grassein phase -= 1;
261475a5d85SAdrien Grassein else
262475a5d85SAdrien Grassein phase = PF8X00_SWXPHASE_SHIFT;
263475a5d85SAdrien Grassein
264475a5d85SAdrien Grassein regmap_update_bits(chip->regmap, reg,
265475a5d85SAdrien Grassein PF8X00_SWXPHASE_MASK,
266475a5d85SAdrien Grassein phase);
267475a5d85SAdrien Grassein } else
268475a5d85SAdrien Grassein dev_warn(chip->dev, "nxp,phase-shift used with incorrect regulator (%d)\n", id);
269475a5d85SAdrien Grassein
270d3795d63SJagan Teki }
271d3795d63SJagan Teki
pf8x00_of_parse_cb(struct device_node * np,const struct regulator_desc * desc,struct regulator_config * config)272d3795d63SJagan Teki static int pf8x00_of_parse_cb(struct device_node *np,
273d3795d63SJagan Teki const struct regulator_desc *desc,
274d3795d63SJagan Teki struct regulator_config *config)
275d3795d63SJagan Teki {
276d3795d63SJagan Teki
277245f5f65SAdrien Grassein handle_ilim_property(np, desc, config);
278475a5d85SAdrien Grassein handle_shift_property(np, desc, config);
279d3795d63SJagan Teki
280d3795d63SJagan Teki return 0;
281d3795d63SJagan Teki }
282d3795d63SJagan Teki
pf8x00_suspend_enable(struct regulator_dev * rdev)2837fefe72bSChristoph Fritz static int pf8x00_suspend_enable(struct regulator_dev *rdev)
2847fefe72bSChristoph Fritz {
2857fefe72bSChristoph Fritz struct pf8x00_regulator_data *regl = rdev_get_drvdata(rdev);
2867fefe72bSChristoph Fritz struct regmap *rmap = rdev_get_regmap(rdev);
2877fefe72bSChristoph Fritz
2887fefe72bSChristoph Fritz return regmap_update_bits(rmap, regl->suspend_enable_reg,
2897fefe72bSChristoph Fritz regl->suspend_enable_mask,
2907fefe72bSChristoph Fritz regl->suspend_enable_mask);
2917fefe72bSChristoph Fritz }
2927fefe72bSChristoph Fritz
pf8x00_suspend_disable(struct regulator_dev * rdev)2937fefe72bSChristoph Fritz static int pf8x00_suspend_disable(struct regulator_dev *rdev)
2947fefe72bSChristoph Fritz {
2957fefe72bSChristoph Fritz struct pf8x00_regulator_data *regl = rdev_get_drvdata(rdev);
2967fefe72bSChristoph Fritz struct regmap *rmap = rdev_get_regmap(rdev);
2977fefe72bSChristoph Fritz
2987fefe72bSChristoph Fritz return regmap_update_bits(rmap, regl->suspend_enable_reg,
2997fefe72bSChristoph Fritz regl->suspend_enable_mask, 0);
3007fefe72bSChristoph Fritz }
3017fefe72bSChristoph Fritz
pf8x00_set_suspend_voltage(struct regulator_dev * rdev,int uV)3027fefe72bSChristoph Fritz static int pf8x00_set_suspend_voltage(struct regulator_dev *rdev, int uV)
3037fefe72bSChristoph Fritz {
3047fefe72bSChristoph Fritz struct pf8x00_regulator_data *regl = rdev_get_drvdata(rdev);
305d3795d63SJagan Teki int ret;
306d3795d63SJagan Teki
3077fefe72bSChristoph Fritz if (regl->suspend_voltage_cache == uV)
3087fefe72bSChristoph Fritz return 0;
309d3795d63SJagan Teki
3107fefe72bSChristoph Fritz ret = regulator_map_voltage_iterate(rdev, uV, uV);
3117fefe72bSChristoph Fritz if (ret < 0) {
3127fefe72bSChristoph Fritz dev_err(rdev_get_dev(rdev), "failed to map %i uV\n", uV);
3137fefe72bSChristoph Fritz return ret;
314d3795d63SJagan Teki }
315d3795d63SJagan Teki
3167fefe72bSChristoph Fritz dev_dbg(rdev_get_dev(rdev), "uV: %i, reg: 0x%x, msk: 0x%x, val: 0x%x\n",
3177fefe72bSChristoph Fritz uV, regl->suspend_voltage_reg, regl->desc.vsel_mask, ret);
3187fefe72bSChristoph Fritz ret = regmap_update_bits(rdev->regmap, regl->suspend_voltage_reg,
3197fefe72bSChristoph Fritz regl->desc.vsel_mask, ret);
3207fefe72bSChristoph Fritz if (ret < 0) {
3217fefe72bSChristoph Fritz dev_err(rdev_get_dev(rdev), "failed to set %i uV\n", uV);
3227fefe72bSChristoph Fritz return ret;
323d3795d63SJagan Teki }
324d3795d63SJagan Teki
3257fefe72bSChristoph Fritz regl->suspend_voltage_cache = uV;
326d3795d63SJagan Teki
327d3795d63SJagan Teki return 0;
328d3795d63SJagan Teki }
329d3795d63SJagan Teki
330d3795d63SJagan Teki static const struct regulator_ops pf8x00_ldo_ops = {
331d3795d63SJagan Teki .enable = regulator_enable_regmap,
332d3795d63SJagan Teki .disable = regulator_disable_regmap,
333d3795d63SJagan Teki .is_enabled = regulator_is_enabled_regmap,
334d3795d63SJagan Teki .list_voltage = regulator_list_voltage_table,
335d3795d63SJagan Teki .set_voltage_sel = regulator_set_voltage_sel_regmap,
336d3795d63SJagan Teki .get_voltage_sel = regulator_get_voltage_sel_regmap,
3377fefe72bSChristoph Fritz .set_suspend_enable = pf8x00_suspend_enable,
3387fefe72bSChristoph Fritz .set_suspend_disable = pf8x00_suspend_disable,
3397fefe72bSChristoph Fritz .set_suspend_voltage = pf8x00_set_suspend_voltage,
340d3795d63SJagan Teki };
341d3795d63SJagan Teki
34235a93349SAdrien Grassein
34335a93349SAdrien Grassein static const struct regulator_ops pf8x00_buck1_6_ops = {
34435a93349SAdrien Grassein .enable = regulator_enable_regmap,
34535a93349SAdrien Grassein .disable = regulator_disable_regmap,
34635a93349SAdrien Grassein .is_enabled = regulator_is_enabled_regmap,
34735a93349SAdrien Grassein .list_voltage = regulator_list_voltage_linear_range,
34835a93349SAdrien Grassein .set_voltage_sel = regulator_set_voltage_sel_regmap,
34935a93349SAdrien Grassein .get_voltage_sel = regulator_get_voltage_sel_regmap,
35035a93349SAdrien Grassein .get_current_limit = regulator_get_current_limit_regmap,
35135a93349SAdrien Grassein .set_current_limit = regulator_set_current_limit_regmap,
3527fefe72bSChristoph Fritz .set_suspend_enable = pf8x00_suspend_enable,
3537fefe72bSChristoph Fritz .set_suspend_disable = pf8x00_suspend_disable,
3547fefe72bSChristoph Fritz .set_suspend_voltage = pf8x00_set_suspend_voltage,
35535a93349SAdrien Grassein };
35635a93349SAdrien Grassein
35735a93349SAdrien Grassein static const struct regulator_ops pf8x00_buck7_ops = {
358d3795d63SJagan Teki .enable = regulator_enable_regmap,
359d3795d63SJagan Teki .disable = regulator_disable_regmap,
360d3795d63SJagan Teki .is_enabled = regulator_is_enabled_regmap,
361d3795d63SJagan Teki .list_voltage = regulator_list_voltage_table,
3621e50433cSAxel Lin .map_voltage = regulator_map_voltage_ascend,
363d3795d63SJagan Teki .set_voltage_sel = regulator_set_voltage_sel_regmap,
364d3795d63SJagan Teki .get_voltage_sel = regulator_get_voltage_sel_regmap,
365245f5f65SAdrien Grassein .get_current_limit = regulator_get_current_limit_regmap,
366245f5f65SAdrien Grassein .set_current_limit = regulator_set_current_limit_regmap,
3677fefe72bSChristoph Fritz .set_suspend_enable = pf8x00_suspend_enable,
3687fefe72bSChristoph Fritz .set_suspend_disable = pf8x00_suspend_disable,
369d3795d63SJagan Teki };
370d3795d63SJagan Teki
371d3795d63SJagan Teki static const struct regulator_ops pf8x00_vsnvs_ops = {
372d3795d63SJagan Teki .enable = regulator_enable_regmap,
373d3795d63SJagan Teki .disable = regulator_disable_regmap,
374d3795d63SJagan Teki .is_enabled = regulator_is_enabled_regmap,
375d3795d63SJagan Teki .list_voltage = regulator_list_voltage_table,
376d3795d63SJagan Teki .map_voltage = regulator_map_voltage_ascend,
377d3795d63SJagan Teki .set_voltage_sel = regulator_set_voltage_sel_regmap,
378d3795d63SJagan Teki .get_voltage_sel = regulator_get_voltage_sel_regmap,
379d3795d63SJagan Teki };
380d3795d63SJagan Teki
381d3795d63SJagan Teki #define PF8X00LDO(_id, _name, base, voltages) \
382d3795d63SJagan Teki [PF8X00_LDO ## _id] = { \
383d3795d63SJagan Teki .desc = { \
384d3795d63SJagan Teki .name = _name, \
385d3795d63SJagan Teki .of_match = _name, \
386d3795d63SJagan Teki .regulators_node = "regulators", \
387d3795d63SJagan Teki .n_voltages = ARRAY_SIZE(voltages), \
388d3795d63SJagan Teki .ops = &pf8x00_ldo_ops, \
389d3795d63SJagan Teki .type = REGULATOR_VOLTAGE, \
390d3795d63SJagan Teki .id = PF8X00_LDO ## _id, \
391d3795d63SJagan Teki .owner = THIS_MODULE, \
392d3795d63SJagan Teki .volt_table = voltages, \
393d3795d63SJagan Teki .vsel_reg = (base) + LDO_RUN_VOLT, \
394d3795d63SJagan Teki .vsel_mask = 0xff, \
395d3795d63SJagan Teki .enable_reg = (base) + LDO_CONFIG2, \
396d3795d63SJagan Teki .enable_val = 0x2, \
397d3795d63SJagan Teki .disable_val = 0x0, \
398d3795d63SJagan Teki .enable_mask = 2, \
399d3795d63SJagan Teki }, \
4007fefe72bSChristoph Fritz .suspend_enable_reg = (base) + LDO_CONFIG2, \
4017fefe72bSChristoph Fritz .suspend_enable_mask = 1, \
4027fefe72bSChristoph Fritz .suspend_voltage_reg = (base) + LDO_STBY_VOLT, \
403d3795d63SJagan Teki }
404d3795d63SJagan Teki
405d3795d63SJagan Teki #define PF8X00BUCK(_id, _name, base, voltages) \
406d3795d63SJagan Teki [PF8X00_BUCK ## _id] = { \
407d3795d63SJagan Teki .desc = { \
408d3795d63SJagan Teki .name = _name, \
409d3795d63SJagan Teki .of_match = _name, \
410d3795d63SJagan Teki .regulators_node = "regulators", \
411d3795d63SJagan Teki .of_parse_cb = pf8x00_of_parse_cb, \
41235a93349SAdrien Grassein .n_voltages = PF8XOO_SW1_6_VOLTAGE_NUM, \
41335a93349SAdrien Grassein .ops = &pf8x00_buck1_6_ops, \
414d3795d63SJagan Teki .type = REGULATOR_VOLTAGE, \
415d3795d63SJagan Teki .id = PF8X00_BUCK ## _id, \
416d3795d63SJagan Teki .owner = THIS_MODULE, \
4174288b4ccSChristoph Fritz .ramp_delay = 19000, \
41835a93349SAdrien Grassein .linear_ranges = pf8x00_sw1_to_6_voltages, \
41935a93349SAdrien Grassein .n_linear_ranges = \
42035a93349SAdrien Grassein ARRAY_SIZE(pf8x00_sw1_to_6_voltages), \
42135a93349SAdrien Grassein .vsel_reg = (base) + SW_RUN_VOLT, \
42235a93349SAdrien Grassein .vsel_mask = 0xff, \
42335a93349SAdrien Grassein .curr_table = pf8x00_sw_current_table, \
42435a93349SAdrien Grassein .n_current_limits = \
42535a93349SAdrien Grassein ARRAY_SIZE(pf8x00_sw_current_table), \
42635a93349SAdrien Grassein .csel_reg = (base) + SW_CONFIG2, \
42735a93349SAdrien Grassein .csel_mask = PF8X00_SWXILIM_MASK, \
42835a93349SAdrien Grassein .enable_reg = (base) + SW_MODE1, \
42935a93349SAdrien Grassein .enable_val = 0x3, \
43035a93349SAdrien Grassein .disable_val = 0x0, \
43135a93349SAdrien Grassein .enable_mask = 0x3, \
43235a93349SAdrien Grassein .enable_time = 500, \
43335a93349SAdrien Grassein }, \
4347fefe72bSChristoph Fritz .suspend_enable_reg = (base) + SW_MODE1, \
4357fefe72bSChristoph Fritz .suspend_enable_mask = 0xc, \
4367fefe72bSChristoph Fritz .suspend_voltage_reg = (base) + SW_STBY_VOLT, \
43735a93349SAdrien Grassein }
43835a93349SAdrien Grassein
43935a93349SAdrien Grassein #define PF8X00BUCK7(_name, base, voltages) \
44035a93349SAdrien Grassein [PF8X00_BUCK7] = { \
44135a93349SAdrien Grassein .desc = { \
44235a93349SAdrien Grassein .name = _name, \
44335a93349SAdrien Grassein .of_match = _name, \
44435a93349SAdrien Grassein .regulators_node = "regulators", \
44535a93349SAdrien Grassein .of_parse_cb = pf8x00_of_parse_cb, \
44635a93349SAdrien Grassein .n_voltages = ARRAY_SIZE(voltages), \
44735a93349SAdrien Grassein .ops = &pf8x00_buck7_ops, \
44835a93349SAdrien Grassein .type = REGULATOR_VOLTAGE, \
44935a93349SAdrien Grassein .id = PF8X00_BUCK7, \
45035a93349SAdrien Grassein .owner = THIS_MODULE, \
4514288b4ccSChristoph Fritz .ramp_delay = 19000, \
452d3795d63SJagan Teki .volt_table = voltages, \
453d3795d63SJagan Teki .vsel_reg = (base) + SW_RUN_VOLT, \
454d3795d63SJagan Teki .vsel_mask = 0xff, \
455245f5f65SAdrien Grassein .curr_table = pf8x00_sw_current_table, \
456245f5f65SAdrien Grassein .n_current_limits = \
457245f5f65SAdrien Grassein ARRAY_SIZE(pf8x00_sw_current_table), \
458245f5f65SAdrien Grassein .csel_reg = (base) + SW_CONFIG2, \
459245f5f65SAdrien Grassein .csel_mask = PF8X00_SWXILIM_MASK, \
460d3795d63SJagan Teki .enable_reg = (base) + SW_MODE1, \
461d3795d63SJagan Teki .enable_val = 0x3, \
462d3795d63SJagan Teki .disable_val = 0x0, \
463d3795d63SJagan Teki .enable_mask = 0x3, \
464d3795d63SJagan Teki .enable_time = 500, \
465d3795d63SJagan Teki }, \
466d3795d63SJagan Teki }
467d3795d63SJagan Teki
46835a93349SAdrien Grassein
469d3795d63SJagan Teki #define PF8X00VSNVS(_name, base, voltages) \
470d3795d63SJagan Teki [PF8X00_VSNVS] = { \
471d3795d63SJagan Teki .desc = { \
472d3795d63SJagan Teki .name = _name, \
473d3795d63SJagan Teki .of_match = _name, \
474d3795d63SJagan Teki .regulators_node = "regulators", \
475d3795d63SJagan Teki .n_voltages = ARRAY_SIZE(voltages), \
476d3795d63SJagan Teki .ops = &pf8x00_vsnvs_ops, \
477d3795d63SJagan Teki .type = REGULATOR_VOLTAGE, \
478d3795d63SJagan Teki .id = PF8X00_VSNVS, \
479d3795d63SJagan Teki .owner = THIS_MODULE, \
480d3795d63SJagan Teki .volt_table = voltages, \
481d3795d63SJagan Teki .vsel_reg = (base), \
482d3795d63SJagan Teki .vsel_mask = 0x3, \
483d3795d63SJagan Teki }, \
484d3795d63SJagan Teki }
485d3795d63SJagan Teki
4867fefe72bSChristoph Fritz static struct pf8x00_regulator_data pf8x00_regs_data[PF8X00_MAX_REGULATORS] = {
487d3795d63SJagan Teki PF8X00LDO(1, "ldo1", PF8X00_LDO_BASE(PF8X00_LDO1), pf8x00_ldo_voltages),
488d3795d63SJagan Teki PF8X00LDO(2, "ldo2", PF8X00_LDO_BASE(PF8X00_LDO2), pf8x00_ldo_voltages),
489d3795d63SJagan Teki PF8X00LDO(3, "ldo3", PF8X00_LDO_BASE(PF8X00_LDO3), pf8x00_ldo_voltages),
490d3795d63SJagan Teki PF8X00LDO(4, "ldo4", PF8X00_LDO_BASE(PF8X00_LDO4), pf8x00_ldo_voltages),
491d3795d63SJagan Teki PF8X00BUCK(1, "buck1", PF8X00_SW_BASE(PF8X00_BUCK1), pf8x00_sw1_to_6_voltages),
492d3795d63SJagan Teki PF8X00BUCK(2, "buck2", PF8X00_SW_BASE(PF8X00_BUCK2), pf8x00_sw1_to_6_voltages),
493d3795d63SJagan Teki PF8X00BUCK(3, "buck3", PF8X00_SW_BASE(PF8X00_BUCK3), pf8x00_sw1_to_6_voltages),
494d3795d63SJagan Teki PF8X00BUCK(4, "buck4", PF8X00_SW_BASE(PF8X00_BUCK4), pf8x00_sw1_to_6_voltages),
495d3795d63SJagan Teki PF8X00BUCK(5, "buck5", PF8X00_SW_BASE(PF8X00_BUCK5), pf8x00_sw1_to_6_voltages),
496d3795d63SJagan Teki PF8X00BUCK(6, "buck6", PF8X00_SW_BASE(PF8X00_BUCK6), pf8x00_sw1_to_6_voltages),
49735a93349SAdrien Grassein PF8X00BUCK7("buck7", PF8X00_SW_BASE(PF8X00_BUCK7), pf8x00_sw7_voltages),
498d3795d63SJagan Teki PF8X00VSNVS("vsnvs", PF8X00_VSNVS_CONFIG1, pf8x00_vsnvs_voltages),
499d3795d63SJagan Teki };
500d3795d63SJagan Teki
pf8x00_identify(struct pf8x00_chip * chip)501d3795d63SJagan Teki static int pf8x00_identify(struct pf8x00_chip *chip)
502d3795d63SJagan Teki {
503d3795d63SJagan Teki unsigned int value;
504d3795d63SJagan Teki u8 dev_fam, dev_id;
505d3795d63SJagan Teki const char *name = NULL;
506d3795d63SJagan Teki int ret;
507d3795d63SJagan Teki
508d3795d63SJagan Teki ret = regmap_read(chip->regmap, PF8X00_DEVICEID, &value);
509d3795d63SJagan Teki if (ret) {
510d3795d63SJagan Teki dev_err(chip->dev, "failed to read chip family\n");
511d3795d63SJagan Teki return ret;
512d3795d63SJagan Teki }
513d3795d63SJagan Teki
514d3795d63SJagan Teki dev_fam = value & PF8X00_DEVICE_FAM_MASK;
515d3795d63SJagan Teki switch (dev_fam) {
516d3795d63SJagan Teki case PF8X00_FAM:
517d3795d63SJagan Teki break;
518d3795d63SJagan Teki default:
519d3795d63SJagan Teki dev_err(chip->dev,
520d3795d63SJagan Teki "Chip 0x%x is not from PF8X00 family\n", dev_fam);
521d3795d63SJagan Teki return ret;
522d3795d63SJagan Teki }
523d3795d63SJagan Teki
524d3795d63SJagan Teki dev_id = value & PF8X00_DEVICE_ID_MASK;
525d3795d63SJagan Teki switch (dev_id) {
526d3795d63SJagan Teki case PF8100:
527d3795d63SJagan Teki name = "PF8100";
528d3795d63SJagan Teki break;
529d3795d63SJagan Teki case PF8121A:
530d3795d63SJagan Teki name = "PF8121A";
531d3795d63SJagan Teki break;
532d3795d63SJagan Teki case PF8200:
53364f09ea1SAxel Lin name = "PF8200";
534d3795d63SJagan Teki break;
535d3795d63SJagan Teki default:
536d3795d63SJagan Teki dev_err(chip->dev, "Unknown pf8x00 device id 0x%x\n", dev_id);
537d3795d63SJagan Teki return -ENODEV;
538d3795d63SJagan Teki }
539d3795d63SJagan Teki
540d3795d63SJagan Teki dev_info(chip->dev, "%s PMIC found.\n", name);
541d3795d63SJagan Teki
542d3795d63SJagan Teki return 0;
543d3795d63SJagan Teki }
544d3795d63SJagan Teki
pf8x00_i2c_probe(struct i2c_client * client)545d3795d63SJagan Teki static int pf8x00_i2c_probe(struct i2c_client *client)
546d3795d63SJagan Teki {
547d3795d63SJagan Teki struct regulator_config config = { NULL, };
548d3795d63SJagan Teki struct pf8x00_chip *chip;
549d3795d63SJagan Teki int id;
550d3795d63SJagan Teki int ret;
551d3795d63SJagan Teki
552d3795d63SJagan Teki chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
553d3795d63SJagan Teki if (!chip)
554d3795d63SJagan Teki return -ENOMEM;
555d3795d63SJagan Teki
556d3795d63SJagan Teki i2c_set_clientdata(client, chip);
557d3795d63SJagan Teki chip->dev = &client->dev;
558d3795d63SJagan Teki
559d3795d63SJagan Teki chip->regmap = devm_regmap_init_i2c(client, &pf8x00_regmap_config);
560d3795d63SJagan Teki if (IS_ERR(chip->regmap)) {
561d3795d63SJagan Teki ret = PTR_ERR(chip->regmap);
562d3795d63SJagan Teki dev_err(&client->dev,
563d3795d63SJagan Teki "regmap allocation failed with err %d\n", ret);
564d3795d63SJagan Teki return ret;
565d3795d63SJagan Teki }
566d3795d63SJagan Teki
567d3795d63SJagan Teki ret = pf8x00_identify(chip);
568d3795d63SJagan Teki if (ret)
569d3795d63SJagan Teki return ret;
570d3795d63SJagan Teki
5717fefe72bSChristoph Fritz for (id = 0; id < ARRAY_SIZE(pf8x00_regs_data); id++) {
5727fefe72bSChristoph Fritz struct pf8x00_regulator_data *data = &pf8x00_regs_data[id];
573d3795d63SJagan Teki struct regulator_dev *rdev;
574d3795d63SJagan Teki
575d3795d63SJagan Teki config.dev = chip->dev;
5767fefe72bSChristoph Fritz config.driver_data = data;
577d3795d63SJagan Teki config.regmap = chip->regmap;
578d3795d63SJagan Teki
579d3795d63SJagan Teki rdev = devm_regulator_register(&client->dev, &data->desc, &config);
580d3795d63SJagan Teki if (IS_ERR(rdev)) {
581d3795d63SJagan Teki dev_err(&client->dev,
582d3795d63SJagan Teki "failed to register %s regulator\n", data->desc.name);
583d3795d63SJagan Teki return PTR_ERR(rdev);
584d3795d63SJagan Teki }
585d3795d63SJagan Teki }
586d3795d63SJagan Teki
587d3795d63SJagan Teki return 0;
588d3795d63SJagan Teki }
589d3795d63SJagan Teki
590d3795d63SJagan Teki static const struct of_device_id pf8x00_dt_ids[] = {
591df9716ecSMark Brown { .compatible = "nxp,pf8100",},
592df9716ecSMark Brown { .compatible = "nxp,pf8121a",},
593df9716ecSMark Brown { .compatible = "nxp,pf8200",},
594d3795d63SJagan Teki { }
595d3795d63SJagan Teki };
596d3795d63SJagan Teki MODULE_DEVICE_TABLE(of, pf8x00_dt_ids);
597d3795d63SJagan Teki
598d3795d63SJagan Teki static const struct i2c_device_id pf8x00_i2c_id[] = {
599df9716ecSMark Brown { "pf8100", 0 },
600df9716ecSMark Brown { "pf8121a", 0 },
601df9716ecSMark Brown { "pf8200", 0 },
602d3795d63SJagan Teki {},
603d3795d63SJagan Teki };
604d3795d63SJagan Teki MODULE_DEVICE_TABLE(i2c, pf8x00_i2c_id);
605d3795d63SJagan Teki
606d3795d63SJagan Teki static struct i2c_driver pf8x00_regulator_driver = {
607d3795d63SJagan Teki .id_table = pf8x00_i2c_id,
608d3795d63SJagan Teki .driver = {
609d3795d63SJagan Teki .name = "pf8x00",
61046600ab1SDouglas Anderson .probe_type = PROBE_PREFER_ASYNCHRONOUS,
611d3795d63SJagan Teki .of_match_table = pf8x00_dt_ids,
612d3795d63SJagan Teki },
613*964e1865SUwe Kleine-König .probe = pf8x00_i2c_probe,
614d3795d63SJagan Teki };
615d3795d63SJagan Teki module_i2c_driver(pf8x00_regulator_driver);
616d3795d63SJagan Teki
617d3795d63SJagan Teki MODULE_AUTHOR("Jagan Teki <jagan@amarulasolutions.com>");
618d3795d63SJagan Teki MODULE_AUTHOR("Troy Kisky <troy.kisky@boundarydevices.com>");
619d3795d63SJagan Teki MODULE_DESCRIPTION("Regulator Driver for NXP's PF8100/PF8121A/PF8200 PMIC");
620d3795d63SJagan Teki MODULE_LICENSE("GPL v2");
621