aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/extcon
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2017-02-22 14:38:22 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2017-02-22 14:38:22 -0500
commite30aee9e10bb5168579e047f05c3d13d09e23356 (patch)
tree12371bdcd52d2427cad838201997479e31b6a9c9 /drivers/extcon
parent8ff546b801e5cca0337c0f0a7234795d0a6309a1 (diff)
parent6cf18e6927c0b224f972e3042fb85770d63cb9f8 (diff)
Merge tag 'char-misc-4.11-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc
Pull char/misc driver updates from Greg KH: "Here is the big char/misc driver patchset for 4.11-rc1. Lots of different driver subsystems updated here: rework for the hyperv subsystem to handle new platforms better, mei and w1 and extcon driver updates, as well as a number of other "minor" driver updates. All of these have been in linux-next for a while with no reported issues" * tag 'char-misc-4.11-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc: (169 commits) goldfish: Sanitize the broken interrupt handler x86/platform/goldfish: Prevent unconditional loading vmbus: replace modulus operation with subtraction vmbus: constify parameters where possible vmbus: expose hv_begin/end_read vmbus: remove conditional locking of vmbus_write vmbus: add direct isr callback mode vmbus: change to per channel tasklet vmbus: put related per-cpu variable together vmbus: callback is in softirq not workqueue binder: Add support for file-descriptor arrays binder: Add support for scatter-gather binder: Add extra size to allocator binder: Refactor binder_transact() binder: Support multiple /dev instances binder: Deal with contexts in debugfs binder: Support multiple context managers binder: Split flat_binder_object auxdisplay: ht16k33: remove private workqueue auxdisplay: ht16k33: rework input device initialization ...
Diffstat (limited to 'drivers/extcon')
-rw-r--r--drivers/extcon/Kconfig10
-rw-r--r--drivers/extcon/Makefile1
-rw-r--r--drivers/extcon/devres.c2
-rw-r--r--drivers/extcon/extcon-adc-jack.c2
-rw-r--r--drivers/extcon/extcon-arizona.c20
-rw-r--r--drivers/extcon/extcon-axp288.c110
-rw-r--r--drivers/extcon/extcon-intel-int3496.c179
-rw-r--r--drivers/extcon/extcon-max14577.c6
-rw-r--r--drivers/extcon/extcon-max77693.c12
-rw-r--r--drivers/extcon/extcon-max77843.c24
-rw-r--r--drivers/extcon/extcon-palmas.c21
-rw-r--r--drivers/extcon/extcon-rt8973a.c6
-rw-r--r--drivers/extcon/extcon-sm5502.c6
-rw-r--r--drivers/extcon/extcon-usb-gpio.c7
-rw-r--r--drivers/extcon/extcon.c43
-rw-r--r--drivers/extcon/extcon.h62
16 files changed, 377 insertions, 134 deletions
diff --git a/drivers/extcon/Kconfig b/drivers/extcon/Kconfig
index 04788d92ea52..96bbae579c0b 100644
--- a/drivers/extcon/Kconfig
+++ b/drivers/extcon/Kconfig
@@ -42,6 +42,16 @@ config EXTCON_GPIO
42 Say Y here to enable GPIO based extcon support. Note that GPIO 42 Say Y here to enable GPIO based extcon support. Note that GPIO
43 extcon supports single state per extcon instance. 43 extcon supports single state per extcon instance.
44 44
45config EXTCON_INTEL_INT3496
46 tristate "Intel INT3496 ACPI device extcon driver"
47 depends on GPIOLIB && ACPI
48 help
49 Say Y here to enable extcon support for USB OTG ports controlled by
50 an Intel INT3496 ACPI device.
51
52 This ACPI device is typically found on Intel Baytrail or Cherrytrail
53 based tablets, or other Baytrail / Cherrytrail devices.
54
45config EXTCON_MAX14577 55config EXTCON_MAX14577
46 tristate "Maxim MAX14577/77836 EXTCON Support" 56 tristate "Maxim MAX14577/77836 EXTCON Support"
47 depends on MFD_MAX14577 57 depends on MFD_MAX14577
diff --git a/drivers/extcon/Makefile b/drivers/extcon/Makefile
index 31a0a999c4fb..237ac3f953c2 100644
--- a/drivers/extcon/Makefile
+++ b/drivers/extcon/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_EXTCON_ADC_JACK) += extcon-adc-jack.o
8obj-$(CONFIG_EXTCON_ARIZONA) += extcon-arizona.o 8obj-$(CONFIG_EXTCON_ARIZONA) += extcon-arizona.o
9obj-$(CONFIG_EXTCON_AXP288) += extcon-axp288.o 9obj-$(CONFIG_EXTCON_AXP288) += extcon-axp288.o
10obj-$(CONFIG_EXTCON_GPIO) += extcon-gpio.o 10obj-$(CONFIG_EXTCON_GPIO) += extcon-gpio.o
11obj-$(CONFIG_EXTCON_INTEL_INT3496) += extcon-intel-int3496.o
11obj-$(CONFIG_EXTCON_MAX14577) += extcon-max14577.o 12obj-$(CONFIG_EXTCON_MAX14577) += extcon-max14577.o
12obj-$(CONFIG_EXTCON_MAX3355) += extcon-max3355.o 13obj-$(CONFIG_EXTCON_MAX3355) += extcon-max3355.o
13obj-$(CONFIG_EXTCON_MAX77693) += extcon-max77693.o 14obj-$(CONFIG_EXTCON_MAX77693) += extcon-max77693.o
diff --git a/drivers/extcon/devres.c b/drivers/extcon/devres.c
index e686acd1c459..b40eb1805927 100644
--- a/drivers/extcon/devres.c
+++ b/drivers/extcon/devres.c
@@ -14,7 +14,7 @@
14 * GNU General Public License for more details. 14 * GNU General Public License for more details.
15 */ 15 */
16 16
17#include <linux/extcon.h> 17#include "extcon.h"
18 18
19static int devm_extcon_dev_match(struct device *dev, void *res, void *data) 19static int devm_extcon_dev_match(struct device *dev, void *res, void *data)
20{ 20{
diff --git a/drivers/extcon/extcon-adc-jack.c b/drivers/extcon/extcon-adc-jack.c
index bc538708c753..6f6537ab0a79 100644
--- a/drivers/extcon/extcon-adc-jack.c
+++ b/drivers/extcon/extcon-adc-jack.c
@@ -67,7 +67,7 @@ static void adc_jack_handler(struct work_struct *work)
67 67
68 ret = iio_read_channel_raw(data->chan, &adc_val); 68 ret = iio_read_channel_raw(data->chan, &adc_val);
69 if (ret < 0) { 69 if (ret < 0) {
70 dev_err(&data->edev->dev, "read channel() error: %d\n", ret); 70 dev_err(data->dev, "read channel() error: %d\n", ret);
71 return; 71 return;
72 } 72 }
73 73
diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c
index d836d4ce5ee4..ed78b7c26627 100644
--- a/drivers/extcon/extcon-arizona.c
+++ b/drivers/extcon/extcon-arizona.c
@@ -236,12 +236,8 @@ static void arizona_extcon_set_mode(struct arizona_extcon_info *info, int mode)
236 236
237 mode %= info->micd_num_modes; 237 mode %= info->micd_num_modes;
238 238
239 if (arizona->pdata.micd_pol_gpio > 0) 239 gpiod_set_value_cansleep(info->micd_pol_gpio,
240 gpio_set_value_cansleep(arizona->pdata.micd_pol_gpio, 240 info->micd_modes[mode].gpio);
241 info->micd_modes[mode].gpio);
242 else
243 gpiod_set_value_cansleep(info->micd_pol_gpio,
244 info->micd_modes[mode].gpio);
245 241
246 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1, 242 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
247 ARIZONA_MICD_BIAS_SRC_MASK, 243 ARIZONA_MICD_BIAS_SRC_MASK,
@@ -1412,21 +1408,21 @@ static int arizona_extcon_probe(struct platform_device *pdev)
1412 regmap_update_bits(arizona->regmap, ARIZONA_GP_SWITCH_1, 1408 regmap_update_bits(arizona->regmap, ARIZONA_GP_SWITCH_1,
1413 ARIZONA_SW1_MODE_MASK, arizona->pdata.gpsw); 1409 ARIZONA_SW1_MODE_MASK, arizona->pdata.gpsw);
1414 1410
1415 if (arizona->pdata.micd_pol_gpio > 0) { 1411 if (pdata->micd_pol_gpio > 0) {
1416 if (info->micd_modes[0].gpio) 1412 if (info->micd_modes[0].gpio)
1417 mode = GPIOF_OUT_INIT_HIGH; 1413 mode = GPIOF_OUT_INIT_HIGH;
1418 else 1414 else
1419 mode = GPIOF_OUT_INIT_LOW; 1415 mode = GPIOF_OUT_INIT_LOW;
1420 1416
1421 ret = devm_gpio_request_one(&pdev->dev, 1417 ret = devm_gpio_request_one(&pdev->dev, pdata->micd_pol_gpio,
1422 arizona->pdata.micd_pol_gpio, 1418 mode, "MICD polarity");
1423 mode,
1424 "MICD polarity");
1425 if (ret != 0) { 1419 if (ret != 0) {
1426 dev_err(arizona->dev, "Failed to request GPIO%d: %d\n", 1420 dev_err(arizona->dev, "Failed to request GPIO%d: %d\n",
1427 arizona->pdata.micd_pol_gpio, ret); 1421 pdata->micd_pol_gpio, ret);
1428 goto err_register; 1422 goto err_register;
1429 } 1423 }
1424
1425 info->micd_pol_gpio = gpio_to_desc(pdata->micd_pol_gpio);
1430 } else { 1426 } else {
1431 if (info->micd_modes[0].gpio) 1427 if (info->micd_modes[0].gpio)
1432 mode = GPIOD_OUT_HIGH; 1428 mode = GPIOD_OUT_HIGH;
diff --git a/drivers/extcon/extcon-axp288.c b/drivers/extcon/extcon-axp288.c
index 42f41e808292..f4fd03e58e37 100644
--- a/drivers/extcon/extcon-axp288.c
+++ b/drivers/extcon/extcon-axp288.c
@@ -21,7 +21,6 @@
21#include <linux/interrupt.h> 21#include <linux/interrupt.h>
22#include <linux/platform_device.h> 22#include <linux/platform_device.h>
23#include <linux/property.h> 23#include <linux/property.h>
24#include <linux/usb/phy.h>
25#include <linux/notifier.h> 24#include <linux/notifier.h>
26#include <linux/extcon.h> 25#include <linux/extcon.h>
27#include <linux/regmap.h> 26#include <linux/regmap.h>
@@ -71,12 +70,6 @@
71#define DET_STAT_CDP 2 70#define DET_STAT_CDP 2
72#define DET_STAT_DCP 3 71#define DET_STAT_DCP 3
73 72
74/* IRQ enable-1 register */
75#define PWRSRC_IRQ_CFG_MASK (BIT(4)|BIT(3)|BIT(2))
76
77/* IRQ enable-6 register */
78#define BC12_IRQ_CFG_MASK BIT(1)
79
80enum axp288_extcon_reg { 73enum axp288_extcon_reg {
81 AXP288_PS_STAT_REG = 0x00, 74 AXP288_PS_STAT_REG = 0x00,
82 AXP288_PS_BOOT_REASON_REG = 0x02, 75 AXP288_PS_BOOT_REASON_REG = 0x02,
@@ -84,8 +77,6 @@ enum axp288_extcon_reg {
84 AXP288_BC_VBUS_CNTL_REG = 0x2d, 77 AXP288_BC_VBUS_CNTL_REG = 0x2d,
85 AXP288_BC_USB_STAT_REG = 0x2e, 78 AXP288_BC_USB_STAT_REG = 0x2e,
86 AXP288_BC_DET_STAT_REG = 0x2f, 79 AXP288_BC_DET_STAT_REG = 0x2f,
87 AXP288_PWRSRC_IRQ_CFG_REG = 0x40,
88 AXP288_BC12_IRQ_CFG_REG = 0x45,
89}; 80};
90 81
91enum axp288_mux_select { 82enum axp288_mux_select {
@@ -105,6 +96,7 @@ static const unsigned int axp288_extcon_cables[] = {
105 EXTCON_CHG_USB_SDP, 96 EXTCON_CHG_USB_SDP,
106 EXTCON_CHG_USB_CDP, 97 EXTCON_CHG_USB_CDP,
107 EXTCON_CHG_USB_DCP, 98 EXTCON_CHG_USB_DCP,
99 EXTCON_USB,
108 EXTCON_NONE, 100 EXTCON_NONE,
109}; 101};
110 102
@@ -112,11 +104,11 @@ struct axp288_extcon_info {
112 struct device *dev; 104 struct device *dev;
113 struct regmap *regmap; 105 struct regmap *regmap;
114 struct regmap_irq_chip_data *regmap_irqc; 106 struct regmap_irq_chip_data *regmap_irqc;
115 struct axp288_extcon_pdata *pdata; 107 struct gpio_desc *gpio_mux_cntl;
116 int irq[EXTCON_IRQ_END]; 108 int irq[EXTCON_IRQ_END];
117 struct extcon_dev *edev; 109 struct extcon_dev *edev;
118 struct notifier_block extcon_nb; 110 struct notifier_block extcon_nb;
119 struct usb_phy *otg; 111 unsigned int previous_cable;
120}; 112};
121 113
122/* Power up/down reason string array */ 114/* Power up/down reason string array */
@@ -156,10 +148,9 @@ static void axp288_extcon_log_rsi(struct axp288_extcon_info *info)
156 148
157static int axp288_handle_chrg_det_event(struct axp288_extcon_info *info) 149static int axp288_handle_chrg_det_event(struct axp288_extcon_info *info)
158{ 150{
159 static bool notify_otg, notify_charger;
160 static unsigned int cable;
161 int ret, stat, cfg, pwr_stat; 151 int ret, stat, cfg, pwr_stat;
162 u8 chrg_type; 152 u8 chrg_type;
153 unsigned int cable = info->previous_cable;
163 bool vbus_attach = false; 154 bool vbus_attach = false;
164 155
165 ret = regmap_read(info->regmap, AXP288_PS_STAT_REG, &pwr_stat); 156 ret = regmap_read(info->regmap, AXP288_PS_STAT_REG, &pwr_stat);
@@ -168,9 +159,9 @@ static int axp288_handle_chrg_det_event(struct axp288_extcon_info *info)
168 return ret; 159 return ret;
169 } 160 }
170 161
171 vbus_attach = (pwr_stat & PS_STAT_VBUS_PRESENT); 162 vbus_attach = (pwr_stat & PS_STAT_VBUS_VALID);
172 if (!vbus_attach) 163 if (!vbus_attach)
173 goto notify_otg; 164 goto no_vbus;
174 165
175 /* Check charger detection completion status */ 166 /* Check charger detection completion status */
176 ret = regmap_read(info->regmap, AXP288_BC_GLOBAL_REG, &cfg); 167 ret = regmap_read(info->regmap, AXP288_BC_GLOBAL_REG, &cfg);
@@ -190,19 +181,14 @@ static int axp288_handle_chrg_det_event(struct axp288_extcon_info *info)
190 switch (chrg_type) { 181 switch (chrg_type) {
191 case DET_STAT_SDP: 182 case DET_STAT_SDP:
192 dev_dbg(info->dev, "sdp cable is connected\n"); 183 dev_dbg(info->dev, "sdp cable is connected\n");
193 notify_otg = true;
194 notify_charger = true;
195 cable = EXTCON_CHG_USB_SDP; 184 cable = EXTCON_CHG_USB_SDP;
196 break; 185 break;
197 case DET_STAT_CDP: 186 case DET_STAT_CDP:
198 dev_dbg(info->dev, "cdp cable is connected\n"); 187 dev_dbg(info->dev, "cdp cable is connected\n");
199 notify_otg = true;
200 notify_charger = true;
201 cable = EXTCON_CHG_USB_CDP; 188 cable = EXTCON_CHG_USB_CDP;
202 break; 189 break;
203 case DET_STAT_DCP: 190 case DET_STAT_DCP:
204 dev_dbg(info->dev, "dcp cable is connected\n"); 191 dev_dbg(info->dev, "dcp cable is connected\n");
205 notify_charger = true;
206 cable = EXTCON_CHG_USB_DCP; 192 cable = EXTCON_CHG_USB_DCP;
207 break; 193 break;
208 default: 194 default:
@@ -210,27 +196,28 @@ static int axp288_handle_chrg_det_event(struct axp288_extcon_info *info)
210 "disconnect or unknown or ID event\n"); 196 "disconnect or unknown or ID event\n");
211 } 197 }
212 198
213notify_otg: 199no_vbus:
214 if (notify_otg) { 200 /*
215 /* 201 * If VBUS is absent Connect D+/D- lines to PMIC for BC
216 * If VBUS is absent Connect D+/D- lines to PMIC for BC 202 * detection. Else connect them to SOC for USB communication.
217 * detection. Else connect them to SOC for USB communication. 203 */
218 */ 204 if (info->gpio_mux_cntl)
219 if (info->pdata->gpio_mux_cntl) 205 gpiod_set_value(info->gpio_mux_cntl,
220 gpiod_set_value(info->pdata->gpio_mux_cntl, 206 vbus_attach ? EXTCON_GPIO_MUX_SEL_SOC
221 vbus_attach ? EXTCON_GPIO_MUX_SEL_SOC 207 : EXTCON_GPIO_MUX_SEL_PMIC);
222 : EXTCON_GPIO_MUX_SEL_PMIC); 208
223 209 extcon_set_state_sync(info->edev, info->previous_cable, false);
224 atomic_notifier_call_chain(&info->otg->notifier, 210 if (info->previous_cable == EXTCON_CHG_USB_SDP)
225 vbus_attach ? USB_EVENT_VBUS : USB_EVENT_NONE, NULL); 211 extcon_set_state_sync(info->edev, EXTCON_USB, false);
226 } 212
227 213 if (vbus_attach) {
228 if (notify_charger)
229 extcon_set_state_sync(info->edev, cable, vbus_attach); 214 extcon_set_state_sync(info->edev, cable, vbus_attach);
215 if (cable == EXTCON_CHG_USB_SDP)
216 extcon_set_state_sync(info->edev, EXTCON_USB,
217 vbus_attach);
230 218
231 /* Clear the flags on disconnect event */ 219 info->previous_cable = cable;
232 if (!vbus_attach) 220 }
233 notify_otg = notify_charger = false;
234 221
235 return 0; 222 return 0;
236 223
@@ -253,15 +240,10 @@ static irqreturn_t axp288_extcon_isr(int irq, void *data)
253 return IRQ_HANDLED; 240 return IRQ_HANDLED;
254} 241}
255 242
256static void axp288_extcon_enable_irq(struct axp288_extcon_info *info) 243static void axp288_extcon_enable(struct axp288_extcon_info *info)
257{ 244{
258 /* Unmask VBUS interrupt */
259 regmap_write(info->regmap, AXP288_PWRSRC_IRQ_CFG_REG,
260 PWRSRC_IRQ_CFG_MASK);
261 regmap_update_bits(info->regmap, AXP288_BC_GLOBAL_REG, 245 regmap_update_bits(info->regmap, AXP288_BC_GLOBAL_REG,
262 BC_GLOBAL_RUN, 0); 246 BC_GLOBAL_RUN, 0);
263 /* Unmask the BC1.2 complete interrupts */
264 regmap_write(info->regmap, AXP288_BC12_IRQ_CFG_REG, BC12_IRQ_CFG_MASK);
265 /* Enable the charger detection logic */ 247 /* Enable the charger detection logic */
266 regmap_update_bits(info->regmap, AXP288_BC_GLOBAL_REG, 248 regmap_update_bits(info->regmap, AXP288_BC_GLOBAL_REG,
267 BC_GLOBAL_RUN, BC_GLOBAL_RUN); 249 BC_GLOBAL_RUN, BC_GLOBAL_RUN);
@@ -271,6 +253,7 @@ static int axp288_extcon_probe(struct platform_device *pdev)
271{ 253{
272 struct axp288_extcon_info *info; 254 struct axp288_extcon_info *info;
273 struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent); 255 struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent);
256 struct axp288_extcon_pdata *pdata = pdev->dev.platform_data;
274 int ret, i, pirq, gpio; 257 int ret, i, pirq, gpio;
275 258
276 info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); 259 info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
@@ -280,15 +263,10 @@ static int axp288_extcon_probe(struct platform_device *pdev)
280 info->dev = &pdev->dev; 263 info->dev = &pdev->dev;
281 info->regmap = axp20x->regmap; 264 info->regmap = axp20x->regmap;
282 info->regmap_irqc = axp20x->regmap_irqc; 265 info->regmap_irqc = axp20x->regmap_irqc;
283 info->pdata = pdev->dev.platform_data; 266 info->previous_cable = EXTCON_NONE;
284 267 if (pdata)
285 if (!info->pdata) { 268 info->gpio_mux_cntl = pdata->gpio_mux_cntl;
286 /* Try ACPI provided pdata via device properties */ 269
287 if (!device_property_present(&pdev->dev,
288 "axp288_extcon_data\n"))
289 dev_err(&pdev->dev, "failed to get platform data\n");
290 return -ENODEV;
291 }
292 platform_set_drvdata(pdev, info); 270 platform_set_drvdata(pdev, info);
293 271
294 axp288_extcon_log_rsi(info); 272 axp288_extcon_log_rsi(info);
@@ -308,23 +286,16 @@ static int axp288_extcon_probe(struct platform_device *pdev)
308 return ret; 286 return ret;
309 } 287 }
310 288
311 /* Get otg transceiver phy */
312 info->otg = devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2);
313 if (IS_ERR(info->otg)) {
314 dev_err(&pdev->dev, "failed to get otg transceiver\n");
315 return PTR_ERR(info->otg);
316 }
317
318 /* Set up gpio control for USB Mux */ 289 /* Set up gpio control for USB Mux */
319 if (info->pdata->gpio_mux_cntl) { 290 if (info->gpio_mux_cntl) {
320 gpio = desc_to_gpio(info->pdata->gpio_mux_cntl); 291 gpio = desc_to_gpio(info->gpio_mux_cntl);
321 ret = devm_gpio_request(&pdev->dev, gpio, "USB_MUX"); 292 ret = devm_gpio_request(&pdev->dev, gpio, "USB_MUX");
322 if (ret < 0) { 293 if (ret < 0) {
323 dev_err(&pdev->dev, 294 dev_err(&pdev->dev,
324 "failed to request the gpio=%d\n", gpio); 295 "failed to request the gpio=%d\n", gpio);
325 return ret; 296 return ret;
326 } 297 }
327 gpiod_direction_output(info->pdata->gpio_mux_cntl, 298 gpiod_direction_output(info->gpio_mux_cntl,
328 EXTCON_GPIO_MUX_SEL_PMIC); 299 EXTCON_GPIO_MUX_SEL_PMIC);
329 } 300 }
330 301
@@ -349,14 +320,21 @@ static int axp288_extcon_probe(struct platform_device *pdev)
349 } 320 }
350 } 321 }
351 322
352 /* Enable interrupts */ 323 /* Start charger cable type detection */
353 axp288_extcon_enable_irq(info); 324 axp288_extcon_enable(info);
354 325
355 return 0; 326 return 0;
356} 327}
357 328
329static const struct platform_device_id axp288_extcon_table[] = {
330 { .name = "axp288_extcon" },
331 {},
332};
333MODULE_DEVICE_TABLE(platform, axp288_extcon_table);
334
358static struct platform_driver axp288_extcon_driver = { 335static struct platform_driver axp288_extcon_driver = {
359 .probe = axp288_extcon_probe, 336 .probe = axp288_extcon_probe,
337 .id_table = axp288_extcon_table,
360 .driver = { 338 .driver = {
361 .name = "axp288_extcon", 339 .name = "axp288_extcon",
362 }, 340 },
diff --git a/drivers/extcon/extcon-intel-int3496.c b/drivers/extcon/extcon-intel-int3496.c
new file mode 100644
index 000000000000..a3131b036de6
--- /dev/null
+++ b/drivers/extcon/extcon-intel-int3496.c
@@ -0,0 +1,179 @@
1/*
2 * Intel INT3496 ACPI device extcon driver
3 *
4 * Copyright (c) 2016 Hans de Goede <hdegoede@redhat.com>
5 *
6 * Based on android x86 kernel code which is:
7 *
8 * Copyright (c) 2014, Intel Corporation.
9 * Author: David Cohen <david.a.cohen@linux.intel.com>
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License version 2 as
13 * published by the Free Software Foundation.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 */
20
21#include <linux/acpi.h>
22#include <linux/extcon.h>
23#include <linux/gpio.h>
24#include <linux/interrupt.h>
25#include <linux/module.h>
26#include <linux/platform_device.h>
27
28#define INT3496_GPIO_USB_ID 0
29#define INT3496_GPIO_VBUS_EN 1
30#define INT3496_GPIO_USB_MUX 2
31#define DEBOUNCE_TIME msecs_to_jiffies(50)
32
33struct int3496_data {
34 struct device *dev;
35 struct extcon_dev *edev;
36 struct delayed_work work;
37 struct gpio_desc *gpio_usb_id;
38 struct gpio_desc *gpio_vbus_en;
39 struct gpio_desc *gpio_usb_mux;
40 int usb_id_irq;
41};
42
43static const unsigned int int3496_cable[] = {
44 EXTCON_USB_HOST,
45 EXTCON_NONE,
46};
47
48static void int3496_do_usb_id(struct work_struct *work)
49{
50 struct int3496_data *data =
51 container_of(work, struct int3496_data, work.work);
52 int id = gpiod_get_value_cansleep(data->gpio_usb_id);
53
54 /* id == 1: PERIPHERAL, id == 0: HOST */
55 dev_dbg(data->dev, "Connected %s cable\n", id ? "PERIPHERAL" : "HOST");
56
57 /*
58 * Peripheral: set USB mux to peripheral and disable VBUS
59 * Host: set USB mux to host and enable VBUS
60 */
61 if (!IS_ERR(data->gpio_usb_mux))
62 gpiod_direction_output(data->gpio_usb_mux, id);
63
64 if (!IS_ERR(data->gpio_vbus_en))
65 gpiod_direction_output(data->gpio_vbus_en, !id);
66
67 extcon_set_state_sync(data->edev, EXTCON_USB_HOST, !id);
68}
69
70static irqreturn_t int3496_thread_isr(int irq, void *priv)
71{
72 struct int3496_data *data = priv;
73
74 /* Let the pin settle before processing it */
75 mod_delayed_work(system_wq, &data->work, DEBOUNCE_TIME);
76
77 return IRQ_HANDLED;
78}
79
80static int int3496_probe(struct platform_device *pdev)
81{
82 struct device *dev = &pdev->dev;
83 struct int3496_data *data;
84 int ret;
85
86 data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
87 if (!data)
88 return -ENOMEM;
89
90 data->dev = dev;
91 INIT_DELAYED_WORK(&data->work, int3496_do_usb_id);
92
93 data->gpio_usb_id = devm_gpiod_get_index(dev, "id",
94 INT3496_GPIO_USB_ID,
95 GPIOD_IN);
96 if (IS_ERR(data->gpio_usb_id)) {
97 ret = PTR_ERR(data->gpio_usb_id);
98 dev_err(dev, "can't request USB ID GPIO: %d\n", ret);
99 return ret;
100 }
101
102 data->usb_id_irq = gpiod_to_irq(data->gpio_usb_id);
103 if (data->usb_id_irq <= 0) {
104 dev_err(dev, "can't get USB ID IRQ: %d\n", data->usb_id_irq);
105 return -EINVAL;
106 }
107
108 data->gpio_vbus_en = devm_gpiod_get_index(dev, "vbus en",
109 INT3496_GPIO_VBUS_EN,
110 GPIOD_ASIS);
111 if (IS_ERR(data->gpio_vbus_en))
112 dev_info(dev, "can't request VBUS EN GPIO\n");
113
114 data->gpio_usb_mux = devm_gpiod_get_index(dev, "usb mux",
115 INT3496_GPIO_USB_MUX,
116 GPIOD_ASIS);
117 if (IS_ERR(data->gpio_usb_mux))
118 dev_info(dev, "can't request USB MUX GPIO\n");
119
120 /* register extcon device */
121 data->edev = devm_extcon_dev_allocate(dev, int3496_cable);
122 if (IS_ERR(data->edev))
123 return -ENOMEM;
124
125 ret = devm_extcon_dev_register(dev, data->edev);
126 if (ret < 0) {
127 dev_err(dev, "can't register extcon device: %d\n", ret);
128 return ret;
129 }
130
131 ret = devm_request_threaded_irq(dev, data->usb_id_irq,
132 NULL, int3496_thread_isr,
133 IRQF_SHARED | IRQF_ONESHOT |
134 IRQF_TRIGGER_RISING |
135 IRQF_TRIGGER_FALLING,
136 dev_name(dev), data);
137 if (ret < 0) {
138 dev_err(dev, "can't request IRQ for USB ID GPIO: %d\n", ret);
139 return ret;
140 }
141
142 /* queue initial processing of id-pin */
143 queue_delayed_work(system_wq, &data->work, 0);
144
145 platform_set_drvdata(pdev, data);
146
147 return 0;
148}
149
150static int int3496_remove(struct platform_device *pdev)
151{
152 struct int3496_data *data = platform_get_drvdata(pdev);
153
154 devm_free_irq(&pdev->dev, data->usb_id_irq, data);
155 cancel_delayed_work_sync(&data->work);
156
157 return 0;
158}
159
160static struct acpi_device_id int3496_acpi_match[] = {
161 { "INT3496" },
162 { }
163};
164MODULE_DEVICE_TABLE(acpi, int3496_acpi_match);
165
166static struct platform_driver int3496_driver = {
167 .driver = {
168 .name = "intel-int3496",
169 .acpi_match_table = int3496_acpi_match,
170 },
171 .probe = int3496_probe,
172 .remove = int3496_remove,
173};
174
175module_platform_driver(int3496_driver);
176
177MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
178MODULE_DESCRIPTION("Intel INT3496 ACPI device extcon driver");
179MODULE_LICENSE("GPL");
diff --git a/drivers/extcon/extcon-max14577.c b/drivers/extcon/extcon-max14577.c
index 12e26c4e7763..f6414b7fa5bc 100644
--- a/drivers/extcon/extcon-max14577.c
+++ b/drivers/extcon/extcon-max14577.c
@@ -531,8 +531,10 @@ static int max14577_parse_irq(struct max14577_muic_info *info, int irq_type)
531 case MAX14577_IRQ_INT1_ADC: 531 case MAX14577_IRQ_INT1_ADC:
532 case MAX14577_IRQ_INT1_ADCLOW: 532 case MAX14577_IRQ_INT1_ADCLOW:
533 case MAX14577_IRQ_INT1_ADCERR: 533 case MAX14577_IRQ_INT1_ADCERR:
534 /* Handle all of accessory except for 534 /*
535 type of charger accessory */ 535 * Handle all of accessory except for
536 * type of charger accessory.
537 */
536 info->irq_adc = true; 538 info->irq_adc = true;
537 return 1; 539 return 1;
538 case MAX14577_IRQ_INT2_CHGTYP: 540 case MAX14577_IRQ_INT2_CHGTYP:
diff --git a/drivers/extcon/extcon-max77693.c b/drivers/extcon/extcon-max77693.c
index 68dbcb814b2f..62163468f205 100644
--- a/drivers/extcon/extcon-max77693.c
+++ b/drivers/extcon/extcon-max77693.c
@@ -188,8 +188,10 @@ enum max77693_muic_acc_type {
188 MAX77693_MUIC_ADC_AUDIO_MODE_REMOTE, 188 MAX77693_MUIC_ADC_AUDIO_MODE_REMOTE,
189 MAX77693_MUIC_ADC_OPEN, 189 MAX77693_MUIC_ADC_OPEN,
190 190
191 /* The below accessories have same ADC value so ADCLow and 191 /*
192 ADC1K bit is used to separate specific accessory */ 192 * The below accessories have same ADC value so ADCLow and
193 * ADC1K bit is used to separate specific accessory.
194 */
193 /* ADC|VBVolot|ADCLow|ADC1K| */ 195 /* ADC|VBVolot|ADCLow|ADC1K| */
194 MAX77693_MUIC_GND_USB_HOST = 0x100, /* 0x0| 0| 0| 0| */ 196 MAX77693_MUIC_GND_USB_HOST = 0x100, /* 0x0| 0| 0| 0| */
195 MAX77693_MUIC_GND_USB_HOST_VB = 0x104, /* 0x0| 1| 0| 0| */ 197 MAX77693_MUIC_GND_USB_HOST_VB = 0x104, /* 0x0| 1| 0| 0| */
@@ -970,8 +972,10 @@ static void max77693_muic_irq_work(struct work_struct *work)
970 case MAX77693_MUIC_IRQ_INT1_ADC_LOW: 972 case MAX77693_MUIC_IRQ_INT1_ADC_LOW:
971 case MAX77693_MUIC_IRQ_INT1_ADC_ERR: 973 case MAX77693_MUIC_IRQ_INT1_ADC_ERR:
972 case MAX77693_MUIC_IRQ_INT1_ADC1K: 974 case MAX77693_MUIC_IRQ_INT1_ADC1K:
973 /* Handle all of accessory except for 975 /*
974 type of charger accessory */ 976 * Handle all of accessory except for
977 * type of charger accessory.
978 */
975 ret = max77693_muic_adc_handler(info); 979 ret = max77693_muic_adc_handler(info);
976 break; 980 break;
977 case MAX77693_MUIC_IRQ_INT2_CHGTYP: 981 case MAX77693_MUIC_IRQ_INT2_CHGTYP:
diff --git a/drivers/extcon/extcon-max77843.c b/drivers/extcon/extcon-max77843.c
index 5d11fdf36e94..6e722d552cf1 100644
--- a/drivers/extcon/extcon-max77843.c
+++ b/drivers/extcon/extcon-max77843.c
@@ -97,8 +97,10 @@ enum max77843_muic_accessory_type {
97 MAX77843_MUIC_ADC_AUDIO_DEVICE_TYPE1, 97 MAX77843_MUIC_ADC_AUDIO_DEVICE_TYPE1,
98 MAX77843_MUIC_ADC_OPEN, 98 MAX77843_MUIC_ADC_OPEN,
99 99
100 /* The blow accessories should check 100 /*
101 not only ADC value but also ADC1K and VBVolt value. */ 101 * The below accessories should check
102 * not only ADC value but also ADC1K and VBVolt value.
103 */
102 /* Offset|ADC1K|VBVolt| */ 104 /* Offset|ADC1K|VBVolt| */
103 MAX77843_MUIC_GND_USB_HOST = 0x100, /* 0x1| 0| 0| */ 105 MAX77843_MUIC_GND_USB_HOST = 0x100, /* 0x1| 0| 0| */
104 MAX77843_MUIC_GND_USB_HOST_VB = 0x101, /* 0x1| 0| 1| */ 106 MAX77843_MUIC_GND_USB_HOST_VB = 0x101, /* 0x1| 0| 1| */
@@ -265,16 +267,20 @@ static int max77843_muic_get_cable_type(struct max77843_muic_info *info,
265 /* Check GROUND accessory with charger cable */ 267 /* Check GROUND accessory with charger cable */
266 if (adc == MAX77843_MUIC_ADC_GROUND) { 268 if (adc == MAX77843_MUIC_ADC_GROUND) {
267 if (chg_type == MAX77843_MUIC_CHG_NONE) { 269 if (chg_type == MAX77843_MUIC_CHG_NONE) {
268 /* The following state when charger cable is 270 /*
271 * The following state when charger cable is
269 * disconnected but the GROUND accessory still 272 * disconnected but the GROUND accessory still
270 * connected */ 273 * connected.
274 */
271 *attached = false; 275 *attached = false;
272 cable_type = info->prev_chg_type; 276 cable_type = info->prev_chg_type;
273 info->prev_chg_type = MAX77843_MUIC_CHG_NONE; 277 info->prev_chg_type = MAX77843_MUIC_CHG_NONE;
274 } else { 278 } else {
275 279
276 /* The following state when charger cable is 280 /*
277 * connected on the GROUND accessory */ 281 * The following state when charger cable is
282 * connected on the GROUND accessory.
283 */
278 *attached = true; 284 *attached = true;
279 cable_type = MAX77843_MUIC_CHG_GND; 285 cable_type = MAX77843_MUIC_CHG_GND;
280 info->prev_chg_type = MAX77843_MUIC_CHG_GND; 286 info->prev_chg_type = MAX77843_MUIC_CHG_GND;
@@ -299,11 +305,13 @@ static int max77843_muic_get_cable_type(struct max77843_muic_info *info,
299 } else { 305 } else {
300 *attached = true; 306 *attached = true;
301 307
302 /* Offset|ADC1K|VBVolt| 308 /*
309 * Offset|ADC1K|VBVolt|
303 * 0x1| 0| 0| USB-HOST 310 * 0x1| 0| 0| USB-HOST
304 * 0x1| 0| 1| USB-HOST with VB 311 * 0x1| 0| 1| USB-HOST with VB
305 * 0x1| 1| 0| MHL 312 * 0x1| 1| 0| MHL
306 * 0x1| 1| 1| MHL with VB */ 313 * 0x1| 1| 1| MHL with VB
314 */
307 /* Get ADC1K register bit */ 315 /* Get ADC1K register bit */
308 gnd_type = (info->status[MAX77843_MUIC_STATUS1] & 316 gnd_type = (info->status[MAX77843_MUIC_STATUS1] &
309 MAX77843_MUIC_STATUS1_ADC1K_MASK); 317 MAX77843_MUIC_STATUS1_ADC1K_MASK);
diff --git a/drivers/extcon/extcon-palmas.c b/drivers/extcon/extcon-palmas.c
index 634ba70782de..ca904e8b3235 100644
--- a/drivers/extcon/extcon-palmas.c
+++ b/drivers/extcon/extcon-palmas.c
@@ -62,7 +62,7 @@ static irqreturn_t palmas_vbus_irq_handler(int irq, void *_palmas_usb)
62 if (palmas_usb->linkstat != PALMAS_USB_STATE_VBUS) { 62 if (palmas_usb->linkstat != PALMAS_USB_STATE_VBUS) {
63 palmas_usb->linkstat = PALMAS_USB_STATE_VBUS; 63 palmas_usb->linkstat = PALMAS_USB_STATE_VBUS;
64 extcon_set_state_sync(edev, EXTCON_USB, true); 64 extcon_set_state_sync(edev, EXTCON_USB, true);
65 dev_info(palmas_usb->dev, "USB cable is attached\n"); 65 dev_dbg(palmas_usb->dev, "USB cable is attached\n");
66 } else { 66 } else {
67 dev_dbg(palmas_usb->dev, 67 dev_dbg(palmas_usb->dev,
68 "Spurious connect event detected\n"); 68 "Spurious connect event detected\n");
@@ -71,7 +71,7 @@ static irqreturn_t palmas_vbus_irq_handler(int irq, void *_palmas_usb)
71 if (palmas_usb->linkstat == PALMAS_USB_STATE_VBUS) { 71 if (palmas_usb->linkstat == PALMAS_USB_STATE_VBUS) {
72 palmas_usb->linkstat = PALMAS_USB_STATE_DISCONNECT; 72 palmas_usb->linkstat = PALMAS_USB_STATE_DISCONNECT;
73 extcon_set_state_sync(edev, EXTCON_USB, false); 73 extcon_set_state_sync(edev, EXTCON_USB, false);
74 dev_info(palmas_usb->dev, "USB cable is detached\n"); 74 dev_dbg(palmas_usb->dev, "USB cable is detached\n");
75 } else { 75 } else {
76 dev_dbg(palmas_usb->dev, 76 dev_dbg(palmas_usb->dev,
77 "Spurious disconnect event detected\n"); 77 "Spurious disconnect event detected\n");
@@ -99,7 +99,7 @@ static irqreturn_t palmas_id_irq_handler(int irq, void *_palmas_usb)
99 PALMAS_USB_ID_INT_EN_HI_CLR_ID_GND); 99 PALMAS_USB_ID_INT_EN_HI_CLR_ID_GND);
100 palmas_usb->linkstat = PALMAS_USB_STATE_ID; 100 palmas_usb->linkstat = PALMAS_USB_STATE_ID;
101 extcon_set_state_sync(edev, EXTCON_USB_HOST, true); 101 extcon_set_state_sync(edev, EXTCON_USB_HOST, true);
102 dev_info(palmas_usb->dev, "USB-HOST cable is attached\n"); 102 dev_dbg(palmas_usb->dev, "USB-HOST cable is attached\n");
103 } else if ((set & PALMAS_USB_ID_INT_SRC_ID_FLOAT) && 103 } else if ((set & PALMAS_USB_ID_INT_SRC_ID_FLOAT) &&
104 (id_src & PALMAS_USB_ID_INT_SRC_ID_FLOAT)) { 104 (id_src & PALMAS_USB_ID_INT_SRC_ID_FLOAT)) {
105 palmas_write(palmas_usb->palmas, PALMAS_USB_OTG_BASE, 105 palmas_write(palmas_usb->palmas, PALMAS_USB_OTG_BASE,
@@ -107,17 +107,17 @@ static irqreturn_t palmas_id_irq_handler(int irq, void *_palmas_usb)
107 PALMAS_USB_ID_INT_EN_HI_CLR_ID_FLOAT); 107 PALMAS_USB_ID_INT_EN_HI_CLR_ID_FLOAT);
108 palmas_usb->linkstat = PALMAS_USB_STATE_DISCONNECT; 108 palmas_usb->linkstat = PALMAS_USB_STATE_DISCONNECT;
109 extcon_set_state_sync(edev, EXTCON_USB_HOST, false); 109 extcon_set_state_sync(edev, EXTCON_USB_HOST, false);
110 dev_info(palmas_usb->dev, "USB-HOST cable is detached\n"); 110 dev_dbg(palmas_usb->dev, "USB-HOST cable is detached\n");
111 } else if ((palmas_usb->linkstat == PALMAS_USB_STATE_ID) && 111 } else if ((palmas_usb->linkstat == PALMAS_USB_STATE_ID) &&
112 (!(set & PALMAS_USB_ID_INT_SRC_ID_GND))) { 112 (!(set & PALMAS_USB_ID_INT_SRC_ID_GND))) {
113 palmas_usb->linkstat = PALMAS_USB_STATE_DISCONNECT; 113 palmas_usb->linkstat = PALMAS_USB_STATE_DISCONNECT;
114 extcon_set_state_sync(edev, EXTCON_USB_HOST, false); 114 extcon_set_state_sync(edev, EXTCON_USB_HOST, false);
115 dev_info(palmas_usb->dev, "USB-HOST cable is detached\n"); 115 dev_dbg(palmas_usb->dev, "USB-HOST cable is detached\n");
116 } else if ((palmas_usb->linkstat == PALMAS_USB_STATE_DISCONNECT) && 116 } else if ((palmas_usb->linkstat == PALMAS_USB_STATE_DISCONNECT) &&
117 (id_src & PALMAS_USB_ID_INT_SRC_ID_GND)) { 117 (id_src & PALMAS_USB_ID_INT_SRC_ID_GND)) {
118 palmas_usb->linkstat = PALMAS_USB_STATE_ID; 118 palmas_usb->linkstat = PALMAS_USB_STATE_ID;
119 extcon_set_state_sync(edev, EXTCON_USB_HOST, true); 119 extcon_set_state_sync(edev, EXTCON_USB_HOST, true);
120 dev_info(palmas_usb->dev, " USB-HOST cable is attached\n"); 120 dev_dbg(palmas_usb->dev, " USB-HOST cable is attached\n");
121 } 121 }
122 122
123 return IRQ_HANDLED; 123 return IRQ_HANDLED;
@@ -138,10 +138,10 @@ static void palmas_gpio_id_detect(struct work_struct *work)
138 138
139 if (id) { 139 if (id) {
140 extcon_set_state_sync(edev, EXTCON_USB_HOST, false); 140 extcon_set_state_sync(edev, EXTCON_USB_HOST, false);
141 dev_info(palmas_usb->dev, "USB-HOST cable is detached\n"); 141 dev_dbg(palmas_usb->dev, "USB-HOST cable is detached\n");
142 } else { 142 } else {
143 extcon_set_state_sync(edev, EXTCON_USB_HOST, true); 143 extcon_set_state_sync(edev, EXTCON_USB_HOST, true);
144 dev_info(palmas_usb->dev, "USB-HOST cable is attached\n"); 144 dev_dbg(palmas_usb->dev, "USB-HOST cable is attached\n");
145 } 145 }
146} 146}
147 147
@@ -190,6 +190,11 @@ static int palmas_usb_probe(struct platform_device *pdev)
190 struct palmas_usb *palmas_usb; 190 struct palmas_usb *palmas_usb;
191 int status; 191 int status;
192 192
193 if (!palmas) {
194 dev_err(&pdev->dev, "failed to get valid parent\n");
195 return -EINVAL;
196 }
197
193 palmas_usb = devm_kzalloc(&pdev->dev, sizeof(*palmas_usb), GFP_KERNEL); 198 palmas_usb = devm_kzalloc(&pdev->dev, sizeof(*palmas_usb), GFP_KERNEL);
194 if (!palmas_usb) 199 if (!palmas_usb)
195 return -ENOMEM; 200 return -ENOMEM;
diff --git a/drivers/extcon/extcon-rt8973a.c b/drivers/extcon/extcon-rt8973a.c
index 174c388739ea..3e882aa107e8 100644
--- a/drivers/extcon/extcon-rt8973a.c
+++ b/drivers/extcon/extcon-rt8973a.c
@@ -142,8 +142,10 @@ enum rt8973a_muic_acc_type {
142 RT8973A_MUIC_ADC_UNKNOWN_ACC_5, 142 RT8973A_MUIC_ADC_UNKNOWN_ACC_5,
143 RT8973A_MUIC_ADC_OPEN = 0x1f, 143 RT8973A_MUIC_ADC_OPEN = 0x1f,
144 144
145 /* The below accessories has same ADC value (0x1f). 145 /*
146 So, Device type1 is used to separate specific accessory. */ 146 * The below accessories has same ADC value (0x1f).
147 * So, Device type1 is used to separate specific accessory.
148 */
147 /* |---------|--ADC| */ 149 /* |---------|--ADC| */
148 /* | [7:5]|[4:0]| */ 150 /* | [7:5]|[4:0]| */
149 RT8973A_MUIC_ADC_USB = 0x3f, /* | 001|11111| */ 151 RT8973A_MUIC_ADC_USB = 0x3f, /* | 001|11111| */
diff --git a/drivers/extcon/extcon-sm5502.c b/drivers/extcon/extcon-sm5502.c
index b22325688503..106ef0297b53 100644
--- a/drivers/extcon/extcon-sm5502.c
+++ b/drivers/extcon/extcon-sm5502.c
@@ -135,8 +135,10 @@ enum sm5502_muic_acc_type {
135 SM5502_MUIC_ADC_AUDIO_TYPE1, 135 SM5502_MUIC_ADC_AUDIO_TYPE1,
136 SM5502_MUIC_ADC_OPEN = 0x1f, 136 SM5502_MUIC_ADC_OPEN = 0x1f,
137 137
138 /* The below accessories have same ADC value (0x1f or 0x1e). 138 /*
139 So, Device type1 is used to separate specific accessory. */ 139 * The below accessories have same ADC value (0x1f or 0x1e).
140 * So, Device type1 is used to separate specific accessory.
141 */
140 /* |---------|--ADC| */ 142 /* |---------|--ADC| */
141 /* | [7:5]|[4:0]| */ 143 /* | [7:5]|[4:0]| */
142 SM5502_MUIC_ADC_AUDIO_TYPE1_FULL_REMOTE = 0x3e, /* | 001|11110| */ 144 SM5502_MUIC_ADC_AUDIO_TYPE1_FULL_REMOTE = 0x3e, /* | 001|11110| */
diff --git a/drivers/extcon/extcon-usb-gpio.c b/drivers/extcon/extcon-usb-gpio.c
index d589c5feff3d..a5e1882b4ca6 100644
--- a/drivers/extcon/extcon-usb-gpio.c
+++ b/drivers/extcon/extcon-usb-gpio.c
@@ -27,6 +27,7 @@
27#include <linux/slab.h> 27#include <linux/slab.h>
28#include <linux/workqueue.h> 28#include <linux/workqueue.h>
29#include <linux/acpi.h> 29#include <linux/acpi.h>
30#include <linux/pinctrl/consumer.h>
30 31
31#define USB_GPIO_DEBOUNCE_MS 20 /* ms */ 32#define USB_GPIO_DEBOUNCE_MS 20 /* ms */
32 33
@@ -245,6 +246,9 @@ static int usb_extcon_suspend(struct device *dev)
245 if (info->vbus_gpiod) 246 if (info->vbus_gpiod)
246 disable_irq(info->vbus_irq); 247 disable_irq(info->vbus_irq);
247 248
249 if (!device_may_wakeup(dev))
250 pinctrl_pm_select_sleep_state(dev);
251
248 return ret; 252 return ret;
249} 253}
250 254
@@ -253,6 +257,9 @@ static int usb_extcon_resume(struct device *dev)
253 struct usb_extcon_info *info = dev_get_drvdata(dev); 257 struct usb_extcon_info *info = dev_get_drvdata(dev);
254 int ret = 0; 258 int ret = 0;
255 259
260 if (!device_may_wakeup(dev))
261 pinctrl_pm_select_default_state(dev);
262
256 if (device_may_wakeup(dev)) { 263 if (device_may_wakeup(dev)) {
257 if (info->id_gpiod) { 264 if (info->id_gpiod) {
258 ret = disable_irq_wake(info->id_irq); 265 ret = disable_irq_wake(info->id_irq);
diff --git a/drivers/extcon/extcon.c b/drivers/extcon/extcon.c
index 7c1e3a7b14e0..09ac5e70c2f3 100644
--- a/drivers/extcon/extcon.c
+++ b/drivers/extcon/extcon.c
@@ -30,11 +30,12 @@
30#include <linux/device.h> 30#include <linux/device.h>
31#include <linux/fs.h> 31#include <linux/fs.h>
32#include <linux/err.h> 32#include <linux/err.h>
33#include <linux/extcon.h>
34#include <linux/of.h> 33#include <linux/of.h>
35#include <linux/slab.h> 34#include <linux/slab.h>
36#include <linux/sysfs.h> 35#include <linux/sysfs.h>
37 36
37#include "extcon.h"
38
38#define SUPPORTED_CABLE_MAX 32 39#define SUPPORTED_CABLE_MAX 32
39#define CABLE_NAME_MAX 30 40#define CABLE_NAME_MAX 30
40 41
@@ -59,7 +60,7 @@ struct __extcon_info {
59 [EXTCON_USB_HOST] = { 60 [EXTCON_USB_HOST] = {
60 .type = EXTCON_TYPE_USB, 61 .type = EXTCON_TYPE_USB,
61 .id = EXTCON_USB_HOST, 62 .id = EXTCON_USB_HOST,
62 .name = "USB_HOST", 63 .name = "USB-HOST",
63 }, 64 },
64 65
65 /* Charging external connector */ 66 /* Charging external connector */
@@ -98,6 +99,11 @@ struct __extcon_info {
98 .id = EXTCON_CHG_WPT, 99 .id = EXTCON_CHG_WPT,
99 .name = "WPT", 100 .name = "WPT",
100 }, 101 },
102 [EXTCON_CHG_USB_PD] = {
103 .type = EXTCON_TYPE_CHG | EXTCON_TYPE_USB,
104 .id = EXTCON_CHG_USB_PD,
105 .name = "PD",
106 },
101 107
102 /* Jack external connector */ 108 /* Jack external connector */
103 [EXTCON_JACK_MICROPHONE] = { 109 [EXTCON_JACK_MICROPHONE] = {
@@ -906,35 +912,16 @@ int extcon_register_notifier(struct extcon_dev *edev, unsigned int id,
906 unsigned long flags; 912 unsigned long flags;
907 int ret, idx = -EINVAL; 913 int ret, idx = -EINVAL;
908 914
909 if (!nb) 915 if (!edev || !nb)
910 return -EINVAL; 916 return -EINVAL;
911 917
912 if (edev) { 918 idx = find_cable_index_by_id(edev, id);
913 idx = find_cable_index_by_id(edev, id); 919 if (idx < 0)
914 if (idx < 0) 920 return idx;
915 return idx;
916
917 spin_lock_irqsave(&edev->lock, flags);
918 ret = raw_notifier_chain_register(&edev->nh[idx], nb);
919 spin_unlock_irqrestore(&edev->lock, flags);
920 } else {
921 struct extcon_dev *extd;
922
923 mutex_lock(&extcon_dev_list_lock);
924 list_for_each_entry(extd, &extcon_dev_list, entry) {
925 idx = find_cable_index_by_id(extd, id);
926 if (idx >= 0)
927 break;
928 }
929 mutex_unlock(&extcon_dev_list_lock);
930 921
931 if (idx >= 0) { 922 spin_lock_irqsave(&edev->lock, flags);
932 edev = extd; 923 ret = raw_notifier_chain_register(&edev->nh[idx], nb);
933 return extcon_register_notifier(extd, id, nb); 924 spin_unlock_irqrestore(&edev->lock, flags);
934 } else {
935 ret = -ENODEV;
936 }
937 }
938 925
939 return ret; 926 return ret;
940} 927}
diff --git a/drivers/extcon/extcon.h b/drivers/extcon/extcon.h
new file mode 100644
index 000000000000..993ddccafe11
--- /dev/null
+++ b/drivers/extcon/extcon.h
@@ -0,0 +1,62 @@
1#ifndef __LINUX_EXTCON_INTERNAL_H__
2#define __LINUX_EXTCON_INTERNAL_H__
3
4#include <linux/extcon.h>
5
6/**
7 * struct extcon_dev - An extcon device represents one external connector.
8 * @name: The name of this extcon device. Parent device name is
9 * used if NULL.
10 * @supported_cable: Array of supported cable names ending with EXTCON_NONE.
11 * If supported_cable is NULL, cable name related APIs
12 * are disabled.
13 * @mutually_exclusive: Array of mutually exclusive set of cables that cannot
14 * be attached simultaneously. The array should be
15 * ending with NULL or be NULL (no mutually exclusive
16 * cables). For example, if it is { 0x7, 0x30, 0}, then,
17 * {0, 1}, {0, 1, 2}, {0, 2}, {1, 2}, or {4, 5} cannot
18 * be attached simulataneously. {0x7, 0} is equivalent to
19 * {0x3, 0x6, 0x5, 0}. If it is {0xFFFFFFFF, 0}, there
20 * can be no simultaneous connections.
21 * @dev: Device of this extcon.
22 * @state: Attach/detach state of this extcon. Do not provide at
23 * register-time.
24 * @nh: Notifier for the state change events from this extcon
25 * @entry: To support list of extcon devices so that users can
26 * search for extcon devices based on the extcon name.
27 * @lock:
28 * @max_supported: Internal value to store the number of cables.
29 * @extcon_dev_type: Device_type struct to provide attribute_groups
30 * customized for each extcon device.
31 * @cables: Sysfs subdirectories. Each represents one cable.
32 *
33 * In most cases, users only need to provide "User initializing data" of
34 * this struct when registering an extcon. In some exceptional cases,
35 * optional callbacks may be needed. However, the values in "internal data"
36 * are overwritten by register function.
37 */
38struct extcon_dev {
39 /* Optional user initializing data */
40 const char *name;
41 const unsigned int *supported_cable;
42 const u32 *mutually_exclusive;
43
44 /* Internal data. Please do not set. */
45 struct device dev;
46 struct raw_notifier_head *nh;
47 struct list_head entry;
48 int max_supported;
49 spinlock_t lock; /* could be called by irq handler */
50 u32 state;
51
52 /* /sys/class/extcon/.../cable.n/... */
53 struct device_type extcon_dev_type;
54 struct extcon_cable *cables;
55
56 /* /sys/class/extcon/.../mutually_exclusive/... */
57 struct attribute_group attr_g_muex;
58 struct attribute **attrs_muex;
59 struct device_attribute *d_attrs_muex;
60};
61
62#endif /* __LINUX_EXTCON_INTERNAL_H__ */