[RFC/PATCH 5/5] usb: musb: musb supports otg notifier

From: Felipe Balbi
Date: Fri Dec 11 2009 - 06:33:18 EST


we use the notifier to kick the charger detection.
Needed on RX-51 board. Later on we will notify
also the bMaxPower field from usb_configuration.

Signed-off-by: Felipe Balbi <felipe.balbi@xxxxxxxxx>
---
drivers/usb/musb/musb_core.c | 72 ++++++++++++++++++++++++++++++++++++++++++
drivers/usb/musb/musb_core.h | 5 +++
2 files changed, 77 insertions(+), 0 deletions(-)

diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c
index 55e185a..c7c60df 100644
--- a/drivers/usb/musb/musb_core.c
+++ b/drivers/usb/musb/musb_core.c
@@ -98,6 +98,7 @@
#include <linux/kobject.h>
#include <linux/platform_device.h>
#include <linux/io.h>
+#include <linux/notifier.h>

#ifdef CONFIG_ARM
#include <mach/hardware.h>
@@ -144,6 +145,74 @@ MODULE_ALIAS("platform:" MUSB_DRIVER_NAME);

/*-------------------------------------------------------------------------*/

+#include "isp1704.h"
+
+static int musb_detect_charger(struct musb *musb)
+{
+ unsigned long timeout;
+ u8 vdat = 0;
+ u8 power;
+ u8 r;
+
+ /* first we disable data pullups */
+ power = musb_readb(musb->mregs, MUSB_POWER);
+ power &= ~MUSB_POWER_SOFTCONN;
+ musb_writeb(musb->mregs, MUSB_POWER, power);
+
+ /* now we set SW control bit in PWR_CTRL register */
+ r = musb_ulpi_readb(musb->mregs, ISP1704_PWR_CTRL);
+ r |= ISP1704_PWR_CTRL_SWCTRL;
+ musb_ulpi_writeb(musb->mregs, ISP1704_PWR_CTRL, r);
+
+ /* and finally enable manual charger detection */
+ r |= ISP1704_PWR_CTRL_DPVSRC_EN;
+ musb_ulpi_writeb(musb->mregs, ISP1704_PWR_CTRL, r);
+ msleep(10);
+
+ timeout = jiffies + msecs_to_jiffies(300);
+ while (!time_after(jiffies, timeout)) {
+ /* Check if there is a charger */
+ vdat = !!(musb_ulpi_readb(musb->mregs, ISP1704_PWR_CTRL)
+ & ISP1704_PWR_CTRL_VDAT_DET);
+ if (vdat)
+ break;
+ }
+
+ /* clear DPVSRC_EN, otherwise usb communication doesn't work */
+ r &= ~ISP1704_PWR_CTRL_DPVSRC_EN;
+ musb_ulpi_writeb(musb->mregs, ISP1704_PWR_CTRL, r);
+
+ if (vdat)
+ blocking_notifier_call_chain(&musb->xceiv->notifier,
+ USB_EVENT_CHARGER, &musb->g);
+
+ /*
+ * re-enable data pullups, we might have been connected
+ * to a host/hub charger
+ */
+ power |= MUSB_POWER_SOFTCONN;
+ musb_writeb(musb->mregs, MUSB_POWER, power);
+
+ return vdat;
+}
+
+static int musb_notifier_call(struct notifier_block *nb, unsigned long event,
+ void *_gadget)
+{
+ struct usb_gadget *g = _gadget;
+ struct musb *musb = container_of(g, struct musb, g);
+
+ switch (event) {
+ case USB_EVENT_VBUS:
+ musb->is_charger = musb_detect_charger(musb);
+ break;
+ default:
+ return NOTIFY_DONE;
+ }
+
+ return NOTIFY_OK;
+}
+
static inline struct musb *dev_to_musb(struct device *dev)
{
#ifdef CONFIG_USB_MUSB_HDRC_HCD
@@ -1961,6 +2030,9 @@ bad_config:
goto fail2;
}

+ musb->nb.notifier_call = musb_notifier_call;
+ otg_register_notifier(musb->xceiv, &musb->nb);
+
#ifndef CONFIG_MUSB_PIO_ONLY
if (use_dma && dev->dma_mask) {
struct dma_controller *c;
diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h
index 644fcd8..3de6eb8 100644
--- a/drivers/usb/musb/musb_core.h
+++ b/drivers/usb/musb/musb_core.h
@@ -322,6 +322,9 @@ struct musb {
struct clk *clock;
irqreturn_t (*isr)(int, void *);
struct work_struct irq_work;
+
+ struct notifier_block nb;
+
#define MUSB_HWVERS_MAJOR(x) ((x >> 10) & 0x1f)
#define MUSB_HWVERS_MINOR(x) (x & 0x3ff)
#define MUSB_HWVERS_RC 0x8000
@@ -432,6 +435,8 @@ struct musb {
unsigned is_self_powered:1;
unsigned is_bus_powered:1;

+ unsigned is_charger:1;
+
unsigned set_address:1;
unsigned test_mode:1;
unsigned softconnect:1;
--
1.6.6.rc0

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