diff options
Diffstat (limited to 'sound/aoa/codecs/onyx.c')
-rw-r--r-- | sound/aoa/codecs/onyx.c | 76 |
1 files changed, 53 insertions, 23 deletions
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) |