mirror of
https://github.com/apache/nuttx.git
synced 2026-05-21 13:13:08 +08:00
Check return from nxsem_wait_initialize()
Resolution of Issue 619 will require multiple steps, this part of the first step in that resolution: Every call to nxsem_wait_uninterruptible() must handle the return value from nxsem_wait_uninterruptible properly. This commit is for all I2C drivers under arch/.
This commit is contained in:
committed by
Abdelatif Guettouche
parent
4addf6c308
commit
fc467021cf
@@ -38,7 +38,7 @@
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
************************************************************************************/
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
@@ -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 */
|
||||
|
||||
|
||||
+120
-84
@@ -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);
|
||||
|
||||
@@ -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 */
|
||||
|
||||
|
||||
@@ -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 */
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 */
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
|
||||
@@ -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 */
|
||||
|
||||
|
||||
@@ -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 */
|
||||
|
||||
|
||||
+118
-75
@@ -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.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
|
||||
@@ -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 */
|
||||
|
||||
|
||||
@@ -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 */
|
||||
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 */
|
||||
|
||||
|
||||
@@ -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 */
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
+47
-68
@@ -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 <gnutt@nuttx.org>
|
||||
* 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
|
||||
|
||||
Reference in New Issue
Block a user