1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * USB GPIO Based Connection Detection Driver
4 *
5 * Copyright (C) 2019 MediaTek Inc.
6 *
7 * Author: Chunfeng Yun <chunfeng.yun@mediatek.com>
8 *
9 * Some code borrowed from drivers/extcon/extcon-usb-gpio.c
10 */
11
12 #include <linux/device.h>
13 #include <linux/gpio/consumer.h>
14 #include <linux/interrupt.h>
15 #include <linux/irq.h>
16 #include <linux/module.h>
17 #include <linux/of.h>
18 #include <linux/pinctrl/consumer.h>
19 #include <linux/platform_device.h>
20 #include <linux/power_supply.h>
21 #include <linux/regulator/consumer.h>
22 #include <linux/string_choices.h>
23 #include <linux/usb/role.h>
24 #include <linux/idr.h>
25
26 static DEFINE_IDA(usb_conn_ida);
27
28 #define USB_GPIO_DEB_MS 20 /* ms */
29 #define USB_GPIO_DEB_US ((USB_GPIO_DEB_MS) * 1000) /* us */
30
31 #define USB_CONN_IRQF \
32 (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT)
33
34 struct usb_conn_info {
35 struct device *dev;
36 int conn_id; /* store the IDA-allocated ID */
37 struct usb_role_switch *role_sw;
38 enum usb_role last_role;
39 struct regulator *vbus;
40 struct delayed_work dw_det;
41 unsigned long debounce_jiffies;
42
43 struct gpio_desc *id_gpiod;
44 struct gpio_desc *vbus_gpiod;
45 int id_irq;
46 int vbus_irq;
47
48 struct power_supply_desc desc;
49 struct power_supply *charger;
50 bool initial_detection;
51 };
52
53 /*
54 * "DEVICE" = VBUS and "HOST" = !ID, so we have:
55 * Both "DEVICE" and "HOST" can't be set as active at the same time
56 * so if "HOST" is active (i.e. ID is 0) we keep "DEVICE" inactive
57 * even if VBUS is on.
58 *
59 * Role | ID | VBUS
60 * ------------------------------------
61 * [1] DEVICE | H | H
62 * [2] NONE | H | L
63 * [3] HOST | L | H
64 * [4] HOST | L | L
65 *
66 * In case we have only one of these signals:
67 * - VBUS only - we want to distinguish between [1] and [2], so ID is always 1
68 * - ID only - we want to distinguish between [1] and [4], so VBUS = ID
69 */
usb_conn_detect_cable(struct work_struct * work)70 static void usb_conn_detect_cable(struct work_struct *work)
71 {
72 struct usb_conn_info *info;
73 enum usb_role role;
74 int id, vbus, ret;
75
76 info = container_of(to_delayed_work(work),
77 struct usb_conn_info, dw_det);
78
79 /* check ID and VBUS */
80 id = info->id_gpiod ?
81 gpiod_get_value_cansleep(info->id_gpiod) : 1;
82 vbus = info->vbus_gpiod ?
83 gpiod_get_value_cansleep(info->vbus_gpiod) : id;
84
85 if (!id)
86 role = USB_ROLE_HOST;
87 else if (vbus)
88 role = USB_ROLE_DEVICE;
89 else
90 role = USB_ROLE_NONE;
91
92 dev_dbg(info->dev, "role %s -> %s, gpios: id %d, vbus %d\n",
93 usb_role_string(info->last_role), usb_role_string(role), id, vbus);
94
95 if (!info->initial_detection && info->last_role == role) {
96 dev_warn(info->dev, "repeated role: %s\n", usb_role_string(role));
97 return;
98 }
99
100 info->initial_detection = false;
101
102 if (info->last_role == USB_ROLE_HOST && info->vbus)
103 regulator_disable(info->vbus);
104
105 ret = usb_role_switch_set_role(info->role_sw, role);
106 if (ret)
107 dev_err(info->dev, "failed to set role: %d\n", ret);
108
109 if (role == USB_ROLE_HOST && info->vbus) {
110 ret = regulator_enable(info->vbus);
111 if (ret)
112 dev_err(info->dev, "enable vbus regulator failed\n");
113 }
114
115 info->last_role = role;
116
117 if (info->vbus)
118 dev_dbg(info->dev, "vbus regulator is %s\n",
119 str_enabled_disabled(regulator_is_enabled(info->vbus)));
120
121 power_supply_changed(info->charger);
122 }
123
usb_conn_queue_dwork(struct usb_conn_info * info,unsigned long delay)124 static void usb_conn_queue_dwork(struct usb_conn_info *info,
125 unsigned long delay)
126 {
127 queue_delayed_work(system_power_efficient_wq, &info->dw_det, delay);
128 }
129
usb_conn_isr(int irq,void * dev_id)130 static irqreturn_t usb_conn_isr(int irq, void *dev_id)
131 {
132 struct usb_conn_info *info = dev_id;
133
134 usb_conn_queue_dwork(info, info->debounce_jiffies);
135
136 return IRQ_HANDLED;
137 }
138
139 static enum power_supply_property usb_charger_properties[] = {
140 POWER_SUPPLY_PROP_ONLINE,
141 };
142
usb_charger_get_property(struct power_supply * psy,enum power_supply_property psp,union power_supply_propval * val)143 static int usb_charger_get_property(struct power_supply *psy,
144 enum power_supply_property psp,
145 union power_supply_propval *val)
146 {
147 struct usb_conn_info *info = power_supply_get_drvdata(psy);
148
149 switch (psp) {
150 case POWER_SUPPLY_PROP_ONLINE:
151 val->intval = info->last_role == USB_ROLE_DEVICE;
152 break;
153 default:
154 return -EINVAL;
155 }
156
157 return 0;
158 }
159
usb_conn_psy_register(struct usb_conn_info * info)160 static int usb_conn_psy_register(struct usb_conn_info *info)
161 {
162 struct device *dev = info->dev;
163 struct power_supply_desc *desc = &info->desc;
164 struct power_supply_config cfg = {
165 .fwnode = dev_fwnode(dev),
166 };
167
168 info->conn_id = ida_alloc(&usb_conn_ida, GFP_KERNEL);
169 if (info->conn_id < 0)
170 return info->conn_id;
171
172 desc->name = devm_kasprintf(dev, GFP_KERNEL, "usb-charger-%d",
173 info->conn_id);
174 if (!desc->name) {
175 ida_free(&usb_conn_ida, info->conn_id);
176 return -ENOMEM;
177 }
178
179 desc->properties = usb_charger_properties;
180 desc->num_properties = ARRAY_SIZE(usb_charger_properties);
181 desc->get_property = usb_charger_get_property;
182 desc->type = POWER_SUPPLY_TYPE_USB;
183 cfg.drv_data = info;
184
185 info->charger = devm_power_supply_register(dev, desc, &cfg);
186 if (IS_ERR(info->charger)) {
187 dev_err(dev, "Unable to register charger %d\n", info->conn_id);
188 ida_free(&usb_conn_ida, info->conn_id);
189 }
190
191 return PTR_ERR_OR_ZERO(info->charger);
192 }
193
usb_conn_probe(struct platform_device * pdev)194 static int usb_conn_probe(struct platform_device *pdev)
195 {
196 struct device *dev = &pdev->dev;
197 struct usb_conn_info *info;
198 int ret = 0;
199
200 info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL);
201 if (!info)
202 return -ENOMEM;
203
204 info->dev = dev;
205 info->id_gpiod = devm_gpiod_get_optional(dev, "id", GPIOD_IN);
206 if (IS_ERR(info->id_gpiod))
207 return PTR_ERR(info->id_gpiod);
208
209 info->vbus_gpiod = devm_gpiod_get_optional(dev, "vbus", GPIOD_IN);
210 if (IS_ERR(info->vbus_gpiod))
211 return PTR_ERR(info->vbus_gpiod);
212
213 if (!info->id_gpiod && !info->vbus_gpiod) {
214 dev_err(dev, "failed to get gpios\n");
215 return -ENODEV;
216 }
217
218 if (info->id_gpiod)
219 ret = gpiod_set_debounce(info->id_gpiod, USB_GPIO_DEB_US);
220 if (!ret && info->vbus_gpiod)
221 ret = gpiod_set_debounce(info->vbus_gpiod, USB_GPIO_DEB_US);
222 if (ret < 0)
223 info->debounce_jiffies = msecs_to_jiffies(USB_GPIO_DEB_MS);
224
225 INIT_DELAYED_WORK(&info->dw_det, usb_conn_detect_cable);
226
227 info->vbus = devm_regulator_get_optional(dev, "vbus");
228 if (PTR_ERR(info->vbus) == -ENODEV)
229 info->vbus = NULL;
230
231 if (IS_ERR(info->vbus))
232 return dev_err_probe(dev, PTR_ERR(info->vbus), "failed to get vbus\n");
233
234 info->role_sw = usb_role_switch_get(dev);
235 if (IS_ERR(info->role_sw))
236 return dev_err_probe(dev, PTR_ERR(info->role_sw),
237 "failed to get role switch\n");
238
239 ret = usb_conn_psy_register(info);
240 if (ret)
241 goto put_role_sw;
242
243 if (info->id_gpiod) {
244 info->id_irq = gpiod_to_irq(info->id_gpiod);
245 if (info->id_irq < 0) {
246 dev_err(dev, "failed to get ID IRQ\n");
247 ret = info->id_irq;
248 goto put_role_sw;
249 }
250
251 ret = devm_request_threaded_irq(dev, info->id_irq, NULL,
252 usb_conn_isr, USB_CONN_IRQF,
253 pdev->name, info);
254 if (ret < 0) {
255 dev_err(dev, "failed to request ID IRQ\n");
256 goto put_role_sw;
257 }
258 }
259
260 if (info->vbus_gpiod) {
261 info->vbus_irq = gpiod_to_irq(info->vbus_gpiod);
262 if (info->vbus_irq < 0) {
263 dev_err(dev, "failed to get VBUS IRQ\n");
264 ret = info->vbus_irq;
265 goto put_role_sw;
266 }
267
268 ret = devm_request_threaded_irq(dev, info->vbus_irq, NULL,
269 usb_conn_isr, USB_CONN_IRQF,
270 pdev->name, info);
271 if (ret < 0) {
272 dev_err(dev, "failed to request VBUS IRQ\n");
273 goto put_role_sw;
274 }
275 }
276
277 platform_set_drvdata(pdev, info);
278 device_set_wakeup_capable(&pdev->dev, true);
279
280 /* Perform initial detection */
281 info->initial_detection = true;
282 usb_conn_queue_dwork(info, 0);
283
284 return 0;
285
286 put_role_sw:
287 usb_role_switch_put(info->role_sw);
288 return ret;
289 }
290
usb_conn_remove(struct platform_device * pdev)291 static void usb_conn_remove(struct platform_device *pdev)
292 {
293 struct usb_conn_info *info = platform_get_drvdata(pdev);
294
295 cancel_delayed_work_sync(&info->dw_det);
296
297 if (info->charger)
298 ida_free(&usb_conn_ida, info->conn_id);
299
300 if (info->last_role == USB_ROLE_HOST && info->vbus)
301 regulator_disable(info->vbus);
302
303 usb_role_switch_put(info->role_sw);
304 }
305
usb_conn_suspend(struct device * dev)306 static int __maybe_unused usb_conn_suspend(struct device *dev)
307 {
308 struct usb_conn_info *info = dev_get_drvdata(dev);
309
310 if (device_may_wakeup(dev)) {
311 if (info->id_gpiod)
312 enable_irq_wake(info->id_irq);
313 if (info->vbus_gpiod)
314 enable_irq_wake(info->vbus_irq);
315 return 0;
316 }
317
318 if (info->id_gpiod)
319 disable_irq(info->id_irq);
320 if (info->vbus_gpiod)
321 disable_irq(info->vbus_irq);
322
323 pinctrl_pm_select_sleep_state(dev);
324
325 return 0;
326 }
327
usb_conn_resume(struct device * dev)328 static int __maybe_unused usb_conn_resume(struct device *dev)
329 {
330 struct usb_conn_info *info = dev_get_drvdata(dev);
331
332 if (device_may_wakeup(dev)) {
333 if (info->id_gpiod)
334 disable_irq_wake(info->id_irq);
335 if (info->vbus_gpiod)
336 disable_irq_wake(info->vbus_irq);
337 return 0;
338 }
339
340 pinctrl_pm_select_default_state(dev);
341
342 if (info->id_gpiod)
343 enable_irq(info->id_irq);
344 if (info->vbus_gpiod)
345 enable_irq(info->vbus_irq);
346
347 usb_conn_queue_dwork(info, 0);
348
349 return 0;
350 }
351
352 static SIMPLE_DEV_PM_OPS(usb_conn_pm_ops,
353 usb_conn_suspend, usb_conn_resume);
354
355 static const struct of_device_id usb_conn_dt_match[] = {
356 { .compatible = "gpio-usb-b-connector", },
357 { }
358 };
359 MODULE_DEVICE_TABLE(of, usb_conn_dt_match);
360
361 static struct platform_driver usb_conn_driver = {
362 .probe = usb_conn_probe,
363 .remove = usb_conn_remove,
364 .driver = {
365 .name = "usb-conn-gpio",
366 .pm = &usb_conn_pm_ops,
367 .of_match_table = usb_conn_dt_match,
368 },
369 };
370
371 module_platform_driver(usb_conn_driver);
372
373 MODULE_AUTHOR("Chunfeng Yun <chunfeng.yun@mediatek.com>");
374 MODULE_DESCRIPTION("USB GPIO based connection detection driver");
375 MODULE_LICENSE("GPL v2");
376