1 /**********************************************************************
2 * $Id$ usbhw.c 2011-06-02
5 * @brief USB Hardware Layer Module for NXP's lpc43xx MCU
8 * @author NXP MCU SW Application Team
10 * Copyright(C) 2011, NXP Semiconductor
11 * All rights reserved.
13 ***********************************************************************
14 * Software that is described herein is for illustrative purposes only
15 * which provides customers with programming information regarding the
16 * products. This software is supplied "AS IS" without any warranties.
17 * NXP Semiconductors assumes no responsibility or liability for the
18 * use of the software, conveys no license or title under any patent,
19 * copyright, or mask work right to the product. NXP Semiconductors
20 * reserves the right to make changes in the software without
21 * notification. NXP Semiconductors also make no representation or
22 * warranty that such application will be suitable for the specified
23 * use without further testing or modification.
24 **********************************************************************/
26 #include "lpc18xx.H" /* lpc43xx definitions */
27 #include "lpc_types.h"
32 #include "lpc18xx_scu.h"
33 #include "lpc18xx_cgu.h"
36 #pragma diag_suppress 1441
40 #pragma data_alignment=2048
41 DQH_T ep_QH[EP_NUM_MAX];
42 #pragma data_alignment=32
43 DTD_T ep_TD[EP_NUM_MAX];
44 #pragma data_alignment=4
45 #elif defined ( __GNUC__ )
46 #define __align(x) __attribute__((aligned(x)))
47 DQH_T ep_QH[EP_NUM_MAX] __attribute__((aligned(2048)));
48 DTD_T ep_TD[EP_NUM_MAX] __attribute__((aligned(32)));
50 DQH_T __align(2048) ep_QH[EP_NUM_MAX];
51 DTD_T __align(32) ep_TD[EP_NUM_MAX];
55 static uint32_t ep_read_len[4];
56 volatile uint32_t DevStatusFS2HS = FALSE;
57 LPC_USBDRV_INIT_T g_drv;
60 * Get Endpoint Physical Address
61 * Parameters: EPNum: Endpoint Number
64 * Return Value: Endpoint Physical Address
67 uint32_t EPAdr (uint32_t EPNum) {
70 val = (EPNum & 0x0F) << 1;
78 * USB Initialize Function
79 * Called by the User to initialize USB
83 void USB_Init (LPC_USBDRV_INIT_T* cbs)
85 memcpy(&g_drv, cbs, sizeof(LPC_USBDRV_INIT_T));
86 /*maxp for EP0 should be atleast 8 */
87 if( g_drv.ep0_maxp == 0)
91 scu_pinmux(0x8,1,MD_PLN_FAST,FUNC1); // 0: motocon pcap0_1 1: usb0 usb0_ind1 2: nc 3: gpio4 gpio4_1
92 scu_pinmux(0x8,2,MD_PLN_FAST,FUNC1); // 0: motocon pcap0_0 1: usb0 usb0_ind0 2: nc 3: gpio4 gpio4_2
96 CGU_EnableEntity(CGU_CLKSRC_PLL0, ENABLE);
97 CGU_EntityConnect(CGU_CLKSRC_PLL0, CGU_BASE_USB0);
100 CGU_EnableEntity(CGU_CLKSRC_PLL1, ENABLE);
101 CGU_EntityConnect(CGU_CLKSRC_PLL1, CGU_BASE_USB1);
\r
103 LPC_CREG->CREG0 &= ~(1 << 5);
104 /* enable USB1_DP and USB1_DN on chip FS phy */
105 LPC_SCU->SFSUSB = 0x12;
106 /* enable USB1_VBUS */
107 scu_pinmux(0x2, 5, MD_PLN | MD_EZI | MD_ZI, FUNC2);
110 /* Turn on the phy */
112 LPC_CREG->CREG0 &= ~(1<<5);
114 /* reset the controller */
115 LPC_USB->USBCMD_D = USBCMD_RST;
116 /* wait for reset to complete */
117 while (LPC_USB->USBCMD_D & USBCMD_RST);
119 /* Program the controller to be the USB device controller */
120 LPC_USB->USBMODE_D = USBMODE_CM_DEV
124 /* set OTG transcever in proper state, device is present
125 on the port(CCS=1), port enable/disable status change(PES=1). */
127 LPC_USB->OTGSC = (1<<3) | (1<<0) /*| (1<<16)| (1<<24)| (1<<25)| (1<<26)| (1<<27)| (1<<28)| (1<<29)| (1<<30)*/;
129 /* force full speed */
130 LPC_USB->PORTSC1_D |= (1<<24);
134 NVIC_EnableIRQ(USB0_IRQn); // enable USB0 interrrupts
135 NVIC_SetPriority(USB0_IRQn, configMAX_SYSCALL_INTERRUPT_PRIORITY );
137 NVIC_EnableIRQ(USB1_IRQn); // enable USB1 interrrupts
138 NVIC_SetPriority(USB0_IRQn, configMAX_SYSCALL_INTERRUPT_PRIORITY );
147 * USB Connect Function
148 * Called by the User to Connect/Disconnect USB
149 * Parameters: con: Connect/Disconnect
152 void USB_Connect (uint32_t con) {
154 LPC_USB->USBCMD_D |= USBCMD_RS;
156 LPC_USB->USBCMD_D &= ~USBCMD_RS;
162 * Called automatically on USB Reset
166 void USB_Reset (void)
170 DevStatusFS2HS = FALSE;
171 /* disable all EPs */
172 LPC_USB->ENDPTCTRL0 &= ~(EPCTRL_RXE | EPCTRL_TXE);
173 LPC_USB->ENDPTCTRL2 &= ~(EPCTRL_RXE | EPCTRL_TXE);
174 LPC_USB->ENDPTCTRL3 &= ~(EPCTRL_RXE | EPCTRL_TXE);
176 /* Clear all pending interrupts */
177 LPC_USB->ENDPTNAK = 0xFFFFFFFF;
178 LPC_USB->ENDPTNAKEN = 0;
179 LPC_USB->USBSTS_D = 0xFFFFFFFF;
180 LPC_USB->ENDPTSETUPSTAT = LPC_USB->ENDPTSETUPSTAT;
181 LPC_USB->ENDPTCOMPLETE = LPC_USB->ENDPTCOMPLETE;
182 while (LPC_USB->ENDPTPRIME) /* Wait until all bits are 0 */
185 LPC_USB->ENDPTFLUSH = 0xFFFFFFFF;
186 while (LPC_USB->ENDPTFLUSH); /* Wait until all bits are 0 */
189 /* Set the interrupt Threshold control interval to 0 */
190 LPC_USB->USBCMD_D &= ~0x00FF0000;
192 /* Zero out the Endpoint queue heads */
193 memset((void*)ep_QH, 0, EP_NUM_MAX * sizeof(DQH_T));
194 /* Zero out the device transfer descriptors */
195 memset((void*)ep_TD, 0, EP_NUM_MAX * sizeof(DTD_T));
196 memset((void*)ep_read_len, 0, sizeof(ep_read_len));
197 /* Configure the Endpoint List Address */
198 /* make sure it in on 64 byte boundary !!! */
199 /* init list address */
200 LPC_USB->ENDPOINTLISTADDR = (uint32_t)ep_QH;
201 /* Initialize device queue heads for non ISO endpoint only */
202 for (i = 0; i < EP_NUM_MAX; i++)
204 ep_QH[i].next_dTD = (uint32_t)&ep_TD[i];
206 /* Enable interrupts */
207 LPC_USB->USBINTR_D = USBSTS_UI
213 // LPC_USB->usbintr |= (0x1<<7); /* Test SOF */
214 /* enable ep0 IN and ep0 OUT */
215 ep_QH[0].cap = QH_MAXP(g_drv.ep0_maxp)
218 ep_QH[1].cap = QH_MAXP(g_drv.ep0_maxp)
222 LPC_USB->ENDPTCTRL0 = EPCTRL_RXE | EPCTRL_RXR | EPCTRL_TXE | EPCTRL_TXR;
229 * USB Suspend Function
230 * Called automatically on USB Suspend
234 void USB_Suspend (void) {
235 /* Performed by Hardware */
240 * USB Resume Function
241 * Called automatically on USB Resume
245 void USB_Resume (void) {
246 /* Performed by Hardware */
251 * USB Remote Wakeup Function
252 * Called automatically on USB Remote Wakeup
256 void USB_WakeUp (void) {
258 //if (USB_DeviceStatus & USB_GETSTATUS_REMOTE_WAKEUP)
260 /* Set FPR bit in PORTSCX reg p63 */
261 LPC_USB->PORTSC1_D |= USBPRTS_FPR ;
267 * USB Remote Wakeup Configuration Function
268 * Parameters: cfg: Enable/Disable
272 void USB_WakeUpCfg (uint32_t cfg) {
279 * USB Set Address Function
280 * Parameters: adr: USB Address
284 void USB_SetAddress (uint32_t adr) {
285 LPC_USB->DEVICEADDR = USBDEV_ADDR(adr);
286 LPC_USB->DEVICEADDR |= USBDEV_ADDR_AD;
290 * USB set test mode Function
291 * Parameters: mode: test mode
292 * Return Value: TRUE if supported else FALSE
295 uint32_t USB_SetTestMode(uint8_t mode)
299 if ((mode > 0) && (mode < 8))
301 portsc = LPC_USB->PORTSC1_D & ~(0xF << 16);
303 LPC_USB->PORTSC1_D = portsc | (mode << 16);
310 * USB Configure Function
311 * Parameters: cfg: Configure/Deconfigure
315 void USB_Configure (uint32_t cfg) {
321 * Configure USB Endpoint according to Descriptor
322 * Parameters: pEPD: Pointer to Endpoint Descriptor
326 void USB_ConfigEP (USB_ENDPOINT_DESCRIPTOR *pEPD) {
329 uint8_t bmAttributes;
331 lep = pEPD->bEndpointAddress & 0x7F;
332 num = EPAdr(pEPD->bEndpointAddress);
334 ep_cfg = ((uint32_t*)&(LPC_USB->ENDPTCTRL0))[lep];
335 /* mask the attributes we are not-intersetd in */
336 bmAttributes = pEPD->bmAttributes & USB_ENDPOINT_TYPE_MASK;
338 if (bmAttributes != USB_ENDPOINT_TYPE_ISOCHRONOUS)
340 /* init EP capabilities */
341 ep_QH[num].cap = QH_MAXP(pEPD->wMaxPacketSize)
343 /* The next DTD pointer is INVALID */
344 ep_TD[num].next_dTD = 0x01 ;
348 /* init EP capabilities */
349 ep_QH[num].cap = QH_MAXP(0x400) | QH_ZLT;
351 /* setup EP control register */
352 if (pEPD->bEndpointAddress & 0x80)
354 ep_cfg &= ~0xFFFF0000;
355 ep_cfg |= EPCTRL_TX_TYPE(bmAttributes)
361 ep_cfg |= EPCTRL_RX_TYPE(bmAttributes)
364 ((uint32_t*)&(LPC_USB->ENDPTCTRL0))[lep] = ep_cfg;
369 * Set Direction for USB Control Endpoint
370 * Parameters: dir: Out (dir == 0), In (dir <> 0)
374 void USB_DirCtrlEP (uint32_t dir) {
381 * Enable USB Endpoint
382 * Parameters: EPNum: Endpoint Number
383 * EPNum.0..3: Address
388 void USB_EnableEP (uint32_t EPNum) {
389 uint32_t lep, bitpos;
395 ((uint32_t*)&(LPC_USB->ENDPTCTRL0))[lep] |= EPCTRL_TXE;
399 ((uint32_t*)&(LPC_USB->ENDPTCTRL0))[lep] |= EPCTRL_RXE;
400 /* enable NAK interrupt */
401 bitpos = USB_EP_BITPOS(EPNum);
402 LPC_USB->ENDPTNAKEN |= (1<<bitpos);
407 * Disable USB Endpoint
408 * Parameters: EPNum: Endpoint Number
409 * EPNum.0..3: Address
414 void USB_DisableEP (uint32_t EPNum) {
415 uint32_t lep, bitpos;
420 ((uint32_t*)&(LPC_USB->ENDPTCTRL0))[lep] &= ~EPCTRL_TXE;
424 /* disable NAK interrupt */
425 bitpos = USB_EP_BITPOS(EPNum);
426 LPC_USB->ENDPTNAKEN &= ~(1<<bitpos);
427 ((uint32_t*)&(LPC_USB->ENDPTCTRL0))[lep] &= ~EPCTRL_RXE;
433 * Parameters: EPNum: Endpoint Number
434 * EPNum.0..3: Address
439 void USB_ResetEP (uint32_t EPNum) {
440 uint32_t bit_pos = USB_EP_BITPOS(EPNum);
441 uint32_t lep = EPNum & 0x0F;
443 /* flush EP buffers */
444 LPC_USB->ENDPTFLUSH = (1<<bit_pos);
445 while (LPC_USB->ENDPTFLUSH & (1<<bit_pos));
446 /* reset data toggles */
449 ((uint32_t*)&(LPC_USB->ENDPTCTRL0))[lep] |= EPCTRL_TXR;
453 ((uint32_t*)&(LPC_USB->ENDPTCTRL0))[lep] |= EPCTRL_RXR;
458 * Set Stall for USB Endpoint
459 * Parameters: EPNum: Endpoint Number
460 * EPNum.0..3: Address
465 void USB_SetStallEP (uint32_t EPNum) {
471 ((uint32_t*)&(LPC_USB->ENDPTCTRL0))[lep] |= EPCTRL_TXS;
475 ((uint32_t*)&(LPC_USB->ENDPTCTRL0))[lep] |= EPCTRL_RXS;
480 * Clear Stall for USB Endpoint
481 * Parameters: EPNum: Endpoint Number
482 * EPNum.0..3: Address
487 void USB_ClrStallEP (uint32_t EPNum) {
493 ((uint32_t*)&(LPC_USB->ENDPTCTRL0))[lep] &= ~EPCTRL_TXS;
494 /* reset data toggle */
495 ((uint32_t*)&(LPC_USB->ENDPTCTRL0))[lep] |= EPCTRL_TXR;
499 ((uint32_t*)&(LPC_USB->ENDPTCTRL0))[lep] &= ~EPCTRL_RXS;
500 /* reset data toggle */
501 ((uint32_t*)&(LPC_USB->ENDPTCTRL0))[lep] |= EPCTRL_RXR;
507 * Parameters: EPNum: Endpoint Number
508 * EPNum.0..3: Address
511 * Transfer buffer size
514 void USB_ProgDTD(uint32_t Edpt, uint32_t ptrBuff, uint32_t TsfSize)
518 pDTD = (DTD_T*)&ep_TD[ Edpt ];
520 /* Zero out the device transfer descriptors */
521 memset((void*)pDTD, 0, sizeof(DTD_T));
522 /* The next DTD pointer is INVALID */
523 pDTD->next_dTD = 0x01 ;
526 pDTD->total_bytes = ((TsfSize & 0x7fff) << 16);
527 pDTD->total_bytes |= TD_IOC ;
528 pDTD->total_bytes |= 0x80 ;
530 pDTD->buffer0 = ptrBuff;
531 pDTD->buffer1 = (ptrBuff + 0x1000) & 0xfffff000;
532 pDTD->buffer2 = (ptrBuff + 0x2000) & 0xfffff000;
533 pDTD->buffer3 = (ptrBuff + 0x3000) & 0xfffff000;
534 pDTD->buffer4 = (ptrBuff + 0x4000) & 0xfffff000;
536 ep_QH[Edpt].next_dTD = (uint32_t)(&ep_TD[ Edpt ]);
537 ep_QH[Edpt].total_bytes &= (~0xC0) ;
541 * Read USB Endpoint Data
542 * Parameters: EPNum: Endpoint Number
543 * EPNum.0..3: Address
545 * pData: Pointer to Data Buffer
546 * Return Value: Number of bytes read
548 uint32_t USB_ReadSetupPkt(uint32_t EPNum, uint32_t *pData)
550 uint32_t setup_int, cnt = 0;
551 uint32_t num = EPAdr(EPNum);
553 setup_int = LPC_USB->ENDPTSETUPSTAT ;
554 /* Clear the setup interrupt */
555 LPC_USB->ENDPTSETUPSTAT = setup_int;
557 /* ********************************** */
558 /* Check if we have received a setup */
559 /* ********************************** */
560 if (setup_int & (1<<0)) /* Check only for bit 0 */
561 /* No setup are admitted on other endpoints than 0 */
565 /* Setup in a setup - must considere only the second setup */
566 /*- Set the tripwire */
567 LPC_USB->USBCMD_D |= USBCMD_SUTW ;
569 /* Transfer Set-up data to the gtmudsCore_Request buffer */
570 pData[0] = ep_QH[num].setup[0];
571 pData[1] = ep_QH[num].setup[1];
575 while (!(LPC_USB->USBCMD_D & USBCMD_SUTW)) ;
577 /* setup in a setup - Clear the tripwire */
578 LPC_USB->USBCMD_D &= (~USBCMD_SUTW);
580 while ((setup_int = LPC_USB->ENDPTSETUPSTAT) != 0)
582 /* Clear the setup interrupt */
583 LPC_USB->ENDPTSETUPSTAT = setup_int;
590 * Parameters: EPNum: Endpoint Number
591 * EPNum.0..3: Address
593 * pData: Pointer to Data Buffer
594 * Return Value: Number of bytes read
597 uint32_t USB_ReadReqEP(uint32_t EPNum, uint8_t *pData, uint32_t len)
599 uint32_t num = EPAdr(EPNum);
600 uint32_t n = USB_EP_BITPOS(EPNum);
602 USB_ProgDTD(num, (uint32_t)pData, len);
603 ep_read_len[EPNum & 0x0F] = len;
604 /* prime the endpoint for read */
605 LPC_USB->ENDPTPRIME |= (1<<n);
609 * Read USB Endpoint Data
610 * Parameters: EPNum: Endpoint Number
611 * EPNum.0..3: Address
613 * pData: Pointer to Data Buffer
614 * Return Value: Number of bytes read
617 uint32_t USB_ReadEP(uint32_t EPNum, uint8_t *pData)
625 pDTD = (DTD_T*)&ep_TD[n];
627 /* return the total bytes read */
628 cnt = (pDTD->total_bytes >> 16) & 0x7FFF;
629 cnt = ep_read_len[EPNum & 0x0F] - cnt;
634 * Write USB Endpoint Data
635 * Parameters: EPNum: Endpoint Number
636 * EPNum.0..3: Address
638 * pData: Pointer to Data Buffer
639 * cnt: Number of bytes to write
640 * Return Value: Number of bytes written
642 uint32_t USB_WriteEP(uint32_t EPNum, uint8_t *pData, uint32_t cnt)
644 uint32_t x = 0, n = USB_EP_BITPOS(EPNum);
646 USB_ProgDTD(EPAdr(EPNum), (uint32_t)pData, cnt);
647 /* prime the endpoint for transmit */
648 LPC_USB->ENDPTPRIME |= (1<<n);
649 /* check if priming succeeded */
650 while ((LPC_USB->ENDPTPRIME & (1<<n))&&(++x<0xffff));/*_RB_ Fix for hang here. */
655 * USB Interrupt Service Routine
658 void USB0_IRQHandler (void)
660 void USB1_IRQHandler (void)
663 uint32_t disr, val, n;
665 disr = LPC_USB->USBSTS_D; /* Device Interrupt Status */
666 LPC_USB->USBSTS_D = disr;
668 // printf("USB interrupt: 0x%08x\n",disr);
670 // LPC_UART1->THR = 'U';
671 // LPC_UART1->THR = 'S';
672 // LPC_UART1->THR = 'B';
673 // LPC_UART1->THR = '\n';
676 /* Device Status Interrupt (Reset, Connect change, Suspend/Resume) */
677 if (disr & USBSTS_URI) /* Reset */
679 // LPC_UART1->THR = 'R';
680 // LPC_UART1->THR = '\n';
682 if (g_drv.USB_Reset_Event)
683 g_drv.USB_Reset_Event();
688 if (disr & USBSTS_SLI) /* Suspend */
690 // LPC_UART1->THR = 'U';
691 // LPC_UART1->THR = '\n';
692 if (g_drv.USB_Suspend_Event)
693 g_drv.USB_Suspend_Event();
696 if (disr & USBSTS_PCI) /* Resume */
698 // LPC_UART1->THR = 'P';
699 // LPC_UART1->THR = '\n';
700 /* check if device isoperating in HS mode or full speed */
701 if (LPC_USB->PORTSC1_D & (1<<9))
702 DevStatusFS2HS = TRUE;
704 if (g_drv.USB_Resume_Event)
705 g_drv.USB_Resume_Event();
708 /* handle setup status interrupts */
709 val = LPC_USB->ENDPTSETUPSTAT;
710 /* Only EP0 will have setup packets so call EP0 handler */
713 // LPC_UART1->THR = 'S';
714 // LPC_UART1->THR = '\n';
715 /* Clear the endpoint complete CTRL OUT & IN when */
716 /* a Setup is received */
717 LPC_USB->ENDPTCOMPLETE = 0x00010001;
718 /* enable NAK inetrrupts */
719 LPC_USB->ENDPTNAKEN |= 0x00010001;
720 if (g_drv.USB_P_EP[0]){
721 // LPC_UART1->THR = 's';
722 // LPC_UART1->THR = '\n';
723 g_drv.USB_P_EP[0](USB_EVT_SETUP);
727 /* handle completion interrupts */
728 val = LPC_USB->ENDPTCOMPLETE;
731 // LPC_UART1->THR = 'C';
732 // LPC_UART1->THR = '\n';
734 LPC_USB->ENDPTNAK = val;
735 for (n = 0; n < EP_NUM_MAX / 2; n++)
739 if (g_drv.USB_P_EP[n])
740 g_drv.USB_P_EP[n](USB_EVT_OUT);
742 LPC_USB->ENDPTCOMPLETE = (1<<n);
744 if (val & (1<<(n + 16)))
746 ep_TD [(n << 1) + 1 ].total_bytes &= 0xC0;
747 if (g_drv.USB_P_EP[n])
748 g_drv.USB_P_EP[n](USB_EVT_IN);
749 LPC_USB->ENDPTCOMPLETE = (1<<(n + 16));
754 if (disr & USBSTS_NAKI)
756 // LPC_UART1->THR = 'N';
757 // LPC_UART1->THR = '\n';
758 val = LPC_USB->ENDPTNAK;
759 val &= LPC_USB->ENDPTNAKEN;
760 /* handle NAK interrupts */
763 for (n = 0; n < EP_NUM_MAX / 2; n++)
767 if (g_drv.USB_P_EP[n])
768 g_drv.USB_P_EP[n](USB_EVT_OUT_NAK);
770 if (val & (1<<(n + 16)))
772 if (g_drv.USB_P_EP[n])
773 g_drv.USB_P_EP[n](USB_EVT_IN_NAK);
776 LPC_USB->ENDPTNAK = val;
780 /* Start of Frame Interrupt */
781 if (disr & USBSTS_SRI)
783 // LPC_UART1->THR = 'F';
784 // LPC_UART1->THR = '\n';
785 if (g_drv.USB_SOF_Event)
786 g_drv.USB_SOF_Event();
789 /* Error Interrupt */
790 if (disr & USBSTS_UEI)
792 // LPC_UART1->THR = 'E';
793 // LPC_UART1->THR = '\n';
794 if (g_drv.USB_Error_Event)
795 g_drv.USB_Error_Event(disr);
798 // LPC_UART1->THR = 'r';
799 // LPC_UART1->THR = '\n';
801 // LPC_VIC->VectAddr = 0; /* Acknowledge Interrupt */