summaryrefslogtreecommitdiffstats
path: root/drivers/i2c
diff options
context:
space:
mode:
authorWolfram Sang <wsa+renesas@sang-engineering.com>2015-12-23 17:56:34 +0100
committerWolfram Sang <wsa@the-dreams.de>2016-01-02 22:11:48 +0100
commit7ee24eb508d61e5b74dcc80f644adfb5916f7580 (patch)
tree21deae6bb2d3924bef10f95c932df2b676279090 /drivers/i2c
parent42c0783b89ae4d41ab65e8b0f7ed8cf52e711554 (diff)
downloadlinux-7ee24eb508d61e5b74dcc80f644adfb5916f7580.tar.bz2
i2c: rcar: disable PM in multi-master mode
In multi master mode, the IP core needs to be always active for arbitration reasons. Get the config from DT and set up PM depending on the config. Acked-by: Geert Uytterhoeven <geert+renesas@glider.be> Signed-off-by: Wolfram Sang <wsa+renesas@sang-engineering.com> Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
Diffstat (limited to 'drivers/i2c')
-rw-r--r--drivers/i2c/busses/i2c-rcar.c17
1 files changed, 14 insertions, 3 deletions
diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c
index 79fd2aab8fa0..e596ed9771bc 100644
--- a/drivers/i2c/busses/i2c-rcar.c
+++ b/drivers/i2c/busses/i2c-rcar.c
@@ -96,6 +96,9 @@
#define ID_DONE (1 << 2)
#define ID_ARBLOST (1 << 3)
#define ID_NACK (1 << 4)
+/* persistent flags */
+#define ID_P_PM_BLOCKED (1 << 31)
+#define ID_P_MASK ID_P_PM_BLOCKED
enum rcar_i2c_type {
I2C_RCAR_GEN1,
@@ -277,7 +280,7 @@ static void rcar_i2c_next_msg(struct rcar_i2c_priv *priv)
{
priv->msg++;
priv->msgs_left--;
- priv->flags = 0;
+ priv->flags &= ID_P_MASK;
rcar_i2c_prepare_msg(priv);
}
@@ -495,7 +498,7 @@ static int rcar_i2c_master_xfer(struct i2c_adapter *adap,
/* init first message */
priv->msg = msgs;
priv->msgs_left = num;
- priv->flags = ID_FIRST_MSG;
+ priv->flags = (priv->flags & ID_P_MASK) | ID_FIRST_MSG;
rcar_i2c_prepare_msg(priv);
time_left = wait_event_timeout(priv->wait, priv->flags & ID_DONE,
@@ -630,7 +633,13 @@ static int rcar_i2c_probe(struct platform_device *pdev)
goto out_pm_put;
rcar_i2c_init(priv);
- pm_runtime_put(dev);
+
+ /* Don't suspend when multi-master to keep arbitration working */
+ if (of_property_read_bool(dev->of_node, "multi-master"))
+ priv->flags |= ID_P_PM_BLOCKED;
+ else
+ pm_runtime_put(dev);
+
irq = platform_get_irq(pdev, 0);
ret = devm_request_irq(dev, irq, rcar_i2c_irq, 0, dev_name(dev), priv);
@@ -664,6 +673,8 @@ static int rcar_i2c_remove(struct platform_device *pdev)
struct device *dev = &pdev->dev;
i2c_del_adapter(&priv->adap);
+ if (priv->flags & ID_P_PM_BLOCKED)
+ pm_runtime_put(dev);
pm_runtime_disable(dev);
return 0;