uboot-fritz4040: add an ipq806x u-boot for FritzBox 4040
[openwrt/openwrt.git] / target / linux / ipq806x / patches-4.9 / 0023-qcom-ipq4019-Add-IPQ4019-USB-HS-SS-PHY-drivers.patch
1 From 04d3f9be0ce80fac99d4ca1f46faf3605258ca1f Mon Sep 17 00:00:00 2001
2 From: Senthilkumar N L <snlakshm@codeaurora.org>
3 Date: Tue, 6 Jan 2015 12:52:23 +0530
4 Subject: [PATCH 23/69] qcom: ipq4019: Add IPQ4019 USB HS/SS PHY drivers
5
6 These drivers handles control and configuration of the HS
7 and SS USB PHY transceivers.
8
9 Signed-off-by: Senthilkumar N L <snlakshm@codeaurora.org>
10 ---
11 drivers/usb/phy/Kconfig | 11 ++
12 drivers/usb/phy/Makefile | 2 +
13 drivers/usb/phy/phy-qca-baldur.c | 262 +++++++++++++++++++++++++++++++++++++++
14 drivers/usb/phy/phy-qca-uniphy.c | 171 +++++++++++++++++++++++++
15 4 files changed, 446 insertions(+)
16 create mode 100644 drivers/usb/phy/phy-qca-baldur.c
17 create mode 100644 drivers/usb/phy/phy-qca-uniphy.c
18
19 --- a/drivers/usb/phy/Kconfig
20 +++ b/drivers/usb/phy/Kconfig
21 @@ -194,6 +194,17 @@ config USB_MXS_PHY
22
23 MXS Phy is used by some of the i.MX SoCs, for example imx23/28/6x.
24
25 +config USB_IPQ4019_PHY
26 + tristate "IPQ4019 PHY wrappers support"
27 + depends on (USB || USB_GADGET) && ARCH_QCOM
28 + select USB_PHY
29 + help
30 + Enable this to support the USB PHY transceivers on QCA961x chips.
31 + It handles PHY initialization, clock management required after
32 + resetting the hardware and power management.
33 + This driver is required even for peripheral only or host only
34 + mode configurations.
35 +
36 config USB_ULPI
37 bool "Generic ULPI Transceiver Driver"
38 depends on ARM || ARM64
39 --- a/drivers/usb/phy/Makefile
40 +++ b/drivers/usb/phy/Makefile
41 @@ -21,6 +21,8 @@ obj-$(CONFIG_USB_GPIO_VBUS) += phy-gpio
42 obj-$(CONFIG_USB_ISP1301) += phy-isp1301.o
43 obj-$(CONFIG_USB_MSM_OTG) += phy-msm-usb.o
44 obj-$(CONFIG_USB_QCOM_8X16_PHY) += phy-qcom-8x16-usb.o
45 +obj-$(CONFIG_USB_IPQ4019_PHY) += phy-qca-baldur.o
46 +obj-$(CONFIG_USB_IPQ4019_PHY) += phy-qca-uniphy.o
47 obj-$(CONFIG_USB_MV_OTG) += phy-mv-usb.o
48 obj-$(CONFIG_USB_MXS_PHY) += phy-mxs-usb.o
49 obj-$(CONFIG_USB_ULPI) += phy-ulpi.o
50 --- /dev/null
51 +++ b/drivers/usb/phy/phy-qca-baldur.c
52 @@ -0,0 +1,262 @@
53 +/* Copyright (c) 2015, The Linux Foundation. All rights reserved.
54 + *
55 + * Permission to use, copy, modify, and/or distribute this software for any
56 + * purpose with or without fee is hereby granted, provided that the above
57 + * copyright notice and this permission notice appear in all copies.
58 + *
59 + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
60 + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
61 + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
62 + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
63 + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
64 + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
65 + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
66 + *
67 + */
68 +
69 +#include <linux/clk.h>
70 +#include <linux/err.h>
71 +#include <linux/io.h>
72 +#include <linux/module.h>
73 +#include <linux/of.h>
74 +#include <linux/platform_device.h>
75 +#include <linux/regulator/consumer.h>
76 +#include <linux/usb/phy.h>
77 +#include <linux/reset.h>
78 +#include <linux/of_device.h>
79 +
80 +/**
81 + * USB Hardware registers
82 + */
83 +#define PHY_CTRL0_ADDR 0x000
84 +#define PHY_CTRL1_ADDR 0x004
85 +#define PHY_CTRL2_ADDR 0x008
86 +#define PHY_CTRL3_ADDR 0x00C
87 +#define PHY_CTRL4_ADDR 0x010
88 +#define PHY_MISC_ADDR 0x024
89 +#define PHY_IPG_ADDR 0x030
90 +
91 +#define PHY_CTRL0_EMU_ADDR 0x180
92 +#define PHY_CTRL1_EMU_ADDR 0x184
93 +#define PHY_CTRL2_EMU_ADDR 0x188
94 +#define PHY_CTRL3_EMU_ADDR 0x18C
95 +#define PHY_CTRL4_EMU_ADDR 0x190
96 +#define PHY_MISC_EMU_ADDR 0x1A4
97 +#define PHY_IPG_EMU_ADDR 0x1B0
98 +
99 +#define PHY_CTRL0_VAL 0xA4600015
100 +#define PHY_CTRL1_VAL 0x09500000
101 +#define PHY_CTRL2_VAL 0x00058180
102 +#define PHY_CTRL3_VAL 0x6DB6DCD6
103 +#define PHY_CTRL4_VAL 0x836DB6DB
104 +#define PHY_MISC_VAL 0x3803FB0C
105 +#define PHY_IPG_VAL 0x47323232
106 +
107 +#define PHY_CTRL0_EMU_VAL 0xb4000015
108 +#define PHY_CTRL1_EMU_VAL 0x09500000
109 +#define PHY_CTRL2_EMU_VAL 0x00058180
110 +#define PHY_CTRL3_EMU_VAL 0x6DB6DCD6
111 +#define PHY_CTRL4_EMU_VAL 0x836DB6DB
112 +#define PHY_MISC_EMU_VAL 0x3803FB0C
113 +#define PHY_IPG_EMU_VAL 0x47323232
114 +
115 +#define USB30_HS_PHY_HOST_MODE (0x01 << 21)
116 +#define USB20_HS_PHY_HOST_MODE (0x01 << 5)
117 +
118 +/* used to differentiate between USB3 HS and USB2 HS PHY */
119 +struct qca_baldur_hs_data {
120 + unsigned int usb3_hs_phy;
121 + unsigned int phy_config_offset;
122 +};
123 +
124 +struct qca_baldur_hs_phy {
125 + struct device *dev;
126 + struct usb_phy phy;
127 +
128 + void __iomem *base;
129 + void __iomem *qscratch_base;
130 +
131 + struct reset_control *por_rst;
132 + struct reset_control *srif_rst;
133 +
134 + unsigned int host;
135 + unsigned int emulation;
136 + const struct qca_baldur_hs_data *data;
137 +};
138 +
139 +#define phy_to_dw_phy(x) container_of((x), struct qca_baldur_hs_phy, phy)
140 +
141 +static int qca_baldur_phy_read(struct usb_phy *x, u32 reg)
142 +{
143 + struct qca_baldur_hs_phy *phy = phy_to_dw_phy(x);
144 +
145 + return readl(phy->base + reg);
146 +}
147 +
148 +static int qca_baldur_phy_write(struct usb_phy *x, u32 val, u32 reg)
149 +{
150 + struct qca_baldur_hs_phy *phy = phy_to_dw_phy(x);
151 +
152 + writel(val, phy->base + reg);
153 + return 0;
154 +}
155 +
156 +static int qca_baldur_hs_phy_init(struct usb_phy *x)
157 +{
158 + struct qca_baldur_hs_phy *phy = phy_to_dw_phy(x);
159 +
160 + /* assert HS PHY POR reset */
161 + reset_control_assert(phy->por_rst);
162 + msleep(10);
163 +
164 + /* assert HS PHY SRIF reset */
165 + reset_control_assert(phy->srif_rst);
166 + msleep(10);
167 +
168 + /* deassert HS PHY SRIF reset and program HS PHY registers */
169 + reset_control_deassert(phy->srif_rst);
170 + msleep(10);
171 +
172 + if (!phy->emulation) {
173 + /* perform PHY register writes */
174 + writel(PHY_CTRL0_VAL, phy->base + PHY_CTRL0_ADDR);
175 + writel(PHY_CTRL1_VAL, phy->base + PHY_CTRL1_ADDR);
176 + writel(PHY_CTRL2_VAL, phy->base + PHY_CTRL2_ADDR);
177 + writel(PHY_CTRL3_VAL, phy->base + PHY_CTRL3_ADDR);
178 + writel(PHY_CTRL4_VAL, phy->base + PHY_CTRL4_ADDR);
179 + writel(PHY_MISC_VAL, phy->base + PHY_MISC_ADDR);
180 + writel(PHY_IPG_VAL, phy->base + PHY_IPG_ADDR);
181 + } else {
182 + /* perform PHY register writes */
183 + writel(PHY_CTRL0_EMU_VAL, phy->base + PHY_CTRL0_EMU_ADDR);
184 + writel(PHY_CTRL1_EMU_VAL, phy->base + PHY_CTRL1_EMU_ADDR);
185 + writel(PHY_CTRL2_EMU_VAL, phy->base + PHY_CTRL2_EMU_ADDR);
186 + writel(PHY_CTRL3_EMU_VAL, phy->base + PHY_CTRL3_EMU_ADDR);
187 + writel(PHY_CTRL4_EMU_VAL, phy->base + PHY_CTRL4_EMU_ADDR);
188 + writel(PHY_MISC_EMU_VAL, phy->base + PHY_MISC_EMU_ADDR);
189 + writel(PHY_IPG_EMU_VAL, phy->base + PHY_IPG_EMU_ADDR);
190 + }
191 +
192 + msleep(10);
193 +
194 + /* de-assert USB3 HS PHY POR reset */
195 + reset_control_deassert(phy->por_rst);
196 +
197 + return 0;
198 +}
199 +
200 +static int qca_baldur_hs_get_resources(struct qca_baldur_hs_phy *phy)
201 +{
202 + struct platform_device *pdev = to_platform_device(phy->dev);
203 + struct resource *res;
204 +
205 + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
206 + phy->base = devm_ioremap_resource(phy->dev, res);
207 + if (IS_ERR(phy->base))
208 + return PTR_ERR(phy->base);
209 +
210 + phy->por_rst = devm_reset_control_get(phy->dev, "por_rst");
211 + if (IS_ERR(phy->por_rst))
212 + return PTR_ERR(phy->por_rst);
213 +
214 + phy->srif_rst = devm_reset_control_get(phy->dev, "srif_rst");
215 + if (IS_ERR(phy->srif_rst))
216 + return PTR_ERR(phy->srif_rst);
217 +
218 + return 0;
219 +}
220 +
221 +static void qca_baldur_hs_put_resources(struct qca_baldur_hs_phy *phy)
222 +{
223 + reset_control_assert(phy->srif_rst);
224 + reset_control_assert(phy->por_rst);
225 +}
226 +
227 +static int qca_baldur_hs_remove(struct platform_device *pdev)
228 +{
229 + struct qca_baldur_hs_phy *phy = platform_get_drvdata(pdev);
230 +
231 + usb_remove_phy(&phy->phy);
232 + return 0;
233 +}
234 +
235 +static void qca_baldur_hs_phy_shutdown(struct usb_phy *x)
236 +{
237 + struct qca_baldur_hs_phy *phy = phy_to_dw_phy(x);
238 +
239 + qca_baldur_hs_put_resources(phy);
240 +}
241 +
242 +static struct usb_phy_io_ops qca_baldur_io_ops = {
243 + .read = qca_baldur_phy_read,
244 + .write = qca_baldur_phy_write,
245 +};
246 +
247 +static const struct qca_baldur_hs_data usb3_hs_data = {
248 + .usb3_hs_phy = 1,
249 + .phy_config_offset = USB30_HS_PHY_HOST_MODE,
250 +};
251 +
252 +static const struct qca_baldur_hs_data usb2_hs_data = {
253 + .usb3_hs_phy = 0,
254 + .phy_config_offset = USB20_HS_PHY_HOST_MODE,
255 +};
256 +
257 +static const struct of_device_id qca_baldur_hs_id_table[] = {
258 + { .compatible = "qca,baldur-usb3-hsphy", .data = &usb3_hs_data },
259 + { .compatible = "qca,baldur-usb2-hsphy", .data = &usb2_hs_data },
260 + { /* Sentinel */ }
261 +};
262 +MODULE_DEVICE_TABLE(of, qca_baldur_hs_id_table);
263 +
264 +static int qca_baldur_hs_probe(struct platform_device *pdev)
265 +{
266 + const struct of_device_id *match;
267 + struct qca_baldur_hs_phy *phy;
268 + int err;
269 +
270 + match = of_match_device(qca_baldur_hs_id_table, &pdev->dev);
271 + if (!match)
272 + return -ENODEV;
273 +
274 + phy = devm_kzalloc(&pdev->dev, sizeof(*phy), GFP_KERNEL);
275 + if (!phy)
276 + return -ENOMEM;
277 +
278 + platform_set_drvdata(pdev, phy);
279 + phy->dev = &pdev->dev;
280 +
281 + phy->data = match->data;
282 +
283 + err = qca_baldur_hs_get_resources(phy);
284 + if (err < 0) {
285 + dev_err(&pdev->dev, "failed to request resources: %d\n", err);
286 + return err;
287 + }
288 +
289 + phy->phy.dev = phy->dev;
290 + phy->phy.label = "qca-baldur-hsphy";
291 + phy->phy.init = qca_baldur_hs_phy_init;
292 + phy->phy.shutdown = qca_baldur_hs_phy_shutdown;
293 + phy->phy.type = USB_PHY_TYPE_USB2;
294 + phy->phy.io_ops = &qca_baldur_io_ops;
295 +
296 + err = usb_add_phy_dev(&phy->phy);
297 + return err;
298 +}
299 +
300 +static struct platform_driver qca_baldur_hs_driver = {
301 + .probe = qca_baldur_hs_probe,
302 + .remove = qca_baldur_hs_remove,
303 + .driver = {
304 + .name = "qca-baldur-hsphy",
305 + .owner = THIS_MODULE,
306 + .of_match_table = qca_baldur_hs_id_table,
307 + },
308 +};
309 +
310 +module_platform_driver(qca_baldur_hs_driver);
311 +
312 +MODULE_ALIAS("platform:qca-baldur-hsphy");
313 +MODULE_LICENSE("Dual BSD/GPL");
314 +MODULE_DESCRIPTION("USB3 QCA BALDUR HSPHY driver");
315 --- /dev/null
316 +++ b/drivers/usb/phy/phy-qca-uniphy.c
317 @@ -0,0 +1,171 @@
318 +/* Copyright (c) 2015, The Linux Foundation. All rights reserved.
319 + *
320 + * Permission to use, copy, modify, and/or distribute this software for any
321 + * purpose with or without fee is hereby granted, provided that the above
322 + * copyright notice and this permission notice appear in all copies.
323 + *
324 + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
325 + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
326 + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
327 + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
328 + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
329 + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
330 + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
331 + *
332 + */
333 +
334 +#include <linux/clk.h>
335 +#include <linux/err.h>
336 +#include <linux/io.h>
337 +#include <linux/module.h>
338 +#include <linux/of.h>
339 +#include <linux/platform_device.h>
340 +#include <linux/regulator/consumer.h>
341 +#include <linux/usb/phy.h>
342 +#include <linux/reset.h>
343 +#include <linux/of_device.h>
344 +
345 +struct qca_uni_ss_phy {
346 + struct usb_phy phy;
347 + struct device *dev;
348 +
349 + void __iomem *base;
350 +
351 + struct reset_control *por_rst;
352 +
353 + unsigned int host;
354 +};
355 +
356 +#define phy_to_dw_phy(x) container_of((x), struct qca_uni_ss_phy, phy)
357 +
358 +/**
359 + * Write register
360 + *
361 + * @base - PHY base virtual address.
362 + * @offset - register offset.
363 + */
364 +static u32 qca_uni_ss_read(void __iomem *base, u32 offset)
365 +{
366 + u32 value;
367 + value = readl_relaxed(base + offset);
368 + return value;
369 +}
370 +
371 +/**
372 + * Write register
373 + *
374 + * @base - PHY base virtual address.
375 + * @offset - register offset.
376 + * @val - value to write.
377 + */
378 +static void qca_uni_ss_write(void __iomem *base, u32 offset, u32 val)
379 +{
380 + writel(val, base + offset);
381 + udelay(100);
382 +}
383 +
384 +static void qca_uni_ss_phy_shutdown(struct usb_phy *x)
385 +{
386 + struct qca_uni_ss_phy *phy = phy_to_dw_phy(x);
387 +
388 + /* assert SS PHY POR reset */
389 + reset_control_assert(phy->por_rst);
390 +}
391 +
392 +static int qca_uni_ss_phy_init(struct usb_phy *x)
393 +{
394 + struct qca_uni_ss_phy *phy = phy_to_dw_phy(x);
395 +
396 + /* assert SS PHY POR reset */
397 + reset_control_assert(phy->por_rst);
398 +
399 + msleep(10);
400 +
401 + msleep(10);
402 +
403 + /* deassert SS PHY POR reset */
404 + reset_control_deassert(phy->por_rst);
405 +
406 + return 0;
407 +}
408 +
409 +static int qca_uni_ss_get_resources(struct platform_device *pdev,
410 + struct qca_uni_ss_phy *phy)
411 +{
412 + struct resource *res;
413 +
414 + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
415 + phy->base = devm_ioremap_resource(phy->dev, res);
416 + if (IS_ERR(phy->base))
417 + return PTR_ERR(phy->base);
418 +
419 + phy->por_rst = devm_reset_control_get(phy->dev, "por_rst");
420 + if (IS_ERR(phy->por_rst))
421 + return PTR_ERR(phy->por_rst);
422 +
423 + return 0;
424 +}
425 +
426 +static int qca_uni_ss_remove(struct platform_device *pdev)
427 +{
428 + struct qca_uni_ss_phy *phy = platform_get_drvdata(pdev);
429 +
430 + usb_remove_phy(&phy->phy);
431 + return 0;
432 +}
433 +
434 +static const struct of_device_id qca_uni_ss_id_table[] = {
435 + { .compatible = "qca,uni-ssphy" },
436 + { /* Sentinel */ }
437 +};
438 +MODULE_DEVICE_TABLE(of, qca_uni_ss_id_table);
439 +
440 +static int qca_uni_ss_probe(struct platform_device *pdev)
441 +{
442 + const struct of_device_id *match;
443 + struct device_node *np = pdev->dev.of_node;
444 + struct qca_uni_ss_phy *phy;
445 + int ret;
446 +
447 + match = of_match_device(qca_uni_ss_id_table, &pdev->dev);
448 + if (!match)
449 + return -ENODEV;
450 +
451 + phy = devm_kzalloc(&pdev->dev, sizeof(*phy), GFP_KERNEL);
452 + if (!phy)
453 + return -ENOMEM;
454 +
455 + platform_set_drvdata(pdev, phy);
456 + phy->dev = &pdev->dev;
457 +
458 + ret = qca_uni_ss_get_resources(pdev, phy);
459 + if (ret < 0) {
460 + dev_err(&pdev->dev, "failed to request resources: %d\n", ret);
461 + return ret;
462 + }
463 +
464 + phy->phy.dev = phy->dev;
465 + phy->phy.label = "qca-uni-ssphy";
466 + phy->phy.init = qca_uni_ss_phy_init;
467 + phy->phy.shutdown = qca_uni_ss_phy_shutdown;
468 + phy->phy.type = USB_PHY_TYPE_USB3;
469 +
470 + ret = usb_add_phy_dev(&phy->phy);
471 + return ret;
472 +}
473 +
474 +static struct platform_driver qca_uni_ss_driver = {
475 + .probe = qca_uni_ss_probe,
476 + .remove = qca_uni_ss_remove,
477 + .driver = {
478 + .name = "qca-uni-ssphy",
479 + .owner = THIS_MODULE,
480 + .of_match_table = qca_uni_ss_id_table,
481 + },
482 +};
483 +
484 +module_platform_driver(qca_uni_ss_driver);
485 +
486 +MODULE_ALIAS("platform:qca-uni-ssphy");
487 +MODULE_LICENSE("Dual BSD/GPL");
488 +MODULE_DESCRIPTION("USB3 QCA UNI SSPHY driver");