]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
pwm: pca9685: Disable unused alternative addresses
authorDavid Jander <david@protonic.nl>
Fri, 28 Aug 2020 12:14:15 +0000 (14:14 +0200)
committerThierry Reding <thierry.reding@gmail.com>
Thu, 24 Sep 2020 07:18:13 +0000 (09:18 +0200)
The PCA9685 supports listening to 1 or more alternative I2C chip addresses
for some special features that this driver does not support.
By default the LED ALLCALL address is active (default 0x70), which causes
this chip to respond to address 0x70 in addition to its main address
(0x41). This is not desireable if there is another device on the same bus
that uses this address (like a TMP103 for example).
Since this feature is not supported by this driver, it is best to disable
these addresses in the chip to avoid unsuspected bus collisions.

Signed-off-by: David Jander <david@protonic.nl>
Signed-off-by: Thierry Reding <thierry.reding@gmail.com>
drivers/pwm/pwm-pca9685.c

index 9d1d9dece0c0b7814b3e1fa5d2e96aed8e41930d..4a55dc18656c51ce876cd4e086e78d26c11fd4e5 100644 (file)
 #define PCA9685_MAXCHAN                0x10
 
 #define LED_FULL               BIT(4)
+#define MODE1_ALLCALL          BIT(0)
+#define MODE1_SUB3             BIT(1)
+#define MODE1_SUB2             BIT(2)
+#define MODE1_SUB1             BIT(3)
 #define MODE1_SLEEP            BIT(4)
 #define MODE2_INVRT            BIT(4)
 #define MODE2_OUTDRV           BIT(2)
@@ -443,8 +447,8 @@ static int pca9685_pwm_probe(struct i2c_client *client,
                                const struct i2c_device_id *id)
 {
        struct pca9685 *pca;
+       unsigned int reg;
        int ret;
-       int mode2;
 
        pca = devm_kzalloc(&client->dev, sizeof(*pca), GFP_KERNEL);
        if (!pca)
@@ -461,19 +465,24 @@ static int pca9685_pwm_probe(struct i2c_client *client,
 
        i2c_set_clientdata(client, pca);
 
-       regmap_read(pca->regmap, PCA9685_MODE2, &mode2);
+       regmap_read(pca->regmap, PCA9685_MODE2, &reg);
 
        if (device_property_read_bool(&client->dev, "invert"))
-               mode2 |= MODE2_INVRT;
+               reg |= MODE2_INVRT;
        else
-               mode2 &= ~MODE2_INVRT;
+               reg &= ~MODE2_INVRT;
 
        if (device_property_read_bool(&client->dev, "open-drain"))
-               mode2 &= ~MODE2_OUTDRV;
+               reg &= ~MODE2_OUTDRV;
        else
-               mode2 |= MODE2_OUTDRV;
+               reg |= MODE2_OUTDRV;
+
+       regmap_write(pca->regmap, PCA9685_MODE2, reg);
 
-       regmap_write(pca->regmap, PCA9685_MODE2, mode2);
+       /* Disable all LED ALLCALL and SUBx addresses to avoid bus collisions */
+       regmap_read(pca->regmap, PCA9685_MODE1, &reg);
+       reg &= ~(MODE1_ALLCALL | MODE1_SUB1 | MODE1_SUB2 | MODE1_SUB3);
+       regmap_write(pca->regmap, PCA9685_MODE1, reg);
 
        /* Clear all "full off" bits */
        regmap_write(pca->regmap, PCA9685_ALL_LED_OFF_L, 0);