Skip to content

Commit b231905

Browse files
ene-stevenfabiobaltieri
authored andcommitted
drivers: i2c: initial device driver for ENE KB1200
Add i2c driver for ENE KB1200 Signed-off-by: Steven Chang <[email protected]>
1 parent b27fac0 commit b231905

File tree

4 files changed

+366
-0
lines changed

4 files changed

+366
-0
lines changed

drivers/i2c/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ zephyr_library_sources_ifdef(CONFIG_I2C_XILINX_AXI i2c_xilinx_axi.c)
6363
zephyr_library_sources_ifdef(CONFIG_I2C_MCHP_MSS i2c_mchp_mss.c)
6464
zephyr_library_sources_ifdef(CONFIG_I2C_SEDI i2c_sedi.c)
6565
zephyr_library_sources_ifdef(CONFIG_I2C_AMBIQ i2c_ambiq.c)
66+
zephyr_library_sources_ifdef(CONFIG_I2C_ENE_KB1200 i2c_ene_kb1200.c)
6667
zephyr_library_sources_ifdef(CONFIG_GPIO_I2C_SWITCH gpio_i2c_switch.c)
6768
zephyr_library_sources_ifdef(CONFIG_I2C_NUMAKER i2c_numaker.c)
6869

drivers/i2c/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ source "drivers/i2c/Kconfig.sedi"
119119
source "drivers/i2c/Kconfig.ambiq"
120120
source "drivers/i2c/Kconfig.numaker"
121121
source "drivers/i2c/Kconfig.mcux"
122+
source "drivers/i2c/Kconfig.ene"
122123

123124
config I2C_INIT_PRIORITY
124125
int "Init priority"

drivers/i2c/Kconfig.ene

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# Copyright (c) 2024 ENE Technology Inc.
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
config I2C_ENE_KB1200
5+
bool "ENE KB1200 I2C driver"
6+
default y
7+
depends on DT_HAS_ENE_KB1200_I2C_ENABLED
8+
select PINCTRL
9+
help
10+
Enable the ENE KB1200 I2C driver.

drivers/i2c/i2c_ene_kb1200.c

Lines changed: 354 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,354 @@
1+
/*
2+
* Copyright (c) 2024 ENE Technology Inc.
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#define DT_DRV_COMPAT ene_kb1200_i2c
8+
9+
#include <zephyr/kernel.h>
10+
#include <zephyr/drivers/i2c.h>
11+
#include <zephyr/drivers/pinctrl.h>
12+
#include <errno.h>
13+
#include <reg/fsmbm.h>
14+
15+
struct i2c_kb1200_config {
16+
struct fsmbm_regs *fsmbm;
17+
const struct pinctrl_dev_config *pcfg;
18+
};
19+
20+
struct i2c_kb1200_data {
21+
struct k_sem mutex;
22+
volatile uint8_t *msg_buf;
23+
volatile uint32_t msg_len;
24+
volatile uint8_t msg_flags;
25+
volatile int state;
26+
volatile uint32_t index;
27+
volatile int err_code;
28+
};
29+
30+
/* I2C Master local functions */
31+
static void i2c_kb1200_isr(const struct device *dev)
32+
{
33+
const struct i2c_kb1200_config *config = dev->config;
34+
struct i2c_kb1200_data *data = dev->data;
35+
36+
if (data->state == STATE_SENDING) {
37+
if (config->fsmbm->FSMBMPF & FSMBM_BLOCK_FINISH_EVENT) {
38+
/* continue block */
39+
uint32_t remain = data->msg_len - data->index;
40+
uint32_t send_bytes =
41+
remain > FSMBM_BUFFER_SIZE ? FSMBM_BUFFER_SIZE : remain;
42+
memcpy((void *)&config->fsmbm->FSMBMDAT[0],
43+
(void *)&data->msg_buf[data->index], send_bytes);
44+
data->index += send_bytes;
45+
/* Increase CNT setting let hw can't match counter */
46+
config->fsmbm->FSMBMPRTC_C += send_bytes;
47+
/* If it was the last protocol recover the correct length value*/
48+
if (data->msg_len == data->index) {
49+
config->fsmbm->FSMBMPRTC_C -= 1;
50+
}
51+
config->fsmbm->FSMBMPF = FSMBM_BLOCK_FINISH_EVENT;
52+
} else if (config->fsmbm->FSMBMPF & FSMBM_COMPLETE_EVENT) {
53+
/* complete */
54+
if (((config->fsmbm->FSMBMSTS & FSMBM_STS_MASK) == FSMBM_SMBUS_BUSY) &&
55+
((config->fsmbm->FSMBMFRT & ___STOP) == ___NONE)) {
56+
/* while packet finish without STOP, the error message is
57+
* FSMBM_SMBUS_BUSY
58+
*/
59+
data->err_code = 0;
60+
} else {
61+
data->err_code = config->fsmbm->FSMBMSTS & FSMBM_STS_MASK;
62+
}
63+
data->state = STATE_COMPLETE;
64+
config->fsmbm->FSMBMPF = FSMBM_COMPLETE_EVENT;
65+
} else {
66+
data->err_code = config->fsmbm->FSMBMSTS & FSMBM_STS_MASK;
67+
data->state = STATE_COMPLETE;
68+
}
69+
} else if (data->state == STATE_RECEIVING) {
70+
uint32_t remain = data->msg_len - data->index;
71+
uint32_t receive_bytes = (remain > FSMBM_BUFFER_SIZE) ? FSMBM_BUFFER_SIZE : remain;
72+
73+
memcpy((void *)&data->msg_buf[data->index], (void *)&config->fsmbm->FSMBMDAT[0],
74+
receive_bytes);
75+
data->index += receive_bytes;
76+
if (config->fsmbm->FSMBMPF & FSMBM_BLOCK_FINISH_EVENT) {
77+
/* continue block */
78+
/* Check next protocl information */
79+
remain = data->msg_len - data->index;
80+
uint32_t NextLen =
81+
(remain > FSMBM_BUFFER_SIZE) ? FSMBM_BUFFER_SIZE : remain;
82+
/* Increase CNT setting let hw can't match counter */
83+
config->fsmbm->FSMBMPRTC_C += NextLen;
84+
/* If it was the last protocol recover the correct length value */
85+
if (data->msg_len == (data->index + NextLen)) {
86+
config->fsmbm->FSMBMPRTC_C -= 1;
87+
}
88+
config->fsmbm->FSMBMPF = FSMBM_BLOCK_FINISH_EVENT;
89+
} else if (config->fsmbm->FSMBMPF & FSMBM_COMPLETE_EVENT) {
90+
/* complete */
91+
if (((config->fsmbm->FSMBMSTS & FSMBM_STS_MASK) == FSMBM_SMBUS_BUSY) &&
92+
((config->fsmbm->FSMBMFRT & ___STOP) == ___NONE)) {
93+
/* while packet finish without STOP, the error message is
94+
* FSMBM_SMBUS_BUSY
95+
*/
96+
data->err_code = 0;
97+
} else {
98+
data->err_code = config->fsmbm->FSMBMSTS & FSMBM_STS_MASK;
99+
}
100+
data->state = STATE_COMPLETE;
101+
config->fsmbm->FSMBMPF = FSMBM_COMPLETE_EVENT;
102+
} else {
103+
data->err_code = config->fsmbm->FSMBMSTS & FSMBM_STS_MASK;
104+
data->state = STATE_COMPLETE;
105+
}
106+
} else if (data->state == STATE_COMPLETE) {
107+
config->fsmbm->FSMBMPF = (FSMBM_COMPLETE_EVENT | FSMBM_BLOCK_FINISH_EVENT);
108+
}
109+
}
110+
111+
static int i2c_kb1200_poll_write(const struct device *dev, struct i2c_msg msg, uint16_t addr)
112+
{
113+
const struct i2c_kb1200_config *config = dev->config;
114+
struct i2c_kb1200_data *data = dev->data;
115+
uint8_t send_bytes;
116+
117+
if (msg.flags & I2C_MSG_STOP) {
118+
/* No CMD, No CNT, No PEC, with STOP*/
119+
config->fsmbm->FSMBMFRT = ___STOP;
120+
} else {
121+
/* No CMD, No CNT, No PEC, no STOP*/
122+
config->fsmbm->FSMBMFRT = ___NONE;
123+
}
124+
data->msg_len = msg.len;
125+
data->msg_buf = msg.buf;
126+
data->msg_flags = msg.flags;
127+
data->state = STATE_IDLE;
128+
data->index = 0;
129+
data->err_code = 0;
130+
131+
send_bytes = (msg.len > FSMBM_BUFFER_SIZE) ? FSMBM_BUFFER_SIZE : msg.len;
132+
memcpy((void *)&config->fsmbm->FSMBMDAT[0], (void *)&data->msg_buf[data->index],
133+
send_bytes);
134+
data->index += send_bytes;
135+
data->state = STATE_SENDING;
136+
137+
config->fsmbm->FSMBMCMD = 0;
138+
config->fsmbm->FSMBMADR = (addr & ~BIT(0)) | FSMBM_WRITE;
139+
config->fsmbm->FSMBMPF = (FSMBM_COMPLETE_EVENT | FSMBM_BLOCK_FINISH_EVENT);
140+
/* If data over bufferSize increase 1 to force continue transmit */
141+
if (msg.len >= (FSMBM_BUFFER_SIZE + 1)) {
142+
config->fsmbm->FSMBMPRTC_C = FSMBM_BUFFER_SIZE + 1;
143+
} else {
144+
config->fsmbm->FSMBMPRTC_C = send_bytes;
145+
}
146+
config->fsmbm->FSMBMIE = (FSMBM_COMPLETE_EVENT | FSMBM_BLOCK_FINISH_EVENT);
147+
config->fsmbm->FSMBMPRTC_P = FLEXIBLE_PROTOCOL;
148+
while (data->state != STATE_COMPLETE)
149+
;
150+
data->state = STATE_IDLE;
151+
if (data->err_code != 0) {
152+
/* reset HW */
153+
config->fsmbm->FSMBMCFG |= FSMBM_HW_RESET;
154+
return data->err_code;
155+
}
156+
return 0;
157+
}
158+
159+
static int i2c_kb1200_poll_read(const struct device *dev, struct i2c_msg msg, uint16_t addr)
160+
{
161+
const struct i2c_kb1200_config *config = dev->config;
162+
struct i2c_kb1200_data *data = dev->data;
163+
164+
if (msg.flags & I2C_MSG_STOP) {
165+
/* No CMD, No CNT, No PEC, with STOP*/
166+
config->fsmbm->FSMBMFRT = ___STOP;
167+
} else {
168+
/* No CMD, No CNT, No PEC, no STOP*/
169+
config->fsmbm->FSMBMFRT = ___NONE;
170+
}
171+
data->msg_len = msg.len;
172+
data->msg_buf = msg.buf;
173+
data->msg_flags = msg.flags;
174+
data->state = STATE_IDLE;
175+
data->index = 0;
176+
data->err_code = 0;
177+
data->state = STATE_RECEIVING;
178+
179+
config->fsmbm->FSMBMCMD = 0;
180+
config->fsmbm->FSMBMADR = (addr & ~BIT(0)) | FSMBM_READ;
181+
config->fsmbm->FSMBMPF = (FSMBM_COMPLETE_EVENT | FSMBM_BLOCK_FINISH_EVENT);
182+
/* If data over bufferSize increase 1 to force continue receive */
183+
if (msg.len >= (FSMBM_BUFFER_SIZE + 1)) {
184+
config->fsmbm->FSMBMPRTC_C = FSMBM_BUFFER_SIZE + 1;
185+
} else {
186+
config->fsmbm->FSMBMPRTC_C = msg.len;
187+
}
188+
config->fsmbm->FSMBMIE = (FSMBM_COMPLETE_EVENT | FSMBM_BLOCK_FINISH_EVENT);
189+
config->fsmbm->FSMBMPRTC_P = FLEXIBLE_PROTOCOL;
190+
while (data->state != STATE_COMPLETE)
191+
;
192+
data->state = STATE_IDLE;
193+
if (data->err_code != 0) {
194+
/* reset HW */
195+
config->fsmbm->FSMBMCFG |= FSMBM_HW_RESET;
196+
return data->err_code;
197+
}
198+
return 0;
199+
}
200+
201+
/* I2C Master api functions */
202+
static int i2c_kb1200_configure(const struct device *dev, uint32_t dev_config)
203+
{
204+
const struct i2c_kb1200_config *config = dev->config;
205+
206+
if (!(dev_config & I2C_MODE_CONTROLLER)) {
207+
return -ENOTSUP;
208+
}
209+
210+
if (dev_config & I2C_ADDR_10_BITS) {
211+
return -ENOTSUP;
212+
}
213+
214+
uint32_t speed = I2C_SPEED_GET(dev_config);
215+
216+
switch (speed) {
217+
case I2C_SPEED_STANDARD:
218+
config->fsmbm->FSMBMCFG = (FSMBM_CLK_100K << FSMBM_CLK_POS);
219+
break;
220+
case I2C_SPEED_FAST:
221+
config->fsmbm->FSMBMCFG = (FSMBM_CLK_400K << FSMBM_CLK_POS);
222+
break;
223+
case I2C_SPEED_FAST_PLUS:
224+
config->fsmbm->FSMBMCFG = (FSMBM_CLK_1M << FSMBM_CLK_POS);
225+
break;
226+
default:
227+
return -EINVAL;
228+
}
229+
230+
config->fsmbm->FSMBMPF = (FSMBM_COMPLETE_EVENT | FSMBM_BLOCK_FINISH_EVENT);
231+
config->fsmbm->FSMBMIE = (FSMBM_COMPLETE_EVENT | FSMBM_BLOCK_FINISH_EVENT);
232+
/* HW reset, Enable FSMBM function, Timeout function*/
233+
config->fsmbm->FSMBMCFG |= FSMBM_HW_RESET | FSMBM_TIMEOUT_ENABLE | FSMBM_FUNCTION_ENABLE;
234+
235+
return 0;
236+
}
237+
238+
static int i2c_kb1200_get_config(const struct device *dev, uint32_t *dev_config)
239+
{
240+
const struct i2c_kb1200_config *config = dev->config;
241+
242+
if ((config->fsmbm->FSMBMCFG & FSMBM_FUNCTION_ENABLE) == 0x00) {
243+
printk("Cannot find i2c controller on 0x%p!\n", config->fsmbm);
244+
return -EIO;
245+
}
246+
247+
switch ((config->fsmbm->FSMBMCFG >> FSMBM_CLK_POS) & FSMBM_CLK_MASK) {
248+
case FSMBM_CLK_100K:
249+
*dev_config = I2C_MODE_CONTROLLER | I2C_SPEED_SET(I2C_SPEED_STANDARD);
250+
break;
251+
case FSMBM_CLK_400K:
252+
*dev_config = I2C_MODE_CONTROLLER | I2C_SPEED_SET(I2C_SPEED_FAST);
253+
break;
254+
case FSMBM_CLK_1M:
255+
*dev_config = I2C_MODE_CONTROLLER | I2C_SPEED_SET(I2C_SPEED_FAST_PLUS);
256+
break;
257+
default:
258+
return -ERANGE;
259+
}
260+
261+
return 0;
262+
}
263+
264+
static int i2c_kb1200_transfer(const struct device *dev, struct i2c_msg *msgs, uint8_t num_msgs,
265+
uint16_t addr)
266+
{
267+
struct i2c_kb1200_data *data = dev->data;
268+
int ret;
269+
270+
/* get the mutex */
271+
k_sem_take(&data->mutex, K_FOREVER);
272+
for (int i = 0U; i < num_msgs; i++) {
273+
if ((msgs[i].flags & I2C_MSG_RW_MASK) == I2C_MSG_WRITE) {
274+
ret = i2c_kb1200_poll_write(dev, msgs[i], addr);
275+
if (ret) {
276+
printk("%s Write error: 0x%X\n", dev->name, ret);
277+
break;
278+
}
279+
} else {
280+
ret = i2c_kb1200_poll_read(dev, msgs[i], addr);
281+
if (ret) {
282+
printk("%s Read error: 0x%X\n", dev->name, ret);
283+
break;
284+
}
285+
}
286+
}
287+
/* release the mutex */
288+
k_sem_give(&data->mutex);
289+
290+
return ret;
291+
}
292+
293+
/* I2C Master driver registration */
294+
static const struct i2c_driver_api i2c_kb1200_api = {
295+
.configure = i2c_kb1200_configure,
296+
.get_config = i2c_kb1200_get_config,
297+
.transfer = i2c_kb1200_transfer,
298+
};
299+
300+
#define KB1200_FSMBM_DEV(inst) DEVICE_DT_INST_GET(inst),
301+
static const struct device *const fsmbm_devices[] = {DT_INST_FOREACH_STATUS_OKAY(KB1200_FSMBM_DEV)};
302+
static void i2c_kb1200_isr_wrap(void)
303+
{
304+
for (size_t i = 0; i < ARRAY_SIZE(fsmbm_devices); i++) {
305+
const struct device *dev_ = fsmbm_devices[i];
306+
const struct i2c_kb1200_config *config = dev_->config;
307+
308+
if (config->fsmbm->FSMBMIE & config->fsmbm->FSMBMPF) {
309+
i2c_kb1200_isr(dev_);
310+
}
311+
}
312+
}
313+
314+
static bool init_irq = true;
315+
static void kb1200_fsmbm_irq_init(void)
316+
{
317+
if (init_irq) {
318+
init_irq = false;
319+
IRQ_CONNECT(DT_INST_IRQN(0), DT_INST_IRQ(0, priority), i2c_kb1200_isr_wrap, NULL,
320+
0);
321+
irq_enable(DT_INST_IRQN(0));
322+
}
323+
}
324+
325+
static int i2c_kb1200_init(const struct device *dev)
326+
{
327+
int ret;
328+
const struct i2c_kb1200_config *config = dev->config;
329+
struct i2c_kb1200_data *data = dev->data;
330+
331+
ret = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT);
332+
if (ret != 0) {
333+
return ret;
334+
}
335+
336+
/* init mutex */
337+
k_sem_init(&data->mutex, 1, 1);
338+
kb1200_fsmbm_irq_init();
339+
340+
return 0;
341+
}
342+
343+
#define I2C_KB1200_DEVICE(inst) \
344+
PINCTRL_DT_INST_DEFINE(inst); \
345+
static struct i2c_kb1200_data i2c_kb1200_data_##inst; \
346+
static const struct i2c_kb1200_config i2c_kb1200_config_##inst = { \
347+
.fsmbm = (struct fsmbm_regs *)DT_INST_REG_ADDR(inst), \
348+
.pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(inst), \
349+
}; \
350+
DEVICE_DT_INST_DEFINE(inst, &i2c_kb1200_init, NULL, &i2c_kb1200_data_##inst, \
351+
&i2c_kb1200_config_##inst, PRE_KERNEL_1, \
352+
CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &i2c_kb1200_api);
353+
354+
DT_INST_FOREACH_STATUS_OKAY(I2C_KB1200_DEVICE)

0 commit comments

Comments
 (0)