1 /*
2  * Copyright (c) 2022 Intel Corporation
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/drivers/i2c.h>
8 #include <zephyr/kernel.h>
9 #include <zephyr/ztest.h>
10 
11 #define FXOS8700_I2C_ADDR	0x1d
12 
13 /* Reduced regmap for FXOS8700 */
14 #define FXOS8700_REG_STATUS			0x00
15 #define FXOS8700_REG_F_SETUP			0x09
16 #define FXOS8700_REG_WHOAMI			0x0d
17 #define FXOS8700_REG_CTRLREG1			0x2a
18 #define FXOS8700_REG_CTRLREG2			0x2b
19 #define FXOS8700_REG_CTRLREG3			0x2c
20 #define FXOS8700_REG_CTRLREG4			0x2d
21 #define FXOS8700_REG_CTRLREG5			0x2e
22 
23 #define WHOAMI_ID_FXOS8700			0xC7
24 
25 #define FXOS8700_CTRLREG2_RST_MASK		0x40
26 
27 
28 static const struct device *const i2c_bus = DEVICE_DT_GET(DT_NODELABEL(i2c0));
29 
30 /**
31  * Setup and enable the fxos8700 with its max sample rate and
32  * FIFO.
33  */
fxos8700_fifo_cfg(void)34 static int fxos8700_fifo_cfg(void)
35 {
36 	int res;
37 	uint8_t data;
38 
39 	TC_PRINT("Configuring FXOS8700\n");
40 
41 	/* Signal a reset */
42 	i2c_reg_write_byte(i2c_bus, FXOS8700_I2C_ADDR,
43 			   FXOS8700_REG_CTRLREG2, FXOS8700_CTRLREG2_RST_MASK);
44 
45 	k_busy_wait(USEC_PER_MSEC);
46 
47 	TC_PRINT("Getting whoami\n");
48 	res = i2c_reg_read_byte(i2c_bus, FXOS8700_I2C_ADDR,
49 			      FXOS8700_REG_WHOAMI, &data);
50 	if (res != 0) {
51 		TC_PRINT("Could not get WHOAMI value after reset\n");
52 		return TC_FAIL;
53 	}
54 
55 	if (data != WHOAMI_ID_FXOS8700) {
56 		TC_PRINT("Not an FXOS8700 sensor\n");
57 		return TC_FAIL;
58 	}
59 
60 	/* Enable FIFO mode with a watermark of 16 */
61 	res = i2c_reg_write_byte(i2c_bus,
62 			    FXOS8700_I2C_ADDR,
63 			    FXOS8700_REG_F_SETUP,
64 			    0x50);
65 
66 	if (res != 0) {
67 		TC_PRINT("Failed to setup FIFO\n");
68 		return TC_FAIL;
69 	}
70 
71 	/* Activate the sensor */
72 	res = i2c_reg_write_byte(i2c_bus,
73 			    FXOS8700_I2C_ADDR,
74 			    FXOS8700_REG_CTRLREG1,
75 			    0x01);
76 
77 	if (res != 0) {
78 		TC_PRINT("Failed to activate the sensor\n");
79 		return TC_FAIL;
80 	}
81 
82 	TC_PRINT("Configured FXOS8700\n");
83 
84 	return TC_PASS;
85 }
86 
87 #define FXOS8700_XFERS 10
88 
89 static uint8_t sample_buf[64];
90 static uint8_t reg = 0x01;
91 static struct i2c_msg msgs[2] = { { .buf = &reg, .len = 1, .flags = I2C_MSG_WRITE },
92 				  { .buf = sample_buf,
93 				    .len = sizeof(sample_buf),
94 				    .flags = I2C_MSG_READ | I2C_MSG_RESTART | I2C_MSG_STOP } };
95 
96 /* Read 3 axis 14 bit (2 byte) data */
97 
test_i2c_fxos8700_sync(void)98 static int test_i2c_fxos8700_sync(void)
99 {
100 	int res;
101 
102 	TC_PRINT("fxos8700 sync test ...\n");
103 	fxos8700_fifo_cfg();
104 
105 	for (int i = 0; i < FXOS8700_XFERS; i++) {
106 		res = i2c_transfer(i2c_bus,
107 			     msgs,
108 			     2,
109 			     FXOS8700_I2C_ADDR);
110 
111 		zassert_ok(res, "expected xfer success");
112 	}
113 
114 	TC_PRINT("fxos8700 async test pass\n");
115 	return TC_PASS;
116 }
117 
ZTEST(frdm_k64f_i2c,test_i2c_sync)118 ZTEST(frdm_k64f_i2c, test_i2c_sync)
119 {
120 	zassert_equal(test_i2c_fxos8700_sync(), TC_PASS, "i2c sync test");
121 }
122 
123 static uint32_t xfer_count;
124 static int xfer_res;
125 static struct k_sem xfer_sem;
126 
test_i2c_fxos8700_async_cb(const struct device * dev,int result,void * userdata)127 static void test_i2c_fxos8700_async_cb(const struct device *dev, int result, void *userdata)
128 {
129 	int res;
130 
131 	if (result != 0) {
132 		xfer_res = result;
133 		k_sem_give(&xfer_sem);
134 		return;
135 	}
136 
137 	if (xfer_count >= FXOS8700_XFERS) {
138 		xfer_res = 0;
139 		k_sem_give(&xfer_sem);
140 		return;
141 	}
142 
143 	xfer_count++;
144 	res = i2c_transfer_cb(dev, msgs, 2, FXOS8700_I2C_ADDR,
145 				 test_i2c_fxos8700_async_cb, NULL);
146 	zassert_ok(res, "expected ok for async transfer start");
147 }
148 
149 
test_i2c_fxos8700_transfer_cb(void)150 static int test_i2c_fxos8700_transfer_cb(void)
151 {
152 	int res;
153 
154 	TC_PRINT("fxos8700 async test ...\n");
155 
156 	fxos8700_fifo_cfg();
157 
158 	xfer_count = 0;
159 	k_sem_init(&xfer_sem, 0, 1);
160 
161 	res = i2c_transfer_cb(i2c_bus, msgs, 2, FXOS8700_I2C_ADDR,
162 				 test_i2c_fxos8700_async_cb, NULL);
163 	zassert_ok(res, "expected ok for async transfer start");
164 
165 	k_sem_take(&xfer_sem, K_FOREVER);
166 
167 	zassert_ok(xfer_res, "expected success of xfer");
168 
169 	TC_PRINT("fxos8700 async test pass\n");
170 	return TC_PASS;
171 }
172 
ZTEST(frdm_k64f_i2c,test_i2c_transfer_cb)173 ZTEST(frdm_k64f_i2c, test_i2c_transfer_cb)
174 {
175 	zassert_equal(test_i2c_fxos8700_transfer_cb(), TC_PASS, "i2c_transfer_cb");
176 }
177 
178 
179 
180 static struct k_poll_signal xfer_signal;
181 
182 /* Mimic synchronous call with async_sem data and callback */
test_i2c_fxos8700_transfer_signal(void)183 static int test_i2c_fxos8700_transfer_signal(void)
184 {
185 	int res;
186 
187 	TC_PRINT("fxos8700 i2c_transfer_signal test ...\n");
188 
189 	uint8_t usample_buf[64];
190 	uint8_t ureg = 0x01;
191 	struct i2c_msg umsgs[2] = { { .buf = &ureg, .len = 1, .flags = I2C_MSG_WRITE },
192 				  { .buf = usample_buf,
193 				    .len = sizeof(usample_buf),
194 				    .flags = I2C_MSG_READ | I2C_MSG_RESTART | I2C_MSG_STOP } };
195 
196 	for (int i = 0; i < 2; i++) {
197 		TC_PRINT("umsgs[%d].flags %x\n", i, umsgs[i].flags);
198 	}
199 
200 	k_poll_signal_init(&xfer_signal);
201 
202 	struct k_poll_event events[1] = {
203 		K_POLL_EVENT_INITIALIZER(K_POLL_TYPE_SIGNAL, K_POLL_MODE_NOTIFY_ONLY, &xfer_signal),
204 	};
205 
206 	fxos8700_fifo_cfg();
207 
208 	for (int i = 0; i < FXOS8700_XFERS; i++) {
209 		res = i2c_transfer_signal(i2c_bus, umsgs, 2, FXOS8700_I2C_ADDR,
210 					 &xfer_signal);
211 		TC_PRINT("result of transfer_signal, %d\n", res);
212 
213 		zassert_ok(res, "expected ok for async transfer start");
214 
215 		TC_PRINT("polling for completion\n");
216 
217 		/* Poll signal */
218 		k_poll(events, 1, K_FOREVER);
219 
220 		unsigned int signaled;
221 		int signal_result;
222 
223 		k_poll_signal_check(&xfer_signal, &signaled, &signal_result);
224 
225 		TC_PRINT("signaled %d, signal result %d\n", signaled, signal_result);
226 
227 		zassert_true(signaled > 0, "expected signaled to be non-zero");
228 		zassert_ok(signal_result, "expected result to be ok\n");
229 
230 		TC_PRINT("resetting signal\n");
231 		k_poll_signal_reset(&xfer_signal);
232 	}
233 
234 	TC_PRINT("fxos8700 i2c_transfer_signal test pass\n");
235 	return TC_PASS;
236 }
237 
ZTEST(frdm_k64f_i2c,test_i2c_transfer_signal)238 ZTEST(frdm_k64f_i2c, test_i2c_transfer_signal)
239 {
240 	zassert_equal(test_i2c_fxos8700_transfer_signal(), TC_PASS,
241 		"i2c_transfer_signal supervisor mode");
242 }
243 
244 ZTEST_SUITE(frdm_k64f_i2c, NULL, NULL, NULL, NULL, NULL);
245