xref: /openbmc/linux/sound/soc/codecs/wm8711.c (revision 4dc7ccf7)
1 /*
2  * wm8711.c  --  WM8711 ALSA SoC Audio driver
3  *
4  * Copyright 2006 Wolfson Microelectronics
5  *
6  * Author: Mike Arthur <linux@wolfsonmicro.com>
7  *
8  * Based on wm8731.c by Richard Purdie
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License version 2 as
12  * published by the Free Software Foundation.
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 <linux/slab.h>
24 #include <sound/core.h>
25 #include <sound/pcm.h>
26 #include <sound/pcm_params.h>
27 #include <sound/soc.h>
28 #include <sound/soc-dapm.h>
29 #include <sound/tlv.h>
30 #include <sound/initval.h>
31 
32 #include "wm8711.h"
33 
34 static struct snd_soc_codec *wm8711_codec;
35 
36 /* codec private data */
37 struct wm8711_priv {
38 	struct snd_soc_codec codec;
39 	u16 reg_cache[WM8711_CACHEREGNUM];
40 	unsigned int sysclk;
41 };
42 
43 /*
44  * wm8711 register cache
45  * We can't read the WM8711 register space when we are
46  * using 2 wire for device control, so we cache them instead.
47  * There is no point in caching the reset register
48  */
49 static const u16 wm8711_reg[WM8711_CACHEREGNUM] = {
50 	0x0079, 0x0079, 0x000a, 0x0008,
51 	0x009f, 0x000a, 0x0000, 0x0000
52 };
53 
54 #define wm8711_reset(c)	snd_soc_write(c, WM8711_RESET, 0)
55 
56 static const DECLARE_TLV_DB_SCALE(out_tlv, -12100, 100, 1);
57 
58 static const struct snd_kcontrol_new wm8711_snd_controls[] = {
59 
60 SOC_DOUBLE_R_TLV("Master Playback Volume", WM8711_LOUT1V, WM8711_ROUT1V,
61 		 0, 127, 0, out_tlv),
62 SOC_DOUBLE_R("Master Playback ZC Switch", WM8711_LOUT1V, WM8711_ROUT1V,
63 	7, 1, 0),
64 
65 };
66 
67 /* Output Mixer */
68 static const struct snd_kcontrol_new wm8711_output_mixer_controls[] = {
69 SOC_DAPM_SINGLE("Line Bypass Switch", WM8711_APANA, 3, 1, 0),
70 SOC_DAPM_SINGLE("HiFi Playback Switch", WM8711_APANA, 4, 1, 0),
71 };
72 
73 static const struct snd_soc_dapm_widget wm8711_dapm_widgets[] = {
74 SND_SOC_DAPM_MIXER("Output Mixer", WM8711_PWR, 4, 1,
75 	&wm8711_output_mixer_controls[0],
76 	ARRAY_SIZE(wm8711_output_mixer_controls)),
77 SND_SOC_DAPM_DAC("DAC", "HiFi Playback", WM8711_PWR, 3, 1),
78 SND_SOC_DAPM_OUTPUT("LOUT"),
79 SND_SOC_DAPM_OUTPUT("LHPOUT"),
80 SND_SOC_DAPM_OUTPUT("ROUT"),
81 SND_SOC_DAPM_OUTPUT("RHPOUT"),
82 };
83 
84 static const struct snd_soc_dapm_route intercon[] = {
85 	/* output mixer */
86 	{"Output Mixer", "Line Bypass Switch", "Line Input"},
87 	{"Output Mixer", "HiFi Playback Switch", "DAC"},
88 
89 	/* outputs */
90 	{"RHPOUT", NULL, "Output Mixer"},
91 	{"ROUT", NULL, "Output Mixer"},
92 	{"LHPOUT", NULL, "Output Mixer"},
93 	{"LOUT", NULL, "Output Mixer"},
94 };
95 
96 static int wm8711_add_widgets(struct snd_soc_codec *codec)
97 {
98 	snd_soc_dapm_new_controls(codec, wm8711_dapm_widgets,
99 				  ARRAY_SIZE(wm8711_dapm_widgets));
100 
101 	snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon));
102 
103 	return 0;
104 }
105 
106 struct _coeff_div {
107 	u32 mclk;
108 	u32 rate;
109 	u16 fs;
110 	u8 sr:4;
111 	u8 bosr:1;
112 	u8 usb:1;
113 };
114 
115 /* codec mclk clock divider coefficients */
116 static const struct _coeff_div coeff_div[] = {
117 	/* 48k */
118 	{12288000, 48000, 256, 0x0, 0x0, 0x0},
119 	{18432000, 48000, 384, 0x0, 0x1, 0x0},
120 	{12000000, 48000, 250, 0x0, 0x0, 0x1},
121 
122 	/* 32k */
123 	{12288000, 32000, 384, 0x6, 0x0, 0x0},
124 	{18432000, 32000, 576, 0x6, 0x1, 0x0},
125 	{12000000, 32000, 375, 0x6, 0x0, 0x1},
126 
127 	/* 8k */
128 	{12288000, 8000, 1536, 0x3, 0x0, 0x0},
129 	{18432000, 8000, 2304, 0x3, 0x1, 0x0},
130 	{11289600, 8000, 1408, 0xb, 0x0, 0x0},
131 	{16934400, 8000, 2112, 0xb, 0x1, 0x0},
132 	{12000000, 8000, 1500, 0x3, 0x0, 0x1},
133 
134 	/* 96k */
135 	{12288000, 96000, 128, 0x7, 0x0, 0x0},
136 	{18432000, 96000, 192, 0x7, 0x1, 0x0},
137 	{12000000, 96000, 125, 0x7, 0x0, 0x1},
138 
139 	/* 44.1k */
140 	{11289600, 44100, 256, 0x8, 0x0, 0x0},
141 	{16934400, 44100, 384, 0x8, 0x1, 0x0},
142 	{12000000, 44100, 272, 0x8, 0x1, 0x1},
143 
144 	/* 88.2k */
145 	{11289600, 88200, 128, 0xf, 0x0, 0x0},
146 	{16934400, 88200, 192, 0xf, 0x1, 0x0},
147 	{12000000, 88200, 136, 0xf, 0x1, 0x1},
148 };
149 
150 static inline int get_coeff(int mclk, int rate)
151 {
152 	int i;
153 
154 	for (i = 0; i < ARRAY_SIZE(coeff_div); i++) {
155 		if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk)
156 			return i;
157 	}
158 	return 0;
159 }
160 
161 static int wm8711_hw_params(struct snd_pcm_substream *substream,
162 	struct snd_pcm_hw_params *params,
163 	struct snd_soc_dai *dai)
164 {
165 	struct snd_soc_codec *codec = dai->codec;
166 	struct wm8711_priv *wm8711 = codec->private_data;
167 	u16 iface = snd_soc_read(codec, WM8711_IFACE) & 0xfffc;
168 	int i = get_coeff(wm8711->sysclk, params_rate(params));
169 	u16 srate = (coeff_div[i].sr << 2) |
170 		(coeff_div[i].bosr << 1) | coeff_div[i].usb;
171 
172 	snd_soc_write(codec, WM8711_SRATE, srate);
173 
174 	/* bit size */
175 	switch (params_format(params)) {
176 	case SNDRV_PCM_FORMAT_S16_LE:
177 		break;
178 	case SNDRV_PCM_FORMAT_S20_3LE:
179 		iface |= 0x0004;
180 		break;
181 	case SNDRV_PCM_FORMAT_S24_LE:
182 		iface |= 0x0008;
183 		break;
184 	}
185 
186 	snd_soc_write(codec, WM8711_IFACE, iface);
187 	return 0;
188 }
189 
190 static int wm8711_pcm_prepare(struct snd_pcm_substream *substream,
191 			      struct snd_soc_dai *dai)
192 {
193 	struct snd_soc_codec *codec = dai->codec;
194 
195 	/* set active */
196 	snd_soc_write(codec, WM8711_ACTIVE, 0x0001);
197 
198 	return 0;
199 }
200 
201 static void wm8711_shutdown(struct snd_pcm_substream *substream,
202 			    struct snd_soc_dai *dai)
203 {
204 	struct snd_soc_codec *codec = dai->codec;
205 
206 	/* deactivate */
207 	if (!codec->active) {
208 		udelay(50);
209 		snd_soc_write(codec, WM8711_ACTIVE, 0x0);
210 	}
211 }
212 
213 static int wm8711_mute(struct snd_soc_dai *dai, int mute)
214 {
215 	struct snd_soc_codec *codec = dai->codec;
216 	u16 mute_reg = snd_soc_read(codec, WM8711_APDIGI) & 0xfff7;
217 
218 	if (mute)
219 		snd_soc_write(codec, WM8711_APDIGI, mute_reg | 0x8);
220 	else
221 		snd_soc_write(codec, WM8711_APDIGI, mute_reg);
222 
223 	return 0;
224 }
225 
226 static int wm8711_set_dai_sysclk(struct snd_soc_dai *codec_dai,
227 		int clk_id, unsigned int freq, int dir)
228 {
229 	struct snd_soc_codec *codec = codec_dai->codec;
230 	struct wm8711_priv *wm8711 = codec->private_data;
231 
232 	switch (freq) {
233 	case 11289600:
234 	case 12000000:
235 	case 12288000:
236 	case 16934400:
237 	case 18432000:
238 		wm8711->sysclk = freq;
239 		return 0;
240 	}
241 	return -EINVAL;
242 }
243 
244 static int wm8711_set_dai_fmt(struct snd_soc_dai *codec_dai,
245 		unsigned int fmt)
246 {
247 	struct snd_soc_codec *codec = codec_dai->codec;
248 	u16 iface = 0;
249 
250 	/* set master/slave audio interface */
251 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
252 	case SND_SOC_DAIFMT_CBM_CFM:
253 		iface |= 0x0040;
254 		break;
255 	case SND_SOC_DAIFMT_CBS_CFS:
256 		break;
257 	default:
258 		return -EINVAL;
259 	}
260 
261 	/* interface format */
262 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
263 	case SND_SOC_DAIFMT_I2S:
264 		iface |= 0x0002;
265 		break;
266 	case SND_SOC_DAIFMT_RIGHT_J:
267 		break;
268 	case SND_SOC_DAIFMT_LEFT_J:
269 		iface |= 0x0001;
270 		break;
271 	case SND_SOC_DAIFMT_DSP_A:
272 		iface |= 0x0003;
273 		break;
274 	case SND_SOC_DAIFMT_DSP_B:
275 		iface |= 0x0013;
276 		break;
277 	default:
278 		return -EINVAL;
279 	}
280 
281 	/* clock inversion */
282 	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
283 	case SND_SOC_DAIFMT_NB_NF:
284 		break;
285 	case SND_SOC_DAIFMT_IB_IF:
286 		iface |= 0x0090;
287 		break;
288 	case SND_SOC_DAIFMT_IB_NF:
289 		iface |= 0x0080;
290 		break;
291 	case SND_SOC_DAIFMT_NB_IF:
292 		iface |= 0x0010;
293 		break;
294 	default:
295 		return -EINVAL;
296 	}
297 
298 	/* set iface */
299 	snd_soc_write(codec, WM8711_IFACE, iface);
300 	return 0;
301 }
302 
303 
304 static int wm8711_set_bias_level(struct snd_soc_codec *codec,
305 	enum snd_soc_bias_level level)
306 {
307 	u16 reg = snd_soc_read(codec, WM8711_PWR) & 0xff7f;
308 
309 	switch (level) {
310 	case SND_SOC_BIAS_ON:
311 		snd_soc_write(codec, WM8711_PWR, reg);
312 		break;
313 	case SND_SOC_BIAS_PREPARE:
314 		break;
315 	case SND_SOC_BIAS_STANDBY:
316 		snd_soc_write(codec, WM8711_PWR, reg | 0x0040);
317 		break;
318 	case SND_SOC_BIAS_OFF:
319 		snd_soc_write(codec, WM8711_ACTIVE, 0x0);
320 		snd_soc_write(codec, WM8711_PWR, 0xffff);
321 		break;
322 	}
323 	codec->bias_level = level;
324 	return 0;
325 }
326 
327 #define WM8711_RATES SNDRV_PCM_RATE_8000_96000
328 
329 #define WM8711_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
330 	SNDRV_PCM_FMTBIT_S24_LE)
331 
332 static struct snd_soc_dai_ops wm8711_ops = {
333 	.prepare = wm8711_pcm_prepare,
334 	.hw_params = wm8711_hw_params,
335 	.shutdown = wm8711_shutdown,
336 	.digital_mute = wm8711_mute,
337 	.set_sysclk = wm8711_set_dai_sysclk,
338 	.set_fmt = wm8711_set_dai_fmt,
339 };
340 
341 struct snd_soc_dai wm8711_dai = {
342 	.name = "WM8711",
343 	.playback = {
344 		.stream_name = "Playback",
345 		.channels_min = 1,
346 		.channels_max = 2,
347 		.rates = WM8711_RATES,
348 		.formats = WM8711_FORMATS,
349 	},
350 	.ops = &wm8711_ops,
351 };
352 EXPORT_SYMBOL_GPL(wm8711_dai);
353 
354 static int wm8711_suspend(struct platform_device *pdev, pm_message_t state)
355 {
356 	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
357 	struct snd_soc_codec *codec = socdev->card->codec;
358 
359 	snd_soc_write(codec, WM8711_ACTIVE, 0x0);
360 	wm8711_set_bias_level(codec, SND_SOC_BIAS_OFF);
361 	return 0;
362 }
363 
364 static int wm8711_resume(struct platform_device *pdev)
365 {
366 	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
367 	struct snd_soc_codec *codec = socdev->card->codec;
368 	int i;
369 	u8 data[2];
370 	u16 *cache = codec->reg_cache;
371 
372 	/* Sync reg_cache with the hardware */
373 	for (i = 0; i < ARRAY_SIZE(wm8711_reg); i++) {
374 		data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001);
375 		data[1] = cache[i] & 0x00ff;
376 		codec->hw_write(codec->control_data, data, 2);
377 	}
378 	wm8711_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
379 	wm8711_set_bias_level(codec, codec->suspend_bias_level);
380 	return 0;
381 }
382 
383 static int wm8711_probe(struct platform_device *pdev)
384 {
385 	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
386 	struct snd_soc_codec *codec;
387 	int ret = 0;
388 
389 	if (wm8711_codec == NULL) {
390 		dev_err(&pdev->dev, "Codec device not registered\n");
391 		return -ENODEV;
392 	}
393 
394 	socdev->card->codec = wm8711_codec;
395 	codec = wm8711_codec;
396 
397 	/* register pcms */
398 	ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
399 	if (ret < 0) {
400 		dev_err(codec->dev, "failed to create pcms: %d\n", ret);
401 		goto pcm_err;
402 	}
403 
404 	snd_soc_add_controls(codec, wm8711_snd_controls,
405 			     ARRAY_SIZE(wm8711_snd_controls));
406 	wm8711_add_widgets(codec);
407 
408 	return ret;
409 
410 pcm_err:
411 	return ret;
412 }
413 
414 /* power down chip */
415 static int wm8711_remove(struct platform_device *pdev)
416 {
417 	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
418 
419 	snd_soc_free_pcms(socdev);
420 	snd_soc_dapm_free(socdev);
421 
422 	return 0;
423 }
424 
425 struct snd_soc_codec_device soc_codec_dev_wm8711 = {
426 	.probe = 	wm8711_probe,
427 	.remove = 	wm8711_remove,
428 	.suspend = 	wm8711_suspend,
429 	.resume =	wm8711_resume,
430 };
431 EXPORT_SYMBOL_GPL(soc_codec_dev_wm8711);
432 
433 static int wm8711_register(struct wm8711_priv *wm8711,
434 			   enum snd_soc_control_type control)
435 {
436 	int ret;
437 	struct snd_soc_codec *codec = &wm8711->codec;
438 	u16 reg;
439 
440 	if (wm8711_codec) {
441 		dev_err(codec->dev, "Another WM8711 is registered\n");
442 		return -EINVAL;
443 	}
444 
445 	mutex_init(&codec->mutex);
446 	INIT_LIST_HEAD(&codec->dapm_widgets);
447 	INIT_LIST_HEAD(&codec->dapm_paths);
448 
449 	codec->private_data = wm8711;
450 	codec->name = "WM8711";
451 	codec->owner = THIS_MODULE;
452 	codec->bias_level = SND_SOC_BIAS_OFF;
453 	codec->set_bias_level = wm8711_set_bias_level;
454 	codec->dai = &wm8711_dai;
455 	codec->num_dai = 1;
456 	codec->reg_cache_size = WM8711_CACHEREGNUM;
457 	codec->reg_cache = &wm8711->reg_cache;
458 
459 	memcpy(codec->reg_cache, wm8711_reg, sizeof(wm8711_reg));
460 
461 	ret = snd_soc_codec_set_cache_io(codec, 7, 9, control);
462 	if (ret < 0) {
463 		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
464 		goto err;
465 	}
466 
467 	ret = wm8711_reset(codec);
468 	if (ret < 0) {
469 		dev_err(codec->dev, "Failed to issue reset\n");
470 		goto err;
471 	}
472 
473 	wm8711_dai.dev = codec->dev;
474 
475 	wm8711_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
476 
477 	/* Latch the update bits */
478 	reg = snd_soc_read(codec, WM8711_LOUT1V);
479 	snd_soc_write(codec, WM8711_LOUT1V, reg | 0x0100);
480 	reg = snd_soc_read(codec, WM8711_ROUT1V);
481 	snd_soc_write(codec, WM8711_ROUT1V, reg | 0x0100);
482 
483 	wm8711_codec = codec;
484 
485 	ret = snd_soc_register_codec(codec);
486 	if (ret != 0) {
487 		dev_err(codec->dev, "Failed to register codec: %d\n", ret);
488 		goto err;
489 	}
490 
491 	ret = snd_soc_register_dai(&wm8711_dai);
492 	if (ret != 0) {
493 		dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
494 		goto err_codec;
495 	}
496 
497 	return 0;
498 
499 err_codec:
500 	snd_soc_unregister_codec(codec);
501 err:
502 	kfree(wm8711);
503 	return ret;
504 }
505 
506 static void wm8711_unregister(struct wm8711_priv *wm8711)
507 {
508 	wm8711_set_bias_level(&wm8711->codec, SND_SOC_BIAS_OFF);
509 	snd_soc_unregister_dai(&wm8711_dai);
510 	snd_soc_unregister_codec(&wm8711->codec);
511 	kfree(wm8711);
512 	wm8711_codec = NULL;
513 }
514 
515 #if defined(CONFIG_SPI_MASTER)
516 static int __devinit wm8711_spi_probe(struct spi_device *spi)
517 {
518 	struct snd_soc_codec *codec;
519 	struct wm8711_priv *wm8711;
520 
521 	wm8711 = kzalloc(sizeof(struct wm8711_priv), GFP_KERNEL);
522 	if (wm8711 == NULL)
523 		return -ENOMEM;
524 
525 	codec = &wm8711->codec;
526 	codec->control_data = spi;
527 	codec->dev = &spi->dev;
528 
529 	dev_set_drvdata(&spi->dev, wm8711);
530 
531 	return wm8711_register(wm8711, SND_SOC_SPI);
532 }
533 
534 static int __devexit wm8711_spi_remove(struct spi_device *spi)
535 {
536 	struct wm8711_priv *wm8711 = dev_get_drvdata(&spi->dev);
537 
538 	wm8711_unregister(wm8711);
539 
540 	return 0;
541 }
542 
543 static struct spi_driver wm8711_spi_driver = {
544 	.driver = {
545 		.name	= "wm8711",
546 		.bus	= &spi_bus_type,
547 		.owner	= THIS_MODULE,
548 	},
549 	.probe		= wm8711_spi_probe,
550 	.remove		= __devexit_p(wm8711_spi_remove),
551 };
552 #endif /* CONFIG_SPI_MASTER */
553 
554 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
555 static __devinit int wm8711_i2c_probe(struct i2c_client *i2c,
556 				      const struct i2c_device_id *id)
557 {
558 	struct wm8711_priv *wm8711;
559 	struct snd_soc_codec *codec;
560 
561 	wm8711 = kzalloc(sizeof(struct wm8711_priv), GFP_KERNEL);
562 	if (wm8711 == NULL)
563 		return -ENOMEM;
564 
565 	codec = &wm8711->codec;
566 	codec->hw_write = (hw_write_t)i2c_master_send;
567 
568 	i2c_set_clientdata(i2c, wm8711);
569 	codec->control_data = i2c;
570 
571 	codec->dev = &i2c->dev;
572 
573 	return wm8711_register(wm8711, SND_SOC_I2C);
574 }
575 
576 static __devexit int wm8711_i2c_remove(struct i2c_client *client)
577 {
578 	struct wm8711_priv *wm8711 = i2c_get_clientdata(client);
579 	wm8711_unregister(wm8711);
580 	return 0;
581 }
582 
583 static const struct i2c_device_id wm8711_i2c_id[] = {
584 	{ "wm8711", 0 },
585 	{ }
586 };
587 MODULE_DEVICE_TABLE(i2c, wm8711_i2c_id);
588 
589 static struct i2c_driver wm8711_i2c_driver = {
590 	.driver = {
591 		.name = "WM8711 I2C Codec",
592 		.owner = THIS_MODULE,
593 	},
594 	.probe =    wm8711_i2c_probe,
595 	.remove =   __devexit_p(wm8711_i2c_remove),
596 	.id_table = wm8711_i2c_id,
597 };
598 #endif
599 
600 static int __init wm8711_modinit(void)
601 {
602 	int ret;
603 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
604 	ret = i2c_add_driver(&wm8711_i2c_driver);
605 	if (ret != 0) {
606 		printk(KERN_ERR "Failed to register WM8711 I2C driver: %d\n",
607 		       ret);
608 	}
609 #endif
610 #if defined(CONFIG_SPI_MASTER)
611 	ret = spi_register_driver(&wm8711_spi_driver);
612 	if (ret != 0) {
613 		printk(KERN_ERR "Failed to register WM8711 SPI driver: %d\n",
614 		       ret);
615 	}
616 #endif
617 	return 0;
618 }
619 module_init(wm8711_modinit);
620 
621 static void __exit wm8711_exit(void)
622 {
623 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
624 	i2c_del_driver(&wm8711_i2c_driver);
625 #endif
626 #if defined(CONFIG_SPI_MASTER)
627 	spi_unregister_driver(&wm8711_spi_driver);
628 #endif
629 }
630 module_exit(wm8711_exit);
631 
632 MODULE_DESCRIPTION("ASoC WM8711 driver");
633 MODULE_AUTHOR("Mike Arthur");
634 MODULE_LICENSE("GPL");
635