summaryrefslogtreecommitdiff
path: root/drivers/usb/mtu3/mtu3_dr.c
diff options
context:
space:
mode:
authorChunfeng Yun <chunfeng.yun@mediatek.com>2018-05-23 16:53:20 +0800
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2018-05-24 18:09:37 +0200
commit681e9485241463e1e8d8cfd0a11fb252f49c997f (patch)
tree8c28668617df61b5bf0be60f3773f601a27299c2 /drivers/usb/mtu3/mtu3_dr.c
parent4f9f032c256c3fc8ed23461e71d7acf3363a969f (diff)
usb: mtu3: fix warning of sleep in atomic context in notifier callback
The notifier callbacks of extcon are called in atomic context, but the callbacks will call regulator_enable()/regulator_disable() which may sleep caused by mutex, so use work queue to call the sleep functions. Signed-off-by: Chunfeng Yun <chunfeng.yun@mediatek.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/usb/mtu3/mtu3_dr.c')
-rw-r--r--drivers/usb/mtu3/mtu3_dr.c44
1 files changed, 36 insertions, 8 deletions
diff --git a/drivers/usb/mtu3/mtu3_dr.c b/drivers/usb/mtu3/mtu3_dr.c
index 80083e092948..8c3bbf732bc4 100644
--- a/drivers/usb/mtu3/mtu3_dr.c
+++ b/drivers/usb/mtu3/mtu3_dr.c
@@ -174,16 +174,40 @@ static void ssusb_set_mailbox(struct otg_switch_mtk *otg_sx,
}
}
-static int ssusb_id_notifier(struct notifier_block *nb,
- unsigned long event, void *ptr)
+static void ssusb_id_work(struct work_struct *work)
{
struct otg_switch_mtk *otg_sx =
- container_of(nb, struct otg_switch_mtk, id_nb);
+ container_of(work, struct otg_switch_mtk, id_work);
- if (event)
+ if (otg_sx->id_event)
ssusb_set_mailbox(otg_sx, MTU3_ID_GROUND);
else
ssusb_set_mailbox(otg_sx, MTU3_ID_FLOAT);
+}
+
+static void ssusb_vbus_work(struct work_struct *work)
+{
+ struct otg_switch_mtk *otg_sx =
+ container_of(work, struct otg_switch_mtk, vbus_work);
+
+ if (otg_sx->vbus_event)
+ ssusb_set_mailbox(otg_sx, MTU3_VBUS_VALID);
+ else
+ ssusb_set_mailbox(otg_sx, MTU3_VBUS_OFF);
+}
+
+/*
+ * @ssusb_id_notifier is called in atomic context, but @ssusb_set_mailbox
+ * may sleep, so use work queue here
+ */
+static int ssusb_id_notifier(struct notifier_block *nb,
+ unsigned long event, void *ptr)
+{
+ struct otg_switch_mtk *otg_sx =
+ container_of(nb, struct otg_switch_mtk, id_nb);
+
+ otg_sx->id_event = event;
+ schedule_work(&otg_sx->id_work);
return NOTIFY_DONE;
}
@@ -194,10 +218,8 @@ static int ssusb_vbus_notifier(struct notifier_block *nb,
struct otg_switch_mtk *otg_sx =
container_of(nb, struct otg_switch_mtk, vbus_nb);
- if (event)
- ssusb_set_mailbox(otg_sx, MTU3_VBUS_VALID);
- else
- ssusb_set_mailbox(otg_sx, MTU3_VBUS_OFF);
+ otg_sx->vbus_event = event;
+ schedule_work(&otg_sx->vbus_work);
return NOTIFY_DONE;
}
@@ -398,6 +420,9 @@ int ssusb_otg_switch_init(struct ssusb_mtk *ssusb)
{
struct otg_switch_mtk *otg_sx = &ssusb->otg_switch;
+ INIT_WORK(&otg_sx->id_work, ssusb_id_work);
+ INIT_WORK(&otg_sx->vbus_work, ssusb_vbus_work);
+
if (otg_sx->manual_drd_enabled)
ssusb_debugfs_init(ssusb);
else
@@ -412,4 +437,7 @@ void ssusb_otg_switch_exit(struct ssusb_mtk *ssusb)
if (otg_sx->manual_drd_enabled)
ssusb_debugfs_exit(ssusb);
+
+ cancel_work_sync(&otg_sx->id_work);
+ cancel_work_sync(&otg_sx->vbus_work);
}