diff options
Diffstat (limited to 'sound/aoa')
-rw-r--r-- | sound/aoa/aoa-gpio.h | 2 | ||||
-rw-r--r-- | sound/aoa/codecs/onyx.c | 76 | ||||
-rw-r--r-- | sound/aoa/codecs/tas.c | 66 | ||||
-rw-r--r-- | sound/aoa/core/gpio-feature.c | 17 | ||||
-rw-r--r-- | sound/aoa/fabrics/layout.c | 81 | ||||
-rw-r--r-- | sound/aoa/soundbus/i2sbus/core.c | 22 |
6 files changed, 194 insertions, 70 deletions
diff --git a/sound/aoa/aoa-gpio.h b/sound/aoa/aoa-gpio.h index ee64f5de8966..6065b0344e23 100644 --- a/sound/aoa/aoa-gpio.h +++ b/sound/aoa/aoa-gpio.h | |||
@@ -34,10 +34,12 @@ struct gpio_methods { | |||
34 | void (*set_headphone)(struct gpio_runtime *rt, int on); | 34 | void (*set_headphone)(struct gpio_runtime *rt, int on); |
35 | void (*set_speakers)(struct gpio_runtime *rt, int on); | 35 | void (*set_speakers)(struct gpio_runtime *rt, int on); |
36 | void (*set_lineout)(struct gpio_runtime *rt, int on); | 36 | void (*set_lineout)(struct gpio_runtime *rt, int on); |
37 | void (*set_master)(struct gpio_runtime *rt, int on); | ||
37 | 38 | ||
38 | int (*get_headphone)(struct gpio_runtime *rt); | 39 | int (*get_headphone)(struct gpio_runtime *rt); |
39 | int (*get_speakers)(struct gpio_runtime *rt); | 40 | int (*get_speakers)(struct gpio_runtime *rt); |
40 | int (*get_lineout)(struct gpio_runtime *rt); | 41 | int (*get_lineout)(struct gpio_runtime *rt); |
42 | int (*get_master)(struct gpio_runtime *rt); | ||
41 | 43 | ||
42 | void (*set_hw_reset)(struct gpio_runtime *rt, int on); | 44 | void (*set_hw_reset)(struct gpio_runtime *rt, int on); |
43 | 45 | ||
diff --git a/sound/aoa/codecs/onyx.c b/sound/aoa/codecs/onyx.c index 15500b9d2da0..84bb07d39a7f 100644 --- a/sound/aoa/codecs/onyx.c +++ b/sound/aoa/codecs/onyx.c | |||
@@ -47,7 +47,7 @@ MODULE_DESCRIPTION("pcm3052 (onyx) codec driver for snd-aoa"); | |||
47 | struct onyx { | 47 | struct onyx { |
48 | /* cache registers 65 to 80, they are write-only! */ | 48 | /* cache registers 65 to 80, they are write-only! */ |
49 | u8 cache[16]; | 49 | u8 cache[16]; |
50 | struct i2c_client i2c; | 50 | struct i2c_client *i2c; |
51 | struct aoa_codec codec; | 51 | struct aoa_codec codec; |
52 | u32 initialised:1, | 52 | u32 initialised:1, |
53 | spdif_locked:1, | 53 | spdif_locked:1, |
@@ -72,7 +72,7 @@ static int onyx_read_register(struct onyx *onyx, u8 reg, u8 *value) | |||
72 | *value = onyx->cache[reg-FIRSTREGISTER]; | 72 | *value = onyx->cache[reg-FIRSTREGISTER]; |
73 | return 0; | 73 | return 0; |
74 | } | 74 | } |
75 | v = i2c_smbus_read_byte_data(&onyx->i2c, reg); | 75 | v = i2c_smbus_read_byte_data(onyx->i2c, reg); |
76 | if (v < 0) | 76 | if (v < 0) |
77 | return -1; | 77 | return -1; |
78 | *value = (u8)v; | 78 | *value = (u8)v; |
@@ -84,7 +84,7 @@ static int onyx_write_register(struct onyx *onyx, u8 reg, u8 value) | |||
84 | { | 84 | { |
85 | int result; | 85 | int result; |
86 | 86 | ||
87 | result = i2c_smbus_write_byte_data(&onyx->i2c, reg, value); | 87 | result = i2c_smbus_write_byte_data(onyx->i2c, reg, value); |
88 | if (!result) | 88 | if (!result) |
89 | onyx->cache[reg-FIRSTREGISTER] = value; | 89 | onyx->cache[reg-FIRSTREGISTER] = value; |
90 | return result; | 90 | return result; |
@@ -996,12 +996,45 @@ static void onyx_exit_codec(struct aoa_codec *codec) | |||
996 | onyx->codec.soundbus_dev->detach_codec(onyx->codec.soundbus_dev, onyx); | 996 | onyx->codec.soundbus_dev->detach_codec(onyx->codec.soundbus_dev, onyx); |
997 | } | 997 | } |
998 | 998 | ||
999 | static struct i2c_driver onyx_driver; | ||
1000 | |||
1001 | static int onyx_create(struct i2c_adapter *adapter, | 999 | static int onyx_create(struct i2c_adapter *adapter, |
1002 | struct device_node *node, | 1000 | struct device_node *node, |
1003 | int addr) | 1001 | int addr) |
1004 | { | 1002 | { |
1003 | struct i2c_board_info info; | ||
1004 | struct i2c_client *client; | ||
1005 | |||
1006 | memset(&info, 0, sizeof(struct i2c_board_info)); | ||
1007 | strlcpy(info.type, "aoa_codec_onyx", I2C_NAME_SIZE); | ||
1008 | info.addr = addr; | ||
1009 | info.platform_data = node; | ||
1010 | client = i2c_new_device(adapter, &info); | ||
1011 | if (!client) | ||
1012 | return -ENODEV; | ||
1013 | |||
1014 | /* | ||
1015 | * We know the driver is already loaded, so the device should be | ||
1016 | * already bound. If not it means binding failed, which suggests | ||
1017 | * the device doesn't really exist and should be deleted. | ||
1018 | * Ideally this would be replaced by better checks _before_ | ||
1019 | * instantiating the device. | ||
1020 | */ | ||
1021 | if (!client->driver) { | ||
1022 | i2c_unregister_device(client); | ||
1023 | return -ENODEV; | ||
1024 | } | ||
1025 | |||
1026 | /* | ||
1027 | * Let i2c-core delete that device on driver removal. | ||
1028 | * This is safe because i2c-core holds the core_lock mutex for us. | ||
1029 | */ | ||
1030 | list_add_tail(&client->detected, &client->driver->clients); | ||
1031 | return 0; | ||
1032 | } | ||
1033 | |||
1034 | static int onyx_i2c_probe(struct i2c_client *client, | ||
1035 | const struct i2c_device_id *id) | ||
1036 | { | ||
1037 | struct device_node *node = client->dev.platform_data; | ||
1005 | struct onyx *onyx; | 1038 | struct onyx *onyx; |
1006 | u8 dummy; | 1039 | u8 dummy; |
1007 | 1040 | ||
@@ -1011,20 +1044,12 @@ static int onyx_create(struct i2c_adapter *adapter, | |||
1011 | return -ENOMEM; | 1044 | return -ENOMEM; |
1012 | 1045 | ||
1013 | mutex_init(&onyx->mutex); | 1046 | mutex_init(&onyx->mutex); |
1014 | onyx->i2c.driver = &onyx_driver; | 1047 | onyx->i2c = client; |
1015 | onyx->i2c.adapter = adapter; | 1048 | i2c_set_clientdata(client, onyx); |
1016 | onyx->i2c.addr = addr & 0x7f; | ||
1017 | strlcpy(onyx->i2c.name, "onyx audio codec", I2C_NAME_SIZE); | ||
1018 | |||
1019 | if (i2c_attach_client(&onyx->i2c)) { | ||
1020 | printk(KERN_ERR PFX "failed to attach to i2c\n"); | ||
1021 | goto fail; | ||
1022 | } | ||
1023 | 1049 | ||
1024 | /* we try to read from register ONYX_REG_CONTROL | 1050 | /* we try to read from register ONYX_REG_CONTROL |
1025 | * to check if the codec is present */ | 1051 | * to check if the codec is present */ |
1026 | if (onyx_read_register(onyx, ONYX_REG_CONTROL, &dummy) != 0) { | 1052 | if (onyx_read_register(onyx, ONYX_REG_CONTROL, &dummy) != 0) { |
1027 | i2c_detach_client(&onyx->i2c); | ||
1028 | printk(KERN_ERR PFX "failed to read control register\n"); | 1053 | printk(KERN_ERR PFX "failed to read control register\n"); |
1029 | goto fail; | 1054 | goto fail; |
1030 | } | 1055 | } |
@@ -1036,14 +1061,14 @@ static int onyx_create(struct i2c_adapter *adapter, | |||
1036 | onyx->codec.node = of_node_get(node); | 1061 | onyx->codec.node = of_node_get(node); |
1037 | 1062 | ||
1038 | if (aoa_codec_register(&onyx->codec)) { | 1063 | if (aoa_codec_register(&onyx->codec)) { |
1039 | i2c_detach_client(&onyx->i2c); | ||
1040 | goto fail; | 1064 | goto fail; |
1041 | } | 1065 | } |
1042 | printk(KERN_DEBUG PFX "created and attached onyx instance\n"); | 1066 | printk(KERN_DEBUG PFX "created and attached onyx instance\n"); |
1043 | return 0; | 1067 | return 0; |
1044 | fail: | 1068 | fail: |
1069 | i2c_set_clientdata(client, NULL); | ||
1045 | kfree(onyx); | 1070 | kfree(onyx); |
1046 | return -EINVAL; | 1071 | return -ENODEV; |
1047 | } | 1072 | } |
1048 | 1073 | ||
1049 | static int onyx_i2c_attach(struct i2c_adapter *adapter) | 1074 | static int onyx_i2c_attach(struct i2c_adapter *adapter) |
@@ -1080,28 +1105,33 @@ static int onyx_i2c_attach(struct i2c_adapter *adapter) | |||
1080 | return onyx_create(adapter, NULL, 0x47); | 1105 | return onyx_create(adapter, NULL, 0x47); |
1081 | } | 1106 | } |
1082 | 1107 | ||
1083 | static int onyx_i2c_detach(struct i2c_client *client) | 1108 | static int onyx_i2c_remove(struct i2c_client *client) |
1084 | { | 1109 | { |
1085 | struct onyx *onyx = container_of(client, struct onyx, i2c); | 1110 | struct onyx *onyx = i2c_get_clientdata(client); |
1086 | int err; | ||
1087 | 1111 | ||
1088 | if ((err = i2c_detach_client(client))) | ||
1089 | return err; | ||
1090 | aoa_codec_unregister(&onyx->codec); | 1112 | aoa_codec_unregister(&onyx->codec); |
1091 | of_node_put(onyx->codec.node); | 1113 | of_node_put(onyx->codec.node); |
1092 | if (onyx->codec_info) | 1114 | if (onyx->codec_info) |
1093 | kfree(onyx->codec_info); | 1115 | kfree(onyx->codec_info); |
1116 | i2c_set_clientdata(client, onyx); | ||
1094 | kfree(onyx); | 1117 | kfree(onyx); |
1095 | return 0; | 1118 | return 0; |
1096 | } | 1119 | } |
1097 | 1120 | ||
1121 | static const struct i2c_device_id onyx_i2c_id[] = { | ||
1122 | { "aoa_codec_onyx", 0 }, | ||
1123 | { } | ||
1124 | }; | ||
1125 | |||
1098 | static struct i2c_driver onyx_driver = { | 1126 | static struct i2c_driver onyx_driver = { |
1099 | .driver = { | 1127 | .driver = { |
1100 | .name = "aoa_codec_onyx", | 1128 | .name = "aoa_codec_onyx", |
1101 | .owner = THIS_MODULE, | 1129 | .owner = THIS_MODULE, |
1102 | }, | 1130 | }, |
1103 | .attach_adapter = onyx_i2c_attach, | 1131 | .attach_adapter = onyx_i2c_attach, |
1104 | .detach_client = onyx_i2c_detach, | 1132 | .probe = onyx_i2c_probe, |
1133 | .remove = onyx_i2c_remove, | ||
1134 | .id_table = onyx_i2c_id, | ||
1105 | }; | 1135 | }; |
1106 | 1136 | ||
1107 | static int __init onyx_init(void) | 1137 | static int __init onyx_init(void) |
diff --git a/sound/aoa/codecs/tas.c b/sound/aoa/codecs/tas.c index 008e0f85097d..f0ebc971c686 100644 --- a/sound/aoa/codecs/tas.c +++ b/sound/aoa/codecs/tas.c | |||
@@ -82,7 +82,7 @@ MODULE_DESCRIPTION("tas codec driver for snd-aoa"); | |||
82 | 82 | ||
83 | struct tas { | 83 | struct tas { |
84 | struct aoa_codec codec; | 84 | struct aoa_codec codec; |
85 | struct i2c_client i2c; | 85 | struct i2c_client *i2c; |
86 | u32 mute_l:1, mute_r:1 , | 86 | u32 mute_l:1, mute_r:1 , |
87 | controls_created:1 , | 87 | controls_created:1 , |
88 | drc_enabled:1, | 88 | drc_enabled:1, |
@@ -108,9 +108,9 @@ static struct tas *codec_to_tas(struct aoa_codec *codec) | |||
108 | static inline int tas_write_reg(struct tas *tas, u8 reg, u8 len, u8 *data) | 108 | static inline int tas_write_reg(struct tas *tas, u8 reg, u8 len, u8 *data) |
109 | { | 109 | { |
110 | if (len == 1) | 110 | if (len == 1) |
111 | return i2c_smbus_write_byte_data(&tas->i2c, reg, *data); | 111 | return i2c_smbus_write_byte_data(tas->i2c, reg, *data); |
112 | else | 112 | else |
113 | return i2c_smbus_write_i2c_block_data(&tas->i2c, reg, len, data); | 113 | return i2c_smbus_write_i2c_block_data(tas->i2c, reg, len, data); |
114 | } | 114 | } |
115 | 115 | ||
116 | static void tas3004_set_drc(struct tas *tas) | 116 | static void tas3004_set_drc(struct tas *tas) |
@@ -882,12 +882,34 @@ static void tas_exit_codec(struct aoa_codec *codec) | |||
882 | } | 882 | } |
883 | 883 | ||
884 | 884 | ||
885 | static struct i2c_driver tas_driver; | ||
886 | |||
887 | static int tas_create(struct i2c_adapter *adapter, | 885 | static int tas_create(struct i2c_adapter *adapter, |
888 | struct device_node *node, | 886 | struct device_node *node, |
889 | int addr) | 887 | int addr) |
890 | { | 888 | { |
889 | struct i2c_board_info info; | ||
890 | struct i2c_client *client; | ||
891 | |||
892 | memset(&info, 0, sizeof(struct i2c_board_info)); | ||
893 | strlcpy(info.type, "aoa_codec_tas", I2C_NAME_SIZE); | ||
894 | info.addr = addr; | ||
895 | info.platform_data = node; | ||
896 | |||
897 | client = i2c_new_device(adapter, &info); | ||
898 | if (!client) | ||
899 | return -ENODEV; | ||
900 | |||
901 | /* | ||
902 | * Let i2c-core delete that device on driver removal. | ||
903 | * This is safe because i2c-core holds the core_lock mutex for us. | ||
904 | */ | ||
905 | list_add_tail(&client->detected, &client->driver->clients); | ||
906 | return 0; | ||
907 | } | ||
908 | |||
909 | static int tas_i2c_probe(struct i2c_client *client, | ||
910 | const struct i2c_device_id *id) | ||
911 | { | ||
912 | struct device_node *node = client->dev.platform_data; | ||
891 | struct tas *tas; | 913 | struct tas *tas; |
892 | 914 | ||
893 | tas = kzalloc(sizeof(struct tas), GFP_KERNEL); | 915 | tas = kzalloc(sizeof(struct tas), GFP_KERNEL); |
@@ -896,17 +918,11 @@ static int tas_create(struct i2c_adapter *adapter, | |||
896 | return -ENOMEM; | 918 | return -ENOMEM; |
897 | 919 | ||
898 | mutex_init(&tas->mtx); | 920 | mutex_init(&tas->mtx); |
899 | tas->i2c.driver = &tas_driver; | 921 | tas->i2c = client; |
900 | tas->i2c.adapter = adapter; | 922 | i2c_set_clientdata(client, tas); |
901 | tas->i2c.addr = addr; | 923 | |
902 | /* seems that half is a saner default */ | 924 | /* seems that half is a saner default */ |
903 | tas->drc_range = TAS3004_DRC_MAX / 2; | 925 | tas->drc_range = TAS3004_DRC_MAX / 2; |
904 | strlcpy(tas->i2c.name, "tas audio codec", I2C_NAME_SIZE); | ||
905 | |||
906 | if (i2c_attach_client(&tas->i2c)) { | ||
907 | printk(KERN_ERR PFX "failed to attach to i2c\n"); | ||
908 | goto fail; | ||
909 | } | ||
910 | 926 | ||
911 | strlcpy(tas->codec.name, "tas", MAX_CODEC_NAME_LEN); | 927 | strlcpy(tas->codec.name, "tas", MAX_CODEC_NAME_LEN); |
912 | tas->codec.owner = THIS_MODULE; | 928 | tas->codec.owner = THIS_MODULE; |
@@ -915,14 +931,12 @@ static int tas_create(struct i2c_adapter *adapter, | |||
915 | tas->codec.node = of_node_get(node); | 931 | tas->codec.node = of_node_get(node); |
916 | 932 | ||
917 | if (aoa_codec_register(&tas->codec)) { | 933 | if (aoa_codec_register(&tas->codec)) { |
918 | goto detach; | 934 | goto fail; |
919 | } | 935 | } |
920 | printk(KERN_DEBUG | 936 | printk(KERN_DEBUG |
921 | "snd-aoa-codec-tas: tas found, addr 0x%02x on %s\n", | 937 | "snd-aoa-codec-tas: tas found, addr 0x%02x on %s\n", |
922 | addr, node->full_name); | 938 | (unsigned int)client->addr, node->full_name); |
923 | return 0; | 939 | return 0; |
924 | detach: | ||
925 | i2c_detach_client(&tas->i2c); | ||
926 | fail: | 940 | fail: |
927 | mutex_destroy(&tas->mtx); | 941 | mutex_destroy(&tas->mtx); |
928 | kfree(tas); | 942 | kfree(tas); |
@@ -970,14 +984,11 @@ static int tas_i2c_attach(struct i2c_adapter *adapter) | |||
970 | return -ENODEV; | 984 | return -ENODEV; |
971 | } | 985 | } |
972 | 986 | ||
973 | static int tas_i2c_detach(struct i2c_client *client) | 987 | static int tas_i2c_remove(struct i2c_client *client) |
974 | { | 988 | { |
975 | struct tas *tas = container_of(client, struct tas, i2c); | 989 | struct tas *tas = i2c_get_clientdata(client); |
976 | int err; | ||
977 | u8 tmp = TAS_ACR_ANALOG_PDOWN; | 990 | u8 tmp = TAS_ACR_ANALOG_PDOWN; |
978 | 991 | ||
979 | if ((err = i2c_detach_client(client))) | ||
980 | return err; | ||
981 | aoa_codec_unregister(&tas->codec); | 992 | aoa_codec_unregister(&tas->codec); |
982 | of_node_put(tas->codec.node); | 993 | of_node_put(tas->codec.node); |
983 | 994 | ||
@@ -989,13 +1000,20 @@ static int tas_i2c_detach(struct i2c_client *client) | |||
989 | return 0; | 1000 | return 0; |
990 | } | 1001 | } |
991 | 1002 | ||
1003 | static const struct i2c_device_id tas_i2c_id[] = { | ||
1004 | { "aoa_codec_tas", 0 }, | ||
1005 | { } | ||
1006 | }; | ||
1007 | |||
992 | static struct i2c_driver tas_driver = { | 1008 | static struct i2c_driver tas_driver = { |
993 | .driver = { | 1009 | .driver = { |
994 | .name = "aoa_codec_tas", | 1010 | .name = "aoa_codec_tas", |
995 | .owner = THIS_MODULE, | 1011 | .owner = THIS_MODULE, |
996 | }, | 1012 | }, |
997 | .attach_adapter = tas_i2c_attach, | 1013 | .attach_adapter = tas_i2c_attach, |
998 | .detach_client = tas_i2c_detach, | 1014 | .probe = tas_i2c_probe, |
1015 | .remove = tas_i2c_remove, | ||
1016 | .id_table = tas_i2c_id, | ||
999 | }; | 1017 | }; |
1000 | 1018 | ||
1001 | static int __init tas_init(void) | 1019 | static int __init tas_init(void) |
diff --git a/sound/aoa/core/gpio-feature.c b/sound/aoa/core/gpio-feature.c index c93ad5dec66b..de8e03afa97b 100644 --- a/sound/aoa/core/gpio-feature.c +++ b/sound/aoa/core/gpio-feature.c | |||
@@ -14,7 +14,7 @@ | |||
14 | #include <linux/interrupt.h> | 14 | #include <linux/interrupt.h> |
15 | #include "../aoa.h" | 15 | #include "../aoa.h" |
16 | 16 | ||
17 | /* TODO: these are 20 global variables | 17 | /* TODO: these are lots of global variables |
18 | * that aren't used on most machines... | 18 | * that aren't used on most machines... |
19 | * Move them into a dynamically allocated | 19 | * Move them into a dynamically allocated |
20 | * structure and use that. | 20 | * structure and use that. |
@@ -23,6 +23,7 @@ | |||
23 | /* these are the GPIO numbers (register addresses as offsets into | 23 | /* these are the GPIO numbers (register addresses as offsets into |
24 | * the GPIO space) */ | 24 | * the GPIO space) */ |
25 | static int headphone_mute_gpio; | 25 | static int headphone_mute_gpio; |
26 | static int master_mute_gpio; | ||
26 | static int amp_mute_gpio; | 27 | static int amp_mute_gpio; |
27 | static int lineout_mute_gpio; | 28 | static int lineout_mute_gpio; |
28 | static int hw_reset_gpio; | 29 | static int hw_reset_gpio; |
@@ -32,6 +33,7 @@ static int linein_detect_gpio; | |||
32 | 33 | ||
33 | /* see the SWITCH_GPIO macro */ | 34 | /* see the SWITCH_GPIO macro */ |
34 | static int headphone_mute_gpio_activestate; | 35 | static int headphone_mute_gpio_activestate; |
36 | static int master_mute_gpio_activestate; | ||
35 | static int amp_mute_gpio_activestate; | 37 | static int amp_mute_gpio_activestate; |
36 | static int lineout_mute_gpio_activestate; | 38 | static int lineout_mute_gpio_activestate; |
37 | static int hw_reset_gpio_activestate; | 39 | static int hw_reset_gpio_activestate; |
@@ -156,6 +158,7 @@ static int ftr_gpio_get_##name(struct gpio_runtime *rt) \ | |||
156 | FTR_GPIO(headphone, 0); | 158 | FTR_GPIO(headphone, 0); |
157 | FTR_GPIO(amp, 1); | 159 | FTR_GPIO(amp, 1); |
158 | FTR_GPIO(lineout, 2); | 160 | FTR_GPIO(lineout, 2); |
161 | FTR_GPIO(master, 3); | ||
159 | 162 | ||
160 | static void ftr_gpio_set_hw_reset(struct gpio_runtime *rt, int on) | 163 | static void ftr_gpio_set_hw_reset(struct gpio_runtime *rt, int on) |
161 | { | 164 | { |
@@ -172,6 +175,8 @@ static void ftr_gpio_set_hw_reset(struct gpio_runtime *rt, int on) | |||
172 | hw_reset_gpio, v); | 175 | hw_reset_gpio, v); |
173 | } | 176 | } |
174 | 177 | ||
178 | static struct gpio_methods methods; | ||
179 | |||
175 | static void ftr_gpio_all_amps_off(struct gpio_runtime *rt) | 180 | static void ftr_gpio_all_amps_off(struct gpio_runtime *rt) |
176 | { | 181 | { |
177 | int saved; | 182 | int saved; |
@@ -181,6 +186,8 @@ static void ftr_gpio_all_amps_off(struct gpio_runtime *rt) | |||
181 | ftr_gpio_set_headphone(rt, 0); | 186 | ftr_gpio_set_headphone(rt, 0); |
182 | ftr_gpio_set_amp(rt, 0); | 187 | ftr_gpio_set_amp(rt, 0); |
183 | ftr_gpio_set_lineout(rt, 0); | 188 | ftr_gpio_set_lineout(rt, 0); |
189 | if (methods.set_master) | ||
190 | ftr_gpio_set_master(rt, 0); | ||
184 | rt->implementation_private = saved; | 191 | rt->implementation_private = saved; |
185 | } | 192 | } |
186 | 193 | ||
@@ -193,6 +200,8 @@ static void ftr_gpio_all_amps_restore(struct gpio_runtime *rt) | |||
193 | ftr_gpio_set_headphone(rt, (s>>0)&1); | 200 | ftr_gpio_set_headphone(rt, (s>>0)&1); |
194 | ftr_gpio_set_amp(rt, (s>>1)&1); | 201 | ftr_gpio_set_amp(rt, (s>>1)&1); |
195 | ftr_gpio_set_lineout(rt, (s>>2)&1); | 202 | ftr_gpio_set_lineout(rt, (s>>2)&1); |
203 | if (methods.set_master) | ||
204 | ftr_gpio_set_master(rt, (s>>3)&1); | ||
196 | } | 205 | } |
197 | 206 | ||
198 | static void ftr_handle_notify(struct work_struct *work) | 207 | static void ftr_handle_notify(struct work_struct *work) |
@@ -231,6 +240,12 @@ static void ftr_gpio_init(struct gpio_runtime *rt) | |||
231 | get_gpio("hw-reset", "audio-hw-reset", | 240 | get_gpio("hw-reset", "audio-hw-reset", |
232 | &hw_reset_gpio, | 241 | &hw_reset_gpio, |
233 | &hw_reset_gpio_activestate); | 242 | &hw_reset_gpio_activestate); |
243 | if (get_gpio("master-mute", NULL, | ||
244 | &master_mute_gpio, | ||
245 | &master_mute_gpio_activestate)) { | ||
246 | methods.set_master = ftr_gpio_set_master; | ||
247 | methods.get_master = ftr_gpio_get_master; | ||
248 | } | ||
234 | 249 | ||
235 | headphone_detect_node = get_gpio("headphone-detect", NULL, | 250 | headphone_detect_node = get_gpio("headphone-detect", NULL, |
236 | &headphone_detect_gpio, | 251 | &headphone_detect_gpio, |
diff --git a/sound/aoa/fabrics/layout.c b/sound/aoa/fabrics/layout.c index ad60f5d10e82..fbf5c933baa4 100644 --- a/sound/aoa/fabrics/layout.c +++ b/sound/aoa/fabrics/layout.c | |||
@@ -1,16 +1,14 @@ | |||
1 | /* | 1 | /* |
2 | * Apple Onboard Audio driver -- layout fabric | 2 | * Apple Onboard Audio driver -- layout/machine id fabric |
3 | * | 3 | * |
4 | * Copyright 2006 Johannes Berg <johannes@sipsolutions.net> | 4 | * Copyright 2006-2008 Johannes Berg <johannes@sipsolutions.net> |
5 | * | 5 | * |
6 | * GPL v2, can be found in COPYING. | 6 | * GPL v2, can be found in COPYING. |
7 | * | 7 | * |
8 | * | 8 | * |
9 | * This fabric module looks for sound codecs | 9 | * This fabric module looks for sound codecs based on the |
10 | * based on the layout-id property in the device tree. | 10 | * layout-id or device-id property in the device tree. |
11 | * | ||
12 | */ | 11 | */ |
13 | |||
14 | #include <asm/prom.h> | 12 | #include <asm/prom.h> |
15 | #include <linux/list.h> | 13 | #include <linux/list.h> |
16 | #include <linux/module.h> | 14 | #include <linux/module.h> |
@@ -63,7 +61,7 @@ struct codec_connect_info { | |||
63 | #define LAYOUT_FLAG_COMBO_LINEOUT_SPDIF (1<<0) | 61 | #define LAYOUT_FLAG_COMBO_LINEOUT_SPDIF (1<<0) |
64 | 62 | ||
65 | struct layout { | 63 | struct layout { |
66 | unsigned int layout_id; | 64 | unsigned int layout_id, device_id; |
67 | struct codec_connect_info codecs[MAX_CODECS_PER_BUS]; | 65 | struct codec_connect_info codecs[MAX_CODECS_PER_BUS]; |
68 | int flags; | 66 | int flags; |
69 | 67 | ||
@@ -111,6 +109,10 @@ MODULE_ALIAS("sound-layout-96"); | |||
111 | MODULE_ALIAS("sound-layout-98"); | 109 | MODULE_ALIAS("sound-layout-98"); |
112 | MODULE_ALIAS("sound-layout-100"); | 110 | MODULE_ALIAS("sound-layout-100"); |
113 | 111 | ||
112 | MODULE_ALIAS("aoa-device-id-14"); | ||
113 | MODULE_ALIAS("aoa-device-id-22"); | ||
114 | MODULE_ALIAS("aoa-device-id-35"); | ||
115 | |||
114 | /* onyx with all but microphone connected */ | 116 | /* onyx with all but microphone connected */ |
115 | static struct codec_connection onyx_connections_nomic[] = { | 117 | static struct codec_connection onyx_connections_nomic[] = { |
116 | { | 118 | { |
@@ -518,6 +520,27 @@ static struct layout layouts[] = { | |||
518 | .connections = onyx_connections_noheadphones, | 520 | .connections = onyx_connections_noheadphones, |
519 | }, | 521 | }, |
520 | }, | 522 | }, |
523 | /* PowerMac3,4 */ | ||
524 | { .device_id = 14, | ||
525 | .codecs[0] = { | ||
526 | .name = "tas", | ||
527 | .connections = tas_connections_noline, | ||
528 | }, | ||
529 | }, | ||
530 | /* PowerMac3,6 */ | ||
531 | { .device_id = 22, | ||
532 | .codecs[0] = { | ||
533 | .name = "tas", | ||
534 | .connections = tas_connections_all, | ||
535 | }, | ||
536 | }, | ||
537 | /* PowerBook5,2 */ | ||
538 | { .device_id = 35, | ||
539 | .codecs[0] = { | ||
540 | .name = "tas", | ||
541 | .connections = tas_connections_all, | ||
542 | }, | ||
543 | }, | ||
521 | {} | 544 | {} |
522 | }; | 545 | }; |
523 | 546 | ||
@@ -526,7 +549,7 @@ static struct layout *find_layout_by_id(unsigned int id) | |||
526 | struct layout *l; | 549 | struct layout *l; |
527 | 550 | ||
528 | l = layouts; | 551 | l = layouts; |
529 | while (l->layout_id) { | 552 | while (l->codecs[0].name) { |
530 | if (l->layout_id == id) | 553 | if (l->layout_id == id) |
531 | return l; | 554 | return l; |
532 | l++; | 555 | l++; |
@@ -534,6 +557,19 @@ static struct layout *find_layout_by_id(unsigned int id) | |||
534 | return NULL; | 557 | return NULL; |
535 | } | 558 | } |
536 | 559 | ||
560 | static struct layout *find_layout_by_device(unsigned int id) | ||
561 | { | ||
562 | struct layout *l; | ||
563 | |||
564 | l = layouts; | ||
565 | while (l->codecs[0].name) { | ||
566 | if (l->device_id == id) | ||
567 | return l; | ||
568 | l++; | ||
569 | } | ||
570 | return NULL; | ||
571 | } | ||
572 | |||
537 | static void use_layout(struct layout *l) | 573 | static void use_layout(struct layout *l) |
538 | { | 574 | { |
539 | int i; | 575 | int i; |
@@ -564,6 +600,7 @@ struct layout_dev { | |||
564 | struct snd_kcontrol *headphone_ctrl; | 600 | struct snd_kcontrol *headphone_ctrl; |
565 | struct snd_kcontrol *lineout_ctrl; | 601 | struct snd_kcontrol *lineout_ctrl; |
566 | struct snd_kcontrol *speaker_ctrl; | 602 | struct snd_kcontrol *speaker_ctrl; |
603 | struct snd_kcontrol *master_ctrl; | ||
567 | struct snd_kcontrol *headphone_detected_ctrl; | 604 | struct snd_kcontrol *headphone_detected_ctrl; |
568 | struct snd_kcontrol *lineout_detected_ctrl; | 605 | struct snd_kcontrol *lineout_detected_ctrl; |
569 | 606 | ||
@@ -615,6 +652,7 @@ static struct snd_kcontrol_new n##_ctl = { \ | |||
615 | AMP_CONTROL(headphone, "Headphone Switch"); | 652 | AMP_CONTROL(headphone, "Headphone Switch"); |
616 | AMP_CONTROL(speakers, "Speakers Switch"); | 653 | AMP_CONTROL(speakers, "Speakers Switch"); |
617 | AMP_CONTROL(lineout, "Line-Out Switch"); | 654 | AMP_CONTROL(lineout, "Line-Out Switch"); |
655 | AMP_CONTROL(master, "Master Switch"); | ||
618 | 656 | ||
619 | static int detect_choice_get(struct snd_kcontrol *kcontrol, | 657 | static int detect_choice_get(struct snd_kcontrol *kcontrol, |
620 | struct snd_ctl_elem_value *ucontrol) | 658 | struct snd_ctl_elem_value *ucontrol) |
@@ -855,6 +893,11 @@ static void layout_attached_codec(struct aoa_codec *codec) | |||
855 | lineout = codec->gpio->methods->get_detect(codec->gpio, | 893 | lineout = codec->gpio->methods->get_detect(codec->gpio, |
856 | AOA_NOTIFY_LINE_OUT); | 894 | AOA_NOTIFY_LINE_OUT); |
857 | 895 | ||
896 | if (codec->gpio->methods->set_master) { | ||
897 | ctl = snd_ctl_new1(&master_ctl, codec->gpio); | ||
898 | ldev->master_ctrl = ctl; | ||
899 | aoa_snd_ctl_add(ctl); | ||
900 | } | ||
858 | while (cc->connected) { | 901 | while (cc->connected) { |
859 | if (cc->connected & CC_SPEAKERS) { | 902 | if (cc->connected & CC_SPEAKERS) { |
860 | if (headphones <= 0 && lineout <= 0) | 903 | if (headphones <= 0 && lineout <= 0) |
@@ -938,8 +981,8 @@ static struct aoa_fabric layout_fabric = { | |||
938 | static int aoa_fabric_layout_probe(struct soundbus_dev *sdev) | 981 | static int aoa_fabric_layout_probe(struct soundbus_dev *sdev) |
939 | { | 982 | { |
940 | struct device_node *sound = NULL; | 983 | struct device_node *sound = NULL; |
941 | const unsigned int *layout_id; | 984 | const unsigned int *id; |
942 | struct layout *layout; | 985 | struct layout *layout = NULL; |
943 | struct layout_dev *ldev = NULL; | 986 | struct layout_dev *ldev = NULL; |
944 | int err; | 987 | int err; |
945 | 988 | ||
@@ -952,15 +995,18 @@ static int aoa_fabric_layout_probe(struct soundbus_dev *sdev) | |||
952 | if (sound->type && strcasecmp(sound->type, "soundchip") == 0) | 995 | if (sound->type && strcasecmp(sound->type, "soundchip") == 0) |
953 | break; | 996 | break; |
954 | } | 997 | } |
955 | if (!sound) return -ENODEV; | 998 | if (!sound) |
999 | return -ENODEV; | ||
956 | 1000 | ||
957 | layout_id = of_get_property(sound, "layout-id", NULL); | 1001 | id = of_get_property(sound, "layout-id", NULL); |
958 | if (!layout_id) | 1002 | if (id) { |
959 | goto outnodev; | 1003 | layout = find_layout_by_id(*id); |
960 | printk(KERN_INFO "snd-aoa-fabric-layout: found bus with layout %d\n", | 1004 | } else { |
961 | *layout_id); | 1005 | id = of_get_property(sound, "device-id", NULL); |
1006 | if (id) | ||
1007 | layout = find_layout_by_device(*id); | ||
1008 | } | ||
962 | 1009 | ||
963 | layout = find_layout_by_id(*layout_id); | ||
964 | if (!layout) { | 1010 | if (!layout) { |
965 | printk(KERN_ERR "snd-aoa-fabric-layout: unknown layout\n"); | 1011 | printk(KERN_ERR "snd-aoa-fabric-layout: unknown layout\n"); |
966 | goto outnodev; | 1012 | goto outnodev; |
@@ -976,6 +1022,7 @@ static int aoa_fabric_layout_probe(struct soundbus_dev *sdev) | |||
976 | ldev->layout = layout; | 1022 | ldev->layout = layout; |
977 | ldev->gpio.node = sound->parent; | 1023 | ldev->gpio.node = sound->parent; |
978 | switch (layout->layout_id) { | 1024 | switch (layout->layout_id) { |
1025 | case 0: /* anything with device_id, not layout_id */ | ||
979 | case 41: /* that unknown machine no one seems to have */ | 1026 | case 41: /* that unknown machine no one seems to have */ |
980 | case 51: /* PowerBook5,4 */ | 1027 | case 51: /* PowerBook5,4 */ |
981 | case 58: /* Mac Mini */ | 1028 | case 58: /* Mac Mini */ |
diff --git a/sound/aoa/soundbus/i2sbus/core.c b/sound/aoa/soundbus/i2sbus/core.c index be468edf3ecb..418c84c99d69 100644 --- a/sound/aoa/soundbus/i2sbus/core.c +++ b/sound/aoa/soundbus/i2sbus/core.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * i2sbus driver | 2 | * i2sbus driver |
3 | * | 3 | * |
4 | * Copyright 2006 Johannes Berg <johannes@sipsolutions.net> | 4 | * Copyright 2006-2008 Johannes Berg <johannes@sipsolutions.net> |
5 | * | 5 | * |
6 | * GPL v2, can be found in COPYING. | 6 | * GPL v2, can be found in COPYING. |
7 | */ | 7 | */ |
@@ -186,13 +186,25 @@ static int i2sbus_add_dev(struct macio_dev *macio, | |||
186 | } | 186 | } |
187 | } | 187 | } |
188 | if (i == 1) { | 188 | if (i == 1) { |
189 | const u32 *layout_id = | 189 | const u32 *id = of_get_property(sound, "layout-id", NULL); |
190 | of_get_property(sound, "layout-id", NULL); | 190 | |
191 | if (layout_id) { | 191 | if (id) { |
192 | layout = *layout_id; | 192 | layout = *id; |
193 | snprintf(dev->sound.modalias, 32, | 193 | snprintf(dev->sound.modalias, 32, |
194 | "sound-layout-%d", layout); | 194 | "sound-layout-%d", layout); |
195 | ok = 1; | 195 | ok = 1; |
196 | } else { | ||
197 | id = of_get_property(sound, "device-id", NULL); | ||
198 | /* | ||
199 | * We probably cannot handle all device-id machines, | ||
200 | * so restrict to those we do handle for now. | ||
201 | */ | ||
202 | if (id && (*id == 22 || *id == 14 || *id == 35)) { | ||
203 | snprintf(dev->sound.modalias, 32, | ||
204 | "aoa-device-id-%d", *id); | ||
205 | ok = 1; | ||
206 | layout = -1; | ||
207 | } | ||
196 | } | 208 | } |
197 | } | 209 | } |
198 | /* for the time being, until we can handle non-layout-id | 210 | /* for the time being, until we can handle non-layout-id |