Blame view

drivers/regulator/wm831x-dcdc.c 21.5 KB
3cad5fc89   Axel Lin   regulator: wm831x...
1
2
3
4
5
6
7
  // SPDX-License-Identifier: GPL-2.0+
  //
  // wm831x-dcdc.c  --  DC-DC buck converter driver for the WM831x series
  //
  // Copyright 2009 Wolfson Microelectronics PLC.
  //
  // Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
e4ee831f9   Mark Brown   regulator: Add WM...
8
9
10
11
12
13
14
15
16
  
  #include <linux/module.h>
  #include <linux/moduleparam.h>
  #include <linux/init.h>
  #include <linux/bitops.h>
  #include <linux/err.h>
  #include <linux/i2c.h>
  #include <linux/platform_device.h>
  #include <linux/regulator/driver.h>
e24a04c44   Mark Brown   regulator: Implem...
17
  #include <linux/regulator/machine.h>
9a5ed0bac   Linus Walleij   regulator: wm831x...
18
  #include <linux/gpio/consumer.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
19
  #include <linux/slab.h>
e4ee831f9   Mark Brown   regulator: Add WM...
20
21
22
23
24
25
26
27
28
29
30
31
  
  #include <linux/mfd/wm831x/core.h>
  #include <linux/mfd/wm831x/regulator.h>
  #include <linux/mfd/wm831x/pdata.h>
  
  #define WM831X_BUCKV_MAX_SELECTOR 0x68
  #define WM831X_BUCKP_MAX_SELECTOR 0x66
  
  #define WM831X_DCDC_MODE_FAST    0
  #define WM831X_DCDC_MODE_NORMAL  1
  #define WM831X_DCDC_MODE_IDLE    2
  #define WM831X_DCDC_MODE_STANDBY 3
82caa9780   Mark Brown   regulator: wm831x...
32
  #define WM831X_DCDC_MAX_NAME 9
e4ee831f9   Mark Brown   regulator: Add WM...
33
34
35
36
37
38
  
  /* Register offsets in control block */
  #define WM831X_DCDC_CONTROL_1     0
  #define WM831X_DCDC_CONTROL_2     1
  #define WM831X_DCDC_ON_CONFIG     2
  #define WM831X_DCDC_SLEEP_CONTROL 3
e24a04c44   Mark Brown   regulator: Implem...
39
  #define WM831X_DCDC_DVS_CONTROL   4
e4ee831f9   Mark Brown   regulator: Add WM...
40
41
42
43
44
45
46
  
  /*
   * Shared
   */
  
  struct wm831x_dcdc {
  	char name[WM831X_DCDC_MAX_NAME];
82caa9780   Mark Brown   regulator: wm831x...
47
  	char supply_name[WM831X_DCDC_MAX_NAME];
e4ee831f9   Mark Brown   regulator: Add WM...
48
49
50
51
  	struct regulator_desc desc;
  	int base;
  	struct wm831x *wm831x;
  	struct regulator_dev *regulator;
9a5ed0bac   Linus Walleij   regulator: wm831x...
52
  	struct gpio_desc *dvs_gpiod;
e24a04c44   Mark Brown   regulator: Implem...
53
54
55
  	int dvs_gpio_state;
  	int on_vsel;
  	int dvs_vsel;
e4ee831f9   Mark Brown   regulator: Add WM...
56
  };
e4ee831f9   Mark Brown   regulator: Add WM...
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
  static unsigned int wm831x_dcdc_get_mode(struct regulator_dev *rdev)
  
  {
  	struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev);
  	struct wm831x *wm831x = dcdc->wm831x;
  	u16 reg = dcdc->base + WM831X_DCDC_ON_CONFIG;
  	int val;
  
  	val = wm831x_reg_read(wm831x, reg);
  	if (val < 0)
  		return val;
  
  	val = (val & WM831X_DC1_ON_MODE_MASK) >> WM831X_DC1_ON_MODE_SHIFT;
  
  	switch (val) {
  	case WM831X_DCDC_MODE_FAST:
  		return REGULATOR_MODE_FAST;
  	case WM831X_DCDC_MODE_NORMAL:
  		return REGULATOR_MODE_NORMAL;
  	case WM831X_DCDC_MODE_STANDBY:
  		return REGULATOR_MODE_STANDBY;
  	case WM831X_DCDC_MODE_IDLE:
  		return REGULATOR_MODE_IDLE;
  	default:
  		BUG();
9ee291a45   Mark Brown   regulator: Fix wa...
82
  		return -EINVAL;
e4ee831f9   Mark Brown   regulator: Add WM...
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
  	}
  }
  
  static int wm831x_dcdc_set_mode_int(struct wm831x *wm831x, int reg,
  				    unsigned int mode)
  {
  	int val;
  
  	switch (mode) {
  	case REGULATOR_MODE_FAST:
  		val = WM831X_DCDC_MODE_FAST;
  		break;
  	case REGULATOR_MODE_NORMAL:
  		val = WM831X_DCDC_MODE_NORMAL;
  		break;
  	case REGULATOR_MODE_STANDBY:
  		val = WM831X_DCDC_MODE_STANDBY;
  		break;
  	case REGULATOR_MODE_IDLE:
  		val = WM831X_DCDC_MODE_IDLE;
  		break;
  	default:
  		return -EINVAL;
  	}
  
  	return wm831x_set_bits(wm831x, reg, WM831X_DC1_ON_MODE_MASK,
  			       val << WM831X_DC1_ON_MODE_SHIFT);
  }
  
  static int wm831x_dcdc_set_mode(struct regulator_dev *rdev, unsigned int mode)
  {
  	struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev);
  	struct wm831x *wm831x = dcdc->wm831x;
  	u16 reg = dcdc->base + WM831X_DCDC_ON_CONFIG;
  
  	return wm831x_dcdc_set_mode_int(wm831x, reg, mode);
  }
  
  static int wm831x_dcdc_set_suspend_mode(struct regulator_dev *rdev,
  					unsigned int mode)
  {
  	struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev);
  	struct wm831x *wm831x = dcdc->wm831x;
  	u16 reg = dcdc->base + WM831X_DCDC_SLEEP_CONTROL;
  
  	return wm831x_dcdc_set_mode_int(wm831x, reg, mode);
  }
  
  static int wm831x_dcdc_get_status(struct regulator_dev *rdev)
  {
  	struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev);
  	struct wm831x *wm831x = dcdc->wm831x;
  	int ret;
  
  	/* First, check for errors */
  	ret = wm831x_reg_read(wm831x, WM831X_DCDC_UV_STATUS);
  	if (ret < 0)
  		return ret;
  
  	if (ret & (1 << rdev_get_id(rdev))) {
  		dev_dbg(wm831x->dev, "DCDC%d under voltage
  ",
  			rdev_get_id(rdev) + 1);
  		return REGULATOR_STATUS_ERROR;
  	}
  
  	/* DCDC1 and DCDC2 can additionally detect high voltage/current */
  	if (rdev_get_id(rdev) < 2) {
  		if (ret & (WM831X_DC1_OV_STS << rdev_get_id(rdev))) {
  			dev_dbg(wm831x->dev, "DCDC%d over voltage
  ",
  				rdev_get_id(rdev) + 1);
  			return REGULATOR_STATUS_ERROR;
  		}
  
  		if (ret & (WM831X_DC1_HC_STS << rdev_get_id(rdev))) {
  			dev_dbg(wm831x->dev, "DCDC%d over current
  ",
  				rdev_get_id(rdev) + 1);
  			return REGULATOR_STATUS_ERROR;
  		}
  	}
  
  	/* Is the regulator on? */
  	ret = wm831x_reg_read(wm831x, WM831X_DCDC_STATUS);
  	if (ret < 0)
  		return ret;
  	if (!(ret & (1 << rdev_get_id(rdev))))
  		return REGULATOR_STATUS_OFF;
  
  	/* TODO: When we handle hardware control modes so we can report the
  	 * current mode. */
  	return REGULATOR_STATUS_ON;
  }
  
  static irqreturn_t wm831x_dcdc_uv_irq(int irq, void *data)
  {
  	struct wm831x_dcdc *dcdc = data;
  
  	regulator_notifier_call_chain(dcdc->regulator,
  				      REGULATOR_EVENT_UNDER_VOLTAGE,
  				      NULL);
  
  	return IRQ_HANDLED;
  }
  
  static irqreturn_t wm831x_dcdc_oc_irq(int irq, void *data)
  {
  	struct wm831x_dcdc *dcdc = data;
  
  	regulator_notifier_call_chain(dcdc->regulator,
  				      REGULATOR_EVENT_OVER_CURRENT,
  				      NULL);
  
  	return IRQ_HANDLED;
  }
  
  /*
   * BUCKV specifics
   */
60ab7f415   Matti Vaittinen   regulator: use li...
203
  static const struct linear_range wm831x_buckv_ranges[] = {
ccffcb8e9   Axel Lin   regulator: wm831x...
204
205
206
  	REGULATOR_LINEAR_RANGE(600000, 0, 0x7, 0),
  	REGULATOR_LINEAR_RANGE(600000, 0x8, 0x68, 12500),
  };
e24a04c44   Mark Brown   regulator: Implem...
207

e24a04c44   Mark Brown   regulator: Implem...
208
209
210
211
212
213
214
215
  static int wm831x_buckv_set_dvs(struct regulator_dev *rdev, int state)
  {
  	struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev);
  
  	if (state == dcdc->dvs_gpio_state)
  		return 0;
  
  	dcdc->dvs_gpio_state = state;
9a5ed0bac   Linus Walleij   regulator: wm831x...
216
  	gpiod_set_value(dcdc->dvs_gpiod, state);
e24a04c44   Mark Brown   regulator: Implem...
217
218
219
220
221
222
223
  
  	/* Should wait for DVS state change to be asserted if we have
  	 * a GPIO for it, for now assume the device is configured
  	 * for the fastest possible transition.
  	 */
  
  	return 0;
e4ee831f9   Mark Brown   regulator: Add WM...
224
  }
b5fb77e01   Axel Lin   regulator: wm831x...
225
226
  static int wm831x_buckv_set_voltage_sel(struct regulator_dev *rdev,
  					unsigned vsel)
e4ee831f9   Mark Brown   regulator: Add WM...
227
228
  {
  	struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev);
e24a04c44   Mark Brown   regulator: Implem...
229
230
231
  	struct wm831x *wm831x = dcdc->wm831x;
  	int on_reg = dcdc->base + WM831X_DCDC_ON_CONFIG;
  	int dvs_reg = dcdc->base + WM831X_DCDC_DVS_CONTROL;
b5fb77e01   Axel Lin   regulator: wm831x...
232
  	int ret;
3a93f2a9f   Mark Brown   regulator: Report...
233

e24a04c44   Mark Brown   regulator: Implem...
234
  	/* If this value is already set then do a GPIO update if we can */
9a5ed0bac   Linus Walleij   regulator: wm831x...
235
  	if (dcdc->dvs_gpiod && dcdc->on_vsel == vsel)
e24a04c44   Mark Brown   regulator: Implem...
236
  		return wm831x_buckv_set_dvs(rdev, 0);
9a5ed0bac   Linus Walleij   regulator: wm831x...
237
  	if (dcdc->dvs_gpiod && dcdc->dvs_vsel == vsel)
e24a04c44   Mark Brown   regulator: Implem...
238
239
240
241
242
243
244
  		return wm831x_buckv_set_dvs(rdev, 1);
  
  	/* Always set the ON status to the minimum voltage */
  	ret = wm831x_set_bits(wm831x, on_reg, WM831X_DC1_ON_VSEL_MASK, vsel);
  	if (ret < 0)
  		return ret;
  	dcdc->on_vsel = vsel;
9a5ed0bac   Linus Walleij   regulator: wm831x...
245
  	if (!dcdc->dvs_gpiod)
e24a04c44   Mark Brown   regulator: Implem...
246
247
248
249
250
251
  		return ret;
  
  	/* Kick the voltage transition now */
  	ret = wm831x_buckv_set_dvs(rdev, 0);
  	if (ret < 0)
  		return ret;
88cda60e5   Mark Brown   regulator: Improv...
252
253
254
255
256
257
258
259
260
  	/*
  	 * If this VSEL is higher than the last one we've seen then
  	 * remember it as the DVS VSEL.  This is optimised for CPUfreq
  	 * usage where we want to get to the highest voltage very
  	 * quickly.
  	 */
  	if (vsel > dcdc->dvs_vsel) {
  		ret = wm831x_set_bits(wm831x, dvs_reg,
  				      WM831X_DC1_DVS_VSEL_MASK,
13ae633cf   Mark Brown   regulator: wm831x...
261
  				      vsel);
88cda60e5   Mark Brown   regulator: Improv...
262
263
264
265
266
267
  		if (ret == 0)
  			dcdc->dvs_vsel = vsel;
  		else
  			dev_warn(wm831x->dev,
  				 "Failed to set DCDC DVS VSEL: %d
  ", ret);
e24a04c44   Mark Brown   regulator: Implem...
268
  	}
e24a04c44   Mark Brown   regulator: Implem...
269
  	return 0;
e4ee831f9   Mark Brown   regulator: Add WM...
270
271
272
  }
  
  static int wm831x_buckv_set_suspend_voltage(struct regulator_dev *rdev,
e24a04c44   Mark Brown   regulator: Implem...
273
  					    int uV)
e4ee831f9   Mark Brown   regulator: Add WM...
274
275
  {
  	struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev);
e24a04c44   Mark Brown   regulator: Implem...
276
  	struct wm831x *wm831x = dcdc->wm831x;
e4ee831f9   Mark Brown   regulator: Add WM...
277
  	u16 reg = dcdc->base + WM831X_DCDC_SLEEP_CONTROL;
e24a04c44   Mark Brown   regulator: Implem...
278
  	int vsel;
ccffcb8e9   Axel Lin   regulator: wm831x...
279
  	vsel = regulator_map_voltage_linear_range(rdev, uV, uV);
e24a04c44   Mark Brown   regulator: Implem...
280
281
  	if (vsel < 0)
  		return vsel;
e4ee831f9   Mark Brown   regulator: Add WM...
282

e24a04c44   Mark Brown   regulator: Implem...
283
  	return wm831x_set_bits(wm831x, reg, WM831X_DC1_SLP_VSEL_MASK, vsel);
e4ee831f9   Mark Brown   regulator: Add WM...
284
  }
afb8bb805   Mark Brown   regulator: Conver...
285
  static int wm831x_buckv_get_voltage_sel(struct regulator_dev *rdev)
e4ee831f9   Mark Brown   regulator: Add WM...
286
287
  {
  	struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev);
e4ee831f9   Mark Brown   regulator: Add WM...
288

9a5ed0bac   Linus Walleij   regulator: wm831x...
289
  	if (dcdc->dvs_gpiod && dcdc->dvs_gpio_state)
afb8bb805   Mark Brown   regulator: Conver...
290
  		return dcdc->dvs_vsel;
e24a04c44   Mark Brown   regulator: Implem...
291
  	else
afb8bb805   Mark Brown   regulator: Conver...
292
  		return dcdc->on_vsel;
e4ee831f9   Mark Brown   regulator: Add WM...
293
294
295
  }
  
  /* Current limit options */
c25d47888   Axel Lin   regulator: wm831x...
296
297
  static const unsigned int wm831x_dcdc_ilim[] = {
  	125000, 250000, 375000, 500000, 625000, 750000, 875000, 1000000
e4ee831f9   Mark Brown   regulator: Add WM...
298
  };
b0d6dd3ba   Julia Lawall   regulator: wm8*: ...
299
  static const struct regulator_ops wm831x_buckv_ops = {
b5fb77e01   Axel Lin   regulator: wm831x...
300
  	.set_voltage_sel = wm831x_buckv_set_voltage_sel,
afb8bb805   Mark Brown   regulator: Conver...
301
  	.get_voltage_sel = wm831x_buckv_get_voltage_sel,
ccffcb8e9   Axel Lin   regulator: wm831x...
302
303
  	.list_voltage = regulator_list_voltage_linear_range,
  	.map_voltage = regulator_map_voltage_linear_range,
e4ee831f9   Mark Brown   regulator: Add WM...
304
  	.set_suspend_voltage = wm831x_buckv_set_suspend_voltage,
20eb641e4   Axel Lin   regulator: wm831x...
305
306
  	.set_current_limit = regulator_set_current_limit_regmap,
  	.get_current_limit = regulator_get_current_limit_regmap,
e4ee831f9   Mark Brown   regulator: Add WM...
307

3d138fccc   Mark Brown   regulator: wm831x...
308
309
310
  	.is_enabled = regulator_is_enabled_regmap,
  	.enable = regulator_enable_regmap,
  	.disable = regulator_disable_regmap,
e4ee831f9   Mark Brown   regulator: Add WM...
311
312
313
314
315
  	.get_status = wm831x_dcdc_get_status,
  	.get_mode = wm831x_dcdc_get_mode,
  	.set_mode = wm831x_dcdc_set_mode,
  	.set_suspend_mode = wm831x_dcdc_set_suspend_mode,
  };
e24a04c44   Mark Brown   regulator: Implem...
316
317
318
319
  /*
   * Set up DVS control.  We just log errors since we can still run
   * (with reduced performance) if we fail.
   */
1aa20d27b   Mark Brown   regulator: wm831x...
320
321
322
  static void wm831x_buckv_dvs_init(struct platform_device *pdev,
  				  struct wm831x_dcdc *dcdc,
  				  struct wm831x_buckv_pdata *pdata)
e24a04c44   Mark Brown   regulator: Implem...
323
324
325
326
  {
  	struct wm831x *wm831x = dcdc->wm831x;
  	int ret;
  	u16 ctrl;
9a5ed0bac   Linus Walleij   regulator: wm831x...
327
  	if (!pdata)
e24a04c44   Mark Brown   regulator: Implem...
328
  		return;
e24a04c44   Mark Brown   regulator: Implem...
329
330
331
332
  	/* gpiolib won't let us read the GPIO status so pick the higher
  	 * of the two existing voltages so we take it as platform data.
  	 */
  	dcdc->dvs_gpio_state = pdata->dvs_init_state;
9a5ed0bac   Linus Walleij   regulator: wm831x...
333
334
335
336
337
338
  	dcdc->dvs_gpiod = devm_gpiod_get(&pdev->dev, "dvs",
  			dcdc->dvs_gpio_state ? GPIOD_OUT_HIGH : GPIOD_OUT_LOW);
  	if (IS_ERR(dcdc->dvs_gpiod)) {
  		dev_err(wm831x->dev, "Failed to get %s DVS GPIO: %ld
  ",
  			dcdc->name, PTR_ERR(dcdc->dvs_gpiod));
e24a04c44   Mark Brown   regulator: Implem...
339
340
  		return;
  	}
b47ba9fdd   Mark Brown   regulator: Set up...
341
342
343
344
345
346
347
348
349
350
351
352
353
  	switch (pdata->dvs_control_src) {
  	case 1:
  		ctrl = 2 << WM831X_DC1_DVS_SRC_SHIFT;
  		break;
  	case 2:
  		ctrl = 3 << WM831X_DC1_DVS_SRC_SHIFT;
  		break;
  	default:
  		dev_err(wm831x->dev, "Invalid DVS control source %d for %s
  ",
  			pdata->dvs_control_src, dcdc->name);
  		return;
  	}
c439b8f46   Mark Brown   regulator: Bootst...
354
355
356
357
358
359
360
361
362
363
364
365
366
367
  	/* If DVS_VSEL is set to the minimum value then raise it to ON_VSEL
  	 * to make bootstrapping a bit smoother.
  	 */
  	if (!dcdc->dvs_vsel) {
  		ret = wm831x_set_bits(wm831x,
  				      dcdc->base + WM831X_DCDC_DVS_CONTROL,
  				      WM831X_DC1_DVS_VSEL_MASK, dcdc->on_vsel);
  		if (ret == 0)
  			dcdc->dvs_vsel = dcdc->on_vsel;
  		else
  			dev_warn(wm831x->dev, "Failed to set DVS_VSEL: %d
  ",
  				 ret);
  	}
b47ba9fdd   Mark Brown   regulator: Set up...
368
369
370
371
372
373
374
  	ret = wm831x_set_bits(wm831x, dcdc->base + WM831X_DCDC_DVS_CONTROL,
  			      WM831X_DC1_DVS_SRC_MASK, ctrl);
  	if (ret < 0) {
  		dev_err(wm831x->dev, "Failed to set %s DVS source: %d
  ",
  			dcdc->name, ret);
  	}
e24a04c44   Mark Brown   regulator: Implem...
375
  }
a5023574d   Bill Pemberton   regulator: remove...
376
  static int wm831x_buckv_probe(struct platform_device *pdev)
e4ee831f9   Mark Brown   regulator: Add WM...
377
378
  {
  	struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
dff91d0b7   Jingoo Han   regulator: use de...
379
  	struct wm831x_pdata *pdata = dev_get_platdata(wm831x->dev);
c172708d3   Mark Brown   regulator: core: ...
380
  	struct regulator_config config = { };
137a63543   Mark Brown   regulator: Fix WM...
381
  	int id;
e4ee831f9   Mark Brown   regulator: Add WM...
382
383
384
  	struct wm831x_dcdc *dcdc;
  	struct resource *res;
  	int ret, irq;
137a63543   Mark Brown   regulator: Fix WM...
385
386
387
388
389
  	if (pdata && pdata->wm831x_num)
  		id = (pdata->wm831x_num * 10) + 1;
  	else
  		id = 0;
  	id = pdev->id - id;
e4ee831f9   Mark Brown   regulator: Add WM...
390
391
  	dev_dbg(&pdev->dev, "Probing DCDC%d
  ", id + 1);
fded2f4fa   Mark Brown   regulator: Conver...
392
393
  	dcdc = devm_kzalloc(&pdev->dev,  sizeof(struct wm831x_dcdc),
  			    GFP_KERNEL);
5730aa57d   Sachin Kamat   regulator: wm831x...
394
  	if (!dcdc)
e4ee831f9   Mark Brown   regulator: Add WM...
395
  		return -ENOMEM;
e4ee831f9   Mark Brown   regulator: Add WM...
396
397
  
  	dcdc->wm831x = wm831x;
5656098e1   Mark Brown   mfd: wm831x: Conv...
398
  	res = platform_get_resource(pdev, IORESOURCE_REG, 0);
e4ee831f9   Mark Brown   regulator: Add WM...
399
  	if (res == NULL) {
5656098e1   Mark Brown   mfd: wm831x: Conv...
400
401
  		dev_err(&pdev->dev, "No REG resource
  ");
e4ee831f9   Mark Brown   regulator: Add WM...
402
403
404
405
406
407
408
  		ret = -EINVAL;
  		goto err;
  	}
  	dcdc->base = res->start;
  
  	snprintf(dcdc->name, sizeof(dcdc->name), "DCDC%d", id + 1);
  	dcdc->desc.name = dcdc->name;
82caa9780   Mark Brown   regulator: wm831x...
409
410
411
412
  
  	snprintf(dcdc->supply_name, sizeof(dcdc->supply_name),
  		 "DC%dVDD", id + 1);
  	dcdc->desc.supply_name = dcdc->supply_name;
e4ee831f9   Mark Brown   regulator: Add WM...
413
414
415
  	dcdc->desc.id = id;
  	dcdc->desc.type = REGULATOR_VOLTAGE;
  	dcdc->desc.n_voltages = WM831X_BUCKV_MAX_SELECTOR + 1;
ccffcb8e9   Axel Lin   regulator: wm831x...
416
417
  	dcdc->desc.linear_ranges = wm831x_buckv_ranges;
  	dcdc->desc.n_linear_ranges = ARRAY_SIZE(wm831x_buckv_ranges);
e4ee831f9   Mark Brown   regulator: Add WM...
418
419
  	dcdc->desc.ops = &wm831x_buckv_ops;
  	dcdc->desc.owner = THIS_MODULE;
3d138fccc   Mark Brown   regulator: wm831x...
420
421
  	dcdc->desc.enable_reg = WM831X_DCDC_ENABLE;
  	dcdc->desc.enable_mask = 1 << id;
20eb641e4   Axel Lin   regulator: wm831x...
422
423
424
425
  	dcdc->desc.csel_reg = dcdc->base + WM831X_DCDC_CONTROL_2;
  	dcdc->desc.csel_mask = WM831X_DC1_HC_THR_MASK;
  	dcdc->desc.n_current_limits = ARRAY_SIZE(wm831x_dcdc_ilim);
  	dcdc->desc.curr_table = wm831x_dcdc_ilim;
e4ee831f9   Mark Brown   regulator: Add WM...
426

e24a04c44   Mark Brown   regulator: Implem...
427
428
429
430
431
432
433
  	ret = wm831x_reg_read(wm831x, dcdc->base + WM831X_DCDC_ON_CONFIG);
  	if (ret < 0) {
  		dev_err(wm831x->dev, "Failed to read ON VSEL: %d
  ", ret);
  		goto err;
  	}
  	dcdc->on_vsel = ret & WM831X_DC1_ON_VSEL_MASK;
a1b81dd3f   Mark Brown   regulator: Fix WM...
434
  	ret = wm831x_reg_read(wm831x, dcdc->base + WM831X_DCDC_DVS_CONTROL);
e24a04c44   Mark Brown   regulator: Implem...
435
436
437
438
439
440
  	if (ret < 0) {
  		dev_err(wm831x->dev, "Failed to read DVS VSEL: %d
  ", ret);
  		goto err;
  	}
  	dcdc->dvs_vsel = ret & WM831X_DC1_DVS_VSEL_MASK;
f0b067d9b   Mark Brown   regulator: wm831x...
441
  	if (pdata && pdata->dcdc[id])
1aa20d27b   Mark Brown   regulator: wm831x...
442
443
  		wm831x_buckv_dvs_init(pdev, dcdc,
  				      pdata->dcdc[id]->driver_data);
e24a04c44   Mark Brown   regulator: Implem...
444

c172708d3   Mark Brown   regulator: core: ...
445
  	config.dev = pdev->dev.parent;
b7ca87884   Mark Brown   regulator: wm831x...
446
447
  	if (pdata)
  		config.init_data = pdata->dcdc[id];
c172708d3   Mark Brown   regulator: core: ...
448
  	config.driver_data = dcdc;
3d138fccc   Mark Brown   regulator: wm831x...
449
  	config.regmap = wm831x->regmap;
c172708d3   Mark Brown   regulator: core: ...
450

d73b4cb7b   Mark Brown   regulator: wm831x...
451
452
  	dcdc->regulator = devm_regulator_register(&pdev->dev, &dcdc->desc,
  						  &config);
e4ee831f9   Mark Brown   regulator: Add WM...
453
454
455
456
457
458
459
  	if (IS_ERR(dcdc->regulator)) {
  		ret = PTR_ERR(dcdc->regulator);
  		dev_err(wm831x->dev, "Failed to register DCDC%d: %d
  ",
  			id + 1, ret);
  		goto err;
  	}
cd99758ba   Mark Brown   mfd: Convert wm83...
460
  	irq = wm831x_irq(wm831x, platform_get_irq_byname(pdev, "UV"));
b0c4c0c68   Mark Brown   regulator: wm831x...
461
462
  	ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
  					wm831x_dcdc_uv_irq,
29454738f   Fabio Estevam   regulator: wm831x...
463
464
  					IRQF_TRIGGER_RISING | IRQF_ONESHOT,
  					dcdc->name, dcdc);
e4ee831f9   Mark Brown   regulator: Add WM...
465
466
467
468
  	if (ret != 0) {
  		dev_err(&pdev->dev, "Failed to request UV IRQ %d: %d
  ",
  			irq, ret);
d73b4cb7b   Mark Brown   regulator: wm831x...
469
  		goto err;
e4ee831f9   Mark Brown   regulator: Add WM...
470
  	}
cd99758ba   Mark Brown   mfd: Convert wm83...
471
  	irq = wm831x_irq(wm831x, platform_get_irq_byname(pdev, "HC"));
b0c4c0c68   Mark Brown   regulator: wm831x...
472
473
  	ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
  					wm831x_dcdc_oc_irq,
29454738f   Fabio Estevam   regulator: wm831x...
474
475
  					IRQF_TRIGGER_RISING | IRQF_ONESHOT,
  					dcdc->name, dcdc);
e4ee831f9   Mark Brown   regulator: Add WM...
476
477
478
479
  	if (ret != 0) {
  		dev_err(&pdev->dev, "Failed to request HC IRQ %d: %d
  ",
  			irq, ret);
d73b4cb7b   Mark Brown   regulator: wm831x...
480
  		goto err;
e4ee831f9   Mark Brown   regulator: Add WM...
481
482
483
484
485
  	}
  
  	platform_set_drvdata(pdev, dcdc);
  
  	return 0;
e4ee831f9   Mark Brown   regulator: Add WM...
486
  err:
e4ee831f9   Mark Brown   regulator: Add WM...
487
488
  	return ret;
  }
e4ee831f9   Mark Brown   regulator: Add WM...
489
490
  static struct platform_driver wm831x_buckv_driver = {
  	.probe = wm831x_buckv_probe,
e4ee831f9   Mark Brown   regulator: Add WM...
491
492
493
494
495
496
497
498
  	.driver		= {
  		.name	= "wm831x-buckv",
  	},
  };
  
  /*
   * BUCKP specifics
   */
d580cb5e7   Axel Lin   regulator: wm831x...
499
  static int wm831x_buckp_set_suspend_voltage(struct regulator_dev *rdev, int uV)
e4ee831f9   Mark Brown   regulator: Add WM...
500
501
502
  {
  	struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev);
  	struct wm831x *wm831x = dcdc->wm831x;
e4ee831f9   Mark Brown   regulator: Add WM...
503
  	u16 reg = dcdc->base + WM831X_DCDC_SLEEP_CONTROL;
d580cb5e7   Axel Lin   regulator: wm831x...
504
505
506
507
508
  	int sel;
  
  	sel = regulator_map_voltage_linear(rdev, uV, uV);
  	if (sel < 0)
  		return sel;
e4ee831f9   Mark Brown   regulator: Add WM...
509

d580cb5e7   Axel Lin   regulator: wm831x...
510
  	return wm831x_set_bits(wm831x, reg, WM831X_DC3_ON_VSEL_MASK, sel);
e4ee831f9   Mark Brown   regulator: Add WM...
511
  }
b0d6dd3ba   Julia Lawall   regulator: wm8*: ...
512
  static const struct regulator_ops wm831x_buckp_ops = {
d580cb5e7   Axel Lin   regulator: wm831x...
513
  	.set_voltage_sel = regulator_set_voltage_sel_regmap,
817436e72   Mark Brown   regulator: wm831x...
514
  	.get_voltage_sel = regulator_get_voltage_sel_regmap,
c70ad9dcf   Axel Lin   regulator: wm831x...
515
  	.list_voltage = regulator_list_voltage_linear,
d580cb5e7   Axel Lin   regulator: wm831x...
516
  	.map_voltage = regulator_map_voltage_linear,
e4ee831f9   Mark Brown   regulator: Add WM...
517
  	.set_suspend_voltage = wm831x_buckp_set_suspend_voltage,
3d138fccc   Mark Brown   regulator: wm831x...
518
519
520
  	.is_enabled = regulator_is_enabled_regmap,
  	.enable = regulator_enable_regmap,
  	.disable = regulator_disable_regmap,
e4ee831f9   Mark Brown   regulator: Add WM...
521
522
523
524
525
  	.get_status = wm831x_dcdc_get_status,
  	.get_mode = wm831x_dcdc_get_mode,
  	.set_mode = wm831x_dcdc_set_mode,
  	.set_suspend_mode = wm831x_dcdc_set_suspend_mode,
  };
a5023574d   Bill Pemberton   regulator: remove...
526
  static int wm831x_buckp_probe(struct platform_device *pdev)
e4ee831f9   Mark Brown   regulator: Add WM...
527
528
  {
  	struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
dff91d0b7   Jingoo Han   regulator: use de...
529
  	struct wm831x_pdata *pdata = dev_get_platdata(wm831x->dev);
c172708d3   Mark Brown   regulator: core: ...
530
  	struct regulator_config config = { };
137a63543   Mark Brown   regulator: Fix WM...
531
  	int id;
e4ee831f9   Mark Brown   regulator: Add WM...
532
533
534
  	struct wm831x_dcdc *dcdc;
  	struct resource *res;
  	int ret, irq;
137a63543   Mark Brown   regulator: Fix WM...
535
536
537
538
539
  	if (pdata && pdata->wm831x_num)
  		id = (pdata->wm831x_num * 10) + 1;
  	else
  		id = 0;
  	id = pdev->id - id;
e4ee831f9   Mark Brown   regulator: Add WM...
540
541
  	dev_dbg(&pdev->dev, "Probing DCDC%d
  ", id + 1);
fded2f4fa   Mark Brown   regulator: Conver...
542
543
  	dcdc = devm_kzalloc(&pdev->dev, sizeof(struct wm831x_dcdc),
  			    GFP_KERNEL);
5730aa57d   Sachin Kamat   regulator: wm831x...
544
  	if (!dcdc)
e4ee831f9   Mark Brown   regulator: Add WM...
545
  		return -ENOMEM;
e4ee831f9   Mark Brown   regulator: Add WM...
546
547
  
  	dcdc->wm831x = wm831x;
5656098e1   Mark Brown   mfd: wm831x: Conv...
548
  	res = platform_get_resource(pdev, IORESOURCE_REG, 0);
e4ee831f9   Mark Brown   regulator: Add WM...
549
  	if (res == NULL) {
5656098e1   Mark Brown   mfd: wm831x: Conv...
550
551
  		dev_err(&pdev->dev, "No REG resource
  ");
e4ee831f9   Mark Brown   regulator: Add WM...
552
553
554
555
556
557
558
  		ret = -EINVAL;
  		goto err;
  	}
  	dcdc->base = res->start;
  
  	snprintf(dcdc->name, sizeof(dcdc->name), "DCDC%d", id + 1);
  	dcdc->desc.name = dcdc->name;
82caa9780   Mark Brown   regulator: wm831x...
559
560
561
562
  
  	snprintf(dcdc->supply_name, sizeof(dcdc->supply_name),
  		 "DC%dVDD", id + 1);
  	dcdc->desc.supply_name = dcdc->supply_name;
e4ee831f9   Mark Brown   regulator: Add WM...
563
564
565
566
567
  	dcdc->desc.id = id;
  	dcdc->desc.type = REGULATOR_VOLTAGE;
  	dcdc->desc.n_voltages = WM831X_BUCKP_MAX_SELECTOR + 1;
  	dcdc->desc.ops = &wm831x_buckp_ops;
  	dcdc->desc.owner = THIS_MODULE;
817436e72   Mark Brown   regulator: wm831x...
568
569
  	dcdc->desc.vsel_reg = dcdc->base + WM831X_DCDC_ON_CONFIG;
  	dcdc->desc.vsel_mask = WM831X_DC3_ON_VSEL_MASK;
3d138fccc   Mark Brown   regulator: wm831x...
570
571
  	dcdc->desc.enable_reg = WM831X_DCDC_ENABLE;
  	dcdc->desc.enable_mask = 1 << id;
c70ad9dcf   Axel Lin   regulator: wm831x...
572
573
  	dcdc->desc.min_uV = 850000;
  	dcdc->desc.uV_step = 25000;
e4ee831f9   Mark Brown   regulator: Add WM...
574

c172708d3   Mark Brown   regulator: core: ...
575
  	config.dev = pdev->dev.parent;
b7ca87884   Mark Brown   regulator: wm831x...
576
577
  	if (pdata)
  		config.init_data = pdata->dcdc[id];
c172708d3   Mark Brown   regulator: core: ...
578
  	config.driver_data = dcdc;
817436e72   Mark Brown   regulator: wm831x...
579
  	config.regmap = wm831x->regmap;
c172708d3   Mark Brown   regulator: core: ...
580

d73b4cb7b   Mark Brown   regulator: wm831x...
581
582
  	dcdc->regulator = devm_regulator_register(&pdev->dev, &dcdc->desc,
  						  &config);
e4ee831f9   Mark Brown   regulator: Add WM...
583
584
585
586
587
588
589
  	if (IS_ERR(dcdc->regulator)) {
  		ret = PTR_ERR(dcdc->regulator);
  		dev_err(wm831x->dev, "Failed to register DCDC%d: %d
  ",
  			id + 1, ret);
  		goto err;
  	}
cd99758ba   Mark Brown   mfd: Convert wm83...
590
  	irq = wm831x_irq(wm831x, platform_get_irq_byname(pdev, "UV"));
b0c4c0c68   Mark Brown   regulator: wm831x...
591
592
  	ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
  					wm831x_dcdc_uv_irq,
29454738f   Fabio Estevam   regulator: wm831x...
593
594
  					IRQF_TRIGGER_RISING | IRQF_ONESHOT,
  					dcdc->name, dcdc);
e4ee831f9   Mark Brown   regulator: Add WM...
595
596
597
598
  	if (ret != 0) {
  		dev_err(&pdev->dev, "Failed to request UV IRQ %d: %d
  ",
  			irq, ret);
d73b4cb7b   Mark Brown   regulator: wm831x...
599
  		goto err;
e4ee831f9   Mark Brown   regulator: Add WM...
600
601
602
603
604
  	}
  
  	platform_set_drvdata(pdev, dcdc);
  
  	return 0;
e4ee831f9   Mark Brown   regulator: Add WM...
605
  err:
e4ee831f9   Mark Brown   regulator: Add WM...
606
607
  	return ret;
  }
e4ee831f9   Mark Brown   regulator: Add WM...
608
609
  static struct platform_driver wm831x_buckp_driver = {
  	.probe = wm831x_buckp_probe,
e4ee831f9   Mark Brown   regulator: Add WM...
610
611
612
613
  	.driver		= {
  		.name	= "wm831x-buckp",
  	},
  };
8267a9ba8   Mark Brown   regulator: Add WM...
614
  /*
1304850d4   Mark Brown   regulator: Add WM...
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
   * DCDC boost convertors
   */
  
  static int wm831x_boostp_get_status(struct regulator_dev *rdev)
  {
  	struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev);
  	struct wm831x *wm831x = dcdc->wm831x;
  	int ret;
  
  	/* First, check for errors */
  	ret = wm831x_reg_read(wm831x, WM831X_DCDC_UV_STATUS);
  	if (ret < 0)
  		return ret;
  
  	if (ret & (1 << rdev_get_id(rdev))) {
  		dev_dbg(wm831x->dev, "DCDC%d under voltage
  ",
  			rdev_get_id(rdev) + 1);
  		return REGULATOR_STATUS_ERROR;
  	}
  
  	/* Is the regulator on? */
  	ret = wm831x_reg_read(wm831x, WM831X_DCDC_STATUS);
  	if (ret < 0)
  		return ret;
  	if (ret & (1 << rdev_get_id(rdev)))
  		return REGULATOR_STATUS_ON;
  	else
  		return REGULATOR_STATUS_OFF;
  }
b0d6dd3ba   Julia Lawall   regulator: wm8*: ...
645
  static const struct regulator_ops wm831x_boostp_ops = {
1304850d4   Mark Brown   regulator: Add WM...
646
  	.get_status = wm831x_boostp_get_status,
3d138fccc   Mark Brown   regulator: wm831x...
647
648
649
  	.is_enabled = regulator_is_enabled_regmap,
  	.enable = regulator_enable_regmap,
  	.disable = regulator_disable_regmap,
1304850d4   Mark Brown   regulator: Add WM...
650
  };
a5023574d   Bill Pemberton   regulator: remove...
651
  static int wm831x_boostp_probe(struct platform_device *pdev)
1304850d4   Mark Brown   regulator: Add WM...
652
653
  {
  	struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
dff91d0b7   Jingoo Han   regulator: use de...
654
  	struct wm831x_pdata *pdata = dev_get_platdata(wm831x->dev);
c172708d3   Mark Brown   regulator: core: ...
655
  	struct regulator_config config = { };
1304850d4   Mark Brown   regulator: Add WM...
656
657
658
659
660
661
662
663
664
665
  	int id = pdev->id % ARRAY_SIZE(pdata->dcdc);
  	struct wm831x_dcdc *dcdc;
  	struct resource *res;
  	int ret, irq;
  
  	dev_dbg(&pdev->dev, "Probing DCDC%d
  ", id + 1);
  
  	if (pdata == NULL || pdata->dcdc[id] == NULL)
  		return -ENODEV;
4c60165dc   Axel Lin   regulator: wm831x...
666
  	dcdc = devm_kzalloc(&pdev->dev, sizeof(struct wm831x_dcdc), GFP_KERNEL);
5730aa57d   Sachin Kamat   regulator: wm831x...
667
  	if (!dcdc)
1304850d4   Mark Brown   regulator: Add WM...
668
  		return -ENOMEM;
1304850d4   Mark Brown   regulator: Add WM...
669
670
  
  	dcdc->wm831x = wm831x;
5656098e1   Mark Brown   mfd: wm831x: Conv...
671
  	res = platform_get_resource(pdev, IORESOURCE_REG, 0);
1304850d4   Mark Brown   regulator: Add WM...
672
  	if (res == NULL) {
5656098e1   Mark Brown   mfd: wm831x: Conv...
673
674
  		dev_err(&pdev->dev, "No REG resource
  ");
477b2bacb   Fabio Estevam   regulator: wm831x...
675
  		return -EINVAL;
1304850d4   Mark Brown   regulator: Add WM...
676
677
678
679
680
681
682
683
684
  	}
  	dcdc->base = res->start;
  
  	snprintf(dcdc->name, sizeof(dcdc->name), "DCDC%d", id + 1);
  	dcdc->desc.name = dcdc->name;
  	dcdc->desc.id = id;
  	dcdc->desc.type = REGULATOR_VOLTAGE;
  	dcdc->desc.ops = &wm831x_boostp_ops;
  	dcdc->desc.owner = THIS_MODULE;
3d138fccc   Mark Brown   regulator: wm831x...
685
686
  	dcdc->desc.enable_reg = WM831X_DCDC_ENABLE;
  	dcdc->desc.enable_mask = 1 << id;
1304850d4   Mark Brown   regulator: Add WM...
687

c172708d3   Mark Brown   regulator: core: ...
688
  	config.dev = pdev->dev.parent;
f0b067d9b   Mark Brown   regulator: wm831x...
689
690
  	if (pdata)
  		config.init_data = pdata->dcdc[id];
c172708d3   Mark Brown   regulator: core: ...
691
  	config.driver_data = dcdc;
3d138fccc   Mark Brown   regulator: wm831x...
692
  	config.regmap = wm831x->regmap;
c172708d3   Mark Brown   regulator: core: ...
693

d73b4cb7b   Mark Brown   regulator: wm831x...
694
695
  	dcdc->regulator = devm_regulator_register(&pdev->dev, &dcdc->desc,
  						  &config);
1304850d4   Mark Brown   regulator: Add WM...
696
697
698
699
700
  	if (IS_ERR(dcdc->regulator)) {
  		ret = PTR_ERR(dcdc->regulator);
  		dev_err(wm831x->dev, "Failed to register DCDC%d: %d
  ",
  			id + 1, ret);
477b2bacb   Fabio Estevam   regulator: wm831x...
701
  		return ret;
1304850d4   Mark Brown   regulator: Add WM...
702
  	}
cd99758ba   Mark Brown   mfd: Convert wm83...
703
  	irq = wm831x_irq(wm831x, platform_get_irq_byname(pdev, "UV"));
b0c4c0c68   Mark Brown   regulator: wm831x...
704
705
  	ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
  					wm831x_dcdc_uv_irq,
29454738f   Fabio Estevam   regulator: wm831x...
706
707
  					IRQF_TRIGGER_RISING | IRQF_ONESHOT,
  					dcdc->name,
b0c4c0c68   Mark Brown   regulator: wm831x...
708
  					dcdc);
1304850d4   Mark Brown   regulator: Add WM...
709
710
711
712
  	if (ret != 0) {
  		dev_err(&pdev->dev, "Failed to request UV IRQ %d: %d
  ",
  			irq, ret);
477b2bacb   Fabio Estevam   regulator: wm831x...
713
  		return ret;
1304850d4   Mark Brown   regulator: Add WM...
714
715
716
717
718
  	}
  
  	platform_set_drvdata(pdev, dcdc);
  
  	return 0;
1304850d4   Mark Brown   regulator: Add WM...
719
  }
1304850d4   Mark Brown   regulator: Add WM...
720
721
  static struct platform_driver wm831x_boostp_driver = {
  	.probe = wm831x_boostp_probe,
1304850d4   Mark Brown   regulator: Add WM...
722
723
724
725
726
727
  	.driver		= {
  		.name	= "wm831x-boostp",
  	},
  };
  
  /*
8267a9ba8   Mark Brown   regulator: Add WM...
728
729
730
731
732
733
734
   * External Power Enable
   *
   * These aren't actually DCDCs but look like them in hardware so share
   * code.
   */
  
  #define WM831X_EPE_BASE 6
b0d6dd3ba   Julia Lawall   regulator: wm8*: ...
735
  static const struct regulator_ops wm831x_epe_ops = {
3d138fccc   Mark Brown   regulator: wm831x...
736
737
738
  	.is_enabled = regulator_is_enabled_regmap,
  	.enable = regulator_enable_regmap,
  	.disable = regulator_disable_regmap,
8267a9ba8   Mark Brown   regulator: Add WM...
739
740
  	.get_status = wm831x_dcdc_get_status,
  };
a5023574d   Bill Pemberton   regulator: remove...
741
  static int wm831x_epe_probe(struct platform_device *pdev)
8267a9ba8   Mark Brown   regulator: Add WM...
742
743
  {
  	struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
dff91d0b7   Jingoo Han   regulator: use de...
744
  	struct wm831x_pdata *pdata = dev_get_platdata(wm831x->dev);
c172708d3   Mark Brown   regulator: core: ...
745
  	struct regulator_config config = { };
8267a9ba8   Mark Brown   regulator: Add WM...
746
747
748
749
750
751
  	int id = pdev->id % ARRAY_SIZE(pdata->epe);
  	struct wm831x_dcdc *dcdc;
  	int ret;
  
  	dev_dbg(&pdev->dev, "Probing EPE%d
  ", id + 1);
4c60165dc   Axel Lin   regulator: wm831x...
752
  	dcdc = devm_kzalloc(&pdev->dev, sizeof(struct wm831x_dcdc), GFP_KERNEL);
5730aa57d   Sachin Kamat   regulator: wm831x...
753
  	if (!dcdc)
8267a9ba8   Mark Brown   regulator: Add WM...
754
  		return -ENOMEM;
8267a9ba8   Mark Brown   regulator: Add WM...
755
756
757
758
759
760
761
762
763
764
765
766
  
  	dcdc->wm831x = wm831x;
  
  	/* For current parts this is correct; probably need to revisit
  	 * in future.
  	 */
  	snprintf(dcdc->name, sizeof(dcdc->name), "EPE%d", id + 1);
  	dcdc->desc.name = dcdc->name;
  	dcdc->desc.id = id + WM831X_EPE_BASE; /* Offset in DCDC registers */
  	dcdc->desc.ops = &wm831x_epe_ops;
  	dcdc->desc.type = REGULATOR_VOLTAGE;
  	dcdc->desc.owner = THIS_MODULE;
3d138fccc   Mark Brown   regulator: wm831x...
767
768
  	dcdc->desc.enable_reg = WM831X_DCDC_ENABLE;
  	dcdc->desc.enable_mask = 1 << dcdc->desc.id;
8267a9ba8   Mark Brown   regulator: Add WM...
769

c172708d3   Mark Brown   regulator: core: ...
770
  	config.dev = pdev->dev.parent;
b7ca87884   Mark Brown   regulator: wm831x...
771
772
  	if (pdata)
  		config.init_data = pdata->epe[id];
c172708d3   Mark Brown   regulator: core: ...
773
  	config.driver_data = dcdc;
3d138fccc   Mark Brown   regulator: wm831x...
774
  	config.regmap = wm831x->regmap;
c172708d3   Mark Brown   regulator: core: ...
775

d73b4cb7b   Mark Brown   regulator: wm831x...
776
777
  	dcdc->regulator = devm_regulator_register(&pdev->dev, &dcdc->desc,
  						  &config);
8267a9ba8   Mark Brown   regulator: Add WM...
778
779
780
781
782
783
784
785
786
787
788
789
790
  	if (IS_ERR(dcdc->regulator)) {
  		ret = PTR_ERR(dcdc->regulator);
  		dev_err(wm831x->dev, "Failed to register EPE%d: %d
  ",
  			id + 1, ret);
  		goto err;
  	}
  
  	platform_set_drvdata(pdev, dcdc);
  
  	return 0;
  
  err:
8267a9ba8   Mark Brown   regulator: Add WM...
791
792
  	return ret;
  }
8267a9ba8   Mark Brown   regulator: Add WM...
793
794
  static struct platform_driver wm831x_epe_driver = {
  	.probe = wm831x_epe_probe,
8267a9ba8   Mark Brown   regulator: Add WM...
795
796
797
798
  	.driver		= {
  		.name	= "wm831x-epe",
  	},
  };
55e03e9c2   Thierry Reding   regulator: wm831x...
799
800
801
802
803
804
  static struct platform_driver * const drivers[] = {
  	&wm831x_buckv_driver,
  	&wm831x_buckp_driver,
  	&wm831x_boostp_driver,
  	&wm831x_epe_driver,
  };
e4ee831f9   Mark Brown   regulator: Add WM...
805
806
  static int __init wm831x_dcdc_init(void)
  {
55e03e9c2   Thierry Reding   regulator: wm831x...
807
  	return platform_register_drivers(drivers, ARRAY_SIZE(drivers));
e4ee831f9   Mark Brown   regulator: Add WM...
808
809
810
811
812
  }
  subsys_initcall(wm831x_dcdc_init);
  
  static void __exit wm831x_dcdc_exit(void)
  {
55e03e9c2   Thierry Reding   regulator: wm831x...
813
  	platform_unregister_drivers(drivers, ARRAY_SIZE(drivers));
e4ee831f9   Mark Brown   regulator: Add WM...
814
815
816
817
818
819
820
821
822
  }
  module_exit(wm831x_dcdc_exit);
  
  /* Module information */
  MODULE_AUTHOR("Mark Brown");
  MODULE_DESCRIPTION("WM831x DC-DC convertor driver");
  MODULE_LICENSE("GPL");
  MODULE_ALIAS("platform:wm831x-buckv");
  MODULE_ALIAS("platform:wm831x-buckp");
43f1f2165   Axel Lin   regulator: wm831x...
823
  MODULE_ALIAS("platform:wm831x-boostp");
24b431505   Mark Brown   regulator: Add EP...
824
  MODULE_ALIAS("platform:wm831x-epe");