fdc88f1ffccd7a8a5ed0a016fc140f48fdab44c9
[hackover2013-badge-firmware.git] / core / usbcdc / usbhw.c
1 /*----------------------------------------------------------------------------
2 * U S B - K e r n e l
3 *----------------------------------------------------------------------------
4 * Name: usbhw.c
5 * Purpose: USB Hardware Layer Module for Philips LPC17xx
6 * Version: V1.20
7 *----------------------------------------------------------------------------
8 * This software is supplied "AS IS" without any warranties, express,
9 * implied or statutory, including but not limited to the implied
10 * warranties of fitness for purpose, satisfactory quality and
11 * noninfringement. Keil extends you a royalty-free right to reproduce
12 * and distribute executable files created using this software for use
13 * on NXP Semiconductors LPC microcontroller devices only. Nothing else
14 * gives you the right to use this software.
15 *
16 * Copyright (c) 2009 Keil - An ARM Company. All rights reserved.
17 *----------------------------------------------------------------------------
18 * History:
19 * V1.20 Added USB_ClearEPBuf
20 * V1.00 Initial Version
21 *----------------------------------------------------------------------------*/
22 #include "projectconfig.h" /* LPC13xx definitions */
23 #include "usb.h"
24 #include "usbcfg.h"
25 #include "usbreg.h"
26 #include "usbhw.h"
27 #include "usbcore.h"
28 #include "usbuser.h"
29
30
31 /*
32 * USB and IO Clock configuration only.
33 * The same as call PeriClkIOInit(IOCON_USB);
34 * The purpose is to reduce the code space for
35 * overall USB project and reserve code space for
36 * USB debugging.
37 * Parameters: None
38 * Return Value: None
39 */
40 void USBIOClkConfig( void )
41 {
42 /* Enable AHB clock to the GPIO domain. */
43 SCB_SYSAHBCLKCTRL |= SCB_SYSAHBCLKCTRL_GPIO;
44
45 /* Enable Timer32_1, IOCON, and USB blocks */
46 SCB_SYSAHBCLKCTRL |= (SCB_SYSAHBCLKCTRL_CT32B1 | SCB_SYSAHBCLKCTRL_IOCON | SCB_SYSAHBCLKCTRL_USB_REG);
47
48 // Setup USB clock
49 SCB_PDRUNCFG &= ~(SCB_PDSLEEPCFG_USBPAD_PD); // Power-up USB PHY
50 SCB_PDRUNCFG &= ~(SCB_PDSLEEPCFG_USBPLL_PD); // Power-up USB PLL
51
52 SCB_USBPLLCLKSEL = SCB_USBPLLCLKSEL_SOURCE_MAINOSC; // Select PLL Input
53 SCB_USBPLLCLKUEN = SCB_USBPLLCLKUEN_UPDATE; // Update Clock Source
54 SCB_USBPLLCLKUEN = SCB_USBPLLCLKUEN_DISABLE; // Toggle Update Register
55 SCB_USBPLLCLKUEN = SCB_USBPLLCLKUEN_UPDATE;
56
57 // Wait until the USB clock is updated
58 while (!(SCB_USBPLLCLKUEN & SCB_USBPLLCLKUEN_UPDATE));
59
60 // Set USB clock to 48MHz (12MHz x 4)
61 SCB_USBPLLCTRL = (SCB_USBPLLCTRL_MULT_4);
62 while (!(SCB_USBPLLSTAT & SCB_USBPLLSTAT_LOCK)); // Wait Until PLL Locked
63 SCB_USBCLKSEL = SCB_USBCLKSEL_SOURCE_USBPLLOUT;
64
65 // Set USB pin functions
66 IOCON_PIO0_1 &= ~IOCON_PIO0_1_FUNC_MASK;
67 IOCON_PIO0_1 |= IOCON_PIO0_1_FUNC_CLKOUT; // CLK OUT
68 IOCON_PIO0_3 &= ~IOCON_PIO0_3_FUNC_MASK;
69 IOCON_PIO0_3 |= IOCON_PIO0_3_FUNC_USB_VBUS; // VBus
70 IOCON_PIO0_6 &= ~IOCON_PIO0_6_FUNC_MASK;
71 IOCON_PIO0_6 |= IOCON_PIO0_6_FUNC_USB_CONNECT; // Soft Connect
72
73 return;
74 }
75
76 /*
77 * Delay number of clock cycles
78 * Parameters: Delay length
79 * Return Value: None
80 */
81
82 void delay (uint32_t length )
83 {
84 uint32_t i;
85
86 for ( i = 0; i < length; i++ )
87 {
88 __asm("nop");
89 }
90 return;
91 }
92
93 /*
94 * Get Endpoint Physical Address
95 * Parameters: EPNum: Endpoint Number
96 * EPNum.0..3: Address
97 * EPNum.7: Dir
98 * Return Value: Endpoint Physical Address
99 */
100
101 uint32_t EPAdr (uint32_t EPNum)
102 {
103 uint32_t val;
104
105 val = (EPNum & 0x0F) << 1;
106 if (EPNum & 0x80) {
107 val += 1;
108 }
109 return (val);
110 }
111
112
113 /*
114 * Write Command
115 * Parameters: cmd: Command
116 * Return Value: None
117 */
118
119 void WrCmd (uint32_t cmd)
120 {
121 USB_DEVINTCLR = CCEMTY_INT;
122 USB_CMDCODE = cmd;
123 while ((USB_DEVINTST & (CCEMTY_INT | DEV_STAT_INT)) == 0);
124 }
125
126
127 /*
128 * Write Command Data
129 * Parameters: cmd: Command
130 * val: Data
131 * Return Value: None
132 */
133
134 void WrCmdDat (uint32_t cmd, uint32_t val)
135 {
136 WrCmd(cmd);
137 WrCmd(val);
138 }
139
140
141 /*
142 * Write Command to Endpoint
143 * Parameters: cmd: Command
144 * val: Data
145 * Return Value: None
146 */
147
148 void WrCmdEP (uint32_t EPNum, uint32_t cmd)
149 {
150 WrCmd(CMD_SEL_EP(EPAdr(EPNum)));
151 WrCmd(cmd);
152 }
153
154
155 /*
156 * Read Command Data
157 * Parameters: cmd: Command
158 * Return Value: Data Value
159 */
160
161 uint32_t RdCmdDat (uint32_t cmd)
162 {
163 USB_DEVINTCLR = CCEMTY_INT | CDFULL_INT;
164 USB_CMDCODE = cmd;
165 while ((USB_DEVINTST & (CDFULL_INT | DEV_STAT_INT)) == 0);
166 return (USB_CMDDATA);
167 }
168
169
170 /*
171 * USB Initialize Function
172 * Called by the User to initialize USB
173 * Return Value: None
174 */
175
176 void USB_Init (void)
177 {
178 // Setup USB clock and pins
179 USBIOClkConfig();
180
181 #if USB_FIQ_EVENT
182 /* It's important that only BULK and FRAME(ISO) can be routed
183 to FIQ. */
184 USB_DEVFIQSEL = 0x01; /* SOF Use FIQ */
185
186 /* Enable the USB Interrupt */
187 NVIC_EnableIRQ(USB_FIQn);
188 #endif
189
190 /* Enable the USB Interrupt */
191 NVIC_EnableIRQ(USB_IRQn);
192
193 USB_Reset();
194 USB_SetAddress(0);
195 return;
196 }
197
198
199 /*
200 * USB Connect Function
201 * Called by the User to Connect/Disconnect USB
202 * Parameters: con: Connect/Disconnect
203 * Return Value: None
204 */
205
206 void USB_Connect (uint32_t con)
207 {
208 WrCmdDat(CMD_SET_DEV_STAT, DAT_WR_BYTE(con ? DEV_CON : 0));
209 }
210
211
212 /*
213 * USB Reset Function
214 * Called automatically on USB Reset
215 * Return Value: None
216 */
217
218 void USB_Reset (void)
219 {
220 USB_DEVINTCLR = 0x000FFFFF;
221 /* Enable all eight(8) EPs, note: EP won't be ready until it's
222 configured/enabled when device sending SetEPStatus command
223 to the command engine. */
224 USB_DEVINTEN = DEV_STAT_INT | (0xFF<<1) |
225 (USB_SOF_EVENT ? FRAME_INT : 0);
226 return;
227 }
228
229
230 /*
231 * USB Suspend Function
232 * Called automatically on USB Suspend
233 * Return Value: None
234 */
235
236 void USB_Suspend (void)
237 {
238 /* Performed by Hardware */
239 }
240
241
242 /*
243 * USB Resume Function
244 * Called automatically on USB Resume
245 * Return Value: None
246 */
247
248 void USB_Resume (void)
249 {
250 /* Performed by Hardware */
251 }
252
253
254 /*
255 * USB Remote Wakeup Function
256 * Called automatically on USB Remote Wakeup
257 * Return Value: None
258 */
259
260 void USB_WakeUp (void)
261 {
262 if (USB_DeviceStatus & USB_GETSTATUS_REMOTE_WAKEUP)
263 {
264 WrCmdDat(CMD_SET_DEV_STAT, DAT_WR_BYTE(DEV_CON));
265 }
266 }
267
268
269 /*
270 * USB Remote Wakeup Configuration Function
271 * Parameters: cfg: Enable/Disable
272 * Return Value: None
273 */
274
275 void USB_WakeUpCfg (uint32_t cfg)
276 {
277 cfg = cfg; /* Not needed */
278 }
279
280
281 /*
282 * USB Set Address Function
283 * Parameters: adr: USB Address
284 * Return Value: None
285 */
286
287 void USB_SetAddress (uint32_t adr)
288 {
289 WrCmdDat(CMD_SET_ADDR, DAT_WR_BYTE(DEV_EN | adr)); /* Don't wait for next */
290 WrCmdDat(CMD_SET_ADDR, DAT_WR_BYTE(DEV_EN | adr)); /* Setup Status Phase */
291 }
292
293
294 /*
295 * USB Configure Function
296 * Parameters: cfg: Configure/Deconfigure
297 * Return Value: None
298 */
299
300 void USB_Configure (uint32_t cfg)
301 {
302 WrCmdDat(CMD_CFG_DEV, DAT_WR_BYTE(cfg ? CONF_DVICE : 0));
303 return;
304 }
305
306
307 /*
308 * Configure USB Endpoint according to Descriptor
309 * Parameters: pEPD: Pointer to Endpoint Descriptor
310 * Return Value: None
311 */
312
313 void USB_ConfigEP (USB_ENDPOINT_DESCRIPTOR *pEPD)
314 {
315 return;
316 }
317
318
319 /*
320 * Set Direction for USB Control Endpoint
321 * Parameters: dir: Out (dir == 0), In (dir <> 0)
322 * Return Value: None
323 */
324
325 void USB_DirCtrlEP (uint32_t dir)
326 {
327 dir = dir; /* Not needed */
328 }
329
330
331 /*
332 * Enable USB Endpoint
333 * Parameters: EPNum: Endpoint Number
334 * EPNum.0..3: Address
335 * EPNum.7: Dir
336 * Return Value: None
337 */
338
339 void USB_EnableEP (uint32_t EPNum)
340 {
341 WrCmdDat(CMD_SET_EP_STAT(EPAdr(EPNum)), DAT_WR_BYTE(0));
342 }
343
344
345 /*
346 * Disable USB Endpoint
347 * Parameters: EPNum: Endpoint Number
348 * EPNum.0..3: Address
349 * EPNum.7: Dir
350 * Return Value: None
351 */
352
353 void USB_DisableEP (uint32_t EPNum)
354 {
355 WrCmdDat(CMD_SET_EP_STAT(EPAdr(EPNum)), DAT_WR_BYTE(EP_STAT_DA));
356 }
357
358
359 /*
360 * Reset USB Endpoint
361 * Parameters: EPNum: Endpoint Number
362 * EPNum.0..3: Address
363 * EPNum.7: Dir
364 * Return Value: None
365 */
366
367 void USB_ResetEP (uint32_t EPNum)
368 {
369 WrCmdDat(CMD_SET_EP_STAT(EPAdr(EPNum)), DAT_WR_BYTE(0));
370 }
371
372
373 /*
374 * Set Stall for USB Endpoint
375 * Parameters: EPNum: Endpoint Number
376 * EPNum.0..3: Address
377 * EPNum.7: Dir
378 * Return Value: None
379 */
380
381 void USB_SetStallEP (uint32_t EPNum)
382 {
383 WrCmdDat(CMD_SET_EP_STAT(EPAdr(EPNum)), DAT_WR_BYTE(EP_STAT_ST));
384 }
385
386
387 /*
388 * Clear Stall for USB Endpoint
389 * Parameters: EPNum: Endpoint Number
390 * EPNum.0..3: Address
391 * EPNum.7: Dir
392 * Return Value: None
393 */
394
395 void USB_ClrStallEP (uint32_t EPNum)
396 {
397 WrCmdDat(CMD_SET_EP_STAT(EPAdr(EPNum)), DAT_WR_BYTE(0));
398 }
399
400
401 /*
402 * Clear USB Endpoint Buffer
403 * Parameters: EPNum: Endpoint Number
404 * EPNum.0..3: Address
405 * EPNum.7: Dir
406 * Return Value: None
407 */
408
409 void USB_ClearEPBuf (uint32_t EPNum)
410 {
411 WrCmdEP(EPNum, CMD_CLR_BUF);
412 }
413
414
415 /*
416 * Read USB Endpoint Data
417 * Parameters: EPNum: Endpoint Number
418 * EPNum.0..3: Address
419 * EPNum.7: Dir
420 * pData: Pointer to Data Buffer
421 * Return Value: Number of bytes read
422 */
423
424 uint32_t USB_ReadEP (uint32_t EPNum, uint8_t *pData)
425 {
426 uint32_t cnt, n;
427
428 USB_CTRL = ((EPNum & 0x0F) << 2) | CTRL_RD_EN;
429 /* 3 clock cycles to fetch the packet length from RAM. */
430 delay( 5 );
431
432 do
433 {
434 cnt = USB_RXPLEN;
435 } while ((cnt & PKT_DV) == 0);
436 cnt &= PKT_LNGTH_MASK;
437
438 for (n = 0; n < (cnt + 3) / 4; n++)
439 {
440 *((uint32_t __attribute__((packed)) *)pData) = USB_RXDATA;
441 pData += 4;
442 }
443
444 USB_CTRL = 0;
445
446 if ((EPNum & 0x80) != 0x04)
447 { /* Non-Isochronous Endpoint */
448 WrCmdEP(EPNum, CMD_CLR_BUF);
449 }
450
451 return (cnt);
452 }
453
454
455 /*
456 * Write USB Endpoint Data
457 * Parameters: EPNum: Endpoint Number
458 * EPNum.0..3: Address
459 * EPNum.7: Dir
460 * pData: Pointer to Data Buffer
461 * cnt: Number of bytes to write
462 * Return Value: Number of bytes written
463 */
464
465 uint32_t USB_WriteEP (uint32_t EPNum, uint8_t *pData, uint32_t cnt)
466 {
467 uint32_t n;
468
469 USB_CTRL = ((EPNum & 0x0F) << 2) | CTRL_WR_EN;
470 /* 3 clock cycles to fetch the packet length from RAM. */
471 delay( 5 );
472 USB_TXPLEN = cnt;
473
474 for (n = 0; n < (cnt + 3) / 4; n++)
475 {
476 USB_TXDATA = *((uint32_t __attribute__((packed)) *)pData);
477 pData += 4;
478 }
479
480 USB_CTRL = 0;
481
482 WrCmdEP(EPNum, CMD_VALID_BUF);
483
484 return (cnt);
485 }
486
487 /*
488 * Get USB Last Frame Number
489 * Parameters: None
490 * Return Value: Frame Number
491 */
492
493 uint32_t USB_GetFrame (void)
494 {
495 uint32_t val;
496
497 WrCmd(CMD_RD_FRAME);
498 val = RdCmdDat(DAT_RD_FRAME);
499 val = val | (RdCmdDat(DAT_RD_FRAME) << 8);
500
501 return (val);
502 }
503
504
505 /*
506 * USB Interrupt Service Routine
507 */
508
509 #ifdef CFG_USBCDC
510 void USB_IRQHandler (void)
511 {
512 uint32_t disr, val, n, m;
513
514 disr = USB_DEVINTST; /* Device Interrupt Status */
515 USB_DEVINTCLR = disr;
516
517 /* Device Status Interrupt (Reset, Connect change, Suspend/Resume) */
518 if (disr & DEV_STAT_INT)
519 {
520 WrCmd(CMD_GET_DEV_STAT);
521 val = RdCmdDat(DAT_GET_DEV_STAT); /* Device Status */
522 if (val & DEV_RST) { /* Reset */
523 USB_Reset();
524 #if USB_RESET_EVENT
525 USB_Reset_Event();
526 #endif
527 }
528 if (val & DEV_CON_CH) { /* Connect change */
529 #if USB_POWER_EVENT
530 USB_Power_Event(val & DEV_CON);
531 #endif
532 }
533 if (val & DEV_SUS_CH) { /* Suspend/Resume */
534 if (val & DEV_SUS) { /* Suspend */
535 USB_Suspend();
536 #if USB_SUSPEND_EVENT
537 USB_Suspend_Event();
538 #endif
539 } else { /* Resume */
540 USB_Resume();
541 #if USB_RESUME_EVENT
542 USB_Resume_Event();
543 #endif
544 }
545 }
546 goto isr_end;
547 }
548
549 #if USB_SOF_EVENT
550 /* Start of Frame Interrupt */
551 if (disr & FRAME_INT)
552 {
553 USB_DEVINTCLR = FRAME_INT;
554 USB_SOF_Event();
555 // SOFIRQCount++;
556 }
557 #endif
558
559 #if USB_ERROR_EVENT
560 /* NO error interrupt anymore, below code can be used
561 as example to get error status from command engine. */
562 /* Error Interrupt */
563 if (disr & ERR_INT)
564 {
565 WrCmd(CMD_RD_ERR_STAT);
566 val = RdCmdDat(DAT_RD_ERR_STAT);
567 USB_Error_Event(val);
568 }
569 #endif
570
571 /* Endpoint's Interrupt */
572 if (disr & (0xFF<<1)) {
573 /* if any of the EP0 through EP7 is set, or bit 1 through 9 on disr */
574 for (n = 0; n < USB_EP_NUM; n++) { /* Check All Endpoints */
575 /* skip frame interrupt at bit 0 in disr */
576 // if (disr & ((1 << n)<<1)) {
577 if ((disr>>1) & (1 << n)) {
578 m = n >> 1;
579 /* clear EP interrupt by sending cmd to the command engine. */
580 WrCmd(CMD_SEL_EP_CLRI(n));
581 val = RdCmdDat(DAT_SEL_EP_CLRI(n));
582 if ((n & 1) == 0) { /* OUT Endpoint */
583 if (n == 0) { /* Control OUT Endpoint */
584 if (val & EP_SEL_STP) { /* Setup Packet */
585 if (USB_P_EP[0]) {
586 USB_P_EP[0](USB_EVT_SETUP);
587 continue;
588 }
589 }
590 }
591 if (USB_P_EP[m]) {
592 USB_P_EP[m](USB_EVT_OUT);
593 }
594 } else { /* IN Endpoint */
595 if (USB_P_EP[m]) {
596 USB_P_EP[m](USB_EVT_IN);
597 }
598 }
599 }
600 }
601 }
602 isr_end:
603 return;
604 }
605
606 #endif
This page took 0.071361 seconds and 3 git commands to generate.