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