Blame view

drivers/regulator/ab8500-ext.c 25.8 KB
0376148f3   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-only
d1a820011   Lee Jones   regulator: ab8500...
2
3
4
  /*
   * Copyright (C) ST-Ericsson SA 2010
   *
d1a820011   Lee Jones   regulator: ab8500...
5
6
7
8
9
10
11
12
13
14
15
16
17
   * Authors: Bengt Jonsson <bengt.g.jonsson@stericsson.com>
   *
   * This file is based on drivers/regulator/ab8500.c
   *
   * AB8500 external regulators
   *
   * ab8500-ext supports the following regulators:
   * - VextSupply3
   */
  #include <linux/init.h>
  #include <linux/kernel.h>
  #include <linux/err.h>
  #include <linux/module.h>
30aa4b26c   Lee Jones   regulator: ab8500...
18
  #include <linux/of.h>
d1a820011   Lee Jones   regulator: ab8500...
19
20
21
  #include <linux/platform_device.h>
  #include <linux/regulator/driver.h>
  #include <linux/regulator/machine.h>
30aa4b26c   Lee Jones   regulator: ab8500...
22
  #include <linux/regulator/of_regulator.h>
d1a820011   Lee Jones   regulator: ab8500...
23
24
25
  #include <linux/mfd/abx500.h>
  #include <linux/mfd/abx500/ab8500.h>
  #include <linux/regulator/ab8500.h>
79886be09   Arnd Bergmann   ARM: ux500: move ...
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
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
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
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
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
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
  static struct regulator_consumer_supply ab8500_vaux1_consumers[] = {
  	/* Main display, u8500 R3 uib */
  	REGULATOR_SUPPLY("vddi", "mcde_disp_sony_acx424akp.0"),
  	/* Main display, u8500 uib and ST uib */
  	REGULATOR_SUPPLY("vdd1", "samsung_s6d16d0.0"),
  	/* Secondary display, ST uib */
  	REGULATOR_SUPPLY("vdd1", "samsung_s6d16d0.1"),
  	/* SFH7741 proximity sensor */
  	REGULATOR_SUPPLY("vcc", "gpio-keys.0"),
  	/* BH1780GLS ambient light sensor */
  	REGULATOR_SUPPLY("vcc", "2-0029"),
  	/* lsm303dlh accelerometer */
  	REGULATOR_SUPPLY("vdd", "2-0018"),
  	/* lsm303dlhc accelerometer */
  	REGULATOR_SUPPLY("vdd", "2-0019"),
  	/* lsm303dlh magnetometer */
  	REGULATOR_SUPPLY("vdd", "2-001e"),
  	/* Rohm BU21013 Touchscreen devices */
  	REGULATOR_SUPPLY("avdd", "3-005c"),
  	REGULATOR_SUPPLY("avdd", "3-005d"),
  	/* Synaptics RMI4 Touchscreen device */
  	REGULATOR_SUPPLY("vdd", "3-004b"),
  	/* L3G4200D Gyroscope device */
  	REGULATOR_SUPPLY("vdd", "2-0068"),
  	/* Ambient light sensor device */
  	REGULATOR_SUPPLY("vdd", "3-0029"),
  	/* Pressure sensor device */
  	REGULATOR_SUPPLY("vdd", "2-005c"),
  	/* Cypress TrueTouch Touchscreen device */
  	REGULATOR_SUPPLY("vcpin", "spi8.0"),
  	/* Camera device */
  	REGULATOR_SUPPLY("vaux12v5", "mmio_camera"),
  };
  
  static struct regulator_consumer_supply ab8500_vaux2_consumers[] = {
  	/* On-board eMMC power */
  	REGULATOR_SUPPLY("vmmc", "sdi4"),
  	/* AB8500 audio codec */
  	REGULATOR_SUPPLY("vcc-N2158", "ab8500-codec.0"),
  	/* AB8500 accessory detect 1 */
  	REGULATOR_SUPPLY("vcc-N2158", "ab8500-acc-det.0"),
  	/* AB8500 Tv-out device */
  	REGULATOR_SUPPLY("vcc-N2158", "mcde_tv_ab8500.4"),
  	/* AV8100 HDMI device */
  	REGULATOR_SUPPLY("vcc-N2158", "av8100_hdmi.3"),
  };
  
  static struct regulator_consumer_supply ab8500_vaux3_consumers[] = {
  	REGULATOR_SUPPLY("v-SD-STM", "stm"),
  	/* External MMC slot power */
  	REGULATOR_SUPPLY("vmmc", "sdi0"),
  };
  
  static struct regulator_consumer_supply ab8500_vtvout_consumers[] = {
  	/* TV-out DENC supply */
  	REGULATOR_SUPPLY("vtvout", "ab8500-denc.0"),
  	/* Internal general-purpose ADC */
  	REGULATOR_SUPPLY("vddadc", "ab8500-gpadc.0"),
  	/* ADC for charger */
  	REGULATOR_SUPPLY("vddadc", "ab8500-charger.0"),
  	/* AB8500 Tv-out device */
  	REGULATOR_SUPPLY("vtvout", "mcde_tv_ab8500.4"),
  };
  
  static struct regulator_consumer_supply ab8500_vaud_consumers[] = {
  	/* AB8500 audio-codec main supply */
  	REGULATOR_SUPPLY("vaud", "ab8500-codec.0"),
  };
  
  static struct regulator_consumer_supply ab8500_vamic1_consumers[] = {
  	/* AB8500 audio-codec Mic1 supply */
  	REGULATOR_SUPPLY("vamic1", "ab8500-codec.0"),
  };
  
  static struct regulator_consumer_supply ab8500_vamic2_consumers[] = {
  	/* AB8500 audio-codec Mic2 supply */
  	REGULATOR_SUPPLY("vamic2", "ab8500-codec.0"),
  };
  
  static struct regulator_consumer_supply ab8500_vdmic_consumers[] = {
  	/* AB8500 audio-codec DMic supply */
  	REGULATOR_SUPPLY("vdmic", "ab8500-codec.0"),
  };
  
  static struct regulator_consumer_supply ab8500_vintcore_consumers[] = {
  	/* SoC core supply, no device */
  	REGULATOR_SUPPLY("v-intcore", NULL),
  	/* USB Transceiver */
  	REGULATOR_SUPPLY("vddulpivio18", "ab8500-usb.0"),
  	/* Handled by abx500 clk driver */
  	REGULATOR_SUPPLY("v-intcore", "abx500-clk.0"),
  };
  
  static struct regulator_consumer_supply ab8500_vana_consumers[] = {
  	/* DB8500 DSI */
  	REGULATOR_SUPPLY("vdddsi1v2", "mcde"),
  	REGULATOR_SUPPLY("vdddsi1v2", "b2r2_core"),
  	REGULATOR_SUPPLY("vdddsi1v2", "b2r2_1_core"),
  	REGULATOR_SUPPLY("vdddsi1v2", "dsilink.0"),
  	REGULATOR_SUPPLY("vdddsi1v2", "dsilink.1"),
  	REGULATOR_SUPPLY("vdddsi1v2", "dsilink.2"),
  	/* DB8500 CSI */
  	REGULATOR_SUPPLY("vddcsi1v2", "mmio_camera"),
  };
  
  /* ab8500 regulator register initialization */
  static struct ab8500_regulator_reg_init ab8500_reg_init[] = {
  	/*
  	 * VanaRequestCtrl          = HP/LP depending on VxRequest
  	 * VextSupply1RequestCtrl   = HP/LP depending on VxRequest
  	 */
  	INIT_REGULATOR_REGISTER(AB8500_REGUREQUESTCTRL2,       0xf0, 0x00),
  	/*
  	 * VextSupply2RequestCtrl   = HP/LP depending on VxRequest
  	 * VextSupply3RequestCtrl   = HP/LP depending on VxRequest
  	 * Vaux1RequestCtrl         = HP/LP depending on VxRequest
  	 * Vaux2RequestCtrl         = HP/LP depending on VxRequest
  	 */
  	INIT_REGULATOR_REGISTER(AB8500_REGUREQUESTCTRL3,       0xff, 0x00),
  	/*
  	 * Vaux3RequestCtrl         = HP/LP depending on VxRequest
  	 * SwHPReq                  = Control through SWValid disabled
  	 */
  	INIT_REGULATOR_REGISTER(AB8500_REGUREQUESTCTRL4,       0x07, 0x00),
  	/*
  	 * VanaSysClkReq1HPValid    = disabled
  	 * Vaux1SysClkReq1HPValid   = disabled
  	 * Vaux2SysClkReq1HPValid   = disabled
  	 * Vaux3SysClkReq1HPValid   = disabled
  	 */
  	INIT_REGULATOR_REGISTER(AB8500_REGUSYSCLKREQ1HPVALID1, 0xe8, 0x00),
  	/*
  	 * VextSupply1SysClkReq1HPValid = disabled
  	 * VextSupply2SysClkReq1HPValid = disabled
  	 * VextSupply3SysClkReq1HPValid = SysClkReq1 controlled
  	 */
  	INIT_REGULATOR_REGISTER(AB8500_REGUSYSCLKREQ1HPVALID2, 0x70, 0x40),
  	/*
  	 * VanaHwHPReq1Valid        = disabled
  	 * Vaux1HwHPreq1Valid       = disabled
  	 * Vaux2HwHPReq1Valid       = disabled
  	 * Vaux3HwHPReqValid        = disabled
  	 */
  	INIT_REGULATOR_REGISTER(AB8500_REGUHWHPREQ1VALID1,     0xe8, 0x00),
  	/*
  	 * VextSupply1HwHPReq1Valid = disabled
  	 * VextSupply2HwHPReq1Valid = disabled
  	 * VextSupply3HwHPReq1Valid = disabled
  	 */
  	INIT_REGULATOR_REGISTER(AB8500_REGUHWHPREQ1VALID2,     0x07, 0x00),
  	/*
  	 * VanaHwHPReq2Valid        = disabled
  	 * Vaux1HwHPReq2Valid       = disabled
  	 * Vaux2HwHPReq2Valid       = disabled
  	 * Vaux3HwHPReq2Valid       = disabled
  	 */
  	INIT_REGULATOR_REGISTER(AB8500_REGUHWHPREQ2VALID1,     0xe8, 0x00),
  	/*
  	 * VextSupply1HwHPReq2Valid = disabled
  	 * VextSupply2HwHPReq2Valid = disabled
  	 * VextSupply3HwHPReq2Valid = HWReq2 controlled
  	 */
  	INIT_REGULATOR_REGISTER(AB8500_REGUHWHPREQ2VALID2,     0x07, 0x04),
  	/*
  	 * VanaSwHPReqValid         = disabled
  	 * Vaux1SwHPReqValid        = disabled
  	 */
  	INIT_REGULATOR_REGISTER(AB8500_REGUSWHPREQVALID1,      0xa0, 0x00),
  	/*
  	 * Vaux2SwHPReqValid        = disabled
  	 * Vaux3SwHPReqValid        = disabled
  	 * VextSupply1SwHPReqValid  = disabled
  	 * VextSupply2SwHPReqValid  = disabled
  	 * VextSupply3SwHPReqValid  = disabled
  	 */
  	INIT_REGULATOR_REGISTER(AB8500_REGUSWHPREQVALID2,      0x1f, 0x00),
  	/*
  	 * SysClkReq2Valid1         = SysClkReq2 controlled
  	 * SysClkReq3Valid1         = disabled
  	 * SysClkReq4Valid1         = SysClkReq4 controlled
  	 * SysClkReq5Valid1         = disabled
  	 * SysClkReq6Valid1         = SysClkReq6 controlled
  	 * SysClkReq7Valid1         = disabled
  	 * SysClkReq8Valid1         = disabled
  	 */
  	INIT_REGULATOR_REGISTER(AB8500_REGUSYSCLKREQVALID1,    0xfe, 0x2a),
  	/*
  	 * SysClkReq2Valid2         = disabled
  	 * SysClkReq3Valid2         = disabled
  	 * SysClkReq4Valid2         = disabled
  	 * SysClkReq5Valid2         = disabled
  	 * SysClkReq6Valid2         = SysClkReq6 controlled
  	 * SysClkReq7Valid2         = disabled
  	 * SysClkReq8Valid2         = disabled
  	 */
  	INIT_REGULATOR_REGISTER(AB8500_REGUSYSCLKREQVALID2,    0xfe, 0x20),
  	/*
  	 * VTVoutEna                = disabled
  	 * Vintcore12Ena            = disabled
  	 * Vintcore12Sel            = 1.25 V
  	 * Vintcore12LP             = inactive (HP)
  	 * VTVoutLP                 = inactive (HP)
  	 */
  	INIT_REGULATOR_REGISTER(AB8500_REGUMISC1,              0xfe, 0x10),
  	/*
  	 * VaudioEna                = disabled
  	 * VdmicEna                 = disabled
  	 * Vamic1Ena                = disabled
  	 * Vamic2Ena                = disabled
  	 */
  	INIT_REGULATOR_REGISTER(AB8500_VAUDIOSUPPLY,           0x1e, 0x00),
  	/*
  	 * Vamic1_dzout             = high-Z when Vamic1 is disabled
  	 * Vamic2_dzout             = high-Z when Vamic2 is disabled
  	 */
  	INIT_REGULATOR_REGISTER(AB8500_REGUCTRL1VAMIC,         0x03, 0x00),
  	/*
  	 * VPll                     = Hw controlled (NOTE! PRCMU bits)
  	 * VanaRegu                 = force off
  	 */
  	INIT_REGULATOR_REGISTER(AB8500_VPLLVANAREGU,           0x0f, 0x02),
  	/*
  	 * VrefDDREna               = disabled
  	 * VrefDDRSleepMode         = inactive (no pulldown)
  	 */
  	INIT_REGULATOR_REGISTER(AB8500_VREFDDR,                0x03, 0x00),
  	/*
  	 * VextSupply1Regu          = force LP
  	 * VextSupply2Regu          = force OFF
  	 * VextSupply3Regu          = force HP (-> STBB2=LP and TPS=LP)
  	 * ExtSupply2Bypass         = ExtSupply12LPn ball is 0 when Ena is 0
  	 * ExtSupply3Bypass         = ExtSupply3LPn ball is 0 when Ena is 0
  	 */
  	INIT_REGULATOR_REGISTER(AB8500_EXTSUPPLYREGU,          0xff, 0x13),
  	/*
  	 * Vaux1Regu                = force HP
  	 * Vaux2Regu                = force off
  	 */
  	INIT_REGULATOR_REGISTER(AB8500_VAUX12REGU,             0x0f, 0x01),
  	/*
  	 * Vaux3Regu                = force off
  	 */
  	INIT_REGULATOR_REGISTER(AB8500_VRF1VAUX3REGU,          0x03, 0x00),
  	/*
  	 * Vaux1Sel                 = 2.8 V
  	 */
  	INIT_REGULATOR_REGISTER(AB8500_VAUX1SEL,               0x0f, 0x0C),
  	/*
  	 * Vaux2Sel                 = 2.9 V
  	 */
  	INIT_REGULATOR_REGISTER(AB8500_VAUX2SEL,               0x0f, 0x0d),
  	/*
  	 * Vaux3Sel                 = 2.91 V
  	 */
  	INIT_REGULATOR_REGISTER(AB8500_VRF1VAUX3SEL,           0x07, 0x07),
  	/*
  	 * VextSupply12LP           = disabled (no LP)
  	 */
  	INIT_REGULATOR_REGISTER(AB8500_REGUCTRL2SPARE,         0x01, 0x00),
  	/*
  	 * Vaux1Disch               = short discharge time
  	 * Vaux2Disch               = short discharge time
  	 * Vaux3Disch               = short discharge time
  	 * Vintcore12Disch          = short discharge time
  	 * VTVoutDisch              = short discharge time
  	 * VaudioDisch              = short discharge time
  	 */
  	INIT_REGULATOR_REGISTER(AB8500_REGUCTRLDISCH,          0xfc, 0x00),
  	/*
  	 * VanaDisch                = short discharge time
  	 * VdmicPullDownEna         = pulldown disabled when Vdmic is disabled
  	 * VdmicDisch               = short discharge time
  	 */
  	INIT_REGULATOR_REGISTER(AB8500_REGUCTRLDISCH2,         0x16, 0x00),
  };
  
  /* AB8500 regulators */
  static struct regulator_init_data ab8500_regulators[AB8500_NUM_REGULATORS] = {
  	/* supplies to the display/camera */
  	[AB8500_LDO_AUX1] = {
  		.supply_regulator = "ab8500-ext-supply3",
  		.constraints = {
  			.name = "V-DISPLAY",
  			.min_uV = 2800000,
  			.max_uV = 3300000,
  			.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE |
  					  REGULATOR_CHANGE_STATUS,
  			.boot_on = 1, /* display is on at boot */
  		},
  		.num_consumer_supplies = ARRAY_SIZE(ab8500_vaux1_consumers),
  		.consumer_supplies = ab8500_vaux1_consumers,
  	},
  	/* supplies to the on-board eMMC */
  	[AB8500_LDO_AUX2] = {
  		.supply_regulator = "ab8500-ext-supply3",
  		.constraints = {
  			.name = "V-eMMC1",
  			.min_uV = 1100000,
  			.max_uV = 3300000,
  			.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE |
  					  REGULATOR_CHANGE_STATUS |
  					  REGULATOR_CHANGE_MODE,
  			.valid_modes_mask = REGULATOR_MODE_NORMAL |
  					    REGULATOR_MODE_IDLE,
  		},
  		.num_consumer_supplies = ARRAY_SIZE(ab8500_vaux2_consumers),
  		.consumer_supplies = ab8500_vaux2_consumers,
  	},
  	/* supply for VAUX3, supplies to SDcard slots */
  	[AB8500_LDO_AUX3] = {
  		.supply_regulator = "ab8500-ext-supply3",
  		.constraints = {
  			.name = "V-MMC-SD",
  			.min_uV = 1100000,
  			.max_uV = 3300000,
  			.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE |
  					  REGULATOR_CHANGE_STATUS |
  					  REGULATOR_CHANGE_MODE,
  			.valid_modes_mask = REGULATOR_MODE_NORMAL |
  					    REGULATOR_MODE_IDLE,
  		},
  		.num_consumer_supplies = ARRAY_SIZE(ab8500_vaux3_consumers),
  		.consumer_supplies = ab8500_vaux3_consumers,
  	},
  	/* supply for tvout, gpadc, TVOUT LDO */
  	[AB8500_LDO_TVOUT] = {
  		.constraints = {
  			.name = "V-TVOUT",
  			.valid_ops_mask = REGULATOR_CHANGE_STATUS,
  		},
  		.num_consumer_supplies = ARRAY_SIZE(ab8500_vtvout_consumers),
  		.consumer_supplies = ab8500_vtvout_consumers,
  	},
  	/* supply for ab8500-vaudio, VAUDIO LDO */
  	[AB8500_LDO_AUDIO] = {
  		.constraints = {
  			.name = "V-AUD",
  			.valid_ops_mask = REGULATOR_CHANGE_STATUS,
  		},
  		.num_consumer_supplies = ARRAY_SIZE(ab8500_vaud_consumers),
  		.consumer_supplies = ab8500_vaud_consumers,
  	},
  	/* supply for v-anamic1 VAMic1-LDO */
  	[AB8500_LDO_ANAMIC1] = {
  		.constraints = {
  			.name = "V-AMIC1",
  			.valid_ops_mask = REGULATOR_CHANGE_STATUS,
  		},
  		.num_consumer_supplies = ARRAY_SIZE(ab8500_vamic1_consumers),
  		.consumer_supplies = ab8500_vamic1_consumers,
  	},
  	/* supply for v-amic2, VAMIC2 LDO, reuse constants for AMIC1 */
  	[AB8500_LDO_ANAMIC2] = {
  		.constraints = {
  			.name = "V-AMIC2",
  			.valid_ops_mask = REGULATOR_CHANGE_STATUS,
  		},
  		.num_consumer_supplies = ARRAY_SIZE(ab8500_vamic2_consumers),
  		.consumer_supplies = ab8500_vamic2_consumers,
  	},
  	/* supply for v-dmic, VDMIC LDO */
  	[AB8500_LDO_DMIC] = {
  		.constraints = {
  			.name = "V-DMIC",
  			.valid_ops_mask = REGULATOR_CHANGE_STATUS,
  		},
  		.num_consumer_supplies = ARRAY_SIZE(ab8500_vdmic_consumers),
  		.consumer_supplies = ab8500_vdmic_consumers,
  	},
  	/* supply for v-intcore12, VINTCORE12 LDO */
  	[AB8500_LDO_INTCORE] = {
  		.constraints = {
  			.name = "V-INTCORE",
  			.min_uV = 1250000,
  			.max_uV = 1350000,
  			.input_uV = 1800000,
  			.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE |
  					  REGULATOR_CHANGE_STATUS |
  					  REGULATOR_CHANGE_MODE |
  					  REGULATOR_CHANGE_DRMS,
  			.valid_modes_mask = REGULATOR_MODE_NORMAL |
  					    REGULATOR_MODE_IDLE,
  		},
  		.num_consumer_supplies = ARRAY_SIZE(ab8500_vintcore_consumers),
  		.consumer_supplies = ab8500_vintcore_consumers,
  	},
  	/* supply for U8500 CSI-DSI, VANA LDO */
  	[AB8500_LDO_ANA] = {
  		.constraints = {
  			.name = "V-CSI-DSI",
  			.valid_ops_mask = REGULATOR_CHANGE_STATUS,
  		},
  		.num_consumer_supplies = ARRAY_SIZE(ab8500_vana_consumers),
  		.consumer_supplies = ab8500_vana_consumers,
  	},
  };
  
  /* supply for VextSupply3 */
  static struct regulator_consumer_supply ab8500_ext_supply3_consumers[] = {
  	/* SIM supply for 3 V SIM cards */
  	REGULATOR_SUPPLY("vinvsim", "sim-detect.0"),
  };
  
  /*
   * AB8500 external regulators
   */
  static struct regulator_init_data ab8500_ext_regulators[] = {
  	/* fixed Vbat supplies VSMPS1_EXT_1V8 */
  	[AB8500_EXT_SUPPLY1] = {
  		.constraints = {
  			.name = "ab8500-ext-supply1",
  			.min_uV = 1800000,
  			.max_uV = 1800000,
  			.initial_mode = REGULATOR_MODE_IDLE,
  			.boot_on = 1,
  			.always_on = 1,
  		},
  	},
  	/* fixed Vbat supplies VSMPS2_EXT_1V36 and VSMPS5_EXT_1V15 */
  	[AB8500_EXT_SUPPLY2] = {
  		.constraints = {
  			.name = "ab8500-ext-supply2",
  			.min_uV = 1360000,
  			.max_uV = 1360000,
  		},
  	},
  	/* fixed Vbat supplies VSMPS3_EXT_3V4 and VSMPS4_EXT_3V4 */
  	[AB8500_EXT_SUPPLY3] = {
  		.constraints = {
  			.name = "ab8500-ext-supply3",
  			.min_uV = 3400000,
  			.max_uV = 3400000,
  			.valid_ops_mask = REGULATOR_CHANGE_STATUS,
  			.boot_on = 1,
  		},
  		.num_consumer_supplies =
  			ARRAY_SIZE(ab8500_ext_supply3_consumers),
  		.consumer_supplies = ab8500_ext_supply3_consumers,
  	},
  };
  
  static struct ab8500_regulator_platform_data ab8500_regulator_plat_data = {
  	.reg_init               = ab8500_reg_init,
  	.num_reg_init           = ARRAY_SIZE(ab8500_reg_init),
  	.regulator              = ab8500_regulators,
  	.num_regulator          = ARRAY_SIZE(ab8500_regulators),
  	.ext_regulator          = ab8500_ext_regulators,
  	.num_ext_regulator      = ARRAY_SIZE(ab8500_ext_regulators),
  };
d1a820011   Lee Jones   regulator: ab8500...
475
476
477
478
  /**
   * struct ab8500_ext_regulator_info - ab8500 regulator information
   * @dev: device pointer
   * @desc: regulator description
18bc2b393   Bengt Jonsson   regulator: ab8500...
479
   * @cfg: regulator configuration (extension of regulator FW configuration)
d1a820011   Lee Jones   regulator: ab8500...
480
481
482
483
   * @update_bank: bank to control on/off
   * @update_reg: register to control on/off
   * @update_mask: mask to enable/disable and set mode of regulator
   * @update_val: bits holding the regulator current mode
18bc2b393   Bengt Jonsson   regulator: ab8500...
484
   * @update_val_hp: bits to set EN pin active (LPn pin deactive)
d1a820011   Lee Jones   regulator: ab8500...
485
   *                 normally this means high power mode
18bc2b393   Bengt Jonsson   regulator: ab8500...
486
487
488
489
   * @update_val_lp: bits to set EN pin active and LPn pin active
   *                 normally this means low power mode
   * @update_val_hw: bits to set regulator pins in HW control
   *                 SysClkReq pins and logic will choose mode
d1a820011   Lee Jones   regulator: ab8500...
490
491
492
493
   */
  struct ab8500_ext_regulator_info {
  	struct device *dev;
  	struct regulator_desc desc;
18bc2b393   Bengt Jonsson   regulator: ab8500...
494
  	struct ab8500_ext_regulator_cfg *cfg;
d1a820011   Lee Jones   regulator: ab8500...
495
496
497
498
  	u8 update_bank;
  	u8 update_reg;
  	u8 update_mask;
  	u8 update_val;
18bc2b393   Bengt Jonsson   regulator: ab8500...
499
500
501
  	u8 update_val_hp;
  	u8 update_val_lp;
  	u8 update_val_hw;
d1a820011   Lee Jones   regulator: ab8500...
502
  };
7384744d2   Axel Lin   regulator: ab8500...
503
  static int ab8500_ext_regulator_enable(struct regulator_dev *rdev)
d1a820011   Lee Jones   regulator: ab8500...
504
505
  {
  	int ret;
7384744d2   Axel Lin   regulator: ab8500...
506
507
  	struct ab8500_ext_regulator_info *info = rdev_get_drvdata(rdev);
  	u8 regval;
d1a820011   Lee Jones   regulator: ab8500...
508

7384744d2   Axel Lin   regulator: ab8500...
509
510
511
512
513
  	if (info == NULL) {
  		dev_err(rdev_get_dev(rdev), "regulator info null pointer
  ");
  		return -EINVAL;
  	}
18bc2b393   Bengt Jonsson   regulator: ab8500...
514
515
516
517
518
519
  
  	/*
  	 * To satisfy both HW high power request and SW request, the regulator
  	 * must be on in high power.
  	 */
  	if (info->cfg && info->cfg->hwreq)
7384744d2   Axel Lin   regulator: ab8500...
520
521
522
  		regval = info->update_val_hp;
  	else
  		regval = info->update_val;
d1a820011   Lee Jones   regulator: ab8500...
523
524
525
  
  	ret = abx500_mask_and_set_register_interruptible(info->dev,
  		info->update_bank, info->update_reg,
7384744d2   Axel Lin   regulator: ab8500...
526
  		info->update_mask, regval);
37daa8aed   Axel Lin   regulator: ab8500...
527
  	if (ret < 0) {
80a9c22a9   Axel Lin   regulator: ab8500...
528
  		dev_err(rdev_get_dev(rdev),
d1a820011   Lee Jones   regulator: ab8500...
529
530
  			"couldn't set enable bits for regulator
  ");
37daa8aed   Axel Lin   regulator: ab8500...
531
532
  		return ret;
  	}
d1a820011   Lee Jones   regulator: ab8500...
533

7384744d2   Axel Lin   regulator: ab8500...
534
535
536
537
538
539
540
  	dev_dbg(rdev_get_dev(rdev),
  		"%s-enable (bank, reg, mask, value): 0x%02x, 0x%02x, 0x%02x, 0x%02x
  ",
  		info->desc.name, info->update_bank, info->update_reg,
  		info->update_mask, regval);
  
  	return 0;
d1a820011   Lee Jones   regulator: ab8500...
541
  }
7384744d2   Axel Lin   regulator: ab8500...
542
  static int ab8500_ext_regulator_disable(struct regulator_dev *rdev)
d1a820011   Lee Jones   regulator: ab8500...
543
544
545
  {
  	int ret;
  	struct ab8500_ext_regulator_info *info = rdev_get_drvdata(rdev);
18bc2b393   Bengt Jonsson   regulator: ab8500...
546
  	u8 regval;
d1a820011   Lee Jones   regulator: ab8500...
547
548
549
550
551
552
  
  	if (info == NULL) {
  		dev_err(rdev_get_dev(rdev), "regulator info null pointer
  ");
  		return -EINVAL;
  	}
18bc2b393   Bengt Jonsson   regulator: ab8500...
553
554
555
556
  	/*
  	 * Set the regulator in HW request mode if configured
  	 */
  	if (info->cfg && info->cfg->hwreq)
7384744d2   Axel Lin   regulator: ab8500...
557
558
559
  		regval = info->update_val_hw;
  	else
  		regval = 0;
18bc2b393   Bengt Jonsson   regulator: ab8500...
560

d1a820011   Lee Jones   regulator: ab8500...
561
562
  	ret = abx500_mask_and_set_register_interruptible(info->dev,
  		info->update_bank, info->update_reg,
7384744d2   Axel Lin   regulator: ab8500...
563
  		info->update_mask, regval);
37daa8aed   Axel Lin   regulator: ab8500...
564
  	if (ret < 0) {
80a9c22a9   Axel Lin   regulator: ab8500...
565
  		dev_err(rdev_get_dev(rdev),
d1a820011   Lee Jones   regulator: ab8500...
566
567
  			"couldn't set disable bits for regulator
  ");
37daa8aed   Axel Lin   regulator: ab8500...
568
569
  		return ret;
  	}
d1a820011   Lee Jones   regulator: ab8500...
570

d1a820011   Lee Jones   regulator: ab8500...
571
572
573
574
  	dev_dbg(rdev_get_dev(rdev), "%s-disable (bank, reg, mask, value):"
  		" 0x%02x, 0x%02x, 0x%02x, 0x%02x
  ",
  		info->desc.name, info->update_bank, info->update_reg,
18bc2b393   Bengt Jonsson   regulator: ab8500...
575
  		info->update_mask, regval);
d1a820011   Lee Jones   regulator: ab8500...
576

7384744d2   Axel Lin   regulator: ab8500...
577
  	return 0;
d1a820011   Lee Jones   regulator: ab8500...
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
  }
  
  static int ab8500_ext_regulator_is_enabled(struct regulator_dev *rdev)
  {
  	int ret;
  	struct ab8500_ext_regulator_info *info = rdev_get_drvdata(rdev);
  	u8 regval;
  
  	if (info == NULL) {
  		dev_err(rdev_get_dev(rdev), "regulator info null pointer
  ");
  		return -EINVAL;
  	}
  
  	ret = abx500_get_register_interruptible(info->dev,
  		info->update_bank, info->update_reg, &regval);
  	if (ret < 0) {
  		dev_err(rdev_get_dev(rdev),
  			"couldn't read 0x%x register
  ", info->update_reg);
  		return ret;
  	}
  
  	dev_dbg(rdev_get_dev(rdev), "%s-is_enabled (bank, reg, mask, value):"
  		" 0x%02x, 0x%02x, 0x%02x, 0x%02x
  ",
  		info->desc.name, info->update_bank, info->update_reg,
  		info->update_mask, regval);
18bc2b393   Bengt Jonsson   regulator: ab8500...
606
607
  	if (((regval & info->update_mask) == info->update_val_lp) ||
  	    ((regval & info->update_mask) == info->update_val_hp))
9ab51a0eb   Axel Lin   regulator: ab8500...
608
  		return 1;
d1a820011   Lee Jones   regulator: ab8500...
609
  	else
9ab51a0eb   Axel Lin   regulator: ab8500...
610
  		return 0;
d1a820011   Lee Jones   regulator: ab8500...
611
612
613
614
615
616
617
  }
  
  static int ab8500_ext_regulator_set_mode(struct regulator_dev *rdev,
  					 unsigned int mode)
  {
  	int ret = 0;
  	struct ab8500_ext_regulator_info *info = rdev_get_drvdata(rdev);
66511fa4a   Axel Lin   regulator: ab8500...
618
  	u8 regval;
d1a820011   Lee Jones   regulator: ab8500...
619
620
621
622
623
624
625
626
627
  
  	if (info == NULL) {
  		dev_err(rdev_get_dev(rdev), "regulator info null pointer
  ");
  		return -EINVAL;
  	}
  
  	switch (mode) {
  	case REGULATOR_MODE_NORMAL:
66511fa4a   Axel Lin   regulator: ab8500...
628
  		regval = info->update_val_hp;
d1a820011   Lee Jones   regulator: ab8500...
629
630
  		break;
  	case REGULATOR_MODE_IDLE:
66511fa4a   Axel Lin   regulator: ab8500...
631
  		regval = info->update_val_lp;
d1a820011   Lee Jones   regulator: ab8500...
632
633
634
635
636
  		break;
  
  	default:
  		return -EINVAL;
  	}
66511fa4a   Axel Lin   regulator: ab8500...
637
638
639
640
641
642
643
644
645
646
  	/* If regulator is enabled and info->cfg->hwreq is set, the regulator
  	   must be on in high power, so we don't need to write the register with
  	   the same value.
  	 */
  	if (ab8500_ext_regulator_is_enabled(rdev) &&
  	    !(info->cfg && info->cfg->hwreq)) {
  		ret = abx500_mask_and_set_register_interruptible(info->dev,
  					info->update_bank, info->update_reg,
  					info->update_mask, regval);
  		if (ret < 0) {
d1a820011   Lee Jones   regulator: ab8500...
647
648
649
  			dev_err(rdev_get_dev(rdev),
  				"Could not set regulator mode.
  ");
66511fa4a   Axel Lin   regulator: ab8500...
650
651
  			return ret;
  		}
d1a820011   Lee Jones   regulator: ab8500...
652
653
654
655
656
657
658
659
  
  		dev_dbg(rdev_get_dev(rdev),
  			"%s-set_mode (bank, reg, mask, value): "
  			"0x%x, 0x%x, 0x%x, 0x%x
  ",
  			info->desc.name, info->update_bank, info->update_reg,
  			info->update_mask, regval);
  	}
66511fa4a   Axel Lin   regulator: ab8500...
660
661
662
  	info->update_val = regval;
  
  	return 0;
d1a820011   Lee Jones   regulator: ab8500...
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
  }
  
  static unsigned int ab8500_ext_regulator_get_mode(struct regulator_dev *rdev)
  {
  	struct ab8500_ext_regulator_info *info = rdev_get_drvdata(rdev);
  	int ret;
  
  	if (info == NULL) {
  		dev_err(rdev_get_dev(rdev), "regulator info null pointer
  ");
  		return -EINVAL;
  	}
  
  	if (info->update_val == info->update_val_hp)
  		ret = REGULATOR_MODE_NORMAL;
  	else if (info->update_val == info->update_val_lp)
  		ret = REGULATOR_MODE_IDLE;
  	else
  		ret = -EINVAL;
  
  	return ret;
  }
33fb88024   Lee Jones   regulator: ab8500...
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
  static int ab8500_ext_set_voltage(struct regulator_dev *rdev, int min_uV,
  				  int max_uV, unsigned *selector)
  {
  	struct regulation_constraints *regu_constraints = rdev->constraints;
  
  	if (!regu_constraints) {
  		dev_err(rdev_get_dev(rdev), "No regulator constraints
  ");
  		return -EINVAL;
  	}
  
  	if (regu_constraints->min_uV == min_uV &&
  	    regu_constraints->max_uV == max_uV)
  		return 0;
  
  	dev_err(rdev_get_dev(rdev),
  		"Requested min %duV max %duV != constrained min %duV max %duV
  ",
  		min_uV, max_uV,
  		regu_constraints->min_uV, regu_constraints->max_uV);
  
  	return -EINVAL;
  }
d1a820011   Lee Jones   regulator: ab8500...
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
  static int ab8500_ext_list_voltage(struct regulator_dev *rdev,
  				   unsigned selector)
  {
  	struct regulation_constraints *regu_constraints = rdev->constraints;
  
  	if (regu_constraints == NULL) {
  		dev_err(rdev_get_dev(rdev), "regulator constraints null pointer
  ");
  		return -EINVAL;
  	}
  	/* return the uV for the fixed regulators */
  	if (regu_constraints->min_uV && regu_constraints->max_uV) {
  		if (regu_constraints->min_uV == regu_constraints->max_uV)
  			return regu_constraints->min_uV;
  	}
  	return -EINVAL;
  }
8e5be4f7e   Axel Lin   regulator: ab8500...
725
  static const struct regulator_ops ab8500_ext_regulator_ops = {
d1a820011   Lee Jones   regulator: ab8500...
726
727
728
729
730
  	.enable			= ab8500_ext_regulator_enable,
  	.disable		= ab8500_ext_regulator_disable,
  	.is_enabled		= ab8500_ext_regulator_is_enabled,
  	.set_mode		= ab8500_ext_regulator_set_mode,
  	.get_mode		= ab8500_ext_regulator_get_mode,
33fb88024   Lee Jones   regulator: ab8500...
731
  	.set_voltage		= ab8500_ext_set_voltage,
d1a820011   Lee Jones   regulator: ab8500...
732
733
  	.list_voltage		= ab8500_ext_list_voltage,
  };
d1a820011   Lee Jones   regulator: ab8500...
734
735
736
737
738
  static struct ab8500_ext_regulator_info
  		ab8500_ext_regulator_info[AB8500_NUM_EXT_REGULATORS] = {
  	[AB8500_EXT_SUPPLY1] = {
  		.desc = {
  			.name		= "VEXTSUPPLY1",
48cb9737e   Axel Lin   regulator: ab8500...
739
  			.of_match	= of_match_ptr("ab8500_ext1"),
d1a820011   Lee Jones   regulator: ab8500...
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
  			.ops		= &ab8500_ext_regulator_ops,
  			.type		= REGULATOR_VOLTAGE,
  			.id		= AB8500_EXT_SUPPLY1,
  			.owner		= THIS_MODULE,
  			.n_voltages	= 1,
  		},
  		.update_bank		= 0x04,
  		.update_reg		= 0x08,
  		.update_mask		= 0x03,
  		.update_val		= 0x01,
  		.update_val_hp		= 0x01,
  		.update_val_lp		= 0x03,
  		.update_val_hw		= 0x02,
  	},
  	[AB8500_EXT_SUPPLY2] = {
  		.desc = {
  			.name		= "VEXTSUPPLY2",
48cb9737e   Axel Lin   regulator: ab8500...
757
  			.of_match	= of_match_ptr("ab8500_ext2"),
d1a820011   Lee Jones   regulator: ab8500...
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
  			.ops		= &ab8500_ext_regulator_ops,
  			.type		= REGULATOR_VOLTAGE,
  			.id		= AB8500_EXT_SUPPLY2,
  			.owner		= THIS_MODULE,
  			.n_voltages	= 1,
  		},
  		.update_bank		= 0x04,
  		.update_reg		= 0x08,
  		.update_mask		= 0x0c,
  		.update_val		= 0x04,
  		.update_val_hp		= 0x04,
  		.update_val_lp		= 0x0c,
  		.update_val_hw		= 0x08,
  	},
  	[AB8500_EXT_SUPPLY3] = {
  		.desc = {
  			.name		= "VEXTSUPPLY3",
48cb9737e   Axel Lin   regulator: ab8500...
775
  			.of_match	= of_match_ptr("ab8500_ext3"),
d1a820011   Lee Jones   regulator: ab8500...
776
777
778
779
780
781
782
783
784
785
  			.ops		= &ab8500_ext_regulator_ops,
  			.type		= REGULATOR_VOLTAGE,
  			.id		= AB8500_EXT_SUPPLY3,
  			.owner		= THIS_MODULE,
  			.n_voltages	= 1,
  		},
  		.update_bank		= 0x04,
  		.update_reg		= 0x08,
  		.update_mask		= 0x30,
  		.update_val		= 0x10,
18bc2b393   Bengt Jonsson   regulator: ab8500...
786
787
788
  		.update_val_hp		= 0x10,
  		.update_val_lp		= 0x30,
  		.update_val_hw		= 0x20,
d1a820011   Lee Jones   regulator: ab8500...
789
790
  	},
  };
08d49f437   Sachin Kamat   regulator: ab8500...
791
  static int ab8500_ext_regulator_probe(struct platform_device *pdev)
d1a820011   Lee Jones   regulator: ab8500...
792
793
  {
  	struct ab8500 *ab8500 = dev_get_drvdata(pdev->dev.parent);
79886be09   Arnd Bergmann   ARM: ux500: move ...
794
  	struct ab8500_regulator_platform_data *pdata = &ab8500_regulator_plat_data;
d1a820011   Lee Jones   regulator: ab8500...
795
  	struct regulator_config config = { };
80a9c22a9   Axel Lin   regulator: ab8500...
796
  	struct regulator_dev *rdev;
48cb9737e   Axel Lin   regulator: ab8500...
797
  	int i;
30aa4b26c   Lee Jones   regulator: ab8500...
798

d1a820011   Lee Jones   regulator: ab8500...
799
800
801
802
803
  	if (!ab8500) {
  		dev_err(&pdev->dev, "null mfd parent
  ");
  		return -EINVAL;
  	}
30aa4b26c   Lee Jones   regulator: ab8500...
804

d1a820011   Lee Jones   regulator: ab8500...
805
806
807
808
809
810
811
812
  	/* make sure the platform data has the correct size */
  	if (pdata->num_ext_regulator != ARRAY_SIZE(ab8500_ext_regulator_info)) {
  		dev_err(&pdev->dev, "Configuration error: size mismatch.
  ");
  		return -EINVAL;
  	}
  
  	/* check for AB8500 2.x */
a6324709a   Bengt Jonsson   regulator: ab8500...
813
  	if (is_ab8500_2p0_or_earlier(ab8500)) {
d1a820011   Lee Jones   regulator: ab8500...
814
815
816
817
818
  		struct ab8500_ext_regulator_info *info;
  
  		/* VextSupply3LPn is inverted on AB8500 2.x */
  		info = &ab8500_ext_regulator_info[AB8500_EXT_SUPPLY3];
  		info->update_val = 0x30;
18bc2b393   Bengt Jonsson   regulator: ab8500...
819
820
  		info->update_val_hp = 0x30;
  		info->update_val_lp = 0x10;
d1a820011   Lee Jones   regulator: ab8500...
821
822
823
824
825
826
827
828
829
  	}
  
  	/* register all regulators */
  	for (i = 0; i < ARRAY_SIZE(ab8500_ext_regulator_info); i++) {
  		struct ab8500_ext_regulator_info *info = NULL;
  
  		/* assign per-regulator data */
  		info = &ab8500_ext_regulator_info[i];
  		info->dev = &pdev->dev;
18bc2b393   Bengt Jonsson   regulator: ab8500...
830
831
  		info->cfg = (struct ab8500_ext_regulator_cfg *)
  			pdata->ext_regulator[i].driver_data;
d1a820011   Lee Jones   regulator: ab8500...
832
833
  
  		config.dev = &pdev->dev;
d1a820011   Lee Jones   regulator: ab8500...
834
  		config.driver_data = info;
48cb9737e   Axel Lin   regulator: ab8500...
835
  		config.init_data = &pdata->ext_regulator[i];
d1a820011   Lee Jones   regulator: ab8500...
836
837
  
  		/* register regulator with framework */
80a9c22a9   Axel Lin   regulator: ab8500...
838
839
840
  		rdev = devm_regulator_register(&pdev->dev, &info->desc,
  					       &config);
  		if (IS_ERR(rdev)) {
d1a820011   Lee Jones   regulator: ab8500...
841
842
843
  			dev_err(&pdev->dev, "failed to register regulator %s
  ",
  					info->desc.name);
80a9c22a9   Axel Lin   regulator: ab8500...
844
  			return PTR_ERR(rdev);
d1a820011   Lee Jones   regulator: ab8500...
845
  		}
80a9c22a9   Axel Lin   regulator: ab8500...
846
847
  		dev_dbg(&pdev->dev, "%s-probed
  ", info->desc.name);
d1a820011   Lee Jones   regulator: ab8500...
848
849
850
851
  	}
  
  	return 0;
  }
5a49b4a52   Lee Jones   regulator: ab8500...
852
853
  static struct platform_driver ab8500_ext_regulator_driver = {
  	.probe = ab8500_ext_regulator_probe,
5a49b4a52   Lee Jones   regulator: ab8500...
854
855
  	.driver         = {
  		.name   = "ab8500-ext-regulator",
5a49b4a52   Lee Jones   regulator: ab8500...
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
  	},
  };
  
  static int __init ab8500_ext_regulator_init(void)
  {
  	int ret;
  
  	ret = platform_driver_register(&ab8500_ext_regulator_driver);
  	if (ret)
  		pr_err("Failed to register ab8500 ext regulator: %d
  ", ret);
  
  	return ret;
  }
  subsys_initcall(ab8500_ext_regulator_init);
  
  static void __exit ab8500_ext_regulator_exit(void)
  {
  	platform_driver_unregister(&ab8500_ext_regulator_driver);
d1a820011   Lee Jones   regulator: ab8500...
875
  }
5a49b4a52   Lee Jones   regulator: ab8500...
876
  module_exit(ab8500_ext_regulator_exit);
d1a820011   Lee Jones   regulator: ab8500...
877
878
879
880
881
  
  MODULE_LICENSE("GPL v2");
  MODULE_AUTHOR("Bengt Jonsson <bengt.g.jonsson@stericsson.com>");
  MODULE_DESCRIPTION("AB8500 external regulator driver");
  MODULE_ALIAS("platform:ab8500-ext-regulator");