diff options
Diffstat (limited to 'sound/soc/codecs')
-rw-r--r-- | sound/soc/codecs/wm8711.c | 297 |
1 files changed, 129 insertions, 168 deletions
diff --git a/sound/soc/codecs/wm8711.c b/sound/soc/codecs/wm8711.c index 84ead3f9293f..812283e27603 100644 --- a/sound/soc/codecs/wm8711.c +++ b/sound/soc/codecs/wm8711.c | |||
@@ -28,11 +28,12 @@ | |||
28 | 28 | ||
29 | #include "wm8711.h" | 29 | #include "wm8711.h" |
30 | 30 | ||
31 | #define AUDIO_NAME "wm8711" | 31 | static struct snd_soc_codec *wm8711_codec; |
32 | #define WM8711_VERSION "0.3" | ||
33 | 32 | ||
34 | /* codec private data */ | 33 | /* codec private data */ |
35 | struct wm8711_priv { | 34 | struct wm8711_priv { |
35 | struct snd_soc_codec codec; | ||
36 | u16 reg_cache[WM8711_CACHEREGNUM]; | ||
36 | unsigned int sysclk; | 37 | unsigned int sysclk; |
37 | }; | 38 | }; |
38 | 39 | ||
@@ -442,241 +443,201 @@ static int wm8711_resume(struct platform_device *pdev) | |||
442 | return 0; | 443 | return 0; |
443 | } | 444 | } |
444 | 445 | ||
445 | /* | 446 | static int wm8711_probe(struct platform_device *pdev) |
446 | * initialise the WM8711 driver | ||
447 | * register the mixer and dsp interfaces with the kernel | ||
448 | */ | ||
449 | static int wm8711_init(struct snd_soc_device *socdev) | ||
450 | { | 447 | { |
451 | struct snd_soc_codec *codec = socdev->card->codec; | 448 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
452 | int reg, ret = 0; | 449 | struct snd_soc_codec *codec; |
453 | 450 | int ret = 0; | |
454 | codec->name = "WM8711"; | ||
455 | codec->owner = THIS_MODULE; | ||
456 | codec->read = wm8711_read_reg_cache; | ||
457 | codec->write = wm8711_write; | ||
458 | codec->set_bias_level = wm8711_set_bias_level; | ||
459 | codec->dai = &wm8711_dai; | ||
460 | codec->num_dai = 1; | ||
461 | codec->reg_cache_size = ARRAY_SIZE(wm8711_reg); | ||
462 | codec->reg_cache = kmemdup(wm8711_reg, sizeof(wm8711_reg), GFP_KERNEL); | ||
463 | 451 | ||
464 | if (codec->reg_cache == NULL) | 452 | if (wm8711_codec == NULL) { |
465 | return -ENOMEM; | 453 | dev_err(&pdev->dev, "Codec device not registered\n"); |
454 | return -ENODEV; | ||
455 | } | ||
466 | 456 | ||
467 | wm8711_reset(codec); | 457 | socdev->card->codec = wm8711_codec; |
458 | codec = wm8711_codec; | ||
468 | 459 | ||
469 | /* register pcms */ | 460 | /* register pcms */ |
470 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | 461 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); |
471 | if (ret < 0) { | 462 | if (ret < 0) { |
472 | printk(KERN_ERR "wm8711: failed to create pcms\n"); | 463 | dev_err(codec->dev, "failed to create pcms: %d\n", ret); |
473 | goto pcm_err; | 464 | goto pcm_err; |
474 | } | 465 | } |
475 | 466 | ||
476 | /* power on device */ | 467 | snd_soc_add_controls(codec, wm8711_snd_controls, |
477 | wm8711_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 468 | ARRAY_SIZE(wm8711_snd_controls)); |
478 | |||
479 | /* set the update bits */ | ||
480 | reg = wm8711_read_reg_cache(codec, WM8711_LOUT1V); | ||
481 | wm8711_write(codec, WM8711_LOUT1V, reg | 0x0100); | ||
482 | reg = wm8711_read_reg_cache(codec, WM8711_ROUT1V); | ||
483 | wm8711_write(codec, WM8711_ROUT1V, reg | 0x0100); | ||
484 | |||
485 | wm8711_add_controls(codec); | ||
486 | wm8711_add_widgets(codec); | 469 | wm8711_add_widgets(codec); |
487 | ret = snd_soc_init_card(socdev); | 470 | ret = snd_soc_init_card(socdev); |
488 | if (ret < 0) { | 471 | if (ret < 0) { |
489 | printk(KERN_ERR "wm8711: failed to register card\n"); | 472 | dev_err(codec->dev, "failed to register card: %d\n", ret); |
490 | goto card_err; | 473 | goto card_err; |
491 | } | 474 | } |
475 | |||
492 | return ret; | 476 | return ret; |
493 | 477 | ||
494 | card_err: | 478 | card_err: |
495 | snd_soc_free_pcms(socdev); | 479 | snd_soc_free_pcms(socdev); |
496 | snd_soc_dapm_free(socdev); | 480 | snd_soc_dapm_free(socdev); |
497 | pcm_err: | 481 | pcm_err: |
498 | kfree(codec->reg_cache); | ||
499 | return ret; | 482 | return ret; |
500 | } | 483 | } |
501 | 484 | ||
502 | static struct snd_soc_device *wm8711_socdev; | 485 | /* power down chip */ |
503 | 486 | static int wm8711_remove(struct platform_device *pdev) | |
504 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 487 | { |
505 | 488 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | |
506 | /* | ||
507 | * WM8711 2 wire address is determined by GPIO5 | ||
508 | * state during powerup. | ||
509 | * low = 0x1a | ||
510 | * high = 0x1b | ||
511 | */ | ||
512 | #define I2C_DRIVERID_WM8711 0xfefe /* liam - need a proper id */ | ||
513 | |||
514 | static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END }; | ||
515 | 489 | ||
516 | /* Magic definition of all other variables and things */ | 490 | snd_soc_free_pcms(socdev); |
517 | I2C_CLIENT_INSMOD; | 491 | snd_soc_dapm_free(socdev); |
518 | 492 | ||
519 | static struct i2c_driver wm8711_i2c_driver; | 493 | return 0; |
520 | static struct i2c_client client_template; | 494 | } |
521 | 495 | ||
522 | /* If the i2c layer weren't so broken, we could pass this kind of data | 496 | struct snd_soc_codec_device soc_codec_dev_wm8711 = { |
523 | around */ | 497 | .probe = wm8711_probe, |
498 | .remove = wm8711_remove, | ||
499 | .suspend = wm8711_suspend, | ||
500 | .resume = wm8711_resume, | ||
501 | }; | ||
502 | EXPORT_SYMBOL_GPL(soc_codec_dev_wm8711); | ||
524 | 503 | ||
525 | static int wm8711_codec_probe(struct i2c_adapter *adap, int addr, int kind) | 504 | static int wm8711_register(struct wm8711_priv *wm8711) |
526 | { | 505 | { |
527 | struct snd_soc_device *socdev = wm8711_socdev; | ||
528 | struct wm8711_setup_data *setup = socdev->codec_data; | ||
529 | struct snd_soc_codec *codec = socdev->card->codec; | ||
530 | struct i2c_client *i2c; | ||
531 | int ret; | 506 | int ret; |
507 | struct snd_soc_codec *codec = &wm8711->codec; | ||
508 | u16 reg; | ||
532 | 509 | ||
533 | if (addr != setup->i2c_address) | 510 | if (wm8711_codec) { |
534 | return -ENODEV; | 511 | dev_err(codec->dev, "Another WM8711 is registered\n"); |
535 | 512 | return -EINVAL; | |
536 | client_template.adapter = adap; | ||
537 | client_template.addr = addr; | ||
538 | |||
539 | i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL); | ||
540 | if (i2c == NULL) { | ||
541 | kfree(codec); | ||
542 | return -ENOMEM; | ||
543 | } | 513 | } |
544 | 514 | ||
545 | i2c_set_clientdata(i2c, codec); | 515 | mutex_init(&codec->mutex); |
516 | INIT_LIST_HEAD(&codec->dapm_widgets); | ||
517 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
546 | 518 | ||
547 | codec->control_data = i2c; | 519 | codec->private_data = wm8711; |
520 | codec->name = "WM8711"; | ||
521 | codec->owner = THIS_MODULE; | ||
522 | codec->read = wm8711_read_reg_cache; | ||
523 | codec->write = wm8711_write; | ||
524 | codec->bias_level = SND_SOC_BIAS_OFF; | ||
525 | codec->set_bias_level = wm8711_set_bias_level; | ||
526 | codec->dai = &wm8711_dai; | ||
527 | codec->num_dai = 1; | ||
528 | codec->reg_cache_size = WM8711_CACHEREGNUM; | ||
529 | codec->reg_cache = &wm8711->reg_cache; | ||
548 | 530 | ||
549 | ret = i2c_attach_client(i2c); | 531 | memcpy(codec->reg_cache, wm8711_reg, sizeof(wm8711_reg)); |
550 | if (ret < 0) { | ||
551 | pr_err("failed to attach codec at addr %x\n", addr); | ||
552 | goto err; | ||
553 | } | ||
554 | 532 | ||
555 | ret = wm8711_init(socdev); | 533 | ret = wm8711_reset(codec); |
556 | if (ret < 0) { | 534 | if (ret < 0) { |
557 | pr_err("failed to initialise WM8711\n"); | 535 | dev_err(codec->dev, "Failed to issue reset\n"); |
558 | goto err; | 536 | return ret; |
559 | } | 537 | } |
560 | return ret; | ||
561 | 538 | ||
562 | err: | 539 | wm8711_dai.dev = codec->dev; |
563 | kfree(codec); | ||
564 | kfree(i2c); | ||
565 | return ret; | ||
566 | } | ||
567 | 540 | ||
568 | static int wm8711_i2c_detach(struct i2c_client *client) | 541 | wm8711_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
569 | { | 542 | |
570 | struct snd_soc_codec *codec = i2c_get_clientdata(client); | 543 | /* Latch the update bits */ |
544 | reg = wm8711_read_reg_cache(codec, WM8711_LOUT1V); | ||
545 | wm8711_write(codec, WM8711_LOUT1V, reg | 0x0100); | ||
546 | reg = wm8711_read_reg_cache(codec, WM8711_ROUT1V); | ||
547 | wm8711_write(codec, WM8711_ROUT1V, reg | 0x0100); | ||
548 | |||
549 | wm8711_codec = codec; | ||
550 | |||
551 | ret = snd_soc_register_codec(codec); | ||
552 | if (ret != 0) { | ||
553 | dev_err(codec->dev, "Failed to register codec: %d\n", ret); | ||
554 | return ret; | ||
555 | } | ||
556 | |||
557 | ret = snd_soc_register_dai(&wm8711_dai); | ||
558 | if (ret != 0) { | ||
559 | dev_err(codec->dev, "Failed to register DAI: %d\n", ret); | ||
560 | snd_soc_unregister_codec(codec); | ||
561 | return ret; | ||
562 | } | ||
571 | 563 | ||
572 | i2c_detach_client(client); | ||
573 | kfree(codec->reg_cache); | ||
574 | kfree(client); | ||
575 | return 0; | 564 | return 0; |
576 | } | 565 | } |
577 | 566 | ||
578 | static int wm8711_i2c_attach(struct i2c_adapter *adap) | 567 | static void wm8711_unregister(struct wm8711_priv *wm8711) |
579 | { | 568 | { |
580 | return i2c_probe(adap, &addr_data, wm8711_codec_probe); | 569 | wm8711_set_bias_level(&wm8711->codec, SND_SOC_BIAS_OFF); |
570 | snd_soc_unregister_dai(&wm8711_dai); | ||
571 | snd_soc_unregister_codec(&wm8711->codec); | ||
572 | kfree(wm8711); | ||
573 | wm8711_codec = NULL; | ||
581 | } | 574 | } |
582 | 575 | ||
583 | /* corgi i2c codec control layer */ | 576 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
584 | static struct i2c_driver wm8711_i2c_driver = { | 577 | static __devinit int wm8711_i2c_probe(struct i2c_client *i2c, |
585 | .driver = { | 578 | const struct i2c_device_id *id) |
586 | .name = "WM8711 I2C Codec", | ||
587 | .owner = THIS_MODULE, | ||
588 | }, | ||
589 | .id = I2C_DRIVERID_WM8711, | ||
590 | .attach_adapter = wm8711_i2c_attach, | ||
591 | .detach_client = wm8711_i2c_detach, | ||
592 | .command = NULL, | ||
593 | }; | ||
594 | |||
595 | static struct i2c_client client_template = { | ||
596 | .name = "WM8711", | ||
597 | .driver = &wm8711_i2c_driver, | ||
598 | }; | ||
599 | #endif | ||
600 | |||
601 | static int wm8711_probe(struct platform_device *pdev) | ||
602 | { | 579 | { |
603 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
604 | struct wm8711_setup_data *setup; | ||
605 | struct snd_soc_codec *codec; | ||
606 | struct wm8711_priv *wm8711; | 580 | struct wm8711_priv *wm8711; |
607 | int ret = 0; | 581 | struct snd_soc_codec *codec; |
608 | |||
609 | pr_info("WM8711 Audio Codec %s", WM8711_VERSION); | ||
610 | |||
611 | setup = socdev->codec_data; | ||
612 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); | ||
613 | if (codec == NULL) | ||
614 | return -ENOMEM; | ||
615 | 582 | ||
616 | wm8711 = kzalloc(sizeof(struct wm8711_priv), GFP_KERNEL); | 583 | wm8711 = kzalloc(sizeof(struct wm8711_priv), GFP_KERNEL); |
617 | if (wm8711 == NULL) { | 584 | if (wm8711 == NULL) |
618 | kfree(codec); | ||
619 | return -ENOMEM; | 585 | return -ENOMEM; |
620 | } | ||
621 | 586 | ||
622 | codec->private_data = wm8711; | 587 | codec = &wm8711->codec; |
623 | socdev->card->codec = codec; | 588 | codec->hw_write = (hw_write_t)i2c_master_send; |
624 | mutex_init(&codec->mutex); | ||
625 | INIT_LIST_HEAD(&codec->dapm_widgets); | ||
626 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
627 | |||
628 | wm8711_socdev = socdev; | ||
629 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
630 | if (setup->i2c_address) { | ||
631 | normal_i2c[0] = setup->i2c_address; | ||
632 | codec->hw_write = (hw_write_t)i2c_master_send; | ||
633 | ret = i2c_add_driver(&wm8711_i2c_driver); | ||
634 | if (ret != 0) | ||
635 | printk(KERN_ERR "can't add i2c driver"); | ||
636 | } | ||
637 | #else | ||
638 | /* Add other interfaces here */ | ||
639 | #endif | ||
640 | return ret; | ||
641 | } | ||
642 | 589 | ||
643 | /* power down chip */ | 590 | i2c_set_clientdata(i2c, wm8711); |
644 | static int wm8711_remove(struct platform_device *pdev) | 591 | codec->control_data = i2c; |
645 | { | ||
646 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
647 | struct snd_soc_codec *codec = socdev->card->codec; | ||
648 | 592 | ||
649 | if (codec->control_data) | 593 | codec->dev = &i2c->dev; |
650 | wm8711_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
651 | 594 | ||
652 | snd_soc_free_pcms(socdev); | 595 | return wm8711_register(wm8711); |
653 | snd_soc_dapm_free(socdev); | 596 | } |
654 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
655 | i2c_del_driver(&wm8711_i2c_driver); | ||
656 | #endif | ||
657 | kfree(codec->private_data); | ||
658 | kfree(codec); | ||
659 | 597 | ||
598 | static __devexit int wm8711_i2c_remove(struct i2c_client *client) | ||
599 | { | ||
600 | struct wm8711_priv *wm8711 = i2c_get_clientdata(client); | ||
601 | wm8711_unregister(wm8711); | ||
660 | return 0; | 602 | return 0; |
661 | } | 603 | } |
662 | 604 | ||
663 | struct snd_soc_codec_device soc_codec_dev_wm8711 = { | 605 | static const struct i2c_device_id wm8711_i2c_id[] = { |
664 | .probe = wm8711_probe, | 606 | { "wm8711", 0 }, |
665 | .remove = wm8711_remove, | 607 | { } |
666 | .suspend = wm8711_suspend, | ||
667 | .resume = wm8711_resume, | ||
668 | }; | 608 | }; |
669 | EXPORT_SYMBOL_GPL(soc_codec_dev_wm8711); | 609 | MODULE_DEVICE_TABLE(i2c, wm8711_i2c_id); |
610 | |||
611 | static struct i2c_driver wm8711_i2c_driver = { | ||
612 | .driver = { | ||
613 | .name = "WM8711 I2C Codec", | ||
614 | .owner = THIS_MODULE, | ||
615 | }, | ||
616 | .probe = wm8711_i2c_probe, | ||
617 | .remove = __devexit_p(wm8711_i2c_remove), | ||
618 | .id_table = wm8711_i2c_id, | ||
619 | }; | ||
620 | #endif | ||
670 | 621 | ||
671 | static int __init wm8711_modinit(void) | 622 | static int __init wm8711_modinit(void) |
672 | { | 623 | { |
673 | return snd_soc_register_dai(&wm8711_dai); | 624 | int ret; |
625 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
626 | ret = i2c_add_driver(&wm8711_i2c_driver); | ||
627 | if (ret != 0) { | ||
628 | printk(KERN_ERR "Failed to register WM8711 I2C driver: %d\n", | ||
629 | ret); | ||
630 | } | ||
631 | #endif | ||
632 | return 0; | ||
674 | } | 633 | } |
675 | module_init(wm8711_modinit); | 634 | module_init(wm8711_modinit); |
676 | 635 | ||
677 | static void __exit wm8711_exit(void) | 636 | static void __exit wm8711_exit(void) |
678 | { | 637 | { |
679 | snd_soc_unregister_dai(&wm8711_dai); | 638 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
639 | i2c_del_driver(&wm8711_i2c_driver); | ||
640 | #endif | ||
680 | } | 641 | } |
681 | module_exit(wm8711_exit); | 642 | module_exit(wm8711_exit); |
682 | 643 | ||