2017-11-30 09:43:57 +01:00
// SPDX-License-Identifier: GPL-2.0
2017-09-14 16:28:37 +02:00
/*
* Driver for STMicroelectronics STM32F7 I2C controller
*
* This I2C controller is described in the STM32F75xxx and STM32F74xxx Soc
* reference manual .
* Please see below a link to the documentation :
* http : //www.st.com/resource/en/reference_manual/dm00124865.pdf
*
* Copyright ( C ) M ' boumba Cedric Madianga 2017
2017-11-30 09:43:57 +01:00
* Copyright ( C ) STMicroelectronics 2017
2017-09-14 16:28:37 +02:00
* Author : M ' boumba Cedric Madianga < cedric . madianga @ gmail . com >
*
* This driver is based on i2c - stm32f4 . c
*
*/
# include <linux/clk.h>
# include <linux/delay.h>
# include <linux/err.h>
# include <linux/i2c.h>
2020-08-03 07:17:56 +02:00
# include <linux/i2c-smbus.h>
2017-09-14 16:28:37 +02:00
# include <linux/interrupt.h>
# include <linux/io.h>
# include <linux/iopoll.h>
2018-11-19 12:03:32 +01:00
# include <linux/mfd/syscon.h>
2017-09-14 16:28:37 +02:00
# include <linux/module.h>
# include <linux/of.h>
# include <linux/of_address.h>
# include <linux/of_platform.h>
# include <linux/platform_device.h>
2018-11-27 15:35:31 +01:00
# include <linux/pinctrl/consumer.h>
# include <linux/pm_runtime.h>
2020-02-03 18:52:08 +01:00
# include <linux/pm_wakeirq.h>
2018-11-19 12:03:32 +01:00
# include <linux/regmap.h>
2017-09-14 16:28:37 +02:00
# include <linux/reset.h>
# include <linux/slab.h>
# include "i2c-stm32.h"
/* STM32F7 I2C registers */
# define STM32F7_I2C_CR1 0x00
# define STM32F7_I2C_CR2 0x04
2018-04-11 15:24:54 +02:00
# define STM32F7_I2C_OAR1 0x08
# define STM32F7_I2C_OAR2 0x0C
2018-04-11 15:24:55 +02:00
# define STM32F7_I2C_PECR 0x20
2017-09-14 16:28:37 +02:00
# define STM32F7_I2C_TIMINGR 0x10
# define STM32F7_I2C_ISR 0x18
# define STM32F7_I2C_ICR 0x1C
# define STM32F7_I2C_RXDR 0x24
# define STM32F7_I2C_TXDR 0x28
/* STM32F7 I2C control 1 */
2018-04-11 15:24:55 +02:00
# define STM32F7_I2C_CR1_PECEN BIT(23)
2021-05-05 15:14:39 +02:00
# define STM32F7_I2C_CR1_ALERTEN BIT(22)
2020-08-03 07:17:56 +02:00
# define STM32F7_I2C_CR1_SMBHEN BIT(20)
2020-02-03 18:52:08 +01:00
# define STM32F7_I2C_CR1_WUPEN BIT(18)
2018-04-11 15:24:54 +02:00
# define STM32F7_I2C_CR1_SBC BIT(16)
2018-04-11 15:24:57 +02:00
# define STM32F7_I2C_CR1_RXDMAEN BIT(15)
# define STM32F7_I2C_CR1_TXDMAEN BIT(14)
2017-09-14 16:28:37 +02:00
# define STM32F7_I2C_CR1_ANFOFF BIT(12)
2021-02-05 09:51:40 +01:00
# define STM32F7_I2C_CR1_DNF_MASK GENMASK(11, 8)
# define STM32F7_I2C_CR1_DNF(n) (((n) & 0xf) << 8)
2017-09-14 16:28:37 +02:00
# define STM32F7_I2C_CR1_ERRIE BIT(7)
# define STM32F7_I2C_CR1_TCIE BIT(6)
# define STM32F7_I2C_CR1_STOPIE BIT(5)
# define STM32F7_I2C_CR1_NACKIE BIT(4)
# define STM32F7_I2C_CR1_ADDRIE BIT(3)
# define STM32F7_I2C_CR1_RXIE BIT(2)
# define STM32F7_I2C_CR1_TXIE BIT(1)
# define STM32F7_I2C_CR1_PE BIT(0)
# define STM32F7_I2C_ALL_IRQ_MASK (STM32F7_I2C_CR1_ERRIE \
| STM32F7_I2C_CR1_TCIE \
| STM32F7_I2C_CR1_STOPIE \
| STM32F7_I2C_CR1_NACKIE \
| STM32F7_I2C_CR1_RXIE \
| STM32F7_I2C_CR1_TXIE )
2018-04-11 15:24:54 +02:00
# define STM32F7_I2C_XFER_IRQ_MASK (STM32F7_I2C_CR1_TCIE \
| STM32F7_I2C_CR1_STOPIE \
| STM32F7_I2C_CR1_NACKIE \
| STM32F7_I2C_CR1_RXIE \
| STM32F7_I2C_CR1_TXIE )
2017-09-14 16:28:37 +02:00
/* STM32F7 I2C control 2 */
2018-04-11 15:24:55 +02:00
# define STM32F7_I2C_CR2_PECBYTE BIT(26)
2017-09-14 16:28:37 +02:00
# define STM32F7_I2C_CR2_RELOAD BIT(24)
# define STM32F7_I2C_CR2_NBYTES_MASK GENMASK(23, 16)
# define STM32F7_I2C_CR2_NBYTES(n) (((n) & 0xff) << 16)
# define STM32F7_I2C_CR2_NACK BIT(15)
# define STM32F7_I2C_CR2_STOP BIT(14)
# define STM32F7_I2C_CR2_START BIT(13)
2018-04-11 15:24:53 +02:00
# define STM32F7_I2C_CR2_HEAD10R BIT(12)
# define STM32F7_I2C_CR2_ADD10 BIT(11)
2017-09-14 16:28:37 +02:00
# define STM32F7_I2C_CR2_RD_WRN BIT(10)
2018-04-11 15:24:53 +02:00
# define STM32F7_I2C_CR2_SADD10_MASK GENMASK(9, 0)
# define STM32F7_I2C_CR2_SADD10(n) (((n) & \
STM32F7_I2C_CR2_SADD10_MASK ) )
2017-09-14 16:28:37 +02:00
# define STM32F7_I2C_CR2_SADD7_MASK GENMASK(7, 1)
# define STM32F7_I2C_CR2_SADD7(n) (((n) & 0x7f) << 1)
2018-04-11 15:24:54 +02:00
/* STM32F7 I2C Own Address 1 */
# define STM32F7_I2C_OAR1_OA1EN BIT(15)
# define STM32F7_I2C_OAR1_OA1MODE BIT(10)
# define STM32F7_I2C_OAR1_OA1_10_MASK GENMASK(9, 0)
# define STM32F7_I2C_OAR1_OA1_10(n) (((n) & \
STM32F7_I2C_OAR1_OA1_10_MASK ) )
# define STM32F7_I2C_OAR1_OA1_7_MASK GENMASK(7, 1)
# define STM32F7_I2C_OAR1_OA1_7(n) (((n) & 0x7f) << 1)
# define STM32F7_I2C_OAR1_MASK (STM32F7_I2C_OAR1_OA1_7_MASK \
| STM32F7_I2C_OAR1_OA1_10_MASK \
| STM32F7_I2C_OAR1_OA1EN \
| STM32F7_I2C_OAR1_OA1MODE )
/* STM32F7 I2C Own Address 2 */
# define STM32F7_I2C_OAR2_OA2EN BIT(15)
# define STM32F7_I2C_OAR2_OA2MSK_MASK GENMASK(10, 8)
# define STM32F7_I2C_OAR2_OA2MSK(n) (((n) & 0x7) << 8)
# define STM32F7_I2C_OAR2_OA2_7_MASK GENMASK(7, 1)
# define STM32F7_I2C_OAR2_OA2_7(n) (((n) & 0x7f) << 1)
# define STM32F7_I2C_OAR2_MASK (STM32F7_I2C_OAR2_OA2MSK_MASK \
| STM32F7_I2C_OAR2_OA2_7_MASK \
| STM32F7_I2C_OAR2_OA2EN )
2017-09-14 16:28:37 +02:00
/* STM32F7 I2C Interrupt Status */
2018-04-11 15:24:54 +02:00
# define STM32F7_I2C_ISR_ADDCODE_MASK GENMASK(23, 17)
# define STM32F7_I2C_ISR_ADDCODE_GET(n) \
( ( ( n ) & STM32F7_I2C_ISR_ADDCODE_MASK ) > > 17 )
# define STM32F7_I2C_ISR_DIR BIT(16)
2017-09-14 16:28:37 +02:00
# define STM32F7_I2C_ISR_BUSY BIT(15)
2021-05-05 15:14:39 +02:00
# define STM32F7_I2C_ISR_ALERT BIT(13)
2018-04-11 15:24:55 +02:00
# define STM32F7_I2C_ISR_PECERR BIT(11)
2017-09-14 16:28:37 +02:00
# define STM32F7_I2C_ISR_ARLO BIT(9)
# define STM32F7_I2C_ISR_BERR BIT(8)
# define STM32F7_I2C_ISR_TCR BIT(7)
# define STM32F7_I2C_ISR_TC BIT(6)
# define STM32F7_I2C_ISR_STOPF BIT(5)
# define STM32F7_I2C_ISR_NACKF BIT(4)
2018-04-11 15:24:54 +02:00
# define STM32F7_I2C_ISR_ADDR BIT(3)
2017-09-14 16:28:37 +02:00
# define STM32F7_I2C_ISR_RXNE BIT(2)
# define STM32F7_I2C_ISR_TXIS BIT(1)
2018-04-11 15:24:54 +02:00
# define STM32F7_I2C_ISR_TXE BIT(0)
2017-09-14 16:28:37 +02:00
/* STM32F7 I2C Interrupt Clear */
2021-05-05 15:14:39 +02:00
# define STM32F7_I2C_ICR_ALERTCF BIT(13)
2018-04-11 15:24:55 +02:00
# define STM32F7_I2C_ICR_PECCF BIT(11)
2017-09-14 16:28:37 +02:00
# define STM32F7_I2C_ICR_ARLOCF BIT(9)
# define STM32F7_I2C_ICR_BERRCF BIT(8)
# define STM32F7_I2C_ICR_STOPCF BIT(5)
# define STM32F7_I2C_ICR_NACKCF BIT(4)
2018-04-11 15:24:54 +02:00
# define STM32F7_I2C_ICR_ADDRCF BIT(3)
2017-09-14 16:28:37 +02:00
/* STM32F7 I2C Timing */
# define STM32F7_I2C_TIMINGR_PRESC(n) (((n) & 0xf) << 28)
# define STM32F7_I2C_TIMINGR_SCLDEL(n) (((n) & 0xf) << 20)
# define STM32F7_I2C_TIMINGR_SDADEL(n) (((n) & 0xf) << 16)
# define STM32F7_I2C_TIMINGR_SCLH(n) (((n) & 0xff) << 8)
# define STM32F7_I2C_TIMINGR_SCLL(n) ((n) & 0xff)
# define STM32F7_I2C_MAX_LEN 0xff
2018-04-11 15:24:57 +02:00
# define STM32F7_I2C_DMA_LEN_MIN 0x16
2020-09-15 11:11:41 +02:00
enum {
STM32F7_SLAVE_HOSTNOTIFY ,
STM32F7_SLAVE_7_10_BITS_ADDR ,
STM32F7_SLAVE_7_BITS_ADDR ,
STM32F7_I2C_MAX_SLAVE
} ;
2017-09-14 16:28:37 +02:00
# define STM32F7_I2C_DNF_DEFAULT 0
2021-02-05 09:51:40 +01:00
# define STM32F7_I2C_DNF_MAX 15
2017-09-14 16:28:37 +02:00
# define STM32F7_I2C_ANALOG_FILTER_DELAY_MIN 50 /* ns */
# define STM32F7_I2C_ANALOG_FILTER_DELAY_MAX 260 /* ns */
# define STM32F7_I2C_RISE_TIME_DEFAULT 25 /* ns */
# define STM32F7_I2C_FALL_TIME_DEFAULT 10 /* ns */
# define STM32F7_PRESC_MAX BIT(4)
# define STM32F7_SCLDEL_MAX BIT(4)
# define STM32F7_SDADEL_MAX BIT(4)
# define STM32F7_SCLH_MAX BIT(8)
# define STM32F7_SCLL_MAX BIT(8)
2018-11-27 15:35:31 +01:00
# define STM32F7_AUTOSUSPEND_DELAY (HZ / 100)
2020-01-06 14:28:32 +01:00
/**
* struct stm32f7_i2c_regs - i2c f7 registers backup
* @ cr1 : Control register 1
* @ cr2 : Control register 2
* @ oar1 : Own address 1 register
* @ oar2 : Own address 2 register
* @ tmgr : Timing register
*/
struct stm32f7_i2c_regs {
u32 cr1 ;
u32 cr2 ;
u32 oar1 ;
u32 oar2 ;
u32 tmgr ;
} ;
2017-09-14 16:28:37 +02:00
/**
* struct stm32f7_i2c_spec - private i2c specification timing
* @ rate : I2C bus speed ( Hz )
* @ fall_max : Max fall time of both SDA and SCL signals ( ns )
* @ rise_max : Max rise time of both SDA and SCL signals ( ns )
* @ hddat_min : Min data hold time ( ns )
* @ vddat_max : Max data valid time ( ns )
* @ sudat_min : Min data setup time ( ns )
* @ l_min : Min low period of the SCL clock ( ns )
* @ h_min : Min high period of the SCL clock ( ns )
*/
struct stm32f7_i2c_spec {
u32 rate ;
u32 fall_max ;
u32 rise_max ;
u32 hddat_min ;
u32 vddat_max ;
u32 sudat_min ;
u32 l_min ;
u32 h_min ;
} ;
/**
* struct stm32f7_i2c_setup - private I2C timing setup parameters
* @ speed_freq : I2C speed frequency ( Hz )
* @ clock_src : I2C clock source frequency ( Hz )
* @ rise_time : Rise time ( ns )
* @ fall_time : Fall time ( ns )
2020-03-02 12:33:16 +01:00
* @ fmp_clr_offset : Fast Mode Plus clear register offset from set register
2017-09-14 16:28:37 +02:00
*/
struct stm32f7_i2c_setup {
u32 speed_freq ;
u32 clock_src ;
u32 rise_time ;
u32 fall_time ;
2020-03-02 12:33:16 +01:00
u32 fmp_clr_offset ;
2017-09-14 16:28:37 +02:00
} ;
/**
* struct stm32f7_i2c_timings - private I2C output parameters
2018-05-11 10:20:25 +02:00
* @ node : List entry
* @ presc : Prescaler value
2017-09-14 16:28:37 +02:00
* @ scldel : Data setup time
* @ sdadel : Data hold time
* @ sclh : SCL high period ( master mode )
2018-05-11 10:20:25 +02:00
* @ scll : SCL low period ( master mode )
2017-09-14 16:28:37 +02:00
*/
struct stm32f7_i2c_timings {
struct list_head node ;
u8 presc ;
u8 scldel ;
u8 sdadel ;
u8 sclh ;
u8 scll ;
} ;
/**
* struct stm32f7_i2c_msg - client specific data
2018-04-11 15:24:53 +02:00
* @ addr : 8 - bit or 10 - bit slave addr , including r / w bit
2017-09-14 16:28:37 +02:00
* @ count : number of bytes to be transferred
* @ buf : data buffer
* @ result : result of the transfer
* @ stop : last I2C msg to be sent , i . e . STOP to be generated
2018-04-11 15:24:55 +02:00
* @ smbus : boolean to know if the I2C IP is used in SMBus mode
* @ size : type of SMBus protocol
* @ read_write : direction of SMBus protocol
* SMBus block read and SMBus block write - block read process call protocols
2018-05-11 10:20:25 +02:00
* @ smbus_buf : buffer to be used for SMBus protocol transfer . It will
2018-04-11 15:24:55 +02:00
* contain a maximum of 32 bytes of data + byte command + byte count + PEC
* This buffer has to be 32 - bit aligned to be compliant with memory address
* register in DMA mode .
2017-09-14 16:28:37 +02:00
*/
struct stm32f7_i2c_msg {
2018-04-11 15:24:53 +02:00
u16 addr ;
2017-09-14 16:28:37 +02:00
u32 count ;
u8 * buf ;
int result ;
bool stop ;
2018-04-11 15:24:55 +02:00
bool smbus ;
int size ;
char read_write ;
u8 smbus_buf [ I2C_SMBUS_BLOCK_MAX + 3 ] __aligned ( 4 ) ;
2017-09-14 16:28:37 +02:00
} ;
2021-05-05 15:14:39 +02:00
/**
* struct stm32f7_i2c_alert - SMBus alert specific data
* @ setup : platform data for the smbus_alert i2c client
* @ ara : I2C slave device used to respond to the SMBus Alert with Alert
* Response Address
*/
struct stm32f7_i2c_alert {
struct i2c_smbus_alert_setup setup ;
struct i2c_client * ara ;
} ;
2017-09-14 16:28:37 +02:00
/**
* struct stm32f7_i2c_dev - private data of the controller
* @ adap : I2C adapter for this controller
* @ dev : device for this controller
* @ base : virtual memory area
* @ complete : completion of I2C message
* @ clk : hw i2c clock
2020-04-20 16:57:57 +02:00
* @ bus_rate : I2C clock frequency of the controller
2017-09-14 16:28:37 +02:00
* @ msg : Pointer to data to be written
* @ msg_num : number of I2C messages to be executed
* @ msg_id : message identifiant
* @ f7_msg : customized i2c msg for driver usage
* @ setup : I2C timing input setup
* @ timing : I2C computed timings
2018-04-11 15:24:54 +02:00
* @ slave : list of slave devices registered on the I2C bus
* @ slave_running : slave device currently used
2020-01-06 14:28:32 +01:00
* @ backup_regs : backup of i2c controller registers ( for suspend / resume )
2018-04-11 15:24:54 +02:00
* @ slave_dir : transfer direction for the current slave device
* @ master_mode : boolean to know in which mode the I2C is running ( master or
* slave )
2018-04-11 15:24:57 +02:00
* @ dma : dma data
* @ use_dma : boolean to know if dma is used in the current transfer
2018-11-19 12:03:32 +01:00
* @ regmap : holds SYSCFG phandle for Fast Mode Plus bits
2020-03-02 12:33:16 +01:00
* @ fmp_sreg : register address for setting Fast Mode Plus bits
* @ fmp_creg : register address for clearing Fast Mode Plus bits
2020-03-02 12:33:07 +01:00
* @ fmp_mask : mask for Fast Mode Plus bits in set register
2020-02-03 18:52:08 +01:00
* @ wakeup_src : boolean to know if the device is a wakeup source
2020-08-03 07:17:56 +02:00
* @ smbus_mode : states that the controller is configured in SMBus mode
* @ host_notify_client : SMBus host - notify client
2021-02-05 09:51:41 +01:00
* @ analog_filter : boolean to indicate enabling of the analog filter
2021-02-05 09:51:42 +01:00
* @ dnf_dt : value of digital filter requested via dt
* @ dnf : value of digital filter to apply
2021-05-05 15:14:39 +02:00
* @ alert : SMBus alert specific data
2023-10-23 10:50:15 +02:00
* @ atomic : boolean indicating that current transfer is atomic
2017-09-14 16:28:37 +02:00
*/
struct stm32f7_i2c_dev {
struct i2c_adapter adap ;
struct device * dev ;
void __iomem * base ;
struct completion complete ;
struct clk * clk ;
2020-04-20 16:57:57 +02:00
unsigned int bus_rate ;
2017-09-14 16:28:37 +02:00
struct i2c_msg * msg ;
unsigned int msg_num ;
unsigned int msg_id ;
struct stm32f7_i2c_msg f7_msg ;
2017-09-21 15:30:09 +02:00
struct stm32f7_i2c_setup setup ;
2017-09-14 16:28:37 +02:00
struct stm32f7_i2c_timings timing ;
2018-04-11 15:24:54 +02:00
struct i2c_client * slave [ STM32F7_I2C_MAX_SLAVE ] ;
struct i2c_client * slave_running ;
2020-01-06 14:28:32 +01:00
struct stm32f7_i2c_regs backup_regs ;
2018-04-11 15:24:54 +02:00
u32 slave_dir ;
bool master_mode ;
2018-04-11 15:24:57 +02:00
struct stm32_i2c_dma * dma ;
bool use_dma ;
2018-11-19 12:03:32 +01:00
struct regmap * regmap ;
2020-03-02 12:33:16 +01:00
u32 fmp_sreg ;
u32 fmp_creg ;
2020-03-02 12:33:07 +01:00
u32 fmp_mask ;
2020-02-03 18:52:08 +01:00
bool wakeup_src ;
2020-08-03 07:17:56 +02:00
bool smbus_mode ;
struct i2c_client * host_notify_client ;
2021-02-05 09:51:41 +01:00
bool analog_filter ;
2021-02-05 09:51:42 +01:00
u32 dnf_dt ;
u32 dnf ;
2021-05-05 15:14:39 +02:00
struct stm32f7_i2c_alert * alert ;
2023-08-16 10:05:52 +02:00
bool atomic ;
2017-09-14 16:28:37 +02:00
} ;
2019-10-15 15:11:58 +02:00
/*
2017-09-14 16:28:37 +02:00
* All these values are coming from I2C Specification , Version 6.0 , 4 th of
* April 2014.
*
* Table10 . Characteristics of the SDA and SCL bus lines for Standard , Fast ,
* and Fast - mode Plus I2C - bus devices
*/
2020-04-20 16:57:57 +02:00
static struct stm32f7_i2c_spec stm32f7_i2c_specs [ ] = {
{
2020-03-24 14:32:14 +02:00
. rate = I2C_MAX_STANDARD_MODE_FREQ ,
2017-09-14 16:28:37 +02:00
. fall_max = 300 ,
. rise_max = 1000 ,
. hddat_min = 0 ,
. vddat_max = 3450 ,
. sudat_min = 250 ,
. l_min = 4700 ,
. h_min = 4000 ,
} ,
2020-04-20 16:57:57 +02:00
{
2020-03-24 14:32:14 +02:00
. rate = I2C_MAX_FAST_MODE_FREQ ,
2017-09-14 16:28:37 +02:00
. fall_max = 300 ,
. rise_max = 300 ,
. hddat_min = 0 ,
. vddat_max = 900 ,
. sudat_min = 100 ,
. l_min = 1300 ,
. h_min = 600 ,
} ,
2020-04-20 16:57:57 +02:00
{
2020-03-24 14:32:14 +02:00
. rate = I2C_MAX_FAST_MODE_PLUS_FREQ ,
2017-09-14 16:28:37 +02:00
. fall_max = 100 ,
. rise_max = 120 ,
. hddat_min = 0 ,
. vddat_max = 450 ,
. sudat_min = 50 ,
. l_min = 500 ,
. h_min = 260 ,
} ,
} ;
2017-09-18 09:15:39 +01:00
static const struct stm32f7_i2c_setup stm32f7_setup = {
2017-09-14 16:28:37 +02:00
. rise_time = STM32F7_I2C_RISE_TIME_DEFAULT ,
. fall_time = STM32F7_I2C_FALL_TIME_DEFAULT ,
} ;
2020-03-02 12:33:16 +01:00
static const struct stm32f7_i2c_setup stm32mp15_setup = {
. rise_time = STM32F7_I2C_RISE_TIME_DEFAULT ,
. fall_time = STM32F7_I2C_FALL_TIME_DEFAULT ,
. fmp_clr_offset = 0x40 ,
} ;
2022-07-07 09:44:02 +02:00
static const struct stm32f7_i2c_setup stm32mp13_setup = {
. rise_time = STM32F7_I2C_RISE_TIME_DEFAULT ,
. fall_time = STM32F7_I2C_FALL_TIME_DEFAULT ,
. fmp_clr_offset = 0x4 ,
} ;
2017-09-14 16:28:37 +02:00
static inline void stm32f7_i2c_set_bits ( void __iomem * reg , u32 mask )
{
writel_relaxed ( readl_relaxed ( reg ) | mask , reg ) ;
}
static inline void stm32f7_i2c_clr_bits ( void __iomem * reg , u32 mask )
{
writel_relaxed ( readl_relaxed ( reg ) & ~ mask , reg ) ;
}
2018-04-11 15:24:54 +02:00
static void stm32f7_i2c_disable_irq ( struct stm32f7_i2c_dev * i2c_dev , u32 mask )
{
stm32f7_i2c_clr_bits ( i2c_dev - > base + STM32F7_I2C_CR1 , mask ) ;
}
2020-04-20 16:57:57 +02:00
static struct stm32f7_i2c_spec * stm32f7_get_specs ( u32 rate )
{
int i ;
for ( i = 0 ; i < ARRAY_SIZE ( stm32f7_i2c_specs ) ; i + + )
if ( rate < = stm32f7_i2c_specs [ i ] . rate )
return & stm32f7_i2c_specs [ i ] ;
return ERR_PTR ( - EINVAL ) ;
}
# define RATE_MIN(rate) ((rate) * 8 / 10)
2017-09-14 16:28:37 +02:00
static int stm32f7_i2c_compute_timing ( struct stm32f7_i2c_dev * i2c_dev ,
struct stm32f7_i2c_setup * setup ,
struct stm32f7_i2c_timings * output )
{
2020-04-20 16:57:57 +02:00
struct stm32f7_i2c_spec * specs ;
2017-09-14 16:28:37 +02:00
u32 p_prev = STM32F7_PRESC_MAX ;
u32 i2cclk = DIV_ROUND_CLOSEST ( NSEC_PER_SEC ,
setup - > clock_src ) ;
u32 i2cbus = DIV_ROUND_CLOSEST ( NSEC_PER_SEC ,
setup - > speed_freq ) ;
u32 clk_error_prev = i2cbus ;
u32 tsync ;
u32 af_delay_min , af_delay_max ;
u32 dnf_delay ;
u32 clk_min , clk_max ;
int sdadel_min , sdadel_max ;
int scldel_min ;
struct stm32f7_i2c_timings * v , * _v , * s ;
struct list_head solutions ;
u16 p , l , a , h ;
int ret = 0 ;
2020-04-20 16:57:57 +02:00
specs = stm32f7_get_specs ( setup - > speed_freq ) ;
if ( specs = = ERR_PTR ( - EINVAL ) ) {
dev_err ( i2c_dev - > dev , " speed out of bound {%d} \n " ,
setup - > speed_freq ) ;
2017-09-14 16:28:37 +02:00
return - EINVAL ;
}
2020-04-20 16:57:57 +02:00
if ( ( setup - > rise_time > specs - > rise_max ) | |
( setup - > fall_time > specs - > fall_max ) ) {
2017-09-14 16:28:37 +02:00
dev_err ( i2c_dev - > dev ,
" timings out of bound Rise{%d>%d}/Fall{%d>%d} \n " ,
2020-04-20 16:57:57 +02:00
setup - > rise_time , specs - > rise_max ,
setup - > fall_time , specs - > fall_max ) ;
2017-09-14 16:28:37 +02:00
return - EINVAL ;
}
2021-02-05 09:51:42 +01:00
i2c_dev - > dnf = DIV_ROUND_CLOSEST ( i2c_dev - > dnf_dt , i2cclk ) ;
if ( i2c_dev - > dnf > STM32F7_I2C_DNF_MAX ) {
2017-09-14 16:28:37 +02:00
dev_err ( i2c_dev - > dev ,
" DNF out of bound %d/%d \n " ,
2021-02-05 09:51:42 +01:00
i2c_dev - > dnf * i2cclk , STM32F7_I2C_DNF_MAX * i2cclk ) ;
2017-09-14 16:28:37 +02:00
return - EINVAL ;
}
/* Analog and Digital Filters */
af_delay_min =
2021-02-05 09:51:41 +01:00
( i2c_dev - > analog_filter ?
2017-09-14 16:28:37 +02:00
STM32F7_I2C_ANALOG_FILTER_DELAY_MIN : 0 ) ;
af_delay_max =
2021-02-05 09:51:41 +01:00
( i2c_dev - > analog_filter ?
2017-09-14 16:28:37 +02:00
STM32F7_I2C_ANALOG_FILTER_DELAY_MAX : 0 ) ;
2021-02-05 09:51:42 +01:00
dnf_delay = i2c_dev - > dnf * i2cclk ;
2017-09-14 16:28:37 +02:00
2020-04-20 16:57:57 +02:00
sdadel_min = specs - > hddat_min + setup - > fall_time -
2021-02-05 09:51:42 +01:00
af_delay_min - ( i2c_dev - > dnf + 3 ) * i2cclk ;
2017-09-14 16:28:37 +02:00
2020-04-20 16:57:57 +02:00
sdadel_max = specs - > vddat_max - setup - > rise_time -
2021-02-05 09:51:42 +01:00
af_delay_max - ( i2c_dev - > dnf + 4 ) * i2cclk ;
2017-09-14 16:28:37 +02:00
2020-04-20 16:57:57 +02:00
scldel_min = setup - > rise_time + specs - > sudat_min ;
2017-09-14 16:28:37 +02:00
if ( sdadel_min < 0 )
sdadel_min = 0 ;
if ( sdadel_max < 0 )
sdadel_max = 0 ;
dev_dbg ( i2c_dev - > dev , " SDADEL(min/max): %i/%i, SCLDEL(Min): %i \n " ,
sdadel_min , sdadel_max , scldel_min ) ;
INIT_LIST_HEAD ( & solutions ) ;
/* Compute possible values for PRESC, SCLDEL and SDADEL */
for ( p = 0 ; p < STM32F7_PRESC_MAX ; p + + ) {
for ( l = 0 ; l < STM32F7_SCLDEL_MAX ; l + + ) {
u32 scldel = ( l + 1 ) * ( p + 1 ) * i2cclk ;
if ( scldel < scldel_min )
continue ;
for ( a = 0 ; a < STM32F7_SDADEL_MAX ; a + + ) {
u32 sdadel = ( a * ( p + 1 ) + 1 ) * i2cclk ;
if ( ( ( sdadel > = sdadel_min ) & &
( sdadel < = sdadel_max ) ) & &
( p ! = p_prev ) ) {
v = kmalloc ( sizeof ( * v ) , GFP_KERNEL ) ;
if ( ! v ) {
ret = - ENOMEM ;
goto exit ;
}
v - > presc = p ;
v - > scldel = l ;
v - > sdadel = a ;
p_prev = p ;
list_add_tail ( & v - > node ,
& solutions ) ;
2019-03-06 15:12:32 +00:00
break ;
2017-09-14 16:28:37 +02:00
}
}
2019-03-06 15:12:32 +00:00
if ( p_prev = = p )
break ;
2017-09-14 16:28:37 +02:00
}
}
if ( list_empty ( & solutions ) ) {
dev_err ( i2c_dev - > dev , " no Prescaler solution \n " ) ;
ret = - EPERM ;
goto exit ;
}
tsync = af_delay_min + dnf_delay + ( 2 * i2cclk ) ;
s = NULL ;
2020-04-20 16:57:57 +02:00
clk_max = NSEC_PER_SEC / RATE_MIN ( setup - > speed_freq ) ;
clk_min = NSEC_PER_SEC / setup - > speed_freq ;
2017-09-14 16:28:37 +02:00
/*
* Among Prescaler possibilities discovered above figures out SCL Low
* and High Period . Provided :
* - SCL Low Period has to be higher than SCL Clock Low Period
* defined by I2C Specification . I2C Clock has to be lower than
* ( SCL Low Period - Analog / Digital filters ) / 4.
* - SCL High Period has to be lower than SCL Clock High Period
* defined by I2C Specification
* - I2C Clock has to be lower than SCL High Period
*/
list_for_each_entry ( v , & solutions , node ) {
u32 prescaler = ( v - > presc + 1 ) * i2cclk ;
for ( l = 0 ; l < STM32F7_SCLL_MAX ; l + + ) {
u32 tscl_l = ( l + 1 ) * prescaler + tsync ;
2020-04-20 16:57:57 +02:00
if ( ( tscl_l < specs - > l_min ) | |
2017-09-14 16:28:37 +02:00
( i2cclk > =
( ( tscl_l - af_delay_min - dnf_delay ) / 4 ) ) ) {
continue ;
}
for ( h = 0 ; h < STM32F7_SCLH_MAX ; h + + ) {
u32 tscl_h = ( h + 1 ) * prescaler + tsync ;
u32 tscl = tscl_l + tscl_h +
setup - > rise_time + setup - > fall_time ;
if ( ( tscl > = clk_min ) & & ( tscl < = clk_max ) & &
2020-04-20 16:57:57 +02:00
( tscl_h > = specs - > h_min ) & &
2017-09-14 16:28:37 +02:00
( i2cclk < tscl_h ) ) {
int clk_error = tscl - i2cbus ;
if ( clk_error < 0 )
clk_error = - clk_error ;
if ( clk_error < clk_error_prev ) {
clk_error_prev = clk_error ;
v - > scll = l ;
v - > sclh = h ;
s = v ;
}
}
}
}
}
if ( ! s ) {
dev_err ( i2c_dev - > dev , " no solution at all \n " ) ;
ret = - EPERM ;
goto exit ;
}
output - > presc = s - > presc ;
output - > scldel = s - > scldel ;
output - > sdadel = s - > sdadel ;
output - > scll = s - > scll ;
output - > sclh = s - > sclh ;
dev_dbg ( i2c_dev - > dev ,
" Presc: %i, scldel: %i, sdadel: %i, scll: %i, sclh: %i \n " ,
output - > presc ,
output - > scldel , output - > sdadel ,
output - > scll , output - > sclh ) ;
exit :
/* Release list and memory */
list_for_each_entry_safe ( v , _v , & solutions , node ) {
list_del ( & v - > node ) ;
kfree ( v ) ;
}
return ret ;
}
2020-04-20 16:57:57 +02:00
static u32 stm32f7_get_lower_rate ( u32 rate )
{
int i = ARRAY_SIZE ( stm32f7_i2c_specs ) ;
2020-04-29 16:23:23 +03:00
while ( - - i )
2020-04-20 16:57:57 +02:00
if ( stm32f7_i2c_specs [ i ] . rate < rate )
break ;
return stm32f7_i2c_specs [ i ] . rate ;
}
2017-09-14 16:28:37 +02:00
static int stm32f7_i2c_setup_timing ( struct stm32f7_i2c_dev * i2c_dev ,
struct stm32f7_i2c_setup * setup )
{
2020-03-24 14:32:14 +02:00
struct i2c_timings timings , * t = & timings ;
2017-09-14 16:28:37 +02:00
int ret = 0 ;
2020-03-24 14:32:14 +02:00
t - > bus_freq_hz = I2C_MAX_STANDARD_MODE_FREQ ;
t - > scl_rise_ns = i2c_dev - > setup . rise_time ;
t - > scl_fall_ns = i2c_dev - > setup . fall_time ;
i2c_parse_fw_timings ( i2c_dev - > dev , t , false ) ;
2020-04-20 16:57:57 +02:00
if ( t - > bus_freq_hz > I2C_MAX_FAST_MODE_PLUS_FREQ ) {
dev_err ( i2c_dev - > dev , " Invalid bus speed (%i>%i) \n " ,
t - > bus_freq_hz , I2C_MAX_FAST_MODE_PLUS_FREQ ) ;
return - EINVAL ;
}
2020-03-24 14:32:14 +02:00
2020-04-20 16:57:57 +02:00
setup - > speed_freq = t - > bus_freq_hz ;
2020-03-24 14:32:14 +02:00
i2c_dev - > setup . rise_time = t - > scl_rise_ns ;
i2c_dev - > setup . fall_time = t - > scl_fall_ns ;
2021-02-05 09:51:42 +01:00
i2c_dev - > dnf_dt = t - > digital_filter_width_ns ;
2017-09-14 16:28:37 +02:00
setup - > clock_src = clk_get_rate ( i2c_dev - > clk ) ;
if ( ! setup - > clock_src ) {
dev_err ( i2c_dev - > dev , " clock rate is 0 \n " ) ;
return - EINVAL ;
}
2021-02-05 09:51:42 +01:00
if ( ! of_property_read_bool ( i2c_dev - > dev - > of_node , " i2c-digital-filter " ) )
i2c_dev - > dnf_dt = STM32F7_I2C_DNF_DEFAULT ;
2017-09-14 16:28:37 +02:00
do {
ret = stm32f7_i2c_compute_timing ( i2c_dev , setup ,
& i2c_dev - > timing ) ;
if ( ret ) {
dev_err ( i2c_dev - > dev ,
" failed to compute I2C timings. \n " ) ;
2020-04-20 16:57:57 +02:00
if ( setup - > speed_freq < = I2C_MAX_STANDARD_MODE_FREQ )
2017-09-14 16:28:37 +02:00
break ;
2020-04-20 16:57:57 +02:00
setup - > speed_freq =
stm32f7_get_lower_rate ( setup - > speed_freq ) ;
dev_warn ( i2c_dev - > dev ,
" downgrade I2C Speed Freq to (%i) \n " ,
setup - > speed_freq ) ;
2017-09-14 16:28:37 +02:00
}
} while ( ret ) ;
if ( ret ) {
dev_err ( i2c_dev - > dev , " Impossible to compute I2C timings. \n " ) ;
return ret ;
}
2021-02-05 09:51:41 +01:00
i2c_dev - > analog_filter = of_property_read_bool ( i2c_dev - > dev - > of_node ,
" i2c-analog-filter " ) ;
2020-04-20 16:57:57 +02:00
dev_dbg ( i2c_dev - > dev , " I2C Speed(%i), Clk Source(%i) \n " ,
setup - > speed_freq , setup - > clock_src ) ;
2017-09-14 16:28:37 +02:00
dev_dbg ( i2c_dev - > dev , " I2C Rise(%i) and Fall(%i) Time \n " ,
setup - > rise_time , setup - > fall_time ) ;
dev_dbg ( i2c_dev - > dev , " I2C Analog Filter(%s), DNF(%i) \n " ,
2021-02-05 09:51:42 +01:00
( i2c_dev - > analog_filter ? " On " : " Off " ) , i2c_dev - > dnf ) ;
2017-09-14 16:28:37 +02:00
2020-04-20 16:57:57 +02:00
i2c_dev - > bus_rate = setup - > speed_freq ;
2017-09-14 16:28:37 +02:00
return 0 ;
}
2018-04-11 15:24:57 +02:00
static void stm32f7_i2c_disable_dma_req ( struct stm32f7_i2c_dev * i2c_dev )
{
void __iomem * base = i2c_dev - > base ;
u32 mask = STM32F7_I2C_CR1_RXDMAEN | STM32F7_I2C_CR1_TXDMAEN ;
stm32f7_i2c_clr_bits ( base + STM32F7_I2C_CR1 , mask ) ;
}
static void stm32f7_i2c_dma_callback ( void * arg )
{
struct stm32f7_i2c_dev * i2c_dev = ( struct stm32f7_i2c_dev * ) arg ;
struct stm32_i2c_dma * dma = i2c_dev - > dma ;
struct device * dev = dma - > chan_using - > device - > dev ;
stm32f7_i2c_disable_dma_req ( i2c_dev ) ;
dma_unmap_single ( dev , dma - > dma_buf , dma - > dma_len , dma - > dma_data_dir ) ;
complete ( & dma - > dma_complete ) ;
}
2017-09-14 16:28:37 +02:00
static void stm32f7_i2c_hw_config ( struct stm32f7_i2c_dev * i2c_dev )
{
struct stm32f7_i2c_timings * t = & i2c_dev - > timing ;
u32 timing = 0 ;
/* Timing settings */
timing | = STM32F7_I2C_TIMINGR_PRESC ( t - > presc ) ;
timing | = STM32F7_I2C_TIMINGR_SCLDEL ( t - > scldel ) ;
timing | = STM32F7_I2C_TIMINGR_SDADEL ( t - > sdadel ) ;
timing | = STM32F7_I2C_TIMINGR_SCLH ( t - > sclh ) ;
timing | = STM32F7_I2C_TIMINGR_SCLL ( t - > scll ) ;
writel_relaxed ( timing , i2c_dev - > base + STM32F7_I2C_TIMINGR ) ;
2021-02-05 09:51:41 +01:00
/* Configure the Analog Filter */
if ( i2c_dev - > analog_filter )
2017-09-14 16:28:37 +02:00
stm32f7_i2c_clr_bits ( i2c_dev - > base + STM32F7_I2C_CR1 ,
STM32F7_I2C_CR1_ANFOFF ) ;
else
stm32f7_i2c_set_bits ( i2c_dev - > base + STM32F7_I2C_CR1 ,
STM32F7_I2C_CR1_ANFOFF ) ;
2021-02-05 09:51:40 +01:00
/* Program the Digital Filter */
stm32f7_i2c_clr_bits ( i2c_dev - > base + STM32F7_I2C_CR1 ,
STM32F7_I2C_CR1_DNF_MASK ) ;
stm32f7_i2c_set_bits ( i2c_dev - > base + STM32F7_I2C_CR1 ,
2021-02-05 09:51:42 +01:00
STM32F7_I2C_CR1_DNF ( i2c_dev - > dnf ) ) ;
2021-02-05 09:51:40 +01:00
2017-09-14 16:28:37 +02:00
stm32f7_i2c_set_bits ( i2c_dev - > base + STM32F7_I2C_CR1 ,
STM32F7_I2C_CR1_PE ) ;
}
static void stm32f7_i2c_write_tx_data ( struct stm32f7_i2c_dev * i2c_dev )
{
struct stm32f7_i2c_msg * f7_msg = & i2c_dev - > f7_msg ;
void __iomem * base = i2c_dev - > base ;
if ( f7_msg - > count ) {
writeb_relaxed ( * f7_msg - > buf + + , base + STM32F7_I2C_TXDR ) ;
f7_msg - > count - - ;
}
}
static void stm32f7_i2c_read_rx_data ( struct stm32f7_i2c_dev * i2c_dev )
{
struct stm32f7_i2c_msg * f7_msg = & i2c_dev - > f7_msg ;
void __iomem * base = i2c_dev - > base ;
if ( f7_msg - > count ) {
* f7_msg - > buf + + = readb_relaxed ( base + STM32F7_I2C_RXDR ) ;
f7_msg - > count - - ;
2018-04-11 15:24:54 +02:00
} else {
/* Flush RX buffer has no data is expected */
readb_relaxed ( base + STM32F7_I2C_RXDR ) ;
2017-09-14 16:28:37 +02:00
}
}
static void stm32f7_i2c_reload ( struct stm32f7_i2c_dev * i2c_dev )
{
struct stm32f7_i2c_msg * f7_msg = & i2c_dev - > f7_msg ;
u32 cr2 ;
2018-04-11 15:24:57 +02:00
if ( i2c_dev - > use_dma )
f7_msg - > count - = STM32F7_I2C_MAX_LEN ;
2017-09-14 16:28:37 +02:00
cr2 = readl_relaxed ( i2c_dev - > base + STM32F7_I2C_CR2 ) ;
cr2 & = ~ STM32F7_I2C_CR2_NBYTES_MASK ;
if ( f7_msg - > count > STM32F7_I2C_MAX_LEN ) {
cr2 | = STM32F7_I2C_CR2_NBYTES ( STM32F7_I2C_MAX_LEN ) ;
} else {
cr2 & = ~ STM32F7_I2C_CR2_RELOAD ;
cr2 | = STM32F7_I2C_CR2_NBYTES ( f7_msg - > count ) ;
}
writel_relaxed ( cr2 , i2c_dev - > base + STM32F7_I2C_CR2 ) ;
}
2018-04-11 15:24:55 +02:00
static void stm32f7_i2c_smbus_reload ( struct stm32f7_i2c_dev * i2c_dev )
{
struct stm32f7_i2c_msg * f7_msg = & i2c_dev - > f7_msg ;
u32 cr2 ;
u8 * val ;
/*
* For I2C_SMBUS_BLOCK_DATA & & I2C_SMBUS_BLOCK_PROC_CALL , the first
* data received inform us how many data will follow .
*/
stm32f7_i2c_read_rx_data ( i2c_dev ) ;
/*
* Update NBYTES with the value read to continue the transfer
*/
val = f7_msg - > buf - sizeof ( u8 ) ;
f7_msg - > count = * val ;
cr2 = readl_relaxed ( i2c_dev - > base + STM32F7_I2C_CR2 ) ;
cr2 & = ~ ( STM32F7_I2C_CR2_NBYTES_MASK | STM32F7_I2C_CR2_RELOAD ) ;
cr2 | = STM32F7_I2C_CR2_NBYTES ( f7_msg - > count ) ;
writel_relaxed ( cr2 , i2c_dev - > base + STM32F7_I2C_CR2 ) ;
}
2021-12-01 12:47:50 +01:00
static void stm32f7_i2c_release_bus ( struct i2c_adapter * i2c_adap )
2018-04-11 15:24:58 +02:00
{
struct stm32f7_i2c_dev * i2c_dev = i2c_get_adapdata ( i2c_adap ) ;
stm32f7_i2c_clr_bits ( i2c_dev - > base + STM32F7_I2C_CR1 ,
STM32F7_I2C_CR1_PE ) ;
stm32f7_i2c_hw_config ( i2c_dev ) ;
}
2017-09-14 16:28:37 +02:00
static int stm32f7_i2c_wait_free_bus ( struct stm32f7_i2c_dev * i2c_dev )
{
u32 status ;
int ret ;
ret = readl_relaxed_poll_timeout ( i2c_dev - > base + STM32F7_I2C_ISR ,
status ,
! ( status & STM32F7_I2C_ISR_BUSY ) ,
10 , 1000 ) ;
2018-04-11 15:24:58 +02:00
if ( ! ret )
return 0 ;
2021-12-01 12:47:50 +01:00
stm32f7_i2c_release_bus ( & i2c_dev - > adap ) ;
2017-09-14 16:28:37 +02:00
2018-04-11 15:24:58 +02:00
return - EBUSY ;
2017-09-14 16:28:37 +02:00
}
static void stm32f7_i2c_xfer_msg ( struct stm32f7_i2c_dev * i2c_dev ,
struct i2c_msg * msg )
{
struct stm32f7_i2c_msg * f7_msg = & i2c_dev - > f7_msg ;
void __iomem * base = i2c_dev - > base ;
u32 cr1 , cr2 ;
2018-04-11 15:24:57 +02:00
int ret ;
2017-09-14 16:28:37 +02:00
f7_msg - > addr = msg - > addr ;
f7_msg - > buf = msg - > buf ;
f7_msg - > count = msg - > len ;
f7_msg - > result = 0 ;
f7_msg - > stop = ( i2c_dev - > msg_id > = i2c_dev - > msg_num - 1 ) ;
reinit_completion ( & i2c_dev - > complete ) ;
cr1 = readl_relaxed ( base + STM32F7_I2C_CR1 ) ;
cr2 = readl_relaxed ( base + STM32F7_I2C_CR2 ) ;
/* Set transfer direction */
cr2 & = ~ STM32F7_I2C_CR2_RD_WRN ;
if ( msg - > flags & I2C_M_RD )
cr2 | = STM32F7_I2C_CR2_RD_WRN ;
/* Set slave address */
2018-04-11 15:24:53 +02:00
cr2 & = ~ ( STM32F7_I2C_CR2_HEAD10R | STM32F7_I2C_CR2_ADD10 ) ;
if ( msg - > flags & I2C_M_TEN ) {
cr2 & = ~ STM32F7_I2C_CR2_SADD10_MASK ;
cr2 | = STM32F7_I2C_CR2_SADD10 ( f7_msg - > addr ) ;
cr2 | = STM32F7_I2C_CR2_ADD10 ;
} else {
cr2 & = ~ STM32F7_I2C_CR2_SADD7_MASK ;
cr2 | = STM32F7_I2C_CR2_SADD7 ( f7_msg - > addr ) ;
}
2017-09-14 16:28:37 +02:00
/* Set nb bytes to transfer and reload if needed */
cr2 & = ~ ( STM32F7_I2C_CR2_NBYTES_MASK | STM32F7_I2C_CR2_RELOAD ) ;
if ( f7_msg - > count > STM32F7_I2C_MAX_LEN ) {
cr2 | = STM32F7_I2C_CR2_NBYTES ( STM32F7_I2C_MAX_LEN ) ;
cr2 | = STM32F7_I2C_CR2_RELOAD ;
} else {
cr2 | = STM32F7_I2C_CR2_NBYTES ( f7_msg - > count ) ;
}
/* Enable NACK, STOP, error and transfer complete interrupts */
cr1 | = STM32F7_I2C_CR1_ERRIE | STM32F7_I2C_CR1_TCIE |
STM32F7_I2C_CR1_STOPIE | STM32F7_I2C_CR1_NACKIE ;
2018-04-11 15:24:57 +02:00
/* Clear DMA req and TX/RX interrupt */
cr1 & = ~ ( STM32F7_I2C_CR1_RXIE | STM32F7_I2C_CR1_TXIE |
STM32F7_I2C_CR1_RXDMAEN | STM32F7_I2C_CR1_TXDMAEN ) ;
/* Configure DMA or enable RX/TX interrupt */
i2c_dev - > use_dma = false ;
2023-08-16 10:05:52 +02:00
if ( i2c_dev - > dma & & f7_msg - > count > = STM32F7_I2C_DMA_LEN_MIN
& & ! i2c_dev - > atomic ) {
2018-04-11 15:24:57 +02:00
ret = stm32_i2c_prep_dma_xfer ( i2c_dev - > dev , i2c_dev - > dma ,
msg - > flags & I2C_M_RD ,
f7_msg - > count , f7_msg - > buf ,
stm32f7_i2c_dma_callback ,
i2c_dev ) ;
if ( ! ret )
i2c_dev - > use_dma = true ;
else
dev_warn ( i2c_dev - > dev , " can't use DMA \n " ) ;
}
2017-09-14 16:28:37 +02:00
2018-04-11 15:24:57 +02:00
if ( ! i2c_dev - > use_dma ) {
if ( msg - > flags & I2C_M_RD )
cr1 | = STM32F7_I2C_CR1_RXIE ;
else
cr1 | = STM32F7_I2C_CR1_TXIE ;
} else {
if ( msg - > flags & I2C_M_RD )
cr1 | = STM32F7_I2C_CR1_RXDMAEN ;
else
cr1 | = STM32F7_I2C_CR1_TXDMAEN ;
}
2017-09-14 16:28:37 +02:00
2023-08-16 10:05:52 +02:00
if ( i2c_dev - > atomic )
cr1 & = ~ STM32F7_I2C_ALL_IRQ_MASK ; /* Disable all interrupts */
2017-09-14 16:28:37 +02:00
/* Configure Start/Repeated Start */
cr2 | = STM32F7_I2C_CR2_START ;
2018-04-11 15:24:54 +02:00
i2c_dev - > master_mode = true ;
2017-09-14 16:28:37 +02:00
/* Write configurations registers */
writel_relaxed ( cr1 , base + STM32F7_I2C_CR1 ) ;
writel_relaxed ( cr2 , base + STM32F7_I2C_CR2 ) ;
}
2018-04-11 15:24:55 +02:00
static int stm32f7_i2c_smbus_xfer_msg ( struct stm32f7_i2c_dev * i2c_dev ,
unsigned short flags , u8 command ,
union i2c_smbus_data * data )
{
struct stm32f7_i2c_msg * f7_msg = & i2c_dev - > f7_msg ;
struct device * dev = i2c_dev - > dev ;
void __iomem * base = i2c_dev - > base ;
u32 cr1 , cr2 ;
2018-04-11 15:24:57 +02:00
int i , ret ;
2018-04-11 15:24:55 +02:00
f7_msg - > result = 0 ;
reinit_completion ( & i2c_dev - > complete ) ;
cr2 = readl_relaxed ( base + STM32F7_I2C_CR2 ) ;
cr1 = readl_relaxed ( base + STM32F7_I2C_CR1 ) ;
/* Set transfer direction */
cr2 & = ~ STM32F7_I2C_CR2_RD_WRN ;
if ( f7_msg - > read_write )
cr2 | = STM32F7_I2C_CR2_RD_WRN ;
/* Set slave address */
cr2 & = ~ ( STM32F7_I2C_CR2_ADD10 | STM32F7_I2C_CR2_SADD7_MASK ) ;
cr2 | = STM32F7_I2C_CR2_SADD7 ( f7_msg - > addr ) ;
f7_msg - > smbus_buf [ 0 ] = command ;
switch ( f7_msg - > size ) {
case I2C_SMBUS_QUICK :
f7_msg - > stop = true ;
f7_msg - > count = 0 ;
break ;
case I2C_SMBUS_BYTE :
f7_msg - > stop = true ;
f7_msg - > count = 1 ;
break ;
case I2C_SMBUS_BYTE_DATA :
if ( f7_msg - > read_write ) {
f7_msg - > stop = false ;
f7_msg - > count = 1 ;
cr2 & = ~ STM32F7_I2C_CR2_RD_WRN ;
} else {
f7_msg - > stop = true ;
f7_msg - > count = 2 ;
f7_msg - > smbus_buf [ 1 ] = data - > byte ;
}
break ;
case I2C_SMBUS_WORD_DATA :
if ( f7_msg - > read_write ) {
f7_msg - > stop = false ;
f7_msg - > count = 1 ;
cr2 & = ~ STM32F7_I2C_CR2_RD_WRN ;
} else {
f7_msg - > stop = true ;
f7_msg - > count = 3 ;
f7_msg - > smbus_buf [ 1 ] = data - > word & 0xff ;
f7_msg - > smbus_buf [ 2 ] = data - > word > > 8 ;
}
break ;
case I2C_SMBUS_BLOCK_DATA :
if ( f7_msg - > read_write ) {
f7_msg - > stop = false ;
f7_msg - > count = 1 ;
cr2 & = ~ STM32F7_I2C_CR2_RD_WRN ;
} else {
f7_msg - > stop = true ;
if ( data - > block [ 0 ] > I2C_SMBUS_BLOCK_MAX | |
! data - > block [ 0 ] ) {
dev_err ( dev , " Invalid block write size %d \n " ,
data - > block [ 0 ] ) ;
return - EINVAL ;
}
f7_msg - > count = data - > block [ 0 ] + 2 ;
for ( i = 1 ; i < f7_msg - > count ; i + + )
f7_msg - > smbus_buf [ i ] = data - > block [ i - 1 ] ;
}
break ;
case I2C_SMBUS_PROC_CALL :
f7_msg - > stop = false ;
f7_msg - > count = 3 ;
f7_msg - > smbus_buf [ 1 ] = data - > word & 0xff ;
f7_msg - > smbus_buf [ 2 ] = data - > word > > 8 ;
cr2 & = ~ STM32F7_I2C_CR2_RD_WRN ;
f7_msg - > read_write = I2C_SMBUS_READ ;
break ;
case I2C_SMBUS_BLOCK_PROC_CALL :
f7_msg - > stop = false ;
if ( data - > block [ 0 ] > I2C_SMBUS_BLOCK_MAX - 1 ) {
dev_err ( dev , " Invalid block write size %d \n " ,
data - > block [ 0 ] ) ;
return - EINVAL ;
}
f7_msg - > count = data - > block [ 0 ] + 2 ;
for ( i = 1 ; i < f7_msg - > count ; i + + )
f7_msg - > smbus_buf [ i ] = data - > block [ i - 1 ] ;
cr2 & = ~ STM32F7_I2C_CR2_RD_WRN ;
f7_msg - > read_write = I2C_SMBUS_READ ;
break ;
2019-06-04 15:20:51 +02:00
case I2C_SMBUS_I2C_BLOCK_DATA :
/* Rely on emulated i2c transfer (through master_xfer) */
return - EOPNOTSUPP ;
2018-04-11 15:24:55 +02:00
default :
dev_err ( dev , " Unsupported smbus protocol %d \n " , f7_msg - > size ) ;
return - EOPNOTSUPP ;
}
f7_msg - > buf = f7_msg - > smbus_buf ;
/* Configure PEC */
if ( ( flags & I2C_CLIENT_PEC ) & & f7_msg - > size ! = I2C_SMBUS_QUICK ) {
cr1 | = STM32F7_I2C_CR1_PECEN ;
2023-10-10 10:44:54 +02:00
if ( ! f7_msg - > read_write ) {
cr2 | = STM32F7_I2C_CR2_PECBYTE ;
2018-04-11 15:24:55 +02:00
f7_msg - > count + + ;
2023-10-10 10:44:54 +02:00
}
2018-04-11 15:24:55 +02:00
} else {
cr1 & = ~ STM32F7_I2C_CR1_PECEN ;
cr2 & = ~ STM32F7_I2C_CR2_PECBYTE ;
}
/* Set number of bytes to be transferred */
cr2 & = ~ ( STM32F7_I2C_CR2_NBYTES_MASK | STM32F7_I2C_CR2_RELOAD ) ;
cr2 | = STM32F7_I2C_CR2_NBYTES ( f7_msg - > count ) ;
/* Enable NACK, STOP, error and transfer complete interrupts */
cr1 | = STM32F7_I2C_CR1_ERRIE | STM32F7_I2C_CR1_TCIE |
STM32F7_I2C_CR1_STOPIE | STM32F7_I2C_CR1_NACKIE ;
2018-04-11 15:24:57 +02:00
/* Clear DMA req and TX/RX interrupt */
cr1 & = ~ ( STM32F7_I2C_CR1_RXIE | STM32F7_I2C_CR1_TXIE |
STM32F7_I2C_CR1_RXDMAEN | STM32F7_I2C_CR1_TXDMAEN ) ;
/* Configure DMA or enable RX/TX interrupt */
i2c_dev - > use_dma = false ;
if ( i2c_dev - > dma & & f7_msg - > count > = STM32F7_I2C_DMA_LEN_MIN ) {
ret = stm32_i2c_prep_dma_xfer ( i2c_dev - > dev , i2c_dev - > dma ,
cr2 & STM32F7_I2C_CR2_RD_WRN ,
f7_msg - > count , f7_msg - > buf ,
stm32f7_i2c_dma_callback ,
i2c_dev ) ;
if ( ! ret )
i2c_dev - > use_dma = true ;
else
dev_warn ( i2c_dev - > dev , " can't use DMA \n " ) ;
}
2018-04-11 15:24:55 +02:00
2018-04-11 15:24:57 +02:00
if ( ! i2c_dev - > use_dma ) {
if ( cr2 & STM32F7_I2C_CR2_RD_WRN )
cr1 | = STM32F7_I2C_CR1_RXIE ;
else
cr1 | = STM32F7_I2C_CR1_TXIE ;
} else {
if ( cr2 & STM32F7_I2C_CR2_RD_WRN )
cr1 | = STM32F7_I2C_CR1_RXDMAEN ;
else
cr1 | = STM32F7_I2C_CR1_TXDMAEN ;
}
2018-04-11 15:24:55 +02:00
/* Set Start bit */
cr2 | = STM32F7_I2C_CR2_START ;
i2c_dev - > master_mode = true ;
/* Write configurations registers */
writel_relaxed ( cr1 , base + STM32F7_I2C_CR1 ) ;
writel_relaxed ( cr2 , base + STM32F7_I2C_CR2 ) ;
return 0 ;
}
static void stm32f7_i2c_smbus_rep_start ( struct stm32f7_i2c_dev * i2c_dev )
{
struct stm32f7_i2c_msg * f7_msg = & i2c_dev - > f7_msg ;
void __iomem * base = i2c_dev - > base ;
u32 cr1 , cr2 ;
2018-04-11 15:24:57 +02:00
int ret ;
2018-04-11 15:24:55 +02:00
cr2 = readl_relaxed ( base + STM32F7_I2C_CR2 ) ;
cr1 = readl_relaxed ( base + STM32F7_I2C_CR1 ) ;
/* Set transfer direction */
cr2 | = STM32F7_I2C_CR2_RD_WRN ;
switch ( f7_msg - > size ) {
case I2C_SMBUS_BYTE_DATA :
f7_msg - > count = 1 ;
break ;
case I2C_SMBUS_WORD_DATA :
case I2C_SMBUS_PROC_CALL :
f7_msg - > count = 2 ;
break ;
case I2C_SMBUS_BLOCK_DATA :
case I2C_SMBUS_BLOCK_PROC_CALL :
f7_msg - > count = 1 ;
cr2 | = STM32F7_I2C_CR2_RELOAD ;
break ;
}
f7_msg - > buf = f7_msg - > smbus_buf ;
f7_msg - > stop = true ;
/* Add one byte for PEC if needed */
2023-10-10 10:44:54 +02:00
if ( cr1 & STM32F7_I2C_CR1_PECEN ) {
cr2 | = STM32F7_I2C_CR2_PECBYTE ;
2018-04-11 15:24:55 +02:00
f7_msg - > count + + ;
2023-10-10 10:44:54 +02:00
}
2018-04-11 15:24:55 +02:00
/* Set number of bytes to be transferred */
cr2 & = ~ ( STM32F7_I2C_CR2_NBYTES_MASK ) ;
cr2 | = STM32F7_I2C_CR2_NBYTES ( f7_msg - > count ) ;
/*
* Configure RX / TX interrupt :
*/
cr1 & = ~ ( STM32F7_I2C_CR1_RXIE | STM32F7_I2C_CR1_TXIE ) ;
cr1 | = STM32F7_I2C_CR1_RXIE ;
2018-04-11 15:24:57 +02:00
/*
* Configure DMA or enable RX / TX interrupt :
* For I2C_SMBUS_BLOCK_DATA and I2C_SMBUS_BLOCK_PROC_CALL we don ' t use
* dma as we don ' t know in advance how many data will be received
*/
cr1 & = ~ ( STM32F7_I2C_CR1_RXIE | STM32F7_I2C_CR1_TXIE |
STM32F7_I2C_CR1_RXDMAEN | STM32F7_I2C_CR1_TXDMAEN ) ;
i2c_dev - > use_dma = false ;
if ( i2c_dev - > dma & & f7_msg - > count > = STM32F7_I2C_DMA_LEN_MIN & &
f7_msg - > size ! = I2C_SMBUS_BLOCK_DATA & &
f7_msg - > size ! = I2C_SMBUS_BLOCK_PROC_CALL ) {
ret = stm32_i2c_prep_dma_xfer ( i2c_dev - > dev , i2c_dev - > dma ,
cr2 & STM32F7_I2C_CR2_RD_WRN ,
f7_msg - > count , f7_msg - > buf ,
stm32f7_i2c_dma_callback ,
i2c_dev ) ;
if ( ! ret )
i2c_dev - > use_dma = true ;
else
dev_warn ( i2c_dev - > dev , " can't use DMA \n " ) ;
}
if ( ! i2c_dev - > use_dma )
cr1 | = STM32F7_I2C_CR1_RXIE ;
else
cr1 | = STM32F7_I2C_CR1_RXDMAEN ;
2018-04-11 15:24:55 +02:00
/* Configure Repeated Start */
cr2 | = STM32F7_I2C_CR2_START ;
/* Write configurations registers */
writel_relaxed ( cr1 , base + STM32F7_I2C_CR1 ) ;
writel_relaxed ( cr2 , base + STM32F7_I2C_CR2 ) ;
}
static int stm32f7_i2c_smbus_check_pec ( struct stm32f7_i2c_dev * i2c_dev )
{
struct stm32f7_i2c_msg * f7_msg = & i2c_dev - > f7_msg ;
u8 count , internal_pec , received_pec ;
internal_pec = readl_relaxed ( i2c_dev - > base + STM32F7_I2C_PECR ) ;
switch ( f7_msg - > size ) {
case I2C_SMBUS_BYTE :
case I2C_SMBUS_BYTE_DATA :
received_pec = f7_msg - > smbus_buf [ 1 ] ;
break ;
case I2C_SMBUS_WORD_DATA :
case I2C_SMBUS_PROC_CALL :
received_pec = f7_msg - > smbus_buf [ 2 ] ;
break ;
case I2C_SMBUS_BLOCK_DATA :
case I2C_SMBUS_BLOCK_PROC_CALL :
count = f7_msg - > smbus_buf [ 0 ] ;
received_pec = f7_msg - > smbus_buf [ count ] ;
break ;
default :
dev_err ( i2c_dev - > dev , " Unsupported smbus protocol for PEC \n " ) ;
return - EINVAL ;
}
if ( internal_pec ! = received_pec ) {
dev_err ( i2c_dev - > dev , " Bad PEC 0x%02x vs. 0x%02x \n " ,
internal_pec , received_pec ) ;
return - EBADMSG ;
}
return 0 ;
}
2018-04-11 15:24:54 +02:00
static bool stm32f7_i2c_is_addr_match ( struct i2c_client * slave , u32 addcode )
2017-09-14 16:28:37 +02:00
{
2018-04-11 15:24:54 +02:00
u32 addr ;
if ( ! slave )
return false ;
if ( slave - > flags & I2C_CLIENT_TEN ) {
/*
* For 10 - bit addr , addcode = 11110 XY with
* X = Bit 9 of slave address
* Y = Bit 8 of slave address
*/
addr = slave - > addr > > 8 ;
addr | = 0x78 ;
if ( addr = = addcode )
return true ;
} else {
addr = slave - > addr & 0x7f ;
if ( addr = = addcode )
return true ;
}
return false ;
}
static void stm32f7_i2c_slave_start ( struct stm32f7_i2c_dev * i2c_dev )
{
struct i2c_client * slave = i2c_dev - > slave_running ;
void __iomem * base = i2c_dev - > base ;
u32 mask ;
u8 value = 0 ;
if ( i2c_dev - > slave_dir ) {
/* Notify i2c slave that new read transfer is starting */
i2c_slave_event ( slave , I2C_SLAVE_READ_REQUESTED , & value ) ;
/*
* Disable slave TX config in case of I2C combined message
* ( I2C Write followed by I2C Read )
*/
mask = STM32F7_I2C_CR2_RELOAD ;
stm32f7_i2c_clr_bits ( base + STM32F7_I2C_CR2 , mask ) ;
mask = STM32F7_I2C_CR1_SBC | STM32F7_I2C_CR1_RXIE |
STM32F7_I2C_CR1_TCIE ;
stm32f7_i2c_clr_bits ( base + STM32F7_I2C_CR1 , mask ) ;
/* Enable TX empty, STOP, NACK interrupts */
mask = STM32F7_I2C_CR1_STOPIE | STM32F7_I2C_CR1_NACKIE |
STM32F7_I2C_CR1_TXIE ;
stm32f7_i2c_set_bits ( base + STM32F7_I2C_CR1 , mask ) ;
2019-09-30 17:28:01 +02:00
/* Write 1st data byte */
writel_relaxed ( value , base + STM32F7_I2C_TXDR ) ;
2018-04-11 15:24:54 +02:00
} else {
/* Notify i2c slave that new write transfer is starting */
i2c_slave_event ( slave , I2C_SLAVE_WRITE_REQUESTED , & value ) ;
/* Set reload mode to be able to ACK/NACK each received byte */
mask = STM32F7_I2C_CR2_RELOAD ;
stm32f7_i2c_set_bits ( base + STM32F7_I2C_CR2 , mask ) ;
/*
* Set STOP , NACK , RX empty and transfer complete interrupts . *
* Set Slave Byte Control to be able to ACK / NACK each data
* byte received
*/
mask = STM32F7_I2C_CR1_STOPIE | STM32F7_I2C_CR1_NACKIE |
STM32F7_I2C_CR1_SBC | STM32F7_I2C_CR1_RXIE |
STM32F7_I2C_CR1_TCIE ;
stm32f7_i2c_set_bits ( base + STM32F7_I2C_CR1 , mask ) ;
}
}
static void stm32f7_i2c_slave_addr ( struct stm32f7_i2c_dev * i2c_dev )
{
void __iomem * base = i2c_dev - > base ;
u32 isr , addcode , dir , mask ;
int i ;
isr = readl_relaxed ( i2c_dev - > base + STM32F7_I2C_ISR ) ;
addcode = STM32F7_I2C_ISR_ADDCODE_GET ( isr ) ;
dir = isr & STM32F7_I2C_ISR_DIR ;
for ( i = 0 ; i < STM32F7_I2C_MAX_SLAVE ; i + + ) {
if ( stm32f7_i2c_is_addr_match ( i2c_dev - > slave [ i ] , addcode ) ) {
i2c_dev - > slave_running = i2c_dev - > slave [ i ] ;
i2c_dev - > slave_dir = dir ;
/* Start I2C slave processing */
stm32f7_i2c_slave_start ( i2c_dev ) ;
/* Clear ADDR flag */
mask = STM32F7_I2C_ICR_ADDRCF ;
writel_relaxed ( mask , base + STM32F7_I2C_ICR ) ;
break ;
}
}
}
static int stm32f7_i2c_get_slave_id ( struct stm32f7_i2c_dev * i2c_dev ,
struct i2c_client * slave , int * id )
{
int i ;
for ( i = 0 ; i < STM32F7_I2C_MAX_SLAVE ; i + + ) {
if ( i2c_dev - > slave [ i ] = = slave ) {
* id = i ;
return 0 ;
}
}
dev_err ( i2c_dev - > dev , " Slave 0x%x not registered \n " , slave - > addr ) ;
return - ENODEV ;
}
static int stm32f7_i2c_get_free_slave_id ( struct stm32f7_i2c_dev * i2c_dev ,
struct i2c_client * slave , int * id )
{
struct device * dev = i2c_dev - > dev ;
int i ;
/*
2020-09-15 11:11:41 +02:00
* slave [ STM32F7_SLAVE_HOSTNOTIFY ] support only SMBus Host address ( 0x8 )
* slave [ STM32F7_SLAVE_7_10_BITS_ADDR ] supports 7 - bit and 10 - bit slave address
* slave [ STM32F7_SLAVE_7_BITS_ADDR ] supports 7 - bit slave address only
2018-04-11 15:24:54 +02:00
*/
2020-08-03 07:17:56 +02:00
if ( i2c_dev - > smbus_mode & & ( slave - > addr = = 0x08 ) ) {
2020-09-15 11:11:41 +02:00
if ( i2c_dev - > slave [ STM32F7_SLAVE_HOSTNOTIFY ] )
2020-08-03 07:17:56 +02:00
goto fail ;
2020-09-15 11:11:41 +02:00
* id = STM32F7_SLAVE_HOSTNOTIFY ;
2020-08-03 07:17:56 +02:00
return 0 ;
}
2020-09-15 11:11:41 +02:00
for ( i = STM32F7_I2C_MAX_SLAVE - 1 ; i > STM32F7_SLAVE_HOSTNOTIFY ; i - - ) {
if ( ( i = = STM32F7_SLAVE_7_BITS_ADDR ) & &
( slave - > flags & I2C_CLIENT_TEN ) )
2018-04-11 15:24:54 +02:00
continue ;
if ( ! i2c_dev - > slave [ i ] ) {
* id = i ;
return 0 ;
}
}
2020-08-03 07:17:56 +02:00
fail :
2018-04-11 15:24:54 +02:00
dev_err ( dev , " Slave 0x%x could not be registered \n " , slave - > addr ) ;
return - EINVAL ;
}
static bool stm32f7_i2c_is_slave_registered ( struct stm32f7_i2c_dev * i2c_dev )
{
int i ;
for ( i = 0 ; i < STM32F7_I2C_MAX_SLAVE ; i + + ) {
if ( i2c_dev - > slave [ i ] )
return true ;
}
return false ;
}
static bool stm32f7_i2c_is_slave_busy ( struct stm32f7_i2c_dev * i2c_dev )
{
int i , busy ;
busy = 0 ;
for ( i = 0 ; i < STM32F7_I2C_MAX_SLAVE ; i + + ) {
if ( i2c_dev - > slave [ i ] )
busy + + ;
}
return i = = busy ;
}
static irqreturn_t stm32f7_i2c_slave_isr_event ( struct stm32f7_i2c_dev * i2c_dev )
{
void __iomem * base = i2c_dev - > base ;
u32 cr2 , status , mask ;
u8 val ;
int ret ;
status = readl_relaxed ( i2c_dev - > base + STM32F7_I2C_ISR ) ;
/* Slave transmitter mode */
if ( status & STM32F7_I2C_ISR_TXIS ) {
i2c_slave_event ( i2c_dev - > slave_running ,
I2C_SLAVE_READ_PROCESSED ,
& val ) ;
/* Write data byte */
writel_relaxed ( val , base + STM32F7_I2C_TXDR ) ;
}
/* Transfer Complete Reload for Slave receiver mode */
if ( status & STM32F7_I2C_ISR_TCR | | status & STM32F7_I2C_ISR_RXNE ) {
/*
* Read data byte then set NBYTES to receive next byte or NACK
* the current received byte
*/
val = readb_relaxed ( i2c_dev - > base + STM32F7_I2C_RXDR ) ;
ret = i2c_slave_event ( i2c_dev - > slave_running ,
I2C_SLAVE_WRITE_RECEIVED ,
& val ) ;
if ( ! ret ) {
cr2 = readl_relaxed ( i2c_dev - > base + STM32F7_I2C_CR2 ) ;
cr2 | = STM32F7_I2C_CR2_NBYTES ( 1 ) ;
writel_relaxed ( cr2 , i2c_dev - > base + STM32F7_I2C_CR2 ) ;
} else {
mask = STM32F7_I2C_CR2_NACK ;
stm32f7_i2c_set_bits ( base + STM32F7_I2C_CR2 , mask ) ;
}
}
/* NACK received */
if ( status & STM32F7_I2C_ISR_NACKF ) {
dev_dbg ( i2c_dev - > dev , " <%s>: Receive NACK \n " , __func__ ) ;
writel_relaxed ( STM32F7_I2C_ICR_NACKCF , base + STM32F7_I2C_ICR ) ;
}
/* STOP received */
if ( status & STM32F7_I2C_ISR_STOPF ) {
/* Disable interrupts */
stm32f7_i2c_disable_irq ( i2c_dev , STM32F7_I2C_XFER_IRQ_MASK ) ;
if ( i2c_dev - > slave_dir ) {
/*
* Flush TX buffer in order to not used the byte in
* TXDR for the next transfer
*/
mask = STM32F7_I2C_ISR_TXE ;
stm32f7_i2c_set_bits ( base + STM32F7_I2C_ISR , mask ) ;
}
/* Clear STOP flag */
writel_relaxed ( STM32F7_I2C_ICR_STOPCF , base + STM32F7_I2C_ICR ) ;
/* Notify i2c slave that a STOP flag has been detected */
i2c_slave_event ( i2c_dev - > slave_running , I2C_SLAVE_STOP , & val ) ;
i2c_dev - > slave_running = NULL ;
}
/* Address match received */
if ( status & STM32F7_I2C_ISR_ADDR )
stm32f7_i2c_slave_addr ( i2c_dev ) ;
return IRQ_HANDLED ;
2017-09-14 16:28:37 +02:00
}
static irqreturn_t stm32f7_i2c_isr_event ( int irq , void * data )
{
struct stm32f7_i2c_dev * i2c_dev = data ;
2023-12-15 18:06:06 +01:00
u32 status ;
2018-04-11 15:24:54 +02:00
2023-12-15 18:06:06 +01:00
/* Check if the interrupt is for a slave device */
if ( ! i2c_dev - > master_mode )
return IRQ_WAKE_THREAD ;
2017-09-14 16:28:37 +02:00
status = readl_relaxed ( i2c_dev - > base + STM32F7_I2C_ISR ) ;
/* Tx empty */
if ( status & STM32F7_I2C_ISR_TXIS )
stm32f7_i2c_write_tx_data ( i2c_dev ) ;
/* RX not empty */
if ( status & STM32F7_I2C_ISR_RXNE )
stm32f7_i2c_read_rx_data ( i2c_dev ) ;
2023-12-15 18:06:06 +01:00
/* Wake up the thread if other flags are raised */
if ( status &
( STM32F7_I2C_ISR_NACKF | STM32F7_I2C_ISR_STOPF |
STM32F7_I2C_ISR_TC | STM32F7_I2C_ISR_TCR ) )
return IRQ_WAKE_THREAD ;
return IRQ_HANDLED ;
}
static irqreturn_t stm32f7_i2c_isr_event_thread ( int irq , void * data )
{
struct stm32f7_i2c_dev * i2c_dev = data ;
struct stm32f7_i2c_msg * f7_msg = & i2c_dev - > f7_msg ;
struct stm32_i2c_dma * dma = i2c_dev - > dma ;
void __iomem * base = i2c_dev - > base ;
u32 status , mask ;
int ret ;
if ( ! i2c_dev - > master_mode )
return stm32f7_i2c_slave_isr_event ( i2c_dev ) ;
status = readl_relaxed ( i2c_dev - > base + STM32F7_I2C_ISR ) ;
2017-09-14 16:28:37 +02:00
/* NACK received */
if ( status & STM32F7_I2C_ISR_NACKF ) {
2020-03-19 19:21:55 +01:00
dev_dbg ( i2c_dev - > dev , " <%s>: Receive NACK (addr %x) \n " ,
__func__ , f7_msg - > addr ) ;
2017-09-14 16:28:37 +02:00
writel_relaxed ( STM32F7_I2C_ICR_NACKCF , base + STM32F7_I2C_ICR ) ;
2021-09-20 17:21:31 +02:00
if ( i2c_dev - > use_dma ) {
stm32f7_i2c_disable_dma_req ( i2c_dev ) ;
2021-09-20 17:21:32 +02:00
dmaengine_terminate_async ( dma - > chan_using ) ;
2021-09-20 17:21:31 +02:00
}
2017-09-14 16:28:37 +02:00
f7_msg - > result = - ENXIO ;
}
2023-12-15 18:06:06 +01:00
if ( status & STM32F7_I2C_ISR_TCR ) {
if ( f7_msg - > smbus )
stm32f7_i2c_smbus_reload ( i2c_dev ) ;
2018-04-11 15:24:54 +02:00
else
2023-12-15 18:06:06 +01:00
stm32f7_i2c_reload ( i2c_dev ) ;
2017-09-14 16:28:37 +02:00
}
/* Transfer complete */
if ( status & STM32F7_I2C_ISR_TC ) {
2023-12-15 18:06:06 +01:00
/* Wait for dma transfer completion before sending next message */
if ( i2c_dev - > use_dma & & ! f7_msg - > result ) {
ret = wait_for_completion_timeout ( & i2c_dev - > dma - > dma_complete , HZ ) ;
if ( ! ret ) {
dev_dbg ( i2c_dev - > dev , " <%s>: Timed out \n " , __func__ ) ;
stm32f7_i2c_disable_dma_req ( i2c_dev ) ;
dmaengine_terminate_async ( dma - > chan_using ) ;
f7_msg - > result = - ETIMEDOUT ;
}
}
2017-09-14 16:28:37 +02:00
if ( f7_msg - > stop ) {
mask = STM32F7_I2C_CR2_STOP ;
stm32f7_i2c_set_bits ( base + STM32F7_I2C_CR2 , mask ) ;
2018-04-11 15:24:55 +02:00
} else if ( f7_msg - > smbus ) {
stm32f7_i2c_smbus_rep_start ( i2c_dev ) ;
2017-09-14 16:28:37 +02:00
} else {
i2c_dev - > msg_id + + ;
i2c_dev - > msg + + ;
stm32f7_i2c_xfer_msg ( i2c_dev , i2c_dev - > msg ) ;
}
}
2023-12-15 18:06:06 +01:00
/* STOP detection flag */
if ( status & STM32F7_I2C_ISR_STOPF ) {
/* Disable interrupts */
if ( stm32f7_i2c_is_slave_registered ( i2c_dev ) )
mask = STM32F7_I2C_XFER_IRQ_MASK ;
2018-04-11 15:24:55 +02:00
else
2023-12-15 18:06:06 +01:00
mask = STM32F7_I2C_ALL_IRQ_MASK ;
stm32f7_i2c_disable_irq ( i2c_dev , mask ) ;
2018-04-11 15:24:57 +02:00
2023-12-15 18:06:06 +01:00
/* Clear STOP flag */
writel_relaxed ( STM32F7_I2C_ICR_STOPCF , base + STM32F7_I2C_ICR ) ;
2018-04-11 15:24:57 +02:00
i2c_dev - > master_mode = false ;
complete ( & i2c_dev - > complete ) ;
}
2017-09-14 16:28:37 +02:00
return IRQ_HANDLED ;
}
2023-12-15 18:06:06 +01:00
static irqreturn_t stm32f7_i2c_isr_error_thread ( int irq , void * data )
2017-09-14 16:28:37 +02:00
{
struct stm32f7_i2c_dev * i2c_dev = data ;
struct stm32f7_i2c_msg * f7_msg = & i2c_dev - > f7_msg ;
2023-12-15 18:06:07 +01:00
u16 addr = f7_msg - > addr ;
2017-09-14 16:28:37 +02:00
void __iomem * base = i2c_dev - > base ;
struct device * dev = i2c_dev - > dev ;
2018-04-11 15:24:57 +02:00
struct stm32_i2c_dma * dma = i2c_dev - > dma ;
2019-10-01 10:51:09 +02:00
u32 status ;
2017-09-14 16:28:37 +02:00
status = readl_relaxed ( i2c_dev - > base + STM32F7_I2C_ISR ) ;
/* Bus error */
if ( status & STM32F7_I2C_ISR_BERR ) {
2023-12-15 18:06:07 +01:00
dev_err ( dev , " Bus error accessing addr 0x%x \n " , addr ) ;
2017-09-14 16:28:37 +02:00
writel_relaxed ( STM32F7_I2C_ICR_BERRCF , base + STM32F7_I2C_ICR ) ;
2018-04-11 15:24:58 +02:00
stm32f7_i2c_release_bus ( & i2c_dev - > adap ) ;
2017-09-14 16:28:37 +02:00
f7_msg - > result = - EIO ;
}
/* Arbitration loss */
if ( status & STM32F7_I2C_ISR_ARLO ) {
2023-12-15 18:06:07 +01:00
dev_dbg ( dev , " Arbitration loss accessing addr 0x%x \n " , addr ) ;
2017-09-14 16:28:37 +02:00
writel_relaxed ( STM32F7_I2C_ICR_ARLOCF , base + STM32F7_I2C_ICR ) ;
f7_msg - > result = - EAGAIN ;
}
2018-04-11 15:24:55 +02:00
if ( status & STM32F7_I2C_ISR_PECERR ) {
2023-12-15 18:06:07 +01:00
dev_err ( dev , " PEC error in reception accessing addr 0x%x \n " , addr ) ;
2018-04-11 15:24:55 +02:00
writel_relaxed ( STM32F7_I2C_ICR_PECCF , base + STM32F7_I2C_ICR ) ;
f7_msg - > result = - EINVAL ;
}
2021-05-05 15:14:39 +02:00
if ( status & STM32F7_I2C_ISR_ALERT ) {
2023-12-15 18:06:07 +01:00
dev_dbg ( dev , " SMBus alert received \n " ) ;
2021-05-05 15:14:39 +02:00
writel_relaxed ( STM32F7_I2C_ICR_ALERTCF , base + STM32F7_I2C_ICR ) ;
i2c_handle_smbus_alert ( i2c_dev - > alert - > ara ) ;
return IRQ_HANDLED ;
}
2019-10-01 10:51:09 +02:00
if ( ! i2c_dev - > slave_running ) {
u32 mask ;
/* Disable interrupts */
if ( stm32f7_i2c_is_slave_registered ( i2c_dev ) )
mask = STM32F7_I2C_XFER_IRQ_MASK ;
else
mask = STM32F7_I2C_ALL_IRQ_MASK ;
stm32f7_i2c_disable_irq ( i2c_dev , mask ) ;
}
2017-09-14 16:28:37 +02:00
2018-04-11 15:24:57 +02:00
/* Disable dma */
if ( i2c_dev - > use_dma ) {
stm32f7_i2c_disable_dma_req ( i2c_dev ) ;
2021-09-20 17:21:32 +02:00
dmaengine_terminate_async ( dma - > chan_using ) ;
2018-04-11 15:24:57 +02:00
}
2018-04-11 15:24:54 +02:00
i2c_dev - > master_mode = false ;
2017-09-14 16:28:37 +02:00
complete ( & i2c_dev - > complete ) ;
return IRQ_HANDLED ;
}
2023-08-16 10:05:52 +02:00
static int stm32f7_i2c_wait_polling ( struct stm32f7_i2c_dev * i2c_dev )
{
ktime_t timeout = ktime_add_ms ( ktime_get ( ) , i2c_dev - > adap . timeout ) ;
while ( ktime_compare ( ktime_get ( ) , timeout ) < 0 ) {
udelay ( 5 ) ;
stm32f7_i2c_isr_event ( 0 , i2c_dev ) ;
if ( completion_done ( & i2c_dev - > complete ) )
return 1 ;
}
return 0 ;
}
static int stm32f7_i2c_xfer_core ( struct i2c_adapter * i2c_adap ,
2017-09-14 16:28:37 +02:00
struct i2c_msg msgs [ ] , int num )
{
struct stm32f7_i2c_dev * i2c_dev = i2c_get_adapdata ( i2c_adap ) ;
struct stm32f7_i2c_msg * f7_msg = & i2c_dev - > f7_msg ;
2018-04-11 15:24:57 +02:00
struct stm32_i2c_dma * dma = i2c_dev - > dma ;
2017-09-14 16:28:37 +02:00
unsigned long time_left ;
int ret ;
i2c_dev - > msg = msgs ;
i2c_dev - > msg_num = num ;
i2c_dev - > msg_id = 0 ;
2018-04-11 15:24:55 +02:00
f7_msg - > smbus = false ;
2017-09-14 16:28:37 +02:00
2020-12-01 17:31:45 +08:00
ret = pm_runtime_resume_and_get ( i2c_dev - > dev ) ;
2018-11-27 15:35:31 +01:00
if ( ret < 0 )
2017-09-14 16:28:37 +02:00
return ret ;
ret = stm32f7_i2c_wait_free_bus ( i2c_dev ) ;
if ( ret )
2018-11-27 15:35:31 +01:00
goto pm_free ;
2017-09-14 16:28:37 +02:00
stm32f7_i2c_xfer_msg ( i2c_dev , msgs ) ;
2023-08-16 10:05:52 +02:00
if ( ! i2c_dev - > atomic )
time_left = wait_for_completion_timeout ( & i2c_dev - > complete ,
i2c_dev - > adap . timeout ) ;
else
time_left = stm32f7_i2c_wait_polling ( i2c_dev ) ;
2017-09-14 16:28:37 +02:00
ret = f7_msg - > result ;
2021-09-20 17:21:29 +02:00
if ( ret ) {
2021-09-20 17:21:32 +02:00
if ( i2c_dev - > use_dma )
dmaengine_synchronize ( dma - > chan_using ) ;
2021-09-20 17:21:29 +02:00
/*
* It is possible that some unsent data have already been
* written into TXDR . To avoid sending old data in a
* further transfer , flush TXDR in case of any error
*/
writel_relaxed ( STM32F7_I2C_ISR_TXE ,
i2c_dev - > base + STM32F7_I2C_ISR ) ;
goto pm_free ;
}
2017-09-14 16:28:37 +02:00
if ( ! time_left ) {
dev_dbg ( i2c_dev - > dev , " Access to slave 0x%x timed out \n " ,
i2c_dev - > msg - > addr ) ;
2018-04-11 15:24:57 +02:00
if ( i2c_dev - > use_dma )
2021-09-20 17:21:32 +02:00
dmaengine_terminate_sync ( dma - > chan_using ) ;
2021-09-20 17:21:30 +02:00
stm32f7_i2c_wait_free_bus ( i2c_dev ) ;
2017-09-14 16:28:37 +02:00
ret = - ETIMEDOUT ;
}
2018-11-27 15:35:31 +01:00
pm_free :
pm_runtime_mark_last_busy ( i2c_dev - > dev ) ;
pm_runtime_put_autosuspend ( i2c_dev - > dev ) ;
2017-09-14 16:28:37 +02:00
return ( ret < 0 ) ? ret : num ;
}
2023-08-16 10:05:52 +02:00
static int stm32f7_i2c_xfer ( struct i2c_adapter * i2c_adap ,
struct i2c_msg msgs [ ] , int num )
{
struct stm32f7_i2c_dev * i2c_dev = i2c_get_adapdata ( i2c_adap ) ;
i2c_dev - > atomic = false ;
return stm32f7_i2c_xfer_core ( i2c_adap , msgs , num ) ;
}
static int stm32f7_i2c_xfer_atomic ( struct i2c_adapter * i2c_adap ,
struct i2c_msg msgs [ ] , int num )
{
struct stm32f7_i2c_dev * i2c_dev = i2c_get_adapdata ( i2c_adap ) ;
i2c_dev - > atomic = true ;
return stm32f7_i2c_xfer_core ( i2c_adap , msgs , num ) ;
}
2018-04-11 15:24:55 +02:00
static int stm32f7_i2c_smbus_xfer ( struct i2c_adapter * adapter , u16 addr ,
unsigned short flags , char read_write ,
u8 command , int size ,
union i2c_smbus_data * data )
{
struct stm32f7_i2c_dev * i2c_dev = i2c_get_adapdata ( adapter ) ;
struct stm32f7_i2c_msg * f7_msg = & i2c_dev - > f7_msg ;
2018-04-11 15:24:57 +02:00
struct stm32_i2c_dma * dma = i2c_dev - > dma ;
2018-04-11 15:24:55 +02:00
struct device * dev = i2c_dev - > dev ;
unsigned long timeout ;
int i , ret ;
f7_msg - > addr = addr ;
f7_msg - > size = size ;
f7_msg - > read_write = read_write ;
f7_msg - > smbus = true ;
2020-12-01 17:31:45 +08:00
ret = pm_runtime_resume_and_get ( dev ) ;
2018-11-27 15:35:31 +01:00
if ( ret < 0 )
2018-04-11 15:24:55 +02:00
return ret ;
ret = stm32f7_i2c_wait_free_bus ( i2c_dev ) ;
if ( ret )
2018-11-27 15:35:31 +01:00
goto pm_free ;
2018-04-11 15:24:55 +02:00
ret = stm32f7_i2c_smbus_xfer_msg ( i2c_dev , flags , command , data ) ;
if ( ret )
2018-11-27 15:35:31 +01:00
goto pm_free ;
2018-04-11 15:24:55 +02:00
timeout = wait_for_completion_timeout ( & i2c_dev - > complete ,
i2c_dev - > adap . timeout ) ;
ret = f7_msg - > result ;
2021-09-20 17:21:29 +02:00
if ( ret ) {
2021-09-20 17:21:32 +02:00
if ( i2c_dev - > use_dma )
dmaengine_synchronize ( dma - > chan_using ) ;
2021-09-20 17:21:29 +02:00
/*
* It is possible that some unsent data have already been
* written into TXDR . To avoid sending old data in a
* further transfer , flush TXDR in case of any error
*/
writel_relaxed ( STM32F7_I2C_ISR_TXE ,
i2c_dev - > base + STM32F7_I2C_ISR ) ;
2018-11-27 15:35:31 +01:00
goto pm_free ;
2021-09-20 17:21:29 +02:00
}
2018-04-11 15:24:55 +02:00
if ( ! timeout ) {
dev_dbg ( dev , " Access to slave 0x%x timed out \n " , f7_msg - > addr ) ;
2018-04-11 15:24:57 +02:00
if ( i2c_dev - > use_dma )
2021-09-20 17:21:32 +02:00
dmaengine_terminate_sync ( dma - > chan_using ) ;
2021-09-20 17:21:30 +02:00
stm32f7_i2c_wait_free_bus ( i2c_dev ) ;
2018-04-11 15:24:55 +02:00
ret = - ETIMEDOUT ;
2018-11-27 15:35:31 +01:00
goto pm_free ;
2018-04-11 15:24:55 +02:00
}
/* Check PEC */
if ( ( flags & I2C_CLIENT_PEC ) & & size ! = I2C_SMBUS_QUICK & & read_write ) {
ret = stm32f7_i2c_smbus_check_pec ( i2c_dev ) ;
if ( ret )
2018-11-27 15:35:31 +01:00
goto pm_free ;
2018-04-11 15:24:55 +02:00
}
if ( read_write & & size ! = I2C_SMBUS_QUICK ) {
switch ( size ) {
case I2C_SMBUS_BYTE :
case I2C_SMBUS_BYTE_DATA :
data - > byte = f7_msg - > smbus_buf [ 0 ] ;
break ;
case I2C_SMBUS_WORD_DATA :
case I2C_SMBUS_PROC_CALL :
data - > word = f7_msg - > smbus_buf [ 0 ] |
( f7_msg - > smbus_buf [ 1 ] < < 8 ) ;
break ;
case I2C_SMBUS_BLOCK_DATA :
case I2C_SMBUS_BLOCK_PROC_CALL :
for ( i = 0 ; i < = f7_msg - > smbus_buf [ 0 ] ; i + + )
data - > block [ i ] = f7_msg - > smbus_buf [ i ] ;
break ;
default :
dev_err ( dev , " Unsupported smbus transaction \n " ) ;
ret = - EINVAL ;
}
}
2018-11-27 15:35:31 +01:00
pm_free :
pm_runtime_mark_last_busy ( dev ) ;
pm_runtime_put_autosuspend ( dev ) ;
2018-04-11 15:24:55 +02:00
return ret ;
}
2020-02-03 18:52:08 +01:00
static void stm32f7_i2c_enable_wakeup ( struct stm32f7_i2c_dev * i2c_dev ,
bool enable )
{
void __iomem * base = i2c_dev - > base ;
u32 mask = STM32F7_I2C_CR1_WUPEN ;
if ( ! i2c_dev - > wakeup_src )
return ;
if ( enable ) {
device_set_wakeup_enable ( i2c_dev - > dev , true ) ;
stm32f7_i2c_set_bits ( base + STM32F7_I2C_CR1 , mask ) ;
} else {
device_set_wakeup_enable ( i2c_dev - > dev , false ) ;
stm32f7_i2c_clr_bits ( base + STM32F7_I2C_CR1 , mask ) ;
}
}
2018-04-11 15:24:54 +02:00
static int stm32f7_i2c_reg_slave ( struct i2c_client * slave )
{
struct stm32f7_i2c_dev * i2c_dev = i2c_get_adapdata ( slave - > adapter ) ;
void __iomem * base = i2c_dev - > base ;
struct device * dev = i2c_dev - > dev ;
u32 oar1 , oar2 , mask ;
int id , ret ;
if ( slave - > flags & I2C_CLIENT_PEC ) {
dev_err ( dev , " SMBus PEC not supported in slave mode \n " ) ;
return - EINVAL ;
}
if ( stm32f7_i2c_is_slave_busy ( i2c_dev ) ) {
dev_err ( dev , " Too much slave registered \n " ) ;
return - EBUSY ;
}
ret = stm32f7_i2c_get_free_slave_id ( i2c_dev , slave , & id ) ;
if ( ret )
return ret ;
2020-12-01 17:31:45 +08:00
ret = pm_runtime_resume_and_get ( dev ) ;
2018-11-27 15:35:31 +01:00
if ( ret < 0 )
return ret ;
2018-04-11 15:24:54 +02:00
2020-02-03 18:52:08 +01:00
if ( ! stm32f7_i2c_is_slave_registered ( i2c_dev ) )
stm32f7_i2c_enable_wakeup ( i2c_dev , true ) ;
2020-08-03 07:17:56 +02:00
switch ( id ) {
case 0 :
/* Slave SMBus Host */
i2c_dev - > slave [ id ] = slave ;
break ;
case 1 :
2018-04-11 15:24:54 +02:00
/* Configure Own Address 1 */
oar1 = readl_relaxed ( i2c_dev - > base + STM32F7_I2C_OAR1 ) ;
oar1 & = ~ STM32F7_I2C_OAR1_MASK ;
if ( slave - > flags & I2C_CLIENT_TEN ) {
oar1 | = STM32F7_I2C_OAR1_OA1_10 ( slave - > addr ) ;
oar1 | = STM32F7_I2C_OAR1_OA1MODE ;
} else {
oar1 | = STM32F7_I2C_OAR1_OA1_7 ( slave - > addr ) ;
}
oar1 | = STM32F7_I2C_OAR1_OA1EN ;
i2c_dev - > slave [ id ] = slave ;
writel_relaxed ( oar1 , i2c_dev - > base + STM32F7_I2C_OAR1 ) ;
2020-08-03 07:17:56 +02:00
break ;
case 2 :
2018-04-11 15:24:54 +02:00
/* Configure Own Address 2 */
oar2 = readl_relaxed ( i2c_dev - > base + STM32F7_I2C_OAR2 ) ;
oar2 & = ~ STM32F7_I2C_OAR2_MASK ;
if ( slave - > flags & I2C_CLIENT_TEN ) {
ret = - EOPNOTSUPP ;
2018-11-27 15:35:31 +01:00
goto pm_free ;
2018-04-11 15:24:54 +02:00
}
oar2 | = STM32F7_I2C_OAR2_OA2_7 ( slave - > addr ) ;
oar2 | = STM32F7_I2C_OAR2_OA2EN ;
i2c_dev - > slave [ id ] = slave ;
writel_relaxed ( oar2 , i2c_dev - > base + STM32F7_I2C_OAR2 ) ;
2020-08-03 07:17:56 +02:00
break ;
default :
dev_err ( dev , " I2C slave id not supported \n " ) ;
2018-04-11 15:24:54 +02:00
ret = - ENODEV ;
2018-11-27 15:35:31 +01:00
goto pm_free ;
2018-04-11 15:24:54 +02:00
}
/* Enable ACK */
stm32f7_i2c_clr_bits ( base + STM32F7_I2C_CR2 , STM32F7_I2C_CR2_NACK ) ;
/* Enable Address match interrupt, error interrupt and enable I2C */
mask = STM32F7_I2C_CR1_ADDRIE | STM32F7_I2C_CR1_ERRIE |
STM32F7_I2C_CR1_PE ;
stm32f7_i2c_set_bits ( base + STM32F7_I2C_CR1 , mask ) ;
2018-11-27 15:35:31 +01:00
ret = 0 ;
pm_free :
2020-02-03 18:52:08 +01:00
if ( ! stm32f7_i2c_is_slave_registered ( i2c_dev ) )
stm32f7_i2c_enable_wakeup ( i2c_dev , false ) ;
2018-11-27 15:35:31 +01:00
pm_runtime_mark_last_busy ( dev ) ;
pm_runtime_put_autosuspend ( dev ) ;
2018-04-11 15:24:54 +02:00
return ret ;
}
static int stm32f7_i2c_unreg_slave ( struct i2c_client * slave )
{
struct stm32f7_i2c_dev * i2c_dev = i2c_get_adapdata ( slave - > adapter ) ;
void __iomem * base = i2c_dev - > base ;
u32 mask ;
int id , ret ;
ret = stm32f7_i2c_get_slave_id ( i2c_dev , slave , & id ) ;
if ( ret )
return ret ;
WARN_ON ( ! i2c_dev - > slave [ id ] ) ;
2020-12-01 17:31:45 +08:00
ret = pm_runtime_resume_and_get ( i2c_dev - > dev ) ;
2018-11-27 15:35:31 +01:00
if ( ret < 0 )
return ret ;
2020-08-03 07:17:56 +02:00
if ( id = = 1 ) {
2018-04-11 15:24:54 +02:00
mask = STM32F7_I2C_OAR1_OA1EN ;
stm32f7_i2c_clr_bits ( base + STM32F7_I2C_OAR1 , mask ) ;
2020-08-03 07:17:56 +02:00
} else if ( id = = 2 ) {
2018-04-11 15:24:54 +02:00
mask = STM32F7_I2C_OAR2_OA2EN ;
stm32f7_i2c_clr_bits ( base + STM32F7_I2C_OAR2 , mask ) ;
}
i2c_dev - > slave [ id ] = NULL ;
2020-02-03 18:52:08 +01:00
if ( ! stm32f7_i2c_is_slave_registered ( i2c_dev ) ) {
2018-04-11 15:24:54 +02:00
stm32f7_i2c_disable_irq ( i2c_dev , STM32F7_I2C_ALL_IRQ_MASK ) ;
2020-02-03 18:52:08 +01:00
stm32f7_i2c_enable_wakeup ( i2c_dev , false ) ;
}
2018-11-27 15:35:31 +01:00
pm_runtime_mark_last_busy ( i2c_dev - > dev ) ;
pm_runtime_put_autosuspend ( i2c_dev - > dev ) ;
2018-04-11 15:24:54 +02:00
return 0 ;
}
2020-03-02 12:33:07 +01:00
static int stm32f7_i2c_write_fm_plus_bits ( struct stm32f7_i2c_dev * i2c_dev ,
bool enable )
{
2020-03-02 12:33:16 +01:00
int ret ;
2020-04-20 16:57:57 +02:00
if ( i2c_dev - > bus_rate < = I2C_MAX_FAST_MODE_FREQ | |
2020-03-02 12:33:07 +01:00
IS_ERR_OR_NULL ( i2c_dev - > regmap ) )
/* Optional */
return 0 ;
2020-03-02 12:33:16 +01:00
if ( i2c_dev - > fmp_sreg = = i2c_dev - > fmp_creg )
ret = regmap_update_bits ( i2c_dev - > regmap ,
i2c_dev - > fmp_sreg ,
i2c_dev - > fmp_mask ,
enable ? i2c_dev - > fmp_mask : 0 ) ;
else
ret = regmap_write ( i2c_dev - > regmap ,
enable ? i2c_dev - > fmp_sreg :
i2c_dev - > fmp_creg ,
i2c_dev - > fmp_mask ) ;
return ret ;
2020-03-02 12:33:07 +01:00
}
2018-11-19 12:03:32 +01:00
static int stm32f7_i2c_setup_fm_plus_bits ( struct platform_device * pdev ,
struct stm32f7_i2c_dev * i2c_dev )
{
struct device_node * np = pdev - > dev . of_node ;
int ret ;
i2c_dev - > regmap = syscon_regmap_lookup_by_phandle ( np , " st,syscfg-fmp " ) ;
2020-03-02 12:33:07 +01:00
if ( IS_ERR ( i2c_dev - > regmap ) )
2018-11-19 12:03:32 +01:00
/* Optional */
return 0 ;
2020-03-02 12:33:07 +01:00
ret = of_property_read_u32_index ( np , " st,syscfg-fmp " , 1 ,
2020-03-02 12:33:16 +01:00
& i2c_dev - > fmp_sreg ) ;
2018-11-19 12:03:32 +01:00
if ( ret )
return ret ;
2020-03-02 12:33:16 +01:00
i2c_dev - > fmp_creg = i2c_dev - > fmp_sreg +
i2c_dev - > setup . fmp_clr_offset ;
2020-03-02 12:33:07 +01:00
return of_property_read_u32_index ( np , " st,syscfg-fmp " , 2 ,
& i2c_dev - > fmp_mask ) ;
2018-11-19 12:03:32 +01:00
}
2020-08-03 07:17:56 +02:00
static int stm32f7_i2c_enable_smbus_host ( struct stm32f7_i2c_dev * i2c_dev )
{
struct i2c_adapter * adap = & i2c_dev - > adap ;
void __iomem * base = i2c_dev - > base ;
struct i2c_client * client ;
client = i2c_new_slave_host_notify_device ( adap ) ;
if ( IS_ERR ( client ) )
return PTR_ERR ( client ) ;
i2c_dev - > host_notify_client = client ;
/* Enable SMBus Host address */
stm32f7_i2c_set_bits ( base + STM32F7_I2C_CR1 , STM32F7_I2C_CR1_SMBHEN ) ;
return 0 ;
}
static void stm32f7_i2c_disable_smbus_host ( struct stm32f7_i2c_dev * i2c_dev )
{
void __iomem * base = i2c_dev - > base ;
if ( i2c_dev - > host_notify_client ) {
/* Disable SMBus Host address */
stm32f7_i2c_clr_bits ( base + STM32F7_I2C_CR1 ,
STM32F7_I2C_CR1_SMBHEN ) ;
i2c_free_slave_host_notify_device ( i2c_dev - > host_notify_client ) ;
}
}
2021-05-05 15:14:39 +02:00
static int stm32f7_i2c_enable_smbus_alert ( struct stm32f7_i2c_dev * i2c_dev )
{
struct stm32f7_i2c_alert * alert ;
struct i2c_adapter * adap = & i2c_dev - > adap ;
struct device * dev = i2c_dev - > dev ;
void __iomem * base = i2c_dev - > base ;
alert = devm_kzalloc ( dev , sizeof ( * alert ) , GFP_KERNEL ) ;
if ( ! alert )
return - ENOMEM ;
alert - > ara = i2c_new_smbus_alert_device ( adap , & alert - > setup ) ;
if ( IS_ERR ( alert - > ara ) )
return PTR_ERR ( alert - > ara ) ;
i2c_dev - > alert = alert ;
/* Enable SMBus Alert */
stm32f7_i2c_set_bits ( base + STM32F7_I2C_CR1 , STM32F7_I2C_CR1_ALERTEN ) ;
return 0 ;
}
static void stm32f7_i2c_disable_smbus_alert ( struct stm32f7_i2c_dev * i2c_dev )
{
struct stm32f7_i2c_alert * alert = i2c_dev - > alert ;
void __iomem * base = i2c_dev - > base ;
if ( alert ) {
/* Disable SMBus Alert */
stm32f7_i2c_clr_bits ( base + STM32F7_I2C_CR1 ,
STM32F7_I2C_CR1_ALERTEN ) ;
i2c_unregister_device ( alert - > ara ) ;
}
}
2017-09-14 16:28:37 +02:00
static u32 stm32f7_i2c_func ( struct i2c_adapter * adap )
{
2020-08-03 07:17:56 +02:00
struct stm32f7_i2c_dev * i2c_dev = i2c_get_adapdata ( adap ) ;
u32 func = I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR | I2C_FUNC_SLAVE |
I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_BLOCK_PROC_CALL |
I2C_FUNC_SMBUS_PROC_CALL | I2C_FUNC_SMBUS_PEC |
I2C_FUNC_SMBUS_I2C_BLOCK ;
if ( i2c_dev - > smbus_mode )
func | = I2C_FUNC_SMBUS_HOST_NOTIFY ;
return func ;
2017-09-14 16:28:37 +02:00
}
2019-08-15 11:28:57 +05:30
static const struct i2c_algorithm stm32f7_i2c_algo = {
2017-09-14 16:28:37 +02:00
. master_xfer = stm32f7_i2c_xfer ,
2023-08-16 10:05:52 +02:00
. master_xfer_atomic = stm32f7_i2c_xfer_atomic ,
2018-04-11 15:24:55 +02:00
. smbus_xfer = stm32f7_i2c_smbus_xfer ,
2017-09-14 16:28:37 +02:00
. functionality = stm32f7_i2c_func ,
2018-04-11 15:24:54 +02:00
. reg_slave = stm32f7_i2c_reg_slave ,
. unreg_slave = stm32f7_i2c_unreg_slave ,
2017-09-14 16:28:37 +02:00
} ;
static int stm32f7_i2c_probe ( struct platform_device * pdev )
{
struct stm32f7_i2c_dev * i2c_dev ;
const struct stm32f7_i2c_setup * setup ;
struct resource * res ;
struct i2c_adapter * adap ;
struct reset_control * rst ;
2018-04-11 15:24:57 +02:00
dma_addr_t phy_addr ;
2019-06-17 09:53:01 +02:00
int irq_error , irq_event , ret ;
2017-09-14 16:28:37 +02:00
i2c_dev = devm_kzalloc ( & pdev - > dev , sizeof ( * i2c_dev ) , GFP_KERNEL ) ;
if ( ! i2c_dev )
return - ENOMEM ;
2020-04-14 21:48:27 +08:00
i2c_dev - > base = devm_platform_get_and_ioremap_resource ( pdev , 0 , & res ) ;
2017-09-14 16:28:37 +02:00
if ( IS_ERR ( i2c_dev - > base ) )
return PTR_ERR ( i2c_dev - > base ) ;
2018-04-11 15:24:57 +02:00
phy_addr = ( dma_addr_t ) res - > start ;
2017-09-14 16:28:37 +02:00
2019-06-17 09:53:01 +02:00
irq_event = platform_get_irq ( pdev , 0 ) ;
2023-07-31 19:27:55 +08:00
if ( irq_event < 0 )
return irq_event ;
2017-09-14 16:28:37 +02:00
2019-06-17 09:53:01 +02:00
irq_error = platform_get_irq ( pdev , 1 ) ;
2023-07-31 19:27:55 +08:00
if ( irq_error < 0 )
return irq_error ;
2017-09-14 16:28:37 +02:00
2020-02-03 18:52:08 +01:00
i2c_dev - > wakeup_src = of_property_read_bool ( pdev - > dev . of_node ,
" wakeup-source " ) ;
2023-06-12 00:56:59 +02:00
i2c_dev - > clk = devm_clk_get_enabled ( & pdev - > dev , NULL ) ;
2020-09-14 12:40:34 +02:00
if ( IS_ERR ( i2c_dev - > clk ) )
return dev_err_probe ( & pdev - > dev , PTR_ERR ( i2c_dev - > clk ) ,
2023-06-12 00:56:59 +02:00
" Failed to enable controller clock \n " ) ;
2017-09-14 16:28:37 +02:00
rst = devm_reset_control_get ( & pdev - > dev , NULL ) ;
2023-06-12 00:56:59 +02:00
if ( IS_ERR ( rst ) )
return dev_err_probe ( & pdev - > dev , PTR_ERR ( rst ) ,
" Error: Missing reset ctrl \n " ) ;
2017-09-14 16:28:37 +02:00
reset_control_assert ( rst ) ;
udelay ( 2 ) ;
reset_control_deassert ( rst ) ;
i2c_dev - > dev = & pdev - > dev ;
2018-04-11 15:24:57 +02:00
ret = devm_request_threaded_irq ( & pdev - > dev , irq_event ,
stm32f7_i2c_isr_event ,
stm32f7_i2c_isr_event_thread ,
IRQF_ONESHOT ,
pdev - > name , i2c_dev ) ;
2023-12-15 18:06:05 +01:00
if ( ret )
return dev_err_probe ( & pdev - > dev , ret , " Failed to request irq event \n " ) ;
2017-09-14 16:28:37 +02:00
2023-12-15 18:06:06 +01:00
ret = devm_request_threaded_irq ( & pdev - > dev , irq_error ,
NULL ,
stm32f7_i2c_isr_error_thread ,
IRQF_ONESHOT ,
pdev - > name , i2c_dev ) ;
2023-12-15 18:06:05 +01:00
if ( ret )
return dev_err_probe ( & pdev - > dev , ret , " Failed to request irq error \n " ) ;
2017-09-14 16:28:37 +02:00
setup = of_device_get_match_data ( & pdev - > dev ) ;
2018-03-21 17:48:40 +01:00
if ( ! setup ) {
dev_err ( & pdev - > dev , " Can't get device data \n " ) ;
2023-06-12 00:56:59 +02:00
return - ENODEV ;
2018-03-21 17:48:40 +01:00
}
2017-09-21 15:30:09 +02:00
i2c_dev - > setup = * setup ;
2017-09-14 16:28:37 +02:00
2017-09-21 15:30:09 +02:00
ret = stm32f7_i2c_setup_timing ( i2c_dev , & i2c_dev - > setup ) ;
2017-09-14 16:28:37 +02:00
if ( ret )
2023-06-12 00:56:59 +02:00
return ret ;
2017-09-14 16:28:37 +02:00
2020-04-20 16:57:57 +02:00
/* Setup Fast mode plus if necessary */
if ( i2c_dev - > bus_rate > I2C_MAX_FAST_MODE_FREQ ) {
2020-03-02 12:33:07 +01:00
ret = stm32f7_i2c_setup_fm_plus_bits ( pdev , i2c_dev ) ;
if ( ret )
2023-06-12 00:56:59 +02:00
return ret ;
2020-03-02 12:33:07 +01:00
ret = stm32f7_i2c_write_fm_plus_bits ( i2c_dev , true ) ;
if ( ret )
2023-06-12 00:56:59 +02:00
return ret ;
2020-03-02 12:33:07 +01:00
}
2017-09-14 16:28:37 +02:00
adap = & i2c_dev - > adap ;
i2c_set_adapdata ( adap , i2c_dev ) ;
snprintf ( adap - > name , sizeof ( adap - > name ) , " STM32F7 I2C(%pa) " ,
& res - > start ) ;
adap - > owner = THIS_MODULE ;
adap - > timeout = 2 * HZ ;
adap - > retries = 3 ;
adap - > algo = & stm32f7_i2c_algo ;
adap - > dev . parent = & pdev - > dev ;
adap - > dev . of_node = pdev - > dev . of_node ;
init_completion ( & i2c_dev - > complete ) ;
2018-04-11 15:24:57 +02:00
/* Init DMA config if supported */
i2c_dev - > dma = stm32_i2c_dma_request ( i2c_dev - > dev , phy_addr ,
STM32F7_I2C_TXDR ,
STM32F7_I2C_RXDR ) ;
2020-09-14 12:40:33 +02:00
if ( IS_ERR ( i2c_dev - > dma ) ) {
2019-10-24 14:52:00 +02:00
ret = PTR_ERR ( i2c_dev - > dma ) ;
2020-09-14 12:40:33 +02:00
/* DMA support is optional, only report other errors */
if ( ret ! = - ENODEV )
goto fmp_clear ;
dev_dbg ( i2c_dev - > dev , " No DMA option: fallback using interrupts \n " ) ;
i2c_dev - > dma = NULL ;
2019-10-24 14:52:00 +02:00
}
2018-04-11 15:24:57 +02:00
2020-02-03 18:52:08 +01:00
if ( i2c_dev - > wakeup_src ) {
device_set_wakeup_capable ( i2c_dev - > dev , true ) ;
ret = dev_pm_set_wake_irq ( i2c_dev - > dev , irq_event ) ;
if ( ret ) {
dev_err ( i2c_dev - > dev , " Failed to set wake up irq \n " ) ;
goto clr_wakeup_capable ;
}
}
2017-09-14 16:28:37 +02:00
platform_set_drvdata ( pdev , i2c_dev ) ;
2018-11-27 15:35:31 +01:00
pm_runtime_set_autosuspend_delay ( i2c_dev - > dev ,
STM32F7_AUTOSUSPEND_DELAY ) ;
pm_runtime_use_autosuspend ( i2c_dev - > dev ) ;
pm_runtime_set_active ( i2c_dev - > dev ) ;
pm_runtime_enable ( i2c_dev - > dev ) ;
pm_runtime_get_noresume ( & pdev - > dev ) ;
stm32f7_i2c_hw_config ( i2c_dev ) ;
2020-08-03 07:17:56 +02:00
i2c_dev - > smbus_mode = of_property_read_bool ( pdev - > dev . of_node , " smbus " ) ;
2018-11-27 15:35:31 +01:00
ret = i2c_add_adapter ( adap ) ;
if ( ret )
goto pm_disable ;
2017-09-14 16:28:37 +02:00
2020-08-03 07:17:56 +02:00
if ( i2c_dev - > smbus_mode ) {
ret = stm32f7_i2c_enable_smbus_host ( i2c_dev ) ;
if ( ret ) {
dev_err ( i2c_dev - > dev ,
" failed to enable SMBus Host-Notify protocol (%d) \n " ,
ret ) ;
goto i2c_adapter_remove ;
}
}
2021-05-05 15:14:39 +02:00
if ( of_property_read_bool ( pdev - > dev . of_node , " smbus-alert " ) ) {
ret = stm32f7_i2c_enable_smbus_alert ( i2c_dev ) ;
if ( ret ) {
dev_err ( i2c_dev - > dev ,
" failed to enable SMBus alert protocol (%d) \n " ,
ret ) ;
goto i2c_disable_smbus_host ;
}
}
2017-09-14 16:28:37 +02:00
dev_info ( i2c_dev - > dev , " STM32F7 I2C-%d bus adapter \n " , adap - > nr ) ;
2018-11-27 15:35:31 +01:00
pm_runtime_mark_last_busy ( i2c_dev - > dev ) ;
pm_runtime_put_autosuspend ( i2c_dev - > dev ) ;
2017-09-14 16:28:37 +02:00
return 0 ;
2021-05-05 15:14:39 +02:00
i2c_disable_smbus_host :
stm32f7_i2c_disable_smbus_host ( i2c_dev ) ;
2020-08-03 07:17:56 +02:00
i2c_adapter_remove :
i2c_del_adapter ( adap ) ;
2018-11-27 15:35:31 +01:00
pm_disable :
pm_runtime_put_noidle ( i2c_dev - > dev ) ;
pm_runtime_disable ( i2c_dev - > dev ) ;
pm_runtime_set_suspended ( i2c_dev - > dev ) ;
pm_runtime_dont_use_autosuspend ( i2c_dev - > dev ) ;
2020-02-03 18:52:08 +01:00
if ( i2c_dev - > wakeup_src )
dev_pm_clear_wake_irq ( i2c_dev - > dev ) ;
clr_wakeup_capable :
if ( i2c_dev - > wakeup_src )
device_set_wakeup_capable ( i2c_dev - > dev , false ) ;
2019-10-25 16:04:24 +02:00
if ( i2c_dev - > dma ) {
stm32_i2c_dma_free ( i2c_dev - > dma ) ;
i2c_dev - > dma = NULL ;
}
2020-03-02 12:33:07 +01:00
fmp_clear :
stm32f7_i2c_write_fm_plus_bits ( i2c_dev , false ) ;
2017-09-14 16:28:37 +02:00
return ret ;
}
2023-05-08 22:51:38 +02:00
static void stm32f7_i2c_remove ( struct platform_device * pdev )
2017-09-14 16:28:37 +02:00
{
struct stm32f7_i2c_dev * i2c_dev = platform_get_drvdata ( pdev ) ;
2021-05-05 15:14:39 +02:00
stm32f7_i2c_disable_smbus_alert ( i2c_dev ) ;
2020-08-03 07:17:56 +02:00
stm32f7_i2c_disable_smbus_host ( i2c_dev ) ;
2017-09-14 16:28:37 +02:00
i2c_del_adapter ( & i2c_dev - > adap ) ;
2018-11-27 15:35:31 +01:00
pm_runtime_get_sync ( i2c_dev - > dev ) ;
2020-02-03 18:52:08 +01:00
if ( i2c_dev - > wakeup_src ) {
dev_pm_clear_wake_irq ( i2c_dev - > dev ) ;
/*
* enforce that wakeup is disabled and that the device
* is marked as non wakeup capable
*/
device_init_wakeup ( i2c_dev - > dev , false ) ;
}
2018-11-27 15:35:31 +01:00
pm_runtime_put_noidle ( i2c_dev - > dev ) ;
pm_runtime_disable ( i2c_dev - > dev ) ;
pm_runtime_set_suspended ( i2c_dev - > dev ) ;
pm_runtime_dont_use_autosuspend ( i2c_dev - > dev ) ;
2019-10-25 16:04:24 +02:00
if ( i2c_dev - > dma ) {
stm32_i2c_dma_free ( i2c_dev - > dma ) ;
i2c_dev - > dma = NULL ;
}
2020-03-02 12:33:07 +01:00
stm32f7_i2c_write_fm_plus_bits ( i2c_dev , false ) ;
2018-11-27 15:35:31 +01:00
}
2020-01-06 14:28:32 +01:00
static int __maybe_unused stm32f7_i2c_runtime_suspend ( struct device * dev )
2018-11-27 15:35:31 +01:00
{
struct stm32f7_i2c_dev * i2c_dev = dev_get_drvdata ( dev ) ;
if ( ! stm32f7_i2c_is_slave_registered ( i2c_dev ) )
clk_disable_unprepare ( i2c_dev - > clk ) ;
return 0 ;
}
2020-01-06 14:28:32 +01:00
static int __maybe_unused stm32f7_i2c_runtime_resume ( struct device * dev )
2018-11-27 15:35:31 +01:00
{
struct stm32f7_i2c_dev * i2c_dev = dev_get_drvdata ( dev ) ;
int ret ;
2017-09-14 16:28:37 +02:00
2018-11-27 15:35:31 +01:00
if ( ! stm32f7_i2c_is_slave_registered ( i2c_dev ) ) {
ret = clk_prepare_enable ( i2c_dev - > clk ) ;
if ( ret ) {
dev_err ( dev , " failed to prepare_enable clock \n " ) ;
return ret ;
}
}
2017-09-14 16:28:37 +02:00
return 0 ;
}
2020-01-06 14:28:32 +01:00
2021-03-12 12:53:27 +01:00
static int __maybe_unused stm32f7_i2c_regs_backup ( struct stm32f7_i2c_dev * i2c_dev )
2020-01-06 14:28:32 +01:00
{
int ret ;
struct stm32f7_i2c_regs * backup_regs = & i2c_dev - > backup_regs ;
2020-12-01 17:31:45 +08:00
ret = pm_runtime_resume_and_get ( i2c_dev - > dev ) ;
2020-01-06 14:28:32 +01:00
if ( ret < 0 )
return ret ;
backup_regs - > cr1 = readl_relaxed ( i2c_dev - > base + STM32F7_I2C_CR1 ) ;
backup_regs - > cr2 = readl_relaxed ( i2c_dev - > base + STM32F7_I2C_CR2 ) ;
backup_regs - > oar1 = readl_relaxed ( i2c_dev - > base + STM32F7_I2C_OAR1 ) ;
backup_regs - > oar2 = readl_relaxed ( i2c_dev - > base + STM32F7_I2C_OAR2 ) ;
backup_regs - > tmgr = readl_relaxed ( i2c_dev - > base + STM32F7_I2C_TIMINGR ) ;
2020-03-02 12:33:07 +01:00
stm32f7_i2c_write_fm_plus_bits ( i2c_dev , false ) ;
2020-01-06 14:28:32 +01:00
pm_runtime_put_sync ( i2c_dev - > dev ) ;
return ret ;
}
2021-03-12 12:53:27 +01:00
static int __maybe_unused stm32f7_i2c_regs_restore ( struct stm32f7_i2c_dev * i2c_dev )
2020-01-06 14:28:32 +01:00
{
u32 cr1 ;
int ret ;
struct stm32f7_i2c_regs * backup_regs = & i2c_dev - > backup_regs ;
2020-12-01 17:31:45 +08:00
ret = pm_runtime_resume_and_get ( i2c_dev - > dev ) ;
2020-01-06 14:28:32 +01:00
if ( ret < 0 )
return ret ;
cr1 = readl_relaxed ( i2c_dev - > base + STM32F7_I2C_CR1 ) ;
if ( cr1 & STM32F7_I2C_CR1_PE )
stm32f7_i2c_clr_bits ( i2c_dev - > base + STM32F7_I2C_CR1 ,
STM32F7_I2C_CR1_PE ) ;
writel_relaxed ( backup_regs - > tmgr , i2c_dev - > base + STM32F7_I2C_TIMINGR ) ;
writel_relaxed ( backup_regs - > cr1 & ~ STM32F7_I2C_CR1_PE ,
i2c_dev - > base + STM32F7_I2C_CR1 ) ;
if ( backup_regs - > cr1 & STM32F7_I2C_CR1_PE )
stm32f7_i2c_set_bits ( i2c_dev - > base + STM32F7_I2C_CR1 ,
STM32F7_I2C_CR1_PE ) ;
writel_relaxed ( backup_regs - > cr2 , i2c_dev - > base + STM32F7_I2C_CR2 ) ;
writel_relaxed ( backup_regs - > oar1 , i2c_dev - > base + STM32F7_I2C_OAR1 ) ;
writel_relaxed ( backup_regs - > oar2 , i2c_dev - > base + STM32F7_I2C_OAR2 ) ;
2020-03-02 12:33:07 +01:00
stm32f7_i2c_write_fm_plus_bits ( i2c_dev , true ) ;
2020-01-06 14:28:32 +01:00
pm_runtime_put_sync ( i2c_dev - > dev ) ;
return ret ;
}
2021-03-12 12:53:27 +01:00
static int __maybe_unused stm32f7_i2c_suspend ( struct device * dev )
2020-01-06 14:28:32 +01:00
{
struct stm32f7_i2c_dev * i2c_dev = dev_get_drvdata ( dev ) ;
int ret ;
i2c_mark_adapter_suspended ( & i2c_dev - > adap ) ;
2020-11-19 08:25:39 +01:00
if ( ! device_may_wakeup ( dev ) & & ! device_wakeup_path ( dev ) ) {
2020-02-03 18:52:08 +01:00
ret = stm32f7_i2c_regs_backup ( i2c_dev ) ;
if ( ret < 0 ) {
i2c_mark_adapter_resumed ( & i2c_dev - > adap ) ;
return ret ;
}
pinctrl_pm_select_sleep_state ( dev ) ;
pm_runtime_force_suspend ( dev ) ;
}
2020-01-06 14:28:32 +01:00
return 0 ;
}
2021-03-12 12:53:27 +01:00
static int __maybe_unused stm32f7_i2c_resume ( struct device * dev )
2020-01-06 14:28:32 +01:00
{
struct stm32f7_i2c_dev * i2c_dev = dev_get_drvdata ( dev ) ;
int ret ;
2020-11-19 08:25:39 +01:00
if ( ! device_may_wakeup ( dev ) & & ! device_wakeup_path ( dev ) ) {
2020-02-03 18:52:08 +01:00
ret = pm_runtime_force_resume ( dev ) ;
if ( ret < 0 )
return ret ;
pinctrl_pm_select_default_state ( dev ) ;
ret = stm32f7_i2c_regs_restore ( i2c_dev ) ;
if ( ret < 0 )
return ret ;
}
2020-01-06 14:28:32 +01:00
i2c_mark_adapter_resumed ( & i2c_dev - > adap ) ;
return 0 ;
}
2018-11-27 15:35:31 +01:00
static const struct dev_pm_ops stm32f7_i2c_pm_ops = {
SET_RUNTIME_PM_OPS ( stm32f7_i2c_runtime_suspend ,
stm32f7_i2c_runtime_resume , NULL )
2020-01-06 14:28:32 +01:00
SET_SYSTEM_SLEEP_PM_OPS ( stm32f7_i2c_suspend , stm32f7_i2c_resume )
2018-11-27 15:35:31 +01:00
} ;
2017-09-14 16:28:37 +02:00
static const struct of_device_id stm32f7_i2c_match [ ] = {
{ . compatible = " st,stm32f7-i2c " , . data = & stm32f7_setup } ,
2020-03-02 12:33:16 +01:00
{ . compatible = " st,stm32mp15-i2c " , . data = & stm32mp15_setup } ,
2022-07-07 09:44:02 +02:00
{ . compatible = " st,stm32mp13-i2c " , . data = & stm32mp13_setup } ,
2017-09-14 16:28:37 +02:00
{ } ,
} ;
MODULE_DEVICE_TABLE ( of , stm32f7_i2c_match ) ;
static struct platform_driver stm32f7_i2c_driver = {
. driver = {
. name = " stm32f7-i2c " ,
. of_match_table = stm32f7_i2c_match ,
2018-11-27 15:35:31 +01:00
. pm = & stm32f7_i2c_pm_ops ,
2017-09-14 16:28:37 +02:00
} ,
. probe = stm32f7_i2c_probe ,
2023-05-08 22:51:38 +02:00
. remove_new = stm32f7_i2c_remove ,
2017-09-14 16:28:37 +02:00
} ;
module_platform_driver ( stm32f7_i2c_driver ) ;
MODULE_AUTHOR ( " M'boumba Cedric Madianga <cedric.madianga@gmail.com> " ) ;
MODULE_DESCRIPTION ( " STMicroelectronics STM32F7 I2C driver " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;