aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>2014-01-08 23:14:19 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2014-01-08 23:14:19 -0500
commit52cb6a205c9750353cbb58dbf7eea1e046c89819 (patch)
tree0fdac6d6e9b4e805d8010adf90828d0475836825
parent19c055738b571c920c6e313fa31ac8c5ef4ce5a1 (diff)
parent6544dfa5795060b01042fd62fd1a92e18c2fc485 (diff)
Merge tag 'extcon-next-for-3.14' of git://git.kernel.org/pub/scm/linux/kernel/git/chanwoo/extcon into char-misc-next
Chanwoo writes: Update extcon for v3.14 This patchset add new driver of extcon-max14577.c which detect various external connector and fix minor issue of extcon provider driver(extcon-arizona/palams/ gpio.c). Also, update documentation of previous 'switch' porting guide and extcon git repository url. Detailed description for patchset: - New driver of extcon-max14577.c : Add extcon-max14577.c drvier to support Maxim MUIC(Micro USB Interface Controller) which detect USB/TA/JIG/AUDIO-DOCK and additional accessory according to each resistance when connected external connector. - extcon-arizoan.c driver : Code clean to use define macro instead of hex value : Fix minor issue to reset back to our staring state : Fix race with microphone detection and removal - extcon-palmas.c driver : Fix minor issue and renaming compatible string of Devicetree - extcon-gpio.c driver : Fix bug about ordering initialization of gpio pin on probe() : Send uevent after wakeup from suspend state because some SoC haven't wakeup interrupt on suspend state. - Documentation (Documentation/extcon/porting-android-switch-class) : Fix switch class porting guide - Update extcon git repository url
-rw-r--r--Documentation/devicetree/bindings/extcon/extcon-palmas.txt6
-rw-r--r--Documentation/extcon/porting-android-switch-class9
-rw-r--r--MAINTAINERS1
-rw-r--r--drivers/extcon/Kconfig10
-rw-r--r--drivers/extcon/Makefile1
-rw-r--r--drivers/extcon/extcon-arizona.c73
-rw-r--r--drivers/extcon/extcon-gpio.c32
-rw-r--r--drivers/extcon/extcon-max14577.c752
-rw-r--r--drivers/extcon/extcon-palmas.c17
-rw-r--r--include/linux/extcon/extcon-gpio.h1
-rw-r--r--include/linux/mfd/arizona/registers.h9
11 files changed, 876 insertions, 35 deletions
diff --git a/Documentation/devicetree/bindings/extcon/extcon-palmas.txt b/Documentation/devicetree/bindings/extcon/extcon-palmas.txt
index 7dab6a8f4a0e..45414bbcd945 100644
--- a/Documentation/devicetree/bindings/extcon/extcon-palmas.txt
+++ b/Documentation/devicetree/bindings/extcon/extcon-palmas.txt
@@ -2,7 +2,11 @@ EXTCON FOR PALMAS/TWL CHIPS
2 2
3PALMAS USB COMPARATOR 3PALMAS USB COMPARATOR
4Required Properties: 4Required Properties:
5 - compatible : Should be "ti,palmas-usb" or "ti,twl6035-usb" 5 - compatible: should contain one of:
6 * "ti,palmas-usb-vid".
7 * "ti,twl6035-usb-vid".
8 * "ti,palmas-usb" (DEPRECATED - use "ti,palmas-usb-vid").
9 * "ti,twl6035-usb" (DEPRECATED - use "ti,twl6035-usb-vid").
6 10
7Optional Properties: 11Optional Properties:
8 - ti,wakeup : To enable the wakeup comparator in probe 12 - ti,wakeup : To enable the wakeup comparator in probe
diff --git a/Documentation/extcon/porting-android-switch-class b/Documentation/extcon/porting-android-switch-class
index 5377f6317961..49c81caef84d 100644
--- a/Documentation/extcon/porting-android-switch-class
+++ b/Documentation/extcon/porting-android-switch-class
@@ -50,7 +50,7 @@ so that they are still compatible with legacy userspace processes.
50 Extcon's extended features for switch device drivers with 50 Extcon's extended features for switch device drivers with
51 complex features usually required magic numbers in state 51 complex features usually required magic numbers in state
52 value of switch_dev. With extcon, such magic numbers that 52 value of switch_dev. With extcon, such magic numbers that
53 support multiple cables ( 53 support multiple cables are no more required or supported.
54 54
55 1. Define cable names at edev->supported_cable. 55 1. Define cable names at edev->supported_cable.
56 2. (Recommended) remove print_state callback. 56 2. (Recommended) remove print_state callback.
@@ -114,11 +114,8 @@ exclusive, the two cables cannot be in ATTACHED state simulteneously.
114 114
115****** ABI Location 115****** ABI Location
116 116
117 If "CONFIG_ANDROID" is enabled and "CONFIG_ANDROID_SWITCH" is 117 If "CONFIG_ANDROID" is enabled, /sys/class/switch/* are created
118disabled, /sys/class/switch/* are created as symbolic links to 118as symbolic links to /sys/class/extcon/*.
119/sys/class/extcon/*. Because CONFIG_ANDROID_SWITCH creates
120/sys/class/switch directory, we disable symboling linking if
121CONFIG_ANDROID_SWITCH is enabled.
122 119
123 The two files of switch class, name and state, are provided with 120 The two files of switch class, name and state, are provided with
124extcon, too. When the multistate support (STEP 2 of CHAPTER 1.) is 121extcon, too. When the multistate support (STEP 2 of CHAPTER 1.) is
diff --git a/MAINTAINERS b/MAINTAINERS
index 0a1475b6b358..cba11d2acd3a 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -3330,6 +3330,7 @@ EXTERNAL CONNECTOR SUBSYSTEM (EXTCON)
3330M: MyungJoo Ham <myungjoo.ham@samsung.com> 3330M: MyungJoo Ham <myungjoo.ham@samsung.com>
3331M: Chanwoo Choi <cw00.choi@samsung.com> 3331M: Chanwoo Choi <cw00.choi@samsung.com>
3332L: linux-kernel@vger.kernel.org 3332L: linux-kernel@vger.kernel.org
3333T: git git://git.kernel.org/pub/scm/linux/kernel/git/chanwoo/extcon.git
3333S: Maintained 3334S: Maintained
3334F: drivers/extcon/ 3335F: drivers/extcon/
3335F: Documentation/extcon/ 3336F: Documentation/extcon/
diff --git a/drivers/extcon/Kconfig b/drivers/extcon/Kconfig
index f1d54a3985bd..bdb5a00f1dfa 100644
--- a/drivers/extcon/Kconfig
+++ b/drivers/extcon/Kconfig
@@ -31,6 +31,16 @@ config EXTCON_ADC_JACK
31 help 31 help
32 Say Y here to enable extcon device driver based on ADC values. 32 Say Y here to enable extcon device driver based on ADC values.
33 33
34config EXTCON_MAX14577
35 tristate "MAX14577 EXTCON Support"
36 depends on MFD_MAX14577
37 select IRQ_DOMAIN
38 select REGMAP_I2C
39 help
40 If you say yes here you get support for the MUIC device of
41 Maxim MAX14577 PMIC. The MAX14577 MUIC is a USB port accessory
42 detector and switch.
43
34config EXTCON_MAX77693 44config EXTCON_MAX77693
35 tristate "MAX77693 EXTCON Support" 45 tristate "MAX77693 EXTCON Support"
36 depends on MFD_MAX77693 && INPUT 46 depends on MFD_MAX77693 && INPUT
diff --git a/drivers/extcon/Makefile b/drivers/extcon/Makefile
index 759fdae46f95..43eccc0e3448 100644
--- a/drivers/extcon/Makefile
+++ b/drivers/extcon/Makefile
@@ -7,6 +7,7 @@ obj-$(CONFIG_OF_EXTCON) += of_extcon.o
7obj-$(CONFIG_EXTCON) += extcon-class.o 7obj-$(CONFIG_EXTCON) += extcon-class.o
8obj-$(CONFIG_EXTCON_GPIO) += extcon-gpio.o 8obj-$(CONFIG_EXTCON_GPIO) += extcon-gpio.o
9obj-$(CONFIG_EXTCON_ADC_JACK) += extcon-adc-jack.o 9obj-$(CONFIG_EXTCON_ADC_JACK) += extcon-adc-jack.o
10obj-$(CONFIG_EXTCON_MAX14577) += extcon-max14577.o
10obj-$(CONFIG_EXTCON_MAX77693) += extcon-max77693.o 11obj-$(CONFIG_EXTCON_MAX77693) += extcon-max77693.o
11obj-$(CONFIG_EXTCON_MAX8997) += extcon-max8997.o 12obj-$(CONFIG_EXTCON_MAX8997) += extcon-max8997.o
12obj-$(CONFIG_EXTCON_ARIZONA) += extcon-arizona.o 13obj-$(CONFIG_EXTCON_ARIZONA) += extcon-arizona.o
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
47struct arizona_extcon_info { 56struct 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
601done:
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
599done:
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 }
diff --git a/drivers/extcon/extcon-gpio.c b/drivers/extcon/extcon-gpio.c
index 7e0dff58e494..a63a6b21c9ad 100644
--- a/drivers/extcon/extcon-gpio.c
+++ b/drivers/extcon/extcon-gpio.c
@@ -40,6 +40,7 @@ struct gpio_extcon_data {
40 int irq; 40 int irq;
41 struct delayed_work work; 41 struct delayed_work work;
42 unsigned long debounce_jiffies; 42 unsigned long debounce_jiffies;
43 bool check_on_resume;
43}; 44};
44 45
45static void gpio_extcon_work(struct work_struct *work) 46static void gpio_extcon_work(struct work_struct *work)
@@ -103,8 +104,15 @@ static int gpio_extcon_probe(struct platform_device *pdev)
103 extcon_data->gpio_active_low = pdata->gpio_active_low; 104 extcon_data->gpio_active_low = pdata->gpio_active_low;
104 extcon_data->state_on = pdata->state_on; 105 extcon_data->state_on = pdata->state_on;
105 extcon_data->state_off = pdata->state_off; 106 extcon_data->state_off = pdata->state_off;
107 extcon_data->check_on_resume = pdata->check_on_resume;
106 if (pdata->state_on && pdata->state_off) 108 if (pdata->state_on && pdata->state_off)
107 extcon_data->edev.print_state = extcon_gpio_print_state; 109 extcon_data->edev.print_state = extcon_gpio_print_state;
110
111 ret = devm_gpio_request_one(&pdev->dev, extcon_data->gpio, GPIOF_DIR_IN,
112 pdev->name);
113 if (ret < 0)
114 return ret;
115
108 if (pdata->debounce) { 116 if (pdata->debounce) {
109 ret = gpio_set_debounce(extcon_data->gpio, 117 ret = gpio_set_debounce(extcon_data->gpio,
110 pdata->debounce * 1000); 118 pdata->debounce * 1000);
@@ -117,11 +125,6 @@ static int gpio_extcon_probe(struct platform_device *pdev)
117 if (ret < 0) 125 if (ret < 0)
118 return ret; 126 return ret;
119 127
120 ret = devm_gpio_request_one(&pdev->dev, extcon_data->gpio, GPIOF_DIR_IN,
121 pdev->name);
122 if (ret < 0)
123 goto err;
124
125 INIT_DELAYED_WORK(&extcon_data->work, gpio_extcon_work); 128 INIT_DELAYED_WORK(&extcon_data->work, gpio_extcon_work);
126 129
127 extcon_data->irq = gpio_to_irq(extcon_data->gpio); 130 extcon_data->irq = gpio_to_irq(extcon_data->gpio);
@@ -159,12 +162,31 @@ static int gpio_extcon_remove(struct platform_device *pdev)
159 return 0; 162 return 0;
160} 163}
161 164
165#ifdef CONFIG_PM_SLEEP
166static int gpio_extcon_resume(struct device *dev)
167{
168 struct gpio_extcon_data *extcon_data;
169
170 extcon_data = dev_get_drvdata(dev);
171 if (extcon_data->check_on_resume)
172 queue_delayed_work(system_power_efficient_wq,
173 &extcon_data->work, extcon_data->debounce_jiffies);
174
175 return 0;
176}
177#endif
178
179static const struct dev_pm_ops gpio_extcon_pm_ops = {
180 SET_SYSTEM_SLEEP_PM_OPS(NULL, gpio_extcon_resume)
181};
182
162static struct platform_driver gpio_extcon_driver = { 183static struct platform_driver gpio_extcon_driver = {
163 .probe = gpio_extcon_probe, 184 .probe = gpio_extcon_probe,
164 .remove = gpio_extcon_remove, 185 .remove = gpio_extcon_remove,
165 .driver = { 186 .driver = {
166 .name = "extcon-gpio", 187 .name = "extcon-gpio",
167 .owner = THIS_MODULE, 188 .owner = THIS_MODULE,
189 .pm = &gpio_extcon_pm_ops,
168 }, 190 },
169}; 191};
170 192
diff --git a/drivers/extcon/extcon-max14577.c b/drivers/extcon/extcon-max14577.c
new file mode 100644
index 000000000000..3846941801b8
--- /dev/null
+++ b/drivers/extcon/extcon-max14577.c
@@ -0,0 +1,752 @@
1/*
2 * extcon-max14577.c - MAX14577 extcon driver to support MAX14577 MUIC
3 *
4 * Copyright (C) 2013 Samsung Electrnoics
5 * Chanwoo Choi <cw00.choi@samsung.com>
6 *
7 * 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 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 */
17
18#include <linux/kernel.h>
19#include <linux/module.h>
20#include <linux/i2c.h>
21#include <linux/interrupt.h>
22#include <linux/platform_device.h>
23#include <linux/mfd/max14577.h>
24#include <linux/mfd/max14577-private.h>
25#include <linux/extcon.h>
26
27#define DEV_NAME "max14577-muic"
28#define DELAY_MS_DEFAULT 17000 /* unit: millisecond */
29
30enum max14577_muic_adc_debounce_time {
31 ADC_DEBOUNCE_TIME_5MS = 0,
32 ADC_DEBOUNCE_TIME_10MS,
33 ADC_DEBOUNCE_TIME_25MS,
34 ADC_DEBOUNCE_TIME_38_62MS,
35};
36
37enum max14577_muic_status {
38 MAX14577_MUIC_STATUS1 = 0,
39 MAX14577_MUIC_STATUS2 = 1,
40 MAX14577_MUIC_STATUS_END,
41};
42
43struct max14577_muic_info {
44 struct device *dev;
45 struct max14577 *max14577;
46 struct extcon_dev *edev;
47 int prev_cable_type;
48 int prev_chg_type;
49 u8 status[MAX14577_MUIC_STATUS_END];
50
51 bool irq_adc;
52 bool irq_chg;
53 struct work_struct irq_work;
54 struct mutex mutex;
55
56 /*
57 * Use delayed workqueue to detect cable state and then
58 * notify cable state to notifiee/platform through uevent.
59 * After completing the booting of platform, the extcon provider
60 * driver should notify cable state to upper layer.
61 */
62 struct delayed_work wq_detcable;
63
64 /*
65 * Default usb/uart path whether UART/USB or AUX_UART/AUX_USB
66 * h/w path of COMP2/COMN1 on CONTROL1 register.
67 */
68 int path_usb;
69 int path_uart;
70};
71
72enum max14577_muic_cable_group {
73 MAX14577_CABLE_GROUP_ADC = 0,
74 MAX14577_CABLE_GROUP_CHG,
75};
76
77/**
78 * struct max14577_muic_irq
79 * @irq: the index of irq list of MUIC device.
80 * @name: the name of irq.
81 * @virq: the virtual irq to use irq domain
82 */
83struct max14577_muic_irq {
84 unsigned int irq;
85 const char *name;
86 unsigned int virq;
87};
88
89static struct max14577_muic_irq muic_irqs[] = {
90 { MAX14577_IRQ_INT1_ADC, "muic-ADC" },
91 { MAX14577_IRQ_INT1_ADCLOW, "muic-ADCLOW" },
92 { MAX14577_IRQ_INT1_ADCERR, "muic-ADCError" },
93 { MAX14577_IRQ_INT2_CHGTYP, "muic-CHGTYP" },
94 { MAX14577_IRQ_INT2_CHGDETRUN, "muic-CHGDETRUN" },
95 { MAX14577_IRQ_INT2_DCDTMR, "muic-DCDTMR" },
96 { MAX14577_IRQ_INT2_DBCHG, "muic-DBCHG" },
97 { MAX14577_IRQ_INT2_VBVOLT, "muic-VBVOLT" },
98};
99
100/* Define supported accessory type */
101enum max14577_muic_acc_type {
102 MAX14577_MUIC_ADC_GROUND = 0x0,
103 MAX14577_MUIC_ADC_SEND_END_BUTTON,
104 MAX14577_MUIC_ADC_REMOTE_S1_BUTTON,
105 MAX14577_MUIC_ADC_REMOTE_S2_BUTTON,
106 MAX14577_MUIC_ADC_REMOTE_S3_BUTTON,
107 MAX14577_MUIC_ADC_REMOTE_S4_BUTTON,
108 MAX14577_MUIC_ADC_REMOTE_S5_BUTTON,
109 MAX14577_MUIC_ADC_REMOTE_S6_BUTTON,
110 MAX14577_MUIC_ADC_REMOTE_S7_BUTTON,
111 MAX14577_MUIC_ADC_REMOTE_S8_BUTTON,
112 MAX14577_MUIC_ADC_REMOTE_S9_BUTTON,
113 MAX14577_MUIC_ADC_REMOTE_S10_BUTTON,
114 MAX14577_MUIC_ADC_REMOTE_S11_BUTTON,
115 MAX14577_MUIC_ADC_REMOTE_S12_BUTTON,
116 MAX14577_MUIC_ADC_RESERVED_ACC_1,
117 MAX14577_MUIC_ADC_RESERVED_ACC_2,
118 MAX14577_MUIC_ADC_RESERVED_ACC_3,
119 MAX14577_MUIC_ADC_RESERVED_ACC_4,
120 MAX14577_MUIC_ADC_RESERVED_ACC_5,
121 MAX14577_MUIC_ADC_AUDIO_DEVICE_TYPE2,
122 MAX14577_MUIC_ADC_PHONE_POWERED_DEV,
123 MAX14577_MUIC_ADC_TTY_CONVERTER,
124 MAX14577_MUIC_ADC_UART_CABLE,
125 MAX14577_MUIC_ADC_CEA936A_TYPE1_CHG,
126 MAX14577_MUIC_ADC_FACTORY_MODE_USB_OFF,
127 MAX14577_MUIC_ADC_FACTORY_MODE_USB_ON,
128 MAX14577_MUIC_ADC_AV_CABLE_NOLOAD,
129 MAX14577_MUIC_ADC_CEA936A_TYPE2_CHG,
130 MAX14577_MUIC_ADC_FACTORY_MODE_UART_OFF,
131 MAX14577_MUIC_ADC_FACTORY_MODE_UART_ON,
132 MAX14577_MUIC_ADC_AUDIO_DEVICE_TYPE1, /* with Remote and Simple Ctrl */
133 MAX14577_MUIC_ADC_OPEN,
134};
135
136/* max14577 MUIC device support below list of accessories(external connector) */
137enum {
138 EXTCON_CABLE_USB = 0,
139 EXTCON_CABLE_TA,
140 EXTCON_CABLE_FAST_CHARGER,
141 EXTCON_CABLE_SLOW_CHARGER,
142 EXTCON_CABLE_CHARGE_DOWNSTREAM,
143 EXTCON_CABLE_JIG_USB_ON,
144 EXTCON_CABLE_JIG_USB_OFF,
145 EXTCON_CABLE_JIG_UART_OFF,
146 EXTCON_CABLE_JIG_UART_ON,
147
148 _EXTCON_CABLE_NUM,
149};
150
151static const char *max14577_extcon_cable[] = {
152 [EXTCON_CABLE_USB] = "USB",
153 [EXTCON_CABLE_TA] = "TA",
154 [EXTCON_CABLE_FAST_CHARGER] = "Fast-charger",
155 [EXTCON_CABLE_SLOW_CHARGER] = "Slow-charger",
156 [EXTCON_CABLE_CHARGE_DOWNSTREAM] = "Charge-downstream",
157 [EXTCON_CABLE_JIG_USB_ON] = "JIG-USB-ON",
158 [EXTCON_CABLE_JIG_USB_OFF] = "JIG-USB-OFF",
159 [EXTCON_CABLE_JIG_UART_OFF] = "JIG-UART-OFF",
160 [EXTCON_CABLE_JIG_UART_ON] = "JIG-UART-ON",
161
162 NULL,
163};
164
165/*
166 * max14577_muic_set_debounce_time - Set the debounce time of ADC
167 * @info: the instance including private data of max14577 MUIC
168 * @time: the debounce time of ADC
169 */
170static int max14577_muic_set_debounce_time(struct max14577_muic_info *info,
171 enum max14577_muic_adc_debounce_time time)
172{
173 u8 ret;
174
175 switch (time) {
176 case ADC_DEBOUNCE_TIME_5MS:
177 case ADC_DEBOUNCE_TIME_10MS:
178 case ADC_DEBOUNCE_TIME_25MS:
179 case ADC_DEBOUNCE_TIME_38_62MS:
180 ret = max14577_update_reg(info->max14577->regmap,
181 MAX14577_MUIC_REG_CONTROL3,
182 CTRL3_ADCDBSET_MASK,
183 time << CTRL3_ADCDBSET_SHIFT);
184 if (ret) {
185 dev_err(info->dev, "failed to set ADC debounce time\n");
186 return ret;
187 }
188 break;
189 default:
190 dev_err(info->dev, "invalid ADC debounce time\n");
191 return -EINVAL;
192 }
193
194 return 0;
195};
196
197/*
198 * max14577_muic_set_path - Set hardware line according to attached cable
199 * @info: the instance including private data of max14577 MUIC
200 * @value: the path according to attached cable
201 * @attached: the state of cable (true:attached, false:detached)
202 *
203 * The max14577 MUIC device share outside H/W line among a varity of cables
204 * so, this function set internal path of H/W line according to the type of
205 * attached cable.
206 */
207static int max14577_muic_set_path(struct max14577_muic_info *info,
208 u8 val, bool attached)
209{
210 int ret = 0;
211 u8 ctrl1, ctrl2 = 0;
212
213 /* Set open state to path before changing hw path */
214 ret = max14577_update_reg(info->max14577->regmap,
215 MAX14577_MUIC_REG_CONTROL1,
216 CLEAR_IDBEN_MICEN_MASK, CTRL1_SW_OPEN);
217 if (ret < 0) {
218 dev_err(info->dev, "failed to update MUIC register\n");
219 return ret;
220 }
221
222 if (attached)
223 ctrl1 = val;
224 else
225 ctrl1 = CTRL1_SW_OPEN;
226
227 ret = max14577_update_reg(info->max14577->regmap,
228 MAX14577_MUIC_REG_CONTROL1,
229 CLEAR_IDBEN_MICEN_MASK, ctrl1);
230 if (ret < 0) {
231 dev_err(info->dev, "failed to update MUIC register\n");
232 return ret;
233 }
234
235 if (attached)
236 ctrl2 |= CTRL2_CPEN_MASK; /* LowPwr=0, CPEn=1 */
237 else
238 ctrl2 |= CTRL2_LOWPWR_MASK; /* LowPwr=1, CPEn=0 */
239
240 ret = max14577_update_reg(info->max14577->regmap,
241 MAX14577_REG_CONTROL2,
242 CTRL2_LOWPWR_MASK | CTRL2_CPEN_MASK, ctrl2);
243 if (ret < 0) {
244 dev_err(info->dev, "failed to update MUIC register\n");
245 return ret;
246 }
247
248 dev_dbg(info->dev,
249 "CONTROL1 : 0x%02x, CONTROL2 : 0x%02x, state : %s\n",
250 ctrl1, ctrl2, attached ? "attached" : "detached");
251
252 return 0;
253}
254
255/*
256 * max14577_muic_get_cable_type - Return cable type and check cable state
257 * @info: the instance including private data of max14577 MUIC
258 * @group: the path according to attached cable
259 * @attached: store cable state and return
260 *
261 * This function check the cable state either attached or detached,
262 * and then divide precise type of cable according to cable group.
263 * - max14577_CABLE_GROUP_ADC
264 * - max14577_CABLE_GROUP_CHG
265 */
266static int max14577_muic_get_cable_type(struct max14577_muic_info *info,
267 enum max14577_muic_cable_group group, bool *attached)
268{
269 int cable_type = 0;
270 int adc;
271 int chg_type;
272
273 switch (group) {
274 case MAX14577_CABLE_GROUP_ADC:
275 /*
276 * Read ADC value to check cable type and decide cable state
277 * according to cable type
278 */
279 adc = info->status[MAX14577_MUIC_STATUS1] & STATUS1_ADC_MASK;
280 adc >>= STATUS1_ADC_SHIFT;
281
282 /*
283 * Check current cable state/cable type and store cable type
284 * (info->prev_cable_type) for handling cable when cable is
285 * detached.
286 */
287 if (adc == MAX14577_MUIC_ADC_OPEN) {
288 *attached = false;
289
290 cable_type = info->prev_cable_type;
291 info->prev_cable_type = MAX14577_MUIC_ADC_OPEN;
292 } else {
293 *attached = true;
294
295 cable_type = info->prev_cable_type = adc;
296 }
297 break;
298 case MAX14577_CABLE_GROUP_CHG:
299 /*
300 * Read charger type to check cable type and decide cable state
301 * according to type of charger cable.
302 */
303 chg_type = info->status[MAX14577_MUIC_STATUS2] &
304 STATUS2_CHGTYP_MASK;
305 chg_type >>= STATUS2_CHGTYP_SHIFT;
306
307 if (chg_type == MAX14577_CHARGER_TYPE_NONE) {
308 *attached = false;
309
310 cable_type = info->prev_chg_type;
311 info->prev_chg_type = MAX14577_CHARGER_TYPE_NONE;
312 } else {
313 *attached = true;
314
315 /*
316 * Check current cable state/cable type and store cable
317 * type(info->prev_chg_type) for handling cable when
318 * charger cable is detached.
319 */
320 cable_type = info->prev_chg_type = chg_type;
321 }
322
323 break;
324 default:
325 dev_err(info->dev, "Unknown cable group (%d)\n", group);
326 cable_type = -EINVAL;
327 break;
328 }
329
330 return cable_type;
331}
332
333static int max14577_muic_jig_handler(struct max14577_muic_info *info,
334 int cable_type, bool attached)
335{
336 char cable_name[32];
337 int ret = 0;
338 u8 path = CTRL1_SW_OPEN;
339
340 dev_dbg(info->dev,
341 "external connector is %s (adc:0x%02x)\n",
342 attached ? "attached" : "detached", cable_type);
343
344 switch (cable_type) {
345 case MAX14577_MUIC_ADC_FACTORY_MODE_USB_OFF: /* ADC_JIG_USB_OFF */
346 /* PATH:AP_USB */
347 strcpy(cable_name, "JIG-USB-OFF");
348 path = CTRL1_SW_USB;
349 break;
350 case MAX14577_MUIC_ADC_FACTORY_MODE_USB_ON: /* ADC_JIG_USB_ON */
351 /* PATH:AP_USB */
352 strcpy(cable_name, "JIG-USB-ON");
353 path = CTRL1_SW_USB;
354 break;
355 case MAX14577_MUIC_ADC_FACTORY_MODE_UART_OFF: /* ADC_JIG_UART_OFF */
356 /* PATH:AP_UART */
357 strcpy(cable_name, "JIG-UART-OFF");
358 path = CTRL1_SW_UART;
359 break;
360 default:
361 dev_err(info->dev, "failed to detect %s jig cable\n",
362 attached ? "attached" : "detached");
363 return -EINVAL;
364 }
365
366 ret = max14577_muic_set_path(info, path, attached);
367 if (ret < 0)
368 return ret;
369
370 extcon_set_cable_state(info->edev, cable_name, attached);
371
372 return 0;
373}
374
375static int max14577_muic_adc_handler(struct max14577_muic_info *info)
376{
377 int cable_type;
378 bool attached;
379 int ret = 0;
380
381 /* Check accessory state which is either detached or attached */
382 cable_type = max14577_muic_get_cable_type(info,
383 MAX14577_CABLE_GROUP_ADC, &attached);
384
385 dev_dbg(info->dev,
386 "external connector is %s (adc:0x%02x, prev_adc:0x%x)\n",
387 attached ? "attached" : "detached", cable_type,
388 info->prev_cable_type);
389
390 switch (cable_type) {
391 case MAX14577_MUIC_ADC_FACTORY_MODE_USB_OFF:
392 case MAX14577_MUIC_ADC_FACTORY_MODE_USB_ON:
393 case MAX14577_MUIC_ADC_FACTORY_MODE_UART_OFF:
394 /* JIG */
395 ret = max14577_muic_jig_handler(info, cable_type, attached);
396 if (ret < 0)
397 return ret;
398 break;
399 case MAX14577_MUIC_ADC_GROUND:
400 case MAX14577_MUIC_ADC_SEND_END_BUTTON:
401 case MAX14577_MUIC_ADC_REMOTE_S1_BUTTON:
402 case MAX14577_MUIC_ADC_REMOTE_S2_BUTTON:
403 case MAX14577_MUIC_ADC_REMOTE_S3_BUTTON:
404 case MAX14577_MUIC_ADC_REMOTE_S4_BUTTON:
405 case MAX14577_MUIC_ADC_REMOTE_S5_BUTTON:
406 case MAX14577_MUIC_ADC_REMOTE_S6_BUTTON:
407 case MAX14577_MUIC_ADC_REMOTE_S7_BUTTON:
408 case MAX14577_MUIC_ADC_REMOTE_S8_BUTTON:
409 case MAX14577_MUIC_ADC_REMOTE_S9_BUTTON:
410 case MAX14577_MUIC_ADC_REMOTE_S10_BUTTON:
411 case MAX14577_MUIC_ADC_REMOTE_S11_BUTTON:
412 case MAX14577_MUIC_ADC_REMOTE_S12_BUTTON:
413 case MAX14577_MUIC_ADC_RESERVED_ACC_1:
414 case MAX14577_MUIC_ADC_RESERVED_ACC_2:
415 case MAX14577_MUIC_ADC_RESERVED_ACC_3:
416 case MAX14577_MUIC_ADC_RESERVED_ACC_4:
417 case MAX14577_MUIC_ADC_RESERVED_ACC_5:
418 case MAX14577_MUIC_ADC_AUDIO_DEVICE_TYPE2:
419 case MAX14577_MUIC_ADC_PHONE_POWERED_DEV:
420 case MAX14577_MUIC_ADC_TTY_CONVERTER:
421 case MAX14577_MUIC_ADC_UART_CABLE:
422 case MAX14577_MUIC_ADC_CEA936A_TYPE1_CHG:
423 case MAX14577_MUIC_ADC_AV_CABLE_NOLOAD:
424 case MAX14577_MUIC_ADC_CEA936A_TYPE2_CHG:
425 case MAX14577_MUIC_ADC_FACTORY_MODE_UART_ON:
426 case MAX14577_MUIC_ADC_AUDIO_DEVICE_TYPE1:
427 /*
428 * This accessory isn't used in general case if it is specially
429 * needed to detect additional accessory, should implement
430 * proper operation when this accessory is attached/detached.
431 */
432 dev_info(info->dev,
433 "accessory is %s but it isn't used (adc:0x%x)\n",
434 attached ? "attached" : "detached", cable_type);
435 return -EAGAIN;
436 default:
437 dev_err(info->dev,
438 "failed to detect %s accessory (adc:0x%x)\n",
439 attached ? "attached" : "detached", cable_type);
440 return -EINVAL;
441 }
442
443 return 0;
444}
445
446static int max14577_muic_chg_handler(struct max14577_muic_info *info)
447{
448 int chg_type;
449 bool attached;
450 int ret = 0;
451
452 chg_type = max14577_muic_get_cable_type(info,
453 MAX14577_CABLE_GROUP_CHG, &attached);
454
455 dev_dbg(info->dev,
456 "external connector is %s(chg_type:0x%x, prev_chg_type:0x%x)\n",
457 attached ? "attached" : "detached",
458 chg_type, info->prev_chg_type);
459
460 switch (chg_type) {
461 case MAX14577_CHARGER_TYPE_USB:
462 /* PATH:AP_USB */
463 ret = max14577_muic_set_path(info, info->path_usb, attached);
464 if (ret < 0)
465 return ret;
466
467 extcon_set_cable_state(info->edev, "USB", attached);
468 break;
469 case MAX14577_CHARGER_TYPE_DEDICATED_CHG:
470 extcon_set_cable_state(info->edev, "TA", attached);
471 break;
472 case MAX14577_CHARGER_TYPE_DOWNSTREAM_PORT:
473 extcon_set_cable_state(info->edev,
474 "Charge-downstream", attached);
475 break;
476 case MAX14577_CHARGER_TYPE_SPECIAL_500MA:
477 extcon_set_cable_state(info->edev, "Slow-charger", attached);
478 break;
479 case MAX14577_CHARGER_TYPE_SPECIAL_1A:
480 extcon_set_cable_state(info->edev, "Fast-charger", attached);
481 break;
482 case MAX14577_CHARGER_TYPE_NONE:
483 case MAX14577_CHARGER_TYPE_DEAD_BATTERY:
484 break;
485 default:
486 dev_err(info->dev,
487 "failed to detect %s accessory (chg_type:0x%x)\n",
488 attached ? "attached" : "detached", chg_type);
489 return -EINVAL;
490 }
491
492 return 0;
493}
494
495static void max14577_muic_irq_work(struct work_struct *work)
496{
497 struct max14577_muic_info *info = container_of(work,
498 struct max14577_muic_info, irq_work);
499 int ret = 0;
500
501 if (!info->edev)
502 return;
503
504 mutex_lock(&info->mutex);
505
506 ret = max14577_bulk_read(info->max14577->regmap,
507 MAX14577_MUIC_REG_STATUS1, info->status, 2);
508 if (ret) {
509 dev_err(info->dev, "failed to read MUIC register\n");
510 mutex_unlock(&info->mutex);
511 return;
512 }
513
514 if (info->irq_adc) {
515 ret = max14577_muic_adc_handler(info);
516 info->irq_adc = false;
517 }
518 if (info->irq_chg) {
519 ret = max14577_muic_chg_handler(info);
520 info->irq_chg = false;
521 }
522
523 if (ret < 0)
524 dev_err(info->dev, "failed to handle MUIC interrupt\n");
525
526 mutex_unlock(&info->mutex);
527
528 return;
529}
530
531static irqreturn_t max14577_muic_irq_handler(int irq, void *data)
532{
533 struct max14577_muic_info *info = data;
534 int i, irq_type = -1;
535
536 /*
537 * We may be called multiple times for different nested IRQ-s.
538 * Including changes in INT1_ADC and INT2_CGHTYP at once.
539 * However we only need to know whether it was ADC, charger
540 * or both interrupts so decode IRQ and turn on proper flags.
541 */
542 for (i = 0; i < ARRAY_SIZE(muic_irqs); i++)
543 if (irq == muic_irqs[i].virq)
544 irq_type = muic_irqs[i].irq;
545
546 switch (irq_type) {
547 case MAX14577_IRQ_INT1_ADC:
548 case MAX14577_IRQ_INT1_ADCLOW:
549 case MAX14577_IRQ_INT1_ADCERR:
550 /* Handle all of accessory except for
551 type of charger accessory */
552 info->irq_adc = true;
553 break;
554 case MAX14577_IRQ_INT2_CHGTYP:
555 case MAX14577_IRQ_INT2_CHGDETRUN:
556 case MAX14577_IRQ_INT2_DCDTMR:
557 case MAX14577_IRQ_INT2_DBCHG:
558 case MAX14577_IRQ_INT2_VBVOLT:
559 /* Handle charger accessory */
560 info->irq_chg = true;
561 break;
562 default:
563 dev_err(info->dev, "muic interrupt: irq %d occurred, skipped\n",
564 irq_type);
565 return IRQ_HANDLED;
566 }
567 schedule_work(&info->irq_work);
568
569 return IRQ_HANDLED;
570}
571
572static int max14577_muic_detect_accessory(struct max14577_muic_info *info)
573{
574 int ret = 0;
575 int adc;
576 int chg_type;
577 bool attached;
578
579 mutex_lock(&info->mutex);
580
581 /* Read STATUSx register to detect accessory */
582 ret = max14577_bulk_read(info->max14577->regmap,
583 MAX14577_MUIC_REG_STATUS1, info->status, 2);
584 if (ret) {
585 dev_err(info->dev, "failed to read MUIC register\n");
586 mutex_unlock(&info->mutex);
587 return ret;
588 }
589
590 adc = max14577_muic_get_cable_type(info, MAX14577_CABLE_GROUP_ADC,
591 &attached);
592 if (attached && adc != MAX14577_MUIC_ADC_OPEN) {
593 ret = max14577_muic_adc_handler(info);
594 if (ret < 0) {
595 dev_err(info->dev, "Cannot detect accessory\n");
596 mutex_unlock(&info->mutex);
597 return ret;
598 }
599 }
600
601 chg_type = max14577_muic_get_cable_type(info, MAX14577_CABLE_GROUP_CHG,
602 &attached);
603 if (attached && chg_type != MAX14577_CHARGER_TYPE_NONE) {
604 ret = max14577_muic_chg_handler(info);
605 if (ret < 0) {
606 dev_err(info->dev, "Cannot detect charger accessory\n");
607 mutex_unlock(&info->mutex);
608 return ret;
609 }
610 }
611
612 mutex_unlock(&info->mutex);
613
614 return 0;
615}
616
617static void max14577_muic_detect_cable_wq(struct work_struct *work)
618{
619 struct max14577_muic_info *info = container_of(to_delayed_work(work),
620 struct max14577_muic_info, wq_detcable);
621
622 max14577_muic_detect_accessory(info);
623}
624
625static int max14577_muic_probe(struct platform_device *pdev)
626{
627 struct max14577 *max14577 = dev_get_drvdata(pdev->dev.parent);
628 struct max14577_muic_info *info;
629 int delay_jiffies;
630 int ret;
631 int i;
632 u8 id;
633
634 info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
635 if (!info) {
636 dev_err(&pdev->dev, "failed to allocate memory\n");
637 return -ENOMEM;
638 }
639 info->dev = &pdev->dev;
640 info->max14577 = max14577;
641
642 platform_set_drvdata(pdev, info);
643 mutex_init(&info->mutex);
644
645 INIT_WORK(&info->irq_work, max14577_muic_irq_work);
646
647 /* Support irq domain for max14577 MUIC device */
648 for (i = 0; i < ARRAY_SIZE(muic_irqs); i++) {
649 struct max14577_muic_irq *muic_irq = &muic_irqs[i];
650 unsigned int virq = 0;
651
652 virq = regmap_irq_get_virq(max14577->irq_data, muic_irq->irq);
653 if (!virq)
654 return -EINVAL;
655 muic_irq->virq = virq;
656
657 ret = devm_request_threaded_irq(&pdev->dev, virq, NULL,
658 max14577_muic_irq_handler,
659 IRQF_NO_SUSPEND,
660 muic_irq->name, info);
661 if (ret) {
662 dev_err(&pdev->dev,
663 "failed: irq request (IRQ: %d,"
664 " error :%d)\n",
665 muic_irq->irq, ret);
666 return ret;
667 }
668 }
669
670 /* Initialize extcon device */
671 info->edev = devm_kzalloc(&pdev->dev, sizeof(*info->edev), GFP_KERNEL);
672 if (!info->edev) {
673 dev_err(&pdev->dev, "failed to allocate memory for extcon\n");
674 return -ENOMEM;
675 }
676 info->edev->name = DEV_NAME;
677 info->edev->supported_cable = max14577_extcon_cable;
678 ret = extcon_dev_register(info->edev);
679 if (ret) {
680 dev_err(&pdev->dev, "failed to register extcon device\n");
681 return ret;
682 }
683
684 /* Default h/w line path */
685 info->path_usb = CTRL1_SW_USB;
686 info->path_uart = CTRL1_SW_UART;
687 delay_jiffies = msecs_to_jiffies(DELAY_MS_DEFAULT);
688
689 /* Set initial path for UART */
690 max14577_muic_set_path(info, info->path_uart, true);
691
692 /* Check revision number of MUIC device*/
693 ret = max14577_read_reg(info->max14577->regmap,
694 MAX14577_REG_DEVICEID, &id);
695 if (ret < 0) {
696 dev_err(&pdev->dev, "failed to read revision number\n");
697 goto err_extcon;
698 }
699 dev_info(info->dev, "device ID : 0x%x\n", id);
700
701 /* Set ADC debounce time */
702 max14577_muic_set_debounce_time(info, ADC_DEBOUNCE_TIME_25MS);
703
704 /*
705 * Detect accessory after completing the initialization of platform
706 *
707 * - Use delayed workqueue to detect cable state and then
708 * notify cable state to notifiee/platform through uevent.
709 * After completing the booting of platform, the extcon provider
710 * driver should notify cable state to upper layer.
711 */
712 INIT_DELAYED_WORK(&info->wq_detcable, max14577_muic_detect_cable_wq);
713 ret = queue_delayed_work(system_power_efficient_wq, &info->wq_detcable,
714 delay_jiffies);
715 if (ret < 0) {
716 dev_err(&pdev->dev,
717 "failed to schedule delayed work for cable detect\n");
718 goto err_extcon;
719 }
720
721 return ret;
722
723err_extcon:
724 extcon_dev_unregister(info->edev);
725 return ret;
726}
727
728static int max14577_muic_remove(struct platform_device *pdev)
729{
730 struct max14577_muic_info *info = platform_get_drvdata(pdev);
731
732 cancel_work_sync(&info->irq_work);
733 extcon_dev_unregister(info->edev);
734
735 return 0;
736}
737
738static struct platform_driver max14577_muic_driver = {
739 .driver = {
740 .name = DEV_NAME,
741 .owner = THIS_MODULE,
742 },
743 .probe = max14577_muic_probe,
744 .remove = max14577_muic_remove,
745};
746
747module_platform_driver(max14577_muic_driver);
748
749MODULE_DESCRIPTION("MAXIM 14577 Extcon driver");
750MODULE_AUTHOR("Chanwoo Choi <cw00.choi@samsung.com>");
751MODULE_LICENSE("GPL");
752MODULE_ALIAS("platform:extcon-max14577");
diff --git a/drivers/extcon/extcon-palmas.c b/drivers/extcon/extcon-palmas.c
index 6c91976dd823..2aea4bcdd7f3 100644
--- a/drivers/extcon/extcon-palmas.c
+++ b/drivers/extcon/extcon-palmas.c
@@ -78,20 +78,24 @@ static irqreturn_t palmas_vbus_irq_handler(int irq, void *_palmas_usb)
78 78
79static irqreturn_t palmas_id_irq_handler(int irq, void *_palmas_usb) 79static irqreturn_t palmas_id_irq_handler(int irq, void *_palmas_usb)
80{ 80{
81 unsigned int set; 81 unsigned int set, id_src;
82 struct palmas_usb *palmas_usb = _palmas_usb; 82 struct palmas_usb *palmas_usb = _palmas_usb;
83 83
84 palmas_read(palmas_usb->palmas, PALMAS_USB_OTG_BASE, 84 palmas_read(palmas_usb->palmas, PALMAS_USB_OTG_BASE,
85 PALMAS_USB_ID_INT_LATCH_SET, &set); 85 PALMAS_USB_ID_INT_LATCH_SET, &set);
86 palmas_read(palmas_usb->palmas, PALMAS_USB_OTG_BASE,
87 PALMAS_USB_ID_INT_SRC, &id_src);
86 88
87 if (set & PALMAS_USB_ID_INT_SRC_ID_GND) { 89 if ((set & PALMAS_USB_ID_INT_SRC_ID_GND) &&
90 (id_src & PALMAS_USB_ID_INT_SRC_ID_GND)) {
88 palmas_write(palmas_usb->palmas, PALMAS_USB_OTG_BASE, 91 palmas_write(palmas_usb->palmas, PALMAS_USB_OTG_BASE,
89 PALMAS_USB_ID_INT_LATCH_CLR, 92 PALMAS_USB_ID_INT_LATCH_CLR,
90 PALMAS_USB_ID_INT_EN_HI_CLR_ID_GND); 93 PALMAS_USB_ID_INT_EN_HI_CLR_ID_GND);
91 palmas_usb->linkstat = PALMAS_USB_STATE_ID; 94 palmas_usb->linkstat = PALMAS_USB_STATE_ID;
92 extcon_set_cable_state(&palmas_usb->edev, "USB-HOST", true); 95 extcon_set_cable_state(&palmas_usb->edev, "USB-HOST", true);
93 dev_info(palmas_usb->dev, "USB-HOST cable is attached\n"); 96 dev_info(palmas_usb->dev, "USB-HOST cable is attached\n");
94 } else if (set & PALMAS_USB_ID_INT_SRC_ID_FLOAT) { 97 } else if ((set & PALMAS_USB_ID_INT_SRC_ID_FLOAT) &&
98 (id_src & PALMAS_USB_ID_INT_SRC_ID_FLOAT)) {
95 palmas_write(palmas_usb->palmas, PALMAS_USB_OTG_BASE, 99 palmas_write(palmas_usb->palmas, PALMAS_USB_OTG_BASE,
96 PALMAS_USB_ID_INT_LATCH_CLR, 100 PALMAS_USB_ID_INT_LATCH_CLR,
97 PALMAS_USB_ID_INT_EN_HI_CLR_ID_FLOAT); 101 PALMAS_USB_ID_INT_EN_HI_CLR_ID_FLOAT);
@@ -103,6 +107,11 @@ static irqreturn_t palmas_id_irq_handler(int irq, void *_palmas_usb)
103 palmas_usb->linkstat = PALMAS_USB_STATE_DISCONNECT; 107 palmas_usb->linkstat = PALMAS_USB_STATE_DISCONNECT;
104 extcon_set_cable_state(&palmas_usb->edev, "USB-HOST", false); 108 extcon_set_cable_state(&palmas_usb->edev, "USB-HOST", false);
105 dev_info(palmas_usb->dev, "USB-HOST cable is detached\n"); 109 dev_info(palmas_usb->dev, "USB-HOST cable is detached\n");
110 } else if ((palmas_usb->linkstat == PALMAS_USB_STATE_DISCONNECT) &&
111 (id_src & PALMAS_USB_ID_INT_SRC_ID_GND)) {
112 palmas_usb->linkstat = PALMAS_USB_STATE_ID;
113 extcon_set_cable_state(&palmas_usb->edev, "USB-HOST", true);
114 dev_info(palmas_usb->dev, " USB-HOST cable is attached\n");
106 } 115 }
107 116
108 return IRQ_HANDLED; 117 return IRQ_HANDLED;
@@ -269,7 +278,9 @@ static const struct dev_pm_ops palmas_pm_ops = {
269 278
270static struct of_device_id of_palmas_match_tbl[] = { 279static struct of_device_id of_palmas_match_tbl[] = {
271 { .compatible = "ti,palmas-usb", }, 280 { .compatible = "ti,palmas-usb", },
281 { .compatible = "ti,palmas-usb-vid", },
272 { .compatible = "ti,twl6035-usb", }, 282 { .compatible = "ti,twl6035-usb", },
283 { .compatible = "ti,twl6035-usb-vid", },
273 { /* end */ } 284 { /* end */ }
274}; 285};
275 286
diff --git a/include/linux/extcon/extcon-gpio.h b/include/linux/extcon/extcon-gpio.h
index 4195810f87fe..8900fdf511c6 100644
--- a/include/linux/extcon/extcon-gpio.h
+++ b/include/linux/extcon/extcon-gpio.h
@@ -51,6 +51,7 @@ struct gpio_extcon_platform_data {
51 /* if NULL, "0" or "1" will be printed */ 51 /* if NULL, "0" or "1" will be printed */
52 const char *state_on; 52 const char *state_on;
53 const char *state_off; 53 const char *state_off;
54 bool check_on_resume;
54}; 55};
55 56
56#endif /* __EXTCON_GPIO_H__ */ 57#endif /* __EXTCON_GPIO_H__ */
diff --git a/include/linux/mfd/arizona/registers.h b/include/linux/mfd/arizona/registers.h
index cb49417f8ba9..b31976595eba 100644
--- a/include/linux/mfd/arizona/registers.h
+++ b/include/linux/mfd/arizona/registers.h
@@ -2196,6 +2196,15 @@
2196/* 2196/*
2197 * R677 (0x2A5) - Mic Detect 3 2197 * R677 (0x2A5) - Mic Detect 3
2198 */ 2198 */
2199#define ARIZONA_MICD_LVL_0 0x0004 /* MICD_LVL - [2] */
2200#define ARIZONA_MICD_LVL_1 0x0008 /* MICD_LVL - [3] */
2201#define ARIZONA_MICD_LVL_2 0x0010 /* MICD_LVL - [4] */
2202#define ARIZONA_MICD_LVL_3 0x0020 /* MICD_LVL - [5] */
2203#define ARIZONA_MICD_LVL_4 0x0040 /* MICD_LVL - [6] */
2204#define ARIZONA_MICD_LVL_5 0x0080 /* MICD_LVL - [7] */
2205#define ARIZONA_MICD_LVL_6 0x0100 /* MICD_LVL - [8] */
2206#define ARIZONA_MICD_LVL_7 0x0200 /* MICD_LVL - [9] */
2207#define ARIZONA_MICD_LVL_8 0x0400 /* MICD_LVL - [10] */
2199#define ARIZONA_MICD_LVL_MASK 0x07FC /* MICD_LVL - [10:2] */ 2208#define ARIZONA_MICD_LVL_MASK 0x07FC /* MICD_LVL - [10:2] */
2200#define ARIZONA_MICD_LVL_SHIFT 2 /* MICD_LVL - [10:2] */ 2209#define ARIZONA_MICD_LVL_SHIFT 2 /* MICD_LVL - [10:2] */
2201#define ARIZONA_MICD_LVL_WIDTH 9 /* MICD_LVL - [10:2] */ 2210#define ARIZONA_MICD_LVL_WIDTH 9 /* MICD_LVL - [10:2] */