i2c: designware: Add missing locks
authorJan Dabros <jsd@semihalf.com>
Tue, 8 Feb 2022 14:12:17 +0000 (15:12 +0100)
committerWolfram Sang <wsa@kernel.org>
Fri, 11 Feb 2022 14:38:23 +0000 (15:38 +0100)
All accesses to controller's registers should be protected on
probe, disable and xfer paths. This is needed for i2c bus controllers
that are shared with but not controller by kernel.

Signed-off-by: Jan Dabros <jsd@semihalf.com>
Reviewed-by: Hans de Goede <hdegoede@redhat.com>
Acked-by: Jarkko Nikula <jarkko.nikula@linux.intel.com>
Tested-by: Jarkko Nikula <jarkko.nikula@linux.intel.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Wolfram Sang <wsa@kernel.org>
drivers/i2c/busses/i2c-designware-common.c
drivers/i2c/busses/i2c-designware-master.c

index bf2a4920638ab6718674939ceabbee522e0714ff..9f8574320eb2dfe3b4bf51bac51b9664e61afa4b 100644 (file)
@@ -578,7 +578,12 @@ int i2c_dw_set_fifo_size(struct dw_i2c_dev *dev)
         * Try to detect the FIFO depth if not set by interface driver,
         * the depth could be from 2 to 256 from HW spec.
         */
+       ret = i2c_dw_acquire_lock(dev);
+       if (ret)
+               return ret;
+
        ret = regmap_read(dev->map, DW_IC_COMP_PARAM_1, &param);
+       i2c_dw_release_lock(dev);
        if (ret)
                return ret;
 
@@ -607,6 +612,11 @@ u32 i2c_dw_func(struct i2c_adapter *adap)
 void i2c_dw_disable(struct dw_i2c_dev *dev)
 {
        u32 dummy;
+       int ret;
+
+       ret = i2c_dw_acquire_lock(dev);
+       if (ret)
+               return;
 
        /* Disable controller */
        __i2c_dw_disable(dev);
@@ -614,6 +624,8 @@ void i2c_dw_disable(struct dw_i2c_dev *dev)
        /* Disable all interrupts */
        regmap_write(dev->map, DW_IC_INTR_MASK, 0);
        regmap_read(dev->map, DW_IC_CLR_INTR, &dummy);
+
+       i2c_dw_release_lock(dev);
 }
 
 void i2c_dw_disable_int(struct dw_i2c_dev *dev)
index 9177463c2cbb4738bebba48721dccebd10746189..1a4b23556db367687f11746a70ec21f24444b2b6 100644 (file)
@@ -905,7 +905,13 @@ int i2c_dw_probe_master(struct dw_i2c_dev *dev)
                irq_flags = IRQF_SHARED | IRQF_COND_SUSPEND;
        }
 
+       ret = i2c_dw_acquire_lock(dev);
+       if (ret)
+               return ret;
+
        i2c_dw_disable_int(dev);
+       i2c_dw_release_lock(dev);
+
        ret = devm_request_irq(dev->dev, dev->irq, i2c_dw_isr, irq_flags,
                               dev_name(dev->dev), dev);
        if (ret) {