Commit 414c73ab authored by Jarkko Nikula's avatar Jarkko Nikula Committed by Liam Girdwood

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: default avatarJarkko Nikula <jhnikula@gmail.com>
Acked-by: default avatarMark Brown <broonie@opensource.wolfsonmicro.com>
Signed-off-by: default avatarLiam Girdwood <lrg@slimlogic.co.uk>
parent 79ee820d
...@@ -61,6 +61,8 @@ static const char *aic3x_supply_names[AIC3X_NUM_SUPPLIES] = { ...@@ -61,6 +61,8 @@ static const char *aic3x_supply_names[AIC3X_NUM_SUPPLIES] = {
"DRVDD", /* ADC Analog and Output Driver Voltage */ "DRVDD", /* ADC Analog and Output Driver Voltage */
}; };
static LIST_HEAD(reset_list);
struct aic3x_priv; struct aic3x_priv;
struct aic3x_disable_nb { struct aic3x_disable_nb {
...@@ -77,6 +79,7 @@ struct aic3x_priv { ...@@ -77,6 +79,7 @@ struct aic3x_priv {
struct aic3x_setup_data *setup; struct aic3x_setup_data *setup;
void *control_data; void *control_data;
unsigned int sysclk; unsigned int sysclk;
struct list_head list;
int master; int master;
int gpio_reset; int gpio_reset;
int power; int power;
...@@ -1344,11 +1347,25 @@ static int aic3x_init(struct snd_soc_codec *codec) ...@@ -1344,11 +1347,25 @@ static int aic3x_init(struct snd_soc_codec *codec)
return 0; return 0;
} }
static bool aic3x_is_shared_reset(struct aic3x_priv *aic3x)
{
struct aic3x_priv *a;
list_for_each_entry(a, &reset_list, list) {
if (gpio_is_valid(aic3x->gpio_reset) &&
aic3x->gpio_reset == a->gpio_reset)
return true;
}
return false;
}
static int aic3x_probe(struct snd_soc_codec *codec) static int aic3x_probe(struct snd_soc_codec *codec)
{ {
struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec); struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec);
int ret, i; int ret, i;
INIT_LIST_HEAD(&aic3x->list);
codec->control_data = aic3x->control_data; codec->control_data = aic3x->control_data;
aic3x->codec = codec; aic3x->codec = codec;
codec->idle_bias_off = 1; codec->idle_bias_off = 1;
...@@ -1359,7 +1376,8 @@ static int aic3x_probe(struct snd_soc_codec *codec) ...@@ -1359,7 +1376,8 @@ static int aic3x_probe(struct snd_soc_codec *codec)
return ret; return ret;
} }
if (gpio_is_valid(aic3x->gpio_reset)) { if (gpio_is_valid(aic3x->gpio_reset) &&
!aic3x_is_shared_reset(aic3x)) {
ret = gpio_request(aic3x->gpio_reset, "tlv320aic3x reset"); ret = gpio_request(aic3x->gpio_reset, "tlv320aic3x reset");
if (ret != 0) if (ret != 0)
goto err_gpio; goto err_gpio;
...@@ -1405,6 +1423,7 @@ static int aic3x_probe(struct snd_soc_codec *codec) ...@@ -1405,6 +1423,7 @@ static int aic3x_probe(struct snd_soc_codec *codec)
snd_soc_add_controls(codec, &aic3x_classd_amp_gain_ctrl, 1); snd_soc_add_controls(codec, &aic3x_classd_amp_gain_ctrl, 1);
aic3x_add_widgets(codec); aic3x_add_widgets(codec);
list_add(&aic3x->list, &reset_list);
return 0; return 0;
...@@ -1414,7 +1433,8 @@ static int aic3x_probe(struct snd_soc_codec *codec) ...@@ -1414,7 +1433,8 @@ static int aic3x_probe(struct snd_soc_codec *codec)
&aic3x->disable_nb[i].nb); &aic3x->disable_nb[i].nb);
regulator_bulk_free(ARRAY_SIZE(aic3x->supplies), aic3x->supplies); regulator_bulk_free(ARRAY_SIZE(aic3x->supplies), aic3x->supplies);
err_get: err_get:
if (gpio_is_valid(aic3x->gpio_reset)) if (gpio_is_valid(aic3x->gpio_reset) &&
!aic3x_is_shared_reset(aic3x))
gpio_free(aic3x->gpio_reset); gpio_free(aic3x->gpio_reset);
err_gpio: err_gpio:
kfree(aic3x); kfree(aic3x);
...@@ -1427,7 +1447,9 @@ static int aic3x_remove(struct snd_soc_codec *codec) ...@@ -1427,7 +1447,9 @@ static int aic3x_remove(struct snd_soc_codec *codec)
int i; int i;
aic3x_set_bias_level(codec, SND_SOC_BIAS_OFF); aic3x_set_bias_level(codec, SND_SOC_BIAS_OFF);
if (gpio_is_valid(aic3x->gpio_reset)) { list_del(&aic3x->list);
if (gpio_is_valid(aic3x->gpio_reset) &&
!aic3x_is_shared_reset(aic3x)) {
gpio_set_value(aic3x->gpio_reset, 0); gpio_set_value(aic3x->gpio_reset, 0);
gpio_free(aic3x->gpio_reset); gpio_free(aic3x->gpio_reset);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment