Skip to content

Commit b686036

Browse files
committed
drivers: i2c: mcux: add support for target mode
Add i2c target support to the i2c_mcux driver. Add the frdm_mcxc242 board to i2c_target_api tests. Signed-off-by: Maximilian Werner <[email protected]>
1 parent 4f2ee86 commit b686036

File tree

3 files changed

+222
-0
lines changed

3 files changed

+222
-0
lines changed

drivers/i2c/i2c_mcux.c

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,14 @@ struct i2c_mcux_data {
4646
i2c_callback_t cb;
4747
void *userdata;
4848
#endif /* CONFIG_I2C_CALLBACK */
49+
#ifdef CONFIG_I2C_TARGET
50+
i2c_slave_handle_t target_handle;
51+
struct i2c_target_config *target_cfg;
52+
uint8_t target_buffer;
53+
bool target_attached;
54+
bool target_receiving;
55+
bool target_first_rxtx;
56+
#endif
4957
};
5058

5159
static int i2c_mcux_configure(const struct device *dev,
@@ -299,12 +307,170 @@ static int i2c_mcux_transfer_cb(const struct device *dev, struct i2c_msg *msgs,
299307

300308
#endif /* CONFIG_I2C_CALLBACK */
301309

310+
#if CONFIG_I2C_TARGET
311+
static void i2c_mcux_target_transfer_cb(I2C_Type *base, i2c_slave_transfer_t *transfer, void *userData)
312+
{
313+
const struct device *dev = (const struct device *)userData;
314+
struct i2c_mcux_data *data = dev->data;
315+
const struct i2c_target_callbacks *target_cb = data->target_cfg->callbacks;
316+
int ret = 0;
317+
318+
ARG_UNUSED(base);
319+
320+
if (transfer->event & kI2C_SlaveStartEvent) {
321+
/* start or repeated start of a transfer */
322+
transfer->dataSize = 0;
323+
data->target_first_rxtx = true;
324+
325+
if (data->target_receiving) {
326+
/* In case of a repeated start after a kI2C_SlaveReceiveEvent,
327+
* the kI2C_SlaveCompletionEvent is not fired. We need to fetch the last
328+
* byte here. */
329+
data->target_receiving = false;
330+
if (target_cb->write_received) {
331+
target_cb->write_received(data->target_cfg, data->target_buffer);
332+
}
333+
}
334+
}
335+
336+
if (transfer->event & kI2C_SlaveReceiveEvent) {
337+
/* request to provide a buffer in which to place received data */
338+
data->target_receiving = true;
339+
340+
transfer->data = &data->target_buffer;
341+
transfer->dataSize = 1;
342+
343+
if (data->target_first_rxtx) {
344+
data->target_first_rxtx = false;
345+
if (target_cb->write_requested) {
346+
ret = target_cb->write_requested(data->target_cfg);
347+
}
348+
} else {
349+
if (target_cb->write_received) {
350+
ret = target_cb->write_received(data->target_cfg,
351+
data->target_buffer);
352+
}
353+
}
354+
355+
if (ret < 0) {
356+
/* abort communication by not providing a buffer in case of an error */
357+
transfer->dataSize = 0;
358+
}
359+
}
360+
361+
if (transfer->event & kI2C_SlaveTransmitEvent) {
362+
/* request to provide data to transmit */
363+
transfer->data = &data->target_buffer;
364+
transfer->dataSize = 1;
365+
366+
if (data->target_first_rxtx) {
367+
data->target_first_rxtx = false;
368+
if (target_cb->read_requested) {
369+
ret = target_cb->read_requested(data->target_cfg,
370+
&data->target_buffer);
371+
}
372+
} else {
373+
if (target_cb->read_processed) {
374+
ret = target_cb->read_processed(data->target_cfg,
375+
&data->target_buffer);
376+
}
377+
}
378+
379+
if (ret < 0) {
380+
/* abort communication by not providing a buffer in case of an error */
381+
transfer->dataSize = 0;
382+
}
383+
}
384+
385+
if (transfer->event & kI2C_SlaveCompletionEvent) {
386+
/* transfer finished */
387+
data->target_first_rxtx = false;
388+
389+
if (data->target_receiving) {
390+
/* fetch last received byte */
391+
data->target_receiving = false;
392+
if (target_cb->write_received) {
393+
target_cb->write_received(data->target_cfg, data->target_buffer);
394+
}
395+
}
396+
397+
if (target_cb->stop) {
398+
target_cb->stop(data->target_cfg);
399+
}
400+
}
401+
}
402+
403+
static int i2c_mcux_target_register(const struct device *dev,
404+
struct i2c_target_config *target_config)
405+
{
406+
I2C_Type *base = DEV_BASE(dev);
407+
const struct i2c_mcux_config *config = dev->config;
408+
struct i2c_mcux_data *data = dev->data;
409+
i2c_slave_config_t slave_config;
410+
uint32_t clock_freq;
411+
412+
I2C_MasterDeinit(base);
413+
414+
if (!target_config) {
415+
return -EINVAL;
416+
}
417+
418+
if (data->target_attached) {
419+
return -EBUSY;
420+
}
421+
422+
data->target_attached = true;
423+
data->target_cfg = target_config;
424+
data->target_first_rxtx = true;
425+
data->target_receiving = false;
426+
427+
I2C_SlaveGetDefaultConfig(&slave_config);
428+
slave_config.slaveAddress = target_config->address;
429+
430+
clock_freq = CLOCK_GetFreq(config->clock_source);
431+
432+
I2C_SlaveInit(base, &slave_config, clock_freq);
433+
I2C_SlaveClearStatusFlags(base, kClearFlags);
434+
I2C_SlaveTransferCreateHandle(base, &data->target_handle, i2c_mcux_target_transfer_cb,
435+
(void *)dev);
436+
I2C_SlaveTransferNonBlocking(base, &data->target_handle, kI2C_SlaveAllEvents);
437+
438+
return 0;
439+
}
440+
441+
static int i2c_mcux_target_unregister(const struct device *dev,
442+
struct i2c_target_config *target_config)
443+
{
444+
I2C_Type *base = DEV_BASE(dev);
445+
struct i2c_mcux_data *data = dev->data;
446+
447+
if (!data->target_attached) {
448+
return -EINVAL;
449+
}
450+
451+
data->target_cfg = NULL;
452+
data->target_attached = false;
453+
454+
I2C_SlaveDeinit(base);
455+
456+
return 0;
457+
}
458+
#endif /* CONFIG_I2C_TARGET */
459+
302460
static void i2c_mcux_isr(const struct device *dev)
303461
{
304462
I2C_Type *base = DEV_BASE(dev);
305463
struct i2c_mcux_data *data = dev->data;
306464

465+
#ifdef CONFIG_I2C_TARGET
466+
if (data->target_attached) {
467+
I2C_SlaveTransferHandleIRQ(base, &data->target_handle);
468+
} else {
469+
I2C_MasterTransferHandleIRQ(base, &data->handle);
470+
}
471+
#else
307472
I2C_MasterTransferHandleIRQ(base, &data->handle);
473+
#endif /* CONFIG_I2C_TARGET */
308474
}
309475

310476
static int i2c_mcux_init(const struct device *dev)
@@ -351,6 +517,10 @@ static DEVICE_API(i2c, i2c_mcux_driver_api) = {
351517
#ifdef CONFIG_I2C_RTIO
352518
.iodev_submit = i2c_iodev_submit_fallback,
353519
#endif
520+
#if CONFIG_I2C_TARGET
521+
.target_register = i2c_mcux_target_register,
522+
.target_unregister = i2c_mcux_target_unregister,
523+
#endif
354524
};
355525

356526
#define I2C_DEVICE_INIT_MCUX(n) \
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/*
2+
* SPDX-License-Identifier: Apache-2.0
3+
*/
4+
#include <nxp/mcx/MCXC142VFM-pinctrl.h>
5+
6+
&pinctrl {
7+
pinmux_i2c0: pinmux_i2c0 {
8+
group0 {
9+
pinmux = <I2C0_SCL_PTB0>,
10+
<I2C0_SDA_PTB1>;
11+
drive-strength = "low";
12+
drive-open-drain;
13+
slew-rate = "fast";
14+
};
15+
};
16+
pinmux_i2c1: pinmux_i2c1 {
17+
group0 {
18+
pinmux = <I2C1_SCL_PTD7>,
19+
<I2C1_SDA_PTD6>;
20+
drive-strength = "low";
21+
drive-open-drain;
22+
slew-rate = "fast";
23+
};
24+
};
25+
};
26+
27+
/* To test this sample, connect
28+
* I2C0 SCL(J4-12, PTB0) --> I2C1 SCL(J2-20, PTD7)
29+
* I2C0 SDA(J4-10, PTB1) --> I2C1 SDA(J2-18, PTD6)
30+
*/
31+
&i2c0 {
32+
pinctrl-0 = <&pinmux_i2c0>;
33+
pinctrl-names = "default";
34+
status = "okay";
35+
eeprom0: eeprom@54 {
36+
compatible = "zephyr,i2c-target-eeprom";
37+
reg = <0x54>;
38+
size = <256>;
39+
};
40+
};
41+
42+
&i2c1 {
43+
pinctrl-0 = <&pinmux_i2c1>;
44+
pinctrl-names = "default";
45+
status = "okay";
46+
eeprom1: eeprom@56 {
47+
compatible = "zephyr,i2c-target-eeprom";
48+
reg = <0x56>;
49+
size = <256>;
50+
};
51+
};

tests/drivers/i2c/i2c_target_api/testcase.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ tests:
5858
- frdm_mcxa346
5959
- frdm_mcxa266
6060
- frdm_mcxa366
61+
- frdm_mcxc242
6162
- max32655evkit/max32655/m4
6263
- max32662evkit
6364
- max32666evkit/max32666/cpu0

0 commit comments

Comments
 (0)