ath79: add new OF only target for QCA MIPS silicon
[openwrt/openwrt.git] / target / linux / ath79 / patches-4.14 / 0004-phy-add-ath79-usb-phys.patch
1 From 08c9d6ceef01893678a5d2e8a15517c745417f21 Mon Sep 17 00:00:00 2001
2 From: John Crispin <john@phrozen.org>
3 Date: Tue, 6 Mar 2018 10:04:05 +0100
4 Subject: [PATCH 04/27] phy: add ath79 usb phys
5
6 Signed-off-by: John Crispin <john@phrozen.org>
7 ---
8 drivers/phy/Kconfig | 16 ++++++
9 drivers/phy/Makefile | 2 +
10 drivers/phy/phy-ar7100-usb.c | 124 +++++++++++++++++++++++++++++++++++++++++++
11 drivers/phy/phy-ar7200-usb.c | 108 +++++++++++++++++++++++++++++++++++++
12 4 files changed, 250 insertions(+)
13 create mode 100644 drivers/phy/phy-ar7100-usb.c
14 create mode 100644 drivers/phy/phy-ar7200-usb.c
15
16 Index: linux-4.14.37/drivers/phy/Kconfig
17 ===================================================================
18 --- linux-4.14.37.orig/drivers/phy/Kconfig
19 +++ linux-4.14.37/drivers/phy/Kconfig
20 @@ -15,6 +15,22 @@ config GENERIC_PHY
21 phy users can obtain reference to the PHY. All the users of this
22 framework should select this config.
23
24 +config PHY_AR7100_USB
25 + tristate "Atheros AR7100 USB PHY driver"
26 + depends on ATH79 || COMPILE_TEST
27 + default y if USB_EHCI_HCD_PLATFORM
28 + select PHY_SIMPLE
29 + help
30 + Enable this to support the USB PHY on Atheros AR7100 SoCs.
31 +
32 +config PHY_AR7200_USB
33 + tristate "Atheros AR7200 USB PHY driver"
34 + depends on ATH79 || COMPILE_TEST
35 + default y if USB_EHCI_HCD_PLATFORM
36 + select PHY_SIMPLE
37 + help
38 + Enable this to support the USB PHY on Atheros AR7200 SoCs.
39 +
40 config PHY_LPC18XX_USB_OTG
41 tristate "NXP LPC18xx/43xx SoC USB OTG PHY driver"
42 depends on OF && (ARCH_LPC18XX || COMPILE_TEST)
43 Index: linux-4.14.37/drivers/phy/Makefile
44 ===================================================================
45 --- linux-4.14.37.orig/drivers/phy/Makefile
46 +++ linux-4.14.37/drivers/phy/Makefile
47 @@ -4,6 +4,8 @@
48 #
49
50 obj-$(CONFIG_GENERIC_PHY) += phy-core.o
51 +obj-$(CONFIG_PHY_AR7100_USB) += phy-ar7100-usb.o
52 +obj-$(CONFIG_PHY_AR7200_USB) += phy-ar7200-usb.o
53 obj-$(CONFIG_PHY_LPC18XX_USB_OTG) += phy-lpc18xx-usb-otg.o
54 obj-$(CONFIG_PHY_XGENE) += phy-xgene.o
55 obj-$(CONFIG_PHY_PISTACHIO_USB) += phy-pistachio-usb.o
56 Index: linux-4.14.37/drivers/phy/phy-ar7100-usb.c
57 ===================================================================
58 --- /dev/null
59 +++ linux-4.14.37/drivers/phy/phy-ar7100-usb.c
60 @@ -0,0 +1,140 @@
61 +/*
62 + * Copyright (C) 2018 John Crispin <john@phrozen.org>
63 + *
64 + * This program is free software; you can redistribute it and/or modify
65 + * it under the terms of the GNU General Public License as published by
66 + * the Free Software Foundation; either version 2 of the License, or
67 + * (at your option) any later version.
68 + */
69 +
70 +#include <linux/module.h>
71 +#include <linux/platform_device.h>
72 +#include <linux/phy/phy.h>
73 +#include <linux/delay.h>
74 +#include <linux/reset.h>
75 +#include <linux/of_gpio.h>
76 +
77 +#include <asm/mach-ath79/ath79.h>
78 +#include <asm/mach-ath79/ar71xx_regs.h>
79 +
80 +struct ar7100_usb_phy {
81 + struct reset_control *rst_phy;
82 + struct reset_control *rst_host;
83 + struct reset_control *rst_ohci_dll;
84 + void __iomem *io_base;
85 + struct phy *phy;
86 + int gpio;
87 +};
88 +
89 +static int ar7100_usb_phy_power_off(struct phy *phy)
90 +{
91 + struct ar7100_usb_phy *priv = phy_get_drvdata(phy);
92 + int err = 0;
93 +
94 + err |= reset_control_assert(priv->rst_host);
95 + err |= reset_control_assert(priv->rst_phy);
96 + err |= reset_control_assert(priv->rst_ohci_dll);
97 +
98 + return err;
99 +}
100 +
101 +static int ar7100_usb_phy_power_on(struct phy *phy)
102 +{
103 + struct ar7100_usb_phy *priv = phy_get_drvdata(phy);
104 + int err = 0;
105 +
106 + err |= ar7100_usb_phy_power_off(phy);
107 + mdelay(100);
108 + err |= reset_control_deassert(priv->rst_ohci_dll);
109 + err |= reset_control_deassert(priv->rst_phy);
110 + err |= reset_control_deassert(priv->rst_host);
111 + mdelay(500);
112 + iowrite32(0xf0000, priv->io_base + AR71XX_USB_CTRL_REG_CONFIG);
113 + iowrite32(0x20c00, priv->io_base + AR71XX_USB_CTRL_REG_FLADJ);
114 +
115 + return err;
116 +}
117 +
118 +static const struct phy_ops ar7100_usb_phy_ops = {
119 + .power_on = ar7100_usb_phy_power_on,
120 + .power_off = ar7100_usb_phy_power_off,
121 + .owner = THIS_MODULE,
122 +};
123 +
124 +static int ar7100_usb_phy_probe(struct platform_device *pdev)
125 +{
126 + struct phy_provider *phy_provider;
127 + struct resource *res;
128 + struct ar7100_usb_phy *priv;
129 +
130 + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
131 + if (!priv)
132 + return -ENOMEM;
133 +
134 + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
135 + priv->io_base = devm_ioremap_resource(&pdev->dev, res);
136 + if (IS_ERR(priv->io_base))
137 + return PTR_ERR(priv->io_base);
138 +
139 + priv->rst_phy = devm_reset_control_get(&pdev->dev, "usb-phy");
140 + if (IS_ERR(priv->rst_phy)) {
141 + dev_err(&pdev->dev, "phy reset is missing\n");
142 + return PTR_ERR(priv->rst_phy);
143 + }
144 +
145 + priv->rst_host = devm_reset_control_get(&pdev->dev, "usb-host");
146 + if (IS_ERR(priv->rst_host)) {
147 + dev_err(&pdev->dev, "host reset is missing\n");
148 + return PTR_ERR(priv->rst_host);
149 + }
150 +
151 + priv->rst_ohci_dll = devm_reset_control_get(&pdev->dev, "usb-ohci-dll");
152 + if (IS_ERR(priv->rst_ohci_dll)) {
153 + dev_err(&pdev->dev, "ohci-dll reset is missing\n");
154 + return PTR_ERR(priv->rst_host);
155 + }
156 +
157 + priv->phy = devm_phy_create(&pdev->dev, NULL, &ar7100_usb_phy_ops);
158 + if (IS_ERR(priv->phy)) {
159 + dev_err(&pdev->dev, "failed to create PHY\n");
160 + return PTR_ERR(priv->phy);
161 + }
162 +
163 + priv->gpio = of_get_gpio(pdev->dev.of_node, 0);
164 + if (priv->gpio >= 0) {
165 + int ret = devm_gpio_request(&pdev->dev, priv->gpio, dev_name(&pdev->dev));
166 +
167 + if (ret) {
168 + dev_err(&pdev->dev, "failed to request gpio\n");
169 + return ret;
170 + }
171 + gpio_export_with_name(priv->gpio, 0, dev_name(&pdev->dev));
172 + gpio_set_value(priv->gpio, 1);
173 + }
174 +
175 + phy_set_drvdata(priv->phy, priv);
176 +
177 + phy_provider = devm_of_phy_provider_register(&pdev->dev, of_phy_simple_xlate);
178 +
179 +
180 + return PTR_ERR_OR_ZERO(phy_provider);
181 +}
182 +
183 +static const struct of_device_id ar7100_usb_phy_of_match[] = {
184 + { .compatible = "qca,ar7100-usb-phy" },
185 + {}
186 +};
187 +MODULE_DEVICE_TABLE(of, ar7100_usb_phy_of_match);
188 +
189 +static struct platform_driver ar7100_usb_phy_driver = {
190 + .probe = ar7100_usb_phy_probe,
191 + .driver = {
192 + .of_match_table = ar7100_usb_phy_of_match,
193 + .name = "ar7100-usb-phy",
194 + }
195 +};
196 +module_platform_driver(ar7100_usb_phy_driver);
197 +
198 +MODULE_DESCRIPTION("ATH79 USB PHY driver");
199 +MODULE_AUTHOR("Alban Bedel <albeu@free.fr>");
200 +MODULE_LICENSE("GPL");
201 Index: linux-4.14.37/drivers/phy/phy-ar7200-usb.c
202 ===================================================================
203 --- /dev/null
204 +++ linux-4.14.37/drivers/phy/phy-ar7200-usb.c
205 @@ -0,0 +1,123 @@
206 +/*
207 + * Copyright (C) 2015 Alban Bedel <albeu@free.fr>
208 + *
209 + * This program is free software; you can redistribute it and/or modify
210 + * it under the terms of the GNU General Public License as published by
211 + * the Free Software Foundation; either version 2 of the License, or
212 + * (at your option) any later version.
213 + */
214 +
215 +#include <linux/module.h>
216 +#include <linux/platform_device.h>
217 +#include <linux/phy/phy.h>
218 +#include <linux/reset.h>
219 +#include <linux/of_gpio.h>
220 +
221 +struct ar7200_usb_phy {
222 + struct reset_control *rst_phy;
223 + struct reset_control *suspend_override;
224 + struct phy *phy;
225 + int gpio;
226 +};
227 +
228 +static int ar7200_usb_phy_power_on(struct phy *phy)
229 +{
230 + struct ar7200_usb_phy *priv = phy_get_drvdata(phy);
231 + int err = 0;
232 +
233 + if (priv->rst_phy)
234 + err = reset_control_deassert(priv->rst_phy);
235 + if (!err && priv->suspend_override)
236 + err = reset_control_assert(priv->suspend_override);
237 + if (err && priv->rst_phy)
238 + err = reset_control_assert(priv->rst_phy);
239 +
240 + return err;
241 +}
242 +
243 +static int ar7200_usb_phy_power_off(struct phy *phy)
244 +{
245 + struct ar7200_usb_phy *priv = phy_get_drvdata(phy);
246 + int err = 0;
247 +
248 + if (priv->suspend_override)
249 + err = reset_control_deassert(priv->suspend_override);
250 + if (priv->rst_phy)
251 + err |= reset_control_assert(priv->rst_phy);
252 +
253 + return err;
254 +}
255 +
256 +static const struct phy_ops ar7200_usb_phy_ops = {
257 + .power_on = ar7200_usb_phy_power_on,
258 + .power_off = ar7200_usb_phy_power_off,
259 + .owner = THIS_MODULE,
260 +};
261 +
262 +static int ar7200_usb_phy_probe(struct platform_device *pdev)
263 +{
264 + struct phy_provider *phy_provider;
265 + struct ar7200_usb_phy *priv;
266 +
267 + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
268 + if (!priv)
269 + return -ENOMEM;
270 +
271 + priv->rst_phy = devm_reset_control_get(&pdev->dev, "usb-phy");
272 + if (IS_ERR(priv->rst_phy)) {
273 + dev_err(&pdev->dev, "phy reset is missing\n");
274 + return PTR_ERR(priv->rst_phy);
275 + }
276 +
277 + priv->suspend_override = devm_reset_control_get_optional(
278 + &pdev->dev, "usb-suspend-override");
279 + if (IS_ERR(priv->suspend_override)) {
280 + if (PTR_ERR(priv->suspend_override) == -ENOENT)
281 + priv->suspend_override = NULL;
282 + else
283 + return PTR_ERR(priv->suspend_override);
284 + }
285 +
286 + priv->phy = devm_phy_create(&pdev->dev, NULL, &ar7200_usb_phy_ops);
287 + if (IS_ERR(priv->phy)) {
288 + dev_err(&pdev->dev, "failed to create PHY\n");
289 + return PTR_ERR(priv->phy);
290 + }
291 +
292 + priv->gpio = of_get_gpio(pdev->dev.of_node, 0);
293 + if (priv->gpio >= 0) {
294 + int ret = devm_gpio_request(&pdev->dev, priv->gpio, dev_name(&pdev->dev));
295 +
296 + if (ret) {
297 + dev_err(&pdev->dev, "failed to request gpio\n");
298 + return ret;
299 + }
300 + gpio_export_with_name(priv->gpio, 0, dev_name(&pdev->dev));
301 + gpio_set_value(priv->gpio, 1);
302 + }
303 +
304 + phy_set_drvdata(priv->phy, priv);
305 +
306 + phy_provider = devm_of_phy_provider_register(&pdev->dev, of_phy_simple_xlate);
307 +
308 + return PTR_ERR_OR_ZERO(phy_provider);
309 +}
310 +
311 +static const struct of_device_id ar7200_usb_phy_of_match[] = {
312 + { .compatible = "qca,ar7200-usb-phy" },
313 + {}
314 +};
315 +MODULE_DEVICE_TABLE(of, ar7200_usb_phy_of_match);
316 +
317 +static struct platform_driver ar7200_usb_phy_driver = {
318 + .probe = ar7200_usb_phy_probe,
319 + .driver = {
320 + .of_match_table = ar7200_usb_phy_of_match,
321 + .name = "ar7200-usb-phy",
322 + }
323 +};
324 +module_platform_driver(ar7200_usb_phy_driver);
325 +
326 +MODULE_DESCRIPTION("ATH79 USB PHY driver");
327 +MODULE_AUTHOR("Alban Bedel <albeu@free.fr>");
328 +MODULE_LICENSE("GPL");