Blame view

drivers/regulator/hi6421-regulator.c 17.8 KB
8b9085200   Axel Lin   regulator: hi6xxx...
1
2
3
4
5
6
7
8
9
10
  // SPDX-License-Identifier: GPL-2.0
  //
  // Device driver for regulators in Hi6421 IC
  //
  // Copyright (c) <2011-2014> HiSilicon Technologies Co., Ltd.
  //              http://www.hisilicon.com
  // Copyright (c) <2013-2014> Linaro Ltd.
  //              http://www.linaro.org
  //
  // Author: Guodong Xu <guodong.xu@linaro.org>
87ca186f7   Guodong Xu   regulator: add dr...
11
12
13
14
15
  
  #include <linux/slab.h>
  #include <linux/device.h>
  #include <linux/module.h>
  #include <linux/err.h>
87ca186f7   Guodong Xu   regulator: add dr...
16
17
  #include <linux/platform_device.h>
  #include <linux/of.h>
87ca186f7   Guodong Xu   regulator: add dr...
18
19
20
21
22
  #include <linux/regmap.h>
  #include <linux/regulator/driver.h>
  #include <linux/regulator/machine.h>
  #include <linux/regulator/of_regulator.h>
  #include <linux/mfd/hi6421-pmic.h>
87ca186f7   Guodong Xu   regulator: add dr...
23
24
25
26
27
28
29
30
31
32
33
  
  /*
   * struct hi6421_regulator_pdata - Hi6421 regulator data of platform device
   * @lock: mutex to serialize regulator enable
   */
  struct hi6421_regulator_pdata {
  	struct mutex lock;
  };
  
  /*
   * struct hi6421_regulator_info - hi6421 regulator information
87ca186f7   Guodong Xu   regulator: add dr...
34
   * @desc: regulator description
87ca186f7   Guodong Xu   regulator: add dr...
35
   * @mode_mask: ECO mode bitmask of LDOs; for BUCKs, this masks sleep
97795e4da   Axel Lin   regulator: hi6421...
36
   * @eco_microamp: eco mode load upper limit (in uA), valid for LDOs only
87ca186f7   Guodong Xu   regulator: add dr...
37
38
   */
  struct hi6421_regulator_info {
87ca186f7   Guodong Xu   regulator: add dr...
39
  	struct regulator_desc	desc;
87ca186f7   Guodong Xu   regulator: add dr...
40
41
  	u8		mode_mask;
  	u32		eco_microamp;
87ca186f7   Guodong Xu   regulator: add dr...
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
  };
  
  /* HI6421 regulators */
  enum hi6421_regulator_id {
  	HI6421_LDO0,
  	HI6421_LDO1,
  	HI6421_LDO2,
  	HI6421_LDO3,
  	HI6421_LDO4,
  	HI6421_LDO5,
  	HI6421_LDO6,
  	HI6421_LDO7,
  	HI6421_LDO8,
  	HI6421_LDO9,
  	HI6421_LDO10,
  	HI6421_LDO11,
  	HI6421_LDO12,
  	HI6421_LDO13,
  	HI6421_LDO14,
  	HI6421_LDO15,
  	HI6421_LDO16,
  	HI6421_LDO17,
  	HI6421_LDO18,
  	HI6421_LDO19,
  	HI6421_LDO20,
  	HI6421_LDOAUDIO,
  	HI6421_BUCK0,
  	HI6421_BUCK1,
  	HI6421_BUCK2,
  	HI6421_BUCK3,
  	HI6421_BUCK4,
  	HI6421_BUCK5,
  	HI6421_NUM_REGULATORS,
  };
87ca186f7   Guodong Xu   regulator: add dr...
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
  /* LDO 0, 4~7, 9~14, 16~20 have same voltage table. */
  static const unsigned int ldo_0_voltages[] = {
  	1500000, 1800000, 2400000, 2500000,
  	2600000, 2700000, 2850000, 3000000,
  };
  
  /* LDO 8, 15 have same voltage table. */
  static const unsigned int ldo_8_voltages[] = {
  	1500000, 1800000, 2400000, 2600000,
  	2700000, 2850000, 3000000, 3300000,
  };
  
  /* Ranges are sorted in ascending order. */
  static const struct regulator_linear_range ldo_audio_volt_range[] = {
  	REGULATOR_LINEAR_RANGE(2800000, 0, 3, 50000),
  	REGULATOR_LINEAR_RANGE(3000000, 4, 7, 100000),
  };
  
  static const unsigned int buck_3_voltages[] = {
  	 950000, 1050000, 1100000, 1117000,
  	1134000, 1150000, 1167000, 1200000,
  };
  
  static const unsigned int buck_4_voltages[] = {
  	1150000, 1200000, 1250000, 1350000,
  	1700000, 1800000, 1900000, 2000000,
  };
  
  static const unsigned int buck_5_voltages[] = {
  	1150000, 1200000, 1250000, 1350000,
  	1600000, 1700000, 1800000, 1900000,
  };
  
  static const struct regulator_ops hi6421_ldo_ops;
  static const struct regulator_ops hi6421_ldo_linear_ops;
  static const struct regulator_ops hi6421_ldo_linear_range_ops;
  static const struct regulator_ops hi6421_buck012_ops;
  static const struct regulator_ops hi6421_buck345_ops;
  
  #define HI6421_LDO_ENABLE_TIME (350)
  /*
   * _id - LDO id name string
29dc269a8   Axel Lin   regulator: hi6421...
118
   * _match - of match name string
87ca186f7   Guodong Xu   regulator: add dr...
119
120
121
122
123
124
125
   * v_table - voltage table
   * vreg - voltage select register
   * vmask - voltage select mask
   * ereg - enable register
   * emask - enable mask
   * odelay - off/on delay time in uS
   * ecomask - eco mode mask
5c5e417bc   Axel Lin   regulator: hi6421...
126
   * ecoamp - eco mode load uppler limit in uA
87ca186f7   Guodong Xu   regulator: add dr...
127
   */
29dc269a8   Axel Lin   regulator: hi6421...
128
  #define HI6421_LDO(_id, _match, v_table, vreg, vmask, ereg, emask,	\
87ca186f7   Guodong Xu   regulator: add dr...
129
130
131
132
  		   odelay, ecomask, ecoamp)				\
  	[HI6421_##_id] = {						\
  		.desc = {						\
  			.name		= #_id,				\
29dc269a8   Axel Lin   regulator: hi6421...
133
134
  			.of_match        = of_match_ptr(#_match),	\
  			.regulators_node = of_match_ptr("regulators"),	\
87ca186f7   Guodong Xu   regulator: add dr...
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
  			.ops		= &hi6421_ldo_ops,		\
  			.type		= REGULATOR_VOLTAGE,		\
  			.id		= HI6421_##_id,			\
  			.owner		= THIS_MODULE,			\
  			.n_voltages	= ARRAY_SIZE(v_table),		\
  			.volt_table	= v_table,			\
  			.vsel_reg	= HI6421_REG_TO_BUS_ADDR(vreg),	\
  			.vsel_mask	= vmask,			\
  			.enable_reg	= HI6421_REG_TO_BUS_ADDR(ereg),	\
  			.enable_mask	= emask,			\
  			.enable_time	= HI6421_LDO_ENABLE_TIME,	\
  			.off_on_delay	= odelay,			\
  		},							\
  		.mode_mask		= ecomask,			\
  		.eco_microamp		= ecoamp,			\
87ca186f7   Guodong Xu   regulator: add dr...
150
151
152
153
154
  	}
  
  /* HI6421 LDO1~3 are linear voltage regulators at fixed uV_step
   *
   * _id - LDO id name string
29dc269a8   Axel Lin   regulator: hi6421...
155
   * _match - of match name string
87ca186f7   Guodong Xu   regulator: add dr...
156
157
158
159
160
161
162
163
164
   * _min_uV - minimum voltage supported in uV
   * n_volt - number of votages available
   * vstep - voltage increase in each linear step in uV
   * vreg - voltage select register
   * vmask - voltage select mask
   * ereg - enable register
   * emask - enable mask
   * odelay - off/on delay time in uS
   * ecomask - eco mode mask
5c5e417bc   Axel Lin   regulator: hi6421...
165
   * ecoamp - eco mode load uppler limit in uA
87ca186f7   Guodong Xu   regulator: add dr...
166
   */
29dc269a8   Axel Lin   regulator: hi6421...
167
  #define HI6421_LDO_LINEAR(_id, _match, _min_uV, n_volt, vstep, vreg, vmask,\
87ca186f7   Guodong Xu   regulator: add dr...
168
169
170
171
  			  ereg, emask, odelay, ecomask, ecoamp)		\
  	[HI6421_##_id] = {						\
  		.desc = {						\
  			.name		= #_id,				\
29dc269a8   Axel Lin   regulator: hi6421...
172
173
  			.of_match        = of_match_ptr(#_match),	\
  			.regulators_node = of_match_ptr("regulators"),	\
87ca186f7   Guodong Xu   regulator: add dr...
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
  			.ops		= &hi6421_ldo_linear_ops,	\
  			.type		= REGULATOR_VOLTAGE,		\
  			.id		= HI6421_##_id,			\
  			.owner		= THIS_MODULE,			\
  			.min_uV		= _min_uV,			\
  			.n_voltages	= n_volt,			\
  			.uV_step	= vstep,			\
  			.vsel_reg	= HI6421_REG_TO_BUS_ADDR(vreg),	\
  			.vsel_mask	= vmask,			\
  			.enable_reg	= HI6421_REG_TO_BUS_ADDR(ereg),	\
  			.enable_mask	= emask,			\
  			.enable_time	= HI6421_LDO_ENABLE_TIME,	\
  			.off_on_delay	= odelay,			\
  		},							\
  		.mode_mask		= ecomask,			\
  		.eco_microamp		= ecoamp,			\
87ca186f7   Guodong Xu   regulator: add dr...
190
191
192
193
194
  	}
  
  /* HI6421 LDOAUDIO is a linear voltage regulator with two 4-step ranges
   *
   * _id - LDO id name string
29dc269a8   Axel Lin   regulator: hi6421...
195
   * _match - of match name string
87ca186f7   Guodong Xu   regulator: add dr...
196
197
198
199
200
201
202
203
204
   * n_volt - number of votages available
   * volt_ranges - array of regulator_linear_range
   * vstep - voltage increase in each linear step in uV
   * vreg - voltage select register
   * vmask - voltage select mask
   * ereg - enable register
   * emask - enable mask
   * odelay - off/on delay time in uS
   * ecomask - eco mode mask
5c5e417bc   Axel Lin   regulator: hi6421...
205
   * ecoamp - eco mode load uppler limit in uA
87ca186f7   Guodong Xu   regulator: add dr...
206
   */
29dc269a8   Axel Lin   regulator: hi6421...
207
  #define HI6421_LDO_LINEAR_RANGE(_id, _match, n_volt, volt_ranges, vreg, vmask,\
87ca186f7   Guodong Xu   regulator: add dr...
208
209
210
211
  				ereg, emask, odelay, ecomask, ecoamp)	\
  	[HI6421_##_id] = {						\
  		.desc = {						\
  			.name		= #_id,				\
29dc269a8   Axel Lin   regulator: hi6421...
212
213
  			.of_match        = of_match_ptr(#_match),	\
  			.regulators_node = of_match_ptr("regulators"),	\
87ca186f7   Guodong Xu   regulator: add dr...
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
  			.ops		= &hi6421_ldo_linear_range_ops,	\
  			.type		= REGULATOR_VOLTAGE,		\
  			.id		= HI6421_##_id,			\
  			.owner		= THIS_MODULE,			\
  			.n_voltages	= n_volt,			\
  			.linear_ranges	= volt_ranges,			\
  			.n_linear_ranges = ARRAY_SIZE(volt_ranges),	\
  			.vsel_reg	= HI6421_REG_TO_BUS_ADDR(vreg),	\
  			.vsel_mask	= vmask,			\
  			.enable_reg	= HI6421_REG_TO_BUS_ADDR(ereg),	\
  			.enable_mask	= emask,			\
  			.enable_time	= HI6421_LDO_ENABLE_TIME,	\
  			.off_on_delay	= odelay,			\
  		},							\
  		.mode_mask		= ecomask,			\
  		.eco_microamp		= ecoamp,			\
87ca186f7   Guodong Xu   regulator: add dr...
230
231
232
233
234
  	}
  
  /* HI6421 BUCK0/1/2 are linear voltage regulators at fixed uV_step
   *
   * _id - BUCK0/1/2 id name string
29dc269a8   Axel Lin   regulator: hi6421...
235
   * _match - of match name string
87ca186f7   Guodong Xu   regulator: add dr...
236
237
238
239
240
241
242
243
   * vreg - voltage select register
   * vmask - voltage select mask
   * ereg - enable register
   * emask - enable mask
   * sleepmask - mask of sleep mode
   * etime - enable time
   * odelay - off/on delay time in uS
   */
29dc269a8   Axel Lin   regulator: hi6421...
244
  #define HI6421_BUCK012(_id, _match, vreg, vmask, ereg, emask, sleepmask,\
87ca186f7   Guodong Xu   regulator: add dr...
245
246
247
248
  			etime, odelay)					\
  	[HI6421_##_id] = {						\
  		.desc = {						\
  			.name		= #_id,				\
29dc269a8   Axel Lin   regulator: hi6421...
249
250
  			.of_match        = of_match_ptr(#_match),	\
  			.regulators_node = of_match_ptr("regulators"),	\
87ca186f7   Guodong Xu   regulator: add dr...
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
  			.ops		= &hi6421_buck012_ops,		\
  			.type		= REGULATOR_VOLTAGE,		\
  			.id		= HI6421_##_id,			\
  			.owner		= THIS_MODULE,			\
  			.min_uV		= 700000,			\
  			.n_voltages	= 128,				\
  			.uV_step	= 7086,				\
  			.vsel_reg	= HI6421_REG_TO_BUS_ADDR(vreg),	\
  			.vsel_mask	= vmask,			\
  			.enable_reg	= HI6421_REG_TO_BUS_ADDR(ereg),	\
  			.enable_mask	= emask,			\
  			.enable_time	= etime,			\
  			.off_on_delay	= odelay,			\
  		},							\
  		.mode_mask		= sleepmask,			\
87ca186f7   Guodong Xu   regulator: add dr...
266
267
268
269
270
271
  	}
  
  /* HI6421 BUCK3/4/5 share similar configurations as LDOs, with exception
   *  that it supports SLEEP mode, so has different .ops.
   *
   * _id - LDO id name string
29dc269a8   Axel Lin   regulator: hi6421...
272
   * _match - of match name string
87ca186f7   Guodong Xu   regulator: add dr...
273
274
275
276
277
278
279
280
   * v_table - voltage table
   * vreg - voltage select register
   * vmask - voltage select mask
   * ereg - enable register
   * emask - enable mask
   * odelay - off/on delay time in uS
   * sleepmask - mask of sleep mode
   */
29dc269a8   Axel Lin   regulator: hi6421...
281
  #define HI6421_BUCK345(_id, _match, v_table, vreg, vmask, ereg, emask,	\
87ca186f7   Guodong Xu   regulator: add dr...
282
283
284
285
  			odelay, sleepmask)				\
  	[HI6421_##_id] = {						\
  		.desc = {						\
  			.name		= #_id,				\
29dc269a8   Axel Lin   regulator: hi6421...
286
287
  			.of_match        = of_match_ptr(#_match),	\
  			.regulators_node = of_match_ptr("regulators"),	\
87ca186f7   Guodong Xu   regulator: add dr...
288
289
290
291
292
293
294
295
296
297
298
299
300
301
  			.ops		= &hi6421_buck345_ops,		\
  			.type		= REGULATOR_VOLTAGE,		\
  			.id		= HI6421_##_id,			\
  			.owner		= THIS_MODULE,			\
  			.n_voltages	= ARRAY_SIZE(v_table),		\
  			.volt_table	= v_table,			\
  			.vsel_reg	= HI6421_REG_TO_BUS_ADDR(vreg),	\
  			.vsel_mask	= vmask,			\
  			.enable_reg	= HI6421_REG_TO_BUS_ADDR(ereg),	\
  			.enable_mask	= emask,			\
  			.enable_time	= HI6421_LDO_ENABLE_TIME,	\
  			.off_on_delay	= odelay,			\
  		},							\
  		.mode_mask		= sleepmask,			\
87ca186f7   Guodong Xu   regulator: add dr...
302
303
304
305
306
  	}
  
  /* HI6421 regulator information */
  static struct hi6421_regulator_info
  		hi6421_regulator_info[HI6421_NUM_REGULATORS] = {
29dc269a8   Axel Lin   regulator: hi6421...
307
  	HI6421_LDO(LDO0, hi6421_vout0, ldo_0_voltages, 0x20, 0x07, 0x20, 0x10,
87ca186f7   Guodong Xu   regulator: add dr...
308
  		   10000, 0x20, 8000),
29dc269a8   Axel Lin   regulator: hi6421...
309
310
311
312
313
314
315
  	HI6421_LDO_LINEAR(LDO1, hi6421_vout1, 1700000, 4, 100000, 0x21, 0x03,
  			  0x21, 0x10, 10000, 0x20, 5000),
  	HI6421_LDO_LINEAR(LDO2, hi6421_vout2, 1050000, 8, 50000, 0x22, 0x07,
  			  0x22, 0x10, 20000, 0x20, 8000),
  	HI6421_LDO_LINEAR(LDO3, hi6421_vout3, 1050000, 8, 50000, 0x23, 0x07,
  			  0x23, 0x10, 20000, 0x20, 8000),
  	HI6421_LDO(LDO4, hi6421_vout4, ldo_0_voltages, 0x24, 0x07, 0x24, 0x10,
87ca186f7   Guodong Xu   regulator: add dr...
316
  		   20000, 0x20, 8000),
29dc269a8   Axel Lin   regulator: hi6421...
317
  	HI6421_LDO(LDO5, hi6421_vout5, ldo_0_voltages, 0x25, 0x07, 0x25, 0x10,
87ca186f7   Guodong Xu   regulator: add dr...
318
  		   20000, 0x20, 8000),
29dc269a8   Axel Lin   regulator: hi6421...
319
  	HI6421_LDO(LDO6, hi6421_vout6, ldo_0_voltages, 0x26, 0x07, 0x26, 0x10,
87ca186f7   Guodong Xu   regulator: add dr...
320
  		   20000, 0x20, 8000),
29dc269a8   Axel Lin   regulator: hi6421...
321
  	HI6421_LDO(LDO7, hi6421_vout7, ldo_0_voltages, 0x27, 0x07, 0x27, 0x10,
87ca186f7   Guodong Xu   regulator: add dr...
322
  		   20000, 0x20, 5000),
29dc269a8   Axel Lin   regulator: hi6421...
323
  	HI6421_LDO(LDO8, hi6421_vout8, ldo_8_voltages, 0x28, 0x07, 0x28, 0x10,
87ca186f7   Guodong Xu   regulator: add dr...
324
  		   20000, 0x20, 8000),
29dc269a8   Axel Lin   regulator: hi6421...
325
  	HI6421_LDO(LDO9, hi6421_vout9, ldo_0_voltages, 0x29, 0x07, 0x29, 0x10,
87ca186f7   Guodong Xu   regulator: add dr...
326
  		   40000, 0x20, 8000),
29dc269a8   Axel Lin   regulator: hi6421...
327
  	HI6421_LDO(LDO10, hi6421_vout10, ldo_0_voltages, 0x2a, 0x07, 0x2a, 0x10,
87ca186f7   Guodong Xu   regulator: add dr...
328
  		   40000, 0x20, 8000),
29dc269a8   Axel Lin   regulator: hi6421...
329
  	HI6421_LDO(LDO11, hi6421_vout11, ldo_0_voltages, 0x2b, 0x07, 0x2b, 0x10,
87ca186f7   Guodong Xu   regulator: add dr...
330
  		   40000, 0x20, 8000),
29dc269a8   Axel Lin   regulator: hi6421...
331
  	HI6421_LDO(LDO12, hi6421_vout12, ldo_0_voltages, 0x2c, 0x07, 0x2c, 0x10,
87ca186f7   Guodong Xu   regulator: add dr...
332
  		   40000, 0x20, 8000),
29dc269a8   Axel Lin   regulator: hi6421...
333
  	HI6421_LDO(LDO13, hi6421_vout13, ldo_0_voltages, 0x2d, 0x07, 0x2d, 0x10,
87ca186f7   Guodong Xu   regulator: add dr...
334
  		   40000, 0x20, 8000),
29dc269a8   Axel Lin   regulator: hi6421...
335
  	HI6421_LDO(LDO14, hi6421_vout14, ldo_0_voltages, 0x2e, 0x07, 0x2e, 0x10,
87ca186f7   Guodong Xu   regulator: add dr...
336
  		   40000, 0x20, 8000),
29dc269a8   Axel Lin   regulator: hi6421...
337
  	HI6421_LDO(LDO15, hi6421_vout15, ldo_8_voltages, 0x2f, 0x07, 0x2f, 0x10,
87ca186f7   Guodong Xu   regulator: add dr...
338
  		   40000, 0x20, 8000),
29dc269a8   Axel Lin   regulator: hi6421...
339
  	HI6421_LDO(LDO16, hi6421_vout16, ldo_0_voltages, 0x30, 0x07, 0x30, 0x10,
87ca186f7   Guodong Xu   regulator: add dr...
340
  		   40000, 0x20, 8000),
29dc269a8   Axel Lin   regulator: hi6421...
341
  	HI6421_LDO(LDO17, hi6421_vout17, ldo_0_voltages, 0x31, 0x07, 0x31, 0x10,
87ca186f7   Guodong Xu   regulator: add dr...
342
  		   40000, 0x20, 8000),
29dc269a8   Axel Lin   regulator: hi6421...
343
  	HI6421_LDO(LDO18, hi6421_vout18, ldo_0_voltages, 0x32, 0x07, 0x32, 0x10,
87ca186f7   Guodong Xu   regulator: add dr...
344
  		   40000, 0x20, 8000),
29dc269a8   Axel Lin   regulator: hi6421...
345
  	HI6421_LDO(LDO19, hi6421_vout19, ldo_0_voltages, 0x33, 0x07, 0x33, 0x10,
87ca186f7   Guodong Xu   regulator: add dr...
346
  		   40000, 0x20, 8000),
29dc269a8   Axel Lin   regulator: hi6421...
347
  	HI6421_LDO(LDO20, hi6421_vout20, ldo_0_voltages, 0x34, 0x07, 0x34, 0x10,
87ca186f7   Guodong Xu   regulator: add dr...
348
  		   40000, 0x20, 8000),
29dc269a8   Axel Lin   regulator: hi6421...
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
  	HI6421_LDO_LINEAR_RANGE(LDOAUDIO, hi6421_vout_audio, 8,
  				ldo_audio_volt_range, 0x36, 0x70, 0x36, 0x01,
  				40000, 0x02, 5000),
  	HI6421_BUCK012(BUCK0, hi6421_buck0, 0x0d, 0x7f, 0x0c, 0x01, 0x10, 400,
  		       20000),
  	HI6421_BUCK012(BUCK1, hi6421_buck1, 0x0f, 0x7f, 0x0e, 0x01, 0x10, 400,
  		       20000),
  	HI6421_BUCK012(BUCK2, hi6421_buck2, 0x11, 0x7f, 0x10, 0x01, 0x10, 350,
  		       100),
  	HI6421_BUCK345(BUCK3, hi6421_buck3, buck_3_voltages, 0x13, 0x07, 0x12,
  		       0x01, 20000, 0x10),
  	HI6421_BUCK345(BUCK4, hi6421_buck4, buck_4_voltages, 0x15, 0x07, 0x14,
  		       0x01, 20000, 0x10),
  	HI6421_BUCK345(BUCK5, hi6421_buck5, buck_5_voltages, 0x17, 0x07, 0x16,
  		       0x01, 20000, 0x10),
87ca186f7   Guodong Xu   regulator: add dr...
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
  };
  
  static int hi6421_regulator_enable(struct regulator_dev *rdev)
  {
  	struct hi6421_regulator_pdata *pdata;
  
  	pdata = dev_get_drvdata(rdev->dev.parent);
  	/* hi6421 spec requires regulator enablement must be serialized:
  	 *  - Because when BUCK, LDO switching from off to on, it will have
  	 *    a huge instantaneous current; so you can not turn on two or
  	 *    more LDO or BUCKs simultaneously, or it may burn the chip.
  	 */
  	mutex_lock(&pdata->lock);
  
  	/* call regulator regmap helper */
  	regulator_enable_regmap(rdev);
  
  	mutex_unlock(&pdata->lock);
  	return 0;
  }
  
  static unsigned int hi6421_regulator_ldo_get_mode(struct regulator_dev *rdev)
  {
  	struct hi6421_regulator_info *info = rdev_get_drvdata(rdev);
  	u32 reg_val;
  
  	regmap_read(rdev->regmap, rdev->desc->enable_reg, &reg_val);
  	if (reg_val & info->mode_mask)
  		return REGULATOR_MODE_IDLE;
ea62f4dfe   Guodong Xu   regulator: hi6421...
393
394
  
  	return REGULATOR_MODE_NORMAL;
87ca186f7   Guodong Xu   regulator: add dr...
395
396
397
398
399
400
401
402
403
404
  }
  
  static unsigned int hi6421_regulator_buck_get_mode(struct regulator_dev *rdev)
  {
  	struct hi6421_regulator_info *info = rdev_get_drvdata(rdev);
  	u32 reg_val;
  
  	regmap_read(rdev->regmap, rdev->desc->enable_reg, &reg_val);
  	if (reg_val & info->mode_mask)
  		return REGULATOR_MODE_STANDBY;
ea62f4dfe   Guodong Xu   regulator: hi6421...
405
406
  
  	return REGULATOR_MODE_NORMAL;
87ca186f7   Guodong Xu   regulator: add dr...
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
  }
  
  static int hi6421_regulator_ldo_set_mode(struct regulator_dev *rdev,
  						unsigned int mode)
  {
  	struct hi6421_regulator_info *info = rdev_get_drvdata(rdev);
  	u32 new_mode;
  
  	switch (mode) {
  	case REGULATOR_MODE_NORMAL:
  		new_mode = 0;
  		break;
  	case REGULATOR_MODE_IDLE:
  		new_mode = info->mode_mask;
  		break;
  	default:
  		return -EINVAL;
  	}
  
  	/* set mode */
  	regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
  			   info->mode_mask, new_mode);
  
  	return 0;
  }
  
  static int hi6421_regulator_buck_set_mode(struct regulator_dev *rdev,
  						unsigned int mode)
  {
  	struct hi6421_regulator_info *info = rdev_get_drvdata(rdev);
  	u32 new_mode;
  
  	switch (mode) {
  	case REGULATOR_MODE_NORMAL:
  		new_mode = 0;
  		break;
  	case REGULATOR_MODE_STANDBY:
  		new_mode = info->mode_mask;
  		break;
  	default:
  		return -EINVAL;
  	}
  
  	/* set mode */
  	regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
  			   info->mode_mask, new_mode);
  
  	return 0;
  }
ea2f7321a   Baoyou Xie   regulator: hi6421...
456
457
  static unsigned int
  hi6421_regulator_ldo_get_optimum_mode(struct regulator_dev *rdev,
87ca186f7   Guodong Xu   regulator: add dr...
458
459
460
461
462
463
  			int input_uV, int output_uV, int load_uA)
  {
  	struct hi6421_regulator_info *info = rdev_get_drvdata(rdev);
  
  	if (load_uA > info->eco_microamp)
  		return REGULATOR_MODE_NORMAL;
ea62f4dfe   Guodong Xu   regulator: hi6421...
464
465
  
  	return REGULATOR_MODE_IDLE;
87ca186f7   Guodong Xu   regulator: add dr...
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
  }
  
  static const struct regulator_ops hi6421_ldo_ops = {
  	.is_enabled = regulator_is_enabled_regmap,
  	.enable = hi6421_regulator_enable,
  	.disable = regulator_disable_regmap,
  	.list_voltage = regulator_list_voltage_table,
  	.map_voltage = regulator_map_voltage_ascend,
  	.get_voltage_sel = regulator_get_voltage_sel_regmap,
  	.set_voltage_sel = regulator_set_voltage_sel_regmap,
  	.get_mode = hi6421_regulator_ldo_get_mode,
  	.set_mode = hi6421_regulator_ldo_set_mode,
  	.get_optimum_mode = hi6421_regulator_ldo_get_optimum_mode,
  };
  
  static const struct regulator_ops hi6421_ldo_linear_ops = {
  	.is_enabled = regulator_is_enabled_regmap,
  	.enable = hi6421_regulator_enable,
  	.disable = regulator_disable_regmap,
  	.list_voltage = regulator_list_voltage_linear,
  	.map_voltage = regulator_map_voltage_linear,
  	.get_voltage_sel = regulator_get_voltage_sel_regmap,
  	.set_voltage_sel = regulator_set_voltage_sel_regmap,
  	.get_mode = hi6421_regulator_ldo_get_mode,
  	.set_mode = hi6421_regulator_ldo_set_mode,
  	.get_optimum_mode = hi6421_regulator_ldo_get_optimum_mode,
  };
  
  static const struct regulator_ops hi6421_ldo_linear_range_ops = {
  	.is_enabled = regulator_is_enabled_regmap,
  	.enable = hi6421_regulator_enable,
  	.disable = regulator_disable_regmap,
  	.list_voltage = regulator_list_voltage_linear_range,
  	.map_voltage = regulator_map_voltage_linear_range,
  	.get_voltage_sel = regulator_get_voltage_sel_regmap,
  	.set_voltage_sel = regulator_set_voltage_sel_regmap,
  	.get_mode = hi6421_regulator_ldo_get_mode,
  	.set_mode = hi6421_regulator_ldo_set_mode,
  	.get_optimum_mode = hi6421_regulator_ldo_get_optimum_mode,
  };
  
  static const struct regulator_ops hi6421_buck012_ops = {
  	.is_enabled = regulator_is_enabled_regmap,
  	.enable = hi6421_regulator_enable,
  	.disable = regulator_disable_regmap,
  	.list_voltage = regulator_list_voltage_linear,
  	.map_voltage = regulator_map_voltage_linear,
  	.get_voltage_sel = regulator_get_voltage_sel_regmap,
  	.set_voltage_sel = regulator_set_voltage_sel_regmap,
  	.get_mode = hi6421_regulator_buck_get_mode,
  	.set_mode = hi6421_regulator_buck_set_mode,
  };
  
  static const struct regulator_ops hi6421_buck345_ops = {
  	.is_enabled = regulator_is_enabled_regmap,
  	.enable = hi6421_regulator_enable,
  	.disable = regulator_disable_regmap,
  	.list_voltage = regulator_list_voltage_table,
  	.map_voltage = regulator_map_voltage_ascend,
  	.get_voltage_sel = regulator_get_voltage_sel_regmap,
  	.set_voltage_sel = regulator_set_voltage_sel_regmap,
  	.get_mode = hi6421_regulator_buck_get_mode,
  	.set_mode = hi6421_regulator_buck_set_mode,
  };
87ca186f7   Guodong Xu   regulator: add dr...
530
531
  static int hi6421_regulator_probe(struct platform_device *pdev)
  {
29dc269a8   Axel Lin   regulator: hi6421...
532
  	struct hi6421_pmic *pmic = dev_get_drvdata(pdev->dev.parent);
87ca186f7   Guodong Xu   regulator: add dr...
533
  	struct hi6421_regulator_pdata *pdata;
29dc269a8   Axel Lin   regulator: hi6421...
534
535
536
537
  	struct hi6421_regulator_info *info;
  	struct regulator_config config = { };
  	struct regulator_dev *rdev;
  	int i;
87ca186f7   Guodong Xu   regulator: add dr...
538
539
540
541
542
543
  
  	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
  	if (!pdata)
  		return -ENOMEM;
  	mutex_init(&pdata->lock);
  	platform_set_drvdata(pdev, pdata);
87ca186f7   Guodong Xu   regulator: add dr...
544
  	for (i = 0; i < ARRAY_SIZE(hi6421_regulator_info); i++) {
29dc269a8   Axel Lin   regulator: hi6421...
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
  		/* assign per-regulator data */
  		info = &hi6421_regulator_info[i];
  
  		config.dev = pdev->dev.parent;
  		config.driver_data = info;
  		config.regmap = pmic->regmap;
  
  		rdev = devm_regulator_register(&pdev->dev, &info->desc,
  					       &config);
  		if (IS_ERR(rdev)) {
  			dev_err(&pdev->dev, "failed to register regulator %s
  ",
  				info->desc.name);
  			return PTR_ERR(rdev);
  		}
87ca186f7   Guodong Xu   regulator: add dr...
560
561
562
563
  	}
  
  	return 0;
  }
a8ea49d7f   Guodong Xu   regulator: hi6421...
564
565
566
567
568
  static const struct platform_device_id hi6421_regulator_table[] = {
  	{ .name = "hi6421-regulator" },
  	{},
  };
  MODULE_DEVICE_TABLE(platform, hi6421_regulator_table);
87ca186f7   Guodong Xu   regulator: add dr...
569
  static struct platform_driver hi6421_regulator_driver = {
a8ea49d7f   Guodong Xu   regulator: hi6421...
570
  	.id_table = hi6421_regulator_table,
87ca186f7   Guodong Xu   regulator: add dr...
571
572
  	.driver = {
  		.name	= "hi6421-regulator",
87ca186f7   Guodong Xu   regulator: add dr...
573
574
575
576
577
578
579
580
  	},
  	.probe	= hi6421_regulator_probe,
  };
  module_platform_driver(hi6421_regulator_driver);
  
  MODULE_AUTHOR("Guodong Xu <guodong.xu@linaro.org>");
  MODULE_DESCRIPTION("Hi6421 regulator driver");
  MODULE_LICENSE("GPL v2");