Blame view

drivers/mfd/wm8994-core.c 15.8 KB
9e5010866   Mark Brown   mfd: Add initial ...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
  /*
   * wm8994-core.c  --  Device access for Wolfson WM8994
   *
   * 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/kernel.h>
  #include <linux/module.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
17
  #include <linux/slab.h>
9e5010866   Mark Brown   mfd: Add initial ...
18
  #include <linux/i2c.h>
d6c645fc0   Mark Brown   mfd: Convert WM89...
19
  #include <linux/err.h>
9e5010866   Mark Brown   mfd: Add initial ...
20
21
  #include <linux/delay.h>
  #include <linux/mfd/core.h>
d450f19ee   Mark Brown   mfd: Implement ru...
22
  #include <linux/pm_runtime.h>
d6c645fc0   Mark Brown   mfd: Convert WM89...
23
  #include <linux/regmap.h>
9e5010866   Mark Brown   mfd: Add initial ...
24
25
26
27
28
29
  #include <linux/regulator/consumer.h>
  #include <linux/regulator/machine.h>
  
  #include <linux/mfd/wm8994/core.h>
  #include <linux/mfd/wm8994/pdata.h>
  #include <linux/mfd/wm8994/registers.h>
c3f138617   Mark Brown   mfd: Enable regis...
30
  #include "wm8994.h"
9e5010866   Mark Brown   mfd: Add initial ...
31
32
33
34
35
36
37
38
39
  
  /**
   * wm8994_reg_read: Read a single WM8994 register.
   *
   * @wm8994: Device to read from.
   * @reg: Register to read.
   */
  int wm8994_reg_read(struct wm8994 *wm8994, unsigned short reg)
  {
d6c645fc0   Mark Brown   mfd: Convert WM89...
40
  	unsigned int val;
9e5010866   Mark Brown   mfd: Add initial ...
41
  	int ret;
d6c645fc0   Mark Brown   mfd: Convert WM89...
42
  	ret = regmap_read(wm8994->regmap, reg, &val);
9e5010866   Mark Brown   mfd: Add initial ...
43
44
45
46
  
  	if (ret < 0)
  		return ret;
  	else
d6c645fc0   Mark Brown   mfd: Convert WM89...
47
  		return val;
9e5010866   Mark Brown   mfd: Add initial ...
48
49
50
51
52
53
54
55
56
  }
  EXPORT_SYMBOL_GPL(wm8994_reg_read);
  
  /**
   * wm8994_bulk_read: Read multiple WM8994 registers
   *
   * @wm8994: Device to read from
   * @reg: First register
   * @count: Number of registers
316b6cc08   Mark Brown   mfd: Push byte sw...
57
   * @buf: Buffer to fill.  The data will be returned big endian.
9e5010866   Mark Brown   mfd: Add initial ...
58
59
60
61
   */
  int wm8994_bulk_read(struct wm8994 *wm8994, unsigned short reg,
  		     int count, u16 *buf)
  {
d6c645fc0   Mark Brown   mfd: Convert WM89...
62
  	return regmap_bulk_read(wm8994->regmap, reg, buf, count);
9e5010866   Mark Brown   mfd: Add initial ...
63
  }
9e5010866   Mark Brown   mfd: Add initial ...
64

9e5010866   Mark Brown   mfd: Add initial ...
65
66
67
68
69
70
71
72
73
74
  /**
   * wm8994_reg_write: Write a single WM8994 register.
   *
   * @wm8994: Device to write to.
   * @reg: Register to write to.
   * @val: Value to write.
   */
  int wm8994_reg_write(struct wm8994 *wm8994, unsigned short reg,
  		     unsigned short val)
  {
d6c645fc0   Mark Brown   mfd: Convert WM89...
75
  	return regmap_write(wm8994->regmap, reg, val);
9e5010866   Mark Brown   mfd: Add initial ...
76
77
78
79
  }
  EXPORT_SYMBOL_GPL(wm8994_reg_write);
  
  /**
e93c53870   Mark Brown   mfd: Add WM8994 b...
80
81
82
83
84
   * wm8994_bulk_write: Write multiple WM8994 registers
   *
   * @wm8994: Device to write to
   * @reg: First register
   * @count: Number of registers
4277163c2   Mark Brown   mfd: Push byte sw...
85
   * @buf: Buffer to write from.  Data must be big-endian formatted.
e93c53870   Mark Brown   mfd: Add WM8994 b...
86
87
   */
  int wm8994_bulk_write(struct wm8994 *wm8994, unsigned short reg,
07e73fbb2   Mark Brown   mfd: Constify WM8...
88
  		      int count, const u16 *buf)
e93c53870   Mark Brown   mfd: Add WM8994 b...
89
  {
d6c645fc0   Mark Brown   mfd: Convert WM89...
90
  	return regmap_raw_write(wm8994->regmap, reg, buf, count * sizeof(u16));
e93c53870   Mark Brown   mfd: Add WM8994 b...
91
92
93
94
  }
  EXPORT_SYMBOL_GPL(wm8994_bulk_write);
  
  /**
9e5010866   Mark Brown   mfd: Add initial ...
95
96
97
98
99
100
101
102
103
104
   * wm8994_set_bits: Set the value of a bitfield in a WM8994 register
   *
   * @wm8994: Device to write to.
   * @reg: Register to write to.
   * @mask: Mask of bits to set.
   * @val: Value to set (unshifted)
   */
  int wm8994_set_bits(struct wm8994 *wm8994, unsigned short reg,
  		    unsigned short mask, unsigned short val)
  {
d6c645fc0   Mark Brown   mfd: Convert WM89...
105
  	return regmap_update_bits(wm8994->regmap, reg, mask, val);
9e5010866   Mark Brown   mfd: Add initial ...
106
107
108
109
  }
  EXPORT_SYMBOL_GPL(wm8994_set_bits);
  
  static struct mfd_cell wm8994_regulator_devs[] = {
d450f19ee   Mark Brown   mfd: Implement ru...
110
111
112
113
114
115
116
117
118
119
  	{
  		.name = "wm8994-ldo",
  		.id = 1,
  		.pm_runtime_no_callbacks = true,
  	},
  	{
  		.name = "wm8994-ldo",
  		.id = 2,
  		.pm_runtime_no_callbacks = true,
  	},
9e5010866   Mark Brown   mfd: Add initial ...
120
  };
c9fbf7e07   Mark Brown   mfd: Add WM8994 i...
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
  static struct resource wm8994_codec_resources[] = {
  	{
  		.start = WM8994_IRQ_TEMP_SHUT,
  		.end   = WM8994_IRQ_TEMP_WARN,
  		.flags = IORESOURCE_IRQ,
  	},
  };
  
  static struct resource wm8994_gpio_resources[] = {
  	{
  		.start = WM8994_IRQ_GPIO(1),
  		.end   = WM8994_IRQ_GPIO(11),
  		.flags = IORESOURCE_IRQ,
  	},
  };
9e5010866   Mark Brown   mfd: Add initial ...
136
  static struct mfd_cell wm8994_devs[] = {
c9fbf7e07   Mark Brown   mfd: Add WM8994 i...
137
138
139
140
141
142
143
144
145
146
  	{
  		.name = "wm8994-codec",
  		.num_resources = ARRAY_SIZE(wm8994_codec_resources),
  		.resources = wm8994_codec_resources,
  	},
  
  	{
  		.name = "wm8994-gpio",
  		.num_resources = ARRAY_SIZE(wm8994_gpio_resources),
  		.resources = wm8994_gpio_resources,
d450f19ee   Mark Brown   mfd: Implement ru...
147
  		.pm_runtime_no_callbacks = true,
c9fbf7e07   Mark Brown   mfd: Add WM8994 i...
148
  	},
9e5010866   Mark Brown   mfd: Add initial ...
149
150
151
152
153
154
155
  };
  
  /*
   * Supplies for the main bulk of CODEC; the LDO supplies are ignored
   * and should be handled via the standard regulator API supply
   * management.
   */
b1f43bf3a   Mark Brown   mfd: Add WM1811 s...
156
157
158
159
160
161
162
163
164
165
166
  static const char *wm1811_main_supplies[] = {
  	"DBVDD1",
  	"DBVDD2",
  	"DBVDD3",
  	"DCVDD",
  	"AVDD1",
  	"AVDD2",
  	"CPVDD",
  	"SPKVDD1",
  	"SPKVDD2",
  };
9e5010866   Mark Brown   mfd: Add initial ...
167
168
169
170
171
172
173
174
175
  static const char *wm8994_main_supplies[] = {
  	"DBVDD",
  	"DCVDD",
  	"AVDD1",
  	"AVDD2",
  	"CPVDD",
  	"SPKVDD1",
  	"SPKVDD2",
  };
559e0df6b   Mark Brown   mfd: Add initial ...
176
177
178
179
180
181
182
183
184
185
186
  static const char *wm8958_main_supplies[] = {
  	"DBVDD1",
  	"DBVDD2",
  	"DBVDD3",
  	"DCVDD",
  	"AVDD1",
  	"AVDD2",
  	"CPVDD",
  	"SPKVDD1",
  	"SPKVDD2",
  };
9e5010866   Mark Brown   mfd: Add initial ...
187
  #ifdef CONFIG_PM
d450f19ee   Mark Brown   mfd: Implement ru...
188
  static int wm8994_suspend(struct device *dev)
9e5010866   Mark Brown   mfd: Add initial ...
189
190
191
  {
  	struct wm8994 *wm8994 = dev_get_drvdata(dev);
  	int ret;
77bd70e90   Mark Brown   mfd: Don't suspen...
192
193
194
195
196
197
198
199
200
201
202
  	/* Don't actually go through with the suspend if the CODEC is
  	 * still active (eg, for audio passthrough from CP. */
  	ret = wm8994_reg_read(wm8994, WM8994_POWER_MANAGEMENT_1);
  	if (ret < 0) {
  		dev_err(dev, "Failed to read power status: %d
  ", ret);
  	} else if (ret & WM8994_VMID_SEL_MASK) {
  		dev_dbg(dev, "CODEC still active, ignoring suspend
  ");
  		return 0;
  	}
5f40c6b65   Mark Brown   mfd: Add more che...
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
  	ret = wm8994_reg_read(wm8994, WM8994_POWER_MANAGEMENT_4);
  	if (ret < 0) {
  		dev_err(dev, "Failed to read power status: %d
  ", ret);
  	} else if (ret & (WM8994_AIF2ADCL_ENA | WM8994_AIF2ADCR_ENA |
  			  WM8994_AIF1ADC2L_ENA | WM8994_AIF1ADC2R_ENA |
  			  WM8994_AIF1ADC1L_ENA | WM8994_AIF1ADC1R_ENA)) {
  		dev_dbg(dev, "CODEC still active, ignoring suspend
  ");
  		return 0;
  	}
  
  	ret = wm8994_reg_read(wm8994, WM8994_POWER_MANAGEMENT_5);
  	if (ret < 0) {
  		dev_err(dev, "Failed to read power status: %d
  ", ret);
  	} else if (ret & (WM8994_AIF2DACL_ENA | WM8994_AIF2DACR_ENA |
  			  WM8994_AIF1DAC2L_ENA | WM8994_AIF1DAC2R_ENA |
  			  WM8994_AIF1DAC1L_ENA | WM8994_AIF1DAC1R_ENA)) {
  		dev_dbg(dev, "CODEC still active, ignoring suspend
  ");
  		return 0;
  	}
  
  	switch (wm8994->type) {
  	case WM8958:
b5488b6e8   Mark Brown   mfd: Update wm899...
229
  	case WM1811:
5f40c6b65   Mark Brown   mfd: Add more che...
230
231
232
233
234
235
236
237
238
239
240
241
242
  		ret = wm8994_reg_read(wm8994, WM8958_MIC_DETECT_1);
  		if (ret < 0) {
  			dev_err(dev, "Failed to read power status: %d
  ", ret);
  		} else if (ret & WM8958_MICD_ENA) {
  			dev_dbg(dev, "CODEC still active, ignoring suspend
  ");
  			return 0;
  		}
  		break;
  	default:
  		break;
  	}
a3462490b   Mark Brown   mfd: Test for jac...
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
  	switch (wm8994->type) {
  	case WM1811:
  		ret = wm8994_reg_read(wm8994, WM8994_ANTIPOP_2);
  		if (ret < 0) {
  			dev_err(dev, "Failed to read jackdet: %d
  ", ret);
  		} else if (ret & WM1811_JACKDET_MODE_MASK) {
  			dev_dbg(dev, "CODEC still active, ignoring suspend
  ");
  			return 0;
  		}
  		break;
  	default:
  		break;
  	}
881de6704   Mark Brown   mfd: Allow WM8994...
258
259
260
261
262
263
  	/* Disable LDO pulldowns while the device is suspended if we
  	 * don't know that something will be driving them. */
  	if (!wm8994->ldo_ena_always_driven)
  		wm8994_set_bits(wm8994, WM8994_PULL_CONTROL_2,
  				WM8994_LDO1ENA_PD | WM8994_LDO2ENA_PD,
  				WM8994_LDO1ENA_PD | WM8994_LDO2ENA_PD);
f40dff9ed   Mark Brown   mfd: Put WM8994 i...
264
265
266
  	/* Explicitly put the device into reset in case regulators
  	 * don't get disabled in order to ensure consistent restart.
  	 */
be79cf2fd   Mark Brown   mfd: Don't hard c...
267
268
  	wm8994_reg_write(wm8994, WM8994_SOFTWARE_RESET,
  			 wm8994_reg_read(wm8994, WM8994_SOFTWARE_RESET));
f40dff9ed   Mark Brown   mfd: Put WM8994 i...
269

3befc925c   Mark Brown   mfd: Put WM8994 i...
270
  	regcache_cache_only(wm8994->regmap, true);
c3f138617   Mark Brown   mfd: Enable regis...
271
  	regcache_mark_dirty(wm8994->regmap);
f40dff9ed   Mark Brown   mfd: Put WM8994 i...
272

77bd70e90   Mark Brown   mfd: Don't suspen...
273
  	wm8994->suspended = true;
559e0df6b   Mark Brown   mfd: Add initial ...
274
  	ret = regulator_bulk_disable(wm8994->num_supplies,
9e5010866   Mark Brown   mfd: Add initial ...
275
276
277
278
279
280
281
282
283
  				     wm8994->supplies);
  	if (ret != 0) {
  		dev_err(dev, "Failed to disable supplies: %d
  ", ret);
  		return ret;
  	}
  
  	return 0;
  }
d450f19ee   Mark Brown   mfd: Implement ru...
284
  static int wm8994_resume(struct device *dev)
9e5010866   Mark Brown   mfd: Add initial ...
285
286
  {
  	struct wm8994 *wm8994 = dev_get_drvdata(dev);
c3f138617   Mark Brown   mfd: Enable regis...
287
  	int ret;
9e5010866   Mark Brown   mfd: Add initial ...
288

77bd70e90   Mark Brown   mfd: Don't suspen...
289
290
291
  	/* We may have lied to the PM core about suspending */
  	if (!wm8994->suspended)
  		return 0;
559e0df6b   Mark Brown   mfd: Add initial ...
292
  	ret = regulator_bulk_enable(wm8994->num_supplies,
9e5010866   Mark Brown   mfd: Add initial ...
293
294
295
296
297
298
  				    wm8994->supplies);
  	if (ret != 0) {
  		dev_err(dev, "Failed to enable supplies: %d
  ", ret);
  		return ret;
  	}
3befc925c   Mark Brown   mfd: Put WM8994 i...
299
  	regcache_cache_only(wm8994->regmap, false);
c3f138617   Mark Brown   mfd: Enable regis...
300
301
302
303
304
  	ret = regcache_sync(wm8994->regmap);
  	if (ret != 0) {
  		dev_err(dev, "Failed to restore register map: %d
  ", ret);
  		goto err_enable;
98ae1ccaf   Mark Brown   mfd: Fix WM8994 I...
305
  	}
c9fbf7e07   Mark Brown   mfd: Add WM8994 i...
306

881de6704   Mark Brown   mfd: Allow WM8994...
307
308
309
310
  	/* Disable LDO pulldowns while the device is active */
  	wm8994_set_bits(wm8994, WM8994_PULL_CONTROL_2,
  			WM8994_LDO1ENA_PD | WM8994_LDO2ENA_PD,
  			0);
77bd70e90   Mark Brown   mfd: Don't suspen...
311
  	wm8994->suspended = false;
9e5010866   Mark Brown   mfd: Add initial ...
312
  	return 0;
c3f138617   Mark Brown   mfd: Enable regis...
313
314
315
316
317
  
  err_enable:
  	regulator_bulk_disable(wm8994->num_supplies, wm8994->supplies);
  
  	return ret;
9e5010866   Mark Brown   mfd: Add initial ...
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
  }
  #endif
  
  #ifdef CONFIG_REGULATOR
  static int wm8994_ldo_in_use(struct wm8994_pdata *pdata, int ldo)
  {
  	struct wm8994_ldo_pdata *ldo_pdata;
  
  	if (!pdata)
  		return 0;
  
  	ldo_pdata = &pdata->ldo[ldo];
  
  	if (!ldo_pdata->init_data)
  		return 0;
  
  	return ldo_pdata->init_data->num_consumer_supplies != 0;
  }
  #else
  static int wm8994_ldo_in_use(struct wm8994_pdata *pdata, int ldo)
  {
  	return 0;
  }
  #endif
  
  /*
   * Instantiate the generic non-control parts of the device.
   */
559e0df6b   Mark Brown   mfd: Add initial ...
346
  static int wm8994_device_init(struct wm8994 *wm8994, int irq)
9e5010866   Mark Brown   mfd: Add initial ...
347
348
  {
  	struct wm8994_pdata *pdata = wm8994->dev->platform_data;
346978980   Mark Brown   mfd: Initialise W...
349
  	struct regmap_config *regmap_config;
559e0df6b   Mark Brown   mfd: Add initial ...
350
  	const char *devname;
9e5010866   Mark Brown   mfd: Add initial ...
351
  	int ret, i;
26c34c25e   Mark Brown   mfd: Disable more...
352
  	int pulls = 0;
9e5010866   Mark Brown   mfd: Add initial ...
353

9e5010866   Mark Brown   mfd: Add initial ...
354
355
356
357
358
359
360
361
362
363
  	dev_set_drvdata(wm8994->dev, wm8994);
  
  	/* Add the on-chip regulators first for bootstrapping */
  	ret = mfd_add_devices(wm8994->dev, -1,
  			      wm8994_regulator_devs,
  			      ARRAY_SIZE(wm8994_regulator_devs),
  			      NULL, 0);
  	if (ret != 0) {
  		dev_err(wm8994->dev, "Failed to add children: %d
  ", ret);
d6c645fc0   Mark Brown   mfd: Convert WM89...
364
  		goto err_regmap;
9e5010866   Mark Brown   mfd: Add initial ...
365
  	}
559e0df6b   Mark Brown   mfd: Add initial ...
366
  	switch (wm8994->type) {
b1f43bf3a   Mark Brown   mfd: Add WM1811 s...
367
368
369
  	case WM1811:
  		wm8994->num_supplies = ARRAY_SIZE(wm1811_main_supplies);
  		break;
559e0df6b   Mark Brown   mfd: Add initial ...
370
371
372
373
374
375
376
377
  	case WM8994:
  		wm8994->num_supplies = ARRAY_SIZE(wm8994_main_supplies);
  		break;
  	case WM8958:
  		wm8994->num_supplies = ARRAY_SIZE(wm8958_main_supplies);
  		break;
  	default:
  		BUG();
d6c645fc0   Mark Brown   mfd: Convert WM89...
378
  		goto err_regmap;
559e0df6b   Mark Brown   mfd: Add initial ...
379
  	}
2fa334946   Mark Brown   mfd: Convert wm89...
380
381
382
  	wm8994->supplies = devm_kzalloc(wm8994->dev,
  					sizeof(struct regulator_bulk_data) *
  					wm8994->num_supplies, GFP_KERNEL);
fccbd21f3   Axel Lin   mfd: Fix wm8994_d...
383
384
  	if (!wm8994->supplies) {
  		ret = -ENOMEM;
d6c645fc0   Mark Brown   mfd: Convert WM89...
385
  		goto err_regmap;
fccbd21f3   Axel Lin   mfd: Fix wm8994_d...
386
  	}
9e5010866   Mark Brown   mfd: Add initial ...
387

559e0df6b   Mark Brown   mfd: Add initial ...
388
  	switch (wm8994->type) {
b1f43bf3a   Mark Brown   mfd: Add WM1811 s...
389
390
391
392
  	case WM1811:
  		for (i = 0; i < ARRAY_SIZE(wm1811_main_supplies); i++)
  			wm8994->supplies[i].supply = wm1811_main_supplies[i];
  		break;
559e0df6b   Mark Brown   mfd: Add initial ...
393
394
395
396
397
398
399
400
401
402
  	case WM8994:
  		for (i = 0; i < ARRAY_SIZE(wm8994_main_supplies); i++)
  			wm8994->supplies[i].supply = wm8994_main_supplies[i];
  		break;
  	case WM8958:
  		for (i = 0; i < ARRAY_SIZE(wm8958_main_supplies); i++)
  			wm8994->supplies[i].supply = wm8958_main_supplies[i];
  		break;
  	default:
  		BUG();
d6c645fc0   Mark Brown   mfd: Convert WM89...
403
  		goto err_regmap;
559e0df6b   Mark Brown   mfd: Add initial ...
404
405
406
  	}
  		
  	ret = regulator_bulk_get(wm8994->dev, wm8994->num_supplies,
9e5010866   Mark Brown   mfd: Add initial ...
407
408
409
410
  				 wm8994->supplies);
  	if (ret != 0) {
  		dev_err(wm8994->dev, "Failed to get supplies: %d
  ", ret);
2fa334946   Mark Brown   mfd: Convert wm89...
411
  		goto err_regmap;
9e5010866   Mark Brown   mfd: Add initial ...
412
  	}
559e0df6b   Mark Brown   mfd: Add initial ...
413
  	ret = regulator_bulk_enable(wm8994->num_supplies,
9e5010866   Mark Brown   mfd: Add initial ...
414
415
416
417
  				    wm8994->supplies);
  	if (ret != 0) {
  		dev_err(wm8994->dev, "Failed to enable supplies: %d
  ", ret);
7731074ab   Joonyoung Shim   mfd: Fix WM8994 e...
418
  		goto err_get;
9e5010866   Mark Brown   mfd: Add initial ...
419
420
421
422
423
424
425
426
  	}
  
  	ret = wm8994_reg_read(wm8994, WM8994_SOFTWARE_RESET);
  	if (ret < 0) {
  		dev_err(wm8994->dev, "Failed to read ID register
  ");
  		goto err_enable;
  	}
559e0df6b   Mark Brown   mfd: Add initial ...
427
  	switch (ret) {
b1f43bf3a   Mark Brown   mfd: Add WM1811 s...
428
429
430
431
432
433
434
435
  	case 0x1811:
  		devname = "WM1811";
  		if (wm8994->type != WM1811)
  			dev_warn(wm8994->dev, "Device registered as type %d
  ",
  				 wm8994->type);
  		wm8994->type = WM1811;
  		break;
559e0df6b   Mark Brown   mfd: Add initial ...
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
  	case 0x8994:
  		devname = "WM8994";
  		if (wm8994->type != WM8994)
  			dev_warn(wm8994->dev, "Device registered as type %d
  ",
  				 wm8994->type);
  		wm8994->type = WM8994;
  		break;
  	case 0x8958:
  		devname = "WM8958";
  		if (wm8994->type != WM8958)
  			dev_warn(wm8994->dev, "Device registered as type %d
  ",
  				 wm8994->type);
  		wm8994->type = WM8958;
  		break;
  	default:
9e5010866   Mark Brown   mfd: Add initial ...
453
454
455
456
457
458
459
460
461
462
463
464
465
466
  		dev_err(wm8994->dev, "Device is not a WM8994, ID is %x
  ",
  			ret);
  		ret = -EINVAL;
  		goto err_enable;
  	}
  
  	ret = wm8994_reg_read(wm8994, WM8994_CHIP_REVISION);
  	if (ret < 0) {
  		dev_err(wm8994->dev, "Failed to read revision register: %d
  ",
  			ret);
  		goto err_enable;
  	}
7ed5849c2   Mark Brown   mfd: Mark WM1811 ...
467
  	wm8994->revision = ret;
9e5010866   Mark Brown   mfd: Add initial ...
468

a2495bc72   Mark Brown   mfd: Restructure ...
469
470
  	switch (wm8994->type) {
  	case WM8994:
7ed5849c2   Mark Brown   mfd: Mark WM1811 ...
471
  		switch (wm8994->revision) {
a2495bc72   Mark Brown   mfd: Restructure ...
472
473
  		case 0:
  		case 1:
559e0df6b   Mark Brown   mfd: Add initial ...
474
475
476
  			dev_warn(wm8994->dev,
  				 "revision %c not fully supported
  ",
7ed5849c2   Mark Brown   mfd: Mark WM1811 ...
477
  				 'A' + wm8994->revision);
a2495bc72   Mark Brown   mfd: Restructure ...
478
479
480
481
  			break;
  		default:
  			break;
  		}
9e5010866   Mark Brown   mfd: Add initial ...
482
  		break;
443e67ed8   Mark Brown   mfd: Correct revi...
483
484
  	case WM1811:
  		/* Revision C did not change the relevant layer */
7ed5849c2   Mark Brown   mfd: Mark WM1811 ...
485
486
  		if (wm8994->revision > 1)
  			wm8994->revision++;
443e67ed8   Mark Brown   mfd: Correct revi...
487
  		break;
9e5010866   Mark Brown   mfd: Add initial ...
488
  	default:
9e5010866   Mark Brown   mfd: Add initial ...
489
490
  		break;
  	}
7ed5849c2   Mark Brown   mfd: Mark WM1811 ...
491
492
493
  	dev_info(wm8994->dev, "%s revision %c
  ", devname,
  		 'A' + wm8994->revision);
9e5010866   Mark Brown   mfd: Add initial ...
494

346978980   Mark Brown   mfd: Initialise W...
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
  	switch (wm8994->type) {
  	case WM1811:
  		regmap_config = &wm1811_regmap_config;
  		break;
  	case WM8994:
  		regmap_config = &wm8994_regmap_config;
  		break;
  	case WM8958:
  		regmap_config = &wm8958_regmap_config;
  		break;
  	default:
  		dev_err(wm8994->dev, "Unknown device type %d
  ", wm8994->type);
  		return -EINVAL;
  	}
  
  	ret = regmap_reinit_cache(wm8994->regmap, regmap_config);
  	if (ret != 0) {
  		dev_err(wm8994->dev, "Failed to reinit register cache: %d
  ",
  			ret);
  		return ret;
  	}
9e5010866   Mark Brown   mfd: Add initial ...
518
519
  
  	if (pdata) {
c9fbf7e07   Mark Brown   mfd: Add WM8994 i...
520
  		wm8994->irq_base = pdata->irq_base;
9e5010866   Mark Brown   mfd: Add initial ...
521
522
523
524
525
526
527
528
529
530
  		wm8994->gpio_base = pdata->gpio_base;
  
  		/* GPIO configuration is only applied if it's non-zero */
  		for (i = 0; i < ARRAY_SIZE(pdata->gpio_defaults); i++) {
  			if (pdata->gpio_defaults[i]) {
  				wm8994_set_bits(wm8994, WM8994_GPIO_1 + i,
  						0xffff,
  						pdata->gpio_defaults[i]);
  			}
  		}
881de6704   Mark Brown   mfd: Allow WM8994...
531
532
  
  		wm8994->ldo_ena_always_driven = pdata->ldo_ena_always_driven;
26c34c25e   Mark Brown   mfd: Disable more...
533
534
535
  
  		if (pdata->spkmode_pu)
  			pulls |= WM8994_SPKMODE_PU;
9e5010866   Mark Brown   mfd: Add initial ...
536
  	}
26c34c25e   Mark Brown   mfd: Disable more...
537
  	/* Disable unneeded pulls */
881de6704   Mark Brown   mfd: Allow WM8994...
538
  	wm8994_set_bits(wm8994, WM8994_PULL_CONTROL_2,
26c34c25e   Mark Brown   mfd: Disable more...
539
540
541
  			WM8994_LDO1ENA_PD | WM8994_LDO2ENA_PD |
  			WM8994_SPKMODE_PU | WM8994_CSNADDR_PD,
  			pulls);
881de6704   Mark Brown   mfd: Allow WM8994...
542

9e5010866   Mark Brown   mfd: Add initial ...
543
544
545
546
547
548
549
550
551
552
553
554
555
556
  	/* In some system designs where the regulators are not in use,
  	 * we can achieve a small reduction in leakage currents by
  	 * floating LDO outputs.  This bit makes no difference if the
  	 * LDOs are enabled, it only affects cases where the LDOs were
  	 * in operation and are then disabled.
  	 */
  	for (i = 0; i < WM8994_NUM_LDO_REGS; i++) {
  		if (wm8994_ldo_in_use(pdata, i))
  			wm8994_set_bits(wm8994, WM8994_LDO_1 + i,
  					WM8994_LDO1_DISCH, WM8994_LDO1_DISCH);
  		else
  			wm8994_set_bits(wm8994, WM8994_LDO_1 + i,
  					WM8994_LDO1_DISCH, 0);
  	}
c9fbf7e07   Mark Brown   mfd: Add WM8994 i...
557
  	wm8994_irq_init(wm8994);
9e5010866   Mark Brown   mfd: Add initial ...
558
559
560
561
562
563
  	ret = mfd_add_devices(wm8994->dev, -1,
  			      wm8994_devs, ARRAY_SIZE(wm8994_devs),
  			      NULL, 0);
  	if (ret != 0) {
  		dev_err(wm8994->dev, "Failed to add children: %d
  ", ret);
c9fbf7e07   Mark Brown   mfd: Add WM8994 i...
564
  		goto err_irq;
9e5010866   Mark Brown   mfd: Add initial ...
565
  	}
d450f19ee   Mark Brown   mfd: Implement ru...
566
567
  	pm_runtime_enable(wm8994->dev);
  	pm_runtime_resume(wm8994->dev);
9e5010866   Mark Brown   mfd: Add initial ...
568
  	return 0;
c9fbf7e07   Mark Brown   mfd: Add WM8994 i...
569
570
  err_irq:
  	wm8994_irq_exit(wm8994);
9e5010866   Mark Brown   mfd: Add initial ...
571
  err_enable:
559e0df6b   Mark Brown   mfd: Add initial ...
572
  	regulator_bulk_disable(wm8994->num_supplies,
9e5010866   Mark Brown   mfd: Add initial ...
573
574
  			       wm8994->supplies);
  err_get:
559e0df6b   Mark Brown   mfd: Add initial ...
575
  	regulator_bulk_free(wm8994->num_supplies, wm8994->supplies);
d6c645fc0   Mark Brown   mfd: Convert WM89...
576
577
  err_regmap:
  	regmap_exit(wm8994->regmap);
9e5010866   Mark Brown   mfd: Add initial ...
578
  	mfd_remove_devices(wm8994->dev);
9e5010866   Mark Brown   mfd: Add initial ...
579
580
581
582
583
  	return ret;
  }
  
  static void wm8994_device_exit(struct wm8994 *wm8994)
  {
d450f19ee   Mark Brown   mfd: Implement ru...
584
  	pm_runtime_disable(wm8994->dev);
9e5010866   Mark Brown   mfd: Add initial ...
585
  	mfd_remove_devices(wm8994->dev);
c9fbf7e07   Mark Brown   mfd: Add WM8994 i...
586
  	wm8994_irq_exit(wm8994);
559e0df6b   Mark Brown   mfd: Add initial ...
587
  	regulator_bulk_disable(wm8994->num_supplies,
9e5010866   Mark Brown   mfd: Add initial ...
588
  			       wm8994->supplies);
559e0df6b   Mark Brown   mfd: Add initial ...
589
  	regulator_bulk_free(wm8994->num_supplies, wm8994->supplies);
d6c645fc0   Mark Brown   mfd: Convert WM89...
590
  	regmap_exit(wm8994->regmap);
9e5010866   Mark Brown   mfd: Add initial ...
591
  }
cf763c2e6   Mark Brown   mfd: Add basic de...
592
593
594
595
596
597
598
  static const struct of_device_id wm8994_of_match[] = {
  	{ .compatible = "wlf,wm1811", },
  	{ .compatible = "wlf,wm8994", },
  	{ .compatible = "wlf,wm8958", },
  	{ }
  };
  MODULE_DEVICE_TABLE(of, wm8994_of_match);
9e5010866   Mark Brown   mfd: Add initial ...
599
600
601
602
  static int wm8994_i2c_probe(struct i2c_client *i2c,
  			    const struct i2c_device_id *id)
  {
  	struct wm8994 *wm8994;
d6c645fc0   Mark Brown   mfd: Convert WM89...
603
  	int ret;
9e5010866   Mark Brown   mfd: Add initial ...
604

2fa334946   Mark Brown   mfd: Convert wm89...
605
  	wm8994 = devm_kzalloc(&i2c->dev, sizeof(struct wm8994), GFP_KERNEL);
d0a116939   Axel Lin   mfd: Fix incorrec...
606
  	if (wm8994 == NULL)
9e5010866   Mark Brown   mfd: Add initial ...
607
  		return -ENOMEM;
9e5010866   Mark Brown   mfd: Add initial ...
608
609
610
  
  	i2c_set_clientdata(i2c, wm8994);
  	wm8994->dev = &i2c->dev;
c9fbf7e07   Mark Brown   mfd: Add WM8994 i...
611
  	wm8994->irq = i2c->irq;
559e0df6b   Mark Brown   mfd: Add initial ...
612
  	wm8994->type = id->driver_data;
9e5010866   Mark Brown   mfd: Add initial ...
613

346978980   Mark Brown   mfd: Initialise W...
614
  	wm8994->regmap = regmap_init_i2c(i2c, &wm8994_base_regmap_config);
d6c645fc0   Mark Brown   mfd: Convert WM89...
615
616
617
618
619
  	if (IS_ERR(wm8994->regmap)) {
  		ret = PTR_ERR(wm8994->regmap);
  		dev_err(wm8994->dev, "Failed to allocate register map: %d
  ",
  			ret);
d6c645fc0   Mark Brown   mfd: Convert WM89...
620
621
  		return ret;
  	}
559e0df6b   Mark Brown   mfd: Add initial ...
622
  	return wm8994_device_init(wm8994, i2c->irq);
9e5010866   Mark Brown   mfd: Add initial ...
623
624
625
626
627
628
629
630
631
632
  }
  
  static int wm8994_i2c_remove(struct i2c_client *i2c)
  {
  	struct wm8994 *wm8994 = i2c_get_clientdata(i2c);
  
  	wm8994_device_exit(wm8994);
  
  	return 0;
  }
9e5010866   Mark Brown   mfd: Add initial ...
633
  static const struct i2c_device_id wm8994_i2c_id[] = {
b1f43bf3a   Mark Brown   mfd: Add WM1811 s...
634
  	{ "wm1811", WM1811 },
71d171847   Mark Brown   mfd: Add WM1811A ...
635
  	{ "wm1811a", WM1811 },
559e0df6b   Mark Brown   mfd: Add initial ...
636
637
  	{ "wm8994", WM8994 },
  	{ "wm8958", WM8958 },
9e5010866   Mark Brown   mfd: Add initial ...
638
639
640
  	{ }
  };
  MODULE_DEVICE_TABLE(i2c, wm8994_i2c_id);
aad343107   Mark Brown   mfd: Staticise WM...
641
642
  static UNIVERSAL_DEV_PM_OPS(wm8994_pm_ops, wm8994_suspend, wm8994_resume,
  			    NULL);
d450f19ee   Mark Brown   mfd: Implement ru...
643

9e5010866   Mark Brown   mfd: Add initial ...
644
645
  static struct i2c_driver wm8994_i2c_driver = {
  	.driver = {
d450f19ee   Mark Brown   mfd: Implement ru...
646
647
648
  		.name = "wm8994",
  		.owner = THIS_MODULE,
  		.pm = &wm8994_pm_ops,
cf763c2e6   Mark Brown   mfd: Add basic de...
649
  		.of_match_table = wm8994_of_match,
9e5010866   Mark Brown   mfd: Add initial ...
650
651
652
  	},
  	.probe = wm8994_i2c_probe,
  	.remove = wm8994_i2c_remove,
9e5010866   Mark Brown   mfd: Add initial ...
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
  	.id_table = wm8994_i2c_id,
  };
  
  static int __init wm8994_i2c_init(void)
  {
  	int ret;
  
  	ret = i2c_add_driver(&wm8994_i2c_driver);
  	if (ret != 0)
  		pr_err("Failed to register wm8994 I2C driver: %d
  ", ret);
  
  	return ret;
  }
  module_init(wm8994_i2c_init);
  
  static void __exit wm8994_i2c_exit(void)
  {
  	i2c_del_driver(&wm8994_i2c_driver);
  }
  module_exit(wm8994_i2c_exit);
  
  MODULE_DESCRIPTION("Core support for the WM8994 audio CODEC");
  MODULE_LICENSE("GPL");
  MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");