phy-sun4i-usb: Add support for the usb-phys on the sun8i-a33 SoC
authorHans de Goede <hdegoede@redhat.com>
Sat, 13 Jun 2015 12:37:49 +0000 (14:37 +0200)
committerKishon Vijay Abraham I <kishon@ti.com>
Sat, 25 Jul 2015 10:15:47 +0000 (15:45 +0530)
The usb-phys on the sun8i-a33 SoC are mostly the same as sun8i-a23 but for
some reason (hw bug?) the phyctl register was moved to a different address
and is not initialized to 0 on reset.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt
drivers/phy/phy-sun4i-usb.c

index f0c640adee64fbfa80d957f114921628fbb18555..5f48979b4edc0037764bc6114b996ed42a2779c0 100644 (file)
@@ -8,6 +8,7 @@ Required properties:
   * allwinner,sun6i-a31-usb-phy
   * allwinner,sun7i-a20-usb-phy
   * allwinner,sun8i-a23-usb-phy
+  * allwinner,sun8i-a33-usb-phy
 - reg : a list of offset + length pairs
 - reg-names :
   * "phy_ctrl"
index 00424dde79c120d8c9b01f1e9553d35319198680..ddc399536c5c2bc0d5ca24c0506f0238478146f8 100644 (file)
 #include <linux/workqueue.h>
 
 #define REG_ISCR                       0x00
-#define REG_PHYCTL                     0x04
+#define REG_PHYCTL_A10                 0x04
 #define REG_PHYBIST                    0x08
 #define REG_PHYTUNE                    0x0c
+#define REG_PHYCTL_A33                 0x10
 
 #define PHYCTL_DATA                    BIT(7)
 
@@ -90,6 +91,7 @@ struct sun4i_usb_phy_data {
        struct mutex mutex;
        int num_phys;
        u32 disc_thresh;
+       bool has_a33_phyctl;
        struct sun4i_usb_phy {
                struct phy *phy;
                void __iomem *pmu;
@@ -152,37 +154,46 @@ static void sun4i_usb_phy_write(struct sun4i_usb_phy *phy, u32 addr, u32 data,
 {
        struct sun4i_usb_phy_data *phy_data = to_sun4i_usb_phy_data(phy);
        u32 temp, usbc_bit = BIT(phy->index * 2);
+       void *phyctl;
        int i;
 
        mutex_lock(&phy_data->mutex);
 
+       if (phy_data->has_a33_phyctl) {
+               phyctl = phy_data->base + REG_PHYCTL_A33;
+               /* A33 needs us to set phyctl to 0 explicitly */
+               writel(0, phyctl);
+       } else {
+               phyctl = phy_data->base + REG_PHYCTL_A10;
+       }
+
        for (i = 0; i < len; i++) {
-               temp = readl(phy_data->base + REG_PHYCTL);
+               temp = readl(phyctl);
 
                /* clear the address portion */
                temp &= ~(0xff << 8);
 
                /* set the address */
                temp |= ((addr + i) << 8);
-               writel(temp, phy_data->base + REG_PHYCTL);
+               writel(temp, phyctl);
 
                /* set the data bit and clear usbc bit*/
-               temp = readb(phy_data->base + REG_PHYCTL);
+               temp = readb(phyctl);
                if (data & 0x1)
                        temp |= PHYCTL_DATA;
                else
                        temp &= ~PHYCTL_DATA;
                temp &= ~usbc_bit;
-               writeb(temp, phy_data->base + REG_PHYCTL);
+               writeb(temp, phyctl);
 
                /* pulse usbc_bit */
-               temp = readb(phy_data->base + REG_PHYCTL);
+               temp = readb(phyctl);
                temp |= usbc_bit;
-               writeb(temp, phy_data->base + REG_PHYCTL);
+               writeb(temp, phyctl);
 
-               temp = readb(phy_data->base + REG_PHYCTL);
+               temp = readb(phyctl);
                temp &= ~usbc_bit;
-               writeb(temp, phy_data->base + REG_PHYCTL);
+               writeb(temp, phyctl);
 
                data >>= 1;
        }
@@ -443,7 +454,8 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev)
        dev_set_drvdata(dev, data);
 
        if (of_device_is_compatible(np, "allwinner,sun5i-a13-usb-phy") ||
-           of_device_is_compatible(np, "allwinner,sun8i-a23-usb-phy"))
+           of_device_is_compatible(np, "allwinner,sun8i-a23-usb-phy") ||
+           of_device_is_compatible(np, "allwinner,sun8i-a33-usb-phy"))
                data->num_phys = 2;
        else
                data->num_phys = 3;
@@ -455,11 +467,15 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev)
                data->disc_thresh = 3;
 
        if (of_device_is_compatible(np, "allwinner,sun6i-a31-usb-phy") ||
-           of_device_is_compatible(np, "allwinner,sun8i-a23-usb-phy"))
+           of_device_is_compatible(np, "allwinner,sun8i-a23-usb-phy") ||
+           of_device_is_compatible(np, "allwinner,sun8i-a33-usb-phy"))
                dedicated_clocks = true;
        else
                dedicated_clocks = false;
 
+       if (of_device_is_compatible(np, "allwinner,sun8i-a33-usb-phy"))
+               data->has_a33_phyctl = true;
+
        res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phy_ctrl");
        data->base = devm_ioremap_resource(dev, res);
        if (IS_ERR(data->base))
@@ -591,6 +607,7 @@ static const struct of_device_id sun4i_usb_phy_of_match[] = {
        { .compatible = "allwinner,sun6i-a31-usb-phy" },
        { .compatible = "allwinner,sun7i-a20-usb-phy" },
        { .compatible = "allwinner,sun8i-a23-usb-phy" },
+       { .compatible = "allwinner,sun8i-a33-usb-phy" },
        { },
 };
 MODULE_DEVICE_TABLE(of, sun4i_usb_phy_of_match);