i2c/i2c_quark_se_ss: extends to do multi-byte read requests

This changes to request bytes that will fill the RX FIFO
instead of requesting byte one-by-one.

Change-Id: I87c6577dc5fcc476284cd3ed0039a178a5221d24
Signed-off-by: Daniel Leung <daniel.leung@intel.com>
This commit is contained in:
Daniel Leung 2016-01-12 13:35:09 -08:00 committed by Anas Nashif
commit 7a5fefbcd8
3 changed files with 54 additions and 17 deletions

View file

@ -31,6 +31,7 @@
#include <sys_io.h> #include <sys_io.h>
#include <board.h> #include <board.h>
#include <misc/util.h>
#include "i2c_quark_se_ss.h" #include "i2c_quark_se_ss.h"
#include "i2c_quark_se_ss_registers.h" #include "i2c_quark_se_ss_registers.h"
@ -131,6 +132,9 @@ static inline void _i2c_qse_ss_data_ask(struct device *dev)
{ {
struct i2c_qse_ss_dev_config * const dw = dev->driver_data; struct i2c_qse_ss_dev_config * const dw = dev->driver_data;
uint32_t data; uint32_t data;
uint8_t tx_empty;
int8_t rx_empty;
uint8_t cnt;
/* No more bytes to request, so command queue is no longer needed */ /* No more bytes to request, so command queue is no longer needed */
if (dw->request_bytes == 0) { if (dw->request_bytes == 0) {
@ -140,23 +144,48 @@ static inline void _i2c_qse_ss_data_ask(struct device *dev)
return; return;
} }
/* Tell controller to get another byte */ /* How many bytes we can actually ask */
data = IC_DATA_CMD_CMD | IC_DATA_CMD_STROBE | IC_DATA_CMD_POP; rx_empty = I2C_QSE_SS_FIFO_DEPTH
- _i2c_qse_ss_reg_read(dev, REG_RXFLR);
rx_empty -= dw->rx_pending;
/* Send RESTART if needed */ if (rx_empty < 0) {
if (dw->xfr_flags & I2C_MSG_RESTART) { /* RX FIFO expected to be full.
data |= IC_DATA_CMD_RESTART; * So don't request any bytes, yet.
dw->xfr_flags &= ~(I2C_MSG_RESTART); */
return;
} }
/* After receiving the last byte, send STOP if needed */ /* How many empty slots in TX FIFO (as command queue) */
if ((dw->xfr_flags & I2C_MSG_STOP) && (dw->request_bytes == 1)) { tx_empty = I2C_QSE_SS_FIFO_DEPTH
data |= IC_DATA_CMD_STOP; - _i2c_qse_ss_reg_read(dev, REG_TXFLR);
/* Figure out how many bytes we can request */
cnt = min(I2C_QSE_SS_FIFO_DEPTH, dw->request_bytes);
cnt = min(min(tx_empty, rx_empty), cnt);
while (cnt > 0) {
/* Tell controller to get another byte */
data = IC_DATA_CMD_CMD | IC_DATA_CMD_STROBE | IC_DATA_CMD_POP;
/* Send RESTART if needed */
if (dw->xfr_flags & I2C_MSG_RESTART) {
data |= IC_DATA_CMD_RESTART;
dw->xfr_flags &= ~(I2C_MSG_RESTART);
}
/* After receiving the last byte, send STOP if needed */
if ((dw->xfr_flags & I2C_MSG_STOP)
&& (dw->request_bytes == 1)) {
data |= IC_DATA_CMD_STOP;
}
_i2c_qse_ss_reg_write(dev, REG_DATA_CMD, data);
dw->rx_pending++;
dw->request_bytes--;
cnt--;
} }
_i2c_qse_ss_reg_write(dev, REG_DATA_CMD, data);
dw->request_bytes--;
} }
static void _i2c_qse_ss_data_read(struct device *dev) static void _i2c_qse_ss_data_read(struct device *dev)
@ -175,12 +204,11 @@ static void _i2c_qse_ss_data_read(struct device *dev)
dw->xfr_buf++; dw->xfr_buf++;
dw->xfr_len--; dw->xfr_len--;
dw->rx_pending--;
if (dw->xfr_len == 0) { if (dw->xfr_len == 0) {
break; break;
} }
_i2c_qse_ss_data_ask(dev);
} }
/* Nothing to receive anymore */ /* Nothing to receive anymore */
@ -374,9 +402,13 @@ static int _i2c_qse_ss_setup(struct device *dev, uint16_t addr)
* *
* TX: * TX:
* Setting it to 0 so TX_EMPTY is set only when * Setting it to 0 so TX_EMPTY is set only when
* the TX FIFO is empty. * TX FIFO is truly empty. So that we can let
* the controller do the transfers for longer period
* before we need to fill the FIFO again. This may
* cause some pauses during transfers, but this keeps
* the device from interrupting often.
* *
* TODO: extend the threshold for multi-byte TX/RX FIFO. * TODO: extend the threshold for multi-byte RX FIFO.
*/ */
_i2c_qse_ss_reg_write(dev, REG_TL, 0x00000000); _i2c_qse_ss_reg_write(dev, REG_TL, 0x00000000);
@ -428,6 +460,7 @@ static int i2c_qse_ss_intr_transfer(struct device *dev,
dw->xfr_buf = cur_msg->buf; dw->xfr_buf = cur_msg->buf;
dw->xfr_len = cur_msg->len; dw->xfr_len = cur_msg->len;
dw->xfr_flags = cur_msg->flags; dw->xfr_flags = cur_msg->flags;
dw->rx_pending = 0;
/* Need to RESTART if changing transfer direction */ /* Need to RESTART if changing transfer direction */
if ((pflags & I2C_MSG_RW_MASK) if ((pflags & I2C_MSG_RW_MASK)

View file

@ -46,6 +46,8 @@
#define I2C_FS_HCNT ((CONFIG_I2C_CLOCK_SPEED * 6) / 8) #define I2C_FS_HCNT ((CONFIG_I2C_CLOCK_SPEED * 6) / 8)
#define I2C_FS_LCNT ((CONFIG_I2C_CLOCK_SPEED * 7) / 8) #define I2C_FS_LCNT ((CONFIG_I2C_CLOCK_SPEED * 7) / 8)
#define I2C_QSE_SS_FIFO_DEPTH 8
typedef void (*i2c_qse_ss_cfg_func_t)(struct device *port); typedef void (*i2c_qse_ss_cfg_func_t)(struct device *port);
struct i2c_qse_ss_rom_config { struct i2c_qse_ss_rom_config {
@ -81,6 +83,7 @@ struct i2c_qse_ss_dev_config {
uint8_t *xfr_buf; uint8_t *xfr_buf;
uint32_t xfr_len; uint32_t xfr_len;
uint32_t request_bytes; uint32_t request_bytes;
uint32_t rx_pending;
uint16_t hcnt; uint16_t hcnt;
uint16_t lcnt; uint16_t lcnt;

View file

@ -32,6 +32,7 @@
#define REG_INTR_CLR 0x0A #define REG_INTR_CLR 0x0A
#define REG_STATUS 0x0B #define REG_STATUS 0x0B
#define REG_TXFLR 0x0C #define REG_TXFLR 0x0C
#define REG_RXFLR 0x0D
#define REG_SDA_CONFIG 0x0E #define REG_SDA_CONFIG 0x0E
#define REG_TX_ABRT_SOURCE 0x0F #define REG_TX_ABRT_SOURCE 0x0F
#define REG_ENABLE_STATUS 0x11 #define REG_ENABLE_STATUS 0x11