blob: cebfe0a68aa7666f0749412741f803d3867eb425 [file] [log] [blame]
Keshava Munegowda17cdd292011-03-01 20:08:17 +05301/**
2 * omap-usb-host.c - The USBHS core driver for OMAP EHCI & OHCI
3 *
4 * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com
5 * Author: Keshava Munegowda <keshava_mgowda@ti.com>
6 *
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 of
9 * the License as published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19#include <linux/kernel.h>
Ming Lei417e2062011-08-19 16:57:54 +080020#include <linux/module.h>
Keshava Munegowda17cdd292011-03-01 20:08:17 +053021#include <linux/types.h>
22#include <linux/slab.h>
23#include <linux/delay.h>
Keshava Munegowda17cdd292011-03-01 20:08:17 +053024#include <linux/clk.h>
25#include <linux/dma-mapping.h>
26#include <linux/spinlock.h>
Russ Dillc05995c2012-06-14 09:24:21 -070027#include <linux/gpio.h>
Russ Dill13176a82012-04-22 01:48:18 -070028#include <plat/cpu.h>
Felipe Balbie8c4a7a2012-10-24 14:26:19 -070029#include <linux/platform_device.h>
30#include <linux/platform_data/usb-omap.h>
Keshava Munegowda1e7fe1a2011-10-11 13:23:29 +053031#include <linux/pm_runtime.h>
Keshava Munegowda17cdd292011-03-01 20:08:17 +053032
Felipe Balbie8c4a7a2012-10-24 14:26:19 -070033#include "omap-usb.h"
34
Keshava Munegowdaa6d3a662011-10-11 13:21:51 +053035#define USBHS_DRIVER_NAME "usbhs_omap"
Keshava Munegowda17cdd292011-03-01 20:08:17 +053036#define OMAP_EHCI_DEVICE "ehci-omap"
37#define OMAP_OHCI_DEVICE "ohci-omap3"
38
39/* OMAP USBHOST Register addresses */
40
Keshava Munegowda17cdd292011-03-01 20:08:17 +053041/* UHH Register Set */
42#define OMAP_UHH_REVISION (0x00)
43#define OMAP_UHH_SYSCONFIG (0x10)
44#define OMAP_UHH_SYSCONFIG_MIDLEMODE (1 << 12)
45#define OMAP_UHH_SYSCONFIG_CACTIVITY (1 << 8)
46#define OMAP_UHH_SYSCONFIG_SIDLEMODE (1 << 3)
47#define OMAP_UHH_SYSCONFIG_ENAWAKEUP (1 << 2)
48#define OMAP_UHH_SYSCONFIG_SOFTRESET (1 << 1)
49#define OMAP_UHH_SYSCONFIG_AUTOIDLE (1 << 0)
50
51#define OMAP_UHH_SYSSTATUS (0x14)
52#define OMAP_UHH_HOSTCONFIG (0x40)
53#define OMAP_UHH_HOSTCONFIG_ULPI_BYPASS (1 << 0)
54#define OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS (1 << 0)
55#define OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS (1 << 11)
56#define OMAP_UHH_HOSTCONFIG_ULPI_P3_BYPASS (1 << 12)
57#define OMAP_UHH_HOSTCONFIG_INCR4_BURST_EN (1 << 2)
58#define OMAP_UHH_HOSTCONFIG_INCR8_BURST_EN (1 << 3)
59#define OMAP_UHH_HOSTCONFIG_INCR16_BURST_EN (1 << 4)
60#define OMAP_UHH_HOSTCONFIG_INCRX_ALIGN_EN (1 << 5)
61#define OMAP_UHH_HOSTCONFIG_P1_CONNECT_STATUS (1 << 8)
62#define OMAP_UHH_HOSTCONFIG_P2_CONNECT_STATUS (1 << 9)
63#define OMAP_UHH_HOSTCONFIG_P3_CONNECT_STATUS (1 << 10)
64#define OMAP4_UHH_HOSTCONFIG_APP_START_CLK (1 << 31)
65
66/* OMAP4-specific defines */
67#define OMAP4_UHH_SYSCONFIG_IDLEMODE_CLEAR (3 << 2)
68#define OMAP4_UHH_SYSCONFIG_NOIDLE (1 << 2)
69#define OMAP4_UHH_SYSCONFIG_STDBYMODE_CLEAR (3 << 4)
70#define OMAP4_UHH_SYSCONFIG_NOSTDBY (1 << 4)
71#define OMAP4_UHH_SYSCONFIG_SOFTRESET (1 << 0)
72
73#define OMAP4_P1_MODE_CLEAR (3 << 16)
74#define OMAP4_P1_MODE_TLL (1 << 16)
75#define OMAP4_P1_MODE_HSIC (3 << 16)
76#define OMAP4_P2_MODE_CLEAR (3 << 18)
77#define OMAP4_P2_MODE_TLL (1 << 18)
78#define OMAP4_P2_MODE_HSIC (3 << 18)
79
Keshava Munegowda17cdd292011-03-01 20:08:17 +053080#define OMAP_UHH_DEBUG_CSR (0x44)
81
82/* Values of UHH_REVISION - Note: these are not given in the TRM */
83#define OMAP_USBHS_REV1 0x00000010 /* OMAP3 */
84#define OMAP_USBHS_REV2 0x50700100 /* OMAP4 */
85
86#define is_omap_usbhs_rev1(x) (x->usbhs_rev == OMAP_USBHS_REV1)
87#define is_omap_usbhs_rev2(x) (x->usbhs_rev == OMAP_USBHS_REV2)
88
89#define is_ehci_phy_mode(x) (x == OMAP_EHCI_PORT_MODE_PHY)
90#define is_ehci_tll_mode(x) (x == OMAP_EHCI_PORT_MODE_TLL)
91#define is_ehci_hsic_mode(x) (x == OMAP_EHCI_PORT_MODE_HSIC)
92
93
94struct usbhs_hcd_omap {
Keshava Munegowda17cdd292011-03-01 20:08:17 +053095 struct clk *xclk60mhsp1_ck;
96 struct clk *xclk60mhsp2_ck;
97 struct clk *utmi_p1_fck;
98 struct clk *usbhost_p1_fck;
Keshava Munegowda17cdd292011-03-01 20:08:17 +053099 struct clk *utmi_p2_fck;
100 struct clk *usbhost_p2_fck;
Keshava Munegowda17cdd292011-03-01 20:08:17 +0530101 struct clk *init_60m_fclk;
Keshava Munegowda1e7fe1a2011-10-11 13:23:29 +0530102 struct clk *ehci_logic_fck;
Keshava Munegowda17cdd292011-03-01 20:08:17 +0530103
104 void __iomem *uhh_base;
Keshava Munegowda17cdd292011-03-01 20:08:17 +0530105
106 struct usbhs_omap_platform_data platdata;
107
108 u32 usbhs_rev;
109 spinlock_t lock;
Keshava Munegowda17cdd292011-03-01 20:08:17 +0530110};
111/*-------------------------------------------------------------------------*/
112
113const char usbhs_driver_name[] = USBHS_DRIVER_NAME;
Govindraj.Rcbb8c222012-02-15 12:27:50 +0530114static u64 usbhs_dmamask = DMA_BIT_MASK(32);
Keshava Munegowda17cdd292011-03-01 20:08:17 +0530115
116/*-------------------------------------------------------------------------*/
117
118static inline void usbhs_write(void __iomem *base, u32 reg, u32 val)
119{
120 __raw_writel(val, base + reg);
121}
122
123static inline u32 usbhs_read(void __iomem *base, u32 reg)
124{
125 return __raw_readl(base + reg);
126}
127
128static inline void usbhs_writeb(void __iomem *base, u8 reg, u8 val)
129{
130 __raw_writeb(val, base + reg);
131}
132
133static inline u8 usbhs_readb(void __iomem *base, u8 reg)
134{
135 return __raw_readb(base + reg);
136}
137
138/*-------------------------------------------------------------------------*/
139
140static struct platform_device *omap_usbhs_alloc_child(const char *name,
141 struct resource *res, int num_resources, void *pdata,
142 size_t pdata_size, struct device *dev)
143{
144 struct platform_device *child;
145 int ret;
146
147 child = platform_device_alloc(name, 0);
148
149 if (!child) {
150 dev_err(dev, "platform_device_alloc %s failed\n", name);
151 goto err_end;
152 }
153
154 ret = platform_device_add_resources(child, res, num_resources);
155 if (ret) {
156 dev_err(dev, "platform_device_add_resources failed\n");
157 goto err_alloc;
158 }
159
160 ret = platform_device_add_data(child, pdata, pdata_size);
161 if (ret) {
162 dev_err(dev, "platform_device_add_data failed\n");
163 goto err_alloc;
164 }
165
166 child->dev.dma_mask = &usbhs_dmamask;
Govindraj.Rcbb8c222012-02-15 12:27:50 +0530167 dma_set_coherent_mask(&child->dev, DMA_BIT_MASK(32));
Keshava Munegowda17cdd292011-03-01 20:08:17 +0530168 child->dev.parent = dev;
169
170 ret = platform_device_add(child);
171 if (ret) {
172 dev_err(dev, "platform_device_add failed\n");
173 goto err_alloc;
174 }
175
176 return child;
177
178err_alloc:
179 platform_device_put(child);
180
181err_end:
182 return NULL;
183}
184
185static int omap_usbhs_alloc_children(struct platform_device *pdev)
186{
187 struct device *dev = &pdev->dev;
188 struct usbhs_hcd_omap *omap;
189 struct ehci_hcd_omap_platform_data *ehci_data;
190 struct ohci_hcd_omap_platform_data *ohci_data;
191 struct platform_device *ehci;
192 struct platform_device *ohci;
193 struct resource *res;
194 struct resource resources[2];
195 int ret;
196
197 omap = platform_get_drvdata(pdev);
198 ehci_data = omap->platdata.ehci_data;
199 ohci_data = omap->platdata.ohci_data;
200
201 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ehci");
202 if (!res) {
203 dev_err(dev, "EHCI get resource IORESOURCE_MEM failed\n");
204 ret = -ENODEV;
205 goto err_end;
206 }
207 resources[0] = *res;
208
209 res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "ehci-irq");
210 if (!res) {
211 dev_err(dev, " EHCI get resource IORESOURCE_IRQ failed\n");
212 ret = -ENODEV;
213 goto err_end;
214 }
215 resources[1] = *res;
216
217 ehci = omap_usbhs_alloc_child(OMAP_EHCI_DEVICE, resources, 2, ehci_data,
218 sizeof(*ehci_data), dev);
219
220 if (!ehci) {
221 dev_err(dev, "omap_usbhs_alloc_child failed\n");
Axel Lind9107742011-05-14 14:15:36 +0800222 ret = -ENOMEM;
Keshava Munegowda17cdd292011-03-01 20:08:17 +0530223 goto err_end;
224 }
225
226 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ohci");
227 if (!res) {
228 dev_err(dev, "OHCI get resource IORESOURCE_MEM failed\n");
229 ret = -ENODEV;
230 goto err_ehci;
231 }
232 resources[0] = *res;
233
234 res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "ohci-irq");
235 if (!res) {
236 dev_err(dev, "OHCI get resource IORESOURCE_IRQ failed\n");
237 ret = -ENODEV;
238 goto err_ehci;
239 }
240 resources[1] = *res;
241
242 ohci = omap_usbhs_alloc_child(OMAP_OHCI_DEVICE, resources, 2, ohci_data,
243 sizeof(*ohci_data), dev);
244 if (!ohci) {
245 dev_err(dev, "omap_usbhs_alloc_child failed\n");
Axel Lind9107742011-05-14 14:15:36 +0800246 ret = -ENOMEM;
Keshava Munegowda17cdd292011-03-01 20:08:17 +0530247 goto err_ehci;
248 }
249
250 return 0;
251
252err_ehci:
Axel Lind9107742011-05-14 14:15:36 +0800253 platform_device_unregister(ehci);
Keshava Munegowda17cdd292011-03-01 20:08:17 +0530254
255err_end:
256 return ret;
257}
258
Keshava Munegowda17cdd292011-03-01 20:08:17 +0530259static bool is_ohci_port(enum usbhs_omap_port_mode pmode)
260{
261 switch (pmode) {
262 case OMAP_OHCI_PORT_MODE_PHY_6PIN_DATSE0:
263 case OMAP_OHCI_PORT_MODE_PHY_6PIN_DPDM:
264 case OMAP_OHCI_PORT_MODE_PHY_3PIN_DATSE0:
265 case OMAP_OHCI_PORT_MODE_PHY_4PIN_DPDM:
266 case OMAP_OHCI_PORT_MODE_TLL_6PIN_DATSE0:
267 case OMAP_OHCI_PORT_MODE_TLL_6PIN_DPDM:
268 case OMAP_OHCI_PORT_MODE_TLL_3PIN_DATSE0:
269 case OMAP_OHCI_PORT_MODE_TLL_4PIN_DPDM:
270 case OMAP_OHCI_PORT_MODE_TLL_2PIN_DATSE0:
271 case OMAP_OHCI_PORT_MODE_TLL_2PIN_DPDM:
272 return true;
273
274 default:
275 return false;
276 }
277}
278
Keshava Munegowda1e7fe1a2011-10-11 13:23:29 +0530279static int usbhs_runtime_resume(struct device *dev)
Keshava Munegowda17cdd292011-03-01 20:08:17 +0530280{
281 struct usbhs_hcd_omap *omap = dev_get_drvdata(dev);
282 struct usbhs_omap_platform_data *pdata = &omap->platdata;
Keshava Munegowda1e7fe1a2011-10-11 13:23:29 +0530283 unsigned long flags;
Keshava Munegowda17cdd292011-03-01 20:08:17 +0530284
Keshava Munegowda1e7fe1a2011-10-11 13:23:29 +0530285 dev_dbg(dev, "usbhs_runtime_resume\n");
286
Keshava Munegowda17cdd292011-03-01 20:08:17 +0530287 if (!pdata) {
288 dev_dbg(dev, "missing platform_data\n");
Axel Lind11536e2011-04-21 19:52:41 +0530289 return -ENODEV;
Keshava Munegowda17cdd292011-03-01 20:08:17 +0530290 }
291
Keshava Munegowda4dc2cce2012-07-16 19:01:09 +0530292 omap_tll_enable();
Keshava Munegowda17cdd292011-03-01 20:08:17 +0530293 spin_lock_irqsave(&omap->lock, flags);
Keshava Munegowda17cdd292011-03-01 20:08:17 +0530294
Keshava Munegowda1e7fe1a2011-10-11 13:23:29 +0530295 if (omap->ehci_logic_fck && !IS_ERR(omap->ehci_logic_fck))
296 clk_enable(omap->ehci_logic_fck);
297
Keshava Munegowda760189b2012-07-16 19:01:10 +0530298 if (is_ehci_tll_mode(pdata->port_mode[0]))
Keshava Munegowda1e7fe1a2011-10-11 13:23:29 +0530299 clk_enable(omap->usbhost_p1_fck);
Keshava Munegowda760189b2012-07-16 19:01:10 +0530300 if (is_ehci_tll_mode(pdata->port_mode[1]))
Keshava Munegowda1e7fe1a2011-10-11 13:23:29 +0530301 clk_enable(omap->usbhost_p2_fck);
Keshava Munegowda760189b2012-07-16 19:01:10 +0530302
Keshava Munegowda1e7fe1a2011-10-11 13:23:29 +0530303 clk_enable(omap->utmi_p1_fck);
304 clk_enable(omap->utmi_p2_fck);
305
306 spin_unlock_irqrestore(&omap->lock, flags);
307
308 return 0;
309}
310
311static int usbhs_runtime_suspend(struct device *dev)
312{
313 struct usbhs_hcd_omap *omap = dev_get_drvdata(dev);
314 struct usbhs_omap_platform_data *pdata = &omap->platdata;
315 unsigned long flags;
316
317 dev_dbg(dev, "usbhs_runtime_suspend\n");
318
319 if (!pdata) {
320 dev_dbg(dev, "missing platform_data\n");
321 return -ENODEV;
322 }
323
324 spin_lock_irqsave(&omap->lock, flags);
325
Keshava Munegowda760189b2012-07-16 19:01:10 +0530326 if (is_ehci_tll_mode(pdata->port_mode[0]))
Keshava Munegowda1e7fe1a2011-10-11 13:23:29 +0530327 clk_disable(omap->usbhost_p1_fck);
Keshava Munegowda760189b2012-07-16 19:01:10 +0530328 if (is_ehci_tll_mode(pdata->port_mode[1]))
Keshava Munegowda1e7fe1a2011-10-11 13:23:29 +0530329 clk_disable(omap->usbhost_p2_fck);
Keshava Munegowda760189b2012-07-16 19:01:10 +0530330
Keshava Munegowda1e7fe1a2011-10-11 13:23:29 +0530331 clk_disable(omap->utmi_p2_fck);
332 clk_disable(omap->utmi_p1_fck);
333
334 if (omap->ehci_logic_fck && !IS_ERR(omap->ehci_logic_fck))
335 clk_disable(omap->ehci_logic_fck);
336
337 spin_unlock_irqrestore(&omap->lock, flags);
Keshava Munegowda4dc2cce2012-07-16 19:01:09 +0530338 omap_tll_disable();
Keshava Munegowda1e7fe1a2011-10-11 13:23:29 +0530339
340 return 0;
341}
342
343static void omap_usbhs_init(struct device *dev)
344{
345 struct usbhs_hcd_omap *omap = dev_get_drvdata(dev);
346 struct usbhs_omap_platform_data *pdata = &omap->platdata;
347 unsigned long flags;
348 unsigned reg;
349
350 dev_dbg(dev, "starting TI HSUSB Controller\n");
351
Russ Dillc05995c2012-06-14 09:24:21 -0700352 if (pdata->ehci_data->phy_reset) {
353 if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0]))
354 gpio_request_one(pdata->ehci_data->reset_gpio_port[0],
355 GPIOF_OUT_INIT_LOW, "USB1 PHY reset");
356
357 if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[1]))
358 gpio_request_one(pdata->ehci_data->reset_gpio_port[1],
359 GPIOF_OUT_INIT_LOW, "USB2 PHY reset");
360
361 /* Hold the PHY in RESET for enough time till DIR is high */
362 udelay(10);
363 }
364
Keshava Munegowda760189b2012-07-16 19:01:10 +0530365 pm_runtime_get_sync(dev);
Russ Dillc05995c2012-06-14 09:24:21 -0700366 spin_lock_irqsave(&omap->lock, flags);
Keshava Munegowda17cdd292011-03-01 20:08:17 +0530367 omap->usbhs_rev = usbhs_read(omap->uhh_base, OMAP_UHH_REVISION);
368 dev_dbg(dev, "OMAP UHH_REVISION 0x%x\n", omap->usbhs_rev);
369
Keshava Munegowda17cdd292011-03-01 20:08:17 +0530370 reg = usbhs_read(omap->uhh_base, OMAP_UHH_HOSTCONFIG);
371 /* setup ULPI bypass and burst configurations */
372 reg |= (OMAP_UHH_HOSTCONFIG_INCR4_BURST_EN
373 | OMAP_UHH_HOSTCONFIG_INCR8_BURST_EN
374 | OMAP_UHH_HOSTCONFIG_INCR16_BURST_EN);
375 reg |= OMAP4_UHH_HOSTCONFIG_APP_START_CLK;
376 reg &= ~OMAP_UHH_HOSTCONFIG_INCRX_ALIGN_EN;
377
378 if (is_omap_usbhs_rev1(omap)) {
379 if (pdata->port_mode[0] == OMAP_USBHS_PORT_MODE_UNUSED)
380 reg &= ~OMAP_UHH_HOSTCONFIG_P1_CONNECT_STATUS;
381 if (pdata->port_mode[1] == OMAP_USBHS_PORT_MODE_UNUSED)
382 reg &= ~OMAP_UHH_HOSTCONFIG_P2_CONNECT_STATUS;
383 if (pdata->port_mode[2] == OMAP_USBHS_PORT_MODE_UNUSED)
384 reg &= ~OMAP_UHH_HOSTCONFIG_P3_CONNECT_STATUS;
385
386 /* Bypass the TLL module for PHY mode operation */
387 if (cpu_is_omap3430() && (omap_rev() <= OMAP3430_REV_ES2_1)) {
388 dev_dbg(dev, "OMAP3 ES version <= ES2.1\n");
389 if (is_ehci_phy_mode(pdata->port_mode[0]) ||
390 is_ehci_phy_mode(pdata->port_mode[1]) ||
391 is_ehci_phy_mode(pdata->port_mode[2]))
392 reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_BYPASS;
393 else
394 reg |= OMAP_UHH_HOSTCONFIG_ULPI_BYPASS;
395 } else {
396 dev_dbg(dev, "OMAP3 ES version > ES2.1\n");
397 if (is_ehci_phy_mode(pdata->port_mode[0]))
398 reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS;
399 else
400 reg |= OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS;
401 if (is_ehci_phy_mode(pdata->port_mode[1]))
402 reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS;
403 else
404 reg |= OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS;
405 if (is_ehci_phy_mode(pdata->port_mode[2]))
406 reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P3_BYPASS;
407 else
408 reg |= OMAP_UHH_HOSTCONFIG_ULPI_P3_BYPASS;
409 }
410 } else if (is_omap_usbhs_rev2(omap)) {
411 /* Clear port mode fields for PHY mode*/
412 reg &= ~OMAP4_P1_MODE_CLEAR;
413 reg &= ~OMAP4_P2_MODE_CLEAR;
414
Keshava Munegowda17cdd292011-03-01 20:08:17 +0530415 if (is_ehci_tll_mode(pdata->port_mode[0]) ||
416 (is_ohci_port(pdata->port_mode[0])))
417 reg |= OMAP4_P1_MODE_TLL;
418 else if (is_ehci_hsic_mode(pdata->port_mode[0]))
419 reg |= OMAP4_P1_MODE_HSIC;
420
421 if (is_ehci_tll_mode(pdata->port_mode[1]) ||
422 (is_ohci_port(pdata->port_mode[1])))
423 reg |= OMAP4_P2_MODE_TLL;
424 else if (is_ehci_hsic_mode(pdata->port_mode[1]))
425 reg |= OMAP4_P2_MODE_HSIC;
426 }
427
428 usbhs_write(omap->uhh_base, OMAP_UHH_HOSTCONFIG, reg);
429 dev_dbg(dev, "UHH setup done, uhh_hostconfig=%x\n", reg);
430
Axel Lind11536e2011-04-21 19:52:41 +0530431 spin_unlock_irqrestore(&omap->lock, flags);
Russ Dillc05995c2012-06-14 09:24:21 -0700432
Keshava Munegowda760189b2012-07-16 19:01:10 +0530433 pm_runtime_put_sync(dev);
Russ Dillc05995c2012-06-14 09:24:21 -0700434 if (pdata->ehci_data->phy_reset) {
435 /* Hold the PHY in RESET for enough time till
436 * PHY is settled and ready
437 */
438 udelay(10);
439
440 if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0]))
441 gpio_set_value_cansleep
442 (pdata->ehci_data->reset_gpio_port[0], 1);
443
444 if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[1]))
445 gpio_set_value_cansleep
446 (pdata->ehci_data->reset_gpio_port[1], 1);
447 }
Keshava Munegowda17cdd292011-03-01 20:08:17 +0530448}
449
Russ Dillc05995c2012-06-14 09:24:21 -0700450static void omap_usbhs_deinit(struct device *dev)
451{
452 struct usbhs_hcd_omap *omap = dev_get_drvdata(dev);
453 struct usbhs_omap_platform_data *pdata = &omap->platdata;
454
455 if (pdata->ehci_data->phy_reset) {
456 if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0]))
457 gpio_free(pdata->ehci_data->reset_gpio_port[0]);
458
459 if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[1]))
460 gpio_free(pdata->ehci_data->reset_gpio_port[1]);
461 }
462}
463
Keshava Munegowda1e7fe1a2011-10-11 13:23:29 +0530464
465/**
466 * usbhs_omap_probe - initialize TI-based HCDs
467 *
468 * Allocates basic resources for this USB host controller.
469 */
470static int __devinit usbhs_omap_probe(struct platform_device *pdev)
Keshava Munegowda17cdd292011-03-01 20:08:17 +0530471{
Keshava Munegowda1e7fe1a2011-10-11 13:23:29 +0530472 struct device *dev = &pdev->dev;
473 struct usbhs_omap_platform_data *pdata = dev->platform_data;
474 struct usbhs_hcd_omap *omap;
475 struct resource *res;
476 int ret = 0;
477 int i;
Keshava Munegowda17cdd292011-03-01 20:08:17 +0530478
Keshava Munegowda1e7fe1a2011-10-11 13:23:29 +0530479 if (!pdata) {
480 dev_err(dev, "Missing platform data\n");
481 ret = -ENOMEM;
482 goto end_probe;
483 }
484
485 omap = kzalloc(sizeof(*omap), GFP_KERNEL);
486 if (!omap) {
487 dev_err(dev, "Memory allocation failed\n");
488 ret = -ENOMEM;
489 goto end_probe;
490 }
491
492 spin_lock_init(&omap->lock);
493
494 for (i = 0; i < OMAP3_HS_USB_PORTS; i++)
495 omap->platdata.port_mode[i] = pdata->port_mode[i];
496
497 omap->platdata.ehci_data = pdata->ehci_data;
498 omap->platdata.ohci_data = pdata->ohci_data;
499
500 pm_runtime_enable(dev);
501
502
503 for (i = 0; i < OMAP3_HS_USB_PORTS; i++)
504 if (is_ehci_phy_mode(i) || is_ehci_tll_mode(i) ||
505 is_ehci_hsic_mode(i)) {
506 omap->ehci_logic_fck = clk_get(dev, "ehci_logic_fck");
507 if (IS_ERR(omap->ehci_logic_fck)) {
508 ret = PTR_ERR(omap->ehci_logic_fck);
509 dev_warn(dev, "ehci_logic_fck failed:%d\n",
510 ret);
511 }
512 break;
513 }
514
515 omap->utmi_p1_fck = clk_get(dev, "utmi_p1_gfclk");
516 if (IS_ERR(omap->utmi_p1_fck)) {
517 ret = PTR_ERR(omap->utmi_p1_fck);
518 dev_err(dev, "utmi_p1_gfclk failed error:%d\n", ret);
519 goto err_end;
520 }
521
522 omap->xclk60mhsp1_ck = clk_get(dev, "xclk60mhsp1_ck");
523 if (IS_ERR(omap->xclk60mhsp1_ck)) {
524 ret = PTR_ERR(omap->xclk60mhsp1_ck);
525 dev_err(dev, "xclk60mhsp1_ck failed error:%d\n", ret);
526 goto err_utmi_p1_fck;
527 }
528
529 omap->utmi_p2_fck = clk_get(dev, "utmi_p2_gfclk");
530 if (IS_ERR(omap->utmi_p2_fck)) {
531 ret = PTR_ERR(omap->utmi_p2_fck);
532 dev_err(dev, "utmi_p2_gfclk failed error:%d\n", ret);
533 goto err_xclk60mhsp1_ck;
534 }
535
536 omap->xclk60mhsp2_ck = clk_get(dev, "xclk60mhsp2_ck");
537 if (IS_ERR(omap->xclk60mhsp2_ck)) {
538 ret = PTR_ERR(omap->xclk60mhsp2_ck);
539 dev_err(dev, "xclk60mhsp2_ck failed error:%d\n", ret);
540 goto err_utmi_p2_fck;
541 }
542
543 omap->usbhost_p1_fck = clk_get(dev, "usb_host_hs_utmi_p1_clk");
544 if (IS_ERR(omap->usbhost_p1_fck)) {
545 ret = PTR_ERR(omap->usbhost_p1_fck);
546 dev_err(dev, "usbhost_p1_fck failed error:%d\n", ret);
547 goto err_xclk60mhsp2_ck;
548 }
549
Keshava Munegowda1e7fe1a2011-10-11 13:23:29 +0530550 omap->usbhost_p2_fck = clk_get(dev, "usb_host_hs_utmi_p2_clk");
551 if (IS_ERR(omap->usbhost_p2_fck)) {
552 ret = PTR_ERR(omap->usbhost_p2_fck);
553 dev_err(dev, "usbhost_p2_fck failed error:%d\n", ret);
Keshava Munegowda760189b2012-07-16 19:01:10 +0530554 goto err_usbhost_p1_fck;
Keshava Munegowda1e7fe1a2011-10-11 13:23:29 +0530555 }
556
557 omap->init_60m_fclk = clk_get(dev, "init_60m_fclk");
558 if (IS_ERR(omap->init_60m_fclk)) {
559 ret = PTR_ERR(omap->init_60m_fclk);
560 dev_err(dev, "init_60m_fclk failed error:%d\n", ret);
Keshava Munegowda760189b2012-07-16 19:01:10 +0530561 goto err_usbhost_p2_fck;
Keshava Munegowda1e7fe1a2011-10-11 13:23:29 +0530562 }
563
564 if (is_ehci_phy_mode(pdata->port_mode[0])) {
565 /* for OMAP3 , the clk set paretn fails */
566 ret = clk_set_parent(omap->utmi_p1_fck,
567 omap->xclk60mhsp1_ck);
568 if (ret != 0)
569 dev_err(dev, "xclk60mhsp1_ck set parent"
570 "failed error:%d\n", ret);
571 } else if (is_ehci_tll_mode(pdata->port_mode[0])) {
572 ret = clk_set_parent(omap->utmi_p1_fck,
573 omap->init_60m_fclk);
574 if (ret != 0)
575 dev_err(dev, "init_60m_fclk set parent"
576 "failed error:%d\n", ret);
577 }
578
579 if (is_ehci_phy_mode(pdata->port_mode[1])) {
580 ret = clk_set_parent(omap->utmi_p2_fck,
581 omap->xclk60mhsp2_ck);
582 if (ret != 0)
583 dev_err(dev, "xclk60mhsp2_ck set parent"
584 "failed error:%d\n", ret);
585 } else if (is_ehci_tll_mode(pdata->port_mode[1])) {
586 ret = clk_set_parent(omap->utmi_p2_fck,
587 omap->init_60m_fclk);
588 if (ret != 0)
589 dev_err(dev, "init_60m_fclk set parent"
590 "failed error:%d\n", ret);
591 }
592
593 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "uhh");
594 if (!res) {
595 dev_err(dev, "UHH EHCI get resource failed\n");
596 ret = -ENODEV;
597 goto err_init_60m_fclk;
598 }
599
600 omap->uhh_base = ioremap(res->start, resource_size(res));
601 if (!omap->uhh_base) {
602 dev_err(dev, "UHH ioremap failed\n");
603 ret = -ENOMEM;
604 goto err_init_60m_fclk;
605 }
606
Keshava Munegowda1e7fe1a2011-10-11 13:23:29 +0530607 platform_set_drvdata(pdev, omap);
608
Govindraj.Rf0447a62012-02-15 15:53:34 +0530609 omap_usbhs_init(dev);
Keshava Munegowda1e7fe1a2011-10-11 13:23:29 +0530610 ret = omap_usbhs_alloc_children(pdev);
611 if (ret) {
612 dev_err(dev, "omap_usbhs_alloc_children failed\n");
613 goto err_alloc;
614 }
615
Keshava Munegowda1e7fe1a2011-10-11 13:23:29 +0530616 goto end_probe;
617
618err_alloc:
Russ Dillc05995c2012-06-14 09:24:21 -0700619 omap_usbhs_deinit(&pdev->dev);
Keshava Munegowda1e7fe1a2011-10-11 13:23:29 +0530620 iounmap(omap->uhh_base);
621
622err_init_60m_fclk:
623 clk_put(omap->init_60m_fclk);
624
Keshava Munegowda1e7fe1a2011-10-11 13:23:29 +0530625err_usbhost_p2_fck:
626 clk_put(omap->usbhost_p2_fck);
627
Keshava Munegowda1e7fe1a2011-10-11 13:23:29 +0530628err_usbhost_p1_fck:
629 clk_put(omap->usbhost_p1_fck);
630
631err_xclk60mhsp2_ck:
632 clk_put(omap->xclk60mhsp2_ck);
633
634err_utmi_p2_fck:
635 clk_put(omap->utmi_p2_fck);
636
637err_xclk60mhsp1_ck:
638 clk_put(omap->xclk60mhsp1_ck);
639
640err_utmi_p1_fck:
641 clk_put(omap->utmi_p1_fck);
642
643err_end:
644 clk_put(omap->ehci_logic_fck);
645 pm_runtime_disable(dev);
646 kfree(omap);
647
648end_probe:
649 return ret;
Keshava Munegowda17cdd292011-03-01 20:08:17 +0530650}
Keshava Munegowda1e7fe1a2011-10-11 13:23:29 +0530651
652/**
653 * usbhs_omap_remove - shutdown processing for UHH & TLL HCDs
654 * @pdev: USB Host Controller being removed
655 *
656 * Reverses the effect of usbhs_omap_probe().
657 */
658static int __devexit usbhs_omap_remove(struct platform_device *pdev)
659{
660 struct usbhs_hcd_omap *omap = platform_get_drvdata(pdev);
661
Russ Dillc05995c2012-06-14 09:24:21 -0700662 omap_usbhs_deinit(&pdev->dev);
Keshava Munegowda1e7fe1a2011-10-11 13:23:29 +0530663 iounmap(omap->uhh_base);
664 clk_put(omap->init_60m_fclk);
Keshava Munegowda1e7fe1a2011-10-11 13:23:29 +0530665 clk_put(omap->usbhost_p2_fck);
Keshava Munegowda1e7fe1a2011-10-11 13:23:29 +0530666 clk_put(omap->usbhost_p1_fck);
667 clk_put(omap->xclk60mhsp2_ck);
668 clk_put(omap->utmi_p2_fck);
669 clk_put(omap->xclk60mhsp1_ck);
670 clk_put(omap->utmi_p1_fck);
671 clk_put(omap->ehci_logic_fck);
672 pm_runtime_disable(&pdev->dev);
673 kfree(omap);
674
675 return 0;
676}
677
678static const struct dev_pm_ops usbhsomap_dev_pm_ops = {
679 .runtime_suspend = usbhs_runtime_suspend,
680 .runtime_resume = usbhs_runtime_resume,
681};
Keshava Munegowda17cdd292011-03-01 20:08:17 +0530682
683static struct platform_driver usbhs_omap_driver = {
684 .driver = {
685 .name = (char *)usbhs_driver_name,
686 .owner = THIS_MODULE,
Keshava Munegowda1e7fe1a2011-10-11 13:23:29 +0530687 .pm = &usbhsomap_dev_pm_ops,
Keshava Munegowda17cdd292011-03-01 20:08:17 +0530688 },
689 .remove = __exit_p(usbhs_omap_remove),
690};
691
692MODULE_AUTHOR("Keshava Munegowda <keshava_mgowda@ti.com>");
693MODULE_ALIAS("platform:" USBHS_DRIVER_NAME);
694MODULE_LICENSE("GPL v2");
695MODULE_DESCRIPTION("usb host common core driver for omap EHCI and OHCI");
696
697static int __init omap_usbhs_drvinit(void)
698{
699 return platform_driver_probe(&usbhs_omap_driver, usbhs_omap_probe);
700}
701
702/*
703 * init before ehci and ohci drivers;
704 * The usbhs core driver should be initialized much before
705 * the omap ehci and ohci probe functions are called.
Keshava Munegowda4dc2cce2012-07-16 19:01:09 +0530706 * This usbhs core driver should be initialized after
707 * usb tll driver
Keshava Munegowda17cdd292011-03-01 20:08:17 +0530708 */
Keshava Munegowda4dc2cce2012-07-16 19:01:09 +0530709fs_initcall_sync(omap_usbhs_drvinit);
Keshava Munegowda17cdd292011-03-01 20:08:17 +0530710
711static void __exit omap_usbhs_drvexit(void)
712{
713 platform_driver_unregister(&usbhs_omap_driver);
714}
715module_exit(omap_usbhs_drvexit);