1 /*
2  * Copyright (c) 2023 Intel Corporation.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include "iut.h"
8 #include "sedi_driver_i2c.h"
9 #include "sedi_driver_rtc.h"
10 #include <zephyr/drivers/i2c.h>
11 
12 #define DT_DRV_COMPAT intel_sedi_i2c
13 
14 #define LOG_I2C_BUS       (0)
15 #define LOG_I2C_DEV_ADDR  (0x5e)
16 #define LOG_I2C_RETRY_CNT (3)
17 #define LOG_I2C_DATA_SIZE (128)
18 
19 #define POLLING (1 << 0)
20 #define IRQ     (1 << 1)
21 #define ASYNC   (1 << 2)
22 
get_sec(void)23 static uint32_t get_sec(void)
24 {
25 	uint64_t start = sedi_rtc_get_us();
26 
27 	return (uint32_t)(start / 1000 / 1000);
28 }
29 
30 #if defined(CONFIG_I2C_ASYNC)
31 static int async_req;
32 static int async_rpl;
33 static int async_err;
async_cb(int result,void * userdata)34 static void async_cb(int result, void *userdata)
35 {
36 	async_rpl++;
37 }
38 #endif
39 
impl_test_log_i2c(uint32_t sec_run,int mode,uint32_t * err_cnt)40 static int impl_test_log_i2c(uint32_t sec_run, int mode, uint32_t *err_cnt)
41 {
42 	int ret;
43 	uint8_t data[LOG_I2C_DATA_SIZE];
44 	const struct device *i2c_dev = DEVICE_DT_GET(DT_DRV_INST(0));
45 
46 	uint32_t sec_start = get_sec();
47 	int loop = 0;
48 	int retry = 0;
49 	uint32_t error = 0;
50 
51 	uint32_t i2c_cfg = I2C_SPEED_SET(I2C_SPEED_FAST) | I2C_MODE_CONTROLLER;
52 
53 	if (!i2c_dev) {
54 		return -ENODEV;
55 	}
56 
57 	ret = i2c_configure(i2c_dev, i2c_cfg);
58 	if (ret) {
59 		return -EINVAL;
60 	}
61 
62 	while (1) {
63 		for (int i = 0; i < sizeof(data) - 2; i++) {
64 			data[i] = ((loop + i) % 10) + 0x30;
65 		}
66 		data[sizeof(data) - 2] = '\n';
67 		data[sizeof(data) - 1] = '\r';
68 
69 		if (mode & POLLING) {
70 			ret = sedi_i2c_master_poll_write(LOG_I2C_BUS, LOG_I2C_DEV_ADDR, data,
71 							 sizeof(data), false);
72 #if defined(CONFIG_I2C_ASYNC)
73 		} else if (mode & ASYNC) {
74 			struct i2c_msg msg;
75 
76 			msg.buf = (uint8_t *)data;
77 			msg.len = sizeof(data);
78 			msg.flags = I2C_MSG_WRITE | I2C_MSG_STOP;
79 			ret = i2c_transfer_async(i2c_dev, &msg, 1, LOG_I2C_DEV_ADDR, async_cb,
80 						 (void *)loop);
81 			async_req++;
82 			if (ret == -EWOULDBLOCK) {
83 				k_sleep(K_MSEC(5));
84 				async_err++;
85 				ret = 0; /* recover async busy */
86 			}
87 #endif
88 		} else {
89 			ret = i2c_write(i2c_dev, data, sizeof(data), LOG_I2C_DEV_ADDR);
90 		}
91 
92 		if (ret) {
93 			if (retry >= LOG_I2C_RETRY_CNT) {
94 				break;
95 			}
96 
97 			retry++;
98 			error++;
99 			continue;
100 		}
101 
102 		loop++;
103 		if (!(loop % 100)) {
104 			iut_print("\ttransfer %d-%d: error=%d\n", loop - 100, loop, error);
105 			retry = 0;
106 			*err_cnt += error;
107 			error = 0;
108 			k_msleep(100);
109 
110 			if ((get_sec() - sec_start) >= sec_run) {
111 				break;
112 			}
113 		}
114 	}
115 
116 	return ret;
117 }
118 
test_log_i2c_polling(int argc,char ** argv)119 static int test_log_i2c_polling(int argc, char **argv)
120 {
121 	uint32_t sec_run = 10;
122 	int ret;
123 	uint32_t err_cnt = 0;
124 
125 	if (argc) {
126 		sec_run = (uint32_t)strtoul(argv[0], NULL, 0);
127 	}
128 
129 	iut_case_print("starting to run %d seconds ...\n", sec_run);
130 
131 	ret = impl_test_log_i2c(sec_run, POLLING, &err_cnt);
132 
133 	iut_case_print("done, ret=%d, err_cnt=%u\n", ret, err_cnt);
134 	TEST_ASSERT_EQUAL(0, ret);
135 
136 	return IUT_ERR_OK;
137 }
138 DEFINE_IUT_CASE(log_i2c_polling, logging, IUT_ATTRI_NONE);
139 
test_log_i2c_irq(int argc,char ** argv)140 static int test_log_i2c_irq(int argc, char **argv)
141 {
142 	uint32_t sec_run = 10;
143 	int ret;
144 	uint32_t err_cnt = 0;
145 
146 	if (argc) {
147 		sec_run = (uint32_t)strtoul(argv[0], NULL, 0);
148 	}
149 
150 	iut_case_print("starting to run %d seconds ...\n", sec_run);
151 
152 	ret = impl_test_log_i2c(sec_run, IRQ, &err_cnt);
153 
154 	iut_case_print("done, ret=%d, err_cnt=%u\n", ret, err_cnt);
155 	TEST_ASSERT_EQUAL(0, ret);
156 
157 	return IUT_ERR_OK;
158 }
159 DEFINE_IUT_CASE(log_i2c_irq, logging, IUT_ATTRI_NONE);
160 
161 #if defined(CONFIG_I2C_ASYNC)
test_log_i2c_async(int argc,char ** argv)162 static int test_log_i2c_async(int argc, char **argv)
163 {
164 	uint32_t sec_run = 10;
165 	int ret;
166 	uint32_t err_cnt = 0;
167 
168 	if (argc) {
169 		sec_run = (uint32_t)strtoul(argv[0], NULL, 0);
170 	}
171 
172 	async_err = 0;
173 	async_req = 0;
174 	async_rpl = 0;
175 
176 	iut_case_print("starting to run %d seconds ...\n", sec_run);
177 
178 	ret = impl_test_log_i2c(sec_run, ASYNC, &err_cnt);
179 
180 	iut_case_print("done, ret=%d, err_cnt=%u\n", ret, err_cnt);
181 	iut_case_print("finish: async_req:%d, async_rpl:%d, async_err:%d\n", async_req, async_rpl,
182 		       async_err);
183 
184 	TEST_ASSERT_EQUAL(0, ret);
185 
186 	return IUT_ERR_OK;
187 }
188 DEFINE_IUT_CASE(log_i2c_async, logging, IUT_ATTRI_NONE);
189 #endif
190