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