driver: i2c: ene_kb1200 i2c slave address

Fix slave address,
Notify transfer completion via semaphore

Signed-off-by: Steven Chang <steven@ene.com.tw>
This commit is contained in:
Steven Chang 2025-02-17 18:02:18 +08:00 committed by Benjamin Cabé
commit 95edcf70fc
2 changed files with 92 additions and 50 deletions

View file

@ -12,13 +12,20 @@
#include <errno.h> #include <errno.h>
#include <reg/fsmbm.h> #include <reg/fsmbm.h>
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(i2c_ene, CONFIG_I2C_LOG_LEVEL);
#include "i2c-priv.h"
struct i2c_kb1200_config { struct i2c_kb1200_config {
struct fsmbm_regs *fsmbm; struct fsmbm_regs *fsmbm;
uint32_t clock_freq;
const struct pinctrl_dev_config *pcfg; const struct pinctrl_dev_config *pcfg;
}; };
struct i2c_kb1200_data { struct i2c_kb1200_data {
struct k_sem mutex; struct k_sem lock;
struct k_sem wait;
volatile uint8_t *msg_buf; volatile uint8_t *msg_buf;
volatile uint32_t msg_len; volatile uint32_t msg_len;
volatile uint8_t msg_flags; volatile uint8_t msg_flags;
@ -39,6 +46,7 @@ static void i2c_kb1200_isr(const struct device *dev)
uint32_t remain = data->msg_len - data->index; uint32_t remain = data->msg_len - data->index;
uint32_t send_bytes = uint32_t send_bytes =
remain > FSMBM_BUFFER_SIZE ? FSMBM_BUFFER_SIZE : remain; remain > FSMBM_BUFFER_SIZE ? FSMBM_BUFFER_SIZE : remain;
memcpy((void *)&config->fsmbm->FSMBMDAT[0], memcpy((void *)&config->fsmbm->FSMBMDAT[0],
(void *)&data->msg_buf[data->index], send_bytes); (void *)&data->msg_buf[data->index], send_bytes);
data->index += send_bytes; data->index += send_bytes;
@ -52,7 +60,7 @@ static void i2c_kb1200_isr(const struct device *dev)
} else if (config->fsmbm->FSMBMPF & FSMBM_COMPLETE_EVENT) { } else if (config->fsmbm->FSMBMPF & FSMBM_COMPLETE_EVENT) {
/* complete */ /* complete */
if (((config->fsmbm->FSMBMSTS & FSMBM_STS_MASK) == FSMBM_SMBUS_BUSY) && if (((config->fsmbm->FSMBMSTS & FSMBM_STS_MASK) == FSMBM_SMBUS_BUSY) &&
((config->fsmbm->FSMBMFRT & ___STOP) == ___NONE)) { ((config->fsmbm->FSMBMFRT & FRT_STOP) == FRT_NONE)) {
/* while packet finish without STOP, the error message is /* while packet finish without STOP, the error message is
* FSMBM_SMBUS_BUSY * FSMBM_SMBUS_BUSY
*/ */
@ -61,10 +69,12 @@ static void i2c_kb1200_isr(const struct device *dev)
data->err_code = config->fsmbm->FSMBMSTS & FSMBM_STS_MASK; data->err_code = config->fsmbm->FSMBMSTS & FSMBM_STS_MASK;
} }
data->state = STATE_COMPLETE; data->state = STATE_COMPLETE;
k_sem_give(&data->wait);
config->fsmbm->FSMBMPF = FSMBM_COMPLETE_EVENT; config->fsmbm->FSMBMPF = FSMBM_COMPLETE_EVENT;
} else { } else {
data->err_code = config->fsmbm->FSMBMSTS & FSMBM_STS_MASK; data->err_code = config->fsmbm->FSMBMSTS & FSMBM_STS_MASK;
data->state = STATE_COMPLETE; data->state = STATE_COMPLETE;
k_sem_give(&data->wait);
} }
} else if (data->state == STATE_RECEIVING) { } else if (data->state == STATE_RECEIVING) {
uint32_t remain = data->msg_len - data->index; uint32_t remain = data->msg_len - data->index;
@ -89,7 +99,7 @@ static void i2c_kb1200_isr(const struct device *dev)
} else if (config->fsmbm->FSMBMPF & FSMBM_COMPLETE_EVENT) { } else if (config->fsmbm->FSMBMPF & FSMBM_COMPLETE_EVENT) {
/* complete */ /* complete */
if (((config->fsmbm->FSMBMSTS & FSMBM_STS_MASK) == FSMBM_SMBUS_BUSY) && if (((config->fsmbm->FSMBMSTS & FSMBM_STS_MASK) == FSMBM_SMBUS_BUSY) &&
((config->fsmbm->FSMBMFRT & ___STOP) == ___NONE)) { ((config->fsmbm->FSMBMFRT & FRT_STOP) == FRT_NONE)) {
/* while packet finish without STOP, the error message is /* while packet finish without STOP, the error message is
* FSMBM_SMBUS_BUSY * FSMBM_SMBUS_BUSY
*/ */
@ -98,13 +108,16 @@ static void i2c_kb1200_isr(const struct device *dev)
data->err_code = config->fsmbm->FSMBMSTS & FSMBM_STS_MASK; data->err_code = config->fsmbm->FSMBMSTS & FSMBM_STS_MASK;
} }
data->state = STATE_COMPLETE; data->state = STATE_COMPLETE;
k_sem_give(&data->wait);
config->fsmbm->FSMBMPF = FSMBM_COMPLETE_EVENT; config->fsmbm->FSMBMPF = FSMBM_COMPLETE_EVENT;
} else { } else {
data->err_code = config->fsmbm->FSMBMSTS & FSMBM_STS_MASK; data->err_code = config->fsmbm->FSMBMSTS & FSMBM_STS_MASK;
data->state = STATE_COMPLETE; data->state = STATE_COMPLETE;
k_sem_give(&data->wait);
} }
} else if (data->state == STATE_COMPLETE) { } else if (data->state == STATE_COMPLETE) {
config->fsmbm->FSMBMPF = (FSMBM_COMPLETE_EVENT | FSMBM_BLOCK_FINISH_EVENT); config->fsmbm->FSMBMPF = (FSMBM_COMPLETE_EVENT | FSMBM_BLOCK_FINISH_EVENT);
k_sem_give(&data->wait);
} }
} }
@ -112,14 +125,16 @@ static int i2c_kb1200_poll_write(const struct device *dev, struct i2c_msg msg, u
{ {
const struct i2c_kb1200_config *config = dev->config; const struct i2c_kb1200_config *config = dev->config;
struct i2c_kb1200_data *data = dev->data; struct i2c_kb1200_data *data = dev->data;
uint8_t send_bytes; uint32_t send_bytes;
int ret;
k_sem_reset(&data->wait);
if (msg.flags & I2C_MSG_STOP) { if (msg.flags & I2C_MSG_STOP) {
/* No CMD, No CNT, No PEC, with STOP*/ /* No CMD, No CNT, No PEC, with STOP*/
config->fsmbm->FSMBMFRT = ___STOP; config->fsmbm->FSMBMFRT = FRT_STOP;
} else { } else {
/* No CMD, No CNT, No PEC, no STOP*/ /* No CMD, No CNT, No PEC, no STOP*/
config->fsmbm->FSMBMFRT = ___NONE; config->fsmbm->FSMBMFRT = FRT_NONE;
} }
data->msg_len = msg.len; data->msg_len = msg.len;
data->msg_buf = msg.buf; data->msg_buf = msg.buf;
@ -135,7 +150,7 @@ static int i2c_kb1200_poll_write(const struct device *dev, struct i2c_msg msg, u
data->state = STATE_SENDING; data->state = STATE_SENDING;
config->fsmbm->FSMBMCMD = 0; config->fsmbm->FSMBMCMD = 0;
config->fsmbm->FSMBMADR = (addr & ~BIT(0)) | FSMBM_WRITE; config->fsmbm->FSMBMADR = (addr << 1) | FSMBM_WRITE;
config->fsmbm->FSMBMPF = (FSMBM_COMPLETE_EVENT | FSMBM_BLOCK_FINISH_EVENT); config->fsmbm->FSMBMPF = (FSMBM_COMPLETE_EVENT | FSMBM_BLOCK_FINISH_EVENT);
/* If data over bufferSize increase 1 to force continue transmit */ /* If data over bufferSize increase 1 to force continue transmit */
if (msg.len >= (FSMBM_BUFFER_SIZE + 1)) { if (msg.len >= (FSMBM_BUFFER_SIZE + 1)) {
@ -145,15 +160,19 @@ static int i2c_kb1200_poll_write(const struct device *dev, struct i2c_msg msg, u
} }
config->fsmbm->FSMBMIE = (FSMBM_COMPLETE_EVENT | FSMBM_BLOCK_FINISH_EVENT); config->fsmbm->FSMBMIE = (FSMBM_COMPLETE_EVENT | FSMBM_BLOCK_FINISH_EVENT);
config->fsmbm->FSMBMPRTC_P = FLEXIBLE_PROTOCOL; config->fsmbm->FSMBMPRTC_P = FLEXIBLE_PROTOCOL;
while (data->state != STATE_COMPLETE) {
; /* Wait until ISR or timeout */
ret = k_sem_take(&data->wait, K_MSEC(FSMBM_MAX_TIMEOUT));
if (ret == -EAGAIN) {
data->err_code |= FSMBM_SDA_TIMEOUT;
} }
data->state = STATE_IDLE; data->state = STATE_IDLE;
if (data->err_code != 0) { if (data->err_code) {
/* reset HW */ /* reset HW */
config->fsmbm->FSMBMCFG |= FSMBM_HW_RESET; config->fsmbm->FSMBMCFG |= FSMBM_HW_RESET;
return data->err_code; return data->err_code;
} }
return 0; return 0;
} }
@ -161,13 +180,18 @@ static int i2c_kb1200_poll_read(const struct device *dev, struct i2c_msg msg, ui
{ {
const struct i2c_kb1200_config *config = dev->config; const struct i2c_kb1200_config *config = dev->config;
struct i2c_kb1200_data *data = dev->data; struct i2c_kb1200_data *data = dev->data;
int ret;
k_sem_reset(&data->wait);
if ((msg.flags & I2C_MSG_RESTART) && !(msg.flags & I2C_MSG_STOP)) {
LOG_ERR("ENE i2c format not support.");
}
if (msg.flags & I2C_MSG_STOP) { if (msg.flags & I2C_MSG_STOP) {
/* No CMD, No CNT, No PEC, with STOP*/ /* No CMD, No CNT, No PEC, with STOP*/
config->fsmbm->FSMBMFRT = ___STOP; config->fsmbm->FSMBMFRT = FRT_STOP;
} else { } else {
/* No CMD, No CNT, No PEC, no STOP*/ /* No CMD, No CNT, No PEC, no STOP*/
config->fsmbm->FSMBMFRT = ___NONE; config->fsmbm->FSMBMFRT = FRT_NONE;
} }
data->msg_len = msg.len; data->msg_len = msg.len;
data->msg_buf = msg.buf; data->msg_buf = msg.buf;
@ -178,7 +202,7 @@ static int i2c_kb1200_poll_read(const struct device *dev, struct i2c_msg msg, ui
data->state = STATE_RECEIVING; data->state = STATE_RECEIVING;
config->fsmbm->FSMBMCMD = 0; config->fsmbm->FSMBMCMD = 0;
config->fsmbm->FSMBMADR = (addr & ~BIT(0)) | FSMBM_READ; config->fsmbm->FSMBMADR = (addr << 1) | FSMBM_READ;
config->fsmbm->FSMBMPF = (FSMBM_COMPLETE_EVENT | FSMBM_BLOCK_FINISH_EVENT); config->fsmbm->FSMBMPF = (FSMBM_COMPLETE_EVENT | FSMBM_BLOCK_FINISH_EVENT);
/* If data over bufferSize increase 1 to force continue receive */ /* If data over bufferSize increase 1 to force continue receive */
if (msg.len >= (FSMBM_BUFFER_SIZE + 1)) { if (msg.len >= (FSMBM_BUFFER_SIZE + 1)) {
@ -188,15 +212,20 @@ static int i2c_kb1200_poll_read(const struct device *dev, struct i2c_msg msg, ui
} }
config->fsmbm->FSMBMIE = (FSMBM_COMPLETE_EVENT | FSMBM_BLOCK_FINISH_EVENT); config->fsmbm->FSMBMIE = (FSMBM_COMPLETE_EVENT | FSMBM_BLOCK_FINISH_EVENT);
config->fsmbm->FSMBMPRTC_P = FLEXIBLE_PROTOCOL; config->fsmbm->FSMBMPRTC_P = FLEXIBLE_PROTOCOL;
while (data->state != STATE_COMPLETE) {
; /* Wait until ISR or timeout */
ret = k_sem_take(&data->wait, K_MSEC(FSMBM_MAX_TIMEOUT));
if (ret == -EAGAIN) {
data->err_code |= FSMBM_SDA_TIMEOUT;
} }
data->state = STATE_IDLE; data->state = STATE_IDLE;
if (data->err_code != 0) {
if (data->err_code) {
/* reset HW */ /* reset HW */
config->fsmbm->FSMBMCFG |= FSMBM_HW_RESET; config->fsmbm->FSMBMCFG |= FSMBM_HW_RESET;
return data->err_code; return data->err_code;
} }
return 0; return 0;
} }
@ -204,6 +233,7 @@ static int i2c_kb1200_poll_read(const struct device *dev, struct i2c_msg msg, ui
static int i2c_kb1200_configure(const struct device *dev, uint32_t dev_config) static int i2c_kb1200_configure(const struct device *dev, uint32_t dev_config)
{ {
const struct i2c_kb1200_config *config = dev->config; const struct i2c_kb1200_config *config = dev->config;
uint32_t speed;
if (!(dev_config & I2C_MODE_CONTROLLER)) { if (!(dev_config & I2C_MODE_CONTROLLER)) {
return -ENOTSUP; return -ENOTSUP;
@ -213,7 +243,7 @@ static int i2c_kb1200_configure(const struct device *dev, uint32_t dev_config)
return -ENOTSUP; return -ENOTSUP;
} }
uint32_t speed = I2C_SPEED_GET(dev_config); speed = I2C_SPEED_GET(dev_config);
switch (speed) { switch (speed) {
case I2C_SPEED_STANDARD: case I2C_SPEED_STANDARD:
@ -242,7 +272,7 @@ static int i2c_kb1200_get_config(const struct device *dev, uint32_t *dev_config)
const struct i2c_kb1200_config *config = dev->config; const struct i2c_kb1200_config *config = dev->config;
if ((config->fsmbm->FSMBMCFG & FSMBM_FUNCTION_ENABLE) == 0x00) { if ((config->fsmbm->FSMBMCFG & FSMBM_FUNCTION_ENABLE) == 0x00) {
printk("Cannot find i2c controller on 0x%p!\n", config->fsmbm); LOG_ERR("Cannot find i2c controller on 0x%p!", config->fsmbm);
return -EIO; return -EIO;
} }
@ -251,6 +281,8 @@ static int i2c_kb1200_get_config(const struct device *dev, uint32_t *dev_config)
*dev_config = I2C_MODE_CONTROLLER | I2C_SPEED_SET(I2C_SPEED_STANDARD); *dev_config = I2C_MODE_CONTROLLER | I2C_SPEED_SET(I2C_SPEED_STANDARD);
break; break;
case FSMBM_CLK_400K: case FSMBM_CLK_400K:
case FSMBM_CLK_500K:
case FSMBM_CLK_666K:
*dev_config = I2C_MODE_CONTROLLER | I2C_SPEED_SET(I2C_SPEED_FAST); *dev_config = I2C_MODE_CONTROLLER | I2C_SPEED_SET(I2C_SPEED_FAST);
break; break;
case FSMBM_CLK_1M: case FSMBM_CLK_1M:
@ -267,27 +299,27 @@ static int i2c_kb1200_transfer(const struct device *dev, struct i2c_msg *msgs, u
uint16_t addr) uint16_t addr)
{ {
struct i2c_kb1200_data *data = dev->data; struct i2c_kb1200_data *data = dev->data;
int ret; int ret = 0;
/* get the mutex */ /* lock */
k_sem_take(&data->mutex, K_FOREVER); k_sem_take(&data->lock, K_FOREVER);
for (int i = 0U; i < num_msgs; i++) { for (int i = 0U; i < num_msgs; i++) {
if ((msgs[i].flags & I2C_MSG_RW_MASK) == I2C_MSG_WRITE) { if ((msgs[i].flags & I2C_MSG_RW_MASK) == I2C_MSG_WRITE) {
ret = i2c_kb1200_poll_write(dev, msgs[i], addr); ret = i2c_kb1200_poll_write(dev, msgs[i], addr);
if (ret) { if (ret) {
printk("%s Write error: 0x%X\n", dev->name, ret); ret = -EIO;
break; break;
} }
} else { } else {
ret = i2c_kb1200_poll_read(dev, msgs[i], addr); ret = i2c_kb1200_poll_read(dev, msgs[i], addr);
if (ret) { if (ret) {
printk("%s Read error: 0x%X\n", dev->name, ret); ret = -EIO;
break; break;
} }
} }
} }
/* release the mutex */ /* release the lock */
k_sem_give(&data->mutex); k_sem_give(&data->lock);
return ret; return ret;
} }
@ -332,14 +364,23 @@ static int i2c_kb1200_init(const struct device *dev)
int ret; int ret;
const struct i2c_kb1200_config *config = dev->config; const struct i2c_kb1200_config *config = dev->config;
struct i2c_kb1200_data *data = dev->data; struct i2c_kb1200_data *data = dev->data;
uint32_t bitrate_cfg;
ret = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT); ret = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT);
if (ret != 0) { if (ret != 0) {
return ret; return ret;
} }
/* init mutex */ bitrate_cfg = i2c_map_dt_bitrate(config->clock_freq);
k_sem_init(&data->mutex, 1, 1); if (!bitrate_cfg) {
return -EINVAL;
}
i2c_kb1200_configure(dev, bitrate_cfg | I2C_MODE_CONTROLLER);
k_sem_init(&data->wait, 0, 1);
/* init lock */
k_sem_init(&data->lock, 1, 1);
kb1200_fsmbm_irq_init(); kb1200_fsmbm_irq_init();
return 0; return 0;
@ -350,10 +391,11 @@ static int i2c_kb1200_init(const struct device *dev)
static struct i2c_kb1200_data i2c_kb1200_data_##inst; \ static struct i2c_kb1200_data i2c_kb1200_data_##inst; \
static const struct i2c_kb1200_config i2c_kb1200_config_##inst = { \ static const struct i2c_kb1200_config i2c_kb1200_config_##inst = { \
.fsmbm = (struct fsmbm_regs *)DT_INST_REG_ADDR(inst), \ .fsmbm = (struct fsmbm_regs *)DT_INST_REG_ADDR(inst), \
.clock_freq = DT_INST_PROP(inst, clock_frequency), \
.pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(inst), \ .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(inst), \
}; \ }; \
I2C_DEVICE_DT_INST_DEFINE(inst, &i2c_kb1200_init, NULL, &i2c_kb1200_data_##inst, \ I2C_DEVICE_DT_INST_DEFINE(inst, &i2c_kb1200_init, NULL, &i2c_kb1200_data_##inst, \
&i2c_kb1200_config_##inst, PRE_KERNEL_1, \ &i2c_kb1200_config_##inst, PRE_KERNEL_1, \
CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &i2c_kb1200_api); CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &i2c_kb1200_api);
DT_INST_FOREACH_STATUS_OKAY(I2C_KB1200_DEVICE) DT_INST_FOREACH_STATUS_OKAY(I2C_KB1200_DEVICE)

View file

@ -58,28 +58,27 @@ struct fsmbm_regs {
#define FSMBM_SMBUS_BUSY 0x1A #define FSMBM_SMBUS_BUSY 0x1A
#define FSMBM_STOP_FAIL 0x1E #define FSMBM_STOP_FAIL 0x1E
#define FSMBM_PEC_ERROR 0x1F #define FSMBM_PEC_ERROR 0x1F
/* Packet Form */ #define FSMBM_SDA_TIMEOUT 0x80
#define ___NONE 0x00 #define FSMBM_MAX_TIMEOUT 200 /* Unit: ms */
#define ___STOP 0x01
#define __PEC_ 0x02 /* Packet Form */
#define __PEC_STOP 0x03 #define FRT_NONE 0x00
#define _CNT__ 0x04 #define FRT_STOP 0x01
#define _CNT__STOP 0x05 #define FRT_PEC 0x02
#define _CNT_PEC_ 0x06 #define FRT_CNT 0x04
#define _CNT_PEC_STOP 0x07 #define FRT_CMD 0x08
#define CMD___ 0x08 #define FRT_PEC_STOP (FRT_PEC | FRT_STOP)
#define CMD___STOP 0x09 #define FRT_CNT_STOP (FRT_CNT | FRT_STOP)
#define CMD__PEC_ 0x0A #define FRT_CNT_PEC (FRT_CNT | FRT_PEC)
#define CMD__PEC_STOP 0x0B #define FRT_CNT_PEC_STOP (FRT_CNT | FRT_PEC | FRT_STOP)
#define CMD_CNT__ 0x0C #define FRT_CMD_STOP (FRT_CMD | FRT_STOP)
#define CMD_CNT__STOP 0x0D #define FRT_CMD_PEC (FRT_CMD | FRT_PEC)
#define CMD_CNT_PEC_ 0x0E #define FRT_CMD_PEC_STOP (FRT_CMD | FRT_PEC | FRT_STOP)
#define CMD_CNT_PEC_STOP 0x0F #define FRT_CMD_CNT (FRT_CMD | FRT_CNT)
#define FRT_CMD_CNT_STOP (FRT_CMD | FRT_CNT | FRT_STOP)
#define FRT_CMD_CNT_PEC (FRT_CMD | FRT_CNT | FRT_PEC)
#define FRT_CMD_CNT_PEC_STOP (FRT_CMD | FRT_CNT | FRT_PEC | FRT_STOP)
#define FLEXIBLE_CMD 0x08
#define FLEXIBLE_CNT 0x04
#define FLEXIBLE_PEC 0x02
#define FLEXIBLE_STOP 0x01
/* HW */ /* HW */
#define FSMBM_BUFFER_SIZE 0x20 #define FSMBM_BUFFER_SIZE 0x20
#define FSMBM_MAXCNT 0xFF #define FSMBM_MAXCNT 0xFF
@ -109,6 +108,7 @@ struct fsmbm_regs {
#define FSMBM_CLK_10K 0x6363 #define FSMBM_CLK_10K 0x6363
/* Other(non 50% Duty Cycle) */ /* Other(non 50% Duty Cycle) */
#define FSMBM_CLK_400K 0x0102 #define FSMBM_CLK_400K 0x0102
#define FSMBM_CLK_666K 0x0001
#define FSMBM_COMPLETE_EVENT 0x01 #define FSMBM_COMPLETE_EVENT 0x01
#define FSMBM_HOST_NOTIFY_EVENT 0x02 #define FSMBM_HOST_NOTIFY_EVENT 0x02