diff options
author | Kishon Vijay Abraham I <kishon@ti.com> | 2014-03-06 09:38:37 -0500 |
---|---|---|
committer | Kishon Vijay Abraham I <kishon@ti.com> | 2014-03-09 03:15:08 -0400 |
commit | 14da699bc04212559d5dda19d3f07c807fb58dfd (patch) | |
tree | da70074191e90be6fef4ac02bff16dde3ce45721 /drivers/phy/phy-omap-control.c | |
parent | db68e80f080a21b295f2262976520c40bc505f9d (diff) |
phy: rename struct omap_control_usb to struct omap_control_phy
Rename struct omap_control_usb to struct omap_control_phy since it can
be used to control PHY of USB, SATA and PCIE. Also move the driver and
include files under *phy* and made the corresponding changes in the users
of phy-omap-control.
Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
Signed-off-by: Roger Quadros <rogerq@ti.com>
Acked-by: Felipe Balbi <balbi@ti.com>
Diffstat (limited to 'drivers/phy/phy-omap-control.c')
-rw-r--r-- | drivers/phy/phy-omap-control.c | 320 |
1 files changed, 320 insertions, 0 deletions
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 | */ | ||
34 | void 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 | } | ||
110 | EXPORT_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 | */ | ||
119 | static 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 | */ | ||
137 | static 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 | */ | ||
156 | static 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 | */ | ||
175 | void 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 | } | ||
207 | EXPORT_SYMBOL_GPL(omap_control_usb_set_mode); | ||
208 | |||
209 | #ifdef CONFIG_OF | ||
210 | |||
211 | static const enum omap_control_phy_type otghs_data = OMAP_CTRL_TYPE_OTGHS; | ||
212 | static const enum omap_control_phy_type usb2_data = OMAP_CTRL_TYPE_USB2; | ||
213 | static const enum omap_control_phy_type pipe3_data = OMAP_CTRL_TYPE_PIPE3; | ||
214 | static const enum omap_control_phy_type dra7usb2_data = OMAP_CTRL_TYPE_DRA7USB2; | ||
215 | static const enum omap_control_phy_type am437usb2_data = OMAP_CTRL_TYPE_AM437USB2; | ||
216 | |||
217 | static 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 | }; | ||
240 | MODULE_DEVICE_TABLE(of, omap_control_phy_id_table); | ||
241 | #endif | ||
242 | |||
243 | |||
244 | static 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 | |||
296 | static 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 | |||
305 | static int __init omap_control_phy_init(void) | ||
306 | { | ||
307 | return platform_driver_register(&omap_control_phy_driver); | ||
308 | } | ||
309 | subsys_initcall(omap_control_phy_init); | ||
310 | |||
311 | static void __exit omap_control_phy_exit(void) | ||
312 | { | ||
313 | platform_driver_unregister(&omap_control_phy_driver); | ||
314 | } | ||
315 | module_exit(omap_control_phy_exit); | ||
316 | |||
317 | MODULE_ALIAS("platform: omap_control_phy"); | ||
318 | MODULE_AUTHOR("Texas Instruments Inc."); | ||
319 | MODULE_DESCRIPTION("OMAP Control Module PHY Driver"); | ||
320 | MODULE_LICENSE("GPL v2"); | ||