diff options
author | patacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3> | 2012-09-17 18:18:44 +0000 |
---|---|---|
committer | patacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3> | 2012-09-17 18:18:44 +0000 |
commit | 57623d42ebb04f0a0b9e6eb7c0847a3ece2aa0ff (patch) | |
tree | 25d07d14e920d31c0b1947c9ca586f2a01fc32d8 /nuttx/arch/arm/src/lpc214x | |
download | px4-firmware-57623d42ebb04f0a0b9e6eb7c0847a3ece2aa0ff.tar.gz px4-firmware-57623d42ebb04f0a0b9e6eb7c0847a3ece2aa0ff.tar.bz2 px4-firmware-57623d42ebb04f0a0b9e6eb7c0847a3ece2aa0ff.zip |
Resync new repository with old repo r5166
git-svn-id: http://svn.code.sf.net/p/nuttx/code/trunk@5153 42af7a65-404d-4744-a932-0658087f49c3
Diffstat (limited to 'nuttx/arch/arm/src/lpc214x')
21 files changed, 7647 insertions, 0 deletions
diff --git a/nuttx/arch/arm/src/lpc214x/Kconfig b/nuttx/arch/arm/src/lpc214x/Kconfig new file mode 100644 index 000000000..a26483ed9 --- /dev/null +++ b/nuttx/arch/arm/src/lpc214x/Kconfig @@ -0,0 +1,6 @@ +# +# For a description of the syntax of this configuration file, +# see misc/tools/kconfig-language.txt. +# + +comment "LPC214x Configuration Options" diff --git a/nuttx/arch/arm/src/lpc214x/Make.defs b/nuttx/arch/arm/src/lpc214x/Make.defs new file mode 100644 index 000000000..41dc0911c --- /dev/null +++ b/nuttx/arch/arm/src/lpc214x/Make.defs @@ -0,0 +1,57 @@ +############################################################################## +# lpc214x/Make.defs +# +# Copyright (C) 2007, 2008 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt <gnutt@nuttx.org> +# +# 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. +# +############################################################################## + +HEAD_ASRC = lpc214x_head.S + +CMN_ASRCS = up_saveusercontext.S up_fullcontextrestore.S up_vectors.S +CMN_CSRCS = up_allocateheap.c up_assert.c up_blocktask.c up_copystate.c \ + up_createstack.c up_dataabort.c up_mdelay.c up_udelay.c \ + up_exit.c up_idle.c up_initialize.c up_initialstate.c \ + up_interruptcontext.c up_prefetchabort.c up_releasepending.c \ + up_releasestack.c up_reprioritizertr.c up_syscall.c up_unblocktask.c \ + up_undefinedinsn.c up_usestack.c up_lowputs.c + +ifneq ($(CONFIG_DISABLE_SIGNALS),y) +CMN_CSRCS += up_schedulesigaction.c up_sigdeliver.c +endif + +CHIP_ASRCS = lpc214x_lowputc.S +CHIP_CSRCS = lpc214x_decodeirq.c lpc214x_irq.c lpc214x_timerisr.c \ + lpc214x_serial.c + +ifeq ($(CONFIG_USBDEV),y) +CHIP_CSRCS += lpc214x_usbdev.c +endif + diff --git a/nuttx/arch/arm/src/lpc214x/README.txt b/nuttx/arch/arm/src/lpc214x/README.txt new file mode 100644 index 000000000..9cfc99593 --- /dev/null +++ b/nuttx/arch/arm/src/lpc214x/README.txt @@ -0,0 +1,61 @@ +General Description +^^^^^^^^^^^^^^^^^^^ + +http://www.nxp.com/pip/LPC2141FBD64.html: + +The LPC2141/42/44/46/48 microcontrollers are based on a 16-bit/32-bit ARM7TDMI-S +CPU with real-time emulation and embedded trace support, that combine +microcontroller with embedded high-speed flash memory ranging from 32 kB to +512 kB. A 128-bit wide memory interface and a unique accelerator architecture +enable 32-bit code execution at the maximum clock rate. For critical code size +applications, the alternative 16-bit Thumb mode reduces code by more than 30 pct +with minimal performance penalty. + +Due to their tiny size and low power consumption, LPC2141/42/44/46/48 are ideal +for applications where miniaturization is a key requirement, such as access +control and point-of-sale. Serial communications interfaces ranging from a USB 2.0 +Full-speed device, multiple UARTs, SPI, SSP to I2C-bus and on-chip SRAM of 8 kB +up to 40 kB, make these devices very well suited for communication gateways and +protocol converters, soft modems, voice recognition and low end imaging, providing +both large buffer size and high processing power. Various 32-bit timers, single +or dual 10-bit ADC(s), 10-bit DAC, PWM channels and 45 fast GPIO lines with up +to nine edge or level sensitive external interrupt pins make these microcontrollers +suitable for industrial control and medical systems. + + +Features +^^^^^^^^ + +o 16-bit/32-bit ARM7TDMI-S microcontroller in a tiny LQFP64 package. +o 8 kB to 40 kB of on-chip static RAM and 32 kB to 512 kB of on-chip flash memory. + 128-bit wide interface/accelerator enables high-speed 60 MHz operation. +o In-System Programming/In-Application Programming (ISP/IAP) via on-chip boot + loader software. Single flash sector or full chip erase in 400 ms and programming + of 256 B in 1 ms. +o EmbeddedICE RT and Embedded Trace interfaces offer real-time debugging with the + on-chip RealMonitor software and high-speed tracing of instruction execution. +o USB 2.0 Full-speed compliant device controller with 2 kB of endpoint RAM. In addition, + the LPC2146/48 provides 8 kB of on-chip RAM accessible to USB by DMA. +o One or two (LPC2141/42 vs. LPC2144/46/48) 10-bit ADCs provide a total of 6/14 analog + inputs, with conversion times as low as 2.44 us per channel. +o Single 10-bit DAC provides variable analog output (LPC2142/44/46/48 only). +o Two 32-bit timers/external event counters (with four capture and four compare + channels each), PWM unit (six outputs) and watchdog. +o Low power Real-Time Clock (RTC) with independent power and 32 kHz clock input. +o Multiple serial interfaces including two UARTs (16C550), two Fast I2C-bus (400 + kbit/s), SPI and SSP with buffering and variable data length capabilities. +o Vectored Interrupt Controller (VIC) with configurable priorities and vector addresses. +o Up to 45 of 5 V tolerant fast general purpose I/O pins in a tiny LQFP64 package. +o Up to 21 external interrupt pins available. +o 60 MHz maximum CPU clock available from programmable on-chip PLL with settling + time of 100 us. +o On-chip integrated oscillator operates with an external crystal from 1 MHz to 25 MHz. +o Power saving modes include Idle and Power-down. +o Individual enable/disable of peripheral functions as well as peripheral clock scaling + for additional power optimization. +o Processor wake-up from Power-down mode via external interrupt or BOD. +o Single power supply chip with POR and BOD circuits: +o CPU operating voltage range of 3.0 V to 3.6 V (3.3 V +- 10 pct) with 5 V tolerant + I/O pads. + + diff --git a/nuttx/arch/arm/src/lpc214x/chip.h b/nuttx/arch/arm/src/lpc214x/chip.h new file mode 100644 index 000000000..d469aae8b --- /dev/null +++ b/nuttx/arch/arm/src/lpc214x/chip.h @@ -0,0 +1,349 @@ +/**************************************************************************************************** + * arch/arm/src/lpc214x/chip.h + * + * Copyright (C) 2007, 2008 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <gnutt@nuttx.org> + * + * 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. + * + ****************************************************************************************************/ + +#ifndef __LPC214X_CHIP_H +#define __LPC214X_CHIP_H + +/**************************************************************************************************** + * Included Files + ****************************************************************************************************/ + +/**************************************************************************************************** + * Definitions + ****************************************************************************************************/ + +/* Memory Map ***************************************************************************************/ + +#define LPC214X_FLASH_BASE 0x00000000 +#define LPC214X_FIO_BASE 0x3fffc000 +#define LPC214X_ONCHIP_RAM_BASE 0x40000000 +#define LPC214X_USBDMA_RAM_BASE 0x7fd00000 +#define LPC214X_BOOT_BLOCK 0x7fffd000 +#define LPC214X_EXTMEM_BASE 0x80000000 +#define LPC214X_APB_BASE 0xe0000000 +#define LPC214X_AHB_BASE 0xf0000000 + +/* Peripheral Registers ****************************************************************************/ + +/* FIO Register block base addresses */ + +#define LPC214X_FIO0_BASE 0x3fffc000 /* Fast I/O 0 base address */ +#define LPC214X_FIO1_BASE 0x3fffc020 /* Fast I/O 1 base address */ + +/* APB Register block base addresses */ + +#define LPC214X_WD_BASE 0xe0000000 /* Watchdog base address */ +#define LPC214X_TMR0_BASE 0xe0004000 /* Timer 0 base address*/ +#define LPC214X_TMR1_BASE 0xe0008000 /* Timer 1 base address */ +#define LPC214X_UART0_BASE 0xe000c000 /* UART0 base address */ +#define LPC214X_UART1_BASE 0xe0010000 /* UART1 base address */ +#define LPC214X_PWM_BASE 0xe0014000 /* Pulse width modulator (PWM) base address */ +#define LPC214X_I2C0_BASE 0xe001c000 /* I2C0 base address */ +#define LPC214X_SPI0_BASE 0xe0020000 /* Serial Peripheral Interface 0 (SPI0) base */ +#define LPC214X_RTC_BASE 0xe0024000 /* Real Time Clock (RTC) base address */ +#define LPC214X_GPIO0_BASE 0xe0028000 /* General Purpose I/O (GPIO) 0 base address */ +#define LPC214X_GPIO1_BASE 0xe0028010 /* General Purpose I/O (GPIO) 0 base address */ +#define LPC214X_PINSEL_BASE 0xe002c000 /* Pin function select registers */ +#define LPC214X_AD0_BASE 0xe0034000 /* Analog to Digital Converter 0 base address*/ +#define LPC214X_I2C1_BASE 0xe005c000 /* I2C1 base address */ +#define LPC214X_AD1_BASE 0xe0060000 /* Analog to Digital Converter 1 base address */ +#define LPC214X_SPI1_BASE 0xe0068000 /* Serial Peripheral Interface 1 (SPI1) base */ +#define LPC214X_DAC_BASE 0xe0090000 /* DAC base address */ +#define LPC214X_USB_BASE 0xe0090000 /* USB base address */ + +#define LPC214X_SCB_BASE 0xe01fc000 /* System Control Block (SBC) base address */ +#define LPC214X_MAM_BASE 0xe01fc000 /* Memory Accelerator Module (MAM) base address */ +#define LPC214X_SCS 0xe01fc1a0 /* System Control and Status flags (SCS) */ +#define LPC214X_MEMMAP 0xe01fc040 /* Memory Mapping Control */ +#define LPC214X_PLL_BASE 0xe01fc080 /* Phase Locked Loop (PLL) base address */ +#define LPC214X_PCON_BASE 0xe01fc0c0 /* Power Control (PCON) base address */ +#define LPC214X_APBDIV 0xe01fc100 /* APBDIV Address */ +#define LPC214X_EXT_BASE 0xe01fc140 /* External Interrupt base address */ + +/* AHB Register block base addresses */ + +#define LPC214X_EMC_BASE 0xffe00000 /* External Memory Controller (EMC) base address */ +#define LPC214X_VIC_BASE 0xfffff000 /* Vectored Interrupt Controller (VIC) Base */ + +/* Watchdog Register Offsets */ + +#define LPC214X_WD_MOD_OFFSET 0x00 /* Watchdog Mode Register */ +#define LPC214X_WD_TC_OFFSET 0x04 /* Watchdog Time Constant Register */ +#define LPC214X_WD_FEED_OFFSET 0x08 /* Watchdog Feed Register */ +#define LPC214X_WD_TV_OFFSET 0x0C /* Watchdog Time Value Register */ + +/* Timer 0/1 register offsets */ + +#define LPC214X_TMR_IR_OFFSET 0x00 /* RW:Interrupt Register */ +#define LPC214X_TMR_TCR_OFFSET 0x04 /* RW: Timer Control Register */ +#define LPC214X_TMR_TC_OFFSET 0x08 /* RW: Timer Counter */ +#define LPC214X_TMR_PR_OFFSET 0x0c /* RW: Prescale Register */ +#define LPC214X_TMR_PC_OFFSET 0x10 /* RW: Prescale Counter Register */ +#define LPC214X_TMR_MCR_OFFSET 0x14 /* RW: Match Control Register */ +#define LPC214X_TMR_MR0_OFFSET 0x18 /* RW: Match Register 0 */ +#define LPC214X_TMR_MR1_OFFSET 0x1c /* RW: Match Register 1 */ +#define LPC214X_TMR_MR2_OFFSET 0x20 /* RW: Match Register 2 */ +#define LPC214X_TMR_MR3_OFFSET 0x24 /* RW: Match Register 3 */ +#define LPC214X_TMR_CCR_OFFSET 0x28 /* RW: Capture Control Register */ +#define LPC214X_TMR_CR0_OFFSET 0x2c /* R: Capture Register 0 */ +#define LPC214X_TMR_CR1_OFFSET 0x30 /* R: Capture Register 1 */ +#define LPC214X_TMR_CR2_OFFSET 0x34 /* R: Capture Register 2 */ +#define LPC214X_TMR_CR3_OFFSET 0x38 /* RW: Capture Register 3 */ +#define LPC214X_TMR_EMR_OFFSET 0x3c /* RW: External Match Register */ + +#define LPC214X_TMR_CTCR_OFFSET 0x70 /* RW: Count Control Register */ + +/* UART0/1 Register Offsets */ + +#define LPC214X_UART_RBR_OFFSET 0x00 /* R: Receive Buffer Register (DLAB=0) */ +#define LPC214X_UART_THR_OFFSET 0x00 /* W: Transmit Holding Register (DLAB=0) */ +#define LPC214X_UART_DLL_OFFSET 0x00 /* W: Divisor Latch Register (LSB, DLAB=1) */ +#define LPC214X_UART_IER_OFFSET 0x04 /* W: Interrupt Enable Register (DLAB=0) */ +#define LPC214X_UART_DLM_OFFSET 0x04 /* RW: Divisor Latch Register (MSB, DLAB=1) */ +#define LPC214X_UART_IIR_OFFSET 0x08 /* R: Interrupt ID Register */ +#define LPC214X_UART_FCR_OFFSET 0x08 /* W: FIFO Control Register */ +#define LPC214X_UART_LCR_OFFSET 0x0c /* RW: Line Control Register */ +#define LPC214X_UART_MCR_OFFSET 0x10 /* RW: Modem Control REgister (2146/6/8 UART1 Only) */ +#define LPC214X_UART_LSR_OFFSET 0x14 /* R: Scratch Pad Register */ +#define LPC214X_UART_MSR_OFFSET 0x18 /* RW: MODEM Status Register (2146/6/8 UART1 Only) */ +#define LPC214X_UART_SCR_OFFSET 0x1c /* RW: Line Status Register */ +#define LPC214X_UART_ACR_OFFSET 0x20 /* RW: Autobaud Control Register */ +#define LPC214X_UART_FDR_OFFSET 0x28 /* RW: Fractional Divider Register */ +#define LPC214X_UART_TER_OFFSET 0x30 /* RW: Transmit Enable Register */ + +/* PWM register offsets */ + +#define LPC214X_PWM_IR_OFFSET 0x00 /* Interrupt Register */ +#define LPC214X_PWM_TCR_OFFSET 0x04 /* Timer Control Register */ +#define LPC214X_PWM_TC_OFFSET 0x08 /* Timer Counter */ +#define LPC214X_PWM_PR_OFFSET 0x0c /* Prescale Register */ +#define LPC214X_PWM_PC_OFFSET 0x10 /* Prescale Counter Register */ +#define LPC214X_PWM_MCR_OFFSET 0x14 /* Match Control Register */ +#define LPC214X_PWM_MR0_OFFSET 0x18 /* Match Register 0 */ +#define LPC214X_PWM_MR1_OFFSET 0x1c /* Match Register 1 */ +#define LPC214X_PWM_MR2_OFFSET 0x20 /* Match Register 2 */ +#define LPC214X_PWM_MR3_OFFSET 0x24 /* Match Register 3 */ +#define LPC214X_PWM_MR4_OFFSET 0x40 /* Match Register 4 */ +#define LPC214X_PWM_MR5_OFFSET 0x44 /* Match Register 5 */ +#define LPC214X_PWM_MR6_OFFSET 0x48 /* Match Register 6 */ +#define LPC214X_PWM_PCR_OFFSET 0x4c /* Control Register */ +#define LPC214X_PWM_LER_OFFSET 0x50 /* Latch Enable Register */ + +/* I2C register offsets */ + +#define LPC214X_I2C_CONSET_OFFSET 0x00 /* Control Set Register */ +#define LPC214X_I2C_STAT_OFFSET 0x04 /* Status Register */ +#define LPC214X_I2C_DAT_OFFSET 0x08 /* Data Register */ +#define LPC214X_I2C_ADR_OFFSET 0x0c /* Slave Address Register */ +#define LPC214X_I2C_SCLH_OFFSET 0x10 /* SCL Duty Cycle Register (high half word) */ +#define LPC214X_I2C_SCLL_OFFSET 0x14 /* SCL Duty Cycle Register (low half word) */ +#define LPC214X_I2C_CONCLR_OFFSET 0x18 /* Control Clear Register */ + +/* Pin function select register offsets */ + +#define LPC214X_PINSEL0_OFFSET 0x00 /* Pin function select register 0 */ +#define LPC214X_PINSEL1_OFFSET 0x04 /* Pin function select register 1 */ +#define LPC214X_PINSEL2_OFFSET 0x14 /* Pin function select register 2 */ + +/* Analog to Digital (AD) Converter registger offsets */ + +#define LPC214X_AD_ADCR_OFFSET 0x00 /* A/D Control Register */ +#define LPC214X_AD_ADGDR_OFFSET 0x04 /* A/D Global Data Register (only one common register!) */ +#define LPC214X_AD_ADGSR_OFFSET 0x08 /* A/D Global Start Register */ +#define LPC214X_AD_ADINTEN_OFFSET 0x0c /* A/D Interrupt Enable Register */ +#define LPC214X_AD_ADDR0_OFFSET 0x10 /* A/D Chanel 0 Data Register */ +#define LPC214X_AD_ADDR1_OFFSET 0x14 /* A/D Chanel 0 Data Register */ +#define LPC214X_AD_ADDR2_OFFSET 0x18 /* A/D Chanel 0 Data Register */ +#define LPC214X_AD_ADDR3_OFFSET 0x1c /* A/D Chanel 0 Data Register */ +#define LPC214X_AD_ADDR4_OFFSET 0x20 /* A/D Chanel 0 Data Register */ +#define LPC214X_AD_ADDR5_OFFSET 0x24 /* A/D Chanel 0 Data Register */ +#define LPC214X_AD_ADDR6_OFFSET 0x28 /* A/D Chanel 0 Data Register */ +#define LPC214X_AD_ADDR7_OFFSET 0x2c /* A/D Chanel 0 Data Register */ +#define LPC214X_AD_ADSTAT_OFFSET 0x30 /* A/D Status Register */ + +/* SPI0 register offsets */ + +#define LPC214X_SPI0_CR_OFFSET 0x00 /* Control Register 0 */ +#define LPC214X_SPI0_SR_OFFSET 0x04 /* Control Register 1 */ +#define LPC214X_SPI0_DR_OFFSET 0x08 /* Data Register */ +#define LPC214X_SPI0_CCR_OFFSET 0x0c /* Status Register */ +#define LPC214X_SPI0_INT_OFFSET 0x1c /* Clock Pre-Scale Regisrer */ + +/* SPI1 register offsets */ + +#define LPC214X_SPI1_CR0_OFFSET 0x00 /* Control Register 0 */ +#define LPC214X_SPI1_CR1_OFFSET 0x04 /* Control Register 1 */ +#define LPC214X_SPI1_DR_OFFSET 0x08 /* Data Register */ +#define LPC214X_SPI1_SR_OFFSET 0x0c /* Status Register */ +#define LPC214X_SPI1_CPSR_OFFSET 0x10 /* Clock Pre-Scale Regisrer */ +#define LPC214X_SPI1_IMSC_OFFSET 0x14 /* Interrupt Mask Set and Clear Register */ +#define LPC214X_SPI1_RIS_OFFSET 0x18 /* Raw Interrupt Status Register */ +#define LPC214X_SPI1_MIS_OFFSET 0x1c /* Masked Interrupt Status Register */ +#define LPC214X_SPI1_ICR_OFFSET 0x20 /* Interrupt Clear Register */ + +/* RTC register offsets */ + +#define LPC214X_RTC_ILR_OFFSET 0x00 /* Interrupt Location Register */ +#define LPC214X_RTC_CTC_OFFSET 0x04 /* Clock Tick Counter */ +#define LPC214X_RTC_CCR_OFFSET 0x08 /* Clock Control Register */ +#define LPC214X_RTC_CIIR_OFFSET 0x0c /* Counter Increment Interrupt Register */ +#define LPC214X_RTC_AMR_OFFSET 0x10 /* Alarm Mask Register */ +#define LPC214X_RTC_CTIME0_OFFSET 0x14 /* Consolidated Time Register 0 */ +#define LPC214X_RTC_CTIME1_OFFSET 0x18 /* Consolidated Time Register 1 */ +#define LPC214X_RTC_CTIME2_OFFSET 0x1c /* Consolidated Time Register 2 */ +#define LPC214X_RTC_SEC_OFFSET 0x20 /* Seconds Register */ +#define LPC214X_RTC_MIN_OFFSET 0x24 /* Minutes Register */ +#define LPC214X_RTC_HOUR_OFFSET 0x28 /* Hours Register */ +#define LPC214X_RTC_DOM_OFFSET 0x2c /* Day Of Month Register */ +#define LPC214X_RTC_DOW_OFFSET 0x30 /* Day Of Week Register */ +#define LPC214X_RTC_DOY_OFFSET 0x34 /* Day Of Year Register */ +#define LPC214X_RTC_MONTH_OFFSET 0x38 /* Months Register */ +#define LPC214X_RTC_YEAR_OFFSET 0x3c /* Years Register */ + +#define LPC214X_RTC_ALSEC_OFFSET 0x60 /* Alarm Seconds Register */ +#define LPC214X_RTC_ALMIN_OFFSET 0x64 /* Alarm Minutes Register */ +#define LPC214X_RTC_ALHOUR_OFFSET 0x68 /* Alarm Hours Register */ +#define LPC214X_RTC_ALDOM_OFFSET 0x6c /* Alarm Day Of Month Register */ +#define LPC214X_RTC_ALDOW_OFFSET 0x70 /* Alarm Day Of Week Register */ +#define LPC214X_RTC_ALDOY_OFFSET 0x74 /* Alarm Day Of Year Register */ +#define LPC214X_RTC_ALMON_OFFSET 0x78 /* Alarm Months Register */ +#define LPC214X_RTC_ALYEAR_OFFSET 0x7c /* Alarm Years Register */ +#define LPC214X_RTC_PREINT_OFFSET 0x80 /* Prescale Value Register (integer) */ +#define LPC214X_RTC_PREFRAC_OFFSET 0x84 /* Prescale Value Register (fraction) */ + +/* GPIO register offsets */ + +#define LPC214X_GPIO_PIN_OFFSET 0x00 /* Pin Value Register */ +#define LPC214X_GPIO_SET_OFFSET 0x04 /* Pin Output Set Register */ +#define LPC214X_GPIO_DIR_OFFSET 0x08 /* Pin Direction Register */ +#define LPC214X_GPIO_CLR_OFFSET 0x0c /* Pin Output Clear Register */ + +/* FIO register offsets */ + +#define LPC214X_FIO_DIR_OFFSET 0x00 /* Fast GPIO Port Direction Register */ +#define LPC214X_FIO_MASK_OFFSET 0x10 /* Fast GPIO Mask Register */ +#define LPC214X_FIO_PIN_OFFSET 0x14 /* Fast GPIO Pin Value Register */ +#define LPC214X_FIO_SET_OFFSET 0x18 /* Fast GPIO Port Output Set Register */ +#define LPC214X_FIO_CLR_OFFSET 0x1c /* Fast GPIO Port Output Clear Register */ + +/* Memory Accelerator Module (MAM) Regiser Offsets */ + +#define LPC214X_MAM_CR_OFFSET 0x00 /* MAM Control Offset*/ +#define LPC214x_MAM_TIM_OFFSET 0x04 /* MAM Timing Offset */ + +/* Phase Locked Loop (PLL) Register Offsets */ + +#define LPC214X_PLL_CON_OFFSET 0x00 /* PLL Control Offset*/ +#define LPC214X_PLL_CFG_OFFSET 0x04 /* PLL Configuration Offset */ +#define LPC214X_PLL_STAT_OFFSET 0x08 /* PLL Status Offset */ +#define LPC214X_PLL_FEED_OFFSET 0x0c /* PLL Feed Offset */ + +/* Power Control register offsets */ + +#define LPC214X_PCON_OFFSET 0x00 /* Control Register */ +#define LPC214X_PCONP_OFFSET 0x04 /* Peripherals Register */ + +/* External Interrupt register offsets */ + +#define LPC214X_EXT_INT_OFFSET 0x00 /* Flag Register */ +#define LPC214X_EXT_WAKE_OFFSET 0x04 /* Wakeup Register */ +#define LPC214X_EXT_MODE_OFFSET 0x08 /* Mode Register */ +#define LPC214X_EXT_POLAR_OFFSET 0x0c /* Polarity Register */ + +/* External Memory Controller (EMC) definitions */ + +#define LPC214X_BCFG0_OFFSET 0x00 /* BCFG0 Offset */ +#define LPC214X_BCFG1_OFFSET 0x04 /* BCFG1 Offset */ +#define LPC214X_BCFG2_OFFSET 0x08 /* BCFG2 Offset */ +#define LPC214X_BCFG3_OFFSET 0x0c /* BCFG3 Offset */ + +/* Vectored Interrupt Controller (VIC) register offsets */ + +#define LPC214X_VIC_IRQSTATUS_OFFSET 0x00 /* R: IRQ Status Register */ +#define LPC214X_VIC_FIQSTATUS_OFFSET 0x04 /* R: FIQ Status Register */ +#define LPC214X_VIC_RAWINTR_OFFSET 0x08 /* R: Raw Interrupt Status Register */ +#define LPC214X_VIC_INTSELECT_OFFSET 0x0c /* RW: Interrupt Select Register */ +#define LPC214X_VIC_INTENABLE_OFFSET 0x10 /* RW: Interrupt Enable Register */ +#define LPC214X_VIC_INTENCLEAR_OFFSET 0x14 /* W: Interrupt Enable Clear Register */ +#define LPC214X_VIC_SOFTINT_OFFSET 0x18 /* RW: Software Interrupt Register */ +#define LPC214X_VIC_SOFTINTCLEAR_OFFSET 0x1c /* W: Software Interrupt Clear Register */ +#define LPC214X_VIC_PROTECTION_OFFSET 0x20 /* Protection Enable Register */ + +#define LPC214X_VIC_VECTADDR_OFFSET 0x30 /* RW: Vector Address Register */ +#define LPC214X_VIC_DEFVECTADDR_OFFSET 0x34 /* RW: Default Vector Address Register */ + +#define LPC214X_VIC_VECTADDR0_OFFSET 0x100 /* RW: Vector Address 0 Register */ +#define LPC214X_VIC_VECTADDR1_OFFSET 0x104 /* RW: Vector Address 1 Register */ +#define LPC214X_VIC_VECTADDR2_OFFSET 0x108 /* RW: Vector Address 2 Register */ +#define LPC214X_VIC_VECTADDR3_OFFSET 0x10c /* RW: Vector Address 3 Register */ +#define LPC214X_VIC_VECTADDR4_OFFSET 0x110 /* RW: Vector Address 4 Register */ +#define LPC214X_VIC_VECTADDR5_OFFSET 0x114 /* RW: Vector Address 5 Register */ +#define LPC214X_VIC_VECTADDR6_OFFSET 0x118 /* RW: Vector Address 6 Register */ +#define LPC214X_VIC_VECTADDR7_OFFSET 0x11c /* RW: Vector Address 7 Register */ +#define LPC214X_VIC_VECTADDR8_OFFSET 0x120 /* RW: Vector Address 8 Register */ +#define LPC214X_VIC_VECTADDR9_OFFSET 0x124 /* RW: Vector Address 9 Register */ +#define LPC214X_VIC_VECTADDR10_OFFSET 0x128 /* RW: Vector Address 10 Register */ +#define LPC214X_VIC_VECTADDR11_OFFSET 0x12c /* RW: Vector Address 11 Register */ +#define LPC214X_VIC_VECTADDR12_OFFSET 0x130 /* RW: Vector Address 12 Register */ +#define LPC214X_VIC_VECTADDR13_OFFSET 0x134 /* RW: Vector Address 13 Register */ +#define LPC214X_VIC_VECTADDR14_OFFSET 0x138 /* RW: Vector Address 14 Register */ +#define LPC214X_VIC_VECTADDR15_OFFSET 0x13c /* RW: Vector Address 15 Register */ + +#define LPC214X_VIC_VECTCNTL0_OFFSET 0x200 /* RW: Vector Control 0 Register */ +#define LPC214X_VIC_VECTCNTL1_OFFSET 0x204 /* RW: Vector Control 1 Register */ +#define LPC214X_VIC_VECTCNTL2_OFFSET 0x208 /* RW: Vector Control 2 Register */ +#define LPC214X_VIC_VECTCNTL3_OFFSET 0x20c /* RW: Vector Control 3 Register */ +#define LPC214X_VIC_VECTCNTL4_OFFSET 0x210 /* RW: Vector Control 4 Register */ +#define LPC214X_VIC_VECTCNTL5_OFFSET 0x214 /* RW: Vector Control 5 Register */ +#define LPC214X_VIC_VECTCNTL6_OFFSET 0x218 /* RW: Vector Control 6 Register */ +#define LPC214X_VIC_VECTCNTL7_OFFSET 0x21c /* RW: Vector Control 7 Register */ +#define LPC214X_VIC_VECTCNTL8_OFFSET 0x220 /* RW: Vector Control 8 Register */ +#define LPC214X_VIC_VECTCNTL9_OFFSET 0x224 /* RW: Vector Control 9 Register */ +#define LPC214X_VIC_VECTCNTL10_OFFSET 0x228 /* RW: Vector Control 10 Register */ +#define LPC214X_VIC_VECTCNTL11_OFFSET 0x22c /* RW: Vector Control 11 Register */ +#define LPC214X_VIC_VECTCNTL12_OFFSET 0x230 /* RW: Vector Control 12 Register */ +#define LPC214X_VIC_VECTCNTL13_OFFSET 0x234 /* RW: Vector Control 13 Register */ +#define LPC214X_VIC_VECTCNTL14_OFFSET 0x238 /* RW: Vector Control 14 Register */ +#define LPC214X_VIC_VECTCNTL15_OFFSET 0x23c /* RW: Vector Control 15 Register */ + +/**************************************************************************************************** + * Inline Functions + ****************************************************************************************************/ + +/**************************************************************************************************** + * Global Function Prototypes + ****************************************************************************************************/ + +#endif /* __LPC214X_CHIP_H */ diff --git a/nuttx/arch/arm/src/lpc214x/lpc214x_apb.h b/nuttx/arch/arm/src/lpc214x/lpc214x_apb.h new file mode 100644 index 000000000..2d41ab106 --- /dev/null +++ b/nuttx/arch/arm/src/lpc214x/lpc214x_apb.h @@ -0,0 +1,72 @@ +/************************************************************************************ + * arch/arm/src/lpc214x/lpc214x_apb.h + * + * Copyright (C) 2008 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <gnutt@nuttx.org> + * + * 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. + * + ************************************************************************************/ + +#ifndef _ARCH_ARM_SRC_LPC214X_APB_H +#define _ARCH_ARM_SRC_LPC214X_APB_H + +/************************************************************************************ + * Included Files + ************************************************************************************/ + +/************************************************************************************ + * Definitions + ************************************************************************************/ + +/* Register address definitions *****************************************************/ + +#define LPC214X_APB_APBDIV (0xe01fc100) /* 8-bit R/W APB divider register */ + +/* Register bit definitions *********************************************************/ + +/* APB divider register */ + +#define LPC214X_APBDIV_MASK (0x03) /* Bit 0:1: APB divider value */ +#define LPC214X_APBDIV_DIV4 (0x00) /* Bit 0:1=00: APB=PCLK/4 */ +#define LPC214X_APBDIV_DIV1 (0x01) /* Bit 0:1=01: APB=PCLK */ +#define LPC214X_APBDIV_DIV2 (0x02) /* Bit 0:1=10: APB=PCLK/2 */ + +/************************************************************************************ + * Public Types + ************************************************************************************/ + +/************************************************************************************ + * Inline Functions + ************************************************************************************/ + +/************************************************************************************ + * Public Function Prototypes + ************************************************************************************/ + +#endif /* _ARCH_ARM_SRC_LPC214X_APB_H */ diff --git a/nuttx/arch/arm/src/lpc214x/lpc214x_decodeirq.c b/nuttx/arch/arm/src/lpc214x/lpc214x_decodeirq.c new file mode 100644 index 000000000..652fe4d61 --- /dev/null +++ b/nuttx/arch/arm/src/lpc214x/lpc214x_decodeirq.c @@ -0,0 +1,177 @@ +/******************************************************************************** + * arch/arm/src/lpc214x/lpc214x_decodeirq.c + * + * Copyright (C) 2007-2009, 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <gnutt@nuttx.org> + * + * 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 <nuttx/config.h> + +#include <stdint.h> +#include <nuttx/irq.h> +#include <nuttx/arch.h> +#include <assert.h> +#include <debug.h> + +#include "chip.h" +#include "up_arch.h" +#include "os_internal.h" +#include "up_internal.h" + +#include "lpc214x_vic.h" + +/******************************************************************************** + * Definitions + ********************************************************************************/ + +/******************************************************************************** + * Private Types + ********************************************************************************/ + +/******************************************************************************** + * Public Data + ********************************************************************************/ + +/******************************************************************************** + * Private Data + ********************************************************************************/ + +/* This array maps 4 bits into the bit number of the lowest bit that it set */ + +#ifndef CONFIG_SUPPRESS_INTERRUPTS +static uint8_t g_nibblemap[16] = { 0, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 }; +#endif + +/******************************************************************************** + * Private Functions + ********************************************************************************/ + +/******************************************************************************** + * Public Funstions + ********************************************************************************/ + +/******************************************************************************** + * up_decodeirq() and/or lpc214x_decodeirq() + * + * Description: + * The vectored interrupt controller (VIC) takes 32 interrupt request inputs + * and programmatically assigns them into 3 categories: FIQ, vectored IRQ, + * and non-vectored IRQ. + * + * - FIQs have the highest priority. There is a single FIQ vector, but multiple + * interrupt sources can be ORed to this FIQ vector. + * + * - Vectored IRQs have the middle priority. Any 16 of the 32 interrupt sources + * can be assigned to vectored IRQs. + * + * - Non-vectored IRQs have the lowest priority. + * + * The general flow of IRQ processing is to simply read the VIC vector address + * and jump to the address of the vector provided in the register. The VIC will + * provide the address of the highest priority vectored IRQ. If a non-vectored + * IRQ is requesting, the address of a default handler is provided. + * + ********************************************************************************/ + +#ifndef CONFIG_VECTORED_INTERRUPTS +void up_decodeirq(uint32_t *regs) +#else +static void lpc214x_decodeirq( uint32_t *regs) +#endif +{ +#ifdef CONFIG_SUPPRESS_INTERRUPTS + lib_lowprintf("Unexpected IRQ\n"); + current_regs = regs; + PANIC(OSERR_ERREXCEPTION); +#else + + /* Decode the interrupt. We have to do this by search for the lowest numbered + * non-zero bit in the interrupt status register. + */ + + uint32_t pending = vic_getreg(LPC214X_VIC_IRQSTATUS_OFFSET) & 0x007fffff; + unsigned int nibble; + unsigned int irq_base; + unsigned int irq = NR_IRQS; + + /* Search in groups of four bits. For 22 sources, this is at most six + * times through the loop. + */ + + for (nibble = pending & 0x0f, irq_base = 0; + pending && irq_base < NR_IRQS; + pending >>= 4, nibble = pending & 0x0f, irq_base += 4) + { + if (nibble) + { + irq = irq_base + g_nibblemap[nibble]; + break; + } + } + + /* Verify that the resulting IRQ number is valid */ + + if (irq < NR_IRQS) + { + uint32_t *savestate; + + /* Current regs non-zero indicates that we are processing an interrupt; + * current_regs is also used to manage interrupt level context switches. + */ + + savestate = (uint32_t*)current_regs; + current_regs = regs; + + /* Deliver the IRQ */ + + irq_dispatch(irq, regs); + + /* Restore the previous value of current_regs. NULL would indicate that + * we are no longer in an interrupt handler. It will be non-NULL if we + * are returning from a nested interrupt. + */ + + current_regs = savestate; + } +#endif +} + +#ifdef CONFIG_VECTORED_INTERRUPTS +void up_decodeirq(uint32_t *regs) +{ + vic_vector_t vector = (vic_vector_t)vic_getreg(LPC214X_VIC_VECTADDR_OFFSET); + vector(regs); +} +#endif diff --git a/nuttx/arch/arm/src/lpc214x/lpc214x_head.S b/nuttx/arch/arm/src/lpc214x/lpc214x_head.S new file mode 100644 index 000000000..678481154 --- /dev/null +++ b/nuttx/arch/arm/src/lpc214x/lpc214x_head.S @@ -0,0 +1,634 @@ +/***************************************************************************** + * arch/arm/src/lpc214x/lpc214x_head.S + * + * Copyright (C) 2007-2009, 2012 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <gnutt@nuttx.org> + * + * 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 <nuttx/config.h> + +#include <arch/board/board.h> + +#include "arm.h" +#include "chip.h" +#include "lpc214x_pll.h" +#include "lpc214x_apb.h" +#include "lpc214x_pinsel.h" +#include "up_internal.h" +#include "up_arch.h" + +/***************************************************************************** + * Definitions + *****************************************************************************/ + +/* This file holds the NuttX start logic that runs when the LPC2148 + * is reset. This logic must be located at address 0x0000:0000 in + * flash but may be linked to run at different locations based on + * the selected mode: + * + * default: Executes from 0x0000:0000. In non-default modes, the + * MEMAP register is set override the settings of the CPU configuration + * pins. + * + * CONFIG_EXTMEM_MODE: Code executes from external memory starting at + * address 0x8000:0000. + * + * CONFIG_RAM_MODE: Code executes from on-chip RAM at address + * 0x4000:0000. + * + * Starupt Code must be linked to run at the correct address + * corresponding to the selected mode. + */ + +#if defined(CONFIG_EXTMEM_MODE) +# if CONFIG_CODE_BASE != LPC214X_EXTMEM_BASE +# error "CONFIG_CODE_BASE must be 0x80000000 in EXTMEM mode" +# endif +#elif defined(CONFIG_RAM_MODE) +# if CONFIG_CODE_BASE != LPC214X_ONCHIP_RAM_BASE +# error "CONFIG_CODE_BASE must be 0x40000000 in EXTMEM mode" +# endif +#else +# if CONFIG_CODE_BASE != LPC214X_FLASH_BASE +# error "CONFIG_CODE_BASE must be 0x00000000 in default mode" +# endif +#endif + +/* Phase Locked Loop (PLL) initialization values + * + * Bit 0:4 MSEL: PLL Multiplier "M" Value + * CCLK = M * Fosc + * Bit 5:6 PSEL: PLL Divider "P" Value + * Fcco = CCLK * 2 * P + * 156MHz <= Fcco <= 320MHz + */ + +/* PLL0 provides CCLK and must always be configured */ + +#ifndef CONFIG_PLLCFG_VALUE /* board.h values can be supeceded config file */ +# ifdef LPC214X_PLL_M +# define CONFIG_PLLCFG_MSEL (LPC214X_PLL_M-1) +# else +# warning "PLL_M not specified" +# define CONFIG_PLLCFG_MSEL (5-1) +# endif +# ifdef LPC214X_PLL_P +# if LPC214X_PLL_P == 1 +# define CONFIG_PLLCFG_PSEL LPC214X_PLL_CFG_PSEL1 +# elif LPC214X_PLL_P == 2 +# define CONFIG_PLLCFG_PSEL LPC214X_PLL_CFG_PSEL2 +# elif LPC214X_PLL_P == 4 +# define CONFIG_PLLCFG_PSEL LPC214X_PLL_CFG_PSEL4 +# elif LPC214X_PLL_P == 8 +# define CONFIG_PLLCFG_PSEL LPC214X_PLL_CFG_PSEL8 +# else +# error "Unrecognized value for PLL_P" +# endif +# else +# warning "PLL_P not specified" +# define CONFIG_PLLCFG_PSEL LPC214X_PLL_CFG_PSEL2 +# endif +# define CONFIG_PLLCFG_VALUE (CONFIG_PLLCFG_PSEL|CONFIG_PLLCFG_MSEL) +#endif + +/* If USB is enabled, PLL1 must be configured for 48MHz to provide USB clocking */ + +#ifdef CONFIG_USBDEV +# ifndef CONFIG_USBPLLCFG_VALUE /* board.h values can be supeceded config file */ +# ifdef LPC214X_USBPLL_M +# define LPC214X_USBPLLCFG_MSEL (LPC214X_USBPLL_M-1) +# else +# warning "PLL_M not specified" +# define LPC214X_USBPLLCFG_MSEL 0x00000004 +# endif +# ifdef LPC214X_USBPLL_P +# if LPC214X_USBPLL_P == 1 +# define LPC214X_USBPLLCFG_PSEL 0x00000000 +# elif LPC214X_USBPLL_P == 2 +# define LPC214X_USBPLLCFG_PSEL 0x00000020 +# elif LPC214X_USBPLL_P == 4 +# define LPC214X_USBPLLCFG_PSEL 0x00000040 +# elif LPC214X_USBPLL_P == 8 +# define LPC214X_USBPLLCFG_PSEL 0x00000060 +# else +# error "Unrecognized value for PLL_P" +# endif +# endif +# define CONFIG_USBPLLCFG_VALUE (LPC214X_USBPLLCFG_PSEL|LPC214X_USBPLLCFG_MSEL) +# endif +#endif + +/* Memory Accelerator Module (MAM) initialization values + * + * MAM Control Register + * Bit 0:1 Mode + * 0 = Disabled + * 1 = Partially Enabled + * 2 = Fully Enabled + * MAM Timing Register + * Bit 0:2 Fetch Cycles + * 0 = Reserved + * 1 = 1 + * 2 = 2 + * 3 = 3 + * 4 = 4 + * 5 = 5 + * 6 = 6 + * 7 = 7 + */ + +#ifndef CONFIG_MAMCR_VALUE /* Can be selected from config file */ +# define CONFIG_MAMCR_VALUE 0x00000002 +#endif + +#ifndef CONFIG_MAMTIM_VALUE /* Can be selected from config file */ +# define CONFIG_MAMTIM_VALUE 0x00000004 +#endif + +/* APBDIV initialization values + * + * Bits 0:1 APB Peripheral Bus Clock Rate + * 0 = APB Clock = CPU Clock / 4 + * 1 = APB Clock = CPU Clock + * 2 = APB Clock = CPU Clock / 2 + */ + +#ifndef CONFIG_APBDIV_VALUE /* Can be selected from config file */ +# ifdef LPC214X_APB_DIV +# if LPC214X_APB_DIV == 1 +# define CONFIG_APBDIV_VALUE LPC214X_APBDIV_DIV1 +# elif LPC214X_APB_DIV == 2 +# define CONFIG_APBDIV_VALUE LPC214X_APBDIV_DIV2 +# elif LPC214X_APB_DIV == 4 +# define CONFIG_APBDIV_VALUE LPC214X_APBDIV_DIV4 +# else +# error "Unrecognized value for APBDIV" +# endif +# else +# define CONFIG_APBDIV_VALUE LPC214X_APBDIV_DIV1 +# endif +#endif + +/* External Memory Controller (EMC) initialization values + * + * Bank Configuration n (BCFG0..3) + * Bit 0:3 IDCY: Idle Cycles (0-15) + * Bit 5:9 WST1: Wait States 1 (0-31) + * Bit 11:15 WST2: Wait States 2 (0-31) + * Bit 10 RBLE: Read Byte Lane Enable + * Bit 26 WP: Write Protect + * Bit 27 BM: Burst ROM + * Bit 28:29 MW: Memory Width (0=8-bit 1=16-bit 2=32-bit 3=Reserved) + */ + +#ifndef CONFIG_BCFG0_VALUE /* Can be selected from config file */ +# define CONFIG_BCFG0_VALUE 0x0000fbef +#endif + +#ifndef CONFIG_BCFG1_VALUE /* Can be selected from config file */ +# define CONFIG_BCFG1_VALUE 0x0000fbef +#endif + +#ifndef CONFIG_BCFG2_VALUE /* Can be selected from config file */ +# define CONFIG_BCFG2_VALUE 0x0000fbef +#endif + +#ifndef CONFIG_BCFG3_VALUE /* Can be selected from config file */ +# define CONFIG_BCFG3_VALUE 0x0000fbef +#endif + +/* The following are used to configure the ADC/DAC */ +#ifndef CONFIG_AD0CR_VALUE +# define CONFIG_AD0CR_VALUE 0x00200402; /* Setup A/D: 10-bit AIN0 @ 3MHz */ +#endif + +/* GIO Pin Selection Register settings + * + * PINSEL0 configures GPIO 0.0 through 0.15 + */ + +#ifndef CONFIG_PINSEL0_VALUE /* Can be selected from config file */ +# define CONFIG_PINSEL0_VALUE 0x00000000 /* Reset value */ +#endif + +/* PINSEL1 configures GPIO 0.16 through 0.30 and GPO */ + +#ifndef CONFIG_PINSEL1_VALUE /* Can be selected from the config file */ +# ifdef CONFIG_ADC_SETUP +# define CONFIG_PINSEL1_ADC 0x01000000 /* Enable DAC */ +# else +# define CONFIG_PINSEL1_ADC 0x00000000 /* Reset value */ +# endif +# ifdef CONFIG_USBDEV +# define CONFIG_PINSEL1_USBDEV 0x80004000 /* Enable Vbus and Connect LED */ +# else +# define CONFIG_PINSEL1_USBDEV 0x00000000 /* Reset value */ +# endif +# define CONFIG_PINSEL1_VALUE (CONFIG_PINSEL1_ADC|CONFIG_PINSEL1_USBDEV) +#endif + +/* External Memory Pins definitions + * Bit 0:1 Reserved + * Bit 2 GPIO/DEBUG + * Bit 3 GPIO/TRACE + * Bit 31:4 Reserved + * CS0..3, OE, WE, BLS0..3, D0..31, A2..23, JTAG Pins + */ + +#ifndef CONFIG_PINSEL2_VALUE /* Can be selected from config file */ +# define CONFIG_PINSEL2_VALUE 0x0e6149e4 +#endif + +/***************************************************************************** + * Macros + *****************************************************************************/ + +/* Print a character on the UART to show boot status. This macro will + * modify r0, r1, r2 and r14 + */ + + .macro showprogress, code +#ifdef CONFIG_DEBUG + mov r0, #\code + bl up_lowputc +#endif + .endm + +/* Configured the PINSEL2 register if EXTMEM mode is selected */ + + .macro configpinsel2, base, val +#ifdef CONFIG_EXTMEM_MODE + ldr \base, =LPC214X_PINSEL2 + ldr \val, =CONFIG_PINSEL2_VALUE + str \val, [\base] +#endif + .endm + +/* Configure the external memory controller */ + + .macro configemc, base, val +#ifdef CONFIG_EMC_SETUP + ldr \base, =LPC214X_EMC_BASE + +#ifdef CONFIG_BCFG0_SETUP + ldr \val, =CONFIG_BCFG0_VALUE + str \val, [\base, #LPC214X_BCFG0_OFFSET] +#endif + +#ifdef CONFIG_BCFG1_SETUP + ldr \val, =CONFIG_BCFG1_VALUE + str \val, [\base, #LPC214X_BCFG1_OFFSET] +#endif + +#ifdef CONFIG_BCFG2_SETUP + ldr \val, =CONFIG_BCFG2_VALUE + str \val, [\base, #LPC214X_BCFG2_OFFSET] +#endif + +#ifdef CONFIG_BCFG3_SETUP + ldr \val, =CONFIG_BCFG3_VALUE + str \val, [\base, #LPC214X_BCFG3_OFFSET] +#endif +#endif + .endm + +/* Configure APBDIV */ + + .macro configapbdiv, base, val +#ifdef CONFIG_APBDIV_SETUP + ldr \base, =LPC214X_APBDIV + ldr \val, =CONFIG_APBDIV_VALUE + strb \val, [\base] +#endif + .endm + +/* Configure the PLL */ + + .macro configpll, base, val1, val2, val3 +#ifdef CONFIG_PLL_SETUP + ldr \base, =LPC214X_PLL0_BASE + mov \val1, #LPC214X_PLL_FEED1 + mov \val2, #LPC214X_PLL_FEED2 + + /* Configure and Enable PLL */ + + mov \val3, #CONFIG_PLLCFG_VALUE + str \val3, [\base, #LPC214X_PLL_CFG_OFFSET] + mov \val3, #LPC214X_PLL_CON_PLLE + str \val3, [\base, #LPC214X_PLL_CON_OFFSET] + str \val1, [\base, #LPC214X_PLL_FEED_OFFSET] + str \val2, [\base, #LPC214X_PLL_FEED_OFFSET] + + /* Wait until PLL Locked */ +1: + ldr \val3, [\base, #LPC214X_PLL_STAT_OFFSET] + ands \val3, \val3, #LPC214X_PLL_STAT_PLOCK + beq 1b + + /* Switch to PLL Clock */ + + mov \val3, #(LPC214X_PLL_CON_PLLE | LPC214X_PLL_CON_PLLC) + str \val3, [\base, #LPC214X_PLL_CON_OFFSET] + str \val1, [\base, #LPC214X_PLL_FEED_OFFSET] + str \val2, [\base, #LPC214X_PLL_FEED_OFFSET] +#endif + .endm + + .macro configusbpll, base, val1, val2, val3 +#ifdef CONFIG_USBDEV + ldr \base, =LPC214X_PLL1_BASE + mov \val1, #LPC214X_PLL_FEED1 + mov \val2, #LPC214X_PLL_FEED2 + + /* Configure and Enable PLL */ + + mov \val3, #CONFIG_USBPLLCFG_VALUE + str \val3, [\base, #LPC214X_PLL_CFG_OFFSET] + mov \val3, #LPC214X_PLL_CON_PLLE + str \val3, [\base, #LPC214X_PLL_CON_OFFSET] + str \val1, [\base, #LPC214X_PLL_FEED_OFFSET] + str \val2, [\base, #LPC214X_PLL_FEED_OFFSET] + + /* Wait until PLL Locked */ +1: + ldr \val3, [\base, #LPC214X_PLL_STAT_OFFSET] + ands \val3, \val3, #LPC214X_PLL_STAT_PLOCK + beq 1b + + /* Switch to PLL Clock */ + + mov \val3, #(LPC214X_PLL_CON_PLLE | LPC214X_PLL_CON_PLLC) + str \val3, [\base, #LPC214X_PLL_CON_OFFSET] + str \val1, [\base, #LPC214X_PLL_FEED_OFFSET] + str \val2, [\base, #LPC214X_PLL_FEED_OFFSET] +#endif + .endm + + +/* Configure the Memory Accelerator Module (MAM) */ + + .macro configmam, base, val +#ifdef CONFIG_MAM_SETUP + ldr \base, =LPC214X_MAM_BASE + mov \val, #CONFIG_MAMTIM_VALUE + str \val, [\base, #LPC214x_MAM_TIM_OFFSET] + mov \val, #CONFIG_MAMCR_VALUE + str \val, [\base, #LPC214X_MAM_CR_OFFSET] +#endif + .endm + +/* Setup MEMMAP for the selected mode of operation */ + + .macro configmemmap, base, val + ldr \base, =LPC214X_MEMMAP +#if defined(CONFIG_EXTMEM_MODE) + mov \val, #3 +#elif defined(CONFIG_RAM_MODE) + mov \val, #2 +#else /* Setting the default should not be necessary */ + mov \val, #1 +#endif + str \val, [\base] + .endm + + .macro configdac, base, tmp +#ifdef CONFIG_ADC_SETUP + ldr \base, =LPC214X_AD0_BASE + ldr \tmp, =CONFIG_AD0CR_VALUE + str \tmp, [\base, #LPC214X_AD_ADCR_OFFSET] + + ldr \base,=LPC214X_PINSEL1 + ldr \tmp, =CONFIG_PINSEL1_VALUE + str \tmp, [\base] +#endif + .endm + + .macro configfastport, base, tmp +#ifdef CONFIG_LPC214x_FIO + ldr \base, =LPC214X_SCS + mov \tmp, #0x03 + str \tmp,[\base] +#endif + .endm + +/***************************************************************************** + * Text + *****************************************************************************/ + + .text + +/***************************************************************************** + * Name: _vector_table + * + * Description: + * Interrrupt vector table. This must be located at the beginning + * of the memory space (at CONFIG_CODE_BASE). The first entry in + * the vector table is the reset vector and this is the code that + * will execute whn the processor is reset. + * + *****************************************************************************/ + + .globl _vector_table + .type _vector_table, %function +_vector_table: + ldr pc, .Lresethandler /* 0x00: Reset */ + ldr pc, .Lundefinedhandler /* 0x04: Undefined instruction */ + ldr pc, .Lswihandler /* 0x08: Software interrupt */ + ldr pc, .Lprefetchaborthandler /* 0x0c: Prefetch abort */ + ldr pc, .Ldataaborthandler /* 0x10: Data abort */ + .long 0 /* 0x14: Vector checksum */ + ldr pc, .Lirqhandler /* 0x18: IRQ */ + ldr pc, .Lfiqhandler /* 0x1c: FIQ */ + + .globl __start + .globl up_vectorundefinsn + .globl up_vectorswi + .globl up_vectorprefetch + .globl up_vectordata + .globl up_vectorirq + .globl up_vectorfiq + +.Lresethandler: + .long __start +.Lundefinedhandler: + .long up_vectorundefinsn +.Lswihandler: + .long up_vectorswi +.Lprefetchaborthandler: + .long up_vectorprefetch +.Ldataaborthandler: + .long up_vectordata +.Lirqhandler: + .long up_vectorirq +.Lfiqhandler: + .long up_vectorfiq + .size _vector_table, . - _vector_table + +/***************************************************************************** + * Name: __start + * + * Description: + * Reset entry point. This is the first function to execute when + * the processor is reset. It initializes hardware and then gives + * control to NuttX. + * + *****************************************************************************/ + + .global __start + .type __start, #function + +__start: + /* Setup the initial processor mode */ + + mov r0, #(SVC_MODE | PSR_I_BIT | PSR_F_BIT ) + msr cpsr, r0 + + /* Set up external memory mode (if so selected) */ + + configpinsel2 r0, r1 + + /* Setup the External Memory Controllor (EMC) as configured */ + + configemc r0, r1 + + /* Configure APBDIV */ + + configapbdiv r0, r1 + + /* Configure the PLL(s) */ + + configpll r0, r1, r2, r3 + configusbpll r0, r1, r2, r3 + + /* Configure the Memory Accelerator Module (MAM) */ + + configmam r0, r1 + + /* Setup MEMMAP for the selected mode of operation */ + + configmemmap r0, r1 + + /* Configure the DAC and ADC */ + + configdac r0, r1 + + /* Configure Fast GPIO Port */ + + configfastport r0, r1 + + /* Configure the uart so that we can get debug output as soon + * as possible. Modifies r0, r1, r2, and r14. + */ + + bl up_lowsetup + showprogress 'A' + + /* Setup system stack (and get the BSS range) */ + + adr r0, LC0 + ldmia r0, {r4, r5, sp} + + /* Clear system BSS section */ + + mov r0, #0 +1: cmp r4, r5 + strcc r0, [r4], #4 + bcc 1b + + showprogress 'B' + + /* Copy system .data sections to new home in RAM. */ + + adr r3, LC2 + ldmia r3, {r0, r1, r2} + +1: ldmia r0!, {r3 - r10} + stmia r1!, {r3 - r10} + cmp r1, r2 + blt 1b + + /* Perform early serial initialization */ + + mov fp, #0 +#ifdef USE_EARLYSERIALINIT + bl up_earlyserialinit +#endif + + showprogress 'C' + showprogress '\n' + + /* Initialize onboard LEDs */ + +#ifdef CONFIG_ARCH_LEDS + bl up_ledinit +#endif + + /* Then jump to OS entry */ + + b os_start + + /* Variables: + * _sbss is the start of the BSS region (see ld.script) + * _ebss is the end of the BSS regsion (see ld.script) + * The idle task stack starts at the end of BSS and is + * of size CONFIG_IDLETHREAD_STACKSIZE. The heap continues + * from there until the end of memory. See g_heapbase + * below. + */ + +LC0: .long _sbss + .long _ebss + .long _ebss+CONFIG_IDLETHREAD_STACKSIZE-4 + +LC2: .long _eronly /* Where .data defaults are stored in FLASH */ + .long _sdata /* Where .data needs to reside in SDRAM */ + .long _edata + .size __start, .-__start + + /* This global variable is unsigned long g_heapbase and is + * exported from here only because of its coupling to LCO + * above. + */ + + .data + .align 4 + .globl g_heapbase + .type g_heapbase, object +g_heapbase: + .long _ebss+CONFIG_IDLETHREAD_STACKSIZE + .size g_heapbase, .-g_heapbase + + .end + diff --git a/nuttx/arch/arm/src/lpc214x/lpc214x_i2c.h b/nuttx/arch/arm/src/lpc214x/lpc214x_i2c.h new file mode 100644 index 000000000..a66399968 --- /dev/null +++ b/nuttx/arch/arm/src/lpc214x/lpc214x_i2c.h @@ -0,0 +1,141 @@ +/************************************************************************************ + * arch/arm/src/lpc214x/lpc214x_i2c.h + * + * Copyright (C) 2009 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <gnutt@nuttx.org> + * + * 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. + * + ************************************************************************************/ + +#ifndef _ARCH_ARM_SRC_LPC214X_I2C_H +#define _ARCH_ARM_SRC_LPC214X_I2C_H + +/************************************************************************************ + * Included Files + ************************************************************************************/ + +#include "chip.h" + +/************************************************************************************ + * Definitions + ************************************************************************************/ + +/* Register address Offsets *********************************************************/ + +/* Defined in chip.h */ + +/* Register Address Definitions *****************************************************/ + +#define LPC214X_I2C0_CONSET (LPC214X_I2C0_BASE + LPC214X_I2C_ONSET_OFFSET) +#define LPC214X_I2C0_STAT (LPC214X_I2C0_BASE + LPC214X_I2C_STAT_OFFSET) +#define LPC214X_I2C0_DAT (LPC214X_I2C0_BASE + LPC214X_I2C_DAT_OFFSET) +#define LPC214X_I2C0_ADR (LPC214X_I2C0_BASE + LPC214X_I2C_ADR_OFFSET) +#define LPC214X_I2C0_SCLH (LPC214X_I2C0_BASE + LPC214X_I2C_SCLH_OFFSET) +#define LPC214X_I2C0_SCLL (LPC214X_I2C0_BASE + LPC214X_I2C_SCLL_OFFSET) +#define LPC214X_I2C0_CONCLR (LPC214X_I2C0_BASE + LPC214X_I2C_ONCLR_OFFSET) + +#define LPC214X_I2C1_CONSET (LPC214X_I2C1_BASE + LPC214X_I2C_ONSET_OFFSET) +#define LPC214X_I2C1_STAT (LPC214X_I2C1_BASE + LPC214X_I2C_STAT_OFFSET) +#define LPC214X_I2C1_DAT (LPC214X_I2C1_BASE + LPC214X_I2C_DAT_OFFSET) +#define LPC214X_I2C1_ADR (LPC214X_I2C1_BASE + LPC214X_I2C_ADR_OFFSET) +#define LPC214X_I2C1_SCLH (LPC214X_I2C1_BASE + LPC214X_I2C_SCLH_OFFSET) +#define LPC214X_I2C1_SCLL (LPC214X_I2C1_BASE + LPC214X_I2C_SCLL_OFFSET) +#define LPC214X_I2C1_CONCLR (LPC214X_I2C1_BASE + LPC214X_I2C_ONCLR_OFFSET) + +/* I2C register bit definitions *****************************************************/ + +/* Control Set Register (CONSET) */ + +#define I2C_CONSET_AA (1 << 2) /* Bit 2: Assert acknowledge flag */ +#define I2C_CONSET_SI (1 << 3) /* Bit 3: I2C interrrupt flag */ +#define I2C_CONSET_STO (1 << 4) /* Bit 4: STOP flag */ +#define I2C_CONSET_STA (1 << 5) /* Bit 5: START flag */ +#define I2C_CONSET_I2EN (1 << 6) /* Bit 6: I2C interface enable */ + +/* Control Clear Register (CONCLR) */ + +#define I2C_CONCLR_AAC (1 << 2) /* Bit 2: Assert acknowledge Clear bit */ +#define I2C_CONCLR_SIC (1 << 3) /* Bit 3: I2C interrupt Clear bit */ +#define I2C_CONCLR_STAC (1 << 5) /* Bit 5: START flag Clear bit */ +#define I2C_CONCLR_I2ENC (1 << 6) /* Bit 6: I2C interface Disable bit */ + +/* Status Register (STAT) */ + +#define I2C_STAT_SHIFT (1 << 3) /* Bits 3-7: Status bits */ +#define I2C_STAT_MASK (0xff << I2C_STAT_SHIFT) + +/* Master transmit mode */ + +# define I2C_STAT_MXSTART (0 << I2C_STAT_SHIFT) /* Start transmitted */ +# define I2C_STAT_MXRSTART (2 << I2C_STAT_SHIFT) /* Repeated start transmitted */ +# define I2C_STAT_MXSLAWACK (3 << I2C_STAT_SHIFT) /* SLA+W tranmitted + ACK received */ +# define I2C_STAT_MXSLAWNAK (4 << I2C_STAT_SHIFT) /* SLA+W tranmitted + NAK received */ +# define I2C_STAT_MXDATAACK (5 << I2C_STAT_SHIFT) /* Data tranmitted + ACK received */ +# define I2C_STAT_MXDATANAK (6 << I2C_STAT_SHIFT) /* Data tranmitted + NAK received */ +# define I2C_STAT_MXARBLOST (7 << I2C_STAT_SHIFT) /* Abritration lost in SLA+W or data */ + +/* Master receive mode */ + +# define I2C_STAT_MRSTART (0 << I2C_STAT_SHIFT) /* Start transmitted */ +# define I2C_STAT_MRRSTART (2 << I2C_STAT_SHIFT) /* Repeated start transmitted */ +# define I2C_STAT_MRARBLOST (7 << I2C_STAT_SHIFT) /* Abritration lost in NAK bit */ +# define I2C_STAT_MRSLARACK (8 << I2C_STAT_SHIFT) /* SLA+R tranmitted + ACK received */ +# define I2C_STAT_MRSLARNAK (9 << I2C_STAT_SHIFT) /* SLA+R tranmitted + NAK received */ +# define I2C_STAT_MRDATAACK (10 << I2C_STAT_SHIFT) /* Data received + send ACK */ +# define I2C_STAT_MRDATANAK (11 << I2C_STAT_SHIFT) /* Data received + send NAK */ + +/* Slave receive mode -- to be provided */ + +/* Slave receive mode -- to be provided */ + +/* Data Register (DAT) -- 8-bits of data */ + +/* Slave Address Register (ADR) */ + +#define I2C_ADR_GCA (1 << 0) /* Bit 0: General call enable */ +#define I2C_ADR_SHIFT 1 /* Bits 7-1: address */ +#define I2C_ADR_MASK (0x7f << I2C_ADR_SHIFT) + +/* SCL Duty Cycle Register (high half word - SCLH) - 16-bits of data */ + +/* SCL Duty Cycle Register (low half word - SCLL) - 16-bits of data */ + +/************************************************************************************ + * Public Types + ************************************************************************************/ + +/************************************************************************************ + * Inline Functions + ************************************************************************************/ + +/************************************************************************************ + * Public Function Prototypes + ************************************************************************************/ + +#endif /* _ARCH_ARM_SRC_LPC214X_I2C_H */ diff --git a/nuttx/arch/arm/src/lpc214x/lpc214x_irq.c b/nuttx/arch/arm/src/lpc214x/lpc214x_irq.c new file mode 100644 index 000000000..cb0f6e12f --- /dev/null +++ b/nuttx/arch/arm/src/lpc214x/lpc214x_irq.c @@ -0,0 +1,224 @@ +/**************************************************************************** + * arch/arm/src/lpc214x/lpc214x_irq.c + * + * Copyright (C) 2007-2009, 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <gnutt@nuttx.org> + * + * 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 <nuttx/config.h> + +#include <stdint.h> +#include <debug.h> +#include <nuttx/irq.h> + +#include "arm.h" +#include "chip.h" +#include "up_arch.h" +#include "os_internal.h" +#include "up_internal.h" + +#include "lpc214x_vic.h" + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +volatile uint32_t *current_regs; + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_irqinitialize + ****************************************************************************/ + +void up_irqinitialize(void) +{ + int reg; + + /* Disable all interrupts. We do this by writing zero to the IntEnable + * register. This is equivalent to writing all ones to the IntClearEnable + * register. + */ + + vic_putreg(0, LPC214X_VIC_INTENABLE_OFFSET); + + /* Select all IRQs, no FIQs */ + + vic_putreg(0, LPC214X_VIC_INTSELECT_OFFSET); + + /* Set the default vector */ + + vic_putreg((uint32_t)up_decodeirq, LPC214X_VIC_DEFVECTADDR_OFFSET); + + /* Disable all vectored interrupts */ + + for (reg = LPC214X_VIC_VECTCNTL0_OFFSET; + reg <= LPC214X_VIC_VECTCNTL15_OFFSET; + reg += 4) + { + vic_putreg(0, reg); + } + + /* currents_regs is non-NULL only while processing an interrupt */ + + current_regs = NULL; + + /* And finally, enable interrupts */ + +#ifndef CONFIG_SUPPRESS_INTERRUPTS + irqrestore(SVC_MODE | PSR_F_BIT); +#endif +} + +/**************************************************************************** + * Name: up_disable_irq + * + * Description: + * Disable the IRQ specified by 'irq' + * + ****************************************************************************/ + +void up_disable_irq(int irq) +{ + /* Verify that the IRQ number is within range */ + + if (irq < NR_IRQS) + { + /* Disable the irq by setting the corresponding bit in the VIC + * Interrupt Enable Clear register. + */ + + vic_putreg((1 << irq), LPC214X_VIC_INTENCLEAR_OFFSET); + } +} + +/**************************************************************************** + * Name: up_enable_irq + * + * Description: + * Enable the IRQ specified by 'irq' + * + ****************************************************************************/ + +void up_enable_irq(int irq) +{ + /* Verify that the IRQ number is within range */ + + if (irq < NR_IRQS) + { + /* Disable all interrupts */ + + irqstate_t flags = irqsave(); + + /* Enable the irq by setting the corresponding bit in the VIC + * Interrupt Enable register. + */ + + uint32_t val = vic_getreg(LPC214X_VIC_INTENABLE_OFFSET); + vic_putreg(val | (1 << irq), LPC214X_VIC_INTENABLE_OFFSET); + irqrestore(flags); + } +} + +/**************************************************************************** + * Name: up_attach_vector + * + * Description: + * Attach a user-supplied handler to a vectored interrupt + * + ****************************************************************************/ + +#ifndef CONFIG_VECTORED_INTERRUPTS +void up_attach_vector(int irq, int vector, vic_vector_t handler) +{ + /* Verify that the IRQ number and vector number are within range */ + + if (irq < NR_IRQS && vector < 16 && handler) + { + int offset = vector << 2; + + /* Disable all interrupts */ + + irqstate_t flags = irqsave(); + + /* Save the vector address */ + + vic_putreg((uint32_t)handler, LPC214X_VIC_VECTADDR0_OFFSET + offset); + + /* Enable the vectored interrupt */ + + vic_putreg(((irq << LPC214X_VECTCNTL_IRQSHIFT) | LPC214X_VECTCNTL_ENABLE), + LPC214X_VIC_VECTCNTL0_OFFSET + offset); + irqrestore(flags); + } +} +#endif + +/**************************************************************************** + * Name: up_detach_vector + * + * Description: + * Detach a user-supplied handler from a vectored interrupt + * + ****************************************************************************/ + +#ifndef CONFIG_VECTORED_INTERRUPTS +void up_detach_vector(int vector) +{ + /* Verify that the vector number is within range */ + + if (vector < 16) + { + /* Disable the vectored interrupt */ + + int offset = vector << 2; + vic_putreg(0, LPC214X_VIC_VECTCNTL0_OFFSET + offset); + } +} +#endif diff --git a/nuttx/arch/arm/src/lpc214x/lpc214x_lowputc.S b/nuttx/arch/arm/src/lpc214x/lpc214x_lowputc.S new file mode 100644 index 000000000..b53e7aa78 --- /dev/null +++ b/nuttx/arch/arm/src/lpc214x/lpc214x_lowputc.S @@ -0,0 +1,209 @@ +/************************************************************************** + * arch/arm/src/lpc214x/lpc214X_lowputc.S + * + * Copyright (C) 2007, 2008 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <gnutt@nuttx.org> + * + * 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 <nuttx/config.h> + +#include "chip.h" +#include "up_arch.h" +#include "up_internal.h" + +#include "lpc214x_pinsel.h" +#include "lpc214x_uart.h" + +/************************************************************************** + * Private Definitions + **************************************************************************/ + +#if defined(CONFIG_UART0_SERIAL_CONSOLE) +# define LPC214X_UART_BASE LPC214X_UART0_BASE +# define LPC214X_UART_PINSEL LPC214X_UART0_PINSEL +# define LPC214X_UART_PINMASK LPC214X_UART0_PINMASK +# define LPC214X_UART_BAUD CONFIG_UART0_BAUD +# define LPC214X_UART_BITS CONFIG_UART0_BITS +# define LPC214X_UART_PARITY CONFIG_UART0_PARITY +# define LPC214X_UART_2STOP CONFIG_UART0_2STOP +#elif defined(CONFIG_UART1_SERIAL_CONSOLE) +# define LPC214X_UART_BASE LPC214X_UART1_BASE +# define LPC214X_UART_PINSEL LPC214X_UART1_PINSEL +# define LPC214X_UART_PINMASK LPC214X_UART1_PINMASK +# define LPC214X_UART_BAUD CONFIG_UART1_BAUD +# define LPC214X_UART_BITS CONFIG_UART1_BITS +# define LPC214X_UART_PARITY CONFIG_UART1_PARITY +# define LPC214X_UART_2STOP CONFIG_UART1_2STOP +#else +# error "No CONFIG_UARTn_SERIAL_CONSOLE Setting" +#endif + +#if LPC214X_UART_BITS == 5 +# define LPC214X_LCR_CHAR LPC214X_LCR_CHAR_5 +#elif LPC214X_UART_BITS == 6 +# define LPC214X_LCR_CHAR LPC214X_LCR_CHAR_6 +#elif LPC214X_UART_BITS == 7 +# define LPC214X_LCR_CHAR LPC214X_LCR_CHAR_7 +#elif LPC214X_UART_BITS == 8 +# define LPC214X_LCR_CHAR LPC214X_LCR_CHAR_8 +#else +# error "No CONFIG_UARTn_BITS Setting" +#endif + +#if LPC214X_UART_PARITY == 0 +# define LPC214X_LCR_PAR LPC214X_LCR_PAR_NONE +#elif LPC214X_UART_PARITY == 1 +# define LPC214X_LCR_PAR LPC214X_LCR_PAR_ODD +#elif LPC214X_UART_PARITY == 2 +# define LPC214X_LCR_PAR LPC214X_LCR_PAR_EVEN +#elif LPC214X_UART_PARITY == 3 +# define LPC214X_LCR_PAR LPC214X_LCR_PAR_MARK +#elif LPC214X_UART_PARITY == 4 +# define LPC214X_LCR_PAR LPC214X_LCR_PAR_SPACE +#else +# error "No CONFIG_UARTn_PARITY Setting" +#endif + +#if LPC214X_UART_2STOP != 0 +# define LPC214X_LCR_STOP LPC214X_LCR_STOP_2 +#else +# define LPC214X_LCR_STOP LPC214X_LCR_STOP_1 +#endif + +#define LPC214X_LCR_VALUE (LPC214X_LCR_CHAR | LPC214X_LCR_PAR | LPC214X_LCR_STOP) +#define LPC214X_FCR_VALUE (LPC214X_FCR_FIFO_TRIG8 | LPC214X_FCR_TX_FIFO_RESET |\ + LPC214X_FCR_RX_FIFO_RESET | LPC214X_FCR_FIFO_ENABLE) + +/************************************************************************** + * Private Types + **************************************************************************/ + +/************************************************************************** + * Private Function Prototypes + **************************************************************************/ + +/************************************************************************** + * Global Variables + **************************************************************************/ + +/************************************************************************** + * Private Variables + **************************************************************************/ + +/************************************************************************** + * Private Functions + **************************************************************************/ + +/************************************************************************** + * Public Functions + **************************************************************************/ + +/************************************************************************** + * Name: up_lowputc + **************************************************************************/ + +/* This assembly language version has the advantage that it can does not + * require a C stack and uses only r0-r1. Hence it can be used during + * early boot phases. + */ + + .text + .global up_lowputc + .type up_lowputc, function +up_lowputc: + /* On entry, r0 holds the character to be printed */ + + ldr r1, =LPC214X_UART_BASE + strb r0, [r1, #LPC214X_UART_THR_OFFSET] + + /* Wait for the byte to be transferred */ + +1: ldr r0, [r1, #LPC214X_UART_LSR_OFFSET] + ands r0, #LPC214X_LSR_TEMT /* Transmitter empty */ + beq 1b + + /* And return */ + + mov pc, lr + .size up_lowputc, . - up_lowputc + +/* This performs basic initialization of the UART. This can be called very + * early in initialization because it does not depend on having a stack. It + * modifies r0-r2 and r14. + */ + + .text + .globl up_lowsetup + .type up_lowsetup, function +up_lowsetup: + /* Configure PINSEL0 */ + + ldr r0, =LPC214X_PINSEL0 + ldr r1, [r0] + ldr r2, =~LPC214X_UART_PINMASK + and r1, r2 + ldr r2, =LPC214X_UART_PINSEL + orr r1, r2 + str r1, [r0] + + /* Configure parity, data bits, stop bits and set DLAB=1 */ + + ldr r0, =LPC214X_UART_BASE + mov r1, #(LPC214X_LCR_VALUE | LPC214X_LCR_DLAB_ENABLE) + strb r1, [r0, #LPC214X_UART_LCR_OFFSET] + + /* Set the BAUD divisor */ + + mov r1, #(UART_BAUD(LPC214X_UART_BAUD) >> 8) + strb r1, [r0, #LPC214X_UART_DLM_OFFSET] + + mov r1, #(UART_BAUD(LPC214X_UART_BAUD) & 0xff) + strb r1, [r0, #LPC214X_UART_DLL_OFFSET] + + /* Clear DLAB */ + + mov r1, #LPC214X_LCR_VALUE + strb r1, [r0, #LPC214X_UART_LCR_OFFSET] + + /* Configure the FIFOs */ + + mov r1, #LPC214X_FCR_VALUE + strb r1, [r0, #LPC214X_UART_FCR_OFFSET] + + /* And return */ + + mov pc, lr + .size up_lowsetup, . - up_lowsetup + .end diff --git a/nuttx/arch/arm/src/lpc214x/lpc214x_pinsel.h b/nuttx/arch/arm/src/lpc214x/lpc214x_pinsel.h new file mode 100644 index 000000000..b34eb86b6 --- /dev/null +++ b/nuttx/arch/arm/src/lpc214x/lpc214x_pinsel.h @@ -0,0 +1,259 @@ +/************************************************************************************ + * arch/arm/src/lpc214x/lpc214x_pinsl.h + * + * Copyright (C) 2008 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <gnutt@nuttx.org> + * + * 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. + * + ************************************************************************************/ + +#ifndef _ARCH_ARM_SRC_LPC214X_PINSEL_H +#define _ARCH_ARM_SRC_LPC214X_PINSEL_H + +/************************************************************************************ + * Included Files + ************************************************************************************/ + +/************************************************************************************ + * Definitions + ************************************************************************************/ + +/* Register address definitions *****************************************************/ + +#define LPC214X_PINSEL0 (LPC214X_PINSEL_BASE + LPC214X_PINSEL0_OFFSET) +#define LPC214X_PINSEL1 (LPC214X_PINSEL_BASE + LPC214X_PINSEL1_OFFSET) +#define LPC214X_PINSEL2 (LPC214X_PINSEL_BASE + LPC214X_PINSEL2_OFFSET) + +/* Register bit definitions *********************************************************/ + +#define LPC214X_PINSEL0_P00_GPIO (0x00000000) +#define LPC214X_PINSEL0_P00_TXD0 (0x00000001) +#define LPC214X_PINSEL0_P00_PWM1 (0x00000002) +#define LPC214X_PINSEL0_P00_RSVD3 (0x00000003) +#define LPC214X_PINSEL0_P00_MASK (0x00000003) + +#define LPC214X_PINSEL0_P01_GPIO (0x00000000) +#define LPC214X_PINSEL0_P01_RXD0 (0x00000004) +#define LPC214X_PINSEL0_P01_PWM3 (0x00000008) +#define LPC214X_PINSEL0_P01_EINT0 (0x0000000c) +#define LPC214X_PINSEL0_P01_MASK (0x0000000c) + +#define LPC214X_PINSEL0_P02_GPIO (0x00000000) +#define LPC214X_PINSEL0_P02_SCL0 (0x00000010) +#define LPC214X_PINSEL0_P02_CAP00 (0x00000020) +#define LPC214X_PINSEL0_P02_RSVD3 (0x00000030) +#define LPC214X_PINSEL0_P02_MASK (0x00000030) + +#define LPC214X_PINSEL0_P03_GPIO (0x00000000) +#define LPC214X_PINSEL0_P03_SDA0 (0x00000040) +#define LPC214X_PINSEL0_P03_MAT00 (0x00000080) +#define LPC214X_PINSEL0_P03_EINT1 (0x000000c0) +#define LPC214X_PINSEL0_P03_MASK (0x000000c0) + +#define LPC214X_PINSEL0_P04_GPIO (0x00000000) +#define LPC214X_PINSEL0_P04_SCK0 (0x00000100) +#define LPC214X_PINSEL0_P04_CAP01 (0x00000200) +#define LPC214X_PINSEL0_P04_RSVD3 (0x00000300) +#define LPC214X_PINSEL0_P04_MASK (0x00000300) + +#define LPC214X_PINSEL0_P05_GPIO (0x00000000) +#define LPC214X_PINSEL0_P05_MISO0 (0x00000400) +#define LPC214X_PINSEL0_P05_MAT01 (0x00000800) +#define LPC214X_PINSEL0_P05_AD06 (0x00000c00) +#define LPC214X_PINSEL0_P05_MASK (0x00000c00) + +#define LPC214X_PINSEL0_P06_GPIO (0x00000000) +#define LPC214X_PINSEL0_P06_MOSI0 (0x00001000) +#define LPC214X_PINSEL0_P06_CAP02 (0x00002000) +#define LPC214X_PINSEL0_P06_AD10 (0x00003000) +#define LPC214X_PINSEL0_P06_MASK (0x00003000) + +#define LPC214X_PINSEL0_P07_GPIO (0x00000000) +#define LPC214X_PINSEL0_P07_SSEL0 (0x00004000) +#define LPC214X_PINSEL0_P07_PWM2 (0x00008000) +#define LPC214X_PINSEL0_P07_EINT2 (0x0000c000) +#define LPC214X_PINSEL0_P07_MASK (0x0000c000) + +#define LPC214X_PINSEL0_P08_GPIO (0x00000000) +#define LPC214X_PINSEL0_P08_TXD1 (0x00010000) +#define LPC214X_PINSEL0_P08_PWM4 (0x00020000) +#define LPC214X_PINSEL0_P08_AD11 (0x00030000) +#define LPC214X_PINSEL0_P08_MASK (0x00030000) + +#define LPC214X_PINSEL0_P09_GPIO (0x00000000) +#define LPC214X_PINSEL0_P09_RXD1 (0x00040000) +#define LPC214X_PINSEL0_P09_PWM6 (0x00080000) +#define LPC214X_PINSEL0_P09_EINT3 (0x000c0000) +#define LPC214X_PINSEL0_P09_MASK (0x000c0000) + +#define LPC214X_PINSEL0_P010_GPIO (0x00000000) +#define LPC214X_PINSEL0_P010_RTS1 (0x00100000) +#define LPC214X_PINSEL0_P010_CAP10 (0x00200000) +#define LPC214X_PINSEL0_P010_AD12 (0x00300000) +#define LPC214X_PINSEL0_P010_MASK (0x00300000) + +#define LPC214X_PINSEL0_P011_GPIO (0x00000000) +#define LPC214X_PINSEL0_P011_CTS1 (0x00400000) +#define LPC214X_PINSEL0_P011_CAP11 (0x00800000) +#define LPC214X_PINSEL0_P011_SCL1 (0x00c00000) +#define LPC214X_PINSEL0_P011_MASK (0x00c00000) + +#define LPC214X_PINSEL0_P012_GPIO (0x00000000) +#define LPC214X_PINSEL0_P012_DSR1 (0x01000000) +#define LPC214X_PINSEL0_P012_MAT10 (0x02000000) +#define LPC214X_PINSEL0_P012_AD13 (0x03000000) +#define LPC214X_PINSEL0_P012_MASK (0x03000000) + +#define LPC214X_PINSEL0_P013_GPIO (0x00000000) +#define LPC214X_PINSEL0_P013_DTR1 (0x04000000) +#define LPC214X_PINSEL0_P013_MAT11 (0x08000000) +#define LPC214X_PINSEL0_P013_AD14 (0x0c000000) +#define LPC214X_PINSEL0_P013_MASK (0x0c000000) + +#define LPC214X_PINSEL0_P014_GPIO (0x00000000) +#define LPC214X_PINSEL0_P014_DCD1 (0x10000000) +#define LPC214X_PINSEL0_P014_EINT1 (0x20000000) +#define LPC214X_PINSEL0_P014_SDA1 (0x30000000) +#define LPC214X_PINSEL0_P014_MASK (0x30000000) + +#define LPC214X_PINSEL0_P015_GPIO (0x00000000) +#define LPC214X_PINSEL0_P015_RI1 (0x40000000) +#define LPC214X_PINSEL0_P015_EINT2 (0x80000000) +#define LPC214X_PINSEL0_P015_AD15 (0xc0000000) +#define LPC214X_PINSEL0_P015_MASK (0xc0000000) + +#define LPC214X_PINSEL1_P016_GPIO (0x00000000) +#define LPC214X_PINSEL1_P016_EINT0 (0x00000001) +#define LPC214X_PINSEL1_P016_MAT02 (0x00000002) +#define LPC214X_PINSEL1_P016_CAP02 (0x00000003) +#define LPC214X_PINSEL1_P016_MASK (0x00000003) + +#define LPC214X_PINSEL1_P017_GPIO (0x00000000) +#define LPC214X_PINSEL1_P017_CAP12 (0x00000004) +#define LPC214X_PINSEL1_P017_SCK1 (0x00000008) +#define LPC214X_PINSEL1_P017_MAT12 (0x0000000c) +#define LPC214X_PINSEL1_P017_MASK (0x0000000c) + +#define LPC214X_PINSEL1_P018_GPIO (0x00000000) +#define LPC214X_PINSEL1_P018_CAP13 (0x00000010) +#define LPC214X_PINSEL1_P018_MISO1 (0x00000020) +#define LPC214X_PINSEL1_P018_MAT13 (0x00000030) +#define LPC214X_PINSEL1_P018_MASK (0x00000030) + +#define LPC214X_PINSEL1_P019_GPIO (0x00000000) +#define LPC214X_PINSEL1_P019_MAT12 (0x00000040) +#define LPC214X_PINSEL1_P019_MOSI1 (0x00000080) +#define LPC214X_PINSEL1_P019_CAP12 (0x000000c0) +#define LPC214X_PINSEL1_P019_MASK (0x000000c0) + +#define LPC214X_PINSEL1_P020_GPIO (0x00000000) +#define LPC214X_PINSEL1_P020_MAT13 (0x00000100) +#define LPC214X_PINSEL1_P020_SSEL1 (0x00000200) +#define LPC214X_PINSEL1_P020_EINT3 (0x00000300) +#define LPC214X_PINSEL1_P020_MASK (0x00000300) + +#define LPC214X_PINSEL1_P021_GPIO (0x00000000) +#define LPC214X_PINSEL1_P021_PWM5 (0x00000400) +#define LPC214X_PINSEL1_P021_AD16 (0x00000800) +#define LPC214X_PINSEL1_P021_CAP13 (0x00000c00) +#define LPC214X_PINSEL1_P021_MASK (0x00000c00) + +#define LPC214X_PINSEL1_P022_GPIO (0x00000000) +#define LPC214X_PINSEL1_P022_AD17 (0x00001000) +#define LPC214X_PINSEL1_P022_CAP00 (0x00002000) +#define LPC214X_PINSEL1_P022_MAT00 (0x00003000) +#define LPC214X_PINSEL1_P022_MASK (0x00003000) + +#define LPC214X_PINSEL1_P023_GPIO (0x00000000) +#define LPC214X_PINSEL1_P023_VBUS (0x00004000) +#define LPC214X_PINSEL1_P023_RSVD2 (0x00008000) +#define LPC214X_PINSEL1_P023_RSVD3 (0x0000c000) +#define LPC214X_PINSEL1_P023_MASK (0x0000c000) + +#define LPC214X_PINSEL1_P024_RSVD0 (0x00000000) +#define LPC214X_PINSEL1_P024_RSVD1 (0x00010000) +#define LPC214X_PINSEL1_P024_RSVD2 (0x00020000) +#define LPC214X_PINSEL1_P024_RSVD3 (0x00030000) +#define LPC214X_PINSEL1_P024_MASK (0x00030000) + +#define LPC214X_PINSEL1_P025_GPIO (0x00000000) +#define LPC214X_PINSEL1_P025_AD04 (0x00040000) +#define LPC214X_PINSEL1_P025_AOUT (0x00080000) +#define LPC214X_PINSEL1_P025_RSVD3 (0x000c0000) +#define LPC214X_PINSEL1_P025_MASK (0x000c0000) + +#define LPC214X_PINSEL1_P026_RSVD0 (0x00000000) +#define LPC214X_PINSEL1_P026_RSVD1 (0x00100000) +#define LPC214X_PINSEL1_P026_RSVD2 (0x00200000) +#define LPC214X_PINSEL1_P026_RSVD3 (0x00300000) +#define LPC214X_PINSEL1_P026_MASK (0x00300000) + +#define LPC214X_PINSEL1_P027_RSVD0 (0x00000000) +#define LPC214X_PINSEL1_P027_RSVD1 (0x00400000) +#define LPC214X_PINSEL1_P027_RSVD2 (0x00800000) +#define LPC214X_PINSEL1_P027_RSVD3 (0x00c00000) +#define LPC214X_PINSEL1_P027_MASK (0x00c00000) + +#define LPC214X_PINSEL1_P028_GPIO (0x00000000) +#define LPC214X_PINSEL1_P028_AD01 (0x01000000) +#define LPC214X_PINSEL1_P028_CAP02 (0x02000000) +#define LPC214X_PINSEL1_P028_MAT02 (0x03000000) +#define LPC214X_PINSEL1_P028_MASK (0x03000000) + +#define LPC214X_PINSEL1_P029_GPIO (0x00000000) +#define LPC214X_PINSEL1_P029_AD02 (0x04000000) +#define LPC214X_PINSEL1_P029_CAP03 (0x08000000) +#define LPC214X_PINSEL1_P029_MAT03 (0x0c000000) +#define LPC214X_PINSEL1_P029_MASK (0x0c000000) + +#define LPC214X_PINSEL1_P030_GPIO (0x00000000) +#define LPC214X_PINSEL1_P030_AD03 (0x10000000) +#define LPC214X_PINSEL1_P030_EINT3 (0x20000000) +#define LPC214X_PINSEL1_P030_CAP00 (0x30000000) +#define LPC214X_PINSEL1_P030_MASK (0x30000000) + +#define LPC214X_PINSEL1_P031_GPIO (0x00000000) +#define LPC214X_PINSEL1_P031_UPLED (0x40000000) +#define LPC214X_PINSEL1_P031_CONNECT (0x80000000) +#define LPC214X_PINSEL1_P031_RSVD3 (0xc0000000) +#define LPC214X_PINSEL1_P031_MASK (0xc0000000) + +/************************************************************************************ + * Public Types + ************************************************************************************/ + +/************************************************************************************ + * Inline Functions + ************************************************************************************/ + +/************************************************************************************ + * Public Function Prototypes + ************************************************************************************/ + +#endif /* _ARCH_ARM_SRC_LPC214X_PINSEL_H */ diff --git a/nuttx/arch/arm/src/lpc214x/lpc214x_pll.h b/nuttx/arch/arm/src/lpc214x/lpc214x_pll.h new file mode 100644 index 000000000..bea923e43 --- /dev/null +++ b/nuttx/arch/arm/src/lpc214x/lpc214x_pll.h @@ -0,0 +1,105 @@ +/**************************************************************************************************** + * arch/arm/src/lpc214x/lpc214x_pll.h + * + * Copyright (C) 2008 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <gnutt@nuttx.org> + * + * 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. + * + ****************************************************************************************************/ + +#ifndef _ARCH_ARM_SRC_LPC214X_PLL_H +#define _ARCH_ARM_SRC_LPC214X_PLL_H + +/**************************************************************************************************** + * Included Files + ****************************************************************************************************/ + +#include <chip.h> + +/**************************************************************************************************** + * Definitions + ****************************************************************************************************/ + +/* PLL bass addresses *******************************************************************************/ + +/* There are two PLLs: PLL0 generates CCLK and PLL1 is configured to provide the 48MHx USB clock */ + +#define LPC214X_PLL0_BASE (LPC214X_PLL_BASE) +#define LPC214X_PLL1_BASE (LPC214X_PLL_BASE + 0x00000020) + +/* PLL registers ************************************************************************************/ + +#define LPC214x_PLL0_CON (LPC214X_PLL0_BASE+LPC214X_PLL_CON_OFFSET) +#define LPC214x_PLL0_CFG (LPC214X_PLL0_BASE+LPC214X_PLL_CFG_OFFSET) +#define LPC214x_PLL0_STAT (LPC214X_PLL0_BASE+LPC214X_PLL_STAT_OFFSET) +#define LPC214x_PLL0_FEED (LPC214X_PLL0_BASE+LPC214X_PLL_FEED_OFFSET) + +#define LPC214x_PLL1_CON (LPC214X_PLL1_BASE+LPC214X_PLL_CON_OFFSET) +#define LPC214x_PLL1_CFG (LPC214X_PLL1_BASE+LPC214X_PLL_CFG_OFFSET) +#define LPC214x_PLL1_STAT (LPC214X_PLL1_BASE+LPC214X_PLL_STAT_OFFSET) +#define LPC214x_PLL1_FEED (LPC214X_PLL1_BASE+LPC214X_PLL_FEED_OFFSET) + +/* Register bit settings ****************************************************************************/ + +/* PLL Control Register Bit Settings */ + +#define LPC214X_PLL_CON_PLLE (1 << 0) /* PLL Enable */ +#define LPC214X_PLL_CON_PLLC (1 << 1) /* PLL Connect */ + +/* PLL Configuration Register Bit Settings */ + +#define LPC214X_PLL_CFG_MSEL (0x1f << 0) /* PLL Multiplier (minus 1) */ +#define LPC214X_PLL_CFG_PSEL (0x03 << 5) /* PLL Divider (encoded) */ +#define LPC214X_PLL_CFG_PSEL1 (0x00 << 5) +#define LPC214X_PLL_CFG_PSEL2 (0x01 << 5) +#define LPC214X_PLL_CFG_PSEL4 (0x02 << 5) +#define LPC214X_PLL_CFG_PSEL8 (0x03 << 5) + +/* PLL Status Register Bit Settings */ + +#define LPC214X_PLL_STAT_MSEL (0x1f << 0) /* PLL Multiplier Readback */ +#define LPC214X_PLL_STAT_PSEL (0x03 << 5) /* PLL Divider Readback */ +#define LPC214X_PLL_STAT_PLLE (1 << 8) /* PLL Enable Readback */ +#define LPC214X_PLL_STAT_PLLC (1 << 9) /* PLL Connect Readback */ +#define LPC214X_PLL_STAT_PLOCK (1 << 10) /* PLL Lock Status */ + +/* PLL Feed Register values */ + +#define LPC214X_PLL_FEED1 0xaa +#define LPC214X_PLL_FEED2 0x55 + +/**************************************************************************************************** + * Inline Functions + ****************************************************************************************************/ + +/**************************************************************************************************** + * Global Function Prototypes + ****************************************************************************************************/ + +#endif /* _ARCH_ARM_SRC_LPC214X_PLL_H */ diff --git a/nuttx/arch/arm/src/lpc214x/lpc214x_power.h b/nuttx/arch/arm/src/lpc214x/lpc214x_power.h new file mode 100644 index 000000000..7eb253160 --- /dev/null +++ b/nuttx/arch/arm/src/lpc214x/lpc214x_power.h @@ -0,0 +1,90 @@ +/************************************************************************************ + * arch/arm/src/lpc214x/lpc214x_power.h + * + * Copyright (C) 2008 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <gnutt@nuttx.org> + * + * 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. + * + ************************************************************************************/ + +#ifndef _ARCH_ARM_SRC_LPC214X_POWER_H +#define _ARCH_ARM_SRC_LPC214X_POWER_H + +/************************************************************************************ + * Included Files + ************************************************************************************/ + +/************************************************************************************ + * Definitions + ************************************************************************************/ + +/* Register address definitions *****************************************************/ + +#define LPC214X_PCON_PCON (0xe01fc0c0) /* Power control register */ +#define LPC214X_PCON_PCONP (0xe01fc0c4) /* Power controls for peripherals register */ + +/* Register bit definitions *********************************************************/ + +/* Power control register */ + +#define LPC214X_PCON_IDL (0x01) /* Bit 0=1: Idle mode ON */ +#define LPC214X_PCON_PD (0x02) /* Bit 1=1: Power down mode ON */ +#define LPC214X_PCON_BODPDM (0x04) /* Bit 2=1: Brown out power down mode ON */ +#define LPC214X_PCON_BOGD (0x08) /* Bit 3=1: Brown out global disable */ +#define LPC214X_PCON_BORD (0x10) /* Bit 4=1: Brown out reset disable */ + +/* Peripheral power control register */ + +#define LPC214X_PCONP_PCTIM0 (0x00000002) /* Bit 1=1: Timer/counter0 control */ +#define LPC214X_PCONP_PCTIM1 (0x00000004) /* Bit 2=1: Timer/counter1 control */ +#define LPC214X_PCONP_PCUART0 (0x00000008) /* Bit 3=1: UART0 control */ +#define LPC214X_PCONP_PCUART1 (0x00000010) /* Bit 4=1: UART1 control */ +#define LPC214X_PCONP_PCWM0 (0x00000020) /* Bit 5=1: PWM0 control */ +#define LPC214X_PCONP_PCI2C0 (0x00000080) /* Bit 7=1: I2C0 control */ +#define LPC214X_PCONP_PCSPI0 (0x00000100) /* Bit 8=1: SPI0 control */ +#define LPC214X_PCONP_PCRTC (0x00000200) /* Bit 9=1: RTCcontrol */ +#define LPC214X_PCONP_PCSPI1 (0x00000400) /* Bit 10=1: SPI1 control */ +#define LPC214X_PCONP_PCAD0 (0x00001000) /* Bit 12=1: A/C converter 0 control */ +#define LPC214X_PCONP_PCI2C1 (0x00080000) /* Bit 19=1: I2C1 control */ +#define LPC214X_PCONP_PCAD1 (0x00100000) /* Bit 20=1: A/C converter 1 control */ +#define LPC214X_PCONP_PCUSB (0x80000000) /* Bit 31=1: USB power/clock control */ + +/************************************************************************************ + * Public Types + ************************************************************************************/ + +/************************************************************************************ + * Inline Functions + ************************************************************************************/ + +/************************************************************************************ + * Public Function Prototypes + ************************************************************************************/ + +#endif /* _ARCH_ARM_SRC_LPC214X_POWER_H */ diff --git a/nuttx/arch/arm/src/lpc214x/lpc214x_serial.c b/nuttx/arch/arm/src/lpc214x/lpc214x_serial.c new file mode 100644 index 000000000..691adfa75 --- /dev/null +++ b/nuttx/arch/arm/src/lpc214x/lpc214x_serial.c @@ -0,0 +1,842 @@ +/**************************************************************************** + * arch/arm/src/lpc214x/lpc214x_serial.c + * + * Copyright (C) 2007-2009, 2012 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <gnutt@nuttx.org> + * + * 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 <nuttx/config.h> + +#include <sys/types.h> +#include <stdint.h> +#include <stdbool.h> +#include <unistd.h> +#include <semaphore.h> +#include <string.h> +#include <errno.h> +#include <debug.h> +#include <nuttx/irq.h> +#include <nuttx/arch.h> +#include <nuttx/serial/serial.h> +#include <arch/serial.h> + +#include "chip.h" +#include "up_arch.h" +#include "os_internal.h" +#include "up_internal.h" + +#include "lpc214x_pinsel.h" +#include "lpc214x_uart.h" + +#ifdef USE_SERIALDRIVER + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct up_dev_s +{ + uint32_t uartbase; /* Base address of UART registers */ + uint32_t baud; /* Configured baud */ + uint8_t ier; /* Saved IER value */ + uint8_t irq; /* IRQ associated with this UART */ + uint8_t parity; /* 0=none, 1=odd, 2=even */ + uint8_t bits; /* Number of bits (7 or 8) */ + bool stopbits2; /* true: Configure with 2 stop bits instead of 1 */ +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static int up_setup(struct uart_dev_s *dev); +static void up_shutdown(struct uart_dev_s *dev); +static int up_attach(struct uart_dev_s *dev); +static void up_detach(struct uart_dev_s *dev); +static int up_interrupt(int irq, void *context); +static int up_ioctl(struct file *filep, int cmd, unsigned long arg); +static int up_receive(struct uart_dev_s *dev, uint32_t *status); +static void up_rxint(struct uart_dev_s *dev, bool enable); +static bool up_rxavailable(struct uart_dev_s *dev); +static void up_send(struct uart_dev_s *dev, int ch); +static void up_txint(struct uart_dev_s *dev, bool enable); +static bool up_txready(struct uart_dev_s *dev); +static bool up_txempty(struct uart_dev_s *dev); + +/**************************************************************************** + * Private Variables + ****************************************************************************/ + +struct uart_ops_s g_uart_ops = +{ + .setup = up_setup, + .shutdown = up_shutdown, + .attach = up_attach, + .detach = up_detach, + .ioctl = up_ioctl, + .receive = up_receive, + .rxint = up_rxint, + .rxavailable = up_rxavailable, + .send = up_send, + .txint = up_txint, + .txready = up_txready, + .txempty = up_txempty, +}; + +/* I/O buffers */ + +static char g_uart0rxbuffer[CONFIG_UART0_RXBUFSIZE]; +static char g_uart0txbuffer[CONFIG_UART0_TXBUFSIZE]; +static char g_uart1rxbuffer[CONFIG_UART1_RXBUFSIZE]; +static char g_uart1txbuffer[CONFIG_UART1_TXBUFSIZE]; + +/* This describes the state of the LPC214X uart0 port. */ + +static struct up_dev_s g_uart0priv = +{ + .uartbase = LPC214X_UART0_BASE, + .baud = CONFIG_UART0_BAUD, + .irq = LPC214X_UART0_IRQ, + .parity = CONFIG_UART0_PARITY, + .bits = CONFIG_UART0_BITS, + .stopbits2 = CONFIG_UART0_2STOP, +}; + +static uart_dev_t g_uart0port = +{ + .recv = + { + .size = CONFIG_UART0_RXBUFSIZE, + .buffer = g_uart0rxbuffer, + }, + .xmit = + { + .size = CONFIG_UART0_TXBUFSIZE, + .buffer = g_uart0txbuffer, + }, + .ops = &g_uart_ops, + .priv = &g_uart0priv, +}; + +/* This describes the state of the LPC214X uart1 port. */ + +static struct up_dev_s g_uart1priv = +{ + .uartbase = LPC214X_UART1_BASE, + .baud = CONFIG_UART1_BAUD, + .irq = LPC214X_UART1_IRQ, + .parity = CONFIG_UART1_PARITY, + .bits = CONFIG_UART1_BITS, + .stopbits2 = CONFIG_UART1_2STOP, +}; + +static uart_dev_t g_uart1port = +{ + .recv = + { + .size = CONFIG_UART1_RXBUFSIZE, + .buffer = g_uart1rxbuffer, + }, + .xmit = + { + .size = CONFIG_UART1_TXBUFSIZE, + .buffer = g_uart1txbuffer, + }, + .ops = &g_uart_ops, + .priv = &g_uart1priv, +}; + +/* Now, which one with be tty0/console and which tty1? */ + +#if defined(CONFIG_UART0_SERIAL_CONSOLE) +# define CONSOLE_DEV g_uart0port +# define TTYS0_DEV g_uart0port +# define TTYS1_DEV g_uart1port +#elif defined(CONFIG_UART1_SERIAL_CONSOLE) +# define CONSOLE_DEV g_uart1port +# define TTYS0_DEV g_uart1port +# define TTYS1_DEV g_uart0port +#else +# error "No CONFIG_UARTn_SERIAL_CONSOLE Setting" +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_serialin + ****************************************************************************/ + +static inline uint8_t up_serialin(struct up_dev_s *priv, int offset) +{ + return getreg8(priv->uartbase + offset); +} + +/**************************************************************************** + * Name: up_serialout + ****************************************************************************/ + +static inline void up_serialout(struct up_dev_s *priv, int offset, uint8_t value) +{ + putreg8(value, priv->uartbase + offset); +} + +/**************************************************************************** + * Name: up_disableuartint + ****************************************************************************/ + +static inline void up_disableuartint(struct up_dev_s *priv, uint8_t *ier) +{ + if (ier) + { + *ier = priv->ier & LPC214X_IER_ALLIE; + } + + priv->ier &= ~LPC214X_IER_ALLIE; + up_serialout(priv, LPC214X_UART_IER_OFFSET, priv->ier); +} + +/**************************************************************************** + * Name: up_restoreuartint + ****************************************************************************/ + +static inline void up_restoreuartint(struct up_dev_s *priv, uint8_t ier) +{ + priv->ier |= ier & LPC214X_IER_ALLIE; + up_serialout(priv, LPC214X_UART_IER_OFFSET, priv->ier); +} + +/**************************************************************************** + * Name: up_waittxready + ****************************************************************************/ + +static inline void up_waittxready(struct up_dev_s *priv) +{ + int tmp; + + /* Limit how long we will wait for the TX available condition */ + for (tmp = 1000 ; tmp > 0 ; tmp--) + { + /* Check if the tranmitter holding register (THR) is empty */ + if ((up_serialin(priv, LPC214X_UART_LSR_OFFSET) & LPC214X_LSR_THRE) != 0) + { + /* The THR is empty, return */ + break; + } + } +} + +/**************************************************************************** + * Name: up_enablebreaks + ****************************************************************************/ + +static inline void up_enablebreaks(struct up_dev_s *priv, bool enable) +{ + uint8_t lcr = up_serialin(priv, LPC214X_UART_LCR_OFFSET); + if (enable) + { + lcr |= LPC214X_LCR_BREAK_ENABLE; + } + else + { + lcr &= ~LPC214X_LCR_BREAK_ENABLE; + } + up_serialout(priv, LPC214X_UART_LCR_OFFSET, lcr); +} + +/**************************************************************************** + * Name: up_setup + * + * Description: + * Configure the UART baud, bits, parity, fifos, etc. This + * method is called the first time that the serial port is + * opened. + * + ****************************************************************************/ + +static int up_setup(struct uart_dev_s *dev) +{ +#ifndef CONFIG_SUPPRESS_LPC214X_UART_CONFIG + struct up_dev_s *priv = (struct up_dev_s*)dev->priv; + uint16_t baud; + uint8_t lcr; + + /* Clear fifos */ + + up_serialout(priv, LPC214X_UART_FCR_OFFSET, + (LPC214X_FCR_RX_FIFO_RESET|LPC214X_FCR_TX_FIFO_RESET)); + + /* Set trigger */ + + up_serialout(priv, LPC214X_UART_FCR_OFFSET, + (LPC214X_FCR_FIFO_ENABLE|LPC214X_FCR_FIFO_TRIG14)); + + /* Set up the IER */ + + priv->ier = up_serialin(priv, LPC214X_UART_IER_OFFSET); + + /* Set up the LCR */ + + lcr = 0; + + if (priv->bits == 7) + { + lcr |= LPC214X_LCR_CHAR_7; + } + else + { + lcr |= LPC214X_LCR_CHAR_8; + } + + if (priv->stopbits2) + { + lcr |= LPC214X_LCR_STOP_2; + } + + if (priv->parity == 1) + { + lcr |= LPC214X_LCR_PAR_ODD; + } + else if (priv->parity == 2) + { + lcr |= LPC214X_LCR_PAR_EVEN; + } + + /* Enter DLAB=1 */ + + up_serialout(priv, LPC214X_UART_LCR_OFFSET, + (lcr | LPC214X_LCR_DLAB_ENABLE)); + + /* Set the BAUD divisor */ + + baud = UART_BAUD(priv->baud); + up_serialout(priv, LPC214X_UART_DLM_OFFSET, baud >> 8); + up_serialout(priv, LPC214X_UART_DLL_OFFSET, baud & 0xff); + + /* Clear DLAB */ + + up_serialout(priv, LPC214X_UART_LCR_OFFSET, lcr); + + /* Configure the FIFOs */ + + up_serialout(priv, LPC214X_UART_FCR_OFFSET, + (LPC214X_FCR_FIFO_TRIG8|LPC214X_FCR_TX_FIFO_RESET|\ + LPC214X_FCR_RX_FIFO_RESET|LPC214X_FCR_FIFO_ENABLE)); + + /* The NuttX serial driver waits for the first THRE interrrupt before + * sending serial data... However, it appears that the lpc214x hardware + * does not generate that interrupt until a transition from not-empty + * to empty. So, the current kludge here is to send one NULL at + * startup to kick things off. + */ + + up_serialout(priv, LPC214X_UART_THR_OFFSET, '\0'); +#endif + return OK; +} + +/**************************************************************************** + * Name: up_shutdown + * + * Description: + * Disable the UART. This method is called when the serial + * port is closed + * + ****************************************************************************/ + +static void up_shutdown(struct uart_dev_s *dev) +{ + struct up_dev_s *priv = (struct up_dev_s*)dev->priv; + up_disableuartint(priv, NULL); +} + +/**************************************************************************** + * Name: up_attach + * + * Description: + * Configure the UART to operation in interrupt driven mode. This method is + * called when the serial port is opened. Normally, this is just after the + * the setup() method is called, however, the serial console may operate in + * a non-interrupt driven mode during the boot phase. + * + * RX and TX interrupts are not enabled when by the attach method (unless the + * hardware supports multiple levels of interrupt enabling). The RX and TX + * interrupts are not enabled until the txint() and rxint() methods are called. + * + ****************************************************************************/ + +static int up_attach(struct uart_dev_s *dev) +{ + struct up_dev_s *priv = (struct up_dev_s*)dev->priv; + int ret; + + /* Attach and enable the IRQ */ + + ret = irq_attach(priv->irq, up_interrupt); + if (ret == OK) + { + /* Enable the interrupt (RX and TX interrupts are still disabled + * in the UART + */ + + up_enable_irq(priv->irq); + } + return ret; +} + +/**************************************************************************** + * Name: up_detach + * + * Description: + * Detach UART interrupts. This method is called when the serial port is + * closed normally just before the shutdown method is called. The exception is + * the serial console which is never shutdown. + * + ****************************************************************************/ + +static void up_detach(struct uart_dev_s *dev) +{ + struct up_dev_s *priv = (struct up_dev_s*)dev->priv; + up_disable_irq(priv->irq); + irq_detach(priv->irq); +} + +/**************************************************************************** + * Name: up_interrupt + * + * Description: + * This is the UART interrupt handler. It will be invoked + * when an interrupt received on the 'irq' It should call + * uart_transmitchars or uart_receivechar to perform the + * appropriate data transfers. The interrupt handling logic\ + * must be able to map the 'irq' number into the approprite + * uart_dev_s structure in order to call these functions. + * + ****************************************************************************/ + +static int up_interrupt(int irq, void *context) +{ + struct uart_dev_s *dev = NULL; + struct up_dev_s *priv; + uint8_t status; + int passes; + + if (g_uart1priv.irq == irq) + { + dev = &g_uart1port; + } + else if (g_uart0priv.irq == irq) + { + dev = &g_uart0port; + } + else + { + PANIC(OSERR_INTERNAL); + } + priv = (struct up_dev_s*)dev->priv; + + /* Loop until there are no characters to be transferred or, + * until we have been looping for a long time. + */ + + for (passes = 0; passes < 256; passes++) + { + /* Get the current UART status and check for loop + * termination conditions + */ + + status = up_serialin(priv, LPC214X_UART_IIR_OFFSET); + + /* The NO INTERRUPT should be zero if there are pending + * interrupts + */ + + if ((status & LPC214X_IIR_NO_INT) != 0) + { + /* Break out of the loop when there is no longer a + * pending interrupt + */ + + break; + } + + /* Handle the interrupt by its interrupt ID field */ + + switch (status & LPC214X_IIR_MASK) + { + /* Handle incoming, receive bytes (with or without timeout) */ + + case LPC214X_IIR_RDA_INT: + case LPC214X_IIR_CTI_INT: + { + uart_recvchars(dev); + break; + } + + /* Handle outgoing, transmit bytes */ + + case LPC214X_IIR_THRE_INT: + { + uart_xmitchars(dev); + break; + } + + /* Just clear modem status interrupts (UART1 only) */ + + case LPC214X_IIR_MS_INT: + { + /* Read the modem status register (MSR) to clear */ + + status = up_serialin(priv, LPC214X_UART_MSR_OFFSET); + vdbg("MSR: %02x\n", status); + break; + } + + /* Just clear any line status interrupts */ + + case LPC214X_IIR_RLS_INT: + { + /* Read the line status register (LSR) to clear */ + + status = up_serialin(priv, LPC214X_UART_LSR_OFFSET); + vdbg("LSR: %02x\n", status); + break; + } + + /* There should be no other values */ + + default: + { + dbg("Unexpected IIR: %02x\n", status); + break; + } + } + } + return OK; +} + +/**************************************************************************** + * Name: up_ioctl + * + * Description: + * All ioctl calls will be routed through this method + * + ****************************************************************************/ + +static int up_ioctl(struct file *filep, int cmd, unsigned long arg) +{ + struct inode *inode = filep->f_inode; + struct uart_dev_s *dev = inode->i_private; + struct up_dev_s *priv = (struct up_dev_s*)dev->priv; + int ret = OK; + + switch (cmd) + { + case TIOCSERGSTRUCT: + { + struct up_dev_s *user = (struct up_dev_s*)arg; + if (!user) + { + ret = -EINVAL; + } + else + { + memcpy(user, dev, sizeof(struct up_dev_s)); + } + } + break; + + case TIOCSBRK: /* BSD compatibility: Turn break on, unconditionally */ + { + irqstate_t flags = irqsave(); + up_enablebreaks(priv, true); + irqrestore(flags); + } + break; + + case TIOCCBRK: /* BSD compatibility: Turn break off, unconditionally */ + { + irqstate_t flags; + flags = irqsave(); + up_enablebreaks(priv, false); + irqrestore(flags); + } + break; + + default: + ret = -ENOTTY; + break; + } + + return ret; +} + +/**************************************************************************** + * Name: up_receive + * + * Description: + * Called (usually) from the interrupt level to receive one + * character from the UART. Error bits associated with the + * receipt are provided in the return 'status'. + * + ****************************************************************************/ + +static int up_receive(struct uart_dev_s *dev, uint32_t *status) +{ + struct up_dev_s *priv = (struct up_dev_s*)dev->priv; + uint8_t rbr; + + *status = up_serialin(priv, LPC214X_UART_LSR_OFFSET); + rbr = up_serialin(priv, LPC214X_UART_RBR_OFFSET); + return rbr; +} + +/**************************************************************************** + * Name: up_rxint + * + * Description: + * Call to enable or disable RX interrupts + * + ****************************************************************************/ + +static void up_rxint(struct uart_dev_s *dev, bool enable) +{ + struct up_dev_s *priv = (struct up_dev_s*)dev->priv; + if (enable) + { +#ifndef CONFIG_SUPPRESS_SERIAL_INTS + priv->ier |= LPC214X_IER_ERBFI; +#endif + } + else + { + priv->ier &= ~LPC214X_IER_ERBFI; + } + up_serialout(priv, LPC214X_UART_IER_OFFSET, priv->ier); +} + +/**************************************************************************** + * Name: up_rxavailable + * + * Description: + * Return true if the receive fifo is not empty + * + ****************************************************************************/ + +static bool up_rxavailable(struct uart_dev_s *dev) +{ + struct up_dev_s *priv = (struct up_dev_s*)dev->priv; + return ((up_serialin(priv, LPC214X_UART_LSR_OFFSET) & LPC214X_LSR_RDR) != 0); +} + +/**************************************************************************** + * Name: up_send + * + * Description: + * This method will send one byte on the UART + * + ****************************************************************************/ + +static void up_send(struct uart_dev_s *dev, int ch) +{ + struct up_dev_s *priv = (struct up_dev_s*)dev->priv; + up_serialout(priv, LPC214X_UART_THR_OFFSET, (uint8_t)ch); +} + +/**************************************************************************** + * Name: up_txint + * + * Description: + * Call to enable or disable TX interrupts + * + ****************************************************************************/ + +static void up_txint(struct uart_dev_s *dev, bool enable) +{ + struct up_dev_s *priv = (struct up_dev_s*)dev->priv; + if (enable) + { +#ifndef CONFIG_SUPPRESS_SERIAL_INTS + priv->ier |= LPC214X_IER_ETBEI; +#endif + } + else + { + priv->ier &= ~LPC214X_IER_ETBEI; + } + up_serialout(priv, LPC214X_UART_IER_OFFSET, priv->ier); +} + +/**************************************************************************** + * Name: up_txready + * + * Description: + * Return true if the tranmsit fifo is not full + * + ****************************************************************************/ + +static bool up_txready(struct uart_dev_s *dev) +{ + struct up_dev_s *priv = (struct up_dev_s*)dev->priv; + return ((up_serialin(priv, LPC214X_UART_LSR_OFFSET) & LPC214X_LSR_THRE) != 0); +} + +/**************************************************************************** + * Name: up_txempty + * + * Description: + * Return true if the transmit fifo is empty + * + ****************************************************************************/ + +static bool up_txempty(struct uart_dev_s *dev) +{ + struct up_dev_s *priv = (struct up_dev_s*)dev->priv; + return ((up_serialin(priv, LPC214X_UART_LSR_OFFSET) & LPC214X_LSR_THRE) != 0); +} + +/**************************************************************************** + * Public Funtions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_serialinit + * + * Description: + * Performs the low level UART initialization early in + * debug so that the serial console will be available + * during bootup. This must be called before up_serialinit. + * + ****************************************************************************/ + +void up_earlyserialinit(void) +{ + /* Enable UART0 and 1 */ + + uint32_t pinsel = getreg32(LPC214X_PINSEL0); + pinsel &= ~(LPC214X_UART0_PINMASK|LPC214X_UART1_PINMASK); + pinsel |= (LPC214X_UART0_PINSEL|LPC214X_UART1_PINSEL); + putreg32(pinsel, LPC214X_PINSEL0); + + /* Disable both UARTS */ + + up_disableuartint(TTYS0_DEV.priv, NULL); + up_disableuartint(TTYS1_DEV.priv, NULL); + + /* Configuration whichever one is the console */ + + CONSOLE_DEV.isconsole = true; + up_setup(&CONSOLE_DEV); +} + +/**************************************************************************** + * Name: up_serialinit + * + * Description: + * Register serial console and serial ports. This assumes + * that up_earlyserialinit was called previously. + * + ****************************************************************************/ + +void up_serialinit(void) +{ + (void)uart_register("/dev/console", &CONSOLE_DEV); + (void)uart_register("/dev/ttyS0", &TTYS0_DEV); + (void)uart_register("/dev/ttyS1", &TTYS1_DEV); +} + +/**************************************************************************** + * Name: up_putc + * + * Description: + * Provide priority, low-level access to support OS debug writes + * + ****************************************************************************/ + +int up_putc(int ch) +{ + struct up_dev_s *priv = (struct up_dev_s*)CONSOLE_DEV.priv; + uint8_t ier; + + up_disableuartint(priv, &ier); + up_waittxready(priv); + up_serialout(priv, LPC214X_UART_THR_OFFSET, (uint8_t)ch); + + /* Check for LF */ + + if (ch == '\n') + { + /* Add CR */ + + up_waittxready(priv); + up_serialout(priv, LPC214X_UART_THR_OFFSET, '\r'); + } + + up_waittxready(priv); + up_restoreuartint(priv, ier); + return ch; +} + +#else /* USE_SERIALDRIVER */ + +/**************************************************************************** + * Name: up_putc + * + * Description: + * Provide priority, low-level access to support OS debug writes + * + ****************************************************************************/ + +int up_putc(int ch) +{ + /* Check for LF */ + + if (ch == '\n') + { + /* Add CR */ + + up_lowputc('\r'); + } + + up_lowputc(ch); + return ch; +} + +#endif /* USE_SERIALDRIVER */ diff --git a/nuttx/arch/arm/src/lpc214x/lpc214x_spi.h b/nuttx/arch/arm/src/lpc214x/lpc214x_spi.h new file mode 100644 index 000000000..ce6a03db9 --- /dev/null +++ b/nuttx/arch/arm/src/lpc214x/lpc214x_spi.h @@ -0,0 +1,166 @@ +/************************************************************************************ + * arch/arm/src/lpc214x/lpc214x_spi.h + * + * Copyright (C) 2008 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <gnutt@nuttx.org> + * + * 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. + * + ************************************************************************************/ + +#ifndef _ARCH_ARM_SRC_LPC214X_SPI_H +#define _ARCH_ARM_SRC_LPC214X_SPI_H + +/************************************************************************************ + * Included Files + ************************************************************************************/ + +#include "chip.h" + +/************************************************************************************ + * Definitions + ************************************************************************************/ + +/* Register address definitions *****************************************************/ + +/* SPI absolute register addresses */ + +#define LPC214X_SPI0_CR (LPC214X_SPI0_BASE+LPC214X_SPI0_CR_OFFSET) /* 16-bits wide */ +#define LPC214X_SPI0_SR (LPC214X_SPI0_BASE+LPC214X_SPI0_SR_OFFSET) /* 8-bits wide */ +#define LPC214X_SPI0_DR (LPC214X_SPI0_BASE+LPC214X_SPI0_DR_OFFSET) /* 16-bits wide */ +#define LPC214X_SPI0_CCR (LPC214X_SPI0_BASE+LPC214X_SPI0_CCR_OFFSET) /* 8-bits wide */ +#define LPC214X_SPI0_INT (LPC214X_SPI0_BASE+LPC214X_SPI0_INT_OFFSET) /* 8-bits wide */ + +#define LPC214X_SPI1_CR0 (LPC214X_SPI1_BASE+LPC214X_SPI1_CR0_OFFSET) /* 16-bits wide */ +#define LPC214X_SPI1_CR1 (LPC214X_SPI1_BASE+LPC214X_SPI1_CR1_OFFSET) /* 8-bits wide */ +#define LPC214X_SPI1_DR (LPC214X_SPI1_BASE+LPC214X_SPI1_DR_OFFSET) /* 16-bits wide */ +#define LPC214X_SPI1_SR (LPC214X_SPI1_BASE+LPC214X_SPI1_SR_OFFSET) /* 8-bits wide */ +#define LPC214X_SPI1_CPSR (LPC214X_SPI1_BASE+LPC214X_SPI1_IMSC_OFFSET) /* 8-bits wide */ +#define LPC214X_SPI1_IMSC (LPC214X_SPI1_BASE+LPC214X_SPI1_IMSC_OFFSET) /* 8-bits wide */ +#define LPC214X_SPI1_RIS (LPC214X_SPI1_BASE+LPC214X_SPI1_RIS_OFFSET) /* 8-bits wide */ +#define LPC214X_SPI1_MIS (LPC214X_SPI1_BASE+LPC214X_SPI1_ICR_OFFSET) /* 8-bits wide */ +#define LPC214X_SPI1_ICR (LPC214X_SPI1_BASE+LPC214X_SPI1_ICR_OFFSET) /* 8-bits wide */ + +/* SPI0 register bit definitions ****************************************************/ + +/* Control Register (CR) for SPI0 */ + +#define LPC214X_SPI0CR0_BITSENB (0x0004) /* Bit 2=0: 8-bits, else see bits 8-11 */ +#define LPC214X_SPI0CR0_CPHA (0x0008) /* Bit 3: Clock phase control */ +#define LPC214X_SPI0CR0_CPOL (0x0010) /* Bit 4: Clock polarity control */ +#define LPC214X_SPI0CR0_MSTR (0x0020) /* Bit 5=1: Master 0: Slave */ +#define LPC214X_SPI0CR0_LSBF (0x0040) /* Bit 6=1: Shift LSB first */ +#define LPC214X_SPI0CR0_SPIE (0x0080) /* Bit 7=1: SPI interrupt enable */ +#define LPC214X_SPI0CR0_BITSMASK (0x0f00) /* Bits 8-11: Number of bits per transfer */ +#define LPC214X_SPI0CR0_BITS8 (0x0800) /* 8-bits per transfer */ +#define LPC214X_SPI0CR0_BITS9 (0x0900) /* 9-bits per transfer */ +#define LPC214X_SPI0CR0_BITS10 (0x0a00) /* 10-bits per transfer */ +#define LPC214X_SPI0CR0_BITS11 (0x0b00) /* 11-bits per transfer */ +#define LPC214X_SPI0CR0_BITS12 (0x0c00) /* 12-bits per transfer */ +#define LPC214X_SPI0CR0_BITS13 (0x0d00) /* 13-bits per transfer */ +#define LPC214X_SPI0CR0_BITS14 (0x0e00) /* 14-bits per transfer */ +#define LPC214X_SPI0CR0_BITS15 (0x0f00) /* 15-bits per transfer */ +#define LPC214X_SPI0CR0_BITS16 (0x0000) /* 16-bits per transfer */ + +/* Status Regiser (SR) for SPI0 */ + +#define LPC214X_SPI0SR_ABRT (0x08) /* Bit 3=1: Slave abort */ +#define LPC214X_SPI0SR_MODF (0x10) /* Bit 4=1: Mode fault */ +#define LPC214X_SPI0SR_ROVR (0x20) /* Bit 5=1: Read overrun */ +#define LPC214X_SPI0SR_WCOL (0x40) /* Bit 6=1: Write collision */ +#define LPC214X_SPI0SR_SPIF (0x80) /* Bit 7=1: SPI transfer complete */ + +/* Interrupt Register for SPI0 */ + +#define LPC214X_SPO0INT_SPI (0x01) /* Bit 0=1: SPI interrupt */ + +/* SPI1 register bit definitions ****************************************************/ + +/* Control Register 0 (CR0) for SPI1 */ + +#define LPC214X_SPI1CR0_DSSMASK (0x000f) /* Bits 0-3: Data size select mask */ +#define LPC214X_SPI1CR0_DSS4BIT (0x0003) /* 4-bit transfer */ +#define LPC214X_SPI1CR0_DSS5BIT (0x0004) /* 5-bit transfer */ +#define LPC214X_SPI1CR0_DSS6BIT (0x0005) /* 6-bit transfer */ +#define LPC214X_SPI1CR0_DSS7BIT (0x0006) /* 7-bit transfer */ +#define LPC214X_SPI1CR0_DSS8BIT (0x0007) /* 8-bit transfer */ +#define LPC214X_SPI1CR0_DSS9BIT (0x0008) /* 9-bit transfer */ +#define LPC214X_SPI1CR0_DSS10BIT (0x0009) /* 10-bit transfer */ +#define LPC214X_SPI1CR0_DSS11BIT (0x000a) /* 11-bit transfer */ +#define LPC214X_SPI1CR0_DSS12BIT (0x000b) /* 12-bit transfer */ +#define LPC214X_SPI1CR0_DSS13BIT (0x000c) /* 13-bit transfer */ +#define LPC214X_SPI1CR0_DSS14BIT (0x000d) /* 14-bit transfer */ +#define LPC214X_SPI1CR0_DSS15BIT (0x000e) /* 15-bit transfer */ +#define LPC214X_SPI1CR0_DSS16BIT (0x000f) /* 16-bit transfer */ +#define LPC214X_SPI1CR0_FRFMASK (0x0030) /* Bits 4-5: Frame format mask */ +#define LPC214X_SPI1CR0_FRFSPI (0x0000) /* SPI */ +#define LPC214X_SPI1CR0_FRFSSI (0x0010) /* SSI */ +#define LPC214X_SPI1CR0_FRFMW (0x0020) /* Microwire */ +#define LPC214X_SPI1CR0_CPOL (0x0040) /* Bit 6: Clock polarity control */ +#define LPC214X_SPI1CR0_CPHA (0x0080) /* Bit 7: Clock phase control */ +#define LPC214X_SPI1CR0_SCR (0xff00) /* Bits 8-15: Serial clock reate */ + +/* Control Register 1 (CR1) */ + +#define LPC214X_SPI1CR1_LBM (0x01) /* Bit 0: 1=Loopback mode */ +#define LPC214X_SPI1CR1_SSE (0x02) /* Bit 1: 1=SSP enable */ +#define LPC214X_SPI1CR1_MS (0x04) /* Bit 2: 1=Controller is slave */ +#define LPC214X_SPI1CR1_SOD (0x08) /* Bit 3: 1=Slave output disable */ + +/* SSP Status Register (SR) */ + +#define LPC214X_SPI1SR_TFE (0x01) /* Bit 0: 1=Transmit FIFO Empty */ +#define LPC214X_SPI1SR_TNF (0x02) /* Bit 1: 1=Transmit FIFO not full */ +#define LPC214X_SPI1SR_RNE (0x04) /* Bit 2: 1=Receive FIFO not empty */ +#define LPC214X_SPI1SR_RFF (0x08) /* Bit 3: 1=Receive FIFO full */ +#define LPC214X_SPI1SR_BSY (0x10) /* Bit 4: 1=Busy */ + +/* Interrupt set/clear/status/mask registers (can't clear RXIM or TXIM) */ + +#define LPC214X_SP1INT_ROR (0x01) /* Bit 0: 1=Recieve Overrun */ +#define LPC214X_SP1INT_RTIM (0x02) /* Bit 1: 1=Recieve Timeout */ +#define LPC214X_SP1INT_RXIM (0x04) /* Bit 2: 1=RX FIFO at least half full */ +#define LPC214X_SP1INT_TXIM (0x08) /* Bit 3: 1=TX FIFO at least half empty */ + +/* SPI1 supports an 8-frame FIFO */ + +#define LPC214X_SPI1_FIFOSZ (8) + +/************************************************************************************ + * Public Types + ************************************************************************************/ + +/************************************************************************************ + * Inline Functions + ************************************************************************************/ + +/************************************************************************************ + * Public Function Prototypes + ************************************************************************************/ + +#endif /* _ARCH_ARM_SRC_LPC214X_SPI_H */ diff --git a/nuttx/arch/arm/src/lpc214x/lpc214x_timer.h b/nuttx/arch/arm/src/lpc214x/lpc214x_timer.h new file mode 100644 index 000000000..6c239f10c --- /dev/null +++ b/nuttx/arch/arm/src/lpc214x/lpc214x_timer.h @@ -0,0 +1,152 @@ +/************************************************************************************ + * arch/arm/src/lpc214x/lpc214x_timer.h + * + * Copyright (C) 2007, 2008 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <gnutt@nuttx.org> + * + * 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. + * + ************************************************************************************/ + +#ifndef __LPC214X_TIMER_H +#define __LPC214X_TIMER_H + +/************************************************************************************ + * Included Files + ************************************************************************************/ + +/************************************************************************************ + * Definitions + ************************************************************************************/ + +/* Timer registers are 8-, 16-bit and 32-bits wide */ + +/* Timer Interrupt Register Bit Definitions (8-bit) */ + +#define LPC214X_TMR_IR_MR0I (1 << 0) /* Interrupt flag for match channel 0 */ +#define LPC214X_TMR_IR_MR1I (1 << 1) /* Interrupt flag for match channel 1 */ +#define LPC214X_TMR_IR_MR2I (1 << 2) /* Interrupt flag for match channel 2 */ +#define LPC214X_TMR_IR_MR3I (1 << 3) /* Interrupt flag for match channel 3 */ +#define LPC214X_TMR_IR_CR0I (1 << 4) /* Interrupt flag for capture channel 0 event */ +#define LPC214X_TMR_IR_CR1I (1 << 5) /* Interrupt flag for capture channel 1 event */ +#define LPC214X_TMR_IR_CR2I (1 << 6) /* Interrupt flag for capture channel 2 event */ +#define LPC214X_TMR_IR_CR3I (1 << 7) /* Interrupt flag for capture channel 3 event */ +#define LPC214X_TMR_IR_ALLI (0xff) /* All timer interrupts */ + +/* Timer Control Register Bit Definitions (8-bits) */ + +#define LPC214X_TMR_CR_ENABLE (1 << 0) /* Counter Enable */ +#define LPC214X_TMR_CR_RESET (1 << 1) /* Countger Reset */ + +/* Timer Counter (32-bits, no bit fields) */ + +/* Timer Prescale Register Bit Definitions (32-bits, no bit fields) */ + +/* Timer Prescale Counter Register Bit Definitions */ + +/* Timer Match Control Register Bit Definitions (16-bit) */ + +#define LPC214X_TMR_MCR_MR0I (1 << 0) /* Enable Interrupt when MR0 matches TC */ +#define LPC214X_TMR_MCR_MR0R (1 << 1) /* Enable Reset of TC upon MR0 match */ +#define LPC214X_TMR_MCR_MR0S (1 << 2) /* Enable Stop of TC upon MR0 match */ +#define LPC214X_TMR_MCR_MR1I (1 << 3) /* Enable Interrupt when MR1 matches TC */ +#define LPC214X_TMR_MCR_MR1R (1 << 4) /* Enable Reset of TC upon MR1 match */ +#define LPC214X_TMR_MCR_MR1S (1 << 5) /* Enable Stop of TC upon MR1 match */ +#define LPC214X_TMR_MCR_MR2I (1 << 6) /* Enable Interrupt when MR2 matches TC */ +#define LPC214X_TMR_MCR_MR2R (1 << 7) /* Enable Reset of TC upon MR2 match */ +#define LPC214X_TMR_MCR_MR2S (1 << 8) /* Enable Stop of TC upon MR2 match */ +#define LPC214X_TMR_MCR_MR3I (1 << 9) /* Enable Interrupt when MR3 matches TC */ +#define LPC214X_TMR_MCR_MR3R (1 << 10) /* Enable Reset of TC upon MR3 match */ +#define LPC214X_TMR_MCR_MR3S (1 << 11) /* Enable Stop of TC upon MR3 match */ + +/* Timer Match Register 0/1/2/3 (32-bits, no bit fields) */ + +/* Timer Capture Control Register Bit Definitions */ + +#define LPC214X_TMR_CCR_CAP0RE (1 << 0) /* Enable Rising edge on CAPn.0 will load TC to CR0 */ +#define LPC214X_TMR_CCR_CAP0FE (1 << 1) /* Enable Falling edge on CAPn.0 will load TC to CR0 */ +#define LPC214X_TMR_CCR_CAP0I (1 << 2) /* Enable Interrupt on load of CR0 */ +#define LPC214X_TMR_CCR_CAP1RE (1 << 3) /* Enable Rising edge on CAPn.1 will load TC to CR1 */ +#define LPC214X_TMR_CCR_CAP1FE (1 << 4) /* Enable Falling edge on CAPn.1 will load TC to CR1 */ +#define LPC214X_TMR_CCR_CAP1I (1 << 5) /* Enable Interrupt on load of CR1 */ +#define LPC214X_TMR_CCR_CAP2RE (1 << 6) /* Enable Rising edge on CAPn.2 will load TC to CR2 */ +#define LPC214X_TMR_CCR_CAP2FE (1 << 7) /* Enable Falling edge on CAPn.2 will load TC to CR2 */ +#define LPC214X_TMR_CCR_CAP2I (1 << 8) /* Enable Interrupt on load of CR2 */ +#define LPC214X_TMR_CCR_CAP3RE (1 << 9) /* Enable Rising edge on CAPn.3 will load TC to CR3 */ +#define LPC214X_TMR_CCR_CAP3FE (1 << 10) /* Enable Falling edge on CAPn.3 will load TC to CR3 */ +#define LPC214X_TMR_CCR_CAP3I (1 << 11) /* Enable Interrupt on load of CR3 */ + +/* Timer Capture Register 0/1/2/3 (32-bits, no bit fields) */ + +/* Timer External Match Register Bit Definitions */ + +#define LPC214X_TMR_EMR_EM0 (1 << 0) /* External Match 0 */ +#define LPC214X_TMR_EMR_EM1 (1 << 1) /* External Match 1 */ +#define LPC214X_TMR_EMR_EM2 (1 << 2) /* External Match 2 */ +#define LPC214X_TMR_EMR_EM3 (1 << 3) /* External Match 3 */ + +#define LPC214X_TMR_EMR_EMC0(b) ((b) << 4) /* External match control 0 (see below) */ +#define LPC214X_TMR_EMR_EMC1(b) ((b) << 6) /* External match control 1 (see below) */ +#define LPC214X_TMR_EMR_EMC2(b) ((b) << 8) /* External match control 2 (see below) */ +#define LPC214X_TMR_EMR_EMC3(b) ((b) << 10) /* External match control 3 (see below) */ + +/* EMR External Match Control (EMCn) Field Falues */ + +#define LPC214X_TMR_EMR_MASK (3) /* Mask for all bits */ +#define LPC214X_TMR_EMR_NOOP (0) /* Do nothing */ +#define LPC214X_TMR_EMR_CLEAR (1) /* Clear corresponding EMn bit/output to 0 */ +#define LPC214X_TMR_EMR_SET (2) /* Set corresponding EMn bit/output to 1 */ +#define LPC214X_TMR_EMR_TOGGLE (3) /* Toggle corresponding EMn bit/output */ + +/* Timer Count Control Register Bit Definitions (8-bit) */ + +#define LPC214X_TMR_ +#define LPC214X_TMR_CTCR_MODE_MASK (3 << 0) /* Counter/Timer Mode */ +#define LPC214X_TMR_CTCR_PCLK (0 << 0) /* Rising edge of PCLK */ +#define LPC214X_TMR_CTCR_RISING (1 << 0) /* Rising edge of CAP input */ +#define LPC214X_TMR_CTDR_FALLING (2 << 0) /* Failing edge of CAP input */ +#define LPC214X_TMR_CTCR_BOTH (3 << 0) /* Both edges of CAP input */ +#define LPC214X_TMR_CTCR_INPUT_MASK (3 << 2) /* Counter Input Select */ +#define LPC214X_TMR_CTCR_CR0 (0 << 2) /* CAPn.0 */ +#define LPC214X_TMR_CTCR_CR1 (1 << 2) /* CAPn.1 */ +#define LPC214X_TMR_CTCR_CR2 (2 << 2) /* CAPn.2 */ +#define LPC214X_TMR_CTCR_CR3 (3 << 2) /* CAPn.3 */ + +/************************************************************************************ + * Public Types + ************************************************************************************/ + +/************************************************************************************ + * Inline Functions + ************************************************************************************/ + +/************************************************************************************ + * Public Function Prototypes + ************************************************************************************/ + +#endif /* __LPC214X_TIMER_H */ diff --git a/nuttx/arch/arm/src/lpc214x/lpc214x_timerisr.c b/nuttx/arch/arm/src/lpc214x/lpc214x_timerisr.c new file mode 100644 index 000000000..99d1d118f --- /dev/null +++ b/nuttx/arch/arm/src/lpc214x/lpc214x_timerisr.c @@ -0,0 +1,170 @@ +/**************************************************************************** + * arch/arm/src/lpc214x/lpc214x_timerisr.c + * + * Copyright (C) 2007-2009 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <gnutt@nuttx.org> + * + * 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 <nuttx/config.h> + +#include <stdint.h> +#include <debug.h> +#include <nuttx/arch.h> +#include <arch/board/board.h> + +#include "chip.h" +#include "up_arch.h" +#include "clock_internal.h" +#include "up_internal.h" + +#include "lpc214x_timer.h" +#include "lpc214x_vic.h" + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +/* The timers count at the rate of PCLK which is determined by PLL_M and + * and APBDIV: + */ + +#define LPC214X_CCLKFREQ (LPC214X_FOSC*LPC214X_PLL_M) +#define LPC214X_PCLKFREQ (LPC214X_CCLKFREQ/LPC214X_APB_DIV) + +#define tmr_getreg8(o) getreg8(LPC214X_TMR0_BASE+(o)) +#define tmr_getreg16(o) getreg16(LPC214X_TMR0_BASE+(o)) +#define tmr_getreg32(o) getreg32(LPC214X_TMR0_BASE+(o)) + +#define tmr_putreg8(v,o) putreg8((v), LPC214X_TMR0_BASE+(o)) +#define tmr_putreg16(v,o) putreg16((v), LPC214X_TMR0_BASE+(o)) +#define tmr_putreg32(v,o) putreg32((v), LPC214X_TMR0_BASE+(o)) + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Global Functions + ****************************************************************************/ + +/**************************************************************************** + * Function: up_timerisr + * + * Description: + * The timer ISR will perform a variety of services for + * various portions of the systems. + * + ****************************************************************************/ + +#ifdef CONFIG_VECTORED_INTERRUPTS +int up_timerisr(uint32_t *regs) +#else +int up_timerisr(int irq, uint32_t *regs) +#endif +{ + /* Process timer interrupt */ + + sched_process_timer(); + + /* Clear the MR0 match interrupt */ + + tmr_putreg8(LPC214X_TMR_IR_MR0I, LPC214X_TMR_IR_OFFSET); + + /* Reset the VIC as well */ + +#ifdef CONFIG_VECTORED_INTERRUPTS + vic_putreg(0, LPC214X_VIC_VECTADDR_OFFSET); +#endif + return 0; +} + +/**************************************************************************** + * Function: up_timerinit + * + * Description: + * This function is called during start-up to initialize + * the timer interrupt. + * + ****************************************************************************/ + +void up_timerinit(void) +{ + uint16_t mcr; + + /* Clear all match and capture event interrupts */ + + tmr_putreg8(LPC214X_TMR_IR_ALLI, LPC214X_TMR_IR_OFFSET); + + /* Clear the timer counter */ + + tmr_putreg32(0, LPC214X_TMR_TC_OFFSET); + + /* No pre-scaler */ + + tmr_putreg32(0, LPC214X_TMR_PR_OFFSET); + + /* Set timer match registger to get a TICK_PER_SEC rate + * See arch/board.h and sched/os_internal.h + */ + + tmr_putreg32(LPC214X_PCLKFREQ/TICK_PER_SEC, LPC214X_TMR_MR0_OFFSET); + + /* Reset timer counter regiser and interrupt on match */ + + mcr = tmr_getreg16(LPC214X_TMR_MCR_OFFSET); + mcr &= ~LPC214X_TMR_MCR_MR1I; + mcr |= (LPC214X_TMR_MCR_MR0I | LPC214X_TMR_MCR_MR0R); + tmr_putreg16(mcr, LPC214X_TMR_MCR_OFFSET); + + /* Enable counting */ + + tmr_putreg8(LPC214X_TMR_CR_ENABLE, LPC214X_TMR_TCR_OFFSET); + + /* Attach the timer interrupt vector */ + +#ifdef CONFIG_VECTORED_INTERRUPTS + up_attach_vector(LPC214X_IRQ_SYSTIMER, LPC214X_SYSTIMER_VEC, (vic_vector_t)up_timerisr); +#else + (void)irq_attach(LPC214X_IRQ_SYSTIMER, (xcpt_t)up_timerisr); +#endif + + /* And enable the timer interrupt */ + + up_enable_irq(LPC214X_IRQ_SYSTIMER); +} diff --git a/nuttx/arch/arm/src/lpc214x/lpc214x_uart.h b/nuttx/arch/arm/src/lpc214x/lpc214x_uart.h new file mode 100644 index 000000000..fd634a816 --- /dev/null +++ b/nuttx/arch/arm/src/lpc214x/lpc214x_uart.h @@ -0,0 +1,142 @@ +/************************************************************************************ + * arch/arm/src/lpc214x/uart.h + * + * Copyright (C) 2007, 2008 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <gnutt@nuttx.org> + * + * 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. + * + ************************************************************************************/ + +#ifndef __LPC214X_UART_H +#define __LPC214X_UART_H + +/************************************************************************************ + * Included Files + ************************************************************************************/ + +#include <arch/board/board.h> /* For clock settings */ + +/************************************************************************************ + * Definitions + ************************************************************************************/ + +/* PINSEL0 bit definitions for UART0/1 */ + +#define LPC214X_UART0_PINSEL 0x00000005 /* PINSEL0 value for UART0 */ +#define LPC214X_UART0_PINMASK 0x0000000f /* PINSEL0 mask for UART0 */ + +#define LPC214X_UART1_PINSEL 0x00050000 /* PINSEL0 value for UART1 */ +#define LPC214X_UART1_PINMASK 0x000f0000 /* PINSEL0 mask for UART1 */ + +/* Derive baud divisor setting from clock settings (see board.h) */ + +#define UART_BAUD(baud) ((LPC214X_FOSC * LPC214X_PLL_M) / (baud * 16)) + +/* Interrupt Enable Register (IER) bit definitions */ + +#define LPC214X_IER_ERBFI (1 << 0) /* Enable receive data available int */ +#define LPC214X_IER_ETBEI (1 << 1) /* Enable THR empty Interrupt */ +#define LPC214X_IER_ELSI (1 << 2) /* Enable receive line status int */ +#define LPC214X_IER_EDSSI (1 << 3) /* Enable MODEM atatus interrupt (2146/6/8 UART1 Only) */ +#define LPC214X_IER_ALLIE 0x0f /* All interrupts */ + +/* Interrupt ID Register(IIR) bit definitions */ + +#define LPC214X_IIR_NO_INT (1 << 0) /* No interrupts pending */ +#define LPC214X_IIR_MS_INT (0 << 1) /* MODEM Status (UART1 only) */ +#define LPC214X_IIR_THRE_INT (1 << 1) /* Transmit Holding Register Empty */ +#define LPC214X_IIR_RDA_INT (2 << 1) /* Receive Data Available */ +#define LPC214X_IIR_RLS_INT (3 << 1) /* Receive Line Status */ +#define LPC214X_IIR_CTI_INT (6 << 1) /* Character Timeout Indicator */ +#define LPC214X_IIR_MASK 0x0e + +/* FIFO Control Register (FCR) bit definitions */ + +#define LPC214X_FCR_FIFO_ENABLE (1 << 0) /* FIFO enable */ +#define LPC214X_FCR_RX_FIFO_RESET (1 << 1) /* Reset receive FIFO */ +#define LPC214X_FCR_TX_FIFO_RESET (1 << 2) /* Reset transmit FIFO */ +#define LPC214X_FCR_FIFO_TRIG1 (0 << 6) /* Trigger @1 character in FIFO */ +#define LPC214X_FCR_FIFO_TRIG4 (1 << 6) /* Trigger @4 characters in FIFO */ +#define LPC214X_FCR_FIFO_TRIG8 (2 << 6) /* Trigger @8 characters in FIFO */ +#define LPC214X_FCR_FIFO_TRIG14 (3 << 6) /* Trigger @14 characters in FIFO */ + +/* Line Control Register (LCR) bit definitions */ + +#define LPC214X_LCR_CHAR_5 (0 << 0) /* 5-bit character length */ +#define LPC214X_LCR_CHAR_6 (1 << 0) /* 6-bit character length */ +#define LPC214X_LCR_CHAR_7 (2 << 0) /* 7-bit character length */ +#define LPC214X_LCR_CHAR_8 (3 << 0) /* 8-bit character length */ +#define LPC214X_LCR_STOP_1 (0 << 2) /* 1 stop bit */ +#define LPC214X_LCR_STOP_2 (1 << 2) /* 2 stop bits */ +#define LPC214X_LCR_PAR_NONE (0 << 3) /* No parity */ +#define LPC214X_LCR_PAR_ODD (1 << 3) /* Odd parity */ +#define LPC214X_LCR_PAR_EVEN (3 << 3) /* Even parity */ +#define LPC214X_LCR_PAR_MARK (5 << 3) /* Mark "1" parity */ +#define LPC214X_LCR_PAR_SPACE (7 << 3) /* Space "0" parity */ +#define LPC214X_LCR_BREAK_ENABLE (1 << 6) /* Output BREAK */ +#define LPC214X_LCR_DLAB_ENABLE (1 << 7) /* Enable divisor latch access */ + +/* Modem Control Register (MCR) bit definitions */ + +#define LPC214X_MCR_DTR (1 << 0) /* Data terminal ready */ +#define LPC214X_MCR_RTS (1 << 1) /* Request to send */ +#define LPC214X_MCR_LB (1 << 4) /* Loopback */ + +/* Line Status Register (LSR) bit definitions */ + +#define LPC214X_LSR_RDR (1 << 0) /* Receive data ready */ +#define LPC214X_LSR_OE (1 << 1) /* Overrun error */ +#define LPC214X_LSR_PE (1 << 2) /* Parity error */ +#define LPC214X_LSR_FE (1 << 3) /* Framing error */ +#define LPC214X_LSR_BI (1 << 4) /* Break interrupt */ +#define LPC214X_LSR_THRE (1 << 5) /* THR empty */ +#define LPC214X_LSR_TEMT (1 << 6) /* Transmitter empty */ +#define LPC214X_LSR_RXFE (1 << 7) /* Error in receive FIFO */ +#define LPC214X_LSR_ERR_MASK 0x1e + +/* Modem Status Register (MSR) bit definitions */ + +#define LPC214X_MSR_DCTS (1 << 0) /* Delta clear to send */ +#define LPC214X_MSR_DDSR (1 << 1) /* Delta data set ready */ +#define LPC214X_MSR_TERI (1 << 2) /* Trailing edge ring indicator */ +#define LPC214X_MSR_DDCD (1 << 3) /* Delta data carrier detect */ +#define LPC214X_MSR_CTS (1 << 4) /* Clear to send */ +#define LPC214X_MSR_DSR (1 << 5) /* Data set ready */ +#define LPC214X_MSR_RI (1 << 6) /* Ring indicator */ +#define LPC214X_MSR_DCD (1 << 7) /* Data carrier detect */ + +/************************************************************************************ + * Inline Functions + ************************************************************************************/ + +/************************************************************************************ + * Global Function Prototypes + ************************************************************************************/ + +#endif /* __LPC214X_UART_H */ diff --git a/nuttx/arch/arm/src/lpc214x/lpc214x_usbdev.c b/nuttx/arch/arm/src/lpc214x/lpc214x_usbdev.c new file mode 100644 index 000000000..78a5fe1c3 --- /dev/null +++ b/nuttx/arch/arm/src/lpc214x/lpc214x_usbdev.c @@ -0,0 +1,3375 @@ +/******************************************************************************* + * arch/arm/src/lpc214x/lpc214x_usbdev.c + * + * Copyright (C) 2008-2010, 2012 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <gnutt@nuttx.org> + * + * 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 <nuttx/config.h> + +#include <sys/types.h> +#include <stdint.h> +#include <stdbool.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <debug.h> + +#include <nuttx/arch.h> +#include <nuttx/usb/usb.h> +#include <nuttx/usb/usbdev.h> +#include <nuttx/usb/usbdev_trace.h> + +#include <arch/irq.h> +#include <arch/board/board.h> + +#include "chip.h" +#include "up_arch.h" +#include "up_internal.h" + +#include "lpc214x_usbdev.h" +#include "lpc214x_pll.h" +#include "lpc214x_power.h" + +/******************************************************************************* + * 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 + +#define USB_SLOW_INT USBDEV_DEVINT_EPSLOW +#define USB_DEVSTATUS_INT USBDEV_DEVINT_DEVSTAT + +#ifdef CONFIG_LPC214X_USBDEV_EPFAST_INTERRUPT +# define USB_FAST_INT USBDEV_DEVINT_EPFAST +#else +# define USB_FAST_INT 0 +#endif + +/* Extremely detailed register debug that you would normally never want + * enabled. + */ + +#undef CONFIG_LPC214X_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_LPC214X_USBDEV_FRAME_INTERRUPT +# define USB_FRAME_INT USBDEV_DEVINT_FRAME +#else +# define USB_FRAME_INT 0 +#endif + +#ifdef CONFIG_DEBUG +# define USB_ERROR_INT USBDEV_DEVINT_EPRINT +#else +# define USB_ERROR_INT 0 +#endif + +/* Number of DMA descriptors */ + +#ifdef CONFIG_LPC214X_USBDEV_DMA +# error DMA SUPPORT NOT YET FULLY IMPLEMENTED +# ifndef CONFIG_LPC214X_USBDEV_NDMADESCRIPTORS +# define CONFIG_LPC214X_USBDEV_NDMADESCRIPTORS 8 +# elif CONFIG_LPC214X_USBDEV_NDMADESCRIPTORS > 30 +# define CONFIG_LPC214X_USBDEV_NDMADESCRIPTORS 30 +# endif +#endif + +/* Debug ***********************************************************************/ + +/* Trace error codes */ + +#define LPC214X_TRACEERR_ALLOCFAIL 0x0001 +#define LPC214X_TRACEERR_BADCLEARFEATURE 0x0002 +#define LPC214X_TRACEERR_BADDEVGETSTATUS 0x0003 +#define LPC214X_TRACEERR_BADEPNO 0x0004 +#define LPC214X_TRACEERR_BADEPGETSTATUS 0x0005 +#define LPC214X_TRACEERR_BADEPTYPE 0x0006 +#define LPC214X_TRACEERR_BADGETCONFIG 0x0007 +#define LPC214X_TRACEERR_BADGETSETDESC 0x0008 +#define LPC214X_TRACEERR_BADGETSTATUS 0x0009 +#define LPC214X_TRACEERR_BADSETADDRESS 0x000a +#define LPC214X_TRACEERR_BADSETCONFIG 0x000b +#define LPC214X_TRACEERR_BADSETFEATURE 0x000c +#define LPC214X_TRACEERR_BINDFAILED 0x000d +#define LPC214X_TRACEERR_DISPATCHSTALL 0x000e +#define LPC214X_TRACEERR_DMABUSY 0x000f +#define LPC214X_TRACEERR_DRIVER 0x0010 +#define LPC214X_TRACEERR_DRIVERREGISTERED 0x0011 +#define LPC214X_TRACEERR_EP0INSTALLED 0x0012 +#define LPC214X_TRACEERR_EP0OUTSTALLED 0x0013 +#define LPC214X_TRACEERR_EP0SETUPSTALLED 0x0014 +#define LPC214X_TRACEERR_EPINNULLPACKET 0x0015 +#define LPC214X_TRACEERR_EPOUTNULLPACKET 0x0016 +#define LPC214X_TRACEERR_EPREAD 0x0017 +#define LPC214X_TRACEERR_INVALIDCMD 0x0018 +#define LPC214X_TRACEERR_INVALIDCTRLREQ 0x0019 +#define LPC214X_TRACEERR_INVALIDPARMS 0x001a +#define LPC214X_TRACEERR_IRQREGISTRATION 0x001b +#define LPC214X_TRACEERR_NODMADESC 0x001c +#define LPC214X_TRACEERR_NOEP 0x001d +#define LPC214X_TRACEERR_NOTCONFIGURED 0x001e +#define LPC214X_TRACEERR_REQABORTED 0x001f + +/* Trace interrupt codes */ + +#define LPC214X_TRACEINTID_USB 0x0001 +#define LPC214X_TRACEINTID_CLEARFEATURE 0x0002 +#define LPC214X_TRACEINTID_CONNECTCHG 0x0003 +#define LPC214X_TRACEINTID_CONNECTED 0x0004 +#define LPC214X_TRACEINTID_DEVGETSTATUS 0x0005 +#define LPC214X_TRACEINTID_DEVRESET 0x0006 +#define LPC214X_TRACEINTID_DEVSTAT 0x0007 +#define LPC214X_TRACEINTID_DISCONNECTED 0x0008 +#define LPC214X_TRACEINTID_DISPATCH 0x0009 +#define LPC214X_TRACEINTID_EP0IN 0x000a +#define LPC214X_TRACEINTID_EP0OUT 0x000b +#define LPC214X_TRACEINTID_EP0SETUP 0x000c +#define LPC214X_TRACEINTID_EPDMA 0x000d +#define LPC214X_TRACEINTID_EPFAST 0x000e +#define LPC214X_TRACEINTID_EPGETSTATUS 0x000f +#define LPC214X_TRACEINTID_EPIN 0x0010 +#define LPC214X_TRACEINTID_EPINQEMPTY 0x0011 +#define LPC214X_TRACEINTID_EP0INSETADDRESS 0x0012 +#define LPC214X_TRACEINTID_EPOUT 0x0013 +#define LPC214X_TRACEINTID_EPOUTQEMPTY 0x0014 +#define LPC214X_TRACEINTID_EP0SETUPSETADDRESS 0x0015 +#define LPC214X_TRACEINTID_EPRINT 0x0016 +#define LPC214X_TRACEINTID_EPSLOW 0x0017 +#define LPC214X_TRACEINTID_FRAME 0x0018 +#define LPC214X_TRACEINTID_GETCONFIG 0x0019 +#define LPC214X_TRACEINTID_GETSETDESC 0x001a +#define LPC214X_TRACEINTID_GETSETIF 0x001b +#define LPC214X_TRACEINTID_GETSTATUS 0x001c +#define LPC214X_TRACEINTID_IFGETSTATUS 0x001d +#define LPC214X_TRACEINTID_SETCONFIG 0x001e +#define LPC214X_TRACEINTID_SETFEATURE 0x001f +#define LPC214X_TRACEINTID_SUSPENDCHG 0x0020 +#define LPC214X_TRACEINTID_SYNCHFRAME 0x0021 + +/* Hardware interface **********************************************************/ + +/* Macros for testing the device status response */ + +#define DEVSTATUS_CONNECT(s) (((s)&USBDEV_DEVSTATUS_CONNECT)!=0) +#define DEVSTATUS_CONNCHG(s) (((s)&USBDEV_DEVSTATUS_CONNCHG)!=0) +#define DEVSTATUS_SUSPEND(s) (((s)&USBDEV_DEVSTATUS_SUSPEND)!=0) +#define DEVSTATUS_SUSPCHG(s) (((s)&USBDEV_DEVSTATUS_SUSPCHG)!=0) +#define DEVSTATUS_RESET(s) (((s)&USBDEV_DEVSTATUS_RESET)!=0) + +/* If this bit is set in the lpc214x_epread response, it means that the + * recevied packet was overwritten by a later setup packet (ep0 only). + */ + +#define LPC214X_READOVERRUN_BIT (0x80000000) +#define LPC214X_READOVERRUN(s) (((s) & LPC214X_READOVERRUN_BIT) != 0) + +/* USB RAM ******************************************************************** + * + * UBS_UDCA is is list of 32 pointers to DMA desciptors located at the + * beginning of USB RAM. Each pointer points to a DMA descriptor with + * assocated DMA buffer. + */ + +#define USB_UDCA (uint32_t*)LPC214X_USBDEV_RAMBASE) +#define USB_USCASIZE (LPC214X_NPHYSENDPOINTS*sizeof(uint32_t)) + +/* Each descriptor must be aligned to a 128 address boundary */ + +#define USB_DDALIGNDOWN(a) ((a)&~0x7f) +#define USB_DDALIGNUP(a) USB_DDALIGNDOWN((a)+0x7f) + +#define USB_DDSIZE USB_DDALIGNDOWN((LPC214X_USBDEV_RAMSIZE-USB_USCASIZE)/CONFIG_LPC214X_USBDEV_NDMADESCRIPTORS) +#define USB_DDESC ((struct lpc214x_dmadesc_s*)(LPC214X_USBDEV_RAMBASE+USB_USCASIZE)) + +#ifdef CONFIG_USBDEV_ISOCHRONOUS +# define USB_DDESCSIZE (5*sizeof(uint32_t)) +#else +# define USB_DDESCSIZE (4*sizeof(uint32_t)) +#endif + +/* Endpoints ******************************************************************/ + +/* Number of endpoints */ + +#define LPC214X_NLOGENDPOINTS (16) /* ep0-15 */ +#define LPC214X_NPHYSENDPOINTS (32) /* x2 for IN and OUT */ + +/* Odd physical endpoint numbers are IN; even are out */ + +#define LPC214X_EPPHYIN(epphy) (((epphy)&1)!=0) +#define LPC214X_EPPHYOUT(epphy) (((epphy)&1)==0) + +#define LPC214X_EPPHYIN2LOG(epphy) (((uint8_t)(epphy)>>1)|USB_DIR_IN) +#define LPC214X_EPPHYOUT2LOG(epphy) (((uint8_t)(epphy)>>1)|USB_DIR_OUT) + +/* Each endpoint has somewhat different characteristics */ + +#define LPC214X_EPALLSET (0xffffffff) /* All endpoints */ +#define LPC214X_EPOUTSET (0x55555555) /* Even phy endpoint numbers are OUT EPs */ +#define LPC214X_EPINSET (0xaaaaaaaa) /* Odd endpoint numbers are IN EPs */ +#define LPC214X_EPCTRLSET (0x00000003) /* EP0 IN/OUT are control endpoints */ +#define LPC214X_EPINTRSET (0x0c30c30c) /* Interrupt endpoints */ +#define LPC214X_EPBULKSET (0xf0c30c30) /* Bulk endpoints */ +#define LPC214X_EPISOCSET (0x030c30c0) /* Isochronous endpoints */ +#define LPC214X_EPDBLBUFFER (0xf3cf3cf0) /* Double buffered endpoints */ + +#define LPC214X_EP0MAXPACKET (64) /* EP0 max packet size (1-64) */ +#define LPC214X_BULKMAXPACKET (64) /* Bulk endpoint max packet (8/16/32/64) */ +#define LPC214X_INTRMAXPACKET (64) /* Interrupt endpoint max packet (1 to 64) */ +#define LPC214X_ISOCMAXPACKET (512) /* Acutally 1..1023 */ + +/* EP0 status. EP0 transfers occur in a number of different contexts. A + * simple state machine is required to handle the various transfer complete + * interrupt responses. The following values are the various states: + */ + /*** INTERRUPT CAUSE ***/ +#define LPC214X_EP0REQUEST (0) /* Normal request handling */ +#define LPC214X_EP0STATUSIN (1) /* Status sent */ +#define LPC214X_EP0STATUSOUT (2) /* Status received */ +#define LPC214X_EP0SHORTWRITE (3) /* Short data sent with no request */ +#define LPC214X_EP0SHORTWRSENT (4) /* Short data write complete */ +#define LPC214X_EP0SETADDRESS (5) /* Set address received */ +#define LPC214X_EP0WRITEREQUEST (6) /* EP0 write request sent */ + +/* Request queue operations ****************************************************/ + +#define lpc214x_rqempty(ep) ((ep)->head == NULL) +#define lpc214x_rqpeek(ep) ((ep)->head) + +/******************************************************************************* + * Private Types + *******************************************************************************/ + +/* A container for a request so that the request make be retained in a list */ + +struct lpc214x_req_s +{ + struct usbdev_req_s req; /* Standard USB request */ + struct lpc214x_req_s *flink; /* Supports a singly linked list */ +}; + +/* This is the internal representation of an endpoint */ + +struct lpc214x_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 lpc214x_ep_s. + */ + + struct usbdev_ep_s ep; /* Standard endpoint structure */ + + /* LPC214X-specific fields */ + + struct lpc214x_usbdev_s *dev; /* Reference to private driver data */ + struct lpc214x_req_s *head; /* Request list for this endpoint */ + struct lpc214x_req_s *tail; + uint8_t epphy; /* Physical EP address */ + uint8_t stalled:1; /* 1: Endpoint is stalled */ + uint8_t halted:1; /* 1: Endpoint feature halted */ + uint8_t txbusy:1; /* 1: TX endpoint FIFO full */ + uint8_t txnullpkt:1; /* Null packet needed at end of transfer */ +}; + +/* This represents a DMA descriptor */ + +#ifdef CONFIG_LPC214X_USBDEV_DMA +struct lpc214x_dmadesc_s +{ + uint32_t nextdesc; /* Address of the next DMA descripto in RAM */ + uint32_t config; /* Misc. bit encoded configuration information */ + uint32_t start; /* DMA start address */ + uint32_t status; /* Misc. bit encoded status inforamation */ +#ifdef CONFIG_USBDEV_ISOCHRONOUS + uint32_t size; /* Isochronous packet size address */ +#endif + uint8_t buffer[USB_DDSIZE-USB_DDESCSIZE]; +}; +#endif + +/* This structure retains the state of the USB device controller */ + +struct lpc214x_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 structlpc214x_usbdev_s. + */ + + struct usbdev_s usbdev; + + /* The bound device class driver */ + + struct usbdevclass_driver_s *driver; + + /* LPC214X-specific fields */ + + uint8_t devstatus; /* Last response to device status command */ + uint8_t ep0state; /* State of certain EP0 operations */ + 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 rxpending:1; /* 1: RX pending */ + uint32_t softprio; /* Bitset of high priority interrupts */ + uint32_t epavail; /* Bitset of available endpoints */ +#ifdef CONFIG_LPC214X_USBDEV_FRAME_INTERRUPT + uint32_t sof; /* Last start-of-frame */ +#endif + + /* Allocated DMA descriptor */ + +#ifdef CONFIG_LPC214X_USBDEV_DMA + struct lpc214x_dmadesc_s *dmadesc; +#endif + + /* The endpoint list */ + + struct lpc214x_ep_s eplist[LPC214X_NPHYSENDPOINTS]; +}; + +/******************************************************************************* + * Private Function Prototypes + *******************************************************************************/ + +/* Register operations ********************************************************/ + +#if defined(CONFIG_LPC214X_USBDEV_REGDEBUG) && defined(CONFIG_DEBUG) +static uint32_t lpc214x_getreg(uint32_t addr); +static void lpc214x_putreg(uint32_t val, uint32_t addr); +#else +# define lpc214x_getreg(addr) getreg32(addr) +# define lpc214x_putreg(val,addr) putreg32(val,addr) +#endif + +/* Command operations **********************************************************/ + +static uint32_t lpc214x_usbcmd(uint16_t cmd, uint8_t data); + +/* Request queue operations ****************************************************/ + +static FAR struct lpc214x_req_s *lpc214x_rqdequeue(FAR struct lpc214x_ep_s *privep); +static void lpc214x_rqenqueue(FAR struct lpc214x_ep_s *privep, + FAR struct lpc214x_req_s *req); + +/* Low level data transfers and request operations *****************************/ + +static void lpc214x_epwrite(uint8_t epphy, const uint8_t *data, uint32_t nbytes); +static int lpc214x_epread(uint8_t epphy, uint8_t *data, uint32_t nbytes); +static inline void lpc214x_abortrequest(struct lpc214x_ep_s *privep, + struct lpc214x_req_s *privreq, int16_t result); +static void lpc214x_reqcomplete(struct lpc214x_ep_s *privep, int16_t result); +static int lpc214x_wrrequest(struct lpc214x_ep_s *privep); +static int lpc214x_rdrequest(struct lpc214x_ep_s *privep); +static void lpc214x_cancelrequests(struct lpc214x_ep_s *privep); + +/* Interrupt handling **********************************************************/ + +static struct lpc214x_ep_s *lpc214x_epfindbyaddr(struct lpc214x_usbdev_s *priv, + uint16_t eplog); +static void lpc214x_eprealize(struct lpc214x_ep_s *privep, bool prio, + uint32_t packetsize); +static uint8_t lpc214x_epclrinterrupt(uint8_t epphy); +static inline void lpc214x_ep0configure(struct lpc214x_usbdev_s *priv); +#ifdef CONFIG_LPC214X_USBDEV_DMA +static inline void lpc214x_dmareset(uint32_t enable); +#endif +static void lpc214x_usbreset(struct lpc214x_usbdev_s *priv); +static void lpc214x_dispatchrequest(struct lpc214x_usbdev_s *priv, + const struct usb_ctrlreq_s *ctrl); +static inline void lpc214x_ep0setup(struct lpc214x_usbdev_s *priv); +static inline void lpc214x_ep0dataoutinterrupt(struct lpc214x_usbdev_s *priv); +static inline void lpc214x_ep0dataininterrupt(struct lpc214x_usbdev_s *priv); +static int lpc214x_usbinterrupt(int irq, FAR void *context); + +#ifdef CONFIG_LPC214X_USBDEV_DMA +static int lpc214x_dmasetup(struct lpc214x_usbdev_s *priv, uint8_t epphy, + uint32_t epmaxsize, uint32_t nbytes, uint32_t *isocpacket, + bool isochronous); +static void lpc214x_dmarestart(uint8_t epphy, uint32_t descndx); +static void lpc214x_dmadisable(uint8_t epphy); +#endif /* CONFIG_LPC214X_USBDEV_DMA */ + +/* Endpoint operations *********************************************************/ + +static int lpc214x_epconfigure(FAR struct usbdev_ep_s *ep, + const struct usb_epdesc_s *desc, bool last); +static int lpc214x_epdisable(FAR struct usbdev_ep_s *ep); +static FAR struct usbdev_req_s *lpc214x_epallocreq(FAR struct usbdev_ep_s *ep); +static void lpc214x_epfreereq(FAR struct usbdev_ep_s *ep, + FAR struct usbdev_req_s *); +#ifdef CONFIG_USBDEV_DMA +static FAR void *lpc214x_epallocbuffer(FAR struct usbdev_ep_s *ep, + uint16_t nbytes); +static void lpc214x_epfreebuffer(FAR struct usbdev_ep_s *ep, void *buf); +#endif +static int lpc214x_epsubmit(FAR struct usbdev_ep_s *ep, + struct usbdev_req_s *req); +static int lpc214x_epcancel(FAR struct usbdev_ep_s *ep, + struct usbdev_req_s *req); +static int lpc214x_epstall(FAR struct usbdev_ep_s *ep, bool resume); + +/* USB device controller operations ********************************************/ + +static FAR struct usbdev_ep_s *lcp214x_allocep(FAR struct usbdev_s *dev, + uint8_t epno, bool in, uint8_t eptype); +static void lpc214x_freeep(FAR struct usbdev_s *dev, FAR struct usbdev_ep_s *ep); +static int lpc214x_getframe(struct usbdev_s *dev); +static int lpc214x_wakeup(struct usbdev_s *dev); +static int lpc214x_selfpowered(struct usbdev_s *dev, bool selfpowered); +static int lpc214x_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 lpc214x_usbdev_s g_usbdev; + +static const struct usbdev_epops_s g_epops = +{ + .configure = lpc214x_epconfigure, + .disable = lpc214x_epdisable, + .allocreq = lpc214x_epallocreq, + .freereq = lpc214x_epfreereq, +#ifdef CONFIG_USBDEV_DMA + .allocbuffer = lpc214x_epallocbuffer, + .freebuffer = lpc214x_epfreebuffer, +#endif + .submit = lpc214x_epsubmit, + .cancel = lpc214x_epcancel, + .stall = lpc214x_epstall, +}; + +static const struct usbdev_ops_s g_devops = +{ + .allocep = lcp214x_allocep, + .freeep = lpc214x_freeep, + .getframe = lpc214x_getframe, + .wakeup = lpc214x_wakeup, + .selfpowered = lpc214x_selfpowered, + .pullup = lpc214x_pullup, +}; + +/******************************************************************************* + * Public Data + *******************************************************************************/ + +/******************************************************************************* + * Private Functions + *******************************************************************************/ + +/******************************************************************************* + * Name: lpc214x_getreg + * + * Description: + * Get the contents of an LPC214x register + * + *******************************************************************************/ + +#if defined(CONFIG_LPC214X_USBDEV_REGDEBUG) && defined(CONFIG_DEBUG) +static uint32_t lpc214x_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: lpc214x_putreg + * + * Description: + * Set the contents of an LPC214x register to a value + * + *******************************************************************************/ + +#if defined(CONFIG_LPC214X_USBDEV_REGDEBUG) && defined(CONFIG_DEBUG) +static void lpc214x_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: lpc214x_usbcmd + * + * Description: + * Transmit commands to the USB engine + * + *******************************************************************************/ + +static uint32_t lpc214x_usbcmd(uint16_t cmd, uint8_t data) +{ + irqstate_t flags; + uint32_t tmp = 0; + + /* Disable interrupt and clear CDFULL and CCEMPTY interrupt status */ + + flags = irqsave(); + lpc214x_putreg(USBDEV_DEVINT_CDFULL|USBDEV_DEVINT_CCEMTY, LPC214X_USBDEV_DEVINTCLR); + + /* Load command + WR in command code register */ + + lpc214x_putreg(((cmd & 0xff) << 16) + CMD_USB_CMDWR, LPC214X_USBDEV_CMDCODE); + + /* Wait until the command register is empty (CCEMPTY != 0, command is accepted) */ + + while ((lpc214x_getreg(LPC214X_USBDEV_DEVINTST) & USBDEV_DEVINT_CCEMTY) == 0); + + /* Clear command register empty (CCEMPTY) interrupt */ + + lpc214x_putreg(USBDEV_DEVINT_CCEMTY, LPC214X_USBDEV_DEVINTCLR); + + /* Determine next phase of the command */ + + switch (cmd) + { + /* Write operations (1 byte of data) */ + + case CMD_USB_DEV_SETADDRESS: + case CMD_USB_DEV_CONFIG: + case CMD_USB_DEV_SETMODE: + case CMD_USB_DEV_SETSTATUS: + { + /* Send data + WR and wait for CCEMPTY */ + + lpc214x_putreg((data << 16) + CMD_USB_DATAWR, LPC214X_USBDEV_CMDCODE); + while ((lpc214x_getreg(LPC214X_USBDEV_DEVINTST) & USBDEV_DEVINT_CCEMTY) == 0); + } + break; + + /* 16 bit read operations */ + + case CMD_USB_DEV_READFRAMENO: + case CMD_USB_DEV_READTESTREG: + { + /* Send command code + RD and wait for CDFULL */ + + lpc214x_putreg((cmd << 16) + CMD_USB_DATARD, LPC214X_USBDEV_CMDCODE); + while ((lpc214x_getreg(LPC214X_USBDEV_DEVINTST) & USBDEV_DEVINT_CDFULL) == 0); + + /* Clear CDFULL and read LS data */ + + lpc214x_putreg(USBDEV_DEVINT_CDFULL, LPC214X_USBDEV_DEVINTCLR); + tmp = lpc214x_getreg(LPC214X_USBDEV_CMDDATA); + + /* Send command code + RD and wait for CDFULL */ + + lpc214x_putreg((cmd << 16) + CMD_USB_DATARD, LPC214X_USBDEV_CMDCODE); + while ((lpc214x_getreg(LPC214X_USBDEV_DEVINTST) & USBDEV_DEVINT_CDFULL) == 0); + + /* Read MS data */ + + tmp |= lpc214x_getreg(LPC214X_USBDEV_CMDDATA) << 8; + } + break; + + /* 8-bit read operations */ + + case CMD_USB_DEV_GETSTATUS: + case CMD_USB_DEV_GETERRORCODE: + case CMD_USB_DEV_READERRORSTATUS: + case CMD_USB_EP_CLRBUFFER: + { + /* Send command code + RD and wait for CDFULL */ + + lpc214x_putreg((cmd << 16) + CMD_USB_DATARD, LPC214X_USBDEV_CMDCODE); + while ((lpc214x_getreg(LPC214X_USBDEV_DEVINTST) & USBDEV_DEVINT_CDFULL) == 0); + + /* Read data */ + + tmp = lpc214x_getreg(LPC214X_USBDEV_CMDDATA); + } + break; + + /* No data transfer */ + + case CMD_USB_EP_VALIDATEBUFFER: + break; + + default: + switch (cmd & 0x1e0) + { + case CMD_USB_EP_SELECT: + case CMD_USB_EP_SELECTCLEAR: + { + /* Send command code + RD and wait for CDFULL */ + + lpc214x_putreg((cmd << 16) + CMD_USB_DATARD, LPC214X_USBDEV_CMDCODE); + while ((lpc214x_getreg(LPC214X_USBDEV_DEVINTST) & USBDEV_DEVINT_CDFULL) == 0); + + /* Read data */ + + tmp = lpc214x_getreg(LPC214X_USBDEV_CMDDATA); + } + break; + + case CMD_USB_EP_SETSTATUS: + { + /* Send data + RD and wait for CCEMPTY */ + + lpc214x_putreg((data << 16) + CMD_USB_DATAWR, LPC214X_USBDEV_CMDCODE); + while ((lpc214x_getreg(LPC214X_USBDEV_DEVINTST) & USBDEV_DEVINT_CCEMTY) == 0); + } + break; + + default: + usbtrace(TRACE_DEVERROR(LPC214X_TRACEERR_INVALIDCMD), 0); + break; + } + break; + } + + /* Restore the interrupt flags */ + + irqrestore(flags); + return tmp; +} + +/******************************************************************************* + * Name: lpc214x_rqdequeue + * + * Description: + * Remove a request from an endpoint request queue + * + *******************************************************************************/ + +static FAR struct lpc214x_req_s *lpc214x_rqdequeue(FAR struct lpc214x_ep_s *privep) +{ + FAR struct lpc214x_req_s *ret = privep->head; + + if (ret) + { + privep->head = ret->flink; + if (!privep->head) + { + privep->tail = NULL; + } + + ret->flink = NULL; + } + + return ret; +} + +/******************************************************************************* + * Name: lpc214x_rqenqueue + * + * Description: + * Add a request from an endpoint request queue + * + *******************************************************************************/ + +static void lpc214x_rqenqueue(FAR struct lpc214x_ep_s *privep, + FAR struct lpc214x_req_s *req) +{ + req->flink = NULL; + if (!privep->head) + { + privep->head = req; + privep->tail = req; + } + else + { + privep->tail->flink = req; + privep->tail = req; + } +} + +/******************************************************************************* + * Name: lpc214x_epwrite + * + * Description: + * Endpoint write (IN) + * + *******************************************************************************/ + +static void lpc214x_epwrite(uint8_t epphy, const uint8_t *data, uint32_t nbytes) +{ + uint32_t value; + bool aligned = (((uint32_t)data & 3) == 0); + + /* Set the write enable bit for this physical EP address. Bits 2-5 are + * the logical endpoint number (0-15) + */ + + lpc214x_putreg(((epphy << 1) & LPC214X_USBCTRL_EPMASK) | LPC214X_USBCTRL_WREN, + LPC214X_USBDEV_CTRL); + + /* Set the transmit packet length (nbytes must be less than 2048) */ + + lpc214x_putreg(nbytes, LPC214X_USBDEV_TXPLEN); + + /* Transfer the packet data */ + + do + { + /* Zero length packets are a special case */ + + if (nbytes) + { + if (aligned) + { + value = *(uint32_t*)data; + } + else + { + value = (uint32_t)data[0] | ((uint32_t)data[1] << 8) | + ((uint32_t)data[2] << 16) | ((uint32_t)data[3] << 24); + } + + lpc214x_putreg(value, LPC214X_USBDEV_TXDATA); + data += 4; + } + else + { + /* Zero length packet */ + + lpc214x_putreg(0, LPC214X_USBDEV_TXDATA); + } + } + while ((lpc214x_getreg(LPC214X_USBDEV_CTRL) & LPC214X_USBCTRL_WREN) != 0); + + /* Done */ + + lpc214x_putreg(0, LPC214X_USBDEV_CTRL); + (void)lpc214x_usbcmd(CMD_USB_EP_SELECT | epphy, 0); + (void)lpc214x_usbcmd(CMD_USB_EP_VALIDATEBUFFER, 0); +} + +/******************************************************************************* + * Name: lpc214x_epread + * + * Description: + * Endpoint read (OUT) + * + *******************************************************************************/ + +static int lpc214x_epread(uint8_t epphy, uint8_t *data, uint32_t nbytes) +{ + uint32_t pktlen; + uint32_t result; + uint32_t value; + uint8_t aligned = 0; + + /* If data is NULL, then we are being asked to read but discard the data. + * For most cases, the resulting buffer will be aligned and we will be + * able to do faster 32-bit transfers. + */ + + if (data) + { + if (((uint32_t)data & 3) == 0) + { + aligned = 1; + } + else + { + aligned = 2; + } + } + + /* Set the read enable bit for this physical EP address. Bits 2-5 are + * the logical endpoint number (0-15). + */ + + lpc214x_putreg(((epphy << 1) & LPC214X_USBCTRL_EPMASK) | LPC214X_USBCTRL_RDEN, + LPC214X_USBDEV_CTRL); + + /* Wait for packet buffer ready for reading */ + + while ((lpc214x_getreg(LPC214X_USBDEV_RXPLEN) & USBDEV_RXPLEN_PKTRDY) == 0); + + /* Get the number of bytes of data to be read */ + + pktlen = lpc214x_getreg(LPC214X_USBDEV_RXPLEN) & USBDEV_RXPLEN_PKTLENGTH; + + /* Read data from input buffer while read data is valid (DV) */ + + while ((lpc214x_getreg(LPC214X_USBDEV_RXPLEN) & USBDEV_RXPLEN_DV) != 0) + { + value = lpc214x_getreg(LPC214X_USBDEV_RXDATA); + if (aligned == 1) + { + *(uint32_t*)data = value; + data += 4; + } + else if (aligned == 2) + { + *data++ = (uint8_t)value; + *data++ = (uint8_t)(value >> 8); + *data++ = (uint8_t)(value >> 16); + *data++ = (uint8_t)(value >> 24); + } + } + + /* Done */ + + lpc214x_putreg(0, LPC214X_USBDEV_CTRL); + (void)lpc214x_usbcmd(CMD_USB_EP_SELECT | epphy, 0); + result = lpc214x_usbcmd(CMD_USB_EP_CLRBUFFER, 0); + + /* The packet overrun bit in the clear buffer response is applicable only + * on EP0 transfers. If set it means that the recevied packet was overwritten + * by a later setup packet. + */ + + if (epphy == LPC214X_EP0_OUT && (result & CMD_USB_CLRBUFFER_PO) != 0) + { + /* Pass this information in bit 31 */ + + pktlen |= LPC214X_READOVERRUN_BIT; + } + return pktlen; +} + +/******************************************************************************* + * Name: lpc214x_abortrequest + * + * Description: + * Discard a request + * + *******************************************************************************/ + +static inline void lpc214x_abortrequest(struct lpc214x_ep_s *privep, + struct lpc214x_req_s *privreq, + int16_t result) +{ + usbtrace(TRACE_DEVERROR(LPC214X_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: lpc214x_reqcomplete + * + * Description: + * Handle termination of the request at the head of the endpoint request queue. + * + *******************************************************************************/ + +static void lpc214x_reqcomplete(struct lpc214x_ep_s *privep, int16_t result) +{ + struct lpc214x_req_s *privreq; + int stalled = privep->stalled; + irqstate_t flags; + + /* Remove the completed request at the head of the endpoint request list */ + + flags = irqsave(); + privreq = lpc214x_rqdequeue(privep); + irqrestore(flags); + + if (privreq) + { + /* If endpoint 0, temporarily reflect the state of protocol stalled + * in the callback. + */ + + if (privep->epphy == LPC214X_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->flink = NULL; + privreq->req.callback(&privep->ep, &privreq->req); + + /* Restore the stalled indication */ + + privep->stalled = stalled; + } +} + +/******************************************************************************* + * Name: lpc214x_wrrequest + * + * Description: + * Send from the next queued write request + * + *******************************************************************************/ + +static int lpc214x_wrrequest(struct lpc214x_ep_s *privep) +{ + struct lpc214x_req_s *privreq; + uint8_t *buf; + int nbytes; + int bytesleft; + + /* Check the request from the head of the endpoint request queue */ + + privreq = lpc214x_rqpeek(privep); + if (!privreq) + { + usbtrace(TRACE_INTDECODE(LPC214X_TRACEINTID_EPINQEMPTY), 0); + return OK; + } + + ullvdbg("epphy=%d req=%p: len=%d xfrd=%d nullpkt=%d\n", + privep->epphy, privreq, privreq->req.len, privreq->req.xfrd, privep->txnullpkt); + + /* Ignore any attempt to send a zero length packet on anything but EP0IN */ + + if (privreq->req.len == 0) + { + if (privep->epphy == LPC214X_EP0_IN) + { + lpc214x_epwrite(LPC214X_EP0_IN, NULL, 0); + } + else + { + usbtrace(TRACE_DEVERROR(LPC214X_TRACEERR_EPINNULLPACKET), 0); + } + + /* In any event, the request is complete */ + + lpc214x_reqcomplete(privep, OK); + return OK; + } + + /* Otherwise send the data in the packet (in the DMA on case, we + * may be resuming transfer already in progress. + */ +#warning REVISIT... If the EP supports double buffering, then we can do better + + /* Get the number of bytes left to be sent in the packet */ + + bytesleft = privreq->req.len - privreq->req.xfrd; + + /* Send the next packet if (1) there are more bytes to be sent, or + * (2) the last packet sent was exactly maxpacketsize (bytesleft == 0) + */ + + usbtrace(TRACE_WRITE(privep->epphy), privreq->req.xfrd); + if (bytesleft > 0 || privep->txnullpkt) + { + /* Indicate that there is data in the TX FIFO. This will be cleared + * when the EPIN interrupt is received + */ + + privep->txbusy = 1; + + /* Try to send maxpacketsize -- unless we don't have that many + * bytes to send. + */ + + privep->txnullpkt = 0; + if (bytesleft > privep->ep.maxpacket) + { + nbytes = privep->ep.maxpacket; + } + else + { + nbytes = bytesleft; + if ((privreq->req.flags & USBDEV_REQFLAGS_NULLPKT) != 0) + { + privep->txnullpkt = (bytesleft == privep->ep.maxpacket); + } + } + + /* Send the largest number of bytes that we can in this packet */ + + buf = privreq->req.buf + privreq->req.xfrd; + lpc214x_epwrite(privep->epphy, buf, nbytes); + + /* Update for the next time through the loop */ + + privreq->req.xfrd += nbytes; + } + + /* If all of the bytes were sent (including any final null packet) + * then we are finished with the transfer + */ + + if (privreq->req.xfrd >= privreq->req.len && !privep->txnullpkt) + { + usbtrace(TRACE_COMPLETE(privep->epphy), privreq->req.xfrd); + privep->txnullpkt = 0; + lpc214x_reqcomplete(privep, OK); + } + + return OK; +} + +/******************************************************************************* + * Name: lpc214x_rdrequest + * + * Description: + * Receive to the next queued read request + * + *******************************************************************************/ + +static int lpc214x_rdrequest(struct lpc214x_ep_s *privep) +{ + struct lpc214x_req_s *privreq; + uint8_t *buf; + int nbytesread; + + /* Check the request from the head of the endpoint request queue */ + + privreq = lpc214x_rqpeek(privep); + if (!privreq) + { + usbtrace(TRACE_INTDECODE(LPC214X_TRACEINTID_EPOUTQEMPTY), 0); + return OK; + } + + ullvdbg("len=%d xfrd=%d nullpkt=%d\n", + privreq->req.len, privreq->req.xfrd, privep->txnullpkt); + + /* Ignore any attempt to receive a zero length packet */ + + if (privreq->req.len == 0) + { + usbtrace(TRACE_DEVERROR(LPC214X_TRACEERR_EPOUTNULLPACKET), 0); + lpc214x_reqcomplete(privep, OK); + return OK; + } + + usbtrace(TRACE_READ(privep->epphy), privreq->req.xfrd); + + /* Receive the next packet */ + + buf = privreq->req.buf + privreq->req.xfrd; + nbytesread = lpc214x_epread(privep->epphy, buf, privep->ep.maxpacket); + if (nbytesread < 0) + { + usbtrace(TRACE_DEVERROR(LPC214X_TRACEERR_EPREAD), nbytesread); + return ERROR; + } + + /* If the receive buffer is full or if the last packet was not full + * then we are finished with the transfer. + */ + + privreq->req.xfrd += nbytesread; + if (privreq->req.xfrd >= privreq->req.len || nbytesread < privep->ep.maxpacket) + { + usbtrace(TRACE_COMPLETE(privep->epphy), privreq->req.xfrd); + lpc214x_reqcomplete(privep, OK); + } + + return OK; +} + +/******************************************************************************* + * Name: lpc214x_cancelrequests + * + * Description: + * Cancel all pending requests for an endpoint + * + *******************************************************************************/ + +static void lpc214x_cancelrequests(struct lpc214x_ep_s *privep) +{ + while (!lpc214x_rqempty(privep)) + { + usbtrace(TRACE_COMPLETE(privep->epphy), + (lpc214x_rqpeek(privep))->req.xfrd); + lpc214x_reqcomplete(privep, -ESHUTDOWN); + } +} + +/******************************************************************************* + * Name: lpc214x_epfindbyaddr + * + * Description: + * Find the physical endpoint structure corresponding to a logic endpoint + * address + * + *******************************************************************************/ + +static struct lpc214x_ep_s *lpc214x_epfindbyaddr(struct lpc214x_usbdev_s *priv, + uint16_t eplog) +{ + struct lpc214x_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 < LPC214X_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: lpc214x_eprealize + * + * Description: + * Enable or disable an endpoint + * + *******************************************************************************/ + +static void lpc214x_eprealize(struct lpc214x_ep_s *privep, bool prio, uint32_t packetsize) +{ + struct lpc214x_usbdev_s *priv = privep->dev; + uint32_t mask; + uint32_t reg; + + /* Initialize endpoint software priority */ + + mask = 1 << privep->epphy; + if (prio) + { + priv->softprio = priv->softprio | mask; + } + else + { + priv->softprio = priv->softprio & ~mask; + } + + /* Clear realize interrupt bit */ + + lpc214x_putreg(USBDEV_DEVINT_EPRLZED, LPC214X_USBDEV_DEVINTCLR); + + /* Realize the endpoint */ + + reg = lpc214x_getreg(LPC214X_USBDEV_REEP); + reg |= (1 << privep->epphy); + lpc214x_putreg(reg, LPC214X_USBDEV_REEP); + + /* Set endpoint maximum packet size */ + + lpc214x_putreg(privep->epphy, LPC214X_USBDEV_EPIND); + lpc214x_putreg(packetsize, LPC214X_USBDEV_MAXPSIZE); + + /* Wait for Realize complete */ + + while ((lpc214x_getreg(LPC214X_USBDEV_DEVINTST) & USBDEV_DEVINT_EPRLZED) == 0); + + /* Clear realize interrupt bit */ + + lpc214x_putreg(USBDEV_DEVINT_EPRLZED,LPC214X_USBDEV_DEVINTCLR); +} + +/******************************************************************************* + * Name: lpc214x_epclrinterrupt + * + * Description: + * Clear the EP interrupt flag and return the current EP status + * + *******************************************************************************/ + +static uint8_t lpc214x_epclrinterrupt(uint8_t epphy) +{ + /* Clear the endpoint interrupt */ + + lpc214x_putreg(1 << epphy, LPC214X_USBDEV_EPINTCLR); + + /* Wait for data in the command data register */ + + while ((lpc214x_getreg(LPC214X_USBDEV_DEVINTST) & USBDEV_DEVINT_CDFULL) == 0); + + /* Return the value of the command data register */ + + return lpc214x_getreg(LPC214X_USBDEV_CMDDATA); +} + +/******************************************************************************* + * Name: lpc214x_ep0configure + * + * Description: + * Configure endpoint 0 + * + *******************************************************************************/ + +static inline void lpc214x_ep0configure(struct lpc214x_usbdev_s *priv) +{ + uint32_t inten; + + /* EndPoint 0 initialization */ + + lpc214x_eprealize(&priv->eplist[LPC214X_CTRLEP_OUT], 0, CONFIG_USBDEV_EP0_MAXSIZE); + lpc214x_eprealize(&priv->eplist[LPC214X_CTRLEP_IN], 1, CONFIG_USBDEV_EP0_MAXSIZE); + + /* Enable EP0 interrupts (not DMA) */ + + inten = lpc214x_getreg(LPC214X_USBDEV_EPINTEN); + inten |= 3; /* EP0 Rx and Tx */ + lpc214x_putreg(inten, LPC214X_USBDEV_EPINTEN); +} + +/******************************************************************************* + * Name: lpc214x_dmareset + * + * Description: Reset USB DMA + * + *******************************************************************************/ + +#ifdef CONFIG_LPC214X_USBDEV_DMA +static inline void lpc214x_dmareset(uint32_t enable) +{ + int i; + + /* Disable All DMA interrupts */ + + lpc214x_putreg(0, LPC214X_USBDEV_DMAINTEN); + + /* DMA Disable */ + + lpc214x_putreg(0xffffffff, LPC214X_USBDEV_EPDMADIS); + + /* DMA Request clear */ + + putreq32(0xffffffff, LPC214X_USBDEV_DMARCLR); + + /* End of Transfer Interrupt Clear */ + + putreq32(0xffffffff, LPC214X_USBDEV_EOTINTCLR); + + /* New DD Request Interrupt Clear */ + + putreq32(0xffffffff, LPC214X_USBDEV_NDDRINTCLR); + + /* System Error Interrupt Clear */ + + putreq32(0xffffffff, LPC214X_USBDEV_SYSERRINTCLR); + + /* Nullify all pointers in the UDCA */ + + for (i = 0; i < LPC214X_NPHYSENDPOINTS; ++i) + { + USB_UDCA[i] = NULL; + } + + /* Set USB UDCA Head register */ + + lpc214x_putreg((uint32_t)USB_UDCA, LPC214X_USBDEV_UDCAH); + + /* Invalidate all DMA descriptors */ + + for (i = 0; i < CONFIG_LPC214X_USBDEV_NDMADESCRIPTORS; ++i) + { + memset(&USB_DDESC[i], 0, USB_DDESCSIZE); + } + + /* Enable DMA interrupts */ + + lpc214x_putreg(enable, LPC214X_USBDEV_DMAINTEN); +} +#endif + +/******************************************************************************* + * Name: lpc214x_usbreset + * + * Description: + * Reset Usb engine + * + *******************************************************************************/ + +static void lpc214x_usbreset(struct lpc214x_usbdev_s *priv) +{ + int epphy; + + /* Disable all endpoint interrupts */ + + lpc214x_putreg(0, LPC214X_USBDEV_EPINTEN); + + /* Frame is Hp interrupt */ + + lpc214x_putreg(1, LPC214X_USBDEV_DEVINTPRI); + + /* Clear all pending interrupts */ + + lpc214x_putreg(0xffffffff, LPC214X_USBDEV_EPINTCLR); + lpc214x_putreg(0xffffffff, LPC214X_USBDEV_DEVINTCLR); + + /* Periperhal address is needed */ + + priv->paddrset = 0; + + /* Reset endpoints */ + + for (epphy = 0; epphy < LPC214X_NPHYSENDPOINTS; epphy++) + { + struct lpc214x_ep_s *privep = &priv->eplist[epphy]; + + lpc214x_cancelrequests(privep); + + /* 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); + } + + /* Endpoints not yet configured */ + + lpc214x_usbcmd(CMD_USB_DEV_CONFIG, 0); + + /* EndPoint 0 initialization */ + + lpc214x_ep0configure(priv); + + /* Enable End_of_Transfer_Interrupt and System_Error_Interrupt USB DMA + * interrupts + */ + +#ifdef CONFIG_LPC214X_USBDEV_DMA + lpc214x_dmareset(CONFIG_LPC214X_USBDEV_DMAINTMASK); +#endif + + /* Enable Device interrupts */ + + lpc214x_putreg(USB_SLOW_INT|USB_DEVSTATUS_INT|USB_FAST_INT|USB_FRAME_INT|USB_ERROR_INT, + LPC214X_USBDEV_DEVINTEN); +} + +/******************************************************************************* + * Name: lpc214x_dispatchrequest + * + * Description: + * Provide unhandled setup actions to the class driver. This is logically part + * of the USB interrupt handler. + * + *******************************************************************************/ + +static void lpc214x_dispatchrequest(struct lpc214x_usbdev_s *priv, + const struct usb_ctrlreq_s *ctrl) +{ + int ret; + + usbtrace(TRACE_INTDECODE(LPC214X_TRACEINTID_DISPATCH), 0); + if (priv && 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(LPC214X_TRACEERR_DISPATCHSTALL), 0); + priv->stalled = 1; + } + } +} + +/******************************************************************************* + * Name: lpc214x_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 lpc214x_ep0setup(struct lpc214x_usbdev_s *priv) +{ + struct lpc214x_ep_s *ep0 = &priv->eplist[LPC214X_EP0_OUT]; + struct lpc214x_ep_s *privep; + struct lpc214x_req_s *privreq = lpc214x_rqpeek(ep0); + struct usb_ctrlreq_s ctrl; + uint16_t value; + uint16_t index; + uint16_t len; + uint8_t response[2]; + int ret; + + /* Starting a control request? */ + + if (priv->usbdev.speed == USB_SPEED_UNKNOWN) + { + priv->usbdev.speed = USB_SPEED_FULL; + lpc214x_usbcmd(CMD_USB_DEV_CONFIG, 1); + } + + /* Terminate any pending requests */ + + while (!lpc214x_rqempty(ep0)) + { + int16_t result = OK; + if (privreq->req.xfrd != privreq->req.len) + { + result = -EPROTO; + } + + usbtrace(TRACE_COMPLETE(ep0->epphy), privreq->req.xfrd); + lpc214x_reqcomplete(ep0, result); + } + + /* Assume NOT stalled */ + + ep0->stalled = 0; + priv->stalled = 0; + + /* Read EP0 data */ + + ret = lpc214x_epread(LPC214X_EP0_OUT, (uint8_t*)&ctrl, USB_SIZEOF_CTRLREQ); + if (ret <= 0) + { + return; + } + + /* 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) + { + lpc214x_dispatchrequest(priv, &ctrl); + return; + } + + /* 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(LPC214X_TRACEINTID_GETSTATUS), 0); + if (!priv->paddrset || len != 2 || + (ctrl.type & USB_REQ_DIR_IN) == 0 || value != 0) + { + priv->stalled = 1; + } + else + { + switch (ctrl.type & USB_REQ_RECIPIENT_MASK) + { + case USB_REQ_RECIPIENT_ENDPOINT: + { + usbtrace(TRACE_INTDECODE(LPC214X_TRACEINTID_EPGETSTATUS), 0); + privep = lpc214x_epfindbyaddr(priv, index); + if (!privep) + { + usbtrace(TRACE_DEVERROR(LPC214X_TRACEERR_BADEPGETSTATUS), 0); + priv->stalled = 1; + } + else + { + if ((lpc214x_usbcmd(CMD_USB_EP_SELECT|privep->epphy, 0) & CMD_USB_EPSELECT_ST) != 0) + { + response[0] = 1; /* Stalled */ + } + else + { + response[0] = 0; /* Not stalled */ + } + response[1] = 0; + lpc214x_epwrite(LPC214X_EP0_IN, response, 2); + priv->ep0state = LPC214X_EP0SHORTWRITE; + } + } + break; + + case USB_REQ_RECIPIENT_DEVICE: + { + if (index == 0) + { + usbtrace(TRACE_INTDECODE(LPC214X_TRACEINTID_DEVGETSTATUS), 0); + + /* Features: Remote Wakeup=YES; selfpowered=? */ + + response[0] = (priv->selfpowered << USB_FEATURE_SELFPOWERED) | + (1 << USB_FEATURE_REMOTEWAKEUP); + response[1] = 0; + lpc214x_epwrite(LPC214X_EP0_IN, response, 2); + priv->ep0state = LPC214X_EP0SHORTWRITE; + } + else + { + usbtrace(TRACE_DEVERROR(LPC214X_TRACEERR_BADDEVGETSTATUS), 0); + priv->stalled = 1; + } + } + break; + + case USB_REQ_RECIPIENT_INTERFACE: + { + usbtrace(TRACE_INTDECODE(LPC214X_TRACEINTID_IFGETSTATUS), 0); + response[0] = 0; + response[1] = 0; + lpc214x_epwrite(LPC214X_EP0_IN, response, 2); + priv->ep0state = LPC214X_EP0SHORTWRITE; + } + break; + + default: + { + usbtrace(TRACE_DEVERROR(LPC214X_TRACEERR_BADGETSTATUS), 0); + priv->stalled = 1; + } + 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(LPC214X_TRACEINTID_CLEARFEATURE), 0); + if ((ctrl.type & USB_REQ_RECIPIENT_MASK) != USB_REQ_RECIPIENT_ENDPOINT) + { + lpc214x_dispatchrequest(priv, &ctrl); + } + else if (priv->paddrset != 0 && value == USB_FEATURE_ENDPOINTHALT && len == 0 && + (privep = lpc214x_epfindbyaddr(priv, index)) != NULL) + { + privep->halted = 0; + ret = lpc214x_epstall(&privep->ep, true); + lpc214x_epwrite(LPC214X_EP0_IN, NULL, 0); + priv->ep0state = LPC214X_EP0STATUSIN; + } + else + { + usbtrace(TRACE_DEVERROR(LPC214X_TRACEERR_BADCLEARFEATURE), 0); + priv->stalled = 1; + } + } + 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(LPC214X_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) + { + lpc214x_dispatchrequest(priv, &ctrl); + } + else if (priv->paddrset != 0 && value == USB_FEATURE_ENDPOINTHALT && len == 0 && + (privep = lpc214x_epfindbyaddr(priv, index)) != NULL) + { + privep->halted = 1; + lpc214x_epwrite(LPC214X_EP0_IN, NULL, 0); + priv->ep0state = LPC214X_EP0STATUSIN; + } + else + { + usbtrace(TRACE_DEVERROR(LPC214X_TRACEERR_BADSETFEATURE), 0); + priv->stalled = 1; + } + } + break; + + case USB_REQ_SETADDRESS: + { + /* type: host-to-device; recipient = device + * value: device address + * index: 0 + * len: 0; data = none + */ + + usbtrace(TRACE_INTDECODE(LPC214X_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]; + + /* Note that if we send the SETADDRESS command twice, that will force the + * address change. Otherwise, the hardware will automatically set the + * address at the end of the status phase. + */ + + lpc214x_usbcmd(CMD_USB_DEV_SETADDRESS, CMD_USB_SETADDRESS_DEVEN | priv->paddr); + + /* Send a NULL packet. The status phase completes when the null packet has + * been sent successfully. + */ + + lpc214x_epwrite(LPC214X_EP0_IN, NULL, 0); + priv->ep0state = LPC214X_EP0SETADDRESS; + } + else + { + usbtrace(TRACE_DEVERROR(LPC214X_TRACEERR_BADSETADDRESS), 0); + priv->stalled = 1; + } + } + 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(LPC214X_TRACEINTID_GETSETDESC), 0); + if ((ctrl.type & USB_REQ_RECIPIENT_MASK) == USB_REQ_RECIPIENT_DEVICE) + { + lpc214x_dispatchrequest(priv, &ctrl); + } + else + { + usbtrace(TRACE_DEVERROR(LPC214X_TRACEERR_BADGETSETDESC), 0); + priv->stalled = 1; + } + } + break; + + case USB_REQ_GETCONFIGURATION: + /* type: device-to-host; recipient = device + * value: 0; + * index: 0; + * len: 1; data = configuration value + */ + { + usbtrace(TRACE_INTDECODE(LPC214X_TRACEINTID_GETCONFIG), 0); + if (priv->paddrset && (ctrl.type & USB_REQ_RECIPIENT_MASK) == USB_REQ_RECIPIENT_DEVICE && + value == 0 && index == 0 && len == 1) + { + lpc214x_dispatchrequest(priv, &ctrl); + } + else + { + usbtrace(TRACE_DEVERROR(LPC214X_TRACEERR_BADGETCONFIG), 0); + priv->stalled = 1; + } + } + break; + + case USB_REQ_SETCONFIGURATION: + /* type: host-to-device; recipient = device + * value: configuration value + * index: 0; + * len: 0; data = none + */ + { + usbtrace(TRACE_INTDECODE(LPC214X_TRACEINTID_SETCONFIG), 0); + if ((ctrl.type & USB_REQ_RECIPIENT_MASK) == USB_REQ_RECIPIENT_DEVICE && + index == 0 && len == 0) + { + lpc214x_dispatchrequest(priv, &ctrl); + } + else + { + usbtrace(TRACE_DEVERROR(LPC214X_TRACEERR_BADSETCONFIG), 0); + priv->stalled = 1; + } + } + 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(LPC214X_TRACEINTID_GETSETIF), 0); + lpc214x_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(LPC214X_TRACEINTID_SYNCHFRAME), 0); + } + break; + + default: + { + usbtrace(TRACE_DEVERROR(LPC214X_TRACEERR_INVALIDCTRLREQ), 0); + priv->stalled = 1; + } + break; + } + + if (priv->stalled) + { + usbtrace(TRACE_DEVERROR(LPC214X_TRACEERR_EP0SETUPSTALLED), priv->ep0state); + ep0 = &priv->eplist[LPC214X_EP0_OUT]; + lpc214x_epstall(&ep0->ep, false); + ep0 = &priv->eplist[LPC214X_EP0_IN]; + lpc214x_epstall(&ep0->ep, false); + } +} + +/******************************************************************************* + * Name: lpc214x_ep0dataoutinterrupt + * + * Description: + * USB Ctrl EP Data OUT Event. This is logically part of the USB interrupt + * handler. Each non-isochronous OUT endpoint gives an interrupt when they + * receive a packet without error. + * + *******************************************************************************/ + +static inline void lpc214x_ep0dataoutinterrupt(struct lpc214x_usbdev_s *priv) +{ + struct lpc214x_ep_s *ep0; + uint32_t pktlen; + + /* Copy new setup packet into setup buffer */ + + switch (priv->ep0state) + { + case LPC214X_EP0SHORTWRITE: + { + priv->ep0state = LPC214X_EP0STATUSOUT; + pktlen = lpc214x_epread(LPC214X_EP0_OUT, NULL, CONFIG_USBDEV_EP0_MAXSIZE); + if (LPC214X_READOVERRUN(pktlen)) + { + lpc214x_ep0setup(priv); + } + } + break; + + case LPC214X_EP0SHORTWRSENT: + { + priv->ep0state = LPC214X_EP0REQUEST; + pktlen = lpc214x_epread(LPC214X_EP0_OUT, NULL, CONFIG_USBDEV_EP0_MAXSIZE); + if (LPC214X_READOVERRUN(pktlen)) + { + lpc214x_ep0setup(priv); + } + } + break; + + case LPC214X_EP0REQUEST: + { + /* Process the next request action (if any) */ + + lpc214x_rdrequest(&priv->eplist[LPC214X_EP0_OUT]); + } + break; + + default: + priv->stalled = 1; + break; + } + + if (priv->stalled) + { + usbtrace(TRACE_DEVERROR(LPC214X_TRACEERR_EP0OUTSTALLED), priv->ep0state); + ep0 = &priv->eplist[LPC214X_EP0_OUT]; + lpc214x_epstall(&ep0->ep, false); + ep0 = &priv->eplist[LPC214X_EP0_IN]; + lpc214x_epstall(&ep0->ep, false); + } + return; +} + +/******************************************************************************* + * Name: lpc214x_ep0dataininterrupt + * + * Description: + * USB Ctrl EP Data IN Event. This is logically part of the USB interrupt + * handler. All non-isochronous IN endpoints give this interrupt when a + * packet is successfully transmitted (OR a NAK handshake is sent on the bus + * provided that the interrupt on NAK feature is enabled). + * + *******************************************************************************/ + +static inline void lpc214x_ep0dataininterrupt(struct lpc214x_usbdev_s *priv) +{ + struct lpc214x_ep_s *ep0; + + switch (priv->ep0state) + { + case LPC214X_EP0STATUSOUT: + case LPC214X_EP0STATUSIN: + priv->ep0state = LPC214X_EP0REQUEST; + break; + + case LPC214X_EP0SHORTWRITE: + priv->ep0state = LPC214X_EP0SHORTWRSENT; + break; + + case LPC214X_EP0SETADDRESS: + { + /* If the address was set to a non-zero value, then thiscompletes the + * default phase, and begins the address phase (still not fully configured) + */ + + usbtrace(TRACE_INTDECODE(LPC214X_TRACEINTID_EP0INSETADDRESS), (uint16_t)priv->paddr); + lpc214x_usbcmd(CMD_USB_DEV_CONFIG, 0); + if (priv->paddr) + { + priv->paddrset = 1; + priv->ep0state = LPC214X_EP0REQUEST; + } + } + break; + + case LPC214X_EP0REQUEST: + { + /* Process the next request action (if any) */ + + ep0 = &priv->eplist[LPC214X_EP0_IN]; + ep0->txbusy = 0; + lpc214x_wrrequest(ep0); + } + break; + + default: + priv->stalled = 1; + break; + } + + if (priv->stalled) + { + usbtrace(TRACE_DEVERROR(LPC214X_TRACEERR_EP0INSTALLED), priv->ep0state); + ep0 = &priv->eplist[LPC214X_EP0_OUT]; + lpc214x_epstall(&ep0->ep, false); + ep0 = &priv->eplist[LPC214X_EP0_IN]; + lpc214x_epstall(&ep0->ep, false); + } +} + +/******************************************************************************* + * Name: lpc214x_usbinterrupt + * + * Description: + * USB interrupt handler + * + *******************************************************************************/ + +static int lpc214x_usbinterrupt(int irq, FAR void *context) +{ + struct lpc214x_usbdev_s *priv = &g_usbdev; + struct lpc214x_ep_s *privep ; + + uint32_t devintstatus; /* Sampled state of the device interrupt status register */ + uint32_t epintstatus; /* Sampled state of the endpoint interrupt status register */ +#ifdef CONFIG_LPC214X_USBDEV_DMA + uint32_t dmaintstatus; /* Sampled state of dma interrupt status register */ +#endif + uint32_t softprio; /* Current priority interrupt bitset */ + uint32_t pending; /* Pending subset of priority interrupt bitset */ + uint8_t epphy; /* Physical endpoint number being processed */ + int i; + + usbtrace(TRACE_INTENTRY(LPC214X_TRACEINTID_USB), 0); + + /* Read the device interrupt status register */ + + devintstatus = lpc214x_getreg(LPC214X_USBDEV_DEVINTST); + +#ifdef CONFIG_LPC214X_USBDEV_DMA + /* Check for low priority and high priority (non-DMA) interrupts */ + + if ((lpc214x_getreg(LPC214X_USBDEV_INTST) & (USBDEV_INTST_REQLP|USBDEV_INTST_REQHP)) != 0) + { +#endif +#ifdef CONFIG_LPC214X_USBDEV_EPFAST_INTERRUPT + /* Fast EP interrupt */ + + if ((devintstatus & USBDEV_DEVINT_EPFAST) != 0) + { + /* Clear Fast EP interrupt */ + + lpc214x_putreg(USBDEV_DEVINT_EPFAST, LPC214X_USBDEV_DEVINTCLR); + usbtrace(TRACE_INTDECODE(LPC214X_TRACEINTID_EPFAST), 0); + + /* Do what? */ + } + +#endif + +#if CONFIG_DEBUG + /* USB engine error interrupt */ + + if ((devintstatus & USBDEV_DEVINT_EPRINT)) + { + uint8_t errcode; + + /* Clear the error interrupt */ + + lpc214x_putreg(USBDEV_DEVINT_EPRINT, LPC214X_USBDEV_DEVINTCLR); + + /* And show what error occurred */ + + errcode = (uint8_t)lpc214x_usbcmd(CMD_USB_DEV_READERRORSTATUS, 0) & 0x0f; + usbtrace(TRACE_INTDECODE(LPC214X_TRACEINTID_EPRINT), (uint16_t)errcode); + } +#endif + +#ifdef CONFIG_LPC214X_USBDEV_FRAME_INTERRUPT + /* Frame interrupt */ + + if ((devintstatus & USBDEV_DEVINT_FRAME) != 0) + { + /* Clear the frame interrupt */ + + lpc214x_putreg(USBDEV_DEVINT_FRAME, LPC214X_USBDEV_DEVINTCLR); + usbtrace(TRACE_INTDECODE(LPC214X_TRACEINTID_FRAME), 0); + + /* Then read the start of frame value */ + + priv->sof = (uint16_t)lpc214x_usbcmd(CMD_USB_DEV_READFRAMENO, 0); + } +#endif + + /* Device Status interrupt */ + + if ((devintstatus & USBDEV_DEVINT_DEVSTAT) != 0) + { + /* Clear Device status interrupt */ + + lpc214x_putreg(USBDEV_DEVINT_DEVSTAT, LPC214X_USBDEV_DEVINTCLR); + + /* Get device status */ + + g_usbdev.devstatus = (uint8_t)lpc214x_usbcmd(CMD_USB_DEV_GETSTATUS, 0); + usbtrace(TRACE_INTDECODE(LPC214X_TRACEINTID_DEVSTAT), (uint16_t)g_usbdev.devstatus); + + /* Device connection status */ + + if (DEVSTATUS_CONNCHG(g_usbdev.devstatus)) + { + usbtrace(TRACE_INTDECODE(LPC214X_TRACEINTID_CONNECTCHG), + (uint16_t)g_usbdev.devstatus); + if (DEVSTATUS_CONNECT(g_usbdev.devstatus)) + { + /* Host is connected */ + + if (!priv->attached) + { + /* We have a transition from unattached to attached */ + + usbtrace(TRACE_INTDECODE(LPC214X_TRACEINTID_CONNECTED), + (uint16_t)g_usbdev.devstatus); + priv->usbdev.speed = USB_SPEED_UNKNOWN; + lpc214x_usbcmd(CMD_USB_DEV_CONFIG, 0); + priv->attached = 1; + } + } + + /* Otherwise the host is not attached */ + + else if (priv->attached) + { + usbtrace(TRACE_INTDECODE(LPC214X_TRACEINTID_DISCONNECTED), + (uint16_t)g_usbdev.devstatus); + priv->usbdev.speed = USB_SPEED_UNKNOWN; + lpc214x_usbcmd(CMD_USB_DEV_CONFIG, 0); + priv->attached = 0; + priv->paddrset = 0; + } + } + + /* Device suspend status */ + + if (DEVSTATUS_SUSPCHG(g_usbdev.devstatus)) + { + usbtrace(TRACE_INTDECODE(LPC214X_TRACEINTID_SUSPENDCHG), + (uint16_t)g_usbdev.devstatus); + } + + /* Device reset */ + + if (DEVSTATUS_RESET(g_usbdev.devstatus)) + { + usbtrace(TRACE_INTDECODE(LPC214X_TRACEINTID_DEVRESET), + (uint16_t)g_usbdev.devstatus); + lpc214x_usbreset(priv); + } + } + + /* Slow EP interrupt */ + + if ((devintstatus & USBDEV_DEVINT_EPSLOW) != 0) + { + /* Clear Slow EP interrupt */ + + lpc214x_putreg(USBDEV_DEVINT_EPSLOW, LPC214X_USBDEV_DEVINTCLR); + usbtrace(TRACE_INTDECODE(LPC214X_TRACEINTID_EPSLOW), 0); + + do + { + /* Read the endpoint interrupt status register */ + + epintstatus = lpc214x_getreg(LPC214X_USBDEV_EPINTST); + + /* Loop twice: Process software high priority interrupts + * on the first pass and low priority interrupts on the + * second. + */ + + softprio = priv->softprio; + for (i = 0; i < 2; i++, softprio = ~softprio) + { + /* On the first time through the loop, pending will be + * the bitset of high priority pending interrupts; on the + * second time throught it will be the bitset of low + * priority interrupts. + */ + + pending = epintstatus & softprio; + + /* EP0 OUT interrupt indicated by bit0 == 1 */ + + if ((pending & 1) != 0) + { + /* Clear the endpoint interrupt */ + + uint32_t result = lpc214x_epclrinterrupt(LPC214X_CTRLEP_OUT); + if (result & USBDEV_EPSETUPPACKET) + { + usbtrace(TRACE_INTDECODE(LPC214X_TRACEINTID_EP0SETUP), (uint16_t)result); + lpc214x_ep0setup(priv); + } + else + { + usbtrace(TRACE_INTDECODE(LPC214X_TRACEINTID_EP0OUT), priv->ep0state); + lpc214x_ep0dataoutinterrupt(priv); + } + break; + } + + /* EP0 IN interrupt indicated by bit1 == 1 */ + + if ((pending & 2) != 0) + { + /* Clear the endpoint interrupt */ + + usbtrace(TRACE_INTDECODE(LPC214X_TRACEINTID_EP0IN), priv->ep0state); + (void)lpc214x_epclrinterrupt(LPC214X_CTRLEP_IN); + lpc214x_ep0dataininterrupt(priv); + } + pending >>= 2; + + /* All other endpoints EP 1-31 */ + + for (epphy = 2; pending; epphy++, pending >>= 1) + { + /* Is the endpoint interrupt pending? */ + + if ((pending & 1) != 0) + { + /* Yes.. clear the endpoint interrupt */ + + (void)lpc214x_epclrinterrupt(epphy); + + /* Get the endpoint sructure corresponding to the physical + * endpoint number. + */ + + privep = &priv->eplist[epphy]; + + /* Check for complete on IN or OUT endpoint. Odd physical + * endpoint addresses are IN endpoints. + */ + + if ((epphy & 1) != 0) + { + /* IN: device-to-host */ + + usbtrace(TRACE_INTDECODE(LPC214X_TRACEINTID_EPOUT), (uint16_t)epphy); + if (priv->usbdev.speed == USB_SPEED_UNKNOWN) + { + priv->usbdev.speed = USB_SPEED_FULL; + lpc214x_usbcmd(CMD_USB_DEV_CONFIG, 1); + } + + /* Write host data from the current write request (if any) */ + + privep->txbusy = 0; + lpc214x_wrrequest(privep); + } + else + { + /* OUT: host-to-device */ + + usbtrace(TRACE_INTDECODE(LPC214X_TRACEINTID_EPIN), (uint16_t)epphy); + + /* Read host data into the current read request */ + + if (!lpc214x_rqempty(privep)) + { + lpc214x_rdrequest(privep); + } + else + { + ullvdbg("Pending data on OUT endpoint\n"); + priv->rxpending = 1; + } + } + } + } + } + } + while (epintstatus); + } +#ifdef CONFIG_LPC214X_USBDEV_DMA + } + + /* Check for DMA interrupts */ + + if ((lpc214x_getreg(LPC214X_USBDEV_INTST) & USBDEV_INTST_REQDMA) != 0) + { + /* First Software High priority and then low priority */ + + uint32_t tmp; + + /* Collect the DMA interrupt sources */ + + dmaintstatus = 0; + tmp = lpc214x_getreg(LPC214X_USBDEV_EOTINTST); + if (lpc214x_getreg(LPC214X_USBDEV_DMAINTEN) & 1) + { + dmaintstatus |= tmp; + } + lpc214x_putreg(tmp, LPC214X_USBDEV_EOTINTCLR); + + tmp = lpc214x_getreg(LPC214X_USBDEV_NDDRINTST); + if (lpc214x_getreg(LPC214X_USBDEV_DMAINTEN) & 2) + { + dmaintstatus |= tmp; + } + lpc214x_putreg(tmp, LPC214X_USBDEV_NDDRINTCLR); + + tmp = lpc214x_getreg(LPC214X_USBDEV_SYSERRINTST); + if (lpc214x_getreg(LPC214X_USBDEV_DMAINTEN) & 4) + { + dmaintstatus |= tmp; + } + lpc214x_putreg(tmp, LPC214X_USBDEV_SYSERRINTCLR); + + /* Loop twice: Process software high priority interrupts on the + * first pass and low priority interrupts on the second. + */ + + softprio = priv->softprio; + for (i = 0; i < 2; i++, softprio = ~softprio) + { + /* On the first time through the loop, pending will be + * the bitset of high priority pending interrupts; on the + * second time throught it will be the bitset of low + * priority interrupts. Note that EP0 IN and OUT are + * omitted. + */ + + pending = (dmaintstatus & softprio) >> 2; + for (epphy = 2; pending; epphy++, pending >>= 1) + { + if ((pending & 1) != 0) + { + usbtrace(TRACE_INTDECODE(LPC214X_TRACEINTID_EPDMA), (uint16_t)epphy); +#warning DO WHAT? + } + } + } + } +#endif + usbtrace(TRACE_INTEXIT(LPC214X_TRACEINTID_USB), 0); + return OK; +} + +/******************************************************************************* + * Name: lpc214x_dmasetup + * + * Description: + * Setup for DMA Transfer + * + *******************************************************************************/ + +#ifdef CONFIG_LPC214X_USBDEV_DMA +static int lpc214x_dmasetup(struct lpc214x_usbdev_s *priv, uint8_t epphy, + uint32_t epmaxsize, uint32_t nbytes, uint32_t *isocpacket, + bool isochronous); +{ + struct lpc214x_dmadesc_s *dmadesc = priv; + uint32_t reg; + +#ifdef CONFIG_DEBUG + if (!priv || epphy < 2) + { + usbtrace(TRACE_DEVERROR(LPC214X_TRACEERR_INVALIDPARMS), 0); + return -EINVAL; + } +#endif + + /* Check if a DMA descriptor has been assigned. If not, than that indicates + * that we will have to do parallel I/O + */ + + if (!dmadesc) + { + usbtrace(TRACE_DEVERROR(LPC214X_TRACEERR_NODMADESC), 0); + return -EBUSY; + } + + /* Verify that the DMA descriptor is available */ + + if ((dmadesc->status & USB_DMADESC_STATUSMASK) == USB_DMADESC_BEINGSERVICED) + { + usbtrace(TRACE_DEVERROR(LPC214X_TRACEERR_DMABUSY), 0); + return -EBUSY; /* Shouldn't happen */ + } + + /* Init DMA Descriptor */ + + dmadesc->nexdesc = 0; + dmadesc->config = USB_DMADESC_MODENORMAL | + ((epmaxsize << USB_DMADESC_PKTSIZESHIFT) & USB_DMADESC_PKTSIZEMASK) | + ((nbytes << USB_DMADESC_BULENSHIFT) & USB_DMADESC_BUFLENMASK); + +#ifdef CONFIG_USBDEV_ISOCHRONOUS + if (isochronous) + { + dmadesc->config |= USB_DMADESC_ISCOEP; + } +#endif + + dmadesc->start = (uint32_t)&dmadesc->buffer; + dmadesc->status = 0; + +#ifdef CONFIG_USBDEV_ISOCHRONOUS + dmadesc->size = (uint32_t)packet; +#endif + + /* Enable DMA tranfer for this endpoint */ + + putreq32(1 << epphy, LPC214X_USBDEV_EPDMAEN); + + /* Check state of IN/OUT Ep buffer */ + + reg = lpc214x_usbcmd(CMD_USB_EP_SELECT | epphy, 0); + + if ((LPC214X_EPPHYIN(epphy) && (reg & 0x60) == 0) || + (LPC214X_EPPHYOUT(epphy) && (reg & 0x60) == 0x60)) + { + /* DMA should be "being serviced" */ + + if ((dmadesc->status & USB_DMADESC_STATUSMASK) != USB_DMADESC_BEINGSERVICED)) + { + /* Re-trigger the DMA Transfer */ + + putreq21(1 << epphy, LPC214X_USBDEV_DMARCLR); + putreq32(1 << epphy, LPC214X_USBDEV_EPDMAEN); + } + } + return OK; +} +#endif /* CONFIG_LPC214X_USBDEV_DMA */ + +/******************************************************************************* + * Name: lpc214x_dmarestart + * + * Description: + * Restart DMA Transfer + * + *******************************************************************************/ + +#ifdef CONFIG_LPC214X_USBDEV_DMA +static void lpc214x_dmarestart(uint8_t epphy, uint32_t descndx) +{ + uint32_t reg; + + /* Clear DMA descriptor status */ + + USB_DmaDesc[descndx].status = 0; + + /* Enable DMA transfer on the endpoint */ + + lpc214x_putreg(1 << epph, LPC214X_USBDEV_EPDMAEN); + + /* Check the state of IN/OUT EP buffer */ + + uint32_t reg = lpc214x_usbcmd(CMD_USB_EP_SELECT | epphy, 0); + if ((LPC214X_EPPHYIN(epphy) && (reg & 0x60) == 0) || + (LPC214X_EPPHYIN(epphy) && (reg & 0x60) == 0x60)) + { + /* Re-trigger the DMA Transfer */ + + putreq21(1 << epphy, LPC214X_USBDEV_DMARCLR); + putreq32(1 << epphy, LPC214X_USBDEV_EPDMAEN); + } +} +#endif /* CONFIG_LPC214X_USBDEV_DMA */ + +/******************************************************************************* + * Name: lpc214x_dmadisable + * + * Description: + * Disable DMA transfer for the EP + * + *******************************************************************************/ + +#ifdef CONFIG_LPC214X_USBDEV_DMA +static void lpc214x_dmadisable(uint8_t epphy) +{ + EPDMADIS = 1 << epphy; +} +#endif /* CONFIG_LPC214X_USBDEV_DMA */ + +/******************************************************************************* + * Endpoint operations + *******************************************************************************/ + +/******************************************************************************* + * Name: lpc214x_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 lpc214x_epconfigure(FAR struct usbdev_ep_s *ep, + FAR const struct usb_epdesc_s *desc, + bool last) +{ + FAR struct lpc214x_ep_s *privep = (FAR struct lpc214x_ep_s *)ep; + uint32_t inten; + + usbtrace(TRACE_EPCONFIGURE, privep->epphy); + DEBUGASSERT(desc->addr == ep->eplog); + + /* Realize the endpoint */ + + lpc214x_eprealize(privep, 1, GETUINT16(desc->mxpacketsize)); + + /* Enable and reset EP -- twice */ + + lpc214x_usbcmd(CMD_USB_EP_SETSTATUS | privep->epphy, 0); + lpc214x_usbcmd(CMD_USB_EP_SETSTATUS | privep->epphy, 0); + +#ifdef CONFIG_LPC214X_USBDEV_DMA + /* Enable DMA Ep interrupt (WO) */ + + lpc214x_putreg(1 << privep->epphy, LPC214X_USBDEV_EPDMAEN); +#else + /* Enable Ep interrupt (R/W) */ + + inten = lpc214x_getreg(LPC214X_USBDEV_EPINTEN); + inten |= (1 << privep->epphy); + lpc214x_putreg(inten, LPC214X_USBDEV_EPINTEN); +#endif + + /* If all of the endpoints have been configured, then tell the USB controller + * to enabled normal activity on all realized endpoints. + */ + + if (last) + { + lpc214x_usbcmd(CMD_USB_DEV_CONFIG, 1); + } + return OK; +} + +/******************************************************************************* + * Name: lpc214x_epdisable + * + * Description: + * The endpoint will no longer be used + * + *******************************************************************************/ + +static int lpc214x_epdisable(FAR struct usbdev_ep_s *ep) +{ + FAR struct lpc214x_ep_s *privep = (FAR struct lpc214x_ep_s *)ep; + irqstate_t flags; + uint32_t mask = (1 << privep->epphy); + uint32_t reg; + +#ifdef CONFIG_DEBUG + if (!ep) + { + usbtrace(TRACE_DEVERROR(LPC214X_TRACEERR_INVALIDPARMS), 0); + return -EINVAL; + } +#endif + usbtrace(TRACE_EPDISABLE, privep->epphy); + + /* Cancel any ongoing activity */ + + flags = irqsave(); + lpc214x_cancelrequests(privep); + + /* Disable endpoint and interrupt */ + + reg = lpc214x_getreg(LPC214X_USBDEV_REEP); + reg &= ~mask; + lpc214x_putreg(reg, LPC214X_USBDEV_REEP); + + lpc214x_putreg(mask, LPC214X_USBDEV_EPDMADIS); + + reg = lpc214x_getreg(LPC214X_USBDEV_EPINTEN); + reg &= ~mask; + lpc214x_putreg(reg, LPC214X_USBDEV_EPINTEN); + + irqrestore(flags); + return OK; +} + +/******************************************************************************* + * Name: lpc214x_epallocreq + * + * Description: + * Allocate an I/O request + * + *******************************************************************************/ + +static FAR struct usbdev_req_s *lpc214x_epallocreq(FAR struct usbdev_ep_s *ep) +{ + FAR struct lpc214x_req_s *privreq; + +#ifdef CONFIG_DEBUG + if (!ep) + { + usbtrace(TRACE_DEVERROR(LPC214X_TRACEERR_INVALIDPARMS), 0); + return NULL; + } +#endif + usbtrace(TRACE_EPALLOCREQ, ((FAR struct lpc214x_ep_s *)ep)->epphy); + + privreq = (FAR struct lpc214x_req_s *)malloc(sizeof(struct lpc214x_req_s)); + if (!privreq) + { + usbtrace(TRACE_DEVERROR(LPC214X_TRACEERR_ALLOCFAIL), 0); + return NULL; + } + + memset(privreq, 0, sizeof(struct lpc214x_req_s)); + return &privreq->req; +} + +/******************************************************************************* + * Name: lpc214x_epfreereq + * + * Description: + * Free an I/O request + * + *******************************************************************************/ + +static void lpc214x_epfreereq(FAR struct usbdev_ep_s *ep, FAR struct usbdev_req_s *req) +{ + FAR struct lpc214x_req_s *privreq = (FAR struct lpc214x_req_s *)req; + +#ifdef CONFIG_DEBUG + if (!ep || !req) + { + usbtrace(TRACE_DEVERROR(LPC214X_TRACEERR_INVALIDPARMS), 0); + return; + } +#endif + usbtrace(TRACE_EPFREEREQ, ((FAR struct lpc214x_ep_s *)ep)->epphy); + + free(privreq); +} + +/******************************************************************************* + * Name: lpc214x_epallocbuffer + * + * Description: + * Allocate an I/O buffer + * + *******************************************************************************/ + +#ifdef CONFIG_LPC214X_USBDEV_DMA +static FAR void *lpc214x_epallocbuffer(FAR struct usbdev_ep_s *ep, uint16_t nbytes) +{ +#ifdef CONFIG_USBDEV_DMA + + FAR struct lpc214x_ep_s *privep = (FAR struct lpc214x_ep_s *)ep; + int descndx; + + usbtrace(TRACE_EPALLOCBUFFER, privep->epphy); + + /* Find a free DMA description */ + +#error "LOGIC INCOMPLETE" + + /* Set UDCA to the allocated DMA descriptor for this endpoint */ + + USB_UDCA[privep->epphy] = &USB_DDESC[descndx]; + return &USB_DDESC[descndx] + +#elif defined(CONFIG_USBDEV_DMAMEMORY) + + usbtrace(TRACE_EPALLOCBUFFER, privep->epphy); + return usbdev_dma_alloc(bytes); + +#else + + usbtrace(TRACE_EPALLOCBUFFER, privep->epphy); + return malloc(bytes); + +#endif +} +#endif + +/******************************************************************************* + * Name: lpc214x_epfreebuffer + * + * Description: + * Free an I/O buffer + * + *******************************************************************************/ + +#ifdef CONFIG_USBDEV_DMA + +static void lpc214x_epfreebuffer(FAR struct usbdev_ep_s *ep, FAR void *buf) +{ +#ifdef CONFIG_LPC214X_USBDEV_DMA + FAR struct lpc214x_ep_s *privep = (FAR struct lpc214x_ep_s *)ep; + + usbtrace(TRACE_EPFREEBUFFER, privep->epphy); + + /* Indicate that there is no DMA descriptor associated with this endpoint */ + + USB_UDCA[privep->epphy] = NULL; + + /* Mark the DMA descriptor as free for re-allocation */ + +# error "LOGIC INCOMPLETE" + +#elif defined(CONFIG_USBDEV_DMAMEMORY) + + usbtrace(TRACE_EPFREEBUFFER, privep->epphy); + usbdev_dma_free(buf); + +#else + + usbtrace(TRACE_EPFREEBUFFER, privep->epphy); + free(buf); + +#endif +} +#endif + +/******************************************************************************* + * Name: lpc214x_epsubmit + * + * Description: + * Submit an I/O request to the endpoint + * + *******************************************************************************/ + +static int lpc214x_epsubmit(FAR struct usbdev_ep_s *ep, FAR struct usbdev_req_s *req) +{ + FAR struct lpc214x_req_s *privreq = (FAR struct lpc214x_req_s *)req; + FAR struct lpc214x_ep_s *privep = (FAR struct lpc214x_ep_s *)ep; + FAR struct lpc214x_usbdev_s *priv; + irqstate_t flags; + int ret = OK; + +#ifdef CONFIG_DEBUG + if (!req || !req->callback || !req->buf || !ep) + { + usbtrace(TRACE_DEVERROR(LPC214X_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(LPC214X_TRACEERR_NOTCONFIGURED), priv->usbdev.speed); + return -ESHUTDOWN; + } + + /* Handle the request from the class driver */ + + req->result = -EINPROGRESS; + req->xfrd = 0; + flags = irqsave(); + + /* If we are stalled, then drop all requests on the floor */ + + if (privep->stalled) + { + lpc214x_abortrequest(privep, privreq, -EBUSY); + ret = -EBUSY; + } + + /* Handle IN (device-to-host) requests */ + + else if (LPC214X_EPPHYIN(privep->epphy)) + { + /* Add the new request to the request queue for the IN endpoint */ + + lpc214x_rqenqueue(privep, privreq); + usbtrace(TRACE_INREQQUEUED(privep->epphy), privreq->req.len); + + /* If the IN endpoint FIFO is available, then transfer the data now */ + + if (privep->txbusy == 0) + { + ret = lpc214x_wrrequest(privep); + } + } + + /* Handle OUT (host-to-device) requests */ + + else + { + /* Add the new request to the request queue for the OUT endpoint */ + + privep->txnullpkt = 0; + lpc214x_rqenqueue(privep, privreq); + usbtrace(TRACE_OUTREQQUEUED(privep->epphy), privreq->req.len); + + /* This there a incoming data pending the availability of a request? */ + + if (priv->rxpending) + { + ret = lpc214x_rdrequest(privep); + priv->rxpending = 0; + } + } + + irqrestore(flags); + return ret; +} + +/******************************************************************************* + * Name: lpc214x_epcancel + * + * Description: + * Cancel an I/O request previously sent to an endpoint + * + *******************************************************************************/ + +static int lpc214x_epcancel(FAR struct usbdev_ep_s *ep, FAR struct usbdev_req_s *req) +{ + FAR struct lpc214x_ep_s *privep = (FAR struct lpc214x_ep_s *)ep; + FAR struct lpc214x_usbdev_s *priv; + irqstate_t flags; + +#ifdef CONFIG_DEBUG + if (!ep || !req) + { + usbtrace(TRACE_DEVERROR(LPC214X_TRACEERR_INVALIDPARMS), 0); + return -EINVAL; + } +#endif + usbtrace(TRACE_EPCANCEL, privep->epphy); + priv = privep->dev; + + flags = irqsave(); + lpc214x_cancelrequests(privep); + irqrestore(flags); + return OK; +} + +/******************************************************************************* + * Name: lpc214x_epstall + * + * Description: + * Stall or resume and endpoint + * + *******************************************************************************/ + +static int lpc214x_epstall(FAR struct usbdev_ep_s *ep, bool resume) +{ + FAR struct lpc214x_ep_s *privep = (FAR struct lpc214x_ep_s *)ep; + irqstate_t flags; + + /* STALL or RESUME the endpoint */ + + flags = irqsave(); + usbtrace(resume ? TRACE_EPRESUME : TRACE_EPSTALL, privep->epphy); + lpc214x_usbcmd(CMD_USB_EP_SETSTATUS | privep->epphy, (resume ? 0 : USBDEV_EPSTALL)); + + /* If the endpoint of was resumed, then restart any queue write requests */ + + if (resume) + { + (void)lpc214x_wrrequest(privep); + } + irqrestore(flags); + return OK; +} + +/******************************************************************************* + * Device operations + *******************************************************************************/ + +/******************************************************************************* + * Name: lcp214x_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 *lcp214x_allocep(FAR struct usbdev_s *dev, uint8_t eplog, + bool in, uint8_t eptype) +{ + FAR struct lpc214x_usbdev_s *priv = (FAR struct lpc214x_usbdev_s *)dev; + uint32_t epset = LPC214X_EPALLSET & ~LPC214X_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 >= LPC214X_NLOGENDPOINTS) + { + usbtrace(TRACE_DEVERROR(LPC214X_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 &= LPC214X_EPINSET; + } + else + { + epset &= LPC214X_EPOUTSET; + } + + /* Get the subset matching the requested type */ + + switch (eptype) + { + case USB_EP_ATTR_XFER_INT: /* Interrupt endpoint */ + epset &= LPC214X_EPINTRSET; + break; + + case USB_EP_ATTR_XFER_BULK: /* Bulk endpoint */ + epset &= LPC214X_EPBULKSET; + break; + + case USB_EP_ATTR_XFER_ISOC: /* Isochronous endpoint */ + epset &= LPC214X_EPISOCSET; + break; + + case USB_EP_ATTR_XFER_CONTROL: /* Control endpoint -- not a valid choice */ + default: + usbtrace(TRACE_DEVERROR(LPC214X_TRACEERR_BADEPTYPE), (uint16_t)eptype); + return NULL; + } + + /* Is the resulting endpoint supported by the LPC214x? */ + + 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 < LPC214X_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(LPC214X_TRACEERR_NOEP), (uint16_t)eplog); + return NULL; +} + +/******************************************************************************* + * Name: lpc214x_freeep + * + * Description: + * Free the previously allocated endpoint + * + *******************************************************************************/ + +static void lpc214x_freeep(FAR struct usbdev_s *dev, FAR struct usbdev_ep_s *ep) +{ + FAR struct lpc214x_usbdev_s *priv = (FAR struct lpc214x_usbdev_s *)dev; + FAR struct lpc214x_ep_s *privep = (FAR struct lpc214x_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: lpc214x_getframe + * + * Description: + * Returns the current frame number + * + *******************************************************************************/ + +static int lpc214x_getframe(struct usbdev_s *dev) +{ +#ifdef CONFIG_LPC214X_USBDEV_FRAME_INTERRUPT + FAR struct lpc214x_usbdev_s *priv = (FAR struct lpc214x_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); + return (int)lpc214x_usbcmd(CMD_USB_DEV_READFRAMENO, 0); +#endif +} + +/******************************************************************************* + * Name: lpc214x_wakeup + * + * Description: + * Tries to wake up the host connected to this device + * + *******************************************************************************/ + +static int lpc214x_wakeup(struct usbdev_s *dev) +{ + uint8_t arg = USBDEV_DEVSTATUS_SUSPEND; + irqstate_t flags; + + usbtrace(TRACE_DEVWAKEUP, (uint16_t)g_usbdev.devstatus); + + flags = irqsave(); + if (DEVSTATUS_CONNECT(g_usbdev.devstatus)) + { + arg |= USBDEV_DEVSTATUS_CONNECT; + } + + lpc214x_usbcmd(CMD_USB_DEV_SETSTATUS, arg); + irqrestore(flags); + return OK; +} + +/******************************************************************************* + * Name: lpc214x_selfpowered + * + * Description: + * Sets/clears the device selfpowered feature + * + *******************************************************************************/ + +static int lpc214x_selfpowered(struct usbdev_s *dev, bool selfpowered) +{ + FAR struct lpc214x_usbdev_s *priv = (FAR struct lpc214x_usbdev_s *)dev; + + usbtrace(TRACE_DEVSELFPOWERED, (uint16_t)selfpowered); + +#ifdef CONFIG_DEBUG + if (!dev) + { + usbtrace(TRACE_DEVERROR(LPC214X_TRACEERR_INVALIDPARMS), 0); + return -ENODEV; + } +#endif + + priv->selfpowered = selfpowered; + return OK; +} + +/******************************************************************************* + * Name: lpc214x_pullup + * + * Description: + * Software-controlled connect to/disconnect from USB host + * + *******************************************************************************/ + +static int lpc214x_pullup(struct usbdev_s *dev, bool enable) +{ + usbtrace(TRACE_DEVPULLUP, (uint16_t)enable); + + /* The USBDEV_DEVSTATUS_CONNECT bit in the CMD_USB_DEV_SETSTATUS command + * controls the LPC214x SoftConnect_N output pin that is used for SoftConnect. + */ + + lpc214x_usbcmd(CMD_USB_DEV_SETSTATUS, (enable ? USBDEV_DEVSTATUS_CONNECT : 0)); + return OK; +} + +/******************************************************************************* + * Public Functions + *******************************************************************************/ + +/******************************************************************************* + * Name: up_usbinitialize + * + * Description: + * Initialize USB hardware. + * + * Assumptions: + * - This function is called very early in the initialization sequence + * - PLL and GIO pin initialization is not performed here but should been in + * the low-level boot logic: PLL1 must be configured for operation at 48MHz + * and P0.23 and PO.31 in PINSEL1 must be configured for Vbus and USB connect + * LED. + * + *******************************************************************************/ + +void up_usbinitialize(void) +{ + struct lpc214x_usbdev_s *priv = &g_usbdev; + uint32_t reg; + int i; + + usbtrace(TRACE_DEVINIT, 0); + + /* Disable USB interrupts */ + + lpc214x_putreg(0, LPC214X_USBDEV_INTST); + + /* Initialize the device state structure */ + + memset(priv, 0, sizeof(struct lpc214x_usbdev_s)); + priv->usbdev.ops = &g_devops; + priv->usbdev.ep0 = &priv->eplist[LPC214X_EP0_IN].ep; + priv->epavail = LPC214X_EPALLSET; + + /* Initialize the endpoint list */ + + for (i = 0; i < LPC214X_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 (LPC214X_EPPHYIN(i)) + { + priv->eplist[i].ep.eplog = LPC214X_EPPHYIN2LOG(i); + } + else + { + priv->eplist[i].ep.eplog = LPC214X_EPPHYOUT2LOG(i); + } + + /* The maximum packet size may depend on the type of endpoint */ + + if ((LPC214X_EPCTRLSET & bit) != 0) + { + priv->eplist[i].ep.maxpacket = LPC214X_EP0MAXPACKET; + } + else if ((LPC214X_EPINTRSET & bit) != 0) + { + priv->eplist[i].ep.maxpacket = LPC214X_INTRMAXPACKET; + } + else if ((LPC214X_EPBULKSET & bit) != 0) + { + priv->eplist[i].ep.maxpacket = LPC214X_BULKMAXPACKET; + } + else /* if ((LPC214X_EPISOCSET & bit) != 0) */ + { + priv->eplist[i].ep.maxpacket = LPC214X_ISOCMAXPACKET; + } + } + + /* Turn on USB power and clocking */ + + reg = lpc214x_getreg(LPC214X_PCON_PCONP); + reg |= LPC214X_PCONP_PCUSB; + lpc214x_putreg(reg, LPC214X_PCON_PCONP); + + /* Attach USB controller interrupt handler */ + + if (irq_attach(LPC214X_USB_IRQ, lpc214x_usbinterrupt) != 0) + { + usbtrace(TRACE_DEVERROR(LPC214X_TRACEERR_IRQREGISTRATION), + (uint16_t)LPC214X_USB_IRQ); + goto errout; + } + + /* Enable USB inerrupts at the controller -- but do not disable + * the ARM interrupt until the device is bound to the class + * driver + */ + + lpc214x_putreg(USBDEV_INTST_ENUSBINTS, LPC214X_USBDEV_INTST); + + /* Disconnect device */ + + lpc214x_pullup(&priv->usbdev, false); + + /* Enable EP0 for OUT (host-to-device) */ + + lpc214x_usbcmd(CMD_USB_DEV_SETADDRESS, CMD_USB_SETADDRESS_DEVEN|0); + lpc214x_usbcmd(CMD_USB_DEV_SETADDRESS, CMD_USB_SETADDRESS_DEVEN|0); + + /* Reset/Re-initialize the USB hardware */ + + lpc214x_usbreset(priv); + + /* Init Device state structure */ + + priv->devstatus = lpc214x_usbcmd(CMD_USB_DEV_GETSTATUS, 0); + return; + +errout: + up_usbuninitialize(); +} + +/******************************************************************************* + * Name: up_usbuninitialize + *******************************************************************************/ + +void up_usbuninitialize(void) +{ + struct lpc214x_usbdev_s *priv = &g_usbdev; + uint32_t reg; + irqstate_t flags; + + usbtrace(TRACE_DEVUNINIT, 0); + + if (priv->driver) + { + usbtrace(TRACE_DEVERROR(LPC214X_TRACEERR_DRIVERREGISTERED), 0); + usbdev_unregister(priv->driver); + } + + /* Disconnect device */ + + flags = irqsave(); + lpc214x_pullup(&priv->usbdev, false); + priv->usbdev.speed = USB_SPEED_UNKNOWN; + lpc214x_usbcmd(CMD_USB_DEV_CONFIG, 0); + + /* Disable and detach IRQs */ + + up_disable_irq(LPC214X_USB_IRQ); + irq_detach(LPC214X_USB_IRQ); + + /* Turn off USB power and clocking */ + + reg = lpc214x_getreg(LPC214X_PCON_PCONP); + reg &= ~LPC214X_PCONP_PCUSB; + lpc214x_putreg(reg, LPC214X_PCON_PCONP); + 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(LPC214X_TRACEERR_INVALIDPARMS), 0); + return -EINVAL; + } + + if (g_usbdev.driver) + { + usbtrace(TRACE_DEVERROR(LPC214X_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(LPC214X_TRACEERR_BINDFAILED), (uint16_t)-ret); + g_usbdev.driver = NULL; + } + else + { + /* Enable USB controller interrupts */ + + up_enable_irq(LPC214X_USB_IRQ); + } + 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(LPC214X_TRACEERR_INVALIDPARMS), 0); + return -EINVAL; + } +#endif + + /* Unbind the class driver */ + + CLASS_UNBIND(driver, &g_usbdev.usbdev); + + /* Disable USB controller interrupts */ + + up_disable_irq(LPC214X_USB_IRQ); + + /* Unhook the driver */ + + g_usbdev.driver = NULL; + return OK; +} diff --git a/nuttx/arch/arm/src/lpc214x/lpc214x_usbdev.h b/nuttx/arch/arm/src/lpc214x/lpc214x_usbdev.h new file mode 100644 index 000000000..814622ef5 --- /dev/null +++ b/nuttx/arch/arm/src/lpc214x/lpc214x_usbdev.h @@ -0,0 +1,346 @@ +/******************************************************************************* + * arch/arm/src/lpc214x/lpc214x_usbdev.h + * + * Copyright (C) 2008-2009 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <gnutt@nuttx.org> + * + * 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. + * + *******************************************************************************/ + +#ifndef __ARCH_ARM_SRC_LPC214X_LPC214X_USBDEV_H +#define __ARCH_ARM_SRC_LPC214X_LPC214X_USBDEV_H + +/******************************************************************************* + * Included Files + *******************************************************************************/ + +#include <nuttx/config.h> + +/******************************************************************************* + * Definitions + *******************************************************************************/ + +/* PINSEL1 bit definitions for UART0/1: + * + * P0.23 = 01 to enable VBus sense (bits 14-15) + * P0.31 = 10 to enable CONNECT (bits 30-31) + */ + +#define LPC214X_USBDEV_PINSEL (0x80004000) /* PINSEL1 value for USB */ +#define LPC214X_USBDEV_PINMASK (0xc000c000) /* PINSEL1 mask for USB */ + +/* USB RAM ********************************************************************/ + +#define LPC214X_USBDEV_RAMBASE (0x7fd00000) +#define LPC214X_USBDEV_RAMSIZE (8*1024) + +/* USB register address definitions ********************************************/ + +#define LPC214X_USBDEV_PLLCON (0xe01fc0a0) +#define LPC214X_USBDEV_PLLCFG (0xe01fc0a4) +#define LPC214X_USBDEV_PLLSTAT (0xe01fc0a8) +#define LPC214X_USBDEV_PLLFEED (0xe01fc0ac) + +#define LPC214X_USBDEV_INTST (0xe01fc1c0) + +#define LPC214X_USBDEV_DEVINTST (0xe0090000) +#define LPC214X_USBDEV_DEVINTEN (0xe0090004) +#define LPC214X_USBDEV_DEVINTCLR (0xe0090008) +#define LPC214X_USBDEV_DEVINTSET (0xe009000c) +#define LPC214X_USBDEV_CMDCODE (0xe0090010) +#define LPC214X_USBDEV_CMDDATA (0xe0090014) +#define LPC214X_USBDEV_RXDATA (0xe0090018) +#define LPC214X_USBDEV_TXDATA (0xe009001c) +#define LPC214X_USBDEV_RXPLEN (0xe0090020) +#define LPC214X_USBDEV_TXPLEN (0xe0090024) +#define LPC214X_USBDEV_CTRL (0xe0090028) +#define LPC214X_USBDEV_DEVINTPRI (0xe009002c) +#define LPC214X_USBDEV_EPINTST (0xe0090030) +#define LPC214X_USBDEV_EPINTEN (0xe0090034) +#define LPC214X_USBDEV_EPINTCLR (0xe0090038) +#define LPC214X_USBDEV_EPINTSET (0xe009003c) +#define LPC214X_USBDEV_EPINTPRI (0xe0090040) +#define LPC214X_USBDEV_REEP (0xe0090044) +#define LPC214X_USBDEV_EPIND (0xe0090048) +#define LPC214X_USBDEV_MAXPSIZE (0xe009004c) +#define LPC214X_USBDEV_DMARST (0xe0090050) +#define LPC214X_USBDEV_DMARCLR (0xe0090054) +#define LPC214X_USBDEV_DMARSET (0xe0090058) + +#define LPC214X_USBDEV_UDCAH (0xe0090080) +#define LPC214X_USBDEV_EPDMAST (0xe0090084) +#define LPC214X_USBDEV_EPDMAEN (0xe0090088) +#define LPC214X_USBDEV_EPDMADIS (0xe009008c) +#define LPC214X_USBDEV_DMAINTST (0xe0090090) +#define LPC214X_USBDEV_DMAINTEN (0xe0090094) + +#define LPC214X_USBDEV_EOTINTST (0xe00900a0) +#define LPC214X_USBDEV_EOTINTCLR (0xe00900a4) +#define LPC214X_USBDEV_EOTINTSET (0xe00900a8) +#define LPC214X_USBDEV_NDDRINTST (0xe00900ac) +#define LPC214X_USBDEV_NDDRINTCLR (0xe00900b0) +#define LPC214X_USBDEV_NDDRINTSET (0xe00900b4) +#define LPC214X_USBDEV_SYSERRINTST (0xe00900b8) +#define LPC214X_USBDEV_SYSERRINTCLR (0xe00900bc) +#define LPC214X_USBDEV_SYSERRINTSET (0xe00900c0) + +/* USB register bit definitions ************************************************/ + +/* INTST bit definitions */ + +#define USBDEV_INTST_REQLP (0x00000001) +#define USBDEV_INTST_REQHP (0x00000002) +#define USBDEV_INTST_REQDMA (0x00000004) +#define USBDEV_INTST_NEEDCLOCK (0x00000100) +#define USBDEV_INTST_ENUSBINTS (0x80000000) +#define USBDEV_INTST_MASK (0x80000107) + +/* DEVINTST/DEVINTEN/DEVINTCLR/DEVINTSET bit definitions */ + +#define USBDEV_DEVINT_FRAME (0x00000001) +#define USBDEV_DEVINT_EPFAST (0x00000002) +#define USBDEV_DEVINT_EPSLOW (0x00000004) +#define USBDEV_DEVINT_DEVSTAT (0x00000008) +#define USBDEV_DEVINT_CCEMTY (0x00000010) +#define USBDEV_DEVINT_CDFULL (0x00000020) +#define USBDEV_DEVINT_RXENDPKT (0x00000040) +#define USBDEV_DEVINT_TXENDPKT (0x00000080) +#define USBDEV_DEVINT_EPRLZED (0x00000100) +#define USBDEV_DEVINT_EPRINT (0x00000200) +#define USBDEV_DEVINT_MASK (0x000003ff) + +/* DEVINTPRI bit definitions */ + +#define USBDEV_DEVINTPRI_FRAME (0x00000001) +#define USBDEV_DEVINTPRI_EPFAST (0x00000002) +#define USBDEV_DEVINTPRI_MASK (0x00000003) + +/* RXPLEN bit definitions */ + +#define USBDEV_RXPLEN_PKTLENGTH (0x000003ff) +#define USBDEV_RXPLEN_PKTLENGTH_MASK (0x000003ff) +#define USBDEV_RXPLEN_DV (0x00000400) +#define USBDEV_RXPLEN_PKTRDY (0x00000800) +#define USBDEV_RXPLEN_MASK (0x00000fff) + +/* TXPLEN bit definitions */ + +#define USBDEV_TXPLEN_PKTLENGTH (0x000003ff) +#define USBDEV_TXPLEN_MASK (0x000003ff) + +/* USBCTRL bit definitions */ + +#define USBDEV_CTRL_RDEN (0x00000001) +#define USBDEV_CTRL_WREN (0x00000002) +#define USBDEV_CTRL_LOGENDPOINT (0x0000003c) +#define USBDEV_CTRL_MASK (0x0000003f) + +/* CMDCODE bit definitions */ + +#define USBDEV_CMDCODE_CMDPHASE (0x0000ff00) +#define USBDEV_CMDCODE_CMDCODE (0x00ff0000) +#define USBDEV_CMDCODE_MASK (0x00ffff00) + +/* DMAINSTST/DMAINSTEN bit defintions */ + +#define USBDEV_DMAINST_EOT (0x00000001) +#define USBDEV_DMAINST_NDDR (0x00000002) +#define USBDEV_DMAINST_SE (0x00000004) +#define USBDEV_DMAINST_MASK (0x00000007) + +/* Device Status Bits */ + +#define USBDEV_EPSTALL (0x00000001) +#define USBDEV_EPSTALLSTATUS (0x00000002) +#define USBDEV_EPSETUPPACKET (0x00000004) +#define USBDEV_EPPOSSTATUS (0x00000010) +#define USBDEV_EPCONDSTALL (0x00000080) + +/* USB Control register bit definitions */ + +#define LPC214X_USBCTRL_RDEN (0x00000001) /* Bit 0=1: Read is enabled */ +#define LPC214X_USBCTRL_WREN (0x00000002) /* Bit 0=1: Write is enabled */ +#define LPC214X_USBCTRL_EPMASK (0x0000003c) /* Bits 2:5: Logical endpoint 0-15 */ + +/* Endpoints *******************************************************************/ + +#define LPC214X_EP0_OUT 0 +#define LPC214X_EP0_IN 1 +#define LPC214X_CTRLEP_OUT LPC214X_EP0_OUT +#define LPC214X_CTRLEP_IN LPC214X_EP0_IN +#define LPC214X_EP1_OUT 2 +#define LPC214X_EP1_IN 3 +#define LPC214X_EP2_OUT 4 +#define LPC214X_EP2_IN 5 +#define LPC214X_EP3_OUT 6 +#define LPC214X_EP3_IN 7 +#define LPC214X_EP4_OUT 8 +#define LPC214X_EP4_IN 9 +#define LPC214X_EP5_OUT 10 +#define LPC214X_EP5_IN 11 +#define LPC214X_EP6_OUT 12 +#define LPC214X_EP6_IN 13 +#define LPC214X_EP7_OUT 14 +#define LPC214X_EP7_IN 15 +#define LPC214X_EP8_OUT 16 +#define LPC214X_EP8_IN 17 +#define LPC214X_EP9_OUT 18 +#define LPC214X_EP9_IN 19 +#define LPC214X_EP10_OUT 20 +#define LPC214X_EP10_IN 21 +#define LPC214X_EP11_OUT 22 +#define LPC214X_EP11_IN 23 +#define LPC214X_EP12_OUT 24 +#define LPC214X_EP12_IN 25 +#define LPC214X_EP13_OUT 26 +#define LPC214X_EP13_IN 27 +#define LPC214X_EP14_OUT 28 +#define LPC214X_EP14_IN 29 +#define LPC214X_EP15_OUT 30 +#define LPC214X_EP15_IN 31 +#define LPC214X_NUMEPS 32 + +/* Commands ********************************************************************/ + +/* USB Command Code Register -- Command phase values */ + +#define CMD_USB_CMDWR (0x00000500) +#define CMD_USB_DATAWR (0x00000100) +#define CMD_USB_DATARD (0x00000200) + +/* Device Commands */ + +#define CMD_USB_DEV_SETADDRESS (0x00d0) +#define CMD_USB_DEV_CONFIG (0x00d8) +#define CMD_USB_DEV_SETMODE (0x00f3) +#define CMD_USB_DEV_READFRAMENO (0x00f5) +#define CMD_USB_DEV_READTESTREG (0x00fd) +#define CMD_USB_DEV_SETSTATUS (0x01fe) +#define CMD_USB_DEV_GETSTATUS (0x00fe) +#define CMD_USB_DEV_GETERRORCODE (0x00ff) +#define CMD_USB_DEV_READERRORSTATUS (0x00fb) + +/* Endpoint Commands */ + +#define CMD_USB_EP_SELECT (0x0000) +#define CMD_USB_EP_SELECTCLEAR (0x0040) +#define CMD_USB_EP_SETSTATUS (0x0140) +#define CMD_USB_EP_CLRBUFFER (0x00f2) +#define CMD_USB_EP_VALIDATEBUFFER (0x00fa) + +/* Command Data ****************************************************************/ + +/* DEV SETADDRESS command bits */ + +#define CMD_USB_SETADDRESS_DEVEN (0x80) + +/* Command Responses ***********************************************************/ + +/* Device Status Bits (8-bits) */ + +#define USBDEV_DEVSTATUS_CONNECT (0x01) /* Bit 0: Connected */ +#define USBDEV_DEVSTATUS_CONNCHG (0x02) /* Bit 1: Connect change */ +#define USBDEV_DEVSTATUS_SUSPEND (0x04) /* Bit 2: Suspend */ +#define USBDEV_DEVSTATUS_SUSPCHG (0x08) /* Bit 3: Suspend change */ +#define USBDEV_DEVSTATUS_RESET (0x10) /* Bit 4: Bus reset bit */ + +/* EP Select response */ + +#define CMD_USB_EPSELECT_FE (0x01) /* Bit 0=1: IN empty or OUT full */ +#define CMD_USB_EPSELECT_ST (0x02) /* Bit 1=1: Endpoint is stalled */ +#define CMD_USB_EPSELECT_STP (0x04) /* Bit 2=1: Last packet was setup */ +#define CMD_USB_EPSELECT_PO (0x05) /* Bit 3=1: Previous packet was overwritten */ +#define CMD_USB_EPSELECT_EPN (0x10) /* Bit 4=1: NAK sent */ +#define CMD_USB_EPSELECT_B1FULL (0x20) /* Bit 5=1: Buffer 1 full */ +#define CMD_USB_EPSELECT_B2FULL (0x40) /* Bit 6=1: Buffer 2 full */ + +/* EP CLRBUFFER response */ + +#define CMD_USB_CLRBUFFER_PO (0x00000001) + +/* DMA *************************************************************************/ + +/* The DMA descriptor */ + +#define USB_DMADESC_NEXTDDPTR 0 /* Offset 0: Next USB descriptor in RAM */ +#define USB_DMADESC_CONFIG 1 /* Offset 1: DMA configuration info. */ +#define USB_DMADESC_STARTADDR 2 /* Offset 2: DMA start address */ +#define USB_DMADESC_STATUS 3 /* Offset 3: DMA status info (read only) */ +#define USB_DMADESC_ISOCSIZEADDR 4 /* Offset 4: Isoc. packet size address */ + +/* Bit settings for offset 1 */ + +#define USB_DMADESC_MODENORMAL (0x00000000) /* Bits 0-1=00: Mode normal */ +#define USB_DMADESC_MODEATLE (0x00000001) /* Bits 0-1=01: ATLE normal */ +#define USB_DMADESC_NEXTDDVALID (0x00000004) /* Bit 2=1: next descriptor valid */ +#define USB_DMADESC_ISCOEP (0x00000010) /* Bit 4=1: isoc endpoint */ +#define USB_DMADESC_PKTSIZEMASK (0x0000ffe0) /* Bits 5-15: packet size */ +#define USB_DMADESC_PKTSIZESHIFT (5) /* Bits 5-15: packet size */ +#define USB_DMADESC_BUFLENMASK (0xffff0000) /* Bits 16-31: buffer length */ +#define USB_DMADESC_BULENSHIFT (16) /* Bits 16-31: buffer length */ + +/* Bit settings for offset 3 (all must be initialized to zero) */ + +#define USB_DMADESC_STATUSMASK (0x0000001e) /* Bits 1-4: DMA status */ +#define USB_DMADESC_NOTSERVICED (0x00000000) +#define USB_DMADESC_BEINGSERVICED (0x00000002) +#define USB_DMADESC_NORMALCOMPLETION (0x00000004) +#define USB_DMADESC_DATAUNDERRUN (0x00000006) +#define USB_DMADESC_DATAOVERRUN (0x00000010) +#define USB_DMADESC_SYSTEMERROR (0x00000012) +#define USB_DMADESC_PKTVALID (0x00000020) /* Bit 5=1: Packet valid */ +#define USB_DMADESC_LSBEXTRACTED (0x00000040) /* Bit 6=1: LS byte extracted */ +#define USB_DMADESC_MSBEXTRACTED (0x00000080) /* Bit 7=1: MS byte extracted */ +#define USB_DMADESC_MSGLENPOSMASK (0x00003f00) /* Bits 8-13: Message length position */ +#define USB_DMADESC_MSGLENPOSSHIFT (8) /* Bits 8-13: Message length position */ +#define USB_DMADESC_DMACOUNTMASK (0xffff0000) /* Bits 16-31: DMA count */ +#define USB_DMADESC_DMACOUNTSHIFT (16) /* Bits 16-31: DMA count */ + +/* DMA packet size format */ + +#define USB_DMAPKTSIZE_PKTLENMASK (0x0000ffff) /* Bits 0-15: Packet length */ +#define USB_DMAPKTSIZE_PKTLENSHIFT (0) /* Bits 0-15: Packet length */ +#define USB_DMAPKTSIZE_PKTVALID (0x00010000) /* Bit 16=1: Packet valid */ +#define USB_DMAPKTSIZE_FRAMENOMASK (0xfffe0000) /* Bit 17-31: Frame number */ +#define USB_DMAPKTSIZE_FRAMENOSHIFT (17) /* Bit 17-31: Frame number */ + + +/******************************************************************************* + * Private Types + *******************************************************************************/ + +/******************************************************************************* + * Public Data + *******************************************************************************/ + +/******************************************************************************* + * Public Functions + *******************************************************************************/ + +#endif /* __ARCH_ARM_SRC_LPC214X_LPC214X_USBDEV_H */ diff --git a/nuttx/arch/arm/src/lpc214x/lpc214x_vic.h b/nuttx/arch/arm/src/lpc214x/lpc214x_vic.h new file mode 100644 index 000000000..520c6037a --- /dev/null +++ b/nuttx/arch/arm/src/lpc214x/lpc214x_vic.h @@ -0,0 +1,70 @@ +/************************************************************************************ + * arch/arm/src/lpc214x/lpc214x_vic.h + * + * Copyright (C) 2007, 2008 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <gnutt@nuttx.org> + * + * 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. + * + ************************************************************************************/ + +#ifndef __LPC214X_VIC_H +#define __LPC214X_VIC_H + +/************************************************************************************ + * Included Files + ************************************************************************************/ + +/************************************************************************************ + * Definitions + ************************************************************************************/ + +/* All VIC registers are 32-bits wide */ + +#define vic_getreg(o) getreg32(LPC214X_VIC_BASE+(o)) +#define vic_putreg(v,o) putreg32((v),LPC214X_VIC_BASE+(o)) + +/* Vector Control Register bit definitions */ + +#define LPC214X_VECTCNTL_IRQMASK (0x0000001f) +#define LPC214X_VECTCNTL_IRQSHIFT (0) +#define LPC214X_VECTCNTL_ENABLE (1 << 5) + +/************************************************************************************ + * Public Types + ************************************************************************************/ + +/************************************************************************************ + * Inline Functions + ************************************************************************************/ + +/************************************************************************************ + * Public Function Prototypes + ************************************************************************************/ + +#endif /* __LPC214X_VIC_H */ |