uboot-fritz4040: add an ipq806x u-boot for FritzBox 4040
[librecmc/librecmc.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");