* @roles: array of supported roles for this controller
* @role: current role
* @is_otg: if the device is otg-capable
- * @otg_task: the thread for handling otg task
- * @otg_wait: the otg event waitqueue head
+ * @work: work for role changing
+ * @wq: workqueue thread
* @qh_pool: allocation pool for queue heads
* @td_pool: allocation pool for transfer descriptors
* @gadget: device side representation for peripheral controller
struct ci_role_driver *roles[CI_ROLE_END];
enum ci_role role;
bool is_otg;
- struct task_struct *otg_task;
- wait_queue_head_t otg_wait;
+ struct work_struct work;
+ struct workqueue_struct *wq;
struct dma_pool *qh_pool;
struct dma_pool *td_pool;
ci->id_event = true;
hw_write_otgsc(ci, OTGSC_IDIS, OTGSC_IDIS);
disable_irq_nosync(ci->irq);
- wake_up(&ci->otg_wait);
+ queue_work(ci->wq, &ci->work);
return IRQ_HANDLED;
}
ci->b_sess_valid_event = true;
hw_write_otgsc(ci, OTGSC_BSVIS, OTGSC_BSVIS);
disable_irq_nosync(ci->irq);
- wake_up(&ci->otg_wait);
+ queue_work(ci->wq, &ci->work);
return IRQ_HANDLED;
}
#include <linux/usb/otg.h>
#include <linux/usb/gadget.h>
#include <linux/usb/chipidea.h>
-#include <linux/kthread.h>
-#include <linux/freezer.h>
#include "ci.h"
#include "bits.h"
ci_role_start(ci, role);
}
}
-
-/* If there is pending otg event */
-static inline bool ci_otg_event_is_pending(struct ci_hdrc *ci)
-{
- return ci->id_event || ci->b_sess_valid_event;
-}
-
/**
- * ci_otg_event - perform otg (vbus/id) event handle
- * @ci: ci_hdrc struct
+ * ci_otg_work - perform otg (vbus/id) event handle
+ * @work: work struct
*/
-static void ci_otg_event(struct ci_hdrc *ci)
+static void ci_otg_work(struct work_struct *work)
{
+ struct ci_hdrc *ci = container_of(work, struct ci_hdrc, work);
+
if (ci->id_event) {
ci->id_event = false;
/* Keep controller active during id switch */
enable_irq(ci->irq);
}
-static int ci_otg_thread(void *ptr)
-{
- struct ci_hdrc *ci = ptr;
-
- set_freezable();
-
- do {
- wait_event_freezable(ci->otg_wait,
- ci_otg_event_is_pending(ci) ||
- kthread_should_stop());
- ci_otg_event(ci);
- } while (!kthread_should_stop());
-
- dev_warn(ci->dev, "ci_otg_thread quits\n");
-
- return 0;
-}
/**
* ci_hdrc_otg_init - initialize otg struct
*/
int ci_hdrc_otg_init(struct ci_hdrc *ci)
{
- init_waitqueue_head(&ci->otg_wait);
- ci->otg_task = kthread_run(ci_otg_thread, ci, "ci otg thread");
- if (IS_ERR(ci->otg_task)) {
- dev_err(ci->dev, "error to create otg thread\n");
- return PTR_ERR(ci->otg_task);
+ INIT_WORK(&ci->work, ci_otg_work);
+ ci->wq = create_singlethread_workqueue("ci_otg");
+ if (!ci->wq) {
+ dev_err(ci->dev, "can't create workqueue\n");
+ return -ENODEV;
}
return 0;
*/
void ci_hdrc_otg_destroy(struct ci_hdrc *ci)
{
- kthread_stop(ci->otg_task);
+ if (ci->wq) {
+ flush_workqueue(ci->wq);
+ destroy_workqueue(ci->wq);
+ }
+
hw_write_otgsc(ci, OTGSC_INT_EN_BITS | OTGSC_INT_STATUS_BITS,
OTGSC_INT_STATUS_BITS);
}