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