diff --git a/arch/arm/src/efm32/efm32_i2c.c b/arch/arm/src/efm32/efm32_i2c.c index 4395c537e6a..949f3579606 100644 --- a/arch/arm/src/efm32/efm32_i2c.c +++ b/arch/arm/src/efm32/efm32_i2c.c @@ -314,11 +314,14 @@ static int efm32_i2c1_isr(int irq, void *context); #endif #endif /* !CONFIG_I2C_POLLED */ -static void efm32_i2c_reset(FAR struct efm32_i2c_priv_s *priv); +static void efm32_i2c_hwreset(FAR struct efm32_i2c_priv_s *priv); 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 int efm32_i2c_transfer(FAR struct i2c_master_s *dev, FAR struct i2c_msg_s *msgs, int count); +#ifdef CONFIG_I2C_RESET +static int efm32_i2c_reset(FAR struct i2c_master_s *dev); +#endif #ifdef CONFIG_I2C_TRACE static const char *efm32_i2c_state_str(int i2c_state); @@ -333,6 +336,9 @@ static const char *efm32_i2c_state_str(int i2c_state); static const struct i2c_ops_s efm32_i2c_ops = { .transfer = efm32_i2c_transfer +#ifdef CONFIG_I2C_RESET + , .reset = efm32_i2c_reset +#endif }; /* I2C device structures */ @@ -1315,14 +1321,14 @@ static int efm32_i2c1_isr(int irq, void *context) ****************************************************************************/ /**************************************************************************** - * Name: efm32_i2c_reset + * Name: efm32_i2c_hwreset * * Description: * Reset I2C to same state as after a HW reset. * ****************************************************************************/ -static void efm32_i2c_reset(FAR struct efm32_i2c_priv_s *priv) +static void efm32_i2c_hwreset(FAR struct efm32_i2c_priv_s *priv) { efm32_i2c_putreg(priv, EFM32_I2C_CTRL_OFFSET, _I2C_CTRL_RESETVALUE); efm32_i2c_putreg(priv, EFM32_I2C_CLKDIV_OFFSET, _I2C_CLKDIV_RESETVALUE); @@ -1357,7 +1363,7 @@ static int efm32_i2c_init(FAR struct efm32_i2c_priv_s *priv) /* Eeset all resgister */ - efm32_i2c_reset(priv); + efm32_i2c_hwreset(priv); /* Configure pins */ @@ -1417,7 +1423,7 @@ static int efm32_i2c_deinit(FAR struct efm32_i2c_priv_s *priv) { /* Disable I2C */ - efm32_i2c_reset(priv); + efm32_i2c_hwreset(priv); /* Unconfigure GPIO pins */ @@ -1594,111 +1600,22 @@ static int efm32_i2c_transfer(FAR struct i2c_master_s *dev, return ret; } -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: up_i2cinitialize +/************************************************************************************ + * Name: efm32_i2c_reset * * Description: - * Initialize one I2C bus + * Perform an I2C bus reset in an attempt to break loose stuck I2C devices. * - ****************************************************************************/ - -FAR struct i2c_master_s *up_i2cinitialize(int port) -{ - struct efm32_i2c_priv_s *priv = NULL; - irqstate_t irqs; - - /* Get I2C private structure */ - - switch (port) - { -#ifdef CONFIG_EFM32_I2C0 - case 0: - priv = (struct efm32_i2c_priv_s *)&efm32_i2c0_priv; - break; -#endif - -#ifdef CONFIG_EFM32_I2C1 - case 1: - priv = (struct efm32_i2c_priv_s *)&efm32_i2c1_priv; - break; -#endif - - default: - return NULL; - } - - /* Initialize private data for the first time, increment reference count, - * power-up hardware and configure GPIOs. - */ - - irqs = irqsave(); - - if ((volatile int)priv->refs++ == 0) - { - efm32_i2c_sem_init(priv); - efm32_i2c_init(priv); - } - - irqrestore(irqs); - return (struct i2c_master_s *)priv; -} - -/**************************************************************************** - * Name: up_i2cuninitialize + * Input Parameters: + * dev - Device-specific state data * - * Description: - * Uninitialize an I2C bus + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. * - ****************************************************************************/ - -int up_i2cuninitialize(FAR struct i2c_master_s *dev) -{ - FAR struct efm32_i2c_priv_s *priv = (struct efm32_i2c_priv_s *)dev; - irqstate_t irqs; - - ASSERT(dev); - - /* Decrement reference count and check for underflow */ - - if (priv->refs == 0) - { - return ERROR; - } - - irqs = irqsave(); - - if (--priv->refs) - { - irqrestore(irqs); - return OK; - } - - irqrestore(irqs); - - /* Disable power and other HW resource (GPIO's) */ - - efm32_i2c_deinit(priv); - - /* Release unused resources */ - - efm32_i2c_sem_destroy(priv); - return OK; -} - -/**************************************************************************** - * Name: up_i2creset - * - * Description: - * Reset an I2C bus - * - ****************************************************************************/ + ************************************************************************************/ #ifdef CONFIG_I2C_RESET -int up_i2creset(FAR struct i2c_master_s *dev) +int efm32_i2c_reset(FAR struct i2c_master_s *dev) { FAR struct efm32_i2c_priv_s *priv = (struct efm32_i2c_priv_s *)dev; unsigned int clock_count; @@ -1802,4 +1719,99 @@ out: } #endif /* CONFIG_I2C_RESET */ +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_i2cinitialize + * + * Description: + * Initialize one I2C bus + * + ****************************************************************************/ + +FAR struct i2c_master_s *up_i2cinitialize(int port) +{ + struct efm32_i2c_priv_s *priv = NULL; + irqstate_t irqs; + + /* Get I2C private structure */ + + switch (port) + { +#ifdef CONFIG_EFM32_I2C0 + case 0: + priv = (struct efm32_i2c_priv_s *)&efm32_i2c0_priv; + break; +#endif + +#ifdef CONFIG_EFM32_I2C1 + case 1: + priv = (struct efm32_i2c_priv_s *)&efm32_i2c1_priv; + break; +#endif + + default: + return NULL; + } + + /* Initialize private data for the first time, increment reference count, + * power-up hardware and configure GPIOs. + */ + + irqs = irqsave(); + + if ((volatile int)priv->refs++ == 0) + { + efm32_i2c_sem_init(priv); + efm32_i2c_init(priv); + } + + irqrestore(irqs); + return (struct i2c_master_s *)priv; +} + +/**************************************************************************** + * Name: up_i2cuninitialize + * + * Description: + * Uninitialize an I2C bus + * + ****************************************************************************/ + +int up_i2cuninitialize(FAR struct i2c_master_s *dev) +{ + FAR struct efm32_i2c_priv_s *priv = (struct efm32_i2c_priv_s *)dev; + irqstate_t irqs; + + ASSERT(dev); + + /* Decrement reference count and check for underflow */ + + if (priv->refs == 0) + { + return ERROR; + } + + irqs = irqsave(); + + if (--priv->refs) + { + irqrestore(irqs); + return OK; + } + + irqrestore(irqs); + + /* Disable power and other HW resource (GPIO's) */ + + efm32_i2c_deinit(priv); + + /* Release unused resources */ + + efm32_i2c_sem_destroy(priv); + return OK; +} + #endif /* CONFIG_EFM32_I2C0 || CONFIG_EFM32_I2C1 */ diff --git a/arch/arm/src/lpc11xx/lpc11_i2c.c b/arch/arm/src/lpc11xx/lpc11_i2c.c index 213ba5a84a5..220a30e09b3 100644 --- a/arch/arm/src/lpc11xx/lpc11_i2c.c +++ b/arch/arm/src/lpc11xx/lpc11_i2c.c @@ -132,12 +132,15 @@ 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); +static void lpc11_stopnext(struct lpc11_i2cdev_s *priv); /* I2C device operations */ 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); +#ifdef CONFIG_I2C_RESET +static int lpc11_i2c_reset(FAR struct i2c_master_s * dev); +#endif /**************************************************************************** * Private Data @@ -156,6 +159,9 @@ static struct lpc11_i2cdev_s g_i2c2dev; struct i2c_ops_s lpc11_i2c_ops = { .transfer = lpc11_i2c_transfer +#ifdef CONFIG_I2C_RESET + , .reset = lpc11_i2c_reset +#endif }; /**************************************************************************** @@ -440,6 +446,27 @@ static int lpc11_i2c_interrupt(int irq, FAR void *context) return OK; } +/************************************************************************************ + * Name: lpc11_i2c_reset + * + * Description: + * Perform an I2C bus reset in an attempt to break loose stuck I2C devices. + * + * Input Parameters: + * dev - Device-specific state data + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + ************************************************************************************/ + +#ifdef CONFIG_I2C_RESET +static int lpc11_i2c_reset(FAR struct i2c_master_s * dev) +{ + return OK; +} +#endif /* CONFIG_I2C_RESET */ + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -615,19 +642,4 @@ int up_i2cuninitialize(FAR struct i2c_master_s * dev) return OK; } -/**************************************************************************** - * Name: up_i2creset - * - * Description: - * Reset an I2C bus - * - ****************************************************************************/ - -#ifdef CONFIG_I2C_RESET -int up_i2creset(FAR struct i2c_master_s * dev) -{ - return OK; -} -#endif /* CONFIG_I2C_RESET */ - #endif /* CONFIG_LPC11_I2C0 || CONFIG_LPC11_I2C1 || CONFIG_LPC11_I2C2 */ diff --git a/arch/arm/src/lpc17xx/lpc17_i2c.c b/arch/arm/src/lpc17xx/lpc17_i2c.c index b5c9ebaf198..f40c8948c16 100644 --- a/arch/arm/src/lpc17xx/lpc17_i2c.c +++ b/arch/arm/src/lpc17xx/lpc17_i2c.c @@ -132,12 +132,15 @@ 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); +static void lpc17_stopnext(struct lpc17_i2cdev_s *priv); /* I2C device operations */ 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); +#ifdef CONFIG_I2C_RESET +static int lpc17_i2c_reset(FAR struct i2c_master_s * dev); +#endif /**************************************************************************** * Private Data @@ -156,6 +159,9 @@ static struct lpc17_i2cdev_s g_i2c2dev; struct i2c_ops_s lpc17_i2c_ops = { .transfer = lpc17_i2c_transfer +#ifdef CONFIG_I2C_RESET + , .reset = lpc17_i2c_reset +#endif }; /**************************************************************************** @@ -440,6 +446,27 @@ static int lpc17_i2c_interrupt(int irq, FAR void *context) return OK; } +/************************************************************************************ + * Name: lpc17_i2c_reset + * + * Description: + * Perform an I2C bus reset in an attempt to break loose stuck I2C devices. + * + * Input Parameters: + * dev - Device-specific state data + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + ************************************************************************************/ + +#ifdef CONFIG_I2C_RESET +static int lpc17_i2c_reset(FAR struct i2c_master_s * dev) +{ + return OK; +} +#endif /* CONFIG_I2C_RESET */ + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -620,19 +647,4 @@ int up_i2cuninitialize(FAR struct i2c_master_s * dev) return OK; } -/**************************************************************************** - * Name: up_i2creset - * - * Description: - * Reset an I2C bus - * - ****************************************************************************/ - -#ifdef CONFIG_I2C_RESET -int up_i2creset(FAR struct i2c_master_s * dev) -{ - return OK; -} -#endif /* CONFIG_I2C_RESET */ - #endif /* CONFIG_LPC17_I2C0 || CONFIG_LPC17_I2C1 || CONFIG_LPC17_I2C2 */ diff --git a/arch/arm/src/lpc2378/lpc23xx_i2c.c b/arch/arm/src/lpc2378/lpc23xx_i2c.c index 399c5a03257..a13d71edc0a 100644 --- a/arch/arm/src/lpc2378/lpc23xx_i2c.c +++ b/arch/arm/src/lpc2378/lpc23xx_i2c.c @@ -137,12 +137,15 @@ 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); +static void lpc2378_stopnext(struct lpc2378_i2cdev_s *priv); /* I2C device operations */ 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); +#ifdef CONFIG_I2C_RESET +static int lpc2378_i2c_reset(FAR struct i2c_master_s * dev); +#endif /**************************************************************************** * Private Data @@ -161,6 +164,9 @@ static struct lpc2378_i2cdev_s g_i2c2dev; struct i2c_ops_s lpc2378_i2c_ops = { .transfer = lpc2378_i2c_transfer +#ifdef CONFIG_I2C_RESET + , .reset = lpc2378_i2c_reset +#endif }; /**************************************************************************** @@ -259,50 +265,7 @@ static void lpc2378_i2c_timeout(int argc, uint32_t arg, ...) } /**************************************************************************** - * Name: lpc2378_i2c_transfer - * - * Description: - * Perform a sequence of I2C transfers - * - ****************************************************************************/ - -static int lpc2378_i2c_transfer(FAR struct i2c_master_s *dev, - FAR struct i2c_msg_s *msgs, int count) -{ - struct lpc2378_i2cdev_s *priv = (struct lpc2378_i2cdev_s *)dev; - int ret; - - DEBUGASSERT(dev != NULL && 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. - */ - - lpc2378_i2c_setfrequency(priv, msgs->frequency); - - /* Perform the transfer */ - - ret = lpc2378_i2c_start(priv); - - sem_post(&priv->mutex); - return ret; -} - -/**************************************************************************** - * Name: lpc2378_i2c_interrupt + * Name: lpc2378_stopnext * * Description: * Check if we need to issue STOP at the next message @@ -445,6 +408,70 @@ static int lpc2378_i2c_interrupt(int irq, FAR void *context) return OK; } +/**************************************************************************** + * Name: lpc2378_i2c_transfer + * + * Description: + * Perform a sequence of I2C transfers + * + ****************************************************************************/ + +static int lpc2378_i2c_transfer(FAR struct i2c_master_s *dev, + FAR struct i2c_msg_s *msgs, int count) +{ + struct lpc2378_i2cdev_s *priv = (struct lpc2378_i2cdev_s *)dev; + int ret; + + DEBUGASSERT(dev != NULL && 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. + */ + + lpc2378_i2c_setfrequency(priv, msgs->frequency); + + /* Perform the transfer */ + + ret = lpc2378_i2c_start(priv); + + sem_post(&priv->mutex); + return ret; +} + +/************************************************************************************ + * Name: lpc2378_i2c_reset + * + * Description: + * Perform an I2C bus reset in an attempt to break loose stuck I2C devices. + * + * Input Parameters: + * dev - Device-specific state data + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + ************************************************************************************/ + +#ifdef CONFIG_I2C_RESET +static int lpc2378_i2c_reset(FAR struct i2c_master_s * dev) +{ + return OK; +} +#endif /* CONFIG_I2C_RESET */ + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -631,19 +658,4 @@ int up_i2cuninitialize(FAR struct i2c_master_s * dev) return OK; } -/**************************************************************************** - * Name: up_i2creset - * - * Description: - * Reset an I2C bus - * - ****************************************************************************/ - -#ifdef CONFIG_I2C_RESET -int up_i2creset(FAR struct i2c_master_s * dev) -{ - return OK; -} -#endif /* CONFIG_I2C_RESET */ - #endif /* CONFIG_LPC2378_I2C0 || CONFIG_LPC2378_I2C1 || CONFIG_LPC2378_I2C2 */ diff --git a/arch/arm/src/lpc31xx/lpc31_i2c.c b/arch/arm/src/lpc31xx/lpc31_i2c.c index b65c9d8f22b..e8ad8aff458 100644 --- a/arch/arm/src/lpc31xx/lpc31_i2c.c +++ b/arch/arm/src/lpc31xx/lpc31_i2c.c @@ -114,10 +114,13 @@ static struct lpc31_i2cdev_s i2cdevices[2]; 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); +static void i2c_hwreset(struct lpc31_i2cdev_s *priv); 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); +#ifdef CONFIG_I2C_RESET +static int i2c_reset(FAR struct i2c_master_s * dev); +#endif /**************************************************************************** * Private Data @@ -126,6 +129,9 @@ static int i2c_transfer(FAR struct i2c_master_s *dev, struct i2c_ops_s lpc31_i2c_ops = { .transfer = i2c_transfer +#ifdef CONFIG_I2C_RESET + , .reset = i2c_reset +#endif }; /**************************************************************************** @@ -169,62 +175,6 @@ static void i2c_setfrequency(struct lpc31_i2cdev_s *priv, uint32_t frequency) } } -/**************************************************************************** - * Name: i2c_transfer - * - * Description: - * Perform a sequence of I2C transfers - * - ****************************************************************************/ - -static int i2c_transfer(FAR struct i2c_master_s *dev, FAR struct i2c_msg_s *msgs, int count) -{ - struct lpc31_i2cdev_s *priv = (struct lpc31_i2cdev_s *) dev; - 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; - - /* 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; -} - /**************************************************************************** * Name: i2c_interrupt * @@ -269,7 +219,7 @@ static void i2c_progress(struct lpc31_i2cdev_s *priv) { /* Perform a soft reset */ - i2c_reset(priv); + i2c_hwreset(priv); /* FIXME: automatic retry? */ @@ -439,7 +389,7 @@ out: priv->nmsg++; } - i2c_reset(priv); + i2c_hwreset(priv); } priv->state = I2C_STATE_DONE; @@ -477,7 +427,7 @@ static void i2c_timeout(int argc, uint32_t arg, ...) /* Soft reset the USB controller */ - i2c_reset(priv); + i2c_hwreset(priv); /* Mark the transfer as finished */ @@ -489,14 +439,14 @@ static void i2c_timeout(int argc, uint32_t arg, ...) } /**************************************************************************** - * Name: i2c_reset + * Name: i2c_hwreset * * Description: * Perform a soft reset of the I2C controller * ****************************************************************************/ -static void i2c_reset(struct lpc31_i2cdev_s *priv) +static void i2c_hwreset(struct lpc31_i2cdev_s *priv) { putreg32(I2C_CTRL_RESET, priv->base + LPC31_I2C_CTRL_OFFSET); @@ -506,6 +456,83 @@ static void i2c_reset(struct lpc31_i2cdev_s *priv) ; } +/**************************************************************************** + * Name: i2c_transfer + * + * Description: + * Perform a sequence of I2C transfers + * + ****************************************************************************/ + +static int i2c_transfer(FAR struct i2c_master_s *dev, FAR struct i2c_msg_s *msgs, int count) +{ + struct lpc31_i2cdev_s *priv = (struct lpc31_i2cdev_s *) dev; + 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; + + /* 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; +} + +/************************************************************************************ + * Name: i2c_reset + * + * Description: + * Perform an I2C bus reset in an attempt to break loose stuck I2C devices. + * + * Input Parameters: + * dev - Device-specific state data + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + ************************************************************************************/ + +#ifdef CONFIG_I2C_RESET +static int i2c_reset(FAR struct i2c_master_s * dev) +{ + return OK; +} +#endif /* CONFIG_I2C_RESET */ + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -540,7 +567,7 @@ struct i2c_master_s *up_i2cinitialize(int port) /* Soft reset the device */ - i2c_reset(priv); + i2c_hwreset(priv); /* Allocate a watchdog timer */ priv->timeout = wd_create(); @@ -571,7 +598,7 @@ void up_i2cuninitalize(struct lpc31_i2cdev_s *priv) { /* Disable All Interrupts, soft reset the device */ - i2c_reset(priv); + i2c_hwreset(priv); /* Detach Interrupt Handler */ diff --git a/arch/arm/src/lpc43xx/lpc43_i2c.c b/arch/arm/src/lpc43xx/lpc43_i2c.c index a831ec80d9a..065be78badd 100644 --- a/arch/arm/src/lpc43xx/lpc43_i2c.c +++ b/arch/arm/src/lpc43xx/lpc43_i2c.c @@ -135,6 +135,9 @@ 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); +#ifdef CONFIG_I2C_RESET +static int lpc43_i2c_reset(FAR struct i2c_master_s * dev); +#endif /**************************************************************************** * I2C device operations @@ -143,6 +146,9 @@ static int lpc43_i2c_transfer(FAR struct i2c_master_s *dev, struct i2c_ops_s lpc43_i2c_ops = { .transfer = lpc43_i2c_transfer +#ifdef CONFIG_I2C_RESET + , .reset = lpc43_i2c_reset +#endif }; /**************************************************************************** @@ -239,49 +245,6 @@ static void lpc43_i2c_timeout(int argc, uint32_t arg, ...) irqrestore(flags); } -/**************************************************************************** - * Name: lpc43_i2c_transfer - * - * Description: - * Perform a sequence of I2C transfers - * - ****************************************************************************/ - -static int lpc43_i2c_transfer(FAR struct i2c_master_s *dev, - FAR struct i2c_msg_s *msgs, int count) -{ - struct lpc43_i2cdev_s *priv = (struct lpc43_i2cdev_s *)dev; - int ret; - - 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; -} - /**************************************************************************** * Name: lpc32_i2c_nextmsg * @@ -419,6 +382,70 @@ static int lpc43_i2c_interrupt(int irq, FAR void *context) return OK; } +/**************************************************************************** + * Name: lpc43_i2c_transfer + * + * Description: + * Perform a sequence of I2C transfers + * + ****************************************************************************/ + +static int lpc43_i2c_transfer(FAR struct i2c_master_s *dev, + FAR struct i2c_msg_s *msgs, int count) +{ + struct lpc43_i2cdev_s *priv = (struct lpc43_i2cdev_s *)dev; + int ret; + + 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; +} + +/************************************************************************************ + * Name: lpc43_i2c_reset + * + * Description: + * Perform an I2C bus reset in an attempt to break loose stuck I2C devices. + * + * Input Parameters: + * dev - Device-specific state data + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + ************************************************************************************/ + +#ifdef CONFIG_I2C_RESET +static int lpc43_i2c_reset(FAR struct i2c_master_s * dev) +{ + return OK; +} +#endif /* CONFIG_I2C_RESET */ + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -552,19 +579,4 @@ int up_i2cuninitialize(FAR struct i2c_master_s * dev) return OK; } -/**************************************************************************** - * Name: up_i2creset - * - * Description: - * Reset an I2C bus - * - ****************************************************************************/ - -#ifdef CONFIG_I2C_RESET -int up_i2creset(FAR struct i2c_master_s * dev) -{ - return OK; -} -#endif /* CONFIG_I2C_RESET */ - #endif /* CONFIG_LPC43_I2C0 || CONFIG_LPC43_I2C1 */ diff --git a/arch/arm/src/sam34/sam_twi.c b/arch/arm/src/sam34/sam_twi.c index e0591fa295d..df906c5a952 100644 --- a/arch/arm/src/sam34/sam_twi.c +++ b/arch/arm/src/sam34/sam_twi.c @@ -170,14 +170,14 @@ static inline void twi_putrel(struct twi_dev_s *priv, unsigned int offset, /* I2C transfer helper functions */ -static int twi_wait(struct twi_dev_s *priv); +static int twi_wait(struct twi_dev_s *priv); static void twi_wakeup(struct twi_dev_s *priv, int result); -static int twi_interrupt(struct twi_dev_s *priv); +static int twi_interrupt(struct twi_dev_s *priv); #ifdef CONFIG_SAM34_TWI0 -static int twi0_interrupt(int irq, FAR void *context); +static int twi0_interrupt(int irq, FAR void *context); #endif #ifdef CONFIG_SAM34_TWI1 -static int twi1_interrupt(int irq, FAR void *context); +static int twi1_interrupt(int irq, FAR void *context); #endif static void twi_timeout(int argc, uint32_t arg, ...); @@ -189,6 +189,9 @@ static void twi_startmessage(struct twi_dev_s *priv, struct i2c_msg_s *msg); static int twi_transfer(FAR struct i2c_master_s *dev, FAR struct i2c_msg_s *msgs, int count); +#ifdef CONFIG_I2C_RESET +static int twi_reset(FAR struct i2c_master_s * dev); +#endif /* Initialization */ @@ -211,6 +214,9 @@ static struct twi_dev_s g_twi1; struct i2c_ops_s g_twiops = { .transfer = twi_transfer +#ifdef CONFIG_I2C_RESET + , .reset = twi_reset +#endif }; /**************************************************************************** @@ -744,6 +750,27 @@ static int twi_transfer(FAR struct i2c_master_s *dev, return ret; } +/************************************************************************************ + * Name: twi_reset + * + * Description: + * Perform an I2C bus reset in an attempt to break loose stuck I2C devices. + * + * Input Parameters: + * dev - Device-specific state data + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + ************************************************************************************/ + +#ifdef CONFIG_I2C_RESET +static int twi_reset(FAR struct i2c_master_s * dev) +{ + return OK; +} +#endif /* CONFIG_I2C_RESET */ + /**************************************************************************** * Initialization ****************************************************************************/ diff --git a/arch/arm/src/sama5/sam_twi.c b/arch/arm/src/sama5/sam_twi.c index 3f82c2011f2..cb78f2b1e2b 100644 --- a/arch/arm/src/sama5/sam_twi.c +++ b/arch/arm/src/sama5/sam_twi.c @@ -234,6 +234,9 @@ static void twi_startmessage(struct twi_dev_s *priv, struct i2c_msg_s *msg); static int twi_transfer(FAR struct i2c_master_s *dev, FAR struct i2c_msg_s *msgs, int count); +#ifdef CONFIG_I2C_RESET +static int twi_reset(FAR struct i2c_master_s * dev); +#endif /* Initialization */ @@ -307,6 +310,9 @@ static struct twi_dev_s g_twi3; struct i2c_ops_s g_twiops = { .transfer = twi_transfer +#ifdef CONFIG_I2C_RESET + , .reset = twi_reset +#endif }; /**************************************************************************** @@ -889,6 +895,140 @@ static int twi_transfer(FAR struct i2c_master_s *dev, return ret; } +/************************************************************************************ + * Name: twi_reset + * + * Description: + * Perform an I2C bus reset in an attempt to break loose stuck I2C devices. + * + * Input Parameters: + * dev - Device-specific state data + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + ************************************************************************************/ + +#ifdef CONFIG_I2C_RESET +static int twi_reset(FAR struct i2c_master_s *dev) +{ + struct twi_dev_s *priv = (struct twi_dev_s *)dev; + unsigned int clockcnt; + unsigned int stretchcnt; + uint32_t sclpin; + uint32_t sdapin; + int ret; + + ASSERT(priv); + + /* Get exclusive access to the TWI device */ + + twi_takesem(&priv->exclsem); + + /* Disable TWI interrupts */ + + up_disable_irq(priv->attr->irq); + + /* Use PIO configuration to un-wedge the bus. + * + * Reconfigure both pins as open drain outputs with initial output value + * "high" (i.e., floating since these are open-drain outputs). + */ + + sclpin = MKI2C_OUTPUT(priv->attr->sclcfg); + sdapin = MKI2C_OUTPUT(priv->attr->sdacfg); + + sam_configpio(sclpin); + sam_configpio(sdapin); + + /* Peripheral clocking must be enabled in order to read valid data from + * the output pin (clocking is enabled automatically for pins configured + * as inputs). + */ + + sam_pio_forceclk(sclpin, true); + sam_pio_forceclk(sdapin, true); + + /* Clock the bus until any slaves currently driving it low let it float. + * Reading from the output will return the actual sensed level on the + * SDA pin (not the level that we wrote). + */ + + clockcnt = 0; + while (sam_pioread(sdapin) == false) + { + /* Give up if we have tried too hard */ + + if (clockcnt++ > 10) + { + ret = -ETIMEDOUT; + goto errout_with_lock; + } + + /* Sniff to make sure that clock stretching has finished. SCL should + * be floating high here unless something is driving it low. + * + * If the bus never relaxes, the reset has failed. + */ + + stretchcnt = 0; + while (sam_pioread(sclpin) == false) + { + /* Give up if we have tried too hard */ + + if (stretchcnt++ > 10) + { + ret = -EAGAIN; + goto errout_with_lock; + } + + up_udelay(10); + } + + /* Drive SCL low */ + + sam_piowrite(sclpin, false); + up_udelay(10); + + /* Drive SCL high (floating) again */ + + sam_piowrite(sclpin, true); + up_udelay(10); + } + + /* Generate a start followed by a stop to reset slave + * state machines. + */ + + sam_piowrite(sdapin, false); + up_udelay(10); + sam_piowrite(sclpin, false); + up_udelay(10); + + sam_piowrite(sclpin, true); + up_udelay(10); + sam_piowrite(sdapin, true); + up_udelay(10); + + /* Clocking is no longer forced */ + + sam_pio_forceclk(sclpin, false); + sam_pio_forceclk(sdapin, false); + + /* Re-initialize the port hardware */ + + twi_hw_initialize(priv, priv->frequency); + ret = OK; + +errout_with_lock: + + /* Release our lock on the bus */ + + twi_givesem(&priv->exclsem); + return ret; +} +#endif /* CONFIG_I2C_RESET */ + /**************************************************************************** * Initialization ****************************************************************************/ @@ -1228,131 +1368,4 @@ int up_i2cuninitialize(FAR struct i2c_master_s *dev) return OK; } -/************************************************************************************ - * Name: up_i2creset - * - * Description: - * Reset an I2C bus - * - ************************************************************************************/ - -#ifdef CONFIG_I2C_RESET -int up_i2creset(FAR struct i2c_master_s *dev) -{ - struct twi_dev_s *priv = (struct twi_dev_s *)dev; - unsigned int clockcnt; - unsigned int stretchcnt; - uint32_t sclpin; - uint32_t sdapin; - int ret; - - ASSERT(priv); - - /* Get exclusive access to the TWI device */ - - twi_takesem(&priv->exclsem); - - /* Disable TWI interrupts */ - - up_disable_irq(priv->attr->irq); - - /* Use PIO configuration to un-wedge the bus. - * - * Reconfigure both pins as open drain outputs with initial output value - * "high" (i.e., floating since these are open-drain outputs). - */ - - sclpin = MKI2C_OUTPUT(priv->attr->sclcfg); - sdapin = MKI2C_OUTPUT(priv->attr->sdacfg); - - sam_configpio(sclpin); - sam_configpio(sdapin); - - /* Peripheral clocking must be enabled in order to read valid data from - * the output pin (clocking is enabled automatically for pins configured - * as inputs). - */ - - sam_pio_forceclk(sclpin, true); - sam_pio_forceclk(sdapin, true); - - /* Clock the bus until any slaves currently driving it low let it float. - * Reading from the output will return the actual sensed level on the - * SDA pin (not the level that we wrote). - */ - - clockcnt = 0; - while (sam_pioread(sdapin) == false) - { - /* Give up if we have tried too hard */ - - if (clockcnt++ > 10) - { - ret = -ETIMEDOUT; - goto errout_with_lock; - } - - /* Sniff to make sure that clock stretching has finished. SCL should - * be floating high here unless something is driving it low. - * - * If the bus never relaxes, the reset has failed. - */ - - stretchcnt = 0; - while (sam_pioread(sclpin) == false) - { - /* Give up if we have tried too hard */ - - if (stretchcnt++ > 10) - { - ret = -EAGAIN; - goto errout_with_lock; - } - - up_udelay(10); - } - - /* Drive SCL low */ - - sam_piowrite(sclpin, false); - up_udelay(10); - - /* Drive SCL high (floating) again */ - - sam_piowrite(sclpin, true); - up_udelay(10); - } - - /* Generate a start followed by a stop to reset slave - * state machines. - */ - - sam_piowrite(sdapin, false); - up_udelay(10); - sam_piowrite(sclpin, false); - up_udelay(10); - - sam_piowrite(sclpin, true); - up_udelay(10); - sam_piowrite(sdapin, true); - up_udelay(10); - - /* Clocking is no longer forced */ - - sam_pio_forceclk(sclpin, false); - sam_pio_forceclk(sdapin, false); - - /* Re-initialize the port hardware */ - - twi_hw_initialize(priv, priv->frequency); - ret = OK; - -errout_with_lock: - - /* Release our lock on the bus */ - - twi_givesem(&priv->exclsem); - return ret; -} -#endif /* CONFIG_I2C_RESET */ #endif /* CONFIG_SAMA5_TWI0 || ... || CONFIG_SAMA5_TWI3 */ diff --git a/arch/arm/src/samv7/sam_twihs.c b/arch/arm/src/samv7/sam_twihs.c index 2dbddddc3cf..7ca134bfe9f 100644 --- a/arch/arm/src/samv7/sam_twihs.c +++ b/arch/arm/src/samv7/sam_twihs.c @@ -229,6 +229,9 @@ static void twi_startmessage(struct twi_dev_s *priv, struct i2c_msg_s *msg); static int twi_transfer(FAR struct i2c_master_s *dev, FAR struct i2c_msg_s *msgs, int count); +#ifdef CONFIG_I2C_RESET +static int twi_reset(FAR struct i2c_master_s * dev); +#endif /* Initialization */ @@ -287,6 +290,9 @@ static struct twi_dev_s g_twi2; struct i2c_ops_s g_twiops = { .transfer = twi_transfer +#ifdef CONFIG_I2C_RESET + , .reset = twi_reset +#endif }; /**************************************************************************** @@ -916,6 +922,140 @@ static int twi_transfer(FAR struct i2c_master_s *dev, return ret; } +/************************************************************************************ + * Name: twi_reset + * + * Description: + * Perform an I2C bus reset in an attempt to break loose stuck I2C devices. + * + * Input Parameters: + * dev - Device-specific state data + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + ************************************************************************************/ + +#ifdef CONFIG_I2C_RESET +static int twi_reset(FAR struct i2c_master_s *dev) +{ + struct twi_dev_s *priv = (struct twi_dev_s *)dev; + unsigned int clockcnt; + unsigned int stretchcnt; + uint32_t sclpin; + uint32_t sdapin; + int ret; + + ASSERT(priv); + + /* Get exclusive access to the TWIHS device */ + + twi_takesem(&priv->exclsem); + + /* Disable TWIHS interrupts */ + + up_disable_irq(priv->attr->irq); + + /* Use PIO configuration to un-wedge the bus. + * + * Reconfigure both pins as open drain outputs with initial output value + * "high" (i.e., floating since these are open-drain outputs). + */ + + sclpin = MKI2C_OUTPUT(priv->attr->sclcfg); + sdapin = MKI2C_OUTPUT(priv->attr->sdacfg); + + sam_configgpio(sclpin); + sam_configgpio(sdapin); + + /* Peripheral clocking must be enabled in order to read valid data from + * the output pin (clocking is enabled automatically for pins configured + * as inputs). + */ + + sam_pio_forceclk(sclpin, true); + sam_pio_forceclk(sdapin, true); + + /* Clock the bus until any slaves currently driving it low let it float. + * Reading from the output will return the actual sensed level on the + * SDA pin (not the level that we wrote). + */ + + clockcnt = 0; + while (sam_pioread(sdapin) == false) + { + /* Give up if we have tried too hard */ + + if (clockcnt++ > 10) + { + ret = -ETIMEDOUT; + goto errout_with_lock; + } + + /* Sniff to make sure that clock stretching has finished. SCL should + * be floating high here unless something is driving it low. + * + * If the bus never relaxes, the reset has failed. + */ + + stretchcnt = 0; + while (sam_pioread(sclpin) == false) + { + /* Give up if we have tried too hard */ + + if (stretchcnt++ > 10) + { + ret = -EAGAIN; + goto errout_with_lock; + } + + up_udelay(10); + } + + /* Drive SCL low */ + + sam_piowrite(sclpin, false); + up_udelay(10); + + /* Drive SCL high (floating) again */ + + sam_piowrite(sclpin, true); + up_udelay(10); + } + + /* Generate a start followed by a stop to reset slave + * state machines. + */ + + sam_piowrite(sdapin, false); + up_udelay(10); + sam_piowrite(sclpin, false); + up_udelay(10); + + sam_piowrite(sclpin, true); + up_udelay(10); + sam_piowrite(sdapin, true); + up_udelay(10); + + /* Clocking is no longer forced */ + + sam_pio_forceclk(sclpin, false); + sam_pio_forceclk(sdapin, false); + + /* Re-initialize the port hardware */ + + twi_hw_initialize(priv, priv->frequency); + ret = OK; + +errout_with_lock: + + /* Release our lock on the bus */ + + twi_givesem(&priv->exclsem); + return ret; +} +#endif /* CONFIG_I2C_RESET */ + /**************************************************************************** * Initialization ****************************************************************************/ @@ -1256,131 +1396,4 @@ int up_i2cuninitialize(FAR struct i2c_master_s *dev) return OK; } -/************************************************************************************ - * Name: up_i2creset - * - * Description: - * Reset an I2C bus - * - ************************************************************************************/ - -#ifdef CONFIG_I2C_RESET -int up_i2creset(FAR struct i2c_master_s *dev) -{ - struct twi_dev_s *priv = (struct twi_dev_s *)dev; - unsigned int clockcnt; - unsigned int stretchcnt; - uint32_t sclpin; - uint32_t sdapin; - int ret; - - ASSERT(priv); - - /* Get exclusive access to the TWIHS device */ - - twi_takesem(&priv->exclsem); - - /* Disable TWIHS interrupts */ - - up_disable_irq(priv->attr->irq); - - /* Use PIO configuration to un-wedge the bus. - * - * Reconfigure both pins as open drain outputs with initial output value - * "high" (i.e., floating since these are open-drain outputs). - */ - - sclpin = MKI2C_OUTPUT(priv->attr->sclcfg); - sdapin = MKI2C_OUTPUT(priv->attr->sdacfg); - - sam_configgpio(sclpin); - sam_configgpio(sdapin); - - /* Peripheral clocking must be enabled in order to read valid data from - * the output pin (clocking is enabled automatically for pins configured - * as inputs). - */ - - sam_pio_forceclk(sclpin, true); - sam_pio_forceclk(sdapin, true); - - /* Clock the bus until any slaves currently driving it low let it float. - * Reading from the output will return the actual sensed level on the - * SDA pin (not the level that we wrote). - */ - - clockcnt = 0; - while (sam_pioread(sdapin) == false) - { - /* Give up if we have tried too hard */ - - if (clockcnt++ > 10) - { - ret = -ETIMEDOUT; - goto errout_with_lock; - } - - /* Sniff to make sure that clock stretching has finished. SCL should - * be floating high here unless something is driving it low. - * - * If the bus never relaxes, the reset has failed. - */ - - stretchcnt = 0; - while (sam_pioread(sclpin) == false) - { - /* Give up if we have tried too hard */ - - if (stretchcnt++ > 10) - { - ret = -EAGAIN; - goto errout_with_lock; - } - - up_udelay(10); - } - - /* Drive SCL low */ - - sam_piowrite(sclpin, false); - up_udelay(10); - - /* Drive SCL high (floating) again */ - - sam_piowrite(sclpin, true); - up_udelay(10); - } - - /* Generate a start followed by a stop to reset slave - * state machines. - */ - - sam_piowrite(sdapin, false); - up_udelay(10); - sam_piowrite(sclpin, false); - up_udelay(10); - - sam_piowrite(sclpin, true); - up_udelay(10); - sam_piowrite(sdapin, true); - up_udelay(10); - - /* Clocking is no longer forced */ - - sam_pio_forceclk(sclpin, false); - sam_pio_forceclk(sdapin, false); - - /* Re-initialize the port hardware */ - - twi_hw_initialize(priv, priv->frequency); - ret = OK; - -errout_with_lock: - - /* Release our lock on the bus */ - - twi_givesem(&priv->exclsem); - return ret; -} -#endif /* CONFIG_I2C_RESET */ #endif /* CONFIG_SAMV7_TWIHS0 || CONFIG_SAMV7_TWIHS1 || CONFIG_SAMV7_TWIHS2 */ diff --git a/arch/arm/src/stm32/stm32_i2c.c b/arch/arm/src/stm32/stm32_i2c.c index 53b7f3536f5..77b7b979896 100644 --- a/arch/arm/src/stm32/stm32_i2c.c +++ b/arch/arm/src/stm32/stm32_i2c.c @@ -339,6 +339,9 @@ 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 int stm32_i2c_transfer(FAR struct i2c_master_s *dev, FAR struct i2c_msg_s *msgs, int count); +#ifdef CONFIG_I2C_RESET +static int stm32_i2c_reset(FAR struct i2c_master_s *dev); +#endif /************************************************************************************ * Private Data @@ -368,6 +371,9 @@ static const char *g_trace_names[] = static const struct i2c_ops_s stm32_i2c_ops = { .transfer = stm32_i2c_transfer +#ifdef CONFIG_I2C_RESET + , .reset = stm32_i2c_reset +#endif }; /* I2C device structures */ @@ -1801,122 +1807,21 @@ static int stm32_i2c_transfer(FAR struct i2c_master_s *dev, FAR struct i2c_msg_s } /************************************************************************************ - * Public Functions - ************************************************************************************/ - -/************************************************************************************ - * Name: up_i2cinitialize + * Name: stm32_i2c_reset * * Description: - * Initialize one I2C bus + * Perform an I2C bus reset in an attempt to break loose stuck I2C devices. * - ************************************************************************************/ - -FAR struct i2c_master_s *up_i2cinitialize(int port) -{ - struct stm32_i2c_priv_s * priv = NULL; - int irqs; - -#if STM32_PCLK1_FREQUENCY < 4000000 -# warning STM32_I2C_INIT: Peripheral clock must be at least 4 MHz to support 400 kHz operation. -#endif - -#if STM32_PCLK1_FREQUENCY < 2000000 -# warning STM32_I2C_INIT: Peripheral clock must be at least 2 MHz to support 100 kHz operation. - return NULL; -#endif - - /* Get I2C private structure */ - - switch (port) - { -#ifdef CONFIG_STM32_I2C1 - case 1: - priv = (struct stm32_i2c_priv_s *)&stm32_i2c1_priv; - break; -#endif -#ifdef CONFIG_STM32_I2C2 - case 2: - priv = (struct stm32_i2c_priv_s *)&stm32_i2c2_priv; - break; -#endif -#ifdef CONFIG_STM32_I2C3 - case 3: - priv = (struct stm32_i2c_priv_s *)&stm32_i2c3_priv; - break; -#endif - default: - return NULL; - } - - /* Initialize private data for the first time, increment reference count, - * power-up hardware and configure GPIOs. - */ - - irqs = irqsave(); - - if ((volatile int)priv->refs++ == 0) - { - stm32_i2c_sem_init(priv); - stm32_i2c_init(priv); - } - - irqrestore(irqs); - return (struct i2c_master_s *)priv; -} - -/************************************************************************************ - * Name: up_i2cuninitialize + * Input Parameters: + * dev - Device-specific state data * - * Description: - * Uninitialize an I2C bus - * - ************************************************************************************/ - -int up_i2cuninitialize(FAR struct i2c_master_s *dev) -{ - FAR struct stm32_i2c_priv_s *priv = (struct stm32_i2c_priv_s *)dev; - int irqs; - - ASSERT(dev); - - /* Decrement reference count and check for underflow */ - - if (priv->refs == 0) - { - return ERROR; - } - - irqs = irqsave(); - - if (--priv->refs) - { - irqrestore(irqs); - return OK; - } - - irqrestore(irqs); - - /* Disable power and other HW resource (GPIO's) */ - - stm32_i2c_deinit(priv); - - /* Release unused resources */ - - stm32_i2c_sem_destroy(priv); - return OK; -} - -/************************************************************************************ - * Name: up_i2creset - * - * Description: - * Reset an I2C bus + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. * ************************************************************************************/ #ifdef CONFIG_I2C_RESET -int up_i2creset(FAR struct i2c_master_s *dev) +static int stm32_i2c_reset(FAR struct i2c_master_s *dev) { FAR struct stm32_i2c_priv_s *priv = (struct stm32_i2c_priv_s *)dev; unsigned int clock_count; @@ -2024,5 +1929,112 @@ out: } #endif /* CONFIG_I2C_RESET */ +/************************************************************************************ + * Public Functions + ************************************************************************************/ + +/************************************************************************************ + * Name: stm32_i2cbus_initialize + * + * Description: + * Initialize one I2C bus + * + ************************************************************************************/ + +FAR struct i2c_master_s *stm32_i2cbus_initialize(int port) +{ + struct stm32_i2c_priv_s * priv = NULL; + int irqs; + +#if STM32_PCLK1_FREQUENCY < 4000000 +# warning STM32_I2C_INIT: Peripheral clock must be at least 4 MHz to support 400 kHz operation. +#endif + +#if STM32_PCLK1_FREQUENCY < 2000000 +# warning STM32_I2C_INIT: Peripheral clock must be at least 2 MHz to support 100 kHz operation. + return NULL; +#endif + + /* Get I2C private structure */ + + switch (port) + { +#ifdef CONFIG_STM32_I2C1 + case 1: + priv = (struct stm32_i2c_priv_s *)&stm32_i2c1_priv; + break; +#endif +#ifdef CONFIG_STM32_I2C2 + case 2: + priv = (struct stm32_i2c_priv_s *)&stm32_i2c2_priv; + break; +#endif +#ifdef CONFIG_STM32_I2C3 + case 3: + priv = (struct stm32_i2c_priv_s *)&stm32_i2c3_priv; + break; +#endif + default: + return NULL; + } + + /* Initialize private data for the first time, increment reference count, + * power-up hardware and configure GPIOs. + */ + + irqs = irqsave(); + + if ((volatile int)priv->refs++ == 0) + { + stm32_i2c_sem_init(priv); + stm32_i2c_init(priv); + } + + irqrestore(irqs); + return (struct i2c_master_s *)priv; +} + +/************************************************************************************ + * Name: stm32_i2cbus_uninitialize + * + * Description: + * Uninitialize an I2C bus + * + ************************************************************************************/ + +int stm32_i2cbus_uninitialize(FAR struct i2c_master_s *dev) +{ + FAR struct stm32_i2c_priv_s *priv = (struct stm32_i2c_priv_s *)dev; + int irqs; + + ASSERT(dev); + + /* Decrement reference count and check for underflow */ + + if (priv->refs == 0) + { + return ERROR; + } + + irqs = irqsave(); + + if (--priv->refs) + { + irqrestore(irqs); + return OK; + } + + irqrestore(irqs); + + /* Disable power and other HW resource (GPIO's) */ + + stm32_i2c_deinit(priv); + + /* Release unused resources */ + + stm32_i2c_sem_destroy(priv); + return OK; +} + #endif /* CONFIG_STM32_STM32F10XX || CONFIG_STM32_STM32F20XX || CONFIG_STM32_STM32F40XX */ #endif /* CONFIG_STM32_I2C1 || CONFIG_STM32_I2C2 || CONFIG_STM32_I2C3 */ diff --git a/arch/arm/src/stm32/stm32_i2c.h b/arch/arm/src/stm32/stm32_i2c.h index 8fd836cd239..2dc97303b3b 100644 --- a/arch/arm/src/stm32/stm32_i2c.h +++ b/arch/arm/src/stm32/stm32_i2c.h @@ -65,5 +65,41 @@ # include "chip/stm32_i2c.h" #endif +/**************************************************************************** + * Name: stm32_i2cbus_initialize + * + * Description: + * Initialize the selected I2C port. And return a unique instance of struct + * struct i2c_master_s. This function may be called to obtain multiple + * instances of the interface, each of which may be set up with a + * different frequency and slave address. + * + * Input Parameter: + * Port number (for hardware that has multiple I2C interfaces) + * + * Returned Value: + * Valid I2C device structure reference on succcess; a NULL on failure + * + ****************************************************************************/ + +FAR struct i2c_master_s *stm32_i2cbus_initialize(int port); + +/**************************************************************************** + * Name: stm32_i2cbus_uninitialize + * + * Description: + * De-initialize the selected I2C port, and power down the device. + * + * Input Parameter: + * Device structure as returned by the stm32_i2cbus_initialize() + * + * Returned Value: + * OK on success, ERROR when internal reference count mismatch or dev + * points to invalid hardware device. + * + ****************************************************************************/ + +int stm32_i2cbus_uninitialize(FAR struct i2c_master_s *dev); + #endif /* __ARCH_ARM_SRC_STM32_STM32_I2C_H */ diff --git a/arch/arm/src/stm32/stm32_i2c_alt.c b/arch/arm/src/stm32/stm32_i2c_alt.c index 343c90ecb36..8e9c5a799d8 100644 --- a/arch/arm/src/stm32/stm32_i2c_alt.c +++ b/arch/arm/src/stm32/stm32_i2c_alt.c @@ -368,6 +368,9 @@ 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 int stm32_i2c_transfer(FAR struct i2c_master_s *dev, FAR struct i2c_msg_s *msgs, int count); +#ifdef CONFIG_I2C_RESET +static int stm32_i2c_reset(FAR struct i2c_master_s *dev); +#endif /************************************************************************************ * Private Data @@ -378,6 +381,9 @@ static int stm32_i2c_transfer(FAR struct i2c_master_s *dev, FAR struct i2c_msg_s static const struct i2c_ops_s stm32_i2c_ops = { .transfer = stm32_i2c_transfer +#ifdef CONFIG_I2C_RESET + , .reset = stm32_i2c_reset +#endif }; #ifdef CONFIG_STM32_I2C1 @@ -2249,122 +2255,21 @@ static int stm32_i2c_transfer(FAR struct i2c_master_s *dev, FAR struct i2c_msg_s } /************************************************************************************ - * Public Functions - ************************************************************************************/ - -/************************************************************************************ - * Name: up_i2cinitialize + * Name: stm32_i2c_reset * * Description: - * Initialize one I2C bus + * Perform an I2C bus reset in an attempt to break loose stuck I2C devices. * - ************************************************************************************/ - -FAR struct i2c_master_s *up_i2cinitialize(int port) -{ - struct stm32_i2c_priv_s *priv = NULL; - int irqs; - -#if STM32_PCLK1_FREQUENCY < 4000000 -# warning STM32_I2C_INIT: Peripheral clock must be at least 4 MHz to support 400 kHz operation. -#endif - -#if STM32_PCLK1_FREQUENCY < 2000000 -# warning STM32_I2C_INIT: Peripheral clock must be at least 2 MHz to support 100 kHz operation. - return NULL; -#endif - - /* Get I2C private structure */ - - switch (port) - { -#ifdef CONFIG_STM32_I2C1 - case 1: - priv = (struct stm32_i2c_priv_s *)&stm32_i2c1_priv; - break; -#endif -#ifdef CONFIG_STM32_I2C2 - case 2: - priv = (struct stm32_i2c_priv_s *)&stm32_i2c2_priv; - break; -#endif -#ifdef CONFIG_STM32_I2C3 - case 3: - priv = (struct stm32_i2c_priv_s *)&stm32_i2c3_priv; - break; -#endif - default: - return NULL; - } - - /* Initialize private data for the first time, increment reference count, - * power-up hardware and configure GPIOs. - */ - - irqs = irqsave(); - - if ((volatile int)priv->refs++ == 0) - { - stm32_i2c_sem_init(priv); - stm32_i2c_init(priv); - } - - irqrestore(irqs); - return (struct i2c_master_s *)priv; -} - -/************************************************************************************ - * Name: up_i2cuninitialize + * Input Parameters: + * dev - Device-specific state data * - * Description: - * Uninitialize an I2C bus - * - ************************************************************************************/ - -int up_i2cuninitialize(FAR struct i2c_master_s *dev) -{ - FAR struct stm32_i2c_priv_s *priv = (FAR struct stm32_i2c_priv_s *)dev; - int irqs; - - ASSERT(dev); - - /* Decrement reference count and check for underflow */ - - if (priv->refs == 0) - { - return ERROR; - } - - irqs = irqsave(); - - if (--priv->refs) - { - irqrestore(irqs); - return OK; - } - - irqrestore(irqs); - - /* Disable power and other HW resource (GPIO's) */ - - stm32_i2c_deinit(priv); - - /* Release unused resources */ - - stm32_i2c_sem_destroy(priv); - return OK; -} - -/************************************************************************************ - * Name: up_i2creset - * - * Description: - * Reset an I2C bus + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. * ************************************************************************************/ #ifdef CONFIG_I2C_RESET -int up_i2creset(FAR struct i2c_master_s * dev) +static int stm32_i2c_reset(FAR struct i2c_master_s * dev) { FAR struct stm32_i2c_priv_s *priv = (FAR struct stm32_i2c_priv_s *)dev; unsigned int clock_count; @@ -2469,5 +2374,112 @@ out: } #endif /* CONFIG_I2C_RESET */ +/************************************************************************************ + * Public Functions + ************************************************************************************/ + +/************************************************************************************ + * Name: stm32_i2cbus_initialize + * + * Description: + * Initialize one I2C bus + * + ************************************************************************************/ + +FAR struct i2c_master_s *stm32_i2cbus_initialize(int port) +{ + struct stm32_i2c_priv_s *priv = NULL; + int irqs; + +#if STM32_PCLK1_FREQUENCY < 4000000 +# warning STM32_I2C_INIT: Peripheral clock must be at least 4 MHz to support 400 kHz operation. +#endif + +#if STM32_PCLK1_FREQUENCY < 2000000 +# warning STM32_I2C_INIT: Peripheral clock must be at least 2 MHz to support 100 kHz operation. + return NULL; +#endif + + /* Get I2C private structure */ + + switch (port) + { +#ifdef CONFIG_STM32_I2C1 + case 1: + priv = (struct stm32_i2c_priv_s *)&stm32_i2c1_priv; + break; +#endif +#ifdef CONFIG_STM32_I2C2 + case 2: + priv = (struct stm32_i2c_priv_s *)&stm32_i2c2_priv; + break; +#endif +#ifdef CONFIG_STM32_I2C3 + case 3: + priv = (struct stm32_i2c_priv_s *)&stm32_i2c3_priv; + break; +#endif + default: + return NULL; + } + + /* Initialize private data for the first time, increment reference count, + * power-up hardware and configure GPIOs. + */ + + irqs = irqsave(); + + if ((volatile int)priv->refs++ == 0) + { + stm32_i2c_sem_init(priv); + stm32_i2c_init(priv); + } + + irqrestore(irqs); + return (struct i2c_master_s *)priv; +} + +/************************************************************************************ + * Name: stm32_i2cbus_uninitialize + * + * Description: + * Uninitialize an I2C bus + * + ************************************************************************************/ + +int stm32_i2cbus_uninitialize(FAR struct i2c_master_s *dev) +{ + FAR struct stm32_i2c_priv_s *priv = (FAR struct stm32_i2c_priv_s *)dev; + int irqs; + + ASSERT(dev); + + /* Decrement reference count and check for underflow */ + + if (priv->refs == 0) + { + return ERROR; + } + + irqs = irqsave(); + + if (--priv->refs) + { + irqrestore(irqs); + return OK; + } + + irqrestore(irqs); + + /* Disable power and other HW resource (GPIO's) */ + + stm32_i2c_deinit(priv); + + /* Release unused resources */ + + stm32_i2c_sem_destroy(priv); + return OK; +} + #endif /* CONFIG_STM32_STM32F10XX || CONFIG_STM32_STM32F20XX || CONFIG_STM32_STM32F40XX */ #endif /* CONFIG_STM32_I2C1 || CONFIG_STM32_I2C2 || CONFIG_STM32_I2C3 */ diff --git a/arch/arm/src/stm32/stm32f30xxx_i2c.c b/arch/arm/src/stm32/stm32f30xxx_i2c.c index 120c318c731..a66a3c4e5f4 100644 --- a/arch/arm/src/stm32/stm32f30xxx_i2c.c +++ b/arch/arm/src/stm32/stm32f30xxx_i2c.c @@ -325,6 +325,9 @@ 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 int stm32_i2c_transfer(FAR struct i2c_master_s *dev, FAR struct i2c_msg_s *msgs, int count); +#ifdef CONFIG_I2C_RESET +static int stm32_i2c_reset(FAR struct i2c_master_s *dev); +#endif /************************************************************************************ * Private Data @@ -335,6 +338,9 @@ static int stm32_i2c_transfer(FAR struct i2c_master_s *dev, FAR struct i2c_msg_s const struct i2c_ops_s stm32_i2c_ops = { .transfer = stm32_i2c_transfer +#ifdef CONFIG_I2C_RESET + , .reset = stm32_i2c_reset +#endif }; #ifdef CONFIG_STM32_I2C1 @@ -1806,122 +1812,21 @@ static int stm32_i2c_transfer(FAR struct i2c_master_s *dev, FAR struct i2c_msg_s } /************************************************************************************ - * Public Functions - ************************************************************************************/ - -/************************************************************************************ - * Name: up_i2cinitialize + * Name: stm32_i2c_reset * * Description: - * Initialize one I2C bus + * Perform an I2C bus reset in an attempt to break loose stuck I2C devices. * - ************************************************************************************/ - -FAR struct i2c_master_s *up_i2cinitialize(int port) -{ - struct stm32_i2c_priv_s * priv = NULL; /* private data of device with multiple instances */ - int irqs; - -#if STM32_PCLK1_FREQUENCY < 4000000 -# warning STM32_I2C_INIT: Peripheral clock must be at least 4 MHz to support 400 kHz operation. -#endif - -#if STM32_PCLK1_FREQUENCY < 2000000 -# warning STM32_I2C_INIT: Peripheral clock must be at least 2 MHz to support 100 kHz operation. - return NULL; -#endif - - /* Get I2C private structure */ - - switch (port) - { -#ifdef CONFIG_STM32_I2C1 - case 1: - priv = (struct stm32_i2c_priv_s *)&stm32_i2c1_priv; - break; -#endif -#ifdef CONFIG_STM32_I2C2 - case 2: - priv = (struct stm32_i2c_priv_s *)&stm32_i2c2_priv; - break; -#endif -#ifdef CONFIG_STM32_I2C3 - case 3: - priv = (struct stm32_i2c_priv_s *)&stm32_i2c3_priv; - break; -#endif - default: - return NULL; - } - - /* Init private data for the first time, increment refs count, - * power-up hardware and configure GPIOs. - */ - - irqs = irqsave(); - - if ((volatile int)priv->refs++ == 0) - { - stm32_i2c_sem_init(priv); - stm32_i2c_init(priv); - } - - irqrestore(irqs); - return (struct i2c_master_s *)priv; -} - -/************************************************************************************ - * Name: up_i2cuninitialize + * Input Parameters: + * dev - Device-specific state data * - * Description: - * Uninitialize an I2C bus - * - ************************************************************************************/ - -int up_i2cuninitialize(FAR struct i2c_master_s * dev) -{ - FAR struct stm32_i2c_priv_s *priv = (struct stm32_i2c_priv_s *)dev; - int irqs; - - ASSERT(dev); - - /* Decrement refs and check for underflow */ - - if (priv->refs == 0) - { - return ERROR; - } - - irqs = irqsave(); - - if (--priv->refs) - { - irqrestore(irqs); - return OK; - } - - irqrestore(irqs); - - /* Disable power and other HW resource (GPIO's) */ - - stm32_i2c_deinit(priv); - - /* Release unused resources */ - - stm32_i2c_sem_destroy(priv); - return OK; -} - -/************************************************************************************ - * Name: up_i2creset - * - * Description: - * Reset an I2C bus + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. * ************************************************************************************/ #ifdef CONFIG_I2C_RESET -int up_i2creset(FAR struct i2c_master_s * dev) +static int stm32_i2c_reset(FAR struct i2c_master_s * dev) { unsigned int clock_count; unsigned int stretch_count; @@ -2025,5 +1930,112 @@ out: } #endif /* CONFIG_I2C_RESET */ +/************************************************************************************ + * Public Functions + ************************************************************************************/ + +/************************************************************************************ + * Name: stm32_i2cbus_initialize + * + * Description: + * Initialize one I2C bus + * + ************************************************************************************/ + +FAR struct i2c_master_s *stm32_i2cbus_initialize(int port) +{ + struct stm32_i2c_priv_s * priv = NULL; /* private data of device with multiple instances */ + int irqs; + +#if STM32_PCLK1_FREQUENCY < 4000000 +# warning STM32_I2C_INIT: Peripheral clock must be at least 4 MHz to support 400 kHz operation. +#endif + +#if STM32_PCLK1_FREQUENCY < 2000000 +# warning STM32_I2C_INIT: Peripheral clock must be at least 2 MHz to support 100 kHz operation. + return NULL; +#endif + + /* Get I2C private structure */ + + switch (port) + { +#ifdef CONFIG_STM32_I2C1 + case 1: + priv = (struct stm32_i2c_priv_s *)&stm32_i2c1_priv; + break; +#endif +#ifdef CONFIG_STM32_I2C2 + case 2: + priv = (struct stm32_i2c_priv_s *)&stm32_i2c2_priv; + break; +#endif +#ifdef CONFIG_STM32_I2C3 + case 3: + priv = (struct stm32_i2c_priv_s *)&stm32_i2c3_priv; + break; +#endif + default: + return NULL; + } + + /* Init private data for the first time, increment refs count, + * power-up hardware and configure GPIOs. + */ + + irqs = irqsave(); + + if ((volatile int)priv->refs++ == 0) + { + stm32_i2c_sem_init(priv); + stm32_i2c_init(priv); + } + + irqrestore(irqs); + return (struct i2c_master_s *)priv; +} + +/************************************************************************************ + * Name: stm32_i2cbus_uninitialize + * + * Description: + * Uninitialize an I2C bus + * + ************************************************************************************/ + +int stm32_i2cbus_uninitialize(FAR struct i2c_master_s * dev) +{ + FAR struct stm32_i2c_priv_s *priv = (struct stm32_i2c_priv_s *)dev; + int irqs; + + ASSERT(dev); + + /* Decrement refs and check for underflow */ + + if (priv->refs == 0) + { + return ERROR; + } + + irqs = irqsave(); + + if (--priv->refs) + { + irqrestore(irqs); + return OK; + } + + irqrestore(irqs); + + /* Disable power and other HW resource (GPIO's) */ + + stm32_i2c_deinit(priv); + + /* Release unused resources */ + + stm32_i2c_sem_destroy(priv); + return OK; +} + #endif /* CONFIG_STM32_STM32F30XX */ #endif /* CONFIG_STM32_I2C1 || CONFIG_STM32_I2C2 || CONFIG_STM32_I2C3 */ diff --git a/arch/arm/src/tiva/tiva_i2c.c b/arch/arm/src/tiva/tiva_i2c.c index 21ed5231cd6..70e4bd18f3b 100644 --- a/arch/arm/src/tiva/tiva_i2c.c +++ b/arch/arm/src/tiva/tiva_i2c.c @@ -330,6 +330,9 @@ static int tiva_i2c_uninitialize(struct tiva_i2c_priv_s *priv); static void tiva_i2c_setclock(struct tiva_i2c_priv_s *priv, uint32_t frequency); static int tiva_i2c_transfer(struct i2c_master_s *dev, struct i2c_msg_s *msgv, int msgc); +#ifdef CONFIG_I2C_RESET +static int tiva_i2c_reset(FAR struct i2c_master_s *dev); +#endif /************************************************************************************ * Private Data @@ -340,6 +343,9 @@ static int tiva_i2c_transfer(struct i2c_master_s *dev, struct i2c_msg_s *msgv, static const struct i2c_ops_s tiva_i2c_ops = { .transfer = tiva_i2c_transfer +#ifdef CONFIG_I2C_RESET + , .reset = tiva_i2c_reset +#endif }; #ifdef CONFIG_TIVA_I2C0 @@ -1996,6 +2002,130 @@ static int tiva_i2c_transfer(struct i2c_master_s *dev, struct i2c_msg_s *msgv, return ret; } +/************************************************************************************ + * Name: tiva_i2c_reset + * + * Description: + * Perform an I2C bus reset in an attempt to break loose stuck I2C devices. + * + * Input Parameters: + * dev - Device-specific state data + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + ************************************************************************************/ + +#ifdef CONFIG_I2C_RESET +static int tiva_i2c_reset(FAR struct i2c_master_s * dev) +{ + struct tiva_i2c_priv_s *priv = (struct tiva_i2c_priv_s *)dev; + unsigned int clock_count; + unsigned int stretch_count; + uint32_t scl_gpio; + uint32_t sda_gpio; + int ret = ERROR; + + DEBUGASSERT(priv && priv->config); + i2cvdbg("I2C%d:\n", priv->config->devno); + + /* Our caller must own a ref */ + + ASSERT(priv->refs > 0); + + /* Lock out other clients */ + + tiva_i2c_sem_wait(priv); + + /* Un-initialize the port */ + + tiva_i2c_uninitialize(priv); + + /* Use GPIO configuration to un-wedge the bus */ + + scl_gpio = MKI2C_OUTPUT(priv->config->scl_pin); + sda_gpio = MKI2C_OUTPUT(priv->config->sda_pin); + + tiva_configgpio(scl_gpio); + tiva_configgpio(sda_gpio); + + /* Let SDA go high */ + + tiva_gpiowrite(sda_gpio, 1); + + /* Clock the bus until any slaves currently driving it let it go. */ + + clock_count = 0; + while (!tiva_gpioread(sda_gpio)) + { + /* Give up if we have tried too hard */ + + if (clock_count++ > 10) + { + goto out; + } + + /* Sniff to make sure that clock stretching has finished. + * + * If the bus never relaxes, the reset has failed. + */ + + stretch_count = 0; + while (!tiva_gpioread(scl_gpio)) + { + /* Give up if we have tried too hard */ + + if (stretch_count++ > 10) + { + goto out; + } + + up_udelay(10); + } + + /* Drive SCL low */ + + tiva_gpiowrite(scl_gpio, 0); + up_udelay(10); + + /* Drive SCL high again */ + + tiva_gpiowrite(scl_gpio, 1); + up_udelay(10); + } + + /* Generate a start followed by a stop to reset slave + * state machines. + */ + + tiva_gpiowrite(sda_gpio, 0); + up_udelay(10); + tiva_gpiowrite(scl_gpio, 0); + up_udelay(10); + tiva_gpiowrite(scl_gpio, 1); + up_udelay(10); + tiva_gpiowrite(sda_gpio, 1); + up_udelay(10); + + /* Revert the GPIO configuration. */ + + tiva_configgpio(MKI2C_INPUT(sda_gpio)); + tiva_configgpio(MKI2C_INPUT(scl_gpio)); + + /* Re-init the port */ + + tiva_i2c_initialize(priv, priv->frequency); + ret = OK; + +out: + + /* Release the port for re-use by other clients */ + + tiva_i2c_sem_post(priv); + return ret; +} +#endif /* CONFIG_I2C_RESET */ + /************************************************************************************ * Public Functions ************************************************************************************/ @@ -2167,122 +2297,4 @@ int up_i2cuninitialize(struct i2c_master_s *dev) return OK; } -/************************************************************************************ - * Name: up_i2creset - * - * Description: - * Reset an I2C bus - * - ************************************************************************************/ - -#ifdef CONFIG_I2C_RESET -int up_i2creset(struct i2c_master_s *dev) -{ - struct tiva_i2c_priv_s *priv = (struct tiva_i2c_priv_s *)dev; - unsigned int clock_count; - unsigned int stretch_count; - uint32_t scl_gpio; - uint32_t sda_gpio; - int ret = ERROR; - - DEBUGASSERT(priv && priv->config); - i2cvdbg("I2C%d:\n", priv->config->devno); - - /* Our caller must own a ref */ - - ASSERT(priv->refs > 0); - - /* Lock out other clients */ - - tiva_i2c_sem_wait(priv); - - /* Un-initialize the port */ - - tiva_i2c_uninitialize(priv); - - /* Use GPIO configuration to un-wedge the bus */ - - scl_gpio = MKI2C_OUTPUT(priv->config->scl_pin); - sda_gpio = MKI2C_OUTPUT(priv->config->sda_pin); - - tiva_configgpio(scl_gpio); - tiva_configgpio(sda_gpio); - - /* Let SDA go high */ - - tiva_gpiowrite(sda_gpio, 1); - - /* Clock the bus until any slaves currently driving it let it go. */ - - clock_count = 0; - while (!tiva_gpioread(sda_gpio)) - { - /* Give up if we have tried too hard */ - - if (clock_count++ > 10) - { - goto out; - } - - /* Sniff to make sure that clock stretching has finished. - * - * If the bus never relaxes, the reset has failed. - */ - - stretch_count = 0; - while (!tiva_gpioread(scl_gpio)) - { - /* Give up if we have tried too hard */ - - if (stretch_count++ > 10) - { - goto out; - } - - up_udelay(10); - } - - /* Drive SCL low */ - - tiva_gpiowrite(scl_gpio, 0); - up_udelay(10); - - /* Drive SCL high again */ - - tiva_gpiowrite(scl_gpio, 1); - up_udelay(10); - } - - /* Generate a start followed by a stop to reset slave - * state machines. - */ - - tiva_gpiowrite(sda_gpio, 0); - up_udelay(10); - tiva_gpiowrite(scl_gpio, 0); - up_udelay(10); - tiva_gpiowrite(scl_gpio, 1); - up_udelay(10); - tiva_gpiowrite(sda_gpio, 1); - up_udelay(10); - - /* Revert the GPIO configuration. */ - - tiva_configgpio(MKI2C_INPUT(sda_gpio)); - tiva_configgpio(MKI2C_INPUT(scl_gpio)); - - /* Re-init the port */ - - tiva_i2c_initialize(priv, priv->frequency); - ret = OK; - -out: - - /* Release the port for re-use by other clients */ - - tiva_i2c_sem_post(priv); - return ret; -} -#endif /* CONFIG_I2C_RESET */ - #endif /* CONFIG_TIVA_I2C0 ... CONFIG_TIVA_I2C9 */ diff --git a/arch/z80/src/ez80/ez80_i2c.c b/arch/z80/src/ez80/ez80_i2c.c index ee6684366a9..22c4d2409d5 100644 --- a/arch/z80/src/ez80/ez80_i2c.c +++ b/arch/z80/src/ez80/ez80_i2c.c @@ -99,6 +99,9 @@ static void ez80_i2c_setfrequency(FAR struct ez80_i2cdev_s *priv, static int ez80_i2c_transfer(FAR struct i2c_master_s *dev, FAR struct i2c_msg_s *msgs, int count); +#ifdef CONFIG_I2C_RESET +static int ez80_i2c_reset(FAR struct i2c_master_s *dev); +#endif /**************************************************************************** * Public Function Prototypes @@ -118,6 +121,9 @@ static sem_t g_i2csem; /* Serialize I2C transfers */ const struct i2c_ops_s g_ops = { ez80_i2c_transfer +#ifdef CONFIG_I2C_RESET + , ez80_i2c_reset +#endif }; /**************************************************************************** @@ -910,6 +916,27 @@ static int ez80_i2c_transfer(FAR struct i2c_master_s *dev, return ret; } +/************************************************************************************ + * Name: ez80_i2c_reset + * + * Description: + * Perform an I2C bus reset in an attempt to break loose stuck I2C devices. + * + * Input Parameters: + * dev - Device-specific state data + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + ************************************************************************************/ + +#ifdef CONFIG_I2C_RESET +static int ez80_i2c_reset(FAR struct i2c_master_s * dev) +{ + return OK; +} +#endif + /**************************************************************************** * Public Functions ****************************************************************************/ diff --git a/arch/z80/src/z8/z8_i2c.c b/arch/z80/src/z8/z8_i2c.c index f628a1acdcf..3817b517b4e 100644 --- a/arch/z80/src/z8/z8_i2c.c +++ b/arch/z80/src/z8/z8_i2c.c @@ -1,7 +1,7 @@ /**************************************************************************** * arch/z80/src/z8/z8_i2c.c * - * Copyright(C) 2009, 2011, 2013 Gregory Nutt. All rights reserved. + * Copyright(C) 2009, 2011, 2013, 2016 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -94,6 +94,9 @@ static void z8_i2c_setfrequency(FAR struct z8_i2cdev_s *priv, static int z8_i2c_transfer(FAR struct i2c_master_s *dev, FAR struct i2c_msg_s *msgs, int count); +#ifdef CONFIG_I2C_RESET +static int z8_i2c_reset(FAR struct i2c_master_s *dev); +#endif /**************************************************************************** * Public Function Prototypes @@ -113,6 +116,9 @@ static sem_t g_i2csem; /* Serialize I2C transfers */ const struct i2c_ops_s g_ops = { z8_i2c_transfer, +#ifdef CONFIG_I2C_RESET + , z8_i2c_reset +#endif }; /**************************************************************************** @@ -593,6 +599,27 @@ static int z8_i2c_transfer(FAR struct i2c_master_s *dev, return ret; } +/************************************************************************************ + * Name: z8_i2c_reset + * + * Description: + * Perform an I2C bus reset in an attempt to break loose stuck I2C devices. + * + * Input Parameters: + * dev - Device-specific state data + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + ************************************************************************************/ + +#ifdef CONFIG_I2C_RESET +static int z8_i2c_reset(FAR struct i2c_master_s * dev) +{ + return OK; +} +#endif + /**************************************************************************** * Public Functions ****************************************************************************/