Skip to content

Commit f7a0a54

Browse files
maass-hamburgkartben
authored andcommitted
drivers: i2c: litex: add driver for litei2c
add driver for litei2c. Signed-off-by: Fin Maaß <[email protected]>
1 parent 43e8f11 commit f7a0a54

File tree

4 files changed

+353
-0
lines changed

4 files changed

+353
-0
lines changed

drivers/i2c/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ zephyr_library_sources_ifdef(CONFIG_I2C_IPROC i2c_bcm_iproc.c)
4040
zephyr_library_sources_ifdef(CONFIG_I2C_ITE_ENHANCE i2c_ite_enhance.c)
4141
zephyr_library_sources_ifdef(CONFIG_I2C_ITE_IT8XXX2 i2c_ite_it8xxx2.c)
4242
zephyr_library_sources_ifdef(CONFIG_I2C_LITEX i2c_litex.c)
43+
zephyr_library_sources_ifdef(CONFIG_I2C_LITEX_LITEI2C i2c_litex_litei2c.c)
4344
zephyr_library_sources_ifdef(CONFIG_I2C_LPC11U6X i2c_lpc11u6x.c)
4445
zephyr_library_sources_ifdef(CONFIG_I2C_MCHP_MSS i2c_mchp_mss.c)
4546
zephyr_library_sources_ifdef(CONFIG_I2C_MCUX i2c_mcux.c)

drivers/i2c/Kconfig.litex

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,10 @@ config I2C_LITEX
88
select I2C_BITBANG
99
help
1010
Enable support for Litex I2C driver
11+
12+
config I2C_LITEX_LITEI2C
13+
bool "LiteX LiteI2C I2C driver"
14+
default y
15+
depends on DT_HAS_LITEX_LITEI2C_ENABLED
16+
help
17+
Enable support for Litex I2C driver

drivers/i2c/i2c_litex_litei2c.c

Lines changed: 327 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,327 @@
1+
/*
2+
* Copyright (c) 2024 Vogl Electronic GmbH
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#define DT_DRV_COMPAT litex_litei2c
8+
9+
#include <zephyr/device.h>
10+
#include <zephyr/drivers/i2c.h>
11+
12+
#include <zephyr/logging/log.h>
13+
LOG_MODULE_REGISTER(i2c_litex_litei2c, CONFIG_I2C_LOG_LEVEL);
14+
15+
#include "i2c-priv.h"
16+
17+
#include <soc.h>
18+
19+
#define MASTER_STATUS_TX_READY_OFFSET 0x0
20+
#define MASTER_STATUS_RX_READY_OFFSET 0x1
21+
#define MASTER_STATUS_NACK_OFFSET 0x8
22+
23+
struct i2c_litex_litei2c_config {
24+
uint32_t phy_speed_mode_addr;
25+
uint32_t master_active_addr;
26+
uint32_t master_settings_addr;
27+
uint32_t master_addr_addr;
28+
uint32_t master_rxtx_addr;
29+
uint32_t master_status_addr;
30+
uint32_t bitrate;
31+
};
32+
33+
static int i2c_litex_configure(const struct device *dev, uint32_t dev_config)
34+
{
35+
const struct i2c_litex_litei2c_config *config = dev->config;
36+
37+
if (I2C_ADDR_10_BITS & dev_config) {
38+
return -ENOTSUP;
39+
}
40+
41+
if (!(I2C_MODE_CONTROLLER & dev_config)) {
42+
return -ENOTSUP;
43+
}
44+
45+
/* Setup speed to use */
46+
switch (I2C_SPEED_GET(dev_config)) {
47+
case I2C_SPEED_STANDARD:
48+
litex_write8(0, config->phy_speed_mode_addr);
49+
break;
50+
case I2C_SPEED_FAST:
51+
litex_write8(1, config->phy_speed_mode_addr);
52+
break;
53+
case I2C_SPEED_FAST_PLUS:
54+
litex_write8(2, config->phy_speed_mode_addr);
55+
break;
56+
default:
57+
return -ENOTSUP;
58+
}
59+
60+
return 0;
61+
}
62+
63+
static int i2c_litex_get_config(const struct device *dev, uint32_t *config)
64+
{
65+
const struct i2c_litex_litei2c_config *dev_config = dev->config;
66+
67+
*config = I2C_MODE_CONTROLLER;
68+
69+
switch (litex_read8(dev_config->phy_speed_mode_addr)) {
70+
case 0:
71+
*config |= I2C_SPEED_SET(I2C_SPEED_STANDARD);
72+
break;
73+
case 1:
74+
*config |= I2C_SPEED_SET(I2C_SPEED_FAST);
75+
break;
76+
case 2:
77+
*config |= I2C_SPEED_SET(I2C_SPEED_FAST_PLUS);
78+
break;
79+
default:
80+
break;
81+
}
82+
83+
return 0;
84+
}
85+
86+
static int i2c_litex_write_settings(const struct device *dev, uint8_t len_tx, uint8_t len_rx,
87+
bool recover)
88+
{
89+
const struct i2c_litex_litei2c_config *config = dev->config;
90+
91+
uint32_t settings = len_tx | (len_rx << 8) | (recover << 16);
92+
93+
litex_write32(settings, config->master_settings_addr);
94+
95+
return 0;
96+
}
97+
98+
static int i2c_litex_transfer(const struct device *dev, struct i2c_msg *msgs, uint8_t num_msgs,
99+
uint16_t addr)
100+
{
101+
const struct i2c_litex_litei2c_config *config = dev->config;
102+
uint32_t len_tx_buf = 0;
103+
uint32_t len_rx_buf = 0;
104+
uint8_t len_tx = 0;
105+
uint8_t len_rx = 0;
106+
107+
uint8_t *tx_buf_ptr;
108+
uint8_t *rx_buf_ptr;
109+
110+
uint32_t tx_buf;
111+
uint32_t rx_buf;
112+
113+
uint32_t tx_j = 0;
114+
uint32_t rx_j = 0;
115+
116+
int ret = 0;
117+
118+
litex_write8(1, config->master_active_addr);
119+
120+
LOG_DBG("addr: 0x%x", addr);
121+
litex_write8((uint8_t)addr, config->master_addr_addr);
122+
123+
for (uint8_t i = 0; i < num_msgs; i++) {
124+
if (msgs[i].flags & I2C_MSG_READ) {
125+
len_tx_buf = 0;
126+
len_rx_buf = msgs[i].len;
127+
rx_buf_ptr = msgs[i].buf;
128+
tx_buf_ptr = NULL;
129+
} else {
130+
len_tx_buf = msgs[i].len;
131+
tx_buf_ptr = msgs[i].buf;
132+
if (!(msgs[i].flags & I2C_MSG_STOP) && (i + 1 < num_msgs) &&
133+
(msgs[i + 1].flags & I2C_MSG_READ) &&
134+
(msgs[i + 1].flags & I2C_MSG_RESTART)) {
135+
i++;
136+
len_rx_buf = msgs[i].len;
137+
rx_buf_ptr = msgs[i].buf;
138+
} else {
139+
len_rx_buf = 0;
140+
rx_buf_ptr = NULL;
141+
}
142+
}
143+
144+
LOG_HEXDUMP_DBG(tx_buf_ptr, len_tx_buf, "tx_buf");
145+
146+
tx_j = 0;
147+
rx_j = 0;
148+
do {
149+
150+
if (len_tx_buf > (tx_j + 4)) {
151+
len_tx = 5;
152+
len_rx = 0;
153+
} else {
154+
len_tx = len_tx_buf - tx_j;
155+
156+
if (len_rx_buf > (rx_j + 4)) {
157+
len_rx = 5;
158+
} else {
159+
len_rx = len_rx_buf - rx_j;
160+
}
161+
}
162+
163+
tx_buf = 0;
164+
165+
switch (len_tx) {
166+
case 5:
167+
case 4:
168+
tx_buf |= tx_buf_ptr[0 + tx_j] << 24;
169+
tx_buf |= tx_buf_ptr[1 + tx_j] << 16;
170+
tx_buf |= tx_buf_ptr[2 + tx_j] << 8;
171+
tx_buf |= tx_buf_ptr[3 + tx_j];
172+
tx_j += 4;
173+
break;
174+
case 3:
175+
tx_buf |= tx_buf_ptr[0 + tx_j] << 16;
176+
tx_buf |= tx_buf_ptr[1 + tx_j] << 8;
177+
tx_buf |= tx_buf_ptr[2 + tx_j];
178+
tx_j += 3;
179+
break;
180+
case 2:
181+
tx_buf |= tx_buf_ptr[0 + tx_j] << 8;
182+
tx_buf |= tx_buf_ptr[1 + tx_j];
183+
tx_j += 2;
184+
break;
185+
case 1:
186+
tx_buf |= tx_buf_ptr[0 + tx_j];
187+
tx_j += 1;
188+
break;
189+
default:
190+
break;
191+
}
192+
193+
LOG_DBG("len_tx: %d, len_rx: %d", len_tx, len_rx);
194+
i2c_litex_write_settings(dev, len_tx, len_rx, false);
195+
196+
while (!(litex_read8(config->master_status_addr) &
197+
BIT(MASTER_STATUS_TX_READY_OFFSET))) {
198+
;
199+
}
200+
201+
LOG_DBG("tx_buf: 0x%x", tx_buf);
202+
litex_write32(tx_buf, config->master_rxtx_addr);
203+
204+
while (!(litex_read8(config->master_status_addr) &
205+
BIT(MASTER_STATUS_RX_READY_OFFSET))) {
206+
;
207+
}
208+
209+
if (litex_read16(config->master_status_addr) &
210+
BIT(MASTER_STATUS_NACK_OFFSET)) {
211+
LOG_DBG("NACK received (addr: 0x%x)", addr);
212+
ret = -EIO;
213+
}
214+
215+
rx_buf = litex_read32(config->master_rxtx_addr);
216+
LOG_DBG("rx_buf: 0x%x", rx_buf);
217+
218+
switch (len_rx) {
219+
case 5:
220+
case 4:
221+
rx_buf_ptr[0 + rx_j] = rx_buf >> 24;
222+
rx_buf_ptr[1 + rx_j] = rx_buf >> 16;
223+
rx_buf_ptr[2 + rx_j] = rx_buf >> 8;
224+
rx_buf_ptr[3 + rx_j] = rx_buf;
225+
rx_j += 4;
226+
break;
227+
case 3:
228+
rx_buf_ptr[0 + rx_j] = rx_buf >> 16;
229+
rx_buf_ptr[1 + rx_j] = rx_buf >> 8;
230+
rx_buf_ptr[2 + rx_j] = rx_buf;
231+
rx_j += 3;
232+
break;
233+
case 2:
234+
rx_buf_ptr[0 + rx_j] = rx_buf >> 8;
235+
rx_buf_ptr[1 + rx_j] = rx_buf;
236+
rx_j += 2;
237+
break;
238+
case 1:
239+
rx_buf_ptr[0 + rx_j] = rx_buf;
240+
rx_j += 1;
241+
break;
242+
default:
243+
break;
244+
}
245+
246+
if (ret < 0) {
247+
goto transfer_end;
248+
}
249+
250+
} while ((tx_j < len_tx_buf) || (rx_j < len_rx_buf));
251+
252+
LOG_HEXDUMP_DBG(rx_buf_ptr, len_rx_buf, "rx_buf");
253+
}
254+
255+
transfer_end:
256+
257+
litex_write8(0, config->master_active_addr);
258+
259+
return ret;
260+
}
261+
262+
static int i2c_litex_recover_bus(const struct device *dev)
263+
{
264+
const struct i2c_litex_litei2c_config *config = dev->config;
265+
266+
litex_write8(1, config->master_active_addr);
267+
268+
i2c_litex_write_settings(dev, 0, 0, true);
269+
270+
while (!(litex_read8(config->master_status_addr) & BIT(MASTER_STATUS_TX_READY_OFFSET))) {
271+
;
272+
}
273+
274+
litex_write32(0, config->master_rxtx_addr);
275+
276+
while (!(litex_read8(config->master_status_addr) & BIT(MASTER_STATUS_RX_READY_OFFSET))) {
277+
;
278+
}
279+
280+
(void)litex_read32(config->master_rxtx_addr);
281+
282+
litex_write8(0, config->master_active_addr);
283+
284+
return 0;
285+
}
286+
287+
static int i2c_litex_init(const struct device *dev)
288+
{
289+
const struct i2c_litex_litei2c_config *config = dev->config;
290+
int ret;
291+
292+
ret = i2c_litex_configure(dev, I2C_MODE_CONTROLLER | i2c_map_dt_bitrate(config->bitrate));
293+
if (ret != 0) {
294+
LOG_ERR("failed to configure I2C: %d", ret);
295+
}
296+
297+
return ret;
298+
}
299+
300+
static DEVICE_API(i2c, i2c_litex_litei2c_driver_api) = {
301+
.configure = i2c_litex_configure,
302+
.get_config = i2c_litex_get_config,
303+
.transfer = i2c_litex_transfer,
304+
.recover_bus = i2c_litex_recover_bus,
305+
#ifdef CONFIG_I2C_RTIO
306+
.iodev_submit = i2c_iodev_submit_fallback,
307+
#endif
308+
};
309+
310+
/* Device Instantiation */
311+
312+
#define I2C_LITEX_INIT(n) \
313+
static const struct i2c_litex_litei2c_config i2c_litex_litei2c_config_##n = { \
314+
.phy_speed_mode_addr = DT_INST_REG_ADDR_BY_NAME(n, phy_speed_mode), \
315+
.master_active_addr = DT_INST_REG_ADDR_BY_NAME(n, master_active), \
316+
.master_settings_addr = DT_INST_REG_ADDR_BY_NAME(n, master_settings), \
317+
.master_addr_addr = DT_INST_REG_ADDR_BY_NAME(n, master_addr), \
318+
.master_rxtx_addr = DT_INST_REG_ADDR_BY_NAME(n, master_rxtx), \
319+
.master_status_addr = DT_INST_REG_ADDR_BY_NAME(n, master_status), \
320+
.bitrate = DT_INST_PROP(n, clock_frequency), \
321+
}; \
322+
\
323+
I2C_DEVICE_DT_INST_DEFINE(n, i2c_litex_init, NULL, NULL, \
324+
&i2c_litex_litei2c_config_##n, POST_KERNEL, \
325+
CONFIG_I2C_INIT_PRIORITY, &i2c_litex_litei2c_driver_api);
326+
327+
DT_INST_FOREACH_STATUS_OKAY(I2C_LITEX_INIT)
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#
2+
# Copyright (c) 2024 Vogl Electronic GmbH
3+
#
4+
# SPDX-License-Identifier: Apache-2.0
5+
#
6+
7+
description: LiteX LiteI2C I2C controller
8+
9+
compatible: "litex,litei2c"
10+
11+
include: i2c-controller.yaml
12+
13+
properties:
14+
reg:
15+
required: true
16+
17+
clock-frequency:
18+
required: true

0 commit comments

Comments
 (0)