diff options
Diffstat (limited to 'drivers/usb/musb/da8xx.c')
-rw-r--r-- | drivers/usb/musb/da8xx.c | 70 |
1 files changed, 61 insertions, 9 deletions
diff --git a/drivers/usb/musb/da8xx.c b/drivers/usb/musb/da8xx.c index 2440f88e07a3..e89708d839e5 100644 --- a/drivers/usb/musb/da8xx.c +++ b/drivers/usb/musb/da8xx.c @@ -6,6 +6,9 @@ * Based on the DaVinci "glue layer" code. * Copyright (C) 2005-2006 by Texas Instruments * + * DT support + * Copyright (c) 2016 Petr Kulhavy <petr@barix.com> + * * This file is part of the Inventra Controller Driver for Linux. * * The Inventra Controller Driver for Linux is free software; you @@ -340,6 +343,13 @@ static int da8xx_musb_set_mode(struct musb *musb, u8 musb_mode) struct da8xx_glue *glue = dev_get_drvdata(musb->controller->parent); enum phy_mode phy_mode; + /* + * The PHY has some issues when it is forced in device or host mode. + * Unless the user request another mode, configure the PHY in OTG mode. + */ + if (!musb->is_initialized) + return phy_set_mode(glue->phy, PHY_MODE_USB_OTG); + switch (musb_mode) { case MUSB_HOST: /* Force VBUS valid, ID = 0 */ phy_mode = PHY_MODE_USB_HOST; @@ -366,6 +376,12 @@ static int da8xx_musb_init(struct musb *musb) musb->mregs += DA8XX_MENTOR_CORE_OFFSET; + ret = clk_prepare_enable(glue->clk); + if (ret) { + dev_err(glue->dev, "failed to enable clock\n"); + return ret; + } + /* Returns zero if e.g. not clocked */ rev = musb_readl(reg_base, DA8XX_USB_REVISION_REG); if (!rev) @@ -377,12 +393,6 @@ static int da8xx_musb_init(struct musb *musb) goto fail; } - ret = clk_prepare_enable(glue->clk); - if (ret) { - dev_err(glue->dev, "failed to enable clock\n"); - goto fail; - } - setup_timer(&otg_workaround, otg_timer, (unsigned long)musb); /* Reset the controller */ @@ -392,7 +402,7 @@ static int da8xx_musb_init(struct musb *musb) ret = phy_init(glue->phy); if (ret) { dev_err(glue->dev, "Failed to init phy.\n"); - goto err_phy_init; + goto fail; } ret = phy_power_on(glue->phy); @@ -412,9 +422,8 @@ static int da8xx_musb_init(struct musb *musb) err_phy_power_on: phy_exit(glue->phy); -err_phy_init: - clk_disable_unprepare(glue->clk); fail: + clk_disable_unprepare(glue->clk); return ret; } @@ -433,6 +442,21 @@ static int da8xx_musb_exit(struct musb *musb) return 0; } +static inline u8 get_vbus_power(struct device *dev) +{ + struct regulator *vbus_supply; + int current_uA; + + vbus_supply = regulator_get_optional(dev, "vbus"); + if (IS_ERR(vbus_supply)) + return 255; + current_uA = regulator_get_current_limit(vbus_supply); + regulator_put(vbus_supply); + if (current_uA <= 0 || current_uA > 510000) + return 255; + return current_uA / 1000 / 2; +} + static const struct musb_platform_ops da8xx_ops = { .quirks = MUSB_DMA_CPPI | MUSB_INDEXED_EP, .init = da8xx_musb_init, @@ -458,6 +482,12 @@ static const struct platform_device_info da8xx_dev_info = { .dma_mask = DMA_BIT_MASK(32), }; +static const struct musb_hdrc_config da8xx_config = { + .ram_bits = 10, + .num_eps = 5, + .multipoint = 1, +}; + static int da8xx_probe(struct platform_device *pdev) { struct resource musb_resources[2]; @@ -465,6 +495,7 @@ static int da8xx_probe(struct platform_device *pdev) struct da8xx_glue *glue; struct platform_device_info pinfo; struct clk *clk; + struct device_node *np = pdev->dev.of_node; int ret; glue = devm_kzalloc(&pdev->dev, sizeof(*glue), GFP_KERNEL); @@ -487,6 +518,16 @@ static int da8xx_probe(struct platform_device *pdev) glue->dev = &pdev->dev; glue->clk = clk; + if (IS_ENABLED(CONFIG_OF) && np) { + pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return -ENOMEM; + + pdata->config = &da8xx_config; + pdata->mode = musb_get_mode(&pdev->dev); + pdata->power = get_vbus_power(&pdev->dev); + } + pdata->platform_ops = &da8xx_ops; glue->usb_phy = usb_phy_generic_register(); @@ -537,11 +578,22 @@ static int da8xx_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_OF +static const struct of_device_id da8xx_id_table[] = { + { + .compatible = "ti,da830-musb", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, da8xx_id_table); +#endif + static struct platform_driver da8xx_driver = { .probe = da8xx_probe, .remove = da8xx_remove, .driver = { .name = "musb-da8xx", + .of_match_table = of_match_ptr(da8xx_id_table), }, }; |