Skip to content

Commit 006d9ff

Browse files
teburdnashif
authored andcommitted
i2c: mcux transfer with callbacks
Implements i2c_transfer_cb for the mcux driver Signed-off-by: Tom Burdick <thomas.burdick@intel.com>
1 parent a45ece6 commit 006d9ff

File tree

1 file changed

+129
-3
lines changed

1 file changed

+129
-3
lines changed

drivers/i2c/i2c_mcux.c

Lines changed: 129 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,14 @@ struct i2c_mcux_data {
3636
struct k_sem lock;
3737
struct k_sem device_sync_sem;
3838
status_t callback_status;
39+
#ifdef CONFIG_I2C_CALLBACK
40+
uint16_t addr;
41+
uint32_t msg;
42+
struct i2c_msg *msgs;
43+
uint32_t num_msgs;
44+
i2c_callback_t cb;
45+
void *userdata;
46+
#endif /* CONFIG_I2C_CALLBACK */
3947
};
4048

4149
static int i2c_mcux_configure(const struct device *dev,
@@ -77,16 +85,42 @@ static int i2c_mcux_configure(const struct device *dev,
7785
return 0;
7886
}
7987

88+
#ifdef CONFIG_I2C_CALLBACK
89+
90+
static void i2c_mcux_async_done(const struct device *dev, struct i2c_mcux_data *data, int result);
91+
static void i2c_mcux_async_iter(const struct device *dev);
92+
93+
#endif
94+
8095
static void i2c_mcux_master_transfer_callback(I2C_Type *base,
8196
i2c_master_handle_t *handle,
82-
status_t status, void *userData)
97+
status_t status, void *userdata)
8398
{
84-
struct i2c_mcux_data *data = userData;
8599

86100
ARG_UNUSED(handle);
87101
ARG_UNUSED(base);
88102

103+
struct device *dev = userdata;
104+
struct i2c_mcux_data *data = dev->data;
105+
106+
#ifdef CONFIG_I2C_CALLBACK
107+
if (data->cb != NULL) {
108+
/* Async transfer */
109+
if (status != kStatus_Success) {
110+
I2C_MasterTransferAbort(base, &data->handle);
111+
i2c_mcux_async_done(dev, data, -EIO);
112+
} else if (data->msg == data->num_msgs - 1) {
113+
i2c_mcux_async_done(dev, data, 0);
114+
} else {
115+
data->msg++;
116+
i2c_mcux_async_iter(dev);
117+
}
118+
return;
119+
}
120+
#endif /* CONFIG_I2C_CALLBACK */
121+
89122
data->callback_status = status;
123+
90124
k_sem_give(&data->device_sync_sem);
91125
}
92126

@@ -174,6 +208,95 @@ static int i2c_mcux_transfer(const struct device *dev, struct i2c_msg *msgs,
174208
return ret;
175209
}
176210

211+
#ifdef CONFIG_I2C_CALLBACK
212+
213+
static void i2c_mcux_async_done(const struct device *dev, struct i2c_mcux_data *data, int result)
214+
{
215+
216+
i2c_callback_t cb = data->cb;
217+
void *userdata = data->userdata;
218+
219+
data->msg = 0;
220+
data->msgs = NULL;
221+
data->num_msgs = 0;
222+
data->cb = NULL;
223+
data->userdata = NULL;
224+
data->addr = 0;
225+
226+
k_sem_give(&data->lock);
227+
228+
/* Callback may wish to start another transfer */
229+
cb(dev, result, userdata);
230+
}
231+
232+
/* Start a transfer asynchronously */
233+
static void i2c_mcux_async_iter(const struct device *dev)
234+
{
235+
I2C_Type *base = DEV_BASE(dev);
236+
struct i2c_mcux_data *data = dev->data;
237+
i2c_master_transfer_t transfer;
238+
status_t status;
239+
struct i2c_msg *msg = &data->msgs[data->msg];
240+
241+
if (I2C_MSG_ADDR_10_BITS & msg->flags) {
242+
i2c_mcux_async_done(dev, data, -ENOTSUP);
243+
return;
244+
}
245+
246+
/* Initialize the transfer descriptor */
247+
transfer.flags = i2c_mcux_convert_flags(msg->flags);
248+
transfer.slaveAddress = data->addr;
249+
transfer.direction = (msg->flags & I2C_MSG_READ) ? kI2C_Read : kI2C_Write;
250+
transfer.subaddress = 0;
251+
transfer.subaddressSize = 0;
252+
transfer.data = msg->buf;
253+
transfer.dataSize = msg->len;
254+
255+
/* Prevent the controller to send a start condition between
256+
* messages, except if explicitly requested.
257+
*/
258+
if (data->msg != 0 && !(msg->flags & I2C_MSG_RESTART)) {
259+
transfer.flags |= kI2C_TransferNoStartFlag;
260+
}
261+
262+
/* Start the transfer */
263+
status = I2C_MasterTransferNonBlocking(base, &data->handle, &transfer);
264+
265+
/* Return an error if the transfer didn't start successfully
266+
* e.g., if the bus was busy
267+
*/
268+
if (status != kStatus_Success) {
269+
I2C_MasterTransferAbort(base, &data->handle);
270+
i2c_mcux_async_done(dev, data, -EIO);
271+
}
272+
}
273+
274+
static int i2c_mcux_transfer_cb(const struct device *dev, struct i2c_msg *msgs, uint8_t num_msgs,
275+
uint16_t addr, i2c_callback_t cb, void *userdata)
276+
{
277+
struct i2c_mcux_data *data = dev->data;
278+
279+
int res = k_sem_take(&data->lock, K_NO_WAIT);
280+
281+
if (res != 0) {
282+
return -EWOULDBLOCK;
283+
}
284+
285+
data->msg = 0;
286+
data->msgs = msgs;
287+
data->num_msgs = num_msgs;
288+
data->addr = addr;
289+
data->cb = cb;
290+
data->userdata = userdata;
291+
data->addr = addr;
292+
293+
i2c_mcux_async_iter(dev);
294+
295+
return 0;
296+
}
297+
298+
#endif /* CONFIG_I2C_CALLBACK */
299+
177300
static void i2c_mcux_isr(const struct device *dev)
178301
{
179302
I2C_Type *base = DEV_BASE(dev);
@@ -198,7 +321,7 @@ static int i2c_mcux_init(const struct device *dev)
198321
I2C_MasterGetDefaultConfig(&master_config);
199322
I2C_MasterInit(base, &master_config, clock_freq);
200323
I2C_MasterTransferCreateHandle(base, &data->handle,
201-
i2c_mcux_master_transfer_callback, data);
324+
i2c_mcux_master_transfer_callback, (void *)dev);
202325

203326
bitrate_cfg = i2c_map_dt_bitrate(config->bitrate);
204327

@@ -220,6 +343,9 @@ static int i2c_mcux_init(const struct device *dev)
220343
static const struct i2c_driver_api i2c_mcux_driver_api = {
221344
.configure = i2c_mcux_configure,
222345
.transfer = i2c_mcux_transfer,
346+
#ifdef CONFIG_I2C_CALLBACK
347+
.transfer_cb = i2c_mcux_transfer_cb,
348+
#endif
223349
};
224350

225351
#define I2C_DEVICE_INIT_MCUX(n) \

0 commit comments

Comments
 (0)