Blame view

drivers/mfd/omap-usb-host.c 23.4 KB
17cdd29d6   Keshava Munegowda   usb: host: omap: ...
1
2
3
  /**
   * omap-usb-host.c - The USBHS core driver for OMAP EHCI & OHCI
   *
03a8f438f   Roger Quadros   mfd: omap-usb-hos...
4
   * Copyright (C) 2011-2013 Texas Instruments Incorporated - http://www.ti.com
17cdd29d6   Keshava Munegowda   usb: host: omap: ...
5
   * Author: Keshava Munegowda <keshava_mgowda@ti.com>
03a8f438f   Roger Quadros   mfd: omap-usb-hos...
6
   * Author: Roger Quadros <rogerq@ti.com>
17cdd29d6   Keshava Munegowda   usb: host: omap: ...
7
8
9
10
11
12
13
14
15
16
17
18
19
20
   *
   * This program is free software: you can redistribute it and/or modify
   * it under the terms of the GNU General Public License version 2  of
   * the License as published by the Free Software Foundation.
   *
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License
   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
   */
  #include <linux/kernel.h>
417e206b1   Ming Lei   mfd: Fix omap-usb...
21
  #include <linux/module.h>
17cdd29d6   Keshava Munegowda   usb: host: omap: ...
22
23
24
  #include <linux/types.h>
  #include <linux/slab.h>
  #include <linux/delay.h>
17cdd29d6   Keshava Munegowda   usb: host: omap: ...
25
26
  #include <linux/clk.h>
  #include <linux/dma-mapping.h>
c05995c3d   Russ Dill   mfd: USB: Fix the...
27
  #include <linux/gpio.h>
e8c4a7acc   Felipe Balbi   ARM: OMAP: move O...
28
29
  #include <linux/platform_device.h>
  #include <linux/platform_data/usb-omap.h>
1e7fe1a92   Keshava Munegowda   MFD: OMAP: USB: R...
30
  #include <linux/pm_runtime.h>
03a8f438f   Roger Quadros   mfd: omap-usb-hos...
31
32
  #include <linux/of.h>
  #include <linux/of_platform.h>
d011c4508   Sachin Kamat   mfd: omap-usb-hos...
33
  #include <linux/err.h>
17cdd29d6   Keshava Munegowda   usb: host: omap: ...
34

e8c4a7acc   Felipe Balbi   ARM: OMAP: move O...
35
  #include "omap-usb.h"
a6d3a6622   Keshava Munegowda   ARM: OMAP: USB: d...
36
  #define USBHS_DRIVER_NAME	"usbhs_omap"
17cdd29d6   Keshava Munegowda   usb: host: omap: ...
37
38
39
40
  #define OMAP_EHCI_DEVICE	"ehci-omap"
  #define OMAP_OHCI_DEVICE	"ohci-omap3"
  
  /* OMAP USBHOST Register addresses  */
17cdd29d6   Keshava Munegowda   usb: host: omap: ...
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
  /* UHH Register Set */
  #define	OMAP_UHH_REVISION				(0x00)
  #define	OMAP_UHH_SYSCONFIG				(0x10)
  #define	OMAP_UHH_SYSCONFIG_MIDLEMODE			(1 << 12)
  #define	OMAP_UHH_SYSCONFIG_CACTIVITY			(1 << 8)
  #define	OMAP_UHH_SYSCONFIG_SIDLEMODE			(1 << 3)
  #define	OMAP_UHH_SYSCONFIG_ENAWAKEUP			(1 << 2)
  #define	OMAP_UHH_SYSCONFIG_SOFTRESET			(1 << 1)
  #define	OMAP_UHH_SYSCONFIG_AUTOIDLE			(1 << 0)
  
  #define	OMAP_UHH_SYSSTATUS				(0x14)
  #define	OMAP_UHH_HOSTCONFIG				(0x40)
  #define	OMAP_UHH_HOSTCONFIG_ULPI_BYPASS			(1 << 0)
  #define	OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS		(1 << 0)
  #define	OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS		(1 << 11)
  #define	OMAP_UHH_HOSTCONFIG_ULPI_P3_BYPASS		(1 << 12)
  #define OMAP_UHH_HOSTCONFIG_INCR4_BURST_EN		(1 << 2)
  #define OMAP_UHH_HOSTCONFIG_INCR8_BURST_EN		(1 << 3)
  #define OMAP_UHH_HOSTCONFIG_INCR16_BURST_EN		(1 << 4)
  #define OMAP_UHH_HOSTCONFIG_INCRX_ALIGN_EN		(1 << 5)
  #define OMAP_UHH_HOSTCONFIG_P1_CONNECT_STATUS		(1 << 8)
  #define OMAP_UHH_HOSTCONFIG_P2_CONNECT_STATUS		(1 << 9)
  #define OMAP_UHH_HOSTCONFIG_P3_CONNECT_STATUS		(1 << 10)
  #define OMAP4_UHH_HOSTCONFIG_APP_START_CLK		(1 << 31)
  
  /* OMAP4-specific defines */
  #define OMAP4_UHH_SYSCONFIG_IDLEMODE_CLEAR		(3 << 2)
  #define OMAP4_UHH_SYSCONFIG_NOIDLE			(1 << 2)
  #define OMAP4_UHH_SYSCONFIG_STDBYMODE_CLEAR		(3 << 4)
  #define OMAP4_UHH_SYSCONFIG_NOSTDBY			(1 << 4)
  #define OMAP4_UHH_SYSCONFIG_SOFTRESET			(1 << 0)
  
  #define OMAP4_P1_MODE_CLEAR				(3 << 16)
  #define OMAP4_P1_MODE_TLL				(1 << 16)
  #define OMAP4_P1_MODE_HSIC				(3 << 16)
  #define OMAP4_P2_MODE_CLEAR				(3 << 18)
  #define OMAP4_P2_MODE_TLL				(1 << 18)
  #define OMAP4_P2_MODE_HSIC				(3 << 18)
17cdd29d6   Keshava Munegowda   usb: host: omap: ...
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
  #define	OMAP_UHH_DEBUG_CSR				(0x44)
  
  /* Values of UHH_REVISION - Note: these are not given in the TRM */
  #define OMAP_USBHS_REV1		0x00000010	/* OMAP3 */
  #define OMAP_USBHS_REV2		0x50700100	/* OMAP4 */
  
  #define is_omap_usbhs_rev1(x)	(x->usbhs_rev == OMAP_USBHS_REV1)
  #define is_omap_usbhs_rev2(x)	(x->usbhs_rev == OMAP_USBHS_REV2)
  
  #define is_ehci_phy_mode(x)	(x == OMAP_EHCI_PORT_MODE_PHY)
  #define is_ehci_tll_mode(x)	(x == OMAP_EHCI_PORT_MODE_TLL)
  #define is_ehci_hsic_mode(x)	(x == OMAP_EHCI_PORT_MODE_HSIC)
  
  
  struct usbhs_hcd_omap {
d7eaf8661   Roger Quadros   mfd: omap-usb-hos...
94
  	int				nports;
06ba7dc75   Roger Quadros   mfd: omap-usb-hos...
95
  	struct clk			**utmi_clk;
340c64eab   Roger Quadros   mfd: omap-usb-hos...
96
97
  	struct clk			**hsic60m_clk;
  	struct clk			**hsic480m_clk;
d7eaf8661   Roger Quadros   mfd: omap-usb-hos...
98

17cdd29d6   Keshava Munegowda   usb: host: omap: ...
99
100
  	struct clk			*xclk60mhsp1_ck;
  	struct clk			*xclk60mhsp2_ck;
06ba7dc75   Roger Quadros   mfd: omap-usb-hos...
101
102
  	struct clk			*utmi_p1_gfclk;
  	struct clk			*utmi_p2_gfclk;
17cdd29d6   Keshava Munegowda   usb: host: omap: ...
103
  	struct clk			*init_60m_fclk;
1e7fe1a92   Keshava Munegowda   MFD: OMAP: USB: R...
104
  	struct clk			*ehci_logic_fck;
17cdd29d6   Keshava Munegowda   usb: host: omap: ...
105
106
  
  	void __iomem			*uhh_base;
17cdd29d6   Keshava Munegowda   usb: host: omap: ...
107

9d9c6ae79   Roger Quadros   mfd: omap-usb-hos...
108
  	struct usbhs_omap_platform_data	*pdata;
17cdd29d6   Keshava Munegowda   usb: host: omap: ...
109
110
  
  	u32				usbhs_rev;
17cdd29d6   Keshava Munegowda   usb: host: omap: ...
111
112
  };
  /*-------------------------------------------------------------------------*/
7844b989b   Sachin Kamat   mfd: omap-usb-hos...
113
  static const char usbhs_driver_name[] = USBHS_DRIVER_NAME;
cbb8c220e   Govindraj.R   mfd: Remove omap-...
114
  static u64 usbhs_dmamask = DMA_BIT_MASK(32);
17cdd29d6   Keshava Munegowda   usb: host: omap: ...
115
116
117
118
119
  
  /*-------------------------------------------------------------------------*/
  
  static inline void usbhs_write(void __iomem *base, u32 reg, u32 val)
  {
9981a3146   Victor Kamensky   mfd: omap-usb-hos...
120
  	writel_relaxed(val, base + reg);
17cdd29d6   Keshava Munegowda   usb: host: omap: ...
121
122
123
124
  }
  
  static inline u32 usbhs_read(void __iomem *base, u32 reg)
  {
9981a3146   Victor Kamensky   mfd: omap-usb-hos...
125
  	return readl_relaxed(base + reg);
17cdd29d6   Keshava Munegowda   usb: host: omap: ...
126
  }
17cdd29d6   Keshava Munegowda   usb: host: omap: ...
127
  /*-------------------------------------------------------------------------*/
03a8f438f   Roger Quadros   mfd: omap-usb-hos...
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
  /**
   * Map 'enum usbhs_omap_port_mode' found in <linux/platform_data/usb-omap.h>
   * to the device tree binding portN-mode found in
   * 'Documentation/devicetree/bindings/mfd/omap-usb-host.txt'
   */
  static const char * const port_modes[] = {
  	[OMAP_USBHS_PORT_MODE_UNUSED]	= "",
  	[OMAP_EHCI_PORT_MODE_PHY]	= "ehci-phy",
  	[OMAP_EHCI_PORT_MODE_TLL]	= "ehci-tll",
  	[OMAP_EHCI_PORT_MODE_HSIC]	= "ehci-hsic",
  	[OMAP_OHCI_PORT_MODE_PHY_6PIN_DATSE0]	= "ohci-phy-6pin-datse0",
  	[OMAP_OHCI_PORT_MODE_PHY_6PIN_DPDM]	= "ohci-phy-6pin-dpdm",
  	[OMAP_OHCI_PORT_MODE_PHY_3PIN_DATSE0]	= "ohci-phy-3pin-datse0",
  	[OMAP_OHCI_PORT_MODE_PHY_4PIN_DPDM]	= "ohci-phy-4pin-dpdm",
  	[OMAP_OHCI_PORT_MODE_TLL_6PIN_DATSE0]	= "ohci-tll-6pin-datse0",
  	[OMAP_OHCI_PORT_MODE_TLL_6PIN_DPDM]	= "ohci-tll-6pin-dpdm",
  	[OMAP_OHCI_PORT_MODE_TLL_3PIN_DATSE0]	= "ohci-tll-3pin-datse0",
  	[OMAP_OHCI_PORT_MODE_TLL_4PIN_DPDM]	= "ohci-tll-4pin-dpdm",
  	[OMAP_OHCI_PORT_MODE_TLL_2PIN_DATSE0]	= "ohci-tll-2pin-datse0",
  	[OMAP_OHCI_PORT_MODE_TLL_2PIN_DPDM]	= "ohci-tll-2pin-dpdm",
  };
  
  /**
   * omap_usbhs_get_dt_port_mode - Get the 'enum usbhs_omap_port_mode'
   * from the port mode string.
   * @mode: The port mode string, usually obtained from device tree.
   *
   * The function returns the 'enum usbhs_omap_port_mode' that matches the
   * provided port mode string as per the port_modes table.
   * If no match is found it returns -ENODEV
   */
c7c762777   Lee Jones   mfd: omap-usb-hos...
159
  static int omap_usbhs_get_dt_port_mode(const char *mode)
03a8f438f   Roger Quadros   mfd: omap-usb-hos...
160
161
162
163
164
165
166
167
168
169
  {
  	int i;
  
  	for (i = 0; i < ARRAY_SIZE(port_modes); i++) {
  		if (!strcmp(mode, port_modes[i]))
  			return i;
  	}
  
  	return -ENODEV;
  }
17cdd29d6   Keshava Munegowda   usb: host: omap: ...
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
  static struct platform_device *omap_usbhs_alloc_child(const char *name,
  			struct resource	*res, int num_resources, void *pdata,
  			size_t pdata_size, struct device *dev)
  {
  	struct platform_device	*child;
  	int			ret;
  
  	child = platform_device_alloc(name, 0);
  
  	if (!child) {
  		dev_err(dev, "platform_device_alloc %s failed
  ", name);
  		goto err_end;
  	}
  
  	ret = platform_device_add_resources(child, res, num_resources);
  	if (ret) {
  		dev_err(dev, "platform_device_add_resources failed
  ");
  		goto err_alloc;
  	}
  
  	ret = platform_device_add_data(child, pdata, pdata_size);
  	if (ret) {
  		dev_err(dev, "platform_device_add_data failed
  ");
  		goto err_alloc;
  	}
  
  	child->dev.dma_mask		= &usbhs_dmamask;
cbb8c220e   Govindraj.R   mfd: Remove omap-...
200
  	dma_set_coherent_mask(&child->dev, DMA_BIT_MASK(32));
17cdd29d6   Keshava Munegowda   usb: host: omap: ...
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
  	child->dev.parent		= dev;
  
  	ret = platform_device_add(child);
  	if (ret) {
  		dev_err(dev, "platform_device_add failed
  ");
  		goto err_alloc;
  	}
  
  	return child;
  
  err_alloc:
  	platform_device_put(child);
  
  err_end:
  	return NULL;
  }
  
  static int omap_usbhs_alloc_children(struct platform_device *pdev)
  {
  	struct device				*dev = &pdev->dev;
334a41ce9   Jingoo Han   mfd: Use dev_get_...
222
  	struct usbhs_omap_platform_data		*pdata = dev_get_platdata(dev);
17cdd29d6   Keshava Munegowda   usb: host: omap: ...
223
224
225
226
227
  	struct platform_device			*ehci;
  	struct platform_device			*ohci;
  	struct resource				*res;
  	struct resource				resources[2];
  	int					ret;
17cdd29d6   Keshava Munegowda   usb: host: omap: ...
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
  	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ehci");
  	if (!res) {
  		dev_err(dev, "EHCI get resource IORESOURCE_MEM failed
  ");
  		ret = -ENODEV;
  		goto err_end;
  	}
  	resources[0] = *res;
  
  	res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "ehci-irq");
  	if (!res) {
  		dev_err(dev, " EHCI get resource IORESOURCE_IRQ failed
  ");
  		ret = -ENODEV;
  		goto err_end;
  	}
  	resources[1] = *res;
9d9c6ae79   Roger Quadros   mfd: omap-usb-hos...
245
246
  	ehci = omap_usbhs_alloc_child(OMAP_EHCI_DEVICE, resources, 2, pdata,
  		sizeof(*pdata), dev);
17cdd29d6   Keshava Munegowda   usb: host: omap: ...
247
248
249
250
  
  	if (!ehci) {
  		dev_err(dev, "omap_usbhs_alloc_child failed
  ");
d910774f1   Axel Lin   mfd: Fix omap_usb...
251
  		ret = -ENOMEM;
17cdd29d6   Keshava Munegowda   usb: host: omap: ...
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
  		goto err_end;
  	}
  
  	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ohci");
  	if (!res) {
  		dev_err(dev, "OHCI get resource IORESOURCE_MEM failed
  ");
  		ret = -ENODEV;
  		goto err_ehci;
  	}
  	resources[0] = *res;
  
  	res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "ohci-irq");
  	if (!res) {
  		dev_err(dev, "OHCI get resource IORESOURCE_IRQ failed
  ");
  		ret = -ENODEV;
  		goto err_ehci;
  	}
  	resources[1] = *res;
9d9c6ae79   Roger Quadros   mfd: omap-usb-hos...
272
273
  	ohci = omap_usbhs_alloc_child(OMAP_OHCI_DEVICE, resources, 2, pdata,
  		sizeof(*pdata), dev);
17cdd29d6   Keshava Munegowda   usb: host: omap: ...
274
275
276
  	if (!ohci) {
  		dev_err(dev, "omap_usbhs_alloc_child failed
  ");
d910774f1   Axel Lin   mfd: Fix omap_usb...
277
  		ret = -ENOMEM;
17cdd29d6   Keshava Munegowda   usb: host: omap: ...
278
279
280
281
282
283
  		goto err_ehci;
  	}
  
  	return 0;
  
  err_ehci:
d910774f1   Axel Lin   mfd: Fix omap_usb...
284
  	platform_device_unregister(ehci);
17cdd29d6   Keshava Munegowda   usb: host: omap: ...
285
286
287
288
  
  err_end:
  	return ret;
  }
17cdd29d6   Keshava Munegowda   usb: host: omap: ...
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
  static bool is_ohci_port(enum usbhs_omap_port_mode pmode)
  {
  	switch (pmode) {
  	case OMAP_OHCI_PORT_MODE_PHY_6PIN_DATSE0:
  	case OMAP_OHCI_PORT_MODE_PHY_6PIN_DPDM:
  	case OMAP_OHCI_PORT_MODE_PHY_3PIN_DATSE0:
  	case OMAP_OHCI_PORT_MODE_PHY_4PIN_DPDM:
  	case OMAP_OHCI_PORT_MODE_TLL_6PIN_DATSE0:
  	case OMAP_OHCI_PORT_MODE_TLL_6PIN_DPDM:
  	case OMAP_OHCI_PORT_MODE_TLL_3PIN_DATSE0:
  	case OMAP_OHCI_PORT_MODE_TLL_4PIN_DPDM:
  	case OMAP_OHCI_PORT_MODE_TLL_2PIN_DATSE0:
  	case OMAP_OHCI_PORT_MODE_TLL_2PIN_DPDM:
  		return true;
  
  	default:
  		return false;
  	}
  }
1e7fe1a92   Keshava Munegowda   MFD: OMAP: USB: R...
308
  static int usbhs_runtime_resume(struct device *dev)
17cdd29d6   Keshava Munegowda   usb: host: omap: ...
309
310
  {
  	struct usbhs_hcd_omap		*omap = dev_get_drvdata(dev);
9d9c6ae79   Roger Quadros   mfd: omap-usb-hos...
311
  	struct usbhs_omap_platform_data	*pdata = omap->pdata;
06ba7dc75   Roger Quadros   mfd: omap-usb-hos...
312
  	int i, r;
1e7fe1a92   Keshava Munegowda   MFD: OMAP: USB: R...
313
314
315
  
  	dev_dbg(dev, "usbhs_runtime_resume
  ");
17cdd29d6   Keshava Munegowda   usb: host: omap: ...
316

9f4a3ece0   Roger Quadros   mfd: omap-usb-tll...
317
  	omap_tll_enable(pdata);
17cdd29d6   Keshava Munegowda   usb: host: omap: ...
318

06ba7dc75   Roger Quadros   mfd: omap-usb-hos...
319
  	if (!IS_ERR(omap->ehci_logic_fck))
b0e599261   Roger Quadros   mfd: omap-usb: pr...
320
  		clk_prepare_enable(omap->ehci_logic_fck);
1e7fe1a92   Keshava Munegowda   MFD: OMAP: USB: R...
321

06ba7dc75   Roger Quadros   mfd: omap-usb-hos...
322
  	for (i = 0; i < omap->nports; i++) {
340c64eab   Roger Quadros   mfd: omap-usb-hos...
323
324
325
  		switch (pdata->port_mode[i]) {
  		case OMAP_EHCI_PORT_MODE_HSIC:
  			if (!IS_ERR(omap->hsic60m_clk[i])) {
b0e599261   Roger Quadros   mfd: omap-usb: pr...
326
  				r = clk_prepare_enable(omap->hsic60m_clk[i]);
340c64eab   Roger Quadros   mfd: omap-usb-hos...
327
328
329
330
331
332
333
334
335
  				if (r) {
  					dev_err(dev,
  					 "Can't enable port %d hsic60m clk:%d
  ",
  					 i, r);
  				}
  			}
  
  			if (!IS_ERR(omap->hsic480m_clk[i])) {
b0e599261   Roger Quadros   mfd: omap-usb: pr...
336
  				r = clk_prepare_enable(omap->hsic480m_clk[i]);
340c64eab   Roger Quadros   mfd: omap-usb-hos...
337
338
339
340
341
342
343
344
345
346
347
  				if (r) {
  					dev_err(dev,
  					 "Can't enable port %d hsic480m clk:%d
  ",
  					 i, r);
  				}
  			}
  		/* Fall through as HSIC mode needs utmi_clk */
  
  		case OMAP_EHCI_PORT_MODE_TLL:
  			if (!IS_ERR(omap->utmi_clk[i])) {
b0e599261   Roger Quadros   mfd: omap-usb: pr...
348
  				r = clk_prepare_enable(omap->utmi_clk[i]);
340c64eab   Roger Quadros   mfd: omap-usb-hos...
349
350
351
352
353
354
355
356
357
358
359
  				if (r) {
  					dev_err(dev,
  					 "Can't enable port %d clk : %d
  ",
  					 i, r);
  				}
  			}
  			break;
  		default:
  			break;
  		}
06ba7dc75   Roger Quadros   mfd: omap-usb-hos...
360
  	}
1e7fe1a92   Keshava Munegowda   MFD: OMAP: USB: R...
361

1e7fe1a92   Keshava Munegowda   MFD: OMAP: USB: R...
362
363
364
365
366
367
  	return 0;
  }
  
  static int usbhs_runtime_suspend(struct device *dev)
  {
  	struct usbhs_hcd_omap		*omap = dev_get_drvdata(dev);
9d9c6ae79   Roger Quadros   mfd: omap-usb-hos...
368
  	struct usbhs_omap_platform_data	*pdata = omap->pdata;
06ba7dc75   Roger Quadros   mfd: omap-usb-hos...
369
  	int i;
1e7fe1a92   Keshava Munegowda   MFD: OMAP: USB: R...
370
371
372
  
  	dev_dbg(dev, "usbhs_runtime_suspend
  ");
06ba7dc75   Roger Quadros   mfd: omap-usb-hos...
373
  	for (i = 0; i < omap->nports; i++) {
340c64eab   Roger Quadros   mfd: omap-usb-hos...
374
375
376
  		switch (pdata->port_mode[i]) {
  		case OMAP_EHCI_PORT_MODE_HSIC:
  			if (!IS_ERR(omap->hsic60m_clk[i]))
b0e599261   Roger Quadros   mfd: omap-usb: pr...
377
  				clk_disable_unprepare(omap->hsic60m_clk[i]);
340c64eab   Roger Quadros   mfd: omap-usb-hos...
378
379
  
  			if (!IS_ERR(omap->hsic480m_clk[i]))
b0e599261   Roger Quadros   mfd: omap-usb: pr...
380
  				clk_disable_unprepare(omap->hsic480m_clk[i]);
340c64eab   Roger Quadros   mfd: omap-usb-hos...
381
382
383
384
  		/* Fall through as utmi_clks were used in HSIC mode */
  
  		case OMAP_EHCI_PORT_MODE_TLL:
  			if (!IS_ERR(omap->utmi_clk[i]))
b0e599261   Roger Quadros   mfd: omap-usb: pr...
385
  				clk_disable_unprepare(omap->utmi_clk[i]);
340c64eab   Roger Quadros   mfd: omap-usb-hos...
386
387
388
389
  			break;
  		default:
  			break;
  		}
06ba7dc75   Roger Quadros   mfd: omap-usb-hos...
390
  	}
1e7fe1a92   Keshava Munegowda   MFD: OMAP: USB: R...
391

06ba7dc75   Roger Quadros   mfd: omap-usb-hos...
392
  	if (!IS_ERR(omap->ehci_logic_fck))
b0e599261   Roger Quadros   mfd: omap-usb: pr...
393
  		clk_disable_unprepare(omap->ehci_logic_fck);
1e7fe1a92   Keshava Munegowda   MFD: OMAP: USB: R...
394

9f4a3ece0   Roger Quadros   mfd: omap-usb-tll...
395
  	omap_tll_disable(pdata);
1e7fe1a92   Keshava Munegowda   MFD: OMAP: USB: R...
396
397
398
  
  	return 0;
  }
c4df00aed   Roger Quadros   mfd: omap-usb-hos...
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
  static unsigned omap_usbhs_rev1_hostconfig(struct usbhs_hcd_omap *omap,
  						unsigned reg)
  {
  	struct usbhs_omap_platform_data	*pdata = omap->pdata;
  	int i;
  
  	for (i = 0; i < omap->nports; i++) {
  		switch (pdata->port_mode[i]) {
  		case OMAP_USBHS_PORT_MODE_UNUSED:
  			reg &= ~(OMAP_UHH_HOSTCONFIG_P1_CONNECT_STATUS << i);
  			break;
  		case OMAP_EHCI_PORT_MODE_PHY:
  			if (pdata->single_ulpi_bypass)
  				break;
  
  			if (i == 0)
  				reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS;
  			else
  				reg &= ~(OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS
  								<< (i-1));
  			break;
  		default:
  			if (pdata->single_ulpi_bypass)
  				break;
  
  			if (i == 0)
  				reg |= OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS;
  			else
  				reg |= OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS
  								<< (i-1);
  			break;
  		}
  	}
  
  	if (pdata->single_ulpi_bypass) {
  		/* bypass ULPI only if none of the ports use PHY mode */
  		reg |= OMAP_UHH_HOSTCONFIG_ULPI_BYPASS;
  
  		for (i = 0; i < omap->nports; i++) {
  			if (is_ehci_phy_mode(pdata->port_mode[i])) {
46de8ff8e   Michael Welling   mfd: omap-usb-hos...
439
  				reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_BYPASS;
c4df00aed   Roger Quadros   mfd: omap-usb-hos...
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
  				break;
  			}
  		}
  	}
  
  	return reg;
  }
  
  static unsigned omap_usbhs_rev2_hostconfig(struct usbhs_hcd_omap *omap,
  						unsigned reg)
  {
  	struct usbhs_omap_platform_data	*pdata = omap->pdata;
  	int i;
  
  	for (i = 0; i < omap->nports; i++) {
  		/* Clear port mode fields for PHY mode */
  		reg &= ~(OMAP4_P1_MODE_CLEAR << 2 * i);
  
  		if (is_ehci_tll_mode(pdata->port_mode[i]) ||
  				(is_ohci_port(pdata->port_mode[i])))
  			reg |= OMAP4_P1_MODE_TLL << 2 * i;
  		else if (is_ehci_hsic_mode(pdata->port_mode[i]))
  			reg |= OMAP4_P1_MODE_HSIC << 2 * i;
  	}
  
  	return reg;
  }
1e7fe1a92   Keshava Munegowda   MFD: OMAP: USB: R...
467
468
469
  static void omap_usbhs_init(struct device *dev)
  {
  	struct usbhs_hcd_omap		*omap = dev_get_drvdata(dev);
1e7fe1a92   Keshava Munegowda   MFD: OMAP: USB: R...
470
471
472
473
  	unsigned			reg;
  
  	dev_dbg(dev, "starting TI HSUSB Controller
  ");
760189b36   Keshava Munegowda   mfd: omap-usb-hos...
474
  	pm_runtime_get_sync(dev);
17cdd29d6   Keshava Munegowda   usb: host: omap: ...
475

17cdd29d6   Keshava Munegowda   usb: host: omap: ...
476
477
478
479
480
481
482
  	reg = usbhs_read(omap->uhh_base, OMAP_UHH_HOSTCONFIG);
  	/* setup ULPI bypass and burst configurations */
  	reg |= (OMAP_UHH_HOSTCONFIG_INCR4_BURST_EN
  			| OMAP_UHH_HOSTCONFIG_INCR8_BURST_EN
  			| OMAP_UHH_HOSTCONFIG_INCR16_BURST_EN);
  	reg |= OMAP4_UHH_HOSTCONFIG_APP_START_CLK;
  	reg &= ~OMAP_UHH_HOSTCONFIG_INCRX_ALIGN_EN;
c4df00aed   Roger Quadros   mfd: omap-usb-hos...
483
484
  	switch (omap->usbhs_rev) {
  	case OMAP_USBHS_REV1:
26bacba15   Roger Quadros   mfd: omap-usb-hos...
485
  		reg = omap_usbhs_rev1_hostconfig(omap, reg);
c4df00aed   Roger Quadros   mfd: omap-usb-hos...
486
487
488
  		break;
  
  	case OMAP_USBHS_REV2:
26bacba15   Roger Quadros   mfd: omap-usb-hos...
489
  		reg = omap_usbhs_rev2_hostconfig(omap, reg);
c4df00aed   Roger Quadros   mfd: omap-usb-hos...
490
491
492
  		break;
  
  	default:	/* newer revisions */
26bacba15   Roger Quadros   mfd: omap-usb-hos...
493
  		reg = omap_usbhs_rev2_hostconfig(omap, reg);
c4df00aed   Roger Quadros   mfd: omap-usb-hos...
494
  		break;
17cdd29d6   Keshava Munegowda   usb: host: omap: ...
495
496
497
498
499
  	}
  
  	usbhs_write(omap->uhh_base, OMAP_UHH_HOSTCONFIG, reg);
  	dev_dbg(dev, "UHH setup done, uhh_hostconfig=%x
  ", reg);
760189b36   Keshava Munegowda   mfd: omap-usb-hos...
500
  	pm_runtime_put_sync(dev);
1e7fe1a92   Keshava Munegowda   MFD: OMAP: USB: R...
501
  }
03a8f438f   Roger Quadros   mfd: omap-usb-hos...
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
  static int usbhs_omap_get_dt_pdata(struct device *dev,
  					struct usbhs_omap_platform_data *pdata)
  {
  	int ret, i;
  	struct device_node *node = dev->of_node;
  
  	ret = of_property_read_u32(node, "num-ports", &pdata->nports);
  	if (ret)
  		pdata->nports = 0;
  
  	if (pdata->nports > OMAP3_HS_USB_PORTS) {
  		dev_warn(dev, "Too many num_ports <%d> in device tree. Max %d
  ",
  				pdata->nports, OMAP3_HS_USB_PORTS);
  		return -ENODEV;
  	}
  
  	/* get port modes */
  	for (i = 0; i < OMAP3_HS_USB_PORTS; i++) {
  		char prop[11];
  		const char *mode;
  
  		pdata->port_mode[i] = OMAP_USBHS_PORT_MODE_UNUSED;
  
  		snprintf(prop, sizeof(prop), "port%d-mode", i + 1);
  		ret = of_property_read_string(node, prop, &mode);
  		if (ret < 0)
  			continue;
  
  		ret = omap_usbhs_get_dt_port_mode(mode);
  		if (ret < 0) {
  			dev_warn(dev, "Invalid port%d-mode \"%s\" in device tree
  ",
  					i, mode);
  			return -ENODEV;
  		}
  
  		dev_dbg(dev, "port%d-mode: %s -> %d
  ", i, mode, ret);
  		pdata->port_mode[i] = ret;
  	}
  
  	/* get flags */
  	pdata->single_ulpi_bypass = of_property_read_bool(node,
  						"single-ulpi-bypass");
  
  	return 0;
  }
a7cfee818   Krzysztof Kozlowski   mfd: omap-usb-hos...
550
  static const struct of_device_id usbhs_child_match_table[] = {
03a8f438f   Roger Quadros   mfd: omap-usb-hos...
551
552
553
554
  	{ .compatible = "ti,omap-ehci", },
  	{ .compatible = "ti,omap-ohci", },
  	{ }
  };
1e7fe1a92   Keshava Munegowda   MFD: OMAP: USB: R...
555
556
557
558
559
  /**
   * usbhs_omap_probe - initialize TI-based HCDs
   *
   * Allocates basic resources for this USB host controller.
   */
f791be492   Bill Pemberton   mfd: remove use o...
560
  static int usbhs_omap_probe(struct platform_device *pdev)
17cdd29d6   Keshava Munegowda   usb: host: omap: ...
561
  {
1e7fe1a92   Keshava Munegowda   MFD: OMAP: USB: R...
562
  	struct device			*dev =  &pdev->dev;
334a41ce9   Jingoo Han   mfd: Use dev_get_...
563
  	struct usbhs_omap_platform_data	*pdata = dev_get_platdata(dev);
1e7fe1a92   Keshava Munegowda   MFD: OMAP: USB: R...
564
565
566
567
  	struct usbhs_hcd_omap		*omap;
  	struct resource			*res;
  	int				ret = 0;
  	int				i;
06ba7dc75   Roger Quadros   mfd: omap-usb-hos...
568
  	bool				need_logic_fck;
17cdd29d6   Keshava Munegowda   usb: host: omap: ...
569

03a8f438f   Roger Quadros   mfd: omap-usb-hos...
570
571
572
573
574
575
576
577
578
579
580
581
  	if (dev->of_node) {
  		/* For DT boot we populate platform data from OF node */
  		pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
  		if (!pdata)
  			return -ENOMEM;
  
  		ret = usbhs_omap_get_dt_pdata(dev, pdata);
  		if (ret)
  			return ret;
  
  		dev->platform_data = pdata;
  	}
1e7fe1a92   Keshava Munegowda   MFD: OMAP: USB: R...
582
583
584
  	if (!pdata) {
  		dev_err(dev, "Missing platform data
  ");
27d4f2c65   Roger Quadros   mfd: omap-usb-hos...
585
  		return -ENODEV;
1e7fe1a92   Keshava Munegowda   MFD: OMAP: USB: R...
586
  	}
17cdd29d6   Keshava Munegowda   usb: host: omap: ...
587

03a8f438f   Roger Quadros   mfd: omap-usb-hos...
588
589
590
591
592
593
  	if (pdata->nports > OMAP3_HS_USB_PORTS) {
  		dev_info(dev, "Too many num_ports <%d> in platform_data. Max %d
  ",
  				pdata->nports, OMAP3_HS_USB_PORTS);
  		return -ENODEV;
  	}
27d4f2c65   Roger Quadros   mfd: omap-usb-hos...
594
  	omap = devm_kzalloc(dev, sizeof(*omap), GFP_KERNEL);
1e7fe1a92   Keshava Munegowda   MFD: OMAP: USB: R...
595
596
597
  	if (!omap) {
  		dev_err(dev, "Memory allocation failed
  ");
27d4f2c65   Roger Quadros   mfd: omap-usb-hos...
598
599
  		return -ENOMEM;
  	}
03a8f438f   Roger Quadros   mfd: omap-usb-hos...
600
  	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
d011c4508   Sachin Kamat   mfd: omap-usb-hos...
601
602
603
  	omap->uhh_base = devm_ioremap_resource(dev, res);
  	if (IS_ERR(omap->uhh_base))
  		return PTR_ERR(omap->uhh_base);
17cdd29d6   Keshava Munegowda   usb: host: omap: ...
604

9d9c6ae79   Roger Quadros   mfd: omap-usb-hos...
605
  	omap->pdata = pdata;
17cdd29d6   Keshava Munegowda   usb: host: omap: ...
606

9f4a3ece0   Roger Quadros   mfd: omap-usb-tll...
607
608
  	/* Initialize the TLL subsystem */
  	omap_tll_init(pdata);
1e7fe1a92   Keshava Munegowda   MFD: OMAP: USB: R...
609
  	pm_runtime_enable(dev);
17cdd29d6   Keshava Munegowda   usb: host: omap: ...
610

d7eaf8661   Roger Quadros   mfd: omap-usb-hos...
611
612
613
614
615
616
617
618
619
  	platform_set_drvdata(pdev, omap);
  	pm_runtime_get_sync(dev);
  
  	omap->usbhs_rev = usbhs_read(omap->uhh_base, OMAP_UHH_REVISION);
  
  	/* we need to call runtime suspend before we update omap->nports
  	 * to prevent unbalanced clk_disable()
  	 */
  	pm_runtime_put_sync(dev);
ccac71a7f   Roger Quadros   mfd: omap-usb-hos...
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
  	/*
  	 * If platform data contains nports then use that
  	 * else make out number of ports from USBHS revision
  	 */
  	if (pdata->nports) {
  		omap->nports = pdata->nports;
  	} else {
  		switch (omap->usbhs_rev) {
  		case OMAP_USBHS_REV1:
  			omap->nports = 3;
  			break;
  		case OMAP_USBHS_REV2:
  			omap->nports = 2;
  			break;
  		default:
  			omap->nports = OMAP3_HS_USB_PORTS;
  			dev_dbg(dev,
ddde06b18   Hans Wennborg   mfd: omap-usb-hos...
637
638
  			 "USB HOST Rev:0x%x not recognized, assuming %d ports
  ",
ccac71a7f   Roger Quadros   mfd: omap-usb-hos...
639
640
641
  			 omap->usbhs_rev, omap->nports);
  			break;
  		}
662e469e9   Roger Quadros   mfd: omap-usb-hos...
642
  		pdata->nports = omap->nports;
d7eaf8661   Roger Quadros   mfd: omap-usb-hos...
643
  	}
06ba7dc75   Roger Quadros   mfd: omap-usb-hos...
644
645
  	i = sizeof(struct clk *) * omap->nports;
  	omap->utmi_clk = devm_kzalloc(dev, i, GFP_KERNEL);
340c64eab   Roger Quadros   mfd: omap-usb-hos...
646
647
648
649
  	omap->hsic480m_clk = devm_kzalloc(dev, i, GFP_KERNEL);
  	omap->hsic60m_clk = devm_kzalloc(dev, i, GFP_KERNEL);
  
  	if (!omap->utmi_clk || !omap->hsic480m_clk || !omap->hsic60m_clk) {
06ba7dc75   Roger Quadros   mfd: omap-usb-hos...
650
651
652
653
654
  		dev_err(dev, "Memory allocation failed
  ");
  		ret = -ENOMEM;
  		goto err_mem;
  	}
3aca446ac   Roger Quadros   mfd: omap-usb-hos...
655
656
657
658
659
660
661
  	/* Set all clocks as invalid to begin with */
  	omap->ehci_logic_fck = ERR_PTR(-ENODEV);
  	omap->init_60m_fclk = ERR_PTR(-ENODEV);
  	omap->utmi_p1_gfclk = ERR_PTR(-ENODEV);
  	omap->utmi_p2_gfclk = ERR_PTR(-ENODEV);
  	omap->xclk60mhsp1_ck = ERR_PTR(-ENODEV);
  	omap->xclk60mhsp2_ck = ERR_PTR(-ENODEV);
06ba7dc75   Roger Quadros   mfd: omap-usb-hos...
662
  	for (i = 0; i < omap->nports; i++) {
3aca446ac   Roger Quadros   mfd: omap-usb-hos...
663
664
665
  		omap->utmi_clk[i] = ERR_PTR(-ENODEV);
  		omap->hsic480m_clk[i] = ERR_PTR(-ENODEV);
  		omap->hsic60m_clk[i] = ERR_PTR(-ENODEV);
06ba7dc75   Roger Quadros   mfd: omap-usb-hos...
666
  	}
3aca446ac   Roger Quadros   mfd: omap-usb-hos...
667
668
669
670
671
672
673
674
675
676
677
678
679
  	/* for OMAP3 i.e. USBHS REV1 */
  	if (omap->usbhs_rev == OMAP_USBHS_REV1) {
  		need_logic_fck = false;
  		for (i = 0; i < omap->nports; i++) {
  			if (is_ehci_phy_mode(pdata->port_mode[i]) ||
  			    is_ehci_tll_mode(pdata->port_mode[i]) ||
  			    is_ehci_hsic_mode(pdata->port_mode[i]))
  
  				need_logic_fck |= true;
  		}
  
  		if (need_logic_fck) {
  			omap->ehci_logic_fck = devm_clk_get(dev,
775bb078e   Roger Quadros   mfd: omap-usb-hos...
680
  							    "usbhost_120m_fck");
3aca446ac   Roger Quadros   mfd: omap-usb-hos...
681
682
  			if (IS_ERR(omap->ehci_logic_fck)) {
  				ret = PTR_ERR(omap->ehci_logic_fck);
775bb078e   Roger Quadros   mfd: omap-usb-hos...
683
684
685
  				dev_err(dev, "usbhost_120m_fck failed:%d
  ",
  					ret);
fedb2e7c2   Roger Quadros   mfd: omap-usb-hos...
686
  				goto err_mem;
3aca446ac   Roger Quadros   mfd: omap-usb-hos...
687
  			}
1e7fe1a92   Keshava Munegowda   MFD: OMAP: USB: R...
688
  		}
3aca446ac   Roger Quadros   mfd: omap-usb-hos...
689
  		goto initialize;
06ba7dc75   Roger Quadros   mfd: omap-usb-hos...
690
  	}
17cdd29d6   Keshava Munegowda   usb: host: omap: ...
691

3aca446ac   Roger Quadros   mfd: omap-usb-hos...
692
  	/* for OMAP4+ i.e. USBHS REV2+ */
61b7025f6   Roger Quadros   mfd: omap-usb-hos...
693
  	omap->utmi_p1_gfclk = devm_clk_get(dev, "utmi_p1_gfclk");
06ba7dc75   Roger Quadros   mfd: omap-usb-hos...
694
695
696
697
  	if (IS_ERR(omap->utmi_p1_gfclk)) {
  		ret = PTR_ERR(omap->utmi_p1_gfclk);
  		dev_err(dev, "utmi_p1_gfclk failed error:%d
  ", ret);
61b7025f6   Roger Quadros   mfd: omap-usb-hos...
698
  		goto err_mem;
06ba7dc75   Roger Quadros   mfd: omap-usb-hos...
699
  	}
61b7025f6   Roger Quadros   mfd: omap-usb-hos...
700
  	omap->utmi_p2_gfclk = devm_clk_get(dev, "utmi_p2_gfclk");
06ba7dc75   Roger Quadros   mfd: omap-usb-hos...
701
702
703
704
  	if (IS_ERR(omap->utmi_p2_gfclk)) {
  		ret = PTR_ERR(omap->utmi_p2_gfclk);
  		dev_err(dev, "utmi_p2_gfclk failed error:%d
  ", ret);
61b7025f6   Roger Quadros   mfd: omap-usb-hos...
705
  		goto err_mem;
17cdd29d6   Keshava Munegowda   usb: host: omap: ...
706
  	}
051fc06df   Roger Quadros   mfd: omap-usb-hos...
707
  	omap->xclk60mhsp1_ck = devm_clk_get(dev, "refclk_60m_ext_p1");
1e7fe1a92   Keshava Munegowda   MFD: OMAP: USB: R...
708
709
  	if (IS_ERR(omap->xclk60mhsp1_ck)) {
  		ret = PTR_ERR(omap->xclk60mhsp1_ck);
051fc06df   Roger Quadros   mfd: omap-usb-hos...
710
711
  		dev_err(dev, "refclk_60m_ext_p1 failed error:%d
  ", ret);
61b7025f6   Roger Quadros   mfd: omap-usb-hos...
712
  		goto err_mem;
17cdd29d6   Keshava Munegowda   usb: host: omap: ...
713
  	}
051fc06df   Roger Quadros   mfd: omap-usb-hos...
714
  	omap->xclk60mhsp2_ck = devm_clk_get(dev, "refclk_60m_ext_p2");
1e7fe1a92   Keshava Munegowda   MFD: OMAP: USB: R...
715
716
  	if (IS_ERR(omap->xclk60mhsp2_ck)) {
  		ret = PTR_ERR(omap->xclk60mhsp2_ck);
051fc06df   Roger Quadros   mfd: omap-usb-hos...
717
718
  		dev_err(dev, "refclk_60m_ext_p2 failed error:%d
  ", ret);
61b7025f6   Roger Quadros   mfd: omap-usb-hos...
719
  		goto err_mem;
17cdd29d6   Keshava Munegowda   usb: host: omap: ...
720
  	}
051fc06df   Roger Quadros   mfd: omap-usb-hos...
721
  	omap->init_60m_fclk = devm_clk_get(dev, "refclk_60m_int");
1e7fe1a92   Keshava Munegowda   MFD: OMAP: USB: R...
722
723
  	if (IS_ERR(omap->init_60m_fclk)) {
  		ret = PTR_ERR(omap->init_60m_fclk);
051fc06df   Roger Quadros   mfd: omap-usb-hos...
724
725
  		dev_err(dev, "refclk_60m_int failed error:%d
  ", ret);
61b7025f6   Roger Quadros   mfd: omap-usb-hos...
726
  		goto err_mem;
06ba7dc75   Roger Quadros   mfd: omap-usb-hos...
727
728
729
  	}
  
  	for (i = 0; i < omap->nports; i++) {
340c64eab   Roger Quadros   mfd: omap-usb-hos...
730
  		char clkname[30];
06ba7dc75   Roger Quadros   mfd: omap-usb-hos...
731
732
733
734
735
736
737
738
739
  
  		/* clock names are indexed from 1*/
  		snprintf(clkname, sizeof(clkname),
  				"usb_host_hs_utmi_p%d_clk", i + 1);
  
  		/* If a clock is not found we won't bail out as not all
  		 * platforms have all clocks and we can function without
  		 * them
  		 */
61b7025f6   Roger Quadros   mfd: omap-usb-hos...
740
  		omap->utmi_clk[i] = devm_clk_get(dev, clkname);
fedb2e7c2   Roger Quadros   mfd: omap-usb-hos...
741
742
743
744
745
746
747
  		if (IS_ERR(omap->utmi_clk[i])) {
  			ret = PTR_ERR(omap->utmi_clk[i]);
  			dev_err(dev, "Failed to get clock : %s : %d
  ",
  				clkname, ret);
  			goto err_mem;
  		}
340c64eab   Roger Quadros   mfd: omap-usb-hos...
748
749
750
  
  		snprintf(clkname, sizeof(clkname),
  				"usb_host_hs_hsic480m_p%d_clk", i + 1);
61b7025f6   Roger Quadros   mfd: omap-usb-hos...
751
  		omap->hsic480m_clk[i] = devm_clk_get(dev, clkname);
fedb2e7c2   Roger Quadros   mfd: omap-usb-hos...
752
753
754
755
756
757
758
  		if (IS_ERR(omap->hsic480m_clk[i])) {
  			ret = PTR_ERR(omap->hsic480m_clk[i]);
  			dev_err(dev, "Failed to get clock : %s : %d
  ",
  				clkname, ret);
  			goto err_mem;
  		}
340c64eab   Roger Quadros   mfd: omap-usb-hos...
759
760
761
  
  		snprintf(clkname, sizeof(clkname),
  				"usb_host_hs_hsic60m_p%d_clk", i + 1);
61b7025f6   Roger Quadros   mfd: omap-usb-hos...
762
  		omap->hsic60m_clk[i] = devm_clk_get(dev, clkname);
fedb2e7c2   Roger Quadros   mfd: omap-usb-hos...
763
764
765
766
767
768
769
  		if (IS_ERR(omap->hsic60m_clk[i])) {
  			ret = PTR_ERR(omap->hsic60m_clk[i]);
  			dev_err(dev, "Failed to get clock : %s : %d
  ",
  				clkname, ret);
  			goto err_mem;
  		}
17cdd29d6   Keshava Munegowda   usb: host: omap: ...
770
  	}
1e7fe1a92   Keshava Munegowda   MFD: OMAP: USB: R...
771
  	if (is_ehci_phy_mode(pdata->port_mode[0])) {
06ba7dc75   Roger Quadros   mfd: omap-usb-hos...
772
  		ret = clk_set_parent(omap->utmi_p1_gfclk,
1e7fe1a92   Keshava Munegowda   MFD: OMAP: USB: R...
773
  					omap->xclk60mhsp1_ck);
fedb2e7c2   Roger Quadros   mfd: omap-usb-hos...
774
775
776
777
778
779
  		if (ret != 0) {
  			dev_err(dev, "xclk60mhsp1_ck set parent failed: %d
  ",
  				ret);
  			goto err_mem;
  		}
1e7fe1a92   Keshava Munegowda   MFD: OMAP: USB: R...
780
  	} else if (is_ehci_tll_mode(pdata->port_mode[0])) {
06ba7dc75   Roger Quadros   mfd: omap-usb-hos...
781
  		ret = clk_set_parent(omap->utmi_p1_gfclk,
1e7fe1a92   Keshava Munegowda   MFD: OMAP: USB: R...
782
  					omap->init_60m_fclk);
fedb2e7c2   Roger Quadros   mfd: omap-usb-hos...
783
784
785
786
787
788
  		if (ret != 0) {
  			dev_err(dev, "P0 init_60m_fclk set parent failed: %d
  ",
  				ret);
  			goto err_mem;
  		}
1e7fe1a92   Keshava Munegowda   MFD: OMAP: USB: R...
789
  	}
17cdd29d6   Keshava Munegowda   usb: host: omap: ...
790

1e7fe1a92   Keshava Munegowda   MFD: OMAP: USB: R...
791
  	if (is_ehci_phy_mode(pdata->port_mode[1])) {
06ba7dc75   Roger Quadros   mfd: omap-usb-hos...
792
  		ret = clk_set_parent(omap->utmi_p2_gfclk,
1e7fe1a92   Keshava Munegowda   MFD: OMAP: USB: R...
793
  					omap->xclk60mhsp2_ck);
fedb2e7c2   Roger Quadros   mfd: omap-usb-hos...
794
795
796
797
798
799
  		if (ret != 0) {
  			dev_err(dev, "xclk60mhsp2_ck set parent failed: %d
  ",
  				ret);
  			goto err_mem;
  		}
1e7fe1a92   Keshava Munegowda   MFD: OMAP: USB: R...
800
  	} else if (is_ehci_tll_mode(pdata->port_mode[1])) {
06ba7dc75   Roger Quadros   mfd: omap-usb-hos...
801
  		ret = clk_set_parent(omap->utmi_p2_gfclk,
1e7fe1a92   Keshava Munegowda   MFD: OMAP: USB: R...
802
  						omap->init_60m_fclk);
fedb2e7c2   Roger Quadros   mfd: omap-usb-hos...
803
804
805
806
807
808
  		if (ret != 0) {
  			dev_err(dev, "P1 init_60m_fclk set parent failed: %d
  ",
  				ret);
  			goto err_mem;
  		}
1e7fe1a92   Keshava Munegowda   MFD: OMAP: USB: R...
809
  	}
6eb6fbbf3   Keshava Munegowda   mfd: Fix omap usb...
810

3aca446ac   Roger Quadros   mfd: omap-usb-hos...
811
  initialize:
f0447a690   Govindraj.R   mfd: Move omap-us...
812
  	omap_usbhs_init(dev);
03a8f438f   Roger Quadros   mfd: omap-usb-hos...
813
814
815
816
817
818
819
820
  
  	if (dev->of_node) {
  		ret = of_platform_populate(dev->of_node,
  				usbhs_child_match_table, NULL, dev);
  
  		if (ret) {
  			dev_err(dev, "Failed to create DT children: %d
  ", ret);
61b7025f6   Roger Quadros   mfd: omap-usb-hos...
821
  			goto err_mem;
03a8f438f   Roger Quadros   mfd: omap-usb-hos...
822
823
824
825
826
827
828
829
  		}
  
  	} else {
  		ret = omap_usbhs_alloc_children(pdev);
  		if (ret) {
  			dev_err(dev, "omap_usbhs_alloc_children failed: %d
  ",
  						ret);
61b7025f6   Roger Quadros   mfd: omap-usb-hos...
830
  			goto err_mem;
03a8f438f   Roger Quadros   mfd: omap-usb-hos...
831
  		}
1e7fe1a92   Keshava Munegowda   MFD: OMAP: USB: R...
832
  	}
27d4f2c65   Roger Quadros   mfd: omap-usb-hos...
833
  	return 0;
1e7fe1a92   Keshava Munegowda   MFD: OMAP: USB: R...
834

06ba7dc75   Roger Quadros   mfd: omap-usb-hos...
835
  err_mem:
1e7fe1a92   Keshava Munegowda   MFD: OMAP: USB: R...
836
  	pm_runtime_disable(dev);
1e7fe1a92   Keshava Munegowda   MFD: OMAP: USB: R...
837

1e7fe1a92   Keshava Munegowda   MFD: OMAP: USB: R...
838
  	return ret;
17cdd29d6   Keshava Munegowda   usb: host: omap: ...
839
  }
17cdd29d6   Keshava Munegowda   usb: host: omap: ...
840

03a8f438f   Roger Quadros   mfd: omap-usb-hos...
841
842
843
844
845
846
847
  static int usbhs_omap_remove_child(struct device *dev, void *data)
  {
  	dev_info(dev, "unregistering
  ");
  	platform_device_unregister(to_platform_device(dev));
  	return 0;
  }
1e7fe1a92   Keshava Munegowda   MFD: OMAP: USB: R...
848
849
850
851
852
853
  /**
   * usbhs_omap_remove - shutdown processing for UHH & TLL HCDs
   * @pdev: USB Host Controller being removed
   *
   * Reverses the effect of usbhs_omap_probe().
   */
4740f73fe   Bill Pemberton   mfd: remove use o...
854
  static int usbhs_omap_remove(struct platform_device *pdev)
17cdd29d6   Keshava Munegowda   usb: host: omap: ...
855
  {
1e7fe1a92   Keshava Munegowda   MFD: OMAP: USB: R...
856
  	pm_runtime_disable(&pdev->dev);
1e7fe1a92   Keshava Munegowda   MFD: OMAP: USB: R...
857

03a8f438f   Roger Quadros   mfd: omap-usb-hos...
858
859
  	/* remove children */
  	device_for_each_child(&pdev->dev, NULL, usbhs_omap_remove_child);
1e7fe1a92   Keshava Munegowda   MFD: OMAP: USB: R...
860
  	return 0;
17cdd29d6   Keshava Munegowda   usb: host: omap: ...
861
  }
1e7fe1a92   Keshava Munegowda   MFD: OMAP: USB: R...
862
863
864
865
866
  
  static const struct dev_pm_ops usbhsomap_dev_pm_ops = {
  	.runtime_suspend	= usbhs_runtime_suspend,
  	.runtime_resume		= usbhs_runtime_resume,
  };
17cdd29d6   Keshava Munegowda   usb: host: omap: ...
867

03a8f438f   Roger Quadros   mfd: omap-usb-hos...
868
869
870
871
872
873
  static const struct of_device_id usbhs_omap_dt_ids[] = {
  	{ .compatible = "ti,usbhs-host" },
  	{ }
  };
  
  MODULE_DEVICE_TABLE(of, usbhs_omap_dt_ids);
17cdd29d6   Keshava Munegowda   usb: host: omap: ...
874
875
876
  static struct platform_driver usbhs_omap_driver = {
  	.driver = {
  		.name		= (char *)usbhs_driver_name,
1e7fe1a92   Keshava Munegowda   MFD: OMAP: USB: R...
877
  		.pm		= &usbhsomap_dev_pm_ops,
0f54e1e12   Sachin Kamat   mfd: omap-usb: Re...
878
  		.of_match_table = usbhs_omap_dt_ids,
17cdd29d6   Keshava Munegowda   usb: host: omap: ...
879
  	},
ab3f2a86d   Roger Quadros   mfd: omap-usb-hos...
880
  	.remove		= usbhs_omap_remove,
17cdd29d6   Keshava Munegowda   usb: host: omap: ...
881
882
883
  };
  
  MODULE_AUTHOR("Keshava Munegowda <keshava_mgowda@ti.com>");
03a8f438f   Roger Quadros   mfd: omap-usb-hos...
884
  MODULE_AUTHOR("Roger Quadros <rogerq@ti.com>");
17cdd29d6   Keshava Munegowda   usb: host: omap: ...
885
886
887
888
889
890
891
892
893
894
895
896
897
  MODULE_ALIAS("platform:" USBHS_DRIVER_NAME);
  MODULE_LICENSE("GPL v2");
  MODULE_DESCRIPTION("usb host common core driver for omap EHCI and OHCI");
  
  static int __init omap_usbhs_drvinit(void)
  {
  	return platform_driver_probe(&usbhs_omap_driver, usbhs_omap_probe);
  }
  
  /*
   * init before ehci and ohci drivers;
   * The usbhs core driver should be initialized much before
   * the omap ehci and ohci probe functions are called.
4dc2cceb5   Keshava Munegowda   mfd: omap-usb-hos...
898
899
   * This usbhs core driver should be initialized after
   * usb tll driver
17cdd29d6   Keshava Munegowda   usb: host: omap: ...
900
   */
4dc2cceb5   Keshava Munegowda   mfd: omap-usb-hos...
901
  fs_initcall_sync(omap_usbhs_drvinit);
17cdd29d6   Keshava Munegowda   usb: host: omap: ...
902
903
904
905
906
907
  
  static void __exit omap_usbhs_drvexit(void)
  {
  	platform_driver_unregister(&usbhs_omap_driver);
  }
  module_exit(omap_usbhs_drvexit);