Skip to content

Commit

Permalink
ASoC: tlv320aic3x: Use regulator notifiers for optimizing the cache sync
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Jarkko Nikula authored and Liam Girdwood committed Sep 20, 2010
1 parent 6c1a7d4 commit 5a895f8
Showing 1 changed file with 61 additions and 2 deletions.
63 changes: 61 additions & 2 deletions sound/soc/codecs/tlv320aic3x.c
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,18 @@ static const char *aic3x_supply_names[AIC3X_NUM_SUPPLIES] = {
"DRVDD", /* ADC Analog and Output Driver Voltage */
};

struct aic3x_priv;

struct aic3x_disable_nb {
struct notifier_block nb;
struct aic3x_priv *aic3x;
};

/* codec private data */
struct aic3x_priv {
struct snd_soc_codec *codec;
struct regulator_bulk_data supplies[AIC3X_NUM_SUPPLIES];
struct aic3x_disable_nb disable_nb[AIC3X_NUM_SUPPLIES];
enum snd_soc_control_type control_type;
struct aic3x_setup_data *setup;
void *control_data;
Expand Down Expand Up @@ -122,6 +131,8 @@ static int aic3x_read(struct snd_soc_codec *codec, unsigned int reg,
{
u8 *cache = codec->reg_cache;

if (codec->cache_only)
return -EINVAL;
if (reg >= AIC3X_CACHEREGNUM)
return -1;

Expand Down Expand Up @@ -1052,6 +1063,26 @@ static int aic3x_init_3007(struct snd_soc_codec *codec)
return 0;
}

static int aic3x_regulator_event(struct notifier_block *nb,
unsigned long event, void *data)
{
struct aic3x_disable_nb *disable_nb =
container_of(nb, struct aic3x_disable_nb, nb);
struct aic3x_priv *aic3x = disable_nb->aic3x;

if (event & REGULATOR_EVENT_DISABLE) {
/*
* Put codec to reset and require cache sync as at least one
* of the supplies was disabled
*/
if (aic3x->gpio_reset >= 0)
gpio_set_value(aic3x->gpio_reset, 0);
aic3x->codec->cache_sync = 1;
}

return 0;
}

static int aic3x_set_power(struct snd_soc_codec *codec, int power)
{
struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec);
Expand All @@ -1064,6 +1095,13 @@ static int aic3x_set_power(struct snd_soc_codec *codec, int power)
if (ret)
goto out;
aic3x->power = 1;
/*
* Reset release and cache sync is necessary only if some
* supply was off or if there were cached writes
*/
if (!codec->cache_sync)
goto out;

if (aic3x->gpio_reset >= 0) {
udelay(1);
gpio_set_value(aic3x->gpio_reset, 1);
Expand All @@ -1078,8 +1116,8 @@ static int aic3x_set_power(struct snd_soc_codec *codec, int power)
codec->cache_sync = 0;
} else {
aic3x->power = 0;
if (aic3x->gpio_reset >= 0)
gpio_set_value(aic3x->gpio_reset, 0);
/* HW writes are needless when bias is off */
codec->cache_only = 1;
ret = regulator_bulk_disable(ARRAY_SIZE(aic3x->supplies),
aic3x->supplies);
}
Expand Down Expand Up @@ -1315,6 +1353,7 @@ static int aic3x_probe(struct snd_soc_codec *codec)
int ret, i;

codec->control_data = aic3x->control_data;
aic3x->codec = codec;

ret = snd_soc_codec_set_cache_io(codec, 8, 8, aic3x->control_type);
if (ret != 0) {
Expand All @@ -1338,6 +1377,18 @@ static int aic3x_probe(struct snd_soc_codec *codec)
dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
goto err_get;
}
for (i = 0; i < ARRAY_SIZE(aic3x->supplies); i++) {
aic3x->disable_nb[i].nb.notifier_call = aic3x_regulator_event;
aic3x->disable_nb[i].aic3x = aic3x;
ret = regulator_register_notifier(aic3x->supplies[i].consumer,
&aic3x->disable_nb[i].nb);
if (ret) {
dev_err(codec->dev,
"Failed to request regulator notifier: %d\n",
ret);
goto err_notif;
}
}

ret = regulator_bulk_enable(ARRAY_SIZE(aic3x->supplies),
aic3x->supplies);
Expand Down Expand Up @@ -1372,6 +1423,10 @@ static int aic3x_probe(struct snd_soc_codec *codec)
return 0;

err_enable:
err_notif:
while (i--)
regulator_unregister_notifier(aic3x->supplies[i].consumer,
&aic3x->disable_nb[i].nb);
regulator_bulk_free(ARRAY_SIZE(aic3x->supplies), aic3x->supplies);
err_get:
if (aic3x->gpio_reset >= 0)
Expand All @@ -1384,13 +1439,17 @@ static int aic3x_probe(struct snd_soc_codec *codec)
static int aic3x_remove(struct snd_soc_codec *codec)
{
struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec);
int i;

aic3x_set_bias_level(codec, SND_SOC_BIAS_OFF);
if (aic3x->gpio_reset >= 0) {
gpio_set_value(aic3x->gpio_reset, 0);
gpio_free(aic3x->gpio_reset);
}
regulator_bulk_disable(ARRAY_SIZE(aic3x->supplies), aic3x->supplies);
for (i = 0; i < ARRAY_SIZE(aic3x->supplies); i++)
regulator_unregister_notifier(aic3x->supplies[i].consumer,
&aic3x->disable_nb[i].nb);
regulator_bulk_free(ARRAY_SIZE(aic3x->supplies), aic3x->supplies);

return 0;
Expand Down

0 comments on commit 5a895f8

Please sign in to comment.