aboutsummaryrefslogtreecommitdiffstats
path: root/sound
diff options
context:
space:
mode:
authorJarkko Nikula <jhnikula@gmail.com>2010-11-01 08:03:56 -0400
committerLiam Girdwood <lrg@slimlogic.co.uk>2010-11-03 10:18:58 -0400
commit414c73abfd0e565950f3b02336cf516147f0e104 (patch)
tree173fdad40106b19f7c58006833c108a0fcc23d0a /sound
parent79ee820d2aa24ac2577ca4e89ecc49c26d099707 (diff)
ASoC: tlv320aic3x: Add support to shared common reset line
This is aimed to configurations where multiple aic3x codecs share the same reset line and are powered from same supply voltages. Currently aic3x_probe will fail if trying to request already requested gpio_reset and passing -1 to another aic3x instances cause that those instances cannot release reset in aic3x_set_power. That is, another instances can work only if primary aic3x instance is powered and reset is released. Solve this by implementing a list of probed instances that is used for checking if other instance shares the same gpio_reset number. If a shared reset line exists, then only first instance tries to request and configure it and the last instance releases it. Runtime modifications are not needed since aic3x_regulator_event with help of regulator framework takes already care that reset is pulled down only when some or all supplies are disabled meaning that all instances using them are idle. Signed-off-by: Jarkko Nikula <jhnikula@gmail.com> Acked-by: Mark Brown <broonie@opensource.wolfsonmicro.com> Signed-off-by: Liam Girdwood <lrg@slimlogic.co.uk>
Diffstat (limited to 'sound')
-rw-r--r--sound/soc/codecs/tlv320aic3x.c28
1 files changed, 25 insertions, 3 deletions
diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c
index 157b534585f4..684ca3a57caa 100644
--- a/sound/soc/codecs/tlv320aic3x.c
+++ b/sound/soc/codecs/tlv320aic3x.c
@@ -61,6 +61,8 @@ static const char *aic3x_supply_names[AIC3X_NUM_SUPPLIES] = {
61 "DRVDD", /* ADC Analog and Output Driver Voltage */ 61 "DRVDD", /* ADC Analog and Output Driver Voltage */
62}; 62};
63 63
64static LIST_HEAD(reset_list);
65
64struct aic3x_priv; 66struct aic3x_priv;
65 67
66struct aic3x_disable_nb { 68struct aic3x_disable_nb {
@@ -77,6 +79,7 @@ struct aic3x_priv {
77 struct aic3x_setup_data *setup; 79 struct aic3x_setup_data *setup;
78 void *control_data; 80 void *control_data;
79 unsigned int sysclk; 81 unsigned int sysclk;
82 struct list_head list;
80 int master; 83 int master;
81 int gpio_reset; 84 int gpio_reset;
82 int power; 85 int power;
@@ -1344,11 +1347,25 @@ static int aic3x_init(struct snd_soc_codec *codec)
1344 return 0; 1347 return 0;
1345} 1348}
1346 1349
1350static bool aic3x_is_shared_reset(struct aic3x_priv *aic3x)
1351{
1352 struct aic3x_priv *a;
1353
1354 list_for_each_entry(a, &reset_list, list) {
1355 if (gpio_is_valid(aic3x->gpio_reset) &&
1356 aic3x->gpio_reset == a->gpio_reset)
1357 return true;
1358 }
1359
1360 return false;
1361}
1362
1347static int aic3x_probe(struct snd_soc_codec *codec) 1363static int aic3x_probe(struct snd_soc_codec *codec)
1348{ 1364{
1349 struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec); 1365 struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec);
1350 int ret, i; 1366 int ret, i;
1351 1367
1368 INIT_LIST_HEAD(&aic3x->list);
1352 codec->control_data = aic3x->control_data; 1369 codec->control_data = aic3x->control_data;
1353 aic3x->codec = codec; 1370 aic3x->codec = codec;
1354 codec->idle_bias_off = 1; 1371 codec->idle_bias_off = 1;
@@ -1359,7 +1376,8 @@ static int aic3x_probe(struct snd_soc_codec *codec)
1359 return ret; 1376 return ret;
1360 } 1377 }
1361 1378
1362 if (gpio_is_valid(aic3x->gpio_reset)) { 1379 if (gpio_is_valid(aic3x->gpio_reset) &&
1380 !aic3x_is_shared_reset(aic3x)) {
1363 ret = gpio_request(aic3x->gpio_reset, "tlv320aic3x reset"); 1381 ret = gpio_request(aic3x->gpio_reset, "tlv320aic3x reset");
1364 if (ret != 0) 1382 if (ret != 0)
1365 goto err_gpio; 1383 goto err_gpio;
@@ -1405,6 +1423,7 @@ static int aic3x_probe(struct snd_soc_codec *codec)
1405 snd_soc_add_controls(codec, &aic3x_classd_amp_gain_ctrl, 1); 1423 snd_soc_add_controls(codec, &aic3x_classd_amp_gain_ctrl, 1);
1406 1424
1407 aic3x_add_widgets(codec); 1425 aic3x_add_widgets(codec);
1426 list_add(&aic3x->list, &reset_list);
1408 1427
1409 return 0; 1428 return 0;
1410 1429
@@ -1414,7 +1433,8 @@ err_notif:
1414 &aic3x->disable_nb[i].nb); 1433 &aic3x->disable_nb[i].nb);
1415 regulator_bulk_free(ARRAY_SIZE(aic3x->supplies), aic3x->supplies); 1434 regulator_bulk_free(ARRAY_SIZE(aic3x->supplies), aic3x->supplies);
1416err_get: 1435err_get:
1417 if (gpio_is_valid(aic3x->gpio_reset)) 1436 if (gpio_is_valid(aic3x->gpio_reset) &&
1437 !aic3x_is_shared_reset(aic3x))
1418 gpio_free(aic3x->gpio_reset); 1438 gpio_free(aic3x->gpio_reset);
1419err_gpio: 1439err_gpio:
1420 kfree(aic3x); 1440 kfree(aic3x);
@@ -1427,7 +1447,9 @@ static int aic3x_remove(struct snd_soc_codec *codec)
1427 int i; 1447 int i;
1428 1448
1429 aic3x_set_bias_level(codec, SND_SOC_BIAS_OFF); 1449 aic3x_set_bias_level(codec, SND_SOC_BIAS_OFF);
1430 if (gpio_is_valid(aic3x->gpio_reset)) { 1450 list_del(&aic3x->list);
1451 if (gpio_is_valid(aic3x->gpio_reset) &&
1452 !aic3x_is_shared_reset(aic3x)) {
1431 gpio_set_value(aic3x->gpio_reset, 0); 1453 gpio_set_value(aic3x->gpio_reset, 0);
1432 gpio_free(aic3x->gpio_reset); 1454 gpio_free(aic3x->gpio_reset);
1433 } 1455 }