From 83c3408f7b9c6b0aa8441204801a15a6c1c0665c Mon Sep 17 00:00:00 2001 From: Alain Volmat Date: Fri, 5 Feb 2021 09:51:41 +0100 Subject: i2c: stm32f7: support DT binding i2c-analog-filter Replace driver internally coded enabling/disabling of the analog-filter with the DT binding "i2c-analog-filter". Signed-off-by: Alain Volmat Reviewed-by: Pierre-Yves MORDRET Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-stm32f7.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'drivers/i2c/busses/i2c-stm32f7.c') diff --git a/drivers/i2c/busses/i2c-stm32f7.c b/drivers/i2c/busses/i2c-stm32f7.c index c62c815b88eb..140b1078146b 100644 --- a/drivers/i2c/busses/i2c-stm32f7.c +++ b/drivers/i2c/busses/i2c-stm32f7.c @@ -164,7 +164,6 @@ enum { #define STM32F7_I2C_DNF_DEFAULT 0 #define STM32F7_I2C_DNF_MAX 15 -#define STM32F7_I2C_ANALOG_FILTER_ENABLE 1 #define STM32F7_I2C_ANALOG_FILTER_DELAY_MIN 50 /* ns */ #define STM32F7_I2C_ANALOG_FILTER_DELAY_MAX 260 /* ns */ @@ -224,7 +223,6 @@ struct stm32f7_i2c_spec { * @rise_time: Rise time (ns) * @fall_time: Fall time (ns) * @dnf: Digital filter coefficient (0-16) - * @analog_filter: Analog filter delay (On/Off) * @fmp_clr_offset: Fast Mode Plus clear register offset from set register */ struct stm32f7_i2c_setup { @@ -233,7 +231,6 @@ struct stm32f7_i2c_setup { u32 rise_time; u32 fall_time; u8 dnf; - bool analog_filter; u32 fmp_clr_offset; }; @@ -312,6 +309,7 @@ struct stm32f7_i2c_msg { * @wakeup_src: boolean to know if the device is a wakeup source * @smbus_mode: states that the controller is configured in SMBus mode * @host_notify_client: SMBus host-notify client + * @analog_filter: boolean to indicate enabling of the analog filter */ struct stm32f7_i2c_dev { struct i2c_adapter adap; @@ -340,6 +338,7 @@ struct stm32f7_i2c_dev { bool wakeup_src; bool smbus_mode; struct i2c_client *host_notify_client; + bool analog_filter; }; /* @@ -386,14 +385,12 @@ static const struct stm32f7_i2c_setup stm32f7_setup = { .rise_time = STM32F7_I2C_RISE_TIME_DEFAULT, .fall_time = STM32F7_I2C_FALL_TIME_DEFAULT, .dnf = STM32F7_I2C_DNF_DEFAULT, - .analog_filter = STM32F7_I2C_ANALOG_FILTER_ENABLE, }; static const struct stm32f7_i2c_setup stm32mp15_setup = { .rise_time = STM32F7_I2C_RISE_TIME_DEFAULT, .fall_time = STM32F7_I2C_FALL_TIME_DEFAULT, .dnf = STM32F7_I2C_DNF_DEFAULT, - .analog_filter = STM32F7_I2C_ANALOG_FILTER_ENABLE, .fmp_clr_offset = 0x40, }; @@ -471,10 +468,10 @@ static int stm32f7_i2c_compute_timing(struct stm32f7_i2c_dev *i2c_dev, /* Analog and Digital Filters */ af_delay_min = - (setup->analog_filter ? + (i2c_dev->analog_filter ? STM32F7_I2C_ANALOG_FILTER_DELAY_MIN : 0); af_delay_max = - (setup->analog_filter ? + (i2c_dev->analog_filter ? STM32F7_I2C_ANALOG_FILTER_DELAY_MAX : 0); dnf_delay = setup->dnf * i2cclk; @@ -676,12 +673,15 @@ static int stm32f7_i2c_setup_timing(struct stm32f7_i2c_dev *i2c_dev, return ret; } + i2c_dev->analog_filter = of_property_read_bool(i2c_dev->dev->of_node, + "i2c-analog-filter"); + dev_dbg(i2c_dev->dev, "I2C Speed(%i), Clk Source(%i)\n", setup->speed_freq, setup->clock_src); 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", - (setup->analog_filter ? "On" : "Off"), setup->dnf); + (i2c_dev->analog_filter ? "On" : "Off"), setup->dnf); i2c_dev->bus_rate = setup->speed_freq; @@ -720,8 +720,8 @@ static void stm32f7_i2c_hw_config(struct stm32f7_i2c_dev *i2c_dev) timing |= STM32F7_I2C_TIMINGR_SCLL(t->scll); writel_relaxed(timing, i2c_dev->base + STM32F7_I2C_TIMINGR); - /* Enable I2C */ - if (i2c_dev->setup.analog_filter) + /* Configure the Analog Filter */ + if (i2c_dev->analog_filter) stm32f7_i2c_clr_bits(i2c_dev->base + STM32F7_I2C_CR1, STM32F7_I2C_CR1_ANFOFF); else -- cgit v1.2.3 From 9449a558549978c1fe9af340164b17fa7d12af16 Mon Sep 17 00:00:00 2001 From: Alain Volmat Date: Fri, 5 Feb 2021 09:51:42 +0100 Subject: i2c: stm32f7: add support for DNF i2c-digital-filter binding Add the support for the i2c-digital-filter binding, allowing to enable the digital filter via the device-tree and indicate its value in the DT. Signed-off-by: Alain Volmat Reviewed-by: Pierre-Yves MORDRET Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-stm32f7.c | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) (limited to 'drivers/i2c/busses/i2c-stm32f7.c') diff --git a/drivers/i2c/busses/i2c-stm32f7.c b/drivers/i2c/busses/i2c-stm32f7.c index 140b1078146b..c019548e9ded 100644 --- a/drivers/i2c/busses/i2c-stm32f7.c +++ b/drivers/i2c/busses/i2c-stm32f7.c @@ -222,7 +222,6 @@ struct stm32f7_i2c_spec { * @clock_src: I2C clock source frequency (Hz) * @rise_time: Rise time (ns) * @fall_time: Fall time (ns) - * @dnf: Digital filter coefficient (0-16) * @fmp_clr_offset: Fast Mode Plus clear register offset from set register */ struct stm32f7_i2c_setup { @@ -230,7 +229,6 @@ struct stm32f7_i2c_setup { u32 clock_src; u32 rise_time; u32 fall_time; - u8 dnf; u32 fmp_clr_offset; }; @@ -310,6 +308,8 @@ struct stm32f7_i2c_msg { * @smbus_mode: states that the controller is configured in SMBus mode * @host_notify_client: SMBus host-notify client * @analog_filter: boolean to indicate enabling of the analog filter + * @dnf_dt: value of digital filter requested via dt + * @dnf: value of digital filter to apply */ struct stm32f7_i2c_dev { struct i2c_adapter adap; @@ -339,6 +339,8 @@ struct stm32f7_i2c_dev { bool smbus_mode; struct i2c_client *host_notify_client; bool analog_filter; + u32 dnf_dt; + u32 dnf; }; /* @@ -384,13 +386,11 @@ static struct stm32f7_i2c_spec stm32f7_i2c_specs[] = { static const struct stm32f7_i2c_setup stm32f7_setup = { .rise_time = STM32F7_I2C_RISE_TIME_DEFAULT, .fall_time = STM32F7_I2C_FALL_TIME_DEFAULT, - .dnf = STM32F7_I2C_DNF_DEFAULT, }; static const struct stm32f7_i2c_setup stm32mp15_setup = { .rise_time = STM32F7_I2C_RISE_TIME_DEFAULT, .fall_time = STM32F7_I2C_FALL_TIME_DEFAULT, - .dnf = STM32F7_I2C_DNF_DEFAULT, .fmp_clr_offset = 0x40, }; @@ -459,10 +459,11 @@ static int stm32f7_i2c_compute_timing(struct stm32f7_i2c_dev *i2c_dev, return -EINVAL; } - if (setup->dnf > STM32F7_I2C_DNF_MAX) { + i2c_dev->dnf = DIV_ROUND_CLOSEST(i2c_dev->dnf_dt, i2cclk); + if (i2c_dev->dnf > STM32F7_I2C_DNF_MAX) { dev_err(i2c_dev->dev, "DNF out of bound %d/%d\n", - setup->dnf, STM32F7_I2C_DNF_MAX); + i2c_dev->dnf * i2cclk, STM32F7_I2C_DNF_MAX * i2cclk); return -EINVAL; } @@ -473,13 +474,13 @@ static int stm32f7_i2c_compute_timing(struct stm32f7_i2c_dev *i2c_dev, af_delay_max = (i2c_dev->analog_filter ? STM32F7_I2C_ANALOG_FILTER_DELAY_MAX : 0); - dnf_delay = setup->dnf * i2cclk; + dnf_delay = i2c_dev->dnf * i2cclk; sdadel_min = specs->hddat_min + setup->fall_time - - af_delay_min - (setup->dnf + 3) * i2cclk; + af_delay_min - (i2c_dev->dnf + 3) * i2cclk; sdadel_max = specs->vddat_max - setup->rise_time - - af_delay_max - (setup->dnf + 4) * i2cclk; + af_delay_max - (i2c_dev->dnf + 4) * i2cclk; scldel_min = setup->rise_time + specs->sudat_min; @@ -645,6 +646,7 @@ static int stm32f7_i2c_setup_timing(struct stm32f7_i2c_dev *i2c_dev, setup->speed_freq = t->bus_freq_hz; i2c_dev->setup.rise_time = t->scl_rise_ns; i2c_dev->setup.fall_time = t->scl_fall_ns; + i2c_dev->dnf_dt = t->digital_filter_width_ns; setup->clock_src = clk_get_rate(i2c_dev->clk); if (!setup->clock_src) { @@ -652,6 +654,9 @@ static int stm32f7_i2c_setup_timing(struct stm32f7_i2c_dev *i2c_dev, return -EINVAL; } + if (!of_property_read_bool(i2c_dev->dev->of_node, "i2c-digital-filter")) + i2c_dev->dnf_dt = STM32F7_I2C_DNF_DEFAULT; + do { ret = stm32f7_i2c_compute_timing(i2c_dev, setup, &i2c_dev->timing); @@ -681,7 +686,7 @@ static int stm32f7_i2c_setup_timing(struct stm32f7_i2c_dev *i2c_dev, 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", - (i2c_dev->analog_filter ? "On" : "Off"), setup->dnf); + (i2c_dev->analog_filter ? "On" : "Off"), i2c_dev->dnf); i2c_dev->bus_rate = setup->speed_freq; @@ -732,7 +737,7 @@ static void stm32f7_i2c_hw_config(struct stm32f7_i2c_dev *i2c_dev) 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, - STM32F7_I2C_CR1_DNF(i2c_dev->setup.dnf)); + STM32F7_I2C_CR1_DNF(i2c_dev->dnf)); stm32f7_i2c_set_bits(i2c_dev->base + STM32F7_I2C_CR1, STM32F7_I2C_CR1_PE); -- cgit v1.2.3 From b87752528fe562f01034168b7e4c476b200bc456 Mon Sep 17 00:00:00 2001 From: Alain Volmat Date: Fri, 5 Feb 2021 09:51:44 +0100 Subject: i2c: stm32f7: indicate the address being accessed on errors To help debugging issues, add the address of the slave being accessed when getting an error. Signed-off-by: Alain Volmat Signed-off-by: Pierre-Yves MORDRET Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-stm32f7.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers/i2c/busses/i2c-stm32f7.c') diff --git a/drivers/i2c/busses/i2c-stm32f7.c b/drivers/i2c/busses/i2c-stm32f7.c index c019548e9ded..162a3b069261 100644 --- a/drivers/i2c/busses/i2c-stm32f7.c +++ b/drivers/i2c/busses/i2c-stm32f7.c @@ -1602,7 +1602,8 @@ static irqreturn_t stm32f7_i2c_isr_error(int irq, void *data) /* Bus error */ if (status & STM32F7_I2C_ISR_BERR) { - dev_err(dev, "<%s>: Bus error\n", __func__); + dev_err(dev, "<%s>: Bus error accessing addr 0x%x\n", + __func__, f7_msg->addr); writel_relaxed(STM32F7_I2C_ICR_BERRCF, base + STM32F7_I2C_ICR); stm32f7_i2c_release_bus(&i2c_dev->adap); f7_msg->result = -EIO; @@ -1610,13 +1611,15 @@ static irqreturn_t stm32f7_i2c_isr_error(int irq, void *data) /* Arbitration loss */ if (status & STM32F7_I2C_ISR_ARLO) { - dev_dbg(dev, "<%s>: Arbitration loss\n", __func__); + dev_dbg(dev, "<%s>: Arbitration loss accessing addr 0x%x\n", + __func__, f7_msg->addr); writel_relaxed(STM32F7_I2C_ICR_ARLOCF, base + STM32F7_I2C_ICR); f7_msg->result = -EAGAIN; } if (status & STM32F7_I2C_ISR_PECERR) { - dev_err(dev, "<%s>: PEC error in reception\n", __func__); + dev_err(dev, "<%s>: PEC error in reception accessing addr 0x%x\n", + __func__, f7_msg->addr); writel_relaxed(STM32F7_I2C_ICR_PECCF, base + STM32F7_I2C_ICR); f7_msg->result = -EINVAL; } -- cgit v1.2.3 From 8f66edb25c4e10f8380c88f4c097158ff611fd10 Mon Sep 17 00:00:00 2001 From: Tian Tao Date: Thu, 25 Mar 2021 20:04:32 +0800 Subject: i2c: stm32f7: Remove useless error message Fix the following coccicheck report: drivers/i2c/busses/i2c-stm32f7.c:2032:3-10 : platform_get_irq : line 2032 is redundant because platform_get_irq() already prints an error Remove dev_err() messages after platform_get_irq() failures. Signed-off-by: Tian Tao Signed-off-by: Zihao Tang Reviewed-by: Alain Volmat Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-stm32f7.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'drivers/i2c/busses/i2c-stm32f7.c') diff --git a/drivers/i2c/busses/i2c-stm32f7.c b/drivers/i2c/busses/i2c-stm32f7.c index 162a3b069261..9fbcbd1807df 100644 --- a/drivers/i2c/busses/i2c-stm32f7.c +++ b/drivers/i2c/busses/i2c-stm32f7.c @@ -2035,12 +2035,8 @@ static int stm32f7_i2c_probe(struct platform_device *pdev) phy_addr = (dma_addr_t)res->start; irq_event = platform_get_irq(pdev, 0); - if (irq_event <= 0) { - if (irq_event != -EPROBE_DEFER) - dev_err(&pdev->dev, "Failed to get IRQ event: %d\n", - irq_event); + if (irq_event <= 0) return irq_event ? : -ENOENT; - } irq_error = platform_get_irq(pdev, 1); if (irq_error <= 0) -- cgit v1.2.3 From 010e32ab205bfee3a3e860d0366c1516c3e298f9 Mon Sep 17 00:00:00 2001 From: Alain Volmat Date: Fri, 12 Mar 2021 12:53:27 +0100 Subject: i2c: stm32f7: avoid ifdef CONFIG_PM_SLEEP for pm callbacks Avoid CONFIG_PM preprocessor check for pm suspend/resume callbacks and identify the functions with __maybe_unused. Signed-off-by: Alain Volmat Reviewed-by: Pierre-Yves MORDRET Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-stm32f7.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'drivers/i2c/busses/i2c-stm32f7.c') diff --git a/drivers/i2c/busses/i2c-stm32f7.c b/drivers/i2c/busses/i2c-stm32f7.c index 9fbcbd1807df..7e06e6b79b21 100644 --- a/drivers/i2c/busses/i2c-stm32f7.c +++ b/drivers/i2c/busses/i2c-stm32f7.c @@ -2271,8 +2271,7 @@ static int __maybe_unused stm32f7_i2c_runtime_resume(struct device *dev) return 0; } -#ifdef CONFIG_PM_SLEEP -static int stm32f7_i2c_regs_backup(struct stm32f7_i2c_dev *i2c_dev) +static int __maybe_unused stm32f7_i2c_regs_backup(struct stm32f7_i2c_dev *i2c_dev) { int ret; struct stm32f7_i2c_regs *backup_regs = &i2c_dev->backup_regs; @@ -2293,7 +2292,7 @@ static int stm32f7_i2c_regs_backup(struct stm32f7_i2c_dev *i2c_dev) return ret; } -static int stm32f7_i2c_regs_restore(struct stm32f7_i2c_dev *i2c_dev) +static int __maybe_unused stm32f7_i2c_regs_restore(struct stm32f7_i2c_dev *i2c_dev) { u32 cr1; int ret; @@ -2324,7 +2323,7 @@ static int stm32f7_i2c_regs_restore(struct stm32f7_i2c_dev *i2c_dev) return ret; } -static int stm32f7_i2c_suspend(struct device *dev) +static int __maybe_unused stm32f7_i2c_suspend(struct device *dev) { struct stm32f7_i2c_dev *i2c_dev = dev_get_drvdata(dev); int ret; @@ -2345,7 +2344,7 @@ static int stm32f7_i2c_suspend(struct device *dev) return 0; } -static int stm32f7_i2c_resume(struct device *dev) +static int __maybe_unused stm32f7_i2c_resume(struct device *dev) { struct stm32f7_i2c_dev *i2c_dev = dev_get_drvdata(dev); int ret; @@ -2365,7 +2364,6 @@ static int stm32f7_i2c_resume(struct device *dev) return 0; } -#endif static const struct dev_pm_ops stm32f7_i2c_pm_ops = { SET_RUNTIME_PM_OPS(stm32f7_i2c_runtime_suspend, -- cgit v1.2.3 From 2c662660ce2bd3b09dae21a9a9ac9395e1e6c00b Mon Sep 17 00:00:00 2001 From: Qinglang Miao Date: Tue, 1 Dec 2020 17:31:45 +0800 Subject: i2c: stm32f7: fix reference leak when pm_runtime_get_sync fails The PM reference count is not expected to be incremented on return in these stm32f7_i2c_xx serious functions. However, pm_runtime_get_sync will increment the PM reference count even failed. Forgetting to putting operation will result in a reference leak here. Replace it with pm_runtime_resume_and_get to keep usage counter balanced. Fixes: ea6dd25deeb5 ("i2c: stm32f7: add PM_SLEEP suspend/resume support") Reported-by: Hulk Robot Signed-off-by: Qinglang Miao Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-stm32f7.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/i2c/busses/i2c-stm32f7.c') diff --git a/drivers/i2c/busses/i2c-stm32f7.c b/drivers/i2c/busses/i2c-stm32f7.c index 7e06e6b79b21..0138317ea600 100644 --- a/drivers/i2c/busses/i2c-stm32f7.c +++ b/drivers/i2c/busses/i2c-stm32f7.c @@ -1660,7 +1660,7 @@ static int stm32f7_i2c_xfer(struct i2c_adapter *i2c_adap, i2c_dev->msg_id = 0; f7_msg->smbus = false; - ret = pm_runtime_get_sync(i2c_dev->dev); + ret = pm_runtime_resume_and_get(i2c_dev->dev); if (ret < 0) return ret; @@ -1706,7 +1706,7 @@ static int stm32f7_i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, f7_msg->read_write = read_write; f7_msg->smbus = true; - ret = pm_runtime_get_sync(dev); + ret = pm_runtime_resume_and_get(dev); if (ret < 0) return ret; @@ -1807,7 +1807,7 @@ static int stm32f7_i2c_reg_slave(struct i2c_client *slave) if (ret) return ret; - ret = pm_runtime_get_sync(dev); + ret = pm_runtime_resume_and_get(dev); if (ret < 0) return ret; @@ -1888,7 +1888,7 @@ static int stm32f7_i2c_unreg_slave(struct i2c_client *slave) WARN_ON(!i2c_dev->slave[id]); - ret = pm_runtime_get_sync(i2c_dev->dev); + ret = pm_runtime_resume_and_get(i2c_dev->dev); if (ret < 0) return ret; @@ -2276,7 +2276,7 @@ static int __maybe_unused stm32f7_i2c_regs_backup(struct stm32f7_i2c_dev *i2c_de int ret; struct stm32f7_i2c_regs *backup_regs = &i2c_dev->backup_regs; - ret = pm_runtime_get_sync(i2c_dev->dev); + ret = pm_runtime_resume_and_get(i2c_dev->dev); if (ret < 0) return ret; @@ -2298,7 +2298,7 @@ static int __maybe_unused stm32f7_i2c_regs_restore(struct stm32f7_i2c_dev *i2c_d int ret; struct stm32f7_i2c_regs *backup_regs = &i2c_dev->backup_regs; - ret = pm_runtime_get_sync(i2c_dev->dev); + ret = pm_runtime_resume_and_get(i2c_dev->dev); if (ret < 0) return ret; -- cgit v1.2.3