On Tue, Apr 06, 2021 at 06:41:39PM +0200, Clemens Gruber wrote: > Previously, the last used PWM channel could change the global prescale > setting, even if other channels are already in use. > > Fix it by only allowing the first enabled PWM to change the global > chip-wide prescale setting. If there is more than one channel in use, > the prescale settings resulting from the chosen periods must match. > > GPIOs do not count as enabled PWMs as they are not using the prescaler > and can't change it. > > Signed-off-by: Clemens Gruber > --- > Changes since v6: > - Only allow the first PWM that is enabled to change the prescaler, not > the first one that uses the prescaler > > drivers/pwm/pwm-pca9685.c | 66 +++++++++++++++++++++++++++++++++------ > 1 file changed, 56 insertions(+), 10 deletions(-) > > diff --git a/drivers/pwm/pwm-pca9685.c b/drivers/pwm/pwm-pca9685.c > index 24221ee7a77a..cf0c98e4ef44 100644 > --- a/drivers/pwm/pwm-pca9685.c > +++ b/drivers/pwm/pwm-pca9685.c > @@ -23,11 +23,11 @@ > #include > > /* > - * Because the PCA9685 has only one prescaler per chip, changing the period of > - * one channel affects the period of all 16 PWM outputs! > - * However, the ratio between each configured duty cycle and the chip-wide > - * period remains constant, because the OFF time is set in proportion to the > - * counter range. > + * Because the PCA9685 has only one prescaler per chip, only the first channel > + * that is enabled is allowed to change the prescale register. > + * PWM channels requested afterwards must use a period that results in the same > + * prescale setting as the one set by the first requested channel. > + * GPIOs do not count as enabled PWMs as they are not using the prescaler. > */ > > #define PCA9685_MODE1 0x00 > @@ -78,8 +78,9 @@ > struct pca9685 { > struct pwm_chip chip; > struct regmap *regmap; > -#if IS_ENABLED(CONFIG_GPIOLIB) > struct mutex lock; > + DECLARE_BITMAP(pwms_enabled, PCA9685_MAXCHAN + 1); > +#if IS_ENABLED(CONFIG_GPIOLIB) > struct gpio_chip gpio; > DECLARE_BITMAP(pwms_inuse, PCA9685_MAXCHAN + 1); > #endif > @@ -90,6 +91,22 @@ static inline struct pca9685 *to_pca(struct pwm_chip *chip) > return container_of(chip, struct pca9685, chip); > } > > +/* This function is supposed to be called with the lock mutex held */ > +static bool pca9685_prescaler_can_change(struct pca9685 *pca, int channel) > +{ > + /* No PWM enabled: Change allowed */ > + if (bitmap_empty(pca->pwms_enabled, PCA9685_MAXCHAN + 1)) > + return true; > + /* More than one PWM enabled: Change not allowed */ > + if (bitmap_weight(pca->pwms_enabled, PCA9685_MAXCHAN + 1) > 1) > + return false; > + /* > + * Only one PWM enabled: Change allowed if the PWM about to > + * be changed is the one that is already enabled > + */ > + return test_bit(channel, pca->pwms_enabled); Maybe this is a bit more effective?: DECLARE_BITMAP(blablub, PCA9685_MAXCHAN + 1); bitmap_zero(blablub, PCA9685_MAXCHAN + 1); bitmap_set(blablub, channel); return bitmap_subset(pca->pwms_enabled, blablub); (but that's a minor issue, the suggested algorithm is correct.) So: Acked-by: Uwe Kleine-König (side-note: I wonder if the handling of the set-all channel is correct here. But given that it is messy anyhow, (e.g. because setting some state to this set-all channel doesn't influence pwm_get_state for the individual channels) I don't object if there is another problem in this corner case. IMHO just dropping this virtual channel would be nice.) Best regards Uwe -- Pengutronix e.K. | Uwe Kleine-König | Industrial Linux Solutions | https://www.pengutronix.de/ |