aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/phy/phy-sun4i-usb.c
diff options
context:
space:
mode:
authorMaxime Ripard <maxime.ripard@free-electrons.com>2014-05-13 11:44:18 -0400
committerKishon Vijay Abraham I <kishon@ti.com>2014-05-14 10:11:13 -0400
commiteadd43123933e8c0a55245c51de68668e620e27f (patch)
tree96d17ccd42a34af285e96ca2c414266be81409c3 /drivers/phy/phy-sun4i-usb.c
parentfecc2d785ba99ce219f5c10d3b416dc9e74516b1 (diff)
phy: usb: sunxi: Introduce Allwinner A31 USB PHY support
The USB phy controller in the A31 differs mostly from the older controllers because it has a clock dedicated for each phy, while the older ones were having a single clock for all the phys. Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com> Reviewed-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.c33
1 files changed, 22 insertions, 11 deletions
diff --git a/drivers/phy/phy-sun4i-usb.c b/drivers/phy/phy-sun4i-usb.c
index 66a87d50512b..115d8d5190d5 100644
--- a/drivers/phy/phy-sun4i-usb.c
+++ b/drivers/phy/phy-sun4i-usb.c
@@ -61,7 +61,6 @@
61#define MAX_PHYS 3 61#define MAX_PHYS 3
62 62
63struct sun4i_usb_phy_data { 63struct sun4i_usb_phy_data {
64 struct clk *clk;
65 void __iomem *base; 64 void __iomem *base;
66 struct mutex mutex; 65 struct mutex mutex;
67 int num_phys; 66 int num_phys;
@@ -71,6 +70,7 @@ struct sun4i_usb_phy_data {
71 void __iomem *pmu; 70 void __iomem *pmu;
72 struct regulator *vbus; 71 struct regulator *vbus;
73 struct reset_control *reset; 72 struct reset_control *reset;
73 struct clk *clk;
74 int index; 74 int index;
75 } phys[MAX_PHYS]; 75 } phys[MAX_PHYS];
76}; 76};
@@ -146,13 +146,13 @@ static int sun4i_usb_phy_init(struct phy *_phy)
146 struct sun4i_usb_phy_data *data = to_sun4i_usb_phy_data(phy); 146 struct sun4i_usb_phy_data *data = to_sun4i_usb_phy_data(phy);
147 int ret; 147 int ret;
148 148
149 ret = clk_prepare_enable(data->clk); 149 ret = clk_prepare_enable(phy->clk);
150 if (ret) 150 if (ret)
151 return ret; 151 return ret;
152 152
153 ret = reset_control_deassert(phy->reset); 153 ret = reset_control_deassert(phy->reset);
154 if (ret) { 154 if (ret) {
155 clk_disable_unprepare(data->clk); 155 clk_disable_unprepare(phy->clk);
156 return ret; 156 return ret;
157 } 157 }
158 158
@@ -170,11 +170,10 @@ static int sun4i_usb_phy_init(struct phy *_phy)
170static int sun4i_usb_phy_exit(struct phy *_phy) 170static int sun4i_usb_phy_exit(struct phy *_phy)
171{ 171{
172 struct sun4i_usb_phy *phy = phy_get_drvdata(_phy); 172 struct sun4i_usb_phy *phy = phy_get_drvdata(_phy);
173 struct sun4i_usb_phy_data *data = to_sun4i_usb_phy_data(phy);
174 173
175 sun4i_usb_phy_passby(phy, 0); 174 sun4i_usb_phy_passby(phy, 0);
176 reset_control_assert(phy->reset); 175 reset_control_assert(phy->reset);
177 clk_disable_unprepare(data->clk); 176 clk_disable_unprepare(phy->clk);
178 177
179 return 0; 178 return 0;
180} 179}
@@ -225,6 +224,7 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev)
225 struct device *dev = &pdev->dev; 224 struct device *dev = &pdev->dev;
226 struct device_node *np = dev->of_node; 225 struct device_node *np = dev->of_node;
227 struct phy_provider *phy_provider; 226 struct phy_provider *phy_provider;
227 bool dedicated_clocks;
228 struct resource *res; 228 struct resource *res;
229 int i; 229 int i;
230 230
@@ -244,17 +244,16 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev)
244 else 244 else
245 data->disc_thresh = 2; 245 data->disc_thresh = 2;
246 246
247 if (of_device_is_compatible(np, "allwinner,sun6i-a31-usb-phy"))
248 dedicated_clocks = true;
249 else
250 dedicated_clocks = false;
251
247 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phy_ctrl"); 252 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phy_ctrl");
248 data->base = devm_ioremap_resource(dev, res); 253 data->base = devm_ioremap_resource(dev, res);
249 if (IS_ERR(data->base)) 254 if (IS_ERR(data->base))
250 return PTR_ERR(data->base); 255 return PTR_ERR(data->base);
251 256
252 data->clk = devm_clk_get(dev, "usb_phy");
253 if (IS_ERR(data->clk)) {
254 dev_err(dev, "could not get usb_phy clock\n");
255 return PTR_ERR(data->clk);
256 }
257
258 /* Skip 0, 0 is the phy for otg which is not yet supported. */ 257 /* Skip 0, 0 is the phy for otg which is not yet supported. */
259 for (i = 1; i < data->num_phys; i++) { 258 for (i = 1; i < data->num_phys; i++) {
260 struct sun4i_usb_phy *phy = data->phys + i; 259 struct sun4i_usb_phy *phy = data->phys + i;
@@ -268,6 +267,17 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev)
268 phy->vbus = NULL; 267 phy->vbus = NULL;
269 } 268 }
270 269
270 if (dedicated_clocks)
271 snprintf(name, sizeof(name), "usb%d_phy", i);
272 else
273 strlcpy(name, "usb_phy", sizeof(name));
274
275 phy->clk = devm_clk_get(dev, name);
276 if (IS_ERR(phy->clk)) {
277 dev_err(dev, "failed to get clock %s\n", name);
278 return PTR_ERR(phy->clk);
279 }
280
271 snprintf(name, sizeof(name), "usb%d_reset", i); 281 snprintf(name, sizeof(name), "usb%d_reset", i);
272 phy->reset = devm_reset_control_get(dev, name); 282 phy->reset = devm_reset_control_get(dev, name);
273 if (IS_ERR(phy->reset)) { 283 if (IS_ERR(phy->reset)) {
@@ -305,6 +315,7 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev)
305static const struct of_device_id sun4i_usb_phy_of_match[] = { 315static const struct of_device_id sun4i_usb_phy_of_match[] = {
306 { .compatible = "allwinner,sun4i-a10-usb-phy" }, 316 { .compatible = "allwinner,sun4i-a10-usb-phy" },
307 { .compatible = "allwinner,sun5i-a13-usb-phy" }, 317 { .compatible = "allwinner,sun5i-a13-usb-phy" },
318 { .compatible = "allwinner,sun6i-a31-usb-phy" },
308 { .compatible = "allwinner,sun7i-a20-usb-phy" }, 319 { .compatible = "allwinner,sun7i-a20-usb-phy" },
309 { }, 320 { },
310}; 321};