summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt1
-rw-r--r--drivers/phy/phy-sun4i-usb.c39
2 files changed, 29 insertions, 11 deletions
diff --git a/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt b/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt
index f0c640adee64..5f48979b4edc 100644
--- a/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt
+++ b/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt
@@ -8,6 +8,7 @@ Required properties:
8 * allwinner,sun6i-a31-usb-phy 8 * allwinner,sun6i-a31-usb-phy
9 * allwinner,sun7i-a20-usb-phy 9 * allwinner,sun7i-a20-usb-phy
10 * allwinner,sun8i-a23-usb-phy 10 * allwinner,sun8i-a23-usb-phy
11 * allwinner,sun8i-a33-usb-phy
11- reg : a list of offset + length pairs 12- reg : a list of offset + length pairs
12- reg-names : 13- reg-names :
13 * "phy_ctrl" 14 * "phy_ctrl"
diff --git a/drivers/phy/phy-sun4i-usb.c b/drivers/phy/phy-sun4i-usb.c
index 00424dde79c1..ddc399536c5c 100644
--- a/drivers/phy/phy-sun4i-usb.c
+++ b/drivers/phy/phy-sun4i-usb.c
@@ -40,9 +40,10 @@
40#include <linux/workqueue.h> 40#include <linux/workqueue.h>
41 41
42#define REG_ISCR 0x00 42#define REG_ISCR 0x00
43#define REG_PHYCTL 0x04 43#define REG_PHYCTL_A10 0x04
44#define REG_PHYBIST 0x08 44#define REG_PHYBIST 0x08
45#define REG_PHYTUNE 0x0c 45#define REG_PHYTUNE 0x0c
46#define REG_PHYCTL_A33 0x10
46 47
47#define PHYCTL_DATA BIT(7) 48#define PHYCTL_DATA BIT(7)
48 49
@@ -90,6 +91,7 @@ struct sun4i_usb_phy_data {
90 struct mutex mutex; 91 struct mutex mutex;
91 int num_phys; 92 int num_phys;
92 u32 disc_thresh; 93 u32 disc_thresh;
94 bool has_a33_phyctl;
93 struct sun4i_usb_phy { 95 struct sun4i_usb_phy {
94 struct phy *phy; 96 struct phy *phy;
95 void __iomem *pmu; 97 void __iomem *pmu;
@@ -152,37 +154,46 @@ static void sun4i_usb_phy_write(struct sun4i_usb_phy *phy, u32 addr, u32 data,
152{ 154{
153 struct sun4i_usb_phy_data *phy_data = to_sun4i_usb_phy_data(phy); 155 struct sun4i_usb_phy_data *phy_data = to_sun4i_usb_phy_data(phy);
154 u32 temp, usbc_bit = BIT(phy->index * 2); 156 u32 temp, usbc_bit = BIT(phy->index * 2);
157 void *phyctl;
155 int i; 158 int i;
156 159
157 mutex_lock(&phy_data->mutex); 160 mutex_lock(&phy_data->mutex);
158 161
162 if (phy_data->has_a33_phyctl) {
163 phyctl = phy_data->base + REG_PHYCTL_A33;
164 /* A33 needs us to set phyctl to 0 explicitly */
165 writel(0, phyctl);
166 } else {
167 phyctl = phy_data->base + REG_PHYCTL_A10;
168 }
169
159 for (i = 0; i < len; i++) { 170 for (i = 0; i < len; i++) {
160 temp = readl(phy_data->base + REG_PHYCTL); 171 temp = readl(phyctl);
161 172
162 /* clear the address portion */ 173 /* clear the address portion */
163 temp &= ~(0xff << 8); 174 temp &= ~(0xff << 8);
164 175
165 /* set the address */ 176 /* set the address */
166 temp |= ((addr + i) << 8); 177 temp |= ((addr + i) << 8);
167 writel(temp, phy_data->base + REG_PHYCTL); 178 writel(temp, phyctl);
168 179
169 /* set the data bit and clear usbc bit*/ 180 /* set the data bit and clear usbc bit*/
170 temp = readb(phy_data->base + REG_PHYCTL); 181 temp = readb(phyctl);
171 if (data & 0x1) 182 if (data & 0x1)
172 temp |= PHYCTL_DATA; 183 temp |= PHYCTL_DATA;
173 else 184 else
174 temp &= ~PHYCTL_DATA; 185 temp &= ~PHYCTL_DATA;
175 temp &= ~usbc_bit; 186 temp &= ~usbc_bit;
176 writeb(temp, phy_data->base + REG_PHYCTL); 187 writeb(temp, phyctl);
177 188
178 /* pulse usbc_bit */ 189 /* pulse usbc_bit */
179 temp = readb(phy_data->base + REG_PHYCTL); 190 temp = readb(phyctl);
180 temp |= usbc_bit; 191 temp |= usbc_bit;
181 writeb(temp, phy_data->base + REG_PHYCTL); 192 writeb(temp, phyctl);
182 193
183 temp = readb(phy_data->base + REG_PHYCTL); 194 temp = readb(phyctl);
184 temp &= ~usbc_bit; 195 temp &= ~usbc_bit;
185 writeb(temp, phy_data->base + REG_PHYCTL); 196 writeb(temp, phyctl);
186 197
187 data >>= 1; 198 data >>= 1;
188 } 199 }
@@ -443,7 +454,8 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev)
443 dev_set_drvdata(dev, data); 454 dev_set_drvdata(dev, data);
444 455
445 if (of_device_is_compatible(np, "allwinner,sun5i-a13-usb-phy") || 456 if (of_device_is_compatible(np, "allwinner,sun5i-a13-usb-phy") ||
446 of_device_is_compatible(np, "allwinner,sun8i-a23-usb-phy")) 457 of_device_is_compatible(np, "allwinner,sun8i-a23-usb-phy") ||
458 of_device_is_compatible(np, "allwinner,sun8i-a33-usb-phy"))
447 data->num_phys = 2; 459 data->num_phys = 2;
448 else 460 else
449 data->num_phys = 3; 461 data->num_phys = 3;
@@ -455,11 +467,15 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev)
455 data->disc_thresh = 3; 467 data->disc_thresh = 3;
456 468
457 if (of_device_is_compatible(np, "allwinner,sun6i-a31-usb-phy") || 469 if (of_device_is_compatible(np, "allwinner,sun6i-a31-usb-phy") ||
458 of_device_is_compatible(np, "allwinner,sun8i-a23-usb-phy")) 470 of_device_is_compatible(np, "allwinner,sun8i-a23-usb-phy") ||
471 of_device_is_compatible(np, "allwinner,sun8i-a33-usb-phy"))
459 dedicated_clocks = true; 472 dedicated_clocks = true;
460 else 473 else
461 dedicated_clocks = false; 474 dedicated_clocks = false;
462 475
476 if (of_device_is_compatible(np, "allwinner,sun8i-a33-usb-phy"))
477 data->has_a33_phyctl = true;
478
463 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phy_ctrl"); 479 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phy_ctrl");
464 data->base = devm_ioremap_resource(dev, res); 480 data->base = devm_ioremap_resource(dev, res);
465 if (IS_ERR(data->base)) 481 if (IS_ERR(data->base))
@@ -591,6 +607,7 @@ static const struct of_device_id sun4i_usb_phy_of_match[] = {
591 { .compatible = "allwinner,sun6i-a31-usb-phy" }, 607 { .compatible = "allwinner,sun6i-a31-usb-phy" },
592 { .compatible = "allwinner,sun7i-a20-usb-phy" }, 608 { .compatible = "allwinner,sun7i-a20-usb-phy" },
593 { .compatible = "allwinner,sun8i-a23-usb-phy" }, 609 { .compatible = "allwinner,sun8i-a23-usb-phy" },
610 { .compatible = "allwinner,sun8i-a33-usb-phy" },
594 { }, 611 { },
595}; 612};
596MODULE_DEVICE_TABLE(of, sun4i_usb_phy_of_match); 613MODULE_DEVICE_TABLE(of, sun4i_usb_phy_of_match);