diff options
Diffstat (limited to 'sound/soc/codecs/wm8750.c')
-rw-r--r-- | sound/soc/codecs/wm8750.c | 177 |
1 files changed, 123 insertions, 54 deletions
diff --git a/sound/soc/codecs/wm8750.c b/sound/soc/codecs/wm8750.c index dd1f55404b29..4892e398a598 100644 --- a/sound/soc/codecs/wm8750.c +++ b/sound/soc/codecs/wm8750.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> |
@@ -841,88 +842,147 @@ static struct snd_soc_device *wm8750_socdev; | |||
841 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 842 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
842 | 843 | ||
843 | /* | 844 | /* |
844 | * WM8731 2 wire address is determined by GPIO5 | 845 | * WM8750 2 wire address is determined by GPIO5 |
845 | * state during powerup. | 846 | * state during powerup. |
846 | * low = 0x1a | 847 | * low = 0x1a |
847 | * high = 0x1b | 848 | * high = 0x1b |
848 | */ | 849 | */ |
849 | static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END }; | ||
850 | 850 | ||
851 | /* Magic definition of all other variables and things */ | 851 | static int wm8750_i2c_probe(struct i2c_client *i2c, |
852 | I2C_CLIENT_INSMOD; | 852 | const struct i2c_device_id *id) |
853 | |||
854 | static struct i2c_driver wm8750_i2c_driver; | ||
855 | static struct i2c_client client_template; | ||
856 | |||
857 | static int wm8750_codec_probe(struct i2c_adapter *adap, int addr, int kind) | ||
858 | { | 853 | { |
859 | struct snd_soc_device *socdev = wm8750_socdev; | 854 | struct snd_soc_device *socdev = wm8750_socdev; |
860 | struct wm8750_setup_data *setup = socdev->codec_data; | ||
861 | struct snd_soc_codec *codec = socdev->codec; | 855 | struct snd_soc_codec *codec = socdev->codec; |
862 | struct i2c_client *i2c; | ||
863 | int ret; | 856 | int ret; |
864 | 857 | ||
865 | if (addr != setup->i2c_address) | ||
866 | return -ENODEV; | ||
867 | |||
868 | client_template.adapter = adap; | ||
869 | client_template.addr = addr; | ||
870 | |||
871 | i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL); | ||
872 | if (i2c == NULL) | ||
873 | return -ENOMEM; | ||
874 | |||
875 | i2c_set_clientdata(i2c, codec); | 858 | i2c_set_clientdata(i2c, codec); |
876 | codec->control_data = i2c; | 859 | codec->control_data = i2c; |
877 | 860 | ||
878 | ret = i2c_attach_client(i2c); | ||
879 | if (ret < 0) { | ||
880 | pr_err("failed to attach codec at addr %x\n", addr); | ||
881 | goto err; | ||
882 | } | ||
883 | |||
884 | ret = wm8750_init(socdev); | 861 | ret = wm8750_init(socdev); |
885 | if (ret < 0) { | 862 | if (ret < 0) |
886 | pr_err("failed to initialise WM8750\n"); | 863 | pr_err("failed to initialise WM8750\n"); |
887 | goto err; | ||
888 | } | ||
889 | return ret; | ||
890 | 864 | ||
891 | err: | ||
892 | kfree(i2c); | ||
893 | return ret; | 865 | return ret; |
894 | } | 866 | } |
895 | 867 | ||
896 | static int wm8750_i2c_detach(struct i2c_client *client) | 868 | static int wm8750_i2c_remove(struct i2c_client *client) |
897 | { | 869 | { |
898 | struct snd_soc_codec *codec = i2c_get_clientdata(client); | 870 | struct snd_soc_codec *codec = i2c_get_clientdata(client); |
899 | i2c_detach_client(client); | ||
900 | kfree(codec->reg_cache); | 871 | kfree(codec->reg_cache); |
901 | kfree(client); | ||
902 | return 0; | 872 | return 0; |
903 | } | 873 | } |
904 | 874 | ||
905 | static int wm8750_i2c_attach(struct i2c_adapter *adap) | 875 | static const struct i2c_device_id wm8750_i2c_id[] = { |
906 | { | 876 | { "wm8750", 0 }, |
907 | return i2c_probe(adap, &addr_data, wm8750_codec_probe); | 877 | { } |
908 | } | 878 | }; |
879 | MODULE_DEVICE_TABLE(i2c, wm8750_i2c_id); | ||
909 | 880 | ||
910 | /* corgi i2c codec control layer */ | ||
911 | static struct i2c_driver wm8750_i2c_driver = { | 881 | static struct i2c_driver wm8750_i2c_driver = { |
912 | .driver = { | 882 | .driver = { |
913 | .name = "WM8750 I2C Codec", | 883 | .name = "WM8750 I2C Codec", |
914 | .owner = THIS_MODULE, | 884 | .owner = THIS_MODULE, |
915 | }, | 885 | }, |
916 | .id = I2C_DRIVERID_WM8750, | 886 | .probe = wm8750_i2c_probe, |
917 | .attach_adapter = wm8750_i2c_attach, | 887 | .remove = wm8750_i2c_remove, |
918 | .detach_client = wm8750_i2c_detach, | 888 | .id_table = wm8750_i2c_id, |
919 | .command = NULL, | ||
920 | }; | 889 | }; |
921 | 890 | ||
922 | static struct i2c_client client_template = { | 891 | static int wm8750_add_i2c_device(struct platform_device *pdev, |
923 | .name = "WM8750", | 892 | const struct wm8750_setup_data *setup) |
924 | .driver = &wm8750_i2c_driver, | 893 | { |
894 | struct i2c_board_info info; | ||
895 | struct i2c_adapter *adapter; | ||
896 | struct i2c_client *client; | ||
897 | int ret; | ||
898 | |||
899 | ret = i2c_add_driver(&wm8750_i2c_driver); | ||
900 | if (ret != 0) { | ||
901 | dev_err(&pdev->dev, "can't add i2c driver\n"); | ||
902 | return ret; | ||
903 | } | ||
904 | |||
905 | memset(&info, 0, sizeof(struct i2c_board_info)); | ||
906 | info.addr = setup->i2c_address; | ||
907 | strlcpy(info.type, "wm8750", I2C_NAME_SIZE); | ||
908 | |||
909 | adapter = i2c_get_adapter(setup->i2c_bus); | ||
910 | if (!adapter) { | ||
911 | dev_err(&pdev->dev, "can't get i2c adapter %d\n", | ||
912 | setup->i2c_bus); | ||
913 | goto err_driver; | ||
914 | } | ||
915 | |||
916 | client = i2c_new_device(adapter, &info); | ||
917 | i2c_put_adapter(adapter); | ||
918 | if (!client) { | ||
919 | dev_err(&pdev->dev, "can't add i2c device at 0x%x\n", | ||
920 | (unsigned int)info.addr); | ||
921 | goto err_driver; | ||
922 | } | ||
923 | |||
924 | return 0; | ||
925 | |||
926 | err_driver: | ||
927 | i2c_del_driver(&wm8750_i2c_driver); | ||
928 | return -ENODEV; | ||
929 | } | ||
930 | #endif | ||
931 | |||
932 | #if defined(CONFIG_SPI_MASTER) | ||
933 | static int __devinit wm8750_spi_probe(struct spi_device *spi) | ||
934 | { | ||
935 | struct snd_soc_device *socdev = wm8750_socdev; | ||
936 | struct snd_soc_codec *codec = socdev->codec; | ||
937 | int ret; | ||
938 | |||
939 | codec->control_data = spi; | ||
940 | |||
941 | ret = wm8750_init(socdev); | ||
942 | if (ret < 0) | ||
943 | dev_err(&spi->dev, "failed to initialise WM8750\n"); | ||
944 | |||
945 | return ret; | ||
946 | } | ||
947 | |||
948 | static int __devexit wm8750_spi_remove(struct spi_device *spi) | ||
949 | { | ||
950 | return 0; | ||
951 | } | ||
952 | |||
953 | static struct spi_driver wm8750_spi_driver = { | ||
954 | .driver = { | ||
955 | .name = "wm8750", | ||
956 | .bus = &spi_bus_type, | ||
957 | .owner = THIS_MODULE, | ||
958 | }, | ||
959 | .probe = wm8750_spi_probe, | ||
960 | .remove = __devexit_p(wm8750_spi_remove), | ||
925 | }; | 961 | }; |
962 | |||
963 | static int wm8750_spi_write(struct spi_device *spi, const char *data, int len) | ||
964 | { | ||
965 | struct spi_transfer t; | ||
966 | struct spi_message m; | ||
967 | u8 msg[2]; | ||
968 | |||
969 | if (len <= 0) | ||
970 | return 0; | ||
971 | |||
972 | msg[0] = data[0]; | ||
973 | msg[1] = data[1]; | ||
974 | |||
975 | spi_message_init(&m); | ||
976 | memset(&t, 0, (sizeof t)); | ||
977 | |||
978 | t.tx_buf = &msg[0]; | ||
979 | t.len = len; | ||
980 | |||
981 | spi_message_add_tail(&t, &m); | ||
982 | spi_sync(spi, &m); | ||
983 | |||
984 | return len; | ||
985 | } | ||
926 | #endif | 986 | #endif |
927 | 987 | ||
928 | static int wm8750_probe(struct platform_device *pdev) | 988 | static int wm8750_probe(struct platform_device *pdev) |
@@ -931,7 +991,7 @@ static int wm8750_probe(struct platform_device *pdev) | |||
931 | struct wm8750_setup_data *setup = socdev->codec_data; | 991 | struct wm8750_setup_data *setup = socdev->codec_data; |
932 | struct snd_soc_codec *codec; | 992 | struct snd_soc_codec *codec; |
933 | struct wm8750_priv *wm8750; | 993 | struct wm8750_priv *wm8750; |
934 | int ret = 0; | 994 | int ret; |
935 | 995 | ||
936 | pr_info("WM8750 Audio Codec %s", WM8750_VERSION); | 996 | pr_info("WM8750 Audio Codec %s", WM8750_VERSION); |
937 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); | 997 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); |
@@ -952,16 +1012,21 @@ static int wm8750_probe(struct platform_device *pdev) | |||
952 | wm8750_socdev = socdev; | 1012 | wm8750_socdev = socdev; |
953 | INIT_DELAYED_WORK(&codec->delayed_work, wm8750_work); | 1013 | INIT_DELAYED_WORK(&codec->delayed_work, wm8750_work); |
954 | 1014 | ||
1015 | ret = -ENODEV; | ||
1016 | |||
955 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 1017 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
956 | if (setup->i2c_address) { | 1018 | if (setup->i2c_address) { |
957 | normal_i2c[0] = setup->i2c_address; | ||
958 | codec->hw_write = (hw_write_t)i2c_master_send; | 1019 | codec->hw_write = (hw_write_t)i2c_master_send; |
959 | ret = i2c_add_driver(&wm8750_i2c_driver); | 1020 | ret = wm8750_add_i2c_device(pdev, setup); |
1021 | } | ||
1022 | #endif | ||
1023 | #if defined(CONFIG_SPI_MASTER) | ||
1024 | if (setup->spi) { | ||
1025 | codec->hw_write = (hw_write_t)wm8750_spi_write; | ||
1026 | ret = spi_register_driver(&wm8750_spi_driver); | ||
960 | if (ret != 0) | 1027 | if (ret != 0) |
961 | printk(KERN_ERR "can't add i2c driver"); | 1028 | printk(KERN_ERR "can't add spi driver"); |
962 | } | 1029 | } |
963 | #else | ||
964 | /* Add other interfaces here */ | ||
965 | #endif | 1030 | #endif |
966 | 1031 | ||
967 | if (ret != 0) { | 1032 | if (ret != 0) { |
@@ -1002,8 +1067,12 @@ static int wm8750_remove(struct platform_device *pdev) | |||
1002 | snd_soc_free_pcms(socdev); | 1067 | snd_soc_free_pcms(socdev); |
1003 | snd_soc_dapm_free(socdev); | 1068 | snd_soc_dapm_free(socdev); |
1004 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 1069 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
1070 | i2c_unregister_device(codec->control_data); | ||
1005 | i2c_del_driver(&wm8750_i2c_driver); | 1071 | i2c_del_driver(&wm8750_i2c_driver); |
1006 | #endif | 1072 | #endif |
1073 | #if defined(CONFIG_SPI_MASTER) | ||
1074 | spi_unregister_driver(&wm8750_spi_driver); | ||
1075 | #endif | ||
1007 | kfree(codec->private_data); | 1076 | kfree(codec->private_data); |
1008 | kfree(codec); | 1077 | kfree(codec); |
1009 | 1078 | ||