xref: /arm-trusted-firmware/drivers/st/i2c/stm32_i2c.c (revision 91f16700b400a8c0651d24a598fc48ee2997a0d7)
1*91f16700Schasinglulu /*
2*91f16700Schasinglulu  * Copyright (c) 2016-2021, STMicroelectronics - All Rights Reserved
3*91f16700Schasinglulu  *
4*91f16700Schasinglulu  * SPDX-License-Identifier: BSD-3-Clause
5*91f16700Schasinglulu  */
6*91f16700Schasinglulu 
7*91f16700Schasinglulu #include <errno.h>
8*91f16700Schasinglulu #include <stdbool.h>
9*91f16700Schasinglulu #include <stdlib.h>
10*91f16700Schasinglulu 
11*91f16700Schasinglulu #include <libfdt.h>
12*91f16700Schasinglulu 
13*91f16700Schasinglulu #include <platform_def.h>
14*91f16700Schasinglulu 
15*91f16700Schasinglulu #include <common/debug.h>
16*91f16700Schasinglulu #include <drivers/clk.h>
17*91f16700Schasinglulu #include <drivers/delay_timer.h>
18*91f16700Schasinglulu #include <drivers/st/stm32_gpio.h>
19*91f16700Schasinglulu #include <drivers/st/stm32_i2c.h>
20*91f16700Schasinglulu #include <lib/mmio.h>
21*91f16700Schasinglulu #include <lib/utils.h>
22*91f16700Schasinglulu 
23*91f16700Schasinglulu /* STM32 I2C registers offsets */
24*91f16700Schasinglulu #define I2C_CR1			0x00U
25*91f16700Schasinglulu #define I2C_CR2			0x04U
26*91f16700Schasinglulu #define I2C_OAR1		0x08U
27*91f16700Schasinglulu #define I2C_OAR2		0x0CU
28*91f16700Schasinglulu #define I2C_TIMINGR		0x10U
29*91f16700Schasinglulu #define I2C_TIMEOUTR		0x14U
30*91f16700Schasinglulu #define I2C_ISR			0x18U
31*91f16700Schasinglulu #define I2C_ICR			0x1CU
32*91f16700Schasinglulu #define I2C_PECR		0x20U
33*91f16700Schasinglulu #define I2C_RXDR		0x24U
34*91f16700Schasinglulu #define I2C_TXDR		0x28U
35*91f16700Schasinglulu 
36*91f16700Schasinglulu #define TIMINGR_CLEAR_MASK	0xF0FFFFFFU
37*91f16700Schasinglulu 
38*91f16700Schasinglulu #define MAX_NBYTE_SIZE		255U
39*91f16700Schasinglulu 
40*91f16700Schasinglulu #define I2C_NSEC_PER_SEC	1000000000L
41*91f16700Schasinglulu 
42*91f16700Schasinglulu /* I2C Timing hard-coded value, for I2C clock source is HSI at 64MHz */
43*91f16700Schasinglulu #define I2C_TIMING			0x10D07DB5
44*91f16700Schasinglulu 
45*91f16700Schasinglulu static void notif_i2c_timeout(struct i2c_handle_s *hi2c)
46*91f16700Schasinglulu {
47*91f16700Schasinglulu 	hi2c->i2c_err |= I2C_ERROR_TIMEOUT;
48*91f16700Schasinglulu 	hi2c->i2c_mode = I2C_MODE_NONE;
49*91f16700Schasinglulu 	hi2c->i2c_state = I2C_STATE_READY;
50*91f16700Schasinglulu }
51*91f16700Schasinglulu 
52*91f16700Schasinglulu /*
53*91f16700Schasinglulu  * @brief  Configure I2C Analog noise filter.
54*91f16700Schasinglulu  * @param  hi2c: Pointer to a struct i2c_handle_s structure that contains
55*91f16700Schasinglulu  *               the configuration information for the specified I2C peripheral.
56*91f16700Schasinglulu  * @param  analog_filter: New state of the Analog filter
57*91f16700Schasinglulu  * @retval 0 if OK, negative value else
58*91f16700Schasinglulu  */
59*91f16700Schasinglulu static int i2c_config_analog_filter(struct i2c_handle_s *hi2c,
60*91f16700Schasinglulu 				    uint32_t analog_filter)
61*91f16700Schasinglulu {
62*91f16700Schasinglulu 	if ((hi2c->i2c_state != I2C_STATE_READY) || (hi2c->lock != 0U)) {
63*91f16700Schasinglulu 		return -EBUSY;
64*91f16700Schasinglulu 	}
65*91f16700Schasinglulu 
66*91f16700Schasinglulu 	hi2c->lock = 1;
67*91f16700Schasinglulu 
68*91f16700Schasinglulu 	hi2c->i2c_state = I2C_STATE_BUSY;
69*91f16700Schasinglulu 
70*91f16700Schasinglulu 	/* Disable the selected I2C peripheral */
71*91f16700Schasinglulu 	mmio_clrbits_32(hi2c->i2c_base_addr + I2C_CR1, I2C_CR1_PE);
72*91f16700Schasinglulu 
73*91f16700Schasinglulu 	/* Reset I2Cx ANOFF bit */
74*91f16700Schasinglulu 	mmio_clrbits_32(hi2c->i2c_base_addr + I2C_CR1, I2C_CR1_ANFOFF);
75*91f16700Schasinglulu 
76*91f16700Schasinglulu 	/* Set analog filter bit*/
77*91f16700Schasinglulu 	mmio_setbits_32(hi2c->i2c_base_addr + I2C_CR1, analog_filter);
78*91f16700Schasinglulu 
79*91f16700Schasinglulu 	/* Enable the selected I2C peripheral */
80*91f16700Schasinglulu 	mmio_setbits_32(hi2c->i2c_base_addr + I2C_CR1, I2C_CR1_PE);
81*91f16700Schasinglulu 
82*91f16700Schasinglulu 	hi2c->i2c_state = I2C_STATE_READY;
83*91f16700Schasinglulu 
84*91f16700Schasinglulu 	hi2c->lock = 0;
85*91f16700Schasinglulu 
86*91f16700Schasinglulu 	return 0;
87*91f16700Schasinglulu }
88*91f16700Schasinglulu 
89*91f16700Schasinglulu /*
90*91f16700Schasinglulu  * @brief  Get I2C setup information from the device tree and set pinctrl
91*91f16700Schasinglulu  *         configuration.
92*91f16700Schasinglulu  * @param  fdt: Pointer to the device tree
93*91f16700Schasinglulu  * @param  node: I2C node offset
94*91f16700Schasinglulu  * @param  init: Ref to the initialization configuration structure
95*91f16700Schasinglulu  * @retval 0 if OK, negative value else
96*91f16700Schasinglulu  */
97*91f16700Schasinglulu int stm32_i2c_get_setup_from_fdt(void *fdt, int node,
98*91f16700Schasinglulu 				 struct stm32_i2c_init_s *init)
99*91f16700Schasinglulu {
100*91f16700Schasinglulu 	const fdt32_t *cuint;
101*91f16700Schasinglulu 
102*91f16700Schasinglulu 	cuint = fdt_getprop(fdt, node, "i2c-scl-rising-time-ns", NULL);
103*91f16700Schasinglulu 	if (cuint == NULL) {
104*91f16700Schasinglulu 		init->rise_time = STM32_I2C_RISE_TIME_DEFAULT;
105*91f16700Schasinglulu 	} else {
106*91f16700Schasinglulu 		init->rise_time = fdt32_to_cpu(*cuint);
107*91f16700Schasinglulu 	}
108*91f16700Schasinglulu 
109*91f16700Schasinglulu 	cuint = fdt_getprop(fdt, node, "i2c-scl-falling-time-ns", NULL);
110*91f16700Schasinglulu 	if (cuint == NULL) {
111*91f16700Schasinglulu 		init->fall_time = STM32_I2C_FALL_TIME_DEFAULT;
112*91f16700Schasinglulu 	} else {
113*91f16700Schasinglulu 		init->fall_time = fdt32_to_cpu(*cuint);
114*91f16700Schasinglulu 	}
115*91f16700Schasinglulu 
116*91f16700Schasinglulu 	cuint = fdt_getprop(fdt, node, "clock-frequency", NULL);
117*91f16700Schasinglulu 	if (cuint == NULL) {
118*91f16700Schasinglulu 		init->speed_mode = STM32_I2C_SPEED_DEFAULT;
119*91f16700Schasinglulu 	} else {
120*91f16700Schasinglulu 		switch (fdt32_to_cpu(*cuint)) {
121*91f16700Schasinglulu 		case STANDARD_RATE:
122*91f16700Schasinglulu 			init->speed_mode = I2C_SPEED_STANDARD;
123*91f16700Schasinglulu 			break;
124*91f16700Schasinglulu 		case FAST_RATE:
125*91f16700Schasinglulu 			init->speed_mode = I2C_SPEED_FAST;
126*91f16700Schasinglulu 			break;
127*91f16700Schasinglulu 		case FAST_PLUS_RATE:
128*91f16700Schasinglulu 			init->speed_mode = I2C_SPEED_FAST_PLUS;
129*91f16700Schasinglulu 			break;
130*91f16700Schasinglulu 		default:
131*91f16700Schasinglulu 			init->speed_mode = STM32_I2C_SPEED_DEFAULT;
132*91f16700Schasinglulu 			break;
133*91f16700Schasinglulu 		}
134*91f16700Schasinglulu 	}
135*91f16700Schasinglulu 
136*91f16700Schasinglulu 	return dt_set_pinctrl_config(node);
137*91f16700Schasinglulu }
138*91f16700Schasinglulu 
139*91f16700Schasinglulu /*
140*91f16700Schasinglulu  * @brief  Initialize the I2C device.
141*91f16700Schasinglulu  * @param  hi2c: Pointer to a struct i2c_handle_s structure that contains
142*91f16700Schasinglulu  *               the configuration information for the specified I2C.
143*91f16700Schasinglulu  * @param  init_data: Initialization configuration structure
144*91f16700Schasinglulu  * @retval 0 if OK, negative value else
145*91f16700Schasinglulu  */
146*91f16700Schasinglulu int stm32_i2c_init(struct i2c_handle_s *hi2c,
147*91f16700Schasinglulu 		   struct stm32_i2c_init_s *init_data)
148*91f16700Schasinglulu {
149*91f16700Schasinglulu 	int rc = 0;
150*91f16700Schasinglulu 	uint32_t timing = I2C_TIMING;
151*91f16700Schasinglulu 
152*91f16700Schasinglulu 	if (hi2c == NULL) {
153*91f16700Schasinglulu 		return -ENOENT;
154*91f16700Schasinglulu 	}
155*91f16700Schasinglulu 
156*91f16700Schasinglulu 	if (hi2c->i2c_state == I2C_STATE_RESET) {
157*91f16700Schasinglulu 		hi2c->lock = 0;
158*91f16700Schasinglulu 	}
159*91f16700Schasinglulu 
160*91f16700Schasinglulu 	hi2c->i2c_state = I2C_STATE_BUSY;
161*91f16700Schasinglulu 
162*91f16700Schasinglulu 	clk_enable(hi2c->clock);
163*91f16700Schasinglulu 
164*91f16700Schasinglulu 	/* Disable the selected I2C peripheral */
165*91f16700Schasinglulu 	mmio_clrbits_32(hi2c->i2c_base_addr + I2C_CR1, I2C_CR1_PE);
166*91f16700Schasinglulu 
167*91f16700Schasinglulu 	/* Configure I2Cx: Frequency range */
168*91f16700Schasinglulu 	mmio_write_32(hi2c->i2c_base_addr + I2C_TIMINGR,
169*91f16700Schasinglulu 		      timing & TIMINGR_CLEAR_MASK);
170*91f16700Schasinglulu 
171*91f16700Schasinglulu 	/* Disable Own Address1 before set the Own Address1 configuration */
172*91f16700Schasinglulu 	mmio_clrbits_32(hi2c->i2c_base_addr + I2C_OAR1, I2C_OAR1_OA1EN);
173*91f16700Schasinglulu 
174*91f16700Schasinglulu 	/* Configure I2Cx: Own Address1 and ack own address1 mode */
175*91f16700Schasinglulu 	if (init_data->addressing_mode == I2C_ADDRESSINGMODE_7BIT) {
176*91f16700Schasinglulu 		mmio_write_32(hi2c->i2c_base_addr + I2C_OAR1,
177*91f16700Schasinglulu 			      I2C_OAR1_OA1EN | init_data->own_address1);
178*91f16700Schasinglulu 	} else { /* I2C_ADDRESSINGMODE_10BIT */
179*91f16700Schasinglulu 		mmio_write_32(hi2c->i2c_base_addr + I2C_OAR1,
180*91f16700Schasinglulu 			      I2C_OAR1_OA1EN | I2C_OAR1_OA1MODE |
181*91f16700Schasinglulu 			      init_data->own_address1);
182*91f16700Schasinglulu 	}
183*91f16700Schasinglulu 
184*91f16700Schasinglulu 	mmio_write_32(hi2c->i2c_base_addr + I2C_CR2, 0);
185*91f16700Schasinglulu 
186*91f16700Schasinglulu 	/* Configure I2Cx: Addressing Master mode */
187*91f16700Schasinglulu 	if (init_data->addressing_mode == I2C_ADDRESSINGMODE_10BIT) {
188*91f16700Schasinglulu 		mmio_setbits_32(hi2c->i2c_base_addr + I2C_CR2, I2C_CR2_ADD10);
189*91f16700Schasinglulu 	}
190*91f16700Schasinglulu 
191*91f16700Schasinglulu 	/*
192*91f16700Schasinglulu 	 * Enable the AUTOEND by default, and enable NACK
193*91f16700Schasinglulu 	 * (should be disabled only during Slave process).
194*91f16700Schasinglulu 	 */
195*91f16700Schasinglulu 	mmio_setbits_32(hi2c->i2c_base_addr + I2C_CR2,
196*91f16700Schasinglulu 			I2C_CR2_AUTOEND | I2C_CR2_NACK);
197*91f16700Schasinglulu 
198*91f16700Schasinglulu 	/* Disable Own Address2 before set the Own Address2 configuration */
199*91f16700Schasinglulu 	mmio_clrbits_32(hi2c->i2c_base_addr + I2C_OAR2, I2C_DUALADDRESS_ENABLE);
200*91f16700Schasinglulu 
201*91f16700Schasinglulu 	/* Configure I2Cx: Dual mode and Own Address2 */
202*91f16700Schasinglulu 	mmio_write_32(hi2c->i2c_base_addr + I2C_OAR2,
203*91f16700Schasinglulu 		      init_data->dual_address_mode |
204*91f16700Schasinglulu 		      init_data->own_address2 |
205*91f16700Schasinglulu 		      (init_data->own_address2_masks << 8));
206*91f16700Schasinglulu 
207*91f16700Schasinglulu 	/* Configure I2Cx: Generalcall and NoStretch mode */
208*91f16700Schasinglulu 	mmio_write_32(hi2c->i2c_base_addr + I2C_CR1,
209*91f16700Schasinglulu 		      init_data->general_call_mode |
210*91f16700Schasinglulu 		      init_data->no_stretch_mode);
211*91f16700Schasinglulu 
212*91f16700Schasinglulu 	/* Enable the selected I2C peripheral */
213*91f16700Schasinglulu 	mmio_setbits_32(hi2c->i2c_base_addr + I2C_CR1, I2C_CR1_PE);
214*91f16700Schasinglulu 
215*91f16700Schasinglulu 	hi2c->i2c_err = I2C_ERROR_NONE;
216*91f16700Schasinglulu 	hi2c->i2c_state = I2C_STATE_READY;
217*91f16700Schasinglulu 	hi2c->i2c_mode = I2C_MODE_NONE;
218*91f16700Schasinglulu 
219*91f16700Schasinglulu 	rc = i2c_config_analog_filter(hi2c, init_data->analog_filter ?
220*91f16700Schasinglulu 						I2C_ANALOGFILTER_ENABLE :
221*91f16700Schasinglulu 						I2C_ANALOGFILTER_DISABLE);
222*91f16700Schasinglulu 	if (rc != 0) {
223*91f16700Schasinglulu 		ERROR("Cannot initialize I2C analog filter (%d)\n", rc);
224*91f16700Schasinglulu 		clk_disable(hi2c->clock);
225*91f16700Schasinglulu 		return rc;
226*91f16700Schasinglulu 	}
227*91f16700Schasinglulu 
228*91f16700Schasinglulu 	clk_disable(hi2c->clock);
229*91f16700Schasinglulu 
230*91f16700Schasinglulu 	return rc;
231*91f16700Schasinglulu }
232*91f16700Schasinglulu 
233*91f16700Schasinglulu /*
234*91f16700Schasinglulu  * @brief  I2C Tx data register flush process.
235*91f16700Schasinglulu  * @param  hi2c: I2C handle
236*91f16700Schasinglulu  * @retval None
237*91f16700Schasinglulu  */
238*91f16700Schasinglulu static void i2c_flush_txdr(struct i2c_handle_s *hi2c)
239*91f16700Schasinglulu {
240*91f16700Schasinglulu 	/*
241*91f16700Schasinglulu 	 * If a pending TXIS flag is set,
242*91f16700Schasinglulu 	 * write a dummy data in TXDR to clear it.
243*91f16700Schasinglulu 	 */
244*91f16700Schasinglulu 	if ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) & I2C_FLAG_TXIS) !=
245*91f16700Schasinglulu 	    0U) {
246*91f16700Schasinglulu 		mmio_write_32(hi2c->i2c_base_addr + I2C_TXDR, 0);
247*91f16700Schasinglulu 	}
248*91f16700Schasinglulu 
249*91f16700Schasinglulu 	/* Flush TX register if not empty */
250*91f16700Schasinglulu 	if ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) & I2C_FLAG_TXE) ==
251*91f16700Schasinglulu 	    0U) {
252*91f16700Schasinglulu 		mmio_setbits_32(hi2c->i2c_base_addr + I2C_ISR,
253*91f16700Schasinglulu 				I2C_FLAG_TXE);
254*91f16700Schasinglulu 	}
255*91f16700Schasinglulu }
256*91f16700Schasinglulu 
257*91f16700Schasinglulu /*
258*91f16700Schasinglulu  * @brief  This function handles I2C Communication timeout.
259*91f16700Schasinglulu  * @param  hi2c: Pointer to a struct i2c_handle_s structure that contains
260*91f16700Schasinglulu  *               the configuration information for the specified I2C.
261*91f16700Schasinglulu  * @param  flag: Specifies the I2C flag to check
262*91f16700Schasinglulu  * @param  awaited_value: The awaited bit value for the flag (0 or 1)
263*91f16700Schasinglulu  * @param  timeout_ref: Reference to target timeout
264*91f16700Schasinglulu  * @retval 0 if OK, negative value else
265*91f16700Schasinglulu  */
266*91f16700Schasinglulu static int i2c_wait_flag(struct i2c_handle_s *hi2c, uint32_t flag,
267*91f16700Schasinglulu 			 uint8_t awaited_value, uint64_t timeout_ref)
268*91f16700Schasinglulu {
269*91f16700Schasinglulu 	for ( ; ; ) {
270*91f16700Schasinglulu 		uint32_t isr = mmio_read_32(hi2c->i2c_base_addr + I2C_ISR);
271*91f16700Schasinglulu 
272*91f16700Schasinglulu 		if (!!(isr & flag) != !!awaited_value) {
273*91f16700Schasinglulu 			return 0;
274*91f16700Schasinglulu 		}
275*91f16700Schasinglulu 
276*91f16700Schasinglulu 		if (timeout_elapsed(timeout_ref)) {
277*91f16700Schasinglulu 			notif_i2c_timeout(hi2c);
278*91f16700Schasinglulu 			hi2c->lock = 0;
279*91f16700Schasinglulu 
280*91f16700Schasinglulu 			return -EIO;
281*91f16700Schasinglulu 		}
282*91f16700Schasinglulu 	}
283*91f16700Schasinglulu }
284*91f16700Schasinglulu 
285*91f16700Schasinglulu /*
286*91f16700Schasinglulu  * @brief  This function handles Acknowledge failed detection during
287*91f16700Schasinglulu  *	   an I2C Communication.
288*91f16700Schasinglulu  * @param  hi2c: Pointer to a struct i2c_handle_s structure that contains
289*91f16700Schasinglulu  *               the configuration information for the specified I2C.
290*91f16700Schasinglulu  * @param  timeout_ref: Reference to target timeout
291*91f16700Schasinglulu  * @retval 0 if OK, negative value else
292*91f16700Schasinglulu  */
293*91f16700Schasinglulu static int i2c_ack_failed(struct i2c_handle_s *hi2c, uint64_t timeout_ref)
294*91f16700Schasinglulu {
295*91f16700Schasinglulu 	if ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) & I2C_FLAG_AF) == 0U) {
296*91f16700Schasinglulu 		return 0;
297*91f16700Schasinglulu 	}
298*91f16700Schasinglulu 
299*91f16700Schasinglulu 	/*
300*91f16700Schasinglulu 	 * Wait until STOP Flag is reset.
301*91f16700Schasinglulu 	 * AutoEnd should be initiate after AF.
302*91f16700Schasinglulu 	 */
303*91f16700Schasinglulu 	while ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) &
304*91f16700Schasinglulu 		I2C_FLAG_STOPF) == 0U) {
305*91f16700Schasinglulu 		if (timeout_elapsed(timeout_ref)) {
306*91f16700Schasinglulu 			notif_i2c_timeout(hi2c);
307*91f16700Schasinglulu 			hi2c->lock = 0;
308*91f16700Schasinglulu 
309*91f16700Schasinglulu 			return -EIO;
310*91f16700Schasinglulu 		}
311*91f16700Schasinglulu 	}
312*91f16700Schasinglulu 
313*91f16700Schasinglulu 	mmio_write_32(hi2c->i2c_base_addr + I2C_ICR, I2C_FLAG_AF);
314*91f16700Schasinglulu 
315*91f16700Schasinglulu 	mmio_write_32(hi2c->i2c_base_addr + I2C_ICR, I2C_FLAG_STOPF);
316*91f16700Schasinglulu 
317*91f16700Schasinglulu 	i2c_flush_txdr(hi2c);
318*91f16700Schasinglulu 
319*91f16700Schasinglulu 	mmio_clrbits_32(hi2c->i2c_base_addr + I2C_CR2, I2C_RESET_CR2);
320*91f16700Schasinglulu 
321*91f16700Schasinglulu 	hi2c->i2c_err |= I2C_ERROR_AF;
322*91f16700Schasinglulu 	hi2c->i2c_state = I2C_STATE_READY;
323*91f16700Schasinglulu 	hi2c->i2c_mode = I2C_MODE_NONE;
324*91f16700Schasinglulu 
325*91f16700Schasinglulu 	hi2c->lock = 0;
326*91f16700Schasinglulu 
327*91f16700Schasinglulu 	return -EIO;
328*91f16700Schasinglulu }
329*91f16700Schasinglulu 
330*91f16700Schasinglulu /*
331*91f16700Schasinglulu  * @brief  This function handles I2C Communication timeout for specific usage
332*91f16700Schasinglulu  *	   of TXIS flag.
333*91f16700Schasinglulu  * @param  hi2c: Pointer to a struct i2c_handle_s structure that contains
334*91f16700Schasinglulu  *               the configuration information for the specified I2C.
335*91f16700Schasinglulu  * @param  timeout_ref: Reference to target timeout
336*91f16700Schasinglulu  * @retval 0 if OK, negative value else
337*91f16700Schasinglulu  */
338*91f16700Schasinglulu static int i2c_wait_txis(struct i2c_handle_s *hi2c, uint64_t timeout_ref)
339*91f16700Schasinglulu {
340*91f16700Schasinglulu 	while ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) &
341*91f16700Schasinglulu 		I2C_FLAG_TXIS) == 0U) {
342*91f16700Schasinglulu 		if (i2c_ack_failed(hi2c, timeout_ref) != 0) {
343*91f16700Schasinglulu 			return -EIO;
344*91f16700Schasinglulu 		}
345*91f16700Schasinglulu 
346*91f16700Schasinglulu 		if (timeout_elapsed(timeout_ref)) {
347*91f16700Schasinglulu 			notif_i2c_timeout(hi2c);
348*91f16700Schasinglulu 			hi2c->lock = 0;
349*91f16700Schasinglulu 
350*91f16700Schasinglulu 			return -EIO;
351*91f16700Schasinglulu 		}
352*91f16700Schasinglulu 	}
353*91f16700Schasinglulu 
354*91f16700Schasinglulu 	return 0;
355*91f16700Schasinglulu }
356*91f16700Schasinglulu 
357*91f16700Schasinglulu /*
358*91f16700Schasinglulu  * @brief  This function handles I2C Communication timeout for specific
359*91f16700Schasinglulu  *	   usage of STOP flag.
360*91f16700Schasinglulu  * @param  hi2c: Pointer to a struct i2c_handle_s structure that contains
361*91f16700Schasinglulu  *               the configuration information for the specified I2C.
362*91f16700Schasinglulu  * @param  timeout_ref: Reference to target timeout
363*91f16700Schasinglulu  * @retval 0 if OK, negative value else
364*91f16700Schasinglulu  */
365*91f16700Schasinglulu static int i2c_wait_stop(struct i2c_handle_s *hi2c, uint64_t timeout_ref)
366*91f16700Schasinglulu {
367*91f16700Schasinglulu 	while ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) &
368*91f16700Schasinglulu 		 I2C_FLAG_STOPF) == 0U) {
369*91f16700Schasinglulu 		if (i2c_ack_failed(hi2c, timeout_ref) != 0) {
370*91f16700Schasinglulu 			return -EIO;
371*91f16700Schasinglulu 		}
372*91f16700Schasinglulu 
373*91f16700Schasinglulu 		if (timeout_elapsed(timeout_ref)) {
374*91f16700Schasinglulu 			notif_i2c_timeout(hi2c);
375*91f16700Schasinglulu 			hi2c->lock = 0;
376*91f16700Schasinglulu 
377*91f16700Schasinglulu 			return -EIO;
378*91f16700Schasinglulu 		}
379*91f16700Schasinglulu 	}
380*91f16700Schasinglulu 
381*91f16700Schasinglulu 	return 0;
382*91f16700Schasinglulu }
383*91f16700Schasinglulu 
384*91f16700Schasinglulu /*
385*91f16700Schasinglulu  * @brief  Handles I2Cx communication when starting transfer or during transfer
386*91f16700Schasinglulu  *	   (TC or TCR flag are set).
387*91f16700Schasinglulu  * @param  hi2c: I2C handle
388*91f16700Schasinglulu  * @param  dev_addr: Specifies the slave address to be programmed
389*91f16700Schasinglulu  * @param  size: Specifies the number of bytes to be programmed.
390*91f16700Schasinglulu  *   This parameter must be a value between 0 and 255.
391*91f16700Schasinglulu  * @param  i2c_mode: New state of the I2C START condition generation.
392*91f16700Schasinglulu  *   This parameter can be one of the following values:
393*91f16700Schasinglulu  *     @arg @ref I2C_RELOAD_MODE: Enable Reload mode.
394*91f16700Schasinglulu  *     @arg @ref I2C_AUTOEND_MODE: Enable Automatic end mode.
395*91f16700Schasinglulu  *     @arg @ref I2C_SOFTEND_MODE: Enable Software end mode.
396*91f16700Schasinglulu  * @param  request: New state of the I2C START condition generation.
397*91f16700Schasinglulu  *   This parameter can be one of the following values:
398*91f16700Schasinglulu  *     @arg @ref I2C_NO_STARTSTOP: Don't Generate stop and start condition.
399*91f16700Schasinglulu  *     @arg @ref I2C_GENERATE_STOP: Generate stop condition
400*91f16700Schasinglulu  *                                  (size should be set to 0).
401*91f16700Schasinglulu  *     @arg @ref I2C_GENERATE_START_READ: Generate Restart for read request.
402*91f16700Schasinglulu  *     @arg @ref I2C_GENERATE_START_WRITE: Generate Restart for write request.
403*91f16700Schasinglulu  * @retval None
404*91f16700Schasinglulu  */
405*91f16700Schasinglulu static void i2c_transfer_config(struct i2c_handle_s *hi2c, uint16_t dev_addr,
406*91f16700Schasinglulu 				uint16_t size, uint32_t i2c_mode,
407*91f16700Schasinglulu 				uint32_t request)
408*91f16700Schasinglulu {
409*91f16700Schasinglulu 	uint32_t clr_value, set_value;
410*91f16700Schasinglulu 
411*91f16700Schasinglulu 	clr_value = (I2C_CR2_SADD | I2C_CR2_NBYTES | I2C_CR2_RELOAD |
412*91f16700Schasinglulu 		     I2C_CR2_AUTOEND | I2C_CR2_START | I2C_CR2_STOP) |
413*91f16700Schasinglulu 		(I2C_CR2_RD_WRN & (request >> (31U - I2C_CR2_RD_WRN_OFFSET)));
414*91f16700Schasinglulu 
415*91f16700Schasinglulu 	set_value = ((uint32_t)dev_addr & I2C_CR2_SADD) |
416*91f16700Schasinglulu 		(((uint32_t)size << I2C_CR2_NBYTES_OFFSET) & I2C_CR2_NBYTES) |
417*91f16700Schasinglulu 		i2c_mode | request;
418*91f16700Schasinglulu 
419*91f16700Schasinglulu 	mmio_clrsetbits_32(hi2c->i2c_base_addr + I2C_CR2, clr_value, set_value);
420*91f16700Schasinglulu }
421*91f16700Schasinglulu 
422*91f16700Schasinglulu /*
423*91f16700Schasinglulu  * @brief  Master sends target device address followed by internal memory
424*91f16700Schasinglulu  *	   address for write request.
425*91f16700Schasinglulu  * @param  hi2c: Pointer to a struct i2c_handle_s structure that contains
426*91f16700Schasinglulu  *               the configuration information for the specified I2C.
427*91f16700Schasinglulu  * @param  dev_addr: Target device address
428*91f16700Schasinglulu  * @param  mem_addr: Internal memory address
429*91f16700Schasinglulu  * @param  mem_add_size: Size of internal memory address
430*91f16700Schasinglulu  * @param  timeout_ref: Reference to target timeout
431*91f16700Schasinglulu  * @retval 0 if OK, negative value else
432*91f16700Schasinglulu  */
433*91f16700Schasinglulu static int i2c_request_memory_write(struct i2c_handle_s *hi2c,
434*91f16700Schasinglulu 				    uint16_t dev_addr, uint16_t mem_addr,
435*91f16700Schasinglulu 				    uint16_t mem_add_size, uint64_t timeout_ref)
436*91f16700Schasinglulu {
437*91f16700Schasinglulu 	i2c_transfer_config(hi2c, dev_addr, mem_add_size, I2C_RELOAD_MODE,
438*91f16700Schasinglulu 			    I2C_GENERATE_START_WRITE);
439*91f16700Schasinglulu 
440*91f16700Schasinglulu 	if (i2c_wait_txis(hi2c, timeout_ref) != 0) {
441*91f16700Schasinglulu 		return -EIO;
442*91f16700Schasinglulu 	}
443*91f16700Schasinglulu 
444*91f16700Schasinglulu 	if (mem_add_size == I2C_MEMADD_SIZE_8BIT) {
445*91f16700Schasinglulu 		/* Send Memory Address */
446*91f16700Schasinglulu 		mmio_write_8(hi2c->i2c_base_addr + I2C_TXDR,
447*91f16700Schasinglulu 			     (uint8_t)(mem_addr & 0x00FFU));
448*91f16700Schasinglulu 	} else {
449*91f16700Schasinglulu 		/* Send MSB of Memory Address */
450*91f16700Schasinglulu 		mmio_write_8(hi2c->i2c_base_addr + I2C_TXDR,
451*91f16700Schasinglulu 			     (uint8_t)((mem_addr & 0xFF00U) >> 8));
452*91f16700Schasinglulu 
453*91f16700Schasinglulu 		if (i2c_wait_txis(hi2c, timeout_ref) != 0) {
454*91f16700Schasinglulu 			return -EIO;
455*91f16700Schasinglulu 		}
456*91f16700Schasinglulu 
457*91f16700Schasinglulu 		/* Send LSB of Memory Address */
458*91f16700Schasinglulu 		mmio_write_8(hi2c->i2c_base_addr + I2C_TXDR,
459*91f16700Schasinglulu 			     (uint8_t)(mem_addr & 0x00FFU));
460*91f16700Schasinglulu 	}
461*91f16700Schasinglulu 
462*91f16700Schasinglulu 	if (i2c_wait_flag(hi2c, I2C_FLAG_TCR, 0, timeout_ref) != 0) {
463*91f16700Schasinglulu 		return -EIO;
464*91f16700Schasinglulu 	}
465*91f16700Schasinglulu 
466*91f16700Schasinglulu 	return 0;
467*91f16700Schasinglulu }
468*91f16700Schasinglulu 
469*91f16700Schasinglulu /*
470*91f16700Schasinglulu  * @brief  Master sends target device address followed by internal memory
471*91f16700Schasinglulu  *	   address for read request.
472*91f16700Schasinglulu  * @param  hi2c: Pointer to a struct i2c_handle_s structure that contains
473*91f16700Schasinglulu  *               the configuration information for the specified I2C.
474*91f16700Schasinglulu  * @param  dev_addr: Target device address
475*91f16700Schasinglulu  * @param  mem_addr: Internal memory address
476*91f16700Schasinglulu  * @param  mem_add_size: Size of internal memory address
477*91f16700Schasinglulu  * @param  timeout_ref: Reference to target timeout
478*91f16700Schasinglulu  * @retval 0 if OK, negative value else
479*91f16700Schasinglulu  */
480*91f16700Schasinglulu static int i2c_request_memory_read(struct i2c_handle_s *hi2c, uint16_t dev_addr,
481*91f16700Schasinglulu 				   uint16_t mem_addr, uint16_t mem_add_size,
482*91f16700Schasinglulu 				   uint64_t timeout_ref)
483*91f16700Schasinglulu {
484*91f16700Schasinglulu 	i2c_transfer_config(hi2c, dev_addr, mem_add_size, I2C_SOFTEND_MODE,
485*91f16700Schasinglulu 			    I2C_GENERATE_START_WRITE);
486*91f16700Schasinglulu 
487*91f16700Schasinglulu 	if (i2c_wait_txis(hi2c, timeout_ref) != 0) {
488*91f16700Schasinglulu 		return -EIO;
489*91f16700Schasinglulu 	}
490*91f16700Schasinglulu 
491*91f16700Schasinglulu 	if (mem_add_size == I2C_MEMADD_SIZE_8BIT) {
492*91f16700Schasinglulu 		/* Send Memory Address */
493*91f16700Schasinglulu 		mmio_write_8(hi2c->i2c_base_addr + I2C_TXDR,
494*91f16700Schasinglulu 			     (uint8_t)(mem_addr & 0x00FFU));
495*91f16700Schasinglulu 	} else {
496*91f16700Schasinglulu 		/* Send MSB of Memory Address */
497*91f16700Schasinglulu 		mmio_write_8(hi2c->i2c_base_addr + I2C_TXDR,
498*91f16700Schasinglulu 			     (uint8_t)((mem_addr & 0xFF00U) >> 8));
499*91f16700Schasinglulu 
500*91f16700Schasinglulu 		if (i2c_wait_txis(hi2c, timeout_ref) != 0) {
501*91f16700Schasinglulu 			return -EIO;
502*91f16700Schasinglulu 		}
503*91f16700Schasinglulu 
504*91f16700Schasinglulu 		/* Send LSB of Memory Address */
505*91f16700Schasinglulu 		mmio_write_8(hi2c->i2c_base_addr + I2C_TXDR,
506*91f16700Schasinglulu 			     (uint8_t)(mem_addr & 0x00FFU));
507*91f16700Schasinglulu 	}
508*91f16700Schasinglulu 
509*91f16700Schasinglulu 	if (i2c_wait_flag(hi2c, I2C_FLAG_TC, 0, timeout_ref) != 0) {
510*91f16700Schasinglulu 		return -EIO;
511*91f16700Schasinglulu 	}
512*91f16700Schasinglulu 
513*91f16700Schasinglulu 	return 0;
514*91f16700Schasinglulu }
515*91f16700Schasinglulu /*
516*91f16700Schasinglulu  * @brief  Generic function to write an amount of data in blocking mode
517*91f16700Schasinglulu  *         (for Memory Mode and Master Mode)
518*91f16700Schasinglulu  * @param  hi2c: Pointer to a struct i2c_handle_s structure that contains
519*91f16700Schasinglulu  *               the configuration information for the specified I2C.
520*91f16700Schasinglulu  * @param  dev_addr: Target device address
521*91f16700Schasinglulu  * @param  mem_addr: Internal memory address (if Memory Mode)
522*91f16700Schasinglulu  * @param  mem_add_size: Size of internal memory address (if Memory Mode)
523*91f16700Schasinglulu  * @param  p_data: Pointer to data buffer
524*91f16700Schasinglulu  * @param  size: Amount of data to be sent
525*91f16700Schasinglulu  * @param  timeout_ms: Timeout duration in milliseconds
526*91f16700Schasinglulu  * @param  mode: Communication mode
527*91f16700Schasinglulu  * @retval 0 if OK, negative value else
528*91f16700Schasinglulu  */
529*91f16700Schasinglulu static int i2c_write(struct i2c_handle_s *hi2c, uint16_t dev_addr,
530*91f16700Schasinglulu 		     uint16_t mem_addr, uint16_t mem_add_size,
531*91f16700Schasinglulu 		     uint8_t *p_data, uint16_t size, uint32_t timeout_ms,
532*91f16700Schasinglulu 		     enum i2c_mode_e mode)
533*91f16700Schasinglulu {
534*91f16700Schasinglulu 	uint64_t timeout_ref;
535*91f16700Schasinglulu 	int rc = -EIO;
536*91f16700Schasinglulu 	uint8_t *p_buff = p_data;
537*91f16700Schasinglulu 	uint32_t xfer_size;
538*91f16700Schasinglulu 	uint32_t xfer_count = size;
539*91f16700Schasinglulu 
540*91f16700Schasinglulu 	if ((mode != I2C_MODE_MASTER) && (mode != I2C_MODE_MEM)) {
541*91f16700Schasinglulu 		return -1;
542*91f16700Schasinglulu 	}
543*91f16700Schasinglulu 
544*91f16700Schasinglulu 	if ((hi2c->i2c_state != I2C_STATE_READY) || (hi2c->lock != 0U)) {
545*91f16700Schasinglulu 		return -EBUSY;
546*91f16700Schasinglulu 	}
547*91f16700Schasinglulu 
548*91f16700Schasinglulu 	if ((p_data == NULL) || (size == 0U)) {
549*91f16700Schasinglulu 		return -EINVAL;
550*91f16700Schasinglulu 	}
551*91f16700Schasinglulu 
552*91f16700Schasinglulu 	clk_enable(hi2c->clock);
553*91f16700Schasinglulu 
554*91f16700Schasinglulu 	hi2c->lock = 1;
555*91f16700Schasinglulu 
556*91f16700Schasinglulu 	timeout_ref = timeout_init_us(I2C_TIMEOUT_BUSY_MS * 1000);
557*91f16700Schasinglulu 	if (i2c_wait_flag(hi2c, I2C_FLAG_BUSY, 1, timeout_ref) != 0) {
558*91f16700Schasinglulu 		goto bail;
559*91f16700Schasinglulu 	}
560*91f16700Schasinglulu 
561*91f16700Schasinglulu 	hi2c->i2c_state = I2C_STATE_BUSY_TX;
562*91f16700Schasinglulu 	hi2c->i2c_mode = mode;
563*91f16700Schasinglulu 	hi2c->i2c_err = I2C_ERROR_NONE;
564*91f16700Schasinglulu 
565*91f16700Schasinglulu 	timeout_ref = timeout_init_us(timeout_ms * 1000);
566*91f16700Schasinglulu 
567*91f16700Schasinglulu 	if (mode == I2C_MODE_MEM) {
568*91f16700Schasinglulu 		/* In Memory Mode, Send Slave Address and Memory Address */
569*91f16700Schasinglulu 		if (i2c_request_memory_write(hi2c, dev_addr, mem_addr,
570*91f16700Schasinglulu 					     mem_add_size, timeout_ref) != 0) {
571*91f16700Schasinglulu 			goto bail;
572*91f16700Schasinglulu 		}
573*91f16700Schasinglulu 
574*91f16700Schasinglulu 		if (xfer_count > MAX_NBYTE_SIZE) {
575*91f16700Schasinglulu 			xfer_size = MAX_NBYTE_SIZE;
576*91f16700Schasinglulu 			i2c_transfer_config(hi2c, dev_addr, xfer_size,
577*91f16700Schasinglulu 					    I2C_RELOAD_MODE, I2C_NO_STARTSTOP);
578*91f16700Schasinglulu 		} else {
579*91f16700Schasinglulu 			xfer_size = xfer_count;
580*91f16700Schasinglulu 			i2c_transfer_config(hi2c, dev_addr, xfer_size,
581*91f16700Schasinglulu 					    I2C_AUTOEND_MODE, I2C_NO_STARTSTOP);
582*91f16700Schasinglulu 		}
583*91f16700Schasinglulu 	} else {
584*91f16700Schasinglulu 		/* In Master Mode, Send Slave Address */
585*91f16700Schasinglulu 		if (xfer_count > MAX_NBYTE_SIZE) {
586*91f16700Schasinglulu 			xfer_size = MAX_NBYTE_SIZE;
587*91f16700Schasinglulu 			i2c_transfer_config(hi2c, dev_addr, xfer_size,
588*91f16700Schasinglulu 					    I2C_RELOAD_MODE,
589*91f16700Schasinglulu 					    I2C_GENERATE_START_WRITE);
590*91f16700Schasinglulu 		} else {
591*91f16700Schasinglulu 			xfer_size = xfer_count;
592*91f16700Schasinglulu 			i2c_transfer_config(hi2c, dev_addr, xfer_size,
593*91f16700Schasinglulu 					    I2C_AUTOEND_MODE,
594*91f16700Schasinglulu 					    I2C_GENERATE_START_WRITE);
595*91f16700Schasinglulu 		}
596*91f16700Schasinglulu 	}
597*91f16700Schasinglulu 
598*91f16700Schasinglulu 	do {
599*91f16700Schasinglulu 		if (i2c_wait_txis(hi2c, timeout_ref) != 0) {
600*91f16700Schasinglulu 			goto bail;
601*91f16700Schasinglulu 		}
602*91f16700Schasinglulu 
603*91f16700Schasinglulu 		mmio_write_8(hi2c->i2c_base_addr + I2C_TXDR, *p_buff);
604*91f16700Schasinglulu 		p_buff++;
605*91f16700Schasinglulu 		xfer_count--;
606*91f16700Schasinglulu 		xfer_size--;
607*91f16700Schasinglulu 
608*91f16700Schasinglulu 		if ((xfer_count != 0U) && (xfer_size == 0U)) {
609*91f16700Schasinglulu 			/* Wait until TCR flag is set */
610*91f16700Schasinglulu 			if (i2c_wait_flag(hi2c, I2C_FLAG_TCR, 0,
611*91f16700Schasinglulu 					  timeout_ref) != 0) {
612*91f16700Schasinglulu 				goto bail;
613*91f16700Schasinglulu 			}
614*91f16700Schasinglulu 
615*91f16700Schasinglulu 			if (xfer_count > MAX_NBYTE_SIZE) {
616*91f16700Schasinglulu 				xfer_size = MAX_NBYTE_SIZE;
617*91f16700Schasinglulu 				i2c_transfer_config(hi2c, dev_addr,
618*91f16700Schasinglulu 						    xfer_size,
619*91f16700Schasinglulu 						    I2C_RELOAD_MODE,
620*91f16700Schasinglulu 						    I2C_NO_STARTSTOP);
621*91f16700Schasinglulu 			} else {
622*91f16700Schasinglulu 				xfer_size = xfer_count;
623*91f16700Schasinglulu 				i2c_transfer_config(hi2c, dev_addr,
624*91f16700Schasinglulu 						    xfer_size,
625*91f16700Schasinglulu 						    I2C_AUTOEND_MODE,
626*91f16700Schasinglulu 						    I2C_NO_STARTSTOP);
627*91f16700Schasinglulu 			}
628*91f16700Schasinglulu 		}
629*91f16700Schasinglulu 
630*91f16700Schasinglulu 	} while (xfer_count > 0U);
631*91f16700Schasinglulu 
632*91f16700Schasinglulu 	/*
633*91f16700Schasinglulu 	 * No need to Check TC flag, with AUTOEND mode the stop
634*91f16700Schasinglulu 	 * is automatically generated.
635*91f16700Schasinglulu 	 * Wait until STOPF flag is reset.
636*91f16700Schasinglulu 	 */
637*91f16700Schasinglulu 	if (i2c_wait_stop(hi2c, timeout_ref) != 0) {
638*91f16700Schasinglulu 		goto bail;
639*91f16700Schasinglulu 	}
640*91f16700Schasinglulu 
641*91f16700Schasinglulu 	mmio_write_32(hi2c->i2c_base_addr + I2C_ICR, I2C_FLAG_STOPF);
642*91f16700Schasinglulu 
643*91f16700Schasinglulu 	mmio_clrbits_32(hi2c->i2c_base_addr + I2C_CR2, I2C_RESET_CR2);
644*91f16700Schasinglulu 
645*91f16700Schasinglulu 	hi2c->i2c_state = I2C_STATE_READY;
646*91f16700Schasinglulu 	hi2c->i2c_mode  = I2C_MODE_NONE;
647*91f16700Schasinglulu 
648*91f16700Schasinglulu 	rc = 0;
649*91f16700Schasinglulu 
650*91f16700Schasinglulu bail:
651*91f16700Schasinglulu 	hi2c->lock = 0;
652*91f16700Schasinglulu 	clk_disable(hi2c->clock);
653*91f16700Schasinglulu 
654*91f16700Schasinglulu 	return rc;
655*91f16700Schasinglulu }
656*91f16700Schasinglulu 
657*91f16700Schasinglulu /*
658*91f16700Schasinglulu  * @brief  Write an amount of data in blocking mode to a specific memory
659*91f16700Schasinglulu  *         address.
660*91f16700Schasinglulu  * @param  hi2c: Pointer to a struct i2c_handle_s structure that contains
661*91f16700Schasinglulu  *               the configuration information for the specified I2C.
662*91f16700Schasinglulu  * @param  dev_addr: Target device address
663*91f16700Schasinglulu  * @param  mem_addr: Internal memory address
664*91f16700Schasinglulu  * @param  mem_add_size: Size of internal memory address
665*91f16700Schasinglulu  * @param  p_data: Pointer to data buffer
666*91f16700Schasinglulu  * @param  size: Amount of data to be sent
667*91f16700Schasinglulu  * @param  timeout_ms: Timeout duration in milliseconds
668*91f16700Schasinglulu  * @retval 0 if OK, negative value else
669*91f16700Schasinglulu  */
670*91f16700Schasinglulu int stm32_i2c_mem_write(struct i2c_handle_s *hi2c, uint16_t dev_addr,
671*91f16700Schasinglulu 			uint16_t mem_addr, uint16_t mem_add_size,
672*91f16700Schasinglulu 			uint8_t *p_data, uint16_t size, uint32_t timeout_ms)
673*91f16700Schasinglulu {
674*91f16700Schasinglulu 	return i2c_write(hi2c, dev_addr, mem_addr, mem_add_size,
675*91f16700Schasinglulu 			 p_data, size, timeout_ms, I2C_MODE_MEM);
676*91f16700Schasinglulu }
677*91f16700Schasinglulu 
678*91f16700Schasinglulu /*
679*91f16700Schasinglulu  * @brief  Transmits in master mode an amount of data in blocking mode.
680*91f16700Schasinglulu  * @param  hi2c: Pointer to a struct i2c_handle_s structure that contains
681*91f16700Schasinglulu  *               the configuration information for the specified I2C.
682*91f16700Schasinglulu  * @param  dev_addr: Target device address
683*91f16700Schasinglulu  * @param  p_data: Pointer to data buffer
684*91f16700Schasinglulu  * @param  size: Amount of data to be sent
685*91f16700Schasinglulu  * @param  timeout_ms: Timeout duration in milliseconds
686*91f16700Schasinglulu  * @retval 0 if OK, negative value else
687*91f16700Schasinglulu  */
688*91f16700Schasinglulu int stm32_i2c_master_transmit(struct i2c_handle_s *hi2c, uint16_t dev_addr,
689*91f16700Schasinglulu 			      uint8_t *p_data, uint16_t size,
690*91f16700Schasinglulu 			      uint32_t timeout_ms)
691*91f16700Schasinglulu {
692*91f16700Schasinglulu 	return i2c_write(hi2c, dev_addr, 0, 0,
693*91f16700Schasinglulu 			 p_data, size, timeout_ms, I2C_MODE_MASTER);
694*91f16700Schasinglulu }
695*91f16700Schasinglulu 
696*91f16700Schasinglulu /*
697*91f16700Schasinglulu  * @brief  Generic function to read an amount of data in blocking mode
698*91f16700Schasinglulu  *         (for Memory Mode and Master Mode)
699*91f16700Schasinglulu  * @param  hi2c: Pointer to a struct i2c_handle_s structure that contains
700*91f16700Schasinglulu  *               the configuration information for the specified I2C.
701*91f16700Schasinglulu  * @param  dev_addr: Target device address
702*91f16700Schasinglulu  * @param  mem_addr: Internal memory address (if Memory Mode)
703*91f16700Schasinglulu  * @param  mem_add_size: Size of internal memory address (if Memory Mode)
704*91f16700Schasinglulu  * @param  p_data: Pointer to data buffer
705*91f16700Schasinglulu  * @param  size: Amount of data to be sent
706*91f16700Schasinglulu  * @param  timeout_ms: Timeout duration in milliseconds
707*91f16700Schasinglulu  * @param  mode: Communication mode
708*91f16700Schasinglulu  * @retval 0 if OK, negative value else
709*91f16700Schasinglulu  */
710*91f16700Schasinglulu static int i2c_read(struct i2c_handle_s *hi2c, uint16_t dev_addr,
711*91f16700Schasinglulu 		    uint16_t mem_addr, uint16_t mem_add_size,
712*91f16700Schasinglulu 		    uint8_t *p_data, uint16_t size, uint32_t timeout_ms,
713*91f16700Schasinglulu 		    enum i2c_mode_e mode)
714*91f16700Schasinglulu {
715*91f16700Schasinglulu 	uint64_t timeout_ref;
716*91f16700Schasinglulu 	int rc = -EIO;
717*91f16700Schasinglulu 	uint8_t *p_buff = p_data;
718*91f16700Schasinglulu 	uint32_t xfer_count = size;
719*91f16700Schasinglulu 	uint32_t xfer_size;
720*91f16700Schasinglulu 
721*91f16700Schasinglulu 	if ((mode != I2C_MODE_MASTER) && (mode != I2C_MODE_MEM)) {
722*91f16700Schasinglulu 		return -1;
723*91f16700Schasinglulu 	}
724*91f16700Schasinglulu 
725*91f16700Schasinglulu 	if ((hi2c->i2c_state != I2C_STATE_READY) || (hi2c->lock != 0U)) {
726*91f16700Schasinglulu 		return -EBUSY;
727*91f16700Schasinglulu 	}
728*91f16700Schasinglulu 
729*91f16700Schasinglulu 	if ((p_data == NULL) || (size == 0U)) {
730*91f16700Schasinglulu 		return  -EINVAL;
731*91f16700Schasinglulu 	}
732*91f16700Schasinglulu 
733*91f16700Schasinglulu 	clk_enable(hi2c->clock);
734*91f16700Schasinglulu 
735*91f16700Schasinglulu 	hi2c->lock = 1;
736*91f16700Schasinglulu 
737*91f16700Schasinglulu 	timeout_ref = timeout_init_us(I2C_TIMEOUT_BUSY_MS * 1000);
738*91f16700Schasinglulu 	if (i2c_wait_flag(hi2c, I2C_FLAG_BUSY, 1, timeout_ref) != 0) {
739*91f16700Schasinglulu 		goto bail;
740*91f16700Schasinglulu 	}
741*91f16700Schasinglulu 
742*91f16700Schasinglulu 	hi2c->i2c_state = I2C_STATE_BUSY_RX;
743*91f16700Schasinglulu 	hi2c->i2c_mode = mode;
744*91f16700Schasinglulu 	hi2c->i2c_err = I2C_ERROR_NONE;
745*91f16700Schasinglulu 
746*91f16700Schasinglulu 	if (mode == I2C_MODE_MEM) {
747*91f16700Schasinglulu 		/* Send Memory Address */
748*91f16700Schasinglulu 		if (i2c_request_memory_read(hi2c, dev_addr, mem_addr,
749*91f16700Schasinglulu 					    mem_add_size, timeout_ref) != 0) {
750*91f16700Schasinglulu 			goto bail;
751*91f16700Schasinglulu 		}
752*91f16700Schasinglulu 	}
753*91f16700Schasinglulu 
754*91f16700Schasinglulu 	/*
755*91f16700Schasinglulu 	 * Send Slave Address.
756*91f16700Schasinglulu 	 * Set NBYTES to write and reload if xfer_count > MAX_NBYTE_SIZE
757*91f16700Schasinglulu 	 * and generate RESTART.
758*91f16700Schasinglulu 	 */
759*91f16700Schasinglulu 	if (xfer_count > MAX_NBYTE_SIZE) {
760*91f16700Schasinglulu 		xfer_size = MAX_NBYTE_SIZE;
761*91f16700Schasinglulu 		i2c_transfer_config(hi2c, dev_addr, xfer_size,
762*91f16700Schasinglulu 				    I2C_RELOAD_MODE, I2C_GENERATE_START_READ);
763*91f16700Schasinglulu 	} else {
764*91f16700Schasinglulu 		xfer_size = xfer_count;
765*91f16700Schasinglulu 		i2c_transfer_config(hi2c, dev_addr, xfer_size,
766*91f16700Schasinglulu 				    I2C_AUTOEND_MODE, I2C_GENERATE_START_READ);
767*91f16700Schasinglulu 	}
768*91f16700Schasinglulu 
769*91f16700Schasinglulu 	do {
770*91f16700Schasinglulu 		if (i2c_wait_flag(hi2c, I2C_FLAG_RXNE, 0, timeout_ref) != 0) {
771*91f16700Schasinglulu 			goto bail;
772*91f16700Schasinglulu 		}
773*91f16700Schasinglulu 
774*91f16700Schasinglulu 		*p_buff = mmio_read_8(hi2c->i2c_base_addr + I2C_RXDR);
775*91f16700Schasinglulu 		p_buff++;
776*91f16700Schasinglulu 		xfer_size--;
777*91f16700Schasinglulu 		xfer_count--;
778*91f16700Schasinglulu 
779*91f16700Schasinglulu 		if ((xfer_count != 0U) && (xfer_size == 0U)) {
780*91f16700Schasinglulu 			if (i2c_wait_flag(hi2c, I2C_FLAG_TCR, 0,
781*91f16700Schasinglulu 					  timeout_ref) != 0) {
782*91f16700Schasinglulu 				goto bail;
783*91f16700Schasinglulu 			}
784*91f16700Schasinglulu 
785*91f16700Schasinglulu 			if (xfer_count > MAX_NBYTE_SIZE) {
786*91f16700Schasinglulu 				xfer_size = MAX_NBYTE_SIZE;
787*91f16700Schasinglulu 				i2c_transfer_config(hi2c, dev_addr,
788*91f16700Schasinglulu 						    xfer_size,
789*91f16700Schasinglulu 						    I2C_RELOAD_MODE,
790*91f16700Schasinglulu 						    I2C_NO_STARTSTOP);
791*91f16700Schasinglulu 			} else {
792*91f16700Schasinglulu 				xfer_size = xfer_count;
793*91f16700Schasinglulu 				i2c_transfer_config(hi2c, dev_addr,
794*91f16700Schasinglulu 						    xfer_size,
795*91f16700Schasinglulu 						    I2C_AUTOEND_MODE,
796*91f16700Schasinglulu 						    I2C_NO_STARTSTOP);
797*91f16700Schasinglulu 			}
798*91f16700Schasinglulu 		}
799*91f16700Schasinglulu 	} while (xfer_count > 0U);
800*91f16700Schasinglulu 
801*91f16700Schasinglulu 	/*
802*91f16700Schasinglulu 	 * No need to Check TC flag, with AUTOEND mode the stop
803*91f16700Schasinglulu 	 * is automatically generated.
804*91f16700Schasinglulu 	 * Wait until STOPF flag is reset.
805*91f16700Schasinglulu 	 */
806*91f16700Schasinglulu 	if (i2c_wait_stop(hi2c, timeout_ref) != 0) {
807*91f16700Schasinglulu 		goto bail;
808*91f16700Schasinglulu 	}
809*91f16700Schasinglulu 
810*91f16700Schasinglulu 	mmio_write_32(hi2c->i2c_base_addr + I2C_ICR, I2C_FLAG_STOPF);
811*91f16700Schasinglulu 
812*91f16700Schasinglulu 	mmio_clrbits_32(hi2c->i2c_base_addr + I2C_CR2, I2C_RESET_CR2);
813*91f16700Schasinglulu 
814*91f16700Schasinglulu 	hi2c->i2c_state = I2C_STATE_READY;
815*91f16700Schasinglulu 	hi2c->i2c_mode = I2C_MODE_NONE;
816*91f16700Schasinglulu 
817*91f16700Schasinglulu 	rc = 0;
818*91f16700Schasinglulu 
819*91f16700Schasinglulu bail:
820*91f16700Schasinglulu 	hi2c->lock = 0;
821*91f16700Schasinglulu 	clk_disable(hi2c->clock);
822*91f16700Schasinglulu 
823*91f16700Schasinglulu 	return rc;
824*91f16700Schasinglulu }
825*91f16700Schasinglulu 
826*91f16700Schasinglulu /*
827*91f16700Schasinglulu  * @brief  Read an amount of data in blocking mode from a specific memory
828*91f16700Schasinglulu  *	   address.
829*91f16700Schasinglulu  * @param  hi2c: Pointer to a struct i2c_handle_s structure that contains
830*91f16700Schasinglulu  *               the configuration information for the specified I2C.
831*91f16700Schasinglulu  * @param  dev_addr: Target device address
832*91f16700Schasinglulu  * @param  mem_addr: Internal memory address
833*91f16700Schasinglulu  * @param  mem_add_size: Size of internal memory address
834*91f16700Schasinglulu  * @param  p_data: Pointer to data buffer
835*91f16700Schasinglulu  * @param  size: Amount of data to be sent
836*91f16700Schasinglulu  * @param  timeout_ms: Timeout duration in milliseconds
837*91f16700Schasinglulu  * @retval 0 if OK, negative value else
838*91f16700Schasinglulu  */
839*91f16700Schasinglulu int stm32_i2c_mem_read(struct i2c_handle_s *hi2c, uint16_t dev_addr,
840*91f16700Schasinglulu 		       uint16_t mem_addr, uint16_t mem_add_size,
841*91f16700Schasinglulu 		       uint8_t *p_data, uint16_t size, uint32_t timeout_ms)
842*91f16700Schasinglulu {
843*91f16700Schasinglulu 	return i2c_read(hi2c, dev_addr, mem_addr, mem_add_size,
844*91f16700Schasinglulu 			p_data, size, timeout_ms, I2C_MODE_MEM);
845*91f16700Schasinglulu }
846*91f16700Schasinglulu 
847*91f16700Schasinglulu /*
848*91f16700Schasinglulu  * @brief  Receives in master mode an amount of data in blocking mode.
849*91f16700Schasinglulu  * @param  hi2c: Pointer to a struct i2c_handle_s structure that contains
850*91f16700Schasinglulu  *               the configuration information for the specified I2C.
851*91f16700Schasinglulu  * @param  dev_addr: Target device address
852*91f16700Schasinglulu  * @param  p_data: Pointer to data buffer
853*91f16700Schasinglulu  * @param  size: Amount of data to be sent
854*91f16700Schasinglulu  * @param  timeout_ms: Timeout duration in milliseconds
855*91f16700Schasinglulu  * @retval 0 if OK, negative value else
856*91f16700Schasinglulu  */
857*91f16700Schasinglulu int stm32_i2c_master_receive(struct i2c_handle_s *hi2c, uint16_t dev_addr,
858*91f16700Schasinglulu 			     uint8_t *p_data, uint16_t size,
859*91f16700Schasinglulu 			     uint32_t timeout_ms)
860*91f16700Schasinglulu {
861*91f16700Schasinglulu 	return i2c_read(hi2c, dev_addr, 0, 0,
862*91f16700Schasinglulu 			p_data, size, timeout_ms, I2C_MODE_MASTER);
863*91f16700Schasinglulu }
864*91f16700Schasinglulu 
865*91f16700Schasinglulu /*
866*91f16700Schasinglulu  * @brief  Checks if target device is ready for communication.
867*91f16700Schasinglulu  * @note   This function is used with Memory devices
868*91f16700Schasinglulu  * @param  hi2c: Pointer to a struct i2c_handle_s structure that contains
869*91f16700Schasinglulu  *               the configuration information for the specified I2C.
870*91f16700Schasinglulu  * @param  dev_addr: Target device address
871*91f16700Schasinglulu  * @param  trials: Number of trials
872*91f16700Schasinglulu  * @param  timeout_ms: Timeout duration in milliseconds
873*91f16700Schasinglulu  * @retval True if device is ready, false else
874*91f16700Schasinglulu  */
875*91f16700Schasinglulu bool stm32_i2c_is_device_ready(struct i2c_handle_s *hi2c,
876*91f16700Schasinglulu 			       uint16_t dev_addr, uint32_t trials,
877*91f16700Schasinglulu 			       uint32_t timeout_ms)
878*91f16700Schasinglulu {
879*91f16700Schasinglulu 	uint32_t i2c_trials = 0U;
880*91f16700Schasinglulu 	bool rc = false;
881*91f16700Schasinglulu 
882*91f16700Schasinglulu 	if ((hi2c->i2c_state != I2C_STATE_READY) || (hi2c->lock != 0U)) {
883*91f16700Schasinglulu 		return rc;
884*91f16700Schasinglulu 	}
885*91f16700Schasinglulu 
886*91f16700Schasinglulu 	clk_enable(hi2c->clock);
887*91f16700Schasinglulu 
888*91f16700Schasinglulu 	hi2c->lock = 1;
889*91f16700Schasinglulu 	hi2c->i2c_mode = I2C_MODE_NONE;
890*91f16700Schasinglulu 
891*91f16700Schasinglulu 	if ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) & I2C_FLAG_BUSY) !=
892*91f16700Schasinglulu 	    0U) {
893*91f16700Schasinglulu 		goto bail;
894*91f16700Schasinglulu 	}
895*91f16700Schasinglulu 
896*91f16700Schasinglulu 	hi2c->i2c_state = I2C_STATE_BUSY;
897*91f16700Schasinglulu 	hi2c->i2c_err = I2C_ERROR_NONE;
898*91f16700Schasinglulu 
899*91f16700Schasinglulu 	do {
900*91f16700Schasinglulu 		uint64_t timeout_ref;
901*91f16700Schasinglulu 
902*91f16700Schasinglulu 		/* Generate Start */
903*91f16700Schasinglulu 		if ((mmio_read_32(hi2c->i2c_base_addr + I2C_OAR1) &
904*91f16700Schasinglulu 		     I2C_OAR1_OA1MODE) == 0) {
905*91f16700Schasinglulu 			mmio_write_32(hi2c->i2c_base_addr + I2C_CR2,
906*91f16700Schasinglulu 				      (((uint32_t)dev_addr & I2C_CR2_SADD) |
907*91f16700Schasinglulu 				       I2C_CR2_START | I2C_CR2_AUTOEND) &
908*91f16700Schasinglulu 				      ~I2C_CR2_RD_WRN);
909*91f16700Schasinglulu 		} else {
910*91f16700Schasinglulu 			mmio_write_32(hi2c->i2c_base_addr + I2C_CR2,
911*91f16700Schasinglulu 				      (((uint32_t)dev_addr & I2C_CR2_SADD) |
912*91f16700Schasinglulu 				       I2C_CR2_START | I2C_CR2_ADD10) &
913*91f16700Schasinglulu 				      ~I2C_CR2_RD_WRN);
914*91f16700Schasinglulu 		}
915*91f16700Schasinglulu 
916*91f16700Schasinglulu 		/*
917*91f16700Schasinglulu 		 * No need to Check TC flag, with AUTOEND mode the stop
918*91f16700Schasinglulu 		 * is automatically generated.
919*91f16700Schasinglulu 		 * Wait until STOPF flag is set or a NACK flag is set.
920*91f16700Schasinglulu 		 */
921*91f16700Schasinglulu 		timeout_ref = timeout_init_us(timeout_ms * 1000);
922*91f16700Schasinglulu 		do {
923*91f16700Schasinglulu 			if ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) &
924*91f16700Schasinglulu 			     (I2C_FLAG_STOPF | I2C_FLAG_AF)) != 0U) {
925*91f16700Schasinglulu 				break;
926*91f16700Schasinglulu 			}
927*91f16700Schasinglulu 
928*91f16700Schasinglulu 			if (timeout_elapsed(timeout_ref)) {
929*91f16700Schasinglulu 				notif_i2c_timeout(hi2c);
930*91f16700Schasinglulu 				goto bail;
931*91f16700Schasinglulu 			}
932*91f16700Schasinglulu 		} while (true);
933*91f16700Schasinglulu 
934*91f16700Schasinglulu 		if ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) &
935*91f16700Schasinglulu 		     I2C_FLAG_AF) == 0U) {
936*91f16700Schasinglulu 			if (i2c_wait_flag(hi2c, I2C_FLAG_STOPF, 0,
937*91f16700Schasinglulu 					  timeout_ref) != 0) {
938*91f16700Schasinglulu 				goto bail;
939*91f16700Schasinglulu 			}
940*91f16700Schasinglulu 
941*91f16700Schasinglulu 			mmio_write_32(hi2c->i2c_base_addr + I2C_ICR,
942*91f16700Schasinglulu 				      I2C_FLAG_STOPF);
943*91f16700Schasinglulu 
944*91f16700Schasinglulu 			hi2c->i2c_state = I2C_STATE_READY;
945*91f16700Schasinglulu 
946*91f16700Schasinglulu 			rc = true;
947*91f16700Schasinglulu 			goto bail;
948*91f16700Schasinglulu 		}
949*91f16700Schasinglulu 
950*91f16700Schasinglulu 		if (i2c_wait_flag(hi2c, I2C_FLAG_STOPF, 0, timeout_ref) != 0) {
951*91f16700Schasinglulu 			goto bail;
952*91f16700Schasinglulu 		}
953*91f16700Schasinglulu 
954*91f16700Schasinglulu 		mmio_write_32(hi2c->i2c_base_addr + I2C_ICR, I2C_FLAG_AF);
955*91f16700Schasinglulu 
956*91f16700Schasinglulu 		mmio_write_32(hi2c->i2c_base_addr + I2C_ICR, I2C_FLAG_STOPF);
957*91f16700Schasinglulu 
958*91f16700Schasinglulu 		if (i2c_trials == trials) {
959*91f16700Schasinglulu 			mmio_setbits_32(hi2c->i2c_base_addr + I2C_CR2,
960*91f16700Schasinglulu 					I2C_CR2_STOP);
961*91f16700Schasinglulu 
962*91f16700Schasinglulu 			if (i2c_wait_flag(hi2c, I2C_FLAG_STOPF, 0,
963*91f16700Schasinglulu 					  timeout_ref) != 0) {
964*91f16700Schasinglulu 				goto bail;
965*91f16700Schasinglulu 			}
966*91f16700Schasinglulu 
967*91f16700Schasinglulu 			mmio_write_32(hi2c->i2c_base_addr + I2C_ICR,
968*91f16700Schasinglulu 				      I2C_FLAG_STOPF);
969*91f16700Schasinglulu 		}
970*91f16700Schasinglulu 
971*91f16700Schasinglulu 		i2c_trials++;
972*91f16700Schasinglulu 	} while (i2c_trials < trials);
973*91f16700Schasinglulu 
974*91f16700Schasinglulu 	notif_i2c_timeout(hi2c);
975*91f16700Schasinglulu 
976*91f16700Schasinglulu bail:
977*91f16700Schasinglulu 	hi2c->lock = 0;
978*91f16700Schasinglulu 	clk_disable(hi2c->clock);
979*91f16700Schasinglulu 
980*91f16700Schasinglulu 	return rc;
981*91f16700Schasinglulu }
982*91f16700Schasinglulu 
983