mfd: da9063: Support SMBus and I2C mode
authorHubert Streidl <hubert.streidl@de.bosch.com>
Tue, 16 Mar 2021 16:22:37 +0000 (17:22 +0100)
committerLee Jones <lee.jones@linaro.org>
Wed, 14 Apr 2021 15:06:05 +0000 (16:06 +0100)
By default the PMIC DA9063 2-wire interface is SMBus compliant. This
means the PMIC will automatically reset the interface when the clock
signal ceases for more than the SMBus timeout of 35 ms.

If the I2C driver / device is not capable of creating atomic I2C
transactions, a context change can cause a ceasing of the clock signal.
This can happen if for example a real-time thread is scheduled. Then
the DA9063 in SMBus mode will reset the 2-wire interface. Subsequently
a write message could end up in the wrong register. This could cause
unpredictable system behavior.

The DA9063 PMIC also supports an I2C compliant mode for the 2-wire
interface. This mode does not reset the interface when the clock
signal ceases. Thus the problem depicted above does not occur.

This patch tests for the bus functionality "I2C_FUNC_I2C". It can
reasonably be assumed that the bus cannot obey SMBus timings if
this functionality is set. SMBus commands most probably are emulated
in this case which is prone to the latency issue described above.

This patch enables the I2C bus mode if I2C_FUNC_I2C is set or
otherwise keeps the default SMBus mode.

Signed-off-by: Hubert Streidl <hubert.streidl@de.bosch.com>
Signed-off-by: Mark Jonas <mark.jonas@de.bosch.com>
Reviewed-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
Signed-off-by: Lee Jones <lee.jones@linaro.org>
drivers/mfd/da9063-i2c.c
include/linux/mfd/da9063/registers.h

index 3781d0bb778658e90ceb7857c7628ad098556b87..783a14af18e26cbf35588070dc1f1ce79d29b1c7 100644 (file)
@@ -442,6 +442,16 @@ static int da9063_i2c_probe(struct i2c_client *i2c,
                return ret;
        }
 
+       /* If SMBus is not available and only I2C is possible, enter I2C mode */
+       if (i2c_check_functionality(i2c->adapter, I2C_FUNC_I2C)) {
+               ret = regmap_clear_bits(da9063->regmap, DA9063_REG_CONFIG_J,
+                                       DA9063_TWOWIRE_TO);
+               if (ret < 0) {
+                       dev_err(da9063->dev, "Failed to set Two-Wire Bus Mode.\n");
+                       return -EIO;
+               }
+       }
+
        return da9063_device_init(da9063, i2c->irq);
 }
 
index 1dbabf1b3cb81025330902e06b6b2ce8f82521a2..6e0f66a2e7279f734e93fe37a9b011f7729f4f24 100644 (file)
 #define                DA9063_NONKEY_PIN_AUTODOWN      0x02
 #define                DA9063_NONKEY_PIN_AUTOFLPRT     0x03
 
+/* DA9063_REG_CONFIG_J (addr=0x10F) */
+#define DA9063_TWOWIRE_TO                      0x40
+
 /* DA9063_REG_MON_REG_5 (addr=0x116) */
 #define DA9063_MON_A8_IDX_MASK                 0x07
 #define                DA9063_MON_A8_IDX_NONE          0x00