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

I2c fixes #204

Merged
merged 5 commits into from
Jan 15, 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
144 changes: 110 additions & 34 deletions arch/risc-v/src/mpfs/mpfs_i2c.c
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,10 @@ typedef enum mpfs_i2c_status
MPFS_I2C_SUCCESS = 0u,
MPFS_I2C_IN_PROGRESS,
MPFS_I2C_FAILED,
MPFS_I2C_TIMED_OUT
MPFS_I2C_FAILED_SLAW_NACK,
MPFS_I2C_FAILED_SLAR_NACK,
MPFS_I2C_FAILED_TX_DATA_NACK,
MPFS_I2C_FAILED_BUS_ERROR,
} mpfs_i2c_status_t;

typedef enum mpfs_i2c_clock_divider
Expand Down Expand Up @@ -122,6 +125,8 @@ static const uint32_t mpfs_i2c_freqs_fpga[MPFS_I2C_NUMBER_OF_DIVIDERS] =
MPFS_FPGA_BCLK / 8
};

static int mpfs_i2c_irq(int cpuint, void *context, void *arg);

static int mpfs_i2c_transfer(struct i2c_master_s *dev,
struct i2c_msg_s *msgs,
int count);
Expand Down Expand Up @@ -297,8 +302,67 @@ static uint32_t mpfs_i2c_timeout(int msgc, struct i2c_msg_s *msgv);

static int mpfs_i2c_init(struct mpfs_i2c_priv_s *priv)
{
int ret = OK;
uint32_t ctrl;
uint32_t status;

if (!priv->initialized)
{
/* In case of warm boot, or after reset, check that the IP block is
* not already active and try to recover from any pending data
* transfer if it is.
*/

ctrl = getreg32(MPFS_I2C_CTRL);
if (ctrl != 0)
{
/* Check if the IP is enabled */

status = getreg32(MPFS_I2C_STATUS);
if (ctrl & MPFS_I2C_CTRL_ENS1_MASK)
{
if (status == MPFS_I2C_ST_RX_DATA_ACK)
{
/* In case the machine was in the middle of data RX, try to
* receive one byte and nack it
*/

modifyreg32(MPFS_I2C_CTRL, MPFS_I2C_CTRL_AA_MASK, 0);
modifyreg32(MPFS_I2C_CTRL, MPFS_I2C_CTRL_SI_MASK, 0);
usleep(100);
status = getreg32(MPFS_I2C_STATUS);
}

if (status != MPFS_I2C_ST_IDLE)
{
/* If the bus is not idle, send STOP */

modifyreg32(MPFS_I2C_CTRL, MPFS_I2C_CTRL_SI_MASK, 0);
modifyreg32(MPFS_I2C_CTRL, 0, MPFS_I2C_CTRL_STO_MASK);
usleep(100);
modifyreg32(MPFS_I2C_CTRL, MPFS_I2C_CTRL_SI_MASK, 0);
status = getreg32(MPFS_I2C_STATUS);
}
}

if (status != MPFS_I2C_ST_IDLE)
{
i2cerr("Bus not idle before init\n");
}

/* Disable IP and continue initialization */

putreg32(0, MPFS_I2C_CTRL);
}

/* Attach interrupt */

ret = irq_attach(priv->plic_irq, mpfs_i2c_irq, priv);
if (ret != OK)
{
return ret;
}

if (priv->fpga)
{
/* FIC3 is used by many, don't reset it here, or many
Expand Down Expand Up @@ -357,10 +421,9 @@ static int mpfs_i2c_init(struct mpfs_i2c_priv_s *priv)

putreg32(priv->ser_address, MPFS_I2C_ADDR);

/* Enable i2c bus */
/* Enable i2c bus, clear all other bits */

modifyreg32(MPFS_I2C_CTRL, MPFS_I2C_CTRL_ENS1_MASK,
MPFS_I2C_CTRL_ENS1_MASK);
putreg32(MPFS_I2C_CTRL_ENS1_MASK, MPFS_I2C_CTRL);

priv->initialized = true;
}
Expand All @@ -384,8 +447,7 @@ static void mpfs_i2c_deinit(struct mpfs_i2c_priv_s *priv)
up_disable_irq(priv->plic_irq);
irq_detach(priv->plic_irq);

modifyreg32(MPFS_I2C_CTRL, MPFS_I2C_CTRL_ENS1_MASK,
~MPFS_I2C_CTRL_ENS1_MASK);
putreg32(0, MPFS_I2C_CTRL);

priv->initialized = false;
}
Expand Down Expand Up @@ -469,7 +531,7 @@ static int mpfs_i2c_irq(int cpuint, void *context, void *arg)

case MPFS_I2C_ST_SLAW_NACK:
modifyreg32(MPFS_I2C_CTRL, 0, MPFS_I2C_CTRL_STO_MASK);
priv->status = MPFS_I2C_FAILED;
priv->status = MPFS_I2C_FAILED_SLAW_NACK;
break;

case MPFS_I2C_ST_SLAW_ACK:
Expand Down Expand Up @@ -537,7 +599,7 @@ static int mpfs_i2c_irq(int cpuint, void *context, void *arg)

case MPFS_I2C_ST_TX_DATA_NACK:
modifyreg32(MPFS_I2C_CTRL, 0, MPFS_I2C_CTRL_STO_MASK);
priv->status = MPFS_I2C_FAILED;
priv->status = MPFS_I2C_FAILED_TX_DATA_NACK;
break;

case MPFS_I2C_ST_SLAR_ACK: /* SLA+R tx'ed. */
Expand All @@ -559,7 +621,7 @@ static int mpfs_i2c_irq(int cpuint, void *context, void *arg)

case MPFS_I2C_ST_SLAR_NACK: /* SLA+R tx'ed; send a stop condition */
modifyreg32(MPFS_I2C_CTRL, 0, MPFS_I2C_CTRL_STO_MASK);
priv->status = MPFS_I2C_FAILED;
priv->status = MPFS_I2C_FAILED_SLAR_NACK;
break;

case MPFS_I2C_ST_RX_DATA_ACK:
Expand Down Expand Up @@ -611,7 +673,6 @@ static int mpfs_i2c_irq(int cpuint, void *context, void *arg)

priv->rx_buffer[priv->rx_idx] = (uint8_t)getreg32(MPFS_I2C_DATA);
priv->rx_idx++;

priv->status = MPFS_I2C_SUCCESS;
modifyreg32(MPFS_I2C_CTRL, 0, MPFS_I2C_CTRL_STO_MASK);
break;
Expand Down Expand Up @@ -652,7 +713,7 @@ static int mpfs_i2c_irq(int cpuint, void *context, void *arg)

if (priv->status == MPFS_I2C_IN_PROGRESS)
{
priv->status = MPFS_I2C_FAILED;
priv->status = MPFS_I2C_FAILED_BUS_ERROR;
}

break;
Expand Down Expand Up @@ -704,6 +765,10 @@ static int mpfs_i2c_transfer(struct i2c_master_s *dev,
{
struct mpfs_i2c_priv_s *priv = (struct mpfs_i2c_priv_s *)dev;
int ret = OK;
#ifdef CONFIG_DEBUG_I2C_ERROR
int sval;
uint32_t status;
#endif

i2cinfo("Starting transfer request of %d message(s):\n", count);

Expand All @@ -718,6 +783,24 @@ static int mpfs_i2c_transfer(struct i2c_master_s *dev,
return ret;
}

#ifdef CONFIG_DEBUG_I2C_ERROR
/* We should never start at transfer with semaphore already signalled */

sem_getvalue(&priv->sem_isr, &sval);
if (sval != 0)
{
i2cerr("Already signalled at start? %d\n", sval);
}

/* We should always be idle before transfer */

status = getreg32(MPFS_I2C_STATUS);
if (status != MPFS_I2C_ST_IDLE)
{
i2cerr("I2C bus not idle before transfer! Status: 0x%x\n", status);
}
#endif

priv->msgv = msgs;
priv->msgc = count;

Expand Down Expand Up @@ -810,6 +893,16 @@ static int mpfs_i2c_transfer(struct i2c_master_s *dev,
i2cinfo("Message %" PRIu8 " transfer complete.\n", priv->msgid);
}

#ifdef CONFIG_DEBUG_I2C_ERROR
/* We should always be idle after the transfers */

status = getreg32(MPFS_I2C_STATUS);
if (status != MPFS_I2C_ST_IDLE)
{
i2cerr("I2C bus not idle after transfer! Status: 0x%x\n", status);
}
#endif

/* Irq was enabled at mpfs_i2c_sendstart() */

up_disable_irq(priv->plic_irq);
Expand Down Expand Up @@ -837,35 +930,26 @@ static int mpfs_i2c_reset(struct i2c_master_s *dev)
{
struct mpfs_i2c_priv_s *priv = (struct mpfs_i2c_priv_s *)dev;
int ret;
irqstate_t flags;

DEBUGASSERT(priv != NULL);

flags = enter_critical_section();

/* Disabling I2C interrupts.
* NOTE: up_enable_irq() will be called at mpfs_i2c_sendstart()
*/

up_disable_irq(priv->plic_irq);
nxmutex_lock(&priv->lock);

priv->inflight = false;
priv->status = MPFS_I2C_SUCCESS;
priv->initialized = false;
mpfs_i2c_deinit(priv);

ret = mpfs_i2c_init(priv);
if (ret != OK)
{
leave_critical_section(flags);
nxmutex_unlock(&priv->lock);
return ret;
}

priv->tx_size = 0;
priv->tx_idx = 0;
priv->rx_size = 0;
priv->rx_idx = 0;
priv->inflight = false;
priv->status = MPFS_I2C_SUCCESS;

leave_critical_section(flags);
nxmutex_unlock(&priv->lock);

return OK;
}
Expand Down Expand Up @@ -1059,14 +1143,6 @@ struct i2c_master_s *mpfs_i2cbus_initialize(int port)
priv->fpga = true;
#endif

ret = irq_attach(priv->plic_irq, mpfs_i2c_irq, priv);
if (ret != OK)
{
priv->refs--;
nxmutex_unlock(&priv->lock);
return NULL;
}

ret = mpfs_i2c_init(priv);
if (ret != OK)
{
Expand Down
Loading