[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20210329125707.182732-2-clemens.gruber@pqgruber.com>
Date: Mon, 29 Mar 2021 14:57:02 +0200
From: Clemens Gruber <clemens.gruber@...ruber.com>
To: linux-pwm@...r.kernel.org
Cc: Thierry Reding <thierry.reding@...il.com>,
Sven Van Asbroeck <TheSven73@...il.com>,
u.kleine-koenig@...gutronix.de, linux-kernel@...r.kernel.org,
Clemens Gruber <clemens.gruber@...ruber.com>
Subject: [PATCH v6 2/7] pwm: pca9685: Support hardware readout
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 <clemens.gruber@...ruber.com>
---
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, &val);
+ 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
Powered by blists - more mailing lists