Branch data Line data Source code
1 : : /* SPDX-License-Identifier: Apache-2.0 */
2 : : /*
3 : : * Copyright © 2023 Calian Ltd. All rights reserved.
4 : : *
5 : : * Driver for the Xilinx AXI IIC Bus Interface.
6 : : * This is an FPGA logic core as described by Xilinx document PG090.
7 : : */
8 : :
9 : : #include <errno.h>
10 : : #include <zephyr/drivers/i2c.h>
11 : : #include <zephyr/sys/util.h>
12 : : #include <zephyr/logging/log.h>
13 : : #include <zephyr/irq.h>
14 : :
15 : : LOG_MODULE_REGISTER(i2c_xilinx_axi, CONFIG_I2C_LOG_LEVEL);
16 : :
17 : : #include "i2c-priv.h"
18 : : #include "i2c_xilinx_axi.h"
19 : :
20 : : struct i2c_xilinx_axi_config {
21 : : mem_addr_t base;
22 : : void (*irq_config_func)(const struct device *dev);
23 : : /* Whether device has working dynamic read (broken prior to core rev. 2.1) */
24 : : bool dyn_read_working;
25 : : };
26 : :
27 : : struct i2c_xilinx_axi_data {
28 : : struct k_event irq_event;
29 : : /* Serializes between ISR and other calls */
30 : : struct k_spinlock lock;
31 : : /* Provides exclusion against multiple concurrent requests */
32 : : struct k_mutex mutex;
33 : :
34 : : #if defined(CONFIG_I2C_TARGET)
35 : : struct i2c_target_config *target_cfg;
36 : : bool target_reading;
37 : : bool target_read_aborted;
38 : : bool target_writing;
39 : : #endif
40 : : };
41 : :
42 : 9 : static void i2c_xilinx_axi_reinit(const struct i2c_xilinx_axi_config *config)
43 : : {
44 [ - + ]: 9 : LOG_DBG("Controller reinit");
45 : 9 : sys_write32(SOFTR_KEY, config->base + REG_SOFTR);
46 : 9 : sys_write32(CR_TX_FIFO_RST, config->base + REG_CR);
47 : 9 : sys_write32(CR_EN, config->base + REG_CR);
48 : 9 : sys_write32(GIE_ENABLE, config->base + REG_GIE);
49 : 9 : }
50 : :
51 : : #if defined(CONFIG_I2C_TARGET)
52 : :
53 : : #define I2C_XILINX_AXI_TARGET_INTERRUPTS \
54 : : (ISR_ADDR_TARGET | ISR_NOT_ADDR_TARGET | ISR_RX_FIFO_FULL | ISR_TX_FIFO_EMPTY | \
55 : : ISR_TX_ERR_TARGET_COMP)
56 : :
57 : : static void i2c_xilinx_axi_target_setup(const struct i2c_xilinx_axi_config *config,
58 : : struct i2c_target_config *cfg)
59 : : {
60 : : i2c_xilinx_axi_reinit(config);
61 : :
62 : : sys_write32(ISR_ADDR_TARGET, config->base + REG_IER);
63 : : sys_write32(cfg->address << 1, config->base + REG_ADR);
64 : : sys_write32(0, config->base + REG_RX_FIFO_PIRQ);
65 : : }
66 : :
67 : : static int i2c_xilinx_axi_target_register(const struct device *dev, struct i2c_target_config *cfg)
68 : : {
69 : : const struct i2c_xilinx_axi_config *config = dev->config;
70 : : struct i2c_xilinx_axi_data *data = dev->data;
71 : : k_spinlock_key_t key;
72 : : int ret;
73 : :
74 : : if (cfg->flags & I2C_TARGET_FLAGS_ADDR_10_BITS) {
75 : : /* Optionally supported in core, but not implemented in driver yet */
76 : : return -EOPNOTSUPP;
77 : : }
78 : :
79 : : k_mutex_lock(&data->mutex, K_FOREVER);
80 : : key = k_spin_lock(&data->lock);
81 : :
82 : : if (data->target_cfg) {
83 : : ret = -EBUSY;
84 : : goto out_unlock;
85 : : }
86 : :
87 : : data->target_cfg = cfg;
88 : : i2c_xilinx_axi_target_setup(config, cfg);
89 : : ret = 0;
90 : :
91 : : out_unlock:
92 : : k_spin_unlock(&data->lock, key);
93 : : LOG_DBG("Target register ret=%d", ret);
94 : : k_mutex_unlock(&data->mutex);
95 : : return ret;
96 : : }
97 : :
98 : : static int i2c_xilinx_axi_target_unregister(const struct device *dev, struct i2c_target_config *cfg)
99 : : {
100 : : const struct i2c_xilinx_axi_config *config = dev->config;
101 : : struct i2c_xilinx_axi_data *data = dev->data;
102 : : k_spinlock_key_t key;
103 : : uint32_t int_enable;
104 : : int ret;
105 : :
106 : : k_mutex_lock(&data->mutex, K_FOREVER);
107 : : key = k_spin_lock(&data->lock);
108 : :
109 : : if (!data->target_cfg) {
110 : : ret = -EINVAL;
111 : : goto out_unlock;
112 : : }
113 : :
114 : : if (data->target_reading || data->target_writing) {
115 : : ret = -EBUSY;
116 : : goto out_unlock;
117 : : }
118 : :
119 : : data->target_cfg = NULL;
120 : : sys_write32(0, config->base + REG_ADR);
121 : :
122 : : sys_write32(CR_EN, config->base + REG_CR);
123 : : int_enable = sys_read32(config->base + REG_IER);
124 : : int_enable &= ~I2C_XILINX_AXI_TARGET_INTERRUPTS;
125 : : sys_write32(int_enable, config->base + REG_IER);
126 : : ret = 0;
127 : :
128 : : out_unlock:
129 : : k_spin_unlock(&data->lock, key);
130 : : LOG_DBG("Target unregister ret=%d", ret);
131 : : k_mutex_unlock(&data->mutex);
132 : : return ret;
133 : : }
134 : :
135 : : static void i2c_xilinx_axi_target_isr(const struct i2c_xilinx_axi_config *config,
136 : : struct i2c_xilinx_axi_data *data, uint32_t *int_status,
137 : : uint32_t *ints_to_clear, uint32_t *int_enable)
138 : : {
139 : : if (*int_status & ISR_ADDR_TARGET) {
140 : : LOG_DBG("Addressed as target");
141 : : *int_status &= ~ISR_ADDR_TARGET;
142 : : *int_enable &= ~ISR_ADDR_TARGET;
143 : : *int_enable |= ISR_NOT_ADDR_TARGET;
144 : : *ints_to_clear |= ISR_NOT_ADDR_TARGET;
145 : :
146 : : if (sys_read32(config->base + REG_SR) & SR_SRW) {
147 : : uint8_t read_byte;
148 : :
149 : : data->target_reading = true;
150 : : *ints_to_clear |= ISR_TX_FIFO_EMPTY | ISR_TX_ERR_TARGET_COMP;
151 : : *int_enable |= ISR_TX_FIFO_EMPTY | ISR_TX_ERR_TARGET_COMP;
152 : : if ((*data->target_cfg->callbacks->read_requested)(data->target_cfg,
153 : : &read_byte)) {
154 : : LOG_DBG("target read_requested rejected");
155 : : data->target_read_aborted = true;
156 : : read_byte = 0xFF;
157 : : }
158 : : sys_write32(read_byte, config->base + REG_TX_FIFO);
159 : : } else {
160 : : data->target_writing = true;
161 : : *int_enable |= ISR_RX_FIFO_FULL;
162 : : if ((*data->target_cfg->callbacks->write_requested)(data->target_cfg)) {
163 : : uint32_t cr = sys_read32(config->base + REG_CR);
164 : :
165 : : LOG_DBG("target write_requested rejected");
166 : : cr |= CR_TXAK;
167 : : sys_write32(cr, config->base + REG_CR);
168 : : }
169 : : }
170 : : } else if (*int_status & ISR_NOT_ADDR_TARGET) {
171 : : LOG_DBG("Not addressed as target");
172 : : (*data->target_cfg->callbacks->stop)(data->target_cfg);
173 : : data->target_reading = false;
174 : : data->target_read_aborted = false;
175 : : data->target_writing = false;
176 : :
177 : : sys_write32(CR_EN, config->base + REG_CR);
178 : : *int_status &= ~ISR_NOT_ADDR_TARGET;
179 : : *int_enable &= ~I2C_XILINX_AXI_TARGET_INTERRUPTS;
180 : : *int_enable |= ISR_ADDR_TARGET;
181 : : *ints_to_clear |= ISR_ADDR_TARGET;
182 : : } else if (data->target_writing && (*int_status & ISR_RX_FIFO_FULL)) {
183 : : *int_status &= ~ISR_RX_FIFO_FULL;
184 : : const uint8_t written_byte =
185 : : sys_read32(config->base + REG_RX_FIFO) & RX_FIFO_DATA_MASK;
186 : :
187 : : if ((*data->target_cfg->callbacks->write_received)(data->target_cfg,
188 : : written_byte)) {
189 : : uint32_t cr = sys_read32(config->base + REG_CR);
190 : :
191 : : LOG_DBG("target write_received rejected");
192 : : cr |= CR_TXAK;
193 : : sys_write32(cr, config->base + REG_CR);
194 : : }
195 : : } else if (data->target_reading && (*int_status & ISR_TX_ERR_TARGET_COMP)) {
196 : : /* Controller has NAKed the last byte read, so no more to send.
197 : : * Ignore TX FIFO empty so we don't write an extra byte.
198 : : */
199 : : LOG_DBG("target read completed");
200 : : *int_status &= ~ISR_TX_ERR_TARGET_COMP;
201 : : *int_enable &= ~ISR_TX_FIFO_EMPTY;
202 : : *ints_to_clear |= ISR_TX_FIFO_EMPTY;
203 : : } else if (data->target_reading && (*int_status & ISR_TX_FIFO_EMPTY)) {
204 : : *int_status &= ~ISR_TX_FIFO_EMPTY;
205 : : uint8_t read_byte = 0xFF;
206 : :
207 : : if (!data->target_read_aborted &&
208 : : (*data->target_cfg->callbacks->read_processed)(data->target_cfg,
209 : : &read_byte)) {
210 : : LOG_DBG("target read_processed rejected");
211 : : data->target_read_aborted = true;
212 : : }
213 : : sys_write32(read_byte, config->base + REG_TX_FIFO);
214 : : }
215 : : }
216 : : #endif
217 : :
218 : 9 : static void i2c_xilinx_axi_isr(const struct device *dev)
219 : : {
220 : 9 : const struct i2c_xilinx_axi_config *config = dev->config;
221 : 9 : struct i2c_xilinx_axi_data *data = dev->data;
222 : 9 : const k_spinlock_key_t key = k_spin_lock(&data->lock);
223 : 9 : uint32_t int_enable = sys_read32(config->base + REG_IER);
224 : 9 : uint32_t int_status = sys_read32(config->base + REG_ISR) & int_enable;
225 : 9 : uint32_t ints_to_clear = int_status;
226 : :
227 [ - + ]: 9 : LOG_DBG("ISR called for 0x%08" PRIxPTR ", status 0x%02x", config->base, int_status);
228 : :
229 [ - + ]: 9 : if (int_status & ISR_ARB_LOST) {
230 : : /* Must clear MSMS before clearing interrupt */
231 : 0 : uint32_t cr = sys_read32(config->base + REG_CR);
232 : :
233 : 0 : cr &= ~CR_MSMS;
234 : 0 : sys_write32(cr, config->base + REG_CR);
235 : : }
236 : :
237 : : #if defined(CONFIG_I2C_TARGET)
238 : : if (data->target_cfg && (int_status & I2C_XILINX_AXI_TARGET_INTERRUPTS)) {
239 : : /* This clears events from int_status which are already handled */
240 : : i2c_xilinx_axi_target_isr(config, data, &int_status, &ints_to_clear, &int_enable);
241 : : }
242 : : #endif
243 : :
244 : : /* Mask any interrupts which have not already been handled separately */
245 : 9 : sys_write32(int_enable & ~int_status, config->base + REG_IER);
246 : : /* Be careful, writing 1 to a bit that is not currently set in ISR will SET it! */
247 : 9 : sys_write32(ints_to_clear & sys_read32(config->base + REG_ISR), config->base + REG_ISR);
248 : :
249 : 9 : k_spin_unlock(&data->lock, key);
250 [ + - ]: 9 : if (int_status) {
251 : 9 : k_event_post(&data->irq_event, int_status);
252 : : }
253 : 9 : }
254 : :
255 : 4 : static int i2c_xilinx_axi_configure(const struct device *dev, uint32_t dev_config)
256 : : {
257 : 4 : const struct i2c_xilinx_axi_config *config = dev->config;
258 : :
259 [ - + ]: 4 : LOG_INF("Configuring %s at 0x%08" PRIxPTR, dev->name, config->base);
260 : 4 : i2c_xilinx_axi_reinit(config);
261 : 4 : return 0;
262 : : }
263 : :
264 : 8 : static uint32_t i2c_xilinx_axi_wait_interrupt(const struct i2c_xilinx_axi_config *config,
265 : : struct i2c_xilinx_axi_data *data, uint32_t int_mask)
266 : : {
267 : 8 : const k_spinlock_key_t key = k_spin_lock(&data->lock);
268 : 8 : const uint32_t int_enable = sys_read32(config->base + REG_IER) | int_mask;
269 : : uint32_t events;
270 : :
271 [ - + ]: 8 : LOG_DBG("Set IER to 0x%02x", int_enable);
272 : 8 : sys_write32(int_enable, config->base + REG_IER);
273 : 8 : k_event_clear(&data->irq_event, int_mask);
274 : 8 : k_spin_unlock(&data->lock, key);
275 : :
276 : 8 : events = k_event_wait(&data->irq_event, int_mask, false, K_MSEC(100));
277 : :
278 [ - + ]: 8 : LOG_DBG("Got ISR events 0x%02x", events);
279 [ - + ]: 8 : if (!events) {
280 [ # # ]: 0 : LOG_ERR("Timeout waiting for ISR events 0x%02x, SR 0x%02x, ISR 0x%02x", int_mask,
281 : : sys_read32(config->base + REG_SR), sys_read32(config->base + REG_ISR));
282 : : }
283 : 8 : return events;
284 : : }
285 : :
286 : 11 : static void i2c_xilinx_axi_clear_interrupt(const struct i2c_xilinx_axi_config *config,
287 : : struct i2c_xilinx_axi_data *data, uint32_t int_mask)
288 : : {
289 : 11 : const k_spinlock_key_t key = k_spin_lock(&data->lock);
290 : 11 : const uint32_t int_status = sys_read32(config->base + REG_ISR);
291 : :
292 [ + + ]: 11 : if (int_status & int_mask) {
293 : 5 : sys_write32(int_status & int_mask, config->base + REG_ISR);
294 : : }
295 : 11 : k_spin_unlock(&data->lock, key);
296 : 11 : }
297 : :
298 : 5 : static int i2c_xilinx_axi_wait_rx_full(const struct i2c_xilinx_axi_config *config,
299 : : struct i2c_xilinx_axi_data *data, uint32_t read_bytes)
300 : : {
301 : : uint32_t events;
302 : :
303 : 5 : i2c_xilinx_axi_clear_interrupt(config, data, ISR_RX_FIFO_FULL);
304 [ - + ]: 5 : if (!(sys_read32(config->base + REG_SR) & SR_RX_FIFO_EMPTY) &&
305 [ # # ]: 0 : (sys_read32(config->base + REG_RX_FIFO_OCY) & RX_FIFO_OCY_MASK) + 1 >= read_bytes) {
306 [ # # ]: 0 : LOG_DBG("RX already full on checking, SR 0x%02x RXOCY 0x%02x",
307 : : sys_read32(config->base + REG_SR),
308 : : sys_read32(config->base + REG_RX_FIFO_OCY));
309 : 0 : return 0;
310 : : }
311 : 5 : events = i2c_xilinx_axi_wait_interrupt(config, data, ISR_RX_FIFO_FULL | ISR_ARB_LOST);
312 [ - + ]: 5 : if (!events) {
313 : 0 : return -ETIMEDOUT;
314 : : }
315 [ - + ]: 5 : if (events & ISR_ARB_LOST) {
316 [ # # ]: 0 : LOG_ERR("Arbitration lost on RX");
317 : 0 : return -ENXIO;
318 : : }
319 : 5 : return 0;
320 : : }
321 : :
322 : 1 : static int i2c_xilinx_axi_read_nondyn(const struct i2c_xilinx_axi_config *config,
323 : : struct i2c_xilinx_axi_data *data, struct i2c_msg *msg,
324 : : uint16_t addr)
325 : : {
326 : 1 : uint8_t *read_ptr = msg->buf;
327 : 1 : uint32_t bytes_left = msg->len;
328 : 1 : uint32_t cr = CR_EN | CR_MSMS;
329 : :
330 [ - + ]: 1 : if (!bytes_left) {
331 : 0 : return -EINVAL;
332 : : }
333 [ - + ]: 1 : if (bytes_left == 1) {
334 : : /* Set TXAK bit now, to NAK after the first byte is received */
335 : 0 : cr |= CR_TXAK;
336 : : }
337 : :
338 : : /**
339 : : * The Xilinx core's RX FIFO full logic seems rather broken in that the interrupt
340 : : * is triggered, and the I2C receive is throttled, only when the FIFO occupancy
341 : : * equals the PIRQ threshold, not when greater or equal. In the non-dynamic mode
342 : : * of operation, we need to stop the read prior to the last bytes being received
343 : : * from the target in order to set the TXAK bit and clear MSMS to terminate the
344 : : * receive properly.
345 : : * However, if we previously allowed multiple bytes into the RX FIFO, this requires
346 : : * reducing the PIRQ threshold to 0 (single byte) during the receive operation. This
347 : : * can cause the receive to unthrottle (since FIFO occupancy now exceeds PIRQ
348 : : * threshold) and depending on timing between the driver code and the core,
349 : : * this can cause the core to try to receive more data into the FIFO than desired
350 : : * and cause various unexpected results.
351 : : *
352 : : * To avoid this, we only receive one byte at a time in the non-dynamic mode.
353 : : * Dynamic mode doesn't have this issue as it provides the RX byte count to the
354 : : * controller specifically and the TXAK and MSMS bits are handled automatically.
355 : : */
356 : 1 : sys_write32(0, config->base + REG_RX_FIFO_PIRQ);
357 : :
358 [ - + ]: 1 : if (msg->flags & I2C_MSG_RESTART) {
359 : 0 : cr |= CR_RSTA;
360 : :
361 : 0 : sys_write32(cr, config->base + REG_CR);
362 : 0 : sys_write32((addr << 1) | I2C_MSG_READ, config->base + REG_TX_FIFO);
363 : : } else {
364 : 1 : sys_write32((addr << 1) | I2C_MSG_READ, config->base + REG_TX_FIFO);
365 : 1 : sys_write32(cr, config->base + REG_CR);
366 : : }
367 : :
368 [ + + ]: 4 : while (bytes_left) {
369 : 3 : int ret = i2c_xilinx_axi_wait_rx_full(config, data, 1);
370 : :
371 [ - + ]: 3 : if (ret) {
372 : 0 : return ret;
373 : : }
374 : :
375 [ + + ]: 3 : if (bytes_left == 2) {
376 : : /* Set TXAK so the last byte is NAKed */
377 : 1 : cr |= CR_TXAK;
378 [ + + + - ]: 2 : } else if (bytes_left == 1 && (msg->flags & I2C_MSG_STOP)) {
379 : : /* Before reading the last byte, clear MSMS to issue a stop if required */
380 : 1 : cr &= ~CR_MSMS;
381 : : }
382 : 3 : cr &= ~CR_RSTA;
383 : 3 : sys_write32(cr, config->base + REG_CR);
384 : :
385 : 3 : *read_ptr++ = sys_read32(config->base + REG_RX_FIFO) & RX_FIFO_DATA_MASK;
386 : 3 : bytes_left--;
387 : : }
388 : 1 : return 0;
389 : : }
390 : :
391 : 2 : static int i2c_xilinx_axi_read_dyn(const struct i2c_xilinx_axi_config *config,
392 : : struct i2c_xilinx_axi_data *data, struct i2c_msg *msg,
393 : : uint16_t addr)
394 : : {
395 : 2 : uint8_t *read_ptr = msg->buf;
396 : 2 : uint32_t bytes_left = msg->len;
397 : 2 : uint32_t bytes_to_read = bytes_left;
398 : 2 : uint32_t cr = CR_EN;
399 : 2 : uint32_t len_word = bytes_left;
400 : :
401 [ + - - + ]: 2 : if (!bytes_left || bytes_left > MAX_DYNAMIC_READ_LEN) {
402 : 0 : return -EINVAL;
403 : : }
404 [ + + ]: 2 : if (msg->flags & I2C_MSG_RESTART) {
405 : 1 : cr |= CR_MSMS | CR_RSTA;
406 : : }
407 : 2 : sys_write32(cr, config->base + REG_CR);
408 : :
409 [ - + ]: 2 : if (bytes_to_read > FIFO_SIZE) {
410 : 0 : bytes_to_read = FIFO_SIZE;
411 : : }
412 : 2 : sys_write32(bytes_to_read - 1, config->base + REG_RX_FIFO_PIRQ);
413 : 2 : sys_write32((addr << 1) | I2C_MSG_READ | TX_FIFO_START, config->base + REG_TX_FIFO);
414 : :
415 [ + - ]: 2 : if (msg->flags & I2C_MSG_STOP) {
416 : 2 : len_word |= TX_FIFO_STOP;
417 : : }
418 : 2 : sys_write32(len_word, config->base + REG_TX_FIFO);
419 : :
420 [ + + ]: 4 : while (bytes_left) {
421 : : int ret;
422 : :
423 : 2 : bytes_to_read = bytes_left;
424 [ - + ]: 2 : if (bytes_to_read > FIFO_SIZE) {
425 : 0 : bytes_to_read = FIFO_SIZE;
426 : : }
427 : :
428 : 2 : sys_write32(bytes_to_read - 1, config->base + REG_RX_FIFO_PIRQ);
429 : 2 : ret = i2c_xilinx_axi_wait_rx_full(config, data, bytes_to_read);
430 [ - + ]: 2 : if (ret) {
431 : 0 : return ret;
432 : : }
433 : :
434 [ + + ]: 6 : while (bytes_to_read) {
435 : 4 : *read_ptr++ = sys_read32(config->base + REG_RX_FIFO) & RX_FIFO_DATA_MASK;
436 : 4 : bytes_to_read--;
437 : 4 : bytes_left--;
438 : : }
439 : : }
440 : 2 : return 0;
441 : : }
442 : :
443 : 3 : static int i2c_xilinx_axi_wait_tx_done(const struct i2c_xilinx_axi_config *config,
444 : : struct i2c_xilinx_axi_data *data)
445 : : {
446 : 3 : const uint32_t finish_bits = ISR_BUS_NOT_BUSY | ISR_TX_FIFO_EMPTY;
447 : :
448 : 3 : uint32_t events = i2c_xilinx_axi_wait_interrupt(
449 : : config, data, finish_bits | ISR_TX_ERR_TARGET_COMP | ISR_ARB_LOST);
450 [ + - - + ]: 3 : if (!(events & finish_bits) || (events & ~finish_bits)) {
451 [ # # ]: 0 : if (!events) {
452 : 0 : return -ETIMEDOUT;
453 : : }
454 [ # # ]: 0 : if (events & ISR_ARB_LOST) {
455 [ # # ]: 0 : LOG_ERR("Arbitration lost on TX");
456 : 0 : return -EAGAIN;
457 : : }
458 [ # # ]: 0 : LOG_ERR("TX received NAK");
459 : 0 : return -ENXIO;
460 : : }
461 : 3 : return 0;
462 : : }
463 : :
464 : 10 : static int i2c_xilinx_axi_wait_not_busy(const struct i2c_xilinx_axi_config *config,
465 : : struct i2c_xilinx_axi_data *data)
466 : : {
467 [ - + ]: 10 : if (sys_read32(config->base + REG_SR) & SR_BB) {
468 : 0 : uint32_t events = i2c_xilinx_axi_wait_interrupt(config, data, ISR_BUS_NOT_BUSY);
469 : :
470 [ # # ]: 0 : if (events != ISR_BUS_NOT_BUSY) {
471 [ # # ]: 0 : LOG_ERR("Bus stuck busy");
472 : 0 : i2c_xilinx_axi_reinit(config);
473 : 0 : return -EBUSY;
474 : : }
475 : : }
476 : 10 : return 0;
477 : : }
478 : :
479 : 3 : static int i2c_xilinx_axi_write(const struct i2c_xilinx_axi_config *config,
480 : : struct i2c_xilinx_axi_data *data, const struct i2c_msg *msg,
481 : : uint16_t addr)
482 : : {
483 : 3 : const uint8_t *write_ptr = msg->buf;
484 : 3 : uint32_t bytes_left = msg->len;
485 : 3 : uint32_t cr = CR_EN | CR_TX;
486 : 3 : uint32_t fifo_space = FIFO_SIZE - 1; /* account for address being written */
487 : :
488 [ - + ]: 3 : if (msg->flags & I2C_MSG_RESTART) {
489 : 0 : cr |= CR_MSMS | CR_RSTA;
490 : : }
491 : :
492 : 3 : i2c_xilinx_axi_clear_interrupt(config, data, ISR_TX_ERR_TARGET_COMP | ISR_ARB_LOST);
493 : :
494 : 3 : sys_write32(cr, config->base + REG_CR);
495 : 3 : sys_write32((addr << 1) | TX_FIFO_START, config->base + REG_TX_FIFO);
496 : :
497 : : /* TX FIFO empty detection is somewhat fragile because the status register
498 : : * TX_FIFO_EMPTY bit can be set prior to the transaction actually being
499 : : * complete, so we have to rely on the TX empty interrupt.
500 : : * However, delays in writing data to the TX FIFO could cause it
501 : : * to run empty in the middle of the process, causing us to get a spurious
502 : : * completion detection from the interrupt. Therefore we disable interrupts
503 : : * while the TX FIFO is being filled up to try to avoid this.
504 : : */
505 : :
506 [ + + ]: 6 : while (bytes_left) {
507 : 3 : uint32_t bytes_to_send = bytes_left;
508 : 3 : const k_spinlock_key_t key = k_spin_lock(&data->lock);
509 : : int ret;
510 : :
511 [ - + ]: 3 : if (bytes_to_send > fifo_space) {
512 : 0 : bytes_to_send = fifo_space;
513 : : }
514 [ + + ]: 6 : while (bytes_to_send) {
515 : 3 : uint32_t write_word = *write_ptr++;
516 : :
517 [ + - + + ]: 3 : if (bytes_left == 1 && (msg->flags & I2C_MSG_STOP)) {
518 : 2 : write_word |= TX_FIFO_STOP;
519 : : }
520 : 3 : sys_write32(write_word, config->base + REG_TX_FIFO);
521 : 3 : bytes_to_send--;
522 : 3 : bytes_left--;
523 : : }
524 : 3 : k_spin_unlock(&data->lock, key);
525 : 3 : i2c_xilinx_axi_clear_interrupt(config, data, ISR_TX_FIFO_EMPTY | ISR_BUS_NOT_BUSY);
526 : :
527 : 3 : ret = i2c_xilinx_axi_wait_tx_done(config, data);
528 [ - + ]: 3 : if (ret) {
529 : 0 : return ret;
530 : : }
531 : 3 : fifo_space = FIFO_SIZE;
532 : : }
533 : 3 : return 0;
534 : : }
535 : :
536 : 5 : static int i2c_xilinx_axi_transfer(const struct device *dev, struct i2c_msg *msgs, uint8_t num_msgs,
537 : : uint16_t addr)
538 : : {
539 : 5 : const struct i2c_xilinx_axi_config *config = dev->config;
540 : 5 : struct i2c_xilinx_axi_data *data = dev->data;
541 : : int ret;
542 : :
543 : 5 : k_mutex_lock(&data->mutex, K_FOREVER);
544 : :
545 : 5 : ret = i2c_xilinx_axi_wait_not_busy(config, data);
546 [ - + ]: 5 : if (ret) {
547 : 0 : goto out_unlock;
548 : : }
549 : :
550 [ - + ]: 5 : if (!num_msgs) {
551 : 0 : goto out_unlock;
552 : : }
553 : :
554 : : /**
555 : : * Reinitializing before each transfer shouldn't technically be needed, but
556 : : * seems to improve general reliability. The Linux driver also does this.
557 : : */
558 : 5 : i2c_xilinx_axi_reinit(config);
559 : :
560 : : do {
561 [ - + ]: 6 : if (msgs->flags & I2C_MSG_ADDR_10_BITS) {
562 : : /* Optionally supported in core, but not implemented in driver yet */
563 : 0 : ret = -EOPNOTSUPP;
564 : 0 : goto out_check_target;
565 : : }
566 [ + + ]: 6 : if (msgs->flags & I2C_MSG_READ) {
567 [ + + + - ]: 3 : if (config->dyn_read_working && msgs->len <= MAX_DYNAMIC_READ_LEN) {
568 : 2 : ret = i2c_xilinx_axi_read_dyn(config, data, msgs, addr);
569 : : } else {
570 : 1 : ret = i2c_xilinx_axi_read_nondyn(config, data, msgs, addr);
571 : : }
572 : : } else {
573 : 3 : ret = i2c_xilinx_axi_write(config, data, msgs, addr);
574 : : }
575 [ + - + + ]: 6 : if (!ret && (msgs->flags & I2C_MSG_STOP)) {
576 : 5 : ret = i2c_xilinx_axi_wait_not_busy(config, data);
577 : : }
578 [ - + ]: 6 : if (ret) {
579 : 0 : goto out_check_target;
580 : : }
581 : 6 : msgs++;
582 : 6 : num_msgs--;
583 [ + + ]: 6 : } while (num_msgs);
584 : :
585 : 5 : out_check_target:
586 : : #if defined(CONFIG_I2C_TARGET)
587 : : /* If a target is registered, then ensure the controller gets put back
588 : : * into a suitable state to handle target transfers.
589 : : */
590 : : k_spinlock_key_t key = k_spin_lock(&data->lock);
591 : :
592 : : if (data->target_cfg) {
593 : : i2c_xilinx_axi_target_setup(config, data->target_cfg);
594 : : }
595 : : k_spin_unlock(&data->lock, key);
596 : : #endif
597 : :
598 : 5 : out_unlock:
599 : 5 : k_mutex_unlock(&data->mutex);
600 : 5 : return ret;
601 : : }
602 : :
603 : 4 : static int i2c_xilinx_axi_init(const struct device *dev)
604 : : {
605 : 4 : const struct i2c_xilinx_axi_config *config = dev->config;
606 : 4 : struct i2c_xilinx_axi_data *data = dev->data;
607 : : int error;
608 : :
609 : 4 : k_event_init(&data->irq_event);
610 : 4 : k_mutex_init(&data->mutex);
611 : :
612 : 4 : error = i2c_xilinx_axi_configure(dev, I2C_MODE_CONTROLLER);
613 [ - + ]: 4 : if (error) {
614 : 0 : return error;
615 : : }
616 : :
617 : 4 : config->irq_config_func(dev);
618 : :
619 [ - + ]: 4 : LOG_INF("initialized");
620 : 4 : return 0;
621 : : }
622 : :
623 : : static const struct i2c_driver_api i2c_xilinx_axi_driver_api = {
624 : : .configure = i2c_xilinx_axi_configure,
625 : : .transfer = i2c_xilinx_axi_transfer,
626 : : #if defined(CONFIG_I2C_TARGET)
627 : : .target_register = i2c_xilinx_axi_target_register,
628 : : .target_unregister = i2c_xilinx_axi_target_unregister,
629 : : #endif
630 : : };
631 : :
632 : : #define I2C_XILINX_AXI_INIT(n, compat) \
633 : : static void i2c_xilinx_axi_config_func_##compat##_##n(const struct device *dev); \
634 : : \
635 : : static const struct i2c_xilinx_axi_config i2c_xilinx_axi_config_##compat##_##n = { \
636 : : .base = DT_INST_REG_ADDR(n), \
637 : : .irq_config_func = i2c_xilinx_axi_config_func_##compat##_##n, \
638 : : .dyn_read_working = DT_INST_NODE_HAS_COMPAT(n, xlnx_xps_iic_2_1)}; \
639 : : \
640 : : static struct i2c_xilinx_axi_data i2c_xilinx_axi_data_##compat##_##n; \
641 : : \
642 : : I2C_DEVICE_DT_INST_DEFINE(n, i2c_xilinx_axi_init, NULL, \
643 : : &i2c_xilinx_axi_data_##compat##_##n, \
644 : : &i2c_xilinx_axi_config_##compat##_##n, POST_KERNEL, \
645 : : CONFIG_I2C_INIT_PRIORITY, &i2c_xilinx_axi_driver_api); \
646 : : \
647 : : static void i2c_xilinx_axi_config_func_##compat##_##n(const struct device *dev) \
648 : : { \
649 : : ARG_UNUSED(dev); \
650 : : \
651 : : IRQ_CONNECT(DT_INST_IRQN(n), DT_INST_IRQ(n, priority), i2c_xilinx_axi_isr, \
652 : : DEVICE_DT_INST_GET(n), 0); \
653 : : \
654 : : irq_enable(DT_INST_IRQN(n)); \
655 : : }
656 : :
657 : : #define DT_DRV_COMPAT xlnx_xps_iic_2_1
658 : 1 : DT_INST_FOREACH_STATUS_OKAY_VARGS(I2C_XILINX_AXI_INIT, DT_DRV_COMPAT)
659 : : #undef DT_DRV_COMPAT
660 : : #define DT_DRV_COMPAT xlnx_xps_iic_2_00_a
661 : 3 : DT_INST_FOREACH_STATUS_OKAY_VARGS(I2C_XILINX_AXI_INIT, DT_DRV_COMPAT)
|