diff options
author | Hans de Goede <hdegoede@redhat.com> | 2015-06-13 08:37:49 -0400 |
---|---|---|
committer | Kishon Vijay Abraham I <kishon@ti.com> | 2015-07-25 06:15:47 -0400 |
commit | fc1f45ed3043da3aa901e88a9ef0995bbd320698 (patch) | |
tree | d51776ff56eb12fc06e27b6a131c9f8cf0ea55a9 /drivers/phy/phy-sun4i-usb.c | |
parent | 123dfdbcfaf5eb8753cd6293ab50c41e9b8e9ebf (diff) |
phy-sun4i-usb: Add support for the usb-phys on the sun8i-a33 SoC
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>
Diffstat (limited to 'drivers/phy/phy-sun4i-usb.c')
-rw-r--r-- | drivers/phy/phy-sun4i-usb.c | 39 |
1 files changed, 28 insertions, 11 deletions
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 | }; |
596 | MODULE_DEVICE_TABLE(of, sun4i_usb_phy_of_match); | 613 | MODULE_DEVICE_TABLE(of, sun4i_usb_phy_of_match); |