xref: /rk3399_ARM-atf/drivers/st/i2c/stm32_i2c.c (revision 586701cece33cc576a10f6c94ad5417b8f2d4e7b)
1435832abSYann Gautier /*
2*586701ceSYann Gautier  * Copyright (c) 2016-2024, STMicroelectronics - All Rights Reserved
3435832abSYann Gautier  *
4435832abSYann Gautier  * SPDX-License-Identifier: BSD-3-Clause
5435832abSYann Gautier  */
6435832abSYann Gautier 
7435832abSYann Gautier #include <errno.h>
8435832abSYann Gautier #include <stdbool.h>
9435832abSYann Gautier #include <stdlib.h>
10435832abSYann Gautier 
11d82d4ff0SYann Gautier #include <common/debug.h>
12*586701ceSYann Gautier #include <common/fdt_wrappers.h>
1333667d29SYann Gautier #include <drivers/clk.h>
14435832abSYann Gautier #include <drivers/delay_timer.h>
15d82d4ff0SYann Gautier #include <drivers/st/stm32_gpio.h>
16435832abSYann Gautier #include <drivers/st/stm32_i2c.h>
17435832abSYann Gautier #include <lib/mmio.h>
18d82d4ff0SYann Gautier #include <lib/utils.h>
19*586701ceSYann Gautier #include <libfdt.h>
20*586701ceSYann Gautier 
21*586701ceSYann Gautier #include <platform_def.h>
22435832abSYann Gautier 
23435832abSYann Gautier /* STM32 I2C registers offsets */
24435832abSYann Gautier #define I2C_CR1			0x00U
25435832abSYann Gautier #define I2C_CR2			0x04U
26435832abSYann Gautier #define I2C_OAR1		0x08U
27435832abSYann Gautier #define I2C_OAR2		0x0CU
28435832abSYann Gautier #define I2C_TIMINGR		0x10U
29435832abSYann Gautier #define I2C_TIMEOUTR		0x14U
30435832abSYann Gautier #define I2C_ISR			0x18U
31435832abSYann Gautier #define I2C_ICR			0x1CU
32435832abSYann Gautier #define I2C_PECR		0x20U
33435832abSYann Gautier #define I2C_RXDR		0x24U
34435832abSYann Gautier #define I2C_TXDR		0x28U
35435832abSYann Gautier 
36d82d4ff0SYann Gautier #define TIMINGR_CLEAR_MASK	0xF0FFFFFFU
37435832abSYann Gautier 
38435832abSYann Gautier #define MAX_NBYTE_SIZE		255U
39435832abSYann Gautier 
40d82d4ff0SYann Gautier #define I2C_NSEC_PER_SEC	1000000000L
41435832abSYann Gautier 
42d82d4ff0SYann Gautier /* I2C Timing hard-coded value, for I2C clock source is HSI at 64MHz */
43d82d4ff0SYann Gautier #define I2C_TIMING			0x10D07DB5
44435832abSYann Gautier 
45d82d4ff0SYann Gautier static void notif_i2c_timeout(struct i2c_handle_s *hi2c)
46d82d4ff0SYann Gautier {
47d82d4ff0SYann Gautier 	hi2c->i2c_err |= I2C_ERROR_TIMEOUT;
48d82d4ff0SYann Gautier 	hi2c->i2c_mode = I2C_MODE_NONE;
49d82d4ff0SYann Gautier 	hi2c->i2c_state = I2C_STATE_READY;
50d82d4ff0SYann Gautier }
51435832abSYann Gautier 
52d82d4ff0SYann Gautier /*
53d82d4ff0SYann Gautier  * @brief  Configure I2C Analog noise filter.
54d82d4ff0SYann Gautier  * @param  hi2c: Pointer to a struct i2c_handle_s structure that contains
55d82d4ff0SYann Gautier  *               the configuration information for the specified I2C peripheral.
56d82d4ff0SYann Gautier  * @param  analog_filter: New state of the Analog filter
57d82d4ff0SYann Gautier  * @retval 0 if OK, negative value else
58d82d4ff0SYann Gautier  */
59d82d4ff0SYann Gautier static int i2c_config_analog_filter(struct i2c_handle_s *hi2c,
60d82d4ff0SYann Gautier 				    uint32_t analog_filter)
61d82d4ff0SYann Gautier {
62d82d4ff0SYann Gautier 	if ((hi2c->i2c_state != I2C_STATE_READY) || (hi2c->lock != 0U)) {
63d82d4ff0SYann Gautier 		return -EBUSY;
64d82d4ff0SYann Gautier 	}
65d82d4ff0SYann Gautier 
66d82d4ff0SYann Gautier 	hi2c->lock = 1;
67d82d4ff0SYann Gautier 
68d82d4ff0SYann Gautier 	hi2c->i2c_state = I2C_STATE_BUSY;
69d82d4ff0SYann Gautier 
70d82d4ff0SYann Gautier 	/* Disable the selected I2C peripheral */
71d82d4ff0SYann Gautier 	mmio_clrbits_32(hi2c->i2c_base_addr + I2C_CR1, I2C_CR1_PE);
72d82d4ff0SYann Gautier 
73d82d4ff0SYann Gautier 	/* Reset I2Cx ANOFF bit */
74d82d4ff0SYann Gautier 	mmio_clrbits_32(hi2c->i2c_base_addr + I2C_CR1, I2C_CR1_ANFOFF);
75d82d4ff0SYann Gautier 
76d82d4ff0SYann Gautier 	/* Set analog filter bit*/
77d82d4ff0SYann Gautier 	mmio_setbits_32(hi2c->i2c_base_addr + I2C_CR1, analog_filter);
78d82d4ff0SYann Gautier 
79d82d4ff0SYann Gautier 	/* Enable the selected I2C peripheral */
80d82d4ff0SYann Gautier 	mmio_setbits_32(hi2c->i2c_base_addr + I2C_CR1, I2C_CR1_PE);
81d82d4ff0SYann Gautier 
82d82d4ff0SYann Gautier 	hi2c->i2c_state = I2C_STATE_READY;
83d82d4ff0SYann Gautier 
84d82d4ff0SYann Gautier 	hi2c->lock = 0;
85d82d4ff0SYann Gautier 
86d82d4ff0SYann Gautier 	return 0;
87d82d4ff0SYann Gautier }
88d82d4ff0SYann Gautier 
89d82d4ff0SYann Gautier /*
90d82d4ff0SYann Gautier  * @brief  Get I2C setup information from the device tree and set pinctrl
91d82d4ff0SYann Gautier  *         configuration.
92d82d4ff0SYann Gautier  * @param  fdt: Pointer to the device tree
93d82d4ff0SYann Gautier  * @param  node: I2C node offset
94d82d4ff0SYann Gautier  * @param  init: Ref to the initialization configuration structure
95d82d4ff0SYann Gautier  * @retval 0 if OK, negative value else
96d82d4ff0SYann Gautier  */
97d82d4ff0SYann Gautier int stm32_i2c_get_setup_from_fdt(void *fdt, int node,
98d82d4ff0SYann Gautier 				 struct stm32_i2c_init_s *init)
99d82d4ff0SYann Gautier {
100*586701ceSYann Gautier 	uint32_t read_val;
101d82d4ff0SYann Gautier 
102*586701ceSYann Gautier 	init->rise_time = fdt_read_uint32_default(fdt, node,
103*586701ceSYann Gautier 						  "i2c-scl-rising-time-ns",
104*586701ceSYann Gautier 						  STM32_I2C_RISE_TIME_DEFAULT);
105d82d4ff0SYann Gautier 
106*586701ceSYann Gautier 	init->fall_time = fdt_read_uint32_default(fdt, node,
107*586701ceSYann Gautier 						  "i2c-scl-falling-time-ns",
108*586701ceSYann Gautier 						  STM32_I2C_FALL_TIME_DEFAULT);
109d82d4ff0SYann Gautier 
110*586701ceSYann Gautier 	read_val = fdt_read_uint32_default(fdt, node, "clock-frequency",
111*586701ceSYann Gautier 					   STANDARD_RATE);
112*586701ceSYann Gautier 	switch (read_val) {
113*586701ceSYann Gautier 	case FAST_PLUS_RATE:
114*586701ceSYann Gautier 		init->speed_mode = I2C_SPEED_FAST_PLUS;
115d82d4ff0SYann Gautier 		break;
116d82d4ff0SYann Gautier 	case FAST_RATE:
117d82d4ff0SYann Gautier 		init->speed_mode = I2C_SPEED_FAST;
118d82d4ff0SYann Gautier 		break;
119*586701ceSYann Gautier 	case STANDARD_RATE:
120d82d4ff0SYann Gautier 	default:
121*586701ceSYann Gautier 		init->speed_mode = I2C_SPEED_STANDARD;
122d82d4ff0SYann Gautier 		break;
123d82d4ff0SYann Gautier 	}
124d82d4ff0SYann Gautier 
125d82d4ff0SYann Gautier 	return dt_set_pinctrl_config(node);
126d82d4ff0SYann Gautier }
127435832abSYann Gautier 
128435832abSYann Gautier /*
129435832abSYann Gautier  * @brief  Initialize the I2C device.
130435832abSYann Gautier  * @param  hi2c: Pointer to a struct i2c_handle_s structure that contains
131435832abSYann Gautier  *               the configuration information for the specified I2C.
132d82d4ff0SYann Gautier  * @param  init_data: Initialization configuration structure
133435832abSYann Gautier  * @retval 0 if OK, negative value else
134435832abSYann Gautier  */
135d82d4ff0SYann Gautier int stm32_i2c_init(struct i2c_handle_s *hi2c,
136d82d4ff0SYann Gautier 		   struct stm32_i2c_init_s *init_data)
137435832abSYann Gautier {
138d82d4ff0SYann Gautier 	int rc = 0;
139d82d4ff0SYann Gautier 	uint32_t timing = I2C_TIMING;
140d82d4ff0SYann Gautier 
141435832abSYann Gautier 	if (hi2c == NULL) {
142435832abSYann Gautier 		return -ENOENT;
143435832abSYann Gautier 	}
144435832abSYann Gautier 
145435832abSYann Gautier 	if (hi2c->i2c_state == I2C_STATE_RESET) {
146435832abSYann Gautier 		hi2c->lock = 0;
147435832abSYann Gautier 	}
148435832abSYann Gautier 
149435832abSYann Gautier 	hi2c->i2c_state = I2C_STATE_BUSY;
150435832abSYann Gautier 
15133667d29SYann Gautier 	clk_enable(hi2c->clock);
152d82d4ff0SYann Gautier 
153435832abSYann Gautier 	/* Disable the selected I2C peripheral */
154435832abSYann Gautier 	mmio_clrbits_32(hi2c->i2c_base_addr + I2C_CR1, I2C_CR1_PE);
155435832abSYann Gautier 
156435832abSYann Gautier 	/* Configure I2Cx: Frequency range */
157435832abSYann Gautier 	mmio_write_32(hi2c->i2c_base_addr + I2C_TIMINGR,
158d82d4ff0SYann Gautier 		      timing & TIMINGR_CLEAR_MASK);
159435832abSYann Gautier 
160435832abSYann Gautier 	/* Disable Own Address1 before set the Own Address1 configuration */
161435832abSYann Gautier 	mmio_clrbits_32(hi2c->i2c_base_addr + I2C_OAR1, I2C_OAR1_OA1EN);
162435832abSYann Gautier 
163435832abSYann Gautier 	/* Configure I2Cx: Own Address1 and ack own address1 mode */
164d82d4ff0SYann Gautier 	if (init_data->addressing_mode == I2C_ADDRESSINGMODE_7BIT) {
165435832abSYann Gautier 		mmio_write_32(hi2c->i2c_base_addr + I2C_OAR1,
166d82d4ff0SYann Gautier 			      I2C_OAR1_OA1EN | init_data->own_address1);
167435832abSYann Gautier 	} else { /* I2C_ADDRESSINGMODE_10BIT */
168435832abSYann Gautier 		mmio_write_32(hi2c->i2c_base_addr + I2C_OAR1,
169435832abSYann Gautier 			      I2C_OAR1_OA1EN | I2C_OAR1_OA1MODE |
170d82d4ff0SYann Gautier 			      init_data->own_address1);
171435832abSYann Gautier 	}
172435832abSYann Gautier 
173d82d4ff0SYann Gautier 	mmio_write_32(hi2c->i2c_base_addr + I2C_CR2, 0);
174d82d4ff0SYann Gautier 
175435832abSYann Gautier 	/* Configure I2Cx: Addressing Master mode */
176d82d4ff0SYann Gautier 	if (init_data->addressing_mode == I2C_ADDRESSINGMODE_10BIT) {
177d82d4ff0SYann Gautier 		mmio_setbits_32(hi2c->i2c_base_addr + I2C_CR2, I2C_CR2_ADD10);
178435832abSYann Gautier 	}
179435832abSYann Gautier 
180435832abSYann Gautier 	/*
181435832abSYann Gautier 	 * Enable the AUTOEND by default, and enable NACK
182d82d4ff0SYann Gautier 	 * (should be disabled only during Slave process).
183435832abSYann Gautier 	 */
184435832abSYann Gautier 	mmio_setbits_32(hi2c->i2c_base_addr + I2C_CR2,
185435832abSYann Gautier 			I2C_CR2_AUTOEND | I2C_CR2_NACK);
186435832abSYann Gautier 
187435832abSYann Gautier 	/* Disable Own Address2 before set the Own Address2 configuration */
188435832abSYann Gautier 	mmio_clrbits_32(hi2c->i2c_base_addr + I2C_OAR2, I2C_DUALADDRESS_ENABLE);
189435832abSYann Gautier 
190435832abSYann Gautier 	/* Configure I2Cx: Dual mode and Own Address2 */
191435832abSYann Gautier 	mmio_write_32(hi2c->i2c_base_addr + I2C_OAR2,
192d82d4ff0SYann Gautier 		      init_data->dual_address_mode |
193d82d4ff0SYann Gautier 		      init_data->own_address2 |
194d82d4ff0SYann Gautier 		      (init_data->own_address2_masks << 8));
195435832abSYann Gautier 
196435832abSYann Gautier 	/* Configure I2Cx: Generalcall and NoStretch mode */
197435832abSYann Gautier 	mmio_write_32(hi2c->i2c_base_addr + I2C_CR1,
198d82d4ff0SYann Gautier 		      init_data->general_call_mode |
199d82d4ff0SYann Gautier 		      init_data->no_stretch_mode);
200435832abSYann Gautier 
201435832abSYann Gautier 	/* Enable the selected I2C peripheral */
202435832abSYann Gautier 	mmio_setbits_32(hi2c->i2c_base_addr + I2C_CR1, I2C_CR1_PE);
203435832abSYann Gautier 
204435832abSYann Gautier 	hi2c->i2c_err = I2C_ERROR_NONE;
205435832abSYann Gautier 	hi2c->i2c_state = I2C_STATE_READY;
206435832abSYann Gautier 	hi2c->i2c_mode = I2C_MODE_NONE;
207435832abSYann Gautier 
208d82d4ff0SYann Gautier 	rc = i2c_config_analog_filter(hi2c, init_data->analog_filter ?
209d82d4ff0SYann Gautier 						I2C_ANALOGFILTER_ENABLE :
210d82d4ff0SYann Gautier 						I2C_ANALOGFILTER_DISABLE);
211d82d4ff0SYann Gautier 	if (rc != 0) {
212d82d4ff0SYann Gautier 		ERROR("Cannot initialize I2C analog filter (%d)\n", rc);
21333667d29SYann Gautier 		clk_disable(hi2c->clock);
214d82d4ff0SYann Gautier 		return rc;
215435832abSYann Gautier 	}
216435832abSYann Gautier 
21733667d29SYann Gautier 	clk_disable(hi2c->clock);
218435832abSYann Gautier 
219d82d4ff0SYann Gautier 	return rc;
220435832abSYann Gautier }
221435832abSYann Gautier 
222435832abSYann Gautier /*
223435832abSYann Gautier  * @brief  I2C Tx data register flush process.
224d82d4ff0SYann Gautier  * @param  hi2c: I2C handle
225435832abSYann Gautier  * @retval None
226435832abSYann Gautier  */
227435832abSYann Gautier static void i2c_flush_txdr(struct i2c_handle_s *hi2c)
228435832abSYann Gautier {
229435832abSYann Gautier 	/*
230435832abSYann Gautier 	 * If a pending TXIS flag is set,
231435832abSYann Gautier 	 * write a dummy data in TXDR to clear it.
232435832abSYann Gautier 	 */
233435832abSYann Gautier 	if ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) & I2C_FLAG_TXIS) !=
234435832abSYann Gautier 	    0U) {
235435832abSYann Gautier 		mmio_write_32(hi2c->i2c_base_addr + I2C_TXDR, 0);
236435832abSYann Gautier 	}
237435832abSYann Gautier 
238435832abSYann Gautier 	/* Flush TX register if not empty */
239435832abSYann Gautier 	if ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) & I2C_FLAG_TXE) ==
240435832abSYann Gautier 	    0U) {
241435832abSYann Gautier 		mmio_setbits_32(hi2c->i2c_base_addr + I2C_ISR,
242435832abSYann Gautier 				I2C_FLAG_TXE);
243435832abSYann Gautier 	}
244435832abSYann Gautier }
245435832abSYann Gautier 
246435832abSYann Gautier /*
247435832abSYann Gautier  * @brief  This function handles I2C Communication timeout.
248435832abSYann Gautier  * @param  hi2c: Pointer to a struct i2c_handle_s structure that contains
249435832abSYann Gautier  *               the configuration information for the specified I2C.
250d82d4ff0SYann Gautier  * @param  flag: Specifies the I2C flag to check
251d82d4ff0SYann Gautier  * @param  awaited_value: The awaited bit value for the flag (0 or 1)
252d82d4ff0SYann Gautier  * @param  timeout_ref: Reference to target timeout
253435832abSYann Gautier  * @retval 0 if OK, negative value else
254435832abSYann Gautier  */
255435832abSYann Gautier static int i2c_wait_flag(struct i2c_handle_s *hi2c, uint32_t flag,
256d82d4ff0SYann Gautier 			 uint8_t awaited_value, uint64_t timeout_ref)
257435832abSYann Gautier {
258d82d4ff0SYann Gautier 	for ( ; ; ) {
259d82d4ff0SYann Gautier 		uint32_t isr = mmio_read_32(hi2c->i2c_base_addr + I2C_ISR);
260435832abSYann Gautier 
261d82d4ff0SYann Gautier 		if (!!(isr & flag) != !!awaited_value) {
262435832abSYann Gautier 			return 0;
263435832abSYann Gautier 		}
264435832abSYann Gautier 
265d82d4ff0SYann Gautier 		if (timeout_elapsed(timeout_ref)) {
266d82d4ff0SYann Gautier 			notif_i2c_timeout(hi2c);
267435832abSYann Gautier 			hi2c->lock = 0;
268435832abSYann Gautier 
269435832abSYann Gautier 			return -EIO;
270435832abSYann Gautier 		}
271435832abSYann Gautier 	}
272435832abSYann Gautier }
273435832abSYann Gautier 
274435832abSYann Gautier /*
275435832abSYann Gautier  * @brief  This function handles Acknowledge failed detection during
276435832abSYann Gautier  *	   an I2C Communication.
277435832abSYann Gautier  * @param  hi2c: Pointer to a struct i2c_handle_s structure that contains
278435832abSYann Gautier  *               the configuration information for the specified I2C.
279d82d4ff0SYann Gautier  * @param  timeout_ref: Reference to target timeout
280435832abSYann Gautier  * @retval 0 if OK, negative value else
281435832abSYann Gautier  */
282d82d4ff0SYann Gautier static int i2c_ack_failed(struct i2c_handle_s *hi2c, uint64_t timeout_ref)
283435832abSYann Gautier {
284435832abSYann Gautier 	if ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) & I2C_FLAG_AF) == 0U) {
285435832abSYann Gautier 		return 0;
286435832abSYann Gautier 	}
287435832abSYann Gautier 
288435832abSYann Gautier 	/*
289435832abSYann Gautier 	 * Wait until STOP Flag is reset.
290435832abSYann Gautier 	 * AutoEnd should be initiate after AF.
291435832abSYann Gautier 	 */
292435832abSYann Gautier 	while ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) &
293435832abSYann Gautier 		I2C_FLAG_STOPF) == 0U) {
294d82d4ff0SYann Gautier 		if (timeout_elapsed(timeout_ref)) {
295d82d4ff0SYann Gautier 			notif_i2c_timeout(hi2c);
296435832abSYann Gautier 			hi2c->lock = 0;
297435832abSYann Gautier 
298435832abSYann Gautier 			return -EIO;
299435832abSYann Gautier 		}
300435832abSYann Gautier 	}
301435832abSYann Gautier 
302435832abSYann Gautier 	mmio_write_32(hi2c->i2c_base_addr + I2C_ICR, I2C_FLAG_AF);
303435832abSYann Gautier 
304435832abSYann Gautier 	mmio_write_32(hi2c->i2c_base_addr + I2C_ICR, I2C_FLAG_STOPF);
305435832abSYann Gautier 
306435832abSYann Gautier 	i2c_flush_txdr(hi2c);
307435832abSYann Gautier 
308435832abSYann Gautier 	mmio_clrbits_32(hi2c->i2c_base_addr + I2C_CR2, I2C_RESET_CR2);
309435832abSYann Gautier 
310435832abSYann Gautier 	hi2c->i2c_err |= I2C_ERROR_AF;
311435832abSYann Gautier 	hi2c->i2c_state = I2C_STATE_READY;
312435832abSYann Gautier 	hi2c->i2c_mode = I2C_MODE_NONE;
313435832abSYann Gautier 
314435832abSYann Gautier 	hi2c->lock = 0;
315435832abSYann Gautier 
316435832abSYann Gautier 	return -EIO;
317435832abSYann Gautier }
318435832abSYann Gautier 
319435832abSYann Gautier /*
320d82d4ff0SYann Gautier  * @brief  This function handles I2C Communication timeout for specific usage
321d82d4ff0SYann Gautier  *	   of TXIS flag.
322d82d4ff0SYann Gautier  * @param  hi2c: Pointer to a struct i2c_handle_s structure that contains
323d82d4ff0SYann Gautier  *               the configuration information for the specified I2C.
324d82d4ff0SYann Gautier  * @param  timeout_ref: Reference to target timeout
325d82d4ff0SYann Gautier  * @retval 0 if OK, negative value else
326d82d4ff0SYann Gautier  */
327d82d4ff0SYann Gautier static int i2c_wait_txis(struct i2c_handle_s *hi2c, uint64_t timeout_ref)
328d82d4ff0SYann Gautier {
329d82d4ff0SYann Gautier 	while ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) &
330d82d4ff0SYann Gautier 		I2C_FLAG_TXIS) == 0U) {
331d82d4ff0SYann Gautier 		if (i2c_ack_failed(hi2c, timeout_ref) != 0) {
332d82d4ff0SYann Gautier 			return -EIO;
333d82d4ff0SYann Gautier 		}
334d82d4ff0SYann Gautier 
335d82d4ff0SYann Gautier 		if (timeout_elapsed(timeout_ref)) {
336d82d4ff0SYann Gautier 			notif_i2c_timeout(hi2c);
337d82d4ff0SYann Gautier 			hi2c->lock = 0;
338d82d4ff0SYann Gautier 
339d82d4ff0SYann Gautier 			return -EIO;
340d82d4ff0SYann Gautier 		}
341d82d4ff0SYann Gautier 	}
342d82d4ff0SYann Gautier 
343d82d4ff0SYann Gautier 	return 0;
344d82d4ff0SYann Gautier }
345d82d4ff0SYann Gautier 
346d82d4ff0SYann Gautier /*
347d82d4ff0SYann Gautier  * @brief  This function handles I2C Communication timeout for specific
348d82d4ff0SYann Gautier  *	   usage of STOP flag.
349d82d4ff0SYann Gautier  * @param  hi2c: Pointer to a struct i2c_handle_s structure that contains
350d82d4ff0SYann Gautier  *               the configuration information for the specified I2C.
351d82d4ff0SYann Gautier  * @param  timeout_ref: Reference to target timeout
352d82d4ff0SYann Gautier  * @retval 0 if OK, negative value else
353d82d4ff0SYann Gautier  */
354d82d4ff0SYann Gautier static int i2c_wait_stop(struct i2c_handle_s *hi2c, uint64_t timeout_ref)
355d82d4ff0SYann Gautier {
356d82d4ff0SYann Gautier 	while ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) &
357d82d4ff0SYann Gautier 		 I2C_FLAG_STOPF) == 0U) {
358d82d4ff0SYann Gautier 		if (i2c_ack_failed(hi2c, timeout_ref) != 0) {
359d82d4ff0SYann Gautier 			return -EIO;
360d82d4ff0SYann Gautier 		}
361d82d4ff0SYann Gautier 
362d82d4ff0SYann Gautier 		if (timeout_elapsed(timeout_ref)) {
363d82d4ff0SYann Gautier 			notif_i2c_timeout(hi2c);
364d82d4ff0SYann Gautier 			hi2c->lock = 0;
365d82d4ff0SYann Gautier 
366d82d4ff0SYann Gautier 			return -EIO;
367d82d4ff0SYann Gautier 		}
368d82d4ff0SYann Gautier 	}
369d82d4ff0SYann Gautier 
370d82d4ff0SYann Gautier 	return 0;
371d82d4ff0SYann Gautier }
372d82d4ff0SYann Gautier 
373d82d4ff0SYann Gautier /*
374435832abSYann Gautier  * @brief  Handles I2Cx communication when starting transfer or during transfer
375435832abSYann Gautier  *	   (TC or TCR flag are set).
376d82d4ff0SYann Gautier  * @param  hi2c: I2C handle
377d82d4ff0SYann Gautier  * @param  dev_addr: Specifies the slave address to be programmed
378435832abSYann Gautier  * @param  size: Specifies the number of bytes to be programmed.
379435832abSYann Gautier  *   This parameter must be a value between 0 and 255.
380435832abSYann Gautier  * @param  i2c_mode: New state of the I2C START condition generation.
381435832abSYann Gautier  *   This parameter can be one of the following values:
382435832abSYann Gautier  *     @arg @ref I2C_RELOAD_MODE: Enable Reload mode.
383435832abSYann Gautier  *     @arg @ref I2C_AUTOEND_MODE: Enable Automatic end mode.
384435832abSYann Gautier  *     @arg @ref I2C_SOFTEND_MODE: Enable Software end mode.
385435832abSYann Gautier  * @param  request: New state of the I2C START condition generation.
386435832abSYann Gautier  *   This parameter can be one of the following values:
387435832abSYann Gautier  *     @arg @ref I2C_NO_STARTSTOP: Don't Generate stop and start condition.
388435832abSYann Gautier  *     @arg @ref I2C_GENERATE_STOP: Generate stop condition
389435832abSYann Gautier  *                                  (size should be set to 0).
390435832abSYann Gautier  *     @arg @ref I2C_GENERATE_START_READ: Generate Restart for read request.
391435832abSYann Gautier  *     @arg @ref I2C_GENERATE_START_WRITE: Generate Restart for write request.
392435832abSYann Gautier  * @retval None
393435832abSYann Gautier  */
394435832abSYann Gautier static void i2c_transfer_config(struct i2c_handle_s *hi2c, uint16_t dev_addr,
395435832abSYann Gautier 				uint16_t size, uint32_t i2c_mode,
396435832abSYann Gautier 				uint32_t request)
397435832abSYann Gautier {
398435832abSYann Gautier 	uint32_t clr_value, set_value;
399435832abSYann Gautier 
400435832abSYann Gautier 	clr_value = (I2C_CR2_SADD | I2C_CR2_NBYTES | I2C_CR2_RELOAD |
401435832abSYann Gautier 		     I2C_CR2_AUTOEND | I2C_CR2_START | I2C_CR2_STOP) |
402435832abSYann Gautier 		(I2C_CR2_RD_WRN & (request >> (31U - I2C_CR2_RD_WRN_OFFSET)));
403435832abSYann Gautier 
404435832abSYann Gautier 	set_value = ((uint32_t)dev_addr & I2C_CR2_SADD) |
405435832abSYann Gautier 		(((uint32_t)size << I2C_CR2_NBYTES_OFFSET) & I2C_CR2_NBYTES) |
406435832abSYann Gautier 		i2c_mode | request;
407435832abSYann Gautier 
408435832abSYann Gautier 	mmio_clrsetbits_32(hi2c->i2c_base_addr + I2C_CR2, clr_value, set_value);
409435832abSYann Gautier }
410435832abSYann Gautier 
411435832abSYann Gautier /*
412d82d4ff0SYann Gautier  * @brief  Master sends target device address followed by internal memory
413d82d4ff0SYann Gautier  *	   address for write request.
414435832abSYann Gautier  * @param  hi2c: Pointer to a struct i2c_handle_s structure that contains
415d82d4ff0SYann Gautier  *               the configuration information for the specified I2C.
416d82d4ff0SYann Gautier  * @param  dev_addr: Target device address
417d82d4ff0SYann Gautier  * @param  mem_addr: Internal memory address
418d82d4ff0SYann Gautier  * @param  mem_add_size: Size of internal memory address
419d82d4ff0SYann Gautier  * @param  timeout_ref: Reference to target timeout
420435832abSYann Gautier  * @retval 0 if OK, negative value else
421435832abSYann Gautier  */
422d82d4ff0SYann Gautier static int i2c_request_memory_write(struct i2c_handle_s *hi2c,
423d82d4ff0SYann Gautier 				    uint16_t dev_addr, uint16_t mem_addr,
424d82d4ff0SYann Gautier 				    uint16_t mem_add_size, uint64_t timeout_ref)
425435832abSYann Gautier {
426d82d4ff0SYann Gautier 	i2c_transfer_config(hi2c, dev_addr, mem_add_size, I2C_RELOAD_MODE,
427d82d4ff0SYann Gautier 			    I2C_GENERATE_START_WRITE);
428d82d4ff0SYann Gautier 
429d82d4ff0SYann Gautier 	if (i2c_wait_txis(hi2c, timeout_ref) != 0) {
430d82d4ff0SYann Gautier 		return -EIO;
431d82d4ff0SYann Gautier 	}
432d82d4ff0SYann Gautier 
433d82d4ff0SYann Gautier 	if (mem_add_size == I2C_MEMADD_SIZE_8BIT) {
434d82d4ff0SYann Gautier 		/* Send Memory Address */
435d82d4ff0SYann Gautier 		mmio_write_8(hi2c->i2c_base_addr + I2C_TXDR,
436d82d4ff0SYann Gautier 			     (uint8_t)(mem_addr & 0x00FFU));
437d82d4ff0SYann Gautier 	} else {
438d82d4ff0SYann Gautier 		/* Send MSB of Memory Address */
439d82d4ff0SYann Gautier 		mmio_write_8(hi2c->i2c_base_addr + I2C_TXDR,
440d82d4ff0SYann Gautier 			     (uint8_t)((mem_addr & 0xFF00U) >> 8));
441d82d4ff0SYann Gautier 
442d82d4ff0SYann Gautier 		if (i2c_wait_txis(hi2c, timeout_ref) != 0) {
443d82d4ff0SYann Gautier 			return -EIO;
444d82d4ff0SYann Gautier 		}
445d82d4ff0SYann Gautier 
446d82d4ff0SYann Gautier 		/* Send LSB of Memory Address */
447d82d4ff0SYann Gautier 		mmio_write_8(hi2c->i2c_base_addr + I2C_TXDR,
448d82d4ff0SYann Gautier 			     (uint8_t)(mem_addr & 0x00FFU));
449d82d4ff0SYann Gautier 	}
450d82d4ff0SYann Gautier 
451d82d4ff0SYann Gautier 	if (i2c_wait_flag(hi2c, I2C_FLAG_TCR, 0, timeout_ref) != 0) {
452d82d4ff0SYann Gautier 		return -EIO;
453d82d4ff0SYann Gautier 	}
454d82d4ff0SYann Gautier 
455d82d4ff0SYann Gautier 	return 0;
456d82d4ff0SYann Gautier }
457d82d4ff0SYann Gautier 
458d82d4ff0SYann Gautier /*
459d82d4ff0SYann Gautier  * @brief  Master sends target device address followed by internal memory
460d82d4ff0SYann Gautier  *	   address for read request.
461d82d4ff0SYann Gautier  * @param  hi2c: Pointer to a struct i2c_handle_s structure that contains
462d82d4ff0SYann Gautier  *               the configuration information for the specified I2C.
463d82d4ff0SYann Gautier  * @param  dev_addr: Target device address
464d82d4ff0SYann Gautier  * @param  mem_addr: Internal memory address
465d82d4ff0SYann Gautier  * @param  mem_add_size: Size of internal memory address
466d82d4ff0SYann Gautier  * @param  timeout_ref: Reference to target timeout
467d82d4ff0SYann Gautier  * @retval 0 if OK, negative value else
468d82d4ff0SYann Gautier  */
469d82d4ff0SYann Gautier static int i2c_request_memory_read(struct i2c_handle_s *hi2c, uint16_t dev_addr,
470d82d4ff0SYann Gautier 				   uint16_t mem_addr, uint16_t mem_add_size,
471d82d4ff0SYann Gautier 				   uint64_t timeout_ref)
472d82d4ff0SYann Gautier {
473d82d4ff0SYann Gautier 	i2c_transfer_config(hi2c, dev_addr, mem_add_size, I2C_SOFTEND_MODE,
474d82d4ff0SYann Gautier 			    I2C_GENERATE_START_WRITE);
475d82d4ff0SYann Gautier 
476d82d4ff0SYann Gautier 	if (i2c_wait_txis(hi2c, timeout_ref) != 0) {
477d82d4ff0SYann Gautier 		return -EIO;
478d82d4ff0SYann Gautier 	}
479d82d4ff0SYann Gautier 
480d82d4ff0SYann Gautier 	if (mem_add_size == I2C_MEMADD_SIZE_8BIT) {
481d82d4ff0SYann Gautier 		/* Send Memory Address */
482d82d4ff0SYann Gautier 		mmio_write_8(hi2c->i2c_base_addr + I2C_TXDR,
483d82d4ff0SYann Gautier 			     (uint8_t)(mem_addr & 0x00FFU));
484d82d4ff0SYann Gautier 	} else {
485d82d4ff0SYann Gautier 		/* Send MSB of Memory Address */
486d82d4ff0SYann Gautier 		mmio_write_8(hi2c->i2c_base_addr + I2C_TXDR,
487d82d4ff0SYann Gautier 			     (uint8_t)((mem_addr & 0xFF00U) >> 8));
488d82d4ff0SYann Gautier 
489d82d4ff0SYann Gautier 		if (i2c_wait_txis(hi2c, timeout_ref) != 0) {
490d82d4ff0SYann Gautier 			return -EIO;
491d82d4ff0SYann Gautier 		}
492d82d4ff0SYann Gautier 
493d82d4ff0SYann Gautier 		/* Send LSB of Memory Address */
494d82d4ff0SYann Gautier 		mmio_write_8(hi2c->i2c_base_addr + I2C_TXDR,
495d82d4ff0SYann Gautier 			     (uint8_t)(mem_addr & 0x00FFU));
496d82d4ff0SYann Gautier 	}
497d82d4ff0SYann Gautier 
498d82d4ff0SYann Gautier 	if (i2c_wait_flag(hi2c, I2C_FLAG_TC, 0, timeout_ref) != 0) {
499d82d4ff0SYann Gautier 		return -EIO;
500d82d4ff0SYann Gautier 	}
501d82d4ff0SYann Gautier 
502d82d4ff0SYann Gautier 	return 0;
503d82d4ff0SYann Gautier }
504d82d4ff0SYann Gautier /*
505d82d4ff0SYann Gautier  * @brief  Generic function to write an amount of data in blocking mode
506d82d4ff0SYann Gautier  *         (for Memory Mode and Master Mode)
507d82d4ff0SYann Gautier  * @param  hi2c: Pointer to a struct i2c_handle_s structure that contains
508d82d4ff0SYann Gautier  *               the configuration information for the specified I2C.
509d82d4ff0SYann Gautier  * @param  dev_addr: Target device address
510d82d4ff0SYann Gautier  * @param  mem_addr: Internal memory address (if Memory Mode)
511d82d4ff0SYann Gautier  * @param  mem_add_size: Size of internal memory address (if Memory Mode)
512d82d4ff0SYann Gautier  * @param  p_data: Pointer to data buffer
513d82d4ff0SYann Gautier  * @param  size: Amount of data to be sent
514d82d4ff0SYann Gautier  * @param  timeout_ms: Timeout duration in milliseconds
515d82d4ff0SYann Gautier  * @param  mode: Communication mode
516d82d4ff0SYann Gautier  * @retval 0 if OK, negative value else
517d82d4ff0SYann Gautier  */
518d82d4ff0SYann Gautier static int i2c_write(struct i2c_handle_s *hi2c, uint16_t dev_addr,
519d82d4ff0SYann Gautier 		     uint16_t mem_addr, uint16_t mem_add_size,
520d82d4ff0SYann Gautier 		     uint8_t *p_data, uint16_t size, uint32_t timeout_ms,
521d82d4ff0SYann Gautier 		     enum i2c_mode_e mode)
522d82d4ff0SYann Gautier {
523d82d4ff0SYann Gautier 	uint64_t timeout_ref;
524d82d4ff0SYann Gautier 	int rc = -EIO;
525d82d4ff0SYann Gautier 	uint8_t *p_buff = p_data;
526d82d4ff0SYann Gautier 	uint32_t xfer_size;
527d82d4ff0SYann Gautier 	uint32_t xfer_count = size;
528d82d4ff0SYann Gautier 
529d82d4ff0SYann Gautier 	if ((mode != I2C_MODE_MASTER) && (mode != I2C_MODE_MEM)) {
530d82d4ff0SYann Gautier 		return -1;
531d82d4ff0SYann Gautier 	}
532d82d4ff0SYann Gautier 
533435832abSYann Gautier 	if ((hi2c->i2c_state != I2C_STATE_READY) || (hi2c->lock != 0U)) {
534435832abSYann Gautier 		return -EBUSY;
535435832abSYann Gautier 	}
536435832abSYann Gautier 
537d82d4ff0SYann Gautier 	if ((p_data == NULL) || (size == 0U)) {
538d82d4ff0SYann Gautier 		return -EINVAL;
539d82d4ff0SYann Gautier 	}
540d82d4ff0SYann Gautier 
54133667d29SYann Gautier 	clk_enable(hi2c->clock);
542d82d4ff0SYann Gautier 
543435832abSYann Gautier 	hi2c->lock = 1;
544435832abSYann Gautier 
545d82d4ff0SYann Gautier 	timeout_ref = timeout_init_us(I2C_TIMEOUT_BUSY_MS * 1000);
546d82d4ff0SYann Gautier 	if (i2c_wait_flag(hi2c, I2C_FLAG_BUSY, 1, timeout_ref) != 0) {
547d82d4ff0SYann Gautier 		goto bail;
548d82d4ff0SYann Gautier 	}
549d82d4ff0SYann Gautier 
550d82d4ff0SYann Gautier 	hi2c->i2c_state = I2C_STATE_BUSY_TX;
551d82d4ff0SYann Gautier 	hi2c->i2c_mode = mode;
552d82d4ff0SYann Gautier 	hi2c->i2c_err = I2C_ERROR_NONE;
553d82d4ff0SYann Gautier 
554d82d4ff0SYann Gautier 	timeout_ref = timeout_init_us(timeout_ms * 1000);
555d82d4ff0SYann Gautier 
556d82d4ff0SYann Gautier 	if (mode == I2C_MODE_MEM) {
557d82d4ff0SYann Gautier 		/* In Memory Mode, Send Slave Address and Memory Address */
558d82d4ff0SYann Gautier 		if (i2c_request_memory_write(hi2c, dev_addr, mem_addr,
559d82d4ff0SYann Gautier 					     mem_add_size, timeout_ref) != 0) {
560d82d4ff0SYann Gautier 			goto bail;
561d82d4ff0SYann Gautier 		}
562d82d4ff0SYann Gautier 
563d82d4ff0SYann Gautier 		if (xfer_count > MAX_NBYTE_SIZE) {
564d82d4ff0SYann Gautier 			xfer_size = MAX_NBYTE_SIZE;
565d82d4ff0SYann Gautier 			i2c_transfer_config(hi2c, dev_addr, xfer_size,
566d82d4ff0SYann Gautier 					    I2C_RELOAD_MODE, I2C_NO_STARTSTOP);
567d82d4ff0SYann Gautier 		} else {
568d82d4ff0SYann Gautier 			xfer_size = xfer_count;
569d82d4ff0SYann Gautier 			i2c_transfer_config(hi2c, dev_addr, xfer_size,
570d82d4ff0SYann Gautier 					    I2C_AUTOEND_MODE, I2C_NO_STARTSTOP);
571d82d4ff0SYann Gautier 		}
572d82d4ff0SYann Gautier 	} else {
573d82d4ff0SYann Gautier 		/* In Master Mode, Send Slave Address */
574d82d4ff0SYann Gautier 		if (xfer_count > MAX_NBYTE_SIZE) {
575d82d4ff0SYann Gautier 			xfer_size = MAX_NBYTE_SIZE;
576d82d4ff0SYann Gautier 			i2c_transfer_config(hi2c, dev_addr, xfer_size,
577d82d4ff0SYann Gautier 					    I2C_RELOAD_MODE,
578d82d4ff0SYann Gautier 					    I2C_GENERATE_START_WRITE);
579d82d4ff0SYann Gautier 		} else {
580d82d4ff0SYann Gautier 			xfer_size = xfer_count;
581d82d4ff0SYann Gautier 			i2c_transfer_config(hi2c, dev_addr, xfer_size,
582d82d4ff0SYann Gautier 					    I2C_AUTOEND_MODE,
583d82d4ff0SYann Gautier 					    I2C_GENERATE_START_WRITE);
584d82d4ff0SYann Gautier 		}
585d82d4ff0SYann Gautier 	}
586d82d4ff0SYann Gautier 
587d82d4ff0SYann Gautier 	do {
588d82d4ff0SYann Gautier 		if (i2c_wait_txis(hi2c, timeout_ref) != 0) {
589d82d4ff0SYann Gautier 			goto bail;
590d82d4ff0SYann Gautier 		}
591d82d4ff0SYann Gautier 
592d82d4ff0SYann Gautier 		mmio_write_8(hi2c->i2c_base_addr + I2C_TXDR, *p_buff);
593d82d4ff0SYann Gautier 		p_buff++;
594d82d4ff0SYann Gautier 		xfer_count--;
595d82d4ff0SYann Gautier 		xfer_size--;
596d82d4ff0SYann Gautier 
597d82d4ff0SYann Gautier 		if ((xfer_count != 0U) && (xfer_size == 0U)) {
598d82d4ff0SYann Gautier 			/* Wait until TCR flag is set */
599d82d4ff0SYann Gautier 			if (i2c_wait_flag(hi2c, I2C_FLAG_TCR, 0,
600d82d4ff0SYann Gautier 					  timeout_ref) != 0) {
601d82d4ff0SYann Gautier 				goto bail;
602d82d4ff0SYann Gautier 			}
603d82d4ff0SYann Gautier 
604d82d4ff0SYann Gautier 			if (xfer_count > MAX_NBYTE_SIZE) {
605d82d4ff0SYann Gautier 				xfer_size = MAX_NBYTE_SIZE;
606d82d4ff0SYann Gautier 				i2c_transfer_config(hi2c, dev_addr,
607d82d4ff0SYann Gautier 						    xfer_size,
608d82d4ff0SYann Gautier 						    I2C_RELOAD_MODE,
609d82d4ff0SYann Gautier 						    I2C_NO_STARTSTOP);
610d82d4ff0SYann Gautier 			} else {
611d82d4ff0SYann Gautier 				xfer_size = xfer_count;
612d82d4ff0SYann Gautier 				i2c_transfer_config(hi2c, dev_addr,
613d82d4ff0SYann Gautier 						    xfer_size,
614d82d4ff0SYann Gautier 						    I2C_AUTOEND_MODE,
615d82d4ff0SYann Gautier 						    I2C_NO_STARTSTOP);
616d82d4ff0SYann Gautier 			}
617d82d4ff0SYann Gautier 		}
618d82d4ff0SYann Gautier 
619d82d4ff0SYann Gautier 	} while (xfer_count > 0U);
620d82d4ff0SYann Gautier 
621d82d4ff0SYann Gautier 	/*
622d82d4ff0SYann Gautier 	 * No need to Check TC flag, with AUTOEND mode the stop
623d82d4ff0SYann Gautier 	 * is automatically generated.
624d82d4ff0SYann Gautier 	 * Wait until STOPF flag is reset.
625d82d4ff0SYann Gautier 	 */
626d82d4ff0SYann Gautier 	if (i2c_wait_stop(hi2c, timeout_ref) != 0) {
627d82d4ff0SYann Gautier 		goto bail;
628d82d4ff0SYann Gautier 	}
629d82d4ff0SYann Gautier 
630d82d4ff0SYann Gautier 	mmio_write_32(hi2c->i2c_base_addr + I2C_ICR, I2C_FLAG_STOPF);
631d82d4ff0SYann Gautier 
632d82d4ff0SYann Gautier 	mmio_clrbits_32(hi2c->i2c_base_addr + I2C_CR2, I2C_RESET_CR2);
633d82d4ff0SYann Gautier 
634d82d4ff0SYann Gautier 	hi2c->i2c_state = I2C_STATE_READY;
635d82d4ff0SYann Gautier 	hi2c->i2c_mode  = I2C_MODE_NONE;
636d82d4ff0SYann Gautier 
637d82d4ff0SYann Gautier 	rc = 0;
638d82d4ff0SYann Gautier 
639d82d4ff0SYann Gautier bail:
640d82d4ff0SYann Gautier 	hi2c->lock = 0;
64133667d29SYann Gautier 	clk_disable(hi2c->clock);
642d82d4ff0SYann Gautier 
643d82d4ff0SYann Gautier 	return rc;
644d82d4ff0SYann Gautier }
645d82d4ff0SYann Gautier 
646d82d4ff0SYann Gautier /*
647d82d4ff0SYann Gautier  * @brief  Write an amount of data in blocking mode to a specific memory
648d82d4ff0SYann Gautier  *         address.
649d82d4ff0SYann Gautier  * @param  hi2c: Pointer to a struct i2c_handle_s structure that contains
650d82d4ff0SYann Gautier  *               the configuration information for the specified I2C.
651d82d4ff0SYann Gautier  * @param  dev_addr: Target device address
652d82d4ff0SYann Gautier  * @param  mem_addr: Internal memory address
653d82d4ff0SYann Gautier  * @param  mem_add_size: Size of internal memory address
654d82d4ff0SYann Gautier  * @param  p_data: Pointer to data buffer
655d82d4ff0SYann Gautier  * @param  size: Amount of data to be sent
656d82d4ff0SYann Gautier  * @param  timeout_ms: Timeout duration in milliseconds
657d82d4ff0SYann Gautier  * @retval 0 if OK, negative value else
658d82d4ff0SYann Gautier  */
659d82d4ff0SYann Gautier int stm32_i2c_mem_write(struct i2c_handle_s *hi2c, uint16_t dev_addr,
660d82d4ff0SYann Gautier 			uint16_t mem_addr, uint16_t mem_add_size,
661d82d4ff0SYann Gautier 			uint8_t *p_data, uint16_t size, uint32_t timeout_ms)
662d82d4ff0SYann Gautier {
663d82d4ff0SYann Gautier 	return i2c_write(hi2c, dev_addr, mem_addr, mem_add_size,
664d82d4ff0SYann Gautier 			 p_data, size, timeout_ms, I2C_MODE_MEM);
665d82d4ff0SYann Gautier }
666d82d4ff0SYann Gautier 
667d82d4ff0SYann Gautier /*
668d82d4ff0SYann Gautier  * @brief  Transmits in master mode an amount of data in blocking mode.
669d82d4ff0SYann Gautier  * @param  hi2c: Pointer to a struct i2c_handle_s structure that contains
670d82d4ff0SYann Gautier  *               the configuration information for the specified I2C.
671d82d4ff0SYann Gautier  * @param  dev_addr: Target device address
672d82d4ff0SYann Gautier  * @param  p_data: Pointer to data buffer
673d82d4ff0SYann Gautier  * @param  size: Amount of data to be sent
674d82d4ff0SYann Gautier  * @param  timeout_ms: Timeout duration in milliseconds
675d82d4ff0SYann Gautier  * @retval 0 if OK, negative value else
676d82d4ff0SYann Gautier  */
677d82d4ff0SYann Gautier int stm32_i2c_master_transmit(struct i2c_handle_s *hi2c, uint16_t dev_addr,
678d82d4ff0SYann Gautier 			      uint8_t *p_data, uint16_t size,
679d82d4ff0SYann Gautier 			      uint32_t timeout_ms)
680d82d4ff0SYann Gautier {
681d82d4ff0SYann Gautier 	return i2c_write(hi2c, dev_addr, 0, 0,
682d82d4ff0SYann Gautier 			 p_data, size, timeout_ms, I2C_MODE_MASTER);
683d82d4ff0SYann Gautier }
684d82d4ff0SYann Gautier 
685d82d4ff0SYann Gautier /*
686d82d4ff0SYann Gautier  * @brief  Generic function to read an amount of data in blocking mode
687d82d4ff0SYann Gautier  *         (for Memory Mode and Master Mode)
688d82d4ff0SYann Gautier  * @param  hi2c: Pointer to a struct i2c_handle_s structure that contains
689d82d4ff0SYann Gautier  *               the configuration information for the specified I2C.
690d82d4ff0SYann Gautier  * @param  dev_addr: Target device address
691d82d4ff0SYann Gautier  * @param  mem_addr: Internal memory address (if Memory Mode)
692d82d4ff0SYann Gautier  * @param  mem_add_size: Size of internal memory address (if Memory Mode)
693d82d4ff0SYann Gautier  * @param  p_data: Pointer to data buffer
694d82d4ff0SYann Gautier  * @param  size: Amount of data to be sent
695d82d4ff0SYann Gautier  * @param  timeout_ms: Timeout duration in milliseconds
696d82d4ff0SYann Gautier  * @param  mode: Communication mode
697d82d4ff0SYann Gautier  * @retval 0 if OK, negative value else
698d82d4ff0SYann Gautier  */
699d82d4ff0SYann Gautier static int i2c_read(struct i2c_handle_s *hi2c, uint16_t dev_addr,
700d82d4ff0SYann Gautier 		    uint16_t mem_addr, uint16_t mem_add_size,
701d82d4ff0SYann Gautier 		    uint8_t *p_data, uint16_t size, uint32_t timeout_ms,
702d82d4ff0SYann Gautier 		    enum i2c_mode_e mode)
703d82d4ff0SYann Gautier {
704d82d4ff0SYann Gautier 	uint64_t timeout_ref;
705d82d4ff0SYann Gautier 	int rc = -EIO;
706d82d4ff0SYann Gautier 	uint8_t *p_buff = p_data;
707d82d4ff0SYann Gautier 	uint32_t xfer_count = size;
708d82d4ff0SYann Gautier 	uint32_t xfer_size;
709d82d4ff0SYann Gautier 
710d82d4ff0SYann Gautier 	if ((mode != I2C_MODE_MASTER) && (mode != I2C_MODE_MEM)) {
711d82d4ff0SYann Gautier 		return -1;
712d82d4ff0SYann Gautier 	}
713d82d4ff0SYann Gautier 
714d82d4ff0SYann Gautier 	if ((hi2c->i2c_state != I2C_STATE_READY) || (hi2c->lock != 0U)) {
715d82d4ff0SYann Gautier 		return -EBUSY;
716d82d4ff0SYann Gautier 	}
717d82d4ff0SYann Gautier 
718d82d4ff0SYann Gautier 	if ((p_data == NULL) || (size == 0U)) {
719d82d4ff0SYann Gautier 		return  -EINVAL;
720d82d4ff0SYann Gautier 	}
721d82d4ff0SYann Gautier 
72233667d29SYann Gautier 	clk_enable(hi2c->clock);
723d82d4ff0SYann Gautier 
724d82d4ff0SYann Gautier 	hi2c->lock = 1;
725d82d4ff0SYann Gautier 
726d82d4ff0SYann Gautier 	timeout_ref = timeout_init_us(I2C_TIMEOUT_BUSY_MS * 1000);
727d82d4ff0SYann Gautier 	if (i2c_wait_flag(hi2c, I2C_FLAG_BUSY, 1, timeout_ref) != 0) {
728d82d4ff0SYann Gautier 		goto bail;
729d82d4ff0SYann Gautier 	}
730d82d4ff0SYann Gautier 
731d82d4ff0SYann Gautier 	hi2c->i2c_state = I2C_STATE_BUSY_RX;
732d82d4ff0SYann Gautier 	hi2c->i2c_mode = mode;
733d82d4ff0SYann Gautier 	hi2c->i2c_err = I2C_ERROR_NONE;
734d82d4ff0SYann Gautier 
735d82d4ff0SYann Gautier 	if (mode == I2C_MODE_MEM) {
736d82d4ff0SYann Gautier 		/* Send Memory Address */
737d82d4ff0SYann Gautier 		if (i2c_request_memory_read(hi2c, dev_addr, mem_addr,
738d82d4ff0SYann Gautier 					    mem_add_size, timeout_ref) != 0) {
739d82d4ff0SYann Gautier 			goto bail;
740d82d4ff0SYann Gautier 		}
741d82d4ff0SYann Gautier 	}
742d82d4ff0SYann Gautier 
743d82d4ff0SYann Gautier 	/*
744d82d4ff0SYann Gautier 	 * Send Slave Address.
745d82d4ff0SYann Gautier 	 * Set NBYTES to write and reload if xfer_count > MAX_NBYTE_SIZE
746d82d4ff0SYann Gautier 	 * and generate RESTART.
747d82d4ff0SYann Gautier 	 */
748d82d4ff0SYann Gautier 	if (xfer_count > MAX_NBYTE_SIZE) {
749d82d4ff0SYann Gautier 		xfer_size = MAX_NBYTE_SIZE;
750d82d4ff0SYann Gautier 		i2c_transfer_config(hi2c, dev_addr, xfer_size,
751d82d4ff0SYann Gautier 				    I2C_RELOAD_MODE, I2C_GENERATE_START_READ);
752d82d4ff0SYann Gautier 	} else {
753d82d4ff0SYann Gautier 		xfer_size = xfer_count;
754d82d4ff0SYann Gautier 		i2c_transfer_config(hi2c, dev_addr, xfer_size,
755d82d4ff0SYann Gautier 				    I2C_AUTOEND_MODE, I2C_GENERATE_START_READ);
756d82d4ff0SYann Gautier 	}
757d82d4ff0SYann Gautier 
758d82d4ff0SYann Gautier 	do {
759d82d4ff0SYann Gautier 		if (i2c_wait_flag(hi2c, I2C_FLAG_RXNE, 0, timeout_ref) != 0) {
760d82d4ff0SYann Gautier 			goto bail;
761d82d4ff0SYann Gautier 		}
762d82d4ff0SYann Gautier 
763d82d4ff0SYann Gautier 		*p_buff = mmio_read_8(hi2c->i2c_base_addr + I2C_RXDR);
764d82d4ff0SYann Gautier 		p_buff++;
765d82d4ff0SYann Gautier 		xfer_size--;
766d82d4ff0SYann Gautier 		xfer_count--;
767d82d4ff0SYann Gautier 
768d82d4ff0SYann Gautier 		if ((xfer_count != 0U) && (xfer_size == 0U)) {
769d82d4ff0SYann Gautier 			if (i2c_wait_flag(hi2c, I2C_FLAG_TCR, 0,
770d82d4ff0SYann Gautier 					  timeout_ref) != 0) {
771d82d4ff0SYann Gautier 				goto bail;
772d82d4ff0SYann Gautier 			}
773d82d4ff0SYann Gautier 
774d82d4ff0SYann Gautier 			if (xfer_count > MAX_NBYTE_SIZE) {
775d82d4ff0SYann Gautier 				xfer_size = MAX_NBYTE_SIZE;
776d82d4ff0SYann Gautier 				i2c_transfer_config(hi2c, dev_addr,
777d82d4ff0SYann Gautier 						    xfer_size,
778d82d4ff0SYann Gautier 						    I2C_RELOAD_MODE,
779d82d4ff0SYann Gautier 						    I2C_NO_STARTSTOP);
780d82d4ff0SYann Gautier 			} else {
781d82d4ff0SYann Gautier 				xfer_size = xfer_count;
782d82d4ff0SYann Gautier 				i2c_transfer_config(hi2c, dev_addr,
783d82d4ff0SYann Gautier 						    xfer_size,
784d82d4ff0SYann Gautier 						    I2C_AUTOEND_MODE,
785d82d4ff0SYann Gautier 						    I2C_NO_STARTSTOP);
786d82d4ff0SYann Gautier 			}
787d82d4ff0SYann Gautier 		}
788d82d4ff0SYann Gautier 	} while (xfer_count > 0U);
789d82d4ff0SYann Gautier 
790d82d4ff0SYann Gautier 	/*
791d82d4ff0SYann Gautier 	 * No need to Check TC flag, with AUTOEND mode the stop
792d82d4ff0SYann Gautier 	 * is automatically generated.
793d82d4ff0SYann Gautier 	 * Wait until STOPF flag is reset.
794d82d4ff0SYann Gautier 	 */
795d82d4ff0SYann Gautier 	if (i2c_wait_stop(hi2c, timeout_ref) != 0) {
796d82d4ff0SYann Gautier 		goto bail;
797d82d4ff0SYann Gautier 	}
798d82d4ff0SYann Gautier 
799d82d4ff0SYann Gautier 	mmio_write_32(hi2c->i2c_base_addr + I2C_ICR, I2C_FLAG_STOPF);
800d82d4ff0SYann Gautier 
801d82d4ff0SYann Gautier 	mmio_clrbits_32(hi2c->i2c_base_addr + I2C_CR2, I2C_RESET_CR2);
802d82d4ff0SYann Gautier 
803d82d4ff0SYann Gautier 	hi2c->i2c_state = I2C_STATE_READY;
804d82d4ff0SYann Gautier 	hi2c->i2c_mode = I2C_MODE_NONE;
805d82d4ff0SYann Gautier 
806d82d4ff0SYann Gautier 	rc = 0;
807d82d4ff0SYann Gautier 
808d82d4ff0SYann Gautier bail:
809d82d4ff0SYann Gautier 	hi2c->lock = 0;
81033667d29SYann Gautier 	clk_disable(hi2c->clock);
811d82d4ff0SYann Gautier 
812d82d4ff0SYann Gautier 	return rc;
813d82d4ff0SYann Gautier }
814d82d4ff0SYann Gautier 
815d82d4ff0SYann Gautier /*
816d82d4ff0SYann Gautier  * @brief  Read an amount of data in blocking mode from a specific memory
817d82d4ff0SYann Gautier  *	   address.
818d82d4ff0SYann Gautier  * @param  hi2c: Pointer to a struct i2c_handle_s structure that contains
819d82d4ff0SYann Gautier  *               the configuration information for the specified I2C.
820d82d4ff0SYann Gautier  * @param  dev_addr: Target device address
821d82d4ff0SYann Gautier  * @param  mem_addr: Internal memory address
822d82d4ff0SYann Gautier  * @param  mem_add_size: Size of internal memory address
823d82d4ff0SYann Gautier  * @param  p_data: Pointer to data buffer
824d82d4ff0SYann Gautier  * @param  size: Amount of data to be sent
825d82d4ff0SYann Gautier  * @param  timeout_ms: Timeout duration in milliseconds
826d82d4ff0SYann Gautier  * @retval 0 if OK, negative value else
827d82d4ff0SYann Gautier  */
828d82d4ff0SYann Gautier int stm32_i2c_mem_read(struct i2c_handle_s *hi2c, uint16_t dev_addr,
829d82d4ff0SYann Gautier 		       uint16_t mem_addr, uint16_t mem_add_size,
830d82d4ff0SYann Gautier 		       uint8_t *p_data, uint16_t size, uint32_t timeout_ms)
831d82d4ff0SYann Gautier {
832d82d4ff0SYann Gautier 	return i2c_read(hi2c, dev_addr, mem_addr, mem_add_size,
833d82d4ff0SYann Gautier 			p_data, size, timeout_ms, I2C_MODE_MEM);
834d82d4ff0SYann Gautier }
835d82d4ff0SYann Gautier 
836d82d4ff0SYann Gautier /*
837d82d4ff0SYann Gautier  * @brief  Receives in master mode an amount of data in blocking mode.
838d82d4ff0SYann Gautier  * @param  hi2c: Pointer to a struct i2c_handle_s structure that contains
839d82d4ff0SYann Gautier  *               the configuration information for the specified I2C.
840d82d4ff0SYann Gautier  * @param  dev_addr: Target device address
841d82d4ff0SYann Gautier  * @param  p_data: Pointer to data buffer
842d82d4ff0SYann Gautier  * @param  size: Amount of data to be sent
843d82d4ff0SYann Gautier  * @param  timeout_ms: Timeout duration in milliseconds
844d82d4ff0SYann Gautier  * @retval 0 if OK, negative value else
845d82d4ff0SYann Gautier  */
846d82d4ff0SYann Gautier int stm32_i2c_master_receive(struct i2c_handle_s *hi2c, uint16_t dev_addr,
847d82d4ff0SYann Gautier 			     uint8_t *p_data, uint16_t size,
848d82d4ff0SYann Gautier 			     uint32_t timeout_ms)
849d82d4ff0SYann Gautier {
850d82d4ff0SYann Gautier 	return i2c_read(hi2c, dev_addr, 0, 0,
851d82d4ff0SYann Gautier 			p_data, size, timeout_ms, I2C_MODE_MASTER);
852d82d4ff0SYann Gautier }
853d82d4ff0SYann Gautier 
854d82d4ff0SYann Gautier /*
855d82d4ff0SYann Gautier  * @brief  Checks if target device is ready for communication.
856d82d4ff0SYann Gautier  * @note   This function is used with Memory devices
857d82d4ff0SYann Gautier  * @param  hi2c: Pointer to a struct i2c_handle_s structure that contains
858d82d4ff0SYann Gautier  *               the configuration information for the specified I2C.
859d82d4ff0SYann Gautier  * @param  dev_addr: Target device address
860d82d4ff0SYann Gautier  * @param  trials: Number of trials
861d82d4ff0SYann Gautier  * @param  timeout_ms: Timeout duration in milliseconds
862d82d4ff0SYann Gautier  * @retval True if device is ready, false else
863d82d4ff0SYann Gautier  */
864d82d4ff0SYann Gautier bool stm32_i2c_is_device_ready(struct i2c_handle_s *hi2c,
865d82d4ff0SYann Gautier 			       uint16_t dev_addr, uint32_t trials,
866d82d4ff0SYann Gautier 			       uint32_t timeout_ms)
867d82d4ff0SYann Gautier {
868d82d4ff0SYann Gautier 	uint32_t i2c_trials = 0U;
869d82d4ff0SYann Gautier 	bool rc = false;
870d82d4ff0SYann Gautier 
871d82d4ff0SYann Gautier 	if ((hi2c->i2c_state != I2C_STATE_READY) || (hi2c->lock != 0U)) {
872d82d4ff0SYann Gautier 		return rc;
873d82d4ff0SYann Gautier 	}
874d82d4ff0SYann Gautier 
87533667d29SYann Gautier 	clk_enable(hi2c->clock);
876d82d4ff0SYann Gautier 
877d82d4ff0SYann Gautier 	hi2c->lock = 1;
878d82d4ff0SYann Gautier 	hi2c->i2c_mode = I2C_MODE_NONE;
879d82d4ff0SYann Gautier 
880d82d4ff0SYann Gautier 	if ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) & I2C_FLAG_BUSY) !=
881d82d4ff0SYann Gautier 	    0U) {
882d82d4ff0SYann Gautier 		goto bail;
883d82d4ff0SYann Gautier 	}
884d82d4ff0SYann Gautier 
885435832abSYann Gautier 	hi2c->i2c_state = I2C_STATE_BUSY;
886d82d4ff0SYann Gautier 	hi2c->i2c_err = I2C_ERROR_NONE;
887435832abSYann Gautier 
888d82d4ff0SYann Gautier 	do {
889d82d4ff0SYann Gautier 		uint64_t timeout_ref;
890435832abSYann Gautier 
891d82d4ff0SYann Gautier 		/* Generate Start */
892d82d4ff0SYann Gautier 		if ((mmio_read_32(hi2c->i2c_base_addr + I2C_OAR1) &
893d82d4ff0SYann Gautier 		     I2C_OAR1_OA1MODE) == 0) {
894d82d4ff0SYann Gautier 			mmio_write_32(hi2c->i2c_base_addr + I2C_CR2,
895d82d4ff0SYann Gautier 				      (((uint32_t)dev_addr & I2C_CR2_SADD) |
896d82d4ff0SYann Gautier 				       I2C_CR2_START | I2C_CR2_AUTOEND) &
897d82d4ff0SYann Gautier 				      ~I2C_CR2_RD_WRN);
898d82d4ff0SYann Gautier 		} else {
899d82d4ff0SYann Gautier 			mmio_write_32(hi2c->i2c_base_addr + I2C_CR2,
900d82d4ff0SYann Gautier 				      (((uint32_t)dev_addr & I2C_CR2_SADD) |
901d82d4ff0SYann Gautier 				       I2C_CR2_START | I2C_CR2_ADD10) &
902d82d4ff0SYann Gautier 				      ~I2C_CR2_RD_WRN);
903d82d4ff0SYann Gautier 		}
904435832abSYann Gautier 
905d82d4ff0SYann Gautier 		/*
906d82d4ff0SYann Gautier 		 * No need to Check TC flag, with AUTOEND mode the stop
907d82d4ff0SYann Gautier 		 * is automatically generated.
908d82d4ff0SYann Gautier 		 * Wait until STOPF flag is set or a NACK flag is set.
909d82d4ff0SYann Gautier 		 */
910d82d4ff0SYann Gautier 		timeout_ref = timeout_init_us(timeout_ms * 1000);
911d82d4ff0SYann Gautier 		do {
912d82d4ff0SYann Gautier 			if ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) &
913d82d4ff0SYann Gautier 			     (I2C_FLAG_STOPF | I2C_FLAG_AF)) != 0U) {
914d82d4ff0SYann Gautier 				break;
915d82d4ff0SYann Gautier 			}
916435832abSYann Gautier 
917d82d4ff0SYann Gautier 			if (timeout_elapsed(timeout_ref)) {
918d82d4ff0SYann Gautier 				notif_i2c_timeout(hi2c);
919d82d4ff0SYann Gautier 				goto bail;
920d82d4ff0SYann Gautier 			}
921d82d4ff0SYann Gautier 		} while (true);
922d82d4ff0SYann Gautier 
923d82d4ff0SYann Gautier 		if ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) &
924d82d4ff0SYann Gautier 		     I2C_FLAG_AF) == 0U) {
925d82d4ff0SYann Gautier 			if (i2c_wait_flag(hi2c, I2C_FLAG_STOPF, 0,
926d82d4ff0SYann Gautier 					  timeout_ref) != 0) {
927d82d4ff0SYann Gautier 				goto bail;
928d82d4ff0SYann Gautier 			}
929d82d4ff0SYann Gautier 
930d82d4ff0SYann Gautier 			mmio_write_32(hi2c->i2c_base_addr + I2C_ICR,
931d82d4ff0SYann Gautier 				      I2C_FLAG_STOPF);
932435832abSYann Gautier 
933435832abSYann Gautier 			hi2c->i2c_state = I2C_STATE_READY;
934435832abSYann Gautier 
935d82d4ff0SYann Gautier 			rc = true;
936d82d4ff0SYann Gautier 			goto bail;
937435832abSYann Gautier 		}
938d82d4ff0SYann Gautier 
939d82d4ff0SYann Gautier 		if (i2c_wait_flag(hi2c, I2C_FLAG_STOPF, 0, timeout_ref) != 0) {
940d82d4ff0SYann Gautier 			goto bail;
941d82d4ff0SYann Gautier 		}
942d82d4ff0SYann Gautier 
943d82d4ff0SYann Gautier 		mmio_write_32(hi2c->i2c_base_addr + I2C_ICR, I2C_FLAG_AF);
944d82d4ff0SYann Gautier 
945d82d4ff0SYann Gautier 		mmio_write_32(hi2c->i2c_base_addr + I2C_ICR, I2C_FLAG_STOPF);
946d82d4ff0SYann Gautier 
947d82d4ff0SYann Gautier 		if (i2c_trials == trials) {
948d82d4ff0SYann Gautier 			mmio_setbits_32(hi2c->i2c_base_addr + I2C_CR2,
949d82d4ff0SYann Gautier 					I2C_CR2_STOP);
950d82d4ff0SYann Gautier 
951d82d4ff0SYann Gautier 			if (i2c_wait_flag(hi2c, I2C_FLAG_STOPF, 0,
952d82d4ff0SYann Gautier 					  timeout_ref) != 0) {
953d82d4ff0SYann Gautier 				goto bail;
954d82d4ff0SYann Gautier 			}
955d82d4ff0SYann Gautier 
956d82d4ff0SYann Gautier 			mmio_write_32(hi2c->i2c_base_addr + I2C_ICR,
957d82d4ff0SYann Gautier 				      I2C_FLAG_STOPF);
958d82d4ff0SYann Gautier 		}
959d82d4ff0SYann Gautier 
960d82d4ff0SYann Gautier 		i2c_trials++;
961d82d4ff0SYann Gautier 	} while (i2c_trials < trials);
962d82d4ff0SYann Gautier 
963d82d4ff0SYann Gautier 	notif_i2c_timeout(hi2c);
964d82d4ff0SYann Gautier 
965d82d4ff0SYann Gautier bail:
966d82d4ff0SYann Gautier 	hi2c->lock = 0;
96733667d29SYann Gautier 	clk_disable(hi2c->clock);
968d82d4ff0SYann Gautier 
969d82d4ff0SYann Gautier 	return rc;
970d82d4ff0SYann Gautier }
971d82d4ff0SYann Gautier 
972