summaryrefslogtreecommitdiffstats
path: root/drivers/phy
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/phy')
-rw-r--r--drivers/phy/Kconfig14
-rw-r--r--drivers/phy/Makefile1
-rw-r--r--drivers/phy/phy-omap-control.c320
-rw-r--r--drivers/phy/phy-omap-usb2.c8
-rw-r--r--drivers/phy/phy-ti-pipe3.c8
5 files changed, 341 insertions, 10 deletions
diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index 1b607d7cb03d..fe8c0096f9e4 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -31,12 +31,22 @@ config PHY_MVEBU_SATA
31 depends on OF 31 depends on OF
32 select GENERIC_PHY 32 select GENERIC_PHY
33 33
34config OMAP_CONTROL_PHY
35 tristate "OMAP CONTROL PHY Driver"
36 help
37 Enable this to add support for the PHY part present in the control
38 module. This driver has API to power on the USB2 PHY and to write to
39 the mailbox. The mailbox is present only in omap4 and the register to
40 power on the USB2 PHY is present in OMAP4 and OMAP5. OMAP5 has an
41 additional register to power on USB3 PHY/SATA PHY/PCIE PHY
42 (PIPE3 PHY).
43
34config OMAP_USB2 44config OMAP_USB2
35 tristate "OMAP USB2 PHY Driver" 45 tristate "OMAP USB2 PHY Driver"
36 depends on ARCH_OMAP2PLUS 46 depends on ARCH_OMAP2PLUS
37 depends on USB_PHY 47 depends on USB_PHY
38 select GENERIC_PHY 48 select GENERIC_PHY
39 select OMAP_CONTROL_USB 49 select OMAP_CONTROL_PHY
40 help 50 help
41 Enable this to support the transceiver that is part of SOC. This 51 Enable this to support the transceiver that is part of SOC. This
42 driver takes care of all the PHY functionality apart from comparator. 52 driver takes care of all the PHY functionality apart from comparator.
@@ -47,7 +57,7 @@ config TI_PIPE3
47 tristate "TI PIPE3 PHY Driver" 57 tristate "TI PIPE3 PHY Driver"
48 depends on ARCH_OMAP2PLUS || COMPILE_TEST 58 depends on ARCH_OMAP2PLUS || COMPILE_TEST
49 select GENERIC_PHY 59 select GENERIC_PHY
50 select OMAP_CONTROL_USB 60 select OMAP_CONTROL_PHY
51 help 61 help
52 Enable this to support the PIPE3 PHY that is part of TI SOCs. This 62 Enable this to support the PIPE3 PHY that is part of TI SOCs. This
53 driver takes care of all the PHY functionality apart from comparator. 63 driver takes care of all the PHY functionality apart from comparator.
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
index ecf0d3f5bf1d..8da05a841112 100644
--- a/drivers/phy/Makefile
+++ b/drivers/phy/Makefile
@@ -7,6 +7,7 @@ obj-$(CONFIG_BCM_KONA_USB2_PHY) += phy-bcm-kona-usb2.o
7obj-$(CONFIG_PHY_EXYNOS_DP_VIDEO) += phy-exynos-dp-video.o 7obj-$(CONFIG_PHY_EXYNOS_DP_VIDEO) += phy-exynos-dp-video.o
8obj-$(CONFIG_PHY_EXYNOS_MIPI_VIDEO) += phy-exynos-mipi-video.o 8obj-$(CONFIG_PHY_EXYNOS_MIPI_VIDEO) += phy-exynos-mipi-video.o
9obj-$(CONFIG_PHY_MVEBU_SATA) += phy-mvebu-sata.o 9obj-$(CONFIG_PHY_MVEBU_SATA) += phy-mvebu-sata.o
10obj-$(CONFIG_OMAP_CONTROL_PHY) += phy-omap-control.o
10obj-$(CONFIG_OMAP_USB2) += phy-omap-usb2.o 11obj-$(CONFIG_OMAP_USB2) += phy-omap-usb2.o
11obj-$(CONFIG_TI_PIPE3) += phy-ti-pipe3.o 12obj-$(CONFIG_TI_PIPE3) += phy-ti-pipe3.o
12obj-$(CONFIG_TWL4030_USB) += phy-twl4030-usb.o 13obj-$(CONFIG_TWL4030_USB) += phy-twl4030-usb.o
diff --git a/drivers/phy/phy-omap-control.c b/drivers/phy/phy-omap-control.c
new file mode 100644
index 000000000000..17fc200210c8
--- /dev/null
+++ b/drivers/phy/phy-omap-control.c
@@ -0,0 +1,320 @@
1/*
2 * omap-control-phy.c - The PHY part of control module.
3 *
4 * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * Author: Kishon Vijay Abraham I <kishon@ti.com>
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 */
18
19#include <linux/module.h>
20#include <linux/platform_device.h>
21#include <linux/slab.h>
22#include <linux/of.h>
23#include <linux/of_device.h>
24#include <linux/err.h>
25#include <linux/io.h>
26#include <linux/clk.h>
27#include <linux/phy/omap_control_phy.h>
28
29/**
30 * omap_control_phy_power - power on/off the phy using control module reg
31 * @dev: the control module device
32 * @on: 0 or 1, based on powering on or off the PHY
33 */
34void omap_control_phy_power(struct device *dev, int on)
35{
36 u32 val;
37 unsigned long rate;
38 struct omap_control_phy *control_phy;
39
40 if (IS_ERR(dev) || !dev) {
41 pr_err("%s: invalid device\n", __func__);
42 return;
43 }
44
45 control_phy = dev_get_drvdata(dev);
46 if (!control_phy) {
47 dev_err(dev, "%s: invalid control phy device\n", __func__);
48 return;
49 }
50
51 if (control_phy->type == OMAP_CTRL_TYPE_OTGHS)
52 return;
53
54 val = readl(control_phy->power);
55
56 switch (control_phy->type) {
57 case OMAP_CTRL_TYPE_USB2:
58 if (on)
59 val &= ~OMAP_CTRL_DEV_PHY_PD;
60 else
61 val |= OMAP_CTRL_DEV_PHY_PD;
62 break;
63
64 case OMAP_CTRL_TYPE_PIPE3:
65 rate = clk_get_rate(control_phy->sys_clk);
66 rate = rate/1000000;
67
68 if (on) {
69 val &= ~(OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_CMD_MASK |
70 OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_FREQ_MASK);
71 val |= OMAP_CTRL_PIPE3_PHY_TX_RX_POWERON <<
72 OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_CMD_SHIFT;
73 val |= rate <<
74 OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_FREQ_SHIFT;
75 } else {
76 val &= ~OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_CMD_MASK;
77 val |= OMAP_CTRL_PIPE3_PHY_TX_RX_POWEROFF <<
78 OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_CMD_SHIFT;
79 }
80 break;
81
82 case OMAP_CTRL_TYPE_DRA7USB2:
83 if (on)
84 val &= ~OMAP_CTRL_USB2_PHY_PD;
85 else
86 val |= OMAP_CTRL_USB2_PHY_PD;
87 break;
88
89 case OMAP_CTRL_TYPE_AM437USB2:
90 if (on) {
91 val &= ~(AM437X_CTRL_USB2_PHY_PD |
92 AM437X_CTRL_USB2_OTG_PD);
93 val |= (AM437X_CTRL_USB2_OTGVDET_EN |
94 AM437X_CTRL_USB2_OTGSESSEND_EN);
95 } else {
96 val &= ~(AM437X_CTRL_USB2_OTGVDET_EN |
97 AM437X_CTRL_USB2_OTGSESSEND_EN);
98 val |= (AM437X_CTRL_USB2_PHY_PD |
99 AM437X_CTRL_USB2_OTG_PD);
100 }
101 break;
102 default:
103 dev_err(dev, "%s: type %d not recognized\n",
104 __func__, control_phy->type);
105 break;
106 }
107
108 writel(val, control_phy->power);
109}
110EXPORT_SYMBOL_GPL(omap_control_phy_power);
111
112/**
113 * omap_control_usb_host_mode - set AVALID, VBUSVALID and ID pin in grounded
114 * @ctrl_phy: struct omap_control_phy *
115 *
116 * Writes to the mailbox register to notify the usb core that a usb
117 * device has been connected.
118 */
119static void omap_control_usb_host_mode(struct omap_control_phy *ctrl_phy)
120{
121 u32 val;
122
123 val = readl(ctrl_phy->otghs_control);
124 val &= ~(OMAP_CTRL_DEV_IDDIG | OMAP_CTRL_DEV_SESSEND);
125 val |= OMAP_CTRL_DEV_AVALID | OMAP_CTRL_DEV_VBUSVALID;
126 writel(val, ctrl_phy->otghs_control);
127}
128
129/**
130 * omap_control_usb_device_mode - set AVALID, VBUSVALID and ID pin in high
131 * impedance
132 * @ctrl_phy: struct omap_control_phy *
133 *
134 * Writes to the mailbox register to notify the usb core that it has been
135 * connected to a usb host.
136 */
137static void omap_control_usb_device_mode(struct omap_control_phy *ctrl_phy)
138{
139 u32 val;
140
141 val = readl(ctrl_phy->otghs_control);
142 val &= ~OMAP_CTRL_DEV_SESSEND;
143 val |= OMAP_CTRL_DEV_IDDIG | OMAP_CTRL_DEV_AVALID |
144 OMAP_CTRL_DEV_VBUSVALID;
145 writel(val, ctrl_phy->otghs_control);
146}
147
148/**
149 * omap_control_usb_set_sessionend - Enable SESSIONEND and IDIG to high
150 * impedance
151 * @ctrl_phy: struct omap_control_phy *
152 *
153 * Writes to the mailbox register to notify the usb core it's now in
154 * disconnected state.
155 */
156static void omap_control_usb_set_sessionend(struct omap_control_phy *ctrl_phy)
157{
158 u32 val;
159
160 val = readl(ctrl_phy->otghs_control);
161 val &= ~(OMAP_CTRL_DEV_AVALID | OMAP_CTRL_DEV_VBUSVALID);
162 val |= OMAP_CTRL_DEV_IDDIG | OMAP_CTRL_DEV_SESSEND;
163 writel(val, ctrl_phy->otghs_control);
164}
165
166/**
167 * omap_control_usb_set_mode - Calls to functions to set USB in one of host mode
168 * or device mode or to denote disconnected state
169 * @dev: the control module device
170 * @mode: The mode to which usb should be configured
171 *
172 * This is an API to write to the mailbox register to notify the usb core that
173 * a usb device has been connected.
174 */
175void omap_control_usb_set_mode(struct device *dev,
176 enum omap_control_usb_mode mode)
177{
178 struct omap_control_phy *ctrl_phy;
179
180 if (IS_ERR(dev) || !dev)
181 return;
182
183 ctrl_phy = dev_get_drvdata(dev);
184
185 if (!ctrl_phy) {
186 dev_err(dev, "Invalid control phy device\n");
187 return;
188 }
189
190 if (ctrl_phy->type != OMAP_CTRL_TYPE_OTGHS)
191 return;
192
193 switch (mode) {
194 case USB_MODE_HOST:
195 omap_control_usb_host_mode(ctrl_phy);
196 break;
197 case USB_MODE_DEVICE:
198 omap_control_usb_device_mode(ctrl_phy);
199 break;
200 case USB_MODE_DISCONNECT:
201 omap_control_usb_set_sessionend(ctrl_phy);
202 break;
203 default:
204 dev_vdbg(dev, "invalid omap control usb mode\n");
205 }
206}
207EXPORT_SYMBOL_GPL(omap_control_usb_set_mode);
208
209#ifdef CONFIG_OF
210
211static const enum omap_control_phy_type otghs_data = OMAP_CTRL_TYPE_OTGHS;
212static const enum omap_control_phy_type usb2_data = OMAP_CTRL_TYPE_USB2;
213static const enum omap_control_phy_type pipe3_data = OMAP_CTRL_TYPE_PIPE3;
214static const enum omap_control_phy_type dra7usb2_data = OMAP_CTRL_TYPE_DRA7USB2;
215static const enum omap_control_phy_type am437usb2_data = OMAP_CTRL_TYPE_AM437USB2;
216
217static const struct of_device_id omap_control_phy_id_table[] = {
218 {
219 .compatible = "ti,control-phy-otghs",
220 .data = &otghs_data,
221 },
222 {
223 .compatible = "ti,control-phy-usb2",
224 .data = &usb2_data,
225 },
226 {
227 .compatible = "ti,control-phy-pipe3",
228 .data = &pipe3_data,
229 },
230 {
231 .compatible = "ti,control-phy-dra7usb2",
232 .data = &dra7usb2_data,
233 },
234 {
235 .compatible = "ti,control-phy-am437usb2",
236 .data = &am437usb2_data,
237 },
238 {},
239};
240MODULE_DEVICE_TABLE(of, omap_control_phy_id_table);
241#endif
242
243
244static int omap_control_phy_probe(struct platform_device *pdev)
245{
246 struct resource *res;
247 const struct of_device_id *of_id;
248 struct omap_control_phy *control_phy;
249
250 of_id = of_match_device(of_match_ptr(omap_control_phy_id_table),
251 &pdev->dev);
252 if (!of_id)
253 return -EINVAL;
254
255 control_phy = devm_kzalloc(&pdev->dev, sizeof(*control_phy),
256 GFP_KERNEL);
257 if (!control_phy) {
258 dev_err(&pdev->dev, "unable to alloc memory for control phy\n");
259 return -ENOMEM;
260 }
261
262 control_phy->dev = &pdev->dev;
263 control_phy->type = *(enum omap_control_phy_type *)of_id->data;
264
265 if (control_phy->type == OMAP_CTRL_TYPE_OTGHS) {
266 res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
267 "otghs_control");
268 control_phy->otghs_control = devm_ioremap_resource(
269 &pdev->dev, res);
270 if (IS_ERR(control_phy->otghs_control))
271 return PTR_ERR(control_phy->otghs_control);
272 } else {
273 res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
274 "power");
275 control_phy->power = devm_ioremap_resource(&pdev->dev, res);
276 if (IS_ERR(control_phy->power)) {
277 dev_err(&pdev->dev, "Couldn't get power register\n");
278 return PTR_ERR(control_phy->power);
279 }
280 }
281
282 if (control_phy->type == OMAP_CTRL_TYPE_PIPE3) {
283 control_phy->sys_clk = devm_clk_get(control_phy->dev,
284 "sys_clkin");
285 if (IS_ERR(control_phy->sys_clk)) {
286 pr_err("%s: unable to get sys_clkin\n", __func__);
287 return -EINVAL;
288 }
289 }
290
291 dev_set_drvdata(control_phy->dev, control_phy);
292
293 return 0;
294}
295
296static struct platform_driver omap_control_phy_driver = {
297 .probe = omap_control_phy_probe,
298 .driver = {
299 .name = "omap-control-phy",
300 .owner = THIS_MODULE,
301 .of_match_table = of_match_ptr(omap_control_phy_id_table),
302 },
303};
304
305static int __init omap_control_phy_init(void)
306{
307 return platform_driver_register(&omap_control_phy_driver);
308}
309subsys_initcall(omap_control_phy_init);
310
311static void __exit omap_control_phy_exit(void)
312{
313 platform_driver_unregister(&omap_control_phy_driver);
314}
315module_exit(omap_control_phy_exit);
316
317MODULE_ALIAS("platform: omap_control_phy");
318MODULE_AUTHOR("Texas Instruments Inc.");
319MODULE_DESCRIPTION("OMAP Control Module PHY Driver");
320MODULE_LICENSE("GPL v2");
diff --git a/drivers/phy/phy-omap-usb2.c b/drivers/phy/phy-omap-usb2.c
index 3cc4aba6e50e..a2205a841e5e 100644
--- a/drivers/phy/phy-omap-usb2.c
+++ b/drivers/phy/phy-omap-usb2.c
@@ -27,7 +27,7 @@
27#include <linux/err.h> 27#include <linux/err.h>
28#include <linux/pm_runtime.h> 28#include <linux/pm_runtime.h>
29#include <linux/delay.h> 29#include <linux/delay.h>
30#include <linux/usb/omap_control_usb.h> 30#include <linux/phy/omap_control_phy.h>
31#include <linux/phy/phy.h> 31#include <linux/phy/phy.h>
32#include <linux/of_platform.h> 32#include <linux/of_platform.h>
33 33
@@ -105,7 +105,7 @@ static int omap_usb_power_off(struct phy *x)
105{ 105{
106 struct omap_usb *phy = phy_get_drvdata(x); 106 struct omap_usb *phy = phy_get_drvdata(x);
107 107
108 omap_control_usb_phy_power(phy->control_dev, 0); 108 omap_control_phy_power(phy->control_dev, 0);
109 109
110 return 0; 110 return 0;
111} 111}
@@ -114,7 +114,7 @@ static int omap_usb_power_on(struct phy *x)
114{ 114{
115 struct omap_usb *phy = phy_get_drvdata(x); 115 struct omap_usb *phy = phy_get_drvdata(x);
116 116
117 omap_control_usb_phy_power(phy->control_dev, 1); 117 omap_control_phy_power(phy->control_dev, 1);
118 118
119 return 0; 119 return 0;
120} 120}
@@ -251,7 +251,7 @@ static int omap_usb2_probe(struct platform_device *pdev)
251 } 251 }
252 252
253 phy->control_dev = &control_pdev->dev; 253 phy->control_dev = &control_pdev->dev;
254 omap_control_usb_phy_power(phy->control_dev, 0); 254 omap_control_phy_power(phy->control_dev, 0);
255 255
256 otg->set_host = omap_usb_set_host; 256 otg->set_host = omap_usb_set_host;
257 otg->set_peripheral = omap_usb_set_peripheral; 257 otg->set_peripheral = omap_usb_set_peripheral;
diff --git a/drivers/phy/phy-ti-pipe3.c b/drivers/phy/phy-ti-pipe3.c
index c8d16746a5e2..fd029b14cb3e 100644
--- a/drivers/phy/phy-ti-pipe3.c
+++ b/drivers/phy/phy-ti-pipe3.c
@@ -26,7 +26,7 @@
26#include <linux/io.h> 26#include <linux/io.h>
27#include <linux/pm_runtime.h> 27#include <linux/pm_runtime.h>
28#include <linux/delay.h> 28#include <linux/delay.h>
29#include <linux/usb/omap_control_usb.h> 29#include <linux/phy/omap_control_phy.h>
30#include <linux/of_platform.h> 30#include <linux/of_platform.h>
31 31
32#define PLL_STATUS 0x00000004 32#define PLL_STATUS 0x00000004
@@ -134,7 +134,7 @@ static int ti_pipe3_power_off(struct phy *x)
134 return -EBUSY; 134 return -EBUSY;
135 } 135 }
136 136
137 omap_control_usb_phy_power(phy->control_dev, 0); 137 omap_control_phy_power(phy->control_dev, 0);
138 138
139 return 0; 139 return 0;
140} 140}
@@ -232,7 +232,7 @@ static int ti_pipe3_init(struct phy *x)
232 if (ret) 232 if (ret)
233 return ret; 233 return ret;
234 234
235 omap_control_usb_phy_power(phy->control_dev, 1); 235 omap_control_phy_power(phy->control_dev, 1);
236 236
237 return 0; 237 return 0;
238} 238}
@@ -304,7 +304,7 @@ static int ti_pipe3_probe(struct platform_device *pdev)
304 304
305 phy->control_dev = &control_pdev->dev; 305 phy->control_dev = &control_pdev->dev;
306 306
307 omap_control_usb_phy_power(phy->control_dev, 0); 307 omap_control_phy_power(phy->control_dev, 0);
308 308
309 platform_set_drvdata(pdev, phy); 309 platform_set_drvdata(pdev, phy);
310 pm_runtime_enable(phy->dev); 310 pm_runtime_enable(phy->dev);