xref: /openbmc/linux/sound/soc/codecs/wm8776.c (revision 924914ee)
1 /*
2  * wm8776.c  --  WM8776 ALSA SoC Audio driver
3  *
4  * Copyright 2009 Wolfson Microelectronics plc
5  *
6  * Author: Mark Brown <broonie@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  * TODO: Input ALC/limiter support
13  */
14 
15 #include <linux/module.h>
16 #include <linux/moduleparam.h>
17 #include <linux/init.h>
18 #include <linux/delay.h>
19 #include <linux/pm.h>
20 #include <linux/i2c.h>
21 #include <linux/platform_device.h>
22 #include <linux/spi/spi.h>
23 #include <sound/core.h>
24 #include <sound/pcm.h>
25 #include <sound/pcm_params.h>
26 #include <sound/soc.h>
27 #include <sound/soc-dapm.h>
28 #include <sound/initval.h>
29 #include <sound/tlv.h>
30 
31 #include "wm8776.h"
32 
33 static struct snd_soc_codec *wm8776_codec;
34 struct snd_soc_codec_device soc_codec_dev_wm8776;
35 
36 /* codec private data */
37 struct wm8776_priv {
38 	struct snd_soc_codec codec;
39 	u16 reg_cache[WM8776_CACHEREGNUM];
40 	int sysclk[2];
41 };
42 
43 #ifdef CONFIG_SPI_MASTER
44 static int wm8776_spi_write(struct spi_device *spi, const char *data, int len);
45 #endif
46 
47 static const u16 wm8776_reg[WM8776_CACHEREGNUM] = {
48 	0x79, 0x79, 0x79, 0xff, 0xff,  /* 4 */
49 	0xff, 0x00, 0x90, 0x00, 0x00,  /* 9 */
50 	0x22, 0x22, 0x22, 0x08, 0xcf,  /* 14 */
51 	0xcf, 0x7b, 0x00, 0x32, 0x00,  /* 19 */
52 	0xa6, 0x01, 0x01
53 };
54 
55 /*
56  * read wm8776 register cache
57  */
58 static inline unsigned int wm8776_read_reg_cache(struct snd_soc_codec *codec,
59 	unsigned int reg)
60 {
61 	u16 *cache = codec->reg_cache;
62 	if (reg >= WM8776_CACHEREGNUM)
63 		return -1;
64 	return cache[reg];
65 }
66 
67 /*
68  * write wm8776 register cache
69  */
70 static inline void wm8776_write_reg_cache(struct snd_soc_codec *codec,
71 					  u16 reg, unsigned int value)
72 {
73 	u16 *cache = codec->reg_cache;
74 	if (reg >= WM8776_CACHEREGNUM)
75 		return;
76 	cache[reg] = value;
77 }
78 
79 /*
80  * write to the WM8776 register space
81  */
82 static int wm8776_write(struct snd_soc_codec *codec, unsigned int reg,
83 	unsigned int value)
84 {
85 	u8 data[2];
86 
87 	data[0] = (reg << 1) | ((value >> 8) & 0x0001);
88 	data[1] = value & 0x00ff;
89 
90 	wm8776_write_reg_cache(codec, reg, value);
91 	if (codec->hw_write(codec->control_data, data, 2) == 2)
92 		return 0;
93 	else
94 		return -EIO;
95 }
96 
97 static int wm8776_reset(struct snd_soc_codec *codec)
98 {
99 	return wm8776_write(codec, WM8776_RESET, 0);
100 }
101 
102 static const DECLARE_TLV_DB_SCALE(hp_tlv, -12100, 100, 1);
103 static const DECLARE_TLV_DB_SCALE(dac_tlv, -12750, 50, 1);
104 static const DECLARE_TLV_DB_SCALE(adc_tlv, -10350, 50, 1);
105 
106 static const struct snd_kcontrol_new wm8776_snd_controls[] = {
107 SOC_DOUBLE_R_TLV("Headphone Playback Volume", WM8776_HPLVOL, WM8776_HPRVOL,
108 		 0, 127, 0, hp_tlv),
109 SOC_DOUBLE_R_TLV("Digital Playback Volume", WM8776_DACLVOL, WM8776_DACRVOL,
110 		 0, 255, 0, dac_tlv),
111 SOC_SINGLE("Digital Playback ZC Switch", WM8776_DACCTRL1, 0, 1, 0),
112 
113 SOC_SINGLE("Deemphasis Switch", WM8776_DACCTRL2, 0, 1, 0),
114 
115 SOC_DOUBLE_R_TLV("Capture Volume", WM8776_ADCLVOL, WM8776_ADCRVOL,
116 		 0, 255, 0, adc_tlv),
117 SOC_DOUBLE("Capture Switch", WM8776_ADCMUX, 7, 6, 1, 1),
118 SOC_DOUBLE_R("Capture ZC Switch", WM8776_ADCLVOL, WM8776_ADCRVOL, 8, 1, 0),
119 SOC_SINGLE("Capture HPF Switch", WM8776_ADCIFCTRL, 8, 1, 1),
120 };
121 
122 static const struct snd_kcontrol_new inmix_controls[] = {
123 SOC_DAPM_SINGLE("AIN1 Switch", WM8776_ADCMUX, 0, 1, 0),
124 SOC_DAPM_SINGLE("AIN2 Switch", WM8776_ADCMUX, 1, 1, 0),
125 SOC_DAPM_SINGLE("AIN3 Switch", WM8776_ADCMUX, 2, 1, 0),
126 SOC_DAPM_SINGLE("AIN4 Switch", WM8776_ADCMUX, 3, 1, 0),
127 SOC_DAPM_SINGLE("AIN5 Switch", WM8776_ADCMUX, 4, 1, 0),
128 };
129 
130 static const struct snd_kcontrol_new outmix_controls[] = {
131 SOC_DAPM_SINGLE("DAC Switch", WM8776_OUTMUX, 0, 1, 0),
132 SOC_DAPM_SINGLE("AUX Switch", WM8776_OUTMUX, 1, 1, 0),
133 SOC_DAPM_SINGLE("Bypass Switch", WM8776_OUTMUX, 2, 1, 0),
134 };
135 
136 static const struct snd_soc_dapm_widget wm8776_dapm_widgets[] = {
137 SND_SOC_DAPM_INPUT("AUX"),
138 SND_SOC_DAPM_INPUT("AUX"),
139 
140 SND_SOC_DAPM_INPUT("AIN1"),
141 SND_SOC_DAPM_INPUT("AIN2"),
142 SND_SOC_DAPM_INPUT("AIN3"),
143 SND_SOC_DAPM_INPUT("AIN4"),
144 SND_SOC_DAPM_INPUT("AIN5"),
145 
146 SND_SOC_DAPM_MIXER("Input Mixer", WM8776_PWRDOWN, 6, 1,
147 		   inmix_controls, ARRAY_SIZE(inmix_controls)),
148 
149 SND_SOC_DAPM_ADC("ADC", "Capture", WM8776_PWRDOWN, 1, 1),
150 SND_SOC_DAPM_DAC("DAC", "Playback", WM8776_PWRDOWN, 2, 1),
151 
152 SND_SOC_DAPM_MIXER("Output Mixer", SND_SOC_NOPM, 0, 0,
153 		   outmix_controls, ARRAY_SIZE(outmix_controls)),
154 
155 SND_SOC_DAPM_PGA("Headphone PGA", WM8776_PWRDOWN, 3, 1, NULL, 0),
156 
157 SND_SOC_DAPM_OUTPUT("VOUT"),
158 
159 SND_SOC_DAPM_OUTPUT("HPOUTL"),
160 SND_SOC_DAPM_OUTPUT("HPOUTR"),
161 };
162 
163 static const struct snd_soc_dapm_route routes[] = {
164 	{ "Input Mixer", "AIN1 Switch", "AIN1" },
165 	{ "Input Mixer", "AIN2 Switch", "AIN2" },
166 	{ "Input Mixer", "AIN3 Switch", "AIN3" },
167 	{ "Input Mixer", "AIN4 Switch", "AIN4" },
168 	{ "Input Mixer", "AIN5 Switch", "AIN5" },
169 
170 	{ "ADC", NULL, "Input Mixer" },
171 
172 	{ "Output Mixer", "DAC Switch", "DAC" },
173 	{ "Output Mixer", "AUX Switch", "AUX" },
174 	{ "Output Mixer", "Bypass Switch", "Input Mixer" },
175 
176 	{ "VOUT", NULL, "Output Mixer" },
177 
178 	{ "Headphone PGA", NULL, "Output Mixer" },
179 
180 	{ "HPOUTL", NULL, "Headphone PGA" },
181 	{ "HPOUTR", NULL, "Headphone PGA" },
182 };
183 
184 static int wm8776_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
185 {
186 	struct snd_soc_codec *codec = dai->codec;
187 	int reg, iface, master;
188 
189 	switch (dai->id) {
190 	case WM8776_DAI_DAC:
191 		reg = WM8776_DACIFCTRL;
192 		master = 0x80;
193 		break;
194 	case WM8776_DAI_ADC:
195 		reg = WM8776_ADCIFCTRL;
196 		master = 0x100;
197 		break;
198 	default:
199 		return -EINVAL;
200 	}
201 
202 	iface = 0;
203 
204 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
205 	case SND_SOC_DAIFMT_CBM_CFM:
206 		break;
207 	case SND_SOC_DAIFMT_CBS_CFS:
208 		master = 0;
209 		break;
210 	default:
211 		return -EINVAL;
212 	}
213 
214 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
215 	case SND_SOC_DAIFMT_I2S:
216 		iface |= 0x0002;
217 		break;
218 	case SND_SOC_DAIFMT_RIGHT_J:
219 		break;
220 	case SND_SOC_DAIFMT_LEFT_J:
221 		iface |= 0x0001;
222 		break;
223 		/* FIXME: CHECK A/B */
224 	case SND_SOC_DAIFMT_DSP_A:
225 		iface |= 0x0003;
226 		break;
227 	case SND_SOC_DAIFMT_DSP_B:
228 		iface |= 0x0007;
229 		break;
230 	default:
231 		return -EINVAL;
232 	}
233 
234 	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
235 	case SND_SOC_DAIFMT_NB_NF:
236 		break;
237 	case SND_SOC_DAIFMT_IB_IF:
238 		iface |= 0x00c;
239 		break;
240 	case SND_SOC_DAIFMT_IB_NF:
241 		iface |= 0x008;
242 		break;
243 	case SND_SOC_DAIFMT_NB_IF:
244 		iface |= 0x004;
245 		break;
246 	default:
247 		return -EINVAL;
248 	}
249 
250 	/* Finally, write out the values */
251 	snd_soc_update_bits(codec, reg, 0xf, iface);
252 	snd_soc_update_bits(codec, WM8776_MSTRCTRL, 0x180, master);
253 
254 	return 0;
255 }
256 
257 static int mclk_ratios[] = {
258 	128,
259 	192,
260 	256,
261 	384,
262 	512,
263 	768,
264 };
265 
266 static int wm8776_hw_params(struct snd_pcm_substream *substream,
267 			    struct snd_pcm_hw_params *params,
268 			    struct snd_soc_dai *dai)
269 {
270 	struct snd_soc_codec *codec = dai->codec;
271 	struct wm8776_priv *wm8776 = codec->private_data;
272 	int iface_reg, iface;
273 	int ratio_shift, master;
274 	int i;
275 
276 	iface = 0;
277 
278 	switch (dai->id) {
279 	case WM8776_DAI_DAC:
280 		iface_reg = WM8776_DACIFCTRL;
281 		master = 0x80;
282 		ratio_shift = 4;
283 		break;
284 	case WM8776_DAI_ADC:
285 		iface_reg = WM8776_ADCIFCTRL;
286 		master = 0x100;
287 		ratio_shift = 0;
288 		break;
289 	default:
290 		return -EINVAL;
291 	}
292 
293 
294 	/* Set word length */
295 	switch (params_format(params)) {
296 	case SNDRV_PCM_FORMAT_S16_LE:
297 		break;
298 	case SNDRV_PCM_FORMAT_S20_3LE:
299 		iface |= 0x10;
300 		break;
301 	case SNDRV_PCM_FORMAT_S24_LE:
302 		iface |= 0x20;
303 		break;
304 	case SNDRV_PCM_FORMAT_S32_LE:
305 		iface |= 0x30;
306 		break;
307 	}
308 
309 	/* Only need to set MCLK/LRCLK ratio if we're master */
310 	if (snd_soc_read(codec, WM8776_MSTRCTRL) & master) {
311 		for (i = 0; i < ARRAY_SIZE(mclk_ratios); i++) {
312 			if (wm8776->sysclk[dai->id] / params_rate(params)
313 			    == mclk_ratios[i])
314 				break;
315 		}
316 
317 		if (i == ARRAY_SIZE(mclk_ratios)) {
318 			dev_err(codec->dev,
319 				"Unable to configure MCLK ratio %d/%d\n",
320 				wm8776->sysclk[dai->id], params_rate(params));
321 			return -EINVAL;
322 		}
323 
324 		dev_dbg(codec->dev, "MCLK is %dfs\n", mclk_ratios[i]);
325 
326 		snd_soc_update_bits(codec, WM8776_MSTRCTRL,
327 				    0x7 << ratio_shift, i << ratio_shift);
328 	} else {
329 		dev_dbg(codec->dev, "DAI in slave mode\n");
330 	}
331 
332 	snd_soc_update_bits(codec, iface_reg, 0x30, iface);
333 
334 	return 0;
335 }
336 
337 static int wm8776_mute(struct snd_soc_dai *dai, int mute)
338 {
339 	struct snd_soc_codec *codec = dai->codec;
340 
341 	return snd_soc_write(codec, WM8776_DACMUTE, !!mute);
342 }
343 
344 static int wm8776_set_sysclk(struct snd_soc_dai *dai,
345 			     int clk_id, unsigned int freq, int dir)
346 {
347 	struct snd_soc_codec *codec = dai->codec;
348 	struct wm8776_priv *wm8776 = codec->private_data;
349 
350 	BUG_ON(dai->id >= ARRAY_SIZE(wm8776->sysclk));
351 
352 	wm8776->sysclk[dai->id] = freq;
353 
354 	return 0;
355 }
356 
357 static int wm8776_set_bias_level(struct snd_soc_codec *codec,
358 				 enum snd_soc_bias_level level)
359 {
360 	switch (level) {
361 	case SND_SOC_BIAS_ON:
362 		break;
363 	case SND_SOC_BIAS_PREPARE:
364 		break;
365 	case SND_SOC_BIAS_STANDBY:
366 		if (codec->bias_level == SND_SOC_BIAS_OFF) {
367 			/* Disable the global powerdown; DAPM does the rest */
368 			snd_soc_update_bits(codec, WM8776_PWRDOWN, 1, 0);
369 		}
370 
371 		break;
372 	case SND_SOC_BIAS_OFF:
373 		snd_soc_update_bits(codec, WM8776_PWRDOWN, 1, 1);
374 		break;
375 	}
376 
377 	codec->bias_level = level;
378 	return 0;
379 }
380 
381 #define WM8776_RATES (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\
382 		      SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |\
383 		      SNDRV_PCM_RATE_96000)
384 
385 
386 #define WM8776_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
387 			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
388 
389 static struct snd_soc_dai_ops wm8776_dac_ops = {
390 	.digital_mute	= wm8776_mute,
391 	.hw_params      = wm8776_hw_params,
392 	.set_fmt        = wm8776_set_fmt,
393 	.set_sysclk     = wm8776_set_sysclk,
394 };
395 
396 static struct snd_soc_dai_ops wm8776_adc_ops = {
397 	.hw_params      = wm8776_hw_params,
398 	.set_fmt        = wm8776_set_fmt,
399 	.set_sysclk     = wm8776_set_sysclk,
400 };
401 
402 struct snd_soc_dai wm8776_dai[] = {
403 	{
404 		.name = "WM8776 Playback",
405 		.id = WM8776_DAI_DAC,
406 		.playback = {
407 			.stream_name = "Playback",
408 			.channels_min = 2,
409 			.channels_max = 2,
410 			.rates = WM8776_RATES,
411 			.formats = WM8776_FORMATS,
412 		},
413 		.ops = &wm8776_dac_ops,
414 	},
415 	{
416 		.name = "WM8776 Capture",
417 		.id = WM8776_DAI_ADC,
418 		.capture = {
419 			.stream_name = "Capture",
420 			.channels_min = 2,
421 			.channels_max = 2,
422 			.rates = WM8776_RATES,
423 			.formats = WM8776_FORMATS,
424 		},
425 		.ops = &wm8776_adc_ops,
426 	},
427 };
428 EXPORT_SYMBOL_GPL(wm8776_dai);
429 
430 #ifdef CONFIG_PM
431 static int wm8776_suspend(struct platform_device *pdev, pm_message_t state)
432 {
433 	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
434 	struct snd_soc_codec *codec = socdev->card->codec;
435 
436 	wm8776_set_bias_level(codec, SND_SOC_BIAS_OFF);
437 
438 	return 0;
439 }
440 
441 static int wm8776_resume(struct platform_device *pdev)
442 {
443 	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
444 	struct snd_soc_codec *codec = socdev->card->codec;
445 	int i;
446 	u8 data[2];
447 	u16 *cache = codec->reg_cache;
448 
449 	/* Sync reg_cache with the hardware */
450 	for (i = 0; i < ARRAY_SIZE(wm8776_reg); i++) {
451 		data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001);
452 		data[1] = cache[i] & 0x00ff;
453 		codec->hw_write(codec->control_data, data, 2);
454 	}
455 
456 	wm8776_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
457 
458 	return 0;
459 }
460 #else
461 #define wm8776_suspend NULL
462 #define wm8776_resume NULL
463 #endif
464 
465 static int wm8776_probe(struct platform_device *pdev)
466 {
467 	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
468 	struct snd_soc_codec *codec;
469 	int ret = 0;
470 
471 	if (wm8776_codec == NULL) {
472 		dev_err(&pdev->dev, "Codec device not registered\n");
473 		return -ENODEV;
474 	}
475 
476 	socdev->card->codec = wm8776_codec;
477 	codec = wm8776_codec;
478 
479 	/* register pcms */
480 	ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
481 	if (ret < 0) {
482 		dev_err(codec->dev, "failed to create pcms: %d\n", ret);
483 		goto pcm_err;
484 	}
485 
486 	snd_soc_add_controls(codec, wm8776_snd_controls,
487 			     ARRAY_SIZE(wm8776_snd_controls));
488 	snd_soc_dapm_new_controls(codec, wm8776_dapm_widgets,
489 				  ARRAY_SIZE(wm8776_dapm_widgets));
490 	snd_soc_dapm_add_routes(codec, routes, ARRAY_SIZE(routes));
491 
492 	ret = snd_soc_init_card(socdev);
493 	if (ret < 0) {
494 		dev_err(codec->dev, "failed to register card: %d\n", ret);
495 		goto card_err;
496 	}
497 
498 	return ret;
499 
500 card_err:
501 	snd_soc_free_pcms(socdev);
502 	snd_soc_dapm_free(socdev);
503 pcm_err:
504 	return ret;
505 }
506 
507 /* power down chip */
508 static int wm8776_remove(struct platform_device *pdev)
509 {
510 	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
511 
512 	snd_soc_free_pcms(socdev);
513 	snd_soc_dapm_free(socdev);
514 
515 	return 0;
516 }
517 
518 struct snd_soc_codec_device soc_codec_dev_wm8776 = {
519 	.probe = 	wm8776_probe,
520 	.remove = 	wm8776_remove,
521 	.suspend = 	wm8776_suspend,
522 	.resume =	wm8776_resume,
523 };
524 EXPORT_SYMBOL_GPL(soc_codec_dev_wm8776);
525 
526 static int wm8776_register(struct wm8776_priv *wm8776)
527 {
528 	int ret, i;
529 	struct snd_soc_codec *codec = &wm8776->codec;
530 
531 	if (wm8776_codec) {
532 		dev_err(codec->dev, "Another WM8776 is registered\n");
533 		ret = -EINVAL;
534 		goto err;
535 	}
536 
537 	mutex_init(&codec->mutex);
538 	INIT_LIST_HEAD(&codec->dapm_widgets);
539 	INIT_LIST_HEAD(&codec->dapm_paths);
540 
541 	codec->private_data = wm8776;
542 	codec->name = "WM8776";
543 	codec->owner = THIS_MODULE;
544 	codec->read = wm8776_read_reg_cache;
545 	codec->write = wm8776_write;
546 	codec->bias_level = SND_SOC_BIAS_OFF;
547 	codec->set_bias_level = wm8776_set_bias_level;
548 	codec->dai = wm8776_dai;
549 	codec->num_dai = ARRAY_SIZE(wm8776_dai);
550 	codec->reg_cache_size = WM8776_CACHEREGNUM;
551 	codec->reg_cache = &wm8776->reg_cache;
552 
553 	memcpy(codec->reg_cache, wm8776_reg, sizeof(wm8776_reg));
554 
555 	for (i = 0; i < ARRAY_SIZE(wm8776_dai); i++)
556 		wm8776_dai[i].dev = codec->dev;
557 
558 	ret = wm8776_reset(codec);
559 	if (ret < 0) {
560 		dev_err(codec->dev, "Failed to issue reset: %d\n", ret);
561 		goto err;
562 	}
563 
564 	wm8776_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
565 
566 	/* Latch the update bits; right channel only since we always
567 	 * update both. */
568 	snd_soc_update_bits(codec, WM8776_HPRVOL, 0x100, 0x100);
569 	snd_soc_update_bits(codec, WM8776_DACRVOL, 0x100, 0x100);
570 
571 	wm8776_codec = codec;
572 
573 	ret = snd_soc_register_codec(codec);
574 	if (ret != 0) {
575 		dev_err(codec->dev, "Failed to register codec: %d\n", ret);
576 		goto err;
577 	}
578 
579 	ret = snd_soc_register_dais(wm8776_dai, ARRAY_SIZE(wm8776_dai));
580 	if (ret != 0) {
581 		dev_err(codec->dev, "Failed to register DAIs: %d\n", ret);
582 		goto err_codec;
583 	}
584 
585 	return 0;
586 
587 err_codec:
588 	snd_soc_unregister_codec(codec);
589 err:
590 	kfree(wm8776);
591 	return ret;
592 }
593 
594 static void wm8776_unregister(struct wm8776_priv *wm8776)
595 {
596 	wm8776_set_bias_level(&wm8776->codec, SND_SOC_BIAS_OFF);
597 	snd_soc_unregister_dais(wm8776_dai, ARRAY_SIZE(wm8776_dai));
598 	snd_soc_unregister_codec(&wm8776->codec);
599 	kfree(wm8776);
600 	wm8776_codec = NULL;
601 }
602 
603 #if defined(CONFIG_SPI_MASTER)
604 static int wm8776_spi_write(struct spi_device *spi, const char *data, int len)
605 {
606 	struct spi_transfer t;
607 	struct spi_message m;
608 	u8 msg[2];
609 
610 	if (len <= 0)
611 		return 0;
612 
613 	msg[0] = data[0];
614 	msg[1] = data[1];
615 
616 	spi_message_init(&m);
617 	memset(&t, 0, (sizeof t));
618 
619 	t.tx_buf = &msg[0];
620 	t.len = len;
621 
622 	spi_message_add_tail(&t, &m);
623 	spi_sync(spi, &m);
624 
625 	return len;
626 }
627 
628 static int __devinit wm8776_spi_probe(struct spi_device *spi)
629 {
630 	struct snd_soc_codec *codec;
631 	struct wm8776_priv *wm8776;
632 
633 	wm8776 = kzalloc(sizeof(struct wm8776_priv), GFP_KERNEL);
634 	if (wm8776 == NULL)
635 		return -ENOMEM;
636 
637 	codec = &wm8776->codec;
638 	codec->control_data = spi;
639 	codec->hw_write = (hw_write_t)wm8776_spi_write;
640 	codec->dev = &spi->dev;
641 
642 	dev_set_drvdata(&spi->dev, wm8776);
643 
644 	return wm8776_register(wm8776);
645 }
646 
647 static int __devexit wm8776_spi_remove(struct spi_device *spi)
648 {
649 	struct wm8776_priv *wm8776 = dev_get_drvdata(&spi->dev);
650 
651 	wm8776_unregister(wm8776);
652 
653 	return 0;
654 }
655 
656 #ifdef CONFIG_PM
657 static int wm8776_spi_suspend(struct spi_device *spi, pm_message_t msg)
658 {
659 	return snd_soc_suspend_device(&spi->dev);
660 }
661 
662 static int wm8776_spi_resume(struct spi_device *spi)
663 {
664 	return snd_soc_resume_device(&spi->dev);
665 }
666 #else
667 #define wm8776_spi_suspend NULL
668 #define wm8776_spi_resume NULL
669 #endif
670 
671 static struct spi_driver wm8776_spi_driver = {
672 	.driver = {
673 		.name	= "wm8776",
674 		.bus	= &spi_bus_type,
675 		.owner	= THIS_MODULE,
676 	},
677 	.probe		= wm8776_spi_probe,
678 	.suspend	= wm8776_spi_suspend,
679 	.resume		= wm8776_spi_resume,
680 	.remove		= __devexit_p(wm8776_spi_remove),
681 };
682 #endif /* CONFIG_SPI_MASTER */
683 
684 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
685 static __devinit int wm8776_i2c_probe(struct i2c_client *i2c,
686 				      const struct i2c_device_id *id)
687 {
688 	struct wm8776_priv *wm8776;
689 	struct snd_soc_codec *codec;
690 
691 	wm8776 = kzalloc(sizeof(struct wm8776_priv), GFP_KERNEL);
692 	if (wm8776 == NULL)
693 		return -ENOMEM;
694 
695 	codec = &wm8776->codec;
696 	codec->hw_write = (hw_write_t)i2c_master_send;
697 
698 	i2c_set_clientdata(i2c, wm8776);
699 	codec->control_data = i2c;
700 
701 	codec->dev = &i2c->dev;
702 
703 	return wm8776_register(wm8776);
704 }
705 
706 static __devexit int wm8776_i2c_remove(struct i2c_client *client)
707 {
708 	struct wm8776_priv *wm8776 = i2c_get_clientdata(client);
709 	wm8776_unregister(wm8776);
710 	return 0;
711 }
712 
713 #ifdef CONFIG_PM
714 static int wm8776_i2c_suspend(struct i2c_client *i2c, pm_message_t msg)
715 {
716 	return snd_soc_suspend_device(&i2c->dev);
717 }
718 
719 static int wm8776_i2c_resume(struct i2c_client *i2c)
720 {
721 	return snd_soc_resume_device(&i2c->dev);
722 }
723 #else
724 #define wm8776_i2c_suspend NULL
725 #define wm8776_i2c_resume NULL
726 #endif
727 
728 static const struct i2c_device_id wm8776_i2c_id[] = {
729 	{ "wm8776", 0 },
730 	{ }
731 };
732 MODULE_DEVICE_TABLE(i2c, wm8776_i2c_id);
733 
734 static struct i2c_driver wm8776_i2c_driver = {
735 	.driver = {
736 		.name = "wm8776",
737 		.owner = THIS_MODULE,
738 	},
739 	.probe =    wm8776_i2c_probe,
740 	.remove =   __devexit_p(wm8776_i2c_remove),
741 	.suspend =  wm8776_i2c_suspend,
742 	.resume =   wm8776_i2c_resume,
743 	.id_table = wm8776_i2c_id,
744 };
745 #endif
746 
747 static int __init wm8776_modinit(void)
748 {
749 	int ret;
750 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
751 	ret = i2c_add_driver(&wm8776_i2c_driver);
752 	if (ret != 0) {
753 		printk(KERN_ERR "Failed to register WM8776 I2C driver: %d\n",
754 		       ret);
755 	}
756 #endif
757 #if defined(CONFIG_SPI_MASTER)
758 	ret = spi_register_driver(&wm8776_spi_driver);
759 	if (ret != 0) {
760 		printk(KERN_ERR "Failed to register WM8776 SPI driver: %d\n",
761 		       ret);
762 	}
763 #endif
764 	return 0;
765 }
766 module_init(wm8776_modinit);
767 
768 static void __exit wm8776_exit(void)
769 {
770 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
771 	i2c_del_driver(&wm8776_i2c_driver);
772 #endif
773 #if defined(CONFIG_SPI_MASTER)
774 	spi_unregister_driver(&wm8776_spi_driver);
775 #endif
776 }
777 module_exit(wm8776_exit);
778 
779 MODULE_DESCRIPTION("ASoC WM8776 driver");
780 MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
781 MODULE_LICENSE("GPL");
782