• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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