xref: /optee_os/core/drivers/i2c/atmel_i2c.c (revision 1868eb206733e931b6c6c2d85d55e646bc8a2496)
1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright 2021-2023 Microchip
4  */
5 
6 #include <assert.h>
7 #include <drivers/clk.h>
8 #include <drivers/clk_dt.h>
9 #include <drivers/i2c.h>
10 #include <io.h>
11 #include <kernel/dt.h>
12 #include <kernel/dt_driver.h>
13 #include <libfdt.h>
14 #include <matrix.h>
15 #include <platform_config.h>
16 #include <string.h>
17 
18 #define TWIHS_CR		0x0
19 #define TWIHS_CR_SWRST		BIT(7)
20 #define TWIHS_CR_SVDIS		BIT(5)
21 #define TWIHS_CR_MSEN		BIT(2)
22 #define TWIHS_CR_STOP		BIT(1)
23 #define TWIHS_CR_START		BIT(0)
24 
25 #define TWIHS_MMR		0x4
26 #define TWIHS_MMR_DADR_SHIFT	16
27 #define TWIHS_MMR_DADR_MASK	0x7F
28 #define TWIHS_MMR_MREAD		BIT32(12)
29 
30 #define TWIHS_CWGR		0x10
31 #define TWIHS_CWGR_HOLD_SHIFT	24
32 #define TWIHS_CWGR_HOLD_MAX	0x1F
33 #define TWIHS_CWGR_CKDIV_SHIFT	16
34 #define TWIHS_CWGR_CKDIV_MAX	0x7
35 #define TWIHS_CWGR_CHDIV_SHIFT	8
36 
37 #define TWIHS_CKSRC	BIT32(20)
38 
39 #define TWIHS_SR	0x20
40 #define TWIHS_SR_NACK	BIT32(8)
41 #define TWIHS_SR_TXRDY	BIT32(2)
42 #define TWIHS_SR_RXRDY	BIT32(1)
43 #define TWIHS_SR_TXCOMP	BIT32(0)
44 
45 #define TWIHS_RHR	0x30
46 #define TWIHS_THR	0x34
47 
48 #define TWIHS_WPMR		0xE4
49 #define TWIHS_WPMR_WPKEY	SHIFT_U32(0x545749, 8)
50 
51 #define I2C_BUS_FREQ	400000
52 
53 struct atmel_i2c {
54 	uint32_t sda_hold_time;
55 	vaddr_t base;
56 	struct clk *clk;
57 	struct i2c_ctrl i2c_ctrl;
58 };
59 
60 static struct atmel_i2c *atmel_i2c_from_i2c_ctrl(struct i2c_ctrl *i2c_ctrl)
61 {
62 	return container_of(i2c_ctrl, struct atmel_i2c, i2c_ctrl);
63 }
64 
65 static TEE_Result atmel_i2c_send_one_byte(struct atmel_i2c *i2c, uint8_t byte)
66 {
67 	uint32_t sr = 0;
68 
69 	io_write32(i2c->base + TWIHS_THR, byte);
70 
71 	while (true) {
72 		sr = io_read32(i2c->base + TWIHS_SR);
73 		if (sr & TWIHS_SR_NACK) {
74 			EMSG("I2C received NACK while writing");
75 			return TEE_ERROR_GENERIC;
76 		}
77 		if (sr & TWIHS_SR_TXRDY)
78 			break;
79 	}
80 
81 	return TEE_SUCCESS;
82 }
83 
84 static void atmel_i2c_wait_txcomp(struct atmel_i2c *i2c)
85 {
86 	uint32_t sr = 0;
87 
88 	while (true) {
89 		sr = io_read32(i2c->base + TWIHS_SR);
90 		if (sr & TWIHS_SR_TXCOMP)
91 			return;
92 	}
93 }
94 
95 static void atmel_i2c_send_start(struct atmel_i2c *i2c)
96 {
97 	io_write32(i2c->base + TWIHS_CR, TWIHS_CR_START);
98 }
99 
100 static void atmel_i2c_send_stop(struct atmel_i2c *i2c)
101 {
102 	io_write32(i2c->base + TWIHS_CR, TWIHS_CR_STOP);
103 }
104 
105 static TEE_Result atmel_i2c_write_data_no_stop(struct i2c_dev *i2c_dev,
106 					       const uint8_t *buf, size_t len)
107 {
108 	size_t i = 0;
109 	TEE_Result res = TEE_ERROR_GENERIC;
110 	struct atmel_i2c *i2c = atmel_i2c_from_i2c_ctrl(i2c_dev->ctrl);
111 	uint32_t mmr = SHIFT_U32(i2c_dev->addr, TWIHS_MMR_DADR_SHIFT);
112 
113 	io_write32(i2c->base + TWIHS_MMR, mmr);
114 
115 	for (i = 0; i < len; i++) {
116 		res = atmel_i2c_send_one_byte(i2c, buf[i]);
117 		if (res)
118 			return res;
119 	}
120 
121 	return TEE_SUCCESS;
122 }
123 
124 static TEE_Result atmel_i2c_write_data(struct i2c_dev *i2c_dev,
125 				       const uint8_t *buf, size_t len)
126 {
127 	TEE_Result res = TEE_ERROR_GENERIC;
128 	struct atmel_i2c *i2c = atmel_i2c_from_i2c_ctrl(i2c_dev->ctrl);
129 
130 	res = atmel_i2c_write_data_no_stop(i2c_dev, buf, len);
131 	if (res)
132 		return res;
133 
134 	atmel_i2c_send_stop(i2c);
135 	atmel_i2c_wait_txcomp(i2c);
136 
137 	return TEE_SUCCESS;
138 }
139 
140 static TEE_Result atmel_i2c_recv_one_byte(struct atmel_i2c *i2c,
141 					  uint8_t *byte)
142 {
143 	uint32_t sr = 0;
144 
145 	while (true) {
146 		sr = io_read32(i2c->base + TWIHS_SR);
147 		if (sr & TWIHS_SR_NACK) {
148 			EMSG("I2C received NACK while reading");
149 			return TEE_ERROR_GENERIC;
150 		}
151 		if (sr & TWIHS_SR_RXRDY)
152 			break;
153 	}
154 
155 	*byte = io_read32(i2c->base + TWIHS_RHR);
156 
157 	return TEE_SUCCESS;
158 }
159 
160 static TEE_Result atmel_i2c_read_data(struct i2c_dev *i2c_dev, uint8_t *buf,
161 				      size_t len)
162 {
163 	size_t i = 0;
164 	TEE_Result res = TEE_ERROR_GENERIC;
165 	struct atmel_i2c *i2c = atmel_i2c_from_i2c_ctrl(i2c_dev->ctrl);
166 	uint32_t mmr = TWIHS_MMR_MREAD | SHIFT_U32(i2c_dev->addr,
167 						   TWIHS_MMR_DADR_SHIFT);
168 
169 	io_write32(i2c->base + TWIHS_MMR, mmr);
170 
171 	atmel_i2c_send_start(i2c);
172 
173 	for (i = 0; i < len; i++) {
174 		if (i == len - 1)
175 			atmel_i2c_send_stop(i2c);
176 
177 		res = atmel_i2c_recv_one_byte(i2c, &buf[i]);
178 		if (res)
179 			return res;
180 	}
181 
182 	atmel_i2c_wait_txcomp(i2c);
183 
184 	return TEE_SUCCESS;
185 }
186 
187 static TEE_Result atmel_i2c_smbus(struct i2c_dev *i2c_dev,
188 				  enum i2c_smbus_dir dir,
189 				  enum i2c_smbus_protocol proto __unused,
190 				  uint8_t cmd_code,
191 				  uint8_t buf[I2C_SMBUS_MAX_BUF_SIZE],
192 				  size_t len)
193 {
194 	TEE_Result res = TEE_ERROR_GENERIC;
195 
196 	/* Send command code first */
197 	res = atmel_i2c_write_data_no_stop(i2c_dev, &cmd_code, 1);
198 	if (res)
199 		return res;
200 
201 	if (dir == I2C_SMBUS_READ)
202 		return atmel_i2c_read_data(i2c_dev, buf, len);
203 	else
204 		return atmel_i2c_write_data(i2c_dev, buf, len);
205 }
206 
207 static unsigned int flsi(unsigned int val)
208 {
209 	if (val == 0)
210 		return 0;
211 
212 	return sizeof(unsigned int) * 8 - __builtin_clz(val);
213 }
214 
215 static TEE_Result atmel_i2c_init_clk(struct atmel_i2c *i2c)
216 {
217 	long div = 0;
218 	long hold = 0;
219 	uint32_t cwgr = 0;
220 	uint32_t cxdiv = 0;
221 	uint32_t ckdiv = 0;
222 	unsigned long clk = clk_get_rate(i2c->clk);
223 
224 	/*
225 	 * Since we will configure both CHDIV and CLDIV with the same value
226 	 * use 2 * clk
227 	 */
228 	div = UDIV_ROUND_NEAREST(clk, 2 * I2C_BUS_FREQ) - 3;
229 	if (div < 0)
230 		div = 0;
231 
232 	/* CHDIV/CLDIV are on 8 bits, CKDIV on 3 bits */
233 	ckdiv = flsi(div >> 8);
234 	if (ckdiv > TWIHS_CWGR_CKDIV_MAX) {
235 		EMSG("CKDIV value too large");
236 		return TEE_ERROR_BAD_PARAMETERS;
237 	}
238 	cxdiv = div >> ckdiv;
239 
240 	if (i2c->sda_hold_time) {
241 		/* hold_time = (HOLD + 3) x tperipheral clock */
242 		hold = UDIV_ROUND_NEAREST(i2c->sda_hold_time * clk, 1000000000);
243 		hold -= 3;
244 		if (hold < 0 || hold > TWIHS_CWGR_HOLD_MAX) {
245 			EMSG("Incorrect hold value");
246 			return TEE_ERROR_BAD_PARAMETERS;
247 		}
248 
249 		cwgr |= hold << TWIHS_CWGR_HOLD_SHIFT;
250 	}
251 
252 	cwgr |= ckdiv << TWIHS_CWGR_CKDIV_SHIFT;
253 	/* CHDIV == CLDIV */
254 	cwgr |= cxdiv << TWIHS_CWGR_CHDIV_SHIFT;
255 	cwgr |= cxdiv;
256 	io_write32(i2c->base + TWIHS_CWGR, cwgr);
257 
258 	return TEE_SUCCESS;
259 }
260 
261 static TEE_Result atmel_i2c_init_hw(struct atmel_i2c *i2c)
262 {
263 	/* Unlock TWIHS IP */
264 	io_write32(i2c->base + TWIHS_WPMR, TWIHS_WPMR_WPKEY);
265 
266 	/* Configure master mode */
267 	io_write32(i2c->base + TWIHS_CR, TWIHS_CR_SWRST);
268 
269 	io_write32(i2c->base + TWIHS_CR, TWIHS_CR_SVDIS);
270 	io_write32(i2c->base + TWIHS_CR, TWIHS_CR_MSEN);
271 
272 	return atmel_i2c_init_clk(i2c);
273 }
274 
275 static const struct i2c_ctrl_ops atmel_i2c_ops = {
276 	.read = atmel_i2c_read_data,
277 	.write = atmel_i2c_write_data,
278 	.smbus = atmel_i2c_smbus,
279 };
280 
281 static TEE_Result atmel_i2c_get_dt_i2c(struct dt_pargs *args, void *data,
282 				       struct i2c_dev **out_device)
283 {
284 	struct i2c_dev *i2c_dev = NULL;
285 	struct i2c_ctrl *i2c_ctrl = data;
286 
287 	i2c_dev = i2c_create_dev(i2c_ctrl, args->fdt, args->consumer_node);
288 	if (!i2c_dev)
289 		return TEE_ERROR_OUT_OF_MEMORY;
290 
291 	*out_device = i2c_dev;
292 
293 	return TEE_SUCCESS;
294 }
295 
296 static TEE_Result atmel_i2c_node_probe(const void *fdt, int node,
297 				       const void *compat_data __unused)
298 {
299 	size_t size = 0;
300 	const uint32_t *cuint = 0;
301 	unsigned int matrix_id = 0;
302 	struct i2c_ctrl *i2c_ctrl = NULL;
303 	struct atmel_i2c *atmel_i2c = NULL;
304 	TEE_Result res = TEE_ERROR_GENERIC;
305 	int status = fdt_get_status(fdt, node);
306 
307 	if (status != DT_STATUS_OK_SEC)
308 		return TEE_SUCCESS;
309 
310 	atmel_i2c = calloc(1, sizeof(struct atmel_i2c));
311 	if (!atmel_i2c)
312 		return TEE_ERROR_OUT_OF_MEMORY;
313 
314 	i2c_ctrl = &atmel_i2c->i2c_ctrl;
315 	i2c_ctrl->ops = &atmel_i2c_ops;
316 
317 	res = clk_dt_get_by_index(fdt, node, 0, &atmel_i2c->clk);
318 	if (res)
319 		goto err_free;
320 
321 	res = matrix_dt_get_id(fdt, node, &matrix_id);
322 	if (res)
323 		goto err_free;
324 
325 	if (dt_map_dev(fdt, node, &atmel_i2c->base, &size, DT_MAP_AUTO) < 0) {
326 		res = TEE_ERROR_GENERIC;
327 		goto err_free;
328 	}
329 
330 	matrix_configure_periph_secure(matrix_id);
331 
332 	cuint = fdt_getprop(fdt, node, "i2c-sda-hold-time-ns", NULL);
333 	if (cuint)
334 		atmel_i2c->sda_hold_time = fdt32_to_cpu(*cuint);
335 
336 	clk_enable(atmel_i2c->clk);
337 
338 	res = atmel_i2c_init_hw(atmel_i2c);
339 	if (res)
340 		goto err_clk_disable;
341 
342 	res = i2c_register_provider(fdt, node, atmel_i2c_get_dt_i2c, i2c_ctrl);
343 	if (res)
344 		goto err_clk_disable;
345 
346 	return TEE_SUCCESS;
347 
348 err_clk_disable:
349 	clk_disable(atmel_i2c->clk);
350 err_free:
351 	free(atmel_i2c);
352 
353 	return res;
354 }
355 
356 static const struct dt_device_match atmel_i2c_match_table[] = {
357 	{ .compatible = "atmel,sama5d2-i2c" },
358 	{ }
359 };
360 
361 DEFINE_DT_DRIVER(atmel_i2c_dt_driver) = {
362 	.name = "atmel_i2c",
363 	.type = DT_DRIVER_NOTYPE,
364 	.match_table = atmel_i2c_match_table,
365 	.probe = atmel_i2c_node_probe,
366 };
367