xref: /openbmc/linux/sound/soc/codecs/wm8804.c (revision 034f90b3)
1 /*
2  * wm8804.c  --  WM8804 S/PDIF transceiver driver
3  *
4  * Copyright 2010-11 Wolfson Microelectronics plc
5  *
6  * Author: Dimitris Papastamos <dp@opensource.wolfsonmicro.com>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 as
10  * published by the Free Software Foundation.
11  */
12 
13 #include <linux/module.h>
14 #include <linux/moduleparam.h>
15 #include <linux/init.h>
16 #include <linux/delay.h>
17 #include <linux/pm.h>
18 #include <linux/of_device.h>
19 #include <linux/regulator/consumer.h>
20 #include <linux/slab.h>
21 #include <sound/core.h>
22 #include <sound/pcm.h>
23 #include <sound/pcm_params.h>
24 #include <sound/soc.h>
25 #include <sound/initval.h>
26 #include <sound/tlv.h>
27 
28 #include "wm8804.h"
29 
30 #define WM8804_NUM_SUPPLIES 2
31 static const char *wm8804_supply_names[WM8804_NUM_SUPPLIES] = {
32 	"PVDD",
33 	"DVDD"
34 };
35 
36 static const struct reg_default wm8804_reg_defaults[] = {
37 	{ 3,  0x21 },     /* R3  - PLL1 */
38 	{ 4,  0xFD },     /* R4  - PLL2 */
39 	{ 5,  0x36 },     /* R5  - PLL3 */
40 	{ 6,  0x07 },     /* R6  - PLL4 */
41 	{ 7,  0x16 },     /* R7  - PLL5 */
42 	{ 8,  0x18 },     /* R8  - PLL6 */
43 	{ 9,  0xFF },     /* R9  - SPDMODE */
44 	{ 10, 0x00 },     /* R10 - INTMASK */
45 	{ 18, 0x00 },     /* R18 - SPDTX1 */
46 	{ 19, 0x00 },     /* R19 - SPDTX2 */
47 	{ 20, 0x00 },     /* R20 - SPDTX3 */
48 	{ 21, 0x71 },     /* R21 - SPDTX4 */
49 	{ 22, 0x0B },     /* R22 - SPDTX5 */
50 	{ 23, 0x70 },     /* R23 - GPO0 */
51 	{ 24, 0x57 },     /* R24 - GPO1 */
52 	{ 26, 0x42 },     /* R26 - GPO2 */
53 	{ 27, 0x06 },     /* R27 - AIFTX */
54 	{ 28, 0x06 },     /* R28 - AIFRX */
55 	{ 29, 0x80 },     /* R29 - SPDRX1 */
56 	{ 30, 0x07 },     /* R30 - PWRDN */
57 };
58 
59 struct wm8804_priv {
60 	struct regmap *regmap;
61 	struct regulator_bulk_data supplies[WM8804_NUM_SUPPLIES];
62 	struct notifier_block disable_nb[WM8804_NUM_SUPPLIES];
63 	int mclk_div;
64 };
65 
66 static int txsrc_get(struct snd_kcontrol *kcontrol,
67 		     struct snd_ctl_elem_value *ucontrol);
68 
69 static int txsrc_put(struct snd_kcontrol *kcontrol,
70 		     struct snd_ctl_elem_value *ucontrol);
71 
72 /*
73  * We can't use the same notifier block for more than one supply and
74  * there's no way I can see to get from a callback to the caller
75  * except container_of().
76  */
77 #define WM8804_REGULATOR_EVENT(n) \
78 static int wm8804_regulator_event_##n(struct notifier_block *nb, \
79 				      unsigned long event, void *data)    \
80 { \
81 	struct wm8804_priv *wm8804 = container_of(nb, struct wm8804_priv, \
82 						  disable_nb[n]); \
83 	if (event & REGULATOR_EVENT_DISABLE) { \
84 		regcache_mark_dirty(wm8804->regmap);	\
85 	} \
86 	return 0; \
87 }
88 
89 WM8804_REGULATOR_EVENT(0)
90 WM8804_REGULATOR_EVENT(1)
91 
92 static const char *txsrc_text[] = { "S/PDIF RX", "AIF" };
93 static SOC_ENUM_SINGLE_EXT_DECL(txsrc, txsrc_text);
94 
95 static const struct snd_kcontrol_new wm8804_snd_controls[] = {
96 	SOC_ENUM_EXT("Input Source", txsrc, txsrc_get, txsrc_put),
97 	SOC_SINGLE("TX Playback Switch", WM8804_PWRDN, 2, 1, 1),
98 	SOC_SINGLE("AIF Playback Switch", WM8804_PWRDN, 4, 1, 1)
99 };
100 
101 static int txsrc_get(struct snd_kcontrol *kcontrol,
102 		     struct snd_ctl_elem_value *ucontrol)
103 {
104 	struct snd_soc_codec *codec;
105 	unsigned int src;
106 
107 	codec = snd_soc_kcontrol_codec(kcontrol);
108 	src = snd_soc_read(codec, WM8804_SPDTX4);
109 	if (src & 0x40)
110 		ucontrol->value.integer.value[0] = 1;
111 	else
112 		ucontrol->value.integer.value[0] = 0;
113 
114 	return 0;
115 }
116 
117 static int txsrc_put(struct snd_kcontrol *kcontrol,
118 		     struct snd_ctl_elem_value *ucontrol)
119 {
120 	struct snd_soc_codec *codec;
121 	unsigned int src, txpwr;
122 
123 	codec = snd_soc_kcontrol_codec(kcontrol);
124 
125 	if (ucontrol->value.integer.value[0] != 0
126 			&& ucontrol->value.integer.value[0] != 1)
127 		return -EINVAL;
128 
129 	src = snd_soc_read(codec, WM8804_SPDTX4);
130 	switch ((src & 0x40) >> 6) {
131 	case 0:
132 		if (!ucontrol->value.integer.value[0])
133 			return 0;
134 		break;
135 	case 1:
136 		if (ucontrol->value.integer.value[1])
137 			return 0;
138 		break;
139 	}
140 
141 	/* save the current power state of the transmitter */
142 	txpwr = snd_soc_read(codec, WM8804_PWRDN) & 0x4;
143 	/* power down the transmitter */
144 	snd_soc_update_bits(codec, WM8804_PWRDN, 0x4, 0x4);
145 	/* set the tx source */
146 	snd_soc_update_bits(codec, WM8804_SPDTX4, 0x40,
147 			    ucontrol->value.integer.value[0] << 6);
148 
149 	if (ucontrol->value.integer.value[0]) {
150 		/* power down the receiver */
151 		snd_soc_update_bits(codec, WM8804_PWRDN, 0x2, 0x2);
152 		/* power up the AIF */
153 		snd_soc_update_bits(codec, WM8804_PWRDN, 0x10, 0);
154 	} else {
155 		/* don't power down the AIF -- may be used as an output */
156 		/* power up the receiver */
157 		snd_soc_update_bits(codec, WM8804_PWRDN, 0x2, 0);
158 	}
159 
160 	/* restore the transmitter's configuration */
161 	snd_soc_update_bits(codec, WM8804_PWRDN, 0x4, txpwr);
162 
163 	return 0;
164 }
165 
166 static bool wm8804_volatile(struct device *dev, unsigned int reg)
167 {
168 	switch (reg) {
169 	case WM8804_RST_DEVID1:
170 	case WM8804_DEVID2:
171 	case WM8804_DEVREV:
172 	case WM8804_INTSTAT:
173 	case WM8804_SPDSTAT:
174 	case WM8804_RXCHAN1:
175 	case WM8804_RXCHAN2:
176 	case WM8804_RXCHAN3:
177 	case WM8804_RXCHAN4:
178 	case WM8804_RXCHAN5:
179 		return true;
180 	default:
181 		return false;
182 	}
183 }
184 
185 static int wm8804_reset(struct wm8804_priv *wm8804)
186 {
187 	return regmap_write(wm8804->regmap, WM8804_RST_DEVID1, 0x0);
188 }
189 
190 static int wm8804_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
191 {
192 	struct snd_soc_codec *codec;
193 	u16 format, master, bcp, lrp;
194 
195 	codec = dai->codec;
196 
197 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
198 	case SND_SOC_DAIFMT_I2S:
199 		format = 0x2;
200 		break;
201 	case SND_SOC_DAIFMT_RIGHT_J:
202 		format = 0x0;
203 		break;
204 	case SND_SOC_DAIFMT_LEFT_J:
205 		format = 0x1;
206 		break;
207 	case SND_SOC_DAIFMT_DSP_A:
208 	case SND_SOC_DAIFMT_DSP_B:
209 		format = 0x3;
210 		break;
211 	default:
212 		dev_err(dai->dev, "Unknown dai format\n");
213 		return -EINVAL;
214 	}
215 
216 	/* set data format */
217 	snd_soc_update_bits(codec, WM8804_AIFTX, 0x3, format);
218 	snd_soc_update_bits(codec, WM8804_AIFRX, 0x3, format);
219 
220 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
221 	case SND_SOC_DAIFMT_CBM_CFM:
222 		master = 1;
223 		break;
224 	case SND_SOC_DAIFMT_CBS_CFS:
225 		master = 0;
226 		break;
227 	default:
228 		dev_err(dai->dev, "Unknown master/slave configuration\n");
229 		return -EINVAL;
230 	}
231 
232 	/* set master/slave mode */
233 	snd_soc_update_bits(codec, WM8804_AIFRX, 0x40, master << 6);
234 
235 	bcp = lrp = 0;
236 	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
237 	case SND_SOC_DAIFMT_NB_NF:
238 		break;
239 	case SND_SOC_DAIFMT_IB_IF:
240 		bcp = lrp = 1;
241 		break;
242 	case SND_SOC_DAIFMT_IB_NF:
243 		bcp = 1;
244 		break;
245 	case SND_SOC_DAIFMT_NB_IF:
246 		lrp = 1;
247 		break;
248 	default:
249 		dev_err(dai->dev, "Unknown polarity configuration\n");
250 		return -EINVAL;
251 	}
252 
253 	/* set frame inversion */
254 	snd_soc_update_bits(codec, WM8804_AIFTX, 0x10 | 0x20,
255 			    (bcp << 4) | (lrp << 5));
256 	snd_soc_update_bits(codec, WM8804_AIFRX, 0x10 | 0x20,
257 			    (bcp << 4) | (lrp << 5));
258 	return 0;
259 }
260 
261 static int wm8804_hw_params(struct snd_pcm_substream *substream,
262 			    struct snd_pcm_hw_params *params,
263 			    struct snd_soc_dai *dai)
264 {
265 	struct snd_soc_codec *codec;
266 	u16 blen;
267 
268 	codec = dai->codec;
269 
270 	switch (params_width(params)) {
271 	case 16:
272 		blen = 0x0;
273 		break;
274 	case 20:
275 		blen = 0x1;
276 		break;
277 	case 24:
278 		blen = 0x2;
279 		break;
280 	default:
281 		dev_err(dai->dev, "Unsupported word length: %u\n",
282 			params_width(params));
283 		return -EINVAL;
284 	}
285 
286 	/* set word length */
287 	snd_soc_update_bits(codec, WM8804_AIFTX, 0xc, blen << 2);
288 	snd_soc_update_bits(codec, WM8804_AIFRX, 0xc, blen << 2);
289 
290 	return 0;
291 }
292 
293 struct pll_div {
294 	u32 prescale:1;
295 	u32 mclkdiv:1;
296 	u32 freqmode:2;
297 	u32 n:4;
298 	u32 k:22;
299 };
300 
301 /* PLL rate to output rate divisions */
302 static struct {
303 	unsigned int div;
304 	unsigned int freqmode;
305 	unsigned int mclkdiv;
306 } post_table[] = {
307 	{  2,  0, 0 },
308 	{  4,  0, 1 },
309 	{  4,  1, 0 },
310 	{  8,  1, 1 },
311 	{  8,  2, 0 },
312 	{ 16,  2, 1 },
313 	{ 12,  3, 0 },
314 	{ 24,  3, 1 }
315 };
316 
317 #define FIXED_PLL_SIZE ((1ULL << 22) * 10)
318 static int pll_factors(struct pll_div *pll_div, unsigned int target,
319 		       unsigned int source, unsigned int mclk_div)
320 {
321 	u64 Kpart;
322 	unsigned long int K, Ndiv, Nmod, tmp;
323 	int i;
324 
325 	/*
326 	 * Scale the output frequency up; the PLL should run in the
327 	 * region of 90-100MHz.
328 	 */
329 	for (i = 0; i < ARRAY_SIZE(post_table); i++) {
330 		tmp = target * post_table[i].div;
331 		if ((tmp >= 90000000 && tmp <= 100000000) &&
332 		    (mclk_div == post_table[i].mclkdiv)) {
333 			pll_div->freqmode = post_table[i].freqmode;
334 			pll_div->mclkdiv = post_table[i].mclkdiv;
335 			target *= post_table[i].div;
336 			break;
337 		}
338 	}
339 
340 	if (i == ARRAY_SIZE(post_table)) {
341 		pr_err("%s: Unable to scale output frequency: %uHz\n",
342 		       __func__, target);
343 		return -EINVAL;
344 	}
345 
346 	pll_div->prescale = 0;
347 	Ndiv = target / source;
348 	if (Ndiv < 5) {
349 		source >>= 1;
350 		pll_div->prescale = 1;
351 		Ndiv = target / source;
352 	}
353 
354 	if (Ndiv < 5 || Ndiv > 13) {
355 		pr_err("%s: WM8804 N value is not within the recommended range: %lu\n",
356 		       __func__, Ndiv);
357 		return -EINVAL;
358 	}
359 	pll_div->n = Ndiv;
360 
361 	Nmod = target % source;
362 	Kpart = FIXED_PLL_SIZE * (u64)Nmod;
363 
364 	do_div(Kpart, source);
365 
366 	K = Kpart & 0xffffffff;
367 	if ((K % 10) >= 5)
368 		K += 5;
369 	K /= 10;
370 	pll_div->k = K;
371 
372 	return 0;
373 }
374 
375 static int wm8804_set_pll(struct snd_soc_dai *dai, int pll_id,
376 			  int source, unsigned int freq_in,
377 			  unsigned int freq_out)
378 {
379 	struct snd_soc_codec *codec;
380 
381 	codec = dai->codec;
382 	if (!freq_in || !freq_out) {
383 		/* disable the PLL */
384 		snd_soc_update_bits(codec, WM8804_PWRDN, 0x1, 0x1);
385 		return 0;
386 	} else {
387 		int ret;
388 		struct pll_div pll_div;
389 		struct wm8804_priv *wm8804;
390 
391 		wm8804 = snd_soc_codec_get_drvdata(codec);
392 
393 		ret = pll_factors(&pll_div, freq_out, freq_in,
394 				  wm8804->mclk_div);
395 		if (ret)
396 			return ret;
397 
398 		/* power down the PLL before reprogramming it */
399 		snd_soc_update_bits(codec, WM8804_PWRDN, 0x1, 0x1);
400 
401 		/* set PLLN and PRESCALE */
402 		snd_soc_update_bits(codec, WM8804_PLL4, 0xf | 0x10,
403 				    pll_div.n | (pll_div.prescale << 4));
404 		/* set mclkdiv and freqmode */
405 		snd_soc_update_bits(codec, WM8804_PLL5, 0x3 | 0x8,
406 				    pll_div.freqmode | (pll_div.mclkdiv << 3));
407 		/* set PLLK */
408 		snd_soc_write(codec, WM8804_PLL1, pll_div.k & 0xff);
409 		snd_soc_write(codec, WM8804_PLL2, (pll_div.k >> 8) & 0xff);
410 		snd_soc_write(codec, WM8804_PLL3, pll_div.k >> 16);
411 
412 		/* power up the PLL */
413 		snd_soc_update_bits(codec, WM8804_PWRDN, 0x1, 0);
414 	}
415 
416 	return 0;
417 }
418 
419 static int wm8804_set_sysclk(struct snd_soc_dai *dai,
420 			     int clk_id, unsigned int freq, int dir)
421 {
422 	struct snd_soc_codec *codec;
423 
424 	codec = dai->codec;
425 
426 	switch (clk_id) {
427 	case WM8804_TX_CLKSRC_MCLK:
428 		if ((freq >= 10000000 && freq <= 14400000)
429 				|| (freq >= 16280000 && freq <= 27000000))
430 			snd_soc_update_bits(codec, WM8804_PLL6, 0x80, 0x80);
431 		else {
432 			dev_err(dai->dev, "OSCCLOCK is not within the "
433 				"recommended range: %uHz\n", freq);
434 			return -EINVAL;
435 		}
436 		break;
437 	case WM8804_TX_CLKSRC_PLL:
438 		snd_soc_update_bits(codec, WM8804_PLL6, 0x80, 0);
439 		break;
440 	case WM8804_CLKOUT_SRC_CLK1:
441 		snd_soc_update_bits(codec, WM8804_PLL6, 0x8, 0);
442 		break;
443 	case WM8804_CLKOUT_SRC_OSCCLK:
444 		snd_soc_update_bits(codec, WM8804_PLL6, 0x8, 0x8);
445 		break;
446 	default:
447 		dev_err(dai->dev, "Unknown clock source: %d\n", clk_id);
448 		return -EINVAL;
449 	}
450 
451 	return 0;
452 }
453 
454 static int wm8804_set_clkdiv(struct snd_soc_dai *dai,
455 			     int div_id, int div)
456 {
457 	struct snd_soc_codec *codec;
458 	struct wm8804_priv *wm8804;
459 
460 	codec = dai->codec;
461 	switch (div_id) {
462 	case WM8804_CLKOUT_DIV:
463 		snd_soc_update_bits(codec, WM8804_PLL5, 0x30,
464 				    (div & 0x3) << 4);
465 		break;
466 	case WM8804_MCLK_DIV:
467 		wm8804 = snd_soc_codec_get_drvdata(codec);
468 		wm8804->mclk_div = div;
469 		break;
470 	default:
471 		dev_err(dai->dev, "Unknown clock divider: %d\n", div_id);
472 		return -EINVAL;
473 	}
474 	return 0;
475 }
476 
477 static int wm8804_set_bias_level(struct snd_soc_codec *codec,
478 				 enum snd_soc_bias_level level)
479 {
480 	int ret;
481 	struct wm8804_priv *wm8804;
482 
483 	wm8804 = snd_soc_codec_get_drvdata(codec);
484 	switch (level) {
485 	case SND_SOC_BIAS_ON:
486 		break;
487 	case SND_SOC_BIAS_PREPARE:
488 		/* power up the OSC and the PLL */
489 		snd_soc_update_bits(codec, WM8804_PWRDN, 0x9, 0);
490 		break;
491 	case SND_SOC_BIAS_STANDBY:
492 		if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
493 			ret = regulator_bulk_enable(ARRAY_SIZE(wm8804->supplies),
494 						    wm8804->supplies);
495 			if (ret) {
496 				dev_err(codec->dev,
497 					"Failed to enable supplies: %d\n",
498 					ret);
499 				return ret;
500 			}
501 			regcache_sync(wm8804->regmap);
502 		}
503 		/* power down the OSC and the PLL */
504 		snd_soc_update_bits(codec, WM8804_PWRDN, 0x9, 0x9);
505 		break;
506 	case SND_SOC_BIAS_OFF:
507 		/* power down the OSC and the PLL */
508 		snd_soc_update_bits(codec, WM8804_PWRDN, 0x9, 0x9);
509 		regulator_bulk_disable(ARRAY_SIZE(wm8804->supplies),
510 				       wm8804->supplies);
511 		break;
512 	}
513 
514 	codec->dapm.bias_level = level;
515 	return 0;
516 }
517 
518 static const struct snd_soc_dai_ops wm8804_dai_ops = {
519 	.hw_params = wm8804_hw_params,
520 	.set_fmt = wm8804_set_fmt,
521 	.set_sysclk = wm8804_set_sysclk,
522 	.set_clkdiv = wm8804_set_clkdiv,
523 	.set_pll = wm8804_set_pll
524 };
525 
526 #define WM8804_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
527 			SNDRV_PCM_FMTBIT_S24_LE)
528 
529 #define WM8804_RATES (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
530 		      SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_64000 | \
531 		      SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | \
532 		      SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000)
533 
534 static struct snd_soc_dai_driver wm8804_dai = {
535 	.name = "wm8804-spdif",
536 	.playback = {
537 		.stream_name = "Playback",
538 		.channels_min = 2,
539 		.channels_max = 2,
540 		.rates = WM8804_RATES,
541 		.formats = WM8804_FORMATS,
542 	},
543 	.capture = {
544 		.stream_name = "Capture",
545 		.channels_min = 2,
546 		.channels_max = 2,
547 		.rates = WM8804_RATES,
548 		.formats = WM8804_FORMATS,
549 	},
550 	.ops = &wm8804_dai_ops,
551 	.symmetric_rates = 1
552 };
553 
554 static const struct snd_soc_codec_driver soc_codec_dev_wm8804 = {
555 	.set_bias_level = wm8804_set_bias_level,
556 	.idle_bias_off = true,
557 
558 	.controls = wm8804_snd_controls,
559 	.num_controls = ARRAY_SIZE(wm8804_snd_controls),
560 };
561 
562 const struct regmap_config wm8804_regmap_config = {
563 	.reg_bits = 8,
564 	.val_bits = 8,
565 
566 	.max_register = WM8804_MAX_REGISTER,
567 	.volatile_reg = wm8804_volatile,
568 
569 	.cache_type = REGCACHE_RBTREE,
570 	.reg_defaults = wm8804_reg_defaults,
571 	.num_reg_defaults = ARRAY_SIZE(wm8804_reg_defaults),
572 };
573 EXPORT_SYMBOL_GPL(wm8804_regmap_config);
574 
575 int wm8804_probe(struct device *dev, struct regmap *regmap)
576 {
577 	struct wm8804_priv *wm8804;
578 	unsigned int id1, id2;
579 	int i, ret;
580 
581 	wm8804 = devm_kzalloc(dev, sizeof(*wm8804), GFP_KERNEL);
582 	if (!wm8804)
583 		return -ENOMEM;
584 
585 	dev_set_drvdata(dev, wm8804);
586 
587 	wm8804->regmap = regmap;
588 
589 	for (i = 0; i < ARRAY_SIZE(wm8804->supplies); i++)
590 		wm8804->supplies[i].supply = wm8804_supply_names[i];
591 
592 	ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(wm8804->supplies),
593 				      wm8804->supplies);
594 	if (ret) {
595 		dev_err(dev, "Failed to request supplies: %d\n", ret);
596 		return ret;
597 	}
598 
599 	wm8804->disable_nb[0].notifier_call = wm8804_regulator_event_0;
600 	wm8804->disable_nb[1].notifier_call = wm8804_regulator_event_1;
601 
602 	/* This should really be moved into the regulator core */
603 	for (i = 0; i < ARRAY_SIZE(wm8804->supplies); i++) {
604 		ret = regulator_register_notifier(wm8804->supplies[i].consumer,
605 						  &wm8804->disable_nb[i]);
606 		if (ret != 0) {
607 			dev_err(dev,
608 				"Failed to register regulator notifier: %d\n",
609 				ret);
610 		}
611 	}
612 
613 	ret = regulator_bulk_enable(ARRAY_SIZE(wm8804->supplies),
614 				    wm8804->supplies);
615 	if (ret) {
616 		dev_err(dev, "Failed to enable supplies: %d\n", ret);
617 		goto err_reg_enable;
618 	}
619 
620 	ret = regmap_read(regmap, WM8804_RST_DEVID1, &id1);
621 	if (ret < 0) {
622 		dev_err(dev, "Failed to read device ID: %d\n", ret);
623 		goto err_reg_enable;
624 	}
625 
626 	ret = regmap_read(regmap, WM8804_DEVID2, &id2);
627 	if (ret < 0) {
628 		dev_err(dev, "Failed to read device ID: %d\n", ret);
629 		goto err_reg_enable;
630 	}
631 
632 	id2 = (id2 << 8) | id1;
633 
634 	if (id2 != 0x8805) {
635 		dev_err(dev, "Invalid device ID: %#x\n", id2);
636 		ret = -EINVAL;
637 		goto err_reg_enable;
638 	}
639 
640 	ret = regmap_read(regmap, WM8804_DEVREV, &id1);
641 	if (ret < 0) {
642 		dev_err(dev, "Failed to read device revision: %d\n",
643 			ret);
644 		goto err_reg_enable;
645 	}
646 	dev_info(dev, "revision %c\n", id1 + 'A');
647 
648 	ret = wm8804_reset(wm8804);
649 	if (ret < 0) {
650 		dev_err(dev, "Failed to issue reset: %d\n", ret);
651 		goto err_reg_enable;
652 	}
653 
654 	return snd_soc_register_codec(dev, &soc_codec_dev_wm8804,
655 				      &wm8804_dai, 1);
656 
657 err_reg_enable:
658 	regulator_bulk_disable(ARRAY_SIZE(wm8804->supplies), wm8804->supplies);
659 	return ret;
660 }
661 EXPORT_SYMBOL_GPL(wm8804_probe);
662 
663 void wm8804_remove(struct device *dev)
664 {
665 	struct wm8804_priv *wm8804;
666 	int i;
667 
668 	wm8804 = dev_get_drvdata(dev);
669 
670 	for (i = 0; i < ARRAY_SIZE(wm8804->supplies); ++i)
671 		regulator_unregister_notifier(wm8804->supplies[i].consumer,
672 					      &wm8804->disable_nb[i]);
673 
674 	snd_soc_unregister_codec(dev);
675 }
676 EXPORT_SYMBOL_GPL(wm8804_remove);
677 
678 MODULE_DESCRIPTION("ASoC WM8804 driver");
679 MODULE_AUTHOR("Dimitris Papastamos <dp@opensource.wolfsonmicro.com>");
680 MODULE_LICENSE("GPL");
681