xref: /openbmc/linux/drivers/i2c/busses/i2c-stm32f7.c (revision c896ff2d)
19c41e452SBenjamin Gaignard // SPDX-License-Identifier: GPL-2.0
2aeb068c5SPierre-Yves MORDRET /*
3aeb068c5SPierre-Yves MORDRET  * Driver for STMicroelectronics STM32F7 I2C controller
4aeb068c5SPierre-Yves MORDRET  *
5aeb068c5SPierre-Yves MORDRET  * This I2C controller is described in the STM32F75xxx and STM32F74xxx Soc
6aeb068c5SPierre-Yves MORDRET  * reference manual.
7aeb068c5SPierre-Yves MORDRET  * Please see below a link to the documentation:
8aeb068c5SPierre-Yves MORDRET  * http://www.st.com/resource/en/reference_manual/dm00124865.pdf
9aeb068c5SPierre-Yves MORDRET  *
10aeb068c5SPierre-Yves MORDRET  * Copyright (C) M'boumba Cedric Madianga 2017
119c41e452SBenjamin Gaignard  * Copyright (C) STMicroelectronics 2017
12aeb068c5SPierre-Yves MORDRET  * Author: M'boumba Cedric Madianga <cedric.madianga@gmail.com>
13aeb068c5SPierre-Yves MORDRET  *
14aeb068c5SPierre-Yves MORDRET  * This driver is based on i2c-stm32f4.c
15aeb068c5SPierre-Yves MORDRET  *
16aeb068c5SPierre-Yves MORDRET  */
17aeb068c5SPierre-Yves MORDRET #include <linux/clk.h>
18aeb068c5SPierre-Yves MORDRET #include <linux/delay.h>
19aeb068c5SPierre-Yves MORDRET #include <linux/err.h>
20aeb068c5SPierre-Yves MORDRET #include <linux/i2c.h>
216af07719SAlain Volmat #include <linux/i2c-smbus.h>
22aeb068c5SPierre-Yves MORDRET #include <linux/interrupt.h>
23aeb068c5SPierre-Yves MORDRET #include <linux/io.h>
24aeb068c5SPierre-Yves MORDRET #include <linux/iopoll.h>
25cb944fb9SPierre-Yves MORDRET #include <linux/mfd/syscon.h>
26aeb068c5SPierre-Yves MORDRET #include <linux/module.h>
27aeb068c5SPierre-Yves MORDRET #include <linux/of.h>
28aeb068c5SPierre-Yves MORDRET #include <linux/of_address.h>
29aeb068c5SPierre-Yves MORDRET #include <linux/of_platform.h>
30aeb068c5SPierre-Yves MORDRET #include <linux/platform_device.h>
314e7bca6fSPierre-Yves MORDRET #include <linux/pinctrl/consumer.h>
324e7bca6fSPierre-Yves MORDRET #include <linux/pm_runtime.h>
33419be8e1SAlain Volmat #include <linux/pm_wakeirq.h>
34cb944fb9SPierre-Yves MORDRET #include <linux/regmap.h>
35aeb068c5SPierre-Yves MORDRET #include <linux/reset.h>
36aeb068c5SPierre-Yves MORDRET #include <linux/slab.h>
37aeb068c5SPierre-Yves MORDRET 
38aeb068c5SPierre-Yves MORDRET #include "i2c-stm32.h"
39aeb068c5SPierre-Yves MORDRET 
40aeb068c5SPierre-Yves MORDRET /* STM32F7 I2C registers */
41aeb068c5SPierre-Yves MORDRET #define STM32F7_I2C_CR1				0x00
42aeb068c5SPierre-Yves MORDRET #define STM32F7_I2C_CR2				0x04
4360d609f3SPierre-Yves MORDRET #define STM32F7_I2C_OAR1			0x08
4460d609f3SPierre-Yves MORDRET #define STM32F7_I2C_OAR2			0x0C
459e48155fSPierre-Yves MORDRET #define STM32F7_I2C_PECR			0x20
46aeb068c5SPierre-Yves MORDRET #define STM32F7_I2C_TIMINGR			0x10
47aeb068c5SPierre-Yves MORDRET #define STM32F7_I2C_ISR				0x18
48aeb068c5SPierre-Yves MORDRET #define STM32F7_I2C_ICR				0x1C
49aeb068c5SPierre-Yves MORDRET #define STM32F7_I2C_RXDR			0x24
50aeb068c5SPierre-Yves MORDRET #define STM32F7_I2C_TXDR			0x28
51aeb068c5SPierre-Yves MORDRET 
52aeb068c5SPierre-Yves MORDRET /* STM32F7 I2C control 1 */
539e48155fSPierre-Yves MORDRET #define STM32F7_I2C_CR1_PECEN			BIT(23)
54c8062d11SAlain Volmat #define STM32F7_I2C_CR1_ALERTEN			BIT(22)
556af07719SAlain Volmat #define STM32F7_I2C_CR1_SMBHEN			BIT(20)
56419be8e1SAlain Volmat #define STM32F7_I2C_CR1_WUPEN			BIT(18)
5760d609f3SPierre-Yves MORDRET #define STM32F7_I2C_CR1_SBC			BIT(16)
587ecc8cfdSPierre-Yves MORDRET #define STM32F7_I2C_CR1_RXDMAEN			BIT(15)
597ecc8cfdSPierre-Yves MORDRET #define STM32F7_I2C_CR1_TXDMAEN			BIT(14)
60aeb068c5SPierre-Yves MORDRET #define STM32F7_I2C_CR1_ANFOFF			BIT(12)
613d6a3d3aSAlain Volmat #define STM32F7_I2C_CR1_DNF_MASK		GENMASK(11, 8)
623d6a3d3aSAlain Volmat #define STM32F7_I2C_CR1_DNF(n)			(((n) & 0xf) << 8)
63aeb068c5SPierre-Yves MORDRET #define STM32F7_I2C_CR1_ERRIE			BIT(7)
64aeb068c5SPierre-Yves MORDRET #define STM32F7_I2C_CR1_TCIE			BIT(6)
65aeb068c5SPierre-Yves MORDRET #define STM32F7_I2C_CR1_STOPIE			BIT(5)
66aeb068c5SPierre-Yves MORDRET #define STM32F7_I2C_CR1_NACKIE			BIT(4)
67aeb068c5SPierre-Yves MORDRET #define STM32F7_I2C_CR1_ADDRIE			BIT(3)
68aeb068c5SPierre-Yves MORDRET #define STM32F7_I2C_CR1_RXIE			BIT(2)
69aeb068c5SPierre-Yves MORDRET #define STM32F7_I2C_CR1_TXIE			BIT(1)
70aeb068c5SPierre-Yves MORDRET #define STM32F7_I2C_CR1_PE			BIT(0)
71aeb068c5SPierre-Yves MORDRET #define STM32F7_I2C_ALL_IRQ_MASK		(STM32F7_I2C_CR1_ERRIE \
72aeb068c5SPierre-Yves MORDRET 						| STM32F7_I2C_CR1_TCIE \
73aeb068c5SPierre-Yves MORDRET 						| STM32F7_I2C_CR1_STOPIE \
74aeb068c5SPierre-Yves MORDRET 						| STM32F7_I2C_CR1_NACKIE \
75aeb068c5SPierre-Yves MORDRET 						| STM32F7_I2C_CR1_RXIE \
76aeb068c5SPierre-Yves MORDRET 						| STM32F7_I2C_CR1_TXIE)
7760d609f3SPierre-Yves MORDRET #define STM32F7_I2C_XFER_IRQ_MASK		(STM32F7_I2C_CR1_TCIE \
7860d609f3SPierre-Yves MORDRET 						| STM32F7_I2C_CR1_STOPIE \
7960d609f3SPierre-Yves MORDRET 						| STM32F7_I2C_CR1_NACKIE \
8060d609f3SPierre-Yves MORDRET 						| STM32F7_I2C_CR1_RXIE \
8160d609f3SPierre-Yves MORDRET 						| STM32F7_I2C_CR1_TXIE)
82aeb068c5SPierre-Yves MORDRET 
83aeb068c5SPierre-Yves MORDRET /* STM32F7 I2C control 2 */
849e48155fSPierre-Yves MORDRET #define STM32F7_I2C_CR2_PECBYTE			BIT(26)
85aeb068c5SPierre-Yves MORDRET #define STM32F7_I2C_CR2_RELOAD			BIT(24)
86aeb068c5SPierre-Yves MORDRET #define STM32F7_I2C_CR2_NBYTES_MASK		GENMASK(23, 16)
87aeb068c5SPierre-Yves MORDRET #define STM32F7_I2C_CR2_NBYTES(n)		(((n) & 0xff) << 16)
88aeb068c5SPierre-Yves MORDRET #define STM32F7_I2C_CR2_NACK			BIT(15)
89aeb068c5SPierre-Yves MORDRET #define STM32F7_I2C_CR2_STOP			BIT(14)
90aeb068c5SPierre-Yves MORDRET #define STM32F7_I2C_CR2_START			BIT(13)
918c7ecc99SPierre-Yves MORDRET #define STM32F7_I2C_CR2_HEAD10R			BIT(12)
928c7ecc99SPierre-Yves MORDRET #define STM32F7_I2C_CR2_ADD10			BIT(11)
93aeb068c5SPierre-Yves MORDRET #define STM32F7_I2C_CR2_RD_WRN			BIT(10)
948c7ecc99SPierre-Yves MORDRET #define STM32F7_I2C_CR2_SADD10_MASK		GENMASK(9, 0)
958c7ecc99SPierre-Yves MORDRET #define STM32F7_I2C_CR2_SADD10(n)		(((n) & \
968c7ecc99SPierre-Yves MORDRET 						STM32F7_I2C_CR2_SADD10_MASK))
97aeb068c5SPierre-Yves MORDRET #define STM32F7_I2C_CR2_SADD7_MASK		GENMASK(7, 1)
98aeb068c5SPierre-Yves MORDRET #define STM32F7_I2C_CR2_SADD7(n)		(((n) & 0x7f) << 1)
99aeb068c5SPierre-Yves MORDRET 
10060d609f3SPierre-Yves MORDRET /* STM32F7 I2C Own Address 1 */
10160d609f3SPierre-Yves MORDRET #define STM32F7_I2C_OAR1_OA1EN			BIT(15)
10260d609f3SPierre-Yves MORDRET #define STM32F7_I2C_OAR1_OA1MODE		BIT(10)
10360d609f3SPierre-Yves MORDRET #define STM32F7_I2C_OAR1_OA1_10_MASK		GENMASK(9, 0)
10460d609f3SPierre-Yves MORDRET #define STM32F7_I2C_OAR1_OA1_10(n)		(((n) & \
10560d609f3SPierre-Yves MORDRET 						STM32F7_I2C_OAR1_OA1_10_MASK))
10660d609f3SPierre-Yves MORDRET #define STM32F7_I2C_OAR1_OA1_7_MASK		GENMASK(7, 1)
10760d609f3SPierre-Yves MORDRET #define STM32F7_I2C_OAR1_OA1_7(n)		(((n) & 0x7f) << 1)
10860d609f3SPierre-Yves MORDRET #define STM32F7_I2C_OAR1_MASK			(STM32F7_I2C_OAR1_OA1_7_MASK \
10960d609f3SPierre-Yves MORDRET 						| STM32F7_I2C_OAR1_OA1_10_MASK \
11060d609f3SPierre-Yves MORDRET 						| STM32F7_I2C_OAR1_OA1EN \
11160d609f3SPierre-Yves MORDRET 						| STM32F7_I2C_OAR1_OA1MODE)
11260d609f3SPierre-Yves MORDRET 
11360d609f3SPierre-Yves MORDRET /* STM32F7 I2C Own Address 2 */
11460d609f3SPierre-Yves MORDRET #define STM32F7_I2C_OAR2_OA2EN			BIT(15)
11560d609f3SPierre-Yves MORDRET #define STM32F7_I2C_OAR2_OA2MSK_MASK		GENMASK(10, 8)
11660d609f3SPierre-Yves MORDRET #define STM32F7_I2C_OAR2_OA2MSK(n)		(((n) & 0x7) << 8)
11760d609f3SPierre-Yves MORDRET #define STM32F7_I2C_OAR2_OA2_7_MASK		GENMASK(7, 1)
11860d609f3SPierre-Yves MORDRET #define STM32F7_I2C_OAR2_OA2_7(n)		(((n) & 0x7f) << 1)
11960d609f3SPierre-Yves MORDRET #define STM32F7_I2C_OAR2_MASK			(STM32F7_I2C_OAR2_OA2MSK_MASK \
12060d609f3SPierre-Yves MORDRET 						| STM32F7_I2C_OAR2_OA2_7_MASK \
12160d609f3SPierre-Yves MORDRET 						| STM32F7_I2C_OAR2_OA2EN)
12260d609f3SPierre-Yves MORDRET 
123aeb068c5SPierre-Yves MORDRET /* STM32F7 I2C Interrupt Status */
12460d609f3SPierre-Yves MORDRET #define STM32F7_I2C_ISR_ADDCODE_MASK		GENMASK(23, 17)
12560d609f3SPierre-Yves MORDRET #define STM32F7_I2C_ISR_ADDCODE_GET(n) \
12660d609f3SPierre-Yves MORDRET 				(((n) & STM32F7_I2C_ISR_ADDCODE_MASK) >> 17)
12760d609f3SPierre-Yves MORDRET #define STM32F7_I2C_ISR_DIR			BIT(16)
128aeb068c5SPierre-Yves MORDRET #define STM32F7_I2C_ISR_BUSY			BIT(15)
129c8062d11SAlain Volmat #define STM32F7_I2C_ISR_ALERT			BIT(13)
1309e48155fSPierre-Yves MORDRET #define STM32F7_I2C_ISR_PECERR			BIT(11)
131aeb068c5SPierre-Yves MORDRET #define STM32F7_I2C_ISR_ARLO			BIT(9)
132aeb068c5SPierre-Yves MORDRET #define STM32F7_I2C_ISR_BERR			BIT(8)
133aeb068c5SPierre-Yves MORDRET #define STM32F7_I2C_ISR_TCR			BIT(7)
134aeb068c5SPierre-Yves MORDRET #define STM32F7_I2C_ISR_TC			BIT(6)
135aeb068c5SPierre-Yves MORDRET #define STM32F7_I2C_ISR_STOPF			BIT(5)
136aeb068c5SPierre-Yves MORDRET #define STM32F7_I2C_ISR_NACKF			BIT(4)
13760d609f3SPierre-Yves MORDRET #define STM32F7_I2C_ISR_ADDR			BIT(3)
138aeb068c5SPierre-Yves MORDRET #define STM32F7_I2C_ISR_RXNE			BIT(2)
139aeb068c5SPierre-Yves MORDRET #define STM32F7_I2C_ISR_TXIS			BIT(1)
14060d609f3SPierre-Yves MORDRET #define STM32F7_I2C_ISR_TXE			BIT(0)
141aeb068c5SPierre-Yves MORDRET 
142aeb068c5SPierre-Yves MORDRET /* STM32F7 I2C Interrupt Clear */
143c8062d11SAlain Volmat #define STM32F7_I2C_ICR_ALERTCF			BIT(13)
1449e48155fSPierre-Yves MORDRET #define STM32F7_I2C_ICR_PECCF			BIT(11)
145aeb068c5SPierre-Yves MORDRET #define STM32F7_I2C_ICR_ARLOCF			BIT(9)
146aeb068c5SPierre-Yves MORDRET #define STM32F7_I2C_ICR_BERRCF			BIT(8)
147aeb068c5SPierre-Yves MORDRET #define STM32F7_I2C_ICR_STOPCF			BIT(5)
148aeb068c5SPierre-Yves MORDRET #define STM32F7_I2C_ICR_NACKCF			BIT(4)
14960d609f3SPierre-Yves MORDRET #define STM32F7_I2C_ICR_ADDRCF			BIT(3)
150aeb068c5SPierre-Yves MORDRET 
151aeb068c5SPierre-Yves MORDRET /* STM32F7 I2C Timing */
152aeb068c5SPierre-Yves MORDRET #define STM32F7_I2C_TIMINGR_PRESC(n)		(((n) & 0xf) << 28)
153aeb068c5SPierre-Yves MORDRET #define STM32F7_I2C_TIMINGR_SCLDEL(n)		(((n) & 0xf) << 20)
154aeb068c5SPierre-Yves MORDRET #define STM32F7_I2C_TIMINGR_SDADEL(n)		(((n) & 0xf) << 16)
155aeb068c5SPierre-Yves MORDRET #define STM32F7_I2C_TIMINGR_SCLH(n)		(((n) & 0xff) << 8)
156aeb068c5SPierre-Yves MORDRET #define STM32F7_I2C_TIMINGR_SCLL(n)		((n) & 0xff)
157aeb068c5SPierre-Yves MORDRET 
158aeb068c5SPierre-Yves MORDRET #define STM32F7_I2C_MAX_LEN			0xff
1597ecc8cfdSPierre-Yves MORDRET #define STM32F7_I2C_DMA_LEN_MIN			0x16
160b62590a9SAlain Volmat enum {
161b62590a9SAlain Volmat 	STM32F7_SLAVE_HOSTNOTIFY,
162b62590a9SAlain Volmat 	STM32F7_SLAVE_7_10_BITS_ADDR,
163b62590a9SAlain Volmat 	STM32F7_SLAVE_7_BITS_ADDR,
164b62590a9SAlain Volmat 	STM32F7_I2C_MAX_SLAVE
165b62590a9SAlain Volmat };
166aeb068c5SPierre-Yves MORDRET 
167aeb068c5SPierre-Yves MORDRET #define STM32F7_I2C_DNF_DEFAULT			0
1683d6a3d3aSAlain Volmat #define STM32F7_I2C_DNF_MAX			15
169aeb068c5SPierre-Yves MORDRET 
170aeb068c5SPierre-Yves MORDRET #define STM32F7_I2C_ANALOG_FILTER_DELAY_MIN	50	/* ns */
171aeb068c5SPierre-Yves MORDRET #define STM32F7_I2C_ANALOG_FILTER_DELAY_MAX	260	/* ns */
172aeb068c5SPierre-Yves MORDRET 
173aeb068c5SPierre-Yves MORDRET #define STM32F7_I2C_RISE_TIME_DEFAULT		25	/* ns */
174aeb068c5SPierre-Yves MORDRET #define STM32F7_I2C_FALL_TIME_DEFAULT		10	/* ns */
175aeb068c5SPierre-Yves MORDRET 
176aeb068c5SPierre-Yves MORDRET #define STM32F7_PRESC_MAX			BIT(4)
177aeb068c5SPierre-Yves MORDRET #define STM32F7_SCLDEL_MAX			BIT(4)
178aeb068c5SPierre-Yves MORDRET #define STM32F7_SDADEL_MAX			BIT(4)
179aeb068c5SPierre-Yves MORDRET #define STM32F7_SCLH_MAX			BIT(8)
180aeb068c5SPierre-Yves MORDRET #define STM32F7_SCLL_MAX			BIT(8)
181aeb068c5SPierre-Yves MORDRET 
1824e7bca6fSPierre-Yves MORDRET #define STM32F7_AUTOSUSPEND_DELAY		(HZ / 100)
1834e7bca6fSPierre-Yves MORDRET 
184aeb068c5SPierre-Yves MORDRET /**
185ea6dd25dSAlain Volmat  * struct stm32f7_i2c_regs - i2c f7 registers backup
186ea6dd25dSAlain Volmat  * @cr1: Control register 1
187ea6dd25dSAlain Volmat  * @cr2: Control register 2
188ea6dd25dSAlain Volmat  * @oar1: Own address 1 register
189ea6dd25dSAlain Volmat  * @oar2: Own address 2 register
190ea6dd25dSAlain Volmat  * @tmgr: Timing register
191ea6dd25dSAlain Volmat  */
192ea6dd25dSAlain Volmat struct stm32f7_i2c_regs {
193ea6dd25dSAlain Volmat 	u32 cr1;
194ea6dd25dSAlain Volmat 	u32 cr2;
195ea6dd25dSAlain Volmat 	u32 oar1;
196ea6dd25dSAlain Volmat 	u32 oar2;
197ea6dd25dSAlain Volmat 	u32 tmgr;
198ea6dd25dSAlain Volmat };
199ea6dd25dSAlain Volmat 
200ea6dd25dSAlain Volmat /**
201aeb068c5SPierre-Yves MORDRET  * struct stm32f7_i2c_spec - private i2c specification timing
202aeb068c5SPierre-Yves MORDRET  * @rate: I2C bus speed (Hz)
203aeb068c5SPierre-Yves MORDRET  * @fall_max: Max fall time of both SDA and SCL signals (ns)
204aeb068c5SPierre-Yves MORDRET  * @rise_max: Max rise time of both SDA and SCL signals (ns)
205aeb068c5SPierre-Yves MORDRET  * @hddat_min: Min data hold time (ns)
206aeb068c5SPierre-Yves MORDRET  * @vddat_max: Max data valid time (ns)
207aeb068c5SPierre-Yves MORDRET  * @sudat_min: Min data setup time (ns)
208aeb068c5SPierre-Yves MORDRET  * @l_min: Min low period of the SCL clock (ns)
209aeb068c5SPierre-Yves MORDRET  * @h_min: Min high period of the SCL clock (ns)
210aeb068c5SPierre-Yves MORDRET  */
211aeb068c5SPierre-Yves MORDRET struct stm32f7_i2c_spec {
212aeb068c5SPierre-Yves MORDRET 	u32 rate;
213aeb068c5SPierre-Yves MORDRET 	u32 fall_max;
214aeb068c5SPierre-Yves MORDRET 	u32 rise_max;
215aeb068c5SPierre-Yves MORDRET 	u32 hddat_min;
216aeb068c5SPierre-Yves MORDRET 	u32 vddat_max;
217aeb068c5SPierre-Yves MORDRET 	u32 sudat_min;
218aeb068c5SPierre-Yves MORDRET 	u32 l_min;
219aeb068c5SPierre-Yves MORDRET 	u32 h_min;
220aeb068c5SPierre-Yves MORDRET };
221aeb068c5SPierre-Yves MORDRET 
222aeb068c5SPierre-Yves MORDRET /**
223aeb068c5SPierre-Yves MORDRET  * struct stm32f7_i2c_setup - private I2C timing setup parameters
224aeb068c5SPierre-Yves MORDRET  * @speed_freq: I2C speed frequency  (Hz)
225aeb068c5SPierre-Yves MORDRET  * @clock_src: I2C clock source frequency (Hz)
226aeb068c5SPierre-Yves MORDRET  * @rise_time: Rise time (ns)
227aeb068c5SPierre-Yves MORDRET  * @fall_time: Fall time (ns)
2280f820564SAlain Volmat  * @fmp_clr_offset: Fast Mode Plus clear register offset from set register
229aeb068c5SPierre-Yves MORDRET  */
230aeb068c5SPierre-Yves MORDRET struct stm32f7_i2c_setup {
231aeb068c5SPierre-Yves MORDRET 	u32 speed_freq;
232aeb068c5SPierre-Yves MORDRET 	u32 clock_src;
233aeb068c5SPierre-Yves MORDRET 	u32 rise_time;
234aeb068c5SPierre-Yves MORDRET 	u32 fall_time;
2350f820564SAlain Volmat 	u32 fmp_clr_offset;
236aeb068c5SPierre-Yves MORDRET };
237aeb068c5SPierre-Yves MORDRET 
238aeb068c5SPierre-Yves MORDRET /**
239aeb068c5SPierre-Yves MORDRET  * struct stm32f7_i2c_timings - private I2C output parameters
240c599eb4fSPierre-Yves MORDRET  * @node: List entry
241c599eb4fSPierre-Yves MORDRET  * @presc: Prescaler value
242aeb068c5SPierre-Yves MORDRET  * @scldel: Data setup time
243aeb068c5SPierre-Yves MORDRET  * @sdadel: Data hold time
244aeb068c5SPierre-Yves MORDRET  * @sclh: SCL high period (master mode)
245c599eb4fSPierre-Yves MORDRET  * @scll: SCL low period (master mode)
246aeb068c5SPierre-Yves MORDRET  */
247aeb068c5SPierre-Yves MORDRET struct stm32f7_i2c_timings {
248aeb068c5SPierre-Yves MORDRET 	struct list_head node;
249aeb068c5SPierre-Yves MORDRET 	u8 presc;
250aeb068c5SPierre-Yves MORDRET 	u8 scldel;
251aeb068c5SPierre-Yves MORDRET 	u8 sdadel;
252aeb068c5SPierre-Yves MORDRET 	u8 sclh;
253aeb068c5SPierre-Yves MORDRET 	u8 scll;
254aeb068c5SPierre-Yves MORDRET };
255aeb068c5SPierre-Yves MORDRET 
256aeb068c5SPierre-Yves MORDRET /**
257aeb068c5SPierre-Yves MORDRET  * struct stm32f7_i2c_msg - client specific data
2588c7ecc99SPierre-Yves MORDRET  * @addr: 8-bit or 10-bit slave addr, including r/w bit
259aeb068c5SPierre-Yves MORDRET  * @count: number of bytes to be transferred
260aeb068c5SPierre-Yves MORDRET  * @buf: data buffer
261aeb068c5SPierre-Yves MORDRET  * @result: result of the transfer
262aeb068c5SPierre-Yves MORDRET  * @stop: last I2C msg to be sent, i.e. STOP to be generated
2639e48155fSPierre-Yves MORDRET  * @smbus: boolean to know if the I2C IP is used in SMBus mode
2649e48155fSPierre-Yves MORDRET  * @size: type of SMBus protocol
2659e48155fSPierre-Yves MORDRET  * @read_write: direction of SMBus protocol
2669e48155fSPierre-Yves MORDRET  * SMBus block read and SMBus block write - block read process call protocols
267c599eb4fSPierre-Yves MORDRET  * @smbus_buf: buffer to be used for SMBus protocol transfer. It will
2689e48155fSPierre-Yves MORDRET  * contain a maximum of 32 bytes of data + byte command + byte count + PEC
2699e48155fSPierre-Yves MORDRET  * This buffer has to be 32-bit aligned to be compliant with memory address
2709e48155fSPierre-Yves MORDRET  * register in DMA mode.
271aeb068c5SPierre-Yves MORDRET  */
272aeb068c5SPierre-Yves MORDRET struct stm32f7_i2c_msg {
2738c7ecc99SPierre-Yves MORDRET 	u16 addr;
274aeb068c5SPierre-Yves MORDRET 	u32 count;
275aeb068c5SPierre-Yves MORDRET 	u8 *buf;
276aeb068c5SPierre-Yves MORDRET 	int result;
277aeb068c5SPierre-Yves MORDRET 	bool stop;
2789e48155fSPierre-Yves MORDRET 	bool smbus;
2799e48155fSPierre-Yves MORDRET 	int size;
2809e48155fSPierre-Yves MORDRET 	char read_write;
2819e48155fSPierre-Yves MORDRET 	u8 smbus_buf[I2C_SMBUS_BLOCK_MAX + 3] __aligned(4);
282aeb068c5SPierre-Yves MORDRET };
283aeb068c5SPierre-Yves MORDRET 
284aeb068c5SPierre-Yves MORDRET /**
285c8062d11SAlain Volmat  * struct stm32f7_i2c_alert - SMBus alert specific data
286c8062d11SAlain Volmat  * @setup: platform data for the smbus_alert i2c client
287c8062d11SAlain Volmat  * @ara: I2C slave device used to respond to the SMBus Alert with Alert
288c8062d11SAlain Volmat  * Response Address
289c8062d11SAlain Volmat  */
290c8062d11SAlain Volmat struct stm32f7_i2c_alert {
291c8062d11SAlain Volmat 	struct i2c_smbus_alert_setup setup;
292c8062d11SAlain Volmat 	struct i2c_client *ara;
293c8062d11SAlain Volmat };
294c8062d11SAlain Volmat 
295c8062d11SAlain Volmat /**
296aeb068c5SPierre-Yves MORDRET  * struct stm32f7_i2c_dev - private data of the controller
297aeb068c5SPierre-Yves MORDRET  * @adap: I2C adapter for this controller
298aeb068c5SPierre-Yves MORDRET  * @dev: device for this controller
299aeb068c5SPierre-Yves MORDRET  * @base: virtual memory area
300aeb068c5SPierre-Yves MORDRET  * @complete: completion of I2C message
301aeb068c5SPierre-Yves MORDRET  * @clk: hw i2c clock
30209cc9a3bSAlain Volmat  * @bus_rate: I2C clock frequency of the controller
303aeb068c5SPierre-Yves MORDRET  * @msg: Pointer to data to be written
304aeb068c5SPierre-Yves MORDRET  * @msg_num: number of I2C messages to be executed
305aeb068c5SPierre-Yves MORDRET  * @msg_id: message identifiant
306aeb068c5SPierre-Yves MORDRET  * @f7_msg: customized i2c msg for driver usage
307aeb068c5SPierre-Yves MORDRET  * @setup: I2C timing input setup
308aeb068c5SPierre-Yves MORDRET  * @timing: I2C computed timings
30960d609f3SPierre-Yves MORDRET  * @slave: list of slave devices registered on the I2C bus
31060d609f3SPierre-Yves MORDRET  * @slave_running: slave device currently used
311ea6dd25dSAlain Volmat  * @backup_regs: backup of i2c controller registers (for suspend/resume)
31260d609f3SPierre-Yves MORDRET  * @slave_dir: transfer direction for the current slave device
31360d609f3SPierre-Yves MORDRET  * @master_mode: boolean to know in which mode the I2C is running (master or
31460d609f3SPierre-Yves MORDRET  * slave)
3157ecc8cfdSPierre-Yves MORDRET  * @dma: dma data
3167ecc8cfdSPierre-Yves MORDRET  * @use_dma: boolean to know if dma is used in the current transfer
317cb944fb9SPierre-Yves MORDRET  * @regmap: holds SYSCFG phandle for Fast Mode Plus bits
3180f820564SAlain Volmat  * @fmp_sreg: register address for setting Fast Mode Plus bits
3190f820564SAlain Volmat  * @fmp_creg: register address for clearing Fast Mode Plus bits
3203347ea9bSAlain Volmat  * @fmp_mask: mask for Fast Mode Plus bits in set register
321419be8e1SAlain Volmat  * @wakeup_src: boolean to know if the device is a wakeup source
3226af07719SAlain Volmat  * @smbus_mode: states that the controller is configured in SMBus mode
3236af07719SAlain Volmat  * @host_notify_client: SMBus host-notify client
32483c3408fSAlain Volmat  * @analog_filter: boolean to indicate enabling of the analog filter
3259449a558SAlain Volmat  * @dnf_dt: value of digital filter requested via dt
3269449a558SAlain Volmat  * @dnf: value of digital filter to apply
327c8062d11SAlain Volmat  * @alert: SMBus alert specific data
328aeb068c5SPierre-Yves MORDRET  */
329aeb068c5SPierre-Yves MORDRET struct stm32f7_i2c_dev {
330aeb068c5SPierre-Yves MORDRET 	struct i2c_adapter adap;
331aeb068c5SPierre-Yves MORDRET 	struct device *dev;
332aeb068c5SPierre-Yves MORDRET 	void __iomem *base;
333aeb068c5SPierre-Yves MORDRET 	struct completion complete;
334aeb068c5SPierre-Yves MORDRET 	struct clk *clk;
33509cc9a3bSAlain Volmat 	unsigned int bus_rate;
336aeb068c5SPierre-Yves MORDRET 	struct i2c_msg *msg;
337aeb068c5SPierre-Yves MORDRET 	unsigned int msg_num;
338aeb068c5SPierre-Yves MORDRET 	unsigned int msg_id;
339aeb068c5SPierre-Yves MORDRET 	struct stm32f7_i2c_msg f7_msg;
340463a9215SPierre-Yves MORDRET 	struct stm32f7_i2c_setup setup;
341aeb068c5SPierre-Yves MORDRET 	struct stm32f7_i2c_timings timing;
34260d609f3SPierre-Yves MORDRET 	struct i2c_client *slave[STM32F7_I2C_MAX_SLAVE];
34360d609f3SPierre-Yves MORDRET 	struct i2c_client *slave_running;
344ea6dd25dSAlain Volmat 	struct stm32f7_i2c_regs backup_regs;
34560d609f3SPierre-Yves MORDRET 	u32 slave_dir;
34660d609f3SPierre-Yves MORDRET 	bool master_mode;
3477ecc8cfdSPierre-Yves MORDRET 	struct stm32_i2c_dma *dma;
3487ecc8cfdSPierre-Yves MORDRET 	bool use_dma;
349cb944fb9SPierre-Yves MORDRET 	struct regmap *regmap;
3500f820564SAlain Volmat 	u32 fmp_sreg;
3510f820564SAlain Volmat 	u32 fmp_creg;
3523347ea9bSAlain Volmat 	u32 fmp_mask;
353419be8e1SAlain Volmat 	bool wakeup_src;
3546af07719SAlain Volmat 	bool smbus_mode;
3556af07719SAlain Volmat 	struct i2c_client *host_notify_client;
35683c3408fSAlain Volmat 	bool analog_filter;
3579449a558SAlain Volmat 	u32 dnf_dt;
3589449a558SAlain Volmat 	u32 dnf;
359c8062d11SAlain Volmat 	struct stm32f7_i2c_alert *alert;
360aeb068c5SPierre-Yves MORDRET };
361aeb068c5SPierre-Yves MORDRET 
362348e46fbSAlain Volmat /*
363aeb068c5SPierre-Yves MORDRET  * All these values are coming from I2C Specification, Version 6.0, 4th of
364aeb068c5SPierre-Yves MORDRET  * April 2014.
365aeb068c5SPierre-Yves MORDRET  *
366aeb068c5SPierre-Yves MORDRET  * Table10. Characteristics of the SDA and SCL bus lines for Standard, Fast,
367aeb068c5SPierre-Yves MORDRET  * and Fast-mode Plus I2C-bus devices
368aeb068c5SPierre-Yves MORDRET  */
36909cc9a3bSAlain Volmat static struct stm32f7_i2c_spec stm32f7_i2c_specs[] = {
37009cc9a3bSAlain Volmat 	{
37183672db7SAndy Shevchenko 		.rate = I2C_MAX_STANDARD_MODE_FREQ,
372aeb068c5SPierre-Yves MORDRET 		.fall_max = 300,
373aeb068c5SPierre-Yves MORDRET 		.rise_max = 1000,
374aeb068c5SPierre-Yves MORDRET 		.hddat_min = 0,
375aeb068c5SPierre-Yves MORDRET 		.vddat_max = 3450,
376aeb068c5SPierre-Yves MORDRET 		.sudat_min = 250,
377aeb068c5SPierre-Yves MORDRET 		.l_min = 4700,
378aeb068c5SPierre-Yves MORDRET 		.h_min = 4000,
379aeb068c5SPierre-Yves MORDRET 	},
38009cc9a3bSAlain Volmat 	{
38183672db7SAndy Shevchenko 		.rate = I2C_MAX_FAST_MODE_FREQ,
382aeb068c5SPierre-Yves MORDRET 		.fall_max = 300,
383aeb068c5SPierre-Yves MORDRET 		.rise_max = 300,
384aeb068c5SPierre-Yves MORDRET 		.hddat_min = 0,
385aeb068c5SPierre-Yves MORDRET 		.vddat_max = 900,
386aeb068c5SPierre-Yves MORDRET 		.sudat_min = 100,
387aeb068c5SPierre-Yves MORDRET 		.l_min = 1300,
388aeb068c5SPierre-Yves MORDRET 		.h_min = 600,
389aeb068c5SPierre-Yves MORDRET 	},
39009cc9a3bSAlain Volmat 	{
39183672db7SAndy Shevchenko 		.rate = I2C_MAX_FAST_MODE_PLUS_FREQ,
392aeb068c5SPierre-Yves MORDRET 		.fall_max = 100,
393aeb068c5SPierre-Yves MORDRET 		.rise_max = 120,
394aeb068c5SPierre-Yves MORDRET 		.hddat_min = 0,
395aeb068c5SPierre-Yves MORDRET 		.vddat_max = 450,
396aeb068c5SPierre-Yves MORDRET 		.sudat_min = 50,
397aeb068c5SPierre-Yves MORDRET 		.l_min = 500,
398aeb068c5SPierre-Yves MORDRET 		.h_min = 260,
399aeb068c5SPierre-Yves MORDRET 	},
400aeb068c5SPierre-Yves MORDRET };
401aeb068c5SPierre-Yves MORDRET 
40225f2f440SColin Ian King static const struct stm32f7_i2c_setup stm32f7_setup = {
403aeb068c5SPierre-Yves MORDRET 	.rise_time = STM32F7_I2C_RISE_TIME_DEFAULT,
404aeb068c5SPierre-Yves MORDRET 	.fall_time = STM32F7_I2C_FALL_TIME_DEFAULT,
405aeb068c5SPierre-Yves MORDRET };
406aeb068c5SPierre-Yves MORDRET 
4070f820564SAlain Volmat static const struct stm32f7_i2c_setup stm32mp15_setup = {
4080f820564SAlain Volmat 	.rise_time = STM32F7_I2C_RISE_TIME_DEFAULT,
4090f820564SAlain Volmat 	.fall_time = STM32F7_I2C_FALL_TIME_DEFAULT,
4100f820564SAlain Volmat 	.fmp_clr_offset = 0x40,
4110f820564SAlain Volmat };
4120f820564SAlain Volmat 
413d4d2f170SAlain Volmat static const struct stm32f7_i2c_setup stm32mp13_setup = {
414d4d2f170SAlain Volmat 	.rise_time = STM32F7_I2C_RISE_TIME_DEFAULT,
415d4d2f170SAlain Volmat 	.fall_time = STM32F7_I2C_FALL_TIME_DEFAULT,
416d4d2f170SAlain Volmat 	.fmp_clr_offset = 0x4,
417d4d2f170SAlain Volmat };
418d4d2f170SAlain Volmat 
stm32f7_i2c_set_bits(void __iomem * reg,u32 mask)419aeb068c5SPierre-Yves MORDRET static inline void stm32f7_i2c_set_bits(void __iomem *reg, u32 mask)
420aeb068c5SPierre-Yves MORDRET {
421aeb068c5SPierre-Yves MORDRET 	writel_relaxed(readl_relaxed(reg) | mask, reg);
422aeb068c5SPierre-Yves MORDRET }
423aeb068c5SPierre-Yves MORDRET 
stm32f7_i2c_clr_bits(void __iomem * reg,u32 mask)424aeb068c5SPierre-Yves MORDRET static inline void stm32f7_i2c_clr_bits(void __iomem *reg, u32 mask)
425aeb068c5SPierre-Yves MORDRET {
426aeb068c5SPierre-Yves MORDRET 	writel_relaxed(readl_relaxed(reg) & ~mask, reg);
427aeb068c5SPierre-Yves MORDRET }
428aeb068c5SPierre-Yves MORDRET 
stm32f7_i2c_disable_irq(struct stm32f7_i2c_dev * i2c_dev,u32 mask)42960d609f3SPierre-Yves MORDRET static void stm32f7_i2c_disable_irq(struct stm32f7_i2c_dev *i2c_dev, u32 mask)
43060d609f3SPierre-Yves MORDRET {
43160d609f3SPierre-Yves MORDRET 	stm32f7_i2c_clr_bits(i2c_dev->base + STM32F7_I2C_CR1, mask);
43260d609f3SPierre-Yves MORDRET }
43360d609f3SPierre-Yves MORDRET 
stm32f7_get_specs(u32 rate)43409cc9a3bSAlain Volmat static struct stm32f7_i2c_spec *stm32f7_get_specs(u32 rate)
43509cc9a3bSAlain Volmat {
43609cc9a3bSAlain Volmat 	int i;
43709cc9a3bSAlain Volmat 
43809cc9a3bSAlain Volmat 	for (i = 0; i < ARRAY_SIZE(stm32f7_i2c_specs); i++)
43909cc9a3bSAlain Volmat 		if (rate <= stm32f7_i2c_specs[i].rate)
44009cc9a3bSAlain Volmat 			return &stm32f7_i2c_specs[i];
44109cc9a3bSAlain Volmat 
44209cc9a3bSAlain Volmat 	return ERR_PTR(-EINVAL);
44309cc9a3bSAlain Volmat }
44409cc9a3bSAlain Volmat 
44509cc9a3bSAlain Volmat #define	RATE_MIN(rate)	((rate) * 8 / 10)
stm32f7_i2c_compute_timing(struct stm32f7_i2c_dev * i2c_dev,struct stm32f7_i2c_setup * setup,struct stm32f7_i2c_timings * output)446aeb068c5SPierre-Yves MORDRET static int stm32f7_i2c_compute_timing(struct stm32f7_i2c_dev *i2c_dev,
447aeb068c5SPierre-Yves MORDRET 				      struct stm32f7_i2c_setup *setup,
448aeb068c5SPierre-Yves MORDRET 				      struct stm32f7_i2c_timings *output)
449aeb068c5SPierre-Yves MORDRET {
45009cc9a3bSAlain Volmat 	struct stm32f7_i2c_spec *specs;
451aeb068c5SPierre-Yves MORDRET 	u32 p_prev = STM32F7_PRESC_MAX;
452aeb068c5SPierre-Yves MORDRET 	u32 i2cclk = DIV_ROUND_CLOSEST(NSEC_PER_SEC,
453aeb068c5SPierre-Yves MORDRET 				       setup->clock_src);
454aeb068c5SPierre-Yves MORDRET 	u32 i2cbus = DIV_ROUND_CLOSEST(NSEC_PER_SEC,
455aeb068c5SPierre-Yves MORDRET 				       setup->speed_freq);
456aeb068c5SPierre-Yves MORDRET 	u32 clk_error_prev = i2cbus;
457aeb068c5SPierre-Yves MORDRET 	u32 tsync;
458aeb068c5SPierre-Yves MORDRET 	u32 af_delay_min, af_delay_max;
459aeb068c5SPierre-Yves MORDRET 	u32 dnf_delay;
460aeb068c5SPierre-Yves MORDRET 	u32 clk_min, clk_max;
461aeb068c5SPierre-Yves MORDRET 	int sdadel_min, sdadel_max;
462aeb068c5SPierre-Yves MORDRET 	int scldel_min;
463aeb068c5SPierre-Yves MORDRET 	struct stm32f7_i2c_timings *v, *_v, *s;
464aeb068c5SPierre-Yves MORDRET 	struct list_head solutions;
465aeb068c5SPierre-Yves MORDRET 	u16 p, l, a, h;
466aeb068c5SPierre-Yves MORDRET 	int ret = 0;
467aeb068c5SPierre-Yves MORDRET 
46809cc9a3bSAlain Volmat 	specs = stm32f7_get_specs(setup->speed_freq);
46909cc9a3bSAlain Volmat 	if (specs == ERR_PTR(-EINVAL)) {
47009cc9a3bSAlain Volmat 		dev_err(i2c_dev->dev, "speed out of bound {%d}\n",
47109cc9a3bSAlain Volmat 			setup->speed_freq);
472aeb068c5SPierre-Yves MORDRET 		return -EINVAL;
473aeb068c5SPierre-Yves MORDRET 	}
474aeb068c5SPierre-Yves MORDRET 
47509cc9a3bSAlain Volmat 	if ((setup->rise_time > specs->rise_max) ||
47609cc9a3bSAlain Volmat 	    (setup->fall_time > specs->fall_max)) {
477aeb068c5SPierre-Yves MORDRET 		dev_err(i2c_dev->dev,
478aeb068c5SPierre-Yves MORDRET 			"timings out of bound Rise{%d>%d}/Fall{%d>%d}\n",
47909cc9a3bSAlain Volmat 			setup->rise_time, specs->rise_max,
48009cc9a3bSAlain Volmat 			setup->fall_time, specs->fall_max);
481aeb068c5SPierre-Yves MORDRET 		return -EINVAL;
482aeb068c5SPierre-Yves MORDRET 	}
483aeb068c5SPierre-Yves MORDRET 
4849449a558SAlain Volmat 	i2c_dev->dnf = DIV_ROUND_CLOSEST(i2c_dev->dnf_dt, i2cclk);
4859449a558SAlain Volmat 	if (i2c_dev->dnf > STM32F7_I2C_DNF_MAX) {
486aeb068c5SPierre-Yves MORDRET 		dev_err(i2c_dev->dev,
487aeb068c5SPierre-Yves MORDRET 			"DNF out of bound %d/%d\n",
4889449a558SAlain Volmat 			i2c_dev->dnf * i2cclk, STM32F7_I2C_DNF_MAX * i2cclk);
489aeb068c5SPierre-Yves MORDRET 		return -EINVAL;
490aeb068c5SPierre-Yves MORDRET 	}
491aeb068c5SPierre-Yves MORDRET 
492aeb068c5SPierre-Yves MORDRET 	/*  Analog and Digital Filters */
493aeb068c5SPierre-Yves MORDRET 	af_delay_min =
49483c3408fSAlain Volmat 		(i2c_dev->analog_filter ?
495aeb068c5SPierre-Yves MORDRET 		 STM32F7_I2C_ANALOG_FILTER_DELAY_MIN : 0);
496aeb068c5SPierre-Yves MORDRET 	af_delay_max =
49783c3408fSAlain Volmat 		(i2c_dev->analog_filter ?
498aeb068c5SPierre-Yves MORDRET 		 STM32F7_I2C_ANALOG_FILTER_DELAY_MAX : 0);
4999449a558SAlain Volmat 	dnf_delay = i2c_dev->dnf * i2cclk;
500aeb068c5SPierre-Yves MORDRET 
50109cc9a3bSAlain Volmat 	sdadel_min = specs->hddat_min + setup->fall_time -
5029449a558SAlain Volmat 		af_delay_min - (i2c_dev->dnf + 3) * i2cclk;
503aeb068c5SPierre-Yves MORDRET 
50409cc9a3bSAlain Volmat 	sdadel_max = specs->vddat_max - setup->rise_time -
5059449a558SAlain Volmat 		af_delay_max - (i2c_dev->dnf + 4) * i2cclk;
506aeb068c5SPierre-Yves MORDRET 
50709cc9a3bSAlain Volmat 	scldel_min = setup->rise_time + specs->sudat_min;
508aeb068c5SPierre-Yves MORDRET 
509aeb068c5SPierre-Yves MORDRET 	if (sdadel_min < 0)
510aeb068c5SPierre-Yves MORDRET 		sdadel_min = 0;
511aeb068c5SPierre-Yves MORDRET 	if (sdadel_max < 0)
512aeb068c5SPierre-Yves MORDRET 		sdadel_max = 0;
513aeb068c5SPierre-Yves MORDRET 
514aeb068c5SPierre-Yves MORDRET 	dev_dbg(i2c_dev->dev, "SDADEL(min/max): %i/%i, SCLDEL(Min): %i\n",
515aeb068c5SPierre-Yves MORDRET 		sdadel_min, sdadel_max, scldel_min);
516aeb068c5SPierre-Yves MORDRET 
517aeb068c5SPierre-Yves MORDRET 	INIT_LIST_HEAD(&solutions);
518aeb068c5SPierre-Yves MORDRET 	/* Compute possible values for PRESC, SCLDEL and SDADEL */
519aeb068c5SPierre-Yves MORDRET 	for (p = 0; p < STM32F7_PRESC_MAX; p++) {
520aeb068c5SPierre-Yves MORDRET 		for (l = 0; l < STM32F7_SCLDEL_MAX; l++) {
521aeb068c5SPierre-Yves MORDRET 			u32 scldel = (l + 1) * (p + 1) * i2cclk;
522aeb068c5SPierre-Yves MORDRET 
523aeb068c5SPierre-Yves MORDRET 			if (scldel < scldel_min)
524aeb068c5SPierre-Yves MORDRET 				continue;
525aeb068c5SPierre-Yves MORDRET 
526aeb068c5SPierre-Yves MORDRET 			for (a = 0; a < STM32F7_SDADEL_MAX; a++) {
527aeb068c5SPierre-Yves MORDRET 				u32 sdadel = (a * (p + 1) + 1) * i2cclk;
528aeb068c5SPierre-Yves MORDRET 
529aeb068c5SPierre-Yves MORDRET 				if (((sdadel >= sdadel_min) &&
530aeb068c5SPierre-Yves MORDRET 				     (sdadel <= sdadel_max)) &&
531aeb068c5SPierre-Yves MORDRET 				    (p != p_prev)) {
532aeb068c5SPierre-Yves MORDRET 					v = kmalloc(sizeof(*v), GFP_KERNEL);
533aeb068c5SPierre-Yves MORDRET 					if (!v) {
534aeb068c5SPierre-Yves MORDRET 						ret = -ENOMEM;
535aeb068c5SPierre-Yves MORDRET 						goto exit;
536aeb068c5SPierre-Yves MORDRET 					}
537aeb068c5SPierre-Yves MORDRET 
538aeb068c5SPierre-Yves MORDRET 					v->presc = p;
539aeb068c5SPierre-Yves MORDRET 					v->scldel = l;
540aeb068c5SPierre-Yves MORDRET 					v->sdadel = a;
541aeb068c5SPierre-Yves MORDRET 					p_prev = p;
542aeb068c5SPierre-Yves MORDRET 
543aeb068c5SPierre-Yves MORDRET 					list_add_tail(&v->node,
544aeb068c5SPierre-Yves MORDRET 						      &solutions);
5450d735031SNicolas Le Bayon 					break;
546aeb068c5SPierre-Yves MORDRET 				}
547aeb068c5SPierre-Yves MORDRET 			}
5480d735031SNicolas Le Bayon 
5490d735031SNicolas Le Bayon 			if (p_prev == p)
5500d735031SNicolas Le Bayon 				break;
551aeb068c5SPierre-Yves MORDRET 		}
552aeb068c5SPierre-Yves MORDRET 	}
553aeb068c5SPierre-Yves MORDRET 
554aeb068c5SPierre-Yves MORDRET 	if (list_empty(&solutions)) {
555aeb068c5SPierre-Yves MORDRET 		dev_err(i2c_dev->dev, "no Prescaler solution\n");
556aeb068c5SPierre-Yves MORDRET 		ret = -EPERM;
557aeb068c5SPierre-Yves MORDRET 		goto exit;
558aeb068c5SPierre-Yves MORDRET 	}
559aeb068c5SPierre-Yves MORDRET 
560aeb068c5SPierre-Yves MORDRET 	tsync = af_delay_min + dnf_delay + (2 * i2cclk);
561aeb068c5SPierre-Yves MORDRET 	s = NULL;
56209cc9a3bSAlain Volmat 	clk_max = NSEC_PER_SEC / RATE_MIN(setup->speed_freq);
56309cc9a3bSAlain Volmat 	clk_min = NSEC_PER_SEC / setup->speed_freq;
564aeb068c5SPierre-Yves MORDRET 
565aeb068c5SPierre-Yves MORDRET 	/*
566aeb068c5SPierre-Yves MORDRET 	 * Among Prescaler possibilities discovered above figures out SCL Low
567aeb068c5SPierre-Yves MORDRET 	 * and High Period. Provided:
568aeb068c5SPierre-Yves MORDRET 	 * - SCL Low Period has to be higher than SCL Clock Low Period
569aeb068c5SPierre-Yves MORDRET 	 *   defined by I2C Specification. I2C Clock has to be lower than
570aeb068c5SPierre-Yves MORDRET 	 *   (SCL Low Period - Analog/Digital filters) / 4.
571aeb068c5SPierre-Yves MORDRET 	 * - SCL High Period has to be lower than SCL Clock High Period
572aeb068c5SPierre-Yves MORDRET 	 *   defined by I2C Specification
573aeb068c5SPierre-Yves MORDRET 	 * - I2C Clock has to be lower than SCL High Period
574aeb068c5SPierre-Yves MORDRET 	 */
575aeb068c5SPierre-Yves MORDRET 	list_for_each_entry(v, &solutions, node) {
576aeb068c5SPierre-Yves MORDRET 		u32 prescaler = (v->presc + 1) * i2cclk;
577aeb068c5SPierre-Yves MORDRET 
578aeb068c5SPierre-Yves MORDRET 		for (l = 0; l < STM32F7_SCLL_MAX; l++) {
579aeb068c5SPierre-Yves MORDRET 			u32 tscl_l = (l + 1) * prescaler + tsync;
580aeb068c5SPierre-Yves MORDRET 
58109cc9a3bSAlain Volmat 			if ((tscl_l < specs->l_min) ||
582aeb068c5SPierre-Yves MORDRET 			    (i2cclk >=
583aeb068c5SPierre-Yves MORDRET 			     ((tscl_l - af_delay_min - dnf_delay) / 4))) {
584aeb068c5SPierre-Yves MORDRET 				continue;
585aeb068c5SPierre-Yves MORDRET 			}
586aeb068c5SPierre-Yves MORDRET 
587aeb068c5SPierre-Yves MORDRET 			for (h = 0; h < STM32F7_SCLH_MAX; h++) {
588aeb068c5SPierre-Yves MORDRET 				u32 tscl_h = (h + 1) * prescaler + tsync;
589aeb068c5SPierre-Yves MORDRET 				u32 tscl = tscl_l + tscl_h +
590aeb068c5SPierre-Yves MORDRET 					setup->rise_time + setup->fall_time;
591aeb068c5SPierre-Yves MORDRET 
592aeb068c5SPierre-Yves MORDRET 				if ((tscl >= clk_min) && (tscl <= clk_max) &&
59309cc9a3bSAlain Volmat 				    (tscl_h >= specs->h_min) &&
594aeb068c5SPierre-Yves MORDRET 				    (i2cclk < tscl_h)) {
595aeb068c5SPierre-Yves MORDRET 					int clk_error = tscl - i2cbus;
596aeb068c5SPierre-Yves MORDRET 
597aeb068c5SPierre-Yves MORDRET 					if (clk_error < 0)
598aeb068c5SPierre-Yves MORDRET 						clk_error = -clk_error;
599aeb068c5SPierre-Yves MORDRET 
600aeb068c5SPierre-Yves MORDRET 					if (clk_error < clk_error_prev) {
601aeb068c5SPierre-Yves MORDRET 						clk_error_prev = clk_error;
602aeb068c5SPierre-Yves MORDRET 						v->scll = l;
603aeb068c5SPierre-Yves MORDRET 						v->sclh = h;
604aeb068c5SPierre-Yves MORDRET 						s = v;
605aeb068c5SPierre-Yves MORDRET 					}
606aeb068c5SPierre-Yves MORDRET 				}
607aeb068c5SPierre-Yves MORDRET 			}
608aeb068c5SPierre-Yves MORDRET 		}
609aeb068c5SPierre-Yves MORDRET 	}
610aeb068c5SPierre-Yves MORDRET 
611aeb068c5SPierre-Yves MORDRET 	if (!s) {
612aeb068c5SPierre-Yves MORDRET 		dev_err(i2c_dev->dev, "no solution at all\n");
613aeb068c5SPierre-Yves MORDRET 		ret = -EPERM;
614aeb068c5SPierre-Yves MORDRET 		goto exit;
615aeb068c5SPierre-Yves MORDRET 	}
616aeb068c5SPierre-Yves MORDRET 
617aeb068c5SPierre-Yves MORDRET 	output->presc = s->presc;
618aeb068c5SPierre-Yves MORDRET 	output->scldel = s->scldel;
619aeb068c5SPierre-Yves MORDRET 	output->sdadel = s->sdadel;
620aeb068c5SPierre-Yves MORDRET 	output->scll = s->scll;
621aeb068c5SPierre-Yves MORDRET 	output->sclh = s->sclh;
622aeb068c5SPierre-Yves MORDRET 
623aeb068c5SPierre-Yves MORDRET 	dev_dbg(i2c_dev->dev,
624aeb068c5SPierre-Yves MORDRET 		"Presc: %i, scldel: %i, sdadel: %i, scll: %i, sclh: %i\n",
625aeb068c5SPierre-Yves MORDRET 		output->presc,
626aeb068c5SPierre-Yves MORDRET 		output->scldel, output->sdadel,
627aeb068c5SPierre-Yves MORDRET 		output->scll, output->sclh);
628aeb068c5SPierre-Yves MORDRET 
629aeb068c5SPierre-Yves MORDRET exit:
630aeb068c5SPierre-Yves MORDRET 	/* Release list and memory */
631aeb068c5SPierre-Yves MORDRET 	list_for_each_entry_safe(v, _v, &solutions, node) {
632aeb068c5SPierre-Yves MORDRET 		list_del(&v->node);
633aeb068c5SPierre-Yves MORDRET 		kfree(v);
634aeb068c5SPierre-Yves MORDRET 	}
635aeb068c5SPierre-Yves MORDRET 
636aeb068c5SPierre-Yves MORDRET 	return ret;
637aeb068c5SPierre-Yves MORDRET }
638aeb068c5SPierre-Yves MORDRET 
stm32f7_get_lower_rate(u32 rate)63909cc9a3bSAlain Volmat static u32 stm32f7_get_lower_rate(u32 rate)
64009cc9a3bSAlain Volmat {
64109cc9a3bSAlain Volmat 	int i = ARRAY_SIZE(stm32f7_i2c_specs);
64209cc9a3bSAlain Volmat 
64308736e83SDan Carpenter 	while (--i)
64409cc9a3bSAlain Volmat 		if (stm32f7_i2c_specs[i].rate < rate)
64509cc9a3bSAlain Volmat 			break;
64609cc9a3bSAlain Volmat 
64709cc9a3bSAlain Volmat 	return stm32f7_i2c_specs[i].rate;
64809cc9a3bSAlain Volmat }
64909cc9a3bSAlain Volmat 
stm32f7_i2c_setup_timing(struct stm32f7_i2c_dev * i2c_dev,struct stm32f7_i2c_setup * setup)650aeb068c5SPierre-Yves MORDRET static int stm32f7_i2c_setup_timing(struct stm32f7_i2c_dev *i2c_dev,
651aeb068c5SPierre-Yves MORDRET 				    struct stm32f7_i2c_setup *setup)
652aeb068c5SPierre-Yves MORDRET {
65383672db7SAndy Shevchenko 	struct i2c_timings timings, *t = &timings;
654aeb068c5SPierre-Yves MORDRET 	int ret = 0;
655aeb068c5SPierre-Yves MORDRET 
65683672db7SAndy Shevchenko 	t->bus_freq_hz = I2C_MAX_STANDARD_MODE_FREQ;
65783672db7SAndy Shevchenko 	t->scl_rise_ns = i2c_dev->setup.rise_time;
65883672db7SAndy Shevchenko 	t->scl_fall_ns = i2c_dev->setup.fall_time;
65983672db7SAndy Shevchenko 
66083672db7SAndy Shevchenko 	i2c_parse_fw_timings(i2c_dev->dev, t, false);
66183672db7SAndy Shevchenko 
66209cc9a3bSAlain Volmat 	if (t->bus_freq_hz > I2C_MAX_FAST_MODE_PLUS_FREQ) {
66309cc9a3bSAlain Volmat 		dev_err(i2c_dev->dev, "Invalid bus speed (%i>%i)\n",
66409cc9a3bSAlain Volmat 			t->bus_freq_hz, I2C_MAX_FAST_MODE_PLUS_FREQ);
66509cc9a3bSAlain Volmat 		return -EINVAL;
66609cc9a3bSAlain Volmat 	}
66783672db7SAndy Shevchenko 
66809cc9a3bSAlain Volmat 	setup->speed_freq = t->bus_freq_hz;
66983672db7SAndy Shevchenko 	i2c_dev->setup.rise_time = t->scl_rise_ns;
67083672db7SAndy Shevchenko 	i2c_dev->setup.fall_time = t->scl_fall_ns;
6719449a558SAlain Volmat 	i2c_dev->dnf_dt = t->digital_filter_width_ns;
672aeb068c5SPierre-Yves MORDRET 	setup->clock_src = clk_get_rate(i2c_dev->clk);
673aeb068c5SPierre-Yves MORDRET 
674aeb068c5SPierre-Yves MORDRET 	if (!setup->clock_src) {
675aeb068c5SPierre-Yves MORDRET 		dev_err(i2c_dev->dev, "clock rate is 0\n");
676aeb068c5SPierre-Yves MORDRET 		return -EINVAL;
677aeb068c5SPierre-Yves MORDRET 	}
678aeb068c5SPierre-Yves MORDRET 
6799449a558SAlain Volmat 	if (!of_property_read_bool(i2c_dev->dev->of_node, "i2c-digital-filter"))
6809449a558SAlain Volmat 		i2c_dev->dnf_dt = STM32F7_I2C_DNF_DEFAULT;
6819449a558SAlain Volmat 
682aeb068c5SPierre-Yves MORDRET 	do {
683aeb068c5SPierre-Yves MORDRET 		ret = stm32f7_i2c_compute_timing(i2c_dev, setup,
684aeb068c5SPierre-Yves MORDRET 						 &i2c_dev->timing);
685aeb068c5SPierre-Yves MORDRET 		if (ret) {
686aeb068c5SPierre-Yves MORDRET 			dev_err(i2c_dev->dev,
687aeb068c5SPierre-Yves MORDRET 				"failed to compute I2C timings.\n");
68809cc9a3bSAlain Volmat 			if (setup->speed_freq <= I2C_MAX_STANDARD_MODE_FREQ)
68909cc9a3bSAlain Volmat 				break;
690aeb068c5SPierre-Yves MORDRET 			setup->speed_freq =
69109cc9a3bSAlain Volmat 				stm32f7_get_lower_rate(setup->speed_freq);
692aeb068c5SPierre-Yves MORDRET 			dev_warn(i2c_dev->dev,
693aeb068c5SPierre-Yves MORDRET 				 "downgrade I2C Speed Freq to (%i)\n",
69409cc9a3bSAlain Volmat 				 setup->speed_freq);
695aeb068c5SPierre-Yves MORDRET 		}
696aeb068c5SPierre-Yves MORDRET 	} while (ret);
697aeb068c5SPierre-Yves MORDRET 
698aeb068c5SPierre-Yves MORDRET 	if (ret) {
699aeb068c5SPierre-Yves MORDRET 		dev_err(i2c_dev->dev, "Impossible to compute I2C timings.\n");
700aeb068c5SPierre-Yves MORDRET 		return ret;
701aeb068c5SPierre-Yves MORDRET 	}
702aeb068c5SPierre-Yves MORDRET 
70383c3408fSAlain Volmat 	i2c_dev->analog_filter = of_property_read_bool(i2c_dev->dev->of_node,
70483c3408fSAlain Volmat 						       "i2c-analog-filter");
70583c3408fSAlain Volmat 
70609cc9a3bSAlain Volmat 	dev_dbg(i2c_dev->dev, "I2C Speed(%i), Clk Source(%i)\n",
70709cc9a3bSAlain Volmat 		setup->speed_freq, setup->clock_src);
708aeb068c5SPierre-Yves MORDRET 	dev_dbg(i2c_dev->dev, "I2C Rise(%i) and Fall(%i) Time\n",
709aeb068c5SPierre-Yves MORDRET 		setup->rise_time, setup->fall_time);
710aeb068c5SPierre-Yves MORDRET 	dev_dbg(i2c_dev->dev, "I2C Analog Filter(%s), DNF(%i)\n",
7119449a558SAlain Volmat 		(i2c_dev->analog_filter ? "On" : "Off"), i2c_dev->dnf);
712aeb068c5SPierre-Yves MORDRET 
71309cc9a3bSAlain Volmat 	i2c_dev->bus_rate = setup->speed_freq;
71409cc9a3bSAlain Volmat 
715aeb068c5SPierre-Yves MORDRET 	return 0;
716aeb068c5SPierre-Yves MORDRET }
717aeb068c5SPierre-Yves MORDRET 
stm32f7_i2c_disable_dma_req(struct stm32f7_i2c_dev * i2c_dev)7187ecc8cfdSPierre-Yves MORDRET static void stm32f7_i2c_disable_dma_req(struct stm32f7_i2c_dev *i2c_dev)
7197ecc8cfdSPierre-Yves MORDRET {
7207ecc8cfdSPierre-Yves MORDRET 	void __iomem *base = i2c_dev->base;
7217ecc8cfdSPierre-Yves MORDRET 	u32 mask = STM32F7_I2C_CR1_RXDMAEN | STM32F7_I2C_CR1_TXDMAEN;
7227ecc8cfdSPierre-Yves MORDRET 
7237ecc8cfdSPierre-Yves MORDRET 	stm32f7_i2c_clr_bits(base + STM32F7_I2C_CR1, mask);
7247ecc8cfdSPierre-Yves MORDRET }
7257ecc8cfdSPierre-Yves MORDRET 
stm32f7_i2c_dma_callback(void * arg)7267ecc8cfdSPierre-Yves MORDRET static void stm32f7_i2c_dma_callback(void *arg)
7277ecc8cfdSPierre-Yves MORDRET {
7287ecc8cfdSPierre-Yves MORDRET 	struct stm32f7_i2c_dev *i2c_dev = (struct stm32f7_i2c_dev *)arg;
7297ecc8cfdSPierre-Yves MORDRET 	struct stm32_i2c_dma *dma = i2c_dev->dma;
7307ecc8cfdSPierre-Yves MORDRET 	struct device *dev = dma->chan_using->device->dev;
7317ecc8cfdSPierre-Yves MORDRET 
7327ecc8cfdSPierre-Yves MORDRET 	stm32f7_i2c_disable_dma_req(i2c_dev);
7337ecc8cfdSPierre-Yves MORDRET 	dma_unmap_single(dev, dma->dma_buf, dma->dma_len, dma->dma_data_dir);
7347ecc8cfdSPierre-Yves MORDRET 	complete(&dma->dma_complete);
7357ecc8cfdSPierre-Yves MORDRET }
7367ecc8cfdSPierre-Yves MORDRET 
stm32f7_i2c_hw_config(struct stm32f7_i2c_dev * i2c_dev)737aeb068c5SPierre-Yves MORDRET static void stm32f7_i2c_hw_config(struct stm32f7_i2c_dev *i2c_dev)
738aeb068c5SPierre-Yves MORDRET {
739aeb068c5SPierre-Yves MORDRET 	struct stm32f7_i2c_timings *t = &i2c_dev->timing;
740aeb068c5SPierre-Yves MORDRET 	u32 timing = 0;
741aeb068c5SPierre-Yves MORDRET 
742aeb068c5SPierre-Yves MORDRET 	/* Timing settings */
743aeb068c5SPierre-Yves MORDRET 	timing |= STM32F7_I2C_TIMINGR_PRESC(t->presc);
744aeb068c5SPierre-Yves MORDRET 	timing |= STM32F7_I2C_TIMINGR_SCLDEL(t->scldel);
745aeb068c5SPierre-Yves MORDRET 	timing |= STM32F7_I2C_TIMINGR_SDADEL(t->sdadel);
746aeb068c5SPierre-Yves MORDRET 	timing |= STM32F7_I2C_TIMINGR_SCLH(t->sclh);
747aeb068c5SPierre-Yves MORDRET 	timing |= STM32F7_I2C_TIMINGR_SCLL(t->scll);
748aeb068c5SPierre-Yves MORDRET 	writel_relaxed(timing, i2c_dev->base + STM32F7_I2C_TIMINGR);
749aeb068c5SPierre-Yves MORDRET 
75083c3408fSAlain Volmat 	/* Configure the Analog Filter */
75183c3408fSAlain Volmat 	if (i2c_dev->analog_filter)
752aeb068c5SPierre-Yves MORDRET 		stm32f7_i2c_clr_bits(i2c_dev->base + STM32F7_I2C_CR1,
753aeb068c5SPierre-Yves MORDRET 				     STM32F7_I2C_CR1_ANFOFF);
754aeb068c5SPierre-Yves MORDRET 	else
755aeb068c5SPierre-Yves MORDRET 		stm32f7_i2c_set_bits(i2c_dev->base + STM32F7_I2C_CR1,
756aeb068c5SPierre-Yves MORDRET 				     STM32F7_I2C_CR1_ANFOFF);
7573d6a3d3aSAlain Volmat 
7583d6a3d3aSAlain Volmat 	/* Program the Digital Filter */
7593d6a3d3aSAlain Volmat 	stm32f7_i2c_clr_bits(i2c_dev->base + STM32F7_I2C_CR1,
7603d6a3d3aSAlain Volmat 			     STM32F7_I2C_CR1_DNF_MASK);
7613d6a3d3aSAlain Volmat 	stm32f7_i2c_set_bits(i2c_dev->base + STM32F7_I2C_CR1,
7629449a558SAlain Volmat 			     STM32F7_I2C_CR1_DNF(i2c_dev->dnf));
7633d6a3d3aSAlain Volmat 
764aeb068c5SPierre-Yves MORDRET 	stm32f7_i2c_set_bits(i2c_dev->base + STM32F7_I2C_CR1,
765aeb068c5SPierre-Yves MORDRET 			     STM32F7_I2C_CR1_PE);
766aeb068c5SPierre-Yves MORDRET }
767aeb068c5SPierre-Yves MORDRET 
stm32f7_i2c_write_tx_data(struct stm32f7_i2c_dev * i2c_dev)768aeb068c5SPierre-Yves MORDRET static void stm32f7_i2c_write_tx_data(struct stm32f7_i2c_dev *i2c_dev)
769aeb068c5SPierre-Yves MORDRET {
770aeb068c5SPierre-Yves MORDRET 	struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg;
771aeb068c5SPierre-Yves MORDRET 	void __iomem *base = i2c_dev->base;
772aeb068c5SPierre-Yves MORDRET 
773aeb068c5SPierre-Yves MORDRET 	if (f7_msg->count) {
774aeb068c5SPierre-Yves MORDRET 		writeb_relaxed(*f7_msg->buf++, base + STM32F7_I2C_TXDR);
775aeb068c5SPierre-Yves MORDRET 		f7_msg->count--;
776aeb068c5SPierre-Yves MORDRET 	}
777aeb068c5SPierre-Yves MORDRET }
778aeb068c5SPierre-Yves MORDRET 
stm32f7_i2c_read_rx_data(struct stm32f7_i2c_dev * i2c_dev)779aeb068c5SPierre-Yves MORDRET static void stm32f7_i2c_read_rx_data(struct stm32f7_i2c_dev *i2c_dev)
780aeb068c5SPierre-Yves MORDRET {
781aeb068c5SPierre-Yves MORDRET 	struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg;
782aeb068c5SPierre-Yves MORDRET 	void __iomem *base = i2c_dev->base;
783aeb068c5SPierre-Yves MORDRET 
784aeb068c5SPierre-Yves MORDRET 	if (f7_msg->count) {
785aeb068c5SPierre-Yves MORDRET 		*f7_msg->buf++ = readb_relaxed(base + STM32F7_I2C_RXDR);
786aeb068c5SPierre-Yves MORDRET 		f7_msg->count--;
78760d609f3SPierre-Yves MORDRET 	} else {
78860d609f3SPierre-Yves MORDRET 		/* Flush RX buffer has no data is expected */
78960d609f3SPierre-Yves MORDRET 		readb_relaxed(base + STM32F7_I2C_RXDR);
790aeb068c5SPierre-Yves MORDRET 	}
791aeb068c5SPierre-Yves MORDRET }
792aeb068c5SPierre-Yves MORDRET 
stm32f7_i2c_reload(struct stm32f7_i2c_dev * i2c_dev)793aeb068c5SPierre-Yves MORDRET static void stm32f7_i2c_reload(struct stm32f7_i2c_dev *i2c_dev)
794aeb068c5SPierre-Yves MORDRET {
795aeb068c5SPierre-Yves MORDRET 	struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg;
796aeb068c5SPierre-Yves MORDRET 	u32 cr2;
797aeb068c5SPierre-Yves MORDRET 
7987ecc8cfdSPierre-Yves MORDRET 	if (i2c_dev->use_dma)
7997ecc8cfdSPierre-Yves MORDRET 		f7_msg->count -= STM32F7_I2C_MAX_LEN;
8007ecc8cfdSPierre-Yves MORDRET 
801aeb068c5SPierre-Yves MORDRET 	cr2 = readl_relaxed(i2c_dev->base + STM32F7_I2C_CR2);
802aeb068c5SPierre-Yves MORDRET 
803aeb068c5SPierre-Yves MORDRET 	cr2 &= ~STM32F7_I2C_CR2_NBYTES_MASK;
804aeb068c5SPierre-Yves MORDRET 	if (f7_msg->count > STM32F7_I2C_MAX_LEN) {
805aeb068c5SPierre-Yves MORDRET 		cr2 |= STM32F7_I2C_CR2_NBYTES(STM32F7_I2C_MAX_LEN);
806aeb068c5SPierre-Yves MORDRET 	} else {
807aeb068c5SPierre-Yves MORDRET 		cr2 &= ~STM32F7_I2C_CR2_RELOAD;
808aeb068c5SPierre-Yves MORDRET 		cr2 |= STM32F7_I2C_CR2_NBYTES(f7_msg->count);
809aeb068c5SPierre-Yves MORDRET 	}
810aeb068c5SPierre-Yves MORDRET 
811aeb068c5SPierre-Yves MORDRET 	writel_relaxed(cr2, i2c_dev->base + STM32F7_I2C_CR2);
812aeb068c5SPierre-Yves MORDRET }
813aeb068c5SPierre-Yves MORDRET 
stm32f7_i2c_smbus_reload(struct stm32f7_i2c_dev * i2c_dev)8149e48155fSPierre-Yves MORDRET static void stm32f7_i2c_smbus_reload(struct stm32f7_i2c_dev *i2c_dev)
8159e48155fSPierre-Yves MORDRET {
8169e48155fSPierre-Yves MORDRET 	struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg;
8179e48155fSPierre-Yves MORDRET 	u32 cr2;
8189e48155fSPierre-Yves MORDRET 	u8 *val;
8199e48155fSPierre-Yves MORDRET 
8209e48155fSPierre-Yves MORDRET 	/*
8219e48155fSPierre-Yves MORDRET 	 * For I2C_SMBUS_BLOCK_DATA && I2C_SMBUS_BLOCK_PROC_CALL, the first
8229e48155fSPierre-Yves MORDRET 	 * data received inform us how many data will follow.
8239e48155fSPierre-Yves MORDRET 	 */
8249e48155fSPierre-Yves MORDRET 	stm32f7_i2c_read_rx_data(i2c_dev);
8259e48155fSPierre-Yves MORDRET 
8269e48155fSPierre-Yves MORDRET 	/*
8279e48155fSPierre-Yves MORDRET 	 * Update NBYTES with the value read to continue the transfer
8289e48155fSPierre-Yves MORDRET 	 */
8299e48155fSPierre-Yves MORDRET 	val = f7_msg->buf - sizeof(u8);
8309e48155fSPierre-Yves MORDRET 	f7_msg->count = *val;
8319e48155fSPierre-Yves MORDRET 	cr2 = readl_relaxed(i2c_dev->base + STM32F7_I2C_CR2);
8329e48155fSPierre-Yves MORDRET 	cr2 &= ~(STM32F7_I2C_CR2_NBYTES_MASK | STM32F7_I2C_CR2_RELOAD);
8339e48155fSPierre-Yves MORDRET 	cr2 |= STM32F7_I2C_CR2_NBYTES(f7_msg->count);
8349e48155fSPierre-Yves MORDRET 	writel_relaxed(cr2, i2c_dev->base + STM32F7_I2C_CR2);
8359e48155fSPierre-Yves MORDRET }
8369e48155fSPierre-Yves MORDRET 
stm32f7_i2c_release_bus(struct i2c_adapter * i2c_adap)83705907656SAlain Volmat static void stm32f7_i2c_release_bus(struct i2c_adapter *i2c_adap)
838562de4ffSPierre-Yves MORDRET {
839562de4ffSPierre-Yves MORDRET 	struct stm32f7_i2c_dev *i2c_dev = i2c_get_adapdata(i2c_adap);
840562de4ffSPierre-Yves MORDRET 
841562de4ffSPierre-Yves MORDRET 	stm32f7_i2c_clr_bits(i2c_dev->base + STM32F7_I2C_CR1,
842562de4ffSPierre-Yves MORDRET 			     STM32F7_I2C_CR1_PE);
843562de4ffSPierre-Yves MORDRET 
844562de4ffSPierre-Yves MORDRET 	stm32f7_i2c_hw_config(i2c_dev);
845562de4ffSPierre-Yves MORDRET }
846562de4ffSPierre-Yves MORDRET 
stm32f7_i2c_wait_free_bus(struct stm32f7_i2c_dev * i2c_dev)847aeb068c5SPierre-Yves MORDRET static int stm32f7_i2c_wait_free_bus(struct stm32f7_i2c_dev *i2c_dev)
848aeb068c5SPierre-Yves MORDRET {
849aeb068c5SPierre-Yves MORDRET 	u32 status;
850aeb068c5SPierre-Yves MORDRET 	int ret;
851aeb068c5SPierre-Yves MORDRET 
852aeb068c5SPierre-Yves MORDRET 	ret = readl_relaxed_poll_timeout(i2c_dev->base + STM32F7_I2C_ISR,
853aeb068c5SPierre-Yves MORDRET 					 status,
854aeb068c5SPierre-Yves MORDRET 					 !(status & STM32F7_I2C_ISR_BUSY),
855aeb068c5SPierre-Yves MORDRET 					 10, 1000);
856562de4ffSPierre-Yves MORDRET 	if (!ret)
857562de4ffSPierre-Yves MORDRET 		return 0;
858562de4ffSPierre-Yves MORDRET 
85905907656SAlain Volmat 	stm32f7_i2c_release_bus(&i2c_dev->adap);
860aeb068c5SPierre-Yves MORDRET 
861562de4ffSPierre-Yves MORDRET 	return -EBUSY;
862aeb068c5SPierre-Yves MORDRET }
863aeb068c5SPierre-Yves MORDRET 
stm32f7_i2c_xfer_msg(struct stm32f7_i2c_dev * i2c_dev,struct i2c_msg * msg)864aeb068c5SPierre-Yves MORDRET static void stm32f7_i2c_xfer_msg(struct stm32f7_i2c_dev *i2c_dev,
865aeb068c5SPierre-Yves MORDRET 				 struct i2c_msg *msg)
866aeb068c5SPierre-Yves MORDRET {
867aeb068c5SPierre-Yves MORDRET 	struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg;
868aeb068c5SPierre-Yves MORDRET 	void __iomem *base = i2c_dev->base;
869aeb068c5SPierre-Yves MORDRET 	u32 cr1, cr2;
8707ecc8cfdSPierre-Yves MORDRET 	int ret;
871aeb068c5SPierre-Yves MORDRET 
872aeb068c5SPierre-Yves MORDRET 	f7_msg->addr = msg->addr;
873aeb068c5SPierre-Yves MORDRET 	f7_msg->buf = msg->buf;
874aeb068c5SPierre-Yves MORDRET 	f7_msg->count = msg->len;
875aeb068c5SPierre-Yves MORDRET 	f7_msg->result = 0;
876aeb068c5SPierre-Yves MORDRET 	f7_msg->stop = (i2c_dev->msg_id >= i2c_dev->msg_num - 1);
877aeb068c5SPierre-Yves MORDRET 
878aeb068c5SPierre-Yves MORDRET 	reinit_completion(&i2c_dev->complete);
879aeb068c5SPierre-Yves MORDRET 
880aeb068c5SPierre-Yves MORDRET 	cr1 = readl_relaxed(base + STM32F7_I2C_CR1);
881aeb068c5SPierre-Yves MORDRET 	cr2 = readl_relaxed(base + STM32F7_I2C_CR2);
882aeb068c5SPierre-Yves MORDRET 
883aeb068c5SPierre-Yves MORDRET 	/* Set transfer direction */
884aeb068c5SPierre-Yves MORDRET 	cr2 &= ~STM32F7_I2C_CR2_RD_WRN;
885aeb068c5SPierre-Yves MORDRET 	if (msg->flags & I2C_M_RD)
886aeb068c5SPierre-Yves MORDRET 		cr2 |= STM32F7_I2C_CR2_RD_WRN;
887aeb068c5SPierre-Yves MORDRET 
888aeb068c5SPierre-Yves MORDRET 	/* Set slave address */
8898c7ecc99SPierre-Yves MORDRET 	cr2 &= ~(STM32F7_I2C_CR2_HEAD10R | STM32F7_I2C_CR2_ADD10);
8908c7ecc99SPierre-Yves MORDRET 	if (msg->flags & I2C_M_TEN) {
8918c7ecc99SPierre-Yves MORDRET 		cr2 &= ~STM32F7_I2C_CR2_SADD10_MASK;
8928c7ecc99SPierre-Yves MORDRET 		cr2 |= STM32F7_I2C_CR2_SADD10(f7_msg->addr);
8938c7ecc99SPierre-Yves MORDRET 		cr2 |= STM32F7_I2C_CR2_ADD10;
8948c7ecc99SPierre-Yves MORDRET 	} else {
895aeb068c5SPierre-Yves MORDRET 		cr2 &= ~STM32F7_I2C_CR2_SADD7_MASK;
896aeb068c5SPierre-Yves MORDRET 		cr2 |= STM32F7_I2C_CR2_SADD7(f7_msg->addr);
8978c7ecc99SPierre-Yves MORDRET 	}
898aeb068c5SPierre-Yves MORDRET 
899aeb068c5SPierre-Yves MORDRET 	/* Set nb bytes to transfer and reload if needed */
900aeb068c5SPierre-Yves MORDRET 	cr2 &= ~(STM32F7_I2C_CR2_NBYTES_MASK | STM32F7_I2C_CR2_RELOAD);
901aeb068c5SPierre-Yves MORDRET 	if (f7_msg->count > STM32F7_I2C_MAX_LEN) {
902aeb068c5SPierre-Yves MORDRET 		cr2 |= STM32F7_I2C_CR2_NBYTES(STM32F7_I2C_MAX_LEN);
903aeb068c5SPierre-Yves MORDRET 		cr2 |= STM32F7_I2C_CR2_RELOAD;
904aeb068c5SPierre-Yves MORDRET 	} else {
905aeb068c5SPierre-Yves MORDRET 		cr2 |= STM32F7_I2C_CR2_NBYTES(f7_msg->count);
906aeb068c5SPierre-Yves MORDRET 	}
907aeb068c5SPierre-Yves MORDRET 
908aeb068c5SPierre-Yves MORDRET 	/* Enable NACK, STOP, error and transfer complete interrupts */
909aeb068c5SPierre-Yves MORDRET 	cr1 |= STM32F7_I2C_CR1_ERRIE | STM32F7_I2C_CR1_TCIE |
910aeb068c5SPierre-Yves MORDRET 		STM32F7_I2C_CR1_STOPIE | STM32F7_I2C_CR1_NACKIE;
911aeb068c5SPierre-Yves MORDRET 
9127ecc8cfdSPierre-Yves MORDRET 	/* Clear DMA req and TX/RX interrupt */
9137ecc8cfdSPierre-Yves MORDRET 	cr1 &= ~(STM32F7_I2C_CR1_RXIE | STM32F7_I2C_CR1_TXIE |
9147ecc8cfdSPierre-Yves MORDRET 			STM32F7_I2C_CR1_RXDMAEN | STM32F7_I2C_CR1_TXDMAEN);
915aeb068c5SPierre-Yves MORDRET 
9167ecc8cfdSPierre-Yves MORDRET 	/* Configure DMA or enable RX/TX interrupt */
9177ecc8cfdSPierre-Yves MORDRET 	i2c_dev->use_dma = false;
9187ecc8cfdSPierre-Yves MORDRET 	if (i2c_dev->dma && f7_msg->count >= STM32F7_I2C_DMA_LEN_MIN) {
9197ecc8cfdSPierre-Yves MORDRET 		ret = stm32_i2c_prep_dma_xfer(i2c_dev->dev, i2c_dev->dma,
9207ecc8cfdSPierre-Yves MORDRET 					      msg->flags & I2C_M_RD,
9217ecc8cfdSPierre-Yves MORDRET 					      f7_msg->count, f7_msg->buf,
9227ecc8cfdSPierre-Yves MORDRET 					      stm32f7_i2c_dma_callback,
9237ecc8cfdSPierre-Yves MORDRET 					      i2c_dev);
9247ecc8cfdSPierre-Yves MORDRET 		if (!ret)
9257ecc8cfdSPierre-Yves MORDRET 			i2c_dev->use_dma = true;
9267ecc8cfdSPierre-Yves MORDRET 		else
9277ecc8cfdSPierre-Yves MORDRET 			dev_warn(i2c_dev->dev, "can't use DMA\n");
9287ecc8cfdSPierre-Yves MORDRET 	}
9297ecc8cfdSPierre-Yves MORDRET 
9307ecc8cfdSPierre-Yves MORDRET 	if (!i2c_dev->use_dma) {
931aeb068c5SPierre-Yves MORDRET 		if (msg->flags & I2C_M_RD)
932aeb068c5SPierre-Yves MORDRET 			cr1 |= STM32F7_I2C_CR1_RXIE;
933aeb068c5SPierre-Yves MORDRET 		else
934aeb068c5SPierre-Yves MORDRET 			cr1 |= STM32F7_I2C_CR1_TXIE;
9357ecc8cfdSPierre-Yves MORDRET 	} else {
9367ecc8cfdSPierre-Yves MORDRET 		if (msg->flags & I2C_M_RD)
9377ecc8cfdSPierre-Yves MORDRET 			cr1 |= STM32F7_I2C_CR1_RXDMAEN;
9387ecc8cfdSPierre-Yves MORDRET 		else
9397ecc8cfdSPierre-Yves MORDRET 			cr1 |= STM32F7_I2C_CR1_TXDMAEN;
9407ecc8cfdSPierre-Yves MORDRET 	}
941aeb068c5SPierre-Yves MORDRET 
942aeb068c5SPierre-Yves MORDRET 	/* Configure Start/Repeated Start */
943aeb068c5SPierre-Yves MORDRET 	cr2 |= STM32F7_I2C_CR2_START;
944aeb068c5SPierre-Yves MORDRET 
94560d609f3SPierre-Yves MORDRET 	i2c_dev->master_mode = true;
94660d609f3SPierre-Yves MORDRET 
947aeb068c5SPierre-Yves MORDRET 	/* Write configurations registers */
948aeb068c5SPierre-Yves MORDRET 	writel_relaxed(cr1, base + STM32F7_I2C_CR1);
949aeb068c5SPierre-Yves MORDRET 	writel_relaxed(cr2, base + STM32F7_I2C_CR2);
950aeb068c5SPierre-Yves MORDRET }
951aeb068c5SPierre-Yves MORDRET 
stm32f7_i2c_smbus_xfer_msg(struct stm32f7_i2c_dev * i2c_dev,unsigned short flags,u8 command,union i2c_smbus_data * data)9529e48155fSPierre-Yves MORDRET static int stm32f7_i2c_smbus_xfer_msg(struct stm32f7_i2c_dev *i2c_dev,
9539e48155fSPierre-Yves MORDRET 				      unsigned short flags, u8 command,
9549e48155fSPierre-Yves MORDRET 				      union i2c_smbus_data *data)
9559e48155fSPierre-Yves MORDRET {
9569e48155fSPierre-Yves MORDRET 	struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg;
9579e48155fSPierre-Yves MORDRET 	struct device *dev = i2c_dev->dev;
9589e48155fSPierre-Yves MORDRET 	void __iomem *base = i2c_dev->base;
9599e48155fSPierre-Yves MORDRET 	u32 cr1, cr2;
9607ecc8cfdSPierre-Yves MORDRET 	int i, ret;
9619e48155fSPierre-Yves MORDRET 
9629e48155fSPierre-Yves MORDRET 	f7_msg->result = 0;
9639e48155fSPierre-Yves MORDRET 	reinit_completion(&i2c_dev->complete);
9649e48155fSPierre-Yves MORDRET 
9659e48155fSPierre-Yves MORDRET 	cr2 = readl_relaxed(base + STM32F7_I2C_CR2);
9669e48155fSPierre-Yves MORDRET 	cr1 = readl_relaxed(base + STM32F7_I2C_CR1);
9679e48155fSPierre-Yves MORDRET 
9689e48155fSPierre-Yves MORDRET 	/* Set transfer direction */
9699e48155fSPierre-Yves MORDRET 	cr2 &= ~STM32F7_I2C_CR2_RD_WRN;
9709e48155fSPierre-Yves MORDRET 	if (f7_msg->read_write)
9719e48155fSPierre-Yves MORDRET 		cr2 |= STM32F7_I2C_CR2_RD_WRN;
9729e48155fSPierre-Yves MORDRET 
9739e48155fSPierre-Yves MORDRET 	/* Set slave address */
9749e48155fSPierre-Yves MORDRET 	cr2 &= ~(STM32F7_I2C_CR2_ADD10 | STM32F7_I2C_CR2_SADD7_MASK);
9759e48155fSPierre-Yves MORDRET 	cr2 |= STM32F7_I2C_CR2_SADD7(f7_msg->addr);
9769e48155fSPierre-Yves MORDRET 
9779e48155fSPierre-Yves MORDRET 	f7_msg->smbus_buf[0] = command;
9789e48155fSPierre-Yves MORDRET 	switch (f7_msg->size) {
9799e48155fSPierre-Yves MORDRET 	case I2C_SMBUS_QUICK:
9809e48155fSPierre-Yves MORDRET 		f7_msg->stop = true;
9819e48155fSPierre-Yves MORDRET 		f7_msg->count = 0;
9829e48155fSPierre-Yves MORDRET 		break;
9839e48155fSPierre-Yves MORDRET 	case I2C_SMBUS_BYTE:
9849e48155fSPierre-Yves MORDRET 		f7_msg->stop = true;
9859e48155fSPierre-Yves MORDRET 		f7_msg->count = 1;
9869e48155fSPierre-Yves MORDRET 		break;
9879e48155fSPierre-Yves MORDRET 	case I2C_SMBUS_BYTE_DATA:
9889e48155fSPierre-Yves MORDRET 		if (f7_msg->read_write) {
9899e48155fSPierre-Yves MORDRET 			f7_msg->stop = false;
9909e48155fSPierre-Yves MORDRET 			f7_msg->count = 1;
9919e48155fSPierre-Yves MORDRET 			cr2 &= ~STM32F7_I2C_CR2_RD_WRN;
9929e48155fSPierre-Yves MORDRET 		} else {
9939e48155fSPierre-Yves MORDRET 			f7_msg->stop = true;
9949e48155fSPierre-Yves MORDRET 			f7_msg->count = 2;
9959e48155fSPierre-Yves MORDRET 			f7_msg->smbus_buf[1] = data->byte;
9969e48155fSPierre-Yves MORDRET 		}
9979e48155fSPierre-Yves MORDRET 		break;
9989e48155fSPierre-Yves MORDRET 	case I2C_SMBUS_WORD_DATA:
9999e48155fSPierre-Yves MORDRET 		if (f7_msg->read_write) {
10009e48155fSPierre-Yves MORDRET 			f7_msg->stop = false;
10019e48155fSPierre-Yves MORDRET 			f7_msg->count = 1;
10029e48155fSPierre-Yves MORDRET 			cr2 &= ~STM32F7_I2C_CR2_RD_WRN;
10039e48155fSPierre-Yves MORDRET 		} else {
10049e48155fSPierre-Yves MORDRET 			f7_msg->stop = true;
10059e48155fSPierre-Yves MORDRET 			f7_msg->count = 3;
10069e48155fSPierre-Yves MORDRET 			f7_msg->smbus_buf[1] = data->word & 0xff;
10079e48155fSPierre-Yves MORDRET 			f7_msg->smbus_buf[2] = data->word >> 8;
10089e48155fSPierre-Yves MORDRET 		}
10099e48155fSPierre-Yves MORDRET 		break;
10109e48155fSPierre-Yves MORDRET 	case I2C_SMBUS_BLOCK_DATA:
10119e48155fSPierre-Yves MORDRET 		if (f7_msg->read_write) {
10129e48155fSPierre-Yves MORDRET 			f7_msg->stop = false;
10139e48155fSPierre-Yves MORDRET 			f7_msg->count = 1;
10149e48155fSPierre-Yves MORDRET 			cr2 &= ~STM32F7_I2C_CR2_RD_WRN;
10159e48155fSPierre-Yves MORDRET 		} else {
10169e48155fSPierre-Yves MORDRET 			f7_msg->stop = true;
10179e48155fSPierre-Yves MORDRET 			if (data->block[0] > I2C_SMBUS_BLOCK_MAX ||
10189e48155fSPierre-Yves MORDRET 			    !data->block[0]) {
10199e48155fSPierre-Yves MORDRET 				dev_err(dev, "Invalid block write size %d\n",
10209e48155fSPierre-Yves MORDRET 					data->block[0]);
10219e48155fSPierre-Yves MORDRET 				return -EINVAL;
10229e48155fSPierre-Yves MORDRET 			}
10239e48155fSPierre-Yves MORDRET 			f7_msg->count = data->block[0] + 2;
10249e48155fSPierre-Yves MORDRET 			for (i = 1; i < f7_msg->count; i++)
10259e48155fSPierre-Yves MORDRET 				f7_msg->smbus_buf[i] = data->block[i - 1];
10269e48155fSPierre-Yves MORDRET 		}
10279e48155fSPierre-Yves MORDRET 		break;
10289e48155fSPierre-Yves MORDRET 	case I2C_SMBUS_PROC_CALL:
10299e48155fSPierre-Yves MORDRET 		f7_msg->stop = false;
10309e48155fSPierre-Yves MORDRET 		f7_msg->count = 3;
10319e48155fSPierre-Yves MORDRET 		f7_msg->smbus_buf[1] = data->word & 0xff;
10329e48155fSPierre-Yves MORDRET 		f7_msg->smbus_buf[2] = data->word >> 8;
10339e48155fSPierre-Yves MORDRET 		cr2 &= ~STM32F7_I2C_CR2_RD_WRN;
10349e48155fSPierre-Yves MORDRET 		f7_msg->read_write = I2C_SMBUS_READ;
10359e48155fSPierre-Yves MORDRET 		break;
10369e48155fSPierre-Yves MORDRET 	case I2C_SMBUS_BLOCK_PROC_CALL:
10379e48155fSPierre-Yves MORDRET 		f7_msg->stop = false;
10389e48155fSPierre-Yves MORDRET 		if (data->block[0] > I2C_SMBUS_BLOCK_MAX - 1) {
10399e48155fSPierre-Yves MORDRET 			dev_err(dev, "Invalid block write size %d\n",
10409e48155fSPierre-Yves MORDRET 				data->block[0]);
10419e48155fSPierre-Yves MORDRET 			return -EINVAL;
10429e48155fSPierre-Yves MORDRET 		}
10439e48155fSPierre-Yves MORDRET 		f7_msg->count = data->block[0] + 2;
10449e48155fSPierre-Yves MORDRET 		for (i = 1; i < f7_msg->count; i++)
10459e48155fSPierre-Yves MORDRET 			f7_msg->smbus_buf[i] = data->block[i - 1];
10469e48155fSPierre-Yves MORDRET 		cr2 &= ~STM32F7_I2C_CR2_RD_WRN;
10479e48155fSPierre-Yves MORDRET 		f7_msg->read_write = I2C_SMBUS_READ;
10489e48155fSPierre-Yves MORDRET 		break;
1049473fbdf7SFabrice Gasnier 	case I2C_SMBUS_I2C_BLOCK_DATA:
1050473fbdf7SFabrice Gasnier 		/* Rely on emulated i2c transfer (through master_xfer) */
1051473fbdf7SFabrice Gasnier 		return -EOPNOTSUPP;
10529e48155fSPierre-Yves MORDRET 	default:
10539e48155fSPierre-Yves MORDRET 		dev_err(dev, "Unsupported smbus protocol %d\n", f7_msg->size);
10549e48155fSPierre-Yves MORDRET 		return -EOPNOTSUPP;
10559e48155fSPierre-Yves MORDRET 	}
10569e48155fSPierre-Yves MORDRET 
10579e48155fSPierre-Yves MORDRET 	f7_msg->buf = f7_msg->smbus_buf;
10589e48155fSPierre-Yves MORDRET 
10599e48155fSPierre-Yves MORDRET 	/* Configure PEC */
10609e48155fSPierre-Yves MORDRET 	if ((flags & I2C_CLIENT_PEC) && f7_msg->size != I2C_SMBUS_QUICK) {
10619e48155fSPierre-Yves MORDRET 		cr1 |= STM32F7_I2C_CR1_PECEN;
1062*c896ff2dSAlain Volmat 		if (!f7_msg->read_write) {
10639e48155fSPierre-Yves MORDRET 			cr2 |= STM32F7_I2C_CR2_PECBYTE;
10649e48155fSPierre-Yves MORDRET 			f7_msg->count++;
1065*c896ff2dSAlain Volmat 		}
10669e48155fSPierre-Yves MORDRET 	} else {
10679e48155fSPierre-Yves MORDRET 		cr1 &= ~STM32F7_I2C_CR1_PECEN;
10689e48155fSPierre-Yves MORDRET 		cr2 &= ~STM32F7_I2C_CR2_PECBYTE;
10699e48155fSPierre-Yves MORDRET 	}
10709e48155fSPierre-Yves MORDRET 
10719e48155fSPierre-Yves MORDRET 	/* Set number of bytes to be transferred */
10729e48155fSPierre-Yves MORDRET 	cr2 &= ~(STM32F7_I2C_CR2_NBYTES_MASK | STM32F7_I2C_CR2_RELOAD);
10739e48155fSPierre-Yves MORDRET 	cr2 |= STM32F7_I2C_CR2_NBYTES(f7_msg->count);
10749e48155fSPierre-Yves MORDRET 
10759e48155fSPierre-Yves MORDRET 	/* Enable NACK, STOP, error and transfer complete interrupts */
10769e48155fSPierre-Yves MORDRET 	cr1 |= STM32F7_I2C_CR1_ERRIE | STM32F7_I2C_CR1_TCIE |
10779e48155fSPierre-Yves MORDRET 		STM32F7_I2C_CR1_STOPIE | STM32F7_I2C_CR1_NACKIE;
10789e48155fSPierre-Yves MORDRET 
10797ecc8cfdSPierre-Yves MORDRET 	/* Clear DMA req and TX/RX interrupt */
10807ecc8cfdSPierre-Yves MORDRET 	cr1 &= ~(STM32F7_I2C_CR1_RXIE | STM32F7_I2C_CR1_TXIE |
10817ecc8cfdSPierre-Yves MORDRET 			STM32F7_I2C_CR1_RXDMAEN | STM32F7_I2C_CR1_TXDMAEN);
10829e48155fSPierre-Yves MORDRET 
10837ecc8cfdSPierre-Yves MORDRET 	/* Configure DMA or enable RX/TX interrupt */
10847ecc8cfdSPierre-Yves MORDRET 	i2c_dev->use_dma = false;
10857ecc8cfdSPierre-Yves MORDRET 	if (i2c_dev->dma && f7_msg->count >= STM32F7_I2C_DMA_LEN_MIN) {
10867ecc8cfdSPierre-Yves MORDRET 		ret = stm32_i2c_prep_dma_xfer(i2c_dev->dev, i2c_dev->dma,
10877ecc8cfdSPierre-Yves MORDRET 					      cr2 & STM32F7_I2C_CR2_RD_WRN,
10887ecc8cfdSPierre-Yves MORDRET 					      f7_msg->count, f7_msg->buf,
10897ecc8cfdSPierre-Yves MORDRET 					      stm32f7_i2c_dma_callback,
10907ecc8cfdSPierre-Yves MORDRET 					      i2c_dev);
10917ecc8cfdSPierre-Yves MORDRET 		if (!ret)
10927ecc8cfdSPierre-Yves MORDRET 			i2c_dev->use_dma = true;
10937ecc8cfdSPierre-Yves MORDRET 		else
10947ecc8cfdSPierre-Yves MORDRET 			dev_warn(i2c_dev->dev, "can't use DMA\n");
10957ecc8cfdSPierre-Yves MORDRET 	}
10967ecc8cfdSPierre-Yves MORDRET 
10977ecc8cfdSPierre-Yves MORDRET 	if (!i2c_dev->use_dma) {
10989e48155fSPierre-Yves MORDRET 		if (cr2 & STM32F7_I2C_CR2_RD_WRN)
10999e48155fSPierre-Yves MORDRET 			cr1 |= STM32F7_I2C_CR1_RXIE;
11009e48155fSPierre-Yves MORDRET 		else
11019e48155fSPierre-Yves MORDRET 			cr1 |= STM32F7_I2C_CR1_TXIE;
11027ecc8cfdSPierre-Yves MORDRET 	} else {
11037ecc8cfdSPierre-Yves MORDRET 		if (cr2 & STM32F7_I2C_CR2_RD_WRN)
11047ecc8cfdSPierre-Yves MORDRET 			cr1 |= STM32F7_I2C_CR1_RXDMAEN;
11057ecc8cfdSPierre-Yves MORDRET 		else
11067ecc8cfdSPierre-Yves MORDRET 			cr1 |= STM32F7_I2C_CR1_TXDMAEN;
11077ecc8cfdSPierre-Yves MORDRET 	}
11089e48155fSPierre-Yves MORDRET 
11099e48155fSPierre-Yves MORDRET 	/* Set Start bit */
11109e48155fSPierre-Yves MORDRET 	cr2 |= STM32F7_I2C_CR2_START;
11119e48155fSPierre-Yves MORDRET 
11129e48155fSPierre-Yves MORDRET 	i2c_dev->master_mode = true;
11139e48155fSPierre-Yves MORDRET 
11149e48155fSPierre-Yves MORDRET 	/* Write configurations registers */
11159e48155fSPierre-Yves MORDRET 	writel_relaxed(cr1, base + STM32F7_I2C_CR1);
11169e48155fSPierre-Yves MORDRET 	writel_relaxed(cr2, base + STM32F7_I2C_CR2);
11179e48155fSPierre-Yves MORDRET 
11189e48155fSPierre-Yves MORDRET 	return 0;
11199e48155fSPierre-Yves MORDRET }
11209e48155fSPierre-Yves MORDRET 
stm32f7_i2c_smbus_rep_start(struct stm32f7_i2c_dev * i2c_dev)11219e48155fSPierre-Yves MORDRET static void stm32f7_i2c_smbus_rep_start(struct stm32f7_i2c_dev *i2c_dev)
11229e48155fSPierre-Yves MORDRET {
11239e48155fSPierre-Yves MORDRET 	struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg;
11249e48155fSPierre-Yves MORDRET 	void __iomem *base = i2c_dev->base;
11259e48155fSPierre-Yves MORDRET 	u32 cr1, cr2;
11267ecc8cfdSPierre-Yves MORDRET 	int ret;
11279e48155fSPierre-Yves MORDRET 
11289e48155fSPierre-Yves MORDRET 	cr2 = readl_relaxed(base + STM32F7_I2C_CR2);
11299e48155fSPierre-Yves MORDRET 	cr1 = readl_relaxed(base + STM32F7_I2C_CR1);
11309e48155fSPierre-Yves MORDRET 
11319e48155fSPierre-Yves MORDRET 	/* Set transfer direction */
11329e48155fSPierre-Yves MORDRET 	cr2 |= STM32F7_I2C_CR2_RD_WRN;
11339e48155fSPierre-Yves MORDRET 
11349e48155fSPierre-Yves MORDRET 	switch (f7_msg->size) {
11359e48155fSPierre-Yves MORDRET 	case I2C_SMBUS_BYTE_DATA:
11369e48155fSPierre-Yves MORDRET 		f7_msg->count = 1;
11379e48155fSPierre-Yves MORDRET 		break;
11389e48155fSPierre-Yves MORDRET 	case I2C_SMBUS_WORD_DATA:
11399e48155fSPierre-Yves MORDRET 	case I2C_SMBUS_PROC_CALL:
11409e48155fSPierre-Yves MORDRET 		f7_msg->count = 2;
11419e48155fSPierre-Yves MORDRET 		break;
11429e48155fSPierre-Yves MORDRET 	case I2C_SMBUS_BLOCK_DATA:
11439e48155fSPierre-Yves MORDRET 	case I2C_SMBUS_BLOCK_PROC_CALL:
11449e48155fSPierre-Yves MORDRET 		f7_msg->count = 1;
11459e48155fSPierre-Yves MORDRET 		cr2 |= STM32F7_I2C_CR2_RELOAD;
11469e48155fSPierre-Yves MORDRET 		break;
11479e48155fSPierre-Yves MORDRET 	}
11489e48155fSPierre-Yves MORDRET 
11499e48155fSPierre-Yves MORDRET 	f7_msg->buf = f7_msg->smbus_buf;
11509e48155fSPierre-Yves MORDRET 	f7_msg->stop = true;
11519e48155fSPierre-Yves MORDRET 
11529e48155fSPierre-Yves MORDRET 	/* Add one byte for PEC if needed */
1153*c896ff2dSAlain Volmat 	if (cr1 & STM32F7_I2C_CR1_PECEN) {
1154*c896ff2dSAlain Volmat 		cr2 |= STM32F7_I2C_CR2_PECBYTE;
11559e48155fSPierre-Yves MORDRET 		f7_msg->count++;
1156*c896ff2dSAlain Volmat 	}
11579e48155fSPierre-Yves MORDRET 
11589e48155fSPierre-Yves MORDRET 	/* Set number of bytes to be transferred */
11599e48155fSPierre-Yves MORDRET 	cr2 &= ~(STM32F7_I2C_CR2_NBYTES_MASK);
11609e48155fSPierre-Yves MORDRET 	cr2 |= STM32F7_I2C_CR2_NBYTES(f7_msg->count);
11619e48155fSPierre-Yves MORDRET 
11629e48155fSPierre-Yves MORDRET 	/*
11639e48155fSPierre-Yves MORDRET 	 * Configure RX/TX interrupt:
11649e48155fSPierre-Yves MORDRET 	 */
11659e48155fSPierre-Yves MORDRET 	cr1 &= ~(STM32F7_I2C_CR1_RXIE | STM32F7_I2C_CR1_TXIE);
11669e48155fSPierre-Yves MORDRET 	cr1 |= STM32F7_I2C_CR1_RXIE;
11679e48155fSPierre-Yves MORDRET 
11687ecc8cfdSPierre-Yves MORDRET 	/*
11697ecc8cfdSPierre-Yves MORDRET 	 * Configure DMA or enable RX/TX interrupt:
11707ecc8cfdSPierre-Yves MORDRET 	 * For I2C_SMBUS_BLOCK_DATA and I2C_SMBUS_BLOCK_PROC_CALL we don't use
11717ecc8cfdSPierre-Yves MORDRET 	 * dma as we don't know in advance how many data will be received
11727ecc8cfdSPierre-Yves MORDRET 	 */
11737ecc8cfdSPierre-Yves MORDRET 	cr1 &= ~(STM32F7_I2C_CR1_RXIE | STM32F7_I2C_CR1_TXIE |
11747ecc8cfdSPierre-Yves MORDRET 		 STM32F7_I2C_CR1_RXDMAEN | STM32F7_I2C_CR1_TXDMAEN);
11757ecc8cfdSPierre-Yves MORDRET 
11767ecc8cfdSPierre-Yves MORDRET 	i2c_dev->use_dma = false;
11777ecc8cfdSPierre-Yves MORDRET 	if (i2c_dev->dma && f7_msg->count >= STM32F7_I2C_DMA_LEN_MIN &&
11787ecc8cfdSPierre-Yves MORDRET 	    f7_msg->size != I2C_SMBUS_BLOCK_DATA &&
11797ecc8cfdSPierre-Yves MORDRET 	    f7_msg->size != I2C_SMBUS_BLOCK_PROC_CALL) {
11807ecc8cfdSPierre-Yves MORDRET 		ret = stm32_i2c_prep_dma_xfer(i2c_dev->dev, i2c_dev->dma,
11817ecc8cfdSPierre-Yves MORDRET 					      cr2 & STM32F7_I2C_CR2_RD_WRN,
11827ecc8cfdSPierre-Yves MORDRET 					      f7_msg->count, f7_msg->buf,
11837ecc8cfdSPierre-Yves MORDRET 					      stm32f7_i2c_dma_callback,
11847ecc8cfdSPierre-Yves MORDRET 					      i2c_dev);
11857ecc8cfdSPierre-Yves MORDRET 
11867ecc8cfdSPierre-Yves MORDRET 		if (!ret)
11877ecc8cfdSPierre-Yves MORDRET 			i2c_dev->use_dma = true;
11887ecc8cfdSPierre-Yves MORDRET 		else
11897ecc8cfdSPierre-Yves MORDRET 			dev_warn(i2c_dev->dev, "can't use DMA\n");
11907ecc8cfdSPierre-Yves MORDRET 	}
11917ecc8cfdSPierre-Yves MORDRET 
11927ecc8cfdSPierre-Yves MORDRET 	if (!i2c_dev->use_dma)
11937ecc8cfdSPierre-Yves MORDRET 		cr1 |= STM32F7_I2C_CR1_RXIE;
11947ecc8cfdSPierre-Yves MORDRET 	else
11957ecc8cfdSPierre-Yves MORDRET 		cr1 |= STM32F7_I2C_CR1_RXDMAEN;
11967ecc8cfdSPierre-Yves MORDRET 
11979e48155fSPierre-Yves MORDRET 	/* Configure Repeated Start */
11989e48155fSPierre-Yves MORDRET 	cr2 |= STM32F7_I2C_CR2_START;
11999e48155fSPierre-Yves MORDRET 
12009e48155fSPierre-Yves MORDRET 	/* Write configurations registers */
12019e48155fSPierre-Yves MORDRET 	writel_relaxed(cr1, base + STM32F7_I2C_CR1);
12029e48155fSPierre-Yves MORDRET 	writel_relaxed(cr2, base + STM32F7_I2C_CR2);
12039e48155fSPierre-Yves MORDRET }
12049e48155fSPierre-Yves MORDRET 
stm32f7_i2c_smbus_check_pec(struct stm32f7_i2c_dev * i2c_dev)12059e48155fSPierre-Yves MORDRET static int stm32f7_i2c_smbus_check_pec(struct stm32f7_i2c_dev *i2c_dev)
12069e48155fSPierre-Yves MORDRET {
12079e48155fSPierre-Yves MORDRET 	struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg;
12089e48155fSPierre-Yves MORDRET 	u8 count, internal_pec, received_pec;
12099e48155fSPierre-Yves MORDRET 
12109e48155fSPierre-Yves MORDRET 	internal_pec = readl_relaxed(i2c_dev->base + STM32F7_I2C_PECR);
12119e48155fSPierre-Yves MORDRET 
12129e48155fSPierre-Yves MORDRET 	switch (f7_msg->size) {
12139e48155fSPierre-Yves MORDRET 	case I2C_SMBUS_BYTE:
12149e48155fSPierre-Yves MORDRET 	case I2C_SMBUS_BYTE_DATA:
12159e48155fSPierre-Yves MORDRET 		received_pec = f7_msg->smbus_buf[1];
12169e48155fSPierre-Yves MORDRET 		break;
12179e48155fSPierre-Yves MORDRET 	case I2C_SMBUS_WORD_DATA:
12189e48155fSPierre-Yves MORDRET 	case I2C_SMBUS_PROC_CALL:
12199e48155fSPierre-Yves MORDRET 		received_pec = f7_msg->smbus_buf[2];
12209e48155fSPierre-Yves MORDRET 		break;
12219e48155fSPierre-Yves MORDRET 	case I2C_SMBUS_BLOCK_DATA:
12229e48155fSPierre-Yves MORDRET 	case I2C_SMBUS_BLOCK_PROC_CALL:
12239e48155fSPierre-Yves MORDRET 		count = f7_msg->smbus_buf[0];
12249e48155fSPierre-Yves MORDRET 		received_pec = f7_msg->smbus_buf[count];
12259e48155fSPierre-Yves MORDRET 		break;
12269e48155fSPierre-Yves MORDRET 	default:
12279e48155fSPierre-Yves MORDRET 		dev_err(i2c_dev->dev, "Unsupported smbus protocol for PEC\n");
12289e48155fSPierre-Yves MORDRET 		return -EINVAL;
12299e48155fSPierre-Yves MORDRET 	}
12309e48155fSPierre-Yves MORDRET 
12319e48155fSPierre-Yves MORDRET 	if (internal_pec != received_pec) {
12329e48155fSPierre-Yves MORDRET 		dev_err(i2c_dev->dev, "Bad PEC 0x%02x vs. 0x%02x\n",
12339e48155fSPierre-Yves MORDRET 			internal_pec, received_pec);
12349e48155fSPierre-Yves MORDRET 		return -EBADMSG;
12359e48155fSPierre-Yves MORDRET 	}
12369e48155fSPierre-Yves MORDRET 
12379e48155fSPierre-Yves MORDRET 	return 0;
12389e48155fSPierre-Yves MORDRET }
12399e48155fSPierre-Yves MORDRET 
stm32f7_i2c_is_addr_match(struct i2c_client * slave,u32 addcode)124060d609f3SPierre-Yves MORDRET static bool stm32f7_i2c_is_addr_match(struct i2c_client *slave, u32 addcode)
1241aeb068c5SPierre-Yves MORDRET {
124260d609f3SPierre-Yves MORDRET 	u32 addr;
124360d609f3SPierre-Yves MORDRET 
124460d609f3SPierre-Yves MORDRET 	if (!slave)
124560d609f3SPierre-Yves MORDRET 		return false;
124660d609f3SPierre-Yves MORDRET 
124760d609f3SPierre-Yves MORDRET 	if (slave->flags & I2C_CLIENT_TEN) {
124860d609f3SPierre-Yves MORDRET 		/*
124960d609f3SPierre-Yves MORDRET 		 * For 10-bit addr, addcode = 11110XY with
125060d609f3SPierre-Yves MORDRET 		 * X = Bit 9 of slave address
125160d609f3SPierre-Yves MORDRET 		 * Y = Bit 8 of slave address
125260d609f3SPierre-Yves MORDRET 		 */
125360d609f3SPierre-Yves MORDRET 		addr = slave->addr >> 8;
125460d609f3SPierre-Yves MORDRET 		addr |= 0x78;
125560d609f3SPierre-Yves MORDRET 		if (addr == addcode)
125660d609f3SPierre-Yves MORDRET 			return true;
125760d609f3SPierre-Yves MORDRET 	} else {
125860d609f3SPierre-Yves MORDRET 		addr = slave->addr & 0x7f;
125960d609f3SPierre-Yves MORDRET 		if (addr == addcode)
126060d609f3SPierre-Yves MORDRET 			return true;
126160d609f3SPierre-Yves MORDRET 	}
126260d609f3SPierre-Yves MORDRET 
126360d609f3SPierre-Yves MORDRET 	return false;
126460d609f3SPierre-Yves MORDRET }
126560d609f3SPierre-Yves MORDRET 
stm32f7_i2c_slave_start(struct stm32f7_i2c_dev * i2c_dev)126660d609f3SPierre-Yves MORDRET static void stm32f7_i2c_slave_start(struct stm32f7_i2c_dev *i2c_dev)
126760d609f3SPierre-Yves MORDRET {
126860d609f3SPierre-Yves MORDRET 	struct i2c_client *slave = i2c_dev->slave_running;
126960d609f3SPierre-Yves MORDRET 	void __iomem *base = i2c_dev->base;
127060d609f3SPierre-Yves MORDRET 	u32 mask;
127160d609f3SPierre-Yves MORDRET 	u8 value = 0;
127260d609f3SPierre-Yves MORDRET 
127360d609f3SPierre-Yves MORDRET 	if (i2c_dev->slave_dir) {
127460d609f3SPierre-Yves MORDRET 		/* Notify i2c slave that new read transfer is starting */
127560d609f3SPierre-Yves MORDRET 		i2c_slave_event(slave, I2C_SLAVE_READ_REQUESTED, &value);
127660d609f3SPierre-Yves MORDRET 
127760d609f3SPierre-Yves MORDRET 		/*
127860d609f3SPierre-Yves MORDRET 		 * Disable slave TX config in case of I2C combined message
127960d609f3SPierre-Yves MORDRET 		 * (I2C Write followed by I2C Read)
128060d609f3SPierre-Yves MORDRET 		 */
128160d609f3SPierre-Yves MORDRET 		mask = STM32F7_I2C_CR2_RELOAD;
128260d609f3SPierre-Yves MORDRET 		stm32f7_i2c_clr_bits(base + STM32F7_I2C_CR2, mask);
128360d609f3SPierre-Yves MORDRET 		mask = STM32F7_I2C_CR1_SBC | STM32F7_I2C_CR1_RXIE |
128460d609f3SPierre-Yves MORDRET 		       STM32F7_I2C_CR1_TCIE;
128560d609f3SPierre-Yves MORDRET 		stm32f7_i2c_clr_bits(base + STM32F7_I2C_CR1, mask);
128660d609f3SPierre-Yves MORDRET 
128760d609f3SPierre-Yves MORDRET 		/* Enable TX empty, STOP, NACK interrupts */
128860d609f3SPierre-Yves MORDRET 		mask =  STM32F7_I2C_CR1_STOPIE | STM32F7_I2C_CR1_NACKIE |
128960d609f3SPierre-Yves MORDRET 			STM32F7_I2C_CR1_TXIE;
129060d609f3SPierre-Yves MORDRET 		stm32f7_i2c_set_bits(base + STM32F7_I2C_CR1, mask);
129160d609f3SPierre-Yves MORDRET 
129202e64276SFabrice Gasnier 		/* Write 1st data byte */
129302e64276SFabrice Gasnier 		writel_relaxed(value, base + STM32F7_I2C_TXDR);
129460d609f3SPierre-Yves MORDRET 	} else {
129560d609f3SPierre-Yves MORDRET 		/* Notify i2c slave that new write transfer is starting */
129660d609f3SPierre-Yves MORDRET 		i2c_slave_event(slave, I2C_SLAVE_WRITE_REQUESTED, &value);
129760d609f3SPierre-Yves MORDRET 
129860d609f3SPierre-Yves MORDRET 		/* Set reload mode to be able to ACK/NACK each received byte */
129960d609f3SPierre-Yves MORDRET 		mask = STM32F7_I2C_CR2_RELOAD;
130060d609f3SPierre-Yves MORDRET 		stm32f7_i2c_set_bits(base + STM32F7_I2C_CR2, mask);
130160d609f3SPierre-Yves MORDRET 
130260d609f3SPierre-Yves MORDRET 		/*
130360d609f3SPierre-Yves MORDRET 		 * Set STOP, NACK, RX empty and transfer complete interrupts.*
130460d609f3SPierre-Yves MORDRET 		 * Set Slave Byte Control to be able to ACK/NACK each data
130560d609f3SPierre-Yves MORDRET 		 * byte received
130660d609f3SPierre-Yves MORDRET 		 */
130760d609f3SPierre-Yves MORDRET 		mask =  STM32F7_I2C_CR1_STOPIE | STM32F7_I2C_CR1_NACKIE |
130860d609f3SPierre-Yves MORDRET 			STM32F7_I2C_CR1_SBC | STM32F7_I2C_CR1_RXIE |
130960d609f3SPierre-Yves MORDRET 			STM32F7_I2C_CR1_TCIE;
131060d609f3SPierre-Yves MORDRET 		stm32f7_i2c_set_bits(base + STM32F7_I2C_CR1, mask);
131160d609f3SPierre-Yves MORDRET 	}
131260d609f3SPierre-Yves MORDRET }
131360d609f3SPierre-Yves MORDRET 
stm32f7_i2c_slave_addr(struct stm32f7_i2c_dev * i2c_dev)131460d609f3SPierre-Yves MORDRET static void stm32f7_i2c_slave_addr(struct stm32f7_i2c_dev *i2c_dev)
131560d609f3SPierre-Yves MORDRET {
131660d609f3SPierre-Yves MORDRET 	void __iomem *base = i2c_dev->base;
131760d609f3SPierre-Yves MORDRET 	u32 isr, addcode, dir, mask;
131860d609f3SPierre-Yves MORDRET 	int i;
131960d609f3SPierre-Yves MORDRET 
132060d609f3SPierre-Yves MORDRET 	isr = readl_relaxed(i2c_dev->base + STM32F7_I2C_ISR);
132160d609f3SPierre-Yves MORDRET 	addcode = STM32F7_I2C_ISR_ADDCODE_GET(isr);
132260d609f3SPierre-Yves MORDRET 	dir = isr & STM32F7_I2C_ISR_DIR;
132360d609f3SPierre-Yves MORDRET 
132460d609f3SPierre-Yves MORDRET 	for (i = 0; i < STM32F7_I2C_MAX_SLAVE; i++) {
132560d609f3SPierre-Yves MORDRET 		if (stm32f7_i2c_is_addr_match(i2c_dev->slave[i], addcode)) {
132660d609f3SPierre-Yves MORDRET 			i2c_dev->slave_running = i2c_dev->slave[i];
132760d609f3SPierre-Yves MORDRET 			i2c_dev->slave_dir = dir;
132860d609f3SPierre-Yves MORDRET 
132960d609f3SPierre-Yves MORDRET 			/* Start I2C slave processing */
133060d609f3SPierre-Yves MORDRET 			stm32f7_i2c_slave_start(i2c_dev);
133160d609f3SPierre-Yves MORDRET 
133260d609f3SPierre-Yves MORDRET 			/* Clear ADDR flag */
133360d609f3SPierre-Yves MORDRET 			mask = STM32F7_I2C_ICR_ADDRCF;
133460d609f3SPierre-Yves MORDRET 			writel_relaxed(mask, base + STM32F7_I2C_ICR);
133560d609f3SPierre-Yves MORDRET 			break;
133660d609f3SPierre-Yves MORDRET 		}
133760d609f3SPierre-Yves MORDRET 	}
133860d609f3SPierre-Yves MORDRET }
133960d609f3SPierre-Yves MORDRET 
stm32f7_i2c_get_slave_id(struct stm32f7_i2c_dev * i2c_dev,struct i2c_client * slave,int * id)134060d609f3SPierre-Yves MORDRET static int stm32f7_i2c_get_slave_id(struct stm32f7_i2c_dev *i2c_dev,
134160d609f3SPierre-Yves MORDRET 				    struct i2c_client *slave, int *id)
134260d609f3SPierre-Yves MORDRET {
134360d609f3SPierre-Yves MORDRET 	int i;
134460d609f3SPierre-Yves MORDRET 
134560d609f3SPierre-Yves MORDRET 	for (i = 0; i < STM32F7_I2C_MAX_SLAVE; i++) {
134660d609f3SPierre-Yves MORDRET 		if (i2c_dev->slave[i] == slave) {
134760d609f3SPierre-Yves MORDRET 			*id = i;
134860d609f3SPierre-Yves MORDRET 			return 0;
134960d609f3SPierre-Yves MORDRET 		}
135060d609f3SPierre-Yves MORDRET 	}
135160d609f3SPierre-Yves MORDRET 
135260d609f3SPierre-Yves MORDRET 	dev_err(i2c_dev->dev, "Slave 0x%x not registered\n", slave->addr);
135360d609f3SPierre-Yves MORDRET 
135460d609f3SPierre-Yves MORDRET 	return -ENODEV;
135560d609f3SPierre-Yves MORDRET }
135660d609f3SPierre-Yves MORDRET 
stm32f7_i2c_get_free_slave_id(struct stm32f7_i2c_dev * i2c_dev,struct i2c_client * slave,int * id)135760d609f3SPierre-Yves MORDRET static int stm32f7_i2c_get_free_slave_id(struct stm32f7_i2c_dev *i2c_dev,
135860d609f3SPierre-Yves MORDRET 					 struct i2c_client *slave, int *id)
135960d609f3SPierre-Yves MORDRET {
136060d609f3SPierre-Yves MORDRET 	struct device *dev = i2c_dev->dev;
136160d609f3SPierre-Yves MORDRET 	int i;
136260d609f3SPierre-Yves MORDRET 
136360d609f3SPierre-Yves MORDRET 	/*
1364b62590a9SAlain Volmat 	 * slave[STM32F7_SLAVE_HOSTNOTIFY] support only SMBus Host address (0x8)
1365b62590a9SAlain Volmat 	 * slave[STM32F7_SLAVE_7_10_BITS_ADDR] supports 7-bit and 10-bit slave address
1366b62590a9SAlain Volmat 	 * slave[STM32F7_SLAVE_7_BITS_ADDR] supports 7-bit slave address only
136760d609f3SPierre-Yves MORDRET 	 */
13686af07719SAlain Volmat 	if (i2c_dev->smbus_mode && (slave->addr == 0x08)) {
1369b62590a9SAlain Volmat 		if (i2c_dev->slave[STM32F7_SLAVE_HOSTNOTIFY])
13706af07719SAlain Volmat 			goto fail;
1371b62590a9SAlain Volmat 		*id = STM32F7_SLAVE_HOSTNOTIFY;
13726af07719SAlain Volmat 		return 0;
13736af07719SAlain Volmat 	}
13746af07719SAlain Volmat 
1375b62590a9SAlain Volmat 	for (i = STM32F7_I2C_MAX_SLAVE - 1; i > STM32F7_SLAVE_HOSTNOTIFY; i--) {
1376b62590a9SAlain Volmat 		if ((i == STM32F7_SLAVE_7_BITS_ADDR) &&
1377b62590a9SAlain Volmat 		    (slave->flags & I2C_CLIENT_TEN))
137860d609f3SPierre-Yves MORDRET 			continue;
137960d609f3SPierre-Yves MORDRET 		if (!i2c_dev->slave[i]) {
138060d609f3SPierre-Yves MORDRET 			*id = i;
138160d609f3SPierre-Yves MORDRET 			return 0;
138260d609f3SPierre-Yves MORDRET 		}
138360d609f3SPierre-Yves MORDRET 	}
138460d609f3SPierre-Yves MORDRET 
13856af07719SAlain Volmat fail:
138660d609f3SPierre-Yves MORDRET 	dev_err(dev, "Slave 0x%x could not be registered\n", slave->addr);
138760d609f3SPierre-Yves MORDRET 
138860d609f3SPierre-Yves MORDRET 	return -EINVAL;
138960d609f3SPierre-Yves MORDRET }
139060d609f3SPierre-Yves MORDRET 
stm32f7_i2c_is_slave_registered(struct stm32f7_i2c_dev * i2c_dev)139160d609f3SPierre-Yves MORDRET static bool stm32f7_i2c_is_slave_registered(struct stm32f7_i2c_dev *i2c_dev)
139260d609f3SPierre-Yves MORDRET {
139360d609f3SPierre-Yves MORDRET 	int i;
139460d609f3SPierre-Yves MORDRET 
139560d609f3SPierre-Yves MORDRET 	for (i = 0; i < STM32F7_I2C_MAX_SLAVE; i++) {
139660d609f3SPierre-Yves MORDRET 		if (i2c_dev->slave[i])
139760d609f3SPierre-Yves MORDRET 			return true;
139860d609f3SPierre-Yves MORDRET 	}
139960d609f3SPierre-Yves MORDRET 
140060d609f3SPierre-Yves MORDRET 	return false;
140160d609f3SPierre-Yves MORDRET }
140260d609f3SPierre-Yves MORDRET 
stm32f7_i2c_is_slave_busy(struct stm32f7_i2c_dev * i2c_dev)140360d609f3SPierre-Yves MORDRET static bool stm32f7_i2c_is_slave_busy(struct stm32f7_i2c_dev *i2c_dev)
140460d609f3SPierre-Yves MORDRET {
140560d609f3SPierre-Yves MORDRET 	int i, busy;
140660d609f3SPierre-Yves MORDRET 
140760d609f3SPierre-Yves MORDRET 	busy = 0;
140860d609f3SPierre-Yves MORDRET 	for (i = 0; i < STM32F7_I2C_MAX_SLAVE; i++) {
140960d609f3SPierre-Yves MORDRET 		if (i2c_dev->slave[i])
141060d609f3SPierre-Yves MORDRET 			busy++;
141160d609f3SPierre-Yves MORDRET 	}
141260d609f3SPierre-Yves MORDRET 
141360d609f3SPierre-Yves MORDRET 	return i == busy;
141460d609f3SPierre-Yves MORDRET }
141560d609f3SPierre-Yves MORDRET 
stm32f7_i2c_slave_isr_event(struct stm32f7_i2c_dev * i2c_dev)141660d609f3SPierre-Yves MORDRET static irqreturn_t stm32f7_i2c_slave_isr_event(struct stm32f7_i2c_dev *i2c_dev)
141760d609f3SPierre-Yves MORDRET {
141860d609f3SPierre-Yves MORDRET 	void __iomem *base = i2c_dev->base;
141960d609f3SPierre-Yves MORDRET 	u32 cr2, status, mask;
142060d609f3SPierre-Yves MORDRET 	u8 val;
142160d609f3SPierre-Yves MORDRET 	int ret;
142260d609f3SPierre-Yves MORDRET 
142360d609f3SPierre-Yves MORDRET 	status = readl_relaxed(i2c_dev->base + STM32F7_I2C_ISR);
142460d609f3SPierre-Yves MORDRET 
142560d609f3SPierre-Yves MORDRET 	/* Slave transmitter mode */
142660d609f3SPierre-Yves MORDRET 	if (status & STM32F7_I2C_ISR_TXIS) {
142760d609f3SPierre-Yves MORDRET 		i2c_slave_event(i2c_dev->slave_running,
142860d609f3SPierre-Yves MORDRET 				I2C_SLAVE_READ_PROCESSED,
142960d609f3SPierre-Yves MORDRET 				&val);
143060d609f3SPierre-Yves MORDRET 
143160d609f3SPierre-Yves MORDRET 		/* Write data byte */
143260d609f3SPierre-Yves MORDRET 		writel_relaxed(val, base + STM32F7_I2C_TXDR);
143360d609f3SPierre-Yves MORDRET 	}
143460d609f3SPierre-Yves MORDRET 
143560d609f3SPierre-Yves MORDRET 	/* Transfer Complete Reload for Slave receiver mode */
143660d609f3SPierre-Yves MORDRET 	if (status & STM32F7_I2C_ISR_TCR || status & STM32F7_I2C_ISR_RXNE) {
143760d609f3SPierre-Yves MORDRET 		/*
143860d609f3SPierre-Yves MORDRET 		 * Read data byte then set NBYTES to receive next byte or NACK
143960d609f3SPierre-Yves MORDRET 		 * the current received byte
144060d609f3SPierre-Yves MORDRET 		 */
144160d609f3SPierre-Yves MORDRET 		val = readb_relaxed(i2c_dev->base + STM32F7_I2C_RXDR);
144260d609f3SPierre-Yves MORDRET 		ret = i2c_slave_event(i2c_dev->slave_running,
144360d609f3SPierre-Yves MORDRET 				      I2C_SLAVE_WRITE_RECEIVED,
144460d609f3SPierre-Yves MORDRET 				      &val);
144560d609f3SPierre-Yves MORDRET 		if (!ret) {
144660d609f3SPierre-Yves MORDRET 			cr2 = readl_relaxed(i2c_dev->base + STM32F7_I2C_CR2);
144760d609f3SPierre-Yves MORDRET 			cr2 |= STM32F7_I2C_CR2_NBYTES(1);
144860d609f3SPierre-Yves MORDRET 			writel_relaxed(cr2, i2c_dev->base + STM32F7_I2C_CR2);
144960d609f3SPierre-Yves MORDRET 		} else {
145060d609f3SPierre-Yves MORDRET 			mask = STM32F7_I2C_CR2_NACK;
145160d609f3SPierre-Yves MORDRET 			stm32f7_i2c_set_bits(base + STM32F7_I2C_CR2, mask);
145260d609f3SPierre-Yves MORDRET 		}
145360d609f3SPierre-Yves MORDRET 	}
145460d609f3SPierre-Yves MORDRET 
145560d609f3SPierre-Yves MORDRET 	/* NACK received */
145660d609f3SPierre-Yves MORDRET 	if (status & STM32F7_I2C_ISR_NACKF) {
145760d609f3SPierre-Yves MORDRET 		dev_dbg(i2c_dev->dev, "<%s>: Receive NACK\n", __func__);
145860d609f3SPierre-Yves MORDRET 		writel_relaxed(STM32F7_I2C_ICR_NACKCF, base + STM32F7_I2C_ICR);
145960d609f3SPierre-Yves MORDRET 	}
146060d609f3SPierre-Yves MORDRET 
146160d609f3SPierre-Yves MORDRET 	/* STOP received */
146260d609f3SPierre-Yves MORDRET 	if (status & STM32F7_I2C_ISR_STOPF) {
146360d609f3SPierre-Yves MORDRET 		/* Disable interrupts */
146460d609f3SPierre-Yves MORDRET 		stm32f7_i2c_disable_irq(i2c_dev, STM32F7_I2C_XFER_IRQ_MASK);
146560d609f3SPierre-Yves MORDRET 
146660d609f3SPierre-Yves MORDRET 		if (i2c_dev->slave_dir) {
146760d609f3SPierre-Yves MORDRET 			/*
146860d609f3SPierre-Yves MORDRET 			 * Flush TX buffer in order to not used the byte in
146960d609f3SPierre-Yves MORDRET 			 * TXDR for the next transfer
147060d609f3SPierre-Yves MORDRET 			 */
147160d609f3SPierre-Yves MORDRET 			mask = STM32F7_I2C_ISR_TXE;
147260d609f3SPierre-Yves MORDRET 			stm32f7_i2c_set_bits(base + STM32F7_I2C_ISR, mask);
147360d609f3SPierre-Yves MORDRET 		}
147460d609f3SPierre-Yves MORDRET 
147560d609f3SPierre-Yves MORDRET 		/* Clear STOP flag */
147660d609f3SPierre-Yves MORDRET 		writel_relaxed(STM32F7_I2C_ICR_STOPCF, base + STM32F7_I2C_ICR);
147760d609f3SPierre-Yves MORDRET 
147860d609f3SPierre-Yves MORDRET 		/* Notify i2c slave that a STOP flag has been detected */
147960d609f3SPierre-Yves MORDRET 		i2c_slave_event(i2c_dev->slave_running, I2C_SLAVE_STOP, &val);
148060d609f3SPierre-Yves MORDRET 
148160d609f3SPierre-Yves MORDRET 		i2c_dev->slave_running = NULL;
148260d609f3SPierre-Yves MORDRET 	}
148360d609f3SPierre-Yves MORDRET 
148460d609f3SPierre-Yves MORDRET 	/* Address match received */
148560d609f3SPierre-Yves MORDRET 	if (status & STM32F7_I2C_ISR_ADDR)
148660d609f3SPierre-Yves MORDRET 		stm32f7_i2c_slave_addr(i2c_dev);
148760d609f3SPierre-Yves MORDRET 
148860d609f3SPierre-Yves MORDRET 	return IRQ_HANDLED;
1489aeb068c5SPierre-Yves MORDRET }
1490aeb068c5SPierre-Yves MORDRET 
stm32f7_i2c_isr_event(int irq,void * data)1491aeb068c5SPierre-Yves MORDRET static irqreturn_t stm32f7_i2c_isr_event(int irq, void *data)
1492aeb068c5SPierre-Yves MORDRET {
1493aeb068c5SPierre-Yves MORDRET 	struct stm32f7_i2c_dev *i2c_dev = data;
1494aeb068c5SPierre-Yves MORDRET 	struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg;
149531b90a95SAlain Volmat 	struct stm32_i2c_dma *dma = i2c_dev->dma;
1496aeb068c5SPierre-Yves MORDRET 	void __iomem *base = i2c_dev->base;
1497aeb068c5SPierre-Yves MORDRET 	u32 status, mask;
14987ecc8cfdSPierre-Yves MORDRET 	int ret = IRQ_HANDLED;
149960d609f3SPierre-Yves MORDRET 
150060d609f3SPierre-Yves MORDRET 	/* Check if the interrupt if for a slave device */
150160d609f3SPierre-Yves MORDRET 	if (!i2c_dev->master_mode) {
150260d609f3SPierre-Yves MORDRET 		ret = stm32f7_i2c_slave_isr_event(i2c_dev);
150360d609f3SPierre-Yves MORDRET 		return ret;
150460d609f3SPierre-Yves MORDRET 	}
1505aeb068c5SPierre-Yves MORDRET 
1506aeb068c5SPierre-Yves MORDRET 	status = readl_relaxed(i2c_dev->base + STM32F7_I2C_ISR);
1507aeb068c5SPierre-Yves MORDRET 
1508aeb068c5SPierre-Yves MORDRET 	/* Tx empty */
1509aeb068c5SPierre-Yves MORDRET 	if (status & STM32F7_I2C_ISR_TXIS)
1510aeb068c5SPierre-Yves MORDRET 		stm32f7_i2c_write_tx_data(i2c_dev);
1511aeb068c5SPierre-Yves MORDRET 
1512aeb068c5SPierre-Yves MORDRET 	/* RX not empty */
1513aeb068c5SPierre-Yves MORDRET 	if (status & STM32F7_I2C_ISR_RXNE)
1514aeb068c5SPierre-Yves MORDRET 		stm32f7_i2c_read_rx_data(i2c_dev);
1515aeb068c5SPierre-Yves MORDRET 
1516aeb068c5SPierre-Yves MORDRET 	/* NACK received */
1517aeb068c5SPierre-Yves MORDRET 	if (status & STM32F7_I2C_ISR_NACKF) {
151879d48da3SFabrice Gasnier 		dev_dbg(i2c_dev->dev, "<%s>: Receive NACK (addr %x)\n",
151979d48da3SFabrice Gasnier 			__func__, f7_msg->addr);
1520aeb068c5SPierre-Yves MORDRET 		writel_relaxed(STM32F7_I2C_ICR_NACKCF, base + STM32F7_I2C_ICR);
152131b90a95SAlain Volmat 		if (i2c_dev->use_dma) {
152231b90a95SAlain Volmat 			stm32f7_i2c_disable_dma_req(i2c_dev);
15231229f82dSAlain Volmat 			dmaengine_terminate_async(dma->chan_using);
152431b90a95SAlain Volmat 		}
1525aeb068c5SPierre-Yves MORDRET 		f7_msg->result = -ENXIO;
1526aeb068c5SPierre-Yves MORDRET 	}
1527aeb068c5SPierre-Yves MORDRET 
1528aeb068c5SPierre-Yves MORDRET 	/* STOP detection flag */
1529aeb068c5SPierre-Yves MORDRET 	if (status & STM32F7_I2C_ISR_STOPF) {
1530aeb068c5SPierre-Yves MORDRET 		/* Disable interrupts */
153160d609f3SPierre-Yves MORDRET 		if (stm32f7_i2c_is_slave_registered(i2c_dev))
153260d609f3SPierre-Yves MORDRET 			mask = STM32F7_I2C_XFER_IRQ_MASK;
153360d609f3SPierre-Yves MORDRET 		else
153460d609f3SPierre-Yves MORDRET 			mask = STM32F7_I2C_ALL_IRQ_MASK;
153560d609f3SPierre-Yves MORDRET 		stm32f7_i2c_disable_irq(i2c_dev, mask);
1536aeb068c5SPierre-Yves MORDRET 
1537aeb068c5SPierre-Yves MORDRET 		/* Clear STOP flag */
1538aeb068c5SPierre-Yves MORDRET 		writel_relaxed(STM32F7_I2C_ICR_STOPCF, base + STM32F7_I2C_ICR);
1539aeb068c5SPierre-Yves MORDRET 
154031b90a95SAlain Volmat 		if (i2c_dev->use_dma && !f7_msg->result) {
15417ecc8cfdSPierre-Yves MORDRET 			ret = IRQ_WAKE_THREAD;
15427ecc8cfdSPierre-Yves MORDRET 		} else {
154360d609f3SPierre-Yves MORDRET 			i2c_dev->master_mode = false;
1544aeb068c5SPierre-Yves MORDRET 			complete(&i2c_dev->complete);
1545aeb068c5SPierre-Yves MORDRET 		}
15467ecc8cfdSPierre-Yves MORDRET 	}
1547aeb068c5SPierre-Yves MORDRET 
1548aeb068c5SPierre-Yves MORDRET 	/* Transfer complete */
1549aeb068c5SPierre-Yves MORDRET 	if (status & STM32F7_I2C_ISR_TC) {
1550aeb068c5SPierre-Yves MORDRET 		if (f7_msg->stop) {
1551aeb068c5SPierre-Yves MORDRET 			mask = STM32F7_I2C_CR2_STOP;
1552aeb068c5SPierre-Yves MORDRET 			stm32f7_i2c_set_bits(base + STM32F7_I2C_CR2, mask);
155331b90a95SAlain Volmat 		} else if (i2c_dev->use_dma && !f7_msg->result) {
15547ecc8cfdSPierre-Yves MORDRET 			ret = IRQ_WAKE_THREAD;
15559e48155fSPierre-Yves MORDRET 		} else if (f7_msg->smbus) {
15569e48155fSPierre-Yves MORDRET 			stm32f7_i2c_smbus_rep_start(i2c_dev);
1557aeb068c5SPierre-Yves MORDRET 		} else {
1558aeb068c5SPierre-Yves MORDRET 			i2c_dev->msg_id++;
1559aeb068c5SPierre-Yves MORDRET 			i2c_dev->msg++;
1560aeb068c5SPierre-Yves MORDRET 			stm32f7_i2c_xfer_msg(i2c_dev, i2c_dev->msg);
1561aeb068c5SPierre-Yves MORDRET 		}
1562aeb068c5SPierre-Yves MORDRET 	}
1563aeb068c5SPierre-Yves MORDRET 
15649e48155fSPierre-Yves MORDRET 	if (status & STM32F7_I2C_ISR_TCR) {
15659e48155fSPierre-Yves MORDRET 		if (f7_msg->smbus)
15669e48155fSPierre-Yves MORDRET 			stm32f7_i2c_smbus_reload(i2c_dev);
15679e48155fSPierre-Yves MORDRET 		else
1568aeb068c5SPierre-Yves MORDRET 			stm32f7_i2c_reload(i2c_dev);
15699e48155fSPierre-Yves MORDRET 	}
1570aeb068c5SPierre-Yves MORDRET 
15717ecc8cfdSPierre-Yves MORDRET 	return ret;
15727ecc8cfdSPierre-Yves MORDRET }
15737ecc8cfdSPierre-Yves MORDRET 
stm32f7_i2c_isr_event_thread(int irq,void * data)15747ecc8cfdSPierre-Yves MORDRET static irqreturn_t stm32f7_i2c_isr_event_thread(int irq, void *data)
15757ecc8cfdSPierre-Yves MORDRET {
15767ecc8cfdSPierre-Yves MORDRET 	struct stm32f7_i2c_dev *i2c_dev = data;
15777ecc8cfdSPierre-Yves MORDRET 	struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg;
15787ecc8cfdSPierre-Yves MORDRET 	struct stm32_i2c_dma *dma = i2c_dev->dma;
15797ecc8cfdSPierre-Yves MORDRET 	u32 status;
15807ecc8cfdSPierre-Yves MORDRET 	int ret;
15817ecc8cfdSPierre-Yves MORDRET 
15827ecc8cfdSPierre-Yves MORDRET 	/*
15837ecc8cfdSPierre-Yves MORDRET 	 * Wait for dma transfer completion before sending next message or
15847ecc8cfdSPierre-Yves MORDRET 	 * notity the end of xfer to the client
15857ecc8cfdSPierre-Yves MORDRET 	 */
15867ecc8cfdSPierre-Yves MORDRET 	ret = wait_for_completion_timeout(&i2c_dev->dma->dma_complete, HZ);
15877ecc8cfdSPierre-Yves MORDRET 	if (!ret) {
15887ecc8cfdSPierre-Yves MORDRET 		dev_dbg(i2c_dev->dev, "<%s>: Timed out\n", __func__);
15897ecc8cfdSPierre-Yves MORDRET 		stm32f7_i2c_disable_dma_req(i2c_dev);
15901229f82dSAlain Volmat 		dmaengine_terminate_async(dma->chan_using);
15917ecc8cfdSPierre-Yves MORDRET 		f7_msg->result = -ETIMEDOUT;
15927ecc8cfdSPierre-Yves MORDRET 	}
15937ecc8cfdSPierre-Yves MORDRET 
15947ecc8cfdSPierre-Yves MORDRET 	status = readl_relaxed(i2c_dev->base + STM32F7_I2C_ISR);
15957ecc8cfdSPierre-Yves MORDRET 
15967ecc8cfdSPierre-Yves MORDRET 	if (status & STM32F7_I2C_ISR_TC) {
15977ecc8cfdSPierre-Yves MORDRET 		if (f7_msg->smbus) {
15987ecc8cfdSPierre-Yves MORDRET 			stm32f7_i2c_smbus_rep_start(i2c_dev);
15997ecc8cfdSPierre-Yves MORDRET 		} else {
16007ecc8cfdSPierre-Yves MORDRET 			i2c_dev->msg_id++;
16017ecc8cfdSPierre-Yves MORDRET 			i2c_dev->msg++;
16027ecc8cfdSPierre-Yves MORDRET 			stm32f7_i2c_xfer_msg(i2c_dev, i2c_dev->msg);
16037ecc8cfdSPierre-Yves MORDRET 		}
16047ecc8cfdSPierre-Yves MORDRET 	} else {
16057ecc8cfdSPierre-Yves MORDRET 		i2c_dev->master_mode = false;
16067ecc8cfdSPierre-Yves MORDRET 		complete(&i2c_dev->complete);
16077ecc8cfdSPierre-Yves MORDRET 	}
16087ecc8cfdSPierre-Yves MORDRET 
1609aeb068c5SPierre-Yves MORDRET 	return IRQ_HANDLED;
1610aeb068c5SPierre-Yves MORDRET }
1611aeb068c5SPierre-Yves MORDRET 
stm32f7_i2c_isr_error(int irq,void * data)1612aeb068c5SPierre-Yves MORDRET static irqreturn_t stm32f7_i2c_isr_error(int irq, void *data)
1613aeb068c5SPierre-Yves MORDRET {
1614aeb068c5SPierre-Yves MORDRET 	struct stm32f7_i2c_dev *i2c_dev = data;
1615aeb068c5SPierre-Yves MORDRET 	struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg;
1616aeb068c5SPierre-Yves MORDRET 	void __iomem *base = i2c_dev->base;
1617aeb068c5SPierre-Yves MORDRET 	struct device *dev = i2c_dev->dev;
16187ecc8cfdSPierre-Yves MORDRET 	struct stm32_i2c_dma *dma = i2c_dev->dma;
16196d6b0d0dSFabrice Gasnier 	u32 status;
1620aeb068c5SPierre-Yves MORDRET 
1621aeb068c5SPierre-Yves MORDRET 	status = readl_relaxed(i2c_dev->base + STM32F7_I2C_ISR);
1622aeb068c5SPierre-Yves MORDRET 
1623aeb068c5SPierre-Yves MORDRET 	/* Bus error */
1624aeb068c5SPierre-Yves MORDRET 	if (status & STM32F7_I2C_ISR_BERR) {
1625b8775252SAlain Volmat 		dev_err(dev, "<%s>: Bus error accessing addr 0x%x\n",
1626b8775252SAlain Volmat 			__func__, f7_msg->addr);
1627aeb068c5SPierre-Yves MORDRET 		writel_relaxed(STM32F7_I2C_ICR_BERRCF, base + STM32F7_I2C_ICR);
1628562de4ffSPierre-Yves MORDRET 		stm32f7_i2c_release_bus(&i2c_dev->adap);
1629aeb068c5SPierre-Yves MORDRET 		f7_msg->result = -EIO;
1630aeb068c5SPierre-Yves MORDRET 	}
1631aeb068c5SPierre-Yves MORDRET 
1632aeb068c5SPierre-Yves MORDRET 	/* Arbitration loss */
1633aeb068c5SPierre-Yves MORDRET 	if (status & STM32F7_I2C_ISR_ARLO) {
1634b8775252SAlain Volmat 		dev_dbg(dev, "<%s>: Arbitration loss accessing addr 0x%x\n",
1635b8775252SAlain Volmat 			__func__, f7_msg->addr);
1636aeb068c5SPierre-Yves MORDRET 		writel_relaxed(STM32F7_I2C_ICR_ARLOCF, base + STM32F7_I2C_ICR);
1637aeb068c5SPierre-Yves MORDRET 		f7_msg->result = -EAGAIN;
1638aeb068c5SPierre-Yves MORDRET 	}
1639aeb068c5SPierre-Yves MORDRET 
16409e48155fSPierre-Yves MORDRET 	if (status & STM32F7_I2C_ISR_PECERR) {
1641b8775252SAlain Volmat 		dev_err(dev, "<%s>: PEC error in reception accessing addr 0x%x\n",
1642b8775252SAlain Volmat 			__func__, f7_msg->addr);
16439e48155fSPierre-Yves MORDRET 		writel_relaxed(STM32F7_I2C_ICR_PECCF, base + STM32F7_I2C_ICR);
16449e48155fSPierre-Yves MORDRET 		f7_msg->result = -EINVAL;
16459e48155fSPierre-Yves MORDRET 	}
16469e48155fSPierre-Yves MORDRET 
1647c8062d11SAlain Volmat 	if (status & STM32F7_I2C_ISR_ALERT) {
1648c8062d11SAlain Volmat 		dev_dbg(dev, "<%s>: SMBus alert received\n", __func__);
1649c8062d11SAlain Volmat 		writel_relaxed(STM32F7_I2C_ICR_ALERTCF, base + STM32F7_I2C_ICR);
1650c8062d11SAlain Volmat 		i2c_handle_smbus_alert(i2c_dev->alert->ara);
1651c8062d11SAlain Volmat 		return IRQ_HANDLED;
1652c8062d11SAlain Volmat 	}
1653c8062d11SAlain Volmat 
16546d6b0d0dSFabrice Gasnier 	if (!i2c_dev->slave_running) {
16556d6b0d0dSFabrice Gasnier 		u32 mask;
165660d609f3SPierre-Yves MORDRET 		/* Disable interrupts */
165760d609f3SPierre-Yves MORDRET 		if (stm32f7_i2c_is_slave_registered(i2c_dev))
165860d609f3SPierre-Yves MORDRET 			mask = STM32F7_I2C_XFER_IRQ_MASK;
165960d609f3SPierre-Yves MORDRET 		else
166060d609f3SPierre-Yves MORDRET 			mask = STM32F7_I2C_ALL_IRQ_MASK;
166160d609f3SPierre-Yves MORDRET 		stm32f7_i2c_disable_irq(i2c_dev, mask);
16626d6b0d0dSFabrice Gasnier 	}
1663aeb068c5SPierre-Yves MORDRET 
16647ecc8cfdSPierre-Yves MORDRET 	/* Disable dma */
16657ecc8cfdSPierre-Yves MORDRET 	if (i2c_dev->use_dma) {
16667ecc8cfdSPierre-Yves MORDRET 		stm32f7_i2c_disable_dma_req(i2c_dev);
16671229f82dSAlain Volmat 		dmaengine_terminate_async(dma->chan_using);
16687ecc8cfdSPierre-Yves MORDRET 	}
16697ecc8cfdSPierre-Yves MORDRET 
167060d609f3SPierre-Yves MORDRET 	i2c_dev->master_mode = false;
1671aeb068c5SPierre-Yves MORDRET 	complete(&i2c_dev->complete);
1672aeb068c5SPierre-Yves MORDRET 
1673aeb068c5SPierre-Yves MORDRET 	return IRQ_HANDLED;
1674aeb068c5SPierre-Yves MORDRET }
1675aeb068c5SPierre-Yves MORDRET 
stm32f7_i2c_xfer(struct i2c_adapter * i2c_adap,struct i2c_msg msgs[],int num)1676aeb068c5SPierre-Yves MORDRET static int stm32f7_i2c_xfer(struct i2c_adapter *i2c_adap,
1677aeb068c5SPierre-Yves MORDRET 			    struct i2c_msg msgs[], int num)
1678aeb068c5SPierre-Yves MORDRET {
1679aeb068c5SPierre-Yves MORDRET 	struct stm32f7_i2c_dev *i2c_dev = i2c_get_adapdata(i2c_adap);
1680aeb068c5SPierre-Yves MORDRET 	struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg;
16817ecc8cfdSPierre-Yves MORDRET 	struct stm32_i2c_dma *dma = i2c_dev->dma;
1682aeb068c5SPierre-Yves MORDRET 	unsigned long time_left;
1683aeb068c5SPierre-Yves MORDRET 	int ret;
1684aeb068c5SPierre-Yves MORDRET 
1685aeb068c5SPierre-Yves MORDRET 	i2c_dev->msg = msgs;
1686aeb068c5SPierre-Yves MORDRET 	i2c_dev->msg_num = num;
1687aeb068c5SPierre-Yves MORDRET 	i2c_dev->msg_id = 0;
16889e48155fSPierre-Yves MORDRET 	f7_msg->smbus = false;
1689aeb068c5SPierre-Yves MORDRET 
16902c662660SQinglang Miao 	ret = pm_runtime_resume_and_get(i2c_dev->dev);
16914e7bca6fSPierre-Yves MORDRET 	if (ret < 0)
1692aeb068c5SPierre-Yves MORDRET 		return ret;
1693aeb068c5SPierre-Yves MORDRET 
1694aeb068c5SPierre-Yves MORDRET 	ret = stm32f7_i2c_wait_free_bus(i2c_dev);
1695aeb068c5SPierre-Yves MORDRET 	if (ret)
16964e7bca6fSPierre-Yves MORDRET 		goto pm_free;
1697aeb068c5SPierre-Yves MORDRET 
1698aeb068c5SPierre-Yves MORDRET 	stm32f7_i2c_xfer_msg(i2c_dev, msgs);
1699aeb068c5SPierre-Yves MORDRET 
1700aeb068c5SPierre-Yves MORDRET 	time_left = wait_for_completion_timeout(&i2c_dev->complete,
1701aeb068c5SPierre-Yves MORDRET 						i2c_dev->adap.timeout);
1702aeb068c5SPierre-Yves MORDRET 	ret = f7_msg->result;
17030c21d02cSAlain Volmat 	if (ret) {
17041229f82dSAlain Volmat 		if (i2c_dev->use_dma)
17051229f82dSAlain Volmat 			dmaengine_synchronize(dma->chan_using);
17061229f82dSAlain Volmat 
17070c21d02cSAlain Volmat 		/*
17080c21d02cSAlain Volmat 		 * It is possible that some unsent data have already been
17090c21d02cSAlain Volmat 		 * written into TXDR. To avoid sending old data in a
17100c21d02cSAlain Volmat 		 * further transfer, flush TXDR in case of any error
17110c21d02cSAlain Volmat 		 */
17120c21d02cSAlain Volmat 		writel_relaxed(STM32F7_I2C_ISR_TXE,
17130c21d02cSAlain Volmat 			       i2c_dev->base + STM32F7_I2C_ISR);
17140c21d02cSAlain Volmat 		goto pm_free;
17150c21d02cSAlain Volmat 	}
1716aeb068c5SPierre-Yves MORDRET 
1717aeb068c5SPierre-Yves MORDRET 	if (!time_left) {
1718aeb068c5SPierre-Yves MORDRET 		dev_dbg(i2c_dev->dev, "Access to slave 0x%x timed out\n",
1719aeb068c5SPierre-Yves MORDRET 			i2c_dev->msg->addr);
17207ecc8cfdSPierre-Yves MORDRET 		if (i2c_dev->use_dma)
17211229f82dSAlain Volmat 			dmaengine_terminate_sync(dma->chan_using);
1722b933d1faSAlain Volmat 		stm32f7_i2c_wait_free_bus(i2c_dev);
1723aeb068c5SPierre-Yves MORDRET 		ret = -ETIMEDOUT;
1724aeb068c5SPierre-Yves MORDRET 	}
1725aeb068c5SPierre-Yves MORDRET 
17264e7bca6fSPierre-Yves MORDRET pm_free:
17274e7bca6fSPierre-Yves MORDRET 	pm_runtime_mark_last_busy(i2c_dev->dev);
17284e7bca6fSPierre-Yves MORDRET 	pm_runtime_put_autosuspend(i2c_dev->dev);
1729aeb068c5SPierre-Yves MORDRET 
1730aeb068c5SPierre-Yves MORDRET 	return (ret < 0) ? ret : num;
1731aeb068c5SPierre-Yves MORDRET }
1732aeb068c5SPierre-Yves MORDRET 
stm32f7_i2c_smbus_xfer(struct i2c_adapter * adapter,u16 addr,unsigned short flags,char read_write,u8 command,int size,union i2c_smbus_data * data)17339e48155fSPierre-Yves MORDRET static int stm32f7_i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr,
17349e48155fSPierre-Yves MORDRET 				  unsigned short flags, char read_write,
17359e48155fSPierre-Yves MORDRET 				  u8 command, int size,
17369e48155fSPierre-Yves MORDRET 				  union i2c_smbus_data *data)
17379e48155fSPierre-Yves MORDRET {
17389e48155fSPierre-Yves MORDRET 	struct stm32f7_i2c_dev *i2c_dev = i2c_get_adapdata(adapter);
17399e48155fSPierre-Yves MORDRET 	struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg;
17407ecc8cfdSPierre-Yves MORDRET 	struct stm32_i2c_dma *dma = i2c_dev->dma;
17419e48155fSPierre-Yves MORDRET 	struct device *dev = i2c_dev->dev;
17429e48155fSPierre-Yves MORDRET 	unsigned long timeout;
17439e48155fSPierre-Yves MORDRET 	int i, ret;
17449e48155fSPierre-Yves MORDRET 
17459e48155fSPierre-Yves MORDRET 	f7_msg->addr = addr;
17469e48155fSPierre-Yves MORDRET 	f7_msg->size = size;
17479e48155fSPierre-Yves MORDRET 	f7_msg->read_write = read_write;
17489e48155fSPierre-Yves MORDRET 	f7_msg->smbus = true;
17499e48155fSPierre-Yves MORDRET 
17502c662660SQinglang Miao 	ret = pm_runtime_resume_and_get(dev);
17514e7bca6fSPierre-Yves MORDRET 	if (ret < 0)
17529e48155fSPierre-Yves MORDRET 		return ret;
17539e48155fSPierre-Yves MORDRET 
17549e48155fSPierre-Yves MORDRET 	ret = stm32f7_i2c_wait_free_bus(i2c_dev);
17559e48155fSPierre-Yves MORDRET 	if (ret)
17564e7bca6fSPierre-Yves MORDRET 		goto pm_free;
17579e48155fSPierre-Yves MORDRET 
17589e48155fSPierre-Yves MORDRET 	ret = stm32f7_i2c_smbus_xfer_msg(i2c_dev, flags, command, data);
17599e48155fSPierre-Yves MORDRET 	if (ret)
17604e7bca6fSPierre-Yves MORDRET 		goto pm_free;
17619e48155fSPierre-Yves MORDRET 
17629e48155fSPierre-Yves MORDRET 	timeout = wait_for_completion_timeout(&i2c_dev->complete,
17639e48155fSPierre-Yves MORDRET 					      i2c_dev->adap.timeout);
17649e48155fSPierre-Yves MORDRET 	ret = f7_msg->result;
17650c21d02cSAlain Volmat 	if (ret) {
17661229f82dSAlain Volmat 		if (i2c_dev->use_dma)
17671229f82dSAlain Volmat 			dmaengine_synchronize(dma->chan_using);
17681229f82dSAlain Volmat 
17690c21d02cSAlain Volmat 		/*
17700c21d02cSAlain Volmat 		 * It is possible that some unsent data have already been
17710c21d02cSAlain Volmat 		 * written into TXDR. To avoid sending old data in a
17720c21d02cSAlain Volmat 		 * further transfer, flush TXDR in case of any error
17730c21d02cSAlain Volmat 		 */
17740c21d02cSAlain Volmat 		writel_relaxed(STM32F7_I2C_ISR_TXE,
17750c21d02cSAlain Volmat 			       i2c_dev->base + STM32F7_I2C_ISR);
17764e7bca6fSPierre-Yves MORDRET 		goto pm_free;
17770c21d02cSAlain Volmat 	}
17789e48155fSPierre-Yves MORDRET 
17799e48155fSPierre-Yves MORDRET 	if (!timeout) {
17809e48155fSPierre-Yves MORDRET 		dev_dbg(dev, "Access to slave 0x%x timed out\n", f7_msg->addr);
17817ecc8cfdSPierre-Yves MORDRET 		if (i2c_dev->use_dma)
17821229f82dSAlain Volmat 			dmaengine_terminate_sync(dma->chan_using);
1783b933d1faSAlain Volmat 		stm32f7_i2c_wait_free_bus(i2c_dev);
17849e48155fSPierre-Yves MORDRET 		ret = -ETIMEDOUT;
17854e7bca6fSPierre-Yves MORDRET 		goto pm_free;
17869e48155fSPierre-Yves MORDRET 	}
17879e48155fSPierre-Yves MORDRET 
17889e48155fSPierre-Yves MORDRET 	/* Check PEC */
17899e48155fSPierre-Yves MORDRET 	if ((flags & I2C_CLIENT_PEC) && size != I2C_SMBUS_QUICK && read_write) {
17909e48155fSPierre-Yves MORDRET 		ret = stm32f7_i2c_smbus_check_pec(i2c_dev);
17919e48155fSPierre-Yves MORDRET 		if (ret)
17924e7bca6fSPierre-Yves MORDRET 			goto pm_free;
17939e48155fSPierre-Yves MORDRET 	}
17949e48155fSPierre-Yves MORDRET 
17959e48155fSPierre-Yves MORDRET 	if (read_write && size != I2C_SMBUS_QUICK) {
17969e48155fSPierre-Yves MORDRET 		switch (size) {
17979e48155fSPierre-Yves MORDRET 		case I2C_SMBUS_BYTE:
17989e48155fSPierre-Yves MORDRET 		case I2C_SMBUS_BYTE_DATA:
17999e48155fSPierre-Yves MORDRET 			data->byte = f7_msg->smbus_buf[0];
18009e48155fSPierre-Yves MORDRET 		break;
18019e48155fSPierre-Yves MORDRET 		case I2C_SMBUS_WORD_DATA:
18029e48155fSPierre-Yves MORDRET 		case I2C_SMBUS_PROC_CALL:
18039e48155fSPierre-Yves MORDRET 			data->word = f7_msg->smbus_buf[0] |
18049e48155fSPierre-Yves MORDRET 				(f7_msg->smbus_buf[1] << 8);
18059e48155fSPierre-Yves MORDRET 		break;
18069e48155fSPierre-Yves MORDRET 		case I2C_SMBUS_BLOCK_DATA:
18079e48155fSPierre-Yves MORDRET 		case I2C_SMBUS_BLOCK_PROC_CALL:
18089e48155fSPierre-Yves MORDRET 		for (i = 0; i <= f7_msg->smbus_buf[0]; i++)
18099e48155fSPierre-Yves MORDRET 			data->block[i] = f7_msg->smbus_buf[i];
18109e48155fSPierre-Yves MORDRET 		break;
18119e48155fSPierre-Yves MORDRET 		default:
18129e48155fSPierre-Yves MORDRET 			dev_err(dev, "Unsupported smbus transaction\n");
18139e48155fSPierre-Yves MORDRET 			ret = -EINVAL;
18149e48155fSPierre-Yves MORDRET 		}
18159e48155fSPierre-Yves MORDRET 	}
18169e48155fSPierre-Yves MORDRET 
18174e7bca6fSPierre-Yves MORDRET pm_free:
18184e7bca6fSPierre-Yves MORDRET 	pm_runtime_mark_last_busy(dev);
18194e7bca6fSPierre-Yves MORDRET 	pm_runtime_put_autosuspend(dev);
18209e48155fSPierre-Yves MORDRET 	return ret;
18219e48155fSPierre-Yves MORDRET }
18229e48155fSPierre-Yves MORDRET 
stm32f7_i2c_enable_wakeup(struct stm32f7_i2c_dev * i2c_dev,bool enable)1823419be8e1SAlain Volmat static void stm32f7_i2c_enable_wakeup(struct stm32f7_i2c_dev *i2c_dev,
1824419be8e1SAlain Volmat 				      bool enable)
1825419be8e1SAlain Volmat {
1826419be8e1SAlain Volmat 	void __iomem *base = i2c_dev->base;
1827419be8e1SAlain Volmat 	u32 mask = STM32F7_I2C_CR1_WUPEN;
1828419be8e1SAlain Volmat 
1829419be8e1SAlain Volmat 	if (!i2c_dev->wakeup_src)
1830419be8e1SAlain Volmat 		return;
1831419be8e1SAlain Volmat 
1832419be8e1SAlain Volmat 	if (enable) {
1833419be8e1SAlain Volmat 		device_set_wakeup_enable(i2c_dev->dev, true);
1834419be8e1SAlain Volmat 		stm32f7_i2c_set_bits(base + STM32F7_I2C_CR1, mask);
1835419be8e1SAlain Volmat 	} else {
1836419be8e1SAlain Volmat 		device_set_wakeup_enable(i2c_dev->dev, false);
1837419be8e1SAlain Volmat 		stm32f7_i2c_clr_bits(base + STM32F7_I2C_CR1, mask);
1838419be8e1SAlain Volmat 	}
1839419be8e1SAlain Volmat }
1840419be8e1SAlain Volmat 
stm32f7_i2c_reg_slave(struct i2c_client * slave)184160d609f3SPierre-Yves MORDRET static int stm32f7_i2c_reg_slave(struct i2c_client *slave)
184260d609f3SPierre-Yves MORDRET {
184360d609f3SPierre-Yves MORDRET 	struct stm32f7_i2c_dev *i2c_dev = i2c_get_adapdata(slave->adapter);
184460d609f3SPierre-Yves MORDRET 	void __iomem *base = i2c_dev->base;
184560d609f3SPierre-Yves MORDRET 	struct device *dev = i2c_dev->dev;
184660d609f3SPierre-Yves MORDRET 	u32 oar1, oar2, mask;
184760d609f3SPierre-Yves MORDRET 	int id, ret;
184860d609f3SPierre-Yves MORDRET 
184960d609f3SPierre-Yves MORDRET 	if (slave->flags & I2C_CLIENT_PEC) {
185060d609f3SPierre-Yves MORDRET 		dev_err(dev, "SMBus PEC not supported in slave mode\n");
185160d609f3SPierre-Yves MORDRET 		return -EINVAL;
185260d609f3SPierre-Yves MORDRET 	}
185360d609f3SPierre-Yves MORDRET 
185460d609f3SPierre-Yves MORDRET 	if (stm32f7_i2c_is_slave_busy(i2c_dev)) {
185560d609f3SPierre-Yves MORDRET 		dev_err(dev, "Too much slave registered\n");
185660d609f3SPierre-Yves MORDRET 		return -EBUSY;
185760d609f3SPierre-Yves MORDRET 	}
185860d609f3SPierre-Yves MORDRET 
185960d609f3SPierre-Yves MORDRET 	ret = stm32f7_i2c_get_free_slave_id(i2c_dev, slave, &id);
186060d609f3SPierre-Yves MORDRET 	if (ret)
186160d609f3SPierre-Yves MORDRET 		return ret;
186260d609f3SPierre-Yves MORDRET 
18632c662660SQinglang Miao 	ret = pm_runtime_resume_and_get(dev);
18644e7bca6fSPierre-Yves MORDRET 	if (ret < 0)
186560d609f3SPierre-Yves MORDRET 		return ret;
186660d609f3SPierre-Yves MORDRET 
1867419be8e1SAlain Volmat 	if (!stm32f7_i2c_is_slave_registered(i2c_dev))
1868419be8e1SAlain Volmat 		stm32f7_i2c_enable_wakeup(i2c_dev, true);
1869419be8e1SAlain Volmat 
18706af07719SAlain Volmat 	switch (id) {
18716af07719SAlain Volmat 	case 0:
18726af07719SAlain Volmat 		/* Slave SMBus Host */
18736af07719SAlain Volmat 		i2c_dev->slave[id] = slave;
18746af07719SAlain Volmat 		break;
18756af07719SAlain Volmat 
18766af07719SAlain Volmat 	case 1:
187760d609f3SPierre-Yves MORDRET 		/* Configure Own Address 1 */
187860d609f3SPierre-Yves MORDRET 		oar1 = readl_relaxed(i2c_dev->base + STM32F7_I2C_OAR1);
187960d609f3SPierre-Yves MORDRET 		oar1 &= ~STM32F7_I2C_OAR1_MASK;
188060d609f3SPierre-Yves MORDRET 		if (slave->flags & I2C_CLIENT_TEN) {
188160d609f3SPierre-Yves MORDRET 			oar1 |= STM32F7_I2C_OAR1_OA1_10(slave->addr);
188260d609f3SPierre-Yves MORDRET 			oar1 |= STM32F7_I2C_OAR1_OA1MODE;
188360d609f3SPierre-Yves MORDRET 		} else {
188460d609f3SPierre-Yves MORDRET 			oar1 |= STM32F7_I2C_OAR1_OA1_7(slave->addr);
188560d609f3SPierre-Yves MORDRET 		}
188660d609f3SPierre-Yves MORDRET 		oar1 |= STM32F7_I2C_OAR1_OA1EN;
188760d609f3SPierre-Yves MORDRET 		i2c_dev->slave[id] = slave;
188860d609f3SPierre-Yves MORDRET 		writel_relaxed(oar1, i2c_dev->base + STM32F7_I2C_OAR1);
18896af07719SAlain Volmat 		break;
18906af07719SAlain Volmat 
18916af07719SAlain Volmat 	case 2:
189260d609f3SPierre-Yves MORDRET 		/* Configure Own Address 2 */
189360d609f3SPierre-Yves MORDRET 		oar2 = readl_relaxed(i2c_dev->base + STM32F7_I2C_OAR2);
189460d609f3SPierre-Yves MORDRET 		oar2 &= ~STM32F7_I2C_OAR2_MASK;
189560d609f3SPierre-Yves MORDRET 		if (slave->flags & I2C_CLIENT_TEN) {
189660d609f3SPierre-Yves MORDRET 			ret = -EOPNOTSUPP;
18974e7bca6fSPierre-Yves MORDRET 			goto pm_free;
189860d609f3SPierre-Yves MORDRET 		}
189960d609f3SPierre-Yves MORDRET 
190060d609f3SPierre-Yves MORDRET 		oar2 |= STM32F7_I2C_OAR2_OA2_7(slave->addr);
190160d609f3SPierre-Yves MORDRET 		oar2 |= STM32F7_I2C_OAR2_OA2EN;
190260d609f3SPierre-Yves MORDRET 		i2c_dev->slave[id] = slave;
190360d609f3SPierre-Yves MORDRET 		writel_relaxed(oar2, i2c_dev->base + STM32F7_I2C_OAR2);
19046af07719SAlain Volmat 		break;
19056af07719SAlain Volmat 
19066af07719SAlain Volmat 	default:
19076af07719SAlain Volmat 		dev_err(dev, "I2C slave id not supported\n");
190860d609f3SPierre-Yves MORDRET 		ret = -ENODEV;
19094e7bca6fSPierre-Yves MORDRET 		goto pm_free;
191060d609f3SPierre-Yves MORDRET 	}
191160d609f3SPierre-Yves MORDRET 
191260d609f3SPierre-Yves MORDRET 	/* Enable ACK */
191360d609f3SPierre-Yves MORDRET 	stm32f7_i2c_clr_bits(base + STM32F7_I2C_CR2, STM32F7_I2C_CR2_NACK);
191460d609f3SPierre-Yves MORDRET 
191560d609f3SPierre-Yves MORDRET 	/* Enable Address match interrupt, error interrupt and enable I2C  */
191660d609f3SPierre-Yves MORDRET 	mask = STM32F7_I2C_CR1_ADDRIE | STM32F7_I2C_CR1_ERRIE |
191760d609f3SPierre-Yves MORDRET 		STM32F7_I2C_CR1_PE;
191860d609f3SPierre-Yves MORDRET 	stm32f7_i2c_set_bits(base + STM32F7_I2C_CR1, mask);
191960d609f3SPierre-Yves MORDRET 
19204e7bca6fSPierre-Yves MORDRET 	ret = 0;
19214e7bca6fSPierre-Yves MORDRET pm_free:
1922419be8e1SAlain Volmat 	if (!stm32f7_i2c_is_slave_registered(i2c_dev))
1923419be8e1SAlain Volmat 		stm32f7_i2c_enable_wakeup(i2c_dev, false);
1924419be8e1SAlain Volmat 
19254e7bca6fSPierre-Yves MORDRET 	pm_runtime_mark_last_busy(dev);
19264e7bca6fSPierre-Yves MORDRET 	pm_runtime_put_autosuspend(dev);
192760d609f3SPierre-Yves MORDRET 
192860d609f3SPierre-Yves MORDRET 	return ret;
192960d609f3SPierre-Yves MORDRET }
193060d609f3SPierre-Yves MORDRET 
stm32f7_i2c_unreg_slave(struct i2c_client * slave)193160d609f3SPierre-Yves MORDRET static int stm32f7_i2c_unreg_slave(struct i2c_client *slave)
193260d609f3SPierre-Yves MORDRET {
193360d609f3SPierre-Yves MORDRET 	struct stm32f7_i2c_dev *i2c_dev = i2c_get_adapdata(slave->adapter);
193460d609f3SPierre-Yves MORDRET 	void __iomem *base = i2c_dev->base;
193560d609f3SPierre-Yves MORDRET 	u32 mask;
193660d609f3SPierre-Yves MORDRET 	int id, ret;
193760d609f3SPierre-Yves MORDRET 
193860d609f3SPierre-Yves MORDRET 	ret = stm32f7_i2c_get_slave_id(i2c_dev, slave, &id);
193960d609f3SPierre-Yves MORDRET 	if (ret)
194060d609f3SPierre-Yves MORDRET 		return ret;
194160d609f3SPierre-Yves MORDRET 
194260d609f3SPierre-Yves MORDRET 	WARN_ON(!i2c_dev->slave[id]);
194360d609f3SPierre-Yves MORDRET 
19442c662660SQinglang Miao 	ret = pm_runtime_resume_and_get(i2c_dev->dev);
19454e7bca6fSPierre-Yves MORDRET 	if (ret < 0)
19464e7bca6fSPierre-Yves MORDRET 		return ret;
19474e7bca6fSPierre-Yves MORDRET 
19486af07719SAlain Volmat 	if (id == 1) {
194960d609f3SPierre-Yves MORDRET 		mask = STM32F7_I2C_OAR1_OA1EN;
195060d609f3SPierre-Yves MORDRET 		stm32f7_i2c_clr_bits(base + STM32F7_I2C_OAR1, mask);
19516af07719SAlain Volmat 	} else if (id == 2) {
195260d609f3SPierre-Yves MORDRET 		mask = STM32F7_I2C_OAR2_OA2EN;
195360d609f3SPierre-Yves MORDRET 		stm32f7_i2c_clr_bits(base + STM32F7_I2C_OAR2, mask);
195460d609f3SPierre-Yves MORDRET 	}
195560d609f3SPierre-Yves MORDRET 
195660d609f3SPierre-Yves MORDRET 	i2c_dev->slave[id] = NULL;
195760d609f3SPierre-Yves MORDRET 
1958419be8e1SAlain Volmat 	if (!stm32f7_i2c_is_slave_registered(i2c_dev)) {
195960d609f3SPierre-Yves MORDRET 		stm32f7_i2c_disable_irq(i2c_dev, STM32F7_I2C_ALL_IRQ_MASK);
1960419be8e1SAlain Volmat 		stm32f7_i2c_enable_wakeup(i2c_dev, false);
1961419be8e1SAlain Volmat 	}
19624e7bca6fSPierre-Yves MORDRET 
19634e7bca6fSPierre-Yves MORDRET 	pm_runtime_mark_last_busy(i2c_dev->dev);
19644e7bca6fSPierre-Yves MORDRET 	pm_runtime_put_autosuspend(i2c_dev->dev);
196560d609f3SPierre-Yves MORDRET 
196660d609f3SPierre-Yves MORDRET 	return 0;
196760d609f3SPierre-Yves MORDRET }
196860d609f3SPierre-Yves MORDRET 
stm32f7_i2c_write_fm_plus_bits(struct stm32f7_i2c_dev * i2c_dev,bool enable)19693347ea9bSAlain Volmat static int stm32f7_i2c_write_fm_plus_bits(struct stm32f7_i2c_dev *i2c_dev,
19703347ea9bSAlain Volmat 					  bool enable)
19713347ea9bSAlain Volmat {
19720f820564SAlain Volmat 	int ret;
19730f820564SAlain Volmat 
197409cc9a3bSAlain Volmat 	if (i2c_dev->bus_rate <= I2C_MAX_FAST_MODE_FREQ ||
19753347ea9bSAlain Volmat 	    IS_ERR_OR_NULL(i2c_dev->regmap))
19763347ea9bSAlain Volmat 		/* Optional */
19773347ea9bSAlain Volmat 		return 0;
19783347ea9bSAlain Volmat 
19790f820564SAlain Volmat 	if (i2c_dev->fmp_sreg == i2c_dev->fmp_creg)
19800f820564SAlain Volmat 		ret = regmap_update_bits(i2c_dev->regmap,
19810f820564SAlain Volmat 					 i2c_dev->fmp_sreg,
19823347ea9bSAlain Volmat 					 i2c_dev->fmp_mask,
19833347ea9bSAlain Volmat 					 enable ? i2c_dev->fmp_mask : 0);
19840f820564SAlain Volmat 	else
19850f820564SAlain Volmat 		ret = regmap_write(i2c_dev->regmap,
19860f820564SAlain Volmat 				   enable ? i2c_dev->fmp_sreg :
19870f820564SAlain Volmat 					    i2c_dev->fmp_creg,
19880f820564SAlain Volmat 				   i2c_dev->fmp_mask);
19890f820564SAlain Volmat 
19900f820564SAlain Volmat 	return ret;
19913347ea9bSAlain Volmat }
19923347ea9bSAlain Volmat 
stm32f7_i2c_setup_fm_plus_bits(struct platform_device * pdev,struct stm32f7_i2c_dev * i2c_dev)1993cb944fb9SPierre-Yves MORDRET static int stm32f7_i2c_setup_fm_plus_bits(struct platform_device *pdev,
1994cb944fb9SPierre-Yves MORDRET 					  struct stm32f7_i2c_dev *i2c_dev)
1995cb944fb9SPierre-Yves MORDRET {
1996cb944fb9SPierre-Yves MORDRET 	struct device_node *np = pdev->dev.of_node;
1997cb944fb9SPierre-Yves MORDRET 	int ret;
1998cb944fb9SPierre-Yves MORDRET 
1999cb944fb9SPierre-Yves MORDRET 	i2c_dev->regmap = syscon_regmap_lookup_by_phandle(np, "st,syscfg-fmp");
20003347ea9bSAlain Volmat 	if (IS_ERR(i2c_dev->regmap))
2001cb944fb9SPierre-Yves MORDRET 		/* Optional */
2002cb944fb9SPierre-Yves MORDRET 		return 0;
2003cb944fb9SPierre-Yves MORDRET 
20043347ea9bSAlain Volmat 	ret = of_property_read_u32_index(np, "st,syscfg-fmp", 1,
20050f820564SAlain Volmat 					 &i2c_dev->fmp_sreg);
2006cb944fb9SPierre-Yves MORDRET 	if (ret)
2007cb944fb9SPierre-Yves MORDRET 		return ret;
2008cb944fb9SPierre-Yves MORDRET 
20090f820564SAlain Volmat 	i2c_dev->fmp_creg = i2c_dev->fmp_sreg +
20100f820564SAlain Volmat 			       i2c_dev->setup.fmp_clr_offset;
20110f820564SAlain Volmat 
20123347ea9bSAlain Volmat 	return of_property_read_u32_index(np, "st,syscfg-fmp", 2,
20133347ea9bSAlain Volmat 					  &i2c_dev->fmp_mask);
2014cb944fb9SPierre-Yves MORDRET }
2015cb944fb9SPierre-Yves MORDRET 
stm32f7_i2c_enable_smbus_host(struct stm32f7_i2c_dev * i2c_dev)20166af07719SAlain Volmat static int stm32f7_i2c_enable_smbus_host(struct stm32f7_i2c_dev *i2c_dev)
20176af07719SAlain Volmat {
20186af07719SAlain Volmat 	struct i2c_adapter *adap = &i2c_dev->adap;
20196af07719SAlain Volmat 	void __iomem *base = i2c_dev->base;
20206af07719SAlain Volmat 	struct i2c_client *client;
20216af07719SAlain Volmat 
20226af07719SAlain Volmat 	client = i2c_new_slave_host_notify_device(adap);
20236af07719SAlain Volmat 	if (IS_ERR(client))
20246af07719SAlain Volmat 		return PTR_ERR(client);
20256af07719SAlain Volmat 
20266af07719SAlain Volmat 	i2c_dev->host_notify_client = client;
20276af07719SAlain Volmat 
20286af07719SAlain Volmat 	/* Enable SMBus Host address */
20296af07719SAlain Volmat 	stm32f7_i2c_set_bits(base + STM32F7_I2C_CR1, STM32F7_I2C_CR1_SMBHEN);
20306af07719SAlain Volmat 
20316af07719SAlain Volmat 	return 0;
20326af07719SAlain Volmat }
20336af07719SAlain Volmat 
stm32f7_i2c_disable_smbus_host(struct stm32f7_i2c_dev * i2c_dev)20346af07719SAlain Volmat static void stm32f7_i2c_disable_smbus_host(struct stm32f7_i2c_dev *i2c_dev)
20356af07719SAlain Volmat {
20366af07719SAlain Volmat 	void __iomem *base = i2c_dev->base;
20376af07719SAlain Volmat 
20386af07719SAlain Volmat 	if (i2c_dev->host_notify_client) {
20396af07719SAlain Volmat 		/* Disable SMBus Host address */
20406af07719SAlain Volmat 		stm32f7_i2c_clr_bits(base + STM32F7_I2C_CR1,
20416af07719SAlain Volmat 				     STM32F7_I2C_CR1_SMBHEN);
20426af07719SAlain Volmat 		i2c_free_slave_host_notify_device(i2c_dev->host_notify_client);
20436af07719SAlain Volmat 	}
20446af07719SAlain Volmat }
20456af07719SAlain Volmat 
stm32f7_i2c_enable_smbus_alert(struct stm32f7_i2c_dev * i2c_dev)2046c8062d11SAlain Volmat static int stm32f7_i2c_enable_smbus_alert(struct stm32f7_i2c_dev *i2c_dev)
2047c8062d11SAlain Volmat {
2048c8062d11SAlain Volmat 	struct stm32f7_i2c_alert *alert;
2049c8062d11SAlain Volmat 	struct i2c_adapter *adap = &i2c_dev->adap;
2050c8062d11SAlain Volmat 	struct device *dev = i2c_dev->dev;
2051c8062d11SAlain Volmat 	void __iomem *base = i2c_dev->base;
2052c8062d11SAlain Volmat 
2053c8062d11SAlain Volmat 	alert = devm_kzalloc(dev, sizeof(*alert), GFP_KERNEL);
2054c8062d11SAlain Volmat 	if (!alert)
2055c8062d11SAlain Volmat 		return -ENOMEM;
2056c8062d11SAlain Volmat 
2057c8062d11SAlain Volmat 	alert->ara = i2c_new_smbus_alert_device(adap, &alert->setup);
2058c8062d11SAlain Volmat 	if (IS_ERR(alert->ara))
2059c8062d11SAlain Volmat 		return PTR_ERR(alert->ara);
2060c8062d11SAlain Volmat 
2061c8062d11SAlain Volmat 	i2c_dev->alert = alert;
2062c8062d11SAlain Volmat 
2063c8062d11SAlain Volmat 	/* Enable SMBus Alert */
2064c8062d11SAlain Volmat 	stm32f7_i2c_set_bits(base + STM32F7_I2C_CR1, STM32F7_I2C_CR1_ALERTEN);
2065c8062d11SAlain Volmat 
2066c8062d11SAlain Volmat 	return 0;
2067c8062d11SAlain Volmat }
2068c8062d11SAlain Volmat 
stm32f7_i2c_disable_smbus_alert(struct stm32f7_i2c_dev * i2c_dev)2069c8062d11SAlain Volmat static void stm32f7_i2c_disable_smbus_alert(struct stm32f7_i2c_dev *i2c_dev)
2070c8062d11SAlain Volmat {
2071c8062d11SAlain Volmat 	struct stm32f7_i2c_alert *alert = i2c_dev->alert;
2072c8062d11SAlain Volmat 	void __iomem *base = i2c_dev->base;
2073c8062d11SAlain Volmat 
2074c8062d11SAlain Volmat 	if (alert) {
2075c8062d11SAlain Volmat 		/* Disable SMBus Alert */
2076c8062d11SAlain Volmat 		stm32f7_i2c_clr_bits(base + STM32F7_I2C_CR1,
2077c8062d11SAlain Volmat 				     STM32F7_I2C_CR1_ALERTEN);
2078c8062d11SAlain Volmat 		i2c_unregister_device(alert->ara);
2079c8062d11SAlain Volmat 	}
2080c8062d11SAlain Volmat }
2081c8062d11SAlain Volmat 
stm32f7_i2c_func(struct i2c_adapter * adap)2082aeb068c5SPierre-Yves MORDRET static u32 stm32f7_i2c_func(struct i2c_adapter *adap)
2083aeb068c5SPierre-Yves MORDRET {
20846af07719SAlain Volmat 	struct stm32f7_i2c_dev *i2c_dev = i2c_get_adapdata(adap);
20856af07719SAlain Volmat 
20866af07719SAlain Volmat 	u32 func = I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR | I2C_FUNC_SLAVE |
20879e48155fSPierre-Yves MORDRET 		   I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
20889e48155fSPierre-Yves MORDRET 		   I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
20899e48155fSPierre-Yves MORDRET 		   I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_BLOCK_PROC_CALL |
2090473fbdf7SFabrice Gasnier 		   I2C_FUNC_SMBUS_PROC_CALL | I2C_FUNC_SMBUS_PEC |
2091473fbdf7SFabrice Gasnier 		   I2C_FUNC_SMBUS_I2C_BLOCK;
20926af07719SAlain Volmat 
20936af07719SAlain Volmat 	if (i2c_dev->smbus_mode)
20946af07719SAlain Volmat 		func |= I2C_FUNC_SMBUS_HOST_NOTIFY;
20956af07719SAlain Volmat 
20966af07719SAlain Volmat 	return func;
2097aeb068c5SPierre-Yves MORDRET }
2098aeb068c5SPierre-Yves MORDRET 
20992252c317SNishka Dasgupta static const struct i2c_algorithm stm32f7_i2c_algo = {
2100aeb068c5SPierre-Yves MORDRET 	.master_xfer = stm32f7_i2c_xfer,
21019e48155fSPierre-Yves MORDRET 	.smbus_xfer = stm32f7_i2c_smbus_xfer,
2102aeb068c5SPierre-Yves MORDRET 	.functionality = stm32f7_i2c_func,
210360d609f3SPierre-Yves MORDRET 	.reg_slave = stm32f7_i2c_reg_slave,
210460d609f3SPierre-Yves MORDRET 	.unreg_slave = stm32f7_i2c_unreg_slave,
2105aeb068c5SPierre-Yves MORDRET };
2106aeb068c5SPierre-Yves MORDRET 
stm32f7_i2c_probe(struct platform_device * pdev)2107aeb068c5SPierre-Yves MORDRET static int stm32f7_i2c_probe(struct platform_device *pdev)
2108aeb068c5SPierre-Yves MORDRET {
2109aeb068c5SPierre-Yves MORDRET 	struct stm32f7_i2c_dev *i2c_dev;
2110aeb068c5SPierre-Yves MORDRET 	const struct stm32f7_i2c_setup *setup;
2111aeb068c5SPierre-Yves MORDRET 	struct resource *res;
2112aeb068c5SPierre-Yves MORDRET 	struct i2c_adapter *adap;
2113aeb068c5SPierre-Yves MORDRET 	struct reset_control *rst;
21147ecc8cfdSPierre-Yves MORDRET 	dma_addr_t phy_addr;
211579b44995SFabrice Gasnier 	int irq_error, irq_event, ret;
2116aeb068c5SPierre-Yves MORDRET 
2117aeb068c5SPierre-Yves MORDRET 	i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL);
2118aeb068c5SPierre-Yves MORDRET 	if (!i2c_dev)
2119aeb068c5SPierre-Yves MORDRET 		return -ENOMEM;
2120aeb068c5SPierre-Yves MORDRET 
2121c02fb2b8SDejin Zheng 	i2c_dev->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
2122aeb068c5SPierre-Yves MORDRET 	if (IS_ERR(i2c_dev->base))
2123aeb068c5SPierre-Yves MORDRET 		return PTR_ERR(i2c_dev->base);
21247ecc8cfdSPierre-Yves MORDRET 	phy_addr = (dma_addr_t)res->start;
2125aeb068c5SPierre-Yves MORDRET 
212679b44995SFabrice Gasnier 	irq_event = platform_get_irq(pdev, 0);
21275140b46cSRuan Jinjie 	if (irq_event < 0)
21285140b46cSRuan Jinjie 		return irq_event;
2129aeb068c5SPierre-Yves MORDRET 
213079b44995SFabrice Gasnier 	irq_error = platform_get_irq(pdev, 1);
21315140b46cSRuan Jinjie 	if (irq_error < 0)
21325140b46cSRuan Jinjie 		return irq_error;
2133aeb068c5SPierre-Yves MORDRET 
2134419be8e1SAlain Volmat 	i2c_dev->wakeup_src = of_property_read_bool(pdev->dev.of_node,
2135419be8e1SAlain Volmat 						    "wakeup-source");
2136419be8e1SAlain Volmat 
2137aeb068c5SPierre-Yves MORDRET 	i2c_dev->clk = devm_clk_get(&pdev->dev, NULL);
2138703b3228SKrzysztof Kozlowski 	if (IS_ERR(i2c_dev->clk))
2139703b3228SKrzysztof Kozlowski 		return dev_err_probe(&pdev->dev, PTR_ERR(i2c_dev->clk),
2140703b3228SKrzysztof Kozlowski 				     "Failed to get controller clock\n");
21414e7bca6fSPierre-Yves MORDRET 
2142aeb068c5SPierre-Yves MORDRET 	ret = clk_prepare_enable(i2c_dev->clk);
2143aeb068c5SPierre-Yves MORDRET 	if (ret) {
2144aeb068c5SPierre-Yves MORDRET 		dev_err(&pdev->dev, "Failed to prepare_enable clock\n");
2145aeb068c5SPierre-Yves MORDRET 		return ret;
2146aeb068c5SPierre-Yves MORDRET 	}
2147aeb068c5SPierre-Yves MORDRET 
2148aeb068c5SPierre-Yves MORDRET 	rst = devm_reset_control_get(&pdev->dev, NULL);
2149aeb068c5SPierre-Yves MORDRET 	if (IS_ERR(rst)) {
2150703b3228SKrzysztof Kozlowski 		ret = dev_err_probe(&pdev->dev, PTR_ERR(rst),
2151703b3228SKrzysztof Kozlowski 				    "Error: Missing reset ctrl\n");
2152aeb068c5SPierre-Yves MORDRET 		goto clk_free;
2153aeb068c5SPierre-Yves MORDRET 	}
2154aeb068c5SPierre-Yves MORDRET 	reset_control_assert(rst);
2155aeb068c5SPierre-Yves MORDRET 	udelay(2);
2156aeb068c5SPierre-Yves MORDRET 	reset_control_deassert(rst);
2157aeb068c5SPierre-Yves MORDRET 
2158aeb068c5SPierre-Yves MORDRET 	i2c_dev->dev = &pdev->dev;
2159aeb068c5SPierre-Yves MORDRET 
21607ecc8cfdSPierre-Yves MORDRET 	ret = devm_request_threaded_irq(&pdev->dev, irq_event,
21617ecc8cfdSPierre-Yves MORDRET 					stm32f7_i2c_isr_event,
21627ecc8cfdSPierre-Yves MORDRET 					stm32f7_i2c_isr_event_thread,
21637ecc8cfdSPierre-Yves MORDRET 					IRQF_ONESHOT,
2164aeb068c5SPierre-Yves MORDRET 					pdev->name, i2c_dev);
2165aeb068c5SPierre-Yves MORDRET 	if (ret) {
2166aeb068c5SPierre-Yves MORDRET 		dev_err(&pdev->dev, "Failed to request irq event %i\n",
2167aeb068c5SPierre-Yves MORDRET 			irq_event);
2168aeb068c5SPierre-Yves MORDRET 		goto clk_free;
2169aeb068c5SPierre-Yves MORDRET 	}
2170aeb068c5SPierre-Yves MORDRET 
2171aeb068c5SPierre-Yves MORDRET 	ret = devm_request_irq(&pdev->dev, irq_error, stm32f7_i2c_isr_error, 0,
2172aeb068c5SPierre-Yves MORDRET 			       pdev->name, i2c_dev);
2173aeb068c5SPierre-Yves MORDRET 	if (ret) {
2174aeb068c5SPierre-Yves MORDRET 		dev_err(&pdev->dev, "Failed to request irq error %i\n",
2175aeb068c5SPierre-Yves MORDRET 			irq_error);
2176aeb068c5SPierre-Yves MORDRET 		goto clk_free;
2177aeb068c5SPierre-Yves MORDRET 	}
2178aeb068c5SPierre-Yves MORDRET 
2179aeb068c5SPierre-Yves MORDRET 	setup = of_device_get_match_data(&pdev->dev);
2180771b7bf0SPierre-Yves MORDRET 	if (!setup) {
2181771b7bf0SPierre-Yves MORDRET 		dev_err(&pdev->dev, "Can't get device data\n");
2182771b7bf0SPierre-Yves MORDRET 		ret = -ENODEV;
2183771b7bf0SPierre-Yves MORDRET 		goto clk_free;
2184771b7bf0SPierre-Yves MORDRET 	}
2185463a9215SPierre-Yves MORDRET 	i2c_dev->setup = *setup;
2186aeb068c5SPierre-Yves MORDRET 
2187463a9215SPierre-Yves MORDRET 	ret = stm32f7_i2c_setup_timing(i2c_dev, &i2c_dev->setup);
2188aeb068c5SPierre-Yves MORDRET 	if (ret)
2189aeb068c5SPierre-Yves MORDRET 		goto clk_free;
2190aeb068c5SPierre-Yves MORDRET 
219109cc9a3bSAlain Volmat 	/* Setup Fast mode plus if necessary */
219209cc9a3bSAlain Volmat 	if (i2c_dev->bus_rate > I2C_MAX_FAST_MODE_FREQ) {
21933347ea9bSAlain Volmat 		ret = stm32f7_i2c_setup_fm_plus_bits(pdev, i2c_dev);
21943347ea9bSAlain Volmat 		if (ret)
21953347ea9bSAlain Volmat 			goto clk_free;
21963347ea9bSAlain Volmat 		ret = stm32f7_i2c_write_fm_plus_bits(i2c_dev, true);
21973347ea9bSAlain Volmat 		if (ret)
21983347ea9bSAlain Volmat 			goto clk_free;
21993347ea9bSAlain Volmat 	}
22003347ea9bSAlain Volmat 
2201aeb068c5SPierre-Yves MORDRET 	adap = &i2c_dev->adap;
2202aeb068c5SPierre-Yves MORDRET 	i2c_set_adapdata(adap, i2c_dev);
2203aeb068c5SPierre-Yves MORDRET 	snprintf(adap->name, sizeof(adap->name), "STM32F7 I2C(%pa)",
2204aeb068c5SPierre-Yves MORDRET 		 &res->start);
2205aeb068c5SPierre-Yves MORDRET 	adap->owner = THIS_MODULE;
2206aeb068c5SPierre-Yves MORDRET 	adap->timeout = 2 * HZ;
2207aeb068c5SPierre-Yves MORDRET 	adap->retries = 3;
2208aeb068c5SPierre-Yves MORDRET 	adap->algo = &stm32f7_i2c_algo;
2209aeb068c5SPierre-Yves MORDRET 	adap->dev.parent = &pdev->dev;
2210aeb068c5SPierre-Yves MORDRET 	adap->dev.of_node = pdev->dev.of_node;
2211aeb068c5SPierre-Yves MORDRET 
2212aeb068c5SPierre-Yves MORDRET 	init_completion(&i2c_dev->complete);
2213aeb068c5SPierre-Yves MORDRET 
22147ecc8cfdSPierre-Yves MORDRET 	/* Init DMA config if supported */
22157ecc8cfdSPierre-Yves MORDRET 	i2c_dev->dma = stm32_i2c_dma_request(i2c_dev->dev, phy_addr,
22167ecc8cfdSPierre-Yves MORDRET 					     STM32F7_I2C_TXDR,
22177ecc8cfdSPierre-Yves MORDRET 					     STM32F7_I2C_RXDR);
221827c90870SAlain Volmat 	if (IS_ERR(i2c_dev->dma)) {
2219d77eceb2SAlain Volmat 		ret = PTR_ERR(i2c_dev->dma);
222027c90870SAlain Volmat 		/* DMA support is optional, only report other errors */
222127c90870SAlain Volmat 		if (ret != -ENODEV)
22223347ea9bSAlain Volmat 			goto fmp_clear;
222327c90870SAlain Volmat 		dev_dbg(i2c_dev->dev, "No DMA option: fallback using interrupts\n");
222427c90870SAlain Volmat 		i2c_dev->dma = NULL;
2225d77eceb2SAlain Volmat 	}
22267ecc8cfdSPierre-Yves MORDRET 
2227419be8e1SAlain Volmat 	if (i2c_dev->wakeup_src) {
2228419be8e1SAlain Volmat 		device_set_wakeup_capable(i2c_dev->dev, true);
2229419be8e1SAlain Volmat 
2230419be8e1SAlain Volmat 		ret = dev_pm_set_wake_irq(i2c_dev->dev, irq_event);
2231419be8e1SAlain Volmat 		if (ret) {
2232419be8e1SAlain Volmat 			dev_err(i2c_dev->dev, "Failed to set wake up irq\n");
2233419be8e1SAlain Volmat 			goto clr_wakeup_capable;
2234419be8e1SAlain Volmat 		}
2235419be8e1SAlain Volmat 	}
2236419be8e1SAlain Volmat 
2237aeb068c5SPierre-Yves MORDRET 	platform_set_drvdata(pdev, i2c_dev);
2238aeb068c5SPierre-Yves MORDRET 
22394e7bca6fSPierre-Yves MORDRET 	pm_runtime_set_autosuspend_delay(i2c_dev->dev,
22404e7bca6fSPierre-Yves MORDRET 					 STM32F7_AUTOSUSPEND_DELAY);
22414e7bca6fSPierre-Yves MORDRET 	pm_runtime_use_autosuspend(i2c_dev->dev);
22424e7bca6fSPierre-Yves MORDRET 	pm_runtime_set_active(i2c_dev->dev);
22434e7bca6fSPierre-Yves MORDRET 	pm_runtime_enable(i2c_dev->dev);
22444e7bca6fSPierre-Yves MORDRET 
22454e7bca6fSPierre-Yves MORDRET 	pm_runtime_get_noresume(&pdev->dev);
22464e7bca6fSPierre-Yves MORDRET 
22474e7bca6fSPierre-Yves MORDRET 	stm32f7_i2c_hw_config(i2c_dev);
22484e7bca6fSPierre-Yves MORDRET 
22496af07719SAlain Volmat 	i2c_dev->smbus_mode = of_property_read_bool(pdev->dev.of_node, "smbus");
22506af07719SAlain Volmat 
22514e7bca6fSPierre-Yves MORDRET 	ret = i2c_add_adapter(adap);
22524e7bca6fSPierre-Yves MORDRET 	if (ret)
22534e7bca6fSPierre-Yves MORDRET 		goto pm_disable;
2254aeb068c5SPierre-Yves MORDRET 
22556af07719SAlain Volmat 	if (i2c_dev->smbus_mode) {
22566af07719SAlain Volmat 		ret = stm32f7_i2c_enable_smbus_host(i2c_dev);
22576af07719SAlain Volmat 		if (ret) {
22586af07719SAlain Volmat 			dev_err(i2c_dev->dev,
22596af07719SAlain Volmat 				"failed to enable SMBus Host-Notify protocol (%d)\n",
22606af07719SAlain Volmat 				ret);
22616af07719SAlain Volmat 			goto i2c_adapter_remove;
22626af07719SAlain Volmat 		}
22636af07719SAlain Volmat 	}
22646af07719SAlain Volmat 
2265c8062d11SAlain Volmat 	if (of_property_read_bool(pdev->dev.of_node, "smbus-alert")) {
2266c8062d11SAlain Volmat 		ret = stm32f7_i2c_enable_smbus_alert(i2c_dev);
2267c8062d11SAlain Volmat 		if (ret) {
2268c8062d11SAlain Volmat 			dev_err(i2c_dev->dev,
2269c8062d11SAlain Volmat 				"failed to enable SMBus alert protocol (%d)\n",
2270c8062d11SAlain Volmat 				ret);
2271c8062d11SAlain Volmat 			goto i2c_disable_smbus_host;
2272c8062d11SAlain Volmat 		}
2273c8062d11SAlain Volmat 	}
2274c8062d11SAlain Volmat 
2275aeb068c5SPierre-Yves MORDRET 	dev_info(i2c_dev->dev, "STM32F7 I2C-%d bus adapter\n", adap->nr);
2276aeb068c5SPierre-Yves MORDRET 
22774e7bca6fSPierre-Yves MORDRET 	pm_runtime_mark_last_busy(i2c_dev->dev);
22784e7bca6fSPierre-Yves MORDRET 	pm_runtime_put_autosuspend(i2c_dev->dev);
22794e7bca6fSPierre-Yves MORDRET 
2280aeb068c5SPierre-Yves MORDRET 	return 0;
2281aeb068c5SPierre-Yves MORDRET 
2282c8062d11SAlain Volmat i2c_disable_smbus_host:
2283c8062d11SAlain Volmat 	stm32f7_i2c_disable_smbus_host(i2c_dev);
2284c8062d11SAlain Volmat 
22856af07719SAlain Volmat i2c_adapter_remove:
22866af07719SAlain Volmat 	i2c_del_adapter(adap);
22876af07719SAlain Volmat 
22884e7bca6fSPierre-Yves MORDRET pm_disable:
22894e7bca6fSPierre-Yves MORDRET 	pm_runtime_put_noidle(i2c_dev->dev);
22904e7bca6fSPierre-Yves MORDRET 	pm_runtime_disable(i2c_dev->dev);
22914e7bca6fSPierre-Yves MORDRET 	pm_runtime_set_suspended(i2c_dev->dev);
22924e7bca6fSPierre-Yves MORDRET 	pm_runtime_dont_use_autosuspend(i2c_dev->dev);
22934e7bca6fSPierre-Yves MORDRET 
2294419be8e1SAlain Volmat 	if (i2c_dev->wakeup_src)
2295419be8e1SAlain Volmat 		dev_pm_clear_wake_irq(i2c_dev->dev);
2296419be8e1SAlain Volmat 
2297419be8e1SAlain Volmat clr_wakeup_capable:
2298419be8e1SAlain Volmat 	if (i2c_dev->wakeup_src)
2299419be8e1SAlain Volmat 		device_set_wakeup_capable(i2c_dev->dev, false);
2300419be8e1SAlain Volmat 
230153aaaa5dSAlain Volmat 	if (i2c_dev->dma) {
230253aaaa5dSAlain Volmat 		stm32_i2c_dma_free(i2c_dev->dma);
230353aaaa5dSAlain Volmat 		i2c_dev->dma = NULL;
230453aaaa5dSAlain Volmat 	}
230553aaaa5dSAlain Volmat 
23063347ea9bSAlain Volmat fmp_clear:
23073347ea9bSAlain Volmat 	stm32f7_i2c_write_fm_plus_bits(i2c_dev, false);
23083347ea9bSAlain Volmat 
2309aeb068c5SPierre-Yves MORDRET clk_free:
2310aeb068c5SPierre-Yves MORDRET 	clk_disable_unprepare(i2c_dev->clk);
2311aeb068c5SPierre-Yves MORDRET 
2312aeb068c5SPierre-Yves MORDRET 	return ret;
2313aeb068c5SPierre-Yves MORDRET }
2314aeb068c5SPierre-Yves MORDRET 
stm32f7_i2c_remove(struct platform_device * pdev)2315e190a0c3SUwe Kleine-König static void stm32f7_i2c_remove(struct platform_device *pdev)
2316aeb068c5SPierre-Yves MORDRET {
2317aeb068c5SPierre-Yves MORDRET 	struct stm32f7_i2c_dev *i2c_dev = platform_get_drvdata(pdev);
2318aeb068c5SPierre-Yves MORDRET 
2319c8062d11SAlain Volmat 	stm32f7_i2c_disable_smbus_alert(i2c_dev);
23206af07719SAlain Volmat 	stm32f7_i2c_disable_smbus_host(i2c_dev);
23216af07719SAlain Volmat 
2322aeb068c5SPierre-Yves MORDRET 	i2c_del_adapter(&i2c_dev->adap);
23234e7bca6fSPierre-Yves MORDRET 	pm_runtime_get_sync(i2c_dev->dev);
2324aeb068c5SPierre-Yves MORDRET 
2325419be8e1SAlain Volmat 	if (i2c_dev->wakeup_src) {
2326419be8e1SAlain Volmat 		dev_pm_clear_wake_irq(i2c_dev->dev);
2327419be8e1SAlain Volmat 		/*
2328419be8e1SAlain Volmat 		 * enforce that wakeup is disabled and that the device
2329419be8e1SAlain Volmat 		 * is marked as non wakeup capable
2330419be8e1SAlain Volmat 		 */
2331419be8e1SAlain Volmat 		device_init_wakeup(i2c_dev->dev, false);
2332419be8e1SAlain Volmat 	}
2333419be8e1SAlain Volmat 
23344e7bca6fSPierre-Yves MORDRET 	pm_runtime_put_noidle(i2c_dev->dev);
23354e7bca6fSPierre-Yves MORDRET 	pm_runtime_disable(i2c_dev->dev);
23364e7bca6fSPierre-Yves MORDRET 	pm_runtime_set_suspended(i2c_dev->dev);
23374e7bca6fSPierre-Yves MORDRET 	pm_runtime_dont_use_autosuspend(i2c_dev->dev);
2338aeb068c5SPierre-Yves MORDRET 
233953aaaa5dSAlain Volmat 	if (i2c_dev->dma) {
234053aaaa5dSAlain Volmat 		stm32_i2c_dma_free(i2c_dev->dma);
234153aaaa5dSAlain Volmat 		i2c_dev->dma = NULL;
234253aaaa5dSAlain Volmat 	}
234353aaaa5dSAlain Volmat 
23443347ea9bSAlain Volmat 	stm32f7_i2c_write_fm_plus_bits(i2c_dev, false);
23453347ea9bSAlain Volmat 
234653aaaa5dSAlain Volmat 	clk_disable_unprepare(i2c_dev->clk);
2347aeb068c5SPierre-Yves MORDRET }
2348aeb068c5SPierre-Yves MORDRET 
stm32f7_i2c_runtime_suspend(struct device * dev)2349ea6dd25dSAlain Volmat static int __maybe_unused stm32f7_i2c_runtime_suspend(struct device *dev)
23504e7bca6fSPierre-Yves MORDRET {
23514e7bca6fSPierre-Yves MORDRET 	struct stm32f7_i2c_dev *i2c_dev = dev_get_drvdata(dev);
23524e7bca6fSPierre-Yves MORDRET 
23534e7bca6fSPierre-Yves MORDRET 	if (!stm32f7_i2c_is_slave_registered(i2c_dev))
23544e7bca6fSPierre-Yves MORDRET 		clk_disable_unprepare(i2c_dev->clk);
23554e7bca6fSPierre-Yves MORDRET 
23564e7bca6fSPierre-Yves MORDRET 	return 0;
23574e7bca6fSPierre-Yves MORDRET }
23584e7bca6fSPierre-Yves MORDRET 
stm32f7_i2c_runtime_resume(struct device * dev)2359ea6dd25dSAlain Volmat static int __maybe_unused stm32f7_i2c_runtime_resume(struct device *dev)
23604e7bca6fSPierre-Yves MORDRET {
23614e7bca6fSPierre-Yves MORDRET 	struct stm32f7_i2c_dev *i2c_dev = dev_get_drvdata(dev);
23624e7bca6fSPierre-Yves MORDRET 	int ret;
23634e7bca6fSPierre-Yves MORDRET 
23644e7bca6fSPierre-Yves MORDRET 	if (!stm32f7_i2c_is_slave_registered(i2c_dev)) {
23654e7bca6fSPierre-Yves MORDRET 		ret = clk_prepare_enable(i2c_dev->clk);
23664e7bca6fSPierre-Yves MORDRET 		if (ret) {
23674e7bca6fSPierre-Yves MORDRET 			dev_err(dev, "failed to prepare_enable clock\n");
23684e7bca6fSPierre-Yves MORDRET 			return ret;
23694e7bca6fSPierre-Yves MORDRET 		}
23704e7bca6fSPierre-Yves MORDRET 	}
23714e7bca6fSPierre-Yves MORDRET 
23724e7bca6fSPierre-Yves MORDRET 	return 0;
23734e7bca6fSPierre-Yves MORDRET }
2374ea6dd25dSAlain Volmat 
stm32f7_i2c_regs_backup(struct stm32f7_i2c_dev * i2c_dev)2375010e32abSAlain Volmat static int __maybe_unused stm32f7_i2c_regs_backup(struct stm32f7_i2c_dev *i2c_dev)
2376ea6dd25dSAlain Volmat {
2377ea6dd25dSAlain Volmat 	int ret;
2378ea6dd25dSAlain Volmat 	struct stm32f7_i2c_regs *backup_regs = &i2c_dev->backup_regs;
2379ea6dd25dSAlain Volmat 
23802c662660SQinglang Miao 	ret = pm_runtime_resume_and_get(i2c_dev->dev);
2381ea6dd25dSAlain Volmat 	if (ret < 0)
2382ea6dd25dSAlain Volmat 		return ret;
2383ea6dd25dSAlain Volmat 
2384ea6dd25dSAlain Volmat 	backup_regs->cr1 = readl_relaxed(i2c_dev->base + STM32F7_I2C_CR1);
2385ea6dd25dSAlain Volmat 	backup_regs->cr2 = readl_relaxed(i2c_dev->base + STM32F7_I2C_CR2);
2386ea6dd25dSAlain Volmat 	backup_regs->oar1 = readl_relaxed(i2c_dev->base + STM32F7_I2C_OAR1);
2387ea6dd25dSAlain Volmat 	backup_regs->oar2 = readl_relaxed(i2c_dev->base + STM32F7_I2C_OAR2);
2388ea6dd25dSAlain Volmat 	backup_regs->tmgr = readl_relaxed(i2c_dev->base + STM32F7_I2C_TIMINGR);
23893347ea9bSAlain Volmat 	stm32f7_i2c_write_fm_plus_bits(i2c_dev, false);
2390ea6dd25dSAlain Volmat 
2391ea6dd25dSAlain Volmat 	pm_runtime_put_sync(i2c_dev->dev);
2392ea6dd25dSAlain Volmat 
2393ea6dd25dSAlain Volmat 	return ret;
2394ea6dd25dSAlain Volmat }
2395ea6dd25dSAlain Volmat 
stm32f7_i2c_regs_restore(struct stm32f7_i2c_dev * i2c_dev)2396010e32abSAlain Volmat static int __maybe_unused stm32f7_i2c_regs_restore(struct stm32f7_i2c_dev *i2c_dev)
2397ea6dd25dSAlain Volmat {
2398ea6dd25dSAlain Volmat 	u32 cr1;
2399ea6dd25dSAlain Volmat 	int ret;
2400ea6dd25dSAlain Volmat 	struct stm32f7_i2c_regs *backup_regs = &i2c_dev->backup_regs;
2401ea6dd25dSAlain Volmat 
24022c662660SQinglang Miao 	ret = pm_runtime_resume_and_get(i2c_dev->dev);
2403ea6dd25dSAlain Volmat 	if (ret < 0)
2404ea6dd25dSAlain Volmat 		return ret;
2405ea6dd25dSAlain Volmat 
2406ea6dd25dSAlain Volmat 	cr1 = readl_relaxed(i2c_dev->base + STM32F7_I2C_CR1);
2407ea6dd25dSAlain Volmat 	if (cr1 & STM32F7_I2C_CR1_PE)
2408ea6dd25dSAlain Volmat 		stm32f7_i2c_clr_bits(i2c_dev->base + STM32F7_I2C_CR1,
2409ea6dd25dSAlain Volmat 				     STM32F7_I2C_CR1_PE);
2410ea6dd25dSAlain Volmat 
2411ea6dd25dSAlain Volmat 	writel_relaxed(backup_regs->tmgr, i2c_dev->base + STM32F7_I2C_TIMINGR);
2412ea6dd25dSAlain Volmat 	writel_relaxed(backup_regs->cr1 & ~STM32F7_I2C_CR1_PE,
2413ea6dd25dSAlain Volmat 		       i2c_dev->base + STM32F7_I2C_CR1);
2414ea6dd25dSAlain Volmat 	if (backup_regs->cr1 & STM32F7_I2C_CR1_PE)
2415ea6dd25dSAlain Volmat 		stm32f7_i2c_set_bits(i2c_dev->base + STM32F7_I2C_CR1,
2416ea6dd25dSAlain Volmat 				     STM32F7_I2C_CR1_PE);
2417ea6dd25dSAlain Volmat 	writel_relaxed(backup_regs->cr2, i2c_dev->base + STM32F7_I2C_CR2);
2418ea6dd25dSAlain Volmat 	writel_relaxed(backup_regs->oar1, i2c_dev->base + STM32F7_I2C_OAR1);
2419ea6dd25dSAlain Volmat 	writel_relaxed(backup_regs->oar2, i2c_dev->base + STM32F7_I2C_OAR2);
24203347ea9bSAlain Volmat 	stm32f7_i2c_write_fm_plus_bits(i2c_dev, true);
2421ea6dd25dSAlain Volmat 
2422ea6dd25dSAlain Volmat 	pm_runtime_put_sync(i2c_dev->dev);
2423ea6dd25dSAlain Volmat 
2424ea6dd25dSAlain Volmat 	return ret;
2425ea6dd25dSAlain Volmat }
2426ea6dd25dSAlain Volmat 
stm32f7_i2c_suspend(struct device * dev)2427010e32abSAlain Volmat static int __maybe_unused stm32f7_i2c_suspend(struct device *dev)
2428ea6dd25dSAlain Volmat {
2429ea6dd25dSAlain Volmat 	struct stm32f7_i2c_dev *i2c_dev = dev_get_drvdata(dev);
2430ea6dd25dSAlain Volmat 	int ret;
2431ea6dd25dSAlain Volmat 
2432ea6dd25dSAlain Volmat 	i2c_mark_adapter_suspended(&i2c_dev->adap);
2433419be8e1SAlain Volmat 
24344e1d9a73SPatrice Chotard 	if (!device_may_wakeup(dev) && !device_wakeup_path(dev)) {
2435ea6dd25dSAlain Volmat 		ret = stm32f7_i2c_regs_backup(i2c_dev);
2436ea6dd25dSAlain Volmat 		if (ret < 0) {
2437ea6dd25dSAlain Volmat 			i2c_mark_adapter_resumed(&i2c_dev->adap);
2438ea6dd25dSAlain Volmat 			return ret;
2439ea6dd25dSAlain Volmat 		}
2440ea6dd25dSAlain Volmat 
2441ea6dd25dSAlain Volmat 		pinctrl_pm_select_sleep_state(dev);
2442ea6dd25dSAlain Volmat 		pm_runtime_force_suspend(dev);
2443419be8e1SAlain Volmat 	}
2444ea6dd25dSAlain Volmat 
2445ea6dd25dSAlain Volmat 	return 0;
2446ea6dd25dSAlain Volmat }
2447ea6dd25dSAlain Volmat 
stm32f7_i2c_resume(struct device * dev)2448010e32abSAlain Volmat static int __maybe_unused stm32f7_i2c_resume(struct device *dev)
2449ea6dd25dSAlain Volmat {
2450ea6dd25dSAlain Volmat 	struct stm32f7_i2c_dev *i2c_dev = dev_get_drvdata(dev);
2451ea6dd25dSAlain Volmat 	int ret;
2452ea6dd25dSAlain Volmat 
24534e1d9a73SPatrice Chotard 	if (!device_may_wakeup(dev) && !device_wakeup_path(dev)) {
2454ea6dd25dSAlain Volmat 		ret = pm_runtime_force_resume(dev);
2455ea6dd25dSAlain Volmat 		if (ret < 0)
2456ea6dd25dSAlain Volmat 			return ret;
2457ea6dd25dSAlain Volmat 		pinctrl_pm_select_default_state(dev);
2458ea6dd25dSAlain Volmat 
2459ea6dd25dSAlain Volmat 		ret = stm32f7_i2c_regs_restore(i2c_dev);
2460ea6dd25dSAlain Volmat 		if (ret < 0)
2461ea6dd25dSAlain Volmat 			return ret;
2462419be8e1SAlain Volmat 	}
2463419be8e1SAlain Volmat 
2464ea6dd25dSAlain Volmat 	i2c_mark_adapter_resumed(&i2c_dev->adap);
2465ea6dd25dSAlain Volmat 
2466ea6dd25dSAlain Volmat 	return 0;
2467ea6dd25dSAlain Volmat }
24684e7bca6fSPierre-Yves MORDRET 
24694e7bca6fSPierre-Yves MORDRET static const struct dev_pm_ops stm32f7_i2c_pm_ops = {
24704e7bca6fSPierre-Yves MORDRET 	SET_RUNTIME_PM_OPS(stm32f7_i2c_runtime_suspend,
24714e7bca6fSPierre-Yves MORDRET 			   stm32f7_i2c_runtime_resume, NULL)
2472ea6dd25dSAlain Volmat 	SET_SYSTEM_SLEEP_PM_OPS(stm32f7_i2c_suspend, stm32f7_i2c_resume)
24734e7bca6fSPierre-Yves MORDRET };
24744e7bca6fSPierre-Yves MORDRET 
2475aeb068c5SPierre-Yves MORDRET static const struct of_device_id stm32f7_i2c_match[] = {
2476aeb068c5SPierre-Yves MORDRET 	{ .compatible = "st,stm32f7-i2c", .data = &stm32f7_setup},
24770f820564SAlain Volmat 	{ .compatible = "st,stm32mp15-i2c", .data = &stm32mp15_setup},
2478d4d2f170SAlain Volmat 	{ .compatible = "st,stm32mp13-i2c", .data = &stm32mp13_setup},
2479aeb068c5SPierre-Yves MORDRET 	{},
2480aeb068c5SPierre-Yves MORDRET };
2481aeb068c5SPierre-Yves MORDRET MODULE_DEVICE_TABLE(of, stm32f7_i2c_match);
2482aeb068c5SPierre-Yves MORDRET 
2483aeb068c5SPierre-Yves MORDRET static struct platform_driver stm32f7_i2c_driver = {
2484aeb068c5SPierre-Yves MORDRET 	.driver = {
2485aeb068c5SPierre-Yves MORDRET 		.name = "stm32f7-i2c",
2486aeb068c5SPierre-Yves MORDRET 		.of_match_table = stm32f7_i2c_match,
24874e7bca6fSPierre-Yves MORDRET 		.pm = &stm32f7_i2c_pm_ops,
2488aeb068c5SPierre-Yves MORDRET 	},
2489aeb068c5SPierre-Yves MORDRET 	.probe = stm32f7_i2c_probe,
2490e190a0c3SUwe Kleine-König 	.remove_new = stm32f7_i2c_remove,
2491aeb068c5SPierre-Yves MORDRET };
2492aeb068c5SPierre-Yves MORDRET 
2493aeb068c5SPierre-Yves MORDRET module_platform_driver(stm32f7_i2c_driver);
2494aeb068c5SPierre-Yves MORDRET 
2495aeb068c5SPierre-Yves MORDRET MODULE_AUTHOR("M'boumba Cedric Madianga <cedric.madianga@gmail.com>");
2496aeb068c5SPierre-Yves MORDRET MODULE_DESCRIPTION("STMicroelectronics STM32F7 I2C driver");
2497aeb068c5SPierre-Yves MORDRET MODULE_LICENSE("GPL v2");
2498