aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/codecs/tlv320aic3x.c
diff options
context:
space:
mode:
authorLiam Girdwood <lrg@slimlogic.co.uk>2010-03-17 16:15:21 -0400
committerLiam Girdwood <lrg@slimlogic.co.uk>2010-08-12 09:00:00 -0400
commitf0fba2ad1b6b53d5360125c41953b7afcd6deff0 (patch)
treef6ad50905f8daa616593c978d7ae992e73241180 /sound/soc/codecs/tlv320aic3x.c
parentbda7d2a862e6b788bca2d02d38a07966a9c92e48 (diff)
ASoC: multi-component - ASoC Multi-Component Support
This patch extends the ASoC API to allow sound cards to have more than one CODEC and more than one platform DMA controller. This is achieved by dividing some current ASoC structures that contain both driver data and device data into structures that only either contain device data or driver data. i.e. struct snd_soc_codec ---> struct snd_soc_codec (device data) +-> struct snd_soc_codec_driver (driver data) struct snd_soc_platform ---> struct snd_soc_platform (device data) +-> struct snd_soc_platform_driver (driver data) struct snd_soc_dai ---> struct snd_soc_dai (device data) +-> struct snd_soc_dai_driver (driver data) struct snd_soc_device ---> deleted This now allows ASoC to be more tightly aligned with the Linux driver model and also means that every ASoC codec, platform and (platform) DAI is a kernel device. ASoC component private data is now stored as device private data. The ASoC sound card struct snd_soc_card has also been updated to store lists of it's components rather than a pointer to a codec and platform. The PCM runtime struct soc_pcm_runtime now has pointers to all its components. This patch adds DAPM support for ASoC multi-component and removes struct snd_soc_socdev from DAPM core. All DAPM calls are now made on a card, codec or runtime PCM level basis rather than using snd_soc_socdev. Other notable multi-component changes:- * Stream operations now de-reference less structures. * close_delayed work() now runs on a DAI basis rather than looping all DAIs in a card. * PM suspend()/resume() operations can now handle N CODECs and Platforms per sound card. * Added soc_bind_dai_link() to bind the component devices to the sound card. * Added soc_dai_link_probe() and soc_dai_link_remove() to probe and remove DAI link components. * sysfs entries can now be registered per component per card. * snd_soc_new_pcms() functionailty rolled into dai_link_probe(). * snd_soc_register_codec() now does all the codec list and mutex init. This patch changes the probe() and remove() of the CODEC drivers as follows:- o Make CODEC driver a platform driver o Moved all struct snd_soc_codec list, mutex, etc initialiasation to core. o Removed all static codec pointers (drivers now support > 1 codec dev) o snd_soc_register_pcms() now done by core. o snd_soc_register_dai() folded into snd_soc_register_codec(). CS4270 portions: Acked-by: Timur Tabi <timur@freescale.com> Some TLV320aic23 and Cirrus platform fixes. Signed-off-by: Ryan Mallon <ryan@bluewatersys.com> TI CODEC and OMAP fixes Signed-off-by: Peter Ujfalusi <peter.ujfalusi@nokia.com> Signed-off-by: Janusz Krzysztofik <jkrzyszt@tis.icnet.pl> Signed-off-by: Jarkko Nikula <jhnikula@gmail.com> Samsung platform and misc fixes :- Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com> Signed-off-by: Joonyoung Shim <jy0922.shim@samsung.com> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com> Reviewed-by: Jassi Brar <jassi.brar@samsung.com> Signed-off-by: Seungwhan Youn <sw.youn@samsung.com> MPC8610 and PPC fixes. Signed-off-by: Timur Tabi <timur@freescale.com> i.MX fixes and some core fixes. Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de> J4740 platform fixes:- Signed-off-by: Lars-Peter Clausen <lars@metafoo.de> CC: Tony Lindgren <tony@atomide.com> CC: Nicolas Ferre <nicolas.ferre@atmel.com> CC: Kevin Hilman <khilman@deeprootsystems.com> CC: Sascha Hauer <s.hauer@pengutronix.de> CC: Atsushi Nemoto <anemo@mba.ocn.ne.jp> CC: Kuninori Morimoto <morimoto.kuninori@renesas.com> CC: Daniel Gloeckner <dg@emlix.com> CC: Manuel Lauss <mano@roarinelk.homelinux.net> CC: Mike Frysinger <vapier.adi@gmail.com> CC: Arnaud Patard <apatard@mandriva.com> CC: Wan ZongShun <mcuos.com@gmail.com> Acked-by: Mark Brown <broonie@opensource.wolfsonmicro.com> Signed-off-by: Liam Girdwood <lrg@slimlogic.co.uk>
Diffstat (limited to 'sound/soc/codecs/tlv320aic3x.c')
-rw-r--r--sound/soc/codecs/tlv320aic3x.c223
1 files changed, 71 insertions, 152 deletions
diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c
index 71a69908ccf6..43fd9c171742 100644
--- a/sound/soc/codecs/tlv320aic3x.c
+++ b/sound/soc/codecs/tlv320aic3x.c
@@ -63,8 +63,10 @@ static const char *aic3x_supply_names[AIC3X_NUM_SUPPLIES] = {
63 63
64/* codec private data */ 64/* codec private data */
65struct aic3x_priv { 65struct aic3x_priv {
66 struct snd_soc_codec codec;
67 struct regulator_bulk_data supplies[AIC3X_NUM_SUPPLIES]; 66 struct regulator_bulk_data supplies[AIC3X_NUM_SUPPLIES];
67 enum snd_soc_control_type control_type;
68 struct aic3x_setup_data *setup;
69 void *control_data;
68 unsigned int sysclk; 70 unsigned int sysclk;
69 int master; 71 int master;
70 int gpio_reset; 72 int gpio_reset;
@@ -773,8 +775,7 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream,
773 struct snd_soc_dai *dai) 775 struct snd_soc_dai *dai)
774{ 776{
775 struct snd_soc_pcm_runtime *rtd = substream->private_data; 777 struct snd_soc_pcm_runtime *rtd = substream->private_data;
776 struct snd_soc_device *socdev = rtd->socdev; 778 struct snd_soc_codec *codec =rtd->codec;
777 struct snd_soc_codec *codec = socdev->card->codec;
778 struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec); 779 struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec);
779 int codec_clk = 0, bypass_pll = 0, fsref, last_clk = 0; 780 int codec_clk = 0, bypass_pll = 0, fsref, last_clk = 0;
780 u8 data, j, r, p, pll_q, pll_p = 1, pll_r = 1, pll_j = 1; 781 u8 data, j, r, p, pll_q, pll_p = 1, pll_r = 1, pll_j = 1;
@@ -1101,8 +1102,8 @@ static struct snd_soc_dai_ops aic3x_dai_ops = {
1101 .set_fmt = aic3x_set_dai_fmt, 1102 .set_fmt = aic3x_set_dai_fmt,
1102}; 1103};
1103 1104
1104struct snd_soc_dai aic3x_dai = { 1105static struct snd_soc_dai_driver aic3x_dai = {
1105 .name = "tlv320aic3x", 1106 .name = "tlv320aic3x-hifi",
1106 .playback = { 1107 .playback = {
1107 .stream_name = "Playback", 1108 .stream_name = "Playback",
1108 .channels_min = 1, 1109 .channels_min = 1,
@@ -1117,22 +1118,16 @@ struct snd_soc_dai aic3x_dai = {
1117 .formats = AIC3X_FORMATS,}, 1118 .formats = AIC3X_FORMATS,},
1118 .ops = &aic3x_dai_ops, 1119 .ops = &aic3x_dai_ops,
1119}; 1120};
1120EXPORT_SYMBOL_GPL(aic3x_dai);
1121 1121
1122static int aic3x_suspend(struct platform_device *pdev, pm_message_t state) 1122static int aic3x_suspend(struct snd_soc_codec *codec, pm_message_t state)
1123{ 1123{
1124 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
1125 struct snd_soc_codec *codec = socdev->card->codec;
1126
1127 aic3x_set_bias_level(codec, SND_SOC_BIAS_OFF); 1124 aic3x_set_bias_level(codec, SND_SOC_BIAS_OFF);
1128 1125
1129 return 0; 1126 return 0;
1130} 1127}
1131 1128
1132static int aic3x_resume(struct platform_device *pdev) 1129static int aic3x_resume(struct snd_soc_codec *codec)
1133{ 1130{
1134 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
1135 struct snd_soc_codec *codec = socdev->card->codec;
1136 int i; 1131 int i;
1137 u8 data[2]; 1132 u8 data[2];
1138 u8 *cache = codec->reg_cache; 1133 u8 *cache = codec->reg_cache;
@@ -1157,22 +1152,6 @@ static int aic3x_init(struct snd_soc_codec *codec)
1157{ 1152{
1158 int reg; 1153 int reg;
1159 1154
1160 mutex_init(&codec->mutex);
1161 INIT_LIST_HEAD(&codec->dapm_widgets);
1162 INIT_LIST_HEAD(&codec->dapm_paths);
1163
1164 codec->name = "tlv320aic3x";
1165 codec->owner = THIS_MODULE;
1166 codec->read = aic3x_read_reg_cache;
1167 codec->write = aic3x_write;
1168 codec->set_bias_level = aic3x_set_bias_level;
1169 codec->dai = &aic3x_dai;
1170 codec->num_dai = 1;
1171 codec->reg_cache_size = ARRAY_SIZE(aic3x_reg);
1172 codec->reg_cache = kmemdup(aic3x_reg, sizeof(aic3x_reg), GFP_KERNEL);
1173 if (codec->reg_cache == NULL)
1174 return -ENOMEM;
1175
1176 aic3x_write(codec, AIC3X_PAGE_SELECT, PAGE0_SELECT); 1155 aic3x_write(codec, AIC3X_PAGE_SELECT, PAGE0_SELECT);
1177 aic3x_write(codec, AIC3X_RESET, SOFT_RESET); 1156 aic3x_write(codec, AIC3X_RESET, SOFT_RESET);
1178 1157
@@ -1245,56 +1224,50 @@ static int aic3x_init(struct snd_soc_codec *codec)
1245 return 0; 1224 return 0;
1246} 1225}
1247 1226
1248static struct snd_soc_codec *aic3x_codec; 1227static int aic3x_probe(struct snd_soc_codec *codec)
1249
1250static int aic3x_register(struct snd_soc_codec *codec)
1251{ 1228{
1252 int ret; 1229 struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec);
1230
1231 codec->hw_write = (hw_write_t) i2c_master_send;
1232 codec->control_data = aic3x->control_data;
1253 1233
1254 ret = aic3x_init(codec); 1234 if (aic3x->setup) {
1255 if (ret < 0) { 1235 /* setup GPIO functions */
1256 dev_err(codec->dev, "Failed to initialise device\n"); 1236 aic3x_write(codec, AIC3X_GPIO1_REG,
1257 return ret; 1237 (aic3x->setup->gpio_func[0] & 0xf) << 4);
1238 aic3x_write(codec, AIC3X_GPIO2_REG,
1239 (aic3x->setup->gpio_func[1] & 0xf) << 4);
1258 } 1240 }
1259 1241
1260 aic3x_codec = codec; 1242 aic3x_init(codec);
1261 1243
1262 ret = snd_soc_register_codec(codec); 1244 snd_soc_add_controls(codec, aic3x_snd_controls,
1263 if (ret) { 1245 ARRAY_SIZE(aic3x_snd_controls));
1264 dev_err(codec->dev, "Failed to register codec\n");
1265 return ret;
1266 }
1267 1246
1268 ret = snd_soc_register_dai(&aic3x_dai); 1247 aic3x_add_widgets(codec);
1269 if (ret) {
1270 dev_err(codec->dev, "Failed to register dai\n");
1271 snd_soc_unregister_codec(codec);
1272 return ret;
1273 }
1274 1248
1275 return 0; 1249 return 0;
1276} 1250}
1277 1251
1278static int aic3x_unregister(struct aic3x_priv *aic3x) 1252static int aic3x_remove(struct snd_soc_codec *codec)
1279{ 1253{
1280 aic3x_set_bias_level(&aic3x->codec, SND_SOC_BIAS_OFF); 1254 aic3x_set_bias_level(codec, SND_SOC_BIAS_OFF);
1281
1282 snd_soc_unregister_dai(&aic3x_dai);
1283 snd_soc_unregister_codec(&aic3x->codec);
1284
1285 if (aic3x->gpio_reset >= 0) {
1286 gpio_set_value(aic3x->gpio_reset, 0);
1287 gpio_free(aic3x->gpio_reset);
1288 }
1289 regulator_bulk_disable(ARRAY_SIZE(aic3x->supplies), aic3x->supplies);
1290 regulator_bulk_free(ARRAY_SIZE(aic3x->supplies), aic3x->supplies);
1291
1292 kfree(aic3x);
1293 aic3x_codec = NULL;
1294
1295 return 0; 1255 return 0;
1296} 1256}
1297 1257
1258static struct snd_soc_codec_driver soc_codec_dev_aic3x = {
1259 .read = aic3x_read_reg_cache,
1260 .write = aic3x_write,
1261 .set_bias_level = aic3x_set_bias_level,
1262 .reg_cache_size = ARRAY_SIZE(aic3x_reg),
1263 .reg_word_size = sizeof(u8),
1264 .reg_cache_default = aic3x_reg,
1265 .probe = aic3x_probe,
1266 .remove = aic3x_remove,
1267 .suspend = aic3x_suspend,
1268 .resume = aic3x_resume,
1269};
1270
1298#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) 1271#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
1299/* 1272/*
1300 * AIC3X 2 wire address can be up to 4 devices with device addresses 1273 * AIC3X 2 wire address can be up to 4 devices with device addresses
@@ -1308,9 +1281,9 @@ static int aic3x_unregister(struct aic3x_priv *aic3x)
1308static int aic3x_i2c_probe(struct i2c_client *i2c, 1281static int aic3x_i2c_probe(struct i2c_client *i2c,
1309 const struct i2c_device_id *id) 1282 const struct i2c_device_id *id)
1310{ 1283{
1311 struct snd_soc_codec *codec;
1312 struct aic3x_priv *aic3x;
1313 struct aic3x_pdata *pdata = i2c->dev.platform_data; 1284 struct aic3x_pdata *pdata = i2c->dev.platform_data;
1285 struct aic3x_setup_data *setup = pdata->setup;
1286 struct aic3x_priv *aic3x;
1314 int ret, i; 1287 int ret, i;
1315 1288
1316 aic3x = kzalloc(sizeof(struct aic3x_priv), GFP_KERNEL); 1289 aic3x = kzalloc(sizeof(struct aic3x_priv), GFP_KERNEL);
@@ -1319,12 +1292,8 @@ static int aic3x_i2c_probe(struct i2c_client *i2c,
1319 return -ENOMEM; 1292 return -ENOMEM;
1320 } 1293 }
1321 1294
1322 codec = &aic3x->codec; 1295 aic3x->control_data = i2c;
1323 codec->dev = &i2c->dev; 1296 aic3x->setup = setup;
1324 snd_soc_codec_set_drvdata(codec, aic3x);
1325 codec->control_data = i2c;
1326 codec->hw_write = (hw_write_t) i2c_master_send;
1327
1328 i2c_set_clientdata(i2c, aic3x); 1297 i2c_set_clientdata(i2c, aic3x);
1329 1298
1330 aic3x->gpio_reset = -1; 1299 aic3x->gpio_reset = -1;
@@ -1339,17 +1308,17 @@ static int aic3x_i2c_probe(struct i2c_client *i2c,
1339 for (i = 0; i < ARRAY_SIZE(aic3x->supplies); i++) 1308 for (i = 0; i < ARRAY_SIZE(aic3x->supplies); i++)
1340 aic3x->supplies[i].supply = aic3x_supply_names[i]; 1309 aic3x->supplies[i].supply = aic3x_supply_names[i];
1341 1310
1342 ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(aic3x->supplies), 1311 ret = regulator_bulk_get(&i2c->dev, ARRAY_SIZE(aic3x->supplies),
1343 aic3x->supplies); 1312 aic3x->supplies);
1344 if (ret != 0) { 1313 if (ret != 0) {
1345 dev_err(codec->dev, "Failed to request supplies: %d\n", ret); 1314 dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret);
1346 goto err_get; 1315 goto err_get;
1347 } 1316 }
1348 1317
1349 ret = regulator_bulk_enable(ARRAY_SIZE(aic3x->supplies), 1318 ret = regulator_bulk_enable(ARRAY_SIZE(aic3x->supplies),
1350 aic3x->supplies); 1319 aic3x->supplies);
1351 if (ret != 0) { 1320 if (ret != 0) {
1352 dev_err(codec->dev, "Failed to enable supplies: %d\n", ret); 1321 dev_err(&i2c->dev, "Failed to enable supplies: %d\n", ret);
1353 goto err_enable; 1322 goto err_enable;
1354 } 1323 }
1355 1324
@@ -1358,7 +1327,11 @@ static int aic3x_i2c_probe(struct i2c_client *i2c,
1358 gpio_set_value(aic3x->gpio_reset, 1); 1327 gpio_set_value(aic3x->gpio_reset, 1);
1359 } 1328 }
1360 1329
1361 return aic3x_register(codec); 1330 ret = snd_soc_register_codec(&i2c->dev,
1331 &soc_codec_dev_aic3x, &aic3x_dai, 1);
1332 if (ret < 0)
1333 goto err_enable;
1334 return ret;
1362 1335
1363err_enable: 1336err_enable:
1364 regulator_bulk_free(ARRAY_SIZE(aic3x->supplies), aic3x->supplies); 1337 regulator_bulk_free(ARRAY_SIZE(aic3x->supplies), aic3x->supplies);
@@ -1374,7 +1347,16 @@ static int aic3x_i2c_remove(struct i2c_client *client)
1374{ 1347{
1375 struct aic3x_priv *aic3x = i2c_get_clientdata(client); 1348 struct aic3x_priv *aic3x = i2c_get_clientdata(client);
1376 1349
1377 return aic3x_unregister(aic3x); 1350 if (aic3x->gpio_reset >= 0) {
1351 gpio_set_value(aic3x->gpio_reset, 0);
1352 gpio_free(aic3x->gpio_reset);
1353 }
1354 regulator_bulk_disable(ARRAY_SIZE(aic3x->supplies), aic3x->supplies);
1355 regulator_bulk_free(ARRAY_SIZE(aic3x->supplies), aic3x->supplies);
1356
1357 snd_soc_unregister_codec(&client->dev);
1358 kfree(i2c_get_clientdata(client));
1359 return 0;
1378} 1360}
1379 1361
1380static const struct i2c_device_id aic3x_i2c_id[] = { 1362static const struct i2c_device_id aic3x_i2c_id[] = {
@@ -1387,7 +1369,7 @@ MODULE_DEVICE_TABLE(i2c, aic3x_i2c_id);
1387/* machine i2c codec control layer */ 1369/* machine i2c codec control layer */
1388static struct i2c_driver aic3x_i2c_driver = { 1370static struct i2c_driver aic3x_i2c_driver = {
1389 .driver = { 1371 .driver = {
1390 .name = "aic3x I2C Codec", 1372 .name = "tlv320aic3x-codec",
1391 .owner = THIS_MODULE, 1373 .owner = THIS_MODULE,
1392 }, 1374 },
1393 .probe = aic3x_i2c_probe, 1375 .probe = aic3x_i2c_probe,
@@ -1409,90 +1391,27 @@ static inline void aic3x_i2c_exit(void)
1409{ 1391{
1410 i2c_del_driver(&aic3x_i2c_driver); 1392 i2c_del_driver(&aic3x_i2c_driver);
1411} 1393}
1412#else
1413static inline void aic3x_i2c_init(void) { }
1414static inline void aic3x_i2c_exit(void) { }
1415#endif 1394#endif
1416 1395
1417static int aic3x_probe(struct platform_device *pdev) 1396static int __init aic3x_modinit(void)
1418{ 1397{
1419 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
1420 struct aic3x_setup_data *setup;
1421 struct snd_soc_codec *codec;
1422 int ret = 0; 1398 int ret = 0;
1423 1399#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
1424 codec = aic3x_codec; 1400 ret = i2c_add_driver(&aic3x_i2c_driver);
1425 if (!codec) { 1401 if (ret != 0) {
1426 dev_err(&pdev->dev, "Codec not registered\n"); 1402 printk(KERN_ERR "Failed to register TLV320AIC3x I2C driver: %d\n",
1427 return -ENODEV; 1403 ret);
1428 }
1429
1430 socdev->card->codec = codec;
1431 setup = socdev->codec_data;
1432
1433 if (setup) {
1434 /* setup GPIO functions */
1435 aic3x_write(codec, AIC3X_GPIO1_REG,
1436 (setup->gpio_func[0] & 0xf) << 4);
1437 aic3x_write(codec, AIC3X_GPIO2_REG,
1438 (setup->gpio_func[1] & 0xf) << 4);
1439 }
1440
1441 /* register pcms */
1442 ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
1443 if (ret < 0) {
1444 printk(KERN_ERR "aic3x: failed to create pcms\n");
1445 goto pcm_err;
1446 } 1404 }
1447 1405#endif
1448 snd_soc_add_controls(codec, aic3x_snd_controls,
1449 ARRAY_SIZE(aic3x_snd_controls));
1450
1451 aic3x_add_widgets(codec);
1452
1453 return ret;
1454
1455pcm_err:
1456 kfree(codec->reg_cache);
1457 return ret; 1406 return ret;
1458} 1407}
1459
1460static int aic3x_remove(struct platform_device *pdev)
1461{
1462 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
1463 struct snd_soc_codec *codec = socdev->card->codec;
1464
1465 /* power down chip */
1466 if (codec->control_data)
1467 aic3x_set_bias_level(codec, SND_SOC_BIAS_OFF);
1468
1469 snd_soc_free_pcms(socdev);
1470 snd_soc_dapm_free(socdev);
1471
1472 kfree(codec->reg_cache);
1473
1474 return 0;
1475}
1476
1477struct snd_soc_codec_device soc_codec_dev_aic3x = {
1478 .probe = aic3x_probe,
1479 .remove = aic3x_remove,
1480 .suspend = aic3x_suspend,
1481 .resume = aic3x_resume,
1482};
1483EXPORT_SYMBOL_GPL(soc_codec_dev_aic3x);
1484
1485static int __init aic3x_modinit(void)
1486{
1487 aic3x_i2c_init();
1488
1489 return 0;
1490}
1491module_init(aic3x_modinit); 1408module_init(aic3x_modinit);
1492 1409
1493static void __exit aic3x_exit(void) 1410static void __exit aic3x_exit(void)
1494{ 1411{
1495 aic3x_i2c_exit(); 1412#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
1413 i2c_del_driver(&aic3x_i2c_driver);
1414#endif
1496} 1415}
1497module_exit(aic3x_exit); 1416module_exit(aic3x_exit);
1498 1417