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 
128d3795d63SJagan Teki struct pf8x00_regulator {
129d3795d63SJagan Teki 	struct regulator_desc desc;
130d3795d63SJagan Teki };
131d3795d63SJagan Teki 
132d3795d63SJagan Teki struct pf8x00_chip {
133d3795d63SJagan Teki 	struct regmap *regmap;
134d3795d63SJagan Teki 	struct device *dev;
135d3795d63SJagan Teki };
136d3795d63SJagan Teki 
137d3795d63SJagan Teki static const struct regmap_config pf8x00_regmap_config = {
138d3795d63SJagan Teki 	.reg_bits = 8,
139d3795d63SJagan Teki 	.val_bits = 8,
140d3795d63SJagan Teki 	.max_register = PF8X00_PAGE_SELECT,
141d3795d63SJagan Teki 	.cache_type = REGCACHE_RBTREE,
142d3795d63SJagan Teki };
143d3795d63SJagan Teki 
144d3795d63SJagan Teki /* VLDOx output: 1.5V to 5.0V */
145d3795d63SJagan Teki static const int pf8x00_ldo_voltages[] = {
146d3795d63SJagan Teki 	1500000, 1600000, 1800000, 1850000, 2150000, 2500000, 2800000, 3000000,
147d3795d63SJagan Teki 	3100000, 3150000, 3200000, 3300000, 3350000, 1650000, 1700000, 5000000,
148d3795d63SJagan Teki };
149d3795d63SJagan Teki 
150245f5f65SAdrien Grassein /* Output: 2.1A to 4.5A */
151245f5f65SAdrien Grassein static const unsigned int pf8x00_sw_current_table[] = {
152245f5f65SAdrien Grassein 	2100000, 2600000, 3000000, 4500000,
153245f5f65SAdrien Grassein };
154245f5f65SAdrien Grassein 
155d3795d63SJagan Teki /* Output: 0.4V to 1.8V */
15635a93349SAdrien Grassein #define PF8XOO_SW1_6_VOLTAGE_NUM 0xB2
15735a93349SAdrien Grassein static const struct linear_range pf8x00_sw1_to_6_voltages[] = {
15835a93349SAdrien Grassein 	REGULATOR_LINEAR_RANGE(400000, 0x00, 0xB0, 6250),
15935a93349SAdrien Grassein 	REGULATOR_LINEAR_RANGE(1800000, 0xB1, 0xB1, 0),
160d3795d63SJagan Teki };
161d3795d63SJagan Teki 
162d3795d63SJagan Teki /* Output: 1.0V to 4.1V */
163d3795d63SJagan Teki static const int pf8x00_sw7_voltages[] = {
164d3795d63SJagan Teki 	1000000, 1100000, 1200000, 1250000, 1300000, 1350000, 1500000, 1600000,
165d3795d63SJagan Teki 	1800000, 1850000, 2000000, 2100000, 2150000, 2250000, 2300000, 2400000,
166d3795d63SJagan Teki 	2500000, 2800000, 3150000, 3200000, 3250000, 3300000, 3350000, 3400000,
167d3795d63SJagan Teki 	3500000, 3800000, 4000000, 4100000, 4100000, 4100000, 4100000, 4100000,
168d3795d63SJagan Teki };
169d3795d63SJagan Teki 
170d3795d63SJagan Teki /* Output: 1.8V, 3.0V, or 3.3V */
171d3795d63SJagan Teki static const int pf8x00_vsnvs_voltages[] = {
172d3795d63SJagan Teki 	0, 1800000, 3000000, 3300000,
173d3795d63SJagan Teki };
174d3795d63SJagan Teki 
175245f5f65SAdrien Grassein static void swxilim_select(struct pf8x00_chip *chip, int id, int ilim)
176d3795d63SJagan Teki {
177d3795d63SJagan Teki 	u8 ilim_sel;
178245f5f65SAdrien Grassein 	u8 reg = PF8X00_SW_BASE(id) + SW_CONFIG2;
179d3795d63SJagan Teki 
180d3795d63SJagan Teki 	switch (ilim) {
181d3795d63SJagan Teki 	case 2100:
182d3795d63SJagan Teki 		ilim_sel = SWXILIM_2100_MA;
183d3795d63SJagan Teki 		break;
184d3795d63SJagan Teki 	case 2600:
185d3795d63SJagan Teki 		ilim_sel = SWXILIM_2600_MA;
186d3795d63SJagan Teki 		break;
187d3795d63SJagan Teki 	case 3000:
188d3795d63SJagan Teki 		ilim_sel = SWXILIM_3000_MA;
189d3795d63SJagan Teki 		break;
190d3795d63SJagan Teki 	case 4500:
191d3795d63SJagan Teki 		ilim_sel = SWXILIM_4500_MA;
192d3795d63SJagan Teki 		break;
193d3795d63SJagan Teki 	default:
194d3795d63SJagan Teki 		ilim_sel = SWXILIM_2100_MA;
195d3795d63SJagan Teki 		break;
196d3795d63SJagan Teki 	}
197d3795d63SJagan Teki 
198245f5f65SAdrien Grassein 	regmap_update_bits(chip->regmap, reg,
199245f5f65SAdrien Grassein 					PF8X00_SWXILIM_MASK,
200245f5f65SAdrien Grassein 					ilim_sel << PF8X00_SWXILIM_SHIFT);
201245f5f65SAdrien Grassein }
202245f5f65SAdrien Grassein 
203245f5f65SAdrien Grassein static void handle_ilim_property(struct device_node *np,
204245f5f65SAdrien Grassein 			      const struct regulator_desc *desc,
205245f5f65SAdrien Grassein 			      struct regulator_config *config)
206245f5f65SAdrien Grassein {
207245f5f65SAdrien Grassein 	struct pf8x00_chip *chip = config->driver_data;
208245f5f65SAdrien Grassein 	int ret;
209245f5f65SAdrien Grassein 	int val;
210245f5f65SAdrien Grassein 
211245f5f65SAdrien Grassein 	if ((desc->id >= PF8X00_BUCK1) && (desc->id <= PF8X00_BUCK7)) {
212245f5f65SAdrien Grassein 		ret = of_property_read_u32(np, "nxp,ilim-ma", &val);
213245f5f65SAdrien Grassein 		if (ret) {
214245f5f65SAdrien Grassein 			dev_dbg(chip->dev, "unspecified ilim for BUCK%d, use value stored in OTP\n",
215245f5f65SAdrien Grassein 				desc->id - PF8X00_LDO4);
216245f5f65SAdrien Grassein 			return;
217245f5f65SAdrien Grassein 		}
218245f5f65SAdrien Grassein 
219245f5f65SAdrien Grassein 		dev_warn(chip->dev, "nxp,ilim-ma is deprecated, please use regulator-max-microamp\n");
220245f5f65SAdrien Grassein 		swxilim_select(chip, desc->id, val);
221245f5f65SAdrien Grassein 
222245f5f65SAdrien Grassein 	} else
223245f5f65SAdrien Grassein 		dev_warn(chip->dev, "nxp,ilim-ma used with incorrect regulator (%d)\n", desc->id);
224d3795d63SJagan Teki }
225d3795d63SJagan Teki 
226*475a5d85SAdrien Grassein static void handle_shift_property(struct device_node *np,
227*475a5d85SAdrien Grassein 			      const struct regulator_desc *desc,
228*475a5d85SAdrien Grassein 			      struct regulator_config *config)
229*475a5d85SAdrien Grassein {
230*475a5d85SAdrien Grassein 	unsigned char id = desc->id - PF8X00_LDO4;
231*475a5d85SAdrien Grassein 	unsigned char reg = PF8X00_SW_BASE(id) + SW_CONFIG2;
232*475a5d85SAdrien Grassein 	struct pf8x00_chip *chip = config->driver_data;
233*475a5d85SAdrien Grassein 
234*475a5d85SAdrien Grassein 	int phase;
235*475a5d85SAdrien Grassein 	int val;
236*475a5d85SAdrien Grassein 	int ret;
237*475a5d85SAdrien Grassein 	if ((desc->id >= PF8X00_BUCK1) && (desc->id <= PF8X00_BUCK7)) {
238*475a5d85SAdrien Grassein 		ret = of_property_read_u32(np, "nxp,phase-shift", &val);
239*475a5d85SAdrien Grassein 		if (ret) {
240*475a5d85SAdrien Grassein 			dev_dbg(chip->dev,
241*475a5d85SAdrien Grassein 				"unspecified phase-shift for BUCK%d, using OTP configuration\n",
242*475a5d85SAdrien Grassein 				id);
243*475a5d85SAdrien Grassein 			return;
244*475a5d85SAdrien Grassein 		}
245*475a5d85SAdrien Grassein 
246*475a5d85SAdrien Grassein 		if (val < 0 || val > 315 || val % 45 != 0) {
247*475a5d85SAdrien Grassein 			dev_warn(config->dev,
248*475a5d85SAdrien Grassein 				"invalid phase_shift %d for BUCK%d, using OTP configuration\n",
249*475a5d85SAdrien Grassein 				val, id);
250*475a5d85SAdrien Grassein 			return;
251*475a5d85SAdrien Grassein 		}
252*475a5d85SAdrien Grassein 
253*475a5d85SAdrien Grassein 		phase = val / 45;
254*475a5d85SAdrien Grassein 
255*475a5d85SAdrien Grassein 		if (phase >= 1)
256*475a5d85SAdrien Grassein 			phase -= 1;
257*475a5d85SAdrien Grassein 		else
258*475a5d85SAdrien Grassein 			phase = PF8X00_SWXPHASE_SHIFT;
259*475a5d85SAdrien Grassein 
260*475a5d85SAdrien Grassein 		regmap_update_bits(chip->regmap, reg,
261*475a5d85SAdrien Grassein 				PF8X00_SWXPHASE_MASK,
262*475a5d85SAdrien Grassein 				phase);
263*475a5d85SAdrien Grassein 	} else
264*475a5d85SAdrien Grassein 		dev_warn(chip->dev, "nxp,phase-shift used with incorrect regulator (%d)\n", id);
265*475a5d85SAdrien Grassein 
266*475a5d85SAdrien Grassein }
267*475a5d85SAdrien Grassein 
268d3795d63SJagan Teki static int pf8x00_of_parse_cb(struct device_node *np,
269d3795d63SJagan Teki 			      const struct regulator_desc *desc,
270d3795d63SJagan Teki 			      struct regulator_config *config)
271d3795d63SJagan Teki {
272d3795d63SJagan Teki 
273245f5f65SAdrien Grassein 	handle_ilim_property(np, desc, config);
274*475a5d85SAdrien Grassein 	handle_shift_property(np, desc, config);
275d3795d63SJagan Teki 
276d3795d63SJagan Teki 	return 0;
277d3795d63SJagan Teki }
278d3795d63SJagan Teki 
279d3795d63SJagan Teki static const struct regulator_ops pf8x00_ldo_ops = {
280d3795d63SJagan Teki 	.enable = regulator_enable_regmap,
281d3795d63SJagan Teki 	.disable = regulator_disable_regmap,
282d3795d63SJagan Teki 	.is_enabled = regulator_is_enabled_regmap,
283d3795d63SJagan Teki 	.list_voltage = regulator_list_voltage_table,
284d3795d63SJagan Teki 	.set_voltage_sel = regulator_set_voltage_sel_regmap,
285d3795d63SJagan Teki 	.get_voltage_sel = regulator_get_voltage_sel_regmap,
286d3795d63SJagan Teki };
287d3795d63SJagan Teki 
28835a93349SAdrien Grassein 
28935a93349SAdrien Grassein static const struct regulator_ops pf8x00_buck1_6_ops = {
29035a93349SAdrien Grassein 	.enable = regulator_enable_regmap,
29135a93349SAdrien Grassein 	.disable = regulator_disable_regmap,
29235a93349SAdrien Grassein 	.is_enabled = regulator_is_enabled_regmap,
29335a93349SAdrien Grassein 	.list_voltage = regulator_list_voltage_linear_range,
29435a93349SAdrien Grassein 	.set_voltage_sel = regulator_set_voltage_sel_regmap,
29535a93349SAdrien Grassein 	.get_voltage_sel = regulator_get_voltage_sel_regmap,
29635a93349SAdrien Grassein 	.get_current_limit = regulator_get_current_limit_regmap,
29735a93349SAdrien Grassein 	.set_current_limit = regulator_set_current_limit_regmap,
29835a93349SAdrien Grassein };
29935a93349SAdrien Grassein 
30035a93349SAdrien Grassein static const struct regulator_ops pf8x00_buck7_ops = {
301d3795d63SJagan Teki 	.enable = regulator_enable_regmap,
302d3795d63SJagan Teki 	.disable = regulator_disable_regmap,
303d3795d63SJagan Teki 	.is_enabled = regulator_is_enabled_regmap,
304d3795d63SJagan Teki 	.list_voltage = regulator_list_voltage_table,
305d3795d63SJagan Teki 	.set_voltage_sel = regulator_set_voltage_sel_regmap,
306d3795d63SJagan Teki 	.get_voltage_sel = regulator_get_voltage_sel_regmap,
307245f5f65SAdrien Grassein 	.get_current_limit = regulator_get_current_limit_regmap,
308245f5f65SAdrien Grassein 	.set_current_limit = regulator_set_current_limit_regmap,
309d3795d63SJagan Teki };
310d3795d63SJagan Teki 
311d3795d63SJagan Teki static const struct regulator_ops pf8x00_vsnvs_ops = {
312d3795d63SJagan Teki 	.enable = regulator_enable_regmap,
313d3795d63SJagan Teki 	.disable = regulator_disable_regmap,
314d3795d63SJagan Teki 	.is_enabled = regulator_is_enabled_regmap,
315d3795d63SJagan Teki 	.list_voltage = regulator_list_voltage_table,
316d3795d63SJagan Teki 	.map_voltage = regulator_map_voltage_ascend,
317d3795d63SJagan Teki 	.set_voltage_sel = regulator_set_voltage_sel_regmap,
318d3795d63SJagan Teki 	.get_voltage_sel = regulator_get_voltage_sel_regmap,
319d3795d63SJagan Teki };
320d3795d63SJagan Teki 
321d3795d63SJagan Teki #define PF8X00LDO(_id, _name, base, voltages)			\
322d3795d63SJagan Teki 	[PF8X00_LDO ## _id] = {					\
323d3795d63SJagan Teki 		.desc = {					\
324d3795d63SJagan Teki 			.name = _name,				\
325d3795d63SJagan Teki 			.of_match = _name,			\
326d3795d63SJagan Teki 			.regulators_node = "regulators",	\
327d3795d63SJagan Teki 			.n_voltages = ARRAY_SIZE(voltages),	\
328d3795d63SJagan Teki 			.ops = &pf8x00_ldo_ops,			\
329d3795d63SJagan Teki 			.type = REGULATOR_VOLTAGE,		\
330d3795d63SJagan Teki 			.id = PF8X00_LDO ## _id,		\
331d3795d63SJagan Teki 			.owner = THIS_MODULE,			\
332d3795d63SJagan Teki 			.volt_table = voltages,			\
333d3795d63SJagan Teki 			.vsel_reg = (base) + LDO_RUN_VOLT,	\
334d3795d63SJagan Teki 			.vsel_mask = 0xff,			\
335d3795d63SJagan Teki 			.enable_reg = (base) + LDO_CONFIG2,	\
336d3795d63SJagan Teki 			.enable_val = 0x2,			\
337d3795d63SJagan Teki 			.disable_val = 0x0,			\
338d3795d63SJagan Teki 			.enable_mask = 2,			\
339d3795d63SJagan Teki 		},						\
340d3795d63SJagan Teki 	}
341d3795d63SJagan Teki 
342d3795d63SJagan Teki #define PF8X00BUCK(_id, _name, base, voltages)			\
343d3795d63SJagan Teki 	[PF8X00_BUCK ## _id] = {				\
344d3795d63SJagan Teki 		.desc = {					\
345d3795d63SJagan Teki 			.name = _name,				\
346d3795d63SJagan Teki 			.of_match = _name,			\
347d3795d63SJagan Teki 			.regulators_node = "regulators",	\
348d3795d63SJagan Teki 			.of_parse_cb = pf8x00_of_parse_cb,	\
34935a93349SAdrien Grassein 			.n_voltages = PF8XOO_SW1_6_VOLTAGE_NUM,	\
35035a93349SAdrien Grassein 			.ops = &pf8x00_buck1_6_ops,		\
351d3795d63SJagan Teki 			.type = REGULATOR_VOLTAGE,		\
352d3795d63SJagan Teki 			.id = PF8X00_BUCK ## _id,		\
353d3795d63SJagan Teki 			.owner = THIS_MODULE,			\
35435a93349SAdrien Grassein 			.linear_ranges = pf8x00_sw1_to_6_voltages, \
35535a93349SAdrien Grassein 			.n_linear_ranges = \
35635a93349SAdrien Grassein 				ARRAY_SIZE(pf8x00_sw1_to_6_voltages), \
35735a93349SAdrien Grassein 			.vsel_reg = (base) + SW_RUN_VOLT,	\
35835a93349SAdrien Grassein 			.vsel_mask = 0xff,			\
35935a93349SAdrien Grassein 			.curr_table = pf8x00_sw_current_table, \
36035a93349SAdrien Grassein 			.n_current_limits = \
36135a93349SAdrien Grassein 				ARRAY_SIZE(pf8x00_sw_current_table), \
36235a93349SAdrien Grassein 			.csel_reg = (base) + SW_CONFIG2,	\
36335a93349SAdrien Grassein 			.csel_mask = PF8X00_SWXILIM_MASK,	\
36435a93349SAdrien Grassein 			.enable_reg = (base) + SW_MODE1,	\
36535a93349SAdrien Grassein 			.enable_val = 0x3,			\
36635a93349SAdrien Grassein 			.disable_val = 0x0,			\
36735a93349SAdrien Grassein 			.enable_mask = 0x3,			\
36835a93349SAdrien Grassein 			.enable_time = 500,			\
36935a93349SAdrien Grassein 		},						\
37035a93349SAdrien Grassein 	}
37135a93349SAdrien Grassein 
37235a93349SAdrien Grassein #define PF8X00BUCK7(_name, base, voltages)			\
37335a93349SAdrien Grassein 	[PF8X00_BUCK7] = {				\
37435a93349SAdrien Grassein 		.desc = {					\
37535a93349SAdrien Grassein 			.name = _name,				\
37635a93349SAdrien Grassein 			.of_match = _name,			\
37735a93349SAdrien Grassein 			.regulators_node = "regulators",	\
37835a93349SAdrien Grassein 			.of_parse_cb = pf8x00_of_parse_cb,	\
37935a93349SAdrien Grassein 			.n_voltages = ARRAY_SIZE(voltages),	\
38035a93349SAdrien Grassein 			.ops = &pf8x00_buck7_ops,		\
38135a93349SAdrien Grassein 			.type = REGULATOR_VOLTAGE,		\
38235a93349SAdrien Grassein 			.id = PF8X00_BUCK7,		\
38335a93349SAdrien Grassein 			.owner = THIS_MODULE,			\
384d3795d63SJagan Teki 			.volt_table = voltages,			\
385d3795d63SJagan Teki 			.vsel_reg = (base) + SW_RUN_VOLT,	\
386d3795d63SJagan Teki 			.vsel_mask = 0xff,			\
387245f5f65SAdrien Grassein 			.curr_table = pf8x00_sw_current_table, \
388245f5f65SAdrien Grassein 			.n_current_limits = \
389245f5f65SAdrien Grassein 				ARRAY_SIZE(pf8x00_sw_current_table), \
390245f5f65SAdrien Grassein 			.csel_reg = (base) + SW_CONFIG2,	\
391245f5f65SAdrien Grassein 			.csel_mask = PF8X00_SWXILIM_MASK,	\
392d3795d63SJagan Teki 			.enable_reg = (base) + SW_MODE1,	\
393d3795d63SJagan Teki 			.enable_val = 0x3,			\
394d3795d63SJagan Teki 			.disable_val = 0x0,			\
395d3795d63SJagan Teki 			.enable_mask = 0x3,			\
396d3795d63SJagan Teki 			.enable_time = 500,			\
397d3795d63SJagan Teki 		},						\
398d3795d63SJagan Teki 	}
399d3795d63SJagan Teki 
40035a93349SAdrien Grassein 
401d3795d63SJagan Teki #define PF8X00VSNVS(_name, base, voltages)			\
402d3795d63SJagan Teki 	[PF8X00_VSNVS] = {					\
403d3795d63SJagan Teki 		.desc = {					\
404d3795d63SJagan Teki 			.name = _name,				\
405d3795d63SJagan Teki 			.of_match = _name,			\
406d3795d63SJagan Teki 			.regulators_node = "regulators",	\
407d3795d63SJagan Teki 			.n_voltages = ARRAY_SIZE(voltages),	\
408d3795d63SJagan Teki 			.ops = &pf8x00_vsnvs_ops,		\
409d3795d63SJagan Teki 			.type = REGULATOR_VOLTAGE,		\
410d3795d63SJagan Teki 			.id = PF8X00_VSNVS,			\
411d3795d63SJagan Teki 			.owner = THIS_MODULE,			\
412d3795d63SJagan Teki 			.volt_table = voltages,			\
413d3795d63SJagan Teki 			.vsel_reg = (base),			\
414d3795d63SJagan Teki 			.vsel_mask = 0x3,			\
415d3795d63SJagan Teki 		},						\
416d3795d63SJagan Teki 	}
417d3795d63SJagan Teki 
418d3795d63SJagan Teki static struct pf8x00_regulator pf8x00_regulators_data[PF8X00_MAX_REGULATORS] = {
419d3795d63SJagan Teki 	PF8X00LDO(1, "ldo1", PF8X00_LDO_BASE(PF8X00_LDO1), pf8x00_ldo_voltages),
420d3795d63SJagan Teki 	PF8X00LDO(2, "ldo2", PF8X00_LDO_BASE(PF8X00_LDO2), pf8x00_ldo_voltages),
421d3795d63SJagan Teki 	PF8X00LDO(3, "ldo3", PF8X00_LDO_BASE(PF8X00_LDO3), pf8x00_ldo_voltages),
422d3795d63SJagan Teki 	PF8X00LDO(4, "ldo4", PF8X00_LDO_BASE(PF8X00_LDO4), pf8x00_ldo_voltages),
423d3795d63SJagan Teki 	PF8X00BUCK(1, "buck1", PF8X00_SW_BASE(PF8X00_BUCK1), pf8x00_sw1_to_6_voltages),
424d3795d63SJagan Teki 	PF8X00BUCK(2, "buck2", PF8X00_SW_BASE(PF8X00_BUCK2), pf8x00_sw1_to_6_voltages),
425d3795d63SJagan Teki 	PF8X00BUCK(3, "buck3", PF8X00_SW_BASE(PF8X00_BUCK3), pf8x00_sw1_to_6_voltages),
426d3795d63SJagan Teki 	PF8X00BUCK(4, "buck4", PF8X00_SW_BASE(PF8X00_BUCK4), pf8x00_sw1_to_6_voltages),
427d3795d63SJagan Teki 	PF8X00BUCK(5, "buck5", PF8X00_SW_BASE(PF8X00_BUCK5), pf8x00_sw1_to_6_voltages),
428d3795d63SJagan Teki 	PF8X00BUCK(6, "buck6", PF8X00_SW_BASE(PF8X00_BUCK6), pf8x00_sw1_to_6_voltages),
42935a93349SAdrien Grassein 	PF8X00BUCK7("buck7", PF8X00_SW_BASE(PF8X00_BUCK7), pf8x00_sw7_voltages),
430d3795d63SJagan Teki 	PF8X00VSNVS("vsnvs", PF8X00_VSNVS_CONFIG1, pf8x00_vsnvs_voltages),
431d3795d63SJagan Teki };
432d3795d63SJagan Teki 
433d3795d63SJagan Teki static int pf8x00_identify(struct pf8x00_chip *chip)
434d3795d63SJagan Teki {
435d3795d63SJagan Teki 	unsigned int value;
436d3795d63SJagan Teki 	u8 dev_fam, dev_id;
437d3795d63SJagan Teki 	const char *name = NULL;
438d3795d63SJagan Teki 	int ret;
439d3795d63SJagan Teki 
440d3795d63SJagan Teki 	ret = regmap_read(chip->regmap, PF8X00_DEVICEID, &value);
441d3795d63SJagan Teki 	if (ret) {
442d3795d63SJagan Teki 		dev_err(chip->dev, "failed to read chip family\n");
443d3795d63SJagan Teki 		return ret;
444d3795d63SJagan Teki 	}
445d3795d63SJagan Teki 
446d3795d63SJagan Teki 	dev_fam = value & PF8X00_DEVICE_FAM_MASK;
447d3795d63SJagan Teki 	switch (dev_fam) {
448d3795d63SJagan Teki 	case PF8X00_FAM:
449d3795d63SJagan Teki 		break;
450d3795d63SJagan Teki 	default:
451d3795d63SJagan Teki 		dev_err(chip->dev,
452d3795d63SJagan Teki 			"Chip 0x%x is not from PF8X00 family\n", dev_fam);
453d3795d63SJagan Teki 		return ret;
454d3795d63SJagan Teki 	}
455d3795d63SJagan Teki 
456d3795d63SJagan Teki 	dev_id = value & PF8X00_DEVICE_ID_MASK;
457d3795d63SJagan Teki 	switch (dev_id) {
458d3795d63SJagan Teki 	case PF8100:
459d3795d63SJagan Teki 		name = "PF8100";
460d3795d63SJagan Teki 		break;
461d3795d63SJagan Teki 	case PF8121A:
462d3795d63SJagan Teki 		name = "PF8121A";
463d3795d63SJagan Teki 		break;
464d3795d63SJagan Teki 	case PF8200:
465d3795d63SJagan Teki 		name = "PF8100";
466d3795d63SJagan Teki 		break;
467d3795d63SJagan Teki 	default:
468d3795d63SJagan Teki 		dev_err(chip->dev, "Unknown pf8x00 device id 0x%x\n", dev_id);
469d3795d63SJagan Teki 		return -ENODEV;
470d3795d63SJagan Teki 	}
471d3795d63SJagan Teki 
472d3795d63SJagan Teki 	dev_info(chip->dev, "%s PMIC found.\n", name);
473d3795d63SJagan Teki 
474d3795d63SJagan Teki 	return 0;
475d3795d63SJagan Teki }
476d3795d63SJagan Teki 
477d3795d63SJagan Teki static int pf8x00_i2c_probe(struct i2c_client *client)
478d3795d63SJagan Teki {
479d3795d63SJagan Teki 	struct regulator_config config = { NULL, };
480d3795d63SJagan Teki 	struct pf8x00_chip *chip;
481d3795d63SJagan Teki 	int id;
482d3795d63SJagan Teki 	int ret;
483d3795d63SJagan Teki 
484d3795d63SJagan Teki 	chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
485d3795d63SJagan Teki 	if (!chip)
486d3795d63SJagan Teki 		return -ENOMEM;
487d3795d63SJagan Teki 
488d3795d63SJagan Teki 	i2c_set_clientdata(client, chip);
489d3795d63SJagan Teki 	chip->dev = &client->dev;
490d3795d63SJagan Teki 
491d3795d63SJagan Teki 	chip->regmap = devm_regmap_init_i2c(client, &pf8x00_regmap_config);
492d3795d63SJagan Teki 	if (IS_ERR(chip->regmap)) {
493d3795d63SJagan Teki 		ret = PTR_ERR(chip->regmap);
494d3795d63SJagan Teki 		dev_err(&client->dev,
495d3795d63SJagan Teki 			"regmap allocation failed with err %d\n", ret);
496d3795d63SJagan Teki 		return ret;
497d3795d63SJagan Teki 	}
498d3795d63SJagan Teki 
499d3795d63SJagan Teki 	ret = pf8x00_identify(chip);
500d3795d63SJagan Teki 	if (ret)
501d3795d63SJagan Teki 		return ret;
502d3795d63SJagan Teki 
503d3795d63SJagan Teki 	for (id = 0; id < ARRAY_SIZE(pf8x00_regulators_data); id++) {
504d3795d63SJagan Teki 		struct pf8x00_regulator *data = &pf8x00_regulators_data[id];
505d3795d63SJagan Teki 		struct regulator_dev *rdev;
506d3795d63SJagan Teki 
507d3795d63SJagan Teki 		config.dev = chip->dev;
508d3795d63SJagan Teki 		config.driver_data = chip;
509d3795d63SJagan Teki 		config.regmap = chip->regmap;
510d3795d63SJagan Teki 
511d3795d63SJagan Teki 		rdev = devm_regulator_register(&client->dev, &data->desc, &config);
512d3795d63SJagan Teki 		if (IS_ERR(rdev)) {
513d3795d63SJagan Teki 			dev_err(&client->dev,
514d3795d63SJagan Teki 				"failed to register %s regulator\n", data->desc.name);
515d3795d63SJagan Teki 			return PTR_ERR(rdev);
516d3795d63SJagan Teki 		}
517d3795d63SJagan Teki 	}
518d3795d63SJagan Teki 
519d3795d63SJagan Teki 	return 0;
520d3795d63SJagan Teki }
521d3795d63SJagan Teki 
522d3795d63SJagan Teki static const struct of_device_id pf8x00_dt_ids[] = {
523df9716ecSMark Brown 	{ .compatible = "nxp,pf8100",},
524df9716ecSMark Brown 	{ .compatible = "nxp,pf8121a",},
525df9716ecSMark Brown 	{ .compatible = "nxp,pf8200",},
526d3795d63SJagan Teki 	{ }
527d3795d63SJagan Teki };
528d3795d63SJagan Teki MODULE_DEVICE_TABLE(of, pf8x00_dt_ids);
529d3795d63SJagan Teki 
530d3795d63SJagan Teki static const struct i2c_device_id pf8x00_i2c_id[] = {
531df9716ecSMark Brown 	{ "pf8100", 0 },
532df9716ecSMark Brown 	{ "pf8121a", 0 },
533df9716ecSMark Brown 	{ "pf8200", 0 },
534d3795d63SJagan Teki 	{},
535d3795d63SJagan Teki };
536d3795d63SJagan Teki MODULE_DEVICE_TABLE(i2c, pf8x00_i2c_id);
537d3795d63SJagan Teki 
538d3795d63SJagan Teki static struct i2c_driver pf8x00_regulator_driver = {
539d3795d63SJagan Teki 	.id_table = pf8x00_i2c_id,
540d3795d63SJagan Teki 	.driver = {
541d3795d63SJagan Teki 		.name = "pf8x00",
542d3795d63SJagan Teki 		.of_match_table = pf8x00_dt_ids,
543d3795d63SJagan Teki 	},
544d3795d63SJagan Teki 	.probe_new = pf8x00_i2c_probe,
545d3795d63SJagan Teki };
546d3795d63SJagan Teki module_i2c_driver(pf8x00_regulator_driver);
547d3795d63SJagan Teki 
548d3795d63SJagan Teki MODULE_AUTHOR("Jagan Teki <jagan@amarulasolutions.com>");
549d3795d63SJagan Teki MODULE_AUTHOR("Troy Kisky <troy.kisky@boundarydevices.com>");
550d3795d63SJagan Teki MODULE_DESCRIPTION("Regulator Driver for NXP's PF8100/PF8121A/PF8200 PMIC");
551d3795d63SJagan Teki MODULE_LICENSE("GPL v2");
552