summaryrefslogtreecommitdiff
path: root/sound/soc/codecs
diff options
context:
space:
mode:
authorMark Brown <broonie@opensource.wolfsonmicro.com>2013-02-11 11:06:46 +0000
committerMark Brown <broonie@opensource.wolfsonmicro.com>2013-02-11 11:06:46 +0000
commit315472d5abca4d4db90ba654fd616b9a694c80cf (patch)
tree27510f454328dd1fac3d3855ceac44edf1bc71d8 /sound/soc/codecs
parent56b3f31fb384124790279ad39eb02ee66df4b9fd (diff)
parente2e8bfdf61573c98162d1112b971d8d00f00fcf8 (diff)
Merge remote-tracking branch 'asoc/topic/tlv320aic3x' into asoc-next
Diffstat (limited to 'sound/soc/codecs')
-rw-r--r--sound/soc/codecs/tlv320aic3x.c83
-rw-r--r--sound/soc/codecs/tlv320aic3x.h4
2 files changed, 81 insertions, 6 deletions
diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c
index 49891432af74..65d09d60b7c6 100644
--- a/sound/soc/codecs/tlv320aic3x.c
+++ b/sound/soc/codecs/tlv320aic3x.c
@@ -85,6 +85,9 @@ struct aic3x_priv {
#define AIC3X_MODEL_33 1
#define AIC3X_MODEL_3007 2
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;
}
+/*
+ * 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_right_dac_mux[] = { "DAC_R1", "DAC_R3", "DAC_R2" };
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),
/* Mic Bias */
- SND_SOC_DAPM_REG(snd_soc_dapm_micbias, "Mic Bias 2V",
- MICBIAS_CTRL, 6, 3, 1, 0),
- SND_SOC_DAPM_REG(snd_soc_dapm_micbias, "Mic Bias 2.5V",
- MICBIAS_CTRL, 6, 3, 2, 0),
- SND_SOC_DAPM_REG(snd_soc_dapm_micbias, "Mic Bias AVDD",
- MICBIAS_CTRL, 6, 3, 3, 0),
+ SND_SOC_DAPM_SUPPLY("Mic Bias", MICBIAS_CTRL, 6, 0,
+ mic_bias_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
/* Output mixers */
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)
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);
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 device_node *np = i2c->dev.of_node;
int ret;
+ u32 value;
aic3x = devm_kzalloc(&i2c->dev, sizeof(struct aic3x_priv), GFP_KERNEL);
if (aic3x == NULL) {
@@ -1474,6 +1524,7 @@ static int aic3x_i2c_probe(struct i2c_client *i2c,
if (pdata) {
aic3x->gpio_reset = pdata->gpio_reset;
aic3x->setup = pdata->setup;
+ aic3x->micbias_vg = pdata->micbias_vg;
} else if (np) {
ai3x_setup = devm_kzalloc(&i2c->dev, sizeof(*ai3x_setup),
GFP_KERNEL);
@@ -1493,6 +1544,26 @@ static int aic3x_i2c_probe(struct i2c_client *i2c,
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 {
aic3x->gpio_reset = -1;
}
diff --git a/sound/soc/codecs/tlv320aic3x.h b/sound/soc/codecs/tlv320aic3x.h
index 6db3c41b0163..e521ac3ddde8 100644
--- a/sound/soc/codecs/tlv320aic3x.h
+++ b/sound/soc/codecs/tlv320aic3x.h
@@ -238,6 +238,10 @@
/* Default input volume */
#define DEFAULT_GAIN 0x20
+/* MICBIAS Control Register */
+#define MICBIAS_LEVEL_SHIFT (6)
+#define MICBIAS_LEVEL_MASK (3 << 6)
+
/* headset detection / button API */
/* The AIC3x supports detection of stereo headsets (GND + left + right signal)