diff options
author | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
---|---|---|
committer | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
commit | c71c03bda1e86c9d5198c5d83f712e695c4f2a1e (patch) | |
tree | ecb166cb3e2b7e2adb3b5e292245fefd23381ac8 /drivers/usb/musb/am35x.c | |
parent | ea53c912f8a86a8567697115b6a0d8152beee5c8 (diff) | |
parent | 6a00f206debf8a5c8899055726ad127dbeeed098 (diff) |
Merge branch 'mpi-master' into wip-k-fmlpwip-k-fmlp
Conflicts:
litmus/sched_cedf.c
Diffstat (limited to 'drivers/usb/musb/am35x.c')
-rw-r--r-- | drivers/usb/musb/am35x.c | 657 |
1 files changed, 657 insertions, 0 deletions
diff --git a/drivers/usb/musb/am35x.c b/drivers/usb/musb/am35x.c new file mode 100644 index 000000000000..23ac28f98d91 --- /dev/null +++ b/drivers/usb/musb/am35x.c | |||
@@ -0,0 +1,657 @@ | |||
1 | /* | ||
2 | * Texas Instruments AM35x "glue layer" | ||
3 | * | ||
4 | * Copyright (c) 2010, by Texas Instruments | ||
5 | * | ||
6 | * Based on the DA8xx "glue layer" code. | ||
7 | * Copyright (c) 2008-2009, MontaVista Software, Inc. <source@mvista.com> | ||
8 | * | ||
9 | * This file is part of the Inventra Controller Driver for Linux. | ||
10 | * | ||
11 | * The Inventra Controller Driver for Linux is free software; you | ||
12 | * can redistribute it and/or modify it under the terms of the GNU | ||
13 | * General Public License version 2 as published by the Free Software | ||
14 | * Foundation. | ||
15 | * | ||
16 | * The Inventra Controller Driver for Linux is distributed in | ||
17 | * the hope that it will be useful, but WITHOUT ANY WARRANTY; | ||
18 | * without even the implied warranty of MERCHANTABILITY or | ||
19 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public | ||
20 | * License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with The Inventra Controller Driver for Linux ; if not, | ||
24 | * write to the Free Software Foundation, Inc., 59 Temple Place, | ||
25 | * Suite 330, Boston, MA 02111-1307 USA | ||
26 | * | ||
27 | */ | ||
28 | |||
29 | #include <linux/init.h> | ||
30 | #include <linux/clk.h> | ||
31 | #include <linux/io.h> | ||
32 | #include <linux/platform_device.h> | ||
33 | #include <linux/dma-mapping.h> | ||
34 | |||
35 | #include <plat/usb.h> | ||
36 | |||
37 | #include "musb_core.h" | ||
38 | |||
39 | /* | ||
40 | * AM35x specific definitions | ||
41 | */ | ||
42 | /* USB 2.0 OTG module registers */ | ||
43 | #define USB_REVISION_REG 0x00 | ||
44 | #define USB_CTRL_REG 0x04 | ||
45 | #define USB_STAT_REG 0x08 | ||
46 | #define USB_EMULATION_REG 0x0c | ||
47 | /* 0x10 Reserved */ | ||
48 | #define USB_AUTOREQ_REG 0x14 | ||
49 | #define USB_SRP_FIX_TIME_REG 0x18 | ||
50 | #define USB_TEARDOWN_REG 0x1c | ||
51 | #define EP_INTR_SRC_REG 0x20 | ||
52 | #define EP_INTR_SRC_SET_REG 0x24 | ||
53 | #define EP_INTR_SRC_CLEAR_REG 0x28 | ||
54 | #define EP_INTR_MASK_REG 0x2c | ||
55 | #define EP_INTR_MASK_SET_REG 0x30 | ||
56 | #define EP_INTR_MASK_CLEAR_REG 0x34 | ||
57 | #define EP_INTR_SRC_MASKED_REG 0x38 | ||
58 | #define CORE_INTR_SRC_REG 0x40 | ||
59 | #define CORE_INTR_SRC_SET_REG 0x44 | ||
60 | #define CORE_INTR_SRC_CLEAR_REG 0x48 | ||
61 | #define CORE_INTR_MASK_REG 0x4c | ||
62 | #define CORE_INTR_MASK_SET_REG 0x50 | ||
63 | #define CORE_INTR_MASK_CLEAR_REG 0x54 | ||
64 | #define CORE_INTR_SRC_MASKED_REG 0x58 | ||
65 | /* 0x5c Reserved */ | ||
66 | #define USB_END_OF_INTR_REG 0x60 | ||
67 | |||
68 | /* Control register bits */ | ||
69 | #define AM35X_SOFT_RESET_MASK 1 | ||
70 | |||
71 | /* USB interrupt register bits */ | ||
72 | #define AM35X_INTR_USB_SHIFT 16 | ||
73 | #define AM35X_INTR_USB_MASK (0x1ff << AM35X_INTR_USB_SHIFT) | ||
74 | #define AM35X_INTR_DRVVBUS 0x100 | ||
75 | #define AM35X_INTR_RX_SHIFT 16 | ||
76 | #define AM35X_INTR_TX_SHIFT 0 | ||
77 | #define AM35X_TX_EP_MASK 0xffff /* EP0 + 15 Tx EPs */ | ||
78 | #define AM35X_RX_EP_MASK 0xfffe /* 15 Rx EPs */ | ||
79 | #define AM35X_TX_INTR_MASK (AM35X_TX_EP_MASK << AM35X_INTR_TX_SHIFT) | ||
80 | #define AM35X_RX_INTR_MASK (AM35X_RX_EP_MASK << AM35X_INTR_RX_SHIFT) | ||
81 | |||
82 | #define USB_MENTOR_CORE_OFFSET 0x400 | ||
83 | |||
84 | struct am35x_glue { | ||
85 | struct device *dev; | ||
86 | struct platform_device *musb; | ||
87 | struct clk *phy_clk; | ||
88 | struct clk *clk; | ||
89 | }; | ||
90 | #define glue_to_musb(g) platform_get_drvdata(g->musb) | ||
91 | |||
92 | /* | ||
93 | * am35x_musb_enable - enable interrupts | ||
94 | */ | ||
95 | static void am35x_musb_enable(struct musb *musb) | ||
96 | { | ||
97 | void __iomem *reg_base = musb->ctrl_base; | ||
98 | u32 epmask; | ||
99 | |||
100 | /* Workaround: setup IRQs through both register sets. */ | ||
101 | epmask = ((musb->epmask & AM35X_TX_EP_MASK) << AM35X_INTR_TX_SHIFT) | | ||
102 | ((musb->epmask & AM35X_RX_EP_MASK) << AM35X_INTR_RX_SHIFT); | ||
103 | |||
104 | musb_writel(reg_base, EP_INTR_MASK_SET_REG, epmask); | ||
105 | musb_writel(reg_base, CORE_INTR_MASK_SET_REG, AM35X_INTR_USB_MASK); | ||
106 | |||
107 | /* Force the DRVVBUS IRQ so we can start polling for ID change. */ | ||
108 | if (is_otg_enabled(musb)) | ||
109 | musb_writel(reg_base, CORE_INTR_SRC_SET_REG, | ||
110 | AM35X_INTR_DRVVBUS << AM35X_INTR_USB_SHIFT); | ||
111 | } | ||
112 | |||
113 | /* | ||
114 | * am35x_musb_disable - disable HDRC and flush interrupts | ||
115 | */ | ||
116 | static void am35x_musb_disable(struct musb *musb) | ||
117 | { | ||
118 | void __iomem *reg_base = musb->ctrl_base; | ||
119 | |||
120 | musb_writel(reg_base, CORE_INTR_MASK_CLEAR_REG, AM35X_INTR_USB_MASK); | ||
121 | musb_writel(reg_base, EP_INTR_MASK_CLEAR_REG, | ||
122 | AM35X_TX_INTR_MASK | AM35X_RX_INTR_MASK); | ||
123 | musb_writeb(musb->mregs, MUSB_DEVCTL, 0); | ||
124 | musb_writel(reg_base, USB_END_OF_INTR_REG, 0); | ||
125 | } | ||
126 | |||
127 | #ifdef CONFIG_USB_MUSB_HDRC_HCD | ||
128 | #define portstate(stmt) stmt | ||
129 | #else | ||
130 | #define portstate(stmt) | ||
131 | #endif | ||
132 | |||
133 | static void am35x_musb_set_vbus(struct musb *musb, int is_on) | ||
134 | { | ||
135 | WARN_ON(is_on && is_peripheral_active(musb)); | ||
136 | } | ||
137 | |||
138 | #define POLL_SECONDS 2 | ||
139 | |||
140 | static struct timer_list otg_workaround; | ||
141 | |||
142 | static void otg_timer(unsigned long _musb) | ||
143 | { | ||
144 | struct musb *musb = (void *)_musb; | ||
145 | void __iomem *mregs = musb->mregs; | ||
146 | u8 devctl; | ||
147 | unsigned long flags; | ||
148 | |||
149 | /* | ||
150 | * We poll because AM35x's won't expose several OTG-critical | ||
151 | * status change events (from the transceiver) otherwise. | ||
152 | */ | ||
153 | devctl = musb_readb(mregs, MUSB_DEVCTL); | ||
154 | dev_dbg(musb->controller, "Poll devctl %02x (%s)\n", devctl, | ||
155 | otg_state_string(musb->xceiv->state)); | ||
156 | |||
157 | spin_lock_irqsave(&musb->lock, flags); | ||
158 | switch (musb->xceiv->state) { | ||
159 | case OTG_STATE_A_WAIT_BCON: | ||
160 | devctl &= ~MUSB_DEVCTL_SESSION; | ||
161 | musb_writeb(musb->mregs, MUSB_DEVCTL, devctl); | ||
162 | |||
163 | devctl = musb_readb(musb->mregs, MUSB_DEVCTL); | ||
164 | if (devctl & MUSB_DEVCTL_BDEVICE) { | ||
165 | musb->xceiv->state = OTG_STATE_B_IDLE; | ||
166 | MUSB_DEV_MODE(musb); | ||
167 | } else { | ||
168 | musb->xceiv->state = OTG_STATE_A_IDLE; | ||
169 | MUSB_HST_MODE(musb); | ||
170 | } | ||
171 | break; | ||
172 | case OTG_STATE_A_WAIT_VFALL: | ||
173 | musb->xceiv->state = OTG_STATE_A_WAIT_VRISE; | ||
174 | musb_writel(musb->ctrl_base, CORE_INTR_SRC_SET_REG, | ||
175 | MUSB_INTR_VBUSERROR << AM35X_INTR_USB_SHIFT); | ||
176 | break; | ||
177 | case OTG_STATE_B_IDLE: | ||
178 | if (!is_peripheral_enabled(musb)) | ||
179 | break; | ||
180 | |||
181 | devctl = musb_readb(mregs, MUSB_DEVCTL); | ||
182 | if (devctl & MUSB_DEVCTL_BDEVICE) | ||
183 | mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ); | ||
184 | else | ||
185 | musb->xceiv->state = OTG_STATE_A_IDLE; | ||
186 | break; | ||
187 | default: | ||
188 | break; | ||
189 | } | ||
190 | spin_unlock_irqrestore(&musb->lock, flags); | ||
191 | } | ||
192 | |||
193 | static void am35x_musb_try_idle(struct musb *musb, unsigned long timeout) | ||
194 | { | ||
195 | static unsigned long last_timer; | ||
196 | |||
197 | if (!is_otg_enabled(musb)) | ||
198 | return; | ||
199 | |||
200 | if (timeout == 0) | ||
201 | timeout = jiffies + msecs_to_jiffies(3); | ||
202 | |||
203 | /* Never idle if active, or when VBUS timeout is not set as host */ | ||
204 | if (musb->is_active || (musb->a_wait_bcon == 0 && | ||
205 | musb->xceiv->state == OTG_STATE_A_WAIT_BCON)) { | ||
206 | dev_dbg(musb->controller, "%s active, deleting timer\n", | ||
207 | otg_state_string(musb->xceiv->state)); | ||
208 | del_timer(&otg_workaround); | ||
209 | last_timer = jiffies; | ||
210 | return; | ||
211 | } | ||
212 | |||
213 | if (time_after(last_timer, timeout) && timer_pending(&otg_workaround)) { | ||
214 | dev_dbg(musb->controller, "Longer idle timer already pending, ignoring...\n"); | ||
215 | return; | ||
216 | } | ||
217 | last_timer = timeout; | ||
218 | |||
219 | dev_dbg(musb->controller, "%s inactive, starting idle timer for %u ms\n", | ||
220 | otg_state_string(musb->xceiv->state), | ||
221 | jiffies_to_msecs(timeout - jiffies)); | ||
222 | mod_timer(&otg_workaround, timeout); | ||
223 | } | ||
224 | |||
225 | static irqreturn_t am35x_musb_interrupt(int irq, void *hci) | ||
226 | { | ||
227 | struct musb *musb = hci; | ||
228 | void __iomem *reg_base = musb->ctrl_base; | ||
229 | struct device *dev = musb->controller; | ||
230 | struct musb_hdrc_platform_data *plat = dev->platform_data; | ||
231 | struct omap_musb_board_data *data = plat->board_data; | ||
232 | unsigned long flags; | ||
233 | irqreturn_t ret = IRQ_NONE; | ||
234 | u32 epintr, usbintr; | ||
235 | |||
236 | spin_lock_irqsave(&musb->lock, flags); | ||
237 | |||
238 | /* Get endpoint interrupts */ | ||
239 | epintr = musb_readl(reg_base, EP_INTR_SRC_MASKED_REG); | ||
240 | |||
241 | if (epintr) { | ||
242 | musb_writel(reg_base, EP_INTR_SRC_CLEAR_REG, epintr); | ||
243 | |||
244 | musb->int_rx = | ||
245 | (epintr & AM35X_RX_INTR_MASK) >> AM35X_INTR_RX_SHIFT; | ||
246 | musb->int_tx = | ||
247 | (epintr & AM35X_TX_INTR_MASK) >> AM35X_INTR_TX_SHIFT; | ||
248 | } | ||
249 | |||
250 | /* Get usb core interrupts */ | ||
251 | usbintr = musb_readl(reg_base, CORE_INTR_SRC_MASKED_REG); | ||
252 | if (!usbintr && !epintr) | ||
253 | goto eoi; | ||
254 | |||
255 | if (usbintr) { | ||
256 | musb_writel(reg_base, CORE_INTR_SRC_CLEAR_REG, usbintr); | ||
257 | |||
258 | musb->int_usb = | ||
259 | (usbintr & AM35X_INTR_USB_MASK) >> AM35X_INTR_USB_SHIFT; | ||
260 | } | ||
261 | /* | ||
262 | * DRVVBUS IRQs are the only proxy we have (a very poor one!) for | ||
263 | * AM35x's missing ID change IRQ. We need an ID change IRQ to | ||
264 | * switch appropriately between halves of the OTG state machine. | ||
265 | * Managing DEVCTL.SESSION per Mentor docs requires that we know its | ||
266 | * value but DEVCTL.BDEVICE is invalid without DEVCTL.SESSION set. | ||
267 | * Also, DRVVBUS pulses for SRP (but not at 5V) ... | ||
268 | */ | ||
269 | if (usbintr & (AM35X_INTR_DRVVBUS << AM35X_INTR_USB_SHIFT)) { | ||
270 | int drvvbus = musb_readl(reg_base, USB_STAT_REG); | ||
271 | void __iomem *mregs = musb->mregs; | ||
272 | u8 devctl = musb_readb(mregs, MUSB_DEVCTL); | ||
273 | int err; | ||
274 | |||
275 | err = is_host_enabled(musb) && (musb->int_usb & | ||
276 | MUSB_INTR_VBUSERROR); | ||
277 | if (err) { | ||
278 | /* | ||
279 | * The Mentor core doesn't debounce VBUS as needed | ||
280 | * to cope with device connect current spikes. This | ||
281 | * means it's not uncommon for bus-powered devices | ||
282 | * to get VBUS errors during enumeration. | ||
283 | * | ||
284 | * This is a workaround, but newer RTL from Mentor | ||
285 | * seems to allow a better one: "re"-starting sessions | ||
286 | * without waiting for VBUS to stop registering in | ||
287 | * devctl. | ||
288 | */ | ||
289 | musb->int_usb &= ~MUSB_INTR_VBUSERROR; | ||
290 | musb->xceiv->state = OTG_STATE_A_WAIT_VFALL; | ||
291 | mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ); | ||
292 | WARNING("VBUS error workaround (delay coming)\n"); | ||
293 | } else if (is_host_enabled(musb) && drvvbus) { | ||
294 | MUSB_HST_MODE(musb); | ||
295 | musb->xceiv->default_a = 1; | ||
296 | musb->xceiv->state = OTG_STATE_A_WAIT_VRISE; | ||
297 | portstate(musb->port1_status |= USB_PORT_STAT_POWER); | ||
298 | del_timer(&otg_workaround); | ||
299 | } else { | ||
300 | musb->is_active = 0; | ||
301 | MUSB_DEV_MODE(musb); | ||
302 | musb->xceiv->default_a = 0; | ||
303 | musb->xceiv->state = OTG_STATE_B_IDLE; | ||
304 | portstate(musb->port1_status &= ~USB_PORT_STAT_POWER); | ||
305 | } | ||
306 | |||
307 | /* NOTE: this must complete power-on within 100 ms. */ | ||
308 | dev_dbg(musb->controller, "VBUS %s (%s)%s, devctl %02x\n", | ||
309 | drvvbus ? "on" : "off", | ||
310 | otg_state_string(musb->xceiv->state), | ||
311 | err ? " ERROR" : "", | ||
312 | devctl); | ||
313 | ret = IRQ_HANDLED; | ||
314 | } | ||
315 | |||
316 | if (musb->int_tx || musb->int_rx || musb->int_usb) | ||
317 | ret |= musb_interrupt(musb); | ||
318 | |||
319 | eoi: | ||
320 | /* EOI needs to be written for the IRQ to be re-asserted. */ | ||
321 | if (ret == IRQ_HANDLED || epintr || usbintr) { | ||
322 | /* clear level interrupt */ | ||
323 | if (data->clear_irq) | ||
324 | data->clear_irq(); | ||
325 | /* write EOI */ | ||
326 | musb_writel(reg_base, USB_END_OF_INTR_REG, 0); | ||
327 | } | ||
328 | |||
329 | /* Poll for ID change */ | ||
330 | if (is_otg_enabled(musb) && musb->xceiv->state == OTG_STATE_B_IDLE) | ||
331 | mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ); | ||
332 | |||
333 | spin_unlock_irqrestore(&musb->lock, flags); | ||
334 | |||
335 | return ret; | ||
336 | } | ||
337 | |||
338 | static int am35x_musb_set_mode(struct musb *musb, u8 musb_mode) | ||
339 | { | ||
340 | struct device *dev = musb->controller; | ||
341 | struct musb_hdrc_platform_data *plat = dev->platform_data; | ||
342 | struct omap_musb_board_data *data = plat->board_data; | ||
343 | int retval = 0; | ||
344 | |||
345 | if (data->set_mode) | ||
346 | data->set_mode(musb_mode); | ||
347 | else | ||
348 | retval = -EIO; | ||
349 | |||
350 | return retval; | ||
351 | } | ||
352 | |||
353 | static int am35x_musb_init(struct musb *musb) | ||
354 | { | ||
355 | struct device *dev = musb->controller; | ||
356 | struct musb_hdrc_platform_data *plat = dev->platform_data; | ||
357 | struct omap_musb_board_data *data = plat->board_data; | ||
358 | void __iomem *reg_base = musb->ctrl_base; | ||
359 | u32 rev; | ||
360 | |||
361 | musb->mregs += USB_MENTOR_CORE_OFFSET; | ||
362 | |||
363 | /* Returns zero if e.g. not clocked */ | ||
364 | rev = musb_readl(reg_base, USB_REVISION_REG); | ||
365 | if (!rev) | ||
366 | return -ENODEV; | ||
367 | |||
368 | usb_nop_xceiv_register(); | ||
369 | musb->xceiv = otg_get_transceiver(); | ||
370 | if (!musb->xceiv) | ||
371 | return -ENODEV; | ||
372 | |||
373 | if (is_host_enabled(musb)) | ||
374 | setup_timer(&otg_workaround, otg_timer, (unsigned long) musb); | ||
375 | |||
376 | /* Reset the musb */ | ||
377 | if (data->reset) | ||
378 | data->reset(); | ||
379 | |||
380 | /* Reset the controller */ | ||
381 | musb_writel(reg_base, USB_CTRL_REG, AM35X_SOFT_RESET_MASK); | ||
382 | |||
383 | /* Start the on-chip PHY and its PLL. */ | ||
384 | if (data->set_phy_power) | ||
385 | data->set_phy_power(1); | ||
386 | |||
387 | msleep(5); | ||
388 | |||
389 | musb->isr = am35x_musb_interrupt; | ||
390 | |||
391 | /* clear level interrupt */ | ||
392 | if (data->clear_irq) | ||
393 | data->clear_irq(); | ||
394 | |||
395 | return 0; | ||
396 | } | ||
397 | |||
398 | static int am35x_musb_exit(struct musb *musb) | ||
399 | { | ||
400 | struct device *dev = musb->controller; | ||
401 | struct musb_hdrc_platform_data *plat = dev->platform_data; | ||
402 | struct omap_musb_board_data *data = plat->board_data; | ||
403 | |||
404 | if (is_host_enabled(musb)) | ||
405 | del_timer_sync(&otg_workaround); | ||
406 | |||
407 | /* Shutdown the on-chip PHY and its PLL. */ | ||
408 | if (data->set_phy_power) | ||
409 | data->set_phy_power(0); | ||
410 | |||
411 | otg_put_transceiver(musb->xceiv); | ||
412 | usb_nop_xceiv_unregister(); | ||
413 | |||
414 | return 0; | ||
415 | } | ||
416 | |||
417 | /* AM35x supports only 32bit read operation */ | ||
418 | void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *dst) | ||
419 | { | ||
420 | void __iomem *fifo = hw_ep->fifo; | ||
421 | u32 val; | ||
422 | int i; | ||
423 | |||
424 | /* Read for 32bit-aligned destination address */ | ||
425 | if (likely((0x03 & (unsigned long) dst) == 0) && len >= 4) { | ||
426 | readsl(fifo, dst, len >> 2); | ||
427 | dst += len & ~0x03; | ||
428 | len &= 0x03; | ||
429 | } | ||
430 | /* | ||
431 | * Now read the remaining 1 to 3 byte or complete length if | ||
432 | * unaligned address. | ||
433 | */ | ||
434 | if (len > 4) { | ||
435 | for (i = 0; i < (len >> 2); i++) { | ||
436 | *(u32 *) dst = musb_readl(fifo, 0); | ||
437 | dst += 4; | ||
438 | } | ||
439 | len &= 0x03; | ||
440 | } | ||
441 | if (len > 0) { | ||
442 | val = musb_readl(fifo, 0); | ||
443 | memcpy(dst, &val, len); | ||
444 | } | ||
445 | } | ||
446 | |||
447 | static const struct musb_platform_ops am35x_ops = { | ||
448 | .init = am35x_musb_init, | ||
449 | .exit = am35x_musb_exit, | ||
450 | |||
451 | .enable = am35x_musb_enable, | ||
452 | .disable = am35x_musb_disable, | ||
453 | |||
454 | .set_mode = am35x_musb_set_mode, | ||
455 | .try_idle = am35x_musb_try_idle, | ||
456 | |||
457 | .set_vbus = am35x_musb_set_vbus, | ||
458 | }; | ||
459 | |||
460 | static u64 am35x_dmamask = DMA_BIT_MASK(32); | ||
461 | |||
462 | static int __init am35x_probe(struct platform_device *pdev) | ||
463 | { | ||
464 | struct musb_hdrc_platform_data *pdata = pdev->dev.platform_data; | ||
465 | struct platform_device *musb; | ||
466 | struct am35x_glue *glue; | ||
467 | |||
468 | struct clk *phy_clk; | ||
469 | struct clk *clk; | ||
470 | |||
471 | int ret = -ENOMEM; | ||
472 | |||
473 | glue = kzalloc(sizeof(*glue), GFP_KERNEL); | ||
474 | if (!glue) { | ||
475 | dev_err(&pdev->dev, "failed to allocate glue context\n"); | ||
476 | goto err0; | ||
477 | } | ||
478 | |||
479 | musb = platform_device_alloc("musb-hdrc", -1); | ||
480 | if (!musb) { | ||
481 | dev_err(&pdev->dev, "failed to allocate musb device\n"); | ||
482 | goto err1; | ||
483 | } | ||
484 | |||
485 | phy_clk = clk_get(&pdev->dev, "fck"); | ||
486 | if (IS_ERR(phy_clk)) { | ||
487 | dev_err(&pdev->dev, "failed to get PHY clock\n"); | ||
488 | ret = PTR_ERR(phy_clk); | ||
489 | goto err2; | ||
490 | } | ||
491 | |||
492 | clk = clk_get(&pdev->dev, "ick"); | ||
493 | if (IS_ERR(clk)) { | ||
494 | dev_err(&pdev->dev, "failed to get clock\n"); | ||
495 | ret = PTR_ERR(clk); | ||
496 | goto err3; | ||
497 | } | ||
498 | |||
499 | ret = clk_enable(phy_clk); | ||
500 | if (ret) { | ||
501 | dev_err(&pdev->dev, "failed to enable PHY clock\n"); | ||
502 | goto err4; | ||
503 | } | ||
504 | |||
505 | ret = clk_enable(clk); | ||
506 | if (ret) { | ||
507 | dev_err(&pdev->dev, "failed to enable clock\n"); | ||
508 | goto err5; | ||
509 | } | ||
510 | |||
511 | musb->dev.parent = &pdev->dev; | ||
512 | musb->dev.dma_mask = &am35x_dmamask; | ||
513 | musb->dev.coherent_dma_mask = am35x_dmamask; | ||
514 | |||
515 | glue->dev = &pdev->dev; | ||
516 | glue->musb = musb; | ||
517 | glue->phy_clk = phy_clk; | ||
518 | glue->clk = clk; | ||
519 | |||
520 | pdata->platform_ops = &am35x_ops; | ||
521 | |||
522 | platform_set_drvdata(pdev, glue); | ||
523 | |||
524 | ret = platform_device_add_resources(musb, pdev->resource, | ||
525 | pdev->num_resources); | ||
526 | if (ret) { | ||
527 | dev_err(&pdev->dev, "failed to add resources\n"); | ||
528 | goto err6; | ||
529 | } | ||
530 | |||
531 | ret = platform_device_add_data(musb, pdata, sizeof(*pdata)); | ||
532 | if (ret) { | ||
533 | dev_err(&pdev->dev, "failed to add platform_data\n"); | ||
534 | goto err6; | ||
535 | } | ||
536 | |||
537 | ret = platform_device_add(musb); | ||
538 | if (ret) { | ||
539 | dev_err(&pdev->dev, "failed to register musb device\n"); | ||
540 | goto err6; | ||
541 | } | ||
542 | |||
543 | return 0; | ||
544 | |||
545 | err6: | ||
546 | clk_disable(clk); | ||
547 | |||
548 | err5: | ||
549 | clk_disable(phy_clk); | ||
550 | |||
551 | err4: | ||
552 | clk_put(clk); | ||
553 | |||
554 | err3: | ||
555 | clk_put(phy_clk); | ||
556 | |||
557 | err2: | ||
558 | platform_device_put(musb); | ||
559 | |||
560 | err1: | ||
561 | kfree(glue); | ||
562 | |||
563 | err0: | ||
564 | return ret; | ||
565 | } | ||
566 | |||
567 | static int __exit am35x_remove(struct platform_device *pdev) | ||
568 | { | ||
569 | struct am35x_glue *glue = platform_get_drvdata(pdev); | ||
570 | |||
571 | platform_device_del(glue->musb); | ||
572 | platform_device_put(glue->musb); | ||
573 | clk_disable(glue->clk); | ||
574 | clk_disable(glue->phy_clk); | ||
575 | clk_put(glue->clk); | ||
576 | clk_put(glue->phy_clk); | ||
577 | kfree(glue); | ||
578 | |||
579 | return 0; | ||
580 | } | ||
581 | |||
582 | #ifdef CONFIG_PM | ||
583 | static int am35x_suspend(struct device *dev) | ||
584 | { | ||
585 | struct am35x_glue *glue = dev_get_drvdata(dev); | ||
586 | struct musb_hdrc_platform_data *plat = dev->platform_data; | ||
587 | struct omap_musb_board_data *data = plat->board_data; | ||
588 | |||
589 | /* Shutdown the on-chip PHY and its PLL. */ | ||
590 | if (data->set_phy_power) | ||
591 | data->set_phy_power(0); | ||
592 | |||
593 | clk_disable(glue->phy_clk); | ||
594 | clk_disable(glue->clk); | ||
595 | |||
596 | return 0; | ||
597 | } | ||
598 | |||
599 | static int am35x_resume(struct device *dev) | ||
600 | { | ||
601 | struct am35x_glue *glue = dev_get_drvdata(dev); | ||
602 | struct musb_hdrc_platform_data *plat = dev->platform_data; | ||
603 | struct omap_musb_board_data *data = plat->board_data; | ||
604 | int ret; | ||
605 | |||
606 | /* Start the on-chip PHY and its PLL. */ | ||
607 | if (data->set_phy_power) | ||
608 | data->set_phy_power(1); | ||
609 | |||
610 | ret = clk_enable(glue->phy_clk); | ||
611 | if (ret) { | ||
612 | dev_err(dev, "failed to enable PHY clock\n"); | ||
613 | return ret; | ||
614 | } | ||
615 | |||
616 | ret = clk_enable(glue->clk); | ||
617 | if (ret) { | ||
618 | dev_err(dev, "failed to enable clock\n"); | ||
619 | return ret; | ||
620 | } | ||
621 | |||
622 | return 0; | ||
623 | } | ||
624 | |||
625 | static struct dev_pm_ops am35x_pm_ops = { | ||
626 | .suspend = am35x_suspend, | ||
627 | .resume = am35x_resume, | ||
628 | }; | ||
629 | |||
630 | #define DEV_PM_OPS &am35x_pm_ops | ||
631 | #else | ||
632 | #define DEV_PM_OPS NULL | ||
633 | #endif | ||
634 | |||
635 | static struct platform_driver am35x_driver = { | ||
636 | .remove = __exit_p(am35x_remove), | ||
637 | .driver = { | ||
638 | .name = "musb-am35x", | ||
639 | .pm = DEV_PM_OPS, | ||
640 | }, | ||
641 | }; | ||
642 | |||
643 | MODULE_DESCRIPTION("AM35x MUSB Glue Layer"); | ||
644 | MODULE_AUTHOR("Ajay Kumar Gupta <ajay.gupta@ti.com>"); | ||
645 | MODULE_LICENSE("GPL v2"); | ||
646 | |||
647 | static int __init am35x_init(void) | ||
648 | { | ||
649 | return platform_driver_probe(&am35x_driver, am35x_probe); | ||
650 | } | ||
651 | subsys_initcall(am35x_init); | ||
652 | |||
653 | static void __exit am35x_exit(void) | ||
654 | { | ||
655 | platform_driver_unregister(&am35x_driver); | ||
656 | } | ||
657 | module_exit(am35x_exit); | ||