Blame view

drivers/regulator/tps6586x-regulator.c 15.8 KB
d2912cb15   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-only
49610235d   Mike Rapoport   regulator: add TP...
2
3
4
5
6
7
8
9
10
  /*
   * Regulator driver for TI TPS6586x
   *
   * Copyright (C) 2010 Compulab Ltd.
   * Author: Mike Rapoport <mike@compulab.co.il>
   *
   * Based on da903x
   * Copyright (C) 2006-2008 Marvell International Ltd.
   * Copyright (C) 2008 Compulab Ltd.
49610235d   Mike Rapoport   regulator: add TP...
11
   */
49610235d   Mike Rapoport   regulator: add TP...
12
  #include <linux/kernel.h>
65602c32e   Paul Gortmaker   regulator: Add mo...
13
  #include <linux/module.h>
49610235d   Mike Rapoport   regulator: add TP...
14
15
  #include <linux/init.h>
  #include <linux/err.h>
64e481603   Laxman Dewangan   mfd: tps6586x: mo...
16
  #include <linux/of.h>
49610235d   Mike Rapoport   regulator: add TP...
17
18
19
20
  #include <linux/slab.h>
  #include <linux/platform_device.h>
  #include <linux/regulator/driver.h>
  #include <linux/regulator/machine.h>
64e481603   Laxman Dewangan   mfd: tps6586x: mo...
21
  #include <linux/regulator/of_regulator.h>
49610235d   Mike Rapoport   regulator: add TP...
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
  #include <linux/mfd/tps6586x.h>
  
  /* supply control and voltage setting  */
  #define TPS6586X_SUPPLYENA	0x10
  #define TPS6586X_SUPPLYENB	0x11
  #define TPS6586X_SUPPLYENC	0x12
  #define TPS6586X_SUPPLYEND	0x13
  #define TPS6586X_SUPPLYENE	0x14
  #define TPS6586X_VCC1		0x20
  #define TPS6586X_VCC2		0x21
  #define TPS6586X_SM1V1		0x23
  #define TPS6586X_SM1V2		0x24
  #define TPS6586X_SM1SL		0x25
  #define TPS6586X_SM0V1		0x26
  #define TPS6586X_SM0V2		0x27
  #define TPS6586X_SM0SL		0x28
  #define TPS6586X_LDO2AV1	0x29
  #define TPS6586X_LDO2AV2	0x2A
  #define TPS6586X_LDO2BV1	0x2F
  #define TPS6586X_LDO2BV2	0x30
  #define TPS6586X_LDO4V1		0x32
  #define TPS6586X_LDO4V2		0x33
  
  /* converter settings  */
  #define TPS6586X_SUPPLYV1	0x41
  #define TPS6586X_SUPPLYV2	0x42
  #define TPS6586X_SUPPLYV3	0x43
  #define TPS6586X_SUPPLYV4	0x44
  #define TPS6586X_SUPPLYV5	0x45
  #define TPS6586X_SUPPLYV6	0x46
  #define TPS6586X_SMODE1		0x47
  #define TPS6586X_SMODE2		0x48
  
  struct tps6586x_regulator {
  	struct regulator_desc desc;
49610235d   Mike Rapoport   regulator: add TP...
57
58
  	int enable_bit[2];
  	int enable_reg[2];
49610235d   Mike Rapoport   regulator: add TP...
59
  };
25c804450   Rikard Falkeborn   regulator: tps658...
60
  static const struct regulator_ops tps6586x_rw_regulator_ops = {
f46470379   Axel Lin   regulator: tps658...
61
  	.list_voltage = regulator_list_voltage_table,
4d673bbc5   Axel Lin   regulator: tps658...
62
  	.map_voltage = regulator_map_voltage_ascend,
7c7475c00   Axel Lin   regulator: tps658...
63
  	.get_voltage_sel = regulator_get_voltage_sel_regmap,
d645d5915   Axel Lin   regulator: tps658...
64
  	.set_voltage_sel = regulator_set_voltage_sel_regmap,
49610235d   Mike Rapoport   regulator: add TP...
65

7c7475c00   Axel Lin   regulator: tps658...
66
67
68
  	.is_enabled = regulator_is_enabled_regmap,
  	.enable = regulator_enable_regmap,
  	.disable = regulator_disable_regmap,
49610235d   Mike Rapoport   regulator: add TP...
69
  };
25c804450   Rikard Falkeborn   regulator: tps658...
70
  static const struct regulator_ops tps6586x_rw_linear_regulator_ops = {
2628b1007   Axel Lin   regulator: tps658...
71
72
73
74
75
76
77
78
  	.list_voltage = regulator_list_voltage_linear,
  	.get_voltage_sel = regulator_get_voltage_sel_regmap,
  	.set_voltage_sel = regulator_set_voltage_sel_regmap,
  
  	.is_enabled = regulator_is_enabled_regmap,
  	.enable = regulator_enable_regmap,
  	.disable = regulator_disable_regmap,
  };
25c804450   Rikard Falkeborn   regulator: tps658...
79
  static const struct regulator_ops tps6586x_ro_regulator_ops = {
ad0b40fee   Alban Bedel   regulator: tps658...
80
81
82
83
84
85
86
87
  	.list_voltage = regulator_list_voltage_table,
  	.map_voltage = regulator_map_voltage_ascend,
  	.get_voltage_sel = regulator_get_voltage_sel_regmap,
  
  	.is_enabled = regulator_is_enabled_regmap,
  	.enable = regulator_enable_regmap,
  	.disable = regulator_disable_regmap,
  };
25c804450   Rikard Falkeborn   regulator: tps658...
88
  static const struct regulator_ops tps6586x_sys_regulator_ops = {
49610235d   Mike Rapoport   regulator: add TP...
89
  };
f46470379   Axel Lin   regulator: tps658...
90
91
92
  static const unsigned int tps6586x_ldo0_voltages[] = {
  	1200000, 1500000, 1800000, 2500000, 2700000, 2850000, 3100000, 3300000,
  };
f46470379   Axel Lin   regulator: tps658...
93
94
  static const unsigned int tps6586x_ldo_voltages[] = {
  	1250000, 1500000, 1800000, 2500000, 2700000, 2850000, 3100000, 3300000,
49610235d   Mike Rapoport   regulator: add TP...
95
  };
2628b1007   Axel Lin   regulator: tps658...
96
  static const unsigned int tps658640_rtc_voltages[] = {
6c46ccc8b   Alban Bedel   regulator: tps658...
97
98
  	2500000, 2850000, 3100000, 3300000,
  };
ad0b40fee   Alban Bedel   regulator: tps658...
99
  #define TPS6586X_REGULATOR(_id, _ops, _pin_name, vdata, vreg, shift, nbits, \
d645d5915   Axel Lin   regulator: tps658...
100
  			   ereg0, ebit0, ereg1, ebit1, goreg, gobit)	\
49610235d   Mike Rapoport   regulator: add TP...
101
  	.desc	= {							\
7c7fac305   Laxman Dewangan   regulator: tps658...
102
  		.supply_name = _pin_name,				\
49610235d   Mike Rapoport   regulator: add TP...
103
  		.name	= "REG-" #_id,					\
ad0b40fee   Alban Bedel   regulator: tps658...
104
  		.ops	= &tps6586x_## _ops ## _regulator_ops,		\
49610235d   Mike Rapoport   regulator: add TP...
105
106
  		.type	= REGULATOR_VOLTAGE,				\
  		.id	= TPS6586X_ID_##_id,				\
844a4f0d8   Stefan Agner   regulator: tps658...
107
108
  		.n_voltages = ARRAY_SIZE(vdata##_voltages),		\
  		.volt_table = vdata##_voltages,				\
49610235d   Mike Rapoport   regulator: add TP...
109
  		.owner	= THIS_MODULE,					\
7c7475c00   Axel Lin   regulator: tps658...
110
111
112
113
  		.enable_reg = TPS6586X_SUPPLY##ereg0,			\
  		.enable_mask = 1 << (ebit0),				\
  		.vsel_reg = TPS6586X_##vreg,				\
  		.vsel_mask = ((1 << (nbits)) - 1) << (shift),		\
d645d5915   Axel Lin   regulator: tps658...
114
115
  		.apply_reg = (goreg),				\
  		.apply_bit = (gobit),				\
49610235d   Mike Rapoport   regulator: add TP...
116
  	},								\
49610235d   Mike Rapoport   regulator: add TP...
117
118
119
  	.enable_reg[0]	= TPS6586X_SUPPLY##ereg0,			\
  	.enable_bit[0]	= (ebit0),					\
  	.enable_reg[1]	= TPS6586X_SUPPLY##ereg1,			\
f46470379   Axel Lin   regulator: tps658...
120
  	.enable_bit[1]	= (ebit1),
64db657b5   Danny Huang   regulator: tps658...
121

2628b1007   Axel Lin   regulator: tps658...
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
  #define TPS6586X_REGULATOR_LINEAR(_id, _ops, _pin_name, n_volt, min_uv,	\
  				  uv_step, vreg, shift, nbits, ereg0,	\
  				  ebit0, ereg1, ebit1, goreg, gobit)	\
  	.desc	= {							\
  		.supply_name = _pin_name,				\
  		.name	= "REG-" #_id,					\
  		.ops	= &tps6586x_## _ops ## _regulator_ops,		\
  		.type	= REGULATOR_VOLTAGE,				\
  		.id	= TPS6586X_ID_##_id,				\
  		.n_voltages = n_volt,					\
  		.min_uV = min_uv,					\
  		.uV_step = uv_step,					\
  		.owner	= THIS_MODULE,					\
  		.enable_reg = TPS6586X_SUPPLY##ereg0,			\
  		.enable_mask = 1 << (ebit0),				\
  		.vsel_reg = TPS6586X_##vreg,				\
  		.vsel_mask = ((1 << (nbits)) - 1) << (shift),		\
  		.apply_reg = (goreg),				\
  		.apply_bit = (gobit),				\
  	},								\
  	.enable_reg[0]	= TPS6586X_SUPPLY##ereg0,			\
  	.enable_bit[0]	= (ebit0),					\
  	.enable_reg[1]	= TPS6586X_SUPPLY##ereg1,			\
  	.enable_bit[1]	= (ebit1),
7c7fac305   Laxman Dewangan   regulator: tps658...
146
  #define TPS6586X_LDO(_id, _pname, vdata, vreg, shift, nbits,		\
49610235d   Mike Rapoport   regulator: add TP...
147
  		     ereg0, ebit0, ereg1, ebit1)			\
64db657b5   Danny Huang   regulator: tps658...
148
  {									\
ad0b40fee   Alban Bedel   regulator: tps658...
149
150
151
  	TPS6586X_REGULATOR(_id, rw, _pname, vdata, vreg, shift, nbits,	\
  			   ereg0, ebit0, ereg1, ebit1, 0, 0)		\
  }
2628b1007   Axel Lin   regulator: tps658...
152
153
154
155
156
157
158
  #define TPS6586X_LDO_LINEAR(_id, _pname, n_volt, min_uv, uv_step, vreg,	\
  			    shift, nbits, ereg0, ebit0, ereg1, ebit1)	\
  {									\
  	TPS6586X_REGULATOR_LINEAR(_id, rw_linear, _pname, n_volt,	\
  				  min_uv, uv_step, vreg, shift, nbits,	\
  				  ereg0, ebit0, ereg1, ebit1, 0, 0)	\
  }
ad0b40fee   Alban Bedel   regulator: tps658...
159
160
161
162
  #define TPS6586X_FIXED_LDO(_id, _pname, vdata, vreg, shift, nbits,	\
  			  ereg0, ebit0, ereg1, ebit1)			\
  {									\
  	TPS6586X_REGULATOR(_id, ro, _pname, vdata, vreg, shift, nbits,	\
d645d5915   Axel Lin   regulator: tps658...
163
  			   ereg0, ebit0, ereg1, ebit1, 0, 0)		\
64db657b5   Danny Huang   regulator: tps658...
164
  }
49610235d   Mike Rapoport   regulator: add TP...
165

2628b1007   Axel Lin   regulator: tps658...
166
167
  #define TPS6586X_DVM(_id, _pname, n_volt, min_uv, uv_step, vreg, shift,	\
  		     nbits, ereg0, ebit0, ereg1, ebit1, goreg, gobit)	\
64db657b5   Danny Huang   regulator: tps658...
168
  {									\
2628b1007   Axel Lin   regulator: tps658...
169
170
171
172
  	TPS6586X_REGULATOR_LINEAR(_id, rw_linear, _pname, n_volt,	\
  				  min_uv, uv_step, vreg, shift, nbits,	\
  				  ereg0, ebit0, ereg1, ebit1, goreg,	\
  				  gobit)				\
64db657b5   Danny Huang   regulator: tps658...
173
  }
49610235d   Mike Rapoport   regulator: add TP...
174

9394b80c3   Laxman Dewangan   regulator: tps658...
175
176
177
178
179
180
181
182
183
184
185
  #define TPS6586X_SYS_REGULATOR()					\
  {									\
  	.desc	= {							\
  		.supply_name = "sys",					\
  		.name	= "REG-SYS",					\
  		.ops	= &tps6586x_sys_regulator_ops,			\
  		.type	= REGULATOR_VOLTAGE,				\
  		.id	= TPS6586X_ID_SYS,				\
  		.owner	= THIS_MODULE,					\
  	},								\
  }
49610235d   Mike Rapoport   regulator: add TP...
186
  static struct tps6586x_regulator tps6586x_regulator[] = {
9394b80c3   Laxman Dewangan   regulator: tps658...
187
  	TPS6586X_SYS_REGULATOR(),
844a4f0d8   Stefan Agner   regulator: tps658...
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
  	TPS6586X_LDO(LDO_0, "vinldo01", tps6586x_ldo0, SUPPLYV1, 5, 3, ENC, 0,
  					END, 0),
  	TPS6586X_LDO(LDO_3, "vinldo23", tps6586x_ldo, SUPPLYV4, 0, 3, ENC, 2,
  					END, 2),
  	TPS6586X_LDO(LDO_5, "REG-SYS", tps6586x_ldo, SUPPLYV6, 0, 3, ENE, 6,
  					ENE, 6),
  	TPS6586X_LDO(LDO_6, "vinldo678", tps6586x_ldo, SUPPLYV3, 0, 3, ENC, 4,
  					END, 4),
  	TPS6586X_LDO(LDO_7, "vinldo678", tps6586x_ldo, SUPPLYV3, 3, 3, ENC, 5,
  					END, 5),
  	TPS6586X_LDO(LDO_8, "vinldo678", tps6586x_ldo, SUPPLYV2, 5, 3, ENC, 6,
  					END, 6),
  	TPS6586X_LDO(LDO_9, "vinldo9", tps6586x_ldo, SUPPLYV6, 3, 3, ENE, 7,
  					ENE, 7),
  	TPS6586X_LDO(LDO_RTC, "REG-SYS", tps6586x_ldo, SUPPLYV4, 3, 3, V4, 7,
  					V4, 7),
2628b1007   Axel Lin   regulator: tps658...
204
205
206
207
208
209
210
211
212
213
214
215
  	TPS6586X_LDO_LINEAR(LDO_1, "vinldo01", 32, 725000, 25000, SUPPLYV1,
  			    0, 5, ENC, 1, END, 1),
  	TPS6586X_LDO_LINEAR(SM_2, "vin-sm2", 32, 3000000, 50000, SUPPLYV2,
  			    0, 5, ENC, 7, END, 7),
  	TPS6586X_DVM(LDO_2, "vinldo23", 32, 725000, 25000, LDO2BV1, 0, 5,
  		     ENA, 3, ENB, 3, TPS6586X_VCC2, BIT(6)),
  	TPS6586X_DVM(LDO_4, "vinldo4", 32, 1700000, 25000, LDO4V1, 0, 5,
  		     ENC, 3, END, 3, TPS6586X_VCC1, BIT(6)),
  	TPS6586X_DVM(SM_0, "vin-sm0", 32, 725000, 25000, SM0V1, 0, 5,
  		     ENA, 1, ENB, 1, TPS6586X_VCC1, BIT(2)),
  	TPS6586X_DVM(SM_1, "vin-sm1", 32, 725000, 25000, SM1V1, 0, 5,
  		     ENA, 0, ENB, 0, TPS6586X_VCC1, BIT(0)),
49610235d   Mike Rapoport   regulator: add TP...
216
  };
844a4f0d8   Stefan Agner   regulator: tps658...
217
  static struct tps6586x_regulator tps658623_regulator[] = {
2628b1007   Axel Lin   regulator: tps658...
218
219
  	TPS6586X_LDO_LINEAR(SM_2, "vin-sm2", 32, 1700000, 25000, SUPPLYV2,
  			    0, 5, ENC, 7, END, 7),
844a4f0d8   Stefan Agner   regulator: tps658...
220
  };
6c46ccc8b   Alban Bedel   regulator: tps658...
221
222
223
224
225
226
227
228
229
230
231
232
233
  static struct tps6586x_regulator tps658640_regulator[] = {
  	TPS6586X_LDO(LDO_3, "vinldo23", tps6586x_ldo0, SUPPLYV4, 0, 3,
  					ENC, 2, END, 2),
  	TPS6586X_LDO(LDO_5, "REG-SYS", tps6586x_ldo0, SUPPLYV6, 0, 3,
  					ENE, 6, ENE, 6),
  	TPS6586X_LDO(LDO_6, "vinldo678", tps6586x_ldo0, SUPPLYV3, 0, 3,
  					ENC, 4, END, 4),
  	TPS6586X_LDO(LDO_7, "vinldo678", tps6586x_ldo0, SUPPLYV3, 3, 3,
  					ENC, 5, END, 5),
  	TPS6586X_LDO(LDO_8, "vinldo678", tps6586x_ldo0, SUPPLYV2, 5, 3,
  					ENC, 6, END, 6),
  	TPS6586X_LDO(LDO_9, "vinldo9", tps6586x_ldo0, SUPPLYV6, 3, 3,
  					ENE, 7, ENE, 7),
2628b1007   Axel Lin   regulator: tps658...
234
235
  	TPS6586X_LDO_LINEAR(SM_2, "vin-sm2", 32, 2150000, 50000, SUPPLYV2,
  			    0, 5, ENC, 7, END, 7),
6c46ccc8b   Alban Bedel   regulator: tps658...
236
237
238
239
  
  	TPS6586X_FIXED_LDO(LDO_RTC, "REG-SYS", tps658640_rtc, SUPPLYV4, 3, 2,
  					V4, 7, V4, 7),
  };
844a4f0d8   Stefan Agner   regulator: tps658...
240
  static struct tps6586x_regulator tps658643_regulator[] = {
2628b1007   Axel Lin   regulator: tps658...
241
242
  	TPS6586X_LDO_LINEAR(SM_2, "vin-sm2", 32, 1025000, 25000, SUPPLYV2,
  			    0, 5, ENC, 7, END, 7),
844a4f0d8   Stefan Agner   regulator: tps658...
243
  };
49610235d   Mike Rapoport   regulator: add TP...
244
245
246
247
248
249
250
251
252
253
  /*
   * TPS6586X has 2 enable bits that are OR'ed to determine the actual
   * regulator state. Clearing one of this bits allows switching
   * regulator on and of with single register write.
   */
  static inline int tps6586x_regulator_preinit(struct device *parent,
  					     struct tps6586x_regulator *ri)
  {
  	uint8_t val1, val2;
  	int ret;
1dbcf35cb   Danny Huang   regulator: tps658...
254
255
256
  	if (ri->enable_reg[0] == ri->enable_reg[1] &&
  	    ri->enable_bit[0] == ri->enable_bit[1])
  			return 0;
49610235d   Mike Rapoport   regulator: add TP...
257
258
259
260
261
262
263
  	ret = tps6586x_read(parent, ri->enable_reg[0], &val1);
  	if (ret)
  		return ret;
  
  	ret = tps6586x_read(parent, ri->enable_reg[1], &val2);
  	if (ret)
  		return ret;
4f5867070   Danny Huang   regulator: tps658...
264
  	if (!(val2 & (1 << ri->enable_bit[1])))
49610235d   Mike Rapoport   regulator: add TP...
265
266
267
268
269
270
  		return 0;
  
  	/*
  	 * The regulator is on, but it's enabled with the bit we don't
  	 * want to use, so we switch the enable bits
  	 */
4f5867070   Danny Huang   regulator: tps658...
271
  	if (!(val1 & (1 << ri->enable_bit[0]))) {
49610235d   Mike Rapoport   regulator: add TP...
272
273
274
275
276
277
278
279
280
  		ret = tps6586x_set_bits(parent, ri->enable_reg[0],
  					1 << ri->enable_bit[0]);
  		if (ret)
  			return ret;
  	}
  
  	return tps6586x_clr_bits(parent, ri->enable_reg[1],
  				 1 << ri->enable_bit[1]);
  }
64e481603   Laxman Dewangan   mfd: tps6586x: mo...
281
282
  static int tps6586x_regulator_set_slew_rate(struct platform_device *pdev,
  			int id, struct regulator_init_data *p)
500c524aa   Xin Xie   regulator: tps658...
283
284
  {
  	struct device *parent = pdev->dev.parent;
500c524aa   Xin Xie   regulator: tps658...
285
286
287
288
289
290
291
292
293
294
  	struct tps6586x_settings *setting = p->driver_data;
  	uint8_t reg;
  
  	if (setting == NULL)
  		return 0;
  
  	if (!(setting->slew_rate & TPS6586X_SLEW_RATE_SET))
  		return 0;
  
  	/* only SM0 and SM1 can have the slew rate settings */
64e481603   Laxman Dewangan   mfd: tps6586x: mo...
295
  	switch (id) {
500c524aa   Xin Xie   regulator: tps658...
296
297
298
299
300
301
302
  	case TPS6586X_ID_SM_0:
  		reg = TPS6586X_SM0SL;
  		break;
  	case TPS6586X_ID_SM_1:
  		reg = TPS6586X_SM1SL;
  		break;
  	default:
6673d66e5   Axel Lin   regulator: tps658...
303
304
  		dev_err(&pdev->dev, "Only SM0/SM1 can set slew rate
  ");
500c524aa   Xin Xie   regulator: tps658...
305
306
307
308
309
310
  		return -EINVAL;
  	}
  
  	return tps6586x_write(parent, reg,
  			setting->slew_rate & TPS6586X_SLEW_RATE_MASK);
  }
844a4f0d8   Stefan Agner   regulator: tps658...
311
  static struct tps6586x_regulator *find_regulator_info(int id, int version)
49610235d   Mike Rapoport   regulator: add TP...
312
313
  {
  	struct tps6586x_regulator *ri;
844a4f0d8   Stefan Agner   regulator: tps658...
314
315
  	struct tps6586x_regulator *table = NULL;
  	int num;
49610235d   Mike Rapoport   regulator: add TP...
316
  	int i;
844a4f0d8   Stefan Agner   regulator: tps658...
317
318
  	switch (version) {
  	case TPS658623:
669ca0303   ryang   regulator: tps658...
319
  	case TPS658624:
844a4f0d8   Stefan Agner   regulator: tps658...
320
321
322
  		table = tps658623_regulator;
  		num = ARRAY_SIZE(tps658623_regulator);
  		break;
6c46ccc8b   Alban Bedel   regulator: tps658...
323
324
325
326
327
  	case TPS658640:
  	case TPS658640v2:
  		table = tps658640_regulator;
  		num = ARRAY_SIZE(tps658640_regulator);
  		break;
844a4f0d8   Stefan Agner   regulator: tps658...
328
329
330
331
332
333
334
335
336
337
338
339
340
341
  	case TPS658643:
  		table = tps658643_regulator;
  		num = ARRAY_SIZE(tps658643_regulator);
  		break;
  	}
  
  	/* Search version specific table first */
  	if (table) {
  		for (i = 0; i < num; i++) {
  			ri = &table[i];
  			if (ri->desc.id == id)
  				return ri;
  		}
  	}
49610235d   Mike Rapoport   regulator: add TP...
342
343
344
345
346
347
348
  	for (i = 0; i < ARRAY_SIZE(tps6586x_regulator); i++) {
  		ri = &tps6586x_regulator[i];
  		if (ri->desc.id == id)
  			return ri;
  	}
  	return NULL;
  }
64e481603   Laxman Dewangan   mfd: tps6586x: mo...
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
  #ifdef CONFIG_OF
  static struct of_regulator_match tps6586x_matches[] = {
  	{ .name = "sys",     .driver_data = (void *)TPS6586X_ID_SYS     },
  	{ .name = "sm0",     .driver_data = (void *)TPS6586X_ID_SM_0    },
  	{ .name = "sm1",     .driver_data = (void *)TPS6586X_ID_SM_1    },
  	{ .name = "sm2",     .driver_data = (void *)TPS6586X_ID_SM_2    },
  	{ .name = "ldo0",    .driver_data = (void *)TPS6586X_ID_LDO_0   },
  	{ .name = "ldo1",    .driver_data = (void *)TPS6586X_ID_LDO_1   },
  	{ .name = "ldo2",    .driver_data = (void *)TPS6586X_ID_LDO_2   },
  	{ .name = "ldo3",    .driver_data = (void *)TPS6586X_ID_LDO_3   },
  	{ .name = "ldo4",    .driver_data = (void *)TPS6586X_ID_LDO_4   },
  	{ .name = "ldo5",    .driver_data = (void *)TPS6586X_ID_LDO_5   },
  	{ .name = "ldo6",    .driver_data = (void *)TPS6586X_ID_LDO_6   },
  	{ .name = "ldo7",    .driver_data = (void *)TPS6586X_ID_LDO_7   },
  	{ .name = "ldo8",    .driver_data = (void *)TPS6586X_ID_LDO_8   },
  	{ .name = "ldo9",    .driver_data = (void *)TPS6586X_ID_LDO_9   },
  	{ .name = "ldo_rtc", .driver_data = (void *)TPS6586X_ID_LDO_RTC },
  };
  
  static struct tps6586x_platform_data *tps6586x_parse_regulator_dt(
  		struct platform_device *pdev,
  		struct of_regulator_match **tps6586x_reg_matches)
  {
  	const unsigned int num = ARRAY_SIZE(tps6586x_matches);
  	struct device_node *np = pdev->dev.parent->of_node;
  	struct device_node *regs;
  	const char *sys_rail = NULL;
  	unsigned int i;
  	struct tps6586x_platform_data *pdata;
  	int err;
712c967fe   Laxman Dewangan   regulator: tps658...
379
  	regs = of_get_child_by_name(np, "regulators");
64e481603   Laxman Dewangan   mfd: tps6586x: mo...
380
381
382
383
384
385
386
  	if (!regs) {
  		dev_err(&pdev->dev, "regulator node not found
  ");
  		return NULL;
  	}
  
  	err = of_regulator_match(&pdev->dev, regs, tps6586x_matches, num);
0a4cccaa3   Guennadi Liakhovetski   regulator: tps658...
387
  	of_node_put(regs);
64e481603   Laxman Dewangan   mfd: tps6586x: mo...
388
389
390
  	if (err < 0) {
  		dev_err(&pdev->dev, "Regulator match failed, e %d
  ", err);
64e481603   Laxman Dewangan   mfd: tps6586x: mo...
391
392
  		return NULL;
  	}
64e481603   Laxman Dewangan   mfd: tps6586x: mo...
393
  	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
02e905845   Sachin Kamat   regulator: tps658...
394
  	if (!pdata)
64e481603   Laxman Dewangan   mfd: tps6586x: mo...
395
  		return NULL;
64e481603   Laxman Dewangan   mfd: tps6586x: mo...
396
397
  
  	for (i = 0; i < num; i++) {
a70f0d027   Daniel Kurtz   regulator: tps658...
398
  		uintptr_t id;
64e481603   Laxman Dewangan   mfd: tps6586x: mo...
399
400
401
402
  		if (!tps6586x_matches[i].init_data)
  			continue;
  
  		pdata->reg_init_data[i] = tps6586x_matches[i].init_data;
a70f0d027   Daniel Kurtz   regulator: tps658...
403
  		id = (uintptr_t)tps6586x_matches[i].driver_data;
64e481603   Laxman Dewangan   mfd: tps6586x: mo...
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
  		if (id == TPS6586X_ID_SYS)
  			sys_rail = pdata->reg_init_data[i]->constraints.name;
  
  		if ((id == TPS6586X_ID_LDO_5) || (id == TPS6586X_ID_LDO_RTC))
  			pdata->reg_init_data[i]->supply_regulator = sys_rail;
  	}
  	*tps6586x_reg_matches = tps6586x_matches;
  	return pdata;
  }
  #else
  static struct tps6586x_platform_data *tps6586x_parse_regulator_dt(
  		struct platform_device *pdev,
  		struct of_regulator_match **tps6586x_reg_matches)
  {
  	*tps6586x_reg_matches = NULL;
  	return NULL;
  }
  #endif
a5023574d   Bill Pemberton   regulator: remove...
422
  static int tps6586x_regulator_probe(struct platform_device *pdev)
49610235d   Mike Rapoport   regulator: add TP...
423
424
  {
  	struct tps6586x_regulator *ri = NULL;
c172708d3   Mark Brown   regulator: core: ...
425
  	struct regulator_config config = { };
d6fe2c725   Axel Lin   regulator: tps658...
426
  	struct regulator_dev *rdev;
64e481603   Laxman Dewangan   mfd: tps6586x: mo...
427
428
429
  	struct regulator_init_data *reg_data;
  	struct tps6586x_platform_data *pdata;
  	struct of_regulator_match *tps6586x_reg_matches = NULL;
844a4f0d8   Stefan Agner   regulator: tps658...
430
  	int version;
64e481603   Laxman Dewangan   mfd: tps6586x: mo...
431
  	int id;
49610235d   Mike Rapoport   regulator: add TP...
432
  	int err;
10835600c   Laxman Dewangan   regulator: tps658...
433
434
  	dev_dbg(&pdev->dev, "Probing regulator
  ");
49610235d   Mike Rapoport   regulator: add TP...
435

64e481603   Laxman Dewangan   mfd: tps6586x: mo...
436
437
438
439
  	pdata = dev_get_platdata(pdev->dev.parent);
  	if ((!pdata) && (pdev->dev.parent->of_node))
  		pdata = tps6586x_parse_regulator_dt(pdev,
  					&tps6586x_reg_matches);
49610235d   Mike Rapoport   regulator: add TP...
440

64e481603   Laxman Dewangan   mfd: tps6586x: mo...
441
442
443
444
445
  	if (!pdata) {
  		dev_err(&pdev->dev, "Platform data not available, exiting
  ");
  		return -ENODEV;
  	}
49610235d   Mike Rapoport   regulator: add TP...
446

844a4f0d8   Stefan Agner   regulator: tps658...
447
  	version = tps6586x_get_version(pdev->dev.parent);
64e481603   Laxman Dewangan   mfd: tps6586x: mo...
448
449
  	for (id = 0; id < TPS6586X_ID_MAX_REGULATOR; ++id) {
  		reg_data = pdata->reg_init_data[id];
844a4f0d8   Stefan Agner   regulator: tps658...
450
  		ri = find_regulator_info(id, version);
64e481603   Laxman Dewangan   mfd: tps6586x: mo...
451
452
453
  		if (!ri) {
  			dev_err(&pdev->dev, "invalid regulator ID specified
  ");
884ea5570   Sachin Kamat   regulator: tps658...
454
  			return -EINVAL;
64e481603   Laxman Dewangan   mfd: tps6586x: mo...
455
456
457
458
459
460
461
  		}
  
  		err = tps6586x_regulator_preinit(pdev->dev.parent, ri);
  		if (err) {
  			dev_err(&pdev->dev,
  				"regulator %d preinit failed, e %d
  ", id, err);
884ea5570   Sachin Kamat   regulator: tps658...
462
  			return err;
64e481603   Laxman Dewangan   mfd: tps6586x: mo...
463
464
465
466
467
468
469
470
  		}
  
  		config.dev = pdev->dev.parent;
  		config.init_data = reg_data;
  		config.driver_data = ri;
  
  		if (tps6586x_reg_matches)
  			config.of_node = tps6586x_reg_matches[id].of_node;
d6fe2c725   Axel Lin   regulator: tps658...
471
472
  		rdev = devm_regulator_register(&pdev->dev, &ri->desc, &config);
  		if (IS_ERR(rdev)) {
64e481603   Laxman Dewangan   mfd: tps6586x: mo...
473
474
475
  			dev_err(&pdev->dev, "failed to register regulator %s
  ",
  					ri->desc.name);
d6fe2c725   Axel Lin   regulator: tps658...
476
  			return PTR_ERR(rdev);
64e481603   Laxman Dewangan   mfd: tps6586x: mo...
477
478
479
480
481
482
483
484
485
  		}
  
  		if (reg_data) {
  			err = tps6586x_regulator_set_slew_rate(pdev, id,
  					reg_data);
  			if (err < 0) {
  				dev_err(&pdev->dev,
  					"Slew rate config failed, e %d
  ", err);
884ea5570   Sachin Kamat   regulator: tps658...
486
  				return err;
64e481603   Laxman Dewangan   mfd: tps6586x: mo...
487
488
  			}
  		}
49610235d   Mike Rapoport   regulator: add TP...
489
  	}
e7973c3cb   Axel Lin   regulator: tps658...
490
  	platform_set_drvdata(pdev, rdev);
64e481603   Laxman Dewangan   mfd: tps6586x: mo...
491
  	return 0;
49610235d   Mike Rapoport   regulator: add TP...
492
493
494
495
  }
  
  static struct platform_driver tps6586x_regulator_driver = {
  	.driver	= {
ec8da805c   Marc Dietrich   mfd: tps6586x: co...
496
  		.name	= "tps6586x-regulator",
49610235d   Mike Rapoport   regulator: add TP...
497
498
  	},
  	.probe		= tps6586x_regulator_probe,
49610235d   Mike Rapoport   regulator: add TP...
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
  };
  
  static int __init tps6586x_regulator_init(void)
  {
  	return platform_driver_register(&tps6586x_regulator_driver);
  }
  subsys_initcall(tps6586x_regulator_init);
  
  static void __exit tps6586x_regulator_exit(void)
  {
  	platform_driver_unregister(&tps6586x_regulator_driver);
  }
  module_exit(tps6586x_regulator_exit);
  
  MODULE_LICENSE("GPL");
  MODULE_AUTHOR("Mike Rapoport <mike@compulab.co.il>");
  MODULE_DESCRIPTION("Regulator Driver for TI TPS6586X PMIC");
  MODULE_ALIAS("platform:tps6586x-regulator");