diff options
Diffstat (limited to 'drivers/usb/musb/omap2430.c')
| -rw-r--r-- | drivers/usb/musb/omap2430.c | 516 |
1 files changed, 347 insertions, 169 deletions
diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c index bc8badd1689..d369bf1f393 100644 --- a/drivers/usb/musb/omap2430.c +++ b/drivers/usb/musb/omap2430.c @@ -29,10 +29,16 @@ #include <linux/sched.h> #include <linux/init.h> #include <linux/list.h> -#include <linux/clk.h> #include <linux/io.h> +#include <linux/of.h> #include <linux/platform_device.h> #include <linux/dma-mapping.h> +#include <linux/pm_runtime.h> +#include <linux/err.h> +#include <linux/delay.h> +#include <linux/usb/musb-omap.h> +#include <linux/phy/omap_control_phy.h> +#include <linux/of_platform.h> #include "musb_core.h" #include "omap2430.h" @@ -40,19 +46,21 @@ struct omap2430_glue { struct device *dev; struct platform_device *musb; - struct clk *clk; + enum omap_musb_vbus_id_status status; + struct work_struct omap_musb_mailbox_work; + struct device *control_otghs; }; #define glue_to_musb(g) platform_get_drvdata(g->musb) +static struct omap2430_glue *_glue; + static struct timer_list musb_idle_timer; static void musb_do_idle(unsigned long _musb) { struct musb *musb = (void *)_musb; unsigned long flags; -#ifdef CONFIG_USB_MUSB_HDRC_HCD u8 power; -#endif u8 devctl; spin_lock_irqsave(&musb->lock, flags); @@ -69,32 +77,28 @@ static void musb_do_idle(unsigned long _musb) MUSB_HST_MODE(musb); } break; -#ifdef CONFIG_USB_MUSB_HDRC_HCD case OTG_STATE_A_SUSPEND: /* finish RESUME signaling? */ if (musb->port1_status & MUSB_PORT_STAT_RESUME) { power = musb_readb(musb->mregs, MUSB_POWER); power &= ~MUSB_POWER_RESUME; - DBG(1, "root port resume stopped, power %02x\n", power); + dev_dbg(musb->controller, "root port resume stopped, power %02x\n", power); musb_writeb(musb->mregs, MUSB_POWER, power); musb->is_active = 1; musb->port1_status &= ~(USB_PORT_STAT_SUSPEND | MUSB_PORT_STAT_RESUME); musb->port1_status |= USB_PORT_STAT_C_SUSPEND << 16; - usb_hcd_poll_rh_status(musb_to_hcd(musb)); + usb_hcd_poll_rh_status(musb->hcd); /* NOTE: it might really be A_WAIT_BCON ... */ musb->xceiv->state = OTG_STATE_A_HOST; } break; -#endif -#ifdef CONFIG_USB_MUSB_HDRC_HCD case OTG_STATE_A_HOST: devctl = musb_readb(musb->mregs, MUSB_DEVCTL); if (devctl & MUSB_DEVCTL_BDEVICE) musb->xceiv->state = OTG_STATE_B_IDLE; else musb->xceiv->state = OTG_STATE_A_WAIT_BCON; -#endif default: break; } @@ -113,7 +117,8 @@ static void omap2430_musb_try_idle(struct musb *musb, unsigned long timeout) /* Never idle if active, or when VBUS timeout is not set as host */ if (musb->is_active || ((musb->a_wait_bcon == 0) && (musb->xceiv->state == OTG_STATE_A_WAIT_BCON))) { - DBG(4, "%s active, deleting timer\n", otg_state_string(musb)); + dev_dbg(musb->controller, "%s active, deleting timer\n", + usb_otg_state_string(musb->xceiv->state)); del_timer(&musb_idle_timer); last_timer = jiffies; return; @@ -123,23 +128,23 @@ static void omap2430_musb_try_idle(struct musb *musb, unsigned long timeout) if (!timer_pending(&musb_idle_timer)) last_timer = timeout; else { - DBG(4, "Longer idle timer already pending, ignoring\n"); + dev_dbg(musb->controller, "Longer idle timer already pending, ignoring\n"); return; } } last_timer = timeout; - DBG(4, "%s inactive, for idle timer for %lu ms\n", - otg_state_string(musb), + dev_dbg(musb->controller, "%s inactive, for idle timer for %lu ms\n", + usb_otg_state_string(musb->xceiv->state), (unsigned long)jiffies_to_msecs(timeout - jiffies)); mod_timer(&musb_idle_timer, timeout); } static void omap2430_musb_set_vbus(struct musb *musb, int is_on) { + struct usb_otg *otg = musb->xceiv->otg; u8 devctl; unsigned long timeout = jiffies + msecs_to_jiffies(1000); - int ret = 1; /* HDRC controls CPEN, but beware current surges during device * connect. They can trigger transient overcurrent conditions * that must be ignored. @@ -149,6 +154,7 @@ static void omap2430_musb_set_vbus(struct musb *musb, int is_on) if (is_on) { if (musb->xceiv->state == OTG_STATE_A_IDLE) { + int loops = 100; /* start the session */ devctl |= MUSB_DEVCTL_SESSION; musb_writeb(musb->mregs, MUSB_DEVCTL, devctl); @@ -158,21 +164,21 @@ static void omap2430_musb_set_vbus(struct musb *musb, int is_on) */ while (musb_readb(musb->mregs, MUSB_DEVCTL) & 0x80) { + mdelay(5); cpu_relax(); - if (time_after(jiffies, timeout)) { + if (time_after(jiffies, timeout) + || loops-- <= 0) { dev_err(musb->controller, "configured as A device timeout"); - ret = -EINVAL; break; } } - if (ret && musb->xceiv->set_vbus) - otg_set_vbus(musb->xceiv, 1); + otg_set_vbus(otg, 1); } else { musb->is_active = 1; - musb->xceiv->default_a = 1; + otg->default_a = 1; musb->xceiv->state = OTG_STATE_A_WAIT_VRISE; devctl |= MUSB_DEVCTL_SESSION; MUSB_HST_MODE(musb); @@ -184,7 +190,7 @@ static void omap2430_musb_set_vbus(struct musb *musb, int is_on) * jumping right to B_IDLE... */ - musb->xceiv->default_a = 0; + otg->default_a = 0; musb->xceiv->state = OTG_STATE_B_IDLE; devctl &= ~MUSB_DEVCTL_SESSION; @@ -192,9 +198,9 @@ static void omap2430_musb_set_vbus(struct musb *musb, int is_on) } musb_writeb(musb->mregs, MUSB_DEVCTL, devctl); - DBG(1, "VBUS %s, devctl %02x " + dev_dbg(musb->controller, "VBUS %s, devctl %02x " /* otg %3x conf %08x prcm %08x */ "\n", - otg_state_string(musb), + usb_otg_state_string(musb->xceiv->state), musb_readb(musb->mregs, MUSB_DEVCTL)); } @@ -216,113 +222,179 @@ static inline void omap2430_low_level_exit(struct musb *musb) l = musb_readl(musb->mregs, OTG_FORCESTDBY); l |= ENABLEFORCE; /* enable MSTANDBY */ musb_writel(musb->mregs, OTG_FORCESTDBY, l); - - l = musb_readl(musb->mregs, OTG_SYSCONFIG); - l |= ENABLEWAKEUP; /* enable wakeup */ - musb_writel(musb->mregs, OTG_SYSCONFIG, l); } static inline void omap2430_low_level_init(struct musb *musb) { u32 l; - l = musb_readl(musb->mregs, OTG_SYSCONFIG); - l &= ~ENABLEWAKEUP; /* disable wakeup */ - musb_writel(musb->mregs, OTG_SYSCONFIG, l); - l = musb_readl(musb->mregs, OTG_FORCESTDBY); l &= ~ENABLEFORCE; /* disable MSTANDBY */ musb_writel(musb->mregs, OTG_FORCESTDBY, l); } -/* blocking notifier support */ -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 musb_hdrc_platform_data *pdata = dev->platform_data; - struct omap_musb_board_data *data = pdata->board_data; + struct omap2430_glue *glue = _glue; - switch (event) { - case USB_EVENT_ID: - DBG(4, "ID GND\n"); + if (!glue) { + pr_err("%s: musb core is not yet initialized\n", __func__); + return; + } + glue->status = status; - if (is_otg_enabled(musb)) { -#ifdef CONFIG_USB_GADGET_MUSB_HDRC - if (musb->gadget_driver) { - otg_init(musb->xceiv); + if (!glue_to_musb(glue)) { + pr_err("%s: musb core is not yet ready\n", __func__); + return; + } - if (data->interface_type == - MUSB_INTERFACE_UTMI) - omap2430_musb_set_vbus(musb, 1); + schedule_work(&glue->omap_musb_mailbox_work); +} +EXPORT_SYMBOL_GPL(omap_musb_mailbox); - } -#endif - } else { - otg_init(musb->xceiv); - if (data->interface_type == - MUSB_INTERFACE_UTMI) - omap2430_musb_set_vbus(musb, 1); +static void omap_musb_set_mailbox(struct omap2430_glue *glue) +{ + struct musb *musb = glue_to_musb(glue); + struct device *dev = musb->controller; + struct musb_hdrc_platform_data *pdata = dev_get_platdata(dev); + struct omap_musb_board_data *data = pdata->board_data; + struct usb_otg *otg = musb->xceiv->otg; + + 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 (musb->gadget_driver) { + pm_runtime_get_sync(dev); + omap_control_usb_set_mode(glue->control_otghs, + USB_MODE_HOST); + omap2430_musb_set_vbus(musb, 1); } break; - case USB_EVENT_VBUS: - DBG(4, "VBUS Connect\n"); + case OMAP_MUSB_VBUS_VALID: + dev_dbg(dev, "VBUS Connect\n"); - otg_init(musb->xceiv); + 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(dev); + omap_control_usb_set_mode(glue->control_otghs, USB_MODE_DEVICE); break; - case USB_EVENT_NONE: - DBG(4, "VBUS Disconnect\n"); + case OMAP_MUSB_ID_FLOAT: + case OMAP_MUSB_VBUS_OFF: + dev_dbg(dev, "VBUS Disconnect\n"); - if (data->interface_type == MUSB_INTERFACE_UTMI) { - if (musb->xceiv->set_vbus) - otg_set_vbus(musb->xceiv, 0); + musb->xceiv->last_event = USB_EVENT_NONE; + if (musb->gadget_driver) { + omap2430_musb_set_vbus(musb, 0); + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); } - otg_shutdown(musb->xceiv); + + if (data->interface_type == MUSB_INTERFACE_UTMI) + otg_set_vbus(musb->xceiv->otg, 0); + + omap_control_usb_set_mode(glue->control_otghs, + USB_MODE_DISCONNECT); break; default: - DBG(4, "ID float\n"); - return NOTIFY_DONE; + dev_dbg(dev, "ID float\n"); } - return NOTIFY_OK; + atomic_notifier_call_chain(&musb->xceiv->notifier, + musb->xceiv->last_event, NULL); +} + + +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); + struct musb *musb = glue_to_musb(glue); + struct device *dev = musb->controller; + + pm_runtime_get_sync(dev); + omap_musb_set_mailbox(glue); + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); +} + +static irqreturn_t omap2430_musb_interrupt(int irq, void *__hci) +{ + unsigned long flags; + irqreturn_t retval = IRQ_NONE; + struct musb *musb = __hci; + + spin_lock_irqsave(&musb->lock, flags); + + musb->int_usb = musb_readb(musb->mregs, MUSB_INTRUSB); + musb->int_tx = musb_readw(musb->mregs, MUSB_INTRTX); + musb->int_rx = musb_readw(musb->mregs, MUSB_INTRRX); + + if (musb->int_usb || musb->int_tx || musb->int_rx) + retval = musb_interrupt(musb); + + spin_unlock_irqrestore(&musb->lock, flags); + + return retval; } static int omap2430_musb_init(struct musb *musb) { - u32 l, status = 0; + u32 l; + int status = 0; struct device *dev = musb->controller; - struct musb_hdrc_platform_data *plat = dev->platform_data; + struct omap2430_glue *glue = dev_get_drvdata(dev->parent); + struct musb_hdrc_platform_data *plat = dev_get_platdata(dev); struct omap_musb_board_data *data = plat->board_data; /* We require some kind of external transceiver, hooked * up through ULPI. TWL4030-family PMICs include one, * which needs a driver, drivers aren't always needed. */ - musb->xceiv = otg_get_transceiver(); - if (!musb->xceiv) { + if (dev->parent->of_node) { + musb->phy = devm_phy_get(dev->parent, "usb2-phy"); + + /* We can't totally remove musb->xceiv as of now because + * musb core uses xceiv.state and xceiv.otg. Once we have + * a separate state machine to handle otg, these can be moved + * out of xceiv and then we can start using the generic PHY + * framework + */ + musb->xceiv = devm_usb_get_phy_by_phandle(dev->parent, + "usb-phy", 0); + } else { + musb->xceiv = devm_usb_get_phy_dev(dev, 0); + musb->phy = devm_phy_get(dev, "usb"); + } + + if (IS_ERR(musb->xceiv)) { + status = PTR_ERR(musb->xceiv); + + if (status == -ENXIO) + return status; + pr_err("HS USB OTG: no transceiver configured\n"); - return -ENODEV; + return -EPROBE_DEFER; } - omap2430_low_level_init(musb); + if (IS_ERR(musb->phy)) { + pr_err("HS USB OTG: no PHY configured\n"); + return PTR_ERR(musb->phy); + } + musb->isr = omap2430_musb_interrupt; - l = musb_readl(musb->mregs, OTG_SYSCONFIG); - l &= ~ENABLEWAKEUP; /* disable wakeup */ - l &= ~NOSTDBY; /* remove possible nostdby */ - l |= SMARTSTDBY; /* enable smart standby */ - l &= ~AUTOIDLE; /* disable auto idle */ - l &= ~NOIDLE; /* remove possible noidle */ - l |= SMARTIDLE; /* enable smart idle */ - /* - * MUSB AUTOIDLE don't work in 3430. - * Workaround by Richard Woodruff/TI - */ - if (!cpu_is_omap3430()) - l |= AUTOIDLE; /* enable auto idle */ - musb_writel(musb->mregs, OTG_SYSCONFIG, l); + status = pm_runtime_get_sync(dev); + if (status < 0) { + dev_err(dev, "pm_runtime_get_sync FAILED %d\n", status); + goto err1; + } l = musb_readl(musb->mregs, OTG_INTERFSEL); @@ -344,20 +416,68 @@ 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 = otg_register_notifier(musb->xceiv, &musb->nb); - - if (status) - DBG(1, "notification register failed\n"); + setup_timer(&musb_idle_timer, musb_do_idle, (unsigned long) musb); - /* check whether cable is already connected */ - if (musb->xceiv->state ==OTG_STATE_B_IDLE) - musb_otg_notifications(&musb->nb, 1, - musb->xceiv->gadget); + if (glue->status != OMAP_MUSB_UNKNOWN) + omap_musb_set_mailbox(glue); - setup_timer(&musb_idle_timer, musb_do_idle, (unsigned long) musb); + phy_init(musb->phy); + phy_power_on(musb->phy); + pm_runtime_put_noidle(musb->controller); return 0; + +err1: + return status; +} + +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_get_platdata(dev); + struct omap_musb_board_data *data = pdata->board_data; + + switch (glue->status) { + + case OMAP_MUSB_ID_GROUND: + omap_control_usb_set_mode(glue->control_otghs, USB_MODE_HOST); + if (data->interface_type != MUSB_INTERFACE_UTMI) + break; + devctl = musb_readb(musb->mregs, MUSB_DEVCTL); + /* start the session */ + devctl |= MUSB_DEVCTL_SESSION; + musb_writeb(musb->mregs, MUSB_DEVCTL, devctl); + while (musb_readb(musb->mregs, MUSB_DEVCTL) & + MUSB_DEVCTL_BDEVICE) { + cpu_relax(); + + if (time_after(jiffies, timeout)) { + dev_err(dev, "configured as A device timeout"); + break; + } + } + break; + + case OMAP_MUSB_VBUS_VALID: + omap_control_usb_set_mode(glue->control_otghs, USB_MODE_DEVICE); + break; + + default: + break; + } +} + +static void omap2430_musb_disable(struct musb *musb) +{ + struct device *dev = musb->controller; + struct omap2430_glue *glue = dev_get_drvdata(dev->parent); + + if (glue->status != OMAP_MUSB_UNKNOWN) + omap_control_usb_set_mode(glue->control_otghs, + USB_MODE_DISCONNECT); } static int omap2430_musb_exit(struct musb *musb) @@ -365,7 +485,8 @@ static int omap2430_musb_exit(struct musb *musb) del_timer_sync(&musb_idle_timer); omap2430_low_level_exit(musb); - otg_put_transceiver(musb->xceiv); + phy_power_off(musb->phy); + phy_exit(musb->phy); return 0; } @@ -378,42 +499,34 @@ static const struct musb_platform_ops omap2430_ops = { .try_idle = omap2430_musb_try_idle, .set_vbus = omap2430_musb_set_vbus, + + .enable = omap2430_musb_enable, + .disable = omap2430_musb_disable, }; static u64 omap2430_dmamask = DMA_BIT_MASK(32); -static int __init omap2430_probe(struct platform_device *pdev) +static int omap2430_probe(struct platform_device *pdev) { - struct musb_hdrc_platform_data *pdata = pdev->dev.platform_data; + struct resource musb_resources[3]; + struct musb_hdrc_platform_data *pdata = dev_get_platdata(&pdev->dev); + struct omap_musb_board_data *data; struct platform_device *musb; struct omap2430_glue *glue; - struct clk *clk; - + struct device_node *np = pdev->dev.of_node; + struct musb_hdrc_config *config; 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; } - musb = platform_device_alloc("musb-hdrc", -1); + musb = platform_device_alloc("musb-hdrc", PLATFORM_DEVID_AUTO); if (!musb) { dev_err(&pdev->dev, "failed to allocate musb device\n"); - goto err1; - } - - clk = clk_get(&pdev->dev, "ick"); - if (IS_ERR(clk)) { - dev_err(&pdev->dev, "failed to get clock\n"); - ret = PTR_ERR(clk); - goto err2; - } - - ret = clk_enable(clk); - if (ret) { - dev_err(&pdev->dev, "failed to enable clock\n"); - goto err3; + goto err0; } musb->dev.parent = &pdev->dev; @@ -422,110 +535,160 @@ static int __init omap2430_probe(struct platform_device *pdev) glue->dev = &pdev->dev; glue->musb = musb; - glue->clk = clk; + glue->status = OMAP_MUSB_UNKNOWN; + glue->control_otghs = ERR_PTR(-ENODEV); + + if (np) { + struct device_node *control_node; + struct platform_device *control_pdev; + + pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) { + dev_err(&pdev->dev, + "failed to allocate musb platform data\n"); + goto err2; + } + + data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); + if (!data) { + dev_err(&pdev->dev, + "failed to allocate musb board data\n"); + goto err2; + } + config = devm_kzalloc(&pdev->dev, sizeof(*config), GFP_KERNEL); + if (!config) { + dev_err(&pdev->dev, + "failed to allocate musb hdrc config\n"); + goto err2; + } + + of_property_read_u32(np, "mode", (u32 *)&pdata->mode); + of_property_read_u32(np, "interface-type", + (u32 *)&data->interface_type); + of_property_read_u32(np, "num-eps", (u32 *)&config->num_eps); + of_property_read_u32(np, "ram-bits", (u32 *)&config->ram_bits); + of_property_read_u32(np, "power", (u32 *)&pdata->power); + config->multipoint = of_property_read_bool(np, "multipoint"); + + pdata->board_data = data; + pdata->config = config; + + control_node = of_parse_phandle(np, "ctrl-module", 0); + if (control_node) { + control_pdev = of_find_device_by_node(control_node); + if (!control_pdev) { + dev_err(&pdev->dev, "Failed to get control device\n"); + ret = -EINVAL; + goto err2; + } + glue->control_otghs = &control_pdev->dev; + } + } pdata->platform_ops = &omap2430_ops; platform_set_drvdata(pdev, glue); - ret = platform_device_add_resources(musb, pdev->resource, - pdev->num_resources); + /* + * 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); + + memset(musb_resources, 0x00, sizeof(*musb_resources) * + ARRAY_SIZE(musb_resources)); + + musb_resources[0].name = pdev->resource[0].name; + musb_resources[0].start = pdev->resource[0].start; + musb_resources[0].end = pdev->resource[0].end; + musb_resources[0].flags = pdev->resource[0].flags; + + musb_resources[1].name = pdev->resource[1].name; + musb_resources[1].start = pdev->resource[1].start; + musb_resources[1].end = pdev->resource[1].end; + musb_resources[1].flags = pdev->resource[1].flags; + + musb_resources[2].name = pdev->resource[2].name; + musb_resources[2].start = pdev->resource[2].start; + musb_resources[2].end = pdev->resource[2].end; + musb_resources[2].flags = pdev->resource[2].flags; + + ret = platform_device_add_resources(musb, musb_resources, + ARRAY_SIZE(musb_resources)); if (ret) { dev_err(&pdev->dev, "failed to add resources\n"); - goto err4; + goto err2; } ret = platform_device_add_data(musb, pdata, sizeof(*pdata)); if (ret) { dev_err(&pdev->dev, "failed to add platform_data\n"); - goto err4; + goto err2; } + pm_runtime_enable(&pdev->dev); + ret = platform_device_add(musb); if (ret) { dev_err(&pdev->dev, "failed to register musb device\n"); - goto err4; + goto err2; } return 0; -err4: - clk_disable(clk); - -err3: - clk_put(clk); - err2: platform_device_put(musb); -err1: - kfree(glue); - err0: return ret; } -static int __exit omap2430_remove(struct platform_device *pdev) +static int omap2430_remove(struct platform_device *pdev) { struct omap2430_glue *glue = platform_get_drvdata(pdev); - platform_device_del(glue->musb); - platform_device_put(glue->musb); - clk_disable(glue->clk); - clk_put(glue->clk); - kfree(glue); + cancel_work_sync(&glue->omap_musb_mailbox_work); + platform_device_unregister(glue->musb); return 0; } #ifdef CONFIG_PM -static void omap2430_save_context(struct musb *musb) -{ - musb->context.otg_sysconfig = musb_readl(musb->mregs, OTG_SYSCONFIG); - musb->context.otg_forcestandby = musb_readl(musb->mregs, OTG_FORCESTDBY); -} - -static void omap2430_restore_context(struct musb *musb) -{ - musb_writel(musb->mregs, OTG_SYSCONFIG, musb->context.otg_sysconfig); - musb_writel(musb->mregs, OTG_FORCESTDBY, musb->context.otg_forcestandby); -} -static int omap2430_suspend(struct device *dev) +static int omap2430_runtime_suspend(struct device *dev) { struct omap2430_glue *glue = dev_get_drvdata(dev); struct musb *musb = glue_to_musb(glue); - omap2430_low_level_exit(musb); - otg_set_suspend(musb->xceiv, 1); - omap2430_save_context(musb); - clk_disable(glue->clk); + if (musb) { + musb->context.otg_interfsel = musb_readl(musb->mregs, + OTG_INTERFSEL); + + omap2430_low_level_exit(musb); + } return 0; } -static int omap2430_resume(struct device *dev) +static int omap2430_runtime_resume(struct device *dev) { struct omap2430_glue *glue = dev_get_drvdata(dev); struct musb *musb = glue_to_musb(glue); - int ret; - ret = clk_enable(glue->clk); - if (ret) { - dev_err(dev, "faled to enable clock\n"); - return ret; + if (musb) { + omap2430_low_level_init(musb); + musb_writel(musb->mregs, OTG_INTERFSEL, + musb->context.otg_interfsel); } - omap2430_low_level_init(musb); - omap2430_restore_context(musb); - otg_set_suspend(musb->xceiv, 0); - return 0; } static struct dev_pm_ops omap2430_pm_ops = { - .suspend = omap2430_suspend, - .resume = omap2430_resume, + .runtime_suspend = omap2430_runtime_suspend, + .runtime_resume = omap2430_runtime_resume, }; #define DEV_PM_OPS (&omap2430_pm_ops) @@ -533,11 +696,26 @@ static struct dev_pm_ops omap2430_pm_ops = { #define DEV_PM_OPS NULL #endif +#ifdef CONFIG_OF +static const struct of_device_id omap2430_id_table[] = { + { + .compatible = "ti,omap4-musb" + }, + { + .compatible = "ti,omap3-musb" + }, + {}, +}; +MODULE_DEVICE_TABLE(of, omap2430_id_table); +#endif + static struct platform_driver omap2430_driver = { - .remove = __exit_p(omap2430_remove), + .probe = omap2430_probe, + .remove = omap2430_remove, .driver = { .name = "musb-omap2430", .pm = DEV_PM_OPS, + .of_match_table = of_match_ptr(omap2430_id_table), }, }; @@ -547,7 +725,7 @@ MODULE_LICENSE("GPL v2"); static int __init omap2430_init(void) { - return platform_driver_probe(&omap2430_driver, omap2430_probe); + return platform_driver_register(&omap2430_driver); } subsys_initcall(omap2430_init); |
