Blame view

drivers/regulator/wm831x-ldo.c 16.6 KB
d1c6b4fe6   Mark Brown   regulator: Add WM...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
  /*
   * wm831x-ldo.c  --  LDO driver for the WM831x series
   *
   * Copyright 2009 Wolfson Microelectronics PLC.
   *
   * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
   *
   *  This program is free software; you can redistribute  it and/or modify it
   *  under  the terms of  the GNU General  Public License as published by the
   *  Free Software Foundation;  either version 2 of the  License, or (at your
   *  option) any later version.
   */
  
  #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>
5a0e3ad6a   Tejun Heo   include cleanup: ...
22
  #include <linux/slab.h>
d1c6b4fe6   Mark Brown   regulator: Add WM...
23
24
25
26
  
  #include <linux/mfd/wm831x/core.h>
  #include <linux/mfd/wm831x/regulator.h>
  #include <linux/mfd/wm831x/pdata.h>
f1aba13fb   Mark Brown   regulator: wm831x...
27
  #define WM831X_LDO_MAX_NAME 9
d1c6b4fe6   Mark Brown   regulator: Add WM...
28
29
30
31
32
33
34
35
36
37
  
  #define WM831X_LDO_CONTROL       0
  #define WM831X_LDO_ON_CONTROL    1
  #define WM831X_LDO_SLEEP_CONTROL 2
  
  #define WM831X_ALIVE_LDO_ON_CONTROL    0
  #define WM831X_ALIVE_LDO_SLEEP_CONTROL 1
  
  struct wm831x_ldo {
  	char name[WM831X_LDO_MAX_NAME];
f1aba13fb   Mark Brown   regulator: wm831x...
38
  	char supply_name[WM831X_LDO_MAX_NAME];
d1c6b4fe6   Mark Brown   regulator: Add WM...
39
40
41
42
43
44
45
46
47
  	struct regulator_desc desc;
  	int base;
  	struct wm831x *wm831x;
  	struct regulator_dev *regulator;
  };
  
  /*
   * Shared
   */
d1c6b4fe6   Mark Brown   regulator: Add WM...
48
49
50
51
52
53
54
55
56
57
58
59
60
61
  static irqreturn_t wm831x_ldo_uv_irq(int irq, void *data)
  {
  	struct wm831x_ldo *ldo = data;
  
  	regulator_notifier_call_chain(ldo->regulator,
  				      REGULATOR_EVENT_UNDER_VOLTAGE,
  				      NULL);
  
  	return IRQ_HANDLED;
  }
  
  /*
   * General purpose LDOs
   */
5ff26a14c   Mark Brown   regulator: wm831x...
62
  static const struct regulator_linear_range wm831x_gp_ldo_ranges[] = {
8828bae46   Axel Lin   regulator: Add RE...
63
64
  	REGULATOR_LINEAR_RANGE(900000, 0, 14, 50000),
  	REGULATOR_LINEAR_RANGE(1700000, 15, 31, 100000),
5ff26a14c   Mark Brown   regulator: wm831x...
65
  };
d1c6b4fe6   Mark Brown   regulator: Add WM...
66
67
68
69
70
  
  static int wm831x_gp_ldo_set_suspend_voltage(struct regulator_dev *rdev,
  					     int uV)
  {
  	struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
0a4796896   Axel Lin   regulator: wm831x...
71
72
  	struct wm831x *wm831x = ldo->wm831x;
  	int sel, reg = ldo->base + WM831X_LDO_SLEEP_CONTROL;
d1c6b4fe6   Mark Brown   regulator: Add WM...
73

5ff26a14c   Mark Brown   regulator: wm831x...
74
  	sel = regulator_map_voltage_linear_range(rdev, uV, uV);
0a4796896   Axel Lin   regulator: wm831x...
75
76
77
78
  	if (sel < 0)
  		return sel;
  
  	return wm831x_set_bits(wm831x, reg, WM831X_LDO1_ON_VSEL_MASK, sel);
d1c6b4fe6   Mark Brown   regulator: Add WM...
79
  }
d1c6b4fe6   Mark Brown   regulator: Add WM...
80
81
82
83
84
85
  static unsigned int wm831x_gp_ldo_get_mode(struct regulator_dev *rdev)
  {
  	struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
  	struct wm831x *wm831x = ldo->wm831x;
  	int ctrl_reg = ldo->base + WM831X_LDO_CONTROL;
  	int on_reg = ldo->base + WM831X_LDO_ON_CONTROL;
9a767d43f   Roel Kluin   regulator: Fix ch...
86
  	int ret;
d1c6b4fe6   Mark Brown   regulator: Add WM...
87
88
89
  
  	ret = wm831x_reg_read(wm831x, on_reg);
  	if (ret < 0)
9a767d43f   Roel Kluin   regulator: Fix ch...
90
  		return ret;
d1c6b4fe6   Mark Brown   regulator: Add WM...
91
92
93
94
95
96
  
  	if (!(ret & WM831X_LDO1_ON_MODE))
  		return REGULATOR_MODE_NORMAL;
  
  	ret = wm831x_reg_read(wm831x, ctrl_reg);
  	if (ret < 0)
9a767d43f   Roel Kluin   regulator: Fix ch...
97
  		return ret;
d1c6b4fe6   Mark Brown   regulator: Add WM...
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
  
  	if (ret & WM831X_LDO1_LP_MODE)
  		return REGULATOR_MODE_STANDBY;
  	else
  		return REGULATOR_MODE_IDLE;
  }
  
  static int wm831x_gp_ldo_set_mode(struct regulator_dev *rdev,
  				  unsigned int mode)
  {
  	struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
  	struct wm831x *wm831x = ldo->wm831x;
  	int ctrl_reg = ldo->base + WM831X_LDO_CONTROL;
  	int on_reg = ldo->base + WM831X_LDO_ON_CONTROL;
  	int ret;
  
  
  	switch (mode) {
  	case REGULATOR_MODE_NORMAL:
  		ret = wm831x_set_bits(wm831x, on_reg,
  				      WM831X_LDO1_ON_MODE, 0);
  		if (ret < 0)
  			return ret;
  		break;
  
  	case REGULATOR_MODE_IDLE:
  		ret = wm831x_set_bits(wm831x, ctrl_reg,
e260999c6   Axel Lin   regulator: wm831x...
125
  				      WM831X_LDO1_LP_MODE, 0);
d1c6b4fe6   Mark Brown   regulator: Add WM...
126
127
128
129
130
131
132
133
  		if (ret < 0)
  			return ret;
  
  		ret = wm831x_set_bits(wm831x, on_reg,
  				      WM831X_LDO1_ON_MODE,
  				      WM831X_LDO1_ON_MODE);
  		if (ret < 0)
  			return ret;
e260999c6   Axel Lin   regulator: wm831x...
134
  		break;
d1c6b4fe6   Mark Brown   regulator: Add WM...
135
136
137
  
  	case REGULATOR_MODE_STANDBY:
  		ret = wm831x_set_bits(wm831x, ctrl_reg,
e260999c6   Axel Lin   regulator: wm831x...
138
139
  				      WM831X_LDO1_LP_MODE,
  				      WM831X_LDO1_LP_MODE);
d1c6b4fe6   Mark Brown   regulator: Add WM...
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
  		if (ret < 0)
  			return ret;
  
  		ret = wm831x_set_bits(wm831x, on_reg,
  				      WM831X_LDO1_ON_MODE,
  				      WM831X_LDO1_ON_MODE);
  		if (ret < 0)
  			return ret;
  		break;
  
  	default:
  		return -EINVAL;
  	}
  
  	return 0;
  }
  
  static int wm831x_gp_ldo_get_status(struct regulator_dev *rdev)
  {
  	struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
  	struct wm831x *wm831x = ldo->wm831x;
  	int mask = 1 << rdev_get_id(rdev);
  	int ret;
  
  	/* Is the regulator on? */
  	ret = wm831x_reg_read(wm831x, WM831X_LDO_STATUS);
  	if (ret < 0)
  		return ret;
  	if (!(ret & mask))
  		return REGULATOR_STATUS_OFF;
  
  	/* Is it reporting under voltage? */
  	ret = wm831x_reg_read(wm831x, WM831X_LDO_UV_STATUS);
363506cd7   Axel Lin   regulator: wm831x...
173
174
  	if (ret < 0)
  		return ret;
d1c6b4fe6   Mark Brown   regulator: Add WM...
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
  	if (ret & mask)
  		return REGULATOR_STATUS_ERROR;
  
  	ret = wm831x_gp_ldo_get_mode(rdev);
  	if (ret < 0)
  		return ret;
  	else
  		return regulator_mode_to_status(ret);
  }
  
  static unsigned int wm831x_gp_ldo_get_optimum_mode(struct regulator_dev *rdev,
  						   int input_uV,
  						   int output_uV, int load_uA)
  {
  	if (load_uA < 20000)
  		return REGULATOR_MODE_STANDBY;
  	if (load_uA < 50000)
  		return REGULATOR_MODE_IDLE;
  	return REGULATOR_MODE_NORMAL;
  }
b0d6dd3ba   Julia Lawall   regulator: wm8*: ...
195
  static const struct regulator_ops wm831x_gp_ldo_ops = {
5ff26a14c   Mark Brown   regulator: wm831x...
196
197
  	.list_voltage = regulator_list_voltage_linear_range,
  	.map_voltage = regulator_map_voltage_linear_range,
ac663b472   Mark Brown   regulator: wm831x...
198
  	.get_voltage_sel = regulator_get_voltage_sel_regmap,
0a4796896   Axel Lin   regulator: wm831x...
199
  	.set_voltage_sel = regulator_set_voltage_sel_regmap,
d1c6b4fe6   Mark Brown   regulator: Add WM...
200
201
202
203
204
  	.set_suspend_voltage = wm831x_gp_ldo_set_suspend_voltage,
  	.get_mode = wm831x_gp_ldo_get_mode,
  	.set_mode = wm831x_gp_ldo_set_mode,
  	.get_status = wm831x_gp_ldo_get_status,
  	.get_optimum_mode = wm831x_gp_ldo_get_optimum_mode,
22c5fb6a7   Mark Brown   regulator: wm831x...
205
206
  	.get_bypass = regulator_get_bypass_regmap,
  	.set_bypass = regulator_set_bypass_regmap,
d1c6b4fe6   Mark Brown   regulator: Add WM...
207

ca8c361b4   Mark Brown   regulator: wm831x...
208
209
210
  	.is_enabled = regulator_is_enabled_regmap,
  	.enable = regulator_enable_regmap,
  	.disable = regulator_disable_regmap,
d1c6b4fe6   Mark Brown   regulator: Add WM...
211
  };
a5023574d   Bill Pemberton   regulator: remove...
212
  static int wm831x_gp_ldo_probe(struct platform_device *pdev)
d1c6b4fe6   Mark Brown   regulator: Add WM...
213
214
  {
  	struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
dff91d0b7   Jingoo Han   regulator: use de...
215
  	struct wm831x_pdata *pdata = dev_get_platdata(wm831x->dev);
c172708d3   Mark Brown   regulator: core: ...
216
  	struct regulator_config config = { };
137a63543   Mark Brown   regulator: Fix WM...
217
  	int id;
d1c6b4fe6   Mark Brown   regulator: Add WM...
218
219
220
  	struct wm831x_ldo *ldo;
  	struct resource *res;
  	int ret, irq;
137a63543   Mark Brown   regulator: Fix WM...
221
222
223
224
225
  	if (pdata && pdata->wm831x_num)
  		id = (pdata->wm831x_num * 10) + 1;
  	else
  		id = 0;
  	id = pdev->id - id;
d1c6b4fe6   Mark Brown   regulator: Add WM...
226
227
  	dev_dbg(&pdev->dev, "Probing LDO%d
  ", id + 1);
fded2f4fa   Mark Brown   regulator: Conver...
228
  	ldo = devm_kzalloc(&pdev->dev, sizeof(struct wm831x_ldo), GFP_KERNEL);
fae3b8364   Sachin Kamat   regulator: wm831x...
229
  	if (!ldo)
d1c6b4fe6   Mark Brown   regulator: Add WM...
230
  		return -ENOMEM;
d1c6b4fe6   Mark Brown   regulator: Add WM...
231
232
  
  	ldo->wm831x = wm831x;
5656098e1   Mark Brown   mfd: wm831x: Conv...
233
  	res = platform_get_resource(pdev, IORESOURCE_REG, 0);
d1c6b4fe6   Mark Brown   regulator: Add WM...
234
  	if (res == NULL) {
5656098e1   Mark Brown   mfd: wm831x: Conv...
235
236
  		dev_err(&pdev->dev, "No REG resource
  ");
d1c6b4fe6   Mark Brown   regulator: Add WM...
237
238
239
240
241
242
243
  		ret = -EINVAL;
  		goto err;
  	}
  	ldo->base = res->start;
  
  	snprintf(ldo->name, sizeof(ldo->name), "LDO%d", id + 1);
  	ldo->desc.name = ldo->name;
f1aba13fb   Mark Brown   regulator: wm831x...
244
245
246
247
  
  	snprintf(ldo->supply_name, sizeof(ldo->supply_name),
  		 "LDO%dVDD", id + 1);
  	ldo->desc.supply_name = ldo->supply_name;
d1c6b4fe6   Mark Brown   regulator: Add WM...
248
249
  	ldo->desc.id = id;
  	ldo->desc.type = REGULATOR_VOLTAGE;
5ff26a14c   Mark Brown   regulator: wm831x...
250
  	ldo->desc.n_voltages = 32;
d1c6b4fe6   Mark Brown   regulator: Add WM...
251
252
  	ldo->desc.ops = &wm831x_gp_ldo_ops;
  	ldo->desc.owner = THIS_MODULE;
ac663b472   Mark Brown   regulator: wm831x...
253
254
  	ldo->desc.vsel_reg = ldo->base + WM831X_LDO_ON_CONTROL;
  	ldo->desc.vsel_mask = WM831X_LDO1_ON_VSEL_MASK;
ca8c361b4   Mark Brown   regulator: wm831x...
255
256
  	ldo->desc.enable_reg = WM831X_LDO_ENABLE;
  	ldo->desc.enable_mask = 1 << id;
22c5fb6a7   Mark Brown   regulator: wm831x...
257
258
  	ldo->desc.bypass_reg = ldo->base;
  	ldo->desc.bypass_mask = WM831X_LDO1_SWI;
5ff26a14c   Mark Brown   regulator: wm831x...
259
260
  	ldo->desc.linear_ranges = wm831x_gp_ldo_ranges;
  	ldo->desc.n_linear_ranges = ARRAY_SIZE(wm831x_gp_ldo_ranges);
d1c6b4fe6   Mark Brown   regulator: Add WM...
261

c172708d3   Mark Brown   regulator: core: ...
262
  	config.dev = pdev->dev.parent;
b7ca87884   Mark Brown   regulator: wm831x...
263
264
  	if (pdata)
  		config.init_data = pdata->ldo[id];
c172708d3   Mark Brown   regulator: core: ...
265
  	config.driver_data = ldo;
ac663b472   Mark Brown   regulator: wm831x...
266
  	config.regmap = wm831x->regmap;
c172708d3   Mark Brown   regulator: core: ...
267

fc7c60e39   Mark Brown   regulator: wm831x...
268
269
  	ldo->regulator = devm_regulator_register(&pdev->dev, &ldo->desc,
  						 &config);
d1c6b4fe6   Mark Brown   regulator: Add WM...
270
271
272
273
274
275
276
  	if (IS_ERR(ldo->regulator)) {
  		ret = PTR_ERR(ldo->regulator);
  		dev_err(wm831x->dev, "Failed to register LDO%d: %d
  ",
  			id + 1, ret);
  		goto err;
  	}
cd99758ba   Mark Brown   mfd: Convert wm83...
277
  	irq = wm831x_irq(wm831x, platform_get_irq_byname(pdev, "UV"));
41c7a879d   Mark Brown   regulator: wm831x...
278
279
  	ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
  					wm831x_ldo_uv_irq,
29454738f   Fabio Estevam   regulator: wm831x...
280
281
  					IRQF_TRIGGER_RISING | IRQF_ONESHOT,
  					ldo->name,
41c7a879d   Mark Brown   regulator: wm831x...
282
  					ldo);
d1c6b4fe6   Mark Brown   regulator: Add WM...
283
284
285
286
  	if (ret != 0) {
  		dev_err(&pdev->dev, "Failed to request UV IRQ %d: %d
  ",
  			irq, ret);
fc7c60e39   Mark Brown   regulator: wm831x...
287
  		goto err;
d1c6b4fe6   Mark Brown   regulator: Add WM...
288
289
290
291
292
  	}
  
  	platform_set_drvdata(pdev, ldo);
  
  	return 0;
d1c6b4fe6   Mark Brown   regulator: Add WM...
293
  err:
d1c6b4fe6   Mark Brown   regulator: Add WM...
294
295
  	return ret;
  }
d1c6b4fe6   Mark Brown   regulator: Add WM...
296
297
  static struct platform_driver wm831x_gp_ldo_driver = {
  	.probe = wm831x_gp_ldo_probe,
d1c6b4fe6   Mark Brown   regulator: Add WM...
298
299
300
301
302
303
304
305
  	.driver		= {
  		.name	= "wm831x-ldo",
  	},
  };
  
  /*
   * Analogue LDOs
   */
5ff26a14c   Mark Brown   regulator: wm831x...
306
  static const struct regulator_linear_range wm831x_aldo_ranges[] = {
8828bae46   Axel Lin   regulator: Add RE...
307
308
  	REGULATOR_LINEAR_RANGE(1000000, 0, 12, 50000),
  	REGULATOR_LINEAR_RANGE(1700000, 13, 31, 100000),
5ff26a14c   Mark Brown   regulator: wm831x...
309
  };
d1c6b4fe6   Mark Brown   regulator: Add WM...
310
311
312
313
314
  
  static int wm831x_aldo_set_suspend_voltage(struct regulator_dev *rdev,
  					     int uV)
  {
  	struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
0a4796896   Axel Lin   regulator: wm831x...
315
316
  	struct wm831x *wm831x = ldo->wm831x;
  	int sel, reg = ldo->base + WM831X_LDO_SLEEP_CONTROL;
5ff26a14c   Mark Brown   regulator: wm831x...
317
  	sel = regulator_map_voltage_linear_range(rdev, uV, uV);
0a4796896   Axel Lin   regulator: wm831x...
318
319
  	if (sel < 0)
  		return sel;
d1c6b4fe6   Mark Brown   regulator: Add WM...
320

0a4796896   Axel Lin   regulator: wm831x...
321
  	return wm831x_set_bits(wm831x, reg, WM831X_LDO7_ON_VSEL_MASK, sel);
d1c6b4fe6   Mark Brown   regulator: Add WM...
322
  }
d1c6b4fe6   Mark Brown   regulator: Add WM...
323
324
325
326
327
  static unsigned int wm831x_aldo_get_mode(struct regulator_dev *rdev)
  {
  	struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
  	struct wm831x *wm831x = ldo->wm831x;
  	int on_reg = ldo->base + WM831X_LDO_ON_CONTROL;
6f17c6524   Roel Kluin   regulator: wm831x...
328
  	int ret;
d1c6b4fe6   Mark Brown   regulator: Add WM...
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
  
  	ret = wm831x_reg_read(wm831x, on_reg);
  	if (ret < 0)
  		return 0;
  
  	if (ret & WM831X_LDO7_ON_MODE)
  		return REGULATOR_MODE_IDLE;
  	else
  		return REGULATOR_MODE_NORMAL;
  }
  
  static int wm831x_aldo_set_mode(struct regulator_dev *rdev,
  				  unsigned int mode)
  {
  	struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
  	struct wm831x *wm831x = ldo->wm831x;
d1c6b4fe6   Mark Brown   regulator: Add WM...
345
346
347
348
349
350
  	int on_reg = ldo->base + WM831X_LDO_ON_CONTROL;
  	int ret;
  
  
  	switch (mode) {
  	case REGULATOR_MODE_NORMAL:
e841a36ab   Axel Lin   regulator: Fix se...
351
  		ret = wm831x_set_bits(wm831x, on_reg, WM831X_LDO7_ON_MODE, 0);
d1c6b4fe6   Mark Brown   regulator: Add WM...
352
353
354
355
356
  		if (ret < 0)
  			return ret;
  		break;
  
  	case REGULATOR_MODE_IDLE:
e841a36ab   Axel Lin   regulator: Fix se...
357
  		ret = wm831x_set_bits(wm831x, on_reg, WM831X_LDO7_ON_MODE,
d1c6b4fe6   Mark Brown   regulator: Add WM...
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
  				      WM831X_LDO7_ON_MODE);
  		if (ret < 0)
  			return ret;
  		break;
  
  	default:
  		return -EINVAL;
  	}
  
  	return 0;
  }
  
  static int wm831x_aldo_get_status(struct regulator_dev *rdev)
  {
  	struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
  	struct wm831x *wm831x = ldo->wm831x;
  	int mask = 1 << rdev_get_id(rdev);
  	int ret;
  
  	/* Is the regulator on? */
  	ret = wm831x_reg_read(wm831x, WM831X_LDO_STATUS);
  	if (ret < 0)
  		return ret;
  	if (!(ret & mask))
  		return REGULATOR_STATUS_OFF;
  
  	/* Is it reporting under voltage? */
  	ret = wm831x_reg_read(wm831x, WM831X_LDO_UV_STATUS);
363506cd7   Axel Lin   regulator: wm831x...
386
387
  	if (ret < 0)
  		return ret;
d1c6b4fe6   Mark Brown   regulator: Add WM...
388
389
390
391
392
393
394
395
396
  	if (ret & mask)
  		return REGULATOR_STATUS_ERROR;
  
  	ret = wm831x_aldo_get_mode(rdev);
  	if (ret < 0)
  		return ret;
  	else
  		return regulator_mode_to_status(ret);
  }
b0d6dd3ba   Julia Lawall   regulator: wm8*: ...
397
  static const struct regulator_ops wm831x_aldo_ops = {
5ff26a14c   Mark Brown   regulator: wm831x...
398
399
  	.list_voltage = regulator_list_voltage_linear_range,
  	.map_voltage = regulator_map_voltage_linear_range,
ac663b472   Mark Brown   regulator: wm831x...
400
  	.get_voltage_sel = regulator_get_voltage_sel_regmap,
0a4796896   Axel Lin   regulator: wm831x...
401
  	.set_voltage_sel = regulator_set_voltage_sel_regmap,
d1c6b4fe6   Mark Brown   regulator: Add WM...
402
403
404
405
  	.set_suspend_voltage = wm831x_aldo_set_suspend_voltage,
  	.get_mode = wm831x_aldo_get_mode,
  	.set_mode = wm831x_aldo_set_mode,
  	.get_status = wm831x_aldo_get_status,
22c5fb6a7   Mark Brown   regulator: wm831x...
406
407
  	.set_bypass = regulator_set_bypass_regmap,
  	.get_bypass = regulator_get_bypass_regmap,
d1c6b4fe6   Mark Brown   regulator: Add WM...
408

ca8c361b4   Mark Brown   regulator: wm831x...
409
410
411
  	.is_enabled = regulator_is_enabled_regmap,
  	.enable = regulator_enable_regmap,
  	.disable = regulator_disable_regmap,
d1c6b4fe6   Mark Brown   regulator: Add WM...
412
  };
a5023574d   Bill Pemberton   regulator: remove...
413
  static int wm831x_aldo_probe(struct platform_device *pdev)
d1c6b4fe6   Mark Brown   regulator: Add WM...
414
415
  {
  	struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
dff91d0b7   Jingoo Han   regulator: use de...
416
  	struct wm831x_pdata *pdata = dev_get_platdata(wm831x->dev);
c172708d3   Mark Brown   regulator: core: ...
417
  	struct regulator_config config = { };
137a63543   Mark Brown   regulator: Fix WM...
418
  	int id;
d1c6b4fe6   Mark Brown   regulator: Add WM...
419
420
421
  	struct wm831x_ldo *ldo;
  	struct resource *res;
  	int ret, irq;
137a63543   Mark Brown   regulator: Fix WM...
422
423
424
425
426
  	if (pdata && pdata->wm831x_num)
  		id = (pdata->wm831x_num * 10) + 1;
  	else
  		id = 0;
  	id = pdev->id - id;
d1c6b4fe6   Mark Brown   regulator: Add WM...
427
428
  	dev_dbg(&pdev->dev, "Probing LDO%d
  ", id + 1);
fded2f4fa   Mark Brown   regulator: Conver...
429
  	ldo = devm_kzalloc(&pdev->dev, sizeof(struct wm831x_ldo), GFP_KERNEL);
fae3b8364   Sachin Kamat   regulator: wm831x...
430
  	if (!ldo)
d1c6b4fe6   Mark Brown   regulator: Add WM...
431
  		return -ENOMEM;
d1c6b4fe6   Mark Brown   regulator: Add WM...
432
433
  
  	ldo->wm831x = wm831x;
5656098e1   Mark Brown   mfd: wm831x: Conv...
434
  	res = platform_get_resource(pdev, IORESOURCE_REG, 0);
d1c6b4fe6   Mark Brown   regulator: Add WM...
435
  	if (res == NULL) {
5656098e1   Mark Brown   mfd: wm831x: Conv...
436
437
  		dev_err(&pdev->dev, "No REG resource
  ");
d1c6b4fe6   Mark Brown   regulator: Add WM...
438
439
440
441
442
443
444
  		ret = -EINVAL;
  		goto err;
  	}
  	ldo->base = res->start;
  
  	snprintf(ldo->name, sizeof(ldo->name), "LDO%d", id + 1);
  	ldo->desc.name = ldo->name;
f1aba13fb   Mark Brown   regulator: wm831x...
445
446
447
448
  
  	snprintf(ldo->supply_name, sizeof(ldo->supply_name),
  		 "LDO%dVDD", id + 1);
  	ldo->desc.supply_name = ldo->supply_name;
d1c6b4fe6   Mark Brown   regulator: Add WM...
449
450
  	ldo->desc.id = id;
  	ldo->desc.type = REGULATOR_VOLTAGE;
5ff26a14c   Mark Brown   regulator: wm831x...
451
452
453
  	ldo->desc.n_voltages = 32;
  	ldo->desc.linear_ranges = wm831x_aldo_ranges;
  	ldo->desc.n_linear_ranges = ARRAY_SIZE(wm831x_aldo_ranges);
d1c6b4fe6   Mark Brown   regulator: Add WM...
454
455
  	ldo->desc.ops = &wm831x_aldo_ops;
  	ldo->desc.owner = THIS_MODULE;
ac663b472   Mark Brown   regulator: wm831x...
456
457
  	ldo->desc.vsel_reg = ldo->base + WM831X_LDO_ON_CONTROL;
  	ldo->desc.vsel_mask = WM831X_LDO7_ON_VSEL_MASK;
ca8c361b4   Mark Brown   regulator: wm831x...
458
459
  	ldo->desc.enable_reg = WM831X_LDO_ENABLE;
  	ldo->desc.enable_mask = 1 << id;
22c5fb6a7   Mark Brown   regulator: wm831x...
460
461
  	ldo->desc.bypass_reg = ldo->base;
  	ldo->desc.bypass_mask = WM831X_LDO7_SWI;
d1c6b4fe6   Mark Brown   regulator: Add WM...
462

c172708d3   Mark Brown   regulator: core: ...
463
  	config.dev = pdev->dev.parent;
b7ca87884   Mark Brown   regulator: wm831x...
464
465
  	if (pdata)
  		config.init_data = pdata->ldo[id];
c172708d3   Mark Brown   regulator: core: ...
466
  	config.driver_data = ldo;
ac663b472   Mark Brown   regulator: wm831x...
467
  	config.regmap = wm831x->regmap;
c172708d3   Mark Brown   regulator: core: ...
468

fc7c60e39   Mark Brown   regulator: wm831x...
469
470
  	ldo->regulator = devm_regulator_register(&pdev->dev, &ldo->desc,
  						 &config);
d1c6b4fe6   Mark Brown   regulator: Add WM...
471
472
473
474
475
476
477
  	if (IS_ERR(ldo->regulator)) {
  		ret = PTR_ERR(ldo->regulator);
  		dev_err(wm831x->dev, "Failed to register LDO%d: %d
  ",
  			id + 1, ret);
  		goto err;
  	}
cd99758ba   Mark Brown   mfd: Convert wm83...
478
  	irq = wm831x_irq(wm831x, platform_get_irq_byname(pdev, "UV"));
41c7a879d   Mark Brown   regulator: wm831x...
479
480
  	ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
  					wm831x_ldo_uv_irq,
29454738f   Fabio Estevam   regulator: wm831x...
481
482
  					IRQF_TRIGGER_RISING | IRQF_ONESHOT,
  					ldo->name, ldo);
d1c6b4fe6   Mark Brown   regulator: Add WM...
483
484
485
486
  	if (ret != 0) {
  		dev_err(&pdev->dev, "Failed to request UV IRQ %d: %d
  ",
  			irq, ret);
fc7c60e39   Mark Brown   regulator: wm831x...
487
  		goto err;
d1c6b4fe6   Mark Brown   regulator: Add WM...
488
489
490
491
492
  	}
  
  	platform_set_drvdata(pdev, ldo);
  
  	return 0;
d1c6b4fe6   Mark Brown   regulator: Add WM...
493
  err:
d1c6b4fe6   Mark Brown   regulator: Add WM...
494
495
  	return ret;
  }
d1c6b4fe6   Mark Brown   regulator: Add WM...
496
497
  static struct platform_driver wm831x_aldo_driver = {
  	.probe = wm831x_aldo_probe,
d1c6b4fe6   Mark Brown   regulator: Add WM...
498
499
500
501
502
503
504
505
506
507
  	.driver		= {
  		.name	= "wm831x-aldo",
  	},
  };
  
  /*
   * Alive LDO
   */
  
  #define WM831X_ALIVE_LDO_MAX_SELECTOR 0xf
d1c6b4fe6   Mark Brown   regulator: Add WM...
508
509
510
511
  static int wm831x_alive_ldo_set_suspend_voltage(struct regulator_dev *rdev,
  					     int uV)
  {
  	struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
0a4796896   Axel Lin   regulator: wm831x...
512
513
514
515
516
517
  	struct wm831x *wm831x = ldo->wm831x;
  	int sel, reg = ldo->base + WM831X_ALIVE_LDO_SLEEP_CONTROL;
  
  	sel = regulator_map_voltage_linear(rdev, uV, uV);
  	if (sel < 0)
  		return sel;
d1c6b4fe6   Mark Brown   regulator: Add WM...
518

0a4796896   Axel Lin   regulator: wm831x...
519
  	return wm831x_set_bits(wm831x, reg, WM831X_LDO11_ON_VSEL_MASK, sel);
d1c6b4fe6   Mark Brown   regulator: Add WM...
520
  }
d1c6b4fe6   Mark Brown   regulator: Add WM...
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
  static int wm831x_alive_ldo_get_status(struct regulator_dev *rdev)
  {
  	struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
  	struct wm831x *wm831x = ldo->wm831x;
  	int mask = 1 << rdev_get_id(rdev);
  	int ret;
  
  	/* Is the regulator on? */
  	ret = wm831x_reg_read(wm831x, WM831X_LDO_STATUS);
  	if (ret < 0)
  		return ret;
  	if (ret & mask)
  		return REGULATOR_STATUS_ON;
  	else
  		return REGULATOR_STATUS_OFF;
  }
b0d6dd3ba   Julia Lawall   regulator: wm8*: ...
537
  static const struct regulator_ops wm831x_alive_ldo_ops = {
d31e954e0   Mark Brown   regulator: wm831x...
538
  	.list_voltage = regulator_list_voltage_linear,
c2543b5f6   Axel Lin   regulator: wm831x...
539
  	.map_voltage = regulator_map_voltage_linear,
ac663b472   Mark Brown   regulator: wm831x...
540
  	.get_voltage_sel = regulator_get_voltage_sel_regmap,
0a4796896   Axel Lin   regulator: wm831x...
541
  	.set_voltage_sel = regulator_set_voltage_sel_regmap,
d1c6b4fe6   Mark Brown   regulator: Add WM...
542
543
  	.set_suspend_voltage = wm831x_alive_ldo_set_suspend_voltage,
  	.get_status = wm831x_alive_ldo_get_status,
ca8c361b4   Mark Brown   regulator: wm831x...
544
545
546
  	.is_enabled = regulator_is_enabled_regmap,
  	.enable = regulator_enable_regmap,
  	.disable = regulator_disable_regmap,
d1c6b4fe6   Mark Brown   regulator: Add WM...
547
  };
a5023574d   Bill Pemberton   regulator: remove...
548
  static int wm831x_alive_ldo_probe(struct platform_device *pdev)
d1c6b4fe6   Mark Brown   regulator: Add WM...
549
550
  {
  	struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
dff91d0b7   Jingoo Han   regulator: use de...
551
  	struct wm831x_pdata *pdata = dev_get_platdata(wm831x->dev);
c172708d3   Mark Brown   regulator: core: ...
552
  	struct regulator_config config = { };
137a63543   Mark Brown   regulator: Fix WM...
553
  	int id;
d1c6b4fe6   Mark Brown   regulator: Add WM...
554
555
556
  	struct wm831x_ldo *ldo;
  	struct resource *res;
  	int ret;
137a63543   Mark Brown   regulator: Fix WM...
557
558
559
560
561
  	if (pdata && pdata->wm831x_num)
  		id = (pdata->wm831x_num * 10) + 1;
  	else
  		id = 0;
  	id = pdev->id - id;
d1c6b4fe6   Mark Brown   regulator: Add WM...
562
563
  	dev_dbg(&pdev->dev, "Probing LDO%d
  ", id + 1);
fded2f4fa   Mark Brown   regulator: Conver...
564
  	ldo = devm_kzalloc(&pdev->dev, sizeof(struct wm831x_ldo), GFP_KERNEL);
fae3b8364   Sachin Kamat   regulator: wm831x...
565
  	if (!ldo)
d1c6b4fe6   Mark Brown   regulator: Add WM...
566
  		return -ENOMEM;
d1c6b4fe6   Mark Brown   regulator: Add WM...
567
568
  
  	ldo->wm831x = wm831x;
5656098e1   Mark Brown   mfd: wm831x: Conv...
569
  	res = platform_get_resource(pdev, IORESOURCE_REG, 0);
d1c6b4fe6   Mark Brown   regulator: Add WM...
570
  	if (res == NULL) {
5656098e1   Mark Brown   mfd: wm831x: Conv...
571
572
  		dev_err(&pdev->dev, "No REG resource
  ");
d1c6b4fe6   Mark Brown   regulator: Add WM...
573
574
575
576
577
578
579
  		ret = -EINVAL;
  		goto err;
  	}
  	ldo->base = res->start;
  
  	snprintf(ldo->name, sizeof(ldo->name), "LDO%d", id + 1);
  	ldo->desc.name = ldo->name;
f1aba13fb   Mark Brown   regulator: wm831x...
580
581
582
583
  
  	snprintf(ldo->supply_name, sizeof(ldo->supply_name),
  		 "LDO%dVDD", id + 1);
  	ldo->desc.supply_name = ldo->supply_name;
d1c6b4fe6   Mark Brown   regulator: Add WM...
584
585
586
587
588
  	ldo->desc.id = id;
  	ldo->desc.type = REGULATOR_VOLTAGE;
  	ldo->desc.n_voltages = WM831X_ALIVE_LDO_MAX_SELECTOR + 1;
  	ldo->desc.ops = &wm831x_alive_ldo_ops;
  	ldo->desc.owner = THIS_MODULE;
ac663b472   Mark Brown   regulator: wm831x...
589
590
  	ldo->desc.vsel_reg = ldo->base + WM831X_ALIVE_LDO_ON_CONTROL;
  	ldo->desc.vsel_mask = WM831X_LDO11_ON_VSEL_MASK;
ca8c361b4   Mark Brown   regulator: wm831x...
591
592
  	ldo->desc.enable_reg = WM831X_LDO_ENABLE;
  	ldo->desc.enable_mask = 1 << id;
d31e954e0   Mark Brown   regulator: wm831x...
593
594
  	ldo->desc.min_uV = 800000;
  	ldo->desc.uV_step = 50000;
eefaa3c62   Mark Brown   regulator: wm831x...
595
  	ldo->desc.enable_time = 1000;
d1c6b4fe6   Mark Brown   regulator: Add WM...
596

c172708d3   Mark Brown   regulator: core: ...
597
  	config.dev = pdev->dev.parent;
b7ca87884   Mark Brown   regulator: wm831x...
598
599
  	if (pdata)
  		config.init_data = pdata->ldo[id];
c172708d3   Mark Brown   regulator: core: ...
600
  	config.driver_data = ldo;
ac663b472   Mark Brown   regulator: wm831x...
601
  	config.regmap = wm831x->regmap;
c172708d3   Mark Brown   regulator: core: ...
602

fc7c60e39   Mark Brown   regulator: wm831x...
603
604
  	ldo->regulator = devm_regulator_register(&pdev->dev, &ldo->desc,
  						 &config);
d1c6b4fe6   Mark Brown   regulator: Add WM...
605
606
607
608
609
610
611
612
613
614
615
616
617
  	if (IS_ERR(ldo->regulator)) {
  		ret = PTR_ERR(ldo->regulator);
  		dev_err(wm831x->dev, "Failed to register LDO%d: %d
  ",
  			id + 1, ret);
  		goto err;
  	}
  
  	platform_set_drvdata(pdev, ldo);
  
  	return 0;
  
  err:
d1c6b4fe6   Mark Brown   regulator: Add WM...
618
619
  	return ret;
  }
d1c6b4fe6   Mark Brown   regulator: Add WM...
620
621
  static struct platform_driver wm831x_alive_ldo_driver = {
  	.probe = wm831x_alive_ldo_probe,
d1c6b4fe6   Mark Brown   regulator: Add WM...
622
623
624
625
  	.driver		= {
  		.name	= "wm831x-alive-ldo",
  	},
  };
92a513b79   Thierry Reding   regulator: wm831x...
626
627
628
629
630
  static struct platform_driver * const drivers[] = {
  	&wm831x_gp_ldo_driver,
  	&wm831x_aldo_driver,
  	&wm831x_alive_ldo_driver,
  };
d1c6b4fe6   Mark Brown   regulator: Add WM...
631
632
  static int __init wm831x_ldo_init(void)
  {
92a513b79   Thierry Reding   regulator: wm831x...
633
  	return platform_register_drivers(drivers, ARRAY_SIZE(drivers));
d1c6b4fe6   Mark Brown   regulator: Add WM...
634
635
636
637
638
  }
  subsys_initcall(wm831x_ldo_init);
  
  static void __exit wm831x_ldo_exit(void)
  {
92a513b79   Thierry Reding   regulator: wm831x...
639
  	platform_unregister_drivers(drivers, ARRAY_SIZE(drivers));
d1c6b4fe6   Mark Brown   regulator: Add WM...
640
641
642
643
644
645
646
647
648
649
  }
  module_exit(wm831x_ldo_exit);
  
  /* Module information */
  MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
  MODULE_DESCRIPTION("WM831x LDO driver");
  MODULE_LICENSE("GPL");
  MODULE_ALIAS("platform:wm831x-ldo");
  MODULE_ALIAS("platform:wm831x-aldo");
  MODULE_ALIAS("platform:wm831x-aliveldo");