ASoC: tlv320aic3x: Convert mic bias to a supply widget

Convert MicBias widgets to supply widget.

On tlv320aic3x, Mic bias power on/off shares the same register bits
with output mic bias voltage.  So, when power on mic bias, we need
reclaim it to voltage value.

Provide a new platform data so that the micbias voltage can be sent
according to board requirement. Now since tlv320aic3x codec driver
is DT aware, update dt files and functions to handle this new
"micbias-vg"  platform data.

Because of sharing of bits, when enabling the micbias, voltage also
needs to be updated. So use SND_SOC_DAPM_POST_PMU & SND_SOC_DAPM_PRE_PMD
macro to create an event to handle this.

Since micbias is converted to supply widget, updated machine drivers as
well.

This change is runtime tested on da850-evm with audio loopback
(arecord|aplay) for confirmation.

Signed-off-by: Hebbar Gururaja <gururaja.hebbar@ti.com>
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
This commit is contained in:
Hebbar Gururaja 2013-01-31 18:23:04 +05:30 коммит произвёл Mark Brown
Родитель 88b62b915b
Коммит e2e8bfdf61
7 изменённых файлов: 106 добавлений и 15 удалений

Просмотреть файл

@ -11,6 +11,12 @@ Optional properties:
- gpio-reset - gpio pin number used for codec reset - gpio-reset - gpio pin number used for codec reset
- ai3x-gpio-func - <array of 2 int> - AIC3X_GPIO1 & AIC3X_GPIO2 Functionality - ai3x-gpio-func - <array of 2 int> - AIC3X_GPIO1 & AIC3X_GPIO2 Functionality
- ai3x-micbias-vg - MicBias Voltage required.
1 - MICBIAS output is powered to 2.0V,
2 - MICBIAS output is powered to 2.5V,
3 - MICBIAS output is connected to AVDD,
If this node is not mentioned or if the value is incorrect, then MicBias
is powered down.
Example: Example:

Просмотреть файл

@ -46,6 +46,13 @@ enum {
AIC3X_GPIO2_FUNC_BUTTON_PRESS_IRQ = 15 AIC3X_GPIO2_FUNC_BUTTON_PRESS_IRQ = 15
}; };
enum aic3x_micbias_voltage {
AIC3X_MICBIAS_OFF = 0,
AIC3X_MICBIAS_2_0V = 1,
AIC3X_MICBIAS_2_5V = 2,
AIC3X_MICBIAS_AVDDV = 3,
};
struct aic3x_setup_data { struct aic3x_setup_data {
unsigned int gpio_func[2]; unsigned int gpio_func[2];
}; };
@ -53,6 +60,9 @@ struct aic3x_setup_data {
struct aic3x_pdata { struct aic3x_pdata {
int gpio_reset; /* < 0 if not used */ int gpio_reset; /* < 0 if not used */
struct aic3x_setup_data *setup; struct aic3x_setup_data *setup;
/* Selects the micbias voltage */
enum aic3x_micbias_voltage micbias_vg;
}; };
#endif #endif

Просмотреть файл

@ -85,6 +85,9 @@ struct aic3x_priv {
#define AIC3X_MODEL_33 1 #define AIC3X_MODEL_33 1
#define AIC3X_MODEL_3007 2 #define AIC3X_MODEL_3007 2
u16 model; u16 model;
/* Selects the micbias voltage */
enum aic3x_micbias_voltage micbias_vg;
}; };
/* /*
@ -195,6 +198,37 @@ static int snd_soc_dapm_put_volsw_aic3x(struct snd_kcontrol *kcontrol,
return ret; return ret;
} }
/*
* mic bias power on/off share the same register bits with
* output voltage of mic bias. when power on mic bias, we
* need reclaim it to voltage value.
* 0x0 = Powered off
* 0x1 = MICBIAS output is powered to 2.0V,
* 0x2 = MICBIAS output is powered to 2.5V
* 0x3 = MICBIAS output is connected to AVDD
*/
static int mic_bias_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_codec *codec = w->codec;
struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec);
switch (event) {
case SND_SOC_DAPM_POST_PMU:
/* change mic bias voltage to user defined */
snd_soc_update_bits(codec, MICBIAS_CTRL,
MICBIAS_LEVEL_MASK,
aic3x->micbias_vg << MICBIAS_LEVEL_SHIFT);
break;
case SND_SOC_DAPM_PRE_PMD:
snd_soc_update_bits(codec, MICBIAS_CTRL,
MICBIAS_LEVEL_MASK, 0);
break;
}
return 0;
}
static const char *aic3x_left_dac_mux[] = { "DAC_L1", "DAC_L3", "DAC_L2" }; static const char *aic3x_left_dac_mux[] = { "DAC_L1", "DAC_L3", "DAC_L2" };
static const char *aic3x_right_dac_mux[] = { "DAC_R1", "DAC_R3", "DAC_R2" }; static const char *aic3x_right_dac_mux[] = { "DAC_R1", "DAC_R3", "DAC_R2" };
static const char *aic3x_left_hpcom_mux[] = static const char *aic3x_left_hpcom_mux[] =
@ -596,12 +630,9 @@ static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = {
AIC3X_ASD_INTF_CTRLA, 0, 3, 3, 0), AIC3X_ASD_INTF_CTRLA, 0, 3, 3, 0),
/* Mic Bias */ /* Mic Bias */
SND_SOC_DAPM_REG(snd_soc_dapm_micbias, "Mic Bias 2V", SND_SOC_DAPM_SUPPLY("Mic Bias", MICBIAS_CTRL, 6, 0,
MICBIAS_CTRL, 6, 3, 1, 0), mic_bias_event,
SND_SOC_DAPM_REG(snd_soc_dapm_micbias, "Mic Bias 2.5V", SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
MICBIAS_CTRL, 6, 3, 2, 0),
SND_SOC_DAPM_REG(snd_soc_dapm_micbias, "Mic Bias AVDD",
MICBIAS_CTRL, 6, 3, 3, 0),
/* Output mixers */ /* Output mixers */
SND_SOC_DAPM_MIXER("Left Line Mixer", SND_SOC_NOPM, 0, 0, SND_SOC_DAPM_MIXER("Left Line Mixer", SND_SOC_NOPM, 0, 0,
@ -1386,6 +1417,24 @@ static int aic3x_probe(struct snd_soc_codec *codec)
if (aic3x->model == AIC3X_MODEL_3007) if (aic3x->model == AIC3X_MODEL_3007)
snd_soc_add_codec_controls(codec, &aic3x_classd_amp_gain_ctrl, 1); snd_soc_add_codec_controls(codec, &aic3x_classd_amp_gain_ctrl, 1);
/* set mic bias voltage */
switch (aic3x->micbias_vg) {
case AIC3X_MICBIAS_2_0V:
case AIC3X_MICBIAS_2_5V:
case AIC3X_MICBIAS_AVDDV:
snd_soc_update_bits(codec, MICBIAS_CTRL,
MICBIAS_LEVEL_MASK,
(aic3x->micbias_vg) << MICBIAS_LEVEL_SHIFT);
break;
case AIC3X_MICBIAS_OFF:
/*
* noting to do. target won't enter here. This is just to avoid
* compile time warning "warning: enumeration value
* 'AIC3X_MICBIAS_OFF' not handled in switch"
*/
break;
}
aic3x_add_widgets(codec); aic3x_add_widgets(codec);
list_add(&aic3x->list, &reset_list); list_add(&aic3x->list, &reset_list);
@ -1461,6 +1510,7 @@ static int aic3x_i2c_probe(struct i2c_client *i2c,
struct aic3x_setup_data *ai3x_setup; struct aic3x_setup_data *ai3x_setup;
struct device_node *np = i2c->dev.of_node; struct device_node *np = i2c->dev.of_node;
int ret; int ret;
u32 value;
aic3x = devm_kzalloc(&i2c->dev, sizeof(struct aic3x_priv), GFP_KERNEL); aic3x = devm_kzalloc(&i2c->dev, sizeof(struct aic3x_priv), GFP_KERNEL);
if (aic3x == NULL) { if (aic3x == NULL) {
@ -1474,6 +1524,7 @@ static int aic3x_i2c_probe(struct i2c_client *i2c,
if (pdata) { if (pdata) {
aic3x->gpio_reset = pdata->gpio_reset; aic3x->gpio_reset = pdata->gpio_reset;
aic3x->setup = pdata->setup; aic3x->setup = pdata->setup;
aic3x->micbias_vg = pdata->micbias_vg;
} else if (np) { } else if (np) {
ai3x_setup = devm_kzalloc(&i2c->dev, sizeof(*ai3x_setup), ai3x_setup = devm_kzalloc(&i2c->dev, sizeof(*ai3x_setup),
GFP_KERNEL); GFP_KERNEL);
@ -1493,6 +1544,26 @@ static int aic3x_i2c_probe(struct i2c_client *i2c,
aic3x->setup = ai3x_setup; aic3x->setup = ai3x_setup;
} }
if (!of_property_read_u32(np, "ai3x-micbias-vg", &value)) {
switch (value) {
case 1 :
aic3x->micbias_vg = AIC3X_MICBIAS_2_0V;
break;
case 2 :
aic3x->micbias_vg = AIC3X_MICBIAS_2_5V;
break;
case 3 :
aic3x->micbias_vg = AIC3X_MICBIAS_AVDDV;
break;
default :
aic3x->micbias_vg = AIC3X_MICBIAS_OFF;
dev_err(&i2c->dev, "Unsuitable MicBias voltage "
"found in DT\n");
}
} else {
aic3x->micbias_vg = AIC3X_MICBIAS_OFF;
}
} else { } else {
aic3x->gpio_reset = -1; aic3x->gpio_reset = -1;
} }

Просмотреть файл

@ -238,6 +238,10 @@
/* Default input volume */ /* Default input volume */
#define DEFAULT_GAIN 0x20 #define DEFAULT_GAIN 0x20
/* MICBIAS Control Register */
#define MICBIAS_LEVEL_SHIFT (6)
#define MICBIAS_LEVEL_MASK (3 << 6)
/* headset detection / button API */ /* headset detection / button API */
/* The AIC3x supports detection of stereo headsets (GND + left + right signal) /* The AIC3x supports detection of stereo headsets (GND + left + right signal)

Просмотреть файл

@ -116,9 +116,9 @@ static const struct snd_soc_dapm_route audio_map[] = {
{"Line Out", NULL, "RLOUT"}, {"Line Out", NULL, "RLOUT"},
/* Mic connected to (MIC3L | MIC3R) */ /* Mic connected to (MIC3L | MIC3R) */
{"MIC3L", NULL, "Mic Bias 2V"}, {"MIC3L", NULL, "Mic Bias"},
{"MIC3R", NULL, "Mic Bias 2V"}, {"MIC3R", NULL, "Mic Bias"},
{"Mic Bias 2V", NULL, "Mic Jack"}, {"Mic Bias", NULL, "Mic Jack"},
/* Line In connected to (LINE1L | LINE2L), (LINE1R | LINE2R) */ /* Line In connected to (LINE1L | LINE2L), (LINE1R | LINE2R) */
{"LINE1L", NULL, "Line In"}, {"LINE1L", NULL, "Line In"},

Просмотреть файл

@ -230,8 +230,8 @@ static const struct snd_soc_dapm_route audio_map[] = {
{"Ext Spk", NULL, "LLOUT"}, {"Ext Spk", NULL, "LLOUT"},
{"Ext Spk", NULL, "RLOUT"}, {"Ext Spk", NULL, "RLOUT"},
{"DMic Rate 64", NULL, "Mic Bias 2V"}, {"DMic Rate 64", NULL, "Mic Bias"},
{"Mic Bias 2V", NULL, "DMic"}, {"Mic Bias", NULL, "DMic"},
}; };
static const char *spk_function[] = {"Off", "On"}; static const char *spk_function[] = {"Off", "On"};

Просмотреть файл

@ -248,16 +248,16 @@ static const struct snd_soc_dapm_route audio_map[] = {
{"FM Transmitter", NULL, "LLOUT"}, {"FM Transmitter", NULL, "LLOUT"},
{"FM Transmitter", NULL, "RLOUT"}, {"FM Transmitter", NULL, "RLOUT"},
{"DMic Rate 64", NULL, "Mic Bias 2V"}, {"DMic Rate 64", NULL, "Mic Bias"},
{"Mic Bias 2V", NULL, "DMic"}, {"Mic Bias", NULL, "DMic"},
}; };
static const struct snd_soc_dapm_route audio_mapb[] = { static const struct snd_soc_dapm_route audio_mapb[] = {
{"b LINE2R", NULL, "MONO_LOUT"}, {"b LINE2R", NULL, "MONO_LOUT"},
{"Earphone", NULL, "b HPLOUT"}, {"Earphone", NULL, "b HPLOUT"},
{"LINE1L", NULL, "b Mic Bias 2.5V"}, {"LINE1L", NULL, "b Mic Bias"},
{"b Mic Bias 2.5V", NULL, "HS Mic"} {"b Mic Bias", NULL, "HS Mic"}
}; };
static const char *spk_function[] = {"Off", "On"}; static const char *spk_function[] = {"Off", "On"};