From a644488776e351112c0954c867d9aa9fc5361496 Mon Sep 17 00:00:00 2001 From: patacongo Date: Thu, 5 Jul 2012 14:58:16 +0000 Subject: [PATCH] More LPC43 files in various states of work git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@4909 42af7a65-404d-4744-a932-0658087f49c3 --- arch/arm/src/lpc17xx/lpc17_adc.c | 2 +- arch/arm/src/lpc17xx/lpc17_internal.h | 2 +- arch/arm/src/lpc43xx/Make.defs | 11 +- arch/arm/src/lpc43xx/chip/lpc43_rgu.h | 2 +- arch/arm/src/lpc43xx/lpc43_adc.c | 284 ++++ arch/arm/src/lpc43xx/lpc43_adc.h | 95 ++ .../{lpc43_clockconfig.h => lpc43_cgu.h} | 0 arch/arm/src/lpc43xx/lpc43_dac.c | 204 +++ arch/arm/src/lpc43xx/lpc43_dac.h | 95 ++ arch/arm/src/lpc43xx/lpc43_gpdma.c | 226 +++ arch/arm/src/lpc43xx/lpc43_gpdma.h | 236 +++ arch/arm/src/lpc43xx/lpc43_i2c.c | 567 +++++++ arch/arm/src/lpc43xx/lpc43_lowputc.h | 6 +- arch/arm/src/lpc43xx/lpc43_rgu.c | 120 ++ arch/arm/src/lpc43xx/lpc43_rgu.h | 92 ++ arch/arm/src/lpc43xx/lpc43_serial.c | 1452 +++++++++++++++++ arch/arm/src/lpc43xx/lpc43_spi.h | 3 +- arch/arm/src/lpc43xx/lpc43_ssp.h | 3 +- arch/arm/src/lpc43xx/lpc43_start.c | 18 +- 19 files changed, 3407 insertions(+), 11 deletions(-) create mode 100644 arch/arm/src/lpc43xx/lpc43_adc.c create mode 100644 arch/arm/src/lpc43xx/lpc43_adc.h rename arch/arm/src/lpc43xx/{lpc43_clockconfig.h => lpc43_cgu.h} (100%) create mode 100644 arch/arm/src/lpc43xx/lpc43_dac.c create mode 100644 arch/arm/src/lpc43xx/lpc43_dac.h create mode 100644 arch/arm/src/lpc43xx/lpc43_gpdma.c create mode 100644 arch/arm/src/lpc43xx/lpc43_gpdma.h create mode 100644 arch/arm/src/lpc43xx/lpc43_i2c.c create mode 100644 arch/arm/src/lpc43xx/lpc43_rgu.c create mode 100644 arch/arm/src/lpc43xx/lpc43_rgu.h create mode 100644 arch/arm/src/lpc43xx/lpc43_serial.c diff --git a/arch/arm/src/lpc17xx/lpc17_adc.c b/arch/arm/src/lpc17xx/lpc17_adc.c index c250f88e0f..ebc05d13ee 100644 --- a/arch/arm/src/lpc17xx/lpc17_adc.c +++ b/arch/arm/src/lpc17xx/lpc17_adc.c @@ -261,7 +261,7 @@ static int adc_interrupt(int irq, void *context) ****************************************************************************/ /**************************************************************************** - * Name: stm32_adcinitialize + * Name: lpc17_adcinitialize * * Description: * Initialize the adc diff --git a/arch/arm/src/lpc17xx/lpc17_internal.h b/arch/arm/src/lpc17xx/lpc17_internal.h index a3d03b5db5..8b43581969 100644 --- a/arch/arm/src/lpc17xx/lpc17_internal.h +++ b/arch/arm/src/lpc17xx/lpc17_internal.h @@ -797,7 +797,7 @@ EXTERN void lpc17_dmadump(DMA_HANDLE handle, const struct lpc17_dmaregs_s *regs, #endif /**************************************************************************** - * Name: stm32_adcinitialize + * Name: lpc17_adcinitialize * * Description: * Initialize the adc diff --git a/arch/arm/src/lpc43xx/Make.defs b/arch/arm/src/lpc43xx/Make.defs index f4598adca6..a6682a272c 100644 --- a/arch/arm/src/lpc43xx/Make.defs +++ b/arch/arm/src/lpc43xx/Make.defs @@ -59,7 +59,7 @@ endif CHIP_ASRCS = CHIP_CSRCS = lpc43_clrpend.c lpc43_gpio.c lpc43_irq.c lpc43_lowputc.c -CHIP_CSRCS += lpc43_pinconfig.c lpc43_start.c lpc43_timerisr.c +CHIP_CSRCS += lpc43_pinconfig.c lpc43_rgu.c lpc43_start.c lpc43_timerisr.c ifneq ($(CONFIG_IDLE_CUSTOM),y) CHIP_CSRCS += lpc43_idle.c @@ -81,3 +81,12 @@ CHIP_CSRCS += lpc43_ssp.c endif endif +ifeq ($(CONFIG_LPC43_I2C0),y) +CHIP_CSRCS += lpc43_i2c.c +else +ifeq ($(CONFIG_LPC43_I2C1),y) +CHIP_CSRCS += lpc43_i2c.c +endif +endif + + diff --git a/arch/arm/src/lpc43xx/chip/lpc43_rgu.h b/arch/arm/src/lpc43xx/chip/lpc43_rgu.h index d0338e176f..acf2fdc5d8 100644 --- a/arch/arm/src/lpc43xx/chip/lpc43_rgu.h +++ b/arch/arm/src/lpc43xx/chip/lpc43_rgu.h @@ -624,7 +624,7 @@ /* Bits 27-31: Reserved */ /* Reset external status register 0 for CORE_RST */ -#define RGU_EXTSTAT_CORE_EXTRESET (1 << 0) /* Bit 0: Reset activated by external reset from reset pin +#define RGU_EXTSTAT_CORE_EXTRESET (1 << 0) /* Bit 0: Reset activated by external reset from reset pin */ /* Bits 1-3: Reserved */ #define RGU_EXTSTAT_CORE_BODRESET (1 << 4) /* Bit 4: Reset activated by BOD reset */ #define RGU_EXTSTAT_CORE_WWDTRESET (1 << 5) /* Bit 5: Reset activated by WWDT time-out */ diff --git a/arch/arm/src/lpc43xx/lpc43_adc.c b/arch/arm/src/lpc43xx/lpc43_adc.c new file mode 100644 index 0000000000..a6489a6d08 --- /dev/null +++ b/arch/arm/src/lpc43xx/lpc43_adc.c @@ -0,0 +1,284 @@ +/************************************************************************************ + * arch/arm/src/lpc43xx/lpc43_adc.c + * + * Copyright (C) 2012 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Ported from from the LPC17 version: + * + * Copyright (C) 2011 Li Zhuoyi. All rights reserved. + * Author: Li Zhuoyi + * History: 0.1 2011-08-05 initial version + * + * This file is a part of NuttX: + * + * Copyright (C) 2010-2012 Gregory Nutt. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ************************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "up_internal.h" +#include "up_arch.h" + +#include "chip.h" +#include "lpc43_internal.h" +#include "lpc43_syscon.h" +#include "lpc43_pinconn.h" +#include "lpc43_adc.h" + +#if defined(CONFIG_LPC43_ADC) + +#ifndef CONFIG_ADC0_MASK +#define CONFIG_ADC0_MASK 0x01 +#endif +#ifndef CONFIG_ADC0_SPS +#define CONFIG_ADC0_SPS 1000 +#endif +#ifndef CONFIG_ADC0_AVERAGE +#define CONFIG_ADC0_AVERAGE 200 +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct up_dev_s +{ + uint8_t mask; + uint32_t sps; + int irq; + int32_t buf[8]; + uint8_t count[8]; +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* ADC methods */ + +static void adc_reset(FAR struct adc_dev_s *dev); +static int adc_setup(FAR struct adc_dev_s *dev); +static void adc_shutdown(FAR struct adc_dev_s *dev); +static void adc_rxint(FAR struct adc_dev_s *dev, bool enable); +static int adc_ioctl(FAR struct adc_dev_s *dev, int cmd, unsigned long arg); +static int adc_interrupt(int irq, void *context); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const struct adc_ops_s g_adcops = +{ + .ao_reset =adc_reset, + .ao_setup = adc_setup, + .ao_shutdown = adc_shutdown, + .ao_rxint = adc_rxint, + .ao_ioctl = adc_ioctl, +}; + +static struct up_dev_s g_adcpriv = +{ + .sps = CONFIG_ADC0_SPS, + .mask = CONFIG_ADC0_MASK, + .irq = LPC43_IRQ_ADC, +}; + +static struct adc_dev_s g_adcdev = +{ + .ad_ops = &g_adcops, + .ad_priv= &g_adcpriv, +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/* Reset the ADC device. Called early to initialize the hardware. This + * is called, before ao_setup() and on error conditions. + */ + +static void adc_reset(FAR struct adc_dev_s *dev) +{ + irqstate_t flags; + uint32_t regval; + FAR struct up_dev_s *priv = (FAR struct up_dev_s *)dev->ad_priv; + + flags = irqsave(); + + regval = getreg32(LPC43_SYSCON_PCONP); + regval |= SYSCON_PCONP_PCADC; + putreg32(regval, LPC43_SYSCON_PCONP); + + putreg32(ADC_CR_PDN,LPC43_ADC_CR); + + regval = getreg32(LPC43_SYSCON_PCLKSEL0); + regval &= ~SYSCON_PCLKSEL0_ADC_MASK; + regval |= (SYSCON_PCLKSEL_CCLK8 << SYSCON_PCLKSEL0_ADC_SHIFT); + putreg32(regval, LPC43_SYSCON_PCLKSEL0); + + uint32_t clkdiv=LPC43_CCLK/8/65/priv->sps; + clkdiv<<=8; + clkdiv&=0xff00; + putreg32(ADC_CR_PDN|ADC_CR_BURST|clkdiv|priv->mask,LPC43_ADC_CR); + + if(priv->mask&0x01) + lpc43_configgpio(GPIO_AD0p0); + else if(priv->mask&0x02) + lpc43_configgpio(GPIO_AD0p1); + else if(priv->mask&0x04) + lpc43_configgpio(GPIO_AD0p2); + else if(priv->mask&0x08) + lpc43_configgpio(GPIO_AD0p3); + else if(priv->mask&0x10) + lpc43_configgpio(GPIO_AD0p4); + else if(priv->mask&0x20) + lpc43_configgpio(GPIO_AD0p5); + else if(priv->mask&0x40) + lpc43_configgpio(GPIO_AD0p6); + else if(priv->mask&0x80) + lpc43_configgpio(GPIO_AD0p7); + + irqrestore(flags); +} + +/* Configure the ADC. This method is called the first time that the ADC + * device is opened. This will occur when the port is first opened. + * This setup includes configuring and attaching ADC interrupts. Interrupts + * are all disabled upon return. + */ + +static int adc_setup(FAR struct adc_dev_s *dev) +{ + int i; + FAR struct up_dev_s *priv = (FAR struct up_dev_s *)dev->ad_priv; + int ret = irq_attach(priv->irq, adc_interrupt); + if (ret == OK) + { + for (i = 0; i < 8; i++) + { + priv->buf[i]=0; + priv->count[i]=0; + } + up_enable_irq(priv->irq); + } + return ret; +} + +/* Disable the ADC. This method is called when the ADC device is closed. + * This method reverses the operation the setup method. + */ + +static void adc_shutdown(FAR struct adc_dev_s *dev) +{ + FAR struct up_dev_s *priv = (FAR struct up_dev_s *)dev->ad_priv; + up_disable_irq(priv->irq); + irq_detach(priv->irq); +} + +/* Call to enable or disable RX interrupts */ + +static void adc_rxint(FAR struct adc_dev_s *dev, bool enable) +{ + FAR struct up_dev_s *priv = (FAR struct up_dev_s *)dev->ad_priv; + if (enable) + putreg32(ADC_INTEN_GLOBAL, LPC43_ADC_INTEN); + else + putreg32(0x00, LPC43_ADC_INTEN); +} + +/* All ioctl calls will be routed through this method */ + +static int adc_ioctl(FAR struct adc_dev_s *dev, int cmd, unsigned long arg) +{ + dbg("Fix me:Not Implemented\n"); + return 0; +} + +static int adc_interrupt(int irq, void *context) +{ + uint32_t regval; + FAR struct up_dev_s *priv = (FAR struct up_dev_s *)g_adcdev.ad_priv; + unsigned char ch; + int32_t value; + + regval = getreg32(LPC43_ADC_GDR); + ch = (regval >> 24) & 0x07; + priv->buf[ch] += regval & 0xfff0; + priv->count[ch]++; + if (priv->count[ch] >= CONFIG_ADC0_AVERAGE) + { + value = priv->buf[ch] / priv->count[ch]; + value <<= 15; + adc_receive(&g_adcdev,ch,value); + priv->buf[ch] = 0; + priv->count[ch] = 0; + } + return OK; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: stm32_adcinitialize + * + * Description: + * Initialize the adc + * + * Returned Value: + * Valid can device structure reference on succcess; a NULL on failure + * + ****************************************************************************/ + +FAR struct adc_dev_s *lpc43_adcinitialize(void) +{ + return &g_adcdev; +} +#endif + diff --git a/arch/arm/src/lpc43xx/lpc43_adc.h b/arch/arm/src/lpc43xx/lpc43_adc.h new file mode 100644 index 0000000000..ae8cef6c18 --- /dev/null +++ b/arch/arm/src/lpc43xx/lpc43_adc.h @@ -0,0 +1,95 @@ +/**************************************************************************** + * arch/arm/src/lpc43xx/lpc43_adc.h + * + * Copyright (C) 2012 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_LPC43XX_LPC43_ADC_H +#define __ARCH_ARM_SRC_LPC43XX_LPC43_ADC_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include "chip/lpc43_adc.h" + +#ifdef CONFIG_LPC43_ADC + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" { +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: lpc43_adcinitialize + * + * Description: + * Initialize the adc + * + * Returned Value: + * Valid can device structure reference on succcess; a NULL on failure + * + ****************************************************************************/ + +FAR struct adc_dev_s *lpc43_adcinitialize(void); + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* CONFIG_LPC43_ADC */ +#endif /* __ARCH_ARM_SRC_LPC43XX_LPC43_ADC_H */ diff --git a/arch/arm/src/lpc43xx/lpc43_clockconfig.h b/arch/arm/src/lpc43xx/lpc43_cgu.h similarity index 100% rename from arch/arm/src/lpc43xx/lpc43_clockconfig.h rename to arch/arm/src/lpc43xx/lpc43_cgu.h diff --git a/arch/arm/src/lpc43xx/lpc43_dac.c b/arch/arm/src/lpc43xx/lpc43_dac.c new file mode 100644 index 0000000000..5fcceaa1ee --- /dev/null +++ b/arch/arm/src/lpc43xx/lpc43_dac.c @@ -0,0 +1,204 @@ +/************************************************************************************ + * arch/arm/src/lpc43xx/lpc43_dac.c + * + * Copyright (C) 2012 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Ported from from the LPC17 version: + * + * Copyright (C) 2011 Li Zhuoyi. All rights reserved. + * Author: Li Zhuoyi + * History: 0.1 2011-08-05 initial version + * + * This file is a part of NuttX: + * + * Copyright (C) 2010-2012 Gregory Nutt. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ************************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "up_internal.h" +#include "up_arch.h" + +#include "chip.h" + +#include "lpc43_syscon.h" +#include "lpc43_pinconn.h" +#include "lpc43_dac.h" + +#ifdef CONFIG_LPC43_DAC + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* DAC methods */ + +static void dac_reset(FAR struct dac_dev_s *dev); +static int dac_setup(FAR struct dac_dev_s *dev); +static void dac_shutdown(FAR struct dac_dev_s *dev); +static void dac_txint(FAR struct dac_dev_s *dev, bool enable); +static int dac_send(FAR struct dac_dev_s *dev, FAR struct dac_msg_s *msg); +static int dac_ioctl(FAR struct dac_dev_s *dev, int cmd, unsigned long arg); +static int dac_interrupt(int irq, void *context); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const struct dac_ops_s g_dacops = +{ + .ao_reset =dac_reset, + .ao_setup = dac_setup, + .ao_shutdown = dac_shutdown, + .ao_txint = dac_txint, + .ao_send = dac_send, + .ao_ioctl = dac_ioctl, +}; + +static struct dac_dev_s g_dacdev = +{ + .ad_ops = &g_dacops, +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/* Reset the DAC device. Called early to initialize the hardware. This + * is called, before ao_setup() and on error conditions. + */ + +static void dac_reset(FAR struct dac_dev_s *dev) +{ + irqstate_t flags; + uint32_t regval; + + flags = irqsave(); + + regval = getreg32(LPC43_SYSCON_PCLKSEL0); + regval &= ~SYSCON_PCLKSEL0_DAC_MASK; + regval |= (SYSCON_PCLKSEL_CCLK8 << SYSCON_PCLKSEL0_DAC_SHIFT); + putreg32(regval, LPC43_SYSCON_PCLKSEL0); + + //putreg32(DAC_CTRL_DBLBUFEN,LPC43_DAC_CTRL); ? + + lpc43_configgpio(GPIO_AOUT); + + irqrestore(flags); +} + +/* Configure the DAC. This method is called the first time that the DAC + * device is opened. This will occur when the port is first opened. + * This setup includes configuring and attaching DAC interrupts. Interrupts + * are all disabled upon return. + */ + +static int dac_setup(FAR struct dac_dev_s *dev) +{ + return OK; +} + +/* Disable the DAC. This method is called when the DAC device is closed. + * This method reverses the operation the setup method. + */ + +static void dac_shutdown(FAR struct dac_dev_s *dev) +{ +} + +/* Call to enable or disable TX interrupts */ + +static void dac_txint(FAR struct dac_dev_s *dev, bool enable) +{ +} + +static int dac_send(FAR struct dac_dev_s *dev, FAR struct dac_msg_s *msg) +{ + putreg32((msg->am_data>>16)&0xfffff,LPC43_DAC_CR); + dac_txdone(&g_dacdev); + return 0; +} + +/* All ioctl calls will be routed through this method */ + +static int dac_ioctl(FAR struct dac_dev_s *dev, int cmd, unsigned long arg) +{ + dbg("Fix me:Not Implemented\n"); + return 0; +} + +static int dac_interrupt(int irq, void *context) +{ +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: lpc43_dacinitialize + * + * Description: + * Initialize the DAC + * + * Returned Value: + * Valid dac device structure reference on succcess; a NULL on failure + * + ****************************************************************************/ + +FAR struct dac_dev_s *lpc43_dacinitialize(void) +{ + return &g_dacdev; +} + +#endif /* CONFIG_LPC43_DAC */ + diff --git a/arch/arm/src/lpc43xx/lpc43_dac.h b/arch/arm/src/lpc43xx/lpc43_dac.h new file mode 100644 index 0000000000..310e29f510 --- /dev/null +++ b/arch/arm/src/lpc43xx/lpc43_dac.h @@ -0,0 +1,95 @@ +/**************************************************************************** + * arch/arm/src/lpc43xx/lpc43_dac.h + * + * Copyright (C) 2012 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_LPC43XX_LPC43_DAC_H +#define __ARCH_ARM_SRC_LPC43XX_LPC43_DAC_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include "chip/lpc43_dac.h" + +#ifdef CONFIG_LPC43_DAC + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" { +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: lpc43_dacinitialize + * + * Description: + * Initialize the DAC + * + * Returned Value: + * Valid dac device structure reference on succcess; a NULL on failure + * + ****************************************************************************/ + +EXTERN FAR struct dac_dev_s *lpc43_dacinitialize(void); + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* CONFIG_LPC43_DAC */ +#endif /* __ARCH_ARM_SRC_LPC43XX_LPC43_DAC_H */ diff --git a/arch/arm/src/lpc43xx/lpc43_gpdma.c b/arch/arm/src/lpc43xx/lpc43_gpdma.c new file mode 100644 index 0000000000..4cfc0327fa --- /dev/null +++ b/arch/arm/src/lpc43xx/lpc43_gpdma.c @@ -0,0 +1,226 @@ +/**************************************************************************** + * arch/arm/src/lpc43xx/lpc43_gpdma.c + * + * Copyright (C) 2012 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include + +#include + +#include "up_internal.h" +#include "up_arch.h" + +#include "chip.h" + +#include "lpc43_syscon.h" +#include "lpc43_gpdma.h" + +#ifdef CONFIG_LPC43_GPDMA + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +/* Enables debug output from this file (needs CONFIG_DEBUG too) */ + +#undef DMA_DEBUG /* Define to enable debug */ +#undef DMA_VERBOSE /* Define to enable verbose debug */ + +#ifdef DMA_DEBUG +# define dmadbg lldbg +# ifdef DMA_VERBOSE +# define spivdbg lldbg +# else +# define spivdbg(x...) +# endif +#else +# undef DMA_VERBOSE +# define dmadbg(x...) +# define spivdbg(x...) +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: lpc43_dmainitialize + * + * Description: + * Initialize the GPDMA subsystem. + * + * Returned Value: + * None + * + ****************************************************************************/ + +void lpc43_dmainitilaize(void) +{ +} + +/**************************************************************************** + * Name: lpc43_dmachannel + * + * Description: + * Allocate a DMA channel. This function sets aside a DMA channel and + * gives the caller exclusive access to the DMA channel. + * + * Returned Value: + * One success, this function returns a non-NULL, void* DMA channel + * handle. NULL is returned on any failure. This function can fail only + * if no DMA channel is available. + * + ****************************************************************************/ + +DMA_HANDLE lpc43_dmachannel(void) +{ + return NULL; +} + +/**************************************************************************** + * Name: lpc43_dmafree + * + * Description: + * Release a DMA channel. NOTE: The 'handle' used in this argument must + * NEVER be used again until lpc43_dmachannel() is called again to re-gain + * a valid handle. + * + * Returned Value: + * None + * + ****************************************************************************/ + +void lpc43_dmafree(DMA_HANDLE handle) +{ +} + +/**************************************************************************** + * Name: lpc43_dmasetup + * + * Description: + * Configure DMA for one transfer. + * + ****************************************************************************/ + +int lpc43_dmarxsetup(DMA_HANDLE handle, uint32_t control, uint32_t config, + uint32_t srcaddr, uint32_t destaddr, size_t nbytes) +{ + return -ENOSYS; +} + +/**************************************************************************** + * Name: lpc43_dmastart + * + * Description: + * Start the DMA transfer + * + ****************************************************************************/ + +int lpc43_dmastart(DMA_HANDLE handle, dma_callback_t callback, void *arg) +{ + return -ENOSYS; +} + +/**************************************************************************** + * Name: lpc43_dmastop + * + * Description: + * Cancel the DMA. After lpc43_dmastop() is called, the DMA channel is + * reset and lpc43_dmasetup() must be called before lpc43_dmastart() can be + * called again + * + ****************************************************************************/ + +void lpc43_dmastop(DMA_HANDLE handle) +{ +} + +/**************************************************************************** + * Name: lpc43_dmasample + * + * Description: + * Sample DMA register contents + * + ****************************************************************************/ + +#ifdef CONFIG_DEBUG_DMA +void lpc43_dmasample(DMA_HANDLE handle, struct lpc43_dmaregs_s *regs) +{ +} +#endif /* CONFIG_DEBUG_DMA */ + +/**************************************************************************** + * Name: lpc43_dmadump + * + * Description: + * Dump previously sampled DMA register contents + * + ****************************************************************************/ + +#ifdef CONFIG_DEBUG_DMA +void lpc43_dmadump(DMA_HANDLE handle, const struct lpc43_dmaregs_s *regs, const char *msg) +{ +} +#endif /* CONFIG_DEBUG_DMA */ + +#endif /* CONFIG_LPC43_GPDMA */ diff --git a/arch/arm/src/lpc43xx/lpc43_gpdma.h b/arch/arm/src/lpc43xx/lpc43_gpdma.h new file mode 100644 index 0000000000..68469d9b6e --- /dev/null +++ b/arch/arm/src/lpc43xx/lpc43_gpdma.h @@ -0,0 +1,236 @@ +/**************************************************************************** + * arch/arm/src/lpc43xx/lpc43_gpdma.h + * + * Copyright (C) 2012 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_LPC43XX_LP43_GPDMA_H +#define __ARCH_ARM_SRC_LPC43XX_LP43_GPDMA_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include "chip/lpc43_gpdma.h" + +#ifdef CONFIG_LPC43_GPDMA + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +typedef FAR void *DMA_HANDLE; +typedef void (*dma_callback_t)(DMA_HANDLE handle, void *arg, int result); + +/* The following is used for sampling DMA registers when CONFIG DEBUG_DMA is selected */ + +#ifdef CONFIG_DEBUG_DMA +struct lpc43_dmaglobalregs_s +{ + /* Global Registers */ + + uint32_t intst; /* DMA Interrupt Status Register */ + uint32_t inttcst; /* DMA Interrupt Terminal Count Request Status Register */ + uint32_t interrst; /* DMA Interrupt Error Status Register */ + uint32_t rawinttcst; /* DMA Raw Interrupt Terminal Count Status Register */ + uint32_t rawinterrst; /* DMA Raw Error Interrupt Status Register */ + uint32_t enbldchns; /* DMA Enabled Channel Register */ + uint32_t softbreq; /* DMA Software Burst Request Register */ + uint32_t softsreq; /* DMA Software Single Request Register */ + uint32_t softlbreq; /* DMA Software Last Burst Request Register */ + uint32_t softlsreq; /* DMA Software Last Single Request Register */ + uint32_t config; /* DMA Configuration Register */ + uint32_t sync; /* DMA Synchronization Register */ +}; + +struct lpc43_dmachanregs_s +{ + /* Channel Registers */ + + uint32_t srcaddr; /* DMA Channel Source Address Register */ + uint32_t destaddr; /* DMA Channel Destination Address Register */ + uint32_t lli; /* DMA Channel Linked List Item Register */ + uint32_t control; /* DMA Channel Control Register */ + uint32_t config; /* DMA Channel Configuration Register */ +}; + +struct lpc43_dmaregs_s +{ + /* Global Registers */ + + struct lpc43_dmaglobalregs_s gbl; + + /* Channel Registers */ + + struct lpc43_dmachanregs_s ch; +}; +#endif + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" { +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: lpc43_dmainitialize + * + * Description: + * Initialize the GPDMA subsystem. + * + * Returned Value: + * None + * + ****************************************************************************/ + +EXTERN void lpc43_dmainitilaize(void); + +/**************************************************************************** + * Name: lpc43_dmachannel + * + * Description: + * Allocate a DMA channel. This function sets aside a DMA channel and + * gives the caller exclusive access to the DMA channel. + * + * Returned Value: + * One success, this function returns a non-NULL, void* DMA channel + * handle. NULL is returned on any failure. This function can fail only + * if no DMA channel is available. + * + ****************************************************************************/ + +EXTERN DMA_HANDLE lpc43_dmachannel(void); + +/**************************************************************************** + * Name: lpc43_dmafree + * + * Description: + * Release a DMA channel. NOTE: The 'handle' used in this argument must + * NEVER be used again until lpc43_dmachannel() is called again to re-gain + * a valid handle. + * + * Returned Value: + * None + * + ****************************************************************************/ + +EXTERN void lpc43_dmafree(DMA_HANDLE handle); + +/**************************************************************************** + * Name: lpc43_dmasetup + * + * Description: + * Configure DMA for one transfer. + * + ****************************************************************************/ + +EXTERN int lpc43_dmarxsetup(DMA_HANDLE handle, + uint32_t control, uint32_t config, + uint32_t srcaddr, uint32_t destaddr, + size_t nbytes); + +/**************************************************************************** + * Name: lpc43_dmastart + * + * Description: + * Start the DMA transfer + * + ****************************************************************************/ + +EXTERN int lpc43_dmastart(DMA_HANDLE handle, dma_callback_t callback, void *arg); + +/**************************************************************************** + * Name: lpc43_dmastop + * + * Description: + * Cancel the DMA. After lpc43_dmastop() is called, the DMA channel is + * reset and lpc43_dmasetup() must be called before lpc43_dmastart() can be + * called again + * + ****************************************************************************/ + +EXTERN void lpc43_dmastop(DMA_HANDLE handle); + +/**************************************************************************** + * Name: lpc43_dmasample + * + * Description: + * Sample DMA register contents + * + ****************************************************************************/ + +#ifdef CONFIG_DEBUG_DMA +EXTERN void lpc43_dmasample(DMA_HANDLE handle, struct lpc43_dmaregs_s *regs); +#else +# define lpc43_dmasample(handle,regs) +#endif + +/**************************************************************************** + * Name: lpc43_dmadump + * + * Description: + * Dump previously sampled DMA register contents + * + ****************************************************************************/ + +#ifdef CONFIG_DEBUG_DMA +EXTERN void lpc43_dmadump(DMA_HANDLE handle, const struct lpc43_dmaregs_s *regs, + const char *msg); +#else +# define lpc43_dmadump(handle,regs,msg) +#endif + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* CONFIG_LPC43_GPDMA */ +#endif /* __ARCH_ARM_SRC_LPC43XX_LP43_GPDMA_H */ diff --git a/arch/arm/src/lpc43xx/lpc43_i2c.c b/arch/arm/src/lpc43xx/lpc43_i2c.c new file mode 100644 index 0000000000..64a044f135 --- /dev/null +++ b/arch/arm/src/lpc43xx/lpc43_i2c.c @@ -0,0 +1,567 @@ +/******************************************************************************* + * arch/arm/src/lpc43xx/lpc43_i2c.c + * + * Copyright (C) 2012 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Ported from from the LPC17 version: + * + * Copyright (C) 2011 Li Zhuoyi. All rights reserved. + * Author: Li Zhuoyi + * History: 0.1 2011-08-20 initial version + * + * Derived from arch/arm/src/lpc31xx/lpc31_i2c.c + * + * Author: David Hewson + * + * Copyright (C) 2010-2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + *******************************************************************************/ + +/******************************************************************************* + * Included Files + *******************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include "wdog.h" +#include "chip.h" +#include "up_arch.h" +#include "up_internal.h" +#include "os_internal.h" + +#include "lpc43_syscon.h" +#include "lpc43_pinconn.h" +#include "lpc43_i2c.h" + +#if defined(CONFIG_LPC43_I2C0) || defined(CONFIG_LPC43_I2C1) + +#ifndef GPIO_I2C1_SCL + #define GPIO_I2C1_SCL GPIO_I2C1_SCL_1 + #define GPIO_I2C1_SDA GPIO_I2C1_SDA_1 +#endif +#ifndef CONFIG_I2C0_FREQ + #define CONFIG_I2C0_FREQ 100000 +#endif +#ifndef CONFIG_I2C1_FREQ + #define CONFIG_I2C1_FREQ 100000 +#endif +#ifndef CONFIG_I2C2_FREQ + #define CONFIG_I2C2_FREQ 100000 +#endif + +/******************************************************************************* + * Definitions + *******************************************************************************/ + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define I2C_TIMEOUT ((20 * CLK_TCK) / 1000) /* 20 mS */ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +struct lpc43_i2cdev_s +{ + struct i2c_dev_s dev; /* Generic I2C device */ + struct i2c_msg_s msg; /* a single message for legacy read/write */ + unsigned int base; /* Base address of registers */ + uint16_t irqid; /* IRQ for this device */ + + sem_t mutex; /* Only one thread can access at a time */ + sem_t wait; /* Place to wait for state machine completion */ + volatile uint8_t state; /* State of state machine */ + WDOG_ID timeout; /* watchdog to timeout when bus hung */ + + uint16_t wrcnt; /* number of bytes sent to tx fifo */ + uint16_t rdcnt; /* number of bytes read from rx fifo */ +}; + +#ifdef CONFIG_LPC43_I2C0 +static struct lpc43_i2cdev_s g_i2c0dev; +#endif +#ifdef CONFIG_LPC43_I2C1 +static struct lpc43_i2cdev_s g_i2c1dev; +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static int i2c_start(struct lpc43_i2cdev_s *priv); +static void i2c_stop(struct lpc43_i2cdev_s *priv); +static int i2c_interrupt(int irq, FAR void *context); +static void i2c_timeout(int argc, uint32_t arg, ...); + +/**************************************************************************** + * I2C device operations + ****************************************************************************/ + +static uint32_t i2c_setfrequency(FAR struct i2c_dev_s *dev, + uint32_t frequency); +static int i2c_setaddress(FAR struct i2c_dev_s *dev, int addr, + int nbits); +static int i2c_write(FAR struct i2c_dev_s *dev, const uint8_t *buffer, + int buflen); +static int i2c_read(FAR struct i2c_dev_s *dev, uint8_t *buffer, + int buflen); +static int i2c_transfer(FAR struct i2c_dev_s *dev, + FAR struct i2c_msg_s *msgs, int count); + +struct i2c_ops_s lpc43_i2c_ops = +{ + .setfrequency = i2c_setfrequency, + .setaddress = i2c_setaddress, + .write = i2c_write, + .read = i2c_read, +#ifdef CONFIG_I2C_TRANSFER + .transfer = i2c_transfer +#endif +}; + +/******************************************************************************* + * Name: lpc43_i2c_setfrequency + * + * Description: + * Set the frequence for the next transfer + * + *******************************************************************************/ + +static uint32_t i2c_setfrequency(FAR struct i2c_dev_s *dev, uint32_t frequency) +{ + struct lpc43_i2cdev_s *priv = (struct lpc43_i2cdev_s *) dev; + + if (frequency > 100000) + { + /* asymetric per 400Khz I2C spec */ + + putreg32(LPC43_CCLK / (83 + 47) * 47 / frequency, priv->base + LPC43_I2C_SCLH_OFFSET); + putreg32(LPC43_CCLK / (83 + 47) * 83 / frequency, priv->base + LPC43_I2C_SCLL_OFFSET); + } + else + { + /* 50/50 mark space ratio */ + + putreg32(LPC43_CCLK / 100 * 50 / frequency, priv->base + LPC43_I2C_SCLH_OFFSET); + putreg32(LPC43_CCLK / 100 * 50 / frequency, priv->base + LPC43_I2C_SCLL_OFFSET); + } + + /* FIXME: This function should return the actual selected frequency */ + + return frequency; +} + +/******************************************************************************* + * Name: lpc43_i2c_setaddress + * + * Description: + * Set the I2C slave address for a subsequent read/write + * + *******************************************************************************/ + +static int i2c_setaddress(FAR struct i2c_dev_s *dev, int addr, int nbits) +{ + struct lpc43_i2cdev_s *priv = (struct lpc43_i2cdev_s *)dev; + + DEBUGASSERT(dev != NULL); + DEBUGASSERT(nbits == 7); + + priv->msg.addr = addr << 1; + priv->msg.flags = 0 ; + + return OK; +} + +/******************************************************************************* + * Name: lpc43_i2c_write + * + * Description: + * Send a block of data on I2C using the previously selected I2C + * frequency and slave address. + * + *******************************************************************************/ + +static int i2c_write(FAR struct i2c_dev_s *dev, const uint8_t *buffer, + int buflen) +{ + struct lpc43_i2cdev_s *priv = (struct lpc43_i2cdev_s *)dev; + int ret; + + DEBUGASSERT(dev != NULL); + + priv->wrcnt = 0; + priv->rdcnt = 0; + priv->msg.addr &= ~0x01; + priv->msg.buffer = (uint8_t*)buffer; + priv->msg.length = buflen; + + ret = i2c_start(priv); + + return ret > 0 ? OK : -ETIMEDOUT; +} + +/******************************************************************************* + * Name: lpc43_i2c_read + * + * Description: + * Receive a block of data on I2C using the previously selected I2C + * frequency and slave address. + * + *******************************************************************************/ + +static int i2c_read(FAR struct i2c_dev_s *dev, uint8_t *buffer, int buflen) +{ + struct lpc43_i2cdev_s *priv = (struct lpc43_i2cdev_s *)dev; + int ret; + + DEBUGASSERT(dev != NULL); + + priv->wrcnt=0; + priv->rdcnt=0; + priv->msg.addr |= 0x01; + priv->msg.buffer = buffer; + priv->msg.length = buflen; + + ret = i2c_start(priv); + + return ret >0 ? OK : -ETIMEDOUT; +} + +/******************************************************************************* + * Name: i2c_start + * + * Description: + * Perform a I2C transfer start + * + *******************************************************************************/ + +static int i2c_start(struct lpc43_i2cdev_s *priv) +{ + int ret = -1; + + sem_wait(&priv->mutex); + + putreg32(I2C_CONCLR_STAC|I2C_CONCLR_SIC,priv->base+LPC43_I2C_CONCLR_OFFSET); + putreg32(I2C_CONSET_STA,priv->base+LPC43_I2C_CONSET_OFFSET); + + wd_start(priv->timeout, I2C_TIMEOUT, i2c_timeout, 1, (uint32_t)priv); + sem_wait(&priv->wait); + wd_cancel(priv->timeout); + sem_post(&priv->mutex); + + if (priv-> state == 0x18 || priv->state == 0x28) + { + ret = priv->wrcnt; + } + else if (priv-> state == 0x50 || priv->state == 0x58) + { + ret = priv->rdcnt; + } + + return ret; +} + +/******************************************************************************* + * Name: i2c_stop + * + * Description: + * Perform a I2C transfer stop + * + *******************************************************************************/ + +static void i2c_stop(struct lpc43_i2cdev_s *priv) +{ + if (priv->state != 0x38) + { + putreg32(I2C_CONSET_STO|I2C_CONSET_AA,priv->base+LPC43_I2C_CONSET_OFFSET); + } + + sem_post(&priv->wait); +} + +/******************************************************************************* + * Name: i2c_timeout + * + * Description: + * Watchdog timer for timeout of I2C operation + * + *******************************************************************************/ + +static void i2c_timeout(int argc, uint32_t arg, ...) +{ + struct lpc43_i2cdev_s *priv = (struct lpc43_i2cdev_s *)arg; + + irqstate_t flags = irqsave(); + priv->state = 0xff; + sem_post(&priv->wait); + irqrestore(flags); +} + +/******************************************************************************* + * Name: i2c_interrupt + * + * Description: + * The I2C Interrupt Handler + * + *******************************************************************************/ + +static int i2c_interrupt(int irq, FAR void *context) +{ + struct lpc43_i2cdev_s *priv; + uint32_t state; + +#ifdef CONFIG_LPC43_I2C0 + if (irq == LPC43_IRQ_I2C0) + { + priv = &g_i2c0dev; + } + else +#endif +#ifdef CONFIG_LPC43_I2C1 + if (irq == LPC43_IRQ_I2C1) + { + priv = &g_i2c1dev; + } + else +#endif + { + PANIC(OSERR_INTERNAL); + } + + /* Reference UM10360 19.10.5 */ + + state = getreg32(priv->base+LPC43_I2C_STAT_OFFSET); + putreg32(I2C_CONCLR_SIC, priv->base + LPC43_I2C_CONCLR_OFFSET); + + priv->state = state; + state &= 0xf8; + switch (state) + { + case 0x00: /* Bus Error */ + case 0x20: + case 0x30: + case 0x38: + case 0x48: + i2c_stop(priv); + break; + + case 0x08: /* START */ + case 0x10: /* Repeated START */ + putreg32(priv->msg.addr, priv->base + LPC43_I2C_DAT_OFFSET); + putreg32(I2C_CONCLR_STAC, priv->base + LPC43_I2C_CONCLR_OFFSET); + break; + + case 0x18: + priv->wrcnt=0; + putreg32(priv->msg.buffer[0], priv->base + LPC43_I2C_DAT_OFFSET); + break; + + case 0x28: + priv->wrcnt++; + if (priv->wrcnt < priv->msg.length) + { + putreg32(priv->msg.buffer[priv->wrcnt],priv->base+LPC43_I2C_DAT_OFFSET); + } + else + { + i2c_stop(priv); + } + break; + + case 0x40: + priv->rdcnt = -1; + putreg32(I2C_CONSET_AA, priv->base + LPC43_I2C_CONSET_OFFSET); + break; + + case 0x50: + priv->rdcnt++; + if (priv->rdcnt < priv->msg.length) + { + priv->msg.buffer[priv->rdcnt]=getreg32(priv->base+LPC43_I2C_BUFR_OFFSET); + } + + if (priv->rdcnt >= priv->msg.length - 1) + { + putreg32(I2C_CONCLR_AAC|I2C_CONCLR_SIC,priv->base+LPC43_I2C_CONCLR_OFFSET); + } + break; + + case 0x58: + i2c_stop(priv); + break; + + default: + i2c_stop(priv); + break; + } + + return OK; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/******************************************************************************* + * Name: up_i2cinitialize + * + * Description: + * Initialise an I2C device + * + *******************************************************************************/ + +struct i2c_dev_s *up_i2cinitialize(int port) +{ + struct lpc43_i2cdev_s *priv; + + if (port>2) + { + dbg("lpc I2C Only support 0,1,2\n"); + return NULL; + } + + irqstate_t flags; + uint32_t regval; + + flags = irqsave(); + +#ifdef CONFIG_LPC43_I2C0 + if (port == 0) + { + priv = &g_i2c0dev; + priv->base = LPC43_I2C0_BASE; + priv->irqid = LPC43_IRQ_I2C0; + + regval = getreg32(LPC43_SYSCON_PCONP); + regval |= SYSCON_PCONP_PCI2C0; + putreg32(regval, LPC43_SYSCON_PCONP); + + regval = getreg32(LPC43_SYSCON_PCLKSEL0); + regval &= ~SYSCON_PCLKSEL0_I2C0_MASK; + regval |= (SYSCON_PCLKSEL_CCLK << SYSCON_PCLKSEL0_I2C0_SHIFT); + putreg32(regval, LPC43_SYSCON_PCLKSEL0); + + lpc43_configgpio(GPIO_I2C0_SCL); + lpc43_configgpio(GPIO_I2C0_SDA); + + putreg32(LPC43_CCLK/CONFIG_I2C0_FREQ/2, priv->base + LPC43_I2C_SCLH_OFFSET); + putreg32(LPC43_CCLK/CONFIG_I2C0_FREQ/2, priv->base + LPC43_I2C_SCLL_OFFSET); + } + else +#endif +#ifdef CONFIG_LPC43_I2C1 + if (port == 1) + { + priv = &g_i2c1dev; + priv->base = LPC43_I2C1_BASE; + priv->irqid = LPC43_IRQ_I2C1; + + regval = getreg32(LPC43_SYSCON_PCONP); + regval |= SYSCON_PCONP_PCI2C1; + putreg32(regval, LPC43_SYSCON_PCONP); + + regval = getreg32(LPC43_SYSCON_PCLKSEL1); + regval &= ~SYSCON_PCLKSEL1_I2C1_MASK; + regval |= (SYSCON_PCLKSEL_CCLK << SYSCON_PCLKSEL1_I2C1_SHIFT); + putreg32(regval, LPC43_SYSCON_PCLKSEL1); + + lpc43_configgpio(GPIO_I2C1_SCL); + lpc43_configgpio(GPIO_I2C1_SDA); + + putreg32(LPC43_CCLK/CONFIG_I2C1_FREQ/2, priv->base + LPC43_I2C_SCLH_OFFSET); + putreg32(LPC43_CCLK/CONFIG_I2C1_FREQ/2, priv->base + LPC43_I2C_SCLL_OFFSET); + } + else +#endif + { + return NULL; + } + + putreg32(I2C_CONSET_I2EN,priv->base+LPC43_I2C_CONSET_OFFSET); + + sem_init(&priv->mutex, 0, 1); + sem_init(&priv->wait, 0, 0); + + /* Allocate a watchdog timer */ + + priv->timeout = wd_create(); + DEBUGASSERT(priv->timeout != 0); + + /* Attach Interrupt Handler */ + + irq_attach(priv->irqid, i2c_interrupt); + + /* Enable Interrupt Handler */ + + up_enable_irq(priv->irqid); + + /* Install our operations */ + + priv->dev.ops = &lpc43_i2c_ops; + return &priv->dev; +} + +/******************************************************************************* + * Name: up_i2cuninitalize + * + * Description: + * Uninitialise an I2C device + * + *******************************************************************************/ + +int up_i2cuninitialize(FAR struct i2c_dev_s * dev) +{ + struct lpc43_i2cdev_s *priv = (struct lpc43_i2cdev_s *) dev; + + putreg32(I2C_CONCLRT_I2ENC,priv->base+LPC43_I2C_CONCLR_OFFSET); + up_disable_irq(priv->irqid); + irq_detach(priv->irqid); + return OK; +} + +#endif diff --git a/arch/arm/src/lpc43xx/lpc43_lowputc.h b/arch/arm/src/lpc43xx/lpc43_lowputc.h index b15c9411c9..d74d5a8bd8 100644 --- a/arch/arm/src/lpc43xx/lpc43_lowputc.h +++ b/arch/arm/src/lpc43xx/lpc43_lowputc.h @@ -33,8 +33,8 @@ * ****************************************************************************/ -#ifndef __ARCH_ARM_SRC_LPC43XX_LOWSETUP_H -#define __ARCH_ARM_SRC_LPC43XX_LOWSETUP_H +#ifndef __ARCH_ARM_SRC_LPC43XX_LPC43_LOWSETUP_H +#define __ARCH_ARM_SRC_LPC43XX_LPC43_LOWSETUP_H /**************************************************************************** * Included Files @@ -85,4 +85,4 @@ EXTERN void lpc43_lowsetup(void); #endif #endif /* __ASSEMBLY__ */ -#endif /* __ARCH_ARM_SRC_LPC43XX_LOWSETUP_H */ +#endif /* __ARCH_ARM_SRC_LPC43XX_LPC43_LOWSETUP_H */ diff --git a/arch/arm/src/lpc43xx/lpc43_rgu.c b/arch/arm/src/lpc43xx/lpc43_rgu.c new file mode 100644 index 0000000000..daa7464834 --- /dev/null +++ b/arch/arm/src/lpc43xx/lpc43_rgu.c @@ -0,0 +1,120 @@ +/**************************************************************************** + * arch/arm/src/lpc43/lpc43_clrpend.c + * arch/arm/src/chip/lpc43_clrpend.c + * + * Copyright (C) 2012 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include + +#include "nvic.h" +#include "up_arch.h" + +#include "chip.h" +#include "lpc43_rgu.h" + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: lpc43_softreset + * + * Description: + * Reset as many of the LPC43 peripherals as possible. This is necessary + * because the LPC43 does not provide any way of performing a full system + * reset under debugger control. So, if CONFIG_DEBUG is set (indicating + * that a debugger is being used?), the the boot logic will call this + * function on all restarts. + * + * Assumptions: + * Since this function is called early in the boot sequence, it cannot + * depend on anything such as initialization of .bss or .data. It can + * only assume that it has a stack. + * + ****************************************************************************/ + +void lpc43_softreset(void) +{ + irqstate_t flags; + + /* Disable interrupts */ + + flags = irqsave(); + + /* Reset all of the peripherals that we can (safely) */ + + putreg32((RGU_CTRL0_LCD_RST | RGU_CTRL0_USB0_RST | + RGU_CTRL0_USB1_RST | RGU_CTRL0_DMA_RST | + RGU_CTRL0_SDIO_RST | RGU_CTRL0_ETHERNET_RST | + RGU_CTRL0_GPIO_RST), LPC43_RGU_CTRL0); + putreg32((RGU_CTRL1_TIMER0_RST | RGU_CTRL1_TIMER1_RST | + RGU_CTRL1_TIMER2_RST | RGU_CTRL1_TIMER3_RST | + RGU_CTRL1_RITIMER_RST | RGU_CTRL1_SCT_RST | + RGU_CTRL1_MCPWM_RST | RGU_CTRL1_QEI_RST | + RGU_CTRL1_ADC0_RST | RGU_CTRL1_ADC1_RST | + RGU_CTRL1_USART0_RST | RGU_CTRL1_UART1_RST | + RGU_CTRL1_USART2_RST | RGU_CTRL1_USART3_RST | + RGU_CTRL1_I2C0_RST | RGU_CTRL1_I2C1_RST | + RGU_CTRL1_SSP0_RST | RGU_CTRL1_SSP1_RST | + RGU_CTRL1_I2S_RST | RGU_CTRL1_CAN1_RST | + RGU_CTRL1_CAN0_RST | RGU_CTRL1_M0APP_RST), + LPC43_RGU_CTRL1); + + /* Clear all pending interupts */ + + putreg32(0xffffffff, NVIC_IRQ0_31_CLRPEND); + putreg32(0xffffffff, NVIC_IRQ32_63_CLRPEND); + irqrestore(flags); +} diff --git a/arch/arm/src/lpc43xx/lpc43_rgu.h b/arch/arm/src/lpc43xx/lpc43_rgu.h new file mode 100644 index 0000000000..364b4d0664 --- /dev/null +++ b/arch/arm/src/lpc43xx/lpc43_rgu.h @@ -0,0 +1,92 @@ +/**************************************************************************** + * arch/arm/src/lpc43xx/lpc43_rgu.h + * + * Copyright (C) 2012 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_LPC43XX_LPC43_RGU_H +#define __ARCH_ARM_SRC_LPC43XX_LPC43_RGU_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include "chip/lpc43_rgu.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" { +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: lpc43_softreset + * + * Description: + * Reset as many of the LPC43 peripherals as possible. This is necessary + * because the LPC43 does not provide any way of performing a full system + * reset under debugger control. So, if CONFIG_DEBUG is set (indicating + * that a debugger is being used?), the the boot logic will call this + * function on all restarts. + * + ****************************************************************************/ + +EXTERN void lpc43_softreset(void); + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* __ARCH_ARM_SRC_LPC43XX_LPC43_RGU_H */ diff --git a/arch/arm/src/lpc43xx/lpc43_serial.c b/arch/arm/src/lpc43xx/lpc43_serial.c new file mode 100644 index 0000000000..5fc0cc049e --- /dev/null +++ b/arch/arm/src/lpc43xx/lpc43_serial.c @@ -0,0 +1,1452 @@ +/**************************************************************************** + * arch/arm/src/lpc43xx/lpc43_serial.c + * + * Copyright (C) 2010-2012 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include "chip.h" +#include "up_arch.h" +#include "os_internal.h" +#include "up_internal.h" + +#include "lpc43_internal.h" +#include "lpc43_uart.h" +#include "lpc43_serial.h" + +/**************************************************************************** + * Pre-processor definitions + ****************************************************************************/ + +/* If we are not using the serial driver for the console, then we still must + * provide some minimal implementation of up_putc. + */ + +#if defined(USE_SERIALDRIVER) && defined(HAVE_UART) + +/* We cannot allow the DLM/DLL divisor to become to small or will will lose too + * much accuracy. This following is a "fudge factor" that represents the minimum + * value of the divisor that we will permit. + */ + +#define UART_MINDL 32 + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct up_dev_s +{ + uint32_t uartbase; /* Base address of UART registers */ + uint32_t baud; /* Configured baud */ + uint32_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) */ + uint8_t cclkdiv; /* Divisor needed to get PCLK from CCLK */ + 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 */ + +#ifdef CONFIG_LPC43_USART0 +static char g_uart0rxbuffer[CONFIG_USART0_RXBUFSIZE]; +static char g_uart0txbuffer[CONFIG_USART0_TXBUFSIZE]; +#endif +#ifdef CONFIG_LPC43_UART1 +static char g_uart1rxbuffer[CONFIG_UART1_RXBUFSIZE]; +static char g_uart1txbuffer[CONFIG_UART1_TXBUFSIZE]; +#endif +#ifdef CONFIG_LPC43_USART2 +static char g_uart2rxbuffer[CONFIG_USART2_RXBUFSIZE]; +static char g_uart2txbuffer[CONFIG_USART2_TXBUFSIZE]; +#endif +#ifdef CONFIG_LPC43_USART3 +static char g_uart3rxbuffer[CONFIG_USART3_RXBUFSIZE]; +static char g_uart3txbuffer[CONFIG_USART3_TXBUFSIZE]; +#endif + +/* This describes the state of the LPC43xx uart0 port. */ + +#ifdef CONFIG_LPC43_USART0 +static struct up_dev_s g_uart0priv = +{ + .uartbase = LPC43_USART0_BASE, + .baud = CONFIG_USART0_BAUD, + .irq = LPC43_IRQ_USART0, + .parity = CONFIG_USART0_PARITY, + .bits = CONFIG_USART0_BITS, + .stopbits2 = CONFIG_USART0_2STOP, +}; + +static uart_dev_t g_uart0port = +{ + .recv = + { + .size = CONFIG_USART0_RXBUFSIZE, + .buffer = g_uart0rxbuffer, + }, + .xmit = + { + .size = CONFIG_USART0_TXBUFSIZE, + .buffer = g_uart0txbuffer, + }, + .ops = &g_uart_ops, + .priv = &g_uart0priv, +}; +#endif + +/* This describes the state of the LPC43xx uart1 port. */ + +#ifdef CONFIG_LPC43_UART1 +static struct up_dev_s g_uart1priv = +{ + .uartbase = LPC43_UART1_BASE, + .baud = CONFIG_UART1_BAUD, + .irq = LPC43_IRQ_UART1, + .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, +}; +#endif + +/* This describes the state of the LPC43xx uart1 port. */ + +#ifdef CONFIG_LPC43_USART2 +static struct up_dev_s g_uart2priv = +{ + .uartbase = LPC43_USART2_BASE, + .baud = CONFIG_USART2_BAUD, + .irq = LPC43_IRQ_USART2, + .parity = CONFIG_USART2_PARITY, + .bits = CONFIG_USART2_BITS, + .stopbits2 = CONFIG_USART2_2STOP, +}; + +static uart_dev_t g_uart2port = +{ + .recv = + { + .size = CONFIG_USART2_RXBUFSIZE, + .buffer = g_uart2rxbuffer, + }, + .xmit = + { + .size = CONFIG_USART2_TXBUFSIZE, + .buffer = g_uart2txbuffer, + }, + .ops = &g_uart_ops, + .priv = &g_uart2priv, +}; +#endif + +/* This describes the state of the LPC43xx uart1 port. */ + +#ifdef CONFIG_LPC43_USART3 +static struct up_dev_s g_uart3priv = +{ + .uartbase = LPC43_USART3_BASE, + .baud = CONFIG_USART3_BAUD, + .irq = LPC43_IRQ_USART3, + .parity = CONFIG_USART3_PARITY, + .bits = CONFIG_USART3_BITS, + .stopbits2 = CONFIG_USART3_2STOP, +}; + +static uart_dev_t g_uart3port = +{ + .recv = + { + .size = CONFIG_USART3_RXBUFSIZE, + .buffer = g_uart3rxbuffer, + }, + .xmit = + { + .size = CONFIG_USART3_TXBUFSIZE, + .buffer = g_uart3txbuffer, + }, + .ops = &g_uart_ops, + .priv = &g_uart3priv, +}; +#endif + +/* Which UART with be tty0/console and which tty1? tty2? tty3? */ + +#ifdef HAVE_CONSOLE +# if defined(CONFIG_USART0_SERIAL_CONSOLE) +# define CONSOLE_DEV g_uart0port /* USART0=console */ +# define TTYS0_DEV g_uart0port /* USART0=ttyS0 */ +# ifdef CONFIG_LPC43_UART1 +# define TTYS1_DEV g_uart1port /* USART0=ttyS0;UART1=ttyS1 */ +# ifdef CONFIG_LPC43_USART2 +# define TTYS2_DEV g_uart2port /* USART0=ttyS0;UART1=ttyS1;USART2=ttyS2 */ +# ifdef CONFIG_LPC43_USART3 +# define TTYS3_DEV g_uart3port /* USART0=ttyS0;UART1=ttyS1;USART2=ttyS2;USART3=ttyS3 */ +# else +# undef TTYS3_DEV /* USART0=ttyS0;UART1=ttyS1;USART2=ttyS;No ttyS3 */ +# endif +# else +# ifdef CONFIG_LPC43_USART3 +# define TTYS2_DEV g_uart3port /* USART0=ttyS0;UART1=ttyS1;USART3=ttys2;No ttyS3 */ +# else +# undef TTYS2_DEV /* USART0=ttyS0;UART1=ttyS1;No ttyS2;No ttyS3 */ +# endif +# undef TTYS3_DEV /* No ttyS3 */ +# endif +# else +# ifdef CONFIG_LPC43_USART2 +# define TTYS1_DEV g_uart2port /* USART0=ttyS0;USART2=ttyS1;No ttyS3 */ +# ifdef CONFIG_LPC43_USART3 +# define TTYS2_DEV g_uart3port /* USART0=ttyS0;USART2=ttyS1;USART3=ttyS2;No ttyS3 */ +# else +# undef TTYS2_DEV /* USART0=ttyS0;USART2=ttyS1;No ttyS2;No ttyS3 */ +# endif +# undef TTYS3_DEV /* No ttyS3 */ +# else +# ifdef CONFIG_LPC43_USART3 +# define TTYS1_DEV g_uart3port /* USART0=ttyS0;USART3=ttyS1;No ttyS2;No ttyS3 */ +# else +# undef TTYS1_DEV /* USART0=ttyS0;No ttyS1;No ttyS2;No ttyS3 */ +# endif +# undef TTYS2_DEV /* No ttyS2 */ +# undef TTYS3_DEV /* No ttyS3 */ +# endif +# endif +# elif defined(CONFIG_UART1_SERIAL_CONSOLE) +# define CONSOLE_DEV g_uart1port /* UART1=console */ +# define TTYS0_DEV g_uart1port /* UART1=ttyS0 */ +# ifdef CONFIG_LPC43_USART0 +# define TTYS1_DEV g_uart0port /* UART1=ttyS0;USART0=ttyS1 */ +# ifdef CONFIG_LPC43_USART2 +# define TTYS2_DEV g_uart2port /* UART1=ttyS0;USART0=ttyS1;USART2=ttyS2 */ +# ifdef CONFIG_LPC43_USART3 +# define TTYS3_DEV g_uart3port /* UART1=ttyS0;USART0=ttyS1;USART2=ttyS2;USART3=ttyS3 */ +# else +# undef TTYS3_DEV /* UART1=ttyS0;USART0=ttyS1;USART2=ttyS;No ttyS3 */ +# endif +# else +# ifdef CONFIG_LPC43_USART3 +# define TTYS2_DEV g_uart3port /* UART1=ttyS0;USART0=ttyS1;USART3=ttys2;No ttyS3 */ +# else +# undef TTYS2_DEV /* UART1=ttyS0;USART0=ttyS1;No ttyS2;No ttyS3 */ +# endif +# undef TTYS3_DEV /* No ttyS3 */ +# endif +# else +# ifdef CONFIG_LPC43_USART2 +# define TTYS1_DEV g_uart2port /* UART1=ttyS0;USART2=ttyS1 */ +# ifdef CONFIG_LPC43_USART3 +# define TTYS2_DEV g_uart3port /* UART1=ttyS0;USART2=ttyS1;USART3=ttyS2;No ttyS3 */ +# else +# undef TTYS2_DEV /* UART1=ttyS0;USART2=ttyS1;No ttyS2;No ttyS3 */ +# endif +# undef TTYS3_DEV /* No ttyS3 */ +# else +# ifdef CONFIG_LPC43_USART3 +# define TTYS1_DEV g_uart3port /* UART1=ttyS0;USART3=ttyS1;No ttyS2;No ttyS3 */ +# else +# undef TTYS1_DEV /* UART1=ttyS0;No ttyS1;No ttyS2;No ttyS3 */ +# endif +# undef TTYS2_DEV /* No ttyS2 */ +# undef TTYS3_DEV /* No ttyS3 */ +# endif +# endif +# elif defined(CONFIG_USART2_SERIAL_CONSOLE) +# define CONSOLE_DEV g_uart2port /* USART2=console */ +# define TTYS0_DEV g_uart2port /* USART2=ttyS0 */ +# ifdef CONFIG_LPC43_USART2 +# define TTYS1_DEV g_uart0port /* USART2=ttyS0;USART0=ttyS1 */ +# ifdef CONFIG_LPC43_UART1 +# define TTYS2_DEV g_uart1port /* USART2=ttyS0;USART0=ttyS1;UART1=ttyS2 */ +# ifdef CONFIG_LPC43_USART3 +# define TTYS3_DEV g_uart3port /* USART2=ttyS0;USART0=ttyS1;UART1=ttyS2;USART3=ttyS3 */ +# else +# undef TTYS3_DEV /* USART2=ttyS0;USART0=ttyS1;UART1=ttyS;No ttyS3 */ +# endif +# else +# ifdef CONFIG_LPC43_USART3 +# define TTYS2_DEV g_uart3port /* USART2=ttyS0;USART0=ttyS1;USART3=ttys2;No ttyS3 */ +# else +# undef TTYS2_DEV /* USART2=ttyS0;USART0=ttyS1;No ttyS2;No ttyS3 */ +# endif +# undef TTYS3_DEV /* No ttyS3 */ +# endif +# else +# ifdef CONFIG_LPC43_UART1 +# define TTYS1_DEV g_uart1port /* USART2=ttyS0;UART1=ttyS1 */ +# ifdef CONFIG_LPC43_USART3 +# define TTYS2_DEV g_uart3port /* USART2=ttyS0;UART1=ttyS1;USART3=ttyS2 */ +# else +# undef TTYS2_DEV /* USART2=ttyS0;UART1=ttyS1;No ttyS2;No ttyS3 */ +# endif +# undef TTYS3_DEV /* No ttyS3 */ +# else +# ifdef CONFIG_LPC43_USART3 +# define TTYS1_DEV g_uart3port /* USART2=ttyS0;USART3=ttyS1;No ttyS3 */ +# else +# undef TTYS1_DEV /* USART2=ttyS0;No ttyS1;No ttyS2;No ttyS3 */ +# endif +# undef TTYS2_DEV /* No ttyS2 */ +# undef TTYS3_DEV /* No ttyS3 */ +# endif +# endif +# elif defined(CONFIG_USART3_SERIAL_CONSOLE) +# define CONSOLE_DEV g_uart3port /* USART3=console */ +# define TTYS0_DEV g_uart3port /* USART3=ttyS0 */ +# ifdef CONFIG_LPC43_USART0 +# define TTYS1_DEV g_uart0port /* USART3=ttyS0;USART0=ttyS1 */ +# ifdef CONFIG_LPC43_UART1 +# define TTYS2_DEV g_uart1port /* USART3=ttyS0;USART0=ttyS1;UART1=ttyS2 */ +# ifdef CONFIG_LPC43_USART2 +# define TTYS3_DEV g_uart2port /* USART3=ttyS0;USART0=ttyS1;UART1=ttyS2;USART2=ttyS3 */ +# else +# undef TTYS3_DEV /* USART3=ttyS0;USART0=ttyS1;UART1=ttyS;No ttyS3 */ +# endif +# else +# ifdef CONFIG_LPC43_USART2 +# define TTYS2_DEV g_uart2port /* USART3=ttyS0;USART0=ttyS1;USART2=ttys2;No ttyS3 */ +# else +# undef TTYS2_DEV /* USART3=ttyS0;USART0=ttyS1;No ttyS2;No ttyS3 */ +# endif +# undef TTYS3_DEV /* No ttyS3 */ +# endif +# else +# ifdef CONFIG_LPC43_UART1 +# define TTYS1_DEV g_uart1port /* USART3=ttyS0;UART1=ttyS1 */ +# ifdef CONFIG_LPC43_USART2 +# define TTYS2_DEV g_uart2port /* USART3=ttyS0;UART1=ttyS1;USART2=ttyS2;No ttyS3 */ +# else +# undef TTYS2_DEV /* USART3=ttyS0;UART1=ttyS1;No ttyS2;No ttyS3 */ +# endif +# undef TTYS3_DEV /* No ttyS3 */ +# else +# ifdef CONFIG_LPC43_USART2 +# define TTYS1_DEV g_uart2port /* USART3=ttyS0;USART2=ttyS1;No ttyS3;No ttyS3 */ +# undef TTYS3_DEV /* USART3=ttyS0;USART2=ttyS1;No ttyS2;No ttyS3 */ +# else +# undef TTYS1_DEV /* USART3=ttyS0;No ttyS1;No ttyS2;No ttyS3 */ +# endif +# undef TTYS2_DEV /* No ttyS2 */ +# undef TTYS3_DEV /* No ttyS3 */ +# endif +# endif +# endif +#else /* No console */ +# define TTYS0_DEV g_uart0port /* USART0=ttyS0 */ +# ifdef CONFIG_LPC43_UART1 +# define TTYS1_DEV g_uart1port /* USART0=ttyS0;UART1=ttyS1 */ +# ifdef CONFIG_LPC43_USART2 +# define TTYS2_DEV g_uart2port /* USART0=ttyS0;UART1=ttyS1;USART2=ttyS2 */ +# ifdef CONFIG_LPC43_USART3 +# define TTYS3_DEV g_uart3port /* USART0=ttyS0;UART1=ttyS1;USART2=ttyS2;USART3=ttyS3 */ +# else +# undef TTYS3_DEV /* USART0=ttyS0;UART1=ttyS1;USART2=ttyS;No ttyS3 */ +# endif +# else +# ifdef CONFIG_LPC43_USART3 +# define TTYS2_DEV g_uart3port /* USART0=ttyS0;UART1=ttyS1;USART3=ttys2;No ttyS3 */ +# else +# undef TTYS2_DEV /* USART0=ttyS0;UART1=ttyS1;No ttyS2;No ttyS3 */ +# endif +# undef TTYS3_DEV /* No ttyS3 */ +# endif +# else +# ifdef CONFIG_LPC43_USART2 +# define TTYS1_DEV g_uart2port /* USART0=ttyS0;USART2=ttyS1;No ttyS3 */ +# ifdef CONFIG_LPC43_USART3 +# define TTYS2_DEV g_uart3port /* USART0=ttyS0;USART2=ttyS1;USART3=ttyS2;No ttyS3 */ +# else +# undef TTYS2_DEV /* USART0=ttyS0;USART2=ttyS1;No ttyS2;No ttyS3 */ +# endif +# undef TTYS3_DEV /* No ttyS3 */ +# else +# ifdef CONFIG_LPC43_USART3 +# define TTYS1_DEV g_uart3port /* USART0=ttyS0;USART3=ttyS1;No ttyS2;No ttyS3 */ +# else +# undef TTYS1_DEV /* USART0=ttyS0;No ttyS1;No ttyS2;No ttyS3 */ +# endif +# undef TTYS2_DEV /* No ttyS2 */ +# undef TTYS3_DEV /* No ttyS3 */ +# endif +# endif +#endif /*HAVE_CONSOLE*/ + +/************************************************************************************ + * Inline Functions + ************************************************************************************/ + +/**************************************************************************** + * Name: up_serialin + ****************************************************************************/ + +static inline uint32_t up_serialin(struct up_dev_s *priv, int offset) +{ + return getreg32(priv->uartbase + offset); +} + +/**************************************************************************** + * Name: up_serialout + ****************************************************************************/ + +static inline void up_serialout(struct up_dev_s *priv, int offset, uint32_t value) +{ + putreg32(value, priv->uartbase + offset); +} + +/**************************************************************************** + * Name: up_disableuartint + ****************************************************************************/ + +static inline void up_disableuartint(struct up_dev_s *priv, uint32_t *ier) +{ + if (ier) + { + *ier = priv->ier & UART_IER_ALLIE; + } + + priv->ier &= ~UART_IER_ALLIE; + up_serialout(priv, LPC43_UART_IER_OFFSET, priv->ier); +} + +/**************************************************************************** + * Name: up_restoreuartint + ****************************************************************************/ + +static inline void up_restoreuartint(struct up_dev_s *priv, uint32_t ier) +{ + priv->ier |= ier & UART_IER_ALLIE; + up_serialout(priv, LPC43_UART_IER_OFFSET, priv->ier); +} + +/**************************************************************************** + * Name: up_enablebreaks + ****************************************************************************/ + +static inline void up_enablebreaks(struct up_dev_s *priv, bool enable) +{ + uint32_t lcr = up_serialin(priv, LPC43_UART_LCR_OFFSET); + if (enable) + { + lcr |= UART_LCR_BRK; + } + else + { + lcr &= ~UART_LCR_BRK; + } + up_serialout(priv, LPC43_UART_LCR_OFFSET, lcr); +} + +/************************************************************************************ + * Name: lpc43_uartcclkdiv + * + * Descrption: + * Select a CCLK divider to produce the UART PCLK. The stratey is to select the + * smallest divisor that results in an solution within range of the 16-bit + * DLM and DLL divisor: + * + * PCLK = CCLK / divisor + * BAUD = PCLK / (16 * DL) + * + * Ignoring the fractional divider for now. + * + * NOTE: This is an inline function. If a typical optimization level is used and + * a constant is provided for the desired frequency, then most of the following + * logic will be optimized away. + * + ************************************************************************************/ + +static inline uint32_t lpc43_uartcclkdiv(uint32_t baud) +{ + /* Ignoring the fractional divider, the BAUD is given by: + * + * BAUD = PCLK / (16 * DL), or + * DL = PCLK / BAUD / 16 + * + * Where: + * + * PCLK = CCLK / divisor. + * + * Check divisor == 1. This works if the upper limit is met + * + * DL < 0xffff, or + * PCLK / BAUD / 16 < 0xffff, or + * CCLK / BAUD / 16 < 0xffff, or + * CCLK < BAUD * 0xffff * 16 + * BAUD > CCLK / 0xffff / 16 + * + * And the lower limit is met (we can't allow DL to get very close to one). + * + * DL >= MinDL + * CCLK / BAUD / 16 >= MinDL, or + * BAUD <= CCLK / 16 / MinDL + */ + + if (baud < (LPC43_CCLK / 16 / UART_MINDL )) + { + return SYSCON_PCLKSEL_CCLK; + } + + /* Check divisor == 2. This works if: + * + * 2 * CCLK / BAUD / 16 < 0xffff, or + * BAUD > CCLK / 0xffff / 8 + * + * And + * + * 2 * CCLK / BAUD / 16 >= MinDL, or + * BAUD <= CCLK / 8 / MinDL + */ + + else if (baud < (LPC43_CCLK / 8 / UART_MINDL )) + { + return SYSCON_PCLKSEL_CCLK2; + } + + /* Check divisor == 4. This works if: + * + * 4 * CCLK / BAUD / 16 < 0xffff, or + * BAUD > CCLK / 0xffff / 4 + * + * And + * + * 4 * CCLK / BAUD / 16 >= MinDL, or + * BAUD <= CCLK / 4 / MinDL + */ + + else if (baud < (LPC43_CCLK / 4 / UART_MINDL )) + { + return SYSCON_PCLKSEL_CCLK4; + } + + /* Check divisor == 8. This works if: + * + * 8 * CCLK / BAUD / 16 < 0xffff, or + * BAUD > CCLK / 0xffff / 2 + * + * And + * + * 8 * CCLK / BAUD / 16 >= MinDL, or + * BAUD <= CCLK / 2 / MinDL + */ + + else /* if (baud < (LPC43_CCLK / 2 / UART_MINDL )) */ + { + return SYSCON_PCLKSEL_CCLK8; + } +} + +/************************************************************************************ + * Name: lpc43_uart0config, uart1config, uart2config, and uart3config + * + * Descrption: + * Configure the UART. USART0/2/3 and UART1 peripherals are configured using the following + * registers: + * + * 1. Power: In the PCONP register, set bits PCUSART0/1/2/3. + * On reset, USART0 and UART 1 are enabled (PCUSART0 = 1 and PCUART1 = 1) + * and USART2/3 are disabled (PCUART1 = 0 and PCUSART3 = 0). + * 2. Peripheral clock: In the PCLKSEL0 register, select PCLK_USART0 and + * PCLK_UART1; in the PCLKSEL1 register, select PCLK_USART2 and PCLK_USART3. + * 3. Pins: Select UART pins through the PINSEL registers and pin modes + * through the PINMODE registers. UART receive pins should not have + * pull-down resistors enabled. + * + ************************************************************************************/ + +#ifdef CONFIG_LPC43_USART0 +static inline void lpc43_uart0config(uint32_t clkdiv) +{ + uint32_t regval; + irqstate_t flags; + + /* Step 1: Enable power on USART0 */ + + flags = irqsave(); + regval = getreg32(LPC43_SYSCON_PCONP); + regval |= SYSCON_PCONP_PCUSART0; + putreg32(regval, LPC43_SYSCON_PCONP); + + /* Step 2: Enable clocking on UART */ + + regval = getreg32(LPC43_SYSCON_PCLKSEL0); + regval &= ~SYSCON_PCLKSEL0_USART0_MASK; + regval |= (clkdiv << SYSCON_PCLKSEL0_USART0_SHIFT); + putreg32(regval, LPC43_SYSCON_PCLKSEL0); + + /* Step 3: Configure I/O pins */ + + lpc43_configgpio(GPIO_USART0_TXD); + lpc43_configgpio(GPIO_USART0_RXD); + irqrestore(flags); +}; +#endif + +#ifdef CONFIG_LPC43_UART1 +static inline void lpc43_uart1config(uint32_t clkdiv) +{ + uint32_t regval; + irqstate_t flags; + + /* Step 1: Enable power on UART1 */ + + flags = irqsave(); + regval = getreg32(LPC43_SYSCON_PCONP); + regval |= SYSCON_PCONP_PCUART1; + putreg32(regval, LPC43_SYSCON_PCONP); + + /* Step 2: Enable clocking on UART */ + + regval = getreg32(LPC43_SYSCON_PCLKSEL0); + regval &= ~SYSCON_PCLKSEL0_UART1_MASK; + regval |= (clkdiv << SYSCON_PCLKSEL0_UART1_SHIFT); + putreg32(regval, LPC43_SYSCON_PCLKSEL0); + + /* Step 3: Configure I/O pins */ + + lpc43_configgpio(GPIO_UART1_TXD); + lpc43_configgpio(GPIO_UART1_RXD); +#ifdef CONFIG_UART1_FLOWCONTROL + lpc43_configgpio(GPIO_UART1_CTS); + lpc43_configgpio(GPIO_UART1_RTS); + lpc43_configgpio(GPIO_UART1_DCD); + lpc43_configgpio(GPIO_UART1_DSR); + lpc43_configgpio(GPIO_UART1_DTR); +#ifdef CONFIG_UART1_RINGINDICATOR + lpc43_configgpio(GPIO_UART1_RI); +#endif +#endif + irqrestore(flags); +}; +#endif + +#ifdef CONFIG_LPC43_USART2 +static inline void lpc43_uart2config(uint32_t clkdiv) +{ + uint32_t regval; + irqstate_t flags; + + /* Step 1: Enable power on USART2 */ + + flags = irqsave(); + regval = getreg32(LPC43_SYSCON_PCONP); + regval |= SYSCON_PCONP_PCUSART2; + putreg32(regval, LPC43_SYSCON_PCONP); + + /* Step 2: Enable clocking on UART */ + + regval = getreg32(LPC43_SYSCON_PCLKSEL1); + regval &= ~SYSCON_PCLKSEL1_USART2_MASK; + regval |= (clkdiv << SYSCON_PCLKSEL1_USART2_SHIFT); + putreg32(regval, LPC43_SYSCON_PCLKSEL1); + + /* Step 3: Configure I/O pins */ + + lpc43_configgpio(GPIO_USART2_TXD); + lpc43_configgpio(GPIO_USART2_RXD); + irqrestore(flags); +}; +#endif + +#ifdef CONFIG_LPC43_USART3 +static inline void lpc43_uart3config(uint32_t clkdiv) +{ + uint32_t regval; + irqstate_t flags; + + /* Step 1: Enable power on USART3 */ + + flags = irqsave(); + regval = getreg32(LPC43_SYSCON_PCONP); + regval |= SYSCON_PCONP_PCUSART3; + putreg32(regval, LPC43_SYSCON_PCONP); + + /* Step 2: Enable clocking on UART */ + + regval = getreg32(LPC43_SYSCON_PCLKSEL1); + regval &= ~SYSCON_PCLKSEL1_USART3_MASK; + regval |= (clkdiv << SYSCON_PCLKSEL1_USART3_SHIFT); + putreg32(regval, LPC43_SYSCON_PCLKSEL1); + + /* Step 3: Configure I/O pins */ + + lpc43_configgpio(GPIO_USART3_TXD); + lpc43_configgpio(GPIO_USART3_RXD); + irqrestore(flags); +}; +#endif + +/************************************************************************************ + * Name: lpc43_uartdl + * + * Descrption: + * Select a divider to produce the BAUD from the UART PCLK. + * + * BAUD = PCLK / (16 * DL), or + * DL = PCLK / BAUD / 16 + * + * Ignoring the fractional divider for now. + * + ************************************************************************************/ + +static inline uint32_t lpc43_uartdl(uint32_t baud, uint8_t divcode) +{ + uint32_t num; + + switch (divcode) + { + + case SYSCON_PCLKSEL_CCLK4: /* PCLK_peripheral = CCLK/4 */ + num = (LPC43_CCLK / 4); + break; + + case SYSCON_PCLKSEL_CCLK: /* PCLK_peripheral = CCLK */ + num = LPC43_CCLK; + break; + + case SYSCON_PCLKSEL_CCLK2: /* PCLK_peripheral = CCLK/2 */ + num = (LPC43_CCLK / 2); + break; + + case SYSCON_PCLKSEL_CCLK8: /* PCLK_peripheral = CCLK/8 (except CAN1, CAN2, and CAN) */ + default: + num = (LPC43_CCLK / 8); + break; + } + return num / (baud << 4); +} + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * 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_LPC43_UART_CONFIG + struct up_dev_s *priv = (struct up_dev_s*)dev->priv; + uint16_t dl; + uint32_t lcr; + + /* Clear fifos */ + + up_serialout(priv, LPC43_UART_FCR_OFFSET, (UART_FCR_RXRST|UART_FCR_TXRST)); + + /* Set trigger */ + + up_serialout(priv, LPC43_UART_FCR_OFFSET, (UART_FCR_FIFOEN|UART_FCR_RXTRIGGER_8)); + + /* Set up the IER */ + + priv->ier = up_serialin(priv, LPC43_UART_IER_OFFSET); + + /* Set up the LCR */ + + lcr = 0; + + if (priv->bits == 7) + { + lcr |= UART_LCR_WLS_7BIT; + } + else + { + lcr |= UART_LCR_WLS_8BIT; + } + + if (priv->stopbits2) + { + lcr |= UART_LCR_STOP; + } + + if (priv->parity == 1) + { + lcr |= (UART_LCR_PE|UART_LCR_PS_ODD); + } + else if (priv->parity == 2) + { + lcr |= (UART_LCR_PE|UART_LCR_PS_EVEN); + } + + /* Enter DLAB=1 */ + + up_serialout(priv, LPC43_UART_LCR_OFFSET, (lcr | UART_LCR_DLAB)); + + /* Set the BAUD divisor */ + + dl = lpc43_uartdl(priv->baud, priv->cclkdiv); + up_serialout(priv, LPC43_UART_DLM_OFFSET, dl >> 8); + up_serialout(priv, LPC43_UART_DLL_OFFSET, dl & 0xff); + + /* Clear DLAB */ + + up_serialout(priv, LPC43_UART_LCR_OFFSET, lcr); + + /* Configure the FIFOs */ + + up_serialout(priv, LPC43_UART_FCR_OFFSET, + (UART_FCR_RXTRIGGER_8|UART_FCR_TXRST|UART_FCR_RXRST|UART_FCR_FIFOEN)); + + /* Enable Auto-RTS and Auto-CS Flow Control in the Modem Control Register */ + +#ifdef CONFIG_UART1_FLOWCONTROL + if (priv->uartbase == LPC43_UART1_BASE) + { + up_serialout(priv, LPC43_UART_MCR_OFFSET, (UART_MCR_RTSEN|UART_MCR_CTSEN)); + } +#endif + +#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 + * appropriate 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; + uint32_t status; + int passes; + +#ifdef CONFIG_LPC43_USART0 + if (g_uart0priv.irq == irq) + { + dev = &g_uart0port; + } + else +#endif +#ifdef CONFIG_LPC43_UART1 + if (g_uart1priv.irq == irq) + { + dev = &g_uart1port; + } + else +#endif +#ifdef CONFIG_LPC43_USART2 + if (g_uart2priv.irq == irq) + { + dev = &g_uart2port; + } + else +#endif +#ifdef CONFIG_LPC43_USART3 + if (g_uart3priv.irq == irq) + { + dev = &g_uart3port; + } + else +#endif + { + 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, LPC43_UART_IIR_OFFSET); + + /* The UART_IIR_INTSTATUS bit should be zero if there are pending + * interrupts + */ + + if ((status & UART_IIR_INTSTATUS) != 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 & UART_IIR_INTID_MASK) + { + /* Handle incoming, receive bytes (with or without timeout) */ + + case UART_IIR_INTID_RDA: + case UART_IIR_INTID_CTI: + { + uart_recvchars(dev); + break; + } + + /* Handle outgoing, transmit bytes */ + + case UART_IIR_INTID_THRE: + { + uart_xmitchars(dev); + break; + } + + /* Just clear modem status interrupts (UART1 only) */ + + case UART_IIR_INTID_MSI: + { + /* Read the modem status register (MSR) to clear */ + + status = up_serialin(priv, LPC43_UART_MSR_OFFSET); + vdbg("MSR: %02x\n", status); + break; + } + + /* Just clear any line status interrupts */ + + case UART_IIR_INTID_RLS: + { + /* Read the line status register (LSR) to clear */ + + status = up_serialin(priv, LPC43_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) + { + *get_errno_ptr() = EINVAL; + ret = ERROR; + } + 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: + *get_errno_ptr() = ENOTTY; + ret = ERROR; + 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; + uint32_t rbr; + + *status = up_serialin(priv, LPC43_UART_LSR_OFFSET); + rbr = up_serialin(priv, LPC43_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 |= UART_IER_RBRIE; +#endif + } + else + { + priv->ier &= ~UART_IER_RBRIE; + } + up_serialout(priv, LPC43_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, LPC43_UART_LSR_OFFSET) & UART_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, LPC43_UART_THR_OFFSET, (uint32_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; + irqstate_t flags; + + flags = irqsave(); + if (enable) + { +#ifndef CONFIG_SUPPRESS_SERIAL_INTS + priv->ier |= UART_IER_THREIE; + up_serialout(priv, LPC43_UART_IER_OFFSET, priv->ier); + + /* Fake a TX interrupt here by just calling uart_xmitchars() with + * interrupts disabled (note this may recurse). + */ + + uart_xmitchars(dev); +#endif + } + else + { + priv->ier &= ~UART_IER_THREIE; + up_serialout(priv, LPC43_UART_IER_OFFSET, priv->ier); + } + irqrestore(flags); +} + +/**************************************************************************** + * 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, LPC43_UART_LSR_OFFSET) & UART_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, LPC43_UART_LSR_OFFSET) & UART_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. + * + * NOTE: Configuration of the CONSOLE UART was performed by up_lowsetup() + * very early in the boot sequence. + * + ****************************************************************************/ + +void up_earlyserialinit(void) +{ + /* Configure all UARTs (except the CONSOLE UART) and disable interrupts */ + +#ifdef CONFIG_LPC43_USART0 + g_uart0priv.cclkdiv = lpc43_uartcclkdiv(CONFIG_USART0_BAUD); +#ifndef CONFIG_USART0_SERIAL_CONSOLE + lpc43_uart0config(g_uart0priv.cclkdiv); +#endif + up_disableuartint(&g_uart0priv, NULL); +#endif + +#ifdef CONFIG_LPC43_UART1 + g_uart1priv.cclkdiv = lpc43_uartcclkdiv(CONFIG_UART1_BAUD); +#ifndef CONFIG_UART1_SERIAL_CONSOLE + lpc43_uart1config(g_uart1priv.cclkdiv); +#endif + up_disableuartint(&g_uart1priv, NULL); +#endif + +#ifdef CONFIG_LPC43_USART2 + g_uart2priv.cclkdiv = lpc43_uartcclkdiv(CONFIG_USART2_BAUD); +#ifndef CONFIG_USART2_SERIAL_CONSOLE + lpc43_uart2config(g_uart2priv.cclkdiv); +#endif + up_disableuartint(&g_uart2priv, NULL); +#endif + +#ifdef CONFIG_LPC43_USART3 + g_uart3priv.cclkdiv = lpc43_uartcclkdiv(CONFIG_USART3_BAUD); +#ifndef CONFIG_USART3_SERIAL_CONSOLE + lpc43_uart3config(g_uart3priv.cclkdiv); +#endif + up_disableuartint(&g_uart3priv, NULL); +#endif + + /* Configuration whichever one is the console */ + +#ifdef CONSOLE_DEV + CONSOLE_DEV.isconsole = true; + up_setup(&CONSOLE_DEV); +#endif +} + +/**************************************************************************** + * Name: up_serialinit + * + * Description: + * Register serial console and serial ports. This assumes that + * up_earlyserialinit was called previously. + * + ****************************************************************************/ + +void up_serialinit(void) +{ +#ifdef CONSOLE_DEV + (void)uart_register("/dev/console", &CONSOLE_DEV); +#endif +#ifdef TTYS0_DEV + (void)uart_register("/dev/ttyS0", &TTYS0_DEV); +#endif +#ifdef TTYS1_DEV + (void)uart_register("/dev/ttyS1", &TTYS1_DEV); +#endif +#ifdef TTYS2_DEV + (void)uart_register("/dev/ttyS2", &TTYS2_DEV); +#endif +#ifdef TTYS3_DEV + (void)uart_register("/dev/ttyS3", &TTYS3_DEV); +#endif +} + +/**************************************************************************** + * Name: up_putc + * + * Description: + * Provide priority, low-level access to support OS debug writes + * + ****************************************************************************/ + +int up_putc(int ch) +{ +#ifdef HAVE_CONSOLE + struct up_dev_s *priv = (struct up_dev_s*)CONSOLE_DEV.priv; + uint32_t ier; + up_disableuartint(priv, &ier); +#endif + + /* Check for LF */ + + if (ch == '\n') + { + /* Add CR */ + + up_lowputc('\r'); + } + + up_lowputc(ch); +#ifdef HAVE_CONSOLE + up_restoreuartint(priv, ier); +#endif + + return ch; +} + +#else /* USE_SERIALDRIVER */ + +/**************************************************************************** + * Name: up_putc + * + * Description: + * Provide priority, low-level access to support OS debug writes + * + ****************************************************************************/ + +int up_putc(int ch) +{ +#ifdef HAVE_UART + /* Check for LF */ + + if (ch == '\n') + { + /* Add CR */ + + up_lowputc('\r'); + } + + up_lowputc(ch); +#endif + return ch; +} + +#endif /* USE_SERIALDRIVER */ diff --git a/arch/arm/src/lpc43xx/lpc43_spi.h b/arch/arm/src/lpc43xx/lpc43_spi.h index ba447a1131..7af965947d 100644 --- a/arch/arm/src/lpc43xx/lpc43_spi.h +++ b/arch/arm/src/lpc43xx/lpc43_spi.h @@ -41,7 +41,8 @@ ************************************************************************************/ #include -#include +#include +#include "chip/lpc32_spi.h" #ifdef CONFIG_LPC43_SPI diff --git a/arch/arm/src/lpc43xx/lpc43_ssp.h b/arch/arm/src/lpc43xx/lpc43_ssp.h index e2fd386713..cec08e5d03 100644 --- a/arch/arm/src/lpc43xx/lpc43_ssp.h +++ b/arch/arm/src/lpc43xx/lpc43_ssp.h @@ -41,7 +41,8 @@ ************************************************************************************/ #include -#include +#include +#include "chip/lpc43_ssp.h" #if defined(CONFIG_LPC43_SSP0) || defined(CONFIG_LPC43_SSP1) diff --git a/arch/arm/src/lpc43xx/lpc43_start.c b/arch/arm/src/lpc43xx/lpc43_start.c index 76f4f8ca3a..972591019f 100644 --- a/arch/arm/src/lpc43xx/lpc43_start.c +++ b/arch/arm/src/lpc43xx/lpc43_start.c @@ -50,7 +50,8 @@ # include "nvic.h" #endif -#include "lpc43_clockconfig.h" +#include "lpc43_rgu.h" +#include "lpc43_cgu.h" #include "lpc43_lowputc.h" /**************************************************************************** @@ -178,7 +179,20 @@ void __start(void) const uint32_t *src; uint32_t *dest; - /* Configure the uart so that we can get debug output as soon as possible */ + /* Reset as many of the LPC43 peripherals as possible. This is necessary + * because the LPC43 does not provide any way of performing a full system + * reset under debugger control. So, if CONFIG_DEBUG is set (indicating + * that a debugger is being used?), the the boot logic will call this + * function on all restarts. + */ + +#ifdef CONFIG_DEBUG + lpc43_softreset(); +#endif + + /* Configure the CGU clocking and the console uart so that we can get + * debug output as soon as possible. + */ lpc43_clockconfig(); lpc43_fpuconfig();