aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/codecs/wm8776.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/codecs/wm8776.c')
-rw-r--r--sound/soc/codecs/wm8776.c251
1 files changed, 66 insertions, 185 deletions
diff --git a/sound/soc/codecs/wm8776.c b/sound/soc/codecs/wm8776.c
index 4e212ed62ea6..51a2d265d40e 100644
--- a/sound/soc/codecs/wm8776.c
+++ b/sound/soc/codecs/wm8776.c
@@ -31,20 +31,14 @@
31 31
32#include "wm8776.h" 32#include "wm8776.h"
33 33
34static struct snd_soc_codec *wm8776_codec;
35struct snd_soc_codec_device soc_codec_dev_wm8776;
36
37/* codec private data */ 34/* codec private data */
38struct wm8776_priv { 35struct wm8776_priv {
39 struct snd_soc_codec codec; 36 enum snd_soc_control_type control_type;
37 void *control_data;
40 u16 reg_cache[WM8776_CACHEREGNUM]; 38 u16 reg_cache[WM8776_CACHEREGNUM];
41 int sysclk[2]; 39 int sysclk[2];
42}; 40};
43 41
44#ifdef CONFIG_SPI_MASTER
45static int wm8776_spi_write(struct spi_device *spi, const char *data, int len);
46#endif
47
48static const u16 wm8776_reg[WM8776_CACHEREGNUM] = { 42static const u16 wm8776_reg[WM8776_CACHEREGNUM] = {
49 0x79, 0x79, 0x79, 0xff, 0xff, /* 4 */ 43 0x79, 0x79, 0x79, 0xff, 0xff, /* 4 */
50 0xff, 0x00, 0x90, 0x00, 0x00, /* 9 */ 44 0xff, 0x00, 0x90, 0x00, 0x00, /* 9 */
@@ -144,7 +138,7 @@ static int wm8776_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
144 struct snd_soc_codec *codec = dai->codec; 138 struct snd_soc_codec *codec = dai->codec;
145 int reg, iface, master; 139 int reg, iface, master;
146 140
147 switch (dai->id) { 141 switch (dai->driver->id) {
148 case WM8776_DAI_DAC: 142 case WM8776_DAI_DAC:
149 reg = WM8776_DACIFCTRL; 143 reg = WM8776_DACIFCTRL;
150 master = 0x80; 144 master = 0x80;
@@ -233,7 +227,7 @@ static int wm8776_hw_params(struct snd_pcm_substream *substream,
233 227
234 iface = 0; 228 iface = 0;
235 229
236 switch (dai->id) { 230 switch (dai->driver->id) {
237 case WM8776_DAI_DAC: 231 case WM8776_DAI_DAC:
238 iface_reg = WM8776_DACIFCTRL; 232 iface_reg = WM8776_DACIFCTRL;
239 master = 0x80; 233 master = 0x80;
@@ -267,7 +261,7 @@ static int wm8776_hw_params(struct snd_pcm_substream *substream,
267 /* Only need to set MCLK/LRCLK ratio if we're master */ 261 /* Only need to set MCLK/LRCLK ratio if we're master */
268 if (snd_soc_read(codec, WM8776_MSTRCTRL) & master) { 262 if (snd_soc_read(codec, WM8776_MSTRCTRL) & master) {
269 for (i = 0; i < ARRAY_SIZE(mclk_ratios); i++) { 263 for (i = 0; i < ARRAY_SIZE(mclk_ratios); i++) {
270 if (wm8776->sysclk[dai->id] / params_rate(params) 264 if (wm8776->sysclk[dai->driver->id] / params_rate(params)
271 == mclk_ratios[i]) 265 == mclk_ratios[i])
272 break; 266 break;
273 } 267 }
@@ -275,7 +269,7 @@ static int wm8776_hw_params(struct snd_pcm_substream *substream,
275 if (i == ARRAY_SIZE(mclk_ratios)) { 269 if (i == ARRAY_SIZE(mclk_ratios)) {
276 dev_err(codec->dev, 270 dev_err(codec->dev,
277 "Unable to configure MCLK ratio %d/%d\n", 271 "Unable to configure MCLK ratio %d/%d\n",
278 wm8776->sysclk[dai->id], params_rate(params)); 272 wm8776->sysclk[dai->driver->id], params_rate(params));
279 return -EINVAL; 273 return -EINVAL;
280 } 274 }
281 275
@@ -305,9 +299,9 @@ static int wm8776_set_sysclk(struct snd_soc_dai *dai,
305 struct snd_soc_codec *codec = dai->codec; 299 struct snd_soc_codec *codec = dai->codec;
306 struct wm8776_priv *wm8776 = snd_soc_codec_get_drvdata(codec); 300 struct wm8776_priv *wm8776 = snd_soc_codec_get_drvdata(codec);
307 301
308 BUG_ON(dai->id >= ARRAY_SIZE(wm8776->sysclk)); 302 BUG_ON(dai->driver->id >= ARRAY_SIZE(wm8776->sysclk));
309 303
310 wm8776->sysclk[dai->id] = freq; 304 wm8776->sysclk[dai->driver->id] = freq;
311 305
312 return 0; 306 return 0;
313} 307}
@@ -357,10 +351,10 @@ static struct snd_soc_dai_ops wm8776_adc_ops = {
357 .set_sysclk = wm8776_set_sysclk, 351 .set_sysclk = wm8776_set_sysclk,
358}; 352};
359 353
360struct snd_soc_dai wm8776_dai[] = { 354static struct snd_soc_dai_driver wm8776_dai[] = {
361 { 355 {
362 .name = "WM8776 Playback", 356 .name = "wm8776-hifi-playback",
363 .id = WM8776_DAI_DAC, 357 .id = WM8776_DAI_DAC,
364 .playback = { 358 .playback = {
365 .stream_name = "Playback", 359 .stream_name = "Playback",
366 .channels_min = 2, 360 .channels_min = 2,
@@ -371,8 +365,8 @@ struct snd_soc_dai wm8776_dai[] = {
371 .ops = &wm8776_dac_ops, 365 .ops = &wm8776_dac_ops,
372 }, 366 },
373 { 367 {
374 .name = "WM8776 Capture", 368 .name = "wm8776-hifi-capture",
375 .id = WM8776_DAI_ADC, 369 .id = WM8776_DAI_ADC,
376 .capture = { 370 .capture = {
377 .stream_name = "Capture", 371 .stream_name = "Capture",
378 .channels_min = 2, 372 .channels_min = 2,
@@ -383,23 +377,17 @@ struct snd_soc_dai wm8776_dai[] = {
383 .ops = &wm8776_adc_ops, 377 .ops = &wm8776_adc_ops,
384 }, 378 },
385}; 379};
386EXPORT_SYMBOL_GPL(wm8776_dai);
387 380
388#ifdef CONFIG_PM 381#ifdef CONFIG_PM
389static int wm8776_suspend(struct platform_device *pdev, pm_message_t state) 382static int wm8776_suspend(struct snd_soc_codec *codec, pm_message_t state)
390{ 383{
391 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
392 struct snd_soc_codec *codec = socdev->card->codec;
393
394 wm8776_set_bias_level(codec, SND_SOC_BIAS_OFF); 384 wm8776_set_bias_level(codec, SND_SOC_BIAS_OFF);
395 385
396 return 0; 386 return 0;
397} 387}
398 388
399static int wm8776_resume(struct platform_device *pdev) 389static int wm8776_resume(struct snd_soc_codec *codec)
400{ 390{
401 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
402 struct snd_soc_codec *codec = socdev->card->codec;
403 int i; 391 int i;
404 u8 data[2]; 392 u8 data[2];
405 u16 *cache = codec->reg_cache; 393 u16 *cache = codec->reg_cache;
@@ -422,27 +410,31 @@ static int wm8776_resume(struct platform_device *pdev)
422#define wm8776_resume NULL 410#define wm8776_resume NULL
423#endif 411#endif
424 412
425static int wm8776_probe(struct platform_device *pdev) 413static int wm8776_probe(struct snd_soc_codec *codec)
426{ 414{
427 struct snd_soc_device *socdev = platform_get_drvdata(pdev); 415 struct wm8776_priv *wm8776 = snd_soc_codec_get_drvdata(codec);
428 struct snd_soc_codec *codec;
429 int ret = 0; 416 int ret = 0;
430 417
431 if (wm8776_codec == NULL) { 418 codec->control_data = wm8776->control_data;
432 dev_err(&pdev->dev, "Codec device not registered\n"); 419 ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8776->control_type);
433 return -ENODEV; 420 if (ret < 0) {
421 dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
422 return ret;
434 } 423 }
435 424
436 socdev->card->codec = wm8776_codec; 425 ret = wm8776_reset(codec);
437 codec = wm8776_codec;
438
439 /* register pcms */
440 ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
441 if (ret < 0) { 426 if (ret < 0) {
442 dev_err(codec->dev, "failed to create pcms: %d\n", ret); 427 dev_err(codec->dev, "Failed to issue reset: %d\n", ret);
443 goto pcm_err; 428 return ret;
444 } 429 }
445 430
431 wm8776_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
432
433 /* Latch the update bits; right channel only since we always
434 * update both. */
435 snd_soc_update_bits(codec, WM8776_HPRVOL, 0x100, 0x100);
436 snd_soc_update_bits(codec, WM8776_DACRVOL, 0x100, 0x100);
437
446 snd_soc_add_controls(codec, wm8776_snd_controls, 438 snd_soc_add_controls(codec, wm8776_snd_controls,
447 ARRAY_SIZE(wm8776_snd_controls)); 439 ARRAY_SIZE(wm8776_snd_controls));
448 snd_soc_dapm_new_controls(codec, wm8776_dapm_widgets, 440 snd_soc_dapm_new_controls(codec, wm8776_dapm_widgets,
@@ -450,168 +442,57 @@ static int wm8776_probe(struct platform_device *pdev)
450 snd_soc_dapm_add_routes(codec, routes, ARRAY_SIZE(routes)); 442 snd_soc_dapm_add_routes(codec, routes, ARRAY_SIZE(routes));
451 443
452 return ret; 444 return ret;
453
454pcm_err:
455 return ret;
456} 445}
457 446
458/* power down chip */ 447/* power down chip */
459static int wm8776_remove(struct platform_device *pdev) 448static int wm8776_remove(struct snd_soc_codec *codec)
460{ 449{
461 struct snd_soc_device *socdev = platform_get_drvdata(pdev); 450 wm8776_set_bias_level(codec, SND_SOC_BIAS_OFF);
462
463 snd_soc_free_pcms(socdev);
464 snd_soc_dapm_free(socdev);
465
466 return 0; 451 return 0;
467} 452}
468 453
469struct snd_soc_codec_device soc_codec_dev_wm8776 = { 454static struct snd_soc_codec_driver soc_codec_dev_wm8776 = {
470 .probe = wm8776_probe, 455 .probe = wm8776_probe,
471 .remove = wm8776_remove, 456 .remove = wm8776_remove,
472 .suspend = wm8776_suspend, 457 .suspend = wm8776_suspend,
473 .resume = wm8776_resume, 458 .resume = wm8776_resume,
459 .set_bias_level = wm8776_set_bias_level,
460 .reg_cache_size = sizeof(wm8776_reg),
461 .reg_word_size = sizeof(u16),
462 .reg_cache_default = wm8776_reg,
474}; 463};
475EXPORT_SYMBOL_GPL(soc_codec_dev_wm8776);
476
477static int wm8776_register(struct wm8776_priv *wm8776,
478 enum snd_soc_control_type control)
479{
480 int ret, i;
481 struct snd_soc_codec *codec = &wm8776->codec;
482
483 if (wm8776_codec) {
484 dev_err(codec->dev, "Another WM8776 is registered\n");
485 ret = -EINVAL;
486 goto err;
487 }
488
489 mutex_init(&codec->mutex);
490 INIT_LIST_HEAD(&codec->dapm_widgets);
491 INIT_LIST_HEAD(&codec->dapm_paths);
492
493 snd_soc_codec_set_drvdata(codec, wm8776);
494 codec->name = "WM8776";
495 codec->owner = THIS_MODULE;
496 codec->bias_level = SND_SOC_BIAS_OFF;
497 codec->set_bias_level = wm8776_set_bias_level;
498 codec->dai = wm8776_dai;
499 codec->num_dai = ARRAY_SIZE(wm8776_dai);
500 codec->reg_cache_size = WM8776_CACHEREGNUM;
501 codec->reg_cache = &wm8776->reg_cache;
502
503 memcpy(codec->reg_cache, wm8776_reg, sizeof(wm8776_reg));
504
505 ret = snd_soc_codec_set_cache_io(codec, 7, 9, control);
506 if (ret < 0) {
507 dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
508 goto err;
509 }
510
511 for (i = 0; i < ARRAY_SIZE(wm8776_dai); i++)
512 wm8776_dai[i].dev = codec->dev;
513
514 ret = wm8776_reset(codec);
515 if (ret < 0) {
516 dev_err(codec->dev, "Failed to issue reset: %d\n", ret);
517 goto err;
518 }
519
520 wm8776_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
521
522 /* Latch the update bits; right channel only since we always
523 * update both. */
524 snd_soc_update_bits(codec, WM8776_HPRVOL, 0x100, 0x100);
525 snd_soc_update_bits(codec, WM8776_DACRVOL, 0x100, 0x100);
526
527 wm8776_codec = codec;
528
529 ret = snd_soc_register_codec(codec);
530 if (ret != 0) {
531 dev_err(codec->dev, "Failed to register codec: %d\n", ret);
532 goto err;
533 }
534
535 ret = snd_soc_register_dais(wm8776_dai, ARRAY_SIZE(wm8776_dai));
536 if (ret != 0) {
537 dev_err(codec->dev, "Failed to register DAIs: %d\n", ret);
538 goto err_codec;
539 }
540
541 return 0;
542
543err_codec:
544 snd_soc_unregister_codec(codec);
545err:
546 kfree(wm8776);
547 return ret;
548}
549
550static void wm8776_unregister(struct wm8776_priv *wm8776)
551{
552 wm8776_set_bias_level(&wm8776->codec, SND_SOC_BIAS_OFF);
553 snd_soc_unregister_dais(wm8776_dai, ARRAY_SIZE(wm8776_dai));
554 snd_soc_unregister_codec(&wm8776->codec);
555 kfree(wm8776);
556 wm8776_codec = NULL;
557}
558 464
559#if defined(CONFIG_SPI_MASTER) 465#if defined(CONFIG_SPI_MASTER)
560static int wm8776_spi_write(struct spi_device *spi, const char *data, int len)
561{
562 struct spi_transfer t;
563 struct spi_message m;
564 u8 msg[2];
565
566 if (len <= 0)
567 return 0;
568
569 msg[0] = data[0];
570 msg[1] = data[1];
571
572 spi_message_init(&m);
573 memset(&t, 0, (sizeof t));
574
575 t.tx_buf = &msg[0];
576 t.len = len;
577
578 spi_message_add_tail(&t, &m);
579 spi_sync(spi, &m);
580
581 return len;
582}
583
584static int __devinit wm8776_spi_probe(struct spi_device *spi) 466static int __devinit wm8776_spi_probe(struct spi_device *spi)
585{ 467{
586 struct snd_soc_codec *codec;
587 struct wm8776_priv *wm8776; 468 struct wm8776_priv *wm8776;
469 int ret;
588 470
589 wm8776 = kzalloc(sizeof(struct wm8776_priv), GFP_KERNEL); 471 wm8776 = kzalloc(sizeof(struct wm8776_priv), GFP_KERNEL);
590 if (wm8776 == NULL) 472 if (wm8776 == NULL)
591 return -ENOMEM; 473 return -ENOMEM;
592 474
593 codec = &wm8776->codec; 475 wm8776->control_data = spi;
594 codec->control_data = spi; 476 wm8776->control_type = SND_SOC_SPI;
595 codec->hw_write = (hw_write_t)wm8776_spi_write; 477 spi_set_drvdata(spi, wm8776);
596 codec->dev = &spi->dev;
597 478
598 dev_set_drvdata(&spi->dev, wm8776); 479 ret = snd_soc_register_codec(&spi->dev,
599 480 &soc_codec_dev_wm8776, wm8776_dai, ARRAY_SIZE(wm8776_dai));
600 return wm8776_register(wm8776, SND_SOC_SPI); 481 if (ret < 0)
482 kfree(wm8776);
483 return ret;
601} 484}
602 485
603static int __devexit wm8776_spi_remove(struct spi_device *spi) 486static int __devexit wm8776_spi_remove(struct spi_device *spi)
604{ 487{
605 struct wm8776_priv *wm8776 = dev_get_drvdata(&spi->dev); 488 snd_soc_unregister_codec(&spi->dev);
606 489 kfree(spi_get_drvdata(spi));
607 wm8776_unregister(wm8776);
608
609 return 0; 490 return 0;
610} 491}
611 492
612static struct spi_driver wm8776_spi_driver = { 493static struct spi_driver wm8776_spi_driver = {
613 .driver = { 494 .driver = {
614 .name = "wm8776", 495 .name = "wm8776-codec",
615 .bus = &spi_bus_type, 496 .bus = &spi_bus_type,
616 .owner = THIS_MODULE, 497 .owner = THIS_MODULE,
617 }, 498 },
@@ -625,27 +506,27 @@ static __devinit int wm8776_i2c_probe(struct i2c_client *i2c,
625 const struct i2c_device_id *id) 506 const struct i2c_device_id *id)
626{ 507{
627 struct wm8776_priv *wm8776; 508 struct wm8776_priv *wm8776;
628 struct snd_soc_codec *codec; 509 int ret;
629 510
630 wm8776 = kzalloc(sizeof(struct wm8776_priv), GFP_KERNEL); 511 wm8776 = kzalloc(sizeof(struct wm8776_priv), GFP_KERNEL);
631 if (wm8776 == NULL) 512 if (wm8776 == NULL)
632 return -ENOMEM; 513 return -ENOMEM;
633 514
634 codec = &wm8776->codec;
635 codec->hw_write = (hw_write_t)i2c_master_send;
636
637 i2c_set_clientdata(i2c, wm8776); 515 i2c_set_clientdata(i2c, wm8776);
638 codec->control_data = i2c; 516 wm8776->control_data = i2c;
639 517 wm8776->control_type = SND_SOC_I2C;
640 codec->dev = &i2c->dev;
641 518
642 return wm8776_register(wm8776, SND_SOC_I2C); 519 ret = snd_soc_register_codec(&i2c->dev,
520 &soc_codec_dev_wm8776, wm8776_dai, ARRAY_SIZE(wm8776_dai));
521 if (ret < 0)
522 kfree(wm8776);
523 return ret;
643} 524}
644 525
645static __devexit int wm8776_i2c_remove(struct i2c_client *client) 526static __devexit int wm8776_i2c_remove(struct i2c_client *client)
646{ 527{
647 struct wm8776_priv *wm8776 = i2c_get_clientdata(client); 528 snd_soc_unregister_codec(&client->dev);
648 wm8776_unregister(wm8776); 529 kfree(i2c_get_clientdata(client));
649 return 0; 530 return 0;
650} 531}
651 532
@@ -657,7 +538,7 @@ MODULE_DEVICE_TABLE(i2c, wm8776_i2c_id);
657 538
658static struct i2c_driver wm8776_i2c_driver = { 539static struct i2c_driver wm8776_i2c_driver = {
659 .driver = { 540 .driver = {
660 .name = "wm8776", 541 .name = "wm8776-codec",
661 .owner = THIS_MODULE, 542 .owner = THIS_MODULE,
662 }, 543 },
663 .probe = wm8776_i2c_probe, 544 .probe = wm8776_i2c_probe,
@@ -668,22 +549,22 @@ static struct i2c_driver wm8776_i2c_driver = {
668 549
669static int __init wm8776_modinit(void) 550static int __init wm8776_modinit(void)
670{ 551{
671 int ret; 552 int ret = 0;
672#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) 553#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
673 ret = i2c_add_driver(&wm8776_i2c_driver); 554 ret = i2c_add_driver(&wm8776_i2c_driver);
674 if (ret != 0) { 555 if (ret != 0) {
675 printk(KERN_ERR "Failed to register WM8776 I2C driver: %d\n", 556 printk(KERN_ERR "Failed to register wm8776 I2C driver: %d\n",
676 ret); 557 ret);
677 } 558 }
678#endif 559#endif
679#if defined(CONFIG_SPI_MASTER) 560#if defined(CONFIG_SPI_MASTER)
680 ret = spi_register_driver(&wm8776_spi_driver); 561 ret = spi_register_driver(&wm8776_spi_driver);
681 if (ret != 0) { 562 if (ret != 0) {
682 printk(KERN_ERR "Failed to register WM8776 SPI driver: %d\n", 563 printk(KERN_ERR "Failed to register wm8776 SPI driver: %d\n",
683 ret); 564 ret);
684 } 565 }
685#endif 566#endif
686 return 0; 567 return ret;
687} 568}
688module_init(wm8776_modinit); 569module_init(wm8776_modinit);
689 570