Blame view

drivers/mfd/omap-usb-host.c 23.9 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
127
128
129
  }
  
  static inline void usbhs_writeb(void __iomem *base, u8 reg, u8 val)
  {
9981a3146   Victor Kamensky   mfd: omap-usb-hos...
130
  	writeb_relaxed(val, base + reg);
17cdd29d6   Keshava Munegowda   usb: host: omap: ...
131
132
133
134
  }
  
  static inline u8 usbhs_readb(void __iomem *base, u8 reg)
  {
9981a3146   Victor Kamensky   mfd: omap-usb-hos...
135
  	return readb_relaxed(base + reg);
17cdd29d6   Keshava Munegowda   usb: host: omap: ...
136
137
138
  }
  
  /*-------------------------------------------------------------------------*/
03a8f438f   Roger Quadros   mfd: omap-usb-hos...
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
  /**
   * 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
   */
  static const int omap_usbhs_get_dt_port_mode(const char *mode)
  {
  	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: ...
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
  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-...
211
  	dma_set_coherent_mask(&child->dev, DMA_BIT_MASK(32));
17cdd29d6   Keshava Munegowda   usb: host: omap: ...
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
  	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_...
233
  	struct usbhs_omap_platform_data		*pdata = dev_get_platdata(dev);
17cdd29d6   Keshava Munegowda   usb: host: omap: ...
234
235
236
237
238
  	struct platform_device			*ehci;
  	struct platform_device			*ohci;
  	struct resource				*res;
  	struct resource				resources[2];
  	int					ret;
17cdd29d6   Keshava Munegowda   usb: host: omap: ...
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
  	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...
256
257
  	ehci = omap_usbhs_alloc_child(OMAP_EHCI_DEVICE, resources, 2, pdata,
  		sizeof(*pdata), dev);
17cdd29d6   Keshava Munegowda   usb: host: omap: ...
258
259
260
261
  
  	if (!ehci) {
  		dev_err(dev, "omap_usbhs_alloc_child failed
  ");
d910774f1   Axel Lin   mfd: Fix omap_usb...
262
  		ret = -ENOMEM;
17cdd29d6   Keshava Munegowda   usb: host: omap: ...
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
  		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...
283
284
  	ohci = omap_usbhs_alloc_child(OMAP_OHCI_DEVICE, resources, 2, pdata,
  		sizeof(*pdata), dev);
17cdd29d6   Keshava Munegowda   usb: host: omap: ...
285
286
287
  	if (!ohci) {
  		dev_err(dev, "omap_usbhs_alloc_child failed
  ");
d910774f1   Axel Lin   mfd: Fix omap_usb...
288
  		ret = -ENOMEM;
17cdd29d6   Keshava Munegowda   usb: host: omap: ...
289
290
291
292
293
294
  		goto err_ehci;
  	}
  
  	return 0;
  
  err_ehci:
d910774f1   Axel Lin   mfd: Fix omap_usb...
295
  	platform_device_unregister(ehci);
17cdd29d6   Keshava Munegowda   usb: host: omap: ...
296
297
298
299
  
  err_end:
  	return ret;
  }
17cdd29d6   Keshava Munegowda   usb: host: omap: ...
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
  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...
319
  static int usbhs_runtime_resume(struct device *dev)
17cdd29d6   Keshava Munegowda   usb: host: omap: ...
320
321
  {
  	struct usbhs_hcd_omap		*omap = dev_get_drvdata(dev);
9d9c6ae79   Roger Quadros   mfd: omap-usb-hos...
322
  	struct usbhs_omap_platform_data	*pdata = omap->pdata;
06ba7dc75   Roger Quadros   mfd: omap-usb-hos...
323
  	int i, r;
1e7fe1a92   Keshava Munegowda   MFD: OMAP: USB: R...
324
325
326
  
  	dev_dbg(dev, "usbhs_runtime_resume
  ");
17cdd29d6   Keshava Munegowda   usb: host: omap: ...
327

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

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

06ba7dc75   Roger Quadros   mfd: omap-usb-hos...
333
  	for (i = 0; i < omap->nports; i++) {
340c64eab   Roger Quadros   mfd: omap-usb-hos...
334
335
336
  		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...
337
  				r = clk_prepare_enable(omap->hsic60m_clk[i]);
340c64eab   Roger Quadros   mfd: omap-usb-hos...
338
339
340
341
342
343
344
345
346
  				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...
347
  				r = clk_prepare_enable(omap->hsic480m_clk[i]);
340c64eab   Roger Quadros   mfd: omap-usb-hos...
348
349
350
351
352
353
354
355
356
357
358
  				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...
359
  				r = clk_prepare_enable(omap->utmi_clk[i]);
340c64eab   Roger Quadros   mfd: omap-usb-hos...
360
361
362
363
364
365
366
367
368
369
370
  				if (r) {
  					dev_err(dev,
  					 "Can't enable port %d clk : %d
  ",
  					 i, r);
  				}
  			}
  			break;
  		default:
  			break;
  		}
06ba7dc75   Roger Quadros   mfd: omap-usb-hos...
371
  	}
1e7fe1a92   Keshava Munegowda   MFD: OMAP: USB: R...
372

1e7fe1a92   Keshava Munegowda   MFD: OMAP: USB: R...
373
374
375
376
377
378
  	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...
379
  	struct usbhs_omap_platform_data	*pdata = omap->pdata;
06ba7dc75   Roger Quadros   mfd: omap-usb-hos...
380
  	int i;
1e7fe1a92   Keshava Munegowda   MFD: OMAP: USB: R...
381
382
383
  
  	dev_dbg(dev, "usbhs_runtime_suspend
  ");
06ba7dc75   Roger Quadros   mfd: omap-usb-hos...
384
  	for (i = 0; i < omap->nports; i++) {
340c64eab   Roger Quadros   mfd: omap-usb-hos...
385
386
387
  		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...
388
  				clk_disable_unprepare(omap->hsic60m_clk[i]);
340c64eab   Roger Quadros   mfd: omap-usb-hos...
389
390
  
  			if (!IS_ERR(omap->hsic480m_clk[i]))
b0e599261   Roger Quadros   mfd: omap-usb: pr...
391
  				clk_disable_unprepare(omap->hsic480m_clk[i]);
340c64eab   Roger Quadros   mfd: omap-usb-hos...
392
393
394
395
  		/* 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...
396
  				clk_disable_unprepare(omap->utmi_clk[i]);
340c64eab   Roger Quadros   mfd: omap-usb-hos...
397
398
399
400
  			break;
  		default:
  			break;
  		}
06ba7dc75   Roger Quadros   mfd: omap-usb-hos...
401
  	}
1e7fe1a92   Keshava Munegowda   MFD: OMAP: USB: R...
402

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

9f4a3ece0   Roger Quadros   mfd: omap-usb-tll...
406
  	omap_tll_disable(pdata);
1e7fe1a92   Keshava Munegowda   MFD: OMAP: USB: R...
407
408
409
  
  	return 0;
  }
c4df00aed   Roger Quadros   mfd: omap-usb-hos...
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
439
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
467
468
469
470
471
472
473
474
475
476
477
  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])) {
  				reg &= OMAP_UHH_HOSTCONFIG_ULPI_BYPASS;
  				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...
478
479
480
  static void omap_usbhs_init(struct device *dev)
  {
  	struct usbhs_hcd_omap		*omap = dev_get_drvdata(dev);
1e7fe1a92   Keshava Munegowda   MFD: OMAP: USB: R...
481
482
483
484
  	unsigned			reg;
  
  	dev_dbg(dev, "starting TI HSUSB Controller
  ");
760189b36   Keshava Munegowda   mfd: omap-usb-hos...
485
  	pm_runtime_get_sync(dev);
17cdd29d6   Keshava Munegowda   usb: host: omap: ...
486

17cdd29d6   Keshava Munegowda   usb: host: omap: ...
487
488
489
490
491
492
493
  	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...
494
495
  	switch (omap->usbhs_rev) {
  	case OMAP_USBHS_REV1:
26bacba15   Roger Quadros   mfd: omap-usb-hos...
496
  		reg = omap_usbhs_rev1_hostconfig(omap, reg);
c4df00aed   Roger Quadros   mfd: omap-usb-hos...
497
498
499
  		break;
  
  	case OMAP_USBHS_REV2:
26bacba15   Roger Quadros   mfd: omap-usb-hos...
500
  		reg = omap_usbhs_rev2_hostconfig(omap, reg);
c4df00aed   Roger Quadros   mfd: omap-usb-hos...
501
502
503
  		break;
  
  	default:	/* newer revisions */
26bacba15   Roger Quadros   mfd: omap-usb-hos...
504
  		reg = omap_usbhs_rev2_hostconfig(omap, reg);
c4df00aed   Roger Quadros   mfd: omap-usb-hos...
505
  		break;
17cdd29d6   Keshava Munegowda   usb: host: omap: ...
506
507
508
509
510
  	}
  
  	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...
511
  	pm_runtime_put_sync(dev);
1e7fe1a92   Keshava Munegowda   MFD: OMAP: USB: R...
512
  }
03a8f438f   Roger Quadros   mfd: omap-usb-hos...
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
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
  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;
  }
  
  static struct of_device_id usbhs_child_match_table[] = {
  	{ .compatible = "ti,omap-ehci", },
  	{ .compatible = "ti,omap-ohci", },
  	{ }
  };
1e7fe1a92   Keshava Munegowda   MFD: OMAP: USB: R...
567
568
569
570
571
  /**
   * usbhs_omap_probe - initialize TI-based HCDs
   *
   * Allocates basic resources for this USB host controller.
   */
f791be492   Bill Pemberton   mfd: remove use o...
572
  static int usbhs_omap_probe(struct platform_device *pdev)
17cdd29d6   Keshava Munegowda   usb: host: omap: ...
573
  {
1e7fe1a92   Keshava Munegowda   MFD: OMAP: USB: R...
574
  	struct device			*dev =  &pdev->dev;
334a41ce9   Jingoo Han   mfd: Use dev_get_...
575
  	struct usbhs_omap_platform_data	*pdata = dev_get_platdata(dev);
1e7fe1a92   Keshava Munegowda   MFD: OMAP: USB: R...
576
577
578
579
  	struct usbhs_hcd_omap		*omap;
  	struct resource			*res;
  	int				ret = 0;
  	int				i;
06ba7dc75   Roger Quadros   mfd: omap-usb-hos...
580
  	bool				need_logic_fck;
17cdd29d6   Keshava Munegowda   usb: host: omap: ...
581

03a8f438f   Roger Quadros   mfd: omap-usb-hos...
582
583
584
585
586
587
588
589
590
591
592
593
  	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...
594
595
596
  	if (!pdata) {
  		dev_err(dev, "Missing platform data
  ");
27d4f2c65   Roger Quadros   mfd: omap-usb-hos...
597
  		return -ENODEV;
1e7fe1a92   Keshava Munegowda   MFD: OMAP: USB: R...
598
  	}
17cdd29d6   Keshava Munegowda   usb: host: omap: ...
599

03a8f438f   Roger Quadros   mfd: omap-usb-hos...
600
601
602
603
604
605
  	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...
606
  	omap = devm_kzalloc(dev, sizeof(*omap), GFP_KERNEL);
1e7fe1a92   Keshava Munegowda   MFD: OMAP: USB: R...
607
608
609
  	if (!omap) {
  		dev_err(dev, "Memory allocation failed
  ");
27d4f2c65   Roger Quadros   mfd: omap-usb-hos...
610
611
  		return -ENOMEM;
  	}
03a8f438f   Roger Quadros   mfd: omap-usb-hos...
612
  	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
d011c4508   Sachin Kamat   mfd: omap-usb-hos...
613
614
615
  	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: ...
616

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

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

d7eaf8661   Roger Quadros   mfd: omap-usb-hos...
623
624
625
626
627
628
629
630
631
  	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...
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
  	/*
  	 * 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,
  			 "USB HOST Rev:0x%d not recognized, assuming %d ports
  ",
  			 omap->usbhs_rev, omap->nports);
  			break;
  		}
662e469e9   Roger Quadros   mfd: omap-usb-hos...
654
  		pdata->nports = omap->nports;
d7eaf8661   Roger Quadros   mfd: omap-usb-hos...
655
  	}
06ba7dc75   Roger Quadros   mfd: omap-usb-hos...
656
657
  	i = sizeof(struct clk *) * omap->nports;
  	omap->utmi_clk = devm_kzalloc(dev, i, GFP_KERNEL);
340c64eab   Roger Quadros   mfd: omap-usb-hos...
658
659
660
661
  	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...
662
663
664
665
666
667
668
669
  		dev_err(dev, "Memory allocation failed
  ");
  		ret = -ENOMEM;
  		goto err_mem;
  	}
  
  	need_logic_fck = false;
  	for (i = 0; i < omap->nports; i++) {
1e7fe1a92   Keshava Munegowda   MFD: OMAP: USB: R...
670
  		if (is_ehci_phy_mode(i) || is_ehci_tll_mode(i) ||
06ba7dc75   Roger Quadros   mfd: omap-usb-hos...
671
672
673
674
675
676
677
678
679
680
681
  			is_ehci_hsic_mode(i))
  				need_logic_fck |= true;
  	}
  
  	omap->ehci_logic_fck = ERR_PTR(-EINVAL);
  	if (need_logic_fck) {
  		omap->ehci_logic_fck = clk_get(dev, "ehci_logic_fck");
  		if (IS_ERR(omap->ehci_logic_fck)) {
  			ret = PTR_ERR(omap->ehci_logic_fck);
  			dev_dbg(dev, "ehci_logic_fck failed:%d
  ", ret);
1e7fe1a92   Keshava Munegowda   MFD: OMAP: USB: R...
682
  		}
06ba7dc75   Roger Quadros   mfd: omap-usb-hos...
683
  	}
17cdd29d6   Keshava Munegowda   usb: host: omap: ...
684

06ba7dc75   Roger Quadros   mfd: omap-usb-hos...
685
686
687
688
689
690
691
692
693
694
695
696
697
698
  	omap->utmi_p1_gfclk = clk_get(dev, "utmi_p1_gfclk");
  	if (IS_ERR(omap->utmi_p1_gfclk)) {
  		ret = PTR_ERR(omap->utmi_p1_gfclk);
  		dev_err(dev, "utmi_p1_gfclk failed error:%d
  ", ret);
  		goto err_p1_gfclk;
  	}
  
  	omap->utmi_p2_gfclk = clk_get(dev, "utmi_p2_gfclk");
  	if (IS_ERR(omap->utmi_p2_gfclk)) {
  		ret = PTR_ERR(omap->utmi_p2_gfclk);
  		dev_err(dev, "utmi_p2_gfclk failed error:%d
  ", ret);
  		goto err_p2_gfclk;
17cdd29d6   Keshava Munegowda   usb: host: omap: ...
699
  	}
1e7fe1a92   Keshava Munegowda   MFD: OMAP: USB: R...
700
701
702
703
704
  	omap->xclk60mhsp1_ck = clk_get(dev, "xclk60mhsp1_ck");
  	if (IS_ERR(omap->xclk60mhsp1_ck)) {
  		ret = PTR_ERR(omap->xclk60mhsp1_ck);
  		dev_err(dev, "xclk60mhsp1_ck failed error:%d
  ", ret);
06ba7dc75   Roger Quadros   mfd: omap-usb-hos...
705
  		goto err_xclk60mhsp1;
17cdd29d6   Keshava Munegowda   usb: host: omap: ...
706
  	}
1e7fe1a92   Keshava Munegowda   MFD: OMAP: USB: R...
707
708
709
710
711
  	omap->xclk60mhsp2_ck = clk_get(dev, "xclk60mhsp2_ck");
  	if (IS_ERR(omap->xclk60mhsp2_ck)) {
  		ret = PTR_ERR(omap->xclk60mhsp2_ck);
  		dev_err(dev, "xclk60mhsp2_ck failed error:%d
  ", ret);
06ba7dc75   Roger Quadros   mfd: omap-usb-hos...
712
  		goto err_xclk60mhsp2;
17cdd29d6   Keshava Munegowda   usb: host: omap: ...
713
  	}
1e7fe1a92   Keshava Munegowda   MFD: OMAP: USB: R...
714
715
716
717
718
  	omap->init_60m_fclk = clk_get(dev, "init_60m_fclk");
  	if (IS_ERR(omap->init_60m_fclk)) {
  		ret = PTR_ERR(omap->init_60m_fclk);
  		dev_err(dev, "init_60m_fclk failed error:%d
  ", ret);
06ba7dc75   Roger Quadros   mfd: omap-usb-hos...
719
720
721
722
  		goto err_init60m;
  	}
  
  	for (i = 0; i < omap->nports; i++) {
340c64eab   Roger Quadros   mfd: omap-usb-hos...
723
  		char clkname[30];
06ba7dc75   Roger Quadros   mfd: omap-usb-hos...
724
725
726
727
728
729
730
731
732
733
734
735
736
737
  
  		/* 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
  		 */
  		omap->utmi_clk[i] = clk_get(dev, clkname);
  		if (IS_ERR(omap->utmi_clk[i]))
  			dev_dbg(dev, "Failed to get clock : %s : %ld
  ",
  				clkname, PTR_ERR(omap->utmi_clk[i]));
340c64eab   Roger Quadros   mfd: omap-usb-hos...
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
  
  		snprintf(clkname, sizeof(clkname),
  				"usb_host_hs_hsic480m_p%d_clk", i + 1);
  		omap->hsic480m_clk[i] = clk_get(dev, clkname);
  		if (IS_ERR(omap->hsic480m_clk[i]))
  			dev_dbg(dev, "Failed to get clock : %s : %ld
  ",
  				clkname, PTR_ERR(omap->hsic480m_clk[i]));
  
  		snprintf(clkname, sizeof(clkname),
  				"usb_host_hs_hsic60m_p%d_clk", i + 1);
  		omap->hsic60m_clk[i] = clk_get(dev, clkname);
  		if (IS_ERR(omap->hsic60m_clk[i]))
  			dev_dbg(dev, "Failed to get clock : %s : %ld
  ",
  				clkname, PTR_ERR(omap->hsic60m_clk[i]));
17cdd29d6   Keshava Munegowda   usb: host: omap: ...
754
  	}
1e7fe1a92   Keshava Munegowda   MFD: OMAP: USB: R...
755
  	if (is_ehci_phy_mode(pdata->port_mode[0])) {
a8c4e9e11   Roger Quadros   mfd: omap-usb-hos...
756
  		/* for OMAP3, clk_set_parent fails */
06ba7dc75   Roger Quadros   mfd: omap-usb-hos...
757
  		ret = clk_set_parent(omap->utmi_p1_gfclk,
1e7fe1a92   Keshava Munegowda   MFD: OMAP: USB: R...
758
759
  					omap->xclk60mhsp1_ck);
  		if (ret != 0)
a8c4e9e11   Roger Quadros   mfd: omap-usb-hos...
760
761
762
  			dev_dbg(dev, "xclk60mhsp1_ck set parent failed: %d
  ",
  					ret);
1e7fe1a92   Keshava Munegowda   MFD: OMAP: USB: R...
763
  	} else if (is_ehci_tll_mode(pdata->port_mode[0])) {
06ba7dc75   Roger Quadros   mfd: omap-usb-hos...
764
  		ret = clk_set_parent(omap->utmi_p1_gfclk,
1e7fe1a92   Keshava Munegowda   MFD: OMAP: USB: R...
765
766
  					omap->init_60m_fclk);
  		if (ret != 0)
a8c4e9e11   Roger Quadros   mfd: omap-usb-hos...
767
768
769
  			dev_dbg(dev, "P0 init_60m_fclk set parent failed: %d
  ",
  					ret);
1e7fe1a92   Keshava Munegowda   MFD: OMAP: USB: R...
770
  	}
17cdd29d6   Keshava Munegowda   usb: host: omap: ...
771

1e7fe1a92   Keshava Munegowda   MFD: OMAP: USB: R...
772
  	if (is_ehci_phy_mode(pdata->port_mode[1])) {
06ba7dc75   Roger Quadros   mfd: omap-usb-hos...
773
  		ret = clk_set_parent(omap->utmi_p2_gfclk,
1e7fe1a92   Keshava Munegowda   MFD: OMAP: USB: R...
774
775
  					omap->xclk60mhsp2_ck);
  		if (ret != 0)
a8c4e9e11   Roger Quadros   mfd: omap-usb-hos...
776
777
778
  			dev_dbg(dev, "xclk60mhsp2_ck set parent failed: %d
  ",
  					ret);
1e7fe1a92   Keshava Munegowda   MFD: OMAP: USB: R...
779
  	} else if (is_ehci_tll_mode(pdata->port_mode[1])) {
06ba7dc75   Roger Quadros   mfd: omap-usb-hos...
780
  		ret = clk_set_parent(omap->utmi_p2_gfclk,
1e7fe1a92   Keshava Munegowda   MFD: OMAP: USB: R...
781
782
  						omap->init_60m_fclk);
  		if (ret != 0)
a8c4e9e11   Roger Quadros   mfd: omap-usb-hos...
783
784
785
  			dev_dbg(dev, "P1 init_60m_fclk set parent failed: %d
  ",
  					ret);
1e7fe1a92   Keshava Munegowda   MFD: OMAP: USB: R...
786
  	}
6eb6fbbf3   Keshava Munegowda   mfd: Fix omap usb...
787

f0447a690   Govindraj.R   mfd: Move omap-us...
788
  	omap_usbhs_init(dev);
03a8f438f   Roger Quadros   mfd: omap-usb-hos...
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
  
  	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);
  			goto err_alloc;
  		}
  
  	} else {
  		ret = omap_usbhs_alloc_children(pdev);
  		if (ret) {
  			dev_err(dev, "omap_usbhs_alloc_children failed: %d
  ",
  						ret);
  			goto err_alloc;
  		}
1e7fe1a92   Keshava Munegowda   MFD: OMAP: USB: R...
808
  	}
27d4f2c65   Roger Quadros   mfd: omap-usb-hos...
809
  	return 0;
1e7fe1a92   Keshava Munegowda   MFD: OMAP: USB: R...
810
811
  
  err_alloc:
340c64eab   Roger Quadros   mfd: omap-usb-hos...
812
  	for (i = 0; i < omap->nports; i++) {
06ba7dc75   Roger Quadros   mfd: omap-usb-hos...
813
814
  		if (!IS_ERR(omap->utmi_clk[i]))
  			clk_put(omap->utmi_clk[i]);
340c64eab   Roger Quadros   mfd: omap-usb-hos...
815
816
817
818
819
  		if (!IS_ERR(omap->hsic60m_clk[i]))
  			clk_put(omap->hsic60m_clk[i]);
  		if (!IS_ERR(omap->hsic480m_clk[i]))
  			clk_put(omap->hsic480m_clk[i]);
  	}
1e7fe1a92   Keshava Munegowda   MFD: OMAP: USB: R...
820

06ba7dc75   Roger Quadros   mfd: omap-usb-hos...
821
  	clk_put(omap->init_60m_fclk);
1e7fe1a92   Keshava Munegowda   MFD: OMAP: USB: R...
822

06ba7dc75   Roger Quadros   mfd: omap-usb-hos...
823
  err_init60m:
1e7fe1a92   Keshava Munegowda   MFD: OMAP: USB: R...
824
  	clk_put(omap->xclk60mhsp2_ck);
06ba7dc75   Roger Quadros   mfd: omap-usb-hos...
825
  err_xclk60mhsp2:
1e7fe1a92   Keshava Munegowda   MFD: OMAP: USB: R...
826
  	clk_put(omap->xclk60mhsp1_ck);
06ba7dc75   Roger Quadros   mfd: omap-usb-hos...
827
828
  err_xclk60mhsp1:
  	clk_put(omap->utmi_p2_gfclk);
1e7fe1a92   Keshava Munegowda   MFD: OMAP: USB: R...
829

06ba7dc75   Roger Quadros   mfd: omap-usb-hos...
830
831
832
833
834
835
836
837
  err_p2_gfclk:
  	clk_put(omap->utmi_p1_gfclk);
  
  err_p1_gfclk:
  	if (!IS_ERR(omap->ehci_logic_fck))
  		clk_put(omap->ehci_logic_fck);
  
  err_mem:
1e7fe1a92   Keshava Munegowda   MFD: OMAP: USB: R...
838
  	pm_runtime_disable(dev);
1e7fe1a92   Keshava Munegowda   MFD: OMAP: USB: R...
839

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

03a8f438f   Roger Quadros   mfd: omap-usb-hos...
843
844
845
846
847
848
849
  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...
850
851
852
853
854
855
  /**
   * 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...
856
  static int usbhs_omap_remove(struct platform_device *pdev)
17cdd29d6   Keshava Munegowda   usb: host: omap: ...
857
  {
1e7fe1a92   Keshava Munegowda   MFD: OMAP: USB: R...
858
  	struct usbhs_hcd_omap *omap = platform_get_drvdata(pdev);
06ba7dc75   Roger Quadros   mfd: omap-usb-hos...
859
  	int i;
1e7fe1a92   Keshava Munegowda   MFD: OMAP: USB: R...
860

340c64eab   Roger Quadros   mfd: omap-usb-hos...
861
  	for (i = 0; i < omap->nports; i++) {
06ba7dc75   Roger Quadros   mfd: omap-usb-hos...
862
863
  		if (!IS_ERR(omap->utmi_clk[i]))
  			clk_put(omap->utmi_clk[i]);
340c64eab   Roger Quadros   mfd: omap-usb-hos...
864
865
866
867
868
  		if (!IS_ERR(omap->hsic60m_clk[i]))
  			clk_put(omap->hsic60m_clk[i]);
  		if (!IS_ERR(omap->hsic480m_clk[i]))
  			clk_put(omap->hsic480m_clk[i]);
  	}
06ba7dc75   Roger Quadros   mfd: omap-usb-hos...
869

1e7fe1a92   Keshava Munegowda   MFD: OMAP: USB: R...
870
  	clk_put(omap->init_60m_fclk);
06ba7dc75   Roger Quadros   mfd: omap-usb-hos...
871
872
  	clk_put(omap->utmi_p1_gfclk);
  	clk_put(omap->utmi_p2_gfclk);
1e7fe1a92   Keshava Munegowda   MFD: OMAP: USB: R...
873
  	clk_put(omap->xclk60mhsp2_ck);
1e7fe1a92   Keshava Munegowda   MFD: OMAP: USB: R...
874
  	clk_put(omap->xclk60mhsp1_ck);
06ba7dc75   Roger Quadros   mfd: omap-usb-hos...
875
876
877
  
  	if (!IS_ERR(omap->ehci_logic_fck))
  		clk_put(omap->ehci_logic_fck);
1e7fe1a92   Keshava Munegowda   MFD: OMAP: USB: R...
878
  	pm_runtime_disable(&pdev->dev);
1e7fe1a92   Keshava Munegowda   MFD: OMAP: USB: R...
879

03a8f438f   Roger Quadros   mfd: omap-usb-hos...
880
881
  	/* remove children */
  	device_for_each_child(&pdev->dev, NULL, usbhs_omap_remove_child);
1e7fe1a92   Keshava Munegowda   MFD: OMAP: USB: R...
882
  	return 0;
17cdd29d6   Keshava Munegowda   usb: host: omap: ...
883
  }
1e7fe1a92   Keshava Munegowda   MFD: OMAP: USB: R...
884
885
886
887
888
  
  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: ...
889

03a8f438f   Roger Quadros   mfd: omap-usb-hos...
890
891
892
893
894
895
  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: ...
896
897
898
899
  static struct platform_driver usbhs_omap_driver = {
  	.driver = {
  		.name		= (char *)usbhs_driver_name,
  		.owner		= THIS_MODULE,
1e7fe1a92   Keshava Munegowda   MFD: OMAP: USB: R...
900
  		.pm		= &usbhsomap_dev_pm_ops,
0f54e1e12   Sachin Kamat   mfd: omap-usb: Re...
901
  		.of_match_table = usbhs_omap_dt_ids,
17cdd29d6   Keshava Munegowda   usb: host: omap: ...
902
  	},
ab3f2a86d   Roger Quadros   mfd: omap-usb-hos...
903
  	.remove		= usbhs_omap_remove,
17cdd29d6   Keshava Munegowda   usb: host: omap: ...
904
905
906
  };
  
  MODULE_AUTHOR("Keshava Munegowda <keshava_mgowda@ti.com>");
03a8f438f   Roger Quadros   mfd: omap-usb-hos...
907
  MODULE_AUTHOR("Roger Quadros <rogerq@ti.com>");
17cdd29d6   Keshava Munegowda   usb: host: omap: ...
908
909
910
911
912
913
914
915
916
917
918
919
920
  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...
921
922
   * This usbhs core driver should be initialized after
   * usb tll driver
17cdd29d6   Keshava Munegowda   usb: host: omap: ...
923
   */
4dc2cceb5   Keshava Munegowda   mfd: omap-usb-hos...
924
  fs_initcall_sync(omap_usbhs_drvinit);
17cdd29d6   Keshava Munegowda   usb: host: omap: ...
925
926
927
928
929
930
  
  static void __exit omap_usbhs_drvexit(void)
  {
  	platform_driver_unregister(&usbhs_omap_driver);
  }
  module_exit(omap_usbhs_drvexit);