diff options
author | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2013-04-03 14:28:18 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2013-04-03 14:28:18 -0400 |
commit | 2638953fcd6eeea27b4975c1cdd5e62e32758f8f (patch) | |
tree | 0ea42b074ce2432bb1a38e4cc977d197e9439341 /drivers/extcon | |
parent | 33facb4d69cd60895073ed0a018a524a8e2a01ba (diff) | |
parent | 7abd4e2a8f1c3e534da44c35e2d3d6353573e51f (diff) |
Merge tag 'extcon-arizona-v3.10' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/misc into char-misc-next
Mark writes:
extcon: arizona: Updates for v3.10
There's a bunch of different things in this series, I can split them out
if need be:
- Support for configuring the button detection circuit to reflect the
accessories supplied with the system.
- Improvements in the HPDET based detection scheme.
- Additional robustness against more pathological use cases.
- A few small standalone fixes.
Diffstat (limited to 'drivers/extcon')
-rw-r--r-- | drivers/extcon/extcon-arizona.c | 391 |
1 files changed, 287 insertions, 104 deletions
diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c index b28927972128..7a1b4a7791ba 100644 --- a/drivers/extcon/extcon-arizona.c +++ b/drivers/extcon/extcon-arizona.c | |||
@@ -33,12 +33,17 @@ | |||
33 | #include <linux/mfd/arizona/pdata.h> | 33 | #include <linux/mfd/arizona/pdata.h> |
34 | #include <linux/mfd/arizona/registers.h> | 34 | #include <linux/mfd/arizona/registers.h> |
35 | 35 | ||
36 | #define ARIZONA_NUM_BUTTONS 6 | 36 | #define ARIZONA_MAX_MICD_RANGE 8 |
37 | 37 | ||
38 | #define ARIZONA_ACCDET_MODE_MIC 0 | 38 | #define ARIZONA_ACCDET_MODE_MIC 0 |
39 | #define ARIZONA_ACCDET_MODE_HPL 1 | 39 | #define ARIZONA_ACCDET_MODE_HPL 1 |
40 | #define ARIZONA_ACCDET_MODE_HPR 2 | 40 | #define ARIZONA_ACCDET_MODE_HPR 2 |
41 | 41 | ||
42 | #define ARIZONA_HPDET_MAX 10000 | ||
43 | |||
44 | #define HPDET_DEBOUNCE 500 | ||
45 | #define DEFAULT_MICD_TIMEOUT 2000 | ||
46 | |||
42 | struct arizona_extcon_info { | 47 | struct arizona_extcon_info { |
43 | struct device *dev; | 48 | struct device *dev; |
44 | struct arizona *arizona; | 49 | struct arizona *arizona; |
@@ -46,17 +51,27 @@ struct arizona_extcon_info { | |||
46 | struct regulator *micvdd; | 51 | struct regulator *micvdd; |
47 | struct input_dev *input; | 52 | struct input_dev *input; |
48 | 53 | ||
54 | u16 last_jackdet; | ||
55 | |||
49 | int micd_mode; | 56 | int micd_mode; |
50 | const struct arizona_micd_config *micd_modes; | 57 | const struct arizona_micd_config *micd_modes; |
51 | int micd_num_modes; | 58 | int micd_num_modes; |
52 | 59 | ||
60 | const struct arizona_micd_range *micd_ranges; | ||
61 | int num_micd_ranges; | ||
62 | |||
63 | int micd_timeout; | ||
64 | |||
53 | bool micd_reva; | 65 | bool micd_reva; |
54 | bool micd_clamp; | 66 | bool micd_clamp; |
55 | 67 | ||
56 | struct delayed_work hpdet_work; | 68 | struct delayed_work hpdet_work; |
69 | struct delayed_work micd_detect_work; | ||
70 | struct delayed_work micd_timeout_work; | ||
57 | 71 | ||
58 | bool hpdet_active; | 72 | bool hpdet_active; |
59 | bool hpdet_done; | 73 | bool hpdet_done; |
74 | bool hpdet_retried; | ||
60 | 75 | ||
61 | int num_hpdet_res; | 76 | int num_hpdet_res; |
62 | unsigned int hpdet_res[3]; | 77 | unsigned int hpdet_res[3]; |
@@ -71,20 +86,25 @@ struct arizona_extcon_info { | |||
71 | }; | 86 | }; |
72 | 87 | ||
73 | static const struct arizona_micd_config micd_default_modes[] = { | 88 | static const struct arizona_micd_config micd_default_modes[] = { |
74 | { 0, 2 << ARIZONA_MICD_BIAS_SRC_SHIFT, 1 }, | ||
75 | { ARIZONA_ACCDET_SRC, 1 << ARIZONA_MICD_BIAS_SRC_SHIFT, 0 }, | 89 | { ARIZONA_ACCDET_SRC, 1 << ARIZONA_MICD_BIAS_SRC_SHIFT, 0 }, |
90 | { 0, 2 << ARIZONA_MICD_BIAS_SRC_SHIFT, 1 }, | ||
76 | }; | 91 | }; |
77 | 92 | ||
78 | static struct { | 93 | static const struct arizona_micd_range micd_default_ranges[] = { |
79 | u16 status; | 94 | { .max = 11, .key = BTN_0 }, |
80 | int report; | 95 | { .max = 28, .key = BTN_1 }, |
81 | } arizona_lvl_to_key[ARIZONA_NUM_BUTTONS] = { | 96 | { .max = 54, .key = BTN_2 }, |
82 | { 0x1, BTN_0 }, | 97 | { .max = 100, .key = BTN_3 }, |
83 | { 0x2, BTN_1 }, | 98 | { .max = 186, .key = BTN_4 }, |
84 | { 0x4, BTN_2 }, | 99 | { .max = 430, .key = BTN_5 }, |
85 | { 0x8, BTN_3 }, | 100 | }; |
86 | { 0x10, BTN_4 }, | 101 | |
87 | { 0x20, BTN_5 }, | 102 | static const int arizona_micd_levels[] = { |
103 | 3, 6, 8, 11, 13, 16, 18, 21, 23, 26, 28, 31, 34, 36, 39, 41, 44, 46, | ||
104 | 49, 52, 54, 57, 60, 62, 65, 67, 70, 73, 75, 78, 81, 83, 89, 94, 100, | ||
105 | 105, 111, 116, 122, 127, 139, 150, 161, 173, 186, 196, 209, 220, 245, | ||
106 | 270, 295, 321, 348, 375, 402, 430, 489, 550, 614, 681, 752, 903, 1071, | ||
107 | 1257, | ||
88 | }; | 108 | }; |
89 | 109 | ||
90 | #define ARIZONA_CABLE_MECHANICAL 0 | 110 | #define ARIZONA_CABLE_MECHANICAL 0 |
@@ -100,6 +120,8 @@ static const char *arizona_cable[] = { | |||
100 | NULL, | 120 | NULL, |
101 | }; | 121 | }; |
102 | 122 | ||
123 | static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info); | ||
124 | |||
103 | static void arizona_extcon_do_magic(struct arizona_extcon_info *info, | 125 | static void arizona_extcon_do_magic(struct arizona_extcon_info *info, |
104 | unsigned int magic) | 126 | unsigned int magic) |
105 | { | 127 | { |
@@ -153,6 +175,8 @@ static void arizona_extcon_set_mode(struct arizona_extcon_info *info, int mode) | |||
153 | { | 175 | { |
154 | struct arizona *arizona = info->arizona; | 176 | struct arizona *arizona = info->arizona; |
155 | 177 | ||
178 | mode %= info->micd_num_modes; | ||
179 | |||
156 | if (arizona->pdata.micd_pol_gpio > 0) | 180 | if (arizona->pdata.micd_pol_gpio > 0) |
157 | gpio_set_value_cansleep(arizona->pdata.micd_pol_gpio, | 181 | gpio_set_value_cansleep(arizona->pdata.micd_pol_gpio, |
158 | info->micd_modes[mode].gpio); | 182 | info->micd_modes[mode].gpio); |
@@ -379,7 +403,7 @@ static int arizona_hpdet_read(struct arizona_extcon_info *info) | |||
379 | /* If we go out of range report top of range */ | 403 | /* If we go out of range report top of range */ |
380 | if (val < 100 || val > 0x3fb) { | 404 | if (val < 100 || val > 0x3fb) { |
381 | dev_dbg(arizona->dev, "Measurement out of range\n"); | 405 | dev_dbg(arizona->dev, "Measurement out of range\n"); |
382 | return 10000; | 406 | return ARIZONA_HPDET_MAX; |
383 | } | 407 | } |
384 | 408 | ||
385 | dev_dbg(arizona->dev, "HPDET read %d in range %d\n", | 409 | dev_dbg(arizona->dev, "HPDET read %d in range %d\n", |
@@ -440,7 +464,8 @@ static int arizona_hpdet_read(struct arizona_extcon_info *info) | |||
440 | return val; | 464 | return val; |
441 | } | 465 | } |
442 | 466 | ||
443 | static int arizona_hpdet_do_id(struct arizona_extcon_info *info, int *reading) | 467 | static int arizona_hpdet_do_id(struct arizona_extcon_info *info, int *reading, |
468 | bool *mic) | ||
444 | { | 469 | { |
445 | struct arizona *arizona = info->arizona; | 470 | struct arizona *arizona = info->arizona; |
446 | int id_gpio = arizona->pdata.hpdet_id_gpio; | 471 | int id_gpio = arizona->pdata.hpdet_id_gpio; |
@@ -452,32 +477,8 @@ static int arizona_hpdet_do_id(struct arizona_extcon_info *info, int *reading) | |||
452 | if (arizona->pdata.hpdet_acc_id) { | 477 | if (arizona->pdata.hpdet_acc_id) { |
453 | info->hpdet_res[info->num_hpdet_res++] = *reading; | 478 | info->hpdet_res[info->num_hpdet_res++] = *reading; |
454 | 479 | ||
455 | /* | ||
456 | * If the impedence is too high don't measure the | ||
457 | * second ground. | ||
458 | */ | ||
459 | if (info->num_hpdet_res == 1 && *reading >= 45) { | ||
460 | dev_dbg(arizona->dev, "Skipping ground flip\n"); | ||
461 | info->hpdet_res[info->num_hpdet_res++] = *reading; | ||
462 | } | ||
463 | |||
464 | if (info->num_hpdet_res == 1) { | ||
465 | dev_dbg(arizona->dev, "Flipping ground\n"); | ||
466 | |||
467 | regmap_update_bits(arizona->regmap, | ||
468 | ARIZONA_ACCESSORY_DETECT_MODE_1, | ||
469 | ARIZONA_ACCDET_SRC, | ||
470 | ~info->micd_modes[0].src); | ||
471 | |||
472 | regmap_update_bits(arizona->regmap, | ||
473 | ARIZONA_HEADPHONE_DETECT_1, | ||
474 | ARIZONA_HP_POLL, ARIZONA_HP_POLL); | ||
475 | return -EAGAIN; | ||
476 | } | ||
477 | |||
478 | /* Only check the mic directly if we didn't already ID it */ | 480 | /* Only check the mic directly if we didn't already ID it */ |
479 | if (id_gpio && info->num_hpdet_res == 2 && | 481 | if (id_gpio && info->num_hpdet_res == 1) { |
480 | !((info->hpdet_res[0] > info->hpdet_res[1] * 2))) { | ||
481 | dev_dbg(arizona->dev, "Measuring mic\n"); | 482 | dev_dbg(arizona->dev, "Measuring mic\n"); |
482 | 483 | ||
483 | regmap_update_bits(arizona->regmap, | 484 | regmap_update_bits(arizona->regmap, |
@@ -496,22 +497,28 @@ static int arizona_hpdet_do_id(struct arizona_extcon_info *info, int *reading) | |||
496 | } | 497 | } |
497 | 498 | ||
498 | /* OK, got both. Now, compare... */ | 499 | /* OK, got both. Now, compare... */ |
499 | dev_dbg(arizona->dev, "HPDET measured %d %d %d\n", | 500 | dev_dbg(arizona->dev, "HPDET measured %d %d\n", |
500 | info->hpdet_res[0], info->hpdet_res[1], | 501 | info->hpdet_res[0], info->hpdet_res[1]); |
501 | info->hpdet_res[2]); | ||
502 | |||
503 | 502 | ||
504 | /* Take the headphone impedance for the main report */ | 503 | /* Take the headphone impedance for the main report */ |
505 | *reading = info->hpdet_res[0]; | 504 | *reading = info->hpdet_res[0]; |
506 | 505 | ||
506 | /* Sometimes we get false readings due to slow insert */ | ||
507 | if (*reading >= ARIZONA_HPDET_MAX && !info->hpdet_retried) { | ||
508 | dev_dbg(arizona->dev, "Retrying high impedance\n"); | ||
509 | info->num_hpdet_res = 0; | ||
510 | info->hpdet_retried = true; | ||
511 | arizona_start_hpdet_acc_id(info); | ||
512 | pm_runtime_put(info->dev); | ||
513 | return -EAGAIN; | ||
514 | } | ||
515 | |||
507 | /* | 516 | /* |
508 | * Either the two grounds measure differently or we | 517 | * If we measure the mic as |
509 | * measure the mic as high impedance. | ||
510 | */ | 518 | */ |
511 | if ((info->hpdet_res[0] > info->hpdet_res[1] * 2) || | 519 | if (!id_gpio || info->hpdet_res[1] > 50) { |
512 | (id_gpio && info->hpdet_res[2] > 10)) { | ||
513 | dev_dbg(arizona->dev, "Detected mic\n"); | 520 | dev_dbg(arizona->dev, "Detected mic\n"); |
514 | info->mic = true; | 521 | *mic = true; |
515 | info->detecting = true; | 522 | info->detecting = true; |
516 | } else { | 523 | } else { |
517 | dev_dbg(arizona->dev, "Detected headphone\n"); | 524 | dev_dbg(arizona->dev, "Detected headphone\n"); |
@@ -534,6 +541,7 @@ static irqreturn_t arizona_hpdet_irq(int irq, void *data) | |||
534 | int id_gpio = arizona->pdata.hpdet_id_gpio; | 541 | int id_gpio = arizona->pdata.hpdet_id_gpio; |
535 | int report = ARIZONA_CABLE_HEADPHONE; | 542 | int report = ARIZONA_CABLE_HEADPHONE; |
536 | int ret, reading; | 543 | int ret, reading; |
544 | bool mic = false; | ||
537 | 545 | ||
538 | mutex_lock(&info->lock); | 546 | mutex_lock(&info->lock); |
539 | 547 | ||
@@ -569,7 +577,7 @@ static irqreturn_t arizona_hpdet_irq(int irq, void *data) | |||
569 | ARIZONA_HP_IMPEDANCE_RANGE_MASK | ARIZONA_HP_POLL, | 577 | ARIZONA_HP_IMPEDANCE_RANGE_MASK | ARIZONA_HP_POLL, |
570 | 0); | 578 | 0); |
571 | 579 | ||
572 | ret = arizona_hpdet_do_id(info, &reading); | 580 | ret = arizona_hpdet_do_id(info, &reading, &mic); |
573 | if (ret == -EAGAIN) { | 581 | if (ret == -EAGAIN) { |
574 | goto out; | 582 | goto out; |
575 | } else if (ret < 0) { | 583 | } else if (ret < 0) { |
@@ -599,7 +607,7 @@ done: | |||
599 | ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC); | 607 | ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC); |
600 | 608 | ||
601 | /* If we have a mic then reenable MICDET */ | 609 | /* If we have a mic then reenable MICDET */ |
602 | if (info->mic) | 610 | if (mic || info->mic) |
603 | arizona_start_mic(info); | 611 | arizona_start_mic(info); |
604 | 612 | ||
605 | if (info->hpdet_active) { | 613 | if (info->hpdet_active) { |
@@ -674,6 +682,8 @@ err: | |||
674 | static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info) | 682 | static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info) |
675 | { | 683 | { |
676 | struct arizona *arizona = info->arizona; | 684 | struct arizona *arizona = info->arizona; |
685 | int hp_reading = 32; | ||
686 | bool mic; | ||
677 | int ret; | 687 | int ret; |
678 | 688 | ||
679 | dev_dbg(arizona->dev, "Starting identification via HPDET\n"); | 689 | dev_dbg(arizona->dev, "Starting identification via HPDET\n"); |
@@ -683,8 +693,6 @@ static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info) | |||
683 | 693 | ||
684 | info->hpdet_active = true; | 694 | info->hpdet_active = true; |
685 | 695 | ||
686 | arizona_extcon_pulse_micbias(info); | ||
687 | |||
688 | arizona_extcon_do_magic(info, 0x4000); | 696 | arizona_extcon_do_magic(info, 0x4000); |
689 | 697 | ||
690 | ret = regmap_update_bits(arizona->regmap, | 698 | ret = regmap_update_bits(arizona->regmap, |
@@ -697,12 +705,18 @@ static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info) | |||
697 | goto err; | 705 | goto err; |
698 | } | 706 | } |
699 | 707 | ||
700 | ret = regmap_update_bits(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1, | 708 | if (arizona->pdata.hpdet_acc_id_line) { |
701 | ARIZONA_HP_POLL, ARIZONA_HP_POLL); | 709 | ret = regmap_update_bits(arizona->regmap, |
702 | if (ret != 0) { | 710 | ARIZONA_HEADPHONE_DETECT_1, |
703 | dev_err(arizona->dev, "Can't start HPDETL measurement: %d\n", | 711 | ARIZONA_HP_POLL, ARIZONA_HP_POLL); |
704 | ret); | 712 | if (ret != 0) { |
705 | goto err; | 713 | dev_err(arizona->dev, |
714 | "Can't start HPDETL measurement: %d\n", | ||
715 | ret); | ||
716 | goto err; | ||
717 | } | ||
718 | } else { | ||
719 | arizona_hpdet_do_id(info, &hp_reading, &mic); | ||
706 | } | 720 | } |
707 | 721 | ||
708 | return; | 722 | return; |
@@ -721,28 +735,58 @@ err: | |||
721 | info->hpdet_active = false; | 735 | info->hpdet_active = false; |
722 | } | 736 | } |
723 | 737 | ||
724 | static irqreturn_t arizona_micdet(int irq, void *data) | 738 | static void arizona_micd_timeout_work(struct work_struct *work) |
725 | { | 739 | { |
726 | struct arizona_extcon_info *info = data; | 740 | struct arizona_extcon_info *info = container_of(work, |
741 | struct arizona_extcon_info, | ||
742 | micd_timeout_work.work); | ||
743 | |||
744 | mutex_lock(&info->lock); | ||
745 | |||
746 | dev_dbg(info->arizona->dev, "MICD timed out, reporting HP\n"); | ||
747 | arizona_identify_headphone(info); | ||
748 | |||
749 | info->detecting = false; | ||
750 | |||
751 | arizona_stop_mic(info); | ||
752 | |||
753 | mutex_unlock(&info->lock); | ||
754 | } | ||
755 | |||
756 | static void arizona_micd_detect(struct work_struct *work) | ||
757 | { | ||
758 | struct arizona_extcon_info *info = container_of(work, | ||
759 | struct arizona_extcon_info, | ||
760 | micd_detect_work.work); | ||
727 | struct arizona *arizona = info->arizona; | 761 | struct arizona *arizona = info->arizona; |
728 | unsigned int val, lvl; | 762 | unsigned int val = 0, lvl; |
729 | int ret, i; | 763 | int ret, i, key; |
764 | |||
765 | cancel_delayed_work_sync(&info->micd_timeout_work); | ||
730 | 766 | ||
731 | mutex_lock(&info->lock); | 767 | mutex_lock(&info->lock); |
732 | 768 | ||
733 | ret = regmap_read(arizona->regmap, ARIZONA_MIC_DETECT_3, &val); | 769 | for (i = 0; i < 10 && !(val & 0x7fc); i++) { |
734 | if (ret != 0) { | 770 | ret = regmap_read(arizona->regmap, ARIZONA_MIC_DETECT_3, &val); |
735 | dev_err(arizona->dev, "Failed to read MICDET: %d\n", ret); | 771 | if (ret != 0) { |
736 | mutex_unlock(&info->lock); | 772 | dev_err(arizona->dev, "Failed to read MICDET: %d\n", ret); |
737 | return IRQ_NONE; | 773 | mutex_unlock(&info->lock); |
738 | } | 774 | return; |
775 | } | ||
739 | 776 | ||
740 | dev_dbg(arizona->dev, "MICDET: %x\n", val); | 777 | dev_dbg(arizona->dev, "MICDET: %x\n", val); |
741 | 778 | ||
742 | if (!(val & ARIZONA_MICD_VALID)) { | 779 | if (!(val & ARIZONA_MICD_VALID)) { |
743 | dev_warn(arizona->dev, "Microphone detection state invalid\n"); | 780 | dev_warn(arizona->dev, "Microphone detection state invalid\n"); |
781 | mutex_unlock(&info->lock); | ||
782 | return; | ||
783 | } | ||
784 | } | ||
785 | |||
786 | if (i == 10 && !(val & 0x7fc)) { | ||
787 | dev_err(arizona->dev, "Failed to get valid MICDET value\n"); | ||
744 | mutex_unlock(&info->lock); | 788 | mutex_unlock(&info->lock); |
745 | return IRQ_NONE; | 789 | return; |
746 | } | 790 | } |
747 | 791 | ||
748 | /* Due to jack detect this should never happen */ | 792 | /* Due to jack detect this should never happen */ |
@@ -783,7 +827,7 @@ static irqreturn_t arizona_micdet(int irq, void *data) | |||
783 | * impedence then give up and report headphones. | 827 | * impedence then give up and report headphones. |
784 | */ | 828 | */ |
785 | if (info->detecting && (val & 0x3f8)) { | 829 | if (info->detecting && (val & 0x3f8)) { |
786 | if (info->jack_flips >= info->micd_num_modes) { | 830 | if (info->jack_flips >= info->micd_num_modes * 10) { |
787 | dev_dbg(arizona->dev, "Detected HP/line\n"); | 831 | dev_dbg(arizona->dev, "Detected HP/line\n"); |
788 | arizona_identify_headphone(info); | 832 | arizona_identify_headphone(info); |
789 | 833 | ||
@@ -813,12 +857,17 @@ static irqreturn_t arizona_micdet(int irq, void *data) | |||
813 | lvl = val & ARIZONA_MICD_LVL_MASK; | 857 | lvl = val & ARIZONA_MICD_LVL_MASK; |
814 | lvl >>= ARIZONA_MICD_LVL_SHIFT; | 858 | lvl >>= ARIZONA_MICD_LVL_SHIFT; |
815 | 859 | ||
816 | for (i = 0; i < ARIZONA_NUM_BUTTONS; i++) | 860 | for (i = 0; i < info->num_micd_ranges; i++) |
817 | if (lvl & arizona_lvl_to_key[i].status) | 861 | input_report_key(info->input, |
818 | input_report_key(info->input, | 862 | info->micd_ranges[i].key, 0); |
819 | arizona_lvl_to_key[i].report, | 863 | |
820 | 1); | 864 | WARN_ON(!lvl); |
821 | input_sync(info->input); | 865 | WARN_ON(ffs(lvl) - 1 >= info->num_micd_ranges); |
866 | if (lvl && ffs(lvl) - 1 < info->num_micd_ranges) { | ||
867 | key = info->micd_ranges[ffs(lvl) - 1].key; | ||
868 | input_report_key(info->input, key, 1); | ||
869 | input_sync(info->input); | ||
870 | } | ||
822 | 871 | ||
823 | } else if (info->detecting) { | 872 | } else if (info->detecting) { |
824 | dev_dbg(arizona->dev, "Headphone detected\n"); | 873 | dev_dbg(arizona->dev, "Headphone detected\n"); |
@@ -832,16 +881,41 @@ static irqreturn_t arizona_micdet(int irq, void *data) | |||
832 | } | 881 | } |
833 | } else { | 882 | } else { |
834 | dev_dbg(arizona->dev, "Mic button released\n"); | 883 | dev_dbg(arizona->dev, "Mic button released\n"); |
835 | for (i = 0; i < ARIZONA_NUM_BUTTONS; i++) | 884 | for (i = 0; i < info->num_micd_ranges; i++) |
836 | input_report_key(info->input, | 885 | input_report_key(info->input, |
837 | arizona_lvl_to_key[i].report, 0); | 886 | info->micd_ranges[i].key, 0); |
838 | input_sync(info->input); | 887 | input_sync(info->input); |
839 | arizona_extcon_pulse_micbias(info); | 888 | arizona_extcon_pulse_micbias(info); |
840 | } | 889 | } |
841 | 890 | ||
842 | handled: | 891 | handled: |
892 | if (info->detecting) | ||
893 | schedule_delayed_work(&info->micd_timeout_work, | ||
894 | msecs_to_jiffies(info->micd_timeout)); | ||
895 | |||
843 | pm_runtime_mark_last_busy(info->dev); | 896 | pm_runtime_mark_last_busy(info->dev); |
844 | mutex_unlock(&info->lock); | 897 | mutex_unlock(&info->lock); |
898 | } | ||
899 | |||
900 | static irqreturn_t arizona_micdet(int irq, void *data) | ||
901 | { | ||
902 | struct arizona_extcon_info *info = data; | ||
903 | struct arizona *arizona = info->arizona; | ||
904 | int debounce = arizona->pdata.micd_detect_debounce; | ||
905 | |||
906 | cancel_delayed_work_sync(&info->micd_detect_work); | ||
907 | cancel_delayed_work_sync(&info->micd_timeout_work); | ||
908 | |||
909 | mutex_lock(&info->lock); | ||
910 | if (!info->detecting) | ||
911 | debounce = 0; | ||
912 | mutex_unlock(&info->lock); | ||
913 | |||
914 | if (debounce) | ||
915 | schedule_delayed_work(&info->micd_detect_work, | ||
916 | msecs_to_jiffies(debounce)); | ||
917 | else | ||
918 | arizona_micd_detect(&info->micd_detect_work.work); | ||
845 | 919 | ||
846 | return IRQ_HANDLED; | 920 | return IRQ_HANDLED; |
847 | } | 921 | } |
@@ -862,11 +936,13 @@ static irqreturn_t arizona_jackdet(int irq, void *data) | |||
862 | struct arizona_extcon_info *info = data; | 936 | struct arizona_extcon_info *info = data; |
863 | struct arizona *arizona = info->arizona; | 937 | struct arizona *arizona = info->arizona; |
864 | unsigned int val, present, mask; | 938 | unsigned int val, present, mask; |
939 | bool cancelled_hp, cancelled_mic; | ||
865 | int ret, i; | 940 | int ret, i; |
866 | 941 | ||
867 | pm_runtime_get_sync(info->dev); | 942 | cancelled_hp = cancel_delayed_work_sync(&info->hpdet_work); |
943 | cancelled_mic = cancel_delayed_work_sync(&info->micd_timeout_work); | ||
868 | 944 | ||
869 | cancel_delayed_work_sync(&info->hpdet_work); | 945 | pm_runtime_get_sync(info->dev); |
870 | 946 | ||
871 | mutex_lock(&info->lock); | 947 | mutex_lock(&info->lock); |
872 | 948 | ||
@@ -887,7 +963,22 @@ static irqreturn_t arizona_jackdet(int irq, void *data) | |||
887 | return IRQ_NONE; | 963 | return IRQ_NONE; |
888 | } | 964 | } |
889 | 965 | ||
890 | if ((val & mask) == present) { | 966 | val &= mask; |
967 | if (val == info->last_jackdet) { | ||
968 | dev_dbg(arizona->dev, "Suppressing duplicate JACKDET\n"); | ||
969 | if (cancelled_hp) | ||
970 | schedule_delayed_work(&info->hpdet_work, | ||
971 | msecs_to_jiffies(HPDET_DEBOUNCE)); | ||
972 | |||
973 | if (cancelled_mic) | ||
974 | schedule_delayed_work(&info->micd_timeout_work, | ||
975 | msecs_to_jiffies(info->micd_timeout)); | ||
976 | |||
977 | goto out; | ||
978 | } | ||
979 | info->last_jackdet = val; | ||
980 | |||
981 | if (info->last_jackdet == present) { | ||
891 | dev_dbg(arizona->dev, "Detected jack\n"); | 982 | dev_dbg(arizona->dev, "Detected jack\n"); |
892 | ret = extcon_set_cable_state_(&info->edev, | 983 | ret = extcon_set_cable_state_(&info->edev, |
893 | ARIZONA_CABLE_MECHANICAL, true); | 984 | ARIZONA_CABLE_MECHANICAL, true); |
@@ -904,7 +995,7 @@ static irqreturn_t arizona_jackdet(int irq, void *data) | |||
904 | arizona_start_mic(info); | 995 | arizona_start_mic(info); |
905 | } else { | 996 | } else { |
906 | schedule_delayed_work(&info->hpdet_work, | 997 | schedule_delayed_work(&info->hpdet_work, |
907 | msecs_to_jiffies(250)); | 998 | msecs_to_jiffies(HPDET_DEBOUNCE)); |
908 | } | 999 | } |
909 | 1000 | ||
910 | regmap_update_bits(arizona->regmap, | 1001 | regmap_update_bits(arizona->regmap, |
@@ -920,10 +1011,11 @@ static irqreturn_t arizona_jackdet(int irq, void *data) | |||
920 | info->hpdet_res[i] = 0; | 1011 | info->hpdet_res[i] = 0; |
921 | info->mic = false; | 1012 | info->mic = false; |
922 | info->hpdet_done = false; | 1013 | info->hpdet_done = false; |
1014 | info->hpdet_retried = false; | ||
923 | 1015 | ||
924 | for (i = 0; i < ARIZONA_NUM_BUTTONS; i++) | 1016 | for (i = 0; i < info->num_micd_ranges; i++) |
925 | input_report_key(info->input, | 1017 | input_report_key(info->input, |
926 | arizona_lvl_to_key[i].report, 0); | 1018 | info->micd_ranges[i].key, 0); |
927 | input_sync(info->input); | 1019 | input_sync(info->input); |
928 | 1020 | ||
929 | ret = extcon_update_state(&info->edev, 0xffffffff, 0); | 1021 | ret = extcon_update_state(&info->edev, 0xffffffff, 0); |
@@ -937,6 +1029,11 @@ static irqreturn_t arizona_jackdet(int irq, void *data) | |||
937 | ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB); | 1029 | ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB); |
938 | } | 1030 | } |
939 | 1031 | ||
1032 | if (arizona->pdata.micd_timeout) | ||
1033 | info->micd_timeout = arizona->pdata.micd_timeout; | ||
1034 | else | ||
1035 | info->micd_timeout = DEFAULT_MICD_TIMEOUT; | ||
1036 | |||
940 | /* Clear trig_sts to make sure DCVDD is not forced up */ | 1037 | /* Clear trig_sts to make sure DCVDD is not forced up */ |
941 | regmap_write(arizona->regmap, ARIZONA_AOD_WKUP_AND_TRIG, | 1038 | regmap_write(arizona->regmap, ARIZONA_AOD_WKUP_AND_TRIG, |
942 | ARIZONA_MICD_CLAMP_FALL_TRIG_STS | | 1039 | ARIZONA_MICD_CLAMP_FALL_TRIG_STS | |
@@ -944,6 +1041,7 @@ static irqreturn_t arizona_jackdet(int irq, void *data) | |||
944 | ARIZONA_JD1_FALL_TRIG_STS | | 1041 | ARIZONA_JD1_FALL_TRIG_STS | |
945 | ARIZONA_JD1_RISE_TRIG_STS); | 1042 | ARIZONA_JD1_RISE_TRIG_STS); |
946 | 1043 | ||
1044 | out: | ||
947 | mutex_unlock(&info->lock); | 1045 | mutex_unlock(&info->lock); |
948 | 1046 | ||
949 | pm_runtime_mark_last_busy(info->dev); | 1047 | pm_runtime_mark_last_busy(info->dev); |
@@ -952,13 +1050,34 @@ static irqreturn_t arizona_jackdet(int irq, void *data) | |||
952 | return IRQ_HANDLED; | 1050 | return IRQ_HANDLED; |
953 | } | 1051 | } |
954 | 1052 | ||
1053 | /* Map a level onto a slot in the register bank */ | ||
1054 | static void arizona_micd_set_level(struct arizona *arizona, int index, | ||
1055 | unsigned int level) | ||
1056 | { | ||
1057 | int reg; | ||
1058 | unsigned int mask; | ||
1059 | |||
1060 | reg = ARIZONA_MIC_DETECT_LEVEL_4 - (index / 2); | ||
1061 | |||
1062 | if (!(index % 2)) { | ||
1063 | mask = 0x3f00; | ||
1064 | level <<= 8; | ||
1065 | } else { | ||
1066 | mask = 0x3f; | ||
1067 | } | ||
1068 | |||
1069 | /* Program the level itself */ | ||
1070 | regmap_update_bits(arizona->regmap, reg, mask, level); | ||
1071 | } | ||
1072 | |||
955 | static int arizona_extcon_probe(struct platform_device *pdev) | 1073 | static int arizona_extcon_probe(struct platform_device *pdev) |
956 | { | 1074 | { |
957 | struct arizona *arizona = dev_get_drvdata(pdev->dev.parent); | 1075 | struct arizona *arizona = dev_get_drvdata(pdev->dev.parent); |
958 | struct arizona_pdata *pdata; | 1076 | struct arizona_pdata *pdata; |
959 | struct arizona_extcon_info *info; | 1077 | struct arizona_extcon_info *info; |
1078 | unsigned int val; | ||
960 | int jack_irq_fall, jack_irq_rise; | 1079 | int jack_irq_fall, jack_irq_rise; |
961 | int ret, mode, i; | 1080 | int ret, mode, i, j; |
962 | 1081 | ||
963 | if (!arizona->dapm || !arizona->dapm->card) | 1082 | if (!arizona->dapm || !arizona->dapm->card) |
964 | return -EPROBE_DEFER; | 1083 | return -EPROBE_DEFER; |
@@ -982,7 +1101,10 @@ static int arizona_extcon_probe(struct platform_device *pdev) | |||
982 | mutex_init(&info->lock); | 1101 | mutex_init(&info->lock); |
983 | info->arizona = arizona; | 1102 | info->arizona = arizona; |
984 | info->dev = &pdev->dev; | 1103 | info->dev = &pdev->dev; |
1104 | info->last_jackdet = ~(ARIZONA_MICD_CLAMP_STS | ARIZONA_JD1_STS); | ||
985 | INIT_DELAYED_WORK(&info->hpdet_work, arizona_hpdet_work); | 1105 | INIT_DELAYED_WORK(&info->hpdet_work, arizona_hpdet_work); |
1106 | INIT_DELAYED_WORK(&info->micd_detect_work, arizona_micd_detect); | ||
1107 | INIT_DELAYED_WORK(&info->micd_timeout_work, arizona_micd_timeout_work); | ||
986 | platform_set_drvdata(pdev, info); | 1108 | platform_set_drvdata(pdev, info); |
987 | 1109 | ||
988 | switch (arizona->type) { | 1110 | switch (arizona->type) { |
@@ -1011,6 +1133,17 @@ static int arizona_extcon_probe(struct platform_device *pdev) | |||
1011 | goto err; | 1133 | goto err; |
1012 | } | 1134 | } |
1013 | 1135 | ||
1136 | info->input = devm_input_allocate_device(&pdev->dev); | ||
1137 | if (!info->input) { | ||
1138 | dev_err(arizona->dev, "Can't allocate input dev\n"); | ||
1139 | ret = -ENOMEM; | ||
1140 | goto err_register; | ||
1141 | } | ||
1142 | |||
1143 | info->input->name = "Headset"; | ||
1144 | info->input->phys = "arizona/extcon"; | ||
1145 | info->input->dev.parent = &pdev->dev; | ||
1146 | |||
1014 | if (pdata->num_micd_configs) { | 1147 | if (pdata->num_micd_configs) { |
1015 | info->micd_modes = pdata->micd_configs; | 1148 | info->micd_modes = pdata->micd_configs; |
1016 | info->micd_num_modes = pdata->num_micd_configs; | 1149 | info->micd_num_modes = pdata->num_micd_configs; |
@@ -1066,15 +1199,79 @@ static int arizona_extcon_probe(struct platform_device *pdev) | |||
1066 | arizona->pdata.micd_dbtime | 1199 | arizona->pdata.micd_dbtime |
1067 | << ARIZONA_MICD_DBTIME_SHIFT); | 1200 | << ARIZONA_MICD_DBTIME_SHIFT); |
1068 | 1201 | ||
1202 | BUILD_BUG_ON(ARRAY_SIZE(arizona_micd_levels) != 0x40); | ||
1203 | |||
1204 | if (arizona->pdata.num_micd_ranges) { | ||
1205 | info->micd_ranges = pdata->micd_ranges; | ||
1206 | info->num_micd_ranges = pdata->num_micd_ranges; | ||
1207 | } else { | ||
1208 | info->micd_ranges = micd_default_ranges; | ||
1209 | info->num_micd_ranges = ARRAY_SIZE(micd_default_ranges); | ||
1210 | } | ||
1211 | |||
1212 | if (arizona->pdata.num_micd_ranges > ARIZONA_MAX_MICD_RANGE) { | ||
1213 | dev_err(arizona->dev, "Too many MICD ranges: %d\n", | ||
1214 | arizona->pdata.num_micd_ranges); | ||
1215 | } | ||
1216 | |||
1217 | if (info->num_micd_ranges > 1) { | ||
1218 | for (i = 1; i < info->num_micd_ranges; i++) { | ||
1219 | if (info->micd_ranges[i - 1].max > | ||
1220 | info->micd_ranges[i].max) { | ||
1221 | dev_err(arizona->dev, | ||
1222 | "MICD ranges must be sorted\n"); | ||
1223 | ret = -EINVAL; | ||
1224 | goto err_input; | ||
1225 | } | ||
1226 | } | ||
1227 | } | ||
1228 | |||
1229 | /* Disable all buttons by default */ | ||
1230 | regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_2, | ||
1231 | ARIZONA_MICD_LVL_SEL_MASK, 0x81); | ||
1232 | |||
1233 | /* Set up all the buttons the user specified */ | ||
1234 | for (i = 0; i < info->num_micd_ranges; i++) { | ||
1235 | for (j = 0; j < ARRAY_SIZE(arizona_micd_levels); j++) | ||
1236 | if (arizona_micd_levels[j] >= info->micd_ranges[i].max) | ||
1237 | break; | ||
1238 | |||
1239 | if (j == ARRAY_SIZE(arizona_micd_levels)) { | ||
1240 | dev_err(arizona->dev, "Unsupported MICD level %d\n", | ||
1241 | info->micd_ranges[i].max); | ||
1242 | ret = -EINVAL; | ||
1243 | goto err_input; | ||
1244 | } | ||
1245 | |||
1246 | dev_dbg(arizona->dev, "%d ohms for MICD threshold %d\n", | ||
1247 | arizona_micd_levels[j], i); | ||
1248 | |||
1249 | arizona_micd_set_level(arizona, i, j); | ||
1250 | input_set_capability(info->input, EV_KEY, | ||
1251 | info->micd_ranges[i].key); | ||
1252 | |||
1253 | /* Enable reporting of that range */ | ||
1254 | regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_2, | ||
1255 | 1 << i, 1 << i); | ||
1256 | } | ||
1257 | |||
1258 | /* Set all the remaining keys to a maximum */ | ||
1259 | for (; i < ARIZONA_MAX_MICD_RANGE; i++) | ||
1260 | arizona_micd_set_level(arizona, i, 0x3f); | ||
1261 | |||
1069 | /* | 1262 | /* |
1070 | * If we have a clamp use it, activating in conjunction with | 1263 | * If we have a clamp use it, activating in conjunction with |
1071 | * GPIO5 if that is connected for jack detect operation. | 1264 | * GPIO5 if that is connected for jack detect operation. |
1072 | */ | 1265 | */ |
1073 | if (info->micd_clamp) { | 1266 | if (info->micd_clamp) { |
1074 | if (arizona->pdata.jd_gpio5) { | 1267 | if (arizona->pdata.jd_gpio5) { |
1075 | /* Put the GPIO into input mode */ | 1268 | /* Put the GPIO into input mode with optional pull */ |
1269 | val = 0xc101; | ||
1270 | if (arizona->pdata.jd_gpio5_nopull) | ||
1271 | val &= ~ARIZONA_GPN_PU; | ||
1272 | |||
1076 | regmap_write(arizona->regmap, ARIZONA_GPIO5_CTRL, | 1273 | regmap_write(arizona->regmap, ARIZONA_GPIO5_CTRL, |
1077 | 0xc101); | 1274 | val); |
1078 | 1275 | ||
1079 | regmap_update_bits(arizona->regmap, | 1276 | regmap_update_bits(arizona->regmap, |
1080 | ARIZONA_MICD_CLAMP_CONTROL, | 1277 | ARIZONA_MICD_CLAMP_CONTROL, |
@@ -1093,20 +1290,6 @@ static int arizona_extcon_probe(struct platform_device *pdev) | |||
1093 | 1290 | ||
1094 | arizona_extcon_set_mode(info, 0); | 1291 | arizona_extcon_set_mode(info, 0); |
1095 | 1292 | ||
1096 | info->input = devm_input_allocate_device(&pdev->dev); | ||
1097 | if (!info->input) { | ||
1098 | dev_err(arizona->dev, "Can't allocate input dev\n"); | ||
1099 | ret = -ENOMEM; | ||
1100 | goto err_register; | ||
1101 | } | ||
1102 | |||
1103 | for (i = 0; i < ARIZONA_NUM_BUTTONS; i++) | ||
1104 | input_set_capability(info->input, EV_KEY, | ||
1105 | arizona_lvl_to_key[i].report); | ||
1106 | info->input->name = "Headset"; | ||
1107 | info->input->phys = "arizona/extcon"; | ||
1108 | info->input->dev.parent = &pdev->dev; | ||
1109 | |||
1110 | pm_runtime_enable(&pdev->dev); | 1293 | pm_runtime_enable(&pdev->dev); |
1111 | pm_runtime_idle(&pdev->dev); | 1294 | pm_runtime_idle(&pdev->dev); |
1112 | pm_runtime_get_sync(&pdev->dev); | 1295 | pm_runtime_get_sync(&pdev->dev); |