aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJarkko Nikula <jhnikula@gmail.com>2010-09-20 03:39:13 -0400
committerLiam Girdwood <lrg@slimlogic.co.uk>2010-09-20 13:40:47 -0400
commit5a895f8a09218716654fb89e0f876e4e3ca606a8 (patch)
treecef536f517a54d24a637c2734d24c8795be5eaf2
parent6c1a7d40c2237ff7690ca682336e22777c847ffe (diff)
ASoC: tlv320aic3x: Use regulator notifiers for optimizing the cache sync
There is no need to reset the codec and perform cache sync if none of the supply regulators were not disabled. Patch registers a notifier callback for each supply and callback then sets a flag to indicate when cache sync is required. HW writes are also needless when codec bias is off so cache_only flag is set independently of actual supply regulators state. 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>
-rw-r--r--sound/soc/codecs/tlv320aic3x.c63
1 files changed, 61 insertions, 2 deletions
diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c
index 5f8a7c4045c2..5356946fb6b2 100644
--- a/sound/soc/codecs/tlv320aic3x.c
+++ b/sound/soc/codecs/tlv320aic3x.c
@@ -61,9 +61,18 @@ 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
64struct aic3x_priv;
65
66struct aic3x_disable_nb {
67 struct notifier_block nb;
68 struct aic3x_priv *aic3x;
69};
70
64/* codec private data */ 71/* codec private data */
65struct aic3x_priv { 72struct aic3x_priv {
73 struct snd_soc_codec *codec;
66 struct regulator_bulk_data supplies[AIC3X_NUM_SUPPLIES]; 74 struct regulator_bulk_data supplies[AIC3X_NUM_SUPPLIES];
75 struct aic3x_disable_nb disable_nb[AIC3X_NUM_SUPPLIES];
67 enum snd_soc_control_type control_type; 76 enum snd_soc_control_type control_type;
68 struct aic3x_setup_data *setup; 77 struct aic3x_setup_data *setup;
69 void *control_data; 78 void *control_data;
@@ -122,6 +131,8 @@ static int aic3x_read(struct snd_soc_codec *codec, unsigned int reg,
122{ 131{
123 u8 *cache = codec->reg_cache; 132 u8 *cache = codec->reg_cache;
124 133
134 if (codec->cache_only)
135 return -EINVAL;
125 if (reg >= AIC3X_CACHEREGNUM) 136 if (reg >= AIC3X_CACHEREGNUM)
126 return -1; 137 return -1;
127 138
@@ -1052,6 +1063,26 @@ static int aic3x_init_3007(struct snd_soc_codec *codec)
1052 return 0; 1063 return 0;
1053} 1064}
1054 1065
1066static int aic3x_regulator_event(struct notifier_block *nb,
1067 unsigned long event, void *data)
1068{
1069 struct aic3x_disable_nb *disable_nb =
1070 container_of(nb, struct aic3x_disable_nb, nb);
1071 struct aic3x_priv *aic3x = disable_nb->aic3x;
1072
1073 if (event & REGULATOR_EVENT_DISABLE) {
1074 /*
1075 * Put codec to reset and require cache sync as at least one
1076 * of the supplies was disabled
1077 */
1078 if (aic3x->gpio_reset >= 0)
1079 gpio_set_value(aic3x->gpio_reset, 0);
1080 aic3x->codec->cache_sync = 1;
1081 }
1082
1083 return 0;
1084}
1085
1055static int aic3x_set_power(struct snd_soc_codec *codec, int power) 1086static int aic3x_set_power(struct snd_soc_codec *codec, int power)
1056{ 1087{
1057 struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec); 1088 struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec);
@@ -1064,6 +1095,13 @@ static int aic3x_set_power(struct snd_soc_codec *codec, int power)
1064 if (ret) 1095 if (ret)
1065 goto out; 1096 goto out;
1066 aic3x->power = 1; 1097 aic3x->power = 1;
1098 /*
1099 * Reset release and cache sync is necessary only if some
1100 * supply was off or if there were cached writes
1101 */
1102 if (!codec->cache_sync)
1103 goto out;
1104
1067 if (aic3x->gpio_reset >= 0) { 1105 if (aic3x->gpio_reset >= 0) {
1068 udelay(1); 1106 udelay(1);
1069 gpio_set_value(aic3x->gpio_reset, 1); 1107 gpio_set_value(aic3x->gpio_reset, 1);
@@ -1078,8 +1116,8 @@ static int aic3x_set_power(struct snd_soc_codec *codec, int power)
1078 codec->cache_sync = 0; 1116 codec->cache_sync = 0;
1079 } else { 1117 } else {
1080 aic3x->power = 0; 1118 aic3x->power = 0;
1081 if (aic3x->gpio_reset >= 0) 1119 /* HW writes are needless when bias is off */
1082 gpio_set_value(aic3x->gpio_reset, 0); 1120 codec->cache_only = 1;
1083 ret = regulator_bulk_disable(ARRAY_SIZE(aic3x->supplies), 1121 ret = regulator_bulk_disable(ARRAY_SIZE(aic3x->supplies),
1084 aic3x->supplies); 1122 aic3x->supplies);
1085 } 1123 }
@@ -1315,6 +1353,7 @@ static int aic3x_probe(struct snd_soc_codec *codec)
1315 int ret, i; 1353 int ret, i;
1316 1354
1317 codec->control_data = aic3x->control_data; 1355 codec->control_data = aic3x->control_data;
1356 aic3x->codec = codec;
1318 1357
1319 ret = snd_soc_codec_set_cache_io(codec, 8, 8, aic3x->control_type); 1358 ret = snd_soc_codec_set_cache_io(codec, 8, 8, aic3x->control_type);
1320 if (ret != 0) { 1359 if (ret != 0) {
@@ -1338,6 +1377,18 @@ static int aic3x_probe(struct snd_soc_codec *codec)
1338 dev_err(codec->dev, "Failed to request supplies: %d\n", ret); 1377 dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
1339 goto err_get; 1378 goto err_get;
1340 } 1379 }
1380 for (i = 0; i < ARRAY_SIZE(aic3x->supplies); i++) {
1381 aic3x->disable_nb[i].nb.notifier_call = aic3x_regulator_event;
1382 aic3x->disable_nb[i].aic3x = aic3x;
1383 ret = regulator_register_notifier(aic3x->supplies[i].consumer,
1384 &aic3x->disable_nb[i].nb);
1385 if (ret) {
1386 dev_err(codec->dev,
1387 "Failed to request regulator notifier: %d\n",
1388 ret);
1389 goto err_notif;
1390 }
1391 }
1341 1392
1342 ret = regulator_bulk_enable(ARRAY_SIZE(aic3x->supplies), 1393 ret = regulator_bulk_enable(ARRAY_SIZE(aic3x->supplies),
1343 aic3x->supplies); 1394 aic3x->supplies);
@@ -1372,6 +1423,10 @@ static int aic3x_probe(struct snd_soc_codec *codec)
1372 return 0; 1423 return 0;
1373 1424
1374err_enable: 1425err_enable:
1426err_notif:
1427 while (i--)
1428 regulator_unregister_notifier(aic3x->supplies[i].consumer,
1429 &aic3x->disable_nb[i].nb);
1375 regulator_bulk_free(ARRAY_SIZE(aic3x->supplies), aic3x->supplies); 1430 regulator_bulk_free(ARRAY_SIZE(aic3x->supplies), aic3x->supplies);
1376err_get: 1431err_get:
1377 if (aic3x->gpio_reset >= 0) 1432 if (aic3x->gpio_reset >= 0)
@@ -1384,6 +1439,7 @@ err_gpio:
1384static int aic3x_remove(struct snd_soc_codec *codec) 1439static int aic3x_remove(struct snd_soc_codec *codec)
1385{ 1440{
1386 struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec); 1441 struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec);
1442 int i;
1387 1443
1388 aic3x_set_bias_level(codec, SND_SOC_BIAS_OFF); 1444 aic3x_set_bias_level(codec, SND_SOC_BIAS_OFF);
1389 if (aic3x->gpio_reset >= 0) { 1445 if (aic3x->gpio_reset >= 0) {
@@ -1391,6 +1447,9 @@ static int aic3x_remove(struct snd_soc_codec *codec)
1391 gpio_free(aic3x->gpio_reset); 1447 gpio_free(aic3x->gpio_reset);
1392 } 1448 }
1393 regulator_bulk_disable(ARRAY_SIZE(aic3x->supplies), aic3x->supplies); 1449 regulator_bulk_disable(ARRAY_SIZE(aic3x->supplies), aic3x->supplies);
1450 for (i = 0; i < ARRAY_SIZE(aic3x->supplies); i++)
1451 regulator_unregister_notifier(aic3x->supplies[i].consumer,
1452 &aic3x->disable_nb[i].nb);
1394 regulator_bulk_free(ARRAY_SIZE(aic3x->supplies), aic3x->supplies); 1453 regulator_bulk_free(ARRAY_SIZE(aic3x->supplies), aic3x->supplies);
1395 1454
1396 return 0; 1455 return 0;