Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Hebbar Gururaja and committed by
Mark Brown
e2e8bfdf 88b62b91

+106 -15
+6
Documentation/devicetree/bindings/sound/tlv320aic3x.txt
··· 11 11 12 12 - gpio-reset - gpio pin number used for codec reset 13 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 15 21 Example: 16 22
+10
include/sound/tlv320aic3x.h
··· 46 46 AIC3X_GPIO2_FUNC_BUTTON_PRESS_IRQ = 15 47 47 }; 48 48 49 + enum 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 + 49 56 struct aic3x_setup_data { 50 57 unsigned int gpio_func[2]; 51 58 }; ··· 60 53 struct aic3x_pdata { 61 54 int gpio_reset; /* < 0 if not used */ 62 55 struct aic3x_setup_data *setup; 56 + 57 + /* Selects the micbias voltage */ 58 + enum aic3x_micbias_voltage micbias_vg; 63 59 }; 64 60 65 61 #endif
+77 -6
sound/soc/codecs/tlv320aic3x.c
··· 85 85 #define AIC3X_MODEL_33 1 86 86 #define AIC3X_MODEL_3007 2 87 87 u16 model; 88 + 89 + /* Selects the micbias voltage */ 90 + enum aic3x_micbias_voltage micbias_vg; 88 91 }; 89 92 90 93 /* ··· 196 193 197 194 mutex_unlock(&widget->codec->mutex); 198 195 return ret; 196 + } 197 + 198 + /* 199 + * mic bias power on/off share the same register bits with 200 + * output voltage of mic bias. when power on mic bias, we 201 + * need reclaim it to voltage value. 202 + * 0x0 = Powered off 203 + * 0x1 = MICBIAS output is powered to 2.0V, 204 + * 0x2 = MICBIAS output is powered to 2.5V 205 + * 0x3 = MICBIAS output is connected to AVDD 206 + */ 207 + static int mic_bias_event(struct snd_soc_dapm_widget *w, 208 + struct snd_kcontrol *kcontrol, int event) 209 + { 210 + struct snd_soc_codec *codec = w->codec; 211 + struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec); 212 + 213 + switch (event) { 214 + case SND_SOC_DAPM_POST_PMU: 215 + /* change mic bias voltage to user defined */ 216 + snd_soc_update_bits(codec, MICBIAS_CTRL, 217 + MICBIAS_LEVEL_MASK, 218 + aic3x->micbias_vg << MICBIAS_LEVEL_SHIFT); 219 + break; 220 + 221 + case SND_SOC_DAPM_PRE_PMD: 222 + snd_soc_update_bits(codec, MICBIAS_CTRL, 223 + MICBIAS_LEVEL_MASK, 0); 224 + break; 225 + } 226 + return 0; 199 227 } 200 228 201 229 static const char *aic3x_left_dac_mux[] = { "DAC_L1", "DAC_L3", "DAC_L2" }; ··· 630 596 AIC3X_ASD_INTF_CTRLA, 0, 3, 3, 0), 631 597 632 598 /* Mic Bias */ 633 - SND_SOC_DAPM_REG(snd_soc_dapm_micbias, "Mic Bias 2V", 634 - MICBIAS_CTRL, 6, 3, 1, 0), 635 - SND_SOC_DAPM_REG(snd_soc_dapm_micbias, "Mic Bias 2.5V", 636 - MICBIAS_CTRL, 6, 3, 2, 0), 637 - SND_SOC_DAPM_REG(snd_soc_dapm_micbias, "Mic Bias AVDD", 638 - MICBIAS_CTRL, 6, 3, 3, 0), 599 + SND_SOC_DAPM_SUPPLY("Mic Bias", MICBIAS_CTRL, 6, 0, 600 + mic_bias_event, 601 + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), 639 602 640 603 /* Output mixers */ 641 604 SND_SOC_DAPM_MIXER("Left Line Mixer", SND_SOC_NOPM, 0, 0, ··· 1417 1386 if (aic3x->model == AIC3X_MODEL_3007) 1418 1387 snd_soc_add_codec_controls(codec, &aic3x_classd_amp_gain_ctrl, 1); 1419 1388 1389 + /* set mic bias voltage */ 1390 + switch (aic3x->micbias_vg) { 1391 + case AIC3X_MICBIAS_2_0V: 1392 + case AIC3X_MICBIAS_2_5V: 1393 + case AIC3X_MICBIAS_AVDDV: 1394 + snd_soc_update_bits(codec, MICBIAS_CTRL, 1395 + MICBIAS_LEVEL_MASK, 1396 + (aic3x->micbias_vg) << MICBIAS_LEVEL_SHIFT); 1397 + break; 1398 + case AIC3X_MICBIAS_OFF: 1399 + /* 1400 + * noting to do. target won't enter here. This is just to avoid 1401 + * compile time warning "warning: enumeration value 1402 + * 'AIC3X_MICBIAS_OFF' not handled in switch" 1403 + */ 1404 + break; 1405 + } 1406 + 1420 1407 aic3x_add_widgets(codec); 1421 1408 list_add(&aic3x->list, &reset_list); 1422 1409 ··· 1510 1461 struct aic3x_setup_data *ai3x_setup; 1511 1462 struct device_node *np = i2c->dev.of_node; 1512 1463 int ret; 1464 + u32 value; 1513 1465 1514 1466 aic3x = devm_kzalloc(&i2c->dev, sizeof(struct aic3x_priv), GFP_KERNEL); 1515 1467 if (aic3x == NULL) { ··· 1524 1474 if (pdata) { 1525 1475 aic3x->gpio_reset = pdata->gpio_reset; 1526 1476 aic3x->setup = pdata->setup; 1477 + aic3x->micbias_vg = pdata->micbias_vg; 1527 1478 } else if (np) { 1528 1479 ai3x_setup = devm_kzalloc(&i2c->dev, sizeof(*ai3x_setup), 1529 1480 GFP_KERNEL); ··· 1542 1491 if (of_property_read_u32_array(np, "ai3x-gpio-func", 1543 1492 ai3x_setup->gpio_func, 2) >= 0) { 1544 1493 aic3x->setup = ai3x_setup; 1494 + } 1495 + 1496 + if (!of_property_read_u32(np, "ai3x-micbias-vg", &value)) { 1497 + switch (value) { 1498 + case 1 : 1499 + aic3x->micbias_vg = AIC3X_MICBIAS_2_0V; 1500 + break; 1501 + case 2 : 1502 + aic3x->micbias_vg = AIC3X_MICBIAS_2_5V; 1503 + break; 1504 + case 3 : 1505 + aic3x->micbias_vg = AIC3X_MICBIAS_AVDDV; 1506 + break; 1507 + default : 1508 + aic3x->micbias_vg = AIC3X_MICBIAS_OFF; 1509 + dev_err(&i2c->dev, "Unsuitable MicBias voltage " 1510 + "found in DT\n"); 1511 + } 1512 + } else { 1513 + aic3x->micbias_vg = AIC3X_MICBIAS_OFF; 1545 1514 } 1546 1515 1547 1516 } else {
+4
sound/soc/codecs/tlv320aic3x.h
··· 238 238 /* Default input volume */ 239 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 245 /* headset detection / button API */ 242 246 243 247 /* The AIC3x supports detection of stereo headsets (GND + left + right signal)
+3 -3
sound/soc/davinci/davinci-evm.c
··· 116 116 {"Line Out", NULL, "RLOUT"}, 117 117 118 118 /* Mic connected to (MIC3L | MIC3R) */ 119 - {"MIC3L", NULL, "Mic Bias 2V"}, 120 - {"MIC3R", NULL, "Mic Bias 2V"}, 121 - {"Mic Bias 2V", NULL, "Mic Jack"}, 119 + {"MIC3L", NULL, "Mic Bias"}, 120 + {"MIC3R", NULL, "Mic Bias"}, 121 + {"Mic Bias", NULL, "Mic Jack"}, 122 122 123 123 /* Line In connected to (LINE1L | LINE2L), (LINE1R | LINE2R) */ 124 124 {"LINE1L", NULL, "Line In"},
+2 -2
sound/soc/omap/n810.c
··· 230 230 {"Ext Spk", NULL, "LLOUT"}, 231 231 {"Ext Spk", NULL, "RLOUT"}, 232 232 233 - {"DMic Rate 64", NULL, "Mic Bias 2V"}, 234 - {"Mic Bias 2V", NULL, "DMic"}, 233 + {"DMic Rate 64", NULL, "Mic Bias"}, 234 + {"Mic Bias", NULL, "DMic"}, 235 235 }; 236 236 237 237 static const char *spk_function[] = {"Off", "On"};
+4 -4
sound/soc/omap/rx51.c
··· 248 248 {"FM Transmitter", NULL, "LLOUT"}, 249 249 {"FM Transmitter", NULL, "RLOUT"}, 250 250 251 - {"DMic Rate 64", NULL, "Mic Bias 2V"}, 252 - {"Mic Bias 2V", NULL, "DMic"}, 251 + {"DMic Rate 64", NULL, "Mic Bias"}, 252 + {"Mic Bias", NULL, "DMic"}, 253 253 }; 254 254 255 255 static const struct snd_soc_dapm_route audio_mapb[] = { 256 256 {"b LINE2R", NULL, "MONO_LOUT"}, 257 257 {"Earphone", NULL, "b HPLOUT"}, 258 258 259 - {"LINE1L", NULL, "b Mic Bias 2.5V"}, 260 - {"b Mic Bias 2.5V", NULL, "HS Mic"} 259 + {"LINE1L", NULL, "b Mic Bias"}, 260 + {"b Mic Bias", NULL, "HS Mic"} 261 261 }; 262 262 263 263 static const char *spk_function[] = {"Off", "On"};