Branch data Line data Source code
1 : : /*
2 : : * Copyright (c) 2024 Advanced Micro Devices, Inc.
3 : : *
4 : : * SPDX-License-Identifier: Apache-2.0
5 : : */
6 : :
7 : : #include <zephyr/drivers/i2c.h>
8 : : #include <zephyr/sys/util.h>
9 : : #include <zephyr/logging/log.h>
10 : : #include <zephyr/irq.h>
11 : :
12 : : LOG_MODULE_REGISTER(i2c_cadence, CONFIG_I2C_LOG_LEVEL);
13 : :
14 : : /* Register offsets for the I2C device. */
15 : : #define CDNS_I2C_CR_OFFSET 0x00 /* Control Register, RW */
16 : : #define CDNS_I2C_SR_OFFSET 0x04 /* Status Register, RO */
17 : : #define CDNS_I2C_ADDR_OFFSET 0x08 /* I2C Address Register, RW */
18 : : #define CDNS_I2C_DATA_OFFSET 0x0C /* I2C Data Register, RW */
19 : : #define CDNS_I2C_ISR_OFFSET 0x10 /* IRQ Status Register, RW */
20 : : #define CDNS_I2C_XFER_SIZE_OFFSET 0x14 /* Transfer Size Register, RW */
21 : : #define CDNS_I2C_TIME_OUT_OFFSET 0x1C /* Time Out Register, RW */
22 : : #define CDNS_I2C_IMR_OFFSET 0x20 /* IRQ Mask Register, RO */
23 : : #define CDNS_I2C_IER_OFFSET 0x24 /* IRQ Enable Register, WO */
24 : : #define CDNS_I2C_IDR_OFFSET 0x28 /* IRQ Disable Register, WO */
25 : :
26 : : /* Control Register Bit mask definitions */
27 : : #define CDNS_I2C_CR_HOLD BIT(4) /* Hold the I2C Bus */
28 : : #define CDNS_I2C_CR_ACK_EN BIT(3) /* Enables or disables acknowledgment */
29 : : #define CDNS_I2C_CR_NEA BIT(2) /* No Extended addressing */
30 : : #define CDNS_I2C_CR_MS BIT(1) /* 0 = Slave Mode, 1 = Master Mode */
31 : : #define CDNS_I2C_CR_RW BIT(0) /* Transfer Dir: 0 = Transmitter, 1 = Receiver */
32 : : #define CDNS_I2C_CR_CLR_FIFO BIT(6) /* Clears the FIFO on initialization */
33 : :
34 : : /* Dividers for clock generation */
35 : : #define CDNS_I2C_CR_DIVA_SHIFT 14U
36 : : #define CDNS_I2C_CR_DIVA_MASK ((uint32_t)3U << CDNS_I2C_CR_DIVA_SHIFT)
37 : : #define CDNS_I2C_CR_DIVB_SHIFT 8U
38 : : #define CDNS_I2C_CR_DIVB_MASK ((uint32_t)0x3f << CDNS_I2C_CR_DIVB_SHIFT)
39 : :
40 : : /* Master Enable Mask - master mode, acknowledgment, and no extended address */
41 : : #define CDNS_I2C_CR_MASTER_EN_MASK (CDNS_I2C_CR_NEA | \
42 : : CDNS_I2C_CR_ACK_EN | \
43 : : CDNS_I2C_CR_MS)
44 : :
45 : : /* Slave Enable Mask - used for slave configuration */
46 : : #define CDNS_I2C_CR_SLAVE_EN_MASK ~CDNS_I2C_CR_MASTER_EN_MASK
47 : :
48 : : /* Status Register Bit mask definitions */
49 : : #define CDNS_I2C_SR_BA BIT(8) /* Bus is available */
50 : : #define CDNS_I2C_SR_TXDV BIT(6) /* Transmit data is valid */
51 : : #define CDNS_I2C_SR_RXDV BIT(5) /* Received data is valid */
52 : : #define CDNS_I2C_SR_RXRW BIT(3) /* Read or Write operation */
53 : :
54 : : /*
55 : : * I2C Address Register Bit mask definitions
56 : : * Normal addressing mode uses [6:0] bits.
57 : : * Extended addressing mode uses [9:0] bits.
58 : : * A write access to this register always initiates a transfer if the I2C is in master mode.
59 : : */
60 : : #define CDNS_I2C_ADDR_MASK 0x000003FFU /* I2C Address Mask */
61 : :
62 : : /*
63 : : * I2C Interrupt Registers Bit mask definitions
64 : : * All the four interrupt registers (Status/Mask/Enable/Disable) have the same bit definitions.
65 : : */
66 : : #define CDNS_I2C_IXR_ARB_LOST BIT(9) /* Arbitration Lost Interrupt */
67 : : #define CDNS_I2C_IXR_RX_UNF BIT(7) /* RX FIFO Underflow Interrupt */
68 : : #define CDNS_I2C_IXR_TX_OVF BIT(6) /* TX FIFO Overflow Interrupt */
69 : : #define CDNS_I2C_IXR_RX_OVF BIT(5) /* RX FIFO Overflow Interrupt */
70 : : #define CDNS_I2C_IXR_SLV_RDY BIT(4) /* Slave Ready Interrupt */
71 : : #define CDNS_I2C_IXR_TO BIT(3) /* Timeout Interrupt */
72 : : #define CDNS_I2C_IXR_NACK BIT(2) /* NACK Interrupt */
73 : : #define CDNS_I2C_IXR_DATA BIT(1) /* Data Interrupt */
74 : : #define CDNS_I2C_IXR_COMP BIT(0) /* Transfer Complete Interrupt */
75 : :
76 : : /* All Interrupt Mask */
77 : : #define CDNS_I2C_IXR_ALL_INTR_MASK (CDNS_I2C_IXR_ARB_LOST | \
78 : : CDNS_I2C_IXR_RX_UNF | \
79 : : CDNS_I2C_IXR_TX_OVF | \
80 : : CDNS_I2C_IXR_RX_OVF | \
81 : : CDNS_I2C_IXR_SLV_RDY | \
82 : : CDNS_I2C_IXR_TO | \
83 : : CDNS_I2C_IXR_NACK | \
84 : : CDNS_I2C_IXR_DATA | \
85 : : CDNS_I2C_IXR_COMP)
86 : :
87 : : /* Error Interrupt Mask */
88 : : #define CDNS_I2C_IXR_ERR_INTR_MASK (CDNS_I2C_IXR_ARB_LOST | \
89 : : CDNS_I2C_IXR_RX_UNF | \
90 : : CDNS_I2C_IXR_TX_OVF | \
91 : : CDNS_I2C_IXR_RX_OVF | \
92 : : CDNS_I2C_IXR_NACK)
93 : :
94 : : /* Enabled Interrupt Mask */
95 : : #define CDNS_I2C_ENABLED_INTR_MASK (CDNS_I2C_IXR_ARB_LOST | \
96 : : CDNS_I2C_IXR_RX_UNF | \
97 : : CDNS_I2C_IXR_TX_OVF | \
98 : : CDNS_I2C_IXR_RX_OVF | \
99 : : CDNS_I2C_IXR_NACK | \
100 : : CDNS_I2C_IXR_DATA | \
101 : : CDNS_I2C_IXR_COMP)
102 : :
103 : : /* Slave Interrupt Mask */
104 : : #define CDNS_I2C_IXR_SLAVE_INTR_MASK (CDNS_I2C_IXR_RX_UNF | \
105 : : CDNS_I2C_IXR_TX_OVF | \
106 : : CDNS_I2C_IXR_RX_OVF | \
107 : : CDNS_I2C_IXR_TO | \
108 : : CDNS_I2C_IXR_NACK | \
109 : : CDNS_I2C_IXR_DATA | \
110 : : CDNS_I2C_IXR_COMP)
111 : :
112 : : /* System clock frequency for I2C ticks */
113 : : #define CDNS_I2C_TICKS_PER_SEC CONFIG_SYS_CLOCK_TICKS_PER_SEC
114 : :
115 : : /* Default timeout ticks for I2C operations */
116 : : #define CDNS_I2C_TIMEOUT_TICKS CDNS_I2C_TICKS_PER_SEC
117 : :
118 : : #define CDNS_I2C_FIFO_DEPTH_DEFAULT 16U /* Default FIFO depth for I2C operations */
119 : : #define CDNS_I2C_MAX_TRANSFER_SIZE 255U /* Maximum transfer size for I2C data */
120 : :
121 : : /* Default transfer size */
122 : : #define CDNS_I2C_TRANSFER_SIZE_DEFAULT (CDNS_I2C_MAX_TRANSFER_SIZE - 3U)
123 : :
124 : : /* Maximum dividers for I2C clock */
125 : : #define CDNS_I2C_DIVA_MAX 4U
126 : : #define CDNS_I2C_DIVB_MAX 64U
127 : : #define CDNS_I2C_CLK_DIV_FACTOR 22U
128 : :
129 : : #define CDNS_I2C_TIMEOUT_MAX 0xFFU /* Maximum value for Timeout Register */
130 : : #define CDNS_I2C_POLL_US 100000U /* Polling interval in microseconds */
131 : : #define CDNS_I2C_TIMEOUT_US 500000U /* Timeout value for I2C operations */
132 : : #define CDNS_I2C_BROKEN_HOLD_BIT BIT(0) /* Broken Hold - Cadence I2C controller ver 1.0 */
133 : :
134 : : /* Event flag for I2C transfer completion */
135 : : #define I2C_XFER_COMPLETION_EVENT BIT(0)
136 : :
137 : : /* I2C Speed Definitions */
138 : : #define CDNS_I2C_SPEED_STANDARD_HZ (100000UL) /* Standard I2C speed (100 kHz) */
139 : : #define CDNS_I2C_SPEED_FAST_HZ (400000UL) /* Fast I2C speed (400 kHz) */
140 : :
141 : : #if defined(CONFIG_I2C_TARGET)
142 : : /**
143 : : * enum cdns_i2c_mode - I2C Controller current operating mode
144 : : *
145 : : * @CDNS_I2C_MODE_SLAVE: I2C controller operating in slave mode
146 : : * @CDNS_I2C_MODE_MASTER: I2C Controller operating in master mode
147 : : */
148 : : enum cdns_i2c_mode {
149 : : CDNS_I2C_MODE_SLAVE = 0,
150 : : CDNS_I2C_MODE_MASTER,
151 : : };
152 : :
153 : : /**
154 : : * enum cdns_i2c_slave_state - Slave state when I2C is operating in slave mode
155 : : *
156 : : * @CDNS_I2C_SLAVE_STATE_IDLE: I2C slave idle
157 : : * @CDNS_I2C_SLAVE_STATE_SEND: I2C slave sending data to master
158 : : * @CDNS_I2C_SLAVE_STATE_RECV: I2C slave receiving data from master
159 : : */
160 : : enum cdns_i2c_slave_state {
161 : : CDNS_I2C_SLAVE_STATE_IDLE = 0,
162 : : CDNS_I2C_SLAVE_STATE_SEND,
163 : : CDNS_I2C_SLAVE_STATE_RECV,
164 : : };
165 : : #endif
166 : :
167 : : /* Driver config */
168 : : struct cdns_i2c_config {
169 : : void (*irq_config_func)(const struct device *dev);
170 : : };
171 : :
172 : : /**
173 : : * struct cdns_i2c_data - Cadence I2C device private data structure
174 : : * @membase: Base address of the I2C device.
175 : : * @ctrl_reg: Cached value of the control register.
176 : : * @input_clk: Input clock to I2C controller.
177 : : * @i2c_clk: Maximum I2C clock speed.
178 : : * @i2c_config: Configuration of I2C settings.
179 : : * @fifo_depth: The depth of the transfer FIFO.
180 : : * @transfer_size: The maximum number of bytes in one transfer.
181 : : * @bus_hold_flag: Flag used in repeated start for clearing HOLD bit.
182 : : * @broken_hold_flag: Flag for broken hold bit usage in r1p10.
183 : : * @xfer_done: Transfer complete event.
184 : : * @err_status: Error status in Interrupt Status Register.
185 : : * @p_msg: Message pointer for I2C communication.
186 : : * @p_send_buf: Pointer to transmit buffer.
187 : : * @p_recv_buf: Pointer to receive buffer.
188 : : * @send_count: Number of bytes still expected to send.
189 : : * @recv_count: Number of bytes still expected to receive.
190 : : * @curr_recv_count: Number of bytes to be received in current transfer.
191 : : * @bus_mutex: Mutex for bus access synchronization
192 : : * @ctrl_reg_diva_divb: Value of fields DIV_A and DIV_B from CR register.
193 : : * @slave: Registered slave instance.
194 : : * @dev_mode: I2C operating role (master/slave).
195 : : * @slave_state: I2C Slave state (idle/read/write).
196 : : */
197 : : struct cdns_i2c_data {
198 : : mem_addr_t membase;
199 : : uint32_t ctrl_reg;
200 : : uint32_t input_clk;
201 : : uint32_t i2c_clk;
202 : : uint32_t i2c_config;
203 : : uint32_t fifo_depth;
204 : : uint32_t transfer_size;
205 : : uint32_t bus_hold_flag;
206 : : uint32_t broken_hold_flag;
207 : :
208 : : struct k_event xfer_done;
209 : : uint32_t err_status;
210 : : struct i2c_msg *p_msg;
211 : : uint8_t *p_send_buf;
212 : : uint8_t *p_recv_buf;
213 : : uint32_t send_count;
214 : : uint32_t recv_count;
215 : : uint32_t curr_recv_count;
216 : :
217 : : struct k_mutex bus_mutex;
218 : :
219 : : #if defined(CONFIG_I2C_TARGET)
220 : : uint16_t ctrl_reg_diva_divb;
221 : : struct i2c_target_config *slave;
222 : : enum cdns_i2c_mode dev_mode;
223 : : enum cdns_i2c_slave_state slave_state;
224 : : #endif
225 : : };
226 : :
227 : : /**
228 : : * cdns_i2c_writereg - Write a 32-bit value to a specific offset in the I2C register space.
229 : : * @i2c_bus: Pointer to the I2C data structure.
230 : : * @value: The 32-bit value to write to the register.
231 : : * @offset: The offset in the I2C register space where the value will be written.
232 : : */
233 : 52 : static inline void cdns_i2c_writereg(const struct cdns_i2c_data *i2c_bus,
234 : : uint32_t value, uintptr_t offset)
235 : : {
236 : 52 : uintptr_t reg_address = (uintptr_t)(i2c_bus->membase) + offset;
237 : :
238 : 52 : sys_write32(value, reg_address);
239 : 52 : }
240 : :
241 : : /**
242 : : * cdns_i2c_readreg - Read a 32-bit value from a specific offset in the I2C register space.
243 : : * @i2c_bus: Pointer to the I2C data structure.
244 : : * @offset: The offset in the I2C register space from which the value will be read.
245 : : *
246 : : * Return: The 32-bit value read from the register.
247 : : */
248 : 53 : static inline uint32_t cdns_i2c_readreg(const struct cdns_i2c_data *i2c_bus, uintptr_t offset)
249 : : {
250 : 53 : uintptr_t reg_address = (uintptr_t)(i2c_bus->membase) + offset;
251 : :
252 : 53 : return sys_read32(reg_address);
253 : : }
254 : :
255 : : /**
256 : : * cdns_i2c_enable_peripheral - Enable the Cadence I2C controller
257 : : * @i2c_bus: Pointer to the device's private data structure for the I2C controller
258 : : */
259 : 2 : static void cdns_i2c_enable_peripheral(struct cdns_i2c_data *i2c_bus)
260 : : {
261 : 2 : cdns_i2c_writereg(i2c_bus, i2c_bus->ctrl_reg, CDNS_I2C_CR_OFFSET);
262 : :
263 : : /*
264 : : * Cadence I2C controller has a bug causing invalid reads after a timeout
265 : : * in master receiver mode. While the timeout feature is disabled,
266 : : * writing the max value to the timeout register reduces the issue.
267 : : */
268 : 2 : cdns_i2c_writereg(i2c_bus, CDNS_I2C_TIMEOUT_MAX, CDNS_I2C_TIME_OUT_OFFSET);
269 : 2 : }
270 : :
271 : : /**
272 : : * cdns_i2c_calc_divs - Calculate clock dividers for I2C frequency
273 : : * @f: Pointer to the I2C target frequency (input/output)
274 : : * @input_clk: Input clock frequency in Hz
275 : : * @a: Pointer to the first divider (output)
276 : : * @b: Pointer to the second divider (output)
277 : : *
278 : : * On entry, @f holds the target I2C frequency. On exit, @f will hold the
279 : : * actual I2C frequency generated by the calculated dividers.
280 : : *
281 : : * Return: 0 on success, negative errno otherwise.
282 : : */
283 : 2 : static int32_t cdns_i2c_calc_divs(uint32_t *f, uint32_t input_clk,
284 : : uint32_t *a, uint32_t *b)
285 : : {
286 : 2 : uint32_t fscl = *f;
287 : 2 : uint32_t best_fscl = *f;
288 : : uint32_t actual_fscl, temp;
289 : : uint32_t div_a, div_b;
290 : 2 : uint32_t calc_div_a = 0, calc_div_b = 0;
291 : : uint32_t last_error, current_error;
292 : 2 : int32_t ret = 0;
293 : :
294 : : /* calculate initial estimate for divisor_a and divisor_b */
295 : 2 : temp = input_clk / (CDNS_I2C_CLK_DIV_FACTOR * fscl);
296 : :
297 : : /* Check if the calculated value is out of range */
298 [ + - - + ]: 2 : if ((temp == 0U) || (temp > (CDNS_I2C_DIVA_MAX * CDNS_I2C_DIVB_MAX))) {
299 : 0 : ret = -EINVAL;
300 : 0 : goto out;
301 : : }
302 : :
303 : : /* Initialize the last error to a large value (no error yet) */
304 : 2 : last_error = UINT32_MAX;
305 : :
306 : : /* Iterate over possible values for divisor_a */
307 [ + + ]: 10 : for (div_a = 0; div_a < CDNS_I2C_DIVA_MAX; div_a++) {
308 : : /* Calculate the corresponding divisor_b for this div_a */
309 : 8 : div_b = DIV_ROUND_UP(input_clk, CDNS_I2C_CLK_DIV_FACTOR * fscl * (div_a + 1U));
310 : :
311 : : /* Skip invalid values of div_b */
312 [ + - - + ]: 8 : if ((div_b < 1U) || (div_b > CDNS_I2C_DIVB_MAX)) {
313 : 0 : continue;
314 : : }
315 : :
316 : : /* Adjust div_b for zero-based indexing */
317 : 8 : div_b--;
318 : :
319 : : /* Calculate the actual fscl based on the current divisors */
320 : 8 : actual_fscl = input_clk / (CDNS_I2C_CLK_DIV_FACTOR * (div_a + 1U) * (div_b + 1U));
321 : :
322 : : /* Skip if the actual fscl exceeds the target fscl */
323 [ - + ]: 8 : if (actual_fscl > fscl) {
324 : 0 : continue;
325 : : }
326 : :
327 : : /* Calculate the error between the target fscl and the actual fscl */
328 : 8 : current_error = fscl - actual_fscl;
329 : :
330 : : /* Update the best divisors if a smaller error is found */
331 [ + + ]: 8 : if (last_error > current_error) {
332 : 2 : calc_div_a = div_a;
333 : 2 : calc_div_b = div_b;
334 : 2 : best_fscl = actual_fscl;
335 : 2 : last_error = current_error;
336 : : }
337 : : }
338 : :
339 : : /* Set the output values */
340 : 2 : *a = calc_div_a;
341 : 2 : *b = calc_div_b;
342 : 2 : *f = best_fscl;
343 : :
344 : 2 : out:
345 : 2 : return ret;
346 : : }
347 : :
348 : : /**
349 : : * cdns_i2c_setclk - Set the serial clock rate for the I2C device
350 : : * @i2c_bus: Pointer to the I2C data structure
351 : : * @clk_in: I2C clock input frequency in Hz
352 : : *
353 : : * This function sets the serial clock rate for the I2C device by configuring
354 : : * the clock divisors in the device's control register. The device must be idle
355 : : * (i.e., not actively transferring data) before calling this function.
356 : : *
357 : : * The clock rate is determined by the following formula:
358 : : * Fscl = Fpclk / (22 * (divisor_a + 1) * (divisor_b + 1))
359 : : * Where:
360 : : * - Fscl is the desired I2C clock rate
361 : : * - Fpclk is the input clock frequency
362 : : * - divisor_a and divisor_b are the calculated divisors to achieve the desired clock rate
363 : : *
364 : : * The serial clock rate cannot exceed the input clock divided by 22. Common I2C clock
365 : : * rates are 100 KHz and 400 KHz.
366 : : *
367 : : * Return: 0 on success, negative error code on failure
368 : : */
369 : 2 : static int32_t cdns_i2c_setclk(struct cdns_i2c_data *i2c_bus, uint32_t clk_in)
370 : : {
371 : : uint32_t div_a, div_b;
372 : : uint32_t ctrl_reg;
373 : 2 : int32_t ret = 0;
374 : 2 : uint32_t fscl = i2c_bus->i2c_clk;
375 : :
376 : : /* Calculate the divider values */
377 : 2 : ret = cdns_i2c_calc_divs(&fscl, clk_in, &div_a, &div_b);
378 [ - + ]: 2 : if (ret != 0) {
379 : 0 : goto out;
380 : : }
381 : :
382 : : /* Set new divider values in the control register */
383 : 2 : ctrl_reg = i2c_bus->ctrl_reg;
384 : 2 : ctrl_reg &= ~(CDNS_I2C_CR_DIVA_MASK | CDNS_I2C_CR_DIVB_MASK);
385 : 2 : ctrl_reg |= ((div_a << CDNS_I2C_CR_DIVA_SHIFT) |
386 : 2 : (div_b << CDNS_I2C_CR_DIVB_SHIFT));
387 : 2 : i2c_bus->ctrl_reg = ctrl_reg;
388 : 2 : cdns_i2c_writereg(i2c_bus, ctrl_reg, CDNS_I2C_CR_OFFSET);
389 : :
390 : : #if defined(CONFIG_I2C_TARGET)
391 : : /* Save the divider values for switching between master and slave modes */
392 : : i2c_bus->ctrl_reg_diva_divb = (uint16_t)(uint32_t)(ctrl_reg & (CDNS_I2C_CR_DIVA_MASK |
393 : : CDNS_I2C_CR_DIVB_MASK));
394 : : #endif
395 : :
396 : 2 : out:
397 : 2 : return ret;
398 : : }
399 : :
400 : : /**
401 : : * cdns_i2c_configure - Configures the I2C bus speed and initializes the I2C peripheral
402 : : * @dev: Pointer to the device structure representing the I2C bus
403 : : * @dev_config: Configuration value containing the desired I2C bus speed
404 : : *
405 : : * This function configures the I2C bus speed based on the value provided in
406 : : * @dev_config, which can be either I2C_SPEED_STANDARD (100 KHz) or I2C_SPEED_FAST (400 KHz).
407 : : * It then sets the appropriate clock for the I2C bus, verifies the clock is valid, and
408 : : * initializes the I2C peripheral. The configuration is saved to the device's data structure.
409 : : *
410 : : * Return: 0 on success, -EIO on failure
411 : : */
412 : 1 : static int32_t cdns_i2c_configure(const struct device *dev, uint32_t dev_config)
413 : : {
414 : 1 : int32_t ret = 0;
415 : 1 : struct cdns_i2c_data *i2c_bus = (struct cdns_i2c_data *)dev->data;
416 : 1 : uint32_t speed = I2C_SPEED_GET(dev_config);
417 : : uint32_t i2c_speed;
418 : :
419 : 1 : (void)k_mutex_lock(&i2c_bus->bus_mutex, K_FOREVER);
420 : :
421 : : /* Check requested I2C Speed */
422 [ + - ]: 1 : if (speed == I2C_SPEED_STANDARD) {
423 : 1 : i2c_speed = CDNS_I2C_SPEED_STANDARD_HZ; /* 100 KHz */
424 [ # # ]: 0 : } else if (speed == I2C_SPEED_FAST) {
425 : 0 : i2c_speed = CDNS_I2C_SPEED_FAST_HZ; /* 400 KHz */
426 : : } else {
427 [ # # ]: 0 : LOG_ERR("Unsupported I2C speed requested: %u", speed);
428 : 0 : ret = -EIO;
429 : 0 : goto out;
430 : : }
431 : :
432 : : /* Set the I2C clock */
433 : 1 : i2c_bus->i2c_clk = i2c_speed;
434 : 1 : ret = cdns_i2c_setclk(i2c_bus, i2c_bus->input_clk);
435 [ - + ]: 1 : if (ret != 0) {
436 [ # # ]: 0 : LOG_ERR("Invalid SCL clock: %u Hz", i2c_bus->i2c_clk);
437 : 0 : ret = -EIO;
438 : 0 : goto out;
439 : : }
440 : :
441 : : /* Enable the I2C peripheral */
442 : 1 : i2c_bus->ctrl_reg |= CDNS_I2C_CR_ACK_EN | CDNS_I2C_CR_NEA | CDNS_I2C_CR_MS;
443 : 1 : cdns_i2c_enable_peripheral(i2c_bus);
444 : :
445 : : /* Save I2C host configuration */
446 : 1 : i2c_bus->i2c_config = dev_config;
447 : :
448 : 1 : out:
449 : 1 : (void)k_mutex_unlock(&i2c_bus->bus_mutex);
450 : :
451 : 1 : return ret;
452 : : }
453 : :
454 : : /**
455 : : * cdns_i2c_get_config - Retrieve the saved I2C configuration.
456 : : * @dev: Pointer to the device structure.
457 : : * @dev_config: Pointer to a variable where the configuration will be stored.
458 : : *
459 : : * Return: 0 on success, or a negative error code on failure.
460 : : */
461 : 1 : static int32_t cdns_i2c_get_config(const struct device *dev, uint32_t *dev_config)
462 : : {
463 : 1 : int32_t ret = 0;
464 : 1 : struct cdns_i2c_data *i2c_bus = (struct cdns_i2c_data *)dev->data;
465 : :
466 : : /* Check if the configuration is valid (non-zero) */
467 [ - + ]: 1 : if (i2c_bus->i2c_config == 0U) {
468 : 0 : ret = -EINVAL;
469 : : } else {
470 : : /* Return the saved configuration */
471 : 1 : *dev_config = i2c_bus->i2c_config;
472 : : }
473 : :
474 : 1 : return ret;
475 : : }
476 : :
477 : : /**
478 : : * cdns_i2c_clear_bus_hold - Clear bus hold bit in the controller's register
479 : : * @i2c_bus: Pointer to the I2C controller driver data structure
480 : : */
481 : 5 : static void cdns_i2c_clear_bus_hold(struct cdns_i2c_data *i2c_bus)
482 : : {
483 : 5 : uint32_t reg = cdns_i2c_readreg(i2c_bus, CDNS_I2C_CR_OFFSET);
484 : :
485 [ - + ]: 5 : if ((reg & CDNS_I2C_CR_HOLD) == CDNS_I2C_CR_HOLD) {
486 : 0 : cdns_i2c_writereg(i2c_bus, reg & ~CDNS_I2C_CR_HOLD, CDNS_I2C_CR_OFFSET);
487 : : }
488 : 5 : }
489 : :
490 : : /**
491 : : * cdns_is_fifo_hold_quirk - Check if the FIFO hold quirk is triggered for I2C
492 : : * @i2c_bus: Pointer to the I2C controller driver data structure
493 : : * @hold_wrkaround: Boolean indicating if hold workarounds should be applied
494 : : *
495 : : * Return: True if the quirk condition is met, false otherwise.
496 : : */
497 : 8 : static inline bool cdns_is_fifo_hold_quirk(const struct cdns_i2c_data *i2c_bus,
498 : : bool hold_wrkaround)
499 : : {
500 [ - + - - ]: 8 : return (hold_wrkaround && (i2c_bus->curr_recv_count == (i2c_bus->fifo_depth + 1U)));
501 : : }
502 : :
503 : : #if defined(CONFIG_I2C_TARGET)
504 : : /**
505 : : * cdns_i2c_set_mode - Set the I2C bus mode (master or slave)
506 : : * @mode: The mode to set (CDNS_I2C_MODE_MASTER or CDNS_I2C_MODE_SLAVE)
507 : : * @i2c_bus: Pointer to the I2C data structure
508 : : */
509 : : static void cdns_i2c_set_mode(enum cdns_i2c_mode mode, struct cdns_i2c_data *i2c_bus)
510 : : {
511 : : /* Disable all interrupts */
512 : : cdns_i2c_writereg(i2c_bus, CDNS_I2C_IXR_ALL_INTR_MASK, CDNS_I2C_IDR_OFFSET);
513 : :
514 : : /* Clear FIFO and reset transfer size */
515 : : cdns_i2c_writereg(i2c_bus, CDNS_I2C_CR_CLR_FIFO, CDNS_I2C_CR_OFFSET);
516 : :
517 : : /* Update the I2C device mode and state */
518 : : i2c_bus->dev_mode = mode;
519 : : i2c_bus->slave_state = CDNS_I2C_SLAVE_STATE_IDLE;
520 : :
521 : : if (mode == CDNS_I2C_MODE_MASTER) {
522 : : /* Enable i2c master */
523 : : cdns_i2c_writereg(i2c_bus, i2c_bus->ctrl_reg_diva_divb |
524 : : CDNS_I2C_CR_MASTER_EN_MASK,
525 : : CDNS_I2C_CR_OFFSET);
526 : :
527 : : /* Allow time for master mode to stabilize */
528 : : (void)k_usleep(120);
529 : : } else {
530 : : /* Enable i2c slave */
531 : : cdns_i2c_writereg(i2c_bus, i2c_bus->ctrl_reg_diva_divb &
532 : : CDNS_I2C_CR_SLAVE_EN_MASK,
533 : : CDNS_I2C_CR_OFFSET);
534 : :
535 : : /* Configure the slave address */
536 : : cdns_i2c_writereg(i2c_bus,
537 : : ((uint32_t)(i2c_bus->slave->address) & CDNS_I2C_ADDR_MASK),
538 : : CDNS_I2C_ADDR_OFFSET);
539 : :
540 : : /* Enable slave send/receive interrupts */
541 : : cdns_i2c_writereg(i2c_bus, CDNS_I2C_IXR_SLAVE_INTR_MASK, CDNS_I2C_IER_OFFSET);
542 : : }
543 : : }
544 : :
545 : : /**
546 : : * cdns_i2c_slave_rcv_data - Handle data reception for I2C slave mode
547 : : * @i2c_bus: Pointer to the I2C data structure
548 : : */
549 : : static void cdns_i2c_slave_rcv_data(struct cdns_i2c_data *i2c_bus)
550 : : {
551 : : uint8_t bytes;
552 : : uint8_t data;
553 : : const struct i2c_target_callbacks *i2c_slave_event = i2c_bus->slave->callbacks;
554 : :
555 : : /* Prepare backend for data reception */
556 : : if (i2c_bus->slave_state == CDNS_I2C_SLAVE_STATE_IDLE) {
557 : : i2c_bus->slave_state = CDNS_I2C_SLAVE_STATE_RECV;
558 : : if ((i2c_slave_event != NULL) &&
559 : : (i2c_slave_event->write_requested != NULL)) {
560 : : (void)i2c_slave_event->write_requested(i2c_bus->slave);
561 : : }
562 : : }
563 : :
564 : : /* Fetch number of bytes to receive */
565 : : bytes = (uint8_t)cdns_i2c_readreg(i2c_bus, CDNS_I2C_XFER_SIZE_OFFSET);
566 : :
567 : : /* Read data and send it to backend */
568 : : while (bytes > 0U) {
569 : : data = (uint8_t)cdns_i2c_readreg(i2c_bus, CDNS_I2C_DATA_OFFSET);
570 : : if ((i2c_slave_event != NULL) &&
571 : : (i2c_slave_event->write_requested != NULL)) {
572 : : (void)i2c_slave_event->write_received(i2c_bus->slave, data);
573 : : }
574 : : bytes--;
575 : : }
576 : : }
577 : :
578 : : /**
579 : : * cdns_i2c_slave_send_data - Handle data transmission for I2C slave mode
580 : : * @i2c_bus: Pointer to the I2C data structure
581 : : */
582 : : static void cdns_i2c_slave_send_data(struct cdns_i2c_data *i2c_bus)
583 : : {
584 : : uint8_t data = 0U;
585 : : const struct i2c_target_callbacks *i2c_slave_event = i2c_bus->slave->callbacks;
586 : :
587 : : /* Prepare backend for data transmission */
588 : : if (i2c_bus->slave_state == CDNS_I2C_SLAVE_STATE_IDLE) {
589 : : i2c_bus->slave_state = CDNS_I2C_SLAVE_STATE_SEND;
590 : : if ((i2c_slave_event != NULL) &&
591 : : (i2c_slave_event->read_requested != NULL)) {
592 : : (void)i2c_slave_event->read_requested(i2c_bus->slave, &data);
593 : : }
594 : : } else {
595 : : if ((i2c_slave_event != NULL) &&
596 : : (i2c_slave_event->read_processed != NULL)) {
597 : : (void)i2c_slave_event->read_processed(i2c_bus->slave, &data);
598 : : }
599 : : }
600 : :
601 : : /* Send data over the bus */
602 : : cdns_i2c_writereg(i2c_bus, data, CDNS_I2C_DATA_OFFSET);
603 : : }
604 : :
605 : : /**
606 : : * cdns_slave_handle_receive_interrupt - Handle the receive interrupt for I2C slave.
607 : : * @i2c_bus: Pointer to the I2C data structure.
608 : : * @isr_status: Interrupt status, indicating the cause of the interrupt.
609 : : */
610 : : static void cdns_slave_handle_receive_interrupt(struct cdns_i2c_data *i2c_bus, uint32_t isr_status)
611 : : {
612 : : const struct i2c_target_callbacks *i2c_slave_event = i2c_bus->slave->callbacks;
613 : :
614 : : /* Receive data from master */
615 : : if ((isr_status & CDNS_I2C_IXR_DATA) == CDNS_I2C_IXR_DATA) {
616 : : cdns_i2c_slave_rcv_data(i2c_bus);
617 : : }
618 : :
619 : : /* Transfer complete, reset state */
620 : : if ((isr_status & CDNS_I2C_IXR_COMP) == CDNS_I2C_IXR_COMP) {
621 : : cdns_i2c_slave_rcv_data(i2c_bus); /* Ensure final reception */
622 : : i2c_bus->slave_state = CDNS_I2C_SLAVE_STATE_IDLE;
623 : : if ((i2c_slave_event != NULL) && (i2c_slave_event->stop != NULL)) {
624 : : (void)i2c_slave_event->stop(i2c_bus->slave);
625 : : }
626 : : }
627 : : }
628 : :
629 : : /**
630 : : * cdns_slave_handle_transmit_interrupt - Handle the transmit interrupt for I2C slave.
631 : : * @i2c_bus: Pointer to the I2C data structure.
632 : : * @isr_status: Interrupt status, indicating the cause of the interrupt.
633 : : */
634 : : static void cdns_slave_handle_transmit_interrupt(struct cdns_i2c_data *i2c_bus, uint32_t isr_status)
635 : : {
636 : : const struct i2c_target_callbacks *i2c_slave_event = i2c_bus->slave->callbacks;
637 : :
638 : : /* Send data to master */
639 : : if ((isr_status & CDNS_I2C_IXR_DATA) == CDNS_I2C_IXR_DATA) {
640 : : cdns_i2c_slave_send_data(i2c_bus);
641 : : }
642 : :
643 : : /* Transfer complete, reset state */
644 : : if ((isr_status & CDNS_I2C_IXR_COMP) == CDNS_I2C_IXR_COMP) {
645 : : i2c_bus->slave_state = CDNS_I2C_SLAVE_STATE_IDLE;
646 : : if ((i2c_slave_event != NULL) && (i2c_slave_event->stop != NULL)) {
647 : : (void)i2c_slave_event->stop(i2c_bus->slave);
648 : : }
649 : : }
650 : : }
651 : :
652 : : /**
653 : : * cdns_slave_handle_error_interrupt - Handle the error interrupt for I2C slave.
654 : : * @i2c_bus: Pointer to the I2C data structure.
655 : : * @isr_status: Interrupt status, indicating the cause of the error.
656 : : */
657 : : static void cdns_slave_handle_error_interrupt(struct cdns_i2c_data *i2c_bus, uint32_t isr_status)
658 : : {
659 : : const struct i2c_target_callbacks *i2c_slave_event = i2c_bus->slave->callbacks;
660 : :
661 : : /* Master indicated xfer stop or FIFO underflow/overflow */
662 : : if ((isr_status & (CDNS_I2C_IXR_NACK | CDNS_I2C_IXR_RX_OVF |
663 : : CDNS_I2C_IXR_RX_UNF | CDNS_I2C_IXR_TX_OVF)) != 0U) {
664 : : i2c_bus->slave_state = CDNS_I2C_SLAVE_STATE_IDLE;
665 : : if ((i2c_slave_event != NULL) && (i2c_slave_event->stop != NULL)) {
666 : : (void)i2c_slave_event->stop(i2c_bus->slave);
667 : : }
668 : : /* Clear FIFO errors */
669 : : cdns_i2c_writereg(i2c_bus, CDNS_I2C_CR_CLR_FIFO, CDNS_I2C_CR_OFFSET);
670 : : }
671 : : }
672 : :
673 : : /**
674 : : * cdns_i2c_slave_isr - Interrupt Service Routine for the I2C slave
675 : : * @i2c_bus: Pointer to the I2C data structure
676 : : *
677 : : * The function processes the interrupt status, handles the data transfer
678 : : * (send/receive), and clears any necessary interrupt flags.
679 : : */
680 : : static void cdns_i2c_slave_isr(struct cdns_i2c_data *i2c_bus)
681 : : {
682 : : uint32_t isr_status, i2c_status;
683 : :
684 : : /* Fetch and clear the interrupt status */
685 : : isr_status = cdns_i2c_readreg(i2c_bus, CDNS_I2C_ISR_OFFSET);
686 : : cdns_i2c_writereg(i2c_bus, isr_status, CDNS_I2C_ISR_OFFSET);
687 : :
688 : : /* Masked interrupts handling */
689 : : isr_status &= ~cdns_i2c_readreg(i2c_bus, CDNS_I2C_IMR_OFFSET);
690 : :
691 : : /* Fetch transfer mode (send/receive) */
692 : : i2c_status = cdns_i2c_readreg(i2c_bus, CDNS_I2C_SR_OFFSET);
693 : :
694 : : /* Handle data send/receive based on transfer mode */
695 : : if ((i2c_status & CDNS_I2C_SR_RXRW) == CDNS_I2C_SR_RXRW) {
696 : : cdns_slave_handle_transmit_interrupt(i2c_bus, isr_status);
697 : : } else {
698 : : cdns_slave_handle_receive_interrupt(i2c_bus, isr_status);
699 : : }
700 : :
701 : : /* Handle any errors (FIFO, NACK, overflow, underflow) */
702 : : cdns_slave_handle_error_interrupt(i2c_bus, isr_status);
703 : : }
704 : : #endif
705 : :
706 : : /**
707 : : * cdns_i2c_master_handle_receive_interrupt - Handles I2C master receive interrupts
708 : : * @i2c_bus: Pointer to the I2C data structure
709 : : * @isr_status: Interrupt status, indicating the cause of the interrupt
710 : : */
711 : 3 : static void cdns_i2c_master_handle_receive_interrupt(struct cdns_i2c_data *i2c_bus,
712 : : uint32_t isr_status)
713 : : {
714 : : uint32_t transfer_size;
715 : : uint32_t xfer_size;
716 : :
717 : : /* Handle reception interrupt (data available or transfer complete) */
718 [ - + - - ]: 3 : if (((isr_status & CDNS_I2C_IXR_COMP) == 0U) && ((isr_status & CDNS_I2C_IXR_DATA) == 0U)) {
719 : 0 : return;
720 : : }
721 : :
722 : : /* Receiving Data: Keep reading as long as data is available */
723 [ + + ]: 8 : while ((cdns_i2c_readreg(i2c_bus, CDNS_I2C_SR_OFFSET) & CDNS_I2C_SR_RXDV) != 0U) {
724 : : /* Ensure there's space to store received data */
725 [ + - ]: 5 : if (i2c_bus->recv_count > 0U) {
726 : 5 : *(i2c_bus->p_recv_buf) = (uint8_t)cdns_i2c_readreg(i2c_bus,
727 : : CDNS_I2C_DATA_OFFSET);
728 : 5 : i2c_bus->p_recv_buf++;
729 : 5 : i2c_bus->recv_count--;
730 : 5 : i2c_bus->curr_recv_count--;
731 : : } else {
732 : : /* Handle receive buffer overflow or unexpected condition */
733 [ # # ]: 0 : LOG_ERR("I2C receive buffer overflow. Transfer aborted!");
734 : 0 : i2c_bus->err_status |= CDNS_I2C_IXR_TO;
735 : 0 : break;
736 : : }
737 : :
738 : : /* Handle issues with receiving more data than expected */
739 [ - + ]: 5 : if (cdns_is_fifo_hold_quirk(i2c_bus,
740 : 5 : i2c_bus->recv_count > i2c_bus->curr_recv_count)) {
741 : 0 : break;
742 : : }
743 : : }
744 : :
745 : : /* Workaround for large data receive in case of FIFO space issues */
746 [ - + ]: 3 : if (cdns_is_fifo_hold_quirk(i2c_bus, i2c_bus->recv_count > i2c_bus->curr_recv_count)) {
747 : 0 : transfer_size = i2c_bus->recv_count - i2c_bus->fifo_depth;
748 : :
749 [ # # ]: 0 : if (transfer_size > i2c_bus->transfer_size) {
750 : 0 : xfer_size = i2c_bus->transfer_size;
751 : : } else {
752 : 0 : xfer_size = transfer_size;
753 : : }
754 : :
755 : : /* Busy-wait until FIFO has space for more data */
756 : 0 : while (cdns_i2c_readreg(i2c_bus, CDNS_I2C_XFER_SIZE_OFFSET) !=
757 [ # # ]: 0 : (i2c_bus->curr_recv_count - i2c_bus->fifo_depth)) {
758 : : }
759 : :
760 : : /* Update the transfer size for the next batch of data */
761 : 0 : cdns_i2c_writereg(i2c_bus, xfer_size, CDNS_I2C_XFER_SIZE_OFFSET);
762 : 0 : i2c_bus->curr_recv_count = xfer_size + i2c_bus->fifo_depth;
763 : : }
764 : :
765 : : /* Complete transfer if all data has been received and no more data is expected */
766 [ + - ]: 3 : if (((isr_status & CDNS_I2C_IXR_COMP) == CDNS_I2C_IXR_COMP) &&
767 [ + - ]: 3 : (i2c_bus->recv_count == 0U)) {
768 : : /* Release bus hold if no longer needed */
769 [ + - ]: 3 : if (i2c_bus->bus_hold_flag == 0U) {
770 : 3 : cdns_i2c_clear_bus_hold(i2c_bus);
771 : : }
772 : : /* Notify completion of the transfer */
773 : 3 : (void)k_event_post(&i2c_bus->xfer_done, I2C_XFER_COMPLETION_EVENT);
774 : : }
775 : : }
776 : :
777 : : /**
778 : : * cdns_i2c_master_handle_transmit_interrupt - Handles I2C master transmit interrupts
779 : : * @i2c_bus: Pointer to the I2C data structure
780 : : * @isr_status: Interrupt status, indicating the cause of the interrupt
781 : : */
782 : 3 : static void cdns_i2c_master_handle_transmit_interrupt(struct cdns_i2c_data *i2c_bus,
783 : : uint32_t isr_status)
784 : : {
785 : : uint32_t avail_bytes;
786 : : uint32_t bytes_to_send;
787 : :
788 : : /* Handle transmission interrupt (data sent or transfer complete) */
789 [ - + ]: 3 : if ((isr_status & CDNS_I2C_IXR_COMP) == 0U) {
790 : 0 : return;
791 : : }
792 : :
793 : : /* Sending data: Check if there is any data left to send */
794 [ - + ]: 3 : if (i2c_bus->send_count > 0U) {
795 : : /* Calculate how many bytes can be sent based on FIFO availability */
796 : 0 : avail_bytes = i2c_bus->fifo_depth - cdns_i2c_readreg(i2c_bus,
797 : : CDNS_I2C_XFER_SIZE_OFFSET);
798 : :
799 [ # # ]: 0 : if (i2c_bus->send_count > avail_bytes) {
800 : 0 : bytes_to_send = avail_bytes;
801 : : } else {
802 : 0 : bytes_to_send = i2c_bus->send_count;
803 : : }
804 : :
805 : : /* Write data to the I2C data register */
806 [ # # ]: 0 : while (bytes_to_send > 0U) {
807 : 0 : cdns_i2c_writereg(i2c_bus, *(i2c_bus->p_send_buf), CDNS_I2C_DATA_OFFSET);
808 : 0 : i2c_bus->p_send_buf++;
809 : 0 : i2c_bus->send_count--;
810 : 0 : bytes_to_send--;
811 : : }
812 : : } else {
813 : : /* If there is no data to send, signal transfer completion */
814 : 3 : (void)k_event_post(&i2c_bus->xfer_done, I2C_XFER_COMPLETION_EVENT);
815 : : }
816 : :
817 : : /* Clear bus hold if no more data is pending */
818 [ + - + + ]: 3 : if ((i2c_bus->send_count == 0U) && (i2c_bus->bus_hold_flag == 0U)) {
819 : 1 : cdns_i2c_clear_bus_hold(i2c_bus);
820 : : }
821 : : }
822 : :
823 : : /**
824 : : * cdns_i2c_master_isr - Interrupt handler for the I2C device in master role
825 : : * @i2c_bus: Pointer to I2C device private data structure
826 : : *
827 : : * This function handles various interrupt events including data received,
828 : : * transfer complete, and error interrupts for the I2C master role.
829 : : */
830 : 6 : static void cdns_i2c_master_isr(struct cdns_i2c_data *i2c_bus)
831 : : {
832 : : uint32_t isr_status;
833 : :
834 : : /* Read the interrupt status register */
835 : 6 : isr_status = cdns_i2c_readreg(i2c_bus, CDNS_I2C_ISR_OFFSET);
836 : :
837 : : /* Clear interrupt status */
838 : 6 : cdns_i2c_writereg(i2c_bus, isr_status, CDNS_I2C_ISR_OFFSET);
839 : :
840 : : /* Update the error status based on interrupt flags */
841 : 6 : i2c_bus->err_status = isr_status & CDNS_I2C_IXR_ERR_INTR_MASK;
842 : :
843 : : /* Handling NACK or arbitration lost interrupts */
844 [ - + ]: 6 : if ((isr_status & (CDNS_I2C_IXR_NACK | CDNS_I2C_IXR_ARB_LOST)) != 0U) {
845 : 0 : (void)k_event_post(&i2c_bus->xfer_done, I2C_XFER_COMPLETION_EVENT);
846 : 0 : return;
847 : : }
848 : :
849 : : /* Handle reception interrupt */
850 [ + + ]: 6 : if (i2c_bus->p_recv_buf != NULL) {
851 : 3 : cdns_i2c_master_handle_receive_interrupt(i2c_bus, isr_status);
852 : : }
853 : :
854 : : /* Handle transmission interrupt */
855 [ + + ]: 6 : if (i2c_bus->p_recv_buf == NULL) {
856 : 3 : cdns_i2c_master_handle_transmit_interrupt(i2c_bus, isr_status);
857 : : }
858 : : }
859 : :
860 : : /**
861 : : * cdns_i2c_isr - Interrupt handler for the I2C controller
862 : : * @dev: Pointer to I2C device
863 : : *
864 : : * If the controller is in slave mode, the slave ISR is invoked.
865 : : * If the controller is in master mode, the master ISR is used.
866 : : */
867 : 6 : static void cdns_i2c_isr(const struct device *dev)
868 : : {
869 : 6 : struct cdns_i2c_data *i2c_bus = (struct cdns_i2c_data *)dev->data;
870 : :
871 : : #if defined(CONFIG_I2C_TARGET)
872 : : /* Handle the interrupt for slave mode */
873 : : if (i2c_bus->dev_mode == CDNS_I2C_MODE_SLAVE) {
874 : : cdns_i2c_slave_isr(i2c_bus);
875 : : return;
876 : : }
877 : : #endif
878 : : /* Handle the interrupt for master mode */
879 : 6 : cdns_i2c_master_isr(i2c_bus);
880 : 6 : }
881 : :
882 : : /**
883 : : * cdns_i2c_mrecv - Prepare and start a master receive operation
884 : : * @i2c_bus: Pointer to the I2C data structure
885 : : * @msg_addr: The address of the slave device to receive data from
886 : : */
887 : 3 : static void cdns_i2c_mrecv(struct cdns_i2c_data *i2c_bus, uint16_t msg_addr)
888 : : {
889 : : uint32_t ctrl_reg;
890 : : uint32_t isr_status;
891 : 3 : bool hold_clear = false;
892 : 3 : bool irq_save = false;
893 : : uint32_t addr;
894 : :
895 : : /* Initialize the receive buffer and count */
896 : 3 : i2c_bus->p_recv_buf = i2c_bus->p_msg->buf;
897 : 3 : i2c_bus->recv_count = i2c_bus->p_msg->len;
898 : 3 : i2c_bus->curr_recv_count = i2c_bus->recv_count;
899 : :
900 : : /* Prepare controller for master receive mode and clear FIFO */
901 : 3 : ctrl_reg = cdns_i2c_readreg(i2c_bus, CDNS_I2C_CR_OFFSET);
902 : 3 : ctrl_reg |= CDNS_I2C_CR_RW | CDNS_I2C_CR_CLR_FIFO;
903 : :
904 : : /* Check if the message size exceeds FIFO depth, hold the bus if true */
905 [ - + ]: 3 : if (i2c_bus->recv_count > i2c_bus->fifo_depth) {
906 : 0 : ctrl_reg |= CDNS_I2C_CR_HOLD;
907 : : }
908 : :
909 : 3 : cdns_i2c_writereg(i2c_bus, ctrl_reg, CDNS_I2C_CR_OFFSET);
910 : :
911 : : /* Clear the interrupts in interrupt status register */
912 : 3 : isr_status = cdns_i2c_readreg(i2c_bus, CDNS_I2C_ISR_OFFSET);
913 : 3 : cdns_i2c_writereg(i2c_bus, isr_status, CDNS_I2C_ISR_OFFSET);
914 : :
915 : : /* Set transfer size register and enable interrupts */
916 [ - + ]: 3 : if ((i2c_bus->recv_count) > (i2c_bus->transfer_size)) {
917 : 0 : cdns_i2c_writereg(i2c_bus, i2c_bus->transfer_size,
918 : : CDNS_I2C_XFER_SIZE_OFFSET);
919 : 0 : i2c_bus->curr_recv_count = i2c_bus->transfer_size;
920 : : } else {
921 : 3 : cdns_i2c_writereg(i2c_bus, i2c_bus->recv_count, CDNS_I2C_XFER_SIZE_OFFSET);
922 : : }
923 : :
924 : : /* Determine whether to clear the hold bit based on conditions */
925 [ + - + - ]: 3 : if ((i2c_bus->bus_hold_flag == 0U) && (i2c_bus->recv_count <= i2c_bus->fifo_depth)) {
926 [ + + ]: 3 : if ((ctrl_reg & CDNS_I2C_CR_HOLD) != 0U) {
927 : 2 : hold_clear = true;
928 : :
929 : : /* Check if broken hold flag requires special handling */
930 [ - + ]: 2 : if ((i2c_bus->broken_hold_flag & CDNS_I2C_BROKEN_HOLD_BIT) != 0U) {
931 : 0 : irq_save = true;
932 : : }
933 : : }
934 : : }
935 : :
936 : : /* Mask address and prepare for I2C communication */
937 : 3 : addr = msg_addr;
938 : 3 : addr &= CDNS_I2C_ADDR_MASK;
939 : :
940 : : /* Handle clearing of the hold bit */
941 [ + + ]: 3 : if (hold_clear) {
942 : 2 : ctrl_reg &= ~CDNS_I2C_CR_HOLD;
943 : 2 : ctrl_reg &= ~CDNS_I2C_CR_CLR_FIFO;
944 : :
945 : : /* If IRQ saving is necessary, disable interrupts for a safe register write */
946 [ - + ]: 2 : if (irq_save) {
947 : 0 : (void)irq_lock();
948 : : }
949 : :
950 : : /* Write the address and control register values */
951 : 2 : cdns_i2c_writereg(i2c_bus, addr, CDNS_I2C_ADDR_OFFSET);
952 : 2 : cdns_i2c_writereg(i2c_bus, ctrl_reg, CDNS_I2C_CR_OFFSET);
953 : : /* Read back to ensure write completion */
954 : 2 : (void)cdns_i2c_readreg(i2c_bus, CDNS_I2C_CR_OFFSET);
955 : :
956 : : /* Restore IRQ state if needed */
957 [ - + ]: 2 : if (irq_save) {
958 : 0 : irq_unlock(0);
959 : : }
960 : : } else {
961 : : /* Directly write the address if no need to clear the hold bit */
962 : 1 : cdns_i2c_writereg(i2c_bus, addr, CDNS_I2C_ADDR_OFFSET);
963 : : }
964 : :
965 : : /* Enable interrupts */
966 : 3 : cdns_i2c_writereg(i2c_bus, CDNS_I2C_ENABLED_INTR_MASK, CDNS_I2C_IER_OFFSET);
967 : 3 : }
968 : :
969 : : /**
970 : : * cdns_i2c_msend - Prepare and start a master send operation
971 : : * @i2c_bus: Pointer to the I2C data structure
972 : : * @msg_addr: I2C address of the slave to communicate with
973 : : */
974 : 3 : static void cdns_i2c_msend(struct cdns_i2c_data *i2c_bus, uint16_t msg_addr)
975 : : {
976 : : uint32_t avail_bytes;
977 : : uint32_t bytes_to_send;
978 : : uint32_t ctrl_reg;
979 : : uint32_t isr_status;
980 : :
981 : : /* Initialize send buffer and update send count */
982 : 3 : i2c_bus->p_recv_buf = NULL;
983 : 3 : i2c_bus->p_send_buf = i2c_bus->p_msg->buf;
984 : 3 : i2c_bus->send_count = i2c_bus->p_msg->len;
985 : :
986 : : /* Configure the controller in Master transmit mode and clear FIFO. */
987 : 3 : ctrl_reg = cdns_i2c_readreg(i2c_bus, CDNS_I2C_CR_OFFSET);
988 : 3 : ctrl_reg &= ~CDNS_I2C_CR_RW;
989 : 3 : ctrl_reg |= CDNS_I2C_CR_CLR_FIFO;
990 : :
991 : : /* Check if the message size exceeds FIFO depth, hold the bus if true */
992 [ - + ]: 3 : if (i2c_bus->send_count > i2c_bus->fifo_depth) {
993 : 0 : ctrl_reg |= CDNS_I2C_CR_HOLD;
994 : : }
995 : 3 : cdns_i2c_writereg(i2c_bus, ctrl_reg, CDNS_I2C_CR_OFFSET);
996 : :
997 : : /* Clear any previous interrupt flags */
998 : 3 : isr_status = cdns_i2c_readreg(i2c_bus, CDNS_I2C_ISR_OFFSET);
999 : 3 : cdns_i2c_writereg(i2c_bus, isr_status, CDNS_I2C_ISR_OFFSET);
1000 : :
1001 : : /* Calculate available FIFO space and determine how many bytes to send */
1002 : 3 : avail_bytes = i2c_bus->fifo_depth - cdns_i2c_readreg(i2c_bus, CDNS_I2C_XFER_SIZE_OFFSET);
1003 : 3 : bytes_to_send = (i2c_bus->send_count > avail_bytes) ? avail_bytes : i2c_bus->send_count;
1004 : :
1005 : : /* Send data to FIFO until all bytes are transmitted */
1006 [ + + ]: 6 : while (bytes_to_send > 0U) {
1007 : 3 : cdns_i2c_writereg(i2c_bus, (*(i2c_bus->p_send_buf)), CDNS_I2C_DATA_OFFSET);
1008 : 3 : (i2c_bus->p_send_buf)++;
1009 : 3 : i2c_bus->send_count--;
1010 : 3 : bytes_to_send--;
1011 : : }
1012 : :
1013 : : /* Clear the 'hold bus' flag if there's no more data and it's the last message */
1014 [ + + + - ]: 3 : if ((i2c_bus->bus_hold_flag == 0U) && (i2c_bus->send_count == 0U)) {
1015 : 1 : cdns_i2c_clear_bus_hold(i2c_bus);
1016 : : }
1017 : :
1018 : : /* Set the slave address to trigger operation. */
1019 : 3 : cdns_i2c_writereg(i2c_bus, ((uint32_t)msg_addr & CDNS_I2C_ADDR_MASK),
1020 : : CDNS_I2C_ADDR_OFFSET);
1021 : :
1022 : : /* Enable interrupts after data transmission starts */
1023 : 3 : cdns_i2c_writereg(i2c_bus, CDNS_I2C_ENABLED_INTR_MASK, CDNS_I2C_IER_OFFSET);
1024 : 3 : }
1025 : :
1026 : : /**
1027 : : * cdns_i2c_master_reset - Reset the I2C master interface
1028 : : * @i2c_bus: Pointer to the i2c driver instance
1029 : : *
1030 : : * This function performs a full reset of the I2C master interface
1031 : : * The reset ensures that the interface is returned to a known idle state.
1032 : : */
1033 : 0 : static void cdns_i2c_master_reset(struct cdns_i2c_data *i2c_bus)
1034 : : {
1035 : : uint32_t regval;
1036 : :
1037 : : /* Disable the interrupts */
1038 : 0 : cdns_i2c_writereg(i2c_bus, CDNS_I2C_IXR_ALL_INTR_MASK, CDNS_I2C_IDR_OFFSET);
1039 : :
1040 : : /* Clear the hold bit and flush FIFOs */
1041 : 0 : regval = cdns_i2c_readreg(i2c_bus, CDNS_I2C_CR_OFFSET);
1042 : 0 : regval &= ~CDNS_I2C_CR_HOLD;
1043 : 0 : regval |= CDNS_I2C_CR_CLR_FIFO;
1044 : 0 : cdns_i2c_writereg(i2c_bus, regval, CDNS_I2C_CR_OFFSET);
1045 : :
1046 : : /* Reset transfer count register to zero */
1047 : 0 : cdns_i2c_writereg(i2c_bus, 0, CDNS_I2C_XFER_SIZE_OFFSET);
1048 : :
1049 : : /* Clear the interrupt status register */
1050 : 0 : regval = cdns_i2c_readreg(i2c_bus, CDNS_I2C_ISR_OFFSET);
1051 : 0 : cdns_i2c_writereg(i2c_bus, regval, CDNS_I2C_ISR_OFFSET);
1052 : :
1053 : : /* Clear the status register */
1054 : 0 : regval = cdns_i2c_readreg(i2c_bus, CDNS_I2C_SR_OFFSET);
1055 : 0 : cdns_i2c_writereg(i2c_bus, regval, CDNS_I2C_SR_OFFSET);
1056 : 0 : }
1057 : :
1058 : : /**
1059 : : * cdns_i2c_process_msg - Processes an I2C message on the specified I2C bus
1060 : : * @i2c_bus: Pointer to the I2C data structure
1061 : : * @msg: Pointer to the I2C message to be processed
1062 : : * @addr: The 7-bit or 10-bit I2C address of the slave device
1063 : : *
1064 : : * Return: 0 on success, negative error code on failure.
1065 : : */
1066 : 6 : static int32_t cdns_i2c_process_msg(struct cdns_i2c_data *i2c_bus, struct i2c_msg *msg,
1067 : : uint16_t addr)
1068 : : {
1069 : 6 : int32_t ret = 0;
1070 : : uint32_t reg;
1071 : : k_timeout_t msg_timeout;
1072 : : uint32_t events;
1073 : :
1074 : : /* Initialize message processing state */
1075 : 6 : i2c_bus->p_msg = msg;
1076 : 6 : i2c_bus->err_status = 0U;
1077 : 6 : (void)k_event_clear(&i2c_bus->xfer_done, (uint32_t)I2C_XFER_COMPLETION_EVENT);
1078 : :
1079 : : /* Handle 10-bit addressing mode */
1080 : 6 : reg = cdns_i2c_readreg(i2c_bus, CDNS_I2C_CR_OFFSET);
1081 [ - + ]: 6 : if ((msg->flags & I2C_MSG_ADDR_10_BITS) != 0U) {
1082 : : /* Enable 10-bit address mode if not already enabled */
1083 [ # # ]: 0 : if ((reg & CDNS_I2C_CR_NEA) == CDNS_I2C_CR_NEA) {
1084 : 0 : cdns_i2c_writereg(i2c_bus,
1085 : : reg & ~CDNS_I2C_CR_NEA,
1086 : : CDNS_I2C_CR_OFFSET);
1087 : : }
1088 : : } else {
1089 : : /* Disable 10-bit address mode if currently enabled */
1090 [ - + ]: 6 : if ((reg & CDNS_I2C_CR_NEA) == 0U) {
1091 : 0 : cdns_i2c_writereg(i2c_bus,
1092 : 0 : reg | CDNS_I2C_CR_NEA,
1093 : : CDNS_I2C_CR_OFFSET);
1094 : : }
1095 : : }
1096 : :
1097 : : /* Handle read/write flag and perform the appropriate action */
1098 [ + + ]: 6 : if ((msg->flags & I2C_MSG_READ) != 0U) {
1099 : 3 : cdns_i2c_mrecv(i2c_bus, addr); /* Receive data */
1100 : : } else {
1101 : 3 : cdns_i2c_msend(i2c_bus, addr); /* Send data */
1102 : : }
1103 : :
1104 : : /* Calculate the minimal timeout based on message length */
1105 : 6 : msg_timeout.ticks = (((k_ticks_t)(msg->len) * 8)*(CDNS_I2C_TICKS_PER_SEC)) /
1106 : 6 : ((k_ticks_t)(i2c_bus->i2c_clk));
1107 : 6 : msg_timeout.ticks += (CDNS_I2C_TICKS_PER_SEC / 2);
1108 [ + - ]: 6 : if (msg_timeout.ticks < CDNS_I2C_TIMEOUT_TICKS) {
1109 : 6 : msg_timeout.ticks = CDNS_I2C_TIMEOUT_TICKS;
1110 : : }
1111 : :
1112 : : /* Wait for the completion signal or timeout */
1113 : 6 : events = k_event_wait(&i2c_bus->xfer_done, (uint32_t)I2C_XFER_COMPLETION_EVENT,
1114 : : false, msg_timeout);
1115 [ - + ]: 6 : if ((events & I2C_XFER_COMPLETION_EVENT) == 0U) {
1116 : : /* Timeout occurred, reset the master */
1117 : 0 : cdns_i2c_master_reset(i2c_bus);
1118 : 0 : ret = -ETIMEDOUT;
1119 : 0 : goto out;
1120 : : }
1121 : :
1122 : : /* Disable interrupt masking for the current transfer */
1123 : 6 : cdns_i2c_writereg(i2c_bus, CDNS_I2C_IXR_ALL_INTR_MASK, CDNS_I2C_IDR_OFFSET);
1124 : :
1125 : : /* If it is bus arbitration error, try again */
1126 [ + - ]: 6 : if ((i2c_bus->err_status & CDNS_I2C_IXR_ARB_LOST) == CDNS_I2C_IXR_ARB_LOST) {
1127 : 0 : ret = -EAGAIN;
1128 : : }
1129 : :
1130 : 6 : out:
1131 : 6 : return ret;
1132 : : }
1133 : :
1134 : : /**
1135 : : * cdns_i2c_wait_for_bus_free - Wait for the I2C bus to become free.
1136 : : * @i2c_bus: Pointer to the I2C data structure that holds bus state information.
1137 : : * @timeout_us: Maximum time (in microseconds) to wait for the bus to become free.
1138 : : *
1139 : : * This function waits for the I2C bus to become idle. It checks the bus state
1140 : : * register periodically until the bus is free or the timeout occurs.
1141 : : *
1142 : : * Return: true if the bus is free within the timeout, false otherwise.
1143 : : */
1144 : 4 : static bool cdns_i2c_wait_for_bus_free(struct cdns_i2c_data *i2c_bus, uint32_t timeout_us)
1145 : : {
1146 : 4 : bool ret_flag = false;
1147 : : uint32_t reg;
1148 : :
1149 : : /* Poll until the bus is free or the timeout is reached */
1150 [ + - ]: 4 : while (timeout_us > 0U) {
1151 : 4 : reg = cdns_i2c_readreg(i2c_bus, CDNS_I2C_SR_OFFSET);
1152 [ + - ]: 4 : if ((reg & CDNS_I2C_SR_BA) == 0U) {
1153 : : /* Bus Available (BA) bit is cleared, the bus is free */
1154 : 4 : ret_flag = true;
1155 : 4 : break;
1156 : : }
1157 : :
1158 : : /* Wait for a small period before checking again */
1159 : 0 : (void)k_usleep((int32_t)CDNS_I2C_POLL_US);
1160 : 0 : timeout_us -= CDNS_I2C_POLL_US;
1161 : : }
1162 : :
1163 [ - + ]: 4 : if (timeout_us == 0U) {
1164 : : /* Timeout reached, bus not available */
1165 : 0 : ret_flag = false;
1166 : : }
1167 : :
1168 : 4 : return ret_flag;
1169 : : }
1170 : :
1171 : : /**
1172 : : * cdns_i2c_master_handle_repeated_start - Handle repeated start during I2C master transfer
1173 : : * @i2c_bus: Pointer to the I2C data structure that holds bus state information
1174 : : * @msgs: Array of I2C messages to be processed
1175 : : * @num_msgs: Number of messages in the @msgs array
1176 : : *
1177 : : * Return: 0 on success, or a negative error code on failure
1178 : : */
1179 : 2 : static int32_t cdns_i2c_master_handle_repeated_start(struct cdns_i2c_data *i2c_bus,
1180 : : struct i2c_msg *msgs, uint8_t num_msgs)
1181 : : {
1182 : 2 : int32_t ret = 0;
1183 : : uint32_t reg;
1184 : : uint32_t count;
1185 : 2 : bool hold_quirk = false;
1186 : 2 : struct i2c_msg *msg_ptr = msgs;
1187 : :
1188 : : /* Handle potential quirks with bus holding on hardware using Controller Version 1.0 */
1189 [ - + ]: 2 : if ((i2c_bus->broken_hold_flag & CDNS_I2C_BROKEN_HOLD_BIT) == CDNS_I2C_BROKEN_HOLD_BIT) {
1190 : 0 : hold_quirk = true;
1191 : : }
1192 : :
1193 : : /* Check if the first message is a read, then no repeated start can follow */
1194 [ + - - + ]: 2 : for (count = 0; ((count < ((uint32_t)num_msgs - 1U)) && hold_quirk); count++) {
1195 [ # # ]: 0 : if ((msg_ptr[count].flags & I2C_MSG_READ) != 0U) {
1196 [ # # ]: 0 : LOG_ERR("Can't do repeated start after a receive message");
1197 : 0 : ret = -EOPNOTSUPP;
1198 : 0 : goto out;
1199 : : }
1200 : : }
1201 : :
1202 : : /* Set the hold flag and register */
1203 : 2 : i2c_bus->bus_hold_flag = 1;
1204 : 2 : reg = cdns_i2c_readreg(i2c_bus, CDNS_I2C_CR_OFFSET);
1205 : 2 : reg |= CDNS_I2C_CR_HOLD;
1206 : 2 : cdns_i2c_writereg(i2c_bus, reg, CDNS_I2C_CR_OFFSET);
1207 : :
1208 : 2 : out:
1209 : 2 : return ret;
1210 : : }
1211 : :
1212 : : /**
1213 : : * cdns_i2c_master_handle_transfer_error - Handle errors during I2C master transfer.
1214 : : * @i2c_bus: Pointer to the I2C data structure
1215 : : *
1216 : : * Return: -EIO or -ENXIO.
1217 : : */
1218 : 0 : static int32_t cdns_i2c_master_handle_transfer_error(struct cdns_i2c_data *i2c_bus)
1219 : : {
1220 : : int32_t ret;
1221 : :
1222 : : /* Perform a reset of the I2C master to clear the error condition */
1223 : 0 : cdns_i2c_master_reset(i2c_bus);
1224 : :
1225 [ # # ]: 0 : if ((i2c_bus->err_status & CDNS_I2C_IXR_NACK) != 0U) {
1226 : 0 : ret = -ENXIO; /* No device found (NACK) */
1227 : : } else {
1228 : 0 : ret = -EIO; /* General I/O error */
1229 : : }
1230 : :
1231 : 0 : return ret;
1232 : : }
1233 : :
1234 : : /**
1235 : : * cdns_i2c_master_transfer - Performs an I2C master transfer using the Cadence I2C controller.
1236 : : * @dev: Pointer to the device structure representing the I2C controller.
1237 : : * @msgs: Array of I2C message structures representing the messages to be sent/received.
1238 : : * @num_msgs: Number of messages in the msgs array.
1239 : : * @addr: The 7-bit or 10-bit I2C address of the slave device.
1240 : : *
1241 : : * Return: 0 on success, negative error code on failure.
1242 : : */
1243 : 4 : static int32_t cdns_i2c_master_transfer(const struct device *dev, struct i2c_msg *msgs,
1244 : : uint8_t num_msgs, uint16_t addr)
1245 : : {
1246 : 4 : struct cdns_i2c_data *i2c_bus = (struct cdns_i2c_data *)dev->data;
1247 : 4 : int32_t ret = 0;
1248 : : uint32_t count;
1249 : 4 : struct i2c_msg *msg_ptr = msgs;
1250 : :
1251 : : #if defined(CONFIG_I2C_TARGET)
1252 : : bool change_role = false;
1253 : : #endif
1254 : :
1255 : 4 : (void)k_mutex_lock(&i2c_bus->bus_mutex, K_FOREVER);
1256 : :
1257 : : #if defined(CONFIG_I2C_TARGET)
1258 : : /* Switch to master mode if operating in slave mode */
1259 : : if (i2c_bus->dev_mode == CDNS_I2C_MODE_SLAVE) {
1260 : : if (i2c_bus->slave_state != CDNS_I2C_SLAVE_STATE_IDLE) {
1261 : : ret = -EAGAIN;
1262 : : goto out;
1263 : : }
1264 : :
1265 : : /* Switch mode to master and set flag to switch back to slave after transfer */
1266 : : cdns_i2c_set_mode(CDNS_I2C_MODE_MASTER, i2c_bus);
1267 : : change_role = true;
1268 : : }
1269 : : #endif
1270 : :
1271 : : /* Wait for the bus to be free */
1272 [ - + ]: 4 : if (cdns_i2c_wait_for_bus_free(i2c_bus, CDNS_I2C_TIMEOUT_US) == false) {
1273 : 0 : ret = -EAGAIN;
1274 : 0 : goto out;
1275 : : }
1276 : :
1277 : : /* Handle repeated start for multiple messages */
1278 [ + + ]: 4 : if (num_msgs > 1U) {
1279 : 2 : ret = cdns_i2c_master_handle_repeated_start(i2c_bus, msgs, num_msgs);
1280 [ - + ]: 2 : if (ret != 0) {
1281 : 0 : goto out;
1282 : : }
1283 : : }
1284 : :
1285 : : /* Process each message individually */
1286 [ + + ]: 10 : for (count = 0; count < num_msgs; count++) {
1287 : : /* Reset hold flag for the last message */
1288 [ + + ]: 6 : if (count == ((uint32_t)num_msgs - 1U)) {
1289 : 4 : i2c_bus->bus_hold_flag = 0;
1290 : : }
1291 : :
1292 : : /* Process the current message */
1293 : 6 : ret = cdns_i2c_process_msg(i2c_bus, msg_ptr, addr);
1294 [ - + ]: 6 : if (ret != 0) {
1295 : 0 : goto out;
1296 : : }
1297 : :
1298 : : /* Handle any errors during the transfer */
1299 [ - + ]: 6 : if ((i2c_bus->err_status) != 0U) {
1300 : 0 : ret = cdns_i2c_master_handle_transfer_error(i2c_bus);
1301 [ # # ]: 0 : if (ret != 0) {
1302 : 0 : goto out;
1303 : : }
1304 : : }
1305 : :
1306 : 6 : msg_ptr++;
1307 : : }
1308 : :
1309 : 4 : out:
1310 : : #if defined(CONFIG_I2C_TARGET)
1311 : : /* Switch back to slave mode if the role was changed */
1312 : : if (change_role) {
1313 : : cdns_i2c_set_mode(CDNS_I2C_MODE_SLAVE, i2c_bus);
1314 : : }
1315 : : #endif
1316 : 4 : (void)k_mutex_unlock(&i2c_bus->bus_mutex);
1317 : :
1318 : 4 : return ret;
1319 : : }
1320 : :
1321 : : #if defined(CONFIG_I2C_TARGET)
1322 : : /**
1323 : : * cdns_i2c_target_register - Registers the device as an I2C target (slave).
1324 : : * @dev: Pointer to the device structure representing the I2C bus.
1325 : : * @slave_cfg: Configuration settings for the I2C target (slave).
1326 : : *
1327 : : * Return: 0 on success, or a negative error code.
1328 : : */
1329 : : static int32_t cdns_i2c_target_register(const struct device *dev,
1330 : : struct i2c_target_config *slave_cfg)
1331 : : {
1332 : : struct cdns_i2c_data *i2c_bus = (struct cdns_i2c_data *)dev->data;
1333 : :
1334 : : /* Return busy error if a slave is already configured */
1335 : : if (i2c_bus->slave != NULL) {
1336 : : return -EBUSY;
1337 : : }
1338 : :
1339 : : /* Check for unsupported 10-bit address mode */
1340 : : if ((slave_cfg->flags & I2C_TARGET_FLAGS_ADDR_10_BITS) == I2C_TARGET_FLAGS_ADDR_10_BITS) {
1341 : : return -EAFNOSUPPORT;
1342 : : }
1343 : :
1344 : : (void)k_mutex_lock(&i2c_bus->bus_mutex, K_FOREVER);
1345 : :
1346 : : /* Store the slave configuration */
1347 : : i2c_bus->slave = slave_cfg;
1348 : :
1349 : : /* Enable I2C slave mode */
1350 : : cdns_i2c_set_mode(CDNS_I2C_MODE_SLAVE, i2c_bus);
1351 : :
1352 : : (void)k_mutex_unlock(&i2c_bus->bus_mutex);
1353 : :
1354 : : return 0;
1355 : : }
1356 : :
1357 : : /**
1358 : : * cdns_i2c_target_unregister - Unregisters the device as an I2C target (slave).
1359 : : * @dev: Pointer to the device structure representing the I2C bus.
1360 : : * @cfg: Pointer to the I2C target configuration, which is ignored in this function.
1361 : : *
1362 : : * Return: 0 on success.
1363 : : */
1364 : : static int32_t cdns_i2c_target_unregister(const struct device *dev, struct i2c_target_config *cfg)
1365 : : {
1366 : : struct cdns_i2c_data *i2c_bus = (struct cdns_i2c_data *)dev->data;
1367 : : (void)cfg;
1368 : :
1369 : : (void)k_mutex_lock(&i2c_bus->bus_mutex, K_FOREVER);
1370 : :
1371 : : /* Clear slave information */
1372 : : i2c_bus->slave = NULL;
1373 : :
1374 : : /* Switch to I2C master mode */
1375 : : cdns_i2c_set_mode(CDNS_I2C_MODE_MASTER, i2c_bus);
1376 : :
1377 : : (void)k_mutex_unlock(&i2c_bus->bus_mutex);
1378 : :
1379 : : return 0;
1380 : : }
1381 : : #endif
1382 : :
1383 : : /**
1384 : : * cdns_i2c_init - Initialize the Cadence I2C controller
1385 : : * @dev: Pointer to the device
1386 : : *
1387 : : * Return: 0 on success, negative error code on failure.
1388 : : */
1389 : 1 : static int32_t cdns_i2c_init(const struct device *dev)
1390 : : {
1391 : 1 : const struct cdns_i2c_config *config = (const struct cdns_i2c_config *)dev->config;
1392 : 1 : struct cdns_i2c_data *i2c_bus = (struct cdns_i2c_data *)dev->data;
1393 : : int32_t ret;
1394 : :
1395 : 1 : (void)k_mutex_init(&i2c_bus->bus_mutex);
1396 : 1 : k_event_init(&i2c_bus->xfer_done);
1397 : :
1398 : : #if defined(CONFIG_I2C_TARGET)
1399 : : /* Set initial mode to master and confligure slave states */
1400 : : i2c_bus->dev_mode = CDNS_I2C_MODE_MASTER;
1401 : : i2c_bus->slave_state = CDNS_I2C_SLAVE_STATE_IDLE;
1402 : : i2c_bus->slave = NULL;
1403 : : i2c_bus->ctrl_reg_diva_divb = 0;
1404 : : #endif
1405 : :
1406 : : /* Configure the control reg flags, transfer size */
1407 : 1 : i2c_bus->ctrl_reg = CDNS_I2C_CR_ACK_EN | CDNS_I2C_CR_NEA | CDNS_I2C_CR_MS;
1408 : 1 : i2c_bus->transfer_size = CDNS_I2C_TRANSFER_SIZE_DEFAULT;
1409 : :
1410 : : /* Set the I2C clock frequency */
1411 : 1 : ret = cdns_i2c_setclk(i2c_bus, i2c_bus->input_clk);
1412 [ - + ]: 1 : if (ret != 0) {
1413 [ # # ]: 0 : LOG_ERR("Invalid SCL clock: %u Hz", i2c_bus->i2c_clk);
1414 : 0 : ret = -EINVAL;
1415 : 0 : goto out;
1416 : : }
1417 : 1 : i2c_bus->i2c_config = I2C_MODE_CONTROLLER | i2c_bus->i2c_clk;
1418 : :
1419 : : /* Configure IRQ */
1420 : 1 : config->irq_config_func(dev);
1421 : :
1422 : : /* Enable the I2C peripheral */
1423 : 1 : cdns_i2c_enable_peripheral(i2c_bus);
1424 : :
1425 [ - + ]: 1 : LOG_INF("%u KHz mmio %08lx", i2c_bus->i2c_clk/1000U, i2c_bus->membase);
1426 : :
1427 : 1 : out:
1428 : 1 : return ret;
1429 : : }
1430 : :
1431 : : /* I2C driver API structure for the Cadence I2C controller */
1432 : : static const struct i2c_driver_api cdns_i2c_driver_api = {
1433 : : .configure = cdns_i2c_configure,
1434 : : .get_config = cdns_i2c_get_config,
1435 : : .transfer = cdns_i2c_master_transfer,
1436 : : #if defined(CONFIG_I2C_TARGET)
1437 : : .target_register = cdns_i2c_target_register,
1438 : : .target_unregister = cdns_i2c_target_unregister,
1439 : : #endif
1440 : : };
1441 : :
1442 : : /* CDNS_I2C_BROKEN_HOLD_COMPAT - Handles bus holding quirk based on the device's compatibility */
1443 : : #define CDNS_I2C_BROKEN_HOLD_COMPAT(n) \
1444 : : COND_CODE_1(DT_INST_NODE_HAS_COMPAT(n, cdns_i2c_r1p10), (CDNS_I2C_BROKEN_HOLD_BIT), (0U))
1445 : :
1446 : : #define CADENCE_I2C_INIT(n, compat) \
1447 : : static void cdns_i2c_config_func_##compat##_##n(const struct device *dev); \
1448 : : \
1449 : : static const struct cdns_i2c_config cdns_i2c_config_##compat##_##n = { \
1450 : : .irq_config_func = cdns_i2c_config_func_##compat##_##n, \
1451 : : }; \
1452 : : \
1453 : : static struct cdns_i2c_data cdns_i2c_data_##compat##_##n = { \
1454 : : .membase = DT_INST_REG_ADDR(n), \
1455 : : .input_clk = DT_INST_PROP_BY_PHANDLE(n, clocks, clock_frequency), \
1456 : : .i2c_clk = DT_INST_PROP_OR(n, clock_frequency, CDNS_I2C_SPEED_STANDARD_HZ), \
1457 : : .fifo_depth = DT_INST_PROP_OR(n, fifo_depth, CDNS_I2C_FIFO_DEPTH_DEFAULT), \
1458 : : .broken_hold_flag = CDNS_I2C_BROKEN_HOLD_COMPAT(n), \
1459 : : }; \
1460 : : \
1461 : : I2C_DEVICE_DT_INST_DEFINE(n, cdns_i2c_init, NULL, \
1462 : : &cdns_i2c_data_##compat##_##n, \
1463 : : &cdns_i2c_config_##compat##_##n, POST_KERNEL, \
1464 : : CONFIG_I2C_INIT_PRIORITY, &cdns_i2c_driver_api); \
1465 : : \
1466 : : static void cdns_i2c_config_func_##compat##_##n(const struct device *dev) \
1467 : : { \
1468 : : ARG_UNUSED(dev); \
1469 : : \
1470 : : IRQ_CONNECT(DT_INST_IRQN(n), DT_INST_IRQ(n, priority), cdns_i2c_isr, \
1471 : : DEVICE_DT_INST_GET(n), 0); \
1472 : : \
1473 : : irq_enable(DT_INST_IRQN(n)); \
1474 : : }
1475 : :
1476 : : #define DT_DRV_COMPAT cdns_i2c_r1p10
1477 : : DT_INST_FOREACH_STATUS_OKAY_VARGS(CADENCE_I2C_INIT, DT_DRV_COMPAT)
1478 : :
1479 : : #undef DT_DRV_COMPAT
1480 : : #define DT_DRV_COMPAT cdns_i2c_r1p14
1481 : 1 : DT_INST_FOREACH_STATUS_OKAY_VARGS(CADENCE_I2C_INIT, DT_DRV_COMPAT)
|