[RFC PATCH 1/1] usb: musb: omap: support for OFF-mode

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



New support for OFF-mode on OMAP using notifier communicating usb events
In the present case VBUS events are checked.

Signed-off-by: Arnaud Mandy <ext-arnaud.2.mandy@xxxxxxxxx>
---
 drivers/usb/musb/musb_core.c |   34 ++++++++++++++++++++++-
 drivers/usb/musb/musb_core.h |   13 ++++++++-
 drivers/usb/musb/omap2430.c  |   62 +++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 106 insertions(+), 3 deletions(-)

diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c
index a3da667..3245f1e 100644
--- a/drivers/usb/musb/musb_core.c
+++ b/drivers/usb/musb/musb_core.c
@@ -137,6 +137,28 @@ MODULE_ALIAS("platform:" MUSB_DRIVER_NAME);
 
 /*-------------------------------------------------------------------------*/
 
+#ifdef CONFIG_PM
+/* blocking notifier support */
+static int musb_notifier_call(struct notifier_block *nb,
+		unsigned long event, void *unused)
+{
+	struct musb		*musb = container_of(nb, struct musb, nb);
+
+	switch (event) {
+	case USB_EVENT_VBUS:
+			musb_platform_power_on(musb);
+		break;
+	case USB_EVENT_NONE:
+			musb_platform_power_off(musb);
+		break;
+	default:
+		return NOTIFY_DONE;
+	}
+
+	return NOTIFY_OK;
+}
+#endif
+
 static inline struct musb *dev_to_musb(struct device *dev)
 {
 #ifdef CONFIG_USB_MUSB_HDRC_HCD
@@ -956,6 +978,9 @@ static void musb_shutdown(struct platform_device *pdev)
 	struct musb	*musb = dev_to_musb(&pdev->dev);
 	unsigned long	flags;
 
+#ifdef CONFIG_PM
+	otg_unregister_notifier(musb->xceiv, &musb->nb);
+#endif
 	spin_lock_irqsave(&musb->lock, flags);
 	musb_platform_disable(musb);
 	musb_generic_disable(musb);
@@ -1824,6 +1849,9 @@ allocate_instance(struct device *dev,
 	}
 
 	musb->controller = dev;
+#ifdef CONFIG_PM
+	musb->nb.notifier_call = musb_notifier_call;
+#endif
 	return musb;
 }
 
@@ -2089,7 +2117,11 @@ bad_config:
 #endif
 	if (status)
 		goto fail2;
-
+#ifdef CONFIG_PM
+	status = otg_register_notifier(musb->xceiv, &musb->nb);
+	if (status)
+		goto fail2;
+#endif
 	return 0;
 
 fail2:
diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h
index e8e7d1c..60556b2 100644
--- a/drivers/usb/musb/musb_core.h
+++ b/drivers/usb/musb/musb_core.h
@@ -330,7 +330,9 @@ struct musb {
 #define MUSB_HWVERS_1800	0x720
 #define MUSB_HWVERS_2000	0x800
 	u16			hwvers;
-
+#ifdef CONFIG_PM
+	struct notifier_block	nb;
+#endif
 /* this hub status bit is reserved by USB 2.0 and not seen by usbcore */
 #define MUSB_PORT_STAT_RESUME	(1 << 31)
 
@@ -406,6 +408,9 @@ struct musb {
 	/* active means connected and not suspended */
 	unsigned		is_active:1;
 
+	/* off mode is  supported */
+	unsigned		off_mode:1;
+
 	unsigned is_multipoint:1;
 	unsigned ignore_disconnect:1;	/* during bus resets */
 
@@ -486,9 +491,15 @@ extern void musb_platform_save_context(struct musb *musb,
 		struct musb_context_registers *musb_context);
 extern void musb_platform_restore_context(struct musb *musb,
 		struct musb_context_registers *musb_context);
+extern void musb_save_context(struct musb *musb);
+extern void musb_restore_context(struct musb *musb);
+extern void musb_platform_power_on(struct musb *musb);
+extern void musb_platform_power_off(struct musb *musb);
 #else
 #define musb_platform_save_context(m, x)	do {} while (0)
 #define musb_platform_restore_context(m, x)	do {} while (0)
+#define musb_platform_power_on(x)		do {} while (0)
+#define musb_platform_power_off(x)		do {} while (0)
 #endif
 
 #endif
diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c
index c4cba52..01b7041 100644
--- a/drivers/usb/musb/omap2430.c
+++ b/drivers/usb/musb/omap2430.c
@@ -271,7 +271,67 @@ void musb_platform_restore_context(struct musb *musb,
 	musb_writel(musb->mregs, OTG_SYSCONFIG, musb_context->otg_sysconfig);
 	musb_writel(musb->mregs, OTG_FORCESTDBY, musb_context->otg_forcestandby);
 }
-#endif
+
+void musb_platform_power_off(struct musb *musb)
+{
+	u32 l;
+
+	DBG(3, "allow OFF-mode\n");
+
+	l = musb_readl(musb->mregs, OTG_FORCESTDBY);
+	l |= ENABLEFORCE;	/* enable MSTANDBY */
+	musb_writel(musb->mregs, OTG_FORCESTDBY, l);
+
+	l = musb_readl(musb->mregs, OTG_SYSCONFIG);
+	l |= ENABLEWAKEUP;	/* enable wakeup */
+	l &= ~NOSTDBY;		/* disable nostdby */
+	l |= SMARTSTDBY;	/* enable smart standby */
+
+	l |= AUTOIDLE;		/* enable auto idle */
+	l &= ~NOIDLE;		/* disable noidle */
+	l |= SMARTIDLE;		/* enable smart idle */
+	musb_writel(musb->mregs, OTG_SYSCONFIG, l);
+
+	if (!cpu_is_omap3430())
+		l |= AUTOIDLE;		/* enable auto idle */
+	musb_writel(musb->mregs, OTG_SYSCONFIG, l);
+}
+EXPORT_SYMBOL_GPL(musb_platform_power_off);
+
+void musb_platform_power_on(struct musb *musb)
+{
+	u32 l;
+
+	DBG(3, "wake-up from OFF-mode\n");
+
+	l = musb_readl(musb->mregs, OTG_SYSCONFIG);
+	l &= ~ENABLEWAKEUP;	/* disable wakeup */
+	musb_writel(musb->mregs, OTG_SYSCONFIG, l);
+
+	l = musb_readl(musb->mregs, OTG_FORCESTDBY);
+	l &= ~ENABLEFORCE;	/* disable MSTANDBY */
+	musb_writel(musb->mregs, OTG_FORCESTDBY, l);
+
+	l = musb_readl(musb->mregs, OTG_SYSCONFIG);
+	l |= NOSTDBY;		/* enable nostdby */
+	l &= ~SMARTSTDBY;	/* disable smart standby */
+
+	l &= ~AUTOIDLE;		/* disable auto idle */
+	l |= NOIDLE;		/* enable noidle */
+	l &= ~SMARTIDLE;	/* disable smart idle */
+	musb_writel(musb->mregs, OTG_SYSCONFIG, l);
+
+	l = musb_readl(musb->mregs, OTG_INTERFSEL);
+	l |= ULPI_12PIN;
+	musb_writel(musb->mregs, OTG_INTERFSEL, l);
+
+	/* Restore register context */
+	musb->off_mode = 1;
+	musb_restore_context(musb);
+	musb->off_mode = 0;
+}
+EXPORT_SYMBOL_GPL(musb_platform_power_on);
+#endif /* CONFIG_PM */
 
 int musb_platform_suspend(struct musb *musb)
 {
-- 
1.6.0.4

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux