aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKishon Vijay Abraham I <kishon@ti.com>2012-09-06 10:57:06 -0400
committerFelipe Balbi <balbi@ti.com>2012-09-06 13:14:53 -0400
commit657b306a7bdfca4ae1514b533a0e7c3c6d26dbc6 (patch)
tree37862b7feec66ad89ca111ed88662fedb122698e
parenta4c3ddec5c5293953d8472eb151c48a3205b738b (diff)
usb: phy: add a new driver for omap usb2 phy
All phy related programming like enabling/disabling the clocks, powering on/off the phy is taken care of by this driver. It is also used for OTG related functionality like srp. This also includes device tree support for usb2 phy driver and the documentation with device tree binding information is updated. Currently writing to control module register is taken care in this driver which will be removed once the control module driver is in place. Cc: Felipe Balbi <balbi@ti.com> Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com> Signed-off-by: Felipe Balbi <balbi@ti.com>
-rw-r--r--Documentation/devicetree/bindings/usb/usb-phy.txt17
-rw-r--r--drivers/usb/phy/Kconfig9
-rw-r--r--drivers/usb/phy/Makefile1
-rw-r--r--drivers/usb/phy/omap-usb2.c271
-rw-r--r--include/linux/usb/omap_usb.h46
-rw-r--r--include/linux/usb/phy_companion.h34
6 files changed, 378 insertions, 0 deletions
diff --git a/Documentation/devicetree/bindings/usb/usb-phy.txt b/Documentation/devicetree/bindings/usb/usb-phy.txt
new file mode 100644
index 000000000000..80d4148cb661
--- /dev/null
+++ b/Documentation/devicetree/bindings/usb/usb-phy.txt
@@ -0,0 +1,17 @@
1USB PHY
2
3OMAP USB2 PHY
4
5Required properties:
6 - compatible: Should be "ti,omap-usb2"
7 - reg : Address and length of the register set for the device. Also
8add the address of control module dev conf register until a driver for
9control module is added
10
11This is usually a subnode of ocp2scp to which it is connected.
12
13usb2phy@4a0ad080 {
14 compatible = "ti,omap-usb2";
15 reg = <0x4a0ad080 0x58>,
16 <0x4a002300 0x4>;
17};
diff --git a/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig
index 2838adb225e8..63c339b3e676 100644
--- a/drivers/usb/phy/Kconfig
+++ b/drivers/usb/phy/Kconfig
@@ -4,6 +4,15 @@
4comment "USB Physical Layer drivers" 4comment "USB Physical Layer drivers"
5 depends on USB || USB_GADGET 5 depends on USB || USB_GADGET
6 6
7config OMAP_USB2
8 tristate "OMAP USB2 PHY Driver"
9 select USB_OTG_UTILS
10 help
11 Enable this to support the transceiver that is part of SOC. This
12 driver takes care of all the PHY functionality apart from comparator.
13 The USB OTG controller communicates with the comparator using this
14 driver.
15
7config USB_ISP1301 16config USB_ISP1301
8 tristate "NXP ISP1301 USB transceiver support" 17 tristate "NXP ISP1301 USB transceiver support"
9 depends on USB || USB_GADGET 18 depends on USB || USB_GADGET
diff --git a/drivers/usb/phy/Makefile b/drivers/usb/phy/Makefile
index bb948fb8654c..b069f29f1225 100644
--- a/drivers/usb/phy/Makefile
+++ b/drivers/usb/phy/Makefile
@@ -4,6 +4,7 @@
4 4
5ccflags-$(CONFIG_USB_DEBUG) := -DDEBUG 5ccflags-$(CONFIG_USB_DEBUG) := -DDEBUG
6 6
7obj-$(CONFIG_OMAP_USB2) += omap-usb2.o
7obj-$(CONFIG_USB_ISP1301) += isp1301.o 8obj-$(CONFIG_USB_ISP1301) += isp1301.o
8obj-$(CONFIG_MV_U3D_PHY) += mv_u3d_phy.o 9obj-$(CONFIG_MV_U3D_PHY) += mv_u3d_phy.o
9obj-$(CONFIG_USB_EHCI_TEGRA) += tegra_usb_phy.o 10obj-$(CONFIG_USB_EHCI_TEGRA) += tegra_usb_phy.o
diff --git a/drivers/usb/phy/omap-usb2.c b/drivers/usb/phy/omap-usb2.c
new file mode 100644
index 000000000000..15ab3d6f2e8c
--- /dev/null
+++ b/drivers/usb/phy/omap-usb2.c
@@ -0,0 +1,271 @@
1/*
2 * omap-usb2.c - USB PHY, talking to musb controller in OMAP.
3 *
4 * Copyright (C) 2012 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/io.h>
24#include <linux/usb/omap_usb.h>
25#include <linux/usb/phy_companion.h>
26#include <linux/clk.h>
27#include <linux/err.h>
28#include <linux/pm_runtime.h>
29#include <linux/delay.h>
30
31/**
32 * omap_usb2_set_comparator - links the comparator present in the sytem with
33 * this phy
34 * @comparator - the companion phy(comparator) for this phy
35 *
36 * The phy companion driver should call this API passing the phy_companion
37 * filled with set_vbus and start_srp to be used by usb phy.
38 *
39 * For use by phy companion driver
40 */
41int omap_usb2_set_comparator(struct phy_companion *comparator)
42{
43 struct omap_usb *phy;
44 struct usb_phy *x = usb_get_phy(USB_PHY_TYPE_USB2);
45
46 if (IS_ERR(x))
47 return -ENODEV;
48
49 phy = phy_to_omapusb(x);
50 phy->comparator = comparator;
51 return 0;
52}
53EXPORT_SYMBOL_GPL(omap_usb2_set_comparator);
54
55/**
56 * omap_usb_phy_power - power on/off the phy using control module reg
57 * @phy: struct omap_usb *
58 * @on: 0 or 1, based on powering on or off the PHY
59 *
60 * XXX: Remove this function once control module driver gets merged
61 */
62static void omap_usb_phy_power(struct omap_usb *phy, int on)
63{
64 u32 val;
65
66 if (on) {
67 val = readl(phy->control_dev);
68 if (val & PHY_PD) {
69 writel(~PHY_PD, phy->control_dev);
70 /* XXX: add proper documentation for this delay */
71 mdelay(200);
72 }
73 } else {
74 writel(PHY_PD, phy->control_dev);
75 }
76}
77
78static int omap_usb_set_vbus(struct usb_otg *otg, bool enabled)
79{
80 struct omap_usb *phy = phy_to_omapusb(otg->phy);
81
82 if (!phy->comparator)
83 return -ENODEV;
84
85 return phy->comparator->set_vbus(phy->comparator, enabled);
86}
87
88static int omap_usb_start_srp(struct usb_otg *otg)
89{
90 struct omap_usb *phy = phy_to_omapusb(otg->phy);
91
92 if (!phy->comparator)
93 return -ENODEV;
94
95 return phy->comparator->start_srp(phy->comparator);
96}
97
98static int omap_usb_set_host(struct usb_otg *otg, struct usb_bus *host)
99{
100 struct usb_phy *phy = otg->phy;
101
102 otg->host = host;
103 if (!host)
104 phy->state = OTG_STATE_UNDEFINED;
105
106 return 0;
107}
108
109static int omap_usb_set_peripheral(struct usb_otg *otg,
110 struct usb_gadget *gadget)
111{
112 struct usb_phy *phy = otg->phy;
113
114 otg->gadget = gadget;
115 if (!gadget)
116 phy->state = OTG_STATE_UNDEFINED;
117
118 return 0;
119}
120
121static int omap_usb2_suspend(struct usb_phy *x, int suspend)
122{
123 u32 ret;
124 struct omap_usb *phy = phy_to_omapusb(x);
125
126 if (suspend && !phy->is_suspended) {
127 omap_usb_phy_power(phy, 0);
128 pm_runtime_put_sync(phy->dev);
129 phy->is_suspended = 1;
130 } else if (!suspend && phy->is_suspended) {
131 ret = pm_runtime_get_sync(phy->dev);
132 if (ret < 0) {
133 dev_err(phy->dev, "get_sync failed with err %d\n",
134 ret);
135 return ret;
136 }
137 omap_usb_phy_power(phy, 1);
138 phy->is_suspended = 0;
139 }
140
141 return 0;
142}
143
144static int __devinit omap_usb2_probe(struct platform_device *pdev)
145{
146 struct omap_usb *phy;
147 struct usb_otg *otg;
148 struct resource *res;
149
150 phy = devm_kzalloc(&pdev->dev, sizeof(*phy), GFP_KERNEL);
151 if (!phy) {
152 dev_err(&pdev->dev, "unable to allocate memory for USB2 PHY\n");
153 return -ENOMEM;
154 }
155
156 otg = devm_kzalloc(&pdev->dev, sizeof(*otg), GFP_KERNEL);
157 if (!otg) {
158 dev_err(&pdev->dev, "unable to allocate memory for USB OTG\n");
159 return -ENOMEM;
160 }
161
162 phy->dev = &pdev->dev;
163
164 phy->phy.dev = phy->dev;
165 phy->phy.label = "omap-usb2";
166 phy->phy.set_suspend = omap_usb2_suspend;
167 phy->phy.otg = otg;
168
169 res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
170
171 phy->control_dev = devm_request_and_ioremap(&pdev->dev, res);
172 if (phy->control_dev == NULL) {
173 dev_err(&pdev->dev, "Failed to obtain io memory\n");
174 return -ENXIO;
175 }
176
177 phy->is_suspended = 1;
178 omap_usb_phy_power(phy, 0);
179
180 otg->set_host = omap_usb_set_host;
181 otg->set_peripheral = omap_usb_set_peripheral;
182 otg->set_vbus = omap_usb_set_vbus;
183 otg->start_srp = omap_usb_start_srp;
184 otg->phy = &phy->phy;
185
186 phy->wkupclk = devm_clk_get(phy->dev, "usb_phy_cm_clk32k");
187 if (IS_ERR(phy->wkupclk)) {
188 dev_err(&pdev->dev, "unable to get usb_phy_cm_clk32k\n");
189 return PTR_ERR(phy->wkupclk);
190 }
191 clk_prepare(phy->wkupclk);
192
193 usb_add_phy(&phy->phy, USB_PHY_TYPE_USB2);
194
195 platform_set_drvdata(pdev, phy);
196
197 pm_runtime_enable(phy->dev);
198
199 return 0;
200}
201
202static int __devexit omap_usb2_remove(struct platform_device *pdev)
203{
204 struct omap_usb *phy = platform_get_drvdata(pdev);
205
206 clk_unprepare(phy->wkupclk);
207 usb_remove_phy(&phy->phy);
208
209 return 0;
210}
211
212#ifdef CONFIG_PM_RUNTIME
213
214static int omap_usb2_runtime_suspend(struct device *dev)
215{
216 struct platform_device *pdev = to_platform_device(dev);
217 struct omap_usb *phy = platform_get_drvdata(pdev);
218
219 clk_disable(phy->wkupclk);
220
221 return 0;
222}
223
224static int omap_usb2_runtime_resume(struct device *dev)
225{
226 u32 ret = 0;
227 struct platform_device *pdev = to_platform_device(dev);
228 struct omap_usb *phy = platform_get_drvdata(pdev);
229
230 ret = clk_enable(phy->wkupclk);
231 if (ret < 0)
232 dev_err(phy->dev, "Failed to enable wkupclk %d\n", ret);
233
234 return ret;
235}
236
237static const struct dev_pm_ops omap_usb2_pm_ops = {
238 SET_RUNTIME_PM_OPS(omap_usb2_runtime_suspend, omap_usb2_runtime_resume,
239 NULL)
240};
241
242#define DEV_PM_OPS (&omap_usb2_pm_ops)
243#else
244#define DEV_PM_OPS NULL
245#endif
246
247#ifdef CONFIG_OF
248static const struct of_device_id omap_usb2_id_table[] = {
249 { .compatible = "ti,omap-usb2" },
250 {}
251};
252MODULE_DEVICE_TABLE(of, omap_usb2_id_table);
253#endif
254
255static struct platform_driver omap_usb2_driver = {
256 .probe = omap_usb2_probe,
257 .remove = __devexit_p(omap_usb2_remove),
258 .driver = {
259 .name = "omap-usb2",
260 .owner = THIS_MODULE,
261 .pm = DEV_PM_OPS,
262 .of_match_table = of_match_ptr(omap_usb2_id_table),
263 },
264};
265
266module_platform_driver(omap_usb2_driver);
267
268MODULE_ALIAS("platform: omap_usb2");
269MODULE_AUTHOR("Texas Instruments Inc.");
270MODULE_DESCRIPTION("OMAP USB2 phy driver");
271MODULE_LICENSE("GPL v2");
diff --git a/include/linux/usb/omap_usb.h b/include/linux/usb/omap_usb.h
new file mode 100644
index 000000000000..0ea17f8ae820
--- /dev/null
+++ b/include/linux/usb/omap_usb.h
@@ -0,0 +1,46 @@
1/*
2 * omap_usb.h -- omap usb2 phy header file
3 *
4 * Copyright (C) 2012 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#ifndef __DRIVERS_OMAP_USB2_H
20#define __DRIVERS_OMAP_USB2_H
21
22#include <linux/usb/otg.h>
23
24struct omap_usb {
25 struct usb_phy phy;
26 struct phy_companion *comparator;
27 struct device *dev;
28 u32 __iomem *control_dev;
29 struct clk *wkupclk;
30 u8 is_suspended:1;
31};
32
33#define PHY_PD 0x1
34
35#define phy_to_omapusb(x) container_of((x), struct omap_usb, phy)
36
37#if defined(CONFIG_OMAP_USB2) || defined(CONFIG_OMAP_USB2_MODULE)
38extern int omap_usb2_set_comparator(struct phy_companion *comparator);
39#else
40static inline int omap_usb2_set_comparator(struct phy_companion *comparator)
41{
42 return -ENODEV;
43}
44#endif
45
46#endif /* __DRIVERS_OMAP_USB_H */
diff --git a/include/linux/usb/phy_companion.h b/include/linux/usb/phy_companion.h
new file mode 100644
index 000000000000..edd2ec23d282
--- /dev/null
+++ b/include/linux/usb/phy_companion.h
@@ -0,0 +1,34 @@
1/*
2 * phy-companion.h -- phy companion to indicate the comparator part of PHY
3 *
4 * Copyright (C) 2012 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#ifndef __DRIVERS_PHY_COMPANION_H
20#define __DRIVERS_PHY_COMPANION_H
21
22#include <linux/usb/otg.h>
23
24/* phy_companion to take care of VBUS, ID and srp capabilities */
25struct phy_companion {
26
27 /* effective for A-peripheral, ignored for B devices */
28 int (*set_vbus)(struct phy_companion *x, bool enabled);
29
30 /* for B devices only: start session with A-Host */
31 int (*start_srp)(struct phy_companion *x);
32};
33
34#endif /* __DRIVERS_PHY_COMPANION_H */