Re: [PATCH v8 1/8] pwm: pca9685: Switch to atomic API

2021-04-17 Thread Clemens Gruber
Hi,

On Sat, Apr 17, 2021 at 05:37:28PM +0200, Uwe Kleine-König wrote:
> On Mon, Apr 12, 2021 at 03:27:38PM +0200, Clemens Gruber wrote:
> > The switch to the atomic API goes hand in hand with a few fixes to
> > previously experienced issues:
> > - The duty cycle is no longer lost after disable/enable (previously the
> >   OFF registers were cleared in disable and the user was required to
> >   call config to restore the duty cycle settings)
> > - If one sets a period resulting in the same prescale register value,
> >   the sleep and write to the register is now skipped
> > - Previously, only the full ON bit was toggled in GPIO mode (and full
> >   OFF cleared if set to high), which could result in both full OFF and
> >   full ON not being set and on=0, off=0, which is not allowed according
> >   to the datasheet
> > - The OFF registers were reset to 0 in probe, which could lead to the
> >   forbidden on=0, off=0. Fixed by resetting to POR default (full OFF)
> 
> I didn't recheck all details, but the patch is definitively an
> improvement, so:
> 
> Acked-by: Uwe Kleine-König 

Thanks, but there is a newer version v9, I assume your acks are meant
for the newer one?

Clemens


Re: [PATCH v8 4/8] dt-bindings: pwm: Support new PWM_USAGE_POWER flag

2021-04-16 Thread Clemens Gruber
On Fri, Apr 16, 2021 at 03:55:11PM +0200, Thierry Reding wrote:
> On Mon, Apr 12, 2021 at 03:27:41PM +0200, Clemens Gruber wrote:
> > Add the flag and corresponding documentation for PWM_USAGE_POWER.
> > 
> > Cc: Rob Herring 
> > Signed-off-by: Clemens Gruber 
> > ---
> >  Documentation/devicetree/bindings/pwm/pwm.txt | 3 +++
> >  include/dt-bindings/pwm/pwm.h | 1 +
> >  2 files changed, 4 insertions(+)
> 
> Rob, what are your thoughts on this? I've been thinking about this some
> more and I'm having second thoughts about putting this into device tree
> because it doesn't actually describe a property of the PWM hardware but
> rather a use-case specific hint. It's a bit of a gray area because this
> is just part of the PWM specifier which already has use-case specific
> "configuration", such as the period and the polarity.
> 
> Perhaps a better place for this is within the PWM API? We could add the
> same information into struct pwm_state and then consumers that don't
> care about specifics of the signal (such as pwm-backlight) can set that
> flag when they request a state to be applied.

I just want to note that in my opinion, this is not a flag that is
changed often, so is it really a good idea to require setting this
wherever PWM state is applied? Also, this can't be read-out in
.get_state.

Thierry: If this discussion carries on and a v10 is required: Could you
maybe merge the uncontroversial patches 1 to 3 of v9 separately and
maybe get those in 5.12 ? Patches 4 to 8 can probably wait for 5.13 and
have some time in linux-next.

Thanks,
Clemens


[PATCH v9 8/8] pwm: pca9685: Add error messages for failed regmap calls

2021-04-15 Thread Clemens Gruber
Regmap operations can fail if the underlying subsystem is not working
properly (e.g. hogged I2C bus, etc.)
As this is useful information for the user, print an error message if it
happens.
Let probe fail if the first regmap_read or the first regmap_write fails.

Signed-off-by: Clemens Gruber 
---
Changes since v8:
- Minor readability improvements
- Rebased

Changes since v7:
- Use %pe instead of %d for error codes (Suggested by Uwe)

 drivers/pwm/pwm-pca9685.c | 83 ---
 1 file changed, 59 insertions(+), 24 deletions(-)

diff --git a/drivers/pwm/pwm-pca9685.c b/drivers/pwm/pwm-pca9685.c
index f3ff36381c5b..e88e02118f25 100644
--- a/drivers/pwm/pwm-pca9685.c
+++ b/drivers/pwm/pwm-pca9685.c
@@ -107,6 +107,30 @@ static bool pca9685_prescaler_can_change(struct pca9685 
*pca, int channel)
return test_bit(channel, pca->pwms_enabled);
 }
 
+static int pca9685_read_reg(struct pca9685 *pca, unsigned int reg, unsigned 
int *val)
+{
+   struct device *dev = pca->chip.dev;
+   int err;
+
+   err = regmap_read(pca->regmap, reg, val);
+   if (err)
+   dev_err(dev, "regmap_read of register 0x%x failed: %pe\n", reg, 
ERR_PTR(err));
+
+   return err;
+}
+
+static int pca9685_write_reg(struct pca9685 *pca, unsigned int reg, unsigned 
int val)
+{
+   struct device *dev = pca->chip.dev;
+   int err;
+
+   err = regmap_write(pca->regmap, reg, val);
+   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 pca9685 *pca, int channel, unsigned 
int duty)
 {
@@ -115,12 +139,12 @@ static void pca9685_pwm_set_duty(struct pca9685 *pca, int 
channel, unsigned int
 
if (duty == 0) {
/* Set the full OFF bit, which has the highest precedence */
-   regmap_write(pca->regmap, REG_OFF_H(channel), LED_FULL);
+   pca9685_write_reg(pca, REG_OFF_H(channel), LED_FULL);
return;
} else if (duty >= PCA9685_COUNTER_RANGE) {
/* Set the full ON bit and clear the full OFF bit */
-   regmap_write(pca->regmap, REG_ON_H(channel), LED_FULL);
-   regmap_write(pca->regmap, REG_OFF_H(channel), 0);
+   pca9685_write_reg(pca, REG_ON_H(channel), LED_FULL);
+   pca9685_write_reg(pca, REG_OFF_H(channel), 0);
return;
}
 
@@ -141,11 +165,11 @@ static void pca9685_pwm_set_duty(struct pca9685 *pca, int 
channel, unsigned int
off = (on + duty) % PCA9685_COUNTER_RANGE;
 
/* Set ON time (clears full ON bit) */
-   regmap_write(pca->regmap, REG_ON_L(channel), on & 0xff);
-   regmap_write(pca->regmap, REG_ON_H(channel), (on >> 8) & 0xf);
+   pca9685_write_reg(pca, REG_ON_L(channel), on & 0xff);
+   pca9685_write_reg(pca, REG_ON_H(channel), (on >> 8) & 0xf);
/* Set OFF time (clears full OFF bit) */
-   regmap_write(pca->regmap, REG_OFF_L(channel), off & 0xff);
-   regmap_write(pca->regmap, REG_OFF_H(channel), (off >> 8) & 0xf);
+   pca9685_write_reg(pca, REG_OFF_L(channel), off & 0xff);
+   pca9685_write_reg(pca, REG_OFF_H(channel), (off >> 8) & 0xf);
 }
 
 static unsigned int pca9685_pwm_get_duty(struct pca9685 *pca, int channel)
@@ -158,25 +182,25 @@ static unsigned int pca9685_pwm_get_duty(struct pca9685 
*pca, int channel)
return 0;
}
 
-   regmap_read(pca->regmap, LED_N_OFF_H(channel), );
+   pca9685_read_reg(pca, LED_N_OFF_H(channel), );
if (off & LED_FULL) {
/* Full OFF bit is set */
return 0;
}
 
-   regmap_read(pca->regmap, LED_N_ON_H(channel), );
+   pca9685_read_reg(pca, LED_N_ON_H(channel), );
if (on & LED_FULL) {
/* Full ON bit is set */
return PCA9685_COUNTER_RANGE;
}
 
-   regmap_read(pca->regmap, LED_N_OFF_L(channel), );
+   pca9685_read_reg(pca, LED_N_OFF_L(channel), );
off = ((off & 0xf) << 8) | (val & 0xff);
if (!pwm->args.usage_power)
return off;
 
/* Read ON register to calculate duty cycle of staggered output */
-   if (regmap_read(pca->regmap, LED_N_ON_L(channel), )) {
+   if (pca9685_read_reg(pca, LED_N_ON_L(channel), )) {
/* Reset val to 0 in case reading LED_N_ON_L failed */
val = 0;
}
@@ -322,8 +346,15 @@ static inline int pca9685_pwm_gpio_probe(struct pca9685 
*pca)
 
 static void pca9685_set_sleep_mode(struct pca9685 *pca, bool enable)
 {
-   regmap_update_bits(pca->regmap, PCA9685_MODE1,
-   

[PATCH v9 7/8] pwm: pca9685: Restrict period change for enabled PWMs

2021-04-15 Thread Clemens Gruber
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 v8:
- Rebased

Changes since v7:
- As the HW readout always returns enabled, also set the pwms_enabled
  bit in request (except for the "all LEDs" channel)

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 | 74 +--
 1 file changed, 64 insertions(+), 10 deletions(-)

diff --git a/drivers/pwm/pwm-pca9685.c b/drivers/pwm/pwm-pca9685.c
index 315a75db254d..f3ff36381c5b 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);
+}
+
 /* Helper function to set the duty cycle ratio to duty/4096 (e.g. duty=2048 -> 
50%) */
 static void pca9685_pwm_set_duty(struct pca9685 *pca, int channel, unsigned 
int duty)
 {
@@ -270,8 +287,6 @@ static int pca9685_pwm_gpio_probe(struct pca9685 *pca)
 {
struct device *dev = pca->chip.dev;
 
-   mutex_init(>lock);
-
pca->gpio.label = dev_name(dev);
pca->gpio.parent = dev;
pca->gpio.request = pca9685_pwm_gpio_request;
@@ -315,8 +330,8 @@ static void pca9685_set_sleep_mode(struct pca9685 *pca, 
bool enable)
}
 }
 
-static int pca9685_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
-const struct pwm_state *state)
+static int __pca9685_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
+  const struct pwm_state *state)
 {
struct pca9685 *pca = to_pca(chip);
unsigned long long duty, prescale;
@@ -339,6 +354,12 @@ static int pca9685_pwm_apply(struct pwm_chip *chip, struct 
pwm_device *pwm,
 
regmap_read(pca->regmap, PCA9685_PRESCALE, );
if (prescale != val) {
+   if (!pca9685_prescaler_can_change(pca, pwm->hwpwm)) {
+   dev_err(chip->dev,
+   "pwm not changed: periods of enabled pwms must 
match!\n");
+   return -EBUSY;
+   }
+
/*
 * Putting the chip briefly into SLEEP mode
 * at this point won't interfere with the
@@ -361,6 +382,25 @@ static int pca9685_pwm_apply(struct pwm_chip *chip, struct 
pwm_device *pwm,
return 0;
 }
 
+static int pca9685_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
+const struct pwm_state *state)
+{
+   struct pca9685 *pca = to_pca(chip);
+   int ret;
+
+   mutex_lock(>lock);
+   ret = __pca9685_pwm_apply(chip, pwm, state);
+   if (ret == 0) {
+   if (s

[PATCH v9 6/8] pwm: pca9685: Support new PWM_USAGE_POWER flag

2021-04-15 Thread Clemens Gruber
If PWM_USAGE_POWER is set on a PWM, the pca9685 driver will phase shift
the individual channels relative to their channel number. This improves
EMI because the enabled channels no longer turn on at the same time,
while still maintaining the configured duty cycle / power output.

Signed-off-by: Clemens Gruber 
---
Changes since v8:
- Improved readability of failed regmap_read
- Rebased

 drivers/pwm/pwm-pca9685.c | 65 ++-
 1 file changed, 50 insertions(+), 15 deletions(-)

diff --git a/drivers/pwm/pwm-pca9685.c b/drivers/pwm/pwm-pca9685.c
index 1b013d03f5d8..315a75db254d 100644
--- a/drivers/pwm/pwm-pca9685.c
+++ b/drivers/pwm/pwm-pca9685.c
@@ -93,48 +93,78 @@ static inline struct pca9685 *to_pca(struct pwm_chip *chip)
 /* Helper function to set the duty cycle ratio to duty/4096 (e.g. duty=2048 -> 
50%) */
 static void pca9685_pwm_set_duty(struct pca9685 *pca, int channel, unsigned 
int duty)
 {
+   struct pwm_device *pwm = >chip.pwms[channel];
+   unsigned int on, off;
+
if (duty == 0) {
/* Set the full OFF bit, which has the highest precedence */
regmap_write(pca->regmap, REG_OFF_H(channel), LED_FULL);
+   return;
} else if (duty >= PCA9685_COUNTER_RANGE) {
/* Set the full ON bit and clear the full OFF bit */
regmap_write(pca->regmap, REG_ON_H(channel), LED_FULL);
regmap_write(pca->regmap, REG_OFF_H(channel), 0);
-   } else {
-   /* Set OFF time (clears the full OFF bit) */
-   regmap_write(pca->regmap, REG_OFF_L(channel), duty & 0xff);
-   regmap_write(pca->regmap, REG_OFF_H(channel), (duty >> 8) & 
0xf);
-   /* Clear the full ON bit */
-   regmap_write(pca->regmap, REG_ON_H(channel), 0);
+   return;
}
+
+
+   if (pwm->args.usage_power && channel < PCA9685_MAXCHAN) {
+   /*
+* If PWM_USAGE_POWER is set on a PWM, the pca9685
+* driver will phase shift the individual channels
+* relative to their channel number.
+* This improves EMI because the enabled channels no
+* longer turn on at the same time, while still
+* maintaining the configured duty cycle / power output.
+*/
+   on = channel * PCA9685_COUNTER_RANGE / PCA9685_MAXCHAN;
+   } else
+   on = 0;
+
+   off = (on + duty) % PCA9685_COUNTER_RANGE;
+
+   /* Set ON time (clears full ON bit) */
+   regmap_write(pca->regmap, REG_ON_L(channel), on & 0xff);
+   regmap_write(pca->regmap, REG_ON_H(channel), (on >> 8) & 0xf);
+   /* Set OFF time (clears full OFF bit) */
+   regmap_write(pca->regmap, REG_OFF_L(channel), off & 0xff);
+   regmap_write(pca->regmap, REG_OFF_H(channel), (off >> 8) & 0xf);
 }
 
 static unsigned int pca9685_pwm_get_duty(struct pca9685 *pca, int channel)
 {
-   unsigned int off_h = 0, val = 0;
+   struct pwm_device *pwm = >chip.pwms[channel];
+   unsigned int off = 0, on = 0, val = 0;
 
if (WARN_ON(channel >= PCA9685_MAXCHAN)) {
/* HW does not support reading state of "all LEDs" channel */
return 0;
}
 
-   regmap_read(pca->regmap, LED_N_OFF_H(channel), _h);
-   if (off_h & LED_FULL) {
+   regmap_read(pca->regmap, LED_N_OFF_H(channel), );
+   if (off & LED_FULL) {
/* Full OFF bit is set */
return 0;
}
 
-   regmap_read(pca->regmap, LED_N_ON_H(channel), );
-   if (val & LED_FULL) {
+   regmap_read(pca->regmap, LED_N_ON_H(channel), );
+   if (on & LED_FULL) {
/* Full ON bit is set */
return PCA9685_COUNTER_RANGE;
}
 
-   if (regmap_read(pca->regmap, LED_N_OFF_L(channel), )) {
-   /* Reset val to 0 in case reading LED_N_OFF_L failed */
+   regmap_read(pca->regmap, LED_N_OFF_L(channel), );
+   off = ((off & 0xf) << 8) | (val & 0xff);
+   if (!pwm->args.usage_power)
+   return off;
+
+   /* Read ON register to calculate duty cycle of staggered output */
+   if (regmap_read(pca->regmap, LED_N_ON_L(channel), )) {
+   /* Reset val to 0 in case reading LED_N_ON_L failed */
val = 0;
}
-   return ((off_h & 0xf) << 8) | (val & 0xff);
+   on = ((on & 0xf) << 8) | (val & 0xff);
+   return (off - on) & (PCA9685_COUNTER_RANGE - 1);
 }
 
 #if IS_ENABLED(CONFIG_GPIOLIB)
@@ -441,9 +471,11 @@ static int pca9685_pwm_probe(struct i2c_client *client,
reg &= ~(MODE1_ALLCALL | MODE1_SUB1 | MODE1_SUB2 | MODE1_SUB3);
regmap_write(pca->regmap, PCA9685_MODE1, reg);

[PATCH v9 4/8] dt-bindings: pwm: Support new PWM_USAGE_POWER flag

2021-04-15 Thread Clemens Gruber
Add the flag and corresponding documentation for PWM_USAGE_POWER.

Cc: Rob Herring 
Signed-off-by: Clemens Gruber 
---
 Documentation/devicetree/bindings/pwm/pwm.txt | 3 +++
 include/dt-bindings/pwm/pwm.h | 1 +
 2 files changed, 4 insertions(+)

diff --git a/Documentation/devicetree/bindings/pwm/pwm.txt 
b/Documentation/devicetree/bindings/pwm/pwm.txt
index 084886bd721e..fe3a28f887c0 100644
--- a/Documentation/devicetree/bindings/pwm/pwm.txt
+++ b/Documentation/devicetree/bindings/pwm/pwm.txt
@@ -46,6 +46,9 @@ period in nanoseconds.
 Optionally, the pwm-specifier can encode a number of flags (defined in
 ) in a third cell:
 - PWM_POLARITY_INVERTED: invert the PWM signal polarity
+- PWM_USAGE_POWER: Only care about the power output of the signal. This
+  allows drivers (if supported) to optimize the signals, for example to
+  improve EMI and reduce current spikes.
 
 Example with optional PWM specifier for inverse polarity
 
diff --git a/include/dt-bindings/pwm/pwm.h b/include/dt-bindings/pwm/pwm.h
index ab9a077e3c7d..0d5a8f0c0035 100644
--- a/include/dt-bindings/pwm/pwm.h
+++ b/include/dt-bindings/pwm/pwm.h
@@ -11,5 +11,6 @@
 #define _DT_BINDINGS_PWM_PWM_H
 
 #define PWM_POLARITY_INVERTED  (1 << 0)
+#define PWM_USAGE_POWER(1 << 1)
 
 #endif
-- 
2.31.1



[PATCH v9 5/8] pwm: core: Support new PWM_USAGE_POWER flag

2021-04-15 Thread Clemens Gruber
If the flag PWM_USAGE_POWER is set on a channel, the PWM driver may
optimize the signal as long as the power output is not changed.

Depending on the specific driver, the optimization could for example
improve EMI (if supported) by phase-shifting the individual channels.

Signed-off-by: Clemens Gruber 
---
 drivers/pwm/core.c  | 9 +++--
 include/linux/pwm.h | 1 +
 2 files changed, 8 insertions(+), 2 deletions(-)

diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c
index a8eff4b3ee36..56a9c739e1b2 100644
--- a/drivers/pwm/core.c
+++ b/drivers/pwm/core.c
@@ -153,9 +153,14 @@ of_pwm_xlate_with_flags(struct pwm_chip *pc, const struct 
of_phandle_args *args)
 
pwm->args.period = args->args[1];
pwm->args.polarity = PWM_POLARITY_NORMAL;
+   pwm->args.usage_power = false;
 
-   if (args->args_count > 2 && args->args[2] & PWM_POLARITY_INVERTED)
-   pwm->args.polarity = PWM_POLARITY_INVERSED;
+   if (args->args_count > 2) {
+   if (args->args[2] & PWM_POLARITY_INVERTED)
+   pwm->args.polarity = PWM_POLARITY_INVERSED;
+   if (args->args[2] & PWM_USAGE_POWER)
+   pwm->args.usage_power = true;
+   }
 
return pwm;
 }
diff --git a/include/linux/pwm.h b/include/linux/pwm.h
index e4d84d4db293..555e050e8bec 100644
--- a/include/linux/pwm.h
+++ b/include/linux/pwm.h
@@ -41,6 +41,7 @@ enum pwm_polarity {
 struct pwm_args {
u64 period;
enum pwm_polarity polarity;
+   bool usage_power;
 };
 
 enum {
-- 
2.31.1



[PATCH v9 3/8] pwm: pca9685: Improve runtime PM behavior

2021-04-15 Thread Clemens Gruber
The chip does not come out of POR in active state but in sleep state.
To be sure (in case the bootloader woke it up) we force it to sleep in
probe.

If runtime PM is disabled, we instead wake the chip in .probe and put it
to sleep in .remove.

Signed-off-by: Clemens Gruber 
---
Changes since v8:
- Rebased

Changes since v7:
- Handle sysfs power control as well and not just CONFIG_PM

Changes since v6:
- Improved !CONFIG_PM handling (wake it up without putting it to sleep
  first)

 drivers/pwm/pwm-pca9685.c | 25 +++--
 1 file changed, 19 insertions(+), 6 deletions(-)

diff --git a/drivers/pwm/pwm-pca9685.c b/drivers/pwm/pwm-pca9685.c
index aa48c45bd294..1b013d03f5d8 100644
--- a/drivers/pwm/pwm-pca9685.c
+++ b/drivers/pwm/pwm-pca9685.c
@@ -462,14 +462,20 @@ static int pca9685_pwm_probe(struct i2c_client *client,
return ret;
}
 
-   /* The chip comes out of power-up in the active state */
-   pm_runtime_set_active(>dev);
-   /*
-* Enable will put the chip into suspend, which is what we
-* want as all outputs are disabled at this point
-*/
pm_runtime_enable(>dev);
 
+   if (pm_runtime_enabled(>dev)) {
+   /*
+* Although the chip comes out of power-up in the sleep state,
+* we force it to sleep in case it was woken up before
+*/
+   pca9685_set_sleep_mode(pca, true);
+   pm_runtime_set_suspended(>dev);
+   } else {
+   /* Wake the chip up if runtime PM is disabled */
+   pca9685_set_sleep_mode(pca, false);
+   }
+
return 0;
 }
 
@@ -481,7 +487,14 @@ static int pca9685_pwm_remove(struct i2c_client *client)
ret = pwmchip_remove(>chip);
if (ret)
return ret;
+
+   if (!pm_runtime_enabled(>dev)) {
+   /* Put chip in sleep state if runtime PM is disabled */
+   pca9685_set_sleep_mode(pca, true);
+   }
+
pm_runtime_disable(>dev);
+
return 0;
 }
 
-- 
2.31.1



[PATCH v9 2/8] pwm: pca9685: Support hardware readout

2021-04-15 Thread Clemens Gruber
Implement .get_state to read-out the current hardware state.

The hardware readout may return slightly different values than those
that were set in apply due to the limited range of possible prescale and
counter register values.

Also note that although the datasheet mentions 200 Hz as default
frequency when using the internal 25 MHz oscillator, the calculated
period from the default prescaler register setting of 30 is 5079040ns.

Signed-off-by: Clemens Gruber 
---
Changes since v8:
- As we left the math in apply as-is, use DIV_ROUND_DOWN in get_state

Changes since v7:
- Always return enabled=true for channels except "all LEDs" channel
- Use DIV_ROUND_UP in .get_state

Changes since v6:
- Added a comment regarding the division (Suggested by Uwe)
- Rebased

 drivers/pwm/pwm-pca9685.c | 36 
 1 file changed, 36 insertions(+)

diff --git a/drivers/pwm/pwm-pca9685.c b/drivers/pwm/pwm-pca9685.c
index ea19d72e5c34..aa48c45bd294 100644
--- a/drivers/pwm/pwm-pca9685.c
+++ b/drivers/pwm/pwm-pca9685.c
@@ -331,6 +331,41 @@ static int pca9685_pwm_apply(struct pwm_chip *chip, struct 
pwm_device *pwm,
return 0;
 }
 
+static void pca9685_pwm_get_state(struct pwm_chip *chip, struct pwm_device 
*pwm,
+ struct pwm_state *state)
+{
+   struct pca9685 *pca = to_pca(chip);
+   unsigned long long duty;
+   unsigned int val = 0;
+
+   /* Calculate (chip-wide) period from prescale value */
+   regmap_read(pca->regmap, PCA9685_PRESCALE, );
+   /*
+* PCA9685_OSC_CLOCK_MHZ is 25, i.e. an integer divider of 1000.
+* The following calculation is therefore only a multiplication
+* and we are not losing precision.
+*/
+   state->period = (PCA9685_COUNTER_RANGE * 1000 / PCA9685_OSC_CLOCK_MHZ) *
+   (val + 1);
+
+   /* The (per-channel) polarity is fixed */
+   state->polarity = PWM_POLARITY_NORMAL;
+
+   if (pwm->hwpwm >= PCA9685_MAXCHAN) {
+   /*
+* The "all LEDs" channel does not support HW readout
+* Return 0 and disabled for backwards compatibility
+*/
+   state->duty_cycle = 0;
+   state->enabled = false;
+   return;
+   }
+
+   state->enabled = true;
+   duty = pca9685_pwm_get_duty(pca, pwm->hwpwm);
+   state->duty_cycle = DIV_ROUND_DOWN_ULL(duty * state->period, 
PCA9685_COUNTER_RANGE);
+}
+
 static int pca9685_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
 {
struct pca9685 *pca = to_pca(chip);
@@ -353,6 +388,7 @@ static void pca9685_pwm_free(struct pwm_chip *chip, struct 
pwm_device *pwm)
 
 static const struct pwm_ops pca9685_pwm_ops = {
.apply = pca9685_pwm_apply,
+   .get_state = pca9685_pwm_get_state,
.request = pca9685_pwm_request,
.free = pca9685_pwm_free,
.owner = THIS_MODULE,
-- 
2.31.1



[PATCH v9 1/8] pwm: pca9685: Switch to atomic API

2021-04-15 Thread Clemens Gruber
The switch to the atomic API goes hand in hand with a few fixes to
previously experienced issues:
- The duty cycle is no longer lost after disable/enable (previously the
  OFF registers were cleared in disable and the user was required to
  call config to restore the duty cycle settings)
- If one sets a period resulting in the same prescale register value,
  the sleep and write to the register is now skipped
- Previously, only the full ON bit was toggled in GPIO mode (and full
  OFF cleared if set to high), which could result in both full OFF and
  full ON not being set and on=0, off=0, which is not allowed according
  to the datasheet
- The OFF registers were reset to 0 in probe, which could lead to the
  forbidden on=0, off=0. Fixed by resetting to POR default (full OFF)

Signed-off-by: Clemens Gruber 
---
Changes since v8:
- Revert to DIV_ROUND_UP (keep math as-is)
- Readability improvement for failed regmap_read

Changes since v7:
- Moved check for !state->enabled before prescaler configuration
- Removed unnecessary cast
- Use DIV_ROUND_DOWN in .apply

Changes since v6:
- Order of a comparison switched for improved readability

Changes since v5:
- Function documentation for set_duty
- Variable initializations
- Print warning if all LEDs channel
- Changed EOPNOTSUPP to EINVAL
- Improved error messages
- Register reset corrections moved to this patch

Changes since v4:
- Patches split up
- Use a single set_duty function
- Improve readability / new macros
- Added a patch to restrict prescale changes to the first user

Changes since v3:
- Refactoring: Extracted common functions
- Read prescale register value instead of caching it
- Return all zeros and disabled for "all LEDs" channel state
- Improved duty calculation / mapping to 0..4096

Changes since v2:
- Always set default prescale value in probe
- Simplified probe code
- Inlined functions with one callsite

Changes since v1:
- Fixed a logic error
- Impoved PM runtime handling and fixed !CONFIG_PM
- Write default prescale reg value if invalid in probe
- Reuse full_off/_on functions throughout driver
- Use cached prescale value whenever possible

 drivers/pwm/pwm-pca9685.c | 261 +-
 1 file changed, 91 insertions(+), 170 deletions(-)

diff --git a/drivers/pwm/pwm-pca9685.c b/drivers/pwm/pwm-pca9685.c
index 4a55dc18656c..ea19d72e5c34 100644
--- a/drivers/pwm/pwm-pca9685.c
+++ b/drivers/pwm/pwm-pca9685.c
@@ -51,7 +51,6 @@
 #define PCA9685_PRESCALE_MAX   0xFF/* => min. frequency of 24 Hz */
 
 #define PCA9685_COUNTER_RANGE  4096
-#define PCA9685_DEFAULT_PERIOD 500 /* Default period_ns = 1/200 Hz */
 #define PCA9685_OSC_CLOCK_MHZ  25  /* Internal oscillator with 25 MHz */
 
 #define PCA9685_NUMREGS0xFF
@@ -71,10 +70,14 @@
 #define LED_N_OFF_H(N) (PCA9685_LEDX_OFF_H + (4 * (N)))
 #define LED_N_OFF_L(N) (PCA9685_LEDX_OFF_L + (4 * (N)))
 
+#define REG_ON_H(C)((C) >= PCA9685_MAXCHAN ? PCA9685_ALL_LED_ON_H : 
LED_N_ON_H((C)))
+#define REG_ON_L(C)((C) >= PCA9685_MAXCHAN ? PCA9685_ALL_LED_ON_L : 
LED_N_ON_L((C)))
+#define REG_OFF_H(C)   ((C) >= PCA9685_MAXCHAN ? PCA9685_ALL_LED_OFF_H : 
LED_N_OFF_H((C)))
+#define REG_OFF_L(C)   ((C) >= PCA9685_MAXCHAN ? PCA9685_ALL_LED_OFF_L : 
LED_N_OFF_L((C)))
+
 struct pca9685 {
struct pwm_chip chip;
struct regmap *regmap;
-   int period_ns;
 #if IS_ENABLED(CONFIG_GPIOLIB)
struct mutex lock;
struct gpio_chip gpio;
@@ -87,6 +90,53 @@ static inline struct pca9685 *to_pca(struct pwm_chip *chip)
return container_of(chip, struct pca9685, chip);
 }
 
+/* Helper function to set the duty cycle ratio to duty/4096 (e.g. duty=2048 -> 
50%) */
+static void pca9685_pwm_set_duty(struct pca9685 *pca, int channel, unsigned 
int duty)
+{
+   if (duty == 0) {
+   /* Set the full OFF bit, which has the highest precedence */
+   regmap_write(pca->regmap, REG_OFF_H(channel), LED_FULL);
+   } else if (duty >= PCA9685_COUNTER_RANGE) {
+   /* Set the full ON bit and clear the full OFF bit */
+   regmap_write(pca->regmap, REG_ON_H(channel), LED_FULL);
+   regmap_write(pca->regmap, REG_OFF_H(channel), 0);
+   } else {
+   /* Set OFF time (clears the full OFF bit) */
+   regmap_write(pca->regmap, REG_OFF_L(channel), duty & 0xff);
+   regmap_write(pca->regmap, REG_OFF_H(channel), (duty >> 8) & 
0xf);
+   /* Clear the full ON bit */
+   regmap_write(pca->regmap, REG_ON_H(channel), 0);
+   }
+}
+
+static unsigned int pca9685_pwm_get_duty(struct pca9685 *pca, int channel)
+{
+   unsigned int off_h = 0, val = 0;
+
+   if (WARN_ON(channel >= PCA9685_MAXCHAN)) {
+   /* HW does not support reading state of "all LEDs" channel */
+   return 0;
+   }
+
+   regmap_read(pca->regmap, LED_N_OFF_H(cha

Re: [PATCH v8 1/8] pwm: pca9685: Switch to atomic API

2021-04-14 Thread Clemens Gruber
On Wed, Apr 14, 2021 at 09:21:31PM +0200, Uwe Kleine-König wrote:
> On Wed, Apr 14, 2021 at 02:09:14PM +0200, Clemens Gruber wrote:
> > Hi Uwe,
> > 
> > On Tue, Apr 13, 2021 at 09:38:18PM +0200, Uwe Kleine-König wrote:
> > > Hello Clemens,
> > > 
> > > On Tue, Apr 13, 2021 at 02:11:38PM +0200, Clemens Gruber wrote:
> > > > On Mon, Apr 12, 2021 at 10:10:19PM +0200, Uwe Kleine-König wrote:
> > > > > On Mon, Apr 12, 2021 at 06:39:28PM +0200, Clemens Gruber wrote:
> > > > > > With your suggested round-down, the example with frequency of 200 Hz
> > > > > > would no longer result in 30 but 29 and that contradicts the 
> > > > > > datasheet.
> > > > > 
> > > > > Well, with PRESCALE = 30 we get a frequency of 196.88 Hz and with
> > > > > PRESCALE = 29 we get a frequency of 203.45 Hz. So no matter if you 
> > > > > pick
> > > > > 29 or 30, you don't get 200 Hz. And which of the two possible values 
> > > > > is
> > > > > the better one depends on the consumer, no matter what rounding
> > > > > algorithm the data sheet suggests. Also note that the math here 
> > > > > contains
> > > > > surprises you don't expect at first. For example, what PRESCALE value
> > > > > would you pick to get 284 Hz? [If my mail was a video, I'd suggest to
> > > > > press Space now to pause and let you think first :-)] The data sheet's
> > > > > formula suggests:
> > > > > 
> > > > >   round(25 MHz / (4096 * 284)) - 1 = 20
> > > > > 
> > > > > The resulting frequency when picking PRESCALE = 20 is 290.644 Hz (so 
> > > > > an
> > > > > error of 6.644 Hz). If instead you pick PRESCALE = 21 you get 277.433 
> > > > > Hz
> > > > > (error = 6.567 Hz), so 21 is the better choice.
> > > > > 
> > > > > Exercise for the reader:
> > > > >  What is the correct formula to really determine the PRESCALE value 
> > > > > that
> > > > >  yields the best approximation (i.e. minimizing
> > > > >  abs(real_freq - target_freq)) for a given target_freq?
> > > 
> > > I wonder if you tried this.
> > 
> > We could calculate both round-up and round-down and decide which one is
> > closer to "real freq" (even though that is not the actual frequency but
> > just our backwards-calculated frequency).
> 
> Yeah, the backwards-calculated frequency is the best assumption we
> have.
> 
> > But I can't give you a formula with minimized abs(real_freq-target_freq)
> > Is it a different round point than 0.5 and maybe relative to f ?
> > 
> > Please enlighten us :-)
> 
> Sorry, I cannot. I spend ~20 min today after lunch with pencil and
> paper, but without success. I was aware that it isn't trivial and this
> is the main reason I established round-down as default for new drivers
> instead of round-nearest.

Oh, I thought you already solved it. I tried too for a while but was
unsuccessful. Not trivial indeed!

But regarding you establishing round-down: Wouldn't it be even better if
the driver did what I suggested above, namely calculate backwards from
both the rounded-up as well as the rounded-down prescale value and then
write the one with the smallest abs(f_target - f_real) to the register?

Clemens


Re: [PATCH v8 1/8] pwm: pca9685: Switch to atomic API

2021-04-14 Thread Clemens Gruber
Hi Uwe,

On Tue, Apr 13, 2021 at 09:38:18PM +0200, Uwe Kleine-König wrote:
> Hello Clemens,
> 
> On Tue, Apr 13, 2021 at 02:11:38PM +0200, Clemens Gruber wrote:
> > On Mon, Apr 12, 2021 at 10:10:19PM +0200, Uwe Kleine-König wrote:
> > > On Mon, Apr 12, 2021 at 06:39:28PM +0200, Clemens Gruber wrote:
> > > > On Mon, Apr 12, 2021 at 06:18:08PM +0200, Uwe Kleine-König wrote:
> > > > > On Mon, Apr 12, 2021 at 03:27:38PM +0200, Clemens Gruber wrote:
> > > > > > The switch to the atomic API goes hand in hand with a few fixes to
> > > > > > previously experienced issues:
> > > > > > - The duty cycle is no longer lost after disable/enable (previously 
> > > > > > the
> > > > > >   OFF registers were cleared in disable and the user was required to
> > > > > >   call config to restore the duty cycle settings)
> > > > > > - If one sets a period resulting in the same prescale register 
> > > > > > value,
> > > > > >   the sleep and write to the register is now skipped
> > > > > > - Previously, only the full ON bit was toggled in GPIO mode (and 
> > > > > > full
> > > > > >   OFF cleared if set to high), which could result in both full OFF 
> > > > > > and
> > > > > >   full ON not being set and on=0, off=0, which is not allowed 
> > > > > > according
> > > > > >   to the datasheet
> > > > > > - The OFF registers were reset to 0 in probe, which could lead to 
> > > > > > the
> > > > > >   forbidden on=0, off=0. Fixed by resetting to POR default (full 
> > > > > > OFF)
> > > > > > 
> > > > > > Signed-off-by: Clemens Gruber 
> > > > > > ---
> > > > > > Changes since v7:
> > > > > > - Moved check for !state->enabled before prescaler configuration
> > > > > > - Removed unnecessary cast
> > > > > > - Use DIV_ROUND_DOWN in .apply
> > > > > > 
> > > > > > Changes since v6:
> > > > > > - Order of a comparison switched for improved readability
> > > > > > 
> > > > > > Changes since v5:
> > > > > > - Function documentation for set_duty
> > > > > > - Variable initializations
> > > > > > - Print warning if all LEDs channel
> > > > > > - Changed EOPNOTSUPP to EINVAL
> > > > > > - Improved error messages
> > > > > > - Register reset corrections moved to this patch
> > > > > > 
> > > > > > Changes since v4:
> > > > > > - Patches split up
> > > > > > - Use a single set_duty function
> > > > > > - Improve readability / new macros
> > > > > > - Added a patch to restrict prescale changes to the first user
> > > > > > 
> > > > > > Changes since v3:
> > > > > > - Refactoring: Extracted common functions
> > > > > > - Read prescale register value instead of caching it
> > > > > > - Return all zeros and disabled for "all LEDs" channel state
> > > > > > - Improved duty calculation / mapping to 0..4096
> > > > > > 
> > > > > > Changes since v2:
> > > > > > - Always set default prescale value in probe
> > > > > > - Simplified probe code
> > > > > > - Inlined functions with one callsite
> > > > > > 
> > > > > > Changes since v1:
> > > > > > - Fixed a logic error
> > > > > > - Impoved PM runtime handling and fixed !CONFIG_PM
> > > > > > - Write default prescale reg value if invalid in probe
> > > > > > - Reuse full_off/_on functions throughout driver
> > > > > > - Use cached prescale value whenever possible
> > > > > > 
> > > > > >  drivers/pwm/pwm-pca9685.c | 259 
> > > > > > +-
> > > > > >  1 file changed, 89 insertions(+), 170 deletions(-)
> > > > > > 
> > > > > > diff --git a/drivers/pwm/pwm-pca9685.c b/drivers/pwm/pwm-pca9685.c
> > > > > > index 4a55dc18656c..827b57ced3c2 100644
> > > > > > --- a/drivers/pwm/pwm-pca9685.c
> > > > > > +++ b/drivers/pwm/pwm-pca9685.c
> > > > &g

Re: [PATCH v8 1/8] pwm: pca9685: Switch to atomic API

2021-04-13 Thread Clemens Gruber
On Tue, Apr 13, 2021 at 02:37:50PM +0200, Thierry Reding wrote:
> On Tue, Apr 13, 2021 at 02:11:38PM +0200, Clemens Gruber wrote:
> > Hi Uwe,
> > 
> > On Mon, Apr 12, 2021 at 10:10:19PM +0200, Uwe Kleine-König wrote:
> > > Hello Clemens,
> > > 
> > > On Mon, Apr 12, 2021 at 06:39:28PM +0200, Clemens Gruber wrote:
> > > > On Mon, Apr 12, 2021 at 06:18:08PM +0200, Uwe Kleine-König wrote:
> > > > > On Mon, Apr 12, 2021 at 03:27:38PM +0200, Clemens Gruber wrote:
> > > > > > The switch to the atomic API goes hand in hand with a few fixes to
> > > > > > previously experienced issues:
> > > > > > - The duty cycle is no longer lost after disable/enable (previously 
> > > > > > the
> > > > > >   OFF registers were cleared in disable and the user was required to
> > > > > >   call config to restore the duty cycle settings)
> > > > > > - If one sets a period resulting in the same prescale register 
> > > > > > value,
> > > > > >   the sleep and write to the register is now skipped
> > > > > > - Previously, only the full ON bit was toggled in GPIO mode (and 
> > > > > > full
> > > > > >   OFF cleared if set to high), which could result in both full OFF 
> > > > > > and
> > > > > >   full ON not being set and on=0, off=0, which is not allowed 
> > > > > > according
> > > > > >   to the datasheet
> > > > > > - The OFF registers were reset to 0 in probe, which could lead to 
> > > > > > the
> > > > > >   forbidden on=0, off=0. Fixed by resetting to POR default (full 
> > > > > > OFF)
> > > > > > 
> > > > > > Signed-off-by: Clemens Gruber 
> > > > > > ---
> > > > > > Changes since v7:
> > > > > > - Moved check for !state->enabled before prescaler configuration
> > > > > > - Removed unnecessary cast
> > > > > > - Use DIV_ROUND_DOWN in .apply
> > > > > > 
> > > > > > Changes since v6:
> > > > > > - Order of a comparison switched for improved readability
> > > > > > 
> > > > > > Changes since v5:
> > > > > > - Function documentation for set_duty
> > > > > > - Variable initializations
> > > > > > - Print warning if all LEDs channel
> > > > > > - Changed EOPNOTSUPP to EINVAL
> > > > > > - Improved error messages
> > > > > > - Register reset corrections moved to this patch
> > > > > > 
> > > > > > Changes since v4:
> > > > > > - Patches split up
> > > > > > - Use a single set_duty function
> > > > > > - Improve readability / new macros
> > > > > > - Added a patch to restrict prescale changes to the first user
> > > > > > 
> > > > > > Changes since v3:
> > > > > > - Refactoring: Extracted common functions
> > > > > > - Read prescale register value instead of caching it
> > > > > > - Return all zeros and disabled for "all LEDs" channel state
> > > > > > - Improved duty calculation / mapping to 0..4096
> > > > > > 
> > > > > > Changes since v2:
> > > > > > - Always set default prescale value in probe
> > > > > > - Simplified probe code
> > > > > > - Inlined functions with one callsite
> > > > > > 
> > > > > > Changes since v1:
> > > > > > - Fixed a logic error
> > > > > > - Impoved PM runtime handling and fixed !CONFIG_PM
> > > > > > - Write default prescale reg value if invalid in probe
> > > > > > - Reuse full_off/_on functions throughout driver
> > > > > > - Use cached prescale value whenever possible
> > > > > > 
> > > > > >  drivers/pwm/pwm-pca9685.c | 259 
> > > > > > +-
> > > > > >  1 file changed, 89 insertions(+), 170 deletions(-)
> > > > > > 
> > > > > > diff --git a/drivers/pwm/pwm-pca9685.c b/drivers/pwm/pwm-pca9685.c
> > > > > > index 4a55dc18656c..827b57ced3c2 100644
> > > > > > --- a/drivers/pwm/pwm-pca9685.c
> > > > > > +++ b/drivers/

Re: [PATCH v8 1/8] pwm: pca9685: Switch to atomic API

2021-04-13 Thread Clemens Gruber
On Tue, Apr 13, 2021 at 02:11:38PM +0200, Clemens Gruber wrote:
> Hi Uwe,
> 
> On Mon, Apr 12, 2021 at 10:10:19PM +0200, Uwe Kleine-König wrote:
> > Hello Clemens,
> > 
> > On Mon, Apr 12, 2021 at 06:39:28PM +0200, Clemens Gruber wrote:
> > > On Mon, Apr 12, 2021 at 06:18:08PM +0200, Uwe Kleine-König wrote:
> > > > On Mon, Apr 12, 2021 at 03:27:38PM +0200, Clemens Gruber wrote:
> > > > > The switch to the atomic API goes hand in hand with a few fixes to
> > > > > previously experienced issues:
> > > > > - The duty cycle is no longer lost after disable/enable (previously 
> > > > > the
> > > > >   OFF registers were cleared in disable and the user was required to
> > > > >   call config to restore the duty cycle settings)
> > > > > - If one sets a period resulting in the same prescale register value,
> > > > >   the sleep and write to the register is now skipped
> > > > > - Previously, only the full ON bit was toggled in GPIO mode (and full
> > > > >   OFF cleared if set to high), which could result in both full OFF and
> > > > >   full ON not being set and on=0, off=0, which is not allowed 
> > > > > according
> > > > >   to the datasheet
> > > > > - The OFF registers were reset to 0 in probe, which could lead to the
> > > > >   forbidden on=0, off=0. Fixed by resetting to POR default (full OFF)
> > > > > 
> > > > > Signed-off-by: Clemens Gruber 
> > > > > ---
> > > > > Changes since v7:
> > > > > - Moved check for !state->enabled before prescaler configuration
> > > > > - Removed unnecessary cast
> > > > > - Use DIV_ROUND_DOWN in .apply
> > > > > 
> > > > > Changes since v6:
> > > > > - Order of a comparison switched for improved readability
> > > > > 
> > > > > Changes since v5:
> > > > > - Function documentation for set_duty
> > > > > - Variable initializations
> > > > > - Print warning if all LEDs channel
> > > > > - Changed EOPNOTSUPP to EINVAL
> > > > > - Improved error messages
> > > > > - Register reset corrections moved to this patch
> > > > > 
> > > > > Changes since v4:
> > > > > - Patches split up
> > > > > - Use a single set_duty function
> > > > > - Improve readability / new macros
> > > > > - Added a patch to restrict prescale changes to the first user
> > > > > 
> > > > > Changes since v3:
> > > > > - Refactoring: Extracted common functions
> > > > > - Read prescale register value instead of caching it
> > > > > - Return all zeros and disabled for "all LEDs" channel state
> > > > > - Improved duty calculation / mapping to 0..4096
> > > > > 
> > > > > Changes since v2:
> > > > > - Always set default prescale value in probe
> > > > > - Simplified probe code
> > > > > - Inlined functions with one callsite
> > > > > 
> > > > > Changes since v1:
> > > > > - Fixed a logic error
> > > > > - Impoved PM runtime handling and fixed !CONFIG_PM
> > > > > - Write default prescale reg value if invalid in probe
> > > > > - Reuse full_off/_on functions throughout driver
> > > > > - Use cached prescale value whenever possible
> > > > > 
> > > > >  drivers/pwm/pwm-pca9685.c | 259 
> > > > > +-
> > > > >  1 file changed, 89 insertions(+), 170 deletions(-)
> > > > > 
> > > > > diff --git a/drivers/pwm/pwm-pca9685.c b/drivers/pwm/pwm-pca9685.c
> > > > > index 4a55dc18656c..827b57ced3c2 100644
> > > > > --- a/drivers/pwm/pwm-pca9685.c
> > > > > +++ b/drivers/pwm/pwm-pca9685.c
> > > > > @@ -51,7 +51,6 @@
> > > > >  #define PCA9685_PRESCALE_MAX 0xFF/* => min. frequency of 24 Hz */
> > > > >  
> > > > >  #define PCA9685_COUNTER_RANGE4096
> > > > > -#define PCA9685_DEFAULT_PERIOD   500 /* Default period_ns = 
> > > > > 1/200 Hz */
> > > > >  #define PCA9685_OSC_CLOCK_MHZ25  /* Internal oscillator 
> > > > > with 25 MHz */
> > > > >  
> > > > >  #define PCA9685_NUMREG

Re: [PATCH v8 1/8] pwm: pca9685: Switch to atomic API

2021-04-13 Thread Clemens Gruber
Hi Uwe,

On Mon, Apr 12, 2021 at 10:10:19PM +0200, Uwe Kleine-König wrote:
> Hello Clemens,
> 
> On Mon, Apr 12, 2021 at 06:39:28PM +0200, Clemens Gruber wrote:
> > On Mon, Apr 12, 2021 at 06:18:08PM +0200, Uwe Kleine-König wrote:
> > > On Mon, Apr 12, 2021 at 03:27:38PM +0200, Clemens Gruber wrote:
> > > > The switch to the atomic API goes hand in hand with a few fixes to
> > > > previously experienced issues:
> > > > - The duty cycle is no longer lost after disable/enable (previously the
> > > >   OFF registers were cleared in disable and the user was required to
> > > >   call config to restore the duty cycle settings)
> > > > - If one sets a period resulting in the same prescale register value,
> > > >   the sleep and write to the register is now skipped
> > > > - Previously, only the full ON bit was toggled in GPIO mode (and full
> > > >   OFF cleared if set to high), which could result in both full OFF and
> > > >   full ON not being set and on=0, off=0, which is not allowed according
> > > >   to the datasheet
> > > > - The OFF registers were reset to 0 in probe, which could lead to the
> > > >   forbidden on=0, off=0. Fixed by resetting to POR default (full OFF)
> > > > 
> > > > Signed-off-by: Clemens Gruber 
> > > > ---
> > > > Changes since v7:
> > > > - Moved check for !state->enabled before prescaler configuration
> > > > - Removed unnecessary cast
> > > > - Use DIV_ROUND_DOWN in .apply
> > > > 
> > > > Changes since v6:
> > > > - Order of a comparison switched for improved readability
> > > > 
> > > > Changes since v5:
> > > > - Function documentation for set_duty
> > > > - Variable initializations
> > > > - Print warning if all LEDs channel
> > > > - Changed EOPNOTSUPP to EINVAL
> > > > - Improved error messages
> > > > - Register reset corrections moved to this patch
> > > > 
> > > > Changes since v4:
> > > > - Patches split up
> > > > - Use a single set_duty function
> > > > - Improve readability / new macros
> > > > - Added a patch to restrict prescale changes to the first user
> > > > 
> > > > Changes since v3:
> > > > - Refactoring: Extracted common functions
> > > > - Read prescale register value instead of caching it
> > > > - Return all zeros and disabled for "all LEDs" channel state
> > > > - Improved duty calculation / mapping to 0..4096
> > > > 
> > > > Changes since v2:
> > > > - Always set default prescale value in probe
> > > > - Simplified probe code
> > > > - Inlined functions with one callsite
> > > > 
> > > > Changes since v1:
> > > > - Fixed a logic error
> > > > - Impoved PM runtime handling and fixed !CONFIG_PM
> > > > - Write default prescale reg value if invalid in probe
> > > > - Reuse full_off/_on functions throughout driver
> > > > - Use cached prescale value whenever possible
> > > > 
> > > >  drivers/pwm/pwm-pca9685.c | 259 +-
> > > >  1 file changed, 89 insertions(+), 170 deletions(-)
> > > > 
> > > > diff --git a/drivers/pwm/pwm-pca9685.c b/drivers/pwm/pwm-pca9685.c
> > > > index 4a55dc18656c..827b57ced3c2 100644
> > > > --- a/drivers/pwm/pwm-pca9685.c
> > > > +++ b/drivers/pwm/pwm-pca9685.c
> > > > @@ -51,7 +51,6 @@
> > > >  #define PCA9685_PRESCALE_MAX   0xFF/* => min. frequency of 24 Hz */
> > > >  
> > > >  #define PCA9685_COUNTER_RANGE  4096
> > > > -#define PCA9685_DEFAULT_PERIOD 500 /* Default period_ns = 1/200 Hz 
> > > > */
> > > >  #define PCA9685_OSC_CLOCK_MHZ  25  /* Internal oscillator with 25 
> > > > MHz */
> > > >  
> > > >  #define PCA9685_NUMREGS0xFF
> > > > @@ -71,10 +70,14 @@
> > > >  #define LED_N_OFF_H(N) (PCA9685_LEDX_OFF_H + (4 * (N)))
> > > >  #define LED_N_OFF_L(N) (PCA9685_LEDX_OFF_L + (4 * (N)))
> > > >  
> > > > +#define REG_ON_H(C)((C) >= PCA9685_MAXCHAN ? PCA9685_ALL_LED_ON_H 
> > > > : LED_N_ON_H((C)))
> > > > +#define REG_ON_L(C)((C) >= PCA9685_MAXCHAN ? PCA9685_ALL_LED_ON_L 
> > > > : LED_N_ON_L((C)))
> > > > +#define REG_OFF_H(C)   ((C) &g

Re: [PATCH v8 6/8] pwm: pca9685: Support new PWM_USAGE_POWER flag

2021-04-12 Thread Clemens Gruber
Hi,

On Mon, Apr 12, 2021 at 06:30:45PM +0200, Uwe Kleine-König wrote:
> On Mon, Apr 12, 2021 at 03:27:43PM +0200, Clemens Gruber wrote:
> > If PWM_USAGE_POWER is set on a PWM, the pca9685 driver will phase shift
> > the individual channels relative to their channel number. This improves
> > EMI because the enabled channels no longer turn on at the same time,
> > while still maintaining the configured duty cycle / power output.
> > 
> > Signed-off-by: Clemens Gruber 
> > ---
> >  drivers/pwm/pwm-pca9685.c | 63 ++-
> >  1 file changed, 49 insertions(+), 14 deletions(-)
> > 
> > diff --git a/drivers/pwm/pwm-pca9685.c b/drivers/pwm/pwm-pca9685.c
> > index 7f97965033e7..410b93b115dc 100644
> > --- a/drivers/pwm/pwm-pca9685.c
> > +++ b/drivers/pwm/pwm-pca9685.c
> > @@ -93,46 +93,76 @@ static inline struct pca9685 *to_pca(struct pwm_chip 
> > *chip)
> >  /* Helper function to set the duty cycle ratio to duty/4096 (e.g. 
> > duty=2048 -> 50%) */
> >  static void pca9685_pwm_set_duty(struct pca9685 *pca, int channel, 
> > unsigned int duty)
> >  {
> > +   struct pwm_device *pwm = >chip.pwms[channel];
> > +   unsigned int on, off;
> > +
> > if (duty == 0) {
> > /* Set the full OFF bit, which has the highest precedence */
> > regmap_write(pca->regmap, REG_OFF_H(channel), LED_FULL);
> > +   return;
> > } else if (duty >= PCA9685_COUNTER_RANGE) {
> > /* Set the full ON bit and clear the full OFF bit */
> > regmap_write(pca->regmap, REG_ON_H(channel), LED_FULL);
> > regmap_write(pca->regmap, REG_OFF_H(channel), 0);
> > -   } else {
> > -   /* Set OFF time (clears the full OFF bit) */
> > -   regmap_write(pca->regmap, REG_OFF_L(channel), duty & 0xff);
> > -   regmap_write(pca->regmap, REG_OFF_H(channel), (duty >> 8) & 
> > 0xf);
> > -   /* Clear the full ON bit */
> > -   regmap_write(pca->regmap, REG_ON_H(channel), 0);
> > +   return;
> > }
> > +
> > +
> > +   if (pwm->args.usage_power && channel < PCA9685_MAXCHAN) {
> > +   /*
> > +* If PWM_USAGE_POWER is set on a PWM, the pca9685
> > +* driver will phase shift the individual channels
> > +* relative to their channel number.
> > +* This improves EMI because the enabled channels no
> > +* longer turn on at the same time, while still
> > +* maintaining the configured duty cycle / power output.
> > +*/
> > +   on = channel * PCA9685_COUNTER_RANGE / PCA9685_MAXCHAN;
> > +   } else
> > +   on = 0;
> > +
> > +   off = (on + duty) % PCA9685_COUNTER_RANGE;
> > +
> > +   /* Set ON time (clears full ON bit) */
> > +   regmap_write(pca->regmap, REG_ON_L(channel), on & 0xff);
> > +   regmap_write(pca->regmap, REG_ON_H(channel), (on >> 8) & 0xf);
> > +   /* Set OFF time (clears full OFF bit) */
> > +   regmap_write(pca->regmap, REG_OFF_L(channel), off & 0xff);
> > +   regmap_write(pca->regmap, REG_OFF_H(channel), (off >> 8) & 0xf);
> >  }
> >  
> >  static unsigned int pca9685_pwm_get_duty(struct pca9685 *pca, int channel)
> >  {
> > -   unsigned int off_h = 0, val = 0;
> > +   struct pwm_device *pwm = >chip.pwms[channel];
> > +   unsigned int off = 0, on = 0, val = 0;
> >  
> > if (WARN_ON(channel >= PCA9685_MAXCHAN)) {
> > /* HW does not support reading state of "all LEDs" channel */
> > return 0;
> > }
> >  
> > -   regmap_read(pca->regmap, LED_N_OFF_H(channel), _h);
> > -   if (off_h & LED_FULL) {
> > +   regmap_read(pca->regmap, LED_N_OFF_H(channel), );
> > +   if (off & LED_FULL) {
> > /* Full OFF bit is set */
> > return 0;
> > }
> >  
> > -   regmap_read(pca->regmap, LED_N_ON_H(channel), );
> > -   if (val & LED_FULL) {
> > +   regmap_read(pca->regmap, LED_N_ON_H(channel), );
> > +   if (on & LED_FULL) {
> > /* Full ON bit is set */
> > return PCA9685_COUNTER_RANGE;
> > }
> >  
> > -   val = 0;
> > regmap_read(pca->regmap, LED_N_OFF_L(channel), );
> > -   return ((off_h & 0xf) << 8) | (val & 0xff);
> > +   off = ((off & 0xf) << 8) | (val & 0xff);
> > +   if

Re: [PATCH v8 4/8] dt-bindings: pwm: Support new PWM_USAGE_POWER flag

2021-04-12 Thread Clemens Gruber
On Mon, Apr 12, 2021 at 06:27:23PM +0200, Uwe Kleine-König wrote:
> On Mon, Apr 12, 2021 at 03:27:41PM +0200, Clemens Gruber wrote:
> > Add the flag and corresponding documentation for PWM_USAGE_POWER.
> 
> My concern here in the previous round was that PWM_USAGE_POWER isn't a
> name that intuitively suggests its semantic. Do you disagree?

No. It is more abstract and requires documentation. But I also didn't
want to waste too much time on discussing names, so I used Thierry's
suggestion.

I guess we need his input on this subject. I can live both with
PWM_ALLOW_PHASE_SHIFTING and PWM_USAGE_POWER, as long as it is
documented well enough.

> 
> > Cc: Rob Herring 
> > Signed-off-by: Clemens Gruber 
> > ---
> >  Documentation/devicetree/bindings/pwm/pwm.txt | 3 +++
> >  include/dt-bindings/pwm/pwm.h | 1 +
> >  2 files changed, 4 insertions(+)
> > 
> > diff --git a/Documentation/devicetree/bindings/pwm/pwm.txt 
> > b/Documentation/devicetree/bindings/pwm/pwm.txt
> > index 084886bd721e..fe3a28f887c0 100644
> > --- a/Documentation/devicetree/bindings/pwm/pwm.txt
> > +++ b/Documentation/devicetree/bindings/pwm/pwm.txt
> > @@ -46,6 +46,9 @@ period in nanoseconds.
> >  Optionally, the pwm-specifier can encode a number of flags (defined in
> >  ) in a third cell:
> >  - PWM_POLARITY_INVERTED: invert the PWM signal polarity
> > +- PWM_USAGE_POWER: Only care about the power output of the signal. This
> > +  allows drivers (if supported) to optimize the signals, for example to
> > +  improve EMI and reduce current spikes.
> 
> IMHO there are too many open questions about which freedom this gives to
> the lowlevel driver. If the consumer requests .duty_cycle = 25ns +
> .period = 100ns, can the driver provide .duty_cycle = 25s + .period =
> 100s which nominally has the same power output? Let's not introduce more
> ambiguity than there already is.
> 
> This is a NAck.
> 
> Best regards
> Uwe
> 
> -- 
> Pengutronix e.K.   | Uwe Kleine-König|
> Industrial Linux Solutions | https://www.pengutronix.de/ |




Re: [PATCH v8 1/8] pwm: pca9685: Switch to atomic API

2021-04-12 Thread Clemens Gruber
Hi Uwe,

On Mon, Apr 12, 2021 at 06:18:08PM +0200, Uwe Kleine-König wrote:
> Hello Clemens,
> 
> On Mon, Apr 12, 2021 at 03:27:38PM +0200, Clemens Gruber wrote:
> > The switch to the atomic API goes hand in hand with a few fixes to
> > previously experienced issues:
> > - The duty cycle is no longer lost after disable/enable (previously the
> >   OFF registers were cleared in disable and the user was required to
> >   call config to restore the duty cycle settings)
> > - If one sets a period resulting in the same prescale register value,
> >   the sleep and write to the register is now skipped
> > - Previously, only the full ON bit was toggled in GPIO mode (and full
> >   OFF cleared if set to high), which could result in both full OFF and
> >   full ON not being set and on=0, off=0, which is not allowed according
> >   to the datasheet
> > - The OFF registers were reset to 0 in probe, which could lead to the
> >   forbidden on=0, off=0. Fixed by resetting to POR default (full OFF)
> > 
> > Signed-off-by: Clemens Gruber 
> > ---
> > Changes since v7:
> > - Moved check for !state->enabled before prescaler configuration
> > - Removed unnecessary cast
> > - Use DIV_ROUND_DOWN in .apply
> > 
> > Changes since v6:
> > - Order of a comparison switched for improved readability
> > 
> > Changes since v5:
> > - Function documentation for set_duty
> > - Variable initializations
> > - Print warning if all LEDs channel
> > - Changed EOPNOTSUPP to EINVAL
> > - Improved error messages
> > - Register reset corrections moved to this patch
> > 
> > Changes since v4:
> > - Patches split up
> > - Use a single set_duty function
> > - Improve readability / new macros
> > - Added a patch to restrict prescale changes to the first user
> > 
> > Changes since v3:
> > - Refactoring: Extracted common functions
> > - Read prescale register value instead of caching it
> > - Return all zeros and disabled for "all LEDs" channel state
> > - Improved duty calculation / mapping to 0..4096
> > 
> > Changes since v2:
> > - Always set default prescale value in probe
> > - Simplified probe code
> > - Inlined functions with one callsite
> > 
> > Changes since v1:
> > - Fixed a logic error
> > - Impoved PM runtime handling and fixed !CONFIG_PM
> > - Write default prescale reg value if invalid in probe
> > - Reuse full_off/_on functions throughout driver
> > - Use cached prescale value whenever possible
> > 
> >  drivers/pwm/pwm-pca9685.c | 259 +-
> >  1 file changed, 89 insertions(+), 170 deletions(-)
> > 
> > diff --git a/drivers/pwm/pwm-pca9685.c b/drivers/pwm/pwm-pca9685.c
> > index 4a55dc18656c..827b57ced3c2 100644
> > --- a/drivers/pwm/pwm-pca9685.c
> > +++ b/drivers/pwm/pwm-pca9685.c
> > @@ -51,7 +51,6 @@
> >  #define PCA9685_PRESCALE_MAX   0xFF/* => min. frequency of 24 Hz */
> >  
> >  #define PCA9685_COUNTER_RANGE  4096
> > -#define PCA9685_DEFAULT_PERIOD 500 /* Default period_ns = 1/200 Hz 
> > */
> >  #define PCA9685_OSC_CLOCK_MHZ  25  /* Internal oscillator with 25 
> > MHz */
> >  
> >  #define PCA9685_NUMREGS0xFF
> > @@ -71,10 +70,14 @@
> >  #define LED_N_OFF_H(N) (PCA9685_LEDX_OFF_H + (4 * (N)))
> >  #define LED_N_OFF_L(N) (PCA9685_LEDX_OFF_L + (4 * (N)))
> >  
> > +#define REG_ON_H(C)((C) >= PCA9685_MAXCHAN ? PCA9685_ALL_LED_ON_H 
> > : LED_N_ON_H((C)))
> > +#define REG_ON_L(C)((C) >= PCA9685_MAXCHAN ? PCA9685_ALL_LED_ON_L 
> > : LED_N_ON_L((C)))
> > +#define REG_OFF_H(C)   ((C) >= PCA9685_MAXCHAN ? PCA9685_ALL_LED_OFF_H 
> > : LED_N_OFF_H((C)))
> > +#define REG_OFF_L(C)   ((C) >= PCA9685_MAXCHAN ? PCA9685_ALL_LED_OFF_L 
> > : LED_N_OFF_L((C)))
> 
> I'd like to see these named PCA9685_REG_ON_H etc.

I did not use the prefix because the existing LED_N_ON/OFF_H/L also do
not have a prefix. If the prefix is mandatory, I think LED_N_.. should
also be prefixed, right?

> 
> >  struct pca9685 {
> > struct pwm_chip chip;
> > struct regmap *regmap;
> > -   int period_ns;
> >  #if IS_ENABLED(CONFIG_GPIOLIB)
> > struct mutex lock;
> > struct gpio_chip gpio;
> > @@ -87,6 +90,51 @@ static inline struct pca9685 *to_pca(struct pwm_chip 
> > *chip)
> > return container_of(chip, struct pca9685, chip);
> >  }
> >  
> > +/* Helper function to set the duty cycle ratio to duty/4096 (e.g. 
&

[PATCH v8 5/8] pwm: core: Support new PWM_USAGE_POWER flag

2021-04-12 Thread Clemens Gruber
If the flag PWM_USAGE_POWER is set on a channel, the PWM driver may
optimize the signal as long as the power output is not changed.

Depending on the specific driver, the optimization could for example
improve EMI (if supported) by phase-shifting the individual channels.

Signed-off-by: Clemens Gruber 
---
 drivers/pwm/core.c  | 9 +++--
 include/linux/pwm.h | 1 +
 2 files changed, 8 insertions(+), 2 deletions(-)

diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c
index a8eff4b3ee36..56a9c739e1b2 100644
--- a/drivers/pwm/core.c
+++ b/drivers/pwm/core.c
@@ -153,9 +153,14 @@ of_pwm_xlate_with_flags(struct pwm_chip *pc, const struct 
of_phandle_args *args)
 
pwm->args.period = args->args[1];
pwm->args.polarity = PWM_POLARITY_NORMAL;
+   pwm->args.usage_power = false;
 
-   if (args->args_count > 2 && args->args[2] & PWM_POLARITY_INVERTED)
-   pwm->args.polarity = PWM_POLARITY_INVERSED;
+   if (args->args_count > 2) {
+   if (args->args[2] & PWM_POLARITY_INVERTED)
+   pwm->args.polarity = PWM_POLARITY_INVERSED;
+   if (args->args[2] & PWM_USAGE_POWER)
+   pwm->args.usage_power = true;
+   }
 
return pwm;
 }
diff --git a/include/linux/pwm.h b/include/linux/pwm.h
index e4d84d4db293..555e050e8bec 100644
--- a/include/linux/pwm.h
+++ b/include/linux/pwm.h
@@ -41,6 +41,7 @@ enum pwm_polarity {
 struct pwm_args {
u64 period;
enum pwm_polarity polarity;
+   bool usage_power;
 };
 
 enum {
-- 
2.31.1



[PATCH v8 6/8] pwm: pca9685: Support new PWM_USAGE_POWER flag

2021-04-12 Thread Clemens Gruber
If PWM_USAGE_POWER is set on a PWM, the pca9685 driver will phase shift
the individual channels relative to their channel number. This improves
EMI because the enabled channels no longer turn on at the same time,
while still maintaining the configured duty cycle / power output.

Signed-off-by: Clemens Gruber 
---
 drivers/pwm/pwm-pca9685.c | 63 ++-
 1 file changed, 49 insertions(+), 14 deletions(-)

diff --git a/drivers/pwm/pwm-pca9685.c b/drivers/pwm/pwm-pca9685.c
index 7f97965033e7..410b93b115dc 100644
--- a/drivers/pwm/pwm-pca9685.c
+++ b/drivers/pwm/pwm-pca9685.c
@@ -93,46 +93,76 @@ static inline struct pca9685 *to_pca(struct pwm_chip *chip)
 /* Helper function to set the duty cycle ratio to duty/4096 (e.g. duty=2048 -> 
50%) */
 static void pca9685_pwm_set_duty(struct pca9685 *pca, int channel, unsigned 
int duty)
 {
+   struct pwm_device *pwm = >chip.pwms[channel];
+   unsigned int on, off;
+
if (duty == 0) {
/* Set the full OFF bit, which has the highest precedence */
regmap_write(pca->regmap, REG_OFF_H(channel), LED_FULL);
+   return;
} else if (duty >= PCA9685_COUNTER_RANGE) {
/* Set the full ON bit and clear the full OFF bit */
regmap_write(pca->regmap, REG_ON_H(channel), LED_FULL);
regmap_write(pca->regmap, REG_OFF_H(channel), 0);
-   } else {
-   /* Set OFF time (clears the full OFF bit) */
-   regmap_write(pca->regmap, REG_OFF_L(channel), duty & 0xff);
-   regmap_write(pca->regmap, REG_OFF_H(channel), (duty >> 8) & 
0xf);
-   /* Clear the full ON bit */
-   regmap_write(pca->regmap, REG_ON_H(channel), 0);
+   return;
}
+
+
+   if (pwm->args.usage_power && channel < PCA9685_MAXCHAN) {
+   /*
+* If PWM_USAGE_POWER is set on a PWM, the pca9685
+* driver will phase shift the individual channels
+* relative to their channel number.
+* This improves EMI because the enabled channels no
+* longer turn on at the same time, while still
+* maintaining the configured duty cycle / power output.
+*/
+   on = channel * PCA9685_COUNTER_RANGE / PCA9685_MAXCHAN;
+   } else
+   on = 0;
+
+   off = (on + duty) % PCA9685_COUNTER_RANGE;
+
+   /* Set ON time (clears full ON bit) */
+   regmap_write(pca->regmap, REG_ON_L(channel), on & 0xff);
+   regmap_write(pca->regmap, REG_ON_H(channel), (on >> 8) & 0xf);
+   /* Set OFF time (clears full OFF bit) */
+   regmap_write(pca->regmap, REG_OFF_L(channel), off & 0xff);
+   regmap_write(pca->regmap, REG_OFF_H(channel), (off >> 8) & 0xf);
 }
 
 static unsigned int pca9685_pwm_get_duty(struct pca9685 *pca, int channel)
 {
-   unsigned int off_h = 0, val = 0;
+   struct pwm_device *pwm = >chip.pwms[channel];
+   unsigned int off = 0, on = 0, val = 0;
 
if (WARN_ON(channel >= PCA9685_MAXCHAN)) {
/* HW does not support reading state of "all LEDs" channel */
return 0;
}
 
-   regmap_read(pca->regmap, LED_N_OFF_H(channel), _h);
-   if (off_h & LED_FULL) {
+   regmap_read(pca->regmap, LED_N_OFF_H(channel), );
+   if (off & LED_FULL) {
/* Full OFF bit is set */
return 0;
}
 
-   regmap_read(pca->regmap, LED_N_ON_H(channel), );
-   if (val & LED_FULL) {
+   regmap_read(pca->regmap, LED_N_ON_H(channel), );
+   if (on & LED_FULL) {
/* Full ON bit is set */
return PCA9685_COUNTER_RANGE;
}
 
-   val = 0;
regmap_read(pca->regmap, LED_N_OFF_L(channel), );
-   return ((off_h & 0xf) << 8) | (val & 0xff);
+   off = ((off & 0xf) << 8) | (val & 0xff);
+   if (!pwm->args.usage_power)
+   return off;
+
+   /* Read ON register to calculate duty cycle of staggered output */
+   val = 0;
+   regmap_read(pca->regmap, LED_N_ON_L(channel), );
+   on = ((on & 0xf) << 8) | (val & 0xff);
+   return (off - on) & (PCA9685_COUNTER_RANGE - 1);
 }
 
 #if IS_ENABLED(CONFIG_GPIOLIB)
@@ -439,9 +469,11 @@ static int pca9685_pwm_probe(struct i2c_client *client,
reg &= ~(MODE1_ALLCALL | MODE1_SUB1 | MODE1_SUB2 | MODE1_SUB3);
regmap_write(pca->regmap, PCA9685_MODE1, reg);
 
-   /* Reset OFF registers to POR default */
+   /* Reset OFF/ON registers to POR default */
regmap_write(pca->regmap, PCA9685_ALL_LED_OFF_L, LED_FULL);
regmap_write(pca->regmap, PCA9685_ALL_LED_OFF_H, LED_FULL);
+   regmap_write(pca->regmap, PCA9685_ALL_LE

[PATCH v8 4/8] dt-bindings: pwm: Support new PWM_USAGE_POWER flag

2021-04-12 Thread Clemens Gruber
Add the flag and corresponding documentation for PWM_USAGE_POWER.

Cc: Rob Herring 
Signed-off-by: Clemens Gruber 
---
 Documentation/devicetree/bindings/pwm/pwm.txt | 3 +++
 include/dt-bindings/pwm/pwm.h | 1 +
 2 files changed, 4 insertions(+)

diff --git a/Documentation/devicetree/bindings/pwm/pwm.txt 
b/Documentation/devicetree/bindings/pwm/pwm.txt
index 084886bd721e..fe3a28f887c0 100644
--- a/Documentation/devicetree/bindings/pwm/pwm.txt
+++ b/Documentation/devicetree/bindings/pwm/pwm.txt
@@ -46,6 +46,9 @@ period in nanoseconds.
 Optionally, the pwm-specifier can encode a number of flags (defined in
 ) in a third cell:
 - PWM_POLARITY_INVERTED: invert the PWM signal polarity
+- PWM_USAGE_POWER: Only care about the power output of the signal. This
+  allows drivers (if supported) to optimize the signals, for example to
+  improve EMI and reduce current spikes.
 
 Example with optional PWM specifier for inverse polarity
 
diff --git a/include/dt-bindings/pwm/pwm.h b/include/dt-bindings/pwm/pwm.h
index ab9a077e3c7d..0d5a8f0c0035 100644
--- a/include/dt-bindings/pwm/pwm.h
+++ b/include/dt-bindings/pwm/pwm.h
@@ -11,5 +11,6 @@
 #define _DT_BINDINGS_PWM_PWM_H
 
 #define PWM_POLARITY_INVERTED  (1 << 0)
+#define PWM_USAGE_POWER(1 << 1)
 
 #endif
-- 
2.31.1



[PATCH v8 2/8] pwm: pca9685: Support hardware readout

2021-04-12 Thread Clemens Gruber
Implement .get_state to read-out the current hardware state.

The hardware readout may return slightly different values than those
that were set in apply due to the limited range of possible prescale and
counter register values.

Also note that although the datasheet mentions 200 Hz as default
frequency when using the internal 25 MHz oscillator, the calculated
period from the default prescaler register setting of 30 is 5079040ns.

Signed-off-by: Clemens Gruber 
---
Changes since v7:
- Always return enabled=true for channels except "all LEDs" channel
- Use DIV_ROUND_UP in .get_state

Changes since v6:
- Added a comment regarding the division (Suggested by Uwe)
- Rebased

 drivers/pwm/pwm-pca9685.c | 36 
 1 file changed, 36 insertions(+)

diff --git a/drivers/pwm/pwm-pca9685.c b/drivers/pwm/pwm-pca9685.c
index 827b57ced3c2..b39c0ba701ab 100644
--- a/drivers/pwm/pwm-pca9685.c
+++ b/drivers/pwm/pwm-pca9685.c
@@ -329,6 +329,41 @@ static int pca9685_pwm_apply(struct pwm_chip *chip, struct 
pwm_device *pwm,
return 0;
 }
 
+static void pca9685_pwm_get_state(struct pwm_chip *chip, struct pwm_device 
*pwm,
+ struct pwm_state *state)
+{
+   struct pca9685 *pca = to_pca(chip);
+   unsigned long long duty;
+   unsigned int val = 0;
+
+   /* Calculate (chip-wide) period from prescale value */
+   regmap_read(pca->regmap, PCA9685_PRESCALE, );
+   /*
+* PCA9685_OSC_CLOCK_MHZ is 25, i.e. an integer divider of 1000.
+* The following calculation is therefore only a multiplication
+* and we are not losing precision.
+*/
+   state->period = (PCA9685_COUNTER_RANGE * 1000 / PCA9685_OSC_CLOCK_MHZ) *
+   (val + 1);
+
+   /* The (per-channel) polarity is fixed */
+   state->polarity = PWM_POLARITY_NORMAL;
+
+   if (pwm->hwpwm >= PCA9685_MAXCHAN) {
+   /*
+* The "all LEDs" channel does not support HW readout
+* Return 0 and disabled for backwards compatibility
+*/
+   state->duty_cycle = 0;
+   state->enabled = false;
+   return;
+   }
+
+   state->enabled = true;
+   duty = pca9685_pwm_get_duty(pca, pwm->hwpwm);
+   state->duty_cycle = DIV_ROUND_UP_ULL(duty * state->period, 
PCA9685_COUNTER_RANGE);
+}
+
 static int pca9685_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
 {
struct pca9685 *pca = to_pca(chip);
@@ -351,6 +386,7 @@ static void pca9685_pwm_free(struct pwm_chip *chip, struct 
pwm_device *pwm)
 
 static const struct pwm_ops pca9685_pwm_ops = {
.apply = pca9685_pwm_apply,
+   .get_state = pca9685_pwm_get_state,
.request = pca9685_pwm_request,
.free = pca9685_pwm_free,
.owner = THIS_MODULE,
-- 
2.31.1



[PATCH v8 1/8] pwm: pca9685: Switch to atomic API

2021-04-12 Thread Clemens Gruber
The switch to the atomic API goes hand in hand with a few fixes to
previously experienced issues:
- The duty cycle is no longer lost after disable/enable (previously the
  OFF registers were cleared in disable and the user was required to
  call config to restore the duty cycle settings)
- If one sets a period resulting in the same prescale register value,
  the sleep and write to the register is now skipped
- Previously, only the full ON bit was toggled in GPIO mode (and full
  OFF cleared if set to high), which could result in both full OFF and
  full ON not being set and on=0, off=0, which is not allowed according
  to the datasheet
- The OFF registers were reset to 0 in probe, which could lead to the
  forbidden on=0, off=0. Fixed by resetting to POR default (full OFF)

Signed-off-by: Clemens Gruber 
---
Changes since v7:
- Moved check for !state->enabled before prescaler configuration
- Removed unnecessary cast
- Use DIV_ROUND_DOWN in .apply

Changes since v6:
- Order of a comparison switched for improved readability

Changes since v5:
- Function documentation for set_duty
- Variable initializations
- Print warning if all LEDs channel
- Changed EOPNOTSUPP to EINVAL
- Improved error messages
- Register reset corrections moved to this patch

Changes since v4:
- Patches split up
- Use a single set_duty function
- Improve readability / new macros
- Added a patch to restrict prescale changes to the first user

Changes since v3:
- Refactoring: Extracted common functions
- Read prescale register value instead of caching it
- Return all zeros and disabled for "all LEDs" channel state
- Improved duty calculation / mapping to 0..4096

Changes since v2:
- Always set default prescale value in probe
- Simplified probe code
- Inlined functions with one callsite

Changes since v1:
- Fixed a logic error
- Impoved PM runtime handling and fixed !CONFIG_PM
- Write default prescale reg value if invalid in probe
- Reuse full_off/_on functions throughout driver
- Use cached prescale value whenever possible

 drivers/pwm/pwm-pca9685.c | 259 +-
 1 file changed, 89 insertions(+), 170 deletions(-)

diff --git a/drivers/pwm/pwm-pca9685.c b/drivers/pwm/pwm-pca9685.c
index 4a55dc18656c..827b57ced3c2 100644
--- a/drivers/pwm/pwm-pca9685.c
+++ b/drivers/pwm/pwm-pca9685.c
@@ -51,7 +51,6 @@
 #define PCA9685_PRESCALE_MAX   0xFF/* => min. frequency of 24 Hz */
 
 #define PCA9685_COUNTER_RANGE  4096
-#define PCA9685_DEFAULT_PERIOD 500 /* Default period_ns = 1/200 Hz */
 #define PCA9685_OSC_CLOCK_MHZ  25  /* Internal oscillator with 25 MHz */
 
 #define PCA9685_NUMREGS0xFF
@@ -71,10 +70,14 @@
 #define LED_N_OFF_H(N) (PCA9685_LEDX_OFF_H + (4 * (N)))
 #define LED_N_OFF_L(N) (PCA9685_LEDX_OFF_L + (4 * (N)))
 
+#define REG_ON_H(C)((C) >= PCA9685_MAXCHAN ? PCA9685_ALL_LED_ON_H : 
LED_N_ON_H((C)))
+#define REG_ON_L(C)((C) >= PCA9685_MAXCHAN ? PCA9685_ALL_LED_ON_L : 
LED_N_ON_L((C)))
+#define REG_OFF_H(C)   ((C) >= PCA9685_MAXCHAN ? PCA9685_ALL_LED_OFF_H : 
LED_N_OFF_H((C)))
+#define REG_OFF_L(C)   ((C) >= PCA9685_MAXCHAN ? PCA9685_ALL_LED_OFF_L : 
LED_N_OFF_L((C)))
+
 struct pca9685 {
struct pwm_chip chip;
struct regmap *regmap;
-   int period_ns;
 #if IS_ENABLED(CONFIG_GPIOLIB)
struct mutex lock;
struct gpio_chip gpio;
@@ -87,6 +90,51 @@ static inline struct pca9685 *to_pca(struct pwm_chip *chip)
return container_of(chip, struct pca9685, chip);
 }
 
+/* Helper function to set the duty cycle ratio to duty/4096 (e.g. duty=2048 -> 
50%) */
+static void pca9685_pwm_set_duty(struct pca9685 *pca, int channel, unsigned 
int duty)
+{
+   if (duty == 0) {
+   /* Set the full OFF bit, which has the highest precedence */
+   regmap_write(pca->regmap, REG_OFF_H(channel), LED_FULL);
+   } else if (duty >= PCA9685_COUNTER_RANGE) {
+   /* Set the full ON bit and clear the full OFF bit */
+   regmap_write(pca->regmap, REG_ON_H(channel), LED_FULL);
+   regmap_write(pca->regmap, REG_OFF_H(channel), 0);
+   } else {
+   /* Set OFF time (clears the full OFF bit) */
+   regmap_write(pca->regmap, REG_OFF_L(channel), duty & 0xff);
+   regmap_write(pca->regmap, REG_OFF_H(channel), (duty >> 8) & 
0xf);
+   /* Clear the full ON bit */
+   regmap_write(pca->regmap, REG_ON_H(channel), 0);
+   }
+}
+
+static unsigned int pca9685_pwm_get_duty(struct pca9685 *pca, int channel)
+{
+   unsigned int off_h = 0, val = 0;
+
+   if (WARN_ON(channel >= PCA9685_MAXCHAN)) {
+   /* HW does not support reading state of "all LEDs" channel */
+   return 0;
+   }
+
+   regmap_read(pca->regmap, LED_N_OFF_H(channel), _h);
+   if (off_h & LED_FULL) {
+   /* Full OFF bit is set */
+  

[PATCH v8 7/8] pwm: pca9685: Restrict period change for enabled PWMs

2021-04-12 Thread Clemens Gruber
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 v7:
- As the HW readout always returns enabled, also set the pwms_enabled
  bit in request (except for the "all LEDs" channel)

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 | 74 +--
 1 file changed, 64 insertions(+), 10 deletions(-)

diff --git a/drivers/pwm/pwm-pca9685.c b/drivers/pwm/pwm-pca9685.c
index 410b93b115dc..4583edd5e477 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);
+}
+
 /* Helper function to set the duty cycle ratio to duty/4096 (e.g. duty=2048 -> 
50%) */
 static void pca9685_pwm_set_duty(struct pca9685 *pca, int channel, unsigned 
int duty)
 {
@@ -268,8 +285,6 @@ static int pca9685_pwm_gpio_probe(struct pca9685 *pca)
 {
struct device *dev = pca->chip.dev;
 
-   mutex_init(>lock);
-
pca->gpio.label = dev_name(dev);
pca->gpio.parent = dev;
pca->gpio.request = pca9685_pwm_gpio_request;
@@ -313,8 +328,8 @@ static void pca9685_set_sleep_mode(struct pca9685 *pca, 
bool enable)
}
 }
 
-static int pca9685_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
-const struct pwm_state *state)
+static int __pca9685_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
+  const struct pwm_state *state)
 {
struct pca9685 *pca = to_pca(chip);
unsigned long long duty, prescale;
@@ -337,6 +352,12 @@ static int pca9685_pwm_apply(struct pwm_chip *chip, struct 
pwm_device *pwm,
 
regmap_read(pca->regmap, PCA9685_PRESCALE, );
if (prescale != val) {
+   if (!pca9685_prescaler_can_change(pca, pwm->hwpwm)) {
+   dev_err(chip->dev,
+   "pwm not changed: periods of enabled pwms must 
match!\n");
+   return -EBUSY;
+   }
+
/*
 * Putting the chip briefly into SLEEP mode
 * at this point won't interfere with the
@@ -359,6 +380,25 @@ static int pca9685_pwm_apply(struct pwm_chip *chip, struct 
pwm_device *pwm,
return 0;
 }
 
+static int pca9685_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
+const struct pwm_state *state)
+{
+   struct pca9685 *pca = to_pca(chip);
+   int ret;
+
+   mutex_lock(>lock);
+   ret = __pca9685_pwm_apply(chip, pwm, state);
+   if (ret == 0) {
+   if (state->enabled)
+  

[PATCH v8 8/8] pwm: pca9685: Add error messages for failed regmap calls

2021-04-12 Thread Clemens Gruber
Regmap operations can fail if the underlying subsystem is not working
properly (e.g. hogged I2C bus, etc.)
As this is useful information for the user, print an error message if it
happens.
Let probe fail if the first regmap_read or the first regmap_write fails.

Signed-off-by: Clemens Gruber 
---
Changes since v7:
- Use %pe instead of %d for error codes (Suggested by Uwe)

drivers/pwm/pwm-pca9685.c | 83 ---
 1 file changed, 59 insertions(+), 24 deletions(-)

diff --git a/drivers/pwm/pwm-pca9685.c b/drivers/pwm/pwm-pca9685.c
index 4583edd5e477..b0b321203947 100644
--- a/drivers/pwm/pwm-pca9685.c
+++ b/drivers/pwm/pwm-pca9685.c
@@ -107,6 +107,30 @@ static bool pca9685_prescaler_can_change(struct pca9685 
*pca, int channel)
return test_bit(channel, pca->pwms_enabled);
 }
 
+static int pca9685_read_reg(struct pca9685 *pca, unsigned int reg, unsigned 
int *val)
+{
+   struct device *dev = pca->chip.dev;
+   int err;
+
+   err = regmap_read(pca->regmap, reg, val);
+   if (err != 0)
+   dev_err(dev, "regmap_read of register 0x%x failed: %pe\n", reg, 
ERR_PTR(err));
+
+   return err;
+}
+
+static int pca9685_write_reg(struct pca9685 *pca, unsigned int reg, unsigned 
int val)
+{
+   struct device *dev = pca->chip.dev;
+   int err;
+
+   err = regmap_write(pca->regmap, reg, val);
+   if (err != 0)
+   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 pca9685 *pca, int channel, unsigned 
int duty)
 {
@@ -115,12 +139,12 @@ static void pca9685_pwm_set_duty(struct pca9685 *pca, int 
channel, unsigned int
 
if (duty == 0) {
/* Set the full OFF bit, which has the highest precedence */
-   regmap_write(pca->regmap, REG_OFF_H(channel), LED_FULL);
+   pca9685_write_reg(pca, REG_OFF_H(channel), LED_FULL);
return;
} else if (duty >= PCA9685_COUNTER_RANGE) {
/* Set the full ON bit and clear the full OFF bit */
-   regmap_write(pca->regmap, REG_ON_H(channel), LED_FULL);
-   regmap_write(pca->regmap, REG_OFF_H(channel), 0);
+   pca9685_write_reg(pca, REG_ON_H(channel), LED_FULL);
+   pca9685_write_reg(pca, REG_OFF_H(channel), 0);
return;
}
 
@@ -141,11 +165,11 @@ static void pca9685_pwm_set_duty(struct pca9685 *pca, int 
channel, unsigned int
off = (on + duty) % PCA9685_COUNTER_RANGE;
 
/* Set ON time (clears full ON bit) */
-   regmap_write(pca->regmap, REG_ON_L(channel), on & 0xff);
-   regmap_write(pca->regmap, REG_ON_H(channel), (on >> 8) & 0xf);
+   pca9685_write_reg(pca, REG_ON_L(channel), on & 0xff);
+   pca9685_write_reg(pca, REG_ON_H(channel), (on >> 8) & 0xf);
/* Set OFF time (clears full OFF bit) */
-   regmap_write(pca->regmap, REG_OFF_L(channel), off & 0xff);
-   regmap_write(pca->regmap, REG_OFF_H(channel), (off >> 8) & 0xf);
+   pca9685_write_reg(pca, REG_OFF_L(channel), off & 0xff);
+   pca9685_write_reg(pca, REG_OFF_H(channel), (off >> 8) & 0xf);
 }
 
 static unsigned int pca9685_pwm_get_duty(struct pca9685 *pca, int channel)
@@ -158,26 +182,26 @@ static unsigned int pca9685_pwm_get_duty(struct pca9685 
*pca, int channel)
return 0;
}
 
-   regmap_read(pca->regmap, LED_N_OFF_H(channel), );
+   pca9685_read_reg(pca, LED_N_OFF_H(channel), );
if (off & LED_FULL) {
/* Full OFF bit is set */
return 0;
}
 
-   regmap_read(pca->regmap, LED_N_ON_H(channel), );
+   pca9685_read_reg(pca, LED_N_ON_H(channel), );
if (on & LED_FULL) {
/* Full ON bit is set */
return PCA9685_COUNTER_RANGE;
}
 
-   regmap_read(pca->regmap, LED_N_OFF_L(channel), );
+   pca9685_read_reg(pca, LED_N_OFF_L(channel), );
off = ((off & 0xf) << 8) | (val & 0xff);
if (!pwm->args.usage_power)
return off;
 
/* Read ON register to calculate duty cycle of staggered output */
val = 0;
-   regmap_read(pca->regmap, LED_N_ON_L(channel), );
+   pca9685_read_reg(pca, LED_N_ON_L(channel), );
on = ((on & 0xf) << 8) | (val & 0xff);
return (off - on) & (PCA9685_COUNTER_RANGE - 1);
 }
@@ -320,8 +344,15 @@ static inline int pca9685_pwm_gpio_probe(struct pca9685 
*pca)
 
 static void pca9685_set_sleep_mode(struct pca9685 *pca, bool enable)
 {
-   regmap_update_bits(pca->regmap, PCA9685_MODE1,
-  MODE1_SLEEP, enable ? MODE1_SLEEP : 0);
+   struct device *de

[PATCH v8 3/8] pwm: pca9685: Improve runtime PM behavior

2021-04-12 Thread Clemens Gruber
The chip does not come out of POR in active state but in sleep state.
To be sure (in case the bootloader woke it up) we force it to sleep in
probe.

If runtime PM is disabled, we instead wake the chip in .probe and put it
to sleep in .remove.

Signed-off-by: Clemens Gruber 
---
Changes since v7:
- Handle sysfs power control as well and not just CONFIG_PM

Changes since v6:
- Improved !CONFIG_PM handling (wake it up without putting it to sleep
  first)

 drivers/pwm/pwm-pca9685.c | 25 +++--
 1 file changed, 19 insertions(+), 6 deletions(-)

diff --git a/drivers/pwm/pwm-pca9685.c b/drivers/pwm/pwm-pca9685.c
index b39c0ba701ab..7f97965033e7 100644
--- a/drivers/pwm/pwm-pca9685.c
+++ b/drivers/pwm/pwm-pca9685.c
@@ -460,14 +460,20 @@ static int pca9685_pwm_probe(struct i2c_client *client,
return ret;
}
 
-   /* The chip comes out of power-up in the active state */
-   pm_runtime_set_active(>dev);
-   /*
-* Enable will put the chip into suspend, which is what we
-* want as all outputs are disabled at this point
-*/
pm_runtime_enable(>dev);
 
+   if (pm_runtime_enabled(>dev)) {
+   /*
+* Although the chip comes out of power-up in the sleep state,
+* we force it to sleep in case it was woken up before
+*/
+   pca9685_set_sleep_mode(pca, true);
+   pm_runtime_set_suspended(>dev);
+   } else {
+   /* Wake the chip up if runtime PM is disabled */
+   pca9685_set_sleep_mode(pca, false);
+   }
+
return 0;
 }
 
@@ -479,7 +485,14 @@ static int pca9685_pwm_remove(struct i2c_client *client)
ret = pwmchip_remove(>chip);
if (ret)
return ret;
+
+   if (!pm_runtime_enabled(>dev)) {
+   /* Put chip in sleep state if runtime PM is disabled */
+   pca9685_set_sleep_mode(pca, true);
+   }
+
pm_runtime_disable(>dev);
+
return 0;
 }
 
-- 
2.31.1



Re: [PATCH v7 3/8] pwm: pca9685: Improve runtime PM behavior

2021-04-09 Thread Clemens Gruber
On Fri, Apr 09, 2021 at 03:03:20PM +0200, Thierry Reding wrote:
> On Tue, Apr 06, 2021 at 06:41:35PM +0200, Clemens Gruber wrote:
> > The chip does not come out of POR in active state but in sleep state.
> > To be sure (in case the bootloader woke it up) we force it to sleep in
> > probe.
> > 
> > On kernels without CONFIG_PM, we wake the chip in .probe and put it to
> > sleep in .remove.
> > 
> > Signed-off-by: Clemens Gruber 
> > ---
> > Changes since v6:
> > - Improved !CONFIG_PM handling (wake it up without putting it to sleep
> >   first)
> > 
> >  drivers/pwm/pwm-pca9685.c | 26 +++---
> >  1 file changed, 19 insertions(+), 7 deletions(-)
> > 
> > diff --git a/drivers/pwm/pwm-pca9685.c b/drivers/pwm/pwm-pca9685.c
> > index d4474c5ff96f..0bcec04b138a 100644
> > --- a/drivers/pwm/pwm-pca9685.c
> > +++ b/drivers/pwm/pwm-pca9685.c
> > @@ -474,13 +474,18 @@ static int pca9685_pwm_probe(struct i2c_client 
> > *client,
> > return ret;
> > }
> >  
> > -   /* The chip comes out of power-up in the active state */
> > -   pm_runtime_set_active(>dev);
> > -   /*
> > -* Enable will put the chip into suspend, which is what we
> > -* want as all outputs are disabled at this point
> > -*/
> > -   pm_runtime_enable(>dev);
> > +   if (IS_ENABLED(CONFIG_PM)) {
> 
> This looks odd to me. I've seen similar constructs, but they usually go
> something like this (I think):
> 
>   pm_runtime_enable(>dev);
> 
>   if (!pm_runtime_enabled(>dev)) {
>   /* resume device */
>   }
> 
> Which I guess in your would be somewhat the opposite and it wouldn't
> actually resume the device but rather put it to sleep.

Yes, I wanted to keep it in sleep mode if runtime PM is supported (to be
woken up later) and otherwise just wake it up in probe.

> 
> Perhaps something like this:
> 
>   pm_runtime_enable(>dev);
> 
>   if (pm_runtime_enabled(>dev)) {
>   pca9685_set_sleep_mode(pca, true);
>   pm_runtime_set_suspended(>dev);
>   } else {
>   /* wake the chip up on non-PM environments */
>   pca9685_set_sleep_mode(pca, false);
>   }
> 
> ? I think that's slightly more correct than your original because it
> takes into account things like sysfs power control and such. It also
> doesn't rely on the config option alone but instead uses the runtime
> PM API to achieve this more transparently.

Ah, yes, I missed the fact that runtime could be disabled 'at runtime'
via sysfs as well, so yes, that's more correct and pm_runtime_enabled
will just return false if !CONFIG_PM, so that should work as well.

Thanks,
Clemens


Re: [PATCH v7 5/8] pwm: core: Support new PWM_STAGGERING_ALLOWED flag

2021-04-09 Thread Clemens Gruber
On Fri, Apr 09, 2021 at 01:25:36PM +0200, Thierry Reding wrote:
> On Thu, Apr 08, 2021 at 07:36:37PM +0200, Uwe Kleine-König wrote:
> > On Thu, Apr 08, 2021 at 05:51:36PM +0200, Clemens Gruber wrote:
> > > On Thu, Apr 08, 2021 at 02:50:40PM +0200, Thierry Reding wrote:
> > > > Yes, I think that's basically what this is saying. I think we're perhaps
> > > > getting hung up on the terminology here. PWM_STAGGERING_ALLOWED gives
> > > > the impression that we're dealing with some provider-specific feature,
> > > > whereas what we really want to express is that the PWM doesn't care
> > > > exactly when the active cycle starts and based on that a provider that
> > > > can support it may optimize the EMI behavior.
> > > > 
> > > > Maybe we can find a better name for this? Ultimately what this means is
> > > > that the consumer is primarily interested in the power output of the PWM
> > > > rather than the exact shape of the signal. So perhaps something like
> > > > PWM_USAGE_POWER would be more appropriate.
> > > 
> > > Yes, although it would then no longer be obvious that this feature leads
> > > to improved EMI behavior, as long as we mention that in the docs, I
> > > think it's a good idea
> > > 
> > > Maybe document it as follows?
> > > PWM_USAGE_POWER - Allow the driver to delay the start of the cycle
> > > for EMI improvements, as long as the power output stays the same
> > 
> > I don't like both names, because for someone who is only halfway into
> > PWM stuff it is not understandable. Maybe ALLOW_PHASE_SHIFT?
> 
> Heh... how's that any more understandable?
> 
> > When a consumer is only interested in the power output than
> > 
> > .period = 20
> > .duty_cycle = 5
> > 
> > would also be an allowed response for the request
> > 
> > .period = 200
> > .duty_cycle = 50
> > 
> > and this is not what is in the focus here.
> 
> Actually, that's *exactly* what's important here. From a consumer point
> of view the output power is the key in this case. The specifier is a
> description of a particular PWM in the consumer context. And the
> consumer not going to care what exactly the PWM controller might end up
> configuring to achieve best results. If the controller allows the phase
> shift to be changed and the constraints allow it, then that's great, but
> it isn't something that the consumer has to know if all it wants is that
> the power output is as requested.
> 
> Put another way, the more generically we can describe the constraints or
> use cases, the more flexibility we get for drivers to fulfill those
> constraints. For example one controller might support phase shifting and
> use that for PWM_USAGE_POWER for better EMI behaviour. But another PWM
> controller may not support it. But it could perhaps want to optimize the
> PWM signal by reversing the polarity of one channel or whatever other
> mechanism there may be.
> 
> If we add a flag such as ALLOW_PHASE_SHIFT, then only controllers that
> support programmable phase shift will be able to support this. If some
> other mechanism can also be used to support "equivalent power" use
> cases, that would have to be described as some other flag, which has
> essentially the same meaning. So you can get into a situation where you
> have multiple flags used for the same thing.

I see what you mean. We have more flexibility with PWM_USAGE_POWER. The
only downside is that there is no real connection to the improved EMI
but I guess that's what documentation is for.

I will try to document it as follows:
- PWM_USAGE_POWER - Only care about the power output of the signal. This
  allows drivers (if supported) to optimize the signals, for example to
  improve EMI and reduce current spikes.

Maybe I then add a comment describing the specific optimization in the
pca9685 code, maybe like this:
If PWM_USAGE_POWER is set on a PWM, the pca9685 driver will phase shift
the individual channels relative to their channel number. This improves
EMI because the enabled channels no longer turn on at the same time,
while still maintaining the configured duty cycle.

Thanks,
Clemens


Re: [PATCH v7 5/8] pwm: core: Support new PWM_STAGGERING_ALLOWED flag

2021-04-08 Thread Clemens Gruber
On Thu, Apr 08, 2021 at 07:36:37PM +0200, Uwe Kleine-König wrote:
> On Thu, Apr 08, 2021 at 05:51:36PM +0200, Clemens Gruber wrote:
> > On Thu, Apr 08, 2021 at 02:50:40PM +0200, Thierry Reding wrote:
> > > Yes, I think that's basically what this is saying. I think we're perhaps
> > > getting hung up on the terminology here. PWM_STAGGERING_ALLOWED gives
> > > the impression that we're dealing with some provider-specific feature,
> > > whereas what we really want to express is that the PWM doesn't care
> > > exactly when the active cycle starts and based on that a provider that
> > > can support it may optimize the EMI behavior.
> > > 
> > > Maybe we can find a better name for this? Ultimately what this means is
> > > that the consumer is primarily interested in the power output of the PWM
> > > rather than the exact shape of the signal. So perhaps something like
> > > PWM_USAGE_POWER would be more appropriate.
> > 
> > Yes, although it would then no longer be obvious that this feature leads
> > to improved EMI behavior, as long as we mention that in the docs, I
> > think it's a good idea
> > 
> > Maybe document it as follows?
> > PWM_USAGE_POWER - Allow the driver to delay the start of the cycle
> > for EMI improvements, as long as the power output stays the same
> 
> I don't like both names, because for someone who is only halfway into
> PWM stuff it is not understandable. Maybe ALLOW_PHASE_SHIFT?

Sounds good to me.

> When a consumer is only interested in the power output than
> 
>   .period = 20
>   .duty_cycle = 5
> 
> would also be an allowed response for the request
> 
>   .period = 200
>   .duty_cycle = 50
> 
> and this is not what is in the focus here.

Right.

If Thierry agrees, I can spin up a new revision.

Maybe we can get it into 5.13 after all.

Thanks,
Clemens


Re: [PATCH v7 5/8] pwm: core: Support new PWM_STAGGERING_ALLOWED flag

2021-04-08 Thread Clemens Gruber
On Thu, Apr 08, 2021 at 02:50:40PM +0200, Thierry Reding wrote:
> On Wed, Apr 07, 2021 at 11:34:03PM +0200, Uwe Kleine-König wrote:
> > On Wed, Apr 07, 2021 at 10:21:10PM +0200, Clemens Gruber wrote:
> > > On Wed, Apr 07, 2021 at 07:46:58AM +0200, Uwe Kleine-König wrote:
> > > > On Tue, Apr 06, 2021 at 06:41:37PM +0200, Clemens Gruber wrote:
> > > > > If the flag PWM_STAGGERING_ALLOWED is set on a channel, the PWM driver
> > > > > may (if supported by the HW) delay the ON time of the channel relative
> > > > > to the channel number.
> > > > > This does not alter the duty cycle ratio and is only relevant for PWM
> > > > > chips with less prescalers than channels, which would otherwise assert
> > > > > multiple or even all enabled channels at the same time.
> > > > > 
> > > > > If this feature is supported by the driver and the flag is set on
> > > > > multiple channels, their ON times are spread out to improve EMI and
> > > > > reduce current spikes.
> > > > 
> > > > As said in reply to patch 4/8 already: I don't like this idea and
> > > > think this should be made explicit using a new offset member in struct
> > > > pwm_state instead. That's because I think that the wave form a PWM
> > > > generates should be (completely) defined by the consumer and not by a
> > > > mix between consumer and device tree. Also the consumer has no (sane)
> > > > way to determine if staggering is in use or not.
> > > 
> > > I don't think offsets are ideal for this feature: It makes it more
> > > cumbersome for the user, because he has to allocate the offsets
> > > himself instead of a simple on/off switch.
> > > The envisioned usecase is: "I want better EMI behavior and don't care
> > > about the individual channels no longer being asserted at the exact same
> > > time".
> > 
> > The formal thing is: "I want better EMI behavior and don't care if
> > periods start with the active phase, it might be anywhere, even over a
> > period boundary." Being asserted at the exact same time is just a detail
> > for the pca9685.
> >  
> > > > One side effect (at least for the pca9685) is that when programming a
> > > > new duty cycle it takes a bit longer than without staggering until the
> > > > new setting is active. 
> > > 
> > > Yes, but it can be turned off if this is a problem, now even per-PWM.
> > 
> > Yes and that is a good thing. (BTW: I'd call it per-PWM-consumer, but
> > details.)
> > 
> > > > Another objection I have is that we already have some technical debt
> > > > because there are already two different types of drivers (.apply vs
> > > > .config+.set_polarity+.enable+.disable) and I would like to unify this
> > > > first before introducing new stuff.
> > > 
> > > But there is already PWM_POLARITY_INVERTED, which can be set in the DT.
> > > I am only adding another flag.
> > 
> > I understand your reasoning, and similar to "This diplay backlight needs
> > an inverted PWM (as a low duty-cycle results in a high brightness" this
> > semantic "This consumer doesn't care if the active cycle is anywhere in
> > the period". Hmm, maybe I just have to think about it a bit more to
> > become friends with that thought.
> 
> Yes, I think that's basically what this is saying. I think we're perhaps
> getting hung up on the terminology here. PWM_STAGGERING_ALLOWED gives
> the impression that we're dealing with some provider-specific feature,
> whereas what we really want to express is that the PWM doesn't care
> exactly when the active cycle starts and based on that a provider that
> can support it may optimize the EMI behavior.
> 
> Maybe we can find a better name for this? Ultimately what this means is
> that the consumer is primarily interested in the power output of the PWM
> rather than the exact shape of the signal. So perhaps something like
> PWM_USAGE_POWER would be more appropriate.

Yes, although it would then no longer be obvious that this feature leads
to improved EMI behavior, as long as we mention that in the docs, I
think it's a good idea

Maybe document it as follows?
PWM_USAGE_POWER - Allow the driver to delay the start of the cycle
for EMI improvements, as long as the power output stays the same

> 
> Come to think of it, a flag like that might even be useful to implement
> the common case of emulating inverted polarity with reversing the duty
> cycle. That is, if PWM_USAGE_POWER | PWM_POLARITY_INVERSED was specified
> and the PWM provider did not support polarity inversion, the inversion
> could still be implemented using emulation. Currently we push that logic
> down into consumers, but this could be a way to bring that up into
> drivers, or perhaps even the core.

Interesting, but that would be left for another series in the future, I
assume?

Thanks,
Clemens


Re: [PATCH v7 8/8] pwm: pca9685: Add error messages for failed regmap calls

2021-04-07 Thread Clemens Gruber
On Wed, Apr 07, 2021 at 08:16:19AM +0200, Uwe Kleine-König wrote:
> On Tue, Apr 06, 2021 at 06:41:40PM +0200, Clemens Gruber wrote:
> > Regmap operations can fail if the underlying subsystem is not working
> > properly (e.g. hogged I2C bus, etc.)
> > As this is useful information for the user, print an error message if it
> > happens.
> > Let probe fail if the first regmap_read or the first regmap_write fails.
> > 
> > Signed-off-by: Clemens Gruber 
> > ---
> > Changes since v6:
> > - Rebased
> > 
> >  drivers/pwm/pwm-pca9685.c | 83 ---
> >  1 file changed, 59 insertions(+), 24 deletions(-)
> > 
> > diff --git a/drivers/pwm/pwm-pca9685.c b/drivers/pwm/pwm-pca9685.c
> > index cf0c98e4ef44..8a4993882b40 100644
> > --- a/drivers/pwm/pwm-pca9685.c
> > +++ b/drivers/pwm/pwm-pca9685.c
> > @@ -107,6 +107,30 @@ static bool pca9685_prescaler_can_change(struct 
> > pca9685 *pca, int channel)
> > return test_bit(channel, pca->pwms_enabled);
> >  }
> >  
> > +static int pca9685_read_reg(struct pca9685 *pca, unsigned int reg, 
> > unsigned int *val)
> > +{
> > +   struct device *dev = pca->chip.dev;
> > +   int err;
> > +
> > +   err = regmap_read(pca->regmap, reg, val);
> > +   if (err != 0)
> > +   dev_err(dev, "regmap_read of register 0x%x failed: %d\n", reg, 
> > err);
> 
> Please use %pe to emit the error code instead of %d.

Will do.

> 
> > +
> > +   return err;
> > +}
> > +
> > +static int pca9685_write_reg(struct pca9685 *pca, unsigned int reg, 
> > unsigned int val)
> > +{
> > +   struct device *dev = pca->chip.dev;
> > +   int err;
> > +
> > +   err = regmap_write(pca->regmap, reg, val);
> > +   if (err != 0)
> > +   dev_err(dev, "regmap_write to register 0x%x failed: %d\n", reg, 
> > 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 pca9685 *pca, int channel, 
> > unsigned int duty)
> >  {
> > @@ -115,12 +139,12 @@ static void pca9685_pwm_set_duty(struct pca9685 *pca, 
> > int channel, unsigned int
> >  
> > if (duty == 0) {
> > /* Set the full OFF bit, which has the highest precedence */
> > -   regmap_write(pca->regmap, REG_OFF_H(channel), LED_FULL);
> > +   pca9685_write_reg(pca, REG_OFF_H(channel), LED_FULL);
> 
> You didn't check all return codes? How did you select the calls to
> check?

No, because it would become a big mess and really obstruct readability
in my opinion.

So I chose some kind of middleground:
I decided to check the first regmap_read and regmap_write in probe and
return the error code if something goes wrong there.
If something goes wrong after probe, I only print an error message.

Is that acceptable?

Thanks,
Clemens


Re: [PATCH v7 7/8] pwm: pca9685: Restrict period change for enabled PWMs

2021-04-07 Thread Clemens Gruber
On Wed, Apr 07, 2021 at 08:12:29AM +0200, Uwe Kleine-König wrote:
> 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 if no PWM is enabled, it should return true, not false.

> (but that's a minor issue, the suggested algorithm is correct.)

I would prefer to keep it explicit because it is a little easier to
follow and probably not worth optimizing.

> 
> So:
> 
> Acked-by: Uwe Kleine-König 

Thanks.

> 
> (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.)

As you can't request the all channel and the individual channels
together, there shouldn't be any problems.

I agree that it would be nice to drop the ALL channel support.

Clemens


Re: [PATCH v7 5/8] pwm: core: Support new PWM_STAGGERING_ALLOWED flag

2021-04-07 Thread Clemens Gruber
On Wed, Apr 07, 2021 at 07:46:58AM +0200, Uwe Kleine-König wrote:
> On Tue, Apr 06, 2021 at 06:41:37PM +0200, Clemens Gruber wrote:
> > If the flag PWM_STAGGERING_ALLOWED is set on a channel, the PWM driver
> > may (if supported by the HW) delay the ON time of the channel relative
> > to the channel number.
> > This does not alter the duty cycle ratio and is only relevant for PWM
> > chips with less prescalers than channels, which would otherwise assert
> > multiple or even all enabled channels at the same time.
> > 
> > If this feature is supported by the driver and the flag is set on
> > multiple channels, their ON times are spread out to improve EMI and
> > reduce current spikes.
> 
> As said in reply to patch 4/8 already: I don't like this idea and
> think this should be made explicit using a new offset member in struct
> pwm_state instead. That's because I think that the wave form a PWM
> generates should be (completely) defined by the consumer and not by a
> mix between consumer and device tree. Also the consumer has no (sane)
> way to determine if staggering is in use or not.

I don't think offsets are ideal for this feature: It makes it more
cumbersome for the user, because he has to allocate the offsets
himself instead of a simple on/off switch.
The envisioned usecase is: "I want better EMI behavior and don't care
about the individual channels no longer being asserted at the exact same
time".

> One side effect (at least for the pca9685) is that when programming a
> new duty cycle it takes a bit longer than without staggering until the
> new setting is active. 

Yes, but it can be turned off if this is a problem, now even per-PWM.

> Another objection I have is that we already have some technical debt
> because there are already two different types of drivers (.apply vs
> .config+.set_polarity+.enable+.disable) and I would like to unify this
> first before introducing new stuff.

But there is already PWM_POLARITY_INVERTED, which can be set in the DT.
I am only adding another flag.

Thierry: What's your take on this?

Thanks,
Clemens


Re: [PATCH v7 2/8] pwm: pca9685: Support hardware readout

2021-04-07 Thread Clemens Gruber
On Wed, Apr 07, 2021 at 11:09:43AM +0200, Uwe Kleine-König wrote:
> On Wed, Apr 07, 2021 at 09:33:20AM +0200, Clemens Gruber wrote:
> > On Wed, Apr 07, 2021 at 07:31:35AM +0200, Uwe Kleine-König wrote:
> > > On Tue, Apr 06, 2021 at 06:41:34PM +0200, Clemens Gruber wrote:
> > > > Implements .get_state to read-out the current hardware state.
> > > > 
> > > > The hardware readout may return slightly different values than those
> > > > that were set in apply due to the limited range of possible prescale and
> > > > counter register values.
> > > > 
> > > > Also note that although the datasheet mentions 200 Hz as default
> > > > frequency when using the internal 25 MHz oscillator, the calculated
> > > > period from the default prescaler register setting of 30 is 5079040ns.
> > > > 
> > > > Signed-off-by: Clemens Gruber 
> > > > ---
> > > > Changes since v6:
> > > > - Added a comment regarding the division (Suggested by Uwe)
> > > > - Rebased
> > > > 
> > > >  drivers/pwm/pwm-pca9685.c | 46 +++
> > > >  1 file changed, 46 insertions(+)
> > > > 
> > > > diff --git a/drivers/pwm/pwm-pca9685.c b/drivers/pwm/pwm-pca9685.c
> > > > index 5a2ce97e71fd..d4474c5ff96f 100644
> > > > --- a/drivers/pwm/pwm-pca9685.c
> > > > +++ b/drivers/pwm/pwm-pca9685.c
> > > > @@ -333,6 +333,51 @@ static int pca9685_pwm_apply(struct pwm_chip 
> > > > *chip, struct pwm_device *pwm,
> > > > return 0;
> > > >  }
> > > >  
> > > > +static void pca9685_pwm_get_state(struct pwm_chip *chip, struct 
> > > > pwm_device *pwm,
> > > > + struct pwm_state *state)
> > > > +{
> > > > +   struct pca9685 *pca = to_pca(chip);
> > > > +   unsigned long long duty;
> > > > +   unsigned int val = 0;
> > > > +
> > > > +   /* Calculate (chip-wide) period from prescale value */
> > > > +   regmap_read(pca->regmap, PCA9685_PRESCALE, );
> > > > +   /*
> > > > +* PCA9685_OSC_CLOCK_MHZ is 25, i.e. an integer divider of 1000.
> > > > +* The following calculation is therefore only a multiplication
> > > > +* and we are not losing precision.
> > > > +*/
> > > > +   state->period = (PCA9685_COUNTER_RANGE * 1000 / 
> > > > PCA9685_OSC_CLOCK_MHZ) *
> > > > +   (val + 1);
> > > > +
> > > > +   /* The (per-channel) polarity is fixed */
> > > > +   state->polarity = PWM_POLARITY_NORMAL;
> > > > +
> > > > +   if (pwm->hwpwm >= PCA9685_MAXCHAN) {
> > > > +   /*
> > > > +* The "all LEDs" channel does not support HW readout
> > > > +* Return 0 and disabled for backwards compatibility
> > > > +*/
> > > > +   state->duty_cycle = 0;
> > > > +   state->enabled = false;
> > > > +   return;
> > > > +   }
> > > > +
> > > > +   duty = pca9685_pwm_get_duty(pca, pwm->hwpwm);
> > > > +
> > > > +   state->enabled = !!duty;
> > > > +   if (!state->enabled) {
> > > > +   state->duty_cycle = 0;
> > > > +   return;
> > > > +   } else if (duty == PCA9685_COUNTER_RANGE) {
> > > > +   state->duty_cycle = state->period;
> > > > +   return;
> > > > +   }
> > > > +
> > > > +   duty *= state->period;
> > > > +   state->duty_cycle = duty / PCA9685_COUNTER_RANGE;
> > > 
> > > Given that with duty = 0 the chip is still "on" and changing the duty
> > > will first complete the currently running period, I'd model duty=0 as
> > > enabled. This also simplifies the code a bit, to something like:
> > > 
> > > 
> > >   state->enabled = true;
> > >   duty = pca9685_pwm_get_duty(pca, pwm->hwpwm);
> > >   state->duty_cycle = div_round_up(duty * state->period, 
> > > PCA9685_COUNTER_RANGE);
> > > 
> > > (I'm using round-up here assuming apply uses round-down to get
> > > idempotency. In the current patch set state this is wrong however.)
> > 
> > So, in your opinion, every requested PWM of the pca9685 should always be
> > enabled by default (from the PWM core viewpoint) ?
> > 
> > And this wouldn't break the following because pwm_get_state does not
> > actually read out the hw state:
> > pwm_get_state -> enabled=true duty=0
> > pwm_apply_state -> enabled =false duty=0
> > pwm_get_state -> enabled=false duty=0
> 
> I don't see any breakage here. Either there is none or I failed to grasp
> where you see a problem.

Me neither, I was just thinking out loud.

Clemens


Re: [PATCH v7 2/8] pwm: pca9685: Support hardware readout

2021-04-07 Thread Clemens Gruber
On Wed, Apr 07, 2021 at 07:31:35AM +0200, Uwe Kleine-König wrote:
> On Tue, Apr 06, 2021 at 06:41:34PM +0200, Clemens Gruber wrote:
> > Implements .get_state to read-out the current hardware state.
> > 
> > The hardware readout may return slightly different values than those
> > that were set in apply due to the limited range of possible prescale and
> > counter register values.
> > 
> > Also note that although the datasheet mentions 200 Hz as default
> > frequency when using the internal 25 MHz oscillator, the calculated
> > period from the default prescaler register setting of 30 is 5079040ns.
> > 
> > Signed-off-by: Clemens Gruber 
> > ---
> > Changes since v6:
> > - Added a comment regarding the division (Suggested by Uwe)
> > - Rebased
> > 
> >  drivers/pwm/pwm-pca9685.c | 46 +++
> >  1 file changed, 46 insertions(+)
> > 
> > diff --git a/drivers/pwm/pwm-pca9685.c b/drivers/pwm/pwm-pca9685.c
> > index 5a2ce97e71fd..d4474c5ff96f 100644
> > --- a/drivers/pwm/pwm-pca9685.c
> > +++ b/drivers/pwm/pwm-pca9685.c
> > @@ -333,6 +333,51 @@ static int pca9685_pwm_apply(struct pwm_chip *chip, 
> > struct pwm_device *pwm,
> > return 0;
> >  }
> >  
> > +static void pca9685_pwm_get_state(struct pwm_chip *chip, struct pwm_device 
> > *pwm,
> > + struct pwm_state *state)
> > +{
> > +   struct pca9685 *pca = to_pca(chip);
> > +   unsigned long long duty;
> > +   unsigned int val = 0;
> > +
> > +   /* Calculate (chip-wide) period from prescale value */
> > +   regmap_read(pca->regmap, PCA9685_PRESCALE, );
> > +   /*
> > +* PCA9685_OSC_CLOCK_MHZ is 25, i.e. an integer divider of 1000.
> > +* The following calculation is therefore only a multiplication
> > +* and we are not losing precision.
> > +*/
> > +   state->period = (PCA9685_COUNTER_RANGE * 1000 / PCA9685_OSC_CLOCK_MHZ) *
> > +   (val + 1);
> > +
> > +   /* The (per-channel) polarity is fixed */
> > +   state->polarity = PWM_POLARITY_NORMAL;
> > +
> > +   if (pwm->hwpwm >= PCA9685_MAXCHAN) {
> > +   /*
> > +* The "all LEDs" channel does not support HW readout
> > +* Return 0 and disabled for backwards compatibility
> > +*/
> > +   state->duty_cycle = 0;
> > +   state->enabled = false;
> > +   return;
> > +   }
> > +
> > +   duty = pca9685_pwm_get_duty(pca, pwm->hwpwm);
> > +
> > +   state->enabled = !!duty;
> > +   if (!state->enabled) {
> > +   state->duty_cycle = 0;
> > +   return;
> > +   } else if (duty == PCA9685_COUNTER_RANGE) {
> > +   state->duty_cycle = state->period;
> > +   return;
> > +   }
> > +
> > +   duty *= state->period;
> > +   state->duty_cycle = duty / PCA9685_COUNTER_RANGE;
> 
> Given that with duty = 0 the chip is still "on" and changing the duty
> will first complete the currently running period, I'd model duty=0 as
> enabled. This also simplifies the code a bit, to something like:
> 
> 
>   state->enabled = true;
>   duty = pca9685_pwm_get_duty(pca, pwm->hwpwm);
>   state->duty_cycle = div_round_up(duty * state->period, 
> PCA9685_COUNTER_RANGE);
> 
> (I'm using round-up here assuming apply uses round-down to get
> idempotency. In the current patch set state this is wrong however.)

So, in your opinion, every requested PWM of the pca9685 should always be
enabled by default (from the PWM core viewpoint) ?

And this wouldn't break the following because pwm_get_state does not
actually read out the hw state:
pwm_get_state -> enabled=true duty=0
pwm_apply_state -> enabled =false duty=0
pwm_get_state -> enabled=false duty=0

Thanks,
Clemens


Re: [PATCH v7 1/8] pwm: pca9685: Switch to atomic API

2021-04-07 Thread Clemens Gruber
Hi,

On Wed, Apr 07, 2021 at 07:24:28AM +0200, Uwe Kleine-König wrote:
> Hello,
> 
> On Tue, Apr 06, 2021 at 06:41:33PM +0200, Clemens Gruber wrote:
> > The switch to the atomic API goes hand in hand with a few fixes to
> > previously experienced issues:
> > - The duty cycle is no longer lost after disable/enable (previously the
> >   OFF registers were cleared in disable and the user was required to
> >   call config to restore the duty cycle settings)
> > - If one sets a period resulting in the same prescale register value,
> >   the sleep and write to the register is now skipped
> > 
> > Signed-off-by: Clemens Gruber 
> > ---
> > Changes since v6:
> > - Order of a comparison switched for improved readability
> > 
> > Changes since v5:
> > - Function documentation for set_duty
> > - Variable initializations
> > - Print warning if all LEDs channel
> > - Changed EOPNOTSUPP to EINVAL
> > - Improved error messages
> > - Register reset corrections moved to this patch
> > 
> > Changes since v4:
> > - Patches split up
> > - Use a single set_duty function
> > - Improve readability / new macros
> > - Added a patch to restrict prescale changes to the first user
> > 
> > Changes since v3:
> > - Refactoring: Extracted common functions
> > - Read prescale register value instead of caching it
> > - Return all zeros and disabled for "all LEDs" channel state
> > - Improved duty calculation / mapping to 0..4096
> > 
> > Changes since v2:
> > - Always set default prescale value in probe
> > - Simplified probe code
> > - Inlined functions with one callsite
> > 
> > Changes since v1:
> > - Fixed a logic error
> > - Impoved PM runtime handling and fixed !CONFIG_PM
> > - Write default prescale reg value if invalid in probe
> > - Reuse full_off/_on functions throughout driver
> > - Use cached prescale value whenever possible
> > 
> >  drivers/pwm/pwm-pca9685.c | 261 ++
> >  1 file changed, 92 insertions(+), 169 deletions(-)
> > 
> > diff --git a/drivers/pwm/pwm-pca9685.c b/drivers/pwm/pwm-pca9685.c
> > index 4a55dc18656c..5a2ce97e71fd 100644
> > --- a/drivers/pwm/pwm-pca9685.c
> > +++ b/drivers/pwm/pwm-pca9685.c
> > @@ -51,7 +51,6 @@
> >  #define PCA9685_PRESCALE_MAX   0xFF/* => min. frequency of 24 Hz */
> >  
> >  #define PCA9685_COUNTER_RANGE  4096
> > -#define PCA9685_DEFAULT_PERIOD 500 /* Default period_ns = 1/200 Hz 
> > */
> >  #define PCA9685_OSC_CLOCK_MHZ  25  /* Internal oscillator with 25 
> > MHz */
> >  
> >  #define PCA9685_NUMREGS0xFF
> > @@ -71,10 +70,14 @@
> >  #define LED_N_OFF_H(N) (PCA9685_LEDX_OFF_H + (4 * (N)))
> >  #define LED_N_OFF_L(N) (PCA9685_LEDX_OFF_L + (4 * (N)))
> >  
> > +#define REG_ON_H(C)((C) >= PCA9685_MAXCHAN ? PCA9685_ALL_LED_ON_H 
> > : LED_N_ON_H((C)))
> > +#define REG_ON_L(C)((C) >= PCA9685_MAXCHAN ? PCA9685_ALL_LED_ON_L 
> > : LED_N_ON_L((C)))
> > +#define REG_OFF_H(C)   ((C) >= PCA9685_MAXCHAN ? PCA9685_ALL_LED_OFF_H 
> > : LED_N_OFF_H((C)))
> > +#define REG_OFF_L(C)   ((C) >= PCA9685_MAXCHAN ? PCA9685_ALL_LED_OFF_L 
> > : LED_N_OFF_L((C)))
> > +
> >  struct pca9685 {
> > struct pwm_chip chip;
> > struct regmap *regmap;
> > -   int period_ns;
> >  #if IS_ENABLED(CONFIG_GPIOLIB)
> > struct mutex lock;
> > struct gpio_chip gpio;
> > @@ -87,6 +90,51 @@ static inline struct pca9685 *to_pca(struct pwm_chip 
> > *chip)
> > return container_of(chip, struct pca9685, chip);
> >  }
> >  
> > +/* Helper function to set the duty cycle ratio to duty/4096 (e.g. 
> > duty=2048 -> 50%) */
> > +static void pca9685_pwm_set_duty(struct pca9685 *pca, int channel, 
> > unsigned int duty)
> > +{
> > +   if (duty == 0) {
> > +   /* Set the full OFF bit, which has the highest precedence */
> > +   regmap_write(pca->regmap, REG_OFF_H(channel), LED_FULL);
> > +   } else if (duty >= PCA9685_COUNTER_RANGE) {
> > +   /* Set the full ON bit and clear the full OFF bit */
> > +   regmap_write(pca->regmap, REG_ON_H(channel), LED_FULL);
> > +   regmap_write(pca->regmap, REG_OFF_H(channel), 0);
> > +   } else {
> > +   /* Set OFF time (clears the full OFF bit) */
> > +   regmap_write(pca->regmap, REG_OFF_L(channel), duty & 0xff);
> > +   regmap_write(pca->regmap, 

[PATCH v7 8/8] pwm: pca9685: Add error messages for failed regmap calls

2021-04-06 Thread Clemens Gruber
Regmap operations can fail if the underlying subsystem is not working
properly (e.g. hogged I2C bus, etc.)
As this is useful information for the user, print an error message if it
happens.
Let probe fail if the first regmap_read or the first regmap_write fails.

Signed-off-by: Clemens Gruber 
---
Changes since v6:
- Rebased

 drivers/pwm/pwm-pca9685.c | 83 ---
 1 file changed, 59 insertions(+), 24 deletions(-)

diff --git a/drivers/pwm/pwm-pca9685.c b/drivers/pwm/pwm-pca9685.c
index cf0c98e4ef44..8a4993882b40 100644
--- a/drivers/pwm/pwm-pca9685.c
+++ b/drivers/pwm/pwm-pca9685.c
@@ -107,6 +107,30 @@ static bool pca9685_prescaler_can_change(struct pca9685 
*pca, int channel)
return test_bit(channel, pca->pwms_enabled);
 }
 
+static int pca9685_read_reg(struct pca9685 *pca, unsigned int reg, unsigned 
int *val)
+{
+   struct device *dev = pca->chip.dev;
+   int err;
+
+   err = regmap_read(pca->regmap, reg, val);
+   if (err != 0)
+   dev_err(dev, "regmap_read of register 0x%x failed: %d\n", reg, 
err);
+
+   return err;
+}
+
+static int pca9685_write_reg(struct pca9685 *pca, unsigned int reg, unsigned 
int val)
+{
+   struct device *dev = pca->chip.dev;
+   int err;
+
+   err = regmap_write(pca->regmap, reg, val);
+   if (err != 0)
+   dev_err(dev, "regmap_write to register 0x%x failed: %d\n", reg, 
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 pca9685 *pca, int channel, unsigned 
int duty)
 {
@@ -115,12 +139,12 @@ static void pca9685_pwm_set_duty(struct pca9685 *pca, int 
channel, unsigned int
 
if (duty == 0) {
/* Set the full OFF bit, which has the highest precedence */
-   regmap_write(pca->regmap, REG_OFF_H(channel), LED_FULL);
+   pca9685_write_reg(pca, REG_OFF_H(channel), LED_FULL);
return;
} else if (duty >= PCA9685_COUNTER_RANGE) {
/* Set the full ON bit and clear the full OFF bit */
-   regmap_write(pca->regmap, REG_ON_H(channel), LED_FULL);
-   regmap_write(pca->regmap, REG_OFF_H(channel), 0);
+   pca9685_write_reg(pca, REG_ON_H(channel), LED_FULL);
+   pca9685_write_reg(pca, REG_OFF_H(channel), 0);
return;
}
 
@@ -138,11 +162,11 @@ static void pca9685_pwm_set_duty(struct pca9685 *pca, int 
channel, unsigned int
off = (on + duty) % PCA9685_COUNTER_RANGE;
 
/* Set ON time (clears full ON bit) */
-   regmap_write(pca->regmap, REG_ON_L(channel), on & 0xff);
-   regmap_write(pca->regmap, REG_ON_H(channel), (on >> 8) & 0xf);
+   pca9685_write_reg(pca, REG_ON_L(channel), on & 0xff);
+   pca9685_write_reg(pca, REG_ON_H(channel), (on >> 8) & 0xf);
/* Set OFF time (clears full OFF bit) */
-   regmap_write(pca->regmap, REG_OFF_L(channel), off & 0xff);
-   regmap_write(pca->regmap, REG_OFF_H(channel), (off >> 8) & 0xf);
+   pca9685_write_reg(pca, REG_OFF_L(channel), off & 0xff);
+   pca9685_write_reg(pca, REG_OFF_H(channel), (off >> 8) & 0xf);
 }
 
 static unsigned int pca9685_pwm_get_duty(struct pca9685 *pca, int channel)
@@ -155,26 +179,26 @@ static unsigned int pca9685_pwm_get_duty(struct pca9685 
*pca, int channel)
return 0;
}
 
-   regmap_read(pca->regmap, LED_N_OFF_H(channel), );
+   pca9685_read_reg(pca, LED_N_OFF_H(channel), );
if (off & LED_FULL) {
/* Full OFF bit is set */
return 0;
}
 
-   regmap_read(pca->regmap, LED_N_ON_H(channel), );
+   pca9685_read_reg(pca, LED_N_ON_H(channel), );
if (on & LED_FULL) {
/* Full ON bit is set */
return PCA9685_COUNTER_RANGE;
}
 
-   regmap_read(pca->regmap, LED_N_OFF_L(channel), );
+   pca9685_read_reg(pca, LED_N_OFF_L(channel), );
off = ((off & 0xf) << 8) | (val & 0xff);
if (!pwm->args.staggering_allowed)
return off;
 
/* Read ON register to calculate duty cycle of staggered output */
val = 0;
-   regmap_read(pca->regmap, LED_N_ON_L(channel), );
+   pca9685_read_reg(pca, LED_N_ON_L(channel), );
on = ((on & 0xf) << 8) | (val & 0xff);
return (off - on) & (PCA9685_COUNTER_RANGE - 1);
 }
@@ -317,8 +341,15 @@ static inline int pca9685_pwm_gpio_probe(struct pca9685 
*pca)
 
 static void pca9685_set_sleep_mode(struct pca9685 *pca, bool enable)
 {
-   regmap_update_bits(pca->regmap, PCA9685_MODE1,
-  MODE1_SLEEP, enable ? MODE1_SLEEP : 0);
+   struct device *dev = pca->chip.dev;
+   int err = regmap_update_bit

[PATCH v7 7/8] pwm: pca9685: Restrict period change for enabled PWMs

2021-04-06 Thread Clemens Gruber
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);
+}
+
 /* Helper function to set the duty cycle ratio to duty/4096 (e.g. duty=2048 -> 
50%) */
 static void pca9685_pwm_set_duty(struct pca9685 *pca, int channel, unsigned 
int duty)
 {
@@ -265,8 +282,6 @@ static int pca9685_pwm_gpio_probe(struct pca9685 *pca)
 {
struct device *dev = pca->chip.dev;
 
-   mutex_init(>lock);
-
pca->gpio.label = dev_name(dev);
pca->gpio.parent = dev;
pca->gpio.request = pca9685_pwm_gpio_request;
@@ -310,8 +325,8 @@ static void pca9685_set_sleep_mode(struct pca9685 *pca, 
bool enable)
}
 }
 
-static int pca9685_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
-const struct pwm_state *state)
+static int __pca9685_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
+  const struct pwm_state *state)
 {
struct pca9685 *pca = to_pca(chip);
unsigned long long duty, prescale;
@@ -340,6 +355,12 @@ static int pca9685_pwm_apply(struct pwm_chip *chip, struct 
pwm_device *pwm,
 
regmap_read(pca->regmap, PCA9685_PRESCALE, );
if (prescale != val) {
+   if (!pca9685_prescaler_can_change(pca, pwm->hwpwm)) {
+   dev_err(chip->dev,
+   "pwm not changed: periods of enabled pwms must 
match!\n");
+   return -EBUSY;
+   }
+
/*
 * Putting the chip briefly into SLEEP mode
 * at this point won't interfere with the
@@ -360,6 +381,25 @@ static int pca9685_pwm_apply(struct pwm_chip *chip, struct 
pwm_device *pwm,
return 0;
 }
 
+static int pca9685_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
+const struct pwm_state *state)
+{
+   struct pca9685 *pca = to_pca(chip);
+   int ret;
+
+   mutex_lock(>lock);
+   ret = __pca9685_pwm_apply(chip, pwm, state);
+   if (ret == 0) {
+   if (state->enabled)
+   set_bit(pwm->hwpwm, pca->pwms_enabled);
+   else
+   clear_bit(pwm->hwpwm, pca->pwms_enabled);
+   }
+

[PATCH v7 6/8] pwm: pca9685: Support new PWM_STAGGERING_ALLOWED flag

2021-04-06 Thread Clemens Gruber
The PCA9685 supports staggered LED output ON times to minimize current
surges and reduce EMI.
When the PWM_STAGGERING_ALLOWED flag is set for a channel, its ON time
is delayed by channel number x counter range / 16, which avoids
asserting all the enabled outputs at the same counter value while still
maintaining the configured duty cycle of each output.

Signed-off-by: Clemens Gruber 
---
Changes since v6:
- Use a per-PWM flag instead of one global DT parameter

 drivers/pwm/pwm-pca9685.c | 60 ++-
 1 file changed, 46 insertions(+), 14 deletions(-)

diff --git a/drivers/pwm/pwm-pca9685.c b/drivers/pwm/pwm-pca9685.c
index 0bcec04b138a..24221ee7a77a 100644
--- a/drivers/pwm/pwm-pca9685.c
+++ b/drivers/pwm/pwm-pca9685.c
@@ -93,46 +93,73 @@ static inline struct pca9685 *to_pca(struct pwm_chip *chip)
 /* Helper function to set the duty cycle ratio to duty/4096 (e.g. duty=2048 -> 
50%) */
 static void pca9685_pwm_set_duty(struct pca9685 *pca, int channel, unsigned 
int duty)
 {
+   struct pwm_device *pwm = >chip.pwms[channel];
+   unsigned int on, off;
+
if (duty == 0) {
/* Set the full OFF bit, which has the highest precedence */
regmap_write(pca->regmap, REG_OFF_H(channel), LED_FULL);
+   return;
} else if (duty >= PCA9685_COUNTER_RANGE) {
/* Set the full ON bit and clear the full OFF bit */
regmap_write(pca->regmap, REG_ON_H(channel), LED_FULL);
regmap_write(pca->regmap, REG_OFF_H(channel), 0);
-   } else {
-   /* Set OFF time (clears the full OFF bit) */
-   regmap_write(pca->regmap, REG_OFF_L(channel), duty & 0xff);
-   regmap_write(pca->regmap, REG_OFF_H(channel), (duty >> 8) & 
0xf);
-   /* Clear the full ON bit */
-   regmap_write(pca->regmap, REG_ON_H(channel), 0);
+   return;
}
+
+
+   if (pwm->args.staggering_allowed && channel < PCA9685_MAXCHAN) {
+   /*
+* To reduce EMI, the ON times of each channel are
+* spread out evenly within the counter range, while
+* still maintaining the configured duty cycle
+*/
+   on = channel * PCA9685_COUNTER_RANGE / PCA9685_MAXCHAN;
+   } else
+   on = 0;
+
+   off = (on + duty) % PCA9685_COUNTER_RANGE;
+
+   /* Set ON time (clears full ON bit) */
+   regmap_write(pca->regmap, REG_ON_L(channel), on & 0xff);
+   regmap_write(pca->regmap, REG_ON_H(channel), (on >> 8) & 0xf);
+   /* Set OFF time (clears full OFF bit) */
+   regmap_write(pca->regmap, REG_OFF_L(channel), off & 0xff);
+   regmap_write(pca->regmap, REG_OFF_H(channel), (off >> 8) & 0xf);
 }
 
 static unsigned int pca9685_pwm_get_duty(struct pca9685 *pca, int channel)
 {
-   unsigned int off_h = 0, val = 0;
+   struct pwm_device *pwm = >chip.pwms[channel];
+   unsigned int off = 0, on = 0, val = 0;
 
if (WARN_ON(channel >= PCA9685_MAXCHAN)) {
/* HW does not support reading state of "all LEDs" channel */
return 0;
}
 
-   regmap_read(pca->regmap, LED_N_OFF_H(channel), _h);
-   if (off_h & LED_FULL) {
+   regmap_read(pca->regmap, LED_N_OFF_H(channel), );
+   if (off & LED_FULL) {
/* Full OFF bit is set */
return 0;
}
 
-   regmap_read(pca->regmap, LED_N_ON_H(channel), );
-   if (val & LED_FULL) {
+   regmap_read(pca->regmap, LED_N_ON_H(channel), );
+   if (on & LED_FULL) {
/* Full ON bit is set */
return PCA9685_COUNTER_RANGE;
}
 
-   val = 0;
regmap_read(pca->regmap, LED_N_OFF_L(channel), );
-   return ((off_h & 0xf) << 8) | (val & 0xff);
+   off = ((off & 0xf) << 8) | (val & 0xff);
+   if (!pwm->args.staggering_allowed)
+   return off;
+
+   /* Read ON register to calculate duty cycle of staggered output */
+   val = 0;
+   regmap_read(pca->regmap, LED_N_ON_L(channel), );
+   on = ((on & 0xf) << 8) | (val & 0xff);
+   return (off - on) & (PCA9685_COUNTER_RANGE - 1);
 }
 
 #if IS_ENABLED(CONFIG_GPIOLIB)
@@ -453,9 +480,11 @@ static int pca9685_pwm_probe(struct i2c_client *client,
reg &= ~(MODE1_ALLCALL | MODE1_SUB1 | MODE1_SUB2 | MODE1_SUB3);
regmap_write(pca->regmap, PCA9685_MODE1, reg);
 
-   /* Reset OFF registers to POR default */
+   /* Reset OFF/ON registers to POR default */
regmap_write(pca->regmap, PCA9685_ALL_LED_OFF_L, LED_FULL);
regmap_write(pca->regmap, PCA9685_ALL_LED_OFF_H, LED_FULL);
+   regmap_write(pca->regmap, PCA9685_ALL_LED_ON_L, 0);
+   regmap_write

[PATCH v7 5/8] pwm: core: Support new PWM_STAGGERING_ALLOWED flag

2021-04-06 Thread Clemens Gruber
If the flag PWM_STAGGERING_ALLOWED is set on a channel, the PWM driver
may (if supported by the HW) delay the ON time of the channel relative
to the channel number.
This does not alter the duty cycle ratio and is only relevant for PWM
chips with less prescalers than channels, which would otherwise assert
multiple or even all enabled channels at the same time.

If this feature is supported by the driver and the flag is set on
multiple channels, their ON times are spread out to improve EMI and
reduce current spikes.

Signed-off-by: Clemens Gruber 
---
 drivers/pwm/core.c  | 9 +++--
 include/linux/pwm.h | 1 +
 2 files changed, 8 insertions(+), 2 deletions(-)

diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c
index a8eff4b3ee36..f58aad754741 100644
--- a/drivers/pwm/core.c
+++ b/drivers/pwm/core.c
@@ -153,9 +153,14 @@ of_pwm_xlate_with_flags(struct pwm_chip *pc, const struct 
of_phandle_args *args)
 
pwm->args.period = args->args[1];
pwm->args.polarity = PWM_POLARITY_NORMAL;
+   pwm->args.staggering_allowed = false;
 
-   if (args->args_count > 2 && args->args[2] & PWM_POLARITY_INVERTED)
-   pwm->args.polarity = PWM_POLARITY_INVERSED;
+   if (args->args_count > 2) {
+   if (args->args[2] & PWM_POLARITY_INVERTED)
+   pwm->args.polarity = PWM_POLARITY_INVERSED;
+   if (args->args[2] & PWM_STAGGERING_ALLOWED)
+   pwm->args.staggering_allowed = true;
+   }
 
return pwm;
 }
diff --git a/include/linux/pwm.h b/include/linux/pwm.h
index e4d84d4db293..3d5dee8c564f 100644
--- a/include/linux/pwm.h
+++ b/include/linux/pwm.h
@@ -41,6 +41,7 @@ enum pwm_polarity {
 struct pwm_args {
u64 period;
enum pwm_polarity polarity;
+   bool staggering_allowed;
 };
 
 enum {
-- 
2.31.1



[PATCH v7 4/8] dt-bindings: pwm: Support new PWM_STAGGERING_ALLOWED flag

2021-04-06 Thread Clemens Gruber
Add the flag and corresponding documentation for the new PWM staggering
mode feature.

Cc: Rob Herring 
Signed-off-by: Clemens Gruber 
---
 Documentation/devicetree/bindings/pwm/pwm.txt | 1 +
 include/dt-bindings/pwm/pwm.h | 1 +
 2 files changed, 2 insertions(+)

diff --git a/Documentation/devicetree/bindings/pwm/pwm.txt 
b/Documentation/devicetree/bindings/pwm/pwm.txt
index 084886bd721e..11d539302398 100644
--- a/Documentation/devicetree/bindings/pwm/pwm.txt
+++ b/Documentation/devicetree/bindings/pwm/pwm.txt
@@ -46,6 +46,7 @@ period in nanoseconds.
 Optionally, the pwm-specifier can encode a number of flags (defined in
 ) in a third cell:
 - PWM_POLARITY_INVERTED: invert the PWM signal polarity
+- PWM_STAGGERING_ALLOWED: allow delayed ON-time for improved EMI
 
 Example with optional PWM specifier for inverse polarity
 
diff --git a/include/dt-bindings/pwm/pwm.h b/include/dt-bindings/pwm/pwm.h
index ab9a077e3c7d..51d67dec1aad 100644
--- a/include/dt-bindings/pwm/pwm.h
+++ b/include/dt-bindings/pwm/pwm.h
@@ -11,5 +11,6 @@
 #define _DT_BINDINGS_PWM_PWM_H
 
 #define PWM_POLARITY_INVERTED  (1 << 0)
+#define PWM_STAGGERING_ALLOWED (1 << 1)
 
 #endif
-- 
2.31.1



[PATCH v7 3/8] pwm: pca9685: Improve runtime PM behavior

2021-04-06 Thread Clemens Gruber
The chip does not come out of POR in active state but in sleep state.
To be sure (in case the bootloader woke it up) we force it to sleep in
probe.

On kernels without CONFIG_PM, we wake the chip in .probe and put it to
sleep in .remove.

Signed-off-by: Clemens Gruber 
---
Changes since v6:
- Improved !CONFIG_PM handling (wake it up without putting it to sleep
  first)

 drivers/pwm/pwm-pca9685.c | 26 +++---
 1 file changed, 19 insertions(+), 7 deletions(-)

diff --git a/drivers/pwm/pwm-pca9685.c b/drivers/pwm/pwm-pca9685.c
index d4474c5ff96f..0bcec04b138a 100644
--- a/drivers/pwm/pwm-pca9685.c
+++ b/drivers/pwm/pwm-pca9685.c
@@ -474,13 +474,18 @@ static int pca9685_pwm_probe(struct i2c_client *client,
return ret;
}
 
-   /* The chip comes out of power-up in the active state */
-   pm_runtime_set_active(>dev);
-   /*
-* Enable will put the chip into suspend, which is what we
-* want as all outputs are disabled at this point
-*/
-   pm_runtime_enable(>dev);
+   if (IS_ENABLED(CONFIG_PM)) {
+   /*
+* The chip comes out of power-up in the sleep state,
+* but force it to sleep in case it was woken up before
+*/
+   pca9685_set_sleep_mode(pca, true);
+   pm_runtime_set_suspended(>dev);
+   pm_runtime_enable(>dev);
+   } else {
+   /* Wake the chip up on non-PM environments */
+   pca9685_set_sleep_mode(pca, false);
+   }
 
return 0;
 }
@@ -493,7 +498,14 @@ static int pca9685_pwm_remove(struct i2c_client *client)
ret = pwmchip_remove(>chip);
if (ret)
return ret;
+
pm_runtime_disable(>dev);
+
+   if (!IS_ENABLED(CONFIG_PM)) {
+   /* Put chip in sleep state on non-PM environments */
+   pca9685_set_sleep_mode(pca, true);
+   }
+
return 0;
 }
 
-- 
2.31.1



[PATCH v7 2/8] pwm: pca9685: Support hardware readout

2021-04-06 Thread Clemens Gruber
Implements .get_state to read-out the current hardware state.

The hardware readout may return slightly different values than those
that were set in apply due to the limited range of possible prescale and
counter register values.

Also note that although the datasheet mentions 200 Hz as default
frequency when using the internal 25 MHz oscillator, the calculated
period from the default prescaler register setting of 30 is 5079040ns.

Signed-off-by: Clemens Gruber 
---
Changes since v6:
- Added a comment regarding the division (Suggested by Uwe)
- Rebased

 drivers/pwm/pwm-pca9685.c | 46 +++
 1 file changed, 46 insertions(+)

diff --git a/drivers/pwm/pwm-pca9685.c b/drivers/pwm/pwm-pca9685.c
index 5a2ce97e71fd..d4474c5ff96f 100644
--- a/drivers/pwm/pwm-pca9685.c
+++ b/drivers/pwm/pwm-pca9685.c
@@ -333,6 +333,51 @@ static int pca9685_pwm_apply(struct pwm_chip *chip, struct 
pwm_device *pwm,
return 0;
 }
 
+static void pca9685_pwm_get_state(struct pwm_chip *chip, struct pwm_device 
*pwm,
+ struct pwm_state *state)
+{
+   struct pca9685 *pca = to_pca(chip);
+   unsigned long long duty;
+   unsigned int val = 0;
+
+   /* Calculate (chip-wide) period from prescale value */
+   regmap_read(pca->regmap, PCA9685_PRESCALE, );
+   /*
+* PCA9685_OSC_CLOCK_MHZ is 25, i.e. an integer divider of 1000.
+* The following calculation is therefore only a multiplication
+* and we are not losing precision.
+*/
+   state->period = (PCA9685_COUNTER_RANGE * 1000 / PCA9685_OSC_CLOCK_MHZ) *
+   (val + 1);
+
+   /* The (per-channel) polarity is fixed */
+   state->polarity = PWM_POLARITY_NORMAL;
+
+   if (pwm->hwpwm >= PCA9685_MAXCHAN) {
+   /*
+* The "all LEDs" channel does not support HW readout
+* Return 0 and disabled for backwards compatibility
+*/
+   state->duty_cycle = 0;
+   state->enabled = false;
+   return;
+   }
+
+   duty = pca9685_pwm_get_duty(pca, pwm->hwpwm);
+
+   state->enabled = !!duty;
+   if (!state->enabled) {
+   state->duty_cycle = 0;
+   return;
+   } else if (duty == PCA9685_COUNTER_RANGE) {
+   state->duty_cycle = state->period;
+   return;
+   }
+
+   duty *= state->period;
+   state->duty_cycle = duty / PCA9685_COUNTER_RANGE;
+}
+
 static int pca9685_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
 {
struct pca9685 *pca = to_pca(chip);
@@ -355,6 +400,7 @@ static void pca9685_pwm_free(struct pwm_chip *chip, struct 
pwm_device *pwm)
 
 static const struct pwm_ops pca9685_pwm_ops = {
.apply = pca9685_pwm_apply,
+   .get_state = pca9685_pwm_get_state,
.request = pca9685_pwm_request,
.free = pca9685_pwm_free,
.owner = THIS_MODULE,
-- 
2.31.1



[PATCH v7 1/8] pwm: pca9685: Switch to atomic API

2021-04-06 Thread Clemens Gruber
The switch to the atomic API goes hand in hand with a few fixes to
previously experienced issues:
- The duty cycle is no longer lost after disable/enable (previously the
  OFF registers were cleared in disable and the user was required to
  call config to restore the duty cycle settings)
- If one sets a period resulting in the same prescale register value,
  the sleep and write to the register is now skipped

Signed-off-by: Clemens Gruber 
---
Changes since v6:
- Order of a comparison switched for improved readability

Changes since v5:
- Function documentation for set_duty
- Variable initializations
- Print warning if all LEDs channel
- Changed EOPNOTSUPP to EINVAL
- Improved error messages
- Register reset corrections moved to this patch

Changes since v4:
- Patches split up
- Use a single set_duty function
- Improve readability / new macros
- Added a patch to restrict prescale changes to the first user

Changes since v3:
- Refactoring: Extracted common functions
- Read prescale register value instead of caching it
- Return all zeros and disabled for "all LEDs" channel state
- Improved duty calculation / mapping to 0..4096

Changes since v2:
- Always set default prescale value in probe
- Simplified probe code
- Inlined functions with one callsite

Changes since v1:
- Fixed a logic error
- Impoved PM runtime handling and fixed !CONFIG_PM
- Write default prescale reg value if invalid in probe
- Reuse full_off/_on functions throughout driver
- Use cached prescale value whenever possible

 drivers/pwm/pwm-pca9685.c | 261 ++
 1 file changed, 92 insertions(+), 169 deletions(-)

diff --git a/drivers/pwm/pwm-pca9685.c b/drivers/pwm/pwm-pca9685.c
index 4a55dc18656c..5a2ce97e71fd 100644
--- a/drivers/pwm/pwm-pca9685.c
+++ b/drivers/pwm/pwm-pca9685.c
@@ -51,7 +51,6 @@
 #define PCA9685_PRESCALE_MAX   0xFF/* => min. frequency of 24 Hz */
 
 #define PCA9685_COUNTER_RANGE  4096
-#define PCA9685_DEFAULT_PERIOD 500 /* Default period_ns = 1/200 Hz */
 #define PCA9685_OSC_CLOCK_MHZ  25  /* Internal oscillator with 25 MHz */
 
 #define PCA9685_NUMREGS0xFF
@@ -71,10 +70,14 @@
 #define LED_N_OFF_H(N) (PCA9685_LEDX_OFF_H + (4 * (N)))
 #define LED_N_OFF_L(N) (PCA9685_LEDX_OFF_L + (4 * (N)))
 
+#define REG_ON_H(C)((C) >= PCA9685_MAXCHAN ? PCA9685_ALL_LED_ON_H : 
LED_N_ON_H((C)))
+#define REG_ON_L(C)((C) >= PCA9685_MAXCHAN ? PCA9685_ALL_LED_ON_L : 
LED_N_ON_L((C)))
+#define REG_OFF_H(C)   ((C) >= PCA9685_MAXCHAN ? PCA9685_ALL_LED_OFF_H : 
LED_N_OFF_H((C)))
+#define REG_OFF_L(C)   ((C) >= PCA9685_MAXCHAN ? PCA9685_ALL_LED_OFF_L : 
LED_N_OFF_L((C)))
+
 struct pca9685 {
struct pwm_chip chip;
struct regmap *regmap;
-   int period_ns;
 #if IS_ENABLED(CONFIG_GPIOLIB)
struct mutex lock;
struct gpio_chip gpio;
@@ -87,6 +90,51 @@ static inline struct pca9685 *to_pca(struct pwm_chip *chip)
return container_of(chip, struct pca9685, chip);
 }
 
+/* Helper function to set the duty cycle ratio to duty/4096 (e.g. duty=2048 -> 
50%) */
+static void pca9685_pwm_set_duty(struct pca9685 *pca, int channel, unsigned 
int duty)
+{
+   if (duty == 0) {
+   /* Set the full OFF bit, which has the highest precedence */
+   regmap_write(pca->regmap, REG_OFF_H(channel), LED_FULL);
+   } else if (duty >= PCA9685_COUNTER_RANGE) {
+   /* Set the full ON bit and clear the full OFF bit */
+   regmap_write(pca->regmap, REG_ON_H(channel), LED_FULL);
+   regmap_write(pca->regmap, REG_OFF_H(channel), 0);
+   } else {
+   /* Set OFF time (clears the full OFF bit) */
+   regmap_write(pca->regmap, REG_OFF_L(channel), duty & 0xff);
+   regmap_write(pca->regmap, REG_OFF_H(channel), (duty >> 8) & 
0xf);
+   /* Clear the full ON bit */
+   regmap_write(pca->regmap, REG_ON_H(channel), 0);
+   }
+}
+
+static unsigned int pca9685_pwm_get_duty(struct pca9685 *pca, int channel)
+{
+   unsigned int off_h = 0, val = 0;
+
+   if (WARN_ON(channel >= PCA9685_MAXCHAN)) {
+   /* HW does not support reading state of "all LEDs" channel */
+   return 0;
+   }
+
+   regmap_read(pca->regmap, LED_N_OFF_H(channel), _h);
+   if (off_h & LED_FULL) {
+   /* Full OFF bit is set */
+   return 0;
+   }
+
+   regmap_read(pca->regmap, LED_N_ON_H(channel), );
+   if (val & LED_FULL) {
+   /* Full ON bit is set */
+   return PCA9685_COUNTER_RANGE;
+   }
+
+   val = 0;
+   regmap_read(pca->regmap, LED_N_OFF_L(channel), );
+   return ((off_h & 0xf) << 8) | (val & 0xff);
+}
+
 #if IS_ENABLED(CONFIG_GPIOLIB)
 static bool pca9685_pwm_test_and_set_inuse(struct pca9685 *pca, int pwm_idx)
 {
@@ -138,34 +186,23 @@ static int pca9685_pwm_g

Re: [PATCH v6 4/7] pwm: pca9685: Support staggered output ON times

2021-04-01 Thread Clemens Gruber
On Thu, Apr 01, 2021 at 10:59:36PM +0200, Uwe Kleine-König wrote:
> On Wed, Mar 31, 2021 at 03:55:49PM +0200, Clemens Gruber wrote:
> > On Wed, Mar 31, 2021 at 02:26:14PM +0200, Clemens Gruber wrote:
> > > On Mon, Mar 29, 2021 at 08:02:06PM +0200, Uwe Kleine-König wrote:
> > > > On Mon, Mar 29, 2021 at 07:16:38PM +0200, Clemens Gruber wrote:
> > > > > On Mon, Mar 29, 2021 at 07:03:57PM +0200, Uwe Kleine-König wrote:
> > > > > > On Mon, Mar 29, 2021 at 02:57:04PM +0200, Clemens Gruber wrote:
> > > > > > > The PCA9685 supports staggered LED output ON times to minimize 
> > > > > > > current
> > > > > > > surges and reduce EMI.
> > > > > > > When this new option is enabled, the ON times of each channel are
> > > > > > > delayed by channel number x counter range / 16, which avoids 
> > > > > > > asserting
> > > > > > > all enabled outputs at the same counter value while still 
> > > > > > > maintaining
> > > > > > > the configured duty cycle of each output.
> > > > > > > 
> > > > > > > Signed-off-by: Clemens Gruber 
> > > > > > 
> > > > > > Is there a reason to not want this staggered output? If it never 
> > > > > > hurts I
> > > > > > suggest to always stagger and drop the dt property.
> > > > > 
> > > > > There might be applications where you want multiple outputs to assert 
> > > > > at
> > > > > the same time / to be synchronized.
> > > > > With staggered outputs mode always enabled, this would no longer be
> > > > > possible as they are spread out according to their channel number.
> > > > > 
> > > > > Not sure how often that usecase is required, but just enforcing the
> > > > > staggered mode by default sounds risky to me.
> > > > 
> > > > There is no such guarantee in the PWM framework, so I don't think we
> > > > need to fear breaking setups. Thierry?
> > > 
> > > Still, someone might rely on it? But let's wait for Thierry's opinion.
> > > 
> > > > 
> > > > One reason we might not want staggering is if we have a consumer who
> > > > cares about config transitions. (This however is moot it the hardware
> > > > doesn't provide sane transitions even without staggering.)
> > > > 
> > > > Did I already ask about races in this driver? I assume there is a
> > > > free running counter and the ON and OFF registers just define where in
> > > > the period the transitions happen, right? Given that changing ON and OFF
> > > > needs two register writes probably all kind of strange things can
> > > > happen, right? (Example thought: for simplicity's sake I assume ON is
> > > > always 0. Then if you want to change from OFF = 0xaaa to OFF = 0xccc we
> > > > might see a period with 0xacc. Depending on how the hardware works we
> > > > might even see 4 edges in a single period then.)
> > > 
> > > Yes, there is a free running counter from 0 to 4095.
> > > And it is probably true, that there can be short intermediate states
> > > with our two register writes.
> > > 
> > > There is a separate mode "Update on ACK" (MODE2 register, bit 3 "OCH"),
> > > which is 0 by default (Outputs change on STOP command) but could be set
> > > to 1 (Outputs change on ACK):
> > > "Update on ACK requires all 4 PWM channel registers to be loaded before
> > > outputs will change on the last ACK."
> > 
> > This would require the auto-increment feature to be enabled, then
> > multiple registers could be written before the STOP condition:
> > LEDn_ON_L, LEDn_ON_H, LEDn_OFF_L & LEDn_OFF_H
> > (With OCH=0 in MODE2)
> 
> Maybe a continued START would work, too?!

Yes, maybe. But according to the datasheet bus transaction examples,
it's enough to have one START condition and write multiple (continuous)
registers using the auto-increment feature. And repeated START does not
seem to be supported via regmap..?

Clemens


Re: [PATCH v6 4/7] pwm: pca9685: Support staggered output ON times

2021-04-01 Thread Clemens Gruber
Hello Uwe,

On Thu, Apr 01, 2021 at 10:58:19PM +0200, Uwe Kleine-König wrote:
> Hello Clemens,
> 
> On Wed, Mar 31, 2021 at 02:26:14PM +0200, Clemens Gruber wrote:
> > On Mon, Mar 29, 2021 at 08:02:06PM +0200, Uwe Kleine-König wrote:
> > > On Mon, Mar 29, 2021 at 07:16:38PM +0200, Clemens Gruber wrote:
> > > > On Mon, Mar 29, 2021 at 07:03:57PM +0200, Uwe Kleine-König wrote:
> > > > > On Mon, Mar 29, 2021 at 02:57:04PM +0200, Clemens Gruber wrote:
> > > > > > The PCA9685 supports staggered LED output ON times to minimize 
> > > > > > current
> > > > > > surges and reduce EMI.
> > > > > > When this new option is enabled, the ON times of each channel are
> > > > > > delayed by channel number x counter range / 16, which avoids 
> > > > > > asserting
> > > > > > all enabled outputs at the same counter value while still 
> > > > > > maintaining
> > > > > > the configured duty cycle of each output.
> > > > > > 
> > > > > > Signed-off-by: Clemens Gruber 
> > > > > 
> > > > > Is there a reason to not want this staggered output? If it never 
> > > > > hurts I
> > > > > suggest to always stagger and drop the dt property.
> > > > 
> > > > There might be applications where you want multiple outputs to assert at
> > > > the same time / to be synchronized.
> > > > With staggered outputs mode always enabled, this would no longer be
> > > > possible as they are spread out according to their channel number.
> > > > 
> > > > Not sure how often that usecase is required, but just enforcing the
> > > > staggered mode by default sounds risky to me.
> > > 
> > > There is no such guarantee in the PWM framework, so I don't think we
> > > need to fear breaking setups. Thierry?
> > 
> > Still, someone might rely on it? But let's wait for Thierry's opinion.
> 
> Someone might rely on the pca9685 driver being as racy as a driver with
> legacy bindings usually is. Should this be the reason to drop this whole
> series?

That's not really a fair comparison. I just don't want the whole
staggering mode patch to get reverted someday because it broke someone's
setup. If it is opt-in, something like that can't happen.

If you say that we don't have to care about usecases that are not
officialy guaranteed by the framework, then I'm fine with enabling it by
default.

But in the meantime, Thierry also argued against enabling it by default.

> 
> > > One reason we might not want staggering is if we have a consumer who
> > > cares about config transitions. (This however is moot it the hardware
> > > doesn't provide sane transitions even without staggering.)
> > > 
> > > Did I already ask about races in this driver? I assume there is a
> > > free running counter and the ON and OFF registers just define where in
> > > the period the transitions happen, right? Given that changing ON and OFF
> > > needs two register writes probably all kind of strange things can
> > > happen, right? (Example thought: for simplicity's sake I assume ON is
> > > always 0. Then if you want to change from OFF = 0xaaa to OFF = 0xccc we
> > > might see a period with 0xacc. Depending on how the hardware works we
> > > might even see 4 edges in a single period then.)
> > 
> > Yes, there is a free running counter from 0 to 4095.
> > And it is probably true, that there can be short intermediate states
> > with our two register writes.
> > 
> > There is a separate mode "Update on ACK" (MODE2 register, bit 3 "OCH"),
> > which is 0 by default (Outputs change on STOP command) but could be set
> > to 1 (Outputs change on ACK):
> > "Update on ACK requires all 4 PWM channel registers to be loaded before
> > outputs will change on the last ACK."
> 
> This is about the ACK and STOP in the i2c communication, right? I fail
> to understand the relevance of this difference. I guess I have to read
> the manual myself.

Yes. Not sure why they added the other mode myself, as you should be
able to send multiple bytes before the STOP with auto-increment as well.
But I did not try this out yet as this won't go into this series anyway.
I will look into it in more detail and do some experiments as soon as
this series is merged.

>  
> > The chip datasheet also states:
> > "Because the loading of the LEDn_ON and LEDn_OFF registers is via the
> > I2C-bus, and asynchronous to the internal oscillator, we want to ensure
> > that we do not see any visual artifacts of changing the ON and OFF
> > values. This is achieved by updating the changes at the end of the LOW
> > cycle."
> 
> So we're only out of luck if the first register write happens before and
> the second after the end of the LOW cycle, aren't we?

Yes. And this will be fixed with the auto-increment feature when we can
write all registers in one transaction.

Thanks,
Clemens


Re: [PATCH v6 4/7] pwm: pca9685: Support staggered output ON times

2021-04-01 Thread Clemens Gruber
On Thu, Apr 01, 2021 at 03:47:26PM +0200, Thierry Reding wrote:
> On Thu, Apr 01, 2021 at 09:50:44AM +0200, Clemens Gruber wrote:
> > Hi Thierry,
> > 
> > On Wed, Mar 31, 2021 at 06:21:32PM +0200, Thierry Reding wrote:
> > > On Wed, Mar 31, 2021 at 02:26:14PM +0200, Clemens Gruber wrote:
> > > > On Mon, Mar 29, 2021 at 08:02:06PM +0200, Uwe Kleine-König wrote:
> > > > > On Mon, Mar 29, 2021 at 07:16:38PM +0200, Clemens Gruber wrote:
> > > > > > On Mon, Mar 29, 2021 at 07:03:57PM +0200, Uwe Kleine-König wrote:
> > > > > > > On Mon, Mar 29, 2021 at 02:57:04PM +0200, Clemens Gruber wrote:
> > > > > > > > The PCA9685 supports staggered LED output ON times to minimize 
> > > > > > > > current
> > > > > > > > surges and reduce EMI.
> > > > > > > > When this new option is enabled, the ON times of each channel 
> > > > > > > > are
> > > > > > > > delayed by channel number x counter range / 16, which avoids 
> > > > > > > > asserting
> > > > > > > > all enabled outputs at the same counter value while still 
> > > > > > > > maintaining
> > > > > > > > the configured duty cycle of each output.
> > > > > > > > 
> > > > > > > > Signed-off-by: Clemens Gruber 
> > > > > > > 
> > > > > > > Is there a reason to not want this staggered output? If it never 
> > > > > > > hurts I
> > > > > > > suggest to always stagger and drop the dt property.
> > > > > > 
> > > > > > There might be applications where you want multiple outputs to 
> > > > > > assert at
> > > > > > the same time / to be synchronized.
> > > > > > With staggered outputs mode always enabled, this would no longer be
> > > > > > possible as they are spread out according to their channel number.
> > > > > > 
> > > > > > Not sure how often that usecase is required, but just enforcing the
> > > > > > staggered mode by default sounds risky to me.
> > > > > 
> > > > > There is no such guarantee in the PWM framework, so I don't think we
> > > > > need to fear breaking setups. Thierry?
> > > > 
> > > > Still, someone might rely on it? But let's wait for Thierry's opinion.
> > > 
> > > There's currently no way to synchronize two PWM channels in the PWM
> > > framework. And given that each PWM channel is handled separately the
> > > programming for two channels will never happen atomically or even
> > > concurrently, so I don't see how you could run two PWMs completely
> > > synchronized to one another.
> > 
> > As the PCA9685 has only one prescaler and one counter per chip, by
> > default, all PWMs enabled will go high at the same time. If they also
> > have the same duty cycle configured, they also go low at the same time.
> 
> What happens if you enable one of them, it then goes high and then you
> enable the next one? Is the second one going to get enabled on the next
> period? Or will it start in the middle of the period?

The channel configuration is updated at the end of the low cycle of the
channel in question and if the counter is already past the ON time, it
will start with the next period. So the second one should never start
while the first one is high (unless staggering mode is enabled).

> To truly enable them atomically, you'd have to ensure they all get
> enabled in basically the same write, right? Because otherwise you can
> still end up with just a subset enabled and the rest getting enabled
> only after the first period.

Yes. This could probably be achieved with auto-increment for consecutive
channels or with the special ALL channel for all channels.

In our usecases this is not required. I'd still like to send a follow up
patch in the future that at least implements the register writes per
channel with auto increment to not have intermediate states (due to high
and low byte being written separately)

> > > Or did I misunderstand and it's only the start time of the rising edge
> > > that's shifted, but the signal will remain high for a full duty cycle
> > > after that and then go down and remain low for period - duty - offset?
> > 
> > Yes, that's how it works.
> 
> That's less problematic because the signal will remain a standard PWM,
> it's just shifted by some amount. Technically pwm

Re: [PATCH v6 4/7] pwm: pca9685: Support staggered output ON times

2021-04-01 Thread Clemens Gruber
Hi Thierry,

On Wed, Mar 31, 2021 at 06:21:32PM +0200, Thierry Reding wrote:
> On Wed, Mar 31, 2021 at 02:26:14PM +0200, Clemens Gruber wrote:
> > On Mon, Mar 29, 2021 at 08:02:06PM +0200, Uwe Kleine-König wrote:
> > > On Mon, Mar 29, 2021 at 07:16:38PM +0200, Clemens Gruber wrote:
> > > > On Mon, Mar 29, 2021 at 07:03:57PM +0200, Uwe Kleine-König wrote:
> > > > > On Mon, Mar 29, 2021 at 02:57:04PM +0200, Clemens Gruber wrote:
> > > > > > The PCA9685 supports staggered LED output ON times to minimize 
> > > > > > current
> > > > > > surges and reduce EMI.
> > > > > > When this new option is enabled, the ON times of each channel are
> > > > > > delayed by channel number x counter range / 16, which avoids 
> > > > > > asserting
> > > > > > all enabled outputs at the same counter value while still 
> > > > > > maintaining
> > > > > > the configured duty cycle of each output.
> > > > > > 
> > > > > > Signed-off-by: Clemens Gruber 
> > > > > 
> > > > > Is there a reason to not want this staggered output? If it never 
> > > > > hurts I
> > > > > suggest to always stagger and drop the dt property.
> > > > 
> > > > There might be applications where you want multiple outputs to assert at
> > > > the same time / to be synchronized.
> > > > With staggered outputs mode always enabled, this would no longer be
> > > > possible as they are spread out according to their channel number.
> > > > 
> > > > Not sure how often that usecase is required, but just enforcing the
> > > > staggered mode by default sounds risky to me.
> > > 
> > > There is no such guarantee in the PWM framework, so I don't think we
> > > need to fear breaking setups. Thierry?
> > 
> > Still, someone might rely on it? But let's wait for Thierry's opinion.
> 
> There's currently no way to synchronize two PWM channels in the PWM
> framework. And given that each PWM channel is handled separately the
> programming for two channels will never happen atomically or even
> concurrently, so I don't see how you could run two PWMs completely
> synchronized to one another.

As the PCA9685 has only one prescaler and one counter per chip, by
default, all PWMs enabled will go high at the same time. If they also
have the same duty cycle configured, they also go low at the same time.

> Or did I misunderstand and it's only the start time of the rising edge
> that's shifted, but the signal will remain high for a full duty cycle
> after that and then go down and remain low for period - duty - offset?

Yes, that's how it works.

> 
> That's slightly better than the above in that it likely won't trip up
> any consumers. But it might still be worth to make this configurable per
> PWM (perhaps by specifying a third specifier cell, in addition to the
> period and flags, that defines the offset/phase of the signal).
> 
> In both cases, doing this on a per-PWM basis will allow the consumer to
> specify that they're okay with staggered mode and you won't actually
> force it onto anyone. This effectively makes this opt-in and there will
> be no change for existing consumers.

I agree that it should be opt-in, but I am not sure about doing it
per-pwm:
The reason why you'd want staggered mode is to reduce EMI or current
spikes and it is most effective if it is enabled for all PWMs.

If it is specified in the DT anyway and you have a consumer that does
not support staggered mode (probably rare but can happen), then I'd
suggest just disabling it globally by not specifying nxp,staggered-mode;

Also it would make the configuration more complicated: You have to do
the "staggering" yourself and assign offsets per channel.
It's certainly easier to just enable or disable it.

What do you think?

> > > One reason we might not want staggering is if we have a consumer who
> > > cares about config transitions. (This however is moot it the hardware
> > > doesn't provide sane transitions even without staggering.)
> > > 
> > > Did I already ask about races in this driver? I assume there is a
> > > free running counter and the ON and OFF registers just define where in
> > > the period the transitions happen, right? Given that changing ON and OFF
> > > needs two register writes probably all kind of strange things can
> > > happen, right? (Example thought: for simplicity's sake I assume ON is
> > > always 0. Then if you want to change from OFF = 0xaaa to OFF = 0xccc we
> > > might see a period with 0xacc

Re: [PATCH v6 4/7] pwm: pca9685: Support staggered output ON times

2021-03-31 Thread Clemens Gruber
On Wed, Mar 31, 2021 at 02:26:14PM +0200, Clemens Gruber wrote:
> On Mon, Mar 29, 2021 at 08:02:06PM +0200, Uwe Kleine-König wrote:
> > On Mon, Mar 29, 2021 at 07:16:38PM +0200, Clemens Gruber wrote:
> > > On Mon, Mar 29, 2021 at 07:03:57PM +0200, Uwe Kleine-König wrote:
> > > > On Mon, Mar 29, 2021 at 02:57:04PM +0200, Clemens Gruber wrote:
> > > > > The PCA9685 supports staggered LED output ON times to minimize current
> > > > > surges and reduce EMI.
> > > > > When this new option is enabled, the ON times of each channel are
> > > > > delayed by channel number x counter range / 16, which avoids asserting
> > > > > all enabled outputs at the same counter value while still maintaining
> > > > > the configured duty cycle of each output.
> > > > > 
> > > > > Signed-off-by: Clemens Gruber 
> > > > 
> > > > Is there a reason to not want this staggered output? If it never hurts I
> > > > suggest to always stagger and drop the dt property.
> > > 
> > > There might be applications where you want multiple outputs to assert at
> > > the same time / to be synchronized.
> > > With staggered outputs mode always enabled, this would no longer be
> > > possible as they are spread out according to their channel number.
> > > 
> > > Not sure how often that usecase is required, but just enforcing the
> > > staggered mode by default sounds risky to me.
> > 
> > There is no such guarantee in the PWM framework, so I don't think we
> > need to fear breaking setups. Thierry?
> 
> Still, someone might rely on it? But let's wait for Thierry's opinion.
> 
> > 
> > One reason we might not want staggering is if we have a consumer who
> > cares about config transitions. (This however is moot it the hardware
> > doesn't provide sane transitions even without staggering.)
> > 
> > Did I already ask about races in this driver? I assume there is a
> > free running counter and the ON and OFF registers just define where in
> > the period the transitions happen, right? Given that changing ON and OFF
> > needs two register writes probably all kind of strange things can
> > happen, right? (Example thought: for simplicity's sake I assume ON is
> > always 0. Then if you want to change from OFF = 0xaaa to OFF = 0xccc we
> > might see a period with 0xacc. Depending on how the hardware works we
> > might even see 4 edges in a single period then.)
> 
> Yes, there is a free running counter from 0 to 4095.
> And it is probably true, that there can be short intermediate states
> with our two register writes.
> 
> There is a separate mode "Update on ACK" (MODE2 register, bit 3 "OCH"),
> which is 0 by default (Outputs change on STOP command) but could be set
> to 1 (Outputs change on ACK):
> "Update on ACK requires all 4 PWM channel registers to be loaded before
> outputs will change on the last ACK."

This would require the auto-increment feature to be enabled, then
multiple registers could be written before the STOP condition:
LEDn_ON_L, LEDn_ON_H, LEDn_OFF_L & LEDn_OFF_H
(With OCH=0 in MODE2)

But I think this should be done in a separate improvement patch/series
to reduce glitches.

> The chip datasheet also states:
> "Because the loading of the LEDn_ON and LEDn_OFF registers is via the
> I2C-bus, and asynchronous to the internal oscillator, we want to ensure
> that we do not see any visual artifacts of changing the ON and OFF
> values. This is achieved by updating the changes at the end of the LOW
> cycle."
> 
> We could look into this in a future patch series, however I would like
> to keep the register updating as-is for this series (otherwise I would
> have to do all the tests with the oscilloscope again and the transitions
> were like this since the driver was first implemented).
> 
> Thanks,
> Clemens


Re: [PATCH v6 4/7] pwm: pca9685: Support staggered output ON times

2021-03-31 Thread Clemens Gruber
On Mon, Mar 29, 2021 at 08:02:06PM +0200, Uwe Kleine-König wrote:
> On Mon, Mar 29, 2021 at 07:16:38PM +0200, Clemens Gruber wrote:
> > On Mon, Mar 29, 2021 at 07:03:57PM +0200, Uwe Kleine-König wrote:
> > > On Mon, Mar 29, 2021 at 02:57:04PM +0200, Clemens Gruber wrote:
> > > > The PCA9685 supports staggered LED output ON times to minimize current
> > > > surges and reduce EMI.
> > > > When this new option is enabled, the ON times of each channel are
> > > > delayed by channel number x counter range / 16, which avoids asserting
> > > > all enabled outputs at the same counter value while still maintaining
> > > > the configured duty cycle of each output.
> > > > 
> > > > Signed-off-by: Clemens Gruber 
> > > 
> > > Is there a reason to not want this staggered output? If it never hurts I
> > > suggest to always stagger and drop the dt property.
> > 
> > There might be applications where you want multiple outputs to assert at
> > the same time / to be synchronized.
> > With staggered outputs mode always enabled, this would no longer be
> > possible as they are spread out according to their channel number.
> > 
> > Not sure how often that usecase is required, but just enforcing the
> > staggered mode by default sounds risky to me.
> 
> There is no such guarantee in the PWM framework, so I don't think we
> need to fear breaking setups. Thierry?

Still, someone might rely on it? But let's wait for Thierry's opinion.

> 
> One reason we might not want staggering is if we have a consumer who
> cares about config transitions. (This however is moot it the hardware
> doesn't provide sane transitions even without staggering.)
> 
> Did I already ask about races in this driver? I assume there is a
> free running counter and the ON and OFF registers just define where in
> the period the transitions happen, right? Given that changing ON and OFF
> needs two register writes probably all kind of strange things can
> happen, right? (Example thought: for simplicity's sake I assume ON is
> always 0. Then if you want to change from OFF = 0xaaa to OFF = 0xccc we
> might see a period with 0xacc. Depending on how the hardware works we
> might even see 4 edges in a single period then.)

Yes, there is a free running counter from 0 to 4095.
And it is probably true, that there can be short intermediate states
with our two register writes.

There is a separate mode "Update on ACK" (MODE2 register, bit 3 "OCH"),
which is 0 by default (Outputs change on STOP command) but could be set
to 1 (Outputs change on ACK):
"Update on ACK requires all 4 PWM channel registers to be loaded before
outputs will change on the last ACK."

The chip datasheet also states:
"Because the loading of the LEDn_ON and LEDn_OFF registers is via the
I2C-bus, and asynchronous to the internal oscillator, we want to ensure
that we do not see any visual artifacts of changing the ON and OFF
values. This is achieved by updating the changes at the end of the LOW
cycle."

We could look into this in a future patch series, however I would like
to keep the register updating as-is for this series (otherwise I would
have to do all the tests with the oscilloscope again and the transitions
were like this since the driver was first implemented).

Thanks,
Clemens


Re: [PATCH v6 6/7] pwm: pca9685: Restrict period change for prescaler users

2021-03-29 Thread Clemens Gruber
On Mon, Mar 29, 2021 at 07:15:59PM +0200, Uwe Kleine-König wrote:
> On Mon, Mar 29, 2021 at 02:57:06PM +0200, Clemens Gruber wrote:
> > @@ -330,14 +345,22 @@ static int pca9685_pwm_apply(struct pwm_chip *chip, 
> > struct pwm_device *pwm,
> >  
> > if (!state->enabled || duty < 1) {
> > pca9685_pwm_set_duty(pca, pwm->hwpwm, 0);
> > +   clear_bit(pwm->hwpwm, pca->prescaler_users);
> 
> Hmm, so if "my" channel runs at say
> 
>   .duty_cycle = 2539520 ns
>   .period = 5079040 ns
> 
> and I call pwm_apply_state(mypwm, { .duty_cycle = 0, .period = 5079040,
> enabled = true }); it might happen that another channel modifies the
> period and I won't be able to return to the initial setting.

Yes, that's correct.

But that also applies to PWMs set to 100%:

pwm_apply_state(mypwm, { .duty_cycle = 5079040, .period = 5079040,
enabled = true });

As this sets the full ON bit and does not use the prescaler, with the
current code, another channel could modify the period and you wouldn't
be able to return to the initial setting of 50%.

> 
> So I think it's sensible to only clear the user bit if the PWM is
> disabled, but not if it is configured for duty_cycle = 0.
> 
> Does this make sense?

With both cases in mind, you are suggesting we block modifications of
the prescaler if other PWMs are enabled and not if other PWMs are using
the prescaler?

Clemens


Re: [PATCH v6 4/7] pwm: pca9685: Support staggered output ON times

2021-03-29 Thread Clemens Gruber
On Mon, Mar 29, 2021 at 07:03:57PM +0200, Uwe Kleine-König wrote:
> On Mon, Mar 29, 2021 at 02:57:04PM +0200, Clemens Gruber wrote:
> > The PCA9685 supports staggered LED output ON times to minimize current
> > surges and reduce EMI.
> > When this new option is enabled, the ON times of each channel are
> > delayed by channel number x counter range / 16, which avoids asserting
> > all enabled outputs at the same counter value while still maintaining
> > the configured duty cycle of each output.
> > 
> > Signed-off-by: Clemens Gruber 
> 
> Is there a reason to not want this staggered output? If it never hurts I
> suggest to always stagger and drop the dt property.

There might be applications where you want multiple outputs to assert at
the same time / to be synchronized.
With staggered outputs mode always enabled, this would no longer be
possible as they are spread out according to their channel number.

Not sure how often that usecase is required, but just enforcing the
staggered mode by default sounds risky to me.

Thanks,
Clemens


Re: [PATCH v6 2/7] pwm: pca9685: Support hardware readout

2021-03-29 Thread Clemens Gruber
On Mon, Mar 29, 2021 at 06:54:29PM +0200, Uwe Kleine-König wrote:
> On Mon, Mar 29, 2021 at 02:57:02PM +0200, Clemens Gruber wrote:
> > Implements .get_state to read-out the current hardware state.
> > 
> > The hardware readout may return slightly different values than those
> > that were set in apply due to the limited range of possible prescale and
> > counter register values.
> > 
> > Also note that although the datasheet mentions 200 Hz as default
> > frequency when using the internal 25 MHz oscillator, the calculated
> > period from the default prescaler register setting of 30 is 5079040ns.
> > 
> > Signed-off-by: Clemens Gruber 
> > ---
> >  drivers/pwm/pwm-pca9685.c | 41 +++
> >  1 file changed, 41 insertions(+)
> > 
> > diff --git a/drivers/pwm/pwm-pca9685.c b/drivers/pwm/pwm-pca9685.c
> > index 0ed1013737e3..fb026a25fb61 100644
> > --- a/drivers/pwm/pwm-pca9685.c
> > +++ b/drivers/pwm/pwm-pca9685.c
> > @@ -333,6 +333,46 @@ static int pca9685_pwm_apply(struct pwm_chip *chip, 
> > struct pwm_device *pwm,
> > return 0;
> >  }
> >  
> > +static void pca9685_pwm_get_state(struct pwm_chip *chip, struct pwm_device 
> > *pwm,
> > + struct pwm_state *state)
> > +{
> > +   struct pca9685 *pca = to_pca(chip);
> > +   unsigned long long duty;
> > +   unsigned int val = 0;
> > +
> > +   /* Calculate (chip-wide) period from prescale value */
> > +   regmap_read(pca->regmap, PCA9685_PRESCALE, );
> > +   state->period = (PCA9685_COUNTER_RANGE * 1000 / PCA9685_OSC_CLOCK_MHZ) *
> > +   (val + 1);
> 
> As we have PCA9685_OSC_CLOCK_MHZ = 25 this is an integer calculation
> without loss of precision. It might be worth to point that out in a
> comment. (Otherwise doing the division at the end might be more
> sensible.)

What comment do you have in mind?
/* 1 integer multiplication (without loss of precision) at runtime */ ?

> 
> > +   /* The (per-channel) polarity is fixed */
> > +   state->polarity = PWM_POLARITY_NORMAL;
> > +
> > +   if (pwm->hwpwm >= PCA9685_MAXCHAN) {
> > +   /*
> > +* The "all LEDs" channel does not support HW readout
> > +* Return 0 and disabled for backwards compatibility
> > +*/
> > +   state->duty_cycle = 0;
> > +   state->enabled = false;
> > +   return;
> > +   }
> > +
> > +   duty = pca9685_pwm_get_duty(pca, pwm->hwpwm);
> > +
> > +   state->enabled = !!duty;
> > +   if (!state->enabled) {
> > +   state->duty_cycle = 0;
> > +   return;
> > +   } else if (duty == PCA9685_COUNTER_RANGE) {
> > +   state->duty_cycle = state->period;
> > +   return;
> > +   }
> > +
> > +   duty *= state->period;
> > +   state->duty_cycle = duty / PCA9685_COUNTER_RANGE;
> 
> .apply uses ROUND_CLOSEST to calculate duty from state->duty_cycle,
> still using / here (instead of ROUND_CLOSEST), but again as
> PCA9685_OSC_CLOCK_MHZ is 25 this calculation doesn't suffer from
> rounding errors. So if you feed the state returned here into .apply
> again, there is (as I want it) no change.
> 
> The only annoyance is that if PCA9685_PRESCALE holds a value smaller
> than 3, .apply() will fail. Not sure there is any saner way to handle
> this.

According to the datasheet, "The hardware forces a minimum value that
can be loaded into the PRE_SCALE register at '3'", so there should never
be anything below 3 in that register.

Thanks for your review!

Clemens


Re: [PATCH v6 2/7] pwm: pca9685: Support hardware readout

2021-03-29 Thread Clemens Gruber
Hi Uwe,

On Mon, Mar 29, 2021 at 05:51:40PM +0200, Uwe Kleine-König wrote:
> Hello Clemens,
> 
> On Mon, Mar 29, 2021 at 02:57:02PM +0200, Clemens Gruber wrote:
> > The hardware readout may return slightly different values than those
> > that were set in apply due to the limited range of possible prescale and
> > counter register values.
> 
> This is fine and for most hardware that's not preventable. My
> requirement here is that 
> 
>   .get_state(pwm, );
>   .apply_state(pwm, );
> 
> doesn't yield any changes.

Yes, that would not change anything.

Thanks,
Clemens


Re: [PATCH v6 3/7] pwm: pca9685: Improve runtime PM behavior

2021-03-29 Thread Clemens Gruber
Hi Uwe,

On Mon, Mar 29, 2021 at 05:55:27PM +0200, Uwe Kleine-König wrote:
> On Mon, Mar 29, 2021 at 02:57:03PM +0200, Clemens Gruber wrote:
> > The chip does not come out of POR in active state but in sleep state.
> > To be sure (in case the bootloader woke it up) we force it to sleep in
> > probe.
> > 
> > On kernels without CONFIG_PM, we wake the chip in .probe and put it to
> > sleep in .remove.
> 
> What is the effect of sleep state? Does it continue to oscilate it the
> bootloader set up some configuration?

The datasheet says: "When the oscillator is off (Sleep mode) the LEDn
outputs cannot be turned on, off or dimmed/blinked."

At the moment, we reset the output registers anyway, so everything is
turned off at probe time, even if the bootloader did set something up.

When removing the resets in the future, I would read out the state of
the SLEEP bit at probe time and set the pm runtime state accordingly.

> 
> 
> > Signed-off-by: Clemens Gruber 
> > ---
> >  drivers/pwm/pwm-pca9685.c | 20 
> >  1 file changed, 16 insertions(+), 4 deletions(-)
> > 
> > diff --git a/drivers/pwm/pwm-pca9685.c b/drivers/pwm/pwm-pca9685.c
> > index fb026a25fb61..4d6684b90819 100644
> > --- a/drivers/pwm/pwm-pca9685.c
> > +++ b/drivers/pwm/pwm-pca9685.c
> > @@ -469,14 +469,19 @@ static int pca9685_pwm_probe(struct i2c_client 
> > *client,
> > return ret;
> > }
> >  
> > -   /* The chip comes out of power-up in the active state */
> > -   pm_runtime_set_active(>dev);
> > /*
> > -* Enable will put the chip into suspend, which is what we
> > -* want as all outputs are disabled at this point
> > +* The chip comes out of power-up in the sleep state,
> > +* but force it to sleep in case it was woken up before
> >  */
> > +   pca9685_set_sleep_mode(pca, true);
> > +   pm_runtime_set_suspended(>dev);
> > pm_runtime_enable(>dev);
> >  
> > +   if (!IS_ENABLED(CONFIG_PM)) {
> > +   /* Wake the chip up on non-PM environments */
> > +   pca9685_set_sleep_mode(pca, false);
> 
> I admit I didn't grasp all the PM framework details, but I wonder if
> it's right to first call set_sleep_mode(true) and then in some cases to
> false again.

That was done for readability reasons, however, I admit that after we no
longer reset the period (deemed not necessary by me due to the planned
removal of the resets) it would probably be as readable to have:

if (IS_ENABLED(CONFIG_PM)) {
pca9685_set_sleep_mode(pca, true);
pm_runtime_set_suspended..
pm_runtime_enable..
} else
pca9685_set_sleep_mode(pca, false);

Thanks,
Clemens


[PATCH v6 6/7] pwm: pca9685: Restrict period change for prescaler users

2021-03-29 Thread Clemens Gruber
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 user of the prescaler 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.

PWMs that are disabled or have a duty cycle of 0% or 100% are not
considered to be using the prescaler as they have the full OFF or full
ON bits set. This also applies to channels used as GPIOs.

Signed-off-by: Clemens Gruber 
---
Changes since v5:
- Reused the existing lock
- Improved readability of can_change function
- Moved locking out of apply function
- Improved error messages

drivers/pwm/pwm-pca9685.c | 63 ---
 1 file changed, 53 insertions(+), 10 deletions(-)

diff --git a/drivers/pwm/pwm-pca9685.c b/drivers/pwm/pwm-pca9685.c
index a61eafdd2335..418d3c5b2fa2 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 uses the prescaler 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, unless they
+ * use duty cycles of 0% or 100% (prescaler not used for full OFF/ON).
  */
 
 #define PCA9685_MODE1  0x00
@@ -79,8 +79,9 @@ struct pca9685 {
struct pwm_chip chip;
struct regmap *regmap;
bool staggered_outputs;
-#if IS_ENABLED(CONFIG_GPIOLIB)
struct mutex lock;
+   DECLARE_BITMAP(prescaler_users, PCA9685_MAXCHAN + 1);
+#if IS_ENABLED(CONFIG_GPIOLIB)
struct gpio_chip gpio;
DECLARE_BITMAP(pwms_inuse, PCA9685_MAXCHAN + 1);
 #endif
@@ -91,6 +92,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)
+{
+   /* Prescaler not in use: Change allowed */
+   if (bitmap_empty(pca->prescaler_users, PCA9685_MAXCHAN + 1))
+   return true;
+   /* More than one PWM using the prescaler: Change not allowed */
+   if (bitmap_weight(pca->prescaler_users, PCA9685_MAXCHAN + 1) > 1)
+   return false;
+   /*
+* Only one PWM using the prescaler: Change allowed if the PWM about to
+* be changed is the one using the prescaler
+*/
+   return test_bit(channel, pca->prescaler_users);
+}
+
 /* Helper function to set the duty cycle ratio to duty/4096 (e.g. duty=2048 -> 
50%) */
 static void pca9685_pwm_set_duty(struct pca9685 *pca, int channel, unsigned 
int duty)
 {
@@ -263,8 +280,6 @@ static int pca9685_pwm_gpio_probe(struct pca9685 *pca)
 {
struct device *dev = pca->chip.dev;
 
-   mutex_init(>lock);
-
pca->gpio.label = dev_name(dev);
pca->gpio.parent = dev;
pca->gpio.request = pca9685_pwm_gpio_request;
@@ -308,8 +323,8 @@ static void pca9685_set_sleep_mode(struct pca9685 *pca, 
bool enable)
}
 }
 
-static int pca9685_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
-const struct pwm_state *state)
+static int __pca9685_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
+  const struct pwm_state *state)
 {
struct pca9685 *pca = to_pca(chip);
unsigned long long duty, prescale;
@@ -330,14 +345,22 @@ static int pca9685_pwm_apply(struct pwm_chip *chip, 
struct pwm_device *pwm,
 
if (!state->enabled || duty < 1) {
pca9685_pwm_set_duty(pca, pwm->hwpwm, 0);
+   clear_bit(pwm->hwpwm, pca->prescaler_users);
return 0;
} else if (duty == PCA9685_COUNTER_RANGE) {
pca9685_pwm_set_duty(pca, pwm->hwpwm, duty);
+   clear_bit(pwm->hwpwm, pca->prescaler_users);
return 0;
}
 
regmap_read(pca->regmap, PCA9685_PRESCALE, );
if (prescale != val) {
+   if (!pca9685_prescaler_can_change(pca, pwm->hwpwm)) {
+   dev_err(chip->dev,
+   "pwm not changed: prescaler in use with 
different setting!\n");
+   return -EBUSY;
+   }
+
/*
 * Putting the chip briefly into SLEEP mode
 * at this point won't interfere w

[PATCH v6 5/7] dt-bindings: pwm: pca9685: Add nxp,staggered-outputs property

2021-03-29 Thread Clemens Gruber
The pca9685 driver supports a new nxp,staggered-outputs property for
reduced current surges and EMI. This adds documentation for the new DT
property.

Signed-off-by: Clemens Gruber 
---
 Documentation/devicetree/bindings/pwm/nxp,pca9685-pwm.txt | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/Documentation/devicetree/bindings/pwm/nxp,pca9685-pwm.txt 
b/Documentation/devicetree/bindings/pwm/nxp,pca9685-pwm.txt
index f21b55c95738..fafe954369dc 100644
--- a/Documentation/devicetree/bindings/pwm/nxp,pca9685-pwm.txt
+++ b/Documentation/devicetree/bindings/pwm/nxp,pca9685-pwm.txt
@@ -12,6 +12,8 @@ Optional properties:
   - invert (bool): boolean to enable inverted logic
   - open-drain (bool): boolean to configure outputs with open-drain structure;
   if omitted use totem-pole structure
+  - nxp,staggered-outputs (bool): boolean to enable staggered output ON times 
to
+ minimize current surges and EMI
 
 Example:
 
-- 
2.31.1



[PATCH v6 4/7] pwm: pca9685: Support staggered output ON times

2021-03-29 Thread Clemens Gruber
The PCA9685 supports staggered LED output ON times to minimize current
surges and reduce EMI.
When this new option is enabled, the ON times of each channel are
delayed by channel number x counter range / 16, which avoids asserting
all enabled outputs at the same counter value while still maintaining
the configured duty cycle of each output.

Signed-off-by: Clemens Gruber 
---
Changes since v5:
- Simplified staggered outputs special case in set/get_duty

drivers/pwm/pwm-pca9685.c | 58 +--
 1 file changed, 44 insertions(+), 14 deletions(-)

diff --git a/drivers/pwm/pwm-pca9685.c b/drivers/pwm/pwm-pca9685.c
index 4d6684b90819..a61eafdd2335 100644
--- a/drivers/pwm/pwm-pca9685.c
+++ b/drivers/pwm/pwm-pca9685.c
@@ -78,6 +78,7 @@
 struct pca9685 {
struct pwm_chip chip;
struct regmap *regmap;
+   bool staggered_outputs;
 #if IS_ENABLED(CONFIG_GPIOLIB)
struct mutex lock;
struct gpio_chip gpio;
@@ -93,46 +94,70 @@ static inline struct pca9685 *to_pca(struct pwm_chip *chip)
 /* Helper function to set the duty cycle ratio to duty/4096 (e.g. duty=2048 -> 
50%) */
 static void pca9685_pwm_set_duty(struct pca9685 *pca, int channel, unsigned 
int duty)
 {
+   unsigned int on, off;
+
if (duty == 0) {
/* Set the full OFF bit, which has the highest precedence */
regmap_write(pca->regmap, REG_OFF_H(channel), LED_FULL);
+   return;
} else if (duty >= PCA9685_COUNTER_RANGE) {
/* Set the full ON bit and clear the full OFF bit */
regmap_write(pca->regmap, REG_ON_H(channel), LED_FULL);
regmap_write(pca->regmap, REG_OFF_H(channel), 0);
-   } else {
-   /* Set OFF time (clears the full OFF bit) */
-   regmap_write(pca->regmap, REG_OFF_L(channel), duty & 0xff);
-   regmap_write(pca->regmap, REG_OFF_H(channel), (duty >> 8) & 
0xf);
-   /* Clear the full ON bit */
-   regmap_write(pca->regmap, REG_ON_H(channel), 0);
+   return;
}
+
+   if (pca->staggered_outputs && channel < PCA9685_MAXCHAN) {
+   /*
+* To reduce EMI, the ON times of each channel are
+* spread out evenly within the counter range, while
+* still maintaining the configured duty cycle
+*/
+   on = channel * PCA9685_COUNTER_RANGE / PCA9685_MAXCHAN;
+   } else
+   on = 0;
+
+   off = (on + duty) % PCA9685_COUNTER_RANGE;
+
+   /* Set ON time (clears full ON bit) */
+   regmap_write(pca->regmap, REG_ON_L(channel), on & 0xff);
+   regmap_write(pca->regmap, REG_ON_H(channel), (on >> 8) & 0xf);
+   /* Set OFF time (clears full OFF bit) */
+   regmap_write(pca->regmap, REG_OFF_L(channel), off & 0xff);
+   regmap_write(pca->regmap, REG_OFF_H(channel), (off >> 8) & 0xf);
 }
 
 static unsigned int pca9685_pwm_get_duty(struct pca9685 *pca, int channel)
 {
-   unsigned int off_h = 0, val = 0;
+   unsigned int off = 0, on = 0, val = 0;
 
if (WARN_ON(channel >= PCA9685_MAXCHAN)) {
/* HW does not support reading state of "all LEDs" channel */
return 0;
}
 
-   regmap_read(pca->regmap, LED_N_OFF_H(channel), _h);
-   if (off_h & LED_FULL) {
+   regmap_read(pca->regmap, LED_N_OFF_H(channel), );
+   if (off & LED_FULL) {
/* Full OFF bit is set */
return 0;
}
 
-   regmap_read(pca->regmap, LED_N_ON_H(channel), );
-   if (val & LED_FULL) {
+   regmap_read(pca->regmap, LED_N_ON_H(channel), );
+   if (on & LED_FULL) {
/* Full ON bit is set */
return PCA9685_COUNTER_RANGE;
}
 
-   val = 0;
regmap_read(pca->regmap, LED_N_OFF_L(channel), );
-   return ((off_h & 0xf) << 8) | (val & 0xff);
+   off = ((off & 0xf) << 8) | (val & 0xff);
+   if (!pca->staggered_outputs)
+   return off;
+
+   /* Read ON register to calculate duty cycle of staggered output */
+   val = 0;
+   regmap_read(pca->regmap, LED_N_ON_L(channel), );
+   on = ((on & 0xf) << 8) | (val & 0xff);
+   return (off - on) & (PCA9685_COUNTER_RANGE - 1);
 }
 
 #if IS_ENABLED(CONFIG_GPIOLIB)
@@ -443,14 +468,19 @@ static int pca9685_pwm_probe(struct i2c_client *client,
 
regmap_write(pca->regmap, PCA9685_MODE2, reg);
 
+   pca->staggered_outputs = device_property_read_bool(
+   >dev, "nxp,staggered-outputs");
+
/* Disable all LED ALLCALL and SUBx addresses to avoid bus collisions */
regmap_read(pca->regmap, PCA9685_MODE1, );
reg &= ~(MODE1_ALLCALL | MODE1_SUB1 | MO

[PATCH v6 7/7] pwm: pca9685: Add error messages for failed regmap calls

2021-03-29 Thread Clemens Gruber
Regmap operations can fail if the underlying subsystem is not working
properly (e.g. hogged I2C bus, etc.)
As this is useful information for the user, print an error message if it
happens.
Let probe fail if the first regmap_read or the first regmap_write fails.

Signed-off-by: Clemens Gruber 
---
 drivers/pwm/pwm-pca9685.c | 83 ---
 1 file changed, 59 insertions(+), 24 deletions(-)

diff --git a/drivers/pwm/pwm-pca9685.c b/drivers/pwm/pwm-pca9685.c
index 418d3c5b2fa2..065141b87fc3 100644
--- a/drivers/pwm/pwm-pca9685.c
+++ b/drivers/pwm/pwm-pca9685.c
@@ -108,6 +108,30 @@ static bool pca9685_prescaler_can_change(struct pca9685 
*pca, int channel)
return test_bit(channel, pca->prescaler_users);
 }
 
+static int pca9685_read_reg(struct pca9685 *pca, unsigned int reg, unsigned 
int *val)
+{
+   struct device *dev = pca->chip.dev;
+   int err;
+
+   err = regmap_read(pca->regmap, reg, val);
+   if (err != 0)
+   dev_err(dev, "regmap_read of register 0x%x failed: %d\n", reg, 
err);
+
+   return err;
+}
+
+static int pca9685_write_reg(struct pca9685 *pca, unsigned int reg, unsigned 
int val)
+{
+   struct device *dev = pca->chip.dev;
+   int err;
+
+   err = regmap_write(pca->regmap, reg, val);
+   if (err != 0)
+   dev_err(dev, "regmap_write to register 0x%x failed: %d\n", reg, 
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 pca9685 *pca, int channel, unsigned 
int duty)
 {
@@ -115,12 +139,12 @@ static void pca9685_pwm_set_duty(struct pca9685 *pca, int 
channel, unsigned int
 
if (duty == 0) {
/* Set the full OFF bit, which has the highest precedence */
-   regmap_write(pca->regmap, REG_OFF_H(channel), LED_FULL);
+   pca9685_write_reg(pca, REG_OFF_H(channel), LED_FULL);
return;
} else if (duty >= PCA9685_COUNTER_RANGE) {
/* Set the full ON bit and clear the full OFF bit */
-   regmap_write(pca->regmap, REG_ON_H(channel), LED_FULL);
-   regmap_write(pca->regmap, REG_OFF_H(channel), 0);
+   pca9685_write_reg(pca, REG_ON_H(channel), LED_FULL);
+   pca9685_write_reg(pca, REG_OFF_H(channel), 0);
return;
}
 
@@ -137,11 +161,11 @@ static void pca9685_pwm_set_duty(struct pca9685 *pca, int 
channel, unsigned int
off = (on + duty) % PCA9685_COUNTER_RANGE;
 
/* Set ON time (clears full ON bit) */
-   regmap_write(pca->regmap, REG_ON_L(channel), on & 0xff);
-   regmap_write(pca->regmap, REG_ON_H(channel), (on >> 8) & 0xf);
+   pca9685_write_reg(pca, REG_ON_L(channel), on & 0xff);
+   pca9685_write_reg(pca, REG_ON_H(channel), (on >> 8) & 0xf);
/* Set OFF time (clears full OFF bit) */
-   regmap_write(pca->regmap, REG_OFF_L(channel), off & 0xff);
-   regmap_write(pca->regmap, REG_OFF_H(channel), (off >> 8) & 0xf);
+   pca9685_write_reg(pca, REG_OFF_L(channel), off & 0xff);
+   pca9685_write_reg(pca, REG_OFF_H(channel), (off >> 8) & 0xf);
 }
 
 static unsigned int pca9685_pwm_get_duty(struct pca9685 *pca, int channel)
@@ -153,26 +177,26 @@ static unsigned int pca9685_pwm_get_duty(struct pca9685 
*pca, int channel)
return 0;
}
 
-   regmap_read(pca->regmap, LED_N_OFF_H(channel), );
+   pca9685_read_reg(pca, LED_N_OFF_H(channel), );
if (off & LED_FULL) {
/* Full OFF bit is set */
return 0;
}
 
-   regmap_read(pca->regmap, LED_N_ON_H(channel), );
+   pca9685_read_reg(pca, LED_N_ON_H(channel), );
if (on & LED_FULL) {
/* Full ON bit is set */
return PCA9685_COUNTER_RANGE;
}
 
-   regmap_read(pca->regmap, LED_N_OFF_L(channel), );
+   pca9685_read_reg(pca, LED_N_OFF_L(channel), );
off = ((off & 0xf) << 8) | (val & 0xff);
if (!pca->staggered_outputs)
return off;
 
/* Read ON register to calculate duty cycle of staggered output */
val = 0;
-   regmap_read(pca->regmap, LED_N_ON_L(channel), );
+   pca9685_read_reg(pca, LED_N_ON_L(channel), );
on = ((on & 0xf) << 8) | (val & 0xff);
return (off - on) & (PCA9685_COUNTER_RANGE - 1);
 }
@@ -315,8 +339,15 @@ static inline int pca9685_pwm_gpio_probe(struct pca9685 
*pca)
 
 static void pca9685_set_sleep_mode(struct pca9685 *pca, bool enable)
 {
-   regmap_update_bits(pca->regmap, PCA9685_MODE1,
-  MODE1_SLEEP, enable ? MODE1_SLEEP : 0);
+   struct device *dev = pca->chip.dev;
+   int err = regmap_update_bits(pca->regmap, PCA9685_MODE

[PATCH v6 3/7] pwm: pca9685: Improve runtime PM behavior

2021-03-29 Thread Clemens Gruber
The chip does not come out of POR in active state but in sleep state.
To be sure (in case the bootloader woke it up) we force it to sleep in
probe.

On kernels without CONFIG_PM, we wake the chip in .probe and put it to
sleep in .remove.

Signed-off-by: Clemens Gruber 
---
 drivers/pwm/pwm-pca9685.c | 20 
 1 file changed, 16 insertions(+), 4 deletions(-)

diff --git a/drivers/pwm/pwm-pca9685.c b/drivers/pwm/pwm-pca9685.c
index fb026a25fb61..4d6684b90819 100644
--- a/drivers/pwm/pwm-pca9685.c
+++ b/drivers/pwm/pwm-pca9685.c
@@ -469,14 +469,19 @@ static int pca9685_pwm_probe(struct i2c_client *client,
return ret;
}
 
-   /* The chip comes out of power-up in the active state */
-   pm_runtime_set_active(>dev);
/*
-* Enable will put the chip into suspend, which is what we
-* want as all outputs are disabled at this point
+* The chip comes out of power-up in the sleep state,
+* but force it to sleep in case it was woken up before
 */
+   pca9685_set_sleep_mode(pca, true);
+   pm_runtime_set_suspended(>dev);
pm_runtime_enable(>dev);
 
+   if (!IS_ENABLED(CONFIG_PM)) {
+   /* Wake the chip up on non-PM environments */
+   pca9685_set_sleep_mode(pca, false);
+   }
+
return 0;
 }
 
@@ -488,7 +493,14 @@ static int pca9685_pwm_remove(struct i2c_client *client)
ret = pwmchip_remove(>chip);
if (ret)
return ret;
+
pm_runtime_disable(>dev);
+
+   if (!IS_ENABLED(CONFIG_PM)) {
+   /* Put chip in sleep state on non-PM environments */
+   pca9685_set_sleep_mode(pca, true);
+   }
+
return 0;
 }
 
-- 
2.31.1



[PATCH v6 2/7] pwm: pca9685: Support hardware readout

2021-03-29 Thread Clemens Gruber
Implements .get_state to read-out the current hardware state.

The hardware readout may return slightly different values than those
that were set in apply due to the limited range of possible prescale and
counter register values.

Also note that although the datasheet mentions 200 Hz as default
frequency when using the internal 25 MHz oscillator, the calculated
period from the default prescaler register setting of 30 is 5079040ns.

Signed-off-by: Clemens Gruber 
---
 drivers/pwm/pwm-pca9685.c | 41 +++
 1 file changed, 41 insertions(+)

diff --git a/drivers/pwm/pwm-pca9685.c b/drivers/pwm/pwm-pca9685.c
index 0ed1013737e3..fb026a25fb61 100644
--- a/drivers/pwm/pwm-pca9685.c
+++ b/drivers/pwm/pwm-pca9685.c
@@ -333,6 +333,46 @@ static int pca9685_pwm_apply(struct pwm_chip *chip, struct 
pwm_device *pwm,
return 0;
 }
 
+static void pca9685_pwm_get_state(struct pwm_chip *chip, struct pwm_device 
*pwm,
+ struct pwm_state *state)
+{
+   struct pca9685 *pca = to_pca(chip);
+   unsigned long long duty;
+   unsigned int val = 0;
+
+   /* Calculate (chip-wide) period from prescale value */
+   regmap_read(pca->regmap, PCA9685_PRESCALE, );
+   state->period = (PCA9685_COUNTER_RANGE * 1000 / PCA9685_OSC_CLOCK_MHZ) *
+   (val + 1);
+
+   /* The (per-channel) polarity is fixed */
+   state->polarity = PWM_POLARITY_NORMAL;
+
+   if (pwm->hwpwm >= PCA9685_MAXCHAN) {
+   /*
+* The "all LEDs" channel does not support HW readout
+* Return 0 and disabled for backwards compatibility
+*/
+   state->duty_cycle = 0;
+   state->enabled = false;
+   return;
+   }
+
+   duty = pca9685_pwm_get_duty(pca, pwm->hwpwm);
+
+   state->enabled = !!duty;
+   if (!state->enabled) {
+   state->duty_cycle = 0;
+   return;
+   } else if (duty == PCA9685_COUNTER_RANGE) {
+   state->duty_cycle = state->period;
+   return;
+   }
+
+   duty *= state->period;
+   state->duty_cycle = duty / PCA9685_COUNTER_RANGE;
+}
+
 static int pca9685_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
 {
struct pca9685 *pca = to_pca(chip);
@@ -355,6 +395,7 @@ static void pca9685_pwm_free(struct pwm_chip *chip, struct 
pwm_device *pwm)
 
 static const struct pwm_ops pca9685_pwm_ops = {
.apply = pca9685_pwm_apply,
+   .get_state = pca9685_pwm_get_state,
.request = pca9685_pwm_request,
.free = pca9685_pwm_free,
.owner = THIS_MODULE,
-- 
2.31.1



[PATCH v6 1/7] pwm: pca9685: Switch to atomic API

2021-03-29 Thread Clemens Gruber
The switch to the atomic API goes hand in hand with a few fixes to
previously experienced issues:
- The duty cycle is no longer lost after disable/enable (previously the
  OFF registers were cleared in disable and the user was required to
  call config to restore the duty cycle settings)
- If one sets a period resulting in the same prescale register value,
  the sleep and write to the register is now skipped

Signed-off-by: Clemens Gruber 
---
Changes since v5:
- Function documentation for set_duty
- Variable initializations
- Print warning if all LEDs channel
- Changed EOPNOTSUPP to EINVAL
- Improved error messages
- Register reset corrections moved to this patch

Changes since v4:
- Patches split up
- Use a single set_duty function
- Improve readability / new macros
- Added a patch to restrict prescale changes to the first user

Changes since v3:
- Refactoring: Extracted common functions
- Read prescale register value instead of caching it
- Return all zeros and disabled for "all LEDs" channel state
- Improved duty calculation / mapping to 0..4096

Changes since v2:
- Always set default prescale value in probe
- Simplified probe code
- Inlined functions with one callsite

Changes since v1:
- Fixed a logic error
- Impoved PM runtime handling and fixed !CONFIG_PM
- Write default prescale reg value if invalid in probe
- Reuse full_off/_on functions throughout driver
- Use cached prescale value whenever possible

 drivers/pwm/pwm-pca9685.c | 261 ++
 1 file changed, 92 insertions(+), 169 deletions(-)

diff --git a/drivers/pwm/pwm-pca9685.c b/drivers/pwm/pwm-pca9685.c
index 4a55dc18656c..0ed1013737e3 100644
--- a/drivers/pwm/pwm-pca9685.c
+++ b/drivers/pwm/pwm-pca9685.c
@@ -51,7 +51,6 @@
 #define PCA9685_PRESCALE_MAX   0xFF/* => min. frequency of 24 Hz */
 
 #define PCA9685_COUNTER_RANGE  4096
-#define PCA9685_DEFAULT_PERIOD 500 /* Default period_ns = 1/200 Hz */
 #define PCA9685_OSC_CLOCK_MHZ  25  /* Internal oscillator with 25 MHz */
 
 #define PCA9685_NUMREGS0xFF
@@ -71,10 +70,14 @@
 #define LED_N_OFF_H(N) (PCA9685_LEDX_OFF_H + (4 * (N)))
 #define LED_N_OFF_L(N) (PCA9685_LEDX_OFF_L + (4 * (N)))
 
+#define REG_ON_H(C)((C) >= PCA9685_MAXCHAN ? PCA9685_ALL_LED_ON_H : 
LED_N_ON_H((C)))
+#define REG_ON_L(C)((C) >= PCA9685_MAXCHAN ? PCA9685_ALL_LED_ON_L : 
LED_N_ON_L((C)))
+#define REG_OFF_H(C)   ((C) >= PCA9685_MAXCHAN ? PCA9685_ALL_LED_OFF_H : 
LED_N_OFF_H((C)))
+#define REG_OFF_L(C)   ((C) >= PCA9685_MAXCHAN ? PCA9685_ALL_LED_OFF_L : 
LED_N_OFF_L((C)))
+
 struct pca9685 {
struct pwm_chip chip;
struct regmap *regmap;
-   int period_ns;
 #if IS_ENABLED(CONFIG_GPIOLIB)
struct mutex lock;
struct gpio_chip gpio;
@@ -87,6 +90,51 @@ static inline struct pca9685 *to_pca(struct pwm_chip *chip)
return container_of(chip, struct pca9685, chip);
 }
 
+/* Helper function to set the duty cycle ratio to duty/4096 (e.g. duty=2048 -> 
50%) */
+static void pca9685_pwm_set_duty(struct pca9685 *pca, int channel, unsigned 
int duty)
+{
+   if (duty == 0) {
+   /* Set the full OFF bit, which has the highest precedence */
+   regmap_write(pca->regmap, REG_OFF_H(channel), LED_FULL);
+   } else if (duty >= PCA9685_COUNTER_RANGE) {
+   /* Set the full ON bit and clear the full OFF bit */
+   regmap_write(pca->regmap, REG_ON_H(channel), LED_FULL);
+   regmap_write(pca->regmap, REG_OFF_H(channel), 0);
+   } else {
+   /* Set OFF time (clears the full OFF bit) */
+   regmap_write(pca->regmap, REG_OFF_L(channel), duty & 0xff);
+   regmap_write(pca->regmap, REG_OFF_H(channel), (duty >> 8) & 
0xf);
+   /* Clear the full ON bit */
+   regmap_write(pca->regmap, REG_ON_H(channel), 0);
+   }
+}
+
+static unsigned int pca9685_pwm_get_duty(struct pca9685 *pca, int channel)
+{
+   unsigned int off_h = 0, val = 0;
+
+   if (WARN_ON(channel >= PCA9685_MAXCHAN)) {
+   /* HW does not support reading state of "all LEDs" channel */
+   return 0;
+   }
+
+   regmap_read(pca->regmap, LED_N_OFF_H(channel), _h);
+   if (off_h & LED_FULL) {
+   /* Full OFF bit is set */
+   return 0;
+   }
+
+   regmap_read(pca->regmap, LED_N_ON_H(channel), );
+   if (val & LED_FULL) {
+   /* Full ON bit is set */
+   return PCA9685_COUNTER_RANGE;
+   }
+
+   val = 0;
+   regmap_read(pca->regmap, LED_N_OFF_L(channel), );
+   return ((off_h & 0xf) << 8) | (val & 0xff);
+}
+
 #if IS_ENABLED(CONFIG_GPIOLIB)
 static bool pca9685_pwm_test_and_set_inuse(struct pca9685 *pca, int pwm_idx)
 {
@@ -138,34 +186,23 @@ static int pca9685_pwm_gpio_request(struct gpio_chip 
*gpio, unsigned int offset)
 

Re: [PATCH v5 2/7] pwm: pca9685: Support hardware readout

2021-03-27 Thread Clemens Gruber
Hi Thierry,

On Mon, Mar 22, 2021 at 10:19:22AM +0100, Thierry Reding wrote:
> On Fri, Jan 29, 2021 at 09:37:47PM +0100, Clemens Gruber wrote:
> > Hi Sven,
> > 
> > On Fri, Jan 29, 2021 at 01:05:14PM -0500, Sven Van Asbroeck wrote:
> > > Hi Clemens,
> > > 
> > > On Fri, Jan 29, 2021 at 11:31 AM Clemens Gruber
> > >  wrote:
> > > >
> > > > Ok, so you suggest we extend our get_state logic to deal with cases
> > > > like the following:
> > > 
> > > Kind of. We can't control how other actors (bootloaders etc) program the
> > > chip. As far as I know, there are many, many different register settings 
> > > that
> > > result in the same physical chip outputs. So if .probe() wants to 
> > > preserve the
> > > existing chip settings, .get_state() has to be able to deal with every 
> > > possible
> > > setting. Even invalid ones.
> > 
> > Is the driver really responsible for bootloaders that program the chip
> > with invalid values?
> > The chip comes out of PoR with sane default values. If the bootloader of
> > a user messes them up, isn't that a bootloader problem instead of a
> > Linux kernel driver problem?
> 
> It is ultimately a problem of the bootloader and where possible the
> bootloader should be fixed. However, fixing bootloaders sometimes isn't
> possible, or impractical, so the kernel has to be able to deal with
> hardware that's been badly programmed by the bootloader. Within reason,
> of course. Sometimes this can't be done in any other way than forcing a
> hard reset of the chip, but it should always be a last resort.
> 
> > > In addition, .apply() cannot make any assumptions as to which bits are
> > > already set/cleared on the chip. Including preserved, invalid settings.
> > > 
> > > This might get quite complex.
> > > 
> > > However if we reset the chip in .probe() to a known state (a normalized 
> > > state,
> > > in the mathematical sense), then both .get_state() and .apply() become
> > > much simpler. because they only need to deal with known, normalized 
> > > states.
> > 
> > Yes, I agree. This would however make it impossible to do a flicker-free
> > transition from bootloader to kernel, but that's not really a usecase I
> > have so I can live without it.
> > 
> > Another point in favor of resetting is that the driver already does it.
> > Removing the reset of the OFF register may break some boards who rely on
> > that behaviour.
> > My version only extended the reset to include the ON register.
> > 
> > > 
> > > In short, it's a tradeoff between code complexity, and user friendliness/
> > > features.
> > > 
> > > Sven
> > 
> > Thierry, Uwe, what's your take on this?
> > 
> > Thierry: Would you accept it if we continue to reset the registers in
> > .probe?
> 
> Yes, I think it's fine to continue to reset the registers since that's
> basically what the driver already does. It'd be great if you could
> follow up with a patch that removes the reset and leaves the hardware in
> whatever state the bootloader has set up. Then we can take that patch
> for a ride and see if there are any complains about it breaking. If
> there are we can always try to fix them, but as a last resort we can
> also revert, which then may be something we have to live with. But I
> think we should at least try to make this consistent with how other
> drivers do this so that people don't stumble over this particular
> driver's behaviour.

Thanks for your input!

Sounds good to me. I am currently preparing a new revision of the
series. As soon as that is reviewed and good to go, I will look into
removing the resets.

Clemens


Re: [PATCH v5 1/7] pwm: pca9685: Switch to atomic API

2021-03-27 Thread Clemens Gruber
Hi Thierry,

On Mon, Mar 22, 2021 at 08:58:35AM +0100, Thierry Reding wrote:
> On Thu, Dec 17, 2020 at 12:10:10PM -0500, Sven Van Asbroeck wrote:
> > On Thu, Dec 17, 2020 at 11:48 AM Clemens Gruber
> >  wrote:
> > >
> > > I can initialize the values to 0 of course and check the file for other
> > > places with missing initializations.
> > >
> > > Or would it be better to check the return codes of regmap_read/write in
> > > such cases? I'm not sure.
> > 
> > I think that checking the regmap_read/write return values is overkill
> > in this driver. These functions can't realistically fail, except if the i2c
> > bus is bad, i.e. h/w failure or intermittency. And that's an externality
> > which I believe we can ignore.
> 
> I think there are (rare) occasions where it's fine to not check for
> errors, i.e. if you definitively know that calls can't fail. However,
> given that this uses regmap and you don't really know what's backing
> this, I think it's always better to err on the side of caution and
> properly check the return values.
> 
> The fact that this can be externally caused is actually a reason why
> we shouldn't be ignoring any errors. If there's a chip that's hogging
> the I2C bus or if you've even just mistyped the I2C client's address
> in DT, it's better if the PWM driver tells you with an error message
> than if it is silently ignoring the errors and keeps you guessing at
> why the PWM isn't behaving the way it should.
> 
> Granted, the error code isn't always going to pinpoint exactly what's
> going wrong, but for serious errors often the I2C bus driver will let
> you know with an extra error message. However, it's much easier to go
> looking for that error message if the PWM driver lets you know that
> something went wrong.
> 
> Please just add full checking of regmap operations.

OK, I will create a separate patch adding these checks in the next
series.

This will lead to > 20 additional dev_err statements, let me know if I
should instead just return the error code and not add dev_err's for
every failed regmap operation.

Clemens


Re: [PATCH v5 2/7] pwm: pca9685: Support hardware readout

2021-03-04 Thread Clemens Gruber
Hi Uwe,

On Mon, Mar 01, 2021 at 10:52:48PM +0100, Uwe Kleine-König wrote:
> Hello,
> 
> On Mon, Feb 01, 2021 at 06:24:02PM +0100, Clemens Gruber wrote:
> > Hi Sven, Thierry, Uwe,
> > 
> > On Fri, Jan 29, 2021 at 05:16:51PM -0500, Sven Van Asbroeck wrote:
> > > Hi Clemens,
> > > 
> > > On Fri, Jan 29, 2021 at 4:24 PM Sven Van Asbroeck  
> > > wrote:
> > > >
> > > > LEN_ON = 409, LED_OFF = 1228 and
> > > > LED_ON = 419, LED_OFF = 1238
> > > > produce the same result. you can't see the difference between the two
> > > > when scoping the channel. there are probably more ways to do this,
> > > > some might surprise us. It's a tricky chip.
> > > 
> > > Please ignore this example, it's bogus. In my defence, it's a Friday
> > > afternoon here :)
> > 
> > Happens to the best of us :)
> > 
> > > 
> > > But consider the following: imagine the bootloader has enabled a few
> > > pwm channels, and the driver's .probe() has left them on/unchanged.
> > > Then the user enables another pwm channel, and tries to change the
> > > period/prescaler. How would pca9685_may_change_prescaler() know
> > > if changing the prescaler is allowed?
> > > 
> > > And the following: imagine the bootloader has enabled a few
> > > pwm channels, and the driver's .probe() has left them on/unchanged.
> > > After .probe(), the runtime_pm will immediately put the chip to sleep,
> > > because it's unaware that some channels are alive.
> > 
> > (We could read out the state in .probe. If a pwm is already enabled by
> > the bootloader, then the user can't change the period. Also, the chip
> > would not be put to sleep.
> > 
> > The user then can export channels and see if they are enabled. If he
> > wants to change the period, he needs to find the one enabled by the
> > bootloader and change the period there, before he requests more.
> > If the bootloader enabled more than one, then he has to disable all but
> > one to change the period.
> > 
> > Or did I miss something?)
> > 
> > > 
> > > I'm sure I'm overlooking a few complications here. probe not changing
> > > the existing configuration, will add a lot of complexity to the driver.
> > > I'm not saying this is necessarily bad, just a tradeoff. Or, a management
> > > decision.
> > 
> > But I agree that it is simpler if we keep the resets in probe. It would
> > also avoid a potentially breaking change for users that do not reset
> > their pca9685 chips in their bootloader code.
> 
> I would prefer to drop the reset. If the bootloader left with an invalid
> state, this is active for sure until the PWM driver is loaded. If you
> don't reset, the time is extended (usually) until the consumer comes
> along and corrects the setting. So the downside of not resetting is
> quite limited, but if you disable the PWM in .probe() the effect can be
> worse. And consistency dictates to not reset.
> 
> > Removing the resets could then be left as something to discuss further
> > in the future and something that belongs in a separate patch series?
> 
> That would be fine for me, too.

Great, then I will prepare a new series next week.

Thanks,
Clemens


Re: [PATCH v5 4/7] pwm: pca9685: Reset registers to POR state in probe

2021-03-04 Thread Clemens Gruber
On Mon, Mar 01, 2021 at 10:46:33PM +0100, Uwe Kleine-König wrote:
> Hello Clemens,
> 
> On Tue, Dec 15, 2020 at 10:22:25PM +0100, Clemens Gruber wrote:
> > Reset the prescale and ON/OFF registers to their POR default state in
> > the probe function. Otherwise, the PWMs could still be active after a
> > watchdog reset and reboot, etc.
> 
> My memories are swapped out because it's already so long ago I looked
> into this series. I thought it was already said that taking over the
> configured state in probe is the nice thing to do?!

Yes, but Sven voiced some concerns about the introduced complexities
when removing the resets.

I was torn between the two options.

I think it would be a good idea to first switch to the atomic API while
keeping the resets and then evaluate removing them in a separate patch
series.

Thanks,
Clemens


Re: [PATCH v5 1/7] pwm: pca9685: Switch to atomic API

2021-03-04 Thread Clemens Gruber
Hi Uwe,

On Mon, Mar 01, 2021 at 10:44:07PM +0100, Uwe Kleine-König wrote:
> Hello Clemens,
> 
> On Tue, Dec 15, 2020 at 10:22:22PM +0100, Clemens Gruber wrote:
> > +   if (state->polarity != PWM_POLARITY_NORMAL)
> > +   return -EOPNOTSUPP;
> 
> We agreed on -EINVAL for that one since 2b1c1a5d5148.
> 
> Other than that the patch looks ok (but note I only looked quickly).

Thanks for looking over it. This will be -EINVAL in the next revision.

Best regards,
Clemens


Re: [PATCH v5 1/7] pwm: pca9685: Switch to atomic API

2021-03-04 Thread Clemens Gruber
Hi Uwe,

On Mon, Mar 01, 2021 at 10:41:15PM +0100, Uwe Kleine-König wrote:
> On Thu, Dec 17, 2020 at 12:10:10PM -0500, Sven Van Asbroeck wrote:
> > On Thu, Dec 17, 2020 at 11:48 AM Clemens Gruber
> >  wrote:
> > >
> > > I can initialize the values to 0 of course and check the file for other
> > > places with missing initializations.
> > >
> > > Or would it be better to check the return codes of regmap_read/write in
> > > such cases? I'm not sure.
> > 
> > I think that checking the regmap_read/write return values is overkill
> > in this driver. These functions can't realistically fail, except if the i2c
> > bus is bad, i.e. h/w failure or intermittency. And that's an externality
> > which I believe we can ignore.
> > 
> > Maybe Thierry or Uwe have further insights here.
> 
> I'm a fan of full checking, but I'm not sure what's Thierry's position
> on that.
> 
> My reasoning is: If the bus is bad and a request to modify the PWM fails
> because of that, the PWM consumer probably wants to know.

I see. Then I'd suggest that we postpone adding these checks until we
get a response from Thierry and if he agrees with you, we could add
these checks in a separate patch series?

Thanks,
Clemens


Re: [PATCH v5 2/7] pwm: pca9685: Support hardware readout

2021-02-14 Thread Clemens Gruber
Hi all,

On Fri, Jan 29, 2021 at 09:37:47PM +0100, Clemens Gruber wrote:
> Hi Sven,
> 
> On Fri, Jan 29, 2021 at 01:05:14PM -0500, Sven Van Asbroeck wrote:
> > Hi Clemens,
> > 
> > On Fri, Jan 29, 2021 at 11:31 AM Clemens Gruber
> >  wrote:
> > >
> > > Ok, so you suggest we extend our get_state logic to deal with cases
> > > like the following:
> > 
> > Kind of. We can't control how other actors (bootloaders etc) program the
> > chip. As far as I know, there are many, many different register settings 
> > that
> > result in the same physical chip outputs. So if .probe() wants to preserve 
> > the
> > existing chip settings, .get_state() has to be able to deal with every 
> > possible
> > setting. Even invalid ones.
> 
> Is the driver really responsible for bootloaders that program the chip
> with invalid values?
> The chip comes out of PoR with sane default values. If the bootloader of
> a user messes them up, isn't that a bootloader problem instead of a
> Linux kernel driver problem?
> 
> > In addition, .apply() cannot make any assumptions as to which bits are
> > already set/cleared on the chip. Including preserved, invalid settings.
> > 
> > This might get quite complex.
> > 
> > However if we reset the chip in .probe() to a known state (a normalized 
> > state,
> > in the mathematical sense), then both .get_state() and .apply() become
> > much simpler. because they only need to deal with known, normalized states.
> 
> Yes, I agree. This would however make it impossible to do a flicker-free
> transition from bootloader to kernel, but that's not really a usecase I
> have so I can live without it.
> 
> Another point in favor of resetting is that the driver already does it.
> Removing the reset of the OFF register may break some boards who rely on
> that behaviour.
> My version only extended the reset to include the ON register.
> 
> > 
> > In short, it's a tradeoff between code complexity, and user friendliness/
> > features.
> > 
> > Sven
> 
> Thierry, Uwe, what's your take on this?
> 
> Thierry: Would you accept it if we continue to reset the registers in
> .probe?
> 
> Thanks,
> Clemens

I realize that it is a difficult time at the moment, but it is a little
bit frustrating not getting any response from the maintainer.

I think the best way forward is to just keep the register resets in
probe as they are. If this is to be changed, I think it should be done
in a separate patchset and by someone who has a usecase requiring it.

Best regards,
Clemens


Re: [PATCH v5 2/7] pwm: pca9685: Support hardware readout

2021-02-01 Thread Clemens Gruber
Hi Sven, Thierry, Uwe,

On Fri, Jan 29, 2021 at 05:16:51PM -0500, Sven Van Asbroeck wrote:
> Hi Clemens,
> 
> On Fri, Jan 29, 2021 at 4:24 PM Sven Van Asbroeck  wrote:
> >
> > LEN_ON = 409, LED_OFF = 1228 and
> > LED_ON = 419, LED_OFF = 1238
> > produce the same result. you can't see the difference between the two
> > when scoping the channel. there are probably more ways to do this,
> > some might surprise us. It's a tricky chip.
> 
> Please ignore this example, it's bogus. In my defence, it's a Friday
> afternoon here :)

Happens to the best of us :)

> 
> But consider the following: imagine the bootloader has enabled a few
> pwm channels, and the driver's .probe() has left them on/unchanged.
> Then the user enables another pwm channel, and tries to change the
> period/prescaler. How would pca9685_may_change_prescaler() know
> if changing the prescaler is allowed?
> 
> And the following: imagine the bootloader has enabled a few
> pwm channels, and the driver's .probe() has left them on/unchanged.
> After .probe(), the runtime_pm will immediately put the chip to sleep,
> because it's unaware that some channels are alive.

(We could read out the state in .probe. If a pwm is already enabled by
the bootloader, then the user can't change the period. Also, the chip
would not be put to sleep.

The user then can export channels and see if they are enabled. If he
wants to change the period, he needs to find the one enabled by the
bootloader and change the period there, before he requests more.
If the bootloader enabled more than one, then he has to disable all but
one to change the period.

Or did I miss something?)

> 
> I'm sure I'm overlooking a few complications here. probe not changing
> the existing configuration, will add a lot of complexity to the driver.
> I'm not saying this is necessarily bad, just a tradeoff. Or, a management
> decision.

But I agree that it is simpler if we keep the resets in probe. It would
also avoid a potentially breaking change for users that do not reset
their pca9685 chips in their bootloader code.
There might be users out there that depend on the driver to reset the
OFF registers in .probe.

If Thierry agrees / allows it, I can keep the resets for now.

Removing the resets could then be left as something to discuss further
in the future and something that belongs in a separate patch series?

Clemens


Re: [PATCH v5 2/7] pwm: pca9685: Support hardware readout

2021-01-29 Thread Clemens Gruber
Hi Sven,

On Fri, Jan 29, 2021 at 01:05:14PM -0500, Sven Van Asbroeck wrote:
> Hi Clemens,
> 
> On Fri, Jan 29, 2021 at 11:31 AM Clemens Gruber
>  wrote:
> >
> > Ok, so you suggest we extend our get_state logic to deal with cases
> > like the following:
> 
> Kind of. We can't control how other actors (bootloaders etc) program the
> chip. As far as I know, there are many, many different register settings that
> result in the same physical chip outputs. So if .probe() wants to preserve the
> existing chip settings, .get_state() has to be able to deal with every 
> possible
> setting. Even invalid ones.

Is the driver really responsible for bootloaders that program the chip
with invalid values?
The chip comes out of PoR with sane default values. If the bootloader of
a user messes them up, isn't that a bootloader problem instead of a
Linux kernel driver problem?

> In addition, .apply() cannot make any assumptions as to which bits are
> already set/cleared on the chip. Including preserved, invalid settings.
> 
> This might get quite complex.
> 
> However if we reset the chip in .probe() to a known state (a normalized state,
> in the mathematical sense), then both .get_state() and .apply() become
> much simpler. because they only need to deal with known, normalized states.

Yes, I agree. This would however make it impossible to do a flicker-free
transition from bootloader to kernel, but that's not really a usecase I
have so I can live without it.

Another point in favor of resetting is that the driver already does it.
Removing the reset of the OFF register may break some boards who rely on
that behaviour.
My version only extended the reset to include the ON register.

> 
> In short, it's a tradeoff between code complexity, and user friendliness/
> features.
> 
> Sven

Thierry, Uwe, what's your take on this?

Thierry: Would you accept it if we continue to reset the registers in
.probe?

Thanks,
Clemens


Re: [PATCH v5 2/7] pwm: pca9685: Support hardware readout

2021-01-29 Thread Clemens Gruber
Hi Sven,

On Fri, Jan 29, 2021 at 08:42:13AM -0500, Sven Van Asbroeck wrote:
> On Mon, Jan 11, 2021 at 3:35 PM Uwe Kleine-König
>  wrote:
> >
> > My position here is: A consumer should disable a PWM before calling
> > pwm_put. The driver should however not enforce this and so should not
> > modify the hardware state in .free().
> >
> > Also .probe should not change the PWM configuration.
> 
> I agree that this is the most user-friendly behaviour.
> 
> The problem however with the pca9685 is that it has many degrees of
> freedom: there are many possible register values which produce the same
> physical chip outputs.
> 
> This could lead to a situation where, if .probe() does not reset the register
> values, subsequent writes may lead to different outputs than expected.
> 
> One possible solution is to write .get_state() so that it always reads the
> correct state, even if "unconventional" register settings are present, i.e.
> those written by an outside entity, e.g. a bootloader. Then write that
> state back using driver conventions.
> 
> This may be trickier than it sounds - after all we've learnt that the pca9685
> looks simple on the surface, but is actually quite challenging to get right.
> 
> Clemens, Uwe, what do you think?

Ok, so you suggest we extend our get_state logic to deal with cases
like the following:
If neither full OFF nor full ON is set && ON == OFF, we should probably
set the full OFF bit to disable the PWM and log a warning message?
(e.g. "invalid register setting detected: pwm disabled" ?)
If the ON registers are set and the nxp,staggered-outputs property is
not, I'd calculate (off - on) & 4095, set the OFF register to that value
and clear the ON register.

And then call our get_state in .probe, followed by a write of the
resulting / fixed-up state?

This would definitely solve the problem of invalid/unconventional values
set by the bootloader and avoid inconsistencies.
Sounds good to me!

If Thierry and Uwe have no objections, I can send out a new round of
patches in the upcoming weeks.

My current goal is to get the changes into 5.13.

Thanks,
Clemens


Re: [PATCH v5 2/7] pwm: pca9685: Support hardware readout

2021-01-14 Thread Clemens Gruber
Hi,

On Mon, Jan 11, 2021 at 09:35:32PM +0100, Uwe Kleine-König wrote:
> Hello,
> 
> On Thu, Dec 17, 2020 at 06:43:04PM +0100, Clemens Gruber wrote:
> > On Wed, Dec 16, 2020 at 11:00:59PM -0500, Sven Van Asbroeck wrote:
> > > On Wed, Dec 16, 2020 at 7:53 AM Clemens Gruber
> > >  wrote:
> > > >
> > > > Implements .get_state to read-out the current hardware state.
> > > >
> > > 
> > > I am not convinced that we actually need this.
> > > 
> > > Looking at the pwm core, .get_state() is only called right after 
> > > .request(),
> > > to initialize the cached value of the state. The core then uses the cached
> > > value throughout, it'll never read out the h/w again, until the next 
> > > .request().
> > > 
> > > In our case, we know that the state right after request is always 
> > > disabled,
> > > because:
> > > - we disable all pwm channels on probe (in PATCH v5 4/7)
> > > - .free() disables the pwm channel
> > > 
> > > Conclusion: .get_state() will always return "pwm disabled", so why do we
> > > bother reading out the h/w?
> > 
> > If there are no plans for the PWM core to call .get_state more often in
> > the future, we could just read out the period and return 0 duty and
> > disabled.
> > 
> > Thierry, Uwe, what's your take on this?
> 
> I have some plans here. In the past I tried to implement them (see
> commit 01ccf903edd65f6421612321648fa5a7f4b7cb10), but this failed
> (commit 40a6b9a00930fd6b59aa2eb6135abc2efe5440c3).
> 
> > > Of course, if we choose to leave the pwm enabled after .free(), then
> > > .get_state() can even be left out! Do we want that? Genuine question, I do
> > > not know the answer.
> > 
> > I do not think we should leave it enabled after free. It is less
> > complicated if we know that unrequested channels are not in use.
> 
> My position here is: A consumer should disable a PWM before calling
> pwm_put. The driver should however not enforce this and so should not
> modify the hardware state in .free().
> 
> Also .probe should not change the PWM configuration.

I see. This would also allow PWMs initialized in the bootloader (e.g.
backlights) to stay on between the bootloader and Linux and avoid
flickering.

If no one objects, I would then no longer reset period and duty cycles
in the driver (and for our projects, reset them in the bootloader code
to avoid leaving PWMs on after a kernel panic and watchdog reset, etc.)

And if there is no pre-known state of the registers, we actually need
the .get_state function fully implemented.

Thanks,
Clemens


Re: [PATCH v5 2/7] pwm: pca9685: Support hardware readout

2021-01-03 Thread Clemens Gruber
Hi everyone,

happy new year, hope you are all well!

On Thu, Dec 17, 2020 at 12:52:42PM -0500, Sven Van Asbroeck wrote:
> On Thu, Dec 17, 2020 at 12:43 PM Clemens Gruber
>  wrote:
> > >
> > > Conclusion: .get_state() will always return "pwm disabled", so why do we
> > > bother reading out the h/w?
> >
> > If there are no plans for the PWM core to call .get_state more often in
> > the future, we could just read out the period and return 0 duty and
> > disabled.
> 
> I'm not sure why we should even read out the period?
> When a channel is disabled, the period is not externally visible,
> therefore it's meaningless ?
> 
> As far as I can tell, we can use this for .get_state():
> memset(>state, 0, sizeof(pwm_state));
> 
> >
> > Thierry, Uwe, what's your take on this?

I will continue working on this series in the upcoming weeks.
Feedback on the .get_state issue would be greatly appreciated.

To summarize:
Is it OK for a driver to expect the chip->ops->get_state function to be
only called from the place in pwm core it is currently called from?
(Namely in pwm_device_request after chip->ops->request)

If yes, we could always return a 0 duty cycle and disabled state,
because this is the state we left it in after .probe (and .free).

However, if in the future, the pwm core adds additional calls to
chip->ops->get_state in other places, this could lead to problems.

--

Another point is the period: Sven suggested we do not read out the
period at all, as the PWM is disabled anyway (see above).
Is this acceptable?

And, if we never return anything but 0 in .get_state, should it be
implemented at all?

> >
> > > Of course, if we choose to leave the pwm enabled after .free(), then
> > > .get_state() can even be left out! Do we want that? Genuine question, I do
> > > not know the answer.
> >
> > I do not think we should leave it enabled after free. It is less
> > complicated if we know that unrequested channels are not in use.
> >
> 
> Good point, I agree with you.

Thanks and best regards,
Clemens


Re: [PATCH v5 7/7] pwm: pca9685: Restrict period change for prescaler users

2020-12-17 Thread Clemens Gruber
Hi Sven,

On Wed, Dec 16, 2020 at 11:03:39PM -0500, Sven Van Asbroeck wrote:
> Hi Clemens, see below.
> 
> On Wed, Dec 16, 2020 at 7:53 AM Clemens Gruber
>  wrote:
> >
> > Previously, the last used PWM channel could change the global prescale
> > setting, even if other channels were already in use.
> >
> > Fix it by only allowing the first user of the prescaler 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.
> >
> > PWMs that are disabled or have a duty cycle of 0% or 100% are not
> > considered to be using the prescaler as they have the full OFF or full
> > ON bits set. This also applies to channels used as GPIOs.
> >
> > Signed-off-by: Clemens Gruber 
> > ---
> >  drivers/pwm/pwm-pca9685.c | 51 +--
> >  1 file changed, 44 insertions(+), 7 deletions(-)
> >
> > diff --git a/drivers/pwm/pwm-pca9685.c b/drivers/pwm/pwm-pca9685.c
> > index ff916980de49..438492d4aed4 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 uses the prescaler 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, unless 
> > they
> > + * use duty cycles of 0% or 100% (prescaler not used for full OFF/ON).
> >   */
> >
> >  #define PCA9685_MODE1  0x00
> > @@ -80,6 +80,8 @@ struct pca9685 {
> > struct pwm_chip chip;
> > struct regmap *regmap;
> > bool staggered_outputs;
> > +   struct mutex prescaler_users_lock;
> 
> Keep things simple by re-using the "struct mutex lock" below?
> This code isn't performance-intensive, so having a single lock for
> pwm/gpio requests + pwm_apply() is probably ok.

Yes, I think this could work. Good idea.

> 
> > +   DECLARE_BITMAP(prescaler_users, PCA9685_MAXCHAN + 1);
> 
> Rename to pwms_use_prescale ?

Yes, fine with me.

> 
> >  #if IS_ENABLED(CONFIG_GPIOLIB)
> > struct mutex lock;
> > struct gpio_chip gpio;
> > @@ -92,6 +94,18 @@ 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 prescaler_users_lock 
> > held */
> > +static inline bool pca9685_may_change_prescaler(struct pca9685 *pca, int 
> > channel)
> 
> Drop the inline? Only the compiler knows if inlining this function makes sense
> on a platform (armv7, x86, etc). Compilers are usually better at this then
> humans...

You're probably right. I will drop the inline.

> 
> Rename to pca9685_prescaler_can_change() ?

Sounds good!

> 
> > +{
> > +   /*
> > +* A PWM channel may only change the prescaler if there are no 
> > users of
> > +* the prescaler yet or that same channel is the only one in use.
> > +*/
> > +   return bitmap_empty(pca->prescaler_users, PCA9685_MAXCHAN + 1) ||
> > +   (bitmap_weight(pca->prescaler_users, PCA9685_MAXCHAN + 1) 
> > == 1 &&
> > +test_bit(channel, pca->prescaler_users));
> > +}
> 
> I found this logic expression quite complex to read. Perhaps simplify by using
> a few steps? For example:
> 
> /* if prescaler not in use, we can always change it */
> if (empty) return true;
> /* if more than one pwm is using the prescaler, we can never change it */
> if (weight > 1) return false;
> /* one pwm is using the prescaler, we can only change it if it's us */
> return test_bit(us);

Good point, I will simplify it!

> 
> > +
> >  static void pca9685_pwm_set_duty(struct pca9685 *pca, int channel, 
> > unsigned int duty)
> >  {
> > unsigned int on, off;
> > @@ -337,16 +351,25 @@ static int pca9685_pwm_apply(struct pwm_chip *chip, 
> > struct pwm_device *pwm,
> >

Re: [PATCH v5 5/7] pwm: pca9685: Support staggered output ON times

2020-12-17 Thread Clemens Gruber
On Wed, Dec 16, 2020 at 11:02:57PM -0500, Sven Van Asbroeck wrote:
> Hi Clemens, see below.
> 
> On Wed, Dec 16, 2020 at 7:53 AM Clemens Gruber
>  wrote:
> >
> > The PCA9685 supports staggered LED output ON times to minimize current
> > surges and reduce EMI.
> > When this new option is enabled, the ON times of each channel are
> > delayed by channel number x counter range / 16, which avoids asserting
> > all enabled outputs at the same counter value while still maintaining
> > the configured duty cycle of each output.
> >
> > Signed-off-by: Clemens Gruber 
> > ---
> >  drivers/pwm/pwm-pca9685.c | 62 +++
> >  1 file changed, 50 insertions(+), 12 deletions(-)
> >
> > diff --git a/drivers/pwm/pwm-pca9685.c b/drivers/pwm/pwm-pca9685.c
> > index 38aadaf50996..ff916980de49 100644
> > --- a/drivers/pwm/pwm-pca9685.c
> > +++ b/drivers/pwm/pwm-pca9685.c
> > @@ -79,6 +79,7 @@
> >  struct pca9685 {
> > struct pwm_chip chip;
> > struct regmap *regmap;
> > +   bool staggered_outputs;
> >  #if IS_ENABLED(CONFIG_GPIOLIB)
> > struct mutex lock;
> > struct gpio_chip gpio;
> > @@ -93,45 +94,79 @@ static inline struct pca9685 *to_pca(struct pwm_chip 
> > *chip)
> >
> >  static void pca9685_pwm_set_duty(struct pca9685 *pca, int channel, 
> > unsigned int duty)
> >  {
> > +   unsigned int on, off;
> > +
> > if (duty == 0) {
> > /* Set the full OFF bit, which has the highest precedence */
> > regmap_write(pca->regmap, REG_OFF_H(channel), LED_FULL);
> > +   return;
> > } else if (duty >= PCA9685_COUNTER_RANGE) {
> > /* Set the full ON bit and clear the full OFF bit */
> > regmap_write(pca->regmap, REG_ON_H(channel), LED_FULL);
> > regmap_write(pca->regmap, REG_OFF_H(channel), 0);
> > -   } else {
> > -   /* Set OFF time (clears the full OFF bit) */
> > -   regmap_write(pca->regmap, REG_OFF_L(channel), duty & 0xff);
> > -   regmap_write(pca->regmap, REG_OFF_H(channel), (duty >> 8) & 
> > 0xf);
> > -   /* Clear the full ON bit */
> > -   regmap_write(pca->regmap, REG_ON_H(channel), 0);
> > +   return;
> > +   }
> > +
> > +   if (pca->staggered_outputs) {
> > +   if (channel < PCA9685_MAXCHAN) {
> > +   /*
> > +* To reduce EMI, the ON times of each channel are
> > +* spread out evenly within the counter range, while
> > +* still maintaining the configured duty cycle
> > +*/
> > +   on = channel * PCA9685_COUNTER_RANGE / 
> > PCA9685_MAXCHAN;
> > +   off = (on + duty) % PCA9685_COUNTER_RANGE;
> > +   regmap_write(pca->regmap, REG_ON_L(channel), on & 
> > 0xff);
> > +   regmap_write(pca->regmap, REG_ON_H(channel), (on >> 
> > 8) & 0xf);
> > +   regmap_write(pca->regmap, REG_OFF_L(channel), off & 
> > 0xff);
> > +   regmap_write(pca->regmap, REG_OFF_H(channel), (off 
> > >> 8) & 0xf);
> > +   return;
> > +   }
> > +   /* No staggering possible if "all LEDs" channel is used */
> > +   regmap_write(pca->regmap, PCA9685_ALL_LED_ON_L, 0);
> > }
> > +   /* Set OFF time (clears the full OFF bit) */
> > +   regmap_write(pca->regmap, REG_OFF_L(channel), duty & 0xff);
> > +   regmap_write(pca->regmap, REG_OFF_H(channel), (duty >> 8) & 0xf);
> > +   /* Clear the full ON bit */
> > +   regmap_write(pca->regmap, REG_ON_H(channel), 0);
> >  }
> 
> I find the set_duty() function quite hard to follow.
> Can we simplify this by eliminating the !staggered_outputs special case?
> E.g. always calculate and write 'on' and 'off'.
> But if !staggered_outputs => on = 0 and off = duty.
> 
> Yes this adds one extra/unnecessary register write in the !staggered case,
> but simplicity/maintainability >>> efficiency here. And this "issue" will
> disappear when we switch on regmap caching.

No objections, I will eliminate the special case.

> 
> >
> >  static unsigned int pca9685_pwm_get_duty(struct pca96

Re: [PATCH v5 4/7] pwm: pca9685: Reset registers to POR state in probe

2020-12-17 Thread Clemens Gruber
On Wed, Dec 16, 2020 at 11:02:03PM -0500, Sven Van Asbroeck wrote:
> Hi Clemens, minor nit below.
> 
> On Wed, Dec 16, 2020 at 7:53 AM Clemens Gruber
>  wrote:
> >
> > Reset the prescale and ON/OFF registers to their POR default state in
> > the probe function. Otherwise, the PWMs could still be active after a
> > watchdog reset and reboot, etc.
> >
> > Signed-off-by: Clemens Gruber 
> > ---
> >  drivers/pwm/pwm-pca9685.c | 9 +++--
> >  1 file changed, 7 insertions(+), 2 deletions(-)
> >
> > diff --git a/drivers/pwm/pwm-pca9685.c b/drivers/pwm/pwm-pca9685.c
> > index 7b14447f3c05..38aadaf50996 100644
> > --- a/drivers/pwm/pwm-pca9685.c
> > +++ b/drivers/pwm/pwm-pca9685.c
> > @@ -47,6 +47,7 @@
> >  #define PCA9685_ALL_LED_OFF_H  0xFD
> >  #define PCA9685_PRESCALE   0xFE
> >
> > +#define PCA9685_PRESCALE_DEF   0x1E/* => default frequency of ~200 Hz 
> > */
> >  #define PCA9685_PRESCALE_MIN   0x03/* => max. frequency of 1526 Hz */
> >  #define PCA9685_PRESCALE_MAX   0xFF/* => min. frequency of 24 Hz */
> >
> > @@ -446,9 +447,11 @@ static int pca9685_pwm_probe(struct i2c_client *client,
> > reg &= ~(MODE1_ALLCALL | MODE1_SUB1 | MODE1_SUB2 | MODE1_SUB3);
> > regmap_write(pca->regmap, PCA9685_MODE1, reg);
> >
> > -   /* Clear all "full off" bits */
> > +   /* Reset ON/OFF registers to HW defaults (only full OFF bit is set) 
> > */
> > +   regmap_write(pca->regmap, PCA9685_ALL_LED_ON_L, 0);
> > +   regmap_write(pca->regmap, PCA9685_ALL_LED_ON_H, 0);
> > regmap_write(pca->regmap, PCA9685_ALL_LED_OFF_L, 0);
> > -   regmap_write(pca->regmap, PCA9685_ALL_LED_OFF_H, 0);
> > +   regmap_write(pca->regmap, PCA9685_ALL_LED_OFF_H, LED_FULL);
> >
> > pca->chip.ops = _pwm_ops;
> > /* Add an extra channel for ALL_LED */
> > @@ -470,8 +473,10 @@ static int pca9685_pwm_probe(struct i2c_client *client,
> > /*
> >  * The chip comes out of power-up in the sleep state,
> >  * but force it to sleep in case it was woken up before
> > +* and set the default prescale value
> >  */
> > pca9685_set_sleep_mode(pca, true);
> > +   regmap_write(pca->regmap, PCA9685_PRESCALE, PCA9685_PRESCALE_DEF);
> > pm_runtime_set_suspended(>dev);
> > pm_runtime_enable(>dev);
> 
> Consider making it clearer that prescale can only be touched when the chip is
> in sleep mode. Suggestion:
> 
> /* set the default prescale value - chip _must_ be in sleep mode */
> regmap_write(pca->regmap, PCA9685_PRESCALE, PCA9685_PRESCALE_DEF);

Good point, thanks.

> 
> >
> > --
> > 2.29.2
> >


Re: [PATCH v5 2/7] pwm: pca9685: Support hardware readout

2020-12-17 Thread Clemens Gruber
On Wed, Dec 16, 2020 at 11:00:59PM -0500, Sven Van Asbroeck wrote:
> On Wed, Dec 16, 2020 at 7:53 AM Clemens Gruber
>  wrote:
> >
> > Implements .get_state to read-out the current hardware state.
> >
> 
> I am not convinced that we actually need this.
> 
> Looking at the pwm core, .get_state() is only called right after .request(),
> to initialize the cached value of the state. The core then uses the cached
> value throughout, it'll never read out the h/w again, until the next 
> .request().
> 
> In our case, we know that the state right after request is always disabled,
> because:
> - we disable all pwm channels on probe (in PATCH v5 4/7)
> - .free() disables the pwm channel
> 
> Conclusion: .get_state() will always return "pwm disabled", so why do we
> bother reading out the h/w?

If there are no plans for the PWM core to call .get_state more often in
the future, we could just read out the period and return 0 duty and
disabled.

Thierry, Uwe, what's your take on this?

> Of course, if we choose to leave the pwm enabled after .free(), then
> .get_state() can even be left out! Do we want that? Genuine question, I do
> not know the answer.

I do not think we should leave it enabled after free. It is less
complicated if we know that unrequested channels are not in use.

> 
> > The hardware readout may return slightly different values than those
> > that were set in apply due to the limited range of possible prescale and
> > counter register values.
> >
> > Also note that although the datasheet mentions 200 Hz as default
> > frequency when using the internal 25 MHz oscillator, the calculated
> > period from the default prescaler register setting of 30 is 5079040ns.
> >
> > Signed-off-by: Clemens Gruber 
> > ---
> >  drivers/pwm/pwm-pca9685.c | 41 +++
> >  1 file changed, 41 insertions(+)
> >
> > diff --git a/drivers/pwm/pwm-pca9685.c b/drivers/pwm/pwm-pca9685.c
> > index 1b5b5fb93b43..b3398963c0ff 100644
> > --- a/drivers/pwm/pwm-pca9685.c
> > +++ b/drivers/pwm/pwm-pca9685.c
> > @@ -331,6 +331,46 @@ static int pca9685_pwm_apply(struct pwm_chip *chip, 
> > struct pwm_device *pwm,
> > return 0;
> >  }
> >
> > +static void pca9685_pwm_get_state(struct pwm_chip *chip, struct pwm_device 
> > *pwm,
> > + struct pwm_state *state)
> > +{
> > +   struct pca9685 *pca = to_pca(chip);
> > +   unsigned long long duty;
> > +   unsigned int val;
> > +
> > +   /* Calculate (chip-wide) period from prescale value */
> > +   regmap_read(pca->regmap, PCA9685_PRESCALE, );
> > +   state->period = (PCA9685_COUNTER_RANGE * 1000 / 
> > PCA9685_OSC_CLOCK_MHZ) *
> > +   (val + 1);
> > +
> > +   /* The (per-channel) polarity is fixed */
> > +   state->polarity = PWM_POLARITY_NORMAL;
> > +
> > +   if (pwm->hwpwm >= PCA9685_MAXCHAN) {
> > +   /*
> > +* The "all LEDs" channel does not support HW readout
> > +* Return 0 and disabled for backwards compatibility
> > +*/
> > +   state->duty_cycle = 0;
> > +   state->enabled = false;
> > +   return;
> > +   }
> > +
> > +   duty = pca9685_pwm_get_duty(pca, pwm->hwpwm);
> > +
> > +   state->enabled = !!duty;
> > +   if (!state->enabled) {
> > +   state->duty_cycle = 0;
> > +   return;
> > +   } else if (duty == PCA9685_COUNTER_RANGE) {
> > +   state->duty_cycle = state->period;
> > +   return;
> > +   }
> > +
> > +   duty *= state->period;
> > +   state->duty_cycle = duty / PCA9685_COUNTER_RANGE;
> > +}
> > +
> >  static int pca9685_pwm_request(struct pwm_chip *chip, struct pwm_device 
> > *pwm)
> >  {
> > struct pca9685 *pca = to_pca(chip);
> > @@ -353,6 +393,7 @@ static void pca9685_pwm_free(struct pwm_chip *chip, 
> > struct pwm_device *pwm)
> >
> >  static const struct pwm_ops pca9685_pwm_ops = {
> > .apply = pca9685_pwm_apply,
> > +   .get_state = pca9685_pwm_get_state,
> > .request = pca9685_pwm_request,
> > .free = pca9685_pwm_free,
> > .owner = THIS_MODULE,
> > --
> > 2.29.2
> >


Re: [PATCH v5 1/7] pwm: pca9685: Switch to atomic API

2020-12-17 Thread Clemens Gruber
Hi Sven,

On Wed, Dec 16, 2020 at 10:58:07PM -0500, Sven Van Asbroeck wrote:
> Hi Clemens, this looks compact, simple and neat. I like it a lot !!

Thanks!

> 
> Few very minor nits below.
> 
> On Wed, Dec 16, 2020 at 7:53 AM Clemens Gruber
>  wrote:
> >
> > The switch to the atomic API goes hand in hand with a few fixes to
> > previously experienced issues:
> > - The duty cycle is no longer lost after disable/enable (previously the
> >   OFF registers were cleared in disable and the user was required to
> >   call config to restore the duty cycle settings)
> > - If one sets a period resulting in the same prescale register value,
> >   the sleep and write to the register is now skipped
> >
> > Signed-off-by: Clemens Gruber 
> > ---
> > Changes since v4:
> > - Patches split up
> > - Use a single set_duty function
> > - Improve readability / new macros
> > - Added a patch to restrict prescale changes to the first user
> >
> > Changes since v3:
> > - Refactoring: Extracted common functions
> > - Read prescale register value instead of caching it
> > - Return all zeros and disabled for "all LEDs" channel state
> > - Improved duty calculation / mapping to 0..4096
> >
> > Changes since v2:
> > - Always set default prescale value in probe
> > - Simplified probe code
> > - Inlined functions with one callsite
> >
> > Changes since v1:
> > - Fixed a logic error
> > - Impoved PM runtime handling and fixed !CONFIG_PM
> > - Write default prescale reg value if invalid in probe
> > - Reuse full_off/_on functions throughout driver
> > - Use cached prescale value whenever possible
> >
> >  drivers/pwm/pwm-pca9685.c | 253 +-
> >  1 file changed, 87 insertions(+), 166 deletions(-)
> >
> > diff --git a/drivers/pwm/pwm-pca9685.c b/drivers/pwm/pwm-pca9685.c
> > index 4a55dc18656c..1b5b5fb93b43 100644
> > --- a/drivers/pwm/pwm-pca9685.c
> > +++ b/drivers/pwm/pwm-pca9685.c
> > @@ -51,7 +51,6 @@
> >  #define PCA9685_PRESCALE_MAX   0xFF/* => min. frequency of 24 Hz */
> >
> >  #define PCA9685_COUNTER_RANGE  4096
> > -#define PCA9685_DEFAULT_PERIOD 500 /* Default period_ns = 1/200 Hz */
> >  #define PCA9685_OSC_CLOCK_MHZ  25  /* Internal oscillator with 25 MHz 
> > */
> >
> >  #define PCA9685_NUMREGS0xFF
> > @@ -71,10 +70,14 @@
> >  #define LED_N_OFF_H(N) (PCA9685_LEDX_OFF_H + (4 * (N)))
> >  #define LED_N_OFF_L(N) (PCA9685_LEDX_OFF_L + (4 * (N)))
> >
> > +#define REG_ON_H(C)((C) >= PCA9685_MAXCHAN ? PCA9685_ALL_LED_ON_H : 
> > LED_N_ON_H((C)))
> > +#define REG_ON_L(C)((C) >= PCA9685_MAXCHAN ? PCA9685_ALL_LED_ON_L : 
> > LED_N_ON_L((C)))
> > +#define REG_OFF_H(C)   ((C) >= PCA9685_MAXCHAN ? PCA9685_ALL_LED_OFF_H : 
> > LED_N_OFF_H((C)))
> > +#define REG_OFF_L(C)   ((C) >= PCA9685_MAXCHAN ? PCA9685_ALL_LED_OFF_L : 
> > LED_N_OFF_L((C)))
> 
> Yes !!
> 
> > +
> >  struct pca9685 {
> > struct pwm_chip chip;
> > struct regmap *regmap;
> > -   int period_ns;
> >  #if IS_ENABLED(CONFIG_GPIOLIB)
> > struct mutex lock;
> > struct gpio_chip gpio;
> > @@ -87,6 +90,49 @@ static inline struct pca9685 *to_pca(struct pwm_chip 
> > *chip)
> > return container_of(chip, struct pca9685, chip);
> >  }
> >
> > +static void pca9685_pwm_set_duty(struct pca9685 *pca, int channel, 
> > unsigned int duty)
> > +{
> 
> Add brief function documentation to clarify that 'duty' sets the duty cycle
> _ratio_ to 'duty/4096' on ? I.e.
> duty == 2048 => duty cycle ratio = 2048/4096 = 50%  on
> duty == 4096 => duty cycle ratio = 4096/4086 = 100% on etc

Will do.

> 
> > +   if (duty == 0) {
> > +   /* Set the full OFF bit, which has the highest precedence */
> > +   regmap_write(pca->regmap, REG_OFF_H(channel), LED_FULL);
> > +   } else if (duty >= PCA9685_COUNTER_RANGE) {
> > +   /* Set the full ON bit and clear the full OFF bit */
> > +   regmap_write(pca->regmap, REG_ON_H(channel), LED_FULL);
> > +   regmap_write(pca->regmap, REG_OFF_H(channel), 0);
> > +   } else {
> > +   /* Set OFF time (clears the full OFF bit) */
> > +   regmap_write(pca->regmap, REG_OFF_L(channel), duty & 0xff);
> > +   regmap_write(pca->regmap, REG_OFF_H(channel), (duty >> 8) & 
> > 0xf);
> > +   /* Cle

[PATCH v5 7/7] pwm: pca9685: Restrict period change for prescaler users

2020-12-15 Thread Clemens Gruber
Previously, the last used PWM channel could change the global prescale
setting, even if other channels were already in use.

Fix it by only allowing the first user of the prescaler 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.

PWMs that are disabled or have a duty cycle of 0% or 100% are not
considered to be using the prescaler as they have the full OFF or full
ON bits set. This also applies to channels used as GPIOs.

Signed-off-by: Clemens Gruber 
---
 drivers/pwm/pwm-pca9685.c | 51 +--
 1 file changed, 44 insertions(+), 7 deletions(-)

diff --git a/drivers/pwm/pwm-pca9685.c b/drivers/pwm/pwm-pca9685.c
index ff916980de49..438492d4aed4 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 uses the prescaler 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, unless they
+ * use duty cycles of 0% or 100% (prescaler not used for full OFF/ON).
  */
 
 #define PCA9685_MODE1  0x00
@@ -80,6 +80,8 @@ struct pca9685 {
struct pwm_chip chip;
struct regmap *regmap;
bool staggered_outputs;
+   struct mutex prescaler_users_lock;
+   DECLARE_BITMAP(prescaler_users, PCA9685_MAXCHAN + 1);
 #if IS_ENABLED(CONFIG_GPIOLIB)
struct mutex lock;
struct gpio_chip gpio;
@@ -92,6 +94,18 @@ 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 prescaler_users_lock held */
+static inline bool pca9685_may_change_prescaler(struct pca9685 *pca, int 
channel)
+{
+   /*
+* A PWM channel may only change the prescaler if there are no users of
+* the prescaler yet or that same channel is the only one in use.
+*/
+   return bitmap_empty(pca->prescaler_users, PCA9685_MAXCHAN + 1) ||
+   (bitmap_weight(pca->prescaler_users, PCA9685_MAXCHAN + 1) == 1 
&&
+test_bit(channel, pca->prescaler_users));
+}
+
 static void pca9685_pwm_set_duty(struct pca9685 *pca, int channel, unsigned 
int duty)
 {
unsigned int on, off;
@@ -337,16 +351,25 @@ static int pca9685_pwm_apply(struct pwm_chip *chip, 
struct pwm_device *pwm,
duty = PCA9685_COUNTER_RANGE * state->duty_cycle;
duty = DIV_ROUND_CLOSEST_ULL(duty, state->period);
 
+   mutex_lock(>prescaler_users_lock);
+
if (!state->enabled || duty < 1) {
pca9685_pwm_set_duty(pca, pwm->hwpwm, 0);
-   return 0;
+   goto prescaler_unused;
} else if (duty == PCA9685_COUNTER_RANGE) {
pca9685_pwm_set_duty(pca, pwm->hwpwm, duty);
-   return 0;
+   goto prescaler_unused;
}
 
regmap_read(pca->regmap, PCA9685_PRESCALE, );
if (prescale != val) {
+   if (!pca9685_may_change_prescaler(pca, pwm->hwpwm)) {
+   mutex_unlock(>prescaler_users_lock);
+   dev_err(chip->dev,
+   "prescaler not set: already in use with 
different setting!\n");
+   return -EBUSY;
+   }
+
/*
 * Putting the chip briefly into SLEEP mode
 * at this point won't interfere with the
@@ -364,6 +387,14 @@ static int pca9685_pwm_apply(struct pwm_chip *chip, struct 
pwm_device *pwm,
}
 
pca9685_pwm_set_duty(pca, pwm->hwpwm, duty);
+
+   set_bit(pwm->hwpwm, pca->prescaler_users);
+   mutex_unlock(>prescaler_users_lock);
+   return 0;
+
+prescaler_unused:
+   clear_bit(pwm->hwpwm, pca->prescaler_users);
+   mutex_unlock(>prescaler_users_lock);
return 0;
 }
 
@@ -422,7 +453,11 @@ static void pca9685_pwm_free(struct pwm_chip *chip, struct 
pwm_device *pwm)
 {
struct pca9685 *pca = to_pca(chip);
 
+   mutex_lock(>prescaler_users_lock);
+   clear_bit(pwm->hwpwm, pca->prescaler_users);
pca9685_pwm_set_duty(pca, pwm->hwpwm, 0);
+   mutex_unlock(>prescaler_users_lock);
+
pm_runtime_put(chip->dev);
pca9685_pwm_clear_inuse(pca, pwm->hwpwm);
 }
@@ -463,6 +498,8 @@ static int pca9685_pwm_probe(struct i2c

[PATCH v5 6/7] dt-bindings: pwm: pca9685: Add nxp,staggered-outputs property

2020-12-15 Thread Clemens Gruber
The pca9685 driver supports a new nxp,staggered-outputs property for
reduced current surges and EMI. This adds documentation for the new DT
property.

Signed-off-by: Clemens Gruber 
---
 Documentation/devicetree/bindings/pwm/nxp,pca9685-pwm.txt | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/Documentation/devicetree/bindings/pwm/nxp,pca9685-pwm.txt 
b/Documentation/devicetree/bindings/pwm/nxp,pca9685-pwm.txt
index f21b55c95738..fafe954369dc 100644
--- a/Documentation/devicetree/bindings/pwm/nxp,pca9685-pwm.txt
+++ b/Documentation/devicetree/bindings/pwm/nxp,pca9685-pwm.txt
@@ -12,6 +12,8 @@ Optional properties:
   - invert (bool): boolean to enable inverted logic
   - open-drain (bool): boolean to configure outputs with open-drain structure;
   if omitted use totem-pole structure
+  - nxp,staggered-outputs (bool): boolean to enable staggered output ON times 
to
+ minimize current surges and EMI
 
 Example:
 
-- 
2.29.2



[PATCH v5 5/7] pwm: pca9685: Support staggered output ON times

2020-12-15 Thread Clemens Gruber
The PCA9685 supports staggered LED output ON times to minimize current
surges and reduce EMI.
When this new option is enabled, the ON times of each channel are
delayed by channel number x counter range / 16, which avoids asserting
all enabled outputs at the same counter value while still maintaining
the configured duty cycle of each output.

Signed-off-by: Clemens Gruber 
---
 drivers/pwm/pwm-pca9685.c | 62 +++
 1 file changed, 50 insertions(+), 12 deletions(-)

diff --git a/drivers/pwm/pwm-pca9685.c b/drivers/pwm/pwm-pca9685.c
index 38aadaf50996..ff916980de49 100644
--- a/drivers/pwm/pwm-pca9685.c
+++ b/drivers/pwm/pwm-pca9685.c
@@ -79,6 +79,7 @@
 struct pca9685 {
struct pwm_chip chip;
struct regmap *regmap;
+   bool staggered_outputs;
 #if IS_ENABLED(CONFIG_GPIOLIB)
struct mutex lock;
struct gpio_chip gpio;
@@ -93,45 +94,79 @@ static inline struct pca9685 *to_pca(struct pwm_chip *chip)
 
 static void pca9685_pwm_set_duty(struct pca9685 *pca, int channel, unsigned 
int duty)
 {
+   unsigned int on, off;
+
if (duty == 0) {
/* Set the full OFF bit, which has the highest precedence */
regmap_write(pca->regmap, REG_OFF_H(channel), LED_FULL);
+   return;
} else if (duty >= PCA9685_COUNTER_RANGE) {
/* Set the full ON bit and clear the full OFF bit */
regmap_write(pca->regmap, REG_ON_H(channel), LED_FULL);
regmap_write(pca->regmap, REG_OFF_H(channel), 0);
-   } else {
-   /* Set OFF time (clears the full OFF bit) */
-   regmap_write(pca->regmap, REG_OFF_L(channel), duty & 0xff);
-   regmap_write(pca->regmap, REG_OFF_H(channel), (duty >> 8) & 
0xf);
-   /* Clear the full ON bit */
-   regmap_write(pca->regmap, REG_ON_H(channel), 0);
+   return;
+   }
+
+   if (pca->staggered_outputs) {
+   if (channel < PCA9685_MAXCHAN) {
+   /*
+* To reduce EMI, the ON times of each channel are
+* spread out evenly within the counter range, while
+* still maintaining the configured duty cycle
+*/
+   on = channel * PCA9685_COUNTER_RANGE / PCA9685_MAXCHAN;
+   off = (on + duty) % PCA9685_COUNTER_RANGE;
+   regmap_write(pca->regmap, REG_ON_L(channel), on & 0xff);
+   regmap_write(pca->regmap, REG_ON_H(channel), (on >> 8) 
& 0xf);
+   regmap_write(pca->regmap, REG_OFF_L(channel), off & 
0xff);
+   regmap_write(pca->regmap, REG_OFF_H(channel), (off >> 
8) & 0xf);
+   return;
+   }
+   /* No staggering possible if "all LEDs" channel is used */
+   regmap_write(pca->regmap, PCA9685_ALL_LED_ON_L, 0);
}
+   /* Set OFF time (clears the full OFF bit) */
+   regmap_write(pca->regmap, REG_OFF_L(channel), duty & 0xff);
+   regmap_write(pca->regmap, REG_OFF_H(channel), (duty >> 8) & 0xf);
+   /* Clear the full ON bit */
+   regmap_write(pca->regmap, REG_ON_H(channel), 0);
 }
 
 static unsigned int pca9685_pwm_get_duty(struct pca9685 *pca, int channel)
 {
-   unsigned int off_h, val;
+   unsigned int off, on, val;
 
if (WARN_ON(channel >= PCA9685_MAXCHAN)) {
/* Hardware readout not supported for "all LEDs" channel */
return 0;
}
 
-   regmap_read(pca->regmap, LED_N_OFF_H(channel), _h);
-   if (off_h & LED_FULL) {
+   regmap_read(pca->regmap, LED_N_OFF_H(channel), );
+   if (off & LED_FULL) {
/* Full OFF bit is set */
return 0;
}
 
-   regmap_read(pca->regmap, LED_N_ON_H(channel), );
-   if (val & LED_FULL) {
+   regmap_read(pca->regmap, LED_N_ON_H(channel), );
+   if (on & LED_FULL) {
/* Full ON bit is set */
return PCA9685_COUNTER_RANGE;
}
 
regmap_read(pca->regmap, LED_N_OFF_L(channel), );
-   return ((off_h & 0xf) << 8) | (val & 0xff);
+   off = ((off & 0xf) << 8) | (val & 0xff);
+
+   if (pca->staggered_outputs) {
+   regmap_read(pca->regmap, LED_N_ON_L(channel), );
+   on = ((on & 0xf) << 8) | (val & 0xff);
+
+   if (off >= on)
+   return off - on;
+   else
+   return off + PCA9685_COUNTER_RANGE - on;
+   }
+
+   return off;
 }
 
 #if IS_ENABLED(CONFIG_GPIOLIB)
@@ -442,6 +477,9 @@ static int pca9685_pwm_probe(struct i2c_client *client,
 
regmap_write(

[PATCH v5 3/7] pwm: pca9685: Improve runtime PM behavior

2020-12-15 Thread Clemens Gruber
The chip does not come out of POR in active state but in sleep state.
To be sure (in case the bootloader woke it up) we force it to sleep in
probe.

On kernels without CONFIG_PM, we wake the chip in .probe and put it to
sleep in .remove.

Signed-off-by: Clemens Gruber 
---
 drivers/pwm/pwm-pca9685.c | 20 
 1 file changed, 16 insertions(+), 4 deletions(-)

diff --git a/drivers/pwm/pwm-pca9685.c b/drivers/pwm/pwm-pca9685.c
index b3398963c0ff..7b14447f3c05 100644
--- a/drivers/pwm/pwm-pca9685.c
+++ b/drivers/pwm/pwm-pca9685.c
@@ -467,14 +467,19 @@ static int pca9685_pwm_probe(struct i2c_client *client,
return ret;
}
 
-   /* The chip comes out of power-up in the active state */
-   pm_runtime_set_active(>dev);
/*
-* Enable will put the chip into suspend, which is what we
-* want as all outputs are disabled at this point
+* The chip comes out of power-up in the sleep state,
+* but force it to sleep in case it was woken up before
 */
+   pca9685_set_sleep_mode(pca, true);
+   pm_runtime_set_suspended(>dev);
pm_runtime_enable(>dev);
 
+   if (!IS_ENABLED(CONFIG_PM)) {
+   /* Wake the chip up on non-PM environments */
+   pca9685_set_sleep_mode(pca, false);
+   }
+
return 0;
 }
 
@@ -486,7 +491,14 @@ static int pca9685_pwm_remove(struct i2c_client *client)
ret = pwmchip_remove(>chip);
if (ret)
return ret;
+
pm_runtime_disable(>dev);
+
+   if (!IS_ENABLED(CONFIG_PM)) {
+   /* Put chip in sleep state on non-PM environments */
+   pca9685_set_sleep_mode(pca, true);
+   }
+
return 0;
 }
 
-- 
2.29.2



[PATCH v5 4/7] pwm: pca9685: Reset registers to POR state in probe

2020-12-15 Thread Clemens Gruber
Reset the prescale and ON/OFF registers to their POR default state in
the probe function. Otherwise, the PWMs could still be active after a
watchdog reset and reboot, etc.

Signed-off-by: Clemens Gruber 
---
 drivers/pwm/pwm-pca9685.c | 9 +++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/drivers/pwm/pwm-pca9685.c b/drivers/pwm/pwm-pca9685.c
index 7b14447f3c05..38aadaf50996 100644
--- a/drivers/pwm/pwm-pca9685.c
+++ b/drivers/pwm/pwm-pca9685.c
@@ -47,6 +47,7 @@
 #define PCA9685_ALL_LED_OFF_H  0xFD
 #define PCA9685_PRESCALE   0xFE
 
+#define PCA9685_PRESCALE_DEF   0x1E/* => default frequency of ~200 Hz */
 #define PCA9685_PRESCALE_MIN   0x03/* => max. frequency of 1526 Hz */
 #define PCA9685_PRESCALE_MAX   0xFF/* => min. frequency of 24 Hz */
 
@@ -446,9 +447,11 @@ static int pca9685_pwm_probe(struct i2c_client *client,
reg &= ~(MODE1_ALLCALL | MODE1_SUB1 | MODE1_SUB2 | MODE1_SUB3);
regmap_write(pca->regmap, PCA9685_MODE1, reg);
 
-   /* Clear all "full off" bits */
+   /* Reset ON/OFF registers to HW defaults (only full OFF bit is set) */
+   regmap_write(pca->regmap, PCA9685_ALL_LED_ON_L, 0);
+   regmap_write(pca->regmap, PCA9685_ALL_LED_ON_H, 0);
regmap_write(pca->regmap, PCA9685_ALL_LED_OFF_L, 0);
-   regmap_write(pca->regmap, PCA9685_ALL_LED_OFF_H, 0);
+   regmap_write(pca->regmap, PCA9685_ALL_LED_OFF_H, LED_FULL);
 
pca->chip.ops = _pwm_ops;
/* Add an extra channel for ALL_LED */
@@ -470,8 +473,10 @@ static int pca9685_pwm_probe(struct i2c_client *client,
/*
 * The chip comes out of power-up in the sleep state,
 * but force it to sleep in case it was woken up before
+* and set the default prescale value
 */
pca9685_set_sleep_mode(pca, true);
+   regmap_write(pca->regmap, PCA9685_PRESCALE, PCA9685_PRESCALE_DEF);
pm_runtime_set_suspended(>dev);
pm_runtime_enable(>dev);
 
-- 
2.29.2



[PATCH v5 2/7] pwm: pca9685: Support hardware readout

2020-12-15 Thread Clemens Gruber
Implements .get_state to read-out the current hardware state.

The hardware readout may return slightly different values than those
that were set in apply due to the limited range of possible prescale and
counter register values.

Also note that although the datasheet mentions 200 Hz as default
frequency when using the internal 25 MHz oscillator, the calculated
period from the default prescaler register setting of 30 is 5079040ns.

Signed-off-by: Clemens Gruber 
---
 drivers/pwm/pwm-pca9685.c | 41 +++
 1 file changed, 41 insertions(+)

diff --git a/drivers/pwm/pwm-pca9685.c b/drivers/pwm/pwm-pca9685.c
index 1b5b5fb93b43..b3398963c0ff 100644
--- a/drivers/pwm/pwm-pca9685.c
+++ b/drivers/pwm/pwm-pca9685.c
@@ -331,6 +331,46 @@ static int pca9685_pwm_apply(struct pwm_chip *chip, struct 
pwm_device *pwm,
return 0;
 }
 
+static void pca9685_pwm_get_state(struct pwm_chip *chip, struct pwm_device 
*pwm,
+ struct pwm_state *state)
+{
+   struct pca9685 *pca = to_pca(chip);
+   unsigned long long duty;
+   unsigned int val;
+
+   /* Calculate (chip-wide) period from prescale value */
+   regmap_read(pca->regmap, PCA9685_PRESCALE, );
+   state->period = (PCA9685_COUNTER_RANGE * 1000 / PCA9685_OSC_CLOCK_MHZ) *
+   (val + 1);
+
+   /* The (per-channel) polarity is fixed */
+   state->polarity = PWM_POLARITY_NORMAL;
+
+   if (pwm->hwpwm >= PCA9685_MAXCHAN) {
+   /*
+* The "all LEDs" channel does not support HW readout
+* Return 0 and disabled for backwards compatibility
+*/
+   state->duty_cycle = 0;
+   state->enabled = false;
+   return;
+   }
+
+   duty = pca9685_pwm_get_duty(pca, pwm->hwpwm);
+
+   state->enabled = !!duty;
+   if (!state->enabled) {
+   state->duty_cycle = 0;
+   return;
+   } else if (duty == PCA9685_COUNTER_RANGE) {
+   state->duty_cycle = state->period;
+   return;
+   }
+
+   duty *= state->period;
+   state->duty_cycle = duty / PCA9685_COUNTER_RANGE;
+}
+
 static int pca9685_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
 {
struct pca9685 *pca = to_pca(chip);
@@ -353,6 +393,7 @@ static void pca9685_pwm_free(struct pwm_chip *chip, struct 
pwm_device *pwm)
 
 static const struct pwm_ops pca9685_pwm_ops = {
.apply = pca9685_pwm_apply,
+   .get_state = pca9685_pwm_get_state,
.request = pca9685_pwm_request,
.free = pca9685_pwm_free,
.owner = THIS_MODULE,
-- 
2.29.2



[PATCH v5 1/7] pwm: pca9685: Switch to atomic API

2020-12-15 Thread Clemens Gruber
The switch to the atomic API goes hand in hand with a few fixes to
previously experienced issues:
- The duty cycle is no longer lost after disable/enable (previously the
  OFF registers were cleared in disable and the user was required to
  call config to restore the duty cycle settings)
- If one sets a period resulting in the same prescale register value,
  the sleep and write to the register is now skipped

Signed-off-by: Clemens Gruber 
---
Changes since v4:
- Patches split up
- Use a single set_duty function
- Improve readability / new macros
- Added a patch to restrict prescale changes to the first user

Changes since v3:
- Refactoring: Extracted common functions
- Read prescale register value instead of caching it
- Return all zeros and disabled for "all LEDs" channel state
- Improved duty calculation / mapping to 0..4096

Changes since v2:
- Always set default prescale value in probe
- Simplified probe code
- Inlined functions with one callsite

Changes since v1:
- Fixed a logic error
- Impoved PM runtime handling and fixed !CONFIG_PM
- Write default prescale reg value if invalid in probe
- Reuse full_off/_on functions throughout driver
- Use cached prescale value whenever possible

 drivers/pwm/pwm-pca9685.c | 253 +-
 1 file changed, 87 insertions(+), 166 deletions(-)

diff --git a/drivers/pwm/pwm-pca9685.c b/drivers/pwm/pwm-pca9685.c
index 4a55dc18656c..1b5b5fb93b43 100644
--- a/drivers/pwm/pwm-pca9685.c
+++ b/drivers/pwm/pwm-pca9685.c
@@ -51,7 +51,6 @@
 #define PCA9685_PRESCALE_MAX   0xFF/* => min. frequency of 24 Hz */
 
 #define PCA9685_COUNTER_RANGE  4096
-#define PCA9685_DEFAULT_PERIOD 500 /* Default period_ns = 1/200 Hz */
 #define PCA9685_OSC_CLOCK_MHZ  25  /* Internal oscillator with 25 MHz */
 
 #define PCA9685_NUMREGS0xFF
@@ -71,10 +70,14 @@
 #define LED_N_OFF_H(N) (PCA9685_LEDX_OFF_H + (4 * (N)))
 #define LED_N_OFF_L(N) (PCA9685_LEDX_OFF_L + (4 * (N)))
 
+#define REG_ON_H(C)((C) >= PCA9685_MAXCHAN ? PCA9685_ALL_LED_ON_H : 
LED_N_ON_H((C)))
+#define REG_ON_L(C)((C) >= PCA9685_MAXCHAN ? PCA9685_ALL_LED_ON_L : 
LED_N_ON_L((C)))
+#define REG_OFF_H(C)   ((C) >= PCA9685_MAXCHAN ? PCA9685_ALL_LED_OFF_H : 
LED_N_OFF_H((C)))
+#define REG_OFF_L(C)   ((C) >= PCA9685_MAXCHAN ? PCA9685_ALL_LED_OFF_L : 
LED_N_OFF_L((C)))
+
 struct pca9685 {
struct pwm_chip chip;
struct regmap *regmap;
-   int period_ns;
 #if IS_ENABLED(CONFIG_GPIOLIB)
struct mutex lock;
struct gpio_chip gpio;
@@ -87,6 +90,49 @@ static inline struct pca9685 *to_pca(struct pwm_chip *chip)
return container_of(chip, struct pca9685, chip);
 }
 
+static void pca9685_pwm_set_duty(struct pca9685 *pca, int channel, unsigned 
int duty)
+{
+   if (duty == 0) {
+   /* Set the full OFF bit, which has the highest precedence */
+   regmap_write(pca->regmap, REG_OFF_H(channel), LED_FULL);
+   } else if (duty >= PCA9685_COUNTER_RANGE) {
+   /* Set the full ON bit and clear the full OFF bit */
+   regmap_write(pca->regmap, REG_ON_H(channel), LED_FULL);
+   regmap_write(pca->regmap, REG_OFF_H(channel), 0);
+   } else {
+   /* Set OFF time (clears the full OFF bit) */
+   regmap_write(pca->regmap, REG_OFF_L(channel), duty & 0xff);
+   regmap_write(pca->regmap, REG_OFF_H(channel), (duty >> 8) & 
0xf);
+   /* Clear the full ON bit */
+   regmap_write(pca->regmap, REG_ON_H(channel), 0);
+   }
+}
+
+static unsigned int pca9685_pwm_get_duty(struct pca9685 *pca, int channel)
+{
+   unsigned int off_h, val;
+
+   if (WARN_ON(channel >= PCA9685_MAXCHAN)) {
+   /* Hardware readout not supported for "all LEDs" channel */
+   return 0;
+   }
+
+   regmap_read(pca->regmap, LED_N_OFF_H(channel), _h);
+   if (off_h & LED_FULL) {
+   /* Full OFF bit is set */
+   return 0;
+   }
+
+   regmap_read(pca->regmap, LED_N_ON_H(channel), );
+   if (val & LED_FULL) {
+   /* Full ON bit is set */
+   return PCA9685_COUNTER_RANGE;
+   }
+
+   regmap_read(pca->regmap, LED_N_OFF_L(channel), );
+   return ((off_h & 0xf) << 8) | (val & 0xff);
+}
+
 #if IS_ENABLED(CONFIG_GPIOLIB)
 static bool pca9685_pwm_test_and_set_inuse(struct pca9685 *pca, int pwm_idx)
 {
@@ -138,34 +184,23 @@ static int pca9685_pwm_gpio_request(struct gpio_chip 
*gpio, unsigned int offset)
 static int pca9685_pwm_gpio_get(struct gpio_chip *gpio, unsigned int offset)
 {
struct pca9685 *pca = gpiochip_get_data(gpio);
-   struct pwm_device *pwm = >chip.pwms[offset];
-   unsigned int value;
 
-   regmap_read(pca->regmap, LED_N_ON_H(pwm->hwpwm), );
-
-   return value & LED_FULL;
+   return pca96

Re: [PATCH v4 1/4] pwm: pca9685: Switch to atomic API

2020-12-14 Thread Clemens Gruber
On Mon, Dec 14, 2020 at 03:28:24PM +0100, Thierry Reding wrote:
> On Fri, Dec 11, 2020 at 11:34:54AM +0100, Uwe Kleine-König wrote:
> > Hello Thierry,
> > 
> > On Fri, Dec 11, 2020 at 09:33:55AM +0100, Thierry Reding wrote:
> > > On Thu, Dec 10, 2020 at 09:39:26PM +0100, Uwe Kleine-König wrote:
> > > > On Thu, Dec 10, 2020 at 06:10:45PM +0100, Thierry Reding wrote:
> > > > > Like I said, that's not what I was saying. I was merely saying that if
> > > > > there aren't any use-cases that current users rely on that would be
> > > > > broken by using this simpler implementation, then I'm okay with it, 
> > > > > even
> > > > > if it's less flexible than a more complicated implementation. It 
> > > > > should
> > > > > be possible to determine what the current users are by inspecting 
> > > > > device
> > > > > trees present in the kernel. Anything outside the kernel isn't 
> > > > > something
> > > > > we need to consider, as usual.
> > > > 
> > > > If "users in mainline" is the criteria that's a word.
> > > 
> > > I didn't say "users in mainline", I said "use-cases". What I don't want
> > > to happen is for this change under discussion to break any existing use-
> > > cases of any existing users in the kernel. I said that we can determine
> > > what the existing users are by looking at which device trees use the
> > > compatible strings that the driver matches on.
> > > 
> > > > So you agree we remove the following drivers?:
> > > > 
> > > >  - pwm-hibvt.c
> > > >Last driver specific change in Feb 2019, no mainline user
> > > >  - pwm-sprd.c
> > > >Last driver specific change in Aug 2019, no mainline user
> > > 
> > > No, that's an extrapolation of what I was saying above. Drivers with no
> > > apparent users are a separate topic, so don't conflate it with the issue
> > > at hand.
> > 
> > I cannot follow (and I think that's the problem between us and why those
> > conflicts happen between us). For me it's a logic consequence of
> > "Anything outside the kernel isn't something we need to consider, as
> > usual." that drivers that are untouched for some period and have no
> > mainline users can/should go away. (Is "extrapolation" as strong as
> > "implication", or has it subjective interpretation added? My dictionary
> > isn't accurate enough for that question.) But it seems there is
> > something with my logic or you not saying exactly what you actually
> > mean. (Did I miss any option? If yes it might be covered by a problem in
> > my logic.)
> 
> To me this is not as black and white as it seems to be for you. First I
> wasn't talking about unused drivers, but about use-cases that are not
> represented in mainline. Secondly I didn't say anything about removing
> support for use-cases that weren't in use upstream. All I said was that
> I didn't want any changes to regress existing use-cases.
> 
> "Guessing" how that statement reflects on my thoughts about unused
> drivers is extrapolation. Your logic implication could've been correct,
> but in this case it wasn't because I consider a driver that was
> upstreamed to be part of the kernel, and people invested a fair amount
> of work to get it to that point, so I'm in no hurry to get rid of them.
> Instead, I prefer to give people the benefit of the doubt and assume
> that they had planned to get users upstream and for some reason just
> haven't gotten around to it.
> 
> On the other hand, almost 18-24 months without activity is quite long. A
> compromise that works well for me is to keep drivers, even unused ones,
> as long as they're not getting in the way.
> 
> > Having said that, even in the question at hand (i.e. what is the better
> > compromise for mapping the inter-channel hardware limitations to
> > software policy in the pac9685 driver) the idea "let's inspecting device
> > trees present in the kernel" doesn't work, because for this driver there
> > are none, too. (It might be used by a mainline machine via ACPI, but
> > this is even less possible to consider for our judgements than a device
> > tree with such a device and no user but the sysfs PWM interface.)
> 
> Perhaps Clemens and Sven can shed some light into how this driver is
> being used. There clearly seem to be people interested in this driver,
> so why are there no consumers of this upstream. What's keeping people
> from upstreaming device trees that make use of this?

Our DT using the pca9685 is for an embedded board within a product and
that board within is not sold alone.
That's the reason why I did not upstream it yet, because I did not know
if it is acceptable to upstream DTs for boards that are not really of
great use to other people, because they can't (easily) get the hardware,
unless they buy a big beer dispensing system.
If that's not an issue then I am willig to upstream it of course.

Clemens


Re: [PATCH v4 1/4] pwm: pca9685: Switch to atomic API

2020-12-10 Thread Clemens Gruber
On Thu, Dec 10, 2020 at 06:10:45PM +0100, Thierry Reding wrote:
> On Thu, Dec 10, 2020 at 10:01:24AM +0100, Uwe Kleine-König wrote:
> > Hello Thierry,
> > 
> > On Wed, Dec 09, 2020 at 06:02:16PM +0100, Thierry Reding wrote:
> > > On Tue, Dec 08, 2020 at 07:26:37PM +0100, Uwe Kleine-König wrote:
> > > > Hello Thierry, hello Sven,
> > > > 
> > > > On Tue, Dec 08, 2020 at 05:57:12PM +0100, Thierry Reding wrote:
> > > > > On Tue, Dec 08, 2020 at 09:44:42AM -0500, Sven Van Asbroeck wrote:
> > > > > > Which brings us to an even trickier question: what happens if a pwm 
> > > > > > output
> > > > > > is set to 0% or 100% duty cycle? In that case, it'll behave like a 
> > > > > > gpio output.
> > > > > > So when it's enabled, it does not use the prescaler.
> > > > > > But! what happens if we now set that output to a different duty 
> > > > > > cycle?
> > > > > > 
> > > > > > Example:
> > > > > > 1. output 1: set pwm mode (enabled=true, duty_cycle=50%,  
> > > > > > period=1/200Hz)
> > > > > > 2. output 2: set pwm mode (enabled=true, duty_cycle=100%, 
> > > > > > period=1/400Hz)
> > > > > >   fail? no, because it's not actually using the period (it's full 
> > > > > > on)
> > > > > > 3. output 2: set pwm mode (enabled=true, duty_cycle=100%, 
> > > > > > period=1/200Hz)
> > > > > >   fail? no, because it's not actually using the period (it's full 
> > > > > > on)
> > > > > > 4. output 1: set pwm mode (enabled=true, duty_cycle=50%,  
> > > > > > period=1/400Hz)
> > > > > >   fail? no, because only output 1 is using the prescaler
> > > > > > 5. output 2: set pwm mode (enabled=true, duty_cycle=50%, 
> > > > > > period=1/400Hz)
> > > > > >   fail? no, because output 2 is not changing the prescaler
> > > > > > 6. output 2: set pwm mode (enabled=true, duty_cycle=50%, 
> > > > > > period=1/200Hz)
> > > > > >   fail? yes, because output 2 is changing prescaler and it's 
> > > > > > already in use
> > > > > > 
> > > > > > IMHO all this can get very complicated and tricky.
> > > > > 
> > > > > Is this really that complicated?
> > > > 
> > > > I think it is.
> > > 
> > > Care to specify what exactly is complicated about it? You're just saying
> > > that you don't like the restrictions that this implements, but there's
> > > really nothing we can do about that because the hardware just doesn't
> > > give you that flexibility.
> > 
> > The complicated thing is to chose how to map the hardware imposed
> > limitations to the consumers of the two (or more?) channels. And the
> > problem is there is no golden way that is objectively better than all
> > others.
> > 
> > > > > I sounds to me like the only thing that you need is to have some sort
> > > > > of usage count for the prescaler. Whenever you want to use the
> > > > > prescaler you check that usage count. If it is zero, then you can just
> > > > > set it to whatever you need. If it isn't zero, that means somebody
> > > > > else is already using it and you can't change it, which means you have
> > > > > to check if you're trying to request the value that's already set. If
> > > > > so, you can succeed, but otherwise you'll have to fail.
> > > > 
> > > > With this abstraction Sven's questions are changed to:
> > > > 
> > > > Does a PWM that runs at 0% or 100% use the prescaler?
> > > > 
> > > > If yes, you limit the possibilities of the brother channels. And if not,
> > > > it will not be possible to go to a 50% relative duty cycle while
> > > > retaining the period. Both sounds not optimal.
> > > 
> > > Again, this is a restriction imposed by the hardware design and there's
> > > nothing in software that we can do about that. The only thing I proposed
> > > was a simple way to detect the circumstances and make sure we can deal
> > > with it.
> > 
> > The point I want to make is, that with the usage counter you suggested
> > you just shifted the problem and didn't solve it. I agree we need a
> > usage counter, but you still have to think about how you want to answer
> > the original questions by Sven. Depending on that you have to
> > consider a channel running at 0% or 100% a user, or not.  (Or the other
> > way round: You select a policy if you consider 0% and 100% a use and
> > implicitly answer the questions with it.)
> 
> The way I see it, and I think this matches what was said earlier, we
> have two options:
> 
>   1) Use two channels as proper PWMs. In that case, if they happen to
>  run at the same period, they are free to choose the duty-cycle and
>  can be treated as independent PWM channels. If the run at different
>  periods, one of them can only be used as either full-on or full-off
>  PWM. It would still be a PWM, but just with additional restrictions
>  on the duty cycle.
> 
>   2) Use one channel as full PWM and the other channel as GPIO.
> 
> 2) is a subset of 1) because we can implement 2) using 1) by treating
> the full-on/full-off PWM as a GPIO pin. In my opinion, that makes the
> first policy better because it is more flexible.
> 
> > > 

Re: [PATCH v4 1/4] pwm: pca9685: Switch to atomic API

2020-12-08 Thread Clemens Gruber
Hi everyone,

On Tue, Dec 08, 2020 at 07:26:37PM +0100, Uwe Kleine-König wrote:
> Hello Thierry, hello Sven,
> 
> On Tue, Dec 08, 2020 at 05:57:12PM +0100, Thierry Reding wrote:
> > On Tue, Dec 08, 2020 at 09:44:42AM -0500, Sven Van Asbroeck wrote:
> > > On Tue, Dec 8, 2020 at 4:10 AM Uwe Kleine-König
> > >  wrote:
> > > >
> > > > If this is already in the old code, this probably warrants a separate
> > > > fix, and yes, I consider this a severe bug. (Consider one channel
> > > > driving a motor and reconfiguring an LED modifies the motor's speed.)
> > > >
> > > 
> > > I think you are 100% correct, this would be a severe bug. I have only used
> > > this chip to drive LEDs, where the actual period is not that important. 
> > > But
> > > for motor control, it's a different story.
> > > 
> > > Basically you are suggesting: the period (prescaler) can only be changed 
> > > iff
> > > its use-count is 1.
> > > 
> > > This however brings up a whole load of additional questions: consider the 
> > > case
> > > where the chip outputs are also used in gpio mode. the gpio functionality
> > > only sets "full on" and "full off" bits. On a scope, a gpio output will 
> > > look
> > > identical, no matter the value of the period. So when a gpio output is in 
> > > use,
> > > does it increment the prescaler use-count ?
> > > 
> > > Example:
> > > 1. output 1: set pwm mode (enabled=true, duty_cycle=50%, period=1/200Hz)
> > > 2. output 2: set led mode (full-on bit set)
> > > 3. output 1: change period(enabled=true, duty_cycle=50%, period=1/100Hz)
> > > 
> > > Do we have to make (3) fail? I would say no: although output 2 is in use,
> > > it's not actually using the prescaler. Changing prescale won't modify
> > > output 2 in any way.
> > > 
> > > Which brings us to an even trickier question: what happens if a pwm output
> > > is set to 0% or 100% duty cycle? In that case, it'll behave like a gpio 
> > > output.
> > > So when it's enabled, it does not use the prescaler.
> > > But! what happens if we now set that output to a different duty cycle?
> > > 
> > > Example:
> > > 1. output 1: set pwm mode (enabled=true, duty_cycle=50%,  period=1/200Hz)
> > > 2. output 2: set pwm mode (enabled=true, duty_cycle=100%, period=1/400Hz)
> > >   fail? no, because it's not actually using the period (it's full on)
> > > 3. output 2: set pwm mode (enabled=true, duty_cycle=100%, period=1/200Hz)
> > >   fail? no, because it's not actually using the period (it's full on)
> > > 4. output 1: set pwm mode (enabled=true, duty_cycle=50%,  period=1/400Hz)
> > >   fail? no, because only output 1 is using the prescaler
> > > 5. output 2: set pwm mode (enabled=true, duty_cycle=50%, period=1/400Hz)
> > >   fail? no, because output 2 is not changing the prescaler
> > > 6. output 2: set pwm mode (enabled=true, duty_cycle=50%, period=1/200Hz)
> > >   fail? yes, because output 2 is changing prescaler and it's already in 
> > > use
> > > 
> > > IMHO all this can get very complicated and tricky.
> > 
> > Is this really that complicated?
> 
> I think it is.
> 
> > I sounds to me like the only thing that you need is to have some sort
> > of usage count for the prescaler. Whenever you want to use the
> > prescaler you check that usage count. If it is zero, then you can just
> > set it to whatever you need. If it isn't zero, that means somebody
> > else is already using it and you can't change it, which means you have
> > to check if you're trying to request the value that's already set. If
> > so, you can succeed, but otherwise you'll have to fail.
> 
> With this abstraction Sven's questions are changed to:
> 
> Does a PWM that runs at 0% or 100% use the prescaler?
> 
> If yes, you limit the possibilities of the brother channels. And if not,
> it will not be possible to go to a 50% relative duty cycle while
> retaining the period. Both sounds not optimal.

In my opinion, limiting the possibilities of brother channels is
preferrable to introducing another restriction: Not being able to
reconfigure a duty cycle from 0%/100% to something else while keeping
the previously set period.
Better deny the period change in the first place, even if the duty cycle
is 0% or 100%.

>  
> > > We can of course make this much simpler by assumung that gpio or on/off 
> > > pwms
> > > are actually using the prescaler. But then we'd be limiting this chip's
> > > functionality.
> > 
> > Yeah, this is obviously much simpler, but the cost is a bit high, in my
> > opinion. I'm fine with this alternative if there aren't any use-cases
> > where multiple outputs are actually used.
> 
> This metric is wishy-washy; of course you can construct a use-case. I'd
> still go for this simpler option and assume the prescaler used if the
> PWM runs at 0% or 100%, but not when it is a GPIO.

I'd also prefer this solution.

Thanks,
Clemens


Re: [PATCH v4 1/4] pwm: pca9685: Switch to atomic API

2020-12-08 Thread Clemens Gruber
Hello Uwe,

On Tue, Dec 08, 2020 at 10:10:33AM +0100, Uwe Kleine-König wrote:
> Hello Clemens,
> 
> On Tue, Dec 08, 2020 at 12:13:44AM +0100, Clemens Gruber wrote:
> > On Mon, Dec 07, 2020 at 11:00:25PM +0100, Uwe Kleine-König wrote:
> > > On Mon, Dec 07, 2020 at 08:36:27PM +0100, Clemens Gruber wrote:
> > > > The hardware readout may return slightly different values than those
> > > > that were set in apply due to the limited range of possible prescale and
> > > > counter register values. If one channel is reconfigured with new duty
> > > > cycle and period, the others will keep the same relative duty cycle to
> > > > period ratio as they had before, even though the per-chip / global
> > > > frequency changed. (The PCA9685 has only one prescaler!)
> > > 
> > > This is not acceptable, if you have two PWM outputs and a consumer
> > > modifies one of them the other must change. So if this chip only
> > > supports a single period length of all channels, the first consumer
> > > enabling a channel defines the period to be used. All later consumers
> > > must live with that. (Also the first must be denied modifying the period
> > > if a second consumer has enabled its PWM.)
> > 
> > Good idea, but is it OK to potentially break users relying on the old
> > behavior ("the last one who changes the period wins") ?
> 
> If this is already in the old code, this probably warrants a separate
> fix, and yes, I consider this a severe bug. (Consider one channel
> driving a motor and reconfiguring an LED modifies the motor's speed.)

Yes, but a user could also be relying on the old behavior as follows:
1. Requests & enables pwm 0 for a backlight, using a period of 500ns
   (does not care about the frequency as long as it does not flicker)
2. Requests & enables pwm 1 for a motor, using a period of 100ns
   (does care about the frequency)

In the previous kernel versions, this would work, but with your
suggested change, (2) would fail and the motor would no longer work.

We are basically changing "the last one to set the period wins" to "the
first one to set the period wins".

If we do it like this, I'll split it out so we can at least revert it if
someone complains that it breaks his application, without reverting the
whole series.

Thanks,
Clemens


Re: [PATCH v4 1/4] pwm: pca9685: Switch to atomic API

2020-12-07 Thread Clemens Gruber
Hi Sven,

On Mon, Dec 07, 2020 at 06:22:08PM -0500, Sven Van Asbroeck wrote:
> Hi Clemens, see below.
> 
> On Mon, Dec 7, 2020 at 2:37 PM Clemens Gruber
>  wrote:
> >
> > The switch to the atomic API goes hand in hand with a few fixes to
> > previously experienced issues:
> > - The duty cycle is no longer lost after disable/enable (previously the
> >   OFF registers were cleared in disable and the user was required to
> >   call config to restore the duty cycle settings)
> > - If one sets a period resulting in the same prescale register value,
> >   the sleep and write to the register is now skipped
> > - The prescale register is now set to the default value in probe. On
> >   systems without CONFIG_PM, the chip is woken up at probe time.
> >
> > The hardware readout may return slightly different values than those
> > that were set in apply due to the limited range of possible prescale and
> > counter register values. If one channel is reconfigured with new duty
> > cycle and period, the others will keep the same relative duty cycle to
> > period ratio as they had before, even though the per-chip / global
> > frequency changed. (The PCA9685 has only one prescaler!)
> >
> > Note that although the datasheet mentions 200 Hz as default frequency
> > when using the internal 25 MHz oscillator, the calculated period from
> > the default prescaler register setting of 30 is 5079040ns.
> >
> > Signed-off-by: Clemens Gruber 
> > ---
> > Changes since v3:
> > - Refactoring: Extracted common functions
> > - Read prescale register value instead of caching it
> > - Return all zeros and disabled for "all LEDs" channel state
> > - Improved duty calculation / mapping to 0..4096
> >
> > Changes since v2:
> > - Always set default prescale value in probe
> > - Simplified probe code
> > - Inlined functions with one callsite
> >
> > Changes since v1:
> > - Fixed a logic error
> > - Impoved PM runtime handling and fixed !CONFIG_PM
> > - Write default prescale reg value if invalid in probe
> > - Reuse full_off/_on functions throughout driver
> > - Use cached prescale value whenever possible
> >
> >  drivers/pwm/pwm-pca9685.c | 335 --
> >  1 file changed, 175 insertions(+), 160 deletions(-)
> >
> > diff --git a/drivers/pwm/pwm-pca9685.c b/drivers/pwm/pwm-pca9685.c
> > index 4a55dc18656c..0425e0bcb81e 100644
> > --- a/drivers/pwm/pwm-pca9685.c
> > +++ b/drivers/pwm/pwm-pca9685.c
> > @@ -47,11 +47,11 @@
> >  #define PCA9685_ALL_LED_OFF_H  0xFD
> >  #define PCA9685_PRESCALE   0xFE
> >
> > +#define PCA9685_PRESCALE_DEF   0x1E/* => default frequency of ~200 Hz 
> > */
> >  #define PCA9685_PRESCALE_MIN   0x03/* => max. frequency of 1526 Hz */
> >  #define PCA9685_PRESCALE_MAX   0xFF/* => min. frequency of 24 Hz */
> >
> >  #define PCA9685_COUNTER_RANGE  4096
> > -#define PCA9685_DEFAULT_PERIOD 500 /* Default period_ns = 1/200 Hz */
> >  #define PCA9685_OSC_CLOCK_MHZ  25  /* Internal oscillator with 25 MHz 
> > */
> >
> >  #define PCA9685_NUMREGS0xFF
> > @@ -74,7 +74,6 @@
> >  struct pca9685 {
> > struct pwm_chip chip;
> > struct regmap *regmap;
> > -   int period_ns;
> >  #if IS_ENABLED(CONFIG_GPIOLIB)
> > struct mutex lock;
> > struct gpio_chip gpio;
> > @@ -87,6 +86,81 @@ static inline struct pca9685 *to_pca(struct pwm_chip 
> > *chip)
> > return container_of(chip, struct pca9685, chip);
> >  }
> >
> > +static void pca9685_pwm_set_full_off(struct pca9685 *pca, int index, bool 
> > enable)
> > +{
> > +   unsigned int val = enable ? LED_FULL : 0;
> > +
> > +   /* Note: The full OFF bit has the highest precedence */
> > +
> > +   if (index >= PCA9685_MAXCHAN) {
> > +   regmap_write(pca->regmap, PCA9685_ALL_LED_OFF_H, val);
> > +   return;
> > +   }
> > +   regmap_update_bits(pca->regmap, LED_N_OFF_H(index), LED_FULL, val);
> > +}
> > +
> > +static bool pca9685_pwm_is_full_off(struct pca9685 *pca, int index)
> > +{
> > +   unsigned int val = 0;
> > +
> > +   if (index >= PCA9685_MAXCHAN)
> > +   return false;
> > +
> > +   regmap_read(pca->regmap, LED_N_OFF_H(index), );
> > +   return val & LED_FULL;
> > +}
> > +
> > +static void pca9685_pwm_set_full_on(struct pca9685 *pca, int index, bool 

Re: [PATCH v4 1/4] pwm: pca9685: Switch to atomic API

2020-12-07 Thread Clemens Gruber
On Mon, Dec 07, 2020 at 05:34:58PM -0500, Sven Van Asbroeck wrote:
> Hi Uwe,
> 
> On Mon, Dec 7, 2020 at 5:00 PM Uwe Kleine-König
>  wrote:
> >
> > This is not acceptable, if you have two PWM outputs and a consumer
> > modifies one of them the other must change. So if this chip only
> > supports a single period length of all channels, the first consumer
> > enabling a channel defines the period to be used. All later consumers
> > must live with that. (Also the first must be denied modifying the period
> > if a second consumer has enabled its PWM.)
> 
> That makes sense. However, a possible wrinkle: when more than one pwm channel
> is requested, which one is able to change the period?
> 
> Example:
> 1. start with all pwms free
> 2. pwm_request(0), pwm_apply(period=200Hz)
> 3. pwm_request(1)
> 4. pwm_apply(1, period=400Hz) fails?
> 5. pwm_apply(0, period=400Hz) succeeds?
> 
> And if (5) succeeds, then pwm_get_state(1) will still return period=200Hz,
> because the pwm core doesn't realize anything has changed. Are you ok
> with this behaviour?

I think we'd have to deny the pwm_apply in step 5 as well. So, only the
first consumer is allowed to change the period and only as long as it is
the only one that is in use / was requested.

But that's definitely a breaking change.

Thanks,
Clemens


Re: [PATCH v4 1/4] pwm: pca9685: Switch to atomic API

2020-12-07 Thread Clemens Gruber
On Mon, Dec 07, 2020 at 11:00:25PM +0100, Uwe Kleine-König wrote:
> On Mon, Dec 07, 2020 at 08:36:27PM +0100, Clemens Gruber wrote:
> > The switch to the atomic API goes hand in hand with a few fixes to
> > previously experienced issues:
> > - The duty cycle is no longer lost after disable/enable (previously the
> >   OFF registers were cleared in disable and the user was required to
> >   call config to restore the duty cycle settings)
> > - If one sets a period resulting in the same prescale register value,
> >   the sleep and write to the register is now skipped
> > - The prescale register is now set to the default value in probe. On
> >   systems without CONFIG_PM, the chip is woken up at probe time.
> > 
> > The hardware readout may return slightly different values than those
> > that were set in apply due to the limited range of possible prescale and
> > counter register values. If one channel is reconfigured with new duty
> > cycle and period, the others will keep the same relative duty cycle to
> > period ratio as they had before, even though the per-chip / global
> > frequency changed. (The PCA9685 has only one prescaler!)
> 
> This is not acceptable, if you have two PWM outputs and a consumer
> modifies one of them the other must change. So if this chip only
> supports a single period length of all channels, the first consumer
> enabling a channel defines the period to be used. All later consumers
> must live with that. (Also the first must be denied modifying the period
> if a second consumer has enabled its PWM.)

Good idea, but is it OK to potentially break users relying on the old
behavior ("the last one who changes the period wins") ?

> 
> > Note that although the datasheet mentions 200 Hz as default frequency
> > when using the internal 25 MHz oscillator, the calculated period from
> > the default prescaler register setting of 30 is 5079040ns.
> 
> That means the datasheet is lax because 5079040ns corresponds to
> 196.88760080645162 Hz but it calls that 200 Hz, right?

Yes, it calls prescale setting 0x1E 200 Hz, but calculating the
period from that prescaler setting leads to 5079040ns (196.9 Hz) as you
mentioned.
Also, the datasheet does not specify frequency accuracy / internal
oscillator specifications. I measured about 207 Hz on one chip and about
205 Hz on another with the scope today, when configuring a 5079040ns
period.

> 
> I didn't look in the patch in detail, but get the impression it is more
> complicated than necessary. For example adding improved PM behaviour
> should probably go into a separate patch, also adding the .get_state
> callback should be split out.

Agreed. I'll split it up more in the next revision!

Thanks,
Clemens


[PATCH v4 2/4] pwm: pca9685: Set full OFF bits in probe

2020-12-07 Thread Clemens Gruber
The full OFF bits are set by default in the PCA9685 LEDn_OFF_H
registers at POR. LEDn_ON_L/H and LEDn_OFF_L default to 0.

The datasheet states that LEDn_OFF and LEDn_ON should never be both set
to the same values.

This patch removes the clearing of the full OFF bit in the probe
function. We still clear the rest of the OFF regs but now we set the
full OFF bit to avoid having both OFF and ON registers set to 0 and
start up in a safe default state.

Signed-off-by: Clemens Gruber 
---
Changes since v1:
- Rebased

 drivers/pwm/pwm-pca9685.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/pwm/pwm-pca9685.c b/drivers/pwm/pwm-pca9685.c
index 0425e0bcb81e..fdce5fb9f41e 100644
--- a/drivers/pwm/pwm-pca9685.c
+++ b/drivers/pwm/pwm-pca9685.c
@@ -486,9 +486,9 @@ static int pca9685_pwm_probe(struct i2c_client *client,
reg &= ~(MODE1_ALLCALL | MODE1_SUB1 | MODE1_SUB2 | MODE1_SUB3);
regmap_write(pca->regmap, PCA9685_MODE1, reg);
 
-   /* Clear all "full off" bits */
+   /* Reset OFF registers to HW default (only full OFF bit is set) */
regmap_write(pca->regmap, PCA9685_ALL_LED_OFF_L, 0);
-   regmap_write(pca->regmap, PCA9685_ALL_LED_OFF_H, 0);
+   regmap_write(pca->regmap, PCA9685_ALL_LED_OFF_H, LED_FULL);
 
pca->chip.ops = _pwm_ops;
/* Add an extra channel for ALL_LED */
-- 
2.29.2



[PATCH v4 4/4] dt-bindings: pwm: pca9685: Add nxp,staggered-outputs property

2020-12-07 Thread Clemens Gruber
The pca9685 driver supports a new nxp,staggered-outputs property for
reduced current surges and EMI. This adds documentation for the new DT
property.

Signed-off-by: Clemens Gruber 
---
Changes since v1:
- Added vendor prefix

 Documentation/devicetree/bindings/pwm/nxp,pca9685-pwm.txt | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/Documentation/devicetree/bindings/pwm/nxp,pca9685-pwm.txt 
b/Documentation/devicetree/bindings/pwm/nxp,pca9685-pwm.txt
index f21b55c95738..fafe954369dc 100644
--- a/Documentation/devicetree/bindings/pwm/nxp,pca9685-pwm.txt
+++ b/Documentation/devicetree/bindings/pwm/nxp,pca9685-pwm.txt
@@ -12,6 +12,8 @@ Optional properties:
   - invert (bool): boolean to enable inverted logic
   - open-drain (bool): boolean to configure outputs with open-drain structure;
   if omitted use totem-pole structure
+  - nxp,staggered-outputs (bool): boolean to enable staggered output ON times 
to
+ minimize current surges and EMI
 
 Example:
 
-- 
2.29.2



[PATCH v4 1/4] pwm: pca9685: Switch to atomic API

2020-12-07 Thread Clemens Gruber
The switch to the atomic API goes hand in hand with a few fixes to
previously experienced issues:
- The duty cycle is no longer lost after disable/enable (previously the
  OFF registers were cleared in disable and the user was required to
  call config to restore the duty cycle settings)
- If one sets a period resulting in the same prescale register value,
  the sleep and write to the register is now skipped
- The prescale register is now set to the default value in probe. On
  systems without CONFIG_PM, the chip is woken up at probe time.

The hardware readout may return slightly different values than those
that were set in apply due to the limited range of possible prescale and
counter register values. If one channel is reconfigured with new duty
cycle and period, the others will keep the same relative duty cycle to
period ratio as they had before, even though the per-chip / global
frequency changed. (The PCA9685 has only one prescaler!)

Note that although the datasheet mentions 200 Hz as default frequency
when using the internal 25 MHz oscillator, the calculated period from
the default prescaler register setting of 30 is 5079040ns.

Signed-off-by: Clemens Gruber 
---
Changes since v3:
- Refactoring: Extracted common functions
- Read prescale register value instead of caching it
- Return all zeros and disabled for "all LEDs" channel state
- Improved duty calculation / mapping to 0..4096

Changes since v2:
- Always set default prescale value in probe
- Simplified probe code
- Inlined functions with one callsite

Changes since v1:
- Fixed a logic error
- Impoved PM runtime handling and fixed !CONFIG_PM
- Write default prescale reg value if invalid in probe
- Reuse full_off/_on functions throughout driver
- Use cached prescale value whenever possible

 drivers/pwm/pwm-pca9685.c | 335 --
 1 file changed, 175 insertions(+), 160 deletions(-)

diff --git a/drivers/pwm/pwm-pca9685.c b/drivers/pwm/pwm-pca9685.c
index 4a55dc18656c..0425e0bcb81e 100644
--- a/drivers/pwm/pwm-pca9685.c
+++ b/drivers/pwm/pwm-pca9685.c
@@ -47,11 +47,11 @@
 #define PCA9685_ALL_LED_OFF_H  0xFD
 #define PCA9685_PRESCALE   0xFE
 
+#define PCA9685_PRESCALE_DEF   0x1E/* => default frequency of ~200 Hz */
 #define PCA9685_PRESCALE_MIN   0x03/* => max. frequency of 1526 Hz */
 #define PCA9685_PRESCALE_MAX   0xFF/* => min. frequency of 24 Hz */
 
 #define PCA9685_COUNTER_RANGE  4096
-#define PCA9685_DEFAULT_PERIOD 500 /* Default period_ns = 1/200 Hz */
 #define PCA9685_OSC_CLOCK_MHZ  25  /* Internal oscillator with 25 MHz */
 
 #define PCA9685_NUMREGS0xFF
@@ -74,7 +74,6 @@
 struct pca9685 {
struct pwm_chip chip;
struct regmap *regmap;
-   int period_ns;
 #if IS_ENABLED(CONFIG_GPIOLIB)
struct mutex lock;
struct gpio_chip gpio;
@@ -87,6 +86,81 @@ static inline struct pca9685 *to_pca(struct pwm_chip *chip)
return container_of(chip, struct pca9685, chip);
 }
 
+static void pca9685_pwm_set_full_off(struct pca9685 *pca, int index, bool 
enable)
+{
+   unsigned int val = enable ? LED_FULL : 0;
+
+   /* Note: The full OFF bit has the highest precedence */
+
+   if (index >= PCA9685_MAXCHAN) {
+   regmap_write(pca->regmap, PCA9685_ALL_LED_OFF_H, val);
+   return;
+   }
+   regmap_update_bits(pca->regmap, LED_N_OFF_H(index), LED_FULL, val);
+}
+
+static bool pca9685_pwm_is_full_off(struct pca9685 *pca, int index)
+{
+   unsigned int val = 0;
+
+   if (index >= PCA9685_MAXCHAN)
+   return false;
+
+   regmap_read(pca->regmap, LED_N_OFF_H(index), );
+   return val & LED_FULL;
+}
+
+static void pca9685_pwm_set_full_on(struct pca9685 *pca, int index, bool 
enable)
+{
+   unsigned int val = enable ? LED_FULL : 0;
+
+   if (index >= PCA9685_MAXCHAN) {
+   regmap_write(pca->regmap, PCA9685_ALL_LED_ON_H, val);
+   return;
+   }
+   regmap_update_bits(pca->regmap, LED_N_ON_H(index), LED_FULL, val);
+}
+
+static bool pca9685_pwm_is_full_on(struct pca9685 *pca, int index)
+{
+   unsigned int val = 0;
+
+   if (index >= PCA9685_MAXCHAN)
+   return false;
+
+   regmap_read(pca->regmap, LED_N_ON_H(index), );
+   return val & LED_FULL;
+}
+
+static void pca9685_pwm_set_off_time(struct pca9685 *pca, int index, unsigned 
int off)
+{
+   int reg;
+
+   /* Note: This function also clears the full OFF bit */
+
+   reg = index >= PCA9685_MAXCHAN ?
+   PCA9685_ALL_LED_OFF_L : LED_N_OFF_L(index);
+   regmap_write(pca->regmap, reg, off & 0xff);
+
+   reg = index >= PCA9685_MAXCHAN ?
+   PCA9685_ALL_LED_OFF_H : LED_N_OFF_H(index);
+   regmap_write(pca->regmap, reg, (off >> 8) & 0xf);
+}
+
+static unsigned int pca9685_pwm_off_time(struct pca9685 *pca, int index)
+{
+   unsigned

[PATCH v4 3/4] pwm: pca9685: Support staggered output ON times

2020-12-07 Thread Clemens Gruber
The PCA9685 supports staggered LED output ON times to minimize current
surges and reduce EMI.
When this new option is enabled, the ON times of each channel are
delayed by channel number x counter range / 16, which avoids asserting
all enabled outputs at the same counter value while still maintaining
the configured duty cycle of each output.

Signed-off-by: Clemens Gruber 
---
Changes since v3:
- Refactoring: Extracted common functions
- Fixed error in .get_state
- Added vendor prefix to DT property

Changes since v1:
- Rebased

 drivers/pwm/pwm-pca9685.c | 72 +--
 1 file changed, 69 insertions(+), 3 deletions(-)

diff --git a/drivers/pwm/pwm-pca9685.c b/drivers/pwm/pwm-pca9685.c
index fdce5fb9f41e..2697138ee95a 100644
--- a/drivers/pwm/pwm-pca9685.c
+++ b/drivers/pwm/pwm-pca9685.c
@@ -74,6 +74,7 @@
 struct pca9685 {
struct pwm_chip chip;
struct regmap *regmap;
+   bool staggered_outputs;
 #if IS_ENABLED(CONFIG_GPIOLIB)
struct mutex lock;
struct gpio_chip gpio;
@@ -161,6 +162,35 @@ static unsigned int pca9685_pwm_off_time(struct pca9685 
*pca, int index)
return off | (val & 0xff);
 }
 
+static void pca9685_pwm_set_on_time(struct pca9685 *pca, int index, unsigned 
int on)
+{
+   int reg;
+
+   /* Note: This function also clears the full ON bit */
+
+   reg = index >= PCA9685_MAXCHAN ?
+   PCA9685_ALL_LED_ON_L : LED_N_ON_L(index);
+   regmap_write(pca->regmap, reg, on & 0xff);
+
+   reg = index >= PCA9685_MAXCHAN ?
+   PCA9685_ALL_LED_ON_H : LED_N_ON_H(index);
+   regmap_write(pca->regmap, reg, (on >> 8) & 0xf);
+}
+
+static unsigned int pca9685_pwm_on_time(struct pca9685 *pca, int index)
+{
+   unsigned int on, val = 0;
+
+   if (index >= PCA9685_MAXCHAN)
+   return 0;
+
+   regmap_read(pca->regmap, LED_N_ON_H(index), );
+   on = (val & 0xf) << 8;
+
+   regmap_read(pca->regmap, LED_N_ON_L(index), );
+   return on | (val & 0xff);
+}
+
 #if IS_ENABLED(CONFIG_GPIOLIB)
 static bool pca9685_pwm_test_and_set_inuse(struct pca9685 *pca, int pwm_idx)
 {
@@ -322,7 +352,7 @@ static void pca9685_pwm_get_state(struct pwm_chip *chip, 
struct pwm_device *pwm,
 {
struct pca9685 *pca = to_pca(chip);
unsigned long long duty;
-   unsigned int val = 0;
+   unsigned int on, off, val = 0;
 
/* Calculate (chip-wide) period from prescale value */
regmap_read(pca->regmap, PCA9685_PRESCALE, );
@@ -349,7 +379,19 @@ static void pca9685_pwm_get_state(struct pwm_chip *chip, 
struct pwm_device *pwm,
return;
}
 
-   duty = pca9685_pwm_off_time(pca, pwm->hwpwm) * state->period;
+   off = pca9685_pwm_off_time(pca, pwm->hwpwm);
+
+   if (pca->staggered_outputs) {
+   on = pca9685_pwm_on_time(pca, pwm->hwpwm);
+
+   if (off >= on)
+   duty = off - on;
+   else
+   duty = off + PCA9685_COUNTER_RANGE - on;
+   } else
+   duty = off;
+
+   duty *= state->period;
state->duty_cycle = duty / PCA9685_COUNTER_RANGE;
 }
 
@@ -358,7 +400,7 @@ static int pca9685_pwm_apply(struct pwm_chip *chip, struct 
pwm_device *pwm,
 {
struct pca9685 *pca = to_pca(chip);
unsigned long long duty, prescale;
-   unsigned int val = 0;
+   unsigned int on, off, val = 0;
 
if (state->polarity != PWM_POLARITY_NORMAL)
return -EOPNOTSUPP;
@@ -405,6 +447,24 @@ static int pca9685_pwm_apply(struct pwm_chip *chip, struct 
pwm_device *pwm,
return 0;
}
 
+   if (pca->staggered_outputs) {
+   if (pwm->hwpwm < PCA9685_MAXCHAN) {
+   /*
+* To reduce EMI, the ON times of each channel are
+* spread out evenly within the counter range, while
+* still maintaining the configured duty cycle
+*/
+   on = pwm->hwpwm * PCA9685_COUNTER_RANGE / 
PCA9685_MAXCHAN;
+   off = (on + duty) % PCA9685_COUNTER_RANGE;
+   pca9685_pwm_set_on_time(pca, pwm->hwpwm, on);
+   pca9685_pwm_set_off_time(pca, pwm->hwpwm, off);
+   return 0;
+   }
+
+   /* No staggering possible if "all LEDs" channel is used */
+   pca9685_pwm_set_on_time(pca, PCA9685_MAXCHAN, 0);
+   }
+
pca9685_pwm_set_off_time(pca, pwm->hwpwm, duty);
/* Clear full ON bit after OFF time was set */
pca9685_pwm_set_full_on(pca, pwm->hwpwm, false);
@@ -481,6 +541,9 @@ static int pca9685_pwm_probe(struct i2c_client *client,
 
regmap_write(pca->regmap, PCA9685_MODE2, reg);
 
+   pca->staggered_outputs = device_property_

Re: [PATCH v3 1/4] pwm: pca9685: Switch to atomic API

2020-11-25 Thread Clemens Gruber
Hi Sven,

On Wed, Nov 25, 2020 at 10:04:32AM -0500, Sven Van Asbroeck wrote:
> On Wed, Nov 25, 2020 at 3:35 AM Clemens Gruber
>  wrote:
> >
> > >
> > > The datasheet I found for this chip indicates that every ALL_LED_XXX 
> > > register
> > > is write-only. Those registers cannot be read back from the chip.
> > >
> > > Datasheet "Rev. 4 - 16 April 2015"
> >
> > Thanks, good catch! Would you agree that we should just return 0 duty
> > cycle and disabled state if the "all LEDs" channel is used?
> 
> I think get_state() for the all led channel should just return -ENOTSUPP,
> if the pwm core will allow that.
> 
> Because it's the truth, the chip does not support reading from the all led
> channel.

I thought about that too, but get_state is a void function and there is
no error/errno variable in pwm_state that could signal a problem.

> 
> When we start buffering the all led state, we make the code much
> more complex, and again we'll run into all sorts of subtle corner cases.

What's the lesser evil in your opinion, always returning 0 duty and
disabled for the ALL channel or caching it?

> 
> > > > +
> > > > +   if (duty < PCA9685_COUNTER_RANGE) {
> > >
> > > How can duty >= 4096 ?
> > >
> > > > +   duty *= state->period;
> > > > +   state->duty_cycle = duty / (PCA9685_COUNTER_RANGE - 1);
> > >
> > > is this calculation correct?
> > > imagine led_on = 0 (default), and led_off = 4095
> > > then the led is off for one single tick per cycle
> > > but the above formula would calculate it as full on (period == 
> > > duty_cycle)?
> 
> I just wanted to make sure you hadn't overlooked the two comments above.

Yes I saw them, thanks. You are suggesting that we change the scaling of
the relative duty cycle from 0..4095 to 0..4096 and in .apply_state we
do full OFF if 0 and full ON if 4096, so we still have a 4095 duty state
with a single tick off?
Then in .get_state: duty_cycle = (duty * period) / COUNTER_RANGE

Please let me know if I misunderstood you.

> 
> --
> 
> Each time I read the code, my thoughts get interrupted by all this
> if hwpwm >= MAXCHAN then { one macro } else { another macro } business
> which is spread around in the code !
> 
> Same thing with the splitting of the value between H and L registers.
> Same thing with the LED_FULL bit.

Yes, this is indeed confusing.

> 
> Maybe the code will be much more readable if we do the following?
> 
> - keep pca9685_pwm_full_off/full_on but rename to pca9685_pwm_set_full_off/on
> - create pca9685_pwm_is_full_off/on
> - create pca9685_pwm_set_on_time/set_off_time
> 
> Then LED_FULL, >= MAXCHAN, and register splits are fully confined to
> these functions, and we can call them freely in the rest of the code,
> without getting confused by these details.

Great idea!

> 
> --
> 
> > I noticed something else that does not look great:
> > Let's say you set up pwm channel 0 with a period of 500 and after
> > that you set up pwm channel 1 with a period of 4000.
> > So far so good. But if you now set pwm channel 0's period to 500
> > again, the period stays at 4000. (Tested with /sys/class/pwm)
> >
> 
> If the driver isn't buggy, this should work ok. Changing the period on one
> channel changes the global prescale, which in turn changes the period on
> every other channel. But that's ok, because the ON/OFF times are relative
> to a 4096-tick counter, so all duty cycles are preserved.
> 
> Example:
> 1. SET channel 0 : duty  50_000 period 100_000 (real duty cycle = 0.5)
> 2. SET channel 1 : duty  50_000 period 200_000 (real duty cycle = 0.25)
> 3. GET channel 0 : duty 100_000 period 200_000 (real duty cycle STILL 0.5)
> 
> I think this is acceptable behaviour.

Yes the effect of a global period change to the duty cycles of other
channels is acceptable but that was not what I meant.

I meant that with sysfs, the period does not change if the new value is
the same as the last time that channel's period was set.
See my example above.

But we probably can't do anything about that.

> 
> --
> 
> I have been thinking about how this patch caches the global prescaler.
> There is a possible synchronization issue. Sysfs will always work ok, because
> it uses a mutex to protect accesses to pwm_set_state(), which means 
> set_state()
> will never be called concurrently.
> 
> But I do not think there's any protection when the driver is used as a client
> in the devicetree, like so:
> 
>  {
> my_pca: pwm@0 {
> compatible = "nxp,pca9685-pwm&qu

Re: [PATCH v3 1/4] pwm: pca9685: Switch to atomic API

2020-11-25 Thread Clemens Gruber
On Wed, Nov 25, 2020 at 09:35:08AM +0100, Clemens Gruber wrote:
> On Tue, Nov 24, 2020 at 10:49:27PM -0500, Sven Van Asbroeck wrote:
> > Hi Clemens, I checked the patch against the datasheet register definitions.
> > More constructive feedback below.
> > 
> > On Tue, Nov 24, 2020 at 1:10 PM Clemens Gruber
> >  wrote:
> > >
> > > The switch to the atomic API goes hand in hand with a few fixes to
> > > previously experienced issues:
> > > - The duty cycle is no longer lost after disable/enable (previously the
> > >   OFF registers were cleared in disable and the user was required to
> > >   call config to restore the duty cycle settings)
> > > - If one sets a period resulting in the same prescale register value,
> > >   the sleep and write to the register is now skipped
> > > - The prescale register is now set to the default value in probe. On
> > >   systems without CONFIG_PM, the chip is woken up at probe time.
> > >
> > > The hardware readout may return slightly different values than those
> > > that were set in apply due to the limited range of possible prescale and
> > > counter register values. If one channel is reconfigured with new duty
> > > cycle and period, the others will keep the same relative duty cycle to
> > > period ratio as they had before, even though the per-chip / global
> > > frequency changed. (The PCA9685 has only one prescaler!)
> > >
> > > Note that although the datasheet mentions 200 Hz as default frequency
> > > when using the internal 25 MHz oscillator, the calculated period from
> > > the default prescaler register setting of 30 is 5079040ns.
> > >
> > > Signed-off-by: Clemens Gruber 
> > > ---
> > > Changes since v2:
> > > - Always set default prescale value in probe
> > > - Simplified probe code
> > > - Inlined functions with one callsite
> > >
> > > Changes since v1:
> > > - Fixed a logic error
> > > - Impoved PM runtime handling and fixed !CONFIG_PM
> > > - Write default prescale reg value if invalid in probe
> > > - Reuse full_off/_on functions throughout driver
> > > - Use cached prescale value whenever possible
> > >
> > >  drivers/pwm/pwm-pca9685.c | 251 +++---
> > >  1 file changed, 128 insertions(+), 123 deletions(-)
> > >
> > > diff --git a/drivers/pwm/pwm-pca9685.c b/drivers/pwm/pwm-pca9685.c
> > > index 4a55dc18656c..4cfbf1467f15 100644
> > > --- a/drivers/pwm/pwm-pca9685.c
> > > +++ b/drivers/pwm/pwm-pca9685.c
> > > @@ -47,11 +47,11 @@
> > >  #define PCA9685_ALL_LED_OFF_H  0xFD
> > >  #define PCA9685_PRESCALE   0xFE
> > >
> > > +#define PCA9685_PRESCALE_DEF   0x1E/* => default frequency of ~200 
> > > Hz */
> > >  #define PCA9685_PRESCALE_MIN   0x03/* => max. frequency of 1526 Hz */
> > >  #define PCA9685_PRESCALE_MAX   0xFF/* => min. frequency of 24 Hz */
> > >
> > >  #define PCA9685_COUNTER_RANGE  4096
> > > -#define PCA9685_DEFAULT_PERIOD 500 /* Default period_ns = 1/200 Hz */
> > >  #define PCA9685_OSC_CLOCK_MHZ  25  /* Internal oscillator with 25 
> > > MHz */
> > >
> > >  #define PCA9685_NUMREGS0xFF
> > > @@ -74,7 +74,7 @@
> > >  struct pca9685 {
> > > struct pwm_chip chip;
> > > struct regmap *regmap;
> > > -   int period_ns;
> > > +   int prescale;
> > >  #if IS_ENABLED(CONFIG_GPIOLIB)
> > > struct mutex lock;
> > > struct gpio_chip gpio;
> > > @@ -87,6 +87,54 @@ static inline struct pca9685 *to_pca(struct pwm_chip 
> > > *chip)
> > > return container_of(chip, struct pca9685, chip);
> > >  }
> > >
> > > +static void pca9685_pwm_full_off(struct pca9685 *pca, int index)
> > > +{
> > > +   int reg;
> > > +
> > > +   /*
> > > +* Set the full OFF bit to cause the PWM channel to be always off.
> > > +* The full OFF bit has precedence over the other register values.
> > > +*/
> > > +
> > > +   if (index >= PCA9685_MAXCHAN)
> > > +   reg = PCA9685_ALL_LED_OFF_H;
> > > +   else
> > > +   reg = LED_N_OFF_H(index);
> > > +
> > > +   regmap_write(pca->regmap, reg, LED_FULL);
> > > +}
> > > +
> > > +static void pca9685_pwm_full_on(st

Re: [PATCH v3 3/4] pwm: pca9685: Support staggered output ON times

2020-11-25 Thread Clemens Gruber
On Tue, Nov 24, 2020 at 10:51:23PM -0500, Sven Van Asbroeck wrote:
> On Tue, Nov 24, 2020 at 1:10 PM Clemens Gruber
>  wrote:
> >
> > The PCA9685 supports staggered LED output ON times to minimize current
> > surges and reduce EMI.
> > When this new option is enabled, the ON times of each channel are
> > delayed by channel number x counter range / 16, which avoids asserting
> > all enabled outputs at the same counter value while still maintaining
> > the configured duty cycle of each output.
> >
> > Signed-off-by: Clemens Gruber 
> > ---
> >
> > Changes since v1:
> > - Rebased
> >
> >  drivers/pwm/pwm-pca9685.c | 35 ++-
> >  1 file changed, 34 insertions(+), 1 deletion(-)
> >
> > diff --git a/drivers/pwm/pwm-pca9685.c b/drivers/pwm/pwm-pca9685.c
> > index 2b82b35ff0de..37c80bc8edcf 100644
> > --- a/drivers/pwm/pwm-pca9685.c
> > +++ b/drivers/pwm/pwm-pca9685.c
> > @@ -75,6 +75,7 @@ struct pca9685 {
> > struct pwm_chip chip;
> > struct regmap *regmap;
> > int prescale;
> > +   bool staggered_outputs;
> >  #if IS_ENABLED(CONFIG_GPIOLIB)
> > struct mutex lock;
> > struct gpio_chip gpio;
> > @@ -329,7 +330,7 @@ static int pca9685_pwm_apply(struct pwm_chip *chip, 
> > struct pwm_device *pwm,
> >  {
> > struct pca9685 *pca = to_pca(chip);
> > unsigned long long duty, prescale;
> > -   unsigned int reg;
> > +   unsigned int on, off, reg;
> >
> > if (state->polarity != PWM_POLARITY_NORMAL)
> > return -EOPNOTSUPP;
> > @@ -375,6 +376,32 @@ static int pca9685_pwm_apply(struct pwm_chip *chip, 
> > struct pwm_device *pwm,
> > duty = (PCA9685_COUNTER_RANGE - 1) * state->duty_cycle;
> > duty = DIV_ROUND_UP_ULL(duty, state->period);
> >
> > +   if (pca->staggered_outputs) {
> > +   if (pwm->hwpwm < PCA9685_MAXCHAN) {
> > +   /*
> > +* To reduce EMI, the ON times of each channel are
> > +* spread out evenly within the counter range, while
> > +* still maintaining the configured duty cycle
> > +*/
> > +   on = pwm->hwpwm * PCA9685_COUNTER_RANGE /
> > +   PCA9685_MAXCHAN;
> > +   off = (on + duty) % PCA9685_COUNTER_RANGE;
> 
> Will pwm_get_state() still return the correct duty cycle in case
> of staggered outputs?

No, but it should. I will improve the get_state function in the next
version to cover all cases.

Thanks for your input. This would have been a mess without your feedback
;)

> 
> > +   regmap_write(pca->regmap, LED_N_ON_L(pwm->hwpwm),
> > +on & 0xff);
> > +   regmap_write(pca->regmap, LED_N_ON_H(pwm->hwpwm),
> > +(on >> 8) & 0xf);
> > +   regmap_write(pca->regmap, LED_N_OFF_L(pwm->hwpwm),
> > +off & 0xff);
> > +   regmap_write(pca->regmap, LED_N_OFF_H(pwm->hwpwm),
> > +(off >> 8) & 0xf);
> > +   return 0;
> > +   }
> > +
> > +   /* No staggering possible if "all LEDs" channel is used */
> > +   regmap_write(pca->regmap, PCA9685_ALL_LED_ON_L, 0);
> > +   regmap_write(pca->regmap, PCA9685_ALL_LED_ON_H, 0);
> > +   }
> > +
> > if (pwm->hwpwm >= PCA9685_MAXCHAN)
> > reg = PCA9685_ALL_LED_OFF_L;
> > else
> > @@ -470,6 +497,9 @@ static int pca9685_pwm_probe(struct i2c_client *client,
> >
> > regmap_write(pca->regmap, PCA9685_MODE2, reg);
> >
> > +   pca->staggered_outputs = device_property_read_bool(
> > +   >dev, "staggered-outputs");
> > +
> > /* Disable all LED ALLCALL and SUBx addresses to avoid bus 
> > collisions */
> > regmap_read(pca->regmap, PCA9685_MODE1, );
> > reg &= ~(MODE1_ALLCALL | MODE1_SUB1 | MODE1_SUB2 | MODE1_SUB3);
> > @@ -478,6 +508,9 @@ static int pca9685_pwm_probe(struct i2c_client *client,
> > /* Reset OFF registers to HW default (only full OFF bit is set) */
> > regmap_write(pca->regmap, PCA9685_ALL_LED_OFF_L, 0);
> > regmap_write(pca->regmap, PCA9685_ALL_LED_OFF_H, LED_FULL);
> > +   /* Reset ON registers to HW default */
> > +   regmap_write(pca->regmap, PCA9685_ALL_LED_ON_L, 0);
> > +   regmap_write(pca->regmap, PCA9685_ALL_LED_ON_H, 0);
> >
> > pca->chip.ops = _pwm_ops;
> > /* Add an extra channel for ALL_LED */
> > --
> > 2.29.2
> >


  1   2   3   4   >