Commit 697ad249 authored by Sam Protsenko's avatar Sam Protsenko Committed by Wolfram Sang
Browse files

i2c: exynos5: Add bus clock support



In new Exynos SoCs (like Exynos850) where HSI2C is implemented as a
part of USIv2 block, there are two clocks provided to HSI2C controller:
  - PCLK: bus clock (APB), provides access to register interface
  - IPCLK: operating IP-core clock; SCL is derived from this one

Both clocks have to be asserted for HSI2C to be functional in that case.

Add code to obtain and enable/disable PCLK in addition to already
handled operating clock. Make it optional though, as older Exynos SoC
variants only have one HSI2C clock.

Signed-off-by: default avatarSam Protsenko <semen.protsenko@linaro.org>
Reviewed-by: default avatarKrzysztof Kozlowski <krzysztof.kozlowski@canonical.com>
Reviewed-by: default avatarChanho Park <chanho61.park@samsung.com>
Signed-off-by: default avatarWolfram Sang <wsa@kernel.org>
parent 3f689102
Loading
Loading
Loading
Loading
+38 −8
Original line number Diff line number Diff line
@@ -182,7 +182,8 @@ struct exynos5_i2c {
	unsigned int		irq;

	void __iomem		*regs;
	struct clk		*clk;
	struct clk		*clk;		/* operating clock */
	struct clk		*pclk;		/* bus clock */
	struct device		*dev;
	int			state;

@@ -757,10 +758,14 @@ static int exynos5_i2c_xfer(struct i2c_adapter *adap,
	struct exynos5_i2c *i2c = adap->algo_data;
	int i, ret;

	ret = clk_enable(i2c->clk);
	ret = clk_enable(i2c->pclk);
	if (ret)
		return ret;

	ret = clk_enable(i2c->clk);
	if (ret)
		goto err_pclk;

	for (i = 0; i < num; ++i) {
		ret = exynos5_i2c_xfer_msg(i2c, msgs + i, i + 1 == num);
		if (ret)
@@ -768,6 +773,8 @@ static int exynos5_i2c_xfer(struct i2c_adapter *adap,
	}

	clk_disable(i2c->clk);
err_pclk:
	clk_disable(i2c->pclk);

	return ret ?: num;
}
@@ -807,10 +814,18 @@ static int exynos5_i2c_probe(struct platform_device *pdev)
		return -ENOENT;
	}

	ret = clk_prepare_enable(i2c->clk);
	i2c->pclk = devm_clk_get(&pdev->dev, "hsi2c_pclk");
	if (IS_ERR(i2c->pclk))
		i2c->pclk = NULL; /* pclk is optional */

	ret = clk_prepare_enable(i2c->pclk);
	if (ret)
		return ret;

	ret = clk_prepare_enable(i2c->clk);
	if (ret)
		goto err_pclk;

	i2c->regs = devm_platform_ioremap_resource(pdev, 0);
	if (IS_ERR(i2c->regs)) {
		ret = PTR_ERR(i2c->regs);
@@ -853,11 +868,15 @@ static int exynos5_i2c_probe(struct platform_device *pdev)
	platform_set_drvdata(pdev, i2c);

	clk_disable(i2c->clk);
	clk_disable(i2c->pclk);

	return 0;

 err_clk:
	clk_disable_unprepare(i2c->clk);

 err_pclk:
	clk_disable_unprepare(i2c->pclk);
	return ret;
}

@@ -868,6 +887,7 @@ static int exynos5_i2c_remove(struct platform_device *pdev)
	i2c_del_adapter(&i2c->adap);

	clk_unprepare(i2c->clk);
	clk_unprepare(i2c->pclk);

	return 0;
}
@@ -879,6 +899,7 @@ static int exynos5_i2c_suspend_noirq(struct device *dev)

	i2c_mark_adapter_suspended(&i2c->adap);
	clk_unprepare(i2c->clk);
	clk_unprepare(i2c->pclk);

	return 0;
}
@@ -888,21 +909,30 @@ static int exynos5_i2c_resume_noirq(struct device *dev)
	struct exynos5_i2c *i2c = dev_get_drvdata(dev);
	int ret = 0;

	ret = clk_prepare_enable(i2c->clk);
	ret = clk_prepare_enable(i2c->pclk);
	if (ret)
		return ret;

	ret = clk_prepare_enable(i2c->clk);
	if (ret)
		goto err_pclk;

	ret = exynos5_hsi2c_clock_setup(i2c);
	if (ret) {
		clk_disable_unprepare(i2c->clk);
		return ret;
	}
	if (ret)
		goto err_clk;

	exynos5_i2c_init(i2c);
	clk_disable(i2c->clk);
	clk_disable(i2c->pclk);
	i2c_mark_adapter_resumed(&i2c->adap);

	return 0;

err_clk:
	clk_disable_unprepare(i2c->clk);
err_pclk:
	clk_disable_unprepare(i2c->pclk);
	return ret;
}
#endif