diff options
author | patacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3> | 2012-09-13 18:32:24 +0000 |
---|---|---|
committer | patacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3> | 2012-09-13 18:32:24 +0000 |
commit | df4622c8aa68493604f1e611eeb50c0960bb61a9 (patch) | |
tree | 1628300d9dbfac947ef9a9a8ec6013337cba17bb /nuttx/arch/arm/src/lpc17xx/lpc17_i2c.c | |
parent | 0661f846bdd4ef584ab5d0e85e3fecf74a1d9922 (diff) | |
download | px4-nuttx-df4622c8aa68493604f1e611eeb50c0960bb61a9.tar.gz px4-nuttx-df4622c8aa68493604f1e611eeb50c0960bb61a9.tar.bz2 px4-nuttx-df4622c8aa68493604f1e611eeb50c0960bb61a9.zip |
Email address change in nuttx/
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@5145 42af7a65-404d-4744-a932-0658087f49c3
Diffstat (limited to 'nuttx/arch/arm/src/lpc17xx/lpc17_i2c.c')
-rw-r--r-- | nuttx/arch/arm/src/lpc17xx/lpc17_i2c.c | 1090 |
1 files changed, 545 insertions, 545 deletions
diff --git a/nuttx/arch/arm/src/lpc17xx/lpc17_i2c.c b/nuttx/arch/arm/src/lpc17xx/lpc17_i2c.c index ccff276e5..48d6fefce 100644 --- a/nuttx/arch/arm/src/lpc17xx/lpc17_i2c.c +++ b/nuttx/arch/arm/src/lpc17xx/lpc17_i2c.c @@ -1,545 +1,545 @@ -/*******************************************************************************
- * arch/arm/src/lpc17xx/lpc17_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 <spudmonkey@racsa.co.cr>
- *
- * 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 "lpc17_internal.h"
-#include "lpc17_syscon.h"
-#include "lpc17_pinconn.h"
-#include "lpc17_i2c.h"
-
-#if defined(CONFIG_LPC17_I2C0) || defined(CONFIG_LPC17_I2C1) || defined(CONFIG_LPC17_I2C2)
-
-#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 lpc17_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 lpc17_i2cdev_s i2cdevices[3];
-
-/****************************************************************************
- * Private Functions
- ****************************************************************************/
-static int i2c_start (struct lpc17_i2cdev_s *priv);
-static void i2c_stop (struct lpc17_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 lpc17_i2c_ops =
-{
- .setfrequency = i2c_setfrequency,
- .setaddress = i2c_setaddress,
- .write = i2c_write,
- .read = i2c_read,
-#ifdef CONFIG_I2C_TRANSFER
- .transfer = i2c_transfer
-#endif
-};
-
-/*******************************************************************************
- * Name: lpc17_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 lpc17_i2cdev_s *priv = (struct lpc17_i2cdev_s *) dev;
-
- if (frequency > 100000)
- {
- /* asymetric per 400Khz I2C spec */
- putreg32 ( LPC17_CCLK / (83 + 47) * 47 / frequency, priv->base + LPC17_I2C_SCLH_OFFSET);
- putreg32 ( LPC17_CCLK / (83 + 47) * 83 / frequency, priv->base + LPC17_I2C_SCLL_OFFSET);
- }
- else
- {
- /* 50/50 mark space ratio */
- putreg32 (LPC17_CCLK / 100 * 50 / frequency, priv->base + LPC17_I2C_SCLH_OFFSET);
- putreg32 (LPC17_CCLK / 100 * 50 / frequency, priv->base + LPC17_I2C_SCLL_OFFSET);
- }
-
- /* FIXME: This function should return the actual selected frequency */
- return frequency;
-}
-
-/*******************************************************************************
- * Name: lpc17_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 lpc17_i2cdev_s *priv = (struct lpc17_i2cdev_s *) dev;
-
- DEBUGASSERT(dev != NULL);
- DEBUGASSERT(nbits == 7 );
-
- priv->msg.addr = addr<<1;
- priv->msg.flags = 0 ;
-
- return OK;
-}
-
-/*******************************************************************************
- * Name: lpc17_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 lpc17_i2cdev_s *priv = (struct lpc17_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: lpc17_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 lpc17_i2cdev_s *priv = (struct lpc17_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 lpc17_i2cdev_s *priv)
-{
- int ret=-1;
- sem_wait (&priv->mutex);
-
- putreg32(I2C_CONCLR_STAC|I2C_CONCLR_SIC,priv->base+LPC17_I2C_CONCLR_OFFSET);
- putreg32(I2C_CONSET_STA,priv->base+LPC17_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 lpc17_i2cdev_s *priv)
-{
- if(priv->state!=0x38)
- putreg32(I2C_CONSET_STO|I2C_CONSET_AA,priv->base+LPC17_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 lpc17_i2cdev_s *priv = (struct lpc17_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 lpc17_i2cdev_s *priv;
-#ifdef CONFIG_LPC17_I2C0
- if (irq == LPC17_IRQ_I2C0)
- {
- priv=&i2cdevices[0];
- }
- else
-#endif
-#ifdef CONFIG_LPC17_I2C1
- if (irq == LPC17_IRQ_I2C1)
- {
- priv=&i2cdevices[1];
- }
- else
-#endif
-#ifdef CONFIG_LPC17_I2C2
- if (irq == LPC17_IRQ_I2C2)
- {
- priv=&i2cdevices[2];
- }
- else
-#endif
- {
- PANIC(OSERR_INTERNAL);
- }
-/*
- * refrence UM10360 19.10.5
- */
- uint32_t state = getreg32(priv->base+LPC17_I2C_STAT_OFFSET);
- putreg32(I2C_CONCLR_SIC,priv->base+LPC17_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: //Repeat START
- putreg32(priv->msg.addr,priv->base+LPC17_I2C_DAT_OFFSET);
- putreg32(I2C_CONCLR_STAC,priv->base+LPC17_I2C_CONCLR_OFFSET);
- break;
- case 0x18:
- priv->wrcnt=0;
- putreg32(priv->msg.buffer[0],priv->base+LPC17_I2C_DAT_OFFSET);
- break;
- case 0x28:
- priv->wrcnt++;
- if(priv->wrcnt<priv->msg.length)
- putreg32(priv->msg.buffer[priv->wrcnt],priv->base+LPC17_I2C_DAT_OFFSET);
- else
- i2c_stop(priv);
- break;
- case 0x40:
- priv->rdcnt=-1;
- putreg32(I2C_CONSET_AA,priv->base+LPC17_I2C_CONSET_OFFSET);
- break;
- case 0x50:
- priv->rdcnt++;
- if(priv->rdcnt<priv->msg.length)
- priv->msg.buffer[priv->rdcnt]=getreg32(priv->base+LPC17_I2C_BUFR_OFFSET);
- if(priv->rdcnt>=priv->msg.length-1)
- putreg32(I2C_CONCLR_AAC|I2C_CONCLR_SIC,priv->base+LPC17_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 lpc17_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();
-
- priv= &i2cdevices[port];
-#ifdef CONFIG_LPC17_I2C0
- if (port==0)
- {
- priv= (FAR struct lpc17_i2cdev_s *)&i2cdevices[0];
- priv->base = LPC17_I2C0_BASE;
- priv->irqid = LPC17_IRQ_I2C0;
-
- regval = getreg32(LPC17_SYSCON_PCONP);
- regval |= SYSCON_PCONP_PCI2C0;
- putreg32(regval, LPC17_SYSCON_PCONP);
-
- regval = getreg32(LPC17_SYSCON_PCLKSEL0);
- regval &= ~SYSCON_PCLKSEL0_I2C0_MASK;
- regval |= (SYSCON_PCLKSEL_CCLK << SYSCON_PCLKSEL0_I2C0_SHIFT);
- putreg32(regval, LPC17_SYSCON_PCLKSEL0);
-
- lpc17_configgpio(GPIO_I2C0_SCL);
- lpc17_configgpio(GPIO_I2C0_SDA);
-
- putreg32 (LPC17_CCLK/CONFIG_I2C0_FREQ/2, priv->base + LPC17_I2C_SCLH_OFFSET);
- putreg32 (LPC17_CCLK/CONFIG_I2C0_FREQ/2, priv->base + LPC17_I2C_SCLL_OFFSET);
-
- }
- else
-#endif
-#ifdef CONFIG_LPC17_I2C1
- if(port==1)
- {
- priv= (FAR struct lpc17_i2cdev_s *)&i2cdevices[1];
- priv->base = LPC17_I2C1_BASE;
- priv->irqid = LPC17_IRQ_I2C1;
-
- regval = getreg32(LPC17_SYSCON_PCONP);
- regval |= SYSCON_PCONP_PCI2C1;
- putreg32(regval, LPC17_SYSCON_PCONP);
-
- regval = getreg32(LPC17_SYSCON_PCLKSEL1);
- regval &= ~SYSCON_PCLKSEL1_I2C1_MASK;
- regval |= (SYSCON_PCLKSEL_CCLK << SYSCON_PCLKSEL1_I2C1_SHIFT);
- putreg32(regval, LPC17_SYSCON_PCLKSEL1);
-
- lpc17_configgpio(GPIO_I2C1_SCL);
- lpc17_configgpio(GPIO_I2C1_SDA);
-
- putreg32 (LPC17_CCLK/CONFIG_I2C1_FREQ/2, priv->base + LPC17_I2C_SCLH_OFFSET);
- putreg32 (LPC17_CCLK/CONFIG_I2C1_FREQ/2, priv->base + LPC17_I2C_SCLL_OFFSET);
- }
- else
-#endif
-#ifdef CONFIG_LPC17_I2C2
- if(port==2)
- {
- priv= (FAR struct lpc17_i2cdev_s *)&i2cdevices[2];
- priv->base = LPC17_I2C2_BASE;
- priv->irqid = LPC17_IRQ_I2C2;
-
- regval = getreg32(LPC17_SYSCON_PCONP);
- regval |= SYSCON_PCONP_PCI2C2;
- putreg32(regval, LPC17_SYSCON_PCONP);
-
- regval = getreg32(LPC17_SYSCON_PCLKSEL1);
- regval &= ~SYSCON_PCLKSEL1_I2C2_MASK;
- regval |= (SYSCON_PCLKSEL_CCLK << SYSCON_PCLKSEL1_I2C2_SHIFT);
- putreg32(regval, LPC17_SYSCON_PCLKSEL1);
-
- lpc17_configgpio(GPIO_I2C2_SCL);
- lpc17_configgpio(GPIO_I2C2_SDA);
-
- putreg32 (LPC17_CCLK/CONFIG_I2C2_FREQ/2, priv->base + LPC17_I2C_SCLH_OFFSET);
- putreg32 (LPC17_CCLK/CONFIG_I2C2_FREQ/2, priv->base + LPC17_I2C_SCLL_OFFSET);
- }
- else
-#endif
- {
- return NULL;
- }
- putreg32(I2C_CONSET_I2EN,priv->base+LPC17_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 = &lpc17_i2c_ops;
-
- return &priv->dev;
-}
-
-/*******************************************************************************
- * Name: up_i2cuninitalize
- *
- * Description:
- * Uninitialise an I2C device
- *
- *******************************************************************************/
-
-int up_i2cuninitialize(FAR struct i2c_dev_s * dev)
-{
- struct lpc17_i2cdev_s *priv = (struct lpc17_i2cdev_s *) dev;
-
- putreg32(I2C_CONCLRT_I2ENC,priv->base+LPC17_I2C_CONCLR_OFFSET);
- up_disable_irq(priv->irqid);
- irq_detach (priv->irqid);
- return OK;
-}
-
-#endif
+/******************************************************************************* + * arch/arm/src/lpc17xx/lpc17_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 "lpc17_internal.h" +#include "lpc17_syscon.h" +#include "lpc17_pinconn.h" +#include "lpc17_i2c.h" + +#if defined(CONFIG_LPC17_I2C0) || defined(CONFIG_LPC17_I2C1) || defined(CONFIG_LPC17_I2C2) + +#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 lpc17_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 lpc17_i2cdev_s i2cdevices[3]; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ +static int i2c_start (struct lpc17_i2cdev_s *priv); +static void i2c_stop (struct lpc17_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 lpc17_i2c_ops = +{ + .setfrequency = i2c_setfrequency, + .setaddress = i2c_setaddress, + .write = i2c_write, + .read = i2c_read, +#ifdef CONFIG_I2C_TRANSFER + .transfer = i2c_transfer +#endif +}; + +/******************************************************************************* + * Name: lpc17_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 lpc17_i2cdev_s *priv = (struct lpc17_i2cdev_s *) dev; + + if (frequency > 100000) + { + /* asymetric per 400Khz I2C spec */ + putreg32 ( LPC17_CCLK / (83 + 47) * 47 / frequency, priv->base + LPC17_I2C_SCLH_OFFSET); + putreg32 ( LPC17_CCLK / (83 + 47) * 83 / frequency, priv->base + LPC17_I2C_SCLL_OFFSET); + } + else + { + /* 50/50 mark space ratio */ + putreg32 (LPC17_CCLK / 100 * 50 / frequency, priv->base + LPC17_I2C_SCLH_OFFSET); + putreg32 (LPC17_CCLK / 100 * 50 / frequency, priv->base + LPC17_I2C_SCLL_OFFSET); + } + + /* FIXME: This function should return the actual selected frequency */ + return frequency; +} + +/******************************************************************************* + * Name: lpc17_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 lpc17_i2cdev_s *priv = (struct lpc17_i2cdev_s *) dev; + + DEBUGASSERT(dev != NULL); + DEBUGASSERT(nbits == 7 ); + + priv->msg.addr = addr<<1; + priv->msg.flags = 0 ; + + return OK; +} + +/******************************************************************************* + * Name: lpc17_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 lpc17_i2cdev_s *priv = (struct lpc17_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: lpc17_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 lpc17_i2cdev_s *priv = (struct lpc17_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 lpc17_i2cdev_s *priv) +{ + int ret=-1; + sem_wait (&priv->mutex); + + putreg32(I2C_CONCLR_STAC|I2C_CONCLR_SIC,priv->base+LPC17_I2C_CONCLR_OFFSET); + putreg32(I2C_CONSET_STA,priv->base+LPC17_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 lpc17_i2cdev_s *priv) +{ + if(priv->state!=0x38) + putreg32(I2C_CONSET_STO|I2C_CONSET_AA,priv->base+LPC17_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 lpc17_i2cdev_s *priv = (struct lpc17_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 lpc17_i2cdev_s *priv; +#ifdef CONFIG_LPC17_I2C0 + if (irq == LPC17_IRQ_I2C0) + { + priv=&i2cdevices[0]; + } + else +#endif +#ifdef CONFIG_LPC17_I2C1 + if (irq == LPC17_IRQ_I2C1) + { + priv=&i2cdevices[1]; + } + else +#endif +#ifdef CONFIG_LPC17_I2C2 + if (irq == LPC17_IRQ_I2C2) + { + priv=&i2cdevices[2]; + } + else +#endif + { + PANIC(OSERR_INTERNAL); + } +/* + * refrence UM10360 19.10.5 + */ + uint32_t state = getreg32(priv->base+LPC17_I2C_STAT_OFFSET); + putreg32(I2C_CONCLR_SIC,priv->base+LPC17_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: //Repeat START + putreg32(priv->msg.addr,priv->base+LPC17_I2C_DAT_OFFSET); + putreg32(I2C_CONCLR_STAC,priv->base+LPC17_I2C_CONCLR_OFFSET); + break; + case 0x18: + priv->wrcnt=0; + putreg32(priv->msg.buffer[0],priv->base+LPC17_I2C_DAT_OFFSET); + break; + case 0x28: + priv->wrcnt++; + if(priv->wrcnt<priv->msg.length) + putreg32(priv->msg.buffer[priv->wrcnt],priv->base+LPC17_I2C_DAT_OFFSET); + else + i2c_stop(priv); + break; + case 0x40: + priv->rdcnt=-1; + putreg32(I2C_CONSET_AA,priv->base+LPC17_I2C_CONSET_OFFSET); + break; + case 0x50: + priv->rdcnt++; + if(priv->rdcnt<priv->msg.length) + priv->msg.buffer[priv->rdcnt]=getreg32(priv->base+LPC17_I2C_BUFR_OFFSET); + if(priv->rdcnt>=priv->msg.length-1) + putreg32(I2C_CONCLR_AAC|I2C_CONCLR_SIC,priv->base+LPC17_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 lpc17_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(); + + priv= &i2cdevices[port]; +#ifdef CONFIG_LPC17_I2C0 + if (port==0) + { + priv= (FAR struct lpc17_i2cdev_s *)&i2cdevices[0]; + priv->base = LPC17_I2C0_BASE; + priv->irqid = LPC17_IRQ_I2C0; + + regval = getreg32(LPC17_SYSCON_PCONP); + regval |= SYSCON_PCONP_PCI2C0; + putreg32(regval, LPC17_SYSCON_PCONP); + + regval = getreg32(LPC17_SYSCON_PCLKSEL0); + regval &= ~SYSCON_PCLKSEL0_I2C0_MASK; + regval |= (SYSCON_PCLKSEL_CCLK << SYSCON_PCLKSEL0_I2C0_SHIFT); + putreg32(regval, LPC17_SYSCON_PCLKSEL0); + + lpc17_configgpio(GPIO_I2C0_SCL); + lpc17_configgpio(GPIO_I2C0_SDA); + + putreg32 (LPC17_CCLK/CONFIG_I2C0_FREQ/2, priv->base + LPC17_I2C_SCLH_OFFSET); + putreg32 (LPC17_CCLK/CONFIG_I2C0_FREQ/2, priv->base + LPC17_I2C_SCLL_OFFSET); + + } + else +#endif +#ifdef CONFIG_LPC17_I2C1 + if(port==1) + { + priv= (FAR struct lpc17_i2cdev_s *)&i2cdevices[1]; + priv->base = LPC17_I2C1_BASE; + priv->irqid = LPC17_IRQ_I2C1; + + regval = getreg32(LPC17_SYSCON_PCONP); + regval |= SYSCON_PCONP_PCI2C1; + putreg32(regval, LPC17_SYSCON_PCONP); + + regval = getreg32(LPC17_SYSCON_PCLKSEL1); + regval &= ~SYSCON_PCLKSEL1_I2C1_MASK; + regval |= (SYSCON_PCLKSEL_CCLK << SYSCON_PCLKSEL1_I2C1_SHIFT); + putreg32(regval, LPC17_SYSCON_PCLKSEL1); + + lpc17_configgpio(GPIO_I2C1_SCL); + lpc17_configgpio(GPIO_I2C1_SDA); + + putreg32 (LPC17_CCLK/CONFIG_I2C1_FREQ/2, priv->base + LPC17_I2C_SCLH_OFFSET); + putreg32 (LPC17_CCLK/CONFIG_I2C1_FREQ/2, priv->base + LPC17_I2C_SCLL_OFFSET); + } + else +#endif +#ifdef CONFIG_LPC17_I2C2 + if(port==2) + { + priv= (FAR struct lpc17_i2cdev_s *)&i2cdevices[2]; + priv->base = LPC17_I2C2_BASE; + priv->irqid = LPC17_IRQ_I2C2; + + regval = getreg32(LPC17_SYSCON_PCONP); + regval |= SYSCON_PCONP_PCI2C2; + putreg32(regval, LPC17_SYSCON_PCONP); + + regval = getreg32(LPC17_SYSCON_PCLKSEL1); + regval &= ~SYSCON_PCLKSEL1_I2C2_MASK; + regval |= (SYSCON_PCLKSEL_CCLK << SYSCON_PCLKSEL1_I2C2_SHIFT); + putreg32(regval, LPC17_SYSCON_PCLKSEL1); + + lpc17_configgpio(GPIO_I2C2_SCL); + lpc17_configgpio(GPIO_I2C2_SDA); + + putreg32 (LPC17_CCLK/CONFIG_I2C2_FREQ/2, priv->base + LPC17_I2C_SCLH_OFFSET); + putreg32 (LPC17_CCLK/CONFIG_I2C2_FREQ/2, priv->base + LPC17_I2C_SCLL_OFFSET); + } + else +#endif + { + return NULL; + } + putreg32(I2C_CONSET_I2EN,priv->base+LPC17_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 = &lpc17_i2c_ops; + + return &priv->dev; +} + +/******************************************************************************* + * Name: up_i2cuninitalize + * + * Description: + * Uninitialise an I2C device + * + *******************************************************************************/ + +int up_i2cuninitialize(FAR struct i2c_dev_s * dev) +{ + struct lpc17_i2cdev_s *priv = (struct lpc17_i2cdev_s *) dev; + + putreg32(I2C_CONCLRT_I2ENC,priv->base+LPC17_I2C_CONCLR_OFFSET); + up_disable_irq(priv->irqid); + irq_detach (priv->irqid); + return OK; +} + +#endif |