1 /*
2 * drivers/usb/sunxi_usb/manager/usb_manager.c
3 * (C) Copyright 2010-2015
4 * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
5 * javen, 2011-4-14, create this file
6 *
7 * usb manager.
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as
11 * published by the Free Software Foundation; either version 2 of
12 * the License, or (at your option) any later version.
13 *
14 */
15
16 #include <linux/module.h>
17 #include <linux/kernel.h>
18 #include <linux/delay.h>
19 #include <linux/ioport.h>
20 #include <linux/sched.h>
21 #include <linux/slab.h>
22 #include <linux/errno.h>
23 #include <linux/init.h>
24 #include <linux/timer.h>
25 #include <linux/list.h>
26 #include <linux/interrupt.h>
27 #include <linux/platform_device.h>
28 #include <linux/clk.h>
29 #include <linux/kthread.h>
30
31 #include <linux/debugfs.h>
32 #include <linux/seq_file.h>
33 #include <linux/of_gpio.h>
34
35 #include "../include/sunxi_usb_config.h"
36 #include "usb_manager.h"
37 #include "usbc_platform.h"
38 #include "usb_hw_scan.h"
39 #include "usb_msg_center.h"
40
41 struct usb_cfg g_usb_cfg;
42 int thread_id_irq_run_flag;
43 int thread_device_run_flag;
44 int thread_host_run_flag;
45
46 __u32 thread_run_flag = 1;
47 int thread_stopped_flag = 1;
48 atomic_t thread_suspend_flag;
49
50 #if defined(CONFIG_TYPEC)
sunxi_dr_set(struct typec_port * p,enum typec_data_role data)51 static int sunxi_dr_set(struct typec_port *p, enum typec_data_role data)
52 {
53 return 0;
54 }
sunxi_pr_set(struct typec_port * p,enum typec_role data)55 static int sunxi_pr_set(struct typec_port *p, enum typec_role data)
56 {
57 return 0;
58 }
59
60 static const struct typec_operations sunxi_usb_ops = {
61 .dr_set = sunxi_dr_set,
62 .pr_set = sunxi_pr_set,
63 };
64
65 #endif
66
67 #if IS_ENABLED(CONFIG_DUAL_ROLE_USB_INTF)
68 static enum dual_role_property sunxi_usb_dr_properties[] = {
69 DUAL_ROLE_PROP_SUPPORTED_MODES,
70 DUAL_ROLE_PROP_MODE,
71 DUAL_ROLE_PROP_PR,
72 DUAL_ROLE_PROP_DR,
73 };
74
sunxi_dr_get_property(struct dual_role_phy_instance * dual_role,enum dual_role_property prop,unsigned int * val)75 static int sunxi_dr_get_property(struct dual_role_phy_instance *dual_role,
76 enum dual_role_property prop, unsigned int *val)
77 {
78 enum usb_role role = USB_ROLE_NULL;
79 int mode, pr, dr;
80
81 /*
82 * FIXME: e.g
83 * 1.mutex_lock is needed ?
84 * 2.synchronize current status before updated role ?
85 * ...
86 */
87
88 role = get_usb_role();
89
90 if (role == USB_ROLE_HOST) {
91 DMSG_DEBUG("mode is HOST(DFP)\n");
92 mode = DUAL_ROLE_PROP_MODE_DFP;
93 pr = DUAL_ROLE_PROP_PR_SRC;
94 dr = DUAL_ROLE_PROP_DR_HOST;
95 } else if (role == USB_ROLE_DEVICE) {
96 DMSG_DEBUG("mode is DEVICE(UFP)\n");
97 mode = DUAL_ROLE_PROP_MODE_UFP;
98 pr = DUAL_ROLE_PROP_PR_SNK;
99 dr = DUAL_ROLE_PROP_DR_DEVICE;
100 } else {
101 DMSG_DEBUG("mode is NULL(NONE)\n");
102 mode = DUAL_ROLE_PROP_MODE_NONE;
103 pr = DUAL_ROLE_PROP_PR_NONE;
104 dr = DUAL_ROLE_PROP_DR_NONE;
105 }
106
107 switch (prop) {
108 case DUAL_ROLE_PROP_MODE:
109 *val = mode;
110 break;
111 case DUAL_ROLE_PROP_PR:
112 *val = pr;
113 break;
114 case DUAL_ROLE_PROP_DR:
115 *val = dr;
116 break;
117 default:
118 DMSG_PANIC("unsupported property %d\n", prop);
119 return -EINVAL;
120 }
121
122 return 0;
123 }
124 #endif
125
usb_device_scan_thread(void * pArg)126 static int usb_device_scan_thread(void *pArg)
127 {
128
129 while (thread_device_run_flag) {
130
131 msleep(1000); /* 1s */
132 hw_rmmod_usb_host();
133 hw_rmmod_usb_device();
134 usb_msg_center(&g_usb_cfg);
135
136 hw_insmod_usb_device();
137 usb_msg_center(&g_usb_cfg);
138 thread_device_run_flag = 0;
139 DMSG_INFO("device_chose finished %d!\n", __LINE__);
140 }
141
142 return 0;
143 }
144
usb_host_scan_thread(void * pArg)145 static int usb_host_scan_thread(void *pArg)
146 {
147
148 while (thread_host_run_flag) {
149
150 msleep(1000); /* 1s */
151 hw_rmmod_usb_host();
152 hw_rmmod_usb_device();
153 usb_msg_center(&g_usb_cfg);
154
155 hw_insmod_usb_host();
156 usb_msg_center(&g_usb_cfg);
157 thread_host_run_flag = 0;
158 DMSG_INFO("host_chose finished %d!\n", __LINE__);
159 }
160
161 return 0;
162 }
163
usb_hardware_scan_thread(void * pArg)164 static int usb_hardware_scan_thread(void *pArg)
165 {
166 struct usb_cfg *cfg = pArg;
167
168 while (thread_run_flag) {
169 msleep(1000); /* 1s */
170
171 if (atomic_read(&thread_suspend_flag))
172 continue;
173 usb_hw_scan(cfg);
174 usb_msg_center(cfg);
175 }
176
177 thread_stopped_flag = 1;
178 return 0;
179 }
180
usb_id_irq(int irq,void * parg)181 static irqreturn_t usb_id_irq(int irq, void *parg)
182 {
183 struct usb_cfg *cfg = parg;
184
185 mdelay(1000);
186
187 /**
188 * rmmod usb device/host driver first,
189 * then insmod usb host/device driver.
190 */
191 usb_hw_scan(cfg);
192 usb_msg_center(cfg);
193
194 usb_hw_scan(cfg);
195 usb_msg_center(cfg);
196
197 return IRQ_HANDLED;
198 }
199
usb_id_irq_thread(void * parg)200 static int usb_id_irq_thread(void *parg)
201 {
202 struct usb_cfg *cfg = parg;
203 int id_irq_num = 0;
204 unsigned long irq_flags = 0;
205 int ret = 0;
206
207 /* delay for udc & hcd ready */
208 msleep(3000);
209
210 while (thread_id_irq_run_flag) {
211 msleep(1000);
212 hw_rmmod_usb_host();
213 hw_rmmod_usb_device();
214 usb_msg_center(cfg);
215
216 hw_insmod_usb_device();
217 usb_msg_center(cfg);
218
219 if (cfg->port.id.valid) {
220 id_irq_num = gpio_to_irq(cfg->port.id.gpio_set.gpio);
221 if (IS_ERR_VALUE((unsigned long)id_irq_num)) {
222 DMSG_PANIC("ERR: map usb id gpio to virq failed, err %d\n",
223 id_irq_num);
224 return -EINVAL;
225 }
226
227 irq_flags = IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING |
228 IRQF_ONESHOT;
229 ret = request_threaded_irq(id_irq_num, NULL, usb_id_irq,
230 irq_flags, "usb_id", cfg);
231 if (IS_ERR_VALUE((unsigned long)ret)) {
232 DMSG_PANIC("ERR: request usb id virq %d failed, err %d\n",
233 id_irq_num, ret);
234 return -EINVAL;
235 }
236 cfg->port.id_irq_num = id_irq_num;
237 }
238
239 thread_id_irq_run_flag = 0;
240 }
241
242 return 0;
243 }
244
usb_script_parse(struct device_node * np,struct usb_cfg * cfg)245 static __s32 usb_script_parse(struct device_node *np, struct usb_cfg *cfg)
246 {
247 struct device_node *usbc_np = NULL;
248 int ret = -1;
249 const char *used_status;
250
251 usbc_np = of_find_node_by_type(NULL, SET_USB0);
252
253 /* usbc enable */
254 ret = of_property_read_string(usbc_np, "status", &used_status);
255 if (ret) {
256 DMSG_INFO("get usb_used is fail, %d\n", ret);
257 cfg->port.enable = 0;
258 } else if (!strcmp(used_status, "okay")) {
259 cfg->port.enable = 1;
260 } else {
261 cfg->port.enable = 0;
262 }
263
264 /* usbc port type */
265 ret = of_property_read_u32(usbc_np,
266 KEY_USB_PORT_TYPE,
267 &cfg->port.port_type);
268 if (ret)
269 DMSG_INFO("get usb_port_type is fail, %d\n", ret);
270
271 /* usbc det mode */
272 ret = of_property_read_u32(usbc_np,
273 KEY_USB_DET_MODE,
274 &cfg->port.detect_mode);
275 if (ret)
276 DMSG_INFO("get usb_detect_mode is fail, %d\n", ret);
277
278 /* usbc det_vbus */
279 ret = of_property_read_string(usbc_np,
280 KEY_USB_DETVBUS_GPIO,
281 &cfg->port.det_vbus_name);
282 if (ret) {
283 DMSG_INFO("get det_vbus is fail, %d\n", ret);
284 cfg->port.det_vbus.valid = 0;
285 } else {
286 if (strncmp(cfg->port.det_vbus_name, "axp_ctrl", 8) == 0) {
287 cfg->port.det_vbus_type = USB_DET_VBUS_TYPE_AXP;
288 cfg->port.det_vbus.valid = 0;
289 } else {
290 /*get det vbus gpio */
291 cfg->port.det_vbus.gpio_set.gpio = of_get_named_gpio(usbc_np, KEY_USB_DETVBUS_GPIO, 0);
292 if (gpio_is_valid(cfg->port.det_vbus.gpio_set.gpio)) {
293 cfg->port.det_vbus.valid = 1;
294 cfg->port.det_vbus_type = USB_DET_VBUS_TYPE_GPIO;
295 } else {
296 cfg->port.det_vbus.valid = 0;
297 }
298 }
299 }
300
301 /* usbc id */
302 ret = of_property_read_string(usbc_np,
303 KEY_USB_ID_GPIO,
304 &cfg->port.id_name);
305 if (ret) {
306 DMSG_INFO("get id is fail, %d\n", ret);
307 cfg->port.id.valid = 0;
308 } else {
309 if (strncmp(cfg->port.id_name, "axp_ctrl", 8) == 0) {
310 cfg->port.id_type = USB_ID_TYPE_AXP;
311 cfg->port.id.valid = 0;
312 } else {
313 /*get id gpio */
314 cfg->port.id.gpio_set.gpio = of_get_named_gpio(usbc_np, KEY_USB_ID_GPIO, 0);
315 if (gpio_is_valid(cfg->port.id.gpio_set.gpio)) {
316 cfg->port.id.valid = 1;
317 cfg->port.id_type = USB_ID_TYPE_GPIO;
318 } else {
319 cfg->port.id.valid = 0;
320 }
321 }
322 }
323
324 return 0;
325 }
326
sunxi_otg_manager_probe(struct platform_device * pdev)327 static int sunxi_otg_manager_probe(struct platform_device *pdev)
328 {
329 struct device_node *np = pdev->dev.of_node;
330 struct task_struct *device_th = NULL;
331 struct task_struct *host_th = NULL;
332 struct task_struct *th = NULL;
333 struct task_struct *id_irq_th = NULL;
334 int ret = -1;
335
336 memset(&g_usb_cfg, 0, sizeof(struct usb_cfg));
337 g_usb_cfg.usb_global_enable = 1;
338 g_usb_cfg.pdev = pdev;
339 usb_msg_center_init();
340
341 ret = usb_script_parse(np, &g_usb_cfg);
342 if (ret != 0) {
343 DMSG_PANIC("ERR: get_usb_cfg failed\n");
344 return -1;
345 }
346
347 if (g_usb_cfg.port.enable == 0) {
348 DMSG_PANIC("wrn: usb0 is disable\n");
349 return 0;
350 }
351
352 create_node_file(pdev);
353
354 if (g_usb_cfg.port.port_type == USB_PORT_TYPE_DEVICE) {
355 thread_device_run_flag = 1;
356 device_th = kthread_create(usb_device_scan_thread,
357 NULL,
358 "usb_device_chose");
359 if (IS_ERR(device_th)) {
360 DMSG_PANIC("ERR: device kthread_create failed\n");
361 return -1;
362 }
363
364 wake_up_process(device_th);
365 }
366
367 if (g_usb_cfg.port.port_type == USB_PORT_TYPE_HOST) {
368 thread_host_run_flag = 0;
369 host_th = kthread_create(usb_host_scan_thread,
370 NULL,
371 "usb_host_chose");
372 if (IS_ERR(host_th)) {
373 DMSG_PANIC("ERR: host kthread_create failed\n");
374 return -1;
375 }
376
377 wake_up_process(host_th);
378 }
379
380 if (g_usb_cfg.port.port_type == USB_PORT_TYPE_OTG) {
381 usb_hw_scan_init(&g_usb_cfg);
382
383 if (g_usb_cfg.port.detect_mode == USB_DETECT_MODE_THREAD) {
384 atomic_set(&thread_suspend_flag, 0);
385 thread_run_flag = 1;
386 thread_stopped_flag = 0;
387
388 th = kthread_create(usb_hardware_scan_thread,
389 &g_usb_cfg,
390 "usb-hardware-scan");
391 if (IS_ERR(th)) {
392 DMSG_PANIC("ERR: kthread_create failed\n");
393 return -1;
394 }
395
396 wake_up_process(th);
397 } else if (g_usb_cfg.port.detect_mode == USB_DETECT_MODE_INTR) {
398 thread_id_irq_run_flag = 1;
399 id_irq_th = kthread_create(usb_id_irq_thread,
400 &g_usb_cfg,
401 "usb_id_irq");
402 if (IS_ERR(id_irq_th)) {
403 DMSG_PANIC("ERR: id_irq kthread_create failed\n");
404 return -1;
405 }
406
407 wake_up_process(id_irq_th);
408 } else {
409 DMSG_PANIC("ERR: usb detect mode isn't supported\n");
410 return -1;
411 }
412
413 #if IS_ENABLED(CONFIG_DUAL_ROLE_USB_INTF)
414 g_usb_cfg.port.dr_desc.name = "dr_usbc0";
415 g_usb_cfg.port.dr_desc.supported_modes = DUAL_ROLE_SUPPORTED_MODES_DFP_AND_UFP;
416 g_usb_cfg.port.dr_desc.properties = sunxi_usb_dr_properties;
417 g_usb_cfg.port.dr_desc.num_properties = ARRAY_SIZE(sunxi_usb_dr_properties);
418 g_usb_cfg.port.dr_desc.get_property = sunxi_dr_get_property;
419 g_usb_cfg.port.dr_desc.set_property = NULL;
420 g_usb_cfg.port.dr_desc.property_is_writeable = NULL;
421
422 g_usb_cfg.port.dual_role = devm_dual_role_instance_register(&pdev->dev, &g_usb_cfg.port.dr_desc);
423 if (IS_ERR(g_usb_cfg.port.dual_role))
424 DMSG_PANIC("ERR: failed to register dual_role_class device\n");
425 #endif
426
427 #if defined(CONFIG_TYPEC)
428 g_usb_cfg.port.typec_caps.type = TYPEC_PORT_SNK;
429 g_usb_cfg.port.typec_caps.ops = &sunxi_usb_ops;
430 g_usb_cfg.port.typec_port = typec_register_port(&pdev->dev, &g_usb_cfg.port.typec_caps);
431 #endif
432 }
433
434 return 0;
435 }
436
sunxi_otg_manager_remove(struct platform_device * pdev)437 static int sunxi_otg_manager_remove(struct platform_device *pdev)
438 {
439
440 #if IS_ENABLED(CONFIG_DUAL_ROLE_USB_INTF)
441 struct dual_role_phy_instance *dual_role = g_usb_cfg.port.dual_role;
442 #endif
443
444 if (g_usb_cfg.port.enable == 0) {
445 DMSG_PANIC("wrn: usb0 is disable\n");
446 return 0;
447 }
448
449 if (g_usb_cfg.port.port_type == USB_PORT_TYPE_OTG) {
450 #if IS_ENABLED(CONFIG_DUAL_ROLE_USB_INTF)
451 devm_dual_role_instance_unregister(&pdev->dev, dual_role);
452 dual_role = NULL;
453 #endif
454
455 thread_run_flag = 0;
456 while (!thread_stopped_flag) {
457 DMSG_INFO("waitting for usb_hardware_scan_thread stop\n");
458 msleep(20);
459 }
460 if (g_usb_cfg.port.detect_mode == USB_DETECT_MODE_INTR)
461 if (g_usb_cfg.port.id.valid
462 && g_usb_cfg.port.id_irq_num)
463 free_irq(g_usb_cfg.port.id_irq_num, &g_usb_cfg);
464 usb_hw_scan_exit(&g_usb_cfg);
465 }
466
467 remove_node_file(pdev);
468
469 /* Remove host and device driver before manager exit. */
470 hw_rmmod_usb_host();
471 hw_rmmod_usb_device();
472 usb_msg_center(&g_usb_cfg);
473
474 return 0;
475 }
476
477 #if IS_ENABLED(CONFIG_PM)
sunxi_otg_manager_suspend(struct device * dev)478 static int sunxi_otg_manager_suspend(struct device *dev)
479 {
480 device_insmod_delay = 0;
481 atomic_set(&thread_suspend_flag, 1);
482 return 0;
483 }
484
sunxi_otg_manager_resume(struct device * dev)485 static int sunxi_otg_manager_resume(struct device *dev)
486 {
487 device_insmod_delay = 0;
488 atomic_set(&thread_suspend_flag, 0);
489 return 0;
490 }
491
492 static const struct dev_pm_ops sunxi_otg_manager_pm_ops = {
493 .suspend = sunxi_otg_manager_suspend,
494 .resume = sunxi_otg_manager_resume,
495 };
496 #define OTG_MANAGER_PM_OPS (&sunxi_otg_manager_pm_ops)
497
498 #else /* !CONFIG_PM_SLEEP */
499
500 #define OTG_MANAGER_PM_OPS NULL
501 #endif /* CONFIG_PM_SLEEP */
502
503 static const struct of_device_id sunxi_otg_manager_match[] = {
504 {.compatible = "allwinner,sunxi-otg-manager", },
505 {},
506 };
507 MODULE_DEVICE_TABLE(of, sunxi_otg_manager_match);
508
509 static struct platform_driver sunxi_otg_manager_platform_driver = {
510 .probe = sunxi_otg_manager_probe,
511 .remove = sunxi_otg_manager_remove,
512 .driver = {
513 .name = "otg manager",
514 .pm = OTG_MANAGER_PM_OPS,
515 .owner = THIS_MODULE,
516 .of_match_table = sunxi_otg_manager_match,
517 },
518 };
519
usb_manager_init(void)520 static int __init usb_manager_init(void)
521 {
522 return platform_driver_register(&sunxi_otg_manager_platform_driver);
523 }
524
usb_manager_exit(void)525 static void __exit usb_manager_exit(void)
526 {
527 return platform_driver_unregister(&sunxi_otg_manager_platform_driver);
528 }
529
530 late_initcall(usb_manager_init);
531 module_exit(usb_manager_exit);
532
533 MODULE_AUTHOR("wangjx<wangjx@allwinnertech.com>");
534 MODULE_DESCRIPTION("Driver for Allwinner usb otg manager");
535 MODULE_ALIAS("platform: usb manager for host and udc");
536 MODULE_LICENSE("GPL v2");
537 MODULE_VERSION("1.0.10");
538