diff options
Diffstat (limited to 'drivers/usb/musb/blackfin.c')
-rw-r--r-- | drivers/usb/musb/blackfin.c | 181 |
1 files changed, 159 insertions, 22 deletions
diff --git a/drivers/usb/musb/blackfin.c b/drivers/usb/musb/blackfin.c index fcb5206a65b..eeba228eb2a 100644 --- a/drivers/usb/musb/blackfin.c +++ b/drivers/usb/musb/blackfin.c @@ -15,12 +15,20 @@ #include <linux/list.h> #include <linux/gpio.h> #include <linux/io.h> +#include <linux/platform_device.h> +#include <linux/dma-mapping.h> #include <asm/cacheflush.h> #include "musb_core.h" #include "blackfin.h" +struct bfin_glue { + struct device *dev; + struct platform_device *musb; +}; +#define glue_to_musb(g) platform_get_drvdata(g->musb) + /* * Load an endpoint's FIFO */ @@ -278,7 +286,7 @@ static void musb_conn_timer_handler(unsigned long _musb) DBG(4, "state is %s\n", otg_state_string(musb)); } -void musb_platform_enable(struct musb *musb) +static void bfin_musb_enable(struct musb *musb) { if (!is_otg_enabled(musb) && is_host_enabled(musb)) { mod_timer(&musb_conn_timer, jiffies + TIMER_DELAY); @@ -286,11 +294,11 @@ void musb_platform_enable(struct musb *musb) } } -void musb_platform_disable(struct musb *musb) +static void bfin_musb_disable(struct musb *musb) { } -static void bfin_set_vbus(struct musb *musb, int is_on) +static void bfin_musb_set_vbus(struct musb *musb, int is_on) { int value = musb->config->gpio_vrsel_active; if (!is_on) @@ -303,28 +311,28 @@ static void bfin_set_vbus(struct musb *musb, int is_on) musb_readb(musb->mregs, MUSB_DEVCTL)); } -static int bfin_set_power(struct otg_transceiver *x, unsigned mA) +static int bfin_musb_set_power(struct otg_transceiver *x, unsigned mA) { return 0; } -void musb_platform_try_idle(struct musb *musb, unsigned long timeout) +static void bfin_musb_try_idle(struct musb *musb, unsigned long timeout) { if (!is_otg_enabled(musb) && is_host_enabled(musb)) mod_timer(&musb_conn_timer, jiffies + TIMER_DELAY); } -int musb_platform_get_vbus_status(struct musb *musb) +static int bfin_musb_get_vbus_status(struct musb *musb) { return 0; } -int musb_platform_set_mode(struct musb *musb, u8 musb_mode) +static int bfin_musb_set_mode(struct musb *musb, u8 musb_mode) { return -EIO; } -static void musb_platform_reg_init(struct musb *musb) +static void bfin_musb_reg_init(struct musb *musb) { if (ANOMALY_05000346) { bfin_write_USB_APHY_CALIB(ANOMALY_05000346_value); @@ -362,7 +370,7 @@ static void musb_platform_reg_init(struct musb *musb) SSYNC(); } -int __init musb_platform_init(struct musb *musb, void *board_data) +static int bfin_musb_init(struct musb *musb) { /* @@ -386,25 +394,124 @@ int __init musb_platform_init(struct musb *musb, void *board_data) return -ENODEV; } - musb_platform_reg_init(musb); + bfin_musb_reg_init(musb); if (is_host_enabled(musb)) { - musb->board_set_vbus = bfin_set_vbus; setup_timer(&musb_conn_timer, musb_conn_timer_handler, (unsigned long) musb); } if (is_peripheral_enabled(musb)) - musb->xceiv->set_power = bfin_set_power; + musb->xceiv->set_power = bfin_musb_set_power; musb->isr = blackfin_interrupt; return 0; } +static int bfin_musb_exit(struct musb *musb) +{ + gpio_free(musb->config->gpio_vrsel); + + otg_put_transceiver(musb->xceiv); + usb_nop_xceiv_unregister(); + return 0; +} + +static const struct musb_platform_ops bfin_ops = { + .init = bfin_musb_init, + .exit = bfin_musb_exit, + + .enable = bfin_musb_enable, + .disable = bfin_musb_disable, + + .set_mode = bfin_musb_set_mode, + .try_idle = bfin_musb_try_idle, + + .vbus_status = bfin_musb_vbus_status, + .set_vbus = bfin_musb_set_vbus, +}; + +static u64 bfin_dmamask = DMA_BIT_MASK(32); + +static int __init bfin_probe(struct platform_device *pdev) +{ + struct musb_hdrc_platform_data *pdata = pdev->dev.platform_data; + struct platform_device *musb; + struct bfin_glue *glue; + + int ret = -ENOMEM; + + glue = kzalloc(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); + if (!musb) { + dev_err(&pdev->dev, "failed to allocate musb device\n"); + goto err1; + } + + musb->dev.parent = &pdev->dev; + musb->dev.dma_mask = &bfin_dmamask; + musb->dev.coherent_dma_mask = bfin_dmamask; + + glue->dev = &pdev->dev; + glue->musb = musb; + + pdata->platform_ops = &bfin_ops; + + platform_set_drvdata(pdev, glue); + + ret = platform_device_add_resources(musb, pdev->resource, + pdev->num_resources); + if (ret) { + dev_err(&pdev->dev, "failed to add resources\n"); + goto err2; + } + + ret = platform_device_add_data(musb, pdata, sizeof(*pdata)); + if (ret) { + dev_err(&pdev->dev, "failed to add platform_data\n"); + goto err2; + } + + ret = platform_device_add(musb); + if (ret) { + dev_err(&pdev->dev, "failed to register musb device\n"); + goto err2; + } + + return 0; + +err2: + platform_device_put(musb); + +err1: + kfree(glue); + +err0: + return ret; +} + +static int __exit bfin_remove(struct platform_device *pdev) +{ + struct bfin_glue *glue = platform_get_drvdata(pdev); + + platform_device_del(glue->musb); + platform_device_put(glue->musb); + kfree(glue); + + return 0; +} + #ifdef CONFIG_PM -void musb_platform_save_context(struct musb *musb, - struct musb_context_registers *musb_context) +static int bfin_suspend(struct device *dev) { + struct bfin_glue *glue = dev_get_drvdata(dev); + struct musb *musb = glue_to_musb(glue); + if (is_host_active(musb)) /* * During hibernate gpio_vrsel will change from high to low @@ -413,20 +520,50 @@ void musb_platform_save_context(struct musb *musb, * wakeup event. */ gpio_set_value(musb->config->gpio_vrsel, 0); + + return 0; } -void musb_platform_restore_context(struct musb *musb, - struct musb_context_registers *musb_context) +static int bfin_resume(struct device *dev) { - musb_platform_reg_init(musb); + struct bfin_glue *glue = dev_get_drvdata(dev); + struct musb *musb = glue_to_musb(glue); + + bfin_musb_reg_init(musb); + + return 0; } + +static struct dev_pm_ops bfin_pm_ops = { + .suspend = bfin_suspend, + .resume = bfin_resume, +}; + +#define DEV_PM_OPS &bfin_pm_op, +#else +#define DEV_PM_OPS NULL #endif -int musb_platform_exit(struct musb *musb) +static struct platform_driver bfin_driver = { + .remove = __exit_p(bfin_remove), + .driver = { + .name = "musb-bfin", + .pm = DEV_PM_OPS, + }, +}; + +MODULE_DESCRIPTION("Blackfin MUSB Glue Layer"); +MODULE_AUTHOR("Bryan Wy <cooloney@kernel.org>"); +MODULE_LICENSE("GPL v2"); + +static int __init bfin_init(void) { - gpio_free(musb->config->gpio_vrsel); + return platform_driver_probe(&bfin_driver, bfin_probe); +} +subsys_initcall(bfin_init); - otg_put_transceiver(musb->xceiv); - usb_nop_xceiv_unregister(); - return 0; +static void __exit bfin_exit(void) +{ + platform_driver_unregister(&bfin_driver); } +module_exit(bfin_exit); |