Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

arch/arm64/src/imx9/imx9_lpi2c.c: Fix bus reset #317

Merged
merged 1 commit into from
Nov 25, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
138 changes: 23 additions & 115 deletions arch/arm64/src/imx9/imx9_lpi2c.c
Original file line number Diff line number Diff line change
Expand Up @@ -176,10 +176,6 @@ struct imx9_lpi2c_config_s
uint8_t filtsda; /* Glitch Filter for SDA pin */
iomux_cfg_t scl_pin; /* Peripheral configuration for SCL as SCL */
iomux_cfg_t sda_pin; /* Peripheral configuration for SDA as SDA */
#if defined(CONFIG_I2C_RESET)
gpio_pinset_t reset_scl_pin; /* GPIO configuration for SCL as GPIO */
gpio_pinset_t reset_sda_pin; /* GPIO configuration for SDA as GPIO */
#endif
uint8_t mode; /* Master or Slave mode */
#ifndef CONFIG_I2C_POLLED
uint32_t irq; /* Event IRQ */
Expand Down Expand Up @@ -338,10 +334,6 @@ static const struct imx9_lpi2c_config_s imx9_lpi2c1_config =
.filtsda = CONFIG_IMX9_LPI2C1_FILTSDA,
.scl_pin = MUX_LPI2C1_SCL,
.sda_pin = MUX_LPI2C1_SDA,
#if defined(CONFIG_I2C_RESET)
.reset_scl_pin = GPIO_LPI2C1_SCL_RESET,
.reset_sda_pin = GPIO_LPI2C1_SDA_RESET,
#endif
#ifndef CONFIG_I2C_SLAVE
.mode = LPI2C_MASTER,
#else
Expand Down Expand Up @@ -386,10 +378,6 @@ static const struct imx9_lpi2c_config_s imx9_lpi2c2_config =
.filtsda = CONFIG_IMX9_LPI2C2_FILTSDA,
.scl_pin = MUX_LPI2C2_SCL,
.sda_pin = MUX_LPI2C2_SDA,
#if defined(CONFIG_I2C_RESET)
.reset_scl_pin = GPIO_LPI2C2_SCL_RESET,
.reset_sda_pin = GPIO_LPI2C2_SDA_RESET,
#endif
#ifndef CONFIG_I2C_SLAVE
.mode = LPI2C_MASTER,
#else
Expand Down Expand Up @@ -434,10 +422,6 @@ static const struct imx9_lpi2c_config_s imx9_lpi2c3_config =
.filtsda = CONFIG_IMX9_LPI2C3_FILTSDA,
.scl_pin = MUX_LPI2C3_SCL,
.sda_pin = MUX_LPI2C3_SDA,
#if defined(CONFIG_I2C_RESET)
.reset_scl_pin = GPIO_LPI2C3_SCL_RESET,
.reset_sda_pin = GPIO_LPI2C3_SDA_RESET,
#endif
#ifndef CONFIG_I2C_SLAVE
.mode = LPI2C_MASTER,
#else
Expand Down Expand Up @@ -482,10 +466,6 @@ static const struct imx9_lpi2c_config_s imx9_lpi2c4_config =
.filtsda = CONFIG_IMX9_LPI2C4_FILTSDA,
.scl_pin = MUX_LPI2C4_SCL,
.sda_pin = MUX_LPI2C4_SDA,
#if defined(CONFIG_I2C_RESET)
.reset_scl_pin = GPIO_LPI2C4_SCL_RESET,
.reset_sda_pin = GPIO_LPI2C4_SDA_RESET,
#endif
#ifndef CONFIG_I2C_SLAVE
.mode = LPI2C_MASTER,
#else
Expand Down Expand Up @@ -530,10 +510,6 @@ static const struct imx9_lpi2c_config_s imx9_lpi2c5_config =
.filtsda = CONFIG_IMX9_LPI2C5_FILTSDA,
.scl_pin = MUX_LPI2C5_SCL,
.sda_pin = MUX_LPI2C5_SDA,
#if defined(CONFIG_I2C_RESET)
.reset_scl_pin = GPIO_LPI2C5_SCL_RESET,
.reset_sda_pin = GPIO_LPI2C5_SDA_RESET,
#endif
#ifndef CONFIG_I2C_SLAVE
.mode = LPI2C_MASTER,
#else
Expand Down Expand Up @@ -578,10 +554,6 @@ static const struct imx9_lpi2c_config_s imx9_lpi2c6_config =
.filtsda = CONFIG_IMX9_LPI2C6_FILTSDA,
.scl_pin = MUX_LPI2C6_SCL,
.sda_pin = MUX_LPI2C6_SDA,
#if defined(CONFIG_I2C_RESET)
.reset_scl_pin = GPIO_LPI2C6_SCL_RESET,
.reset_sda_pin = GPIO_LPI2C6_SDA_RESET,
#endif
#ifndef CONFIG_I2C_SLAVE
.mode = LPI2C_MASTER,
#else
Expand Down Expand Up @@ -626,10 +598,6 @@ static const struct imx9_lpi2c_config_s imx9_lpi2c7_config =
.filtsda = CONFIG_IMX9_LPI2C7_FILTSDA,
.scl_pin = MUX_LPI2C7_SCL,
.sda_pin = MUX_LPI2C7_SDA,
#if defined(CONFIG_I2C_RESET)
.reset_scl_pin = GPIO_LPI2C7_SCL_RESET,
.reset_sda_pin = GPIO_LPI2C7_SDA_RESET,
#endif
#ifndef CONFIG_I2C_SLAVE
.mode = LPI2C_MASTER,
#else
Expand Down Expand Up @@ -674,10 +642,6 @@ static const struct imx9_lpi2c_config_s imx9_lpi2c8_config =
.filtsda = CONFIG_IMX9_LPI2C8_FILTSDA,
.scl_pin = MUX_LPI2C8_SCL,
.sda_pin = MUX_LPI2C8_SDA,
#if defined(CONFIG_I2C_RESET)
.reset_scl_pin = GPIO_LPI2C8_SCL_RESET,
.reset_sda_pin = GPIO_LPI2C8_SDA_RESET,
#endif
#ifndef CONFIG_I2C_SLAVE
.mode = LPI2C_MASTER,
#else
Expand Down Expand Up @@ -2187,11 +2151,8 @@ static int imx9_lpi2c_transfer(struct i2c_master_s *dev,
static int imx9_lpi2c_reset(struct i2c_master_s *dev)
{
struct imx9_lpi2c_priv_s *priv = (struct imx9_lpi2c_priv_s *)dev;
unsigned int clock_count;
unsigned int stretch_count;
uint32_t scl_gpio;
uint32_t sda_gpio;
uint32_t frequency;
uint32_t status;
unsigned count;
int ret;

DEBUGASSERT(dev);
Expand All @@ -2208,95 +2169,42 @@ static int imx9_lpi2c_reset(struct i2c_master_s *dev)
return ret;
}

ret = -EIO;

/* Save the current frequency */

frequency = priv->frequency;

/* De-init the port */

imx9_lpi2c_deinit(priv);

/* Use GPIO configuration to un-wedge the bus */

imx9_iomux_gpio(priv->config->scl_pin, true);
imx9_iomux_gpio(priv->config->sda_pin, true);

scl_gpio = priv->config->reset_scl_pin;
sda_gpio = priv->config->reset_sda_pin;
/* Re-init the port */

imx9_config_gpio(scl_gpio);
imx9_config_gpio(sda_gpio);
imx9_lpi2c_init(priv);

/* Let SDA go high */
/* Set bus to relaxed mode - this allows clocking the bus even when it
* is busy
*/

imx9_gpio_write(sda_gpio, 1);
imx9_lpi2c_modifyreg(priv, IMX9_LPI2C_MCFGR0_OFFSET,
0, LPI2C_MCFG0_RELAX);

/* Clock the bus until any slaves currently driving it let it go. */
/* Clock the bus until it gets freed (max 10 times) */

clock_count = 0;
while (!imx9_gpio_read(sda_gpio))
count = 0;
status = imx9_lpi2c_getstatus(priv);
while ((status & LPI2C_MSR_BBF) != 0 && count++ < 10)
{
/* 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 (!imx9_gpio_read(scl_gpio))
{
/* Give up if we have tried too hard */

if (stretch_count++ > 10)
{
goto out;
}

up_udelay(10);
}

/* Drive SCL low */

imx9_gpio_write(scl_gpio, 0);
up_udelay(10);

/* Drive SCL high again */

imx9_gpio_write(scl_gpio, 1);
up_udelay(10);
i2cerr("Bus %d busy!\n", priv->config->clk_root - CCM_CR_LPI2C1 + 1);
imx9_lpi2c_sendstart(priv, 0);
imx9_lpi2c_sendstop(priv);
usleep(1000);
status = imx9_lpi2c_getstatus(priv);
}

/* Generate a start followed by a stop to reset slave
* state machines.
*/

imx9_gpio_write(sda_gpio, 0);
up_udelay(10);
imx9_gpio_write(scl_gpio, 0);
up_udelay(10);
imx9_gpio_write(scl_gpio, 1);
up_udelay(10);
imx9_gpio_write(sda_gpio, 1);
up_udelay(10);
/* Check that the bus is now free */

/* Re-init the port */

imx9_lpi2c_init(priv);
ret = (status & LPI2C_MSR_BBF) == 0 ? OK : -EIO;

/* Restore the frequency */
/* Exit relaxed mode */

imx9_lpi2c_setclock(priv, frequency);
ret = OK;

out:
imx9_lpi2c_modifyreg(priv, IMX9_LPI2C_MCFGR0_OFFSET,
LPI2C_MCFG0_RELAX, 0);

/* Release the port for re-use by other clients */

Expand Down
Loading