aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHebbar Gururaja <gururaja.hebbar@ti.com>2013-01-31 07:53:04 -0500
committerMark Brown <broonie@opensource.wolfsonmicro.com>2013-02-04 13:35:19 -0500
commite2e8bfdf61573c98162d1112b971d8d00f00fcf8 (patch)
tree3cfe1c7a55fa32bad47edd3b5541fcbb7380e876
parent88b62b915b0b7e25870eb0604ed9a92ba4bfc9f7 (diff)
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>
-rw-r--r--Documentation/devicetree/bindings/sound/tlv320aic3x.txt6
-rw-r--r--include/sound/tlv320aic3x.h10
-rw-r--r--sound/soc/codecs/tlv320aic3x.c83
-rw-r--r--sound/soc/codecs/tlv320aic3x.h4
-rw-r--r--sound/soc/davinci/davinci-evm.c6
-rw-r--r--sound/soc/omap/n810.c4
-rw-r--r--sound/soc/omap/rx51.c8
7 files changed, 106 insertions, 15 deletions
diff --git a/Documentation/devicetree/bindings/sound/tlv320aic3x.txt b/Documentation/devicetree/bindings/sound/tlv320aic3x.txt
index e7b98f41fa5f..f47c3f589fd0 100644
--- a/Documentation/devicetree/bindings/sound/tlv320aic3x.txt
+++ b/Documentation/devicetree/bindings/sound/tlv320aic3x.txt
@@ -11,6 +11,12 @@ Optional properties:
11 11
12- gpio-reset - gpio pin number used for codec reset 12- gpio-reset - gpio pin number used for codec reset
13- ai3x-gpio-func - <array of 2 int> - AIC3X_GPIO1 & AIC3X_GPIO2 Functionality 13- ai3x-gpio-func - <array of 2 int> - AIC3X_GPIO1 & AIC3X_GPIO2 Functionality
14- ai3x-micbias-vg - MicBias Voltage required.
15 1 - MICBIAS output is powered to 2.0V,
16 2 - MICBIAS output is powered to 2.5V,
17 3 - MICBIAS output is connected to AVDD,
18 If this node is not mentioned or if the value is incorrect, then MicBias
19 is powered down.
14 20
15Example: 21Example:
16 22
diff --git a/include/sound/tlv320aic3x.h b/include/sound/tlv320aic3x.h
index ffd9bc793105..9407fd00363b 100644
--- a/include/sound/tlv320aic3x.h
+++ b/include/sound/tlv320aic3x.h
@@ -46,6 +46,13 @@ enum {
46 AIC3X_GPIO2_FUNC_BUTTON_PRESS_IRQ = 15 46 AIC3X_GPIO2_FUNC_BUTTON_PRESS_IRQ = 15
47}; 47};
48 48
49enum aic3x_micbias_voltage {
50 AIC3X_MICBIAS_OFF = 0,
51 AIC3X_MICBIAS_2_0V = 1,
52 AIC3X_MICBIAS_2_5V = 2,
53 AIC3X_MICBIAS_AVDDV = 3,
54};
55
49struct aic3x_setup_data { 56struct aic3x_setup_data {
50 unsigned int gpio_func[2]; 57 unsigned int gpio_func[2];
51}; 58};
@@ -53,6 +60,9 @@ struct aic3x_setup_data {
53struct aic3x_pdata { 60struct aic3x_pdata {
54 int gpio_reset; /* < 0 if not used */ 61 int gpio_reset; /* < 0 if not used */
55 struct aic3x_setup_data *setup; 62 struct aic3x_setup_data *setup;
63
64 /* Selects the micbias voltage */
65 enum aic3x_micbias_voltage micbias_vg;
56}; 66};
57 67
58#endif 68#endif
diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c
index 5708a973a776..ba82ba2a7133 100644
--- a/sound/soc/codecs/tlv320aic3x.c
+++ b/sound/soc/codecs/tlv320aic3x.c
@@ -85,6 +85,9 @@ struct aic3x_priv {
85#define AIC3X_MODEL_33 1 85#define AIC3X_MODEL_33 1
86#define AIC3X_MODEL_3007 2 86#define AIC3X_MODEL_3007 2
87 u16 model; 87 u16 model;
88
89 /* Selects the micbias voltage */
90 enum aic3x_micbias_voltage micbias_vg;
88}; 91};
89 92
90/* 93/*
@@ -195,6 +198,37 @@ static int snd_soc_dapm_put_volsw_aic3x(struct snd_kcontrol *kcontrol,
195 return ret; 198 return ret;
196} 199}
197 200
201/*
202 * mic bias power on/off share the same register bits with
203 * output voltage of mic bias. when power on mic bias, we
204 * need reclaim it to voltage value.
205 * 0x0 = Powered off
206 * 0x1 = MICBIAS output is powered to 2.0V,
207 * 0x2 = MICBIAS output is powered to 2.5V
208 * 0x3 = MICBIAS output is connected to AVDD
209 */
210static int mic_bias_event(struct snd_soc_dapm_widget *w,
211 struct snd_kcontrol *kcontrol, int event)
212{
213 struct snd_soc_codec *codec = w->codec;
214 struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec);
215
216 switch (event) {
217 case SND_SOC_DAPM_POST_PMU:
218 /* change mic bias voltage to user defined */
219 snd_soc_update_bits(codec, MICBIAS_CTRL,
220 MICBIAS_LEVEL_MASK,
221 aic3x->micbias_vg << MICBIAS_LEVEL_SHIFT);
222 break;
223
224 case SND_SOC_DAPM_PRE_PMD:
225 snd_soc_update_bits(codec, MICBIAS_CTRL,
226 MICBIAS_LEVEL_MASK, 0);
227 break;
228 }
229 return 0;
230}
231
198static const char *aic3x_left_dac_mux[] = { "DAC_L1", "DAC_L3", "DAC_L2" }; 232static const char *aic3x_left_dac_mux[] = { "DAC_L1", "DAC_L3", "DAC_L2" };
199static const char *aic3x_right_dac_mux[] = { "DAC_R1", "DAC_R3", "DAC_R2" }; 233static const char *aic3x_right_dac_mux[] = { "DAC_R1", "DAC_R3", "DAC_R2" };
200static const char *aic3x_left_hpcom_mux[] = 234static const char *aic3x_left_hpcom_mux[] =
@@ -596,12 +630,9 @@ static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = {
596 AIC3X_ASD_INTF_CTRLA, 0, 3, 3, 0), 630 AIC3X_ASD_INTF_CTRLA, 0, 3, 3, 0),
597 631
598 /* Mic Bias */ 632 /* Mic Bias */
599 SND_SOC_DAPM_REG(snd_soc_dapm_micbias, "Mic Bias 2V", 633 SND_SOC_DAPM_SUPPLY("Mic Bias", MICBIAS_CTRL, 6, 0,
600 MICBIAS_CTRL, 6, 3, 1, 0), 634 mic_bias_event,
601 SND_SOC_DAPM_REG(snd_soc_dapm_micbias, "Mic Bias 2.5V", 635 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
602 MICBIAS_CTRL, 6, 3, 2, 0),
603 SND_SOC_DAPM_REG(snd_soc_dapm_micbias, "Mic Bias AVDD",
604 MICBIAS_CTRL, 6, 3, 3, 0),
605 636
606 /* Output mixers */ 637 /* Output mixers */
607 SND_SOC_DAPM_MIXER("Left Line Mixer", SND_SOC_NOPM, 0, 0, 638 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)
1386 if (aic3x->model == AIC3X_MODEL_3007) 1417 if (aic3x->model == AIC3X_MODEL_3007)
1387 snd_soc_add_codec_controls(codec, &aic3x_classd_amp_gain_ctrl, 1); 1418 snd_soc_add_codec_controls(codec, &aic3x_classd_amp_gain_ctrl, 1);
1388 1419
1420 /* set mic bias voltage */
1421 switch (aic3x->micbias_vg) {
1422 case AIC3X_MICBIAS_2_0V:
1423 case AIC3X_MICBIAS_2_5V:
1424 case AIC3X_MICBIAS_AVDDV:
1425 snd_soc_update_bits(codec, MICBIAS_CTRL,
1426 MICBIAS_LEVEL_MASK,
1427 (aic3x->micbias_vg) << MICBIAS_LEVEL_SHIFT);
1428 break;
1429 case AIC3X_MICBIAS_OFF:
1430 /*
1431 * noting to do. target won't enter here. This is just to avoid
1432 * compile time warning "warning: enumeration value
1433 * 'AIC3X_MICBIAS_OFF' not handled in switch"
1434 */
1435 break;
1436 }
1437
1389 aic3x_add_widgets(codec); 1438 aic3x_add_widgets(codec);
1390 list_add(&aic3x->list, &reset_list); 1439 list_add(&aic3x->list, &reset_list);
1391 1440
@@ -1461,6 +1510,7 @@ static int aic3x_i2c_probe(struct i2c_client *i2c,
1461 struct aic3x_setup_data *ai3x_setup; 1510 struct aic3x_setup_data *ai3x_setup;
1462 struct device_node *np = i2c->dev.of_node; 1511 struct device_node *np = i2c->dev.of_node;
1463 int ret; 1512 int ret;
1513 u32 value;
1464 1514
1465 aic3x = devm_kzalloc(&i2c->dev, sizeof(struct aic3x_priv), GFP_KERNEL); 1515 aic3x = devm_kzalloc(&i2c->dev, sizeof(struct aic3x_priv), GFP_KERNEL);
1466 if (aic3x == NULL) { 1516 if (aic3x == NULL) {
@@ -1474,6 +1524,7 @@ static int aic3x_i2c_probe(struct i2c_client *i2c,
1474 if (pdata) { 1524 if (pdata) {
1475 aic3x->gpio_reset = pdata->gpio_reset; 1525 aic3x->gpio_reset = pdata->gpio_reset;
1476 aic3x->setup = pdata->setup; 1526 aic3x->setup = pdata->setup;
1527 aic3x->micbias_vg = pdata->micbias_vg;
1477 } else if (np) { 1528 } else if (np) {
1478 ai3x_setup = devm_kzalloc(&i2c->dev, sizeof(*ai3x_setup), 1529 ai3x_setup = devm_kzalloc(&i2c->dev, sizeof(*ai3x_setup),
1479 GFP_KERNEL); 1530 GFP_KERNEL);
@@ -1493,6 +1544,26 @@ static int aic3x_i2c_probe(struct i2c_client *i2c,
1493 aic3x->setup = ai3x_setup; 1544 aic3x->setup = ai3x_setup;
1494 } 1545 }
1495 1546
1547 if (!of_property_read_u32(np, "ai3x-micbias-vg", &value)) {
1548 switch (value) {
1549 case 1 :
1550 aic3x->micbias_vg = AIC3X_MICBIAS_2_0V;
1551 break;
1552 case 2 :
1553 aic3x->micbias_vg = AIC3X_MICBIAS_2_5V;
1554 break;
1555 case 3 :
1556 aic3x->micbias_vg = AIC3X_MICBIAS_AVDDV;
1557 break;
1558 default :
1559 aic3x->micbias_vg = AIC3X_MICBIAS_OFF;
1560 dev_err(&i2c->dev, "Unsuitable MicBias voltage "
1561 "found in DT\n");
1562 }
1563 } else {
1564 aic3x->micbias_vg = AIC3X_MICBIAS_OFF;
1565 }
1566
1496 } else { 1567 } else {
1497 aic3x->gpio_reset = -1; 1568 aic3x->gpio_reset = -1;
1498 } 1569 }
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 @@
238/* Default input volume */ 238/* Default input volume */
239#define DEFAULT_GAIN 0x20 239#define DEFAULT_GAIN 0x20
240 240
241/* MICBIAS Control Register */
242#define MICBIAS_LEVEL_SHIFT (6)
243#define MICBIAS_LEVEL_MASK (3 << 6)
244
241/* headset detection / button API */ 245/* headset detection / button API */
242 246
243/* The AIC3x supports detection of stereo headsets (GND + left + right signal) 247/* The AIC3x supports detection of stereo headsets (GND + left + right signal)
diff --git a/sound/soc/davinci/davinci-evm.c b/sound/soc/davinci/davinci-evm.c
index d55e6477bff0..484b22c5df5d 100644
--- a/sound/soc/davinci/davinci-evm.c
+++ b/sound/soc/davinci/davinci-evm.c
@@ -116,9 +116,9 @@ static const struct snd_soc_dapm_route audio_map[] = {
116 {"Line Out", NULL, "RLOUT"}, 116 {"Line Out", NULL, "RLOUT"},
117 117
118 /* Mic connected to (MIC3L | MIC3R) */ 118 /* Mic connected to (MIC3L | MIC3R) */
119 {"MIC3L", NULL, "Mic Bias 2V"}, 119 {"MIC3L", NULL, "Mic Bias"},
120 {"MIC3R", NULL, "Mic Bias 2V"}, 120 {"MIC3R", NULL, "Mic Bias"},
121 {"Mic Bias 2V", NULL, "Mic Jack"}, 121 {"Mic Bias", NULL, "Mic Jack"},
122 122
123 /* Line In connected to (LINE1L | LINE2L), (LINE1R | LINE2R) */ 123 /* Line In connected to (LINE1L | LINE2L), (LINE1R | LINE2R) */
124 {"LINE1L", NULL, "Line In"}, 124 {"LINE1L", NULL, "Line In"},
diff --git a/sound/soc/omap/n810.c b/sound/soc/omap/n810.c
index 230b8c144848..ee7cd53aa3ee 100644
--- a/sound/soc/omap/n810.c
+++ b/sound/soc/omap/n810.c
@@ -230,8 +230,8 @@ static const struct snd_soc_dapm_route audio_map[] = {
230 {"Ext Spk", NULL, "LLOUT"}, 230 {"Ext Spk", NULL, "LLOUT"},
231 {"Ext Spk", NULL, "RLOUT"}, 231 {"Ext Spk", NULL, "RLOUT"},
232 232
233 {"DMic Rate 64", NULL, "Mic Bias 2V"}, 233 {"DMic Rate 64", NULL, "Mic Bias"},
234 {"Mic Bias 2V", NULL, "DMic"}, 234 {"Mic Bias", NULL, "DMic"},
235}; 235};
236 236
237static const char *spk_function[] = {"Off", "On"}; 237static const char *spk_function[] = {"Off", "On"};
diff --git a/sound/soc/omap/rx51.c b/sound/soc/omap/rx51.c
index d921ddbe3ecb..3cd525748975 100644
--- a/sound/soc/omap/rx51.c
+++ b/sound/soc/omap/rx51.c
@@ -248,16 +248,16 @@ static const struct snd_soc_dapm_route audio_map[] = {
248 {"FM Transmitter", NULL, "LLOUT"}, 248 {"FM Transmitter", NULL, "LLOUT"},
249 {"FM Transmitter", NULL, "RLOUT"}, 249 {"FM Transmitter", NULL, "RLOUT"},
250 250
251 {"DMic Rate 64", NULL, "Mic Bias 2V"}, 251 {"DMic Rate 64", NULL, "Mic Bias"},
252 {"Mic Bias 2V", NULL, "DMic"}, 252 {"Mic Bias", NULL, "DMic"},
253}; 253};
254 254
255static const struct snd_soc_dapm_route audio_mapb[] = { 255static const struct snd_soc_dapm_route audio_mapb[] = {
256 {"b LINE2R", NULL, "MONO_LOUT"}, 256 {"b LINE2R", NULL, "MONO_LOUT"},
257 {"Earphone", NULL, "b HPLOUT"}, 257 {"Earphone", NULL, "b HPLOUT"},
258 258
259 {"LINE1L", NULL, "b Mic Bias 2.5V"}, 259 {"LINE1L", NULL, "b Mic Bias"},
260 {"b Mic Bias 2.5V", NULL, "HS Mic"} 260 {"b Mic Bias", NULL, "HS Mic"}
261}; 261};
262 262
263static const char *spk_function[] = {"Off", "On"}; 263static const char *spk_function[] = {"Off", "On"};