xref: /linux/sound/soc/codecs/wm8728.c (revision d39d0ed196aa1685bb24771e92f78633c66ac9cb)
1 /*
2  * wm8728.c  --  WM8728 ALSA SoC Audio driver
3  *
4  * Copyright 2008 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 
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/i2c.h>
19 #include <linux/platform_device.h>
20 #include <linux/spi/spi.h>
21 #include <linux/slab.h>
22 #include <sound/core.h>
23 #include <sound/pcm.h>
24 #include <sound/pcm_params.h>
25 #include <sound/soc.h>
26 #include <sound/soc-dapm.h>
27 #include <sound/initval.h>
28 #include <sound/tlv.h>
29 
30 #include "wm8728.h"
31 
32 struct snd_soc_codec_device soc_codec_dev_wm8728;
33 
34 /*
35  * We can't read the WM8728 register space so we cache them instead.
36  * Note that the defaults here aren't the physical defaults, we latch
37  * the volume update bits, mute the output and enable infinite zero
38  * detect.
39  */
40 static const u16 wm8728_reg_defaults[] = {
41 	0x1ff,
42 	0x1ff,
43 	0x001,
44 	0x100,
45 };
46 
47 static const DECLARE_TLV_DB_SCALE(wm8728_tlv, -12750, 50, 1);
48 
49 static const struct snd_kcontrol_new wm8728_snd_controls[] = {
50 
51 SOC_DOUBLE_R_TLV("Digital Playback Volume", WM8728_DACLVOL, WM8728_DACRVOL,
52 		 0, 255, 0, wm8728_tlv),
53 
54 SOC_SINGLE("Deemphasis", WM8728_DACCTL, 1, 1, 0),
55 };
56 
57 /*
58  * DAPM controls.
59  */
60 static const struct snd_soc_dapm_widget wm8728_dapm_widgets[] = {
61 SND_SOC_DAPM_DAC("DAC", "HiFi Playback", SND_SOC_NOPM, 0, 0),
62 SND_SOC_DAPM_OUTPUT("VOUTL"),
63 SND_SOC_DAPM_OUTPUT("VOUTR"),
64 };
65 
66 static const struct snd_soc_dapm_route intercon[] = {
67 	{"VOUTL", NULL, "DAC"},
68 	{"VOUTR", NULL, "DAC"},
69 };
70 
71 static int wm8728_add_widgets(struct snd_soc_codec *codec)
72 {
73 	snd_soc_dapm_new_controls(codec, wm8728_dapm_widgets,
74 				  ARRAY_SIZE(wm8728_dapm_widgets));
75 
76 	snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon));
77 
78 	return 0;
79 }
80 
81 static int wm8728_mute(struct snd_soc_dai *dai, int mute)
82 {
83 	struct snd_soc_codec *codec = dai->codec;
84 	u16 mute_reg = snd_soc_read(codec, WM8728_DACCTL);
85 
86 	if (mute)
87 		snd_soc_write(codec, WM8728_DACCTL, mute_reg | 1);
88 	else
89 		snd_soc_write(codec, WM8728_DACCTL, mute_reg & ~1);
90 
91 	return 0;
92 }
93 
94 static int wm8728_hw_params(struct snd_pcm_substream *substream,
95 	struct snd_pcm_hw_params *params,
96 	struct snd_soc_dai *dai)
97 {
98 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
99 	struct snd_soc_device *socdev = rtd->socdev;
100 	struct snd_soc_codec *codec = socdev->card->codec;
101 	u16 dac = snd_soc_read(codec, WM8728_DACCTL);
102 
103 	dac &= ~0x18;
104 
105 	switch (params_format(params)) {
106 	case SNDRV_PCM_FORMAT_S16_LE:
107 		break;
108 	case SNDRV_PCM_FORMAT_S20_3LE:
109 		dac |= 0x10;
110 		break;
111 	case SNDRV_PCM_FORMAT_S24_LE:
112 		dac |= 0x08;
113 		break;
114 	default:
115 		return -EINVAL;
116 	}
117 
118 	snd_soc_write(codec, WM8728_DACCTL, dac);
119 
120 	return 0;
121 }
122 
123 static int wm8728_set_dai_fmt(struct snd_soc_dai *codec_dai,
124 		unsigned int fmt)
125 {
126 	struct snd_soc_codec *codec = codec_dai->codec;
127 	u16 iface = snd_soc_read(codec, WM8728_IFCTL);
128 
129 	/* Currently only I2S is supported by the driver, though the
130 	 * hardware is more flexible.
131 	 */
132 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
133 	case SND_SOC_DAIFMT_I2S:
134 		iface |= 1;
135 		break;
136 	default:
137 		return -EINVAL;
138 	}
139 
140 	/* The hardware only support full slave mode */
141 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
142 	case SND_SOC_DAIFMT_CBS_CFS:
143 		break;
144 	default:
145 		return -EINVAL;
146 	}
147 
148 	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
149 	case SND_SOC_DAIFMT_NB_NF:
150 		iface &= ~0x22;
151 		break;
152 	case SND_SOC_DAIFMT_IB_NF:
153 		iface |=  0x20;
154 		iface &= ~0x02;
155 		break;
156 	case SND_SOC_DAIFMT_NB_IF:
157 		iface |= 0x02;
158 		iface &= ~0x20;
159 		break;
160 	case SND_SOC_DAIFMT_IB_IF:
161 		iface |= 0x22;
162 		break;
163 	default:
164 		return -EINVAL;
165 	}
166 
167 	snd_soc_write(codec, WM8728_IFCTL, iface);
168 	return 0;
169 }
170 
171 static int wm8728_set_bias_level(struct snd_soc_codec *codec,
172 				 enum snd_soc_bias_level level)
173 {
174 	u16 reg;
175 	int i;
176 
177 	switch (level) {
178 	case SND_SOC_BIAS_ON:
179 	case SND_SOC_BIAS_PREPARE:
180 	case SND_SOC_BIAS_STANDBY:
181 		if (codec->bias_level == SND_SOC_BIAS_OFF) {
182 			/* Power everything up... */
183 			reg = snd_soc_read(codec, WM8728_DACCTL);
184 			snd_soc_write(codec, WM8728_DACCTL, reg & ~0x4);
185 
186 			/* ..then sync in the register cache. */
187 			for (i = 0; i < ARRAY_SIZE(wm8728_reg_defaults); i++)
188 				snd_soc_write(codec, i,
189 					     snd_soc_read(codec, i));
190 		}
191 		break;
192 
193 	case SND_SOC_BIAS_OFF:
194 		reg = snd_soc_read(codec, WM8728_DACCTL);
195 		snd_soc_write(codec, WM8728_DACCTL, reg | 0x4);
196 		break;
197 	}
198 	codec->bias_level = level;
199 	return 0;
200 }
201 
202 #define WM8728_RATES (SNDRV_PCM_RATE_8000_192000)
203 
204 #define WM8728_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
205 	SNDRV_PCM_FMTBIT_S24_LE)
206 
207 static struct snd_soc_dai_ops wm8728_dai_ops = {
208 	.hw_params	= wm8728_hw_params,
209 	.digital_mute	= wm8728_mute,
210 	.set_fmt	= wm8728_set_dai_fmt,
211 };
212 
213 struct snd_soc_dai wm8728_dai = {
214 	.name = "WM8728",
215 	.playback = {
216 		.stream_name = "Playback",
217 		.channels_min = 2,
218 		.channels_max = 2,
219 		.rates = WM8728_RATES,
220 		.formats = WM8728_FORMATS,
221 	},
222 	.ops = &wm8728_dai_ops,
223 };
224 EXPORT_SYMBOL_GPL(wm8728_dai);
225 
226 static int wm8728_suspend(struct platform_device *pdev, pm_message_t state)
227 {
228 	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
229 	struct snd_soc_codec *codec = socdev->card->codec;
230 
231 	wm8728_set_bias_level(codec, SND_SOC_BIAS_OFF);
232 
233 	return 0;
234 }
235 
236 static int wm8728_resume(struct platform_device *pdev)
237 {
238 	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
239 	struct snd_soc_codec *codec = socdev->card->codec;
240 
241 	wm8728_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
242 
243 	return 0;
244 }
245 
246 /*
247  * initialise the WM8728 driver
248  * register the mixer and dsp interfaces with the kernel
249  */
250 static int wm8728_init(struct snd_soc_device *socdev,
251 		       enum snd_soc_control_type control)
252 {
253 	struct snd_soc_codec *codec = socdev->card->codec;
254 	int ret = 0;
255 
256 	codec->name = "WM8728";
257 	codec->owner = THIS_MODULE;
258 	codec->set_bias_level = wm8728_set_bias_level;
259 	codec->dai = &wm8728_dai;
260 	codec->num_dai = 1;
261 	codec->bias_level = SND_SOC_BIAS_OFF;
262 	codec->reg_cache_size = ARRAY_SIZE(wm8728_reg_defaults);
263 	codec->reg_cache = kmemdup(wm8728_reg_defaults,
264 				   sizeof(wm8728_reg_defaults),
265 				   GFP_KERNEL);
266 	if (codec->reg_cache == NULL)
267 		return -ENOMEM;
268 
269 	ret = snd_soc_codec_set_cache_io(codec, 7, 9, control);
270 	if (ret < 0) {
271 		printk(KERN_ERR "wm8728: failed to configure cache I/O: %d\n",
272 		       ret);
273 		goto err;
274 	}
275 
276 	/* register pcms */
277 	ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
278 	if (ret < 0) {
279 		printk(KERN_ERR "wm8728: failed to create pcms\n");
280 		goto err;
281 	}
282 
283 	/* power on device */
284 	wm8728_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
285 
286 	snd_soc_add_controls(codec, wm8728_snd_controls,
287 				ARRAY_SIZE(wm8728_snd_controls));
288 	wm8728_add_widgets(codec);
289 
290 	return ret;
291 
292 err:
293 	kfree(codec->reg_cache);
294 	return ret;
295 }
296 
297 static struct snd_soc_device *wm8728_socdev;
298 
299 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
300 
301 /*
302  * WM8728 2 wire address is determined by GPIO5
303  * state during powerup.
304  *    low  = 0x1a
305  *    high = 0x1b
306  */
307 
308 static int wm8728_i2c_probe(struct i2c_client *i2c,
309 			    const struct i2c_device_id *id)
310 {
311 	struct snd_soc_device *socdev = wm8728_socdev;
312 	struct snd_soc_codec *codec = socdev->card->codec;
313 	int ret;
314 
315 	i2c_set_clientdata(i2c, codec);
316 	codec->control_data = i2c;
317 
318 	ret = wm8728_init(socdev, SND_SOC_I2C);
319 	if (ret < 0)
320 		pr_err("failed to initialise WM8728\n");
321 
322 	return ret;
323 }
324 
325 static int wm8728_i2c_remove(struct i2c_client *client)
326 {
327 	struct snd_soc_codec *codec = i2c_get_clientdata(client);
328 	kfree(codec->reg_cache);
329 	return 0;
330 }
331 
332 static const struct i2c_device_id wm8728_i2c_id[] = {
333 	{ "wm8728", 0 },
334 	{ }
335 };
336 MODULE_DEVICE_TABLE(i2c, wm8728_i2c_id);
337 
338 static struct i2c_driver wm8728_i2c_driver = {
339 	.driver = {
340 		.name = "WM8728 I2C Codec",
341 		.owner = THIS_MODULE,
342 	},
343 	.probe =    wm8728_i2c_probe,
344 	.remove =   wm8728_i2c_remove,
345 	.id_table = wm8728_i2c_id,
346 };
347 
348 static int wm8728_add_i2c_device(struct platform_device *pdev,
349 				 const struct wm8728_setup_data *setup)
350 {
351 	struct i2c_board_info info;
352 	struct i2c_adapter *adapter;
353 	struct i2c_client *client;
354 	int ret;
355 
356 	ret = i2c_add_driver(&wm8728_i2c_driver);
357 	if (ret != 0) {
358 		dev_err(&pdev->dev, "can't add i2c driver\n");
359 		return ret;
360 	}
361 
362 	memset(&info, 0, sizeof(struct i2c_board_info));
363 	info.addr = setup->i2c_address;
364 	strlcpy(info.type, "wm8728", I2C_NAME_SIZE);
365 
366 	adapter = i2c_get_adapter(setup->i2c_bus);
367 	if (!adapter) {
368 		dev_err(&pdev->dev, "can't get i2c adapter %d\n",
369 			setup->i2c_bus);
370 		goto err_driver;
371 	}
372 
373 	client = i2c_new_device(adapter, &info);
374 	i2c_put_adapter(adapter);
375 	if (!client) {
376 		dev_err(&pdev->dev, "can't add i2c device at 0x%x\n",
377 			(unsigned int)info.addr);
378 		goto err_driver;
379 	}
380 
381 	return 0;
382 
383 err_driver:
384 	i2c_del_driver(&wm8728_i2c_driver);
385 	return -ENODEV;
386 }
387 #endif
388 
389 #if defined(CONFIG_SPI_MASTER)
390 static int __devinit wm8728_spi_probe(struct spi_device *spi)
391 {
392 	struct snd_soc_device *socdev = wm8728_socdev;
393 	struct snd_soc_codec *codec = socdev->card->codec;
394 	int ret;
395 
396 	codec->control_data = spi;
397 
398 	ret = wm8728_init(socdev, SND_SOC_SPI);
399 	if (ret < 0)
400 		dev_err(&spi->dev, "failed to initialise WM8728\n");
401 
402 	return ret;
403 }
404 
405 static int __devexit wm8728_spi_remove(struct spi_device *spi)
406 {
407 	return 0;
408 }
409 
410 static struct spi_driver wm8728_spi_driver = {
411 	.driver = {
412 		.name	= "wm8728",
413 		.bus	= &spi_bus_type,
414 		.owner	= THIS_MODULE,
415 	},
416 	.probe		= wm8728_spi_probe,
417 	.remove		= __devexit_p(wm8728_spi_remove),
418 };
419 #endif /* CONFIG_SPI_MASTER */
420 
421 static int wm8728_probe(struct platform_device *pdev)
422 {
423 	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
424 	struct wm8728_setup_data *setup;
425 	struct snd_soc_codec *codec;
426 	int ret = 0;
427 
428 	setup = socdev->codec_data;
429 	codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
430 	if (codec == NULL)
431 		return -ENOMEM;
432 
433 	socdev->card->codec = codec;
434 	mutex_init(&codec->mutex);
435 	INIT_LIST_HEAD(&codec->dapm_widgets);
436 	INIT_LIST_HEAD(&codec->dapm_paths);
437 
438 	wm8728_socdev = socdev;
439 	ret = -ENODEV;
440 
441 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
442 	if (setup->i2c_address) {
443 		ret = wm8728_add_i2c_device(pdev, setup);
444 	}
445 #endif
446 #if defined(CONFIG_SPI_MASTER)
447 	if (setup->spi) {
448 		ret = spi_register_driver(&wm8728_spi_driver);
449 		if (ret != 0)
450 			printk(KERN_ERR "can't add spi driver");
451 	}
452 #endif
453 
454 	if (ret != 0)
455 		kfree(codec);
456 
457 	return ret;
458 }
459 
460 /* power down chip */
461 static int wm8728_remove(struct platform_device *pdev)
462 {
463 	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
464 	struct snd_soc_codec *codec = socdev->card->codec;
465 
466 	if (codec->control_data)
467 		wm8728_set_bias_level(codec, SND_SOC_BIAS_OFF);
468 
469 	snd_soc_free_pcms(socdev);
470 	snd_soc_dapm_free(socdev);
471 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
472 	i2c_unregister_device(codec->control_data);
473 	i2c_del_driver(&wm8728_i2c_driver);
474 #endif
475 #if defined(CONFIG_SPI_MASTER)
476 	spi_unregister_driver(&wm8728_spi_driver);
477 #endif
478 	kfree(codec);
479 
480 	return 0;
481 }
482 
483 struct snd_soc_codec_device soc_codec_dev_wm8728 = {
484 	.probe = 	wm8728_probe,
485 	.remove = 	wm8728_remove,
486 	.suspend = 	wm8728_suspend,
487 	.resume =	wm8728_resume,
488 };
489 EXPORT_SYMBOL_GPL(soc_codec_dev_wm8728);
490 
491 static int __init wm8728_modinit(void)
492 {
493 	return snd_soc_register_dai(&wm8728_dai);
494 }
495 module_init(wm8728_modinit);
496 
497 static void __exit wm8728_exit(void)
498 {
499 	snd_soc_unregister_dai(&wm8728_dai);
500 }
501 module_exit(wm8728_exit);
502 
503 MODULE_DESCRIPTION("ASoC WM8728 driver");
504 MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
505 MODULE_LICENSE("GPL");
506