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

Configure Feed

Select the types of activity you want to include in your feed.

ASoC: samsung: midas-audio: Add GPIO-based headset

Merge series from Artur Weber <aweber.kernel@gmail.com>:

Many of Samsung's Exynos 4 devices share the same midas-audio driver
to handle the codec setup. While most of these devices, including the
Midas itself, use the jack detection provided by the WM8994 driver,
other devices such as the Samsung Galaxy Tab 3 8.0 (lt01) use two GPIOs
and an ADC channel to determine jack insertion, the jack's type, and
button presses (for headsets with volume up/down/play buttons).

In the downstream kernel, this behavior is implemented in the sec-jack
driver[1], and the per-device settings are configured in *-jack.c files
in the mach folder (see e.g. the Tab 3's implementation[2]).

This patchset implements this mechanism in the midas_wm1811.c driver,
and adds new DTS options to allow for its configuration. It also
enables jack detection for the Samsung Galaxy Tab 3 8.0.

A very similar mechanism was already present in the aries_wm8994.c
driver[3]; this implementation heavily borrows from it, though there
are a few extra cleanups as well.

+317 -68
+33
Documentation/devicetree/bindings/sound/samsung,midas-audio.yaml
··· 53 53 submic-bias-supply: 54 54 description: Supply for the micbias on the Sub microphone 55 55 56 + headset-mic-bias-supply: 57 + description: Supply for the micbias on the Headset microphone 58 + 56 59 fm-sel-gpios: 57 60 maxItems: 1 58 61 description: GPIO pin for FM selection ··· 63 60 lineout-sel-gpios: 64 61 maxItems: 1 65 62 description: GPIO pin for line out selection 63 + 64 + headset-detect-gpios: 65 + maxItems: 1 66 + description: GPIO for detection of headset insertion 67 + 68 + headset-key-gpios: 69 + maxItems: 1 70 + description: GPIO for detection of headset key press 71 + 72 + io-channels: 73 + maxItems: 1 74 + description: IO channel to read micbias voltage for headset detection 75 + 76 + io-channel-names: 77 + const: headset-detect 78 + 79 + samsung,headset-4pole-threshold-microvolt: 80 + minItems: 2 81 + maxItems: 2 82 + description: 83 + Array containing minimum and maximum IO channel value for 4-pole 84 + (with microphone/button) headsets. If the IO channel value is 85 + outside of this range, a 3-pole headset is assumed. 86 + 87 + samsung,headset-button-threshold-microvolt: 88 + minItems: 3 89 + maxItems: 3 90 + description: | 91 + Array of minimum (inclusive) IO channel values for headset button 92 + detection, in order: "Media", "Volume Up" and "Volume Down". 66 93 67 94 required: 68 95 - compatible
+1 -1
sound/soc/samsung/Kconfig
··· 140 140 141 141 config SND_SOC_SAMSUNG_MIDAS_WM1811 142 142 tristate "SoC I2S Audio support for Midas boards" 143 - depends on SND_SOC_SAMSUNG 143 + depends on SND_SOC_SAMSUNG && IIO 144 144 select SND_SAMSUNG_I2S 145 145 select SND_SOC_WM8994 146 146 help
+283 -67
sound/soc/samsung/midas_wm1811.c
··· 7 7 8 8 #include <linux/clk.h> 9 9 #include <linux/gpio/consumer.h> 10 + #include <linux/iio/consumer.h> 10 11 #include <linux/mfd/wm8994/registers.h> 12 + #include <linux/input-event-codes.h> 11 13 #include <linux/module.h> 12 14 #include <linux/of.h> 13 - #include <linux/regulator/consumer.h> 14 15 #include <sound/jack.h> 15 16 #include <sound/soc.h> 16 17 #include <sound/soc-dapm.h> ··· 28 27 #define DEFAULT_FLL1_RATE 11289600U 29 28 30 29 struct midas_priv { 31 - struct regulator *reg_mic_bias; 32 - struct regulator *reg_submic_bias; 33 30 struct gpio_desc *gpio_fm_sel; 34 31 struct gpio_desc *gpio_lineout_sel; 32 + struct gpio_desc *gpio_headset_detect; 33 + struct gpio_desc *gpio_headset_key; 34 + struct iio_channel *adc_headset_detect; 35 35 unsigned int fll1_rate; 36 36 37 37 struct snd_soc_jack headset_jack; ··· 46 44 { 47 45 .pin = "Headset Mic", 48 46 .mask = SND_JACK_MICROPHONE, 47 + }, 48 + }; 49 + 50 + /* 51 + * min_mv/max_mv values in this struct are set up based on DT values. 52 + */ 53 + static struct snd_soc_jack_zone headset_jack_zones[] = { 54 + { .jack_type = SND_JACK_HEADPHONE, }, 55 + { .jack_type = SND_JACK_HEADSET, }, 56 + { .jack_type = SND_JACK_HEADPHONE, }, 57 + }; 58 + 59 + /* 60 + * This is used for manual detection in headset_key_check, we reuse the 61 + * structure since it's convenient. 62 + * 63 + * min_mv/max_mv values in this struct are set up based on DT values. 64 + */ 65 + static struct snd_soc_jack_zone headset_key_zones[] = { 66 + { .jack_type = SND_JACK_BTN_0, }, /* Media */ 67 + { .jack_type = SND_JACK_BTN_1, }, /* Volume Up */ 68 + { .jack_type = SND_JACK_BTN_2, }, /* Volume Down */ 69 + }; 70 + 71 + static int headset_jack_check(void *data) 72 + { 73 + struct snd_soc_component *codec = data; 74 + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(codec); 75 + struct midas_priv *priv = snd_soc_card_get_drvdata(codec->card); 76 + int adc, ret; 77 + int jack_type = 0; 78 + 79 + if (!gpiod_get_value_cansleep(priv->gpio_headset_detect)) 80 + return 0; 81 + 82 + /* Enable headset mic bias regulator so that the ADC reading works */ 83 + ret = snd_soc_dapm_force_enable_pin(dapm, "headset-mic-bias"); 84 + if (ret < 0) { 85 + pr_err("%s: Failed to enable headset mic bias regulator (%d), assuming headphones\n", 86 + __func__, ret); 87 + return SND_JACK_HEADPHONE; 88 + } 89 + snd_soc_dapm_sync(dapm); 90 + 91 + /* Sleep for a small amount of time to get the value to stabilize */ 92 + msleep(20); 93 + 94 + ret = iio_read_channel_processed(priv->adc_headset_detect, &adc); 95 + if (ret) { 96 + pr_err("%s: Failed to read ADC (%d), assuming headphones\n", 97 + __func__, ret); 98 + jack_type = SND_JACK_HEADPHONE; 99 + goto out; 100 + } 101 + pr_debug("%s: ADC value is %d\n", __func__, adc); 102 + 103 + jack_type = snd_soc_jack_get_type(&priv->headset_jack, adc); 104 + 105 + out: 106 + ret = snd_soc_dapm_disable_pin(dapm, "headset-mic-bias"); 107 + if (ret < 0) 108 + pr_err("%s: Failed to disable headset mic bias regulator (%d)\n", 109 + __func__, ret); 110 + snd_soc_dapm_sync(dapm); 111 + 112 + return jack_type; 113 + } 114 + 115 + static int headset_key_check(void *data) 116 + { 117 + struct snd_soc_component *codec = data; 118 + struct midas_priv *priv = snd_soc_card_get_drvdata(codec->card); 119 + int adc, i, ret; 120 + 121 + if (!gpiod_get_value_cansleep(priv->gpio_headset_key)) 122 + return 0; 123 + 124 + /* Filter out keypresses when 4 pole jack not detected */ 125 + if (!(priv->headset_jack.status & SND_JACK_MICROPHONE)) 126 + return 0; 127 + 128 + ret = iio_read_channel_processed(priv->adc_headset_detect, &adc); 129 + if (ret) { 130 + pr_err("%s: Failed to read ADC (%d), can't detect key type\n", 131 + __func__, ret); 132 + return 0; 133 + } 134 + pr_debug("%s: ADC value is %d\n", __func__, adc); 135 + 136 + for (i = 0; i < ARRAY_SIZE(headset_key_zones); i++) { 137 + if (adc >= headset_key_zones[i].min_mv && 138 + adc <= headset_key_zones[i].max_mv) { 139 + return headset_key_zones[i].jack_type; 140 + } 141 + } 142 + 143 + return 0; 144 + } 145 + 146 + static struct snd_soc_jack_gpio headset_gpio[] = { 147 + { 148 + .name = "Headset Jack", 149 + .report = SND_JACK_HEADSET, 150 + .debounce_time = 150, 151 + .jack_status_check = headset_jack_check, 152 + }, 153 + { 154 + .name = "Headset Key", 155 + .report = SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2, 156 + .debounce_time = 30, 157 + .jack_status_check = headset_key_check, 49 158 }, 50 159 }; 51 160 ··· 282 169 return ret; 283 170 } 284 171 285 - static int midas_mic_bias(struct snd_soc_dapm_widget *w, 286 - struct snd_kcontrol *kcontrol, int event) 287 - { 288 - struct snd_soc_card *card = w->dapm->card; 289 - struct midas_priv *priv = snd_soc_card_get_drvdata(card); 290 - 291 - switch (event) { 292 - case SND_SOC_DAPM_PRE_PMU: 293 - return regulator_enable(priv->reg_mic_bias); 294 - case SND_SOC_DAPM_POST_PMD: 295 - return regulator_disable(priv->reg_mic_bias); 296 - } 297 - 298 - return 0; 299 - } 300 - 301 - static int midas_submic_bias(struct snd_soc_dapm_widget *w, 302 - struct snd_kcontrol *kcontrol, int event) 303 - { 304 - struct snd_soc_card *card = w->dapm->card; 305 - struct midas_priv *priv = snd_soc_card_get_drvdata(card); 306 - 307 - switch (event) { 308 - case SND_SOC_DAPM_PRE_PMU: 309 - return regulator_enable(priv->reg_submic_bias); 310 - case SND_SOC_DAPM_POST_PMD: 311 - return regulator_disable(priv->reg_submic_bias); 312 - } 313 - 314 - return 0; 315 - } 316 - 317 172 static int midas_fm_set(struct snd_soc_dapm_widget *w, 318 173 struct snd_kcontrol *kcontrol, int event) 319 174 { ··· 353 272 354 273 SND_SOC_DAPM_HP("Headphone", NULL), 355 274 SND_SOC_DAPM_MIC("Headset Mic", NULL), 356 - SND_SOC_DAPM_MIC("Main Mic", midas_mic_bias), 357 - SND_SOC_DAPM_MIC("Sub Mic", midas_submic_bias), 275 + SND_SOC_DAPM_REGULATOR_SUPPLY("headset-mic-bias", 0, 0), 276 + SND_SOC_DAPM_MIC("Main Mic", NULL), 277 + SND_SOC_DAPM_REGULATOR_SUPPLY("mic-bias", 0, 0), 278 + SND_SOC_DAPM_MIC("Sub Mic", NULL), 279 + SND_SOC_DAPM_REGULATOR_SUPPLY("submic-bias", 0, 0), 280 + }; 281 + 282 + /* Default routing; supplemented by audio-routing DT property */ 283 + static const struct snd_soc_dapm_route midas_dapm_routes[] = { 284 + /* Bind microphones with their respective regulator supplies */ 285 + {"Main Mic", NULL, "mic-bias"}, 286 + {"Sub Mic", NULL, "submic-bias"}, 287 + {"Headset Mic", NULL, "headset-mic-bias"}, 358 288 }; 359 289 360 290 static int midas_set_bias_level(struct snd_soc_card *card, ··· 407 315 return ret; 408 316 } 409 317 410 - ret = snd_soc_card_jack_new_pins(card, "Headset", 411 - SND_JACK_HEADSET | SND_JACK_MECHANICAL | 412 - SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2 | 413 - SND_JACK_BTN_3 | SND_JACK_BTN_4 | SND_JACK_BTN_5, 414 - &priv->headset_jack, 415 - headset_jack_pins, 416 - ARRAY_SIZE(headset_jack_pins)); 417 - if (ret) 418 - return ret; 318 + if (!priv->gpio_headset_detect) { 319 + ret = snd_soc_card_jack_new_pins(card, "Headset", 320 + SND_JACK_HEADSET | SND_JACK_MECHANICAL | 321 + SND_JACK_BTN_0 | SND_JACK_BTN_1 | 322 + SND_JACK_BTN_2 | SND_JACK_BTN_3 | 323 + SND_JACK_BTN_4 | SND_JACK_BTN_5, 324 + &priv->headset_jack, 325 + headset_jack_pins, 326 + ARRAY_SIZE(headset_jack_pins)); 327 + if (ret) 328 + return ret; 419 329 420 - wm8958_mic_detect(aif1_dai->component, &priv->headset_jack, 421 - NULL, NULL, NULL, NULL); 330 + wm8958_mic_detect(aif1_dai->component, &priv->headset_jack, 331 + NULL, NULL, NULL, NULL); 332 + } else { 333 + /* Some devices (n8000, t310) use a GPIO to detect the jack. */ 334 + ret = snd_soc_card_jack_new_pins(card, "Headset", 335 + SND_JACK_HEADSET | SND_JACK_BTN_0 | 336 + SND_JACK_BTN_1 | SND_JACK_BTN_2, 337 + &priv->headset_jack, 338 + headset_jack_pins, 339 + ARRAY_SIZE(headset_jack_pins)); 340 + if (ret) { 341 + dev_err(card->dev, 342 + "Failed to set up headset pins: %d\n", ret); 343 + return ret; 344 + } 345 + 346 + ret = snd_soc_jack_add_zones(&priv->headset_jack, 347 + ARRAY_SIZE(headset_jack_zones), 348 + headset_jack_zones); 349 + if (ret) { 350 + dev_err(card->dev, 351 + "Failed to set up headset zones: %d\n", ret); 352 + return ret; 353 + } 354 + 355 + headset_gpio[0].data = aif1_dai->component; 356 + headset_gpio[0].desc = priv->gpio_headset_detect; 357 + 358 + headset_gpio[1].data = aif1_dai->component; 359 + headset_gpio[1].desc = priv->gpio_headset_key; 360 + 361 + snd_jack_set_key(priv->headset_jack.jack, 362 + SND_JACK_BTN_0, KEY_MEDIA); 363 + snd_jack_set_key(priv->headset_jack.jack, 364 + SND_JACK_BTN_1, KEY_VOLUMEUP); 365 + snd_jack_set_key(priv->headset_jack.jack, 366 + SND_JACK_BTN_2, KEY_VOLUMEDOWN); 367 + 368 + ret = snd_soc_jack_add_gpios(&priv->headset_jack, 369 + ARRAY_SIZE(headset_gpio), 370 + headset_gpio); 371 + if (ret) 372 + dev_err(card->dev, 373 + "Failed to set up headset jack GPIOs: %d\n", 374 + ret); 375 + 376 + return ret; 377 + } 378 + 422 379 return 0; 423 380 } 424 381 ··· 562 421 .num_controls = ARRAY_SIZE(midas_controls), 563 422 .dapm_widgets = midas_dapm_widgets, 564 423 .num_dapm_widgets = ARRAY_SIZE(midas_dapm_widgets), 424 + .dapm_routes = midas_dapm_routes, 425 + .num_dapm_routes = ARRAY_SIZE(midas_dapm_routes), 565 426 566 427 .set_bias_level = midas_set_bias_level, 567 428 .late_probe = midas_late_probe, ··· 576 433 struct snd_soc_card *card = &midas_card; 577 434 struct device *dev = &pdev->dev; 578 435 static struct snd_soc_dai_link *dai_link; 436 + enum iio_chan_type channel_type; 437 + u32 fourpole_threshold[2]; 438 + u32 button_threshold[3]; 579 439 struct midas_priv *priv; 580 440 int ret, i; 581 441 ··· 589 443 snd_soc_card_set_drvdata(card, priv); 590 444 card->dev = dev; 591 445 592 - priv->reg_mic_bias = devm_regulator_get(dev, "mic-bias"); 593 - if (IS_ERR(priv->reg_mic_bias)) { 594 - dev_err(dev, "Failed to get mic bias regulator\n"); 595 - return PTR_ERR(priv->reg_mic_bias); 596 - } 597 - 598 - priv->reg_submic_bias = devm_regulator_get(dev, "submic-bias"); 599 - if (IS_ERR(priv->reg_submic_bias)) { 600 - dev_err(dev, "Failed to get submic bias regulator\n"); 601 - return PTR_ERR(priv->reg_submic_bias); 602 - } 603 - 604 446 priv->gpio_fm_sel = devm_gpiod_get_optional(dev, "fm-sel", GPIOD_OUT_HIGH); 605 - if (IS_ERR(priv->gpio_fm_sel)) { 606 - dev_err(dev, "Failed to get FM selection GPIO\n"); 607 - return PTR_ERR(priv->gpio_fm_sel); 608 - } 447 + if (IS_ERR(priv->gpio_fm_sel)) 448 + return dev_err_probe(dev, PTR_ERR(priv->gpio_fm_sel), 449 + "Failed to get FM selection GPIO\n"); 609 450 610 451 priv->gpio_lineout_sel = devm_gpiod_get_optional(dev, "lineout-sel", 611 452 GPIOD_OUT_HIGH); 612 - if (IS_ERR(priv->gpio_lineout_sel)) { 613 - dev_err(dev, "Failed to get line out selection GPIO\n"); 614 - return PTR_ERR(priv->gpio_lineout_sel); 453 + if (IS_ERR(priv->gpio_lineout_sel)) 454 + return dev_err_probe(dev, PTR_ERR(priv->gpio_lineout_sel), 455 + "Failed to get line out selection GPIO\n"); 456 + 457 + priv->gpio_headset_detect = devm_gpiod_get_optional(dev, 458 + "headset-detect", GPIOD_IN); 459 + if (IS_ERR(priv->gpio_headset_detect)) 460 + return dev_err_probe(dev, PTR_ERR(priv->gpio_headset_detect), 461 + "Failed to get headset jack detect GPIO\n"); 462 + 463 + if (priv->gpio_headset_detect) { 464 + priv->adc_headset_detect = devm_iio_channel_get(dev, 465 + "headset-detect"); 466 + if (IS_ERR(priv->adc_headset_detect)) 467 + return dev_err_probe(dev, 468 + PTR_ERR(priv->adc_headset_detect), 469 + "Failed to get ADC channel\n"); 470 + 471 + ret = iio_get_channel_type(priv->adc_headset_detect, 472 + &channel_type); 473 + if (ret) { 474 + dev_err(dev, "Failed to get ADC channel type\n"); 475 + return ret; 476 + } 477 + 478 + if (channel_type != IIO_VOLTAGE) { 479 + dev_err(dev, "ADC channel is not voltage\n"); 480 + return ret; 481 + } 482 + 483 + priv->gpio_headset_key = devm_gpiod_get(dev, "headset-key", 484 + GPIOD_IN); 485 + if (IS_ERR(priv->gpio_headset_key)) 486 + return dev_err_probe(dev, 487 + PTR_ERR(priv->gpio_headset_key), 488 + "Failed to get headset key GPIO\n"); 489 + 490 + ret = of_property_read_u32_array(dev->of_node, 491 + "samsung,headset-4pole-threshold-microvolt", 492 + fourpole_threshold, 493 + ARRAY_SIZE(fourpole_threshold)); 494 + if (ret) { 495 + dev_err(dev, "Failed to get 4-pole jack detection threshold\n"); 496 + return ret; 497 + } 498 + 499 + if (fourpole_threshold[0] > fourpole_threshold[1]) { 500 + dev_err(dev, "Invalid 4-pole jack detection threshold value\n"); 501 + return -EINVAL; 502 + } 503 + 504 + headset_jack_zones[0].max_mv = (fourpole_threshold[0]); 505 + headset_jack_zones[1].min_mv = (fourpole_threshold[0] + 1); 506 + 507 + headset_jack_zones[1].max_mv = (fourpole_threshold[1]); 508 + headset_jack_zones[2].min_mv = (fourpole_threshold[1] + 1); 509 + 510 + ret = of_property_read_u32_array(dev->of_node, 511 + "samsung,headset-button-threshold-microvolt", 512 + button_threshold, 513 + ARRAY_SIZE(button_threshold)); 514 + if (ret) { 515 + dev_err(dev, "Failed to get headset button detection threshold\n"); 516 + return ret; 517 + } 518 + 519 + if (button_threshold[0] > button_threshold[1] || 520 + button_threshold[1] > button_threshold[2]) { 521 + dev_err(dev, "Invalid headset button detection threshold value\n"); 522 + return -EINVAL; 523 + } 524 + 525 + for (i = 0; i < 3; i++) { 526 + if (i != 0 && button_threshold[i] <= 0) { 527 + dev_err(dev, "Invalid headset button detection threshold value\n"); 528 + return -EINVAL; 529 + } 530 + 531 + headset_key_zones[i].min_mv = button_threshold[i]; 532 + 533 + if (i == 2) 534 + headset_key_zones[i].max_mv = UINT_MAX; 535 + else 536 + headset_key_zones[i].max_mv = \ 537 + (button_threshold[i+1] - 1); 538 + } 615 539 } 616 540 617 541 ret = snd_soc_of_parse_card_name(card, "model");