summaryrefslogtreecommitdiffstats
path: root/drivers/usb/musb/omap2430.c
diff options
context:
space:
mode:
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-07-05 15:35:41 -0700
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-07-05 15:35:41 -0700
commitff9cce82772a78983b529e044d85884d3ec95fda (patch)
tree6491adac0538739a415f7b776d1865ce7ae5d1f7 /drivers/usb/musb/omap2430.c
parent933141509cefd64102a943d61d154c5c53bad889 (diff)
parentf8ecf829481b2cc7301a811da9d2df53ef174977 (diff)
downloadop-kernel-dev-ff9cce82772a78983b529e044d85884d3ec95fda.zip
op-kernel-dev-ff9cce82772a78983b529e044d85884d3ec95fda.tar.gz
Merge tag 'xceiv-for-v3.6' of git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb into usb-next
usb: phy: patches for v3.6 merge window We are starting to support multiple USB phys as we should thanks for Kishon's work. DeviceTree support for USB PHYs won't come until discussion with DeviceTree maintainer is finished. Together with that series, we have one fix for twl4030 which missed a IRQF_ONESHOT annotation when requesting a threaded IRQ without a top half handler, and removal of an unused variable compilation warning to isp1301_omap.
Diffstat (limited to 'drivers/usb/musb/omap2430.c')
-rw-r--r--drivers/usb/musb/omap2430.c124
1 files changed, 77 insertions, 47 deletions
diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c
index c7785e8..5fdb9da 100644
--- a/drivers/usb/musb/omap2430.c
+++ b/drivers/usb/musb/omap2430.c
@@ -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"
@@ -41,9 +42,13 @@
struct omap2430_glue {
struct device *dev;
struct platform_device *musb;
+ 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)
@@ -223,50 +228,63 @@ 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 omap2430_glue *glue = _glue;
+ struct musb *musb = glue_to_musb(glue);
- musb->xceiv_event = event;
- schedule_work(&musb->otg_notifier_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 musb_otg_notifier_work(struct work_struct *data_notifier_work)
+static void omap_musb_set_mailbox(struct omap2430_glue *glue)
{
- struct musb *musb = container_of(data_notifier_work, struct musb, otg_notifier_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;
+ struct usb_otg *otg = musb->xceiv->otg;
- switch (musb->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");
+ otg->default_a = true;
+ musb->xceiv->state = OTG_STATE_A_IDLE;
+ 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");
+ otg->default_a = false;
+ musb->xceiv->state = OTG_STATE_B_IDLE;
+ 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) {
@@ -276,15 +294,24 @@ static void musb_otg_notifier_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;
@@ -292,14 +319,12 @@ static int omap2430_musb_init(struct musb *musb)
* up through ULPI. TWL4030-family PMICs include one,
* which needs a driver, drivers aren't always needed.
*/
- musb->xceiv = usb_get_transceiver();
- if (!musb->xceiv) {
+ musb->xceiv = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2);
+ if (IS_ERR_OR_NULL(musb->xceiv)) {
pr_err("HS USB OTG: no transceiver configured\n");
return -ENODEV;
}
- INIT_WORK(&musb->otg_notifier_work, musb_otg_notifier_work);
-
status = pm_runtime_get_sync(dev);
if (status < 0) {
dev_err(dev, "pm_runtime_get_sync FAILED %d\n", status);
@@ -326,14 +351,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;
@@ -346,12 +368,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;
@@ -370,7 +393,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;
@@ -381,17 +404,18 @@ 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);
}
static int omap2430_musb_exit(struct musb *musb)
{
del_timer_sync(&musb_idle_timer);
- cancel_work_sync(&musb->otg_notifier_work);
omap2430_low_level_exit(musb);
- usb_put_transceiver(musb->xceiv);
return 0;
}
@@ -418,7 +442,7 @@ static int __devinit omap2430_probe(struct platform_device *pdev)
struct omap2430_glue *glue;
int ret = -ENOMEM;
- glue = kzalloc(sizeof(*glue), GFP_KERNEL);
+ glue = devm_kzalloc(&pdev->dev, sizeof(*glue), GFP_KERNEL);
if (!glue) {
dev_err(&pdev->dev, "failed to allocate glue context\n");
goto err0;
@@ -427,7 +451,7 @@ static int __devinit omap2430_probe(struct platform_device *pdev)
musb = platform_device_alloc("musb-hdrc", -1);
if (!musb) {
dev_err(&pdev->dev, "failed to allocate musb device\n");
- goto err1;
+ goto err0;
}
musb->dev.parent = &pdev->dev;
@@ -436,22 +460,31 @@ 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,
pdev->num_resources);
if (ret) {
dev_err(&pdev->dev, "failed to add resources\n");
- goto err2;
+ goto err1;
}
ret = platform_device_add_data(musb, pdata, sizeof(*pdata));
if (ret) {
dev_err(&pdev->dev, "failed to add platform_data\n");
- goto err2;
+ goto err1;
}
pm_runtime_enable(&pdev->dev);
@@ -459,16 +492,13 @@ static int __devinit omap2430_probe(struct platform_device *pdev)
ret = platform_device_add(musb);
if (ret) {
dev_err(&pdev->dev, "failed to register musb device\n");
- goto err2;
+ goto err1;
}
return 0;
-err2:
- platform_device_put(musb);
-
err1:
- kfree(glue);
+ platform_device_put(musb);
err0:
return ret;
@@ -478,9 +508,9 @@ static int __devexit omap2430_remove(struct platform_device *pdev)
{
struct omap2430_glue *glue = platform_get_drvdata(pdev);
+ cancel_work_sync(&glue->omap_musb_mailbox_work);
platform_device_del(glue->musb);
platform_device_put(glue->musb);
- kfree(glue);
return 0;
}
@@ -546,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)
{
OpenPOWER on IntegriCloud