mirror of https://github.com/ARMmbed/mbed-os.git
				
				
				
			Add USBPhy for the LPC17xx
Move the LPC17xx USB driver files from mbed-os\features\unsupported\USBDevice\targets\TARGET_NXP and update them to match the new USBPhy API.pull/9768/head
							parent
							
								
									f9f12766d8
								
							
						
					
					
						commit
						4be11ff158
					
				| 
						 | 
					@ -0,0 +1,97 @@
 | 
				
			||||||
 | 
					/* mbed Microcontroller Library
 | 
				
			||||||
 | 
					 * Copyright (c) 2018-2018 ARM Limited
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Licensed under the Apache License, Version 2.0 (the "License");
 | 
				
			||||||
 | 
					 * you may not use this file except in compliance with the License.
 | 
				
			||||||
 | 
					 * You may obtain a copy of the License at
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *     http://www.apache.org/licenses/LICENSE-2.0
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Unless required by applicable law or agreed to in writing, software
 | 
				
			||||||
 | 
					 * distributed under the License is distributed on an "AS IS" BASIS,
 | 
				
			||||||
 | 
					 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
				
			||||||
 | 
					 * See the License for the specific language governing permissions and
 | 
				
			||||||
 | 
					 * limitations under the License.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define NUMBER_OF_LOGICAL_ENDPOINTS (16)
 | 
				
			||||||
 | 
					#define NUMBER_OF_PHYSICAL_ENDPOINTS (NUMBER_OF_LOGICAL_ENDPOINTS * 2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Define physical endpoint numbers */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*      Endpoint    No.     Type(s)       MaxPacket   DoubleBuffer  */
 | 
				
			||||||
 | 
					/*      ----------------    ------------  ----------  ---           */
 | 
				
			||||||
 | 
					#define EP0OUT      (0x00)  /* Control       64          No            */
 | 
				
			||||||
 | 
					#define EP0IN       (0x80)  /* Control       64          No            */
 | 
				
			||||||
 | 
					#define EP1OUT      (0x01)  /* Interrupt     64          No            */
 | 
				
			||||||
 | 
					#define EP1IN       (0x81)  /* Interrupt     64          No            */
 | 
				
			||||||
 | 
					#define EP2OUT      (0x02)  /* Bulk          64          Yes           */
 | 
				
			||||||
 | 
					#define EP2IN       (0x82)  /* Bulk          64          Yes           */
 | 
				
			||||||
 | 
					#define EP3OUT      (0x03)  /* Isochronous   1023        Yes           */
 | 
				
			||||||
 | 
					#define EP3IN       (0x83)  /* Isochronous   1023        Yes           */
 | 
				
			||||||
 | 
					#define EP4OUT      (0x04)  /* Interrupt     64          No            */
 | 
				
			||||||
 | 
					#define EP4IN       (0x84)  /* Interrupt     64          No            */
 | 
				
			||||||
 | 
					#define EP5OUT      (0x05)  /* Bulk          64          Yes           */
 | 
				
			||||||
 | 
					#define EP5IN       (0x85)  /* Bulk          64          Yes           */
 | 
				
			||||||
 | 
					#define EP6OUT      (0x06)  /* Isochronous   1023        Yes           */
 | 
				
			||||||
 | 
					#define EP6IN       (0x86)  /* Isochronous   1023        Yes           */
 | 
				
			||||||
 | 
					#define EP7OUT      (0x07)  /* Interrupt     64          No            */
 | 
				
			||||||
 | 
					#define EP7IN       (0x87)  /* Interrupt     64          No            */
 | 
				
			||||||
 | 
					#define EP8OUT      (0x08)  /* Bulk          64          Yes           */
 | 
				
			||||||
 | 
					#define EP8IN       (0x88)  /* Bulk          64          Yes           */
 | 
				
			||||||
 | 
					#define EP9OUT      (0x09)  /* Isochronous   1023        Yes           */
 | 
				
			||||||
 | 
					#define EP9IN       (0x89)  /* Isochronous   1023        Yes           */
 | 
				
			||||||
 | 
					#define EP10OUT     (0x0A)  /* Interrupt     64          No            */
 | 
				
			||||||
 | 
					#define EP10IN      (0x8A)  /* Interrupt     64          No            */
 | 
				
			||||||
 | 
					#define EP11OUT     (0x0B)  /* Bulk          64          Yes           */
 | 
				
			||||||
 | 
					#define EP11IN      (0x8B)  /* Bulk          64          Yes           */
 | 
				
			||||||
 | 
					#define EP12OUT     (0x0C)  /* Isochronous   1023        Yes           */
 | 
				
			||||||
 | 
					#define EP12IN      (0x8C)  /* Isochronous   1023        Yes           */
 | 
				
			||||||
 | 
					#define EP13OUT     (0x0D)  /* Interrupt     64          No            */
 | 
				
			||||||
 | 
					#define EP13IN      (0x8D)  /* Interrupt     64          No            */
 | 
				
			||||||
 | 
					#define EP14OUT     (0x0E)  /* Bulk          64          Yes           */
 | 
				
			||||||
 | 
					#define EP14IN      (0x8E)  /* Bulk          64          Yes           */
 | 
				
			||||||
 | 
					#define EP15OUT     (0x0F)  /* Bulk          64          Yes           */
 | 
				
			||||||
 | 
					#define EP15IN      (0x8F)  /* Bulk          64          Yes           */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Maximum Packet sizes */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define MAX_PACKET_SIZE_EP0  (64)
 | 
				
			||||||
 | 
					#define MAX_PACKET_SIZE_EP1  (64)
 | 
				
			||||||
 | 
					#define MAX_PACKET_SIZE_EP2  (64)
 | 
				
			||||||
 | 
					#define MAX_PACKET_SIZE_EP3  (1023)
 | 
				
			||||||
 | 
					#define MAX_PACKET_SIZE_EP4  (64)
 | 
				
			||||||
 | 
					#define MAX_PACKET_SIZE_EP5  (64)
 | 
				
			||||||
 | 
					#define MAX_PACKET_SIZE_EP6  (1023)
 | 
				
			||||||
 | 
					#define MAX_PACKET_SIZE_EP7  (64)
 | 
				
			||||||
 | 
					#define MAX_PACKET_SIZE_EP8  (64)
 | 
				
			||||||
 | 
					#define MAX_PACKET_SIZE_EP9  (1023)
 | 
				
			||||||
 | 
					#define MAX_PACKET_SIZE_EP10 (64)
 | 
				
			||||||
 | 
					#define MAX_PACKET_SIZE_EP11 (64)
 | 
				
			||||||
 | 
					#define MAX_PACKET_SIZE_EP12 (1023)
 | 
				
			||||||
 | 
					#define MAX_PACKET_SIZE_EP13 (64)
 | 
				
			||||||
 | 
					#define MAX_PACKET_SIZE_EP14 (64)
 | 
				
			||||||
 | 
					#define MAX_PACKET_SIZE_EP15 (64)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Generic endpoints - intended to be portable accross devices */
 | 
				
			||||||
 | 
					/* and be suitable for simple USB devices. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Bulk endpoints */
 | 
				
			||||||
 | 
					#define EPBULK_OUT  (EP2OUT)
 | 
				
			||||||
 | 
					#define EPBULK_IN   (EP2IN)
 | 
				
			||||||
 | 
					#define EPBULK_OUT_callback   EP2_OUT_callback
 | 
				
			||||||
 | 
					#define EPBULK_IN_callback    EP2_IN_callback
 | 
				
			||||||
 | 
					/* Interrupt endpoints */
 | 
				
			||||||
 | 
					#define EPINT_OUT   (EP1OUT)
 | 
				
			||||||
 | 
					#define EPINT_IN    (EP1IN)
 | 
				
			||||||
 | 
					#define EPINT_OUT_callback    EP1_OUT_callback
 | 
				
			||||||
 | 
					#define EPINT_IN_callback     EP1_IN_callback
 | 
				
			||||||
 | 
					/* Isochronous endpoints */
 | 
				
			||||||
 | 
					#define EPISO_OUT   (EP3OUT)
 | 
				
			||||||
 | 
					#define EPISO_IN    (EP3IN)
 | 
				
			||||||
 | 
					#define EPISO_OUT_callback    EP3_OUT_callback
 | 
				
			||||||
 | 
					#define EPISO_IN_callback     EP3_IN_callback
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define MAX_PACKET_SIZE_EPBULK  (MAX_PACKET_SIZE_EP2)
 | 
				
			||||||
 | 
					#define MAX_PACKET_SIZE_EPINT   (MAX_PACKET_SIZE_EP1)
 | 
				
			||||||
 | 
					#define MAX_PACKET_SIZE_EPISO   (MAX_PACKET_SIZE_EP3)
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,709 @@
 | 
				
			||||||
 | 
					/* mbed Microcontroller Library
 | 
				
			||||||
 | 
					 * Copyright (c) 2018-2018 ARM Limited
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Licensed under the Apache License, Version 2.0 (the "License");
 | 
				
			||||||
 | 
					 * you may not use this file except in compliance with the License.
 | 
				
			||||||
 | 
					 * You may obtain a copy of the License at
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *     http://www.apache.org/licenses/LICENSE-2.0
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Unless required by applicable law or agreed to in writing, software
 | 
				
			||||||
 | 
					 * distributed under the License is distributed on an "AS IS" BASIS,
 | 
				
			||||||
 | 
					 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
				
			||||||
 | 
					 * See the License for the specific language governing permissions and
 | 
				
			||||||
 | 
					 * limitations under the License.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if defined(DEVICE_USBDEVICE) && DEVICE_USBDEVICE && \
 | 
				
			||||||
 | 
					    (defined(TARGET_LPC1768) || defined(TARGET_LPC2368) || defined(TARGET_LPC2460))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "USBEndpoints_LPC17_LPC23.h"
 | 
				
			||||||
 | 
					#include "USBPhyHw.h"
 | 
				
			||||||
 | 
					#include "usb_phy_api.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Get endpoint direction
 | 
				
			||||||
 | 
					#define IN_EP(endpoint)     ((endpoint) & 1U ? true : false)
 | 
				
			||||||
 | 
					#define OUT_EP(endpoint)    ((endpoint) & 1U ? false : true)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Convert physical endpoint number to register bit
 | 
				
			||||||
 | 
					#define EP(endpoint) (1UL<<DESC_TO_PHY(endpoint))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define DESC_TO_PHY(endpoint) ((((endpoint)&0x0F)<<1) | (((endpoint) & 0x80) ? 1:0))
 | 
				
			||||||
 | 
					#define PHY_TO_DESC(endpoint) (((endpoint)>>1)|(((endpoint)&1)?0x80:0))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Power Control for Peripherals register
 | 
				
			||||||
 | 
					#define PCUSB      (1UL<<31)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// USB Clock Control register
 | 
				
			||||||
 | 
					#define DEV_CLK_EN (1UL<<1)
 | 
				
			||||||
 | 
					#define AHB_CLK_EN (1UL<<4)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// USB Clock Status register
 | 
				
			||||||
 | 
					#define DEV_CLK_ON (1UL<<1)
 | 
				
			||||||
 | 
					#define AHB_CLK_ON (1UL<<4)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// USB Device Interupt registers
 | 
				
			||||||
 | 
					#define FRAME      (1UL<<0)
 | 
				
			||||||
 | 
					#define EP_FAST    (1UL<<1)
 | 
				
			||||||
 | 
					#define EP_SLOW    (1UL<<2)
 | 
				
			||||||
 | 
					#define DEV_STAT   (1UL<<3)
 | 
				
			||||||
 | 
					#define CCEMPTY    (1UL<<4)
 | 
				
			||||||
 | 
					#define CDFULL     (1UL<<5)
 | 
				
			||||||
 | 
					#define RxENDPKT   (1UL<<6)
 | 
				
			||||||
 | 
					#define TxENDPKT   (1UL<<7)
 | 
				
			||||||
 | 
					#define EP_RLZED   (1UL<<8)
 | 
				
			||||||
 | 
					#define ERR_INT    (1UL<<9)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// USB Control register
 | 
				
			||||||
 | 
					#define RD_EN (1<<0)
 | 
				
			||||||
 | 
					#define WR_EN (1<<1)
 | 
				
			||||||
 | 
					#define LOG_ENDPOINT(endpoint) ((DESC_TO_PHY(endpoint)>>1)<<2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// USB Receive Packet Length register
 | 
				
			||||||
 | 
					#define DV      (1UL<<10)
 | 
				
			||||||
 | 
					#define PKT_RDY (1UL<<11)
 | 
				
			||||||
 | 
					#define PKT_LNGTH_MASK (0x3ff)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Serial Interface Engine (SIE)
 | 
				
			||||||
 | 
					#define SIE_WRITE   (0x01)
 | 
				
			||||||
 | 
					#define SIE_READ    (0x02)
 | 
				
			||||||
 | 
					#define SIE_COMMAND (0x05)
 | 
				
			||||||
 | 
					#define SIE_CMD_CODE(phase, data) ((phase<<8)|(data<<16))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// SIE Command codes
 | 
				
			||||||
 | 
					#define SIE_CMD_SET_ADDRESS        (0xD0)
 | 
				
			||||||
 | 
					#define SIE_CMD_CONFIGURE_DEVICE   (0xD8)
 | 
				
			||||||
 | 
					#define SIE_CMD_SET_MODE           (0xF3)
 | 
				
			||||||
 | 
					#define SIE_CMD_READ_FRAME_NUMBER  (0xF5)
 | 
				
			||||||
 | 
					#define SIE_CMD_READ_TEST_REGISTER (0xFD)
 | 
				
			||||||
 | 
					#define SIE_CMD_SET_DEVICE_STATUS  (0xFE)
 | 
				
			||||||
 | 
					#define SIE_CMD_GET_DEVICE_STATUS  (0xFE)
 | 
				
			||||||
 | 
					#define SIE_CMD_GET_ERROR_CODE     (0xFF)
 | 
				
			||||||
 | 
					#define SIE_CMD_READ_ERROR_STATUS  (0xFB)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define SIE_CMD_SELECT_ENDPOINT(endpoint)                 (0x00+DESC_TO_PHY(endpoint))
 | 
				
			||||||
 | 
					#define SIE_CMD_SELECT_ENDPOINT_CLEAR_INTERRUPT(endpoint) (0x40+DESC_TO_PHY(endpoint))
 | 
				
			||||||
 | 
					#define SIE_CMD_SET_ENDPOINT_STATUS(endpoint)             (0x40+DESC_TO_PHY(endpoint))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define SIE_CMD_CLEAR_BUFFER    (0xF2)
 | 
				
			||||||
 | 
					#define SIE_CMD_VALIDATE_BUFFER (0xFA)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// SIE Device Status register
 | 
				
			||||||
 | 
					#define SIE_DS_CON    (1<<0)
 | 
				
			||||||
 | 
					#define SIE_DS_CON_CH (1<<1)
 | 
				
			||||||
 | 
					#define SIE_DS_SUS    (1<<2)
 | 
				
			||||||
 | 
					#define SIE_DS_SUS_CH (1<<3)
 | 
				
			||||||
 | 
					#define SIE_DS_RST    (1<<4)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// SIE Device Set Address register
 | 
				
			||||||
 | 
					#define SIE_DSA_DEV_EN  (1<<7)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// SIE Configue Device register
 | 
				
			||||||
 | 
					#define SIE_CONF_DEVICE (1<<0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Select Endpoint register
 | 
				
			||||||
 | 
					#define SIE_SE_FE       (1<<0)
 | 
				
			||||||
 | 
					#define SIE_SE_ST       (1<<1)
 | 
				
			||||||
 | 
					#define SIE_SE_STP      (1<<2)
 | 
				
			||||||
 | 
					#define SIE_SE_PO       (1<<3)
 | 
				
			||||||
 | 
					#define SIE_SE_EPN      (1<<4)
 | 
				
			||||||
 | 
					#define SIE_SE_B_1_FULL (1<<5)
 | 
				
			||||||
 | 
					#define SIE_SE_B_2_FULL (1<<6)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Set Endpoint Status command
 | 
				
			||||||
 | 
					#define SIE_SES_ST      (1<<0)
 | 
				
			||||||
 | 
					#define SIE_SES_DA      (1<<5)
 | 
				
			||||||
 | 
					#define SIE_SES_RF_MO   (1<<6)
 | 
				
			||||||
 | 
					#define SIE_SES_CND_ST  (1<<7)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static USBPhyHw *instance;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static volatile int epComplete;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void SIECommand(uint32_t command)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    // The command phase of a SIE transaction
 | 
				
			||||||
 | 
					    LPC_USB->USBDevIntClr = CCEMPTY;
 | 
				
			||||||
 | 
					    LPC_USB->USBCmdCode = SIE_CMD_CODE(SIE_COMMAND, command);
 | 
				
			||||||
 | 
					    while (!(LPC_USB->USBDevIntSt & CCEMPTY));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void SIEWriteData(uint8_t data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    // The data write phase of a SIE transaction
 | 
				
			||||||
 | 
					    LPC_USB->USBDevIntClr = CCEMPTY;
 | 
				
			||||||
 | 
					    LPC_USB->USBCmdCode = SIE_CMD_CODE(SIE_WRITE, data);
 | 
				
			||||||
 | 
					    while (!(LPC_USB->USBDevIntSt & CCEMPTY));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static uint8_t SIEReadData(uint32_t command)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    // The data read phase of a SIE transaction
 | 
				
			||||||
 | 
					    LPC_USB->USBDevIntClr = CDFULL;
 | 
				
			||||||
 | 
					    LPC_USB->USBCmdCode = SIE_CMD_CODE(SIE_READ, command);
 | 
				
			||||||
 | 
					    while (!(LPC_USB->USBDevIntSt & CDFULL));
 | 
				
			||||||
 | 
					    return (uint8_t)LPC_USB->USBCmdData;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void SIEsetDeviceStatus(uint8_t status)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    // Write SIE device status register
 | 
				
			||||||
 | 
					    SIECommand(SIE_CMD_SET_DEVICE_STATUS);
 | 
				
			||||||
 | 
					    SIEWriteData(status);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static uint8_t SIEgetDeviceStatus(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    // Read SIE device status register
 | 
				
			||||||
 | 
					    SIECommand(SIE_CMD_GET_DEVICE_STATUS);
 | 
				
			||||||
 | 
					    return SIEReadData(SIE_CMD_GET_DEVICE_STATUS);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void SIEsetAddress(uint8_t address)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    // Write SIE device address register
 | 
				
			||||||
 | 
					    SIECommand(SIE_CMD_SET_ADDRESS);
 | 
				
			||||||
 | 
					    SIEWriteData((address & 0x7f) | SIE_DSA_DEV_EN);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static uint8_t SIEselectEndpoint(uint8_t endpoint)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    // SIE select endpoint command
 | 
				
			||||||
 | 
					    SIECommand(SIE_CMD_SELECT_ENDPOINT(endpoint));
 | 
				
			||||||
 | 
					    return SIEReadData(SIE_CMD_SELECT_ENDPOINT(endpoint));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static uint8_t SIEclearBuffer(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    // SIE clear buffer command
 | 
				
			||||||
 | 
					    SIECommand(SIE_CMD_CLEAR_BUFFER);
 | 
				
			||||||
 | 
					    return SIEReadData(SIE_CMD_CLEAR_BUFFER);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void SIEvalidateBuffer(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    // SIE validate buffer command
 | 
				
			||||||
 | 
					    SIECommand(SIE_CMD_VALIDATE_BUFFER);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void SIEsetEndpointStatus(uint8_t endpoint, uint8_t status)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    // SIE set endpoint status command
 | 
				
			||||||
 | 
					    SIECommand(SIE_CMD_SET_ENDPOINT_STATUS(endpoint));
 | 
				
			||||||
 | 
					    SIEWriteData(status);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static uint16_t SIEgetFrameNumber(void) __attribute__((unused));
 | 
				
			||||||
 | 
					static uint16_t SIEgetFrameNumber(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    // Read current frame number
 | 
				
			||||||
 | 
					    uint16_t lowByte;
 | 
				
			||||||
 | 
					    uint16_t highByte;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    SIECommand(SIE_CMD_READ_FRAME_NUMBER);
 | 
				
			||||||
 | 
					    lowByte = SIEReadData(SIE_CMD_READ_FRAME_NUMBER);
 | 
				
			||||||
 | 
					    highByte = SIEReadData(SIE_CMD_READ_FRAME_NUMBER);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return (highByte << 8) | lowByte;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void SIEconfigureDevice(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    // SIE Configure device command
 | 
				
			||||||
 | 
					    SIECommand(SIE_CMD_CONFIGURE_DEVICE);
 | 
				
			||||||
 | 
					    SIEWriteData(SIE_CONF_DEVICE);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void SIEunconfigureDevice(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    // SIE Configure device command
 | 
				
			||||||
 | 
					    SIECommand(SIE_CMD_CONFIGURE_DEVICE);
 | 
				
			||||||
 | 
					    SIEWriteData(0);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void SIEconnect(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    // Connect USB device
 | 
				
			||||||
 | 
					    uint8_t status = SIEgetDeviceStatus();
 | 
				
			||||||
 | 
					    SIEsetDeviceStatus(status | SIE_DS_CON);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void SIEdisconnect(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    // Disconnect USB device
 | 
				
			||||||
 | 
					    uint8_t status = SIEgetDeviceStatus();
 | 
				
			||||||
 | 
					    SIEsetDeviceStatus(status & ~SIE_DS_CON);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static uint8_t selectEndpointClearInterrupt(uint8_t endpoint)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    // Implemented using using EP_INT_CLR.
 | 
				
			||||||
 | 
					    LPC_USB->USBEpIntClr = EP(endpoint);
 | 
				
			||||||
 | 
					    while (!(LPC_USB->USBDevIntSt & CDFULL));
 | 
				
			||||||
 | 
					    return (uint8_t)LPC_USB->USBCmdData;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void enableEndpointEvent(uint8_t endpoint)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    // Enable an endpoint interrupt
 | 
				
			||||||
 | 
					    LPC_USB->USBEpIntEn |= EP(endpoint);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void disableEndpointEvent(uint8_t endpoint) __attribute__((unused));
 | 
				
			||||||
 | 
					static void disableEndpointEvent(uint8_t endpoint)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    // Disable an endpoint interrupt
 | 
				
			||||||
 | 
					    LPC_USB->USBEpIntEn &= ~EP(endpoint);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static uint32_t endpointReadcore(uint8_t endpoint, uint8_t *buffer, uint32_t size)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    // Read from an OUT endpoint
 | 
				
			||||||
 | 
					    uint32_t actual_size;
 | 
				
			||||||
 | 
					    uint32_t i;
 | 
				
			||||||
 | 
					    uint32_t data = 0;
 | 
				
			||||||
 | 
					    uint8_t offset;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    LPC_USB->USBCtrl = LOG_ENDPOINT(endpoint) | RD_EN;
 | 
				
			||||||
 | 
					    while (!(LPC_USB->USBRxPLen & PKT_RDY));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    actual_size = LPC_USB->USBRxPLen & PKT_LNGTH_MASK;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    offset = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (actual_size > 0) {
 | 
				
			||||||
 | 
					        for (i = 0; i < actual_size; i++) {
 | 
				
			||||||
 | 
					            if (offset == 0) {
 | 
				
			||||||
 | 
					                // Fetch up to four bytes of data as a word
 | 
				
			||||||
 | 
					                data = LPC_USB->USBRxData;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // extract a byte
 | 
				
			||||||
 | 
					            if (size) {
 | 
				
			||||||
 | 
					                *buffer = (data >> offset) & 0xff;
 | 
				
			||||||
 | 
					                buffer++;
 | 
				
			||||||
 | 
					                size--;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // move on to the next byte
 | 
				
			||||||
 | 
					            offset = (offset + 8) % 32;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        (void)LPC_USB->USBRxData;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    LPC_USB->USBCtrl = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return actual_size;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void endpointWritecore(uint8_t endpoint, uint8_t *buffer, uint32_t size)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    // Write to an IN endpoint
 | 
				
			||||||
 | 
					    uint32_t temp, data;
 | 
				
			||||||
 | 
					    uint8_t offset;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    LPC_USB->USBCtrl = LOG_ENDPOINT(endpoint) | WR_EN;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    LPC_USB->USBTxPLen = size;
 | 
				
			||||||
 | 
					    offset = 0;
 | 
				
			||||||
 | 
					    data = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (size > 0) {
 | 
				
			||||||
 | 
					        do {
 | 
				
			||||||
 | 
					            // Fetch next data byte into a word-sized temporary variable
 | 
				
			||||||
 | 
					            temp = *buffer++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Add to current data word
 | 
				
			||||||
 | 
					            temp = temp << offset;
 | 
				
			||||||
 | 
					            data = data | temp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // move on to the next byte
 | 
				
			||||||
 | 
					            offset = (offset + 8) % 32;
 | 
				
			||||||
 | 
					            size--;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if ((offset == 0) || (size == 0)) {
 | 
				
			||||||
 | 
					                // Write the word to the endpoint
 | 
				
			||||||
 | 
					                LPC_USB->USBTxData = data;
 | 
				
			||||||
 | 
					                data = 0;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        } while (size > 0);
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        LPC_USB->USBTxData = 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Clear WR_EN to cover zero length packet case
 | 
				
			||||||
 | 
					    LPC_USB->USBCtrl = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    SIEselectEndpoint(endpoint);
 | 
				
			||||||
 | 
					    SIEvalidateBuffer();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					USBPhy *get_usb_phy()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    static USBPhyHw usbphy;
 | 
				
			||||||
 | 
					    return &usbphy;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					USBPhyHw::USBPhyHw(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					USBPhyHw::~USBPhyHw(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void USBPhyHw::init(USBPhyEvents *events)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    this->events = events;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Disable IRQ
 | 
				
			||||||
 | 
					    NVIC_DisableIRQ(USB_IRQn);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Enable power to USB device controller
 | 
				
			||||||
 | 
					    LPC_SC->PCONP |= PCUSB;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Enable USB clocks
 | 
				
			||||||
 | 
					    LPC_USB->USBClkCtrl |= DEV_CLK_EN | AHB_CLK_EN;
 | 
				
			||||||
 | 
					    while (LPC_USB->USBClkSt != (DEV_CLK_ON | AHB_CLK_ON));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Configure pins P0.29 and P0.30 to be USB D+ and USB D-
 | 
				
			||||||
 | 
					    LPC_PINCON->PINSEL1 &= 0xc3ffffff;
 | 
				
			||||||
 | 
					    LPC_PINCON->PINSEL1 |= 0x14000000;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Disconnect USB device
 | 
				
			||||||
 | 
					    SIEdisconnect();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Configure pin P2.9 to be Connect
 | 
				
			||||||
 | 
					    LPC_PINCON->PINSEL4 &= 0xfffcffff;
 | 
				
			||||||
 | 
					    LPC_PINCON->PINSEL4 |= 0x00040000;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Connect must be low for at least 2.5uS
 | 
				
			||||||
 | 
					    wait(0.3);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Set the maximum packet size for the control endpoints
 | 
				
			||||||
 | 
					    endpoint_add(EP0IN, MAX_PACKET_SIZE_EP0, USB_EP_TYPE_CTRL);
 | 
				
			||||||
 | 
					    endpoint_add(EP0OUT, MAX_PACKET_SIZE_EP0, USB_EP_TYPE_CTRL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Attach IRQ
 | 
				
			||||||
 | 
					    instance = this;
 | 
				
			||||||
 | 
					    NVIC_SetVector(USB_IRQn, (uint32_t)&_usbisr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Enable interrupts for device events and EP0
 | 
				
			||||||
 | 
					    LPC_USB->USBDevIntEn = EP_SLOW | DEV_STAT | FRAME;
 | 
				
			||||||
 | 
					    enableEndpointEvent(EP0IN);
 | 
				
			||||||
 | 
					    enableEndpointEvent(EP0OUT);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void USBPhyHw::deinit()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    // Ensure device disconnected
 | 
				
			||||||
 | 
					    SIEdisconnect();
 | 
				
			||||||
 | 
					    // Disable USB interrupts
 | 
				
			||||||
 | 
					    NVIC_DisableIRQ(USB_IRQn);
 | 
				
			||||||
 | 
					    events = NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool USBPhyHw::powered()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void USBPhyHw::connect(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    NVIC_EnableIRQ(USB_IRQn);
 | 
				
			||||||
 | 
					    // Connect USB device
 | 
				
			||||||
 | 
					    SIEconnect();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void USBPhyHw::disconnect(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    NVIC_DisableIRQ(USB_IRQn);
 | 
				
			||||||
 | 
					    // Disconnect USB device
 | 
				
			||||||
 | 
					    SIEdisconnect();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void USBPhyHw::configure(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    SIEconfigureDevice();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void USBPhyHw::unconfigure(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    SIEunconfigureDevice();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void USBPhyHw::sof_enable()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    //TODO
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void USBPhyHw::sof_disable()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    //TODO
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void USBPhyHw::set_address(uint8_t address)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    SIEsetAddress(address);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					uint32_t USBPhyHw::ep0_set_max_packet(uint32_t max_packet)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    return MAX_PACKET_SIZE_EP0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void USBPhyHw::ep0_setup_read_result(uint8_t *buffer, uint32_t size)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    endpointReadcore(EP0OUT, buffer, size);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void USBPhyHw::ep0_read(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    endpoint_read(EP0OUT, MAX_PACKET_SIZE_EP0);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					uint32_t USBPhyHw::ep0_read_result(uint8_t *buffer, uint32_t size)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    return endpointReadcore(EP0OUT, buffer, size);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void USBPhyHw::ep0_write(uint8_t *buffer, uint32_t size)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    endpointWritecore(EP0IN, buffer, size);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void USBPhyHw::ep0_stall(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    // This will stall both control endpoints
 | 
				
			||||||
 | 
					    endpoint_stall(EP0OUT);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool USBPhyHw::endpoint_read(usb_ep_t endpoint, uint32_t maximumSize)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    // Don't clear isochronous endpoints
 | 
				
			||||||
 | 
					    if ((DESC_TO_PHY(endpoint) >> 1) % 3 || (DESC_TO_PHY(endpoint) >> 1) == 0) {
 | 
				
			||||||
 | 
					        SIEselectEndpoint(endpoint);
 | 
				
			||||||
 | 
					        SIEclearBuffer();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool USBPhyHw::endpoint_read_result(usb_ep_t endpoint, uint8_t *buffer, uint32_t size, uint32_t *bytesRead)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    //for isochronous endpoint, we don't wait an interrupt
 | 
				
			||||||
 | 
					    if ((DESC_TO_PHY(endpoint) >> 1) % 3 || (DESC_TO_PHY(endpoint) >> 1) == 0) {
 | 
				
			||||||
 | 
					        if (!(epComplete & EP(endpoint))) {
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    *bytesRead = endpointReadcore(endpoint, buffer, size);
 | 
				
			||||||
 | 
					    epComplete &= ~EP(endpoint);
 | 
				
			||||||
 | 
					    return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool USBPhyHw::endpoint_write(usb_ep_t endpoint, uint8_t *data, uint32_t size)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    epComplete &= ~EP(endpoint);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    endpointWritecore(endpoint, data, size);
 | 
				
			||||||
 | 
					    return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void USBPhyHw::endpoint_abort(usb_ep_t endpoint)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    //TODO - needs to be implemented
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool USBPhyHw::endpoint_add(usb_ep_t endpoint, uint32_t maxPacket, usb_ep_type_t type)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    // Realise an endpoint
 | 
				
			||||||
 | 
					    LPC_USB->USBDevIntClr = EP_RLZED;
 | 
				
			||||||
 | 
					    LPC_USB->USBReEp |= EP(endpoint);
 | 
				
			||||||
 | 
					    LPC_USB->USBEpInd = DESC_TO_PHY(endpoint);
 | 
				
			||||||
 | 
					    LPC_USB->USBMaxPSize = maxPacket;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    while (!(LPC_USB->USBDevIntSt & EP_RLZED));
 | 
				
			||||||
 | 
					    LPC_USB->USBDevIntClr = EP_RLZED;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    enableEndpointEvent(endpoint);
 | 
				
			||||||
 | 
					    return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void USBPhyHw::endpoint_remove(usb_ep_t endpoint)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    // Unrealise an endpoint
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    disableEndpointEvent(endpoint);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    LPC_USB->USBDevIntClr = EP_RLZED;
 | 
				
			||||||
 | 
					    LPC_USB->USBReEp &= ~EP(endpoint);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    while (!(LPC_USB->USBDevIntSt & EP_RLZED));
 | 
				
			||||||
 | 
					    LPC_USB->USBDevIntClr = EP_RLZED;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void USBPhyHw::endpoint_stall(usb_ep_t endpoint)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    // Stall an endpoint
 | 
				
			||||||
 | 
					    if ((endpoint == EP0IN) || (endpoint == EP0OUT)) {
 | 
				
			||||||
 | 
					        // Conditionally stall both control endpoints
 | 
				
			||||||
 | 
					        SIEsetEndpointStatus(EP0OUT, SIE_SES_CND_ST);
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        SIEsetEndpointStatus(endpoint, SIE_SES_ST);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void USBPhyHw::endpoint_unstall(usb_ep_t endpoint)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    // Unstall an endpoint. The endpoint will also be reinitialised
 | 
				
			||||||
 | 
					    SIEsetEndpointStatus(endpoint, 0);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void USBPhyHw::remote_wakeup(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    // Remote wakeup
 | 
				
			||||||
 | 
					    uint8_t status;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Enable USB clocks
 | 
				
			||||||
 | 
					    LPC_USB->USBClkCtrl |= DEV_CLK_EN | AHB_CLK_EN;
 | 
				
			||||||
 | 
					    while (LPC_USB->USBClkSt != (DEV_CLK_ON | AHB_CLK_ON));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    status = SIEgetDeviceStatus();
 | 
				
			||||||
 | 
					    SIEsetDeviceStatus(status & ~SIE_DS_SUS);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const usb_ep_table_t *USBPhyHw::endpoint_table()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    static const usb_ep_table_t lpc_table = {
 | 
				
			||||||
 | 
					        4096 - 32 * 4, // 32 words for endpoint buffers
 | 
				
			||||||
 | 
					        // +3 based added to interrupt and isochronous to ensure enough
 | 
				
			||||||
 | 
					        // space for 4 byte alignment
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            {USB_EP_ATTR_ALLOW_CTRL | USB_EP_ATTR_DIR_IN_AND_OUT, 1, 0},
 | 
				
			||||||
 | 
					            {USB_EP_ATTR_ALLOW_INT | USB_EP_ATTR_DIR_IN_AND_OUT,  1, 3},
 | 
				
			||||||
 | 
					            {USB_EP_ATTR_ALLOW_BULK | USB_EP_ATTR_DIR_IN_AND_OUT, 2, 0},
 | 
				
			||||||
 | 
					            {USB_EP_ATTR_ALLOW_ISO | USB_EP_ATTR_DIR_IN_AND_OUT,  1, 3},
 | 
				
			||||||
 | 
					            {USB_EP_ATTR_ALLOW_INT | USB_EP_ATTR_DIR_IN_AND_OUT,  1, 3},
 | 
				
			||||||
 | 
					            {USB_EP_ATTR_ALLOW_BULK | USB_EP_ATTR_DIR_IN_AND_OUT, 2, 0},
 | 
				
			||||||
 | 
					            {USB_EP_ATTR_ALLOW_ISO | USB_EP_ATTR_DIR_IN_AND_OUT,  1, 3},
 | 
				
			||||||
 | 
					            {USB_EP_ATTR_ALLOW_INT | USB_EP_ATTR_DIR_IN_AND_OUT,  1, 3},
 | 
				
			||||||
 | 
					            {USB_EP_ATTR_ALLOW_BULK | USB_EP_ATTR_DIR_IN_AND_OUT, 2, 0},
 | 
				
			||||||
 | 
					            {USB_EP_ATTR_ALLOW_ISO | USB_EP_ATTR_DIR_IN_AND_OUT,  1, 3},
 | 
				
			||||||
 | 
					            {USB_EP_ATTR_ALLOW_INT | USB_EP_ATTR_DIR_IN_AND_OUT,  1, 3},
 | 
				
			||||||
 | 
					            {USB_EP_ATTR_ALLOW_BULK | USB_EP_ATTR_DIR_IN_AND_OUT, 2, 0},
 | 
				
			||||||
 | 
					            {USB_EP_ATTR_ALLOW_ISO | USB_EP_ATTR_DIR_IN_AND_OUT,  1, 3},
 | 
				
			||||||
 | 
					            {USB_EP_ATTR_ALLOW_INT | USB_EP_ATTR_DIR_IN_AND_OUT,  1, 3},
 | 
				
			||||||
 | 
					            {USB_EP_ATTR_ALLOW_BULK | USB_EP_ATTR_DIR_IN_AND_OUT, 2, 0},
 | 
				
			||||||
 | 
					            {USB_EP_ATTR_ALLOW_BULK | USB_EP_ATTR_DIR_IN_AND_OUT, 2, 0}
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    return &lpc_table;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void USBPhyHw::_usbisr(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    NVIC_DisableIRQ(USB_IRQn);
 | 
				
			||||||
 | 
					    instance->events->start_process();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void USBPhyHw::process(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    uint8_t devStat;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (LPC_USB->USBDevIntSt & FRAME) {
 | 
				
			||||||
 | 
					        // Start of frame event
 | 
				
			||||||
 | 
					        events->sof(SIEgetFrameNumber());
 | 
				
			||||||
 | 
					        // Clear interrupt status flag
 | 
				
			||||||
 | 
					        LPC_USB->USBDevIntClr = FRAME;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (LPC_USB->USBDevIntSt & DEV_STAT) {
 | 
				
			||||||
 | 
					        // Device Status interrupt
 | 
				
			||||||
 | 
					        // Must clear the interrupt status flag before reading the device status from the SIE
 | 
				
			||||||
 | 
					        LPC_USB->USBDevIntClr = DEV_STAT;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Read device status from SIE
 | 
				
			||||||
 | 
					        devStat = SIEgetDeviceStatus();
 | 
				
			||||||
 | 
					        //printf("devStat: %d\r\n", devStat);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (devStat & SIE_DS_SUS_CH) {
 | 
				
			||||||
 | 
					            // Suspend status changed
 | 
				
			||||||
 | 
					            if ((devStat & SIE_DS_SUS) != 0) {
 | 
				
			||||||
 | 
					                events->suspend(false);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (devStat & SIE_DS_RST) {
 | 
				
			||||||
 | 
					            // Bus reset
 | 
				
			||||||
 | 
					            if ((devStat & SIE_DS_SUS) == 0) {
 | 
				
			||||||
 | 
					                events->suspend(true);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            events->reset();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (LPC_USB->USBDevIntSt & EP_SLOW) {
 | 
				
			||||||
 | 
					        // (Slow) Endpoint Interrupt
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Process IN packets before SETUP packets
 | 
				
			||||||
 | 
					        // Note - order of OUT and SETUP does not matter as OUT packets
 | 
				
			||||||
 | 
					        //        are clobbered by SETUP packets and thus ignored.
 | 
				
			||||||
 | 
					        //
 | 
				
			||||||
 | 
					        // A SETUP packet can arrive at any time where as an IN packet is
 | 
				
			||||||
 | 
					        // only sent after calling EP0write and an OUT packet after EP0read.
 | 
				
			||||||
 | 
					        // The functions EP0write and EP0read are called only in response to
 | 
				
			||||||
 | 
					        // a setup packet or IN/OUT packets sent in response to that
 | 
				
			||||||
 | 
					        // setup packet. Therefore, if an IN or OUT packet is pending
 | 
				
			||||||
 | 
					        // at the same time as a SETUP packet, the IN or OUT packet belongs
 | 
				
			||||||
 | 
					        // to the previous control transfer and should either be processed
 | 
				
			||||||
 | 
					        // before the SETUP packet (in the case of IN) or dropped (in the
 | 
				
			||||||
 | 
					        // case of OUT as SETUP clobbers the OUT data).
 | 
				
			||||||
 | 
					        if (LPC_USB->USBEpIntSt & EP(EP0IN)) {
 | 
				
			||||||
 | 
					            selectEndpointClearInterrupt(EP0IN);
 | 
				
			||||||
 | 
					            LPC_USB->USBDevIntClr = EP_SLOW;
 | 
				
			||||||
 | 
					            events->ep0_in();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Process each endpoint interrupt
 | 
				
			||||||
 | 
					        if (LPC_USB->USBEpIntSt & EP(EP0OUT)) {
 | 
				
			||||||
 | 
					            if (selectEndpointClearInterrupt(EP0OUT) & SIE_SE_STP) {
 | 
				
			||||||
 | 
					                // this is a setup packet
 | 
				
			||||||
 | 
					                events->ep0_setup();
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                events->ep0_out();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            LPC_USB->USBDevIntClr = EP_SLOW;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        //TODO - should probably process in the reverse order
 | 
				
			||||||
 | 
					        for (uint8_t num = 2; num < 16 * 2; num++) {
 | 
				
			||||||
 | 
					            uint8_t endpoint = PHY_TO_DESC(num);
 | 
				
			||||||
 | 
					            if (LPC_USB->USBEpIntSt & EP(endpoint)) {
 | 
				
			||||||
 | 
					                selectEndpointClearInterrupt(endpoint);
 | 
				
			||||||
 | 
					                epComplete |= EP(endpoint);
 | 
				
			||||||
 | 
					                LPC_USB->USBDevIntClr = EP_SLOW;
 | 
				
			||||||
 | 
					                if (endpoint & 0x80) {//TODO - use macro
 | 
				
			||||||
 | 
					                    events->in(endpoint);
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    events->out(endpoint);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    NVIC_ClearPendingIRQ(USB_IRQn);
 | 
				
			||||||
 | 
					    NVIC_EnableIRQ(USB_IRQn);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,66 @@
 | 
				
			||||||
 | 
					/* mbed Microcontroller Library
 | 
				
			||||||
 | 
					 * Copyright (c) 2018-2018 ARM Limited
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Licensed under the Apache License, Version 2.0 (the "License");
 | 
				
			||||||
 | 
					 * you may not use this file except in compliance with the License.
 | 
				
			||||||
 | 
					 * You may obtain a copy of the License at
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *     http://www.apache.org/licenses/LICENSE-2.0
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Unless required by applicable law or agreed to in writing, software
 | 
				
			||||||
 | 
					 * distributed under the License is distributed on an "AS IS" BASIS,
 | 
				
			||||||
 | 
					 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
				
			||||||
 | 
					 * See the License for the specific language governing permissions and
 | 
				
			||||||
 | 
					 * limitations under the License.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef USBPHYHW_H
 | 
				
			||||||
 | 
					#define USBPHYHW_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "mbed.h"
 | 
				
			||||||
 | 
					#include "USBPhy.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class USBPhyHw : public USBPhy {
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
					    USBPhyHw();
 | 
				
			||||||
 | 
					    virtual ~USBPhyHw();
 | 
				
			||||||
 | 
					    virtual void init(USBPhyEvents *events);
 | 
				
			||||||
 | 
					    virtual void deinit();
 | 
				
			||||||
 | 
					    virtual bool powered();
 | 
				
			||||||
 | 
					    virtual void connect();
 | 
				
			||||||
 | 
					    virtual void disconnect();
 | 
				
			||||||
 | 
					    virtual void configure();
 | 
				
			||||||
 | 
					    virtual void unconfigure();
 | 
				
			||||||
 | 
					    virtual void sof_enable();
 | 
				
			||||||
 | 
					    virtual void sof_disable();
 | 
				
			||||||
 | 
					    virtual void set_address(uint8_t address);
 | 
				
			||||||
 | 
					    virtual void remote_wakeup();
 | 
				
			||||||
 | 
					    virtual const usb_ep_table_t *endpoint_table();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    virtual uint32_t ep0_set_max_packet(uint32_t max_packet);
 | 
				
			||||||
 | 
					    virtual void ep0_setup_read_result(uint8_t *buffer, uint32_t size);
 | 
				
			||||||
 | 
					    virtual void ep0_read(void);
 | 
				
			||||||
 | 
					    virtual uint32_t ep0_read_result(uint8_t *buffer, uint32_t size);
 | 
				
			||||||
 | 
					    virtual void ep0_write(uint8_t *buffer, uint32_t size);
 | 
				
			||||||
 | 
					    virtual void ep0_stall(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    virtual bool endpoint_add(usb_ep_t endpoint, uint32_t max_packet, usb_ep_type_t type);
 | 
				
			||||||
 | 
					    virtual void endpoint_remove(usb_ep_t endpoint);
 | 
				
			||||||
 | 
					    virtual void endpoint_stall(usb_ep_t endpoint);
 | 
				
			||||||
 | 
					    virtual void endpoint_unstall(usb_ep_t endpoint);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    virtual bool endpoint_read(usb_ep_t endpoint, uint32_t maximumSize);
 | 
				
			||||||
 | 
					    virtual bool endpoint_read_result(usb_ep_t endpoint, uint8_t *data, uint32_t size, uint32_t *bytesRead);
 | 
				
			||||||
 | 
					    virtual bool endpoint_write(usb_ep_t endpoint, uint8_t *data, uint32_t size);
 | 
				
			||||||
 | 
					    virtual void endpoint_abort(usb_ep_t endpoint);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    virtual void process();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
					    USBPhyEvents *events;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    static void _usbisr(void);
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					@ -600,7 +600,8 @@
 | 
				
			||||||
            "SPISLAVE",
 | 
					            "SPISLAVE",
 | 
				
			||||||
            "STDIO_MESSAGES",
 | 
					            "STDIO_MESSAGES",
 | 
				
			||||||
            "FLASH",
 | 
					            "FLASH",
 | 
				
			||||||
            "MPU"
 | 
					            "MPU",
 | 
				
			||||||
 | 
					            "USBDEVICE"
 | 
				
			||||||
        ],
 | 
					        ],
 | 
				
			||||||
        "release_versions": ["2", "5"],
 | 
					        "release_versions": ["2", "5"],
 | 
				
			||||||
        "device_name": "LPC1768",
 | 
					        "device_name": "LPC1768",
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue