Skip to content

Commit 49ef7d4

Browse files
bogdanovsnashif
authored andcommitted
drivers: i2c: Add support for cc23x0 I2C
Add support for I2C to cc23x0 SoC. Only controller mode is implemented. Signed-off-by: Stoyan Bogdanov <[email protected]>
1 parent f74f19e commit 49ef7d4

File tree

5 files changed

+332
-0
lines changed

5 files changed

+332
-0
lines changed

drivers/i2c/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ zephyr_library_sources_ifdef(CONFIG_I2C_AMBIQ i2c_ambiq.c)
2727
zephyr_library_sources_ifdef(CONFIG_I2C_ANDES_ATCIIC100 i2c_andes_atciic100.c)
2828
zephyr_library_sources_ifdef(CONFIG_I2C_CADENCE i2c_cdns.c)
2929
zephyr_library_sources_ifdef(CONFIG_I2C_CC13XX_CC26XX i2c_cc13xx_cc26xx.c)
30+
zephyr_library_sources_ifdef(CONFIG_I2C_CC23X0 i2c_cc23x0.c)
3031
zephyr_library_sources_ifdef(CONFIG_I2C_CC32XX i2c_cc32xx.c)
3132
zephyr_library_sources_ifdef(CONFIG_I2C_DW i2c_dw.c)
3233
zephyr_library_sources_ifdef(CONFIG_I2C_ENE_KB1200 i2c_ene_kb1200.c)

drivers/i2c/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ source "drivers/i2c/Kconfig.andes_atciic100"
123123
source "drivers/i2c/Kconfig.b91"
124124
source "drivers/i2c/Kconfig.bcm_iproc"
125125
source "drivers/i2c/Kconfig.cc13xx_cc26xx"
126+
source "drivers/i2c/Kconfig.cc23x0"
126127
source "drivers/i2c/Kconfig.cdns"
127128
source "drivers/i2c/Kconfig.dw"
128129
source "drivers/i2c/Kconfig.ene"

drivers/i2c/Kconfig.cc23x0

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# Copyright (c) 2024 Baylibre, SAS
2+
#
3+
# SPDX-License-Identifier: Apache-2.0
4+
5+
config I2C_CC23X0
6+
bool "TI SimpleLink CC23x0 I2C driver"
7+
default y
8+
depends on DT_HAS_TI_CC23X0_I2C_ENABLED
9+
select PINCTRL
10+
help
11+
Enable support for I2C on the TI SimpleLink CC23x0 series.

drivers/i2c/i2c_cc23x0.c

Lines changed: 297 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,297 @@
1+
/*
2+
* Copyright (c) 2024 Baylibre, SAS
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#define DT_DRV_COMPAT ti_cc23x0_i2c
8+
9+
#include <zephyr/kernel.h>
10+
#include <zephyr/drivers/i2c.h>
11+
#include <zephyr/drivers/pinctrl.h>
12+
#include <zephyr/pm/device.h>
13+
#include <zephyr/pm/policy.h>
14+
#include <zephyr/irq.h>
15+
16+
#define LOG_LEVEL CONFIG_I2C_LOG_LEVEL
17+
18+
#include <zephyr/logging/log.h>
19+
20+
LOG_MODULE_REGISTER(i2c_cc23x0);
21+
22+
#include <driverlib/clkctl.h>
23+
#include <driverlib/i2c.h>
24+
25+
#include "i2c-priv.h"
26+
27+
#define I2C_MASTER_ERR_NONE 0
28+
29+
struct i2c_cc23x0_data {
30+
struct k_sem lock;
31+
struct k_sem complete;
32+
volatile uint32_t error;
33+
};
34+
35+
struct i2c_cc23x0_config {
36+
uint32_t base;
37+
const struct pinctrl_dev_config *pcfg;
38+
};
39+
40+
static int i2c_cc23x0_transmit(const struct device *dev, const uint8_t *buf, uint32_t len,
41+
uint16_t addr)
42+
{
43+
const struct i2c_cc23x0_config *config = dev->config;
44+
const uint32_t base = config->base;
45+
struct i2c_cc23x0_data *data = dev->data;
46+
47+
/* Sending address without data is not supported */
48+
if (len == 0) {
49+
return -EIO;
50+
}
51+
52+
I2CControllerSetTargetAddr(base, addr, false);
53+
54+
/* Single transmission */
55+
if (len == 1) {
56+
I2CControllerPutData(base, *buf);
57+
I2CControllerCommand(base, I2C_CONTROLLER_CMD_SINGLE_SEND);
58+
k_sem_take(&data->complete, K_FOREVER);
59+
return data->error == I2C_MASTER_ERR_NONE ? 0 : -EIO;
60+
}
61+
62+
/* Burst transmission */
63+
I2CControllerPutData(base, buf[0]);
64+
I2CControllerCommand(base, I2C_CONTROLLER_CMD_BURST_SEND_START);
65+
k_sem_take(&data->complete, K_FOREVER);
66+
67+
if (data->error != I2C_MASTER_ERR_NONE) {
68+
goto send_error_stop;
69+
}
70+
71+
for (int i = 1; i < len - 1; i++) {
72+
I2CControllerPutData(base, buf[i]);
73+
I2CControllerCommand(base, I2C_CONTROLLER_CMD_BURST_SEND_CONT);
74+
k_sem_take(&data->complete, K_FOREVER);
75+
76+
if (data->error != I2C_MASTER_ERR_NONE) {
77+
goto send_error_stop;
78+
}
79+
}
80+
81+
I2CControllerPutData(base, buf[len - 1]);
82+
I2CControllerCommand(base, I2C_CONTROLLER_CMD_BURST_SEND_FINISH);
83+
k_sem_take(&data->complete, K_FOREVER);
84+
85+
if (data->error != I2C_MASTER_ERR_NONE) {
86+
return -EIO;
87+
}
88+
89+
return 0;
90+
91+
send_error_stop:
92+
I2CControllerCommand(base, I2C_CONTROLLER_CMD_BURST_SEND_ERROR_STOP);
93+
return -EIO;
94+
}
95+
96+
static int i2c_cc23x0_receive(const struct device *dev, uint8_t *buf, uint32_t len, uint16_t addr)
97+
{
98+
const struct i2c_cc23x0_config *config = dev->config;
99+
const uint32_t base = config->base;
100+
struct i2c_cc23x0_data *data = dev->data;
101+
102+
/* Sending address without data is not supported */
103+
if (len == 0) {
104+
return -EIO;
105+
}
106+
I2CControllerSetTargetAddr(base, addr, true);
107+
108+
/* Single receive */
109+
if (len == 1) {
110+
I2CControllerCommand(base, I2C_CONTROLLER_CMD_SINGLE_RECEIVE);
111+
k_sem_take(&data->complete, K_FOREVER);
112+
113+
if (data->error != I2C_MASTER_ERR_NONE) {
114+
return -EIO;
115+
}
116+
117+
*buf = I2CControllerGetData(base);
118+
return 0;
119+
}
120+
121+
/* Burst receive */
122+
I2CControllerCommand(base, I2C_CONTROLLER_CMD_BURST_RECEIVE_START);
123+
k_sem_take(&data->complete, K_FOREVER);
124+
125+
if (data->error != I2C_MASTER_ERR_NONE) {
126+
goto recv_error_stop;
127+
}
128+
129+
buf[0] = I2CControllerGetData(base);
130+
131+
for (int i = 1; i < len - 1; i++) {
132+
I2CControllerCommand(base, I2C_CONTROLLER_CMD_BURST_RECEIVE_CONT);
133+
k_sem_take(&data->complete, K_FOREVER);
134+
135+
if (data->error != I2C_MASTER_ERR_NONE) {
136+
goto recv_error_stop;
137+
}
138+
139+
buf[i] = I2CControllerGetData(base);
140+
}
141+
142+
I2CControllerCommand(base, I2C_CONTROLLER_CMD_BURST_RECEIVE_FINISH);
143+
k_sem_take(&data->complete, K_FOREVER);
144+
145+
if (data->error != I2C_MASTER_ERR_NONE) {
146+
return -EIO;
147+
}
148+
149+
buf[len - 1] = I2CControllerGetData(base);
150+
151+
return 0;
152+
153+
recv_error_stop:
154+
I2CControllerCommand(base, I2C_CONTROLLER_CMD_BURST_RECEIVE_ERROR_STOP);
155+
return -EIO;
156+
}
157+
158+
static int i2c_cc23x0_transfer(const struct device *dev, struct i2c_msg *msgs, uint8_t num_msgs,
159+
uint16_t addr)
160+
{
161+
struct i2c_cc23x0_data *data = dev->data;
162+
int ret = 0;
163+
164+
if (num_msgs == 0) {
165+
return 0;
166+
}
167+
168+
k_sem_take(&data->lock, K_FOREVER);
169+
170+
for (int i = 0; i < num_msgs; i++) {
171+
/* Not supported by hardware */
172+
if (msgs[i].flags & I2C_MSG_ADDR_10_BITS) {
173+
ret = -EIO;
174+
break;
175+
}
176+
177+
if ((msgs[i].flags & I2C_MSG_RW_MASK) == I2C_MSG_WRITE) {
178+
ret = i2c_cc23x0_transmit(dev, msgs[i].buf, msgs[i].len, addr);
179+
} else {
180+
ret = i2c_cc23x0_receive(dev, msgs[i].buf, msgs[i].len, addr);
181+
}
182+
183+
if (ret) {
184+
break;
185+
}
186+
}
187+
k_sem_give(&data->lock);
188+
189+
return ret;
190+
}
191+
192+
#define CPU_FREQ DT_PROP(DT_PATH(cpus, cpu_0), clock_frequency)
193+
static int i2c_cc23x0_configure(const struct device *dev, uint32_t dev_config)
194+
{
195+
const struct i2c_cc23x0_config *config = dev->config;
196+
bool fast;
197+
198+
switch (I2C_SPEED_GET(dev_config)) {
199+
case I2C_SPEED_STANDARD:
200+
fast = false;
201+
break;
202+
case I2C_SPEED_FAST:
203+
fast = true;
204+
break;
205+
default:
206+
LOG_ERR("Unsupported speed");
207+
return -EIO;
208+
}
209+
210+
/* Support for slave mode has not been implemented */
211+
if (!(dev_config & I2C_MODE_CONTROLLER)) {
212+
LOG_ERR("Slave mode is not supported");
213+
return -EIO;
214+
}
215+
216+
/* This is deprecated and could be ignored in the future */
217+
if (dev_config & I2C_ADDR_10_BITS) {
218+
LOG_ERR("10-bit addressing mode is not supported");
219+
return -EIO;
220+
}
221+
222+
/* Enables and configures I2C master */
223+
I2CControllerInitExpClk(config->base, fast);
224+
225+
CLKCTLEnable(CLKCTL_BASE, CLKCTL_I2C0);
226+
227+
return 0;
228+
}
229+
230+
static void i2c_cc23x0_isr(const struct device *dev)
231+
{
232+
const struct i2c_cc23x0_config *config = dev->config;
233+
struct i2c_cc23x0_data *data = dev->data;
234+
const uint32_t base = config->base;
235+
236+
if (I2CControllerIntStatus(base, true)) {
237+
I2CControllerClearInt(base);
238+
239+
data->error = I2CControllerError(base);
240+
241+
k_sem_give(&data->complete);
242+
}
243+
}
244+
245+
static const struct i2c_driver_api i2c_cc23x0_driver_api = {.configure = i2c_cc23x0_configure,
246+
.transfer = i2c_cc23x0_transfer};
247+
248+
#define I2C_CC23X0_INIT_FUNC(id) \
249+
static int i2c_cc23x0_init##id(const struct device *dev) \
250+
{ \
251+
const struct i2c_cc23x0_config *config = dev->config; \
252+
uint32_t cfg; \
253+
int err; \
254+
\
255+
CLKCTLEnable(CLKCTL_BASE, CLKCTL_I2C0); \
256+
\
257+
IRQ_CONNECT(DT_INST_IRQN(id), DT_INST_IRQ(id, priority), i2c_cc23x0_isr, \
258+
DEVICE_DT_INST_GET(id), 0); \
259+
\
260+
irq_enable(DT_INST_IRQN(id)); \
261+
\
262+
err = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT); \
263+
if (err < 0) { \
264+
LOG_ERR("Failed to configure pinctrl state\n"); \
265+
return err; \
266+
} \
267+
\
268+
cfg = i2c_map_dt_bitrate(DT_INST_PROP(id, clock_frequency)); \
269+
err = i2c_cc23x0_configure(dev, cfg | I2C_MODE_CONTROLLER); \
270+
if (err) { \
271+
LOG_ERR("Failed to configure\n"); \
272+
return err; \
273+
} \
274+
\
275+
I2CControllerEnableInt(config->base); \
276+
return 0; \
277+
}
278+
279+
#define CC23X0_I2C(id) \
280+
I2C_CC23X0_INIT_FUNC(id); \
281+
PINCTRL_DT_INST_DEFINE(id); \
282+
\
283+
static const struct i2c_cc23x0_config i2c_cc23x0_##id##_config = { \
284+
.base = DT_INST_REG_ADDR(id), \
285+
.pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(id), \
286+
}; \
287+
\
288+
static struct i2c_cc23x0_data i2c_cc23x0_##id##_data = { \
289+
.lock = Z_SEM_INITIALIZER(i2c_cc23x0_##id##_data.lock, 1, 1), \
290+
.complete = Z_SEM_INITIALIZER(i2c_cc23x0_##id##_data.complete, 0, 1), \
291+
.error = I2C_MASTER_ERR_NONE}; \
292+
\
293+
I2C_DEVICE_DT_INST_DEFINE(id, i2c_cc23x0_init##id, NULL, &i2c_cc23x0_##id##_data, \
294+
&i2c_cc23x0_##id##_config, POST_KERNEL, \
295+
CONFIG_I2C_INIT_PRIORITY, &i2c_cc23x0_driver_api);
296+
297+
DT_INST_FOREACH_STATUS_OKAY(CC23X0_I2C);
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# Copyright (c) 2024 Baylibre, SAS
2+
#
3+
# SPDX-License-Identifier: Apache-2.0
4+
5+
description: TI CC23x0 I2C node
6+
7+
compatible: "ti,cc23x0-i2c"
8+
9+
include: [i2c-controller.yaml, pinctrl-device.yaml, base.yaml]
10+
11+
properties:
12+
reg:
13+
required: true
14+
15+
interrupts:
16+
required: true
17+
18+
pinctrl-0:
19+
required: true
20+
21+
pinctrl-names:
22+
required: true

0 commit comments

Comments
 (0)