Version:  2.6.34 2.6.35 2.6.36 2.6.37 2.6.38 2.6.39 3.0 3.1 3.2 3.3 3.4 3.5 3.6 3.7 3.8 3.9 3.10 3.11 3.12 3.13 3.14

Linux/drivers/usb/phy/phy-omap-control.c

  1 /*
  2  * omap-control-usb.c - The USB 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/usb/omap_control_usb.h>
 28 
 29 /**
 30  * omap_control_usb_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_usb_phy_power(struct device *dev, int on)
 35 {
 36         u32 val;
 37         unsigned long rate;
 38         struct omap_control_usb *control_usb;
 39 
 40         if (IS_ERR(dev) || !dev) {
 41                 pr_err("%s: invalid device\n", __func__);
 42                 return;
 43         }
 44 
 45         control_usb = dev_get_drvdata(dev);
 46         if (!control_usb) {
 47                 dev_err(dev, "%s: invalid control usb device\n", __func__);
 48                 return;
 49         }
 50 
 51         if (control_usb->type == OMAP_CTRL_TYPE_OTGHS)
 52                 return;
 53 
 54         val = readl(control_usb->power);
 55 
 56         switch (control_usb->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_usb->sys_clk);
 66                 rate = rate/1000000;
 67 
 68                 if (on) {
 69                         val &= ~(OMAP_CTRL_USB_PWRCTL_CLK_CMD_MASK |
 70                                         OMAP_CTRL_USB_PWRCTL_CLK_FREQ_MASK);
 71                         val |= OMAP_CTRL_USB3_PHY_TX_RX_POWERON <<
 72                                 OMAP_CTRL_USB_PWRCTL_CLK_CMD_SHIFT;
 73                         val |= rate << OMAP_CTRL_USB_PWRCTL_CLK_FREQ_SHIFT;
 74                 } else {
 75                         val &= ~OMAP_CTRL_USB_PWRCTL_CLK_CMD_MASK;
 76                         val |= OMAP_CTRL_USB3_PHY_TX_RX_POWEROFF <<
 77                                 OMAP_CTRL_USB_PWRCTL_CLK_CMD_SHIFT;
 78                 }
 79                 break;
 80 
 81         case OMAP_CTRL_TYPE_DRA7USB2:
 82                 if (on)
 83                         val &= ~OMAP_CTRL_USB2_PHY_PD;
 84                 else
 85                         val |= OMAP_CTRL_USB2_PHY_PD;
 86                 break;
 87 
 88         case OMAP_CTRL_TYPE_AM437USB2:
 89                 if (on) {
 90                         val &= ~(AM437X_CTRL_USB2_PHY_PD |
 91                                         AM437X_CTRL_USB2_OTG_PD);
 92                         val |= (AM437X_CTRL_USB2_OTGVDET_EN |
 93                                         AM437X_CTRL_USB2_OTGSESSEND_EN);
 94                 } else {
 95                         val &= ~(AM437X_CTRL_USB2_OTGVDET_EN |
 96                                         AM437X_CTRL_USB2_OTGSESSEND_EN);
 97                         val |= (AM437X_CTRL_USB2_PHY_PD |
 98                                          AM437X_CTRL_USB2_OTG_PD);
 99                 }
100                 break;
101         default:
102                 dev_err(dev, "%s: type %d not recognized\n",
103                                         __func__, control_usb->type);
104                 break;
105         }
106 
107         writel(val, control_usb->power);
108 }
109 EXPORT_SYMBOL_GPL(omap_control_usb_phy_power);
110 
111 /**
112  * omap_control_usb_host_mode - set AVALID, VBUSVALID and ID pin in grounded
113  * @ctrl_usb: struct omap_control_usb *
114  *
115  * Writes to the mailbox register to notify the usb core that a usb
116  * device has been connected.
117  */
118 static void omap_control_usb_host_mode(struct omap_control_usb *ctrl_usb)
119 {
120         u32 val;
121 
122         val = readl(ctrl_usb->otghs_control);
123         val &= ~(OMAP_CTRL_DEV_IDDIG | OMAP_CTRL_DEV_SESSEND);
124         val |= OMAP_CTRL_DEV_AVALID | OMAP_CTRL_DEV_VBUSVALID;
125         writel(val, ctrl_usb->otghs_control);
126 }
127 
128 /**
129  * omap_control_usb_device_mode - set AVALID, VBUSVALID and ID pin in high
130  * impedance
131  * @ctrl_usb: struct omap_control_usb *
132  *
133  * Writes to the mailbox register to notify the usb core that it has been
134  * connected to a usb host.
135  */
136 static void omap_control_usb_device_mode(struct omap_control_usb *ctrl_usb)
137 {
138         u32 val;
139 
140         val = readl(ctrl_usb->otghs_control);
141         val &= ~OMAP_CTRL_DEV_SESSEND;
142         val |= OMAP_CTRL_DEV_IDDIG | OMAP_CTRL_DEV_AVALID |
143                 OMAP_CTRL_DEV_VBUSVALID;
144         writel(val, ctrl_usb->otghs_control);
145 }
146 
147 /**
148  * omap_control_usb_set_sessionend - Enable SESSIONEND and IDIG to high
149  * impedance
150  * @ctrl_usb: struct omap_control_usb *
151  *
152  * Writes to the mailbox register to notify the usb core it's now in
153  * disconnected state.
154  */
155 static void omap_control_usb_set_sessionend(struct omap_control_usb *ctrl_usb)
156 {
157         u32 val;
158 
159         val = readl(ctrl_usb->otghs_control);
160         val &= ~(OMAP_CTRL_DEV_AVALID | OMAP_CTRL_DEV_VBUSVALID);
161         val |= OMAP_CTRL_DEV_IDDIG | OMAP_CTRL_DEV_SESSEND;
162         writel(val, ctrl_usb->otghs_control);
163 }
164 
165 /**
166  * omap_control_usb_set_mode - Calls to functions to set USB in one of host mode
167  * or device mode or to denote disconnected state
168  * @dev: the control module device
169  * @mode: The mode to which usb should be configured
170  *
171  * This is an API to write to the mailbox register to notify the usb core that
172  * a usb device has been connected.
173  */
174 void omap_control_usb_set_mode(struct device *dev,
175         enum omap_control_usb_mode mode)
176 {
177         struct omap_control_usb *ctrl_usb;
178 
179         if (IS_ERR(dev) || !dev)
180                 return;
181 
182         ctrl_usb = dev_get_drvdata(dev);
183 
184         if (!ctrl_usb) {
185                 dev_err(dev, "Invalid control usb device\n");
186                 return;
187         }
188 
189         if (ctrl_usb->type != OMAP_CTRL_TYPE_OTGHS)
190                 return;
191 
192         switch (mode) {
193         case USB_MODE_HOST:
194                 omap_control_usb_host_mode(ctrl_usb);
195                 break;
196         case USB_MODE_DEVICE:
197                 omap_control_usb_device_mode(ctrl_usb);
198                 break;
199         case USB_MODE_DISCONNECT:
200                 omap_control_usb_set_sessionend(ctrl_usb);
201                 break;
202         default:
203                 dev_vdbg(dev, "invalid omap control usb mode\n");
204         }
205 }
206 EXPORT_SYMBOL_GPL(omap_control_usb_set_mode);
207 
208 #ifdef CONFIG_OF
209 
210 static const enum omap_control_usb_type otghs_data = OMAP_CTRL_TYPE_OTGHS;
211 static const enum omap_control_usb_type usb2_data = OMAP_CTRL_TYPE_USB2;
212 static const enum omap_control_usb_type pipe3_data = OMAP_CTRL_TYPE_PIPE3;
213 static const enum omap_control_usb_type dra7usb2_data = OMAP_CTRL_TYPE_DRA7USB2;
214 static const enum omap_control_usb_type am437usb2_data = OMAP_CTRL_TYPE_AM437USB2;
215 
216 static const struct of_device_id omap_control_usb_id_table[] = {
217         {
218                 .compatible = "ti,control-phy-otghs",
219                 .data = &otghs_data,
220         },
221         {
222                 .compatible = "ti,control-phy-usb2",
223                 .data = &usb2_data,
224         },
225         {
226                 .compatible = "ti,control-phy-pipe3",
227                 .data = &pipe3_data,
228         },
229         {
230                 .compatible = "ti,control-phy-dra7usb2",
231                 .data = &dra7usb2_data,
232         },
233         {
234                 .compatible = "ti,control-phy-am437usb2",
235                 .data = &am437usb2_data,
236         },
237         {},
238 };
239 MODULE_DEVICE_TABLE(of, omap_control_usb_id_table);
240 #endif
241 
242 
243 static int omap_control_usb_probe(struct platform_device *pdev)
244 {
245         struct resource *res;
246         const struct of_device_id *of_id;
247         struct omap_control_usb *control_usb;
248 
249         of_id = of_match_device(of_match_ptr(omap_control_usb_id_table),
250                                                                 &pdev->dev);
251         if (!of_id)
252                 return -EINVAL;
253 
254         control_usb = devm_kzalloc(&pdev->dev, sizeof(*control_usb),
255                 GFP_KERNEL);
256         if (!control_usb) {
257                 dev_err(&pdev->dev, "unable to alloc memory for control usb\n");
258                 return -ENOMEM;
259         }
260 
261         control_usb->dev = &pdev->dev;
262         control_usb->type = *(enum omap_control_usb_type *)of_id->data;
263 
264         if (control_usb->type == OMAP_CTRL_TYPE_OTGHS) {
265                 res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
266                         "otghs_control");
267                 control_usb->otghs_control = devm_ioremap_resource(
268                         &pdev->dev, res);
269                 if (IS_ERR(control_usb->otghs_control))
270                         return PTR_ERR(control_usb->otghs_control);
271         } else {
272                 res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
273                                 "power");
274                 control_usb->power = devm_ioremap_resource(&pdev->dev, res);
275                 if (IS_ERR(control_usb->power)) {
276                         dev_err(&pdev->dev, "Couldn't get power register\n");
277                         return PTR_ERR(control_usb->power);
278                 }
279         }
280 
281         if (control_usb->type == OMAP_CTRL_TYPE_PIPE3) {
282                 control_usb->sys_clk = devm_clk_get(control_usb->dev,
283                         "sys_clkin");
284                 if (IS_ERR(control_usb->sys_clk)) {
285                         pr_err("%s: unable to get sys_clkin\n", __func__);
286                         return -EINVAL;
287                 }
288         }
289 
290         dev_set_drvdata(control_usb->dev, control_usb);
291 
292         return 0;
293 }
294 
295 static struct platform_driver omap_control_usb_driver = {
296         .probe          = omap_control_usb_probe,
297         .driver         = {
298                 .name   = "omap-control-usb",
299                 .owner  = THIS_MODULE,
300                 .of_match_table = of_match_ptr(omap_control_usb_id_table),
301         },
302 };
303 
304 static int __init omap_control_usb_init(void)
305 {
306         return platform_driver_register(&omap_control_usb_driver);
307 }
308 subsys_initcall(omap_control_usb_init);
309 
310 static void __exit omap_control_usb_exit(void)
311 {
312         platform_driver_unregister(&omap_control_usb_driver);
313 }
314 module_exit(omap_control_usb_exit);
315 
316 MODULE_ALIAS("platform: omap_control_usb");
317 MODULE_AUTHOR("Texas Instruments Inc.");
318 MODULE_DESCRIPTION("OMAP Control Module USB Driver");
319 MODULE_LICENSE("GPL v2");
320 

This page was automatically generated by LXR 0.3.1 (source).  •  Linux is a registered trademark of Linus Torvalds  •  Contact us