From: Biju Das <biju.das.jz@xxxxxxxxxxxxxx> Convert the rzg2l-gpt driver to use the new callbacks for hardware programming. Signed-off-by: Biju Das <biju.das.jz@xxxxxxxxxxxxxx> --- 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