Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 316976
b: refs/heads/master
c: c972143
h: refs/heads/master
v: v3
  • Loading branch information
Kishon Vijay Abraham I authored and Felipe Balbi committed Jun 25, 2012
1 parent 990b894 commit 29b3531
Show file tree
Hide file tree
Showing 5 changed files with 134 additions and 85 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 1e5acb8d6113a0f159257845e153d5b870ca618a
refs/heads/master: c9721438c009adf8e81d376839ed037c53b9b8d9
94 changes: 59 additions & 35 deletions trunk/drivers/usb/musb/omap2430.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,18 +34,21 @@
#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)
Expand Down Expand Up @@ -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) {
Expand All @@ -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;

Expand Down Expand Up @@ -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;

Expand All @@ -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;
Expand All @@ -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;

Expand All @@ -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);
}

Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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)
{
Expand Down
46 changes: 23 additions & 23 deletions trunk/drivers/usb/otg/twl4030-usb.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,11 @@
#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 */
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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 {
Expand Down Expand Up @@ -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
Expand All @@ -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");

Expand All @@ -531,20 +532,20 @@ 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 {
__twl4030_phy_resume(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");
}
Expand Down Expand Up @@ -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";
Expand All @@ -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.
*
Expand Down
Loading

0 comments on commit 29b3531

Please sign in to comment.