|
@@ -30,13 +30,11 @@
|
|
|
#include <linux/clk.h>
|
|
|
#include <linux/err.h>
|
|
|
#include <linux/io.h>
|
|
|
+#include <linux/phy/phy.h>
|
|
|
#include <linux/platform_device.h>
|
|
|
#include <linux/dma-mapping.h>
|
|
|
#include <linux/usb/usb_phy_generic.h>
|
|
|
|
|
|
-#include <mach/da8xx.h>
|
|
|
-#include <linux/platform_data/usb-davinci.h>
|
|
|
-
|
|
|
#include "musb_core.h"
|
|
|
|
|
|
/*
|
|
@@ -80,60 +78,14 @@
|
|
|
|
|
|
#define DA8XX_MENTOR_CORE_OFFSET 0x400
|
|
|
|
|
|
-#define CFGCHIP2 IO_ADDRESS(DA8XX_SYSCFG0_BASE + DA8XX_CFGCHIP2_REG)
|
|
|
-
|
|
|
struct da8xx_glue {
|
|
|
struct device *dev;
|
|
|
struct platform_device *musb;
|
|
|
- struct platform_device *phy;
|
|
|
+ struct platform_device *usb_phy;
|
|
|
struct clk *clk;
|
|
|
+ struct phy *phy;
|
|
|
};
|
|
|
|
|
|
-/*
|
|
|
- * REVISIT (PM): we should be able to keep the PHY in low power mode most
|
|
|
- * of the time (24 MHz oscillator and PLL off, etc.) by setting POWER.D0
|
|
|
- * and, when in host mode, autosuspending idle root ports... PHY_PLLON
|
|
|
- * (overriding SUSPENDM?) then likely needs to stay off.
|
|
|
- */
|
|
|
-
|
|
|
-static inline void phy_on(void)
|
|
|
-{
|
|
|
- u32 cfgchip2 = __raw_readl(CFGCHIP2);
|
|
|
-
|
|
|
- /*
|
|
|
- * Start the on-chip PHY and its PLL.
|
|
|
- */
|
|
|
- cfgchip2 &= ~(CFGCHIP2_RESET | CFGCHIP2_PHYPWRDN | CFGCHIP2_OTGPWRDN);
|
|
|
- cfgchip2 |= CFGCHIP2_PHY_PLLON;
|
|
|
- __raw_writel(cfgchip2, CFGCHIP2);
|
|
|
-
|
|
|
- pr_info("Waiting for USB PHY clock good...\n");
|
|
|
- while (!(__raw_readl(CFGCHIP2) & CFGCHIP2_PHYCLKGD))
|
|
|
- cpu_relax();
|
|
|
-}
|
|
|
-
|
|
|
-static inline void phy_off(void)
|
|
|
-{
|
|
|
- u32 cfgchip2 = __raw_readl(CFGCHIP2);
|
|
|
-
|
|
|
- /*
|
|
|
- * Ensure that USB 1.1 reference clock is not being sourced from
|
|
|
- * USB 2.0 PHY. Otherwise do not power down the PHY.
|
|
|
- */
|
|
|
- if (!(cfgchip2 & CFGCHIP2_USB1PHYCLKMUX) &&
|
|
|
- (cfgchip2 & CFGCHIP2_USB1SUSPENDM)) {
|
|
|
- pr_warning("USB 1.1 clocked from USB 2.0 PHY -- "
|
|
|
- "can't power it down\n");
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- /*
|
|
|
- * Power down the on-chip PHY.
|
|
|
- */
|
|
|
- cfgchip2 |= CFGCHIP2_PHYPWRDN | CFGCHIP2_OTGPWRDN;
|
|
|
- __raw_writel(cfgchip2, CFGCHIP2);
|
|
|
-}
|
|
|
-
|
|
|
/*
|
|
|
* Because we don't set CTRL.UINT, it's "important" to:
|
|
|
* - not read/write INTRUSB/INTRUSBE (except during
|
|
@@ -385,29 +337,29 @@ static irqreturn_t da8xx_musb_interrupt(int irq, void *hci)
|
|
|
|
|
|
static int da8xx_musb_set_mode(struct musb *musb, u8 musb_mode)
|
|
|
{
|
|
|
- u32 cfgchip2 = __raw_readl(CFGCHIP2);
|
|
|
+ struct da8xx_glue *glue = dev_get_drvdata(musb->controller->parent);
|
|
|
+ enum phy_mode phy_mode;
|
|
|
|
|
|
- cfgchip2 &= ~CFGCHIP2_OTGMODE;
|
|
|
switch (musb_mode) {
|
|
|
case MUSB_HOST: /* Force VBUS valid, ID = 0 */
|
|
|
- cfgchip2 |= CFGCHIP2_FORCE_HOST;
|
|
|
+ phy_mode = PHY_MODE_USB_HOST;
|
|
|
break;
|
|
|
case MUSB_PERIPHERAL: /* Force VBUS valid, ID = 1 */
|
|
|
- cfgchip2 |= CFGCHIP2_FORCE_DEVICE;
|
|
|
+ phy_mode = PHY_MODE_USB_DEVICE;
|
|
|
break;
|
|
|
case MUSB_OTG: /* Don't override the VBUS/ID comparators */
|
|
|
- cfgchip2 |= CFGCHIP2_NO_OVERRIDE;
|
|
|
+ phy_mode = PHY_MODE_USB_OTG;
|
|
|
break;
|
|
|
default:
|
|
|
- dev_dbg(musb->controller, "Trying to set unsupported mode %u\n", musb_mode);
|
|
|
+ return -EINVAL;
|
|
|
}
|
|
|
|
|
|
- __raw_writel(cfgchip2, CFGCHIP2);
|
|
|
- return 0;
|
|
|
+ return phy_set_mode(glue->phy, phy_mode);
|
|
|
}
|
|
|
|
|
|
static int da8xx_musb_init(struct musb *musb)
|
|
|
{
|
|
|
+ struct da8xx_glue *glue = dev_get_drvdata(musb->controller->parent);
|
|
|
void __iomem *reg_base = musb->ctrl_base;
|
|
|
u32 rev;
|
|
|
int ret = -ENODEV;
|
|
@@ -425,32 +377,56 @@ 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 */
|
|
|
musb_writel(reg_base, DA8XX_USB_CTRL_REG, DA8XX_SOFT_RESET_MASK);
|
|
|
|
|
|
/* Start the on-chip PHY and its PLL. */
|
|
|
- phy_on();
|
|
|
+ ret = phy_init(glue->phy);
|
|
|
+ if (ret) {
|
|
|
+ dev_err(glue->dev, "Failed to init phy.\n");
|
|
|
+ goto err_phy_init;
|
|
|
+ }
|
|
|
+
|
|
|
+ ret = phy_power_on(glue->phy);
|
|
|
+ if (ret) {
|
|
|
+ dev_err(glue->dev, "Failed to power on phy.\n");
|
|
|
+ goto err_phy_power_on;
|
|
|
+ }
|
|
|
|
|
|
msleep(5);
|
|
|
|
|
|
/* NOTE: IRQs are in mixed mode, not bypass to pure MUSB */
|
|
|
- pr_debug("DA8xx OTG revision %08x, PHY %03x, control %02x\n",
|
|
|
- rev, __raw_readl(CFGCHIP2),
|
|
|
+ pr_debug("DA8xx OTG revision %08x, control %02x\n", rev,
|
|
|
musb_readb(reg_base, DA8XX_USB_CTRL_REG));
|
|
|
|
|
|
musb->isr = da8xx_musb_interrupt;
|
|
|
return 0;
|
|
|
+
|
|
|
+err_phy_power_on:
|
|
|
+ phy_exit(glue->phy);
|
|
|
+err_phy_init:
|
|
|
+ clk_disable_unprepare(glue->clk);
|
|
|
fail:
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
static int da8xx_musb_exit(struct musb *musb)
|
|
|
{
|
|
|
+ struct da8xx_glue *glue = dev_get_drvdata(musb->controller->parent);
|
|
|
+
|
|
|
del_timer_sync(&otg_workaround);
|
|
|
|
|
|
- phy_off();
|
|
|
+ phy_power_off(glue->phy);
|
|
|
+ phy_exit(glue->phy);
|
|
|
+ clk_disable_unprepare(glue->clk);
|
|
|
|
|
|
usb_put_phy(musb->xceiv);
|
|
|
|
|
@@ -502,10 +478,10 @@ static int da8xx_probe(struct platform_device *pdev)
|
|
|
return PTR_ERR(clk);
|
|
|
}
|
|
|
|
|
|
- ret = clk_enable(clk);
|
|
|
- if (ret) {
|
|
|
- dev_err(&pdev->dev, "failed to enable clock\n");
|
|
|
- goto err4;
|
|
|
+ glue->phy = devm_phy_get(&pdev->dev, "usb-phy");
|
|
|
+ if (IS_ERR(glue->phy)) {
|
|
|
+ dev_err(&pdev->dev, "failed to get phy\n");
|
|
|
+ return PTR_ERR(glue->phy);
|
|
|
}
|
|
|
|
|
|
glue->dev = &pdev->dev;
|
|
@@ -513,10 +489,10 @@ static int da8xx_probe(struct platform_device *pdev)
|
|
|
|
|
|
pdata->platform_ops = &da8xx_ops;
|
|
|
|
|
|
- glue->phy = usb_phy_generic_register();
|
|
|
- if (IS_ERR(glue->phy)) {
|
|
|
- ret = PTR_ERR(glue->phy);
|
|
|
- goto err5;
|
|
|
+ glue->usb_phy = usb_phy_generic_register();
|
|
|
+ if (IS_ERR(glue->usb_phy)) {
|
|
|
+ dev_err(&pdev->dev, "failed to register usb_phy\n");
|
|
|
+ return PTR_ERR(glue->usb_phy);
|
|
|
}
|
|
|
platform_set_drvdata(pdev, glue);
|
|
|
|
|
@@ -542,22 +518,12 @@ static int da8xx_probe(struct platform_device *pdev)
|
|
|
|
|
|
glue->musb = musb = platform_device_register_full(&pinfo);
|
|
|
if (IS_ERR(musb)) {
|
|
|
- ret = PTR_ERR(musb);
|
|
|
dev_err(&pdev->dev, "failed to register musb device: %d\n", ret);
|
|
|
- goto err6;
|
|
|
+ usb_phy_generic_unregister(glue->usb_phy);
|
|
|
+ return PTR_ERR(musb);
|
|
|
}
|
|
|
|
|
|
return 0;
|
|
|
-
|
|
|
-err6:
|
|
|
- usb_phy_generic_unregister(glue->phy);
|
|
|
-
|
|
|
-err5:
|
|
|
- clk_disable(clk);
|
|
|
-
|
|
|
-err4:
|
|
|
-
|
|
|
- return ret;
|
|
|
}
|
|
|
|
|
|
static int da8xx_remove(struct platform_device *pdev)
|
|
@@ -565,8 +531,7 @@ static int da8xx_remove(struct platform_device *pdev)
|
|
|
struct da8xx_glue *glue = platform_get_drvdata(pdev);
|
|
|
|
|
|
platform_device_unregister(glue->musb);
|
|
|
- usb_phy_generic_unregister(glue->phy);
|
|
|
- clk_disable(glue->clk);
|
|
|
+ usb_phy_generic_unregister(glue->usb_phy);
|
|
|
|
|
|
return 0;
|
|
|
}
|