i2c: Remove all polling based functions
Now that i2c is fully synchronous on top of an interrupt based implementation, polling mode can be removed. Applying the API change into the existing drivers. Change-Id: I05d2a6089743b6b69f7c9da6312057134578e2f7 Signed-off-by: Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>
This commit is contained in:
parent
7770c3ed9d
commit
ce31c524f2
5 changed files with 33 additions and 346 deletions
|
@ -174,29 +174,24 @@ static inline void _i2c_dw_transfer_complete(struct device *dev)
|
|||
{
|
||||
struct i2c_dw_rom_config const * const rom = dev->config->config_info;
|
||||
struct i2c_dw_dev_config * const dw = dev->driver_data;
|
||||
uint32_t cb_type = 0;
|
||||
bool done = false;
|
||||
uint32_t value;
|
||||
|
||||
volatile struct i2c_dw_registers * const regs =
|
||||
(struct i2c_dw_registers *)rom->base_address;
|
||||
|
||||
if (dw->state == I2C_DW_CMD_ERROR) {
|
||||
cb_type = I2C_CB_ERROR;
|
||||
} else if (dw->tx_buffer && !dw->tx_len) {
|
||||
cb_type = I2C_CB_WRITE;
|
||||
} else if (dw->rx_buffer && !dw->rx_len) {
|
||||
cb_type = I2C_CB_READ;
|
||||
if ((dw->state == I2C_DW_CMD_ERROR) ||
|
||||
(!dw->tx_len && !dw->rx_len) ||
|
||||
(dw->tx_buffer && !dw->tx_len && !dw->rx_buffer) ||
|
||||
(dw->rx_buffer && !dw->rx_len && !dw->tx_buffer)) {
|
||||
done = true;
|
||||
}
|
||||
|
||||
if (cb_type) {
|
||||
if (done) {
|
||||
regs->ic_intr_mask.raw = DW_DISABLE_ALL_I2C_INT;
|
||||
dw->state = I2C_DW_STATE_READY;
|
||||
value = regs->ic_clr_intr;
|
||||
|
||||
synchronous_call_complete(&dw->sync);
|
||||
if (dw->cb) {
|
||||
dw->cb(dev, cb_type);
|
||||
}
|
||||
}
|
||||
|
||||
dw->state &= ~I2C_DW_BUSY;
|
||||
|
@ -397,7 +392,7 @@ static int _i2c_dw_transfer_init(struct device *dev,
|
|||
struct i2c_dw_rom_config const * const rom = dev->config->config_info;
|
||||
struct i2c_dw_dev_config * const dw = dev->driver_data;
|
||||
uint32_t value = 0;
|
||||
int ret;
|
||||
int ret = DEV_OK;
|
||||
|
||||
volatile struct i2c_dw_registers * const regs =
|
||||
(struct i2c_dw_registers *)rom->base_address;
|
||||
|
@ -480,122 +475,11 @@ static int i2c_dw_transfer(struct device *dev,
|
|||
regs->ic_enable.bits.enable = 1;
|
||||
|
||||
synchronous_call_wait(&dw->sync);
|
||||
|
||||
return DEV_OK;
|
||||
}
|
||||
|
||||
#define POLLING_TIMEOUT (sys_clock_ticks_per_sec / 10)
|
||||
static int i2c_dw_poll_transfer(struct device *dev,
|
||||
uint8_t *write_buf, uint32_t write_len,
|
||||
uint8_t *read_buf, uint32_t read_len,
|
||||
uint16_t slave_address, uint32_t flags)
|
||||
{
|
||||
struct i2c_dw_rom_config const * const rom = dev->config->config_info;
|
||||
struct i2c_dw_dev_config * const dw = dev->driver_data;
|
||||
uint32_t value = 0;
|
||||
uint32_t start_time;
|
||||
int ret = DEV_OK;
|
||||
|
||||
volatile struct i2c_dw_registers * const regs =
|
||||
(struct i2c_dw_registers *)rom->base_address;
|
||||
|
||||
if (!regs->ic_con.bits.master_mode) {
|
||||
/* Only acting as master is supported */
|
||||
return DEV_INVALID_OP;
|
||||
}
|
||||
|
||||
/* Wait for bus idle */
|
||||
start_time = sys_tick_get_32();
|
||||
while (regs->ic_status.bits.activity) {
|
||||
if ((sys_tick_get_32() - start_time) > POLLING_TIMEOUT) {
|
||||
return DEV_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
ret = _i2c_dw_transfer_init(dev, write_buf, write_len,
|
||||
read_buf, read_len, slave_address);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Enable controller */
|
||||
regs->ic_enable.bits.enable = 1;
|
||||
|
||||
if (dw->tx_len == 0) {
|
||||
goto do_receive;
|
||||
}
|
||||
|
||||
/* Transmit */
|
||||
while (dw->tx_len > 0) {
|
||||
/* Wait for space in TX FIFO */
|
||||
start_time = sys_tick_get_32();
|
||||
while (!regs->ic_status.bits.tfnf) {
|
||||
if ((sys_tick_get_32() - start_time) > POLLING_TIMEOUT) {
|
||||
if (dw->state == I2C_DW_CMD_ERROR) {
|
||||
ret = DEV_FAIL;
|
||||
goto finish;
|
||||
}
|
||||
}
|
||||
|
||||
_i2c_dw_data_send(dev);
|
||||
}
|
||||
|
||||
/* Wait for TX FIFO empty to be sure everything is sent. */
|
||||
start_time = sys_tick_get_32();
|
||||
while (!regs->ic_status.bits.tfe) {
|
||||
if ((sys_tick_get_32() - start_time) > POLLING_TIMEOUT) {
|
||||
ret = DEV_FAIL;
|
||||
goto finish;
|
||||
}
|
||||
}
|
||||
|
||||
do_receive:
|
||||
/* Finalize TX when there is nothing more to send as
|
||||
* the data send function has code to deal with the end of
|
||||
* TX phase.
|
||||
*/
|
||||
_i2c_dw_data_send(dev);
|
||||
|
||||
/* Finish transfer when there is nothing to receive */
|
||||
if (dw->rx_len == 0) {
|
||||
goto stop_det;
|
||||
}
|
||||
|
||||
while (dw->rx_len > 0) {
|
||||
/* Wait for data in RX FIFO*/
|
||||
start_time = sys_tick_get_32();
|
||||
while (!regs->ic_status.bits.rfne) {
|
||||
if ((sys_tick_get_32() - start_time) > POLLING_TIMEOUT) {
|
||||
ret = DEV_FAIL;
|
||||
goto finish;
|
||||
}
|
||||
}
|
||||
|
||||
_i2c_dw_data_read(dev);
|
||||
}
|
||||
|
||||
stop_det:
|
||||
/* Wait for transfer to complete */
|
||||
start_time = sys_tick_get_32();
|
||||
while (!regs->ic_raw_intr_stat.bits.stop_det) {
|
||||
if ((sys_tick_get_32() - start_time) > POLLING_TIMEOUT) {
|
||||
ret = DEV_FAIL;
|
||||
goto finish;
|
||||
}
|
||||
}
|
||||
value = regs->ic_clr_stop_det;
|
||||
|
||||
/* Wait for bus idle */
|
||||
start_time = sys_tick_get_32();
|
||||
while (regs->ic_status.bits.activity) {
|
||||
if ((sys_tick_get_32() - start_time) > POLLING_TIMEOUT) {
|
||||
ret = DEV_FAIL;
|
||||
goto finish;
|
||||
}
|
||||
}
|
||||
|
||||
finish:
|
||||
/* Disable controller when done */
|
||||
regs->ic_enable.bits.enable = 0;
|
||||
dw->state = I2C_DW_STATE_READY;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -706,15 +590,6 @@ static int i2c_dw_runtime_configure(struct device *dev, uint32_t config)
|
|||
return rc;
|
||||
}
|
||||
|
||||
static int i2c_dw_set_callback(struct device *dev, i2c_callback cb)
|
||||
{
|
||||
struct i2c_dw_dev_config * const dw = dev->driver_data;
|
||||
|
||||
dw->cb = cb;
|
||||
|
||||
return DEV_OK;
|
||||
}
|
||||
|
||||
static int i2c_dw_suspend(struct device *dev)
|
||||
{
|
||||
DBG("I2C: suspend called - function not yet implemented\n");
|
||||
|
@ -733,11 +608,9 @@ static int i2c_dw_resume(struct device *dev)
|
|||
|
||||
static struct i2c_driver_api funcs = {
|
||||
.configure = i2c_dw_runtime_configure,
|
||||
.set_callback = i2c_dw_set_callback,
|
||||
.transfer = i2c_dw_transfer,
|
||||
.suspend = i2c_dw_suspend,
|
||||
.resume = i2c_dw_resume,
|
||||
.poll_transfer = i2c_dw_poll_transfer,
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -120,12 +120,6 @@ struct i2c_dw_dev_config {
|
|||
bool support_hs_mode;
|
||||
uint16_t hcnt;
|
||||
uint16_t lcnt;
|
||||
|
||||
i2c_callback cb;
|
||||
};
|
||||
|
||||
void i2c_dw_isr(struct device *port);
|
||||
|
||||
extern int i2c_dw_initialize(struct device *port);
|
||||
|
||||
#endif /* __DRIVERS_I2C_DW_H */
|
||||
|
|
|
@ -246,6 +246,8 @@ static inline void _i2c_qse_ss_transfer_complete(struct device *dev)
|
|||
_i2c_qse_ss_reg_write(dev, REG_INTR_MASK, IC_INTR_MASK_ALL);
|
||||
_i2c_qse_ss_reg_write(dev, REG_INTR_CLR, IC_INTR_CLR_ALL);
|
||||
|
||||
synchronous_call_complete(&dw->sync);
|
||||
|
||||
dw->state &= ~I2C_QSE_SS_BUSY;
|
||||
}
|
||||
|
||||
|
@ -414,7 +416,7 @@ static int i2c_qse_ss_intr_transfer(struct device *dev,
|
|||
uint8_t *read_buf, uint32_t read_len,
|
||||
uint16_t slave_address, uint32_t flags)
|
||||
{
|
||||
int ret;
|
||||
int ret = DEV_OK;
|
||||
|
||||
/* First step, check if there is current activity */
|
||||
if (_i2c_qse_ss_is_busy(dev)) {
|
||||
|
@ -434,124 +436,12 @@ static int i2c_qse_ss_intr_transfer(struct device *dev,
|
|||
/* Enable controller */
|
||||
_i2c_qse_ss_reg_write_or(dev, REG_CON, IC_CON_ENABLE);
|
||||
|
||||
return DEV_OK;
|
||||
}
|
||||
|
||||
#define POLLING_TIMEOUT (sys_clock_ticks_per_sec / 10)
|
||||
static int i2c_qse_ss_poll_transfer(struct device *dev,
|
||||
uint8_t *write_buf, uint32_t write_len,
|
||||
uint8_t *read_buf, uint32_t read_len,
|
||||
uint16_t slave_address, uint32_t flags)
|
||||
{
|
||||
struct i2c_qse_ss_dev_config * const dw = dev->driver_data;
|
||||
uint32_t start_time;
|
||||
int ret = DEV_OK;
|
||||
|
||||
/* Wait for bus idle */
|
||||
start_time = sys_tick_get_32();
|
||||
while (_i2c_qse_ss_is_busy(dev)) {
|
||||
if ((sys_tick_get_32() - start_time) > POLLING_TIMEOUT) {
|
||||
return DEV_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
ret = _i2c_qse_ss_transfer_init(dev, write_buf, write_len,
|
||||
read_buf, read_len, slave_address, 0);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Enable controller */
|
||||
_i2c_qse_ss_reg_write_or(dev, REG_CON, IC_CON_ENABLE);
|
||||
|
||||
if (dw->tx_len == 0) {
|
||||
goto do_receive;
|
||||
}
|
||||
|
||||
/* Transmit */
|
||||
while (dw->tx_len > 0) {
|
||||
/* Wait for space in TX FIFO */
|
||||
start_time = sys_tick_get_32();
|
||||
while (!_i2c_qse_ss_is_tfnf(dev)) {
|
||||
if ((sys_tick_get_32() - start_time)
|
||||
> POLLING_TIMEOUT) {
|
||||
synchronous_call_wait(&dw->sync);
|
||||
if (dw->state == I2C_QSE_SS_CMD_ERROR) {
|
||||
ret = DEV_FAIL;
|
||||
goto finish;
|
||||
}
|
||||
}
|
||||
|
||||
ret = _i2c_qse_ss_data_send(dev);
|
||||
if (ret != DEV_OK) {
|
||||
goto finish;
|
||||
}
|
||||
}
|
||||
|
||||
/* Wait for TX FIFO empty to be sure everything is sent. */
|
||||
start_time = sys_tick_get_32();
|
||||
while (!_i2c_qse_ss_is_tfe(dev)) {
|
||||
if ((sys_tick_get_32() - start_time) > POLLING_TIMEOUT) {
|
||||
ret = DEV_FAIL;
|
||||
goto finish;
|
||||
}
|
||||
}
|
||||
|
||||
dw->state &= ~I2C_QSE_SS_CMD_SEND;
|
||||
|
||||
do_receive:
|
||||
/* Finalize TX when there is nothing more to send as
|
||||
* the data send function has code to deal with the end of
|
||||
* TX phase.
|
||||
*/
|
||||
_i2c_qse_ss_data_send(dev);
|
||||
|
||||
/* Finish transfer when there is nothing to receive */
|
||||
if (dw->rx_len == 0) {
|
||||
goto stop_det;
|
||||
}
|
||||
|
||||
while (dw->rx_len > 0) {
|
||||
/* Wait for data in RX FIFO*/
|
||||
start_time = sys_tick_get_32();
|
||||
while (!_i2c_qse_ss_is_rfne(dev)) {
|
||||
if ((sys_tick_get_32() - start_time)
|
||||
> POLLING_TIMEOUT) {
|
||||
ret = DEV_FAIL;
|
||||
goto finish;
|
||||
}
|
||||
}
|
||||
|
||||
_i2c_qse_ss_data_read(dev);
|
||||
}
|
||||
|
||||
dw->state &= ~I2C_QSE_SS_CMD_RECV;
|
||||
|
||||
stop_det:
|
||||
/* Wait for transfer to complete */
|
||||
start_time = sys_tick_get_32();
|
||||
while (!_i2c_qse_ss_check_irq(dev, IC_INTR_STOP_DET)) {
|
||||
if ((sys_tick_get_32() - start_time) > POLLING_TIMEOUT) {
|
||||
ret = DEV_FAIL;
|
||||
goto finish;
|
||||
}
|
||||
}
|
||||
_i2c_qse_ss_reg_write(dev, REG_INTR_CLR, IC_INTR_STOP_DET);
|
||||
|
||||
/* Wait for bus idle */
|
||||
start_time = sys_tick_get_32();
|
||||
while (_i2c_qse_ss_is_busy(dev)) {
|
||||
if ((sys_tick_get_32() - start_time) > POLLING_TIMEOUT) {
|
||||
ret = DEV_FAIL;
|
||||
goto finish;
|
||||
}
|
||||
}
|
||||
|
||||
finish:
|
||||
/* Disable controller when done */
|
||||
_i2c_qse_ss_reg_write_and(dev, REG_CON, ~(IC_CON_ENABLE));
|
||||
|
||||
_i2c_qse_ss_transfer_complete(dev);
|
||||
|
||||
dw->state = I2C_QSE_SS_STATE_READY;
|
||||
dw->state = I2C_DW_STATE_READY;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -661,7 +551,6 @@ static int i2c_qse_ss_set_callback(struct device *dev, i2c_callback cb)
|
|||
static struct i2c_driver_api ss_funcs = {
|
||||
.configure = i2c_qse_ss_runtime_configure,
|
||||
.transfer = i2c_qse_ss_intr_transfer,
|
||||
.poll_transfer = i2c_qse_ss_poll_transfer,
|
||||
.suspend = i2c_qse_ss_suspend,
|
||||
.resume = i2c_qse_ss_resume,
|
||||
.set_callback = i2c_qse_ss_set_callback,
|
||||
|
@ -681,6 +570,8 @@ int i2c_qse_ss_initialize(struct device *dev)
|
|||
/* Enable clock for controller so we can talk to it */
|
||||
_i2c_qse_ss_reg_write_or(dev, REG_CON, IC_CON_CLK_ENA);
|
||||
|
||||
synchronous_call_init(&dev->sync);
|
||||
|
||||
if (i2c_qse_ss_runtime_configure(dev, dw->app_config.raw) != DEV_OK) {
|
||||
DBG("I2C_SS: Cannot set default configuration 0x%x\n",
|
||||
dev->app_config.raw);
|
||||
|
|
|
@ -71,6 +71,7 @@ struct i2c_qse_ss_rom_config {
|
|||
};
|
||||
|
||||
struct i2c_qse_ss_dev_config {
|
||||
device_sync_call_t sync;
|
||||
union dev_config app_config;
|
||||
|
||||
volatile uint8_t state; /* last direction of transfer */
|
||||
|
|
|
@ -63,13 +63,8 @@ enum i2c_cb_type {
|
|||
I2C_CB_ERROR = 3,
|
||||
};
|
||||
|
||||
typedef void (*i2c_callback)(struct device *dev,
|
||||
uint32_t cb_type);
|
||||
|
||||
typedef int (*i2c_api_configure_t)(struct device *dev,
|
||||
uint32_t dev_config);
|
||||
typedef int (*i2c_api_set_callback_t)(struct device *dev,
|
||||
i2c_callback cb);
|
||||
typedef int (*i2c_api_full_io_t)(struct device *dev,
|
||||
uint8_t *tx_buf,
|
||||
uint32_t tx_len,
|
||||
|
@ -82,15 +77,14 @@ typedef int (*i2c_api_resume_t)(struct device *dev);
|
|||
|
||||
struct i2c_driver_api {
|
||||
i2c_api_configure_t configure;
|
||||
i2c_api_set_callback_t set_callback;
|
||||
i2c_api_full_io_t transfer;
|
||||
i2c_api_full_io_t poll_transfer;
|
||||
i2c_api_suspend_t suspend;
|
||||
i2c_api_resume_t resume;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Configure a host controllers operation
|
||||
*
|
||||
* @param dev Pointer to the device structure for the driver instance
|
||||
* @param dev_config Bit-packed 32-bit value to the device runtime configuration
|
||||
* for the I2C controller.
|
||||
|
@ -106,22 +100,10 @@ static inline int i2c_configure(struct device *dev, uint32_t dev_config)
|
|||
}
|
||||
|
||||
/**
|
||||
* @brief Set an application callback
|
||||
* @param dev Pointer to the device structure for the driver instance
|
||||
* @param cb A valid pointer to a callback, or NULL
|
||||
* @brief Write a set amount of data to an I2C device
|
||||
*
|
||||
* The function is synchronous.
|
||||
*
|
||||
* @return DEV_OK if successful, another DEV_* code otherwise.
|
||||
*/
|
||||
static inline int i2c_set_callback(struct device *dev, i2c_callback cb)
|
||||
{
|
||||
struct i2c_driver_api *api;
|
||||
|
||||
api = (struct i2c_driver_api *)dev->driver_api;
|
||||
return api->set_callback(dev, cb);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Configure a host controllers operation
|
||||
* @param dev Pointer to the device structure for the driver instance
|
||||
* @param buf Memory pool that data should be transferred from
|
||||
* @param len Size of the memory pool available for reading from
|
||||
|
@ -139,7 +121,10 @@ static inline int i2c_write(struct device *dev, uint8_t *buf,
|
|||
}
|
||||
|
||||
/**
|
||||
* @brief Read a set amount of data from an I2C driver
|
||||
* @brief Read a set amount of data from an I2C device
|
||||
*
|
||||
* The function is synchronous.
|
||||
*
|
||||
* @param dev Pointer to the device structure for the driver instance
|
||||
* @param buf Memory pool that data should be transferred to
|
||||
* @param len Size of the memory pool available for writing to
|
||||
|
@ -156,37 +141,12 @@ static inline int i2c_read(struct device *dev, uint8_t *buf,
|
|||
return api->transfer(dev, 0, 0, buf, len, addr, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Provide an interrupt free write as master
|
||||
*
|
||||
* This is for situation where transactions are guaranteed to finish
|
||||
* before returning.
|
||||
*
|
||||
* Note that this is only for I2C device acting as master.
|
||||
* Slave mode is currently not supported.
|
||||
*
|
||||
* @param dev Pointer to the device structure for the driver instance
|
||||
* @param buf Memory pool that data should be transferred from
|
||||
* @param len Size of the memory pool available for reading from
|
||||
* @param addr Address of the I2C device to perform transfer
|
||||
*
|
||||
* @return DEV_OK if successful, otherwise failed.
|
||||
*/
|
||||
static inline int i2c_polling_write(struct device *dev, uint8_t *buf,
|
||||
uint32_t len, uint16_t addr)
|
||||
{
|
||||
struct i2c_driver_api *api;
|
||||
|
||||
api = (struct i2c_driver_api *)dev->driver_api;
|
||||
return api->poll_transfer(dev, buf, len, 0, 0, addr, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Performs data transfer to another I2C device
|
||||
*
|
||||
* This provides a generic interface to perform data transfer
|
||||
* to another I2C device. If a simple read or write is needed,
|
||||
* use i2c_read()/i2c_write() instead.
|
||||
* use i2c_read()/i2c_write() instead. The function is synchronous.
|
||||
*
|
||||
* @param dev Pointer to the device structure for the driver instance
|
||||
* @param tx_buf Memory pool that data should be transferred from
|
||||
|
@ -210,38 +170,6 @@ static inline int i2c_transfer(struct device *dev,
|
|||
rx_buf, rx_len, addr, ctrl_flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Performs interrupt free data transfer
|
||||
*
|
||||
* This provides a generic interface to perform data transfer
|
||||
* to another I2C device. This is for situation where transactions
|
||||
* are guaranteed to finish before returning.
|
||||
*
|
||||
* Note that this is only for I2C device acting as master.
|
||||
* Slave mode is currently not supported.
|
||||
*
|
||||
* @param dev Pointer to the device structure for the driver instance
|
||||
* @param tx_buf Memory pool that data should be transferred from
|
||||
* @param tx_len Size of the memory pool available for reading from
|
||||
* @param rx_buf Memory pool that data should be transferred to
|
||||
* @param rx_len Size of the memory pool available for writing to
|
||||
* @param addr Address of the I2C target device
|
||||
* @param ctrl_flags Control flags for this transfer
|
||||
*
|
||||
* @return DEV_OK if successful, another DEV_* code otherwise.
|
||||
*/
|
||||
static inline int i2c_poll_transfer(struct device *dev,
|
||||
uint8_t *tx_buf, uint32_t tx_len,
|
||||
uint8_t *rx_buf, uint32_t rx_len,
|
||||
uint16_t addr, uint32_t ctrl_flags)
|
||||
{
|
||||
struct i2c_driver_api *api;
|
||||
|
||||
api = (struct i2c_driver_api *)dev->driver_api;
|
||||
return api->poll_transfer(dev, tx_buf, tx_len,
|
||||
rx_buf, rx_len, addr, ctrl_flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Suspend an I2C driver
|
||||
* @param dev Pointer to the device structure for the driver instance
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue