[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-ID: <20250805065032.193766-1-biju.das.jz@bp.renesas.com>
Date: Tue, 5 Aug 2025 07:50:23 +0100
From: Biju <biju.das.au@...il.com>
To: Uwe Kleine-König <ukleinek@...nel.org>
Cc: Biju Das <biju.das.jz@...renesas.com>,
linux-pwm@...r.kernel.org,
linux-kernel@...r.kernel.org,
Geert Uytterhoeven <geert+renesas@...der.be>,
Prabhakar Mahadev Lad <prabhakar.mahadev-lad.rj@...renesas.com>,
Biju Das <biju.das.au@...il.com>,
linux-renesas-soc@...r.kernel.org
Subject: [PATCH] pwm: rzg2l-gpt: Implementation of the waveform callbacks
From: Biju Das <biju.das.jz@...renesas.com>
Convert the rzg2l-gpt driver to use the new callbacks for hardware
programming.
Signed-off-by: Biju Das <biju.das.jz@...renesas.com>
---
drivers/pwm/pwm-rzg2l-gpt.c | 174 +++++++++++++++++++++---------------
1 file changed, 101 insertions(+), 73 deletions(-)
diff --git a/drivers/pwm/pwm-rzg2l-gpt.c b/drivers/pwm/pwm-rzg2l-gpt.c
index 360c8bf3b190..a34a541da8c3 100644
--- a/drivers/pwm/pwm-rzg2l-gpt.c
+++ b/drivers/pwm/pwm-rzg2l-gpt.c
@@ -86,6 +86,13 @@ struct rzg2l_gpt_chip {
u32 channel_enable_count[RZG2L_MAX_HW_CHANNELS];
};
+/* This represents a hardware configuration for one channel */
+struct rzg2l_gpt_waveform {
+ u32 gtpr;
+ u32 gtccr;
+ u8 prescale;
+};
+
static inline struct rzg2l_gpt_chip *to_rzg2l_gpt_chip(struct pwm_chip *chip)
{
return pwmchip_get_drvdata(chip);
@@ -190,8 +197,10 @@ static void rzg2l_gpt_disable(struct rzg2l_gpt_chip *rzg2l_gpt,
/* Stop count, Output low on GTIOCx pin when counting stops */
rzg2l_gpt->channel_enable_count[ch]--;
- if (!rzg2l_gpt->channel_enable_count[ch])
+ if (!rzg2l_gpt->channel_enable_count[ch]) {
rzg2l_gpt_modify(rzg2l_gpt, RZG2L_GTCR(ch), RZG2L_GTCR_CST, 0);
+ rzg2l_gpt->period_ticks[ch] = 0;
+ }
/* Disable pin output */
rzg2l_gpt_modify(rzg2l_gpt, RZG2L_GTIOR(ch), RZG2L_GTIOR_OxE(sub_ch), 0);
@@ -215,54 +224,38 @@ static u64 rzg2l_gpt_calculate_period_or_duty(struct rzg2l_gpt_chip *rzg2l_gpt,
return DIV64_U64_ROUND_UP(tmp, rzg2l_gpt->rate_khz);
}
-static int rzg2l_gpt_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
- struct pwm_state *state)
-{
- struct rzg2l_gpt_chip *rzg2l_gpt = to_rzg2l_gpt_chip(chip);
-
- state->enabled = rzg2l_gpt_is_ch_enabled(rzg2l_gpt, pwm->hwpwm);
- if (state->enabled) {
- u32 sub_ch = rzg2l_gpt_subchannel(pwm->hwpwm);
- u32 ch = RZG2L_GET_CH(pwm->hwpwm);
- u8 prescale;
- u32 val;
-
- val = rzg2l_gpt_read(rzg2l_gpt, RZG2L_GTCR(ch));
- prescale = FIELD_GET(RZG2L_GTCR_TPCS, val);
-
- val = rzg2l_gpt_read(rzg2l_gpt, RZG2L_GTPR(ch));
- state->period = rzg2l_gpt_calculate_period_or_duty(rzg2l_gpt, val, prescale);
-
- val = rzg2l_gpt_read(rzg2l_gpt, RZG2L_GTCCR(ch, sub_ch));
- state->duty_cycle = rzg2l_gpt_calculate_period_or_duty(rzg2l_gpt, val, prescale);
- if (state->duty_cycle > state->period)
- state->duty_cycle = state->period;
- }
-
- state->polarity = PWM_POLARITY_NORMAL;
-
- return 0;
-}
-
static u32 rzg2l_gpt_calculate_pv_or_dc(u64 period_or_duty_cycle, u8 prescale)
{
return min_t(u64, DIV_ROUND_DOWN_ULL(period_or_duty_cycle, 1 << (2 * prescale)),
U32_MAX);
}
-/* Caller holds the lock while calling rzg2l_gpt_config() */
-static int rzg2l_gpt_config(struct pwm_chip *chip, struct pwm_device *pwm,
- const struct pwm_state *state)
+static int rzg2l_gpt_round_waveform_tohw(struct pwm_chip *chip,
+ struct pwm_device *pwm,
+ const struct pwm_waveform *wf,
+ void *_wfhw)
+
{
struct rzg2l_gpt_chip *rzg2l_gpt = to_rzg2l_gpt_chip(chip);
- u8 sub_ch = rzg2l_gpt_subchannel(pwm->hwpwm);
+ struct rzg2l_gpt_waveform *wfhw = _wfhw;
u8 ch = RZG2L_GET_CH(pwm->hwpwm);
u64 period_ticks, duty_ticks;
unsigned long pv, dc;
- u8 prescale;
+
+ guard(mutex)(&rzg2l_gpt->lock);
+ if (wf->period_length_ns == 0) {
+ *wfhw = (struct rzg2l_gpt_waveform){
+ .gtpr = 0,
+ .gtccr = 0,
+ };
+
+ if (rzg2l_gpt_is_ch_enabled(rzg2l_gpt, pwm->hwpwm))
+ rzg2l_gpt_disable(rzg2l_gpt, pwm);
+ return 0;
+ }
/* Limit period/duty cycle to max value supported by the HW */
- period_ticks = mul_u64_u64_div_u64(state->period, rzg2l_gpt->rate_khz, USEC_PER_SEC);
+ period_ticks = mul_u64_u64_div_u64(wf->period_length_ns, rzg2l_gpt->rate_khz, USEC_PER_SEC);
if (period_ticks > RZG2L_MAX_TICKS)
period_ticks = RZG2L_MAX_TICKS;
/*
@@ -277,13 +270,14 @@ static int rzg2l_gpt_config(struct pwm_chip *chip, struct pwm_device *pwm,
period_ticks = rzg2l_gpt->period_ticks[ch];
}
- prescale = rzg2l_gpt_calculate_prescale(rzg2l_gpt, period_ticks);
- pv = rzg2l_gpt_calculate_pv_or_dc(period_ticks, prescale);
-
- duty_ticks = mul_u64_u64_div_u64(state->duty_cycle, rzg2l_gpt->rate_khz, USEC_PER_SEC);
+ wfhw->prescale = rzg2l_gpt_calculate_prescale(rzg2l_gpt, period_ticks);
+ pv = rzg2l_gpt_calculate_pv_or_dc(period_ticks, wfhw->prescale);
+ wfhw->gtpr = pv;
+ duty_ticks = mul_u64_u64_div_u64(wf->duty_length_ns, rzg2l_gpt->rate_khz, USEC_PER_SEC);
if (duty_ticks > period_ticks)
duty_ticks = period_ticks;
- dc = rzg2l_gpt_calculate_pv_or_dc(duty_ticks, prescale);
+ dc = rzg2l_gpt_calculate_pv_or_dc(duty_ticks, wfhw->prescale);
+ wfhw->gtccr = dc;
/*
* GPT counter is shared by multiple channels, we cache the period ticks
@@ -292,6 +286,58 @@ static int rzg2l_gpt_config(struct pwm_chip *chip, struct pwm_device *pwm,
*/
rzg2l_gpt->period_ticks[ch] = period_ticks;
+ return 0;
+}
+
+static int rzg2l_gpt_round_waveform_fromhw(struct pwm_chip *chip,
+ struct pwm_device *pwm,
+ const void *_wfhw,
+ struct pwm_waveform *wf)
+{
+ struct rzg2l_gpt_chip *rzg2l_gpt = to_rzg2l_gpt_chip(chip);
+ const struct rzg2l_gpt_waveform *wfhw = _wfhw;
+
+ wf->period_length_ns = rzg2l_gpt_calculate_period_or_duty(rzg2l_gpt, wfhw->gtpr,
+ wfhw->prescale);
+ wf->duty_length_ns = rzg2l_gpt_calculate_period_or_duty(rzg2l_gpt, wfhw->gtccr,
+ wfhw->prescale);
+ wf->duty_offset_ns = 0;
+
+ return 0;
+}
+
+static int rzg2l_gpt_read_waveform(struct pwm_chip *chip,
+ struct pwm_device *pwm,
+ void *_wfhw)
+{
+ struct rzg2l_gpt_chip *rzg2l_gpt = to_rzg2l_gpt_chip(chip);
+ struct rzg2l_gpt_waveform *wfhw = _wfhw;
+ u32 sub_ch = rzg2l_gpt_subchannel(pwm->hwpwm);
+ u32 ch = RZG2L_GET_CH(pwm->hwpwm);
+ u32 gtcr;
+
+ if (rzg2l_gpt_is_ch_enabled(rzg2l_gpt, pwm->hwpwm)) {
+ gtcr = rzg2l_gpt_read(rzg2l_gpt, RZG2L_GTCR(ch));
+ wfhw->prescale = FIELD_GET(RZG2L_GTCR_TPCS, gtcr);
+ wfhw->gtpr = rzg2l_gpt_read(rzg2l_gpt, RZG2L_GTPR(ch));
+ wfhw->gtccr = rzg2l_gpt_read(rzg2l_gpt, RZG2L_GTCCR(ch, sub_ch));
+ if (wfhw->gtccr > wfhw->gtpr)
+ wfhw->gtccr = wfhw->gtpr;
+ }
+
+ return 0;
+}
+
+static int rzg2l_gpt_write_waveform(struct pwm_chip *chip,
+ struct pwm_device *pwm,
+ const void *_wfhw)
+{
+ struct rzg2l_gpt_chip *rzg2l_gpt = to_rzg2l_gpt_chip(chip);
+ const struct rzg2l_gpt_waveform *wfhw = _wfhw;
+ u8 sub_ch = rzg2l_gpt_subchannel(pwm->hwpwm);
+ u8 ch = RZG2L_GET_CH(pwm->hwpwm);
+
+ guard(mutex)(&rzg2l_gpt->lock);
/*
* Counter must be stopped before modifying mode, prescaler, timer
* counter and buffer enable registers. These registers are shared
@@ -310,14 +356,14 @@ static int rzg2l_gpt_config(struct pwm_chip *chip, struct pwm_device *pwm,
/* Select count clock */
rzg2l_gpt_modify(rzg2l_gpt, RZG2L_GTCR(ch), RZG2L_GTCR_TPCS,
- FIELD_PREP(RZG2L_GTCR_TPCS, prescale));
+ FIELD_PREP(RZG2L_GTCR_TPCS, wfhw->prescale));
/* Set period */
- rzg2l_gpt_write(rzg2l_gpt, RZG2L_GTPR(ch), pv);
+ rzg2l_gpt_write(rzg2l_gpt, RZG2L_GTPR(ch), wfhw->gtpr);
}
/* Set duty cycle */
- rzg2l_gpt_write(rzg2l_gpt, RZG2L_GTCCR(ch, sub_ch), dc);
+ rzg2l_gpt_write(rzg2l_gpt, RZG2L_GTCCR(ch, sub_ch), wfhw->gtccr);
if (rzg2l_gpt->channel_enable_count[ch] <= 1) {
/* Set initial value for counter */
@@ -326,44 +372,26 @@ static int rzg2l_gpt_config(struct pwm_chip *chip, struct pwm_device *pwm,
/* Set no buffer operation */
rzg2l_gpt_write(rzg2l_gpt, RZG2L_GTBER(ch), 0);
- /* Restart the counter after updating the registers */
- rzg2l_gpt_modify(rzg2l_gpt, RZG2L_GTCR(ch),
- RZG2L_GTCR_CST, RZG2L_GTCR_CST);
- }
-
- return 0;
-}
-
-static int rzg2l_gpt_apply(struct pwm_chip *chip, struct pwm_device *pwm,
- const struct pwm_state *state)
-{
- struct rzg2l_gpt_chip *rzg2l_gpt = to_rzg2l_gpt_chip(chip);
- bool enabled = pwm->state.enabled;
- int ret;
-
- if (state->polarity != PWM_POLARITY_NORMAL)
- return -EINVAL;
-
- guard(mutex)(&rzg2l_gpt->lock);
- if (!state->enabled) {
- if (enabled)
- rzg2l_gpt_disable(rzg2l_gpt, pwm);
-
- return 0;
+ if (wfhw->gtpr)
+ /* Restart the counter after updating the registers */
+ rzg2l_gpt_modify(rzg2l_gpt, RZG2L_GTCR(ch),
+ RZG2L_GTCR_CST, RZG2L_GTCR_CST);
}
- ret = rzg2l_gpt_config(chip, pwm, state);
- if (!ret && !enabled)
+ if (wfhw->gtpr && !rzg2l_gpt_is_ch_enabled(rzg2l_gpt, pwm->hwpwm))
rzg2l_gpt_enable(rzg2l_gpt, pwm);
- return ret;
+ return 0;
}
static const struct pwm_ops rzg2l_gpt_ops = {
.request = rzg2l_gpt_request,
.free = rzg2l_gpt_free,
- .get_state = rzg2l_gpt_get_state,
- .apply = rzg2l_gpt_apply,
+ .sizeof_wfhw = sizeof(struct rzg2l_gpt_waveform),
+ .round_waveform_tohw = rzg2l_gpt_round_waveform_tohw,
+ .round_waveform_fromhw = rzg2l_gpt_round_waveform_fromhw,
+ .read_waveform = rzg2l_gpt_read_waveform,
+ .write_waveform = rzg2l_gpt_write_waveform,
};
static int rzg2l_gpt_probe(struct platform_device *pdev)
base-commit: 4b53f8d76cbedfd7c2a2eccb5f1cd85ec6c5a8d3
--
2.43.0
Powered by blists - more mailing lists