Lines Matching +full:vbus +full:- +full:gpio
1 // SPDX-License-Identifier: GPL-2.0-only
3 * drivers/extcon/extcon-usb-gpio.c - USB GPIO extcon driver
5 * Copyright (C) 2015 Texas Instruments Incorporated - https://www.ti.com
9 #include <linux/extcon-provider.h>
10 #include <linux/gpio.h>
11 #include <linux/gpio/consumer.h>
45 * "USB" = VBUS and "USB-HOST" = !ID, so we have:
46 * Both "USB" and "USB-HOST" can't be set as active at the
47 * same time so if "USB-HOST" is active (i.e. ID is 0) we keep "USB" inactive
48 * even if VBUS is on.
50 * State | ID | VBUS
51 * ----------------------------------------
54 * [3] USB-HOST | L | H
55 * [4] USB-HOST | L | L
58 * - VBUS only - we want to distinguish between [1] and [2], so ID is always 1.
59 * - ID only - we want to distinguish between [1] and [4], so VBUS = ID.
63 int id, vbus; in usb_extcon_detect_cable() local
68 /* check ID and VBUS and update cable state */ in usb_extcon_detect_cable()
69 id = info->id_gpiod ? in usb_extcon_detect_cable()
70 gpiod_get_value_cansleep(info->id_gpiod) : 1; in usb_extcon_detect_cable()
71 vbus = info->vbus_gpiod ? in usb_extcon_detect_cable()
72 gpiod_get_value_cansleep(info->vbus_gpiod) : id; in usb_extcon_detect_cable()
76 extcon_set_state_sync(info->edev, EXTCON_USB_HOST, false); in usb_extcon_detect_cable()
77 if (!vbus) in usb_extcon_detect_cable()
78 extcon_set_state_sync(info->edev, EXTCON_USB, false); in usb_extcon_detect_cable()
81 extcon_set_state_sync(info->edev, EXTCON_USB_HOST, true); in usb_extcon_detect_cable()
83 if (vbus) in usb_extcon_detect_cable()
84 extcon_set_state_sync(info->edev, EXTCON_USB, true); in usb_extcon_detect_cable()
92 queue_delayed_work(system_power_efficient_wq, &info->wq_detcable, in usb_irq_handler()
93 info->debounce_jiffies); in usb_irq_handler()
100 struct device *dev = &pdev->dev; in usb_extcon_probe()
101 struct device_node *np = dev->of_node; in usb_extcon_probe()
106 return -EINVAL; in usb_extcon_probe()
108 info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); in usb_extcon_probe()
110 return -ENOMEM; in usb_extcon_probe()
112 info->dev = dev; in usb_extcon_probe()
113 info->id_gpiod = devm_gpiod_get_optional(&pdev->dev, "id", GPIOD_IN); in usb_extcon_probe()
114 info->vbus_gpiod = devm_gpiod_get_optional(&pdev->dev, "vbus", in usb_extcon_probe()
117 if (!info->id_gpiod && !info->vbus_gpiod) { in usb_extcon_probe()
119 return -ENODEV; in usb_extcon_probe()
122 if (IS_ERR(info->id_gpiod)) in usb_extcon_probe()
123 return PTR_ERR(info->id_gpiod); in usb_extcon_probe()
125 if (IS_ERR(info->vbus_gpiod)) in usb_extcon_probe()
126 return PTR_ERR(info->vbus_gpiod); in usb_extcon_probe()
128 info->edev = devm_extcon_dev_allocate(dev, usb_extcon_cable); in usb_extcon_probe()
129 if (IS_ERR(info->edev)) { in usb_extcon_probe()
131 return -ENOMEM; in usb_extcon_probe()
134 ret = devm_extcon_dev_register(dev, info->edev); in usb_extcon_probe()
140 if (info->id_gpiod) in usb_extcon_probe()
141 ret = gpiod_set_debounce(info->id_gpiod, in usb_extcon_probe()
143 if (!ret && info->vbus_gpiod) in usb_extcon_probe()
144 ret = gpiod_set_debounce(info->vbus_gpiod, in usb_extcon_probe()
148 info->debounce_jiffies = msecs_to_jiffies(USB_GPIO_DEBOUNCE_MS); in usb_extcon_probe()
150 INIT_DELAYED_WORK(&info->wq_detcable, usb_extcon_detect_cable); in usb_extcon_probe()
152 if (info->id_gpiod) { in usb_extcon_probe()
153 info->id_irq = gpiod_to_irq(info->id_gpiod); in usb_extcon_probe()
154 if (info->id_irq < 0) { in usb_extcon_probe()
156 return info->id_irq; in usb_extcon_probe()
159 ret = devm_request_threaded_irq(dev, info->id_irq, NULL, in usb_extcon_probe()
163 pdev->name, info); in usb_extcon_probe()
170 if (info->vbus_gpiod) { in usb_extcon_probe()
171 info->vbus_irq = gpiod_to_irq(info->vbus_gpiod); in usb_extcon_probe()
172 if (info->vbus_irq < 0) { in usb_extcon_probe()
173 dev_err(dev, "failed to get VBUS IRQ\n"); in usb_extcon_probe()
174 return info->vbus_irq; in usb_extcon_probe()
177 ret = devm_request_threaded_irq(dev, info->vbus_irq, NULL, in usb_extcon_probe()
181 pdev->name, info); in usb_extcon_probe()
183 dev_err(dev, "failed to request handler for VBUS IRQ\n"); in usb_extcon_probe()
189 device_set_wakeup_capable(&pdev->dev, true); in usb_extcon_probe()
192 usb_extcon_detect_cable(&info->wq_detcable.work); in usb_extcon_probe()
201 cancel_delayed_work_sync(&info->wq_detcable); in usb_extcon_remove()
202 device_init_wakeup(&pdev->dev, false); in usb_extcon_remove()
214 if (info->id_gpiod) { in usb_extcon_suspend()
215 ret = enable_irq_wake(info->id_irq); in usb_extcon_suspend()
219 if (info->vbus_gpiod) { in usb_extcon_suspend()
220 ret = enable_irq_wake(info->vbus_irq); in usb_extcon_suspend()
222 if (info->id_gpiod) in usb_extcon_suspend()
223 disable_irq_wake(info->id_irq); in usb_extcon_suspend()
235 if (info->id_gpiod) in usb_extcon_suspend()
236 disable_irq(info->id_irq); in usb_extcon_suspend()
237 if (info->vbus_gpiod) in usb_extcon_suspend()
238 disable_irq(info->vbus_irq); in usb_extcon_suspend()
255 if (info->id_gpiod) { in usb_extcon_resume()
256 ret = disable_irq_wake(info->id_irq); in usb_extcon_resume()
260 if (info->vbus_gpiod) { in usb_extcon_resume()
261 ret = disable_irq_wake(info->vbus_irq); in usb_extcon_resume()
263 if (info->id_gpiod) in usb_extcon_resume()
264 enable_irq_wake(info->id_irq); in usb_extcon_resume()
271 if (info->id_gpiod) in usb_extcon_resume()
272 enable_irq(info->id_irq); in usb_extcon_resume()
273 if (info->vbus_gpiod) in usb_extcon_resume()
274 enable_irq(info->vbus_irq); in usb_extcon_resume()
277 &info->wq_detcable, 0); in usb_extcon_resume()
287 { .compatible = "linux,extcon-usb-gpio", },
293 { .name = "extcon-usb-gpio", },
302 .name = "extcon-usb-gpio",
312 MODULE_DESCRIPTION("USB GPIO extcon driver");