diff options
Diffstat (limited to 'sound/soc/codecs/wm8731.c')
-rw-r--r-- | sound/soc/codecs/wm8731.c | 178 |
1 files changed, 122 insertions, 56 deletions
diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c index 9402fcaf04fa..7b64d9a7ff76 100644 --- a/sound/soc/codecs/wm8731.c +++ b/sound/soc/codecs/wm8731.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <linux/pm.h> | 19 | #include <linux/pm.h> |
20 | #include <linux/i2c.h> | 20 | #include <linux/i2c.h> |
21 | #include <linux/platform_device.h> | 21 | #include <linux/platform_device.h> |
22 | #include <linux/spi/spi.h> | ||
22 | #include <sound/core.h> | 23 | #include <sound/core.h> |
23 | #include <sound/pcm.h> | 24 | #include <sound/pcm.h> |
24 | #include <sound/pcm_params.h> | 25 | #include <sound/pcm_params.h> |
@@ -570,88 +571,144 @@ static struct snd_soc_device *wm8731_socdev; | |||
570 | * low = 0x1a | 571 | * low = 0x1a |
571 | * high = 0x1b | 572 | * high = 0x1b |
572 | */ | 573 | */ |
573 | static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END }; | ||
574 | 574 | ||
575 | /* Magic definition of all other variables and things */ | 575 | static int wm8731_i2c_probe(struct i2c_client *i2c, |
576 | I2C_CLIENT_INSMOD; | 576 | const struct i2c_device_id *id) |
577 | |||
578 | static struct i2c_driver wm8731_i2c_driver; | ||
579 | static struct i2c_client client_template; | ||
580 | |||
581 | /* If the i2c layer weren't so broken, we could pass this kind of data | ||
582 | around */ | ||
583 | |||
584 | static int wm8731_codec_probe(struct i2c_adapter *adap, int addr, int kind) | ||
585 | { | 577 | { |
586 | struct snd_soc_device *socdev = wm8731_socdev; | 578 | struct snd_soc_device *socdev = wm8731_socdev; |
587 | struct wm8731_setup_data *setup = socdev->codec_data; | ||
588 | struct snd_soc_codec *codec = socdev->codec; | 579 | struct snd_soc_codec *codec = socdev->codec; |
589 | struct i2c_client *i2c; | ||
590 | int ret; | 580 | int ret; |
591 | 581 | ||
592 | if (addr != setup->i2c_address) | ||
593 | return -ENODEV; | ||
594 | |||
595 | client_template.adapter = adap; | ||
596 | client_template.addr = addr; | ||
597 | |||
598 | i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL); | ||
599 | if (i2c == NULL) | ||
600 | return -ENOMEM; | ||
601 | |||
602 | i2c_set_clientdata(i2c, codec); | 582 | i2c_set_clientdata(i2c, codec); |
603 | codec->control_data = i2c; | 583 | codec->control_data = i2c; |
604 | 584 | ||
605 | ret = i2c_attach_client(i2c); | ||
606 | if (ret < 0) { | ||
607 | pr_err("failed to attach codec at addr %x\n", addr); | ||
608 | goto err; | ||
609 | } | ||
610 | |||
611 | ret = wm8731_init(socdev); | 585 | ret = wm8731_init(socdev); |
612 | if (ret < 0) { | 586 | if (ret < 0) |
613 | pr_err("failed to initialise WM8731\n"); | 587 | pr_err("failed to initialise WM8731\n"); |
614 | goto err; | ||
615 | } | ||
616 | return ret; | ||
617 | 588 | ||
618 | err: | ||
619 | kfree(i2c); | ||
620 | return ret; | 589 | return ret; |
621 | } | 590 | } |
622 | 591 | ||
623 | static int wm8731_i2c_detach(struct i2c_client *client) | 592 | static int wm8731_i2c_remove(struct i2c_client *client) |
624 | { | 593 | { |
625 | struct snd_soc_codec *codec = i2c_get_clientdata(client); | 594 | struct snd_soc_codec *codec = i2c_get_clientdata(client); |
626 | i2c_detach_client(client); | ||
627 | kfree(codec->reg_cache); | 595 | kfree(codec->reg_cache); |
628 | kfree(client); | ||
629 | return 0; | 596 | return 0; |
630 | } | 597 | } |
631 | 598 | ||
632 | static int wm8731_i2c_attach(struct i2c_adapter *adap) | 599 | static const struct i2c_device_id wm8731_i2c_id[] = { |
633 | { | 600 | { "wm8731", 0 }, |
634 | return i2c_probe(adap, &addr_data, wm8731_codec_probe); | 601 | { } |
635 | } | 602 | }; |
603 | MODULE_DEVICE_TABLE(i2c, wm8731_i2c_id); | ||
636 | 604 | ||
637 | /* corgi i2c codec control layer */ | ||
638 | static struct i2c_driver wm8731_i2c_driver = { | 605 | static struct i2c_driver wm8731_i2c_driver = { |
639 | .driver = { | 606 | .driver = { |
640 | .name = "WM8731 I2C Codec", | 607 | .name = "WM8731 I2C Codec", |
641 | .owner = THIS_MODULE, | 608 | .owner = THIS_MODULE, |
642 | }, | 609 | }, |
643 | .id = I2C_DRIVERID_WM8731, | 610 | .probe = wm8731_i2c_probe, |
644 | .attach_adapter = wm8731_i2c_attach, | 611 | .remove = wm8731_i2c_remove, |
645 | .detach_client = wm8731_i2c_detach, | 612 | .id_table = wm8731_i2c_id, |
646 | .command = NULL, | ||
647 | }; | 613 | }; |
648 | 614 | ||
649 | static struct i2c_client client_template = { | 615 | static int wm8731_add_i2c_device(struct platform_device *pdev, |
650 | .name = "WM8731", | 616 | const struct wm8731_setup_data *setup) |
651 | .driver = &wm8731_i2c_driver, | 617 | { |
652 | }; | 618 | struct i2c_board_info info; |
619 | struct i2c_adapter *adapter; | ||
620 | struct i2c_client *client; | ||
621 | int ret; | ||
622 | |||
623 | ret = i2c_add_driver(&wm8731_i2c_driver); | ||
624 | if (ret != 0) { | ||
625 | dev_err(&pdev->dev, "can't add i2c driver\n"); | ||
626 | return ret; | ||
627 | } | ||
628 | |||
629 | memset(&info, 0, sizeof(struct i2c_board_info)); | ||
630 | info.addr = setup->i2c_address; | ||
631 | strlcpy(info.type, "wm8731", I2C_NAME_SIZE); | ||
632 | |||
633 | adapter = i2c_get_adapter(setup->i2c_bus); | ||
634 | if (!adapter) { | ||
635 | dev_err(&pdev->dev, "can't get i2c adapter %d\n", | ||
636 | setup->i2c_bus); | ||
637 | goto err_driver; | ||
638 | } | ||
639 | |||
640 | client = i2c_new_device(adapter, &info); | ||
641 | i2c_put_adapter(adapter); | ||
642 | if (!client) { | ||
643 | dev_err(&pdev->dev, "can't add i2c device at 0x%x\n", | ||
644 | (unsigned int)info.addr); | ||
645 | goto err_driver; | ||
646 | } | ||
647 | |||
648 | return 0; | ||
649 | |||
650 | err_driver: | ||
651 | i2c_del_driver(&wm8731_i2c_driver); | ||
652 | return -ENODEV; | ||
653 | } | ||
653 | #endif | 654 | #endif |
654 | 655 | ||
656 | #if defined(CONFIG_SPI_MASTER) | ||
657 | static int __devinit wm8731_spi_probe(struct spi_device *spi) | ||
658 | { | ||
659 | struct snd_soc_device *socdev = wm8731_socdev; | ||
660 | struct snd_soc_codec *codec = socdev->codec; | ||
661 | int ret; | ||
662 | |||
663 | codec->control_data = spi; | ||
664 | |||
665 | ret = wm8731_init(socdev); | ||
666 | if (ret < 0) | ||
667 | dev_err(&spi->dev, "failed to initialise WM8731\n"); | ||
668 | |||
669 | return ret; | ||
670 | } | ||
671 | |||
672 | static int __devexit wm8731_spi_remove(struct spi_device *spi) | ||
673 | { | ||
674 | return 0; | ||
675 | } | ||
676 | |||
677 | static struct spi_driver wm8731_spi_driver = { | ||
678 | .driver = { | ||
679 | .name = "wm8731", | ||
680 | .bus = &spi_bus_type, | ||
681 | .owner = THIS_MODULE, | ||
682 | }, | ||
683 | .probe = wm8731_spi_probe, | ||
684 | .remove = __devexit_p(wm8731_spi_remove), | ||
685 | }; | ||
686 | |||
687 | static int wm8731_spi_write(struct spi_device *spi, const char *data, int len) | ||
688 | { | ||
689 | struct spi_transfer t; | ||
690 | struct spi_message m; | ||
691 | u8 msg[2]; | ||
692 | |||
693 | if (len <= 0) | ||
694 | return 0; | ||
695 | |||
696 | msg[0] = data[0]; | ||
697 | msg[1] = data[1]; | ||
698 | |||
699 | spi_message_init(&m); | ||
700 | memset(&t, 0, (sizeof t)); | ||
701 | |||
702 | t.tx_buf = &msg[0]; | ||
703 | t.len = len; | ||
704 | |||
705 | spi_message_add_tail(&t, &m); | ||
706 | spi_sync(spi, &m); | ||
707 | |||
708 | return len; | ||
709 | } | ||
710 | #endif /* CONFIG_SPI_MASTER */ | ||
711 | |||
655 | static int wm8731_probe(struct platform_device *pdev) | 712 | static int wm8731_probe(struct platform_device *pdev) |
656 | { | 713 | { |
657 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 714 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
@@ -680,16 +737,21 @@ static int wm8731_probe(struct platform_device *pdev) | |||
680 | INIT_LIST_HEAD(&codec->dapm_paths); | 737 | INIT_LIST_HEAD(&codec->dapm_paths); |
681 | 738 | ||
682 | wm8731_socdev = socdev; | 739 | wm8731_socdev = socdev; |
740 | ret = -ENODEV; | ||
741 | |||
683 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 742 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
684 | if (setup->i2c_address) { | 743 | if (setup->i2c_address) { |
685 | normal_i2c[0] = setup->i2c_address; | ||
686 | codec->hw_write = (hw_write_t)i2c_master_send; | 744 | codec->hw_write = (hw_write_t)i2c_master_send; |
687 | ret = i2c_add_driver(&wm8731_i2c_driver); | 745 | ret = wm8731_add_i2c_device(pdev, setup); |
746 | } | ||
747 | #endif | ||
748 | #if defined(CONFIG_SPI_MASTER) | ||
749 | if (setup->spi) { | ||
750 | codec->hw_write = (hw_write_t)wm8731_spi_write; | ||
751 | ret = spi_register_driver(&wm8731_spi_driver); | ||
688 | if (ret != 0) | 752 | if (ret != 0) |
689 | printk(KERN_ERR "can't add i2c driver"); | 753 | printk(KERN_ERR "can't add spi driver"); |
690 | } | 754 | } |
691 | #else | ||
692 | /* Add other interfaces here */ | ||
693 | #endif | 755 | #endif |
694 | 756 | ||
695 | if (ret != 0) { | 757 | if (ret != 0) { |
@@ -711,8 +773,12 @@ static int wm8731_remove(struct platform_device *pdev) | |||
711 | snd_soc_free_pcms(socdev); | 773 | snd_soc_free_pcms(socdev); |
712 | snd_soc_dapm_free(socdev); | 774 | snd_soc_dapm_free(socdev); |
713 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 775 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
776 | i2c_unregister_device(codec->control_data); | ||
714 | i2c_del_driver(&wm8731_i2c_driver); | 777 | i2c_del_driver(&wm8731_i2c_driver); |
715 | #endif | 778 | #endif |
779 | #if defined(CONFIG_SPI_MASTER) | ||
780 | spi_unregister_driver(&wm8731_spi_driver); | ||
781 | #endif | ||
716 | kfree(codec->private_data); | 782 | kfree(codec->private_data); |
717 | kfree(codec); | 783 | kfree(codec); |
718 | 784 | ||