diff options
Diffstat (limited to 'sound/soc/codecs/wm9090.c')
-rw-r--r-- | sound/soc/codecs/wm9090.c | 183 |
1 files changed, 59 insertions, 124 deletions
diff --git a/sound/soc/codecs/wm9090.c b/sound/soc/codecs/wm9090.c index 1592250daec0..7a1825418ee4 100644 --- a/sound/soc/codecs/wm9090.c +++ b/sound/soc/codecs/wm9090.c | |||
@@ -34,8 +34,6 @@ | |||
34 | 34 | ||
35 | #include "wm9090.h" | 35 | #include "wm9090.h" |
36 | 36 | ||
37 | static struct snd_soc_codec *wm9090_codec; | ||
38 | |||
39 | static const u16 wm9090_reg_defaults[] = { | 37 | static const u16 wm9090_reg_defaults[] = { |
40 | 0x9093, /* R0 - Software Reset */ | 38 | 0x9093, /* R0 - Software Reset */ |
41 | 0x0006, /* R1 - Power Management (1) */ | 39 | 0x0006, /* R1 - Power Management (1) */ |
@@ -142,15 +140,10 @@ static const u16 wm9090_reg_defaults[] = { | |||
142 | 140 | ||
143 | /* This struct is used to save the context */ | 141 | /* This struct is used to save the context */ |
144 | struct wm9090_priv { | 142 | struct wm9090_priv { |
145 | /* We're not really registering as a CODEC since ASoC core | ||
146 | * does not yet support multiple CODECs but having the CODEC | ||
147 | * structure means we can reuse some of the ASoC core | ||
148 | * features. | ||
149 | */ | ||
150 | struct snd_soc_codec codec; | ||
151 | struct mutex mutex; | 143 | struct mutex mutex; |
152 | u16 reg_cache[WM9090_MAX_REGISTER + 1]; | 144 | u16 reg_cache[WM9090_MAX_REGISTER + 1]; |
153 | struct wm9090_platform_data pdata; | 145 | struct wm9090_platform_data pdata; |
146 | void *control_data; | ||
154 | }; | 147 | }; |
155 | 148 | ||
156 | static int wm9090_volatile(unsigned int reg) | 149 | static int wm9090_volatile(unsigned int reg) |
@@ -523,7 +516,7 @@ static int wm9090_set_bias_level(struct snd_soc_codec *codec, | |||
523 | case SND_SOC_BIAS_STANDBY: | 516 | case SND_SOC_BIAS_STANDBY: |
524 | if (codec->bias_level == SND_SOC_BIAS_OFF) { | 517 | if (codec->bias_level == SND_SOC_BIAS_OFF) { |
525 | /* Restore the register cache */ | 518 | /* Restore the register cache */ |
526 | for (i = 1; i < codec->reg_cache_size; i++) { | 519 | for (i = 1; i < codec->driver->reg_cache_size; i++) { |
527 | if (reg_cache[i] == wm9090_reg_defaults[i]) | 520 | if (reg_cache[i] == wm9090_reg_defaults[i]) |
528 | continue; | 521 | continue; |
529 | if (wm9090_volatile(i)) | 522 | if (wm9090_volatile(i)) |
@@ -556,51 +549,67 @@ static int wm9090_set_bias_level(struct snd_soc_codec *codec, | |||
556 | return 0; | 549 | return 0; |
557 | } | 550 | } |
558 | 551 | ||
559 | static int wm9090_probe(struct platform_device *pdev) | 552 | static int wm9090_probe(struct snd_soc_codec *codec) |
560 | { | 553 | { |
561 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 554 | struct wm9090_priv *wm9090 = snd_soc_codec_get_drvdata(codec); |
562 | struct snd_soc_codec *codec; | 555 | int ret; |
563 | int ret = 0; | ||
564 | 556 | ||
565 | if (wm9090_codec == NULL) { | 557 | codec->control_data = wm9090->control_data; |
566 | dev_err(&pdev->dev, "Codec device not registered\n"); | 558 | ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C); |
567 | return -ENODEV; | 559 | if (ret != 0) { |
560 | dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); | ||
561 | return ret; | ||
568 | } | 562 | } |
569 | 563 | ||
570 | socdev->card->codec = wm9090_codec; | 564 | ret = snd_soc_read(codec, WM9090_SOFTWARE_RESET); |
571 | codec = wm9090_codec; | 565 | if (ret < 0) |
572 | 566 | return ret; | |
573 | /* register pcms */ | 567 | if (ret != wm9090_reg_defaults[WM9090_SOFTWARE_RESET]) { |
574 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | 568 | dev_err(codec->dev, "Device is not a WM9090, ID=%x\n", ret); |
575 | if (ret < 0) { | 569 | return -EINVAL; |
576 | dev_err(codec->dev, "failed to create pcms: %d\n", ret); | ||
577 | goto pcm_err; | ||
578 | } | 570 | } |
579 | 571 | ||
572 | ret = snd_soc_write(codec, WM9090_SOFTWARE_RESET, 0); | ||
573 | if (ret < 0) | ||
574 | return ret; | ||
575 | |||
576 | /* Configure some defaults; they will be written out when we | ||
577 | * bring the bias up. | ||
578 | */ | ||
579 | wm9090->reg_cache[WM9090_IN1_LINE_INPUT_A_VOLUME] |= WM9090_IN1_VU | ||
580 | | WM9090_IN1A_ZC; | ||
581 | wm9090->reg_cache[WM9090_IN1_LINE_INPUT_B_VOLUME] |= WM9090_IN1_VU | ||
582 | | WM9090_IN1B_ZC; | ||
583 | wm9090->reg_cache[WM9090_IN2_LINE_INPUT_A_VOLUME] |= WM9090_IN2_VU | ||
584 | | WM9090_IN2A_ZC; | ||
585 | wm9090->reg_cache[WM9090_IN2_LINE_INPUT_B_VOLUME] |= WM9090_IN2_VU | ||
586 | | WM9090_IN2B_ZC; | ||
587 | wm9090->reg_cache[WM9090_SPEAKER_VOLUME_LEFT] |= | ||
588 | WM9090_SPKOUT_VU | WM9090_SPKOUTL_ZC; | ||
589 | wm9090->reg_cache[WM9090_LEFT_OUTPUT_VOLUME] |= | ||
590 | WM9090_HPOUT1_VU | WM9090_HPOUT1L_ZC; | ||
591 | wm9090->reg_cache[WM9090_RIGHT_OUTPUT_VOLUME] |= | ||
592 | WM9090_HPOUT1_VU | WM9090_HPOUT1R_ZC; | ||
593 | |||
594 | wm9090->reg_cache[WM9090_CLOCKING_1] |= WM9090_TOCLK_ENA; | ||
595 | |||
596 | wm9090_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
597 | |||
580 | wm9090_add_controls(codec); | 598 | wm9090_add_controls(codec); |
581 | 599 | ||
582 | return 0; | 600 | return 0; |
583 | |||
584 | pcm_err: | ||
585 | return ret; | ||
586 | } | 601 | } |
587 | 602 | ||
588 | #ifdef CONFIG_PM | 603 | #ifdef CONFIG_PM |
589 | static int wm9090_suspend(struct platform_device *pdev, pm_message_t state) | 604 | static int wm9090_suspend(struct snd_soc_codec *codec, pm_message_t state) |
590 | { | 605 | { |
591 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
592 | struct snd_soc_codec *codec = socdev->card->codec; | ||
593 | |||
594 | wm9090_set_bias_level(codec, SND_SOC_BIAS_OFF); | 606 | wm9090_set_bias_level(codec, SND_SOC_BIAS_OFF); |
595 | 607 | ||
596 | return 0; | 608 | return 0; |
597 | } | 609 | } |
598 | 610 | ||
599 | static int wm9090_resume(struct platform_device *pdev) | 611 | static int wm9090_resume(struct snd_soc_codec *codec) |
600 | { | 612 | { |
601 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
602 | struct snd_soc_codec *codec = socdev->card->codec; | ||
603 | |||
604 | wm9090_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 613 | wm9090_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
605 | 614 | ||
606 | return 0; | 615 | return 0; |
@@ -610,29 +619,29 @@ static int wm9090_resume(struct platform_device *pdev) | |||
610 | #define wm9090_resume NULL | 619 | #define wm9090_resume NULL |
611 | #endif | 620 | #endif |
612 | 621 | ||
613 | static int wm9090_remove(struct platform_device *pdev) | 622 | static int wm9090_remove(struct snd_soc_codec *codec) |
614 | { | 623 | { |
615 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 624 | wm9090_set_bias_level(codec, SND_SOC_BIAS_OFF); |
616 | |||
617 | snd_soc_free_pcms(socdev); | ||
618 | snd_soc_dapm_free(socdev); | ||
619 | 625 | ||
620 | return 0; | 626 | return 0; |
621 | } | 627 | } |
622 | 628 | ||
623 | struct snd_soc_codec_device soc_codec_dev_wm9090 = { | 629 | static struct snd_soc_codec_driver soc_codec_dev_wm9090 = { |
624 | .probe = wm9090_probe, | 630 | .probe = wm9090_probe, |
625 | .remove = wm9090_remove, | 631 | .remove = wm9090_remove, |
626 | .suspend = wm9090_suspend, | 632 | .suspend = wm9090_suspend, |
627 | .resume = wm9090_resume, | 633 | .resume = wm9090_resume, |
634 | .set_bias_level = wm9090_set_bias_level, | ||
635 | .reg_cache_size = (WM9090_MAX_REGISTER + 1), | ||
636 | .reg_word_size = sizeof(u16), | ||
637 | .reg_cache_default = wm9090_reg_defaults, | ||
638 | .volatile_register = wm9090_volatile, | ||
628 | }; | 639 | }; |
629 | EXPORT_SYMBOL_GPL(soc_codec_dev_wm9090); | ||
630 | 640 | ||
631 | static int wm9090_i2c_probe(struct i2c_client *i2c, | 641 | static int wm9090_i2c_probe(struct i2c_client *i2c, |
632 | const struct i2c_device_id *id) | 642 | const struct i2c_device_id *id) |
633 | { | 643 | { |
634 | struct wm9090_priv *wm9090; | 644 | struct wm9090_priv *wm9090; |
635 | struct snd_soc_codec *codec; | ||
636 | int ret; | 645 | int ret; |
637 | 646 | ||
638 | wm9090 = kzalloc(sizeof(*wm9090), GFP_KERNEL); | 647 | wm9090 = kzalloc(sizeof(*wm9090), GFP_KERNEL); |
@@ -640,102 +649,28 @@ static int wm9090_i2c_probe(struct i2c_client *i2c, | |||
640 | dev_err(&i2c->dev, "Can not allocate memory\n"); | 649 | dev_err(&i2c->dev, "Can not allocate memory\n"); |
641 | return -ENOMEM; | 650 | return -ENOMEM; |
642 | } | 651 | } |
643 | codec = &wm9090->codec; | ||
644 | 652 | ||
645 | if (i2c->dev.platform_data) | 653 | if (i2c->dev.platform_data) |
646 | memcpy(&wm9090->pdata, i2c->dev.platform_data, | 654 | memcpy(&wm9090->pdata, i2c->dev.platform_data, |
647 | sizeof(wm9090->pdata)); | 655 | sizeof(wm9090->pdata)); |
648 | 656 | ||
649 | wm9090_codec = codec; | ||
650 | |||
651 | i2c_set_clientdata(i2c, wm9090); | 657 | i2c_set_clientdata(i2c, wm9090); |
658 | wm9090->control_data = i2c; | ||
659 | mutex_init(&wm9090->mutex); | ||
652 | 660 | ||
653 | mutex_init(&codec->mutex); | 661 | ret = snd_soc_register_codec(&i2c->dev, |
654 | INIT_LIST_HEAD(&codec->dapm_widgets); | 662 | &soc_codec_dev_wm9090, NULL, 0); |
655 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
656 | |||
657 | codec->control_data = i2c; | ||
658 | snd_soc_codec_set_drvdata(codec, wm9090); | ||
659 | codec->dev = &i2c->dev; | ||
660 | codec->name = "WM9090"; | ||
661 | codec->owner = THIS_MODULE; | ||
662 | codec->bias_level = SND_SOC_BIAS_OFF; | ||
663 | codec->set_bias_level = wm9090_set_bias_level, | ||
664 | codec->reg_cache_size = WM9090_MAX_REGISTER + 1; | ||
665 | codec->reg_cache = &wm9090->reg_cache; | ||
666 | codec->volatile_register = wm9090_volatile; | ||
667 | |||
668 | ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C); | ||
669 | if (ret != 0) { | ||
670 | dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); | ||
671 | goto err; | ||
672 | } | ||
673 | |||
674 | memcpy(&wm9090->reg_cache, wm9090_reg_defaults, | ||
675 | sizeof(wm9090->reg_cache)); | ||
676 | |||
677 | ret = snd_soc_read(codec, WM9090_SOFTWARE_RESET); | ||
678 | if (ret < 0) | ||
679 | goto err; | ||
680 | if (ret != wm9090_reg_defaults[WM9090_SOFTWARE_RESET]) { | ||
681 | dev_err(&i2c->dev, "Device is not a WM9090, ID=%x\n", ret); | ||
682 | ret = -EINVAL; | ||
683 | goto err; | ||
684 | } | ||
685 | |||
686 | ret = snd_soc_write(codec, WM9090_SOFTWARE_RESET, 0); | ||
687 | if (ret < 0) | 663 | if (ret < 0) |
688 | goto err; | 664 | kfree(wm9090); |
689 | |||
690 | /* Configure some defaults; they will be written out when we | ||
691 | * bring the bias up. | ||
692 | */ | ||
693 | wm9090->reg_cache[WM9090_IN1_LINE_INPUT_A_VOLUME] |= WM9090_IN1_VU | ||
694 | | WM9090_IN1A_ZC; | ||
695 | wm9090->reg_cache[WM9090_IN1_LINE_INPUT_B_VOLUME] |= WM9090_IN1_VU | ||
696 | | WM9090_IN1B_ZC; | ||
697 | wm9090->reg_cache[WM9090_IN2_LINE_INPUT_A_VOLUME] |= WM9090_IN2_VU | ||
698 | | WM9090_IN2A_ZC; | ||
699 | wm9090->reg_cache[WM9090_IN2_LINE_INPUT_B_VOLUME] |= WM9090_IN2_VU | ||
700 | | WM9090_IN2B_ZC; | ||
701 | wm9090->reg_cache[WM9090_SPEAKER_VOLUME_LEFT] |= | ||
702 | WM9090_SPKOUT_VU | WM9090_SPKOUTL_ZC; | ||
703 | wm9090->reg_cache[WM9090_LEFT_OUTPUT_VOLUME] |= | ||
704 | WM9090_HPOUT1_VU | WM9090_HPOUT1L_ZC; | ||
705 | wm9090->reg_cache[WM9090_RIGHT_OUTPUT_VOLUME] |= | ||
706 | WM9090_HPOUT1_VU | WM9090_HPOUT1R_ZC; | ||
707 | |||
708 | wm9090->reg_cache[WM9090_CLOCKING_1] |= WM9090_TOCLK_ENA; | ||
709 | |||
710 | wm9090_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
711 | |||
712 | ret = snd_soc_register_codec(codec); | ||
713 | if (ret != 0) { | ||
714 | dev_err(&i2c->dev, "Failed to register CODEC: %d\n", ret); | ||
715 | goto err_bias; | ||
716 | } | ||
717 | |||
718 | return 0; | ||
719 | |||
720 | err_bias: | ||
721 | wm9090_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
722 | err: | ||
723 | kfree(wm9090); | ||
724 | i2c_set_clientdata(i2c, NULL); | ||
725 | wm9090_codec = NULL; | ||
726 | |||
727 | return ret; | 665 | return ret; |
728 | } | 666 | } |
729 | 667 | ||
730 | static int wm9090_i2c_remove(struct i2c_client *i2c) | 668 | static int wm9090_i2c_remove(struct i2c_client *i2c) |
731 | { | 669 | { |
732 | struct wm9090_priv *wm9090 = i2c_get_clientdata(i2c); | 670 | struct wm9090_priv *wm9090 = i2c_get_clientdata(i2c); |
733 | struct snd_soc_codec *codec = &wm9090->codec; | ||
734 | 671 | ||
735 | snd_soc_unregister_codec(codec); | 672 | snd_soc_unregister_codec(&i2c->dev); |
736 | wm9090_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
737 | kfree(wm9090); | 673 | kfree(wm9090); |
738 | wm9090_codec = NULL; | ||
739 | 674 | ||
740 | return 0; | 675 | return 0; |
741 | } | 676 | } |
@@ -748,7 +683,7 @@ MODULE_DEVICE_TABLE(i2c, wm9090_id); | |||
748 | 683 | ||
749 | static struct i2c_driver wm9090_i2c_driver = { | 684 | static struct i2c_driver wm9090_i2c_driver = { |
750 | .driver = { | 685 | .driver = { |
751 | .name = "wm9090", | 686 | .name = "wm9090-codec", |
752 | .owner = THIS_MODULE, | 687 | .owner = THIS_MODULE, |
753 | }, | 688 | }, |
754 | .probe = wm9090_i2c_probe, | 689 | .probe = wm9090_i2c_probe, |