#define MODE1_SUB2 BIT(2)
#define MODE1_SUB1 BIT(3)
#define MODE1_SLEEP BIT(4)
+#define MODE1_AI BIT(5)
+
#define MODE2_INVRT BIT(4)
#define MODE2_OUTDRV BIT(2)
return err;
}
+static int pca9685_write_4reg(struct pwm_chip *chip, unsigned int reg, u8 val[4])
+{
+ struct pca9685 *pca = to_pca(chip);
+ struct device *dev = pwmchip_parent(chip);
+ int err;
+
+ err = regmap_bulk_write(pca->regmap, reg, val, 4);
+ if (err)
+ dev_err(dev, "regmap_write to register 0x%x failed: %pe\n", reg, ERR_PTR(err));
+
+ return err;
+}
+
/* Helper function to set the duty cycle ratio to duty/4096 (e.g. duty=2048 -> 50%) */
static void pca9685_pwm_set_duty(struct pwm_chip *chip, int channel, unsigned int duty)
{
return;
} else if (duty >= PCA9685_COUNTER_RANGE) {
/* Set the full ON bit and clear the full OFF bit */
- pca9685_write_reg(chip, REG_ON_H(channel), LED_FULL);
- pca9685_write_reg(chip, REG_OFF_H(channel), 0);
+ pca9685_write_4reg(chip, REG_ON_L(channel), (u8[4]){ 0, LED_FULL, 0, 0 });
return;
}
-
if (pwm->state.usage_power && channel < PCA9685_MAXCHAN) {
/*
* If usage_power is set, the pca9685 driver will phase shift
off = (on + duty) % PCA9685_COUNTER_RANGE;
- /* Set ON time (clears full ON bit) */
- pca9685_write_reg(chip, REG_ON_L(channel), on & 0xff);
- pca9685_write_reg(chip, REG_ON_H(channel), (on >> 8) & 0xf);
- /* Set OFF time (clears full OFF bit) */
- pca9685_write_reg(chip, REG_OFF_L(channel), off & 0xff);
- pca9685_write_reg(chip, REG_OFF_H(channel), (off >> 8) & 0xf);
+ /* implicitly clear full ON and full OFF bit */
+ pca9685_write_4reg(chip, REG_ON_L(channel),
+ (u8[4]){ on & 0xff, (on >> 8) & 0xf, off & 0xff, (off >> 8) & 0xf });
}
static unsigned int pca9685_pwm_get_duty(struct pwm_chip *chip, int channel)
mutex_init(&pca->lock);
- ret = pca9685_read_reg(chip, PCA9685_MODE2, ®);
- if (ret)
- return ret;
+ /* clear MODE2_OCH */
+ reg = 0;
if (device_property_read_bool(&client->dev, "invert"))
reg |= MODE2_INVRT;
if (ret)
return ret;
- /* Disable all LED ALLCALL and SUBx addresses to avoid bus collisions */
+ /*
+ * Disable all LED ALLCALL and SUBx addresses to avoid bus collisions,
+ * enable Auto-Increment.
+ */
pca9685_read_reg(chip, PCA9685_MODE1, ®);
reg &= ~(MODE1_ALLCALL | MODE1_SUB1 | MODE1_SUB2 | MODE1_SUB3);
+ reg |= MODE1_AI;
pca9685_write_reg(chip, PCA9685_MODE1, reg);
/* Reset OFF/ON registers to POR default */
- pca9685_write_reg(chip, PCA9685_ALL_LED_OFF_L, 0);
- pca9685_write_reg(chip, PCA9685_ALL_LED_OFF_H, LED_FULL);
- pca9685_write_reg(chip, PCA9685_ALL_LED_ON_L, 0);
- pca9685_write_reg(chip, PCA9685_ALL_LED_ON_H, LED_FULL);
+ ret = pca9685_write_4reg(chip, PCA9685_ALL_LED_ON_L, (u8[]){ 0, LED_FULL, 0, LED_FULL });
+ if (ret < 0)
+ return dev_err_probe(&client->dev, ret, "Failed to reset ON/OFF registers\n");
chip->ops = &pca9685_pwm_ops;