ITE: drivers/i2c/target: Introduce I2C target transfer using PIO mode
Introduce I2C target transfer using the PIO mode. Add an option "target-pio-mode" in the yaml file, determined by the DTS, to dictate whether I2C target transfer uses the PIO mode. Signed-off-by: Tim Lin <tim2.lin@ite.corp-partner.google.com>
This commit is contained in:
parent
3ae9a358fb
commit
8a779fc706
|
@ -72,6 +72,7 @@ struct i2c_enhance_config {
|
|||
uint8_t prescale_scl_low;
|
||||
uint32_t clock_gate_offset;
|
||||
bool target_enable;
|
||||
bool target_pio_mode;
|
||||
};
|
||||
|
||||
enum i2c_pin_fun {
|
||||
|
@ -137,6 +138,7 @@ struct i2c_enhance_data {
|
|||
#ifdef CONFIG_I2C_TARGET
|
||||
struct i2c_target_config *target_cfg;
|
||||
uint32_t buffer_size;
|
||||
int target_nack;
|
||||
bool target_attached;
|
||||
#endif
|
||||
union {
|
||||
|
@ -209,6 +211,7 @@ enum i2c_reset_cause {
|
|||
I2C_RC_TIMEOUT,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_I2C_TARGET
|
||||
enum enhanced_i2c_target_status {
|
||||
/* Time out error */
|
||||
E_TARGET_TMOE = 0x08,
|
||||
|
@ -217,6 +220,7 @@ enum enhanced_i2c_target_status {
|
|||
/* Time out or lost arbitration */
|
||||
E_TARGET_ANY_ERROR = (E_TARGET_TMOE | E_TARGET_ARB),
|
||||
};
|
||||
#endif
|
||||
|
||||
static int i2c_parsing_return_value(const struct device *dev)
|
||||
{
|
||||
|
@ -381,6 +385,8 @@ static int enhanced_i2c_error(const struct device *dev)
|
|||
} else if ((i2c_str & E_HOSTA_BDS_AND_ACK) == E_HOSTA_BDS) {
|
||||
if (IT8XXX2_I2C_CTR(base) & E_ACK) {
|
||||
data->err = E_HOSTA_ACK;
|
||||
/* STOP */
|
||||
IT8XXX2_I2C_CTR(base) = E_FINISH;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -955,10 +961,104 @@ static int i2c_enhance_transfer(const struct device *dev,
|
|||
}
|
||||
|
||||
#ifdef CONFIG_I2C_TARGET
|
||||
static void target_i2c_isr_dma(const struct device *dev,
|
||||
uint8_t interrupt_status)
|
||||
{
|
||||
struct i2c_enhance_data *data = dev->data;
|
||||
const struct i2c_enhance_config *config = dev->config;
|
||||
const struct i2c_target_callbacks *target_cb = data->target_cfg->callbacks;
|
||||
struct i2c_target_dma_buffer *target_buffer = &data->target_buffer;
|
||||
uint8_t *base = config->base;
|
||||
|
||||
/* Byte counter enable */
|
||||
if (interrupt_status & IT8XXX2_I2C_IDW_CLR) {
|
||||
IT8XXX2_I2C_BYTE_CNT_L(base) |=
|
||||
(IT8XXX2_I2C_DMA_ADDR_RELOAD |
|
||||
IT8XXX2_I2C_BYTE_CNT_ENABLE);
|
||||
}
|
||||
/* The number of received data exceeds the byte counter setting */
|
||||
if (interrupt_status & IT8XXX2_I2C_CNT_HOLD) {
|
||||
LOG_ERR("The excess data written starts "
|
||||
"from the memory address:%p",
|
||||
target_buffer->in_buffer +
|
||||
CONFIG_I2C_TARGET_IT8XXX2_MAX_BUF_SIZE);
|
||||
}
|
||||
/* Controller to write data */
|
||||
if (interrupt_status & IT8XXX2_I2C_SLVDATAFLG) {
|
||||
/* Number of receive data in target mode */
|
||||
data->buffer_size =
|
||||
((IT8XXX2_I2C_SLV_NUM_H(base) << 8) |
|
||||
IT8XXX2_I2C_SLV_NUM_L(base)) + 1;
|
||||
|
||||
/* Write data done callback function */
|
||||
target_cb->buf_write_received(data->target_cfg,
|
||||
target_buffer->in_buffer, data->buffer_size);
|
||||
}
|
||||
/* Controller to read data */
|
||||
if (interrupt_status & IT8XXX2_I2C_IDR_CLR) {
|
||||
uint32_t len;
|
||||
uint8_t *rdata = NULL;
|
||||
|
||||
/* Clear byte counter setting */
|
||||
IT8XXX2_I2C_BYTE_CNT_L(base) &=
|
||||
~(IT8XXX2_I2C_DMA_ADDR_RELOAD |
|
||||
IT8XXX2_I2C_BYTE_CNT_ENABLE);
|
||||
/* Read data callback function */
|
||||
target_cb->buf_read_requested(data->target_cfg,
|
||||
&rdata, &len);
|
||||
|
||||
if (len > CONFIG_I2C_TARGET_IT8XXX2_MAX_BUF_SIZE) {
|
||||
LOG_ERR("The bufffer size exceeds "
|
||||
"I2C_TARGET_IT8XXX2_MAX_BUF_SIZE: len=%d",
|
||||
len);
|
||||
} else {
|
||||
memcpy(target_buffer->out_buffer, rdata, len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int target_i2c_isr_pio(const struct device *dev,
|
||||
uint8_t interrupt_status,
|
||||
uint8_t target_status)
|
||||
{
|
||||
struct i2c_enhance_data *data = dev->data;
|
||||
const struct i2c_enhance_config *config = dev->config;
|
||||
const struct i2c_target_callbacks *target_cb = data->target_cfg->callbacks;
|
||||
int ret = 0;
|
||||
uint8_t *base = config->base;
|
||||
uint8_t val;
|
||||
|
||||
/* Target ID write flag */
|
||||
if (interrupt_status & IT8XXX2_I2C_IDW_CLR) {
|
||||
ret = target_cb->write_requested(data->target_cfg);
|
||||
}
|
||||
/* Target ID read flag */
|
||||
else if (interrupt_status & IT8XXX2_I2C_IDR_CLR) {
|
||||
if (!target_cb->read_requested(data->target_cfg, &val)) {
|
||||
IT8XXX2_I2C_DTR(base) = val;
|
||||
}
|
||||
}
|
||||
/* Byte transfer done */
|
||||
else if (target_status & IT8XXX2_I2C_BYTE_DONE) {
|
||||
/* Read of write */
|
||||
if (target_status & IT8XXX2_I2C_RW) {
|
||||
/* Host receiving, target transmitting */
|
||||
if (!target_cb->read_processed(data->target_cfg, &val)) {
|
||||
IT8XXX2_I2C_DTR(base) = val;
|
||||
}
|
||||
} else {
|
||||
/* Host transmitting, target receiving */
|
||||
val = IT8XXX2_I2C_DRR(base);
|
||||
ret = target_cb->write_received(data->target_cfg, val);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void target_i2c_isr(const struct device *dev)
|
||||
{
|
||||
struct i2c_enhance_data *data = dev->data;
|
||||
struct i2c_target_dma_buffer *target_buffer = &data->target_buffer;
|
||||
const struct i2c_enhance_config *config = dev->config;
|
||||
const struct i2c_target_callbacks *target_cb = data->target_cfg->callbacks;
|
||||
uint8_t *base = config->base;
|
||||
|
@ -973,55 +1073,27 @@ static void target_i2c_isr(const struct device *dev)
|
|||
if (target_status & IT8XXX2_I2C_INT_PEND) {
|
||||
uint8_t interrupt_status = IT8XXX2_I2C_IRQ_ST(base);
|
||||
|
||||
/* Byte counter enable */
|
||||
if (interrupt_status & IT8XXX2_I2C_IDW_CLR) {
|
||||
IT8XXX2_I2C_BYTE_CNT_L(base) |=
|
||||
(IT8XXX2_I2C_DMA_ADDR_RELOAD |
|
||||
IT8XXX2_I2C_BYTE_CNT_ENABLE);
|
||||
}
|
||||
/* The number of received data exceeds the byte counter setting */
|
||||
if (interrupt_status & IT8XXX2_I2C_CNT_HOLD) {
|
||||
LOG_ERR("The excess data written starts "
|
||||
"from the memory address:%p",
|
||||
target_buffer->in_buffer +
|
||||
CONFIG_I2C_TARGET_IT8XXX2_MAX_BUF_SIZE);
|
||||
}
|
||||
/* Controller to write data */
|
||||
if (interrupt_status & IT8XXX2_I2C_SLVDATAFLG) {
|
||||
/* Number of receive data in target mode */
|
||||
data->buffer_size =
|
||||
((IT8XXX2_I2C_SLV_NUM_H(base) << 8) |
|
||||
IT8XXX2_I2C_SLV_NUM_L(base)) + 1;
|
||||
|
||||
/* Write data done callback function */
|
||||
target_cb->buf_write_received(data->target_cfg,
|
||||
target_buffer->in_buffer, data->buffer_size);
|
||||
}
|
||||
/* Controller to read data */
|
||||
if (interrupt_status & IT8XXX2_I2C_IDR_CLR) {
|
||||
uint32_t len;
|
||||
uint8_t *rdata = NULL;
|
||||
|
||||
/* Clear byte counter setting */
|
||||
IT8XXX2_I2C_BYTE_CNT_L(base) &=
|
||||
~(IT8XXX2_I2C_DMA_ADDR_RELOAD |
|
||||
IT8XXX2_I2C_BYTE_CNT_ENABLE);
|
||||
/* Read data callback function */
|
||||
target_cb->buf_read_requested(data->target_cfg,
|
||||
&rdata, &len);
|
||||
|
||||
if (len > CONFIG_I2C_TARGET_IT8XXX2_MAX_BUF_SIZE) {
|
||||
LOG_ERR("The bufffer size exceeds "
|
||||
"I2C_TARGET_IT8XXX2_MAX_BUF_SIZE: len=%d",
|
||||
len);
|
||||
} else {
|
||||
memcpy(target_buffer->out_buffer, rdata, len);
|
||||
/* Determine whether the transaction uses PIO or DMA mode */
|
||||
if (config->target_pio_mode) {
|
||||
if (target_i2c_isr_pio(dev, interrupt_status, target_status) < 0) {
|
||||
/* NACK */
|
||||
IT8XXX2_I2C_CTR(base) &= ~IT8XXX2_I2C_ACK;
|
||||
IT8XXX2_I2C_CTR(base) |= IT8XXX2_I2C_HALT;
|
||||
data->target_nack = 1;
|
||||
}
|
||||
} else {
|
||||
target_i2c_isr_dma(dev, interrupt_status);
|
||||
}
|
||||
/* Peripheral finish */
|
||||
if (interrupt_status & IT8XXX2_I2C_P_CLR) {
|
||||
/* Transfer done callback function */
|
||||
target_cb->stop(data->target_cfg);
|
||||
|
||||
if (data->target_nack) {
|
||||
/* Set acknowledge */
|
||||
IT8XXX2_I2C_CTR(base) |= IT8XXX2_I2C_ACK;
|
||||
data->target_nack = 0;
|
||||
}
|
||||
}
|
||||
/* Write clear the peripheral status */
|
||||
IT8XXX2_I2C_IRQ_ST(base) = interrupt_status;
|
||||
|
@ -1200,8 +1272,6 @@ static int i2c_enhance_target_register(const struct device *dev,
|
|||
{
|
||||
const struct i2c_enhance_config *config = dev->config;
|
||||
struct i2c_enhance_data *data = dev->data;
|
||||
struct i2c_target_dma_buffer *target_buffer = &data->target_buffer;
|
||||
uint32_t in_data_addr, out_data_addr;
|
||||
uint8_t *base = config->base;
|
||||
|
||||
if (!target_cfg) {
|
||||
|
@ -1235,44 +1305,59 @@ static int i2c_enhance_target_register(const struct device *dev,
|
|||
/* Interrupt status write clear */
|
||||
IT8XXX2_I2C_IRQ_ST(base) = 0xff;
|
||||
|
||||
/* Clear read and write data buffer of DMA */
|
||||
memset(target_buffer->in_buffer, 0, CONFIG_I2C_TARGET_IT8XXX2_MAX_BUF_SIZE);
|
||||
memset(target_buffer->out_buffer, 0, CONFIG_I2C_TARGET_IT8XXX2_MAX_BUF_SIZE);
|
||||
/* I2C target initial configuration of PIO mode */
|
||||
if (config->target_pio_mode) {
|
||||
/* Block to enter power policy. */
|
||||
pm_policy_state_lock_get(PM_STATE_STANDBY, PM_ALL_SUBSTATES);
|
||||
|
||||
in_data_addr = (uint32_t)target_buffer->in_buffer & 0xffffff;
|
||||
out_data_addr = (uint32_t)target_buffer->out_buffer & 0xffffff;
|
||||
/*
|
||||
* DMA write target address register
|
||||
* for high order byte
|
||||
*/
|
||||
IT8XXX2_I2C_RAMH2A(base) = in_data_addr >> 16;
|
||||
IT8XXX2_I2C_RAMHA(base) = in_data_addr >> 8;
|
||||
IT8XXX2_I2C_RAMLA(base) = in_data_addr;
|
||||
/*
|
||||
* DMA read target address register
|
||||
* for high order byte
|
||||
*/
|
||||
IT8XXX2_I2C_CMD_ADDH2(base) = out_data_addr >> 16;
|
||||
IT8XXX2_I2C_RAMHA2(base) = out_data_addr >> 8;
|
||||
IT8XXX2_I2C_RAMLA2(base) = out_data_addr;
|
||||
/* I2C module enable */
|
||||
IT8XXX2_I2C_CTR1(base) = IT8XXX2_I2C_MDL_EN;
|
||||
/* I2C target initial configuration of DMA mode */
|
||||
} else {
|
||||
struct i2c_target_dma_buffer *target_buffer = &data->target_buffer;
|
||||
uint32_t in_data_addr, out_data_addr;
|
||||
int buf_size = CONFIG_I2C_TARGET_IT8XXX2_MAX_BUF_SIZE;
|
||||
|
||||
/* Byte counter setting */
|
||||
/* This register indicates byte count[10:3]. */
|
||||
IT8XXX2_I2C_BYTE_CNT_H(base) = CONFIG_I2C_TARGET_IT8XXX2_MAX_BUF_SIZE >> 3;
|
||||
/* This register indicates byte count[2:0]. */
|
||||
IT8XXX2_I2C_BYTE_CNT_L(base) = CONFIG_I2C_TARGET_IT8XXX2_MAX_BUF_SIZE &
|
||||
GENMASK(2, 0);
|
||||
/* Clear read and write data buffer of DMA */
|
||||
memset(target_buffer->in_buffer, 0, buf_size);
|
||||
memset(target_buffer->out_buffer, 0, buf_size);
|
||||
|
||||
/*
|
||||
* The EC processor(CPU) cannot be in the k_cpu_idle() and power
|
||||
* policy during the transactions with the CQ mode(DMA mode).
|
||||
* Otherwise, the EC processor would be clock gated.
|
||||
*/
|
||||
chip_block_idle();
|
||||
pm_policy_state_lock_get(PM_STATE_STANDBY, PM_ALL_SUBSTATES);
|
||||
in_data_addr = (uint32_t)target_buffer->in_buffer & 0xffffff;
|
||||
out_data_addr = (uint32_t)target_buffer->out_buffer & 0xffffff;
|
||||
/*
|
||||
* DMA write target address register
|
||||
* for high order byte
|
||||
*/
|
||||
IT8XXX2_I2C_RAMH2A(base) = in_data_addr >> 16;
|
||||
IT8XXX2_I2C_RAMHA(base) = in_data_addr >> 8;
|
||||
IT8XXX2_I2C_RAMLA(base) = in_data_addr;
|
||||
/*
|
||||
* DMA read target address register
|
||||
* for high order byte
|
||||
*/
|
||||
IT8XXX2_I2C_CMD_ADDH2(base) = out_data_addr >> 16;
|
||||
IT8XXX2_I2C_RAMHA2(base) = out_data_addr >> 8;
|
||||
IT8XXX2_I2C_RAMLA2(base) = out_data_addr;
|
||||
|
||||
/* I2C module enable and command queue mode */
|
||||
IT8XXX2_I2C_CTR1(base) = IT8XXX2_I2C_COMQ_EN | IT8XXX2_I2C_MDL_EN;
|
||||
/* Byte counter setting */
|
||||
/* This register indicates byte count[10:3]. */
|
||||
IT8XXX2_I2C_BYTE_CNT_H(base) =
|
||||
CONFIG_I2C_TARGET_IT8XXX2_MAX_BUF_SIZE >> 3;
|
||||
/* This register indicates byte count[2:0]. */
|
||||
IT8XXX2_I2C_BYTE_CNT_L(base) =
|
||||
CONFIG_I2C_TARGET_IT8XXX2_MAX_BUF_SIZE & GENMASK(2, 0);
|
||||
|
||||
/*
|
||||
* The EC processor(CPU) cannot be in the k_cpu_idle() and power
|
||||
* policy during the transactions with the CQ mode(DMA mode).
|
||||
* Otherwise, the EC processor would be clock gated.
|
||||
*/
|
||||
chip_block_idle();
|
||||
pm_policy_state_lock_get(PM_STATE_STANDBY, PM_ALL_SUBSTATES);
|
||||
|
||||
/* I2C module enable and command queue mode */
|
||||
IT8XXX2_I2C_CTR1(base) = IT8XXX2_I2C_COMQ_EN | IT8XXX2_I2C_MDL_EN;
|
||||
}
|
||||
|
||||
ite_intc_isr_clear(config->i2c_irq_base);
|
||||
irq_enable(config->i2c_irq_base);
|
||||
|
@ -1294,10 +1379,13 @@ static int i2c_enhance_target_unregister(const struct device *dev,
|
|||
|
||||
/* Permit to enter power policy and idle mode. */
|
||||
pm_policy_state_lock_put(PM_STATE_STANDBY, PM_ALL_SUBSTATES);
|
||||
chip_permit_idle();
|
||||
if (!config->target_pio_mode) {
|
||||
chip_permit_idle();
|
||||
}
|
||||
|
||||
data->target_cfg = NULL;
|
||||
data->target_attached = false;
|
||||
data->target_nack = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1343,6 +1431,7 @@ BUILD_ASSERT(IS_ENABLED(CONFIG_I2C_TARGET_BUFFER_MODE),
|
|||
.clock_gate_offset = DT_INST_PROP(inst, clock_gate_offset), \
|
||||
.pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(inst), \
|
||||
.target_enable = DT_INST_PROP(inst, target_enable), \
|
||||
.target_pio_mode = DT_INST_PROP(inst, target_pio_mode), \
|
||||
}; \
|
||||
\
|
||||
static struct i2c_enhance_data i2c_enhance_data_##inst; \
|
||||
|
|
|
@ -24,3 +24,9 @@ properties:
|
|||
This option is used when the I2C target is enabled. It is
|
||||
necessary to prevent the target port from being configured
|
||||
with I2C host related initialization.
|
||||
|
||||
target-pio-mode:
|
||||
type: boolean
|
||||
description: |
|
||||
This option is used when the I2C target is enabled and it can
|
||||
support PIO mode for I2C target transfer.
|
||||
|
|
|
@ -1321,6 +1321,8 @@ enum chip_pll_mode {
|
|||
/* 0x55: Slave A FIFO Control */
|
||||
#define IT8XXX2_SMB_HSAPE BIT(1)
|
||||
/* 0x03: Status Register */
|
||||
#define IT8XXX2_I2C_BYTE_DONE BIT(7)
|
||||
#define IT8XXX2_I2C_RW BIT(2)
|
||||
#define IT8XXX2_I2C_INT_PEND BIT(1)
|
||||
/* 0x04: Data Hold Time */
|
||||
#define IT8XXX2_I2C_SOFT_RST BIT(7)
|
||||
|
|
Loading…
Reference in a new issue