i2c-host-fixes for v7.1-rc8
- imx: keep clock and pinctrl states consistent in runtime PM - imx-lpi2c: fix DMA resource leaks on PIO fallback - qcom-cci: fix NULL pointer dereference on remove - riic: fix reset refcount leak on resume_noirq error path - stm32f7: account for analog filter in timing computation - tegra: fix suspend/resume handling in NOIRQ phase - tegra: update Tegra410 I2C timings to match hardware specs - MAINTAINERS: hand over I2C maintainership to Andi -----BEGIN PGP SIGNATURE----- iHQEABYKAB0WIQScDfrjQa34uOld1VLaeAVmJtMtbgUCaivYkgAKCRDaeAVmJtMt bq6BAQDIi1pJu3mcfXZagsn/DWVqM55a6H8pvYHkpdIQFcchXQD4lgbiopNoKusj I5qIKtRs2KD/FLAhWYl0vhEoY4PkBw== =LfKo -----END PGP SIGNATURE----- Merge tag 'i2c-host-fixes-7.1-rc8' of git://git.kernel.org/pub/scm/linux/kernel/git/andi.shyti/linux into i2c/for-current i2c-host-fixes for v7.1-rc8 - imx: keep clock and pinctrl states consistent in runtime PM - imx-lpi2c: fix DMA resource leaks on PIO fallback - qcom-cci: fix NULL pointer dereference on remove - riic: fix reset refcount leak on resume_noirq error path - stm32f7: account for analog filter in timing computation - tegra: fix suspend/resume handling in NOIRQ phase - tegra: update Tegra410 I2C timings to match hardware specs - MAINTAINERS: hand over I2C maintainership to Andi
This commit is contained in:
commit
35ebcfcc9e
7 changed files with 87 additions and 58 deletions
|
|
@ -12095,11 +12095,11 @@ F: Documentation/i2c/busses/i2c-parport.rst
|
|||
F: drivers/i2c/busses/i2c-parport.c
|
||||
|
||||
I2C SUBSYSTEM
|
||||
M: Wolfram Sang <wsa+renesas@sang-engineering.com>
|
||||
M: Andi Shyti <andi.shyti@kernel.org>
|
||||
L: linux-i2c@vger.kernel.org
|
||||
S: Maintained
|
||||
Q: https://patchwork.ozlabs.org/project/linux-i2c/list/
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux.git
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/andi.shyti/linux.git
|
||||
F: Documentation/i2c/
|
||||
F: drivers/i2c/*
|
||||
F: include/dt-bindings/i2c/i2c.h
|
||||
|
|
|
|||
|
|
@ -1383,55 +1383,66 @@ static int lpi2c_imx_init_recovery_info(struct lpi2c_imx_struct *lpi2c_imx,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void dma_exit(struct device *dev, struct lpi2c_imx_dma *dma)
|
||||
{
|
||||
if (dma->chan_rx)
|
||||
dma_release_channel(dma->chan_rx);
|
||||
|
||||
if (dma->chan_tx)
|
||||
dma_release_channel(dma->chan_tx);
|
||||
|
||||
devm_kfree(dev, dma);
|
||||
}
|
||||
|
||||
static int lpi2c_dma_init(struct device *dev, dma_addr_t phy_addr)
|
||||
{
|
||||
struct lpi2c_imx_struct *lpi2c_imx = dev_get_drvdata(dev);
|
||||
struct lpi2c_imx_dma *dma;
|
||||
void *group;
|
||||
int ret;
|
||||
|
||||
dma = devm_kzalloc(dev, sizeof(*dma), GFP_KERNEL);
|
||||
if (!dma)
|
||||
/*
|
||||
* Open a devres group so that all resources allocated within
|
||||
* this function can be released together if DMA init fails but
|
||||
* probe continues in PIO mode.
|
||||
*/
|
||||
group = devres_open_group(dev, NULL, GFP_KERNEL);
|
||||
if (!group)
|
||||
return -ENOMEM;
|
||||
|
||||
dma = devm_kzalloc(dev, sizeof(*dma), GFP_KERNEL);
|
||||
if (!dma) {
|
||||
ret = -ENOMEM;
|
||||
goto release_group;
|
||||
}
|
||||
|
||||
dma->phy_addr = phy_addr;
|
||||
|
||||
/* Prepare for TX DMA: */
|
||||
dma->chan_tx = dma_request_chan(dev, "tx");
|
||||
dma->chan_tx = devm_dma_request_chan(dev, "tx");
|
||||
if (IS_ERR(dma->chan_tx)) {
|
||||
ret = PTR_ERR(dma->chan_tx);
|
||||
if (ret != -ENODEV && ret != -EPROBE_DEFER)
|
||||
dev_err(dev, "can't request DMA tx channel (%d)\n", ret);
|
||||
dma->chan_tx = NULL;
|
||||
goto dma_exit;
|
||||
goto release_group;
|
||||
}
|
||||
|
||||
/* Prepare for RX DMA: */
|
||||
dma->chan_rx = dma_request_chan(dev, "rx");
|
||||
dma->chan_rx = devm_dma_request_chan(dev, "rx");
|
||||
if (IS_ERR(dma->chan_rx)) {
|
||||
ret = PTR_ERR(dma->chan_rx);
|
||||
if (ret != -ENODEV && ret != -EPROBE_DEFER)
|
||||
dev_err(dev, "can't request DMA rx channel (%d)\n", ret);
|
||||
dma->chan_rx = NULL;
|
||||
goto dma_exit;
|
||||
goto release_group;
|
||||
}
|
||||
|
||||
/*
|
||||
* DMA init succeeded. Remove the group marker but keep all resources
|
||||
* bound to the device, they will be freed at device removal.
|
||||
*/
|
||||
devres_remove_group(dev, group);
|
||||
|
||||
lpi2c_imx->can_use_dma = true;
|
||||
lpi2c_imx->dma = dma;
|
||||
return 0;
|
||||
|
||||
dma_exit:
|
||||
dma_exit(dev, dma);
|
||||
release_group:
|
||||
/*
|
||||
* DMA init failed. Release ALL resources allocated inside this
|
||||
* group (dma memory, TX channel if already acquired, etc.) so
|
||||
* that a successful PIO-mode probe does not hold unused resources
|
||||
* for the entire device lifetime.
|
||||
*/
|
||||
devres_release_group(dev, group);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1892,9 +1892,15 @@ static void i2c_imx_remove(struct platform_device *pdev)
|
|||
static int i2c_imx_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct imx_i2c_struct *i2c_imx = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
ret = pinctrl_pm_select_sleep_state(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
clk_disable(i2c_imx->clk);
|
||||
return pinctrl_pm_select_sleep_state(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int i2c_imx_runtime_resume(struct device *dev)
|
||||
|
|
@ -1907,10 +1913,13 @@ static int i2c_imx_runtime_resume(struct device *dev)
|
|||
return ret;
|
||||
|
||||
ret = clk_enable(i2c_imx->clk);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
dev_err(dev, "can't enable I2C clock, ret=%d\n", ret);
|
||||
pinctrl_pm_select_sleep_state(dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int i2c_imx_suspend(struct device *dev)
|
||||
|
|
|
|||
|
|
@ -660,8 +660,8 @@ static void cci_remove(struct platform_device *pdev)
|
|||
if (cci->master[i].cci) {
|
||||
i2c_del_adapter(&cci->master[i].adap);
|
||||
of_node_put(cci->master[i].adap.dev.of_node);
|
||||
cci_halt(cci, i);
|
||||
}
|
||||
cci_halt(cci, i);
|
||||
}
|
||||
|
||||
disable_irq(cci->irq);
|
||||
|
|
|
|||
|
|
@ -725,8 +725,10 @@ static int riic_i2c_resume_noirq(struct device *dev)
|
|||
return ret;
|
||||
|
||||
ret = pm_runtime_force_resume(dev);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
reset_control_assert(riic->rstc);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = riic_init_hw(riic);
|
||||
if (ret) {
|
||||
|
|
|
|||
|
|
@ -694,6 +694,9 @@ static int stm32f7_i2c_setup_timing(struct stm32f7_i2c_dev *i2c_dev,
|
|||
if (!of_property_read_bool(i2c_dev->dev->of_node, "i2c-digital-filter"))
|
||||
i2c_dev->dnf_dt = STM32F7_I2C_DNF_DEFAULT;
|
||||
|
||||
i2c_dev->analog_filter = of_property_read_bool(i2c_dev->dev->of_node,
|
||||
"i2c-analog-filter");
|
||||
|
||||
do {
|
||||
ret = stm32f7_i2c_compute_timing(i2c_dev, setup,
|
||||
&i2c_dev->timing);
|
||||
|
|
@ -715,9 +718,6 @@ 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",
|
||||
|
|
|
|||
|
|
@ -2115,9 +2115,9 @@ static const struct tegra_i2c_hw_feature tegra264_i2c_hw = {
|
|||
static const struct tegra_i2c_hw_feature tegra410_i2c_hw = {
|
||||
.has_continue_xfer_support = true,
|
||||
.has_per_pkt_xfer_complete_irq = true,
|
||||
.clk_divisor_hs_mode = 1,
|
||||
.clk_divisor_hs_mode = 2,
|
||||
.clk_divisor_std_mode = 0x3f,
|
||||
.clk_divisor_fast_mode = 0x2c,
|
||||
.clk_divisor_fast_mode = 0x2f,
|
||||
.clk_divisor_fast_plus_mode = 0x11,
|
||||
.has_config_load_reg = true,
|
||||
.has_multi_master_mode = true,
|
||||
|
|
@ -2133,8 +2133,8 @@ static const struct tegra_i2c_hw_feature tegra410_i2c_hw = {
|
|||
.thigh_fast_mode = 0x2,
|
||||
.tlow_fastplus_mode = 0x2,
|
||||
.thigh_fastplus_mode = 0x2,
|
||||
.tlow_hs_mode = 0x8,
|
||||
.thigh_hs_mode = 0x6,
|
||||
.tlow_hs_mode = 0x5,
|
||||
.thigh_hs_mode = 0x2,
|
||||
.setup_hold_time_std_mode = 0x08080808,
|
||||
.setup_hold_time_fast_mode = 0x02020202,
|
||||
.setup_hold_time_fastplus_mode = 0x02020202,
|
||||
|
|
@ -2401,29 +2401,38 @@ static int __maybe_unused tegra_i2c_runtime_suspend(struct device *dev)
|
|||
}
|
||||
|
||||
static int __maybe_unused tegra_i2c_suspend(struct device *dev)
|
||||
{
|
||||
/*
|
||||
* Bring the controller up and hold a usage count so it stays
|
||||
* available until the noirq phase.
|
||||
*/
|
||||
return pm_runtime_resume_and_get(dev);
|
||||
}
|
||||
|
||||
static int __maybe_unused tegra_i2c_suspend_noirq(struct device *dev)
|
||||
{
|
||||
struct tegra_i2c_dev *i2c_dev = dev_get_drvdata(dev);
|
||||
int err;
|
||||
|
||||
i2c_mark_adapter_suspended(&i2c_dev->adapter);
|
||||
|
||||
if (!pm_runtime_status_suspended(dev)) {
|
||||
err = tegra_i2c_runtime_suspend(dev);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
/*
|
||||
* Runtime PM is already disabled at this point, so invoke the
|
||||
* runtime_suspend callback directly to put the controller down.
|
||||
*/
|
||||
return tegra_i2c_runtime_suspend(dev);
|
||||
}
|
||||
|
||||
static int __maybe_unused tegra_i2c_resume(struct device *dev)
|
||||
static int __maybe_unused tegra_i2c_resume_noirq(struct device *dev)
|
||||
{
|
||||
struct tegra_i2c_dev *i2c_dev = dev_get_drvdata(dev);
|
||||
int err;
|
||||
|
||||
/*
|
||||
* We need to ensure that clocks are enabled so that registers can be
|
||||
* restored in tegra_i2c_init().
|
||||
* Runtime PM is still disabled at this point, so invoke the
|
||||
* runtime_resume callback directly to bring the controller back up
|
||||
* before re-initializing the hardware. The adapter is then marked
|
||||
* resumed so that consumers can issue transfers from their own
|
||||
* resume_noirq() handlers and onwards.
|
||||
*/
|
||||
err = tegra_i2c_runtime_resume(dev);
|
||||
if (err)
|
||||
|
|
@ -2433,24 +2442,22 @@ static int __maybe_unused tegra_i2c_resume(struct device *dev)
|
|||
if (err)
|
||||
return err;
|
||||
|
||||
/*
|
||||
* In case we are runtime suspended, disable clocks again so that we
|
||||
* don't unbalance the clock reference counts during the next runtime
|
||||
* resume transition.
|
||||
*/
|
||||
if (pm_runtime_status_suspended(dev)) {
|
||||
err = tegra_i2c_runtime_suspend(dev);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
i2c_mark_adapter_resumed(&i2c_dev->adapter);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused tegra_i2c_resume(struct device *dev)
|
||||
{
|
||||
pm_runtime_put(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops tegra_i2c_pm = {
|
||||
SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(tegra_i2c_suspend, tegra_i2c_resume)
|
||||
SET_SYSTEM_SLEEP_PM_OPS(tegra_i2c_suspend, tegra_i2c_resume)
|
||||
SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(tegra_i2c_suspend_noirq,
|
||||
tegra_i2c_resume_noirq)
|
||||
SET_RUNTIME_PM_OPS(tegra_i2c_runtime_suspend, tegra_i2c_runtime_resume,
|
||||
NULL)
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue