diff options
author | Krzysztof Kozlowski <k.kozlowski@samsung.com> | 2014-04-14 05:17:19 -0400 |
---|---|---|
committer | Lee Jones <lee.jones@linaro.org> | 2014-04-23 09:09:25 -0400 |
commit | 4706a5253bcc502a5889feb98392ea7b15dd936e (patch) | |
tree | cced4579e808011105fe7c04177d0fffe3e83f66 | |
parent | aee2a57c7482c712052b877218aa2c5bc0fe8626 (diff) |
extcon: max14577: Add support for MAX77836
Add support for MAX77836 chipset to the max14577 extcon driver. The
MAX77836 MUIC has additional interrupts (VIDRM, ADC1K) so IRQ handling
is split up into two functions: max14577_parse_irq() and
max77836_parse_irq().
Signed-off-by: Krzysztof Kozlowski <k.kozlowski@samsung.com>
Acked-by: Chanwoo Choi <cw00.choi@samsung.com>
Tested-by: Chanwoo Choi <cw00.choi@samsung.com>
Signed-off-by: Lee Jones <lee.jones@linaro.org>
-rw-r--r-- | drivers/extcon/Kconfig | 4 | ||||
-rw-r--r-- | drivers/extcon/extcon-max14577.c | 109 | ||||
-rw-r--r-- | drivers/mfd/max14577.c | 1 | ||||
-rw-r--r-- | include/linux/mfd/max14577-private.h | 3 |
4 files changed, 96 insertions, 21 deletions
diff --git a/drivers/extcon/Kconfig b/drivers/extcon/Kconfig index be56e8ac95e6..aebde489c291 100644 --- a/drivers/extcon/Kconfig +++ b/drivers/extcon/Kconfig | |||
@@ -28,13 +28,13 @@ config EXTCON_ADC_JACK | |||
28 | Say Y here to enable extcon device driver based on ADC values. | 28 | Say Y here to enable extcon device driver based on ADC values. |
29 | 29 | ||
30 | config EXTCON_MAX14577 | 30 | config EXTCON_MAX14577 |
31 | tristate "MAX14577 EXTCON Support" | 31 | tristate "MAX14577/77836 EXTCON Support" |
32 | depends on MFD_MAX14577 | 32 | depends on MFD_MAX14577 |
33 | select IRQ_DOMAIN | 33 | select IRQ_DOMAIN |
34 | select REGMAP_I2C | 34 | select REGMAP_I2C |
35 | help | 35 | help |
36 | If you say yes here you get support for the MUIC device of | 36 | If you say yes here you get support for the MUIC device of |
37 | Maxim MAX14577 PMIC. The MAX14577 MUIC is a USB port accessory | 37 | Maxim MAX14577/77836. The MAX14577/77836 MUIC is a USB port accessory |
38 | detector and switch. | 38 | detector and switch. |
39 | 39 | ||
40 | config EXTCON_MAX77693 | 40 | config EXTCON_MAX77693 |
diff --git a/drivers/extcon/extcon-max14577.c b/drivers/extcon/extcon-max14577.c index 1513013a92f1..c76734a70171 100644 --- a/drivers/extcon/extcon-max14577.c +++ b/drivers/extcon/extcon-max14577.c | |||
@@ -1,8 +1,9 @@ | |||
1 | /* | 1 | /* |
2 | * extcon-max14577.c - MAX14577 extcon driver to support MAX14577 MUIC | 2 | * extcon-max14577.c - MAX14577/77836 extcon driver to support MUIC |
3 | * | 3 | * |
4 | * Copyright (C) 2013 Samsung Electrnoics | 4 | * Copyright (C) 2013,2014 Samsung Electrnoics |
5 | * Chanwoo Choi <cw00.choi@samsung.com> | 5 | * Chanwoo Choi <cw00.choi@samsung.com> |
6 | * Krzysztof Kozlowski <k.kozlowski@samsung.com> | ||
6 | * | 7 | * |
7 | * This program is free software; you can redistribute it and/or modify | 8 | * This program is free software; you can redistribute it and/or modify |
8 | * it under the terms of the GNU General Public License as published by | 9 | * it under the terms of the GNU General Public License as published by |
@@ -62,6 +63,19 @@ static struct max14577_muic_irq max14577_muic_irqs[] = { | |||
62 | { MAX14577_IRQ_INT2_VBVOLT, "muic-VBVOLT" }, | 63 | { MAX14577_IRQ_INT2_VBVOLT, "muic-VBVOLT" }, |
63 | }; | 64 | }; |
64 | 65 | ||
66 | static struct max14577_muic_irq max77836_muic_irqs[] = { | ||
67 | { MAX14577_IRQ_INT1_ADC, "muic-ADC" }, | ||
68 | { MAX14577_IRQ_INT1_ADCLOW, "muic-ADCLOW" }, | ||
69 | { MAX14577_IRQ_INT1_ADCERR, "muic-ADCError" }, | ||
70 | { MAX77836_IRQ_INT1_ADC1K, "muic-ADC1K" }, | ||
71 | { MAX14577_IRQ_INT2_CHGTYP, "muic-CHGTYP" }, | ||
72 | { MAX14577_IRQ_INT2_CHGDETRUN, "muic-CHGDETRUN" }, | ||
73 | { MAX14577_IRQ_INT2_DCDTMR, "muic-DCDTMR" }, | ||
74 | { MAX14577_IRQ_INT2_DBCHG, "muic-DBCHG" }, | ||
75 | { MAX14577_IRQ_INT2_VBVOLT, "muic-VBVOLT" }, | ||
76 | { MAX77836_IRQ_INT2_VIDRM, "muic-VIDRM" }, | ||
77 | }; | ||
78 | |||
65 | struct max14577_muic_info { | 79 | struct max14577_muic_info { |
66 | struct device *dev; | 80 | struct device *dev; |
67 | struct max14577 *max14577; | 81 | struct max14577 *max14577; |
@@ -529,21 +543,12 @@ static void max14577_muic_irq_work(struct work_struct *work) | |||
529 | return; | 543 | return; |
530 | } | 544 | } |
531 | 545 | ||
532 | static irqreturn_t max14577_muic_irq_handler(int irq, void *data) | 546 | /* |
547 | * Sets irq_adc or irq_chg in max14577_muic_info and returns 1. | ||
548 | * Returns 0 if irq_type does not match registered IRQ for this device type. | ||
549 | */ | ||
550 | static int max14577_parse_irq(struct max14577_muic_info *info, int irq_type) | ||
533 | { | 551 | { |
534 | struct max14577_muic_info *info = data; | ||
535 | int i, irq_type = -1; | ||
536 | |||
537 | /* | ||
538 | * We may be called multiple times for different nested IRQ-s. | ||
539 | * Including changes in INT1_ADC and INT2_CGHTYP at once. | ||
540 | * However we only need to know whether it was ADC, charger | ||
541 | * or both interrupts so decode IRQ and turn on proper flags. | ||
542 | */ | ||
543 | for (i = 0; i < info->muic_irqs_num; i++) | ||
544 | if (irq == info->muic_irqs[i].virq) | ||
545 | irq_type = info->muic_irqs[i].irq; | ||
546 | |||
547 | switch (irq_type) { | 552 | switch (irq_type) { |
548 | case MAX14577_IRQ_INT1_ADC: | 553 | case MAX14577_IRQ_INT1_ADC: |
549 | case MAX14577_IRQ_INT1_ADCLOW: | 554 | case MAX14577_IRQ_INT1_ADCLOW: |
@@ -551,7 +556,7 @@ static irqreturn_t max14577_muic_irq_handler(int irq, void *data) | |||
551 | /* Handle all of accessory except for | 556 | /* Handle all of accessory except for |
552 | type of charger accessory */ | 557 | type of charger accessory */ |
553 | info->irq_adc = true; | 558 | info->irq_adc = true; |
554 | break; | 559 | return 1; |
555 | case MAX14577_IRQ_INT2_CHGTYP: | 560 | case MAX14577_IRQ_INT2_CHGTYP: |
556 | case MAX14577_IRQ_INT2_CHGDETRUN: | 561 | case MAX14577_IRQ_INT2_CHGDETRUN: |
557 | case MAX14577_IRQ_INT2_DCDTMR: | 562 | case MAX14577_IRQ_INT2_DCDTMR: |
@@ -559,8 +564,62 @@ static irqreturn_t max14577_muic_irq_handler(int irq, void *data) | |||
559 | case MAX14577_IRQ_INT2_VBVOLT: | 564 | case MAX14577_IRQ_INT2_VBVOLT: |
560 | /* Handle charger accessory */ | 565 | /* Handle charger accessory */ |
561 | info->irq_chg = true; | 566 | info->irq_chg = true; |
567 | return 1; | ||
568 | default: | ||
569 | return 0; | ||
570 | } | ||
571 | } | ||
572 | |||
573 | /* | ||
574 | * Sets irq_adc or irq_chg in max14577_muic_info and returns 1. | ||
575 | * Returns 0 if irq_type does not match registered IRQ for this device type. | ||
576 | */ | ||
577 | static int max77836_parse_irq(struct max14577_muic_info *info, int irq_type) | ||
578 | { | ||
579 | /* First check common max14577 interrupts */ | ||
580 | if (max14577_parse_irq(info, irq_type)) | ||
581 | return 1; | ||
582 | |||
583 | switch (irq_type) { | ||
584 | case MAX77836_IRQ_INT1_ADC1K: | ||
585 | info->irq_adc = true; | ||
586 | return 1; | ||
587 | case MAX77836_IRQ_INT2_VIDRM: | ||
588 | /* Handle charger accessory */ | ||
589 | info->irq_chg = true; | ||
590 | return 1; | ||
591 | default: | ||
592 | return 0; | ||
593 | } | ||
594 | } | ||
595 | |||
596 | static irqreturn_t max14577_muic_irq_handler(int irq, void *data) | ||
597 | { | ||
598 | struct max14577_muic_info *info = data; | ||
599 | int i, irq_type = -1; | ||
600 | bool irq_parsed; | ||
601 | |||
602 | /* | ||
603 | * We may be called multiple times for different nested IRQ-s. | ||
604 | * Including changes in INT1_ADC and INT2_CGHTYP at once. | ||
605 | * However we only need to know whether it was ADC, charger | ||
606 | * or both interrupts so decode IRQ and turn on proper flags. | ||
607 | */ | ||
608 | for (i = 0; i < info->muic_irqs_num; i++) | ||
609 | if (irq == info->muic_irqs[i].virq) | ||
610 | irq_type = info->muic_irqs[i].irq; | ||
611 | |||
612 | switch (info->max14577->dev_type) { | ||
613 | case MAXIM_DEVICE_TYPE_MAX77836: | ||
614 | irq_parsed = max77836_parse_irq(info, irq_type); | ||
562 | break; | 615 | break; |
616 | case MAXIM_DEVICE_TYPE_MAX14577: | ||
563 | default: | 617 | default: |
618 | irq_parsed = max14577_parse_irq(info, irq_type); | ||
619 | break; | ||
620 | } | ||
621 | |||
622 | if (!irq_parsed) { | ||
564 | dev_err(info->dev, "muic interrupt: irq %d occurred, skipped\n", | 623 | dev_err(info->dev, "muic interrupt: irq %d occurred, skipped\n", |
565 | irq_type); | 624 | irq_type); |
566 | return IRQ_HANDLED; | 625 | return IRQ_HANDLED; |
@@ -646,6 +705,10 @@ static int max14577_muic_probe(struct platform_device *pdev) | |||
646 | INIT_WORK(&info->irq_work, max14577_muic_irq_work); | 705 | INIT_WORK(&info->irq_work, max14577_muic_irq_work); |
647 | 706 | ||
648 | switch (max14577->dev_type) { | 707 | switch (max14577->dev_type) { |
708 | case MAXIM_DEVICE_TYPE_MAX77836: | ||
709 | info->muic_irqs = max77836_muic_irqs; | ||
710 | info->muic_irqs_num = ARRAY_SIZE(max77836_muic_irqs); | ||
711 | break; | ||
649 | case MAXIM_DEVICE_TYPE_MAX14577: | 712 | case MAXIM_DEVICE_TYPE_MAX14577: |
650 | default: | 713 | default: |
651 | info->muic_irqs = max14577_muic_irqs; | 714 | info->muic_irqs = max14577_muic_irqs; |
@@ -744,6 +807,13 @@ static int max14577_muic_remove(struct platform_device *pdev) | |||
744 | return 0; | 807 | return 0; |
745 | } | 808 | } |
746 | 809 | ||
810 | static const struct platform_device_id max14577_muic_id[] = { | ||
811 | { "max14577-muic", MAXIM_DEVICE_TYPE_MAX14577, }, | ||
812 | { "max77836-muic", MAXIM_DEVICE_TYPE_MAX77836, }, | ||
813 | { } | ||
814 | }; | ||
815 | MODULE_DEVICE_TABLE(platform, max14577_muic_id); | ||
816 | |||
747 | static struct platform_driver max14577_muic_driver = { | 817 | static struct platform_driver max14577_muic_driver = { |
748 | .driver = { | 818 | .driver = { |
749 | .name = "max14577-muic", | 819 | .name = "max14577-muic", |
@@ -751,11 +821,12 @@ static struct platform_driver max14577_muic_driver = { | |||
751 | }, | 821 | }, |
752 | .probe = max14577_muic_probe, | 822 | .probe = max14577_muic_probe, |
753 | .remove = max14577_muic_remove, | 823 | .remove = max14577_muic_remove, |
824 | .id_table = max14577_muic_id, | ||
754 | }; | 825 | }; |
755 | 826 | ||
756 | module_platform_driver(max14577_muic_driver); | 827 | module_platform_driver(max14577_muic_driver); |
757 | 828 | ||
758 | MODULE_DESCRIPTION("MAXIM 14577 Extcon driver"); | 829 | MODULE_DESCRIPTION("Maxim 14577/77836 Extcon driver"); |
759 | MODULE_AUTHOR("Chanwoo Choi <cw00.choi@samsung.com>"); | 830 | MODULE_AUTHOR("Chanwoo Choi <cw00.choi@samsung.com>, Krzysztof Kozlowski <k.kozlowski@samsung.com>"); |
760 | MODULE_LICENSE("GPL"); | 831 | MODULE_LICENSE("GPL"); |
761 | MODULE_ALIAS("platform:extcon-max14577"); | 832 | MODULE_ALIAS("platform:extcon-max14577"); |
diff --git a/drivers/mfd/max14577.c b/drivers/mfd/max14577.c index 20e3b2d81bf0..484d372a4892 100644 --- a/drivers/mfd/max14577.c +++ b/drivers/mfd/max14577.c | |||
@@ -147,6 +147,7 @@ static const struct regmap_irq max77836_muic_irqs[] = { | |||
147 | { .reg_offset = 0, .mask = MAX14577_INT1_ADC_MASK, }, | 147 | { .reg_offset = 0, .mask = MAX14577_INT1_ADC_MASK, }, |
148 | { .reg_offset = 0, .mask = MAX14577_INT1_ADCLOW_MASK, }, | 148 | { .reg_offset = 0, .mask = MAX14577_INT1_ADCLOW_MASK, }, |
149 | { .reg_offset = 0, .mask = MAX14577_INT1_ADCERR_MASK, }, | 149 | { .reg_offset = 0, .mask = MAX14577_INT1_ADCERR_MASK, }, |
150 | { .reg_offset = 0, .mask = MAX77836_INT1_ADC1K_MASK, }, | ||
150 | /* INT2 interrupts */ | 151 | /* INT2 interrupts */ |
151 | { .reg_offset = 1, .mask = MAX14577_INT2_CHGTYP_MASK, }, | 152 | { .reg_offset = 1, .mask = MAX14577_INT2_CHGTYP_MASK, }, |
152 | { .reg_offset = 1, .mask = MAX14577_INT2_CHGDETRUN_MASK, }, | 153 | { .reg_offset = 1, .mask = MAX14577_INT2_CHGDETRUN_MASK, }, |
diff --git a/include/linux/mfd/max14577-private.h b/include/linux/mfd/max14577-private.h index e301bd19b067..a557ae27d8a8 100644 --- a/include/linux/mfd/max14577-private.h +++ b/include/linux/mfd/max14577-private.h | |||
@@ -87,6 +87,7 @@ enum max14577_muic_charger_type { | |||
87 | #define MAX14577_INT1_ADC_MASK BIT(0) | 87 | #define MAX14577_INT1_ADC_MASK BIT(0) |
88 | #define MAX14577_INT1_ADCLOW_MASK BIT(1) | 88 | #define MAX14577_INT1_ADCLOW_MASK BIT(1) |
89 | #define MAX14577_INT1_ADCERR_MASK BIT(2) | 89 | #define MAX14577_INT1_ADCERR_MASK BIT(2) |
90 | #define MAX77836_INT1_ADC1K_MASK BIT(3) | ||
90 | 91 | ||
91 | #define MAX14577_INT2_CHGTYP_MASK BIT(0) | 92 | #define MAX14577_INT2_CHGTYP_MASK BIT(0) |
92 | #define MAX14577_INT2_CHGDETRUN_MASK BIT(1) | 93 | #define MAX14577_INT2_CHGDETRUN_MASK BIT(1) |
@@ -332,6 +333,7 @@ enum max14577_irq { | |||
332 | MAX14577_IRQ_INT1_ADC, | 333 | MAX14577_IRQ_INT1_ADC, |
333 | MAX14577_IRQ_INT1_ADCLOW, | 334 | MAX14577_IRQ_INT1_ADCLOW, |
334 | MAX14577_IRQ_INT1_ADCERR, | 335 | MAX14577_IRQ_INT1_ADCERR, |
336 | MAX77836_IRQ_INT1_ADC1K, | ||
335 | 337 | ||
336 | /* INT2 */ | 338 | /* INT2 */ |
337 | MAX14577_IRQ_INT2_CHGTYP, | 339 | MAX14577_IRQ_INT2_CHGTYP, |
@@ -339,6 +341,7 @@ enum max14577_irq { | |||
339 | MAX14577_IRQ_INT2_DCDTMR, | 341 | MAX14577_IRQ_INT2_DCDTMR, |
340 | MAX14577_IRQ_INT2_DBCHG, | 342 | MAX14577_IRQ_INT2_DBCHG, |
341 | MAX14577_IRQ_INT2_VBVOLT, | 343 | MAX14577_IRQ_INT2_VBVOLT, |
344 | MAX77836_IRQ_INT2_VIDRM, | ||
342 | 345 | ||
343 | /* INT3 */ | 346 | /* INT3 */ |
344 | MAX14577_IRQ_INT3_EOC, | 347 | MAX14577_IRQ_INT3_EOC, |