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
6 These drivers handles control and configuration of the HS
7 and SS USB PHY transceivers.
9 Signed-off-by: Senthilkumar N L <snlakshm@codeaurora.org>
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
19 --- a/drivers/usb/phy/Kconfig
20 +++ b/drivers/usb/phy/Kconfig
21 @@ -194,6 +194,17 @@ config USB_MXS_PHY
23 MXS Phy is used by some of the i.MX SoCs, for example imx23/28/6x.
25 +config USB_IPQ4019_PHY
26 + tristate "IPQ4019 PHY wrappers support"
27 + depends on (USB || USB_GADGET) && ARCH_QCOM
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.
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
51 +++ b/drivers/usb/phy/phy-qca-baldur.c
53 +/* Copyright (c) 2015, The Linux Foundation. All rights reserved.
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.
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.
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>
81 + * USB Hardware registers
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
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
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
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
115 +#define USB30_HS_PHY_HOST_MODE (0x01 << 21)
116 +#define USB20_HS_PHY_HOST_MODE (0x01 << 5)
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;
124 +struct qca_baldur_hs_phy {
125 + struct device *dev;
126 + struct usb_phy phy;
128 + void __iomem *base;
129 + void __iomem *qscratch_base;
131 + struct reset_control *por_rst;
132 + struct reset_control *srif_rst;
135 + unsigned int emulation;
136 + const struct qca_baldur_hs_data *data;
139 +#define phy_to_dw_phy(x) container_of((x), struct qca_baldur_hs_phy, phy)
141 +static int qca_baldur_phy_read(struct usb_phy *x, u32 reg)
143 + struct qca_baldur_hs_phy *phy = phy_to_dw_phy(x);
145 + return readl(phy->base + reg);
148 +static int qca_baldur_phy_write(struct usb_phy *x, u32 val, u32 reg)
150 + struct qca_baldur_hs_phy *phy = phy_to_dw_phy(x);
152 + writel(val, phy->base + reg);
156 +static int qca_baldur_hs_phy_init(struct usb_phy *x)
158 + struct qca_baldur_hs_phy *phy = phy_to_dw_phy(x);
160 + /* assert HS PHY POR reset */
161 + reset_control_assert(phy->por_rst);
164 + /* assert HS PHY SRIF reset */
165 + reset_control_assert(phy->srif_rst);
168 + /* deassert HS PHY SRIF reset and program HS PHY registers */
169 + reset_control_deassert(phy->srif_rst);
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);
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);
194 + /* de-assert USB3 HS PHY POR reset */
195 + reset_control_deassert(phy->por_rst);
200 +static int qca_baldur_hs_get_resources(struct qca_baldur_hs_phy *phy)
202 + struct platform_device *pdev = to_platform_device(phy->dev);
203 + struct resource *res;
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);
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);
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);
221 +static void qca_baldur_hs_put_resources(struct qca_baldur_hs_phy *phy)
223 + reset_control_assert(phy->srif_rst);
224 + reset_control_assert(phy->por_rst);
227 +static int qca_baldur_hs_remove(struct platform_device *pdev)
229 + struct qca_baldur_hs_phy *phy = platform_get_drvdata(pdev);
231 + usb_remove_phy(&phy->phy);
235 +static void qca_baldur_hs_phy_shutdown(struct usb_phy *x)
237 + struct qca_baldur_hs_phy *phy = phy_to_dw_phy(x);
239 + qca_baldur_hs_put_resources(phy);
242 +static struct usb_phy_io_ops qca_baldur_io_ops = {
243 + .read = qca_baldur_phy_read,
244 + .write = qca_baldur_phy_write,
247 +static const struct qca_baldur_hs_data usb3_hs_data = {
249 + .phy_config_offset = USB30_HS_PHY_HOST_MODE,
252 +static const struct qca_baldur_hs_data usb2_hs_data = {
254 + .phy_config_offset = USB20_HS_PHY_HOST_MODE,
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 },
262 +MODULE_DEVICE_TABLE(of, qca_baldur_hs_id_table);
264 +static int qca_baldur_hs_probe(struct platform_device *pdev)
266 + const struct of_device_id *match;
267 + struct qca_baldur_hs_phy *phy;
270 + match = of_match_device(qca_baldur_hs_id_table, &pdev->dev);
274 + phy = devm_kzalloc(&pdev->dev, sizeof(*phy), GFP_KERNEL);
278 + platform_set_drvdata(pdev, phy);
279 + phy->dev = &pdev->dev;
281 + phy->data = match->data;
283 + err = qca_baldur_hs_get_resources(phy);
285 + dev_err(&pdev->dev, "failed to request resources: %d\n", err);
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;
296 + err = usb_add_phy_dev(&phy->phy);
300 +static struct platform_driver qca_baldur_hs_driver = {
301 + .probe = qca_baldur_hs_probe,
302 + .remove = qca_baldur_hs_remove,
304 + .name = "qca-baldur-hsphy",
305 + .owner = THIS_MODULE,
306 + .of_match_table = qca_baldur_hs_id_table,
310 +module_platform_driver(qca_baldur_hs_driver);
312 +MODULE_ALIAS("platform:qca-baldur-hsphy");
313 +MODULE_LICENSE("Dual BSD/GPL");
314 +MODULE_DESCRIPTION("USB3 QCA BALDUR HSPHY driver");
316 +++ b/drivers/usb/phy/phy-qca-uniphy.c
318 +/* Copyright (c) 2015, The Linux Foundation. All rights reserved.
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.
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.
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>
345 +struct qca_uni_ss_phy {
346 + struct usb_phy phy;
347 + struct device *dev;
349 + void __iomem *base;
351 + struct reset_control *por_rst;
356 +#define phy_to_dw_phy(x) container_of((x), struct qca_uni_ss_phy, phy)
361 + * @base - PHY base virtual address.
362 + * @offset - register offset.
364 +static u32 qca_uni_ss_read(void __iomem *base, u32 offset)
367 + value = readl_relaxed(base + offset);
374 + * @base - PHY base virtual address.
375 + * @offset - register offset.
376 + * @val - value to write.
378 +static void qca_uni_ss_write(void __iomem *base, u32 offset, u32 val)
380 + writel(val, base + offset);
384 +static void qca_uni_ss_phy_shutdown(struct usb_phy *x)
386 + struct qca_uni_ss_phy *phy = phy_to_dw_phy(x);
388 + /* assert SS PHY POR reset */
389 + reset_control_assert(phy->por_rst);
392 +static int qca_uni_ss_phy_init(struct usb_phy *x)
394 + struct qca_uni_ss_phy *phy = phy_to_dw_phy(x);
396 + /* assert SS PHY POR reset */
397 + reset_control_assert(phy->por_rst);
403 + /* deassert SS PHY POR reset */
404 + reset_control_deassert(phy->por_rst);
409 +static int qca_uni_ss_get_resources(struct platform_device *pdev,
410 + struct qca_uni_ss_phy *phy)
412 + struct resource *res;
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);
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);
426 +static int qca_uni_ss_remove(struct platform_device *pdev)
428 + struct qca_uni_ss_phy *phy = platform_get_drvdata(pdev);
430 + usb_remove_phy(&phy->phy);
434 +static const struct of_device_id qca_uni_ss_id_table[] = {
435 + { .compatible = "qca,uni-ssphy" },
438 +MODULE_DEVICE_TABLE(of, qca_uni_ss_id_table);
440 +static int qca_uni_ss_probe(struct platform_device *pdev)
442 + const struct of_device_id *match;
443 + struct device_node *np = pdev->dev.of_node;
444 + struct qca_uni_ss_phy *phy;
447 + match = of_match_device(qca_uni_ss_id_table, &pdev->dev);
451 + phy = devm_kzalloc(&pdev->dev, sizeof(*phy), GFP_KERNEL);
455 + platform_set_drvdata(pdev, phy);
456 + phy->dev = &pdev->dev;
458 + ret = qca_uni_ss_get_resources(pdev, phy);
460 + dev_err(&pdev->dev, "failed to request resources: %d\n", ret);
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;
470 + ret = usb_add_phy_dev(&phy->phy);
474 +static struct platform_driver qca_uni_ss_driver = {
475 + .probe = qca_uni_ss_probe,
476 + .remove = qca_uni_ss_remove,
478 + .name = "qca-uni-ssphy",
479 + .owner = THIS_MODULE,
480 + .of_match_table = qca_uni_ss_id_table,
484 +module_platform_driver(qca_uni_ss_driver);
486 +MODULE_ALIAS("platform:qca-uni-ssphy");
487 +MODULE_LICENSE("Dual BSD/GPL");
488 +MODULE_DESCRIPTION("USB3 QCA UNI SSPHY driver");