usb: musb: twl: use mailbox API to send VBUS or ID events
authorKishon Vijay Abraham I <kishon@ti.com>
Fri, 22 Jun 2012 12:10:52 +0000 (17:40 +0530)
committerFelipe Balbi <balbi@ti.com>
Mon, 25 Jun 2012 11:07:39 +0000 (14:07 +0300)
The atomic notifier from twl4030/twl6030 to notifiy VBUS and ID events,
is replaced by a direct call to omap musb blue.

Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
Signed-off-by: Felipe Balbi <balbi@ti.com>
drivers/usb/musb/omap2430.c
drivers/usb/otg/twl4030-usb.c
drivers/usb/otg/twl6030-usb.c
include/linux/usb/musb-omap.h [new file with mode: 0644]

index f40c805..0636870 100644 (file)
@@ -34,6 +34,7 @@
 #include <linux/dma-mapping.h>
 #include <linux/pm_runtime.h>
 #include <linux/err.h>
+#include <linux/usb/musb-omap.h>
 
 #include "musb_core.h"
 #include "omap2430.h"
 struct omap2430_glue {
        struct device           *dev;
        struct platform_device  *musb;
-       u8                      xceiv_event;
+       enum omap_musb_vbus_id_status status;
        struct work_struct      omap_musb_mailbox_work;
 };
 #define glue_to_musb(g)                platform_get_drvdata(g->musb)
 
+struct omap2430_glue           *_glue;
+
 static struct timer_list musb_idle_timer;
 
 static void musb_do_idle(unsigned long _musb)
@@ -225,54 +228,58 @@ static inline void omap2430_low_level_init(struct musb *musb)
        musb_writel(musb->mregs, OTG_FORCESTDBY, l);
 }
 
-static int musb_otg_notifications(struct notifier_block *nb,
-               unsigned long event, void *unused)
+void omap_musb_mailbox(enum omap_musb_vbus_id_status status)
 {
-       struct musb             *musb = container_of(nb, struct musb, nb);
-       struct device           *dev = musb->controller;
-       struct omap2430_glue    *glue = dev_get_drvdata(dev->parent);
+       struct omap2430_glue    *glue = _glue;
+       struct musb             *musb = glue_to_musb(glue);
 
-       glue->xceiv_event = event;
-       schedule_work(&glue->omap_musb_mailbox_work);
+       glue->status = status;
+       if (!musb) {
+               dev_err(glue->dev, "musb core is not yet ready\n");
+               return;
+       }
 
-       return NOTIFY_OK;
+       schedule_work(&glue->omap_musb_mailbox_work);
 }
+EXPORT_SYMBOL_GPL(omap_musb_mailbox);
 
-static void omap_musb_mailbox_work(struct work_struct *data_notifier_work)
+static void omap_musb_set_mailbox(struct omap2430_glue *glue)
 {
-       struct omap2430_glue *glue = container_of(data_notifier_work,
-               struct omap2430_glue, omap_musb_mailbox_work);
        struct musb *musb = glue_to_musb(glue);
        struct device *dev = musb->controller;
        struct musb_hdrc_platform_data *pdata = dev->platform_data;
        struct omap_musb_board_data *data = pdata->board_data;
 
-       switch (glue->xceiv_event) {
-       case USB_EVENT_ID:
-               dev_dbg(musb->controller, "ID GND\n");
+       switch (glue->status) {
+       case OMAP_MUSB_ID_GROUND:
+               dev_dbg(dev, "ID GND\n");
 
+               musb->xceiv->last_event = USB_EVENT_ID;
                if (!is_otg_enabled(musb) || musb->gadget_driver) {
-                       pm_runtime_get_sync(musb->controller);
+                       pm_runtime_get_sync(dev);
                        usb_phy_init(musb->xceiv);
                        omap2430_musb_set_vbus(musb, 1);
                }
                break;
 
-       case USB_EVENT_VBUS:
-               dev_dbg(musb->controller, "VBUS Connect\n");
+       case OMAP_MUSB_VBUS_VALID:
+               dev_dbg(dev, "VBUS Connect\n");
 
+               musb->xceiv->last_event = USB_EVENT_VBUS;
                if (musb->gadget_driver)
-                       pm_runtime_get_sync(musb->controller);
+                       pm_runtime_get_sync(dev);
                usb_phy_init(musb->xceiv);
                break;
 
-       case USB_EVENT_NONE:
-               dev_dbg(musb->controller, "VBUS Disconnect\n");
+       case OMAP_MUSB_ID_FLOAT:
+       case OMAP_MUSB_VBUS_OFF:
+               dev_dbg(dev, "VBUS Disconnect\n");
 
+               musb->xceiv->last_event = USB_EVENT_NONE;
                if (is_otg_enabled(musb) || is_peripheral_enabled(musb))
                        if (musb->gadget_driver) {
-                               pm_runtime_mark_last_busy(musb->controller);
-                               pm_runtime_put_autosuspend(musb->controller);
+                               pm_runtime_mark_last_busy(dev);
+                               pm_runtime_put_autosuspend(dev);
                        }
 
                if (data->interface_type == MUSB_INTERFACE_UTMI) {
@@ -282,15 +289,24 @@ static void omap_musb_mailbox_work(struct work_struct *data_notifier_work)
                usb_phy_shutdown(musb->xceiv);
                break;
        default:
-               dev_dbg(musb->controller, "ID float\n");
+               dev_dbg(dev, "ID float\n");
        }
 }
 
+
+static void omap_musb_mailbox_work(struct work_struct *mailbox_work)
+{
+       struct omap2430_glue *glue = container_of(mailbox_work,
+                               struct omap2430_glue, omap_musb_mailbox_work);
+       omap_musb_set_mailbox(glue);
+}
+
 static int omap2430_musb_init(struct musb *musb)
 {
        u32 l;
        int status = 0;
        struct device *dev = musb->controller;
+       struct omap2430_glue *glue = dev_get_drvdata(dev->parent);
        struct musb_hdrc_platform_data *plat = dev->platform_data;
        struct omap_musb_board_data *data = plat->board_data;
 
@@ -330,14 +346,11 @@ static int omap2430_musb_init(struct musb *musb)
                        musb_readl(musb->mregs, OTG_INTERFSEL),
                        musb_readl(musb->mregs, OTG_SIMENABLE));
 
-       musb->nb.notifier_call = musb_otg_notifications;
-       status = usb_register_notifier(musb->xceiv, &musb->nb);
-
-       if (status)
-               dev_dbg(musb->controller, "notification register failed\n");
-
        setup_timer(&musb_idle_timer, musb_do_idle, (unsigned long) musb);
 
+       if (glue->status != OMAP_MUSB_UNKNOWN)
+               omap_musb_set_mailbox(glue);
+
        pm_runtime_put_noidle(musb->controller);
        return 0;
 
@@ -350,12 +363,13 @@ static void omap2430_musb_enable(struct musb *musb)
        u8              devctl;
        unsigned long timeout = jiffies + msecs_to_jiffies(1000);
        struct device *dev = musb->controller;
+       struct omap2430_glue *glue = dev_get_drvdata(dev->parent);
        struct musb_hdrc_platform_data *pdata = dev->platform_data;
        struct omap_musb_board_data *data = pdata->board_data;
 
-       switch (musb->xceiv->last_event) {
+       switch (glue->status) {
 
-       case USB_EVENT_ID:
+       case OMAP_MUSB_ID_GROUND:
                usb_phy_init(musb->xceiv);
                if (data->interface_type != MUSB_INTERFACE_UTMI)
                        break;
@@ -374,7 +388,7 @@ static void omap2430_musb_enable(struct musb *musb)
                }
                break;
 
-       case USB_EVENT_VBUS:
+       case OMAP_MUSB_VBUS_VALID:
                usb_phy_init(musb->xceiv);
                break;
 
@@ -385,7 +399,10 @@ static void omap2430_musb_enable(struct musb *musb)
 
 static void omap2430_musb_disable(struct musb *musb)
 {
-       if (musb->xceiv->last_event)
+       struct device *dev = musb->controller;
+       struct omap2430_glue *glue = dev_get_drvdata(dev->parent);
+
+       if (glue->status != OMAP_MUSB_UNKNOWN)
                usb_phy_shutdown(musb->xceiv);
 }
 
@@ -439,11 +456,18 @@ static int __devinit omap2430_probe(struct platform_device *pdev)
 
        glue->dev                       = &pdev->dev;
        glue->musb                      = musb;
+       glue->status                    = OMAP_MUSB_UNKNOWN;
 
        pdata->platform_ops             = &omap2430_ops;
 
        platform_set_drvdata(pdev, glue);
 
+       /*
+        * REVISIT if we ever have two instances of the wrapper, we will be
+        * in big trouble
+        */
+       _glue   = glue;
+
        INIT_WORK(&glue->omap_musb_mailbox_work, omap_musb_mailbox_work);
 
        ret = platform_device_add_resources(musb, pdev->resource,
@@ -552,7 +576,7 @@ static int __init omap2430_init(void)
 {
        return platform_driver_register(&omap2430_driver);
 }
-module_init(omap2430_init);
+subsys_initcall(omap2430_init);
 
 static void __exit omap2430_exit(void)
 {
index 25a09fa..a7b809e 100644 (file)
 #include <linux/io.h>
 #include <linux/delay.h>
 #include <linux/usb/otg.h>
+#include <linux/usb/musb-omap.h>
 #include <linux/usb/ulpi.h>
 #include <linux/i2c/twl.h>
 #include <linux/regulator/consumer.h>
 #include <linux/err.h>
-#include <linux/notifier.h>
 #include <linux/slab.h>
 
 /* Register defines */
@@ -159,7 +159,7 @@ struct twl4030_usb {
        enum twl4030_usb_mode   usb_mode;
 
        int                     irq;
-       u8                      linkstat;
+       enum omap_musb_vbus_id_status linkstat;
        bool                    vbus_supplied;
        u8                      asleep;
        bool                    irq_enabled;
@@ -246,10 +246,11 @@ twl4030_usb_clear_bits(struct twl4030_usb *twl, u8 reg, u8 bits)
 
 /*-------------------------------------------------------------------------*/
 
-static enum usb_phy_events twl4030_usb_linkstat(struct twl4030_usb *twl)
+static enum omap_musb_vbus_id_status
+       twl4030_usb_linkstat(struct twl4030_usb *twl)
 {
        int     status;
-       int     linkstat = USB_EVENT_NONE;
+       enum omap_musb_vbus_id_status linkstat = OMAP_MUSB_UNKNOWN;
        struct usb_otg *otg = twl->phy.otg;
 
        twl->vbus_supplied = false;
@@ -273,24 +274,24 @@ static enum usb_phy_events twl4030_usb_linkstat(struct twl4030_usb *twl)
                         twl->vbus_supplied = true;
 
                if (status & BIT(2))
-                       linkstat = USB_EVENT_ID;
+                       linkstat = OMAP_MUSB_ID_GROUND;
                else
-                       linkstat = USB_EVENT_VBUS;
-       } else
-               linkstat = USB_EVENT_NONE;
+                       linkstat = OMAP_MUSB_VBUS_VALID;
+       } else {
+               if (twl->linkstat != OMAP_MUSB_UNKNOWN)
+                       linkstat = OMAP_MUSB_VBUS_OFF;
+       }
 
        dev_dbg(twl->dev, "HW_CONDITIONS 0x%02x/%d; link %d\n",
                        status, status, linkstat);
 
-       twl->phy.last_event = linkstat;
-
        /* REVISIT this assumes host and peripheral controllers
         * are registered, and that both are active...
         */
 
        spin_lock_irq(&twl->lock);
        twl->linkstat = linkstat;
-       if (linkstat == USB_EVENT_ID) {
+       if (linkstat == OMAP_MUSB_ID_GROUND) {
                otg->default_a = true;
                twl->phy.state = OTG_STATE_A_IDLE;
        } else {
@@ -501,10 +502,10 @@ static DEVICE_ATTR(vbus, 0444, twl4030_usb_vbus_show, NULL);
 static irqreturn_t twl4030_usb_irq(int irq, void *_twl)
 {
        struct twl4030_usb *twl = _twl;
-       int status;
+       enum omap_musb_vbus_id_status status;
 
        status = twl4030_usb_linkstat(twl);
-       if (status >= 0) {
+       if (status > 0) {
                /* FIXME add a set_power() method so that B-devices can
                 * configure the charger appropriately.  It's not always
                 * correct to consume VBUS power, and how much current to
@@ -516,13 +517,13 @@ static irqreturn_t twl4030_usb_irq(int irq, void *_twl)
                 * USB_LINK_VBUS state.  musb_hdrc won't care until it
                 * starts to handle softconnect right.
                 */
-               if (status == USB_EVENT_NONE)
+               if (status == OMAP_MUSB_VBUS_OFF ||
+                               status == OMAP_MUSB_ID_FLOAT)
                        twl4030_phy_suspend(twl, 0);
                else
                        twl4030_phy_resume(twl);
 
-               atomic_notifier_call_chain(&twl->phy.notifier, status,
-                               twl->phy.otg->gadget);
+               omap_musb_mailbox(twl->linkstat);
        }
        sysfs_notify(&twl->dev->kobj, NULL, "vbus");
 
@@ -531,11 +532,12 @@ static irqreturn_t twl4030_usb_irq(int irq, void *_twl)
 
 static void twl4030_usb_phy_init(struct twl4030_usb *twl)
 {
-       int status;
+       enum omap_musb_vbus_id_status status;
 
        status = twl4030_usb_linkstat(twl);
-       if (status >= 0) {
-               if (status == USB_EVENT_NONE) {
+       if (status > 0) {
+               if (status == OMAP_MUSB_VBUS_OFF ||
+                               status == OMAP_MUSB_ID_FLOAT) {
                        __twl4030_phy_power(twl, 0);
                        twl->asleep = 1;
                } else {
@@ -543,8 +545,7 @@ static void twl4030_usb_phy_init(struct twl4030_usb *twl)
                        twl->asleep = 0;
                }
 
-               atomic_notifier_call_chain(&twl->phy.notifier, status,
-                               twl->phy.otg->gadget);
+               omap_musb_mailbox(twl->linkstat);
        }
        sysfs_notify(&twl->dev->kobj, NULL, "vbus");
 }
@@ -613,6 +614,7 @@ static int __devinit twl4030_usb_probe(struct platform_device *pdev)
        twl->usb_mode           = pdata->usb_mode;
        twl->vbus_supplied      = false;
        twl->asleep             = 1;
+       twl->linkstat           = OMAP_MUSB_UNKNOWN;
 
        twl->phy.dev            = twl->dev;
        twl->phy.label          = "twl4030";
@@ -639,8 +641,6 @@ static int __devinit twl4030_usb_probe(struct platform_device *pdev)
        if (device_create_file(&pdev->dev, &dev_attr_vbus))
                dev_warn(&pdev->dev, "could not create sysfs file\n");
 
-       ATOMIC_INIT_NOTIFIER_HEAD(&twl->phy.notifier);
-
        /* Our job is to use irqs and status from the power module
         * to keep the transceiver disabled when nothing's connected.
         *
index dbee00a..6c75883 100644 (file)
 #include <linux/platform_device.h>
 #include <linux/io.h>
 #include <linux/usb/otg.h>
+#include <linux/usb/musb-omap.h>
 #include <linux/i2c/twl.h>
 #include <linux/regulator/consumer.h>
 #include <linux/err.h>
-#include <linux/notifier.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
 
@@ -100,7 +100,7 @@ struct twl6030_usb {
 
        int                     irq1;
        int                     irq2;
-       u8                      linkstat;
+       enum omap_musb_vbus_id_status linkstat;
        u8                      asleep;
        bool                    irq_enabled;
        bool                    vbus_enable;
@@ -147,7 +147,7 @@ static int twl6030_phy_init(struct usb_phy *x)
        dev  = twl->dev;
        pdata = dev->platform_data;
 
-       if (twl->linkstat == USB_EVENT_ID)
+       if (twl->linkstat == OMAP_MUSB_ID_GROUND)
                pdata->phy_power(twl->dev, 1, 1);
        else
                pdata->phy_power(twl->dev, 0, 1);
@@ -235,13 +235,13 @@ static ssize_t twl6030_usb_vbus_show(struct device *dev,
        spin_lock_irqsave(&twl->lock, flags);
 
        switch (twl->linkstat) {
-       case USB_EVENT_VBUS:
+       case OMAP_MUSB_VBUS_VALID:
               ret = snprintf(buf, PAGE_SIZE, "vbus\n");
               break;
-       case USB_EVENT_ID:
+       case OMAP_MUSB_ID_GROUND:
               ret = snprintf(buf, PAGE_SIZE, "id\n");
               break;
-       case USB_EVENT_NONE:
+       case OMAP_MUSB_VBUS_OFF:
               ret = snprintf(buf, PAGE_SIZE, "none\n");
               break;
        default:
@@ -257,7 +257,7 @@ static irqreturn_t twl6030_usb_irq(int irq, void *_twl)
 {
        struct twl6030_usb *twl = _twl;
        struct usb_otg *otg = twl->phy.otg;
-       int status;
+       enum omap_musb_vbus_id_status status = OMAP_MUSB_UNKNOWN;
        u8 vbus_state, hw_state;
 
        hw_state = twl6030_readb(twl, TWL6030_MODULE_ID0, STS_HW_CONDITIONS);
@@ -268,22 +268,20 @@ static irqreturn_t twl6030_usb_irq(int irq, void *_twl)
                if (vbus_state & VBUS_DET) {
                        regulator_enable(twl->usb3v3);
                        twl->asleep = 1;
-                       status = USB_EVENT_VBUS;
+                       status = OMAP_MUSB_VBUS_VALID;
                        otg->default_a = false;
                        twl->phy.state = OTG_STATE_B_IDLE;
                        twl->linkstat = status;
-                       twl->phy.last_event = status;
-                       atomic_notifier_call_chain(&twl->phy.notifier,
-                                               status, otg->gadget);
+                       omap_musb_mailbox(status);
                } else {
-                       status = USB_EVENT_NONE;
-                       twl->linkstat = status;
-                       twl->phy.last_event = status;
-                       atomic_notifier_call_chain(&twl->phy.notifier,
-                                               status, otg->gadget);
-                       if (twl->asleep) {
-                               regulator_disable(twl->usb3v3);
-                               twl->asleep = 0;
+                       if (twl->linkstat != OMAP_MUSB_UNKNOWN) {
+                               status = OMAP_MUSB_VBUS_OFF;
+                               twl->linkstat = status;
+                               omap_musb_mailbox(status);
+                               if (twl->asleep) {
+                                       regulator_disable(twl->usb3v3);
+                                       twl->asleep = 0;
+                               }
                        }
                }
        }
@@ -296,7 +294,7 @@ static irqreturn_t twl6030_usbotg_irq(int irq, void *_twl)
 {
        struct twl6030_usb *twl = _twl;
        struct usb_otg *otg = twl->phy.otg;
-       int status = USB_EVENT_NONE;
+       enum omap_musb_vbus_id_status status = OMAP_MUSB_UNKNOWN;
        u8 hw_state;
 
        hw_state = twl6030_readb(twl, TWL6030_MODULE_ID0, STS_HW_CONDITIONS);
@@ -308,13 +306,11 @@ static irqreturn_t twl6030_usbotg_irq(int irq, void *_twl)
                twl6030_writeb(twl, TWL_MODULE_USB, USB_ID_INT_EN_HI_CLR, 0x1);
                twl6030_writeb(twl, TWL_MODULE_USB, USB_ID_INT_EN_HI_SET,
                                                                0x10);
-               status = USB_EVENT_ID;
+               status = OMAP_MUSB_ID_GROUND;
                otg->default_a = true;
                twl->phy.state = OTG_STATE_A_IDLE;
                twl->linkstat = status;
-               twl->phy.last_event = status;
-               atomic_notifier_call_chain(&twl->phy.notifier, status,
-                                                       otg->gadget);
+               omap_musb_mailbox(status);
        } else  {
                twl6030_writeb(twl, TWL_MODULE_USB, USB_ID_INT_EN_HI_CLR,
                                                                0x10);
@@ -419,6 +415,7 @@ static int __devinit twl6030_usb_probe(struct platform_device *pdev)
        twl->irq1               = platform_get_irq(pdev, 0);
        twl->irq2               = platform_get_irq(pdev, 1);
        twl->features           = pdata->features;
+       twl->linkstat           = OMAP_MUSB_UNKNOWN;
 
        twl->phy.dev            = twl->dev;
        twl->phy.label          = "twl6030";
@@ -449,8 +446,6 @@ static int __devinit twl6030_usb_probe(struct platform_device *pdev)
        if (device_create_file(&pdev->dev, &dev_attr_vbus))
                dev_warn(&pdev->dev, "could not create sysfs file\n");
 
-       ATOMIC_INIT_NOTIFIER_HEAD(&twl->phy.notifier);
-
        INIT_WORK(&twl->set_vbus_work, otg_set_vbus_work);
 
        twl->irq_enabled = true;
diff --git a/include/linux/usb/musb-omap.h b/include/linux/usb/musb-omap.h
new file mode 100644 (file)
index 0000000..7774c59
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2011-2012 by Texas Instruments
+ *
+ * The Inventra Controller Driver for Linux is free software; you
+ * can redistribute it and/or modify it under the terms of the GNU
+ * General Public License version 2 as published by the Free Software
+ * Foundation.
+ */
+
+#ifndef __MUSB_OMAP_H__
+#define __MUSB_OMAP_H__
+
+enum omap_musb_vbus_id_status {
+       OMAP_MUSB_UNKNOWN = 0,
+       OMAP_MUSB_ID_GROUND,
+       OMAP_MUSB_ID_FLOAT,
+       OMAP_MUSB_VBUS_VALID,
+       OMAP_MUSB_VBUS_OFF,
+};
+
+#if (defined(CONFIG_USB_MUSB_OMAP2PLUS) || \
+                               defined(CONFIG_USB_MUSB_OMAP2PLUS_MODULE))
+void omap_musb_mailbox(enum omap_musb_vbus_id_status status);
+#else
+static inline void omap_musb_mailbox(enum omap_musb_vbus_id_status status)
+{
+}
+#endif
+
+#endif /* __MUSB_OMAP_H__ */