From 585fdf70d85a059a26f914761593066953e8899d Mon Sep 17 00:00:00 2001 From: petekol Date: Tue, 29 Sep 2015 17:23:17 +0200 Subject: [PATCH 01/14] CONFIG_ARCH_CHIP_LPC4370FET100 --- arch/arm/include/lpc43xx/chip.h | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/arch/arm/include/lpc43xx/chip.h b/arch/arm/include/lpc43xx/chip.h index 390f96bd6c9..7c02b7b16cc 100644 --- a/arch/arm/include/lpc43xx/chip.h +++ b/arch/arm/include/lpc43xx/chip.h @@ -46,7 +46,7 @@ * Pre-processor Definitions ************************************************************************************/ -/* Per the data sheet: LPC4350/30/20/10 Rev. 3.2 — 4 June 2012 */ +/* Per the data sheet: LPC4350/30/20/10 Rev. 3.2 � 4 June 2012 */ /* Get customizations for each supported chip. * * SRAM Resources @@ -74,7 +74,7 @@ * manager. This gives some symmetry to all of the members of the family. */ -/* Per the user manual: UM10503, Rev. 1.2 — 8 June 2012 */ +/* Per the user manual: UM10503, Rev. 1.2 � 8 June 2012 */ /* Get customizations for each supported chip. * * SRAM Resources @@ -538,6 +538,31 @@ # define LPC43_NDAC (1) /* One 10-bit DAC */ # define LPC43_NADC (2) /* Two 10-bit ADC controllers */ # define LPC43_NADC_CHANNELS (8) /* Eight ADC channels */ +#elif defined(CONFIG_ARCH_CHIP_LPC4370FET100) +# define LPC43_FLASH_BANKA_SIZE (0) /* Flashless */ +# define LPC43_FLASH_BANKB_SIZE (0) +# define LPC43_LOCSRAM_BANK0_SIZE (128*1024) /* 200Kb Local SRAM*/ +# define LPC43_LOCSRAM_BANK1_SIZE (72*1024) +# define LPC43_AHBSRAM_BANK0_SIZE (48*1024) /* 64Kb AHB SRAM */ +# define LPC43_AHBSRAM_BANK1_SIZE (0) +# define LPC43_AHBSRAM_BANK2_SIZE (16*1024) +# define LPC43_EEPROM_SIZE (0) /* No EEPROM */ +# undef LPC43_NLCD /* No LCD controller */ +# define LPC43_ETHERNET (1) /* One Ethernet controller */ +# define LPC43_USB0 (1) /* Have USB0 (Host, Device, OTG) */ +# define LPC43_USB1 (1) /* Have USB1 (Host, Device) */ +# undef LPC43_USB1_ULPI /* No USB1 (Host, Device) with ULPI I/F */ +# undef LPC43_MCPWM /* No PWM capability */ +# undef LPC43_QEI /* No Quadrature Encoder capability */ +# define LPC43_NUSARTS (4) /* Three USARTs + 1 UART */ +# define LPC43_NSSP (2) /* Two SSP controllers */ +# define LPC43_NTIMERS (4) /* Four Timers */ +# define LPC43_NI2C (2) /* Two I2C controllers */ +# define LPC43_NI2S (2) /* Two I2S controllers */ +# define LPC43_NCAN (2) /* Two CAN controllers */ +# define LPC43_NDAC (1) /* One 10-bit DAC */ +# define LPC43_NADC (2) /* Two 10-bit ADC controllers */ +# define LPC43_NADC_CHANNELS (4) /* Four ADC channels */ #else # error "Unsupported LPC43xx chip" #endif From 0eb1afcdef4a9f339ad01e6803c33d212e1e2307 Mon Sep 17 00:00:00 2001 From: petekol Date: Wed, 30 Sep 2015 17:13:32 +0200 Subject: [PATCH 02/14] usb reset right --- arch/arm/include/lpc43xx/chip.h | 2 +- arch/arm/src/lpc43xx/lpc43_cgu.c | 2 +- arch/arm/src/lpc43xx/lpc43_usb0dev.c | 4 +--- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/arch/arm/include/lpc43xx/chip.h b/arch/arm/include/lpc43xx/chip.h index 7c02b7b16cc..80faf49bc3e 100644 --- a/arch/arm/include/lpc43xx/chip.h +++ b/arch/arm/include/lpc43xx/chip.h @@ -46,7 +46,7 @@ * Pre-processor Definitions ************************************************************************************/ -/* Per the data sheet: LPC4350/30/20/10 Rev. 3.2 � 4 June 2012 */ +/* Per the data sheet: LPC4350/30/20/10 Rev. 3.2 4 June 2012 */ /* Get customizations for each supported chip. * * SRAM Resources diff --git a/arch/arm/src/lpc43xx/lpc43_cgu.c b/arch/arm/src/lpc43xx/lpc43_cgu.c index a50f5e93fa7..6b13ee4fd73 100644 --- a/arch/arm/src/lpc43xx/lpc43_cgu.c +++ b/arch/arm/src/lpc43xx/lpc43_cgu.c @@ -461,7 +461,7 @@ void lpc43_pll0usbenable(void) * operation and will make the lock signal high once it has regained * lock on the input clock * - * Wait for PLL1 to report that it is locked. + * Wait for PLL0 to report that it is locked. */ while ((getreg32(LPC43_PLL0USB_STAT) & PLL0USB_STAT_LOCK) == 0); diff --git a/arch/arm/src/lpc43xx/lpc43_usb0dev.c b/arch/arm/src/lpc43xx/lpc43_usb0dev.c index 0f09d91c28f..2498862e0b3 100644 --- a/arch/arm/src/lpc43xx/lpc43_usb0dev.c +++ b/arch/arm/src/lpc43xx/lpc43_usb0dev.c @@ -2667,9 +2667,7 @@ void up_usbinitialize(void) /* Reset USB block */ - regval = lpc43_getreg(LPC43_RGU_CTRL0); - regval |= RGU_CTRL0_USB0_RST; - lpc43_putreg(regval, LPC43_RGU_CTRL0); + lpc43_putreg(RGU_CTRL0_USB0_RST, LPC43_RGU_CTRL0); /* Reset the controller */ From 9dcff018bcdeabd8c77700eea1a1d858f004726c Mon Sep 17 00:00:00 2001 From: admin Date: Wed, 30 Sep 2015 22:05:53 +0200 Subject: [PATCH 03/14] strange hang reg read --- arch/arm/src/lpc43xx/lpc43_usb0dev.c | 5699 +++++++++++++------------- 1 file changed, 2849 insertions(+), 2850 deletions(-) diff --git a/arch/arm/src/lpc43xx/lpc43_usb0dev.c b/arch/arm/src/lpc43xx/lpc43_usb0dev.c index 2498862e0b3..e5975fc04cb 100644 --- a/arch/arm/src/lpc43xx/lpc43_usb0dev.c +++ b/arch/arm/src/lpc43xx/lpc43_usb0dev.c @@ -1,2850 +1,2849 @@ -/******************************************************************************* - * arch/arm/src/lpc43xx/lpc43_usbdev.c - * - * Copyright (C) 2012-2013 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * Part of the NuttX OS and based, in part, on the LPC31xx USB driver: - * - * Authors: David Hewson - * Gregory Nutt - * - * Which, in turn, was based on the LPC2148 USB driver: - * - * Copyright (C) 2010-2012 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - *******************************************************************************/ - -/******************************************************************************* - * Included Files - *******************************************************************************/ - -#include - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include - -#include "chip.h" -#include "up_arch.h" -#include "up_internal.h" - -#include "lpc43_usb0dev.h" -#include "lpc43_creg.h" -#include "lpc43_ccu.h" -#include "lpc43_cgu.h" -#include "lpc43_rgu.h" - -/******************************************************************************* - * Pre-processor Definitions - *******************************************************************************/ - -/* Configuration ***************************************************************/ - -#ifndef CONFIG_USBDEV_EP0_MAXSIZE -# define CONFIG_USBDEV_EP0_MAXSIZE 64 -#endif - -#ifndef CONFIG_USBDEV_MAXPOWER -# define CONFIG_USBDEV_MAXPOWER 100 /* mA */ -#endif - -/* Extremely detailed register debug that you would normally never want - * enabled. - */ - -#undef CONFIG_LPC43_USBDEV_REGDEBUG - -/* Enable reading SOF from interrupt handler vs. simply reading on demand. Probably - * a bad idea... Unless there is some issue with sampling the SOF from hardware - * asynchronously. - */ - -#ifdef CONFIG_LPC43_USBDEV_FRAME_INTERRUPT -# define USB_FRAME_INT USBDEV_USBINTR_SRE -#else -# define USB_FRAME_INT 0 -#endif - -#ifdef CONFIG_DEBUG -# define USB_ERROR_INT USBDEV_USBINTR_UEE -#else -# define USB_ERROR_INT 0 -#endif - -/* Debug ***********************************************************************/ - -/* Trace error codes */ - -#define LPC43_TRACEERR_ALLOCFAIL 0x0001 -#define LPC43_TRACEERR_BADCLEARFEATURE 0x0002 -#define LPC43_TRACEERR_BADDEVGETSTATUS 0x0003 -#define LPC43_TRACEERR_BADEPNO 0x0004 -#define LPC43_TRACEERR_BADEPGETSTATUS 0x0005 -#define LPC43_TRACEERR_BADEPTYPE 0x0006 -#define LPC43_TRACEERR_BADGETCONFIG 0x0007 -#define LPC43_TRACEERR_BADGETSETDESC 0x0008 -#define LPC43_TRACEERR_BADGETSTATUS 0x0009 -#define LPC43_TRACEERR_BADSETADDRESS 0x000a -#define LPC43_TRACEERR_BADSETCONFIG 0x000b -#define LPC43_TRACEERR_BADSETFEATURE 0x000c -#define LPC43_TRACEERR_BINDFAILED 0x000d -#define LPC43_TRACEERR_DISPATCHSTALL 0x000e -#define LPC43_TRACEERR_DRIVER 0x000f -#define LPC43_TRACEERR_DRIVERREGISTERED 0x0010 -#define LPC43_TRACEERR_EP0SETUPSTALLED 0x0011 -#define LPC43_TRACEERR_EPINNULLPACKET 0x0012 -#define LPC43_TRACEERR_EPOUTNULLPACKET 0x0013 -#define LPC43_TRACEERR_INVALIDCTRLREQ 0x0014 -#define LPC43_TRACEERR_INVALIDPARMS 0x0015 -#define LPC43_TRACEERR_IRQREGISTRATION 0x0016 -#define LPC43_TRACEERR_NOEP 0x0017 -#define LPC43_TRACEERR_NOTCONFIGURED 0x0018 -#define LPC43_TRACEERR_REQABORTED 0x0019 - -/* Trace interrupt codes */ - -#define LPC43_TRACEINTID_USB 0x0001 -#define LPC43_TRACEINTID_CLEARFEATURE 0x0002 -#define LPC43_TRACEINTID_DEVGETSTATUS 0x0003 -#define LPC43_TRACEINTID_DEVRESET 0x0004 -#define LPC43_TRACEINTID_DISPATCH 0x0005 -#define LPC43_TRACEINTID_EP0COMPLETE 0x0006 -#define LPC43_TRACEINTID_EP0NAK 0x0007 -#define LPC43_TRACEINTID_EP0SETUP 0x0008 -#define LPC43_TRACEINTID_EPGETSTATUS 0x0009 -#define LPC43_TRACEINTID_EPIN 0x000a -#define LPC43_TRACEINTID_EPINQEMPTY 0x000b -#define LPC43_TRACEINTID_EP0INSETADDRESS 0x000c -#define LPC43_TRACEINTID_EPOUT 0x000d -#define LPC43_TRACEINTID_EPOUTQEMPTY 0x000e -#define LPC43_TRACEINTID_EP0SETUPSETADDRESS 0x000f -#define LPC43_TRACEINTID_FRAME 0x0010 -#define LPC43_TRACEINTID_GETCONFIG 0x0011 -#define LPC43_TRACEINTID_GETSETDESC 0x0012 -#define LPC43_TRACEINTID_GETSETIF 0x0013 -#define LPC43_TRACEINTID_GETSTATUS 0x0014 -#define LPC43_TRACEINTID_IFGETSTATUS 0x0015 -#define LPC43_TRACEINTID_SETCONFIG 0x0016 -#define LPC43_TRACEINTID_SETFEATURE 0x0017 -#define LPC43_TRACEINTID_SUSPENDED 0x0018 -#define LPC43_TRACEINTID_RESUMED 0x0019 -#define LPC43_TRACEINTID_SYNCHFRAME 0x001a - -/* Hardware interface **********************************************************/ - -/* This represents a Endpoint Transfer Descriptor - note these must be 32 byte - * aligned. - */ - -struct lpc43_dtd_s -{ - volatile uint32_t nextdesc; /* Address of the next DMA descripto in RAM */ - volatile uint32_t config; /* Misc. bit encoded configuration information */ - uint32_t buffer0; /* Buffer start address */ - uint32_t buffer1; /* Buffer start address */ - uint32_t buffer2; /* Buffer start address */ - uint32_t buffer3; /* Buffer start address */ - uint32_t buffer4; /* Buffer start address */ - uint32_t xfer_len; /* Software only - transfer len that was queued */ -}; - -/* DTD nextdesc field */ - -#define DTD_NEXTDESC_INVALID (1 << 0) /* Bit 0 : Next Descriptor Invalid */ - -/* DTD config field */ - -#define DTD_CONFIG_LENGTH(n) ((n) << 16) /* Bits 16-31 : Total bytes to transfer */ -#define DTD_CONFIG_IOC (1 << 15) /* Bit 15 : Interrupt on Completion */ -#define DTD_CONFIG_MULT_VARIABLE (0 << 10) /* Bits 10-11 : Number of packets executed per transacation descriptor (override) */ -#define DTD_CONFIG_MULT_NUM(n) ((n) << 10) -#define DTD_CONFIG_ACTIVE (1 << 7) /* Bit 7 : Status Active */ -#define DTD_CONFIG_HALTED (1 << 6) /* Bit 6 : Status Halted */ -#define DTD_CONFIG_BUFFER_ERROR (1 << 5) /* Bit 6 : Status Buffer Error */ -#define DTD_CONFIG_TRANSACTION_ERROR (1 << 3) /* Bit 3 : Status Transaction Error */ - -/* This represents a queue head - not these must be aligned to a 2048 byte boundary */ - -struct lpc43_dqh_s -{ - uint32_t capability; /* Endpoint capability */ - uint32_t currdesc; /* Current dTD pointer */ - struct lpc43_dtd_s overlay; /* DTD overlay */ - volatile uint32_t setup[2]; /* Set-up buffer */ - uint32_t gap[4]; /* align to 64 bytes */ -}; - -/* DQH capability field */ - -#define DQH_CAPABILITY_MULT_VARIABLE (0 << 30) /* Bits 30-31 : Number of packets executed per transaction descriptor */ -#define DQH_CAPABILITY_MULT_NUM(n) ((n) << 30) -#define DQH_CAPABILITY_ZLT (1 << 29) /* Bit 29 : Zero Length Termination Select */ -#define DQH_CAPABILITY_MAX_PACKET(n) ((n) << 16) /* Bits 16-29 : Maximum packet size of associated endpoint (<1024) */ -#define DQH_CAPABILITY_IOS (1 << 15) /* Bit 15 : Interrupt on Setup */ - -/* Endpoints ******************************************************************/ - -/* Number of endpoints */ - -#define LPC43_NLOGENDPOINTS (4) /* ep0-3 */ -#define LPC43_NPHYSENDPOINTS (8) /* x2 for IN and OUT */ - -/* Odd physical endpoint numbers are IN; even are OUT */ - -#define LPC43_EPPHYIN(epphy) (((epphy)&1)!=0) -#define LPC43_EPPHYOUT(epphy) (((epphy)&1)==0) - -#define LPC43_EPPHYIN2LOG(epphy) (((uint8_t)(epphy)>>1)|USB_DIR_IN) -#define LPC43_EPPHYOUT2LOG(epphy) (((uint8_t)(epphy)>>1)|USB_DIR_OUT) - -/* Endpoint 0 is special... */ - -#define LPC43_EP0_OUT (0) -#define LPC43_EP0_IN (1) - -/* Each endpoint has somewhat different characteristics */ - -#define LPC43_EPALLSET (0xff) /* All endpoints */ -#define LPC43_EPOUTSET (0x55) /* Even phy endpoint numbers are OUT EPs */ -#define LPC43_EPINSET (0xaa) /* Odd endpoint numbers are IN EPs */ -#define LPC43_EPCTRLSET (0x03) /* EP0 IN/OUT are control endpoints */ -#define LPC43_EPINTRSET (0xa8) /* Interrupt endpoints */ -#define LPC43_EPBULKSET (0xfc) /* Bulk endpoints */ -#define LPC43_EPISOCSET (0xfc) /* Isochronous endpoints */ - -/* Maximum packet sizes for endpoints */ - -#define LPC43_EP0MAXPACKET (64) /* EP0 max packet size (1-64) */ -#define LPC43_BULKMAXPACKET (512) /* Bulk endpoint max packet (8/16/32/64/512) */ -#define LPC43_INTRMAXPACKET (1024) /* Interrupt endpoint max packet (1 to 1024) */ -#define LPC43_ISOCMAXPACKET (512) /* Acutally 1..1023 */ - -/* Endpoint bit position in SETUPSTAT, PRIME, FLUSH, STAT, COMPLETE registers */ - -#define LPC43_ENDPTSHIFT(epphy) (LPC43_EPPHYIN(epphy) ? (16 + ((epphy) >> 1)) : ((epphy) >> 1)) -#define LPC43_ENDPTMASK(epphy) (1 << LPC43_ENDPTSHIFT(epphy)) -#define LPC43_ENDPTMASK_ALL 0x000f000f - -/* Request queue operations ****************************************************/ - -#define lpc43_rqempty(ep) ((ep)->head == NULL) -#define lpc43_rqpeek(ep) ((ep)->head) - -/******************************************************************************* - * Private Types - *******************************************************************************/ - -/* A container for a request so that the request may be retained in a list */ - -struct lpc43_req_s -{ - struct usbdev_req_s req; /* Standard USB request */ - struct lpc43_req_s *flink; /* Supports a singly linked list */ -}; - -/* This is the internal representation of an endpoint */ - -struct lpc43_ep_s -{ - /* Common endpoint fields. This must be the first thing defined in the - * structure so that it is possible to simply cast from struct usbdev_ep_s - * to struct lpc43_ep_s. - */ - - struct usbdev_ep_s ep; /* Standard endpoint structure */ - - /* LPC43XX-specific fields */ - - struct lpc43_usbdev_s *dev; /* Reference to private driver data */ - struct lpc43_req_s *head; /* Request list for this endpoint */ - struct lpc43_req_s *tail; - uint8_t epphy; /* Physical EP address */ - uint8_t stalled:1; /* 1: Endpoint is stalled */ -}; - -/* This structure retains the state of the USB device controller */ - -struct lpc43_usbdev_s -{ - /* Common device fields. This must be the first thing defined in the - * structure so that it is possible to simply cast from struct usbdev_s - * to struct lpc43_usbdev_s. - */ - - struct usbdev_s usbdev; - - /* The bound device class driver */ - - struct usbdevclass_driver_s *driver; - - /* LPC43XX-specific fields */ - - uint8_t ep0state; /* State of certain EP0 operations */ - uint8_t ep0buf[64]; /* buffer for EP0 short transfers */ - uint8_t paddr; /* Address assigned by SETADDRESS */ - uint8_t stalled:1; /* 1: Protocol stalled */ - uint8_t selfpowered:1; /* 1: Device is self powered */ - uint8_t paddrset:1; /* 1: Peripheral addr has been set */ - uint8_t attached:1; /* 1: Host attached */ - uint8_t suspended:1; /* 1: Suspended */ - uint32_t softprio; /* Bitset of high priority interrupts */ - uint32_t epavail; /* Bitset of available endpoints */ -#ifdef CONFIG_LPC43_USBDEV_FRAME_INTERRUPT - uint32_t sof; /* Last start-of-frame */ -#endif - - /* The endpoint list */ - - struct lpc43_ep_s eplist[LPC43_NPHYSENDPOINTS]; -}; - -#define EP0STATE_IDLE 0 /* Idle State, leave on receiving a setup packet or epsubmit */ -#define EP0STATE_SETUP_OUT 1 /* Setup Packet received - SET/CLEAR */ -#define EP0STATE_SETUP_IN 2 /* Setup Packet received - GET */ -#define EP0STATE_SHORTWRITE 3 /* Short write without a usb_request */ -#define EP0STATE_WAIT_NAK_OUT 4 /* Waiting for Host to illicit status phase (GET) */ -#define EP0STATE_WAIT_NAK_IN 5 /* Waiting for Host to illicit status phase (SET/CLEAR) */ -#define EP0STATE_WAIT_STATUS_OUT 6 /* Wait for status phase to complete */ -#define EP0STATE_WAIT_STATUS_IN 7 /* Wait for status phase to complete */ -#define EP0STATE_DATA_IN 8 -#define EP0STATE_DATA_OUT 9 - -/******************************************************************************* - * Private Function Prototypes - *******************************************************************************/ - -/* Register operations ********************************************************/ - -#if defined(CONFIG_LPC43_USBDEV_REGDEBUG) && defined(CONFIG_DEBUG) -static uint32_t lpc43_getreg(uint32_t addr); -static void lpc43_putreg(uint32_t val, uint32_t addr); -#else -# define lpc43_getreg(addr) getreg32(addr) -# define lpc43_putreg(val,addr) putreg32(val,addr) -#endif - -static inline void lpc43_clrbits(uint32_t mask, uint32_t addr); -static inline void lpc43_setbits(uint32_t mask, uint32_t addr); -static inline void lpc43_chgbits(uint32_t mask, uint32_t val, uint32_t addr); - -/* Request queue operations ****************************************************/ - -static FAR struct lpc43_req_s *lpc43_rqdequeue(FAR struct lpc43_ep_s *privep); -static bool lpc43_rqenqueue(FAR struct lpc43_ep_s *privep, - FAR struct lpc43_req_s *req); - -/* Low level data transfers and request operations *****************************/ - -static inline void lpc43_writedtd(struct lpc43_dtd_s *dtd, const uint8_t *data, - uint32_t nbytes); -static inline void lpc43_queuedtd(uint8_t epphy, struct lpc43_dtd_s *dtd); -static inline void lpc43_ep0xfer(uint8_t epphy, uint8_t *data, uint32_t nbytes); -static void lpc43_readsetup(uint8_t epphy, struct usb_ctrlreq_s *ctrl); - -static inline void lpc43_set_address(struct lpc43_usbdev_s *priv, uint16_t address); - -static void lpc43_flushep(struct lpc43_ep_s *privep); - -static int lpc43_progressep(struct lpc43_ep_s *privep); -static inline void lpc43_abortrequest(struct lpc43_ep_s *privep, - struct lpc43_req_s *privreq, int16_t result); -static void lpc43_reqcomplete(struct lpc43_ep_s *privep, - struct lpc43_req_s *privreq, int16_t result); - -static void lpc43_cancelrequests(struct lpc43_ep_s *privep, int16_t status); - -/* Interrupt handling **********************************************************/ - -static struct lpc43_ep_s *lpc43_epfindbyaddr(struct lpc43_usbdev_s *priv, - uint16_t eplog); -static void lpc43_dispatchrequest(struct lpc43_usbdev_s *priv, - const struct usb_ctrlreq_s *ctrl); -static void lpc43_ep0configure(struct lpc43_usbdev_s *priv); -static void lpc43_usbreset(struct lpc43_usbdev_s *priv); - -static inline void lpc43_ep0state(struct lpc43_usbdev_s *priv, uint16_t state); -static void lpc43_ep0setup(struct lpc43_usbdev_s *priv); - -static void lpc43_ep0complete(struct lpc43_usbdev_s *priv, uint8_t epphy); -static void lpc43_ep0nak(struct lpc43_usbdev_s *priv, uint8_t epphy); -static bool lpc43_epcomplete(struct lpc43_usbdev_s *priv, uint8_t epphy); - -static int lpc43_usbinterrupt(int irq, FAR void *context); - -/* Endpoint operations *********************************************************/ - -/* USB device controller operations ********************************************/ - -static int lpc43_epconfigure(FAR struct usbdev_ep_s *ep, - const struct usb_epdesc_s *desc, bool last); -static int lpc43_epdisable(FAR struct usbdev_ep_s *ep); -static FAR struct usbdev_req_s *lpc43_epallocreq(FAR struct usbdev_ep_s *ep); -static void lpc43_epfreereq(FAR struct usbdev_ep_s *ep, - FAR struct usbdev_req_s *); -#ifdef CONFIG_USBDEV_DMA -static void *lpc43_epallocbuffer(FAR struct usbdev_ep_s *ep, unsigned bytes); -static void lpc43_epfreebuffer(FAR struct usbdev_ep_s *ep, FAR void *buf); -#endif -static int lpc43_epsubmit(FAR struct usbdev_ep_s *ep, - struct usbdev_req_s *req); -static int lpc43_epcancel(FAR struct usbdev_ep_s *ep, - struct usbdev_req_s *req); -static int lpc43_epstall(FAR struct usbdev_ep_s *ep, bool resume); - -static FAR struct usbdev_ep_s *lpc43_allocep(FAR struct usbdev_s *dev, - uint8_t epno, bool in, uint8_t eptype); -static void lpc43_freeep(FAR struct usbdev_s *dev, FAR struct usbdev_ep_s *ep); -static int lpc43_getframe(struct usbdev_s *dev); -static int lpc43_wakeup(struct usbdev_s *dev); -static int lpc43_selfpowered(struct usbdev_s *dev, bool selfpowered); -static int lpc43_pullup(struct usbdev_s *dev, bool enable); - -/******************************************************************************* - * Private Data - *******************************************************************************/ - -/* Since there is only a single USB interface, all status information can be - * be simply retained in a single global instance. - */ - -static struct lpc43_usbdev_s g_usbdev; - -static struct lpc43_dqh_s __attribute__((aligned(2048))) g_qh[LPC43_NPHYSENDPOINTS]; -static struct lpc43_dtd_s __attribute__((aligned(32))) g_td[LPC43_NPHYSENDPOINTS]; - -static const struct usbdev_epops_s g_epops = -{ - .configure = lpc43_epconfigure, - .disable = lpc43_epdisable, - .allocreq = lpc43_epallocreq, - .freereq = lpc43_epfreereq, -#ifdef CONFIG_USBDEV_DMA - .allocbuffer = lpc43_epallocbuffer, - .freebuffer = lpc43_epfreebuffer, -#endif - .submit = lpc43_epsubmit, - .cancel = lpc43_epcancel, - .stall = lpc43_epstall, -}; - -static const struct usbdev_ops_s g_devops = -{ - .allocep = lpc43_allocep, - .freeep = lpc43_freeep, - .getframe = lpc43_getframe, - .wakeup = lpc43_wakeup, - .selfpowered = lpc43_selfpowered, - .pullup = lpc43_pullup, -}; - -/******************************************************************************* - * Public Data - *******************************************************************************/ - -/******************************************************************************* - * Private Functions - *******************************************************************************/ - -/******************************************************************************* - * Name: lpc43_getreg - * - * Description: - * Get the contents of an LPC433x register - * - *******************************************************************************/ - -#if defined(CONFIG_LPC43_USBDEV_REGDEBUG) && defined(CONFIG_DEBUG) -static uint32_t lpc43_getreg(uint32_t addr) -{ - static uint32_t prevaddr = 0; - static uint32_t preval = 0; - static uint32_t count = 0; - - /* Read the value from the register */ - - uint32_t val = getreg32(addr); - - /* Is this the same value that we read from the same registe last time? Are - * we polling the register? If so, suppress some of the output. - */ - - if (addr == prevaddr && val == preval) - { - if (count == 0xffffffff || ++count > 3) - { - if (count == 4) - { - lldbg("...\n"); - } - return val; - } - } - - /* No this is a new address or value */ - - else - { - /* Did we print "..." for the previous value? */ - - if (count > 3) - { - /* Yes.. then show how many times the value repeated */ - - lldbg("[repeats %d more times]\n", count-3); - } - - /* Save the new address, value, and count */ - - prevaddr = addr; - preval = val; - count = 1; - } - - /* Show the register value read */ - - lldbg("%08x->%08x\n", addr, val); - return val; -} -#endif - -/******************************************************************************* - * Name: lpc43_putreg - * - * Description: - * Set the contents of an LPC433x register to a value - * - *******************************************************************************/ - -#if defined(CONFIG_LPC43_USBDEV_REGDEBUG) && defined(CONFIG_DEBUG) -static void lpc43_putreg(uint32_t val, uint32_t addr) -{ - /* Show the register value being written */ - - lldbg("%08x<-%08x\n", addr, val); - - /* Write the value */ - - putreg32(val, addr); -} -#endif - -/******************************************************************************* - * Name: lpc43_clrbits - * - * Description: - * Clear bits in a register - * - *******************************************************************************/ - -static inline void lpc43_clrbits(uint32_t mask, uint32_t addr) -{ - uint32_t reg = lpc43_getreg(addr); - reg &= ~mask; - lpc43_putreg(reg, addr); -} - -/******************************************************************************* - * Name: lpc43_setbits - * - * Description: - * Set bits in a register - * - *******************************************************************************/ - -static inline void lpc43_setbits(uint32_t mask, uint32_t addr) -{ - uint32_t reg = lpc43_getreg(addr); - reg |= mask; - lpc43_putreg(reg, addr); -} - -/******************************************************************************* - * Name: lpc43_chgbits - * - * Description: - * Change bits in a register - * - *******************************************************************************/ - -static inline void lpc43_chgbits(uint32_t mask, uint32_t val, uint32_t addr) -{ - uint32_t reg = lpc43_getreg(addr); - reg &= ~mask; - reg |= val; - lpc43_putreg(reg, addr); -} - -/******************************************************************************* - * Name: lpc43_rqdequeue - * - * Description: - * Remove a request from an endpoint request queue - * - *******************************************************************************/ - -static FAR struct lpc43_req_s *lpc43_rqdequeue(FAR struct lpc43_ep_s *privep) -{ - FAR struct lpc43_req_s *ret = privep->head; - - if (ret) - { - privep->head = ret->flink; - if (!privep->head) - { - privep->tail = NULL; - } - - ret->flink = NULL; - } - - return ret; -} - -/******************************************************************************* - * Name: lpc43_rqenqueue - * - * Description: - * Add a request from an endpoint request queue - * - *******************************************************************************/ - -static bool lpc43_rqenqueue(FAR struct lpc43_ep_s *privep, - FAR struct lpc43_req_s *req) -{ - bool is_empty = !privep->head; - - req->flink = NULL; - if (is_empty) - { - privep->head = req; - privep->tail = req; - } - else - { - privep->tail->flink = req; - privep->tail = req; - } - - return is_empty; -} - -/******************************************************************************* - * Name: lpc43_writedtd - * - * Description: - * Initialise a DTD to transfer the data - * - *******************************************************************************/ - -static inline void lpc43_writedtd(struct lpc43_dtd_s *dtd, const uint8_t *data, uint32_t nbytes) -{ - dtd->nextdesc = DTD_NEXTDESC_INVALID; - dtd->config = DTD_CONFIG_LENGTH(nbytes) | DTD_CONFIG_IOC | DTD_CONFIG_ACTIVE; - dtd->buffer0 = ((uint32_t) data); - dtd->buffer1 = (((uint32_t) data) + 0x1000) & 0xfffff000; - dtd->buffer2 = (((uint32_t) data) + 0x2000) & 0xfffff000; - dtd->buffer3 = (((uint32_t) data) + 0x3000) & 0xfffff000; - dtd->buffer4 = (((uint32_t) data) + 0x4000) & 0xfffff000; - dtd->xfer_len = nbytes; -} - -/******************************************************************************* - * Name: lpc43_queuedtd - * - * Description: - * Add the DTD to the device list - * - *******************************************************************************/ - -static void lpc43_queuedtd(uint8_t epphy, struct lpc43_dtd_s *dtd) -{ - /* Queue the DTD onto the Endpoint */ - /* NOTE - this only works when no DTD is currently queued */ - - g_qh[epphy].overlay.nextdesc = (uint32_t) dtd; - g_qh[epphy].overlay.config &= ~(DTD_CONFIG_ACTIVE | DTD_CONFIG_HALTED); - - uint32_t bit = LPC43_ENDPTMASK(epphy); - - lpc43_setbits (bit, LPC43_USBDEV_ENDPTPRIME); - - while (lpc43_getreg (LPC43_USBDEV_ENDPTPRIME) & bit) - ; -} - -/******************************************************************************* - * Name: lpc43_ep0xfer - * - * Description: - * Schedule a short transfer for Endpoint 0 (IN or OUT) - * - *******************************************************************************/ - -static inline void lpc43_ep0xfer(uint8_t epphy, uint8_t *buf, uint32_t nbytes) -{ - struct lpc43_dtd_s *dtd = &g_td[epphy]; - - lpc43_writedtd(dtd, buf, nbytes); - - lpc43_queuedtd(epphy, dtd); -} - -/******************************************************************************* - * Name: lpc43_readsetup - * - * Description: - * Read a Setup packet from the DTD. - * - *******************************************************************************/ -static void lpc43_readsetup(uint8_t epphy, struct usb_ctrlreq_s *ctrl) -{ - struct lpc43_dqh_s *dqh = &g_qh[epphy]; - int i; - - do - { - /* Set the trip wire */ - - lpc43_setbits(USBDEV_USBCMD_SUTW, LPC43_USBDEV_USBCMD); - - /* Copy the request... */ - - for (i = 0; i < 8; i++) - { - ((uint8_t *) ctrl)[i] = ((uint8_t *) dqh->setup)[i]; - } - } - while (!(lpc43_getreg(LPC43_USBDEV_USBCMD) & USBDEV_USBCMD_SUTW)); - - /* Clear the trip wire */ - - lpc43_clrbits(USBDEV_USBCMD_SUTW, LPC43_USBDEV_USBCMD); - - /* Clear the Setup Interrupt */ - - lpc43_putreg (LPC43_ENDPTMASK(LPC43_EP0_OUT), LPC43_USBDEV_ENDPTSETUPSTAT); -} - -/******************************************************************************* - * Name: lpc43_set_address - * - * Description: - * Set the devices USB address - * - *******************************************************************************/ - -static inline void lpc43_set_address(struct lpc43_usbdev_s *priv, uint16_t address) -{ - priv->paddr = address; - priv->paddrset = address != 0; - - lpc43_chgbits(USBDEV_DEVICEADDR_MASK, priv->paddr << USBDEV_DEVICEADDR_SHIFT, - LPC43_USBDEV_DEVICEADDR); -} - -/******************************************************************************* - * Name: lpc43_flushep - * - * Description: - * Flush any primed descriptors from this ep - * - *******************************************************************************/ - -static void lpc43_flushep(struct lpc43_ep_s *privep) -{ - uint32_t mask = LPC43_ENDPTMASK(privep->epphy); - do - { - lpc43_putreg (mask, LPC43_USBDEV_ENDPTFLUSH); - while ((lpc43_getreg(LPC43_USBDEV_ENDPTFLUSH) & mask) != 0) - ; - } - while ((lpc43_getreg(LPC43_USBDEV_ENDPTSTATUS) & mask) != 0); -} - - -/******************************************************************************* - * Name: lpc43_progressep - * - * Description: - * Progress the Endpoint by priming the first request into the queue head - * - *******************************************************************************/ - -static int lpc43_progressep(struct lpc43_ep_s *privep) -{ - struct lpc43_dtd_s *dtd = &g_td[privep->epphy]; - struct lpc43_req_s *privreq; - - /* Check the request from the head of the endpoint request queue */ - - privreq = lpc43_rqpeek(privep); - if (!privreq) - { - usbtrace(TRACE_INTDECODE(LPC43_TRACEINTID_EPINQEMPTY), 0); - return OK; - } - - /* Ignore any attempt to send a zero length packet */ - - if (privreq->req.len == 0) - { - /* If the class driver is responding to a setup packet, then wait for - * the host to illicit thr response - */ - - if (privep->epphy == LPC43_EP0_IN && privep->dev->ep0state == EP0STATE_SETUP_OUT) - { - lpc43_ep0state (privep->dev, EP0STATE_WAIT_NAK_IN); - } - else - { - if (LPC43_EPPHYIN(privep->epphy)) - { - usbtrace(TRACE_DEVERROR(LPC43_TRACEERR_EPINNULLPACKET), 0); - } - else - { - usbtrace(TRACE_DEVERROR(LPC43_TRACEERR_EPOUTNULLPACKET), 0); - } - } - - lpc43_reqcomplete(privep, lpc43_rqdequeue(privep), OK); - return OK; - } - - if (privep->epphy == LPC43_EP0_IN) - { - lpc43_ep0state (privep->dev, EP0STATE_DATA_IN); - } - else if (privep->epphy == LPC43_EP0_OUT) - { - lpc43_ep0state (privep->dev, EP0STATE_DATA_OUT); - } - - int bytesleft = privreq->req.len - privreq->req.xfrd; - - if (LPC43_EPPHYIN(privep->epphy)) - { - usbtrace(TRACE_WRITE(privep->epphy), privreq->req.xfrd); - } - else - { - usbtrace(TRACE_READ(privep->epphy), privreq->req.xfrd); - } - - /* Initialise the DTD to transfer the next chunk */ - - lpc43_writedtd (dtd, privreq->req.buf + privreq->req.xfrd, bytesleft); - - /* Then queue onto the DQH */ - - lpc43_queuedtd(privep->epphy, dtd); - - return OK; -} - -/******************************************************************************* - * Name: lpc43_abortrequest - * - * Description: - * Discard a request - * - *******************************************************************************/ - -static inline void lpc43_abortrequest(struct lpc43_ep_s *privep, - struct lpc43_req_s *privreq, - int16_t result) -{ - usbtrace(TRACE_DEVERROR(LPC43_TRACEERR_REQABORTED), (uint16_t)privep->epphy); - - /* Save the result in the request structure */ - - privreq->req.result = result; - - /* Callback to the request completion handler */ - - privreq->req.callback(&privep->ep, &privreq->req); -} - -/******************************************************************************* - * Name: lpc43_reqcomplete - * - * Description: - * Handle termination of the request at the head of the endpoint request queue. - * - *******************************************************************************/ - -static void lpc43_reqcomplete(struct lpc43_ep_s *privep, - struct lpc43_req_s *privreq, int16_t result) -{ - /* If endpoint 0, temporarily reflect the state of protocol stalled - * in the callback. - */ - - bool stalled = privep->stalled; - if (privep->epphy == LPC43_EP0_IN) - privep->stalled = privep->dev->stalled; - - /* Save the result in the request structure */ - - privreq->req.result = result; - - /* Callback to the request completion handler */ - - privreq->req.callback(&privep->ep, &privreq->req); - - /* Restore the stalled indication */ - - privep->stalled = stalled; -} - -/******************************************************************************* - * Name: lpc43_cancelrequests - * - * Description: - * Cancel all pending requests for an endpoint - * - *******************************************************************************/ - -static void lpc43_cancelrequests(struct lpc43_ep_s *privep, int16_t status) -{ - if (!lpc43_rqempty(privep)) - lpc43_flushep(privep); - - while (!lpc43_rqempty(privep)) - { - // FIXME: the entry at the head should be sync'd with the DTD - // FIXME: only report the error status if the transfer hasn't completed - usbtrace(TRACE_COMPLETE(privep->epphy), - (lpc43_rqpeek(privep))->req.xfrd); - lpc43_reqcomplete(privep, lpc43_rqdequeue(privep), status); - } -} - -/******************************************************************************* - * Name: lpc43_epfindbyaddr - * - * Description: - * Find the physical endpoint structure corresponding to a logic endpoint - * address - * - *******************************************************************************/ - -static struct lpc43_ep_s *lpc43_epfindbyaddr(struct lpc43_usbdev_s *priv, - uint16_t eplog) -{ - struct lpc43_ep_s *privep; - int i; - - /* Endpoint zero is a special case */ - - if (USB_EPNO(eplog) == 0) - { - return &priv->eplist[0]; - } - - /* Handle the remaining */ - - for (i = 1; i < LPC43_NPHYSENDPOINTS; i++) - { - privep = &priv->eplist[i]; - - /* Same logical endpoint number? (includes direction bit) */ - - if (eplog == privep->ep.eplog) - { - /* Return endpoint found */ - - return privep; - } - } - - /* Return endpoint not found */ - - return NULL; -} - -/******************************************************************************* - * Name: lpc43_dispatchrequest - * - * Description: - * Provide unhandled setup actions to the class driver. This is logically part - * of the USB interrupt handler. - * - *******************************************************************************/ - -static void lpc43_dispatchrequest(struct lpc43_usbdev_s *priv, - const struct usb_ctrlreq_s *ctrl) -{ - int ret = -EIO; - - usbtrace(TRACE_INTDECODE(LPC43_TRACEINTID_DISPATCH), 0); - if (priv->driver) - { - /* Forward to the control request to the class driver implementation */ - - ret = CLASS_SETUP(priv->driver, &priv->usbdev, ctrl, NULL, 0); - } - - if (ret < 0) - { - /* Stall on failure */ - - usbtrace(TRACE_DEVERROR(LPC43_TRACEERR_DISPATCHSTALL), 0); - priv->stalled = true; - } -} - -/******************************************************************************* - * Name: lpc43_ep0configure - * - * Description: - * Reset Usb engine - * - *******************************************************************************/ - -static void lpc43_ep0configure(struct lpc43_usbdev_s *priv) -{ - /* Enable ep0 IN and ep0 OUT */ - - g_qh[LPC43_EP0_OUT].capability = (DQH_CAPABILITY_MAX_PACKET(CONFIG_USBDEV_EP0_MAXSIZE) | - DQH_CAPABILITY_IOS | - DQH_CAPABILITY_ZLT); - - g_qh[LPC43_EP0_IN ].capability = (DQH_CAPABILITY_MAX_PACKET(CONFIG_USBDEV_EP0_MAXSIZE) | - DQH_CAPABILITY_IOS | - DQH_CAPABILITY_ZLT); - - g_qh[LPC43_EP0_OUT].currdesc = DTD_NEXTDESC_INVALID; - g_qh[LPC43_EP0_IN ].currdesc = DTD_NEXTDESC_INVALID; - - /* Enable EP0 */ - - lpc43_setbits (USBDEV_ENDPTCTRL0_RXE | USBDEV_ENDPTCTRL0_TXE, LPC43_USBDEV_ENDPTCTRL0); -} - -/******************************************************************************* - * Name: lpc43_usbreset - * - * Description: - * Reset Usb engine - * - *******************************************************************************/ - -static void lpc43_usbreset(struct lpc43_usbdev_s *priv) -{ - int epphy; - - /* Disable all endpoints */ - - lpc43_clrbits (USBDEV_ENDPTCTRL_RXE | USBDEV_ENDPTCTRL_TXE, LPC43_USBDEV_ENDPTCTRL0); - lpc43_clrbits (USBDEV_ENDPTCTRL_RXE | USBDEV_ENDPTCTRL_TXE, LPC43_USBDEV_ENDPTCTRL1); - lpc43_clrbits (USBDEV_ENDPTCTRL_RXE | USBDEV_ENDPTCTRL_TXE, LPC43_USBDEV_ENDPTCTRL2); - lpc43_clrbits (USBDEV_ENDPTCTRL_RXE | USBDEV_ENDPTCTRL_TXE, LPC43_USBDEV_ENDPTCTRL3); - - /* Clear all pending interrupts */ - - lpc43_putreg (lpc43_getreg(LPC43_USBDEV_ENDPTNAK), LPC43_USBDEV_ENDPTNAK); - lpc43_putreg (lpc43_getreg(LPC43_USBDEV_ENDPTSETUPSTAT), LPC43_USBDEV_ENDPTSETUPSTAT); - lpc43_putreg (lpc43_getreg(LPC43_USBDEV_ENDPTCOMPLETE), LPC43_USBDEV_ENDPTCOMPLETE); - - /* Wait for all prime operations to have completed and then flush all DTDs */ - - while (lpc43_getreg (LPC43_USBDEV_ENDPTPRIME) != 0) - ; - lpc43_putreg (LPC43_ENDPTMASK_ALL, LPC43_USBDEV_ENDPTFLUSH); - while (lpc43_getreg (LPC43_USBDEV_ENDPTFLUSH)) - ; - - /* Reset endpoints */ - - for (epphy = 0; epphy < LPC43_NPHYSENDPOINTS; epphy++) - { - struct lpc43_ep_s *privep = &priv->eplist[epphy]; - - lpc43_cancelrequests (privep, -ESHUTDOWN); - - /* Reset endpoint status */ - - privep->stalled = false; - } - - /* Tell the class driver that we are disconnected. The class - * driver should then accept any new configurations. */ - - if (priv->driver) - { - CLASS_DISCONNECT(priv->driver, &priv->usbdev); - } - - /* Set the interrupt Threshold control interval to 0 */ - - lpc43_chgbits(USBDEV_USBCMD_ITC_MASK, USBDEV_USBCMD_ITCIMME, LPC43_USBDEV_USBCMD); - - /* Zero out the Endpoint queue heads */ - - memset ((void *) g_qh, 0, sizeof (g_qh)); - memset ((void *) g_td, 0, sizeof (g_td)); - - /* Set USB address to 0 */ - - lpc43_set_address (priv, 0); - - /* Initialise the Enpoint List Address */ - - lpc43_putreg ((uint32_t)g_qh, LPC43_USBDEV_ENDPOINTLIST); - - /* EndPoint 0 initialization */ - - lpc43_ep0configure(priv); - - /* Enable Device interrupts */ - - lpc43_putreg(USB_FRAME_INT | USB_ERROR_INT | - USBDEV_USBINTR_NAKE | USBDEV_USBINTR_SLE | USBDEV_USBINTR_URE | USBDEV_USBINTR_PCE | USBDEV_USBINTR_UE, - LPC43_USBDEV_USBINTR); -} - -/******************************************************************************* - * Name: lpc43_setstate - * - * Description: - * Sets the EP0 state and manages the NAK interrupts - * - *******************************************************************************/ - -static inline void lpc43_ep0state(struct lpc43_usbdev_s *priv, uint16_t state) -{ - priv->ep0state = state; - - switch (state) - { - case EP0STATE_WAIT_NAK_IN: - lpc43_putreg (LPC43_ENDPTMASK(LPC43_EP0_IN), LPC43_USBDEV_ENDPTNAKEN); - break; - - case EP0STATE_WAIT_NAK_OUT: - lpc43_putreg (LPC43_ENDPTMASK(LPC43_EP0_OUT), LPC43_USBDEV_ENDPTNAKEN); - break; - - default: - lpc43_putreg(0, LPC43_USBDEV_ENDPTNAKEN); - break; - } -} - -/******************************************************************************* - * Name: lpc43_ep0setup - * - * Description: - * USB Ctrl EP Setup Event. This is logically part of the USB interrupt - * handler. This event occurs when a setup packet is receive on EP0 OUT. - * - *******************************************************************************/ - -static inline void lpc43_ep0setup(struct lpc43_usbdev_s *priv) -{ - struct lpc43_ep_s *privep; - struct usb_ctrlreq_s ctrl; - uint16_t value; - uint16_t index; - uint16_t len; - - /* Terminate any pending requests - since all DTDs will have been retired - * because of the setup packet. - */ - - lpc43_cancelrequests(&priv->eplist[LPC43_EP0_OUT], -EPROTO); - lpc43_cancelrequests(&priv->eplist[LPC43_EP0_IN], -EPROTO); - - /* Assume NOT stalled */ - - priv->eplist[LPC43_EP0_OUT].stalled = false; - priv->eplist[LPC43_EP0_IN].stalled = false; - priv->stalled = false; - - /* Read EP0 setup data */ - - lpc43_readsetup(LPC43_EP0_OUT, &ctrl); - - /* Starting a control request - update state */ - - lpc43_ep0state (priv, (ctrl.type & USB_REQ_DIR_IN) ? EP0STATE_SETUP_IN : EP0STATE_SETUP_OUT); - - /* And extract the little-endian 16-bit values to host order */ - - value = GETUINT16(ctrl.value); - index = GETUINT16(ctrl.index); - len = GETUINT16(ctrl.len); - - ullvdbg("type=%02x req=%02x value=%04x index=%04x len=%04x\n", - ctrl.type, ctrl.req, value, index, len); - - /* Dispatch any non-standard requests */ - - if ((ctrl.type & USB_REQ_TYPE_MASK) != USB_REQ_TYPE_STANDARD) - { - lpc43_dispatchrequest(priv, &ctrl); - } - else - { - /* Handle standard request. Pick off the things of interest to the USB - * device controller driver; pass what is left to the class driver. - */ - - switch (ctrl.req) - { - case USB_REQ_GETSTATUS: - { - /* type: device-to-host; recipient = device, interface, endpoint - * value: 0 - * index: zero interface endpoint - * len: 2; data = status - */ - - usbtrace(TRACE_INTDECODE(LPC43_TRACEINTID_GETSTATUS), 0); - if (!priv->paddrset || len != 2 || - (ctrl.type & USB_REQ_DIR_IN) == 0 || value != 0) - { - priv->stalled = true; - } - else - { - switch (ctrl.type & USB_REQ_RECIPIENT_MASK) - { - case USB_REQ_RECIPIENT_ENDPOINT: - { - usbtrace(TRACE_INTDECODE(LPC43_TRACEINTID_EPGETSTATUS), 0); - privep = lpc43_epfindbyaddr(priv, index); - if (!privep) - { - usbtrace(TRACE_DEVERROR(LPC43_TRACEERR_BADEPGETSTATUS), 0); - priv->stalled = true; - } - else - { - if (privep->stalled) - { - priv->ep0buf[0] = 1; /* Stalled */ - } - else - { - priv->ep0buf[0] = 0; /* Not stalled */ - } - - priv->ep0buf[1] = 0; - - lpc43_ep0xfer (LPC43_EP0_IN, priv->ep0buf, 2); - lpc43_ep0state (priv, EP0STATE_SHORTWRITE); - } - } - break; - - case USB_REQ_RECIPIENT_DEVICE: - { - if (index == 0) - { - usbtrace(TRACE_INTDECODE(LPC43_TRACEINTID_DEVGETSTATUS), 0); - - /* Features: Remote Wakeup=YES; selfpowered=? */ - - priv->ep0buf[0] = (priv->selfpowered << USB_FEATURE_SELFPOWERED) | - (1 << USB_FEATURE_REMOTEWAKEUP); - priv->ep0buf[1] = 0; - - lpc43_ep0xfer(LPC43_EP0_IN, priv->ep0buf, 2); - lpc43_ep0state (priv, EP0STATE_SHORTWRITE); - } - else - { - usbtrace(TRACE_DEVERROR(LPC43_TRACEERR_BADDEVGETSTATUS), 0); - priv->stalled = true; - } - } - break; - - case USB_REQ_RECIPIENT_INTERFACE: - { - usbtrace(TRACE_INTDECODE(LPC43_TRACEINTID_IFGETSTATUS), 0); - priv->ep0buf[0] = 0; - priv->ep0buf[1] = 0; - - lpc43_ep0xfer(LPC43_EP0_IN, priv->ep0buf, 2); - lpc43_ep0state (priv, EP0STATE_SHORTWRITE); - } - break; - - default: - { - usbtrace(TRACE_DEVERROR(LPC43_TRACEERR_BADGETSTATUS), 0); - priv->stalled = true; - } - break; - } - } - } - break; - - case USB_REQ_CLEARFEATURE: - { - /* type: host-to-device; recipient = device, interface or endpoint - * value: feature selector - * index: zero interface endpoint; - * len: zero, data = none - */ - - usbtrace(TRACE_INTDECODE(LPC43_TRACEINTID_CLEARFEATURE), 0); - if ((ctrl.type & USB_REQ_RECIPIENT_MASK) != USB_REQ_RECIPIENT_ENDPOINT) - { - lpc43_dispatchrequest(priv, &ctrl); - } - else if (priv->paddrset != 0 && value == USB_FEATURE_ENDPOINTHALT && len == 0 && - (privep = lpc43_epfindbyaddr(priv, index)) != NULL) - { - lpc43_epstall(&privep->ep, true); - lpc43_ep0state (priv, EP0STATE_WAIT_NAK_IN); - } - else - { - usbtrace(TRACE_DEVERROR(LPC43_TRACEERR_BADCLEARFEATURE), 0); - priv->stalled = true; - } - } - break; - - case USB_REQ_SETFEATURE: - { - /* type: host-to-device; recipient = device, interface, endpoint - * value: feature selector - * index: zero interface endpoint; - * len: 0; data = none - */ - - usbtrace(TRACE_INTDECODE(LPC43_TRACEINTID_SETFEATURE), 0); - if (((ctrl.type & USB_REQ_RECIPIENT_MASK) == USB_REQ_RECIPIENT_DEVICE) && - value == USB_FEATURE_TESTMODE) - { - ullvdbg("test mode: %d\n", index); - } - else if ((ctrl.type & USB_REQ_RECIPIENT_MASK) != USB_REQ_RECIPIENT_ENDPOINT) - { - lpc43_dispatchrequest(priv, &ctrl); - } - else if (priv->paddrset != 0 && value == USB_FEATURE_ENDPOINTHALT && len == 0 && - (privep = lpc43_epfindbyaddr(priv, index)) != NULL) - { - lpc43_epstall(&privep->ep, false); - lpc43_ep0state (priv, EP0STATE_WAIT_NAK_IN); - } - else - { - usbtrace(TRACE_DEVERROR(LPC43_TRACEERR_BADSETFEATURE), 0); - priv->stalled = true; - } - } - break; - - case USB_REQ_SETADDRESS: - { - /* type: host-to-device; recipient = device - * value: device address - * index: 0 - * len: 0; data = none - */ - - usbtrace(TRACE_INTDECODE(LPC43_TRACEINTID_EP0SETUPSETADDRESS), value); - if ((ctrl.type & USB_REQ_RECIPIENT_MASK) == USB_REQ_RECIPIENT_DEVICE && - index == 0 && len == 0 && value < 128) - { - /* Save the address. We cannot actually change to the next address until - * the completion of the status phase. */ - - priv->paddr = ctrl.value[0]; - priv->paddrset = false; - lpc43_ep0state (priv, EP0STATE_WAIT_NAK_IN); - } - else - { - usbtrace(TRACE_DEVERROR(LPC43_TRACEERR_BADSETADDRESS), 0); - priv->stalled = true; - } - } - break; - - case USB_REQ_GETDESCRIPTOR: - /* type: device-to-host; recipient = device - * value: descriptor type and index - * index: 0 or language ID; - * len: descriptor len; data = descriptor - */ - case USB_REQ_SETDESCRIPTOR: - /* type: host-to-device; recipient = device - * value: descriptor type and index - * index: 0 or language ID; - * len: descriptor len; data = descriptor - */ - { - usbtrace(TRACE_INTDECODE(LPC43_TRACEINTID_GETSETDESC), 0); - if ((ctrl.type & USB_REQ_RECIPIENT_MASK) == USB_REQ_RECIPIENT_DEVICE) - { - lpc43_dispatchrequest(priv, &ctrl); - } - else - { - usbtrace(TRACE_DEVERROR(LPC43_TRACEERR_BADGETSETDESC), 0); - priv->stalled = true; - } - } - break; - - case USB_REQ_GETCONFIGURATION: - /* type: device-to-host; recipient = device - * value: 0; - * index: 0; - * len: 1; data = configuration value - */ - { - usbtrace(TRACE_INTDECODE(LPC43_TRACEINTID_GETCONFIG), 0); - if (priv->paddrset && (ctrl.type & USB_REQ_RECIPIENT_MASK) == USB_REQ_RECIPIENT_DEVICE && - value == 0 && index == 0 && len == 1) - { - lpc43_dispatchrequest(priv, &ctrl); - } - else - { - usbtrace(TRACE_DEVERROR(LPC43_TRACEERR_BADGETCONFIG), 0); - priv->stalled = true; - } - } - break; - - case USB_REQ_SETCONFIGURATION: - /* type: host-to-device; recipient = device - * value: configuration value - * index: 0; - * len: 0; data = none - */ - { - usbtrace(TRACE_INTDECODE(LPC43_TRACEINTID_SETCONFIG), 0); - if ((ctrl.type & USB_REQ_RECIPIENT_MASK) == USB_REQ_RECIPIENT_DEVICE && - index == 0 && len == 0) - { - lpc43_dispatchrequest(priv, &ctrl); - } - else - { - usbtrace(TRACE_DEVERROR(LPC43_TRACEERR_BADSETCONFIG), 0); - priv->stalled = true; - } - } - break; - - case USB_REQ_GETINTERFACE: - /* type: device-to-host; recipient = interface - * value: 0 - * index: interface; - * len: 1; data = alt interface - */ - case USB_REQ_SETINTERFACE: - /* type: host-to-device; recipient = interface - * value: alternate setting - * index: interface; - * len: 0; data = none - */ - { - usbtrace(TRACE_INTDECODE(LPC43_TRACEINTID_GETSETIF), 0); - lpc43_dispatchrequest(priv, &ctrl); - } - break; - - case USB_REQ_SYNCHFRAME: - /* type: device-to-host; recipient = endpoint - * value: 0 - * index: endpoint; - * len: 2; data = frame number - */ - { - usbtrace(TRACE_INTDECODE(LPC43_TRACEINTID_SYNCHFRAME), 0); - } - break; - - default: - { - usbtrace(TRACE_DEVERROR(LPC43_TRACEERR_INVALIDCTRLREQ), 0); - priv->stalled = true; - } - break; - } - } - - if (priv->stalled) - { - usbtrace(TRACE_DEVERROR(LPC43_TRACEERR_EP0SETUPSTALLED), priv->ep0state); - lpc43_epstall(&priv->eplist[LPC43_EP0_IN].ep, false); - lpc43_epstall(&priv->eplist[LPC43_EP0_OUT].ep, false); - } -} - -/******************************************************************************* - * Name: lpc43_ep0complete - * - * Description: - * Transfer complete handler for Endpoint 0 - * - *******************************************************************************/ - -static void lpc43_ep0complete(struct lpc43_usbdev_s *priv, uint8_t epphy) -{ - struct lpc43_ep_s *privep = &priv->eplist[epphy]; - - usbtrace(TRACE_INTDECODE(LPC43_TRACEINTID_EP0COMPLETE), (uint16_t)priv->ep0state); - - switch (priv->ep0state) - { - case EP0STATE_DATA_IN: - if (lpc43_rqempty(privep)) - { - return; - } - - if (lpc43_epcomplete (priv, epphy)) - { - lpc43_ep0state (priv, EP0STATE_WAIT_NAK_OUT); - } - break; - - case EP0STATE_DATA_OUT: - if (lpc43_rqempty(privep)) - { - return; - } - - if (lpc43_epcomplete (priv, epphy)) - { - lpc43_ep0state (priv, EP0STATE_WAIT_NAK_IN); - } - break; - - case EP0STATE_SHORTWRITE: - lpc43_ep0state (priv, EP0STATE_WAIT_NAK_OUT); - break; - - case EP0STATE_WAIT_STATUS_IN: - lpc43_ep0state (priv, EP0STATE_IDLE); - - /* If we've received a SETADDRESS packet, then we set the address - * now that the status phase has completed - */ - - if (! priv->paddrset && priv->paddr != 0) - { - usbtrace(TRACE_INTDECODE(LPC43_TRACEINTID_EP0INSETADDRESS), (uint16_t)priv->paddr); - lpc43_set_address (priv, priv->paddr); - } - - break; - - case EP0STATE_WAIT_STATUS_OUT: - lpc43_ep0state (priv, EP0STATE_IDLE); - break; - - default: -#ifdef CONFIG_DEBUG - DEBUGASSERT(priv->ep0state != EP0STATE_DATA_IN && - priv->ep0state != EP0STATE_DATA_OUT && - priv->ep0state != EP0STATE_SHORTWRITE && - priv->ep0state != EP0STATE_WAIT_STATUS_IN && - priv->ep0state != EP0STATE_WAIT_STATUS_OUT); -#endif - priv->stalled = true; - break; - } - - if (priv->stalled) - { - usbtrace(TRACE_DEVERROR(LPC43_TRACEERR_EP0SETUPSTALLED), priv->ep0state); - lpc43_epstall(&priv->eplist[LPC43_EP0_IN].ep, false); - lpc43_epstall(&priv->eplist[LPC43_EP0_OUT].ep, false); - } -} - -/******************************************************************************* - * Name: lpc43_ep0nak - * - * Description: - * Handle a NAK interrupt on EP0 - * - *******************************************************************************/ - -static void lpc43_ep0nak(struct lpc43_usbdev_s *priv, uint8_t epphy) -{ - usbtrace(TRACE_INTDECODE(LPC43_TRACEINTID_EP0NAK), (uint16_t)priv->ep0state); - - switch (priv->ep0state) - { - case EP0STATE_WAIT_NAK_IN: - lpc43_ep0xfer (LPC43_EP0_IN, NULL, 0); - lpc43_ep0state (priv, EP0STATE_WAIT_STATUS_IN); - break; - - case EP0STATE_WAIT_NAK_OUT: - lpc43_ep0xfer (LPC43_EP0_OUT, NULL, 0); - lpc43_ep0state (priv, EP0STATE_WAIT_STATUS_OUT); - break; - - default: -#ifdef CONFIG_DEBUG - DEBUGASSERT(priv->ep0state != EP0STATE_WAIT_NAK_IN && - priv->ep0state != EP0STATE_WAIT_NAK_OUT); -#endif - priv->stalled = true; - break; - } - - if (priv->stalled) - { - usbtrace(TRACE_DEVERROR(LPC43_TRACEERR_EP0SETUPSTALLED), priv->ep0state); - lpc43_epstall(&priv->eplist[LPC43_EP0_IN].ep, false); - lpc43_epstall(&priv->eplist[LPC43_EP0_OUT].ep, false); - } -} - -/******************************************************************************* - * Name: lpc43_epcomplete - * - * Description: - * Transfer complete handler for Endpoints other than 0 - * returns whether the request at the head has completed - * - *******************************************************************************/ - -bool lpc43_epcomplete(struct lpc43_usbdev_s *priv, uint8_t epphy) -{ - struct lpc43_ep_s *privep = &priv->eplist[epphy]; - struct lpc43_req_s *privreq = privep->head; - struct lpc43_dtd_s *dtd = &g_td[epphy]; - - if (privreq == NULL) /* This shouldn't really happen */ - { - if (LPC43_EPPHYOUT(privep->epphy)) - { - usbtrace(TRACE_INTDECODE(LPC43_TRACEINTID_EPINQEMPTY), 0); - } - else - { - usbtrace(TRACE_INTDECODE(LPC43_TRACEINTID_EPOUTQEMPTY), 0); - } - - return true; - } - - int xfrd = dtd->xfer_len - (dtd->config >> 16); - - privreq->req.xfrd += xfrd; - - bool complete = true; - if (LPC43_EPPHYOUT(privep->epphy)) - { - /* read(OUT) completes when request filled, or a short transfer is received */ - - usbtrace(TRACE_INTDECODE(LPC43_TRACEINTID_EPIN), complete); - } - else - { - /* write(IN) completes when request finished, unless we need to terminate with a ZLP */ - - bool need_zlp = (xfrd == privep->ep.maxpacket) && ((privreq->req.flags & USBDEV_REQFLAGS_NULLPKT) != 0); - - complete = (privreq->req.xfrd >= privreq->req.len && !need_zlp); - - usbtrace(TRACE_INTDECODE(LPC43_TRACEINTID_EPOUT), complete); - } - - /* If the transfer is complete, then dequeue and progress any further queued requests */ - - if (complete) - { - privreq = lpc43_rqdequeue (privep); - } - - if (!lpc43_rqempty(privep)) - { - lpc43_progressep(privep); - } - - /* Now it's safe to call the completion callback as it may well submit a new request */ - - if (complete) - { - usbtrace(TRACE_COMPLETE(privep->epphy), privreq->req.xfrd); - lpc43_reqcomplete(privep, privreq, OK); - } - - return complete; -} - - -/******************************************************************************* - * Name: lpc43_usbinterrupt - * - * Description: - * USB interrupt handler - * - *******************************************************************************/ - -static int lpc43_usbinterrupt(int irq, FAR void *context) -{ - struct lpc43_usbdev_s *priv = &g_usbdev; - uint32_t disr, portsc1, n; - - usbtrace(TRACE_INTENTRY(LPC43_TRACEINTID_USB), 0); - - /* Read the interrupts and then clear them */ - - disr = lpc43_getreg(LPC43_USBDEV_USBSTS); - lpc43_putreg(disr, LPC43_USBDEV_USBSTS); - - if (disr & USBDEV_USBSTS_URI) - { - usbtrace(TRACE_INTDECODE(LPC43_TRACEINTID_DEVRESET),0); - - lpc43_usbreset(priv); - - usbtrace(TRACE_INTEXIT(LPC43_TRACEINTID_USB), 0); - return OK; - } - - /* When the device controller enters a suspend state from an active state, - * the SLI bit will be set to a one. - */ - - if (!priv->suspended && (disr & USBDEV_USBSTS_SLI) != 0) - { - usbtrace(TRACE_INTDECODE(LPC43_TRACEINTID_SUSPENDED),0); - - /* Inform the Class driver of the suspend event */ - - priv->suspended = 1; - if (priv->driver) - { - CLASS_SUSPEND(priv->driver, &priv->usbdev); - } - - /* TODO: Perform power management operations here. */ - } - - /* The device controller clears the SLI bit upon exiting from a suspend - * state. This bit can also be cleared by software writing a one to it. - */ - - else if (priv->suspended && (disr & USBDEV_USBSTS_SLI) == 0) - { - usbtrace(TRACE_INTDECODE(LPC43_TRACEINTID_RESUMED),0); - - /* Inform the Class driver of the resume event */ - - priv->suspended = 0; - if (priv->driver) - { - CLASS_RESUME(priv->driver, &priv->usbdev); - } - - /* TODO: Perform power management operations here. */ - } - - if (disr & USBDEV_USBSTS_PCI) - { - portsc1 = lpc43_getreg(LPC43_USBDEV_PORTSC1); - - if (portsc1 & USBDEV_PRTSC1_HSP) - priv->usbdev.speed = USB_SPEED_HIGH; - else - priv->usbdev.speed = USB_SPEED_FULL; - - if (portsc1 & USBDEV_PRTSC1_FPR) - { - /* FIXME: this occurs because of a J-to-K transition detected - * while the port is in SUSPEND state - presumambly this - * is where the host is resuming the device? - * - * - but do we need to "ack" the interrupt - */ - } - } - -#ifdef CONFIG_LPC43_USBDEV_FRAME_INTERRUPT - if (disr & USBDEV_USBSTT_SRI) - { - usbtrace(TRACE_INTDECODE(LPC43_TRACEINTID_FRAME), 0); - - priv->sof = (int)lpc43_getreg(LPC43_USBDEV_FRINDEX_OFFSET); - } -#endif - - if (disr & USBDEV_USBSTS_UEI) - { - /* FIXME: these occur when a transfer results in an error condition - * it is set alongside USBINT if the DTD also had its IOC - * bit set. */ - } - - if (disr & USBDEV_USBSTS_UI) - { - /* Handle completion interrupts */ - - uint32_t mask = lpc43_getreg (LPC43_USBDEV_ENDPTCOMPLETE); - - if (mask) - { - /* Clear any NAK interrupt and completion interrupts */ - - lpc43_putreg (mask, LPC43_USBDEV_ENDPTNAK); - lpc43_putreg (mask, LPC43_USBDEV_ENDPTCOMPLETE); - - if (mask & LPC43_ENDPTMASK(0)) - { - lpc43_ep0complete(priv, 0); - } - - if (mask & LPC43_ENDPTMASK(1)) - { - lpc43_ep0complete(priv, 1); - } - - for (n = 1; n < LPC43_NLOGENDPOINTS; n++) - { - if (mask & LPC43_ENDPTMASK((n << 1))) - { - lpc43_epcomplete (priv, (n << 1)); - } - - if (mask & LPC43_ENDPTMASK((n << 1)+1)) - { - lpc43_epcomplete(priv, (n << 1)+1); - } - } - } - - /* Handle setup interrupts */ - - uint32_t setupstat = lpc43_getreg(LPC43_USBDEV_ENDPTSETUPSTAT); - if (setupstat) - { - /* Clear the endpoint complete CTRL OUT and IN when a Setup is received */ - - lpc43_putreg(LPC43_ENDPTMASK(LPC43_EP0_IN) | LPC43_ENDPTMASK(LPC43_EP0_OUT), - LPC43_USBDEV_ENDPTCOMPLETE); - - if (setupstat & LPC43_ENDPTMASK(LPC43_EP0_OUT)) - { - usbtrace(TRACE_INTDECODE(LPC43_TRACEINTID_EP0SETUP), setupstat); - lpc43_ep0setup(priv); - } - } - } - - if (disr & USBDEV_USBSTS_NAKI) - { - uint32_t pending = lpc43_getreg(LPC43_USBDEV_ENDPTNAK) & lpc43_getreg(LPC43_USBDEV_ENDPTNAKEN); - if (pending) - { - /* We shouldn't see NAK interrupts except on Endpoint 0 */ - - if (pending & LPC43_ENDPTMASK(0)) - { - lpc43_ep0nak(priv, 0); - } - - if (pending & LPC43_ENDPTMASK(1)) - { - lpc43_ep0nak(priv, 1); - } - } - - /* Clear the interrupts */ - - lpc43_putreg(pending, LPC43_USBDEV_ENDPTNAK); - } - - usbtrace(TRACE_INTEXIT(LPC43_TRACEINTID_USB), 0); - return OK; -} - -/******************************************************************************* - * Endpoint operations - *******************************************************************************/ - -/******************************************************************************* - * Name: lpc43_epconfigure - * - * Description: - * Configure endpoint, making it usable - * - * Input Parameters: - * ep - the struct usbdev_ep_s instance obtained from allocep() - * desc - A struct usb_epdesc_s instance describing the endpoint - * last - true if this this last endpoint to be configured. Some hardware - * needs to take special action when all of the endpoints have been - * configured. - * - *******************************************************************************/ - -static int lpc43_epconfigure(FAR struct usbdev_ep_s *ep, - FAR const struct usb_epdesc_s *desc, - bool last) -{ - FAR struct lpc43_ep_s *privep = (FAR struct lpc43_ep_s *)ep; - - usbtrace(TRACE_EPCONFIGURE, privep->epphy); - DEBUGASSERT(desc->addr == ep->eplog); - - /* Initialise EP capabilities */ - - uint16_t maxsize = GETUINT16(desc->mxpacketsize); - if ((desc->attr & USB_EP_ATTR_XFERTYPE_MASK) == USB_EP_ATTR_XFER_ISOC) - { - g_qh[privep->epphy].capability = (DQH_CAPABILITY_MAX_PACKET(maxsize) | - DQH_CAPABILITY_IOS | - DQH_CAPABILITY_ZLT); - } - else - { - g_qh[privep->epphy].capability = (DQH_CAPABILITY_MAX_PACKET(maxsize) | - DQH_CAPABILITY_ZLT); - } - - /* Setup Endpoint Control Register */ - - if (LPC43_EPPHYIN(privep->epphy)) - { - /* Reset the data toggles */ - - uint32_t cfg = USBDEV_ENDPTCTRL_TXR; - - /* Set the endpoint type */ - - switch (desc->attr & USB_EP_ATTR_XFERTYPE_MASK) - { - case USB_EP_ATTR_XFER_CONTROL: cfg |= USBDEV_ENDPTCTRL_TXT_CTRL; break; - case USB_EP_ATTR_XFER_ISOC: cfg |= USBDEV_ENDPTCTRL_TXT_ISOC; break; - case USB_EP_ATTR_XFER_BULK: cfg |= USBDEV_ENDPTCTRL_TXT_BULK; break; - case USB_EP_ATTR_XFER_INT: cfg |= USBDEV_ENDPTCTRL_TXT_INTR; break; - } - - lpc43_chgbits (0xFFFF0000, cfg, LPC43_USBDEV_ENDPTCTRL(privep->epphy)); - } - else - { - /* Reset the data toggles */ - - uint32_t cfg = USBDEV_ENDPTCTRL_RXR; - - /* Set the endpoint type */ - - switch (desc->attr & USB_EP_ATTR_XFERTYPE_MASK) - { - case USB_EP_ATTR_XFER_CONTROL: cfg |= USBDEV_ENDPTCTRL_RXT_CTRL; break; - case USB_EP_ATTR_XFER_ISOC: cfg |= USBDEV_ENDPTCTRL_RXT_ISOC; break; - case USB_EP_ATTR_XFER_BULK: cfg |= USBDEV_ENDPTCTRL_RXT_BULK; break; - } - - lpc43_chgbits (0x0000FFFF, cfg, LPC43_USBDEV_ENDPTCTRL(privep->epphy)); - } - - /* Reset endpoint status */ - - privep->stalled = false; - - /* Enable the endpoint */ - - if (LPC43_EPPHYIN(privep->epphy)) - { - lpc43_setbits (USBDEV_ENDPTCTRL_TXE, LPC43_USBDEV_ENDPTCTRL(privep->epphy)); - } - else - { - lpc43_setbits (USBDEV_ENDPTCTRL_RXE, LPC43_USBDEV_ENDPTCTRL(privep->epphy)); - } - - return OK; -} - -/******************************************************************************* - * Name: lpc43_epdisable - * - * Description: - * The endpoint will no longer be used - * - *******************************************************************************/ - -static int lpc43_epdisable(FAR struct usbdev_ep_s *ep) -{ - FAR struct lpc43_ep_s *privep = (FAR struct lpc43_ep_s *)ep; - irqstate_t flags; - -#ifdef CONFIG_DEBUG - if (!ep) - { - usbtrace(TRACE_DEVERROR(LPC43_TRACEERR_INVALIDPARMS), 0); - return -EINVAL; - } -#endif - usbtrace(TRACE_EPDISABLE, privep->epphy); - - flags = irqsave(); - - /* Disable Endpoint */ - - if (LPC43_EPPHYIN(privep->epphy)) - { - lpc43_clrbits (USBDEV_ENDPTCTRL_TXE, LPC43_USBDEV_ENDPTCTRL(privep->epphy)); - } - else - { - lpc43_clrbits (USBDEV_ENDPTCTRL_RXE, LPC43_USBDEV_ENDPTCTRL(privep->epphy)); - } - - privep->stalled = true; - - /* Cancel any ongoing activity */ - - lpc43_cancelrequests(privep, -ESHUTDOWN); - - irqrestore(flags); - return OK; -} - -/******************************************************************************* - * Name: lpc43_epallocreq - * - * Description: - * Allocate an I/O request - * - *******************************************************************************/ - -static FAR struct usbdev_req_s *lpc43_epallocreq(FAR struct usbdev_ep_s *ep) -{ - FAR struct lpc43_req_s *privreq; - -#ifdef CONFIG_DEBUG - if (!ep) - { - usbtrace(TRACE_DEVERROR(LPC43_TRACEERR_INVALIDPARMS), 0); - return NULL; - } -#endif - usbtrace(TRACE_EPALLOCREQ, ((FAR struct lpc43_ep_s *)ep)->epphy); - - privreq = (FAR struct lpc43_req_s *)kmm_malloc(sizeof(struct lpc43_req_s)); - if (!privreq) - { - usbtrace(TRACE_DEVERROR(LPC43_TRACEERR_ALLOCFAIL), 0); - return NULL; - } - - memset(privreq, 0, sizeof(struct lpc43_req_s)); - return &privreq->req; -} - -/******************************************************************************* - * Name: lpc43_epfreereq - * - * Description: - * Free an I/O request - * - *******************************************************************************/ - -static void lpc43_epfreereq(FAR struct usbdev_ep_s *ep, FAR struct usbdev_req_s *req) -{ - FAR struct lpc43_req_s *privreq = (FAR struct lpc43_req_s *)req; - -#ifdef CONFIG_DEBUG - if (!ep || !req) - { - usbtrace(TRACE_DEVERROR(LPC43_TRACEERR_INVALIDPARMS), 0); - return; - } -#endif - - usbtrace(TRACE_EPFREEREQ, ((FAR struct lpc43_ep_s *)ep)->epphy); - kmm_free(privreq); -} - -/******************************************************************************* - * Name: lpc43_epallocbuffer - * - * Description: - * Allocate an I/O buffer - * - *******************************************************************************/ - -#ifdef CONFIG_USBDEV_DMA -static void *lpc43_epallocbuffer(FAR struct usbdev_ep_s *ep, unsigned bytes) -{ - usbtrace(TRACE_EPALLOCBUFFER, privep->epphy); - -#ifdef CONFIG_USBDEV_DMAMEMORY - return usbdev_dma_alloc(bytes); -#else - return kmm_malloc(bytes); -#endif -} -#endif - -/******************************************************************************* - * Name: lpc43_epfreebuffer - * - * Description: - * Free an I/O buffer - * - *******************************************************************************/ - -#ifdef CONFIG_USBDEV_DMA -static void lpc43_epfreebuffer(FAR struct usbdev_ep_s *ep, FAR void *buf) -{ - usbtrace(TRACE_EPFREEBUFFER, privep->epphy); - -#ifdef CONFIG_USBDEV_DMAMEMORY - usbdev_dma_free(buf); -#else - kmm_free(buf); -#endif -} -#endif - -/******************************************************************************* - * Name: lpc43_epsubmit - * - * Description: - * Submit an I/O request to the endpoint - * - *******************************************************************************/ - -static int lpc43_epsubmit(FAR struct usbdev_ep_s *ep, FAR struct usbdev_req_s *req) -{ - FAR struct lpc43_req_s *privreq = (FAR struct lpc43_req_s *)req; - FAR struct lpc43_ep_s *privep = (FAR struct lpc43_ep_s *)ep; - FAR struct lpc43_usbdev_s *priv; - irqstate_t flags; - int ret = OK; - -#ifdef CONFIG_DEBUG - if (!req || !req->callback || !req->buf || !ep) - { - usbtrace(TRACE_DEVERROR(LPC43_TRACEERR_INVALIDPARMS), 0); - ullvdbg("req=%p callback=%p buf=%p ep=%p\n", req, req->callback, req->buf, ep); - return -EINVAL; - } -#endif - - usbtrace(TRACE_EPSUBMIT, privep->epphy); - priv = privep->dev; - - if (!priv->driver || priv->usbdev.speed == USB_SPEED_UNKNOWN) - { - usbtrace(TRACE_DEVERROR(LPC43_TRACEERR_NOTCONFIGURED), priv->usbdev.speed); - return -ESHUTDOWN; - } - - /* Handle the request from the class driver */ - - req->result = -EINPROGRESS; - req->xfrd = 0; - - /* Disable Interrupts */ - - flags = irqsave(); - - /* If we are stalled, then drop all requests on the floor */ - - if (privep->stalled) - { - ret = -EBUSY; - } - else - { - /* Add the new request to the request queue for the endpoint */ - - if (LPC43_EPPHYIN(privep->epphy)) - { - usbtrace(TRACE_INREQQUEUED(privep->epphy), privreq->req.len); - } - else - { - usbtrace(TRACE_OUTREQQUEUED(privep->epphy), privreq->req.len); - } - - if (lpc43_rqenqueue(privep, privreq)) - { - lpc43_progressep(privep); - } - } - - irqrestore(flags); - return ret; -} - -/******************************************************************************* - * Name: lpc43_epcancel - * - * Description: - * Cancel an I/O request previously sent to an endpoint - * - *******************************************************************************/ - -static int lpc43_epcancel(FAR struct usbdev_ep_s *ep, FAR struct usbdev_req_s *req) -{ - FAR struct lpc43_ep_s *privep = (FAR struct lpc43_ep_s *)ep; - irqstate_t flags; - -#ifdef CONFIG_DEBUG - if (!ep || !req) - { - usbtrace(TRACE_DEVERROR(LPC43_TRACEERR_INVALIDPARMS), 0); - return -EINVAL; - } -#endif - - usbtrace(TRACE_EPCANCEL, privep->epphy); - - flags = irqsave(); - - /* FIXME: if the request is the first, then we need to flush the EP - * otherwise just remove it from the list - * - * but ... all other implementations cancel all requests ... - */ - - lpc43_cancelrequests(privep, -ESHUTDOWN); - irqrestore(flags); - return OK; -} - -/******************************************************************************* - * Name: lpc43_epstall - * - * Description: - * Stall or resume and endpoint - * - *******************************************************************************/ - -static int lpc43_epstall(FAR struct usbdev_ep_s *ep, bool resume) -{ - FAR struct lpc43_ep_s *privep = (FAR struct lpc43_ep_s *)ep; - irqstate_t flags; - - /* STALL or RESUME the endpoint */ - - flags = irqsave(); - usbtrace(resume ? TRACE_EPRESUME : TRACE_EPSTALL, privep->epphy); - - uint32_t addr = LPC43_USBDEV_ENDPTCTRL(privep->epphy); - uint32_t ctrl_xs = LPC43_EPPHYIN(privep->epphy) ? USBDEV_ENDPTCTRL_TXS : USBDEV_ENDPTCTRL_RXS; - uint32_t ctrl_xr = LPC43_EPPHYIN(privep->epphy) ? USBDEV_ENDPTCTRL_TXR : USBDEV_ENDPTCTRL_RXR; - - if (resume) - { - privep->stalled = false; - - /* Clear stall and reset the data toggle */ - - lpc43_chgbits (ctrl_xs | ctrl_xr, ctrl_xr, addr); - } - else - { - privep->stalled = true; - - lpc43_setbits (ctrl_xs, addr); - } - - irqrestore(flags); - return OK; -} - -/******************************************************************************* - * Device operations - *******************************************************************************/ - -/******************************************************************************* - * Name: lpc43_allocep - * - * Description: - * Allocate an endpoint matching the parameters. - * - * Input Parameters: - * eplog - 7-bit logical endpoint number (direction bit ignored). Zero means - * that any endpoint matching the other requirements will suffice. The - * assigned endpoint can be found in the eplog field. - * in - true: IN (device-to-host) endpoint requested - * eptype - Endpoint type. One of {USB_EP_ATTR_XFER_ISOC, USB_EP_ATTR_XFER_BULK, - * USB_EP_ATTR_XFER_INT} - * - *******************************************************************************/ - -static FAR struct usbdev_ep_s *lpc43_allocep(FAR struct usbdev_s *dev, uint8_t eplog, - bool in, uint8_t eptype) -{ - FAR struct lpc43_usbdev_s *priv = (FAR struct lpc43_usbdev_s *)dev; - uint32_t epset = LPC43_EPALLSET & ~LPC43_EPCTRLSET; - irqstate_t flags; - int epndx = 0; - - usbtrace(TRACE_DEVALLOCEP, (uint16_t)eplog); - - /* Ignore any direction bits in the logical address */ - - eplog = USB_EPNO(eplog); - - /* A logical address of 0 means that any endpoint will do */ - - if (eplog > 0) - { - /* Otherwise, we will return the endpoint structure only for the requested - * 'logical' endpoint. All of the other checks will still be performed. - * - * First, verify that the logical endpoint is in the range supported by - * by the hardware. - */ - - if (eplog >= LPC43_NLOGENDPOINTS) - { - usbtrace(TRACE_DEVERROR(LPC43_TRACEERR_BADEPNO), (uint16_t)eplog); - return NULL; - } - - /* Convert the logical address to a physical OUT endpoint address and - * remove all of the candidate endpoints from the bitset except for the - * the IN/OUT pair for this logical address. - */ - - epset &= 3 << (eplog << 1); - } - - /* Get the subset matching the requested direction */ - - if (in) - { - epset &= LPC43_EPINSET; - } - else - { - epset &= LPC43_EPOUTSET; - } - - /* Get the subset matching the requested type */ - - switch (eptype) - { - case USB_EP_ATTR_XFER_INT: /* Interrupt endpoint */ - epset &= LPC43_EPINTRSET; - break; - - case USB_EP_ATTR_XFER_BULK: /* Bulk endpoint */ - epset &= LPC43_EPBULKSET; - break; - - case USB_EP_ATTR_XFER_ISOC: /* Isochronous endpoint */ - epset &= LPC43_EPISOCSET; - break; - - case USB_EP_ATTR_XFER_CONTROL: /* Control endpoint -- not a valid choice */ - default: - usbtrace(TRACE_DEVERROR(LPC43_TRACEERR_BADEPTYPE), (uint16_t)eptype); - return NULL; - } - - /* Is the resulting endpoint supported by the LPC433x? */ - - if (epset) - { - /* Yes.. now see if any of the request endpoints are available */ - - flags = irqsave(); - epset &= priv->epavail; - if (epset) - { - /* Select the lowest bit in the set of matching, available endpoints */ - - for (epndx = 2; epndx < LPC43_NPHYSENDPOINTS; epndx++) - { - uint32_t bit = 1 << epndx; - if ((epset & bit) != 0) - { - /* Mark the IN/OUT endpoint no longer available */ - - priv->epavail &= ~(3 << (bit & ~1)); - irqrestore(flags); - - /* And return the pointer to the standard endpoint structure */ - - return &priv->eplist[epndx].ep; - } - } - - /* Shouldn't get here */ - - } - - irqrestore(flags); - } - - usbtrace(TRACE_DEVERROR(LPC43_TRACEERR_NOEP), (uint16_t)eplog); - return NULL; -} - -/******************************************************************************* - * Name: lpc43_freeep - * - * Description: - * Free the previously allocated endpoint - * - *******************************************************************************/ - -static void lpc43_freeep(FAR struct usbdev_s *dev, FAR struct usbdev_ep_s *ep) -{ - FAR struct lpc43_usbdev_s *priv = (FAR struct lpc43_usbdev_s *)dev; - FAR struct lpc43_ep_s *privep = (FAR struct lpc43_ep_s *)ep; - irqstate_t flags; - - usbtrace(TRACE_DEVFREEEP, (uint16_t)privep->epphy); - - if (priv && privep) - { - /* Mark the endpoint as available */ - - flags = irqsave(); - priv->epavail |= (1 << privep->epphy); - irqrestore(flags); - } -} - -/******************************************************************************* - * Name: lpc43_getframe - * - * Description: - * Returns the current frame number - * - *******************************************************************************/ - -static int lpc43_getframe(struct usbdev_s *dev) -{ -#ifdef CONFIG_LPC43_USBDEV_FRAME_INTERRUPT - FAR struct lpc43_usbdev_s *priv = (FAR struct lpc43_usbdev_s *)dev; - - /* Return last valid value of SOF read by the interrupt handler */ - - usbtrace(TRACE_DEVGETFRAME, (uint16_t)priv->sof); - return priv->sof; -#else - /* Return the last frame number detected by the hardware */ - - usbtrace(TRACE_DEVGETFRAME, 0); - - /* FIXME: this actually returns the micro frame number! */ - - return (int)lpc43_getreg(LPC43_USBDEV_FRINDEX_OFFSET); -#endif -} - -/******************************************************************************* - * Name: lpc43_wakeup - * - * Description: - * Tries to wake up the host connected to this device - * - *******************************************************************************/ - -static int lpc43_wakeup(struct usbdev_s *dev) -{ - irqstate_t flags; - - usbtrace(TRACE_DEVWAKEUP, 0); - - flags = irqsave(); - lpc43_setbits(USBDEV_PRTSC1_FPR, LPC43_USBDEV_PORTSC1); - irqrestore(flags); - return OK; -} - -/******************************************************************************* - * Name: lpc43_selfpowered - * - * Description: - * Sets/clears the device selfpowered feature - * - *******************************************************************************/ - -static int lpc43_selfpowered(struct usbdev_s *dev, bool selfpowered) -{ - FAR struct lpc43_usbdev_s *priv = (FAR struct lpc43_usbdev_s *)dev; - - usbtrace(TRACE_DEVSELFPOWERED, (uint16_t)selfpowered); - -#ifdef CONFIG_DEBUG - if (!dev) - { - usbtrace(TRACE_DEVERROR(LPC43_TRACEERR_INVALIDPARMS), 0); - return -ENODEV; - } -#endif - - priv->selfpowered = selfpowered; - return OK; -} - -/******************************************************************************* - * Name: lpc43_pullup - * - * Description: - * Software-controlled connect to/disconnect from USB host - * - *******************************************************************************/ - -static int lpc43_pullup(struct usbdev_s *dev, bool enable) -{ - usbtrace(TRACE_DEVPULLUP, (uint16_t)enable); - - irqstate_t flags = irqsave(); - if (enable) - { - lpc43_setbits (USBDEV_USBCMD_RS, LPC43_USBDEV_USBCMD); - } - else - { - lpc43_clrbits (USBDEV_USBCMD_RS, LPC43_USBDEV_USBCMD); - } - - irqrestore(flags); - return OK; -} - -/******************************************************************************* - * Public Functions - *******************************************************************************/ - -/******************************************************************************* - * Name: up_usbinitialize - * - * Description: - * Initialize USB hardware. - * - * Assumptions: - * - This function is called very early in the initialization sequence - * - PLL initialization is not performed here but should been in - * the low-level boot logic: PLL0 must be configured for operation at 480MHz - * - *******************************************************************************/ - -void up_usbinitialize(void) -{ - struct lpc43_usbdev_s *priv = &g_usbdev; - int i; - uint32_t regval; - - usbtrace(TRACE_DEVINIT, 0); - - /* Disable USB interrupts */ - - lpc43_putreg(0, LPC43_USBDEV_USBINTR); - - /* Initialize the device state structure */ - - memset(priv, 0, sizeof(struct lpc43_usbdev_s)); - priv->usbdev.ops = &g_devops; - priv->usbdev.ep0 = &priv->eplist[LPC43_EP0_IN].ep; - priv->epavail = LPC43_EPALLSET; - - /* Initialize the endpoint list */ - - for (i = 0; i < LPC43_NPHYSENDPOINTS; i++) - { - uint32_t bit = 1 << i; - - /* Set endpoint operations, reference to driver structure (not - * really necessary because there is only one controller), and - * the physical endpoint number (which is just the index to the - * endpoint). - */ - - priv->eplist[i].ep.ops = &g_epops; - priv->eplist[i].dev = priv; - - /* The index, i, is the physical endpoint address; Map this - * to a logical endpoint address usable by the class driver. - */ - - priv->eplist[i].epphy = i; - if (LPC43_EPPHYIN(i)) - { - priv->eplist[i].ep.eplog = LPC43_EPPHYIN2LOG(i); - } - else - { - priv->eplist[i].ep.eplog = LPC43_EPPHYOUT2LOG(i); - } - - /* The maximum packet size may depend on the type of endpoint */ - - if ((LPC43_EPCTRLSET & bit) != 0) - { - priv->eplist[i].ep.maxpacket = LPC43_EP0MAXPACKET; - } - else if ((LPC43_EPINTRSET & bit) != 0) - { - priv->eplist[i].ep.maxpacket = LPC43_INTRMAXPACKET; - } - else if ((LPC43_EPBULKSET & bit) != 0) - { - priv->eplist[i].ep.maxpacket = LPC43_BULKMAXPACKET; - } - else /* if ((LPC43_EPISOCSET & bit) != 0) */ - { - priv->eplist[i].ep.maxpacket = LPC43_ISOCMAXPACKET; - } - } - - - /* Clock */ - - regval = getreg32(LPC43_BASE_USB0_CLK); - regval &= ~BASE_USB0_CLK_CLKSEL_MASK; - regval |= (BASE_USB0_CLKSEL_PLL0USB | BASE_USB0_CLK_AUTOBLOCK); - putreg32(regval, LPC43_BASE_USB0_CLK); - - /* Clock run */ - - regval = getreg32(LPC43_CCU1_M4_USB0_CFG); - regval |= CCU_CLK_CFG_RUN; - putreg32(regval, LPC43_CCU1_M4_USB0_CFG); - - /* Enable PLL0 clock*/ - - lpc43_pll0usbconfig(); - lpc43_pll0usbenable(); - - /* Reset USB block */ - - lpc43_putreg(RGU_CTRL0_USB0_RST, LPC43_RGU_CTRL0); - - /* Reset the controller */ - - lpc43_putreg (USBDEV_USBCMD_RST, LPC43_USBDEV_USBCMD); - while (lpc43_getreg (LPC43_USBDEV_USBCMD) & USBDEV_USBCMD_RST) - ; - - /* Power PHY */ - - regval = getreg32(LPC43_CREG0); - regval &= ~CREG0_USB0PHY; - putreg32(regval, LPC43_CREG0); - - /* Attach USB controller interrupt handler */ - - if (irq_attach(LPC43M4_IRQ_USB0, lpc43_usbinterrupt) != 0) - { - usbtrace(TRACE_DEVERROR(LPC43_TRACEERR_IRQREGISTRATION), - (uint16_t)LPC43M4_IRQ_USB0); - goto errout; - } - - - /* Program the controller to be the USB device controller */ - - lpc43_putreg (USBDEV_USBMODE_SDIS | USBDEV_USBMODE_SLOM | USBDEV_USBMODE_CM_DEVICE, - LPC43_USBDEV_USBMODE); - - /* Disconnect device */ - - lpc43_pullup(&priv->usbdev, false); - - /* Reset/Re-initialize the USB hardware */ - - lpc43_usbreset(priv); - - return; - -errout: - up_usbuninitialize(); -} - -/******************************************************************************* - * Name: up_usbuninitialize - *******************************************************************************/ - -void up_usbuninitialize(void) -{ - struct lpc43_usbdev_s *priv = &g_usbdev; - irqstate_t flags; - - usbtrace(TRACE_DEVUNINIT, 0); - - if (priv->driver) - { - usbtrace(TRACE_DEVERROR(LPC43_TRACEERR_DRIVERREGISTERED), 0); - usbdev_unregister(priv->driver); - } - - /* Disconnect device */ - - flags = irqsave(); - lpc43_pullup(&priv->usbdev, false); - priv->usbdev.speed = USB_SPEED_UNKNOWN; - - /* Disable and detach IRQs */ - - up_disable_irq(LPC43M4_IRQ_USB0); - irq_detach(LPC43M4_IRQ_USB0); - - /* Reset the controller */ - - lpc43_putreg (USBDEV_USBCMD_RST, LPC43_USBDEV_USBCMD); - while (lpc43_getreg (LPC43_USBDEV_USBCMD) & USBDEV_USBCMD_RST) - ; - - /* Turn off USB power and clocking */ - - lpc43_pll0usbdisable(); - - irqrestore(flags); -} - -/******************************************************************************* - * Name: usbdev_register - * - * Description: - * Register a USB device class driver. The class driver's bind() method will be - * called to bind it to a USB device driver. - * - *******************************************************************************/ - -int usbdev_register(struct usbdevclass_driver_s *driver) -{ - int ret; - - usbtrace(TRACE_DEVREGISTER, 0); - -#ifdef CONFIG_DEBUG - if (!driver || !driver->ops->bind || !driver->ops->unbind || - !driver->ops->disconnect || !driver->ops->setup) - { - usbtrace(TRACE_DEVERROR(LPC43_TRACEERR_INVALIDPARMS), 0); - return -EINVAL; - } - - if (g_usbdev.driver) - { - usbtrace(TRACE_DEVERROR(LPC43_TRACEERR_DRIVER), 0); - return -EBUSY; - } -#endif - - /* First hook up the driver */ - - g_usbdev.driver = driver; - - /* Then bind the class driver */ - - ret = CLASS_BIND(driver, &g_usbdev.usbdev); - if (ret) - { - usbtrace(TRACE_DEVERROR(LPC43_TRACEERR_BINDFAILED), (uint16_t)-ret); - g_usbdev.driver = NULL; - } - else - { - /* Enable USB controller interrupts */ - - up_enable_irq(LPC43M4_IRQ_USB0); - - /* FIXME: nothing seems to call DEV_CONNECT(), but we need to set - * the RS bit to enable the controller. It kind of makes sense - * to do this after the class has bound to us... - * GEN: This bug is really in the class driver. It should make the - * soft connect when it is ready to be enumerated. I have added - * that logic to the class drivers but left this logic here. - */ - - lpc43_pullup(&g_usbdev.usbdev, true); - } - - return ret; -} - -/******************************************************************************* - * Name: usbdev_unregister - * - * Description: - * Un-register usbdev class driver.If the USB device is connected to a USB host, - * it will first disconnect(). The driver is also requested to unbind() and clean - * up any device state, before this procedure finally returns. - * - *******************************************************************************/ - -int usbdev_unregister(struct usbdevclass_driver_s *driver) -{ - usbtrace(TRACE_DEVUNREGISTER, 0); - -#ifdef CONFIG_DEBUG - if (driver != g_usbdev.driver) - { - usbtrace(TRACE_DEVERROR(LPC43_TRACEERR_INVALIDPARMS), 0); - return -EINVAL; - } -#endif - - /* Unbind the class driver */ - - CLASS_UNBIND(driver, &g_usbdev.usbdev); - - /* Disable USB controller interrupts */ - - up_disable_irq(LPC43M4_IRQ_USB0); - - /* Unhook the driver */ - - g_usbdev.driver = NULL; - return OK; -} +/******************************************************************************* + * arch/arm/src/lpc43xx/lpc43_usbdev.c + * + * Copyright (C) 2012-2013 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Part of the NuttX OS and based, in part, on the LPC31xx USB driver: + * + * Authors: David Hewson + * Gregory Nutt + * + * Which, in turn, was based on the LPC2148 USB driver: + * + * Copyright (C) 2010-2012 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + *******************************************************************************/ + +/******************************************************************************* + * Included Files + *******************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include "chip.h" +#include "up_arch.h" +#include "up_internal.h" + +#include "lpc43_usb0dev.h" +#include "lpc43_creg.h" +#include "lpc43_ccu.h" +#include "lpc43_cgu.h" +#include "lpc43_rgu.h" + +/******************************************************************************* + * Pre-processor Definitions + *******************************************************************************/ + +/* Configuration ***************************************************************/ + +#ifndef CONFIG_USBDEV_EP0_MAXSIZE +# define CONFIG_USBDEV_EP0_MAXSIZE 64 +#endif + +#ifndef CONFIG_USBDEV_MAXPOWER +# define CONFIG_USBDEV_MAXPOWER 100 /* mA */ +#endif + +/* Extremely detailed register debug that you would normally never want + * enabled. + */ + +#undef CONFIG_LPC43_USBDEV_REGDEBUG + +/* Enable reading SOF from interrupt handler vs. simply reading on demand. Probably + * a bad idea... Unless there is some issue with sampling the SOF from hardware + * asynchronously. + */ + +#ifdef CONFIG_LPC43_USBDEV_FRAME_INTERRUPT +# define USB_FRAME_INT USBDEV_USBINTR_SRE +#else +# define USB_FRAME_INT 0 +#endif + +#ifdef CONFIG_DEBUG +# define USB_ERROR_INT USBDEV_USBINTR_UEE +#else +# define USB_ERROR_INT 0 +#endif + +/* Debug ***********************************************************************/ + +/* Trace error codes */ + +#define LPC43_TRACEERR_ALLOCFAIL 0x0001 +#define LPC43_TRACEERR_BADCLEARFEATURE 0x0002 +#define LPC43_TRACEERR_BADDEVGETSTATUS 0x0003 +#define LPC43_TRACEERR_BADEPNO 0x0004 +#define LPC43_TRACEERR_BADEPGETSTATUS 0x0005 +#define LPC43_TRACEERR_BADEPTYPE 0x0006 +#define LPC43_TRACEERR_BADGETCONFIG 0x0007 +#define LPC43_TRACEERR_BADGETSETDESC 0x0008 +#define LPC43_TRACEERR_BADGETSTATUS 0x0009 +#define LPC43_TRACEERR_BADSETADDRESS 0x000a +#define LPC43_TRACEERR_BADSETCONFIG 0x000b +#define LPC43_TRACEERR_BADSETFEATURE 0x000c +#define LPC43_TRACEERR_BINDFAILED 0x000d +#define LPC43_TRACEERR_DISPATCHSTALL 0x000e +#define LPC43_TRACEERR_DRIVER 0x000f +#define LPC43_TRACEERR_DRIVERREGISTERED 0x0010 +#define LPC43_TRACEERR_EP0SETUPSTALLED 0x0011 +#define LPC43_TRACEERR_EPINNULLPACKET 0x0012 +#define LPC43_TRACEERR_EPOUTNULLPACKET 0x0013 +#define LPC43_TRACEERR_INVALIDCTRLREQ 0x0014 +#define LPC43_TRACEERR_INVALIDPARMS 0x0015 +#define LPC43_TRACEERR_IRQREGISTRATION 0x0016 +#define LPC43_TRACEERR_NOEP 0x0017 +#define LPC43_TRACEERR_NOTCONFIGURED 0x0018 +#define LPC43_TRACEERR_REQABORTED 0x0019 + +/* Trace interrupt codes */ + +#define LPC43_TRACEINTID_USB 0x0001 +#define LPC43_TRACEINTID_CLEARFEATURE 0x0002 +#define LPC43_TRACEINTID_DEVGETSTATUS 0x0003 +#define LPC43_TRACEINTID_DEVRESET 0x0004 +#define LPC43_TRACEINTID_DISPATCH 0x0005 +#define LPC43_TRACEINTID_EP0COMPLETE 0x0006 +#define LPC43_TRACEINTID_EP0NAK 0x0007 +#define LPC43_TRACEINTID_EP0SETUP 0x0008 +#define LPC43_TRACEINTID_EPGETSTATUS 0x0009 +#define LPC43_TRACEINTID_EPIN 0x000a +#define LPC43_TRACEINTID_EPINQEMPTY 0x000b +#define LPC43_TRACEINTID_EP0INSETADDRESS 0x000c +#define LPC43_TRACEINTID_EPOUT 0x000d +#define LPC43_TRACEINTID_EPOUTQEMPTY 0x000e +#define LPC43_TRACEINTID_EP0SETUPSETADDRESS 0x000f +#define LPC43_TRACEINTID_FRAME 0x0010 +#define LPC43_TRACEINTID_GETCONFIG 0x0011 +#define LPC43_TRACEINTID_GETSETDESC 0x0012 +#define LPC43_TRACEINTID_GETSETIF 0x0013 +#define LPC43_TRACEINTID_GETSTATUS 0x0014 +#define LPC43_TRACEINTID_IFGETSTATUS 0x0015 +#define LPC43_TRACEINTID_SETCONFIG 0x0016 +#define LPC43_TRACEINTID_SETFEATURE 0x0017 +#define LPC43_TRACEINTID_SUSPENDED 0x0018 +#define LPC43_TRACEINTID_RESUMED 0x0019 +#define LPC43_TRACEINTID_SYNCHFRAME 0x001a + +/* Hardware interface **********************************************************/ + +/* This represents a Endpoint Transfer Descriptor - note these must be 32 byte + * aligned. + */ + +struct lpc43_dtd_s +{ + volatile uint32_t nextdesc; /* Address of the next DMA descripto in RAM */ + volatile uint32_t config; /* Misc. bit encoded configuration information */ + uint32_t buffer0; /* Buffer start address */ + uint32_t buffer1; /* Buffer start address */ + uint32_t buffer2; /* Buffer start address */ + uint32_t buffer3; /* Buffer start address */ + uint32_t buffer4; /* Buffer start address */ + uint32_t xfer_len; /* Software only - transfer len that was queued */ +}; + +/* DTD nextdesc field */ + +#define DTD_NEXTDESC_INVALID (1 << 0) /* Bit 0 : Next Descriptor Invalid */ + +/* DTD config field */ + +#define DTD_CONFIG_LENGTH(n) ((n) << 16) /* Bits 16-31 : Total bytes to transfer */ +#define DTD_CONFIG_IOC (1 << 15) /* Bit 15 : Interrupt on Completion */ +#define DTD_CONFIG_MULT_VARIABLE (0 << 10) /* Bits 10-11 : Number of packets executed per transacation descriptor (override) */ +#define DTD_CONFIG_MULT_NUM(n) ((n) << 10) +#define DTD_CONFIG_ACTIVE (1 << 7) /* Bit 7 : Status Active */ +#define DTD_CONFIG_HALTED (1 << 6) /* Bit 6 : Status Halted */ +#define DTD_CONFIG_BUFFER_ERROR (1 << 5) /* Bit 6 : Status Buffer Error */ +#define DTD_CONFIG_TRANSACTION_ERROR (1 << 3) /* Bit 3 : Status Transaction Error */ + +/* This represents a queue head - not these must be aligned to a 2048 byte boundary */ + +struct lpc43_dqh_s +{ + uint32_t capability; /* Endpoint capability */ + uint32_t currdesc; /* Current dTD pointer */ + struct lpc43_dtd_s overlay; /* DTD overlay */ + volatile uint32_t setup[2]; /* Set-up buffer */ + uint32_t gap[4]; /* align to 64 bytes */ +}; + +/* DQH capability field */ + +#define DQH_CAPABILITY_MULT_VARIABLE (0 << 30) /* Bits 30-31 : Number of packets executed per transaction descriptor */ +#define DQH_CAPABILITY_MULT_NUM(n) ((n) << 30) +#define DQH_CAPABILITY_ZLT (1 << 29) /* Bit 29 : Zero Length Termination Select */ +#define DQH_CAPABILITY_MAX_PACKET(n) ((n) << 16) /* Bits 16-29 : Maximum packet size of associated endpoint (<1024) */ +#define DQH_CAPABILITY_IOS (1 << 15) /* Bit 15 : Interrupt on Setup */ + +/* Endpoints ******************************************************************/ + +/* Number of endpoints */ + +#define LPC43_NLOGENDPOINTS (4) /* ep0-3 */ +#define LPC43_NPHYSENDPOINTS (8) /* x2 for IN and OUT */ + +/* Odd physical endpoint numbers are IN; even are OUT */ + +#define LPC43_EPPHYIN(epphy) (((epphy)&1)!=0) +#define LPC43_EPPHYOUT(epphy) (((epphy)&1)==0) + +#define LPC43_EPPHYIN2LOG(epphy) (((uint8_t)(epphy)>>1)|USB_DIR_IN) +#define LPC43_EPPHYOUT2LOG(epphy) (((uint8_t)(epphy)>>1)|USB_DIR_OUT) + +/* Endpoint 0 is special... */ + +#define LPC43_EP0_OUT (0) +#define LPC43_EP0_IN (1) + +/* Each endpoint has somewhat different characteristics */ + +#define LPC43_EPALLSET (0xff) /* All endpoints */ +#define LPC43_EPOUTSET (0x55) /* Even phy endpoint numbers are OUT EPs */ +#define LPC43_EPINSET (0xaa) /* Odd endpoint numbers are IN EPs */ +#define LPC43_EPCTRLSET (0x03) /* EP0 IN/OUT are control endpoints */ +#define LPC43_EPINTRSET (0xa8) /* Interrupt endpoints */ +#define LPC43_EPBULKSET (0xfc) /* Bulk endpoints */ +#define LPC43_EPISOCSET (0xfc) /* Isochronous endpoints */ + +/* Maximum packet sizes for endpoints */ + +#define LPC43_EP0MAXPACKET (64) /* EP0 max packet size (1-64) */ +#define LPC43_BULKMAXPACKET (512) /* Bulk endpoint max packet (8/16/32/64/512) */ +#define LPC43_INTRMAXPACKET (1024) /* Interrupt endpoint max packet (1 to 1024) */ +#define LPC43_ISOCMAXPACKET (512) /* Acutally 1..1023 */ + +/* Endpoint bit position in SETUPSTAT, PRIME, FLUSH, STAT, COMPLETE registers */ + +#define LPC43_ENDPTSHIFT(epphy) (LPC43_EPPHYIN(epphy) ? (16 + ((epphy) >> 1)) : ((epphy) >> 1)) +#define LPC43_ENDPTMASK(epphy) (1 << LPC43_ENDPTSHIFT(epphy)) +#define LPC43_ENDPTMASK_ALL 0x000f000f + +/* Request queue operations ****************************************************/ + +#define lpc43_rqempty(ep) ((ep)->head == NULL) +#define lpc43_rqpeek(ep) ((ep)->head) + +/******************************************************************************* + * Private Types + *******************************************************************************/ + +/* A container for a request so that the request may be retained in a list */ + +struct lpc43_req_s +{ + struct usbdev_req_s req; /* Standard USB request */ + struct lpc43_req_s *flink; /* Supports a singly linked list */ +}; + +/* This is the internal representation of an endpoint */ + +struct lpc43_ep_s +{ + /* Common endpoint fields. This must be the first thing defined in the + * structure so that it is possible to simply cast from struct usbdev_ep_s + * to struct lpc43_ep_s. + */ + + struct usbdev_ep_s ep; /* Standard endpoint structure */ + + /* LPC43XX-specific fields */ + + struct lpc43_usbdev_s *dev; /* Reference to private driver data */ + struct lpc43_req_s *head; /* Request list for this endpoint */ + struct lpc43_req_s *tail; + uint8_t epphy; /* Physical EP address */ + uint8_t stalled:1; /* 1: Endpoint is stalled */ +}; + +/* This structure retains the state of the USB device controller */ + +struct lpc43_usbdev_s +{ + /* Common device fields. This must be the first thing defined in the + * structure so that it is possible to simply cast from struct usbdev_s + * to struct lpc43_usbdev_s. + */ + + struct usbdev_s usbdev; + + /* The bound device class driver */ + + struct usbdevclass_driver_s *driver; + + /* LPC43XX-specific fields */ + + uint8_t ep0state; /* State of certain EP0 operations */ + uint8_t ep0buf[64]; /* buffer for EP0 short transfers */ + uint8_t paddr; /* Address assigned by SETADDRESS */ + uint8_t stalled:1; /* 1: Protocol stalled */ + uint8_t selfpowered:1; /* 1: Device is self powered */ + uint8_t paddrset:1; /* 1: Peripheral addr has been set */ + uint8_t attached:1; /* 1: Host attached */ + uint8_t suspended:1; /* 1: Suspended */ + uint32_t softprio; /* Bitset of high priority interrupts */ + uint32_t epavail; /* Bitset of available endpoints */ +#ifdef CONFIG_LPC43_USBDEV_FRAME_INTERRUPT + uint32_t sof; /* Last start-of-frame */ +#endif + + /* The endpoint list */ + + struct lpc43_ep_s eplist[LPC43_NPHYSENDPOINTS]; +}; + +#define EP0STATE_IDLE 0 /* Idle State, leave on receiving a setup packet or epsubmit */ +#define EP0STATE_SETUP_OUT 1 /* Setup Packet received - SET/CLEAR */ +#define EP0STATE_SETUP_IN 2 /* Setup Packet received - GET */ +#define EP0STATE_SHORTWRITE 3 /* Short write without a usb_request */ +#define EP0STATE_WAIT_NAK_OUT 4 /* Waiting for Host to illicit status phase (GET) */ +#define EP0STATE_WAIT_NAK_IN 5 /* Waiting for Host to illicit status phase (SET/CLEAR) */ +#define EP0STATE_WAIT_STATUS_OUT 6 /* Wait for status phase to complete */ +#define EP0STATE_WAIT_STATUS_IN 7 /* Wait for status phase to complete */ +#define EP0STATE_DATA_IN 8 +#define EP0STATE_DATA_OUT 9 + +/******************************************************************************* + * Private Function Prototypes + *******************************************************************************/ + +/* Register operations ********************************************************/ + +#if defined(CONFIG_LPC43_USBDEV_REGDEBUG) && defined(CONFIG_DEBUG) +static uint32_t lpc43_getreg(uint32_t addr); +static void lpc43_putreg(uint32_t val, uint32_t addr); +#else +# define lpc43_getreg(addr) getreg32(addr) +# define lpc43_putreg(val,addr) putreg32(val,addr) +#endif + +static inline void lpc43_clrbits(uint32_t mask, uint32_t addr); +static inline void lpc43_setbits(uint32_t mask, uint32_t addr); +static inline void lpc43_chgbits(uint32_t mask, uint32_t val, uint32_t addr); + +/* Request queue operations ****************************************************/ + +static FAR struct lpc43_req_s *lpc43_rqdequeue(FAR struct lpc43_ep_s *privep); +static bool lpc43_rqenqueue(FAR struct lpc43_ep_s *privep, + FAR struct lpc43_req_s *req); + +/* Low level data transfers and request operations *****************************/ + +static inline void lpc43_writedtd(struct lpc43_dtd_s *dtd, const uint8_t *data, + uint32_t nbytes); +static inline void lpc43_queuedtd(uint8_t epphy, struct lpc43_dtd_s *dtd); +static inline void lpc43_ep0xfer(uint8_t epphy, uint8_t *data, uint32_t nbytes); +static void lpc43_readsetup(uint8_t epphy, struct usb_ctrlreq_s *ctrl); + +static inline void lpc43_set_address(struct lpc43_usbdev_s *priv, uint16_t address); + +static void lpc43_flushep(struct lpc43_ep_s *privep); + +static int lpc43_progressep(struct lpc43_ep_s *privep); +static inline void lpc43_abortrequest(struct lpc43_ep_s *privep, + struct lpc43_req_s *privreq, int16_t result); +static void lpc43_reqcomplete(struct lpc43_ep_s *privep, + struct lpc43_req_s *privreq, int16_t result); + +static void lpc43_cancelrequests(struct lpc43_ep_s *privep, int16_t status); + +/* Interrupt handling **********************************************************/ + +static struct lpc43_ep_s *lpc43_epfindbyaddr(struct lpc43_usbdev_s *priv, + uint16_t eplog); +static void lpc43_dispatchrequest(struct lpc43_usbdev_s *priv, + const struct usb_ctrlreq_s *ctrl); +static void lpc43_ep0configure(struct lpc43_usbdev_s *priv); +static void lpc43_usbreset(struct lpc43_usbdev_s *priv); + +static inline void lpc43_ep0state(struct lpc43_usbdev_s *priv, uint16_t state); +static void lpc43_ep0setup(struct lpc43_usbdev_s *priv); + +static void lpc43_ep0complete(struct lpc43_usbdev_s *priv, uint8_t epphy); +static void lpc43_ep0nak(struct lpc43_usbdev_s *priv, uint8_t epphy); +static bool lpc43_epcomplete(struct lpc43_usbdev_s *priv, uint8_t epphy); + +static int lpc43_usbinterrupt(int irq, FAR void *context); + +/* Endpoint operations *********************************************************/ + +/* USB device controller operations ********************************************/ + +static int lpc43_epconfigure(FAR struct usbdev_ep_s *ep, + const struct usb_epdesc_s *desc, bool last); +static int lpc43_epdisable(FAR struct usbdev_ep_s *ep); +static FAR struct usbdev_req_s *lpc43_epallocreq(FAR struct usbdev_ep_s *ep); +static void lpc43_epfreereq(FAR struct usbdev_ep_s *ep, + FAR struct usbdev_req_s *); +#ifdef CONFIG_USBDEV_DMA +static void *lpc43_epallocbuffer(FAR struct usbdev_ep_s *ep, unsigned bytes); +static void lpc43_epfreebuffer(FAR struct usbdev_ep_s *ep, FAR void *buf); +#endif +static int lpc43_epsubmit(FAR struct usbdev_ep_s *ep, + struct usbdev_req_s *req); +static int lpc43_epcancel(FAR struct usbdev_ep_s *ep, + struct usbdev_req_s *req); +static int lpc43_epstall(FAR struct usbdev_ep_s *ep, bool resume); + +static FAR struct usbdev_ep_s *lpc43_allocep(FAR struct usbdev_s *dev, + uint8_t epno, bool in, uint8_t eptype); +static void lpc43_freeep(FAR struct usbdev_s *dev, FAR struct usbdev_ep_s *ep); +static int lpc43_getframe(struct usbdev_s *dev); +static int lpc43_wakeup(struct usbdev_s *dev); +static int lpc43_selfpowered(struct usbdev_s *dev, bool selfpowered); +static int lpc43_pullup(struct usbdev_s *dev, bool enable); + +/******************************************************************************* + * Private Data + *******************************************************************************/ + +/* Since there is only a single USB interface, all status information can be + * be simply retained in a single global instance. + */ + +static struct lpc43_usbdev_s g_usbdev; + +static struct lpc43_dqh_s __attribute__((aligned(2048))) g_qh[LPC43_NPHYSENDPOINTS]; +static struct lpc43_dtd_s __attribute__((aligned(32))) g_td[LPC43_NPHYSENDPOINTS]; + +static const struct usbdev_epops_s g_epops = +{ + .configure = lpc43_epconfigure, + .disable = lpc43_epdisable, + .allocreq = lpc43_epallocreq, + .freereq = lpc43_epfreereq, +#ifdef CONFIG_USBDEV_DMA + .allocbuffer = lpc43_epallocbuffer, + .freebuffer = lpc43_epfreebuffer, +#endif + .submit = lpc43_epsubmit, + .cancel = lpc43_epcancel, + .stall = lpc43_epstall, +}; + +static const struct usbdev_ops_s g_devops = +{ + .allocep = lpc43_allocep, + .freeep = lpc43_freeep, + .getframe = lpc43_getframe, + .wakeup = lpc43_wakeup, + .selfpowered = lpc43_selfpowered, + .pullup = lpc43_pullup, +}; + +/******************************************************************************* + * Public Data + *******************************************************************************/ + +/******************************************************************************* + * Private Functions + *******************************************************************************/ + +/******************************************************************************* + * Name: lpc43_getreg + * + * Description: + * Get the contents of an LPC433x register + * + *******************************************************************************/ + +#if defined(CONFIG_LPC43_USBDEV_REGDEBUG) && defined(CONFIG_DEBUG) +static uint32_t lpc43_getreg(uint32_t addr) +{ + static uint32_t prevaddr = 0; + static uint32_t preval = 0; + static uint32_t count = 0; + + /* Read the value from the register */ + + uint32_t val = getreg32(addr); + + /* Is this the same value that we read from the same registe last time? Are + * we polling the register? If so, suppress some of the output. + */ + + if (addr == prevaddr && val == preval) + { + if (count == 0xffffffff || ++count > 3) + { + if (count == 4) + { + lldbg("...\n"); + } + return val; + } + } + + /* No this is a new address or value */ + + else + { + /* Did we print "..." for the previous value? */ + + if (count > 3) + { + /* Yes.. then show how many times the value repeated */ + + lldbg("[repeats %d more times]\n", count-3); + } + + /* Save the new address, value, and count */ + + prevaddr = addr; + preval = val; + count = 1; + } + + /* Show the register value read */ + + lldbg("%08x->%08x\n", addr, val); + return val; +} +#endif + +/******************************************************************************* + * Name: lpc43_putreg + * + * Description: + * Set the contents of an LPC433x register to a value + * + *******************************************************************************/ + +#if defined(CONFIG_LPC43_USBDEV_REGDEBUG) && defined(CONFIG_DEBUG) +static void lpc43_putreg(uint32_t val, uint32_t addr) +{ + /* Show the register value being written */ + + lldbg("%08x<-%08x\n", addr, val); + + /* Write the value */ + + putreg32(val, addr); +} +#endif + +/******************************************************************************* + * Name: lpc43_clrbits + * + * Description: + * Clear bits in a register + * + *******************************************************************************/ + +static inline void lpc43_clrbits(uint32_t mask, uint32_t addr) +{ + uint32_t reg = lpc43_getreg(addr); + reg &= ~mask; + lpc43_putreg(reg, addr); +} + +/******************************************************************************* + * Name: lpc43_setbits + * + * Description: + * Set bits in a register + * + *******************************************************************************/ + +static inline void lpc43_setbits(uint32_t mask, uint32_t addr) +{ + uint32_t reg = lpc43_getreg(addr); + reg |= mask; + lpc43_putreg(reg, addr); +} + +/******************************************************************************* + * Name: lpc43_chgbits + * + * Description: + * Change bits in a register + * + *******************************************************************************/ + +static inline void lpc43_chgbits(uint32_t mask, uint32_t val, uint32_t addr) +{ + uint32_t reg = lpc43_getreg(addr); + reg &= ~mask; + reg |= val; + lpc43_putreg(reg, addr); +} + +/******************************************************************************* + * Name: lpc43_rqdequeue + * + * Description: + * Remove a request from an endpoint request queue + * + *******************************************************************************/ + +static FAR struct lpc43_req_s *lpc43_rqdequeue(FAR struct lpc43_ep_s *privep) +{ + FAR struct lpc43_req_s *ret = privep->head; + + if (ret) + { + privep->head = ret->flink; + if (!privep->head) + { + privep->tail = NULL; + } + + ret->flink = NULL; + } + + return ret; +} + +/******************************************************************************* + * Name: lpc43_rqenqueue + * + * Description: + * Add a request from an endpoint request queue + * + *******************************************************************************/ + +static bool lpc43_rqenqueue(FAR struct lpc43_ep_s *privep, + FAR struct lpc43_req_s *req) +{ + bool is_empty = !privep->head; + + req->flink = NULL; + if (is_empty) + { + privep->head = req; + privep->tail = req; + } + else + { + privep->tail->flink = req; + privep->tail = req; + } + + return is_empty; +} + +/******************************************************************************* + * Name: lpc43_writedtd + * + * Description: + * Initialise a DTD to transfer the data + * + *******************************************************************************/ + +static inline void lpc43_writedtd(struct lpc43_dtd_s *dtd, const uint8_t *data, uint32_t nbytes) +{ + dtd->nextdesc = DTD_NEXTDESC_INVALID; + dtd->config = DTD_CONFIG_LENGTH(nbytes) | DTD_CONFIG_IOC | DTD_CONFIG_ACTIVE; + dtd->buffer0 = ((uint32_t) data); + dtd->buffer1 = (((uint32_t) data) + 0x1000) & 0xfffff000; + dtd->buffer2 = (((uint32_t) data) + 0x2000) & 0xfffff000; + dtd->buffer3 = (((uint32_t) data) + 0x3000) & 0xfffff000; + dtd->buffer4 = (((uint32_t) data) + 0x4000) & 0xfffff000; + dtd->xfer_len = nbytes; +} + +/******************************************************************************* + * Name: lpc43_queuedtd + * + * Description: + * Add the DTD to the device list + * + *******************************************************************************/ + +static void lpc43_queuedtd(uint8_t epphy, struct lpc43_dtd_s *dtd) +{ + /* Queue the DTD onto the Endpoint */ + /* NOTE - this only works when no DTD is currently queued */ + + g_qh[epphy].overlay.nextdesc = (uint32_t) dtd; + g_qh[epphy].overlay.config &= ~(DTD_CONFIG_ACTIVE | DTD_CONFIG_HALTED); + + uint32_t bit = LPC43_ENDPTMASK(epphy); + + lpc43_setbits (bit, LPC43_USBDEV_ENDPTPRIME); + + while (lpc43_getreg (LPC43_USBDEV_ENDPTPRIME) & bit) + ; +} + +/******************************************************************************* + * Name: lpc43_ep0xfer + * + * Description: + * Schedule a short transfer for Endpoint 0 (IN or OUT) + * + *******************************************************************************/ + +static inline void lpc43_ep0xfer(uint8_t epphy, uint8_t *buf, uint32_t nbytes) +{ + struct lpc43_dtd_s *dtd = &g_td[epphy]; + + lpc43_writedtd(dtd, buf, nbytes); + + lpc43_queuedtd(epphy, dtd); +} + +/******************************************************************************* + * Name: lpc43_readsetup + * + * Description: + * Read a Setup packet from the DTD. + * + *******************************************************************************/ +static void lpc43_readsetup(uint8_t epphy, struct usb_ctrlreq_s *ctrl) +{ + struct lpc43_dqh_s *dqh = &g_qh[epphy]; + int i; + + do + { + /* Set the trip wire */ + + lpc43_setbits(USBDEV_USBCMD_SUTW, LPC43_USBDEV_USBCMD); + + /* Copy the request... */ + + for (i = 0; i < 8; i++) + { + ((uint8_t *) ctrl)[i] = ((uint8_t *) dqh->setup)[i]; + } + } + while (!(lpc43_getreg(LPC43_USBDEV_USBCMD) & USBDEV_USBCMD_SUTW)); + + /* Clear the trip wire */ + + lpc43_clrbits(USBDEV_USBCMD_SUTW, LPC43_USBDEV_USBCMD); + + /* Clear the Setup Interrupt */ + + lpc43_putreg (LPC43_ENDPTMASK(LPC43_EP0_OUT), LPC43_USBDEV_ENDPTSETUPSTAT); +} + +/******************************************************************************* + * Name: lpc43_set_address + * + * Description: + * Set the devices USB address + * + *******************************************************************************/ + +static inline void lpc43_set_address(struct lpc43_usbdev_s *priv, uint16_t address) +{ + priv->paddr = address; + priv->paddrset = address != 0; + + lpc43_chgbits(USBDEV_DEVICEADDR_MASK, priv->paddr << USBDEV_DEVICEADDR_SHIFT, + LPC43_USBDEV_DEVICEADDR); +} + +/******************************************************************************* + * Name: lpc43_flushep + * + * Description: + * Flush any primed descriptors from this ep + * + *******************************************************************************/ + +static void lpc43_flushep(struct lpc43_ep_s *privep) +{ + uint32_t mask = LPC43_ENDPTMASK(privep->epphy); + do + { + lpc43_putreg (mask, LPC43_USBDEV_ENDPTFLUSH); + while ((lpc43_getreg(LPC43_USBDEV_ENDPTFLUSH) & mask) != 0) + ; + } + while ((lpc43_getreg(LPC43_USBDEV_ENDPTSTATUS) & mask) != 0); +} + + +/******************************************************************************* + * Name: lpc43_progressep + * + * Description: + * Progress the Endpoint by priming the first request into the queue head + * + *******************************************************************************/ + +static int lpc43_progressep(struct lpc43_ep_s *privep) +{ + struct lpc43_dtd_s *dtd = &g_td[privep->epphy]; + struct lpc43_req_s *privreq; + + /* Check the request from the head of the endpoint request queue */ + + privreq = lpc43_rqpeek(privep); + if (!privreq) + { + usbtrace(TRACE_INTDECODE(LPC43_TRACEINTID_EPINQEMPTY), 0); + return OK; + } + + /* Ignore any attempt to send a zero length packet */ + + if (privreq->req.len == 0) + { + /* If the class driver is responding to a setup packet, then wait for + * the host to illicit thr response + */ + + if (privep->epphy == LPC43_EP0_IN && privep->dev->ep0state == EP0STATE_SETUP_OUT) + { + lpc43_ep0state (privep->dev, EP0STATE_WAIT_NAK_IN); + } + else + { + if (LPC43_EPPHYIN(privep->epphy)) + { + usbtrace(TRACE_DEVERROR(LPC43_TRACEERR_EPINNULLPACKET), 0); + } + else + { + usbtrace(TRACE_DEVERROR(LPC43_TRACEERR_EPOUTNULLPACKET), 0); + } + } + + lpc43_reqcomplete(privep, lpc43_rqdequeue(privep), OK); + return OK; + } + + if (privep->epphy == LPC43_EP0_IN) + { + lpc43_ep0state (privep->dev, EP0STATE_DATA_IN); + } + else if (privep->epphy == LPC43_EP0_OUT) + { + lpc43_ep0state (privep->dev, EP0STATE_DATA_OUT); + } + + int bytesleft = privreq->req.len - privreq->req.xfrd; + + if (LPC43_EPPHYIN(privep->epphy)) + { + usbtrace(TRACE_WRITE(privep->epphy), privreq->req.xfrd); + } + else + { + usbtrace(TRACE_READ(privep->epphy), privreq->req.xfrd); + } + + /* Initialise the DTD to transfer the next chunk */ + + lpc43_writedtd (dtd, privreq->req.buf + privreq->req.xfrd, bytesleft); + + /* Then queue onto the DQH */ + + lpc43_queuedtd(privep->epphy, dtd); + + return OK; +} + +/******************************************************************************* + * Name: lpc43_abortrequest + * + * Description: + * Discard a request + * + *******************************************************************************/ + +static inline void lpc43_abortrequest(struct lpc43_ep_s *privep, + struct lpc43_req_s *privreq, + int16_t result) +{ + usbtrace(TRACE_DEVERROR(LPC43_TRACEERR_REQABORTED), (uint16_t)privep->epphy); + + /* Save the result in the request structure */ + + privreq->req.result = result; + + /* Callback to the request completion handler */ + + privreq->req.callback(&privep->ep, &privreq->req); +} + +/******************************************************************************* + * Name: lpc43_reqcomplete + * + * Description: + * Handle termination of the request at the head of the endpoint request queue. + * + *******************************************************************************/ + +static void lpc43_reqcomplete(struct lpc43_ep_s *privep, + struct lpc43_req_s *privreq, int16_t result) +{ + /* If endpoint 0, temporarily reflect the state of protocol stalled + * in the callback. + */ + + bool stalled = privep->stalled; + if (privep->epphy == LPC43_EP0_IN) + privep->stalled = privep->dev->stalled; + + /* Save the result in the request structure */ + + privreq->req.result = result; + + /* Callback to the request completion handler */ + + privreq->req.callback(&privep->ep, &privreq->req); + + /* Restore the stalled indication */ + + privep->stalled = stalled; +} + +/******************************************************************************* + * Name: lpc43_cancelrequests + * + * Description: + * Cancel all pending requests for an endpoint + * + *******************************************************************************/ + +static void lpc43_cancelrequests(struct lpc43_ep_s *privep, int16_t status) +{ + if (!lpc43_rqempty(privep)) + lpc43_flushep(privep); + + while (!lpc43_rqempty(privep)) + { + // FIXME: the entry at the head should be sync'd with the DTD + // FIXME: only report the error status if the transfer hasn't completed + usbtrace(TRACE_COMPLETE(privep->epphy), + (lpc43_rqpeek(privep))->req.xfrd); + lpc43_reqcomplete(privep, lpc43_rqdequeue(privep), status); + } +} + +/******************************************************************************* + * Name: lpc43_epfindbyaddr + * + * Description: + * Find the physical endpoint structure corresponding to a logic endpoint + * address + * + *******************************************************************************/ + +static struct lpc43_ep_s *lpc43_epfindbyaddr(struct lpc43_usbdev_s *priv, + uint16_t eplog) +{ + struct lpc43_ep_s *privep; + int i; + + /* Endpoint zero is a special case */ + + if (USB_EPNO(eplog) == 0) + { + return &priv->eplist[0]; + } + + /* Handle the remaining */ + + for (i = 1; i < LPC43_NPHYSENDPOINTS; i++) + { + privep = &priv->eplist[i]; + + /* Same logical endpoint number? (includes direction bit) */ + + if (eplog == privep->ep.eplog) + { + /* Return endpoint found */ + + return privep; + } + } + + /* Return endpoint not found */ + + return NULL; +} + +/******************************************************************************* + * Name: lpc43_dispatchrequest + * + * Description: + * Provide unhandled setup actions to the class driver. This is logically part + * of the USB interrupt handler. + * + *******************************************************************************/ + +static void lpc43_dispatchrequest(struct lpc43_usbdev_s *priv, + const struct usb_ctrlreq_s *ctrl) +{ + int ret = -EIO; + + usbtrace(TRACE_INTDECODE(LPC43_TRACEINTID_DISPATCH), 0); + if (priv->driver) + { + /* Forward to the control request to the class driver implementation */ + + ret = CLASS_SETUP(priv->driver, &priv->usbdev, ctrl, NULL, 0); + } + + if (ret < 0) + { + /* Stall on failure */ + + usbtrace(TRACE_DEVERROR(LPC43_TRACEERR_DISPATCHSTALL), 0); + priv->stalled = true; + } +} + +/******************************************************************************* + * Name: lpc43_ep0configure + * + * Description: + * Reset Usb engine + * + *******************************************************************************/ + +static void lpc43_ep0configure(struct lpc43_usbdev_s *priv) +{ + /* Enable ep0 IN and ep0 OUT */ + + g_qh[LPC43_EP0_OUT].capability = (DQH_CAPABILITY_MAX_PACKET(CONFIG_USBDEV_EP0_MAXSIZE) | + DQH_CAPABILITY_IOS | + DQH_CAPABILITY_ZLT); + + g_qh[LPC43_EP0_IN ].capability = (DQH_CAPABILITY_MAX_PACKET(CONFIG_USBDEV_EP0_MAXSIZE) | + DQH_CAPABILITY_IOS | + DQH_CAPABILITY_ZLT); + + g_qh[LPC43_EP0_OUT].currdesc = DTD_NEXTDESC_INVALID; + g_qh[LPC43_EP0_IN ].currdesc = DTD_NEXTDESC_INVALID; + + /* Enable EP0 */ + + lpc43_setbits (USBDEV_ENDPTCTRL0_RXE | USBDEV_ENDPTCTRL0_TXE, LPC43_USBDEV_ENDPTCTRL0); +} + +/******************************************************************************* + * Name: lpc43_usbreset + * + * Description: + * Reset Usb engine + * + *******************************************************************************/ + +static void lpc43_usbreset(struct lpc43_usbdev_s *priv) +{ + int epphy; + + /* Disable all endpoints. Control endpoint 0 is always enabled */ + + lpc43_clrbits (USBDEV_ENDPTCTRL_RXE | USBDEV_ENDPTCTRL_TXE, LPC43_USBDEV_ENDPTCTRL1); + lpc43_clrbits (USBDEV_ENDPTCTRL_RXE | USBDEV_ENDPTCTRL_TXE, LPC43_USBDEV_ENDPTCTRL2); + lpc43_clrbits (USBDEV_ENDPTCTRL_RXE | USBDEV_ENDPTCTRL_TXE, LPC43_USBDEV_ENDPTCTRL3); + + /* Clear all pending interrupts */ + + lpc43_putreg (lpc43_getreg(LPC43_USBDEV_ENDPTNAK), LPC43_USBDEV_ENDPTNAK); + lpc43_putreg (lpc43_getreg(LPC43_USBDEV_ENDPTSETUPSTAT), LPC43_USBDEV_ENDPTSETUPSTAT); + lpc43_putreg (lpc43_getreg(LPC43_USBDEV_ENDPTCOMPLETE), LPC43_USBDEV_ENDPTCOMPLETE); + + /* Wait for all prime operations to have completed and then flush all DTDs */ + + while (lpc43_getreg (LPC43_USBDEV_ENDPTPRIME) != 0) + ; + lpc43_putreg (LPC43_ENDPTMASK_ALL, LPC43_USBDEV_ENDPTFLUSH); + while (lpc43_getreg (LPC43_USBDEV_ENDPTFLUSH)) + ; + + /* Reset endpoints */ + + for (epphy = 0; epphy < LPC43_NPHYSENDPOINTS; epphy++) + { + struct lpc43_ep_s *privep = &priv->eplist[epphy]; + + lpc43_cancelrequests (privep, -ESHUTDOWN); + + /* Reset endpoint status */ + + privep->stalled = false; + } + + /* Tell the class driver that we are disconnected. The class + * driver should then accept any new configurations. */ + + if (priv->driver) + { + CLASS_DISCONNECT(priv->driver, &priv->usbdev); + } + + /* Set the interrupt Threshold control interval to 0 */ + + lpc43_chgbits(USBDEV_USBCMD_ITC_MASK, USBDEV_USBCMD_ITCIMME, LPC43_USBDEV_USBCMD); + + /* Zero out the Endpoint queue heads */ + + memset ((void *) g_qh, 0, sizeof (g_qh)); + memset ((void *) g_td, 0, sizeof (g_td)); + + /* Set USB address to 0 */ + + lpc43_set_address (priv, 0); + + /* Initialise the Enpoint List Address */ + + lpc43_putreg ((uint32_t)g_qh, LPC43_USBDEV_ENDPOINTLIST); + + /* EndPoint 0 initialization */ + + lpc43_ep0configure(priv); + + /* Enable Device interrupts */ + + lpc43_putreg(USB_FRAME_INT | USB_ERROR_INT | + USBDEV_USBINTR_NAKE | USBDEV_USBINTR_SLE | USBDEV_USBINTR_URE | USBDEV_USBINTR_PCE | USBDEV_USBINTR_UE, + LPC43_USBDEV_USBINTR); +} + +/******************************************************************************* + * Name: lpc43_setstate + * + * Description: + * Sets the EP0 state and manages the NAK interrupts + * + *******************************************************************************/ + +static inline void lpc43_ep0state(struct lpc43_usbdev_s *priv, uint16_t state) +{ + priv->ep0state = state; + + switch (state) + { + case EP0STATE_WAIT_NAK_IN: + lpc43_putreg (LPC43_ENDPTMASK(LPC43_EP0_IN), LPC43_USBDEV_ENDPTNAKEN); + break; + + case EP0STATE_WAIT_NAK_OUT: + lpc43_putreg (LPC43_ENDPTMASK(LPC43_EP0_OUT), LPC43_USBDEV_ENDPTNAKEN); + break; + + default: + lpc43_putreg(0, LPC43_USBDEV_ENDPTNAKEN); + break; + } +} + +/******************************************************************************* + * Name: lpc43_ep0setup + * + * Description: + * USB Ctrl EP Setup Event. This is logically part of the USB interrupt + * handler. This event occurs when a setup packet is receive on EP0 OUT. + * + *******************************************************************************/ + +static inline void lpc43_ep0setup(struct lpc43_usbdev_s *priv) +{ + struct lpc43_ep_s *privep; + struct usb_ctrlreq_s ctrl; + uint16_t value; + uint16_t index; + uint16_t len; + + /* Terminate any pending requests - since all DTDs will have been retired + * because of the setup packet. + */ + + lpc43_cancelrequests(&priv->eplist[LPC43_EP0_OUT], -EPROTO); + lpc43_cancelrequests(&priv->eplist[LPC43_EP0_IN], -EPROTO); + + /* Assume NOT stalled */ + + priv->eplist[LPC43_EP0_OUT].stalled = false; + priv->eplist[LPC43_EP0_IN].stalled = false; + priv->stalled = false; + + /* Read EP0 setup data */ + + lpc43_readsetup(LPC43_EP0_OUT, &ctrl); + + /* Starting a control request - update state */ + + lpc43_ep0state (priv, (ctrl.type & USB_REQ_DIR_IN) ? EP0STATE_SETUP_IN : EP0STATE_SETUP_OUT); + + /* And extract the little-endian 16-bit values to host order */ + + value = GETUINT16(ctrl.value); + index = GETUINT16(ctrl.index); + len = GETUINT16(ctrl.len); + + ullvdbg("type=%02x req=%02x value=%04x index=%04x len=%04x\n", + ctrl.type, ctrl.req, value, index, len); + + /* Dispatch any non-standard requests */ + + if ((ctrl.type & USB_REQ_TYPE_MASK) != USB_REQ_TYPE_STANDARD) + { + lpc43_dispatchrequest(priv, &ctrl); + } + else + { + /* Handle standard request. Pick off the things of interest to the USB + * device controller driver; pass what is left to the class driver. + */ + + switch (ctrl.req) + { + case USB_REQ_GETSTATUS: + { + /* type: device-to-host; recipient = device, interface, endpoint + * value: 0 + * index: zero interface endpoint + * len: 2; data = status + */ + + usbtrace(TRACE_INTDECODE(LPC43_TRACEINTID_GETSTATUS), 0); + if (!priv->paddrset || len != 2 || + (ctrl.type & USB_REQ_DIR_IN) == 0 || value != 0) + { + priv->stalled = true; + } + else + { + switch (ctrl.type & USB_REQ_RECIPIENT_MASK) + { + case USB_REQ_RECIPIENT_ENDPOINT: + { + usbtrace(TRACE_INTDECODE(LPC43_TRACEINTID_EPGETSTATUS), 0); + privep = lpc43_epfindbyaddr(priv, index); + if (!privep) + { + usbtrace(TRACE_DEVERROR(LPC43_TRACEERR_BADEPGETSTATUS), 0); + priv->stalled = true; + } + else + { + if (privep->stalled) + { + priv->ep0buf[0] = 1; /* Stalled */ + } + else + { + priv->ep0buf[0] = 0; /* Not stalled */ + } + + priv->ep0buf[1] = 0; + + lpc43_ep0xfer (LPC43_EP0_IN, priv->ep0buf, 2); + lpc43_ep0state (priv, EP0STATE_SHORTWRITE); + } + } + break; + + case USB_REQ_RECIPIENT_DEVICE: + { + if (index == 0) + { + usbtrace(TRACE_INTDECODE(LPC43_TRACEINTID_DEVGETSTATUS), 0); + + /* Features: Remote Wakeup=YES; selfpowered=? */ + + priv->ep0buf[0] = (priv->selfpowered << USB_FEATURE_SELFPOWERED) | + (1 << USB_FEATURE_REMOTEWAKEUP); + priv->ep0buf[1] = 0; + + lpc43_ep0xfer(LPC43_EP0_IN, priv->ep0buf, 2); + lpc43_ep0state (priv, EP0STATE_SHORTWRITE); + } + else + { + usbtrace(TRACE_DEVERROR(LPC43_TRACEERR_BADDEVGETSTATUS), 0); + priv->stalled = true; + } + } + break; + + case USB_REQ_RECIPIENT_INTERFACE: + { + usbtrace(TRACE_INTDECODE(LPC43_TRACEINTID_IFGETSTATUS), 0); + priv->ep0buf[0] = 0; + priv->ep0buf[1] = 0; + + lpc43_ep0xfer(LPC43_EP0_IN, priv->ep0buf, 2); + lpc43_ep0state (priv, EP0STATE_SHORTWRITE); + } + break; + + default: + { + usbtrace(TRACE_DEVERROR(LPC43_TRACEERR_BADGETSTATUS), 0); + priv->stalled = true; + } + break; + } + } + } + break; + + case USB_REQ_CLEARFEATURE: + { + /* type: host-to-device; recipient = device, interface or endpoint + * value: feature selector + * index: zero interface endpoint; + * len: zero, data = none + */ + + usbtrace(TRACE_INTDECODE(LPC43_TRACEINTID_CLEARFEATURE), 0); + if ((ctrl.type & USB_REQ_RECIPIENT_MASK) != USB_REQ_RECIPIENT_ENDPOINT) + { + lpc43_dispatchrequest(priv, &ctrl); + } + else if (priv->paddrset != 0 && value == USB_FEATURE_ENDPOINTHALT && len == 0 && + (privep = lpc43_epfindbyaddr(priv, index)) != NULL) + { + lpc43_epstall(&privep->ep, true); + lpc43_ep0state (priv, EP0STATE_WAIT_NAK_IN); + } + else + { + usbtrace(TRACE_DEVERROR(LPC43_TRACEERR_BADCLEARFEATURE), 0); + priv->stalled = true; + } + } + break; + + case USB_REQ_SETFEATURE: + { + /* type: host-to-device; recipient = device, interface, endpoint + * value: feature selector + * index: zero interface endpoint; + * len: 0; data = none + */ + + usbtrace(TRACE_INTDECODE(LPC43_TRACEINTID_SETFEATURE), 0); + if (((ctrl.type & USB_REQ_RECIPIENT_MASK) == USB_REQ_RECIPIENT_DEVICE) && + value == USB_FEATURE_TESTMODE) + { + ullvdbg("test mode: %d\n", index); + } + else if ((ctrl.type & USB_REQ_RECIPIENT_MASK) != USB_REQ_RECIPIENT_ENDPOINT) + { + lpc43_dispatchrequest(priv, &ctrl); + } + else if (priv->paddrset != 0 && value == USB_FEATURE_ENDPOINTHALT && len == 0 && + (privep = lpc43_epfindbyaddr(priv, index)) != NULL) + { + lpc43_epstall(&privep->ep, false); + lpc43_ep0state (priv, EP0STATE_WAIT_NAK_IN); + } + else + { + usbtrace(TRACE_DEVERROR(LPC43_TRACEERR_BADSETFEATURE), 0); + priv->stalled = true; + } + } + break; + + case USB_REQ_SETADDRESS: + { + /* type: host-to-device; recipient = device + * value: device address + * index: 0 + * len: 0; data = none + */ + + usbtrace(TRACE_INTDECODE(LPC43_TRACEINTID_EP0SETUPSETADDRESS), value); + if ((ctrl.type & USB_REQ_RECIPIENT_MASK) == USB_REQ_RECIPIENT_DEVICE && + index == 0 && len == 0 && value < 128) + { + /* Save the address. We cannot actually change to the next address until + * the completion of the status phase. */ + + priv->paddr = ctrl.value[0]; + priv->paddrset = false; + lpc43_ep0state (priv, EP0STATE_WAIT_NAK_IN); + } + else + { + usbtrace(TRACE_DEVERROR(LPC43_TRACEERR_BADSETADDRESS), 0); + priv->stalled = true; + } + } + break; + + case USB_REQ_GETDESCRIPTOR: + /* type: device-to-host; recipient = device + * value: descriptor type and index + * index: 0 or language ID; + * len: descriptor len; data = descriptor + */ + case USB_REQ_SETDESCRIPTOR: + /* type: host-to-device; recipient = device + * value: descriptor type and index + * index: 0 or language ID; + * len: descriptor len; data = descriptor + */ + { + usbtrace(TRACE_INTDECODE(LPC43_TRACEINTID_GETSETDESC), 0); + if ((ctrl.type & USB_REQ_RECIPIENT_MASK) == USB_REQ_RECIPIENT_DEVICE) + { + lpc43_dispatchrequest(priv, &ctrl); + } + else + { + usbtrace(TRACE_DEVERROR(LPC43_TRACEERR_BADGETSETDESC), 0); + priv->stalled = true; + } + } + break; + + case USB_REQ_GETCONFIGURATION: + /* type: device-to-host; recipient = device + * value: 0; + * index: 0; + * len: 1; data = configuration value + */ + { + usbtrace(TRACE_INTDECODE(LPC43_TRACEINTID_GETCONFIG), 0); + if (priv->paddrset && (ctrl.type & USB_REQ_RECIPIENT_MASK) == USB_REQ_RECIPIENT_DEVICE && + value == 0 && index == 0 && len == 1) + { + lpc43_dispatchrequest(priv, &ctrl); + } + else + { + usbtrace(TRACE_DEVERROR(LPC43_TRACEERR_BADGETCONFIG), 0); + priv->stalled = true; + } + } + break; + + case USB_REQ_SETCONFIGURATION: + /* type: host-to-device; recipient = device + * value: configuration value + * index: 0; + * len: 0; data = none + */ + { + usbtrace(TRACE_INTDECODE(LPC43_TRACEINTID_SETCONFIG), 0); + if ((ctrl.type & USB_REQ_RECIPIENT_MASK) == USB_REQ_RECIPIENT_DEVICE && + index == 0 && len == 0) + { + lpc43_dispatchrequest(priv, &ctrl); + } + else + { + usbtrace(TRACE_DEVERROR(LPC43_TRACEERR_BADSETCONFIG), 0); + priv->stalled = true; + } + } + break; + + case USB_REQ_GETINTERFACE: + /* type: device-to-host; recipient = interface + * value: 0 + * index: interface; + * len: 1; data = alt interface + */ + case USB_REQ_SETINTERFACE: + /* type: host-to-device; recipient = interface + * value: alternate setting + * index: interface; + * len: 0; data = none + */ + { + usbtrace(TRACE_INTDECODE(LPC43_TRACEINTID_GETSETIF), 0); + lpc43_dispatchrequest(priv, &ctrl); + } + break; + + case USB_REQ_SYNCHFRAME: + /* type: device-to-host; recipient = endpoint + * value: 0 + * index: endpoint; + * len: 2; data = frame number + */ + { + usbtrace(TRACE_INTDECODE(LPC43_TRACEINTID_SYNCHFRAME), 0); + } + break; + + default: + { + usbtrace(TRACE_DEVERROR(LPC43_TRACEERR_INVALIDCTRLREQ), 0); + priv->stalled = true; + } + break; + } + } + + if (priv->stalled) + { + usbtrace(TRACE_DEVERROR(LPC43_TRACEERR_EP0SETUPSTALLED), priv->ep0state); + lpc43_epstall(&priv->eplist[LPC43_EP0_IN].ep, false); + lpc43_epstall(&priv->eplist[LPC43_EP0_OUT].ep, false); + } +} + +/******************************************************************************* + * Name: lpc43_ep0complete + * + * Description: + * Transfer complete handler for Endpoint 0 + * + *******************************************************************************/ + +static void lpc43_ep0complete(struct lpc43_usbdev_s *priv, uint8_t epphy) +{ + struct lpc43_ep_s *privep = &priv->eplist[epphy]; + + usbtrace(TRACE_INTDECODE(LPC43_TRACEINTID_EP0COMPLETE), (uint16_t)priv->ep0state); + + switch (priv->ep0state) + { + case EP0STATE_DATA_IN: + if (lpc43_rqempty(privep)) + { + return; + } + + if (lpc43_epcomplete (priv, epphy)) + { + lpc43_ep0state (priv, EP0STATE_WAIT_NAK_OUT); + } + break; + + case EP0STATE_DATA_OUT: + if (lpc43_rqempty(privep)) + { + return; + } + + if (lpc43_epcomplete (priv, epphy)) + { + lpc43_ep0state (priv, EP0STATE_WAIT_NAK_IN); + } + break; + + case EP0STATE_SHORTWRITE: + lpc43_ep0state (priv, EP0STATE_WAIT_NAK_OUT); + break; + + case EP0STATE_WAIT_STATUS_IN: + lpc43_ep0state (priv, EP0STATE_IDLE); + + /* If we've received a SETADDRESS packet, then we set the address + * now that the status phase has completed + */ + + if (! priv->paddrset && priv->paddr != 0) + { + usbtrace(TRACE_INTDECODE(LPC43_TRACEINTID_EP0INSETADDRESS), (uint16_t)priv->paddr); + lpc43_set_address (priv, priv->paddr); + } + + break; + + case EP0STATE_WAIT_STATUS_OUT: + lpc43_ep0state (priv, EP0STATE_IDLE); + break; + + default: +#ifdef CONFIG_DEBUG + DEBUGASSERT(priv->ep0state != EP0STATE_DATA_IN && + priv->ep0state != EP0STATE_DATA_OUT && + priv->ep0state != EP0STATE_SHORTWRITE && + priv->ep0state != EP0STATE_WAIT_STATUS_IN && + priv->ep0state != EP0STATE_WAIT_STATUS_OUT); +#endif + priv->stalled = true; + break; + } + + if (priv->stalled) + { + usbtrace(TRACE_DEVERROR(LPC43_TRACEERR_EP0SETUPSTALLED), priv->ep0state); + lpc43_epstall(&priv->eplist[LPC43_EP0_IN].ep, false); + lpc43_epstall(&priv->eplist[LPC43_EP0_OUT].ep, false); + } +} + +/******************************************************************************* + * Name: lpc43_ep0nak + * + * Description: + * Handle a NAK interrupt on EP0 + * + *******************************************************************************/ + +static void lpc43_ep0nak(struct lpc43_usbdev_s *priv, uint8_t epphy) +{ + usbtrace(TRACE_INTDECODE(LPC43_TRACEINTID_EP0NAK), (uint16_t)priv->ep0state); + + switch (priv->ep0state) + { + case EP0STATE_WAIT_NAK_IN: + lpc43_ep0xfer (LPC43_EP0_IN, NULL, 0); + lpc43_ep0state (priv, EP0STATE_WAIT_STATUS_IN); + break; + + case EP0STATE_WAIT_NAK_OUT: + lpc43_ep0xfer (LPC43_EP0_OUT, NULL, 0); + lpc43_ep0state (priv, EP0STATE_WAIT_STATUS_OUT); + break; + + default: +#ifdef CONFIG_DEBUG + DEBUGASSERT(priv->ep0state != EP0STATE_WAIT_NAK_IN && + priv->ep0state != EP0STATE_WAIT_NAK_OUT); +#endif + priv->stalled = true; + break; + } + + if (priv->stalled) + { + usbtrace(TRACE_DEVERROR(LPC43_TRACEERR_EP0SETUPSTALLED), priv->ep0state); + lpc43_epstall(&priv->eplist[LPC43_EP0_IN].ep, false); + lpc43_epstall(&priv->eplist[LPC43_EP0_OUT].ep, false); + } +} + +/******************************************************************************* + * Name: lpc43_epcomplete + * + * Description: + * Transfer complete handler for Endpoints other than 0 + * returns whether the request at the head has completed + * + *******************************************************************************/ + +bool lpc43_epcomplete(struct lpc43_usbdev_s *priv, uint8_t epphy) +{ + struct lpc43_ep_s *privep = &priv->eplist[epphy]; + struct lpc43_req_s *privreq = privep->head; + struct lpc43_dtd_s *dtd = &g_td[epphy]; + + if (privreq == NULL) /* This shouldn't really happen */ + { + if (LPC43_EPPHYOUT(privep->epphy)) + { + usbtrace(TRACE_INTDECODE(LPC43_TRACEINTID_EPINQEMPTY), 0); + } + else + { + usbtrace(TRACE_INTDECODE(LPC43_TRACEINTID_EPOUTQEMPTY), 0); + } + + return true; + } + + int xfrd = dtd->xfer_len - (dtd->config >> 16); + + privreq->req.xfrd += xfrd; + + bool complete = true; + if (LPC43_EPPHYOUT(privep->epphy)) + { + /* read(OUT) completes when request filled, or a short transfer is received */ + + usbtrace(TRACE_INTDECODE(LPC43_TRACEINTID_EPIN), complete); + } + else + { + /* write(IN) completes when request finished, unless we need to terminate with a ZLP */ + + bool need_zlp = (xfrd == privep->ep.maxpacket) && ((privreq->req.flags & USBDEV_REQFLAGS_NULLPKT) != 0); + + complete = (privreq->req.xfrd >= privreq->req.len && !need_zlp); + + usbtrace(TRACE_INTDECODE(LPC43_TRACEINTID_EPOUT), complete); + } + + /* If the transfer is complete, then dequeue and progress any further queued requests */ + + if (complete) + { + privreq = lpc43_rqdequeue (privep); + } + + if (!lpc43_rqempty(privep)) + { + lpc43_progressep(privep); + } + + /* Now it's safe to call the completion callback as it may well submit a new request */ + + if (complete) + { + usbtrace(TRACE_COMPLETE(privep->epphy), privreq->req.xfrd); + lpc43_reqcomplete(privep, privreq, OK); + } + + return complete; +} + + +/******************************************************************************* + * Name: lpc43_usbinterrupt + * + * Description: + * USB interrupt handler + * + *******************************************************************************/ + +static int lpc43_usbinterrupt(int irq, FAR void *context) +{ + struct lpc43_usbdev_s *priv = &g_usbdev; + uint32_t disr, portsc1, n; + + usbtrace(TRACE_INTENTRY(LPC43_TRACEINTID_USB), 0); + + /* Read the interrupts and then clear them */ + + disr = lpc43_getreg(LPC43_USBDEV_USBSTS); + lpc43_putreg(disr, LPC43_USBDEV_USBSTS); + + if (disr & USBDEV_USBSTS_URI) + { + usbtrace(TRACE_INTDECODE(LPC43_TRACEINTID_DEVRESET),0); + + lpc43_usbreset(priv); + + usbtrace(TRACE_INTEXIT(LPC43_TRACEINTID_USB), 0); + return OK; + } + + /* When the device controller enters a suspend state from an active state, + * the SLI bit will be set to a one. + */ + + if (!priv->suspended && (disr & USBDEV_USBSTS_SLI) != 0) + { + usbtrace(TRACE_INTDECODE(LPC43_TRACEINTID_SUSPENDED),0); + + /* Inform the Class driver of the suspend event */ + + priv->suspended = 1; + if (priv->driver) + { + CLASS_SUSPEND(priv->driver, &priv->usbdev); + } + + /* TODO: Perform power management operations here. */ + } + + /* The device controller clears the SLI bit upon exiting from a suspend + * state. This bit can also be cleared by software writing a one to it. + */ + + else if (priv->suspended && (disr & USBDEV_USBSTS_SLI) == 0) + { + usbtrace(TRACE_INTDECODE(LPC43_TRACEINTID_RESUMED),0); + + /* Inform the Class driver of the resume event */ + + priv->suspended = 0; + if (priv->driver) + { + CLASS_RESUME(priv->driver, &priv->usbdev); + } + + /* TODO: Perform power management operations here. */ + } + + if (disr & USBDEV_USBSTS_PCI) + { + portsc1 = lpc43_getreg(LPC43_USBDEV_PORTSC1); + + if (portsc1 & USBDEV_PRTSC1_HSP) + priv->usbdev.speed = USB_SPEED_HIGH; + else + priv->usbdev.speed = USB_SPEED_FULL; + + if (portsc1 & USBDEV_PRTSC1_FPR) + { + /* FIXME: this occurs because of a J-to-K transition detected + * while the port is in SUSPEND state - presumambly this + * is where the host is resuming the device? + * + * - but do we need to "ack" the interrupt + */ + } + } + +#ifdef CONFIG_LPC43_USBDEV_FRAME_INTERRUPT + if (disr & USBDEV_USBSTT_SRI) + { + usbtrace(TRACE_INTDECODE(LPC43_TRACEINTID_FRAME), 0); + + priv->sof = (int)lpc43_getreg(LPC43_USBDEV_FRINDEX_OFFSET); + } +#endif + + if (disr & USBDEV_USBSTS_UEI) + { + /* FIXME: these occur when a transfer results in an error condition + * it is set alongside USBINT if the DTD also had its IOC + * bit set. */ + } + + if (disr & USBDEV_USBSTS_UI) + { + /* Handle completion interrupts */ + + uint32_t mask = lpc43_getreg (LPC43_USBDEV_ENDPTCOMPLETE); + + if (mask) + { + /* Clear any NAK interrupt and completion interrupts */ + + lpc43_putreg (mask, LPC43_USBDEV_ENDPTNAK); + lpc43_putreg (mask, LPC43_USBDEV_ENDPTCOMPLETE); + + if (mask & LPC43_ENDPTMASK(0)) + { + lpc43_ep0complete(priv, 0); + } + + if (mask & LPC43_ENDPTMASK(1)) + { + lpc43_ep0complete(priv, 1); + } + + for (n = 1; n < LPC43_NLOGENDPOINTS; n++) + { + if (mask & LPC43_ENDPTMASK((n << 1))) + { + lpc43_epcomplete (priv, (n << 1)); + } + + if (mask & LPC43_ENDPTMASK((n << 1)+1)) + { + lpc43_epcomplete(priv, (n << 1)+1); + } + } + } + + /* Handle setup interrupts */ + + uint32_t setupstat = lpc43_getreg(LPC43_USBDEV_ENDPTSETUPSTAT); + if (setupstat) + { + /* Clear the endpoint complete CTRL OUT and IN when a Setup is received */ + + lpc43_putreg(LPC43_ENDPTMASK(LPC43_EP0_IN) | LPC43_ENDPTMASK(LPC43_EP0_OUT), + LPC43_USBDEV_ENDPTCOMPLETE); + + if (setupstat & LPC43_ENDPTMASK(LPC43_EP0_OUT)) + { + usbtrace(TRACE_INTDECODE(LPC43_TRACEINTID_EP0SETUP), setupstat); + lpc43_ep0setup(priv); + } + } + } + + if (disr & USBDEV_USBSTS_NAKI) + { + uint32_t pending = lpc43_getreg(LPC43_USBDEV_ENDPTNAK) & lpc43_getreg(LPC43_USBDEV_ENDPTNAKEN); + if (pending) + { + /* We shouldn't see NAK interrupts except on Endpoint 0 */ + + if (pending & LPC43_ENDPTMASK(0)) + { + lpc43_ep0nak(priv, 0); + } + + if (pending & LPC43_ENDPTMASK(1)) + { + lpc43_ep0nak(priv, 1); + } + } + + /* Clear the interrupts */ + + lpc43_putreg(pending, LPC43_USBDEV_ENDPTNAK); + } + + usbtrace(TRACE_INTEXIT(LPC43_TRACEINTID_USB), 0); + return OK; +} + +/******************************************************************************* + * Endpoint operations + *******************************************************************************/ + +/******************************************************************************* + * Name: lpc43_epconfigure + * + * Description: + * Configure endpoint, making it usable + * + * Input Parameters: + * ep - the struct usbdev_ep_s instance obtained from allocep() + * desc - A struct usb_epdesc_s instance describing the endpoint + * last - true if this this last endpoint to be configured. Some hardware + * needs to take special action when all of the endpoints have been + * configured. + * + *******************************************************************************/ + +static int lpc43_epconfigure(FAR struct usbdev_ep_s *ep, + FAR const struct usb_epdesc_s *desc, + bool last) +{ + FAR struct lpc43_ep_s *privep = (FAR struct lpc43_ep_s *)ep; + + usbtrace(TRACE_EPCONFIGURE, privep->epphy); + DEBUGASSERT(desc->addr == ep->eplog); + + /* Initialise EP capabilities */ + + uint16_t maxsize = GETUINT16(desc->mxpacketsize); + if ((desc->attr & USB_EP_ATTR_XFERTYPE_MASK) == USB_EP_ATTR_XFER_ISOC) + { + g_qh[privep->epphy].capability = (DQH_CAPABILITY_MAX_PACKET(maxsize) | + DQH_CAPABILITY_IOS | + DQH_CAPABILITY_ZLT); + } + else + { + g_qh[privep->epphy].capability = (DQH_CAPABILITY_MAX_PACKET(maxsize) | + DQH_CAPABILITY_ZLT); + } + + /* Setup Endpoint Control Register */ + + if (LPC43_EPPHYIN(privep->epphy)) + { + /* Reset the data toggles */ + + uint32_t cfg = USBDEV_ENDPTCTRL_TXR; + + /* Set the endpoint type */ + + switch (desc->attr & USB_EP_ATTR_XFERTYPE_MASK) + { + case USB_EP_ATTR_XFER_CONTROL: cfg |= USBDEV_ENDPTCTRL_TXT_CTRL; break; + case USB_EP_ATTR_XFER_ISOC: cfg |= USBDEV_ENDPTCTRL_TXT_ISOC; break; + case USB_EP_ATTR_XFER_BULK: cfg |= USBDEV_ENDPTCTRL_TXT_BULK; break; + case USB_EP_ATTR_XFER_INT: cfg |= USBDEV_ENDPTCTRL_TXT_INTR; break; + } + + lpc43_chgbits (0xFFFF0000, cfg, LPC43_USBDEV_ENDPTCTRL(privep->epphy)); + } + else + { + /* Reset the data toggles */ + + uint32_t cfg = USBDEV_ENDPTCTRL_RXR; + + /* Set the endpoint type */ + + switch (desc->attr & USB_EP_ATTR_XFERTYPE_MASK) + { + case USB_EP_ATTR_XFER_CONTROL: cfg |= USBDEV_ENDPTCTRL_RXT_CTRL; break; + case USB_EP_ATTR_XFER_ISOC: cfg |= USBDEV_ENDPTCTRL_RXT_ISOC; break; + case USB_EP_ATTR_XFER_BULK: cfg |= USBDEV_ENDPTCTRL_RXT_BULK; break; + } + + lpc43_chgbits (0x0000FFFF, cfg, LPC43_USBDEV_ENDPTCTRL(privep->epphy)); + } + + /* Reset endpoint status */ + + privep->stalled = false; + + /* Enable the endpoint */ + + if (LPC43_EPPHYIN(privep->epphy)) + { + lpc43_setbits (USBDEV_ENDPTCTRL_TXE, LPC43_USBDEV_ENDPTCTRL(privep->epphy)); + } + else + { + lpc43_setbits (USBDEV_ENDPTCTRL_RXE, LPC43_USBDEV_ENDPTCTRL(privep->epphy)); + } + + return OK; +} + +/******************************************************************************* + * Name: lpc43_epdisable + * + * Description: + * The endpoint will no longer be used + * + *******************************************************************************/ + +static int lpc43_epdisable(FAR struct usbdev_ep_s *ep) +{ + FAR struct lpc43_ep_s *privep = (FAR struct lpc43_ep_s *)ep; + irqstate_t flags; + +#ifdef CONFIG_DEBUG + if (!ep) + { + usbtrace(TRACE_DEVERROR(LPC43_TRACEERR_INVALIDPARMS), 0); + return -EINVAL; + } +#endif + usbtrace(TRACE_EPDISABLE, privep->epphy); + + flags = irqsave(); + + /* Disable Endpoint */ + + if (LPC43_EPPHYIN(privep->epphy)) + { + lpc43_clrbits (USBDEV_ENDPTCTRL_TXE, LPC43_USBDEV_ENDPTCTRL(privep->epphy)); + } + else + { + lpc43_clrbits (USBDEV_ENDPTCTRL_RXE, LPC43_USBDEV_ENDPTCTRL(privep->epphy)); + } + + privep->stalled = true; + + /* Cancel any ongoing activity */ + + lpc43_cancelrequests(privep, -ESHUTDOWN); + + irqrestore(flags); + return OK; +} + +/******************************************************************************* + * Name: lpc43_epallocreq + * + * Description: + * Allocate an I/O request + * + *******************************************************************************/ + +static FAR struct usbdev_req_s *lpc43_epallocreq(FAR struct usbdev_ep_s *ep) +{ + FAR struct lpc43_req_s *privreq; + +#ifdef CONFIG_DEBUG + if (!ep) + { + usbtrace(TRACE_DEVERROR(LPC43_TRACEERR_INVALIDPARMS), 0); + return NULL; + } +#endif + usbtrace(TRACE_EPALLOCREQ, ((FAR struct lpc43_ep_s *)ep)->epphy); + + privreq = (FAR struct lpc43_req_s *)kmm_malloc(sizeof(struct lpc43_req_s)); + if (!privreq) + { + usbtrace(TRACE_DEVERROR(LPC43_TRACEERR_ALLOCFAIL), 0); + return NULL; + } + + memset(privreq, 0, sizeof(struct lpc43_req_s)); + return &privreq->req; +} + +/******************************************************************************* + * Name: lpc43_epfreereq + * + * Description: + * Free an I/O request + * + *******************************************************************************/ + +static void lpc43_epfreereq(FAR struct usbdev_ep_s *ep, FAR struct usbdev_req_s *req) +{ + FAR struct lpc43_req_s *privreq = (FAR struct lpc43_req_s *)req; + +#ifdef CONFIG_DEBUG + if (!ep || !req) + { + usbtrace(TRACE_DEVERROR(LPC43_TRACEERR_INVALIDPARMS), 0); + return; + } +#endif + + usbtrace(TRACE_EPFREEREQ, ((FAR struct lpc43_ep_s *)ep)->epphy); + kmm_free(privreq); +} + +/******************************************************************************* + * Name: lpc43_epallocbuffer + * + * Description: + * Allocate an I/O buffer + * + *******************************************************************************/ + +#ifdef CONFIG_USBDEV_DMA +static void *lpc43_epallocbuffer(FAR struct usbdev_ep_s *ep, unsigned bytes) +{ + usbtrace(TRACE_EPALLOCBUFFER, privep->epphy); + +#ifdef CONFIG_USBDEV_DMAMEMORY + return usbdev_dma_alloc(bytes); +#else + return kmm_malloc(bytes); +#endif +} +#endif + +/******************************************************************************* + * Name: lpc43_epfreebuffer + * + * Description: + * Free an I/O buffer + * + *******************************************************************************/ + +#ifdef CONFIG_USBDEV_DMA +static void lpc43_epfreebuffer(FAR struct usbdev_ep_s *ep, FAR void *buf) +{ + usbtrace(TRACE_EPFREEBUFFER, privep->epphy); + +#ifdef CONFIG_USBDEV_DMAMEMORY + usbdev_dma_free(buf); +#else + kmm_free(buf); +#endif +} +#endif + +/******************************************************************************* + * Name: lpc43_epsubmit + * + * Description: + * Submit an I/O request to the endpoint + * + *******************************************************************************/ + +static int lpc43_epsubmit(FAR struct usbdev_ep_s *ep, FAR struct usbdev_req_s *req) +{ + FAR struct lpc43_req_s *privreq = (FAR struct lpc43_req_s *)req; + FAR struct lpc43_ep_s *privep = (FAR struct lpc43_ep_s *)ep; + FAR struct lpc43_usbdev_s *priv; + irqstate_t flags; + int ret = OK; + +#ifdef CONFIG_DEBUG + if (!req || !req->callback || !req->buf || !ep) + { + usbtrace(TRACE_DEVERROR(LPC43_TRACEERR_INVALIDPARMS), 0); + ullvdbg("req=%p callback=%p buf=%p ep=%p\n", req, req->callback, req->buf, ep); + return -EINVAL; + } +#endif + + usbtrace(TRACE_EPSUBMIT, privep->epphy); + priv = privep->dev; + + if (!priv->driver || priv->usbdev.speed == USB_SPEED_UNKNOWN) + { + usbtrace(TRACE_DEVERROR(LPC43_TRACEERR_NOTCONFIGURED), priv->usbdev.speed); + return -ESHUTDOWN; + } + + /* Handle the request from the class driver */ + + req->result = -EINPROGRESS; + req->xfrd = 0; + + /* Disable Interrupts */ + + flags = irqsave(); + + /* If we are stalled, then drop all requests on the floor */ + + if (privep->stalled) + { + ret = -EBUSY; + } + else + { + /* Add the new request to the request queue for the endpoint */ + + if (LPC43_EPPHYIN(privep->epphy)) + { + usbtrace(TRACE_INREQQUEUED(privep->epphy), privreq->req.len); + } + else + { + usbtrace(TRACE_OUTREQQUEUED(privep->epphy), privreq->req.len); + } + + if (lpc43_rqenqueue(privep, privreq)) + { + lpc43_progressep(privep); + } + } + + irqrestore(flags); + return ret; +} + +/******************************************************************************* + * Name: lpc43_epcancel + * + * Description: + * Cancel an I/O request previously sent to an endpoint + * + *******************************************************************************/ + +static int lpc43_epcancel(FAR struct usbdev_ep_s *ep, FAR struct usbdev_req_s *req) +{ + FAR struct lpc43_ep_s *privep = (FAR struct lpc43_ep_s *)ep; + irqstate_t flags; + +#ifdef CONFIG_DEBUG + if (!ep || !req) + { + usbtrace(TRACE_DEVERROR(LPC43_TRACEERR_INVALIDPARMS), 0); + return -EINVAL; + } +#endif + + usbtrace(TRACE_EPCANCEL, privep->epphy); + + flags = irqsave(); + + /* FIXME: if the request is the first, then we need to flush the EP + * otherwise just remove it from the list + * + * but ... all other implementations cancel all requests ... + */ + + lpc43_cancelrequests(privep, -ESHUTDOWN); + irqrestore(flags); + return OK; +} + +/******************************************************************************* + * Name: lpc43_epstall + * + * Description: + * Stall or resume and endpoint + * + *******************************************************************************/ + +static int lpc43_epstall(FAR struct usbdev_ep_s *ep, bool resume) +{ + FAR struct lpc43_ep_s *privep = (FAR struct lpc43_ep_s *)ep; + irqstate_t flags; + + /* STALL or RESUME the endpoint */ + + flags = irqsave(); + usbtrace(resume ? TRACE_EPRESUME : TRACE_EPSTALL, privep->epphy); + + uint32_t addr = LPC43_USBDEV_ENDPTCTRL(privep->epphy); + uint32_t ctrl_xs = LPC43_EPPHYIN(privep->epphy) ? USBDEV_ENDPTCTRL_TXS : USBDEV_ENDPTCTRL_RXS; + uint32_t ctrl_xr = LPC43_EPPHYIN(privep->epphy) ? USBDEV_ENDPTCTRL_TXR : USBDEV_ENDPTCTRL_RXR; + + if (resume) + { + privep->stalled = false; + + /* Clear stall and reset the data toggle */ + + lpc43_chgbits (ctrl_xs | ctrl_xr, ctrl_xr, addr); + } + else + { + privep->stalled = true; + + lpc43_setbits (ctrl_xs, addr); + } + + irqrestore(flags); + return OK; +} + +/******************************************************************************* + * Device operations + *******************************************************************************/ + +/******************************************************************************* + * Name: lpc43_allocep + * + * Description: + * Allocate an endpoint matching the parameters. + * + * Input Parameters: + * eplog - 7-bit logical endpoint number (direction bit ignored). Zero means + * that any endpoint matching the other requirements will suffice. The + * assigned endpoint can be found in the eplog field. + * in - true: IN (device-to-host) endpoint requested + * eptype - Endpoint type. One of {USB_EP_ATTR_XFER_ISOC, USB_EP_ATTR_XFER_BULK, + * USB_EP_ATTR_XFER_INT} + * + *******************************************************************************/ + +static FAR struct usbdev_ep_s *lpc43_allocep(FAR struct usbdev_s *dev, uint8_t eplog, + bool in, uint8_t eptype) +{ + FAR struct lpc43_usbdev_s *priv = (FAR struct lpc43_usbdev_s *)dev; + uint32_t epset = LPC43_EPALLSET & ~LPC43_EPCTRLSET; + irqstate_t flags; + int epndx = 0; + + usbtrace(TRACE_DEVALLOCEP, (uint16_t)eplog); + + /* Ignore any direction bits in the logical address */ + + eplog = USB_EPNO(eplog); + + /* A logical address of 0 means that any endpoint will do */ + + if (eplog > 0) + { + /* Otherwise, we will return the endpoint structure only for the requested + * 'logical' endpoint. All of the other checks will still be performed. + * + * First, verify that the logical endpoint is in the range supported by + * by the hardware. + */ + + if (eplog >= LPC43_NLOGENDPOINTS) + { + usbtrace(TRACE_DEVERROR(LPC43_TRACEERR_BADEPNO), (uint16_t)eplog); + return NULL; + } + + /* Convert the logical address to a physical OUT endpoint address and + * remove all of the candidate endpoints from the bitset except for the + * the IN/OUT pair for this logical address. + */ + + epset &= 3 << (eplog << 1); + } + + /* Get the subset matching the requested direction */ + + if (in) + { + epset &= LPC43_EPINSET; + } + else + { + epset &= LPC43_EPOUTSET; + } + + /* Get the subset matching the requested type */ + + switch (eptype) + { + case USB_EP_ATTR_XFER_INT: /* Interrupt endpoint */ + epset &= LPC43_EPINTRSET; + break; + + case USB_EP_ATTR_XFER_BULK: /* Bulk endpoint */ + epset &= LPC43_EPBULKSET; + break; + + case USB_EP_ATTR_XFER_ISOC: /* Isochronous endpoint */ + epset &= LPC43_EPISOCSET; + break; + + case USB_EP_ATTR_XFER_CONTROL: /* Control endpoint -- not a valid choice */ + default: + usbtrace(TRACE_DEVERROR(LPC43_TRACEERR_BADEPTYPE), (uint16_t)eptype); + return NULL; + } + + /* Is the resulting endpoint supported by the LPC433x? */ + + if (epset) + { + /* Yes.. now see if any of the request endpoints are available */ + + flags = irqsave(); + epset &= priv->epavail; + if (epset) + { + /* Select the lowest bit in the set of matching, available endpoints */ + + for (epndx = 2; epndx < LPC43_NPHYSENDPOINTS; epndx++) + { + uint32_t bit = 1 << epndx; + if ((epset & bit) != 0) + { + /* Mark the IN/OUT endpoint no longer available */ + + priv->epavail &= ~(3 << (bit & ~1)); + irqrestore(flags); + + /* And return the pointer to the standard endpoint structure */ + + return &priv->eplist[epndx].ep; + } + } + + /* Shouldn't get here */ + + } + + irqrestore(flags); + } + + usbtrace(TRACE_DEVERROR(LPC43_TRACEERR_NOEP), (uint16_t)eplog); + return NULL; +} + +/******************************************************************************* + * Name: lpc43_freeep + * + * Description: + * Free the previously allocated endpoint + * + *******************************************************************************/ + +static void lpc43_freeep(FAR struct usbdev_s *dev, FAR struct usbdev_ep_s *ep) +{ + FAR struct lpc43_usbdev_s *priv = (FAR struct lpc43_usbdev_s *)dev; + FAR struct lpc43_ep_s *privep = (FAR struct lpc43_ep_s *)ep; + irqstate_t flags; + + usbtrace(TRACE_DEVFREEEP, (uint16_t)privep->epphy); + + if (priv && privep) + { + /* Mark the endpoint as available */ + + flags = irqsave(); + priv->epavail |= (1 << privep->epphy); + irqrestore(flags); + } +} + +/******************************************************************************* + * Name: lpc43_getframe + * + * Description: + * Returns the current frame number + * + *******************************************************************************/ + +static int lpc43_getframe(struct usbdev_s *dev) +{ +#ifdef CONFIG_LPC43_USBDEV_FRAME_INTERRUPT + FAR struct lpc43_usbdev_s *priv = (FAR struct lpc43_usbdev_s *)dev; + + /* Return last valid value of SOF read by the interrupt handler */ + + usbtrace(TRACE_DEVGETFRAME, (uint16_t)priv->sof); + return priv->sof; +#else + /* Return the last frame number detected by the hardware */ + + usbtrace(TRACE_DEVGETFRAME, 0); + + /* FIXME: this actually returns the micro frame number! */ + + return (int)lpc43_getreg(LPC43_USBDEV_FRINDEX_OFFSET); +#endif +} + +/******************************************************************************* + * Name: lpc43_wakeup + * + * Description: + * Tries to wake up the host connected to this device + * + *******************************************************************************/ + +static int lpc43_wakeup(struct usbdev_s *dev) +{ + irqstate_t flags; + + usbtrace(TRACE_DEVWAKEUP, 0); + + flags = irqsave(); + lpc43_setbits(USBDEV_PRTSC1_FPR, LPC43_USBDEV_PORTSC1); + irqrestore(flags); + return OK; +} + +/******************************************************************************* + * Name: lpc43_selfpowered + * + * Description: + * Sets/clears the device selfpowered feature + * + *******************************************************************************/ + +static int lpc43_selfpowered(struct usbdev_s *dev, bool selfpowered) +{ + FAR struct lpc43_usbdev_s *priv = (FAR struct lpc43_usbdev_s *)dev; + + usbtrace(TRACE_DEVSELFPOWERED, (uint16_t)selfpowered); + +#ifdef CONFIG_DEBUG + if (!dev) + { + usbtrace(TRACE_DEVERROR(LPC43_TRACEERR_INVALIDPARMS), 0); + return -ENODEV; + } +#endif + + priv->selfpowered = selfpowered; + return OK; +} + +/******************************************************************************* + * Name: lpc43_pullup + * + * Description: + * Software-controlled connect to/disconnect from USB host + * + *******************************************************************************/ + +static int lpc43_pullup(struct usbdev_s *dev, bool enable) +{ + usbtrace(TRACE_DEVPULLUP, (uint16_t)enable); + + irqstate_t flags = irqsave(); + if (enable) + { + lpc43_setbits (USBDEV_USBCMD_RS, LPC43_USBDEV_USBCMD); + } + else + { + lpc43_clrbits (USBDEV_USBCMD_RS, LPC43_USBDEV_USBCMD); + } + + irqrestore(flags); + return OK; +} + +/******************************************************************************* + * Public Functions + *******************************************************************************/ + +/******************************************************************************* + * Name: up_usbinitialize + * + * Description: + * Initialize USB hardware. + * + * Assumptions: + * - This function is called very early in the initialization sequence + * - PLL initialization is not performed here but should been in + * the low-level boot logic: PLL0 must be configured for operation at 480MHz + * + *******************************************************************************/ + +void up_usbinitialize(void) +{ + struct lpc43_usbdev_s *priv = &g_usbdev; + int i; + uint32_t regval; + + usbtrace(TRACE_DEVINIT, 0); + + /* Disable USB interrupts */ + + lpc43_putreg(0, LPC43_USBDEV_USBINTR); + + /* Initialize the device state structure */ + + memset(priv, 0, sizeof(struct lpc43_usbdev_s)); + priv->usbdev.ops = &g_devops; + priv->usbdev.ep0 = &priv->eplist[LPC43_EP0_IN].ep; + priv->epavail = LPC43_EPALLSET; + + /* Initialize the endpoint list */ + + for (i = 0; i < LPC43_NPHYSENDPOINTS; i++) + { + uint32_t bit = 1 << i; + + /* Set endpoint operations, reference to driver structure (not + * really necessary because there is only one controller), and + * the physical endpoint number (which is just the index to the + * endpoint). + */ + + priv->eplist[i].ep.ops = &g_epops; + priv->eplist[i].dev = priv; + + /* The index, i, is the physical endpoint address; Map this + * to a logical endpoint address usable by the class driver. + */ + + priv->eplist[i].epphy = i; + if (LPC43_EPPHYIN(i)) + { + priv->eplist[i].ep.eplog = LPC43_EPPHYIN2LOG(i); + } + else + { + priv->eplist[i].ep.eplog = LPC43_EPPHYOUT2LOG(i); + } + + /* The maximum packet size may depend on the type of endpoint */ + + if ((LPC43_EPCTRLSET & bit) != 0) + { + priv->eplist[i].ep.maxpacket = LPC43_EP0MAXPACKET; + } + else if ((LPC43_EPINTRSET & bit) != 0) + { + priv->eplist[i].ep.maxpacket = LPC43_INTRMAXPACKET; + } + else if ((LPC43_EPBULKSET & bit) != 0) + { + priv->eplist[i].ep.maxpacket = LPC43_BULKMAXPACKET; + } + else /* if ((LPC43_EPISOCSET & bit) != 0) */ + { + priv->eplist[i].ep.maxpacket = LPC43_ISOCMAXPACKET; + } + } + + + /* Clock */ + + regval = getreg32(LPC43_BASE_USB0_CLK); + regval &= ~BASE_USB0_CLK_CLKSEL_MASK; + regval |= (BASE_USB0_CLKSEL_PLL0USB | BASE_USB0_CLK_AUTOBLOCK); + putreg32(regval, LPC43_BASE_USB0_CLK); + + /* Clock run */ + + regval = getreg32(LPC43_CCU1_M4_USB0_CFG); + regval |= CCU_CLK_CFG_RUN; + putreg32(regval, LPC43_CCU1_M4_USB0_CFG); + + /* Enable PLL0 clock*/ + + lpc43_pll0usbconfig(); + lpc43_pll0usbenable(); + + /* Reset USB block */ + + lpc43_putreg(RGU_CTRL0_USB0_RST, LPC43_RGU_CTRL0); + + /* Reset the controller */ + + lpc43_putreg (USBDEV_USBCMD_RST, LPC43_USBDEV_USBCMD); + while (lpc43_getreg (LPC43_USBDEV_USBCMD) & USBDEV_USBCMD_RST) + ; + + /* Power PHY */ + + regval = getreg32(LPC43_CREG0); + regval &= ~CREG0_USB0PHY; + putreg32(regval, LPC43_CREG0); + + /* Attach USB controller interrupt handler */ + + if (irq_attach(LPC43M4_IRQ_USB0, lpc43_usbinterrupt) != 0) + { + usbtrace(TRACE_DEVERROR(LPC43_TRACEERR_IRQREGISTRATION), + (uint16_t)LPC43M4_IRQ_USB0); + goto errout; + } + + + /* Program the controller to be the USB device controller */ + + lpc43_putreg (USBDEV_USBMODE_SDIS | USBDEV_USBMODE_SLOM | USBDEV_USBMODE_CM_DEVICE, + LPC43_USBDEV_USBMODE); + + /* Disconnect device */ + + lpc43_pullup(&priv->usbdev, false); + + /* Reset/Re-initialize the USB hardware */ + + lpc43_usbreset(priv); + + return; + +errout: + up_usbuninitialize(); +} + +/******************************************************************************* + * Name: up_usbuninitialize + *******************************************************************************/ + +void up_usbuninitialize(void) +{ + struct lpc43_usbdev_s *priv = &g_usbdev; + irqstate_t flags; + + usbtrace(TRACE_DEVUNINIT, 0); + + if (priv->driver) + { + usbtrace(TRACE_DEVERROR(LPC43_TRACEERR_DRIVERREGISTERED), 0); + usbdev_unregister(priv->driver); + } + + /* Disconnect device */ + + flags = irqsave(); + lpc43_pullup(&priv->usbdev, false); + priv->usbdev.speed = USB_SPEED_UNKNOWN; + + /* Disable and detach IRQs */ + + up_disable_irq(LPC43M4_IRQ_USB0); + irq_detach(LPC43M4_IRQ_USB0); + + /* Reset the controller */ + + lpc43_putreg (USBDEV_USBCMD_RST, LPC43_USBDEV_USBCMD); + while (lpc43_getreg (LPC43_USBDEV_USBCMD) & USBDEV_USBCMD_RST) + ; + + /* Turn off USB power and clocking */ + + lpc43_pll0usbdisable(); + + irqrestore(flags); +} + +/******************************************************************************* + * Name: usbdev_register + * + * Description: + * Register a USB device class driver. The class driver's bind() method will be + * called to bind it to a USB device driver. + * + *******************************************************************************/ + +int usbdev_register(struct usbdevclass_driver_s *driver) +{ + int ret; + + usbtrace(TRACE_DEVREGISTER, 0); + +#ifdef CONFIG_DEBUG + if (!driver || !driver->ops->bind || !driver->ops->unbind || + !driver->ops->disconnect || !driver->ops->setup) + { + usbtrace(TRACE_DEVERROR(LPC43_TRACEERR_INVALIDPARMS), 0); + return -EINVAL; + } + + if (g_usbdev.driver) + { + usbtrace(TRACE_DEVERROR(LPC43_TRACEERR_DRIVER), 0); + return -EBUSY; + } +#endif + + /* First hook up the driver */ + + g_usbdev.driver = driver; + + /* Then bind the class driver */ + + ret = CLASS_BIND(driver, &g_usbdev.usbdev); + if (ret) + { + usbtrace(TRACE_DEVERROR(LPC43_TRACEERR_BINDFAILED), (uint16_t)-ret); + g_usbdev.driver = NULL; + } + else + { + /* Enable USB controller interrupts */ + + up_enable_irq(LPC43M4_IRQ_USB0); + + /* FIXME: nothing seems to call DEV_CONNECT(), but we need to set + * the RS bit to enable the controller. It kind of makes sense + * to do this after the class has bound to us... + * GEN: This bug is really in the class driver. It should make the + * soft connect when it is ready to be enumerated. I have added + * that logic to the class drivers but left this logic here. + */ + + lpc43_pullup(&g_usbdev.usbdev, true); + } + + return ret; +} + +/******************************************************************************* + * Name: usbdev_unregister + * + * Description: + * Un-register usbdev class driver.If the USB device is connected to a USB host, + * it will first disconnect(). The driver is also requested to unbind() and clean + * up any device state, before this procedure finally returns. + * + *******************************************************************************/ + +int usbdev_unregister(struct usbdevclass_driver_s *driver) +{ + usbtrace(TRACE_DEVUNREGISTER, 0); + +#ifdef CONFIG_DEBUG + if (driver != g_usbdev.driver) + { + usbtrace(TRACE_DEVERROR(LPC43_TRACEERR_INVALIDPARMS), 0); + return -EINVAL; + } +#endif + + /* Unbind the class driver */ + + CLASS_UNBIND(driver, &g_usbdev.usbdev); + + /* Disable USB controller interrupts */ + + up_disable_irq(LPC43M4_IRQ_USB0); + + /* Unhook the driver */ + + g_usbdev.driver = NULL; + return OK; +} From df5c815267dac81446e97814be73a7c03e831513 Mon Sep 17 00:00:00 2001 From: admin Date: Fri, 2 Oct 2015 12:14:09 +0200 Subject: [PATCH 04/14] return 0 if OK --- arch/arm/src/lpc43xx/lpc43_i2c.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/src/lpc43xx/lpc43_i2c.c b/arch/arm/src/lpc43xx/lpc43_i2c.c index cdb02002be6..848c6f5d554 100644 --- a/arch/arm/src/lpc43xx/lpc43_i2c.c +++ b/arch/arm/src/lpc43xx/lpc43_i2c.c @@ -356,7 +356,7 @@ static int i2c_transfer(FAR struct i2c_dev_s *dev, FAR struct i2c_msg_s *msgs, i priv->msgs = msgs; priv->nmsg = count; - ret = count - i2c_start(priv); + ret = i2c_start(priv); return ret; } From b91fbed6a604d6480b30a5ab771c70848e150e62 Mon Sep 17 00:00:00 2001 From: Lok Tep Date: Wed, 21 Oct 2015 17:35:52 +0200 Subject: [PATCH 05/14] address 7->8 --- arch/arm/src/lpc43xx/lpc43_i2c.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/arch/arm/src/lpc43xx/lpc43_i2c.c b/arch/arm/src/lpc43xx/lpc43_i2c.c index a3c8a2fab27..8dd3175e704 100644 --- a/arch/arm/src/lpc43xx/lpc43_i2c.c +++ b/arch/arm/src/lpc43xx/lpc43_i2c.c @@ -206,8 +206,7 @@ static int i2c_setaddress(FAR struct i2c_dev_s *dev, int addr, int nbits) DEBUGASSERT(dev != NULL); DEBUGASSERT(nbits == 7); - priv->msg.addr = addr << 1; - priv->msg.flags = 0 ; + priv->msg.addr = addr; return OK; } @@ -231,7 +230,7 @@ static int i2c_write(FAR struct i2c_dev_s *dev, const uint8_t *buffer, priv->wrcnt = 0; priv->rdcnt = 0; - priv->msg.addr &= ~0x01; + priv->msg.flags = 0; priv->msg.buffer = (uint8_t *)buffer; priv->msg.length = buflen; @@ -264,7 +263,7 @@ static int i2c_read(FAR struct i2c_dev_s *dev, uint8_t *buffer, int buflen) priv->wrcnt = 0; priv->rdcnt = 0; - priv->msg.addr |= 0x01; + priv->msg.flags = I2C_M_READ; priv->msg.buffer = buffer; priv->msg.length = buflen; @@ -428,7 +427,7 @@ static int i2c_interrupt(int irq, FAR void *context) case 0x08: /* A START condition has been transmitted. */ case 0x10: /* A Repeated START condition has been transmitted. */ - putreg32(msg->addr, priv->base + LPC43_I2C_DAT_OFFSET); /* set address */ + putreg32(((I2C_M_READ & msg->flags) == I2C_M_READ)?I2C_READADDR8(msg->addr):I2C_WRITEADDR8(msg->addr), priv->base + LPC43_I2C_DAT_OFFSET); /* set address */ putreg32(I2C_CONCLR_STAC, priv->base + LPC43_I2C_CONCLR_OFFSET); /* clear start bit */ break; From 3a4b0e12a170520db3d76df349c55cbf88727e3a Mon Sep 17 00:00:00 2001 From: Lok Tep Date: Fri, 30 Oct 2015 17:37:40 +0100 Subject: [PATCH 06/14] tickless --- arch/arm/src/lpc43xx/Make.defs | 2 + arch/arm/src/lpc43xx/lpc43_ssp.c | 194 +++---- arch/arm/src/lpc43xx/lpc43_tickless_rit.c | 589 ++++++++++++++++++++++ 3 files changed, 671 insertions(+), 114 deletions(-) create mode 100644 arch/arm/src/lpc43xx/lpc43_tickless_rit.c diff --git a/arch/arm/src/lpc43xx/Make.defs b/arch/arm/src/lpc43xx/Make.defs index d6990c82449..b944c210b31 100644 --- a/arch/arm/src/lpc43xx/Make.defs +++ b/arch/arm/src/lpc43xx/Make.defs @@ -96,6 +96,8 @@ CHIP_CSRCS += lpc43_start.c lpc43_uart.c ifneq ($(CONFIG_SCHED_TICKLESS),y) CHIP_CSRCS += lpc43_timerisr.c +else +CHIP_CSRCS += lpc43_tickless_rit.c endif ifeq ($(CONFIG_BUILD_PROTECTED),y) diff --git a/arch/arm/src/lpc43xx/lpc43_ssp.c b/arch/arm/src/lpc43xx/lpc43_ssp.c index 8fbc2ad7923..146bf293691 100644 --- a/arch/arm/src/lpc43xx/lpc43_ssp.c +++ b/arch/arm/src/lpc43xx/lpc43_ssp.c @@ -162,8 +162,12 @@ static const struct spi_ops_s g_spi0ops = .cmddata = lpc43_ssp0cmddata, /* Provided externally */ #endif .send = ssp_send, +#ifdef CONFIG_SPI_EXCHANGE + .exchange = ssp_exchange, +#else .sndblock = ssp_sndblock, .recvblock = ssp_recvblock, +#endif #ifdef CONFIG_SPI_CALLBACK .registercallback = lpc43_ssp0register, /* Provided externally */ #else @@ -197,8 +201,12 @@ static const struct spi_ops_s g_spi1ops = .cmddata = lpc43_ssp1cmddata, /* Provided externally */ #endif .send = ssp_send, +#ifdef CONFIG_SPI_EXCHANGE + .exchange = ssp_exchange, +#else .sndblock = ssp_sndblock, .recvblock = ssp_recvblock, +#endif #ifdef CONFIG_SPI_CALLBACK .registercallback = lpc43_ssp1register, /* Provided externally */ #else @@ -526,6 +534,76 @@ static uint16_t ssp_send(FAR struct spi_dev_s *dev, uint16_t wd) return (uint16_t)regval; } +static void ssp_exchange(FAR struct spi_dev_s *dev, FAR const void *txbuffer, + FAR void *rxbuffer, size_t nwords) { + FAR struct lpc43_sspdev_s *priv = (FAR struct lpc43_sspdev_s *)dev; + union + { + FAR uint8_t *p8; + FAR uint16_t *p16; + FAR void *pv; + } tx; + union + { + FAR uint8_t *p8; + FAR uint16_t *p16; + FAR void *pv; + } rx; + uint32_t data; + uint32_t datadummy = (priv->nbits > 8)?0xffff:0xff; + uint32_t rxpending = 0; + + /* While there is remaining to be sent (and no synchronization error has occurred) */ + + sspdbg("nwords: %d\n", nwords); + + tx.pv = txbuffer; + rx.pv = rxbuffer; + + while (nwords || rxpending) + { + /* Write data to the data register while (1) the TX FIFO is + * not full, (2) we have not exceeded the depth of the TX FIFO, + * and (3) there are more bytes to be sent. + */ + + spivdbg("TX: rxpending: %d nwords: %d\n", rxpending, nwords); + while ((ssp_getreg(priv, LPC43_SSP_SR_OFFSET) & SSP_SR_TNF) && + (rxpending < LPC43_SSP_FIFOSZ) && nwords) + { + if (txbuffer && priv->nbits > 8) + { + data = (uint32_t)*tx.p16++; + } + else + { + data = (uint32_t)*tx.p8++; + } + + ssp_putreg(priv, LPC43_SSP_DR_OFFSET, txbuffer?data:datadummy); + nwords--; + rxpending++; + } + + /* Now, read the RX data from the RX FIFO while the RX FIFO is not empty */ + + spivdbg("RX: rxpending: %d\n", rxpending); + while (ssp_getreg(priv, LPC43_SSP_SR_OFFSET) & SSP_SR_RNE) + { + data = ssp_getreg(priv, LPC43_SSP_DR_OFFSET); + if (rxbuffer && priv->nbits > 8) + { + *rx.p16++ = (uint16_t)data; + } + else + { + *rx.p8++ = (uint8_t)data; + } + rxpending--; + } + } +} + /**************************************************************************** * Name: ssp_sndblock * @@ -547,72 +625,7 @@ static uint16_t ssp_send(FAR struct spi_dev_s *dev, uint16_t wd) static void ssp_sndblock(FAR struct spi_dev_s *dev, FAR const void *buffer, size_t nwords) { - FAR struct lpc43_sspdev_s *priv = (FAR struct lpc43_sspdev_s *)dev; - union - { - FAR const uint8_t *p8; - FAR const uint16_t *p16; - FAR const void *pv; - } u; - uint32_t data; - uint32_t sr; - - /* Loop while thre are bytes remaining to be sent */ - - sspdbg("nwords: %d\n", nwords); - u.pv = buffer; - while (nwords > 0) - { - /* While the TX FIFO is not full and there are bytes left to send */ - - while ((ssp_getreg(priv, LPC43_SSP_SR_OFFSET) & SSP_SR_TNF) && nwords) - { - /* Fetch the data to send */ - - if (priv->nbits > 8) - { - data = (uint32_t)*u.p16++; - } - else - { - data = (uint32_t)*u.p8++; - } - - /* Send the data */ - - ssp_putreg(priv, LPC43_SSP_DR_OFFSET, data); - nwords--; - } - } - - /* Then discard all card responses until the RX & TX FIFOs are emptied. */ - - sspdbg("discarding\n"); - do - { - /* Is there anything in the RX fifo? */ - - sr = ssp_getreg(priv, LPC43_SSP_SR_OFFSET); - if ((sr & SSP_SR_RNE) != 0) - { - /* Yes.. Read and discard */ - - (void)ssp_getreg(priv, LPC43_SSP_DR_OFFSET); - } - - /* There is a race condition where TFE may go true just before - * RNE goes true and this loop terminates prematurely. The nasty little - * delay in the following solves that (it could probably be tuned - * to improve performance). - */ - - else if ((sr & SSP_SR_TFE) != 0) - { - up_udelay(100); - sr = ssp_getreg(priv, LPC43_SSP_SR_OFFSET); - } - } - while ((sr & SSP_SR_RNE) != 0 || (sr & SSP_SR_TFE) == 0); + return ssp_exchange(dev, buffer, NULL, nwords); } /**************************************************************************** @@ -636,54 +649,7 @@ static void ssp_sndblock(FAR struct spi_dev_s *dev, FAR const void *buffer, size static void ssp_recvblock(FAR struct spi_dev_s *dev, FAR void *buffer, size_t nwords) { - FAR struct lpc43_sspdev_s *priv = (FAR struct lpc43_sspdev_s *)dev; - union - { - FAR uint8_t *p8; - FAR uint16_t *p16; - FAR void *pv; - } u; - uint32_t data; - uint32_t rxpending = 0; - - /* While there is remaining to be sent (and no synchronization error has occurred) */ - - sspdbg("nwords: %d\n", nwords); - u.pv = buffer; - while (nwords || rxpending) - { - /* Fill the transmit FIFO with 0xffff... - * Write 0xff to the data register while (1) the TX FIFO is - * not full, (2) we have not exceeded the depth of the TX FIFO, - * and (3) there are more bytes to be sent. - */ - - spivdbg("TX: rxpending: %d nwords: %d\n", rxpending, nwords); - while ((ssp_getreg(priv, LPC43_SSP_SR_OFFSET) & SSP_SR_TNF) && - (rxpending < LPC43_SSP_FIFOSZ) && nwords) - { - ssp_putreg(priv, LPC43_SSP_DR_OFFSET, 0xffff); - nwords--; - rxpending++; - } - - /* Now, read the RX data from the RX FIFO while the RX FIFO is not empty */ - - spivdbg("RX: rxpending: %d\n", rxpending); - while (ssp_getreg(priv, LPC43_SSP_SR_OFFSET) & SSP_SR_RNE) - { - data = (uint8_t)ssp_getreg(priv, LPC43_SSP_DR_OFFSET); - if (priv->nbits > 8) - { - *u.p16++ = (uint16_t)data; - } - else - { - *u.p8++ = (uint8_t)data; - } - rxpending--; - } - } + return ssp_exchange(dev, NULL, buffer, nwords); } /**************************************************************************** diff --git a/arch/arm/src/lpc43xx/lpc43_tickless_rit.c b/arch/arm/src/lpc43xx/lpc43_tickless_rit.c new file mode 100644 index 00000000000..e0f6cfb60bb --- /dev/null +++ b/arch/arm/src/lpc43xx/lpc43_tickless_rit.c @@ -0,0 +1,589 @@ +/**************************************************************************** + * arch/arm/src/lpc43/lpc43_rit.c + * + * Copyright (C) 2012 Gregory Nutt. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +#include +#include + +#include "arch.h" +#include "time.h" +#include "chip/lpc43_rit.h" + +#ifdef CONFIG_SCHED_TICKLESS + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define LPC43_TL_NANOS_IN_SEC 1000000000 + +#define LPC43_TL_NANOS_IN_TICK LPC43_TL_NANOS_IN_SEC/LPC43_CCLK + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static uint32_t to_reset = UINT32_MAX / 2; +static uint32_t to_reset_next = to_reset + UINT32_MAX / 4; +static uint32_t to_end = to_reset_next + UINT32_MAX / 8; + +static uint32_t reset_ticks = 1000; /* ticks to add to force a reset */ + +static uint64_t base = 0; /* time base */ + +static uint64_t alarm_time = 0; /* alarmTime to set on next interrupt, used if not already armed */ +static bool call = false; /* true if callback should be called on next interrupt */ +static bool armed = false; /* true if alarm is armed for next match */ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/* some timer HW functions */ + +static inline void lpc43_tl_set_counter (uint32_t value) +{ + putreg32 (value, LPC43_RIT_COUNTER); +} + +static inline uint32_t lpc43_tl_get_counter (void) +{ + return getreg32 (LPC43_RIT_COUNTER); +} + +static inline void lpc43_tl_set_compare (uint32_t value) +{ + putreg32 (value, LPC43_RIT_COMPVAL); +} + +static inline uint32_t lpc43_tl_get_compare (void) +{ + return getreg32 (LPC43_RIT_COMPVAL); +} + +static inline void lpc43_tl_set_mask (uint32_t value) +{ + putreg32 (value, LPC43_RIT_MASK); +} + +static inline uint32_t lpc43_tl_get_mask (void) +{ + return getreg32 (LPC43_RIT_MASK); +} + +static inline void lpc43_tl_set_ctrl_bit (uint32_t bit, bool value) +{ + uint32_t regval; + regval = getreg32 (LPC43_RIT_CTRL); + if (value) + { + regval |= bit; + } + else + { + regval &= ~bit; + } + putreg32 (regval, LPC43_RIT_CTRL); +} + +static inline bool lpc43_tl_get_ctrl_bit (uint32_t bit) +{ + uint32_t regval; + regval = getreg32 (LPC43_RIT_CTRL); + regval |= bit; + if (regval) + { + return true ; + } + else + { + return false ; + } +} + +static inline void lpc43_tl_set_reset_on_match (bool value) +{ + lpc43_tl_set_ctrl_bit (RIT_CTRL_ENCLR, value); +} + +static inline bool lpc43_tl_get_reset_on_match (void) +{ + return lpc43_tl_get_ctrl_bit (RIT_CTRL_ENCLR); +} + +static inline void lpc43_tl_set_enable (bool value) +{ + lpc43_tl_set_ctrl_bit (RIT_CTRL_EN, value); +} + +static inline bool lpc43_tl_get_enable (void) +{ + return lpc43_tl_get_ctrl_bit (RIT_CTRL_EN); +} + +static inline void lpc43_tl_clear_interrupt () +{ + lpc43_tl_set_ctrl_bit (RIT_CTRL_EN, true); +} + +static inline bool lpc43_tl_get_interrupt (void) +{ + return lpc43_tl_get_ctrl_bit (RIT_CTRL_INT); +} + +/* converters */ + +static inline uint64_t lpc43_tl_ts2tick ( FAR struct timespec *ts) +{ + return ((ts->tv_nsec + ts->tv_sec * LPC43_TL_NANOS_IN_SEC) / LPC43_TL_NANOS_IN_TICK); +} + +static inline void lpc43_tl_tick2ts (uint64_t tick, FAR struct timespec *ts) +{ + uint64_t nanos = tick * LPC43_TL_NANOS_IN_TICK; + + ts->tv_sec = nanos / LPC43_TL_NANOS_IN_SEC; + ts->tv_nsec = nanos % LPC43_TL_NANOS_IN_SEC; +} + +/* logic functions */ + +/* force interrupt, no reset possible */ + +static void lpc43_tl_force_int () +{ + lpc43_tl_set_reset_on_match (false); + lpc43_tl_set_mask (UINT32_MAX); +} + +/* init all vars */ + +static void lpc43_tl_init_timer_vars () +{ + alarm_time = 0; + call = false; + armed = false; +} + +/* calc reset_ticks and set compare to to_reset */ + +static void lpc43_tl_calibrate_init () +{ + uint32_t counter = lpc43_tl_get_counter (); + + uint32_t counter_after = lpc43_tl_get_counter (); + counter_after = to_reset + counter; + counter_after = counter_after - counter; + + /*shift to toReset*/ + + lpc43_tl_set_compare (counter_after); + + counter_after = lpc43_tl_get_counter (); + + reset_ticks = (counter_after - counter) * 2; + +} + +/* process current and set timer in default state */ + +static void lpc43_tl_save_timer () +{ + + /*process reset if any*/ + + uint32_t match = lpc43_tl_get_compare (); + + /*move to end, no resets during processing*/ + + lpc43_tl_set_compare (UINT32_MAX); + lpc43_tl_set_mask (0); + + if (lpc43_tl_get_interrupt ()) + { + if (lpc43_tl_get_reset_on_match ()) /*was reset ?*/ + { + base = base + match; + lpc43_tl_set_reset_on_match (false); + } + lpc43_tl_clear_interrupt (); + } +} + +/* assuming safe state, true if set, false - time is in the past */ + +static bool lpc43_tl_set_safe_compare (uint32_t time) +{ + if (time < to_reset) + { + lpc43_tl_set_reset_on_match (false); + } + else + { + lpc43_tl_set_reset_on_match (true); + } + + lpc43_tl_set_compare (time); + + //check if ok + bool reset = lpc43_tl_get_interrupt (); + uint32_t counter = lpc43_tl_get_counter (); + bool reset_after = lpc43_tl_get_interrupt (); + + if (reset != reset_after) + { + //was a reset get new counter + counter = lpc43_tl_get_counter (); + } + + if (reset_after || (!reset_after && time > counter)) + { + return true ; + } + else + { + return false ; + } + +} + +/* set_safe_compare in loop */ + +static void lpc43_tl_looped_forced_set_compare () +{ + uint32_t i = 1; + bool result = lpc43_tl_set_safe_compare (lpc43_tl_get_counter () + reset_ticks); /* like in calibrateInit */ + while (!result) + { + i++; + result = lpc43_tl_set_safe_compare (lpc43_tl_get_counter () + reset_ticks * i); + }; +} + +/* assuming safe state, true if set, false - time is in the past */ + +static bool lpc43_tl_set_calc_arm (uint32_t curr, uint32_t to_set, bool arm) +{ + + uint32_t calcTime; + + if (curr < to_reset_next) + { + calcTime = min (to_reset_next, to_set); + } + else + { + if (curr < to_end) + { + calcTime = min (lpc43_tl_get_counter () + reset_ticks, to_set); + } + else + { + lpc43_tl_looped_forced_set_compare (); + return true ; + } + } + + bool set = lpc43_tl_set_safe_compare (calcTime); + + if (arm && set && (calcTime == to_set)) + { + armed = true; + } + + return set; +} + +/* try to set compare for normal operation */ + +static void lpc43_tl_set_default_compare () +{ + bool result = lpc43_tl_set_calc_arm (lpc43_tl_get_counter (), UINT32_MAX, false); + if (!result) + { + result = lpc43_tl_set_calc_arm (lpc43_tl_get_counter (), UINT32_MAX, false); + if (!result) + { + lpc43_tl_looped_forced_set_compare (); + } + } + +} + +static inline void lpc43_tl_alarm() +{ + lpc43_tl_init_timer_vars (); + lpc43_tl_set_default_compare (); + + struct timespec ts; + + up_timer_gettime(&ts); + + sched_alarm_expiration(&ts); +} + +/* interrupt handler */ + +static int lpc43_tl_isr (int irq, FAR void *context) +{ + irqstate_t flags; + flags = irqsave (); + + if (call) + { + /* forced call case */ + lpc43_tl_set_mask (false); + + lpc43_tl_clear_interrupt (); + + lpc43_tl_alarm(); + + } + else + { + lpc43_tl_save_timer (); + + if (armed) + { + lpc43_tl_alarm(); + } + else + { + if (alarm_time > 0) + { + uint64_t toSet = alarm_time - base; + uint32_t curr = lpc43_tl_get_counter (); + + if (toSet > curr) + { + if (toSet > to_end) + { + lpc43_tl_set_default_compare (); + } + else + { + bool set = lpc43_tl_set_calc_arm (curr, toSet, true); + if (!set) + { + lpc43_tl_alarm(); + } + } + } + else + { + lpc43_tl_alarm(); + } + } + else + { + lpc43_tl_set_default_compare (); + } + } + } + + irqrestore (flags); + return OK; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +void up_timer_initialize (void) +{ + irqstate_t flags; + flags = irqsave (); + + lpc43_tl_set_enable (false); + + lpc43_tl_set_compare (UINT32_MAX); + lpc43_tl_set_counter (0); + lpc43_tl_set_mask (0); + + lpc43_tl_set_reset_on_match (false); + lpc43_tl_clear_interrupt (); + + irq_attach (LPC43M4_IRQ_RITIMER, lpc43_tl_isr); + up_enable_irq (LPC43M4_IRQ_RITIMER); + + lpc43_tl_init_timer_vars (); + + lpc43_tl_set_enable (true); + + lpc43_tl_calibrate_init (); + + irqrestore (flags); +} + +int up_timer_gettime (FAR struct timespec *ts) +{ + irqstate_t flags; + flags = irqsave (); + + uint32_t time; + /* no reg changes, only processing */ + + /* order of calls is important, reset can come during processing */ + + bool reset = lpc43_tl_get_interrupt (); + uint32_t count = lpc43_tl_get_counter (); + + /* not processed reset can exist */ + if (lpc43_tl_get_reset_on_match ()) + { + bool resetAfter = lpc43_tl_get_interrupt (); + + if (reset != resetAfter) /* was a reset get new counter */ + { + count = lpc43_tl_get_counter (); + } + + if (resetAfter) + { + time = base + count + lpc43_tl_get_compare (); + } + else + { + time = base + count; + } + } + else + { + time = base + count; + } + + lpc43_tl_tick2ts (time, ts); + + irqrestore (flags); + return OK; +} + +# ifdef CONFIG_SCHED_TICKLESS_ALARM +int up_alarm_cancel (FAR struct timespec *ts) +{ + irqstate_t flags; + flags = irqsave (); + + /*no reg changes, only variables logic*/ + + up_timer_gettime (ts); + + /* let default setup will be done in interrupt handler or setAlarm */ + lpc43_tl_init_timer_vars (); + + irqrestore (flags); + return OK; +} + +int up_alarm_start (FAR const struct timespec *ts) +{ + irqstate_t flags; + flags = irqsave (); + + lpc43_tl_init_timer_vars (); + + lpc43_tl_save_timer (); + + //----calc time to set + + uint64_t time = lpc43_tl_ts2tick (ts); + uint64_t toSet = time - base; + uint32_t curr = lpc43_tl_get_counter (); + + if (toSet > curr) + { + alarm_time = time; + + if (toSet > to_end) /* future set */ + { + lpc43_tl_set_default_compare (); + } + else + { + bool set = lpc43_tl_set_calc_arm (curr, toSet, true); + if (!set) + { + /* signal call, force interrupt handler */ + + call = true; + lpc43_tl_force_int (); + } + + } + + } + else + { + /* signal call, force interrupt handler */ + + call = true; + lpc43_tl_force_int (); + } + + irqrestore (flags); + + return OK; +} + +# else + +int up_timer_cancel(FAR struct timespec *ts) + { + /*TODO*/ + irqstate_t flags; + flags = irqsave (); + + irqrestore (flags); + return OK; + } + +int up_timer_start(FAR const struct timespec *ts) + { + /*TODO*/ + irqstate_t flags; + flags = irqsave (); + + irqrestore (flags); + return OK; + } + +# endif /* CONFIG_SCHED_TICKLESS_ALARM */ + +#endif /* CONFIG_SCHED_TICKLESS */ From 08224b8606fa3aaaf3b66c931836976a29fd669b Mon Sep 17 00:00:00 2001 From: Lok Tep Date: Sun, 1 Nov 2015 23:11:37 +0100 Subject: [PATCH 07/14] after debug --- arch/arm/src/lpc43xx/chip/lpc43_rit.h | 1 - arch/arm/src/lpc43xx/lpc43_tickless_rit.c | 408 ++++++++++++---------- 2 files changed, 222 insertions(+), 187 deletions(-) diff --git a/arch/arm/src/lpc43xx/chip/lpc43_rit.h b/arch/arm/src/lpc43xx/chip/lpc43_rit.h index 90c911e4ddb..71671cd3ab0 100644 --- a/arch/arm/src/lpc43xx/chip/lpc43_rit.h +++ b/arch/arm/src/lpc43xx/chip/lpc43_rit.h @@ -42,7 +42,6 @@ ************************************************************************************/ #include -#include "chip/lpc4310203050_memorymap.h" /************************************************************************************ * Pre-processor Definitions diff --git a/arch/arm/src/lpc43xx/lpc43_tickless_rit.c b/arch/arm/src/lpc43xx/lpc43_tickless_rit.c index e0f6cfb60bb..59a7979a3ef 100644 --- a/arch/arm/src/lpc43xx/lpc43_tickless_rit.c +++ b/arch/arm/src/lpc43xx/lpc43_tickless_rit.c @@ -41,9 +41,10 @@ #include #include +#include -#include "arch.h" -#include "time.h" +#include "up_arch.h" +#include "chip.h" #include "chip/lpc43_rit.h" #ifdef CONFIG_SCHED_TICKLESS @@ -52,17 +53,19 @@ * Pre-processor Definitions ****************************************************************************/ -#define LPC43_TL_NANOS_IN_SEC 1000000000 +#define LPC43_TL_NANOS_IN_SEC (1000000000) -#define LPC43_TL_NANOS_IN_TICK LPC43_TL_NANOS_IN_SEC/LPC43_CCLK +#ifndef min +# define min(a,b) a < b ? a : b +#endif /**************************************************************************** * Private Data ****************************************************************************/ static uint32_t to_reset = UINT32_MAX / 2; -static uint32_t to_reset_next = to_reset + UINT32_MAX / 4; -static uint32_t to_end = to_reset_next + UINT32_MAX / 8; +static uint32_t to_reset_next = UINT32_MAX / 2 + UINT32_MAX / 4; +static uint32_t to_end = UINT32_MAX / 2 + UINT32_MAX / 4 + UINT32_MAX / 8; static uint32_t reset_ticks = 1000; /* ticks to add to force a reset */ @@ -71,6 +74,9 @@ static uint64_t base = 0; /* time base */ static uint64_t alarm_time = 0; /* alarmTime to set on next interrupt, used if not already armed */ static bool call = false; /* true if callback should be called on next interrupt */ static bool armed = false; /* true if alarm is armed for next match */ +static bool in_isr = false; /* true if inside isr */ +static uint32_t synch = 0; +static irqstate_t g_flags; /**************************************************************************** * Private Functions @@ -80,38 +86,38 @@ static bool armed = false; /* true if alarm is armed for next match */ static inline void lpc43_tl_set_counter (uint32_t value) { - putreg32 (value, LPC43_RIT_COUNTER); + putreg32(value, LPC43_RIT_COUNTER); } static inline uint32_t lpc43_tl_get_counter (void) { - return getreg32 (LPC43_RIT_COUNTER); + return getreg32(LPC43_RIT_COUNTER); } static inline void lpc43_tl_set_compare (uint32_t value) { - putreg32 (value, LPC43_RIT_COMPVAL); + putreg32(value, LPC43_RIT_COMPVAL); } static inline uint32_t lpc43_tl_get_compare (void) { - return getreg32 (LPC43_RIT_COMPVAL); + return getreg32(LPC43_RIT_COMPVAL); } static inline void lpc43_tl_set_mask (uint32_t value) { - putreg32 (value, LPC43_RIT_MASK); + putreg32(value, LPC43_RIT_MASK); } static inline uint32_t lpc43_tl_get_mask (void) { - return getreg32 (LPC43_RIT_MASK); + return getreg32(LPC43_RIT_MASK); } static inline void lpc43_tl_set_ctrl_bit (uint32_t bit, bool value) { uint32_t regval; - regval = getreg32 (LPC43_RIT_CTRL); + regval = getreg32(LPC43_RIT_CTRL); if (value) { regval |= bit; @@ -120,21 +126,21 @@ static inline void lpc43_tl_set_ctrl_bit (uint32_t bit, bool value) { regval &= ~bit; } - putreg32 (regval, LPC43_RIT_CTRL); + putreg32(regval, LPC43_RIT_CTRL); } static inline bool lpc43_tl_get_ctrl_bit (uint32_t bit) { uint32_t regval; - regval = getreg32 (LPC43_RIT_CTRL); - regval |= bit; + regval = getreg32(LPC43_RIT_CTRL); + regval &= bit; if (regval) { - return true ; + return true; } else { - return false ; + return false; } } @@ -158,9 +164,9 @@ static inline bool lpc43_tl_get_enable (void) return lpc43_tl_get_ctrl_bit (RIT_CTRL_EN); } -static inline void lpc43_tl_clear_interrupt () +static inline void lpc43_tl_clear_interrupt (void) { - lpc43_tl_set_ctrl_bit (RIT_CTRL_EN, true); + lpc43_tl_set_ctrl_bit (RIT_CTRL_INT, true); } static inline bool lpc43_tl_get_interrupt (void) @@ -170,24 +176,42 @@ static inline bool lpc43_tl_get_interrupt (void) /* converters */ -static inline uint64_t lpc43_tl_ts2tick ( FAR struct timespec *ts) -{ - return ((ts->tv_nsec + ts->tv_sec * LPC43_TL_NANOS_IN_SEC) / LPC43_TL_NANOS_IN_TICK); -} +static inline uint64_t lpc43_tl_ts2tick ( FAR const struct timespec *ts) + { + return ( (uint64_t)(ts->tv_sec)*LPC43_CCLK + ( (uint64_t)(ts->tv_nsec)*LPC43_CCLK/LPC43_TL_NANOS_IN_SEC) ); + } static inline void lpc43_tl_tick2ts (uint64_t tick, FAR struct timespec *ts) -{ - uint64_t nanos = tick * LPC43_TL_NANOS_IN_TICK; - - ts->tv_sec = nanos / LPC43_TL_NANOS_IN_SEC; - ts->tv_nsec = nanos % LPC43_TL_NANOS_IN_SEC; -} + { + ts->tv_sec = tick/LPC43_CCLK; + ts->tv_nsec = (tick%LPC43_CCLK)*LPC43_TL_NANOS_IN_SEC/LPC43_CCLK; + } /* logic functions */ +static void lpc43_tl_sync_up (void) { + irqstate_t flags; + flags = irqsave (); + + if ( synch == 0 ) + { + g_flags = flags; + + } + synch++; +} + +static void lpc43_tl_sync_down (void) { + synch--; + if ( synch == 0 ) + { + irqrestore (g_flags); + } +} + /* force interrupt, no reset possible */ -static void lpc43_tl_force_int () +static void lpc43_tl_force_int (void) { lpc43_tl_set_reset_on_match (false); lpc43_tl_set_mask (UINT32_MAX); @@ -195,7 +219,7 @@ static void lpc43_tl_force_int () /* init all vars */ -static void lpc43_tl_init_timer_vars () +static void lpc43_tl_init_timer_vars (void) { alarm_time = 0; call = false; @@ -204,7 +228,7 @@ static void lpc43_tl_init_timer_vars () /* calc reset_ticks and set compare to to_reset */ -static void lpc43_tl_calibrate_init () +static void lpc43_tl_calibrate_init (void) { uint32_t counter = lpc43_tl_get_counter (); @@ -224,7 +248,7 @@ static void lpc43_tl_calibrate_init () /* process current and set timer in default state */ -static void lpc43_tl_save_timer () +static void lpc43_tl_save_timer (void) { /*process reset if any*/ @@ -244,14 +268,20 @@ static void lpc43_tl_save_timer () lpc43_tl_set_reset_on_match (false); } lpc43_tl_clear_interrupt (); + + int i=0; + while( lpc43_tl_get_interrupt () ) { + i++; + } + } } /* assuming safe state, true if set, false - time is in the past */ -static bool lpc43_tl_set_safe_compare (uint32_t time) +static bool lpc43_tl_set_safe_compare (uint32_t compare_to_set) { - if (time < to_reset) + if (compare_to_set < to_reset) { lpc43_tl_set_reset_on_match (false); } @@ -260,7 +290,7 @@ static bool lpc43_tl_set_safe_compare (uint32_t time) lpc43_tl_set_reset_on_match (true); } - lpc43_tl_set_compare (time); + lpc43_tl_set_compare (compare_to_set); //check if ok bool reset = lpc43_tl_get_interrupt (); @@ -273,27 +303,29 @@ static bool lpc43_tl_set_safe_compare (uint32_t time) counter = lpc43_tl_get_counter (); } - if (reset_after || (!reset_after && time > counter)) + if (reset_after || (!reset_after && compare_to_set > counter)) { - return true ; + return true; } else { - return false ; + return false; } } /* set_safe_compare in loop */ -static void lpc43_tl_looped_forced_set_compare () +static void lpc43_tl_looped_forced_set_compare (void) { uint32_t i = 1; - bool result = lpc43_tl_set_safe_compare (lpc43_tl_get_counter () + reset_ticks); /* like in calibrateInit */ + bool result = lpc43_tl_set_safe_compare ( + lpc43_tl_get_counter () + reset_ticks); /* like in calibrateInit */ while (!result) { i++; - result = lpc43_tl_set_safe_compare (lpc43_tl_get_counter () + reset_ticks * i); + result = lpc43_tl_set_safe_compare ( + lpc43_tl_get_counter () + reset_ticks * i); }; } @@ -306,18 +338,18 @@ static bool lpc43_tl_set_calc_arm (uint32_t curr, uint32_t to_set, bool arm) if (curr < to_reset_next) { - calcTime = min (to_reset_next, to_set); + calcTime = min(to_reset_next, to_set); } else { if (curr < to_end) { - calcTime = min (lpc43_tl_get_counter () + reset_ticks, to_set); + calcTime = min(lpc43_tl_get_counter () + reset_ticks, to_set); } else { lpc43_tl_looped_forced_set_compare (); - return true ; + return true; } } @@ -333,12 +365,14 @@ static bool lpc43_tl_set_calc_arm (uint32_t curr, uint32_t to_set, bool arm) /* try to set compare for normal operation */ -static void lpc43_tl_set_default_compare () +static void lpc43_tl_set_default_compare (void) { - bool result = lpc43_tl_set_calc_arm (lpc43_tl_get_counter (), UINT32_MAX, false); + bool result = lpc43_tl_set_calc_arm (lpc43_tl_get_counter (), UINT32_MAX, + false); if (!result) { - result = lpc43_tl_set_calc_arm (lpc43_tl_get_counter (), UINT32_MAX, false); + result = lpc43_tl_set_calc_arm (lpc43_tl_get_counter (), UINT32_MAX, + false); if (!result) { lpc43_tl_looped_forced_set_compare (); @@ -347,80 +381,83 @@ static void lpc43_tl_set_default_compare () } -static inline void lpc43_tl_alarm() +static inline void lpc43_tl_alarm (void) { lpc43_tl_init_timer_vars (); lpc43_tl_set_default_compare (); struct timespec ts; - up_timer_gettime(&ts); + up_timer_gettime (&ts); - sched_alarm_expiration(&ts); + sched_alarm_expiration (&ts); } /* interrupt handler */ static int lpc43_tl_isr (int irq, FAR void *context) -{ - irqstate_t flags; - flags = irqsave (); + { + lpc43_tl_sync_up(); - if (call) - { - /* forced call case */ - lpc43_tl_set_mask (false); + in_isr = true; - lpc43_tl_clear_interrupt (); + if (call) + { + /* forced call case */ + lpc43_tl_set_mask (false); - lpc43_tl_alarm(); + lpc43_tl_clear_interrupt (); - } - else - { - lpc43_tl_save_timer (); + lpc43_tl_alarm(); - if (armed) - { - lpc43_tl_alarm(); - } - else - { - if (alarm_time > 0) - { - uint64_t toSet = alarm_time - base; - uint32_t curr = lpc43_tl_get_counter (); + } + else + { + lpc43_tl_save_timer (); - if (toSet > curr) - { - if (toSet > to_end) - { - lpc43_tl_set_default_compare (); - } - else - { - bool set = lpc43_tl_set_calc_arm (curr, toSet, true); - if (!set) - { - lpc43_tl_alarm(); - } - } - } - else - { - lpc43_tl_alarm(); - } - } - else - { - lpc43_tl_set_default_compare (); - } - } - } + if (armed) + { + lpc43_tl_alarm(); + } + else + { + if (alarm_time > 0) + { + int64_t toSet = alarm_time - base; + uint32_t curr = lpc43_tl_get_counter (); - irqrestore (flags); - return OK; -} + if (toSet > curr) + { + if (toSet > to_end) + { + lpc43_tl_set_default_compare (); + } + else + { + bool set = lpc43_tl_set_calc_arm (curr, toSet, true); + if (!set) + { + lpc43_tl_alarm(); + } + } + } + else + { + lpc43_tl_alarm(); + } + } + else + { + lpc43_tl_set_default_compare (); + } + } + } + + in_isr = false; + lpc43_tl_sync_down(); + + return OK; + } /**************************************************************************** * Public Functions @@ -453,134 +490,133 @@ void up_timer_initialize (void) } int up_timer_gettime (FAR struct timespec *ts) -{ - irqstate_t flags; - flags = irqsave (); + { + lpc43_tl_sync_up(); - uint32_t time; - /* no reg changes, only processing */ + uint64_t curr; + /* no reg changes, only processing */ - /* order of calls is important, reset can come during processing */ + /* order of calls is important, reset can come during processing */ - bool reset = lpc43_tl_get_interrupt (); - uint32_t count = lpc43_tl_get_counter (); + bool reset = lpc43_tl_get_interrupt (); + uint32_t count = lpc43_tl_get_counter (); - /* not processed reset can exist */ - if (lpc43_tl_get_reset_on_match ()) - { - bool resetAfter = lpc43_tl_get_interrupt (); + /* not processed reset can exist */ + if (lpc43_tl_get_reset_on_match ()) + { + bool resetAfter = lpc43_tl_get_interrupt (); - if (reset != resetAfter) /* was a reset get new counter */ - { - count = lpc43_tl_get_counter (); - } + if (reset != resetAfter) /* was a reset get new counter */ + { + count = lpc43_tl_get_counter (); + } - if (resetAfter) - { - time = base + count + lpc43_tl_get_compare (); - } - else - { - time = base + count; - } - } - else - { - time = base + count; - } + if (resetAfter) + { + curr = base + count + lpc43_tl_get_compare (); + } + else + { + curr = base + count; + } + } + else + { + curr = base + count; + } - lpc43_tl_tick2ts (time, ts); + lpc43_tl_tick2ts (curr, ts); - irqrestore (flags); - return OK; -} + lpc43_tl_sync_down(); + return OK; + } # ifdef CONFIG_SCHED_TICKLESS_ALARM int up_alarm_cancel (FAR struct timespec *ts) -{ - irqstate_t flags; - flags = irqsave (); + { + lpc43_tl_sync_up(); - /*no reg changes, only variables logic*/ + /*no reg changes, only variables logic*/ - up_timer_gettime (ts); + up_timer_gettime (ts); - /* let default setup will be done in interrupt handler or setAlarm */ - lpc43_tl_init_timer_vars (); + /* let default setup will be done in interrupt handler or setAlarm */ + lpc43_tl_init_timer_vars (); - irqrestore (flags); - return OK; -} + lpc43_tl_sync_down(); + return OK; + } int up_alarm_start (FAR const struct timespec *ts) -{ - irqstate_t flags; - flags = irqsave (); + { + lpc43_tl_sync_up(); - lpc43_tl_init_timer_vars (); + lpc43_tl_init_timer_vars (); - lpc43_tl_save_timer (); + if (in_isr) { + alarm_time = lpc43_tl_ts2tick (ts); + } else { + lpc43_tl_save_timer (); - //----calc time to set + //----calc time to set - uint64_t time = lpc43_tl_ts2tick (ts); - uint64_t toSet = time - base; - uint32_t curr = lpc43_tl_get_counter (); + uint64_t time = lpc43_tl_ts2tick (ts); + int64_t toSet = time - base; + uint32_t curr = lpc43_tl_get_counter (); - if (toSet > curr) - { - alarm_time = time; - - if (toSet > to_end) /* future set */ + if (toSet > curr) { - lpc43_tl_set_default_compare (); - } - else - { - bool set = lpc43_tl_set_calc_arm (curr, toSet, true); - if (!set) + alarm_time = time; + + if (toSet > to_end) /* future set */ { - /* signal call, force interrupt handler */ + lpc43_tl_set_default_compare (); + } + else + { + bool set = lpc43_tl_set_calc_arm (curr, toSet, true); + if (!set) + { + /* signal call, force interrupt handler */ + + call = true; + lpc43_tl_force_int (); + } - call = true; - lpc43_tl_force_int (); } } + else + { + /* signal call, force interrupt handler */ - } - else - { - /* signal call, force interrupt handler */ - - call = true; - lpc43_tl_force_int (); + call = true; + lpc43_tl_force_int (); + } } - irqrestore (flags); + lpc43_tl_sync_down(); - return OK; -} + return OK; + } # else int up_timer_cancel(FAR struct timespec *ts) { /*TODO*/ - irqstate_t flags; - flags = irqsave (); + lpc43_tl_sync_up(); - irqrestore (flags); + lpc43_tl_sync_down(); return OK; } int up_timer_start(FAR const struct timespec *ts) { /*TODO*/ - irqstate_t flags; - flags = irqsave (); + lpc43_tl_sync_up(); - irqrestore (flags); + lpc43_tl_sync_down(); return OK; } From 30cea64430d21521fdae71b1552e844ff693cecf Mon Sep 17 00:00:00 2001 From: Lok Tep Date: Mon, 2 Nov 2015 17:41:03 +0100 Subject: [PATCH 08/14] fixes --- arch/arm/src/lpc43xx/lpc43_tickless_rit.c | 214 +++++++++++++--------- 1 file changed, 125 insertions(+), 89 deletions(-) diff --git a/arch/arm/src/lpc43xx/lpc43_tickless_rit.c b/arch/arm/src/lpc43xx/lpc43_tickless_rit.c index 59a7979a3ef..51f705d33ee 100644 --- a/arch/arm/src/lpc43xx/lpc43_tickless_rit.c +++ b/arch/arm/src/lpc43xx/lpc43_tickless_rit.c @@ -32,6 +32,15 @@ * ****************************************************************************/ +/**************************************************************************** + * + * only controlled resets to 0 are performed, no direct set to counter + * working counter region is from 0 to to_end + * all public functions are synchronized with disabled irqs + * + ****************************************************************************/ + + /**************************************************************************** * Included Files ****************************************************************************/ @@ -40,6 +49,7 @@ #include #include +#include #include #include @@ -53,10 +63,8 @@ * Pre-processor Definitions ****************************************************************************/ -#define LPC43_TL_NANOS_IN_SEC (1000000000) - #ifndef min -# define min(a,b) a < b ? a : b +# define min(a,b) (a < b ? a : b) #endif /**************************************************************************** @@ -73,9 +81,9 @@ static uint64_t base = 0; /* time base */ static uint64_t alarm_time = 0; /* alarmTime to set on next interrupt, used if not already armed */ static bool call = false; /* true if callback should be called on next interrupt */ +static bool forced_int = false; /* true if interrupt was forced with mask, no reset */ static bool armed = false; /* true if alarm is armed for next match */ -static bool in_isr = false; /* true if inside isr */ -static uint32_t synch = 0; +static uint32_t synch = 0; /* synch all calls, recursion is possible */ static irqstate_t g_flags; /**************************************************************************** @@ -178,13 +186,13 @@ static inline bool lpc43_tl_get_interrupt (void) static inline uint64_t lpc43_tl_ts2tick ( FAR const struct timespec *ts) { - return ( (uint64_t)(ts->tv_sec)*LPC43_CCLK + ( (uint64_t)(ts->tv_nsec)*LPC43_CCLK/LPC43_TL_NANOS_IN_SEC) ); + return ( (uint64_t)(ts->tv_sec)*LPC43_CCLK + ( (uint64_t)(ts->tv_nsec)*LPC43_CCLK/NSEC_PER_SEC) ); } static inline void lpc43_tl_tick2ts (uint64_t tick, FAR struct timespec *ts) { ts->tv_sec = tick/LPC43_CCLK; - ts->tv_nsec = (tick%LPC43_CCLK)*LPC43_TL_NANOS_IN_SEC/LPC43_CCLK; + ts->tv_nsec = (tick%LPC43_CCLK)*NSEC_PER_SEC/LPC43_CCLK; } /* logic functions */ @@ -209,21 +217,24 @@ static void lpc43_tl_sync_down (void) { } } -/* force interrupt, no reset possible */ +/* assuming safe timer state, force interrupt, no reset possible */ static void lpc43_tl_force_int (void) { + forced_int = true; lpc43_tl_set_reset_on_match (false); lpc43_tl_set_mask (UINT32_MAX); + lpc43_tl_set_compare(UINT32_MAX); } -/* init all vars */ +/* init all vars, forced_int should not be cleared */ static void lpc43_tl_init_timer_vars (void) { alarm_time = 0; call = false; armed = false; + } /* calc reset_ticks and set compare to to_reset */ @@ -246,38 +257,42 @@ static void lpc43_tl_calibrate_init (void) } -/* process current and set timer in default state */ +/* process current and set timer in default safe state */ static void lpc43_tl_save_timer (void) { - - /*process reset if any*/ - - uint32_t match = lpc43_tl_get_compare (); - - /*move to end, no resets during processing*/ - - lpc43_tl_set_compare (UINT32_MAX); - lpc43_tl_set_mask (0); - - if (lpc43_tl_get_interrupt ()) + if (forced_int) /* special case of forced interrupt by mask*/ { - if (lpc43_tl_get_reset_on_match ()) /*was reset ?*/ - { - base = base + match; - lpc43_tl_set_reset_on_match (false); - } - lpc43_tl_clear_interrupt (); + forced_int = false; + lpc43_tl_set_compare (UINT32_MAX); + lpc43_tl_set_mask (0); + lpc43_tl_clear_interrupt (); + } + else + { - int i=0; - while( lpc43_tl_get_interrupt () ) { - i++; + /*process reset if any*/ + + uint32_t match = lpc43_tl_get_compare (); + + /*move to end, no resets during processing*/ + + lpc43_tl_set_compare (UINT32_MAX); + lpc43_tl_set_mask (0); + + if (lpc43_tl_get_interrupt ()) + { + if (lpc43_tl_get_reset_on_match ()) /*was reset ?*/ + { + base = base + match; + lpc43_tl_set_reset_on_match (false); + } + lpc43_tl_clear_interrupt (); } - - } + } } -/* assuming safe state, true if set, false - time is in the past */ +/* assuming safe timer state, true if set, false - time is in the past */ static bool lpc43_tl_set_safe_compare (uint32_t compare_to_set) { @@ -309,12 +324,15 @@ static bool lpc43_tl_set_safe_compare (uint32_t compare_to_set) } else { + lpc43_tl_set_reset_on_match (false); + lpc43_tl_set_compare (UINT32_MAX); + return false; } } -/* set_safe_compare in loop */ +/* assuming safe timer state, set_safe_compare in loop */ static void lpc43_tl_looped_forced_set_compare (void) { @@ -329,7 +347,7 @@ static void lpc43_tl_looped_forced_set_compare (void) }; } -/* assuming safe state, true if set, false - time is in the past */ +/* assuming safe timer state, true if set, false - time is in the past */ static bool lpc43_tl_set_calc_arm (uint32_t curr, uint32_t to_set, bool arm) { @@ -363,7 +381,7 @@ static bool lpc43_tl_set_calc_arm (uint32_t curr, uint32_t to_set, bool arm) return set; } -/* try to set compare for normal operation */ +/* assuming safe timer state, try to set compare for normal operation */ static void lpc43_tl_set_default_compare (void) { @@ -381,6 +399,7 @@ static void lpc43_tl_set_default_compare (void) } +/* assuming safe timer state, used by isr: sets default compare , calls alarm */ static inline void lpc43_tl_alarm (void) { lpc43_tl_init_timer_vars (); @@ -390,7 +409,11 @@ static inline void lpc43_tl_alarm (void) up_timer_gettime (&ts); +#ifdef CONFIG_SCHED_TICKLESS_ALARM sched_alarm_expiration (&ts); +#else + sched_timer_expiration(); +#endif } /* interrupt handler */ @@ -399,29 +422,21 @@ static int lpc43_tl_isr (int irq, FAR void *context) { lpc43_tl_sync_up(); - in_isr = true; + lpc43_tl_save_timer(); if (call) { - /* forced call case */ - lpc43_tl_set_mask (false); - - lpc43_tl_clear_interrupt (); - lpc43_tl_alarm(); - } else { - lpc43_tl_save_timer (); - if (armed) { - lpc43_tl_alarm(); + lpc43_tl_alarm(); /* armed - call alarm */ } else { - if (alarm_time > 0) + if (alarm_time > 0) /* need to set alarm time */ { int64_t toSet = alarm_time - base; uint32_t curr = lpc43_tl_get_counter (); @@ -453,7 +468,6 @@ static int lpc43_tl_isr (int irq, FAR void *context) } } - in_isr = false; lpc43_tl_sync_down(); return OK; @@ -538,9 +552,11 @@ int up_alarm_cancel (FAR struct timespec *ts) /*no reg changes, only variables logic*/ - up_timer_gettime (ts); + if ( ts != NULL ) { + up_timer_gettime (ts); + } - /* let default setup will be done in interrupt handler or setAlarm */ + /* let default setup will be done in interrupt handler or up_alarm_start */ lpc43_tl_init_timer_vars (); lpc43_tl_sync_down(); @@ -551,49 +567,40 @@ int up_alarm_start (FAR const struct timespec *ts) { lpc43_tl_sync_up(); + lpc43_tl_save_timer (); + lpc43_tl_init_timer_vars (); - if (in_isr) { - alarm_time = lpc43_tl_ts2tick (ts); - } else { - lpc43_tl_save_timer (); + uint64_t alarm_time = lpc43_tl_ts2tick (ts); + int64_t toSet = alarm_time - base; + uint32_t curr = lpc43_tl_get_counter (); - //----calc time to set + if (toSet > curr) + { + if (toSet > to_end) /* future set */ + { + lpc43_tl_set_default_compare (); + } + else + { + bool set = lpc43_tl_set_calc_arm (curr, toSet, true); + if (!set) + { + /* signal call, force interrupt handler */ - uint64_t time = lpc43_tl_ts2tick (ts); - int64_t toSet = time - base; - uint32_t curr = lpc43_tl_get_counter (); + call = true; + lpc43_tl_force_int (); + } - if (toSet > curr) - { - alarm_time = time; + } + } + else + { + /* signal call, force interrupt handler */ - if (toSet > to_end) /* future set */ - { - lpc43_tl_set_default_compare (); - } - else - { - bool set = lpc43_tl_set_calc_arm (curr, toSet, true); - if (!set) - { - /* signal call, force interrupt handler */ - - call = true; - lpc43_tl_force_int (); - } - - } - - } - else - { - /* signal call, force interrupt handler */ - - call = true; - lpc43_tl_force_int (); - } - } + call = true; + lpc43_tl_force_int (); + } lpc43_tl_sync_down(); @@ -604,18 +611,47 @@ int up_alarm_start (FAR const struct timespec *ts) int up_timer_cancel(FAR struct timespec *ts) { - /*TODO*/ lpc43_tl_sync_up(); + if (ts == NULL) + { + up_alarm_cancel(ts); + } + else + { + uint64_t saved_alarm_time = alarm_time; + up_alarm_cancel(ts); + int64_t diff = saved_alarm_time - lpc43_tl_ts2tick(ts); + + if ( diff > 0 ) + { + lpc43_tl_tick2ts(diff, ts); + } + else + { + ts->tv_sec = 0; + ts->tv_nsec = 0; + } + + } + lpc43_tl_sync_down(); return OK; } int up_timer_start(FAR const struct timespec *ts) { - /*TODO*/ + lpc43_tl_sync_up(); + struct timespec tmp_ts; + up_timer_gettime(&tmp_ts); + + tmp_ts->tv_sec += ts->tv_sec; + tmp_ts->tv_nsec += ts->tv_nsec; + + up_alarm_start(tmp_ts); + lpc43_tl_sync_down(); return OK; } From 24f1155d76400eb7e5da1e8bb5c44b233fabba8f Mon Sep 17 00:00:00 2001 From: Lok Tep Date: Mon, 2 Nov 2015 23:34:32 +0100 Subject: [PATCH 09/14] compile fixes --- arch/arm/src/lpc43xx/lpc43_ssp.c | 12 ++++++------ arch/arm/src/lpc43xx/lpc43_tickless_rit.c | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/arch/arm/src/lpc43xx/lpc43_ssp.c b/arch/arm/src/lpc43xx/lpc43_ssp.c index 146bf293691..fe97cbc760f 100644 --- a/arch/arm/src/lpc43xx/lpc43_ssp.c +++ b/arch/arm/src/lpc43xx/lpc43_ssp.c @@ -539,15 +539,15 @@ static void ssp_exchange(FAR struct spi_dev_s *dev, FAR const void *txbuffer, FAR struct lpc43_sspdev_s *priv = (FAR struct lpc43_sspdev_s *)dev; union { - FAR uint8_t *p8; - FAR uint16_t *p16; - FAR void *pv; + FAR uint8_t *p8; + FAR uint16_t *p16; + FAR const void *pv; } tx; union { - FAR uint8_t *p8; - FAR uint16_t *p16; - FAR void *pv; + FAR uint8_t *p8; + FAR uint16_t *p16; + FAR const void *pv; } rx; uint32_t data; uint32_t datadummy = (priv->nbits > 8)?0xffff:0xff; diff --git a/arch/arm/src/lpc43xx/lpc43_tickless_rit.c b/arch/arm/src/lpc43xx/lpc43_tickless_rit.c index 51f705d33ee..d9f91088f36 100644 --- a/arch/arm/src/lpc43xx/lpc43_tickless_rit.c +++ b/arch/arm/src/lpc43xx/lpc43_tickless_rit.c @@ -545,7 +545,7 @@ int up_timer_gettime (FAR struct timespec *ts) return OK; } -# ifdef CONFIG_SCHED_TICKLESS_ALARM + int up_alarm_cancel (FAR struct timespec *ts) { lpc43_tl_sync_up(); @@ -571,7 +571,7 @@ int up_alarm_start (FAR const struct timespec *ts) lpc43_tl_init_timer_vars (); - uint64_t alarm_time = lpc43_tl_ts2tick (ts); + alarm_time = lpc43_tl_ts2tick (ts); int64_t toSet = alarm_time - base; uint32_t curr = lpc43_tl_get_counter (); @@ -607,7 +607,7 @@ int up_alarm_start (FAR const struct timespec *ts) return OK; } -# else +#ifndef CONFIG_SCHED_TICKLESS_ALARM int up_timer_cancel(FAR struct timespec *ts) { @@ -647,10 +647,10 @@ int up_timer_start(FAR const struct timespec *ts) struct timespec tmp_ts; up_timer_gettime(&tmp_ts); - tmp_ts->tv_sec += ts->tv_sec; - tmp_ts->tv_nsec += ts->tv_nsec; + tmp_ts.tv_sec += ts->tv_sec; + tmp_ts.tv_nsec += ts->tv_nsec; - up_alarm_start(tmp_ts); + up_alarm_start(&tmp_ts); lpc43_tl_sync_down(); return OK; From 1f8c0fdcdb7125aa707f232a2271c1c2ae6024f3 Mon Sep 17 00:00:00 2001 From: Lok Tep Date: Mon, 9 Nov 2015 14:34:59 +0100 Subject: [PATCH 10/14] timer base name difference --- arch/arm/src/lpc43xx/chip/lpc43_timer.h | 136 ++++++++++++------------ 1 file changed, 68 insertions(+), 68 deletions(-) diff --git a/arch/arm/src/lpc43xx/chip/lpc43_timer.h b/arch/arm/src/lpc43xx/chip/lpc43_timer.h index 7627b135db4..109b8c8b7fa 100644 --- a/arch/arm/src/lpc43xx/chip/lpc43_timer.h +++ b/arch/arm/src/lpc43xx/chip/lpc43_timer.h @@ -68,77 +68,77 @@ /* Register addresses ***************************************************************/ -#define LPC43_TMR0_IR (LPC43_TMR0_BASE+LPC43_TMR_IR_OFFSET) -#define LPC43_TMR0_TCR (LPC43_TMR0_BASE+LPC43_TMR_TCR_OFFSET) -#define LPC43_TMR0_TC (LPC43_TMR0_BASE+LPC43_TMR_TC_OFFSET) -#define LPC43_TMR0_PR (LPC43_TMR0_BASE+LPC43_TMR_PR_OFFSET) -#define LPC43_TMR0_PC (LPC43_TMR0_BASE+LPC43_TMR_PC_OFFSET) -#define LPC43_TMR0_MCR (LPC43_TMR0_BASE+LPC43_TMR_MCR_OFFSET) -#define LPC43_TMR0_MR0 (LPC43_TMR0_BASE+LPC43_TMR_MR0_OFFSET) -#define LPC43_TMR0_MR1 (LPC43_TMR0_BASE+LPC43_TMR_MR1_OFFSET) -#define LPC43_TMR0_MR2 (LPC43_TMR0_BASE+LPC43_TMR_MR2_OFFSET) -#define LPC43_TMR0_MR3 (LPC43_TMR0_BASE+LPC43_TMR_MR3_OFFSET) -#define LPC43_TMR0_CCR (LPC43_TMR0_BASE+LPC43_TMR_CCR_OFFSET) -#define LPC43_TMR0_CR0 (LPC43_TMR0_BASE+LPC43_TMR_CR0_OFFSET) -#define LPC43_TMR0_CR1 (LPC43_TMR0_BASE+LPC43_TMR_CR1_OFFSET) -#define LPC43_TMR0_CR2 (LPC43_TMR0_BASE+LPC43_TMR_CR2_OFFSET) -#define LPC43_TMR0_CR3 (LPC43_TMR0_BASE+LPC43_TMR_CR3_OFFSET) -#define LPC43_TMR0_EMR (LPC43_TMR0_BASE+LPC43_TMR_EMR_OFFSET) -#define LPC43_TMR0_CTCR (LPC43_TMR0_BASE+LPC43_TMR_CTCR_OFFSET) +#define LPC43_TMR0_IR (LPC43_TIMER0_BASE+LPC43_TMR_IR_OFFSET) +#define LPC43_TMR0_TCR (LPC43_TIMER0_BASE+LPC43_TMR_TCR_OFFSET) +#define LPC43_TMR0_TC (LPC43_TIMER0_BASE+LPC43_TMR_TC_OFFSET) +#define LPC43_TMR0_PR (LPC43_TIMER0_BASE+LPC43_TMR_PR_OFFSET) +#define LPC43_TMR0_PC (LPC43_TIMER0_BASE+LPC43_TMR_PC_OFFSET) +#define LPC43_TMR0_MCR (LPC43_TIMER0_BASE+LPC43_TMR_MCR_OFFSET) +#define LPC43_TMR0_MR0 (LPC43_TIMER0_BASE+LPC43_TMR_MR0_OFFSET) +#define LPC43_TMR0_MR1 (LPC43_TIMER0_BASE+LPC43_TMR_MR1_OFFSET) +#define LPC43_TMR0_MR2 (LPC43_TIMER0_BASE+LPC43_TMR_MR2_OFFSET) +#define LPC43_TMR0_MR3 (LPC43_TIMER0_BASE+LPC43_TMR_MR3_OFFSET) +#define LPC43_TMR0_CCR (LPC43_TIMER0_BASE+LPC43_TMR_CCR_OFFSET) +#define LPC43_TMR0_CR0 (LPC43_TIMER0_BASE+LPC43_TMR_CR0_OFFSET) +#define LPC43_TMR0_CR1 (LPC43_TIMER0_BASE+LPC43_TMR_CR1_OFFSET) +#define LPC43_TMR0_CR2 (LPC43_TIMER0_BASE+LPC43_TMR_CR2_OFFSET) +#define LPC43_TMR0_CR3 (LPC43_TIMER0_BASE+LPC43_TMR_CR3_OFFSET) +#define LPC43_TMR0_EMR (LPC43_TIMER0_BASE+LPC43_TMR_EMR_OFFSET) +#define LPC43_TMR0_CTCR (LPC43_TIMER0_BASE+LPC43_TMR_CTCR_OFFSET) -#define LPC43_TMR1_IR (LPC43_TMR1_BASE+LPC43_TMR_IR_OFFSET) -#define LPC43_TMR1_TCR (LPC43_TMR1_BASE+LPC43_TMR_TCR_OFFSET) -#define LPC43_TMR1_TC (LPC43_TMR1_BASE+LPC43_TMR_TC_OFFSET) -#define LPC43_TMR1_PR (LPC43_TMR1_BASE+LPC43_TMR_PR_OFFSET) -#define LPC43_TMR1_PC (LPC43_TMR1_BASE+LPC43_TMR_PC_OFFSET) -#define LPC43_TMR1_MCR (LPC43_TMR1_BASE+LPC43_TMR_MCR_OFFSET) -#define LPC43_TMR1_MR0 (LPC43_TMR1_BASE+LPC43_TMR_MR0_OFFSET) -#define LPC43_TMR1_MR1 (LPC43_TMR1_BASE+LPC43_TMR_MR1_OFFSET) -#define LPC43_TMR1_MR2 (LPC43_TMR1_BASE+LPC43_TMR_MR2_OFFSET) -#define LPC43_TMR1_MR3 (LPC43_TMR1_BASE+LPC43_TMR_MR3_OFFSET) -#define LPC43_TMR1_CCR (LPC43_TMR1_BASE+LPC43_TMR_CCR_OFFSET) -#define LPC43_TMR1_CR0 (LPC43_TMR1_BASE+LPC43_TMR_CR0_OFFSET) -#define LPC43_TMR1_CR1 (LPC43_TMR1_BASE+LPC43_TMR_CR1_OFFSET) -#define LPC43_TMR1_CR2 (LPC43_TMR1_BASE+LPC43_TMR_CR2_OFFSET) -#define LPC43_TMR1_CR3 (LPC43_TMR1_BASE+LPC43_TMR_CR3_OFFSET) -#define LPC43_TMR1_EMR (LPC43_TMR1_BASE+LPC43_TMR_EMR_OFFSET) -#define LPC43_TMR1_CTCR (LPC43_TMR1_BASE+LPC43_TMR_CTCR_OFFSET) +#define LPC43_TMR1_IR (LPC43_TIMER1_BASE+LPC43_TMR_IR_OFFSET) +#define LPC43_TMR1_TCR (LPC43_TIMER1_BASE+LPC43_TMR_TCR_OFFSET) +#define LPC43_TMR1_TC (LPC43_TIMER1_BASE+LPC43_TMR_TC_OFFSET) +#define LPC43_TMR1_PR (LPC43_TIMER1_BASE+LPC43_TMR_PR_OFFSET) +#define LPC43_TMR1_PC (LPC43_TIMER1_BASE+LPC43_TMR_PC_OFFSET) +#define LPC43_TMR1_MCR (LPC43_TIMER1_BASE+LPC43_TMR_MCR_OFFSET) +#define LPC43_TMR1_MR0 (LPC43_TIMER1_BASE+LPC43_TMR_MR0_OFFSET) +#define LPC43_TMR1_MR1 (LPC43_TIMER1_BASE+LPC43_TMR_MR1_OFFSET) +#define LPC43_TMR1_MR2 (LPC43_TIMER1_BASE+LPC43_TMR_MR2_OFFSET) +#define LPC43_TMR1_MR3 (LPC43_TIMER1_BASE+LPC43_TMR_MR3_OFFSET) +#define LPC43_TMR1_CCR (LPC43_TIMER1_BASE+LPC43_TMR_CCR_OFFSET) +#define LPC43_TMR1_CR0 (LPC43_TIMER1_BASE+LPC43_TMR_CR0_OFFSET) +#define LPC43_TMR1_CR1 (LPC43_TIMER1_BASE+LPC43_TMR_CR1_OFFSET) +#define LPC43_TMR1_CR2 (LPC43_TIMER1_BASE+LPC43_TMR_CR2_OFFSET) +#define LPC43_TMR1_CR3 (LPC43_TIMER1_BASE+LPC43_TMR_CR3_OFFSET) +#define LPC43_TMR1_EMR (LPC43_TIMER1_BASE+LPC43_TMR_EMR_OFFSET) +#define LPC43_TMR1_CTCR (LPC43_TIMER1_BASE+LPC43_TMR_CTCR_OFFSET) -#define LPC43_TMR2_IR (LPC43_TMR2_BASE+LPC43_TMR_IR_OFFSET) -#define LPC43_TMR2_TCR (LPC43_TMR2_BASE+LPC43_TMR_TCR_OFFSET) -#define LPC43_TMR2_TC (LPC43_TMR2_BASE+LPC43_TMR_TC_OFFSET) -#define LPC43_TMR2_PR (LPC43_TMR2_BASE+LPC43_TMR_PR_OFFSET) -#define LPC43_TMR2_PC (LPC43_TMR2_BASE+LPC43_TMR_PC_OFFSET) -#define LPC43_TMR2_MCR (LPC43_TMR2_BASE+LPC43_TMR_MCR_OFFSET) -#define LPC43_TMR2_MR0 (LPC43_TMR2_BASE+LPC43_TMR_MR0_OFFSET) -#define LPC43_TMR2_MR1 (LPC43_TMR2_BASE+LPC43_TMR_MR1_OFFSET) -#define LPC43_TMR2_MR2 (LPC43_TMR2_BASE+LPC43_TMR_MR2_OFFSET) -#define LPC43_TMR2_MR3 (LPC43_TMR2_BASE+LPC43_TMR_MR3_OFFSET) -#define LPC43_TMR2_CCR (LPC43_TMR2_BASE+LPC43_TMR_CCR_OFFSET) -#define LPC43_TMR2_CR0 (LPC43_TMR2_BASE+LPC43_TMR_CR0_OFFSET) -#define LPC43_TMR2_CR1 (LPC43_TMR2_BASE+LPC43_TMR_CR1_OFFSET) -#define LPC43_TMR2_CR2 (LPC43_TMR2_BASE+LPC43_TMR_CR2_OFFSET) -#define LPC43_TMR2_CR3 (LPC43_TMR2_BASE+LPC43_TMR_CR3_OFFSET) -#define LPC43_TMR2_EMR (LPC43_TMR2_BASE+LPC43_TMR_EMR_OFFSET) -#define LPC43_TMR2_CTCR (LPC43_TMR2_BASE+LPC43_TMR_CTCR_OFFSET) +#define LPC43_TMR2_IR (LPC43_TIMER2_BASE+LPC43_TMR_IR_OFFSET) +#define LPC43_TMR2_TCR (LPC43_TIMER2_BASE+LPC43_TMR_TCR_OFFSET) +#define LPC43_TMR2_TC (LPC43_TIMER2_BASE+LPC43_TMR_TC_OFFSET) +#define LPC43_TMR2_PR (LPC43_TIMER2_BASE+LPC43_TMR_PR_OFFSET) +#define LPC43_TMR2_PC (LPC43_TIMER2_BASE+LPC43_TMR_PC_OFFSET) +#define LPC43_TMR2_MCR (LPC43_TIMER2_BASE+LPC43_TMR_MCR_OFFSET) +#define LPC43_TMR2_MR0 (LPC43_TIMER2_BASE+LPC43_TMR_MR0_OFFSET) +#define LPC43_TMR2_MR1 (LPC43_TIMER2_BASE+LPC43_TMR_MR1_OFFSET) +#define LPC43_TMR2_MR2 (LPC43_TIMER2_BASE+LPC43_TMR_MR2_OFFSET) +#define LPC43_TMR2_MR3 (LPC43_TIMER2_BASE+LPC43_TMR_MR3_OFFSET) +#define LPC43_TMR2_CCR (LPC43_TIMER2_BASE+LPC43_TMR_CCR_OFFSET) +#define LPC43_TMR2_CR0 (LPC43_TIMER2_BASE+LPC43_TMR_CR0_OFFSET) +#define LPC43_TMR2_CR1 (LPC43_TIMER2_BASE+LPC43_TMR_CR1_OFFSET) +#define LPC43_TMR2_CR2 (LPC43_TIMER2_BASE+LPC43_TMR_CR2_OFFSET) +#define LPC43_TMR2_CR3 (LPC43_TIMER2_BASE+LPC43_TMR_CR3_OFFSET) +#define LPC43_TMR2_EMR (LPC43_TIMER2_BASE+LPC43_TMR_EMR_OFFSET) +#define LPC43_TMR2_CTCR (LPC43_TIMER2_BASE+LPC43_TMR_CTCR_OFFSET) -#define LPC43_TMR3_IR (LPC43_TMR3_BASE+LPC43_TMR_IR_OFFSET) -#define LPC43_TMR3_TCR (LPC43_TMR3_BASE+LPC43_TMR_TCR_OFFSET) -#define LPC43_TMR3_TC (LPC43_TMR3_BASE+LPC43_TMR_TC_OFFSET) -#define LPC43_TMR3_PR (LPC43_TMR3_BASE+LPC43_TMR_PR_OFFSET) -#define LPC43_TMR3_PC (LPC43_TMR3_BASE+LPC43_TMR_PC_OFFSET) -#define LPC43_TMR3_MCR (LPC43_TMR3_BASE+LPC43_TMR_MCR_OFFSET) -#define LPC43_TMR3_MR0 (LPC43_TMR3_BASE+LPC43_TMR_MR0_OFFSET) -#define LPC43_TMR3_MR1 (LPC43_TMR3_BASE+LPC43_TMR_MR1_OFFSET) -#define LPC43_TMR3_MR2 (LPC43_TMR3_BASE+LPC43_TMR_MR2_OFFSET) -#define LPC43_TMR3_MR3 (LPC43_TMR3_BASE+LPC43_TMR_MR3_OFFSET) -#define LPC43_TMR3_CCR (LPC43_TMR3_BASE+LPC43_TMR_CCR_OFFSET) -#define LPC43_TMR3_CR0 (LPC43_TMR3_BASE+LPC43_TMR_CR0_OFFSET) -#define LPC43_TMR3_CR1 (LPC43_TMR3_BASE+LPC43_TMR_CR1_OFFSET) -#define LPC43_TMR3_CR2 (LPC43_TMR3_BASE+LPC43_TMR_CR2_OFFSET) -#define LPC43_TMR3_CR3 (LPC43_TMR3_BASE+LPC43_TMR_CR3_OFFSET) -#define LPC43_TMR3_EMR (LPC43_TMR3_BASE+LPC43_TMR_EMR_OFFSET) -#define LPC43_TMR3_CTCR (LPC43_TMR3_BASE+LPC43_TMR_CTCR_OFFSET) +#define LPC43_TMR3_IR (LPC43_TIMER3_BASE+LPC43_TMR_IR_OFFSET) +#define LPC43_TMR3_TCR (LPC43_TIMER3_BASE+LPC43_TMR_TCR_OFFSET) +#define LPC43_TMR3_TC (LPC43_TIMER3_BASE+LPC43_TMR_TC_OFFSET) +#define LPC43_TMR3_PR (LPC43_TIMER3_BASE+LPC43_TMR_PR_OFFSET) +#define LPC43_TMR3_PC (LPC43_TIMER3_BASE+LPC43_TMR_PC_OFFSET) +#define LPC43_TMR3_MCR (LPC43_TIMER3_BASE+LPC43_TMR_MCR_OFFSET) +#define LPC43_TMR3_MR0 (LPC43_TIMER3_BASE+LPC43_TMR_MR0_OFFSET) +#define LPC43_TMR3_MR1 (LPC43_TIMER3_BASE+LPC43_TMR_MR1_OFFSET) +#define LPC43_TMR3_MR2 (LPC43_TIMER3_BASE+LPC43_TMR_MR2_OFFSET) +#define LPC43_TMR3_MR3 (LPC43_TIMER3_BASE+LPC43_TMR_MR3_OFFSET) +#define LPC43_TMR3_CCR (LPC43_TIMER3_BASE+LPC43_TMR_CCR_OFFSET) +#define LPC43_TMR3_CR0 (LPC43_TIMER3_BASE+LPC43_TMR_CR0_OFFSET) +#define LPC43_TMR3_CR1 (LPC43_TIMER3_BASE+LPC43_TMR_CR1_OFFSET) +#define LPC43_TMR3_CR2 (LPC43_TIMER3_BASE+LPC43_TMR_CR2_OFFSET) +#define LPC43_TMR3_CR3 (LPC43_TIMER3_BASE+LPC43_TMR_CR3_OFFSET) +#define LPC43_TMR3_EMR (LPC43_TIMER3_BASE+LPC43_TMR_EMR_OFFSET) +#define LPC43_TMR3_CTCR (LPC43_TIMER3_BASE+LPC43_TMR_CTCR_OFFSET) /* Register bit definitions *********************************************************/ /* Registers holding 32-bit numeric values (no bit field definitions): From a8416d2a26571fa8e6d9678ba0d42e3c499c0d11 Mon Sep 17 00:00:00 2001 From: Lok Tep Date: Mon, 9 Nov 2015 14:41:08 +0100 Subject: [PATCH 11/14] revert --- arch/arm/include/lpc43xx/chip.h | 5 ++--- arch/arm/src/lpc43xx/lpc43_usb0dev.c | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/arch/arm/include/lpc43xx/chip.h b/arch/arm/include/lpc43xx/chip.h index abb3ee64834..d0409ef0bb5 100644 --- a/arch/arm/include/lpc43xx/chip.h +++ b/arch/arm/include/lpc43xx/chip.h @@ -46,7 +46,7 @@ * Pre-processor Definitions ************************************************************************************/ -/* Per the data sheet: LPC4350/30/20/10 Rev. 3.2 4 June 2012 */ +/* Per the data sheet: LPC4350/30/20/10 Rev. 3.2 4 June 2012 */ /* Get customizations for each supported chip. * * SRAM Resources @@ -74,7 +74,7 @@ * manager. This gives some symmetry to all of the members of the family. */ -/* Per the user manual: UM10503, Rev. 1.2 � 8 June 2012 */ +/* Per the user manual: UM10503, Rev. 1.2 — 8 June 2012 */ /* Get customizations for each supported chip. * * SRAM Resources @@ -632,7 +632,6 @@ # define LPC43_NDAC (1) /* One 10-bit DAC */ # define LPC43_NADC10_CHANNELS (8) /* Eight ADC channels (per ADC)*/ # define LPC43_NADC12 (1) /* ONne 12-bit ADC controllers (ADCHS)*/ ->>>>>>> remotes/nuttx/arch/master #else # error "Unsupported LPC43xx chip" #endif diff --git a/arch/arm/src/lpc43xx/lpc43_usb0dev.c b/arch/arm/src/lpc43xx/lpc43_usb0dev.c index d7545c82e92..8d8237bcf9b 100644 --- a/arch/arm/src/lpc43xx/lpc43_usb0dev.c +++ b/arch/arm/src/lpc43xx/lpc43_usb0dev.c @@ -2847,4 +2847,4 @@ int usbdev_unregister(struct usbdevclass_driver_s *driver) g_usbdev.driver = NULL; return OK; } ->>>>>>> remotes/nuttx/arch/master + From 3b4c71ef8db531ad8479c7ee00f94ac2b45a65a4 Mon Sep 17 00:00:00 2001 From: Lok Tep Date: Mon, 9 Nov 2015 14:51:00 +0100 Subject: [PATCH 12/14] more revert --- arch/arm/include/lpc43xx/chip.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/include/lpc43xx/chip.h b/arch/arm/include/lpc43xx/chip.h index d0409ef0bb5..dec8ecb762f 100644 --- a/arch/arm/include/lpc43xx/chip.h +++ b/arch/arm/include/lpc43xx/chip.h @@ -46,7 +46,7 @@ * Pre-processor Definitions ************************************************************************************/ -/* Per the data sheet: LPC4350/30/20/10 Rev. 3.2 4 June 2012 */ +/* Per the data sheet: LPC4350/30/20/10 Rev. 3.2 — 4 June 2012 */ /* Get customizations for each supported chip. * * SRAM Resources @@ -74,7 +74,7 @@ * manager. This gives some symmetry to all of the members of the family. */ -/* Per the user manual: UM10503, Rev. 1.2 — 8 June 2012 */ +/* Per the user manual: UM10503, Rev. 1.2 — 8 June 2012 */ /* Get customizations for each supported chip. * * SRAM Resources From b654a6f46722609a0a3df4ddf74ec159df7045cf Mon Sep 17 00:00:00 2001 From: Lok Tep Date: Mon, 9 Nov 2015 21:01:32 +0100 Subject: [PATCH 13/14] alarm --- arch/arm/src/lpc43xx/lpc43_tickless_rit.c | 434 ++++++++++++++-------- 1 file changed, 273 insertions(+), 161 deletions(-) diff --git a/arch/arm/src/lpc43xx/lpc43_tickless_rit.c b/arch/arm/src/lpc43xx/lpc43_tickless_rit.c index d9f91088f36..531755cfe4d 100644 --- a/arch/arm/src/lpc43xx/lpc43_tickless_rit.c +++ b/arch/arm/src/lpc43xx/lpc43_tickless_rit.c @@ -35,7 +35,7 @@ /**************************************************************************** * * only controlled resets to 0 are performed, no direct set to counter - * working counter region is from 0 to to_end + * working counter region is from 0 to TO_END * all public functions are synchronized with disabled irqs * ****************************************************************************/ @@ -71,85 +71,98 @@ * Private Data ****************************************************************************/ -static uint32_t to_reset = UINT32_MAX / 2; -static uint32_t to_reset_next = UINT32_MAX / 2 + UINT32_MAX / 4; -static uint32_t to_end = UINT32_MAX / 2 + UINT32_MAX / 4 + UINT32_MAX / 8; +static uint32_t TO_RESET = UINT32_MAX / 2; +static uint32_t TO_RESET_NEXT = UINT32_MAX / 2 + UINT32_MAX / 4; +static uint32_t TO_END = UINT32_MAX / 2 + UINT32_MAX / 4 + UINT32_MAX / 8; /* any alarm should no last more than UINT32_MAX/8 */ +static struct timespec MAX_TS; -static uint32_t reset_ticks = 1000; /* ticks to add to force a reset */ +static uint32_t COMMON_DEV; +static uint32_t MIN_TICKS; +static uint32_t MIN_NSEC; -static uint64_t base = 0; /* time base */ +static uint32_t RESET_TICKS = 1000; /* ticks to add to force a reset */ -static uint64_t alarm_time = 0; /* alarmTime to set on next interrupt, used if not already armed */ +static struct timespec base_ts; /* time base */ +static uint32_t base_rest; /* rest of ticks that is < MIN_TICKS*/ + +static struct timespec alarm_time_ts; /* alarmTime to set on next interrupt, used if not already armed */ + +static bool alarm_time_set = false; /* true if alarm_time set and need to be processed */ static bool call = false; /* true if callback should be called on next interrupt */ static bool forced_int = false; /* true if interrupt was forced with mask, no reset */ static bool armed = false; /* true if alarm is armed for next match */ static uint32_t synch = 0; /* synch all calls, recursion is possible */ static irqstate_t g_flags; +static uint32_t ctrl_cache; +static uint32_t mask_cache; +static uint32_t compare_cache; + /**************************************************************************** * Private Functions ****************************************************************************/ /* some timer HW functions */ -static inline void lpc43_tl_set_counter (uint32_t value) + static inline void lpc43_tl_set_counter (uint32_t value) { putreg32(value, LPC43_RIT_COUNTER); } -static inline uint32_t lpc43_tl_get_counter (void) + static inline uint32_t lpc43_tl_get_counter (void) { return getreg32(LPC43_RIT_COUNTER); } -static inline void lpc43_tl_set_compare (uint32_t value) + static inline void lpc43_tl_set_compare (uint32_t value) { - putreg32(value, LPC43_RIT_COMPVAL); + if ( value != compare_cache) + { + compare_cache = value; + putreg32(value, LPC43_RIT_COMPVAL); + } } static inline uint32_t lpc43_tl_get_compare (void) { - return getreg32(LPC43_RIT_COMPVAL); + return compare_cache; } -static inline void lpc43_tl_set_mask (uint32_t value) + static inline void lpc43_tl_set_mask (uint32_t value) { - putreg32(value, LPC43_RIT_MASK); + if ( value != mask_cache) + { + mask_cache = value; + putreg32(value, LPC43_RIT_MASK); + } } static inline uint32_t lpc43_tl_get_mask (void) { - return getreg32(LPC43_RIT_MASK); -} - -static inline void lpc43_tl_set_ctrl_bit (uint32_t bit, bool value) -{ - uint32_t regval; - regval = getreg32(LPC43_RIT_CTRL); - if (value) - { - regval |= bit; - } - else - { - regval &= ~bit; - } - putreg32(regval, LPC43_RIT_CTRL); + return mask_cache; } static inline bool lpc43_tl_get_ctrl_bit (uint32_t bit) { - uint32_t regval; - regval = getreg32(LPC43_RIT_CTRL); - regval &= bit; - if (regval) - { - return true; - } - else - { - return false; - } + return ((ctrl_cache & bit)?true:false); +} + + static inline void lpc43_tl_set_ctrl_bit (uint32_t bit, bool value) +{ + + if ( lpc43_tl_get_ctrl_bit(bit) != value ) { + + if (value) + { + ctrl_cache |= bit; + } + else + { + ctrl_cache &= ~bit; + } + + putreg32(ctrl_cache, LPC43_RIT_CTRL); + } } static inline void lpc43_tl_set_reset_on_match (bool value) @@ -172,32 +185,113 @@ static inline bool lpc43_tl_get_enable (void) return lpc43_tl_get_ctrl_bit (RIT_CTRL_EN); } -static inline void lpc43_tl_clear_interrupt (void) + static inline void lpc43_tl_clear_interrupt (void) { - lpc43_tl_set_ctrl_bit (RIT_CTRL_INT, true); + putreg32(ctrl_cache | RIT_CTRL_INT, LPC43_RIT_CTRL); } -static inline bool lpc43_tl_get_interrupt (void) + static inline bool lpc43_tl_get_interrupt (void) { - return lpc43_tl_get_ctrl_bit (RIT_CTRL_INT); + return (( getreg32(LPC43_RIT_CTRL) & RIT_CTRL_INT )?true:false); } /* converters */ +static uint32_t commonDev(uint32_t a, uint32_t b) +{ + while(b !=0) + { + int h = a%b; + a = b; + b = h; + } -static inline uint64_t lpc43_tl_ts2tick ( FAR const struct timespec *ts) + return a; +} + + static void lpc43_tl_add(FAR const struct timespec *ts1, + FAR const struct timespec *ts2, + FAR struct timespec *ts3) +{ + time_t sec = ts1->tv_sec + ts2->tv_sec; + long nsec = ts1->tv_nsec + ts2->tv_nsec; + + if (nsec >= NSEC_PER_SEC) + { + nsec -= NSEC_PER_SEC; + sec++; + } + + ts3->tv_sec = sec; + ts3->tv_nsec = nsec; +} + + static void lpc43_tl_sub(FAR const struct timespec *ts1, + FAR const struct timespec *ts2, + FAR struct timespec *ts3) +{ + time_t sec; + long nsec; + + if (ts1->tv_sec < ts2->tv_sec) + { + sec = 0; + nsec = 0; + } + else if (ts1->tv_sec == ts2->tv_sec && ts1->tv_nsec <= ts2->tv_nsec) + { + sec = 0; + nsec = 0; + } + else + { + sec = ts1->tv_sec - ts2->tv_sec; + if (ts1->tv_nsec < ts2->tv_nsec) + { + nsec = (ts1->tv_nsec + NSEC_PER_SEC) - ts2->tv_nsec; + sec--; + } + else + { + nsec = ts1->tv_nsec - ts2->tv_nsec; + } + } + + ts3->tv_sec = sec; + ts3->tv_nsec = nsec; +} + +static inline uint32_t lpc43_tl_ts2tick ( FAR const struct timespec *ts) { - return ( (uint64_t)(ts->tv_sec)*LPC43_CCLK + ( (uint64_t)(ts->tv_nsec)*LPC43_CCLK/NSEC_PER_SEC) ); + return ( ts->tv_sec*LPC43_CCLK + ( ts->tv_nsec/MIN_NSEC*MIN_TICKS ) ); } -static inline void lpc43_tl_tick2ts (uint64_t tick, FAR struct timespec *ts) + static uint32_t lpc43_tl_tick2ts (uint32_t ticks, FAR struct timespec *ts, bool with_rest) { - ts->tv_sec = tick/LPC43_CCLK; - ts->tv_nsec = (tick%LPC43_CCLK)*NSEC_PER_SEC/LPC43_CCLK; + + uint32_t ticks_whole; + uint32_t ticks_rest = 0; + + if (with_rest) + { + uint32_t ticks_mult = ticks/MIN_TICKS; + ticks_whole = ticks_mult*MIN_TICKS; + ticks_rest = ticks - ticks_whole; + + } + else + { + ticks_whole = ticks; + } + + ts->tv_sec = ticks_whole/LPC43_CCLK; + ts->tv_nsec = ((ticks_whole%LPC43_CCLK)/MIN_TICKS)*MIN_NSEC; + + return ticks_rest; } /* logic functions */ -static void lpc43_tl_sync_up (void) { +static inline void lpc43_tl_sync_up (void) { irqstate_t flags; flags = irqsave (); @@ -209,7 +303,7 @@ static void lpc43_tl_sync_up (void) { synch++; } -static void lpc43_tl_sync_down (void) { +static inline void lpc43_tl_sync_down (void) { synch--; if ( synch == 0 ) { @@ -219,7 +313,7 @@ static void lpc43_tl_sync_down (void) { /* assuming safe timer state, force interrupt, no reset possible */ -static void lpc43_tl_force_int (void) +static inline void lpc43_tl_force_int (void) { forced_int = true; lpc43_tl_set_reset_on_match (false); @@ -229,22 +323,22 @@ static void lpc43_tl_force_int (void) /* init all vars, forced_int should not be cleared */ -static void lpc43_tl_init_timer_vars (void) +static inline void lpc43_tl_init_timer_vars (void) { - alarm_time = 0; + alarm_time_set = false; call = false; armed = false; } -/* calc reset_ticks and set compare to to_reset */ +/* calc RESET_TICKS and set compare to TO_RESET */ static void lpc43_tl_calibrate_init (void) { uint32_t counter = lpc43_tl_get_counter (); uint32_t counter_after = lpc43_tl_get_counter (); - counter_after = to_reset + counter; + counter_after = TO_RESET + counter; counter_after = counter_after - counter; /*shift to toReset*/ @@ -253,13 +347,13 @@ static void lpc43_tl_calibrate_init (void) counter_after = lpc43_tl_get_counter (); - reset_ticks = (counter_after - counter) * 2; + RESET_TICKS = (counter_after - counter) * 2; } /* process current and set timer in default safe state */ -static void lpc43_tl_save_timer (void) +static void lpc43_tl_save_timer (bool from_isr) { if (forced_int) /* special case of forced interrupt by mask*/ { @@ -280,12 +374,13 @@ static void lpc43_tl_save_timer (void) lpc43_tl_set_compare (UINT32_MAX); lpc43_tl_set_mask (0); - if (lpc43_tl_get_interrupt ()) + if (from_isr || lpc43_tl_get_interrupt ()) { if (lpc43_tl_get_reset_on_match ()) /*was reset ?*/ { - base = base + match; - lpc43_tl_set_reset_on_match (false); + struct timespec match_ts; + base_rest = lpc43_tl_tick2ts(match + base_rest, &match_ts,true); + lpc43_tl_add(&base_ts, &match_ts,&base_ts); } lpc43_tl_clear_interrupt (); } @@ -296,7 +391,7 @@ static void lpc43_tl_save_timer (void) static bool lpc43_tl_set_safe_compare (uint32_t compare_to_set) { - if (compare_to_set < to_reset) + if (compare_to_set < TO_RESET) { lpc43_tl_set_reset_on_match (false); } @@ -324,7 +419,6 @@ static bool lpc43_tl_set_safe_compare (uint32_t compare_to_set) } else { - lpc43_tl_set_reset_on_match (false); lpc43_tl_set_compare (UINT32_MAX); return false; @@ -338,12 +432,12 @@ static void lpc43_tl_looped_forced_set_compare (void) { uint32_t i = 1; bool result = lpc43_tl_set_safe_compare ( - lpc43_tl_get_counter () + reset_ticks); /* like in calibrateInit */ + lpc43_tl_get_counter () + RESET_TICKS); /* like in calibrateInit */ while (!result) { i++; result = lpc43_tl_set_safe_compare ( - lpc43_tl_get_counter () + reset_ticks * i); + lpc43_tl_get_counter () + RESET_TICKS * i); }; } @@ -354,15 +448,15 @@ static bool lpc43_tl_set_calc_arm (uint32_t curr, uint32_t to_set, bool arm) uint32_t calcTime; - if (curr < to_reset_next) + if (curr < TO_RESET_NEXT) { - calcTime = min(to_reset_next, to_set); + calcTime = min(TO_RESET_NEXT, to_set); } else { - if (curr < to_end) + if (curr < TO_END) { - calcTime = min(lpc43_tl_get_counter () + reset_ticks, to_set); + calcTime = min(curr + RESET_TICKS, to_set); } else { @@ -383,9 +477,9 @@ static bool lpc43_tl_set_calc_arm (uint32_t curr, uint32_t to_set, bool arm) /* assuming safe timer state, try to set compare for normal operation */ -static void lpc43_tl_set_default_compare (void) +static void lpc43_tl_set_default_compare (uint32_t curr) { - bool result = lpc43_tl_set_calc_arm (lpc43_tl_get_counter (), UINT32_MAX, + bool result = lpc43_tl_set_calc_arm (curr, UINT32_MAX, false); if (!result) { @@ -399,17 +493,36 @@ static void lpc43_tl_set_default_compare (void) } +/* calculates ticks to set from alarm_time_ts and base_ts/base_rest, UINT32_MAX if overflow */ +static inline uint32_t lpc43_tl_calc_to_set (void) +{ + struct timespec diff_ts; + struct timespec ovf_ts; + + lpc43_tl_sub(&alarm_time_ts,&base_ts,&diff_ts); + + lpc43_tl_sub(&diff_ts,&MAX_TS,&ovf_ts); + if ( ovf_ts.tv_sec == 0 && ovf_ts.tv_nsec == 0 ) /* check overflow */ + { + return ( lpc43_tl_ts2tick(&diff_ts) - base_rest ); + } + else + { + return UINT32_MAX; + } + +} + /* assuming safe timer state, used by isr: sets default compare , calls alarm */ -static inline void lpc43_tl_alarm (void) +static inline void lpc43_tl_alarm (uint32_t curr) { lpc43_tl_init_timer_vars (); - lpc43_tl_set_default_compare (); + lpc43_tl_set_default_compare (curr); - struct timespec ts; - - up_timer_gettime (&ts); #ifdef CONFIG_SCHED_TICKLESS_ALARM + struct timespec ts; + up_timer_gettime(&ts); sched_alarm_expiration (&ts); #else sched_timer_expiration(); @@ -422,48 +535,48 @@ static int lpc43_tl_isr (int irq, FAR void *context) { lpc43_tl_sync_up(); - lpc43_tl_save_timer(); + lpc43_tl_save_timer(true); + uint32_t curr = lpc43_tl_get_counter (); if (call) { - lpc43_tl_alarm(); + lpc43_tl_alarm(curr); } else { if (armed) { - lpc43_tl_alarm(); /* armed - call alarm */ + lpc43_tl_alarm(curr); /* armed - call alarm */ } else { - if (alarm_time > 0) /* need to set alarm time */ + if (alarm_time_set) /* need to set alarm time */ { - int64_t toSet = alarm_time - base; - uint32_t curr = lpc43_tl_get_counter (); + uint32_t toSet = lpc43_tl_calc_to_set(); if (toSet > curr) { - if (toSet > to_end) + if (toSet > TO_END) { - lpc43_tl_set_default_compare (); + lpc43_tl_set_default_compare (curr); } else { bool set = lpc43_tl_set_calc_arm (curr, toSet, true); if (!set) { - lpc43_tl_alarm(); + lpc43_tl_alarm(curr); } } } else { - lpc43_tl_alarm(); + lpc43_tl_alarm(curr); } } else { - lpc43_tl_set_default_compare (); + lpc43_tl_set_default_compare (curr); } } } @@ -473,6 +586,7 @@ static int lpc43_tl_isr (int irq, FAR void *context) return OK; } + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -482,6 +596,21 @@ void up_timer_initialize (void) irqstate_t flags; flags = irqsave (); + ctrl_cache = getreg32(LPC43_RIT_CTRL); + ctrl_cache &= ~RIT_CTRL_INT; /* set interrupt to 0*/ + mask_cache = getreg32(LPC43_RIT_MASK); + compare_cache = getreg32(LPC43_RIT_COMPVAL); + + COMMON_DEV = commonDev(NSEC_PER_SEC,LPC43_CCLK); + MIN_TICKS = LPC43_CCLK/COMMON_DEV; + MIN_NSEC = NSEC_PER_SEC/COMMON_DEV; + + base_ts.tv_sec = 0; + base_ts.tv_nsec = 0; + base_rest = 0; + + lpc43_tl_tick2ts(TO_END,&MAX_TS,false); + lpc43_tl_set_enable (false); lpc43_tl_set_compare (UINT32_MAX); @@ -501,15 +630,15 @@ void up_timer_initialize (void) lpc43_tl_calibrate_init (); irqrestore (flags); + } + +/* no reg changes, only processing */ int up_timer_gettime (FAR struct timespec *ts) { lpc43_tl_sync_up(); - uint64_t curr; - /* no reg changes, only processing */ - /* order of calls is important, reset can come during processing */ bool reset = lpc43_tl_get_interrupt (); @@ -518,30 +647,28 @@ int up_timer_gettime (FAR struct timespec *ts) /* not processed reset can exist */ if (lpc43_tl_get_reset_on_match ()) { - bool resetAfter = lpc43_tl_get_interrupt (); + bool resetAfter = lpc43_tl_get_interrupt (); - if (reset != resetAfter) /* was a reset get new counter */ - { - count = lpc43_tl_get_counter (); - } + if (reset != resetAfter) /* was a reset during processing? get new counter */ + { + count = lpc43_tl_get_counter (); + } - if (resetAfter) - { - curr = base + count + lpc43_tl_get_compare (); - } - else - { - curr = base + count; - } - } - else - { - curr = base + count; + if (resetAfter) + { + count += lpc43_tl_get_compare (); /* count should be smaller then UINT32_MAX-TO_END -> no overflow */ + } } - lpc43_tl_tick2ts (curr, ts); + struct timespec count_ts; + + + lpc43_tl_tick2ts(count + base_rest,&count_ts,false ); + + lpc43_tl_add(&base_ts,&count_ts,ts); lpc43_tl_sync_down(); + return OK; } @@ -567,40 +694,40 @@ int up_alarm_start (FAR const struct timespec *ts) { lpc43_tl_sync_up(); - lpc43_tl_save_timer (); + lpc43_tl_save_timer (false); - lpc43_tl_init_timer_vars (); + lpc43_tl_init_timer_vars (); - alarm_time = lpc43_tl_ts2tick (ts); - int64_t toSet = alarm_time - base; - uint32_t curr = lpc43_tl_get_counter (); + alarm_time_set = true; + alarm_time_ts.tv_sec = ts->tv_sec; + alarm_time_ts.tv_nsec = ts->tv_nsec; - if (toSet > curr) - { - if (toSet > to_end) /* future set */ - { - lpc43_tl_set_default_compare (); - } - else - { - bool set = lpc43_tl_set_calc_arm (curr, toSet, true); - if (!set) - { - /* signal call, force interrupt handler */ + uint32_t toSet = lpc43_tl_calc_to_set(); - call = true; - lpc43_tl_force_int (); - } + uint32_t curr = lpc43_tl_get_counter (); - } - } - else - { - /* signal call, force interrupt handler */ + if (toSet > curr) + { + if (toSet > TO_END) /* future set */ + { + lpc43_tl_set_default_compare (curr); + } + else + { + bool set = lpc43_tl_set_calc_arm (curr, toSet, true); + if (!set) /* signal call, force interrupt handler */ + { + call = true; + lpc43_tl_force_int (); + } - call = true; - lpc43_tl_force_int (); - } + } + } + else /* signal call, force interrupt handler */ + { + call = true; + lpc43_tl_force_int (); + } lpc43_tl_sync_down(); @@ -613,27 +740,14 @@ int up_timer_cancel(FAR struct timespec *ts) { lpc43_tl_sync_up(); - if (ts == NULL) + if (ts != NULL) { - up_alarm_cancel(ts); + struct timespec abs_ts; + up_timer_gettime(&abs_ts); + lpc43_tl_sub( &alarm_time_ts,&abs_ts,ts ); } - else - { - uint64_t saved_alarm_time = alarm_time; - up_alarm_cancel(ts); - int64_t diff = saved_alarm_time - lpc43_tl_ts2tick(ts); - if ( diff > 0 ) - { - lpc43_tl_tick2ts(diff, ts); - } - else - { - ts->tv_sec = 0; - ts->tv_nsec = 0; - } - - } + lpc43_tl_init_timer_vars (); lpc43_tl_sync_down(); return OK; @@ -644,13 +758,11 @@ int up_timer_start(FAR const struct timespec *ts) lpc43_tl_sync_up(); - struct timespec tmp_ts; - up_timer_gettime(&tmp_ts); + struct timespec abs_ts; + up_timer_gettime(&abs_ts); + lpc43_tl_add(&abs_ts,ts,&abs_ts); - tmp_ts.tv_sec += ts->tv_sec; - tmp_ts.tv_nsec += ts->tv_nsec; - - up_alarm_start(&tmp_ts); + up_alarm_start(&abs_ts); lpc43_tl_sync_down(); return OK; From 67c5d07e837151243f91e6dbf004b543646c2460 Mon Sep 17 00:00:00 2001 From: Lok Tep Date: Wed, 11 Nov 2015 13:47:21 +0100 Subject: [PATCH 14/14] usb/ssp initialization corrected --- arch/arm/src/lpc43xx/Make.defs | 4 +-- arch/arm/src/lpc43xx/lpc43_spi.c | 37 +++++++++++++++++++++ arch/arm/src/lpc43xx/lpc43_usb0dev.c | 49 ++++++++++------------------ 3 files changed, 57 insertions(+), 33 deletions(-) diff --git a/arch/arm/src/lpc43xx/Make.defs b/arch/arm/src/lpc43xx/Make.defs index b944c210b31..3b3f8b1948f 100644 --- a/arch/arm/src/lpc43xx/Make.defs +++ b/arch/arm/src/lpc43xx/Make.defs @@ -133,10 +133,10 @@ CHIP_CSRCS += lpc43_spifi.c endif ifeq ($(CONFIG_LPC43_SSP0),y) -CHIP_CSRCS += lpc43_ssp.c +CHIP_CSRCS += lpc43_ssp.c lpc43_spi.c else ifeq ($(CONFIG_LPC43_SSP1),y) -CHIP_CSRCS += lpc43_ssp.c +CHIP_CSRCS += lpc43_ssp.c lpc43_spi.c endif endif diff --git a/arch/arm/src/lpc43xx/lpc43_spi.c b/arch/arm/src/lpc43xx/lpc43_spi.c index f1ae4bbf4f2..e56367e4ef1 100644 --- a/arch/arm/src/lpc43xx/lpc43_spi.c +++ b/arch/arm/src/lpc43xx/lpc43_spi.c @@ -56,6 +56,7 @@ #include "chip.h" #include "lpc43_pinconfig.h" #include "lpc43_spi.h" +#include "lpc43_ssp.h" #ifdef CONFIG_LPC43_SPI @@ -583,3 +584,39 @@ FAR struct spi_dev_s *lpc43_spiinitialize(int port) #endif /* CONFIG_LPC43_SPI */ +/**************************************************************************** + * Name: up_spiinitialize + * + * Description: + * Initialize the selected SPI port + * 0 - SPI + * 1 - SSP0 + * 2 - SSP1 + * + * Input Parameter: + * Port number (for hardware that has multiple SPI interfaces) + * + * Returned Value: + * Valid SPI device structure reference on success; a NULL on failure + * + ****************************************************************************/ + +FAR struct spi_dev_s *up_spiinitialize(int port) +{ + if (port) { +#if ( defined(CONFIG_LPC43_SSP0) || defined(CONFIG_LPC43_SSP1) ) + return lpc43_sspinitialize(port-1); +#else + return NULL; +#endif + } else { +#if defined(CONFIG_LPC43_SPI) + return lpc43_spiinitialize(port); +#else + return NULL; +#endif + } +} + + + diff --git a/arch/arm/src/lpc43xx/lpc43_usb0dev.c b/arch/arm/src/lpc43xx/lpc43_usb0dev.c index 8d8237bcf9b..4af4e887919 100644 --- a/arch/arm/src/lpc43xx/lpc43_usb0dev.c +++ b/arch/arm/src/lpc43xx/lpc43_usb0dev.c @@ -2583,12 +2583,9 @@ void up_usbinitialize(void) struct lpc43_usbdev_s *priv = &g_usbdev; int i; uint32_t regval; + irqstate_t flags; - usbtrace(TRACE_DEVINIT, 0); - - /* Disable USB interrupts */ - - lpc43_putreg(0, LPC43_USBDEV_USBINTR); + flags = irqsave(); /* Initialize the device state structure */ @@ -2646,10 +2643,15 @@ void up_usbinitialize(void) } } + /* Enable PLL0 clock */ + + lpc43_pll0usbconfig(); + lpc43_pll0usbenable(); + /* Clock */ regval = getreg32(LPC43_BASE_USB0_CLK); - regval &= ~BASE_USB0_CLK_CLKSEL_MASK; + regval &= ~(BASE_USB0_CLK_CLKSEL_MASK | BASE_USB0_CLK_PD) ; regval |= (BASE_USB0_CLKSEL_PLL0USB | BASE_USB0_CLK_AUTOBLOCK); putreg32(regval, LPC43_BASE_USB0_CLK); @@ -2659,18 +2661,11 @@ void up_usbinitialize(void) regval |= CCU_CLK_CFG_RUN; putreg32(regval, LPC43_CCU1_M4_USB0_CFG); - /* Enable PLL0 clock */ + //lpc43_putreg(RGU_CTRL0_USB0_RST, LPC43_RGU_CTRL0); /* Reset USB block */ - lpc43_pll0usbconfig(); - lpc43_pll0usbenable(); + lpc43_pullup(&priv->usbdev, false); /* disconnect device */ - /* Reset USB block */ - - lpc43_putreg(RGU_CTRL0_USB0_RST, LPC43_RGU_CTRL0); - - /* Reset the controller */ - - lpc43_putreg (USBDEV_USBCMD_RST, LPC43_USBDEV_USBCMD); + lpc43_setbits (USBDEV_USBCMD_RST, LPC43_USBDEV_USBCMD); /* Reset the controller */ while (lpc43_getreg (LPC43_USBDEV_USBCMD) & USBDEV_USBCMD_RST) ; @@ -2680,33 +2675,25 @@ void up_usbinitialize(void) regval &= ~CREG0_USB0PHY; putreg32(regval, LPC43_CREG0); - /* Attach USB controller interrupt handler */ - - if (irq_attach(LPC43M4_IRQ_USB0, lpc43_usbinterrupt) != 0) - { - usbtrace(TRACE_DEVERROR(LPC43_TRACEERR_IRQREGISTRATION), - (uint16_t)LPC43M4_IRQ_USB0); - goto errout; - } - + lpc43_putreg(0, LPC43_USBDEV_USBINTR); /* Disable USB interrupts */ /* Program the controller to be the USB device controller */ lpc43_putreg (USBDEV_USBMODE_SDIS | USBDEV_USBMODE_SLOM | USBDEV_USBMODE_CM_DEVICE, LPC43_USBDEV_USBMODE); - /* Disconnect device */ + /* Attach USB controller interrupt handler */ - lpc43_pullup(&priv->usbdev, false); + irq_attach(LPC43M4_IRQ_USB0, lpc43_usbinterrupt); + up_enable_irq(LPC43M4_IRQ_USB0); + + irqrestore(flags); /* Reset/Re-initialize the USB hardware */ lpc43_usbreset(priv); return; - -errout: - up_usbuninitialize(); } /**************************************************************************** @@ -2739,7 +2726,7 @@ void up_usbuninitialize(void) /* Reset the controller */ - lpc43_putreg (USBDEV_USBCMD_RST, LPC43_USBDEV_USBCMD); + lpc43_setbits (USBDEV_USBCMD_RST, LPC43_USBDEV_USBCMD); while (lpc43_getreg (LPC43_USBDEV_USBCMD) & USBDEV_USBCMD_RST) ;