diff --git a/arch/arm/src/am335x/am335x_i2c.c b/arch/arm/src/am335x/am335x_i2c.c index 879189b9c72..159cb7b4793 100644 --- a/arch/arm/src/am335x/am335x_i2c.c +++ b/arch/arm/src/am335x/am335x_i2c.c @@ -38,7 +38,7 @@ /**************************************************************************** * Included Files - ************************************************************************************/ + ****************************************************************************/ #include @@ -80,7 +80,7 @@ /* Configuration ************************************************************/ /* CONFIG_I2C_POLLED may be set so that I2C interrupts will not be used. - ( Instead, CPU-intensive polling will be used. + * Instead, CPU-intensive polling will be used. */ /* Interrupt wait timeout in seconds and milliseconds */ @@ -189,8 +189,14 @@ struct am335x_i2c_config_s struct am335x_i2c_priv_s { - const struct i2c_ops_s *ops; /* Standard I2C operations */ - const struct am335x_i2c_config_s *config; /* Port configuration */ + /* Standard I2C operations */ + + const struct i2c_ops_s *ops; + + /* Port configuration */ + + const struct am335x_i2c_config_s *config; + int refs; /* Reference count */ sem_t sem_excl; /* Mutual exclusion semaphore */ #ifndef CONFIG_I2C_POLLED @@ -230,17 +236,22 @@ static inline void am335x_i2c_putreg(FAR struct am335x_i2c_priv_s *priv, static inline void am335x_i2c_modifyreg(FAR struct am335x_i2c_priv_s *priv, uint16_t offset, uint32_t clearbits, uint32_t setbits); -static inline void am335x_i2c_sem_wait(FAR struct am335x_i2c_priv_s *priv); +static inline int am335x_i2c_sem_wait(FAR struct am335x_i2c_priv_s *priv); +static int + am335x_i2c_sem_wait_uninterruptible(FAR struct am335x_i2c_priv_s *priv); #ifdef CONFIG_AM335X_I2C_DYNTIMEO static useconds_t am335x_i2c_tousecs(int msgc, FAR struct i2c_msg_s *msgs); #endif /* CONFIG_AM335X_I2C_DYNTIMEO */ -static inline int am335x_i2c_sem_waitdone(FAR struct am335x_i2c_priv_s *priv); -static inline bool am335x_i2c_sem_waitstop(FAR struct am335x_i2c_priv_s *priv); +static inline int + am335x_i2c_sem_waitdone(FAR struct am335x_i2c_priv_s *priv); +static inline bool + am335x_i2c_sem_waitstop(FAR struct am335x_i2c_priv_s *priv); static inline void am335x_i2c_sem_post(FAR struct am335x_i2c_priv_s *priv); static inline void am335x_i2c_sem_init(FAR struct am335x_i2c_priv_s *priv); -static inline void am335x_i2c_sem_destroy(FAR struct am335x_i2c_priv_s *priv); +static inline void + am335x_i2c_sem_destroy(FAR struct am335x_i2c_priv_s *priv); #ifdef CONFIG_I2C_TRACE static void am335x_i2c_tracereset(FAR struct am335x_i2c_priv_s *priv); @@ -256,7 +267,8 @@ static void am335x_i2c_setclock(FAR struct am335x_i2c_priv_s *priv, static inline void am335x_i2c_sendstart(FAR struct am335x_i2c_priv_s *priv, uint16_t address); static inline void am335x_i2c_sendstop(FAR struct am335x_i2c_priv_s *priv); -static inline uint32_t am335x_i2c_getstatus(FAR struct am335x_i2c_priv_s *priv); +static inline uint32_t + am335x_i2c_getstatus(FAR struct am335x_i2c_priv_s *priv); static int am335x_i2c_isr_process(struct am335x_i2c_priv_s * priv); @@ -448,13 +460,28 @@ static inline void am335x_i2c_modifyreg(FAR struct am335x_i2c_priv_s *priv, * Name: am335x_i2c_sem_wait * * Description: - * Take the exclusive access, waiting as necessary + * Take the exclusive access, waiting as necessary. May be interrupted by + * a signal. * ****************************************************************************/ -static inline void am335x_i2c_sem_wait(FAR struct am335x_i2c_priv_s *priv) +static inline int am335x_i2c_sem_wait(FAR struct am335x_i2c_priv_s *priv) { - nxsem_wait_uninterruptible(&priv->sem_excl); + return nxsem_wait(&priv->sem_excl); +} + +/**************************************************************************** + * Name: am335x_i2c_sem_wait_uninterruptible + * + * Description: + * Take the exclusive access, waiting as necessary. + * + ****************************************************************************/ + +static int + am335x_i2c_sem_wait_uninterruptible(FAR struct am335x_i2c_priv_s *priv) +{ + return nxsem_wait_uninterruptible(&priv->sem_excl); } /**************************************************************************** @@ -655,7 +682,8 @@ static inline int am335x_i2c_sem_waitdone(FAR struct am335x_i2c_priv_s *priv) * ****************************************************************************/ -static inline bool am335x_i2c_sem_waitstop(FAR struct am335x_i2c_priv_s *priv) +static inline bool + am335x_i2c_sem_waitstop(FAR struct am335x_i2c_priv_s *priv) { clock_t start; clock_t elapsed; @@ -863,8 +891,10 @@ static void am335x_i2c_tracedump(FAR struct am335x_i2c_priv_s *priv) { trace = &priv->trace[i]; syslog(LOG_DEBUG, - "%2d. STATUS: %08x COUNT: %3d EVENT: %s(%2d) PARM: %08x TIME: %d\n", - i + 1, trace->status, trace->count, g_trace_names[trace->event], + "%2d. STATUS: %08x COUNT: %3d EVENT: %s(%2d) PARM: %08x " + "TIME: %d\n", + i + 1, trace->status, trace->count, + g_trace_names[trace->event], trace->event, trace->parm, trace->time - priv->start_time); } } @@ -1031,7 +1061,8 @@ static inline void am335x_i2c_sendstop(FAR struct am335x_i2c_priv_s *priv) * ****************************************************************************/ -static inline uint32_t am335x_i2c_getstatus(FAR struct am335x_i2c_priv_s *priv) +static inline uint32_t + am335x_i2c_getstatus(FAR struct am335x_i2c_priv_s *priv) { #ifndef CONFIG_I2C_POLLED return am335x_i2c_getreg(priv, AM335X_I2C_IRQ_STAT_OFFSET); @@ -1100,7 +1131,8 @@ static int am335x_i2c_isr_process(struct am335x_i2c_priv_s *priv) am335x_i2c_traceevent(priv, I2CEVENT_RCVBYTE, priv->dcnt); /* No interrupts or context switches should occur in the following - * sequence. Otherwise, additional bytes may be received by the device. + * sequence. Otherwise, additional bytes may be received by the + * device. */ #ifdef CONFIG_I2C_POLLED @@ -1331,7 +1363,8 @@ static int am335x_i2c_init(FAR struct am335x_i2c_priv_s *priv) /* Wait for I2C module comes out of reset */ - while (!(am335x_i2c_getreg(priv, AM335X_I2C_SYSS_OFFSET) & I2C_SYSS_RST_DONE)) + while (!(am335x_i2c_getreg(priv, AM335X_I2C_SYSS_OFFSET) & + I2C_SYSS_RST_DONE)) { } @@ -1382,16 +1415,21 @@ static int am335x_i2c_transfer(FAR struct i2c_master_s *dev, FAR struct i2c_msg_s *msgs, int count) { FAR struct am335x_i2c_priv_s *priv = (struct am335x_i2c_priv_s *)dev; - int ret = -EBUSY; + int ret; DEBUGASSERT(count > 0); /* Ensure that address or flags don't change meanwhile */ - am335x_i2c_sem_wait(priv); + ret = am335x_i2c_sem_wait(priv); + if (ret < 0) + { + return ret; + } /* Wait for any STOP in progress */ + ret = -EBUSY; if (am335x_i2c_sem_waitstop(priv)) { /* Clear any pending error interrupts */ @@ -1526,7 +1564,7 @@ static int am335x_i2c_reset(FAR struct i2c_master_s *dev) gpio_pinset_t scl_gpio; gpio_pinset_t sda_gpio; uint32_t frequency; - int ret = ERROR; + int ret; DEBUGASSERT(dev); @@ -1536,7 +1574,13 @@ static int am335x_i2c_reset(FAR struct i2c_master_s *dev) /* Lock out other clients */ - am335x_i2c_sem_wait(priv); + ret = am335x_i2c_sem_wait_uninterruptible(priv); + if (ret < 0) + { + return ret; + } + + ret = -EIO; /* Save the current frequency */ diff --git a/arch/arm/src/efm32/efm32_i2c.c b/arch/arm/src/efm32/efm32_i2c.c index 146936be68b..2f1b1c41cd5 100644 --- a/arch/arm/src/efm32/efm32_i2c.c +++ b/arch/arm/src/efm32/efm32_i2c.c @@ -1,4 +1,4 @@ -/************************************************************************************ +/**************************************************************************** * arch/arm/src/efm32/efm32_i2c.c * EFM32 I2C Hardware Layer - Device Driver * @@ -45,11 +45,11 @@ * * Structure naming: * - Device: structure as defined by the nuttx/i2c/i2c.h - * - Instance: represents each individual access to the I2C driver, obtained by - * the i2c_init(); it extends the Device structure from the nuttx/i2c/i2c.h; - * Instance points to OPS, to common I2C Hardware private data and contains - * its own private data, as frequency, address, mode of operation (in the - * future) + * - Instance: represents each individual access to the I2C driver, + * obtained by the i2c_init(); it extends the Device structure from the + * nuttx/i2c/i2c.h; Instance points to OPS, to common I2C Hardware + * private data and contains its own private data, as frequency, + * address, mode of operation (in the future) * - Private: Private data of an I2C Hardware * */ @@ -90,10 +90,10 @@ * Pre-processor Definitions ****************************************************************************/ -/* Configuration **************************************************************/ +/* Configuration ************************************************************/ -/* CONFIG_I2C_POLLED may be set so that I2C interrupts will not be used. Instead, - * CPU-intensive polling will be used. +/* CONFIG_I2C_POLLED may be set so that I2C interrupts will not be used. + * Instead, CPU-intensive polling will be used. */ #if !defined(CONFIG_EFM32_EFM32GG) @@ -132,11 +132,11 @@ #define MKI2C_OUTPUT(p) (((p) & (GPIO_PORT_MASK | GPIO_PIN_MASK)) | I2C_OUTPUT) -/* Debug ****************************************************************************/ +/* Debug ********************************************************************/ /* I2C event trace logic. NOTE: trace uses the internal, non-standard, - * low-level debug interface syslog() but does not require that any other debug - * is enabled. + * low-level debug interface syslog() but does not require that any other + * debug is enabled. */ #ifndef CONFIG_I2C_TRACE @@ -151,16 +151,17 @@ /* Error flags indicating I2C transfer has failed somehow. * Notice that I2C_IF_TXOF (transmit overflow) is not really possible with - * this SW supporting master mode. Likewise for I2C_IF_RXUF (receive underflow) - * RXUF is only likely to occur with this SW if using a debugger peeking into - * RXDATA register. Thus, we ignore those types of fault. + * this SW supporting master mode. Likewise for I2C_IF_RXUF (receive + * underflow). RXUF is only likely to occur with this SW if using a + * debugger peeking into RXDATA register. Thus, we ignore those types of + * fault. */ #define I2C_IF_ERRORS (I2C_IF_BUSERR | I2C_IF_ARBLOST) -/************************************************************************************ +/**************************************************************************** * Private Types - ************************************************************************************/ + ****************************************************************************/ /* I2C result state */ @@ -227,9 +228,15 @@ struct efm32_i2c_config_s struct efm32_i2c_priv_s { - const struct i2c_ops_s *ops; /* Standard I2C operations */ - const struct efm32_i2c_config_s *config; /* Port configuration */ - int refs; /* Referernce count */ + /* Standard I2C operations */ + + const struct i2c_ops_s *ops; + + /* Port configuration */ + + const struct efm32_i2c_config_s *config; + + int refs; /* Reference count */ sem_t sem_excl; /* Mutual exclusion semaphore */ #ifndef CONFIG_I2C_POLLED sem_t sem_isr; /* Interrupt wait semaphore */ @@ -272,7 +279,9 @@ static inline void efm32_i2c_putreg(FAR struct efm32_i2c_priv_s *priv, static inline void efm32_i2c_modifyreg(FAR struct efm32_i2c_priv_s *priv, uint8_t offset, uint32_t clearbits, uint32_t setbits); -static inline void efm32_i2c_sem_wait(FAR struct efm32_i2c_priv_s *priv); +static inline int efm32_i2c_sem_wait(FAR struct efm32_i2c_priv_s *priv); +static int + efm32_i2c_sem_wait_uninterruptible(FAR struct efm32_i2c_priv_s *priv); #ifdef CONFIG_EFM32_I2C_DYNTIMEOUT static useconds_t efm32_i2c_tousecs(int msgc, FAR struct i2c_msg_s *msgs); @@ -473,13 +482,28 @@ static const char *efm32_i2c_state_str(int i2c_state) * Name: efm32_i2c_sem_wait * * Description: + * Take the exclusive access, waiting as necessary. May be interrupted by + * a signal. + * + ****************************************************************************/ + +static inline int efm32_i2c_sem_wait(FAR struct efm32_i2c_priv_s *priv) +{ + return nxsem_wait(&priv->sem_excl); +} + +/**************************************************************************** + * Name: efm32_i2c_sem_wait_uninterruptible + * + * Description: * Take the exclusive access, waiting as necessary * ****************************************************************************/ -static inline void efm32_i2c_sem_wait(FAR struct efm32_i2c_priv_s *priv) +static int + efm32_i2c_sem_wait_uninterruptible(FAR struct efm32_i2c_priv_s *priv) { - nxsem_wait_uninterruptible(&priv->sem_excl); + return nxsem_wait_uninterruptible(&priv->sem_excl); } /**************************************************************************** @@ -505,7 +529,8 @@ static useconds_t efm32_i2c_tousecs(int msgc, FAR struct i2c_msg_s *msgs) } /* Then return a number of microseconds based on a user provided scaling - * factor. */ + * factor. + */ return (useconds_t) (CONFIG_EFM32_I2C_DYNTIMEO_USECPERBYTE * bytecount); } @@ -571,8 +596,9 @@ static inline int efm32_i2c_sem_waitdone(FAR struct efm32_i2c_priv_s *priv) if (ret < 0) { - /* Break out of the loop on irrecoverable errors. This would include - * timeouts and mystery errors reported by nxsem_timedwait. + /* Break out of the loop on irrecoverable errors. This would + * include timeouts and mystery errors reported by + * nxsem_timedwait. */ break; @@ -821,8 +847,13 @@ static void efm32_i2c_setclock(FAR struct efm32_i2c_priv_s *priv, #endif << _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) @@ -840,7 +871,8 @@ static void efm32_i2c_setclock(FAR struct efm32_i2c_priv_s *priv, * bus frequency). */ - if ((efm32_i2c_getreg(priv, EFM32_I2C_CTRL_OFFSET) & I2C_CTRL_SLAVE) && !div) + if ((efm32_i2c_getreg(priv, EFM32_I2C_CTRL_OFFSET) & I2C_CTRL_SLAVE) && + !div) { div = 1; } @@ -882,24 +914,25 @@ static int efm32_i2c_isr_process(struct efm32_i2c_priv_s *priv) { if (priv->i2c_reg_if & I2C_IF_ARBLOST) { - /* If arbitration fault, it indicates either a slave device not - * responding as expected, or other master which is not supported - * by this SW. */ + /* If arbitration fault, it indicates either a slave device + * not responding as expected, or other master which is not + * supported by this SW. + */ priv->result = I2CRESULT_ARBLOST; } else if (priv->i2c_reg_if & I2C_IF_BUSERR) { - /* A bus error indicates a misplaced start or stop, which should - * not occur in master mode controlled by this SW. + /* A bus error indicates a misplaced start or stop, which + * should not occur in master mode controlled by this SW. */ priv->result = I2CRESULT_BUSERR; } - /* If error situation occurred, it is difficult to know exact cause - * and how to resolve. It will be up to a wrapper to determine how to - * handle a fault/recovery if possible. + /* If error situation occurred, it is difficult to know exact + * cause and how to resolve. It will be up to a wrapper to + * determine how to handle a fault/recovery if possible. */ priv->i2c_state = I2CSTATE_DONE; @@ -908,9 +941,7 @@ static int efm32_i2c_isr_process(struct efm32_i2c_priv_s *priv) switch (priv->i2c_state) { - /*************************************************** - * Send first start+address (first byte if 10 bit) - */ + /* Send first start+address (first byte if 10 bit) */ case I2CSTATE_STARTADDRSEND: if (priv->flags & I2C_M_TEN) @@ -949,9 +980,7 @@ static int efm32_i2c_isr_process(struct efm32_i2c_priv_s *priv) goto done; - /******************************************************* - * Wait for ACK/NACK on address (first byte if 10 bit) - */ + /* Wait for ACK/NACK on address (first byte if 10 bit) */ case I2CSTATE_ADDRWFACKNACK: if (priv->i2c_reg_if & I2C_IF_NACK) @@ -999,9 +1028,7 @@ static int efm32_i2c_isr_process(struct efm32_i2c_priv_s *priv) goto done; - /****************************************************** - * Wait for ACK/NACK on second byte of 10 bit address - */ + /* Wait for ACK/NACK on second byte of 10 bit address */ case I2CSTATE_ADDRWF2NDACKNACK: if (priv->i2c_reg_if & I2C_IF_NACK) @@ -1030,14 +1057,13 @@ static int efm32_i2c_isr_process(struct efm32_i2c_priv_s *priv) { priv->i2c_state = I2CSTATE_DATASEND; } + continue; } goto done; - /******************************* - * Send repeated start+address - */ + /* Send repeated start+address */ case I2CSTATE_RSTARTADDRSEND: if (priv->flags & I2C_M_TEN) @@ -1078,8 +1104,7 @@ static int efm32_i2c_isr_process(struct efm32_i2c_priv_s *priv) efm32_i2c_putreg(priv, EFM32_I2C_TXDATA_OFFSET, regval); goto done; - /*********************************************** - * Wait for ACK/NACK on repeated start+address + /* Wait for ACK/NACK on repeated start+address * (first byte if 10 bit) */ @@ -1110,11 +1135,10 @@ static int efm32_i2c_isr_process(struct efm32_i2c_priv_s *priv) goto done; - /***************************** - * Send a data byte to slave - */ + /* Send a data byte to slave */ case I2CSTATE_DATASEND: + /* Reached end of data buffer? */ if (priv->dcnt == 0) @@ -1153,9 +1177,7 @@ static int efm32_i2c_isr_process(struct efm32_i2c_priv_s *priv) priv->i2c_state = I2CSTATE_DATAWFACKNACK; goto done; - /********************************************************* - * Wait for ACK/NACK from slave after sending data to it - */ + /* Wait for ACK/NACK from slave after sending data to it */ case I2CSTATE_DATAWFACKNACK: if (priv->i2c_reg_if & I2C_IF_NACK) @@ -1171,11 +1193,10 @@ static int efm32_i2c_isr_process(struct efm32_i2c_priv_s *priv) priv->i2c_state = I2CSTATE_DATASEND; continue; } + goto done; - /**************************** - * Wait for data from slave - */ + /* Wait for data from slave */ case I2CSTATE_WFDATA: if (priv->i2c_reg_if & I2C_IF_RXDATAV) @@ -1200,7 +1221,6 @@ static int efm32_i2c_isr_process(struct efm32_i2c_priv_s *priv) { priv->i2c_state = I2CSTATE_WFSTOPSENT; efm32_i2c_putreg(priv, EFM32_I2C_CMD_OFFSET, I2C_CMD_STOP); - } else { @@ -1210,20 +1230,20 @@ static int efm32_i2c_isr_process(struct efm32_i2c_priv_s *priv) if (priv->dcnt == 1) { - /* If there is more than one byte to receive and this is - * the next to last byte we need to transmit the NACK - * now, before receiving the last byte. + /* If there is more than one byte to receive and this + * is the next to last byte we need to transmit the + * NAK now, before receiving the last byte. */ - efm32_i2c_putreg(priv, EFM32_I2C_CMD_OFFSET, I2C_CMD_NACK); + efm32_i2c_putreg(priv, EFM32_I2C_CMD_OFFSET, + I2C_CMD_NACK); } } } + goto done; - /*********************************** - * Wait for STOP to have been sent - */ + /* Wait for STOP to have been sent */ case I2CSTATE_WFSTOPSENT: if (priv->i2c_reg_if & I2C_IF_MSTOP) @@ -1234,9 +1254,7 @@ static int efm32_i2c_isr_process(struct efm32_i2c_priv_s *priv) goto done; - /******************************/ /* Unexpected state, SW fault */ - /******************************/ default: priv->result = I2CRESULT_SWFAULT; @@ -1294,12 +1312,18 @@ static int efm32_i2c_isr(int irq, void *context, FAR void *arg) 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); - efm32_i2c_putreg(priv, EFM32_I2C_SADDR_OFFSET, _I2C_SADDR_RESETVALUE); - efm32_i2c_putreg(priv, EFM32_I2C_SADDRMASK_OFFSET, _I2C_SADDRMASK_RESETVALUE); - efm32_i2c_putreg(priv, EFM32_I2C_IEN_OFFSET, _I2C_IEN_RESETVALUE); - efm32_i2c_putreg(priv, EFM32_I2C_IFC_OFFSET, _I2C_IFC_MASK); + efm32_i2c_putreg(priv, EFM32_I2C_CTRL_OFFSET, + _I2C_CTRL_RESETVALUE); + efm32_i2c_putreg(priv, EFM32_I2C_CLKDIV_OFFSET, + _I2C_CLKDIV_RESETVALUE); + efm32_i2c_putreg(priv, EFM32_I2C_SADDR_OFFSET, + _I2C_SADDR_RESETVALUE); + efm32_i2c_putreg(priv, EFM32_I2C_SADDRMASK_OFFSET, + _I2C_SADDRMASK_RESETVALUE); + efm32_i2c_putreg(priv, EFM32_I2C_IEN_OFFSET, + _I2C_IEN_RESETVALUE); + efm32_i2c_putreg(priv, EFM32_I2C_IFC_OFFSET, + _I2C_IFC_MASK); /* Do not reset route register, setting should be done independently */ } @@ -1423,7 +1447,7 @@ static int efm32_i2c_transfer(FAR struct i2c_master_s *dev, FAR struct i2c_msg_s *msgs, int count) { FAR struct efm32_i2c_priv_s *priv = (struct efm32_i2c_priv_s *)dev; - int ret = OK; + int ret; DEBUGASSERT(count > 0); @@ -1434,7 +1458,11 @@ static int efm32_i2c_transfer(FAR struct i2c_master_s *dev, /* Ensure that address or flags don't change meanwhile */ - efm32_i2c_sem_wait(priv); + ret = efm32_i2c_sem_wait(priv); + if (ret < 0) + { + return ret; + } /* Reset ptr and dcnt to ensure an unexpected data interrupt doesn't * overwrite stale data. @@ -1486,8 +1514,9 @@ static int efm32_i2c_transfer(FAR struct i2c_master_s *dev, efm32_i2c_putreg(priv, EFM32_I2C_IFC_OFFSET, _I2C_IFC_MASK); - /* Call once isr to start state machine. I2C interrupt are disabled and will - * be enabled in efm32_i2c_sem_waitdone if CONFIG_I2C_POLLED is NOT defined + /* Call once isr to start state machine. I2C interrupt are disabled and + * will be enabled in efm32_i2c_sem_waitdone if CONFIG_I2C_POLLED is NOT + * defined. */ efm32_i2c_isr_process(priv); @@ -1564,7 +1593,7 @@ static int efm32_i2c_transfer(FAR struct i2c_master_s *dev, return ret; } -/************************************************************************************ +/**************************************************************************** * Name: efm32_i2c_reset * * Description: @@ -1576,7 +1605,7 @@ static int efm32_i2c_transfer(FAR struct i2c_master_s *dev, * Returned Value: * Zero (OK) on success; a negated errno value on failure. * - ************************************************************************************/ + ****************************************************************************/ #ifdef CONFIG_I2C_RESET int efm32_i2c_reset(FAR struct i2c_master_s *dev) @@ -1586,7 +1615,7 @@ int efm32_i2c_reset(FAR struct i2c_master_s *dev) unsigned int stretch_count; uint32_t scl_gpio; uint32_t sda_gpio; - int ret = ERROR; + int ret; DEBUGASSERT(dev); @@ -1596,7 +1625,13 @@ int efm32_i2c_reset(FAR struct i2c_master_s *dev) /* Lock out other clients */ - efm32_i2c_sem_wait(priv); + ret = efm32_i2c_sem_wait_uninterruptible(priv); + if (ret < 0) + { + return ret; + } + + ret = -EIO; /* De-init the port */ @@ -1676,6 +1711,7 @@ int efm32_i2c_reset(FAR struct i2c_master_s *dev) ret = OK; out: + /* Release the port for re-use by other clients */ efm32_i2c_sem_post(priv); diff --git a/arch/arm/src/imxrt/imxrt_lpi2c.c b/arch/arm/src/imxrt/imxrt_lpi2c.c index 140a090e7e5..7b3b358bfcc 100644 --- a/arch/arm/src/imxrt/imxrt_lpi2c.c +++ b/arch/arm/src/imxrt/imxrt_lpi2c.c @@ -191,8 +191,14 @@ struct imxrt_lpi2c_config_s struct imxrt_lpi2c_priv_s { - const struct i2c_ops_s *ops; /* Standard I2C operations */ - const struct imxrt_lpi2c_config_s *config; /* Port configuration */ + /* Standard I2C operations */ + + const struct i2c_ops_s *ops; + + /* Port configuration */ + + const struct imxrt_lpi2c_config_s *config; + int refs; /* Reference count */ sem_t sem_excl; /* Mutual exclusion semaphore */ #ifndef CONFIG_I2C_POLLED @@ -225,24 +231,31 @@ struct imxrt_lpi2c_priv_s * Private Function Prototypes ****************************************************************************/ -static inline uint32_t imxrt_lpi2c_getreg(FAR struct imxrt_lpi2c_priv_s *priv, - uint16_t offset); +static inline uint32_t + imxrt_lpi2c_getreg(FAR struct imxrt_lpi2c_priv_s *priv, uint16_t offset); static inline void imxrt_lpi2c_putreg(FAR struct imxrt_lpi2c_priv_s *priv, uint16_t offset, uint32_t value); static inline void imxrt_lpi2c_modifyreg(FAR struct imxrt_lpi2c_priv_s *priv, uint16_t offset, uint32_t clearbits, uint32_t setbits); -static inline void imxrt_lpi2c_sem_wait(FAR struct imxrt_lpi2c_priv_s *priv); +static inline int imxrt_lpi2c_sem_wait(FAR struct imxrt_lpi2c_priv_s *priv); +static int + imxrt_lpi2c_sem_wait_uninterruptible(FAR struct imxrt_lpi2c_priv_s *priv); #ifdef CONFIG_IMXRT_LPI2C_DYNTIMEO static useconds_t imxrt_lpi2c_tousecs(int msgc, FAR struct i2c_msg_s *msgs); #endif /* CONFIG_IMXRT_LPI2C_DYNTIMEO */ -static inline int imxrt_lpi2c_sem_waitdone(FAR struct imxrt_lpi2c_priv_s *priv); -static inline void imxrt_lpi2c_sem_waitstop(FAR struct imxrt_lpi2c_priv_s *priv); -static inline void imxrt_lpi2c_sem_post(FAR struct imxrt_lpi2c_priv_s *priv); -static inline void imxrt_lpi2c_sem_init(FAR struct imxrt_lpi2c_priv_s *priv); -static inline void imxrt_lpi2c_sem_destroy(FAR struct imxrt_lpi2c_priv_s *priv); +static inline int + imxrt_lpi2c_sem_waitdone(FAR struct imxrt_lpi2c_priv_s *priv); +static inline void + imxrt_lpi2c_sem_waitstop(FAR struct imxrt_lpi2c_priv_s *priv); +static inline void + imxrt_lpi2c_sem_post(FAR struct imxrt_lpi2c_priv_s *priv); +static inline void + imxrt_lpi2c_sem_init(FAR struct imxrt_lpi2c_priv_s *priv); +static inline void + imxrt_lpi2c_sem_destroy(FAR struct imxrt_lpi2c_priv_s *priv); #ifdef CONFIG_I2C_TRACE static void imxrt_lpi2c_tracereset(FAR struct imxrt_lpi2c_priv_s *priv); @@ -258,7 +271,8 @@ static void imxrt_lpi2c_setclock(FAR struct imxrt_lpi2c_priv_s *priv, static inline void imxrt_lpi2c_sendstart(FAR struct imxrt_lpi2c_priv_s *priv, uint8_t address); static inline void imxrt_lpi2c_sendstop(FAR struct imxrt_lpi2c_priv_s *priv); -static inline uint32_t imxrt_lpi2c_getstatus(FAR struct imxrt_lpi2c_priv_s *priv); +static inline uint32_t + imxrt_lpi2c_getstatus(FAR struct imxrt_lpi2c_priv_s *priv); static int imxrt_lpi2c_isr_process(struct imxrt_lpi2c_priv_s * priv); @@ -472,8 +486,8 @@ static struct imxrt_lpi2c_priv_s imxrt_lpi2c4_priv = * ****************************************************************************/ -static inline uint32_t imxrt_lpi2c_getreg(FAR struct imxrt_lpi2c_priv_s *priv, - uint16_t offset) +static inline uint32_t + imxrt_lpi2c_getreg(FAR struct imxrt_lpi2c_priv_s *priv, uint16_t offset) { return getreg32(priv->config->base + offset); } @@ -511,13 +525,28 @@ static inline void imxrt_lpi2c_modifyreg(FAR struct imxrt_lpi2c_priv_s *priv, * Name: imxrt_lpi2c_sem_wait * * Description: - * Take the exclusive access, waiting as necessary + * Take the exclusive access, waiting as necessary. May be interrupted by + * a signal. * ****************************************************************************/ -static inline void imxrt_lpi2c_sem_wait(FAR struct imxrt_lpi2c_priv_s *priv) +static inline int imxrt_lpi2c_sem_wait(FAR struct imxrt_lpi2c_priv_s *priv) { - nxsem_wait_uninterruptible(&priv->sem_excl); + return nxsem_wait(&priv->sem_excl); +} + +/**************************************************************************** + * Name: imxrt_lpi2c_sem_wait_uninterruptible + * + * Description: + * Take the exclusive access, waiting as necessary. + * + ****************************************************************************/ + +static int + imxrt_lpi2c_sem_wait_uninterruptible(FAR struct imxrt_lpi2c_priv_s *priv) +{ + return nxsem_wait_uninterruptible(&priv->sem_excl); } /**************************************************************************** @@ -559,7 +588,8 @@ static useconds_t imxrt_lpi2c_tousecs(int msgc, FAR struct i2c_msg_s *msgs) ****************************************************************************/ #ifndef CONFIG_I2C_POLLED -static inline int imxrt_lpi2c_sem_waitdone(FAR struct imxrt_lpi2c_priv_s *priv) +static inline int + imxrt_lpi2c_sem_waitdone(FAR struct imxrt_lpi2c_priv_s *priv) { struct timespec abstime; irqstate_t flags; @@ -671,7 +701,8 @@ static inline int imxrt_lpi2c_sem_waitdone(FAR struct imxrt_lpi2c_priv_s *priv) return ret; } #else -static inline int imxrt_lpi2c_sem_waitdone(FAR struct imxrt_lpi2c_priv_s *priv) +static inline int + imxrt_lpi2c_sem_waitdone(FAR struct imxrt_lpi2c_priv_s *priv) { clock_t timeout; clock_t start; @@ -730,7 +761,8 @@ static inline int imxrt_lpi2c_sem_waitdone(FAR struct imxrt_lpi2c_priv_s *priv) * ****************************************************************************/ -static inline void imxrt_lpi2c_sem_waitstop(FAR struct imxrt_lpi2c_priv_s *priv) +static inline void + imxrt_lpi2c_sem_waitstop(FAR struct imxrt_lpi2c_priv_s *priv) { clock_t start; clock_t elapsed; @@ -853,7 +885,8 @@ static inline void imxrt_lpi2c_sem_init(FAR struct imxrt_lpi2c_priv_s *priv) * ****************************************************************************/ -static inline void imxrt_lpi2c_sem_destroy(FAR struct imxrt_lpi2c_priv_s *priv) +static inline void + imxrt_lpi2c_sem_destroy(FAR struct imxrt_lpi2c_priv_s *priv) { nxsem_destroy(&priv->sem_excl); #ifndef CONFIG_I2C_POLLED @@ -969,8 +1002,10 @@ static void imxrt_lpi2c_tracedump(FAR struct imxrt_lpi2c_priv_s *priv) { trace = &priv->trace[i]; syslog(LOG_DEBUG, - "%2d. STATUS: %08x COUNT: %3d EVENT: %s(%2d) PARM: %08x TIME: %d\n", - i + 1, trace->status, trace->count, g_trace_names[trace->event], + "%2d. STATUS: %08x COUNT: %3d EVENT: %s(%2d) PARM: %08x " + "TIME: %d\n", + i + 1, trace->status, trace->count, + g_trace_names[trace->event], trace->event, trace->parm, trace->time - priv->start_time); } } @@ -1209,7 +1244,8 @@ static inline void imxrt_lpi2c_sendstop(FAR struct imxrt_lpi2c_priv_s *priv) * ****************************************************************************/ -static inline uint32_t imxrt_lpi2c_getstatus(FAR struct imxrt_lpi2c_priv_s *priv) +static inline uint32_t + imxrt_lpi2c_getstatus(FAR struct imxrt_lpi2c_priv_s *priv) { return imxrt_lpi2c_getreg(priv, IMXRT_LPI2C_MSR_OFFSET); } @@ -1240,7 +1276,8 @@ static int imxrt_lpi2c_isr_process(struct imxrt_lpi2c_priv_s *priv) /* Check if there is more bytes to send */ - else if (((priv->flags & I2C_M_READ) == 0) && (status & LPI2C_MSR_TDF) != 0) + else if (((priv->flags & I2C_M_READ) == 0) && + (status & LPI2C_MSR_TDF) != 0) { if (priv->dcnt > 0) { @@ -1259,7 +1296,8 @@ static int imxrt_lpi2c_isr_process(struct imxrt_lpi2c_priv_s *priv) /* Check if there is more bytes to read */ - else if (((priv->flags & I2C_M_READ) != 0) && (status & LPI2C_MSR_RDF) != 0) + else if (((priv->flags & I2C_M_READ) != 0) && + (status & LPI2C_MSR_RDF) != 0) { /* Read a byte, if dcnt goes < 0, then read dummy bytes to ack ISRs */ @@ -1628,13 +1666,17 @@ static int imxrt_lpi2c_transfer(FAR struct i2c_master_s *dev, FAR struct i2c_msg_s *msgs, int count) { FAR struct imxrt_lpi2c_priv_s *priv = (struct imxrt_lpi2c_priv_s *)dev; - int ret = 0; + int ret; DEBUGASSERT(count > 0); /* Ensure that address or flags don't change meanwhile */ - imxrt_lpi2c_sem_wait(priv); + ret = imxrt_lpi2c_sem_wait(priv); + if (ret < 0) + { + return ret; + } /* Clear any pending error interrupts */ @@ -1743,7 +1785,7 @@ static int imxrt_lpi2c_reset(FAR struct i2c_master_s *dev) uint32_t scl_gpio; uint32_t sda_gpio; uint32_t frequency; - int ret = ERROR; + int ret; DEBUGASSERT(dev); @@ -1753,7 +1795,13 @@ static int imxrt_lpi2c_reset(FAR struct i2c_master_s *dev) /* Lock out other clients */ - imxrt_lpi2c_sem_wait(priv); + ret = imxrt_lpi2c_sem_wait_uninterruptible(priv); + if (ret < 0) + { + return ret; + } + + ret = -EIO; /* Save the current frequency */ diff --git a/arch/arm/src/kinetis/kinetis_i2c.c b/arch/arm/src/kinetis/kinetis_i2c.c index cefd92e2c45..666b35ac01c 100644 --- a/arch/arm/src/kinetis/kinetis_i2c.c +++ b/arch/arm/src/kinetis/kinetis_i2c.c @@ -113,8 +113,14 @@ struct kinetis_i2c_config_s struct kinetis_i2cdev_s { - struct i2c_master_s dev; /* Generic I2C device */ - const struct kinetis_i2c_config_s *config; /* Port configuration */ + /* Generic I2C device */ + + struct i2c_master_s dev; + + /* Port configuration */ + + const struct kinetis_i2c_config_s *config; + uint32_t frequency; /* Current I2C frequency */ uint16_t nmsg; /* Number of transfer remaining */ uint16_t wrcnt; /* number of bytes sent to tx fifo */ @@ -143,8 +149,11 @@ static void kinetis_i2c_putreg(struct kinetis_i2cdev_s *priv, /* Exclusion Helpers */ static inline void kinetis_i2c_sem_init(FAR struct kinetis_i2cdev_s *priv); -static inline void kinetis_i2c_sem_destroy(FAR struct kinetis_i2cdev_s *priv); -static inline void kinetis_i2c_sem_wait(FAR struct kinetis_i2cdev_s *priv); +static inline void + kinetis_i2c_sem_destroy(FAR struct kinetis_i2cdev_s *priv); +static inline int kinetis_i2c_sem_wait(FAR struct kinetis_i2cdev_s *priv); +static int + kinetis_i2c_sem_wait_uninterruptible(FAR struct kinetis_i2cdev_s *priv); static inline void kinetis_i2c_sem_post(struct kinetis_i2cdev_s *priv); /* Signal Helper */ @@ -344,13 +353,28 @@ static inline void kinetis_i2c_sem_destroy(FAR struct kinetis_i2cdev_s *priv) * Name: kinetis_i2c_sem_wait * * Description: + * Take the exclusive access, waiting as necessary. May be interrupted by + * a signal. + * + ****************************************************************************/ + +static inline int kinetis_i2c_sem_wait(FAR struct kinetis_i2cdev_s *priv) +{ + return nxsem_wait(&priv->mutex); +} + +/**************************************************************************** + * Name: kinetis_i2c_sem_wait_uninterruptible + * + * Description: * Take the exclusive access, waiting as necessary * ****************************************************************************/ -static inline void kinetis_i2c_sem_wait(FAR struct kinetis_i2cdev_s *priv) +static int + kinetis_i2c_sem_wait_uninterruptible(FAR struct kinetis_i2cdev_s *priv) { - nxsem_wait_uninterruptible(&priv->mutex); + return nxsem_wait_uninterruptible(&priv->mutex); } /**************************************************************************** @@ -370,7 +394,7 @@ static inline void kinetis_i2c_sem_post(struct kinetis_i2cdev_s *priv) * Name: kinetis_i2c_wait * * Description: - * Wait on the signaling semaphore + * Wait on the signaling semaphore. May be interrupted by a signal. * ****************************************************************************/ @@ -1121,14 +1145,18 @@ static int kinetis_i2c_transfer(struct i2c_master_s *dev, { struct kinetis_i2cdev_s *priv = (struct kinetis_i2cdev_s *)dev; int msg_n; - int rv; + int ret; i2cinfo("msgs=%p count=%d\n", msgs, count); DEBUGASSERT(dev != NULL && msgs != NULL && (unsigned)count <= UINT16_MAX); /* Get exclusive access to the I2C bus */ - kinetis_i2c_sem_wait(priv); + ret = kinetis_i2c_sem_wait(priv); + if (ret < 0) + { + return ret; + } /* Set up for the transfer */ @@ -1210,13 +1238,13 @@ timeout: /* Get the result before releasing the bus */ - rv = (priv->state != STATE_OK) ? -EIO : 0; + ret = (priv->state != STATE_OK) ? -EIO : 0; /* Release access to I2C bus */ kinetis_i2c_sem_post(priv); - return rv; + return ret; } /**************************************************************************** @@ -1242,7 +1270,7 @@ static int kinetis_i2c_reset(struct i2c_master_s *dev) uint32_t scl_gpio; uint32_t sda_gpio; uint32_t frequency; - int ret = ERROR; + int ret; DEBUGASSERT(dev); @@ -1252,7 +1280,13 @@ static int kinetis_i2c_reset(struct i2c_master_s *dev) /* Lock out other clients */ - kinetis_i2c_sem_wait(priv); + ret = kinetis_i2c_sem_wait_uninterruptible(priv); + if (ret < 0) + { + return ret; + } + + ret = -EIO; /* Save the current frequency */ diff --git a/arch/arm/src/lc823450/lc823450_i2c.c b/arch/arm/src/lc823450/lc823450_i2c.c index aa138f87fc1..a6d5831cf65 100644 --- a/arch/arm/src/lc823450/lc823450_i2c.c +++ b/arch/arm/src/lc823450/lc823450_i2c.c @@ -126,8 +126,14 @@ struct lc823450_i2c_config_s struct lc823450_i2c_priv_s { - FAR const struct i2c_ops_s *ops; /* Standard I2C operations */ - FAR const struct lc823450_i2c_config_s *config; /* Port configuration */ + /* Standard I2C operations */ + + FAR const struct i2c_ops_s *ops; + + /* Port configuration */ + + FAR const struct lc823450_i2c_config_s *config; + int refs; /* Referernce count */ sem_t sem_excl; /* Mutual exclusion semaphore */ #ifndef CONFIG_I2C_POLLED @@ -150,20 +156,31 @@ struct lc823450_i2c_priv_s * Private Function Prototypes ****************************************************************************/ -static inline void lc823450_i2c_sem_wait(FAR struct lc823450_i2c_priv_s *priv); -static inline void lc823450_i2c_sem_post(FAR struct lc823450_i2c_priv_s *priv); -static inline int lc823450_i2c_sem_waitdone(FAR struct lc823450_i2c_priv_s *priv); +static inline int + lc823450_i2c_sem_wait(FAR struct lc823450_i2c_priv_s *priv); +static inline void + lc823450_i2c_sem_post(FAR struct lc823450_i2c_priv_s *priv); +static inline int + lc823450_i2c_sem_waitdone(FAR struct lc823450_i2c_priv_s *priv); #ifndef CONFIG_I2C_POLLED -static inline void lc823450_i2c_enableirq(FAR struct lc823450_i2c_priv_s *priv); -static inline void lc823450_i2c_disableirq(FAR struct lc823450_i2c_priv_s *priv); +static inline void + lc823450_i2c_enableirq(FAR struct lc823450_i2c_priv_s *priv); +static inline void + lc823450_i2c_disableirq(FAR struct lc823450_i2c_priv_s *priv); #endif -static inline bool lc823450_i2c_checkirq(FAR struct lc823450_i2c_priv_s *priv); -static inline bool lc823450_i2c_checkbusy(FAR struct lc823450_i2c_priv_s *priv); -static inline void lc823450_i2c_prepxfer(FAR struct lc823450_i2c_priv_s *priv); -static inline void lc823450_i2c_sendstart(FAR struct lc823450_i2c_priv_s *priv); -static inline void lc823450_i2c_sendstop(FAR struct lc823450_i2c_priv_s *priv); -static inline uint32_t lc823450_i2c_readdata(FAR struct lc823450_i2c_priv_s *priv); +static inline bool + lc823450_i2c_checkirq(FAR struct lc823450_i2c_priv_s *priv); +static inline bool + lc823450_i2c_checkbusy(FAR struct lc823450_i2c_priv_s *priv); +static inline void + lc823450_i2c_prepxfer(FAR struct lc823450_i2c_priv_s *priv); +static inline void + lc823450_i2c_sendstart(FAR struct lc823450_i2c_priv_s *priv); +static inline void + lc823450_i2c_sendstop(FAR struct lc823450_i2c_priv_s *priv); +static inline uint32_t + lc823450_i2c_readdata(FAR struct lc823450_i2c_priv_s *priv); static void lc823450_i2c_starttransfer(FAR struct lc823450_i2c_priv_s *priv); static int lc823450_i2c_poll(FAR struct lc823450_i2c_priv_s *priv); @@ -172,7 +189,8 @@ static int lc823450_i2c_isr(int irq, FAR void *context, FAR void *arg); #endif static int lc823450_i2c_init(FAR struct lc823450_i2c_priv_s *priv, int port); -static int lc823450_i2c_deinit(FAR struct lc823450_i2c_priv_s *priv, int port); +static int + lc823450_i2c_deinit(FAR struct lc823450_i2c_priv_s *priv, int port); static int lc823450_i2c_transfer(FAR struct i2c_master_s *dev, FAR struct i2c_msg_s *msgs, int count); @@ -255,13 +273,14 @@ static struct lc823450_i2c_priv_s lc823450_i2c1_priv = * Name: lc823450_i2c_sem_wait * * Description: - * Take the exclusive access, waiting as necessary + * Take the exclusive access, waiting as necessary. May be interrupted by + * a signal. * ****************************************************************************/ -static inline void lc823450_i2c_sem_wait(FAR struct lc823450_i2c_priv_s *priv) +static inline int lc823450_i2c_sem_wait(FAR struct lc823450_i2c_priv_s *priv) { - nxsem_wait_uninterruptible(&priv->sem_excl); + return nxsem_wait(&priv->sem_excl); } /**************************************************************************** @@ -272,7 +291,8 @@ static inline void lc823450_i2c_sem_wait(FAR struct lc823450_i2c_priv_s *priv) * ****************************************************************************/ -static inline void lc823450_i2c_sem_post(FAR struct lc823450_i2c_priv_s *priv) +static inline void + lc823450_i2c_sem_post(FAR struct lc823450_i2c_priv_s *priv) { nxsem_post(&priv->sem_excl); } @@ -286,7 +306,8 @@ static inline void lc823450_i2c_sem_post(FAR struct lc823450_i2c_priv_s *priv) ****************************************************************************/ #ifndef CONFIG_I2C_POLLED -static inline int lc823450_i2c_sem_waitdone(FAR struct lc823450_i2c_priv_s *priv) +static inline int + lc823450_i2c_sem_waitdone(FAR struct lc823450_i2c_priv_s *priv) { struct timespec abstime; int ret; @@ -317,10 +338,10 @@ static inline int lc823450_i2c_sem_waitdone(FAR struct lc823450_i2c_priv_s *priv ret = nxsem_timedwait_uninterruptible(&priv->sem_isr, &abstime); if (ret < 0) { - /* Break out of the loop on irrecoverable errors. This would * include timeouts and mystery errors reported by nxsem_timedwait. */ + break; } } @@ -333,7 +354,8 @@ static inline int lc823450_i2c_sem_waitdone(FAR struct lc823450_i2c_priv_s *priv return ret; } #else -static inline int lc823450_i2c_sem_waitdone(FAR struct lc823450_i2c_priv_s *priv) +static inline int + lc823450_i2c_sem_waitdone(FAR struct lc823450_i2c_priv_s *priv) { uint32_t timeout; clock_t start; @@ -388,8 +410,11 @@ static inline int lc823450_i2c_sem_waitdone(FAR struct lc823450_i2c_priv_s *priv static void lc823450_i2c_prepxfer(FAR struct lc823450_i2c_priv_s *priv) { uint32_t base = priv->config->base; - putreg32(((lc823450_get_systemfreq() / priv->msgv->frequency + 7) / 8) & 0xffff, base + I2CCKS); - putreg32((priv->msgv->addr << 1) | (priv->msgv->flags & I2C_M_READ), base + I2CTXD); + putreg32(((lc823450_get_systemfreq() / priv->msgv->frequency + 7) / 8) & + 0xffff, + base + I2CCKS); + putreg32((priv->msgv->addr << 1) | (priv->msgv->flags & I2C_M_READ), + base + I2CTXD); } /**************************************************************************** @@ -400,7 +425,8 @@ static void lc823450_i2c_prepxfer(FAR struct lc823450_i2c_priv_s *priv) * ****************************************************************************/ -static inline bool lc823450_i2c_checkbusy(FAR struct lc823450_i2c_priv_s *priv) +static inline bool + lc823450_i2c_checkbusy(FAR struct lc823450_i2c_priv_s *priv) { return (getreg32(priv->config->base + I2CSTR) & I2C_STR_BBSY) != 0; } @@ -413,7 +439,8 @@ static inline bool lc823450_i2c_checkbusy(FAR struct lc823450_i2c_priv_s *priv) * ****************************************************************************/ -static inline bool lc823450_i2c_checkirq(FAR struct lc823450_i2c_priv_s *priv) +static inline bool + lc823450_i2c_checkirq(FAR struct lc823450_i2c_priv_s *priv) { return (getreg32(priv->config->base + I2CSTR) & I2C_STR_IREQ) != 0; } @@ -426,7 +453,8 @@ static inline bool lc823450_i2c_checkirq(FAR struct lc823450_i2c_priv_s *priv) * ****************************************************************************/ -static inline bool lc823450_i2c_checkack(FAR struct lc823450_i2c_priv_s *priv) +static inline bool + lc823450_i2c_checkack(FAR struct lc823450_i2c_priv_s *priv) { return (getreg32(priv->config->base + I2CSTR) & I2C_STR_ACKD) != 0; } @@ -439,7 +467,8 @@ static inline bool lc823450_i2c_checkack(FAR struct lc823450_i2c_priv_s *priv) * ****************************************************************************/ -static inline void lc823450_i2c_sendstart(FAR struct lc823450_i2c_priv_s *priv) +static inline void + lc823450_i2c_sendstart(FAR struct lc823450_i2c_priv_s *priv) { modifyreg32(priv->config->base + I2CCTL, I2C_CTL_TRX, I2C_CTL_TRX); modifyreg32(priv->config->base + I2CCTL, I2C_CTL_ST, I2C_CTL_ST); @@ -453,7 +482,8 @@ static inline void lc823450_i2c_sendstart(FAR struct lc823450_i2c_priv_s *priv) * ****************************************************************************/ -static inline void lc823450_i2c_sendstop(FAR struct lc823450_i2c_priv_s *priv) +static inline void + lc823450_i2c_sendstop(FAR struct lc823450_i2c_priv_s *priv) { modifyreg32(priv->config->base + I2CSTR, I2C_STR_IREQ, 0); modifyreg32(priv->config->base + I2CCTL, I2C_CTL_TRX, I2C_CTL_TRX); @@ -502,7 +532,8 @@ static int lc823450_i2c_reset(FAR struct i2c_master_s *dev) ****************************************************************************/ #ifndef CONFIG_I2C_POLLED -static inline void lc823450_i2c_enableirq(FAR struct lc823450_i2c_priv_s *priv) +static inline void + lc823450_i2c_enableirq(FAR struct lc823450_i2c_priv_s *priv) { modifyreg32(priv->config->base + I2CCTL, I2C_CTL_IREQEN, I2C_CTL_IREQEN); } @@ -517,7 +548,8 @@ static inline void lc823450_i2c_enableirq(FAR struct lc823450_i2c_priv_s *priv) ****************************************************************************/ #ifndef CONFIG_I2C_POLLED -static inline void lc823450_i2c_disableirq(FAR struct lc823450_i2c_priv_s *priv) +static inline void + lc823450_i2c_disableirq(FAR struct lc823450_i2c_priv_s *priv) { modifyreg32(priv->config->base + I2CCTL, I2C_CTL_IREQEN, 0); } @@ -531,7 +563,8 @@ static inline void lc823450_i2c_disableirq(FAR struct lc823450_i2c_priv_s *priv) * ****************************************************************************/ -static inline uint32_t lc823450_i2c_readdata(FAR struct lc823450_i2c_priv_s *priv) +static inline uint32_t + lc823450_i2c_readdata(FAR struct lc823450_i2c_priv_s *priv) { return getreg32(priv->config->base + I2CRXD); } @@ -558,8 +591,10 @@ static void lc823450_i2c_starttransfer(FAR struct lc823450_i2c_priv_s *priv) { /* If the next byte to be received is not final, we have to send ACK. */ - modifyreg32(priv->config->base + I2CCTL, I2C_CTL_ACK, I2C_CTL_ACK); - modifyreg32(priv->config->base + I2CCTL, I2C_CTL_BTRIG, I2C_CTL_BTRIG); + modifyreg32(priv->config->base + I2CCTL, I2C_CTL_ACK, + I2C_CTL_ACK); + modifyreg32(priv->config->base + I2CCTL, I2C_CTL_BTRIG, + I2C_CTL_BTRIG); } else if (priv->dcnt == 1) { @@ -567,19 +602,20 @@ static void lc823450_i2c_starttransfer(FAR struct lc823450_i2c_priv_s *priv) if (priv->msgc > 0 && priv->msgv->flags & I2C_M_READ) { - - /* But if there is a next message and the direction is READ, we have - * to send ACK. + /* But if there is a next message and the direction is READ, + * we have to send ACK. */ - modifyreg32(priv->config->base + I2CCTL, I2C_CTL_ACK, I2C_CTL_ACK); + modifyreg32(priv->config->base + I2CCTL, I2C_CTL_ACK, + I2C_CTL_ACK); } else { modifyreg32(priv->config->base + I2CCTL, I2C_CTL_ACK, 0); } - modifyreg32(priv->config->base + I2CCTL, I2C_CTL_BTRIG, I2C_CTL_BTRIG); + modifyreg32(priv->config->base + I2CCTL, I2C_CTL_BTRIG, + I2C_CTL_BTRIG); } priv->irqstate = IRQSTATE_WRECV; @@ -589,8 +625,10 @@ static void lc823450_i2c_starttransfer(FAR struct lc823450_i2c_priv_s *priv) if (priv->dcnt > 0) { putreg32(*priv->ptr, priv->config->base + I2CTXD); - modifyreg32(priv->config->base + I2CCTL, I2C_CTL_BTRIG, I2C_CTL_BTRIG); + modifyreg32(priv->config->base + I2CCTL, + I2C_CTL_BTRIG, I2C_CTL_BTRIG); } + priv->irqstate = IRQSTATE_WSEND; } } @@ -660,7 +698,9 @@ static int lc823450_i2c_poll(FAR struct lc823450_i2c_priv_s *priv) priv->msgv++; priv->msgc--; - i2cinfo("WSTART (dcnt=%d flags=%xh msgc=%d)\n", priv->dcnt, priv->flags, priv->msgc); + + i2cinfo("WSTART (dcnt=%d flags=%xh msgc=%d)\n", + priv->dcnt, priv->flags, priv->msgc); lc823450_i2c_starttransfer(priv); } @@ -681,9 +721,9 @@ static int lc823450_i2c_poll(FAR struct lc823450_i2c_priv_s *priv) } else if (priv->irqstate == IRQSTATE_WRECV) { - /* When the master is receiver, it shall send ACK instead of the slave when - * it receives data. In this case, it don't have to check if ACK comes, - * because the slave does not send ACK. + /* When the master is receiver, it shall send ACK instead of the slave + * when it receives data. In this case, it don't have to check if + * ACK comes, because the slave does not send ACK. */ *priv->ptr++ = lc823450_i2c_readdata(priv); @@ -743,24 +783,25 @@ static int lc823450_i2c_poll(FAR struct lc823450_i2c_priv_s *priv) } else { - /* We need restart from START condition. If transfer direction is different - * between current message and next message, restart is necessary. + /* We need restart from START condition. If transfer direction + * is different between current message and next message, + * restart is necessary. */ i2cinfo("re-START condition\n"); #ifdef CONFIG_I2C_RESET - /* Reset I2C bus by softreset. There is not description of the reset, - * but in order to recover I2C bus busy, it must be done. - * Please refer to macaron's code. + /* Reset I2C bus by softreset. There is not description of the + * reset, but in order to recover I2C bus busy, it must be + * done. Please refer to macaron's code. */ lc823450_i2c_reset((FAR struct i2c_master_s *)priv); #endif #ifndef CONFIG_I2C_POLLED - /* We have to enable interrupt again, because all registers are reset by - * lc823450_i2c_reset(). + /* We have to enable interrupt again, because all registers + * are reset by lc823450_i2c_reset(). */ lc823450_i2c_enableirq(priv); @@ -774,8 +815,8 @@ static int lc823450_i2c_poll(FAR struct lc823450_i2c_priv_s *priv) } else if (priv->msgv) { - /* There are no other message. We send STOP condition because all messages - * are transferred. + /* There are no other message. We send STOP condition because all + * messages are transferred. */ i2cinfo("STOP condition\n"); @@ -881,7 +922,8 @@ static int lc823450_i2c_init(FAR struct lc823450_i2c_priv_s *priv, int port) * ****************************************************************************/ -static int lc823450_i2c_deinit(FAR struct lc823450_i2c_priv_s *priv, int port) +static int lc823450_i2c_deinit(FAR struct lc823450_i2c_priv_s *priv, + int port) { /* Disable I2C */ @@ -962,9 +1004,13 @@ static int lc823450_i2c_transfer(FAR struct i2c_master_s *dev, return -EINVAL; } - /* ensure that address or flags don't change meanwhile */ + /* Ensure that address or flags don't change meanwhile */ - lc823450_i2c_sem_wait(priv); + ret = lc823450_i2c_sem_wait(priv); + if (ret < 0) + { + return ret; + } priv->timedout = false; @@ -1008,7 +1054,6 @@ static int lc823450_i2c_transfer(FAR struct i2c_master_s *dev, if (lc823450_i2c_sem_waitdone(priv) < 0) { - irqs = enter_critical_section(); ret = -ETIMEDOUT; @@ -1032,7 +1077,8 @@ static int lc823450_i2c_transfer(FAR struct i2c_master_s *dev, } else { - i2cerr("No need of timeout handling. It may be done in irq handler\n"); + i2cerr("No need of timeout handling. " + "It may be done in irq handler\n"); leave_critical_section(irqs); } @@ -1058,7 +1104,6 @@ exit: lc823450_i2c_sem_post(priv); return ret; - } /**************************************************************************** @@ -1185,7 +1230,8 @@ int lc823450_i2cbus_uninitialize(FAR struct i2c_master_s *dev) * Name: lc823450_i2cbus_changetimeout ****************************************************************************/ -void lc823450_i2cbus_changetimeout(FAR struct i2c_master_s *dev, uint32_t timeoms) +void lc823450_i2cbus_changetimeout(FAR struct i2c_master_s *dev, + uint32_t timeoms) { FAR struct lc823450_i2c_priv_s *priv = (struct lc823450_i2c_priv_s *)dev; priv->timeoms = timeoms; diff --git a/arch/arm/src/s32k1xx/s32k1xx_lpi2c.c b/arch/arm/src/s32k1xx/s32k1xx_lpi2c.c index cb012c397d0..b8b8398e027 100644 --- a/arch/arm/src/s32k1xx/s32k1xx_lpi2c.c +++ b/arch/arm/src/s32k1xx/s32k1xx_lpi2c.c @@ -166,11 +166,11 @@ enum s32k1xx_trace_e struct s32k1xx_trace_s { - uint32_t status; /* I2C 32-bit SR2|SR1 status */ - uint32_t count; /* Interrupt count when status change */ + uint32_t status; /* I2C 32-bit SR2|SR1 status */ + uint32_t count; /* Interrupt count when status change */ enum s32k1xx_intstate_e event; /* Last event that occurred with this status */ - uint32_t parm; /* Parameter associated with the event */ - clock_t time; /* First of event or first status */ + uint32_t parm; /* Parameter associated with the event */ + clock_t time; /* First of event or first status */ }; /* I2C Device hardware configuration */ @@ -193,8 +193,14 @@ struct s32k1xx_lpi2c_config_s struct s32k1xx_lpi2c_priv_s { - const struct i2c_ops_s *ops; /* Standard I2C operations */ - const struct s32k1xx_lpi2c_config_s *config; /* Port configuration */ + /* Standard I2C operations */ + + const struct i2c_ops_s *ops; + + /* Port configuration */ + + const struct s32k1xx_lpi2c_config_s *config; + int refs; /* Reference count */ sem_t sem_excl; /* Mutual exclusion semaphore */ #ifndef CONFIG_I2C_POLLED @@ -227,41 +233,58 @@ struct s32k1xx_lpi2c_priv_s * Private Function Prototypes ****************************************************************************/ -static inline uint32_t s32k1xx_lpi2c_getreg(FAR struct s32k1xx_lpi2c_priv_s *priv, - uint16_t offset); -static inline void s32k1xx_lpi2c_putreg(FAR struct s32k1xx_lpi2c_priv_s *priv, - uint16_t offset, uint32_t value); -static inline void s32k1xx_lpi2c_modifyreg(FAR struct s32k1xx_lpi2c_priv_s *priv, - uint16_t offset, uint32_t clearbits, - uint32_t setbits); -static inline void s32k1xx_lpi2c_sem_wait(FAR struct s32k1xx_lpi2c_priv_s *priv); +static inline uint32_t + s32k1xx_lpi2c_getreg(FAR struct s32k1xx_lpi2c_priv_s *priv, + uint16_t offset); +static inline void + s32k1xx_lpi2c_putreg(FAR struct s32k1xx_lpi2c_priv_s *priv, + uint16_t offset, uint32_t value); +static inline void + s32k1xx_lpi2c_modifyreg(FAR struct s32k1xx_lpi2c_priv_s *priv, + uint16_t offset, uint32_t clearbits, + uint32_t setbits); +static inline int + s32k1xx_lpi2c_sem_wait(FAR struct s32k1xx_lpi2c_priv_s *priv); +static int + s32k1xx_lpi2c_sem_wait_uninterruptible( + FAR struct s32k1xx_lpi2c_priv_s *priv); #ifdef CONFIG_S32K1XX_I2C_DYNTIMEO -static useconds_t s32k1xx_lpi2c_tousecs(int msgc, FAR struct i2c_msg_s *msgs); +static useconds_t + s32k1xx_lpi2c_tousecs(int msgc, FAR struct i2c_msg_s *msgs); #endif /* CONFIG_S32K1XX_I2C_DYNTIMEO */ -static inline int s32k1xx_lpi2c_sem_waitdone(FAR struct s32k1xx_lpi2c_priv_s *priv); -static inline void s32k1xx_lpi2c_sem_waitstop(FAR struct s32k1xx_lpi2c_priv_s *priv); -static inline void s32k1xx_lpi2c_sem_post(FAR struct s32k1xx_lpi2c_priv_s *priv); -static inline void s32k1xx_lpi2c_sem_init(FAR struct s32k1xx_lpi2c_priv_s *priv); -static inline void s32k1xx_lpi2c_sem_destroy(FAR struct s32k1xx_lpi2c_priv_s *priv); +static inline int + s32k1xx_lpi2c_sem_waitdone(FAR struct s32k1xx_lpi2c_priv_s *priv); +static inline void + s32k1xx_lpi2c_sem_waitstop(FAR struct s32k1xx_lpi2c_priv_s *priv); +static inline void + s32k1xx_lpi2c_sem_post(FAR struct s32k1xx_lpi2c_priv_s *priv); +static inline void + s32k1xx_lpi2c_sem_init(FAR struct s32k1xx_lpi2c_priv_s *priv); +static inline void + s32k1xx_lpi2c_sem_destroy(FAR struct s32k1xx_lpi2c_priv_s *priv); #ifdef CONFIG_I2C_TRACE static void s32k1xx_lpi2c_tracereset(FAR struct s32k1xx_lpi2c_priv_s *priv); static void s32k1xx_lpi2c_tracenew(FAR struct s32k1xx_lpi2c_priv_s *priv, uint32_t status); static void s32k1xx_lpi2c_traceevent(FAR struct s32k1xx_lpi2c_priv_s *priv, - enum s32k1xx_trace_e event, uint32_t parm); + enum s32k1xx_trace_e event, + uint32_t parm); static void s32k1xx_lpi2c_tracedump(FAR struct s32k1xx_lpi2c_priv_s *priv); #endif /* CONFIG_I2C_TRACE */ static uint32_t s32k1xx_lpi2c_pckfreq(uintptr_t base); static void s32k1xx_lpi2c_setclock(FAR struct s32k1xx_lpi2c_priv_s *priv, uint32_t frequency); -static inline void s32k1xx_lpi2c_sendstart(FAR struct s32k1xx_lpi2c_priv_s *priv, - uint8_t address); -static inline void s32k1xx_lpi2c_sendstop(FAR struct s32k1xx_lpi2c_priv_s *priv); -static inline uint32_t s32k1xx_lpi2c_getstatus(FAR struct s32k1xx_lpi2c_priv_s *priv); +static inline void + s32k1xx_lpi2c_sendstart(FAR struct s32k1xx_lpi2c_priv_s *priv, + uint8_t address); +static inline void + s32k1xx_lpi2c_sendstop(FAR struct s32k1xx_lpi2c_priv_s *priv); +static inline uint32_t + s32k1xx_lpi2c_getstatus(FAR struct s32k1xx_lpi2c_priv_s *priv); static int s32k1xx_lpi2c_isr_process(struct s32k1xx_lpi2c_priv_s * priv); @@ -389,8 +412,9 @@ static struct s32k1xx_lpi2c_priv_s s32k1xx_lpi2c1_priv = * ****************************************************************************/ -static inline uint32_t s32k1xx_lpi2c_getreg(FAR struct s32k1xx_lpi2c_priv_s *priv, - uint16_t offset) +static inline uint32_t + s32k1xx_lpi2c_getreg(FAR struct s32k1xx_lpi2c_priv_s *priv, + uint16_t offset) { return getreg32(priv->config->base + offset); } @@ -403,8 +427,9 @@ static inline uint32_t s32k1xx_lpi2c_getreg(FAR struct s32k1xx_lpi2c_priv_s *pri * ****************************************************************************/ -static inline void s32k1xx_lpi2c_putreg(FAR struct s32k1xx_lpi2c_priv_s *priv, - uint16_t offset, uint32_t value) +static inline void + s32k1xx_lpi2c_putreg(FAR struct s32k1xx_lpi2c_priv_s *priv, + uint16_t offset, uint32_t value) { putreg32(value, priv->config->base + offset); } @@ -417,9 +442,10 @@ static inline void s32k1xx_lpi2c_putreg(FAR struct s32k1xx_lpi2c_priv_s *priv, * ****************************************************************************/ -static inline void s32k1xx_lpi2c_modifyreg(FAR struct s32k1xx_lpi2c_priv_s *priv, - uint16_t offset, uint32_t clearbits, - uint32_t setbits) +static inline void + s32k1xx_lpi2c_modifyreg(FAR struct s32k1xx_lpi2c_priv_s *priv, + uint16_t offset, uint32_t clearbits, + uint32_t setbits) { modifyreg32(priv->config->base + offset, clearbits, setbits); } @@ -428,13 +454,30 @@ static inline void s32k1xx_lpi2c_modifyreg(FAR struct s32k1xx_lpi2c_priv_s *priv * Name: s32k1xx_lpi2c_sem_wait * * Description: + * Take the exclusive access, waiting as necessary. May be interrupted by + * a signal. + * + ****************************************************************************/ + +static inline int + s32k1xx_lpi2c_sem_wait(FAR struct s32k1xx_lpi2c_priv_s *priv) +{ + return nxsem_wait(&priv->sem_excl); +} + +/**************************************************************************** + * Name: s32k1xx_lpi2c_sem_wait_uninterruptible + * + * Description: * Take the exclusive access, waiting as necessary * ****************************************************************************/ -static inline void s32k1xx_lpi2c_sem_wait(FAR struct s32k1xx_lpi2c_priv_s *priv) +static int + s32k1xx_lpi2c_sem_wait_uninterruptible( + FAR struct s32k1xx_lpi2c_priv_s *priv) { - nxsem_wait_uninterruptible(&priv->sem_excl); + return nxsem_wait_uninterruptible(&priv->sem_excl); } /**************************************************************************** @@ -476,7 +519,8 @@ static useconds_t s32k1xx_lpi2c_tousecs(int msgc, FAR struct i2c_msg_s *msgs) ****************************************************************************/ #ifndef CONFIG_I2C_POLLED -static inline int s32k1xx_lpi2c_sem_waitdone(FAR struct s32k1xx_lpi2c_priv_s *priv) +static inline int + s32k1xx_lpi2c_sem_waitdone(FAR struct s32k1xx_lpi2c_priv_s *priv) { struct timespec abstime; irqstate_t flags; @@ -531,7 +575,9 @@ static inline int s32k1xx_lpi2c_sem_waitdone(FAR struct s32k1xx_lpi2c_priv_s *pr /* Add a value proportional to the number of bytes in the transfer */ #ifdef CONFIG_S32K1XX_I2C_DYNTIMEO - abstime.tv_nsec += 1000 * s32k1xx_lpi2c_tousecs(priv->msgc, priv->msgv); + abstime.tv_nsec += + 1000 * s32k1xx_lpi2c_tousecs(priv->msgc, priv->msgv); + if (abstime.tv_nsec >= 1000 * 1000 * 1000) { abstime.tv_sec++; @@ -588,7 +634,8 @@ static inline int s32k1xx_lpi2c_sem_waitdone(FAR struct s32k1xx_lpi2c_priv_s *pr return ret; } #else -static inline int s32k1xx_lpi2c_sem_waitdone(FAR struct s32k1xx_lpi2c_priv_s *priv) +static inline int + s32k1xx_lpi2c_sem_waitdone(FAR struct s32k1xx_lpi2c_priv_s *priv) { clock_t timeout; clock_t start; @@ -647,7 +694,8 @@ static inline int s32k1xx_lpi2c_sem_waitdone(FAR struct s32k1xx_lpi2c_priv_s *pr * ****************************************************************************/ -static inline void s32k1xx_lpi2c_sem_waitstop(FAR struct s32k1xx_lpi2c_priv_s *priv) +static inline void + s32k1xx_lpi2c_sem_waitstop(FAR struct s32k1xx_lpi2c_priv_s *priv) { clock_t start; clock_t elapsed; @@ -748,7 +796,8 @@ static inline void s32k1xx_lpi2c_sem_post(struct s32k1xx_lpi2c_priv_s *priv) * ****************************************************************************/ -static inline void s32k1xx_lpi2c_sem_init(FAR struct s32k1xx_lpi2c_priv_s *priv) +static inline void + s32k1xx_lpi2c_sem_init(FAR struct s32k1xx_lpi2c_priv_s *priv) { nxsem_init(&priv->sem_excl, 0, 1); @@ -770,7 +819,8 @@ static inline void s32k1xx_lpi2c_sem_init(FAR struct s32k1xx_lpi2c_priv_s *priv) * ****************************************************************************/ -static inline void s32k1xx_lpi2c_sem_destroy(FAR struct s32k1xx_lpi2c_priv_s *priv) +static inline void + s32k1xx_lpi2c_sem_destroy(FAR struct s32k1xx_lpi2c_priv_s *priv) { nxsem_destroy(&priv->sem_excl); #ifndef CONFIG_I2C_POLLED @@ -886,8 +936,10 @@ static void s32k1xx_lpi2c_tracedump(FAR struct s32k1xx_lpi2c_priv_s *priv) { trace = &priv->trace[i]; syslog(LOG_DEBUG, - "%2d. STATUS: %08x COUNT: %3d EVENT: %s(%2d) PARM: %08x TIME: %d\n", - i + 1, trace->status, trace->count, g_trace_names[trace->event], + "%2d. STATUS: %08x COUNT: %3d EVENT: %s(%2d) PARM: %08x " + "TIME: %d\n", + i + 1, trace->status, trace->count, + g_trace_names[trace->event], trace->event, trace->parm, trace->time - priv->start_time); } } @@ -1090,8 +1142,9 @@ static void s32k1xx_lpi2c_setclock(FAR struct s32k1xx_lpi2c_priv_s *priv, * ****************************************************************************/ -static inline void s32k1xx_lpi2c_sendstart(FAR struct s32k1xx_lpi2c_priv_s *priv, - uint8_t address) +static inline void + s32k1xx_lpi2c_sendstart(FAR struct s32k1xx_lpi2c_priv_s *priv, + uint8_t address) { uint32_t txcount = 0; uint32_t status = 0; @@ -1141,7 +1194,8 @@ static inline void s32k1xx_lpi2c_sendstart(FAR struct s32k1xx_lpi2c_priv_s *priv * ****************************************************************************/ -static inline void s32k1xx_lpi2c_sendstop(FAR struct s32k1xx_lpi2c_priv_s *priv) +static inline void + s32k1xx_lpi2c_sendstop(FAR struct s32k1xx_lpi2c_priv_s *priv) { s32k1xx_lpi2c_putreg(priv, S32K1XX_LPI2C_MTDR_OFFSET, LPI2C_MTDR_CMD_STOP); } @@ -1154,7 +1208,8 @@ static inline void s32k1xx_lpi2c_sendstop(FAR struct s32k1xx_lpi2c_priv_s *priv) * ****************************************************************************/ -static inline uint32_t s32k1xx_lpi2c_getstatus(FAR struct s32k1xx_lpi2c_priv_s *priv) +static inline uint32_t + s32k1xx_lpi2c_getstatus(FAR struct s32k1xx_lpi2c_priv_s *priv) { return s32k1xx_lpi2c_getreg(priv, S32K1XX_LPI2C_MSR_OFFSET); } @@ -1185,7 +1240,8 @@ static int s32k1xx_lpi2c_isr_process(struct s32k1xx_lpi2c_priv_s *priv) /* Check if there is more bytes to send */ - else if (((priv->flags & I2C_M_READ) == 0) && (status & LPI2C_MSR_TDF) != 0) + else if (((priv->flags & I2C_M_READ) == 0) && + (status & LPI2C_MSR_TDF) != 0) { if (priv->dcnt > 0) { @@ -1204,7 +1260,8 @@ static int s32k1xx_lpi2c_isr_process(struct s32k1xx_lpi2c_priv_s *priv) /* Check if there is more bytes to read */ - else if (((priv->flags & I2C_M_READ) != 0) && (status & LPI2C_MSR_RDF) != 0) + else if (((priv->flags & I2C_M_READ) != 0) && + (status & LPI2C_MSR_RDF) != 0) { /* Read a byte, if dcnt goes < 0, then read dummy bytes to ack ISRs */ @@ -1222,8 +1279,10 @@ static int s32k1xx_lpi2c_isr_process(struct s32k1xx_lpi2c_priv_s *priv) /* Receive a byte */ - *priv->ptr++ = s32k1xx_lpi2c_getreg(priv, S32K1XX_LPI2C_MRDR_OFFSET) & - LPI2C_MRDR_DATA_MASK; + *priv->ptr++ = + s32k1xx_lpi2c_getreg(priv, S32K1XX_LPI2C_MRDR_OFFSET) & + LPI2C_MRDR_DATA_MASK; + priv->dcnt--; #ifdef CONFIG_I2C_POLLED @@ -1516,13 +1575,17 @@ static int s32k1xx_lpi2c_transfer(FAR struct i2c_master_s *dev, FAR struct i2c_msg_s *msgs, int count) { FAR struct s32k1xx_lpi2c_priv_s *priv = (struct s32k1xx_lpi2c_priv_s *)dev; - int ret = 0; + int ret; DEBUGASSERT(count > 0); /* Ensure that address or flags don't change meanwhile */ - s32k1xx_lpi2c_sem_wait(priv); + ret = s32k1xx_lpi2c_sem_wait(priv); + if (ret < 0) + { + return ret; + } /* Clear any pending error interrupts */ @@ -1625,13 +1688,14 @@ static int s32k1xx_lpi2c_transfer(FAR struct i2c_master_s *dev, #ifdef CONFIG_I2C_RESET static int s32k1xx_lpi2c_reset(FAR struct i2c_master_s *dev) { - FAR struct s32k1xx_lpi2c_priv_s *priv = (FAR struct s32k1xx_lpi2c_priv_s *)dev; + FAR struct s32k1xx_lpi2c_priv_s *priv = + (FAR struct s32k1xx_lpi2c_priv_s *)dev; unsigned int clock_count; unsigned int stretch_count; uint32_t scl_gpio; uint32_t sda_gpio; uint32_t frequency; - int ret = ERROR; + int ret; DEBUGASSERT(dev); @@ -1641,7 +1705,13 @@ static int s32k1xx_lpi2c_reset(FAR struct i2c_master_s *dev) /* Lock out other clients */ - s32k1xx_lpi2c_sem_wait(priv); + ret = s32k1xx_lpi2c_sem_wait_uninterruptible(priv); + if (ret < 0) + { + return ret; + } + + ret = -EIO; /* Save the current frequency */ diff --git a/arch/arm/src/sam34/sam_twi.c b/arch/arm/src/sam34/sam_twi.c index 46e34249997..fced91c3f65 100644 --- a/arch/arm/src/sam34/sam_twi.c +++ b/arch/arm/src/sam34/sam_twi.c @@ -78,7 +78,8 @@ /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ -/* Configuration ***************************************************************/ + +/* Configuration ************************************************************/ #ifndef CONFIG_SAM34_TWIM0_FREQUENCY # define CONFIG_SAM34_TWIM0_FREQUENCY 100000 @@ -92,12 +93,12 @@ # undef CONFIG_SAM34_TWI_REGDEBUG #endif -/* Driver internal definitions *************************************************/ +/* Driver internal definitions **********************************************/ #define TWI_TIMEOUT ((100 * CLK_TCK) / 1000) /* 100 mS */ -/* Clocking to the TWO module(s) is provided by the main clocked, divided down - * as necessary. +/* Clocking to the TWO module(s) is provided by the main clocked, divided + * down as necessary. */ #define TWI_MAX_FREQUENCY 66000000 /* Maximum TWI frequency */ @@ -127,10 +128,10 @@ struct twi_dev_s /* Debug stuff */ #ifdef CONFIG_SAM34_TWI_REGDEBUG - bool wrlast; /* Last was a write */ - uint32_t addrlast; /* Last address */ - uint32_t vallast; /* Last value */ - int ntimes; /* Number of times */ + bool wrlast; /* Last was a write */ + uint32_t addrlast; /* Last address */ + uint32_t vallast; /* Last value */ + int ntimes; /* Number of times */ #endif }; @@ -206,14 +207,14 @@ static const struct i2c_ops_s g_twiops = }; /**************************************************************************** - * Low-level Helpers + * Private Functions ****************************************************************************/ + /**************************************************************************** * Name: twi_takesem * * Description: - * Take the wait semaphore (handling false alarm wake-ups due to the receipt - * of signals). + * Take the wait semaphore. May be interrupted by a signal. * * Input Parameters: * dev - Instance of the SDIO device driver state structure. @@ -223,9 +224,9 @@ static const struct i2c_ops_s g_twiops = * ****************************************************************************/ -static void twi_takesem(sem_t *sem) +static int twi_takesem(sem_t *sem) { - nxsem_wait_uninterruptible(sem); + return nxsem_wait(sem); } /**************************************************************************** @@ -333,7 +334,8 @@ static void twi_putabs(struct twi_dev_s *priv, uintptr_t address, * ****************************************************************************/ -static inline uint32_t twi_getrel(struct twi_dev_s *priv, unsigned int offset) +static inline uint32_t twi_getrel(struct twi_dev_s *priv, + unsigned int offset) { return twi_getabs(priv, priv->base + offset); } @@ -370,6 +372,8 @@ static inline void twi_putrel(struct twi_dev_s *priv, unsigned int offset, static int twi_wait(struct twi_dev_s *priv) { + int ret; + /* Start a timeout to avoid hangs */ wd_start(priv->timeout, TWI_TIMEOUT, twi_timeout, 1, (uint32_t)priv); @@ -379,8 +383,14 @@ static int twi_wait(struct twi_dev_s *priv) do { i2cinfo("TWI%d Waiting...\n", priv->twi); - twi_takesem(&priv->waitsem); + ret = twi_takesem(&priv->waitsem); i2cinfo("TWI%d Awakened with result: %d\n", priv->twi, priv->result); + + if (ret < 0) + { + wd_cancel(priv->timeout); + return ret; + } } while (priv->result == -EBUSY); @@ -588,7 +598,8 @@ static void twi_startread(struct twi_dev_s *priv, struct i2c_msg_s *msg) /* Set slave address and number of internal address bytes. */ twi_putrel(priv, SAM_TWI_MMR_OFFSET, 0); - twi_putrel(priv, SAM_TWI_MMR_OFFSET, TWI_MMR_IADRSZ_NONE | TWI_MMR_MREAD | TWI_MMR_DADR(msg->addr)); + twi_putrel(priv, SAM_TWI_MMR_OFFSET, + TWI_MMR_IADRSZ_NONE | TWI_MMR_MREAD | TWI_MMR_DADR(msg->addr)); /* Set internal address bytes (not used) */ @@ -618,7 +629,8 @@ static void twi_startwrite(struct twi_dev_s *priv, struct i2c_msg_s *msg) /* Set slave address and number of internal address bytes. */ twi_putrel(priv, SAM_TWI_MMR_OFFSET, 0); - twi_putrel(priv, SAM_TWI_MMR_OFFSET, TWI_MMR_IADRSZ_NONE | TWI_MMR_DADR(msg->addr)); + twi_putrel(priv, SAM_TWI_MMR_OFFSET, + TWI_MMR_IADRSZ_NONE | TWI_MMR_DADR(msg->addr)); /* Set internal address bytes (not used) */ @@ -678,18 +690,22 @@ static int twi_transfer(FAR struct i2c_master_s *dev, /* Get exclusive access to the device */ - twi_takesem(&priv->exclsem); + ret = twi_takesem(&priv->exclsem); + if (ret < 0) + { + return ret; + } /* 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. - */ + /* 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); @@ -716,7 +732,7 @@ static int twi_transfer(FAR struct i2c_master_s *dev, return ret; } -/************************************************************************************ +/**************************************************************************** * Name: twi_reset * * Description: @@ -728,7 +744,7 @@ static int twi_transfer(FAR struct i2c_master_s *dev, * 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) diff --git a/arch/arm/src/sama5/sam_twi.c b/arch/arm/src/sama5/sam_twi.c index 32ab61630e7..94f2bd92fa2 100644 --- a/arch/arm/src/sama5/sam_twi.c +++ b/arch/arm/src/sama5/sam_twi.c @@ -78,7 +78,8 @@ /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ -/* Configuration ***************************************************************/ + +/* Configuration ************************************************************/ #ifndef CONFIG_SAMA5_TWI0_FREQUENCY # define CONFIG_SAMA5_TWI0_FREQUENCY 100000 @@ -100,12 +101,14 @@ # undef CONFIG_SAMA5_TWI_REGDEBUG #endif -/* Driver internal definitions *************************************************/ -/* If verbose I2C debug output is enabled, then allow more time before we declare - * a timeout. The debug output from twi_interrupt will really slow things down! +/* Driver internal definitions **********************************************/ + +/* If verbose I2C debug output is enabled, then allow more time before we + * declare a timeout. The debug output from twi_interrupt will really slow + * things down! * - * With a very slow clock (say 100,000 Hz), less than 100 usec would be required - * to transfer on byte. So these define a "long" timeout. + * With a very slow clock (say 100,000 Hz), less than 100 usec would be + * required to transfer on byte. So these define a "long" timeout. */ #ifdef CONFIG_DEBUG_I2C_INFO @@ -131,6 +134,7 @@ /**************************************************************************** * Private Types ****************************************************************************/ + /* Invariant attributes of a TWI bus */ struct twi_attr_s @@ -164,10 +168,10 @@ struct twi_dev_s /* Debug stuff */ #ifdef CONFIG_SAMA5_TWI_REGDEBUG - bool wrlast; /* Last was a write */ - uint32_t addrlast; /* Last address */ - uint32_t vallast; /* Last value */ - int ntimes; /* Number of times */ + bool wrlast; /* Last was a write */ + uint32_t addrlast; /* Last address */ + uint32_t vallast; /* Last value */ + int ntimes; /* Number of times */ #endif }; @@ -177,7 +181,8 @@ struct twi_dev_s /* Low-level helper functions */ -static void twi_takesem(sem_t *sem); +static int twi_takesem(sem_t *sem); +static int twi_takesem_uninterruptible(sem_t *sem); #define twi_givesem(sem) (nxsem_post(sem)) #ifdef CONFIG_SAMA5_TWI_REGDEBUG @@ -290,14 +295,14 @@ static const struct i2c_ops_s g_twiops = }; /**************************************************************************** - * Low-level Helpers + * Private Functions ****************************************************************************/ + /**************************************************************************** * Name: twi_takesem * * Description: - * Take the wait semaphore (handling false alarm wake-ups due to the receipt - * of signals). + * Take the wait semaphore. May be interrupted by a signal. * * Input Parameters: * dev - Instance of the SDIO device driver state structure. @@ -307,9 +312,29 @@ static const struct i2c_ops_s g_twiops = * ****************************************************************************/ -static void twi_takesem(sem_t *sem) +static int twi_takesem(sem_t *sem) { - nxsem_wait_uninterruptible(sem); + return nxsem_wait(sem); +} + +/**************************************************************************** + * Name: twi_takesem_uninterruptible + * + * Description: + * Take the wait semaphore (handling false alarm wake-ups due to the + * receipt of signals). + * + * Input Parameters: + * dev - Instance of the SDIO device driver state structure. + * + * Returned Value: + * None + * + ****************************************************************************/ + +static int twi_takesem_uninterruptible(sem_t *sem) +{ + return nxsem_wait_uninterruptible(sem); } /**************************************************************************** @@ -417,7 +442,8 @@ static void twi_putabs(struct twi_dev_s *priv, uintptr_t address, * ****************************************************************************/ -static inline uint32_t twi_getrel(struct twi_dev_s *priv, unsigned int offset) +static inline uint32_t twi_getrel(struct twi_dev_s *priv, + unsigned int offset) { return twi_getabs(priv, priv->attr->base + offset); } @@ -455,12 +481,14 @@ static inline void twi_putrel(struct twi_dev_s *priv, unsigned int offset, static int twi_wait(struct twi_dev_s *priv, unsigned int size) { uint32_t timeout; + int ret; /* Calculate a timeout value based on the size of the transfer * * ticks = msec-per-byte * bytes / msec-per-tick * - * There is no concern about arithmetic overflow for reasonable transfer sizes. + * There is no concern about arithmetic overflow for reasonable transfer + * sizes. */ timeout = MSEC2TICK(TWI_TIMEOUT_MSPB); @@ -469,8 +497,8 @@ static int twi_wait(struct twi_dev_s *priv, unsigned int size) timeout = 1; } - /* Then start the timeout. This timeout is needed to avoid hangs if/when an - * TWI transfer stalls. + /* Then start the timeout. This timeout is needed to avoid hangs if/when + * a TWI transfer stalls. */ wd_start(priv->timeout, timeout, twi_timeout, 1, (uint32_t)priv); @@ -480,9 +508,15 @@ static int twi_wait(struct twi_dev_s *priv, unsigned int size) do { i2cinfo("TWI%d Waiting...\n", priv->attr->twi); - twi_takesem(&priv->waitsem); + ret = twi_takesem(&priv->waitsem); i2cinfo("TWI%d Awakened with result: %d\n", priv->attr->twi, priv->result); + + if (ret < 0) + { + wd_cancel(priv->timeout); + return ret; + } } while (priv->result == -EBUSY); @@ -720,7 +754,8 @@ static void twi_startwrite(struct twi_dev_s *priv, struct i2c_msg_s *msg) /* Set slave address and number of internal address bytes. */ twi_putrel(priv, SAM_TWI_MMR_OFFSET, 0); - twi_putrel(priv, SAM_TWI_MMR_OFFSET, TWI_MMR_IADRSZ_NONE | TWI_MMR_DADR(msg->addr)); + twi_putrel(priv, SAM_TWI_MMR_OFFSET, + TWI_MMR_IADRSZ_NONE | TWI_MMR_DADR(msg->addr)); /* Set internal address bytes (not used) */ @@ -797,18 +832,22 @@ static int twi_transfer(FAR struct i2c_master_s *dev, /* Get exclusive access to the device */ - twi_takesem(&priv->exclsem); + ret = twi_takesem(&priv->exclsem); + if (ret < 0) + { + return ret; + } /* 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. - */ + /* 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); @@ -835,7 +874,7 @@ static int twi_transfer(FAR struct i2c_master_s *dev, return ret; } -/************************************************************************************ +/**************************************************************************** * Name: twi_reset * * Description: @@ -847,7 +886,7 @@ static int twi_transfer(FAR struct i2c_master_s *dev, * 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) @@ -863,7 +902,11 @@ static int twi_reset(FAR struct i2c_master_s *dev) /* Get exclusive access to the TWI device */ - twi_takesem(&priv->exclsem); + ret = twi_takesem_uninterruptible(&priv->exclsem); + if (ret < 0) + { + return ret; + } /* Disable TWI interrupts */ @@ -1056,8 +1099,8 @@ static void twi_setfrequency(struct twi_dev_s *priv, uint32_t frequency) * * Description: * Initialize/Re-initialize the TWI peripheral. This logic performs only - * repeatable initialization after either (1) the one-time initialization, or - * (2) after each bus reset. + * repeatable initialization after either (1) the one-time initialization, + * or (2) after each bus reset. * ****************************************************************************/ diff --git a/arch/arm/src/samd2l2/sam_i2c_master.c b/arch/arm/src/samd2l2/sam_i2c_master.c index d6cf5ba29ca..b4e031f0544 100644 --- a/arch/arm/src/samd2l2/sam_i2c_master.c +++ b/arch/arm/src/samd2l2/sam_i2c_master.c @@ -163,12 +163,12 @@ struct i2c_attr_s struct sam_i2c_dev_s { - struct i2c_master_s dev; /* I2C master device */ - const struct i2c_attr_s *attr; /* Invariant attributes of I2C device */ - struct i2c_msg_s *msg; /* Current message being processed */ - uint32_t frequency; /* I2C transfer clock frequency */ - uint16_t flags; /* Transfer flags */ - uint16_t nextflags; /* Next message flags */ + struct i2c_master_s dev; /* I2C master device */ + const struct i2c_attr_s *attr; /* Invariant attributes of I2C device */ + struct i2c_msg_s *msg; /* Current message being processed */ + uint32_t frequency; /* I2C transfer clock frequency */ + uint16_t flags; /* Transfer flags */ + uint16_t nextflags; /* Next message flags */ sem_t exclsem; /* Only one thread can access at a time */ sem_t waitsem; /* Wait for I2C transfer completion */ @@ -201,7 +201,8 @@ static uint32_t i2c_getreg32(struct sam_i2c_dev_s *priv, unsigned int offset); static void i2c_putreg32(struct sam_i2c_dev_s *priv, uint32_t regval, unsigned int offset); -static void i2c_takesem(sem_t * sem); +static int i2c_takesem(sem_t * sem); +static int i2c_takesem_uninterruptible(sem_t * sem); #define i2c_givesem(sem) (nxsem_post(sem)) #ifdef CONFIG_SAM_I2C_REGDEBUG @@ -363,7 +364,7 @@ struct i2c_ops_s g_i2cops = }; /******************************************************************************* - * Low-level Helpers + * Private Functions *******************************************************************************/ /******************************************************************************* @@ -451,8 +452,7 @@ static void i2c_putreg32(struct sam_i2c_dev_s *priv, uint32_t regval, * Name: i2c_takesem * * Description: - * Take the wait semaphore (handling false alarm wake-ups due to the receipt - * of signals). + * Take the wait semaphore. May be interrupted by a signal. * * Input Parameters: * dev - Instance of the SDIO device driver state structure. @@ -462,9 +462,29 @@ static void i2c_putreg32(struct sam_i2c_dev_s *priv, uint32_t regval, * *******************************************************************************/ -static void i2c_takesem(sem_t *sem) +static int i2c_takesem(sem_t *sem) { - nxsem_wait_uninterruptible(sem); + return nxsem_wait(sem); +} + +/******************************************************************************* + * Name: i2c_takesem_uninterruptible + * + * Description: + * Take the wait semaphore (handling false alarm wake-ups due to the receipt + * of signals). May be interrupted by a signal. + * + * Input Parameters: + * dev - Instance of the SDIO device driver state structure. + * + * Returned Value: + * None + * + *******************************************************************************/ + +static int i2c_takesem_uninterruptible(sem_t *sem) +{ + return nxsem_wait_uninterruptible(sem); } /******************************************************************************* @@ -703,6 +723,7 @@ static int i2c_interrupt(int irq, FAR void *context, FAR void *arg) i2c_wait_synchronization(priv); /* STOP */ + if ((priv->nextflags & I2C_M_NOSTART) == 0) { regval = i2c_getreg32(priv, SAM_I2C_CTRLB_OFFSET); @@ -737,7 +758,6 @@ static int i2c_interrupt(int irq, FAR void *context, FAR void *arg) /* Cancel timeout */ i2c_wakeup(priv, OK); - // i2cinfo("Got data = 0x%02X\n", msg->buffer[0]); } i2c_putreg8(priv, I2C_INT_SB, SAM_I2C_INTFLAG_OFFSET); @@ -941,7 +961,7 @@ static int sam_i2c_transfer(FAR struct i2c_master_s *dev, irqstate_t flags; unsigned int size; int i; - int ret = -EBUSY; + int ret; DEBUGASSERT(dev != NULL && msgs != NULL && count > 0); @@ -970,10 +990,16 @@ static int sam_i2c_transfer(FAR struct i2c_master_s *dev, /* Get exclusive access to the device */ - i2c_takesem(&priv->exclsem); + ret = i2c_takesem(&priv->exclsem); + if (ret < 0) + { + return ret; + } /* Initiate the message transfer */ + ret = -BUSY; + /* Initiate the transfer. The rest will be handled from interrupt logic. * Interrupts must be disabled to prevent re-entrance from the interrupt * level. @@ -1040,8 +1066,6 @@ static uint32_t sam_i2c_setfrequency(struct sam_i2c_dev_s *priv, uint32_t baud_hs = 0; uint32_t ctrla; - // i2cinfo("sercom=%d frequency=%d\n", priv->attr->sercom, frequency); - /* Check if the configured BAUD is within the valid range */ maxfreq = (priv->attr->srcfreq >> 1); @@ -1429,7 +1453,11 @@ int sam_i2c_reset(FAR struct i2c_master_s *dev) /* Get exclusive access to the I2C device */ - i2c_takesem(&priv->exclsem); + ret = i2c_takesem_uninterruptible(&priv->exclsem); + if (ret < 0) + { + return ret; + } /* Disable I2C interrupts */ diff --git a/arch/arm/src/samd5e5/sam_i2c_master.c b/arch/arm/src/samd5e5/sam_i2c_master.c index 0a9036ff7c8..dac41383f03 100644 --- a/arch/arm/src/samd5e5/sam_i2c_master.c +++ b/arch/arm/src/samd5e5/sam_i2c_master.c @@ -151,12 +151,12 @@ struct i2c_attr_s struct sam_i2c_dev_s { - struct i2c_master_s dev; /* I2C master device */ - const struct i2c_attr_s *attr; /* Invariant attributes of I2C device */ - struct i2c_msg_s *msg; /* Current message being processed */ - uint32_t frequency; /* I2C transfer clock frequency */ - uint16_t flags; /* Transfer flags */ - uint16_t nextflags; /* Next message flags */ + struct i2c_master_s dev; /* I2C master device */ + const struct i2c_attr_s *attr; /* Invariant attributes of I2C device */ + struct i2c_msg_s *msg; /* Current message being processed */ + uint32_t frequency; /* I2C transfer clock frequency */ + uint16_t flags; /* Transfer flags */ + uint16_t nextflags; /* Next message flags */ sem_t exclsem; /* Only one thread can access at a time */ sem_t waitsem; /* Wait for I2C transfer completion */ @@ -189,7 +189,8 @@ static uint32_t i2c_getreg32(struct sam_i2c_dev_s *priv, unsigned int offset); static void i2c_putreg32(struct sam_i2c_dev_s *priv, uint32_t regval, unsigned int offset); -static void i2c_takesem(sem_t * sem); +static int i2c_takesem(sem_t * sem); +static int i2c_takesem_uninterruptible(sem_t * sem); #define i2c_givesem(sem) (nxsem_post(sem)) #ifdef CONFIG_SAM_I2C_REGDEBUG @@ -476,6 +477,25 @@ static void i2c_putreg32(struct sam_i2c_dev_s *priv, uint32_t regval, * Name: i2c_takesem * * Description: + * Take the wait semaphore. May be interrupted by a signal. + * + * Input Parameters: + * dev - Instance of the SDIO device driver state structure. + * + * Returned Value: + * None + * + *******************************************************************************/ + +static int i2c_takesem(sem_t *sem) +{ + return nxsem_wait(sem); +} + +/******************************************************************************* + * Name: i2c_takesem_uninterruptible + * + * Description: * Take the wait semaphore (handling false alarm wake-ups due to the receipt * of signals). * @@ -487,9 +507,9 @@ static void i2c_putreg32(struct sam_i2c_dev_s *priv, uint32_t regval, * *******************************************************************************/ -static void i2c_takesem(sem_t *sem) +static int i2c_takesem_uninterruptible(sem_t *sem) { - nxsem_wait_uninterruptible(sem); + return nxsem_wait_uninterruptible(sem); } /******************************************************************************* @@ -719,6 +739,7 @@ static int i2c_interrupt(int irq, FAR void *context, FAR void *arg) i2c_wait_synchronization(priv); /* STOP */ + if ((priv->nextflags & I2C_M_NOSTART) == 0) { regval = i2c_getreg32(priv, SAM_I2C_CTRLB_OFFSET); @@ -753,7 +774,6 @@ static int i2c_interrupt(int irq, FAR void *context, FAR void *arg) /* Cancel timeout */ i2c_wakeup(priv, OK); - // i2cinfo("Got data = 0x%02X\n", msg->buffer[0]); } i2c_putreg8(priv, I2C_INT_SB, SAM_I2C_INTFLAG_OFFSET); @@ -957,7 +977,7 @@ static int sam_i2c_transfer(FAR struct i2c_master_s *dev, irqstate_t flags; unsigned int size; int i; - int ret = -EBUSY; + int ret; DEBUGASSERT(dev != NULL && msgs != NULL && count > 0); @@ -986,10 +1006,16 @@ static int sam_i2c_transfer(FAR struct i2c_master_s *dev, /* Get exclusive access to the device */ - i2c_takesem(&priv->exclsem); + ret = i2c_takesem(&priv->exclsem); + if (ret < 0) + { + return ret; + } /* Initiate the message transfer */ + ret = -EBUSY; + /* Initiate the transfer. The rest will be handled from interrupt logic. * Interrupts must be disabled to prevent re-entrance from the interrupt * level. @@ -1052,8 +1078,6 @@ static uint32_t sam_i2c_setfrequency(struct sam_i2c_dev_s *priv, uint32_t baud_hs = 0; uint32_t ctrla; - // i2cinfo("sercom=%d frequency=%d\n", priv->attr->sercom, frequency); - /* Check if the configured BAUD is within the valid range */ maxfreq = (priv->attr->srcfreq >> 1); @@ -1168,7 +1192,8 @@ static void i2c_hw_initialize(struct sam_i2c_dev_s *priv, uint32_t frequency) regval = i2c_getreg32(priv, SAM_I2C_CTRLA_OFFSET); if (regval & I2C_CTRLA_ENABLE) { - i2cerr("ERROR: Cannot initialize I2C because it is already initialized!\n"); + i2cerr("ERROR: Cannot initialize I2C " + "because it is already initialized!\n"); return; } @@ -1467,7 +1492,11 @@ int sam_i2c_reset(FAR struct i2c_master_s *dev) /* Get exclusive access to the I2C device */ - i2c_takesem(&priv->exclsem); + ret = i2c_takesem_uninterruptible(&priv->exclsem); + if (ret < 0) + { + return ret; + } /* Disable I2C interrupts */ diff --git a/arch/arm/src/samv7/sam_twihs.c b/arch/arm/src/samv7/sam_twihs.c index a2df6493ff3..9d75440111a 100644 --- a/arch/arm/src/samv7/sam_twihs.c +++ b/arch/arm/src/samv7/sam_twihs.c @@ -78,7 +78,8 @@ /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ -/* Configuration ***************************************************************/ + +/* Configuration ************************************************************/ #ifndef CONFIG_SAMV7_TWIHS0_FREQUENCY # define CONFIG_SAMV7_TWIHS0_FREQUENCY 100000 @@ -96,12 +97,14 @@ # undef CONFIG_SAMV7_TWIHSHS_REGDEBUG #endif -/* Driver internal definitions *************************************************/ -/* If verbose I2C debug output is enable, then allow more time before we declare - * a timeout. The debug output from twi_interrupt will really slow things down! +/* Driver internal definitions **********************************************/ + +/* If verbose I2C debug output is enable, then allow more time before we + * declare a timeout. The debug output from twi_interrupt will really slow + * things down! * - * With a very slow clock (say 100,000 Hz), less than 100 usec would be required - * to transfer on byte. So these define a "long" timeout. + * With a very slow clock (say 100,000 Hz), less than 100 usec would be + * required to transfer on byte. So these define a "long" timeout. */ #ifdef CONFIG_DEBUG_I2C_INFO @@ -110,8 +113,8 @@ # define TWIHS_TIMEOUT_MSPB (5) /* 5 msec/byte */ #endif -/* Clocking to the TWIHS module(s) is provided by the main clock, divided down - * as necessary. +/* Clocking to the TWIHS module(s) is provided by the main clock, divided + * down as necessary. * REVISIT -- This number came from the SAMA5Dx driver. */ @@ -128,6 +131,7 @@ /**************************************************************************** * Private Types ****************************************************************************/ + /* Invariant attributes of a TWIHS bus */ struct twi_attr_s @@ -163,10 +167,10 @@ struct twi_dev_s /* Debug stuff */ #ifdef CONFIG_SAMV7_TWIHSHS_REGDEBUG - bool wrlast; /* Last was a write */ - uint32_t addrlast; /* Last address */ - uint32_t vallast; /* Last value */ - int ntimes; /* Number of times */ + bool wrlast; /* Last was a write */ + uint32_t addrlast; /* Last address */ + uint32_t vallast; /* Last value */ + int ntimes; /* Number of times */ #endif }; @@ -176,7 +180,8 @@ struct twi_dev_s /* Low-level helper functions */ -static void twi_takesem(sem_t *sem); +static int twi_takesem(sem_t *sem); +static int twi_takesem_uninterruptible(sem_t *sem); #define twi_givesem(sem) (nxsem_post(sem)) #ifdef CONFIG_SAMV7_TWIHSHS_REGDEBUG @@ -294,14 +299,14 @@ static const struct i2c_ops_s g_twiops = }; /**************************************************************************** - * Low-level Helpers + * Private Functions ****************************************************************************/ + /**************************************************************************** * Name: twi_takesem * * Description: - * Take the wait semaphore (handling false alarm wake-ups due to the receipt - * of signals). + * Take the wait semaphore. May be interrupted by a signal. * * Input Parameters: * dev - Instance of the SDIO device driver state structure. @@ -311,9 +316,29 @@ static const struct i2c_ops_s g_twiops = * ****************************************************************************/ -static void twi_takesem(sem_t *sem) +static int twi_takesem(sem_t *sem) { - nxsem_wait_uninterruptible(sem); + return nxsem_wait(sem); +} + +/**************************************************************************** + * Name: twi_takesem_uninterruptible + * + * Description: + * Take the wait semaphore (handling false alarm wake-ups due to the + * receipt of signals). + * + * Input Parameters: + * dev - Instance of the SDIO device driver state structure. + * + * Returned Value: + * None + * + ****************************************************************************/ + +static int twi_takesem_uninterruptible(sem_t *sem) +{ + return nxsem_wait_uninterruptible(sem); } /**************************************************************************** @@ -421,7 +446,8 @@ static void twi_putabs(struct twi_dev_s *priv, uintptr_t address, * ****************************************************************************/ -static inline uint32_t twi_getrel(struct twi_dev_s *priv, unsigned int offset) +static inline uint32_t twi_getrel(struct twi_dev_s *priv, + unsigned int offset) { return twi_getabs(priv, priv->attr->base + offset); } @@ -430,8 +456,8 @@ static inline uint32_t twi_getrel(struct twi_dev_s *priv, unsigned int offset) * Name: twi_putrel * * Description: - * Write a value to a TWIHS register using an offset relative to the TWIHS base - * address. + * Write a value to a TWIHS register using an offset relative to the TWIHS + * base address. * ****************************************************************************/ @@ -459,12 +485,14 @@ static inline void twi_putrel(struct twi_dev_s *priv, unsigned int offset, static int twi_wait(struct twi_dev_s *priv, unsigned int size) { uint32_t timeout; + int ret; /* Calculate a timeout value based on the size of the transfer * * ticks = msec-per-byte * bytes / msec-per-tick * - * There is no concern about arithmetic overflow for reasonable transfer sizes. + * There is no concern about arithmetic overflow for reasonable transfer + * sizes. */ timeout = MSEC2TICK(TWIHS_TIMEOUT_MSPB); @@ -473,8 +501,8 @@ static int twi_wait(struct twi_dev_s *priv, unsigned int size) timeout = 1; } - /* Then start the timeout. This timeout is needed to avoid hangs if/when an - * TWIHS transfer stalls. + /* Then start the timeout. This timeout is needed to avoid hangs if/when + * a TWIHS transfer stalls. */ wd_start(priv->timeout, (timeout * size), twi_timeout, 1, @@ -485,9 +513,15 @@ static int twi_wait(struct twi_dev_s *priv, unsigned int size) do { i2cinfo("TWIHS%d Waiting...\n", priv->attr->twi); - twi_takesem(&priv->waitsem); + ret = twi_takesem(&priv->waitsem); i2cinfo("TWIHS%d Awakened with result: %d\n", priv->attr->twi, priv->result); + + if (ret < 0) + { + wd_cancel(priv->timeout); + return ret; + } } while (priv->result == -EBUSY); @@ -508,10 +542,10 @@ static int twi_wait(struct twi_dev_s *priv, unsigned int size) * transfer has failed and should be repeated. */ - if (priv->result == OK) - { + if (priv->result == OK) + { priv->result = -EIO; - } + } } #endif @@ -598,9 +632,9 @@ static int twi_interrupt(int irq, FAR void *context, FAR void *arg) } else { - /* No.. just switch to the next message and continue receiving. - * On the next RXRDY, we will continue with the first byt of the - * next message. + /* No.. just switch to the next message and continue + * receiving. On the next RXRDY, we will continue with the + * first byte of the next message. */ DEBUGASSERT((next->flags & I2C_M_READ) != 0); @@ -632,10 +666,10 @@ static int twi_interrupt(int irq, FAR void *context, FAR void *arg) } #ifdef CONFIG_I2C_RESET - /* If Single-Master Mode is enabled and we lost arbitration (someone else or - * an EMC-Pulse did something on the bus) something went very wrong. So we end - * the current transfer with an EUSERS. The wait function will then reset - * the bus so further communication can take place. + /* If Single-Master Mode is enabled and we lost arbitration (someone else + * or an EMC-Pulse did something on the bus) something went very wrong. So + * we end the current transfer with an EUSERS. The wait function will then + * reset the bus so further communication can take place. */ else if ((priv->attr->s_master) && ((pending & TWIHS_INT_ARBLST) != 0)) @@ -787,8 +821,9 @@ static void twi_startread(struct twi_dev_s *priv, struct i2c_msg_s *msg) /* Set slave address and number of internal address bytes. */ twi_putrel(priv, SAM_TWIHS_MMR_OFFSET, 0); - twi_putrel(priv, SAM_TWIHS_MMR_OFFSET, TWIHS_MMR_IADRSZ_NONE | TWIHS_MMR_MREAD | - TWIHS_MMR_DADR(msg->addr)); + twi_putrel(priv, SAM_TWIHS_MMR_OFFSET, + TWIHS_MMR_IADRSZ_NONE | TWIHS_MMR_MREAD | + TWIHS_MMR_DADR(msg->addr)); /* Set internal address bytes (not used) */ @@ -818,7 +853,8 @@ static void twi_startwrite(struct twi_dev_s *priv, struct i2c_msg_s *msg) /* Set slave address and number of internal address bytes. */ twi_putrel(priv, SAM_TWIHS_MMR_OFFSET, 0); - twi_putrel(priv, SAM_TWIHS_MMR_OFFSET, TWIHS_MMR_IADRSZ_NONE | TWIHS_MMR_DADR(msg->addr)); + twi_putrel(priv, SAM_TWIHS_MMR_OFFSET, + TWIHS_MMR_IADRSZ_NONE | TWIHS_MMR_DADR(msg->addr)); /* Set internal address bytes (not used) */ @@ -898,18 +934,22 @@ static int twi_transfer(FAR struct i2c_master_s *dev, /* Get exclusive access to the device */ - twi_takesem(&priv->exclsem); + ret = twi_takesem(&priv->exclsem); + if (ret < 0) + { + return ret; + } /* 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. - */ + /* 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); @@ -960,22 +1000,22 @@ errout: return ret; } -/************************************************************************************ -* Name: twi_reset_internal -* -* Description: -* Perform an I2C bus reset in an attempt to break loose stuck I2C devices. -* This function can be called from inside the driver while the TWIHS device is -* already locked, so we must not handle any semaphores inside. -* To initiate a bus reset from outside the driver use twi_reset(dev). -* -* Input Parameters: -* dev - Device-specific state data -* -* Returned Value: -* Zero (OK) on success; a negated errno value on failure. -* -************************************************************************************/ +/**************************************************************************** + * Name: twi_reset_internal + * + * Description: + * Perform an I2C bus reset in an attempt to break loose stuck I2C devices. + * This function can be called from inside the driver while the TWIHS + * device is already locked, so we must not handle any semaphores inside. + * To initiate a bus reset from outside the driver use twi_reset(dev). + * + * 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_internal(FAR struct i2c_master_s *dev) @@ -1086,13 +1126,13 @@ errout: } #endif /* CONFIG_I2C_RESET */ -/************************************************************************************ +/**************************************************************************** * Name: twi_reset * * Description: - * Perform an I2C bus reset in an attempt to break loose stuck I2C devices. - * This function can be called from outside the driver, so lock the TWIHS Device - * and then let the internal reset function do the work. + * Perform an I2C bus reset in an attempt to break loose stuck I2C + * devices. This function can be called from outside the driver, so lock + * the TWIHS Device and then let the internal reset function do the work. * * Input Parameters: * dev - Device-specific state data @@ -1100,7 +1140,7 @@ errout: * 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) @@ -1116,15 +1156,18 @@ static int twi_reset(FAR struct i2c_master_s *dev) /* Get exclusive access to the TWIHS device */ - twi_takesem(&priv->exclsem); + ret = twi_takesem_uninterruptible(&priv->exclsem); + if (ret >= 0) + { + /* Do the reset-procedure */ - /* Do the reset-procedure */ + ret = twi_reset_internal(dev); - ret = twi_reset_internal(dev); + /* Release our lock on the bus */ - /* Release our lock on the bus */ + twi_givesem(&priv->exclsem); + } - twi_givesem(&priv->exclsem); return ret; } #endif /* CONFIG_I2C_RESET */ @@ -1194,8 +1237,8 @@ static void twi_setfrequency(struct twi_dev_s *priv, uint32_t frequency) } } - /* Then setup the TWIHS Clock Waveform Generator Register, using the same - * value for CLDIV and CHDIV (for 1:1 duty). + /* 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); @@ -1215,9 +1258,9 @@ static void twi_setfrequency(struct twi_dev_s *priv, uint32_t frequency) * Name: twi_hw_initialize * * Description: - * Initialize/Re-initialize the TWIHS peripheral. This logic performs only - * repeatable initialization after either (1) the one-time initialization, or - * (2) after each bus reset. + * Initialize/Re-initialize the TWIHS peripheral. This logic performs + * only repeatable initialization after either (1) the one-time + * initialization, or (2) after each bus reset. * ****************************************************************************/ diff --git a/arch/arm/src/stm32/stm32_i2c.c b/arch/arm/src/stm32/stm32_i2c.c index a12e835c3fa..8735e58fb19 100644 --- a/arch/arm/src/stm32/stm32_i2c.c +++ b/arch/arm/src/stm32/stm32_i2c.c @@ -100,8 +100,9 @@ #if defined(CONFIG_STM32_I2C1) || defined(CONFIG_STM32_I2C2) || \ defined(CONFIG_STM32_I2C3) -/* This implementation is for the STM32 F1, F2, and F4 only */ -/* Experimentally enabled for STM32L15XX */ +/* This implementation is for the STM32 F1, F2, and F4 only. + * Experimentally enabled for STM32L15XX. + */ #if defined(CONFIG_STM32_STM32L15XX) || defined(CONFIG_STM32_STM32F10XX) || \ defined(CONFIG_STM32_STM32F20XX) || defined(CONFIG_STM32_STM32F4XXX) @@ -109,7 +110,9 @@ /************************************************************************************ * Pre-processor Definitions ************************************************************************************/ + /* Configuration ********************************************************************/ + /* CONFIG_I2C_POLLED may be set so that I2C interrupts will not be used. Instead, * CPU-intensive polling will be used. */ @@ -182,6 +185,7 @@ /************************************************************************************ * Private Types ************************************************************************************/ + /* Interrupt state */ enum stm32_intstate_e @@ -238,8 +242,14 @@ struct stm32_i2c_config_s struct stm32_i2c_priv_s { - const struct i2c_ops_s *ops; /* Standard I2C operations */ - const struct stm32_i2c_config_s *config; /* Port configuration */ + /* Standard I2C operations */ + + const struct i2c_ops_s *ops; + + /* Port configuration */ + + const struct stm32_i2c_config_s *config; + int refs; /* Referernce count */ sem_t sem_excl; /* Mutual exclusion semaphore */ #ifndef CONFIG_I2C_POLLED @@ -274,12 +284,13 @@ struct stm32_i2c_priv_s static inline uint16_t stm32_i2c_getreg(FAR struct stm32_i2c_priv_s *priv, uint8_t offset); -static inline void stm32_i2c_putreg(FAR struct stm32_i2c_priv_s *priv, uint8_t offset, - uint16_t value); +static inline void stm32_i2c_putreg(FAR struct stm32_i2c_priv_s *priv, + uint8_t offset, uint16_t value); static inline void stm32_i2c_modifyreg(FAR struct stm32_i2c_priv_s *priv, uint8_t offset, uint16_t clearbits, uint16_t setbits); -static inline void stm32_i2c_sem_wait(FAR struct stm32_i2c_priv_s *priv); +static inline int stm32_i2c_sem_wait(FAR struct stm32_i2c_priv_s *priv); +static int stm32_i2c_sem_wait_uninterruptible(FAR struct stm32_i2c_priv_s *priv); #ifdef CONFIG_STM32_I2C_DYNTIMEO static useconds_t stm32_i2c_tousecs(int msgc, FAR struct i2c_msg_s *msgs); @@ -319,8 +330,8 @@ static int stm32_i2c_isr(int irq, void *context, FAR void *arg); 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); +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 @@ -473,8 +484,8 @@ static inline uint16_t stm32_i2c_getreg(FAR struct stm32_i2c_priv_s *priv, * ************************************************************************************/ -static inline void stm32_i2c_putreg(FAR struct stm32_i2c_priv_s *priv, uint8_t offset, - uint16_t value) +static inline void stm32_i2c_putreg(FAR struct stm32_i2c_priv_s *priv, + uint8_t offset, uint16_t value) { putreg16(value, priv->config->base + offset); } @@ -498,13 +509,27 @@ static inline void stm32_i2c_modifyreg(FAR struct stm32_i2c_priv_s *priv, * Name: stm32_i2c_sem_wait * * Description: + * Take the exclusive access, waiting as necessary. May be interrupted by a + * signal. + * + ************************************************************************************/ + +static inline int stm32_i2c_sem_wait(FAR struct stm32_i2c_priv_s *priv) +{ + return nxsem_wait(&priv->sem_excl); +} + +/************************************************************************************ + * Name: stm32_i2c_sem_wait_uninterruptible + * + * Description: * Take the exclusive access, waiting as necessary * ************************************************************************************/ -static inline void stm32_i2c_sem_wait(FAR struct stm32_i2c_priv_s *priv) +static int stm32_i2c_sem_wait_uninterruptible(FAR struct stm32_i2c_priv_s *priv) { - nxsem_wait_uninterruptible(&priv->sem_excl); + return nxsem_wait_uninterruptible(&priv->sem_excl); } /************************************************************************************ @@ -838,7 +863,7 @@ static void stm32_i2c_tracenew(FAR struct stm32_i2c_priv_s *priv, uint32_t statu { /* Yes.. bump up the trace index (unless we are out of trace entries) */ - if (priv->tndx >= (CONFIG_I2C_NTRACE-1)) + if (priv->tndx >= (CONFIG_I2C_NTRACE - 1)) { i2cerr("ERROR: Trace table overflow\n"); return; @@ -879,7 +904,7 @@ static void stm32_i2c_traceevent(FAR struct stm32_i2c_priv_s *priv, /* Bump up the trace index (unless we are out of trace entries) */ - if (priv->tndx >= (CONFIG_I2C_NTRACE-1)) + if (priv->tndx >= (CONFIG_I2C_NTRACE - 1)) { i2cerr("ERROR: Trace table overflow\n"); return; @@ -903,7 +928,7 @@ static void stm32_i2c_tracedump(FAR struct stm32_i2c_priv_s *priv) trace = &priv->trace[i]; syslog(LOG_DEBUG, "%2d. STATUS: %08x COUNT: %3d EVENT: %s(%2d) PARM: %08x TIME: %d\n", - i+1, trace->status, trace->count, g_trace_names[trace->event], + i + 1, trace->status, trace->count, g_trace_names[trace->event], trace->event, trace->parm, trace->time - priv->start_time); } } @@ -1193,7 +1218,8 @@ static int stm32_i2c_isr_process(struct stm32_i2c_priv_s *priv) stm32_i2c_putreg(priv, STM32_I2C_DR_OFFSET, (priv->flags & I2C_M_TEN) ? - 0 : ((priv->msgv->addr << 1) | (priv->flags & I2C_M_READ))); + 0 : ((priv->msgv->addr << 1) | + (priv->flags & I2C_M_READ))); /* Set ACK for receive mode */ @@ -1230,7 +1256,8 @@ static int stm32_i2c_isr_process(struct stm32_i2c_priv_s *priv) /* Was address sent, continue with either sending or reading data */ - else if ((priv->flags & I2C_M_READ) == 0 && (status & (I2C_SR1_ADDR | I2C_SR1_TXE)) != 0) + else if ((priv->flags & I2C_M_READ) == 0 && + (status & (I2C_SR1_ADDR | I2C_SR1_TXE)) != 0) { if (priv->dcnt > 0) { @@ -1563,19 +1590,25 @@ 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) +static int stm32_i2c_transfer(FAR struct i2c_master_s *dev, + FAR struct i2c_msg_s *msgs, int count) { FAR struct stm32_i2c_priv_s *priv = (struct stm32_i2c_priv_s *)dev; uint32_t status = 0; #ifdef I2C1_FSMC_CONFLICT uint32_t ahbenr; #endif - int ret = 0; + int ret; DEBUGASSERT(count > 0); - stm32_i2c_sem_wait(priv); /* Ensure that address or flags don't change meanwhile */ + /* Ensure that address or flags don't change meanwhile */ + + ret = stm32_i2c_sem_wait(priv); + if (ret < 0) + { + return ret; + } #ifdef I2C1_FSMC_CONFLICT /* Disable FSMC that shares a pin with I2C1 (LBAR) */ @@ -1783,7 +1816,7 @@ static int stm32_i2c_reset(FAR struct i2c_master_s *dev) uint32_t scl_gpio; uint32_t sda_gpio; uint32_t frequency; - int ret = ERROR; + int ret; DEBUGASSERT(dev); @@ -1793,7 +1826,13 @@ static int stm32_i2c_reset(FAR struct i2c_master_s *dev) /* Lock out other clients */ - stm32_i2c_sem_wait(priv); + ret = stm32_i2c_sem_wait_uninterruptible(priv); + if (ret < 0) + { + return ret; + } + + ret = -EIO; /* Save the current frequency */ diff --git a/arch/arm/src/stm32/stm32_i2c_alt.c b/arch/arm/src/stm32/stm32_i2c_alt.c index a8f480a58d0..3ef147a4f70 100644 --- a/arch/arm/src/stm32/stm32_i2c_alt.c +++ b/arch/arm/src/stm32/stm32_i2c_alt.c @@ -107,8 +107,9 @@ #if defined(CONFIG_STM32_I2C1) || defined(CONFIG_STM32_I2C2) || \ defined(CONFIG_STM32_I2C3) -/* This implementation is for the STM32 F1, F2, and F4 only */ -/* Experimentally enabled for STM32L15XX */ +/* This implementation is for the STM32 F1, F2, and F4 only. + * Experimentally enabled for STM32L15XX. + */ #if defined(CONFIG_STM32_STM32L15XX) || defined(CONFIG_STM32_STM32F10XX) || \ defined(CONFIG_STM32_STM32F20XX) || defined(CONFIG_STM32_STM32F4XXX) @@ -116,7 +117,9 @@ /************************************************************************************ * Pre-processor Definitions ************************************************************************************/ + /* Configuration ********************************************************************/ + /* CONFIG_I2C_POLLED may be set so that I2C interrupts will not be used. Instead, * CPU-intensive polling will be used. */ @@ -189,6 +192,7 @@ /************************************************************************************ * Private Types ************************************************************************************/ + /* Interrupt state */ enum stm32_intstate_e @@ -266,8 +270,14 @@ struct stm32_i2c_config_s struct stm32_i2c_priv_s { - const struct i2c_ops_s *ops; /* Standard I2C operations */ - const struct stm32_i2c_config_s *config; /* Port configuration */ + /* Standard I2C operations */ + + const struct i2c_ops_s *ops; + + /* Port configuration */ + + const struct stm32_i2c_config_s *config; + int refs; /* Referernce count */ sem_t sem_excl; /* Mutual exclusion semaphore */ #ifndef CONFIG_I2C_POLLED @@ -281,7 +291,7 @@ struct stm32_i2c_priv_s 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 */ + bool check_addr_ack; /* Flag to signal if on next interrupt address has ACKed */ uint8_t total_msg_len; /* Flag to signal a short read sequence */ /* I2C trace support */ @@ -304,12 +314,13 @@ struct stm32_i2c_priv_s static inline uint16_t stm32_i2c_getreg(FAR struct stm32_i2c_priv_s *priv, uint8_t offset); -static inline void stm32_i2c_putreg(FAR struct stm32_i2c_priv_s *priv, uint8_t offset, - uint16_t value); +static inline void stm32_i2c_putreg(FAR struct stm32_i2c_priv_s *priv, + uint8_t offset, uint16_t value); static inline void stm32_i2c_modifyreg(FAR struct stm32_i2c_priv_s *priv, uint8_t offset, uint16_t clearbits, uint16_t setbits); -static inline void stm32_i2c_sem_wait(FAR struct stm32_i2c_priv_s *priv); +static inline int stm32_i2c_sem_wait(FAR struct stm32_i2c_priv_s *priv); +static int stm32_i2c_sem_wait_uninterruptible(FAR struct stm32_i2c_priv_s *priv); #ifdef CONFIG_STM32_I2C_DYNTIMEO static useconds_t stm32_i2c_tousecs(int msgc, FAR struct i2c_msg_s *msgs); @@ -349,8 +360,8 @@ static int stm32_i2c_isr(int irq, void *context, FAR void *arg); 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); +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 @@ -482,8 +493,8 @@ static inline uint16_t stm32_i2c_getreg(FAR struct stm32_i2c_priv_s *priv, * ************************************************************************************/ -static inline void stm32_i2c_putreg(FAR struct stm32_i2c_priv_s *priv, uint8_t offset, - uint16_t value) +static inline void stm32_i2c_putreg(FAR struct stm32_i2c_priv_s *priv, + uint8_t offset, uint16_t value) { putreg16(value, priv->config->base + offset); } @@ -507,13 +518,27 @@ static inline void stm32_i2c_modifyreg(FAR struct stm32_i2c_priv_s *priv, * Name: stm32_i2c_sem_wait * * Description: + * Take the exclusive access, waiting as necessary. May be interrupted by a + * signal. + * + ************************************************************************************/ + +static inline int stm32_i2c_sem_wait(FAR struct stm32_i2c_priv_s *priv) +{ + return nxsem_wait(&priv->sem_excl); +} + +/************************************************************************************ + * Name: stm32_i2c_sem_wait_uninterruptible + * + * Description: * Take the exclusive access, waiting as necessary * ************************************************************************************/ -static inline void stm32_i2c_sem_wait(FAR struct stm32_i2c_priv_s *priv) +static int stm32_i2c_sem_wait_uninterruptible(FAR struct stm32_i2c_priv_s *priv) { - nxsem_wait_uninterruptible(&priv->sem_excl); + return nxsem_wait_uninterruptible(&priv->sem_excl); } /************************************************************************************ @@ -847,7 +872,7 @@ static void stm32_i2c_tracenew(FAR struct stm32_i2c_priv_s *priv, uint16_t statu { /* Yes.. bump up the trace index (unless we are out of trace entries) */ - if (priv->tndx >= (CONFIG_I2C_NTRACE-1)) + if (priv->tndx >= (CONFIG_I2C_NTRACE - 1)) { i2cerr("ERROR: Trace table overflow\n"); return; @@ -888,7 +913,7 @@ static void stm32_i2c_traceevent(FAR struct stm32_i2c_priv_s *priv, /* Bump up the trace index (unless we are out of trace entries) */ - if (priv->tndx >= (CONFIG_I2C_NTRACE-1)) + if (priv->tndx >= (CONFIG_I2C_NTRACE - 1)) { i2cerr("ERROR: Trace table overflow\n"); return; @@ -912,7 +937,7 @@ static void stm32_i2c_tracedump(FAR struct stm32_i2c_priv_s *priv) trace = &priv->trace[i]; syslog(LOG_DEBUG, "%2d. STATUS: %08x COUNT: %4d EVENT: %4d PARM: %08x TIME: %d\n", - i+1, trace->status, trace->count, trace->event, trace->parm, + i + 1, trace->status, trace->count, trace->event, trace->parm, trace->time - priv->start_time); } } @@ -1352,14 +1377,15 @@ static int stm32_i2c_isr_process(struct stm32_i2c_priv_s *priv) stm32_i2c_putreg(priv, STM32_I2C_DR_OFFSET, (priv->flags & I2C_M_TEN) ? - 0 :((priv->msgv->addr << 1) | (priv->flags & I2C_M_READ))); + 0 : ((priv->msgv->addr << 1) | + (priv->flags & I2C_M_READ))); i2cinfo("Address sent. Addr=%#02x Write/Read bit=%i\n", priv->msgv->addr, (priv->flags & I2C_M_READ)); /* Flag that address has just been sent */ - priv->check_addr_ACK = true; + priv->check_addr_ack = true; stm32_i2c_traceevent(priv, I2CEVENT_SENDADDR, priv->msgv->addr); } @@ -1367,7 +1393,8 @@ static int stm32_i2c_isr_process(struct stm32_i2c_priv_s *priv) { /* TODO: untested!! */ - i2cwarn("WARNING: An empty message has been detected, ignoring and passing to next message.\n"); + i2cwarn("WARNING: An empty message has been detected, " + "ignoring and passing to next message.\n"); /* Trace event */ @@ -1411,7 +1438,7 @@ static int stm32_i2c_isr_process(struct stm32_i2c_priv_s *priv) * Note: this commentary is found in both places. */ - else if ((status & I2C_SR1_ADDR) == 0 && priv->check_addr_ACK) + else if ((status & I2C_SR1_ADDR) == 0 && priv->check_addr_ack) { i2cinfo("Invalid Address. Setting stop bit and clearing message\n"); i2cinfo("status %i\n", status); @@ -1425,7 +1452,7 @@ static int stm32_i2c_isr_process(struct stm32_i2c_priv_s *priv) /* Reset flag to check for valid address */ - priv->check_addr_ACK = false; + priv->check_addr_ack = false; /* Send stop bit to clear bus */ @@ -1440,11 +1467,11 @@ static int stm32_i2c_isr_process(struct stm32_i2c_priv_s *priv) /* ACK in read mode, ACK in write mode is handled separately */ else if ((priv->flags & I2C_M_READ) != 0 && (status & I2C_SR1_ADDR) != 0 && - priv->check_addr_ACK) + priv->check_addr_ack) { /* Reset check addr flag as we are handling this event */ - priv->check_addr_ACK = false; + priv->check_addr_ack = false; /* Clear ADDR flag by reading SR2 and adding it to status */ @@ -1524,7 +1551,7 @@ static int stm32_i2c_isr_process(struct stm32_i2c_priv_s *priv) /* Address has cleared so don't check on next call */ - priv->check_addr_ACK = false; + priv->check_addr_ack = false; /* Check if we have transmitted the whole message or we are after * the last byte where the stop condition or else(according to the @@ -1541,7 +1568,6 @@ static int stm32_i2c_isr_process(struct stm32_i2c_priv_s *priv) stm32_i2c_traceevent(priv, I2CEVENT_WRITE_TO_DR, priv->dcnt); priv->dcnt--; - } else if (priv->dcnt == 0) { @@ -1567,7 +1593,8 @@ static int stm32_i2c_isr_process(struct stm32_i2c_priv_s *priv) */ else if (priv->msgc > 0 && - (priv->msgv->flags == 0 || (priv->msgv[0].flags & I2C_M_READ) != 0)) + (priv->msgv->flags == 0 || + (priv->msgv[0].flags & I2C_M_READ) != 0)) { stm32_i2c_sendstart(priv); @@ -1595,9 +1622,9 @@ static int stm32_i2c_isr_process(struct stm32_i2c_priv_s *priv) else { i2cerr("ERROR: Write mode: next message has an unrecognized flag.\n"); - stm32_i2c_traceevent(priv, I2CEVENT_WRITE_FLAG_ERROR, priv->msgv->flags); + stm32_i2c_traceevent(priv, I2CEVENT_WRITE_FLAG_ERROR, + priv->msgv->flags); } - } else { @@ -1659,14 +1686,17 @@ static int stm32_i2c_isr_process(struct stm32_i2c_priv_s *priv) /* Case total message length = 2 */ - else if (priv->dcnt == 2 && priv->total_msg_len == 2 && !(status & I2C_SR1_BTF)) + else if (priv->dcnt == 2 && priv->total_msg_len == 2 && + !(status & I2C_SR1_BTF)) { i2cinfo("short read N=2: DR full, SR empty. Waiting for more bytes.\n"); stm32_i2c_traceevent(priv, I2CEVENT_READ_SR_EMPTY, 0); } - else if (priv->dcnt == 2 && priv->total_msg_len == 2 && (status & I2C_SR1_BTF)) + else if (priv->dcnt == 2 && priv->total_msg_len == 2 && + (status & I2C_SR1_BTF)) { - i2cinfo("short read N=2: DR and SR full setting stop bit and reading twice\n"); + i2cinfo("short read N=2: " + "DR and SR full setting stop bit and reading twice\n"); stm32_i2c_sendstop(priv); *priv->ptr++ = stm32_i2c_getreg(priv, STM32_I2C_DR_OFFSET); @@ -2011,21 +2041,25 @@ 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) +static int stm32_i2c_transfer(FAR struct i2c_master_s *dev, + FAR struct i2c_msg_s *msgs, int count) { FAR struct stm32_i2c_priv_s *priv = (FAR struct stm32_i2c_priv_s *)dev; uint32_t status = 0; #ifdef I2C1_FSMC_CONFLICT uint32_t ahbenr; #endif - int ret = 0; + int ret; DEBUGASSERT(dev != NULL && msgs != NULL && count > 0); /* Ensure that address or flags don't change meanwhile */ - stm32_i2c_sem_wait(priv); + ret = stm32_i2c_sem_wait(priv); + if (ret < 0) + { + return ret; + } #ifdef I2C1_FSMC_CONFLICT /* Disable FSMC that shares a pin with I2C1 (LBAR) */ @@ -2248,7 +2282,7 @@ static int stm32_i2c_reset(FAR struct i2c_master_s * dev) uint32_t scl_gpio; uint32_t sda_gpio; uint32_t frequency; - int ret = ERROR; + int ret; DEBUGASSERT(dev); @@ -2258,7 +2292,13 @@ static int stm32_i2c_reset(FAR struct i2c_master_s * dev) /* Lock out other clients */ - stm32_i2c_sem_wait(priv); + ret = stm32_i2c_sem_wait_uninterruptible(priv); + if (ret < 0) + { + return ret; + } + + ret = -EIO; /* Save the current frequency */ diff --git a/arch/arm/src/stm32/stm32_i2c_v2.c b/arch/arm/src/stm32/stm32_i2c_v2.c index 46ae6de58d4..c0062aa795b 100644 --- a/arch/arm/src/stm32/stm32_i2c_v2.c +++ b/arch/arm/src/stm32/stm32_i2c_v2.c @@ -292,7 +292,7 @@ /* Unused bit in I2c_ISR used to communicate a bad state has occurred in * the isr processing -*/ + */ #define I2C_INT_BAD_STATE 0x8000000 @@ -389,7 +389,10 @@ struct stm32_i2c_config_s struct stm32_i2c_priv_s { - const struct stm32_i2c_config_s *config; /* Port configuration */ + /* Port configuration */ + + const struct stm32_i2c_config_s *config; + int refs; /* Reference count */ sem_t sem_excl; /* Mutual exclusion semaphore */ #ifndef CONFIG_I2C_POLLED @@ -437,14 +440,15 @@ struct stm32_i2c_inst_s static inline uint16_t stm32_i2c_getreg(FAR struct stm32_i2c_priv_s *priv, uint8_t offset); -static inline void stm32_i2c_putreg(FAR struct stm32_i2c_priv_s *priv, uint8_t offset, - uint16_t value); -static inline void stm32_i2c_putreg32(FAR struct stm32_i2c_priv_s *priv, uint8_t offset, - uint32_t value); +static inline void stm32_i2c_putreg(FAR struct stm32_i2c_priv_s *priv, + uint8_t offset, uint16_t value); +static inline void stm32_i2c_putreg32(FAR struct stm32_i2c_priv_s *priv, + uint8_t offset, uint32_t value); static inline void stm32_i2c_modifyreg32(FAR struct stm32_i2c_priv_s *priv, uint8_t offset, uint32_t clearbits, uint32_t setbits); -static inline void stm32_i2c_sem_wait(FAR struct i2c_master_s *dev); +static inline int stm32_i2c_sem_wait(FAR struct i2c_master_s *dev); +static int stm32_i2c_sem_wait_uninterruptible(FAR struct i2c_master_s *dev); #ifdef CONFIG_STM32_I2C_DYNTIMEO static useconds_t stm32_i2c_tousecs(int msgc, FAR struct i2c_msg_s *msgs); #endif /* CONFIG_STM32_I2C_DYNTIMEO */ @@ -472,10 +476,10 @@ static int stm32_i2c_isr(int irq, void *context, FAR void *arg); 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_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, - int count); +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, int count); #ifdef CONFIG_I2C_RESET static int stm32_i2c_reset(FAR struct i2c_master_s * dev); #endif @@ -666,8 +670,8 @@ static inline uint32_t stm32_i2c_getreg32(FAR struct stm32_i2c_priv_s *priv, * ************************************************************************************/ -static inline void stm32_i2c_putreg(FAR struct stm32_i2c_priv_s *priv, uint8_t offset, - uint16_t value) +static inline void stm32_i2c_putreg(FAR struct stm32_i2c_priv_s *priv, + uint8_t offset, uint16_t value) { putreg16(value, priv->config->base + offset); } @@ -686,7 +690,6 @@ static inline void stm32_i2c_putreg32(FAR struct stm32_i2c_priv_s *priv, putreg32(value, priv->config->base + offset); } - /************************************************************************************ * Name: stm32_i2c_modifyreg32 * @@ -706,13 +709,28 @@ static inline void stm32_i2c_modifyreg32(FAR struct stm32_i2c_priv_s *priv, * Name: stm32_i2c_sem_wait * * Description: + * Take the exclusive access, waiting as necessary. May be interrupted by a + * signal. + * + ************************************************************************************/ + +static inline int stm32_i2c_sem_wait(FAR struct i2c_master_s *dev) +{ + return nxsem_wait(&((struct stm32_i2c_inst_s *)dev)->priv->sem_excl); +} + +/************************************************************************************ + * Name: stm32_i2c_sem_wait_uninterruptible + * + * Description: * Take the exclusive access, waiting as necessary * ************************************************************************************/ -static inline void stm32_i2c_sem_wait(FAR struct i2c_master_s *dev) +static int stm32_i2c_sem_wait_uninterruptible(FAR struct i2c_master_s *dev) { - nxsem_wait_uninterruptible(&((struct stm32_i2c_inst_s *)dev)->priv->sem_excl); + return + nxsem_wait_uninterruptible(&((struct stm32_i2c_inst_s *)dev)->priv->sem_excl); } /************************************************************************************ @@ -755,7 +773,8 @@ static useconds_t stm32_i2c_tousecs(int msgc, FAR struct i2c_msg_s *msgs) #ifndef CONFIG_I2C_POLLED static inline void stm32_i2c_enableinterrupts(struct stm32_i2c_priv_s *priv) { - stm32_i2c_modifyreg32(priv, STM32_I2C_CR1_OFFSET, 0, (I2C_CR1_TXRX | I2C_CR1_NACKIE)); + stm32_i2c_modifyreg32(priv, STM32_I2C_CR1_OFFSET, 0, + (I2C_CR1_TXRX | I2C_CR1_NACKIE)); } #endif @@ -821,6 +840,7 @@ static inline int stm32_i2c_sem_waitdone(FAR struct stm32_i2c_priv_s *priv) abstime.tv_nsec -= 1000 * 1000 * 1000; } #endif + /* Wait until either the transfer is complete or the timeout expires */ ret = nxsem_timedwait_uninterruptible(&priv->sem_isr, &abstime); @@ -912,7 +932,7 @@ static inline void stm32_i2c_set_7bit_address(FAR struct stm32_i2c_priv_s *priv) { stm32_i2c_modifyreg32(priv, STM32_I2C_CR2_OFFSET, I2C_CR2_SADD7_MASK, - ((priv->msgv->addr & 0x7F) << I2C_CR2_SADD7_SHIFT)); + ((priv->msgv->addr & 0x7f) << I2C_CR2_SADD7_SHIFT)); } /************************************************************************************ @@ -982,7 +1002,6 @@ stm32_i2c_disable_reload(FAR struct stm32_i2c_priv_s *priv) stm32_i2c_modifyreg32(priv, STM32_I2C_CR2_OFFSET, I2C_CR2_RELOAD, 0); } - /************************************************************************************ * Name: stm32_i2c_sem_waitstop * @@ -1031,7 +1050,6 @@ static inline void stm32_i2c_sem_waitstop(FAR struct stm32_i2c_priv_s *priv) { return; } - } /* Loop until the stop is complete or a timeout occurs. */ @@ -1140,7 +1158,7 @@ static void stm32_i2c_tracenew(FAR struct stm32_i2c_priv_s *priv, { /* Yes.. bump up the trace index (unless we are out of trace entries) */ - if (priv->tndx >= (CONFIG_I2C_NTRACE-1)) + if (priv->tndx >= (CONFIG_I2C_NTRACE - 1)) { i2cerr("ERROR: Trace table overflow\n"); return; @@ -1181,7 +1199,7 @@ static void stm32_i2c_traceevent(FAR struct stm32_i2c_priv_s *priv, /* Bump up the trace index (unless we are out of trace entries) */ - if (priv->tndx >= (CONFIG_I2C_NTRACE-1)) + if (priv->tndx >= (CONFIG_I2C_NTRACE - 1)) { i2cerr("ERROR: Trace table overflow\n"); return; @@ -1205,7 +1223,7 @@ static void stm32_i2c_tracedump(FAR struct stm32_i2c_priv_s *priv) trace = &priv->trace[i]; syslog(LOG_DEBUG, "%2d. STATUS: %08x COUNT: %3d EVENT: %2d PARM: %08x TIME: %d\n", - i+1, trace->status, trace->count, trace->event, trace->parm, + i + 1, trace->status, trace->count, trace->event, trace->parm, (int)(trace->time - priv->start_time)); } } @@ -1278,7 +1296,6 @@ static void stm32_i2c_setclock(FAR struct stm32_i2c_priv_s *priv, uint32_t frequ if (frequency != priv->frequency) { - /* The Speed and timing calculation are based on the following * fI2CCLK = HSI and is 16Mhz * Analog filter is on, @@ -1287,39 +1304,38 @@ static void stm32_i2c_setclock(FAR struct stm32_i2c_priv_s *priv, uint32_t frequ * Mode is FastMode */ - if (frequency == 100000) - { - presc = 0; - scl_delay = 5; - sda_delay = 0; - scl_h_period = 61; - scl_l_period = 89; - - } - else if (frequency == 400000) - { - presc = 0; - scl_delay = 3; - sda_delay = 0; - scl_h_period = 6; - scl_l_period = 24; - } - else if (frequency == 1000000) - { - presc = 0; - scl_delay = 2; - sda_delay = 0; - scl_h_period = 1; - scl_l_period = 5; - } - else - { - presc = 7; - scl_delay = 0; - sda_delay = 0; - scl_h_period = 35; - scl_l_period = 162; - } + if (frequency == 100000) + { + presc = 0; + scl_delay = 5; + sda_delay = 0; + scl_h_period = 61; + scl_l_period = 89; + } + else if (frequency == 400000) + { + presc = 0; + scl_delay = 3; + sda_delay = 0; + scl_h_period = 6; + scl_l_period = 24; + } + else if (frequency == 1000000) + { + presc = 0; + scl_delay = 2; + sda_delay = 0; + scl_h_period = 1; + scl_l_period = 5; + } + else + { + presc = 7; + scl_delay = 0; + sda_delay = 0; + scl_h_period = 35; + scl_l_period = 162; + } uint32_t timingr = (presc << I2C_TIMINGR_PRESC_SHIFT) | @@ -1593,10 +1609,8 @@ static int stm32_i2c_isr_process(struct stm32_i2c_priv_s *priv) if (status & I2C_INT_NACK) { - if (priv->astart == true) { - /* NACK received on first (address) byte: address is invalid */ i2cinfo("NACK: Address invalid: dcnt=%i msgc=%i status=0x%08x\n", @@ -1658,7 +1672,6 @@ static int stm32_i2c_isr_process(struct stm32_i2c_priv_s *priv) else if ((priv->flags & (I2C_M_READ)) == 0 && (status & (I2C_ISR_TXIS)) != 0) { - /* TXIS interrupt occurred, address valid, ready to transmit */ stm32_i2c_traceevent(priv, I2CEVENT_WRITE, 0); @@ -1889,7 +1902,6 @@ static int stm32_i2c_isr_process(struct stm32_i2c_priv_s *priv) priv->msgv++; stm32_i2c_sendstart(priv); - } else { @@ -1974,8 +1986,9 @@ static int stm32_i2c_isr_process(struct stm32_i2c_priv_s *priv) priv->dcnt = priv->msgv->length; priv->flags = priv->msgv->flags; - /* if this is the last message, disable reload so the - * TC event fires next time */ + /* If this is the last message, disable reload so the + * TC event fires next time. + */ if (priv->msgc == 0) { @@ -2101,8 +2114,9 @@ static int stm32_i2c_isr_process(struct stm32_i2c_priv_s *priv) stm32_i2c_traceevent(priv, I2CEVENT_ISR_SHUTDOWN, 0); - /* clear pointer to message content to reflect we are done - * with the current transaction */ + /* Clear pointer to message content to reflect we are done + * with the current transaction. + */ priv->msgv = NULL; @@ -2271,7 +2285,8 @@ static int stm32_i2c_deinit(FAR struct stm32_i2c_priv_s *priv) * ************************************************************************************/ -static int stm32_i2c_process(FAR struct i2c_master_s *dev, FAR struct i2c_msg_s *msgs, int count) +static int stm32_i2c_process(FAR struct i2c_master_s *dev, + FAR struct i2c_msg_s *msgs, int count) { struct stm32_i2c_inst_s *inst = (struct stm32_i2c_inst_s *)dev; FAR struct stm32_i2c_priv_s *priv = inst->priv; @@ -2363,12 +2378,12 @@ static int stm32_i2c_process(FAR struct i2c_master_s *dev, FAR struct i2c_msg_s errval = ETIMEDOUT; i2cerr("ERROR: Waitdone timed out CR1: 0x%08x CR2: 0x%08x status: 0x%08x\n", - cr1, cr2,status); + cr1, cr2, status); } else { i2cinfo("Waitdone success: CR1: 0x%08x CR2: 0x%08x status: 0x%08x\n", - cr1, cr2,status ); + cr1, cr2, status); } UNUSED(cr1); @@ -2467,7 +2482,7 @@ static int stm32_i2c_process(FAR struct i2c_master_s *dev, FAR struct i2c_msg_s */ clock_t start = clock_systimer(); - clock_t timeout = USEC2TICK(USEC_PER_SEC/priv->frequency) + 1; + clock_t timeout = USEC2TICK(USEC_PER_SEC / priv->frequency) + 1; status = stm32_i2c_getstatus(priv); @@ -2500,11 +2515,20 @@ static int stm32_i2c_process(FAR struct i2c_master_s *dev, FAR struct i2c_msg_s * ************************************************************************************/ -static int stm32_i2c_transfer(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, int count) { - stm32_i2c_sem_wait(dev); /* ensure that address or flags don't change meanwhile */ - return stm32_i2c_process(dev, msgs, count); + int ret; + + /* Ensure that address or flags don't change meanwhile */ + + ret = stm32_i2c_sem_wait(dev); + if (ret >= 0) + { + ret = stm32_i2c_process(dev, msgs, count); + } + + return ret; } /************************************************************************************ @@ -2524,7 +2548,7 @@ static int stm32_i2c_reset(FAR struct i2c_master_s * dev) uint32_t scl_gpio; uint32_t sda_gpio; uint32_t frequency; - int ret = ERROR; + int ret; DEBUGASSERT(dev); @@ -2538,7 +2562,13 @@ static int stm32_i2c_reset(FAR struct i2c_master_s * dev) /* Lock out other clients */ - stm32_i2c_sem_wait(dev); + ret = stm32_i2c_sem_wait_uninterruptible(dev); + if (ret < 0) + { + return ret; + } + + ret = -EIO; /* Save the current frequency */ @@ -2685,6 +2715,7 @@ static int stm32_i2c_pm_prepare(FAR struct pm_callback_s *cb, int domain, case PM_STANDBY: case PM_SLEEP: + /* Check if exclusive lock for I2C bus is held. */ if (nxsem_getvalue(&priv->sem_excl, &sval) < 0) @@ -2703,6 +2734,7 @@ static int stm32_i2c_pm_prepare(FAR struct pm_callback_s *cb, int domain, break; default: + /* Should not get here */ break; @@ -2734,8 +2766,8 @@ FAR struct i2c_master_s *stm32_i2cbus_initialize(int port) #endif #if STM32_HSI_FREQUENCY != 8000000 || defined(INVALID_CLOCK_SOURCE) -# warning STM32_I2C_INIT: Peripheral clock is HSI and it must be 16mHz or the speed/timing calculations need to be redone. - return NULL; +# warning STM32_I2C_INIT: Peripheral clock is HSI and it must be 16mHz or the speed/timing calculations need to be redone. + return NULL; #endif /* Get I2C private structure */ @@ -2853,4 +2885,4 @@ int stm32_i2cbus_uninitialize(FAR struct i2c_master_s * dev) } #endif /* CONFIG_STM32_I2C1 || CONFIG_STM32_I2C2 || \ - CONFIG_STM32_I2C3 || CONFIG_STM32_I2C4 */ + * CONFIG_STM32_I2C3 || CONFIG_STM32_I2C4 */ diff --git a/arch/arm/src/stm32/stm32f40xxx_i2c.c b/arch/arm/src/stm32/stm32f40xxx_i2c.c index 2a3028d49e4..a8f09808f26 100644 --- a/arch/arm/src/stm32/stm32f40xxx_i2c.c +++ b/arch/arm/src/stm32/stm32f40xxx_i2c.c @@ -100,8 +100,9 @@ #if defined(CONFIG_STM32_I2C1) || defined(CONFIG_STM32_I2C2) || \ defined(CONFIG_STM32_I2C3) -/* This implementation is for the STM32 F1, F2, and F4 only */ -/* Experimentally enabled for STM32L15XX */ +/* This implementation is for the STM32 F1, F2, and F4 only. + * Experimentally enabled for STM32L15XX. + */ #if defined(CONFIG_STM32_STM32L15XX) || defined(CONFIG_STM32_STM32F10XX) || \ defined(CONFIG_STM32_STM32F20XX) || defined(CONFIG_STM32_STM32F4XXX) @@ -109,7 +110,9 @@ /************************************************************************************ * Pre-processor Definitions ************************************************************************************/ + /* Configuration ********************************************************************/ + /* CONFIG_I2C_POLLED may be set so that I2C interrupts will not be used. Instead, * CPU-intensive polling will be used. */ @@ -197,6 +200,7 @@ /************************************************************************************ * Private Types ************************************************************************************/ + /* Interrupt state */ enum stm32_intstate_e @@ -253,8 +257,14 @@ struct stm32_i2c_config_s struct stm32_i2c_priv_s { - const struct i2c_ops_s *ops; /* Standard I2C operations */ - const struct stm32_i2c_config_s *config; /* Port configuration */ + /* Standard I2C operations */ + + const struct i2c_ops_s *ops; + + /* Port configuration */ + + const struct stm32_i2c_config_s *config; + int refs; /* Referernce count */ sem_t sem_excl; /* Mutual exclusion semaphore */ #ifndef CONFIG_I2C_POLLED @@ -268,7 +278,7 @@ struct stm32_i2c_priv_s uint32_t frequency; /* Current I2C frequency */ volatile 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 */ + bool check_addr_ack; /* Flag to signal if on next interrupt address has ACKed */ /* I2C trace support */ @@ -299,12 +309,13 @@ struct stm32_i2c_priv_s static inline uint16_t stm32_i2c_getreg(FAR struct stm32_i2c_priv_s *priv, uint8_t offset); -static inline void stm32_i2c_putreg(FAR struct stm32_i2c_priv_s *priv, uint8_t offset, - uint16_t value); +static inline void stm32_i2c_putreg(FAR struct stm32_i2c_priv_s *priv, + uint8_t offset, uint16_t value); static inline void stm32_i2c_modifyreg(FAR struct stm32_i2c_priv_s *priv, uint8_t offset, uint16_t clearbits, uint16_t setbits); -static inline void stm32_i2c_sem_wait(FAR struct stm32_i2c_priv_s *priv); +static inline int stm32_i2c_sem_wait(FAR struct stm32_i2c_priv_s *priv); +static int stm32_i2c_sem_wait_uninterruptible(FAR struct stm32_i2c_priv_s *priv); #ifdef CONFIG_STM32_I2C_DYNTIMEO static useconds_t stm32_i2c_tousecs(int msgc, FAR struct i2c_msg_s *msgs); @@ -344,8 +355,8 @@ static int stm32_i2c_isr(int irq, void *context, FAR void *arg); 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); +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 @@ -528,8 +539,8 @@ static inline uint16_t stm32_i2c_getreg(FAR struct stm32_i2c_priv_s *priv, * ************************************************************************************/ -static inline void stm32_i2c_putreg(FAR struct stm32_i2c_priv_s *priv, uint8_t offset, - uint16_t value) +static inline void stm32_i2c_putreg(FAR struct stm32_i2c_priv_s *priv, + uint8_t offset, uint16_t value) { putreg16(value, priv->config->base + offset); } @@ -553,13 +564,28 @@ static inline void stm32_i2c_modifyreg(FAR struct stm32_i2c_priv_s *priv, * Name: stm32_i2c_sem_wait * * Description: - * Take the exclusive access, waiting as necessary + * Take the exclusive access, waiting as necessary. May be interrupted by a + * signal. * ************************************************************************************/ -static inline void stm32_i2c_sem_wait(FAR struct stm32_i2c_priv_s *priv) +static inline int stm32_i2c_sem_wait(FAR struct stm32_i2c_priv_s *priv) { - nxsem_wait_uninterruptible(&priv->sem_excl); + return nxsem_wait(&priv->sem_excl); +} + +/************************************************************************************ + * Name: stm32_i2c_sem_wait_uninterruptible + * + * Description: + * Take the exclusive access, waiting as necessary. May be interrupted by a + * signal. + * + ************************************************************************************/ + +static int stm32_i2c_sem_wait_uninterruptible(FAR struct stm32_i2c_priv_s *priv) +{ + return nxsem_wait_uninterruptible(&priv->sem_excl); } /************************************************************************************ @@ -786,7 +812,6 @@ static inline void stm32_i2c_sem_waitstop(FAR struct stm32_i2c_priv_s *priv) { return; } - } /* Loop until the stop is complete or a timeout occurs. */ @@ -894,7 +919,7 @@ static void stm32_i2c_tracenew(FAR struct stm32_i2c_priv_s *priv, uint32_t statu { /* Yes.. bump up the trace index (unless we are out of trace entries) */ - if (priv->tndx >= (CONFIG_I2C_NTRACE-1)) + if (priv->tndx >= (CONFIG_I2C_NTRACE - 1)) { i2cerr("ERROR: Trace table overflow\n"); return; @@ -935,7 +960,7 @@ static void stm32_i2c_traceevent(FAR struct stm32_i2c_priv_s *priv, /* Bump up the trace index (unless we are out of trace entries) */ - if (priv->tndx >= (CONFIG_I2C_NTRACE-1)) + if (priv->tndx >= (CONFIG_I2C_NTRACE - 1)) { i2cerr("ERROR: Trace table overflow\n"); return; @@ -959,7 +984,7 @@ static void stm32_i2c_tracedump(FAR struct stm32_i2c_priv_s *priv) trace = &priv->trace[i]; syslog(LOG_DEBUG, "%2d. STATUS: %08x COUNT: %3d EVENT: %s(%2d) PARM: %08x TIME: %d\n", - i+1, trace->status, trace->count, g_trace_names[trace->event], + i + 1, trace->status, trace->count, g_trace_names[trace->event], trace->event, trace->parm, trace->time - priv->start_time); } } @@ -1289,18 +1314,20 @@ static int stm32_i2c_isr_process(struct stm32_i2c_priv_s *priv) if (priv->dcnt == -1 && priv->msgc > 0) { - /* Any new message should begin with "Start" condition - * However there were 2 situations where that was not true - * Situation 1: Next message continue transmission sequence of previous message - * - * Situation 2: If an error is injected that looks like a STOP the - * interrupt will be reentered with some status that will be incorrect. This - * will ensure that the error handler will clear the interrupt enables and - * return the error to the waiting task. - */ + /* Any new message should begin with "Start" condition + * However there were 2 situations where that was not true + * Situation 1: Next message continue transmission sequence of previous message + * + * Situation 2: If an error is injected that looks like a STOP the + * interrupt will be reentered with some status that will be incorrect. This + * will ensure that the error handler will clear the interrupt enables and + * return the error to the waiting task. + */ - if (((priv->msgv[0].flags & I2C_M_NOSTART) != 0 && (status & I2C_SR1_TXE) == 0) || - ((priv->msgv[0].flags & I2C_M_NOSTART) == 0 && (status & I2C_SR1_SB) == 0)) + if (((priv->msgv[0].flags & I2C_M_NOSTART) != 0 && + (status & I2C_SR1_TXE) == 0) || + ((priv->msgv[0].flags & I2C_M_NOSTART) == 0 && + (status & I2C_SR1_SB) == 0)) { #if defined(CONFIG_STM32_I2C_DMA) || defined(CONFIG_I2C_POLLED) return OK; @@ -1392,14 +1419,15 @@ static int stm32_i2c_isr_process(struct stm32_i2c_priv_s *priv) stm32_i2c_putreg(priv, STM32_I2C_DR_OFFSET, (priv->flags & I2C_M_TEN) ? - 0 :((priv->msgv->addr << 1) | (priv->flags & I2C_M_READ))); + 0 : ((priv->msgv->addr << 1) | + (priv->flags & I2C_M_READ))); i2cinfo("Address sent. Addr=%#02x Write/Read bit=%i\n", priv->msgv->addr, (priv->flags & I2C_M_READ)); /* Flag that address has just been sent */ - priv->check_addr_ACK = true; + priv->check_addr_ack = true; stm32_i2c_traceevent(priv, I2CEVENT_SENDADDR, priv->msgv->addr); } @@ -1407,7 +1435,8 @@ static int stm32_i2c_isr_process(struct stm32_i2c_priv_s *priv) { /* TODO: untested!! */ - i2cwarn(" An empty message has been detected, ignoring and passing to next message.\n"); + i2cwarn(" An empty message has been detected, " + "ignoring and passing to next message.\n"); /* Trace event */ @@ -1432,7 +1461,7 @@ static int stm32_i2c_isr_process(struct stm32_i2c_priv_s *priv) * received the address is valid and transmission can continue. */ - /* Check for NACK after an address*/ + /* Check for NACK after an address */ #ifndef CONFIG_I2C_POLLED /* When polling the i2c ISR it's not possible to determine when @@ -1453,7 +1482,7 @@ static int stm32_i2c_isr_process(struct stm32_i2c_priv_s *priv) * Note: this commentary is found in both places. */ - else if ((status & I2C_SR1_ADDR) == 0 && priv->check_addr_ACK) + else if ((status & I2C_SR1_ADDR) == 0 && priv->check_addr_ack) { i2cinfo("Invalid Address. Setting stop bit and clearing message\n"); i2cinfo("status %i\n", status); @@ -1467,7 +1496,7 @@ static int stm32_i2c_isr_process(struct stm32_i2c_priv_s *priv) /* Reset flag to check for valid address */ - priv->check_addr_ACK = false; + priv->check_addr_ack = false; /* Send stop bit to clear bus */ @@ -1479,14 +1508,14 @@ static int stm32_i2c_isr_process(struct stm32_i2c_priv_s *priv) } #endif - /* ACK in read mode, ACK in write mode is handled separately */ + /* ACK in read mode, ACK in write mode is handled separately */ else if ((priv->flags & I2C_M_READ) != 0 && (status & I2C_SR1_ADDR) != 0 && - priv->check_addr_ACK) + priv->check_addr_ack) { /* Reset check addr flag as we are handling this event */ - priv->check_addr_ACK = false; + priv->check_addr_ack = false; /* Note: * @@ -1584,13 +1613,14 @@ static int stm32_i2c_isr_process(struct stm32_i2c_priv_s *priv) * The DMAEN bit must be set in the I2C_CR2 register before the ADDR event. */ - stm32_dmasetup(priv->rxdma, priv->config->base+STM32_I2C_DR_OFFSET, - (uint32_t) priv->ptr, priv->dcnt, - DMA_SCR_DIR_P2M | - DMA_SCR_MSIZE_8BITS | - DMA_SCR_PSIZE_8BITS | - DMA_SCR_MINC | - I2C_DMA_PRIO); + stm32_dmasetup(priv->rxdma, + priv->config->base + STM32_I2C_DR_OFFSET, + (uint32_t)priv->ptr, priv->dcnt, + DMA_SCR_DIR_P2M | + DMA_SCR_MSIZE_8BITS | + DMA_SCR_PSIZE_8BITS | + DMA_SCR_MINC | + I2C_DMA_PRIO); /* Do not enable the ITBUFEN bit in the I2C_CR2 register if DMA is * used. @@ -1702,7 +1732,7 @@ static int stm32_i2c_isr_process(struct stm32_i2c_priv_s *priv) /* Address has cleared so don't check on next call */ - priv->check_addr_ACK = false; + priv->check_addr_ack = false; /* Check if we have transmitted the whole message or we are after * the last byte where the stop condition or else(according to the @@ -1723,13 +1753,14 @@ static int stm32_i2c_isr_process(struct stm32_i2c_priv_s *priv) * before the ADDR event. */ - stm32_dmasetup(priv->txdma, priv->config->base+STM32_I2C_DR_OFFSET, + stm32_dmasetup(priv->txdma, + priv->config->base + STM32_I2C_DR_OFFSET, (uint32_t) priv->ptr, priv->dcnt, DMA_SCR_DIR_M2P | DMA_SCR_MSIZE_8BITS | DMA_SCR_PSIZE_8BITS | DMA_SCR_MINC | - I2C_DMA_PRIO ); + I2C_DMA_PRIO); /* Do not enable the ITBUFEN bit in the I2C_CR2 register if DMA is * used. @@ -1796,12 +1827,13 @@ static int stm32_i2c_isr_process(struct stm32_i2c_priv_s *priv) stm32_i2c_modifyreg(priv, STM32_I2C_CR2_OFFSET, 0, I2C_CR2_ITBUFEN); } #endif + if (priv->dcnt == 0 && priv->msgc > 0 && (priv->msgv->flags & I2C_M_NOSTART) != 0) { /* Set condition to get to next message */ - priv->dcnt =- 1; + priv->dcnt = -1; stm32_i2c_traceevent(priv, I2CEVENT_WRITE_NO_RESTART, priv->dcnt); } } @@ -1839,7 +1871,7 @@ static int stm32_i2c_isr_process(struct stm32_i2c_priv_s *priv) (status & (I2C_SR1_RXNE | I2C_SR1_BTF)) != 0) { /* When read flag is set and the receive buffer is not empty - *(RXNE is set) then the driver can read from the data register. + * (RXNE is set) then the driver can read from the data register. */ status |= (stm32_i2c_getreg(priv, STM32_I2C_SR2_OFFSET) << 16); @@ -1924,7 +1956,7 @@ static int stm32_i2c_isr_process(struct stm32_i2c_priv_s *priv) * device wasn't ready yet. */ - else + else { #ifdef CONFIG_I2C_POLLED stm32_i2c_traceevent(priv, I2CEVENT_POLL_DEV_NOT_RDY, 0); @@ -2034,13 +2066,13 @@ static int stm32_i2c_isr(int irq, void *context, FAR void *arg) } #endif -/***************************************************************************** +/************************************************************************************ * Name: stm32_i2c_dmarxcallback * * Description: * Called when the RX DMA completes * - *****************************************************************************/ + ************************************************************************************/ #ifdef CONFIG_STM32_I2C_DMA static void stm32_i2c_dmarxcallback(DMA_HANDLE handle, uint8_t status, void *arg) @@ -2088,13 +2120,13 @@ static void stm32_i2c_dmarxcallback(DMA_HANDLE handle, uint8_t status, void *arg } #endif /* ifdef CONFIG_STM32_I2C_DMA */ -/***************************************************************************** +/************************************************************************************ * Name: stm32_i2c_dmarxcallback * * Description: * Called when the RX DMA completes * - *****************************************************************************/ + ************************************************************************************/ #ifdef CONFIG_STM32_I2C_DMA static void stm32_i2c_dmatxcallback(DMA_HANDLE handle, uint8_t status, void *arg) @@ -2244,21 +2276,28 @@ 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) +static int stm32_i2c_transfer(FAR struct i2c_master_s *dev, + FAR struct i2c_msg_s *msgs, int count) { FAR struct stm32_i2c_priv_s *priv = (struct stm32_i2c_priv_s *)dev; uint32_t status = 0; #ifdef I2C1_FSMC_CONFLICT uint32_t ahbenr; #endif - int ret = 0; + int ret; DEBUGASSERT(count); - stm32_i2c_sem_wait(priv); /* Ensure that address or flags don't change meanwhile */ + + /* Ensure that address or flags don't change meanwhile */ + + ret = stm32_i2c_sem_wait(priv); + if (ret < 0) + { + return ret; + } #ifdef CONFIG_STM32_I2C_DMA - /* stop DMA just in case */ + /* Stop DMA just in case */ stm32_i2c_modifyreg(priv, STM32_I2C_CR2_OFFSET, I2C_CR2_DMAEN, 0); stm32_dmastop(priv->rxdma); @@ -2472,7 +2511,7 @@ static int stm32_i2c_reset(FAR struct i2c_master_s *dev) uint32_t scl_gpio; uint32_t sda_gpio; uint32_t frequency; - int ret = ERROR; + int ret; DEBUGASSERT(dev); @@ -2482,7 +2521,13 @@ static int stm32_i2c_reset(FAR struct i2c_master_s *dev) /* Lock out other clients */ - stm32_i2c_sem_wait(priv); + ret = stm32_i2c_sem_wait_uninterruptible(priv); + if (ret < 0) + { + return ret; + } + + ret = -EIO; /* Save the current frequency */ @@ -2642,17 +2687,18 @@ FAR struct i2c_master_s *stm32_i2cbus_initialize(int port) stm32_i2c_init(priv); #ifdef CONFIG_STM32_I2C_DMA - /* Get DMA channels. NOTE: stm32_dmachannel() will always assign the DMA channel. - * if the channel is not available, then stm32_dmachannel() will block and wait - * until the channel becomes available. WARNING: If you have another device sharing - * a DMA channel with SPI and the code never releases that channel, then the call - * to stm32_dmachannel() will hang forever in this function! Don't let your - * design do that! - */ + /* Get DMA channels. NOTE: stm32_dmachannel() will always assign the DMA + * channel. If the channel is not available, then stm32_dmachannel() will + * block and wait until the channel becomes available. WARNING: If you + * have another device sharing a DMA channel with SPI and the code never + * releases that channel, then the call to stm32_dmachannel() will hang + * forever in this function! Don't let your design do that! + */ + priv->rxdma = stm32_dmachannel(priv->rxch); priv->txdma = stm32_dmachannel(priv->txch); DEBUGASSERT(priv->rxdma && priv->txdma); -#endif /* #ifdef CONFIG_STM32_I2C_DMA */ +#endif /* CONFIG_STM32_I2C_DMA */ } leave_critical_section(flags); diff --git a/arch/arm/src/stm32f0l0g0/stm32_i2c.c b/arch/arm/src/stm32f0l0g0/stm32_i2c.c index c4e3b11dbc7..fa1beb916be 100644 --- a/arch/arm/src/stm32f0l0g0/stm32_i2c.c +++ b/arch/arm/src/stm32f0l0g0/stm32_i2c.c @@ -163,16 +163,19 @@ * CONFIG_STM32F0L0G0_I2C3 * CONFIG_STM32F0L0G0_I2C4 * - * To configure the ISR timeout using fixed values (CONFIG_STM32F0L0G0_I2C_DYNTIMEO=n): + * To configure the ISR timeout using fixed values + * (CONFIG_STM32F0L0G0_I2C_DYNTIMEO=n): * * CONFIG_STM32F0L0G0_I2CTIMEOSEC (Timeout in seconds) * CONFIG_STM32F0L0G0_I2CTIMEOMS (Timeout in milliseconds) * CONFIG_STM32F0L0G0_I2CTIMEOTICKS (Timeout in ticks) * - * To configure the ISR timeout using dynamic values (CONFIG_STM32F0L0G0_I2C_DYNTIMEO=y): + * To configure the ISR timeout using dynamic values + * (CONFIG_STM32F0L0G0_I2C_DYNTIMEO=y): * * CONFIG_STM32F0L0G0_I2C_DYNTIMEO_USECPERBYTE (Timeout in microseconds per byte) - * CONFIG_STM32F0L0G0_I2C_DYNTIMEO_STARTSTOP (Timeout for start/stop in milliseconds) + * CONFIG_STM32F0L0G0_I2C_DYNTIMEO_STARTSTOP (Timeout for start/stop in + * milliseconds) * * Debugging output enabled with: * @@ -292,7 +295,7 @@ /* Unused bit in I2c_ISR used to communicate a bad state has occurred in * the isr processing -*/ + */ #define I2C_INT_BAD_STATE 0x8000000 @@ -388,8 +391,12 @@ struct stm32_i2c_config_s struct stm32_i2c_priv_s { - const struct stm32_i2c_config_s *config; /* Port configuration */ + /* Port configuration */ + + const struct stm32_i2c_config_s *config; + int refs; /* Reference count */ + sem_t sem_excl; /* Mutual exclusion semaphore */ #ifndef CONFIG_I2C_POLLED sem_t sem_isr; /* Interrupt wait semaphore */ @@ -436,14 +443,15 @@ struct stm32_i2c_inst_s static inline uint16_t stm32_i2c_getreg(FAR struct stm32_i2c_priv_s *priv, uint8_t offset); -static inline void stm32_i2c_putreg(FAR struct stm32_i2c_priv_s *priv, uint8_t offset, - uint16_t value); -static inline void stm32_i2c_putreg32(FAR struct stm32_i2c_priv_s *priv, uint8_t offset, - uint32_t value); +static inline void stm32_i2c_putreg(FAR struct stm32_i2c_priv_s *priv, + uint8_t offset, uint16_t value); +static inline void stm32_i2c_putreg32(FAR struct stm32_i2c_priv_s *priv, + uint8_t offset, uint32_t value); static inline void stm32_i2c_modifyreg32(FAR struct stm32_i2c_priv_s *priv, uint8_t offset, uint32_t clearbits, uint32_t setbits); -static inline void stm32_i2c_sem_wait(FAR struct i2c_master_s *dev); +static inline int stm32_i2c_sem_wait(FAR struct i2c_master_s *dev); +static int stm32_i2c_sem_wait_uninterruptble(FAR struct i2c_master_s *dev); #ifdef CONFIG_STM32F0L0G0_I2C_DYNTIMEO static useconds_t stm32_i2c_tousecs(int msgc, FAR struct i2c_msg_s *msgs); #endif /* CONFIG_STM32F0L0G0_I2C_DYNTIMEO */ @@ -471,10 +479,10 @@ static int stm32_i2c_isr(int irq, void *context, FAR void *arg); 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_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, - int count); +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, int count); #ifdef CONFIG_I2C_RESET static int stm32_i2c_reset(FAR struct i2c_master_s * dev); #endif @@ -661,8 +669,8 @@ static inline uint32_t stm32_i2c_getreg32(FAR struct stm32_i2c_priv_s *priv, * ************************************************************************************/ -static inline void stm32_i2c_putreg(FAR struct stm32_i2c_priv_s *priv, uint8_t offset, - uint16_t value) +static inline void stm32_i2c_putreg(FAR struct stm32_i2c_priv_s *priv, + uint8_t offset, uint16_t value) { putreg16(value, priv->config->base + offset); } @@ -681,7 +689,6 @@ static inline void stm32_i2c_putreg32(FAR struct stm32_i2c_priv_s *priv, putreg32(value, priv->config->base + offset); } - /************************************************************************************ * Name: stm32_i2c_modifyreg32 * @@ -701,13 +708,28 @@ static inline void stm32_i2c_modifyreg32(FAR struct stm32_i2c_priv_s *priv, * Name: stm32_i2c_sem_wait * * Description: + * Take the exclusive access, waiting as necessary. May be interrupted by a + * signal. + * + ************************************************************************************/ + +static inline int stm32_i2c_sem_wait(FAR struct i2c_master_s *dev) +{ + return nxsem_wait(&((struct stm32_i2c_inst_s *)dev)->priv->sem_excl); +} + +/************************************************************************************ + * Name: stm32_i2c_sem_wait_uninterruptble + * + * Description: * Take the exclusive access, waiting as necessary * ************************************************************************************/ -static inline void stm32_i2c_sem_wait(FAR struct i2c_master_s *dev) +static int stm32_i2c_sem_wait_uninterruptble(FAR struct i2c_master_s *dev) { - nxsem_wait_uninterruptible(&((struct stm32_i2c_inst_s *)dev)->priv->sem_excl); + return + nxsem_wait_uninterruptible(&((struct stm32_i2c_inst_s *)dev)->priv->sem_excl); } /************************************************************************************ @@ -750,7 +772,8 @@ static useconds_t stm32_i2c_tousecs(int msgc, FAR struct i2c_msg_s *msgs) #ifndef CONFIG_I2C_POLLED static inline void stm32_i2c_enableinterrupts(struct stm32_i2c_priv_s *priv) { - stm32_i2c_modifyreg32(priv, STM32_I2C_CR1_OFFSET, 0, (I2C_CR1_TXRX | I2C_CR1_NACKIE)); + stm32_i2c_modifyreg32(priv, STM32_I2C_CR1_OFFSET, 0, + (I2C_CR1_TXRX | I2C_CR1_NACKIE)); } #endif @@ -816,6 +839,7 @@ static inline int stm32_i2c_sem_waitdone(FAR struct stm32_i2c_priv_s *priv) abstime.tv_nsec -= 1000 * 1000 * 1000; } #endif + /* Wait until either the transfer is complete or the timeout expires */ ret = nxsem_timedwait_uninterruptible(&priv->sem_isr, &abstime); @@ -907,7 +931,7 @@ static inline void stm32_i2c_set_7bit_address(FAR struct stm32_i2c_priv_s *priv) { stm32_i2c_modifyreg32(priv, STM32_I2C_CR2_OFFSET, I2C_CR2_SADD7_MASK, - ((priv->msgv->addr & 0x7F) << I2C_CR2_SADD7_SHIFT)); + ((priv->msgv->addr & 0x7f) << I2C_CR2_SADD7_SHIFT)); } /************************************************************************************ @@ -977,7 +1001,6 @@ stm32_i2c_disable_reload(FAR struct stm32_i2c_priv_s *priv) stm32_i2c_modifyreg32(priv, STM32_I2C_CR2_OFFSET, I2C_CR2_RELOAD, 0); } - /************************************************************************************ * Name: stm32_i2c_sem_waitstop * @@ -1026,7 +1049,6 @@ static inline void stm32_i2c_sem_waitstop(FAR struct stm32_i2c_priv_s *priv) { return; } - } /* Loop until the stop is complete or a timeout occurs. */ @@ -1135,7 +1157,7 @@ static void stm32_i2c_tracenew(FAR struct stm32_i2c_priv_s *priv, { /* Yes.. bump up the trace index (unless we are out of trace entries) */ - if (priv->tndx >= (CONFIG_I2C_NTRACE-1)) + if (priv->tndx >= (CONFIG_I2C_NTRACE - 1)) { i2cerr("ERROR: Trace table overflow\n"); return; @@ -1176,7 +1198,7 @@ static void stm32_i2c_traceevent(FAR struct stm32_i2c_priv_s *priv, /* Bump up the trace index (unless we are out of trace entries) */ - if (priv->tndx >= (CONFIG_I2C_NTRACE-1)) + if (priv->tndx >= (CONFIG_I2C_NTRACE - 1)) { i2cerr("ERROR: Trace table overflow\n"); return; @@ -1200,7 +1222,7 @@ static void stm32_i2c_tracedump(FAR struct stm32_i2c_priv_s *priv) trace = &priv->trace[i]; syslog(LOG_DEBUG, "%2d. STATUS: %08x COUNT: %3d EVENT: %2d PARM: %08x TIME: %d\n", - i+1, trace->status, trace->count, trace->event, trace->parm, + i + 1, trace->status, trace->count, trace->event, trace->parm, (int)(trace->time - priv->start_time)); } } @@ -1273,7 +1295,6 @@ static void stm32_i2c_setclock(FAR struct stm32_i2c_priv_s *priv, uint32_t frequ if (frequency != priv->frequency) { - /* The Speed and timing calculation are based on the following * fI2CCLK = HSI and is 16Mhz * Analog filter is on, @@ -1282,39 +1303,38 @@ static void stm32_i2c_setclock(FAR struct stm32_i2c_priv_s *priv, uint32_t frequ * Mode is FastMode */ - if (frequency == 100000) - { - presc = 0; - scl_delay = 5; - sda_delay = 0; - scl_h_period = 61; - scl_l_period = 89; - - } - else if (frequency == 400000) - { - presc = 0; - scl_delay = 3; - sda_delay = 0; - scl_h_period = 6; - scl_l_period = 24; - } - else if (frequency == 1000000) - { - presc = 0; - scl_delay = 2; - sda_delay = 0; - scl_h_period = 1; - scl_l_period = 5; - } - else - { - presc = 7; - scl_delay = 0; - sda_delay = 0; - scl_h_period = 35; - scl_l_period = 162; - } + if (frequency == 100000) + { + presc = 0; + scl_delay = 5; + sda_delay = 0; + scl_h_period = 61; + scl_l_period = 89; + } + else if (frequency == 400000) + { + presc = 0; + scl_delay = 3; + sda_delay = 0; + scl_h_period = 6; + scl_l_period = 24; + } + else if (frequency == 1000000) + { + presc = 0; + scl_delay = 2; + sda_delay = 0; + scl_h_period = 1; + scl_l_period = 5; + } + else + { + presc = 7; + scl_delay = 0; + sda_delay = 0; + scl_h_period = 35; + scl_l_period = 162; + } uint32_t timingr = (presc << I2C_TIMINGR_PRESC_SHIFT) | @@ -1588,10 +1608,8 @@ static int stm32_i2c_isr_process(struct stm32_i2c_priv_s *priv) if (status & I2C_INT_NACK) { - if (priv->astart == true) { - /* NACK received on first (address) byte: address is invalid */ i2cinfo("NACK: Address invalid: dcnt=%i msgc=%i status=0x%08x\n", @@ -1653,7 +1671,6 @@ static int stm32_i2c_isr_process(struct stm32_i2c_priv_s *priv) else if ((priv->flags & (I2C_M_READ)) == 0 && (status & (I2C_ISR_TXIS)) != 0) { - /* TXIS interrupt occurred, address valid, ready to transmit */ stm32_i2c_traceevent(priv, I2CEVENT_WRITE, 0); @@ -1884,7 +1901,6 @@ static int stm32_i2c_isr_process(struct stm32_i2c_priv_s *priv) priv->msgv++; stm32_i2c_sendstart(priv); - } else { @@ -1970,7 +1986,8 @@ static int stm32_i2c_isr_process(struct stm32_i2c_priv_s *priv) priv->flags = priv->msgv->flags; /* if this is the last message, disable reload so the - * TC event fires next time */ + * TC event fires next time. + */ if (priv->msgc == 0) { @@ -2097,7 +2114,8 @@ static int stm32_i2c_isr_process(struct stm32_i2c_priv_s *priv) stm32_i2c_traceevent(priv, I2CEVENT_ISR_SHUTDOWN, 0); /* clear pointer to message content to reflect we are done - * with the current transaction */ + * with the current transaction. + */ priv->msgv = NULL; @@ -2262,7 +2280,8 @@ static int stm32_i2c_deinit(FAR struct stm32_i2c_priv_s *priv) * ************************************************************************************/ -static int stm32_i2c_process(FAR struct i2c_master_s *dev, FAR struct i2c_msg_s *msgs, int count) +static int stm32_i2c_process(FAR struct i2c_master_s *dev, + FAR struct i2c_msg_s *msgs, int count) { struct stm32_i2c_inst_s *inst = (struct stm32_i2c_inst_s *)dev; FAR struct stm32_i2c_priv_s *priv = inst->priv; @@ -2354,12 +2373,12 @@ static int stm32_i2c_process(FAR struct i2c_master_s *dev, FAR struct i2c_msg_s errval = ETIMEDOUT; i2cerr("ERROR: Waitdone timed out CR1: 0x%08x CR2: 0x%08x status: 0x%08x\n", - cr1, cr2,status); + cr1, cr2, status); } else { i2cinfo("Waitdone success: CR1: 0x%08x CR2: 0x%08x status: 0x%08x\n", - cr1, cr2,status ); + cr1, cr2, status); } UNUSED(cr1); @@ -2458,7 +2477,7 @@ static int stm32_i2c_process(FAR struct i2c_master_s *dev, FAR struct i2c_msg_s */ clock_t start = clock_systimer(); - clock_t timeout = USEC2TICK(USEC_PER_SEC/priv->frequency) + 1; + clock_t timeout = USEC2TICK(USEC_PER_SEC / priv->frequency) + 1; status = stm32_i2c_getstatus(priv); @@ -2491,11 +2510,20 @@ static int stm32_i2c_process(FAR struct i2c_master_s *dev, FAR struct i2c_msg_s * ************************************************************************************/ -static int stm32_i2c_transfer(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, int count) { - stm32_i2c_sem_wait(dev); /* ensure that address or flags don't change meanwhile */ - return stm32_i2c_process(dev, msgs, count); + int ret; + + /* Ensure that address or flags don't change meanwhile */ + + ret = stm32_i2c_sem_wait(dev); + if (ret >= 0) + { + ret = stm32_i2c_process(dev, msgs, count); + } + + return ret; } /************************************************************************************ @@ -2515,7 +2543,7 @@ static int stm32_i2c_reset(FAR struct i2c_master_s * dev) uint32_t scl_gpio; uint32_t sda_gpio; uint32_t frequency; - int ret = ERROR; + int ret; DEBUGASSERT(dev); @@ -2529,7 +2557,13 @@ static int stm32_i2c_reset(FAR struct i2c_master_s * dev) /* Lock out other clients */ - stm32_i2c_sem_wait(dev); + ret = stm32_i2c_sem_wait_uninterruptble(dev); + if (ret < 0) + { + return ret; + } + + ret = -EIO; /* Save the current frequency */ @@ -2676,6 +2710,7 @@ static int stm32_i2c_pm_prepare(FAR struct pm_callback_s *cb, int domain, case PM_STANDBY: case PM_SLEEP: + /* Check if exclusive lock for I2C bus is held. */ if (nxsem_getvalue(&priv->sem_excl, &sval) < 0) @@ -2694,6 +2729,7 @@ static int stm32_i2c_pm_prepare(FAR struct pm_callback_s *cb, int domain, break; default: + /* Should not get here */ break; @@ -2726,8 +2762,8 @@ FAR struct i2c_master_s *stm32_i2cbus_initialize(int port) #if 0 /* REVISIT: this is not true for all STM32 M0 */ #if STM32_HSI_FREQUENCY != 8000000 || defined(INVALID_CLOCK_SOURCE) -# warning STM32_I2C_INIT: Peripheral clock is HSI and it must be 16mHz or the speed/timing calculations need to be redone. - return NULL; +# warning STM32_I2C_INIT: Peripheral clock is HSI and it must be 16mHz or the speed/timing calculations need to be redone. + return NULL; #endif #endif @@ -2846,4 +2882,4 @@ int stm32_i2cbus_uninitialize(FAR struct i2c_master_s * dev) } #endif /* CONFIG_STM32F0L0G0_I2C1 || CONFIG_STM32F0L0G0_I2C2 || \ - CONFIG_STM32F0L0G0_I2C3 || CONFIG_STM32F0L0G0_I2C4 */ + * CONFIG_STM32F0L0G0_I2C3 || CONFIG_STM32F0L0G0_I2C4 */ diff --git a/arch/arm/src/stm32f7/stm32_i2c.c b/arch/arm/src/stm32f7/stm32_i2c.c index 7629b9a7c2d..a94254bbe0a 100644 --- a/arch/arm/src/stm32f7/stm32_i2c.c +++ b/arch/arm/src/stm32f7/stm32_i2c.c @@ -181,10 +181,12 @@ * CONFIG_STM32F7_I2CTIMEOMS (Timeout in milliseconds) * CONFIG_STM32F7_I2CTIMEOTICKS (Timeout in ticks) * - * To configure the ISR timeout using dynamic values (CONFIG_STM32F7_I2C_DYNTIMEO=y): + * To configure the ISR timeout using dynamic values + * (CONFIG_STM32F7_I2C_DYNTIMEO=y): * * CONFIG_STM32F7_I2C_DYNTIMEO_USECPERBYTE (Timeout in microseconds per byte) - * CONFIG_STM32F7_I2C_DYNTIMEO_STARTSTOP (Timeout for start/stop in milliseconds) + * CONFIG_STM32F7_I2C_DYNTIMEO_STARTSTOP (Timeout for start/stop in + * milliseconds) * * Debugging output enabled with: * @@ -328,7 +330,7 @@ /* Unused bit in I2c_ISR used to communicate a bad state has occurred in * the isr processing -*/ + */ #define I2C_INT_BAD_STATE 0x8000000 @@ -425,7 +427,10 @@ struct stm32_i2c_config_s struct stm32_i2c_priv_s { - const struct stm32_i2c_config_s *config; /* Port configuration */ + /* Port configuration */ + + const struct stm32_i2c_config_s *config; + int refs; /* Reference count */ sem_t sem_excl; /* Mutual exclusion semaphore */ #ifndef CONFIG_I2C_POLLED @@ -473,14 +478,15 @@ struct stm32_i2c_inst_s static inline uint16_t stm32_i2c_getreg(FAR struct stm32_i2c_priv_s *priv, uint8_t offset); -static inline void stm32_i2c_putreg(FAR struct stm32_i2c_priv_s *priv, uint8_t offset, - uint16_t value); -static inline void stm32_i2c_putreg32(FAR struct stm32_i2c_priv_s *priv, uint8_t offset, - uint32_t value); +static inline void stm32_i2c_putreg(FAR struct stm32_i2c_priv_s *priv, + uint8_t offset, uint16_t value); +static inline void stm32_i2c_putreg32(FAR struct stm32_i2c_priv_s *priv, + uint8_t offset, uint32_t value); static inline void stm32_i2c_modifyreg32(FAR struct stm32_i2c_priv_s *priv, uint8_t offset, uint32_t clearbits, uint32_t setbits); -static inline void stm32_i2c_sem_wait(FAR struct i2c_master_s *dev); +static inline int stm32_i2c_sem_wait(FAR struct i2c_master_s *dev); +static int stm32_i2c_sem_wait_uninterruptible(FAR struct i2c_master_s *dev); #ifdef CONFIG_STM32F7_I2C_DYNTIMEO static useconds_t stm32_i2c_tousecs(int msgc, FAR struct i2c_msg_s *msgs); #endif /* CONFIG_STM32F7_I2C_DYNTIMEO */ @@ -508,10 +514,10 @@ static int stm32_i2c_isr(int irq, void *context, FAR void *arg); 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_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, - int count); +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, int count); #ifdef CONFIG_I2C_RESET static int stm32_i2c_reset(FAR struct i2c_master_s * dev); #endif @@ -702,8 +708,8 @@ static inline uint32_t stm32_i2c_getreg32(FAR struct stm32_i2c_priv_s *priv, * ************************************************************************************/ -static inline void stm32_i2c_putreg(FAR struct stm32_i2c_priv_s *priv, uint8_t offset, - uint16_t value) +static inline void stm32_i2c_putreg(FAR struct stm32_i2c_priv_s *priv, + uint8_t offset, uint16_t value) { putreg16(value, priv->config->base + offset); } @@ -722,7 +728,6 @@ static inline void stm32_i2c_putreg32(FAR struct stm32_i2c_priv_s *priv, putreg32(value, priv->config->base + offset); } - /************************************************************************************ * Name: stm32_i2c_modifyreg32 * @@ -742,13 +747,29 @@ static inline void stm32_i2c_modifyreg32(FAR struct stm32_i2c_priv_s *priv, * Name: stm32_i2c_sem_wait * * Description: - * Take the exclusive access, waiting as necessary + * Take the exclusive access, waiting as necessary. May be interrupted by a + * signal. * ************************************************************************************/ -static inline void stm32_i2c_sem_wait(FAR struct i2c_master_s *dev) +static inline int stm32_i2c_sem_wait(FAR struct i2c_master_s *dev) { - nxsem_wait_uninterruptible(&((struct stm32_i2c_inst_s *)dev)->priv->sem_excl); + return nxsem_wait(&((struct stm32_i2c_inst_s *)dev)->priv->sem_excl); +} + +/************************************************************************************ + * Name: stm32_i2c_sem_wait_uninterruptible + * + * Description: + * Take the exclusive access, waiting as necessary. May be interrupted by a + * signal. + * + ************************************************************************************/ + +static int stm32_i2c_sem_wait_uninterruptible(FAR struct i2c_master_s *dev) +{ + return + nxsem_wait_uninterruptible(&((struct stm32_i2c_inst_s *)dev)->priv->sem_excl); } /************************************************************************************ @@ -791,7 +812,8 @@ static useconds_t stm32_i2c_tousecs(int msgc, FAR struct i2c_msg_s *msgs) #ifndef CONFIG_I2C_POLLED static inline void stm32_i2c_enableinterrupts(struct stm32_i2c_priv_s *priv) { - stm32_i2c_modifyreg32(priv, STM32_I2C_CR1_OFFSET, 0, (I2C_CR1_TXRX | I2C_CR1_NACKIE)); + stm32_i2c_modifyreg32(priv, STM32_I2C_CR1_OFFSET, 0, + (I2C_CR1_TXRX | I2C_CR1_NACKIE)); } #endif @@ -857,6 +879,7 @@ static inline int stm32_i2c_sem_waitdone(FAR struct stm32_i2c_priv_s *priv) abstime.tv_nsec -= 1000 * 1000 * 1000; } #endif + /* Wait until either the transfer is complete or the timeout expires */ ret = nxsem_timedwait_uninterruptible(&priv->sem_isr, &abstime); @@ -948,7 +971,7 @@ static inline void stm32_i2c_set_7bit_address(FAR struct stm32_i2c_priv_s *priv) { stm32_i2c_modifyreg32(priv, STM32_I2C_CR2_OFFSET, I2C_CR2_SADD7_MASK, - ((priv->msgv->addr & 0x7F) << I2C_CR2_SADD7_SHIFT)); + ((priv->msgv->addr & 0x7f) << I2C_CR2_SADD7_SHIFT)); } /************************************************************************************ @@ -1018,7 +1041,6 @@ stm32_i2c_disable_reload(FAR struct stm32_i2c_priv_s *priv) stm32_i2c_modifyreg32(priv, STM32_I2C_CR2_OFFSET, I2C_CR2_RELOAD, 0); } - /************************************************************************************ * Name: stm32_i2c_sem_waitstop * @@ -1067,7 +1089,6 @@ static inline void stm32_i2c_sem_waitstop(FAR struct stm32_i2c_priv_s *priv) { return; } - } /* Loop until the stop is complete or a timeout occurs. */ @@ -1176,7 +1197,7 @@ static void stm32_i2c_tracenew(FAR struct stm32_i2c_priv_s *priv, { /* Yes.. bump up the trace index (unless we are out of trace entries) */ - if (priv->tndx >= (CONFIG_I2C_NTRACE-1)) + if (priv->tndx >= (CONFIG_I2C_NTRACE - 1)) { i2cerr("ERROR: Trace table overflow\n"); return; @@ -1217,7 +1238,7 @@ static void stm32_i2c_traceevent(FAR struct stm32_i2c_priv_s *priv, /* Bump up the trace index (unless we are out of trace entries) */ - if (priv->tndx >= (CONFIG_I2C_NTRACE-1)) + if (priv->tndx >= (CONFIG_I2C_NTRACE - 1)) { i2cerr("ERROR: Trace table overflow\n"); return; @@ -1241,7 +1262,7 @@ static void stm32_i2c_tracedump(FAR struct stm32_i2c_priv_s *priv) trace = &priv->trace[i]; syslog(LOG_DEBUG, "%2d. STATUS: %08x COUNT: %3d EVENT: %2d PARM: %08x TIME: %d\n", - i+1, trace->status, trace->count, trace->event, trace->parm, + i + 1, trace->status, trace->count, trace->event, trace->parm, (int)(trace->time - priv->start_time)); } } @@ -1314,7 +1335,6 @@ static void stm32_i2c_setclock(FAR struct stm32_i2c_priv_s *priv, uint32_t frequ if (frequency != priv->frequency) { - /* The Speed and timing calculation are based on the following * fI2CCLK = HSI and is 16Mhz * Analog filter is on, @@ -1323,39 +1343,38 @@ static void stm32_i2c_setclock(FAR struct stm32_i2c_priv_s *priv, uint32_t frequ * Mode is FastMode */ - if (frequency == 100000) - { - presc = 0; - scl_delay = 5; - sda_delay = 0; - scl_h_period = 61; - scl_l_period = 89; - - } - else if (frequency == 400000) - { - presc = 0; - scl_delay = 3; - sda_delay = 0; - scl_h_period = 6; - scl_l_period = 24; - } - else if (frequency == 1000000) - { - presc = 0; - scl_delay = 2; - sda_delay = 0; - scl_h_period = 1; - scl_l_period = 5; - } - else - { - presc = 7; - scl_delay = 0; - sda_delay = 0; - scl_h_period = 35; - scl_l_period = 162; - } + if (frequency == 100000) + { + presc = 0; + scl_delay = 5; + sda_delay = 0; + scl_h_period = 61; + scl_l_period = 89; + } + else if (frequency == 400000) + { + presc = 0; + scl_delay = 3; + sda_delay = 0; + scl_h_period = 6; + scl_l_period = 24; + } + else if (frequency == 1000000) + { + presc = 0; + scl_delay = 2; + sda_delay = 0; + scl_h_period = 1; + scl_l_period = 5; + } + else + { + presc = 7; + scl_delay = 0; + sda_delay = 0; + scl_h_period = 35; + scl_l_period = 162; + } uint32_t timingr = (presc << I2C_TIMINGR_PRESC_SHIFT) | @@ -1629,10 +1648,8 @@ static int stm32_i2c_isr_process(struct stm32_i2c_priv_s *priv) if (status & I2C_INT_NACK) { - if (priv->astart == true) { - /* NACK received on first (address) byte: address is invalid */ i2cinfo("NACK: Address invalid: dcnt=%i msgc=%i status=0x%08x\n", @@ -1694,7 +1711,6 @@ static int stm32_i2c_isr_process(struct stm32_i2c_priv_s *priv) else if ((priv->flags & (I2C_M_READ)) == 0 && (status & (I2C_ISR_TXIS)) != 0) { - /* TXIS interrupt occurred, address valid, ready to transmit */ stm32_i2c_traceevent(priv, I2CEVENT_WRITE, 0); @@ -1925,7 +1941,6 @@ static int stm32_i2c_isr_process(struct stm32_i2c_priv_s *priv) priv->msgv++; stm32_i2c_sendstart(priv); - } else { @@ -2011,7 +2026,8 @@ static int stm32_i2c_isr_process(struct stm32_i2c_priv_s *priv) priv->flags = priv->msgv->flags; /* if this is the last message, disable reload so the - * TC event fires next time */ + * TC event fires next time. + */ if (priv->msgc == 0) { @@ -2138,7 +2154,8 @@ static int stm32_i2c_isr_process(struct stm32_i2c_priv_s *priv) stm32_i2c_traceevent(priv, I2CEVENT_ISR_SHUTDOWN, 0); /* clear pointer to message content to reflect we are done - * with the current transaction */ + * with the current transaction. + */ priv->msgv = NULL; @@ -2307,7 +2324,8 @@ static int stm32_i2c_deinit(FAR struct stm32_i2c_priv_s *priv) * ************************************************************************************/ -static int stm32_i2c_process(FAR struct i2c_master_s *dev, FAR struct i2c_msg_s *msgs, int count) +static int stm32_i2c_process(FAR struct i2c_master_s *dev, + FAR struct i2c_msg_s *msgs, int count) { struct stm32_i2c_inst_s *inst = (struct stm32_i2c_inst_s *)dev; FAR struct stm32_i2c_priv_s *priv = inst->priv; @@ -2399,12 +2417,12 @@ static int stm32_i2c_process(FAR struct i2c_master_s *dev, FAR struct i2c_msg_s errval = ETIMEDOUT; i2cerr("ERROR: Waitdone timed out CR1: 0x%08x CR2: 0x%08x status: 0x%08x\n", - cr1, cr2,status); + cr1, cr2, status); } else { i2cinfo("Waitdone success: CR1: 0x%08x CR2: 0x%08x status: 0x%08x\n", - cr1, cr2,status ); + cr1, cr2, status); } UNUSED(cr1); @@ -2503,7 +2521,7 @@ static int stm32_i2c_process(FAR struct i2c_master_s *dev, FAR struct i2c_msg_s */ clock_t start = clock_systimer(); - clock_t timeout = USEC2TICK(USEC_PER_SEC/priv->frequency) + 1; + clock_t timeout = USEC2TICK(USEC_PER_SEC / priv->frequency) + 1; status = stm32_i2c_getstatus(priv); @@ -2536,11 +2554,20 @@ static int stm32_i2c_process(FAR struct i2c_master_s *dev, FAR struct i2c_msg_s * ************************************************************************************/ -static int stm32_i2c_transfer(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, int count) { - stm32_i2c_sem_wait(dev); /* ensure that address or flags don't change meanwhile */ - return stm32_i2c_process(dev, msgs, count); + int ret; + + /* Ensure that address or flags don't change meanwhile */ + + ret = stm32_i2c_sem_wait(dev); + if (ret >= 0) + { + ret = stm32_i2c_process(dev, msgs, count); + } + + return ret; } /************************************************************************************ @@ -2560,7 +2587,7 @@ static int stm32_i2c_reset(FAR struct i2c_master_s * dev) uint32_t scl_gpio; uint32_t sda_gpio; uint32_t frequency; - int ret = ERROR; + int ret; DEBUGASSERT(dev); @@ -2574,7 +2601,13 @@ static int stm32_i2c_reset(FAR struct i2c_master_s * dev) /* Lock out other clients */ - stm32_i2c_sem_wait(dev); + ret = stm32_i2c_sem_wait_uninterruptible(dev); + if (ret < 0) + { + return ret; + } + + ret = -EIO; /* Save the current frequency */ @@ -2721,6 +2754,7 @@ static int stm32_i2c_pm_prepare(FAR struct pm_callback_s *cb, int domain, case PM_STANDBY: case PM_SLEEP: + /* Check if exclusive lock for I2C bus is held. */ if (nxsem_getvalue(&priv->sem_excl, &sval) < 0) @@ -2739,6 +2773,7 @@ static int stm32_i2c_pm_prepare(FAR struct pm_callback_s *cb, int domain, break; default: + /* Should not get here */ break; @@ -2770,8 +2805,8 @@ FAR struct i2c_master_s *stm32_i2cbus_initialize(int port) #endif #if STM32_HSI_FREQUENCY != 16000000 || defined(INVALID_CLOCK_SOURCE) -# warning STM32_I2C_INIT: Peripheral clock is HSI and it must be 16mHz or the speed/timing calculations need to be redone. - return NULL; +# warning STM32_I2C_INIT: Peripheral clock is HSI and it must be 16mHz or the speed/timing calculations need to be redone. + return NULL; #endif /* Get I2C private structure */ @@ -2889,4 +2924,4 @@ int stm32_i2cbus_uninitialize(FAR struct i2c_master_s * dev) } #endif /* CONFIG_STM32F7_I2C1 || CONFIG_STM32F7_I2C2 || \ - CONFIG_STM32F7_I2C3 || CONFIG_STM32F7_I2C4 */ + * CONFIG_STM32F7_I2C3 || CONFIG_STM32F7_I2C4 */ diff --git a/arch/arm/src/stm32h7/stm32_i2c.c b/arch/arm/src/stm32h7/stm32_i2c.c index 858094aa064..7a822495d82 100644 --- a/arch/arm/src/stm32h7/stm32_i2c.c +++ b/arch/arm/src/stm32h7/stm32_i2c.c @@ -178,7 +178,8 @@ * CONFIG_STM32H7_I2CTIMEOMS (Timeout in milliseconds) * CONFIG_STM32H7_I2CTIMEOTICKS (Timeout in ticks) * - * To configure the ISR timeout using dynamic values (CONFIG_STM32H7_I2C_DYNTIMEO=y): + * To configure the ISR timeout using dynamic values + * (CONFIG_STM32H7_I2C_DYNTIMEO=y): * * CONFIG_STM32H7_I2C_DYNTIMEO_USECPERBYTE (Timeout in microseconds per byte) * CONFIG_STM32H7_I2C_DYNTIMEO_STARTSTOP (Timeout for start/stop in msec) @@ -379,7 +380,10 @@ struct stm32_i2c_config_s struct stm32_i2c_priv_s { - const struct stm32_i2c_config_s *config; /* Port configuration */ + /* Port configuration */ + + const struct stm32_i2c_config_s *config; + int refs; /* Referernce count */ sem_t sem_excl; /* Mutual exclusion semaphore */ #ifndef CONFIG_I2C_POLLED @@ -434,7 +438,8 @@ static inline void stm32_i2c_putreg32(FAR struct stm32_i2c_priv_s *priv, static inline void stm32_i2c_modifyreg32(FAR struct stm32_i2c_priv_s *priv, uint8_t offset, uint32_t clearbits, uint32_t setbits); -static inline void stm32_i2c_sem_wait(FAR struct i2c_master_s *dev); +static inline int stm32_i2c_sem_wait(FAR struct i2c_master_s *dev); +static int stm32_i2c_sem_wait_uninterruptible(FAR struct i2c_master_s *dev); #ifdef CONFIG_STM32H7_I2C_DYNTIMEO static useconds_t stm32_i2c_tousecs(int msgc, FAR struct i2c_msg_s *msgs); #endif /* CONFIG_STM32H7_I2C_DYNTIMEO */ @@ -462,8 +467,8 @@ static int stm32_i2c_isr(int irq, void *context, FAR void *arg); 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_process(FAR struct i2c_master_s *dev, FAR struct i2c_msg_s *msgs, - int count); +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, int count); #ifdef CONFIG_I2C_RESET @@ -656,8 +661,8 @@ static inline uint32_t stm32_i2c_getreg32(FAR struct stm32_i2c_priv_s *priv, * ************************************************************************************/ -static inline void stm32_i2c_putreg(FAR struct stm32_i2c_priv_s *priv, uint8_t offset, - uint16_t value) +static inline void stm32_i2c_putreg(FAR struct stm32_i2c_priv_s *priv, + uint8_t offset, uint16_t value) { putreg16(value, priv->config->base + offset); } @@ -695,13 +700,29 @@ static inline void stm32_i2c_modifyreg32(FAR struct stm32_i2c_priv_s *priv, * Name: stm32_i2c_sem_wait * * Description: - * Take the exclusive access, waiting as necessary + * Take the exclusive access, waiting as necessary. May be interrupted by a + * signal. * ************************************************************************************/ -static inline void stm32_i2c_sem_wait(FAR struct i2c_master_s *dev) +static inline int stm32_i2c_sem_wait(FAR struct i2c_master_s *dev) { - nxsem_wait_uninterruptible(&((struct stm32_i2c_inst_s *)dev)->priv->sem_excl); + return nxsem_wait(&((struct stm32_i2c_inst_s *)dev)->priv->sem_excl); +} + +/************************************************************************************ + * Name: stm32_i2c_sem_wait_uninterruptible + * + * Description: + * Take the exclusive access, waiting as necessary. May be interrupted by a + * signal. + * + ************************************************************************************/ + +static int stm32_i2c_sem_wait_uninterruptible(FAR struct i2c_master_s *dev) +{ + return + nxsem_wait_uninterruptible(&((struct stm32_i2c_inst_s *)dev)->priv->sem_excl); } /************************************************************************************ @@ -811,6 +832,7 @@ static inline int stm32_i2c_sem_waitdone(FAR struct stm32_i2c_priv_s *priv) abstime.tv_nsec -= 1000 * 1000 * 1000; } #endif + /* Wait until either the transfer is complete or the timeout expires */ ret = nxsem_timedwait_uninterruptible(&priv->sem_isr, &abstime); @@ -902,7 +924,7 @@ static inline void stm32_i2c_set_7bit_address(FAR struct stm32_i2c_priv_s *priv) { stm32_i2c_modifyreg32(priv, STM32_I2C_CR2_OFFSET, I2C_CR2_SADD7_MASK, - ((priv->msgv->addr & 0x7F) << I2C_CR2_SADD7_SHIFT)); + ((priv->msgv->addr & 0x7f) << I2C_CR2_SADD7_SHIFT)); } /************************************************************************************ @@ -1020,7 +1042,6 @@ static inline void stm32_i2c_sem_waitstop(FAR struct stm32_i2c_priv_s *priv) { return; } - } /* Loop until the stop is complete or a timeout occurs. */ @@ -1129,7 +1150,7 @@ static void stm32_i2c_tracenew(FAR struct stm32_i2c_priv_s *priv, { /* Yes.. bump up the trace index (unless we are out of trace entries) */ - if (priv->tndx >= (CONFIG_I2C_NTRACE-1)) + if (priv->tndx >= (CONFIG_I2C_NTRACE - 1)) { i2cerr("ERROR: Trace table overflow\n"); return; @@ -1170,7 +1191,7 @@ static void stm32_i2c_traceevent(FAR struct stm32_i2c_priv_s *priv, /* Bump up the trace index (unless we are out of trace entries) */ - if (priv->tndx >= (CONFIG_I2C_NTRACE-1)) + if (priv->tndx >= (CONFIG_I2C_NTRACE - 1)) { i2cerr("ERROR: Trace table overflow\n"); return; @@ -1194,7 +1215,7 @@ static void stm32_i2c_tracedump(FAR struct stm32_i2c_priv_s *priv) trace = &priv->trace[i]; syslog(LOG_DEBUG, "%2d. STATUS: %08x COUNT: %3d EVENT: %2d PARM: %08x TIME: %d\n", - i+1, trace->status, trace->count, trace->event, trace->parm, + i + 1, trace->status, trace->count, trace->event, trace->parm, trace->time - priv->start_time); } } @@ -1278,39 +1299,38 @@ static void stm32_i2c_setclock(FAR struct stm32_i2c_priv_s *priv, uint32_t frequ * Mode is FastMode */ - if (frequency == 100000) - { - presc = 0; - scl_delay = 5; - sda_delay = 0; - scl_h_period = 61; - scl_l_period = 89; - - } - else if (frequency == 400000) - { - presc = 0; - scl_delay = 3; - sda_delay = 0; - scl_h_period = 6; - scl_l_period = 24; - } - else if (frequency == 1000000) - { - presc = 0; - scl_delay = 2; - sda_delay = 0; - scl_h_period = 1; - scl_l_period = 5; - } - else - { - presc = 7; - scl_delay = 0; - sda_delay = 0; - scl_h_period = 35; - scl_l_period = 162; - } + if (frequency == 100000) + { + presc = 0; + scl_delay = 5; + sda_delay = 0; + scl_h_period = 61; + scl_l_period = 89; + } + else if (frequency == 400000) + { + presc = 0; + scl_delay = 3; + sda_delay = 0; + scl_h_period = 6; + scl_l_period = 24; + } + else if (frequency == 1000000) + { + presc = 0; + scl_delay = 2; + sda_delay = 0; + scl_h_period = 1; + scl_l_period = 5; + } + else + { + presc = 7; + scl_delay = 0; + sda_delay = 0; + scl_h_period = 35; + scl_l_period = 162; + } uint32_t timingr = (presc << I2C_TIMINGR_PRESC_SHIFT) | @@ -1586,10 +1606,8 @@ static int stm32_i2c_isr_process(struct stm32_i2c_priv_s *priv) if (status & I2C_INT_NACK) { - if (priv->astart == true) { - /* NACK received on first (address) byte: address is invalid */ i2cinfo("NACK: Address invalid: dcnt=%i msgc=%i status=0x%08x\n", @@ -1651,7 +1669,6 @@ static int stm32_i2c_isr_process(struct stm32_i2c_priv_s *priv) else if ((priv->flags & (I2C_M_READ)) == 0 && (status & (I2C_ISR_TXIS)) != 0) { - /* TXIS interrupt occurred, address valid, ready to transmit */ stm32_i2c_traceevent(priv, I2CEVENT_WRITE, 0); @@ -1877,7 +1894,6 @@ static int stm32_i2c_isr_process(struct stm32_i2c_priv_s *priv) priv->msgv++; stm32_i2c_sendstart(priv); - } else { @@ -2253,8 +2269,8 @@ static int stm32_i2c_deinit(FAR struct stm32_i2c_priv_s *priv) * ************************************************************************************/ -static int stm32_i2c_process(FAR struct i2c_master_s *dev, FAR struct i2c_msg_s *msgs, - int count) +static int stm32_i2c_process(FAR struct i2c_master_s *dev, + FAR struct i2c_msg_s *msgs, int count) { struct stm32_i2c_inst_s *inst = (struct stm32_i2c_inst_s *)dev; FAR struct stm32_i2c_priv_s *priv = inst->priv; @@ -2450,7 +2466,7 @@ static int stm32_i2c_process(FAR struct i2c_master_s *dev, FAR struct i2c_msg_s */ uint32_t start = clock_systimer(); - uint32_t timeout = USEC2TICK(USEC_PER_SEC/priv->frequency) + 1; + uint32_t timeout = USEC2TICK(USEC_PER_SEC / priv->frequency) + 1; status = stm32_i2c_getstatus(priv); @@ -2486,8 +2502,17 @@ static int stm32_i2c_process(FAR struct i2c_master_s *dev, FAR struct i2c_msg_s static int stm32_i2c_transfer(FAR struct i2c_master_s *dev, FAR struct i2c_msg_s *msgs, int count) { - stm32_i2c_sem_wait(dev); /* ensure that address or flags don't change meanwhile */ - return stm32_i2c_process(dev, msgs, count); + int ret; + + /* Ensure that address or flags don't change meanwhile */ + + ret = stm32_i2c_sem_wait(dev); + if (ret >= 0) + { + ret = stm32_i2c_process(dev, msgs, count); + } + + return ret; } /************************************************************************************ @@ -2507,7 +2532,7 @@ static int stm32_i2c_reset(FAR struct i2c_master_s * dev) uint32_t scl_gpio; uint32_t sda_gpio; uint32_t frequency; - int ret = ERROR; + int ret; DEBUGASSERT(dev); @@ -2521,7 +2546,13 @@ static int stm32_i2c_reset(FAR struct i2c_master_s * dev) /* Lock out other clients */ - stm32_i2c_sem_wait(dev); + ret = stm32_i2c_sem_wait_uninterruptible(dev); + if (ret < 0) + { + return ret; + } + + ret = -EIO; /* Save the current frequency */ @@ -2668,6 +2699,7 @@ static int stm32_i2c_pm_prepare(FAR struct pm_callback_s *cb, int domain, case PM_STANDBY: case PM_SLEEP: + /* Check if exclusive lock for I2C bus is held. */ if (nxsem_getvalue(&priv->sem_excl, &sval) < 0) @@ -2713,7 +2745,7 @@ FAR struct i2c_master_s *stm32_i2cbus_initialize(int port) #if STM32_HSI_FREQUENCY != 16000000 || defined(INVALID_CLOCK_SOURCE) # warning STM32_I2C_INIT: Peripheral clock is HSI and it must be 16mHz or the speed/timing calculations need to be redone. - return NULL; + return NULL; #endif /* Get I2C private structure */ @@ -2831,4 +2863,4 @@ int stm32_i2cbus_uninitialize(FAR struct i2c_master_s * dev) } #endif /* CONFIG_STM32H7_I2C1 || CONFIG_STM32H7_I2C2 || \ - CONFIG_STM32H7_I2C3 || CONFIG_STM32H7_I2C4 */ + * CONFIG_STM32H7_I2C3 || CONFIG_STM32H7_I2C4 */ diff --git a/arch/arm/src/stm32l4/stm32l4_i2c.c b/arch/arm/src/stm32l4/stm32l4_i2c.c index 1c970f95a76..22afcd696dd 100644 --- a/arch/arm/src/stm32l4/stm32l4_i2c.c +++ b/arch/arm/src/stm32l4/stm32l4_i2c.c @@ -201,10 +201,12 @@ * CONFIG_STM32L4_I2CTIMEOMS (Timeout in milliseconds) * CONFIG_STM32L4_I2CTIMEOTICKS (Timeout in ticks) * - * To configure the ISR timeout using dynamic values (CONFIG_STM32L4_I2C_DYNTIMEO=y): + * To configure the ISR timeout using dynamic values + * (CONFIG_STM32L4_I2C_DYNTIMEO=y): * * CONFIG_STM32L4_I2C_DYNTIMEO_USECPERBYTE (Timeout in microseconds per byte) - * CONFIG_STM32L4_I2C_DYNTIMEO_STARTSTOP (Timeout for start/stop in milliseconds) + * CONFIG_STM32L4_I2C_DYNTIMEO_STARTSTOP (Timeout for start/stop in + * milliseconds) * * Debugging output enabled with: * @@ -418,7 +420,10 @@ struct stm32l4_i2c_config_s struct stm32l4_i2c_priv_s { - const struct stm32l4_i2c_config_s *config; /* Port configuration */ + /* Port configuration */ + + const struct stm32l4_i2c_config_s *config; + int refs; /* Reference count */ sem_t sem_excl; /* Mutual exclusion semaphore */ #ifndef CONFIG_I2C_POLLED @@ -473,7 +478,8 @@ static inline void stm32l4_i2c_putreg32(FAR struct stm32l4_i2c_priv_s *priv, static inline void stm32l4_i2c_modifyreg32(FAR struct stm32l4_i2c_priv_s *priv, uint8_t offset, uint32_t clearbits, uint32_t setbits); -static inline void stm32l4_i2c_sem_wait(FAR struct i2c_master_s *dev); +static inline int stm32l4_i2c_sem_wait(FAR struct i2c_master_s *dev); +static int stm32l4_i2c_sem_wait_uninterruptible(FAR struct i2c_master_s *dev); #ifdef CONFIG_STM32L4_I2C_DYNTIMEO static useconds_t stm32l4_i2c_tousecs(int msgc, FAR struct i2c_msg_s *msgs); #endif /* CONFIG_STM32L4_I2C_DYNTIMEO */ @@ -696,8 +702,8 @@ static inline uint32_t stm32l4_i2c_getreg32(FAR struct stm32l4_i2c_priv_s *priv, * ************************************************************************************/ -static inline void stm32l4_i2c_putreg(FAR struct stm32l4_i2c_priv_s *priv, uint8_t offset, - uint16_t value) +static inline void stm32l4_i2c_putreg(FAR struct stm32l4_i2c_priv_s *priv, + uint8_t offset, uint16_t value) { putreg16(value, priv->config->base + offset); } @@ -716,7 +722,6 @@ static inline void stm32l4_i2c_putreg32(FAR struct stm32l4_i2c_priv_s *priv, putreg32(value, priv->config->base + offset); } - /************************************************************************************ * Name: stm32l4_i2c_modifyreg32 * @@ -736,13 +741,28 @@ static inline void stm32l4_i2c_modifyreg32(FAR struct stm32l4_i2c_priv_s *priv, * Name: stm32l4_i2c_sem_wait * * Description: + * Take the exclusive access, waiting as necessary. May be interrupted by a + * signal. + * + ************************************************************************************/ + +static inline int stm32l4_i2c_sem_wait(FAR struct i2c_master_s *dev) +{ + return nxsem_wait(&((struct stm32l4_i2c_inst_s *)dev)->priv->sem_excl); +} + +/************************************************************************************ + * Name: stm32l4_i2c_sem_wait_uninterruptible + * + * Description: * Take the exclusive access, waiting as necessary * ************************************************************************************/ -static inline void stm32l4_i2c_sem_wait(FAR struct i2c_master_s *dev) +static int stm32l4_i2c_sem_wait_uninterruptible(FAR struct i2c_master_s *dev) { - nxsem_wait_uninterruptible(&((struct stm32l4_i2c_inst_s *)dev)->priv->sem_excl); + return + nxsem_wait_uninterruptible(&((struct stm32l4_i2c_inst_s *)dev)->priv->sem_excl); } /************************************************************************************ @@ -852,6 +872,7 @@ static inline int stm32l4_i2c_sem_waitdone(FAR struct stm32l4_i2c_priv_s *priv) abstime.tv_nsec -= 1000 * 1000 * 1000; } #endif + /* Wait until either the transfer is complete or the timeout expires */ ret = nxsem_timedwait_uninterruptible(&priv->sem_isr, &abstime); @@ -943,7 +964,7 @@ static inline void stm32l4_i2c_set_7bit_address(FAR struct stm32l4_i2c_priv_s *priv) { stm32l4_i2c_modifyreg32(priv, STM32L4_I2C_CR2_OFFSET, I2C_CR2_SADD7_MASK, - ((priv->msgv->addr & 0x7F) << I2C_CR2_SADD7_SHIFT)); + ((priv->msgv->addr & 0x7f) << I2C_CR2_SADD7_SHIFT)); } /************************************************************************************ @@ -1013,7 +1034,6 @@ stm32l4_i2c_disable_reload(FAR struct stm32l4_i2c_priv_s *priv) stm32l4_i2c_modifyreg32(priv, STM32L4_I2C_CR2_OFFSET, I2C_CR2_RELOAD, 0); } - /************************************************************************************ * Name: stm32l4_i2c_sem_waitstop * @@ -1062,7 +1082,6 @@ static inline void stm32l4_i2c_sem_waitstop(FAR struct stm32l4_i2c_priv_s *priv) { return; } - } /* Loop until the stop is complete or a timeout occurs. */ @@ -1107,7 +1126,8 @@ static inline void stm32l4_i2c_sem_init(FAR struct i2c_master_s *dev) */ nxsem_init(&((struct stm32l4_i2c_inst_s *)dev)->priv->sem_isr, 0, 0); - nxsem_setprotocol(&((struct stm32l4_i2c_inst_s *)dev)->priv->sem_isr, SEM_PRIO_NONE); + nxsem_setprotocol(&((struct stm32l4_i2c_inst_s *)dev)->priv->sem_isr, + SEM_PRIO_NONE); #endif } @@ -1171,7 +1191,7 @@ static void stm32l4_i2c_tracenew(FAR struct stm32l4_i2c_priv_s *priv, { /* Yes.. bump up the trace index (unless we are out of trace entries) */ - if (priv->tndx >= (CONFIG_I2C_NTRACE-1)) + if (priv->tndx >= (CONFIG_I2C_NTRACE - 1)) { i2cerr("ERROR: Trace table overflow\n"); return; @@ -1212,7 +1232,7 @@ static void stm32l4_i2c_traceevent(FAR struct stm32l4_i2c_priv_s *priv, /* Bump up the trace index (unless we are out of trace entries) */ - if (priv->tndx >= (CONFIG_I2C_NTRACE-1)) + if (priv->tndx >= (CONFIG_I2C_NTRACE - 1)) { i2cerr("ERROR: Trace table overflow\n"); return; @@ -1236,7 +1256,7 @@ static void stm32l4_i2c_tracedump(FAR struct stm32l4_i2c_priv_s *priv) trace = &priv->trace[i]; syslog(LOG_DEBUG, "%2d. STATUS: %08x COUNT: %3d EVENT: %2d PARM: %08x TIME: %d\n", - i+1, trace->status, trace->count, trace->event, trace->parm, + i + 1, trace->status, trace->count, trace->event, trace->parm, (int)(trace->time - priv->start_time)); } } @@ -1347,7 +1367,7 @@ static void stm32l4_i2c_setclock(FAR struct stm32l4_i2c_priv_s *priv, scl_delay = 0x0d; /* SCLDEL - (+1) data setup time from SDA edge to SCL rising edge */ } else if (frequency == 400000) - { + { /* 400 KHz values from I2C timing tool for clock of 80 MHz */ presc = 0x01; /* PRESC - (+1) prescale I2CCLK */ @@ -1355,9 +1375,9 @@ static void stm32l4_i2c_setclock(FAR struct stm32l4_i2c_priv_s *priv, scl_h_period = 0x13; /* SCLH - SCL high period in master mode */ sda_delay = 0x00; /* SDADEL - (+1) data hold time after SCL falling edge */ scl_delay = 0x07; /* SCLDEL - (+1) data setup time from SDA edge to SCL rising edge */ - } + } else if (frequency == 1000000) - { + { /* 1000 KHz values from I2C timing tool for clock of 80 MHz */ presc = 0x01; /* PRESC - (+1) prescale I2CCLK */ @@ -1365,7 +1385,7 @@ static void stm32l4_i2c_setclock(FAR struct stm32l4_i2c_priv_s *priv, scl_h_period = 0x13; /* SCLH - SCL high period in master mode */ sda_delay = 0x00; /* SDADEL - (+1) data hold time after SCL falling edge */ scl_delay = 0x05; /* SCLDEL - (+1) data setup time from SDA edge to SCL rising edge */ - } + } else { /* 10 KHz values from I2C timing tool with clock 80 MHz */ @@ -1398,17 +1418,17 @@ static void stm32l4_i2c_setclock(FAR struct stm32l4_i2c_priv_s *priv, scl_l_period = 230; } else if (frequency == 400000) - { + { /* 400 KHz values from I2C timing tool for clock of 120 MHz */ - presc = 2; - scl_delay = 8; - sda_delay = 0; - scl_h_period = 21; - scl_l_period = 66; - } + presc = 2; + scl_delay = 8; + sda_delay = 0; + scl_h_period = 21; + scl_l_period = 66; + } else if (frequency == 1000000) - { + { /* 1000 KHz values from I2C timing tool for clock of 120 MHz */ presc = 2; @@ -1416,7 +1436,7 @@ static void stm32l4_i2c_setclock(FAR struct stm32l4_i2c_priv_s *priv, sda_delay = 0; scl_h_period = 7; scl_l_period = 20; - } + } else { /* 10 KHz values not supported */ @@ -1746,10 +1766,8 @@ static int stm32l4_i2c_isr_process(struct stm32l4_i2c_priv_s *priv) if (status & I2C_INT_NACK) { - if (priv->astart == true) { - /* NACK received on first (address) byte: address is invalid */ i2cinfo("NACK: Address invalid: dcnt=%i msgc=%i status=0x%08x\n", @@ -1811,7 +1829,6 @@ static int stm32l4_i2c_isr_process(struct stm32l4_i2c_priv_s *priv) else if ((priv->flags & (I2C_M_READ)) == 0 && (status & (I2C_ISR_TXIS)) != 0) { - /* TXIS interrupt occurred, address valid, ready to transmit */ stm32l4_i2c_traceevent(priv, I2CEVENT_WRITE, 0); @@ -2037,7 +2054,6 @@ static int stm32l4_i2c_isr_process(struct stm32l4_i2c_priv_s *priv) priv->msgv++; stm32l4_i2c_sendstart(priv); - } else { @@ -2123,7 +2139,8 @@ static int stm32l4_i2c_isr_process(struct stm32l4_i2c_priv_s *priv) priv->flags = priv->msgv->flags; /* if this is the last message, disable reload so the - * TC event fires next time */ + * TC event fires next time. + */ if (priv->msgc == 0) { @@ -2249,7 +2266,8 @@ static int stm32l4_i2c_isr_process(struct stm32l4_i2c_priv_s *priv) stm32l4_i2c_traceevent(priv, I2CEVENT_ISR_SHUTDOWN, 0); /* clear pointer to message content to reflect we are done - * with the current transaction */ + * with the current transaction. + */ priv->msgv = NULL; @@ -2524,12 +2542,12 @@ static int stm32l4_i2c_process(FAR struct i2c_master_s *dev, errval = ETIMEDOUT; i2cerr("ERROR: Waitdone timed out CR1: 0x%08x CR2: 0x%08x status: 0x%08x\n", - cr1, cr2,status); + cr1, cr2, status); } else { i2cinfo("Waitdone success: CR1: 0x%08x CR2: 0x%08x status: 0x%08x\n", - cr1, cr2,status ); + cr1, cr2, status); } UNUSED(cr1); @@ -2628,7 +2646,7 @@ static int stm32l4_i2c_process(FAR struct i2c_master_s *dev, */ clock_t start = clock_systimer(); - clock_t timeout = USEC2TICK(USEC_PER_SEC/priv->frequency) + 1; + clock_t timeout = USEC2TICK(USEC_PER_SEC / priv->frequency) + 1; status = stm32l4_i2c_getstatus(priv); @@ -2661,11 +2679,21 @@ static int stm32l4_i2c_process(FAR struct i2c_master_s *dev, * ************************************************************************************/ -static int stm32l4_i2c_transfer(FAR struct i2c_master_s *dev, FAR struct i2c_msg_s *msgs, - int count) +static int stm32l4_i2c_transfer(FAR struct i2c_master_s *dev, + FAR struct i2c_msg_s *msgs, + int count) { - stm32l4_i2c_sem_wait(dev); /* ensure that address or flags don't change meanwhile */ - return stm32l4_i2c_process(dev, msgs, count); + int ret; + + /* Ensure that address or flags don't change meanwhile */ + + ret = stm32l4_i2c_sem_wait(dev); + if (ret >= 0) + { + ret = stm32l4_i2c_process(dev, msgs, count); + } + + return ret; } /************************************************************************************ @@ -2685,7 +2713,7 @@ static int stm32l4_i2c_reset(FAR struct i2c_master_s * dev) uint32_t scl_gpio; uint32_t sda_gpio; uint32_t frequency; - int ret = ERROR; + int ret; DEBUGASSERT(dev); @@ -2699,7 +2727,13 @@ static int stm32l4_i2c_reset(FAR struct i2c_master_s * dev) /* Lock out other clients */ - stm32l4_i2c_sem_wait(dev); + ret = stm32l4_i2c_sem_wait_uninterruptible(dev); + if (ret < 0) + { + return ret; + } + + ret = -EIO; /* Save the current frequency */ @@ -2843,6 +2877,7 @@ static int stm32l4_i2c_pm_prepare(FAR struct pm_callback_s *cb, int domain, case PM_STANDBY: case PM_SLEEP: + /* Check if exclusive lock for I2C bus is held. */ if (nxsem_getvalue(&priv->sem_excl, &sval) < 0) @@ -2861,6 +2896,7 @@ static int stm32l4_i2c_pm_prepare(FAR struct pm_callback_s *cb, int domain, break; default: + /* Should not get here */ break; diff --git a/arch/arm/src/tiva/common/tiva_i2c.c b/arch/arm/src/tiva/common/tiva_i2c.c index 047e91f65b3..bda90d5c4c1 100644 --- a/arch/arm/src/tiva/common/tiva_i2c.c +++ b/arch/arm/src/tiva/common/tiva_i2c.c @@ -82,7 +82,9 @@ /************************************************************************************ * Pre-processor Definitions ************************************************************************************/ + /* Configuration ********************************************************************/ + /* CONFIG_I2C_POLLED may be set so that I2C interrupts will not be used. Instead, * CPU-intensive polling will be used. */ @@ -110,6 +112,7 @@ #endif /* GPIO pins ************************************************************************/ + /* Macros to convert a I2C pin to a GPIO output */ #define I2C_INPUT (GPIO_FUNC_INPUT) @@ -143,6 +146,7 @@ /************************************************************************************ * Private Types ************************************************************************************/ + /* Interrupt state */ enum tiva_intstate_e @@ -203,8 +207,13 @@ struct tiva_i2c_config_s struct tiva_i2c_priv_s { - const struct i2c_ops_s *ops; /* Standard I2C operations */ - const struct tiva_i2c_config_s *config; /* Port configuration */ + /* Standard I2C operations */ + + const struct i2c_ops_s *ops; + + /* Port configuration */ + + const struct tiva_i2c_config_s *config; sem_t exclsem; /* Mutual exclusion semaphore */ #ifndef CONFIG_I2C_POLLED sem_t waitsem; /* Interrupt wait semaphore */ @@ -223,10 +232,10 @@ struct tiva_i2c_priv_s #ifdef CONFIG_TIVA_I2C_REGDEBUG /* Register level debug */ - bool wrlast; /* Last was a write */ - uintptr_t addrlast; /* Last address */ - uint32_t vallast; /* Last value */ - int ntimes; /* Number of times */ + bool wrlast; /* Last was a write */ + uintptr_t addrlast; /* Last address */ + uint32_t vallast; /* Last value */ + int ntimes; /* Number of times */ #endif #ifdef CONFIG_I2C_TRACE @@ -259,7 +268,6 @@ static inline uint32_t tiva_i2c_getreg(struct tiva_i2c_priv_s *priv, static inline void tiva_i2c_putreg(struct tiva_i2c_priv_s *priv, unsigned int offset, uint32_t value); #endif -static inline void tiva_i2c_sem_wait(struct tiva_i2c_priv_s *priv); #ifdef CONFIG_TIVA_I2C_DYNTIMEO static useconds_t tiva_i2c_tousecs(int msgc, struct i2c_msg_s *msgv); @@ -635,19 +643,6 @@ static inline void tiva_i2c_putreg(struct tiva_i2c_priv_s *priv, } #endif -/************************************************************************************ - * Name: tiva_i2c_sem_wait - * - * Description: - * Take the exclusive access, waiting as necessary - * - ************************************************************************************/ - -static inline void tiva_i2c_sem_wait(struct tiva_i2c_priv_s *priv) -{ - nxsem_wait_uninterruptible(&priv->exclsem); -} - /************************************************************************************ * Name: tiva_i2c_tousecs * @@ -919,7 +914,7 @@ static void tiva_i2c_tracenew(struct tiva_i2c_priv_s *priv, uint32_t status) { /* Yes.. bump up the trace index (unless we are out of trace entries) */ - if (priv->tndx >= (CONFIG_I2C_NTRACE-1)) + if (priv->tndx >= (CONFIG_I2C_NTRACE - 1)) { i2cerr("ERROR: I2C%d trace table overflow\n", priv->config->devno); return; @@ -968,7 +963,7 @@ static void tiva_i2c_traceevent(struct tiva_i2c_priv_s *priv, /* Bump up the trace index (unless we are out of trace entries) */ - if (priv->tndx >= (CONFIG_I2C_NTRACE-1)) + if (priv->tndx >= (CONFIG_I2C_NTRACE - 1)) { i2cerr("ERROR: I2C%d trace table overflow\n", priv->config->devno); return; @@ -1003,7 +998,7 @@ static void tiva_i2c_tracedump(struct tiva_i2c_priv_s *priv) trace = &priv->trace[i]; syslog(LOG_DEBUG, "%2d. STATUS: %08x COUNT: %3d EVENT: %2d PARM: %08x TIME: %d\n", - i+1, trace->status, trace->count, trace->event, trace->parm, + i + 1, trace->status, trace->count, trace->event, trace->parm, trace->time - priv->ttime); } } @@ -1602,12 +1597,16 @@ static int tiva_i2c_transfer(struct i2c_master_s *dev, struct i2c_msg_s *msgv, { struct tiva_i2c_priv_s *priv = (struct tiva_i2c_priv_s *)dev; uint32_t regval; - int ret = OK; + int ret; DEBUGASSERT(priv && priv->config && msgv && msgc > 0); i2cinfo("I2C%d: msgc=%d\n", priv->config->devno, msgc); - tiva_i2c_sem_wait(priv); /* Ensure that address or flags don't change meanwhile */ + ret = nxsem_wait(&priv->exclsem); + if (ret < 0) + { + return ret; + } /* Reset mptr and mcnt to ensure an unexpected data interrupt doesn't * overwrite stale data. @@ -1764,7 +1763,11 @@ static int tiva_i2c_reset(FAR struct i2c_master_s * dev) /* Lock out other clients */ - tiva_i2c_sem_wait(priv); + ret = nxsem_wait_uninterruptible(&priv->exclsem); + if (ret < 0) + { + return ret; + } /* Un-initialize the port */ diff --git a/arch/mips/src/pic32mz/pic32mz-i2c.c b/arch/mips/src/pic32mz/pic32mz-i2c.c index c02df77a660..2662b850f58 100644 --- a/arch/mips/src/pic32mz/pic32mz-i2c.c +++ b/arch/mips/src/pic32mz/pic32mz-i2c.c @@ -99,7 +99,7 @@ TICK2USEC(CONFIG_PIC32MZ_I2CTIMEOTICKS) #endif -/* Debug *********************************************************************/ +/* Debug ********************************************************************/ /* I2C event trace logic. */ @@ -192,22 +192,29 @@ struct pic32mz_i2c_config_s struct pic32mz_i2c_priv_s { - const struct i2c_ops_s *ops; /* Standard I2C operations */ - const struct pic32mz_i2c_config_s *config; /* Port configuration */ - int refs; /* Referernce count */ - sem_t sem_excl; /* Mutual exclusion semaphore */ + /* Standard I2C operations */ + + const struct i2c_ops_s *ops; + + /* Port configuration */ + + const struct pic32mz_i2c_config_s *config; + + int refs; /* Reference count */ + sem_t sem_excl; /* Mutual exclusion semaphore */ #ifndef CONFIG_I2C_POLLED - sem_t sem_isr; /* Interrupt wait semaphore */ + sem_t sem_isr; /* Interrupt wait semaphore */ #endif - volatile uint8_t intstate; /* Interrupt handshake (see enum pic32mz_intstate_e) */ + volatile uint8_t intstate; /* Interrupt handshake (see enum + * pic32mz_intstate_e) */ volatile uint8_t process_state; /* State of the isr process */ - 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 */ + 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 */ /* I2C trace support */ @@ -227,14 +234,14 @@ struct pic32mz_i2c_priv_s * Private Function Prototypes ****************************************************************************/ -static inline uint32_t pic32mz_i2c_getreg(FAR struct pic32mz_i2c_priv_s *priv, - uint8_t offset); +static inline uint32_t + pic32mz_i2c_getreg(FAR struct pic32mz_i2c_priv_s *priv, + uint8_t offset); static inline void pic32mz_i2c_putreg(FAR struct pic32mz_i2c_priv_s *priv, uint8_t offset, uint32_t value); static inline void pic32mz_i2c_modifyreg(FAR struct pic32mz_i2c_priv_s *priv, uint8_t offset, uint32_t clearbits, uint32_t setbits); -static inline void pic32mz_i2c_sem_wait(FAR struct pic32mz_i2c_priv_s *priv); #ifdef CONFIG_PICM32MZ_I2C_DYNTIMEO static useconds_t pic32mz_i2c_tousecs(int msgc, FAR struct i2c_msg_s *msgs); @@ -253,16 +260,19 @@ static inline void static void pic32mz_i2c_tracereset(FAR struct pic32mz_i2c_priv_s *priv); static void pic32mz_i2c_tracenew(FAR struct pic32mz_i2c_priv_s *priv, uint32_t status); -static void pic32mz_i2c_traceevent(FAR struct pic32mz_i2c_priv_s *priv, - enum pic32mz_trace_e event, uint32_t parm); +static void + pic32mz_i2c_traceevent(FAR struct pic32mz_i2c_priv_s *priv, + enum pic32mz_trace_e event, uint32_t parm); static void pic32mz_i2c_tracedump(FAR struct pic32mz_i2c_priv_s *priv); #endif /* CONFIG_I2C_TRACE */ -static inline int pic32mz_i2c_setbaudrate(FAR struct pic32mz_i2c_priv_s *priv, - uint32_t frequency); +static inline int + pic32mz_i2c_setbaudrate(FAR struct pic32mz_i2c_priv_s *priv, + uint32_t frequency); static inline void pic32mz_i2c_send_start(FAR struct pic32mz_i2c_priv_s *priv); -static inline void pic32mz_i2c_send_stop(FAR struct pic32mz_i2c_priv_s *priv); +static inline void + pic32mz_i2c_send_stop(FAR struct pic32mz_i2c_priv_s *priv); static inline void pic32mz_i2c_send_repeatedstart(FAR struct pic32mz_i2c_priv_s *priv); static inline void pic32mz_i2c_send_ack(FAR struct pic32mz_i2c_priv_s *priv, @@ -586,8 +596,8 @@ static void pic32mz_i2c_tracedump(FAR struct pic32mz_i2c_priv_s *priv) * ****************************************************************************/ -static inline uint32_t pic32mz_i2c_getreg(FAR struct pic32mz_i2c_priv_s *priv, - uint8_t offset) +static inline uint32_t + pic32mz_i2c_getreg(FAR struct pic32mz_i2c_priv_s *priv, uint8_t offset) { return getreg32(priv->config->base + offset); } @@ -621,19 +631,6 @@ static inline void pic32mz_i2c_modifyreg(FAR struct pic32mz_i2c_priv_s *priv, modifyreg32(priv->config->base + offset, clearbits, setbits); } -/**************************************************************************** - * Name: pic32mz_i2c_sem_wait - * - * Description: - * Take the exclusive access, waiting as necessary - * - ****************************************************************************/ - -static inline void pic32mz_i2c_sem_wait(FAR struct pic32mz_i2c_priv_s *priv) -{ - nxsem_wait_uninterruptible(&priv->sem_excl); -} - /**************************************************************************** * Name: pic32mz_i2c_tousecs * @@ -1315,8 +1312,9 @@ static int pic32mz_i2c_isr(int irq, void *context, FAR void *arg) * ****************************************************************************/ -static inline int pic32mz_i2c_setbaudrate(FAR struct pic32mz_i2c_priv_s *priv, - uint32_t frequency) +static inline int + pic32mz_i2c_setbaudrate(FAR struct pic32mz_i2c_priv_s *priv, + uint32_t frequency) { uint32_t baudrate; @@ -1602,12 +1600,16 @@ static int pic32mz_i2c_transfer(FAR struct i2c_master_s *dev, FAR struct i2c_msg_s *msgs, int count) { FAR struct pic32mz_i2c_priv_s *priv = (struct pic32mz_i2c_priv_s *)dev; - int ret = OK; uint32_t status = 0; + int ret; /* Acquire the semaphore. */ - pic32mz_i2c_sem_wait(priv); + ret = nxsem_wait(&priv->sem_excl); + if (ret < 0) + { + return ret; + } /* Wait for the bus to be in an idle state. */ @@ -1732,7 +1734,11 @@ static int pic32mz_i2c_reset(FAR struct i2c_master_s *dev) /* Lock out other clients */ - pic32mz_i2c_sem_wait(priv); + ret = nxsem_wait_uninterruptible(&priv->sem_excl); + if (ret < 0) + { + return ret; + } /* Save the current frequency */ diff --git a/arch/z80/src/ez80/ez80_i2c.c b/arch/z80/src/ez80/ez80_i2c.c index 088bc49d38b..53007500c2a 100644 --- a/arch/z80/src/ez80/ez80_i2c.c +++ b/arch/z80/src/ez80/ez80_i2c.c @@ -115,13 +115,11 @@ const struct i2c_ops_s g_ops = * ****************************************************************************/ -static void ez80_i2c_semtake(void) +static int ez80_i2c_semtake(void) { - nxsem_wait_uninterruptible(&g_i2csem); + return nxsem_wait(&g_i2csem); } -#define ez80_i2c_semgive() nxsem_post(&g_i2csem) - /**************************************************************************** * Name: ez80_i2c_setccr * @@ -808,7 +806,7 @@ static int ez80_i2c_transfer(FAR struct i2c_master_s *dev, FAR struct i2c_msg_s *msg; bool nostop; uint8_t flags; - int ret = OK; + int ret; int i; /* Perform each segment of the transfer, message at a time */ @@ -817,9 +815,13 @@ static int ez80_i2c_transfer(FAR struct i2c_master_s *dev, /* Get exclusive access to the I2C bus */ - ez80_i2c_semtake(); + ret = nxsem_wait(&g_i2csem); + if (ret < 0) + { + return ret; + } - /* The process each message seqment */ + /* The process each message segment */ for (i = 0; i < count; i++) { @@ -885,7 +887,7 @@ static int ez80_i2c_transfer(FAR struct i2c_master_s *dev, flags = (nostop) ? EZ80_NOSTART : 0; } - ez80_i2c_semgive(); + nxsem_post(&g_i2csem); return ret; } diff --git a/arch/z80/src/z8/z8_i2c.c b/arch/z80/src/z8/z8_i2c.c index 2809c108c5e..5f57d37ef9b 100644 --- a/arch/z80/src/z8/z8_i2c.c +++ b/arch/z80/src/z8/z8_i2c.c @@ -1,35 +1,20 @@ /**************************************************************************** * arch/z80/src/z8/z8_i2c.c * - * Copyright(C) 2009, 2011, 2013, 2016-2017 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: + * http://www.apache.org/licenses/LICENSE-2.0 * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES(INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. * ****************************************************************************/ @@ -124,26 +109,6 @@ const struct i2c_ops_s g_ops = /**************************************************************************** * Private Functions ****************************************************************************/ -/**************************************************************************** - * Name: z8_i2c_semtake/z8_i2c_semgive - * - * Description: - * Take/Give the I2C semaphore. - * - * Input Parameters: - * None - * - * Returned Value: - * None - * - ****************************************************************************/ - -static void z8_i2c_semtake(void) -{ - nxsem_wait_uninterruptible(&g_i2csem); -} - -#define z8_i2c_semgive() nxsem_post(&g_i2csem) /**************************************************************************** * Name: z8_i2c_waittxempty @@ -182,7 +147,12 @@ static void z8_i2c_waittxempty(void) static void z8_i2c_waitrxavail(void) { int i; - for (i = 0; i <= 10000 && (I2CSTAT & (I2C_STAT_RDRF | I2C_STAT_NCKI)) == 0; i++); + + for (i = 0; + i <= 10000 && (I2CSTAT & (I2C_STAT_RDRF | I2C_STAT_NCKI)) == 0; + i++) + { + } } /**************************************************************************** @@ -225,10 +195,10 @@ static uint16_t z8_i2c_getbrg(uint32_t frequency) /* Max is 400 Kb/sec */ - if (frequency > 400*1000) + if (frequency > 400 * 1000) { _err("ERROR: Invalid inputs\n"); - frequency = 400*1000; + frequency = 400 * 1000; } /* BRG = sysclock / (4 * frequency) */ @@ -247,7 +217,8 @@ static uint16_t z8_i2c_getbrg(uint32_t frequency) * * Input Parameters: * dev - Device-specific state data - * buffer - A pointer to a buffer of data to receive the data from the device + * buffer - A pointer to a buffer of data to receive the data from the + * device * buflen - The requested number of bytes to be read * flags - Determines is a START and/or STOP indication is needed. * @@ -357,7 +328,8 @@ static int z8_i2c_read_transfer(FAR struct z8_i2cdev_s *priv, * * Input Parameters: * dev - Device-specific state data - * buffer - A pointer to the read-only buffer of data to be written to device + * buffer - A pointer to the read-only buffer of data to be written to + * device * buflen - The number of bytes to send from the buffer * flags - Determines is a START and/or STOP indication is needed. * @@ -474,16 +446,18 @@ static void z8_i2c_setfrequency(FAR struct z8_i2cdev_s *priv, /* Has the frequency changed? */ if (priv->frequency != frequency) - { - /* Calculate and save the BRG (we won't apply it until the first transfer) */ + { + /* Calculate and save the BRG (we won't apply it until the first + * transfer) + */ - brg = z8_i2c_getbrg(frequency); - z8_i2c_setbrg(brg); + brg = z8_i2c_getbrg(frequency); + z8_i2c_setbrg(brg); - /* Save the new I2C frequency */ + /* Save the new I2C frequency */ - priv->frequency = frequency; - } + priv->frequency = frequency; + } } /**************************************************************************** @@ -512,7 +486,7 @@ static int z8_i2c_transfer(FAR struct i2c_master_s *dev, FAR struct i2c_msg_s *msg; bool nostop; uint8_t flags; - int ret = OK; + int ret; int i; /* Perform each segment of the transfer, message at a time */ @@ -521,9 +495,13 @@ static int z8_i2c_transfer(FAR struct i2c_master_s *dev, /* Get exclusive access to the I2C bus */ - z8_i2c_semtake(); + ret = nxsem_wait(&g_i2csem); + if (ret < 0) + { + return ret; + } - /* The process each message seqment */ + /* The process each message segment */ for (i = 0; i < count; i++) { @@ -540,7 +518,7 @@ static int z8_i2c_transfer(FAR struct i2c_master_s *dev, nostop = false; if (i < (count - 1)) - { + { FAR struct i2c_msg_s *next; /* No... Check if the next message should have a repeated start or @@ -553,7 +531,8 @@ static int z8_i2c_transfer(FAR struct i2c_master_s *dev, next = &msgs[i + 1]; if ((msg->flags & I2C_M_NOSTART) != 0 && - (msg->flags & (I2C_M_READ | I2C_M_TEN)) == (next->flags & (I2C_M_READ | I2C_M_TEN)) && + (msg->flags & (I2C_M_READ | I2C_M_TEN)) == + (next->flags & (I2C_M_READ | I2C_M_TEN)) && msg->addr == next->addr) { nostop = true; @@ -586,11 +565,11 @@ static int z8_i2c_transfer(FAR struct i2c_master_s *dev, flags = (nostop) ? Z8_NOSTART : 0; } - z8_i2c_semgive(); + nxsem_post(&g_i2csem); return ret; } -/************************************************************************************ +/**************************************************************************** * Name: z8_i2c_reset * * Description: @@ -602,7 +581,7 @@ static int z8_i2c_transfer(FAR struct i2c_master_s *dev, * 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) @@ -640,7 +619,7 @@ FAR struct i2c_master_s *z8_i2cbus_initialize(int port) { /* Set up some initial BRG value */ - uint16_t brg = z8_i2c_getbrg(100*1000); + uint16_t brg = z8_i2c_getbrg(100 * 1000); z8_i2c_setbrg(brg); /* Make sure that GPIOs are configured for the alternate function (this