xref: /rk3399_ARM-atf/drivers/st/i2c/stm32_i2c.c (revision 33667d299bd5398ca549f542345e0f321b483d17)
1435832abSYann Gautier /*
2*33667d29SYann Gautier  * Copyright (c) 2016-2021, 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 <libfdt.h>
12d82d4ff0SYann Gautier 
13d82d4ff0SYann Gautier #include <platform_def.h>
14d82d4ff0SYann Gautier 
15d82d4ff0SYann Gautier #include <common/debug.h>
16*33667d29SYann Gautier #include <drivers/clk.h>
17435832abSYann Gautier #include <drivers/delay_timer.h>
18d82d4ff0SYann Gautier #include <drivers/st/stm32_gpio.h>
19435832abSYann Gautier #include <drivers/st/stm32_i2c.h>
20435832abSYann Gautier #include <lib/mmio.h>
21d82d4ff0SYann Gautier #include <lib/utils.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 {
100d82d4ff0SYann Gautier 	const fdt32_t *cuint;
101d82d4ff0SYann Gautier 
102d82d4ff0SYann Gautier 	cuint = fdt_getprop(fdt, node, "i2c-scl-rising-time-ns", NULL);
103d82d4ff0SYann Gautier 	if (cuint == NULL) {
104d82d4ff0SYann Gautier 		init->rise_time = STM32_I2C_RISE_TIME_DEFAULT;
105d82d4ff0SYann Gautier 	} else {
106d82d4ff0SYann Gautier 		init->rise_time = fdt32_to_cpu(*cuint);
107d82d4ff0SYann Gautier 	}
108d82d4ff0SYann Gautier 
109d82d4ff0SYann Gautier 	cuint = fdt_getprop(fdt, node, "i2c-scl-falling-time-ns", NULL);
110d82d4ff0SYann Gautier 	if (cuint == NULL) {
111d82d4ff0SYann Gautier 		init->fall_time = STM32_I2C_FALL_TIME_DEFAULT;
112d82d4ff0SYann Gautier 	} else {
113d82d4ff0SYann Gautier 		init->fall_time = fdt32_to_cpu(*cuint);
114d82d4ff0SYann Gautier 	}
115d82d4ff0SYann Gautier 
116d82d4ff0SYann Gautier 	cuint = fdt_getprop(fdt, node, "clock-frequency", NULL);
117d82d4ff0SYann Gautier 	if (cuint == NULL) {
118d82d4ff0SYann Gautier 		init->speed_mode = STM32_I2C_SPEED_DEFAULT;
119d82d4ff0SYann Gautier 	} else {
120d82d4ff0SYann Gautier 		switch (fdt32_to_cpu(*cuint)) {
121d82d4ff0SYann Gautier 		case STANDARD_RATE:
122d82d4ff0SYann Gautier 			init->speed_mode = I2C_SPEED_STANDARD;
123d82d4ff0SYann Gautier 			break;
124d82d4ff0SYann Gautier 		case FAST_RATE:
125d82d4ff0SYann Gautier 			init->speed_mode = I2C_SPEED_FAST;
126d82d4ff0SYann Gautier 			break;
127d82d4ff0SYann Gautier 		case FAST_PLUS_RATE:
128d82d4ff0SYann Gautier 			init->speed_mode = I2C_SPEED_FAST_PLUS;
129d82d4ff0SYann Gautier 			break;
130d82d4ff0SYann Gautier 		default:
131d82d4ff0SYann Gautier 			init->speed_mode = STM32_I2C_SPEED_DEFAULT;
132d82d4ff0SYann Gautier 			break;
133d82d4ff0SYann Gautier 		}
134d82d4ff0SYann Gautier 	}
135d82d4ff0SYann Gautier 
136d82d4ff0SYann Gautier 	return dt_set_pinctrl_config(node);
137d82d4ff0SYann Gautier }
138435832abSYann Gautier 
139435832abSYann Gautier /*
140435832abSYann Gautier  * @brief  Initialize the I2C device.
141435832abSYann Gautier  * @param  hi2c: Pointer to a struct i2c_handle_s structure that contains
142435832abSYann Gautier  *               the configuration information for the specified I2C.
143d82d4ff0SYann Gautier  * @param  init_data: Initialization configuration structure
144435832abSYann Gautier  * @retval 0 if OK, negative value else
145435832abSYann Gautier  */
146d82d4ff0SYann Gautier int stm32_i2c_init(struct i2c_handle_s *hi2c,
147d82d4ff0SYann Gautier 		   struct stm32_i2c_init_s *init_data)
148435832abSYann Gautier {
149d82d4ff0SYann Gautier 	int rc = 0;
150d82d4ff0SYann Gautier 	uint32_t timing = I2C_TIMING;
151d82d4ff0SYann Gautier 
152435832abSYann Gautier 	if (hi2c == NULL) {
153435832abSYann Gautier 		return -ENOENT;
154435832abSYann Gautier 	}
155435832abSYann Gautier 
156435832abSYann Gautier 	if (hi2c->i2c_state == I2C_STATE_RESET) {
157435832abSYann Gautier 		hi2c->lock = 0;
158435832abSYann Gautier 	}
159435832abSYann Gautier 
160435832abSYann Gautier 	hi2c->i2c_state = I2C_STATE_BUSY;
161435832abSYann Gautier 
162*33667d29SYann Gautier 	clk_enable(hi2c->clock);
163d82d4ff0SYann Gautier 
164435832abSYann Gautier 	/* Disable the selected I2C peripheral */
165435832abSYann Gautier 	mmio_clrbits_32(hi2c->i2c_base_addr + I2C_CR1, I2C_CR1_PE);
166435832abSYann Gautier 
167435832abSYann Gautier 	/* Configure I2Cx: Frequency range */
168435832abSYann Gautier 	mmio_write_32(hi2c->i2c_base_addr + I2C_TIMINGR,
169d82d4ff0SYann Gautier 		      timing & TIMINGR_CLEAR_MASK);
170435832abSYann Gautier 
171435832abSYann Gautier 	/* Disable Own Address1 before set the Own Address1 configuration */
172435832abSYann Gautier 	mmio_clrbits_32(hi2c->i2c_base_addr + I2C_OAR1, I2C_OAR1_OA1EN);
173435832abSYann Gautier 
174435832abSYann Gautier 	/* Configure I2Cx: Own Address1 and ack own address1 mode */
175d82d4ff0SYann Gautier 	if (init_data->addressing_mode == I2C_ADDRESSINGMODE_7BIT) {
176435832abSYann Gautier 		mmio_write_32(hi2c->i2c_base_addr + I2C_OAR1,
177d82d4ff0SYann Gautier 			      I2C_OAR1_OA1EN | init_data->own_address1);
178435832abSYann Gautier 	} else { /* I2C_ADDRESSINGMODE_10BIT */
179435832abSYann Gautier 		mmio_write_32(hi2c->i2c_base_addr + I2C_OAR1,
180435832abSYann Gautier 			      I2C_OAR1_OA1EN | I2C_OAR1_OA1MODE |
181d82d4ff0SYann Gautier 			      init_data->own_address1);
182435832abSYann Gautier 	}
183435832abSYann Gautier 
184d82d4ff0SYann Gautier 	mmio_write_32(hi2c->i2c_base_addr + I2C_CR2, 0);
185d82d4ff0SYann Gautier 
186435832abSYann Gautier 	/* Configure I2Cx: Addressing Master mode */
187d82d4ff0SYann Gautier 	if (init_data->addressing_mode == I2C_ADDRESSINGMODE_10BIT) {
188d82d4ff0SYann Gautier 		mmio_setbits_32(hi2c->i2c_base_addr + I2C_CR2, I2C_CR2_ADD10);
189435832abSYann Gautier 	}
190435832abSYann Gautier 
191435832abSYann Gautier 	/*
192435832abSYann Gautier 	 * Enable the AUTOEND by default, and enable NACK
193d82d4ff0SYann Gautier 	 * (should be disabled only during Slave process).
194435832abSYann Gautier 	 */
195435832abSYann Gautier 	mmio_setbits_32(hi2c->i2c_base_addr + I2C_CR2,
196435832abSYann Gautier 			I2C_CR2_AUTOEND | I2C_CR2_NACK);
197435832abSYann Gautier 
198435832abSYann Gautier 	/* Disable Own Address2 before set the Own Address2 configuration */
199435832abSYann Gautier 	mmio_clrbits_32(hi2c->i2c_base_addr + I2C_OAR2, I2C_DUALADDRESS_ENABLE);
200435832abSYann Gautier 
201435832abSYann Gautier 	/* Configure I2Cx: Dual mode and Own Address2 */
202435832abSYann Gautier 	mmio_write_32(hi2c->i2c_base_addr + I2C_OAR2,
203d82d4ff0SYann Gautier 		      init_data->dual_address_mode |
204d82d4ff0SYann Gautier 		      init_data->own_address2 |
205d82d4ff0SYann Gautier 		      (init_data->own_address2_masks << 8));
206435832abSYann Gautier 
207435832abSYann Gautier 	/* Configure I2Cx: Generalcall and NoStretch mode */
208435832abSYann Gautier 	mmio_write_32(hi2c->i2c_base_addr + I2C_CR1,
209d82d4ff0SYann Gautier 		      init_data->general_call_mode |
210d82d4ff0SYann Gautier 		      init_data->no_stretch_mode);
211435832abSYann Gautier 
212435832abSYann Gautier 	/* Enable the selected I2C peripheral */
213435832abSYann Gautier 	mmio_setbits_32(hi2c->i2c_base_addr + I2C_CR1, I2C_CR1_PE);
214435832abSYann Gautier 
215435832abSYann Gautier 	hi2c->i2c_err = I2C_ERROR_NONE;
216435832abSYann Gautier 	hi2c->i2c_state = I2C_STATE_READY;
217435832abSYann Gautier 	hi2c->i2c_mode = I2C_MODE_NONE;
218435832abSYann Gautier 
219d82d4ff0SYann Gautier 	rc = i2c_config_analog_filter(hi2c, init_data->analog_filter ?
220d82d4ff0SYann Gautier 						I2C_ANALOGFILTER_ENABLE :
221d82d4ff0SYann Gautier 						I2C_ANALOGFILTER_DISABLE);
222d82d4ff0SYann Gautier 	if (rc != 0) {
223d82d4ff0SYann Gautier 		ERROR("Cannot initialize I2C analog filter (%d)\n", rc);
224*33667d29SYann Gautier 		clk_disable(hi2c->clock);
225d82d4ff0SYann Gautier 		return rc;
226435832abSYann Gautier 	}
227435832abSYann Gautier 
228*33667d29SYann Gautier 	clk_disable(hi2c->clock);
229435832abSYann Gautier 
230d82d4ff0SYann Gautier 	return rc;
231435832abSYann Gautier }
232435832abSYann Gautier 
233435832abSYann Gautier /*
234435832abSYann Gautier  * @brief  I2C Tx data register flush process.
235d82d4ff0SYann Gautier  * @param  hi2c: I2C handle
236435832abSYann Gautier  * @retval None
237435832abSYann Gautier  */
238435832abSYann Gautier static void i2c_flush_txdr(struct i2c_handle_s *hi2c)
239435832abSYann Gautier {
240435832abSYann Gautier 	/*
241435832abSYann Gautier 	 * If a pending TXIS flag is set,
242435832abSYann Gautier 	 * write a dummy data in TXDR to clear it.
243435832abSYann Gautier 	 */
244435832abSYann Gautier 	if ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) & I2C_FLAG_TXIS) !=
245435832abSYann Gautier 	    0U) {
246435832abSYann Gautier 		mmio_write_32(hi2c->i2c_base_addr + I2C_TXDR, 0);
247435832abSYann Gautier 	}
248435832abSYann Gautier 
249435832abSYann Gautier 	/* Flush TX register if not empty */
250435832abSYann Gautier 	if ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) & I2C_FLAG_TXE) ==
251435832abSYann Gautier 	    0U) {
252435832abSYann Gautier 		mmio_setbits_32(hi2c->i2c_base_addr + I2C_ISR,
253435832abSYann Gautier 				I2C_FLAG_TXE);
254435832abSYann Gautier 	}
255435832abSYann Gautier }
256435832abSYann Gautier 
257435832abSYann Gautier /*
258435832abSYann Gautier  * @brief  This function handles I2C Communication timeout.
259435832abSYann Gautier  * @param  hi2c: Pointer to a struct i2c_handle_s structure that contains
260435832abSYann Gautier  *               the configuration information for the specified I2C.
261d82d4ff0SYann Gautier  * @param  flag: Specifies the I2C flag to check
262d82d4ff0SYann Gautier  * @param  awaited_value: The awaited bit value for the flag (0 or 1)
263d82d4ff0SYann Gautier  * @param  timeout_ref: Reference to target timeout
264435832abSYann Gautier  * @retval 0 if OK, negative value else
265435832abSYann Gautier  */
266435832abSYann Gautier static int i2c_wait_flag(struct i2c_handle_s *hi2c, uint32_t flag,
267d82d4ff0SYann Gautier 			 uint8_t awaited_value, uint64_t timeout_ref)
268435832abSYann Gautier {
269d82d4ff0SYann Gautier 	for ( ; ; ) {
270d82d4ff0SYann Gautier 		uint32_t isr = mmio_read_32(hi2c->i2c_base_addr + I2C_ISR);
271435832abSYann Gautier 
272d82d4ff0SYann Gautier 		if (!!(isr & flag) != !!awaited_value) {
273435832abSYann Gautier 			return 0;
274435832abSYann Gautier 		}
275435832abSYann Gautier 
276d82d4ff0SYann Gautier 		if (timeout_elapsed(timeout_ref)) {
277d82d4ff0SYann Gautier 			notif_i2c_timeout(hi2c);
278435832abSYann Gautier 			hi2c->lock = 0;
279435832abSYann Gautier 
280435832abSYann Gautier 			return -EIO;
281435832abSYann Gautier 		}
282435832abSYann Gautier 	}
283435832abSYann Gautier }
284435832abSYann Gautier 
285435832abSYann Gautier /*
286435832abSYann Gautier  * @brief  This function handles Acknowledge failed detection during
287435832abSYann Gautier  *	   an I2C Communication.
288435832abSYann Gautier  * @param  hi2c: Pointer to a struct i2c_handle_s structure that contains
289435832abSYann Gautier  *               the configuration information for the specified I2C.
290d82d4ff0SYann Gautier  * @param  timeout_ref: Reference to target timeout
291435832abSYann Gautier  * @retval 0 if OK, negative value else
292435832abSYann Gautier  */
293d82d4ff0SYann Gautier static int i2c_ack_failed(struct i2c_handle_s *hi2c, uint64_t timeout_ref)
294435832abSYann Gautier {
295435832abSYann Gautier 	if ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) & I2C_FLAG_AF) == 0U) {
296435832abSYann Gautier 		return 0;
297435832abSYann Gautier 	}
298435832abSYann Gautier 
299435832abSYann Gautier 	/*
300435832abSYann Gautier 	 * Wait until STOP Flag is reset.
301435832abSYann Gautier 	 * AutoEnd should be initiate after AF.
302435832abSYann Gautier 	 */
303435832abSYann Gautier 	while ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) &
304435832abSYann Gautier 		I2C_FLAG_STOPF) == 0U) {
305d82d4ff0SYann Gautier 		if (timeout_elapsed(timeout_ref)) {
306d82d4ff0SYann Gautier 			notif_i2c_timeout(hi2c);
307435832abSYann Gautier 			hi2c->lock = 0;
308435832abSYann Gautier 
309435832abSYann Gautier 			return -EIO;
310435832abSYann Gautier 		}
311435832abSYann Gautier 	}
312435832abSYann Gautier 
313435832abSYann Gautier 	mmio_write_32(hi2c->i2c_base_addr + I2C_ICR, I2C_FLAG_AF);
314435832abSYann Gautier 
315435832abSYann Gautier 	mmio_write_32(hi2c->i2c_base_addr + I2C_ICR, I2C_FLAG_STOPF);
316435832abSYann Gautier 
317435832abSYann Gautier 	i2c_flush_txdr(hi2c);
318435832abSYann Gautier 
319435832abSYann Gautier 	mmio_clrbits_32(hi2c->i2c_base_addr + I2C_CR2, I2C_RESET_CR2);
320435832abSYann Gautier 
321435832abSYann Gautier 	hi2c->i2c_err |= I2C_ERROR_AF;
322435832abSYann Gautier 	hi2c->i2c_state = I2C_STATE_READY;
323435832abSYann Gautier 	hi2c->i2c_mode = I2C_MODE_NONE;
324435832abSYann Gautier 
325435832abSYann Gautier 	hi2c->lock = 0;
326435832abSYann Gautier 
327435832abSYann Gautier 	return -EIO;
328435832abSYann Gautier }
329435832abSYann Gautier 
330435832abSYann Gautier /*
331d82d4ff0SYann Gautier  * @brief  This function handles I2C Communication timeout for specific usage
332d82d4ff0SYann Gautier  *	   of TXIS flag.
333d82d4ff0SYann Gautier  * @param  hi2c: Pointer to a struct i2c_handle_s structure that contains
334d82d4ff0SYann Gautier  *               the configuration information for the specified I2C.
335d82d4ff0SYann Gautier  * @param  timeout_ref: Reference to target timeout
336d82d4ff0SYann Gautier  * @retval 0 if OK, negative value else
337d82d4ff0SYann Gautier  */
338d82d4ff0SYann Gautier static int i2c_wait_txis(struct i2c_handle_s *hi2c, uint64_t timeout_ref)
339d82d4ff0SYann Gautier {
340d82d4ff0SYann Gautier 	while ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) &
341d82d4ff0SYann Gautier 		I2C_FLAG_TXIS) == 0U) {
342d82d4ff0SYann Gautier 		if (i2c_ack_failed(hi2c, timeout_ref) != 0) {
343d82d4ff0SYann Gautier 			return -EIO;
344d82d4ff0SYann Gautier 		}
345d82d4ff0SYann Gautier 
346d82d4ff0SYann Gautier 		if (timeout_elapsed(timeout_ref)) {
347d82d4ff0SYann Gautier 			notif_i2c_timeout(hi2c);
348d82d4ff0SYann Gautier 			hi2c->lock = 0;
349d82d4ff0SYann Gautier 
350d82d4ff0SYann Gautier 			return -EIO;
351d82d4ff0SYann Gautier 		}
352d82d4ff0SYann Gautier 	}
353d82d4ff0SYann Gautier 
354d82d4ff0SYann Gautier 	return 0;
355d82d4ff0SYann Gautier }
356d82d4ff0SYann Gautier 
357d82d4ff0SYann Gautier /*
358d82d4ff0SYann Gautier  * @brief  This function handles I2C Communication timeout for specific
359d82d4ff0SYann Gautier  *	   usage of STOP flag.
360d82d4ff0SYann Gautier  * @param  hi2c: Pointer to a struct i2c_handle_s structure that contains
361d82d4ff0SYann Gautier  *               the configuration information for the specified I2C.
362d82d4ff0SYann Gautier  * @param  timeout_ref: Reference to target timeout
363d82d4ff0SYann Gautier  * @retval 0 if OK, negative value else
364d82d4ff0SYann Gautier  */
365d82d4ff0SYann Gautier static int i2c_wait_stop(struct i2c_handle_s *hi2c, uint64_t timeout_ref)
366d82d4ff0SYann Gautier {
367d82d4ff0SYann Gautier 	while ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) &
368d82d4ff0SYann Gautier 		 I2C_FLAG_STOPF) == 0U) {
369d82d4ff0SYann Gautier 		if (i2c_ack_failed(hi2c, timeout_ref) != 0) {
370d82d4ff0SYann Gautier 			return -EIO;
371d82d4ff0SYann Gautier 		}
372d82d4ff0SYann Gautier 
373d82d4ff0SYann Gautier 		if (timeout_elapsed(timeout_ref)) {
374d82d4ff0SYann Gautier 			notif_i2c_timeout(hi2c);
375d82d4ff0SYann Gautier 			hi2c->lock = 0;
376d82d4ff0SYann Gautier 
377d82d4ff0SYann Gautier 			return -EIO;
378d82d4ff0SYann Gautier 		}
379d82d4ff0SYann Gautier 	}
380d82d4ff0SYann Gautier 
381d82d4ff0SYann Gautier 	return 0;
382d82d4ff0SYann Gautier }
383d82d4ff0SYann Gautier 
384d82d4ff0SYann Gautier /*
385435832abSYann Gautier  * @brief  Handles I2Cx communication when starting transfer or during transfer
386435832abSYann Gautier  *	   (TC or TCR flag are set).
387d82d4ff0SYann Gautier  * @param  hi2c: I2C handle
388d82d4ff0SYann Gautier  * @param  dev_addr: Specifies the slave address to be programmed
389435832abSYann Gautier  * @param  size: Specifies the number of bytes to be programmed.
390435832abSYann Gautier  *   This parameter must be a value between 0 and 255.
391435832abSYann Gautier  * @param  i2c_mode: New state of the I2C START condition generation.
392435832abSYann Gautier  *   This parameter can be one of the following values:
393435832abSYann Gautier  *     @arg @ref I2C_RELOAD_MODE: Enable Reload mode.
394435832abSYann Gautier  *     @arg @ref I2C_AUTOEND_MODE: Enable Automatic end mode.
395435832abSYann Gautier  *     @arg @ref I2C_SOFTEND_MODE: Enable Software end mode.
396435832abSYann Gautier  * @param  request: New state of the I2C START condition generation.
397435832abSYann Gautier  *   This parameter can be one of the following values:
398435832abSYann Gautier  *     @arg @ref I2C_NO_STARTSTOP: Don't Generate stop and start condition.
399435832abSYann Gautier  *     @arg @ref I2C_GENERATE_STOP: Generate stop condition
400435832abSYann Gautier  *                                  (size should be set to 0).
401435832abSYann Gautier  *     @arg @ref I2C_GENERATE_START_READ: Generate Restart for read request.
402435832abSYann Gautier  *     @arg @ref I2C_GENERATE_START_WRITE: Generate Restart for write request.
403435832abSYann Gautier  * @retval None
404435832abSYann Gautier  */
405435832abSYann Gautier static void i2c_transfer_config(struct i2c_handle_s *hi2c, uint16_t dev_addr,
406435832abSYann Gautier 				uint16_t size, uint32_t i2c_mode,
407435832abSYann Gautier 				uint32_t request)
408435832abSYann Gautier {
409435832abSYann Gautier 	uint32_t clr_value, set_value;
410435832abSYann Gautier 
411435832abSYann Gautier 	clr_value = (I2C_CR2_SADD | I2C_CR2_NBYTES | I2C_CR2_RELOAD |
412435832abSYann Gautier 		     I2C_CR2_AUTOEND | I2C_CR2_START | I2C_CR2_STOP) |
413435832abSYann Gautier 		(I2C_CR2_RD_WRN & (request >> (31U - I2C_CR2_RD_WRN_OFFSET)));
414435832abSYann Gautier 
415435832abSYann Gautier 	set_value = ((uint32_t)dev_addr & I2C_CR2_SADD) |
416435832abSYann Gautier 		(((uint32_t)size << I2C_CR2_NBYTES_OFFSET) & I2C_CR2_NBYTES) |
417435832abSYann Gautier 		i2c_mode | request;
418435832abSYann Gautier 
419435832abSYann Gautier 	mmio_clrsetbits_32(hi2c->i2c_base_addr + I2C_CR2, clr_value, set_value);
420435832abSYann Gautier }
421435832abSYann Gautier 
422435832abSYann Gautier /*
423d82d4ff0SYann Gautier  * @brief  Master sends target device address followed by internal memory
424d82d4ff0SYann Gautier  *	   address for write request.
425435832abSYann Gautier  * @param  hi2c: Pointer to a struct i2c_handle_s structure that contains
426d82d4ff0SYann Gautier  *               the configuration information for the specified I2C.
427d82d4ff0SYann Gautier  * @param  dev_addr: Target device address
428d82d4ff0SYann Gautier  * @param  mem_addr: Internal memory address
429d82d4ff0SYann Gautier  * @param  mem_add_size: Size of internal memory address
430d82d4ff0SYann Gautier  * @param  timeout_ref: Reference to target timeout
431435832abSYann Gautier  * @retval 0 if OK, negative value else
432435832abSYann Gautier  */
433d82d4ff0SYann Gautier static int i2c_request_memory_write(struct i2c_handle_s *hi2c,
434d82d4ff0SYann Gautier 				    uint16_t dev_addr, uint16_t mem_addr,
435d82d4ff0SYann Gautier 				    uint16_t mem_add_size, uint64_t timeout_ref)
436435832abSYann Gautier {
437d82d4ff0SYann Gautier 	i2c_transfer_config(hi2c, dev_addr, mem_add_size, I2C_RELOAD_MODE,
438d82d4ff0SYann Gautier 			    I2C_GENERATE_START_WRITE);
439d82d4ff0SYann Gautier 
440d82d4ff0SYann Gautier 	if (i2c_wait_txis(hi2c, timeout_ref) != 0) {
441d82d4ff0SYann Gautier 		return -EIO;
442d82d4ff0SYann Gautier 	}
443d82d4ff0SYann Gautier 
444d82d4ff0SYann Gautier 	if (mem_add_size == I2C_MEMADD_SIZE_8BIT) {
445d82d4ff0SYann Gautier 		/* Send Memory Address */
446d82d4ff0SYann Gautier 		mmio_write_8(hi2c->i2c_base_addr + I2C_TXDR,
447d82d4ff0SYann Gautier 			     (uint8_t)(mem_addr & 0x00FFU));
448d82d4ff0SYann Gautier 	} else {
449d82d4ff0SYann Gautier 		/* Send MSB of Memory Address */
450d82d4ff0SYann Gautier 		mmio_write_8(hi2c->i2c_base_addr + I2C_TXDR,
451d82d4ff0SYann Gautier 			     (uint8_t)((mem_addr & 0xFF00U) >> 8));
452d82d4ff0SYann Gautier 
453d82d4ff0SYann Gautier 		if (i2c_wait_txis(hi2c, timeout_ref) != 0) {
454d82d4ff0SYann Gautier 			return -EIO;
455d82d4ff0SYann Gautier 		}
456d82d4ff0SYann Gautier 
457d82d4ff0SYann Gautier 		/* Send LSB of Memory Address */
458d82d4ff0SYann Gautier 		mmio_write_8(hi2c->i2c_base_addr + I2C_TXDR,
459d82d4ff0SYann Gautier 			     (uint8_t)(mem_addr & 0x00FFU));
460d82d4ff0SYann Gautier 	}
461d82d4ff0SYann Gautier 
462d82d4ff0SYann Gautier 	if (i2c_wait_flag(hi2c, I2C_FLAG_TCR, 0, timeout_ref) != 0) {
463d82d4ff0SYann Gautier 		return -EIO;
464d82d4ff0SYann Gautier 	}
465d82d4ff0SYann Gautier 
466d82d4ff0SYann Gautier 	return 0;
467d82d4ff0SYann Gautier }
468d82d4ff0SYann Gautier 
469d82d4ff0SYann Gautier /*
470d82d4ff0SYann Gautier  * @brief  Master sends target device address followed by internal memory
471d82d4ff0SYann Gautier  *	   address for read request.
472d82d4ff0SYann Gautier  * @param  hi2c: Pointer to a struct i2c_handle_s structure that contains
473d82d4ff0SYann Gautier  *               the configuration information for the specified I2C.
474d82d4ff0SYann Gautier  * @param  dev_addr: Target device address
475d82d4ff0SYann Gautier  * @param  mem_addr: Internal memory address
476d82d4ff0SYann Gautier  * @param  mem_add_size: Size of internal memory address
477d82d4ff0SYann Gautier  * @param  timeout_ref: Reference to target timeout
478d82d4ff0SYann Gautier  * @retval 0 if OK, negative value else
479d82d4ff0SYann Gautier  */
480d82d4ff0SYann Gautier static int i2c_request_memory_read(struct i2c_handle_s *hi2c, uint16_t dev_addr,
481d82d4ff0SYann Gautier 				   uint16_t mem_addr, uint16_t mem_add_size,
482d82d4ff0SYann Gautier 				   uint64_t timeout_ref)
483d82d4ff0SYann Gautier {
484d82d4ff0SYann Gautier 	i2c_transfer_config(hi2c, dev_addr, mem_add_size, I2C_SOFTEND_MODE,
485d82d4ff0SYann Gautier 			    I2C_GENERATE_START_WRITE);
486d82d4ff0SYann Gautier 
487d82d4ff0SYann Gautier 	if (i2c_wait_txis(hi2c, timeout_ref) != 0) {
488d82d4ff0SYann Gautier 		return -EIO;
489d82d4ff0SYann Gautier 	}
490d82d4ff0SYann Gautier 
491d82d4ff0SYann Gautier 	if (mem_add_size == I2C_MEMADD_SIZE_8BIT) {
492d82d4ff0SYann Gautier 		/* Send Memory Address */
493d82d4ff0SYann Gautier 		mmio_write_8(hi2c->i2c_base_addr + I2C_TXDR,
494d82d4ff0SYann Gautier 			     (uint8_t)(mem_addr & 0x00FFU));
495d82d4ff0SYann Gautier 	} else {
496d82d4ff0SYann Gautier 		/* Send MSB of Memory Address */
497d82d4ff0SYann Gautier 		mmio_write_8(hi2c->i2c_base_addr + I2C_TXDR,
498d82d4ff0SYann Gautier 			     (uint8_t)((mem_addr & 0xFF00U) >> 8));
499d82d4ff0SYann Gautier 
500d82d4ff0SYann Gautier 		if (i2c_wait_txis(hi2c, timeout_ref) != 0) {
501d82d4ff0SYann Gautier 			return -EIO;
502d82d4ff0SYann Gautier 		}
503d82d4ff0SYann Gautier 
504d82d4ff0SYann Gautier 		/* Send LSB of Memory Address */
505d82d4ff0SYann Gautier 		mmio_write_8(hi2c->i2c_base_addr + I2C_TXDR,
506d82d4ff0SYann Gautier 			     (uint8_t)(mem_addr & 0x00FFU));
507d82d4ff0SYann Gautier 	}
508d82d4ff0SYann Gautier 
509d82d4ff0SYann Gautier 	if (i2c_wait_flag(hi2c, I2C_FLAG_TC, 0, timeout_ref) != 0) {
510d82d4ff0SYann Gautier 		return -EIO;
511d82d4ff0SYann Gautier 	}
512d82d4ff0SYann Gautier 
513d82d4ff0SYann Gautier 	return 0;
514d82d4ff0SYann Gautier }
515d82d4ff0SYann Gautier /*
516d82d4ff0SYann Gautier  * @brief  Generic function to write an amount of data in blocking mode
517d82d4ff0SYann Gautier  *         (for Memory Mode and Master Mode)
518d82d4ff0SYann Gautier  * @param  hi2c: Pointer to a struct i2c_handle_s structure that contains
519d82d4ff0SYann Gautier  *               the configuration information for the specified I2C.
520d82d4ff0SYann Gautier  * @param  dev_addr: Target device address
521d82d4ff0SYann Gautier  * @param  mem_addr: Internal memory address (if Memory Mode)
522d82d4ff0SYann Gautier  * @param  mem_add_size: Size of internal memory address (if Memory Mode)
523d82d4ff0SYann Gautier  * @param  p_data: Pointer to data buffer
524d82d4ff0SYann Gautier  * @param  size: Amount of data to be sent
525d82d4ff0SYann Gautier  * @param  timeout_ms: Timeout duration in milliseconds
526d82d4ff0SYann Gautier  * @param  mode: Communication mode
527d82d4ff0SYann Gautier  * @retval 0 if OK, negative value else
528d82d4ff0SYann Gautier  */
529d82d4ff0SYann Gautier static int i2c_write(struct i2c_handle_s *hi2c, uint16_t dev_addr,
530d82d4ff0SYann Gautier 		     uint16_t mem_addr, uint16_t mem_add_size,
531d82d4ff0SYann Gautier 		     uint8_t *p_data, uint16_t size, uint32_t timeout_ms,
532d82d4ff0SYann Gautier 		     enum i2c_mode_e mode)
533d82d4ff0SYann Gautier {
534d82d4ff0SYann Gautier 	uint64_t timeout_ref;
535d82d4ff0SYann Gautier 	int rc = -EIO;
536d82d4ff0SYann Gautier 	uint8_t *p_buff = p_data;
537d82d4ff0SYann Gautier 	uint32_t xfer_size;
538d82d4ff0SYann Gautier 	uint32_t xfer_count = size;
539d82d4ff0SYann Gautier 
540d82d4ff0SYann Gautier 	if ((mode != I2C_MODE_MASTER) && (mode != I2C_MODE_MEM)) {
541d82d4ff0SYann Gautier 		return -1;
542d82d4ff0SYann Gautier 	}
543d82d4ff0SYann Gautier 
544435832abSYann Gautier 	if ((hi2c->i2c_state != I2C_STATE_READY) || (hi2c->lock != 0U)) {
545435832abSYann Gautier 		return -EBUSY;
546435832abSYann Gautier 	}
547435832abSYann Gautier 
548d82d4ff0SYann Gautier 	if ((p_data == NULL) || (size == 0U)) {
549d82d4ff0SYann Gautier 		return -EINVAL;
550d82d4ff0SYann Gautier 	}
551d82d4ff0SYann Gautier 
552*33667d29SYann Gautier 	clk_enable(hi2c->clock);
553d82d4ff0SYann Gautier 
554435832abSYann Gautier 	hi2c->lock = 1;
555435832abSYann Gautier 
556d82d4ff0SYann Gautier 	timeout_ref = timeout_init_us(I2C_TIMEOUT_BUSY_MS * 1000);
557d82d4ff0SYann Gautier 	if (i2c_wait_flag(hi2c, I2C_FLAG_BUSY, 1, timeout_ref) != 0) {
558d82d4ff0SYann Gautier 		goto bail;
559d82d4ff0SYann Gautier 	}
560d82d4ff0SYann Gautier 
561d82d4ff0SYann Gautier 	hi2c->i2c_state = I2C_STATE_BUSY_TX;
562d82d4ff0SYann Gautier 	hi2c->i2c_mode = mode;
563d82d4ff0SYann Gautier 	hi2c->i2c_err = I2C_ERROR_NONE;
564d82d4ff0SYann Gautier 
565d82d4ff0SYann Gautier 	timeout_ref = timeout_init_us(timeout_ms * 1000);
566d82d4ff0SYann Gautier 
567d82d4ff0SYann Gautier 	if (mode == I2C_MODE_MEM) {
568d82d4ff0SYann Gautier 		/* In Memory Mode, Send Slave Address and Memory Address */
569d82d4ff0SYann Gautier 		if (i2c_request_memory_write(hi2c, dev_addr, mem_addr,
570d82d4ff0SYann Gautier 					     mem_add_size, timeout_ref) != 0) {
571d82d4ff0SYann Gautier 			goto bail;
572d82d4ff0SYann Gautier 		}
573d82d4ff0SYann Gautier 
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, I2C_NO_STARTSTOP);
578d82d4ff0SYann Gautier 		} else {
579d82d4ff0SYann Gautier 			xfer_size = xfer_count;
580d82d4ff0SYann Gautier 			i2c_transfer_config(hi2c, dev_addr, xfer_size,
581d82d4ff0SYann Gautier 					    I2C_AUTOEND_MODE, I2C_NO_STARTSTOP);
582d82d4ff0SYann Gautier 		}
583d82d4ff0SYann Gautier 	} else {
584d82d4ff0SYann Gautier 		/* In Master Mode, Send Slave Address */
585d82d4ff0SYann Gautier 		if (xfer_count > MAX_NBYTE_SIZE) {
586d82d4ff0SYann Gautier 			xfer_size = MAX_NBYTE_SIZE;
587d82d4ff0SYann Gautier 			i2c_transfer_config(hi2c, dev_addr, xfer_size,
588d82d4ff0SYann Gautier 					    I2C_RELOAD_MODE,
589d82d4ff0SYann Gautier 					    I2C_GENERATE_START_WRITE);
590d82d4ff0SYann Gautier 		} else {
591d82d4ff0SYann Gautier 			xfer_size = xfer_count;
592d82d4ff0SYann Gautier 			i2c_transfer_config(hi2c, dev_addr, xfer_size,
593d82d4ff0SYann Gautier 					    I2C_AUTOEND_MODE,
594d82d4ff0SYann Gautier 					    I2C_GENERATE_START_WRITE);
595d82d4ff0SYann Gautier 		}
596d82d4ff0SYann Gautier 	}
597d82d4ff0SYann Gautier 
598d82d4ff0SYann Gautier 	do {
599d82d4ff0SYann Gautier 		if (i2c_wait_txis(hi2c, timeout_ref) != 0) {
600d82d4ff0SYann Gautier 			goto bail;
601d82d4ff0SYann Gautier 		}
602d82d4ff0SYann Gautier 
603d82d4ff0SYann Gautier 		mmio_write_8(hi2c->i2c_base_addr + I2C_TXDR, *p_buff);
604d82d4ff0SYann Gautier 		p_buff++;
605d82d4ff0SYann Gautier 		xfer_count--;
606d82d4ff0SYann Gautier 		xfer_size--;
607d82d4ff0SYann Gautier 
608d82d4ff0SYann Gautier 		if ((xfer_count != 0U) && (xfer_size == 0U)) {
609d82d4ff0SYann Gautier 			/* Wait until TCR flag is set */
610d82d4ff0SYann Gautier 			if (i2c_wait_flag(hi2c, I2C_FLAG_TCR, 0,
611d82d4ff0SYann Gautier 					  timeout_ref) != 0) {
612d82d4ff0SYann Gautier 				goto bail;
613d82d4ff0SYann Gautier 			}
614d82d4ff0SYann Gautier 
615d82d4ff0SYann Gautier 			if (xfer_count > MAX_NBYTE_SIZE) {
616d82d4ff0SYann Gautier 				xfer_size = MAX_NBYTE_SIZE;
617d82d4ff0SYann Gautier 				i2c_transfer_config(hi2c, dev_addr,
618d82d4ff0SYann Gautier 						    xfer_size,
619d82d4ff0SYann Gautier 						    I2C_RELOAD_MODE,
620d82d4ff0SYann Gautier 						    I2C_NO_STARTSTOP);
621d82d4ff0SYann Gautier 			} else {
622d82d4ff0SYann Gautier 				xfer_size = xfer_count;
623d82d4ff0SYann Gautier 				i2c_transfer_config(hi2c, dev_addr,
624d82d4ff0SYann Gautier 						    xfer_size,
625d82d4ff0SYann Gautier 						    I2C_AUTOEND_MODE,
626d82d4ff0SYann Gautier 						    I2C_NO_STARTSTOP);
627d82d4ff0SYann Gautier 			}
628d82d4ff0SYann Gautier 		}
629d82d4ff0SYann Gautier 
630d82d4ff0SYann Gautier 	} while (xfer_count > 0U);
631d82d4ff0SYann Gautier 
632d82d4ff0SYann Gautier 	/*
633d82d4ff0SYann Gautier 	 * No need to Check TC flag, with AUTOEND mode the stop
634d82d4ff0SYann Gautier 	 * is automatically generated.
635d82d4ff0SYann Gautier 	 * Wait until STOPF flag is reset.
636d82d4ff0SYann Gautier 	 */
637d82d4ff0SYann Gautier 	if (i2c_wait_stop(hi2c, timeout_ref) != 0) {
638d82d4ff0SYann Gautier 		goto bail;
639d82d4ff0SYann Gautier 	}
640d82d4ff0SYann Gautier 
641d82d4ff0SYann Gautier 	mmio_write_32(hi2c->i2c_base_addr + I2C_ICR, I2C_FLAG_STOPF);
642d82d4ff0SYann Gautier 
643d82d4ff0SYann Gautier 	mmio_clrbits_32(hi2c->i2c_base_addr + I2C_CR2, I2C_RESET_CR2);
644d82d4ff0SYann Gautier 
645d82d4ff0SYann Gautier 	hi2c->i2c_state = I2C_STATE_READY;
646d82d4ff0SYann Gautier 	hi2c->i2c_mode  = I2C_MODE_NONE;
647d82d4ff0SYann Gautier 
648d82d4ff0SYann Gautier 	rc = 0;
649d82d4ff0SYann Gautier 
650d82d4ff0SYann Gautier bail:
651d82d4ff0SYann Gautier 	hi2c->lock = 0;
652*33667d29SYann Gautier 	clk_disable(hi2c->clock);
653d82d4ff0SYann Gautier 
654d82d4ff0SYann Gautier 	return rc;
655d82d4ff0SYann Gautier }
656d82d4ff0SYann Gautier 
657d82d4ff0SYann Gautier /*
658d82d4ff0SYann Gautier  * @brief  Write an amount of data in blocking mode to a specific memory
659d82d4ff0SYann Gautier  *         address.
660d82d4ff0SYann Gautier  * @param  hi2c: Pointer to a struct i2c_handle_s structure that contains
661d82d4ff0SYann Gautier  *               the configuration information for the specified I2C.
662d82d4ff0SYann Gautier  * @param  dev_addr: Target device address
663d82d4ff0SYann Gautier  * @param  mem_addr: Internal memory address
664d82d4ff0SYann Gautier  * @param  mem_add_size: Size of internal memory address
665d82d4ff0SYann Gautier  * @param  p_data: Pointer to data buffer
666d82d4ff0SYann Gautier  * @param  size: Amount of data to be sent
667d82d4ff0SYann Gautier  * @param  timeout_ms: Timeout duration in milliseconds
668d82d4ff0SYann Gautier  * @retval 0 if OK, negative value else
669d82d4ff0SYann Gautier  */
670d82d4ff0SYann Gautier int stm32_i2c_mem_write(struct i2c_handle_s *hi2c, uint16_t dev_addr,
671d82d4ff0SYann Gautier 			uint16_t mem_addr, uint16_t mem_add_size,
672d82d4ff0SYann Gautier 			uint8_t *p_data, uint16_t size, uint32_t timeout_ms)
673d82d4ff0SYann Gautier {
674d82d4ff0SYann Gautier 	return i2c_write(hi2c, dev_addr, mem_addr, mem_add_size,
675d82d4ff0SYann Gautier 			 p_data, size, timeout_ms, I2C_MODE_MEM);
676d82d4ff0SYann Gautier }
677d82d4ff0SYann Gautier 
678d82d4ff0SYann Gautier /*
679d82d4ff0SYann Gautier  * @brief  Transmits in master mode an amount of data in blocking mode.
680d82d4ff0SYann Gautier  * @param  hi2c: Pointer to a struct i2c_handle_s structure that contains
681d82d4ff0SYann Gautier  *               the configuration information for the specified I2C.
682d82d4ff0SYann Gautier  * @param  dev_addr: Target device address
683d82d4ff0SYann Gautier  * @param  p_data: Pointer to data buffer
684d82d4ff0SYann Gautier  * @param  size: Amount of data to be sent
685d82d4ff0SYann Gautier  * @param  timeout_ms: Timeout duration in milliseconds
686d82d4ff0SYann Gautier  * @retval 0 if OK, negative value else
687d82d4ff0SYann Gautier  */
688d82d4ff0SYann Gautier int stm32_i2c_master_transmit(struct i2c_handle_s *hi2c, uint16_t dev_addr,
689d82d4ff0SYann Gautier 			      uint8_t *p_data, uint16_t size,
690d82d4ff0SYann Gautier 			      uint32_t timeout_ms)
691d82d4ff0SYann Gautier {
692d82d4ff0SYann Gautier 	return i2c_write(hi2c, dev_addr, 0, 0,
693d82d4ff0SYann Gautier 			 p_data, size, timeout_ms, I2C_MODE_MASTER);
694d82d4ff0SYann Gautier }
695d82d4ff0SYann Gautier 
696d82d4ff0SYann Gautier /*
697d82d4ff0SYann Gautier  * @brief  Generic function to read an amount of data in blocking mode
698d82d4ff0SYann Gautier  *         (for Memory Mode and Master Mode)
699d82d4ff0SYann Gautier  * @param  hi2c: Pointer to a struct i2c_handle_s structure that contains
700d82d4ff0SYann Gautier  *               the configuration information for the specified I2C.
701d82d4ff0SYann Gautier  * @param  dev_addr: Target device address
702d82d4ff0SYann Gautier  * @param  mem_addr: Internal memory address (if Memory Mode)
703d82d4ff0SYann Gautier  * @param  mem_add_size: Size of internal memory address (if Memory Mode)
704d82d4ff0SYann Gautier  * @param  p_data: Pointer to data buffer
705d82d4ff0SYann Gautier  * @param  size: Amount of data to be sent
706d82d4ff0SYann Gautier  * @param  timeout_ms: Timeout duration in milliseconds
707d82d4ff0SYann Gautier  * @param  mode: Communication mode
708d82d4ff0SYann Gautier  * @retval 0 if OK, negative value else
709d82d4ff0SYann Gautier  */
710d82d4ff0SYann Gautier static int i2c_read(struct i2c_handle_s *hi2c, uint16_t dev_addr,
711d82d4ff0SYann Gautier 		    uint16_t mem_addr, uint16_t mem_add_size,
712d82d4ff0SYann Gautier 		    uint8_t *p_data, uint16_t size, uint32_t timeout_ms,
713d82d4ff0SYann Gautier 		    enum i2c_mode_e mode)
714d82d4ff0SYann Gautier {
715d82d4ff0SYann Gautier 	uint64_t timeout_ref;
716d82d4ff0SYann Gautier 	int rc = -EIO;
717d82d4ff0SYann Gautier 	uint8_t *p_buff = p_data;
718d82d4ff0SYann Gautier 	uint32_t xfer_count = size;
719d82d4ff0SYann Gautier 	uint32_t xfer_size;
720d82d4ff0SYann Gautier 
721d82d4ff0SYann Gautier 	if ((mode != I2C_MODE_MASTER) && (mode != I2C_MODE_MEM)) {
722d82d4ff0SYann Gautier 		return -1;
723d82d4ff0SYann Gautier 	}
724d82d4ff0SYann Gautier 
725d82d4ff0SYann Gautier 	if ((hi2c->i2c_state != I2C_STATE_READY) || (hi2c->lock != 0U)) {
726d82d4ff0SYann Gautier 		return -EBUSY;
727d82d4ff0SYann Gautier 	}
728d82d4ff0SYann Gautier 
729d82d4ff0SYann Gautier 	if ((p_data == NULL) || (size == 0U)) {
730d82d4ff0SYann Gautier 		return  -EINVAL;
731d82d4ff0SYann Gautier 	}
732d82d4ff0SYann Gautier 
733*33667d29SYann Gautier 	clk_enable(hi2c->clock);
734d82d4ff0SYann Gautier 
735d82d4ff0SYann Gautier 	hi2c->lock = 1;
736d82d4ff0SYann Gautier 
737d82d4ff0SYann Gautier 	timeout_ref = timeout_init_us(I2C_TIMEOUT_BUSY_MS * 1000);
738d82d4ff0SYann Gautier 	if (i2c_wait_flag(hi2c, I2C_FLAG_BUSY, 1, timeout_ref) != 0) {
739d82d4ff0SYann Gautier 		goto bail;
740d82d4ff0SYann Gautier 	}
741d82d4ff0SYann Gautier 
742d82d4ff0SYann Gautier 	hi2c->i2c_state = I2C_STATE_BUSY_RX;
743d82d4ff0SYann Gautier 	hi2c->i2c_mode = mode;
744d82d4ff0SYann Gautier 	hi2c->i2c_err = I2C_ERROR_NONE;
745d82d4ff0SYann Gautier 
746d82d4ff0SYann Gautier 	if (mode == I2C_MODE_MEM) {
747d82d4ff0SYann Gautier 		/* Send Memory Address */
748d82d4ff0SYann Gautier 		if (i2c_request_memory_read(hi2c, dev_addr, mem_addr,
749d82d4ff0SYann Gautier 					    mem_add_size, timeout_ref) != 0) {
750d82d4ff0SYann Gautier 			goto bail;
751d82d4ff0SYann Gautier 		}
752d82d4ff0SYann Gautier 	}
753d82d4ff0SYann Gautier 
754d82d4ff0SYann Gautier 	/*
755d82d4ff0SYann Gautier 	 * Send Slave Address.
756d82d4ff0SYann Gautier 	 * Set NBYTES to write and reload if xfer_count > MAX_NBYTE_SIZE
757d82d4ff0SYann Gautier 	 * and generate RESTART.
758d82d4ff0SYann Gautier 	 */
759d82d4ff0SYann Gautier 	if (xfer_count > MAX_NBYTE_SIZE) {
760d82d4ff0SYann Gautier 		xfer_size = MAX_NBYTE_SIZE;
761d82d4ff0SYann Gautier 		i2c_transfer_config(hi2c, dev_addr, xfer_size,
762d82d4ff0SYann Gautier 				    I2C_RELOAD_MODE, I2C_GENERATE_START_READ);
763d82d4ff0SYann Gautier 	} else {
764d82d4ff0SYann Gautier 		xfer_size = xfer_count;
765d82d4ff0SYann Gautier 		i2c_transfer_config(hi2c, dev_addr, xfer_size,
766d82d4ff0SYann Gautier 				    I2C_AUTOEND_MODE, I2C_GENERATE_START_READ);
767d82d4ff0SYann Gautier 	}
768d82d4ff0SYann Gautier 
769d82d4ff0SYann Gautier 	do {
770d82d4ff0SYann Gautier 		if (i2c_wait_flag(hi2c, I2C_FLAG_RXNE, 0, timeout_ref) != 0) {
771d82d4ff0SYann Gautier 			goto bail;
772d82d4ff0SYann Gautier 		}
773d82d4ff0SYann Gautier 
774d82d4ff0SYann Gautier 		*p_buff = mmio_read_8(hi2c->i2c_base_addr + I2C_RXDR);
775d82d4ff0SYann Gautier 		p_buff++;
776d82d4ff0SYann Gautier 		xfer_size--;
777d82d4ff0SYann Gautier 		xfer_count--;
778d82d4ff0SYann Gautier 
779d82d4ff0SYann Gautier 		if ((xfer_count != 0U) && (xfer_size == 0U)) {
780d82d4ff0SYann Gautier 			if (i2c_wait_flag(hi2c, I2C_FLAG_TCR, 0,
781d82d4ff0SYann Gautier 					  timeout_ref) != 0) {
782d82d4ff0SYann Gautier 				goto bail;
783d82d4ff0SYann Gautier 			}
784d82d4ff0SYann Gautier 
785d82d4ff0SYann Gautier 			if (xfer_count > MAX_NBYTE_SIZE) {
786d82d4ff0SYann Gautier 				xfer_size = MAX_NBYTE_SIZE;
787d82d4ff0SYann Gautier 				i2c_transfer_config(hi2c, dev_addr,
788d82d4ff0SYann Gautier 						    xfer_size,
789d82d4ff0SYann Gautier 						    I2C_RELOAD_MODE,
790d82d4ff0SYann Gautier 						    I2C_NO_STARTSTOP);
791d82d4ff0SYann Gautier 			} else {
792d82d4ff0SYann Gautier 				xfer_size = xfer_count;
793d82d4ff0SYann Gautier 				i2c_transfer_config(hi2c, dev_addr,
794d82d4ff0SYann Gautier 						    xfer_size,
795d82d4ff0SYann Gautier 						    I2C_AUTOEND_MODE,
796d82d4ff0SYann Gautier 						    I2C_NO_STARTSTOP);
797d82d4ff0SYann Gautier 			}
798d82d4ff0SYann Gautier 		}
799d82d4ff0SYann Gautier 	} while (xfer_count > 0U);
800d82d4ff0SYann Gautier 
801d82d4ff0SYann Gautier 	/*
802d82d4ff0SYann Gautier 	 * No need to Check TC flag, with AUTOEND mode the stop
803d82d4ff0SYann Gautier 	 * is automatically generated.
804d82d4ff0SYann Gautier 	 * Wait until STOPF flag is reset.
805d82d4ff0SYann Gautier 	 */
806d82d4ff0SYann Gautier 	if (i2c_wait_stop(hi2c, timeout_ref) != 0) {
807d82d4ff0SYann Gautier 		goto bail;
808d82d4ff0SYann Gautier 	}
809d82d4ff0SYann Gautier 
810d82d4ff0SYann Gautier 	mmio_write_32(hi2c->i2c_base_addr + I2C_ICR, I2C_FLAG_STOPF);
811d82d4ff0SYann Gautier 
812d82d4ff0SYann Gautier 	mmio_clrbits_32(hi2c->i2c_base_addr + I2C_CR2, I2C_RESET_CR2);
813d82d4ff0SYann Gautier 
814d82d4ff0SYann Gautier 	hi2c->i2c_state = I2C_STATE_READY;
815d82d4ff0SYann Gautier 	hi2c->i2c_mode = I2C_MODE_NONE;
816d82d4ff0SYann Gautier 
817d82d4ff0SYann Gautier 	rc = 0;
818d82d4ff0SYann Gautier 
819d82d4ff0SYann Gautier bail:
820d82d4ff0SYann Gautier 	hi2c->lock = 0;
821*33667d29SYann Gautier 	clk_disable(hi2c->clock);
822d82d4ff0SYann Gautier 
823d82d4ff0SYann Gautier 	return rc;
824d82d4ff0SYann Gautier }
825d82d4ff0SYann Gautier 
826d82d4ff0SYann Gautier /*
827d82d4ff0SYann Gautier  * @brief  Read an amount of data in blocking mode from a specific memory
828d82d4ff0SYann Gautier  *	   address.
829d82d4ff0SYann Gautier  * @param  hi2c: Pointer to a struct i2c_handle_s structure that contains
830d82d4ff0SYann Gautier  *               the configuration information for the specified I2C.
831d82d4ff0SYann Gautier  * @param  dev_addr: Target device address
832d82d4ff0SYann Gautier  * @param  mem_addr: Internal memory address
833d82d4ff0SYann Gautier  * @param  mem_add_size: Size of internal memory address
834d82d4ff0SYann Gautier  * @param  p_data: Pointer to data buffer
835d82d4ff0SYann Gautier  * @param  size: Amount of data to be sent
836d82d4ff0SYann Gautier  * @param  timeout_ms: Timeout duration in milliseconds
837d82d4ff0SYann Gautier  * @retval 0 if OK, negative value else
838d82d4ff0SYann Gautier  */
839d82d4ff0SYann Gautier int stm32_i2c_mem_read(struct i2c_handle_s *hi2c, uint16_t dev_addr,
840d82d4ff0SYann Gautier 		       uint16_t mem_addr, uint16_t mem_add_size,
841d82d4ff0SYann Gautier 		       uint8_t *p_data, uint16_t size, uint32_t timeout_ms)
842d82d4ff0SYann Gautier {
843d82d4ff0SYann Gautier 	return i2c_read(hi2c, dev_addr, mem_addr, mem_add_size,
844d82d4ff0SYann Gautier 			p_data, size, timeout_ms, I2C_MODE_MEM);
845d82d4ff0SYann Gautier }
846d82d4ff0SYann Gautier 
847d82d4ff0SYann Gautier /*
848d82d4ff0SYann Gautier  * @brief  Receives in master mode an amount of data in blocking mode.
849d82d4ff0SYann Gautier  * @param  hi2c: Pointer to a struct i2c_handle_s structure that contains
850d82d4ff0SYann Gautier  *               the configuration information for the specified I2C.
851d82d4ff0SYann Gautier  * @param  dev_addr: Target device address
852d82d4ff0SYann Gautier  * @param  p_data: Pointer to data buffer
853d82d4ff0SYann Gautier  * @param  size: Amount of data to be sent
854d82d4ff0SYann Gautier  * @param  timeout_ms: Timeout duration in milliseconds
855d82d4ff0SYann Gautier  * @retval 0 if OK, negative value else
856d82d4ff0SYann Gautier  */
857d82d4ff0SYann Gautier int stm32_i2c_master_receive(struct i2c_handle_s *hi2c, uint16_t dev_addr,
858d82d4ff0SYann Gautier 			     uint8_t *p_data, uint16_t size,
859d82d4ff0SYann Gautier 			     uint32_t timeout_ms)
860d82d4ff0SYann Gautier {
861d82d4ff0SYann Gautier 	return i2c_read(hi2c, dev_addr, 0, 0,
862d82d4ff0SYann Gautier 			p_data, size, timeout_ms, I2C_MODE_MASTER);
863d82d4ff0SYann Gautier }
864d82d4ff0SYann Gautier 
865d82d4ff0SYann Gautier /*
866d82d4ff0SYann Gautier  * @brief  Checks if target device is ready for communication.
867d82d4ff0SYann Gautier  * @note   This function is used with Memory devices
868d82d4ff0SYann Gautier  * @param  hi2c: Pointer to a struct i2c_handle_s structure that contains
869d82d4ff0SYann Gautier  *               the configuration information for the specified I2C.
870d82d4ff0SYann Gautier  * @param  dev_addr: Target device address
871d82d4ff0SYann Gautier  * @param  trials: Number of trials
872d82d4ff0SYann Gautier  * @param  timeout_ms: Timeout duration in milliseconds
873d82d4ff0SYann Gautier  * @retval True if device is ready, false else
874d82d4ff0SYann Gautier  */
875d82d4ff0SYann Gautier bool stm32_i2c_is_device_ready(struct i2c_handle_s *hi2c,
876d82d4ff0SYann Gautier 			       uint16_t dev_addr, uint32_t trials,
877d82d4ff0SYann Gautier 			       uint32_t timeout_ms)
878d82d4ff0SYann Gautier {
879d82d4ff0SYann Gautier 	uint32_t i2c_trials = 0U;
880d82d4ff0SYann Gautier 	bool rc = false;
881d82d4ff0SYann Gautier 
882d82d4ff0SYann Gautier 	if ((hi2c->i2c_state != I2C_STATE_READY) || (hi2c->lock != 0U)) {
883d82d4ff0SYann Gautier 		return rc;
884d82d4ff0SYann Gautier 	}
885d82d4ff0SYann Gautier 
886*33667d29SYann Gautier 	clk_enable(hi2c->clock);
887d82d4ff0SYann Gautier 
888d82d4ff0SYann Gautier 	hi2c->lock = 1;
889d82d4ff0SYann Gautier 	hi2c->i2c_mode = I2C_MODE_NONE;
890d82d4ff0SYann Gautier 
891d82d4ff0SYann Gautier 	if ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) & I2C_FLAG_BUSY) !=
892d82d4ff0SYann Gautier 	    0U) {
893d82d4ff0SYann Gautier 		goto bail;
894d82d4ff0SYann Gautier 	}
895d82d4ff0SYann Gautier 
896435832abSYann Gautier 	hi2c->i2c_state = I2C_STATE_BUSY;
897d82d4ff0SYann Gautier 	hi2c->i2c_err = I2C_ERROR_NONE;
898435832abSYann Gautier 
899d82d4ff0SYann Gautier 	do {
900d82d4ff0SYann Gautier 		uint64_t timeout_ref;
901435832abSYann Gautier 
902d82d4ff0SYann Gautier 		/* Generate Start */
903d82d4ff0SYann Gautier 		if ((mmio_read_32(hi2c->i2c_base_addr + I2C_OAR1) &
904d82d4ff0SYann Gautier 		     I2C_OAR1_OA1MODE) == 0) {
905d82d4ff0SYann Gautier 			mmio_write_32(hi2c->i2c_base_addr + I2C_CR2,
906d82d4ff0SYann Gautier 				      (((uint32_t)dev_addr & I2C_CR2_SADD) |
907d82d4ff0SYann Gautier 				       I2C_CR2_START | I2C_CR2_AUTOEND) &
908d82d4ff0SYann Gautier 				      ~I2C_CR2_RD_WRN);
909d82d4ff0SYann Gautier 		} else {
910d82d4ff0SYann Gautier 			mmio_write_32(hi2c->i2c_base_addr + I2C_CR2,
911d82d4ff0SYann Gautier 				      (((uint32_t)dev_addr & I2C_CR2_SADD) |
912d82d4ff0SYann Gautier 				       I2C_CR2_START | I2C_CR2_ADD10) &
913d82d4ff0SYann Gautier 				      ~I2C_CR2_RD_WRN);
914d82d4ff0SYann Gautier 		}
915435832abSYann Gautier 
916d82d4ff0SYann Gautier 		/*
917d82d4ff0SYann Gautier 		 * No need to Check TC flag, with AUTOEND mode the stop
918d82d4ff0SYann Gautier 		 * is automatically generated.
919d82d4ff0SYann Gautier 		 * Wait until STOPF flag is set or a NACK flag is set.
920d82d4ff0SYann Gautier 		 */
921d82d4ff0SYann Gautier 		timeout_ref = timeout_init_us(timeout_ms * 1000);
922d82d4ff0SYann Gautier 		do {
923d82d4ff0SYann Gautier 			if ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) &
924d82d4ff0SYann Gautier 			     (I2C_FLAG_STOPF | I2C_FLAG_AF)) != 0U) {
925d82d4ff0SYann Gautier 				break;
926d82d4ff0SYann Gautier 			}
927435832abSYann Gautier 
928d82d4ff0SYann Gautier 			if (timeout_elapsed(timeout_ref)) {
929d82d4ff0SYann Gautier 				notif_i2c_timeout(hi2c);
930d82d4ff0SYann Gautier 				goto bail;
931d82d4ff0SYann Gautier 			}
932d82d4ff0SYann Gautier 		} while (true);
933d82d4ff0SYann Gautier 
934d82d4ff0SYann Gautier 		if ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) &
935d82d4ff0SYann Gautier 		     I2C_FLAG_AF) == 0U) {
936d82d4ff0SYann Gautier 			if (i2c_wait_flag(hi2c, I2C_FLAG_STOPF, 0,
937d82d4ff0SYann Gautier 					  timeout_ref) != 0) {
938d82d4ff0SYann Gautier 				goto bail;
939d82d4ff0SYann Gautier 			}
940d82d4ff0SYann Gautier 
941d82d4ff0SYann Gautier 			mmio_write_32(hi2c->i2c_base_addr + I2C_ICR,
942d82d4ff0SYann Gautier 				      I2C_FLAG_STOPF);
943435832abSYann Gautier 
944435832abSYann Gautier 			hi2c->i2c_state = I2C_STATE_READY;
945435832abSYann Gautier 
946d82d4ff0SYann Gautier 			rc = true;
947d82d4ff0SYann Gautier 			goto bail;
948435832abSYann Gautier 		}
949d82d4ff0SYann Gautier 
950d82d4ff0SYann Gautier 		if (i2c_wait_flag(hi2c, I2C_FLAG_STOPF, 0, timeout_ref) != 0) {
951d82d4ff0SYann Gautier 			goto bail;
952d82d4ff0SYann Gautier 		}
953d82d4ff0SYann Gautier 
954d82d4ff0SYann Gautier 		mmio_write_32(hi2c->i2c_base_addr + I2C_ICR, I2C_FLAG_AF);
955d82d4ff0SYann Gautier 
956d82d4ff0SYann Gautier 		mmio_write_32(hi2c->i2c_base_addr + I2C_ICR, I2C_FLAG_STOPF);
957d82d4ff0SYann Gautier 
958d82d4ff0SYann Gautier 		if (i2c_trials == trials) {
959d82d4ff0SYann Gautier 			mmio_setbits_32(hi2c->i2c_base_addr + I2C_CR2,
960d82d4ff0SYann Gautier 					I2C_CR2_STOP);
961d82d4ff0SYann Gautier 
962d82d4ff0SYann Gautier 			if (i2c_wait_flag(hi2c, I2C_FLAG_STOPF, 0,
963d82d4ff0SYann Gautier 					  timeout_ref) != 0) {
964d82d4ff0SYann Gautier 				goto bail;
965d82d4ff0SYann Gautier 			}
966d82d4ff0SYann Gautier 
967d82d4ff0SYann Gautier 			mmio_write_32(hi2c->i2c_base_addr + I2C_ICR,
968d82d4ff0SYann Gautier 				      I2C_FLAG_STOPF);
969d82d4ff0SYann Gautier 		}
970d82d4ff0SYann Gautier 
971d82d4ff0SYann Gautier 		i2c_trials++;
972d82d4ff0SYann Gautier 	} while (i2c_trials < trials);
973d82d4ff0SYann Gautier 
974d82d4ff0SYann Gautier 	notif_i2c_timeout(hi2c);
975d82d4ff0SYann Gautier 
976d82d4ff0SYann Gautier bail:
977d82d4ff0SYann Gautier 	hi2c->lock = 0;
978*33667d29SYann Gautier 	clk_disable(hi2c->clock);
979d82d4ff0SYann Gautier 
980d82d4ff0SYann Gautier 	return rc;
981d82d4ff0SYann Gautier }
982d82d4ff0SYann Gautier 
983