From 0693e76be8a637e4b1893980fb2bcc022b22dc1e Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Mon, 1 Feb 2016 16:30:29 -0600 Subject: [PATCH] I2C: Remove the setfrequency method from the interface --- arch/arm/src/efm32/efm32_i2c.c | 100 ++++++++-------- arch/arm/src/lpc11xx/lpc11_i2c.c | 125 ++++++++++---------- arch/arm/src/lpc17xx/lpc17_i2c.c | 107 +++++++++-------- arch/arm/src/lpc2378/lpc23xx_i2c.c | 107 +++++++++-------- arch/arm/src/lpc31xx/lpc31_i2c.c | 90 ++++++++------- arch/arm/src/lpc43xx/lpc43_i2c.c | 111 ++++++++++-------- arch/arm/src/sam34/sam_twi.c | 135 +++++++++------------- arch/arm/src/sama5/sam_twi.c | 119 +++++++------------ arch/arm/src/samv7/sam_twihs.c | 119 +++++++------------ arch/arm/src/stm32/stm32_i2c.c | 166 ++++++++++++--------------- arch/arm/src/stm32/stm32_i2c_alt.c | 166 ++++++++++++--------------- arch/arm/src/stm32/stm32f30xxx_i2c.c | 150 +++++++++++------------- arch/arm/src/tiva/tiva_i2c.c | 110 +++++++----------- arch/z80/src/ez80/ez80_i2c.c | 47 +++----- arch/z80/src/z8/z8_i2c.c | 45 +++----- 15 files changed, 777 insertions(+), 920 deletions(-) diff --git a/arch/arm/src/efm32/efm32_i2c.c b/arch/arm/src/efm32/efm32_i2c.c index 8517f90837f..574c788bfbe 100644 --- a/arch/arm/src/efm32/efm32_i2c.c +++ b/arch/arm/src/efm32/efm32_i2c.c @@ -258,6 +258,7 @@ struct efm32_i2c_priv_s uint8_t *ptr; /* Current message buffer */ int dcnt; /* Current message length */ uint32_t flags; /* Current message flags */ + uint32_t frequency; /* Current I2C frequency */ /* I2C trace support */ @@ -275,11 +276,8 @@ struct efm32_i2c_priv_s struct efm32_i2c_inst_s { - const struct i2c_ops_s *ops; /* Standard I2C operations */ - struct efm32_i2c_priv_s *priv; /* Common driver private data structure - */ - - uint32_t frequency; /* Frequency used in this instantiation */ + const struct i2c_ops_s *ops; /* Standard I2C operations */ + struct efm32_i2c_priv_s *priv; /* Common driver private data structure */ }; /**************************************************************************** @@ -325,10 +323,8 @@ static int efm32_i2c1_isr(int irq, void *context); #endif /* !CONFIG_I2C_POLLED */ static void efm32_i2c_reset(FAR struct efm32_i2c_priv_s *priv); -static int efm32_i2c_init(FAR struct efm32_i2c_priv_s *priv, int frequency); +static int efm32_i2c_init(FAR struct efm32_i2c_priv_s *priv); static int efm32_i2c_deinit(FAR struct efm32_i2c_priv_s *priv); -static uint32_t efm32_i2c_setfrequency(FAR struct i2c_master_s *dev, - uint32_t frequency); static int efm32_i2c_process(FAR struct i2c_master_s *dev, FAR struct i2c_msg_s *msgs, int count); static int efm32_i2c_transfer(FAR struct i2c_master_s *dev, @@ -404,8 +400,7 @@ static struct efm32_i2c_priv_s efm32_i2c1_priv = static const struct i2c_ops_s efm32_i2c_ops = { - .setfrequency = efm32_i2c_setfrequency, - .transfer = efm32_i2c_transfer + .transfer = efm32_i2c_transfer }; /**************************************************************************** @@ -830,21 +825,25 @@ static void efm32_i2c_setclock(FAR struct efm32_i2c_priv_s *priv, { uint32_t div; - /* Set the CLHR (clock low to high ratio). */ + /* Has the I2C bus frequency changed? */ - efm32_i2c_modifyreg(priv, EFM32_I2C_CTRL_OFFSET, _I2C_CTRL_CLHR_MASK, + if (priv->frequency != frequency) + { + /* Set the CLHR (clock low to high ratio). */ + + efm32_i2c_modifyreg(priv, EFM32_I2C_CTRL_OFFSET, _I2C_CTRL_CLHR_MASK, #if defined(CONFIG_EFM32_I2C_CLHR_FAST) - _I2C_CTRL_CLHR_FAST /* Ratio is 11:3 */ + _I2C_CTRL_CLHR_FAST /* Ratio is 11:3 */ #elif defined(CONFIG_EFM32_I2C_CLHR_ASYMMETRIC) - _I2C_CTRL_CLHR_ASYMMETRIC /* Ratio is 6:3 */ + _I2C_CTRL_CLHR_ASYMMETRIC /* Ratio is 6:3 */ #else /* CLHR STANDARD */ - _I2C_CTRL_CLHR_STANDARD /* Ratio is 4:4 */ + _I2C_CTRL_CLHR_STANDARD /* Ratio is 4:4 */ #endif - << _I2C_CTRL_CLHR_SHIFT); + << _I2C_CTRL_CLHR_SHIFT); - /* Frequency is given by fSCL = fHFPERCLK/((Nlow + Nhigh)(DIV + 1) + 4), thus - * DIV = ((fHFPERCLK - 4fSCL)/((Nlow + Nhigh)fSCL)) - 1 - */ + /* Frequency is given by fSCL = fHFPERCLK/((Nlow + Nhigh)(DIV + 1) + 4), + * thus DIV = ((fHFPERCLK - 4fSCL)/((Nlow + Nhigh)fSCL)) - 1 + */ #if defined(CONFIG_EFM32_I2C_CLHR_FAST) # define n (11 + 6) /* Ratio is 11:3 */ @@ -854,19 +853,26 @@ static void efm32_i2c_setclock(FAR struct efm32_i2c_priv_s *priv, # define n ( 4 + 4) /* Ratio is 4:4 */ #endif - div = (BOARD_HFPERCLK_FREQUENCY - (4 * frequency)) / (n * frequency); + div = (BOARD_HFPERCLK_FREQUENCY - (4 * frequency)) / (n * frequency); - /* Clock divisor must be at least 1 in slave mode according to reference */ - /* manual (in which case there is normally no need to set bus frequency). */ + /* Clock divisor must be at least 1 in slave mode according to + * reference manual (in which case there is normally no need to set + * bus frequency). + */ - if ((efm32_i2c_getreg(priv, EFM32_I2C_CTRL_OFFSET) & I2C_CTRL_SLAVE) && !div) - { - div = 1; + if ((efm32_i2c_getreg(priv, EFM32_I2C_CTRL_OFFSET) & I2C_CTRL_SLAVE) && !div) + { + div = 1; + } + + DEBUGASSERT(div <= (_I2C_CLKDIV_DIV_MASK >> _I2C_CLKDIV_DIV_SHIFT)); + + efm32_i2c_putreg(priv, EFM32_I2C_CLKDIV_OFFSET, div); + + /* Save the new I2C frequency */ + + priv->frequency = frequency; } - - DEBUGASSERT(div <= (_I2C_CLKDIV_DIV_MASK >> _I2C_CLKDIV_DIV_SHIFT)); - - efm32_i2c_putreg(priv, EFM32_I2C_CLKDIV_OFFSET, div); } /**************************************************************************** @@ -1347,7 +1353,7 @@ static void efm32_i2c_reset(FAR struct efm32_i2c_priv_s *priv) * ****************************************************************************/ -static int efm32_i2c_init(FAR struct efm32_i2c_priv_s *priv, int frequency) +static int efm32_i2c_init(FAR struct efm32_i2c_priv_s *priv) { int regval; @@ -1445,25 +1451,6 @@ static int efm32_i2c_deinit(FAR struct efm32_i2c_priv_s *priv) * Device Driver Operations ****************************************************************************/ -/**************************************************************************** - * Name: efm32_i2c_setfrequency - * - * Description: - * Set the I2C frequency - * - ****************************************************************************/ - -static uint32_t efm32_i2c_setfrequency(FAR struct i2c_master_s *dev, - uint32_t frequency) -{ - efm32_i2c_sem_wait(dev); - - ((struct efm32_i2c_inst_s *)dev)->frequency = frequency; - - efm32_i2c_sem_post(dev); - return frequency; -} - /**************************************************************************** * Name: efm32_i2c_process * @@ -1504,9 +1491,13 @@ static int efm32_i2c_process(FAR struct i2c_master_s *dev, efm32_i2c_tracereset(priv); - /* Set I2C clock frequency (on change it toggles I2C_CR1_PE !) */ + /* Set I2C clock frequency (on change it toggles I2C_CR1_PE !). + * REVISIT: Note that the frequency is set only on the first message. + * This could be extended to support different transfer frequencies for + * each message segment. + */ - efm32_i2c_setclock(priv, inst->frequency); + efm32_i2c_setclock(priv, msgs->frequency); /* Prepare for a transfer */ @@ -1677,9 +1668,8 @@ FAR struct i2c_master_s *up_i2cinitialize(int port) /* Initialize instance */ - inst->ops = &efm32_i2c_ops; + inst->ops = &efm32_i2c_ops; inst->priv = priv; - inst->frequency = 100000; /* Initialize private data for the first time, increment reference count, * power-up hardware and configure GPIOs. @@ -1690,7 +1680,7 @@ FAR struct i2c_master_s *up_i2cinitialize(int port) if ((volatile int)priv->refs++ == 0) { efm32_i2c_sem_init((struct i2c_master_s *)inst); - efm32_i2c_init(priv, inst->frequency); + efm32_i2c_init(priv); } irqrestore(irqs); @@ -1847,7 +1837,7 @@ int up_i2creset(FAR struct i2c_master_s *dev) /* Re-init the port */ - efm32_i2c_init(priv, ((struct efm32_i2c_inst_s *)dev)->frequency); + efm32_i2c_init(priv); ret = OK; out: diff --git a/arch/arm/src/lpc11xx/lpc11_i2c.c b/arch/arm/src/lpc11xx/lpc11_i2c.c index 0d478ac8d39..81b6c63494a 100644 --- a/arch/arm/src/lpc11xx/lpc11_i2c.c +++ b/arch/arm/src/lpc11xx/lpc11_i2c.c @@ -105,38 +105,39 @@ struct lpc11_i2cdev_s { - struct i2c_master_s dev; /* Generic I2C device */ - unsigned int base; /* Base address of registers */ - uint16_t irqid; /* IRQ for this device */ + struct i2c_master_s dev; /* Generic I2C device */ + 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 */ + 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 */ + uint32_t frequency; /* Current I2C frequency */ - struct i2c_msg_s *msgs; /* Remaining transfers - first one is in progress */ - unsigned int nmsg; /* Number of transfer remaining */ + 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 */ + 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 lpc11_i2c_start(struct lpc11_i2cdev_s *priv); -static void lpc11_i2c_stop(struct lpc11_i2cdev_s *priv); -static int lpc11_i2c_interrupt(int irq, FAR void *context); -static void lpc11_i2c_timeout(int argc, uint32_t arg, ...); +static int lpc11_i2c_start(struct lpc11_i2cdev_s *priv); +static void lpc11_i2c_stop(struct lpc11_i2cdev_s *priv); +static int lpc11_i2c_interrupt(int irq, FAR void *context); +static void lpc11_i2c_timeout(int argc, uint32_t arg, ...); +static void lpc11_i2c_setfrequency(struct lpc11_i2cdev_s *priv, + uint32_t frequency); /* I2C device operations */ -static uint32_t lpc11_i2c_setfrequency(FAR struct i2c_master_s *dev, - uint32_t frequency); -static int lpc11_i2c_transfer(FAR struct i2c_master_s *dev, - FAR struct i2c_msg_s *msgs, int count); -static void lpc11_stopnext(struct lpc11_i2cdev_s *priv); +static int lpc11_i2c_transfer(FAR struct i2c_master_s *dev, + FAR struct i2c_msg_s *msgs, int count); +static void lpc11_stopnext(struct lpc11_i2cdev_s *priv); /**************************************************************************** * Private Data @@ -154,45 +155,43 @@ static struct lpc11_i2cdev_s g_i2c2dev; struct i2c_ops_s lpc11_i2c_ops = { - .setfrequency = lpc11_i2c_setfrequency, - .transfer = lpc11_i2c_transfer + .transfer = lpc11_i2c_transfer }; /**************************************************************************** * Name: lpc11_i2c_setfrequency * * Description: - * Set the frequence for the next transfer + * Set the frequency for the next transfer * ****************************************************************************/ -static uint32_t lpc11_i2c_setfrequency(FAR struct i2c_master_s *dev, +static void lpc11_i2c_setfrequency(struct lpc11_i2cdev_s *priv, uint32_t frequency) { - struct lpc11_i2cdev_s *priv = (struct lpc11_i2cdev_s *) dev; - - if (frequency > 100000) + if (frequency != priv->frequency) { - /* Asymetric per 400Khz I2C spec */ + if (frequency > 100000) + { + /* Asymetric per 400Khz I2C spec */ - putreg32(LPC11_MCLK / (83 + 47) * 47 / frequency, - priv->base + LPC11_I2C_SCLH_OFFSET); - putreg32(LPC11_MCLK / (83 + 47) * 83 / frequency, - priv->base + LPC11_I2C_SCLL_OFFSET); + putreg32(LPC11_MCLK / (83 + 47) * 47 / frequency, + priv->base + LPC11_I2C_SCLH_OFFSET); + putreg32(LPC11_MCLK / (83 + 47) * 83 / frequency, + priv->base + LPC11_I2C_SCLL_OFFSET); + } + else + { + /* 50/50 mark space ratio */ + + putreg32(LPC11_MCLK / 100 * 50 / frequency, + priv->base + LPC11_I2C_SCLH_OFFSET); + putreg32(LPC11_MCLK / 100 * 50 / frequency, + priv->base + LPC11_I2C_SCLL_OFFSET); + } + + priv->frequency = frequency; } - else - { - /* 50/50 mark space ratio */ - - putreg32(LPC11_MCLK / 100 * 50 / frequency, - priv->base + LPC11_I2C_SCLH_OFFSET); - putreg32(LPC11_MCLK / 100 * 50 / frequency, - priv->base + LPC11_I2C_SCLL_OFFSET); - } - - /* FIXME: This function should return the actual selected frequency */ - - return frequency; } /**************************************************************************** @@ -207,8 +206,6 @@ static int lpc11_i2c_start(struct lpc11_i2cdev_s *priv) { int ret = -1; - sem_wait(&priv->mutex); - putreg32(I2C_CONCLR_STAC | I2C_CONCLR_SIC, priv->base + LPC11_I2C_CONCLR_OFFSET); putreg32(I2C_CONSET_STA, priv->base + LPC11_I2C_CONSET_OFFSET); @@ -218,11 +215,7 @@ static int lpc11_i2c_start(struct lpc11_i2cdev_s *priv) wd_cancel(priv->timeout); - ret = priv->nmsg; - - sem_post(&priv->mutex); - - return ret; + return priv->nmsg; } /**************************************************************************** @@ -276,15 +269,32 @@ static int lpc11_i2c_transfer(FAR struct i2c_master_s *dev, struct lpc11_i2cdev_s *priv = (struct lpc11_i2cdev_s *)dev; int ret; - DEBUGASSERT(dev != NULL); + DEBUGASSERT(dev != NULL && msgs != NULL && count > 0); + + /* Get exclusive access to the I2C bus */ + + sem_wait(&priv->mutex); + + /* Set up for the transfer */ priv->wrcnt = 0; priv->rdcnt = 0; priv->msgs = msgs; priv->nmsg = count; + /* Configure the I2C frequency. + * REVISIT: Note that the frequency is set only on the first message. + * This could be extended to support different transfer frequencies for + * each message segment. + */ + + lpc11_i2c_setfrequency(priv, msgs->frequency); + + /* Perform the transfer */ + ret = lpc11_i2c_start(priv); + sem_post(&priv->mutex); return ret; } @@ -479,8 +489,7 @@ struct i2c_master_s *up_i2cinitialize(int port) /* Set default frequency */ - lpc11_i2c_setfrequency((struct i2c_master_s *)priv, - CONFIG_LPC11_I2C0_FREQUENCY); + lpc11_i2c_setfrequency(priv, CONFIG_LPC11_I2C0_FREQUENCY); } else #endif @@ -509,8 +518,7 @@ struct i2c_master_s *up_i2cinitialize(int port) /* Set default frequency */ - lpc11_i2c_setfrequency((struct i2c_master_s *)priv, - CONFIG_LPC11_I2C1_FREQUENCY); + lpc11_i2c_setfrequency(priv, CONFIG_LPC11_I2C1_FREQUENCY); } else #endif @@ -539,8 +547,7 @@ struct i2c_master_s *up_i2cinitialize(int port) /* Set default frequency */ - lpc11_i2c_setfrequency((struct i2c_master_s *)priv, - CONFIG_LPC11_I2C2_FREQUENCY); + lpc11_i2c_setfrequency(priv, CONFIG_LPC11_I2C2_FREQUENCY); } else #endif diff --git a/arch/arm/src/lpc17xx/lpc17_i2c.c b/arch/arm/src/lpc17xx/lpc17_i2c.c index 3464c5a0424..2eb41875971 100644 --- a/arch/arm/src/lpc17xx/lpc17_i2c.c +++ b/arch/arm/src/lpc17xx/lpc17_i2c.c @@ -112,7 +112,8 @@ struct lpc17_i2cdev_s 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 */ + WDOG_ID timeout; /* Watchdog to timeout when bus hung */ + uint32_t frequency; /* Current I2C frequency */ struct i2c_msg_s *msgs; /* remaining transfers - first one is in progress */ unsigned int nmsg; /* number of transfer remaining */ @@ -125,18 +126,18 @@ struct lpc17_i2cdev_s * Private Function Prototypes ****************************************************************************/ -static int lpc17_i2c_start(struct lpc17_i2cdev_s *priv); -static void lpc17_i2c_stop(struct lpc17_i2cdev_s *priv); -static int lpc17_i2c_interrupt(int irq, FAR void *context); -static void lpc17_i2c_timeout(int argc, uint32_t arg, ...); +static int lpc17_i2c_start(struct lpc17_i2cdev_s *priv); +static void lpc17_i2c_stop(struct lpc17_i2cdev_s *priv); +static int lpc17_i2c_interrupt(int irq, FAR void *context); +static void lpc17_i2c_timeout(int argc, uint32_t arg, ...); +static void lpc17_i2c_setfrequency(struct lpc17_i2cdev_s *priv, + uint32_t frequency); /* I2C device operations */ -static uint32_t lpc17_i2c_setfrequency(FAR struct i2c_master_s *dev, - uint32_t frequency); -static int lpc17_i2c_transfer(FAR struct i2c_master_s *dev, - FAR struct i2c_msg_s *msgs, int count); -static void lpc17_stopnext(struct lpc17_i2cdev_s *priv); +static int lpc17_i2c_transfer(FAR struct i2c_master_s *dev, + FAR struct i2c_msg_s *msgs, int count); +static void lpc17_stopnext(struct lpc17_i2cdev_s *priv); /**************************************************************************** * Private Data @@ -154,45 +155,43 @@ static struct lpc17_i2cdev_s g_i2c2dev; struct i2c_ops_s lpc17_i2c_ops = { - .setfrequency = lpc17_i2c_setfrequency, - .transfer = lpc17_i2c_transfer + .transfer = lpc17_i2c_transfer }; /**************************************************************************** * Name: lpc17_i2c_setfrequency * * Description: - * Set the frequence for the next transfer + * Set the frequency for the next transfer * ****************************************************************************/ -static uint32_t lpc17_i2c_setfrequency(FAR struct i2c_master_s *dev, - uint32_t frequency) +static void lpc17_i2c_setfrequency(struct lpc17_i2cdev_s *priv, + uint32_t frequency); { - struct lpc17_i2cdev_s *priv = (struct lpc17_i2cdev_s *) dev; - - if (frequency > 100000) + if (frequency != priv->frequency) { - /* Asymetric per 400Khz I2C spec */ + 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); + 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); + } + + priv->frequency = frequency; } - 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; } /**************************************************************************** @@ -207,8 +206,6 @@ static int lpc17_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); @@ -218,11 +215,7 @@ static int lpc17_i2c_start(struct lpc17_i2cdev_s *priv) wd_cancel(priv->timeout); - ret = priv->nmsg; - - sem_post(&priv->mutex); - - return ret; + return priv->nmsg; } /**************************************************************************** @@ -276,15 +269,32 @@ static int lpc17_i2c_transfer(FAR struct i2c_master_s *dev, struct lpc17_i2cdev_s *priv = (struct lpc17_i2cdev_s *)dev; int ret; - DEBUGASSERT(dev != NULL); + DEBUGASSERT(dev != NULL && msgs != NULL && count > 0); + + /* Get exclusive access to the I2C bus */ + + sem_wait(&priv->mutex); + + /* Set up for the transfer */ priv->wrcnt = 0; priv->rdcnt = 0; priv->msgs = msgs; priv->nmsg = count; + /* Configure the I2C frequency. + * REVISIT: Note that the frequency is set only on the first message. + * This could be extended to support different transfer frequencies for + * each message segment. + */ + + lpc17_i2c_setfrequency(priv, msgs->frequency); + + /* Perform the transfer */ + ret = lpc17_i2c_start(priv); + sem_post(&priv->mutex); return ret; } @@ -484,8 +494,7 @@ struct i2c_master_s *up_i2cinitialize(int port) /* Set default frequency */ - lpc17_i2c_setfrequency((struct i2c_master_s *)priv, - CONFIG_LPC17_I2C0_FREQUENCY); + lpc17_i2c_setfrequency(priv, CONFIG_LPC17_I2C0_FREQUENCY); } else #endif @@ -514,8 +523,7 @@ struct i2c_master_s *up_i2cinitialize(int port) /* Set default frequency */ - lpc17_i2c_setfrequency((struct i2c_master_s *)priv, - CONFIG_LPC17_I2C1_FREQUENCY); + lpc17_i2c_setfrequency(priv, CONFIG_LPC17_I2C1_FREQUENCY); } else #endif @@ -544,8 +552,7 @@ struct i2c_master_s *up_i2cinitialize(int port) /* Set default frequency */ - lpc17_i2c_setfrequency((struct i2c_master_s *)priv, - CONFIG_LPC17_I2C2_FREQUENCY); + lpc17_i2c_setfrequency(priv, CONFIG_LPC17_I2C2_FREQUENCY); } else #endif diff --git a/arch/arm/src/lpc2378/lpc23xx_i2c.c b/arch/arm/src/lpc2378/lpc23xx_i2c.c index 1c5c9b74588..dca3dac2fa8 100644 --- a/arch/arm/src/lpc2378/lpc23xx_i2c.c +++ b/arch/arm/src/lpc2378/lpc23xx_i2c.c @@ -117,7 +117,8 @@ struct lpc2378_i2cdev_s 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 */ + WDOG_ID timeout; /* Watchdog to timeout when bus hung */ + uint32_t frequency; /* Current I2C frequency */ struct i2c_msg_s *msgs; /* remaining transfers - first one is in progress */ unsigned int nmsg; /* number of transfer remaining */ @@ -130,18 +131,18 @@ struct lpc2378_i2cdev_s * 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, ...); +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, ...); +static void lpc2378_i2c_setfrequency(struct lpc2378_i2cdev_s *priv, + uint32_t frequency); /* I2C device operations */ -static uint32_t lpc2378_i2c_setfrequency(FAR struct i2c_master_s *dev, - uint32_t frequency); -static int lpc2378_i2c_transfer(FAR struct i2c_master_s *dev, - FAR struct i2c_msg_s *msgs, int count); -static void lpc2378_stopnext(struct lpc2378_i2cdev_s *priv); +static int lpc2378_i2c_transfer(FAR struct i2c_master_s *dev, + FAR struct i2c_msg_s *msgs, int count); +static void lpc2378_stopnext(struct lpc2378_i2cdev_s *priv); /**************************************************************************** * Private Data @@ -159,45 +160,43 @@ static struct lpc2378_i2cdev_s g_i2c2dev; struct i2c_ops_s lpc2378_i2c_ops = { - .setfrequency = lpc2378_i2c_setfrequency, - .transfer = lpc2378_i2c_transfer + .transfer = lpc2378_i2c_transfer }; /**************************************************************************** * Name: lpc2378_i2c_setfrequency * * Description: - * Set the frequence for the next transfer + * Set the frequency for the next transfer * ****************************************************************************/ -static uint32_t lpc2378_i2c_setfrequency(FAR struct i2c_master_s *dev, - uint32_t frequency) +static void lpc2378_i2c_setfrequency(struct lpc2378_i2cdev_s *priv, + uint32_t frequency) { - struct lpc2378_i2cdev_s *priv = (struct lpc2378_i2cdev_s *) dev; - - if (frequency > 100000) + if (frequency != priv->frequency) { - /* Asymetric per 400Khz I2C spec */ + 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); + 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); + } + + priv->frequency = frequency; } - 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; } /**************************************************************************** @@ -212,8 +211,6 @@ static int lpc2378_i2c_start(struct lpc2378_i2cdev_s *priv) { int ret = -1; - sem_wait(&priv->mutex); - putreg32(I2C_CONCLR_STAC | I2C_CONCLR_SIC, priv->base + I2C_CONCLR_OFFSET); putreg32(I2C_CONSET_STA, priv->base + I2C_CONSET_OFFSET); @@ -223,11 +220,7 @@ static int lpc2378_i2c_start(struct lpc2378_i2cdev_s *priv) wd_cancel(priv->timeout); - ret = priv->nmsg; - - sem_post(&priv->mutex); - - return ret; + return priv->nmsg; } /**************************************************************************** @@ -281,15 +274,32 @@ static int lpc2378_i2c_transfer(FAR struct i2c_master_s *dev, struct lpc2378_i2cdev_s *priv = (struct lpc2378_i2cdev_s *)dev; int ret; - DEBUGASSERT(dev != NULL); + DEBUGASSERT(dev != NULL && msgs != NULL && count > 0); + + /* Get exclusive access to the I2C bus */ + + sem_wait(&priv->mutex); + + /* Set up for the transfer */ priv->wrcnt = 0; priv->rdcnt = 0; priv->msgs = msgs; priv->nmsg = count; + /* Configure the I2C frequency. + * REVISIT: Note that the frequency is set only on the first message. + * This could be extended to support different transfer frequencies for + * each message segment. + */ + + lpc23_i2c_setfrequency(priv, msgs->frequency); + + /* Perform the transfer */ + ret = lpc2378_i2c_start(priv); + sem_post(&priv->mutex); return ret; } @@ -491,8 +501,7 @@ struct i2c_master_s *up_i2cinitialize(int port) /* Set default frequency */ - lpc2378_i2c_setfrequency((struct i2c_master_s *)priv, - CONFIG_LPC2378_I2C0_FREQUENCY); + lpc2378_i2c_setfrequency(priv, CONFIG_LPC2378_I2C0_FREQUENCY); } else #endif @@ -523,8 +532,7 @@ struct i2c_master_s *up_i2cinitialize(int port) /* Set default frequency */ - lpc2378_i2c_setfrequency((struct i2c_master_s *)priv, - CONFIG_LPC2378_I2C1_FREQUENCY); + lpc2378_i2c_setfrequency(priv, CONFIG_LPC2378_I2C1_FREQUENCY); } else #endif @@ -555,8 +563,7 @@ struct i2c_master_s *up_i2cinitialize(int port) /* Set default frequency */ - lpc2378_i2c_setfrequency((struct i2c_master_s *)priv, - CONFIG_LPC2378_I2C2_FREQUENCY); + lpc2378_i2c_setfrequency(priv, CONFIG_LPC2378_I2C2_FREQUENCY); } else #endif diff --git a/arch/arm/src/lpc31xx/lpc31_i2c.c b/arch/arm/src/lpc31xx/lpc31_i2c.c index 551a7fea231..4e85610c35a 100644 --- a/arch/arm/src/lpc31xx/lpc31_i2c.c +++ b/arch/arm/src/lpc31xx/lpc31_i2c.c @@ -86,10 +86,10 @@ struct lpc31_i2cdev_s 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 */ + WDOG_ID timeout; /* Watchdog to timeout when bus hung */ + uint32_t frequency; /* Current I2C frequency */ struct i2c_msg_s *msgs; /* remaining transfers - first one is in progress */ unsigned int nmsg; /* number of transfer remaining */ @@ -108,31 +108,24 @@ struct lpc31_i2cdev_s static struct lpc31_i2cdev_s i2cdevices[2]; /**************************************************************************** - * Private Functions + * Private Function Prototypes ****************************************************************************/ static int i2c_interrupt(int irq, FAR void *context); static void i2c_progress(struct lpc31_i2cdev_s *priv); static void i2c_timeout(int argc, uint32_t arg, ...); static void i2c_reset(struct lpc31_i2cdev_s *priv); - -/**************************************************************************** - * Public Functions - ****************************************************************************/ +static void i2c_setfrequency(struct lpc31_i2cdev_s *priv, uint32_t frequency); +static int i2c_transfer(FAR struct i2c_master_s *dev, + FAR struct i2c_msg_s *msgs, int count); /**************************************************************************** * I2C device operations ****************************************************************************/ -static uint32_t i2c_setfrequency(FAR struct i2c_master_s *dev, - uint32_t frequency); -static int i2c_transfer(FAR struct i2c_master_s *dev, - FAR struct i2c_msg_s *msgs, int count); - struct i2c_ops_s lpc31_i2c_ops = { - .setfrequency = i2c_setfrequency, - .transfer = i2c_transfer + .transfer = i2c_transfer }; /**************************************************************************** @@ -215,34 +208,37 @@ void up_i2cuninitalize(struct lpc31_i2cdev_s *priv) * Name: lpc31_i2c_setfrequency * * Description: - * Set the frequence for the next transfer + * Set the frequency for the next transfer * ****************************************************************************/ -static uint32_t i2c_setfrequency(FAR struct i2c_master_s *dev, uint32_t frequency) +static void i2c_setfrequency(struct lpc31_i2cdev_s *priv, uint32_t frequency) { - struct lpc31_i2cdev_s *priv = (struct lpc31_i2cdev_s *) dev; - - uint32_t freq = lpc31_clkfreq(priv->clkid, DOMAINID_AHB0APB1); - - if (freq > 100000) + if (frequency != priv->frequency) { - /* asymetric per 400Khz I2C spec */ + uint32_t freq = lpc31_clkfreq(priv->clkid, DOMAINID_AHB0APB1); - putreg32(((47 * freq) / (83 + 47)) / frequency, priv->base + LPC31_I2C_CLKHI_OFFSET); - putreg32(((83 * freq) / (83 + 47)) / frequency, priv->base + LPC31_I2C_CLKLO_OFFSET); + if (freq > 100000) + { + /* asymetric per 400Khz I2C spec */ + + putreg32(((47 * freq) / (83 + 47)) / frequency, + priv->base + LPC31_I2C_CLKHI_OFFSET); + putreg32(((83 * freq) / (83 + 47)) / frequency, + priv->base + LPC31_I2C_CLKLO_OFFSET); + } + else + { + /* 50/50 mark space ratio */ + + putreg32(((50 * freq) / 100) / frequency, + priv->base + LPC31_I2C_CLKLO_OFFSET); + putreg32(((50 * freq) / 100) / frequency, + priv->base + LPC31_I2C_CLKHI_OFFSET); + } + + priv->frequency = frequency; } - else - { - /* 50/50 mark space ratio */ - - putreg32(((50 * freq) / 100) / frequency, priv->base + LPC31_I2C_CLKLO_OFFSET); - putreg32(((50 * freq) / 100) / frequency, priv->base + LPC31_I2C_CLKHI_OFFSET); - } - - /* FIXME: This function should return the actual selected frequency */ - - return frequency; } /**************************************************************************** @@ -259,33 +255,45 @@ static int i2c_transfer(FAR struct i2c_master_s *dev, FAR struct i2c_msg_s *msgs irqstate_t flags; int ret; + /* Get exclusive access to the I2C bus */ + sem_wait(&priv->mutex); flags = irqsave(); + /* Set up for the transfer */ + priv->state = I2C_STATE_START; priv->msgs = msgs; priv->nmsg = count; - i2c_progress(priv); - - /* start a watchdog to timeout the transfer if - * the bus is locked up... + /* Configure the I2C frequency. + * REVISIT: Note that the frequency is set only on the first message. + * This could be extended to support different transfer frequencies for + * each message segment. */ + i2c_setfrequency(priv, msgs->frequency); + + /* Start the transfer */ + + i2c_progress(priv); + + /* Start a watchdog to timeout the transfer if the bus is locked up... */ + wd_start(priv->timeout, I2C_TIMEOUT, i2c_timeout, 1, (uint32_t)priv); + /* Wait for the transfer to complete */ + while (priv->state != I2C_STATE_DONE) { sem_wait(&priv->wait); } wd_cancel(priv->timeout); - ret = count - priv->nmsg; irqrestore(flags); sem_post(&priv->mutex); - return ret; } diff --git a/arch/arm/src/lpc43xx/lpc43_i2c.c b/arch/arm/src/lpc43xx/lpc43_i2c.c index 658f5520528..e5cbf11f6a2 100644 --- a/arch/arm/src/lpc43xx/lpc43_i2c.c +++ b/arch/arm/src/lpc43xx/lpc43_i2c.c @@ -107,6 +107,7 @@ struct lpc43_i2cdev_s 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 */ + uint32_t frequency; /* Current I2C frequency */ struct i2c_msg_s *msgs; /* remaining transfers - first one is in progress */ unsigned int nmsg; /* number of transfer remaining */ @@ -126,61 +127,58 @@ static struct lpc43_i2cdev_s g_i2c1dev; * Private Functions ****************************************************************************/ -static int lpc43_i2c_start(struct lpc43_i2cdev_s *priv); -static void lpc43_i2c_stop(struct lpc43_i2cdev_s *priv); -static int lpc43_i2c_interrupt(int irq, FAR void *context); -static void lpc43_i2c_timeout(int argc, uint32_t arg, ...); +static int lpc43_i2c_start(struct lpc43_i2cdev_s *priv); +static void lpc43_i2c_stop(struct lpc43_i2cdev_s *priv); +static int lpc43_i2c_interrupt(int irq, FAR void *context); +static void lpc43_i2c_timeout(int argc, uint32_t arg, ...); +static void lpc43_i2c_setfrequency(struct lpc43_i2cdev_s *priv, + uint32_t frequency); +static int lpc43_i2c_transfer(FAR struct i2c_master_s *dev, + FAR struct i2c_msg_s *msgs, int count); /**************************************************************************** * I2C device operations ****************************************************************************/ -static uint32_t lpc43_i2c_setfrequency(FAR struct i2c_master_s *dev, - uint32_t frequency); -static int lpc43_i2c_transfer(FAR struct i2c_master_s *dev, - FAR struct i2c_msg_s *msgs, int count); - struct i2c_ops_s lpc43_i2c_ops = { - .setfrequency = lpc43_i2c_setfrequency, - .transfer = lpc43_i2c_transfer + .transfer = lpc43_i2c_transfer }; /**************************************************************************** * Name: lpc43_i2c_setfrequency * * Description: - * Set the frequence for the next transfer + * Set the frequency for the next transfer * ****************************************************************************/ -static uint32_t lpc43_i2c_setfrequency(FAR struct i2c_master_s *dev, - uint32_t frequency) +static void lpc43_i2c_setfrequency(struct lpc43_i2cdev_s *priv, + uint32_t frequency) { - struct lpc43_i2cdev_s *priv = (struct lpc43_i2cdev_s *) dev; - - if (frequency > 100000) + if (frequency != priv->frequency) { - /* asymetric per 400Khz I2C spec */ + if (frequency > 100000) + { + /* asymetric per 400Khz I2C spec */ - putreg32(priv->baseFreq / (83 + 47) * 47 / frequency, priv->base + - LPC43_I2C_SCLH_OFFSET); - putreg32(priv->baseFreq / (83 + 47) * 83 / frequency, priv->base + - LPC43_I2C_SCLL_OFFSET); + putreg32(priv->baseFreq / (83 + 47) * 47 / frequency, + priv->base + LPC43_I2C_SCLH_OFFSET); + putreg32(priv->baseFreq / (83 + 47) * 83 / frequency, + priv->base + LPC43_I2C_SCLL_OFFSET); + } + else + { + /* 50/50 mark space ratio */ + + putreg32(priv->baseFreq / 100 * 50 / frequency, + priv->base + LPC43_I2C_SCLH_OFFSET); + putreg32(priv->baseFreq / 100 * 50 / frequency, + priv->base + LPC43_I2C_SCLL_OFFSET); + } + + priv->frequency = frequency; } - else - { - /* 50/50 mark space ratio */ - - putreg32(priv->baseFreq / 100 * 50 / frequency, priv->base + - LPC43_I2C_SCLH_OFFSET); - putreg32(priv->baseFreq / 100 * 50 / frequency, priv->base + - LPC43_I2C_SCLL_OFFSET); - } - - /* FIXME: This function should return the actual selected frequency */ - - return frequency; } /**************************************************************************** @@ -195,8 +193,6 @@ static int lpc43_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); @@ -205,12 +201,7 @@ static int lpc43_i2c_start(struct lpc43_i2cdev_s *priv) sem_wait(&priv->wait); wd_cancel(priv->timeout); - - ret = priv->nmsg; - - sem_post(&priv->mutex); - - return ret; + return priv->nmsg; } /**************************************************************************** @@ -266,17 +257,42 @@ static int lpc43_i2c_transfer(FAR struct i2c_master_s *dev, DEBUGASSERT(dev != NULL); + /* Get exclusive access to the I2C bus */ + + sem_wait(&priv->mutex); + + /* Set up for the transfer */ + priv->wrcnt = 0; priv->rdcnt = 0; priv->msgs = msgs; priv->nmsg = count; + /* Configure the I2C frequency. + * REVISIT: Note that the frequency is set only on the first message. + * This could be extended to support different transfer frequencies for + * each message segment. + */ + + lpc43_i2c_setfrequency(priv, msgs->frequency); + + /* Perform the transfer */ + ret = lpc43_i2c_start(priv); + sem_post(&priv->mutex); return ret; } -void startStopNextMessage(struct lpc43_i2cdev_s *priv) +/**************************************************************************** + * Name: lpc32_i2c_nextmsg + * + * Description: + * Setup for the next message. + * + ****************************************************************************/ + +void lpc32_i2c_nextmsg(struct lpc43_i2cdev_s *priv) { priv->nmsg--; @@ -362,7 +378,7 @@ static int lpc43_i2c_interrupt(int irq, FAR void *context) } else { - startStopNextMessage(priv); + lpc32_i2c_nextmsg(priv); } break; @@ -392,7 +408,7 @@ static int lpc43_i2c_interrupt(int irq, FAR void *context) case 0x58: /* Data byte has been received; NACK has been returned. */ msg->buffer[priv->rdcnt] = getreg32(priv->base + LPC43_I2C_BUFR_OFFSET); - startStopNextMessage(priv); + lpc32_i2c_nextmsg(priv); break; default: @@ -459,8 +475,7 @@ struct i2c_master_s *up_i2cinitialize(int port) regval |= CCU_CLK_CFG_RUN; putreg32(regval, LPC43_CCU1_APB1_I2C0_CFG); - lpc43_i2c_setfrequency((struct i2c_master_s *)priv, - I2C0_DEFAULT_FREQUENCY); + lpc43_i2c_setfrequency(priv, I2C0_DEFAULT_FREQUENCY); /* No pin configuration needed */ } diff --git a/arch/arm/src/sam34/sam_twi.c b/arch/arm/src/sam34/sam_twi.c index b04da8159b3..e0591fa295d 100644 --- a/arch/arm/src/sam34/sam_twi.c +++ b/arch/arm/src/sam34/sam_twi.c @@ -119,8 +119,8 @@ struct twi_dev_s struct i2c_master_s dev; /* Generic I2C device */ struct i2c_msg_s *msg; /* Message list */ uintptr_t base; /* Base address of registers */ - uint32_t frequency; /* TWI input clock frequency */ - uint32_t deffreq; /* Selected TWI frequency */ + uint32_t clkin; /* TWI input clock frequency */ + uint32_t i2cfreq; /* Selected TWI frequency */ uint16_t irq; /* IRQ number for this device */ uint8_t msgc; /* Number of message in the message list */ uint8_t twi; /* TWI peripheral number (for debug output) */ @@ -187,15 +187,12 @@ static void twi_startmessage(struct twi_dev_s *priv, struct i2c_msg_s *msg); /* I2C device operations */ -static uint32_t twi_setfrequency(FAR struct i2c_master_s *dev, - uint32_t frequency); static int twi_transfer(FAR struct i2c_master_s *dev, FAR struct i2c_msg_s *msgs, int count); /* Initialization */ -static uint32_t twi_hw_setfrequency(struct twi_dev_s *priv, - uint32_t frequency); +static void twi_setfrequency(struct twi_dev_s *priv, uint32_t frequency); static void twi_hw_initialize(struct twi_dev_s *priv, unsigned int pid, uint32_t frequency); @@ -213,8 +210,7 @@ static struct twi_dev_s g_twi1; struct i2c_ops_s g_twiops = { - .setfrequency = twi_setfrequency, - .transfer = twi_transfer + .transfer = twi_transfer }; /**************************************************************************** @@ -689,32 +685,6 @@ static void twi_startmessage(struct twi_dev_s *priv, struct i2c_msg_s *msg) * I2C device operations ****************************************************************************/ -/**************************************************************************** - * Name: twi_setfrequency - * - * Description: - * Set the frequency for the next transfer - * - ****************************************************************************/ - -static uint32_t twi_setfrequency(FAR struct i2c_master_s *dev, uint32_t frequency) -{ - struct twi_dev_s *priv = (struct twi_dev_s *)dev; - uint32_t actual; - - DEBUGASSERT(dev); - - /* Get exclusive access to the device */ - - twi_takesem(&priv->exclsem); - - /* And setup the clock frequency */ - - actual = twi_hw_setfrequency(priv, frequency); - twi_givesem(&priv->exclsem); - return actual; -} - /**************************************************************************** * Name: twi_transfer * @@ -738,11 +708,19 @@ static int twi_transfer(FAR struct i2c_master_s *dev, twi_takesem(&priv->exclsem); - /* Initiate the message transfer */ + /* Setup the message transfer */ priv->msg = msgs; priv->msgc = count; + /* Configure the I2C frequency. + * REVISIT: Note that the frequency is set only on the first message. + * This could be extended to support different transfer frequencies for + * each message segment. + */ + + twi_setfrequency(priv, msgs->frequency); + /* Initiate the transfer. The rest will be handled from interrupt * logic. Interrupts must be disabled to prevent re-entrance from the * interrupt level. @@ -771,59 +749,54 @@ static int twi_transfer(FAR struct i2c_master_s *dev, ****************************************************************************/ /**************************************************************************** - * Name: twi_hw_setfrequency + * Name: twi_setfrequency * * Description: * Set the frequency for the next transfer * ****************************************************************************/ -static uint32_t twi_hw_setfrequency(struct twi_dev_s *priv, uint32_t frequency) +static void twi_setfrequency(struct twi_dev_s *priv, uint32_t frequency) { unsigned int ckdiv; unsigned int cldiv; - uint32_t actual; uint32_t regval; - /* Configure TWI output clocking, trying each value of CKDIV {0..7} */ - - for (ckdiv = 0; ckdiv < 8; ckdiv++) + if (frequency != priv->i2cfreq) { - /* Calulate the CLDIV value using the current CKDIV guess */ + /* Configure TWI output clocking, trying each value of CKDIV {0..7} */ - cldiv = ((priv->frequency / (frequency << 1)) - 4) / (1 << ckdiv); - - /* Is CLDIV in range? */ - - if (cldiv <= 255) + for (ckdiv = 0; ckdiv < 8; ckdiv++) { - /* Yes, break out and use it */ + /* Calulate the CLDIV value using the current CKDIV guess */ - break; + cldiv = ((priv->clkin / (frequency << 1)) - 4) / (1 << ckdiv); + + /* Is CLDIV in range? */ + + if (cldiv <= 255) + { + /* Yes, break out and use it */ + + break; + } } + + /* Then setup the TWI Clock Waveform Generator Register, using the same + * value for CLDIV and CHDIV (for 1:1 duty). + */ + + twi_putrel(priv, SAM_TWI_CWGR_OFFSET, 0); + + regval = ((uint32_t)ckdiv << TWI_CWGR_CKDIV_SHIFT) | + ((uint32_t)cldiv << TWI_CWGR_CHDIV_SHIFT) | + ((uint32_t)cldiv << TWI_CWGR_CLDIV_SHIFT); + twi_putrel(priv, SAM_TWI_CWGR_OFFSET, regval); + + /* Remember the selected frequency for error recovery */ + + priv->i2cfreq = frequency; } - - /* Then setup the TWI Clock Waveform Generator Register, using the same - * value for CLDIV and CHDIV (for 1:1 duty). - */ - - twi_putrel(priv, SAM_TWI_CWGR_OFFSET, 0); - - regval = ((uint32_t)ckdiv << TWI_CWGR_CKDIV_SHIFT) | - ((uint32_t)cldiv << TWI_CWGR_CHDIV_SHIFT) | - ((uint32_t)cldiv << TWI_CWGR_CLDIV_SHIFT); - twi_putrel(priv, SAM_TWI_CWGR_OFFSET, regval); - - /* Return the actual frequency */ - - actual = (priv->frequency / 2) / (((1 << ckdiv) * cldiv) + 2); - i2cvdbg("TWI%d frequency: %d ckdiv: %d cldiv: %d actual: %d\n", - priv->twi, frequency, ckdiv, cldiv, actual); - - /* Remember the selected frequency for error recovery */ - - priv->deffreq = frequency; - return actual; } /**************************************************************************** @@ -864,7 +837,7 @@ static void twi_hw_initialize(struct twi_dev_s *priv, unsigned int pid, /* Set base frequency */ - priv->frequency = BOARD_MCK_FREQUENCY; + priv->clkin = BOARD_MCK_FREQUENCY; #if 0 /* Determine the maximum valid frequency setting */ @@ -874,23 +847,23 @@ static void twi_hw_initialize(struct twi_dev_s *priv, unsigned int pid, if (mck <= TWI_MAX_FREQUENCY) { - priv->frequency = mck; - regval = PMC_PCR_DIV1; + priv->clkin = mck; + regval = PMC_PCR_DIV1; } else if ((mck >> 1) <= TWI_MAX_FREQUENCY) { - priv->frequency = (mck >> 1); - regval = PMC_PCR_DIV2; + priv->clkin = (mck >> 1); + regval = PMC_PCR_DIV2; } else if ((mck >> 2) <= TWI_MAX_FREQUENCY) { - priv->frequency = (mck >> 2); - regval = PMC_PCR_DIV4; + priv->clkin = (mck >> 2); + regval = PMC_PCR_DIV4; } else /* if ((mck >> 3) <= TWI_MAX_FREQUENCY) */ { - priv->frequency = (mck >> 3); - regval = PMC_PCR_DIV8; + priv->clkin = (mck >> 3); + regval = PMC_PCR_DIV8; } /* Set the TWI peripheral input clock to the maximum, valid frequency */ @@ -901,7 +874,7 @@ static void twi_hw_initialize(struct twi_dev_s *priv, unsigned int pid, /* Set the initial TWI data transfer frequency */ - (void)twi_hw_setfrequency(priv, frequency); + twi_setfrequency(priv, frequency); } /**************************************************************************** diff --git a/arch/arm/src/sama5/sam_twi.c b/arch/arm/src/sama5/sam_twi.c index 802ff9110ff..b8f0e4987df 100644 --- a/arch/arm/src/sama5/sam_twi.c +++ b/arch/arm/src/sama5/sam_twi.c @@ -162,9 +162,7 @@ struct twi_dev_s const struct twi_attr_s *attr; /* Invariant attributes of TWI device */ struct i2c_msg_s *msg; /* Message list */ uint32_t twiclk; /* TWI input clock frequency */ -#ifdef CONFIG_I2C_RESET uint32_t frequency; /* TWI transfer clock frequency */ -#endif uint8_t msgc; /* Number of message in the message list */ sem_t exclsem; /* Only one thread can access at a time */ @@ -234,15 +232,12 @@ static void twi_startmessage(struct twi_dev_s *priv, struct i2c_msg_s *msg); /* I2C device operations */ -static uint32_t twi_setfrequency(FAR struct i2c_master_s *dev, - uint32_t frequency); static int twi_transfer(FAR struct i2c_master_s *dev, FAR struct i2c_msg_s *msgs, int count); /* Initialization */ -static uint32_t twi_hw_setfrequency(struct twi_dev_s *priv, - uint32_t frequency); +static uint32_t twi_setfrequency(struct twi_dev_s *priv, uint32_t frequency); static void twi_hw_initialize(struct twi_dev_s *priv, uint32_t frequency); /**************************************************************************** @@ -311,8 +306,7 @@ static struct twi_dev_s g_twi3; struct i2c_ops_s g_twiops = { - .setfrequency = twi_setfrequency, - .transfer = twi_transfer + .transfer = twi_transfer }; /**************************************************************************** @@ -819,32 +813,6 @@ static void twi_startmessage(struct twi_dev_s *priv, struct i2c_msg_s *msg) * I2C device operations ****************************************************************************/ -/**************************************************************************** - * Name: twi_setfrequency - * - * Description: - * Set the frequency for the next transfer - * - ****************************************************************************/ - -static uint32_t twi_setfrequency(FAR struct i2c_master_s *dev, uint32_t frequency) -{ - struct twi_dev_s *priv = (struct twi_dev_s *)dev; - uint32_t actual; - - DEBUGASSERT(dev); - - /* Get exclusive access to the device */ - - twi_takesem(&priv->exclsem); - - /* And setup the clock frequency */ - - actual = twi_hw_setfrequency(priv, frequency); - twi_givesem(&priv->exclsem); - return actual; -} - /**************************************************************************** * Name: twi_transfer * @@ -885,11 +853,19 @@ static int twi_transfer(FAR struct i2c_master_s *dev, twi_takesem(&priv->exclsem); - /* Initiate the message transfer */ + /* Setup the message transfer */ priv->msg = msgs; priv->msgc = count; + /* Configure the I2C frequency. + * REVISIT: Note that the frequency is set only on the first message. + * This could be extended to support different transfer frequencies for + * each message segment. + */ + + twi_setfrequency(priv, msgs->frequency); + /* Initiate the transfer. The rest will be handled from interrupt * logic. Interrupts must be disabled to prevent re-entrance from the * interrupt level. @@ -945,63 +921,54 @@ static void twi_enableclk(struct twi_dev_s *priv) } /**************************************************************************** - * Name: twi_hw_setfrequency + * Name: twi_setfrequency * * Description: * Set the frequency for the next transfer * ****************************************************************************/ -static uint32_t twi_hw_setfrequency(struct twi_dev_s *priv, uint32_t frequency) +static void twi_setfrequency(struct twi_dev_s *priv, uint32_t frequency) { unsigned int ckdiv; unsigned int cldiv; - uint32_t actual; uint32_t regval; - /* Configure TWI output clocking, trying each value of CKDIV {0..7} */ - - for (ckdiv = 0; ckdiv < 8; ckdiv++) + if (frequency != priv->frequency) { - /* Calculate the CLDIV value using the current CKDIV guess */ + /* Configure TWI output clocking, trying each value of CKDIV {0..7} */ - cldiv = ((priv->twiclk / (frequency << 1)) - 4) / (1 << ckdiv); - - /* Is CLDIV in range? */ - - if (cldiv <= 255) + for (ckdiv = 0; ckdiv < 8; ckdiv++) { - /* Yes, break out and use it */ + /* Calculate the CLDIV value using the current CKDIV guess */ - break; + cldiv = ((priv->twiclk / (frequency << 1)) - 4) / (1 << ckdiv); + + /* Is CLDIV in range? */ + + if (cldiv <= 255) + { + /* Yes, break out and use it */ + + break; + } } + + /* Then setup the TWI Clock Waveform Generator Register, using the same + * value for CLDIV and CHDIV (for 1:1 duty). + */ + + twi_putrel(priv, SAM_TWI_CWGR_OFFSET, 0); + + regval = ((uint32_t)ckdiv << TWI_CWGR_CKDIV_SHIFT) | + ((uint32_t)cldiv << TWI_CWGR_CHDIV_SHIFT) | + ((uint32_t)cldiv << TWI_CWGR_CLDIV_SHIFT); + twi_putrel(priv, SAM_TWI_CWGR_OFFSET, regval); + + /* Save the requested frequency */ + + priv->frequency = frequency; } - - /* Then setup the TWI Clock Waveform Generator Register, using the same - * value for CLDIV and CHDIV (for 1:1 duty). - */ - - twi_putrel(priv, SAM_TWI_CWGR_OFFSET, 0); - - regval = ((uint32_t)ckdiv << TWI_CWGR_CKDIV_SHIFT) | - ((uint32_t)cldiv << TWI_CWGR_CHDIV_SHIFT) | - ((uint32_t)cldiv << TWI_CWGR_CLDIV_SHIFT); - twi_putrel(priv, SAM_TWI_CWGR_OFFSET, regval); - - /* Calculate the actual I2C frequency */ - - actual = (priv->twiclk / 2) / (((1 << ckdiv) * cldiv) + 2); - i2cvdbg("TWI%d frequency: %d ckdiv: %d cldiv: %d actual: %d\n", - priv->attr->twi, frequency, ckdiv, cldiv, actual); - - /* Save the requested frequency (for I2C reset) and return the - * actual frequency. - */ - -#ifdef CONFIG_I2C_RESET - priv->frequency = frequency; -#endif - return actual; } /**************************************************************************** @@ -1093,7 +1060,7 @@ static void twi_hw_initialize(struct twi_dev_s *priv, uint32_t frequency) /* Set the initial TWI data transfer frequency */ - twi_hw_setfrequency(priv, frequency); + twi_setfrequency(priv, frequency); /* Enable Interrupts */ diff --git a/arch/arm/src/samv7/sam_twihs.c b/arch/arm/src/samv7/sam_twihs.c index 77b05bca503..2dbddddc3cf 100644 --- a/arch/arm/src/samv7/sam_twihs.c +++ b/arch/arm/src/samv7/sam_twihs.c @@ -159,9 +159,7 @@ struct twi_dev_s const struct twi_attr_s *attr; /* Invariant attributes of TWIHS device */ struct i2c_msg_s *msg; /* Message list */ uint32_t twiclk; /* TWIHS input clock frequency */ -#ifdef CONFIG_I2C_RESET uint32_t frequency; /* TWIHS transfer clock frequency */ -#endif bool initd; /* True :device has been initialized */ uint8_t msgc; /* Number of message in the message list */ @@ -229,15 +227,12 @@ static void twi_startmessage(struct twi_dev_s *priv, struct i2c_msg_s *msg); /* I2C device operations */ -static uint32_t twi_setfrequency(FAR struct i2c_master_s *dev, - uint32_t frequency); static int twi_transfer(FAR struct i2c_master_s *dev, FAR struct i2c_msg_s *msgs, int count); /* Initialization */ -static uint32_t twi_hw_setfrequency(struct twi_dev_s *priv, - uint32_t frequency); +static void twi_setfrequency(struct twi_dev_s *priv, uint32_t frequency); static void twi_hw_initialize(struct twi_dev_s *priv, uint32_t frequency); /**************************************************************************** @@ -291,8 +286,7 @@ static struct twi_dev_s g_twi2; struct i2c_ops_s g_twiops = { - .setfrequency = twi_setfrequency, - .transfer = twi_transfer + .transfer = twi_transfer }; /**************************************************************************** @@ -846,32 +840,6 @@ static void twi_startmessage(struct twi_dev_s *priv, struct i2c_msg_s *msg) * I2C device operations ****************************************************************************/ -/**************************************************************************** - * Name: twi_setfrequency - * - * Description: - * Set the frequency for the next transfer - * - ****************************************************************************/ - -static uint32_t twi_setfrequency(FAR struct i2c_master_s *dev, uint32_t frequency) -{ - struct twi_dev_s *priv = (struct twi_dev_s *)dev; - uint32_t actual; - - DEBUGASSERT(dev); - - /* Get exclusive access to the device */ - - twi_takesem(&priv->exclsem); - - /* And setup the clock frequency */ - - actual = twi_hw_setfrequency(priv, frequency); - twi_givesem(&priv->exclsem); - return actual; -} - /**************************************************************************** * Name: twi_transfer * @@ -912,11 +880,19 @@ static int twi_transfer(FAR struct i2c_master_s *dev, twi_takesem(&priv->exclsem); - /* Initiate the message transfer */ + /* Setup the message transfer */ priv->msg = msgs; priv->msgc = count; + /* Configure the I2C frequency. + * REVISIT: Note that the frequency is set only on the first message. + * This could be extended to support different transfer frequencies for + * each message segment. + */ + + twi_setfrequency(priv, msgs->frequency); + /* Initiate the transfer. The rest will be handled from interrupt * logic. Interrupts must be disabled to prevent re-entrance from the * interrupt level. @@ -972,63 +948,54 @@ static void twi_enableclk(struct twi_dev_s *priv) } /**************************************************************************** - * Name: twi_hw_setfrequency + * Name: twi_setfrequency * * Description: * Set the frequency for the next transfer * ****************************************************************************/ -static uint32_t twi_hw_setfrequency(struct twi_dev_s *priv, uint32_t frequency) +static void twi_setfrequency(struct twi_dev_s *priv, uint32_t frequency) { unsigned int ckdiv; unsigned int cldiv; - uint32_t actual; uint32_t regval; - /* Configure TWIHS output clocking, trying each value of CKDIV {0..7} */ - - for (ckdiv = 0; ckdiv < 8; ckdiv++) + if (frequency != priv->frequency) { - /* Calculate the CLDIV value using the current CKDIV guess */ + /* Configure TWIHS output clocking, trying each value of CKDIV {0..7} */ - cldiv = ((priv->twiclk / (frequency << 1)) - 4) / (1 << ckdiv); - - /* Is CLDIV in range? */ - - if (cldiv <= 255) + for (ckdiv = 0; ckdiv < 8; ckdiv++) { - /* Yes, break out and use it */ + /* Calculate the CLDIV value using the current CKDIV guess */ - break; + cldiv = ((priv->twiclk / (frequency << 1)) - 4) / (1 << ckdiv); + + /* Is CLDIV in range? */ + + if (cldiv <= 255) + { + /* Yes, break out and use it */ + + break; + } } + + /* Then setup the TWIHS Clock Waveform Generator Register, using the same + * value for CLDIV and CHDIV (for 1:1 duty). + */ + + twi_putrel(priv, SAM_TWIHS_CWGR_OFFSET, 0); + + regval = ((uint32_t)ckdiv << TWIHS_CWGR_CKDIV_SHIFT) | + ((uint32_t)cldiv << TWIHS_CWGR_CHDIV_SHIFT) | + ((uint32_t)cldiv << TWIHS_CWGR_CLDIV_SHIFT); + twi_putrel(priv, SAM_TWIHS_CWGR_OFFSET, regval); + + /* Save the requested frequency */ + + priv->frequency = frequency; } - - /* Then setup the TWIHS Clock Waveform Generator Register, using the same - * value for CLDIV and CHDIV (for 1:1 duty). - */ - - twi_putrel(priv, SAM_TWIHS_CWGR_OFFSET, 0); - - regval = ((uint32_t)ckdiv << TWIHS_CWGR_CKDIV_SHIFT) | - ((uint32_t)cldiv << TWIHS_CWGR_CHDIV_SHIFT) | - ((uint32_t)cldiv << TWIHS_CWGR_CLDIV_SHIFT); - twi_putrel(priv, SAM_TWIHS_CWGR_OFFSET, regval); - - /* Calculate the actual I2C frequency */ - - actual = (priv->twiclk / 2) / (((1 << ckdiv) * cldiv) + 2); - i2cvdbg("TWIHS%d frequency: %d ckdiv: %d cldiv: %d actual: %d\n", - priv->attr->twi, frequency, ckdiv, cldiv, actual); - - /* Save the requested frequency (for I2C reset) and return the - * actual frequency. - */ - -#ifdef CONFIG_I2C_RESET - priv->frequency = frequency; -#endif - return actual; } /**************************************************************************** @@ -1120,7 +1087,7 @@ static void twi_hw_initialize(struct twi_dev_s *priv, uint32_t frequency) /* Set the initial TWIHS data transfer frequency */ - twi_hw_setfrequency(priv, frequency); + twi_setfrequency(priv, frequency); /* Enable Interrupts */ diff --git a/arch/arm/src/stm32/stm32_i2c.c b/arch/arm/src/stm32/stm32_i2c.c index 3b2aca1990f..5c25d49926d 100644 --- a/arch/arm/src/stm32/stm32_i2c.c +++ b/arch/arm/src/stm32/stm32_i2c.c @@ -260,6 +260,7 @@ struct stm32_i2c_priv_s uint8_t msgc; /* Message count */ struct i2c_msg_s *msgv; /* Message list */ uint8_t *ptr; /* Current message buffer */ + uint32_t frequency; /* Current I2C frequency */ int dcnt; /* Current message length */ uint16_t flags; /* Current message flags */ @@ -283,8 +284,6 @@ struct stm32_i2c_inst_s { const struct i2c_ops_s *ops; /* Standard I2C operations */ struct stm32_i2c_priv_s *priv; /* Common driver private data structure */ - - uint32_t frequency; /* Frequency used in this instantiation */ }; /************************************************************************************ @@ -346,8 +345,6 @@ static int stm32_i2c3_isr(int irq, void *context); static int stm32_i2c_init(FAR struct stm32_i2c_priv_s *priv); static int stm32_i2c_deinit(FAR struct stm32_i2c_priv_s *priv); -static uint32_t stm32_i2c_setfrequency(FAR struct i2c_master_s *dev, - uint32_t frequency); static int stm32_i2c_process(FAR struct i2c_master_s *dev, FAR struct i2c_msg_s *msgs, int count); static int stm32_i2c_transfer(FAR struct i2c_master_s *dev, FAR struct i2c_msg_s *msgs, @@ -469,8 +466,7 @@ static struct stm32_i2c_priv_s stm32_i2c3_priv = static const struct i2c_ops_s stm32_i2c_ops = { - .setfrequency = stm32_i2c_setfrequency, - .transfer = stm32_i2c_transfer + .transfer = stm32_i2c_transfer }; /************************************************************************************ @@ -949,90 +945,99 @@ static void stm32_i2c_setclock(FAR struct stm32_i2c_priv_s *priv, uint32_t frequ uint16_t freqmhz; uint16_t speed; - /* Disable the selected I2C peripheral to configure TRISE */ + /* Has the I2C bus frequency changed? */ - cr1 = stm32_i2c_getreg(priv, STM32_I2C_CR1_OFFSET); - stm32_i2c_putreg(priv, STM32_I2C_CR1_OFFSET, cr1 & ~I2C_CR1_PE); - - /* Update timing and control registers */ - - freqmhz = (uint16_t)(STM32_PCLK1_FREQUENCY / 1000000); - ccr = 0; - - /* Configure speed in standard mode */ - - if (frequency <= 100000) + if (frequency != priv->frequency) { - /* Standard mode speed calculation */ + /* Disable the selected I2C peripheral to configure TRISE */ - speed = (uint16_t)(STM32_PCLK1_FREQUENCY / (frequency << 1)); + cr1 = stm32_i2c_getreg(priv, STM32_I2C_CR1_OFFSET); + stm32_i2c_putreg(priv, STM32_I2C_CR1_OFFSET, cr1 & ~I2C_CR1_PE); - /* The CCR fault must be >= 4 */ + /* Update timing and control registers */ - if (speed < 4) + freqmhz = (uint16_t)(STM32_PCLK1_FREQUENCY / 1000000); + ccr = 0; + + /* Configure speed in standard mode */ + + if (frequency <= 100000) { - /* Set the minimum allowed value */ + /* Standard mode speed calculation */ - speed = 4; + speed = (uint16_t)(STM32_PCLK1_FREQUENCY / (frequency << 1)); + + /* The CCR fault must be >= 4 */ + + if (speed < 4) + { + /* Set the minimum allowed value */ + + speed = 4; + } + + ccr |= speed; + + /* Set Maximum Rise Time for standard mode */ + + trise = freqmhz + 1; } - ccr |= speed; + /* Configure speed in fast mode */ - /* Set Maximum Rise Time for standard mode */ - - trise = freqmhz + 1; - } - - /* Configure speed in fast mode */ - - else /* (frequency <= 400000) */ - { - /* Fast mode speed calculation with Tlow/Thigh = 16/9 */ + else /* (frequency <= 400000) */ + { + /* Fast mode speed calculation with Tlow/Thigh = 16/9 */ #ifdef CONFIG_STM32_I2C_DUTY16_9 - speed = (uint16_t)(STM32_PCLK1_FREQUENCY / (frequency * 25)); + speed = (uint16_t)(STM32_PCLK1_FREQUENCY / (frequency * 25)); - /* Set DUTY and fast speed bits */ + /* Set DUTY and fast speed bits */ - ccr |= (I2C_CCR_DUTY | I2C_CCR_FS); + ccr |= (I2C_CCR_DUTY | I2C_CCR_FS); #else - /* Fast mode speed calculation with Tlow/Thigh = 2 */ + /* Fast mode speed calculation with Tlow/Thigh = 2 */ - speed = (uint16_t)(STM32_PCLK1_FREQUENCY / (frequency * 3)); + speed = (uint16_t)(STM32_PCLK1_FREQUENCY / (frequency * 3)); - /* Set fast speed bit */ + /* Set fast speed bit */ - ccr |= I2C_CCR_FS; + ccr |= I2C_CCR_FS; #endif - /* Verify that the CCR speed value is nonzero */ + /* Verify that the CCR speed value is nonzero */ - if (speed < 1) - { - /* Set the minimum allowed value */ + if (speed < 1) + { + /* Set the minimum allowed value */ - speed = 1; + speed = 1; + } + + ccr |= speed; + + /* Set Maximum Rise Time for fast mode */ + + trise = (uint16_t)(((freqmhz * 300) / 1000) + 1); } - ccr |= speed; + /* Write the new values of the CCR and TRISE registers */ - /* Set Maximum Rise Time for fast mode */ + stm32_i2c_putreg(priv, STM32_I2C_CCR_OFFSET, ccr); + stm32_i2c_putreg(priv, STM32_I2C_TRISE_OFFSET, trise); - trise = (uint16_t)(((freqmhz * 300) / 1000) + 1); + /* Bit 14 of OAR1 must be configured and kept at 1 */ + + stm32_i2c_putreg(priv, STM32_I2C_OAR1_OFFSET, I2C_OAR1_ONE); + + /* Re-enable the peripheral (or not) */ + + stm32_i2c_putreg(priv, STM32_I2C_CR1_OFFSET, cr1); + + /* Save the new I2C frequency */ + + priv->frequency = frequency; } - - /* Write the new values of the CCR and TRISE registers */ - - stm32_i2c_putreg(priv, STM32_I2C_CCR_OFFSET, ccr); - stm32_i2c_putreg(priv, STM32_I2C_TRISE_OFFSET, trise); - - /* Bit 14 of OAR1 must be configured and kept at 1 */ - - stm32_i2c_putreg(priv, STM32_I2C_OAR1_OFFSET, I2C_OAR1_ONE); - - /* Re-enable the peripheral (or not) */ - - stm32_i2c_putreg(priv, STM32_I2C_CR1_OFFSET, cr1); } /************************************************************************************ @@ -1598,28 +1603,6 @@ static int stm32_i2c_deinit(FAR struct stm32_i2c_priv_s *priv) * Device Driver Operations ************************************************************************************/ -/************************************************************************************ - * Name: stm32_i2c_setfrequency - * - * Description: - * Set the I2C frequency - * - ************************************************************************************/ - -static uint32_t stm32_i2c_setfrequency(FAR struct i2c_master_s *dev, uint32_t frequency) -{ - stm32_i2c_sem_wait(dev); - -#if STM32_PCLK1_FREQUENCY < 4000000 - ((struct stm32_i2c_inst_s *)dev)->frequency = 100000; -#else - ((struct stm32_i2c_inst_s *)dev)->frequency = frequency; -#endif - - stm32_i2c_sem_post(dev); - return ((struct stm32_i2c_inst_s *)dev)->frequency; -} - /************************************************************************************ * Name: stm32_i2c_process * @@ -1684,9 +1667,13 @@ static int stm32_i2c_process(FAR struct i2c_master_s *dev, FAR struct i2c_msg_s stm32_i2c_tracereset(priv); - /* Set I2C clock frequency (on change it toggles I2C_CR1_PE !) */ + /* Set I2C clock frequency (on change it toggles I2C_CR1_PE !) + * REVISIT: Note that the frequency is set only on the first message. + * This could be extended to support different transfer frequencies for + * each message segment. + */ - stm32_i2c_setclock(priv, inst->frequency); + stm32_i2c_setclock(priv, msgs->frequency); /* Trigger start condition, then the process moves into the ISR. I2C * interrupts will be enabled within stm32_i2c_waitdone(). @@ -1895,9 +1882,8 @@ FAR struct i2c_master_s *up_i2cinitialize(int port) /* Initialize instance */ - inst->ops = &stm32_i2c_ops; - inst->priv = priv; - inst->frequency = 100000; + inst->ops = &stm32_i2c_ops; + inst->priv = priv; /* Initialize private data for the first time, increment reference count, * power-up hardware and configure GPIOs. diff --git a/arch/arm/src/stm32/stm32_i2c_alt.c b/arch/arm/src/stm32/stm32_i2c_alt.c index 653631c9dd5..9e4070f8d86 100644 --- a/arch/arm/src/stm32/stm32_i2c_alt.c +++ b/arch/arm/src/stm32/stm32_i2c_alt.c @@ -287,6 +287,7 @@ struct stm32_i2c_priv_s uint8_t msgc; /* Message count */ struct i2c_msg_s *msgv; /* Message list */ uint8_t *ptr; /* Current message buffer */ + uint32_t frequency; /* Current I2C frequency */ int dcnt; /* Current message length */ uint16_t flags; /* Current message flags */ bool check_addr_ACK; /* Flag to signal if on next interrupt address has ACKed */ @@ -312,8 +313,6 @@ struct stm32_i2c_inst_s { const struct i2c_ops_s *ops; /* Standard I2C operations */ struct stm32_i2c_priv_s *priv; /* Common driver private data structure */ - - uint32_t frequency; /* Frequency used in this instantiation */ }; /************************************************************************************ @@ -375,8 +374,6 @@ static int stm32_i2c3_isr(int irq, void *context); static int stm32_i2c_init(FAR struct stm32_i2c_priv_s *priv); static int stm32_i2c_deinit(FAR struct stm32_i2c_priv_s *priv); -static uint32_t stm32_i2c_setfrequency(FAR struct i2c_master_s *dev, - uint32_t frequency); static int stm32_i2c_process(FAR struct i2c_master_s *dev, FAR struct i2c_msg_s *msgs, int count); static int stm32_i2c_transfer(FAR struct i2c_master_s *dev, FAR struct i2c_msg_s *msgs, @@ -477,8 +474,7 @@ static struct stm32_i2c_priv_s stm32_i2c3_priv = static const struct i2c_ops_s stm32_i2c_ops = { - .setfrequency = stm32_i2c_setfrequency, - .transfer = stm32_i2c_transfer + .transfer = stm32_i2c_transfer }; /************************************************************************************ @@ -957,90 +953,99 @@ static void stm32_i2c_setclock(FAR struct stm32_i2c_priv_s *priv, uint32_t frequ uint16_t freqmhz; uint16_t speed; - /* Disable the selected I2C peripheral to configure TRISE */ + /* Has the I2C bus frequency changed? */ - cr1 = stm32_i2c_getreg(priv, STM32_I2C_CR1_OFFSET); - stm32_i2c_putreg(priv, STM32_I2C_CR1_OFFSET, cr1 & ~I2C_CR1_PE); - - /* Update timing and control registers */ - - freqmhz = (uint16_t)(STM32_PCLK1_FREQUENCY / 1000000); - ccr = 0; - - /* Configure speed in standard mode */ - - if (frequency <= 100000) + if (frequency != priv->frequency) { - /* Standard mode speed calculation */ + /* Disable the selected I2C peripheral to configure TRISE */ - speed = (uint16_t)(STM32_PCLK1_FREQUENCY / (frequency << 1)); + cr1 = stm32_i2c_getreg(priv, STM32_I2C_CR1_OFFSET); + stm32_i2c_putreg(priv, STM32_I2C_CR1_OFFSET, cr1 & ~I2C_CR1_PE); - /* The CCR fault must be >= 4 */ + /* Update timing and control registers */ - if (speed < 4) + freqmhz = (uint16_t)(STM32_PCLK1_FREQUENCY / 1000000); + ccr = 0; + + /* Configure speed in standard mode */ + + if (frequency <= 100000) { - /* Set the minimum allowed value */ + /* Standard mode speed calculation */ - speed = 4; + speed = (uint16_t)(STM32_PCLK1_FREQUENCY / (frequency << 1)); + + /* The CCR fault must be >= 4 */ + + if (speed < 4) + { + /* Set the minimum allowed value */ + + speed = 4; + } + + ccr |= speed; + + /* Set Maximum Rise Time for standard mode */ + + trise = freqmhz + 1; } - ccr |= speed; + /* Configure speed in fast mode */ - /* Set Maximum Rise Time for standard mode */ - - trise = freqmhz + 1; - } - - /* Configure speed in fast mode */ - - else /* (frequency <= 400000) */ - { - /* Fast mode speed calculation with Tlow/Thigh = 16/9 */ + else /* (frequency <= 400000) */ + { + /* Fast mode speed calculation with Tlow/Thigh = 16/9 */ #ifdef CONFIG_STM32_I2C_DUTY16_9 - speed = (uint16_t)(STM32_PCLK1_FREQUENCY / (frequency * 25)); + speed = (uint16_t)(STM32_PCLK1_FREQUENCY / (frequency * 25)); - /* Set DUTY and fast speed bits */ + /* Set DUTY and fast speed bits */ - ccr |= (I2C_CCR_DUTY | I2C_CCR_FS); + ccr |= (I2C_CCR_DUTY | I2C_CCR_FS); #else - /* Fast mode speed calculation with Tlow/Thigh = 2 */ + /* Fast mode speed calculation with Tlow/Thigh = 2 */ - speed = (uint16_t)(STM32_PCLK1_FREQUENCY / (frequency * 3)); + speed = (uint16_t)(STM32_PCLK1_FREQUENCY / (frequency * 3)); - /* Set fast speed bit */ + /* Set fast speed bit */ - ccr |= I2C_CCR_FS; + ccr |= I2C_CCR_FS; #endif - /* Verify that the CCR speed value is nonzero */ + /* Verify that the CCR speed value is nonzero */ - if (speed < 1) - { - /* Set the minimum allowed value */ + if (speed < 1) + { + /* Set the minimum allowed value */ - speed = 1; + speed = 1; + } + + ccr |= speed; + + /* Set Maximum Rise Time for fast mode */ + + trise = (uint16_t)(((freqmhz * 300) / 1000) + 1); } - ccr |= speed; + /* Write the new values of the CCR and TRISE registers */ - /* Set Maximum Rise Time for fast mode */ + stm32_i2c_putreg(priv, STM32_I2C_CCR_OFFSET, ccr); + stm32_i2c_putreg(priv, STM32_I2C_TRISE_OFFSET, trise); - trise = (uint16_t)(((freqmhz * 300) / 1000) + 1); + /* Bit 14 of OAR1 must be configured and kept at 1 */ + + stm32_i2c_putreg(priv, STM32_I2C_OAR1_OFFSET, I2C_OAR1_ONE); + + /* Re-enable the peripheral (or not) */ + + stm32_i2c_putreg(priv, STM32_I2C_CR1_OFFSET, cr1); + + /* Save the new I2C frequency */ + + priv->frequency = frequency; } - - /* Write the new values of the CCR and TRISE registers */ - - stm32_i2c_putreg(priv, STM32_I2C_CCR_OFFSET, ccr); - stm32_i2c_putreg(priv, STM32_I2C_TRISE_OFFSET, trise); - - /* Bit 14 of OAR1 must be configured and kept at 1 */ - - stm32_i2c_putreg(priv, STM32_I2C_OAR1_OFFSET, I2C_OAR1_ONE); - - /* Re-enable the peripheral (or not) */ - - stm32_i2c_putreg(priv, STM32_I2C_CR1_OFFSET, cr1); } /************************************************************************************ @@ -2029,28 +2034,6 @@ static int stm32_i2c_deinit(FAR struct stm32_i2c_priv_s *priv) * Device Driver Operations ************************************************************************************/ -/************************************************************************************ - * Name: stm32_i2c_setfrequency - * - * Description: - * Set the I2C frequency - * - ************************************************************************************/ - -static uint32_t stm32_i2c_setfrequency(FAR struct i2c_master_s *dev, uint32_t frequency) -{ - stm32_i2c_sem_wait(dev); - -#if STM32_PCLK1_FREQUENCY < 4000000 - ((struct stm32_i2c_inst_s *)dev)->frequency = 100000; -#else - ((struct stm32_i2c_inst_s *)dev)->frequency = frequency; -#endif - - stm32_i2c_sem_post(dev); - return ((struct stm32_i2c_inst_s *)dev)->frequency; -} - /************************************************************************************ * Name: stm32_i2c_process * @@ -2108,9 +2091,13 @@ static int stm32_i2c_process(FAR struct i2c_master_s *dev, FAR struct i2c_msg_s stm32_i2c_tracereset(priv); - /* Set I2C clock frequency (on change it toggles I2C_CR1_PE !) */ + /* Set I2C clock frequency (on change it toggles I2C_CR1_PE !) + * REVISIT: Note that the frequency is set only on the first message. + * This could be extended to support different transfer frequencies for + * each message segment. + */ - stm32_i2c_setclock(priv, inst->frequency); + stm32_i2c_setclock(priv, msgs->frequency); /* Trigger start condition, then the process moves into the ISR. I2C * interrupts will be enabled within stm32_i2c_waitdone(). @@ -2339,9 +2326,8 @@ FAR struct i2c_master_s *up_i2cinitialize(int port) /* Initialize instance */ - inst->ops = &stm32_i2c_ops; - inst->priv = priv; - inst->frequency = 100000; + inst->ops = &stm32_i2c_ops; + inst->priv = priv; /* Initialize private data for the first time, increment reference count, * power-up hardware and configure GPIOs. diff --git a/arch/arm/src/stm32/stm32f30xxx_i2c.c b/arch/arm/src/stm32/stm32f30xxx_i2c.c index 8739982cbca..23262fc87bf 100644 --- a/arch/arm/src/stm32/stm32f30xxx_i2c.c +++ b/arch/arm/src/stm32/stm32f30xxx_i2c.c @@ -252,6 +252,7 @@ struct stm32_i2c_priv_s uint8_t msgc; /* Message count */ struct i2c_msg_s *msgv; /* Message list */ uint8_t *ptr; /* Current message buffer */ + uint32_t frequency; /* Current I2C frequency */ int dcnt; /* Current message length */ uint16_t flags; /* Current message flags */ bool astart; /* START sent */ @@ -276,8 +277,6 @@ struct stm32_i2c_inst_s { struct i2c_ops_s *ops; /* Standard I2C operations */ struct stm32_i2c_priv_s *priv; /* Common driver private data structure */ - - uint32_t frequency; /* Frequency used in this instantiation */ }; /************************************************************************************ @@ -332,8 +331,6 @@ static int stm32_i2c3_isr(int irq, void *context); #endif static int stm32_i2c_init(FAR struct stm32_i2c_priv_s *priv); static int stm32_i2c_deinit(FAR struct stm32_i2c_priv_s *priv); -static uint32_t stm32_i2c_setfrequency(FAR struct i2c_master_s *dev, - uint32_t frequency); static int stm32_i2c_process(FAR struct i2c_master_s *dev, FAR struct i2c_msg_s *msgs, int count); static int stm32_i2c_transfer(FAR struct i2c_master_s *dev, FAR struct i2c_msg_s *msgs, @@ -434,8 +431,7 @@ struct stm32_i2c_priv_s stm32_i2c3_priv = struct i2c_ops_s stm32_i2c_ops = { - .setfrequency = stm32_i2c_setfrequency, - .transfer = stm32_i2c_transfer + .transfer = stm32_i2c_transfer }; /************************************************************************************ @@ -1066,70 +1062,79 @@ static void stm32_i2c_setclock(FAR struct stm32_i2c_priv_s *priv, uint32_t frequ uint8_t scl_h_period; uint8_t scl_l_period; - /* Disable the selected I2C peripheral to configure TRISE */ + /* Has the I2C bus frequency changed? */ - pe = (stm32_i2c_getreg32(priv, STM32_I2C_CR1_OFFSET) & I2C_CR1_PE); - if (pe) + if (frequency != priv->frequency) { - stm32_i2c_modifyreg32(priv, STM32_I2C_CR1_OFFSET, I2C_CR1_PE, 0); - } + /* Disable the selected I2C peripheral to configure TRISE */ - /* Update timing and control registers */ + pe = (stm32_i2c_getreg32(priv, STM32_I2C_CR1_OFFSET) & I2C_CR1_PE); + if (pe) + { + stm32_i2c_modifyreg32(priv, STM32_I2C_CR1_OFFSET, I2C_CR1_PE, 0); + } - /* TODO: speed/timing calcs */ + /* Update timing and control registers */ + + /* TODO: speed/timing calcs */ #warning "check set filters before timing, see RM0316" - /* values from 100khz at 8mhz i2c clock */ + /* values from 100khz at 8mhz i2c clock */ - /* prescaler */ - /* t_presc= (presc+1)*t_i2cclk */ - /* RM0316 */ + /* prescaler */ + /* t_presc= (presc+1)*t_i2cclk */ + /* RM0316 */ - if (frequency == 10000) - { - presc = 0x01; - scl_l_period = 0xc7; - scl_h_period = 0xc3; - h_time = 0x02; - s_time = 0x04; - } - else if (frequency == 100000) - { - /* values from datasheet with clock 8mhz */ + if (frequency == 10000) + { + presc = 0x01; + scl_l_period = 0xc7; + scl_h_period = 0xc3; + h_time = 0x02; + s_time = 0x04; + } + else if (frequency == 100000) + { + /* values from datasheet with clock 8mhz */ - presc = 0x01; - scl_l_period = 0x13; - scl_h_period = 0x0f; - h_time = 0x02; - s_time = 0x04; - } - else - { - presc = 0x00; - scl_l_period = 0x09; - scl_h_period = 0x03; - h_time = 0x01; - s_time = 0x03; - } + presc = 0x01; + scl_l_period = 0x13; + scl_h_period = 0x0f; + h_time = 0x02; + s_time = 0x04; + } + else + { + presc = 0x00; + scl_l_period = 0x09; + scl_h_period = 0x03; + h_time = 0x01; + s_time = 0x03; + } - uint32_t timingr = - (presc << I2C_TIMINGR_PRESC_SHIFT) | - (s_time << I2C_TIMINGR_SCLDEL_SHIFT) | - (h_time << I2C_TIMINGR_SDADEL_SHIFT) | - (scl_h_period << I2C_TIMINGR_SCLH_SHIFT) | - (scl_l_period << I2C_TIMINGR_SCLL_SHIFT); + uint32_t timingr = + (presc << I2C_TIMINGR_PRESC_SHIFT) | + (s_time << I2C_TIMINGR_SCLDEL_SHIFT) | + (h_time << I2C_TIMINGR_SDADEL_SHIFT) | + (scl_h_period << I2C_TIMINGR_SCLH_SHIFT) | + (scl_l_period << I2C_TIMINGR_SCLL_SHIFT); - stm32_i2c_putreg32(priv, STM32_I2C_TIMINGR_OFFSET, timingr); + stm32_i2c_putreg32(priv, STM32_I2C_TIMINGR_OFFSET, timingr); - /* Bit 14 of OAR1 must be configured and kept at 1 */ + /* Bit 14 of OAR1 must be configured and kept at 1 */ - stm32_i2c_putreg(priv, STM32_I2C_OAR1_OFFSET, I2C_OAR1_ONE); + stm32_i2c_putreg(priv, STM32_I2C_OAR1_OFFSET, I2C_OAR1_ONE); - /* Re-enable the peripheral (or not) */ + /* Re-enable the peripheral (or not) */ - if (pe) - { - stm32_i2c_modifyreg32(priv, STM32_I2C_CR1_OFFSET, 0, I2C_CR1_PE); + if (pe) + { + stm32_i2c_modifyreg32(priv, STM32_I2C_CR1_OFFSET, 0, I2C_CR1_PE); + } + + /* Save the new I2C frequency */ + + priv->frequency = frequency; } } @@ -1625,28 +1630,6 @@ static int stm32_i2c_deinit(FAR struct stm32_i2c_priv_s *priv) * Device Driver Operations ************************************************************************************/ -/************************************************************************************ - * Name: stm32_i2c_setfrequency - * - * Description: - * Set the I2C frequency - * - ************************************************************************************/ - -static uint32_t stm32_i2c_setfrequency(FAR struct i2c_master_s *dev, uint32_t frequency) -{ - stm32_i2c_sem_wait(dev); - -#if STM32_PCLK1_FREQUENCY < 4000000 - ((struct stm32_i2c_inst_s *)dev)->frequency = 100000; -#else - ((struct stm32_i2c_inst_s *)dev)->frequency = frequency; -#endif - - stm32_i2c_sem_post(dev); - return ((struct stm32_i2c_inst_s *)dev)->frequency; -} - /************************************************************************************ * Name: stm32_i2c_process * @@ -1690,9 +1673,13 @@ static int stm32_i2c_process(FAR struct i2c_master_s *dev, FAR struct i2c_msg_s stm32_i2c_tracereset(priv); - /* Set I2C clock frequency (on change it toggles I2C_CR1_PE !) */ + /* Set I2C clock frequency (on change it toggles I2C_CR1_PE !) + * REVISIT: Note that the frequency is set only on the first message. + * This could be extended to support different transfer frequencies for + * each message segment. + */ - stm32_i2c_setclock(priv, inst->frequency); + stm32_i2c_setclock(priv, msgs->frequency); /* Trigger start condition, then the process moves into the ISR. I2C * interrupts will be enabled within stm32_i2c_waitdone(). @@ -1896,9 +1883,8 @@ FAR struct i2c_master_s *up_i2cinitialize(int port) /* Initialize instance */ - inst->ops = &stm32_i2c_ops; - inst->priv = priv; - inst->frequency = 400000; + inst->ops = &stm32_i2c_ops; + inst->priv = priv; /* Init private data for the first time, increment refs count, * power-up hardware and configure GPIOs. diff --git a/arch/arm/src/tiva/tiva_i2c.c b/arch/arm/src/tiva/tiva_i2c.c index 61ede0b3473..2a2626e1698 100644 --- a/arch/arm/src/tiva/tiva_i2c.c +++ b/arch/arm/src/tiva/tiva_i2c.c @@ -225,6 +225,7 @@ struct tiva_i2c_priv_s uint8_t msgc; /* Message count */ struct i2c_msg_s *msgv; /* Message list */ uint8_t *mptr; /* Current message buffer */ + uint32_t frequency; /* Current I2C frequency */ int mcnt; /* Current message length */ uint16_t mflags; /* Current message flags */ uint32_t mstatus; /* MCS register at the end of the transfer */ @@ -258,8 +259,6 @@ struct tiva_i2c_inst_s { const struct i2c_ops_s *ops; /* Standard I2C operations */ struct tiva_i2c_priv_s *priv; /* Common driver private data structure */ - - uint32_t frequency; /* Frequency used in this instantiation */ }; /************************************************************************************ @@ -336,10 +335,7 @@ static int tiva_i2c9_interrupt(int irq, void *context); static int tiva_i2c_initialize(struct tiva_i2c_priv_s *priv, uint32_t frequency); static int tiva_i2c_uninitialize(struct tiva_i2c_priv_s *priv); -static uint32_t tiva_i2c_setclock(struct tiva_i2c_priv_s *priv, - uint32_t frequency); -static uint32_t tiva_i2c_setfrequency(struct i2c_master_s *dev, - uint32_t frequency); +static void tiva_i2c_setclock(struct tiva_i2c_priv_s *priv, uint32_t frequency); static int tiva_i2c_process(struct i2c_master_s *dev, struct i2c_msg_s *msgv, int msgc); static int tiva_i2c_transfer(struct i2c_master_s *dev, struct i2c_msg_s *msgv, @@ -573,8 +569,7 @@ static struct tiva_i2c_priv_s tiva_i2c9_priv; static const struct i2c_ops_s tiva_i2c_ops = { - .setfrequency = tiva_i2c_setfrequency, - .transfer = tiva_i2c_transfer + .transfer = tiva_i2c_transfer }; /************************************************************************************ @@ -1770,7 +1765,7 @@ static int tiva_i2c_initialize(struct tiva_i2c_priv_s *priv, uint32_t frequency) /* Configure the the initial I2C clock frequency. */ - (void)tiva_i2c_setclock(priv, frequency); + tiva_i2c_setclock(priv, frequency); /* Attach interrupt handlers and enable interrupts at the NVIC (still * disabled at the source). @@ -1835,68 +1830,46 @@ static int tiva_i2c_uninitialize(struct tiva_i2c_priv_s *priv) * ************************************************************************************/ -static uint32_t tiva_i2c_setclock(struct tiva_i2c_priv_s *priv, uint32_t frequency) +static void tiva_i2c_setclock(struct tiva_i2c_priv_s *priv, uint32_t frequency) { uint32_t regval; uint32_t tmp; i2cvdbg("I2C%d: frequency: %u\n", priv->config->devno, frequency); - /* Calculate the clock divider that results in the highest frequency that - * is than or equal to the desired speed. - */ + /* Has the I2C bus frequency changed? */ - tmp = 2 * 10 * frequency; - regval = (((SYSCLK_FREQUENCY + tmp - 1) / tmp) - 1) << I2CM_TPR_SHIFT; - - DEBUGASSERT((regval & I2CM_TPR_MASK) == regval); - tiva_i2c_putreg(priv, TIVA_I2CM_TPR_OFFSET, regval); - -#if defined(CONFIG_TIVA_I2C_HIGHSPEED) && defined(TIVA_I2CSC_PC_OFFSET) - /* If the I2C peripheral is High-Speed enabled then choose the highest - * speed that is less than or equal to 3.4 Mbps. - */ - - regval = tiva_i2c_getreg(priv, TIVA_I2CSC_PC_OFFSET); - if ((regval & I2CSC_PC_HS) != 0) + if (frequency != priv->frequency) { - tmp = (2 * 3 * 3400000); + /* Calculate the clock divider that results in the highest frequency that + * is than or equal to the desired speed. + */ + + tmp = 2 * 10 * frequency; regval = (((SYSCLK_FREQUENCY + tmp - 1) / tmp) - 1) << I2CM_TPR_SHIFT; - tiva_i2c_putreg(priv, TIVA_I2CM_TPR_OFFSET, I2CM_TPR_HS | regval); - } + DEBUGASSERT((regval & I2CM_TPR_MASK) == regval); + tiva_i2c_putreg(priv, TIVA_I2CM_TPR_OFFSET, regval); + +#if defined(CONFIG_TIVA_I2C_HIGHSPEED) && defined(TIVA_I2CSC_PC_OFFSET) + /* If the I2C peripheral is High-Speed enabled then choose the highest + * speed that is less than or equal to 3.4 Mbps. + */ + + regval = tiva_i2c_getreg(priv, TIVA_I2CSC_PC_OFFSET); + if ((regval & I2CSC_PC_HS) != 0) + { + tmp = (2 * 3 * 3400000); + regval = (((SYSCLK_FREQUENCY + tmp - 1) / tmp) - 1) << I2CM_TPR_SHIFT; + + tiva_i2c_putreg(priv, TIVA_I2CM_TPR_OFFSET, I2CM_TPR_HS | regval); + } #endif - return frequency; -} -/************************************************************************************ - * Name: tiva_i2c_setfrequency - * - * Description: - * Set the I2C frequency - * - ************************************************************************************/ + /* Save the new I2C frequency */ -static uint32_t tiva_i2c_setfrequency(struct i2c_master_s *dev, uint32_t frequency) -{ - struct tiva_i2c_inst_s *inst = (struct tiva_i2c_inst_s *)dev; - struct tiva_i2c_priv_s *priv; - - DEBUGASSERT(inst && inst->priv); - priv = inst->priv; - - i2cvdbg("I2C%d: frequency: %u\n", inst->priv->config->devno, frequency); - - /* Get exclusive access to the I2C device */ - - tiva_i2c_sem_wait(dev); - - /* Set the clocking for the selected frequency */ - - inst->frequency = tiva_i2c_setclock(priv, frequency); - - tiva_i2c_sem_post(dev); - return frequency; + priv->frequency = frequency; + } } /************************************************************************************ @@ -1935,9 +1908,14 @@ static int tiva_i2c_process(struct i2c_master_s *dev, struct i2c_msg_s *msgv, in tiva_i2c_tracereset(priv); tiva_i2c_tracenew(priv, 0); - /* Set I2C clock frequency */ + /* Set I2C clock frequency + * + * REVISIT: Note that the frequency is set only on the first message. + * This could be extended to support different transfer frequencies for + * each message segment. + */ - tiva_i2c_setclock(priv, inst->frequency); + tiva_i2c_setclock(priv, msgs->frequency); /* Send the address, then the process moves into the ISR. I2C * interrupts will be enabled within tiva_i2c_waitdone(). @@ -2012,7 +1990,7 @@ static int tiva_i2c_process(struct i2c_master_s *dev, struct i2c_msg_s *msgv, in /* Reset and reinitialize the I2C hardware */ - tiva_i2c_initialize(priv, inst->frequency); + tiva_i2c_initialize(priv, priv->frequency); /* Is the busy condition a consequence of some other error? */ @@ -2032,9 +2010,6 @@ static int tiva_i2c_process(struct i2c_master_s *dev, struct i2c_msg_s *msgv, in priv->mcnt = 0; priv->mptr = NULL; - - tiva_i2c_sem_post(dev); - return -errcode; } @@ -2050,13 +2025,15 @@ static int tiva_i2c_transfer(struct i2c_master_s *dev, struct i2c_msg_s *msgv, int msgc) { struct tiva_i2c_inst_s *inst = (struct tiva_i2c_inst_s *)dev; + int ret; DEBUGASSERT(inst && inst->priv && inst->priv->config); i2cvdbg("I2C%d: msgc=%d\n", inst->priv->config->devno, msgc); UNUSED(inst); tiva_i2c_sem_wait(dev); /* Ensure that address or flags don't change meanwhile */ - return tiva_i2c_process(dev, msgv, msgc); + ret = tiva_i2c_process(dev, msgv, msgc); + tiva_i2c_sem_post(dev); } /************************************************************************************ @@ -2172,7 +2149,6 @@ struct i2c_master_s *up_i2cinitialize(int port) inst->ops = &tiva_i2c_ops; inst->priv = priv; - inst->frequency = 100000; /* Initialize private data for the first time, increment reference count, * power-up hardware and configure GPIOs. @@ -2360,7 +2336,7 @@ int up_i2creset(struct i2c_master_s *dev) /* Re-init the port */ - tiva_i2c_initialize(priv, inst->frequency); + tiva_i2c_initialize(priv, priv->frequency); ret = OK; out: diff --git a/arch/z80/src/ez80/ez80_i2c.c b/arch/z80/src/ez80/ez80_i2c.c index c8fd579328a..ee6684366a9 100644 --- a/arch/z80/src/ez80/ez80_i2c.c +++ b/arch/z80/src/ez80/ez80_i2c.c @@ -70,7 +70,6 @@ struct ez80_i2cdev_s { FAR const struct i2c_ops_s *ops; /* I2C vtable */ uint32_t frequency; /* Currently selected I2C frequency */ - uint16_t ccr; /* Clock control register value */ uint16_t addr; /* 7- or 10-bit address */ uint8_t addr10 : 1; /* 1=Address is 10-bit */ }; @@ -93,11 +92,11 @@ static int ez80_i2c_read_transfer(FAR struct ez80_i2cdev_s *priv, FAR uint8_t *buffer, int buflen, uint8_t flags); static int ez80_i2c_write_transfer(FAR struct ez80_i2cdev_s *priv, FAR const uint8_t *buffer, int buflen, uint8_t flags); +static void ez80_i2c_setfrequency(FAR struct ez80_i2cdev_s *priv, + uint32_t frequency); /* I2C methods */ -static uint32_t ez80_i2c_setfrequency(FAR struct i2c_master_s *dev, - uint32_t frequency); static int ez80_i2c_transfer(FAR struct i2c_master_s *dev, FAR struct i2c_msg_s *msgs, int count); @@ -113,13 +112,11 @@ extern uint32_t get_freq(void); * Private Data ****************************************************************************/ -static uint8_t g_currccr; /* Current setting of I2C CCR register */ -static bool g_initialized; /* true:I2C has been initialized */ -static sem_t g_i2csem; /* Serialize I2C transfers */ +static bool g_initialized; /* true:I2C has been initialized */ +static sem_t g_i2csem; /* Serialize I2C transfers */ const struct i2c_ops_s g_ops = { - ez80_i2c_setfrequency, ez80_i2c_transfer }; @@ -172,11 +169,7 @@ static void ez80_i2c_semtake(void) static void ez80_i2c_setccr(uint16_t ccr) { - if (g_currccr != ccr) - { - outp(EZ80_I2C_CCR, ccr); - g_currccr = ccr; - } + outp(EZ80_I2C_CCR, ccr); } /**************************************************************************** @@ -791,29 +784,26 @@ static int ez80_i2c_write_transfer(FAR struct ez80_i2cdev_s *priv, * frequency - The I2C frequency requested * * Returned Value: - * Returns the actual frequency selected + * None * ****************************************************************************/ -static uint32_t ez80_i2c_setfrequency(FAR struct i2c_master_s *dev, - uint32_t frequency) +static void ez80_i2c_setfrequency(FAR struct ez80_i2cdev_s *priv, + uint32_t frequency) { - FAR struct ez80_i2cdev_s *priv = (FAR struct ez80_i2cdev_s *)dev; + uint16_t ccr; - DEBUGASSERT(dev != NULL); if (priv->frequency != frequency) { - /* Calculate and save the BRG (we won't apply it until the first - * transfer) - */ + /* Calculate and save the BRG and set the CCR */ + + ccr = ez80_i2c_getccr(frequency); + ez80_i2c_setccr(ccr); + + /* Save the new I2C frequency */ - priv->ccr = ez80_i2c_getccr(frequency); priv->frequency = frequency; } - - /* TODO: Calculate and return the actual frequency */ - - return frequency; } /**************************************************************************** @@ -853,9 +843,7 @@ static int ez80_i2c_transfer(FAR struct i2c_master_s *dev, ez80_i2c_semtake(); - /* Set the frequency */ - - ez80_i2c_setccr(priv->ccr); + /* The process each message seqment */ for (i = 0; i < count; i++) { @@ -863,6 +851,8 @@ static int ez80_i2c_transfer(FAR struct i2c_master_s *dev, /* Set the I2C frequency and address */ + ez80_i2c_setfrequency(priv, msg->frequency); + priv->addr = msg->addr; priv->addr10 = ((msg->flags & I2C_M_TEN) != 0); @@ -975,7 +965,6 @@ FAR struct i2c_master_s *up_i2cinitialize(int port) /* Initialize the allocated instance */ i2c->ops = &g_ops; - i2c->ccr = g_currccr; } return (FAR struct i2c_master_s *)i2c; diff --git a/arch/z80/src/z8/z8_i2c.c b/arch/z80/src/z8/z8_i2c.c index 3b7690b4f9b..f628a1acdcf 100644 --- a/arch/z80/src/z8/z8_i2c.c +++ b/arch/z80/src/z8/z8_i2c.c @@ -87,11 +87,11 @@ static int z8_i2c_read_transfer(FAR struct z8_i2cdev_s *priv, FAR uint8_t *buffer, int buflen, uint8_t flags); static int z8_i2c_write_transfer(FAR struct z8_i2cdev_s *priv, FAR const uint8_t *buffer, int buflen, uint8_t flags); +static void z8_i2c_setfrequency(FAR struct z8_i2cdev_s *priv, + uint32_t frequency); /* I2C methods */ -static uint32_t z8_i2c_setfrequency(FAR struct i2c_master_s *dev, - uint32_t frequency); static int z8_i2c_transfer(FAR struct i2c_master_s *dev, FAR struct i2c_msg_s *msgs, int count); @@ -107,13 +107,11 @@ extern uint32_t get_freq(void); * Private Data ****************************************************************************/ -static uint16_t g_currbrg; /* Current BRG setting */ -static bool g_initialized; /* true:I2C has been initialized */ -static sem_t g_i2csem; /* Serialize I2C transfers */ +static bool g_initialized; /* true:I2C has been initialized */ +static sem_t g_i2csem; /* Serialize I2C transfers */ const struct i2c_ops_s g_ops = { - z8_i2c_setfrequency, z8_i2c_transfer, }; @@ -206,12 +204,8 @@ static void z8_i2c_waitrxavail(void) static void z8_i2c_setbrg(uint16_t brg) { - if (g_currbrg != brg) - { - I2CBRH = (uint8_t)(brg >> 8); - I2CBRL = (uint8_t)(brg & 0xff); - g_currbrg = brg; - } + I2CBRH = (uint8_t)(brg >> 8); + I2CBRL = (uint8_t)(brg & 0xff); } /**************************************************************************** @@ -471,16 +465,14 @@ static int z8_i2c_write_transfer(FAR struct z8_i2cdev_s *priv, * frequency - The I2C frequency requested * * Returned Value: - * Returns the actual frequency selected + * None * ****************************************************************************/ -static uint32_t z8_i2c_setfrequency(FAR struct i2c_master_s *dev, - uint32_t frequency) +static void z8_i2c_setfrequency(FAR struct z8_i2cdev_s *priv, + uint32_t frequency) { - FAR struct z8_i2cdev_s *priv = (FAR struct z8_i2cdev_s *)dev; - - DEBUGASSERT(dev != NULL); + uint16_t brg; /* Has the frequency changed? */ @@ -488,11 +480,13 @@ static uint32_t z8_i2c_setfrequency(FAR struct i2c_master_s *dev, { /* Calculate and save the BRG (we won't apply it until the first transfer) */ - priv->brg = z8_i2c_getbrg(frequency); + brg = z8_i2c_getbrg(frequency); + z8_i2c_setbrg(brg); + + /* Save the new I2C frequency */ + priv->frequency = frequency; } - - return OK; } /**************************************************************************** @@ -532,15 +526,15 @@ static int z8_i2c_transfer(FAR struct i2c_master_s *dev, z8_i2c_semtake(); - /* Set the frequency */ - - z8_i2c_setbrg(priv->brg); + /* The process each message seqment */ for (i = 0; i < count; i++) { msg = &msgs[i]; - /* Set the I2C address */ + /* Set the I2C frequency and address */ + + z8_i2c_setfrequency(priv, msg->frequency); priv->addr = msg->addr; DEBUGASSERT((msg->flags & I2C_M_TEN) == 0); @@ -655,7 +649,6 @@ FAR struct i2c_master_s *up_i2cinitialize(int port) /* Initialize the allocated instance */ i2c->ops = &g_ops; - i2c->brg = g_currbrg; } return (FAR struct i2c_master_s *)i2c;