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