summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGregory Nutt <gnutt@nuttx.org>2014-03-08 11:03:58 -0600
committerGregory Nutt <gnutt@nuttx.org>2014-03-08 11:03:58 -0600
commit1418161910e3b44bd8afd85ea107d0452e5967f3 (patch)
treee26120bc4efdeb18f1720c66e32789b8214e388a
parent7454f370021e7f93118b869620247496b0f09516 (diff)
downloadnuttx-1418161910e3b44bd8afd85ea107d0452e5967f3.tar.gz
nuttx-1418161910e3b44bd8afd85ea107d0452e5967f3.tar.bz2
nuttx-1418161910e3b44bd8afd85ea107d0452e5967f3.zip
LPC2378: I2C driver from Lizhuoyi
-rw-r--r--nuttx/ChangeLog4
-rw-r--r--nuttx/arch/arm/src/lpc2378/Kconfig23
-rw-r--r--nuttx/arch/arm/src/lpc2378/lpc23xx_i2c.c608
-rw-r--r--nuttx/arch/arm/src/lpc2378/lpc23xx_i2c.h165
4 files changed, 796 insertions, 4 deletions
diff --git a/nuttx/ChangeLog b/nuttx/ChangeLog
index 7ff45824b..05021d259 100644
--- a/nuttx/ChangeLog
+++ b/nuttx/ChangeLog
@@ -6953,3 +6953,7 @@
thinking about naming (2014-3-8).
* arch/x86/src/qemu/qemu_keypad.c and qemu_vga.c: New QEMU keyboard
and VGA drivers from Lizhuoyi (2014-3-8).
+ * configs/olimex-lpc2378/src: Files renamed to correspond with current
+ thinking about naming (2014-3-8).
+ * arch/arm/src/lpc2378/lpc23xx_i2c.c and lpc23xx_spi.c: I2C and SPI
+ drivers for the LPC23xx from Lizhuoyi (2014-3-8). \ No newline at end of file
diff --git a/nuttx/arch/arm/src/lpc2378/Kconfig b/nuttx/arch/arm/src/lpc2378/Kconfig
index 2d3cbb4ae..c3d5a0036 100644
--- a/nuttx/arch/arm/src/lpc2378/Kconfig
+++ b/nuttx/arch/arm/src/lpc2378/Kconfig
@@ -117,24 +117,39 @@ menu "LPC2378 Peripheral Support"
config LPC2378_UART0
bool "UART0"
- default y
+ default n
select ARCH_HAVE_UART0
config LPC2378_UART1
bool "UART1"
- default y
+ default n
select ARCH_HAVE_UART1
config LPC2378_UART2
bool "UART2"
- default y
+ default n
select ARCH_HAVE_UART2
config LPC2378_USBDEV
bool "USB Device"
- default y
+ default n
depends on USBDEV
+config LPC2378_IC0
+ bool "I2C0"
+ default n
+ select I2C
+
+config LPC2378_IC1
+ bool "I2C1"
+ default n
+ select I2C
+
+config LPC2378_IC2
+ bool "I2C2"
+ default n
+ select I2C
+
endmenu
if LPC2378_USBDEV
diff --git a/nuttx/arch/arm/src/lpc2378/lpc23xx_i2c.c b/nuttx/arch/arm/src/lpc2378/lpc23xx_i2c.c
new file mode 100644
index 000000000..a94deb03a
--- /dev/null
+++ b/nuttx/arch/arm/src/lpc2378/lpc23xx_i2c.c
@@ -0,0 +1,608 @@
+/*******************************************************************************
+ * arch/arm/src/lpc2378/lpc23xx_i2c.c
+ *
+ * Copyright (C) 2013 Li Zhuoyi. All rights reserved.
+ * Author: Li Zhuoyi <lzyy.cn@gmail.com>
+ *
+ * Derived from arch/arm/src/lpc17xx/lpc23xx_i2c.c
+ *
+ * Copyright (C) 2011 Li Zhuoyi. All rights reserved.
+ * Author: Li Zhuoyi <lzyy.cn@gmail.com>
+ * 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 <gnutt@nuttx.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ *******************************************************************************/
+
+/*******************************************************************************
+ * Included Files
+ *******************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <sys/types.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <debug.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/i2c.h>
+
+#include <arch/irq.h>
+#include <arch/board/board.h>
+
+#include "wdog.h"
+#include "chip.h"
+#include "up_arch.h"
+#include "up_internal.h"
+#include "os_internal.h"
+
+#include "lpc23xx_pinsel.h"
+#include "lpc23xx_scb.h"
+#include "lpc23xx_i2c.h"
+
+#if defined(CONFIG_LPC2378_I2C0) || defined(CONFIG_LPC2378_I2C1) || \
+ defined(CONFIG_LPC2378_I2C2)
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#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
+
+#define I2C_TIMEOUT ((500 * CLK_TCK) / 1000) /* 500 mS */
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+struct lpc23xx_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 */
+};
+
+static struct lpc23xx_i2cdev_s i2cdevices[3];
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+static int i2c_start (struct lpc23xx_i2cdev_s *priv);
+static void i2c_stop (struct lpc23xx_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 lpc23xx_i2c_ops =
+{
+ .setfrequency = i2c_setfrequency,
+ .setaddress = i2c_setaddress,
+ .write = i2c_write,
+ .read = i2c_read,
+#ifdef CONFIG_I2C_TRANSFER
+ .transfer = i2c_transfer
+#endif
+};
+
+/*******************************************************************************
+ * Name: lpc23xx_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 lpc23xx_i2cdev_s *priv = (struct lpc23xx_i2cdev_s *) dev;
+
+ if (frequency > 100000)
+ {
+ /* Asymetric per 400Khz I2C spec */
+
+ putreg32(LPC23XX_CCLK / (83 + 47) * 47 / frequency,
+ priv->base + I2C_SCLH_OFFSET);
+ putreg32(LPC23XX_CCLK / (83 + 47) * 83 / frequency,
+ priv->base + I2C_SCLL_OFFSET);
+ }
+ else
+ {
+ /* 50/50 mark space ratio */
+
+ putreg32(LPC23XX_CCLK / 100 * 50 / frequency,
+ priv->base + I2C_SCLH_OFFSET);
+ putreg32(LPC23XX_CCLK / 100 * 50 / frequency,
+ priv->base + I2C_SCLL_OFFSET);
+ }
+
+ /* FIXME: This function should return the actual selected frequency */
+
+ return frequency;
+}
+
+/*******************************************************************************
+ * Name: lpc23xx_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 lpc23xx_i2cdev_s *priv = (struct lpc23xx_i2cdev_s *) dev;
+
+ DEBUGASSERT(dev != NULL);
+ DEBUGASSERT(nbits == 7);
+
+ priv->msg.addr = addr << 1;
+ priv->msg.flags = 0 ;
+
+ return OK;
+}
+
+/*******************************************************************************
+ * Name: lpc23xx_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 lpc23xx_i2cdev_s *priv = (struct lpc23xx_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: lpc23xx_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 lpc23xx_i2cdev_s *priv = (struct lpc23xx_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 lpc23xx_i2cdev_s *priv)
+{
+ int ret = -1;
+
+ sem_wait (&priv->mutex);
+
+ irqstate_t flags = irqsave();
+ putreg32(I2C_CONCLR_STAC | I2C_CONCLR_SIC, priv->base + I2C_CONCLR_OFFSET);
+ putreg32(I2C_CONSET_STA, priv->base + I2C_CONSET_OFFSET);
+ irqrestore (flags);
+
+ 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 lpc23xx_i2cdev_s *priv)
+{
+ if (priv->state != 0x38)
+ {
+ putreg32(I2C_CONSET_STO | I2C_CONSET_AA, priv->base + 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 lpc23xx_i2cdev_s *priv = (struct lpc23xx_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 lpc23xx_i2cdev_s *priv;
+
+#ifdef CONFIG_LPC2378_I2C0
+ if (irq == I2C0_IRQ)
+ {
+ priv = &i2cdevices[0];
+ }
+ else
+#endif
+#ifdef CONFIG_LPC2378_I2C1
+ if (irq == I2C1_IRQ)
+ {
+ priv = &i2cdevices[1];
+ }
+ else
+#endif
+#ifdef CONFIG_LPC2378_I2C2
+ if (irq == I2C2_IRQ)
+ {
+ priv = &i2cdevices[2];
+ }
+ else
+#endif
+ {
+ PANIC();
+ }
+
+ /* Reference UM10360 19.10.5 */
+
+ uint32_t state = getreg32(priv->base + I2C_STAT_OFFSET);
+ putreg32(I2C_CONCLR_SIC, priv->base + 2C_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 + I2C_DAT_OFFSET);
+ putreg32(I2C_CONCLR_STAC, priv->base + I2C_CONCLR_OFFSET);
+ break;
+
+ case 0x18:
+ priv->wrcnt=0;
+ putreg32(priv->msg.buffer[0], priv->base + I2C_DAT_OFFSET);
+ break;
+
+ case 0x28:
+ priv->wrcnt++;
+ if(priv->wrcnt<priv->msg.length)
+ {
+ putreg32(priv->msg.buffer[priv->wrcnt],priv->base+I2C_DAT_OFFSET);
+ }
+ else
+ {
+ i2c_stop(priv);
+ }
+
+ break;
+
+ case 0x40:
+ priv->rdcnt = -1;
+ putreg32(I2C_CONSET_AA, priv->base + I2C_CONSET_OFFSET);
+ break;
+
+ case 0x50:
+ priv->rdcnt++;
+ if (priv->rdcnt<priv->msg.length)
+ {
+ priv->msg.buffer[priv->rdcnt] = getreg32(priv->base + I2C_DAT_OFFSET);
+ }
+
+ if (priv->rdcnt>=priv->msg.length-1)
+ {
+ putreg32(I2C_CONCLR_AAC | I2C_CONCLR_SIC, priv->base + 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 lpc23xx_i2cdev_s *priv;
+ irqstate_t flags;
+ uint32_t regval;
+
+ if (port > 2)
+ {
+ dbg("lpc I2C Only support 0,1,2\n");
+ return NULL;
+ }
+
+ flags = irqsave();
+ priv = &i2cdevices[port];
+
+#ifdef CONFIG_LPC2378_I2C0
+ if (port == 0)
+ {
+ priv = (FAR struct lpc23xx_i2cdev_s *)&i2cdevices[0];
+ priv->base = I2C0_BASE_ADDR;
+ priv->irqid = I2C0_IRQ;
+
+ regval = getreg32(LPC23XX_SCB_BASE + SCB_PCONP_OFFSET);
+ regval |= PCI2C0;
+ putreg32(regval, LPC23XX_SCB_BASE + SCB_PCONP_OFFSET);
+
+ regval = getreg32(LPC23XX_SCB_BASE + SCB_PCLKSEL0_OFFSET);
+ regval &= ~I2C0_PCLKSEL_MASK;
+ regval |= I2C0_PCLKSEL;
+ putreg32(regval, LPC23XX_SCB_BASE + SCB_PCLKSEL0_OFFSET);
+
+ regval = getreg32(LPC23XX_PINSEL1);
+ regval &= ~I2C0_PINSEL_MASK ;
+ regval |= I2C0_PINSEL;
+ putreg32(regval, LPC23XX_PINSEL1);
+
+ putreg32(LPC23XX_CCLK / CONFIG_I2C0_FREQ / 2,
+ priv->base + I2C_SCLH_OFFSET);
+ putreg32(LPC23XX_CCLK / CONFIG_I2C0_FREQ / 2,
+ priv->base + I2C_SCLL_OFFSET);
+ }
+ else
+#endif
+#ifdef CONFIG_LPC2378_I2C1
+ if (port == 1)
+ {
+ priv= (FAR struct lpc23xx_i2cdev_s *)&i2cdevices[1];
+ priv->base = I2C1_BASE_ADDR;
+ priv->irqid = I2C1_IRQ;
+
+ regval = getreg32(LPC23XX_SCB_BASE + SCB_PCONP_OFFSET);
+ regval |= PCI2C1;
+ putreg32(regval, LPC23XX_SCB_BASE + SCB_PCONP_OFFSET);
+
+ regval = getreg32(LPC23XX_SCB_BASE + SCB_PCLKSEL1_OFFSET);
+ regval &= ~I2C1_PCLKSEL_MASK;
+ regval |= I2C1_PCLKSEL;
+ putreg32(regval, LPC23XX_SCB_BASE + SCB_PCLKSEL1_OFFSET);
+
+ regval = getreg32(LPC23XX_PINSEL0);
+ regval &= ~I2C1_PINSEL_MASK ;
+ regval |= I2C1_PINSEL;
+ putreg32(regval, LPC23XX_PINSEL0);
+
+ putreg32(LPC23XX_CCLK / CONFIG_I2C1_FREQ / 2,
+ priv->base + I2C_SCLH_OFFSET);
+ putreg32(LPC23XX_CCLK / CONFIG_I2C1_FREQ / 2,
+ priv->base + I2C_SCLL_OFFSET);
+ }
+ else
+#endif
+#ifdef CONFIG_LPC2378_I2C2
+ if (port == 2)
+ {
+ priv= (FAR struct lpc23xx_i2cdev_s *)&i2cdevices[2];
+ priv->base = I2C2_BASE_ADDR;
+ priv->irqid = I2C2_IRQ;
+
+ regval = getreg32(LPC23XX_SCB_BASE + SCB_PCONP_OFFSET);
+ regval |= PCI2C2;
+ putreg32(regval, LPC23XX_SCB_BASE + SCB_PCONP_OFFSET);
+
+ regval = getreg32(LPC23XX_SCB_BASE + SCB_PCLKSEL1_OFFSET);
+ regval &= ~I2C2_PCLKSEL_MASK;
+ regval |= I2C2_PCLKSEL;
+ putreg32(regval, LPC23XX_SCB_BASE + SCB_PCLKSEL1_OFFSET);
+
+ regval = getreg32(LPC23XX_PINSEL0);
+ regval &= ~I2C2_PINSEL_MASK ;
+ regval |= I2C2_PINSEL;
+ putreg32(regval, LPC23XX_PINSEL0);
+
+ putreg32(LPC23XX_CCLK / CONFIG_I2C2_FREQ / 2,
+ priv->base + I2C_SCLH_OFFSET);
+ putreg32(LPC23XX_CCLK / CONFIG_I2C2_FREQ / 2,
+ priv->base + I2C_SCLL_OFFSET);
+ }
+ else
+#endif
+ {
+ irqrestore(flags);
+ return NULL;
+ }
+
+ putreg32(I2C_CONSET_I2EN,priv->base+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 = &lpc23xx_i2c_ops;
+
+ irqrestore(flags);
+ return &priv->dev;
+}
+
+/*******************************************************************************
+ * Name: up_i2cuninitalize
+ *
+ * Description:
+ * Uninitialise an I2C device
+ *
+ *******************************************************************************/
+
+int up_i2cuninitialize(FAR struct i2c_dev_s * dev)
+{
+ struct lpc23xx_i2cdev_s *priv = (struct lpc23xx_i2cdev_s *)dev;
+
+ putreg32(I2C_CONCLRT_I2ENC,priv->base+I2C_CONCLR_OFFSET);
+ up_disable_irq(priv->irqid);
+ irq_detach(priv->irqid);
+ return OK;
+}
+
+#endif
diff --git a/nuttx/arch/arm/src/lpc2378/lpc23xx_i2c.h b/nuttx/arch/arm/src/lpc2378/lpc23xx_i2c.h
new file mode 100644
index 000000000..62b928b90
--- /dev/null
+++ b/nuttx/arch/arm/src/lpc2378/lpc23xx_i2c.h
@@ -0,0 +1,165 @@
+/************************************************************************************
+ * arch/arm/src/lpc2378/lpc23xx_i2c.h
+ *
+ * Copyright (C) 2013 Li Zhuoyi. All rights reserved.
+ * Author: Li Zhuoyi <lzyy.cn@gmail.com>
+ *
+ * Derived arch/arm/src/lpc17xx/lpc17_i2c.h
+ *
+ * Copyright (C) 2010 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <gnutt@nuttx.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ************************************************************************************/
+
+#ifndef __ARCH_ARM_SRC_LPC2378_LPC23XX_I2C_H
+#define __ARCH_ARM_SRC_LPC2378_LPC23XX_I2C_H
+
+/************************************************************************************
+ * Included Files
+ ************************************************************************************/
+
+#include <nuttx/config.h>
+
+#include "chip.h"
+
+/************************************************************************************
+ * Pre-processor Definitions
+ ************************************************************************************/
+/* I2C Pin Configuration ************************************************************/
+
+#define I2C0_PCLKSEL_MASK (0x03 << 14)
+#define I2C1_PCLKSEL_MASK (0x03 << 6)
+#define I2C2_PCLKSEL_MASK (0x03 << 20)
+#define I2C0_PCLKSEL (0x01 << 14)
+#define I2C1_PCLKSEL (0x01 << 6)
+#define I2C2_PCLKSEL (0x01 << 20)
+
+#define I2C0_PINSEL_MASK (0x0f << 22) /* P0.27 P0.28 PINSEL1 */
+#define I2C1_PINSEL_MASK (0x0f) /* P0.0 P0.1 PINSEL0 */
+#define I2C2_PINSEL_MASK (0x0f << 22) /* P0.10 P0.11 PINSEL0 */
+#define I2C0_PINSEL (0x05 << 22)
+#define I2C1_PINSEL (0x0f)
+#define I2C2_PINSEL (0x0a << 22)
+
+/* I2C Register addresses ***********************************************************/
+
+#define I2C0_CONSET (I2C0_BASE_ADDR+I2C_CONSET_OFFSET)
+#define I2C0_STAT (I2C0_BASE_ADDR+I2C_STAT_OFFSET)
+#define I2C0_DAT (I2C0_BASE_ADDR+I2C_DAT_OFFSET)
+#define I2C0_ADR0 (I2C0_BASE_ADDR+I2C_ADR0_OFFSET)
+#define I2C0_SCLH (I2C0_BASE_ADDR+I2C_SCLH_OFFSET)
+#define I2C0_SCLL (I2C0_BASE_ADDR+I2C_SCLL_OFFSET)
+#define I2C0_CONCLR (I2C0_BASE_ADDR+I2C_CONCLR_OFFSET)
+
+#define I2C1_CONSET (I2C1_BASE_ADDR+I2C_CONSET_OFFSET)
+#define I2C1_STAT (I2C1_BASE_ADDR+I2C_STAT_OFFSET)
+#define I2C1_DAT (I2C1_BASE_ADDR+I2C_DAT_OFFSET)
+#define I2C1_ADR0 (I2C1_BASE_ADDR+I2C_ADR0_OFFSET)
+#define I2C1_SCLH (I2C1_BASE_ADDR+I2C_SCLH_OFFSET)
+#define I2C1_SCLL (I2C1_BASE_ADDR+I2C_SCLL_OFFSET)
+#define I2C1_CONCLR (I2C1_BASE_ADDR+I2C_CONCLR_OFFSET)
+
+#define I2C2_CONSET (I2C2_BASE_ADDR+I2C_CONSET_OFFSET)
+#define I2C2_STAT (I2C2_BASE_ADDR+I2C_STAT_OFFSET)
+#define I2C2_DAT (I2C2_BASE_ADDR+I2C_DAT_OFFSET)
+#define I2C2_ADR0 (I2C2_BASE_ADDR+I2C_ADR0_OFFSET)
+#define I2C2_SCLH (I2C2_BASE_ADDR+I2C_SCLH_OFFSET)
+#define I2C2_SCLL (I2C2_BASE_ADDR+I2C_SCLL_OFFSET)
+#define I2C2_CONCLR (I2C2_BASE_ADDR+I2C_CONCLR_OFFSET)
+
+/* I2C Register bit definitions *****************************************************/
+/* I2C Control Set Register */
+
+ /* Bits 0-1: Reserved */
+#define I2C_CONSET_AA (1 << 2) /* Bit 2: Assert acknowledge flag */
+#define I2C_CONSET_SI (1 << 3) /* Bit 3: I2C interrupt flag */
+#define I2C_CONSET_STO (1 << 4) /* Bit 4: STOP flag */
+#define I2C_CONSET_STA (1 << 5) /* Bit 5: START flag */
+#define I2C_CONSET_I2EN (1 << 6) /* Bit 6: I2C interface enable */
+ /* Bits 7-31: Reserved */
+/* I2C Control Clear Register */
+ /* Bits 0-1: Reserved */
+#define I2C_CONCLR_AAC (1 << 2) /* Bit 2: Assert acknowledge Clear bit */
+#define I2C_CONCLR_SIC (1 << 3) /* Bit 3: I2C interrupt Clear bit */
+ /* Bit 4: Reserved */
+#define I2C_CONCLR_STAC (1 << 5) /* Bit 5: START flag Clear bit */
+#define I2C_CONCLRT_I2ENC (1 << 6) /* Bit 6: I2C interface Disable bit */
+ /* Bits 7-31: Reserved */
+/* I2C Status Register
+ *
+ * See tables 399-402 in the "LPC17xx User Manual" (UM10360), Rev. 01, 4 January
+ * 2010, NXP for definitions of status codes.
+ */
+
+#define I2C_STAT_MASK (0xff) /* Bits 0-7: I2C interface status
+ * Bits 0-1 always zero */
+ /* Bits 8-31: Reserved */
+/* I2C Data Register */
+
+#define I2C_DAT_MASK (0xff) /* Bits 0-7: I2C data */
+ /* Bits 8-31: Reserved */
+
+#define I2C_ADR_GC (1 << 0) /* Bit 0: GC General Call enable bit */
+#define I2C_ADR_ADDR_SHIFT (1) /* Bits 1-7: I2C slave address */
+#define I2C_ADR_ADDR_MASK (0x7f << I2C_ADR_ADDR_SHIFT)
+ /* Bits 8-31: Reserved */
+/* I2C Slave address mask registers:
+ *
+ * I2C Slave address mask register 0
+ * I2C Slave address mask register 1
+ * I2C Slave address mask register 2
+ * I2C Slave address mask register 3
+ */
+ /* Bit 0: Reserved */
+#define I2C_MASK_SHIFT (1) /* Bits 1-7: I2C mask bits */
+#define I2C_MASK_MASK (0x7f << I2C_ADR_ADDR_SHIFT)
+ /* Bits 8-31: Reserved */
+/* SCH Duty Cycle Register High Half Word */
+
+#define I2C_SCLH_MASK (0xffff) /* Bit 0-15: Count for SCL HIGH time period selection */
+ /* Bits 16-31: Reserved */
+/* SCL Duty Cycle Register Low Half Word */
+
+#define I2C_SCLL_MASK (0xffff) /* Bit 0-15: Count for SCL LOW time period selection */
+ /* Bits 16-31: Reserved */
+
+/************************************************************************************
+ * Public Types
+ ************************************************************************************/
+
+/************************************************************************************
+ * Public Data
+ ************************************************************************************/
+
+/************************************************************************************
+ * Public Functions
+ ************************************************************************************/
+
+#endif /* __ARCH_ARM_SRC_LPC2378_LPC23XX_I2C_H */