162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Driver for STMicroelectronics STM32F7 I2C controller
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * This I2C controller is described in the STM32F75xxx and STM32F74xxx Soc
662306a36Sopenharmony_ci * reference manual.
762306a36Sopenharmony_ci * Please see below a link to the documentation:
862306a36Sopenharmony_ci * http://www.st.com/resource/en/reference_manual/dm00124865.pdf
962306a36Sopenharmony_ci *
1062306a36Sopenharmony_ci * Copyright (C) M'boumba Cedric Madianga 2017
1162306a36Sopenharmony_ci * Copyright (C) STMicroelectronics 2017
1262306a36Sopenharmony_ci * Author: M'boumba Cedric Madianga <cedric.madianga@gmail.com>
1362306a36Sopenharmony_ci *
1462306a36Sopenharmony_ci * This driver is based on i2c-stm32f4.c
1562306a36Sopenharmony_ci *
1662306a36Sopenharmony_ci */
1762306a36Sopenharmony_ci#include <linux/clk.h>
1862306a36Sopenharmony_ci#include <linux/delay.h>
1962306a36Sopenharmony_ci#include <linux/err.h>
2062306a36Sopenharmony_ci#include <linux/i2c.h>
2162306a36Sopenharmony_ci#include <linux/i2c-smbus.h>
2262306a36Sopenharmony_ci#include <linux/interrupt.h>
2362306a36Sopenharmony_ci#include <linux/io.h>
2462306a36Sopenharmony_ci#include <linux/iopoll.h>
2562306a36Sopenharmony_ci#include <linux/mfd/syscon.h>
2662306a36Sopenharmony_ci#include <linux/module.h>
2762306a36Sopenharmony_ci#include <linux/of.h>
2862306a36Sopenharmony_ci#include <linux/of_address.h>
2962306a36Sopenharmony_ci#include <linux/of_platform.h>
3062306a36Sopenharmony_ci#include <linux/platform_device.h>
3162306a36Sopenharmony_ci#include <linux/pinctrl/consumer.h>
3262306a36Sopenharmony_ci#include <linux/pm_runtime.h>
3362306a36Sopenharmony_ci#include <linux/pm_wakeirq.h>
3462306a36Sopenharmony_ci#include <linux/regmap.h>
3562306a36Sopenharmony_ci#include <linux/reset.h>
3662306a36Sopenharmony_ci#include <linux/slab.h>
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci#include "i2c-stm32.h"
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci/* STM32F7 I2C registers */
4162306a36Sopenharmony_ci#define STM32F7_I2C_CR1				0x00
4262306a36Sopenharmony_ci#define STM32F7_I2C_CR2				0x04
4362306a36Sopenharmony_ci#define STM32F7_I2C_OAR1			0x08
4462306a36Sopenharmony_ci#define STM32F7_I2C_OAR2			0x0C
4562306a36Sopenharmony_ci#define STM32F7_I2C_PECR			0x20
4662306a36Sopenharmony_ci#define STM32F7_I2C_TIMINGR			0x10
4762306a36Sopenharmony_ci#define STM32F7_I2C_ISR				0x18
4862306a36Sopenharmony_ci#define STM32F7_I2C_ICR				0x1C
4962306a36Sopenharmony_ci#define STM32F7_I2C_RXDR			0x24
5062306a36Sopenharmony_ci#define STM32F7_I2C_TXDR			0x28
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci/* STM32F7 I2C control 1 */
5362306a36Sopenharmony_ci#define STM32F7_I2C_CR1_PECEN			BIT(23)
5462306a36Sopenharmony_ci#define STM32F7_I2C_CR1_ALERTEN			BIT(22)
5562306a36Sopenharmony_ci#define STM32F7_I2C_CR1_SMBHEN			BIT(20)
5662306a36Sopenharmony_ci#define STM32F7_I2C_CR1_WUPEN			BIT(18)
5762306a36Sopenharmony_ci#define STM32F7_I2C_CR1_SBC			BIT(16)
5862306a36Sopenharmony_ci#define STM32F7_I2C_CR1_RXDMAEN			BIT(15)
5962306a36Sopenharmony_ci#define STM32F7_I2C_CR1_TXDMAEN			BIT(14)
6062306a36Sopenharmony_ci#define STM32F7_I2C_CR1_ANFOFF			BIT(12)
6162306a36Sopenharmony_ci#define STM32F7_I2C_CR1_DNF_MASK		GENMASK(11, 8)
6262306a36Sopenharmony_ci#define STM32F7_I2C_CR1_DNF(n)			(((n) & 0xf) << 8)
6362306a36Sopenharmony_ci#define STM32F7_I2C_CR1_ERRIE			BIT(7)
6462306a36Sopenharmony_ci#define STM32F7_I2C_CR1_TCIE			BIT(6)
6562306a36Sopenharmony_ci#define STM32F7_I2C_CR1_STOPIE			BIT(5)
6662306a36Sopenharmony_ci#define STM32F7_I2C_CR1_NACKIE			BIT(4)
6762306a36Sopenharmony_ci#define STM32F7_I2C_CR1_ADDRIE			BIT(3)
6862306a36Sopenharmony_ci#define STM32F7_I2C_CR1_RXIE			BIT(2)
6962306a36Sopenharmony_ci#define STM32F7_I2C_CR1_TXIE			BIT(1)
7062306a36Sopenharmony_ci#define STM32F7_I2C_CR1_PE			BIT(0)
7162306a36Sopenharmony_ci#define STM32F7_I2C_ALL_IRQ_MASK		(STM32F7_I2C_CR1_ERRIE \
7262306a36Sopenharmony_ci						| STM32F7_I2C_CR1_TCIE \
7362306a36Sopenharmony_ci						| STM32F7_I2C_CR1_STOPIE \
7462306a36Sopenharmony_ci						| STM32F7_I2C_CR1_NACKIE \
7562306a36Sopenharmony_ci						| STM32F7_I2C_CR1_RXIE \
7662306a36Sopenharmony_ci						| STM32F7_I2C_CR1_TXIE)
7762306a36Sopenharmony_ci#define STM32F7_I2C_XFER_IRQ_MASK		(STM32F7_I2C_CR1_TCIE \
7862306a36Sopenharmony_ci						| STM32F7_I2C_CR1_STOPIE \
7962306a36Sopenharmony_ci						| STM32F7_I2C_CR1_NACKIE \
8062306a36Sopenharmony_ci						| STM32F7_I2C_CR1_RXIE \
8162306a36Sopenharmony_ci						| STM32F7_I2C_CR1_TXIE)
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci/* STM32F7 I2C control 2 */
8462306a36Sopenharmony_ci#define STM32F7_I2C_CR2_PECBYTE			BIT(26)
8562306a36Sopenharmony_ci#define STM32F7_I2C_CR2_RELOAD			BIT(24)
8662306a36Sopenharmony_ci#define STM32F7_I2C_CR2_NBYTES_MASK		GENMASK(23, 16)
8762306a36Sopenharmony_ci#define STM32F7_I2C_CR2_NBYTES(n)		(((n) & 0xff) << 16)
8862306a36Sopenharmony_ci#define STM32F7_I2C_CR2_NACK			BIT(15)
8962306a36Sopenharmony_ci#define STM32F7_I2C_CR2_STOP			BIT(14)
9062306a36Sopenharmony_ci#define STM32F7_I2C_CR2_START			BIT(13)
9162306a36Sopenharmony_ci#define STM32F7_I2C_CR2_HEAD10R			BIT(12)
9262306a36Sopenharmony_ci#define STM32F7_I2C_CR2_ADD10			BIT(11)
9362306a36Sopenharmony_ci#define STM32F7_I2C_CR2_RD_WRN			BIT(10)
9462306a36Sopenharmony_ci#define STM32F7_I2C_CR2_SADD10_MASK		GENMASK(9, 0)
9562306a36Sopenharmony_ci#define STM32F7_I2C_CR2_SADD10(n)		(((n) & \
9662306a36Sopenharmony_ci						STM32F7_I2C_CR2_SADD10_MASK))
9762306a36Sopenharmony_ci#define STM32F7_I2C_CR2_SADD7_MASK		GENMASK(7, 1)
9862306a36Sopenharmony_ci#define STM32F7_I2C_CR2_SADD7(n)		(((n) & 0x7f) << 1)
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci/* STM32F7 I2C Own Address 1 */
10162306a36Sopenharmony_ci#define STM32F7_I2C_OAR1_OA1EN			BIT(15)
10262306a36Sopenharmony_ci#define STM32F7_I2C_OAR1_OA1MODE		BIT(10)
10362306a36Sopenharmony_ci#define STM32F7_I2C_OAR1_OA1_10_MASK		GENMASK(9, 0)
10462306a36Sopenharmony_ci#define STM32F7_I2C_OAR1_OA1_10(n)		(((n) & \
10562306a36Sopenharmony_ci						STM32F7_I2C_OAR1_OA1_10_MASK))
10662306a36Sopenharmony_ci#define STM32F7_I2C_OAR1_OA1_7_MASK		GENMASK(7, 1)
10762306a36Sopenharmony_ci#define STM32F7_I2C_OAR1_OA1_7(n)		(((n) & 0x7f) << 1)
10862306a36Sopenharmony_ci#define STM32F7_I2C_OAR1_MASK			(STM32F7_I2C_OAR1_OA1_7_MASK \
10962306a36Sopenharmony_ci						| STM32F7_I2C_OAR1_OA1_10_MASK \
11062306a36Sopenharmony_ci						| STM32F7_I2C_OAR1_OA1EN \
11162306a36Sopenharmony_ci						| STM32F7_I2C_OAR1_OA1MODE)
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci/* STM32F7 I2C Own Address 2 */
11462306a36Sopenharmony_ci#define STM32F7_I2C_OAR2_OA2EN			BIT(15)
11562306a36Sopenharmony_ci#define STM32F7_I2C_OAR2_OA2MSK_MASK		GENMASK(10, 8)
11662306a36Sopenharmony_ci#define STM32F7_I2C_OAR2_OA2MSK(n)		(((n) & 0x7) << 8)
11762306a36Sopenharmony_ci#define STM32F7_I2C_OAR2_OA2_7_MASK		GENMASK(7, 1)
11862306a36Sopenharmony_ci#define STM32F7_I2C_OAR2_OA2_7(n)		(((n) & 0x7f) << 1)
11962306a36Sopenharmony_ci#define STM32F7_I2C_OAR2_MASK			(STM32F7_I2C_OAR2_OA2MSK_MASK \
12062306a36Sopenharmony_ci						| STM32F7_I2C_OAR2_OA2_7_MASK \
12162306a36Sopenharmony_ci						| STM32F7_I2C_OAR2_OA2EN)
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci/* STM32F7 I2C Interrupt Status */
12462306a36Sopenharmony_ci#define STM32F7_I2C_ISR_ADDCODE_MASK		GENMASK(23, 17)
12562306a36Sopenharmony_ci#define STM32F7_I2C_ISR_ADDCODE_GET(n) \
12662306a36Sopenharmony_ci				(((n) & STM32F7_I2C_ISR_ADDCODE_MASK) >> 17)
12762306a36Sopenharmony_ci#define STM32F7_I2C_ISR_DIR			BIT(16)
12862306a36Sopenharmony_ci#define STM32F7_I2C_ISR_BUSY			BIT(15)
12962306a36Sopenharmony_ci#define STM32F7_I2C_ISR_ALERT			BIT(13)
13062306a36Sopenharmony_ci#define STM32F7_I2C_ISR_PECERR			BIT(11)
13162306a36Sopenharmony_ci#define STM32F7_I2C_ISR_ARLO			BIT(9)
13262306a36Sopenharmony_ci#define STM32F7_I2C_ISR_BERR			BIT(8)
13362306a36Sopenharmony_ci#define STM32F7_I2C_ISR_TCR			BIT(7)
13462306a36Sopenharmony_ci#define STM32F7_I2C_ISR_TC			BIT(6)
13562306a36Sopenharmony_ci#define STM32F7_I2C_ISR_STOPF			BIT(5)
13662306a36Sopenharmony_ci#define STM32F7_I2C_ISR_NACKF			BIT(4)
13762306a36Sopenharmony_ci#define STM32F7_I2C_ISR_ADDR			BIT(3)
13862306a36Sopenharmony_ci#define STM32F7_I2C_ISR_RXNE			BIT(2)
13962306a36Sopenharmony_ci#define STM32F7_I2C_ISR_TXIS			BIT(1)
14062306a36Sopenharmony_ci#define STM32F7_I2C_ISR_TXE			BIT(0)
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci/* STM32F7 I2C Interrupt Clear */
14362306a36Sopenharmony_ci#define STM32F7_I2C_ICR_ALERTCF			BIT(13)
14462306a36Sopenharmony_ci#define STM32F7_I2C_ICR_PECCF			BIT(11)
14562306a36Sopenharmony_ci#define STM32F7_I2C_ICR_ARLOCF			BIT(9)
14662306a36Sopenharmony_ci#define STM32F7_I2C_ICR_BERRCF			BIT(8)
14762306a36Sopenharmony_ci#define STM32F7_I2C_ICR_STOPCF			BIT(5)
14862306a36Sopenharmony_ci#define STM32F7_I2C_ICR_NACKCF			BIT(4)
14962306a36Sopenharmony_ci#define STM32F7_I2C_ICR_ADDRCF			BIT(3)
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci/* STM32F7 I2C Timing */
15262306a36Sopenharmony_ci#define STM32F7_I2C_TIMINGR_PRESC(n)		(((n) & 0xf) << 28)
15362306a36Sopenharmony_ci#define STM32F7_I2C_TIMINGR_SCLDEL(n)		(((n) & 0xf) << 20)
15462306a36Sopenharmony_ci#define STM32F7_I2C_TIMINGR_SDADEL(n)		(((n) & 0xf) << 16)
15562306a36Sopenharmony_ci#define STM32F7_I2C_TIMINGR_SCLH(n)		(((n) & 0xff) << 8)
15662306a36Sopenharmony_ci#define STM32F7_I2C_TIMINGR_SCLL(n)		((n) & 0xff)
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci#define STM32F7_I2C_MAX_LEN			0xff
15962306a36Sopenharmony_ci#define STM32F7_I2C_DMA_LEN_MIN			0x16
16062306a36Sopenharmony_cienum {
16162306a36Sopenharmony_ci	STM32F7_SLAVE_HOSTNOTIFY,
16262306a36Sopenharmony_ci	STM32F7_SLAVE_7_10_BITS_ADDR,
16362306a36Sopenharmony_ci	STM32F7_SLAVE_7_BITS_ADDR,
16462306a36Sopenharmony_ci	STM32F7_I2C_MAX_SLAVE
16562306a36Sopenharmony_ci};
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci#define STM32F7_I2C_DNF_DEFAULT			0
16862306a36Sopenharmony_ci#define STM32F7_I2C_DNF_MAX			15
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci#define STM32F7_I2C_ANALOG_FILTER_DELAY_MIN	50	/* ns */
17162306a36Sopenharmony_ci#define STM32F7_I2C_ANALOG_FILTER_DELAY_MAX	260	/* ns */
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci#define STM32F7_I2C_RISE_TIME_DEFAULT		25	/* ns */
17462306a36Sopenharmony_ci#define STM32F7_I2C_FALL_TIME_DEFAULT		10	/* ns */
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci#define STM32F7_PRESC_MAX			BIT(4)
17762306a36Sopenharmony_ci#define STM32F7_SCLDEL_MAX			BIT(4)
17862306a36Sopenharmony_ci#define STM32F7_SDADEL_MAX			BIT(4)
17962306a36Sopenharmony_ci#define STM32F7_SCLH_MAX			BIT(8)
18062306a36Sopenharmony_ci#define STM32F7_SCLL_MAX			BIT(8)
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci#define STM32F7_AUTOSUSPEND_DELAY		(HZ / 100)
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci/**
18562306a36Sopenharmony_ci * struct stm32f7_i2c_regs - i2c f7 registers backup
18662306a36Sopenharmony_ci * @cr1: Control register 1
18762306a36Sopenharmony_ci * @cr2: Control register 2
18862306a36Sopenharmony_ci * @oar1: Own address 1 register
18962306a36Sopenharmony_ci * @oar2: Own address 2 register
19062306a36Sopenharmony_ci * @tmgr: Timing register
19162306a36Sopenharmony_ci */
19262306a36Sopenharmony_cistruct stm32f7_i2c_regs {
19362306a36Sopenharmony_ci	u32 cr1;
19462306a36Sopenharmony_ci	u32 cr2;
19562306a36Sopenharmony_ci	u32 oar1;
19662306a36Sopenharmony_ci	u32 oar2;
19762306a36Sopenharmony_ci	u32 tmgr;
19862306a36Sopenharmony_ci};
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci/**
20162306a36Sopenharmony_ci * struct stm32f7_i2c_spec - private i2c specification timing
20262306a36Sopenharmony_ci * @rate: I2C bus speed (Hz)
20362306a36Sopenharmony_ci * @fall_max: Max fall time of both SDA and SCL signals (ns)
20462306a36Sopenharmony_ci * @rise_max: Max rise time of both SDA and SCL signals (ns)
20562306a36Sopenharmony_ci * @hddat_min: Min data hold time (ns)
20662306a36Sopenharmony_ci * @vddat_max: Max data valid time (ns)
20762306a36Sopenharmony_ci * @sudat_min: Min data setup time (ns)
20862306a36Sopenharmony_ci * @l_min: Min low period of the SCL clock (ns)
20962306a36Sopenharmony_ci * @h_min: Min high period of the SCL clock (ns)
21062306a36Sopenharmony_ci */
21162306a36Sopenharmony_cistruct stm32f7_i2c_spec {
21262306a36Sopenharmony_ci	u32 rate;
21362306a36Sopenharmony_ci	u32 fall_max;
21462306a36Sopenharmony_ci	u32 rise_max;
21562306a36Sopenharmony_ci	u32 hddat_min;
21662306a36Sopenharmony_ci	u32 vddat_max;
21762306a36Sopenharmony_ci	u32 sudat_min;
21862306a36Sopenharmony_ci	u32 l_min;
21962306a36Sopenharmony_ci	u32 h_min;
22062306a36Sopenharmony_ci};
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci/**
22362306a36Sopenharmony_ci * struct stm32f7_i2c_setup - private I2C timing setup parameters
22462306a36Sopenharmony_ci * @speed_freq: I2C speed frequency  (Hz)
22562306a36Sopenharmony_ci * @clock_src: I2C clock source frequency (Hz)
22662306a36Sopenharmony_ci * @rise_time: Rise time (ns)
22762306a36Sopenharmony_ci * @fall_time: Fall time (ns)
22862306a36Sopenharmony_ci * @fmp_clr_offset: Fast Mode Plus clear register offset from set register
22962306a36Sopenharmony_ci */
23062306a36Sopenharmony_cistruct stm32f7_i2c_setup {
23162306a36Sopenharmony_ci	u32 speed_freq;
23262306a36Sopenharmony_ci	u32 clock_src;
23362306a36Sopenharmony_ci	u32 rise_time;
23462306a36Sopenharmony_ci	u32 fall_time;
23562306a36Sopenharmony_ci	u32 fmp_clr_offset;
23662306a36Sopenharmony_ci};
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci/**
23962306a36Sopenharmony_ci * struct stm32f7_i2c_timings - private I2C output parameters
24062306a36Sopenharmony_ci * @node: List entry
24162306a36Sopenharmony_ci * @presc: Prescaler value
24262306a36Sopenharmony_ci * @scldel: Data setup time
24362306a36Sopenharmony_ci * @sdadel: Data hold time
24462306a36Sopenharmony_ci * @sclh: SCL high period (master mode)
24562306a36Sopenharmony_ci * @scll: SCL low period (master mode)
24662306a36Sopenharmony_ci */
24762306a36Sopenharmony_cistruct stm32f7_i2c_timings {
24862306a36Sopenharmony_ci	struct list_head node;
24962306a36Sopenharmony_ci	u8 presc;
25062306a36Sopenharmony_ci	u8 scldel;
25162306a36Sopenharmony_ci	u8 sdadel;
25262306a36Sopenharmony_ci	u8 sclh;
25362306a36Sopenharmony_ci	u8 scll;
25462306a36Sopenharmony_ci};
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci/**
25762306a36Sopenharmony_ci * struct stm32f7_i2c_msg - client specific data
25862306a36Sopenharmony_ci * @addr: 8-bit or 10-bit slave addr, including r/w bit
25962306a36Sopenharmony_ci * @count: number of bytes to be transferred
26062306a36Sopenharmony_ci * @buf: data buffer
26162306a36Sopenharmony_ci * @result: result of the transfer
26262306a36Sopenharmony_ci * @stop: last I2C msg to be sent, i.e. STOP to be generated
26362306a36Sopenharmony_ci * @smbus: boolean to know if the I2C IP is used in SMBus mode
26462306a36Sopenharmony_ci * @size: type of SMBus protocol
26562306a36Sopenharmony_ci * @read_write: direction of SMBus protocol
26662306a36Sopenharmony_ci * SMBus block read and SMBus block write - block read process call protocols
26762306a36Sopenharmony_ci * @smbus_buf: buffer to be used for SMBus protocol transfer. It will
26862306a36Sopenharmony_ci * contain a maximum of 32 bytes of data + byte command + byte count + PEC
26962306a36Sopenharmony_ci * This buffer has to be 32-bit aligned to be compliant with memory address
27062306a36Sopenharmony_ci * register in DMA mode.
27162306a36Sopenharmony_ci */
27262306a36Sopenharmony_cistruct stm32f7_i2c_msg {
27362306a36Sopenharmony_ci	u16 addr;
27462306a36Sopenharmony_ci	u32 count;
27562306a36Sopenharmony_ci	u8 *buf;
27662306a36Sopenharmony_ci	int result;
27762306a36Sopenharmony_ci	bool stop;
27862306a36Sopenharmony_ci	bool smbus;
27962306a36Sopenharmony_ci	int size;
28062306a36Sopenharmony_ci	char read_write;
28162306a36Sopenharmony_ci	u8 smbus_buf[I2C_SMBUS_BLOCK_MAX + 3] __aligned(4);
28262306a36Sopenharmony_ci};
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci/**
28562306a36Sopenharmony_ci * struct stm32f7_i2c_alert - SMBus alert specific data
28662306a36Sopenharmony_ci * @setup: platform data for the smbus_alert i2c client
28762306a36Sopenharmony_ci * @ara: I2C slave device used to respond to the SMBus Alert with Alert
28862306a36Sopenharmony_ci * Response Address
28962306a36Sopenharmony_ci */
29062306a36Sopenharmony_cistruct stm32f7_i2c_alert {
29162306a36Sopenharmony_ci	struct i2c_smbus_alert_setup setup;
29262306a36Sopenharmony_ci	struct i2c_client *ara;
29362306a36Sopenharmony_ci};
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci/**
29662306a36Sopenharmony_ci * struct stm32f7_i2c_dev - private data of the controller
29762306a36Sopenharmony_ci * @adap: I2C adapter for this controller
29862306a36Sopenharmony_ci * @dev: device for this controller
29962306a36Sopenharmony_ci * @base: virtual memory area
30062306a36Sopenharmony_ci * @complete: completion of I2C message
30162306a36Sopenharmony_ci * @clk: hw i2c clock
30262306a36Sopenharmony_ci * @bus_rate: I2C clock frequency of the controller
30362306a36Sopenharmony_ci * @msg: Pointer to data to be written
30462306a36Sopenharmony_ci * @msg_num: number of I2C messages to be executed
30562306a36Sopenharmony_ci * @msg_id: message identifiant
30662306a36Sopenharmony_ci * @f7_msg: customized i2c msg for driver usage
30762306a36Sopenharmony_ci * @setup: I2C timing input setup
30862306a36Sopenharmony_ci * @timing: I2C computed timings
30962306a36Sopenharmony_ci * @slave: list of slave devices registered on the I2C bus
31062306a36Sopenharmony_ci * @slave_running: slave device currently used
31162306a36Sopenharmony_ci * @backup_regs: backup of i2c controller registers (for suspend/resume)
31262306a36Sopenharmony_ci * @slave_dir: transfer direction for the current slave device
31362306a36Sopenharmony_ci * @master_mode: boolean to know in which mode the I2C is running (master or
31462306a36Sopenharmony_ci * slave)
31562306a36Sopenharmony_ci * @dma: dma data
31662306a36Sopenharmony_ci * @use_dma: boolean to know if dma is used in the current transfer
31762306a36Sopenharmony_ci * @regmap: holds SYSCFG phandle for Fast Mode Plus bits
31862306a36Sopenharmony_ci * @fmp_sreg: register address for setting Fast Mode Plus bits
31962306a36Sopenharmony_ci * @fmp_creg: register address for clearing Fast Mode Plus bits
32062306a36Sopenharmony_ci * @fmp_mask: mask for Fast Mode Plus bits in set register
32162306a36Sopenharmony_ci * @wakeup_src: boolean to know if the device is a wakeup source
32262306a36Sopenharmony_ci * @smbus_mode: states that the controller is configured in SMBus mode
32362306a36Sopenharmony_ci * @host_notify_client: SMBus host-notify client
32462306a36Sopenharmony_ci * @analog_filter: boolean to indicate enabling of the analog filter
32562306a36Sopenharmony_ci * @dnf_dt: value of digital filter requested via dt
32662306a36Sopenharmony_ci * @dnf: value of digital filter to apply
32762306a36Sopenharmony_ci * @alert: SMBus alert specific data
32862306a36Sopenharmony_ci */
32962306a36Sopenharmony_cistruct stm32f7_i2c_dev {
33062306a36Sopenharmony_ci	struct i2c_adapter adap;
33162306a36Sopenharmony_ci	struct device *dev;
33262306a36Sopenharmony_ci	void __iomem *base;
33362306a36Sopenharmony_ci	struct completion complete;
33462306a36Sopenharmony_ci	struct clk *clk;
33562306a36Sopenharmony_ci	unsigned int bus_rate;
33662306a36Sopenharmony_ci	struct i2c_msg *msg;
33762306a36Sopenharmony_ci	unsigned int msg_num;
33862306a36Sopenharmony_ci	unsigned int msg_id;
33962306a36Sopenharmony_ci	struct stm32f7_i2c_msg f7_msg;
34062306a36Sopenharmony_ci	struct stm32f7_i2c_setup setup;
34162306a36Sopenharmony_ci	struct stm32f7_i2c_timings timing;
34262306a36Sopenharmony_ci	struct i2c_client *slave[STM32F7_I2C_MAX_SLAVE];
34362306a36Sopenharmony_ci	struct i2c_client *slave_running;
34462306a36Sopenharmony_ci	struct stm32f7_i2c_regs backup_regs;
34562306a36Sopenharmony_ci	u32 slave_dir;
34662306a36Sopenharmony_ci	bool master_mode;
34762306a36Sopenharmony_ci	struct stm32_i2c_dma *dma;
34862306a36Sopenharmony_ci	bool use_dma;
34962306a36Sopenharmony_ci	struct regmap *regmap;
35062306a36Sopenharmony_ci	u32 fmp_sreg;
35162306a36Sopenharmony_ci	u32 fmp_creg;
35262306a36Sopenharmony_ci	u32 fmp_mask;
35362306a36Sopenharmony_ci	bool wakeup_src;
35462306a36Sopenharmony_ci	bool smbus_mode;
35562306a36Sopenharmony_ci	struct i2c_client *host_notify_client;
35662306a36Sopenharmony_ci	bool analog_filter;
35762306a36Sopenharmony_ci	u32 dnf_dt;
35862306a36Sopenharmony_ci	u32 dnf;
35962306a36Sopenharmony_ci	struct stm32f7_i2c_alert *alert;
36062306a36Sopenharmony_ci};
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci/*
36362306a36Sopenharmony_ci * All these values are coming from I2C Specification, Version 6.0, 4th of
36462306a36Sopenharmony_ci * April 2014.
36562306a36Sopenharmony_ci *
36662306a36Sopenharmony_ci * Table10. Characteristics of the SDA and SCL bus lines for Standard, Fast,
36762306a36Sopenharmony_ci * and Fast-mode Plus I2C-bus devices
36862306a36Sopenharmony_ci */
36962306a36Sopenharmony_cistatic struct stm32f7_i2c_spec stm32f7_i2c_specs[] = {
37062306a36Sopenharmony_ci	{
37162306a36Sopenharmony_ci		.rate = I2C_MAX_STANDARD_MODE_FREQ,
37262306a36Sopenharmony_ci		.fall_max = 300,
37362306a36Sopenharmony_ci		.rise_max = 1000,
37462306a36Sopenharmony_ci		.hddat_min = 0,
37562306a36Sopenharmony_ci		.vddat_max = 3450,
37662306a36Sopenharmony_ci		.sudat_min = 250,
37762306a36Sopenharmony_ci		.l_min = 4700,
37862306a36Sopenharmony_ci		.h_min = 4000,
37962306a36Sopenharmony_ci	},
38062306a36Sopenharmony_ci	{
38162306a36Sopenharmony_ci		.rate = I2C_MAX_FAST_MODE_FREQ,
38262306a36Sopenharmony_ci		.fall_max = 300,
38362306a36Sopenharmony_ci		.rise_max = 300,
38462306a36Sopenharmony_ci		.hddat_min = 0,
38562306a36Sopenharmony_ci		.vddat_max = 900,
38662306a36Sopenharmony_ci		.sudat_min = 100,
38762306a36Sopenharmony_ci		.l_min = 1300,
38862306a36Sopenharmony_ci		.h_min = 600,
38962306a36Sopenharmony_ci	},
39062306a36Sopenharmony_ci	{
39162306a36Sopenharmony_ci		.rate = I2C_MAX_FAST_MODE_PLUS_FREQ,
39262306a36Sopenharmony_ci		.fall_max = 100,
39362306a36Sopenharmony_ci		.rise_max = 120,
39462306a36Sopenharmony_ci		.hddat_min = 0,
39562306a36Sopenharmony_ci		.vddat_max = 450,
39662306a36Sopenharmony_ci		.sudat_min = 50,
39762306a36Sopenharmony_ci		.l_min = 500,
39862306a36Sopenharmony_ci		.h_min = 260,
39962306a36Sopenharmony_ci	},
40062306a36Sopenharmony_ci};
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_cistatic const struct stm32f7_i2c_setup stm32f7_setup = {
40362306a36Sopenharmony_ci	.rise_time = STM32F7_I2C_RISE_TIME_DEFAULT,
40462306a36Sopenharmony_ci	.fall_time = STM32F7_I2C_FALL_TIME_DEFAULT,
40562306a36Sopenharmony_ci};
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_cistatic const struct stm32f7_i2c_setup stm32mp15_setup = {
40862306a36Sopenharmony_ci	.rise_time = STM32F7_I2C_RISE_TIME_DEFAULT,
40962306a36Sopenharmony_ci	.fall_time = STM32F7_I2C_FALL_TIME_DEFAULT,
41062306a36Sopenharmony_ci	.fmp_clr_offset = 0x40,
41162306a36Sopenharmony_ci};
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_cistatic const struct stm32f7_i2c_setup stm32mp13_setup = {
41462306a36Sopenharmony_ci	.rise_time = STM32F7_I2C_RISE_TIME_DEFAULT,
41562306a36Sopenharmony_ci	.fall_time = STM32F7_I2C_FALL_TIME_DEFAULT,
41662306a36Sopenharmony_ci	.fmp_clr_offset = 0x4,
41762306a36Sopenharmony_ci};
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_cistatic inline void stm32f7_i2c_set_bits(void __iomem *reg, u32 mask)
42062306a36Sopenharmony_ci{
42162306a36Sopenharmony_ci	writel_relaxed(readl_relaxed(reg) | mask, reg);
42262306a36Sopenharmony_ci}
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_cistatic inline void stm32f7_i2c_clr_bits(void __iomem *reg, u32 mask)
42562306a36Sopenharmony_ci{
42662306a36Sopenharmony_ci	writel_relaxed(readl_relaxed(reg) & ~mask, reg);
42762306a36Sopenharmony_ci}
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_cistatic void stm32f7_i2c_disable_irq(struct stm32f7_i2c_dev *i2c_dev, u32 mask)
43062306a36Sopenharmony_ci{
43162306a36Sopenharmony_ci	stm32f7_i2c_clr_bits(i2c_dev->base + STM32F7_I2C_CR1, mask);
43262306a36Sopenharmony_ci}
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_cistatic struct stm32f7_i2c_spec *stm32f7_get_specs(u32 rate)
43562306a36Sopenharmony_ci{
43662306a36Sopenharmony_ci	int i;
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(stm32f7_i2c_specs); i++)
43962306a36Sopenharmony_ci		if (rate <= stm32f7_i2c_specs[i].rate)
44062306a36Sopenharmony_ci			return &stm32f7_i2c_specs[i];
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_ci	return ERR_PTR(-EINVAL);
44362306a36Sopenharmony_ci}
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci#define	RATE_MIN(rate)	((rate) * 8 / 10)
44662306a36Sopenharmony_cistatic int stm32f7_i2c_compute_timing(struct stm32f7_i2c_dev *i2c_dev,
44762306a36Sopenharmony_ci				      struct stm32f7_i2c_setup *setup,
44862306a36Sopenharmony_ci				      struct stm32f7_i2c_timings *output)
44962306a36Sopenharmony_ci{
45062306a36Sopenharmony_ci	struct stm32f7_i2c_spec *specs;
45162306a36Sopenharmony_ci	u32 p_prev = STM32F7_PRESC_MAX;
45262306a36Sopenharmony_ci	u32 i2cclk = DIV_ROUND_CLOSEST(NSEC_PER_SEC,
45362306a36Sopenharmony_ci				       setup->clock_src);
45462306a36Sopenharmony_ci	u32 i2cbus = DIV_ROUND_CLOSEST(NSEC_PER_SEC,
45562306a36Sopenharmony_ci				       setup->speed_freq);
45662306a36Sopenharmony_ci	u32 clk_error_prev = i2cbus;
45762306a36Sopenharmony_ci	u32 tsync;
45862306a36Sopenharmony_ci	u32 af_delay_min, af_delay_max;
45962306a36Sopenharmony_ci	u32 dnf_delay;
46062306a36Sopenharmony_ci	u32 clk_min, clk_max;
46162306a36Sopenharmony_ci	int sdadel_min, sdadel_max;
46262306a36Sopenharmony_ci	int scldel_min;
46362306a36Sopenharmony_ci	struct stm32f7_i2c_timings *v, *_v, *s;
46462306a36Sopenharmony_ci	struct list_head solutions;
46562306a36Sopenharmony_ci	u16 p, l, a, h;
46662306a36Sopenharmony_ci	int ret = 0;
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_ci	specs = stm32f7_get_specs(setup->speed_freq);
46962306a36Sopenharmony_ci	if (specs == ERR_PTR(-EINVAL)) {
47062306a36Sopenharmony_ci		dev_err(i2c_dev->dev, "speed out of bound {%d}\n",
47162306a36Sopenharmony_ci			setup->speed_freq);
47262306a36Sopenharmony_ci		return -EINVAL;
47362306a36Sopenharmony_ci	}
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci	if ((setup->rise_time > specs->rise_max) ||
47662306a36Sopenharmony_ci	    (setup->fall_time > specs->fall_max)) {
47762306a36Sopenharmony_ci		dev_err(i2c_dev->dev,
47862306a36Sopenharmony_ci			"timings out of bound Rise{%d>%d}/Fall{%d>%d}\n",
47962306a36Sopenharmony_ci			setup->rise_time, specs->rise_max,
48062306a36Sopenharmony_ci			setup->fall_time, specs->fall_max);
48162306a36Sopenharmony_ci		return -EINVAL;
48262306a36Sopenharmony_ci	}
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_ci	i2c_dev->dnf = DIV_ROUND_CLOSEST(i2c_dev->dnf_dt, i2cclk);
48562306a36Sopenharmony_ci	if (i2c_dev->dnf > STM32F7_I2C_DNF_MAX) {
48662306a36Sopenharmony_ci		dev_err(i2c_dev->dev,
48762306a36Sopenharmony_ci			"DNF out of bound %d/%d\n",
48862306a36Sopenharmony_ci			i2c_dev->dnf * i2cclk, STM32F7_I2C_DNF_MAX * i2cclk);
48962306a36Sopenharmony_ci		return -EINVAL;
49062306a36Sopenharmony_ci	}
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_ci	/*  Analog and Digital Filters */
49362306a36Sopenharmony_ci	af_delay_min =
49462306a36Sopenharmony_ci		(i2c_dev->analog_filter ?
49562306a36Sopenharmony_ci		 STM32F7_I2C_ANALOG_FILTER_DELAY_MIN : 0);
49662306a36Sopenharmony_ci	af_delay_max =
49762306a36Sopenharmony_ci		(i2c_dev->analog_filter ?
49862306a36Sopenharmony_ci		 STM32F7_I2C_ANALOG_FILTER_DELAY_MAX : 0);
49962306a36Sopenharmony_ci	dnf_delay = i2c_dev->dnf * i2cclk;
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_ci	sdadel_min = specs->hddat_min + setup->fall_time -
50262306a36Sopenharmony_ci		af_delay_min - (i2c_dev->dnf + 3) * i2cclk;
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_ci	sdadel_max = specs->vddat_max - setup->rise_time -
50562306a36Sopenharmony_ci		af_delay_max - (i2c_dev->dnf + 4) * i2cclk;
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci	scldel_min = setup->rise_time + specs->sudat_min;
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci	if (sdadel_min < 0)
51062306a36Sopenharmony_ci		sdadel_min = 0;
51162306a36Sopenharmony_ci	if (sdadel_max < 0)
51262306a36Sopenharmony_ci		sdadel_max = 0;
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci	dev_dbg(i2c_dev->dev, "SDADEL(min/max): %i/%i, SCLDEL(Min): %i\n",
51562306a36Sopenharmony_ci		sdadel_min, sdadel_max, scldel_min);
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_ci	INIT_LIST_HEAD(&solutions);
51862306a36Sopenharmony_ci	/* Compute possible values for PRESC, SCLDEL and SDADEL */
51962306a36Sopenharmony_ci	for (p = 0; p < STM32F7_PRESC_MAX; p++) {
52062306a36Sopenharmony_ci		for (l = 0; l < STM32F7_SCLDEL_MAX; l++) {
52162306a36Sopenharmony_ci			u32 scldel = (l + 1) * (p + 1) * i2cclk;
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_ci			if (scldel < scldel_min)
52462306a36Sopenharmony_ci				continue;
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_ci			for (a = 0; a < STM32F7_SDADEL_MAX; a++) {
52762306a36Sopenharmony_ci				u32 sdadel = (a * (p + 1) + 1) * i2cclk;
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ci				if (((sdadel >= sdadel_min) &&
53062306a36Sopenharmony_ci				     (sdadel <= sdadel_max)) &&
53162306a36Sopenharmony_ci				    (p != p_prev)) {
53262306a36Sopenharmony_ci					v = kmalloc(sizeof(*v), GFP_KERNEL);
53362306a36Sopenharmony_ci					if (!v) {
53462306a36Sopenharmony_ci						ret = -ENOMEM;
53562306a36Sopenharmony_ci						goto exit;
53662306a36Sopenharmony_ci					}
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_ci					v->presc = p;
53962306a36Sopenharmony_ci					v->scldel = l;
54062306a36Sopenharmony_ci					v->sdadel = a;
54162306a36Sopenharmony_ci					p_prev = p;
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ci					list_add_tail(&v->node,
54462306a36Sopenharmony_ci						      &solutions);
54562306a36Sopenharmony_ci					break;
54662306a36Sopenharmony_ci				}
54762306a36Sopenharmony_ci			}
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_ci			if (p_prev == p)
55062306a36Sopenharmony_ci				break;
55162306a36Sopenharmony_ci		}
55262306a36Sopenharmony_ci	}
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_ci	if (list_empty(&solutions)) {
55562306a36Sopenharmony_ci		dev_err(i2c_dev->dev, "no Prescaler solution\n");
55662306a36Sopenharmony_ci		ret = -EPERM;
55762306a36Sopenharmony_ci		goto exit;
55862306a36Sopenharmony_ci	}
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_ci	tsync = af_delay_min + dnf_delay + (2 * i2cclk);
56162306a36Sopenharmony_ci	s = NULL;
56262306a36Sopenharmony_ci	clk_max = NSEC_PER_SEC / RATE_MIN(setup->speed_freq);
56362306a36Sopenharmony_ci	clk_min = NSEC_PER_SEC / setup->speed_freq;
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_ci	/*
56662306a36Sopenharmony_ci	 * Among Prescaler possibilities discovered above figures out SCL Low
56762306a36Sopenharmony_ci	 * and High Period. Provided:
56862306a36Sopenharmony_ci	 * - SCL Low Period has to be higher than SCL Clock Low Period
56962306a36Sopenharmony_ci	 *   defined by I2C Specification. I2C Clock has to be lower than
57062306a36Sopenharmony_ci	 *   (SCL Low Period - Analog/Digital filters) / 4.
57162306a36Sopenharmony_ci	 * - SCL High Period has to be lower than SCL Clock High Period
57262306a36Sopenharmony_ci	 *   defined by I2C Specification
57362306a36Sopenharmony_ci	 * - I2C Clock has to be lower than SCL High Period
57462306a36Sopenharmony_ci	 */
57562306a36Sopenharmony_ci	list_for_each_entry(v, &solutions, node) {
57662306a36Sopenharmony_ci		u32 prescaler = (v->presc + 1) * i2cclk;
57762306a36Sopenharmony_ci
57862306a36Sopenharmony_ci		for (l = 0; l < STM32F7_SCLL_MAX; l++) {
57962306a36Sopenharmony_ci			u32 tscl_l = (l + 1) * prescaler + tsync;
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_ci			if ((tscl_l < specs->l_min) ||
58262306a36Sopenharmony_ci			    (i2cclk >=
58362306a36Sopenharmony_ci			     ((tscl_l - af_delay_min - dnf_delay) / 4))) {
58462306a36Sopenharmony_ci				continue;
58562306a36Sopenharmony_ci			}
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_ci			for (h = 0; h < STM32F7_SCLH_MAX; h++) {
58862306a36Sopenharmony_ci				u32 tscl_h = (h + 1) * prescaler + tsync;
58962306a36Sopenharmony_ci				u32 tscl = tscl_l + tscl_h +
59062306a36Sopenharmony_ci					setup->rise_time + setup->fall_time;
59162306a36Sopenharmony_ci
59262306a36Sopenharmony_ci				if ((tscl >= clk_min) && (tscl <= clk_max) &&
59362306a36Sopenharmony_ci				    (tscl_h >= specs->h_min) &&
59462306a36Sopenharmony_ci				    (i2cclk < tscl_h)) {
59562306a36Sopenharmony_ci					int clk_error = tscl - i2cbus;
59662306a36Sopenharmony_ci
59762306a36Sopenharmony_ci					if (clk_error < 0)
59862306a36Sopenharmony_ci						clk_error = -clk_error;
59962306a36Sopenharmony_ci
60062306a36Sopenharmony_ci					if (clk_error < clk_error_prev) {
60162306a36Sopenharmony_ci						clk_error_prev = clk_error;
60262306a36Sopenharmony_ci						v->scll = l;
60362306a36Sopenharmony_ci						v->sclh = h;
60462306a36Sopenharmony_ci						s = v;
60562306a36Sopenharmony_ci					}
60662306a36Sopenharmony_ci				}
60762306a36Sopenharmony_ci			}
60862306a36Sopenharmony_ci		}
60962306a36Sopenharmony_ci	}
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_ci	if (!s) {
61262306a36Sopenharmony_ci		dev_err(i2c_dev->dev, "no solution at all\n");
61362306a36Sopenharmony_ci		ret = -EPERM;
61462306a36Sopenharmony_ci		goto exit;
61562306a36Sopenharmony_ci	}
61662306a36Sopenharmony_ci
61762306a36Sopenharmony_ci	output->presc = s->presc;
61862306a36Sopenharmony_ci	output->scldel = s->scldel;
61962306a36Sopenharmony_ci	output->sdadel = s->sdadel;
62062306a36Sopenharmony_ci	output->scll = s->scll;
62162306a36Sopenharmony_ci	output->sclh = s->sclh;
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_ci	dev_dbg(i2c_dev->dev,
62462306a36Sopenharmony_ci		"Presc: %i, scldel: %i, sdadel: %i, scll: %i, sclh: %i\n",
62562306a36Sopenharmony_ci		output->presc,
62662306a36Sopenharmony_ci		output->scldel, output->sdadel,
62762306a36Sopenharmony_ci		output->scll, output->sclh);
62862306a36Sopenharmony_ci
62962306a36Sopenharmony_ciexit:
63062306a36Sopenharmony_ci	/* Release list and memory */
63162306a36Sopenharmony_ci	list_for_each_entry_safe(v, _v, &solutions, node) {
63262306a36Sopenharmony_ci		list_del(&v->node);
63362306a36Sopenharmony_ci		kfree(v);
63462306a36Sopenharmony_ci	}
63562306a36Sopenharmony_ci
63662306a36Sopenharmony_ci	return ret;
63762306a36Sopenharmony_ci}
63862306a36Sopenharmony_ci
63962306a36Sopenharmony_cistatic u32 stm32f7_get_lower_rate(u32 rate)
64062306a36Sopenharmony_ci{
64162306a36Sopenharmony_ci	int i = ARRAY_SIZE(stm32f7_i2c_specs);
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_ci	while (--i)
64462306a36Sopenharmony_ci		if (stm32f7_i2c_specs[i].rate < rate)
64562306a36Sopenharmony_ci			break;
64662306a36Sopenharmony_ci
64762306a36Sopenharmony_ci	return stm32f7_i2c_specs[i].rate;
64862306a36Sopenharmony_ci}
64962306a36Sopenharmony_ci
65062306a36Sopenharmony_cistatic int stm32f7_i2c_setup_timing(struct stm32f7_i2c_dev *i2c_dev,
65162306a36Sopenharmony_ci				    struct stm32f7_i2c_setup *setup)
65262306a36Sopenharmony_ci{
65362306a36Sopenharmony_ci	struct i2c_timings timings, *t = &timings;
65462306a36Sopenharmony_ci	int ret = 0;
65562306a36Sopenharmony_ci
65662306a36Sopenharmony_ci	t->bus_freq_hz = I2C_MAX_STANDARD_MODE_FREQ;
65762306a36Sopenharmony_ci	t->scl_rise_ns = i2c_dev->setup.rise_time;
65862306a36Sopenharmony_ci	t->scl_fall_ns = i2c_dev->setup.fall_time;
65962306a36Sopenharmony_ci
66062306a36Sopenharmony_ci	i2c_parse_fw_timings(i2c_dev->dev, t, false);
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_ci	if (t->bus_freq_hz > I2C_MAX_FAST_MODE_PLUS_FREQ) {
66362306a36Sopenharmony_ci		dev_err(i2c_dev->dev, "Invalid bus speed (%i>%i)\n",
66462306a36Sopenharmony_ci			t->bus_freq_hz, I2C_MAX_FAST_MODE_PLUS_FREQ);
66562306a36Sopenharmony_ci		return -EINVAL;
66662306a36Sopenharmony_ci	}
66762306a36Sopenharmony_ci
66862306a36Sopenharmony_ci	setup->speed_freq = t->bus_freq_hz;
66962306a36Sopenharmony_ci	i2c_dev->setup.rise_time = t->scl_rise_ns;
67062306a36Sopenharmony_ci	i2c_dev->setup.fall_time = t->scl_fall_ns;
67162306a36Sopenharmony_ci	i2c_dev->dnf_dt = t->digital_filter_width_ns;
67262306a36Sopenharmony_ci	setup->clock_src = clk_get_rate(i2c_dev->clk);
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_ci	if (!setup->clock_src) {
67562306a36Sopenharmony_ci		dev_err(i2c_dev->dev, "clock rate is 0\n");
67662306a36Sopenharmony_ci		return -EINVAL;
67762306a36Sopenharmony_ci	}
67862306a36Sopenharmony_ci
67962306a36Sopenharmony_ci	if (!of_property_read_bool(i2c_dev->dev->of_node, "i2c-digital-filter"))
68062306a36Sopenharmony_ci		i2c_dev->dnf_dt = STM32F7_I2C_DNF_DEFAULT;
68162306a36Sopenharmony_ci
68262306a36Sopenharmony_ci	do {
68362306a36Sopenharmony_ci		ret = stm32f7_i2c_compute_timing(i2c_dev, setup,
68462306a36Sopenharmony_ci						 &i2c_dev->timing);
68562306a36Sopenharmony_ci		if (ret) {
68662306a36Sopenharmony_ci			dev_err(i2c_dev->dev,
68762306a36Sopenharmony_ci				"failed to compute I2C timings.\n");
68862306a36Sopenharmony_ci			if (setup->speed_freq <= I2C_MAX_STANDARD_MODE_FREQ)
68962306a36Sopenharmony_ci				break;
69062306a36Sopenharmony_ci			setup->speed_freq =
69162306a36Sopenharmony_ci				stm32f7_get_lower_rate(setup->speed_freq);
69262306a36Sopenharmony_ci			dev_warn(i2c_dev->dev,
69362306a36Sopenharmony_ci				 "downgrade I2C Speed Freq to (%i)\n",
69462306a36Sopenharmony_ci				 setup->speed_freq);
69562306a36Sopenharmony_ci		}
69662306a36Sopenharmony_ci	} while (ret);
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_ci	if (ret) {
69962306a36Sopenharmony_ci		dev_err(i2c_dev->dev, "Impossible to compute I2C timings.\n");
70062306a36Sopenharmony_ci		return ret;
70162306a36Sopenharmony_ci	}
70262306a36Sopenharmony_ci
70362306a36Sopenharmony_ci	i2c_dev->analog_filter = of_property_read_bool(i2c_dev->dev->of_node,
70462306a36Sopenharmony_ci						       "i2c-analog-filter");
70562306a36Sopenharmony_ci
70662306a36Sopenharmony_ci	dev_dbg(i2c_dev->dev, "I2C Speed(%i), Clk Source(%i)\n",
70762306a36Sopenharmony_ci		setup->speed_freq, setup->clock_src);
70862306a36Sopenharmony_ci	dev_dbg(i2c_dev->dev, "I2C Rise(%i) and Fall(%i) Time\n",
70962306a36Sopenharmony_ci		setup->rise_time, setup->fall_time);
71062306a36Sopenharmony_ci	dev_dbg(i2c_dev->dev, "I2C Analog Filter(%s), DNF(%i)\n",
71162306a36Sopenharmony_ci		(i2c_dev->analog_filter ? "On" : "Off"), i2c_dev->dnf);
71262306a36Sopenharmony_ci
71362306a36Sopenharmony_ci	i2c_dev->bus_rate = setup->speed_freq;
71462306a36Sopenharmony_ci
71562306a36Sopenharmony_ci	return 0;
71662306a36Sopenharmony_ci}
71762306a36Sopenharmony_ci
71862306a36Sopenharmony_cistatic void stm32f7_i2c_disable_dma_req(struct stm32f7_i2c_dev *i2c_dev)
71962306a36Sopenharmony_ci{
72062306a36Sopenharmony_ci	void __iomem *base = i2c_dev->base;
72162306a36Sopenharmony_ci	u32 mask = STM32F7_I2C_CR1_RXDMAEN | STM32F7_I2C_CR1_TXDMAEN;
72262306a36Sopenharmony_ci
72362306a36Sopenharmony_ci	stm32f7_i2c_clr_bits(base + STM32F7_I2C_CR1, mask);
72462306a36Sopenharmony_ci}
72562306a36Sopenharmony_ci
72662306a36Sopenharmony_cistatic void stm32f7_i2c_dma_callback(void *arg)
72762306a36Sopenharmony_ci{
72862306a36Sopenharmony_ci	struct stm32f7_i2c_dev *i2c_dev = (struct stm32f7_i2c_dev *)arg;
72962306a36Sopenharmony_ci	struct stm32_i2c_dma *dma = i2c_dev->dma;
73062306a36Sopenharmony_ci	struct device *dev = dma->chan_using->device->dev;
73162306a36Sopenharmony_ci
73262306a36Sopenharmony_ci	stm32f7_i2c_disable_dma_req(i2c_dev);
73362306a36Sopenharmony_ci	dma_unmap_single(dev, dma->dma_buf, dma->dma_len, dma->dma_data_dir);
73462306a36Sopenharmony_ci	complete(&dma->dma_complete);
73562306a36Sopenharmony_ci}
73662306a36Sopenharmony_ci
73762306a36Sopenharmony_cistatic void stm32f7_i2c_hw_config(struct stm32f7_i2c_dev *i2c_dev)
73862306a36Sopenharmony_ci{
73962306a36Sopenharmony_ci	struct stm32f7_i2c_timings *t = &i2c_dev->timing;
74062306a36Sopenharmony_ci	u32 timing = 0;
74162306a36Sopenharmony_ci
74262306a36Sopenharmony_ci	/* Timing settings */
74362306a36Sopenharmony_ci	timing |= STM32F7_I2C_TIMINGR_PRESC(t->presc);
74462306a36Sopenharmony_ci	timing |= STM32F7_I2C_TIMINGR_SCLDEL(t->scldel);
74562306a36Sopenharmony_ci	timing |= STM32F7_I2C_TIMINGR_SDADEL(t->sdadel);
74662306a36Sopenharmony_ci	timing |= STM32F7_I2C_TIMINGR_SCLH(t->sclh);
74762306a36Sopenharmony_ci	timing |= STM32F7_I2C_TIMINGR_SCLL(t->scll);
74862306a36Sopenharmony_ci	writel_relaxed(timing, i2c_dev->base + STM32F7_I2C_TIMINGR);
74962306a36Sopenharmony_ci
75062306a36Sopenharmony_ci	/* Configure the Analog Filter */
75162306a36Sopenharmony_ci	if (i2c_dev->analog_filter)
75262306a36Sopenharmony_ci		stm32f7_i2c_clr_bits(i2c_dev->base + STM32F7_I2C_CR1,
75362306a36Sopenharmony_ci				     STM32F7_I2C_CR1_ANFOFF);
75462306a36Sopenharmony_ci	else
75562306a36Sopenharmony_ci		stm32f7_i2c_set_bits(i2c_dev->base + STM32F7_I2C_CR1,
75662306a36Sopenharmony_ci				     STM32F7_I2C_CR1_ANFOFF);
75762306a36Sopenharmony_ci
75862306a36Sopenharmony_ci	/* Program the Digital Filter */
75962306a36Sopenharmony_ci	stm32f7_i2c_clr_bits(i2c_dev->base + STM32F7_I2C_CR1,
76062306a36Sopenharmony_ci			     STM32F7_I2C_CR1_DNF_MASK);
76162306a36Sopenharmony_ci	stm32f7_i2c_set_bits(i2c_dev->base + STM32F7_I2C_CR1,
76262306a36Sopenharmony_ci			     STM32F7_I2C_CR1_DNF(i2c_dev->dnf));
76362306a36Sopenharmony_ci
76462306a36Sopenharmony_ci	stm32f7_i2c_set_bits(i2c_dev->base + STM32F7_I2C_CR1,
76562306a36Sopenharmony_ci			     STM32F7_I2C_CR1_PE);
76662306a36Sopenharmony_ci}
76762306a36Sopenharmony_ci
76862306a36Sopenharmony_cistatic void stm32f7_i2c_write_tx_data(struct stm32f7_i2c_dev *i2c_dev)
76962306a36Sopenharmony_ci{
77062306a36Sopenharmony_ci	struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg;
77162306a36Sopenharmony_ci	void __iomem *base = i2c_dev->base;
77262306a36Sopenharmony_ci
77362306a36Sopenharmony_ci	if (f7_msg->count) {
77462306a36Sopenharmony_ci		writeb_relaxed(*f7_msg->buf++, base + STM32F7_I2C_TXDR);
77562306a36Sopenharmony_ci		f7_msg->count--;
77662306a36Sopenharmony_ci	}
77762306a36Sopenharmony_ci}
77862306a36Sopenharmony_ci
77962306a36Sopenharmony_cistatic void stm32f7_i2c_read_rx_data(struct stm32f7_i2c_dev *i2c_dev)
78062306a36Sopenharmony_ci{
78162306a36Sopenharmony_ci	struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg;
78262306a36Sopenharmony_ci	void __iomem *base = i2c_dev->base;
78362306a36Sopenharmony_ci
78462306a36Sopenharmony_ci	if (f7_msg->count) {
78562306a36Sopenharmony_ci		*f7_msg->buf++ = readb_relaxed(base + STM32F7_I2C_RXDR);
78662306a36Sopenharmony_ci		f7_msg->count--;
78762306a36Sopenharmony_ci	} else {
78862306a36Sopenharmony_ci		/* Flush RX buffer has no data is expected */
78962306a36Sopenharmony_ci		readb_relaxed(base + STM32F7_I2C_RXDR);
79062306a36Sopenharmony_ci	}
79162306a36Sopenharmony_ci}
79262306a36Sopenharmony_ci
79362306a36Sopenharmony_cistatic void stm32f7_i2c_reload(struct stm32f7_i2c_dev *i2c_dev)
79462306a36Sopenharmony_ci{
79562306a36Sopenharmony_ci	struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg;
79662306a36Sopenharmony_ci	u32 cr2;
79762306a36Sopenharmony_ci
79862306a36Sopenharmony_ci	if (i2c_dev->use_dma)
79962306a36Sopenharmony_ci		f7_msg->count -= STM32F7_I2C_MAX_LEN;
80062306a36Sopenharmony_ci
80162306a36Sopenharmony_ci	cr2 = readl_relaxed(i2c_dev->base + STM32F7_I2C_CR2);
80262306a36Sopenharmony_ci
80362306a36Sopenharmony_ci	cr2 &= ~STM32F7_I2C_CR2_NBYTES_MASK;
80462306a36Sopenharmony_ci	if (f7_msg->count > STM32F7_I2C_MAX_LEN) {
80562306a36Sopenharmony_ci		cr2 |= STM32F7_I2C_CR2_NBYTES(STM32F7_I2C_MAX_LEN);
80662306a36Sopenharmony_ci	} else {
80762306a36Sopenharmony_ci		cr2 &= ~STM32F7_I2C_CR2_RELOAD;
80862306a36Sopenharmony_ci		cr2 |= STM32F7_I2C_CR2_NBYTES(f7_msg->count);
80962306a36Sopenharmony_ci	}
81062306a36Sopenharmony_ci
81162306a36Sopenharmony_ci	writel_relaxed(cr2, i2c_dev->base + STM32F7_I2C_CR2);
81262306a36Sopenharmony_ci}
81362306a36Sopenharmony_ci
81462306a36Sopenharmony_cistatic void stm32f7_i2c_smbus_reload(struct stm32f7_i2c_dev *i2c_dev)
81562306a36Sopenharmony_ci{
81662306a36Sopenharmony_ci	struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg;
81762306a36Sopenharmony_ci	u32 cr2;
81862306a36Sopenharmony_ci	u8 *val;
81962306a36Sopenharmony_ci
82062306a36Sopenharmony_ci	/*
82162306a36Sopenharmony_ci	 * For I2C_SMBUS_BLOCK_DATA && I2C_SMBUS_BLOCK_PROC_CALL, the first
82262306a36Sopenharmony_ci	 * data received inform us how many data will follow.
82362306a36Sopenharmony_ci	 */
82462306a36Sopenharmony_ci	stm32f7_i2c_read_rx_data(i2c_dev);
82562306a36Sopenharmony_ci
82662306a36Sopenharmony_ci	/*
82762306a36Sopenharmony_ci	 * Update NBYTES with the value read to continue the transfer
82862306a36Sopenharmony_ci	 */
82962306a36Sopenharmony_ci	val = f7_msg->buf - sizeof(u8);
83062306a36Sopenharmony_ci	f7_msg->count = *val;
83162306a36Sopenharmony_ci	cr2 = readl_relaxed(i2c_dev->base + STM32F7_I2C_CR2);
83262306a36Sopenharmony_ci	cr2 &= ~(STM32F7_I2C_CR2_NBYTES_MASK | STM32F7_I2C_CR2_RELOAD);
83362306a36Sopenharmony_ci	cr2 |= STM32F7_I2C_CR2_NBYTES(f7_msg->count);
83462306a36Sopenharmony_ci	writel_relaxed(cr2, i2c_dev->base + STM32F7_I2C_CR2);
83562306a36Sopenharmony_ci}
83662306a36Sopenharmony_ci
83762306a36Sopenharmony_cistatic void stm32f7_i2c_release_bus(struct i2c_adapter *i2c_adap)
83862306a36Sopenharmony_ci{
83962306a36Sopenharmony_ci	struct stm32f7_i2c_dev *i2c_dev = i2c_get_adapdata(i2c_adap);
84062306a36Sopenharmony_ci
84162306a36Sopenharmony_ci	stm32f7_i2c_clr_bits(i2c_dev->base + STM32F7_I2C_CR1,
84262306a36Sopenharmony_ci			     STM32F7_I2C_CR1_PE);
84362306a36Sopenharmony_ci
84462306a36Sopenharmony_ci	stm32f7_i2c_hw_config(i2c_dev);
84562306a36Sopenharmony_ci}
84662306a36Sopenharmony_ci
84762306a36Sopenharmony_cistatic int stm32f7_i2c_wait_free_bus(struct stm32f7_i2c_dev *i2c_dev)
84862306a36Sopenharmony_ci{
84962306a36Sopenharmony_ci	u32 status;
85062306a36Sopenharmony_ci	int ret;
85162306a36Sopenharmony_ci
85262306a36Sopenharmony_ci	ret = readl_relaxed_poll_timeout(i2c_dev->base + STM32F7_I2C_ISR,
85362306a36Sopenharmony_ci					 status,
85462306a36Sopenharmony_ci					 !(status & STM32F7_I2C_ISR_BUSY),
85562306a36Sopenharmony_ci					 10, 1000);
85662306a36Sopenharmony_ci	if (!ret)
85762306a36Sopenharmony_ci		return 0;
85862306a36Sopenharmony_ci
85962306a36Sopenharmony_ci	stm32f7_i2c_release_bus(&i2c_dev->adap);
86062306a36Sopenharmony_ci
86162306a36Sopenharmony_ci	return -EBUSY;
86262306a36Sopenharmony_ci}
86362306a36Sopenharmony_ci
86462306a36Sopenharmony_cistatic void stm32f7_i2c_xfer_msg(struct stm32f7_i2c_dev *i2c_dev,
86562306a36Sopenharmony_ci				 struct i2c_msg *msg)
86662306a36Sopenharmony_ci{
86762306a36Sopenharmony_ci	struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg;
86862306a36Sopenharmony_ci	void __iomem *base = i2c_dev->base;
86962306a36Sopenharmony_ci	u32 cr1, cr2;
87062306a36Sopenharmony_ci	int ret;
87162306a36Sopenharmony_ci
87262306a36Sopenharmony_ci	f7_msg->addr = msg->addr;
87362306a36Sopenharmony_ci	f7_msg->buf = msg->buf;
87462306a36Sopenharmony_ci	f7_msg->count = msg->len;
87562306a36Sopenharmony_ci	f7_msg->result = 0;
87662306a36Sopenharmony_ci	f7_msg->stop = (i2c_dev->msg_id >= i2c_dev->msg_num - 1);
87762306a36Sopenharmony_ci
87862306a36Sopenharmony_ci	reinit_completion(&i2c_dev->complete);
87962306a36Sopenharmony_ci
88062306a36Sopenharmony_ci	cr1 = readl_relaxed(base + STM32F7_I2C_CR1);
88162306a36Sopenharmony_ci	cr2 = readl_relaxed(base + STM32F7_I2C_CR2);
88262306a36Sopenharmony_ci
88362306a36Sopenharmony_ci	/* Set transfer direction */
88462306a36Sopenharmony_ci	cr2 &= ~STM32F7_I2C_CR2_RD_WRN;
88562306a36Sopenharmony_ci	if (msg->flags & I2C_M_RD)
88662306a36Sopenharmony_ci		cr2 |= STM32F7_I2C_CR2_RD_WRN;
88762306a36Sopenharmony_ci
88862306a36Sopenharmony_ci	/* Set slave address */
88962306a36Sopenharmony_ci	cr2 &= ~(STM32F7_I2C_CR2_HEAD10R | STM32F7_I2C_CR2_ADD10);
89062306a36Sopenharmony_ci	if (msg->flags & I2C_M_TEN) {
89162306a36Sopenharmony_ci		cr2 &= ~STM32F7_I2C_CR2_SADD10_MASK;
89262306a36Sopenharmony_ci		cr2 |= STM32F7_I2C_CR2_SADD10(f7_msg->addr);
89362306a36Sopenharmony_ci		cr2 |= STM32F7_I2C_CR2_ADD10;
89462306a36Sopenharmony_ci	} else {
89562306a36Sopenharmony_ci		cr2 &= ~STM32F7_I2C_CR2_SADD7_MASK;
89662306a36Sopenharmony_ci		cr2 |= STM32F7_I2C_CR2_SADD7(f7_msg->addr);
89762306a36Sopenharmony_ci	}
89862306a36Sopenharmony_ci
89962306a36Sopenharmony_ci	/* Set nb bytes to transfer and reload if needed */
90062306a36Sopenharmony_ci	cr2 &= ~(STM32F7_I2C_CR2_NBYTES_MASK | STM32F7_I2C_CR2_RELOAD);
90162306a36Sopenharmony_ci	if (f7_msg->count > STM32F7_I2C_MAX_LEN) {
90262306a36Sopenharmony_ci		cr2 |= STM32F7_I2C_CR2_NBYTES(STM32F7_I2C_MAX_LEN);
90362306a36Sopenharmony_ci		cr2 |= STM32F7_I2C_CR2_RELOAD;
90462306a36Sopenharmony_ci	} else {
90562306a36Sopenharmony_ci		cr2 |= STM32F7_I2C_CR2_NBYTES(f7_msg->count);
90662306a36Sopenharmony_ci	}
90762306a36Sopenharmony_ci
90862306a36Sopenharmony_ci	/* Enable NACK, STOP, error and transfer complete interrupts */
90962306a36Sopenharmony_ci	cr1 |= STM32F7_I2C_CR1_ERRIE | STM32F7_I2C_CR1_TCIE |
91062306a36Sopenharmony_ci		STM32F7_I2C_CR1_STOPIE | STM32F7_I2C_CR1_NACKIE;
91162306a36Sopenharmony_ci
91262306a36Sopenharmony_ci	/* Clear DMA req and TX/RX interrupt */
91362306a36Sopenharmony_ci	cr1 &= ~(STM32F7_I2C_CR1_RXIE | STM32F7_I2C_CR1_TXIE |
91462306a36Sopenharmony_ci			STM32F7_I2C_CR1_RXDMAEN | STM32F7_I2C_CR1_TXDMAEN);
91562306a36Sopenharmony_ci
91662306a36Sopenharmony_ci	/* Configure DMA or enable RX/TX interrupt */
91762306a36Sopenharmony_ci	i2c_dev->use_dma = false;
91862306a36Sopenharmony_ci	if (i2c_dev->dma && f7_msg->count >= STM32F7_I2C_DMA_LEN_MIN) {
91962306a36Sopenharmony_ci		ret = stm32_i2c_prep_dma_xfer(i2c_dev->dev, i2c_dev->dma,
92062306a36Sopenharmony_ci					      msg->flags & I2C_M_RD,
92162306a36Sopenharmony_ci					      f7_msg->count, f7_msg->buf,
92262306a36Sopenharmony_ci					      stm32f7_i2c_dma_callback,
92362306a36Sopenharmony_ci					      i2c_dev);
92462306a36Sopenharmony_ci		if (!ret)
92562306a36Sopenharmony_ci			i2c_dev->use_dma = true;
92662306a36Sopenharmony_ci		else
92762306a36Sopenharmony_ci			dev_warn(i2c_dev->dev, "can't use DMA\n");
92862306a36Sopenharmony_ci	}
92962306a36Sopenharmony_ci
93062306a36Sopenharmony_ci	if (!i2c_dev->use_dma) {
93162306a36Sopenharmony_ci		if (msg->flags & I2C_M_RD)
93262306a36Sopenharmony_ci			cr1 |= STM32F7_I2C_CR1_RXIE;
93362306a36Sopenharmony_ci		else
93462306a36Sopenharmony_ci			cr1 |= STM32F7_I2C_CR1_TXIE;
93562306a36Sopenharmony_ci	} else {
93662306a36Sopenharmony_ci		if (msg->flags & I2C_M_RD)
93762306a36Sopenharmony_ci			cr1 |= STM32F7_I2C_CR1_RXDMAEN;
93862306a36Sopenharmony_ci		else
93962306a36Sopenharmony_ci			cr1 |= STM32F7_I2C_CR1_TXDMAEN;
94062306a36Sopenharmony_ci	}
94162306a36Sopenharmony_ci
94262306a36Sopenharmony_ci	/* Configure Start/Repeated Start */
94362306a36Sopenharmony_ci	cr2 |= STM32F7_I2C_CR2_START;
94462306a36Sopenharmony_ci
94562306a36Sopenharmony_ci	i2c_dev->master_mode = true;
94662306a36Sopenharmony_ci
94762306a36Sopenharmony_ci	/* Write configurations registers */
94862306a36Sopenharmony_ci	writel_relaxed(cr1, base + STM32F7_I2C_CR1);
94962306a36Sopenharmony_ci	writel_relaxed(cr2, base + STM32F7_I2C_CR2);
95062306a36Sopenharmony_ci}
95162306a36Sopenharmony_ci
95262306a36Sopenharmony_cistatic int stm32f7_i2c_smbus_xfer_msg(struct stm32f7_i2c_dev *i2c_dev,
95362306a36Sopenharmony_ci				      unsigned short flags, u8 command,
95462306a36Sopenharmony_ci				      union i2c_smbus_data *data)
95562306a36Sopenharmony_ci{
95662306a36Sopenharmony_ci	struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg;
95762306a36Sopenharmony_ci	struct device *dev = i2c_dev->dev;
95862306a36Sopenharmony_ci	void __iomem *base = i2c_dev->base;
95962306a36Sopenharmony_ci	u32 cr1, cr2;
96062306a36Sopenharmony_ci	int i, ret;
96162306a36Sopenharmony_ci
96262306a36Sopenharmony_ci	f7_msg->result = 0;
96362306a36Sopenharmony_ci	reinit_completion(&i2c_dev->complete);
96462306a36Sopenharmony_ci
96562306a36Sopenharmony_ci	cr2 = readl_relaxed(base + STM32F7_I2C_CR2);
96662306a36Sopenharmony_ci	cr1 = readl_relaxed(base + STM32F7_I2C_CR1);
96762306a36Sopenharmony_ci
96862306a36Sopenharmony_ci	/* Set transfer direction */
96962306a36Sopenharmony_ci	cr2 &= ~STM32F7_I2C_CR2_RD_WRN;
97062306a36Sopenharmony_ci	if (f7_msg->read_write)
97162306a36Sopenharmony_ci		cr2 |= STM32F7_I2C_CR2_RD_WRN;
97262306a36Sopenharmony_ci
97362306a36Sopenharmony_ci	/* Set slave address */
97462306a36Sopenharmony_ci	cr2 &= ~(STM32F7_I2C_CR2_ADD10 | STM32F7_I2C_CR2_SADD7_MASK);
97562306a36Sopenharmony_ci	cr2 |= STM32F7_I2C_CR2_SADD7(f7_msg->addr);
97662306a36Sopenharmony_ci
97762306a36Sopenharmony_ci	f7_msg->smbus_buf[0] = command;
97862306a36Sopenharmony_ci	switch (f7_msg->size) {
97962306a36Sopenharmony_ci	case I2C_SMBUS_QUICK:
98062306a36Sopenharmony_ci		f7_msg->stop = true;
98162306a36Sopenharmony_ci		f7_msg->count = 0;
98262306a36Sopenharmony_ci		break;
98362306a36Sopenharmony_ci	case I2C_SMBUS_BYTE:
98462306a36Sopenharmony_ci		f7_msg->stop = true;
98562306a36Sopenharmony_ci		f7_msg->count = 1;
98662306a36Sopenharmony_ci		break;
98762306a36Sopenharmony_ci	case I2C_SMBUS_BYTE_DATA:
98862306a36Sopenharmony_ci		if (f7_msg->read_write) {
98962306a36Sopenharmony_ci			f7_msg->stop = false;
99062306a36Sopenharmony_ci			f7_msg->count = 1;
99162306a36Sopenharmony_ci			cr2 &= ~STM32F7_I2C_CR2_RD_WRN;
99262306a36Sopenharmony_ci		} else {
99362306a36Sopenharmony_ci			f7_msg->stop = true;
99462306a36Sopenharmony_ci			f7_msg->count = 2;
99562306a36Sopenharmony_ci			f7_msg->smbus_buf[1] = data->byte;
99662306a36Sopenharmony_ci		}
99762306a36Sopenharmony_ci		break;
99862306a36Sopenharmony_ci	case I2C_SMBUS_WORD_DATA:
99962306a36Sopenharmony_ci		if (f7_msg->read_write) {
100062306a36Sopenharmony_ci			f7_msg->stop = false;
100162306a36Sopenharmony_ci			f7_msg->count = 1;
100262306a36Sopenharmony_ci			cr2 &= ~STM32F7_I2C_CR2_RD_WRN;
100362306a36Sopenharmony_ci		} else {
100462306a36Sopenharmony_ci			f7_msg->stop = true;
100562306a36Sopenharmony_ci			f7_msg->count = 3;
100662306a36Sopenharmony_ci			f7_msg->smbus_buf[1] = data->word & 0xff;
100762306a36Sopenharmony_ci			f7_msg->smbus_buf[2] = data->word >> 8;
100862306a36Sopenharmony_ci		}
100962306a36Sopenharmony_ci		break;
101062306a36Sopenharmony_ci	case I2C_SMBUS_BLOCK_DATA:
101162306a36Sopenharmony_ci		if (f7_msg->read_write) {
101262306a36Sopenharmony_ci			f7_msg->stop = false;
101362306a36Sopenharmony_ci			f7_msg->count = 1;
101462306a36Sopenharmony_ci			cr2 &= ~STM32F7_I2C_CR2_RD_WRN;
101562306a36Sopenharmony_ci		} else {
101662306a36Sopenharmony_ci			f7_msg->stop = true;
101762306a36Sopenharmony_ci			if (data->block[0] > I2C_SMBUS_BLOCK_MAX ||
101862306a36Sopenharmony_ci			    !data->block[0]) {
101962306a36Sopenharmony_ci				dev_err(dev, "Invalid block write size %d\n",
102062306a36Sopenharmony_ci					data->block[0]);
102162306a36Sopenharmony_ci				return -EINVAL;
102262306a36Sopenharmony_ci			}
102362306a36Sopenharmony_ci			f7_msg->count = data->block[0] + 2;
102462306a36Sopenharmony_ci			for (i = 1; i < f7_msg->count; i++)
102562306a36Sopenharmony_ci				f7_msg->smbus_buf[i] = data->block[i - 1];
102662306a36Sopenharmony_ci		}
102762306a36Sopenharmony_ci		break;
102862306a36Sopenharmony_ci	case I2C_SMBUS_PROC_CALL:
102962306a36Sopenharmony_ci		f7_msg->stop = false;
103062306a36Sopenharmony_ci		f7_msg->count = 3;
103162306a36Sopenharmony_ci		f7_msg->smbus_buf[1] = data->word & 0xff;
103262306a36Sopenharmony_ci		f7_msg->smbus_buf[2] = data->word >> 8;
103362306a36Sopenharmony_ci		cr2 &= ~STM32F7_I2C_CR2_RD_WRN;
103462306a36Sopenharmony_ci		f7_msg->read_write = I2C_SMBUS_READ;
103562306a36Sopenharmony_ci		break;
103662306a36Sopenharmony_ci	case I2C_SMBUS_BLOCK_PROC_CALL:
103762306a36Sopenharmony_ci		f7_msg->stop = false;
103862306a36Sopenharmony_ci		if (data->block[0] > I2C_SMBUS_BLOCK_MAX - 1) {
103962306a36Sopenharmony_ci			dev_err(dev, "Invalid block write size %d\n",
104062306a36Sopenharmony_ci				data->block[0]);
104162306a36Sopenharmony_ci			return -EINVAL;
104262306a36Sopenharmony_ci		}
104362306a36Sopenharmony_ci		f7_msg->count = data->block[0] + 2;
104462306a36Sopenharmony_ci		for (i = 1; i < f7_msg->count; i++)
104562306a36Sopenharmony_ci			f7_msg->smbus_buf[i] = data->block[i - 1];
104662306a36Sopenharmony_ci		cr2 &= ~STM32F7_I2C_CR2_RD_WRN;
104762306a36Sopenharmony_ci		f7_msg->read_write = I2C_SMBUS_READ;
104862306a36Sopenharmony_ci		break;
104962306a36Sopenharmony_ci	case I2C_SMBUS_I2C_BLOCK_DATA:
105062306a36Sopenharmony_ci		/* Rely on emulated i2c transfer (through master_xfer) */
105162306a36Sopenharmony_ci		return -EOPNOTSUPP;
105262306a36Sopenharmony_ci	default:
105362306a36Sopenharmony_ci		dev_err(dev, "Unsupported smbus protocol %d\n", f7_msg->size);
105462306a36Sopenharmony_ci		return -EOPNOTSUPP;
105562306a36Sopenharmony_ci	}
105662306a36Sopenharmony_ci
105762306a36Sopenharmony_ci	f7_msg->buf = f7_msg->smbus_buf;
105862306a36Sopenharmony_ci
105962306a36Sopenharmony_ci	/* Configure PEC */
106062306a36Sopenharmony_ci	if ((flags & I2C_CLIENT_PEC) && f7_msg->size != I2C_SMBUS_QUICK) {
106162306a36Sopenharmony_ci		cr1 |= STM32F7_I2C_CR1_PECEN;
106262306a36Sopenharmony_ci		if (!f7_msg->read_write) {
106362306a36Sopenharmony_ci			cr2 |= STM32F7_I2C_CR2_PECBYTE;
106462306a36Sopenharmony_ci			f7_msg->count++;
106562306a36Sopenharmony_ci		}
106662306a36Sopenharmony_ci	} else {
106762306a36Sopenharmony_ci		cr1 &= ~STM32F7_I2C_CR1_PECEN;
106862306a36Sopenharmony_ci		cr2 &= ~STM32F7_I2C_CR2_PECBYTE;
106962306a36Sopenharmony_ci	}
107062306a36Sopenharmony_ci
107162306a36Sopenharmony_ci	/* Set number of bytes to be transferred */
107262306a36Sopenharmony_ci	cr2 &= ~(STM32F7_I2C_CR2_NBYTES_MASK | STM32F7_I2C_CR2_RELOAD);
107362306a36Sopenharmony_ci	cr2 |= STM32F7_I2C_CR2_NBYTES(f7_msg->count);
107462306a36Sopenharmony_ci
107562306a36Sopenharmony_ci	/* Enable NACK, STOP, error and transfer complete interrupts */
107662306a36Sopenharmony_ci	cr1 |= STM32F7_I2C_CR1_ERRIE | STM32F7_I2C_CR1_TCIE |
107762306a36Sopenharmony_ci		STM32F7_I2C_CR1_STOPIE | STM32F7_I2C_CR1_NACKIE;
107862306a36Sopenharmony_ci
107962306a36Sopenharmony_ci	/* Clear DMA req and TX/RX interrupt */
108062306a36Sopenharmony_ci	cr1 &= ~(STM32F7_I2C_CR1_RXIE | STM32F7_I2C_CR1_TXIE |
108162306a36Sopenharmony_ci			STM32F7_I2C_CR1_RXDMAEN | STM32F7_I2C_CR1_TXDMAEN);
108262306a36Sopenharmony_ci
108362306a36Sopenharmony_ci	/* Configure DMA or enable RX/TX interrupt */
108462306a36Sopenharmony_ci	i2c_dev->use_dma = false;
108562306a36Sopenharmony_ci	if (i2c_dev->dma && f7_msg->count >= STM32F7_I2C_DMA_LEN_MIN) {
108662306a36Sopenharmony_ci		ret = stm32_i2c_prep_dma_xfer(i2c_dev->dev, i2c_dev->dma,
108762306a36Sopenharmony_ci					      cr2 & STM32F7_I2C_CR2_RD_WRN,
108862306a36Sopenharmony_ci					      f7_msg->count, f7_msg->buf,
108962306a36Sopenharmony_ci					      stm32f7_i2c_dma_callback,
109062306a36Sopenharmony_ci					      i2c_dev);
109162306a36Sopenharmony_ci		if (!ret)
109262306a36Sopenharmony_ci			i2c_dev->use_dma = true;
109362306a36Sopenharmony_ci		else
109462306a36Sopenharmony_ci			dev_warn(i2c_dev->dev, "can't use DMA\n");
109562306a36Sopenharmony_ci	}
109662306a36Sopenharmony_ci
109762306a36Sopenharmony_ci	if (!i2c_dev->use_dma) {
109862306a36Sopenharmony_ci		if (cr2 & STM32F7_I2C_CR2_RD_WRN)
109962306a36Sopenharmony_ci			cr1 |= STM32F7_I2C_CR1_RXIE;
110062306a36Sopenharmony_ci		else
110162306a36Sopenharmony_ci			cr1 |= STM32F7_I2C_CR1_TXIE;
110262306a36Sopenharmony_ci	} else {
110362306a36Sopenharmony_ci		if (cr2 & STM32F7_I2C_CR2_RD_WRN)
110462306a36Sopenharmony_ci			cr1 |= STM32F7_I2C_CR1_RXDMAEN;
110562306a36Sopenharmony_ci		else
110662306a36Sopenharmony_ci			cr1 |= STM32F7_I2C_CR1_TXDMAEN;
110762306a36Sopenharmony_ci	}
110862306a36Sopenharmony_ci
110962306a36Sopenharmony_ci	/* Set Start bit */
111062306a36Sopenharmony_ci	cr2 |= STM32F7_I2C_CR2_START;
111162306a36Sopenharmony_ci
111262306a36Sopenharmony_ci	i2c_dev->master_mode = true;
111362306a36Sopenharmony_ci
111462306a36Sopenharmony_ci	/* Write configurations registers */
111562306a36Sopenharmony_ci	writel_relaxed(cr1, base + STM32F7_I2C_CR1);
111662306a36Sopenharmony_ci	writel_relaxed(cr2, base + STM32F7_I2C_CR2);
111762306a36Sopenharmony_ci
111862306a36Sopenharmony_ci	return 0;
111962306a36Sopenharmony_ci}
112062306a36Sopenharmony_ci
112162306a36Sopenharmony_cistatic void stm32f7_i2c_smbus_rep_start(struct stm32f7_i2c_dev *i2c_dev)
112262306a36Sopenharmony_ci{
112362306a36Sopenharmony_ci	struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg;
112462306a36Sopenharmony_ci	void __iomem *base = i2c_dev->base;
112562306a36Sopenharmony_ci	u32 cr1, cr2;
112662306a36Sopenharmony_ci	int ret;
112762306a36Sopenharmony_ci
112862306a36Sopenharmony_ci	cr2 = readl_relaxed(base + STM32F7_I2C_CR2);
112962306a36Sopenharmony_ci	cr1 = readl_relaxed(base + STM32F7_I2C_CR1);
113062306a36Sopenharmony_ci
113162306a36Sopenharmony_ci	/* Set transfer direction */
113262306a36Sopenharmony_ci	cr2 |= STM32F7_I2C_CR2_RD_WRN;
113362306a36Sopenharmony_ci
113462306a36Sopenharmony_ci	switch (f7_msg->size) {
113562306a36Sopenharmony_ci	case I2C_SMBUS_BYTE_DATA:
113662306a36Sopenharmony_ci		f7_msg->count = 1;
113762306a36Sopenharmony_ci		break;
113862306a36Sopenharmony_ci	case I2C_SMBUS_WORD_DATA:
113962306a36Sopenharmony_ci	case I2C_SMBUS_PROC_CALL:
114062306a36Sopenharmony_ci		f7_msg->count = 2;
114162306a36Sopenharmony_ci		break;
114262306a36Sopenharmony_ci	case I2C_SMBUS_BLOCK_DATA:
114362306a36Sopenharmony_ci	case I2C_SMBUS_BLOCK_PROC_CALL:
114462306a36Sopenharmony_ci		f7_msg->count = 1;
114562306a36Sopenharmony_ci		cr2 |= STM32F7_I2C_CR2_RELOAD;
114662306a36Sopenharmony_ci		break;
114762306a36Sopenharmony_ci	}
114862306a36Sopenharmony_ci
114962306a36Sopenharmony_ci	f7_msg->buf = f7_msg->smbus_buf;
115062306a36Sopenharmony_ci	f7_msg->stop = true;
115162306a36Sopenharmony_ci
115262306a36Sopenharmony_ci	/* Add one byte for PEC if needed */
115362306a36Sopenharmony_ci	if (cr1 & STM32F7_I2C_CR1_PECEN) {
115462306a36Sopenharmony_ci		cr2 |= STM32F7_I2C_CR2_PECBYTE;
115562306a36Sopenharmony_ci		f7_msg->count++;
115662306a36Sopenharmony_ci	}
115762306a36Sopenharmony_ci
115862306a36Sopenharmony_ci	/* Set number of bytes to be transferred */
115962306a36Sopenharmony_ci	cr2 &= ~(STM32F7_I2C_CR2_NBYTES_MASK);
116062306a36Sopenharmony_ci	cr2 |= STM32F7_I2C_CR2_NBYTES(f7_msg->count);
116162306a36Sopenharmony_ci
116262306a36Sopenharmony_ci	/*
116362306a36Sopenharmony_ci	 * Configure RX/TX interrupt:
116462306a36Sopenharmony_ci	 */
116562306a36Sopenharmony_ci	cr1 &= ~(STM32F7_I2C_CR1_RXIE | STM32F7_I2C_CR1_TXIE);
116662306a36Sopenharmony_ci	cr1 |= STM32F7_I2C_CR1_RXIE;
116762306a36Sopenharmony_ci
116862306a36Sopenharmony_ci	/*
116962306a36Sopenharmony_ci	 * Configure DMA or enable RX/TX interrupt:
117062306a36Sopenharmony_ci	 * For I2C_SMBUS_BLOCK_DATA and I2C_SMBUS_BLOCK_PROC_CALL we don't use
117162306a36Sopenharmony_ci	 * dma as we don't know in advance how many data will be received
117262306a36Sopenharmony_ci	 */
117362306a36Sopenharmony_ci	cr1 &= ~(STM32F7_I2C_CR1_RXIE | STM32F7_I2C_CR1_TXIE |
117462306a36Sopenharmony_ci		 STM32F7_I2C_CR1_RXDMAEN | STM32F7_I2C_CR1_TXDMAEN);
117562306a36Sopenharmony_ci
117662306a36Sopenharmony_ci	i2c_dev->use_dma = false;
117762306a36Sopenharmony_ci	if (i2c_dev->dma && f7_msg->count >= STM32F7_I2C_DMA_LEN_MIN &&
117862306a36Sopenharmony_ci	    f7_msg->size != I2C_SMBUS_BLOCK_DATA &&
117962306a36Sopenharmony_ci	    f7_msg->size != I2C_SMBUS_BLOCK_PROC_CALL) {
118062306a36Sopenharmony_ci		ret = stm32_i2c_prep_dma_xfer(i2c_dev->dev, i2c_dev->dma,
118162306a36Sopenharmony_ci					      cr2 & STM32F7_I2C_CR2_RD_WRN,
118262306a36Sopenharmony_ci					      f7_msg->count, f7_msg->buf,
118362306a36Sopenharmony_ci					      stm32f7_i2c_dma_callback,
118462306a36Sopenharmony_ci					      i2c_dev);
118562306a36Sopenharmony_ci
118662306a36Sopenharmony_ci		if (!ret)
118762306a36Sopenharmony_ci			i2c_dev->use_dma = true;
118862306a36Sopenharmony_ci		else
118962306a36Sopenharmony_ci			dev_warn(i2c_dev->dev, "can't use DMA\n");
119062306a36Sopenharmony_ci	}
119162306a36Sopenharmony_ci
119262306a36Sopenharmony_ci	if (!i2c_dev->use_dma)
119362306a36Sopenharmony_ci		cr1 |= STM32F7_I2C_CR1_RXIE;
119462306a36Sopenharmony_ci	else
119562306a36Sopenharmony_ci		cr1 |= STM32F7_I2C_CR1_RXDMAEN;
119662306a36Sopenharmony_ci
119762306a36Sopenharmony_ci	/* Configure Repeated Start */
119862306a36Sopenharmony_ci	cr2 |= STM32F7_I2C_CR2_START;
119962306a36Sopenharmony_ci
120062306a36Sopenharmony_ci	/* Write configurations registers */
120162306a36Sopenharmony_ci	writel_relaxed(cr1, base + STM32F7_I2C_CR1);
120262306a36Sopenharmony_ci	writel_relaxed(cr2, base + STM32F7_I2C_CR2);
120362306a36Sopenharmony_ci}
120462306a36Sopenharmony_ci
120562306a36Sopenharmony_cistatic int stm32f7_i2c_smbus_check_pec(struct stm32f7_i2c_dev *i2c_dev)
120662306a36Sopenharmony_ci{
120762306a36Sopenharmony_ci	struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg;
120862306a36Sopenharmony_ci	u8 count, internal_pec, received_pec;
120962306a36Sopenharmony_ci
121062306a36Sopenharmony_ci	internal_pec = readl_relaxed(i2c_dev->base + STM32F7_I2C_PECR);
121162306a36Sopenharmony_ci
121262306a36Sopenharmony_ci	switch (f7_msg->size) {
121362306a36Sopenharmony_ci	case I2C_SMBUS_BYTE:
121462306a36Sopenharmony_ci	case I2C_SMBUS_BYTE_DATA:
121562306a36Sopenharmony_ci		received_pec = f7_msg->smbus_buf[1];
121662306a36Sopenharmony_ci		break;
121762306a36Sopenharmony_ci	case I2C_SMBUS_WORD_DATA:
121862306a36Sopenharmony_ci	case I2C_SMBUS_PROC_CALL:
121962306a36Sopenharmony_ci		received_pec = f7_msg->smbus_buf[2];
122062306a36Sopenharmony_ci		break;
122162306a36Sopenharmony_ci	case I2C_SMBUS_BLOCK_DATA:
122262306a36Sopenharmony_ci	case I2C_SMBUS_BLOCK_PROC_CALL:
122362306a36Sopenharmony_ci		count = f7_msg->smbus_buf[0];
122462306a36Sopenharmony_ci		received_pec = f7_msg->smbus_buf[count];
122562306a36Sopenharmony_ci		break;
122662306a36Sopenharmony_ci	default:
122762306a36Sopenharmony_ci		dev_err(i2c_dev->dev, "Unsupported smbus protocol for PEC\n");
122862306a36Sopenharmony_ci		return -EINVAL;
122962306a36Sopenharmony_ci	}
123062306a36Sopenharmony_ci
123162306a36Sopenharmony_ci	if (internal_pec != received_pec) {
123262306a36Sopenharmony_ci		dev_err(i2c_dev->dev, "Bad PEC 0x%02x vs. 0x%02x\n",
123362306a36Sopenharmony_ci			internal_pec, received_pec);
123462306a36Sopenharmony_ci		return -EBADMSG;
123562306a36Sopenharmony_ci	}
123662306a36Sopenharmony_ci
123762306a36Sopenharmony_ci	return 0;
123862306a36Sopenharmony_ci}
123962306a36Sopenharmony_ci
124062306a36Sopenharmony_cistatic bool stm32f7_i2c_is_addr_match(struct i2c_client *slave, u32 addcode)
124162306a36Sopenharmony_ci{
124262306a36Sopenharmony_ci	u32 addr;
124362306a36Sopenharmony_ci
124462306a36Sopenharmony_ci	if (!slave)
124562306a36Sopenharmony_ci		return false;
124662306a36Sopenharmony_ci
124762306a36Sopenharmony_ci	if (slave->flags & I2C_CLIENT_TEN) {
124862306a36Sopenharmony_ci		/*
124962306a36Sopenharmony_ci		 * For 10-bit addr, addcode = 11110XY with
125062306a36Sopenharmony_ci		 * X = Bit 9 of slave address
125162306a36Sopenharmony_ci		 * Y = Bit 8 of slave address
125262306a36Sopenharmony_ci		 */
125362306a36Sopenharmony_ci		addr = slave->addr >> 8;
125462306a36Sopenharmony_ci		addr |= 0x78;
125562306a36Sopenharmony_ci		if (addr == addcode)
125662306a36Sopenharmony_ci			return true;
125762306a36Sopenharmony_ci	} else {
125862306a36Sopenharmony_ci		addr = slave->addr & 0x7f;
125962306a36Sopenharmony_ci		if (addr == addcode)
126062306a36Sopenharmony_ci			return true;
126162306a36Sopenharmony_ci	}
126262306a36Sopenharmony_ci
126362306a36Sopenharmony_ci	return false;
126462306a36Sopenharmony_ci}
126562306a36Sopenharmony_ci
126662306a36Sopenharmony_cistatic void stm32f7_i2c_slave_start(struct stm32f7_i2c_dev *i2c_dev)
126762306a36Sopenharmony_ci{
126862306a36Sopenharmony_ci	struct i2c_client *slave = i2c_dev->slave_running;
126962306a36Sopenharmony_ci	void __iomem *base = i2c_dev->base;
127062306a36Sopenharmony_ci	u32 mask;
127162306a36Sopenharmony_ci	u8 value = 0;
127262306a36Sopenharmony_ci
127362306a36Sopenharmony_ci	if (i2c_dev->slave_dir) {
127462306a36Sopenharmony_ci		/* Notify i2c slave that new read transfer is starting */
127562306a36Sopenharmony_ci		i2c_slave_event(slave, I2C_SLAVE_READ_REQUESTED, &value);
127662306a36Sopenharmony_ci
127762306a36Sopenharmony_ci		/*
127862306a36Sopenharmony_ci		 * Disable slave TX config in case of I2C combined message
127962306a36Sopenharmony_ci		 * (I2C Write followed by I2C Read)
128062306a36Sopenharmony_ci		 */
128162306a36Sopenharmony_ci		mask = STM32F7_I2C_CR2_RELOAD;
128262306a36Sopenharmony_ci		stm32f7_i2c_clr_bits(base + STM32F7_I2C_CR2, mask);
128362306a36Sopenharmony_ci		mask = STM32F7_I2C_CR1_SBC | STM32F7_I2C_CR1_RXIE |
128462306a36Sopenharmony_ci		       STM32F7_I2C_CR1_TCIE;
128562306a36Sopenharmony_ci		stm32f7_i2c_clr_bits(base + STM32F7_I2C_CR1, mask);
128662306a36Sopenharmony_ci
128762306a36Sopenharmony_ci		/* Enable TX empty, STOP, NACK interrupts */
128862306a36Sopenharmony_ci		mask =  STM32F7_I2C_CR1_STOPIE | STM32F7_I2C_CR1_NACKIE |
128962306a36Sopenharmony_ci			STM32F7_I2C_CR1_TXIE;
129062306a36Sopenharmony_ci		stm32f7_i2c_set_bits(base + STM32F7_I2C_CR1, mask);
129162306a36Sopenharmony_ci
129262306a36Sopenharmony_ci		/* Write 1st data byte */
129362306a36Sopenharmony_ci		writel_relaxed(value, base + STM32F7_I2C_TXDR);
129462306a36Sopenharmony_ci	} else {
129562306a36Sopenharmony_ci		/* Notify i2c slave that new write transfer is starting */
129662306a36Sopenharmony_ci		i2c_slave_event(slave, I2C_SLAVE_WRITE_REQUESTED, &value);
129762306a36Sopenharmony_ci
129862306a36Sopenharmony_ci		/* Set reload mode to be able to ACK/NACK each received byte */
129962306a36Sopenharmony_ci		mask = STM32F7_I2C_CR2_RELOAD;
130062306a36Sopenharmony_ci		stm32f7_i2c_set_bits(base + STM32F7_I2C_CR2, mask);
130162306a36Sopenharmony_ci
130262306a36Sopenharmony_ci		/*
130362306a36Sopenharmony_ci		 * Set STOP, NACK, RX empty and transfer complete interrupts.*
130462306a36Sopenharmony_ci		 * Set Slave Byte Control to be able to ACK/NACK each data
130562306a36Sopenharmony_ci		 * byte received
130662306a36Sopenharmony_ci		 */
130762306a36Sopenharmony_ci		mask =  STM32F7_I2C_CR1_STOPIE | STM32F7_I2C_CR1_NACKIE |
130862306a36Sopenharmony_ci			STM32F7_I2C_CR1_SBC | STM32F7_I2C_CR1_RXIE |
130962306a36Sopenharmony_ci			STM32F7_I2C_CR1_TCIE;
131062306a36Sopenharmony_ci		stm32f7_i2c_set_bits(base + STM32F7_I2C_CR1, mask);
131162306a36Sopenharmony_ci	}
131262306a36Sopenharmony_ci}
131362306a36Sopenharmony_ci
131462306a36Sopenharmony_cistatic void stm32f7_i2c_slave_addr(struct stm32f7_i2c_dev *i2c_dev)
131562306a36Sopenharmony_ci{
131662306a36Sopenharmony_ci	void __iomem *base = i2c_dev->base;
131762306a36Sopenharmony_ci	u32 isr, addcode, dir, mask;
131862306a36Sopenharmony_ci	int i;
131962306a36Sopenharmony_ci
132062306a36Sopenharmony_ci	isr = readl_relaxed(i2c_dev->base + STM32F7_I2C_ISR);
132162306a36Sopenharmony_ci	addcode = STM32F7_I2C_ISR_ADDCODE_GET(isr);
132262306a36Sopenharmony_ci	dir = isr & STM32F7_I2C_ISR_DIR;
132362306a36Sopenharmony_ci
132462306a36Sopenharmony_ci	for (i = 0; i < STM32F7_I2C_MAX_SLAVE; i++) {
132562306a36Sopenharmony_ci		if (stm32f7_i2c_is_addr_match(i2c_dev->slave[i], addcode)) {
132662306a36Sopenharmony_ci			i2c_dev->slave_running = i2c_dev->slave[i];
132762306a36Sopenharmony_ci			i2c_dev->slave_dir = dir;
132862306a36Sopenharmony_ci
132962306a36Sopenharmony_ci			/* Start I2C slave processing */
133062306a36Sopenharmony_ci			stm32f7_i2c_slave_start(i2c_dev);
133162306a36Sopenharmony_ci
133262306a36Sopenharmony_ci			/* Clear ADDR flag */
133362306a36Sopenharmony_ci			mask = STM32F7_I2C_ICR_ADDRCF;
133462306a36Sopenharmony_ci			writel_relaxed(mask, base + STM32F7_I2C_ICR);
133562306a36Sopenharmony_ci			break;
133662306a36Sopenharmony_ci		}
133762306a36Sopenharmony_ci	}
133862306a36Sopenharmony_ci}
133962306a36Sopenharmony_ci
134062306a36Sopenharmony_cistatic int stm32f7_i2c_get_slave_id(struct stm32f7_i2c_dev *i2c_dev,
134162306a36Sopenharmony_ci				    struct i2c_client *slave, int *id)
134262306a36Sopenharmony_ci{
134362306a36Sopenharmony_ci	int i;
134462306a36Sopenharmony_ci
134562306a36Sopenharmony_ci	for (i = 0; i < STM32F7_I2C_MAX_SLAVE; i++) {
134662306a36Sopenharmony_ci		if (i2c_dev->slave[i] == slave) {
134762306a36Sopenharmony_ci			*id = i;
134862306a36Sopenharmony_ci			return 0;
134962306a36Sopenharmony_ci		}
135062306a36Sopenharmony_ci	}
135162306a36Sopenharmony_ci
135262306a36Sopenharmony_ci	dev_err(i2c_dev->dev, "Slave 0x%x not registered\n", slave->addr);
135362306a36Sopenharmony_ci
135462306a36Sopenharmony_ci	return -ENODEV;
135562306a36Sopenharmony_ci}
135662306a36Sopenharmony_ci
135762306a36Sopenharmony_cistatic int stm32f7_i2c_get_free_slave_id(struct stm32f7_i2c_dev *i2c_dev,
135862306a36Sopenharmony_ci					 struct i2c_client *slave, int *id)
135962306a36Sopenharmony_ci{
136062306a36Sopenharmony_ci	struct device *dev = i2c_dev->dev;
136162306a36Sopenharmony_ci	int i;
136262306a36Sopenharmony_ci
136362306a36Sopenharmony_ci	/*
136462306a36Sopenharmony_ci	 * slave[STM32F7_SLAVE_HOSTNOTIFY] support only SMBus Host address (0x8)
136562306a36Sopenharmony_ci	 * slave[STM32F7_SLAVE_7_10_BITS_ADDR] supports 7-bit and 10-bit slave address
136662306a36Sopenharmony_ci	 * slave[STM32F7_SLAVE_7_BITS_ADDR] supports 7-bit slave address only
136762306a36Sopenharmony_ci	 */
136862306a36Sopenharmony_ci	if (i2c_dev->smbus_mode && (slave->addr == 0x08)) {
136962306a36Sopenharmony_ci		if (i2c_dev->slave[STM32F7_SLAVE_HOSTNOTIFY])
137062306a36Sopenharmony_ci			goto fail;
137162306a36Sopenharmony_ci		*id = STM32F7_SLAVE_HOSTNOTIFY;
137262306a36Sopenharmony_ci		return 0;
137362306a36Sopenharmony_ci	}
137462306a36Sopenharmony_ci
137562306a36Sopenharmony_ci	for (i = STM32F7_I2C_MAX_SLAVE - 1; i > STM32F7_SLAVE_HOSTNOTIFY; i--) {
137662306a36Sopenharmony_ci		if ((i == STM32F7_SLAVE_7_BITS_ADDR) &&
137762306a36Sopenharmony_ci		    (slave->flags & I2C_CLIENT_TEN))
137862306a36Sopenharmony_ci			continue;
137962306a36Sopenharmony_ci		if (!i2c_dev->slave[i]) {
138062306a36Sopenharmony_ci			*id = i;
138162306a36Sopenharmony_ci			return 0;
138262306a36Sopenharmony_ci		}
138362306a36Sopenharmony_ci	}
138462306a36Sopenharmony_ci
138562306a36Sopenharmony_cifail:
138662306a36Sopenharmony_ci	dev_err(dev, "Slave 0x%x could not be registered\n", slave->addr);
138762306a36Sopenharmony_ci
138862306a36Sopenharmony_ci	return -EINVAL;
138962306a36Sopenharmony_ci}
139062306a36Sopenharmony_ci
139162306a36Sopenharmony_cistatic bool stm32f7_i2c_is_slave_registered(struct stm32f7_i2c_dev *i2c_dev)
139262306a36Sopenharmony_ci{
139362306a36Sopenharmony_ci	int i;
139462306a36Sopenharmony_ci
139562306a36Sopenharmony_ci	for (i = 0; i < STM32F7_I2C_MAX_SLAVE; i++) {
139662306a36Sopenharmony_ci		if (i2c_dev->slave[i])
139762306a36Sopenharmony_ci			return true;
139862306a36Sopenharmony_ci	}
139962306a36Sopenharmony_ci
140062306a36Sopenharmony_ci	return false;
140162306a36Sopenharmony_ci}
140262306a36Sopenharmony_ci
140362306a36Sopenharmony_cistatic bool stm32f7_i2c_is_slave_busy(struct stm32f7_i2c_dev *i2c_dev)
140462306a36Sopenharmony_ci{
140562306a36Sopenharmony_ci	int i, busy;
140662306a36Sopenharmony_ci
140762306a36Sopenharmony_ci	busy = 0;
140862306a36Sopenharmony_ci	for (i = 0; i < STM32F7_I2C_MAX_SLAVE; i++) {
140962306a36Sopenharmony_ci		if (i2c_dev->slave[i])
141062306a36Sopenharmony_ci			busy++;
141162306a36Sopenharmony_ci	}
141262306a36Sopenharmony_ci
141362306a36Sopenharmony_ci	return i == busy;
141462306a36Sopenharmony_ci}
141562306a36Sopenharmony_ci
141662306a36Sopenharmony_cistatic irqreturn_t stm32f7_i2c_slave_isr_event(struct stm32f7_i2c_dev *i2c_dev)
141762306a36Sopenharmony_ci{
141862306a36Sopenharmony_ci	void __iomem *base = i2c_dev->base;
141962306a36Sopenharmony_ci	u32 cr2, status, mask;
142062306a36Sopenharmony_ci	u8 val;
142162306a36Sopenharmony_ci	int ret;
142262306a36Sopenharmony_ci
142362306a36Sopenharmony_ci	status = readl_relaxed(i2c_dev->base + STM32F7_I2C_ISR);
142462306a36Sopenharmony_ci
142562306a36Sopenharmony_ci	/* Slave transmitter mode */
142662306a36Sopenharmony_ci	if (status & STM32F7_I2C_ISR_TXIS) {
142762306a36Sopenharmony_ci		i2c_slave_event(i2c_dev->slave_running,
142862306a36Sopenharmony_ci				I2C_SLAVE_READ_PROCESSED,
142962306a36Sopenharmony_ci				&val);
143062306a36Sopenharmony_ci
143162306a36Sopenharmony_ci		/* Write data byte */
143262306a36Sopenharmony_ci		writel_relaxed(val, base + STM32F7_I2C_TXDR);
143362306a36Sopenharmony_ci	}
143462306a36Sopenharmony_ci
143562306a36Sopenharmony_ci	/* Transfer Complete Reload for Slave receiver mode */
143662306a36Sopenharmony_ci	if (status & STM32F7_I2C_ISR_TCR || status & STM32F7_I2C_ISR_RXNE) {
143762306a36Sopenharmony_ci		/*
143862306a36Sopenharmony_ci		 * Read data byte then set NBYTES to receive next byte or NACK
143962306a36Sopenharmony_ci		 * the current received byte
144062306a36Sopenharmony_ci		 */
144162306a36Sopenharmony_ci		val = readb_relaxed(i2c_dev->base + STM32F7_I2C_RXDR);
144262306a36Sopenharmony_ci		ret = i2c_slave_event(i2c_dev->slave_running,
144362306a36Sopenharmony_ci				      I2C_SLAVE_WRITE_RECEIVED,
144462306a36Sopenharmony_ci				      &val);
144562306a36Sopenharmony_ci		if (!ret) {
144662306a36Sopenharmony_ci			cr2 = readl_relaxed(i2c_dev->base + STM32F7_I2C_CR2);
144762306a36Sopenharmony_ci			cr2 |= STM32F7_I2C_CR2_NBYTES(1);
144862306a36Sopenharmony_ci			writel_relaxed(cr2, i2c_dev->base + STM32F7_I2C_CR2);
144962306a36Sopenharmony_ci		} else {
145062306a36Sopenharmony_ci			mask = STM32F7_I2C_CR2_NACK;
145162306a36Sopenharmony_ci			stm32f7_i2c_set_bits(base + STM32F7_I2C_CR2, mask);
145262306a36Sopenharmony_ci		}
145362306a36Sopenharmony_ci	}
145462306a36Sopenharmony_ci
145562306a36Sopenharmony_ci	/* NACK received */
145662306a36Sopenharmony_ci	if (status & STM32F7_I2C_ISR_NACKF) {
145762306a36Sopenharmony_ci		dev_dbg(i2c_dev->dev, "<%s>: Receive NACK\n", __func__);
145862306a36Sopenharmony_ci		writel_relaxed(STM32F7_I2C_ICR_NACKCF, base + STM32F7_I2C_ICR);
145962306a36Sopenharmony_ci	}
146062306a36Sopenharmony_ci
146162306a36Sopenharmony_ci	/* STOP received */
146262306a36Sopenharmony_ci	if (status & STM32F7_I2C_ISR_STOPF) {
146362306a36Sopenharmony_ci		/* Disable interrupts */
146462306a36Sopenharmony_ci		stm32f7_i2c_disable_irq(i2c_dev, STM32F7_I2C_XFER_IRQ_MASK);
146562306a36Sopenharmony_ci
146662306a36Sopenharmony_ci		if (i2c_dev->slave_dir) {
146762306a36Sopenharmony_ci			/*
146862306a36Sopenharmony_ci			 * Flush TX buffer in order to not used the byte in
146962306a36Sopenharmony_ci			 * TXDR for the next transfer
147062306a36Sopenharmony_ci			 */
147162306a36Sopenharmony_ci			mask = STM32F7_I2C_ISR_TXE;
147262306a36Sopenharmony_ci			stm32f7_i2c_set_bits(base + STM32F7_I2C_ISR, mask);
147362306a36Sopenharmony_ci		}
147462306a36Sopenharmony_ci
147562306a36Sopenharmony_ci		/* Clear STOP flag */
147662306a36Sopenharmony_ci		writel_relaxed(STM32F7_I2C_ICR_STOPCF, base + STM32F7_I2C_ICR);
147762306a36Sopenharmony_ci
147862306a36Sopenharmony_ci		/* Notify i2c slave that a STOP flag has been detected */
147962306a36Sopenharmony_ci		i2c_slave_event(i2c_dev->slave_running, I2C_SLAVE_STOP, &val);
148062306a36Sopenharmony_ci
148162306a36Sopenharmony_ci		i2c_dev->slave_running = NULL;
148262306a36Sopenharmony_ci	}
148362306a36Sopenharmony_ci
148462306a36Sopenharmony_ci	/* Address match received */
148562306a36Sopenharmony_ci	if (status & STM32F7_I2C_ISR_ADDR)
148662306a36Sopenharmony_ci		stm32f7_i2c_slave_addr(i2c_dev);
148762306a36Sopenharmony_ci
148862306a36Sopenharmony_ci	return IRQ_HANDLED;
148962306a36Sopenharmony_ci}
149062306a36Sopenharmony_ci
149162306a36Sopenharmony_cistatic irqreturn_t stm32f7_i2c_isr_event(int irq, void *data)
149262306a36Sopenharmony_ci{
149362306a36Sopenharmony_ci	struct stm32f7_i2c_dev *i2c_dev = data;
149462306a36Sopenharmony_ci	struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg;
149562306a36Sopenharmony_ci	struct stm32_i2c_dma *dma = i2c_dev->dma;
149662306a36Sopenharmony_ci	void __iomem *base = i2c_dev->base;
149762306a36Sopenharmony_ci	u32 status, mask;
149862306a36Sopenharmony_ci	int ret = IRQ_HANDLED;
149962306a36Sopenharmony_ci
150062306a36Sopenharmony_ci	/* Check if the interrupt if for a slave device */
150162306a36Sopenharmony_ci	if (!i2c_dev->master_mode) {
150262306a36Sopenharmony_ci		ret = stm32f7_i2c_slave_isr_event(i2c_dev);
150362306a36Sopenharmony_ci		return ret;
150462306a36Sopenharmony_ci	}
150562306a36Sopenharmony_ci
150662306a36Sopenharmony_ci	status = readl_relaxed(i2c_dev->base + STM32F7_I2C_ISR);
150762306a36Sopenharmony_ci
150862306a36Sopenharmony_ci	/* Tx empty */
150962306a36Sopenharmony_ci	if (status & STM32F7_I2C_ISR_TXIS)
151062306a36Sopenharmony_ci		stm32f7_i2c_write_tx_data(i2c_dev);
151162306a36Sopenharmony_ci
151262306a36Sopenharmony_ci	/* RX not empty */
151362306a36Sopenharmony_ci	if (status & STM32F7_I2C_ISR_RXNE)
151462306a36Sopenharmony_ci		stm32f7_i2c_read_rx_data(i2c_dev);
151562306a36Sopenharmony_ci
151662306a36Sopenharmony_ci	/* NACK received */
151762306a36Sopenharmony_ci	if (status & STM32F7_I2C_ISR_NACKF) {
151862306a36Sopenharmony_ci		dev_dbg(i2c_dev->dev, "<%s>: Receive NACK (addr %x)\n",
151962306a36Sopenharmony_ci			__func__, f7_msg->addr);
152062306a36Sopenharmony_ci		writel_relaxed(STM32F7_I2C_ICR_NACKCF, base + STM32F7_I2C_ICR);
152162306a36Sopenharmony_ci		if (i2c_dev->use_dma) {
152262306a36Sopenharmony_ci			stm32f7_i2c_disable_dma_req(i2c_dev);
152362306a36Sopenharmony_ci			dmaengine_terminate_async(dma->chan_using);
152462306a36Sopenharmony_ci		}
152562306a36Sopenharmony_ci		f7_msg->result = -ENXIO;
152662306a36Sopenharmony_ci	}
152762306a36Sopenharmony_ci
152862306a36Sopenharmony_ci	/* STOP detection flag */
152962306a36Sopenharmony_ci	if (status & STM32F7_I2C_ISR_STOPF) {
153062306a36Sopenharmony_ci		/* Disable interrupts */
153162306a36Sopenharmony_ci		if (stm32f7_i2c_is_slave_registered(i2c_dev))
153262306a36Sopenharmony_ci			mask = STM32F7_I2C_XFER_IRQ_MASK;
153362306a36Sopenharmony_ci		else
153462306a36Sopenharmony_ci			mask = STM32F7_I2C_ALL_IRQ_MASK;
153562306a36Sopenharmony_ci		stm32f7_i2c_disable_irq(i2c_dev, mask);
153662306a36Sopenharmony_ci
153762306a36Sopenharmony_ci		/* Clear STOP flag */
153862306a36Sopenharmony_ci		writel_relaxed(STM32F7_I2C_ICR_STOPCF, base + STM32F7_I2C_ICR);
153962306a36Sopenharmony_ci
154062306a36Sopenharmony_ci		if (i2c_dev->use_dma && !f7_msg->result) {
154162306a36Sopenharmony_ci			ret = IRQ_WAKE_THREAD;
154262306a36Sopenharmony_ci		} else {
154362306a36Sopenharmony_ci			i2c_dev->master_mode = false;
154462306a36Sopenharmony_ci			complete(&i2c_dev->complete);
154562306a36Sopenharmony_ci		}
154662306a36Sopenharmony_ci	}
154762306a36Sopenharmony_ci
154862306a36Sopenharmony_ci	/* Transfer complete */
154962306a36Sopenharmony_ci	if (status & STM32F7_I2C_ISR_TC) {
155062306a36Sopenharmony_ci		if (f7_msg->stop) {
155162306a36Sopenharmony_ci			mask = STM32F7_I2C_CR2_STOP;
155262306a36Sopenharmony_ci			stm32f7_i2c_set_bits(base + STM32F7_I2C_CR2, mask);
155362306a36Sopenharmony_ci		} else if (i2c_dev->use_dma && !f7_msg->result) {
155462306a36Sopenharmony_ci			ret = IRQ_WAKE_THREAD;
155562306a36Sopenharmony_ci		} else if (f7_msg->smbus) {
155662306a36Sopenharmony_ci			stm32f7_i2c_smbus_rep_start(i2c_dev);
155762306a36Sopenharmony_ci		} else {
155862306a36Sopenharmony_ci			i2c_dev->msg_id++;
155962306a36Sopenharmony_ci			i2c_dev->msg++;
156062306a36Sopenharmony_ci			stm32f7_i2c_xfer_msg(i2c_dev, i2c_dev->msg);
156162306a36Sopenharmony_ci		}
156262306a36Sopenharmony_ci	}
156362306a36Sopenharmony_ci
156462306a36Sopenharmony_ci	if (status & STM32F7_I2C_ISR_TCR) {
156562306a36Sopenharmony_ci		if (f7_msg->smbus)
156662306a36Sopenharmony_ci			stm32f7_i2c_smbus_reload(i2c_dev);
156762306a36Sopenharmony_ci		else
156862306a36Sopenharmony_ci			stm32f7_i2c_reload(i2c_dev);
156962306a36Sopenharmony_ci	}
157062306a36Sopenharmony_ci
157162306a36Sopenharmony_ci	return ret;
157262306a36Sopenharmony_ci}
157362306a36Sopenharmony_ci
157462306a36Sopenharmony_cistatic irqreturn_t stm32f7_i2c_isr_event_thread(int irq, void *data)
157562306a36Sopenharmony_ci{
157662306a36Sopenharmony_ci	struct stm32f7_i2c_dev *i2c_dev = data;
157762306a36Sopenharmony_ci	struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg;
157862306a36Sopenharmony_ci	struct stm32_i2c_dma *dma = i2c_dev->dma;
157962306a36Sopenharmony_ci	u32 status;
158062306a36Sopenharmony_ci	int ret;
158162306a36Sopenharmony_ci
158262306a36Sopenharmony_ci	/*
158362306a36Sopenharmony_ci	 * Wait for dma transfer completion before sending next message or
158462306a36Sopenharmony_ci	 * notity the end of xfer to the client
158562306a36Sopenharmony_ci	 */
158662306a36Sopenharmony_ci	ret = wait_for_completion_timeout(&i2c_dev->dma->dma_complete, HZ);
158762306a36Sopenharmony_ci	if (!ret) {
158862306a36Sopenharmony_ci		dev_dbg(i2c_dev->dev, "<%s>: Timed out\n", __func__);
158962306a36Sopenharmony_ci		stm32f7_i2c_disable_dma_req(i2c_dev);
159062306a36Sopenharmony_ci		dmaengine_terminate_async(dma->chan_using);
159162306a36Sopenharmony_ci		f7_msg->result = -ETIMEDOUT;
159262306a36Sopenharmony_ci	}
159362306a36Sopenharmony_ci
159462306a36Sopenharmony_ci	status = readl_relaxed(i2c_dev->base + STM32F7_I2C_ISR);
159562306a36Sopenharmony_ci
159662306a36Sopenharmony_ci	if (status & STM32F7_I2C_ISR_TC) {
159762306a36Sopenharmony_ci		if (f7_msg->smbus) {
159862306a36Sopenharmony_ci			stm32f7_i2c_smbus_rep_start(i2c_dev);
159962306a36Sopenharmony_ci		} else {
160062306a36Sopenharmony_ci			i2c_dev->msg_id++;
160162306a36Sopenharmony_ci			i2c_dev->msg++;
160262306a36Sopenharmony_ci			stm32f7_i2c_xfer_msg(i2c_dev, i2c_dev->msg);
160362306a36Sopenharmony_ci		}
160462306a36Sopenharmony_ci	} else {
160562306a36Sopenharmony_ci		i2c_dev->master_mode = false;
160662306a36Sopenharmony_ci		complete(&i2c_dev->complete);
160762306a36Sopenharmony_ci	}
160862306a36Sopenharmony_ci
160962306a36Sopenharmony_ci	return IRQ_HANDLED;
161062306a36Sopenharmony_ci}
161162306a36Sopenharmony_ci
161262306a36Sopenharmony_cistatic irqreturn_t stm32f7_i2c_isr_error(int irq, void *data)
161362306a36Sopenharmony_ci{
161462306a36Sopenharmony_ci	struct stm32f7_i2c_dev *i2c_dev = data;
161562306a36Sopenharmony_ci	struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg;
161662306a36Sopenharmony_ci	void __iomem *base = i2c_dev->base;
161762306a36Sopenharmony_ci	struct device *dev = i2c_dev->dev;
161862306a36Sopenharmony_ci	struct stm32_i2c_dma *dma = i2c_dev->dma;
161962306a36Sopenharmony_ci	u32 status;
162062306a36Sopenharmony_ci
162162306a36Sopenharmony_ci	status = readl_relaxed(i2c_dev->base + STM32F7_I2C_ISR);
162262306a36Sopenharmony_ci
162362306a36Sopenharmony_ci	/* Bus error */
162462306a36Sopenharmony_ci	if (status & STM32F7_I2C_ISR_BERR) {
162562306a36Sopenharmony_ci		dev_err(dev, "<%s>: Bus error accessing addr 0x%x\n",
162662306a36Sopenharmony_ci			__func__, f7_msg->addr);
162762306a36Sopenharmony_ci		writel_relaxed(STM32F7_I2C_ICR_BERRCF, base + STM32F7_I2C_ICR);
162862306a36Sopenharmony_ci		stm32f7_i2c_release_bus(&i2c_dev->adap);
162962306a36Sopenharmony_ci		f7_msg->result = -EIO;
163062306a36Sopenharmony_ci	}
163162306a36Sopenharmony_ci
163262306a36Sopenharmony_ci	/* Arbitration loss */
163362306a36Sopenharmony_ci	if (status & STM32F7_I2C_ISR_ARLO) {
163462306a36Sopenharmony_ci		dev_dbg(dev, "<%s>: Arbitration loss accessing addr 0x%x\n",
163562306a36Sopenharmony_ci			__func__, f7_msg->addr);
163662306a36Sopenharmony_ci		writel_relaxed(STM32F7_I2C_ICR_ARLOCF, base + STM32F7_I2C_ICR);
163762306a36Sopenharmony_ci		f7_msg->result = -EAGAIN;
163862306a36Sopenharmony_ci	}
163962306a36Sopenharmony_ci
164062306a36Sopenharmony_ci	if (status & STM32F7_I2C_ISR_PECERR) {
164162306a36Sopenharmony_ci		dev_err(dev, "<%s>: PEC error in reception accessing addr 0x%x\n",
164262306a36Sopenharmony_ci			__func__, f7_msg->addr);
164362306a36Sopenharmony_ci		writel_relaxed(STM32F7_I2C_ICR_PECCF, base + STM32F7_I2C_ICR);
164462306a36Sopenharmony_ci		f7_msg->result = -EINVAL;
164562306a36Sopenharmony_ci	}
164662306a36Sopenharmony_ci
164762306a36Sopenharmony_ci	if (status & STM32F7_I2C_ISR_ALERT) {
164862306a36Sopenharmony_ci		dev_dbg(dev, "<%s>: SMBus alert received\n", __func__);
164962306a36Sopenharmony_ci		writel_relaxed(STM32F7_I2C_ICR_ALERTCF, base + STM32F7_I2C_ICR);
165062306a36Sopenharmony_ci		i2c_handle_smbus_alert(i2c_dev->alert->ara);
165162306a36Sopenharmony_ci		return IRQ_HANDLED;
165262306a36Sopenharmony_ci	}
165362306a36Sopenharmony_ci
165462306a36Sopenharmony_ci	if (!i2c_dev->slave_running) {
165562306a36Sopenharmony_ci		u32 mask;
165662306a36Sopenharmony_ci		/* Disable interrupts */
165762306a36Sopenharmony_ci		if (stm32f7_i2c_is_slave_registered(i2c_dev))
165862306a36Sopenharmony_ci			mask = STM32F7_I2C_XFER_IRQ_MASK;
165962306a36Sopenharmony_ci		else
166062306a36Sopenharmony_ci			mask = STM32F7_I2C_ALL_IRQ_MASK;
166162306a36Sopenharmony_ci		stm32f7_i2c_disable_irq(i2c_dev, mask);
166262306a36Sopenharmony_ci	}
166362306a36Sopenharmony_ci
166462306a36Sopenharmony_ci	/* Disable dma */
166562306a36Sopenharmony_ci	if (i2c_dev->use_dma) {
166662306a36Sopenharmony_ci		stm32f7_i2c_disable_dma_req(i2c_dev);
166762306a36Sopenharmony_ci		dmaengine_terminate_async(dma->chan_using);
166862306a36Sopenharmony_ci	}
166962306a36Sopenharmony_ci
167062306a36Sopenharmony_ci	i2c_dev->master_mode = false;
167162306a36Sopenharmony_ci	complete(&i2c_dev->complete);
167262306a36Sopenharmony_ci
167362306a36Sopenharmony_ci	return IRQ_HANDLED;
167462306a36Sopenharmony_ci}
167562306a36Sopenharmony_ci
167662306a36Sopenharmony_cistatic int stm32f7_i2c_xfer(struct i2c_adapter *i2c_adap,
167762306a36Sopenharmony_ci			    struct i2c_msg msgs[], int num)
167862306a36Sopenharmony_ci{
167962306a36Sopenharmony_ci	struct stm32f7_i2c_dev *i2c_dev = i2c_get_adapdata(i2c_adap);
168062306a36Sopenharmony_ci	struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg;
168162306a36Sopenharmony_ci	struct stm32_i2c_dma *dma = i2c_dev->dma;
168262306a36Sopenharmony_ci	unsigned long time_left;
168362306a36Sopenharmony_ci	int ret;
168462306a36Sopenharmony_ci
168562306a36Sopenharmony_ci	i2c_dev->msg = msgs;
168662306a36Sopenharmony_ci	i2c_dev->msg_num = num;
168762306a36Sopenharmony_ci	i2c_dev->msg_id = 0;
168862306a36Sopenharmony_ci	f7_msg->smbus = false;
168962306a36Sopenharmony_ci
169062306a36Sopenharmony_ci	ret = pm_runtime_resume_and_get(i2c_dev->dev);
169162306a36Sopenharmony_ci	if (ret < 0)
169262306a36Sopenharmony_ci		return ret;
169362306a36Sopenharmony_ci
169462306a36Sopenharmony_ci	ret = stm32f7_i2c_wait_free_bus(i2c_dev);
169562306a36Sopenharmony_ci	if (ret)
169662306a36Sopenharmony_ci		goto pm_free;
169762306a36Sopenharmony_ci
169862306a36Sopenharmony_ci	stm32f7_i2c_xfer_msg(i2c_dev, msgs);
169962306a36Sopenharmony_ci
170062306a36Sopenharmony_ci	time_left = wait_for_completion_timeout(&i2c_dev->complete,
170162306a36Sopenharmony_ci						i2c_dev->adap.timeout);
170262306a36Sopenharmony_ci	ret = f7_msg->result;
170362306a36Sopenharmony_ci	if (ret) {
170462306a36Sopenharmony_ci		if (i2c_dev->use_dma)
170562306a36Sopenharmony_ci			dmaengine_synchronize(dma->chan_using);
170662306a36Sopenharmony_ci
170762306a36Sopenharmony_ci		/*
170862306a36Sopenharmony_ci		 * It is possible that some unsent data have already been
170962306a36Sopenharmony_ci		 * written into TXDR. To avoid sending old data in a
171062306a36Sopenharmony_ci		 * further transfer, flush TXDR in case of any error
171162306a36Sopenharmony_ci		 */
171262306a36Sopenharmony_ci		writel_relaxed(STM32F7_I2C_ISR_TXE,
171362306a36Sopenharmony_ci			       i2c_dev->base + STM32F7_I2C_ISR);
171462306a36Sopenharmony_ci		goto pm_free;
171562306a36Sopenharmony_ci	}
171662306a36Sopenharmony_ci
171762306a36Sopenharmony_ci	if (!time_left) {
171862306a36Sopenharmony_ci		dev_dbg(i2c_dev->dev, "Access to slave 0x%x timed out\n",
171962306a36Sopenharmony_ci			i2c_dev->msg->addr);
172062306a36Sopenharmony_ci		if (i2c_dev->use_dma)
172162306a36Sopenharmony_ci			dmaengine_terminate_sync(dma->chan_using);
172262306a36Sopenharmony_ci		stm32f7_i2c_wait_free_bus(i2c_dev);
172362306a36Sopenharmony_ci		ret = -ETIMEDOUT;
172462306a36Sopenharmony_ci	}
172562306a36Sopenharmony_ci
172662306a36Sopenharmony_cipm_free:
172762306a36Sopenharmony_ci	pm_runtime_mark_last_busy(i2c_dev->dev);
172862306a36Sopenharmony_ci	pm_runtime_put_autosuspend(i2c_dev->dev);
172962306a36Sopenharmony_ci
173062306a36Sopenharmony_ci	return (ret < 0) ? ret : num;
173162306a36Sopenharmony_ci}
173262306a36Sopenharmony_ci
173362306a36Sopenharmony_cistatic int stm32f7_i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr,
173462306a36Sopenharmony_ci				  unsigned short flags, char read_write,
173562306a36Sopenharmony_ci				  u8 command, int size,
173662306a36Sopenharmony_ci				  union i2c_smbus_data *data)
173762306a36Sopenharmony_ci{
173862306a36Sopenharmony_ci	struct stm32f7_i2c_dev *i2c_dev = i2c_get_adapdata(adapter);
173962306a36Sopenharmony_ci	struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg;
174062306a36Sopenharmony_ci	struct stm32_i2c_dma *dma = i2c_dev->dma;
174162306a36Sopenharmony_ci	struct device *dev = i2c_dev->dev;
174262306a36Sopenharmony_ci	unsigned long timeout;
174362306a36Sopenharmony_ci	int i, ret;
174462306a36Sopenharmony_ci
174562306a36Sopenharmony_ci	f7_msg->addr = addr;
174662306a36Sopenharmony_ci	f7_msg->size = size;
174762306a36Sopenharmony_ci	f7_msg->read_write = read_write;
174862306a36Sopenharmony_ci	f7_msg->smbus = true;
174962306a36Sopenharmony_ci
175062306a36Sopenharmony_ci	ret = pm_runtime_resume_and_get(dev);
175162306a36Sopenharmony_ci	if (ret < 0)
175262306a36Sopenharmony_ci		return ret;
175362306a36Sopenharmony_ci
175462306a36Sopenharmony_ci	ret = stm32f7_i2c_wait_free_bus(i2c_dev);
175562306a36Sopenharmony_ci	if (ret)
175662306a36Sopenharmony_ci		goto pm_free;
175762306a36Sopenharmony_ci
175862306a36Sopenharmony_ci	ret = stm32f7_i2c_smbus_xfer_msg(i2c_dev, flags, command, data);
175962306a36Sopenharmony_ci	if (ret)
176062306a36Sopenharmony_ci		goto pm_free;
176162306a36Sopenharmony_ci
176262306a36Sopenharmony_ci	timeout = wait_for_completion_timeout(&i2c_dev->complete,
176362306a36Sopenharmony_ci					      i2c_dev->adap.timeout);
176462306a36Sopenharmony_ci	ret = f7_msg->result;
176562306a36Sopenharmony_ci	if (ret) {
176662306a36Sopenharmony_ci		if (i2c_dev->use_dma)
176762306a36Sopenharmony_ci			dmaengine_synchronize(dma->chan_using);
176862306a36Sopenharmony_ci
176962306a36Sopenharmony_ci		/*
177062306a36Sopenharmony_ci		 * It is possible that some unsent data have already been
177162306a36Sopenharmony_ci		 * written into TXDR. To avoid sending old data in a
177262306a36Sopenharmony_ci		 * further transfer, flush TXDR in case of any error
177362306a36Sopenharmony_ci		 */
177462306a36Sopenharmony_ci		writel_relaxed(STM32F7_I2C_ISR_TXE,
177562306a36Sopenharmony_ci			       i2c_dev->base + STM32F7_I2C_ISR);
177662306a36Sopenharmony_ci		goto pm_free;
177762306a36Sopenharmony_ci	}
177862306a36Sopenharmony_ci
177962306a36Sopenharmony_ci	if (!timeout) {
178062306a36Sopenharmony_ci		dev_dbg(dev, "Access to slave 0x%x timed out\n", f7_msg->addr);
178162306a36Sopenharmony_ci		if (i2c_dev->use_dma)
178262306a36Sopenharmony_ci			dmaengine_terminate_sync(dma->chan_using);
178362306a36Sopenharmony_ci		stm32f7_i2c_wait_free_bus(i2c_dev);
178462306a36Sopenharmony_ci		ret = -ETIMEDOUT;
178562306a36Sopenharmony_ci		goto pm_free;
178662306a36Sopenharmony_ci	}
178762306a36Sopenharmony_ci
178862306a36Sopenharmony_ci	/* Check PEC */
178962306a36Sopenharmony_ci	if ((flags & I2C_CLIENT_PEC) && size != I2C_SMBUS_QUICK && read_write) {
179062306a36Sopenharmony_ci		ret = stm32f7_i2c_smbus_check_pec(i2c_dev);
179162306a36Sopenharmony_ci		if (ret)
179262306a36Sopenharmony_ci			goto pm_free;
179362306a36Sopenharmony_ci	}
179462306a36Sopenharmony_ci
179562306a36Sopenharmony_ci	if (read_write && size != I2C_SMBUS_QUICK) {
179662306a36Sopenharmony_ci		switch (size) {
179762306a36Sopenharmony_ci		case I2C_SMBUS_BYTE:
179862306a36Sopenharmony_ci		case I2C_SMBUS_BYTE_DATA:
179962306a36Sopenharmony_ci			data->byte = f7_msg->smbus_buf[0];
180062306a36Sopenharmony_ci		break;
180162306a36Sopenharmony_ci		case I2C_SMBUS_WORD_DATA:
180262306a36Sopenharmony_ci		case I2C_SMBUS_PROC_CALL:
180362306a36Sopenharmony_ci			data->word = f7_msg->smbus_buf[0] |
180462306a36Sopenharmony_ci				(f7_msg->smbus_buf[1] << 8);
180562306a36Sopenharmony_ci		break;
180662306a36Sopenharmony_ci		case I2C_SMBUS_BLOCK_DATA:
180762306a36Sopenharmony_ci		case I2C_SMBUS_BLOCK_PROC_CALL:
180862306a36Sopenharmony_ci		for (i = 0; i <= f7_msg->smbus_buf[0]; i++)
180962306a36Sopenharmony_ci			data->block[i] = f7_msg->smbus_buf[i];
181062306a36Sopenharmony_ci		break;
181162306a36Sopenharmony_ci		default:
181262306a36Sopenharmony_ci			dev_err(dev, "Unsupported smbus transaction\n");
181362306a36Sopenharmony_ci			ret = -EINVAL;
181462306a36Sopenharmony_ci		}
181562306a36Sopenharmony_ci	}
181662306a36Sopenharmony_ci
181762306a36Sopenharmony_cipm_free:
181862306a36Sopenharmony_ci	pm_runtime_mark_last_busy(dev);
181962306a36Sopenharmony_ci	pm_runtime_put_autosuspend(dev);
182062306a36Sopenharmony_ci	return ret;
182162306a36Sopenharmony_ci}
182262306a36Sopenharmony_ci
182362306a36Sopenharmony_cistatic void stm32f7_i2c_enable_wakeup(struct stm32f7_i2c_dev *i2c_dev,
182462306a36Sopenharmony_ci				      bool enable)
182562306a36Sopenharmony_ci{
182662306a36Sopenharmony_ci	void __iomem *base = i2c_dev->base;
182762306a36Sopenharmony_ci	u32 mask = STM32F7_I2C_CR1_WUPEN;
182862306a36Sopenharmony_ci
182962306a36Sopenharmony_ci	if (!i2c_dev->wakeup_src)
183062306a36Sopenharmony_ci		return;
183162306a36Sopenharmony_ci
183262306a36Sopenharmony_ci	if (enable) {
183362306a36Sopenharmony_ci		device_set_wakeup_enable(i2c_dev->dev, true);
183462306a36Sopenharmony_ci		stm32f7_i2c_set_bits(base + STM32F7_I2C_CR1, mask);
183562306a36Sopenharmony_ci	} else {
183662306a36Sopenharmony_ci		device_set_wakeup_enable(i2c_dev->dev, false);
183762306a36Sopenharmony_ci		stm32f7_i2c_clr_bits(base + STM32F7_I2C_CR1, mask);
183862306a36Sopenharmony_ci	}
183962306a36Sopenharmony_ci}
184062306a36Sopenharmony_ci
184162306a36Sopenharmony_cistatic int stm32f7_i2c_reg_slave(struct i2c_client *slave)
184262306a36Sopenharmony_ci{
184362306a36Sopenharmony_ci	struct stm32f7_i2c_dev *i2c_dev = i2c_get_adapdata(slave->adapter);
184462306a36Sopenharmony_ci	void __iomem *base = i2c_dev->base;
184562306a36Sopenharmony_ci	struct device *dev = i2c_dev->dev;
184662306a36Sopenharmony_ci	u32 oar1, oar2, mask;
184762306a36Sopenharmony_ci	int id, ret;
184862306a36Sopenharmony_ci
184962306a36Sopenharmony_ci	if (slave->flags & I2C_CLIENT_PEC) {
185062306a36Sopenharmony_ci		dev_err(dev, "SMBus PEC not supported in slave mode\n");
185162306a36Sopenharmony_ci		return -EINVAL;
185262306a36Sopenharmony_ci	}
185362306a36Sopenharmony_ci
185462306a36Sopenharmony_ci	if (stm32f7_i2c_is_slave_busy(i2c_dev)) {
185562306a36Sopenharmony_ci		dev_err(dev, "Too much slave registered\n");
185662306a36Sopenharmony_ci		return -EBUSY;
185762306a36Sopenharmony_ci	}
185862306a36Sopenharmony_ci
185962306a36Sopenharmony_ci	ret = stm32f7_i2c_get_free_slave_id(i2c_dev, slave, &id);
186062306a36Sopenharmony_ci	if (ret)
186162306a36Sopenharmony_ci		return ret;
186262306a36Sopenharmony_ci
186362306a36Sopenharmony_ci	ret = pm_runtime_resume_and_get(dev);
186462306a36Sopenharmony_ci	if (ret < 0)
186562306a36Sopenharmony_ci		return ret;
186662306a36Sopenharmony_ci
186762306a36Sopenharmony_ci	if (!stm32f7_i2c_is_slave_registered(i2c_dev))
186862306a36Sopenharmony_ci		stm32f7_i2c_enable_wakeup(i2c_dev, true);
186962306a36Sopenharmony_ci
187062306a36Sopenharmony_ci	switch (id) {
187162306a36Sopenharmony_ci	case 0:
187262306a36Sopenharmony_ci		/* Slave SMBus Host */
187362306a36Sopenharmony_ci		i2c_dev->slave[id] = slave;
187462306a36Sopenharmony_ci		break;
187562306a36Sopenharmony_ci
187662306a36Sopenharmony_ci	case 1:
187762306a36Sopenharmony_ci		/* Configure Own Address 1 */
187862306a36Sopenharmony_ci		oar1 = readl_relaxed(i2c_dev->base + STM32F7_I2C_OAR1);
187962306a36Sopenharmony_ci		oar1 &= ~STM32F7_I2C_OAR1_MASK;
188062306a36Sopenharmony_ci		if (slave->flags & I2C_CLIENT_TEN) {
188162306a36Sopenharmony_ci			oar1 |= STM32F7_I2C_OAR1_OA1_10(slave->addr);
188262306a36Sopenharmony_ci			oar1 |= STM32F7_I2C_OAR1_OA1MODE;
188362306a36Sopenharmony_ci		} else {
188462306a36Sopenharmony_ci			oar1 |= STM32F7_I2C_OAR1_OA1_7(slave->addr);
188562306a36Sopenharmony_ci		}
188662306a36Sopenharmony_ci		oar1 |= STM32F7_I2C_OAR1_OA1EN;
188762306a36Sopenharmony_ci		i2c_dev->slave[id] = slave;
188862306a36Sopenharmony_ci		writel_relaxed(oar1, i2c_dev->base + STM32F7_I2C_OAR1);
188962306a36Sopenharmony_ci		break;
189062306a36Sopenharmony_ci
189162306a36Sopenharmony_ci	case 2:
189262306a36Sopenharmony_ci		/* Configure Own Address 2 */
189362306a36Sopenharmony_ci		oar2 = readl_relaxed(i2c_dev->base + STM32F7_I2C_OAR2);
189462306a36Sopenharmony_ci		oar2 &= ~STM32F7_I2C_OAR2_MASK;
189562306a36Sopenharmony_ci		if (slave->flags & I2C_CLIENT_TEN) {
189662306a36Sopenharmony_ci			ret = -EOPNOTSUPP;
189762306a36Sopenharmony_ci			goto pm_free;
189862306a36Sopenharmony_ci		}
189962306a36Sopenharmony_ci
190062306a36Sopenharmony_ci		oar2 |= STM32F7_I2C_OAR2_OA2_7(slave->addr);
190162306a36Sopenharmony_ci		oar2 |= STM32F7_I2C_OAR2_OA2EN;
190262306a36Sopenharmony_ci		i2c_dev->slave[id] = slave;
190362306a36Sopenharmony_ci		writel_relaxed(oar2, i2c_dev->base + STM32F7_I2C_OAR2);
190462306a36Sopenharmony_ci		break;
190562306a36Sopenharmony_ci
190662306a36Sopenharmony_ci	default:
190762306a36Sopenharmony_ci		dev_err(dev, "I2C slave id not supported\n");
190862306a36Sopenharmony_ci		ret = -ENODEV;
190962306a36Sopenharmony_ci		goto pm_free;
191062306a36Sopenharmony_ci	}
191162306a36Sopenharmony_ci
191262306a36Sopenharmony_ci	/* Enable ACK */
191362306a36Sopenharmony_ci	stm32f7_i2c_clr_bits(base + STM32F7_I2C_CR2, STM32F7_I2C_CR2_NACK);
191462306a36Sopenharmony_ci
191562306a36Sopenharmony_ci	/* Enable Address match interrupt, error interrupt and enable I2C  */
191662306a36Sopenharmony_ci	mask = STM32F7_I2C_CR1_ADDRIE | STM32F7_I2C_CR1_ERRIE |
191762306a36Sopenharmony_ci		STM32F7_I2C_CR1_PE;
191862306a36Sopenharmony_ci	stm32f7_i2c_set_bits(base + STM32F7_I2C_CR1, mask);
191962306a36Sopenharmony_ci
192062306a36Sopenharmony_ci	ret = 0;
192162306a36Sopenharmony_cipm_free:
192262306a36Sopenharmony_ci	if (!stm32f7_i2c_is_slave_registered(i2c_dev))
192362306a36Sopenharmony_ci		stm32f7_i2c_enable_wakeup(i2c_dev, false);
192462306a36Sopenharmony_ci
192562306a36Sopenharmony_ci	pm_runtime_mark_last_busy(dev);
192662306a36Sopenharmony_ci	pm_runtime_put_autosuspend(dev);
192762306a36Sopenharmony_ci
192862306a36Sopenharmony_ci	return ret;
192962306a36Sopenharmony_ci}
193062306a36Sopenharmony_ci
193162306a36Sopenharmony_cistatic int stm32f7_i2c_unreg_slave(struct i2c_client *slave)
193262306a36Sopenharmony_ci{
193362306a36Sopenharmony_ci	struct stm32f7_i2c_dev *i2c_dev = i2c_get_adapdata(slave->adapter);
193462306a36Sopenharmony_ci	void __iomem *base = i2c_dev->base;
193562306a36Sopenharmony_ci	u32 mask;
193662306a36Sopenharmony_ci	int id, ret;
193762306a36Sopenharmony_ci
193862306a36Sopenharmony_ci	ret = stm32f7_i2c_get_slave_id(i2c_dev, slave, &id);
193962306a36Sopenharmony_ci	if (ret)
194062306a36Sopenharmony_ci		return ret;
194162306a36Sopenharmony_ci
194262306a36Sopenharmony_ci	WARN_ON(!i2c_dev->slave[id]);
194362306a36Sopenharmony_ci
194462306a36Sopenharmony_ci	ret = pm_runtime_resume_and_get(i2c_dev->dev);
194562306a36Sopenharmony_ci	if (ret < 0)
194662306a36Sopenharmony_ci		return ret;
194762306a36Sopenharmony_ci
194862306a36Sopenharmony_ci	if (id == 1) {
194962306a36Sopenharmony_ci		mask = STM32F7_I2C_OAR1_OA1EN;
195062306a36Sopenharmony_ci		stm32f7_i2c_clr_bits(base + STM32F7_I2C_OAR1, mask);
195162306a36Sopenharmony_ci	} else if (id == 2) {
195262306a36Sopenharmony_ci		mask = STM32F7_I2C_OAR2_OA2EN;
195362306a36Sopenharmony_ci		stm32f7_i2c_clr_bits(base + STM32F7_I2C_OAR2, mask);
195462306a36Sopenharmony_ci	}
195562306a36Sopenharmony_ci
195662306a36Sopenharmony_ci	i2c_dev->slave[id] = NULL;
195762306a36Sopenharmony_ci
195862306a36Sopenharmony_ci	if (!stm32f7_i2c_is_slave_registered(i2c_dev)) {
195962306a36Sopenharmony_ci		stm32f7_i2c_disable_irq(i2c_dev, STM32F7_I2C_ALL_IRQ_MASK);
196062306a36Sopenharmony_ci		stm32f7_i2c_enable_wakeup(i2c_dev, false);
196162306a36Sopenharmony_ci	}
196262306a36Sopenharmony_ci
196362306a36Sopenharmony_ci	pm_runtime_mark_last_busy(i2c_dev->dev);
196462306a36Sopenharmony_ci	pm_runtime_put_autosuspend(i2c_dev->dev);
196562306a36Sopenharmony_ci
196662306a36Sopenharmony_ci	return 0;
196762306a36Sopenharmony_ci}
196862306a36Sopenharmony_ci
196962306a36Sopenharmony_cistatic int stm32f7_i2c_write_fm_plus_bits(struct stm32f7_i2c_dev *i2c_dev,
197062306a36Sopenharmony_ci					  bool enable)
197162306a36Sopenharmony_ci{
197262306a36Sopenharmony_ci	int ret;
197362306a36Sopenharmony_ci
197462306a36Sopenharmony_ci	if (i2c_dev->bus_rate <= I2C_MAX_FAST_MODE_FREQ ||
197562306a36Sopenharmony_ci	    IS_ERR_OR_NULL(i2c_dev->regmap))
197662306a36Sopenharmony_ci		/* Optional */
197762306a36Sopenharmony_ci		return 0;
197862306a36Sopenharmony_ci
197962306a36Sopenharmony_ci	if (i2c_dev->fmp_sreg == i2c_dev->fmp_creg)
198062306a36Sopenharmony_ci		ret = regmap_update_bits(i2c_dev->regmap,
198162306a36Sopenharmony_ci					 i2c_dev->fmp_sreg,
198262306a36Sopenharmony_ci					 i2c_dev->fmp_mask,
198362306a36Sopenharmony_ci					 enable ? i2c_dev->fmp_mask : 0);
198462306a36Sopenharmony_ci	else
198562306a36Sopenharmony_ci		ret = regmap_write(i2c_dev->regmap,
198662306a36Sopenharmony_ci				   enable ? i2c_dev->fmp_sreg :
198762306a36Sopenharmony_ci					    i2c_dev->fmp_creg,
198862306a36Sopenharmony_ci				   i2c_dev->fmp_mask);
198962306a36Sopenharmony_ci
199062306a36Sopenharmony_ci	return ret;
199162306a36Sopenharmony_ci}
199262306a36Sopenharmony_ci
199362306a36Sopenharmony_cistatic int stm32f7_i2c_setup_fm_plus_bits(struct platform_device *pdev,
199462306a36Sopenharmony_ci					  struct stm32f7_i2c_dev *i2c_dev)
199562306a36Sopenharmony_ci{
199662306a36Sopenharmony_ci	struct device_node *np = pdev->dev.of_node;
199762306a36Sopenharmony_ci	int ret;
199862306a36Sopenharmony_ci
199962306a36Sopenharmony_ci	i2c_dev->regmap = syscon_regmap_lookup_by_phandle(np, "st,syscfg-fmp");
200062306a36Sopenharmony_ci	if (IS_ERR(i2c_dev->regmap))
200162306a36Sopenharmony_ci		/* Optional */
200262306a36Sopenharmony_ci		return 0;
200362306a36Sopenharmony_ci
200462306a36Sopenharmony_ci	ret = of_property_read_u32_index(np, "st,syscfg-fmp", 1,
200562306a36Sopenharmony_ci					 &i2c_dev->fmp_sreg);
200662306a36Sopenharmony_ci	if (ret)
200762306a36Sopenharmony_ci		return ret;
200862306a36Sopenharmony_ci
200962306a36Sopenharmony_ci	i2c_dev->fmp_creg = i2c_dev->fmp_sreg +
201062306a36Sopenharmony_ci			       i2c_dev->setup.fmp_clr_offset;
201162306a36Sopenharmony_ci
201262306a36Sopenharmony_ci	return of_property_read_u32_index(np, "st,syscfg-fmp", 2,
201362306a36Sopenharmony_ci					  &i2c_dev->fmp_mask);
201462306a36Sopenharmony_ci}
201562306a36Sopenharmony_ci
201662306a36Sopenharmony_cistatic int stm32f7_i2c_enable_smbus_host(struct stm32f7_i2c_dev *i2c_dev)
201762306a36Sopenharmony_ci{
201862306a36Sopenharmony_ci	struct i2c_adapter *adap = &i2c_dev->adap;
201962306a36Sopenharmony_ci	void __iomem *base = i2c_dev->base;
202062306a36Sopenharmony_ci	struct i2c_client *client;
202162306a36Sopenharmony_ci
202262306a36Sopenharmony_ci	client = i2c_new_slave_host_notify_device(adap);
202362306a36Sopenharmony_ci	if (IS_ERR(client))
202462306a36Sopenharmony_ci		return PTR_ERR(client);
202562306a36Sopenharmony_ci
202662306a36Sopenharmony_ci	i2c_dev->host_notify_client = client;
202762306a36Sopenharmony_ci
202862306a36Sopenharmony_ci	/* Enable SMBus Host address */
202962306a36Sopenharmony_ci	stm32f7_i2c_set_bits(base + STM32F7_I2C_CR1, STM32F7_I2C_CR1_SMBHEN);
203062306a36Sopenharmony_ci
203162306a36Sopenharmony_ci	return 0;
203262306a36Sopenharmony_ci}
203362306a36Sopenharmony_ci
203462306a36Sopenharmony_cistatic void stm32f7_i2c_disable_smbus_host(struct stm32f7_i2c_dev *i2c_dev)
203562306a36Sopenharmony_ci{
203662306a36Sopenharmony_ci	void __iomem *base = i2c_dev->base;
203762306a36Sopenharmony_ci
203862306a36Sopenharmony_ci	if (i2c_dev->host_notify_client) {
203962306a36Sopenharmony_ci		/* Disable SMBus Host address */
204062306a36Sopenharmony_ci		stm32f7_i2c_clr_bits(base + STM32F7_I2C_CR1,
204162306a36Sopenharmony_ci				     STM32F7_I2C_CR1_SMBHEN);
204262306a36Sopenharmony_ci		i2c_free_slave_host_notify_device(i2c_dev->host_notify_client);
204362306a36Sopenharmony_ci	}
204462306a36Sopenharmony_ci}
204562306a36Sopenharmony_ci
204662306a36Sopenharmony_cistatic int stm32f7_i2c_enable_smbus_alert(struct stm32f7_i2c_dev *i2c_dev)
204762306a36Sopenharmony_ci{
204862306a36Sopenharmony_ci	struct stm32f7_i2c_alert *alert;
204962306a36Sopenharmony_ci	struct i2c_adapter *adap = &i2c_dev->adap;
205062306a36Sopenharmony_ci	struct device *dev = i2c_dev->dev;
205162306a36Sopenharmony_ci	void __iomem *base = i2c_dev->base;
205262306a36Sopenharmony_ci
205362306a36Sopenharmony_ci	alert = devm_kzalloc(dev, sizeof(*alert), GFP_KERNEL);
205462306a36Sopenharmony_ci	if (!alert)
205562306a36Sopenharmony_ci		return -ENOMEM;
205662306a36Sopenharmony_ci
205762306a36Sopenharmony_ci	alert->ara = i2c_new_smbus_alert_device(adap, &alert->setup);
205862306a36Sopenharmony_ci	if (IS_ERR(alert->ara))
205962306a36Sopenharmony_ci		return PTR_ERR(alert->ara);
206062306a36Sopenharmony_ci
206162306a36Sopenharmony_ci	i2c_dev->alert = alert;
206262306a36Sopenharmony_ci
206362306a36Sopenharmony_ci	/* Enable SMBus Alert */
206462306a36Sopenharmony_ci	stm32f7_i2c_set_bits(base + STM32F7_I2C_CR1, STM32F7_I2C_CR1_ALERTEN);
206562306a36Sopenharmony_ci
206662306a36Sopenharmony_ci	return 0;
206762306a36Sopenharmony_ci}
206862306a36Sopenharmony_ci
206962306a36Sopenharmony_cistatic void stm32f7_i2c_disable_smbus_alert(struct stm32f7_i2c_dev *i2c_dev)
207062306a36Sopenharmony_ci{
207162306a36Sopenharmony_ci	struct stm32f7_i2c_alert *alert = i2c_dev->alert;
207262306a36Sopenharmony_ci	void __iomem *base = i2c_dev->base;
207362306a36Sopenharmony_ci
207462306a36Sopenharmony_ci	if (alert) {
207562306a36Sopenharmony_ci		/* Disable SMBus Alert */
207662306a36Sopenharmony_ci		stm32f7_i2c_clr_bits(base + STM32F7_I2C_CR1,
207762306a36Sopenharmony_ci				     STM32F7_I2C_CR1_ALERTEN);
207862306a36Sopenharmony_ci		i2c_unregister_device(alert->ara);
207962306a36Sopenharmony_ci	}
208062306a36Sopenharmony_ci}
208162306a36Sopenharmony_ci
208262306a36Sopenharmony_cistatic u32 stm32f7_i2c_func(struct i2c_adapter *adap)
208362306a36Sopenharmony_ci{
208462306a36Sopenharmony_ci	struct stm32f7_i2c_dev *i2c_dev = i2c_get_adapdata(adap);
208562306a36Sopenharmony_ci
208662306a36Sopenharmony_ci	u32 func = I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR | I2C_FUNC_SLAVE |
208762306a36Sopenharmony_ci		   I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
208862306a36Sopenharmony_ci		   I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
208962306a36Sopenharmony_ci		   I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_BLOCK_PROC_CALL |
209062306a36Sopenharmony_ci		   I2C_FUNC_SMBUS_PROC_CALL | I2C_FUNC_SMBUS_PEC |
209162306a36Sopenharmony_ci		   I2C_FUNC_SMBUS_I2C_BLOCK;
209262306a36Sopenharmony_ci
209362306a36Sopenharmony_ci	if (i2c_dev->smbus_mode)
209462306a36Sopenharmony_ci		func |= I2C_FUNC_SMBUS_HOST_NOTIFY;
209562306a36Sopenharmony_ci
209662306a36Sopenharmony_ci	return func;
209762306a36Sopenharmony_ci}
209862306a36Sopenharmony_ci
209962306a36Sopenharmony_cistatic const struct i2c_algorithm stm32f7_i2c_algo = {
210062306a36Sopenharmony_ci	.master_xfer = stm32f7_i2c_xfer,
210162306a36Sopenharmony_ci	.smbus_xfer = stm32f7_i2c_smbus_xfer,
210262306a36Sopenharmony_ci	.functionality = stm32f7_i2c_func,
210362306a36Sopenharmony_ci	.reg_slave = stm32f7_i2c_reg_slave,
210462306a36Sopenharmony_ci	.unreg_slave = stm32f7_i2c_unreg_slave,
210562306a36Sopenharmony_ci};
210662306a36Sopenharmony_ci
210762306a36Sopenharmony_cistatic int stm32f7_i2c_probe(struct platform_device *pdev)
210862306a36Sopenharmony_ci{
210962306a36Sopenharmony_ci	struct stm32f7_i2c_dev *i2c_dev;
211062306a36Sopenharmony_ci	const struct stm32f7_i2c_setup *setup;
211162306a36Sopenharmony_ci	struct resource *res;
211262306a36Sopenharmony_ci	struct i2c_adapter *adap;
211362306a36Sopenharmony_ci	struct reset_control *rst;
211462306a36Sopenharmony_ci	dma_addr_t phy_addr;
211562306a36Sopenharmony_ci	int irq_error, irq_event, ret;
211662306a36Sopenharmony_ci
211762306a36Sopenharmony_ci	i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL);
211862306a36Sopenharmony_ci	if (!i2c_dev)
211962306a36Sopenharmony_ci		return -ENOMEM;
212062306a36Sopenharmony_ci
212162306a36Sopenharmony_ci	i2c_dev->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
212262306a36Sopenharmony_ci	if (IS_ERR(i2c_dev->base))
212362306a36Sopenharmony_ci		return PTR_ERR(i2c_dev->base);
212462306a36Sopenharmony_ci	phy_addr = (dma_addr_t)res->start;
212562306a36Sopenharmony_ci
212662306a36Sopenharmony_ci	irq_event = platform_get_irq(pdev, 0);
212762306a36Sopenharmony_ci	if (irq_event < 0)
212862306a36Sopenharmony_ci		return irq_event;
212962306a36Sopenharmony_ci
213062306a36Sopenharmony_ci	irq_error = platform_get_irq(pdev, 1);
213162306a36Sopenharmony_ci	if (irq_error < 0)
213262306a36Sopenharmony_ci		return irq_error;
213362306a36Sopenharmony_ci
213462306a36Sopenharmony_ci	i2c_dev->wakeup_src = of_property_read_bool(pdev->dev.of_node,
213562306a36Sopenharmony_ci						    "wakeup-source");
213662306a36Sopenharmony_ci
213762306a36Sopenharmony_ci	i2c_dev->clk = devm_clk_get(&pdev->dev, NULL);
213862306a36Sopenharmony_ci	if (IS_ERR(i2c_dev->clk))
213962306a36Sopenharmony_ci		return dev_err_probe(&pdev->dev, PTR_ERR(i2c_dev->clk),
214062306a36Sopenharmony_ci				     "Failed to get controller clock\n");
214162306a36Sopenharmony_ci
214262306a36Sopenharmony_ci	ret = clk_prepare_enable(i2c_dev->clk);
214362306a36Sopenharmony_ci	if (ret) {
214462306a36Sopenharmony_ci		dev_err(&pdev->dev, "Failed to prepare_enable clock\n");
214562306a36Sopenharmony_ci		return ret;
214662306a36Sopenharmony_ci	}
214762306a36Sopenharmony_ci
214862306a36Sopenharmony_ci	rst = devm_reset_control_get(&pdev->dev, NULL);
214962306a36Sopenharmony_ci	if (IS_ERR(rst)) {
215062306a36Sopenharmony_ci		ret = dev_err_probe(&pdev->dev, PTR_ERR(rst),
215162306a36Sopenharmony_ci				    "Error: Missing reset ctrl\n");
215262306a36Sopenharmony_ci		goto clk_free;
215362306a36Sopenharmony_ci	}
215462306a36Sopenharmony_ci	reset_control_assert(rst);
215562306a36Sopenharmony_ci	udelay(2);
215662306a36Sopenharmony_ci	reset_control_deassert(rst);
215762306a36Sopenharmony_ci
215862306a36Sopenharmony_ci	i2c_dev->dev = &pdev->dev;
215962306a36Sopenharmony_ci
216062306a36Sopenharmony_ci	ret = devm_request_threaded_irq(&pdev->dev, irq_event,
216162306a36Sopenharmony_ci					stm32f7_i2c_isr_event,
216262306a36Sopenharmony_ci					stm32f7_i2c_isr_event_thread,
216362306a36Sopenharmony_ci					IRQF_ONESHOT,
216462306a36Sopenharmony_ci					pdev->name, i2c_dev);
216562306a36Sopenharmony_ci	if (ret) {
216662306a36Sopenharmony_ci		dev_err(&pdev->dev, "Failed to request irq event %i\n",
216762306a36Sopenharmony_ci			irq_event);
216862306a36Sopenharmony_ci		goto clk_free;
216962306a36Sopenharmony_ci	}
217062306a36Sopenharmony_ci
217162306a36Sopenharmony_ci	ret = devm_request_irq(&pdev->dev, irq_error, stm32f7_i2c_isr_error, 0,
217262306a36Sopenharmony_ci			       pdev->name, i2c_dev);
217362306a36Sopenharmony_ci	if (ret) {
217462306a36Sopenharmony_ci		dev_err(&pdev->dev, "Failed to request irq error %i\n",
217562306a36Sopenharmony_ci			irq_error);
217662306a36Sopenharmony_ci		goto clk_free;
217762306a36Sopenharmony_ci	}
217862306a36Sopenharmony_ci
217962306a36Sopenharmony_ci	setup = of_device_get_match_data(&pdev->dev);
218062306a36Sopenharmony_ci	if (!setup) {
218162306a36Sopenharmony_ci		dev_err(&pdev->dev, "Can't get device data\n");
218262306a36Sopenharmony_ci		ret = -ENODEV;
218362306a36Sopenharmony_ci		goto clk_free;
218462306a36Sopenharmony_ci	}
218562306a36Sopenharmony_ci	i2c_dev->setup = *setup;
218662306a36Sopenharmony_ci
218762306a36Sopenharmony_ci	ret = stm32f7_i2c_setup_timing(i2c_dev, &i2c_dev->setup);
218862306a36Sopenharmony_ci	if (ret)
218962306a36Sopenharmony_ci		goto clk_free;
219062306a36Sopenharmony_ci
219162306a36Sopenharmony_ci	/* Setup Fast mode plus if necessary */
219262306a36Sopenharmony_ci	if (i2c_dev->bus_rate > I2C_MAX_FAST_MODE_FREQ) {
219362306a36Sopenharmony_ci		ret = stm32f7_i2c_setup_fm_plus_bits(pdev, i2c_dev);
219462306a36Sopenharmony_ci		if (ret)
219562306a36Sopenharmony_ci			goto clk_free;
219662306a36Sopenharmony_ci		ret = stm32f7_i2c_write_fm_plus_bits(i2c_dev, true);
219762306a36Sopenharmony_ci		if (ret)
219862306a36Sopenharmony_ci			goto clk_free;
219962306a36Sopenharmony_ci	}
220062306a36Sopenharmony_ci
220162306a36Sopenharmony_ci	adap = &i2c_dev->adap;
220262306a36Sopenharmony_ci	i2c_set_adapdata(adap, i2c_dev);
220362306a36Sopenharmony_ci	snprintf(adap->name, sizeof(adap->name), "STM32F7 I2C(%pa)",
220462306a36Sopenharmony_ci		 &res->start);
220562306a36Sopenharmony_ci	adap->owner = THIS_MODULE;
220662306a36Sopenharmony_ci	adap->timeout = 2 * HZ;
220762306a36Sopenharmony_ci	adap->retries = 3;
220862306a36Sopenharmony_ci	adap->algo = &stm32f7_i2c_algo;
220962306a36Sopenharmony_ci	adap->dev.parent = &pdev->dev;
221062306a36Sopenharmony_ci	adap->dev.of_node = pdev->dev.of_node;
221162306a36Sopenharmony_ci
221262306a36Sopenharmony_ci	init_completion(&i2c_dev->complete);
221362306a36Sopenharmony_ci
221462306a36Sopenharmony_ci	/* Init DMA config if supported */
221562306a36Sopenharmony_ci	i2c_dev->dma = stm32_i2c_dma_request(i2c_dev->dev, phy_addr,
221662306a36Sopenharmony_ci					     STM32F7_I2C_TXDR,
221762306a36Sopenharmony_ci					     STM32F7_I2C_RXDR);
221862306a36Sopenharmony_ci	if (IS_ERR(i2c_dev->dma)) {
221962306a36Sopenharmony_ci		ret = PTR_ERR(i2c_dev->dma);
222062306a36Sopenharmony_ci		/* DMA support is optional, only report other errors */
222162306a36Sopenharmony_ci		if (ret != -ENODEV)
222262306a36Sopenharmony_ci			goto fmp_clear;
222362306a36Sopenharmony_ci		dev_dbg(i2c_dev->dev, "No DMA option: fallback using interrupts\n");
222462306a36Sopenharmony_ci		i2c_dev->dma = NULL;
222562306a36Sopenharmony_ci	}
222662306a36Sopenharmony_ci
222762306a36Sopenharmony_ci	if (i2c_dev->wakeup_src) {
222862306a36Sopenharmony_ci		device_set_wakeup_capable(i2c_dev->dev, true);
222962306a36Sopenharmony_ci
223062306a36Sopenharmony_ci		ret = dev_pm_set_wake_irq(i2c_dev->dev, irq_event);
223162306a36Sopenharmony_ci		if (ret) {
223262306a36Sopenharmony_ci			dev_err(i2c_dev->dev, "Failed to set wake up irq\n");
223362306a36Sopenharmony_ci			goto clr_wakeup_capable;
223462306a36Sopenharmony_ci		}
223562306a36Sopenharmony_ci	}
223662306a36Sopenharmony_ci
223762306a36Sopenharmony_ci	platform_set_drvdata(pdev, i2c_dev);
223862306a36Sopenharmony_ci
223962306a36Sopenharmony_ci	pm_runtime_set_autosuspend_delay(i2c_dev->dev,
224062306a36Sopenharmony_ci					 STM32F7_AUTOSUSPEND_DELAY);
224162306a36Sopenharmony_ci	pm_runtime_use_autosuspend(i2c_dev->dev);
224262306a36Sopenharmony_ci	pm_runtime_set_active(i2c_dev->dev);
224362306a36Sopenharmony_ci	pm_runtime_enable(i2c_dev->dev);
224462306a36Sopenharmony_ci
224562306a36Sopenharmony_ci	pm_runtime_get_noresume(&pdev->dev);
224662306a36Sopenharmony_ci
224762306a36Sopenharmony_ci	stm32f7_i2c_hw_config(i2c_dev);
224862306a36Sopenharmony_ci
224962306a36Sopenharmony_ci	i2c_dev->smbus_mode = of_property_read_bool(pdev->dev.of_node, "smbus");
225062306a36Sopenharmony_ci
225162306a36Sopenharmony_ci	ret = i2c_add_adapter(adap);
225262306a36Sopenharmony_ci	if (ret)
225362306a36Sopenharmony_ci		goto pm_disable;
225462306a36Sopenharmony_ci
225562306a36Sopenharmony_ci	if (i2c_dev->smbus_mode) {
225662306a36Sopenharmony_ci		ret = stm32f7_i2c_enable_smbus_host(i2c_dev);
225762306a36Sopenharmony_ci		if (ret) {
225862306a36Sopenharmony_ci			dev_err(i2c_dev->dev,
225962306a36Sopenharmony_ci				"failed to enable SMBus Host-Notify protocol (%d)\n",
226062306a36Sopenharmony_ci				ret);
226162306a36Sopenharmony_ci			goto i2c_adapter_remove;
226262306a36Sopenharmony_ci		}
226362306a36Sopenharmony_ci	}
226462306a36Sopenharmony_ci
226562306a36Sopenharmony_ci	if (of_property_read_bool(pdev->dev.of_node, "smbus-alert")) {
226662306a36Sopenharmony_ci		ret = stm32f7_i2c_enable_smbus_alert(i2c_dev);
226762306a36Sopenharmony_ci		if (ret) {
226862306a36Sopenharmony_ci			dev_err(i2c_dev->dev,
226962306a36Sopenharmony_ci				"failed to enable SMBus alert protocol (%d)\n",
227062306a36Sopenharmony_ci				ret);
227162306a36Sopenharmony_ci			goto i2c_disable_smbus_host;
227262306a36Sopenharmony_ci		}
227362306a36Sopenharmony_ci	}
227462306a36Sopenharmony_ci
227562306a36Sopenharmony_ci	dev_info(i2c_dev->dev, "STM32F7 I2C-%d bus adapter\n", adap->nr);
227662306a36Sopenharmony_ci
227762306a36Sopenharmony_ci	pm_runtime_mark_last_busy(i2c_dev->dev);
227862306a36Sopenharmony_ci	pm_runtime_put_autosuspend(i2c_dev->dev);
227962306a36Sopenharmony_ci
228062306a36Sopenharmony_ci	return 0;
228162306a36Sopenharmony_ci
228262306a36Sopenharmony_cii2c_disable_smbus_host:
228362306a36Sopenharmony_ci	stm32f7_i2c_disable_smbus_host(i2c_dev);
228462306a36Sopenharmony_ci
228562306a36Sopenharmony_cii2c_adapter_remove:
228662306a36Sopenharmony_ci	i2c_del_adapter(adap);
228762306a36Sopenharmony_ci
228862306a36Sopenharmony_cipm_disable:
228962306a36Sopenharmony_ci	pm_runtime_put_noidle(i2c_dev->dev);
229062306a36Sopenharmony_ci	pm_runtime_disable(i2c_dev->dev);
229162306a36Sopenharmony_ci	pm_runtime_set_suspended(i2c_dev->dev);
229262306a36Sopenharmony_ci	pm_runtime_dont_use_autosuspend(i2c_dev->dev);
229362306a36Sopenharmony_ci
229462306a36Sopenharmony_ci	if (i2c_dev->wakeup_src)
229562306a36Sopenharmony_ci		dev_pm_clear_wake_irq(i2c_dev->dev);
229662306a36Sopenharmony_ci
229762306a36Sopenharmony_ciclr_wakeup_capable:
229862306a36Sopenharmony_ci	if (i2c_dev->wakeup_src)
229962306a36Sopenharmony_ci		device_set_wakeup_capable(i2c_dev->dev, false);
230062306a36Sopenharmony_ci
230162306a36Sopenharmony_ci	if (i2c_dev->dma) {
230262306a36Sopenharmony_ci		stm32_i2c_dma_free(i2c_dev->dma);
230362306a36Sopenharmony_ci		i2c_dev->dma = NULL;
230462306a36Sopenharmony_ci	}
230562306a36Sopenharmony_ci
230662306a36Sopenharmony_cifmp_clear:
230762306a36Sopenharmony_ci	stm32f7_i2c_write_fm_plus_bits(i2c_dev, false);
230862306a36Sopenharmony_ci
230962306a36Sopenharmony_ciclk_free:
231062306a36Sopenharmony_ci	clk_disable_unprepare(i2c_dev->clk);
231162306a36Sopenharmony_ci
231262306a36Sopenharmony_ci	return ret;
231362306a36Sopenharmony_ci}
231462306a36Sopenharmony_ci
231562306a36Sopenharmony_cistatic void stm32f7_i2c_remove(struct platform_device *pdev)
231662306a36Sopenharmony_ci{
231762306a36Sopenharmony_ci	struct stm32f7_i2c_dev *i2c_dev = platform_get_drvdata(pdev);
231862306a36Sopenharmony_ci
231962306a36Sopenharmony_ci	stm32f7_i2c_disable_smbus_alert(i2c_dev);
232062306a36Sopenharmony_ci	stm32f7_i2c_disable_smbus_host(i2c_dev);
232162306a36Sopenharmony_ci
232262306a36Sopenharmony_ci	i2c_del_adapter(&i2c_dev->adap);
232362306a36Sopenharmony_ci	pm_runtime_get_sync(i2c_dev->dev);
232462306a36Sopenharmony_ci
232562306a36Sopenharmony_ci	if (i2c_dev->wakeup_src) {
232662306a36Sopenharmony_ci		dev_pm_clear_wake_irq(i2c_dev->dev);
232762306a36Sopenharmony_ci		/*
232862306a36Sopenharmony_ci		 * enforce that wakeup is disabled and that the device
232962306a36Sopenharmony_ci		 * is marked as non wakeup capable
233062306a36Sopenharmony_ci		 */
233162306a36Sopenharmony_ci		device_init_wakeup(i2c_dev->dev, false);
233262306a36Sopenharmony_ci	}
233362306a36Sopenharmony_ci
233462306a36Sopenharmony_ci	pm_runtime_put_noidle(i2c_dev->dev);
233562306a36Sopenharmony_ci	pm_runtime_disable(i2c_dev->dev);
233662306a36Sopenharmony_ci	pm_runtime_set_suspended(i2c_dev->dev);
233762306a36Sopenharmony_ci	pm_runtime_dont_use_autosuspend(i2c_dev->dev);
233862306a36Sopenharmony_ci
233962306a36Sopenharmony_ci	if (i2c_dev->dma) {
234062306a36Sopenharmony_ci		stm32_i2c_dma_free(i2c_dev->dma);
234162306a36Sopenharmony_ci		i2c_dev->dma = NULL;
234262306a36Sopenharmony_ci	}
234362306a36Sopenharmony_ci
234462306a36Sopenharmony_ci	stm32f7_i2c_write_fm_plus_bits(i2c_dev, false);
234562306a36Sopenharmony_ci
234662306a36Sopenharmony_ci	clk_disable_unprepare(i2c_dev->clk);
234762306a36Sopenharmony_ci}
234862306a36Sopenharmony_ci
234962306a36Sopenharmony_cistatic int __maybe_unused stm32f7_i2c_runtime_suspend(struct device *dev)
235062306a36Sopenharmony_ci{
235162306a36Sopenharmony_ci	struct stm32f7_i2c_dev *i2c_dev = dev_get_drvdata(dev);
235262306a36Sopenharmony_ci
235362306a36Sopenharmony_ci	if (!stm32f7_i2c_is_slave_registered(i2c_dev))
235462306a36Sopenharmony_ci		clk_disable_unprepare(i2c_dev->clk);
235562306a36Sopenharmony_ci
235662306a36Sopenharmony_ci	return 0;
235762306a36Sopenharmony_ci}
235862306a36Sopenharmony_ci
235962306a36Sopenharmony_cistatic int __maybe_unused stm32f7_i2c_runtime_resume(struct device *dev)
236062306a36Sopenharmony_ci{
236162306a36Sopenharmony_ci	struct stm32f7_i2c_dev *i2c_dev = dev_get_drvdata(dev);
236262306a36Sopenharmony_ci	int ret;
236362306a36Sopenharmony_ci
236462306a36Sopenharmony_ci	if (!stm32f7_i2c_is_slave_registered(i2c_dev)) {
236562306a36Sopenharmony_ci		ret = clk_prepare_enable(i2c_dev->clk);
236662306a36Sopenharmony_ci		if (ret) {
236762306a36Sopenharmony_ci			dev_err(dev, "failed to prepare_enable clock\n");
236862306a36Sopenharmony_ci			return ret;
236962306a36Sopenharmony_ci		}
237062306a36Sopenharmony_ci	}
237162306a36Sopenharmony_ci
237262306a36Sopenharmony_ci	return 0;
237362306a36Sopenharmony_ci}
237462306a36Sopenharmony_ci
237562306a36Sopenharmony_cistatic int __maybe_unused stm32f7_i2c_regs_backup(struct stm32f7_i2c_dev *i2c_dev)
237662306a36Sopenharmony_ci{
237762306a36Sopenharmony_ci	int ret;
237862306a36Sopenharmony_ci	struct stm32f7_i2c_regs *backup_regs = &i2c_dev->backup_regs;
237962306a36Sopenharmony_ci
238062306a36Sopenharmony_ci	ret = pm_runtime_resume_and_get(i2c_dev->dev);
238162306a36Sopenharmony_ci	if (ret < 0)
238262306a36Sopenharmony_ci		return ret;
238362306a36Sopenharmony_ci
238462306a36Sopenharmony_ci	backup_regs->cr1 = readl_relaxed(i2c_dev->base + STM32F7_I2C_CR1);
238562306a36Sopenharmony_ci	backup_regs->cr2 = readl_relaxed(i2c_dev->base + STM32F7_I2C_CR2);
238662306a36Sopenharmony_ci	backup_regs->oar1 = readl_relaxed(i2c_dev->base + STM32F7_I2C_OAR1);
238762306a36Sopenharmony_ci	backup_regs->oar2 = readl_relaxed(i2c_dev->base + STM32F7_I2C_OAR2);
238862306a36Sopenharmony_ci	backup_regs->tmgr = readl_relaxed(i2c_dev->base + STM32F7_I2C_TIMINGR);
238962306a36Sopenharmony_ci	stm32f7_i2c_write_fm_plus_bits(i2c_dev, false);
239062306a36Sopenharmony_ci
239162306a36Sopenharmony_ci	pm_runtime_put_sync(i2c_dev->dev);
239262306a36Sopenharmony_ci
239362306a36Sopenharmony_ci	return ret;
239462306a36Sopenharmony_ci}
239562306a36Sopenharmony_ci
239662306a36Sopenharmony_cistatic int __maybe_unused stm32f7_i2c_regs_restore(struct stm32f7_i2c_dev *i2c_dev)
239762306a36Sopenharmony_ci{
239862306a36Sopenharmony_ci	u32 cr1;
239962306a36Sopenharmony_ci	int ret;
240062306a36Sopenharmony_ci	struct stm32f7_i2c_regs *backup_regs = &i2c_dev->backup_regs;
240162306a36Sopenharmony_ci
240262306a36Sopenharmony_ci	ret = pm_runtime_resume_and_get(i2c_dev->dev);
240362306a36Sopenharmony_ci	if (ret < 0)
240462306a36Sopenharmony_ci		return ret;
240562306a36Sopenharmony_ci
240662306a36Sopenharmony_ci	cr1 = readl_relaxed(i2c_dev->base + STM32F7_I2C_CR1);
240762306a36Sopenharmony_ci	if (cr1 & STM32F7_I2C_CR1_PE)
240862306a36Sopenharmony_ci		stm32f7_i2c_clr_bits(i2c_dev->base + STM32F7_I2C_CR1,
240962306a36Sopenharmony_ci				     STM32F7_I2C_CR1_PE);
241062306a36Sopenharmony_ci
241162306a36Sopenharmony_ci	writel_relaxed(backup_regs->tmgr, i2c_dev->base + STM32F7_I2C_TIMINGR);
241262306a36Sopenharmony_ci	writel_relaxed(backup_regs->cr1 & ~STM32F7_I2C_CR1_PE,
241362306a36Sopenharmony_ci		       i2c_dev->base + STM32F7_I2C_CR1);
241462306a36Sopenharmony_ci	if (backup_regs->cr1 & STM32F7_I2C_CR1_PE)
241562306a36Sopenharmony_ci		stm32f7_i2c_set_bits(i2c_dev->base + STM32F7_I2C_CR1,
241662306a36Sopenharmony_ci				     STM32F7_I2C_CR1_PE);
241762306a36Sopenharmony_ci	writel_relaxed(backup_regs->cr2, i2c_dev->base + STM32F7_I2C_CR2);
241862306a36Sopenharmony_ci	writel_relaxed(backup_regs->oar1, i2c_dev->base + STM32F7_I2C_OAR1);
241962306a36Sopenharmony_ci	writel_relaxed(backup_regs->oar2, i2c_dev->base + STM32F7_I2C_OAR2);
242062306a36Sopenharmony_ci	stm32f7_i2c_write_fm_plus_bits(i2c_dev, true);
242162306a36Sopenharmony_ci
242262306a36Sopenharmony_ci	pm_runtime_put_sync(i2c_dev->dev);
242362306a36Sopenharmony_ci
242462306a36Sopenharmony_ci	return ret;
242562306a36Sopenharmony_ci}
242662306a36Sopenharmony_ci
242762306a36Sopenharmony_cistatic int __maybe_unused stm32f7_i2c_suspend(struct device *dev)
242862306a36Sopenharmony_ci{
242962306a36Sopenharmony_ci	struct stm32f7_i2c_dev *i2c_dev = dev_get_drvdata(dev);
243062306a36Sopenharmony_ci	int ret;
243162306a36Sopenharmony_ci
243262306a36Sopenharmony_ci	i2c_mark_adapter_suspended(&i2c_dev->adap);
243362306a36Sopenharmony_ci
243462306a36Sopenharmony_ci	if (!device_may_wakeup(dev) && !device_wakeup_path(dev)) {
243562306a36Sopenharmony_ci		ret = stm32f7_i2c_regs_backup(i2c_dev);
243662306a36Sopenharmony_ci		if (ret < 0) {
243762306a36Sopenharmony_ci			i2c_mark_adapter_resumed(&i2c_dev->adap);
243862306a36Sopenharmony_ci			return ret;
243962306a36Sopenharmony_ci		}
244062306a36Sopenharmony_ci
244162306a36Sopenharmony_ci		pinctrl_pm_select_sleep_state(dev);
244262306a36Sopenharmony_ci		pm_runtime_force_suspend(dev);
244362306a36Sopenharmony_ci	}
244462306a36Sopenharmony_ci
244562306a36Sopenharmony_ci	return 0;
244662306a36Sopenharmony_ci}
244762306a36Sopenharmony_ci
244862306a36Sopenharmony_cistatic int __maybe_unused stm32f7_i2c_resume(struct device *dev)
244962306a36Sopenharmony_ci{
245062306a36Sopenharmony_ci	struct stm32f7_i2c_dev *i2c_dev = dev_get_drvdata(dev);
245162306a36Sopenharmony_ci	int ret;
245262306a36Sopenharmony_ci
245362306a36Sopenharmony_ci	if (!device_may_wakeup(dev) && !device_wakeup_path(dev)) {
245462306a36Sopenharmony_ci		ret = pm_runtime_force_resume(dev);
245562306a36Sopenharmony_ci		if (ret < 0)
245662306a36Sopenharmony_ci			return ret;
245762306a36Sopenharmony_ci		pinctrl_pm_select_default_state(dev);
245862306a36Sopenharmony_ci
245962306a36Sopenharmony_ci		ret = stm32f7_i2c_regs_restore(i2c_dev);
246062306a36Sopenharmony_ci		if (ret < 0)
246162306a36Sopenharmony_ci			return ret;
246262306a36Sopenharmony_ci	}
246362306a36Sopenharmony_ci
246462306a36Sopenharmony_ci	i2c_mark_adapter_resumed(&i2c_dev->adap);
246562306a36Sopenharmony_ci
246662306a36Sopenharmony_ci	return 0;
246762306a36Sopenharmony_ci}
246862306a36Sopenharmony_ci
246962306a36Sopenharmony_cistatic const struct dev_pm_ops stm32f7_i2c_pm_ops = {
247062306a36Sopenharmony_ci	SET_RUNTIME_PM_OPS(stm32f7_i2c_runtime_suspend,
247162306a36Sopenharmony_ci			   stm32f7_i2c_runtime_resume, NULL)
247262306a36Sopenharmony_ci	SET_SYSTEM_SLEEP_PM_OPS(stm32f7_i2c_suspend, stm32f7_i2c_resume)
247362306a36Sopenharmony_ci};
247462306a36Sopenharmony_ci
247562306a36Sopenharmony_cistatic const struct of_device_id stm32f7_i2c_match[] = {
247662306a36Sopenharmony_ci	{ .compatible = "st,stm32f7-i2c", .data = &stm32f7_setup},
247762306a36Sopenharmony_ci	{ .compatible = "st,stm32mp15-i2c", .data = &stm32mp15_setup},
247862306a36Sopenharmony_ci	{ .compatible = "st,stm32mp13-i2c", .data = &stm32mp13_setup},
247962306a36Sopenharmony_ci	{},
248062306a36Sopenharmony_ci};
248162306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, stm32f7_i2c_match);
248262306a36Sopenharmony_ci
248362306a36Sopenharmony_cistatic struct platform_driver stm32f7_i2c_driver = {
248462306a36Sopenharmony_ci	.driver = {
248562306a36Sopenharmony_ci		.name = "stm32f7-i2c",
248662306a36Sopenharmony_ci		.of_match_table = stm32f7_i2c_match,
248762306a36Sopenharmony_ci		.pm = &stm32f7_i2c_pm_ops,
248862306a36Sopenharmony_ci	},
248962306a36Sopenharmony_ci	.probe = stm32f7_i2c_probe,
249062306a36Sopenharmony_ci	.remove_new = stm32f7_i2c_remove,
249162306a36Sopenharmony_ci};
249262306a36Sopenharmony_ci
249362306a36Sopenharmony_cimodule_platform_driver(stm32f7_i2c_driver);
249462306a36Sopenharmony_ci
249562306a36Sopenharmony_ciMODULE_AUTHOR("M'boumba Cedric Madianga <cedric.madianga@gmail.com>");
249662306a36Sopenharmony_ciMODULE_DESCRIPTION("STMicroelectronics STM32F7 I2C driver");
249762306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
2498