diff options
Diffstat (limited to 'sound/soc/codecs/wm8731.c')
-rw-r--r-- | sound/soc/codecs/wm8731.c | 334 |
1 files changed, 147 insertions, 187 deletions
diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c index 3ff971aeba21..a2c478e53d54 100644 --- a/sound/soc/codecs/wm8731.c +++ b/sound/soc/codecs/wm8731.c | |||
@@ -29,16 +29,18 @@ | |||
29 | 29 | ||
30 | #include "wm8731.h" | 30 | #include "wm8731.h" |
31 | 31 | ||
32 | static struct snd_soc_codec *wm8731_codec; | ||
32 | struct snd_soc_codec_device soc_codec_dev_wm8731; | 33 | struct snd_soc_codec_device soc_codec_dev_wm8731; |
33 | 34 | ||
34 | /* codec private data */ | 35 | /* codec private data */ |
35 | struct wm8731_priv { | 36 | struct wm8731_priv { |
37 | struct snd_soc_codec codec; | ||
38 | u16 reg_cache[WM8731_CACHEREGNUM]; | ||
36 | unsigned int sysclk; | 39 | unsigned int sysclk; |
37 | }; | 40 | }; |
38 | 41 | ||
39 | #ifdef CONFIG_SPI_MASTER | 42 | #ifdef CONFIG_SPI_MASTER |
40 | static int wm8731_spi_write(struct spi_device *spi, const char *data, int len); | 43 | static int wm8731_spi_write(struct spi_device *spi, const char *data, int len); |
41 | static struct spi_driver wm8731_spi_driver; | ||
42 | #endif | 44 | #endif |
43 | 45 | ||
44 | /* | 46 | /* |
@@ -485,55 +487,33 @@ static int wm8731_resume(struct platform_device *pdev) | |||
485 | return 0; | 487 | return 0; |
486 | } | 488 | } |
487 | 489 | ||
488 | /* | 490 | static int wm8731_probe(struct platform_device *pdev) |
489 | * initialise the WM8731 driver | ||
490 | * register the mixer and dsp interfaces with the kernel | ||
491 | */ | ||
492 | static int wm8731_init(struct snd_soc_device *socdev) | ||
493 | { | 491 | { |
494 | struct snd_soc_codec *codec = socdev->card->codec; | 492 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
495 | int reg, ret = 0; | 493 | struct snd_soc_codec *codec; |
494 | int ret = 0; | ||
496 | 495 | ||
497 | codec->name = "WM8731"; | 496 | if (wm8731_codec == NULL) { |
498 | codec->owner = THIS_MODULE; | 497 | dev_err(&pdev->dev, "Codec device not registered\n"); |
499 | codec->read = wm8731_read_reg_cache; | 498 | return -ENODEV; |
500 | codec->write = wm8731_write; | 499 | } |
501 | codec->set_bias_level = wm8731_set_bias_level; | ||
502 | codec->dai = &wm8731_dai; | ||
503 | codec->num_dai = 1; | ||
504 | codec->reg_cache_size = ARRAY_SIZE(wm8731_reg); | ||
505 | codec->reg_cache = kmemdup(wm8731_reg, sizeof(wm8731_reg), GFP_KERNEL); | ||
506 | if (codec->reg_cache == NULL) | ||
507 | return -ENOMEM; | ||
508 | 500 | ||
509 | wm8731_reset(codec); | 501 | socdev->card->codec = wm8731_codec; |
502 | codec = wm8731_codec; | ||
510 | 503 | ||
511 | /* register pcms */ | 504 | /* register pcms */ |
512 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | 505 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); |
513 | if (ret < 0) { | 506 | if (ret < 0) { |
514 | printk(KERN_ERR "wm8731: failed to create pcms\n"); | 507 | dev_err(codec->dev, "failed to create pcms: %d\n", ret); |
515 | goto pcm_err; | 508 | goto pcm_err; |
516 | } | 509 | } |
517 | 510 | ||
518 | /* power on device */ | ||
519 | wm8731_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
520 | |||
521 | /* set the update bits */ | ||
522 | reg = wm8731_read_reg_cache(codec, WM8731_LOUT1V); | ||
523 | wm8731_write(codec, WM8731_LOUT1V, reg & ~0x0100); | ||
524 | reg = wm8731_read_reg_cache(codec, WM8731_ROUT1V); | ||
525 | wm8731_write(codec, WM8731_ROUT1V, reg & ~0x0100); | ||
526 | reg = wm8731_read_reg_cache(codec, WM8731_LINVOL); | ||
527 | wm8731_write(codec, WM8731_LINVOL, reg & ~0x0100); | ||
528 | reg = wm8731_read_reg_cache(codec, WM8731_RINVOL); | ||
529 | wm8731_write(codec, WM8731_RINVOL, reg & ~0x0100); | ||
530 | |||
531 | snd_soc_add_controls(codec, wm8731_snd_controls, | 511 | snd_soc_add_controls(codec, wm8731_snd_controls, |
532 | ARRAY_SIZE(wm8731_snd_controls)); | 512 | ARRAY_SIZE(wm8731_snd_controls)); |
533 | wm8731_add_widgets(codec); | 513 | wm8731_add_widgets(codec); |
534 | ret = snd_soc_init_card(socdev); | 514 | ret = snd_soc_init_card(socdev); |
535 | if (ret < 0) { | 515 | if (ret < 0) { |
536 | printk(KERN_ERR "wm8731: failed to register card\n"); | 516 | dev_err(codec->dev, "failed to register card: %d\n", ret); |
537 | goto card_err; | 517 | goto card_err; |
538 | } | 518 | } |
539 | 519 | ||
@@ -543,104 +523,6 @@ card_err: | |||
543 | snd_soc_free_pcms(socdev); | 523 | snd_soc_free_pcms(socdev); |
544 | snd_soc_dapm_free(socdev); | 524 | snd_soc_dapm_free(socdev); |
545 | pcm_err: | 525 | pcm_err: |
546 | kfree(codec->reg_cache); | ||
547 | return ret; | ||
548 | } | ||
549 | |||
550 | static struct snd_soc_device *wm8731_socdev; | ||
551 | |||
552 | |||
553 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
554 | static struct i2c_driver wm8731_i2c_driver; | ||
555 | |||
556 | static int wm8731_add_i2c_device(struct platform_device *pdev, | ||
557 | const struct wm8731_setup_data *setup) | ||
558 | { | ||
559 | struct i2c_board_info info; | ||
560 | struct i2c_adapter *adapter; | ||
561 | struct i2c_client *client; | ||
562 | int ret; | ||
563 | |||
564 | ret = i2c_add_driver(&wm8731_i2c_driver); | ||
565 | if (ret != 0) { | ||
566 | dev_err(&pdev->dev, "can't add i2c driver\n"); | ||
567 | return ret; | ||
568 | } | ||
569 | |||
570 | memset(&info, 0, sizeof(struct i2c_board_info)); | ||
571 | info.addr = setup->i2c_address; | ||
572 | strlcpy(info.type, "wm8731", I2C_NAME_SIZE); | ||
573 | |||
574 | adapter = i2c_get_adapter(setup->i2c_bus); | ||
575 | if (!adapter) { | ||
576 | dev_err(&pdev->dev, "can't get i2c adapter %d\n", | ||
577 | setup->i2c_bus); | ||
578 | goto err_driver; | ||
579 | } | ||
580 | |||
581 | client = i2c_new_device(adapter, &info); | ||
582 | i2c_put_adapter(adapter); | ||
583 | if (!client) { | ||
584 | dev_err(&pdev->dev, "can't add i2c device at 0x%x\n", | ||
585 | (unsigned int)info.addr); | ||
586 | goto err_driver; | ||
587 | } | ||
588 | |||
589 | return 0; | ||
590 | |||
591 | err_driver: | ||
592 | i2c_del_driver(&wm8731_i2c_driver); | ||
593 | return -ENODEV; | ||
594 | } | ||
595 | #endif | ||
596 | |||
597 | static int wm8731_probe(struct platform_device *pdev) | ||
598 | { | ||
599 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
600 | struct wm8731_setup_data *setup; | ||
601 | struct snd_soc_codec *codec; | ||
602 | struct wm8731_priv *wm8731; | ||
603 | int ret = 0; | ||
604 | |||
605 | setup = socdev->codec_data; | ||
606 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); | ||
607 | if (codec == NULL) | ||
608 | return -ENOMEM; | ||
609 | |||
610 | wm8731 = kzalloc(sizeof(struct wm8731_priv), GFP_KERNEL); | ||
611 | if (wm8731 == NULL) { | ||
612 | kfree(codec); | ||
613 | return -ENOMEM; | ||
614 | } | ||
615 | |||
616 | codec->private_data = wm8731; | ||
617 | socdev->card->codec = codec; | ||
618 | mutex_init(&codec->mutex); | ||
619 | INIT_LIST_HEAD(&codec->dapm_widgets); | ||
620 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
621 | |||
622 | wm8731_socdev = socdev; | ||
623 | ret = -ENODEV; | ||
624 | |||
625 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
626 | if (setup->i2c_address) { | ||
627 | codec->hw_write = (hw_write_t)i2c_master_send; | ||
628 | ret = wm8731_add_i2c_device(pdev, setup); | ||
629 | } | ||
630 | #endif | ||
631 | #if defined(CONFIG_SPI_MASTER) | ||
632 | if (setup->spi) { | ||
633 | codec->hw_write = (hw_write_t)wm8731_spi_write; | ||
634 | ret = spi_register_driver(&wm8731_spi_driver); | ||
635 | if (ret != 0) | ||
636 | printk(KERN_ERR "can't add spi driver"); | ||
637 | } | ||
638 | #endif | ||
639 | |||
640 | if (ret != 0) { | ||
641 | kfree(codec->private_data); | ||
642 | kfree(codec); | ||
643 | } | ||
644 | return ret; | 526 | return ret; |
645 | } | 527 | } |
646 | 528 | ||
@@ -648,22 +530,9 @@ static int wm8731_probe(struct platform_device *pdev) | |||
648 | static int wm8731_remove(struct platform_device *pdev) | 530 | static int wm8731_remove(struct platform_device *pdev) |
649 | { | 531 | { |
650 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 532 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
651 | struct snd_soc_codec *codec = socdev->card->codec; | ||
652 | |||
653 | if (codec->control_data) | ||
654 | wm8731_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
655 | 533 | ||
656 | snd_soc_free_pcms(socdev); | 534 | snd_soc_free_pcms(socdev); |
657 | snd_soc_dapm_free(socdev); | 535 | snd_soc_dapm_free(socdev); |
658 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
659 | i2c_unregister_device(codec->control_data); | ||
660 | i2c_del_driver(&wm8731_i2c_driver); | ||
661 | #endif | ||
662 | #if defined(CONFIG_SPI_MASTER) | ||
663 | spi_unregister_driver(&wm8731_spi_driver); | ||
664 | #endif | ||
665 | kfree(codec->private_data); | ||
666 | kfree(codec); | ||
667 | 536 | ||
668 | return 0; | 537 | return 0; |
669 | } | 538 | } |
@@ -676,37 +545,78 @@ struct snd_soc_codec_device soc_codec_dev_wm8731 = { | |||
676 | }; | 545 | }; |
677 | EXPORT_SYMBOL_GPL(soc_codec_dev_wm8731); | 546 | EXPORT_SYMBOL_GPL(soc_codec_dev_wm8731); |
678 | 547 | ||
679 | #if defined(CONFIG_SPI_MASTER) | 548 | static int wm8731_register(struct wm8731_priv *wm8731) |
680 | static int __devinit wm8731_spi_probe(struct spi_device *spi) | ||
681 | { | 549 | { |
682 | struct snd_soc_device *socdev = wm8731_socdev; | ||
683 | struct snd_soc_codec *codec = socdev->card->codec; | ||
684 | int ret; | 550 | int ret; |
551 | struct snd_soc_codec *codec = &wm8731->codec; | ||
552 | u16 reg; | ||
685 | 553 | ||
686 | codec->control_data = spi; | 554 | if (wm8731_codec) { |
555 | dev_err(codec->dev, "Another WM8731 is registered\n"); | ||
556 | return -EINVAL; | ||
557 | } | ||
687 | 558 | ||
688 | ret = wm8731_init(socdev); | 559 | mutex_init(&codec->mutex); |
689 | if (ret < 0) | 560 | INIT_LIST_HEAD(&codec->dapm_widgets); |
690 | dev_err(&spi->dev, "failed to initialise WM8731\n"); | 561 | INIT_LIST_HEAD(&codec->dapm_paths); |
691 | 562 | ||
692 | return ret; | 563 | codec->private_data = wm8731; |
693 | } | 564 | codec->name = "WM8731"; |
565 | codec->owner = THIS_MODULE; | ||
566 | codec->read = wm8731_read_reg_cache; | ||
567 | codec->write = wm8731_write; | ||
568 | codec->bias_level = SND_SOC_BIAS_OFF; | ||
569 | codec->set_bias_level = wm8731_set_bias_level; | ||
570 | codec->dai = &wm8731_dai; | ||
571 | codec->num_dai = 1; | ||
572 | codec->reg_cache_size = WM8731_CACHEREGNUM; | ||
573 | codec->reg_cache = &wm8731->reg_cache; | ||
574 | |||
575 | memcpy(codec->reg_cache, wm8731_reg, sizeof(wm8731_reg)); | ||
576 | |||
577 | wm8731_dai.dev = codec->dev; | ||
578 | |||
579 | wm8731_reset(codec); | ||
580 | wm8731_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
581 | |||
582 | /* Latch the update bits */ | ||
583 | reg = wm8731_read_reg_cache(codec, WM8731_LOUT1V); | ||
584 | wm8731_write(codec, WM8731_LOUT1V, reg & ~0x0100); | ||
585 | reg = wm8731_read_reg_cache(codec, WM8731_ROUT1V); | ||
586 | wm8731_write(codec, WM8731_ROUT1V, reg & ~0x0100); | ||
587 | reg = wm8731_read_reg_cache(codec, WM8731_LINVOL); | ||
588 | wm8731_write(codec, WM8731_LINVOL, reg & ~0x0100); | ||
589 | reg = wm8731_read_reg_cache(codec, WM8731_RINVOL); | ||
590 | wm8731_write(codec, WM8731_RINVOL, reg & ~0x0100); | ||
591 | |||
592 | wm8731_codec = codec; | ||
593 | |||
594 | ret = snd_soc_register_codec(codec); | ||
595 | if (ret != 0) { | ||
596 | dev_err(codec->dev, "Failed to register codec: %d\n", ret); | ||
597 | return ret; | ||
598 | } | ||
599 | |||
600 | ret = snd_soc_register_dai(&wm8731_dai); | ||
601 | if (ret != 0) { | ||
602 | dev_err(codec->dev, "Failed to register DAI: %d\n", ret); | ||
603 | snd_soc_unregister_codec(codec); | ||
604 | return ret; | ||
605 | } | ||
694 | 606 | ||
695 | static int __devexit wm8731_spi_remove(struct spi_device *spi) | ||
696 | { | ||
697 | return 0; | 607 | return 0; |
698 | } | 608 | } |
699 | 609 | ||
700 | static struct spi_driver wm8731_spi_driver = { | 610 | static void wm8731_unregister(struct wm8731_priv *wm8731) |
701 | .driver = { | 611 | { |
702 | .name = "wm8731", | 612 | wm8731_set_bias_level(&wm8731->codec, SND_SOC_BIAS_OFF); |
703 | .bus = &spi_bus_type, | 613 | snd_soc_unregister_dai(&wm8731_dai); |
704 | .owner = THIS_MODULE, | 614 | snd_soc_unregister_codec(&wm8731->codec); |
705 | }, | 615 | kfree(wm8731); |
706 | .probe = wm8731_spi_probe, | 616 | wm8731_codec = NULL; |
707 | .remove = __devexit_p(wm8731_spi_remove), | 617 | } |
708 | }; | ||
709 | 618 | ||
619 | #if defined(CONFIG_SPI_MASTER) | ||
710 | static int wm8731_spi_write(struct spi_device *spi, const char *data, int len) | 620 | static int wm8731_spi_write(struct spi_device *spi, const char *data, int len) |
711 | { | 621 | { |
712 | struct spi_transfer t; | 622 | struct spi_transfer t; |
@@ -730,37 +640,67 @@ static int wm8731_spi_write(struct spi_device *spi, const char *data, int len) | |||
730 | 640 | ||
731 | return len; | 641 | return len; |
732 | } | 642 | } |
643 | |||
644 | static int __devinit wm8731_spi_probe(struct spi_device *spi) | ||
645 | { | ||
646 | struct snd_soc_codec *codec; | ||
647 | struct wm8731_priv *wm8731; | ||
648 | |||
649 | wm8731 = kzalloc(sizeof(struct wm8731_priv), GFP_KERNEL); | ||
650 | if (wm8731 == NULL) | ||
651 | return -ENOMEM; | ||
652 | |||
653 | codec = &wm8731->codec; | ||
654 | codec->control_data = spi; | ||
655 | codec->hw_write = (hw_write_t)wm8731_spi_write; | ||
656 | codec->dev = &spi->dev; | ||
657 | |||
658 | return wm8731_register(wm8731); | ||
659 | } | ||
660 | |||
661 | static int __devexit wm8731_spi_remove(struct spi_device *spi) | ||
662 | { | ||
663 | /* FIXME: This isn't actually implemented... */ | ||
664 | return 0; | ||
665 | } | ||
666 | |||
667 | static struct spi_driver wm8731_spi_driver = { | ||
668 | .driver = { | ||
669 | .name = "wm8731", | ||
670 | .bus = &spi_bus_type, | ||
671 | .owner = THIS_MODULE, | ||
672 | }, | ||
673 | .probe = wm8731_spi_probe, | ||
674 | .remove = __devexit_p(wm8731_spi_remove), | ||
675 | }; | ||
733 | #endif /* CONFIG_SPI_MASTER */ | 676 | #endif /* CONFIG_SPI_MASTER */ |
734 | 677 | ||
735 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 678 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
736 | /* | ||
737 | * WM8731 2 wire address is determined by GPIO5 | ||
738 | * state during powerup. | ||
739 | * low = 0x1a | ||
740 | * high = 0x1b | ||
741 | */ | ||
742 | |||
743 | static int wm8731_i2c_probe(struct i2c_client *i2c, | 679 | static int wm8731_i2c_probe(struct i2c_client *i2c, |
744 | const struct i2c_device_id *id) | 680 | const struct i2c_device_id *id) |
745 | { | 681 | { |
746 | struct snd_soc_device *socdev = wm8731_socdev; | 682 | struct wm8731_priv *wm8731; |
747 | struct snd_soc_codec *codec = socdev->card->codec; | 683 | struct snd_soc_codec *codec; |
748 | int ret; | ||
749 | 684 | ||
750 | i2c_set_clientdata(i2c, codec); | 685 | wm8731 = kzalloc(sizeof(struct wm8731_priv), GFP_KERNEL); |
686 | if (wm8731 == NULL) | ||
687 | return -ENOMEM; | ||
688 | |||
689 | codec = &wm8731->codec; | ||
690 | codec->hw_write = (hw_write_t)i2c_master_send; | ||
691 | |||
692 | i2c_set_clientdata(i2c, wm8731); | ||
751 | codec->control_data = i2c; | 693 | codec->control_data = i2c; |
752 | 694 | ||
753 | ret = wm8731_init(socdev); | 695 | codec->dev = &i2c->dev; |
754 | if (ret < 0) | ||
755 | pr_err("failed to initialise WM8731\n"); | ||
756 | 696 | ||
757 | return ret; | 697 | return wm8731_register(wm8731); |
758 | } | 698 | } |
759 | 699 | ||
760 | static int wm8731_i2c_remove(struct i2c_client *client) | 700 | static int wm8731_i2c_remove(struct i2c_client *client) |
761 | { | 701 | { |
762 | struct snd_soc_codec *codec = i2c_get_clientdata(client); | 702 | struct wm8731_priv *wm8731 = i2c_get_clientdata(client); |
763 | kfree(codec->reg_cache); | 703 | wm8731_unregister(wm8731); |
764 | return 0; | 704 | return 0; |
765 | } | 705 | } |
766 | 706 | ||
@@ -783,13 +723,33 @@ static struct i2c_driver wm8731_i2c_driver = { | |||
783 | 723 | ||
784 | static int __init wm8731_modinit(void) | 724 | static int __init wm8731_modinit(void) |
785 | { | 725 | { |
786 | return snd_soc_register_dai(&wm8731_dai); | 726 | int ret; |
727 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
728 | ret = i2c_add_driver(&wm8731_i2c_driver); | ||
729 | if (ret != 0) { | ||
730 | printk(KERN_ERR "Failed to register WM8731 I2C driver: %d\n", | ||
731 | ret); | ||
732 | } | ||
733 | #endif | ||
734 | #if defined(CONFIG_SPI_MASTER) | ||
735 | ret = spi_register_driver(&wm8731_spi_driver); | ||
736 | if (ret != 0) { | ||
737 | printk(KERN_ERR "Failed to register WM8731 SPI driver: %d\n", | ||
738 | ret); | ||
739 | } | ||
740 | #endif | ||
741 | return 0; | ||
787 | } | 742 | } |
788 | module_init(wm8731_modinit); | 743 | module_init(wm8731_modinit); |
789 | 744 | ||
790 | static void __exit wm8731_exit(void) | 745 | static void __exit wm8731_exit(void) |
791 | { | 746 | { |
792 | snd_soc_unregister_dai(&wm8731_dai); | 747 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
748 | i2c_del_driver(&wm8731_i2c_driver); | ||
749 | #endif | ||
750 | #if defined(CONFIG_SPI_MASTER) | ||
751 | spi_unregister_driver(&wm8731_spi_driver); | ||
752 | #endif | ||
793 | } | 753 | } |
794 | module_exit(wm8731_exit); | 754 | module_exit(wm8731_exit); |
795 | 755 | ||