diff options
author | Maxime Ripard <maxime.ripard@free-electrons.com> | 2014-05-13 11:44:18 -0400 |
---|---|---|
committer | Kishon Vijay Abraham I <kishon@ti.com> | 2014-05-14 10:11:13 -0400 |
commit | eadd43123933e8c0a55245c51de68668e620e27f (patch) | |
tree | 96d17ccd42a34af285e96ca2c414266be81409c3 /drivers/phy/phy-sun4i-usb.c | |
parent | fecc2d785ba99ce219f5c10d3b416dc9e74516b1 (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.c | 33 |
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 | ||
63 | struct sun4i_usb_phy_data { | 63 | struct 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) | |||
170 | static int sun4i_usb_phy_exit(struct phy *_phy) | 170 | static 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) | |||
305 | static const struct of_device_id sun4i_usb_phy_of_match[] = { | 315 | static 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 | }; |