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