// SPDX-License-Identifier: GPL-2.0 /* * Renesas RZ/G2L General PWM Timer (GPT) driver * * Copyright (C) 2025 Renesas Electronics Corporation * * Hardware manual for this IP can be found here * https://www.renesas.com/eu/en/document/mah/rzg2l-group-rzg2lc-group-users-manual-hardware-0?language=en * * Limitations: * - Counter must be stopped before modifying Mode and Prescaler. * - When PWM is disabled, the output is driven to inactive. * - While the hardware supports both polarities, the driver (for now) * only handles normal polarity. * - General PWM Timer (GPT) has 8 HW channels for PWM operations and * each HW channel have 2 IOs. * - Each IO is modelled as an independent PWM channel. * - When both channels are used, disabling the channel on one stops the * other. * - When both channels are used, the period of both IOs in the HW channel * must be same (for now).
*/
/* 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); if (period_ticks > RZG2L_MAX_TICKS)
period_ticks = RZG2L_MAX_TICKS; /* * GPT counter is shared by the two IOs of a single channel, so * prescale and period can NOT be modified when there are multiple IOs * in use with different settings.
*/ if (rzg2l_gpt->channel_request_count[ch] > 1) { if (period_ticks < rzg2l_gpt->period_ticks[ch]) return -EBUSY; else
period_ticks = rzg2l_gpt->period_ticks[ch];
}
duty_ticks = mul_u64_u64_div_u64(state->duty_cycle, 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);
/* * GPT counter is shared by multiple channels, we cache the period ticks * from the first enabled channel and use the same value for both * channels.
*/
rzg2l_gpt->period_ticks[ch] = period_ticks;
/* * Counter must be stopped before modifying mode, prescaler, timer * counter and buffer enable registers. These registers are shared * between both channels. So allow updating these registers only for the * first enabled channel.
*/ if (rzg2l_gpt->channel_enable_count[ch] <= 1) {
rzg2l_gpt_modify(rzg2l_gpt, RZG2L_GTCR(ch), RZG2L_GTCR_CST, 0);
clk = devm_clk_get_enabled(dev, NULL); if (IS_ERR(clk)) return dev_err_probe(dev, PTR_ERR(clk), "Cannot get clock\n");
ret = devm_clk_rate_exclusive_get(dev, clk); if (ret) return ret;
rate = clk_get_rate(clk); if (!rate) return dev_err_probe(dev, -EINVAL, "The gpt clk rate is 0");
/* * Refuse clk rates > 1 GHz to prevent overflow later for computing * period and duty cycle.
*/ if (rate > NSEC_PER_SEC) return dev_err_probe(dev, -EINVAL, "The gpt clk rate is > 1GHz");
/* * Rate is in MHz and is always integer for peripheral clk * 2^32 * 2^10 (prescalar) * 10^6 (rate_khz) < 2^64 * So make sure rate is multiple of 1000.
*/
rzg2l_gpt->rate_khz = rate / KILO; if (rzg2l_gpt->rate_khz * KILO != rate) return dev_err_probe(dev, -EINVAL, "Rate is not multiple of 1000");
mutex_init(&rzg2l_gpt->lock);
chip->ops = &rzg2l_gpt_ops;
ret = devm_pwmchip_add(dev, chip); if (ret) return dev_err_probe(dev, ret, "Failed to add PWM chip\n");
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.