arch: cxd56xx: Add logic for i2c reset

Add ARCH_HAVE_I2CRESET configration to ARCH_CHIP_CXD56XX
and implement i2c reset function.
This commit is contained in:
SPRESENSE 2024-08-27 14:51:52 +09:00 committed by Alin Jerpelea
parent de8829f8cd
commit 2cc9221c09
2 changed files with 120 additions and 1 deletions

View File

@ -635,6 +635,7 @@ config ARCH_CHIP_CXD56XX
select ARCH_HAVE_TEXT_HEAP
select ARCH_HAVE_SDIO if MMCSD
select ARCH_HAVE_MATH_H
select ARCH_HAVE_I2CRESET
---help---
Sony CXD56XX (ARM Cortex-M4) architectures

View File

@ -46,6 +46,7 @@
#include "cxd56_i2c.h"
#include "hardware/cxd56_i2c.h"
#include "cxd56_pinconfig.h"
#include "cxd56_gpio.h"
#if defined(CONFIG_CXD56_I2C0_SCUSEQ) || defined(CONFIG_CXD56_I2C1_SCUSEQ)
#include <arch/chip/scu.h>
@ -702,7 +703,124 @@ static int cxd56_i2c_transfer(struct i2c_master_s *dev,
#ifdef CONFIG_I2C_RESET
static int cxd56_i2c_reset(struct i2c_master_s *dev)
{
return OK;
struct cxd56_i2cdev_s *priv = (struct cxd56_i2cdev_s *)dev;
unsigned int clock_count;
unsigned int stretch_count;
uint32_t scl_gpio;
uint32_t sda_gpio;
int ret = -EIO;
DEBUGASSERT(dev != NULL);
/* Our caller must own a ref */
DEBUGASSERT(priv->refs > 0);
/* Lock out other clients */
nxmutex_lock(&priv->lock);
/* Use GPIO configuration to un-wedge the bus */
cxd56_i2c_pincontrol(priv->port, false);
switch (priv->port)
{
case 0:
scl_gpio = PIN_I2C0_BCK;
sda_gpio = PIN_I2C0_BDT;
break;
case 1:
scl_gpio = PIN_PWM2;
sda_gpio = PIN_PWM3;
break;
case 2:
default:
scl_gpio = PIN_SPI0_MOSI;
sda_gpio = PIN_SPI0_MISO;
break;
}
/* Enable input of SCL and SDA pins */
cxd56_gpio_config(scl_gpio, true);
cxd56_gpio_config(sda_gpio, true);
/* Let SDA go high */
cxd56_gpio_write(sda_gpio, true);
/* Clock the bus until any slaves currently driving it let it go. */
clock_count = 0;
while (!cxd56_gpio_read(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 (!cxd56_gpio_read(scl_gpio))
{
/* Give up if we have tried too hard */
if (stretch_count++ > 10)
{
goto out;
}
up_udelay(10);
}
/* Drive SCL low */
cxd56_gpio_write(scl_gpio, false);
up_udelay(10);
/* Drive SCL high again */
cxd56_gpio_write(scl_gpio, true);
up_udelay(10);
}
/* Generate a start followed by a stop to reset slave
* state machines.
*/
cxd56_gpio_write(sda_gpio, false);
up_udelay(10);
cxd56_gpio_write(scl_gpio, false);
up_udelay(10);
cxd56_gpio_write(scl_gpio, true);
up_udelay(10);
cxd56_gpio_write(sda_gpio, true);
up_udelay(10);
ret = OK;
out:
/* Disable output of SCL and SDA pins */
cxd56_gpio_write_hiz(scl_gpio);
cxd56_gpio_write_hiz(sda_gpio);
/* Revert the GPIO configuration. */
cxd56_i2c_pincontrol(priv->port, true);
/* Release the port for re-use by other clients */
nxmutex_unlock(&priv->lock);
return ret;
}
#endif /* CONFIG_I2C_RESET */