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_DEFAULT		0
118d3795d63SJagan Teki #define PF8X00_SWXPHASE_SHIFT		7
119d3795d63SJagan Teki 
120d3795d63SJagan Teki enum pf8x00_devid {
121d3795d63SJagan Teki 	PF8100			= 0x0,
122d3795d63SJagan Teki 	PF8121A			= BIT(1),
123d3795d63SJagan Teki 	PF8200			= BIT(3),
124d3795d63SJagan Teki };
125d3795d63SJagan Teki #define PF8X00_FAM			BIT(6)
126d3795d63SJagan Teki #define PF8X00_DEVICE_FAM_MASK		GENMASK(7, 4)
127d3795d63SJagan Teki #define PF8X00_DEVICE_ID_MASK		GENMASK(3, 0)
128d3795d63SJagan Teki 
129d3795d63SJagan Teki struct pf8x00_regulator {
130d3795d63SJagan Teki 	struct regulator_desc desc;
131d3795d63SJagan Teki 	u8 phase_shift;
132d3795d63SJagan Teki };
133d3795d63SJagan Teki 
134d3795d63SJagan Teki struct pf8x00_chip {
135d3795d63SJagan Teki 	struct regmap *regmap;
136d3795d63SJagan Teki 	struct device *dev;
137d3795d63SJagan Teki };
138d3795d63SJagan Teki 
139d3795d63SJagan Teki static const struct regmap_config pf8x00_regmap_config = {
140d3795d63SJagan Teki 	.reg_bits = 8,
141d3795d63SJagan Teki 	.val_bits = 8,
142d3795d63SJagan Teki 	.max_register = PF8X00_PAGE_SELECT,
143d3795d63SJagan Teki 	.cache_type = REGCACHE_RBTREE,
144d3795d63SJagan Teki };
145d3795d63SJagan Teki 
146d3795d63SJagan Teki /* VLDOx output: 1.5V to 5.0V */
147d3795d63SJagan Teki static const int pf8x00_ldo_voltages[] = {
148d3795d63SJagan Teki 	1500000, 1600000, 1800000, 1850000, 2150000, 2500000, 2800000, 3000000,
149d3795d63SJagan Teki 	3100000, 3150000, 3200000, 3300000, 3350000, 1650000, 1700000, 5000000,
150d3795d63SJagan Teki };
151d3795d63SJagan Teki 
152*245f5f65SAdrien Grassein /* Output: 2.1A to 4.5A */
153*245f5f65SAdrien Grassein static const unsigned int pf8x00_sw_current_table[] = {
154*245f5f65SAdrien Grassein 	2100000, 2600000, 3000000, 4500000,
155*245f5f65SAdrien Grassein };
156*245f5f65SAdrien Grassein 
157d3795d63SJagan Teki #define SWV(i)		(6250 * i + 400000)
158d3795d63SJagan Teki #define SWV_LINE(i)	SWV(i*8+0), SWV(i*8+1), SWV(i*8+2), SWV(i*8+3), \
159d3795d63SJagan Teki 			SWV(i*8+4), SWV(i*8+5), SWV(i*8+6), SWV(i*8+7)
160d3795d63SJagan Teki 
161d3795d63SJagan Teki /* Output: 0.4V to 1.8V */
162d3795d63SJagan Teki static const int pf8x00_sw1_to_6_voltages[] = {
163d3795d63SJagan Teki 	SWV_LINE(0),
164d3795d63SJagan Teki 	SWV_LINE(1),
165d3795d63SJagan Teki 	SWV_LINE(2),
166d3795d63SJagan Teki 	SWV_LINE(3),
167d3795d63SJagan Teki 	SWV_LINE(4),
168d3795d63SJagan Teki 	SWV_LINE(5),
169d3795d63SJagan Teki 	SWV_LINE(6),
170d3795d63SJagan Teki 	SWV_LINE(7),
171d3795d63SJagan Teki 	SWV_LINE(8),
172d3795d63SJagan Teki 	SWV_LINE(9),
173d3795d63SJagan Teki 	SWV_LINE(10),
174d3795d63SJagan Teki 	SWV_LINE(11),
175d3795d63SJagan Teki 	SWV_LINE(12),
176d3795d63SJagan Teki 	SWV_LINE(13),
177d3795d63SJagan Teki 	SWV_LINE(14),
178d3795d63SJagan Teki 	SWV_LINE(15),
179d3795d63SJagan Teki 	SWV_LINE(16),
180d3795d63SJagan Teki 	SWV_LINE(17),
181d3795d63SJagan Teki 	SWV_LINE(18),
182d3795d63SJagan Teki 	SWV_LINE(19),
183d3795d63SJagan Teki 	SWV_LINE(20),
184d3795d63SJagan Teki 	SWV_LINE(21),
185d3795d63SJagan Teki 	1500000, 1800000,
186d3795d63SJagan Teki };
187d3795d63SJagan Teki 
188d3795d63SJagan Teki /* Output: 1.0V to 4.1V */
189d3795d63SJagan Teki static const int pf8x00_sw7_voltages[] = {
190d3795d63SJagan Teki 	1000000, 1100000, 1200000, 1250000, 1300000, 1350000, 1500000, 1600000,
191d3795d63SJagan Teki 	1800000, 1850000, 2000000, 2100000, 2150000, 2250000, 2300000, 2400000,
192d3795d63SJagan Teki 	2500000, 2800000, 3150000, 3200000, 3250000, 3300000, 3350000, 3400000,
193d3795d63SJagan Teki 	3500000, 3800000, 4000000, 4100000, 4100000, 4100000, 4100000, 4100000,
194d3795d63SJagan Teki };
195d3795d63SJagan Teki 
196d3795d63SJagan Teki /* Output: 1.8V, 3.0V, or 3.3V */
197d3795d63SJagan Teki static const int pf8x00_vsnvs_voltages[] = {
198d3795d63SJagan Teki 	0, 1800000, 3000000, 3300000,
199d3795d63SJagan Teki };
200d3795d63SJagan Teki 
201d3795d63SJagan Teki static struct pf8x00_regulator *desc_to_regulator(const struct regulator_desc *desc)
202d3795d63SJagan Teki {
203d3795d63SJagan Teki 	return container_of(desc, struct pf8x00_regulator, desc);
204d3795d63SJagan Teki }
205d3795d63SJagan Teki 
206*245f5f65SAdrien Grassein static void swxilim_select(struct pf8x00_chip *chip, int id, int ilim)
207d3795d63SJagan Teki {
208d3795d63SJagan Teki 	u8 ilim_sel;
209*245f5f65SAdrien Grassein 	u8 reg = PF8X00_SW_BASE(id) + SW_CONFIG2;
210d3795d63SJagan Teki 
211d3795d63SJagan Teki 	switch (ilim) {
212d3795d63SJagan Teki 	case 2100:
213d3795d63SJagan Teki 		ilim_sel = SWXILIM_2100_MA;
214d3795d63SJagan Teki 		break;
215d3795d63SJagan Teki 	case 2600:
216d3795d63SJagan Teki 		ilim_sel = SWXILIM_2600_MA;
217d3795d63SJagan Teki 		break;
218d3795d63SJagan Teki 	case 3000:
219d3795d63SJagan Teki 		ilim_sel = SWXILIM_3000_MA;
220d3795d63SJagan Teki 		break;
221d3795d63SJagan Teki 	case 4500:
222d3795d63SJagan Teki 		ilim_sel = SWXILIM_4500_MA;
223d3795d63SJagan Teki 		break;
224d3795d63SJagan Teki 	default:
225d3795d63SJagan Teki 		ilim_sel = SWXILIM_2100_MA;
226d3795d63SJagan Teki 		break;
227d3795d63SJagan Teki 	}
228d3795d63SJagan Teki 
229*245f5f65SAdrien Grassein 	regmap_update_bits(chip->regmap, reg,
230*245f5f65SAdrien Grassein 					PF8X00_SWXILIM_MASK,
231*245f5f65SAdrien Grassein 					ilim_sel << PF8X00_SWXILIM_SHIFT);
232*245f5f65SAdrien Grassein }
233*245f5f65SAdrien Grassein 
234*245f5f65SAdrien Grassein static void handle_ilim_property(struct device_node *np,
235*245f5f65SAdrien Grassein 			      const struct regulator_desc *desc,
236*245f5f65SAdrien Grassein 			      struct regulator_config *config)
237*245f5f65SAdrien Grassein {
238*245f5f65SAdrien Grassein 	struct pf8x00_chip *chip = config->driver_data;
239*245f5f65SAdrien Grassein 	int ret;
240*245f5f65SAdrien Grassein 	int val;
241*245f5f65SAdrien Grassein 
242*245f5f65SAdrien Grassein 	if ((desc->id >= PF8X00_BUCK1) && (desc->id <= PF8X00_BUCK7)) {
243*245f5f65SAdrien Grassein 		ret = of_property_read_u32(np, "nxp,ilim-ma", &val);
244*245f5f65SAdrien Grassein 		if (ret) {
245*245f5f65SAdrien Grassein 			dev_dbg(chip->dev, "unspecified ilim for BUCK%d, use value stored in OTP\n",
246*245f5f65SAdrien Grassein 				desc->id - PF8X00_LDO4);
247*245f5f65SAdrien Grassein 			return;
248*245f5f65SAdrien Grassein 		}
249*245f5f65SAdrien Grassein 
250*245f5f65SAdrien Grassein 		dev_warn(chip->dev, "nxp,ilim-ma is deprecated, please use regulator-max-microamp\n");
251*245f5f65SAdrien Grassein 		swxilim_select(chip, desc->id, val);
252*245f5f65SAdrien Grassein 
253*245f5f65SAdrien Grassein 	} else
254*245f5f65SAdrien Grassein 		dev_warn(chip->dev, "nxp,ilim-ma used with incorrect regulator (%d)\n", desc->id);
255d3795d63SJagan Teki }
256d3795d63SJagan Teki 
257d3795d63SJagan Teki static int pf8x00_of_parse_cb(struct device_node *np,
258d3795d63SJagan Teki 			      const struct regulator_desc *desc,
259d3795d63SJagan Teki 			      struct regulator_config *config)
260d3795d63SJagan Teki {
261d3795d63SJagan Teki 	struct pf8x00_regulator *data = desc_to_regulator(desc);
262d3795d63SJagan Teki 	struct pf8x00_chip *chip = config->driver_data;
263d3795d63SJagan Teki 	int phase;
264d3795d63SJagan Teki 	int val;
265d3795d63SJagan Teki 	int ret;
266d3795d63SJagan Teki 
267*245f5f65SAdrien Grassein 	handle_ilim_property(np, desc, config);
268d3795d63SJagan Teki 
269d3795d63SJagan Teki 	ret = of_property_read_u32(np, "nxp,phase-shift", &val);
270d3795d63SJagan Teki 	if (ret) {
271d3795d63SJagan Teki 		dev_dbg(chip->dev,
272d3795d63SJagan Teki 			"unspecified phase-shift for BUCK%d, use 0 degrees\n",
273d3795d63SJagan Teki 			desc->id - PF8X00_LDO4);
274d3795d63SJagan Teki 		val = PF8X00_SWXPHASE_DEFAULT;
275d3795d63SJagan Teki 	}
276d3795d63SJagan Teki 
277d3795d63SJagan Teki 	phase = val / 45;
278d3795d63SJagan Teki 	if ((phase * 45) != val) {
279d3795d63SJagan Teki 		dev_warn(config->dev,
280d3795d63SJagan Teki 			 "invalid phase_shift %d for BUCK%d, use 0 degrees\n",
281d3795d63SJagan Teki 			 (phase * 45), desc->id - PF8X00_LDO4);
282d3795d63SJagan Teki 		phase = PF8X00_SWXPHASE_SHIFT;
283d3795d63SJagan Teki 	}
284d3795d63SJagan Teki 
285d3795d63SJagan Teki 	data->phase_shift = (phase >= 1) ? phase - 1 : PF8X00_SWXPHASE_SHIFT;
286d3795d63SJagan Teki 
287d3795d63SJagan Teki 	return 0;
288d3795d63SJagan Teki }
289d3795d63SJagan Teki 
290d3795d63SJagan Teki static const struct regulator_ops pf8x00_ldo_ops = {
291d3795d63SJagan Teki 	.enable = regulator_enable_regmap,
292d3795d63SJagan Teki 	.disable = regulator_disable_regmap,
293d3795d63SJagan Teki 	.is_enabled = regulator_is_enabled_regmap,
294d3795d63SJagan Teki 	.list_voltage = regulator_list_voltage_table,
295d3795d63SJagan Teki 	.set_voltage_sel = regulator_set_voltage_sel_regmap,
296d3795d63SJagan Teki 	.get_voltage_sel = regulator_get_voltage_sel_regmap,
297d3795d63SJagan Teki };
298d3795d63SJagan Teki 
299d3795d63SJagan Teki static const struct regulator_ops pf8x00_buck_ops = {
300d3795d63SJagan Teki 	.enable = regulator_enable_regmap,
301d3795d63SJagan Teki 	.disable = regulator_disable_regmap,
302d3795d63SJagan Teki 	.is_enabled = regulator_is_enabled_regmap,
303d3795d63SJagan Teki 	.list_voltage = regulator_list_voltage_table,
304d3795d63SJagan Teki 	.set_voltage_sel = regulator_set_voltage_sel_regmap,
305d3795d63SJagan Teki 	.get_voltage_sel = regulator_get_voltage_sel_regmap,
306*245f5f65SAdrien Grassein 	.get_current_limit = regulator_get_current_limit_regmap,
307*245f5f65SAdrien Grassein 	.set_current_limit = regulator_set_current_limit_regmap,
308d3795d63SJagan Teki };
309d3795d63SJagan Teki 
310d3795d63SJagan Teki static const struct regulator_ops pf8x00_vsnvs_ops = {
311d3795d63SJagan Teki 	.enable = regulator_enable_regmap,
312d3795d63SJagan Teki 	.disable = regulator_disable_regmap,
313d3795d63SJagan Teki 	.is_enabled = regulator_is_enabled_regmap,
314d3795d63SJagan Teki 	.list_voltage = regulator_list_voltage_table,
315d3795d63SJagan Teki 	.map_voltage = regulator_map_voltage_ascend,
316d3795d63SJagan Teki 	.set_voltage_sel = regulator_set_voltage_sel_regmap,
317d3795d63SJagan Teki 	.get_voltage_sel = regulator_get_voltage_sel_regmap,
318d3795d63SJagan Teki };
319d3795d63SJagan Teki 
320d3795d63SJagan Teki #define PF8X00LDO(_id, _name, base, voltages)			\
321d3795d63SJagan Teki 	[PF8X00_LDO ## _id] = {					\
322d3795d63SJagan Teki 		.desc = {					\
323d3795d63SJagan Teki 			.name = _name,				\
324d3795d63SJagan Teki 			.of_match = _name,			\
325d3795d63SJagan Teki 			.regulators_node = "regulators",	\
326d3795d63SJagan Teki 			.n_voltages = ARRAY_SIZE(voltages),	\
327d3795d63SJagan Teki 			.ops = &pf8x00_ldo_ops,			\
328d3795d63SJagan Teki 			.type = REGULATOR_VOLTAGE,		\
329d3795d63SJagan Teki 			.id = PF8X00_LDO ## _id,		\
330d3795d63SJagan Teki 			.owner = THIS_MODULE,			\
331d3795d63SJagan Teki 			.volt_table = voltages,			\
332d3795d63SJagan Teki 			.vsel_reg = (base) + LDO_RUN_VOLT,	\
333d3795d63SJagan Teki 			.vsel_mask = 0xff,			\
334d3795d63SJagan Teki 			.enable_reg = (base) + LDO_CONFIG2,	\
335d3795d63SJagan Teki 			.enable_val = 0x2,			\
336d3795d63SJagan Teki 			.disable_val = 0x0,			\
337d3795d63SJagan Teki 			.enable_mask = 2,			\
338d3795d63SJagan Teki 		},						\
339d3795d63SJagan Teki 	}
340d3795d63SJagan Teki 
341d3795d63SJagan Teki #define PF8X00BUCK(_id, _name, base, voltages)			\
342d3795d63SJagan Teki 	[PF8X00_BUCK ## _id] = {				\
343d3795d63SJagan Teki 		.desc = {					\
344d3795d63SJagan Teki 			.name = _name,				\
345d3795d63SJagan Teki 			.of_match = _name,			\
346d3795d63SJagan Teki 			.regulators_node = "regulators",	\
347d3795d63SJagan Teki 			.of_parse_cb = pf8x00_of_parse_cb,	\
348d3795d63SJagan Teki 			.n_voltages = ARRAY_SIZE(voltages),	\
349d3795d63SJagan Teki 			.ops = &pf8x00_buck_ops,		\
350d3795d63SJagan Teki 			.type = REGULATOR_VOLTAGE,		\
351d3795d63SJagan Teki 			.id = PF8X00_BUCK ## _id,		\
352d3795d63SJagan Teki 			.owner = THIS_MODULE,			\
353d3795d63SJagan Teki 			.volt_table = voltages,			\
354d3795d63SJagan Teki 			.vsel_reg = (base) + SW_RUN_VOLT,	\
355d3795d63SJagan Teki 			.vsel_mask = 0xff,			\
356*245f5f65SAdrien Grassein 			.curr_table = pf8x00_sw_current_table, \
357*245f5f65SAdrien Grassein 			.n_current_limits = \
358*245f5f65SAdrien Grassein 				ARRAY_SIZE(pf8x00_sw_current_table), \
359*245f5f65SAdrien Grassein 			.csel_reg = (base) + SW_CONFIG2,	\
360*245f5f65SAdrien Grassein 			.csel_mask = PF8X00_SWXILIM_MASK,	\
361d3795d63SJagan Teki 			.enable_reg = (base) + SW_MODE1,	\
362d3795d63SJagan Teki 			.enable_val = 0x3,			\
363d3795d63SJagan Teki 			.disable_val = 0x0,			\
364d3795d63SJagan Teki 			.enable_mask = 0x3,			\
365d3795d63SJagan Teki 			.enable_time = 500,			\
366d3795d63SJagan Teki 		},						\
367d3795d63SJagan Teki 	}
368d3795d63SJagan Teki 
369d3795d63SJagan Teki #define PF8X00VSNVS(_name, base, voltages)			\
370d3795d63SJagan Teki 	[PF8X00_VSNVS] = {					\
371d3795d63SJagan Teki 		.desc = {					\
372d3795d63SJagan Teki 			.name = _name,				\
373d3795d63SJagan Teki 			.of_match = _name,			\
374d3795d63SJagan Teki 			.regulators_node = "regulators",	\
375d3795d63SJagan Teki 			.n_voltages = ARRAY_SIZE(voltages),	\
376d3795d63SJagan Teki 			.ops = &pf8x00_vsnvs_ops,		\
377d3795d63SJagan Teki 			.type = REGULATOR_VOLTAGE,		\
378d3795d63SJagan Teki 			.id = PF8X00_VSNVS,			\
379d3795d63SJagan Teki 			.owner = THIS_MODULE,			\
380d3795d63SJagan Teki 			.volt_table = voltages,			\
381d3795d63SJagan Teki 			.vsel_reg = (base),			\
382d3795d63SJagan Teki 			.vsel_mask = 0x3,			\
383d3795d63SJagan Teki 		},						\
384d3795d63SJagan Teki 	}
385d3795d63SJagan Teki 
386d3795d63SJagan Teki static struct pf8x00_regulator pf8x00_regulators_data[PF8X00_MAX_REGULATORS] = {
387d3795d63SJagan Teki 	PF8X00LDO(1, "ldo1", PF8X00_LDO_BASE(PF8X00_LDO1), pf8x00_ldo_voltages),
388d3795d63SJagan Teki 	PF8X00LDO(2, "ldo2", PF8X00_LDO_BASE(PF8X00_LDO2), pf8x00_ldo_voltages),
389d3795d63SJagan Teki 	PF8X00LDO(3, "ldo3", PF8X00_LDO_BASE(PF8X00_LDO3), pf8x00_ldo_voltages),
390d3795d63SJagan Teki 	PF8X00LDO(4, "ldo4", PF8X00_LDO_BASE(PF8X00_LDO4), pf8x00_ldo_voltages),
391d3795d63SJagan Teki 	PF8X00BUCK(1, "buck1", PF8X00_SW_BASE(PF8X00_BUCK1), pf8x00_sw1_to_6_voltages),
392d3795d63SJagan Teki 	PF8X00BUCK(2, "buck2", PF8X00_SW_BASE(PF8X00_BUCK2), pf8x00_sw1_to_6_voltages),
393d3795d63SJagan Teki 	PF8X00BUCK(3, "buck3", PF8X00_SW_BASE(PF8X00_BUCK3), pf8x00_sw1_to_6_voltages),
394d3795d63SJagan Teki 	PF8X00BUCK(4, "buck4", PF8X00_SW_BASE(PF8X00_BUCK4), pf8x00_sw1_to_6_voltages),
395d3795d63SJagan Teki 	PF8X00BUCK(5, "buck5", PF8X00_SW_BASE(PF8X00_BUCK5), pf8x00_sw1_to_6_voltages),
396d3795d63SJagan Teki 	PF8X00BUCK(6, "buck6", PF8X00_SW_BASE(PF8X00_BUCK6), pf8x00_sw1_to_6_voltages),
397d3795d63SJagan Teki 	PF8X00BUCK(7, "buck7", PF8X00_SW_BASE(PF8X00_BUCK7), pf8x00_sw7_voltages),
398d3795d63SJagan Teki 	PF8X00VSNVS("vsnvs", PF8X00_VSNVS_CONFIG1, pf8x00_vsnvs_voltages),
399d3795d63SJagan Teki };
400d3795d63SJagan Teki 
401d3795d63SJagan Teki static int pf8x00_identify(struct pf8x00_chip *chip)
402d3795d63SJagan Teki {
403d3795d63SJagan Teki 	unsigned int value;
404d3795d63SJagan Teki 	u8 dev_fam, dev_id;
405d3795d63SJagan Teki 	const char *name = NULL;
406d3795d63SJagan Teki 	int ret;
407d3795d63SJagan Teki 
408d3795d63SJagan Teki 	ret = regmap_read(chip->regmap, PF8X00_DEVICEID, &value);
409d3795d63SJagan Teki 	if (ret) {
410d3795d63SJagan Teki 		dev_err(chip->dev, "failed to read chip family\n");
411d3795d63SJagan Teki 		return ret;
412d3795d63SJagan Teki 	}
413d3795d63SJagan Teki 
414d3795d63SJagan Teki 	dev_fam = value & PF8X00_DEVICE_FAM_MASK;
415d3795d63SJagan Teki 	switch (dev_fam) {
416d3795d63SJagan Teki 	case PF8X00_FAM:
417d3795d63SJagan Teki 		break;
418d3795d63SJagan Teki 	default:
419d3795d63SJagan Teki 		dev_err(chip->dev,
420d3795d63SJagan Teki 			"Chip 0x%x is not from PF8X00 family\n", dev_fam);
421d3795d63SJagan Teki 		return ret;
422d3795d63SJagan Teki 	}
423d3795d63SJagan Teki 
424d3795d63SJagan Teki 	dev_id = value & PF8X00_DEVICE_ID_MASK;
425d3795d63SJagan Teki 	switch (dev_id) {
426d3795d63SJagan Teki 	case PF8100:
427d3795d63SJagan Teki 		name = "PF8100";
428d3795d63SJagan Teki 		break;
429d3795d63SJagan Teki 	case PF8121A:
430d3795d63SJagan Teki 		name = "PF8121A";
431d3795d63SJagan Teki 		break;
432d3795d63SJagan Teki 	case PF8200:
433d3795d63SJagan Teki 		name = "PF8100";
434d3795d63SJagan Teki 		break;
435d3795d63SJagan Teki 	default:
436d3795d63SJagan Teki 		dev_err(chip->dev, "Unknown pf8x00 device id 0x%x\n", dev_id);
437d3795d63SJagan Teki 		return -ENODEV;
438d3795d63SJagan Teki 	}
439d3795d63SJagan Teki 
440d3795d63SJagan Teki 	dev_info(chip->dev, "%s PMIC found.\n", name);
441d3795d63SJagan Teki 
442d3795d63SJagan Teki 	return 0;
443d3795d63SJagan Teki }
444d3795d63SJagan Teki 
445d3795d63SJagan Teki static int pf8x00_i2c_probe(struct i2c_client *client)
446d3795d63SJagan Teki {
447d3795d63SJagan Teki 	struct regulator_config config = { NULL, };
448d3795d63SJagan Teki 	struct pf8x00_chip *chip;
449d3795d63SJagan Teki 	int id;
450d3795d63SJagan Teki 	int ret;
451d3795d63SJagan Teki 
452d3795d63SJagan Teki 	chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
453d3795d63SJagan Teki 	if (!chip)
454d3795d63SJagan Teki 		return -ENOMEM;
455d3795d63SJagan Teki 
456d3795d63SJagan Teki 	i2c_set_clientdata(client, chip);
457d3795d63SJagan Teki 	chip->dev = &client->dev;
458d3795d63SJagan Teki 
459d3795d63SJagan Teki 	chip->regmap = devm_regmap_init_i2c(client, &pf8x00_regmap_config);
460d3795d63SJagan Teki 	if (IS_ERR(chip->regmap)) {
461d3795d63SJagan Teki 		ret = PTR_ERR(chip->regmap);
462d3795d63SJagan Teki 		dev_err(&client->dev,
463d3795d63SJagan Teki 			"regmap allocation failed with err %d\n", ret);
464d3795d63SJagan Teki 		return ret;
465d3795d63SJagan Teki 	}
466d3795d63SJagan Teki 
467d3795d63SJagan Teki 	ret = pf8x00_identify(chip);
468d3795d63SJagan Teki 	if (ret)
469d3795d63SJagan Teki 		return ret;
470d3795d63SJagan Teki 
471d3795d63SJagan Teki 	for (id = 0; id < ARRAY_SIZE(pf8x00_regulators_data); id++) {
472d3795d63SJagan Teki 		struct pf8x00_regulator *data = &pf8x00_regulators_data[id];
473d3795d63SJagan Teki 		struct regulator_dev *rdev;
474d3795d63SJagan Teki 
475d3795d63SJagan Teki 		config.dev = chip->dev;
476d3795d63SJagan Teki 		config.driver_data = chip;
477d3795d63SJagan Teki 		config.regmap = chip->regmap;
478d3795d63SJagan Teki 
479d3795d63SJagan Teki 		rdev = devm_regulator_register(&client->dev, &data->desc, &config);
480d3795d63SJagan Teki 		if (IS_ERR(rdev)) {
481d3795d63SJagan Teki 			dev_err(&client->dev,
482d3795d63SJagan Teki 				"failed to register %s regulator\n", data->desc.name);
483d3795d63SJagan Teki 			return PTR_ERR(rdev);
484d3795d63SJagan Teki 		}
485d3795d63SJagan Teki 
486d3795d63SJagan Teki 		if ((id >= PF8X00_BUCK1) && (id <= PF8X00_BUCK7)) {
487d3795d63SJagan Teki 			u8 reg = PF8X00_SW_BASE(id) + SW_CONFIG2;
488d3795d63SJagan Teki 
489d3795d63SJagan Teki 			regmap_update_bits(chip->regmap, reg,
490d3795d63SJagan Teki 					   PF8X00_SWXPHASE_MASK,
491d3795d63SJagan Teki 					   data->phase_shift);
492d3795d63SJagan Teki 		}
493d3795d63SJagan Teki 	}
494d3795d63SJagan Teki 
495d3795d63SJagan Teki 	return 0;
496d3795d63SJagan Teki }
497d3795d63SJagan Teki 
498d3795d63SJagan Teki static const struct of_device_id pf8x00_dt_ids[] = {
499df9716ecSMark Brown 	{ .compatible = "nxp,pf8100",},
500df9716ecSMark Brown 	{ .compatible = "nxp,pf8121a",},
501df9716ecSMark Brown 	{ .compatible = "nxp,pf8200",},
502d3795d63SJagan Teki 	{ }
503d3795d63SJagan Teki };
504d3795d63SJagan Teki MODULE_DEVICE_TABLE(of, pf8x00_dt_ids);
505d3795d63SJagan Teki 
506d3795d63SJagan Teki static const struct i2c_device_id pf8x00_i2c_id[] = {
507df9716ecSMark Brown 	{ "pf8100", 0 },
508df9716ecSMark Brown 	{ "pf8121a", 0 },
509df9716ecSMark Brown 	{ "pf8200", 0 },
510d3795d63SJagan Teki 	{},
511d3795d63SJagan Teki };
512d3795d63SJagan Teki MODULE_DEVICE_TABLE(i2c, pf8x00_i2c_id);
513d3795d63SJagan Teki 
514d3795d63SJagan Teki static struct i2c_driver pf8x00_regulator_driver = {
515d3795d63SJagan Teki 	.id_table = pf8x00_i2c_id,
516d3795d63SJagan Teki 	.driver = {
517d3795d63SJagan Teki 		.name = "pf8x00",
518d3795d63SJagan Teki 		.of_match_table = pf8x00_dt_ids,
519d3795d63SJagan Teki 	},
520d3795d63SJagan Teki 	.probe_new = pf8x00_i2c_probe,
521d3795d63SJagan Teki };
522d3795d63SJagan Teki module_i2c_driver(pf8x00_regulator_driver);
523d3795d63SJagan Teki 
524d3795d63SJagan Teki MODULE_AUTHOR("Jagan Teki <jagan@amarulasolutions.com>");
525d3795d63SJagan Teki MODULE_AUTHOR("Troy Kisky <troy.kisky@boundarydevices.com>");
526d3795d63SJagan Teki MODULE_DESCRIPTION("Regulator Driver for NXP's PF8100/PF8121A/PF8200 PMIC");
527d3795d63SJagan Teki MODULE_LICENSE("GPL v2");
528