Lines Matching +full:usb +full:- +full:vbus

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>
44 * "USB" = VBUS and "USB-HOST" = !ID, so we have:
45 * Both "USB" and "USB-HOST" can't be set as active at the
46 * same time so if "USB-HOST" is active (i.e. ID is 0) we keep "USB" inactive
47 * even if VBUS is on.
49 * State | ID | VBUS
50 * ----------------------------------------
51 * [1] USB | H | H
53 * [3] USB-HOST | L | H
54 * [4] USB-HOST | L | L
57 * - VBUS only - we want to distinguish between [1] and [2], so ID is always 1.
58 * - ID only - we want to distinguish between [1] and [4], so VBUS = ID.
62 int id, vbus; in usb_extcon_detect_cable() local
67 /* check ID and VBUS and update cable state */ in usb_extcon_detect_cable()
68 id = info->id_gpiod ? in usb_extcon_detect_cable()
69 gpiod_get_value_cansleep(info->id_gpiod) : 1; in usb_extcon_detect_cable()
70 vbus = info->vbus_gpiod ? in usb_extcon_detect_cable()
71 gpiod_get_value_cansleep(info->vbus_gpiod) : id; in usb_extcon_detect_cable()
75 extcon_set_state_sync(info->edev, EXTCON_USB_HOST, false); in usb_extcon_detect_cable()
76 if (!vbus) in usb_extcon_detect_cable()
77 extcon_set_state_sync(info->edev, EXTCON_USB, false); in usb_extcon_detect_cable()
80 extcon_set_state_sync(info->edev, EXTCON_USB_HOST, true); in usb_extcon_detect_cable()
82 if (vbus) in usb_extcon_detect_cable()
83 extcon_set_state_sync(info->edev, EXTCON_USB, true); in usb_extcon_detect_cable()
91 queue_delayed_work(system_power_efficient_wq, &info->wq_detcable, in usb_irq_handler()
92 info->debounce_jiffies); in usb_irq_handler()
99 struct device *dev = &pdev->dev; in usb_extcon_probe()
100 struct device_node *np = dev->of_node; in usb_extcon_probe()
105 return -EINVAL; in usb_extcon_probe()
107 info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); in usb_extcon_probe()
109 return -ENOMEM; in usb_extcon_probe()
111 info->dev = dev; in usb_extcon_probe()
112 info->id_gpiod = devm_gpiod_get_optional(&pdev->dev, "id", GPIOD_IN); in usb_extcon_probe()
113 info->vbus_gpiod = devm_gpiod_get_optional(&pdev->dev, "vbus", in usb_extcon_probe()
116 if (!info->id_gpiod && !info->vbus_gpiod) { in usb_extcon_probe()
118 return -ENODEV; in usb_extcon_probe()
121 if (IS_ERR(info->id_gpiod)) in usb_extcon_probe()
122 return PTR_ERR(info->id_gpiod); in usb_extcon_probe()
124 if (IS_ERR(info->vbus_gpiod)) in usb_extcon_probe()
125 return PTR_ERR(info->vbus_gpiod); in usb_extcon_probe()
127 info->edev = devm_extcon_dev_allocate(dev, usb_extcon_cable); in usb_extcon_probe()
128 if (IS_ERR(info->edev)) { in usb_extcon_probe()
130 return -ENOMEM; in usb_extcon_probe()
133 ret = devm_extcon_dev_register(dev, info->edev); in usb_extcon_probe()
139 if (info->id_gpiod) in usb_extcon_probe()
140 ret = gpiod_set_debounce(info->id_gpiod, in usb_extcon_probe()
142 if (!ret && info->vbus_gpiod) in usb_extcon_probe()
143 ret = gpiod_set_debounce(info->vbus_gpiod, in usb_extcon_probe()
147 info->debounce_jiffies = msecs_to_jiffies(USB_GPIO_DEBOUNCE_MS); in usb_extcon_probe()
149 INIT_DELAYED_WORK(&info->wq_detcable, usb_extcon_detect_cable); in usb_extcon_probe()
151 if (info->id_gpiod) { in usb_extcon_probe()
152 info->id_irq = gpiod_to_irq(info->id_gpiod); in usb_extcon_probe()
153 if (info->id_irq < 0) { in usb_extcon_probe()
155 return info->id_irq; in usb_extcon_probe()
158 ret = devm_request_threaded_irq(dev, info->id_irq, NULL, in usb_extcon_probe()
162 pdev->name, info); in usb_extcon_probe()
169 if (info->vbus_gpiod) { in usb_extcon_probe()
170 info->vbus_irq = gpiod_to_irq(info->vbus_gpiod); in usb_extcon_probe()
171 if (info->vbus_irq < 0) { in usb_extcon_probe()
172 dev_err(dev, "failed to get VBUS IRQ\n"); in usb_extcon_probe()
173 return info->vbus_irq; in usb_extcon_probe()
176 ret = devm_request_threaded_irq(dev, info->vbus_irq, NULL, in usb_extcon_probe()
180 pdev->name, info); in usb_extcon_probe()
182 dev_err(dev, "failed to request handler for VBUS IRQ\n"); in usb_extcon_probe()
188 device_set_wakeup_capable(&pdev->dev, true); in usb_extcon_probe()
191 usb_extcon_detect_cable(&info->wq_detcable.work); in usb_extcon_probe()
200 cancel_delayed_work_sync(&info->wq_detcable); in usb_extcon_remove()
201 device_init_wakeup(&pdev->dev, false); in usb_extcon_remove()
211 if (info->id_gpiod) { in usb_extcon_suspend()
212 ret = enable_irq_wake(info->id_irq); in usb_extcon_suspend()
216 if (info->vbus_gpiod) { in usb_extcon_suspend()
217 ret = enable_irq_wake(info->vbus_irq); in usb_extcon_suspend()
219 if (info->id_gpiod) in usb_extcon_suspend()
220 disable_irq_wake(info->id_irq); in usb_extcon_suspend()
242 if (info->id_gpiod) { in usb_extcon_resume()
243 ret = disable_irq_wake(info->id_irq); in usb_extcon_resume()
247 if (info->vbus_gpiod) { in usb_extcon_resume()
248 ret = disable_irq_wake(info->vbus_irq); in usb_extcon_resume()
250 if (info->id_gpiod) in usb_extcon_resume()
251 enable_irq_wake(info->id_irq); in usb_extcon_resume()
259 &info->wq_detcable, 0); in usb_extcon_resume()
269 { .compatible = "linux,extcon-usb-gpio", },
275 { .name = "extcon-usb-gpio", },
284 .name = "extcon-usb-gpio",
294 MODULE_DESCRIPTION("USB GPIO extcon driver");