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