diff options
Diffstat (limited to 'drivers/extcon/extcon-arizona.c')
-rw-r--r-- | drivers/extcon/extcon-arizona.c | 498 |
1 files changed, 339 insertions, 159 deletions
diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c index dc357a4051f6..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,10 +120,63 @@ 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 | |||
125 | static void arizona_extcon_do_magic(struct arizona_extcon_info *info, | ||
126 | unsigned int magic) | ||
127 | { | ||
128 | struct arizona *arizona = info->arizona; | ||
129 | int ret; | ||
130 | |||
131 | mutex_lock(&arizona->dapm->card->dapm_mutex); | ||
132 | |||
133 | arizona->hpdet_magic = magic; | ||
134 | |||
135 | /* Keep the HP output stages disabled while doing the magic */ | ||
136 | if (magic) { | ||
137 | ret = regmap_update_bits(arizona->regmap, | ||
138 | ARIZONA_OUTPUT_ENABLES_1, | ||
139 | ARIZONA_OUT1L_ENA | | ||
140 | ARIZONA_OUT1R_ENA, 0); | ||
141 | if (ret != 0) | ||
142 | dev_warn(arizona->dev, | ||
143 | "Failed to disable headphone outputs: %d\n", | ||
144 | ret); | ||
145 | } | ||
146 | |||
147 | ret = regmap_update_bits(arizona->regmap, 0x225, 0x4000, | ||
148 | magic); | ||
149 | if (ret != 0) | ||
150 | dev_warn(arizona->dev, "Failed to do magic: %d\n", | ||
151 | ret); | ||
152 | |||
153 | ret = regmap_update_bits(arizona->regmap, 0x226, 0x4000, | ||
154 | magic); | ||
155 | if (ret != 0) | ||
156 | dev_warn(arizona->dev, "Failed to do magic: %d\n", | ||
157 | ret); | ||
158 | |||
159 | /* Restore the desired state while not doing the magic */ | ||
160 | if (!magic) { | ||
161 | ret = regmap_update_bits(arizona->regmap, | ||
162 | ARIZONA_OUTPUT_ENABLES_1, | ||
163 | ARIZONA_OUT1L_ENA | | ||
164 | ARIZONA_OUT1R_ENA, arizona->hp_ena); | ||
165 | if (ret != 0) | ||
166 | dev_warn(arizona->dev, | ||
167 | "Failed to restore headphone outputs: %d\n", | ||
168 | ret); | ||
169 | } | ||
170 | |||
171 | mutex_unlock(&arizona->dapm->card->dapm_mutex); | ||
172 | } | ||
173 | |||
103 | static void arizona_extcon_set_mode(struct arizona_extcon_info *info, int mode) | 174 | static void arizona_extcon_set_mode(struct arizona_extcon_info *info, int mode) |
104 | { | 175 | { |
105 | struct arizona *arizona = info->arizona; | 176 | struct arizona *arizona = info->arizona; |
106 | 177 | ||
178 | mode %= info->micd_num_modes; | ||
179 | |||
107 | if (arizona->pdata.micd_pol_gpio > 0) | 180 | if (arizona->pdata.micd_pol_gpio > 0) |
108 | gpio_set_value_cansleep(arizona->pdata.micd_pol_gpio, | 181 | gpio_set_value_cansleep(arizona->pdata.micd_pol_gpio, |
109 | info->micd_modes[mode].gpio); | 182 | info->micd_modes[mode].gpio); |
@@ -330,7 +403,7 @@ static int arizona_hpdet_read(struct arizona_extcon_info *info) | |||
330 | /* If we go out of range report top of range */ | 403 | /* If we go out of range report top of range */ |
331 | if (val < 100 || val > 0x3fb) { | 404 | if (val < 100 || val > 0x3fb) { |
332 | dev_dbg(arizona->dev, "Measurement out of range\n"); | 405 | dev_dbg(arizona->dev, "Measurement out of range\n"); |
333 | return 10000; | 406 | return ARIZONA_HPDET_MAX; |
334 | } | 407 | } |
335 | 408 | ||
336 | dev_dbg(arizona->dev, "HPDET read %d in range %d\n", | 409 | dev_dbg(arizona->dev, "HPDET read %d in range %d\n", |
@@ -391,7 +464,8 @@ static int arizona_hpdet_read(struct arizona_extcon_info *info) | |||
391 | return val; | 464 | return val; |
392 | } | 465 | } |
393 | 466 | ||
394 | 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) | ||
395 | { | 469 | { |
396 | struct arizona *arizona = info->arizona; | 470 | struct arizona *arizona = info->arizona; |
397 | int id_gpio = arizona->pdata.hpdet_id_gpio; | 471 | int id_gpio = arizona->pdata.hpdet_id_gpio; |
@@ -403,32 +477,8 @@ static int arizona_hpdet_do_id(struct arizona_extcon_info *info, int *reading) | |||
403 | if (arizona->pdata.hpdet_acc_id) { | 477 | if (arizona->pdata.hpdet_acc_id) { |
404 | info->hpdet_res[info->num_hpdet_res++] = *reading; | 478 | info->hpdet_res[info->num_hpdet_res++] = *reading; |
405 | 479 | ||
406 | /* | ||
407 | * If the impedence is too high don't measure the | ||
408 | * second ground. | ||
409 | */ | ||
410 | if (info->num_hpdet_res == 1 && *reading >= 45) { | ||
411 | dev_dbg(arizona->dev, "Skipping ground flip\n"); | ||
412 | info->hpdet_res[info->num_hpdet_res++] = *reading; | ||
413 | } | ||
414 | |||
415 | if (info->num_hpdet_res == 1) { | ||
416 | dev_dbg(arizona->dev, "Flipping ground\n"); | ||
417 | |||
418 | regmap_update_bits(arizona->regmap, | ||
419 | ARIZONA_ACCESSORY_DETECT_MODE_1, | ||
420 | ARIZONA_ACCDET_SRC, | ||
421 | ~info->micd_modes[0].src); | ||
422 | |||
423 | regmap_update_bits(arizona->regmap, | ||
424 | ARIZONA_HEADPHONE_DETECT_1, | ||
425 | ARIZONA_HP_POLL, ARIZONA_HP_POLL); | ||
426 | return -EAGAIN; | ||
427 | } | ||
428 | |||
429 | /* 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 */ |
430 | if (id_gpio && info->num_hpdet_res == 2 && | 481 | if (id_gpio && info->num_hpdet_res == 1) { |
431 | !((info->hpdet_res[0] > info->hpdet_res[1] * 2))) { | ||
432 | dev_dbg(arizona->dev, "Measuring mic\n"); | 482 | dev_dbg(arizona->dev, "Measuring mic\n"); |
433 | 483 | ||
434 | regmap_update_bits(arizona->regmap, | 484 | regmap_update_bits(arizona->regmap, |
@@ -447,22 +497,28 @@ static int arizona_hpdet_do_id(struct arizona_extcon_info *info, int *reading) | |||
447 | } | 497 | } |
448 | 498 | ||
449 | /* OK, got both. Now, compare... */ | 499 | /* OK, got both. Now, compare... */ |
450 | dev_dbg(arizona->dev, "HPDET measured %d %d %d\n", | 500 | dev_dbg(arizona->dev, "HPDET measured %d %d\n", |
451 | info->hpdet_res[0], info->hpdet_res[1], | 501 | info->hpdet_res[0], info->hpdet_res[1]); |
452 | info->hpdet_res[2]); | ||
453 | |||
454 | 502 | ||
455 | /* Take the headphone impedance for the main report */ | 503 | /* Take the headphone impedance for the main report */ |
456 | *reading = info->hpdet_res[0]; | 504 | *reading = info->hpdet_res[0]; |
457 | 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 | |||
458 | /* | 516 | /* |
459 | * Either the two grounds measure differently or we | 517 | * If we measure the mic as |
460 | * measure the mic as high impedance. | ||
461 | */ | 518 | */ |
462 | if ((info->hpdet_res[0] > info->hpdet_res[1] * 2) || | 519 | if (!id_gpio || info->hpdet_res[1] > 50) { |
463 | (id_gpio && info->hpdet_res[2] > 10)) { | ||
464 | dev_dbg(arizona->dev, "Detected mic\n"); | 520 | dev_dbg(arizona->dev, "Detected mic\n"); |
465 | info->mic = true; | 521 | *mic = true; |
466 | info->detecting = true; | 522 | info->detecting = true; |
467 | } else { | 523 | } else { |
468 | dev_dbg(arizona->dev, "Detected headphone\n"); | 524 | dev_dbg(arizona->dev, "Detected headphone\n"); |
@@ -484,8 +540,8 @@ static irqreturn_t arizona_hpdet_irq(int irq, void *data) | |||
484 | struct arizona *arizona = info->arizona; | 540 | struct arizona *arizona = info->arizona; |
485 | int id_gpio = arizona->pdata.hpdet_id_gpio; | 541 | int id_gpio = arizona->pdata.hpdet_id_gpio; |
486 | int report = ARIZONA_CABLE_HEADPHONE; | 542 | int report = ARIZONA_CABLE_HEADPHONE; |
487 | unsigned int val; | ||
488 | int ret, reading; | 543 | int ret, reading; |
544 | bool mic = false; | ||
489 | 545 | ||
490 | mutex_lock(&info->lock); | 546 | mutex_lock(&info->lock); |
491 | 547 | ||
@@ -521,7 +577,7 @@ static irqreturn_t arizona_hpdet_irq(int irq, void *data) | |||
521 | ARIZONA_HP_IMPEDANCE_RANGE_MASK | ARIZONA_HP_POLL, | 577 | ARIZONA_HP_IMPEDANCE_RANGE_MASK | ARIZONA_HP_POLL, |
522 | 0); | 578 | 0); |
523 | 579 | ||
524 | ret = arizona_hpdet_do_id(info, &reading); | 580 | ret = arizona_hpdet_do_id(info, &reading, &mic); |
525 | if (ret == -EAGAIN) { | 581 | if (ret == -EAGAIN) { |
526 | goto out; | 582 | goto out; |
527 | } else if (ret < 0) { | 583 | } else if (ret < 0) { |
@@ -539,28 +595,7 @@ static irqreturn_t arizona_hpdet_irq(int irq, void *data) | |||
539 | dev_err(arizona->dev, "Failed to report HP/line: %d\n", | 595 | dev_err(arizona->dev, "Failed to report HP/line: %d\n", |
540 | ret); | 596 | ret); |
541 | 597 | ||
542 | mutex_lock(&arizona->dapm->card->dapm_mutex); | 598 | arizona_extcon_do_magic(info, 0); |
543 | |||
544 | ret = regmap_read(arizona->regmap, ARIZONA_OUTPUT_ENABLES_1, &val); | ||
545 | if (ret != 0) { | ||
546 | dev_err(arizona->dev, "Failed to read output enables: %d\n", | ||
547 | ret); | ||
548 | val = 0; | ||
549 | } | ||
550 | |||
551 | if (!(val & (ARIZONA_OUT1L_ENA | ARIZONA_OUT1R_ENA))) { | ||
552 | ret = regmap_update_bits(arizona->regmap, 0x225, 0x4000, 0); | ||
553 | if (ret != 0) | ||
554 | dev_warn(arizona->dev, "Failed to undo magic: %d\n", | ||
555 | ret); | ||
556 | |||
557 | ret = regmap_update_bits(arizona->regmap, 0x226, 0x4000, 0); | ||
558 | if (ret != 0) | ||
559 | dev_warn(arizona->dev, "Failed to undo magic: %d\n", | ||
560 | ret); | ||
561 | } | ||
562 | |||
563 | mutex_unlock(&arizona->dapm->card->dapm_mutex); | ||
564 | 599 | ||
565 | done: | 600 | done: |
566 | if (id_gpio) | 601 | if (id_gpio) |
@@ -572,7 +607,7 @@ done: | |||
572 | ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC); | 607 | ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC); |
573 | 608 | ||
574 | /* If we have a mic then reenable MICDET */ | 609 | /* If we have a mic then reenable MICDET */ |
575 | if (info->mic) | 610 | if (mic || info->mic) |
576 | arizona_start_mic(info); | 611 | arizona_start_mic(info); |
577 | 612 | ||
578 | if (info->hpdet_active) { | 613 | if (info->hpdet_active) { |
@@ -606,13 +641,7 @@ static void arizona_identify_headphone(struct arizona_extcon_info *info) | |||
606 | if (info->mic) | 641 | if (info->mic) |
607 | arizona_stop_mic(info); | 642 | arizona_stop_mic(info); |
608 | 643 | ||
609 | ret = regmap_update_bits(arizona->regmap, 0x225, 0x4000, 0x4000); | 644 | arizona_extcon_do_magic(info, 0x4000); |
610 | if (ret != 0) | ||
611 | dev_warn(arizona->dev, "Failed to do magic: %d\n", ret); | ||
612 | |||
613 | ret = regmap_update_bits(arizona->regmap, 0x226, 0x4000, 0x4000); | ||
614 | if (ret != 0) | ||
615 | dev_warn(arizona->dev, "Failed to do magic: %d\n", ret); | ||
616 | 645 | ||
617 | ret = regmap_update_bits(arizona->regmap, | 646 | ret = regmap_update_bits(arizona->regmap, |
618 | ARIZONA_ACCESSORY_DETECT_MODE_1, | 647 | ARIZONA_ACCESSORY_DETECT_MODE_1, |
@@ -653,7 +682,8 @@ err: | |||
653 | 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) |
654 | { | 683 | { |
655 | struct arizona *arizona = info->arizona; | 684 | struct arizona *arizona = info->arizona; |
656 | unsigned int val; | 685 | int hp_reading = 32; |
686 | bool mic; | ||
657 | int ret; | 687 | int ret; |
658 | 688 | ||
659 | dev_dbg(arizona->dev, "Starting identification via HPDET\n"); | 689 | dev_dbg(arizona->dev, "Starting identification via HPDET\n"); |
@@ -663,32 +693,7 @@ static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info) | |||
663 | 693 | ||
664 | info->hpdet_active = true; | 694 | info->hpdet_active = true; |
665 | 695 | ||
666 | arizona_extcon_pulse_micbias(info); | 696 | arizona_extcon_do_magic(info, 0x4000); |
667 | |||
668 | mutex_lock(&arizona->dapm->card->dapm_mutex); | ||
669 | |||
670 | ret = regmap_read(arizona->regmap, ARIZONA_OUTPUT_ENABLES_1, &val); | ||
671 | if (ret != 0) { | ||
672 | dev_err(arizona->dev, "Failed to read output enables: %d\n", | ||
673 | ret); | ||
674 | val = 0; | ||
675 | } | ||
676 | |||
677 | if (!(val & (ARIZONA_OUT1L_ENA | ARIZONA_OUT1R_ENA))) { | ||
678 | ret = regmap_update_bits(arizona->regmap, 0x225, 0x4000, | ||
679 | 0x4000); | ||
680 | if (ret != 0) | ||
681 | dev_warn(arizona->dev, "Failed to do magic: %d\n", | ||
682 | ret); | ||
683 | |||
684 | ret = regmap_update_bits(arizona->regmap, 0x226, 0x4000, | ||
685 | 0x4000); | ||
686 | if (ret != 0) | ||
687 | dev_warn(arizona->dev, "Failed to do magic: %d\n", | ||
688 | ret); | ||
689 | } | ||
690 | |||
691 | mutex_unlock(&arizona->dapm->card->dapm_mutex); | ||
692 | 697 | ||
693 | ret = regmap_update_bits(arizona->regmap, | 698 | ret = regmap_update_bits(arizona->regmap, |
694 | ARIZONA_ACCESSORY_DETECT_MODE_1, | 699 | ARIZONA_ACCESSORY_DETECT_MODE_1, |
@@ -700,12 +705,18 @@ static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info) | |||
700 | goto err; | 705 | goto err; |
701 | } | 706 | } |
702 | 707 | ||
703 | ret = regmap_update_bits(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1, | 708 | if (arizona->pdata.hpdet_acc_id_line) { |
704 | ARIZONA_HP_POLL, ARIZONA_HP_POLL); | 709 | ret = regmap_update_bits(arizona->regmap, |
705 | if (ret != 0) { | 710 | ARIZONA_HEADPHONE_DETECT_1, |
706 | dev_err(arizona->dev, "Can't start HPDETL measurement: %d\n", | 711 | ARIZONA_HP_POLL, ARIZONA_HP_POLL); |
707 | ret); | 712 | if (ret != 0) { |
708 | 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); | ||
709 | } | 720 | } |
710 | 721 | ||
711 | return; | 722 | return; |
@@ -724,28 +735,58 @@ err: | |||
724 | info->hpdet_active = false; | 735 | info->hpdet_active = false; |
725 | } | 736 | } |
726 | 737 | ||
727 | static irqreturn_t arizona_micdet(int irq, void *data) | 738 | static void arizona_micd_timeout_work(struct work_struct *work) |
728 | { | 739 | { |
729 | 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); | ||
730 | struct arizona *arizona = info->arizona; | 761 | struct arizona *arizona = info->arizona; |
731 | unsigned int val, lvl; | 762 | unsigned int val = 0, lvl; |
732 | int ret, i; | 763 | int ret, i, key; |
764 | |||
765 | cancel_delayed_work_sync(&info->micd_timeout_work); | ||
733 | 766 | ||
734 | mutex_lock(&info->lock); | 767 | mutex_lock(&info->lock); |
735 | 768 | ||
736 | ret = regmap_read(arizona->regmap, ARIZONA_MIC_DETECT_3, &val); | 769 | for (i = 0; i < 10 && !(val & 0x7fc); i++) { |
737 | if (ret != 0) { | 770 | ret = regmap_read(arizona->regmap, ARIZONA_MIC_DETECT_3, &val); |
738 | dev_err(arizona->dev, "Failed to read MICDET: %d\n", ret); | 771 | if (ret != 0) { |
739 | mutex_unlock(&info->lock); | 772 | dev_err(arizona->dev, "Failed to read MICDET: %d\n", ret); |
740 | return IRQ_NONE; | 773 | mutex_unlock(&info->lock); |
741 | } | 774 | return; |
775 | } | ||
742 | 776 | ||
743 | dev_dbg(arizona->dev, "MICDET: %x\n", val); | 777 | dev_dbg(arizona->dev, "MICDET: %x\n", val); |
778 | |||
779 | if (!(val & ARIZONA_MICD_VALID)) { | ||
780 | dev_warn(arizona->dev, "Microphone detection state invalid\n"); | ||
781 | mutex_unlock(&info->lock); | ||
782 | return; | ||
783 | } | ||
784 | } | ||
744 | 785 | ||
745 | if (!(val & ARIZONA_MICD_VALID)) { | 786 | if (i == 10 && !(val & 0x7fc)) { |
746 | dev_warn(arizona->dev, "Microphone detection state invalid\n"); | 787 | dev_err(arizona->dev, "Failed to get valid MICDET value\n"); |
747 | mutex_unlock(&info->lock); | 788 | mutex_unlock(&info->lock); |
748 | return IRQ_NONE; | 789 | return; |
749 | } | 790 | } |
750 | 791 | ||
751 | /* Due to jack detect this should never happen */ | 792 | /* Due to jack detect this should never happen */ |
@@ -786,7 +827,7 @@ static irqreturn_t arizona_micdet(int irq, void *data) | |||
786 | * impedence then give up and report headphones. | 827 | * impedence then give up and report headphones. |
787 | */ | 828 | */ |
788 | if (info->detecting && (val & 0x3f8)) { | 829 | if (info->detecting && (val & 0x3f8)) { |
789 | if (info->jack_flips >= info->micd_num_modes) { | 830 | if (info->jack_flips >= info->micd_num_modes * 10) { |
790 | dev_dbg(arizona->dev, "Detected HP/line\n"); | 831 | dev_dbg(arizona->dev, "Detected HP/line\n"); |
791 | arizona_identify_headphone(info); | 832 | arizona_identify_headphone(info); |
792 | 833 | ||
@@ -816,12 +857,17 @@ static irqreturn_t arizona_micdet(int irq, void *data) | |||
816 | lvl = val & ARIZONA_MICD_LVL_MASK; | 857 | lvl = val & ARIZONA_MICD_LVL_MASK; |
817 | lvl >>= ARIZONA_MICD_LVL_SHIFT; | 858 | lvl >>= ARIZONA_MICD_LVL_SHIFT; |
818 | 859 | ||
819 | for (i = 0; i < ARIZONA_NUM_BUTTONS; i++) | 860 | for (i = 0; i < info->num_micd_ranges; i++) |
820 | if (lvl & arizona_lvl_to_key[i].status) | 861 | input_report_key(info->input, |
821 | input_report_key(info->input, | 862 | info->micd_ranges[i].key, 0); |
822 | arizona_lvl_to_key[i].report, | 863 | |
823 | 1); | 864 | WARN_ON(!lvl); |
824 | 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 | } | ||
825 | 871 | ||
826 | } else if (info->detecting) { | 872 | } else if (info->detecting) { |
827 | dev_dbg(arizona->dev, "Headphone detected\n"); | 873 | dev_dbg(arizona->dev, "Headphone detected\n"); |
@@ -835,16 +881,41 @@ static irqreturn_t arizona_micdet(int irq, void *data) | |||
835 | } | 881 | } |
836 | } else { | 882 | } else { |
837 | dev_dbg(arizona->dev, "Mic button released\n"); | 883 | dev_dbg(arizona->dev, "Mic button released\n"); |
838 | for (i = 0; i < ARIZONA_NUM_BUTTONS; i++) | 884 | for (i = 0; i < info->num_micd_ranges; i++) |
839 | input_report_key(info->input, | 885 | input_report_key(info->input, |
840 | arizona_lvl_to_key[i].report, 0); | 886 | info->micd_ranges[i].key, 0); |
841 | input_sync(info->input); | 887 | input_sync(info->input); |
842 | arizona_extcon_pulse_micbias(info); | 888 | arizona_extcon_pulse_micbias(info); |
843 | } | 889 | } |
844 | 890 | ||
845 | handled: | 891 | handled: |
892 | if (info->detecting) | ||
893 | schedule_delayed_work(&info->micd_timeout_work, | ||
894 | msecs_to_jiffies(info->micd_timeout)); | ||
895 | |||
846 | pm_runtime_mark_last_busy(info->dev); | 896 | pm_runtime_mark_last_busy(info->dev); |
847 | 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); | ||
848 | 919 | ||
849 | return IRQ_HANDLED; | 920 | return IRQ_HANDLED; |
850 | } | 921 | } |
@@ -865,11 +936,13 @@ static irqreturn_t arizona_jackdet(int irq, void *data) | |||
865 | struct arizona_extcon_info *info = data; | 936 | struct arizona_extcon_info *info = data; |
866 | struct arizona *arizona = info->arizona; | 937 | struct arizona *arizona = info->arizona; |
867 | unsigned int val, present, mask; | 938 | unsigned int val, present, mask; |
939 | bool cancelled_hp, cancelled_mic; | ||
868 | int ret, i; | 940 | int ret, i; |
869 | 941 | ||
870 | 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); | ||
871 | 944 | ||
872 | cancel_delayed_work_sync(&info->hpdet_work); | 945 | pm_runtime_get_sync(info->dev); |
873 | 946 | ||
874 | mutex_lock(&info->lock); | 947 | mutex_lock(&info->lock); |
875 | 948 | ||
@@ -890,7 +963,22 @@ static irqreturn_t arizona_jackdet(int irq, void *data) | |||
890 | return IRQ_NONE; | 963 | return IRQ_NONE; |
891 | } | 964 | } |
892 | 965 | ||
893 | 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) { | ||
894 | dev_dbg(arizona->dev, "Detected jack\n"); | 982 | dev_dbg(arizona->dev, "Detected jack\n"); |
895 | ret = extcon_set_cable_state_(&info->edev, | 983 | ret = extcon_set_cable_state_(&info->edev, |
896 | ARIZONA_CABLE_MECHANICAL, true); | 984 | ARIZONA_CABLE_MECHANICAL, true); |
@@ -907,7 +995,7 @@ static irqreturn_t arizona_jackdet(int irq, void *data) | |||
907 | arizona_start_mic(info); | 995 | arizona_start_mic(info); |
908 | } else { | 996 | } else { |
909 | schedule_delayed_work(&info->hpdet_work, | 997 | schedule_delayed_work(&info->hpdet_work, |
910 | msecs_to_jiffies(250)); | 998 | msecs_to_jiffies(HPDET_DEBOUNCE)); |
911 | } | 999 | } |
912 | 1000 | ||
913 | regmap_update_bits(arizona->regmap, | 1001 | regmap_update_bits(arizona->regmap, |
@@ -923,10 +1011,11 @@ static irqreturn_t arizona_jackdet(int irq, void *data) | |||
923 | info->hpdet_res[i] = 0; | 1011 | info->hpdet_res[i] = 0; |
924 | info->mic = false; | 1012 | info->mic = false; |
925 | info->hpdet_done = false; | 1013 | info->hpdet_done = false; |
1014 | info->hpdet_retried = false; | ||
926 | 1015 | ||
927 | for (i = 0; i < ARIZONA_NUM_BUTTONS; i++) | 1016 | for (i = 0; i < info->num_micd_ranges; i++) |
928 | input_report_key(info->input, | 1017 | input_report_key(info->input, |
929 | arizona_lvl_to_key[i].report, 0); | 1018 | info->micd_ranges[i].key, 0); |
930 | input_sync(info->input); | 1019 | input_sync(info->input); |
931 | 1020 | ||
932 | ret = extcon_update_state(&info->edev, 0xffffffff, 0); | 1021 | ret = extcon_update_state(&info->edev, 0xffffffff, 0); |
@@ -940,6 +1029,11 @@ static irqreturn_t arizona_jackdet(int irq, void *data) | |||
940 | ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB); | 1029 | ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB); |
941 | } | 1030 | } |
942 | 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 | |||
943 | /* Clear trig_sts to make sure DCVDD is not forced up */ | 1037 | /* Clear trig_sts to make sure DCVDD is not forced up */ |
944 | regmap_write(arizona->regmap, ARIZONA_AOD_WKUP_AND_TRIG, | 1038 | regmap_write(arizona->regmap, ARIZONA_AOD_WKUP_AND_TRIG, |
945 | ARIZONA_MICD_CLAMP_FALL_TRIG_STS | | 1039 | ARIZONA_MICD_CLAMP_FALL_TRIG_STS | |
@@ -947,6 +1041,7 @@ static irqreturn_t arizona_jackdet(int irq, void *data) | |||
947 | ARIZONA_JD1_FALL_TRIG_STS | | 1041 | ARIZONA_JD1_FALL_TRIG_STS | |
948 | ARIZONA_JD1_RISE_TRIG_STS); | 1042 | ARIZONA_JD1_RISE_TRIG_STS); |
949 | 1043 | ||
1044 | out: | ||
950 | mutex_unlock(&info->lock); | 1045 | mutex_unlock(&info->lock); |
951 | 1046 | ||
952 | pm_runtime_mark_last_busy(info->dev); | 1047 | pm_runtime_mark_last_busy(info->dev); |
@@ -955,13 +1050,34 @@ static irqreturn_t arizona_jackdet(int irq, void *data) | |||
955 | return IRQ_HANDLED; | 1050 | return IRQ_HANDLED; |
956 | } | 1051 | } |
957 | 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 | |||
958 | static int arizona_extcon_probe(struct platform_device *pdev) | 1073 | static int arizona_extcon_probe(struct platform_device *pdev) |
959 | { | 1074 | { |
960 | struct arizona *arizona = dev_get_drvdata(pdev->dev.parent); | 1075 | struct arizona *arizona = dev_get_drvdata(pdev->dev.parent); |
961 | struct arizona_pdata *pdata; | 1076 | struct arizona_pdata *pdata; |
962 | struct arizona_extcon_info *info; | 1077 | struct arizona_extcon_info *info; |
1078 | unsigned int val; | ||
963 | int jack_irq_fall, jack_irq_rise; | 1079 | int jack_irq_fall, jack_irq_rise; |
964 | int ret, mode, i; | 1080 | int ret, mode, i, j; |
965 | 1081 | ||
966 | if (!arizona->dapm || !arizona->dapm->card) | 1082 | if (!arizona->dapm || !arizona->dapm->card) |
967 | return -EPROBE_DEFER; | 1083 | return -EPROBE_DEFER; |
@@ -985,7 +1101,10 @@ static int arizona_extcon_probe(struct platform_device *pdev) | |||
985 | mutex_init(&info->lock); | 1101 | mutex_init(&info->lock); |
986 | info->arizona = arizona; | 1102 | info->arizona = arizona; |
987 | info->dev = &pdev->dev; | 1103 | info->dev = &pdev->dev; |
1104 | info->last_jackdet = ~(ARIZONA_MICD_CLAMP_STS | ARIZONA_JD1_STS); | ||
988 | 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); | ||
989 | platform_set_drvdata(pdev, info); | 1108 | platform_set_drvdata(pdev, info); |
990 | 1109 | ||
991 | switch (arizona->type) { | 1110 | switch (arizona->type) { |
@@ -1014,6 +1133,17 @@ static int arizona_extcon_probe(struct platform_device *pdev) | |||
1014 | goto err; | 1133 | goto err; |
1015 | } | 1134 | } |
1016 | 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 | |||
1017 | if (pdata->num_micd_configs) { | 1147 | if (pdata->num_micd_configs) { |
1018 | info->micd_modes = pdata->micd_configs; | 1148 | info->micd_modes = pdata->micd_configs; |
1019 | info->micd_num_modes = pdata->num_micd_configs; | 1149 | info->micd_num_modes = pdata->num_micd_configs; |
@@ -1069,15 +1199,79 @@ static int arizona_extcon_probe(struct platform_device *pdev) | |||
1069 | arizona->pdata.micd_dbtime | 1199 | arizona->pdata.micd_dbtime |
1070 | << ARIZONA_MICD_DBTIME_SHIFT); | 1200 | << ARIZONA_MICD_DBTIME_SHIFT); |
1071 | 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 | |||
1072 | /* | 1262 | /* |
1073 | * If we have a clamp use it, activating in conjunction with | 1263 | * If we have a clamp use it, activating in conjunction with |
1074 | * GPIO5 if that is connected for jack detect operation. | 1264 | * GPIO5 if that is connected for jack detect operation. |
1075 | */ | 1265 | */ |
1076 | if (info->micd_clamp) { | 1266 | if (info->micd_clamp) { |
1077 | if (arizona->pdata.jd_gpio5) { | 1267 | if (arizona->pdata.jd_gpio5) { |
1078 | /* 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 | |||
1079 | regmap_write(arizona->regmap, ARIZONA_GPIO5_CTRL, | 1273 | regmap_write(arizona->regmap, ARIZONA_GPIO5_CTRL, |
1080 | 0xc101); | 1274 | val); |
1081 | 1275 | ||
1082 | regmap_update_bits(arizona->regmap, | 1276 | regmap_update_bits(arizona->regmap, |
1083 | ARIZONA_MICD_CLAMP_CONTROL, | 1277 | ARIZONA_MICD_CLAMP_CONTROL, |
@@ -1096,20 +1290,6 @@ static int arizona_extcon_probe(struct platform_device *pdev) | |||
1096 | 1290 | ||
1097 | arizona_extcon_set_mode(info, 0); | 1291 | arizona_extcon_set_mode(info, 0); |
1098 | 1292 | ||
1099 | info->input = devm_input_allocate_device(&pdev->dev); | ||
1100 | if (!info->input) { | ||
1101 | dev_err(arizona->dev, "Can't allocate input dev\n"); | ||
1102 | ret = -ENOMEM; | ||
1103 | goto err_register; | ||
1104 | } | ||
1105 | |||
1106 | for (i = 0; i < ARIZONA_NUM_BUTTONS; i++) | ||
1107 | input_set_capability(info->input, EV_KEY, | ||
1108 | arizona_lvl_to_key[i].report); | ||
1109 | info->input->name = "Headset"; | ||
1110 | info->input->phys = "arizona/extcon"; | ||
1111 | info->input->dev.parent = &pdev->dev; | ||
1112 | |||
1113 | pm_runtime_enable(&pdev->dev); | 1293 | pm_runtime_enable(&pdev->dev); |
1114 | pm_runtime_idle(&pdev->dev); | 1294 | pm_runtime_idle(&pdev->dev); |
1115 | pm_runtime_get_sync(&pdev->dev); | 1295 | pm_runtime_get_sync(&pdev->dev); |