drivers: i2c: cc13xx_cc26xx: Add support for I2C_MSG_RESTART
Add support for the I2C_MSG_RESTART flag to be able to use a repeated start in between chained transactions. The driver now uses the stop/restart flags set in the i2c_msg, instead of starting and stopping for each transaction in the chain. Signed-off-by: Lorenz Clijnen <github@lorc.be>
This commit is contained in:
parent
0f64fe4cf8
commit
31855964f1
1 changed files with 49 additions and 113 deletions
|
@ -40,153 +40,82 @@ struct i2c_cc13xx_cc26xx_config {
|
||||||
const struct pinctrl_dev_config *pcfg;
|
const struct pinctrl_dev_config *pcfg;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int i2c_cc13xx_cc26xx_transmit(const struct device *dev,
|
static int i2c_cc13xx_cc26xx_transmit(const struct device *dev, const struct i2c_msg *msg,
|
||||||
const uint8_t *buf,
|
const uint8_t addr)
|
||||||
uint32_t len, uint16_t addr)
|
|
||||||
{
|
{
|
||||||
const struct i2c_cc13xx_cc26xx_config *config = dev->config;
|
const struct i2c_cc13xx_cc26xx_config *config = dev->config;
|
||||||
const uint32_t base = config->base;
|
const uint32_t base = config->base;
|
||||||
struct i2c_cc13xx_cc26xx_data *data = dev->data;
|
struct i2c_cc13xx_cc26xx_data *data = dev->data;
|
||||||
|
|
||||||
/* Sending address without data is not supported */
|
|
||||||
if (len == 0) {
|
|
||||||
return -EIO;
|
|
||||||
}
|
|
||||||
|
|
||||||
I2CMasterSlaveAddrSet(base, addr, false);
|
I2CMasterSlaveAddrSet(base, addr, false);
|
||||||
|
|
||||||
/* The following assumes a single master. Use I2CMasterBusBusy() if
|
for (int i = 0; i < msg->len; i++) {
|
||||||
* wanting to implement multiple master support.
|
uint32_t command = I2C_MCTRL_RUN;
|
||||||
*/
|
|
||||||
|
|
||||||
/* Single transmission */
|
if (i == 0 && msg->flags & I2C_MSG_RESTART) {
|
||||||
if (len == 1) {
|
command |= I2C_MCTRL_START;
|
||||||
I2CMasterDataPut(base, *buf);
|
}
|
||||||
|
|
||||||
I2CMasterControl(base, I2C_MASTER_CMD_SINGLE_SEND);
|
if (i == msg->len - 1 && msg->flags & I2C_MSG_STOP) {
|
||||||
|
command |= I2C_MCTRL_STOP;
|
||||||
k_sem_take(&data->complete, K_FOREVER);
|
}
|
||||||
|
|
||||||
return data->error == I2C_MASTER_ERR_NONE ? 0 : -EIO;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Burst transmission */
|
|
||||||
I2CMasterDataPut(base, buf[0]);
|
|
||||||
|
|
||||||
I2CMasterControl(base, I2C_MASTER_CMD_BURST_SEND_START);
|
|
||||||
|
|
||||||
k_sem_take(&data->complete, K_FOREVER);
|
|
||||||
|
|
||||||
if (data->error != I2C_MASTER_ERR_NONE) {
|
|
||||||
goto send_error_stop;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 1; i < len - 1; i++) {
|
|
||||||
I2CMasterDataPut(base, buf[i]);
|
|
||||||
|
|
||||||
I2CMasterControl(base, I2C_MASTER_CMD_BURST_SEND_CONT);
|
|
||||||
|
|
||||||
|
I2CMasterDataPut(base, msg->buf[i]);
|
||||||
|
I2CMasterControl(base, command);
|
||||||
k_sem_take(&data->complete, K_FOREVER);
|
k_sem_take(&data->complete, K_FOREVER);
|
||||||
|
|
||||||
if (data->error != I2C_MASTER_ERR_NONE) {
|
if (data->error != I2C_MASTER_ERR_NONE) {
|
||||||
goto send_error_stop;
|
if ((command & I2C_MCTRL_STOP) == 0) {
|
||||||
|
I2CMasterControl(base, I2C_MCTRL_STOP);
|
||||||
|
}
|
||||||
|
return -EIO;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
I2CMasterDataPut(base, buf[len - 1]);
|
|
||||||
|
|
||||||
I2CMasterControl(base, I2C_MASTER_CMD_BURST_SEND_FINISH);
|
|
||||||
|
|
||||||
k_sem_take(&data->complete, K_FOREVER);
|
|
||||||
|
|
||||||
if (data->error != I2C_MASTER_ERR_NONE) {
|
|
||||||
return -EIO;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
send_error_stop:
|
|
||||||
I2CMasterControl(base, I2C_MASTER_CMD_BURST_SEND_ERROR_STOP);
|
|
||||||
return -EIO;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int i2c_cc13xx_cc26xx_receive(const struct device *dev, uint8_t *buf,
|
static int i2c_cc13xx_cc26xx_receive(const struct device *dev, const struct i2c_msg *msg,
|
||||||
uint32_t len,
|
const uint8_t addr)
|
||||||
uint16_t addr)
|
|
||||||
{
|
{
|
||||||
|
struct i2c_cc13xx_cc26xx_data *data = dev->data;
|
||||||
const struct i2c_cc13xx_cc26xx_config *config = dev->config;
|
const struct i2c_cc13xx_cc26xx_config *config = dev->config;
|
||||||
const uint32_t base = config->base;
|
const uint32_t base = config->base;
|
||||||
struct i2c_cc13xx_cc26xx_data *data = dev->data;
|
|
||||||
|
|
||||||
/* Sending address without data is not supported */
|
|
||||||
if (len == 0) {
|
|
||||||
return -EIO;
|
|
||||||
}
|
|
||||||
|
|
||||||
I2CMasterSlaveAddrSet(base, addr, true);
|
I2CMasterSlaveAddrSet(base, addr, true);
|
||||||
|
|
||||||
/* The following assumes a single master. Use I2CMasterBusBusy() if
|
for (int i = 0; i < msg->len; i++) {
|
||||||
* wanting to implement multiple master support.
|
uint32_t command = I2C_MCTRL_RUN;
|
||||||
*/
|
|
||||||
|
|
||||||
/* Single receive */
|
if (i == 0 && msg->flags & I2C_MSG_RESTART) {
|
||||||
if (len == 1) {
|
command |= I2C_MCTRL_START;
|
||||||
I2CMasterControl(base, I2C_MASTER_CMD_SINGLE_RECEIVE);
|
}
|
||||||
|
|
||||||
|
if (i == msg->len - 1 && msg->flags & I2C_MSG_STOP) {
|
||||||
|
command |= I2C_MCTRL_STOP;
|
||||||
|
} else if (i < msg->len - 1) {
|
||||||
|
command |= I2C_MCTRL_ACK;
|
||||||
|
}
|
||||||
|
|
||||||
|
I2CMasterControl(base, command);
|
||||||
|
|
||||||
k_sem_take(&data->complete, K_FOREVER);
|
k_sem_take(&data->complete, K_FOREVER);
|
||||||
|
|
||||||
if (data->error != I2C_MASTER_ERR_NONE) {
|
if (data->error != I2C_MASTER_ERR_NONE) {
|
||||||
|
if ((command & I2C_MCTRL_STOP) == 0) {
|
||||||
|
I2CMasterControl(base, I2C_MCTRL_STOP);
|
||||||
|
}
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
*buf = I2CMasterDataGet(base);
|
msg->buf[i] = I2CMasterDataGet(base);
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Burst receive */
|
|
||||||
I2CMasterControl(base, I2C_MASTER_CMD_BURST_RECEIVE_START);
|
|
||||||
|
|
||||||
k_sem_take(&data->complete, K_FOREVER);
|
|
||||||
|
|
||||||
if (data->error != I2C_MASTER_ERR_NONE) {
|
|
||||||
goto recv_error_stop;
|
|
||||||
}
|
|
||||||
|
|
||||||
buf[0] = I2CMasterDataGet(base);
|
|
||||||
|
|
||||||
for (int i = 1; i < len - 1; i++) {
|
|
||||||
I2CMasterControl(base, I2C_MASTER_CMD_BURST_RECEIVE_CONT);
|
|
||||||
|
|
||||||
k_sem_take(&data->complete, K_FOREVER);
|
|
||||||
|
|
||||||
if (data->error != I2C_MASTER_ERR_NONE) {
|
|
||||||
goto recv_error_stop;
|
|
||||||
}
|
|
||||||
|
|
||||||
buf[i] = I2CMasterDataGet(base);
|
|
||||||
}
|
|
||||||
|
|
||||||
I2CMasterControl(base, I2C_MASTER_CMD_BURST_RECEIVE_FINISH);
|
|
||||||
|
|
||||||
k_sem_take(&data->complete, K_FOREVER);
|
|
||||||
|
|
||||||
if (data->error != I2C_MASTER_ERR_NONE) {
|
|
||||||
return -EIO;
|
|
||||||
}
|
|
||||||
|
|
||||||
buf[len - 1] = I2CMasterDataGet(base);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
recv_error_stop:
|
|
||||||
I2CMasterControl(base, I2C_MASTER_CMD_BURST_RECEIVE_ERROR_STOP);
|
|
||||||
return -EIO;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int i2c_cc13xx_cc26xx_transfer(const struct device *dev,
|
static int i2c_cc13xx_cc26xx_transfer(const struct device *dev, struct i2c_msg *msgs,
|
||||||
struct i2c_msg *msgs,
|
const uint8_t num_msgs, const uint16_t addr)
|
||||||
uint8_t num_msgs, uint16_t addr)
|
|
||||||
{
|
{
|
||||||
struct i2c_cc13xx_cc26xx_data *data = dev->data;
|
struct i2c_cc13xx_cc26xx_data *data = dev->data;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
@ -195,6 +124,9 @@ static int i2c_cc13xx_cc26xx_transfer(const struct device *dev,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Always a start condition in the first message */
|
||||||
|
msgs[0].flags |= I2C_MSG_RESTART;
|
||||||
|
|
||||||
k_sem_take(&data->lock, K_FOREVER);
|
k_sem_take(&data->lock, K_FOREVER);
|
||||||
|
|
||||||
pm_policy_state_lock_get(PM_STATE_STANDBY, PM_ALL_SUBSTATES);
|
pm_policy_state_lock_get(PM_STATE_STANDBY, PM_ALL_SUBSTATES);
|
||||||
|
@ -206,12 +138,16 @@ static int i2c_cc13xx_cc26xx_transfer(const struct device *dev,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Sending address without data is not supported */
|
||||||
|
if (msgs[i].len == 0) {
|
||||||
|
ret = -EIO;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if ((msgs[i].flags & I2C_MSG_RW_MASK) == I2C_MSG_WRITE) {
|
if ((msgs[i].flags & I2C_MSG_RW_MASK) == I2C_MSG_WRITE) {
|
||||||
ret = i2c_cc13xx_cc26xx_transmit(dev, msgs[i].buf,
|
ret = i2c_cc13xx_cc26xx_transmit(dev, &msgs[i], addr);
|
||||||
msgs[i].len, addr);
|
|
||||||
} else {
|
} else {
|
||||||
ret = i2c_cc13xx_cc26xx_receive(dev, msgs[i].buf,
|
ret = i2c_cc13xx_cc26xx_receive(dev, &msgs[i], addr);
|
||||||
msgs[i].len, addr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ret) {
|
if (ret) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue