|
@@ -18,6 +18,7 @@
|
|
|
|
|
|
#include <linux/module.h>
|
|
|
#include <linux/device.h>
|
|
|
+#include <linux/gpio/consumer.h>
|
|
|
#include <linux/platform_device.h>
|
|
|
#include <linux/clk.h>
|
|
|
#include <linux/slab.h>
|
|
@@ -32,6 +33,7 @@
|
|
|
#include <linux/pm_runtime.h>
|
|
|
#include <linux/of.h>
|
|
|
#include <linux/of_device.h>
|
|
|
+#include <linux/reboot.h>
|
|
|
#include <linux/reset.h>
|
|
|
|
|
|
#include <linux/usb.h>
|
|
@@ -1471,6 +1473,14 @@ static int msm_otg_vbus_notifier(struct notifier_block *nb, unsigned long event,
|
|
|
else
|
|
|
clear_bit(B_SESS_VLD, &motg->inputs);
|
|
|
|
|
|
+ if (test_bit(B_SESS_VLD, &motg->inputs)) {
|
|
|
+ /* Switch D+/D- lines to Device connector */
|
|
|
+ gpiod_set_value_cansleep(motg->switch_gpio, 0);
|
|
|
+ } else {
|
|
|
+ /* Switch D+/D- lines to Hub */
|
|
|
+ gpiod_set_value_cansleep(motg->switch_gpio, 1);
|
|
|
+ }
|
|
|
+
|
|
|
schedule_work(&motg->sm_work);
|
|
|
|
|
|
return NOTIFY_DONE;
|
|
@@ -1546,6 +1556,11 @@ static int msm_otg_read_dt(struct platform_device *pdev, struct msm_otg *motg)
|
|
|
|
|
|
motg->manual_pullup = of_property_read_bool(node, "qcom,manual-pullup");
|
|
|
|
|
|
+ motg->switch_gpio = devm_gpiod_get_optional(&pdev->dev, "switch",
|
|
|
+ GPIOD_OUT_LOW);
|
|
|
+ if (IS_ERR(motg->switch_gpio))
|
|
|
+ return PTR_ERR(motg->switch_gpio);
|
|
|
+
|
|
|
ext_id = ERR_PTR(-ENODEV);
|
|
|
ext_vbus = ERR_PTR(-ENODEV);
|
|
|
if (of_property_read_bool(node, "extcon")) {
|
|
@@ -1617,6 +1632,19 @@ static int msm_otg_read_dt(struct platform_device *pdev, struct msm_otg *motg)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static int msm_otg_reboot_notify(struct notifier_block *this,
|
|
|
+ unsigned long code, void *unused)
|
|
|
+{
|
|
|
+ struct msm_otg *motg = container_of(this, struct msm_otg, reboot);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Ensure that D+/D- lines are routed to uB connector, so
|
|
|
+ * we could load bootloader/kernel at next reboot
|
|
|
+ */
|
|
|
+ gpiod_set_value_cansleep(motg->switch_gpio, 0);
|
|
|
+ return NOTIFY_DONE;
|
|
|
+}
|
|
|
+
|
|
|
static int msm_otg_probe(struct platform_device *pdev)
|
|
|
{
|
|
|
struct regulator_bulk_data regs[3];
|
|
@@ -1781,6 +1809,17 @@ static int msm_otg_probe(struct platform_device *pdev)
|
|
|
dev_dbg(&pdev->dev, "Can not create mode change file\n");
|
|
|
}
|
|
|
|
|
|
+ if (test_bit(B_SESS_VLD, &motg->inputs)) {
|
|
|
+ /* Switch D+/D- lines to Device connector */
|
|
|
+ gpiod_set_value_cansleep(motg->switch_gpio, 0);
|
|
|
+ } else {
|
|
|
+ /* Switch D+/D- lines to Hub */
|
|
|
+ gpiod_set_value_cansleep(motg->switch_gpio, 1);
|
|
|
+ }
|
|
|
+
|
|
|
+ motg->reboot.notifier_call = msm_otg_reboot_notify;
|
|
|
+ register_reboot_notifier(&motg->reboot);
|
|
|
+
|
|
|
pm_runtime_set_active(&pdev->dev);
|
|
|
pm_runtime_enable(&pdev->dev);
|
|
|
|
|
@@ -1807,6 +1846,14 @@ static int msm_otg_remove(struct platform_device *pdev)
|
|
|
if (phy->otg->host || phy->otg->gadget)
|
|
|
return -EBUSY;
|
|
|
|
|
|
+ unregister_reboot_notifier(&motg->reboot);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Ensure that D+/D- lines are routed to uB connector, so
|
|
|
+ * we could load bootloader/kernel at next reboot
|
|
|
+ */
|
|
|
+ gpiod_set_value_cansleep(motg->switch_gpio, 0);
|
|
|
+
|
|
|
extcon_unregister_notifier(motg->id.extcon, EXTCON_USB_HOST, &motg->id.nb);
|
|
|
extcon_unregister_notifier(motg->vbus.extcon, EXTCON_USB, &motg->vbus.nb);
|
|
|
|