diff options
Diffstat (limited to 'drivers/extcon/extcon-arizona.c')
-rw-r--r-- | drivers/extcon/extcon-arizona.c | 73 |
1 files changed, 53 insertions, 20 deletions
diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c index a287cece0593..c20602f601ee 100644 --- a/drivers/extcon/extcon-arizona.c +++ b/drivers/extcon/extcon-arizona.c | |||
@@ -44,6 +44,15 @@ | |||
44 | #define HPDET_DEBOUNCE 500 | 44 | #define HPDET_DEBOUNCE 500 |
45 | #define DEFAULT_MICD_TIMEOUT 2000 | 45 | #define DEFAULT_MICD_TIMEOUT 2000 |
46 | 46 | ||
47 | #define MICD_LVL_1_TO_7 (ARIZONA_MICD_LVL_1 | ARIZONA_MICD_LVL_2 | \ | ||
48 | ARIZONA_MICD_LVL_3 | ARIZONA_MICD_LVL_4 | \ | ||
49 | ARIZONA_MICD_LVL_5 | ARIZONA_MICD_LVL_6 | \ | ||
50 | ARIZONA_MICD_LVL_7) | ||
51 | |||
52 | #define MICD_LVL_0_TO_7 (ARIZONA_MICD_LVL_0 | MICD_LVL_1_TO_7) | ||
53 | |||
54 | #define MICD_LVL_0_TO_8 (MICD_LVL_0_TO_7 | ARIZONA_MICD_LVL_8) | ||
55 | |||
47 | struct arizona_extcon_info { | 56 | struct arizona_extcon_info { |
48 | struct device *dev; | 57 | struct device *dev; |
49 | struct arizona *arizona; | 58 | struct arizona *arizona; |
@@ -426,26 +435,15 @@ static int arizona_hpdet_read(struct arizona_extcon_info *info) | |||
426 | } | 435 | } |
427 | 436 | ||
428 | val &= ARIZONA_HP_LVL_B_MASK; | 437 | val &= ARIZONA_HP_LVL_B_MASK; |
438 | /* Convert to ohms, the value is in 0.5 ohm increments */ | ||
439 | val /= 2; | ||
429 | 440 | ||
430 | regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1, | 441 | regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1, |
431 | &range); | 442 | &range); |
432 | range = (range & ARIZONA_HP_IMPEDANCE_RANGE_MASK) | 443 | range = (range & ARIZONA_HP_IMPEDANCE_RANGE_MASK) |
433 | >> ARIZONA_HP_IMPEDANCE_RANGE_SHIFT; | 444 | >> ARIZONA_HP_IMPEDANCE_RANGE_SHIFT; |
434 | 445 | ||
435 | /* Skip up or down a range? */ | 446 | /* Skip up a range, or report? */ |
436 | if (range && (val < arizona_hpdet_c_ranges[range].min)) { | ||
437 | range--; | ||
438 | dev_dbg(arizona->dev, "Moving to HPDET range %d-%d\n", | ||
439 | arizona_hpdet_c_ranges[range].min, | ||
440 | arizona_hpdet_c_ranges[range].max); | ||
441 | regmap_update_bits(arizona->regmap, | ||
442 | ARIZONA_HEADPHONE_DETECT_1, | ||
443 | ARIZONA_HP_IMPEDANCE_RANGE_MASK, | ||
444 | range << | ||
445 | ARIZONA_HP_IMPEDANCE_RANGE_SHIFT); | ||
446 | return -EAGAIN; | ||
447 | } | ||
448 | |||
449 | if (range < ARRAY_SIZE(arizona_hpdet_c_ranges) - 1 && | 447 | if (range < ARRAY_SIZE(arizona_hpdet_c_ranges) - 1 && |
450 | (val >= arizona_hpdet_c_ranges[range].max)) { | 448 | (val >= arizona_hpdet_c_ranges[range].max)) { |
451 | range++; | 449 | range++; |
@@ -459,6 +457,12 @@ static int arizona_hpdet_read(struct arizona_extcon_info *info) | |||
459 | ARIZONA_HP_IMPEDANCE_RANGE_SHIFT); | 457 | ARIZONA_HP_IMPEDANCE_RANGE_SHIFT); |
460 | return -EAGAIN; | 458 | return -EAGAIN; |
461 | } | 459 | } |
460 | |||
461 | if (range && (val < arizona_hpdet_c_ranges[range].min)) { | ||
462 | dev_dbg(arizona->dev, "Reporting range boundary %d\n", | ||
463 | arizona_hpdet_c_ranges[range].min); | ||
464 | val = arizona_hpdet_c_ranges[range].min; | ||
465 | } | ||
462 | } | 466 | } |
463 | 467 | ||
464 | dev_dbg(arizona->dev, "HP impedance %d ohms\n", val); | 468 | dev_dbg(arizona->dev, "HP impedance %d ohms\n", val); |
@@ -594,9 +598,15 @@ static irqreturn_t arizona_hpdet_irq(int irq, void *data) | |||
594 | dev_err(arizona->dev, "Failed to report HP/line: %d\n", | 598 | dev_err(arizona->dev, "Failed to report HP/line: %d\n", |
595 | ret); | 599 | ret); |
596 | 600 | ||
601 | done: | ||
602 | /* Reset back to starting range */ | ||
603 | regmap_update_bits(arizona->regmap, | ||
604 | ARIZONA_HEADPHONE_DETECT_1, | ||
605 | ARIZONA_HP_IMPEDANCE_RANGE_MASK | ARIZONA_HP_POLL, | ||
606 | 0); | ||
607 | |||
597 | arizona_extcon_do_magic(info, 0); | 608 | arizona_extcon_do_magic(info, 0); |
598 | 609 | ||
599 | done: | ||
600 | if (id_gpio) | 610 | if (id_gpio) |
601 | gpio_set_value_cansleep(id_gpio, 0); | 611 | gpio_set_value_cansleep(id_gpio, 0); |
602 | 612 | ||
@@ -765,7 +775,20 @@ static void arizona_micd_detect(struct work_struct *work) | |||
765 | 775 | ||
766 | mutex_lock(&info->lock); | 776 | mutex_lock(&info->lock); |
767 | 777 | ||
768 | for (i = 0; i < 10 && !(val & 0x7fc); i++) { | 778 | /* If the cable was removed while measuring ignore the result */ |
779 | ret = extcon_get_cable_state_(&info->edev, ARIZONA_CABLE_MECHANICAL); | ||
780 | if (ret < 0) { | ||
781 | dev_err(arizona->dev, "Failed to check cable state: %d\n", | ||
782 | ret); | ||
783 | mutex_unlock(&info->lock); | ||
784 | return; | ||
785 | } else if (!ret) { | ||
786 | dev_dbg(arizona->dev, "Ignoring MICDET for removed cable\n"); | ||
787 | mutex_unlock(&info->lock); | ||
788 | return; | ||
789 | } | ||
790 | |||
791 | for (i = 0; i < 10 && !(val & MICD_LVL_0_TO_8); i++) { | ||
769 | ret = regmap_read(arizona->regmap, ARIZONA_MIC_DETECT_3, &val); | 792 | ret = regmap_read(arizona->regmap, ARIZONA_MIC_DETECT_3, &val); |
770 | if (ret != 0) { | 793 | if (ret != 0) { |
771 | dev_err(arizona->dev, | 794 | dev_err(arizona->dev, |
@@ -784,7 +807,7 @@ static void arizona_micd_detect(struct work_struct *work) | |||
784 | } | 807 | } |
785 | } | 808 | } |
786 | 809 | ||
787 | if (i == 10 && !(val & 0x7fc)) { | 810 | if (i == 10 && !(val & MICD_LVL_0_TO_8)) { |
788 | dev_err(arizona->dev, "Failed to get valid MICDET value\n"); | 811 | dev_err(arizona->dev, "Failed to get valid MICDET value\n"); |
789 | mutex_unlock(&info->lock); | 812 | mutex_unlock(&info->lock); |
790 | return; | 813 | return; |
@@ -798,7 +821,7 @@ static void arizona_micd_detect(struct work_struct *work) | |||
798 | } | 821 | } |
799 | 822 | ||
800 | /* If we got a high impedence we should have a headset, report it. */ | 823 | /* If we got a high impedence we should have a headset, report it. */ |
801 | if (info->detecting && (val & 0x400)) { | 824 | if (info->detecting && (val & ARIZONA_MICD_LVL_8)) { |
802 | arizona_identify_headphone(info); | 825 | arizona_identify_headphone(info); |
803 | 826 | ||
804 | ret = extcon_update_state(&info->edev, | 827 | ret = extcon_update_state(&info->edev, |
@@ -827,7 +850,7 @@ static void arizona_micd_detect(struct work_struct *work) | |||
827 | * plain headphones. If both polarities report a low | 850 | * plain headphones. If both polarities report a low |
828 | * impedence then give up and report headphones. | 851 | * impedence then give up and report headphones. |
829 | */ | 852 | */ |
830 | if (info->detecting && (val & 0x3f8)) { | 853 | if (info->detecting && (val & MICD_LVL_1_TO_7)) { |
831 | if (info->jack_flips >= info->micd_num_modes * 10) { | 854 | if (info->jack_flips >= info->micd_num_modes * 10) { |
832 | dev_dbg(arizona->dev, "Detected HP/line\n"); | 855 | dev_dbg(arizona->dev, "Detected HP/line\n"); |
833 | arizona_identify_headphone(info); | 856 | arizona_identify_headphone(info); |
@@ -851,7 +874,7 @@ static void arizona_micd_detect(struct work_struct *work) | |||
851 | * If we're still detecting and we detect a short then we've | 874 | * If we're still detecting and we detect a short then we've |
852 | * got a headphone. Otherwise it's a button press. | 875 | * got a headphone. Otherwise it's a button press. |
853 | */ | 876 | */ |
854 | if (val & 0x3fc) { | 877 | if (val & MICD_LVL_0_TO_7) { |
855 | if (info->mic) { | 878 | if (info->mic) { |
856 | dev_dbg(arizona->dev, "Mic button detected\n"); | 879 | dev_dbg(arizona->dev, "Mic button detected\n"); |
857 | 880 | ||
@@ -1126,6 +1149,16 @@ static int arizona_extcon_probe(struct platform_device *pdev) | |||
1126 | break; | 1149 | break; |
1127 | } | 1150 | } |
1128 | break; | 1151 | break; |
1152 | case WM5110: | ||
1153 | switch (arizona->rev) { | ||
1154 | case 0 ... 2: | ||
1155 | break; | ||
1156 | default: | ||
1157 | info->micd_clamp = true; | ||
1158 | info->hpdet_ip = 2; | ||
1159 | break; | ||
1160 | } | ||
1161 | break; | ||
1129 | default: | 1162 | default: |
1130 | break; | 1163 | break; |
1131 | } | 1164 | } |