]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/usb/phy/phy-rcar-usb.c
cw1200: Fix spurious BUG_ON() trigger when starting AP mode.
[karo-tx-linux.git] / drivers / usb / phy / phy-rcar-usb.c
index 23c3dd30b2f0e654437ff415ab562ecb9c42510f..ae909408958dcb8a9b0efcc2866d19d0cff7571b 100644 (file)
@@ -1,8 +1,9 @@
 /*
  * Renesas R-Car USB phy driver
  *
- * Copyright (C) 2012 Renesas Solutions Corp.
+ * Copyright (C) 2012-2013 Renesas Solutions Corp.
  * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+ * Copyright (C) 2013 Cogent Embedded, Inc.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
 #include <linux/platform_device.h>
 #include <linux/spinlock.h>
 #include <linux/module.h>
-
-/* USBH common register */
-#define USBPCTRL0      0x0800
-#define USBPCTRL1      0x0804
-#define USBST          0x0808
-#define USBEH0         0x080C
-#define USBOH0         0x081C
-#define USBCTL0                0x0858
-#define EIIBC1         0x0094
-#define EIIBC2         0x009C
-
+#include <linux/platform_data/usb-rcar-phy.h>
+
+/* REGS block */
+#define USBPCTRL0      0x00
+#define USBPCTRL1      0x04
+#define USBST          0x08
+#define USBEH0         0x0C
+#define USBOH0         0x1C
+#define USBCTL0                0x58
+
+/* High-speed signal quality characteristic control registers (R8A7778 only) */
+#define HSQCTL1                0x24
+#define HSQCTL2                0x28
+
+/* USBPCTRL0 */
+#define OVC2           (1 << 10) /* (R8A7779 only)                     */
+                               /* Switches the OVC input pin for port 2: */
+                               /* 1: USB_OVC2, 0: OVC2                 */
+#define OVC1_VBUS1     (1 << 9) /* Switches the OVC input pin for port 1: */
+                               /* 1: USB_OVC1, 0: OVC1/VBUS1           */
+                               /* Function mode: set to 0              */
+#define OVC0           (1 << 8) /* Switches the OVC input pin for port 0: */
+                               /* 1: USB_OVC0 pin, 0: OVC0             */
+#define OVC2_ACT       (1 << 6) /* (R8A7779 only)                      */
+                               /* Host mode: OVC2 polarity:            */
+                               /* 1: active-high, 0: active-low        */
+#define PENC           (1 << 4) /* Function mode: output level of PENC1 pin: */
+                               /* 1: high, 0: low                      */
+#define OVC0_ACT       (1 << 3) /* Host mode: OVC0 polarity:           */
+                               /* 1: active-high, 0: active-low        */
+#define OVC1_ACT       (1 << 1) /* Host mode: OVC1 polarity:           */
+                               /* 1: active-high, 0: active-low        */
+                               /* Function mode: be sure to set to 1   */
+#define PORT1          (1 << 0) /* Selects port 1 mode:                */
+                               /* 1: function, 0: host                 */
 /* USBPCTRL1 */
 #define PHY_RST                (1 << 2)
 #define PLL_ENB                (1 << 1)
@@ -58,8 +83,10 @@ static int rcar_usb_phy_init(struct usb_phy *phy)
 {
        struct rcar_usb_phy_priv *priv = usb_phy_to_priv(phy);
        struct device *dev = phy->dev;
+       struct rcar_phy_platform_data *pdata = dev->platform_data;
        void __iomem *reg0 = priv->reg0;
        void __iomem *reg1 = priv->reg1;
+       static const u8 ovcn_act[] = { OVC0_ACT, OVC1_ACT, OVC2_ACT };
        int i;
        u32 val;
        unsigned long flags;
@@ -77,7 +104,16 @@ static int rcar_usb_phy_init(struct usb_phy *phy)
                /* (2) start USB-PHY internal PLL */
                iowrite32(PHY_ENB | PLL_ENB, (reg0 + USBPCTRL1));
 
-               /* (3) USB module status check */
+               /* (3) set USB-PHY in accord with the conditions of usage */
+               if (reg1) {
+                       u32 hsqctl1 = pdata->ferrite_bead ? 0x41 : 0;
+                       u32 hsqctl2 = pdata->ferrite_bead ? 0x0d : 7;
+
+                       iowrite32(hsqctl1, reg1 + HSQCTL1);
+                       iowrite32(hsqctl2, reg1 + HSQCTL2);
+               }
+
+               /* (4) USB module status check */
                for (i = 0; i < 1024; i++) {
                        udelay(10);
                        val = ioread32(reg0 + USBST);
@@ -90,24 +126,24 @@ static int rcar_usb_phy_init(struct usb_phy *phy)
                        goto phy_init_end;
                }
 
-               /* (4) USB-PHY reset clear */
+               /* (5) USB-PHY reset clear */
                iowrite32(PHY_ENB | PLL_ENB | PHY_RST, (reg0 + USBPCTRL1));
 
-               /* set platform specific port settings */
-               iowrite32(0x00000000, (reg0 + USBPCTRL0));
-
-               /*
-                * EHCI IP internal buffer setting
-                * EHCI IP internal buffer enable
-                *
-                * These are recommended value of a datasheet
-                * see [USB :: EHCI internal buffer setting]
-                */
-               iowrite32(0x00ff0040, (reg0 + EIIBC1));
-               iowrite32(0x00ff0040, (reg1 + EIIBC1));
-
-               iowrite32(0x00000001, (reg0 + EIIBC2));
-               iowrite32(0x00000001, (reg1 + EIIBC2));
+               /* Board specific port settings */
+               val = 0;
+               if (pdata->port1_func)
+                       val |= PORT1;
+               if (pdata->penc1)
+                       val |= PENC;
+               for (i = 0; i < 3; i++) {
+                       /* OVCn bits follow each other in the right order */
+                       if (pdata->ovc_pin[i].select_3_3v)
+                               val |= OVC0 << i;
+                       /* OVCn_ACT bits are spaced by irregular intervals */
+                       if (pdata->ovc_pin[i].active_high)
+                               val |= ovcn_act[i];
+               }
+               iowrite32(val, (reg0 + USBPCTRL0));
 
                /*
                 * Bus alignment settings
@@ -134,10 +170,8 @@ static void rcar_usb_phy_shutdown(struct usb_phy *phy)
 
        spin_lock_irqsave(&priv->lock, flags);
 
-       if (priv->counter-- == 1) { /* last user */
-               iowrite32(0x00000000, (reg0 + USBPCTRL0));
+       if (priv->counter-- == 1)       /* last user */
                iowrite32(0x00000000, (reg0 + USBPCTRL1));
-       }
 
        spin_unlock_irqrestore(&priv->lock, flags);
 }
@@ -147,27 +181,29 @@ static int rcar_usb_phy_probe(struct platform_device *pdev)
        struct rcar_usb_phy_priv *priv;
        struct resource *res0, *res1;
        struct device *dev = &pdev->dev;
-       void __iomem *reg0, *reg1;
+       void __iomem *reg0, *reg1 = NULL;
        int ret;
 
+       if (!pdev->dev.platform_data) {
+               dev_err(dev, "No platform data\n");
+               return -EINVAL;
+       }
+
        res0 = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       res1 = platform_get_resource(pdev, IORESOURCE_MEM, 1);
-       if (!res0 || !res1) {
+       if (!res0) {
                dev_err(dev, "Not enough platform resources\n");
                return -EINVAL;
        }
 
-       /*
-        * CAUTION
-        *
-        * Because this phy address is also mapped under OHCI/EHCI address area,
-        * this driver can't use devm_ioremap_resource(dev, res) here
-        */
-       reg0 = devm_ioremap_nocache(dev, res0->start, resource_size(res0));
-       reg1 = devm_ioremap_nocache(dev, res1->start, resource_size(res1));
-       if (!reg0 || !reg1) {
-               dev_err(dev, "ioremap error\n");
-               return -ENOMEM;
+       reg0 = devm_ioremap_resource(dev, res0);
+       if (IS_ERR(reg0))
+               return PTR_ERR(reg0);
+
+       res1 = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+       if (res1) {
+               reg1 = devm_ioremap_resource(dev, res1);
+               if (IS_ERR(reg1))
+                       return PTR_ERR(reg1);
        }
 
        priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);