summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHarry Cutts <hcutts@chromium.org>2019-09-30 16:50:42 -0700
committerCommit Bot <commit-bot@chromium.org>2019-10-09 19:35:03 +0000
commitcb856036beaa8d2c552b4d71c0b9c0144ff53aec (patch)
treeafca774c3f23c0ec4af728a40862faaa7f6d97c8
parentef1f88d4561b96c24485d910a402f59b3005b1e6 (diff)
downloadchrome-ec-cb856036beaa8d2c552b4d71c0b9c0144ff53aec.tar.gz
max32660: put slave-only code in `#ifdef`s
This fixes a bunch of "<method> defined but not used" build warnings when working with a board that only uses the I2C master and not the slave. Also fixed various checkpatch.pl errors and warnings that appeared in the lines that were moved. BRANCH=none BUG=chromium:1008568 TEST=Build a MAX32660 board that only uses the I2C master and check that it succeeds with no warnings. Modify it to use the slave as well and check that host commands still work. Change-Id: Icee04ad6d7b641f934e56b670be8770710a41e64 Signed-off-by: Harry Cutts <hcutts@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/1832892 Reviewed-by: Jes Klinke <jbk@chromium.org> Reviewed-by: Randall Spangler <rspangler@chromium.org>
-rw-r--r--chip/max32660/i2c_chip.c798
1 files changed, 395 insertions, 403 deletions
diff --git a/chip/max32660/i2c_chip.c b/chip/max32660/i2c_chip.c
index 4f8bc6f7ae..2069cf7921 100644
--- a/chip/max32660/i2c_chip.c
+++ b/chip/max32660/i2c_chip.c
@@ -144,7 +144,6 @@ struct i2c_req {
};
static i2c_req_state_t states[MXC_I2C_INSTANCES];
-static int slave_rx_remain = 0, slave_tx_remain = 0;
/**
* struct i2c_port_data
@@ -172,25 +171,23 @@ struct i2c_port_data {
static struct i2c_port_data pdata[I2C_PORT_COUNT];
/* **** Function Prototypes **** */
-static void i2c_free_callback(int i2c_num, int error);
-static void init_i2cs(int port);
static int i2c_init_peripheral(mxc_i2c_regs_t *i2c, i2c_speed_t i2cspeed);
static int i2c_master_write(mxc_i2c_regs_t *i2c, uint8_t addr, int start,
int stop, const uint8_t *data, int len,
int restart);
static int i2c_master_read(mxc_i2c_regs_t *i2c, uint8_t addr, int start,
int stop, uint8_t *data, int len, int restart);
+
+#ifdef CONFIG_HOSTCMD_I2C_SLAVE_ADDR_FLAGS
+static void i2c_free_callback(int i2c_num, int error);
+static void init_i2cs(int port);
static int i2c_slave_async(mxc_i2c_regs_t *i2c, i2c_req_t *req);
-static void i2c_handler(mxc_i2c_regs_t *i2c);
+static void i2c_slave_handler(mxc_i2c_regs_t *i2c);
+#endif /* CONFIG_HOSTCMD_I2C_SLAVE_ADDR_FLAGS */
/* Port address for each I2C */
static mxc_i2c_regs_t *i2c_bus_ports[] = {MXC_I2C0, MXC_I2C1};
-#ifdef CONFIG_HOSTCMD_I2C_SLAVE_ADDR_FLAGS
-/* IRQ for each I2C */
-static uint32_t i2c_bus_irqs[] = {EC_I2C0_IRQn, EC_I2C1_IRQn};
-#endif
-
/**
* chip_i2c_xfer() - Low Level function for I2C Master Reads and Writes.
* @port: Port to access
@@ -291,6 +288,9 @@ DECLARE_HOOK(HOOK_INIT, i2c_init, HOOK_PRIO_INIT_I2C);
*/
#ifdef CONFIG_HOSTCMD_I2C_SLAVE_ADDR_FLAGS
+/* IRQ for each I2C */
+static uint32_t i2c_bus_irqs[] = {EC_I2C0_IRQn, EC_I2C1_IRQn};
+
/**
* Buffer for received host command packets (including prefix byte on request,
* and result/size on response). After any protocol-specific headers, the
@@ -301,6 +301,7 @@ static uint8_t host_buffer_padded[I2C_MAX_HOST_PACKET_SIZE + 4 +
static uint8_t *const host_buffer = host_buffer_padded + 2;
static uint8_t params_copy[I2C_MAX_HOST_PACKET_SIZE] __aligned(4);
static struct host_packet i2c_packet;
+static int slave_rx_remain, slave_tx_remain;
static i2c_req_t req_slave;
volatile int ec_pending_response = 0;
@@ -328,7 +329,7 @@ static void i2c_send_response_packet(struct host_packet *pkt)
req_slave.tx_len = size + 2;
/* Call the handler for transmition of response packet. */
- i2c_handler(i2c_bus_ports[I2C_PORT_EC]);
+ i2c_slave_handler(i2c_bus_ports[I2C_PORT_EC]);
}
/**
@@ -395,7 +396,7 @@ void i2c_chip_callback(i2c_req_t *req, int error)
*/
void I2C0_IRQHandler(void)
{
- i2c_handler(i2c_bus_ports[0]);
+ i2c_slave_handler(i2c_bus_ports[0]);
}
/**
@@ -403,13 +404,353 @@ void I2C0_IRQHandler(void)
*/
void I2C1_IRQHandler(void)
{
- i2c_handler(i2c_bus_ports[1]);
+ i2c_slave_handler(i2c_bus_ports[1]);
}
DECLARE_IRQ(EC_I2C0_IRQn, I2C0_IRQHandler, 1);
DECLARE_IRQ(EC_I2C1_IRQn, I2C1_IRQHandler, 1);
/**
+ * i2c_slave_read() - Handles async read request from the I2c master.
+ * @i2c: I2C peripheral pointer.
+ * @req: Pointer to the request info.
+ * @int_flags: Current state of the interrupt flags for this request.
+ *
+ * Return EC_SUCCESS if successful, otherwise returns a common error code.
+ */
+static int i2c_slave_read(mxc_i2c_regs_t *i2c, i2c_req_t *req,
+ uint32_t int_flags)
+{
+ int i2c_num;
+
+ i2c_num = MXC_I2C_GET_IDX(i2c);
+ req->direction = I2C_TRANSFER_DIRECTION_MASTER_READ;
+ if (slave_tx_remain != 0) {
+ /* Fill the FIFO */
+ while ((slave_tx_remain > 0) &&
+ !(i2c->status & MXC_F_I2C_STATUS_TX_FULL)) {
+ i2c->fifo = *(req->tx_data)++;
+ states[i2c_num].num_wr++;
+ slave_tx_remain--;
+ }
+ /* Set the TX threshold interrupt level. */
+ if (slave_tx_remain >= (MXC_I2C_FIFO_DEPTH - 1)) {
+ i2c->tx_ctrl0 =
+ ((i2c->tx_ctrl0 &
+ ~(MXC_F_I2C_TX_CTRL0_TX_THRESH)) |
+ (MXC_I2C_FIFO_DEPTH - 1)
+ << MXC_F_I2C_TX_CTRL0_TX_THRESH_POS);
+
+ } else {
+ i2c->tx_ctrl0 =
+ ((i2c->tx_ctrl0 &
+ ~(MXC_F_I2C_TX_CTRL0_TX_THRESH)) |
+ (slave_tx_remain)
+ << MXC_F_I2C_TX_CTRL0_TX_THRESH_POS);
+ }
+ /* Enable TXTH interrupt and Error interrupts. */
+ i2c->int_en0 |= (MXC_F_I2C_INT_EN0_TX_THRESH | I2C_ERROR);
+ if (int_flags & I2C_ERROR) {
+ i2c->int_en0 = 0;
+ /* Calculate the number of bytes sent by the slave. */
+ req->tx_num =
+ states[i2c_num].num_wr -
+ ((i2c->tx_ctrl1 & MXC_F_I2C_TX_CTRL1_TX_FIFO) >>
+ MXC_F_I2C_TX_CTRL1_TX_FIFO_POS);
+ if (!req->sw_autoflush_disable) {
+ /* Manually clear the TXFIFO. */
+ i2c->tx_ctrl0 |= MXC_F_I2C_TX_CTRL0_TX_FLUSH;
+ }
+ states[i2c_num].num_wr = 0;
+ if (req->callback != NULL) {
+ /* Disable and clear interrupts. */
+ i2c->int_en0 = 0;
+ i2c->int_en1 = 0;
+ i2c->int_fl0 = i2c->int_fl0;
+ i2c->int_fl1 = i2c->int_fl1;
+ /* Cycle the I2C peripheral enable on error. */
+ i2c->ctrl = 0;
+ i2c->ctrl = MXC_F_I2C_CTRL_I2C_EN;
+ i2c_free_callback(i2c_num, EC_ERROR_UNKNOWN);
+ }
+ return EC_ERROR_UNKNOWN;
+ }
+ } else {
+ /**
+ * If there is nothing to transmit to the EC HOST, then default
+ * to clock stretching.
+ */
+ if (req->tx_len == -1)
+ return EC_SUCCESS;
+ /**
+ * The EC HOST is requesting more that we are able to transmit.
+ * Fulfill the EC HOST reading of extra bytes by sending the
+ * EC_PADDING_BYTE.
+ */
+ if (!(i2c->status & MXC_F_I2C_STATUS_TX_FULL))
+ i2c->fifo = EC_PADDING_BYTE;
+ /* set tx threshold to zero */
+ i2c->tx_ctrl0 =
+ ((i2c->tx_ctrl0 & ~(MXC_F_I2C_TX_CTRL0_TX_THRESH)) |
+ (0) << MXC_F_I2C_TX_CTRL0_TX_THRESH_POS);
+ /* Enable TXTH interrupt and Error interrupts */
+ i2c->int_en0 |= (MXC_F_I2C_INT_EN0_TX_THRESH | I2C_ERROR);
+ }
+ return EC_SUCCESS;
+}
+
+/**
+ * i2c_slave_write() - Handles async write request from the I2c master.
+ * @i2c: I2C peripheral pointer.
+ * @req: Pointer to the request info.
+ * @int_flags: Current state of the interrupt flags for this request.
+ *
+ * Return EC_SUCCESS if successful, otherwise returns a common error code.
+ */
+static int i2c_slave_write(mxc_i2c_regs_t *i2c, i2c_req_t *req,
+ uint32_t int_flags)
+{
+ int i2c_num;
+
+ /**
+ * Master Write has been called and if there is a
+ * rx_data buffer
+ */
+ i2c_num = MXC_I2C_GET_IDX(i2c);
+ req->direction = I2C_TRANSFER_DIRECTION_MASTER_WRITE;
+ if (slave_rx_remain != 0) {
+ /* Read out any data in the RX FIFO. */
+ while ((slave_rx_remain > 0) &&
+ !(i2c->status & MXC_F_I2C_STATUS_RX_EMPTY)) {
+ *(req->rx_data)++ = i2c->fifo;
+ req->rx_num++;
+ slave_rx_remain--;
+ }
+ /* Set the RX threshold interrupt level. */
+ if (slave_rx_remain >= (MXC_I2C_FIFO_DEPTH - 1)) {
+ i2c->rx_ctrl0 =
+ ((i2c->rx_ctrl0 &
+ ~(MXC_F_I2C_RX_CTRL0_RX_THRESH)) |
+ (MXC_I2C_FIFO_DEPTH - 1)
+ << MXC_F_I2C_RX_CTRL0_RX_THRESH_POS);
+ } else {
+ i2c->rx_ctrl0 =
+ ((i2c->rx_ctrl0 &
+ ~(MXC_F_I2C_RX_CTRL0_RX_THRESH)) |
+ (slave_rx_remain)
+ << MXC_F_I2C_RX_CTRL0_RX_THRESH_POS);
+ }
+ /* Enable RXTH interrupt and Error interrupts. */
+ i2c->int_en0 |= (MXC_F_I2C_INT_EN0_RX_THRESH | I2C_ERROR);
+ if (int_flags & I2C_ERROR) {
+ i2c->int_en0 = 0;
+ /**
+ * Calculate the number of bytes sent
+ * by the slave.
+ */
+ req->tx_num =
+ states[i2c_num].num_wr -
+ ((i2c->tx_ctrl1 & MXC_F_I2C_TX_CTRL1_TX_FIFO) >>
+ MXC_F_I2C_TX_CTRL1_TX_FIFO_POS);
+
+ if (!req->sw_autoflush_disable) {
+ /* Manually clear the TXFIFO. */
+ i2c->tx_ctrl0 |= MXC_F_I2C_TX_CTRL0_TX_FLUSH;
+ }
+ states[i2c_num].num_wr = 0;
+ if (req->callback != NULL) {
+ /* Disable and clear interrupts. */
+ i2c->int_en0 = 0;
+ i2c->int_en1 = 0;
+ i2c->int_fl0 = i2c->int_fl0;
+ i2c->int_fl1 = i2c->int_fl1;
+ /* Cycle the I2C peripheral enable on error. */
+ i2c->ctrl = 0;
+ i2c->ctrl = MXC_F_I2C_CTRL_I2C_EN;
+ i2c_free_callback(i2c_num, EC_ERROR_UNKNOWN);
+ }
+ return EC_ERROR_UNKNOWN;
+ }
+ } else {
+ /* Disable RXTH interrupt. */
+ i2c->int_en0 &= ~(MXC_F_I2C_INT_EN0_RX_THRESH);
+ /* Flush any extra bytes in the RXFIFO */
+ i2c->rx_ctrl0 |= MXC_F_I2C_RX_CTRL0_RX_FLUSH;
+ /* Store the current state of the slave */
+ states[i2c_num].slave_state = I2C_SLAVE_READ_COMPLETE;
+ }
+ return EC_SUCCESS;
+}
+
+/**
+ * i2c_slave_handler() - I2C interrupt handler.
+ * @i2c: Base address of the I2C module.
+ *
+ * This function should be called by the application from the interrupt
+ * handler if I2C interrupts are enabled. Alternately, this function
+ * can be periodically called by the application if I2C interrupts are
+ * disabled.
+ */
+static void i2c_slave_handler(mxc_i2c_regs_t *i2c)
+{
+ uint32_t int_flags;
+ int i2c_num;
+ i2c_req_t *req;
+ int status;
+
+ i2c_num = MXC_I2C_GET_IDX(i2c);
+ req = states[i2c_num].req;
+
+ /* Check for an Address match */
+ if (i2c->int_fl0 & MXC_F_I2C_INT_FL0_ADDR_MATCH) {
+ /* Clear AMI and TXLOI */
+ i2c->int_fl0 |= MXC_F_I2C_INT_FL0_DONE;
+ i2c->int_fl0 |= MXC_F_I2C_INT_FL0_ADDR_MATCH;
+ i2c->int_fl0 |= MXC_F_I2C_INT_FL0_TX_LOCK_OUT;
+ /* Store the current state of the Slave */
+ states[i2c_num].slave_state = I2C_SLAVE_ADDR_MATCH;
+ /* Set the Done, Stop interrupt */
+ i2c->int_en0 |= MXC_F_I2C_INT_EN0_DONE | MXC_F_I2C_INT_EN0_STOP;
+ /* Inhibit sleep mode when addressed until STOPF flag is set */
+ disable_sleep(SLEEP_MASK_I2C_SLAVE);
+ }
+
+ /* Check for errors */
+ int_flags = i2c->int_fl0;
+ /* Clear the interrupts */
+ i2c->int_fl0 = int_flags;
+
+ if (int_flags & I2C_ERROR) {
+ i2c->int_en0 = 0;
+ /* Calculate the number of bytes sent by the slave */
+ req->tx_num = states[i2c_num].num_wr -
+ ((i2c->tx_ctrl1 & MXC_F_I2C_TX_CTRL1_TX_FIFO) >>
+ MXC_F_I2C_TX_CTRL1_TX_FIFO_POS);
+
+ if (!req->sw_autoflush_disable) {
+ /* Manually clear the TXFIFO */
+ i2c->tx_ctrl0 |= MXC_F_I2C_TX_CTRL0_TX_FLUSH;
+ }
+ states[i2c_num].num_wr = 0;
+ if (req->callback != NULL) {
+ /* Disable and clear interrupts */
+ i2c->int_en0 = 0;
+ i2c->int_en1 = 0;
+ i2c->int_fl0 = i2c->int_fl0;
+ i2c->int_fl1 = i2c->int_fl1;
+ /* Cycle the I2C peripheral enable on error. */
+ i2c->ctrl = 0;
+ i2c->ctrl = MXC_F_I2C_CTRL_I2C_EN;
+ i2c_free_callback(i2c_num, EC_ERROR_UNKNOWN);
+ }
+ return;
+ }
+
+ slave_rx_remain = req->rx_len - req->rx_num;
+ /* determine if there is any data ready to transmit to the EC HOST */
+ if (req->tx_len != -1)
+ slave_tx_remain = req->tx_len - states[i2c_num].num_wr;
+ else
+ slave_tx_remain = 0;
+
+ /* Check for Stop interrupt */
+ if (int_flags & MXC_F_I2C_INT_FL0_STOP) {
+ /* Disable all interrupts except address match. */
+ i2c->int_en1 = 0;
+ i2c->int_en0 = MXC_F_I2C_INT_EN0_ADDR_MATCH;
+ /* Clear all interrupts except a possible address match. */
+ i2c->int_fl0 = i2c->int_fl0 & ~MXC_F_I2C_INT_FL0_ADDR_MATCH;
+ i2c->int_fl1 = i2c->int_fl1;
+ if (req->direction == I2C_TRANSFER_DIRECTION_MASTER_WRITE) {
+ /* Read out any data in the RX FIFO */
+ while (!(i2c->status & MXC_F_I2C_STATUS_RX_EMPTY)) {
+ *(req->rx_data)++ = i2c->fifo;
+ req->rx_num++;
+ }
+ }
+
+ /* Calculate the number of bytes sent by the slave */
+ req->tx_num = states[i2c_num].num_wr -
+ ((i2c->tx_ctrl1 & MXC_F_I2C_TX_CTRL1_TX_FIFO) >>
+ MXC_F_I2C_TX_CTRL1_TX_FIFO_POS);
+ slave_rx_remain = 0;
+ slave_tx_remain = 0;
+ if (!req->sw_autoflush_disable) {
+ /* Manually clear the TXFIFO */
+ i2c->tx_ctrl0 |= MXC_F_I2C_TX_CTRL0_TX_FLUSH;
+ }
+ /* Callback to the EC request processor */
+ i2c_free_callback(i2c_num, EC_SUCCESS);
+ req->direction = I2C_TRANSFER_DIRECTION_NONE;
+ states[i2c_num].num_wr = 0;
+
+ /* Be ready to receive more data */
+ req->rx_len = 128;
+ /* Clear the byte counters */
+ req->tx_num = 0;
+ req->rx_num = 0;
+ req->tx_len = -1; /* Nothing to send. */
+
+ /* No longer inhibit deep sleep after stop condition */
+ enable_sleep(SLEEP_MASK_I2C_SLAVE);
+ return;
+ }
+
+ /* Check for DONE interrupt */
+ if (int_flags & MXC_F_I2C_INT_FL0_DONE) {
+ if (req->direction == I2C_TRANSFER_DIRECTION_MASTER_WRITE) {
+ /* Read out any data in the RX FIFO */
+ while (!(i2c->status & MXC_F_I2C_STATUS_RX_EMPTY)) {
+ *(req->rx_data)++ = i2c->fifo;
+ req->rx_num++;
+ }
+ }
+ /* Disable Done interrupt */
+ i2c->int_en0 &= ~(MXC_F_I2C_INT_EN0_DONE);
+ /* Calculate the number of bytes sent by the slave */
+ req->tx_num = states[i2c_num].num_wr -
+ ((i2c->tx_ctrl1 & MXC_F_I2C_TX_CTRL1_TX_FIFO) >>
+ MXC_F_I2C_TX_CTRL1_TX_FIFO_POS);
+ slave_rx_remain = 0;
+ slave_tx_remain = 0;
+ if (!req->sw_autoflush_disable) {
+ /* Manually clear the TXFIFO */
+ i2c->tx_ctrl0 |= MXC_F_I2C_TX_CTRL0_TX_FLUSH;
+ }
+ i2c_free_callback(i2c_num, EC_SUCCESS);
+ req->direction = I2C_TRANSFER_DIRECTION_NONE;
+ states[i2c_num].num_wr = 0;
+ return;
+ }
+
+ if (states[i2c_num].slave_state != I2C_SLAVE_ADDR_MATCH)
+ return;
+ /**
+ * Check if Master Read has been called and if there is a
+ * tx_data buffer
+ */
+ if (i2c->ctrl & MXC_F_I2C_CTRL_READ) {
+ status = i2c_slave_read(i2c, req, int_flags);
+ if (status != EC_SUCCESS)
+ return;
+ } else {
+ status = i2c_slave_write(i2c, req, int_flags);
+ if (status != EC_SUCCESS)
+ return;
+ }
+}
+
+static void i2c_free_callback(int i2c_num, int error)
+{
+ /* Save the request */
+ i2c_req_t *temp_req = states[i2c_num].req;
+
+ /* Callback if not NULL */
+ if (temp_req->callback != NULL)
+ temp_req->callback(temp_req, error);
+}
+
+/**
* init_i2cs() - Async Handler for I2C Slave driver.
* @port: I2C port number to initialize.
*/
@@ -417,8 +758,11 @@ void init_i2cs(int port)
{
int error;
- if ((error = i2c_init_peripheral(i2c_bus_ports[port], I2C_STD_MODE)) !=
- EC_SUCCESS) {
+ slave_rx_remain = 0;
+ slave_tx_remain = 0;
+
+ error = i2c_init_peripheral(i2c_bus_ports[port], I2C_STD_MODE);
+ if (error != EC_SUCCESS) {
while (1)
;
}
@@ -431,8 +775,8 @@ void init_i2cs(int port)
req_slave.restart = 0;
req_slave.callback = i2c_chip_callback;
- if ((error = i2c_slave_async(i2c_bus_ports[port], &req_slave)) !=
- EC_SUCCESS) {
+ error = i2c_slave_async(i2c_bus_ports[port], &req_slave);
+ if (error != EC_SUCCESS) {
while (1)
;
}
@@ -440,6 +784,41 @@ void init_i2cs(int port)
task_enable_irq(i2c_bus_irqs[port]);
}
+/**
+ * i2c_slave_async() - Slave Read and Write Asynchronous.
+ * @i2c: Pointer to I2C regs.
+ * @req: Request for an I2C transaction.
+ *
+ * Return EC_SUCCESS if successful, otherwise returns a common error code.
+ */
+static int i2c_slave_async(mxc_i2c_regs_t *i2c, i2c_req_t *req)
+{
+ /* Make sure the I2C has been initialized. */
+ if (!(i2c->ctrl & MXC_F_I2C_CTRL_I2C_EN))
+ return EC_ERROR_UNKNOWN;
+
+ states[MXC_I2C_GET_IDX(i2c)].req = req;
+
+ /* Disable master mode */
+ i2c->ctrl &= ~(MXC_F_I2C_CTRL_MST);
+ /* Set the Slave Address in the I2C peripheral register. */
+ i2c->slave_addr = req->addr;
+
+ /* Clear the byte counters */
+ req->tx_num = 0;
+ req->rx_num = 0;
+
+ /* Disable and clear the interrupts. */
+ i2c->int_en0 = 0;
+ i2c->int_en1 = 0;
+ i2c->int_fl0 = i2c->int_fl0;
+ i2c->int_fl1 = i2c->int_fl1;
+ /* Only enable the I2C Address match interrupt. */
+ i2c->int_en0 = MXC_F_I2C_INT_EN0_ADDR_MATCH;
+
+ return EC_SUCCESS;
+}
+
#endif /* CONFIG_HOSTCMD_I2C_SLAVE_ADDR_FLAGS */
/**
@@ -846,390 +1225,3 @@ static int i2c_master_read(mxc_i2c_regs_t *i2c, uint8_t addr, int start,
return EC_SUCCESS;
}
-
-/**
- * i2c_slave_async() - Slave Read and Write Asynchronous.
- * @i2c: Pointer to I2C regs.
- * @req: Request for an I2C transaction.
- *
- * Return EC_SUCCESS if successful, otherwise returns a common error code.
- */
-static int i2c_slave_async(mxc_i2c_regs_t *i2c, i2c_req_t *req)
-{
- /* Make sure the I2C has been initialized. */
- if (!(i2c->ctrl & MXC_F_I2C_CTRL_I2C_EN)) {
- return EC_ERROR_UNKNOWN;
- }
-
- states[MXC_I2C_GET_IDX(i2c)].req = req;
-
- /* Disable master mode */
- i2c->ctrl &= ~(MXC_F_I2C_CTRL_MST);
- /* Set the Slave Address in the I2C peripheral register. */
- i2c->slave_addr = req->addr;
-
- /* Clear the byte counters */
- req->tx_num = 0;
- req->rx_num = 0;
-
- /* Disable and clear the interrupts. */
- i2c->int_en0 = 0;
- i2c->int_en1 = 0;
- i2c->int_fl0 = i2c->int_fl0;
- i2c->int_fl1 = i2c->int_fl1;
- /* Only enable the I2C Address match interrupt. */
- i2c->int_en0 = MXC_F_I2C_INT_EN0_ADDR_MATCH;
-
- return EC_SUCCESS;
-}
-
-/**
- * i2c_slave_read() - Handles async read request from the I2c master.
- * @i2c: I2C peripheral pointer.
- * @req: Pointer to the request info.
- * @int_flags: Current state of the interrupt flags for this request.
- *
- * Return EC_SUCCESS if successful, otherwise returns a common error code.
- */
-static int i2c_slave_read(mxc_i2c_regs_t *i2c, i2c_req_t *req,
- uint32_t int_flags)
-{
- int i2c_num;
-
- i2c_num = MXC_I2C_GET_IDX(i2c);
- req->direction = I2C_TRANSFER_DIRECTION_MASTER_READ;
- if (slave_tx_remain != 0) {
- /* Fill the FIFO */
- while ((slave_tx_remain > 0) &&
- !(i2c->status & MXC_F_I2C_STATUS_TX_FULL)) {
- i2c->fifo = *(req->tx_data)++;
- states[i2c_num].num_wr++;
- slave_tx_remain--;
- }
- /* Set the TX threshold interrupt level. */
- if (slave_tx_remain >= (MXC_I2C_FIFO_DEPTH - 1)) {
- i2c->tx_ctrl0 =
- ((i2c->tx_ctrl0 &
- ~(MXC_F_I2C_TX_CTRL0_TX_THRESH)) |
- (MXC_I2C_FIFO_DEPTH - 1)
- << MXC_F_I2C_TX_CTRL0_TX_THRESH_POS);
-
- } else {
- i2c->tx_ctrl0 =
- ((i2c->tx_ctrl0 &
- ~(MXC_F_I2C_TX_CTRL0_TX_THRESH)) |
- (slave_tx_remain)
- << MXC_F_I2C_TX_CTRL0_TX_THRESH_POS);
- }
- /* Enable TXTH interrupt and Error interrupts. */
- i2c->int_en0 |= (MXC_F_I2C_INT_EN0_TX_THRESH | I2C_ERROR);
- if (int_flags & I2C_ERROR) {
- i2c->int_en0 = 0;
- /* Calculate the number of bytes sent by the slave. */
- req->tx_num =
- states[i2c_num].num_wr -
- ((i2c->tx_ctrl1 & MXC_F_I2C_TX_CTRL1_TX_FIFO) >>
- MXC_F_I2C_TX_CTRL1_TX_FIFO_POS);
- if (!req->sw_autoflush_disable) {
- /* Manually clear the TXFIFO. */
- i2c->tx_ctrl0 |= MXC_F_I2C_TX_CTRL0_TX_FLUSH;
- }
- states[i2c_num].num_wr = 0;
- if (req->callback != NULL) {
- /* Disable and clear interrupts. */
- i2c->int_en0 = 0;
- i2c->int_en1 = 0;
- i2c->int_fl0 = i2c->int_fl0;
- i2c->int_fl1 = i2c->int_fl1;
- /* Cycle the I2C peripheral enable on error. */
- i2c->ctrl = 0;
- i2c->ctrl = MXC_F_I2C_CTRL_I2C_EN;
- i2c_free_callback(i2c_num, EC_ERROR_UNKNOWN);
- }
- return EC_ERROR_UNKNOWN;
- }
- } else {
- /**
- * If there is nothing to transmit to the EC HOST, then default
- * to clock stretching.
- */
- if (req->tx_len == -1)
- return EC_SUCCESS;
- /**
- * The EC HOST is requesting more that we are able to transmit.
- * Fulfill the EC HOST reading of extra bytes by sending the
- * EC_PADDING_BYTE.
- */
- if (!(i2c->status & MXC_F_I2C_STATUS_TX_FULL)) {
- i2c->fifo = EC_PADDING_BYTE;
- }
- /* set tx threshold to zero */
- i2c->tx_ctrl0 =
- ((i2c->tx_ctrl0 & ~(MXC_F_I2C_TX_CTRL0_TX_THRESH)) |
- (0) << MXC_F_I2C_TX_CTRL0_TX_THRESH_POS);
- /* Enable TXTH interrupt and Error interrupts */
- i2c->int_en0 |= (MXC_F_I2C_INT_EN0_TX_THRESH | I2C_ERROR);
- }
- return EC_SUCCESS;
-}
-
-/**
- * i2c_slave_write() - Handles async write request from the I2c master.
- * @i2c: I2C peripheral pointer.
- * @req: Pointer to the request info.
- * @int_flags: Current state of the interrupt flags for this request.
- *
- * Return EC_SUCCESS if successful, otherwise returns a common error code.
- */
-static int i2c_slave_write(mxc_i2c_regs_t *i2c, i2c_req_t *req,
- uint32_t int_flags)
-{
- int i2c_num;
-
- /**
- * Master Write has been called and if there is a
- * rx_data buffer
- */
- i2c_num = MXC_I2C_GET_IDX(i2c);
- req->direction = I2C_TRANSFER_DIRECTION_MASTER_WRITE;
- if (slave_rx_remain != 0) {
- /* Read out any data in the RX FIFO. */
- while ((slave_rx_remain > 0) &&
- !(i2c->status & MXC_F_I2C_STATUS_RX_EMPTY)) {
- *(req->rx_data)++ = i2c->fifo;
- req->rx_num++;
- slave_rx_remain--;
- }
- /* Set the RX threshold interrupt level. */
- if (slave_rx_remain >= (MXC_I2C_FIFO_DEPTH - 1)) {
- i2c->rx_ctrl0 =
- ((i2c->rx_ctrl0 &
- ~(MXC_F_I2C_RX_CTRL0_RX_THRESH)) |
- (MXC_I2C_FIFO_DEPTH - 1)
- << MXC_F_I2C_RX_CTRL0_RX_THRESH_POS);
- } else {
- i2c->rx_ctrl0 =
- ((i2c->rx_ctrl0 &
- ~(MXC_F_I2C_RX_CTRL0_RX_THRESH)) |
- (slave_rx_remain)
- << MXC_F_I2C_RX_CTRL0_RX_THRESH_POS);
- }
- /* Enable RXTH interrupt and Error interrupts. */
- i2c->int_en0 |= (MXC_F_I2C_INT_EN0_RX_THRESH | I2C_ERROR);
- if (int_flags & I2C_ERROR) {
- i2c->int_en0 = 0;
- /**
- * Calculate the number of bytes sent
- * by the slave.
- */
- req->tx_num =
- states[i2c_num].num_wr -
- ((i2c->tx_ctrl1 & MXC_F_I2C_TX_CTRL1_TX_FIFO) >>
- MXC_F_I2C_TX_CTRL1_TX_FIFO_POS);
-
- if (!req->sw_autoflush_disable) {
- /* Manually clear the TXFIFO. */
- i2c->tx_ctrl0 |= MXC_F_I2C_TX_CTRL0_TX_FLUSH;
- }
- states[i2c_num].num_wr = 0;
- if (req->callback != NULL) {
- /* Disable and clear interrupts. */
- i2c->int_en0 = 0;
- i2c->int_en1 = 0;
- i2c->int_fl0 = i2c->int_fl0;
- i2c->int_fl1 = i2c->int_fl1;
- /* Cycle the I2C peripheral enable on error. */
- i2c->ctrl = 0;
- i2c->ctrl = MXC_F_I2C_CTRL_I2C_EN;
- i2c_free_callback(i2c_num, EC_ERROR_UNKNOWN);
- }
- return EC_ERROR_UNKNOWN;
- }
- } else {
- /* Disable RXTH interrupt. */
- i2c->int_en0 &= ~(MXC_F_I2C_INT_EN0_RX_THRESH);
- /* Flush any extra bytes in the RXFIFO */
- i2c->rx_ctrl0 |= MXC_F_I2C_RX_CTRL0_RX_FLUSH;
- /* Store the current state of the slave */
- states[i2c_num].slave_state = I2C_SLAVE_READ_COMPLETE;
- }
- return EC_SUCCESS;
-}
-
-static void i2c_slave_handler(mxc_i2c_regs_t *i2c)
-{
- uint32_t int_flags;
- int i2c_num;
- i2c_req_t *req;
- int status;
-
- i2c_num = MXC_I2C_GET_IDX(i2c);
- req = states[i2c_num].req;
-
- /* Check for an Address match */
- if (i2c->int_fl0 & MXC_F_I2C_INT_FL0_ADDR_MATCH) {
- /* Clear AMI and TXLOI */
- i2c->int_fl0 |= MXC_F_I2C_INT_FL0_DONE;
- i2c->int_fl0 |= MXC_F_I2C_INT_FL0_ADDR_MATCH;
- i2c->int_fl0 |= MXC_F_I2C_INT_FL0_TX_LOCK_OUT;
- /* Store the current state of the Slave */
- states[i2c_num].slave_state = I2C_SLAVE_ADDR_MATCH;
- /* Set the Done, Stop interrupt */
- i2c->int_en0 |= MXC_F_I2C_INT_EN0_DONE | MXC_F_I2C_INT_EN0_STOP;
- /* Inhibit sleep mode when addressed until STOPF flag is set */
- disable_sleep(SLEEP_MASK_I2C_SLAVE);
- }
-
- /* Check for errors */
- int_flags = i2c->int_fl0;
- /* Clear the interrupts */
- i2c->int_fl0 = int_flags;
-
- if (int_flags & I2C_ERROR) {
- i2c->int_en0 = 0;
- /* Calculate the number of bytes sent by the slave */
- req->tx_num = states[i2c_num].num_wr -
- ((i2c->tx_ctrl1 & MXC_F_I2C_TX_CTRL1_TX_FIFO) >>
- MXC_F_I2C_TX_CTRL1_TX_FIFO_POS);
-
- if (!req->sw_autoflush_disable) {
- /* Manually clear the TXFIFO */
- i2c->tx_ctrl0 |= MXC_F_I2C_TX_CTRL0_TX_FLUSH;
- }
- states[i2c_num].num_wr = 0;
- if (req->callback != NULL) {
- /* Disable and clear interrupts */
- i2c->int_en0 = 0;
- i2c->int_en1 = 0;
- i2c->int_fl0 = i2c->int_fl0;
- i2c->int_fl1 = i2c->int_fl1;
- /* Cycle the I2C peripheral enable on error. */
- i2c->ctrl = 0;
- i2c->ctrl = MXC_F_I2C_CTRL_I2C_EN;
- i2c_free_callback(i2c_num, EC_ERROR_UNKNOWN);
- }
- return;
- }
-
- slave_rx_remain = req->rx_len - req->rx_num;
- /* determine if there is any data ready to transmit to the EC HOST */
- if (req->tx_len != -1) {
- slave_tx_remain = req->tx_len - states[i2c_num].num_wr;
- } else {
- slave_tx_remain = 0;
- }
-
- /* Check for Stop interrupt */
- if (int_flags & MXC_F_I2C_INT_FL0_STOP) {
- /* Disable all interrupts except address match. */
- i2c->int_en1 = 0;
- i2c->int_en0 = MXC_F_I2C_INT_EN0_ADDR_MATCH;
- /* Clear all interrupts except a possible address match. */
- i2c->int_fl0 = i2c->int_fl0 & ~MXC_F_I2C_INT_FL0_ADDR_MATCH;
- i2c->int_fl1 = i2c->int_fl1;
- if (req->direction == I2C_TRANSFER_DIRECTION_MASTER_WRITE) {
- /* Read out any data in the RX FIFO */
- while (!(i2c->status & MXC_F_I2C_STATUS_RX_EMPTY)) {
- *(req->rx_data)++ = i2c->fifo;
- req->rx_num++;
- }
- }
-
- /* Calculate the number of bytes sent by the slave */
- req->tx_num = states[i2c_num].num_wr -
- ((i2c->tx_ctrl1 & MXC_F_I2C_TX_CTRL1_TX_FIFO) >>
- MXC_F_I2C_TX_CTRL1_TX_FIFO_POS);
- slave_rx_remain = 0;
- slave_tx_remain = 0;
- if (!req->sw_autoflush_disable) {
- /* Manually clear the TXFIFO */
- i2c->tx_ctrl0 |= MXC_F_I2C_TX_CTRL0_TX_FLUSH;
- }
- /* Callback to the EC request processor */
- i2c_free_callback(i2c_num, EC_SUCCESS);
- req->direction = I2C_TRANSFER_DIRECTION_NONE;
- states[i2c_num].num_wr = 0;
-
- /* Be ready to receive more data */
- req->rx_len = 128;
- /* Clear the byte counters */
- req->tx_num = 0;
- req->rx_num = 0;
- req->tx_len = -1; /* Nothing to send. */
-
- /* No longer inhibit deep sleep after stop condition */
- enable_sleep(SLEEP_MASK_I2C_SLAVE);
- return;
- }
-
- /* Check for DONE interrupt */
- if (int_flags & MXC_F_I2C_INT_FL0_DONE) {
- if (req->direction == I2C_TRANSFER_DIRECTION_MASTER_WRITE) {
- /* Read out any data in the RX FIFO */
- while (!(i2c->status & MXC_F_I2C_STATUS_RX_EMPTY)) {
- *(req->rx_data)++ = i2c->fifo;
- req->rx_num++;
- }
- }
- /* Disable Done interrupt */
- i2c->int_en0 &= ~(MXC_F_I2C_INT_EN0_DONE);
- /* Calculate the number of bytes sent by the slave */
- req->tx_num = states[i2c_num].num_wr -
- ((i2c->tx_ctrl1 & MXC_F_I2C_TX_CTRL1_TX_FIFO) >>
- MXC_F_I2C_TX_CTRL1_TX_FIFO_POS);
- slave_rx_remain = 0;
- slave_tx_remain = 0;
- if (!req->sw_autoflush_disable) {
- /* Manually clear the TXFIFO */
- i2c->tx_ctrl0 |= MXC_F_I2C_TX_CTRL0_TX_FLUSH;
- }
- i2c_free_callback(i2c_num, EC_SUCCESS);
- req->direction = I2C_TRANSFER_DIRECTION_NONE;
- states[i2c_num].num_wr = 0;
- return;
- }
-
- if (states[i2c_num].slave_state != I2C_SLAVE_ADDR_MATCH) {
- return;
- }
- /**
- * Check if Master Read has been called and if there is a
- * tx_data buffer
- */
- if (i2c->ctrl & MXC_F_I2C_CTRL_READ) {
- status = i2c_slave_read(i2c, req, int_flags);
- if (status != EC_SUCCESS) {
- return;
- }
- } else {
- status = i2c_slave_write(i2c, req, int_flags);
- if (status != EC_SUCCESS) {
- return;
- }
- }
-}
-
-/**
- * i2c_handler() - I2C interrupt handler.
- * @i2c: Base address of the I2C module.
- *
- * This function should be called by the application from the interrupt
- * handler if I2C interrupts are enabled. Alternately, this function
- * can be periodically called by the application if I2C interrupts are
- * disabled.
- */
-static void i2c_handler(mxc_i2c_regs_t *i2c)
-{
- i2c_slave_handler(i2c);
-}
-
-static void i2c_free_callback(int i2c_num, int error)
-{
- /* Save the request */
- i2c_req_t *temp_req = states[i2c_num].req;
-
- /* Callback if not NULL */
- if (temp_req->callback != NULL) {
- temp_req->callback(temp_req, error);
- }
-}