aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>2015-10-17 23:12:19 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2015-10-17 23:12:19 -0400
commit539669779a8e369912d86dc4048175cc47f20c33 (patch)
treed3b9cd5659589783313ec5eda43f0196d24aea7f
parent50bdb12388c520e93947fca3cabf233a77fefd42 (diff)
parent0f8669e343982ac66f4420335777cb5456b8abb0 (diff)
Merge tag 'phy-for-4.4' of git://git.kernel.org/pub/scm/linux/kernel/git/kishon/linux-phy into usb-next
Kishon writes: phy: for 4.4 *) Add new PHY driver for Broadcom's cygnus PCIe PHY *) Add USB3 PHY driver for mediatek's SoCs *) Add VBUS regulator support for Samsung's exynos PHY *) Misc cleanup Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
-rw-r--r--Documentation/devicetree/bindings/phy/brcm,cygnus-pcie-phy.txt47
-rw-r--r--Documentation/devicetree/bindings/phy/phy-mt65xx-usb.txt68
-rw-r--r--Documentation/devicetree/bindings/phy/samsung-phy.txt3
-rw-r--r--MAINTAINERS7
-rw-r--r--drivers/phy/Kconfig18
-rw-r--r--drivers/phy/Makefile2
-rw-r--r--drivers/phy/phy-bcm-cygnus-pcie.c213
-rw-r--r--drivers/phy/phy-mt65xx-usb3.c506
-rw-r--r--drivers/phy/phy-samsung-usb2.c25
-rw-r--r--drivers/phy/phy-samsung-usb2.h2
-rw-r--r--drivers/phy/phy-sun4i-usb.c22
11 files changed, 898 insertions, 15 deletions
diff --git a/Documentation/devicetree/bindings/phy/brcm,cygnus-pcie-phy.txt b/Documentation/devicetree/bindings/phy/brcm,cygnus-pcie-phy.txt
new file mode 100644
index 000000000000..761c4bc24a9b
--- /dev/null
+++ b/Documentation/devicetree/bindings/phy/brcm,cygnus-pcie-phy.txt
@@ -0,0 +1,47 @@
1Broadcom Cygnus PCIe PHY
2
3Required properties:
4- compatible: must be "brcm,cygnus-pcie-phy"
5- reg: base address and length of the PCIe PHY block
6- #address-cells: must be 1
7- #size-cells: must be 0
8
9Each PCIe PHY should be represented by a child node
10
11Required properties For the child node:
12- reg: the PHY ID
130 - PCIe RC 0
141 - PCIe RC 1
15- #phy-cells: must be 0
16
17Example:
18 pcie_phy: phy@0301d0a0 {
19 compatible = "brcm,cygnus-pcie-phy";
20 reg = <0x0301d0a0 0x14>;
21
22 pcie0_phy: phy@0 {
23 reg = <0>;
24 #phy-cells = <0>;
25 };
26
27 pcie1_phy: phy@1 {
28 reg = <1>;
29 #phy-cells = <0>;
30 };
31 };
32
33 /* users of the PCIe phy */
34
35 pcie0: pcie@18012000 {
36 ...
37 ...
38 phys = <&pcie0_phy>;
39 phy-names = "pcie-phy";
40 };
41
42 pcie1: pcie@18013000 {
43 ...
44 ...
45 phys = <pcie1_phy>;
46 phy-names = "pcie-phy";
47 };
diff --git a/Documentation/devicetree/bindings/phy/phy-mt65xx-usb.txt b/Documentation/devicetree/bindings/phy/phy-mt65xx-usb.txt
new file mode 100644
index 000000000000..00100cf3e037
--- /dev/null
+++ b/Documentation/devicetree/bindings/phy/phy-mt65xx-usb.txt
@@ -0,0 +1,68 @@
1mt65xx USB3.0 PHY binding
2--------------------------
3
4This binding describes a usb3.0 phy for mt65xx platforms of Medaitek SoC.
5
6Required properties (controller (parent) node):
7 - compatible : should be "mediatek,mt8173-u3phy"
8 - reg : offset and length of register for phy, exclude port's
9 register.
10 - clocks : a list of phandle + clock-specifier pairs, one for each
11 entry in clock-names
12 - clock-names : must contain
13 "u3phya_ref": for reference clock of usb3.0 analog phy.
14
15Required nodes : a sub-node is required for each port the controller
16 provides. Address range information including the usual
17 'reg' property is used inside these nodes to describe
18 the controller's topology.
19
20Required properties (port (child) node):
21- reg : address and length of the register set for the port.
22- #phy-cells : should be 1 (See second example)
23 cell after port phandle is phy type from:
24 - PHY_TYPE_USB2
25 - PHY_TYPE_USB3
26
27Example:
28
29u3phy: usb-phy@11290000 {
30 compatible = "mediatek,mt8173-u3phy";
31 reg = <0 0x11290000 0 0x800>;
32 clocks = <&apmixedsys CLK_APMIXED_REF2USB_TX>;
33 clock-names = "u3phya_ref";
34 #address-cells = <2>;
35 #size-cells = <2>;
36 ranges;
37 status = "okay";
38
39 phy_port0: port@11290800 {
40 reg = <0 0x11290800 0 0x800>;
41 #phy-cells = <1>;
42 status = "okay";
43 };
44
45 phy_port1: port@11291000 {
46 reg = <0 0x11291000 0 0x800>;
47 #phy-cells = <1>;
48 status = "okay";
49 };
50};
51
52Specifying phy control of devices
53---------------------------------
54
55Device nodes should specify the configuration required in their "phys"
56property, containing a phandle to the phy port node and a device type;
57phy-names for each port are optional.
58
59Example:
60
61#include <dt-bindings/phy/phy.h>
62
63usb30: usb@11270000 {
64 ...
65 phys = <&phy_port0 PHY_TYPE_USB3>;
66 phy-names = "usb3-0";
67 ...
68};
diff --git a/Documentation/devicetree/bindings/phy/samsung-phy.txt b/Documentation/devicetree/bindings/phy/samsung-phy.txt
index 60c6f2a633e0..0289d3b07853 100644
--- a/Documentation/devicetree/bindings/phy/samsung-phy.txt
+++ b/Documentation/devicetree/bindings/phy/samsung-phy.txt
@@ -44,6 +44,9 @@ Required properties:
44 - the "ref" clock is used to get the rate of the clock provided to the 44 - the "ref" clock is used to get the rate of the clock provided to the
45 PHY module 45 PHY module
46 46
47Optional properties:
48- vbus-supply: power-supply phandle for vbus power source
49
47The first phandle argument in the PHY specifier identifies the PHY, its 50The first phandle argument in the PHY specifier identifies the PHY, its
48meaning is compatible dependent. For the currently supported SoCs (Exynos 4210 51meaning is compatible dependent. For the currently supported SoCs (Exynos 4210
49and Exynos 4212) it is as follows: 52and Exynos 4212) it is as follows:
diff --git a/MAINTAINERS b/MAINTAINERS
index 5f467845ef72..7f142e748bea 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1297,6 +1297,13 @@ F: arch/arm/mach-mediatek/
1297N: mtk 1297N: mtk
1298K: mediatek 1298K: mediatek
1299 1299
1300ARM/Mediatek USB3 PHY DRIVER
1301M: Chunfeng Yun <chunfeng.yun@mediatek.com>
1302L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
1303L: linux-mediatek@lists.infradead.org (moderated for non-subscribers)
1304S: Maintained
1305F: drivers/phy/phy-mt65xx-usb3.c
1306
1300ARM/MICREL KS8695 ARCHITECTURE 1307ARM/MICREL KS8695 ARCHITECTURE
1301M: Greg Ungerer <gerg@uclinux.org> 1308M: Greg Ungerer <gerg@uclinux.org>
1302L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) 1309L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index 47da573d0bab..7eb5859dd035 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -206,6 +206,15 @@ config PHY_HIX5HD2_SATA
206 help 206 help
207 Support for SATA PHY on Hisilicon hix5hd2 Soc. 207 Support for SATA PHY on Hisilicon hix5hd2 Soc.
208 208
209config PHY_MT65XX_USB3
210 tristate "Mediatek USB3.0 PHY Driver"
211 depends on ARCH_MEDIATEK && OF
212 select GENERIC_PHY
213 help
214 Say 'Y' here to add support for Mediatek USB3.0 PHY driver
215 for mt65xx SoCs. it supports two usb2.0 ports and
216 one usb3.0 port.
217
209config PHY_SUN4I_USB 218config PHY_SUN4I_USB
210 tristate "Allwinner sunxi SoC USB PHY driver" 219 tristate "Allwinner sunxi SoC USB PHY driver"
211 depends on ARCH_SUNXI && HAS_IOMEM && OF 220 depends on ARCH_SUNXI && HAS_IOMEM && OF
@@ -371,4 +380,13 @@ config PHY_BRCMSTB_SATA
371 Enable this to support the SATA3 PHY on 28nm Broadcom STB SoCs. 380 Enable this to support the SATA3 PHY on 28nm Broadcom STB SoCs.
372 Likely useful only with CONFIG_SATA_BRCMSTB enabled. 381 Likely useful only with CONFIG_SATA_BRCMSTB enabled.
373 382
383config PHY_CYGNUS_PCIE
384 tristate "Broadcom Cygnus PCIe PHY driver"
385 depends on OF && (ARCH_BCM_CYGNUS || COMPILE_TEST)
386 select GENERIC_PHY
387 default ARCH_BCM_CYGNUS
388 help
389 Enable this to support the Broadcom Cygnus PCIe PHY.
390 If unsure, say N.
391
374endmenu 392endmenu
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
index a5b18c18fc12..075db1a81aa5 100644
--- a/drivers/phy/Makefile
+++ b/drivers/phy/Makefile
@@ -23,6 +23,7 @@ obj-$(CONFIG_TI_PIPE3) += phy-ti-pipe3.o
23obj-$(CONFIG_TWL4030_USB) += phy-twl4030-usb.o 23obj-$(CONFIG_TWL4030_USB) += phy-twl4030-usb.o
24obj-$(CONFIG_PHY_EXYNOS5250_SATA) += phy-exynos5250-sata.o 24obj-$(CONFIG_PHY_EXYNOS5250_SATA) += phy-exynos5250-sata.o
25obj-$(CONFIG_PHY_HIX5HD2_SATA) += phy-hix5hd2-sata.o 25obj-$(CONFIG_PHY_HIX5HD2_SATA) += phy-hix5hd2-sata.o
26obj-$(CONFIG_PHY_MT65XX_USB3) += phy-mt65xx-usb3.o
26obj-$(CONFIG_PHY_SUN4I_USB) += phy-sun4i-usb.o 27obj-$(CONFIG_PHY_SUN4I_USB) += phy-sun4i-usb.o
27obj-$(CONFIG_PHY_SUN9I_USB) += phy-sun9i-usb.o 28obj-$(CONFIG_PHY_SUN9I_USB) += phy-sun9i-usb.o
28obj-$(CONFIG_PHY_SAMSUNG_USB2) += phy-exynos-usb2.o 29obj-$(CONFIG_PHY_SAMSUNG_USB2) += phy-exynos-usb2.o
@@ -46,3 +47,4 @@ obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs-qmp-14nm.o
46obj-$(CONFIG_PHY_TUSB1210) += phy-tusb1210.o 47obj-$(CONFIG_PHY_TUSB1210) += phy-tusb1210.o
47obj-$(CONFIG_PHY_BRCMSTB_SATA) += phy-brcmstb-sata.o 48obj-$(CONFIG_PHY_BRCMSTB_SATA) += phy-brcmstb-sata.o
48obj-$(CONFIG_PHY_PISTACHIO_USB) += phy-pistachio-usb.o 49obj-$(CONFIG_PHY_PISTACHIO_USB) += phy-pistachio-usb.o
50obj-$(CONFIG_PHY_CYGNUS_PCIE) += phy-bcm-cygnus-pcie.o
diff --git a/drivers/phy/phy-bcm-cygnus-pcie.c b/drivers/phy/phy-bcm-cygnus-pcie.c
new file mode 100644
index 000000000000..7ad72b7d2b98
--- /dev/null
+++ b/drivers/phy/phy-bcm-cygnus-pcie.c
@@ -0,0 +1,213 @@
1/*
2 * Copyright (C) 2015 Broadcom Corporation
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation version 2.
7 *
8 * This program is distributed "as is" WITHOUT ANY WARRANTY of any
9 * kind, whether express or implied; without even the implied warranty
10 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 */
13
14#include <linux/delay.h>
15#include <linux/io.h>
16#include <linux/module.h>
17#include <linux/of.h>
18#include <linux/phy/phy.h>
19#include <linux/platform_device.h>
20
21#define PCIE_CFG_OFFSET 0x00
22#define PCIE1_PHY_IDDQ_SHIFT 10
23#define PCIE0_PHY_IDDQ_SHIFT 2
24
25enum cygnus_pcie_phy_id {
26 CYGNUS_PHY_PCIE0 = 0,
27 CYGNUS_PHY_PCIE1,
28 MAX_NUM_PHYS,
29};
30
31struct cygnus_pcie_phy_core;
32
33/**
34 * struct cygnus_pcie_phy - Cygnus PCIe PHY device
35 * @core: pointer to the Cygnus PCIe PHY core control
36 * @id: internal ID to identify the Cygnus PCIe PHY
37 * @phy: pointer to the kernel PHY device
38 */
39struct cygnus_pcie_phy {
40 struct cygnus_pcie_phy_core *core;
41 enum cygnus_pcie_phy_id id;
42 struct phy *phy;
43};
44
45/**
46 * struct cygnus_pcie_phy_core - Cygnus PCIe PHY core control
47 * @dev: pointer to device
48 * @base: base register
49 * @lock: mutex to protect access to individual PHYs
50 * @phys: pointer to Cygnus PHY device
51 */
52struct cygnus_pcie_phy_core {
53 struct device *dev;
54 void __iomem *base;
55 struct mutex lock;
56 struct cygnus_pcie_phy phys[MAX_NUM_PHYS];
57};
58
59static int cygnus_pcie_power_config(struct cygnus_pcie_phy *phy, bool enable)
60{
61 struct cygnus_pcie_phy_core *core = phy->core;
62 unsigned shift;
63 u32 val;
64
65 mutex_lock(&core->lock);
66
67 switch (phy->id) {
68 case CYGNUS_PHY_PCIE0:
69 shift = PCIE0_PHY_IDDQ_SHIFT;
70 break;
71
72 case CYGNUS_PHY_PCIE1:
73 shift = PCIE1_PHY_IDDQ_SHIFT;
74 break;
75
76 default:
77 mutex_unlock(&core->lock);
78 dev_err(core->dev, "PCIe PHY %d invalid\n", phy->id);
79 return -EINVAL;
80 }
81
82 if (enable) {
83 val = readl(core->base + PCIE_CFG_OFFSET);
84 val &= ~BIT(shift);
85 writel(val, core->base + PCIE_CFG_OFFSET);
86 /*
87 * Wait 50 ms for the PCIe Serdes to stabilize after the analog
88 * front end is brought up
89 */
90 msleep(50);
91 } else {
92 val = readl(core->base + PCIE_CFG_OFFSET);
93 val |= BIT(shift);
94 writel(val, core->base + PCIE_CFG_OFFSET);
95 }
96
97 mutex_unlock(&core->lock);
98 dev_dbg(core->dev, "PCIe PHY %d %s\n", phy->id,
99 enable ? "enabled" : "disabled");
100 return 0;
101}
102
103static int cygnus_pcie_phy_power_on(struct phy *p)
104{
105 struct cygnus_pcie_phy *phy = phy_get_drvdata(p);
106
107 return cygnus_pcie_power_config(phy, true);
108}
109
110static int cygnus_pcie_phy_power_off(struct phy *p)
111{
112 struct cygnus_pcie_phy *phy = phy_get_drvdata(p);
113
114 return cygnus_pcie_power_config(phy, false);
115}
116
117static struct phy_ops cygnus_pcie_phy_ops = {
118 .power_on = cygnus_pcie_phy_power_on,
119 .power_off = cygnus_pcie_phy_power_off,
120 .owner = THIS_MODULE,
121};
122
123static int cygnus_pcie_phy_probe(struct platform_device *pdev)
124{
125 struct device *dev = &pdev->dev;
126 struct device_node *node = dev->of_node, *child;
127 struct cygnus_pcie_phy_core *core;
128 struct phy_provider *provider;
129 struct resource *res;
130 unsigned cnt = 0;
131
132 if (of_get_child_count(node) == 0) {
133 dev_err(dev, "PHY no child node\n");
134 return -ENODEV;
135 }
136
137 core = devm_kzalloc(dev, sizeof(*core), GFP_KERNEL);
138 if (!core)
139 return -ENOMEM;
140
141 core->dev = dev;
142
143 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
144 core->base = devm_ioremap_resource(dev, res);
145 if (IS_ERR(core->base))
146 return PTR_ERR(core->base);
147
148 mutex_init(&core->lock);
149
150 for_each_available_child_of_node(node, child) {
151 unsigned int id;
152 struct cygnus_pcie_phy *p;
153
154 if (of_property_read_u32(child, "reg", &id)) {
155 dev_err(dev, "missing reg property for %s\n",
156 child->name);
157 return -EINVAL;
158 }
159
160 if (id >= MAX_NUM_PHYS) {
161 dev_err(dev, "invalid PHY id: %u\n", id);
162 return -EINVAL;
163 }
164
165 if (core->phys[id].phy) {
166 dev_err(dev, "duplicated PHY id: %u\n", id);
167 return -EINVAL;
168 }
169
170 p = &core->phys[id];
171 p->phy = devm_phy_create(dev, child, &cygnus_pcie_phy_ops);
172 if (IS_ERR(p->phy)) {
173 dev_err(dev, "failed to create PHY\n");
174 return PTR_ERR(p->phy);
175 }
176
177 p->core = core;
178 p->id = id;
179 phy_set_drvdata(p->phy, p);
180 cnt++;
181 }
182
183 dev_set_drvdata(dev, core);
184
185 provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
186 if (IS_ERR(provider)) {
187 dev_err(dev, "failed to register PHY provider\n");
188 return PTR_ERR(provider);
189 }
190
191 dev_dbg(dev, "registered %u PCIe PHY(s)\n", cnt);
192
193 return 0;
194}
195
196static const struct of_device_id cygnus_pcie_phy_match_table[] = {
197 { .compatible = "brcm,cygnus-pcie-phy" },
198 { /* sentinel */ }
199};
200MODULE_DEVICE_TABLE(of, cygnus_pcie_phy_match_table);
201
202static struct platform_driver cygnus_pcie_phy_driver = {
203 .driver = {
204 .name = "cygnus-pcie-phy",
205 .of_match_table = cygnus_pcie_phy_match_table,
206 },
207 .probe = cygnus_pcie_phy_probe,
208};
209module_platform_driver(cygnus_pcie_phy_driver);
210
211MODULE_AUTHOR("Ray Jui <rjui@broadcom.com>");
212MODULE_DESCRIPTION("Broadcom Cygnus PCIe PHY driver");
213MODULE_LICENSE("GPL v2");
diff --git a/drivers/phy/phy-mt65xx-usb3.c b/drivers/phy/phy-mt65xx-usb3.c
new file mode 100644
index 000000000000..f30b28bd41fe
--- /dev/null
+++ b/drivers/phy/phy-mt65xx-usb3.c
@@ -0,0 +1,506 @@
1/*
2 * Copyright (c) 2015 MediaTek Inc.
3 * Author: Chunfeng Yun <chunfeng.yun@mediatek.com>
4 *
5 * This software is licensed under the terms of the GNU General Public
6 * License version 2, as published by the Free Software Foundation, and
7 * may be copied, distributed, and modified under those terms.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 */
15
16#include <dt-bindings/phy/phy.h>
17#include <linux/clk.h>
18#include <linux/delay.h>
19#include <linux/io.h>
20#include <linux/module.h>
21#include <linux/of_address.h>
22#include <linux/phy/phy.h>
23#include <linux/platform_device.h>
24
25/*
26 * for sifslv2 register, but exclude port's;
27 * relative to USB3_SIF2_BASE base address
28 */
29#define SSUSB_SIFSLV_SPLLC 0x0000
30
31/* offsets of sub-segment in each port registers */
32#define SSUSB_SIFSLV_U2PHY_COM_BASE 0x0000
33#define SSUSB_SIFSLV_U3PHYD_BASE 0x0100
34#define SSUSB_USB30_PHYA_SIV_B_BASE 0x0300
35#define SSUSB_SIFSLV_U3PHYA_DA_BASE 0x0400
36
37#define U3P_USBPHYACR0 (SSUSB_SIFSLV_U2PHY_COM_BASE + 0x0000)
38#define PA0_RG_U2PLL_FORCE_ON BIT(15)
39
40#define U3P_USBPHYACR2 (SSUSB_SIFSLV_U2PHY_COM_BASE + 0x0008)
41#define PA2_RG_SIF_U2PLL_FORCE_EN BIT(18)
42
43#define U3P_USBPHYACR5 (SSUSB_SIFSLV_U2PHY_COM_BASE + 0x0014)
44#define PA5_RG_U2_HSTX_SRCTRL GENMASK(14, 12)
45#define PA5_RG_U2_HSTX_SRCTRL_VAL(x) ((0x7 & (x)) << 12)
46#define PA5_RG_U2_HS_100U_U3_EN BIT(11)
47
48#define U3P_USBPHYACR6 (SSUSB_SIFSLV_U2PHY_COM_BASE + 0x0018)
49#define PA6_RG_U2_ISO_EN BIT(31)
50#define PA6_RG_U2_BC11_SW_EN BIT(23)
51#define PA6_RG_U2_OTG_VBUSCMP_EN BIT(20)
52
53#define U3P_U2PHYACR4 (SSUSB_SIFSLV_U2PHY_COM_BASE + 0x0020)
54#define P2C_RG_USB20_GPIO_CTL BIT(9)
55#define P2C_USB20_GPIO_MODE BIT(8)
56#define P2C_U2_GPIO_CTR_MSK (P2C_RG_USB20_GPIO_CTL | P2C_USB20_GPIO_MODE)
57
58#define U3D_U2PHYDCR0 (SSUSB_SIFSLV_U2PHY_COM_BASE + 0x0060)
59#define P2C_RG_SIF_U2PLL_FORCE_ON BIT(24)
60
61#define U3P_U2PHYDTM0 (SSUSB_SIFSLV_U2PHY_COM_BASE + 0x0068)
62#define P2C_FORCE_UART_EN BIT(26)
63#define P2C_FORCE_DATAIN BIT(23)
64#define P2C_FORCE_DM_PULLDOWN BIT(21)
65#define P2C_FORCE_DP_PULLDOWN BIT(20)
66#define P2C_FORCE_XCVRSEL BIT(19)
67#define P2C_FORCE_SUSPENDM BIT(18)
68#define P2C_FORCE_TERMSEL BIT(17)
69#define P2C_RG_DATAIN GENMASK(13, 10)
70#define P2C_RG_DATAIN_VAL(x) ((0xf & (x)) << 10)
71#define P2C_RG_DMPULLDOWN BIT(7)
72#define P2C_RG_DPPULLDOWN BIT(6)
73#define P2C_RG_XCVRSEL GENMASK(5, 4)
74#define P2C_RG_XCVRSEL_VAL(x) ((0x3 & (x)) << 4)
75#define P2C_RG_SUSPENDM BIT(3)
76#define P2C_RG_TERMSEL BIT(2)
77#define P2C_DTM0_PART_MASK \
78 (P2C_FORCE_DATAIN | P2C_FORCE_DM_PULLDOWN | \
79 P2C_FORCE_DP_PULLDOWN | P2C_FORCE_XCVRSEL | \
80 P2C_FORCE_TERMSEL | P2C_RG_DMPULLDOWN | \
81 P2C_RG_DPPULLDOWN | P2C_RG_TERMSEL)
82
83#define U3P_U2PHYDTM1 (SSUSB_SIFSLV_U2PHY_COM_BASE + 0x006C)
84#define P2C_RG_UART_EN BIT(16)
85#define P2C_RG_VBUSVALID BIT(5)
86#define P2C_RG_SESSEND BIT(4)
87#define P2C_RG_AVALID BIT(2)
88
89#define U3P_U3_PHYA_REG0 (SSUSB_USB30_PHYA_SIV_B_BASE + 0x0000)
90#define P3A_RG_U3_VUSB10_ON BIT(5)
91
92#define U3P_U3_PHYA_REG6 (SSUSB_USB30_PHYA_SIV_B_BASE + 0x0018)
93#define P3A_RG_TX_EIDLE_CM GENMASK(31, 28)
94#define P3A_RG_TX_EIDLE_CM_VAL(x) ((0xf & (x)) << 28)
95
96#define U3P_U3_PHYA_REG9 (SSUSB_USB30_PHYA_SIV_B_BASE + 0x0024)
97#define P3A_RG_RX_DAC_MUX GENMASK(5, 1)
98#define P3A_RG_RX_DAC_MUX_VAL(x) ((0x1f & (x)) << 1)
99
100#define U3P_U3PHYA_DA_REG0 (SSUSB_SIFSLV_U3PHYA_DA_BASE + 0x0000)
101#define P3A_RG_XTAL_EXT_EN_U3 GENMASK(11, 10)
102#define P3A_RG_XTAL_EXT_EN_U3_VAL(x) ((0x3 & (x)) << 10)
103
104#define U3P_PHYD_CDR1 (SSUSB_SIFSLV_U3PHYD_BASE + 0x005c)
105#define P3D_RG_CDR_BIR_LTD1 GENMASK(28, 24)
106#define P3D_RG_CDR_BIR_LTD1_VAL(x) ((0x1f & (x)) << 24)
107#define P3D_RG_CDR_BIR_LTD0 GENMASK(12, 8)
108#define P3D_RG_CDR_BIR_LTD0_VAL(x) ((0x1f & (x)) << 8)
109
110#define U3P_XTALCTL3 (SSUSB_SIFSLV_SPLLC + 0x0018)
111#define XC3_RG_U3_XTAL_RX_PWD BIT(9)
112#define XC3_RG_U3_FRC_XTAL_RX_PWD BIT(8)
113
114struct mt65xx_phy_instance {
115 struct phy *phy;
116 void __iomem *port_base;
117 u32 index;
118 u8 type;
119};
120
121struct mt65xx_u3phy {
122 struct device *dev;
123 void __iomem *sif_base; /* include sif2, but exclude port's */
124 struct clk *u3phya_ref; /* reference clock of usb3 anolog phy */
125 struct mt65xx_phy_instance **phys;
126 int nphys;
127};
128
129static void phy_instance_init(struct mt65xx_u3phy *u3phy,
130 struct mt65xx_phy_instance *instance)
131{
132 void __iomem *port_base = instance->port_base;
133 u32 index = instance->index;
134 u32 tmp;
135
136 /* switch to USB function. (system register, force ip into usb mode) */
137 tmp = readl(port_base + U3P_U2PHYDTM0);
138 tmp &= ~P2C_FORCE_UART_EN;
139 tmp |= P2C_RG_XCVRSEL_VAL(1) | P2C_RG_DATAIN_VAL(0);
140 writel(tmp, port_base + U3P_U2PHYDTM0);
141
142 tmp = readl(port_base + U3P_U2PHYDTM1);
143 tmp &= ~P2C_RG_UART_EN;
144 writel(tmp, port_base + U3P_U2PHYDTM1);
145
146 if (!index) {
147 tmp = readl(port_base + U3P_U2PHYACR4);
148 tmp &= ~P2C_U2_GPIO_CTR_MSK;
149 writel(tmp, port_base + U3P_U2PHYACR4);
150
151 tmp = readl(port_base + U3P_USBPHYACR2);
152 tmp |= PA2_RG_SIF_U2PLL_FORCE_EN;
153 writel(tmp, port_base + U3P_USBPHYACR2);
154
155 tmp = readl(port_base + U3D_U2PHYDCR0);
156 tmp &= ~P2C_RG_SIF_U2PLL_FORCE_ON;
157 writel(tmp, port_base + U3D_U2PHYDCR0);
158 } else {
159 tmp = readl(port_base + U3D_U2PHYDCR0);
160 tmp |= P2C_RG_SIF_U2PLL_FORCE_ON;
161 writel(tmp, port_base + U3D_U2PHYDCR0);
162
163 tmp = readl(port_base + U3P_U2PHYDTM0);
164 tmp |= P2C_RG_SUSPENDM | P2C_FORCE_SUSPENDM;
165 writel(tmp, port_base + U3P_U2PHYDTM0);
166 }
167
168 /* DP/DM BC1.1 path Disable */
169 tmp = readl(port_base + U3P_USBPHYACR6);
170 tmp &= ~PA6_RG_U2_BC11_SW_EN;
171 writel(tmp, port_base + U3P_USBPHYACR6);
172
173 tmp = readl(port_base + U3P_U3PHYA_DA_REG0);
174 tmp &= ~P3A_RG_XTAL_EXT_EN_U3;
175 tmp |= P3A_RG_XTAL_EXT_EN_U3_VAL(2);
176 writel(tmp, port_base + U3P_U3PHYA_DA_REG0);
177
178 tmp = readl(port_base + U3P_U3_PHYA_REG9);
179 tmp &= ~P3A_RG_RX_DAC_MUX;
180 tmp |= P3A_RG_RX_DAC_MUX_VAL(4);
181 writel(tmp, port_base + U3P_U3_PHYA_REG9);
182
183 tmp = readl(port_base + U3P_U3_PHYA_REG6);
184 tmp &= ~P3A_RG_TX_EIDLE_CM;
185 tmp |= P3A_RG_TX_EIDLE_CM_VAL(0xe);
186 writel(tmp, port_base + U3P_U3_PHYA_REG6);
187
188 tmp = readl(port_base + U3P_PHYD_CDR1);
189 tmp &= ~(P3D_RG_CDR_BIR_LTD0 | P3D_RG_CDR_BIR_LTD1);
190 tmp |= P3D_RG_CDR_BIR_LTD0_VAL(0xc) | P3D_RG_CDR_BIR_LTD1_VAL(0x3);
191 writel(tmp, port_base + U3P_PHYD_CDR1);
192
193 dev_dbg(u3phy->dev, "%s(%d)\n", __func__, index);
194}
195
196static void phy_instance_power_on(struct mt65xx_u3phy *u3phy,
197 struct mt65xx_phy_instance *instance)
198{
199 void __iomem *port_base = instance->port_base;
200 u32 index = instance->index;
201 u32 tmp;
202
203 if (!index) {
204 /* Set RG_SSUSB_VUSB10_ON as 1 after VUSB10 ready */
205 tmp = readl(port_base + U3P_U3_PHYA_REG0);
206 tmp |= P3A_RG_U3_VUSB10_ON;
207 writel(tmp, port_base + U3P_U3_PHYA_REG0);
208 }
209
210 /* (force_suspendm=0) (let suspendm=1, enable usb 480MHz pll) */
211 tmp = readl(port_base + U3P_U2PHYDTM0);
212 tmp &= ~(P2C_FORCE_SUSPENDM | P2C_RG_XCVRSEL);
213 tmp &= ~(P2C_RG_DATAIN | P2C_DTM0_PART_MASK);
214 writel(tmp, port_base + U3P_U2PHYDTM0);
215
216 /* OTG Enable */
217 tmp = readl(port_base + U3P_USBPHYACR6);
218 tmp |= PA6_RG_U2_OTG_VBUSCMP_EN;
219 writel(tmp, port_base + U3P_USBPHYACR6);
220
221 if (!index) {
222 tmp = readl(u3phy->sif_base + U3P_XTALCTL3);
223 tmp |= XC3_RG_U3_XTAL_RX_PWD | XC3_RG_U3_FRC_XTAL_RX_PWD;
224 writel(tmp, u3phy->sif_base + U3P_XTALCTL3);
225
226 /* [mt8173]disable Change 100uA current from SSUSB */
227 tmp = readl(port_base + U3P_USBPHYACR5);
228 tmp &= ~PA5_RG_U2_HS_100U_U3_EN;
229 writel(tmp, port_base + U3P_USBPHYACR5);
230 }
231
232 tmp = readl(port_base + U3P_U2PHYDTM1);
233 tmp |= P2C_RG_VBUSVALID | P2C_RG_AVALID;
234 tmp &= ~P2C_RG_SESSEND;
235 writel(tmp, port_base + U3P_U2PHYDTM1);
236
237 /* USB 2.0 slew rate calibration */
238 tmp = readl(port_base + U3P_USBPHYACR5);
239 tmp &= ~PA5_RG_U2_HSTX_SRCTRL;
240 tmp |= PA5_RG_U2_HSTX_SRCTRL_VAL(4);
241 writel(tmp, port_base + U3P_USBPHYACR5);
242
243 if (index) {
244 tmp = readl(port_base + U3D_U2PHYDCR0);
245 tmp |= P2C_RG_SIF_U2PLL_FORCE_ON;
246 writel(tmp, port_base + U3D_U2PHYDCR0);
247
248 tmp = readl(port_base + U3P_U2PHYDTM0);
249 tmp |= P2C_RG_SUSPENDM | P2C_FORCE_SUSPENDM;
250 writel(tmp, port_base + U3P_U2PHYDTM0);
251 }
252 dev_dbg(u3phy->dev, "%s(%d)\n", __func__, index);
253}
254
255static void phy_instance_power_off(struct mt65xx_u3phy *u3phy,
256 struct mt65xx_phy_instance *instance)
257{
258 void __iomem *port_base = instance->port_base;
259 u32 index = instance->index;
260 u32 tmp;
261
262 tmp = readl(port_base + U3P_U2PHYDTM0);
263 tmp &= ~(P2C_RG_XCVRSEL | P2C_RG_DATAIN);
264 tmp |= P2C_FORCE_SUSPENDM;
265 writel(tmp, port_base + U3P_U2PHYDTM0);
266
267 /* OTG Disable */
268 tmp = readl(port_base + U3P_USBPHYACR6);
269 tmp &= ~PA6_RG_U2_OTG_VBUSCMP_EN;
270 writel(tmp, port_base + U3P_USBPHYACR6);
271
272 if (!index) {
273 /* (also disable)Change 100uA current switch to USB2.0 */
274 tmp = readl(port_base + U3P_USBPHYACR5);
275 tmp &= ~PA5_RG_U2_HS_100U_U3_EN;
276 writel(tmp, port_base + U3P_USBPHYACR5);
277 }
278
279 /* let suspendm=0, set utmi into analog power down */
280 tmp = readl(port_base + U3P_U2PHYDTM0);
281 tmp &= ~P2C_RG_SUSPENDM;
282 writel(tmp, port_base + U3P_U2PHYDTM0);
283 udelay(1);
284
285 tmp = readl(port_base + U3P_U2PHYDTM1);
286 tmp &= ~(P2C_RG_VBUSVALID | P2C_RG_AVALID);
287 tmp |= P2C_RG_SESSEND;
288 writel(tmp, port_base + U3P_U2PHYDTM1);
289
290 if (!index) {
291 tmp = readl(port_base + U3P_U3_PHYA_REG0);
292 tmp &= ~P3A_RG_U3_VUSB10_ON;
293 writel(tmp, port_base + U3P_U3_PHYA_REG0);
294 } else {
295 tmp = readl(port_base + U3D_U2PHYDCR0);
296 tmp &= ~P2C_RG_SIF_U2PLL_FORCE_ON;
297 writel(tmp, port_base + U3D_U2PHYDCR0);
298 }
299
300 dev_dbg(u3phy->dev, "%s(%d)\n", __func__, index);
301}
302
303static void phy_instance_exit(struct mt65xx_u3phy *u3phy,
304 struct mt65xx_phy_instance *instance)
305{
306 void __iomem *port_base = instance->port_base;
307 u32 index = instance->index;
308 u32 tmp;
309
310 if (index) {
311 tmp = readl(port_base + U3D_U2PHYDCR0);
312 tmp &= ~P2C_RG_SIF_U2PLL_FORCE_ON;
313 writel(tmp, port_base + U3D_U2PHYDCR0);
314
315 tmp = readl(port_base + U3P_U2PHYDTM0);
316 tmp &= ~P2C_FORCE_SUSPENDM;
317 writel(tmp, port_base + U3P_U2PHYDTM0);
318 }
319}
320
321static int mt65xx_phy_init(struct phy *phy)
322{
323 struct mt65xx_phy_instance *instance = phy_get_drvdata(phy);
324 struct mt65xx_u3phy *u3phy = dev_get_drvdata(phy->dev.parent);
325 int ret;
326
327 ret = clk_prepare_enable(u3phy->u3phya_ref);
328 if (ret) {
329 dev_err(u3phy->dev, "failed to enable u3phya_ref\n");
330 return ret;
331 }
332
333 phy_instance_init(u3phy, instance);
334 return 0;
335}
336
337static int mt65xx_phy_power_on(struct phy *phy)
338{
339 struct mt65xx_phy_instance *instance = phy_get_drvdata(phy);
340 struct mt65xx_u3phy *u3phy = dev_get_drvdata(phy->dev.parent);
341
342 phy_instance_power_on(u3phy, instance);
343 return 0;
344}
345
346static int mt65xx_phy_power_off(struct phy *phy)
347{
348 struct mt65xx_phy_instance *instance = phy_get_drvdata(phy);
349 struct mt65xx_u3phy *u3phy = dev_get_drvdata(phy->dev.parent);
350
351 phy_instance_power_off(u3phy, instance);
352 return 0;
353}
354
355static int mt65xx_phy_exit(struct phy *phy)
356{
357 struct mt65xx_phy_instance *instance = phy_get_drvdata(phy);
358 struct mt65xx_u3phy *u3phy = dev_get_drvdata(phy->dev.parent);
359
360 phy_instance_exit(u3phy, instance);
361 clk_disable_unprepare(u3phy->u3phya_ref);
362 return 0;
363}
364
365static struct phy *mt65xx_phy_xlate(struct device *dev,
366 struct of_phandle_args *args)
367{
368 struct mt65xx_u3phy *u3phy = dev_get_drvdata(dev);
369 struct mt65xx_phy_instance *instance = NULL;
370 struct device_node *phy_np = args->np;
371 int index;
372
373
374 if (args->args_count != 1) {
375 dev_err(dev, "invalid number of cells in 'phy' property\n");
376 return ERR_PTR(-EINVAL);
377 }
378
379 for (index = 0; index < u3phy->nphys; index++)
380 if (phy_np == u3phy->phys[index]->phy->dev.of_node) {
381 instance = u3phy->phys[index];
382 break;
383 }
384
385 if (!instance) {
386 dev_err(dev, "failed to find appropriate phy\n");
387 return ERR_PTR(-EINVAL);
388 }
389
390 instance->type = args->args[0];
391
392 if (!(instance->type == PHY_TYPE_USB2 ||
393 instance->type == PHY_TYPE_USB3)) {
394 dev_err(dev, "unsupported device type: %d\n", instance->type);
395 return ERR_PTR(-EINVAL);
396 }
397
398 return instance->phy;
399}
400
401static struct phy_ops mt65xx_u3phy_ops = {
402 .init = mt65xx_phy_init,
403 .exit = mt65xx_phy_exit,
404 .power_on = mt65xx_phy_power_on,
405 .power_off = mt65xx_phy_power_off,
406 .owner = THIS_MODULE,
407};
408
409static int mt65xx_u3phy_probe(struct platform_device *pdev)
410{
411 struct device *dev = &pdev->dev;
412 struct device_node *np = dev->of_node;
413 struct device_node *child_np;
414 struct phy_provider *provider;
415 struct resource *sif_res;
416 struct mt65xx_u3phy *u3phy;
417 struct resource res;
418 int port;
419
420 u3phy = devm_kzalloc(dev, sizeof(*u3phy), GFP_KERNEL);
421 if (!u3phy)
422 return -ENOMEM;
423
424 u3phy->nphys = of_get_child_count(np);
425 u3phy->phys = devm_kcalloc(dev, u3phy->nphys,
426 sizeof(*u3phy->phys), GFP_KERNEL);
427 if (!u3phy->phys)
428 return -ENOMEM;
429
430 u3phy->dev = dev;
431 platform_set_drvdata(pdev, u3phy);
432
433 sif_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
434 u3phy->sif_base = devm_ioremap_resource(dev, sif_res);
435 if (IS_ERR(u3phy->sif_base)) {
436 dev_err(dev, "failed to remap sif regs\n");
437 return PTR_ERR(u3phy->sif_base);
438 }
439
440 u3phy->u3phya_ref = devm_clk_get(dev, "u3phya_ref");
441 if (IS_ERR(u3phy->u3phya_ref)) {
442 dev_err(dev, "error to get u3phya_ref\n");
443 return PTR_ERR(u3phy->u3phya_ref);
444 }
445
446 port = 0;
447 for_each_child_of_node(np, child_np) {
448 struct mt65xx_phy_instance *instance;
449 struct phy *phy;
450 int retval;
451
452 instance = devm_kzalloc(dev, sizeof(*instance), GFP_KERNEL);
453 if (!instance)
454 return -ENOMEM;
455
456 u3phy->phys[port] = instance;
457
458 phy = devm_phy_create(dev, child_np, &mt65xx_u3phy_ops);
459 if (IS_ERR(phy)) {
460 dev_err(dev, "failed to create phy\n");
461 return PTR_ERR(phy);
462 }
463
464 retval = of_address_to_resource(child_np, 0, &res);
465 if (retval) {
466 dev_err(dev, "failed to get address resource(id-%d)\n",
467 port);
468 return retval;
469 }
470
471 instance->port_base = devm_ioremap_resource(&phy->dev, &res);
472 if (IS_ERR(instance->port_base)) {
473 dev_err(dev, "failed to remap phy regs\n");
474 return PTR_ERR(instance->port_base);
475 }
476
477 instance->phy = phy;
478 instance->index = port;
479 phy_set_drvdata(phy, instance);
480 port++;
481 }
482
483 provider = devm_of_phy_provider_register(dev, mt65xx_phy_xlate);
484
485 return PTR_ERR_OR_ZERO(provider);
486}
487
488static const struct of_device_id mt65xx_u3phy_id_table[] = {
489 { .compatible = "mediatek,mt8173-u3phy", },
490 { },
491};
492MODULE_DEVICE_TABLE(of, mt65xx_u3phy_id_table);
493
494static struct platform_driver mt65xx_u3phy_driver = {
495 .probe = mt65xx_u3phy_probe,
496 .driver = {
497 .name = "mt65xx-u3phy",
498 .of_match_table = mt65xx_u3phy_id_table,
499 },
500};
501
502module_platform_driver(mt65xx_u3phy_driver);
503
504MODULE_AUTHOR("Chunfeng Yun <chunfeng.yun@mediatek.com>");
505MODULE_DESCRIPTION("mt65xx USB PHY driver");
506MODULE_LICENSE("GPL v2");
diff --git a/drivers/phy/phy-samsung-usb2.c b/drivers/phy/phy-samsung-usb2.c
index f278a9c547e1..1d22d93b552d 100644
--- a/drivers/phy/phy-samsung-usb2.c
+++ b/drivers/phy/phy-samsung-usb2.c
@@ -27,6 +27,13 @@ static int samsung_usb2_phy_power_on(struct phy *phy)
27 27
28 dev_dbg(drv->dev, "Request to power_on \"%s\" usb phy\n", 28 dev_dbg(drv->dev, "Request to power_on \"%s\" usb phy\n",
29 inst->cfg->label); 29 inst->cfg->label);
30
31 if (drv->vbus) {
32 ret = regulator_enable(drv->vbus);
33 if (ret)
34 goto err_regulator;
35 }
36
30 ret = clk_prepare_enable(drv->clk); 37 ret = clk_prepare_enable(drv->clk);
31 if (ret) 38 if (ret)
32 goto err_main_clk; 39 goto err_main_clk;
@@ -48,6 +55,9 @@ err_power_on:
48err_instance_clk: 55err_instance_clk:
49 clk_disable_unprepare(drv->clk); 56 clk_disable_unprepare(drv->clk);
50err_main_clk: 57err_main_clk:
58 if (drv->vbus)
59 regulator_disable(drv->vbus);
60err_regulator:
51 return ret; 61 return ret;
52} 62}
53 63
@@ -55,7 +65,7 @@ static int samsung_usb2_phy_power_off(struct phy *phy)
55{ 65{
56 struct samsung_usb2_phy_instance *inst = phy_get_drvdata(phy); 66 struct samsung_usb2_phy_instance *inst = phy_get_drvdata(phy);
57 struct samsung_usb2_phy_driver *drv = inst->drv; 67 struct samsung_usb2_phy_driver *drv = inst->drv;
58 int ret; 68 int ret = 0;
59 69
60 dev_dbg(drv->dev, "Request to power_off \"%s\" usb phy\n", 70 dev_dbg(drv->dev, "Request to power_off \"%s\" usb phy\n",
61 inst->cfg->label); 71 inst->cfg->label);
@@ -68,7 +78,10 @@ static int samsung_usb2_phy_power_off(struct phy *phy)
68 } 78 }
69 clk_disable_unprepare(drv->ref_clk); 79 clk_disable_unprepare(drv->ref_clk);
70 clk_disable_unprepare(drv->clk); 80 clk_disable_unprepare(drv->clk);
71 return 0; 81 if (drv->vbus)
82 ret = regulator_disable(drv->vbus);
83
84 return ret;
72} 85}
73 86
74static const struct phy_ops samsung_usb2_phy_ops = { 87static const struct phy_ops samsung_usb2_phy_ops = {
@@ -203,6 +216,14 @@ static int samsung_usb2_phy_probe(struct platform_device *pdev)
203 return ret; 216 return ret;
204 } 217 }
205 218
219 drv->vbus = devm_regulator_get(dev, "vbus");
220 if (IS_ERR(drv->vbus)) {
221 ret = PTR_ERR(drv->vbus);
222 if (ret == -EPROBE_DEFER)
223 return ret;
224 drv->vbus = NULL;
225 }
226
206 for (i = 0; i < drv->cfg->num_phys; i++) { 227 for (i = 0; i < drv->cfg->num_phys; i++) {
207 char *label = drv->cfg->phys[i].label; 228 char *label = drv->cfg->phys[i].label;
208 struct samsung_usb2_phy_instance *p = &drv->instances[i]; 229 struct samsung_usb2_phy_instance *p = &drv->instances[i];
diff --git a/drivers/phy/phy-samsung-usb2.h b/drivers/phy/phy-samsung-usb2.h
index 44bead9b8f34..6563e7ca0ac4 100644
--- a/drivers/phy/phy-samsung-usb2.h
+++ b/drivers/phy/phy-samsung-usb2.h
@@ -17,6 +17,7 @@
17#include <linux/device.h> 17#include <linux/device.h>
18#include <linux/regmap.h> 18#include <linux/regmap.h>
19#include <linux/spinlock.h> 19#include <linux/spinlock.h>
20#include <linux/regulator/consumer.h>
20 21
21#define KHZ 1000 22#define KHZ 1000
22#define MHZ (KHZ * KHZ) 23#define MHZ (KHZ * KHZ)
@@ -37,6 +38,7 @@ struct samsung_usb2_phy_driver {
37 const struct samsung_usb2_phy_config *cfg; 38 const struct samsung_usb2_phy_config *cfg;
38 struct clk *clk; 39 struct clk *clk;
39 struct clk *ref_clk; 40 struct clk *ref_clk;
41 struct regulator *vbus;
40 unsigned long ref_rate; 42 unsigned long ref_rate;
41 u32 ref_reg_val; 43 u32 ref_reg_val;
42 struct device *dev; 44 struct device *dev;
diff --git a/drivers/phy/phy-sun4i-usb.c b/drivers/phy/phy-sun4i-usb.c
index 731b395d6e6a..b12964b70625 100644
--- a/drivers/phy/phy-sun4i-usb.c
+++ b/drivers/phy/phy-sun4i-usb.c
@@ -551,19 +551,15 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev)
551 if (IS_ERR(data->base)) 551 if (IS_ERR(data->base))
552 return PTR_ERR(data->base); 552 return PTR_ERR(data->base);
553 553
554 data->id_det_gpio = devm_gpiod_get(dev, "usb0_id_det", GPIOD_IN); 554 data->id_det_gpio = devm_gpiod_get_optional(dev, "usb0_id_det",
555 if (IS_ERR(data->id_det_gpio)) { 555 GPIOD_IN);
556 if (PTR_ERR(data->id_det_gpio) == -EPROBE_DEFER) 556 if (IS_ERR(data->id_det_gpio))
557 return -EPROBE_DEFER; 557 return PTR_ERR(data->id_det_gpio);
558 data->id_det_gpio = NULL; 558
559 } 559 data->vbus_det_gpio = devm_gpiod_get_optional(dev, "usb0_vbus_det",
560 560 GPIOD_IN);
561 data->vbus_det_gpio = devm_gpiod_get(dev, "usb0_vbus_det", GPIOD_IN); 561 if (IS_ERR(data->vbus_det_gpio))
562 if (IS_ERR(data->vbus_det_gpio)) { 562 return PTR_ERR(data->vbus_det_gpio);
563 if (PTR_ERR(data->vbus_det_gpio) == -EPROBE_DEFER)
564 return -EPROBE_DEFER;
565 data->vbus_det_gpio = NULL;
566 }
567 563
568 if (of_find_property(np, "usb0_vbus_power-supply", NULL)) { 564 if (of_find_property(np, "usb0_vbus_power-supply", NULL)) {
569 data->vbus_power_supply = devm_power_supply_get_by_phandle(dev, 565 data->vbus_power_supply = devm_power_supply_get_by_phandle(dev,