diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-02-22 14:38:22 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-02-22 14:38:22 -0500 |
commit | e30aee9e10bb5168579e047f05c3d13d09e23356 (patch) | |
tree | 12371bdcd52d2427cad838201997479e31b6a9c9 /drivers/extcon | |
parent | 8ff546b801e5cca0337c0f0a7234795d0a6309a1 (diff) | |
parent | 6cf18e6927c0b224f972e3042fb85770d63cb9f8 (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/Kconfig | 10 | ||||
-rw-r--r-- | drivers/extcon/Makefile | 1 | ||||
-rw-r--r-- | drivers/extcon/devres.c | 2 | ||||
-rw-r--r-- | drivers/extcon/extcon-adc-jack.c | 2 | ||||
-rw-r--r-- | drivers/extcon/extcon-arizona.c | 20 | ||||
-rw-r--r-- | drivers/extcon/extcon-axp288.c | 110 | ||||
-rw-r--r-- | drivers/extcon/extcon-intel-int3496.c | 179 | ||||
-rw-r--r-- | drivers/extcon/extcon-max14577.c | 6 | ||||
-rw-r--r-- | drivers/extcon/extcon-max77693.c | 12 | ||||
-rw-r--r-- | drivers/extcon/extcon-max77843.c | 24 | ||||
-rw-r--r-- | drivers/extcon/extcon-palmas.c | 21 | ||||
-rw-r--r-- | drivers/extcon/extcon-rt8973a.c | 6 | ||||
-rw-r--r-- | drivers/extcon/extcon-sm5502.c | 6 | ||||
-rw-r--r-- | drivers/extcon/extcon-usb-gpio.c | 7 | ||||
-rw-r--r-- | drivers/extcon/extcon.c | 43 | ||||
-rw-r--r-- | drivers/extcon/extcon.h | 62 |
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 | ||
45 | config 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 | |||
45 | config EXTCON_MAX14577 | 55 | config 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 | |||
8 | obj-$(CONFIG_EXTCON_ARIZONA) += extcon-arizona.o | 8 | obj-$(CONFIG_EXTCON_ARIZONA) += extcon-arizona.o |
9 | obj-$(CONFIG_EXTCON_AXP288) += extcon-axp288.o | 9 | obj-$(CONFIG_EXTCON_AXP288) += extcon-axp288.o |
10 | obj-$(CONFIG_EXTCON_GPIO) += extcon-gpio.o | 10 | obj-$(CONFIG_EXTCON_GPIO) += extcon-gpio.o |
11 | obj-$(CONFIG_EXTCON_INTEL_INT3496) += extcon-intel-int3496.o | ||
11 | obj-$(CONFIG_EXTCON_MAX14577) += extcon-max14577.o | 12 | obj-$(CONFIG_EXTCON_MAX14577) += extcon-max14577.o |
12 | obj-$(CONFIG_EXTCON_MAX3355) += extcon-max3355.o | 13 | obj-$(CONFIG_EXTCON_MAX3355) += extcon-max3355.o |
13 | obj-$(CONFIG_EXTCON_MAX77693) += extcon-max77693.o | 14 | obj-$(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 | ||
19 | static int devm_extcon_dev_match(struct device *dev, void *res, void *data) | 19 | static 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 | |||
80 | enum axp288_extcon_reg { | 73 | enum 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 | ||
91 | enum axp288_mux_select { | 82 | enum 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 | ||
157 | static int axp288_handle_chrg_det_event(struct axp288_extcon_info *info) | 149 | static 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 | ||
213 | notify_otg: | 199 | no_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 | ||
256 | static void axp288_extcon_enable_irq(struct axp288_extcon_info *info) | 243 | static 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 | ||
329 | static const struct platform_device_id axp288_extcon_table[] = { | ||
330 | { .name = "axp288_extcon" }, | ||
331 | {}, | ||
332 | }; | ||
333 | MODULE_DEVICE_TABLE(platform, axp288_extcon_table); | ||
334 | |||
358 | static struct platform_driver axp288_extcon_driver = { | 335 | static 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 | |||
33 | struct 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 | |||
43 | static const unsigned int int3496_cable[] = { | ||
44 | EXTCON_USB_HOST, | ||
45 | EXTCON_NONE, | ||
46 | }; | ||
47 | |||
48 | static 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 | |||
70 | static 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 | |||
80 | static 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 | |||
150 | static 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 | |||
160 | static struct acpi_device_id int3496_acpi_match[] = { | ||
161 | { "INT3496" }, | ||
162 | { } | ||
163 | }; | ||
164 | MODULE_DEVICE_TABLE(acpi, int3496_acpi_match); | ||
165 | |||
166 | static 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 | |||
175 | module_platform_driver(int3496_driver); | ||
176 | |||
177 | MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>"); | ||
178 | MODULE_DESCRIPTION("Intel INT3496 ACPI device extcon driver"); | ||
179 | MODULE_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 | */ | ||
38 | struct 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__ */ | ||