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-omap" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html