aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>2016-07-13 23:03:50 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2016-07-13 23:03:50 -0400
commitca2b6faeb96d6d71ebc0627d6679f7b6667cfb00 (patch)
treef05df9d14c6cf7669caf2c368c597e4f82f290fb
parent25b1f9acc452209ae0fcc8c1332be852b5c52f53 (diff)
parentc14f8a4032efa73d9c4e155add47c19252b3bdf4 (diff)
Merge tag 'phy-for-4.8-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/kishon/linux-phy into usb-testing
Kishon writes: phy: for 4.8 -rc1 *) Add a new phy_ops for setting the phy mode *) Add a new phy driver for DA8xx SoC USB PHY *) Minor fixes and cleanups Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
-rw-r--r--Documentation/devicetree/bindings/phy/phy-da8xx-usb.txt40
-rw-r--r--Documentation/devicetree/bindings/phy/rockchip-usb-phy.txt27
-rw-r--r--drivers/phy/Kconfig10
-rw-r--r--drivers/phy/Makefile1
-rw-r--r--drivers/phy/phy-core.c15
-rw-r--r--drivers/phy/phy-da8xx-usb.c245
-rw-r--r--drivers/phy/phy-qcom-ufs-qmp-14nm.c1
-rw-r--r--drivers/phy/phy-qcom-ufs-qmp-20nm.c1
-rw-r--r--drivers/phy/phy-rcar-gen3-usb2.c26
-rw-r--r--drivers/phy/phy-rockchip-usb.c23
-rw-r--r--drivers/phy/phy-sun4i-usb.c34
-rw-r--r--drivers/phy/phy-xgene.c4
-rw-r--r--include/linux/phy/phy.h17
13 files changed, 408 insertions, 36 deletions
diff --git a/Documentation/devicetree/bindings/phy/phy-da8xx-usb.txt b/Documentation/devicetree/bindings/phy/phy-da8xx-usb.txt
new file mode 100644
index 000000000000..c26478be391b
--- /dev/null
+++ b/Documentation/devicetree/bindings/phy/phy-da8xx-usb.txt
@@ -0,0 +1,40 @@
1TI DA8xx/OMAP-L1xx/AM18xx USB PHY
2
3Required properties:
4 - compatible: must be "ti,da830-usb-phy".
5 - #phy-cells: must be 1.
6
7This device controls the PHY for both the USB 1.1 OHCI and USB 2.0 OTG
8controllers on DA8xx SoCs. Consumers of this device should use index 0 for
9the USB 2.0 phy device and index 1 for the USB 1.1 phy device.
10
11It also requires a "syscon" node with compatible = "ti,da830-cfgchip", "syscon"
12to access the CFGCHIP2 register.
13
14Example:
15
16 cfgchip: cfgchip@1417c {
17 compatible = "ti,da830-cfgchip", "syscon";
18 reg = <0x1417c 0x14>;
19 };
20
21 usb_phy: usb-phy {
22 compatible = "ti,da830-usb-phy";
23 #phy-cells = <1>;
24 };
25
26 usb20: usb@200000 {
27 compatible = "ti,da830-musb";
28 reg = <0x200000 0x1000>;
29 interrupts = <58>;
30 phys = <&usb_phy 0>;
31 phy-names = "usb-phy";
32 };
33
34 usb11: usb@225000 {
35 compatible = "ti,da830-ohci";
36 reg = <0x225000 0x1000>;
37 interrupts = <59>;
38 phys = <&usb_phy 1>;
39 phy-names = "usb-phy";
40 };
diff --git a/Documentation/devicetree/bindings/phy/rockchip-usb-phy.txt b/Documentation/devicetree/bindings/phy/rockchip-usb-phy.txt
index 68498d560354..cc6be9680a6d 100644
--- a/Documentation/devicetree/bindings/phy/rockchip-usb-phy.txt
+++ b/Documentation/devicetree/bindings/phy/rockchip-usb-phy.txt
@@ -5,11 +5,13 @@ Required properties:
5 "rockchip,rk3066a-usb-phy" 5 "rockchip,rk3066a-usb-phy"
6 "rockchip,rk3188-usb-phy" 6 "rockchip,rk3188-usb-phy"
7 "rockchip,rk3288-usb-phy" 7 "rockchip,rk3288-usb-phy"
8 - rockchip,grf : phandle to the syscon managing the "general
9 register files"
10 - #address-cells: should be 1 8 - #address-cells: should be 1
11 - #size-cells: should be 0 9 - #size-cells: should be 0
12 10
11Deprecated properties:
12 - rockchip,grf : phandle to the syscon managing the "general
13 register files" - phy should be a child of the GRF instead
14
13Sub-nodes: 15Sub-nodes:
14Each PHY should be represented as a sub-node. 16Each PHY should be represented as a sub-node.
15 17
@@ -28,14 +30,19 @@ Optional Properties:
28 30
29Example: 31Example:
30 32
31usbphy: phy { 33grf: syscon@ff770000 {
32 compatible = "rockchip,rk3288-usb-phy"; 34 compatible = "rockchip,rk3288-grf", "syscon", "simple-mfd";
33 rockchip,grf = <&grf>; 35
34 #address-cells = <1>; 36...
35 #size-cells = <0>; 37
38 usbphy: phy {
39 compatible = "rockchip,rk3288-usb-phy";
40 #address-cells = <1>;
41 #size-cells = <0>;
36 42
37 usbphy0: usb-phy0 { 43 usbphy0: usb-phy0 {
38 #phy-cells = <0>; 44 #phy-cells = <0>;
39 reg = <0x320>; 45 reg = <0x320>;
46 };
40 }; 47 };
41}; 48};
diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index 8d1cfb7f3ea2..cc0b69545385 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -44,6 +44,16 @@ config ARMADA375_USBCLUSTER_PHY
44 depends on OF && HAS_IOMEM 44 depends on OF && HAS_IOMEM
45 select GENERIC_PHY 45 select GENERIC_PHY
46 46
47config PHY_DA8XX_USB
48 tristate "TI DA8xx USB PHY Driver"
49 depends on ARCH_DAVINCI_DA8XX
50 select GENERIC_PHY
51 select MFD_SYSCON
52 help
53 Enable this to support the USB PHY on DA8xx SoCs.
54
55 This driver controls both the USB 1.1 PHY and the USB 2.0 PHY.
56
47config PHY_DM816X_USB 57config PHY_DM816X_USB
48 tristate "TI dm816x USB PHY driver" 58 tristate "TI dm816x USB PHY driver"
49 depends on ARCH_OMAP2PLUS 59 depends on ARCH_OMAP2PLUS
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
index 9c3e73ccabc4..fa8480e89724 100644
--- a/drivers/phy/Makefile
+++ b/drivers/phy/Makefile
@@ -6,6 +6,7 @@ obj-$(CONFIG_GENERIC_PHY) += phy-core.o
6obj-$(CONFIG_PHY_BCM_NS_USB2) += phy-bcm-ns-usb2.o 6obj-$(CONFIG_PHY_BCM_NS_USB2) += phy-bcm-ns-usb2.o
7obj-$(CONFIG_PHY_BERLIN_USB) += phy-berlin-usb.o 7obj-$(CONFIG_PHY_BERLIN_USB) += phy-berlin-usb.o
8obj-$(CONFIG_PHY_BERLIN_SATA) += phy-berlin-sata.o 8obj-$(CONFIG_PHY_BERLIN_SATA) += phy-berlin-sata.o
9obj-$(CONFIG_PHY_DA8XX_USB) += phy-da8xx-usb.o
9obj-$(CONFIG_PHY_DM816X_USB) += phy-dm816x-usb.o 10obj-$(CONFIG_PHY_DM816X_USB) += phy-dm816x-usb.o
10obj-$(CONFIG_ARMADA375_USBCLUSTER_PHY) += phy-armada375-usb2.o 11obj-$(CONFIG_ARMADA375_USBCLUSTER_PHY) += phy-armada375-usb2.o
11obj-$(CONFIG_BCM_KONA_USB2_PHY) += phy-bcm-kona-usb2.o 12obj-$(CONFIG_BCM_KONA_USB2_PHY) += phy-bcm-kona-usb2.o
diff --git a/drivers/phy/phy-core.c b/drivers/phy/phy-core.c
index b72e9a3b6429..8eca906b6e70 100644
--- a/drivers/phy/phy-core.c
+++ b/drivers/phy/phy-core.c
@@ -342,6 +342,21 @@ int phy_power_off(struct phy *phy)
342} 342}
343EXPORT_SYMBOL_GPL(phy_power_off); 343EXPORT_SYMBOL_GPL(phy_power_off);
344 344
345int phy_set_mode(struct phy *phy, enum phy_mode mode)
346{
347 int ret;
348
349 if (!phy || !phy->ops->set_mode)
350 return 0;
351
352 mutex_lock(&phy->mutex);
353 ret = phy->ops->set_mode(phy, mode);
354 mutex_unlock(&phy->mutex);
355
356 return ret;
357}
358EXPORT_SYMBOL_GPL(phy_set_mode);
359
345/** 360/**
346 * _of_phy_get() - lookup and obtain a reference to a phy by phandle 361 * _of_phy_get() - lookup and obtain a reference to a phy by phandle
347 * @np: device_node for which to get the phy 362 * @np: device_node for which to get the phy
diff --git a/drivers/phy/phy-da8xx-usb.c b/drivers/phy/phy-da8xx-usb.c
new file mode 100644
index 000000000000..b2e59b6170ac
--- /dev/null
+++ b/drivers/phy/phy-da8xx-usb.c
@@ -0,0 +1,245 @@
1/*
2 * phy-da8xx-usb - TI DaVinci DA8xx USB PHY driver
3 *
4 * Copyright (C) 2016 David Lechner <david@lechnology.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 */
15
16#include <linux/clk.h>
17#include <linux/io.h>
18#include <linux/of.h>
19#include <linux/mfd/da8xx-cfgchip.h>
20#include <linux/mfd/syscon.h>
21#include <linux/module.h>
22#include <linux/phy/phy.h>
23#include <linux/platform_device.h>
24#include <linux/regmap.h>
25
26struct da8xx_usb_phy {
27 struct phy_provider *phy_provider;
28 struct phy *usb11_phy;
29 struct phy *usb20_phy;
30 struct clk *usb11_clk;
31 struct clk *usb20_clk;
32 struct regmap *regmap;
33};
34
35static int da8xx_usb11_phy_power_on(struct phy *phy)
36{
37 struct da8xx_usb_phy *d_phy = phy_get_drvdata(phy);
38 int ret;
39
40 ret = clk_prepare_enable(d_phy->usb11_clk);
41 if (ret)
42 return ret;
43
44 regmap_write_bits(d_phy->regmap, CFGCHIP(2), CFGCHIP2_USB1SUSPENDM,
45 CFGCHIP2_USB1SUSPENDM);
46
47 return 0;
48}
49
50static int da8xx_usb11_phy_power_off(struct phy *phy)
51{
52 struct da8xx_usb_phy *d_phy = phy_get_drvdata(phy);
53
54 regmap_write_bits(d_phy->regmap, CFGCHIP(2), CFGCHIP2_USB1SUSPENDM, 0);
55
56 clk_disable_unprepare(d_phy->usb11_clk);
57
58 return 0;
59}
60
61static const struct phy_ops da8xx_usb11_phy_ops = {
62 .power_on = da8xx_usb11_phy_power_on,
63 .power_off = da8xx_usb11_phy_power_off,
64 .owner = THIS_MODULE,
65};
66
67static int da8xx_usb20_phy_power_on(struct phy *phy)
68{
69 struct da8xx_usb_phy *d_phy = phy_get_drvdata(phy);
70 int ret;
71
72 ret = clk_prepare_enable(d_phy->usb20_clk);
73 if (ret)
74 return ret;
75
76 regmap_write_bits(d_phy->regmap, CFGCHIP(2), CFGCHIP2_OTGPWRDN, 0);
77
78 return 0;
79}
80
81static int da8xx_usb20_phy_power_off(struct phy *phy)
82{
83 struct da8xx_usb_phy *d_phy = phy_get_drvdata(phy);
84
85 regmap_write_bits(d_phy->regmap, CFGCHIP(2), CFGCHIP2_OTGPWRDN,
86 CFGCHIP2_OTGPWRDN);
87
88 clk_disable_unprepare(d_phy->usb20_clk);
89
90 return 0;
91}
92
93static int da8xx_usb20_phy_set_mode(struct phy *phy, enum phy_mode mode)
94{
95 struct da8xx_usb_phy *d_phy = phy_get_drvdata(phy);
96 u32 val;
97
98 switch (mode) {
99 case PHY_MODE_USB_HOST: /* Force VBUS valid, ID = 0 */
100 val = CFGCHIP2_OTGMODE_FORCE_HOST;
101 break;
102 case PHY_MODE_USB_DEVICE: /* Force VBUS valid, ID = 1 */
103 val = CFGCHIP2_OTGMODE_FORCE_DEVICE;
104 break;
105 case PHY_MODE_USB_OTG: /* Don't override the VBUS/ID comparators */
106 val = CFGCHIP2_OTGMODE_NO_OVERRIDE;
107 break;
108 default:
109 return -EINVAL;
110 }
111
112 regmap_write_bits(d_phy->regmap, CFGCHIP(2), CFGCHIP2_OTGMODE_MASK,
113 val);
114
115 return 0;
116}
117
118static const struct phy_ops da8xx_usb20_phy_ops = {
119 .power_on = da8xx_usb20_phy_power_on,
120 .power_off = da8xx_usb20_phy_power_off,
121 .set_mode = da8xx_usb20_phy_set_mode,
122 .owner = THIS_MODULE,
123};
124
125static struct phy *da8xx_usb_phy_of_xlate(struct device *dev,
126 struct of_phandle_args *args)
127{
128 struct da8xx_usb_phy *d_phy = dev_get_drvdata(dev);
129
130 if (!d_phy)
131 return ERR_PTR(-ENODEV);
132
133 switch (args->args[0]) {
134 case 0:
135 return d_phy->usb20_phy;
136 case 1:
137 return d_phy->usb11_phy;
138 default:
139 return ERR_PTR(-EINVAL);
140 }
141}
142
143static int da8xx_usb_phy_probe(struct platform_device *pdev)
144{
145 struct device *dev = &pdev->dev;
146 struct device_node *node = dev->of_node;
147 struct da8xx_usb_phy *d_phy;
148
149 d_phy = devm_kzalloc(dev, sizeof(*d_phy), GFP_KERNEL);
150 if (!d_phy)
151 return -ENOMEM;
152
153 if (node)
154 d_phy->regmap = syscon_regmap_lookup_by_compatible(
155 "ti,da830-cfgchip");
156 else
157 d_phy->regmap = syscon_regmap_lookup_by_pdevname("syscon.0");
158 if (IS_ERR(d_phy->regmap)) {
159 dev_err(dev, "Failed to get syscon\n");
160 return PTR_ERR(d_phy->regmap);
161 }
162
163 d_phy->usb11_clk = devm_clk_get(dev, "usb11_phy");
164 if (IS_ERR(d_phy->usb11_clk)) {
165 dev_err(dev, "Failed to get usb11_phy clock\n");
166 return PTR_ERR(d_phy->usb11_clk);
167 }
168
169 d_phy->usb20_clk = devm_clk_get(dev, "usb20_phy");
170 if (IS_ERR(d_phy->usb20_clk)) {
171 dev_err(dev, "Failed to get usb20_phy clock\n");
172 return PTR_ERR(d_phy->usb20_clk);
173 }
174
175 d_phy->usb11_phy = devm_phy_create(dev, node, &da8xx_usb11_phy_ops);
176 if (IS_ERR(d_phy->usb11_phy)) {
177 dev_err(dev, "Failed to create usb11 phy\n");
178 return PTR_ERR(d_phy->usb11_phy);
179 }
180
181 d_phy->usb20_phy = devm_phy_create(dev, node, &da8xx_usb20_phy_ops);
182 if (IS_ERR(d_phy->usb20_phy)) {
183 dev_err(dev, "Failed to create usb20 phy\n");
184 return PTR_ERR(d_phy->usb20_phy);
185 }
186
187 platform_set_drvdata(pdev, d_phy);
188 phy_set_drvdata(d_phy->usb11_phy, d_phy);
189 phy_set_drvdata(d_phy->usb20_phy, d_phy);
190
191 if (node) {
192 d_phy->phy_provider = devm_of_phy_provider_register(dev,
193 da8xx_usb_phy_of_xlate);
194 if (IS_ERR(d_phy->phy_provider)) {
195 dev_err(dev, "Failed to create phy provider\n");
196 return PTR_ERR(d_phy->phy_provider);
197 }
198 } else {
199 int ret;
200
201 ret = phy_create_lookup(d_phy->usb11_phy, "usb-phy", "ohci.0");
202 if (ret)
203 dev_warn(dev, "Failed to create usb11 phy lookup\n");
204 ret = phy_create_lookup(d_phy->usb20_phy, "usb-phy",
205 "musb-da8xx");
206 if (ret)
207 dev_warn(dev, "Failed to create usb20 phy lookup\n");
208 }
209
210 return 0;
211}
212
213static int da8xx_usb_phy_remove(struct platform_device *pdev)
214{
215 struct da8xx_usb_phy *d_phy = platform_get_drvdata(pdev);
216
217 if (!pdev->dev.of_node) {
218 phy_remove_lookup(d_phy->usb20_phy, "usb-phy", "musb-da8xx");
219 phy_remove_lookup(d_phy->usb11_phy, "usb-phy", "ohci.0");
220 }
221
222 return 0;
223}
224
225static const struct of_device_id da8xx_usb_phy_ids[] = {
226 { .compatible = "ti,da830-usb-phy" },
227 { }
228};
229MODULE_DEVICE_TABLE(of, da8xx_usb_phy_ids);
230
231static struct platform_driver da8xx_usb_phy_driver = {
232 .probe = da8xx_usb_phy_probe,
233 .remove = da8xx_usb_phy_remove,
234 .driver = {
235 .name = "da8xx-usb-phy",
236 .of_match_table = da8xx_usb_phy_ids,
237 },
238};
239
240module_platform_driver(da8xx_usb_phy_driver);
241
242MODULE_ALIAS("platform:da8xx-usb-phy");
243MODULE_AUTHOR("David Lechner <david@lechnology.com>");
244MODULE_DESCRIPTION("TI DA8xx USB PHY driver");
245MODULE_LICENSE("GPL v2");
diff --git a/drivers/phy/phy-qcom-ufs-qmp-14nm.c b/drivers/phy/phy-qcom-ufs-qmp-14nm.c
index 56631e77c11d..6ee51490f786 100644
--- a/drivers/phy/phy-qcom-ufs-qmp-14nm.c
+++ b/drivers/phy/phy-qcom-ufs-qmp-14nm.c
@@ -140,7 +140,6 @@ static int ufs_qcom_phy_qmp_14nm_probe(struct platform_device *pdev)
140 140
141 phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL); 141 phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL);
142 if (!phy) { 142 if (!phy) {
143 dev_err(dev, "%s: failed to allocate phy\n", __func__);
144 err = -ENOMEM; 143 err = -ENOMEM;
145 goto out; 144 goto out;
146 } 145 }
diff --git a/drivers/phy/phy-qcom-ufs-qmp-20nm.c b/drivers/phy/phy-qcom-ufs-qmp-20nm.c
index b16ea77d07b9..770087ab05e2 100644
--- a/drivers/phy/phy-qcom-ufs-qmp-20nm.c
+++ b/drivers/phy/phy-qcom-ufs-qmp-20nm.c
@@ -196,7 +196,6 @@ static int ufs_qcom_phy_qmp_20nm_probe(struct platform_device *pdev)
196 196
197 phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL); 197 phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL);
198 if (!phy) { 198 if (!phy) {
199 dev_err(dev, "%s: failed to allocate phy\n", __func__);
200 err = -ENOMEM; 199 err = -ENOMEM;
201 goto out; 200 goto out;
202 } 201 }
diff --git a/drivers/phy/phy-rcar-gen3-usb2.c b/drivers/phy/phy-rcar-gen3-usb2.c
index 4be3f5dbbc9f..31156c9c4707 100644
--- a/drivers/phy/phy-rcar-gen3-usb2.c
+++ b/drivers/phy/phy-rcar-gen3-usb2.c
@@ -21,6 +21,7 @@
21#include <linux/phy/phy.h> 21#include <linux/phy/phy.h>
22#include <linux/platform_device.h> 22#include <linux/platform_device.h>
23#include <linux/regulator/consumer.h> 23#include <linux/regulator/consumer.h>
24#include <linux/workqueue.h>
24 25
25/******* USB2.0 Host registers (original offset is +0x200) *******/ 26/******* USB2.0 Host registers (original offset is +0x200) *******/
26#define USB2_INT_ENABLE 0x000 27#define USB2_INT_ENABLE 0x000
@@ -81,9 +82,25 @@ struct rcar_gen3_chan {
81 struct extcon_dev *extcon; 82 struct extcon_dev *extcon;
82 struct phy *phy; 83 struct phy *phy;
83 struct regulator *vbus; 84 struct regulator *vbus;
85 struct work_struct work;
86 bool extcon_host;
84 bool has_otg; 87 bool has_otg;
85}; 88};
86 89
90static void rcar_gen3_phy_usb2_work(struct work_struct *work)
91{
92 struct rcar_gen3_chan *ch = container_of(work, struct rcar_gen3_chan,
93 work);
94
95 if (ch->extcon_host) {
96 extcon_set_cable_state_(ch->extcon, EXTCON_USB_HOST, true);
97 extcon_set_cable_state_(ch->extcon, EXTCON_USB, false);
98 } else {
99 extcon_set_cable_state_(ch->extcon, EXTCON_USB_HOST, false);
100 extcon_set_cable_state_(ch->extcon, EXTCON_USB, true);
101 }
102}
103
87static void rcar_gen3_set_host_mode(struct rcar_gen3_chan *ch, int host) 104static void rcar_gen3_set_host_mode(struct rcar_gen3_chan *ch, int host)
88{ 105{
89 void __iomem *usb2_base = ch->base; 106 void __iomem *usb2_base = ch->base;
@@ -130,8 +147,8 @@ static void rcar_gen3_init_for_host(struct rcar_gen3_chan *ch)
130 rcar_gen3_set_host_mode(ch, 1); 147 rcar_gen3_set_host_mode(ch, 1);
131 rcar_gen3_enable_vbus_ctrl(ch, 1); 148 rcar_gen3_enable_vbus_ctrl(ch, 1);
132 149
133 extcon_set_cable_state_(ch->extcon, EXTCON_USB_HOST, true); 150 ch->extcon_host = true;
134 extcon_set_cable_state_(ch->extcon, EXTCON_USB, false); 151 schedule_work(&ch->work);
135} 152}
136 153
137static void rcar_gen3_init_for_peri(struct rcar_gen3_chan *ch) 154static void rcar_gen3_init_for_peri(struct rcar_gen3_chan *ch)
@@ -140,8 +157,8 @@ static void rcar_gen3_init_for_peri(struct rcar_gen3_chan *ch)
140 rcar_gen3_set_host_mode(ch, 0); 157 rcar_gen3_set_host_mode(ch, 0);
141 rcar_gen3_enable_vbus_ctrl(ch, 0); 158 rcar_gen3_enable_vbus_ctrl(ch, 0);
142 159
143 extcon_set_cable_state_(ch->extcon, EXTCON_USB_HOST, false); 160 ch->extcon_host = false;
144 extcon_set_cable_state_(ch->extcon, EXTCON_USB, true); 161 schedule_work(&ch->work);
145} 162}
146 163
147static bool rcar_gen3_check_id(struct rcar_gen3_chan *ch) 164static bool rcar_gen3_check_id(struct rcar_gen3_chan *ch)
@@ -301,6 +318,7 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev)
301 if (irq >= 0) { 318 if (irq >= 0) {
302 int ret; 319 int ret;
303 320
321 INIT_WORK(&channel->work, rcar_gen3_phy_usb2_work);
304 irq = devm_request_irq(dev, irq, rcar_gen3_phy_usb2_irq, 322 irq = devm_request_irq(dev, irq, rcar_gen3_phy_usb2_irq,
305 IRQF_SHARED, dev_name(dev), channel); 323 IRQF_SHARED, dev_name(dev), channel);
306 if (irq < 0) 324 if (irq < 0)
diff --git a/drivers/phy/phy-rockchip-usb.c b/drivers/phy/phy-rockchip-usb.c
index d60b149cff0f..2a7381f4fe4c 100644
--- a/drivers/phy/phy-rockchip-usb.c
+++ b/drivers/phy/phy-rockchip-usb.c
@@ -236,9 +236,10 @@ static int rockchip_usb_phy_init(struct rockchip_usb_phy_base *base,
236 goto err_clk_prov; 236 goto err_clk_prov;
237 } 237 }
238 238
239 err = devm_add_action(base->dev, rockchip_usb_phy_action, rk_phy); 239 err = devm_add_action_or_reset(base->dev, rockchip_usb_phy_action,
240 rk_phy);
240 if (err) 241 if (err)
241 goto err_devm_action; 242 return err;
242 243
243 rk_phy->phy = devm_phy_create(base->dev, child, &ops); 244 rk_phy->phy = devm_phy_create(base->dev, child, &ops);
244 if (IS_ERR(rk_phy->phy)) { 245 if (IS_ERR(rk_phy->phy)) {
@@ -256,9 +257,6 @@ static int rockchip_usb_phy_init(struct rockchip_usb_phy_base *base,
256 else 257 else
257 return rockchip_usb_phy_power(rk_phy, 1); 258 return rockchip_usb_phy_power(rk_phy, 1);
258 259
259err_devm_action:
260 if (!rk_phy->uart_enabled)
261 of_clk_del_provider(child);
262err_clk_prov: 260err_clk_prov:
263 if (!rk_phy->uart_enabled) 261 if (!rk_phy->uart_enabled)
264 clk_unregister(rk_phy->clk480m); 262 clk_unregister(rk_phy->clk480m);
@@ -397,8 +395,13 @@ static int rockchip_usb_phy_probe(struct platform_device *pdev)
397 phy_base->pdata = match->data; 395 phy_base->pdata = match->data;
398 396
399 phy_base->dev = dev; 397 phy_base->dev = dev;
400 phy_base->reg_base = syscon_regmap_lookup_by_phandle(dev->of_node, 398 phy_base->reg_base = ERR_PTR(-ENODEV);
401 "rockchip,grf"); 399 if (dev->parent && dev->parent->of_node)
400 phy_base->reg_base = syscon_node_to_regmap(
401 dev->parent->of_node);
402 if (IS_ERR(phy_base->reg_base))
403 phy_base->reg_base = syscon_regmap_lookup_by_phandle(
404 dev->of_node, "rockchip,grf");
402 if (IS_ERR(phy_base->reg_base)) { 405 if (IS_ERR(phy_base->reg_base)) {
403 dev_err(&pdev->dev, "Missing rockchip,grf property\n"); 406 dev_err(&pdev->dev, "Missing rockchip,grf property\n");
404 return PTR_ERR(phy_base->reg_base); 407 return PTR_ERR(phy_base->reg_base);
@@ -463,7 +466,11 @@ static int __init rockchip_init_usb_uart(void)
463 return -ENOTSUPP; 466 return -ENOTSUPP;
464 } 467 }
465 468
466 grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf"); 469 grf = ERR_PTR(-ENODEV);
470 if (np->parent)
471 grf = syscon_node_to_regmap(np->parent);
472 if (IS_ERR(grf))
473 grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf");
467 if (IS_ERR(grf)) { 474 if (IS_ERR(grf)) {
468 pr_err("%s: Missing rockchip,grf property, %lu\n", 475 pr_err("%s: Missing rockchip,grf property, %lu\n",
469 __func__, PTR_ERR(grf)); 476 __func__, PTR_ERR(grf));
diff --git a/drivers/phy/phy-sun4i-usb.c b/drivers/phy/phy-sun4i-usb.c
index de3101fbbf40..0a45bc6088ae 100644
--- a/drivers/phy/phy-sun4i-usb.c
+++ b/drivers/phy/phy-sun4i-usb.c
@@ -94,6 +94,7 @@
94 94
95enum sun4i_usb_phy_type { 95enum sun4i_usb_phy_type {
96 sun4i_a10_phy, 96 sun4i_a10_phy,
97 sun6i_a31_phy,
97 sun8i_a33_phy, 98 sun8i_a33_phy,
98 sun8i_h3_phy, 99 sun8i_h3_phy,
99}; 100};
@@ -122,7 +123,6 @@ struct sun4i_usb_phy_data {
122 /* phy0 / otg related variables */ 123 /* phy0 / otg related variables */
123 struct extcon_dev *extcon; 124 struct extcon_dev *extcon;
124 bool phy0_init; 125 bool phy0_init;
125 bool phy0_poll;
126 struct gpio_desc *id_det_gpio; 126 struct gpio_desc *id_det_gpio;
127 struct gpio_desc *vbus_det_gpio; 127 struct gpio_desc *vbus_det_gpio;
128 struct power_supply *vbus_power_supply; 128 struct power_supply *vbus_power_supply;
@@ -343,6 +343,24 @@ static bool sun4i_usb_phy0_have_vbus_det(struct sun4i_usb_phy_data *data)
343 return data->vbus_det_gpio || data->vbus_power_supply; 343 return data->vbus_det_gpio || data->vbus_power_supply;
344} 344}
345 345
346static bool sun4i_usb_phy0_poll(struct sun4i_usb_phy_data *data)
347{
348 if ((data->id_det_gpio && data->id_det_irq <= 0) ||
349 (data->vbus_det_gpio && data->vbus_det_irq <= 0))
350 return true;
351
352 /*
353 * The A31 companion pmic (axp221) does not generate vbus change
354 * interrupts when the board is driving vbus, so we must poll
355 * when using the pmic for vbus-det _and_ we're driving vbus.
356 */
357 if (data->cfg->type == sun6i_a31_phy &&
358 data->vbus_power_supply && data->phys[0].regulator_on)
359 return true;
360
361 return false;
362}
363
346static int sun4i_usb_phy_power_on(struct phy *_phy) 364static int sun4i_usb_phy_power_on(struct phy *_phy)
347{ 365{
348 struct sun4i_usb_phy *phy = phy_get_drvdata(_phy); 366 struct sun4i_usb_phy *phy = phy_get_drvdata(_phy);
@@ -364,7 +382,7 @@ static int sun4i_usb_phy_power_on(struct phy *_phy)
364 phy->regulator_on = true; 382 phy->regulator_on = true;
365 383
366 /* We must report Vbus high within OTG_TIME_A_WAIT_VRISE msec. */ 384 /* We must report Vbus high within OTG_TIME_A_WAIT_VRISE msec. */
367 if (phy->index == 0 && data->vbus_det_gpio && data->phy0_poll) 385 if (phy->index == 0 && sun4i_usb_phy0_poll(data))
368 mod_delayed_work(system_wq, &data->detect, DEBOUNCE_TIME); 386 mod_delayed_work(system_wq, &data->detect, DEBOUNCE_TIME);
369 387
370 return 0; 388 return 0;
@@ -385,7 +403,7 @@ static int sun4i_usb_phy_power_off(struct phy *_phy)
385 * phy0 vbus typically slowly discharges, sometimes this causes the 403 * phy0 vbus typically slowly discharges, sometimes this causes the
386 * Vbus gpio to not trigger an edge irq on Vbus off, so force a rescan. 404 * Vbus gpio to not trigger an edge irq on Vbus off, so force a rescan.
387 */ 405 */
388 if (phy->index == 0 && data->vbus_det_gpio && !data->phy0_poll) 406 if (phy->index == 0 && !sun4i_usb_phy0_poll(data))
389 mod_delayed_work(system_wq, &data->detect, POLL_TIME); 407 mod_delayed_work(system_wq, &data->detect, POLL_TIME);
390 408
391 return 0; 409 return 0;
@@ -468,7 +486,7 @@ static void sun4i_usb_phy0_id_vbus_det_scan(struct work_struct *work)
468 if (vbus_notify) 486 if (vbus_notify)
469 extcon_set_cable_state_(data->extcon, EXTCON_USB, vbus_det); 487 extcon_set_cable_state_(data->extcon, EXTCON_USB, vbus_det);
470 488
471 if (data->phy0_poll) 489 if (sun4i_usb_phy0_poll(data))
472 queue_delayed_work(system_wq, &data->detect, POLL_TIME); 490 queue_delayed_work(system_wq, &data->detect, POLL_TIME);
473} 491}
474 492
@@ -644,11 +662,6 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev)
644 } 662 }
645 663
646 data->id_det_irq = gpiod_to_irq(data->id_det_gpio); 664 data->id_det_irq = gpiod_to_irq(data->id_det_gpio);
647 data->vbus_det_irq = gpiod_to_irq(data->vbus_det_gpio);
648 if ((data->id_det_gpio && data->id_det_irq <= 0) ||
649 (data->vbus_det_gpio && data->vbus_det_irq <= 0))
650 data->phy0_poll = true;
651
652 if (data->id_det_irq > 0) { 665 if (data->id_det_irq > 0) {
653 ret = devm_request_irq(dev, data->id_det_irq, 666 ret = devm_request_irq(dev, data->id_det_irq,
654 sun4i_usb_phy0_id_vbus_det_irq, 667 sun4i_usb_phy0_id_vbus_det_irq,
@@ -660,6 +673,7 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev)
660 } 673 }
661 } 674 }
662 675
676 data->vbus_det_irq = gpiod_to_irq(data->vbus_det_gpio);
663 if (data->vbus_det_irq > 0) { 677 if (data->vbus_det_irq > 0) {
664 ret = devm_request_irq(dev, data->vbus_det_irq, 678 ret = devm_request_irq(dev, data->vbus_det_irq,
665 sun4i_usb_phy0_id_vbus_det_irq, 679 sun4i_usb_phy0_id_vbus_det_irq,
@@ -711,7 +725,7 @@ static const struct sun4i_usb_phy_cfg sun5i_a13_cfg = {
711 725
712static const struct sun4i_usb_phy_cfg sun6i_a31_cfg = { 726static const struct sun4i_usb_phy_cfg sun6i_a31_cfg = {
713 .num_phys = 3, 727 .num_phys = 3,
714 .type = sun4i_a10_phy, 728 .type = sun6i_a31_phy,
715 .disc_thresh = 3, 729 .disc_thresh = 3,
716 .phyctl_offset = REG_PHYCTL_A10, 730 .phyctl_offset = REG_PHYCTL_A10,
717 .dedicated_clocks = true, 731 .dedicated_clocks = true,
diff --git a/drivers/phy/phy-xgene.c b/drivers/phy/phy-xgene.c
index 385362e5b2f6..ae266e0c8368 100644
--- a/drivers/phy/phy-xgene.c
+++ b/drivers/phy/phy-xgene.c
@@ -518,7 +518,7 @@ enum clk_type_t {
518 CLK_INT_SING = 2, /* Internal single ended */ 518 CLK_INT_SING = 2, /* Internal single ended */
519}; 519};
520 520
521enum phy_mode { 521enum xgene_phy_mode {
522 MODE_SATA = 0, /* List them for simple reference */ 522 MODE_SATA = 0, /* List them for simple reference */
523 MODE_SGMII = 1, 523 MODE_SGMII = 1,
524 MODE_PCIE = 2, 524 MODE_PCIE = 2,
@@ -542,7 +542,7 @@ struct xgene_sata_override_param {
542struct xgene_phy_ctx { 542struct xgene_phy_ctx {
543 struct device *dev; 543 struct device *dev;
544 struct phy *phy; 544 struct phy *phy;
545 enum phy_mode mode; /* Mode of operation */ 545 enum xgene_phy_mode mode; /* Mode of operation */
546 enum clk_type_t clk_type; /* Input clock selection */ 546 enum clk_type_t clk_type; /* Input clock selection */
547 void __iomem *sds_base; /* PHY CSR base addr */ 547 void __iomem *sds_base; /* PHY CSR base addr */
548 struct clk *clk; /* Optional clock */ 548 struct clk *clk; /* Optional clock */
diff --git a/include/linux/phy/phy.h b/include/linux/phy/phy.h
index a810f2a18842..f08b67238b58 100644
--- a/include/linux/phy/phy.h
+++ b/include/linux/phy/phy.h
@@ -22,12 +22,20 @@
22 22
23struct phy; 23struct phy;
24 24
25enum phy_mode {
26 PHY_MODE_INVALID,
27 PHY_MODE_USB_HOST,
28 PHY_MODE_USB_DEVICE,
29 PHY_MODE_USB_OTG,
30};
31
25/** 32/**
26 * struct phy_ops - set of function pointers for performing phy operations 33 * struct phy_ops - set of function pointers for performing phy operations
27 * @init: operation to be performed for initializing phy 34 * @init: operation to be performed for initializing phy
28 * @exit: operation to be performed while exiting 35 * @exit: operation to be performed while exiting
29 * @power_on: powering on the phy 36 * @power_on: powering on the phy
30 * @power_off: powering off the phy 37 * @power_off: powering off the phy
38 * @set_mode: set the mode of the phy
31 * @owner: the module owner containing the ops 39 * @owner: the module owner containing the ops
32 */ 40 */
33struct phy_ops { 41struct phy_ops {
@@ -35,6 +43,7 @@ struct phy_ops {
35 int (*exit)(struct phy *phy); 43 int (*exit)(struct phy *phy);
36 int (*power_on)(struct phy *phy); 44 int (*power_on)(struct phy *phy);
37 int (*power_off)(struct phy *phy); 45 int (*power_off)(struct phy *phy);
46 int (*set_mode)(struct phy *phy, enum phy_mode mode);
38 struct module *owner; 47 struct module *owner;
39}; 48};
40 49
@@ -126,6 +135,7 @@ int phy_init(struct phy *phy);
126int phy_exit(struct phy *phy); 135int phy_exit(struct phy *phy);
127int phy_power_on(struct phy *phy); 136int phy_power_on(struct phy *phy);
128int phy_power_off(struct phy *phy); 137int phy_power_off(struct phy *phy);
138int phy_set_mode(struct phy *phy, enum phy_mode mode);
129static inline int phy_get_bus_width(struct phy *phy) 139static inline int phy_get_bus_width(struct phy *phy)
130{ 140{
131 return phy->attrs.bus_width; 141 return phy->attrs.bus_width;
@@ -233,6 +243,13 @@ static inline int phy_power_off(struct phy *phy)
233 return -ENOSYS; 243 return -ENOSYS;
234} 244}
235 245
246static inline int phy_set_mode(struct phy *phy, enum phy_mode mode)
247{
248 if (!phy)
249 return 0;
250 return -ENOSYS;
251}
252
236static inline int phy_get_bus_width(struct phy *phy) 253static inline int phy_get_bus_width(struct phy *phy)
237{ 254{
238 return -ENOSYS; 255 return -ENOSYS;