static int wakeup_event_thread(void *param) { struct wakeup_ctrl *ctrl = (struct wakeup_ctrl *)param; struct sched_param sch_param = {.sched_priority = 1}; sched_setscheduler(current, SCHED_RR, &sch_param); while (1) { wait_for_completion(&ctrl->event); if (kthread_should_stop()) break; wakeup_event_handler(ctrl); enable_irq(ctrl->wakeup_irq); if ((ctrl->usb_irq > 0) && (ctrl->wakeup_irq != ctrl->usb_irq)) enable_irq(ctrl->usb_irq); } return 0; } static int wakeup_dev_probe(struct platform_device *pdev) { struct fsl_usb2_wakeup_platform_data *pdata; struct wakeup_ctrl *ctrl = NULL; int status; printk(KERN_INFO "IMX usb wakeup probe\n"); if (!pdev || !pdev->dev.platform_data) return -ENODEV; ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL); if (!ctrl) return -ENOMEM; pdata = pdev->dev.platform_data; ctrl->pdata = pdata; init_completion(&ctrl->event); ctrl->wakeup_irq = platform_get_irq(pdev, 0); status = request_irq(ctrl->wakeup_irq, usb_wakeup_handler, IRQF_SHARED, "usb_wakeup", (void *)ctrl); if (status) goto error1; ctrl->usb_irq = platform_get_irq(pdev, 1); ctrl->thread = kthread_run(wakeup_event_thread, (void *)ctrl, "usb_wakeup thread"); status = IS_ERR(ctrl->thread) ? -1 : 0; if (status) goto error2; g_ctrl = ctrl; return 0; error2: free_irq(ctrl->wakeup_irq, (void *)ctrl); error1: kfree(ctrl); return status; } static int wakeup_dev_exit(struct platform_device *pdev) { if (g_ctrl->thread) { complete(&g_ctrl->event); kthread_stop(g_ctrl->thread); } free_irq(g_ctrl->wakeup_irq, (void *)g_ctrl); kfree(g_ctrl); return 0; } static struct platform_driver wakeup_d = { .probe = wakeup_dev_probe, .remove = wakeup_dev_exit, .driver = { .name = "usb_wakeup", }, }; static int __init wakeup_dev_init(void) { return platform_driver_register(&wakeup_d); } static void __exit wakeup_dev_uninit(void) { platform_driver_unregister(&wakeup_d); }
static int wakeup_event_thread(void *param) { struct wakeup_ctrl *ctrl = (struct wakeup_ctrl *)param; struct sched_param sch_param = {.sched_priority = 1}; sched_setscheduler(current, SCHED_RR, &sch_param); while (1) { wait_for_completion_interruptible(&ctrl->event); if (kthread_should_stop()) break; wakeup_event_handler(ctrl); enable_irq(ctrl->wakeup_irq); if ((ctrl->usb_irq > 0) && (ctrl->wakeup_irq != ctrl->usb_irq)) enable_irq(ctrl->usb_irq); } return 0; } static int wakeup_dev_probe(struct platform_device *pdev) { struct fsl_usb2_wakeup_platform_data *pdata; struct wakeup_ctrl *ctrl = NULL; int status; unsigned long interrupt_flag; printk(KERN_INFO "IMX usb wakeup probe\n"); if (!pdev || !pdev->dev.platform_data) return -ENODEV; ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL); if (!ctrl) return -ENOMEM; pdata = pdev->dev.platform_data; ctrl->pdata = pdata; init_waitqueue_head(&pdata->wq); pdata->usb_wakeup_is_pending = false; init_completion(&ctrl->event); /* Currently, both mx5x and mx6q uses usb controller's irq * as wakeup irq. */ ctrl->wakeup_irq = platform_get_irq(pdev, 1); ctrl->usb_irq = platform_get_irq(pdev, 1); if (ctrl->wakeup_irq != ctrl->usb_irq) interrupt_flag = IRQF_DISABLED; else interrupt_flag = IRQF_SHARED; status = request_irq(ctrl->wakeup_irq, usb_wakeup_handler, interrupt_flag, "usb_wakeup", (void *)ctrl); if (status) goto error1; ctrl->thread = kthread_run(wakeup_event_thread, (void *)ctrl, "usb_wakeup thread"); status = IS_ERR(ctrl->thread) ? -1 : 0; if (status) goto error2; g_ctrl = ctrl; printk(KERN_DEBUG "the wakeup pdata is 0x%p\n", pdata); return 0; error2: free_irq(ctrl->wakeup_irq, (void *)ctrl); error1: kfree(ctrl); return status; } static int wakeup_dev_exit(struct platform_device *pdev) { if (g_ctrl->thread) { complete(&g_ctrl->event); kthread_stop(g_ctrl->thread); } free_irq(g_ctrl->wakeup_irq, (void *)g_ctrl); kfree(g_ctrl); return 0; } static struct platform_driver wakeup_d = { .probe = wakeup_dev_probe, .remove = wakeup_dev_exit, .driver = { .name = "usb-wakeup", }, }; static int __init wakeup_dev_init(void) { return platform_driver_register(&wakeup_d); } static void __exit wakeup_dev_uninit(void) { platform_driver_unregister(&wakeup_d); }