xref: /optee_os/core/drivers/i2c/atmel_i2c.c (revision d2b4dffde58cd08c7ca38a1e98867fc1802cb6f9)
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_driver.h>
12 #include <libfdt.h>
13 #include <matrix.h>
14 #include <platform_config.h>
15 #include <string.h>
16 
17 #define TWIHS_CR		0x0
18 #define TWIHS_CR_SWRST		BIT(7)
19 #define TWIHS_CR_SVDIS		BIT(5)
20 #define TWIHS_CR_MSEN		BIT(2)
21 #define TWIHS_CR_STOP		BIT(1)
22 #define TWIHS_CR_START		BIT(0)
23 
24 #define TWIHS_MMR		0x4
25 #define TWIHS_MMR_DADR_SHIFT	16
26 #define TWIHS_MMR_DADR_MASK	0x7F
27 #define TWIHS_MMR_MREAD		BIT32(12)
28 
29 #define TWIHS_CWGR		0x10
30 #define TWIHS_CWGR_HOLD_SHIFT	24
31 #define TWIHS_CWGR_HOLD_MAX	0x1F
32 #define TWIHS_CWGR_CKDIV_SHIFT	16
33 #define TWIHS_CWGR_CKDIV_MAX	0x7
34 #define TWIHS_CWGR_CHDIV_SHIFT	8
35 
36 #define TWIHS_CKSRC	BIT32(20)
37 
38 #define TWIHS_SR	0x20
39 #define TWIHS_SR_NACK	BIT32(8)
40 #define TWIHS_SR_TXRDY	BIT32(2)
41 #define TWIHS_SR_RXRDY	BIT32(1)
42 #define TWIHS_SR_TXCOMP	BIT32(0)
43 
44 #define TWIHS_RHR	0x30
45 #define TWIHS_THR	0x34
46 
47 #define TWIHS_WPMR		0xE4
48 #define TWIHS_WPMR_WPKEY	SHIFT_U32(0x545749, 8)
49 
50 #define I2C_BUS_FREQ	400000
51 
52 struct atmel_i2c {
53 	uint32_t sda_hold_time;
54 	vaddr_t base;
55 	struct clk *clk;
56 	struct i2c_ctrl i2c_ctrl;
57 };
58 
59 static struct atmel_i2c *atmel_i2c_from_i2c_ctrl(struct i2c_ctrl *i2c_ctrl)
60 {
61 	return container_of(i2c_ctrl, struct atmel_i2c, i2c_ctrl);
62 }
63 
64 static TEE_Result atmel_i2c_send_one_byte(struct atmel_i2c *i2c, uint8_t byte)
65 {
66 	uint32_t sr = 0;
67 
68 	io_write32(i2c->base + TWIHS_THR, byte);
69 
70 	while (true) {
71 		sr = io_read32(i2c->base + TWIHS_SR);
72 		if (sr & TWIHS_SR_NACK) {
73 			EMSG("I2C received NACK while writing");
74 			return TEE_ERROR_GENERIC;
75 		}
76 		if (sr & TWIHS_SR_TXRDY)
77 			break;
78 	}
79 
80 	return TEE_SUCCESS;
81 }
82 
83 static void atmel_i2c_wait_txcomp(struct atmel_i2c *i2c)
84 {
85 	uint32_t sr = 0;
86 
87 	while (true) {
88 		sr = io_read32(i2c->base + TWIHS_SR);
89 		if (sr & TWIHS_SR_TXCOMP)
90 			return;
91 	}
92 }
93 
94 static void atmel_i2c_send_start(struct atmel_i2c *i2c)
95 {
96 	io_write32(i2c->base + TWIHS_CR, TWIHS_CR_START);
97 }
98 
99 static void atmel_i2c_send_stop(struct atmel_i2c *i2c)
100 {
101 	io_write32(i2c->base + TWIHS_CR, TWIHS_CR_STOP);
102 }
103 
104 static TEE_Result atmel_i2c_write_data_no_stop(struct i2c_dev *i2c_dev,
105 					       const uint8_t *buf, size_t len)
106 {
107 	size_t i = 0;
108 	TEE_Result res = TEE_ERROR_GENERIC;
109 	struct atmel_i2c *i2c = atmel_i2c_from_i2c_ctrl(i2c_dev->ctrl);
110 	uint32_t mmr = SHIFT_U32(i2c_dev->addr, TWIHS_MMR_DADR_SHIFT);
111 
112 	io_write32(i2c->base + TWIHS_MMR, mmr);
113 
114 	for (i = 0; i < len; i++) {
115 		res = atmel_i2c_send_one_byte(i2c, buf[i]);
116 		if (res)
117 			return res;
118 	}
119 
120 	return TEE_SUCCESS;
121 }
122 
123 static TEE_Result atmel_i2c_write_data(struct i2c_dev *i2c_dev,
124 				       const uint8_t *buf, size_t len)
125 {
126 	TEE_Result res = TEE_ERROR_GENERIC;
127 	struct atmel_i2c *i2c = atmel_i2c_from_i2c_ctrl(i2c_dev->ctrl);
128 
129 	res = atmel_i2c_write_data_no_stop(i2c_dev, buf, len);
130 	if (res)
131 		return res;
132 
133 	atmel_i2c_send_stop(i2c);
134 	atmel_i2c_wait_txcomp(i2c);
135 
136 	return TEE_SUCCESS;
137 }
138 
139 static TEE_Result atmel_i2c_recv_one_byte(struct atmel_i2c *i2c,
140 					  uint8_t *byte)
141 {
142 	uint32_t sr = 0;
143 
144 	while (true) {
145 		sr = io_read32(i2c->base + TWIHS_SR);
146 		if (sr & TWIHS_SR_NACK) {
147 			EMSG("I2C received NACK while reading");
148 			return TEE_ERROR_GENERIC;
149 		}
150 		if (sr & TWIHS_SR_RXRDY)
151 			break;
152 	}
153 
154 	*byte = io_read32(i2c->base + TWIHS_RHR);
155 
156 	return TEE_SUCCESS;
157 }
158 
159 static TEE_Result atmel_i2c_read_data(struct i2c_dev *i2c_dev, uint8_t *buf,
160 				      size_t len)
161 {
162 	size_t i = 0;
163 	TEE_Result res = TEE_ERROR_GENERIC;
164 	struct atmel_i2c *i2c = atmel_i2c_from_i2c_ctrl(i2c_dev->ctrl);
165 	uint32_t mmr = TWIHS_MMR_MREAD | SHIFT_U32(i2c_dev->addr,
166 						   TWIHS_MMR_DADR_SHIFT);
167 
168 	io_write32(i2c->base + TWIHS_MMR, mmr);
169 
170 	atmel_i2c_send_start(i2c);
171 
172 	for (i = 0; i < len; i++) {
173 		if (i == len - 1)
174 			atmel_i2c_send_stop(i2c);
175 
176 		res = atmel_i2c_recv_one_byte(i2c, &buf[i]);
177 		if (res)
178 			return res;
179 	}
180 
181 	atmel_i2c_wait_txcomp(i2c);
182 
183 	return TEE_SUCCESS;
184 }
185 
186 static TEE_Result atmel_i2c_smbus(struct i2c_dev *i2c_dev,
187 				  enum i2c_smbus_dir dir,
188 				  enum i2c_smbus_protocol proto __unused,
189 				  uint8_t cmd_code,
190 				  uint8_t buf[I2C_SMBUS_MAX_BUF_SIZE],
191 				  size_t len)
192 {
193 	TEE_Result res = TEE_ERROR_GENERIC;
194 
195 	/* Send command code first */
196 	res = atmel_i2c_write_data_no_stop(i2c_dev, &cmd_code, 1);
197 	if (res)
198 		return res;
199 
200 	if (dir == I2C_SMBUS_READ)
201 		return atmel_i2c_read_data(i2c_dev, buf, len);
202 	else
203 		return atmel_i2c_write_data(i2c_dev, buf, len);
204 }
205 
206 static unsigned int flsi(unsigned int val)
207 {
208 	if (val == 0)
209 		return 0;
210 
211 	return sizeof(unsigned int) * 8 - __builtin_clz(val);
212 }
213 
214 static TEE_Result atmel_i2c_init_clk(struct atmel_i2c *i2c)
215 {
216 	long div = 0;
217 	long hold = 0;
218 	uint32_t cwgr = 0;
219 	uint32_t cxdiv = 0;
220 	uint32_t ckdiv = 0;
221 	unsigned long clk = clk_get_rate(i2c->clk);
222 
223 	/*
224 	 * Since we will configure both CHDIV and CLDIV with the same value
225 	 * use 2 * clk
226 	 */
227 	div = UDIV_ROUND_NEAREST(clk, 2 * I2C_BUS_FREQ) - 3;
228 	if (div < 0)
229 		div = 0;
230 
231 	/* CHDIV/CLDIV are on 8 bits, CKDIV on 3 bits */
232 	ckdiv = flsi(div >> 8);
233 	if (ckdiv > TWIHS_CWGR_CKDIV_MAX) {
234 		EMSG("CKDIV value too large");
235 		return TEE_ERROR_BAD_PARAMETERS;
236 	}
237 	cxdiv = div >> ckdiv;
238 
239 	if (i2c->sda_hold_time) {
240 		/* hold_time = (HOLD + 3) x tperipheral clock */
241 		hold = UDIV_ROUND_NEAREST(i2c->sda_hold_time * clk, 1000000000);
242 		hold -= 3;
243 		if (hold < 0 || hold > TWIHS_CWGR_HOLD_MAX) {
244 			EMSG("Incorrect hold value");
245 			return TEE_ERROR_BAD_PARAMETERS;
246 		}
247 
248 		cwgr |= hold << TWIHS_CWGR_HOLD_SHIFT;
249 	}
250 
251 	cwgr |= ckdiv << TWIHS_CWGR_CKDIV_SHIFT;
252 	/* CHDIV == CLDIV */
253 	cwgr |= cxdiv << TWIHS_CWGR_CHDIV_SHIFT;
254 	cwgr |= cxdiv;
255 	io_write32(i2c->base + TWIHS_CWGR, cwgr);
256 
257 	return TEE_SUCCESS;
258 }
259 
260 static TEE_Result atmel_i2c_init_hw(struct atmel_i2c *i2c)
261 {
262 	/* Unlock TWIHS IP */
263 	io_write32(i2c->base + TWIHS_WPMR, TWIHS_WPMR_WPKEY);
264 
265 	/* Configure master mode */
266 	io_write32(i2c->base + TWIHS_CR, TWIHS_CR_SWRST);
267 
268 	io_write32(i2c->base + TWIHS_CR, TWIHS_CR_SVDIS);
269 	io_write32(i2c->base + TWIHS_CR, TWIHS_CR_MSEN);
270 
271 	return atmel_i2c_init_clk(i2c);
272 }
273 
274 static const struct i2c_ctrl_ops atmel_i2c_ops = {
275 	.read = atmel_i2c_read_data,
276 	.write = atmel_i2c_write_data,
277 	.smbus = atmel_i2c_smbus,
278 };
279 
280 static struct i2c_dev *atmel_i2c_get_dt_i2c(struct dt_driver_phandle_args *a,
281 					    void *data, TEE_Result *res)
282 {
283 	struct i2c_dev *i2c_dev = NULL;
284 	struct i2c_ctrl *i2c_ctrl = data;
285 
286 	i2c_dev = i2c_create_dev(i2c_ctrl, a->fdt, a->phandle_node);
287 	if (!i2c_dev) {
288 		*res = TEE_ERROR_OUT_OF_MEMORY;
289 		return NULL;
290 	}
291 
292 	*res = TEE_SUCCESS;
293 	return i2c_dev;
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