i2c: sprd: Fix the i2c count issue
[sfrench/cifs-2.6.git] / drivers / i2c / busses / i2c-sprd.c
index 25fcc3c1e32bf3d9a41fa345982039fb234dbcbd..4053259bccb8d704d9d386287086841690174844 100644 (file)
@@ -86,6 +86,7 @@ struct sprd_i2c {
        u32 count;
        int irq;
        int err;
+       bool is_suspended;
 };
 
 static void sprd_i2c_set_count(struct sprd_i2c *i2c_dev, u32 count)
@@ -283,6 +284,9 @@ static int sprd_i2c_master_xfer(struct i2c_adapter *i2c_adap,
        struct sprd_i2c *i2c_dev = i2c_adap->algo_data;
        int im, ret;
 
+       if (i2c_dev->is_suspended)
+               return -EBUSY;
+
        ret = pm_runtime_get_sync(i2c_dev->dev);
        if (ret < 0)
                return ret;
@@ -364,13 +368,12 @@ static irqreturn_t sprd_i2c_isr_thread(int irq, void *dev_id)
        struct sprd_i2c *i2c_dev = dev_id;
        struct i2c_msg *msg = i2c_dev->msg;
        bool ack = !(readl(i2c_dev->base + I2C_STATUS) & I2C_RX_ACK);
-       u32 i2c_count = readl(i2c_dev->base + I2C_COUNT);
        u32 i2c_tran;
 
        if (msg->flags & I2C_M_RD)
                i2c_tran = i2c_dev->count >= I2C_FIFO_FULL_THLD;
        else
-               i2c_tran = i2c_count;
+               i2c_tran = i2c_dev->count;
 
        /*
         * If we got one ACK from slave when writing data, and we did not
@@ -408,14 +411,13 @@ static irqreturn_t sprd_i2c_isr(int irq, void *dev_id)
 {
        struct sprd_i2c *i2c_dev = dev_id;
        struct i2c_msg *msg = i2c_dev->msg;
-       u32 i2c_count = readl(i2c_dev->base + I2C_COUNT);
        bool ack = !(readl(i2c_dev->base + I2C_STATUS) & I2C_RX_ACK);
        u32 i2c_tran;
 
        if (msg->flags & I2C_M_RD)
                i2c_tran = i2c_dev->count >= I2C_FIFO_FULL_THLD;
        else
-               i2c_tran = i2c_count;
+               i2c_tran = i2c_dev->count;
 
        /*
         * If we did not get one ACK from slave when writing data, then we
@@ -586,11 +588,23 @@ static int sprd_i2c_remove(struct platform_device *pdev)
 
 static int __maybe_unused sprd_i2c_suspend_noirq(struct device *pdev)
 {
+       struct sprd_i2c *i2c_dev = dev_get_drvdata(pdev);
+
+       i2c_lock_adapter(&i2c_dev->adap);
+       i2c_dev->is_suspended = true;
+       i2c_unlock_adapter(&i2c_dev->adap);
+
        return pm_runtime_force_suspend(pdev);
 }
 
 static int __maybe_unused sprd_i2c_resume_noirq(struct device *pdev)
 {
+       struct sprd_i2c *i2c_dev = dev_get_drvdata(pdev);
+
+       i2c_lock_adapter(&i2c_dev->adap);
+       i2c_dev->is_suspended = false;
+       i2c_unlock_adapter(&i2c_dev->adap);
+
        return pm_runtime_force_resume(pdev);
 }