diff --git a/arch/arm/src/lpc2378/lpc23xx_i2c.c b/arch/arm/src/lpc2378/lpc23xx_i2c.c index 8ca35d9fd2a..bb0f784ac6c 100644 --- a/arch/arm/src/lpc2378/lpc23xx_i2c.c +++ b/arch/arm/src/lpc2378/lpc23xx_i2c.c @@ -1,20 +1,21 @@ /**************************************************************************** - * arch/arm/src/lpc2378/lpc23xx_i2c.c + * arch/arm/src/lpc23xx/lpc23xx_i2c.c * - * Copyright (C) 2013 Li Zhuoyi. All rights reserved. - * Author: Li Zhuoyi + * Copyright (C) 2013, 2016 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt * - * Derived from arch/arm/src/lpc17xx/lpc23xx_i2c.c + * Derived from arch/arm/src/lpc17xx/lpc17xx_i2c.c * + * Copyright (C) 2012, 2014-2016 Gregory Nutt. All rights reserved. * Copyright (C) 2011 Li Zhuoyi. All rights reserved. - * Author: Li Zhuoyi - * History: 0.1 2011-08-20 initial version + * Author: Li Zhuoyi (Original author) + * Gregory Nutt * * Derived from arch/arm/src/lpc31xx/lpc31_i2c.c * * Author: David Hewson * - * Copyright (C) 2010-2011, 2014 Gregory Nutt. All rights reserved. + * Copyright (C) 2010-2011 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -87,83 +88,106 @@ # define GPIO_I2C1_SDA GPIO_I2C1_SDA_1 #endif -#ifndef CONFIG_I2C0_FREQ -# define CONFIG_I2C0_FREQ 100000 +#ifndef CONFIG_LPC2378_I2C0_FREQUENCY +# define CONFIG_LPC2378_I2C0_FREQUENCY 100000 #endif -#ifndef CONFIG_I2C1_FREQ -# define CONFIG_I2C1_FREQ 100000 +#ifndef CONFIG_LPC2378_I2C1_FREQUENCY +# define CONFIG_LPC2378_I2C1_FREQUENCY 100000 #endif -#ifndef CONFIG_I2C2_FREQ -# define CONFIG_I2C2_FREQ 100000 +#ifndef CONFIG_LPC2378_I2C2_FREQUENCY +# define CONFIG_LPC2378_I2C2_FREQUENCY 100000 #endif -#define I2C_TIMEOUT ((500 * CLK_TCK) / 1000) /* 500 mS */ +#define I2C_TIMEOUT (20 * 1000/CONFIG_USEC_PER_TICK) /* 20 mS */ +#define LPC2378_I2C1_FREQUENCY 400000 + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct lpc2378_i2cdev_s +{ + struct i2c_master_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 */ + + struct i2c_msg_s *msgs; /* remaining transfers - first one is in progress */ + unsigned int nmsg; /* number of transfer remaining */ + + uint16_t wrcnt; /* number of bytes sent to tx fifo */ + uint16_t rdcnt; /* number of bytes read from rx fifo */ +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static int lpc2378_i2c_start(struct lpc2378_i2cdev_s *priv); +static void lpc2378_i2c_stop(struct lpc2378_i2cdev_s *priv); +static int lpc2378_i2c_interrupt(int irq, FAR void *context); +static void lpc2378_i2c_timeout(int argc, uint32_t arg, ...); + +/* I2C device operations */ + +static uint32_t lpc2378_i2c_setfrequency(FAR struct i2c_master_s *dev, + uint32_t frequency); +static int lpc2378_i2c_setaddress(FAR struct i2c_master_s *dev, int addr, + int nbits); +static int lpc2378_i2c_write(FAR struct i2c_master_s *dev, + const uint8_t *buffer, int buflen); +static int lpc2378_i2c_read(FAR struct i2c_master_s *dev, uint8_t *buffer, + int buflen); +#ifdef CONFIG_I2C_TRANSFER +static int lpc2378_i2c_transfer(FAR struct i2c_master_s *dev, + FAR struct i2c_msg_s *msgs, int count); +#endif +static void lpc2378_stopnext(struct lpc2378_i2cdev_s *priv); /**************************************************************************** * Private Data ****************************************************************************/ -struct lpc23xx_i2cdev_s +#ifdef CONFIG_LPC2378_I2C0 +static struct lpc2378_i2cdev_s g_i2c0dev; +#endif +#ifdef CONFIG_LPC2378_I2C1 +static struct lpc2378_i2cdev_s g_i2c1dev; +#endif +#ifdef CONFIG_LPC2378_I2C2 +static struct lpc2378_i2cdev_s g_i2c2dev; +#endif + +struct i2c_ops_s lpc2378_i2c_ops = { - struct i2c_master_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_master_s *dev, uint32_t frequency); -static int i2c_setaddress(FAR struct i2c_master_s *dev, int addr, int nbits); -static int i2c_write(FAR struct i2c_master_s *dev, const uint8_t *buffer, int buflen); -static int i2c_read(FAR struct i2c_master_s *dev, uint8_t *buffer, int buflen); -static int i2c_transfer(FAR struct i2c_master_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, + .setfrequency = lpc2378_i2c_setfrequency, + .setaddress = lpc2378_i2c_setaddress, + .write = lpc2378_i2c_write, + .read = lpc2378_i2c_read, #ifdef CONFIG_I2C_TRANSFER - .transfer = i2c_transfer + .transfer = lpc2378_i2c_transfer #endif }; /**************************************************************************** - * Name: lpc23xx_i2c_setfrequency + * Name: lpc2378_i2c_setfrequency * * Description: * Set the frequence for the next transfer * ****************************************************************************/ -static uint32_t i2c_setfrequency(FAR struct i2c_master_s *dev, uint32_t frequency) +static uint32_t lpc2378_i2c_setfrequency(FAR struct i2c_master_s *dev, + uint32_t frequency) { - struct lpc23xx_i2cdev_s *priv = (struct lpc23xx_i2cdev_s *) dev; + struct lpc2378_i2cdev_s *priv = (struct lpc2378_i2cdev_s *) dev; if (frequency > 100000) { @@ -190,28 +214,28 @@ static uint32_t i2c_setfrequency(FAR struct i2c_master_s *dev, uint32_t frequenc } /**************************************************************************** - * Name: lpc23xx_i2c_setaddress + * Name: lpc2378_i2c_setaddress * * Description: * Set the I2C slave address for a subsequent read/write * ****************************************************************************/ -static int i2c_setaddress(FAR struct i2c_master_s *dev, int addr, int nbits) +static int lpc2378_i2c_setaddress(FAR struct i2c_master_s *dev, int addr, + int nbits) { - struct lpc23xx_i2cdev_s *priv = (struct lpc23xx_i2cdev_s *) dev; + struct lpc2378_i2cdev_s *priv = (struct lpc2378_i2cdev_s *)dev; DEBUGASSERT(dev != NULL); DEBUGASSERT(nbits == 7); - priv->msg.addr = addr << 1; - priv->msg.flags = 0 ; + priv->msg.addr = addr; return OK; } /**************************************************************************** - * Name: lpc23xx_i2c_write + * Name: lpc2378_i2c_write * * Description: * Send a block of data on I2C using the previously selected I2C @@ -219,26 +243,33 @@ static int i2c_setaddress(FAR struct i2c_master_s *dev, int addr, int nbits) * ****************************************************************************/ -static int i2c_write(FAR struct i2c_master_s *dev, const uint8_t *buffer, int buflen) +static int lpc2378_i2c_write(FAR struct i2c_master_s *dev, const uint8_t *buffer, + int buflen) { - struct lpc23xx_i2cdev_s *priv = (struct lpc23xx_i2cdev_s *) dev; - int ret; + struct lpc2378_i2cdev_s *priv = (struct lpc2378_i2cdev_s *)dev; + int ret = 0; - DEBUGASSERT (dev != NULL); + DEBUGASSERT(dev != NULL); - priv->wrcnt = 0; - priv->rdcnt = 0; - priv->msg.addr &= ~0x01; + priv->wrcnt = 0; + priv->rdcnt = 0; + priv->msg.flags = 0; priv->msg.buffer = (uint8_t *)buffer; priv->msg.length = buflen; - ret = i2c_start (priv); + priv->nmsg = 1; + priv->msgs = &(priv->msg); - return ret > 0 ? OK : -ETIMEDOUT; + if (buflen > 0) + { + ret = lpc2378_i2c_start(priv); + } + + return (ret == 0 ? 0 : -ETIMEDOUT); } /**************************************************************************** - * Name: lpc23xx_i2c_read + * Name: lpc2378_i2c_read * * Description: * Receive a block of data on I2C using the previously selected I2C @@ -246,89 +277,91 @@ static int i2c_write(FAR struct i2c_master_s *dev, const uint8_t *buffer, int bu * ****************************************************************************/ -static int i2c_read(FAR struct i2c_master_s *dev, uint8_t *buffer, int buflen) +static int lpc2378_i2c_read(FAR struct i2c_master_s *dev, uint8_t *buffer, + int buflen) { - struct lpc23xx_i2cdev_s *priv = (struct lpc23xx_i2cdev_s *) dev; - int ret; + struct lpc2378_i2cdev_s *priv = (struct lpc2378_i2cdev_s *)dev; + int ret = 0; - DEBUGASSERT (dev != NULL); + DEBUGASSERT(dev != NULL); - priv->wrcnt = 0; - priv->rdcnt = 0; - priv->msg.addr |= 0x01; + priv->wrcnt = 0; + priv->rdcnt = 0; + priv->msg.flags = I2C_M_READ; priv->msg.buffer = buffer; priv->msg.length = buflen; - ret = i2c_start(priv); + priv->nmsg = 1; + priv->msgs = &(priv->msg); - return ret > 0 ? OK : -ETIMEDOUT; + if (buflen > 0) + { + ret = lpc2378_i2c_start(priv); + } + + return (ret == 0 ? 0 : -ETIMEDOUT); } /**************************************************************************** - * Name: i2c_start + * Name: lpc2378_i2c_start * * Description: * Perform a I2C transfer start * ****************************************************************************/ -static int i2c_start (struct lpc23xx_i2cdev_s *priv) +static int lpc2378_i2c_start(struct lpc2378_i2cdev_s *priv) { int ret = -1; - sem_wait (&priv->mutex); + sem_wait(&priv->mutex); - irqstate_t flags = irqsave(); - putreg32(I2C_CONCLR_STAC | I2C_CONCLR_SIC, priv->base + I2C_CONCLR_OFFSET); + 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); + wd_start(priv->timeout, I2C_TIMEOUT, lpc2378_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; - } + wd_cancel(priv->timeout); + + ret = priv->nmsg; + + sem_post(&priv->mutex); return ret; } /**************************************************************************** - * Name: i2c_stop + * Name: lpc2378_i2c_stop * * Description: * Perform a I2C transfer stop * ****************************************************************************/ -static void i2c_stop (struct lpc23xx_i2cdev_s *priv) +static void lpc2378_i2c_stop(struct lpc2378_i2cdev_s *priv) { if (priv->state != 0x38) { - putreg32(I2C_CONSET_STO | I2C_CONSET_AA, priv->base + I2C_CONSET_OFFSET); + putreg32(I2C_CONSET_STO | I2C_CONSET_AA, + priv->base + I2C_CONSET_OFFSET); } - sem_post (&priv->wait); + sem_post(&priv->wait); } /**************************************************************************** - * Name: i2c_timeout + * Name: lpc2378_i2c_timeout * * Description: * Watchdog timer for timeout of I2C operation * ****************************************************************************/ -static void i2c_timeout (int argc, uint32_t arg, ...) +static void lpc2378_i2c_timeout(int argc, uint32_t arg, ...) { - struct lpc23xx_i2cdev_s *priv = (struct lpc23xx_i2cdev_s *)arg; + struct lpc2378_i2cdev_s *priv = (struct lpc2378_i2cdev_s *)arg; irqstate_t flags = irqsave(); priv->state = 0xff; @@ -337,35 +370,88 @@ static void i2c_timeout (int argc, uint32_t arg, ...) } /**************************************************************************** - * Name: i2c_interrupt + * Name: lpc2378_i2c_transfer + * + * Description: + * Perform a sequence of I2C transfers + * + ****************************************************************************/ + +#ifdef CONFIG_I2C_TRANSFER +static int lpc2378_i2c_transfer(FAR struct i2c_master_s *dev, + FAR struct i2c_msg_s *msgs, int count) +{ + struct lpc2378_i2cdev_s *priv = (struct lpc2378_i2cdev_s *)dev; + int ret; + + DEBUGASSERT(dev != NULL); + + priv->wrcnt = 0; + priv->rdcnt = 0; + priv->msgs = msgs; + priv->nmsg = count; + + ret = lpc2378_i2c_start(priv); + + return ret; +} +#endif + +/**************************************************************************** + * Name: lpc2378_i2c_interrupt + * + * Description: + * Check if we need to issue STOP at the next message + * + ****************************************************************************/ + +static void lpc2378_stopnext(struct lpc2378_i2cdev_s *priv) +{ + priv->nmsg--; + + if (priv->nmsg > 0) + { + priv->msgs++; + putreg32(I2C_CONSET_STA, priv->base + I2C_CONSET_OFFSET); + } + else + { + lpc2378_i2c_stop(priv); + } +} + +/**************************************************************************** + * Name: lpc2378_i2c_interrupt * * Description: * The I2C Interrupt Handler * ****************************************************************************/ -static int i2c_interrupt (int irq, FAR void *context) +static int lpc2378_i2c_interrupt(int irq, FAR void *context) { - struct lpc23xx_i2cdev_s *priv; + struct lpc2378_i2cdev_s *priv; + struct i2c_msg_s *msg; + uint32_t state; #ifdef CONFIG_LPC2378_I2C0 if (irq == I2C0_IRQ) { - priv = &i2cdevices[0]; + priv = &g_i2c0dev; } else #endif #ifdef CONFIG_LPC2378_I2C1 if (irq == I2C1_IRQ) { - priv = &i2cdevices[1]; + priv = &g_i2c1dev; } else #endif #ifdef CONFIG_LPC2378_I2C2 if (irq == I2C2_IRQ) { - priv = &i2cdevices[2]; + priv = &g_i2c2dev; } else #endif @@ -375,78 +461,90 @@ static int i2c_interrupt (int irq, FAR void *context) /* Reference UM10360 19.10.5 */ - uint32_t state = getreg32(priv->base + I2C_STAT_OFFSET); - putreg32(I2C_CONCLR_SIC, priv->base + I2C_CONCLR_OFFSET); + state = getreg32(priv->base + I2C_STAT_OFFSET); + msg = priv->msgs; priv->state = state; - state &= 0xf8; + state &= 0xf8; /* state mask, only 0xX8 is possible */ 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 0x08: /* A START condition has been transmitted. */ + case 0x10: /* A Repeated START condition has been transmitted. */ + /* Set address */ - case 0x18: - priv->wrcnt = 0; - putreg32(priv->msg.buffer[0], priv->base + I2C_DAT_OFFSET); - break; + putreg32(((I2C_M_READ & msg->flags) == I2C_M_READ) ? + I2C_READADDR8(msg->addr) : + I2C_WRITEADDR8(msg->addr), priv->base + I2C_DAT_OFFSET); - 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); - } + /* Clear start bit */ - break; + putreg32(I2C_CONCLR_STAC, priv->base + I2C_CONCLR_OFFSET); + break; - case 0x40: - priv->rdcnt = -1; - putreg32(I2C_CONSET_AA, priv->base + I2C_CONSET_OFFSET); - break; + /* Write cases */ - case 0x50: - priv->rdcnt++; - if (priv->rdcnt < priv->msg.length) - { - priv->msg.buffer[priv->rdcnt] = getreg32(priv->base + I2C_DAT_OFFSET); - } + case 0x18: /* SLA+W has been transmitted; ACK has been received */ + priv->wrcnt = 0; + putreg32(msg->buffer[0], priv->base + I2C_DAT_OFFSET); /* put first byte */ + break; - if (priv->rdcnt >= priv->msg.length-1) - { - putreg32(I2C_CONCLR_AAC | I2C_CONCLR_SIC, priv->base + I2C_CONCLR_OFFSET); - } - break; + case 0x28: /* Data byte in DAT has been transmitted; ACK has been received. */ + priv->wrcnt++; - case 0x58: - i2c_stop(priv); - break; + if (priv->wrcnt < msg->length) + { + putreg32(msg->buffer[priv->wrcnt], priv->base + I2C_DAT_OFFSET); /* Put next byte */ + } + else + { + lpc2378_stopnext(priv); + } + break; - default: - i2c_stop(priv); - break; + /* Read cases */ + + case 0x40: /* SLA+R has been transmitted; ACK has been received */ + priv->rdcnt = 0; + if (msg->length > 1) + { + putreg32(I2C_CONSET_AA, priv->base + I2C_CONSET_OFFSET); /* Set ACK next read */ + } + else + { + putreg32(I2C_CONCLR_AAC, priv->base + I2C_CONCLR_OFFSET); /* Do not ACK because only one byte */ + } + break; + + case 0x50: /* Data byte has been received; ACK has been returned. */ + priv->rdcnt++; + msg->buffer[priv->rdcnt - 1] = getreg32(priv->base + I2C_DAT_OFFSET); + + if (priv->rdcnt >= (msg->length - 1)) + { + putreg32(I2C_CONCLR_AAC, priv->base + I2C_CONCLR_OFFSET); /* Do not ACK any more */ + } + break; + + case 0x58: /* Data byte has been received; NACK has been returned. */ + msg->buffer[priv->rdcnt] = getreg32(priv->base + I2C_DAT_OFFSET); + lpc2378_stopnext(priv); + break; + + default: + lpc2378_i2c_stop(priv); + break; } + putreg32(I2C_CONCLR_SIC, priv->base + I2C_CONCLR_OFFSET); /* clear interrupt */ + return OK; } /**************************************************************************** * Public Functions ****************************************************************************/ + /**************************************************************************** * Name: up_i2cinitialize * @@ -457,26 +555,28 @@ static int i2c_interrupt (int irq, FAR void *context) struct i2c_master_s *up_i2cinitialize(int port) { - struct lpc23xx_i2cdev_s *priv; - irqstate_t flags; - uint32_t regval; + struct lpc2378_i2cdev_s *priv; - if (port > 2) + if (port > 1) { - dbg("lpc I2C Only support 0,1,2\n"); + dbg("lpc I2C Only support 0,1\n"); return NULL; } + irqstate_t flags; + uint32_t regval; + flags = irqsave(); - priv = &i2cdevices[port]; #ifdef CONFIG_LPC2378_I2C0 if (port == 0) { - priv = (FAR struct lpc23xx_i2cdev_s *)&i2cdevices[0]; + priv = &g_i2c0dev; priv->base = I2C0_BASE_ADDR; priv->irqid = I2C0_IRQ; + /* Enable clocking */ + regval = getreg32(LPC23XX_SCB_BASE + SCB_PCONP_OFFSET); regval |= PCI2C0; putreg32(regval, LPC23XX_SCB_BASE + SCB_PCONP_OFFSET); @@ -486,25 +586,29 @@ struct i2c_master_s *up_i2cinitialize(int port) regval |= I2C0_PCLKSEL; putreg32(regval, LPC23XX_SCB_BASE + SCB_PCLKSEL0_OFFSET); + /* Pin configuration */ + 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); + /* Set default frequency */ + + lpc2378_i2c_setfrequency((struct i2c_master_s *)priv, + CONFIG_LPC2378_I2C0_FREQUENCY); } else #endif #ifdef CONFIG_LPC2378_I2C1 if (port == 1) { - priv = (FAR struct lpc23xx_i2cdev_s *)&i2cdevices[1]; + priv = &g_i2c1dev; priv->base = I2C1_BASE_ADDR; priv->irqid = I2C1_IRQ; + /* Enable clocking */ + regval = getreg32(LPC23XX_SCB_BASE + SCB_PCONP_OFFSET); regval |= PCI2C1; putreg32(regval, LPC23XX_SCB_BASE + SCB_PCONP_OFFSET); @@ -514,25 +618,29 @@ struct i2c_master_s *up_i2cinitialize(int port) regval |= I2C1_PCLKSEL; putreg32(regval, LPC23XX_SCB_BASE + SCB_PCLKSEL1_OFFSET); + /* Pin configuration */ + 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); + /* Set default frequency */ + + lpc2378_i2c_setfrequency((struct i2c_master_s *)priv, + CONFIG_LPC2378_I2C1_FREQUENCY); } else #endif #ifdef CONFIG_LPC2378_I2C2 if (port == 2) { - priv = (FAR struct lpc23xx_i2cdev_s *)&i2cdevices[2]; + priv = &g_i2c2dev; priv->base = I2C2_BASE_ADDR; priv->irqid = I2C2_IRQ; + /* Enable clocking */ + regval = getreg32(LPC23XX_SCB_BASE + SCB_PCONP_OFFSET); regval |= PCI2C2; putreg32(regval, LPC23XX_SCB_BASE + SCB_PCONP_OFFSET); @@ -542,37 +650,39 @@ struct i2c_master_s *up_i2cinitialize(int port) regval |= I2C2_PCLKSEL; putreg32(regval, LPC23XX_SCB_BASE + SCB_PCLKSEL1_OFFSET); + /* Pin configuration */ + 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); + /* Set default frequency */ + + lpc2378_i2c_setfrequency((struct i2c_master_s *)priv, + CONFIG_LPC2378_I2C2_FREQUENCY); } else #endif { - irqrestore(flags); return NULL; } + irqrestore(flags); + putreg32(I2C_CONSET_I2EN, priv->base + I2C_CONSET_OFFSET); - sem_init (&priv->mutex, 0, 1); - sem_init (&priv->wait, 0, 0); + 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); + irq_attach(priv->irqid, lpc2378_i2c_interrupt); /* Enable Interrupt Handler */ @@ -580,9 +690,7 @@ struct i2c_master_s *up_i2cinitialize(int port) /* Install our operations */ - priv->dev.ops = &lpc23xx_i2c_ops; - - irqrestore(flags); + priv->dev.ops = &lpc2378_i2c_ops; return &priv->dev; } @@ -596,12 +704,45 @@ struct i2c_master_s *up_i2cinitialize(int port) int up_i2cuninitialize(FAR struct i2c_master_s * dev) { - struct lpc23xx_i2cdev_s *priv = (struct lpc23xx_i2cdev_s *)dev; + struct lpc2378_i2cdev_s *priv = (struct lpc2378_i2cdev_s *) dev; + + /* Disable I2C */ putreg32(I2C_CONCLRT_I2ENC, priv->base + I2C_CONCLR_OFFSET); + + /* Reset data structures */ + + sem_destroy(&priv->mutex); + sem_destroy(&priv->wait); + + /* Free the watchdog timer */ + + wd_delete(priv->timeout); + priv->timeout = NULL; + + /* Disable interrupts */ + up_disable_irq(priv->irqid); + + /* Detach Interrupt Handler */ + irq_detach(priv->irqid); return OK; } -#endif +/**************************************************************************** + * Name: up_i2creset + * + * Description: + * Reset an I2C bus + * + ****************************************************************************/ + +#ifdef CONFIG_I2C_RESET +int up_i2creset(FAR struct i2c_master_s * dev) +{ + return OK; +} +#endif /* CONFIG_I2C_RESET */ + +#endif /* CONFIG_LPC2378_I2C0 || CONFIG_LPC2378_I2C1 || CONFIG_LPC2378_I2C2 */