Commit 5f436443 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull i2c fixes from Wolfram Sang:
 "Two runtime PM fixes and one leak fix"

* 'i2c/for-current' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux:
  i2c: iop3xx: Fix memory leak in probe error path
  i2c: tegra: Properly disable runtime PM on driver's probe error
  i2c: tegra: Fix suspending in active runtime PM state
parents 8f8972a3 e6417577
Loading
Loading
Loading
Loading
+8 −4
Original line number Diff line number Diff line
@@ -433,13 +433,17 @@ iop3xx_i2c_probe(struct platform_device *pdev)
	adapter_data->gpio_scl = devm_gpiod_get_optional(&pdev->dev,
							 "scl",
							 GPIOD_ASIS);
	if (IS_ERR(adapter_data->gpio_scl))
		return PTR_ERR(adapter_data->gpio_scl);
	if (IS_ERR(adapter_data->gpio_scl)) {
		ret = PTR_ERR(adapter_data->gpio_scl);
		goto free_both;
	}
	adapter_data->gpio_sda = devm_gpiod_get_optional(&pdev->dev,
							 "sda",
							 GPIOD_ASIS);
	if (IS_ERR(adapter_data->gpio_sda))
		return PTR_ERR(adapter_data->gpio_sda);
	if (IS_ERR(adapter_data->gpio_sda)) {
		ret = PTR_ERR(adapter_data->gpio_sda);
		goto free_both;
	}

	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	if (!res) {
+28 −10
Original line number Diff line number Diff line
@@ -1608,22 +1608,26 @@ static int tegra_i2c_probe(struct platform_device *pdev)
	}

	pm_runtime_enable(&pdev->dev);
	if (!pm_runtime_enabled(&pdev->dev))
	if (!pm_runtime_enabled(&pdev->dev)) {
		ret = tegra_i2c_runtime_resume(&pdev->dev);
	else
		ret = pm_runtime_get_sync(i2c_dev->dev);

		if (ret < 0) {
			dev_err(&pdev->dev, "runtime resume failed\n");
			goto unprepare_div_clk;
		}
	} else {
		ret = pm_runtime_get_sync(i2c_dev->dev);
		if (ret < 0) {
			dev_err(&pdev->dev, "runtime resume failed\n");
			goto disable_rpm;
		}
	}

	if (i2c_dev->is_multimaster_mode) {
		ret = clk_enable(i2c_dev->div_clk);
		if (ret < 0) {
			dev_err(i2c_dev->dev, "div_clk enable failed %d\n",
				ret);
			goto disable_rpm;
			goto put_rpm;
		}
	}

@@ -1671,10 +1675,15 @@ disable_div_clk:
	if (i2c_dev->is_multimaster_mode)
		clk_disable(i2c_dev->div_clk);

put_rpm:
	if (pm_runtime_enabled(&pdev->dev))
		pm_runtime_put_sync(&pdev->dev);
	else
		tegra_i2c_runtime_suspend(&pdev->dev);

disable_rpm:
	if (pm_runtime_enabled(&pdev->dev))
		pm_runtime_disable(&pdev->dev);
	if (!pm_runtime_status_suspended(&pdev->dev))
		tegra_i2c_runtime_suspend(&pdev->dev);

unprepare_div_clk:
	clk_unprepare(i2c_dev->div_clk);
@@ -1710,9 +1719,14 @@ static int tegra_i2c_remove(struct platform_device *pdev)
static int __maybe_unused tegra_i2c_suspend(struct device *dev)
{
	struct tegra_i2c_dev *i2c_dev = dev_get_drvdata(dev);
	int err;

	i2c_mark_adapter_suspended(&i2c_dev->adapter);

	err = pm_runtime_force_suspend(dev);
	if (err < 0)
		return err;

	return 0;
}

@@ -1733,6 +1747,10 @@ static int __maybe_unused tegra_i2c_resume(struct device *dev)
	if (err)
		return err;

	err = pm_runtime_force_resume(dev);
	if (err < 0)
		return err;

	i2c_mark_adapter_resumed(&i2c_dev->adapter);

	return 0;