aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/extcon
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2015-04-21 12:42:58 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2015-04-21 12:42:58 -0400
commit1fc149933fd49a5b0e7738dc0853dbfbac4ae0e1 (patch)
treedfe99751c21aaf39e49765379d0b9b32114c757d /drivers/extcon
parent41d5e08ea86af3359239d5a6f7021cdc61beaa49 (diff)
parentea5505fabd3b59608750bfd3721d0f8bc5c8b0bb (diff)
Merge tag 'char-misc-4.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc
Pull char/misc driver updates from Greg KH: "Here's the big char/misc driver patchset for 4.1-rc1. Lots of different driver subsystem updates here, nothing major, full details are in the shortlog. All of this has been in linux-next for a while" * tag 'char-misc-4.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc: (133 commits) mei: trace: remove unused TRACE_SYSTEM_STRING DTS: ARM: OMAP3-N900: Add lis3lv02d support Documentation: DT: lis302: update wakeup binding lis3lv02d: DT: add wakeup unit 2 and wakeup threshold lis3lv02d: DT: use s32 to support negative values Drivers: hv: hv_balloon: correctly handle num_pages>INT_MAX case Drivers: hv: hv_balloon: correctly handle val.freeram<num_pages case mei: replace check for connection instead of transitioning mei: use mei_cl_is_connected consistently mei: fix mei_poll operation hv_vmbus: Add gradually increased delay for retries in vmbus_post_msg() Drivers: hv: hv_balloon: survive ballooning request with num_pages=0 Drivers: hv: hv_balloon: eliminate jumps in piecewiese linear floor function Drivers: hv: hv_balloon: do not online pages in offline blocks hv: remove the per-channel workqueue hv: don't schedule new works in vmbus_onoffer()/vmbus_onoffer_rescind() hv: run non-blocking message handlers in the dispatch tasklet coresight: moving to new "hwtracing" directory coresight-tmc: Adding a status interface to sysfs coresight: remove the unnecessary configuration coresight-default-sink ...
Diffstat (limited to 'drivers/extcon')
-rw-r--r--drivers/extcon/Kconfig17
-rw-r--r--drivers/extcon/Makefile4
-rw-r--r--drivers/extcon/extcon-arizona.c49
-rw-r--r--drivers/extcon/extcon-max14577.c5
-rw-r--r--drivers/extcon/extcon-max77693.c37
-rw-r--r--drivers/extcon/extcon-max77843.c881
-rw-r--r--drivers/extcon/extcon-max8997.c5
-rw-r--r--drivers/extcon/extcon-rt8973a.c6
-rw-r--r--drivers/extcon/extcon-sm5502.c6
-rw-r--r--drivers/extcon/extcon-usb-gpio.c237
-rw-r--r--drivers/extcon/extcon.c (renamed from drivers/extcon/extcon-class.c)36
11 files changed, 1227 insertions, 56 deletions
diff --git a/drivers/extcon/Kconfig b/drivers/extcon/Kconfig
index 6a1f7de6fa54..fdc0bf0543ce 100644
--- a/drivers/extcon/Kconfig
+++ b/drivers/extcon/Kconfig
@@ -55,6 +55,16 @@ config EXTCON_MAX77693
55 Maxim MAX77693 PMIC. The MAX77693 MUIC is a USB port accessory 55 Maxim MAX77693 PMIC. The MAX77693 MUIC is a USB port accessory
56 detector and switch. 56 detector and switch.
57 57
58config EXTCON_MAX77843
59 tristate "MAX77843 EXTCON Support"
60 depends on MFD_MAX77843
61 select IRQ_DOMAIN
62 select REGMAP_I2C
63 help
64 If you say yes here you get support for the MUIC device of
65 Maxim MAX77843. The MAX77843 MUIC is a USB port accessory
66 detector add switch.
67
58config EXTCON_MAX8997 68config EXTCON_MAX8997
59 tristate "MAX8997 EXTCON Support" 69 tristate "MAX8997 EXTCON Support"
60 depends on MFD_MAX8997 && IRQ_DOMAIN 70 depends on MFD_MAX8997 && IRQ_DOMAIN
@@ -93,4 +103,11 @@ config EXTCON_SM5502
93 Silicon Mitus SM5502. The SM5502 is a USB port accessory 103 Silicon Mitus SM5502. The SM5502 is a USB port accessory
94 detector and switch. 104 detector and switch.
95 105
106config EXTCON_USB_GPIO
107 tristate "USB GPIO extcon support"
108 depends on GPIOLIB
109 help
110 Say Y here to enable GPIO based USB cable detection extcon support.
111 Used typically if GPIO is used for USB ID pin detection.
112
96endif # MULTISTATE_SWITCH 113endif # MULTISTATE_SWITCH
diff --git a/drivers/extcon/Makefile b/drivers/extcon/Makefile
index 0370b42e5a27..9204114791a3 100644
--- a/drivers/extcon/Makefile
+++ b/drivers/extcon/Makefile
@@ -2,13 +2,15 @@
2# Makefile for external connector class (extcon) devices 2# Makefile for external connector class (extcon) devices
3# 3#
4 4
5obj-$(CONFIG_EXTCON) += extcon-class.o 5obj-$(CONFIG_EXTCON) += extcon.o
6obj-$(CONFIG_EXTCON_ADC_JACK) += extcon-adc-jack.o 6obj-$(CONFIG_EXTCON_ADC_JACK) += extcon-adc-jack.o
7obj-$(CONFIG_EXTCON_ARIZONA) += extcon-arizona.o 7obj-$(CONFIG_EXTCON_ARIZONA) += extcon-arizona.o
8obj-$(CONFIG_EXTCON_GPIO) += extcon-gpio.o 8obj-$(CONFIG_EXTCON_GPIO) += extcon-gpio.o
9obj-$(CONFIG_EXTCON_MAX14577) += extcon-max14577.o 9obj-$(CONFIG_EXTCON_MAX14577) += extcon-max14577.o
10obj-$(CONFIG_EXTCON_MAX77693) += extcon-max77693.o 10obj-$(CONFIG_EXTCON_MAX77693) += extcon-max77693.o
11obj-$(CONFIG_EXTCON_MAX77843) += extcon-max77843.o
11obj-$(CONFIG_EXTCON_MAX8997) += extcon-max8997.o 12obj-$(CONFIG_EXTCON_MAX8997) += extcon-max8997.o
12obj-$(CONFIG_EXTCON_PALMAS) += extcon-palmas.o 13obj-$(CONFIG_EXTCON_PALMAS) += extcon-palmas.o
13obj-$(CONFIG_EXTCON_RT8973A) += extcon-rt8973a.o 14obj-$(CONFIG_EXTCON_RT8973A) += extcon-rt8973a.o
14obj-$(CONFIG_EXTCON_SM5502) += extcon-sm5502.o 15obj-$(CONFIG_EXTCON_SM5502) += extcon-sm5502.o
16obj-$(CONFIG_EXTCON_USB_GPIO) += extcon-usb-gpio.o
diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c
index 6b5e795f3fe2..a0ed35b336e4 100644
--- a/drivers/extcon/extcon-arizona.c
+++ b/drivers/extcon/extcon-arizona.c
@@ -136,18 +136,35 @@ static const char *arizona_cable[] = {
136 136
137static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info); 137static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info);
138 138
139static void arizona_extcon_do_magic(struct arizona_extcon_info *info, 139static void arizona_extcon_hp_clamp(struct arizona_extcon_info *info,
140 unsigned int magic) 140 bool clamp)
141{ 141{
142 struct arizona *arizona = info->arizona; 142 struct arizona *arizona = info->arizona;
143 unsigned int mask = 0, val = 0;
143 int ret; 144 int ret;
144 145
146 switch (arizona->type) {
147 case WM5110:
148 mask = ARIZONA_HP1L_SHRTO | ARIZONA_HP1L_FLWR |
149 ARIZONA_HP1L_SHRTI;
150 if (clamp)
151 val = ARIZONA_HP1L_SHRTO;
152 else
153 val = ARIZONA_HP1L_FLWR | ARIZONA_HP1L_SHRTI;
154 break;
155 default:
156 mask = ARIZONA_RMV_SHRT_HP1L;
157 if (clamp)
158 val = ARIZONA_RMV_SHRT_HP1L;
159 break;
160 };
161
145 mutex_lock(&arizona->dapm->card->dapm_mutex); 162 mutex_lock(&arizona->dapm->card->dapm_mutex);
146 163
147 arizona->hpdet_magic = magic; 164 arizona->hpdet_clamp = clamp;
148 165
149 /* Keep the HP output stages disabled while doing the magic */ 166 /* Keep the HP output stages disabled while doing the clamp */
150 if (magic) { 167 if (clamp) {
151 ret = regmap_update_bits(arizona->regmap, 168 ret = regmap_update_bits(arizona->regmap,
152 ARIZONA_OUTPUT_ENABLES_1, 169 ARIZONA_OUTPUT_ENABLES_1,
153 ARIZONA_OUT1L_ENA | 170 ARIZONA_OUT1L_ENA |
@@ -158,20 +175,20 @@ static void arizona_extcon_do_magic(struct arizona_extcon_info *info,
158 ret); 175 ret);
159 } 176 }
160 177
161 ret = regmap_update_bits(arizona->regmap, 0x225, 0x4000, 178 ret = regmap_update_bits(arizona->regmap, ARIZONA_HP_CTRL_1L,
162 magic); 179 mask, val);
163 if (ret != 0) 180 if (ret != 0)
164 dev_warn(arizona->dev, "Failed to do magic: %d\n", 181 dev_warn(arizona->dev, "Failed to do clamp: %d\n",
165 ret); 182 ret);
166 183
167 ret = regmap_update_bits(arizona->regmap, 0x226, 0x4000, 184 ret = regmap_update_bits(arizona->regmap, ARIZONA_HP_CTRL_1R,
168 magic); 185 mask, val);
169 if (ret != 0) 186 if (ret != 0)
170 dev_warn(arizona->dev, "Failed to do magic: %d\n", 187 dev_warn(arizona->dev, "Failed to do clamp: %d\n",
171 ret); 188 ret);
172 189
173 /* Restore the desired state while not doing the magic */ 190 /* Restore the desired state while not doing the clamp */
174 if (!magic) { 191 if (!clamp) {
175 ret = regmap_update_bits(arizona->regmap, 192 ret = regmap_update_bits(arizona->regmap,
176 ARIZONA_OUTPUT_ENABLES_1, 193 ARIZONA_OUTPUT_ENABLES_1,
177 ARIZONA_OUT1L_ENA | 194 ARIZONA_OUT1L_ENA |
@@ -603,7 +620,7 @@ done:
603 ARIZONA_HP_IMPEDANCE_RANGE_MASK | ARIZONA_HP_POLL, 620 ARIZONA_HP_IMPEDANCE_RANGE_MASK | ARIZONA_HP_POLL,
604 0); 621 0);
605 622
606 arizona_extcon_do_magic(info, 0); 623 arizona_extcon_hp_clamp(info, false);
607 624
608 if (id_gpio) 625 if (id_gpio)
609 gpio_set_value_cansleep(id_gpio, 0); 626 gpio_set_value_cansleep(id_gpio, 0);
@@ -648,7 +665,7 @@ static void arizona_identify_headphone(struct arizona_extcon_info *info)
648 if (info->mic) 665 if (info->mic)
649 arizona_stop_mic(info); 666 arizona_stop_mic(info);
650 667
651 arizona_extcon_do_magic(info, 0x4000); 668 arizona_extcon_hp_clamp(info, true);
652 669
653 ret = regmap_update_bits(arizona->regmap, 670 ret = regmap_update_bits(arizona->regmap,
654 ARIZONA_ACCESSORY_DETECT_MODE_1, 671 ARIZONA_ACCESSORY_DETECT_MODE_1,
@@ -699,7 +716,7 @@ static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info)
699 716
700 info->hpdet_active = true; 717 info->hpdet_active = true;
701 718
702 arizona_extcon_do_magic(info, 0x4000); 719 arizona_extcon_hp_clamp(info, true);
703 720
704 ret = regmap_update_bits(arizona->regmap, 721 ret = regmap_update_bits(arizona->regmap,
705 ARIZONA_ACCESSORY_DETECT_MODE_1, 722 ARIZONA_ACCESSORY_DETECT_MODE_1,
diff --git a/drivers/extcon/extcon-max14577.c b/drivers/extcon/extcon-max14577.c
index c1bf0cf747b0..3823aa4a3a80 100644
--- a/drivers/extcon/extcon-max14577.c
+++ b/drivers/extcon/extcon-max14577.c
@@ -539,8 +539,6 @@ static void max14577_muic_irq_work(struct work_struct *work)
539 dev_err(info->dev, "failed to handle MUIC interrupt\n"); 539 dev_err(info->dev, "failed to handle MUIC interrupt\n");
540 540
541 mutex_unlock(&info->mutex); 541 mutex_unlock(&info->mutex);
542
543 return;
544} 542}
545 543
546/* 544/*
@@ -730,8 +728,7 @@ static int max14577_muic_probe(struct platform_device *pdev)
730 muic_irq->name, info); 728 muic_irq->name, info);
731 if (ret) { 729 if (ret) {
732 dev_err(&pdev->dev, 730 dev_err(&pdev->dev,
733 "failed: irq request (IRQ: %d," 731 "failed: irq request (IRQ: %d, error :%d)\n",
734 " error :%d)\n",
735 muic_irq->irq, ret); 732 muic_irq->irq, ret);
736 return ret; 733 return ret;
737 } 734 }
diff --git a/drivers/extcon/extcon-max77693.c b/drivers/extcon/extcon-max77693.c
index af165fd0c6f5..a66bec8f6252 100644
--- a/drivers/extcon/extcon-max77693.c
+++ b/drivers/extcon/extcon-max77693.c
@@ -190,8 +190,8 @@ enum max77693_muic_acc_type {
190 /* The below accessories have same ADC value so ADCLow and 190 /* The below accessories have same ADC value so ADCLow and
191 ADC1K bit is used to separate specific accessory */ 191 ADC1K bit is used to separate specific accessory */
192 /* ADC|VBVolot|ADCLow|ADC1K| */ 192 /* ADC|VBVolot|ADCLow|ADC1K| */
193 MAX77693_MUIC_GND_USB_OTG = 0x100, /* 0x0| 0| 0| 0| */ 193 MAX77693_MUIC_GND_USB_HOST = 0x100, /* 0x0| 0| 0| 0| */
194 MAX77693_MUIC_GND_USB_OTG_VB = 0x104, /* 0x0| 1| 0| 0| */ 194 MAX77693_MUIC_GND_USB_HOST_VB = 0x104, /* 0x0| 1| 0| 0| */
195 MAX77693_MUIC_GND_AV_CABLE_LOAD = 0x102,/* 0x0| 0| 1| 0| */ 195 MAX77693_MUIC_GND_AV_CABLE_LOAD = 0x102,/* 0x0| 0| 1| 0| */
196 MAX77693_MUIC_GND_MHL = 0x103, /* 0x0| 0| 1| 1| */ 196 MAX77693_MUIC_GND_MHL = 0x103, /* 0x0| 0| 1| 1| */
197 MAX77693_MUIC_GND_MHL_VB = 0x107, /* 0x0| 1| 1| 1| */ 197 MAX77693_MUIC_GND_MHL_VB = 0x107, /* 0x0| 1| 1| 1| */
@@ -228,7 +228,7 @@ static const char *max77693_extcon_cable[] = {
228 [EXTCON_CABLE_SLOW_CHARGER] = "Slow-charger", 228 [EXTCON_CABLE_SLOW_CHARGER] = "Slow-charger",
229 [EXTCON_CABLE_CHARGE_DOWNSTREAM] = "Charge-downstream", 229 [EXTCON_CABLE_CHARGE_DOWNSTREAM] = "Charge-downstream",
230 [EXTCON_CABLE_MHL] = "MHL", 230 [EXTCON_CABLE_MHL] = "MHL",
231 [EXTCON_CABLE_MHL_TA] = "MHL_TA", 231 [EXTCON_CABLE_MHL_TA] = "MHL-TA",
232 [EXTCON_CABLE_JIG_USB_ON] = "JIG-USB-ON", 232 [EXTCON_CABLE_JIG_USB_ON] = "JIG-USB-ON",
233 [EXTCON_CABLE_JIG_USB_OFF] = "JIG-USB-OFF", 233 [EXTCON_CABLE_JIG_USB_OFF] = "JIG-USB-OFF",
234 [EXTCON_CABLE_JIG_UART_OFF] = "JIG-UART-OFF", 234 [EXTCON_CABLE_JIG_UART_OFF] = "JIG-UART-OFF",
@@ -403,8 +403,8 @@ static int max77693_muic_get_cable_type(struct max77693_muic_info *info,
403 403
404 /** 404 /**
405 * [0x1|VBVolt|ADCLow|ADC1K] 405 * [0x1|VBVolt|ADCLow|ADC1K]
406 * [0x1| 0| 0| 0] USB_OTG 406 * [0x1| 0| 0| 0] USB_HOST
407 * [0x1| 1| 0| 0] USB_OTG_VB 407 * [0x1| 1| 0| 0] USB_HSOT_VB
408 * [0x1| 0| 1| 0] Audio Video cable with load 408 * [0x1| 0| 1| 0] Audio Video cable with load
409 * [0x1| 0| 1| 1] MHL without charging cable 409 * [0x1| 0| 1| 1] MHL without charging cable
410 * [0x1| 1| 1| 1] MHL with charging cable 410 * [0x1| 1| 1| 1] MHL with charging cable
@@ -523,7 +523,7 @@ static int max77693_muic_dock_handler(struct max77693_muic_info *info,
523 * - Support charging and data connection through micro-usb port 523 * - Support charging and data connection through micro-usb port
524 * if USB cable is connected between target and host 524 * if USB cable is connected between target and host
525 * device. 525 * device.
526 * - Support OTG device (Mouse/Keyboard) 526 * - Support OTG(On-The-Go) device (Ex: Mouse/Keyboard)
527 */ 527 */
528 ret = max77693_muic_set_path(info, info->path_usb, attached); 528 ret = max77693_muic_set_path(info, info->path_usb, attached);
529 if (ret < 0) 529 if (ret < 0)
@@ -609,9 +609,9 @@ static int max77693_muic_adc_ground_handler(struct max77693_muic_info *info)
609 MAX77693_CABLE_GROUP_ADC_GND, &attached); 609 MAX77693_CABLE_GROUP_ADC_GND, &attached);
610 610
611 switch (cable_type_gnd) { 611 switch (cable_type_gnd) {
612 case MAX77693_MUIC_GND_USB_OTG: 612 case MAX77693_MUIC_GND_USB_HOST:
613 case MAX77693_MUIC_GND_USB_OTG_VB: 613 case MAX77693_MUIC_GND_USB_HOST_VB:
614 /* USB_OTG, PATH: AP_USB */ 614 /* USB_HOST, PATH: AP_USB */
615 ret = max77693_muic_set_path(info, CONTROL1_SW_USB, attached); 615 ret = max77693_muic_set_path(info, CONTROL1_SW_USB, attached);
616 if (ret < 0) 616 if (ret < 0)
617 return ret; 617 return ret;
@@ -704,7 +704,7 @@ static int max77693_muic_adc_handler(struct max77693_muic_info *info)
704 704
705 switch (cable_type) { 705 switch (cable_type) {
706 case MAX77693_MUIC_ADC_GROUND: 706 case MAX77693_MUIC_ADC_GROUND:
707 /* USB_OTG/MHL/Audio */ 707 /* USB_HOST/MHL/Audio */
708 max77693_muic_adc_ground_handler(info); 708 max77693_muic_adc_ground_handler(info);
709 break; 709 break;
710 case MAX77693_MUIC_ADC_FACTORY_MODE_USB_OFF: 710 case MAX77693_MUIC_ADC_FACTORY_MODE_USB_OFF:
@@ -823,19 +823,19 @@ static int max77693_muic_chg_handler(struct max77693_muic_info *info)
823 case MAX77693_MUIC_GND_MHL: 823 case MAX77693_MUIC_GND_MHL:
824 case MAX77693_MUIC_GND_MHL_VB: 824 case MAX77693_MUIC_GND_MHL_VB:
825 /* 825 /*
826 * MHL cable with MHL_TA(USB/TA) cable 826 * MHL cable with MHL-TA(USB/TA) cable
827 * - MHL cable include two port(HDMI line and separate 827 * - MHL cable include two port(HDMI line and separate
828 * micro-usb port. When the target connect MHL cable, 828 * micro-usb port. When the target connect MHL cable,
829 * extcon driver check whether MHL_TA(USB/TA) cable is 829 * extcon driver check whether MHL-TA(USB/TA) cable is
830 * connected. If MHL_TA cable is connected, extcon 830 * connected. If MHL-TA cable is connected, extcon
831 * driver notify state to notifiee for charging battery. 831 * driver notify state to notifiee for charging battery.
832 * 832 *
833 * Features of 'MHL_TA(USB/TA) with MHL cable' 833 * Features of 'MHL-TA(USB/TA) with MHL cable'
834 * - Support MHL 834 * - Support MHL
835 * - Support charging through micro-usb port without 835 * - Support charging through micro-usb port without
836 * data connection 836 * data connection
837 */ 837 */
838 extcon_set_cable_state(info->edev, "MHL_TA", attached); 838 extcon_set_cable_state(info->edev, "MHL-TA", attached);
839 if (!cable_attached) 839 if (!cable_attached)
840 extcon_set_cable_state(info->edev, 840 extcon_set_cable_state(info->edev,
841 "MHL", cable_attached); 841 "MHL", cable_attached);
@@ -886,7 +886,7 @@ static int max77693_muic_chg_handler(struct max77693_muic_info *info)
886 * - Support charging and data connection through micro- 886 * - Support charging and data connection through micro-
887 * usb port if USB cable is connected between target 887 * usb port if USB cable is connected between target
888 * and host device 888 * and host device
889 * - Support OTG device (Mouse/Keyboard) 889 * - Support OTG(On-The-Go) device (Ex: Mouse/Keyboard)
890 */ 890 */
891 ret = max77693_muic_set_path(info, info->path_usb, 891 ret = max77693_muic_set_path(info, info->path_usb,
892 attached); 892 attached);
@@ -1019,8 +1019,6 @@ static void max77693_muic_irq_work(struct work_struct *work)
1019 dev_err(info->dev, "failed to handle MUIC interrupt\n"); 1019 dev_err(info->dev, "failed to handle MUIC interrupt\n");
1020 1020
1021 mutex_unlock(&info->mutex); 1021 mutex_unlock(&info->mutex);
1022
1023 return;
1024} 1022}
1025 1023
1026static irqreturn_t max77693_muic_irq_handler(int irq, void *data) 1024static irqreturn_t max77693_muic_irq_handler(int irq, void *data)
@@ -1171,8 +1169,7 @@ static int max77693_muic_probe(struct platform_device *pdev)
1171 muic_irq->name, info); 1169 muic_irq->name, info);
1172 if (ret) { 1170 if (ret) {
1173 dev_err(&pdev->dev, 1171 dev_err(&pdev->dev,
1174 "failed: irq request (IRQ: %d," 1172 "failed: irq request (IRQ: %d, error :%d)\n",
1175 " error :%d)\n",
1176 muic_irq->irq, ret); 1173 muic_irq->irq, ret);
1177 return ret; 1174 return ret;
1178 } 1175 }
diff --git a/drivers/extcon/extcon-max77843.c b/drivers/extcon/extcon-max77843.c
new file mode 100644
index 000000000000..8db6a926ea07
--- /dev/null
+++ b/drivers/extcon/extcon-max77843.c
@@ -0,0 +1,881 @@
1/*
2 * extcon-max77843.c - Maxim MAX77843 extcon driver to support
3 * MUIC(Micro USB Interface Controller)
4 *
5 * Copyright (C) 2015 Samsung Electronics
6 * Author: Jaewon Kim <jaewon02.kim@samsung.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 */
13
14#include <linux/extcon.h>
15#include <linux/i2c.h>
16#include <linux/interrupt.h>
17#include <linux/kernel.h>
18#include <linux/mfd/max77843-private.h>
19#include <linux/module.h>
20#include <linux/platform_device.h>
21#include <linux/workqueue.h>
22
23#define DELAY_MS_DEFAULT 15000 /* unit: millisecond */
24
25enum max77843_muic_status {
26 MAX77843_MUIC_STATUS1 = 0,
27 MAX77843_MUIC_STATUS2,
28 MAX77843_MUIC_STATUS3,
29
30 MAX77843_MUIC_STATUS_NUM,
31};
32
33struct max77843_muic_info {
34 struct device *dev;
35 struct max77843 *max77843;
36 struct extcon_dev *edev;
37
38 struct mutex mutex;
39 struct work_struct irq_work;
40 struct delayed_work wq_detcable;
41
42 u8 status[MAX77843_MUIC_STATUS_NUM];
43 int prev_cable_type;
44 int prev_chg_type;
45 int prev_gnd_type;
46
47 bool irq_adc;
48 bool irq_chg;
49};
50
51enum max77843_muic_cable_group {
52 MAX77843_CABLE_GROUP_ADC = 0,
53 MAX77843_CABLE_GROUP_ADC_GND,
54 MAX77843_CABLE_GROUP_CHG,
55};
56
57enum max77843_muic_adc_debounce_time {
58 MAX77843_DEBOUNCE_TIME_5MS = 0,
59 MAX77843_DEBOUNCE_TIME_10MS,
60 MAX77843_DEBOUNCE_TIME_25MS,
61 MAX77843_DEBOUNCE_TIME_38_62MS,
62};
63
64/* Define accessory cable type */
65enum max77843_muic_accessory_type {
66 MAX77843_MUIC_ADC_GROUND = 0,
67 MAX77843_MUIC_ADC_SEND_END_BUTTON,
68 MAX77843_MUIC_ADC_REMOTE_S1_BUTTON,
69 MAX77843_MUIC_ADC_REMOTE_S2_BUTTON,
70 MAX77843_MUIC_ADC_REMOTE_S3_BUTTON,
71 MAX77843_MUIC_ADC_REMOTE_S4_BUTTON,
72 MAX77843_MUIC_ADC_REMOTE_S5_BUTTON,
73 MAX77843_MUIC_ADC_REMOTE_S6_BUTTON,
74 MAX77843_MUIC_ADC_REMOTE_S7_BUTTON,
75 MAX77843_MUIC_ADC_REMOTE_S8_BUTTON,
76 MAX77843_MUIC_ADC_REMOTE_S9_BUTTON,
77 MAX77843_MUIC_ADC_REMOTE_S10_BUTTON,
78 MAX77843_MUIC_ADC_REMOTE_S11_BUTTON,
79 MAX77843_MUIC_ADC_REMOTE_S12_BUTTON,
80 MAX77843_MUIC_ADC_RESERVED_ACC_1,
81 MAX77843_MUIC_ADC_RESERVED_ACC_2,
82 MAX77843_MUIC_ADC_RESERVED_ACC_3,
83 MAX77843_MUIC_ADC_RESERVED_ACC_4,
84 MAX77843_MUIC_ADC_RESERVED_ACC_5,
85 MAX77843_MUIC_ADC_AUDIO_DEVICE_TYPE2,
86 MAX77843_MUIC_ADC_PHONE_POWERED_DEV,
87 MAX77843_MUIC_ADC_TTY_CONVERTER,
88 MAX77843_MUIC_ADC_UART_CABLE,
89 MAX77843_MUIC_ADC_CEA936A_TYPE1_CHG,
90 MAX77843_MUIC_ADC_FACTORY_MODE_USB_OFF,
91 MAX77843_MUIC_ADC_FACTORY_MODE_USB_ON,
92 MAX77843_MUIC_ADC_AV_CABLE_NOLOAD,
93 MAX77843_MUIC_ADC_CEA936A_TYPE2_CHG,
94 MAX77843_MUIC_ADC_FACTORY_MODE_UART_OFF,
95 MAX77843_MUIC_ADC_FACTORY_MODE_UART_ON,
96 MAX77843_MUIC_ADC_AUDIO_DEVICE_TYPE1,
97 MAX77843_MUIC_ADC_OPEN,
98
99 /* The blow accessories should check
100 not only ADC value but also ADC1K and VBVolt value. */
101 /* Offset|ADC1K|VBVolt| */
102 MAX77843_MUIC_GND_USB_HOST = 0x100, /* 0x1| 0| 0| */
103 MAX77843_MUIC_GND_USB_HOST_VB = 0x101, /* 0x1| 0| 1| */
104 MAX77843_MUIC_GND_MHL = 0x102, /* 0x1| 1| 0| */
105 MAX77843_MUIC_GND_MHL_VB = 0x103, /* 0x1| 1| 1| */
106};
107
108/* Define charger cable type */
109enum max77843_muic_charger_type {
110 MAX77843_MUIC_CHG_NONE = 0,
111 MAX77843_MUIC_CHG_USB,
112 MAX77843_MUIC_CHG_DOWNSTREAM,
113 MAX77843_MUIC_CHG_DEDICATED,
114 MAX77843_MUIC_CHG_SPECIAL_500MA,
115 MAX77843_MUIC_CHG_SPECIAL_1A,
116 MAX77843_MUIC_CHG_SPECIAL_BIAS,
117 MAX77843_MUIC_CHG_RESERVED,
118 MAX77843_MUIC_CHG_GND,
119};
120
121enum {
122 MAX77843_CABLE_USB = 0,
123 MAX77843_CABLE_USB_HOST,
124 MAX77843_CABLE_TA,
125 MAX77843_CABLE_CHARGE_DOWNSTREAM,
126 MAX77843_CABLE_FAST_CHARGER,
127 MAX77843_CABLE_SLOW_CHARGER,
128 MAX77843_CABLE_MHL,
129 MAX77843_CABLE_MHL_TA,
130 MAX77843_CABLE_JIG_USB_ON,
131 MAX77843_CABLE_JIG_USB_OFF,
132 MAX77843_CABLE_JIG_UART_ON,
133 MAX77843_CABLE_JIG_UART_OFF,
134
135 MAX77843_CABLE_NUM,
136};
137
138static const char *max77843_extcon_cable[] = {
139 [MAX77843_CABLE_USB] = "USB",
140 [MAX77843_CABLE_USB_HOST] = "USB-HOST",
141 [MAX77843_CABLE_TA] = "TA",
142 [MAX77843_CABLE_CHARGE_DOWNSTREAM] = "CHARGER-DOWNSTREAM",
143 [MAX77843_CABLE_FAST_CHARGER] = "FAST-CHARGER",
144 [MAX77843_CABLE_SLOW_CHARGER] = "SLOW-CHARGER",
145 [MAX77843_CABLE_MHL] = "MHL",
146 [MAX77843_CABLE_MHL_TA] = "MHL-TA",
147 [MAX77843_CABLE_JIG_USB_ON] = "JIG-USB-ON",
148 [MAX77843_CABLE_JIG_USB_OFF] = "JIG-USB-OFF",
149 [MAX77843_CABLE_JIG_UART_ON] = "JIG-UART-ON",
150 [MAX77843_CABLE_JIG_UART_OFF] = "JIG-UART-OFF",
151};
152
153struct max77843_muic_irq {
154 unsigned int irq;
155 const char *name;
156 unsigned int virq;
157};
158
159static struct max77843_muic_irq max77843_muic_irqs[] = {
160 { MAX77843_MUIC_IRQ_INT1_ADC, "MUIC-ADC" },
161 { MAX77843_MUIC_IRQ_INT1_ADCERROR, "MUIC-ADC_ERROR" },
162 { MAX77843_MUIC_IRQ_INT1_ADC1K, "MUIC-ADC1K" },
163 { MAX77843_MUIC_IRQ_INT2_CHGTYP, "MUIC-CHGTYP" },
164 { MAX77843_MUIC_IRQ_INT2_CHGDETRUN, "MUIC-CHGDETRUN" },
165 { MAX77843_MUIC_IRQ_INT2_DCDTMR, "MUIC-DCDTMR" },
166 { MAX77843_MUIC_IRQ_INT2_DXOVP, "MUIC-DXOVP" },
167 { MAX77843_MUIC_IRQ_INT2_VBVOLT, "MUIC-VBVOLT" },
168 { MAX77843_MUIC_IRQ_INT3_VBADC, "MUIC-VBADC" },
169 { MAX77843_MUIC_IRQ_INT3_VDNMON, "MUIC-VDNMON" },
170 { MAX77843_MUIC_IRQ_INT3_DNRES, "MUIC-DNRES" },
171 { MAX77843_MUIC_IRQ_INT3_MPNACK, "MUIC-MPNACK"},
172 { MAX77843_MUIC_IRQ_INT3_MRXBUFOW, "MUIC-MRXBUFOW"},
173 { MAX77843_MUIC_IRQ_INT3_MRXTRF, "MUIC-MRXTRF"},
174 { MAX77843_MUIC_IRQ_INT3_MRXPERR, "MUIC-MRXPERR"},
175 { MAX77843_MUIC_IRQ_INT3_MRXRDY, "MUIC-MRXRDY"},
176};
177
178static const struct regmap_config max77843_muic_regmap_config = {
179 .reg_bits = 8,
180 .val_bits = 8,
181 .max_register = MAX77843_MUIC_REG_END,
182};
183
184static const struct regmap_irq max77843_muic_irq[] = {
185 /* INT1 interrupt */
186 { .reg_offset = 0, .mask = MAX77843_MUIC_ADC, },
187 { .reg_offset = 0, .mask = MAX77843_MUIC_ADCERROR, },
188 { .reg_offset = 0, .mask = MAX77843_MUIC_ADC1K, },
189
190 /* INT2 interrupt */
191 { .reg_offset = 1, .mask = MAX77843_MUIC_CHGTYP, },
192 { .reg_offset = 1, .mask = MAX77843_MUIC_CHGDETRUN, },
193 { .reg_offset = 1, .mask = MAX77843_MUIC_DCDTMR, },
194 { .reg_offset = 1, .mask = MAX77843_MUIC_DXOVP, },
195 { .reg_offset = 1, .mask = MAX77843_MUIC_VBVOLT, },
196
197 /* INT3 interrupt */
198 { .reg_offset = 2, .mask = MAX77843_MUIC_VBADC, },
199 { .reg_offset = 2, .mask = MAX77843_MUIC_VDNMON, },
200 { .reg_offset = 2, .mask = MAX77843_MUIC_DNRES, },
201 { .reg_offset = 2, .mask = MAX77843_MUIC_MPNACK, },
202 { .reg_offset = 2, .mask = MAX77843_MUIC_MRXBUFOW, },
203 { .reg_offset = 2, .mask = MAX77843_MUIC_MRXTRF, },
204 { .reg_offset = 2, .mask = MAX77843_MUIC_MRXPERR, },
205 { .reg_offset = 2, .mask = MAX77843_MUIC_MRXRDY, },
206};
207
208static const struct regmap_irq_chip max77843_muic_irq_chip = {
209 .name = "max77843-muic",
210 .status_base = MAX77843_MUIC_REG_INT1,
211 .mask_base = MAX77843_MUIC_REG_INTMASK1,
212 .mask_invert = true,
213 .num_regs = 3,
214 .irqs = max77843_muic_irq,
215 .num_irqs = ARRAY_SIZE(max77843_muic_irq),
216};
217
218static int max77843_muic_set_path(struct max77843_muic_info *info,
219 u8 val, bool attached)
220{
221 struct max77843 *max77843 = info->max77843;
222 int ret = 0;
223 unsigned int ctrl1, ctrl2;
224
225 if (attached)
226 ctrl1 = val;
227 else
228 ctrl1 = CONTROL1_SW_OPEN;
229
230 ret = regmap_update_bits(max77843->regmap_muic,
231 MAX77843_MUIC_REG_CONTROL1,
232 CONTROL1_COM_SW, ctrl1);
233 if (ret < 0) {
234 dev_err(info->dev, "Cannot switch MUIC port\n");
235 return ret;
236 }
237
238 if (attached)
239 ctrl2 = MAX77843_MUIC_CONTROL2_CPEN_MASK;
240 else
241 ctrl2 = MAX77843_MUIC_CONTROL2_LOWPWR_MASK;
242
243 ret = regmap_update_bits(max77843->regmap_muic,
244 MAX77843_MUIC_REG_CONTROL2,
245 MAX77843_MUIC_CONTROL2_LOWPWR_MASK |
246 MAX77843_MUIC_CONTROL2_CPEN_MASK, ctrl2);
247 if (ret < 0) {
248 dev_err(info->dev, "Cannot update lowpower mode\n");
249 return ret;
250 }
251
252 dev_dbg(info->dev,
253 "CONTROL1 : 0x%02x, CONTROL2 : 0x%02x, state : %s\n",
254 ctrl1, ctrl2, attached ? "attached" : "detached");
255
256 return 0;
257}
258
259static int max77843_muic_get_cable_type(struct max77843_muic_info *info,
260 enum max77843_muic_cable_group group, bool *attached)
261{
262 int adc, chg_type, cable_type, gnd_type;
263
264 adc = info->status[MAX77843_MUIC_STATUS1] &
265 MAX77843_MUIC_STATUS1_ADC_MASK;
266 adc >>= STATUS1_ADC_SHIFT;
267
268 switch (group) {
269 case MAX77843_CABLE_GROUP_ADC:
270 if (adc == MAX77843_MUIC_ADC_OPEN) {
271 *attached = false;
272 cable_type = info->prev_cable_type;
273 info->prev_cable_type = MAX77843_MUIC_ADC_OPEN;
274 } else {
275 *attached = true;
276 cable_type = info->prev_cable_type = adc;
277 }
278 break;
279 case MAX77843_CABLE_GROUP_CHG:
280 chg_type = info->status[MAX77843_MUIC_STATUS2] &
281 MAX77843_MUIC_STATUS2_CHGTYP_MASK;
282
283 /* Check GROUND accessory with charger cable */
284 if (adc == MAX77843_MUIC_ADC_GROUND) {
285 if (chg_type == MAX77843_MUIC_CHG_NONE) {
286 /* The following state when charger cable is
287 * disconnected but the GROUND accessory still
288 * connected */
289 *attached = false;
290 cable_type = info->prev_chg_type;
291 info->prev_chg_type = MAX77843_MUIC_CHG_NONE;
292 } else {
293
294 /* The following state when charger cable is
295 * connected on the GROUND accessory */
296 *attached = true;
297 cable_type = MAX77843_MUIC_CHG_GND;
298 info->prev_chg_type = MAX77843_MUIC_CHG_GND;
299 }
300 break;
301 }
302
303 if (chg_type == MAX77843_MUIC_CHG_NONE) {
304 *attached = false;
305 cable_type = info->prev_chg_type;
306 info->prev_chg_type = MAX77843_MUIC_CHG_NONE;
307 } else {
308 *attached = true;
309 cable_type = info->prev_chg_type = chg_type;
310 }
311 break;
312 case MAX77843_CABLE_GROUP_ADC_GND:
313 if (adc == MAX77843_MUIC_ADC_OPEN) {
314 *attached = false;
315 cable_type = info->prev_gnd_type;
316 info->prev_gnd_type = MAX77843_MUIC_ADC_OPEN;
317 } else {
318 *attached = true;
319
320 /* Offset|ADC1K|VBVolt|
321 * 0x1| 0| 0| USB-HOST
322 * 0x1| 0| 1| USB-HOST with VB
323 * 0x1| 1| 0| MHL
324 * 0x1| 1| 1| MHL with VB */
325 /* Get ADC1K register bit */
326 gnd_type = (info->status[MAX77843_MUIC_STATUS1] &
327 MAX77843_MUIC_STATUS1_ADC1K_MASK);
328
329 /* Get VBVolt register bit */
330 gnd_type |= (info->status[MAX77843_MUIC_STATUS2] &
331 MAX77843_MUIC_STATUS2_VBVOLT_MASK);
332 gnd_type >>= STATUS2_VBVOLT_SHIFT;
333
334 /* Offset of GND cable */
335 gnd_type |= MAX77843_MUIC_GND_USB_HOST;
336 cable_type = info->prev_gnd_type = gnd_type;
337 }
338 break;
339 default:
340 dev_err(info->dev, "Unknown cable group (%d)\n", group);
341 cable_type = -EINVAL;
342 break;
343 }
344
345 return cable_type;
346}
347
348static int max77843_muic_adc_gnd_handler(struct max77843_muic_info *info)
349{
350 int ret, gnd_cable_type;
351 bool attached;
352
353 gnd_cable_type = max77843_muic_get_cable_type(info,
354 MAX77843_CABLE_GROUP_ADC_GND, &attached);
355 dev_dbg(info->dev, "external connector is %s (gnd:0x%02x)\n",
356 attached ? "attached" : "detached", gnd_cable_type);
357
358 switch (gnd_cable_type) {
359 case MAX77843_MUIC_GND_USB_HOST:
360 case MAX77843_MUIC_GND_USB_HOST_VB:
361 ret = max77843_muic_set_path(info, CONTROL1_SW_USB, attached);
362 if (ret < 0)
363 return ret;
364
365 extcon_set_cable_state(info->edev, "USB-HOST", attached);
366 break;
367 case MAX77843_MUIC_GND_MHL_VB:
368 case MAX77843_MUIC_GND_MHL:
369 ret = max77843_muic_set_path(info, CONTROL1_SW_OPEN, attached);
370 if (ret < 0)
371 return ret;
372
373 extcon_set_cable_state(info->edev, "MHL", attached);
374 break;
375 default:
376 dev_err(info->dev, "failed to detect %s accessory(gnd:0x%x)\n",
377 attached ? "attached" : "detached", gnd_cable_type);
378 return -EINVAL;
379 }
380
381 return 0;
382}
383
384static int max77843_muic_jig_handler(struct max77843_muic_info *info,
385 int cable_type, bool attached)
386{
387 int ret;
388
389 dev_dbg(info->dev, "external connector is %s (adc:0x%02x)\n",
390 attached ? "attached" : "detached", cable_type);
391
392 switch (cable_type) {
393 case MAX77843_MUIC_ADC_FACTORY_MODE_USB_OFF:
394 ret = max77843_muic_set_path(info, CONTROL1_SW_USB, attached);
395 if (ret < 0)
396 return ret;
397 extcon_set_cable_state(info->edev, "JIG-USB-OFF", attached);
398 break;
399 case MAX77843_MUIC_ADC_FACTORY_MODE_USB_ON:
400 ret = max77843_muic_set_path(info, CONTROL1_SW_USB, attached);
401 if (ret < 0)
402 return ret;
403 extcon_set_cable_state(info->edev, "JIG-USB-ON", attached);
404 break;
405 case MAX77843_MUIC_ADC_FACTORY_MODE_UART_OFF:
406 ret = max77843_muic_set_path(info, CONTROL1_SW_UART, attached);
407 if (ret < 0)
408 return ret;
409 extcon_set_cable_state(info->edev, "JIG-UART-OFF", attached);
410 break;
411 default:
412 ret = max77843_muic_set_path(info, CONTROL1_SW_OPEN, attached);
413 if (ret < 0)
414 return ret;
415 break;
416 }
417
418 return 0;
419}
420
421static int max77843_muic_adc_handler(struct max77843_muic_info *info)
422{
423 int ret, cable_type;
424 bool attached;
425
426 cable_type = max77843_muic_get_cable_type(info,
427 MAX77843_CABLE_GROUP_ADC, &attached);
428
429 dev_dbg(info->dev,
430 "external connector is %s (adc:0x%02x, prev_adc:0x%x)\n",
431 attached ? "attached" : "detached", cable_type,
432 info->prev_cable_type);
433
434 switch (cable_type) {
435 case MAX77843_MUIC_ADC_GROUND:
436 ret = max77843_muic_adc_gnd_handler(info);
437 if (ret < 0)
438 return ret;
439 break;
440 case MAX77843_MUIC_ADC_FACTORY_MODE_USB_OFF:
441 case MAX77843_MUIC_ADC_FACTORY_MODE_USB_ON:
442 case MAX77843_MUIC_ADC_FACTORY_MODE_UART_OFF:
443 ret = max77843_muic_jig_handler(info, cable_type, attached);
444 if (ret < 0)
445 return ret;
446 break;
447 case MAX77843_MUIC_ADC_SEND_END_BUTTON:
448 case MAX77843_MUIC_ADC_REMOTE_S1_BUTTON:
449 case MAX77843_MUIC_ADC_REMOTE_S2_BUTTON:
450 case MAX77843_MUIC_ADC_REMOTE_S3_BUTTON:
451 case MAX77843_MUIC_ADC_REMOTE_S4_BUTTON:
452 case MAX77843_MUIC_ADC_REMOTE_S5_BUTTON:
453 case MAX77843_MUIC_ADC_REMOTE_S6_BUTTON:
454 case MAX77843_MUIC_ADC_REMOTE_S7_BUTTON:
455 case MAX77843_MUIC_ADC_REMOTE_S8_BUTTON:
456 case MAX77843_MUIC_ADC_REMOTE_S9_BUTTON:
457 case MAX77843_MUIC_ADC_REMOTE_S10_BUTTON:
458 case MAX77843_MUIC_ADC_REMOTE_S11_BUTTON:
459 case MAX77843_MUIC_ADC_REMOTE_S12_BUTTON:
460 case MAX77843_MUIC_ADC_RESERVED_ACC_1:
461 case MAX77843_MUIC_ADC_RESERVED_ACC_2:
462 case MAX77843_MUIC_ADC_RESERVED_ACC_3:
463 case MAX77843_MUIC_ADC_RESERVED_ACC_4:
464 case MAX77843_MUIC_ADC_RESERVED_ACC_5:
465 case MAX77843_MUIC_ADC_AUDIO_DEVICE_TYPE2:
466 case MAX77843_MUIC_ADC_PHONE_POWERED_DEV:
467 case MAX77843_MUIC_ADC_TTY_CONVERTER:
468 case MAX77843_MUIC_ADC_UART_CABLE:
469 case MAX77843_MUIC_ADC_CEA936A_TYPE1_CHG:
470 case MAX77843_MUIC_ADC_AV_CABLE_NOLOAD:
471 case MAX77843_MUIC_ADC_CEA936A_TYPE2_CHG:
472 case MAX77843_MUIC_ADC_FACTORY_MODE_UART_ON:
473 case MAX77843_MUIC_ADC_AUDIO_DEVICE_TYPE1:
474 case MAX77843_MUIC_ADC_OPEN:
475 dev_err(info->dev,
476 "accessory is %s but it isn't used (adc:0x%x)\n",
477 attached ? "attached" : "detached", cable_type);
478 return -EAGAIN;
479 default:
480 dev_err(info->dev,
481 "failed to detect %s accessory (adc:0x%x)\n",
482 attached ? "attached" : "detached", cable_type);
483 return -EINVAL;
484 }
485
486 return 0;
487}
488
489static int max77843_muic_chg_handler(struct max77843_muic_info *info)
490{
491 int ret, chg_type, gnd_type;
492 bool attached;
493
494 chg_type = max77843_muic_get_cable_type(info,
495 MAX77843_CABLE_GROUP_CHG, &attached);
496
497 dev_dbg(info->dev,
498 "external connector is %s(chg_type:0x%x, prev_chg_type:0x%x)\n",
499 attached ? "attached" : "detached",
500 chg_type, info->prev_chg_type);
501
502 switch (chg_type) {
503 case MAX77843_MUIC_CHG_USB:
504 ret = max77843_muic_set_path(info, CONTROL1_SW_USB, attached);
505 if (ret < 0)
506 return ret;
507
508 extcon_set_cable_state(info->edev, "USB", attached);
509 break;
510 case MAX77843_MUIC_CHG_DOWNSTREAM:
511 ret = max77843_muic_set_path(info, CONTROL1_SW_OPEN, attached);
512 if (ret < 0)
513 return ret;
514
515 extcon_set_cable_state(info->edev,
516 "CHARGER-DOWNSTREAM", attached);
517 break;
518 case MAX77843_MUIC_CHG_DEDICATED:
519 ret = max77843_muic_set_path(info, CONTROL1_SW_OPEN, attached);
520 if (ret < 0)
521 return ret;
522
523 extcon_set_cable_state(info->edev, "TA", attached);
524 break;
525 case MAX77843_MUIC_CHG_SPECIAL_500MA:
526 ret = max77843_muic_set_path(info, CONTROL1_SW_OPEN, attached);
527 if (ret < 0)
528 return ret;
529
530 extcon_set_cable_state(info->edev, "SLOW-CHAREGER", attached);
531 break;
532 case MAX77843_MUIC_CHG_SPECIAL_1A:
533 ret = max77843_muic_set_path(info, CONTROL1_SW_OPEN, attached);
534 if (ret < 0)
535 return ret;
536
537 extcon_set_cable_state(info->edev, "FAST-CHARGER", attached);
538 break;
539 case MAX77843_MUIC_CHG_GND:
540 gnd_type = max77843_muic_get_cable_type(info,
541 MAX77843_CABLE_GROUP_ADC_GND, &attached);
542
543 /* Charger cable on MHL accessory is attach or detach */
544 if (gnd_type == MAX77843_MUIC_GND_MHL_VB)
545 extcon_set_cable_state(info->edev, "MHL-TA", true);
546 else if (gnd_type == MAX77843_MUIC_GND_MHL)
547 extcon_set_cable_state(info->edev, "MHL-TA", false);
548 break;
549 case MAX77843_MUIC_CHG_NONE:
550 break;
551 default:
552 dev_err(info->dev,
553 "failed to detect %s accessory (chg_type:0x%x)\n",
554 attached ? "attached" : "detached", chg_type);
555
556 max77843_muic_set_path(info, CONTROL1_SW_OPEN, attached);
557 return -EINVAL;
558 }
559
560 return 0;
561}
562
563static void max77843_muic_irq_work(struct work_struct *work)
564{
565 struct max77843_muic_info *info = container_of(work,
566 struct max77843_muic_info, irq_work);
567 struct max77843 *max77843 = info->max77843;
568 int ret = 0;
569
570 mutex_lock(&info->mutex);
571
572 ret = regmap_bulk_read(max77843->regmap_muic,
573 MAX77843_MUIC_REG_STATUS1, info->status,
574 MAX77843_MUIC_STATUS_NUM);
575 if (ret) {
576 dev_err(info->dev, "Cannot read STATUS registers\n");
577 mutex_unlock(&info->mutex);
578 return;
579 }
580
581 if (info->irq_adc) {
582 ret = max77843_muic_adc_handler(info);
583 if (ret)
584 dev_err(info->dev, "Unknown cable type\n");
585 info->irq_adc = false;
586 }
587
588 if (info->irq_chg) {
589 ret = max77843_muic_chg_handler(info);
590 if (ret)
591 dev_err(info->dev, "Unknown charger type\n");
592 info->irq_chg = false;
593 }
594
595 mutex_unlock(&info->mutex);
596}
597
598static irqreturn_t max77843_muic_irq_handler(int irq, void *data)
599{
600 struct max77843_muic_info *info = data;
601 int i, irq_type = -1;
602
603 for (i = 0; i < ARRAY_SIZE(max77843_muic_irqs); i++)
604 if (irq == max77843_muic_irqs[i].virq)
605 irq_type = max77843_muic_irqs[i].irq;
606
607 switch (irq_type) {
608 case MAX77843_MUIC_IRQ_INT1_ADC:
609 case MAX77843_MUIC_IRQ_INT1_ADCERROR:
610 case MAX77843_MUIC_IRQ_INT1_ADC1K:
611 info->irq_adc = true;
612 break;
613 case MAX77843_MUIC_IRQ_INT2_CHGTYP:
614 case MAX77843_MUIC_IRQ_INT2_CHGDETRUN:
615 case MAX77843_MUIC_IRQ_INT2_DCDTMR:
616 case MAX77843_MUIC_IRQ_INT2_DXOVP:
617 case MAX77843_MUIC_IRQ_INT2_VBVOLT:
618 info->irq_chg = true;
619 break;
620 case MAX77843_MUIC_IRQ_INT3_VBADC:
621 case MAX77843_MUIC_IRQ_INT3_VDNMON:
622 case MAX77843_MUIC_IRQ_INT3_DNRES:
623 case MAX77843_MUIC_IRQ_INT3_MPNACK:
624 case MAX77843_MUIC_IRQ_INT3_MRXBUFOW:
625 case MAX77843_MUIC_IRQ_INT3_MRXTRF:
626 case MAX77843_MUIC_IRQ_INT3_MRXPERR:
627 case MAX77843_MUIC_IRQ_INT3_MRXRDY:
628 break;
629 default:
630 dev_err(info->dev, "Cannot recognize IRQ(%d)\n", irq_type);
631 break;
632 }
633
634 schedule_work(&info->irq_work);
635
636 return IRQ_HANDLED;
637}
638
639static void max77843_muic_detect_cable_wq(struct work_struct *work)
640{
641 struct max77843_muic_info *info = container_of(to_delayed_work(work),
642 struct max77843_muic_info, wq_detcable);
643 struct max77843 *max77843 = info->max77843;
644 int chg_type, adc, ret;
645 bool attached;
646
647 mutex_lock(&info->mutex);
648
649 ret = regmap_bulk_read(max77843->regmap_muic,
650 MAX77843_MUIC_REG_STATUS1, info->status,
651 MAX77843_MUIC_STATUS_NUM);
652 if (ret) {
653 dev_err(info->dev, "Cannot read STATUS registers\n");
654 goto err_cable_wq;
655 }
656
657 adc = max77843_muic_get_cable_type(info,
658 MAX77843_CABLE_GROUP_ADC, &attached);
659 if (attached && adc != MAX77843_MUIC_ADC_OPEN) {
660 ret = max77843_muic_adc_handler(info);
661 if (ret < 0) {
662 dev_err(info->dev, "Cannot detect accessory\n");
663 goto err_cable_wq;
664 }
665 }
666
667 chg_type = max77843_muic_get_cable_type(info,
668 MAX77843_CABLE_GROUP_CHG, &attached);
669 if (attached && chg_type != MAX77843_MUIC_CHG_NONE) {
670 ret = max77843_muic_chg_handler(info);
671 if (ret < 0) {
672 dev_err(info->dev, "Cannot detect charger accessory\n");
673 goto err_cable_wq;
674 }
675 }
676
677err_cable_wq:
678 mutex_unlock(&info->mutex);
679}
680
681static int max77843_muic_set_debounce_time(struct max77843_muic_info *info,
682 enum max77843_muic_adc_debounce_time time)
683{
684 struct max77843 *max77843 = info->max77843;
685 int ret;
686
687 switch (time) {
688 case MAX77843_DEBOUNCE_TIME_5MS:
689 case MAX77843_DEBOUNCE_TIME_10MS:
690 case MAX77843_DEBOUNCE_TIME_25MS:
691 case MAX77843_DEBOUNCE_TIME_38_62MS:
692 ret = regmap_update_bits(max77843->regmap_muic,
693 MAX77843_MUIC_REG_CONTROL4,
694 MAX77843_MUIC_CONTROL4_ADCDBSET_MASK,
695 time << CONTROL4_ADCDBSET_SHIFT);
696 if (ret < 0) {
697 dev_err(info->dev, "Cannot write MUIC regmap\n");
698 return ret;
699 }
700 break;
701 default:
702 dev_err(info->dev, "Invalid ADC debounce time\n");
703 return -EINVAL;
704 }
705
706 return 0;
707}
708
709static int max77843_init_muic_regmap(struct max77843 *max77843)
710{
711 int ret;
712
713 max77843->i2c_muic = i2c_new_dummy(max77843->i2c->adapter,
714 I2C_ADDR_MUIC);
715 if (!max77843->i2c_muic) {
716 dev_err(&max77843->i2c->dev,
717 "Cannot allocate I2C device for MUIC\n");
718 return -ENOMEM;
719 }
720
721 i2c_set_clientdata(max77843->i2c_muic, max77843);
722
723 max77843->regmap_muic = devm_regmap_init_i2c(max77843->i2c_muic,
724 &max77843_muic_regmap_config);
725 if (IS_ERR(max77843->regmap_muic)) {
726 ret = PTR_ERR(max77843->regmap_muic);
727 goto err_muic_i2c;
728 }
729
730 ret = regmap_add_irq_chip(max77843->regmap_muic, max77843->irq,
731 IRQF_TRIGGER_LOW | IRQF_ONESHOT | IRQF_SHARED,
732 0, &max77843_muic_irq_chip, &max77843->irq_data_muic);
733 if (ret < 0) {
734 dev_err(&max77843->i2c->dev, "Cannot add MUIC IRQ chip\n");
735 goto err_muic_i2c;
736 }
737
738 return 0;
739
740err_muic_i2c:
741 i2c_unregister_device(max77843->i2c_muic);
742
743 return ret;
744}
745
746static int max77843_muic_probe(struct platform_device *pdev)
747{
748 struct max77843 *max77843 = dev_get_drvdata(pdev->dev.parent);
749 struct max77843_muic_info *info;
750 unsigned int id;
751 int i, ret;
752
753 info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
754 if (!info)
755 return -ENOMEM;
756
757 info->dev = &pdev->dev;
758 info->max77843 = max77843;
759
760 platform_set_drvdata(pdev, info);
761 mutex_init(&info->mutex);
762
763 /* Initialize i2c and regmap */
764 ret = max77843_init_muic_regmap(max77843);
765 if (ret) {
766 dev_err(&pdev->dev, "Failed to init MUIC regmap\n");
767 return ret;
768 }
769
770 /* Turn off auto detection configuration */
771 ret = regmap_update_bits(max77843->regmap_muic,
772 MAX77843_MUIC_REG_CONTROL4,
773 MAX77843_MUIC_CONTROL4_USBAUTO_MASK |
774 MAX77843_MUIC_CONTROL4_FCTAUTO_MASK,
775 CONTROL4_AUTO_DISABLE);
776
777 /* Initialize extcon device */
778 info->edev = devm_extcon_dev_allocate(&pdev->dev,
779 max77843_extcon_cable);
780 if (IS_ERR(info->edev)) {
781 dev_err(&pdev->dev, "Failed to allocate memory for extcon\n");
782 ret = -ENODEV;
783 goto err_muic_irq;
784 }
785
786 ret = devm_extcon_dev_register(&pdev->dev, info->edev);
787 if (ret) {
788 dev_err(&pdev->dev, "Failed to register extcon device\n");
789 goto err_muic_irq;
790 }
791
792 /* Set ADC debounce time */
793 max77843_muic_set_debounce_time(info, MAX77843_DEBOUNCE_TIME_25MS);
794
795 /* Set initial path for UART */
796 max77843_muic_set_path(info, CONTROL1_SW_UART, true);
797
798 /* Check revision number of MUIC device */
799 ret = regmap_read(max77843->regmap_muic, MAX77843_MUIC_REG_ID, &id);
800 if (ret < 0) {
801 dev_err(&pdev->dev, "Failed to read revision number\n");
802 goto err_muic_irq;
803 }
804 dev_info(info->dev, "MUIC device ID : 0x%x\n", id);
805
806 /* Support virtual irq domain for max77843 MUIC device */
807 INIT_WORK(&info->irq_work, max77843_muic_irq_work);
808
809 for (i = 0; i < ARRAY_SIZE(max77843_muic_irqs); i++) {
810 struct max77843_muic_irq *muic_irq = &max77843_muic_irqs[i];
811 unsigned int virq = 0;
812
813 virq = regmap_irq_get_virq(max77843->irq_data_muic,
814 muic_irq->irq);
815 if (virq <= 0) {
816 ret = -EINVAL;
817 goto err_muic_irq;
818 }
819 muic_irq->virq = virq;
820
821 ret = devm_request_threaded_irq(&pdev->dev, virq, NULL,
822 max77843_muic_irq_handler, IRQF_NO_SUSPEND,
823 muic_irq->name, info);
824 if (ret) {
825 dev_err(&pdev->dev,
826 "Failed to request irq (IRQ: %d, error: %d)\n",
827 muic_irq->irq, ret);
828 goto err_muic_irq;
829 }
830 }
831
832 /* Detect accessory after completing the initialization of platform */
833 INIT_DELAYED_WORK(&info->wq_detcable, max77843_muic_detect_cable_wq);
834 queue_delayed_work(system_power_efficient_wq,
835 &info->wq_detcable, msecs_to_jiffies(DELAY_MS_DEFAULT));
836
837 return 0;
838
839err_muic_irq:
840 regmap_del_irq_chip(max77843->irq, max77843->irq_data_muic);
841 i2c_unregister_device(max77843->i2c_muic);
842
843 return ret;
844}
845
846static int max77843_muic_remove(struct platform_device *pdev)
847{
848 struct max77843_muic_info *info = platform_get_drvdata(pdev);
849 struct max77843 *max77843 = info->max77843;
850
851 cancel_work_sync(&info->irq_work);
852 regmap_del_irq_chip(max77843->irq, max77843->irq_data_muic);
853 i2c_unregister_device(max77843->i2c_muic);
854
855 return 0;
856}
857
858static const struct platform_device_id max77843_muic_id[] = {
859 { "max77843-muic", },
860 { /* sentinel */ },
861};
862MODULE_DEVICE_TABLE(platform, max77843_muic_id);
863
864static struct platform_driver max77843_muic_driver = {
865 .driver = {
866 .name = "max77843-muic",
867 },
868 .probe = max77843_muic_probe,
869 .remove = max77843_muic_remove,
870 .id_table = max77843_muic_id,
871};
872
873static int __init max77843_muic_init(void)
874{
875 return platform_driver_register(&max77843_muic_driver);
876}
877subsys_initcall(max77843_muic_init);
878
879MODULE_DESCRIPTION("Maxim MAX77843 Extcon driver");
880MODULE_AUTHOR("Jaewon Kim <jaewon02.kim@samsung.com>");
881MODULE_LICENSE("GPL");
diff --git a/drivers/extcon/extcon-max8997.c b/drivers/extcon/extcon-max8997.c
index fc1678fa95c4..5774e56c6422 100644
--- a/drivers/extcon/extcon-max8997.c
+++ b/drivers/extcon/extcon-max8997.c
@@ -579,8 +579,6 @@ static void max8997_muic_irq_work(struct work_struct *work)
579 dev_err(info->dev, "failed to handle MUIC interrupt\n"); 579 dev_err(info->dev, "failed to handle MUIC interrupt\n");
580 580
581 mutex_unlock(&info->mutex); 581 mutex_unlock(&info->mutex);
582
583 return;
584} 582}
585 583
586static irqreturn_t max8997_muic_irq_handler(int irq, void *data) 584static irqreturn_t max8997_muic_irq_handler(int irq, void *data)
@@ -689,8 +687,7 @@ static int max8997_muic_probe(struct platform_device *pdev)
689 muic_irq->name, info); 687 muic_irq->name, info);
690 if (ret) { 688 if (ret) {
691 dev_err(&pdev->dev, 689 dev_err(&pdev->dev,
692 "failed: irq request (IRQ: %d," 690 "failed: irq request (IRQ: %d, error :%d)\n",
693 " error :%d)\n",
694 muic_irq->irq, ret); 691 muic_irq->irq, ret);
695 goto err_irq; 692 goto err_irq;
696 } 693 }
diff --git a/drivers/extcon/extcon-rt8973a.c b/drivers/extcon/extcon-rt8973a.c
index a784b2d5ee72..9ccd5af89d1c 100644
--- a/drivers/extcon/extcon-rt8973a.c
+++ b/drivers/extcon/extcon-rt8973a.c
@@ -582,10 +582,8 @@ static int rt8973a_muic_i2c_probe(struct i2c_client *i2c,
582 return -EINVAL; 582 return -EINVAL;
583 583
584 info = devm_kzalloc(&i2c->dev, sizeof(*info), GFP_KERNEL); 584 info = devm_kzalloc(&i2c->dev, sizeof(*info), GFP_KERNEL);
585 if (!info) { 585 if (!info)
586 dev_err(&i2c->dev, "failed to allocate memory\n");
587 return -ENOMEM; 586 return -ENOMEM;
588 }
589 i2c_set_clientdata(i2c, info); 587 i2c_set_clientdata(i2c, info);
590 588
591 info->dev = &i2c->dev; 589 info->dev = &i2c->dev;
@@ -681,7 +679,7 @@ static int rt8973a_muic_i2c_remove(struct i2c_client *i2c)
681 return 0; 679 return 0;
682} 680}
683 681
684static struct of_device_id rt8973a_dt_match[] = { 682static const struct of_device_id rt8973a_dt_match[] = {
685 { .compatible = "richtek,rt8973a-muic" }, 683 { .compatible = "richtek,rt8973a-muic" },
686 { }, 684 { },
687}; 685};
diff --git a/drivers/extcon/extcon-sm5502.c b/drivers/extcon/extcon-sm5502.c
index b0f7bd82af90..2f93cf307852 100644
--- a/drivers/extcon/extcon-sm5502.c
+++ b/drivers/extcon/extcon-sm5502.c
@@ -359,8 +359,8 @@ static unsigned int sm5502_muic_get_cable_type(struct sm5502_muic_info *info)
359 break; 359 break;
360 default: 360 default:
361 dev_dbg(info->dev, 361 dev_dbg(info->dev,
362 "cannot identify the cable type: adc(0x%x) " 362 "cannot identify the cable type: adc(0x%x)\n",
363 "dev_type1(0x%x)\n", adc, dev_type1); 363 adc);
364 return -EINVAL; 364 return -EINVAL;
365 }; 365 };
366 break; 366 break;
@@ -659,7 +659,7 @@ static int sm5502_muic_i2c_remove(struct i2c_client *i2c)
659 return 0; 659 return 0;
660} 660}
661 661
662static struct of_device_id sm5502_dt_match[] = { 662static const struct of_device_id sm5502_dt_match[] = {
663 { .compatible = "siliconmitus,sm5502-muic" }, 663 { .compatible = "siliconmitus,sm5502-muic" },
664 { }, 664 { },
665}; 665};
diff --git a/drivers/extcon/extcon-usb-gpio.c b/drivers/extcon/extcon-usb-gpio.c
new file mode 100644
index 000000000000..de67fce18984
--- /dev/null
+++ b/drivers/extcon/extcon-usb-gpio.c
@@ -0,0 +1,237 @@
1/**
2 * drivers/extcon/extcon-usb-gpio.c - USB GPIO extcon driver
3 *
4 * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com
5 * Author: Roger Quadros <rogerq@ti.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 version 2 as
9 * published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 */
16
17#include <linux/extcon.h>
18#include <linux/init.h>
19#include <linux/interrupt.h>
20#include <linux/irq.h>
21#include <linux/kernel.h>
22#include <linux/module.h>
23#include <linux/of_gpio.h>
24#include <linux/platform_device.h>
25#include <linux/slab.h>
26#include <linux/workqueue.h>
27
28#define USB_GPIO_DEBOUNCE_MS 20 /* ms */
29
30struct usb_extcon_info {
31 struct device *dev;
32 struct extcon_dev *edev;
33
34 struct gpio_desc *id_gpiod;
35 int id_irq;
36
37 unsigned long debounce_jiffies;
38 struct delayed_work wq_detcable;
39};
40
41/* List of detectable cables */
42enum {
43 EXTCON_CABLE_USB = 0,
44 EXTCON_CABLE_USB_HOST,
45
46 EXTCON_CABLE_END,
47};
48
49static const char *usb_extcon_cable[] = {
50 [EXTCON_CABLE_USB] = "USB",
51 [EXTCON_CABLE_USB_HOST] = "USB-HOST",
52 NULL,
53};
54
55static void usb_extcon_detect_cable(struct work_struct *work)
56{
57 int id;
58 struct usb_extcon_info *info = container_of(to_delayed_work(work),
59 struct usb_extcon_info,
60 wq_detcable);
61
62 /* check ID and update cable state */
63 id = gpiod_get_value_cansleep(info->id_gpiod);
64 if (id) {
65 /*
66 * ID = 1 means USB HOST cable detached.
67 * As we don't have event for USB peripheral cable attached,
68 * we simulate USB peripheral attach here.
69 */
70 extcon_set_cable_state(info->edev,
71 usb_extcon_cable[EXTCON_CABLE_USB_HOST],
72 false);
73 extcon_set_cable_state(info->edev,
74 usb_extcon_cable[EXTCON_CABLE_USB],
75 true);
76 } else {
77 /*
78 * ID = 0 means USB HOST cable attached.
79 * As we don't have event for USB peripheral cable detached,
80 * we simulate USB peripheral detach here.
81 */
82 extcon_set_cable_state(info->edev,
83 usb_extcon_cable[EXTCON_CABLE_USB],
84 false);
85 extcon_set_cable_state(info->edev,
86 usb_extcon_cable[EXTCON_CABLE_USB_HOST],
87 true);
88 }
89}
90
91static irqreturn_t usb_irq_handler(int irq, void *dev_id)
92{
93 struct usb_extcon_info *info = dev_id;
94
95 queue_delayed_work(system_power_efficient_wq, &info->wq_detcable,
96 info->debounce_jiffies);
97
98 return IRQ_HANDLED;
99}
100
101static int usb_extcon_probe(struct platform_device *pdev)
102{
103 struct device *dev = &pdev->dev;
104 struct device_node *np = dev->of_node;
105 struct usb_extcon_info *info;
106 int ret;
107
108 if (!np)
109 return -EINVAL;
110
111 info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
112 if (!info)
113 return -ENOMEM;
114
115 info->dev = dev;
116 info->id_gpiod = devm_gpiod_get(&pdev->dev, "id");
117 if (IS_ERR(info->id_gpiod)) {
118 dev_err(dev, "failed to get ID GPIO\n");
119 return PTR_ERR(info->id_gpiod);
120 }
121
122 ret = gpiod_set_debounce(info->id_gpiod,
123 USB_GPIO_DEBOUNCE_MS * 1000);
124 if (ret < 0)
125 info->debounce_jiffies = msecs_to_jiffies(USB_GPIO_DEBOUNCE_MS);
126
127 INIT_DELAYED_WORK(&info->wq_detcable, usb_extcon_detect_cable);
128
129 info->id_irq = gpiod_to_irq(info->id_gpiod);
130 if (info->id_irq < 0) {
131 dev_err(dev, "failed to get ID IRQ\n");
132 return info->id_irq;
133 }
134
135 ret = devm_request_threaded_irq(dev, info->id_irq, NULL,
136 usb_irq_handler,
137 IRQF_TRIGGER_RISING |
138 IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
139 pdev->name, info);
140 if (ret < 0) {
141 dev_err(dev, "failed to request handler for ID IRQ\n");
142 return ret;
143 }
144
145 info->edev = devm_extcon_dev_allocate(dev, usb_extcon_cable);
146 if (IS_ERR(info->edev)) {
147 dev_err(dev, "failed to allocate extcon device\n");
148 return -ENOMEM;
149 }
150
151 ret = devm_extcon_dev_register(dev, info->edev);
152 if (ret < 0) {
153 dev_err(dev, "failed to register extcon device\n");
154 return ret;
155 }
156
157 platform_set_drvdata(pdev, info);
158 device_init_wakeup(dev, 1);
159
160 /* Perform initial detection */
161 usb_extcon_detect_cable(&info->wq_detcable.work);
162
163 return 0;
164}
165
166static int usb_extcon_remove(struct platform_device *pdev)
167{
168 struct usb_extcon_info *info = platform_get_drvdata(pdev);
169
170 cancel_delayed_work_sync(&info->wq_detcable);
171
172 return 0;
173}
174
175#ifdef CONFIG_PM_SLEEP
176static int usb_extcon_suspend(struct device *dev)
177{
178 struct usb_extcon_info *info = dev_get_drvdata(dev);
179 int ret = 0;
180
181 if (device_may_wakeup(dev)) {
182 ret = enable_irq_wake(info->id_irq);
183 if (ret)
184 return ret;
185 }
186
187 /*
188 * We don't want to process any IRQs after this point
189 * as GPIOs used behind I2C subsystem might not be
190 * accessible until resume completes. So disable IRQ.
191 */
192 disable_irq(info->id_irq);
193
194 return ret;
195}
196
197static int usb_extcon_resume(struct device *dev)
198{
199 struct usb_extcon_info *info = dev_get_drvdata(dev);
200 int ret = 0;
201
202 if (device_may_wakeup(dev)) {
203 ret = disable_irq_wake(info->id_irq);
204 if (ret)
205 return ret;
206 }
207
208 enable_irq(info->id_irq);
209
210 return ret;
211}
212#endif
213
214static SIMPLE_DEV_PM_OPS(usb_extcon_pm_ops,
215 usb_extcon_suspend, usb_extcon_resume);
216
217static const struct of_device_id usb_extcon_dt_match[] = {
218 { .compatible = "linux,extcon-usb-gpio", },
219 { /* sentinel */ }
220};
221MODULE_DEVICE_TABLE(of, usb_extcon_dt_match);
222
223static struct platform_driver usb_extcon_driver = {
224 .probe = usb_extcon_probe,
225 .remove = usb_extcon_remove,
226 .driver = {
227 .name = "extcon-usb-gpio",
228 .pm = &usb_extcon_pm_ops,
229 .of_match_table = usb_extcon_dt_match,
230 },
231};
232
233module_platform_driver(usb_extcon_driver);
234
235MODULE_AUTHOR("Roger Quadros <rogerq@ti.com>");
236MODULE_DESCRIPTION("USB GPIO extcon driver");
237MODULE_LICENSE("GPL v2");
diff --git a/drivers/extcon/extcon-class.c b/drivers/extcon/extcon.c
index 8319f25b7145..4c9f165e4a04 100644
--- a/drivers/extcon/extcon-class.c
+++ b/drivers/extcon/extcon.c
@@ -158,6 +158,7 @@ static ssize_t name_show(struct device *dev, struct device_attribute *attr,
158 /* Optional callback given by the user */ 158 /* Optional callback given by the user */
159 if (edev->print_name) { 159 if (edev->print_name) {
160 int ret = edev->print_name(edev, buf); 160 int ret = edev->print_name(edev, buf);
161
161 if (ret >= 0) 162 if (ret >= 0)
162 return ret; 163 return ret;
163 } 164 }
@@ -444,6 +445,9 @@ int extcon_register_interest(struct extcon_specific_cable_nb *obj,
444 const char *extcon_name, const char *cable_name, 445 const char *extcon_name, const char *cable_name,
445 struct notifier_block *nb) 446 struct notifier_block *nb)
446{ 447{
448 unsigned long flags;
449 int ret;
450
447 if (!obj || !cable_name || !nb) 451 if (!obj || !cable_name || !nb)
448 return -EINVAL; 452 return -EINVAL;
449 453
@@ -461,8 +465,11 @@ int extcon_register_interest(struct extcon_specific_cable_nb *obj,
461 465
462 obj->internal_nb.notifier_call = _call_per_cable; 466 obj->internal_nb.notifier_call = _call_per_cable;
463 467
464 return raw_notifier_chain_register(&obj->edev->nh, 468 spin_lock_irqsave(&obj->edev->lock, flags);
469 ret = raw_notifier_chain_register(&obj->edev->nh,
465 &obj->internal_nb); 470 &obj->internal_nb);
471 spin_unlock_irqrestore(&obj->edev->lock, flags);
472 return ret;
466 } else { 473 } else {
467 struct class_dev_iter iter; 474 struct class_dev_iter iter;
468 struct extcon_dev *extd; 475 struct extcon_dev *extd;
@@ -495,10 +502,17 @@ EXPORT_SYMBOL_GPL(extcon_register_interest);
495 */ 502 */
496int extcon_unregister_interest(struct extcon_specific_cable_nb *obj) 503int extcon_unregister_interest(struct extcon_specific_cable_nb *obj)
497{ 504{
505 unsigned long flags;
506 int ret;
507
498 if (!obj) 508 if (!obj)
499 return -EINVAL; 509 return -EINVAL;
500 510
501 return raw_notifier_chain_unregister(&obj->edev->nh, &obj->internal_nb); 511 spin_lock_irqsave(&obj->edev->lock, flags);
512 ret = raw_notifier_chain_unregister(&obj->edev->nh, &obj->internal_nb);
513 spin_unlock_irqrestore(&obj->edev->lock, flags);
514
515 return ret;
502} 516}
503EXPORT_SYMBOL_GPL(extcon_unregister_interest); 517EXPORT_SYMBOL_GPL(extcon_unregister_interest);
504 518
@@ -515,7 +529,14 @@ EXPORT_SYMBOL_GPL(extcon_unregister_interest);
515int extcon_register_notifier(struct extcon_dev *edev, 529int extcon_register_notifier(struct extcon_dev *edev,
516 struct notifier_block *nb) 530 struct notifier_block *nb)
517{ 531{
518 return raw_notifier_chain_register(&edev->nh, nb); 532 unsigned long flags;
533 int ret;
534
535 spin_lock_irqsave(&edev->lock, flags);
536 ret = raw_notifier_chain_register(&edev->nh, nb);
537 spin_unlock_irqrestore(&edev->lock, flags);
538
539 return ret;
519} 540}
520EXPORT_SYMBOL_GPL(extcon_register_notifier); 541EXPORT_SYMBOL_GPL(extcon_register_notifier);
521 542
@@ -527,7 +548,14 @@ EXPORT_SYMBOL_GPL(extcon_register_notifier);
527int extcon_unregister_notifier(struct extcon_dev *edev, 548int extcon_unregister_notifier(struct extcon_dev *edev,
528 struct notifier_block *nb) 549 struct notifier_block *nb)
529{ 550{
530 return raw_notifier_chain_unregister(&edev->nh, nb); 551 unsigned long flags;
552 int ret;
553
554 spin_lock_irqsave(&edev->lock, flags);
555 ret = raw_notifier_chain_unregister(&edev->nh, nb);
556 spin_unlock_irqrestore(&edev->lock, flags);
557
558 return ret;
531} 559}
532EXPORT_SYMBOL_GPL(extcon_unregister_notifier); 560EXPORT_SYMBOL_GPL(extcon_unregister_notifier);
533 561