| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * extcon-arizona.c - Extcon driver Wolfson Arizona devices |
|---|
| 3 | 4 | * |
|---|
| 4 | 5 | * Copyright (C) 2012-2014 Wolfson Microelectronics plc |
|---|
| 5 | | - * |
|---|
| 6 | | - * This program is free software; you can redistribute it and/or modify |
|---|
| 7 | | - * it under the terms of the GNU General Public License as published by |
|---|
| 8 | | - * the Free Software Foundation; either version 2 of the License, or |
|---|
| 9 | | - * (at your option) any later version. |
|---|
| 10 | | - * |
|---|
| 11 | | - * This program is distributed in the hope that it will be useful, |
|---|
| 12 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 13 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 14 | | - * GNU General Public License for more details. |
|---|
| 15 | 6 | */ |
|---|
| 16 | 7 | |
|---|
| 17 | 8 | #include <linux/kernel.h> |
|---|
| .. | .. |
|---|
| 85 | 76 | |
|---|
| 86 | 77 | const struct arizona_micd_range *micd_ranges; |
|---|
| 87 | 78 | int num_micd_ranges; |
|---|
| 88 | | - |
|---|
| 89 | | - int micd_timeout; |
|---|
| 90 | 79 | |
|---|
| 91 | 80 | bool micd_reva; |
|---|
| 92 | 81 | bool micd_clamp; |
|---|
| .. | .. |
|---|
| 319 | 308 | } |
|---|
| 320 | 309 | |
|---|
| 321 | 310 | if (info->micd_reva) { |
|---|
| 322 | | - regmap_write(arizona->regmap, 0x80, 0x3); |
|---|
| 323 | | - regmap_write(arizona->regmap, 0x294, 0); |
|---|
| 324 | | - regmap_write(arizona->regmap, 0x80, 0x0); |
|---|
| 311 | + const struct reg_sequence reva[] = { |
|---|
| 312 | + { 0x80, 0x3 }, |
|---|
| 313 | + { 0x294, 0x0 }, |
|---|
| 314 | + { 0x80, 0x0 }, |
|---|
| 315 | + }; |
|---|
| 316 | + |
|---|
| 317 | + regmap_multi_reg_write(arizona->regmap, reva, ARRAY_SIZE(reva)); |
|---|
| 325 | 318 | } |
|---|
| 326 | 319 | |
|---|
| 327 | 320 | if (info->detecting && arizona->pdata.micd_software_compare) |
|---|
| .. | .. |
|---|
| 335 | 328 | |
|---|
| 336 | 329 | arizona_extcon_pulse_micbias(info); |
|---|
| 337 | 330 | |
|---|
| 338 | | - regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1, |
|---|
| 339 | | - ARIZONA_MICD_ENA, ARIZONA_MICD_ENA, |
|---|
| 340 | | - &change); |
|---|
| 341 | | - if (!change) { |
|---|
| 331 | + ret = regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1, |
|---|
| 332 | + ARIZONA_MICD_ENA, ARIZONA_MICD_ENA, |
|---|
| 333 | + &change); |
|---|
| 334 | + if (ret < 0) { |
|---|
| 335 | + dev_err(arizona->dev, "Failed to enable micd: %d\n", ret); |
|---|
| 336 | + } else if (!change) { |
|---|
| 342 | 337 | regulator_disable(info->micvdd); |
|---|
| 343 | 338 | pm_runtime_put_autosuspend(info->dev); |
|---|
| 344 | 339 | } |
|---|
| .. | .. |
|---|
| 350 | 345 | const char *widget = arizona_extcon_get_micbias(info); |
|---|
| 351 | 346 | struct snd_soc_dapm_context *dapm = arizona->dapm; |
|---|
| 352 | 347 | struct snd_soc_component *component = snd_soc_dapm_to_component(dapm); |
|---|
| 353 | | - bool change; |
|---|
| 348 | + bool change = false; |
|---|
| 354 | 349 | int ret; |
|---|
| 355 | 350 | |
|---|
| 356 | | - regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1, |
|---|
| 357 | | - ARIZONA_MICD_ENA, 0, |
|---|
| 358 | | - &change); |
|---|
| 351 | + ret = regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1, |
|---|
| 352 | + ARIZONA_MICD_ENA, 0, |
|---|
| 353 | + &change); |
|---|
| 354 | + if (ret < 0) |
|---|
| 355 | + dev_err(arizona->dev, "Failed to disable micd: %d\n", ret); |
|---|
| 359 | 356 | |
|---|
| 360 | 357 | ret = snd_soc_component_disable_pin(component, widget); |
|---|
| 361 | 358 | if (ret != 0) |
|---|
| .. | .. |
|---|
| 366 | 363 | snd_soc_dapm_sync(dapm); |
|---|
| 367 | 364 | |
|---|
| 368 | 365 | if (info->micd_reva) { |
|---|
| 369 | | - regmap_write(arizona->regmap, 0x80, 0x3); |
|---|
| 370 | | - regmap_write(arizona->regmap, 0x294, 2); |
|---|
| 371 | | - regmap_write(arizona->regmap, 0x80, 0x0); |
|---|
| 366 | + const struct reg_sequence reva[] = { |
|---|
| 367 | + { 0x80, 0x3 }, |
|---|
| 368 | + { 0x294, 0x2 }, |
|---|
| 369 | + { 0x80, 0x0 }, |
|---|
| 370 | + }; |
|---|
| 371 | + |
|---|
| 372 | + regmap_multi_reg_write(arizona->regmap, reva, ARRAY_SIZE(reva)); |
|---|
| 372 | 373 | } |
|---|
| 373 | 374 | |
|---|
| 374 | 375 | ret = regulator_allow_bypass(info->micvdd, true); |
|---|
| .. | .. |
|---|
| 532 | 533 | struct arizona *arizona = info->arizona; |
|---|
| 533 | 534 | int id_gpio = arizona->pdata.hpdet_id_gpio; |
|---|
| 534 | 535 | |
|---|
| 536 | + if (!arizona->pdata.hpdet_acc_id) |
|---|
| 537 | + return 0; |
|---|
| 538 | + |
|---|
| 535 | 539 | /* |
|---|
| 536 | 540 | * If we're using HPDET for accessory identification we need |
|---|
| 537 | 541 | * to take multiple measurements, step through them in sequence. |
|---|
| 538 | 542 | */ |
|---|
| 539 | | - if (arizona->pdata.hpdet_acc_id) { |
|---|
| 540 | | - info->hpdet_res[info->num_hpdet_res++] = *reading; |
|---|
| 543 | + info->hpdet_res[info->num_hpdet_res++] = *reading; |
|---|
| 541 | 544 | |
|---|
| 542 | | - /* Only check the mic directly if we didn't already ID it */ |
|---|
| 543 | | - if (id_gpio && info->num_hpdet_res == 1) { |
|---|
| 544 | | - dev_dbg(arizona->dev, "Measuring mic\n"); |
|---|
| 545 | + /* Only check the mic directly if we didn't already ID it */ |
|---|
| 546 | + if (id_gpio && info->num_hpdet_res == 1) { |
|---|
| 547 | + dev_dbg(arizona->dev, "Measuring mic\n"); |
|---|
| 545 | 548 | |
|---|
| 546 | | - regmap_update_bits(arizona->regmap, |
|---|
| 547 | | - ARIZONA_ACCESSORY_DETECT_MODE_1, |
|---|
| 548 | | - ARIZONA_ACCDET_MODE_MASK | |
|---|
| 549 | | - ARIZONA_ACCDET_SRC, |
|---|
| 550 | | - ARIZONA_ACCDET_MODE_HPR | |
|---|
| 551 | | - info->micd_modes[0].src); |
|---|
| 552 | | - |
|---|
| 553 | | - gpio_set_value_cansleep(id_gpio, 1); |
|---|
| 554 | | - |
|---|
| 555 | | - regmap_update_bits(arizona->regmap, |
|---|
| 556 | | - ARIZONA_HEADPHONE_DETECT_1, |
|---|
| 557 | | - ARIZONA_HP_POLL, ARIZONA_HP_POLL); |
|---|
| 558 | | - return -EAGAIN; |
|---|
| 559 | | - } |
|---|
| 560 | | - |
|---|
| 561 | | - /* OK, got both. Now, compare... */ |
|---|
| 562 | | - dev_dbg(arizona->dev, "HPDET measured %d %d\n", |
|---|
| 563 | | - info->hpdet_res[0], info->hpdet_res[1]); |
|---|
| 564 | | - |
|---|
| 565 | | - /* Take the headphone impedance for the main report */ |
|---|
| 566 | | - *reading = info->hpdet_res[0]; |
|---|
| 567 | | - |
|---|
| 568 | | - /* Sometimes we get false readings due to slow insert */ |
|---|
| 569 | | - if (*reading >= ARIZONA_HPDET_MAX && !info->hpdet_retried) { |
|---|
| 570 | | - dev_dbg(arizona->dev, "Retrying high impedance\n"); |
|---|
| 571 | | - info->num_hpdet_res = 0; |
|---|
| 572 | | - info->hpdet_retried = true; |
|---|
| 573 | | - arizona_start_hpdet_acc_id(info); |
|---|
| 574 | | - pm_runtime_put(info->dev); |
|---|
| 575 | | - return -EAGAIN; |
|---|
| 576 | | - } |
|---|
| 577 | | - |
|---|
| 578 | | - /* |
|---|
| 579 | | - * If we measure the mic as high impedance |
|---|
| 580 | | - */ |
|---|
| 581 | | - if (!id_gpio || info->hpdet_res[1] > 50) { |
|---|
| 582 | | - dev_dbg(arizona->dev, "Detected mic\n"); |
|---|
| 583 | | - *mic = true; |
|---|
| 584 | | - info->detecting = true; |
|---|
| 585 | | - } else { |
|---|
| 586 | | - dev_dbg(arizona->dev, "Detected headphone\n"); |
|---|
| 587 | | - } |
|---|
| 588 | | - |
|---|
| 589 | | - /* Make sure everything is reset back to the real polarity */ |
|---|
| 590 | 549 | regmap_update_bits(arizona->regmap, |
|---|
| 591 | 550 | ARIZONA_ACCESSORY_DETECT_MODE_1, |
|---|
| 551 | + ARIZONA_ACCDET_MODE_MASK | |
|---|
| 592 | 552 | ARIZONA_ACCDET_SRC, |
|---|
| 553 | + ARIZONA_ACCDET_MODE_HPR | |
|---|
| 593 | 554 | info->micd_modes[0].src); |
|---|
| 555 | + |
|---|
| 556 | + gpio_set_value_cansleep(id_gpio, 1); |
|---|
| 557 | + |
|---|
| 558 | + regmap_update_bits(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1, |
|---|
| 559 | + ARIZONA_HP_POLL, ARIZONA_HP_POLL); |
|---|
| 560 | + return -EAGAIN; |
|---|
| 594 | 561 | } |
|---|
| 562 | + |
|---|
| 563 | + /* OK, got both. Now, compare... */ |
|---|
| 564 | + dev_dbg(arizona->dev, "HPDET measured %d %d\n", |
|---|
| 565 | + info->hpdet_res[0], info->hpdet_res[1]); |
|---|
| 566 | + |
|---|
| 567 | + /* Take the headphone impedance for the main report */ |
|---|
| 568 | + *reading = info->hpdet_res[0]; |
|---|
| 569 | + |
|---|
| 570 | + /* Sometimes we get false readings due to slow insert */ |
|---|
| 571 | + if (*reading >= ARIZONA_HPDET_MAX && !info->hpdet_retried) { |
|---|
| 572 | + dev_dbg(arizona->dev, "Retrying high impedance\n"); |
|---|
| 573 | + info->num_hpdet_res = 0; |
|---|
| 574 | + info->hpdet_retried = true; |
|---|
| 575 | + arizona_start_hpdet_acc_id(info); |
|---|
| 576 | + pm_runtime_put(info->dev); |
|---|
| 577 | + return -EAGAIN; |
|---|
| 578 | + } |
|---|
| 579 | + |
|---|
| 580 | + /* |
|---|
| 581 | + * If we measure the mic as high impedance |
|---|
| 582 | + */ |
|---|
| 583 | + if (!id_gpio || info->hpdet_res[1] > 50) { |
|---|
| 584 | + dev_dbg(arizona->dev, "Detected mic\n"); |
|---|
| 585 | + *mic = true; |
|---|
| 586 | + info->detecting = true; |
|---|
| 587 | + } else { |
|---|
| 588 | + dev_dbg(arizona->dev, "Detected headphone\n"); |
|---|
| 589 | + } |
|---|
| 590 | + |
|---|
| 591 | + /* Make sure everything is reset back to the real polarity */ |
|---|
| 592 | + regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1, |
|---|
| 593 | + ARIZONA_ACCDET_SRC, info->micd_modes[0].src); |
|---|
| 595 | 594 | |
|---|
| 596 | 595 | return 0; |
|---|
| 597 | 596 | } |
|---|
| .. | .. |
|---|
| 666 | 665 | if (id_gpio) |
|---|
| 667 | 666 | gpio_set_value_cansleep(id_gpio, 0); |
|---|
| 668 | 667 | |
|---|
| 669 | | - /* Revert back to MICDET mode */ |
|---|
| 670 | | - regmap_update_bits(arizona->regmap, |
|---|
| 671 | | - ARIZONA_ACCESSORY_DETECT_MODE_1, |
|---|
| 672 | | - ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC); |
|---|
| 673 | | - |
|---|
| 674 | 668 | /* If we have a mic then reenable MICDET */ |
|---|
| 675 | 669 | if (state && (mic || info->mic)) |
|---|
| 676 | 670 | arizona_start_mic(info); |
|---|
| .. | .. |
|---|
| 705 | 699 | |
|---|
| 706 | 700 | info->hpdet_active = true; |
|---|
| 707 | 701 | |
|---|
| 708 | | - if (info->mic) |
|---|
| 709 | | - arizona_stop_mic(info); |
|---|
| 702 | + arizona_stop_mic(info); |
|---|
| 710 | 703 | |
|---|
| 711 | 704 | arizona_extcon_hp_clamp(info, true); |
|---|
| 712 | 705 | |
|---|
| .. | .. |
|---|
| 730 | 723 | return; |
|---|
| 731 | 724 | |
|---|
| 732 | 725 | err: |
|---|
| 733 | | - regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1, |
|---|
| 734 | | - ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC); |
|---|
| 726 | + arizona_extcon_hp_clamp(info, false); |
|---|
| 727 | + pm_runtime_put_autosuspend(info->dev); |
|---|
| 735 | 728 | |
|---|
| 736 | 729 | /* Just report headphone */ |
|---|
| 737 | 730 | ret = extcon_set_state_sync(info->edev, EXTCON_JACK_HEADPHONE, true); |
|---|
| .. | .. |
|---|
| 787 | 780 | return; |
|---|
| 788 | 781 | |
|---|
| 789 | 782 | err: |
|---|
| 790 | | - regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1, |
|---|
| 791 | | - ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC); |
|---|
| 792 | | - |
|---|
| 793 | 783 | /* Just report headphone */ |
|---|
| 794 | 784 | ret = extcon_set_state_sync(info->edev, EXTCON_JACK_HEADPHONE, true); |
|---|
| 795 | 785 | if (ret != 0) |
|---|
| .. | .. |
|---|
| 812 | 802 | |
|---|
| 813 | 803 | arizona_identify_headphone(info); |
|---|
| 814 | 804 | |
|---|
| 815 | | - arizona_stop_mic(info); |
|---|
| 816 | | - |
|---|
| 817 | 805 | mutex_unlock(&info->lock); |
|---|
| 818 | 806 | } |
|---|
| 819 | 807 | |
|---|
| 820 | | -static void arizona_micd_detect(struct work_struct *work) |
|---|
| 808 | +static int arizona_micd_adc_read(struct arizona_extcon_info *info) |
|---|
| 821 | 809 | { |
|---|
| 822 | | - struct arizona_extcon_info *info = container_of(work, |
|---|
| 823 | | - struct arizona_extcon_info, |
|---|
| 824 | | - micd_detect_work.work); |
|---|
| 825 | 810 | struct arizona *arizona = info->arizona; |
|---|
| 826 | | - unsigned int val = 0, lvl; |
|---|
| 827 | | - int ret, i, key; |
|---|
| 811 | + unsigned int val; |
|---|
| 812 | + int ret; |
|---|
| 828 | 813 | |
|---|
| 829 | | - cancel_delayed_work_sync(&info->micd_timeout_work); |
|---|
| 814 | + /* Must disable MICD before we read the ADCVAL */ |
|---|
| 815 | + regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1, |
|---|
| 816 | + ARIZONA_MICD_ENA, 0); |
|---|
| 830 | 817 | |
|---|
| 831 | | - mutex_lock(&info->lock); |
|---|
| 832 | | - |
|---|
| 833 | | - /* If the cable was removed while measuring ignore the result */ |
|---|
| 834 | | - ret = extcon_get_state(info->edev, EXTCON_MECHANICAL); |
|---|
| 835 | | - if (ret < 0) { |
|---|
| 836 | | - dev_err(arizona->dev, "Failed to check cable state: %d\n", |
|---|
| 837 | | - ret); |
|---|
| 838 | | - mutex_unlock(&info->lock); |
|---|
| 839 | | - return; |
|---|
| 840 | | - } else if (!ret) { |
|---|
| 841 | | - dev_dbg(arizona->dev, "Ignoring MICDET for removed cable\n"); |
|---|
| 842 | | - mutex_unlock(&info->lock); |
|---|
| 843 | | - return; |
|---|
| 818 | + ret = regmap_read(arizona->regmap, ARIZONA_MIC_DETECT_4, &val); |
|---|
| 819 | + if (ret != 0) { |
|---|
| 820 | + dev_err(arizona->dev, |
|---|
| 821 | + "Failed to read MICDET_ADCVAL: %d\n", ret); |
|---|
| 822 | + return ret; |
|---|
| 844 | 823 | } |
|---|
| 845 | 824 | |
|---|
| 846 | | - if (info->detecting && arizona->pdata.micd_software_compare) { |
|---|
| 847 | | - /* Must disable MICD before we read the ADCVAL */ |
|---|
| 848 | | - regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1, |
|---|
| 849 | | - ARIZONA_MICD_ENA, 0); |
|---|
| 850 | | - ret = regmap_read(arizona->regmap, ARIZONA_MIC_DETECT_4, &val); |
|---|
| 851 | | - if (ret != 0) { |
|---|
| 852 | | - dev_err(arizona->dev, |
|---|
| 853 | | - "Failed to read MICDET_ADCVAL: %d\n", |
|---|
| 854 | | - ret); |
|---|
| 855 | | - mutex_unlock(&info->lock); |
|---|
| 856 | | - return; |
|---|
| 857 | | - } |
|---|
| 825 | + dev_dbg(arizona->dev, "MICDET_ADCVAL: %x\n", val); |
|---|
| 858 | 826 | |
|---|
| 859 | | - dev_dbg(arizona->dev, "MICDET_ADCVAL: %x\n", val); |
|---|
| 827 | + val &= ARIZONA_MICDET_ADCVAL_MASK; |
|---|
| 828 | + if (val < ARRAY_SIZE(arizona_micd_levels)) |
|---|
| 829 | + val = arizona_micd_levels[val]; |
|---|
| 830 | + else |
|---|
| 831 | + val = INT_MAX; |
|---|
| 860 | 832 | |
|---|
| 861 | | - val &= ARIZONA_MICDET_ADCVAL_MASK; |
|---|
| 862 | | - if (val < ARRAY_SIZE(arizona_micd_levels)) |
|---|
| 863 | | - val = arizona_micd_levels[val]; |
|---|
| 864 | | - else |
|---|
| 865 | | - val = INT_MAX; |
|---|
| 833 | + if (val <= QUICK_HEADPHONE_MAX_OHM) |
|---|
| 834 | + val = ARIZONA_MICD_STS | ARIZONA_MICD_LVL_0; |
|---|
| 835 | + else if (val <= MICROPHONE_MIN_OHM) |
|---|
| 836 | + val = ARIZONA_MICD_STS | ARIZONA_MICD_LVL_1; |
|---|
| 837 | + else if (val <= MICROPHONE_MAX_OHM) |
|---|
| 838 | + val = ARIZONA_MICD_STS | ARIZONA_MICD_LVL_8; |
|---|
| 839 | + else |
|---|
| 840 | + val = ARIZONA_MICD_LVL_8; |
|---|
| 866 | 841 | |
|---|
| 867 | | - if (val <= QUICK_HEADPHONE_MAX_OHM) |
|---|
| 868 | | - val = ARIZONA_MICD_STS | ARIZONA_MICD_LVL_0; |
|---|
| 869 | | - else if (val <= MICROPHONE_MIN_OHM) |
|---|
| 870 | | - val = ARIZONA_MICD_STS | ARIZONA_MICD_LVL_1; |
|---|
| 871 | | - else if (val <= MICROPHONE_MAX_OHM) |
|---|
| 872 | | - val = ARIZONA_MICD_STS | ARIZONA_MICD_LVL_8; |
|---|
| 873 | | - else |
|---|
| 874 | | - val = ARIZONA_MICD_LVL_8; |
|---|
| 875 | | - } |
|---|
| 842 | + return val; |
|---|
| 843 | +} |
|---|
| 844 | + |
|---|
| 845 | +static int arizona_micd_read(struct arizona_extcon_info *info) |
|---|
| 846 | +{ |
|---|
| 847 | + struct arizona *arizona = info->arizona; |
|---|
| 848 | + unsigned int val = 0; |
|---|
| 849 | + int ret, i; |
|---|
| 876 | 850 | |
|---|
| 877 | 851 | for (i = 0; i < 10 && !(val & MICD_LVL_0_TO_8); i++) { |
|---|
| 878 | 852 | ret = regmap_read(arizona->regmap, ARIZONA_MIC_DETECT_3, &val); |
|---|
| 879 | 853 | if (ret != 0) { |
|---|
| 880 | 854 | dev_err(arizona->dev, |
|---|
| 881 | 855 | "Failed to read MICDET: %d\n", ret); |
|---|
| 882 | | - mutex_unlock(&info->lock); |
|---|
| 883 | | - return; |
|---|
| 856 | + return ret; |
|---|
| 884 | 857 | } |
|---|
| 885 | 858 | |
|---|
| 886 | 859 | dev_dbg(arizona->dev, "MICDET: %x\n", val); |
|---|
| .. | .. |
|---|
| 888 | 861 | if (!(val & ARIZONA_MICD_VALID)) { |
|---|
| 889 | 862 | dev_warn(arizona->dev, |
|---|
| 890 | 863 | "Microphone detection state invalid\n"); |
|---|
| 891 | | - mutex_unlock(&info->lock); |
|---|
| 892 | | - return; |
|---|
| 864 | + return -EINVAL; |
|---|
| 893 | 865 | } |
|---|
| 894 | 866 | } |
|---|
| 895 | 867 | |
|---|
| 896 | 868 | if (i == 10 && !(val & MICD_LVL_0_TO_8)) { |
|---|
| 897 | 869 | dev_err(arizona->dev, "Failed to get valid MICDET value\n"); |
|---|
| 898 | | - mutex_unlock(&info->lock); |
|---|
| 899 | | - return; |
|---|
| 870 | + return -EINVAL; |
|---|
| 900 | 871 | } |
|---|
| 872 | + |
|---|
| 873 | + return val; |
|---|
| 874 | +} |
|---|
| 875 | + |
|---|
| 876 | +static int arizona_micdet_reading(void *priv) |
|---|
| 877 | +{ |
|---|
| 878 | + struct arizona_extcon_info *info = priv; |
|---|
| 879 | + struct arizona *arizona = info->arizona; |
|---|
| 880 | + int ret, val; |
|---|
| 881 | + |
|---|
| 882 | + if (info->detecting && arizona->pdata.micd_software_compare) |
|---|
| 883 | + ret = arizona_micd_adc_read(info); |
|---|
| 884 | + else |
|---|
| 885 | + ret = arizona_micd_read(info); |
|---|
| 886 | + if (ret < 0) |
|---|
| 887 | + return ret; |
|---|
| 888 | + |
|---|
| 889 | + val = ret; |
|---|
| 901 | 890 | |
|---|
| 902 | 891 | /* Due to jack detect this should never happen */ |
|---|
| 903 | 892 | if (!(val & ARIZONA_MICD_STS)) { |
|---|
| 904 | 893 | dev_warn(arizona->dev, "Detected open circuit\n"); |
|---|
| 905 | 894 | info->mic = false; |
|---|
| 906 | | - arizona_stop_mic(info); |
|---|
| 907 | 895 | info->detecting = false; |
|---|
| 908 | 896 | arizona_identify_headphone(info); |
|---|
| 909 | | - goto handled; |
|---|
| 897 | + return 0; |
|---|
| 910 | 898 | } |
|---|
| 911 | 899 | |
|---|
| 912 | 900 | /* If we got a high impedence we should have a headset, report it. */ |
|---|
| 913 | | - if (info->detecting && (val & ARIZONA_MICD_LVL_8)) { |
|---|
| 901 | + if (val & ARIZONA_MICD_LVL_8) { |
|---|
| 914 | 902 | info->mic = true; |
|---|
| 915 | 903 | info->detecting = false; |
|---|
| 916 | 904 | |
|---|
| .. | .. |
|---|
| 929 | 917 | ret); |
|---|
| 930 | 918 | } |
|---|
| 931 | 919 | |
|---|
| 932 | | - goto handled; |
|---|
| 920 | + return 0; |
|---|
| 933 | 921 | } |
|---|
| 934 | 922 | |
|---|
| 935 | 923 | /* If we detected a lower impedence during initial startup |
|---|
| .. | .. |
|---|
| 938 | 926 | * plain headphones. If both polarities report a low |
|---|
| 939 | 927 | * impedence then give up and report headphones. |
|---|
| 940 | 928 | */ |
|---|
| 941 | | - if (info->detecting && (val & MICD_LVL_1_TO_7)) { |
|---|
| 929 | + if (val & MICD_LVL_1_TO_7) { |
|---|
| 942 | 930 | if (info->jack_flips >= info->micd_num_modes * 10) { |
|---|
| 943 | 931 | dev_dbg(arizona->dev, "Detected HP/line\n"); |
|---|
| 944 | 932 | |
|---|
| 945 | 933 | info->detecting = false; |
|---|
| 946 | 934 | |
|---|
| 947 | 935 | arizona_identify_headphone(info); |
|---|
| 948 | | - |
|---|
| 949 | | - arizona_stop_mic(info); |
|---|
| 950 | 936 | } else { |
|---|
| 951 | 937 | info->micd_mode++; |
|---|
| 952 | 938 | if (info->micd_mode == info->micd_num_modes) |
|---|
| .. | .. |
|---|
| 954 | 940 | arizona_extcon_set_mode(info, info->micd_mode); |
|---|
| 955 | 941 | |
|---|
| 956 | 942 | info->jack_flips++; |
|---|
| 943 | + |
|---|
| 944 | + if (arizona->pdata.micd_software_compare) |
|---|
| 945 | + regmap_update_bits(arizona->regmap, |
|---|
| 946 | + ARIZONA_MIC_DETECT_1, |
|---|
| 947 | + ARIZONA_MICD_ENA, |
|---|
| 948 | + ARIZONA_MICD_ENA); |
|---|
| 949 | + |
|---|
| 950 | + queue_delayed_work(system_power_efficient_wq, |
|---|
| 951 | + &info->micd_timeout_work, |
|---|
| 952 | + msecs_to_jiffies(arizona->pdata.micd_timeout)); |
|---|
| 957 | 953 | } |
|---|
| 958 | 954 | |
|---|
| 959 | | - goto handled; |
|---|
| 955 | + return 0; |
|---|
| 960 | 956 | } |
|---|
| 957 | + |
|---|
| 958 | + /* |
|---|
| 959 | + * If we're still detecting and we detect a short then we've |
|---|
| 960 | + * got a headphone. |
|---|
| 961 | + */ |
|---|
| 962 | + dev_dbg(arizona->dev, "Headphone detected\n"); |
|---|
| 963 | + info->detecting = false; |
|---|
| 964 | + |
|---|
| 965 | + arizona_identify_headphone(info); |
|---|
| 966 | + |
|---|
| 967 | + return 0; |
|---|
| 968 | +} |
|---|
| 969 | + |
|---|
| 970 | +static int arizona_button_reading(void *priv) |
|---|
| 971 | +{ |
|---|
| 972 | + struct arizona_extcon_info *info = priv; |
|---|
| 973 | + struct arizona *arizona = info->arizona; |
|---|
| 974 | + int val, key, lvl, i; |
|---|
| 975 | + |
|---|
| 976 | + val = arizona_micd_read(info); |
|---|
| 977 | + if (val < 0) |
|---|
| 978 | + return val; |
|---|
| 961 | 979 | |
|---|
| 962 | 980 | /* |
|---|
| 963 | 981 | * If we're still detecting and we detect a short then we've |
|---|
| .. | .. |
|---|
| 974 | 992 | input_report_key(info->input, |
|---|
| 975 | 993 | info->micd_ranges[i].key, 0); |
|---|
| 976 | 994 | |
|---|
| 977 | | - WARN_ON(!lvl); |
|---|
| 978 | | - WARN_ON(ffs(lvl) - 1 >= info->num_micd_ranges); |
|---|
| 979 | 995 | if (lvl && ffs(lvl) - 1 < info->num_micd_ranges) { |
|---|
| 980 | 996 | key = info->micd_ranges[ffs(lvl) - 1].key; |
|---|
| 981 | 997 | input_report_key(info->input, key, 1); |
|---|
| 982 | 998 | input_sync(info->input); |
|---|
| 999 | + } else { |
|---|
| 1000 | + dev_err(arizona->dev, "Button out of range\n"); |
|---|
| 983 | 1001 | } |
|---|
| 984 | | - |
|---|
| 985 | | - } else if (info->detecting) { |
|---|
| 986 | | - dev_dbg(arizona->dev, "Headphone detected\n"); |
|---|
| 987 | | - info->detecting = false; |
|---|
| 988 | | - arizona_stop_mic(info); |
|---|
| 989 | | - |
|---|
| 990 | | - arizona_identify_headphone(info); |
|---|
| 991 | 1002 | } else { |
|---|
| 992 | 1003 | dev_warn(arizona->dev, "Button with no mic: %x\n", |
|---|
| 993 | 1004 | val); |
|---|
| .. | .. |
|---|
| 1001 | 1012 | arizona_extcon_pulse_micbias(info); |
|---|
| 1002 | 1013 | } |
|---|
| 1003 | 1014 | |
|---|
| 1004 | | -handled: |
|---|
| 1005 | | - if (info->detecting) { |
|---|
| 1006 | | - if (arizona->pdata.micd_software_compare) |
|---|
| 1007 | | - regmap_update_bits(arizona->regmap, |
|---|
| 1008 | | - ARIZONA_MIC_DETECT_1, |
|---|
| 1009 | | - ARIZONA_MICD_ENA, |
|---|
| 1010 | | - ARIZONA_MICD_ENA); |
|---|
| 1015 | + return 0; |
|---|
| 1016 | +} |
|---|
| 1011 | 1017 | |
|---|
| 1012 | | - queue_delayed_work(system_power_efficient_wq, |
|---|
| 1013 | | - &info->micd_timeout_work, |
|---|
| 1014 | | - msecs_to_jiffies(info->micd_timeout)); |
|---|
| 1018 | +static void arizona_micd_detect(struct work_struct *work) |
|---|
| 1019 | +{ |
|---|
| 1020 | + struct arizona_extcon_info *info = container_of(work, |
|---|
| 1021 | + struct arizona_extcon_info, |
|---|
| 1022 | + micd_detect_work.work); |
|---|
| 1023 | + struct arizona *arizona = info->arizona; |
|---|
| 1024 | + int ret; |
|---|
| 1025 | + |
|---|
| 1026 | + cancel_delayed_work_sync(&info->micd_timeout_work); |
|---|
| 1027 | + |
|---|
| 1028 | + mutex_lock(&info->lock); |
|---|
| 1029 | + |
|---|
| 1030 | + /* If the cable was removed while measuring ignore the result */ |
|---|
| 1031 | + ret = extcon_get_state(info->edev, EXTCON_MECHANICAL); |
|---|
| 1032 | + if (ret < 0) { |
|---|
| 1033 | + dev_err(arizona->dev, "Failed to check cable state: %d\n", |
|---|
| 1034 | + ret); |
|---|
| 1035 | + mutex_unlock(&info->lock); |
|---|
| 1036 | + return; |
|---|
| 1037 | + } else if (!ret) { |
|---|
| 1038 | + dev_dbg(arizona->dev, "Ignoring MICDET for removed cable\n"); |
|---|
| 1039 | + mutex_unlock(&info->lock); |
|---|
| 1040 | + return; |
|---|
| 1015 | 1041 | } |
|---|
| 1042 | + |
|---|
| 1043 | + if (info->detecting) |
|---|
| 1044 | + arizona_micdet_reading(info); |
|---|
| 1045 | + else |
|---|
| 1046 | + arizona_button_reading(info); |
|---|
| 1016 | 1047 | |
|---|
| 1017 | 1048 | pm_runtime_mark_last_busy(info->dev); |
|---|
| 1018 | 1049 | mutex_unlock(&info->lock); |
|---|
| .. | .. |
|---|
| 1131 | 1162 | msecs_to_jiffies(HPDET_DEBOUNCE)); |
|---|
| 1132 | 1163 | |
|---|
| 1133 | 1164 | if (cancelled_mic) { |
|---|
| 1134 | | - int micd_timeout = info->micd_timeout; |
|---|
| 1165 | + int micd_timeout = arizona->pdata.micd_timeout; |
|---|
| 1135 | 1166 | |
|---|
| 1136 | 1167 | queue_delayed_work(system_power_efficient_wq, |
|---|
| 1137 | 1168 | &info->micd_timeout_work, |
|---|
| .. | .. |
|---|
| 1151 | 1182 | dev_err(arizona->dev, "Mechanical report failed: %d\n", |
|---|
| 1152 | 1183 | ret); |
|---|
| 1153 | 1184 | |
|---|
| 1154 | | - if (!arizona->pdata.hpdet_acc_id) { |
|---|
| 1155 | | - info->detecting = true; |
|---|
| 1156 | | - info->mic = false; |
|---|
| 1157 | | - info->jack_flips = 0; |
|---|
| 1185 | + info->detecting = true; |
|---|
| 1186 | + info->mic = false; |
|---|
| 1187 | + info->jack_flips = 0; |
|---|
| 1158 | 1188 | |
|---|
| 1189 | + if (!arizona->pdata.hpdet_acc_id) { |
|---|
| 1159 | 1190 | arizona_start_mic(info); |
|---|
| 1160 | 1191 | } else { |
|---|
| 1161 | 1192 | queue_delayed_work(system_power_efficient_wq, |
|---|
| .. | .. |
|---|
| 1208 | 1239 | ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB); |
|---|
| 1209 | 1240 | } |
|---|
| 1210 | 1241 | |
|---|
| 1211 | | - if (arizona->pdata.micd_timeout) |
|---|
| 1212 | | - info->micd_timeout = arizona->pdata.micd_timeout; |
|---|
| 1213 | | - else |
|---|
| 1214 | | - info->micd_timeout = DEFAULT_MICD_TIMEOUT; |
|---|
| 1215 | | - |
|---|
| 1216 | 1242 | out: |
|---|
| 1217 | 1243 | /* Clear trig_sts to make sure DCVDD is not forced up */ |
|---|
| 1218 | 1244 | regmap_write(arizona->regmap, ARIZONA_AOD_WKUP_AND_TRIG, |
|---|
| .. | .. |
|---|
| 1259 | 1285 | int i, j; |
|---|
| 1260 | 1286 | u32 *vals; |
|---|
| 1261 | 1287 | |
|---|
| 1262 | | - nconfs = device_property_read_u32_array(arizona->dev, prop, NULL, 0); |
|---|
| 1288 | + nconfs = device_property_count_u32(arizona->dev, prop); |
|---|
| 1263 | 1289 | if (nconfs <= 0) |
|---|
| 1264 | 1290 | return 0; |
|---|
| 1265 | 1291 | |
|---|
| .. | .. |
|---|
| 1435 | 1461 | if (!info->input) { |
|---|
| 1436 | 1462 | dev_err(arizona->dev, "Can't allocate input dev\n"); |
|---|
| 1437 | 1463 | ret = -ENOMEM; |
|---|
| 1438 | | - goto err_register; |
|---|
| 1464 | + return ret; |
|---|
| 1439 | 1465 | } |
|---|
| 1440 | 1466 | |
|---|
| 1441 | 1467 | info->input->name = "Headset"; |
|---|
| 1442 | 1468 | info->input->phys = "arizona/extcon"; |
|---|
| 1469 | + |
|---|
| 1470 | + if (!pdata->micd_timeout) |
|---|
| 1471 | + pdata->micd_timeout = DEFAULT_MICD_TIMEOUT; |
|---|
| 1443 | 1472 | |
|---|
| 1444 | 1473 | if (pdata->num_micd_configs) { |
|---|
| 1445 | 1474 | info->micd_modes = pdata->micd_configs; |
|---|
| .. | .. |
|---|
| 1464 | 1493 | if (ret != 0) { |
|---|
| 1465 | 1494 | dev_err(arizona->dev, "Failed to request GPIO%d: %d\n", |
|---|
| 1466 | 1495 | pdata->micd_pol_gpio, ret); |
|---|
| 1467 | | - goto err_register; |
|---|
| 1496 | + return ret; |
|---|
| 1468 | 1497 | } |
|---|
| 1469 | 1498 | |
|---|
| 1470 | 1499 | info->micd_pol_gpio = gpio_to_desc(pdata->micd_pol_gpio); |
|---|
| .. | .. |
|---|
| 1487 | 1516 | dev_err(arizona->dev, |
|---|
| 1488 | 1517 | "Failed to get microphone polarity GPIO: %d\n", |
|---|
| 1489 | 1518 | ret); |
|---|
| 1490 | | - goto err_register; |
|---|
| 1519 | + return ret; |
|---|
| 1491 | 1520 | } |
|---|
| 1492 | 1521 | } |
|---|
| 1493 | 1522 | |
|---|
| .. | .. |
|---|
| 1644 | 1673 | if (ret != 0) { |
|---|
| 1645 | 1674 | dev_err(&pdev->dev, "Failed to get JACKDET rise IRQ: %d\n", |
|---|
| 1646 | 1675 | ret); |
|---|
| 1647 | | - goto err_gpio; |
|---|
| 1676 | + goto err_pm; |
|---|
| 1648 | 1677 | } |
|---|
| 1649 | 1678 | |
|---|
| 1650 | 1679 | ret = arizona_set_irq_wake(arizona, jack_irq_rise, 1); |
|---|
| .. | .. |
|---|
| 1693 | 1722 | dev_warn(arizona->dev, "Failed to set MICVDD to bypass: %d\n", |
|---|
| 1694 | 1723 | ret); |
|---|
| 1695 | 1724 | |
|---|
| 1696 | | - pm_runtime_put(&pdev->dev); |
|---|
| 1697 | | - |
|---|
| 1698 | 1725 | ret = input_register_device(info->input); |
|---|
| 1699 | 1726 | if (ret) { |
|---|
| 1700 | 1727 | dev_err(&pdev->dev, "Can't register input device: %d\n", ret); |
|---|
| 1701 | 1728 | goto err_hpdet; |
|---|
| 1702 | 1729 | } |
|---|
| 1730 | + |
|---|
| 1731 | + pm_runtime_put(&pdev->dev); |
|---|
| 1703 | 1732 | |
|---|
| 1704 | 1733 | return 0; |
|---|
| 1705 | 1734 | |
|---|
| .. | .. |
|---|
| 1715 | 1744 | arizona_set_irq_wake(arizona, jack_irq_rise, 0); |
|---|
| 1716 | 1745 | err_rise: |
|---|
| 1717 | 1746 | arizona_free_irq(arizona, jack_irq_rise, info); |
|---|
| 1747 | +err_pm: |
|---|
| 1748 | + pm_runtime_put(&pdev->dev); |
|---|
| 1749 | + pm_runtime_disable(&pdev->dev); |
|---|
| 1718 | 1750 | err_gpio: |
|---|
| 1719 | 1751 | gpiod_put(info->micd_pol_gpio); |
|---|
| 1720 | | -err_register: |
|---|
| 1721 | | - pm_runtime_disable(&pdev->dev); |
|---|
| 1722 | 1752 | return ret; |
|---|
| 1723 | 1753 | } |
|---|
| 1724 | 1754 | |
|---|
| .. | .. |
|---|
| 1728 | 1758 | struct arizona *arizona = info->arizona; |
|---|
| 1729 | 1759 | int jack_irq_rise, jack_irq_fall; |
|---|
| 1730 | 1760 | bool change; |
|---|
| 1731 | | - |
|---|
| 1732 | | - regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1, |
|---|
| 1733 | | - ARIZONA_MICD_ENA, 0, |
|---|
| 1734 | | - &change); |
|---|
| 1735 | | - |
|---|
| 1736 | | - if (change) { |
|---|
| 1737 | | - regulator_disable(info->micvdd); |
|---|
| 1738 | | - pm_runtime_put(info->dev); |
|---|
| 1739 | | - } |
|---|
| 1740 | | - |
|---|
| 1741 | | - gpiod_put(info->micd_pol_gpio); |
|---|
| 1742 | | - |
|---|
| 1743 | | - pm_runtime_disable(&pdev->dev); |
|---|
| 1744 | | - |
|---|
| 1745 | | - regmap_update_bits(arizona->regmap, |
|---|
| 1746 | | - ARIZONA_MICD_CLAMP_CONTROL, |
|---|
| 1747 | | - ARIZONA_MICD_CLAMP_MODE_MASK, 0); |
|---|
| 1761 | + int ret; |
|---|
| 1748 | 1762 | |
|---|
| 1749 | 1763 | if (info->micd_clamp) { |
|---|
| 1750 | 1764 | jack_irq_rise = ARIZONA_IRQ_MICD_CLAMP_RISE; |
|---|
| .. | .. |
|---|
| 1761 | 1775 | arizona_free_irq(arizona, jack_irq_rise, info); |
|---|
| 1762 | 1776 | arizona_free_irq(arizona, jack_irq_fall, info); |
|---|
| 1763 | 1777 | cancel_delayed_work_sync(&info->hpdet_work); |
|---|
| 1778 | + cancel_delayed_work_sync(&info->micd_detect_work); |
|---|
| 1779 | + cancel_delayed_work_sync(&info->micd_timeout_work); |
|---|
| 1780 | + |
|---|
| 1781 | + ret = regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1, |
|---|
| 1782 | + ARIZONA_MICD_ENA, 0, |
|---|
| 1783 | + &change); |
|---|
| 1784 | + if (ret < 0) { |
|---|
| 1785 | + dev_err(&pdev->dev, "Failed to disable micd on remove: %d\n", |
|---|
| 1786 | + ret); |
|---|
| 1787 | + } else if (change) { |
|---|
| 1788 | + regulator_disable(info->micvdd); |
|---|
| 1789 | + pm_runtime_put(info->dev); |
|---|
| 1790 | + } |
|---|
| 1791 | + |
|---|
| 1792 | + regmap_update_bits(arizona->regmap, |
|---|
| 1793 | + ARIZONA_MICD_CLAMP_CONTROL, |
|---|
| 1794 | + ARIZONA_MICD_CLAMP_MODE_MASK, 0); |
|---|
| 1764 | 1795 | regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE, |
|---|
| 1765 | 1796 | ARIZONA_JD1_ENA, 0); |
|---|
| 1766 | 1797 | arizona_clk32k_disable(arizona); |
|---|
| 1767 | 1798 | |
|---|
| 1799 | + gpiod_put(info->micd_pol_gpio); |
|---|
| 1800 | + |
|---|
| 1801 | + pm_runtime_disable(&pdev->dev); |
|---|
| 1802 | + |
|---|
| 1768 | 1803 | return 0; |
|---|
| 1769 | 1804 | } |
|---|
| 1770 | 1805 | |
|---|