Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

pwm: Add support for RZ/G2L GPT

RZ/G2L General PWM Timer (GPT) composed of 8 channels with 32-bit timer
(GPT32E). It supports the following functions
* 32 bits x 8 channels
* Up-counting or down-counting (saw waves) or up/down-counting
(triangle waves) for each counter.
* Clock sources independently selectable for each channel
* Two I/O pins per channel
* Two output compare/input capture registers per channel
* For the two output compare/input capture registers of each channel,
four registers are provided as buffer registers and are capable of
operating as comparison registers when buffering is not in use.
* In output compare operation, buffer switching can be at crests or
troughs, enabling the generation of laterally asymmetric PWM waveforms.
* Registers for setting up frame cycles in each channel (with capability
for generating interrupts at overflow or underflow)
* Generation of dead times in PWM operation
* Synchronous starting, stopping and clearing counters for arbitrary
channels
* Starting, stopping, clearing and up/down counters in response to input
level comparison
* Starting, clearing, stopping and up/down counters in response to a
maximum of four external triggers
* Output pin disable function by dead time error and detected
short-circuits between output pins
* A/D converter start triggers can be generated (GPT32E0 to GPT32E3)
* Enables the noise filter for input capture and external trigger
operation

Add basic pwm support for RZ/G2L GPT driver by creating separate
logical channels for each IOs.

Signed-off-by: Biju Das <biju.das.jz@bp.renesas.com>
Link: https://lore.kernel.org/r/20250226144531.176819-4-biju.das.jz@bp.renesas.com
Signed-off-by: Uwe Kleine-König <ukleinek@kernel.org>

authored by

Biju Das and committed by
Uwe Kleine-König
061f087f 9549d226

+455
+11
drivers/pwm/Kconfig
··· 552 552 Generic PWM framework driver for the PWM controller found on 553 553 Rockchip SoCs. 554 554 555 + config PWM_RZG2L_GPT 556 + tristate "Renesas RZ/G2L General PWM Timer support" 557 + depends on ARCH_RZG2L || COMPILE_TEST 558 + depends on HAS_IOMEM 559 + help 560 + This driver exposes the General PWM Timer controller found in Renesas 561 + RZ/G2L like chips through the PWM API. 562 + 563 + To compile this driver as a module, choose M here: the module 564 + will be called pwm-rzg2l-gpt. 565 + 555 566 config PWM_RZ_MTU3 556 567 tristate "Renesas RZ/G2L MTU3a PWM Timer support" 557 568 depends on RZ_MTU3
+1
drivers/pwm/Makefile
··· 50 50 obj-$(CONFIG_PWM_RCAR) += pwm-rcar.o 51 51 obj-$(CONFIG_PWM_RENESAS_TPU) += pwm-renesas-tpu.o 52 52 obj-$(CONFIG_PWM_ROCKCHIP) += pwm-rockchip.o 53 + obj-$(CONFIG_PWM_RZG2L_GPT) += pwm-rzg2l-gpt.o 53 54 obj-$(CONFIG_PWM_RZ_MTU3) += pwm-rz-mtu3.o 54 55 obj-$(CONFIG_PWM_SAMSUNG) += pwm-samsung.o 55 56 obj-$(CONFIG_PWM_SIFIVE) += pwm-sifive.o
+443
drivers/pwm/pwm-rzg2l-gpt.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Renesas RZ/G2L General PWM Timer (GPT) driver 4 + * 5 + * Copyright (C) 2025 Renesas Electronics Corporation 6 + * 7 + * Hardware manual for this IP can be found here 8 + * https://www.renesas.com/eu/en/document/mah/rzg2l-group-rzg2lc-group-users-manual-hardware-0?language=en 9 + * 10 + * Limitations: 11 + * - Counter must be stopped before modifying Mode and Prescaler. 12 + * - When PWM is disabled, the output is driven to inactive. 13 + * - While the hardware supports both polarities, the driver (for now) 14 + * only handles normal polarity. 15 + * - General PWM Timer (GPT) has 8 HW channels for PWM operations and 16 + * each HW channel have 2 IOs. 17 + * - Each IO is modelled as an independent PWM channel. 18 + * - When both channels are used, disabling the channel on one stops the 19 + * other. 20 + * - When both channels are used, the period of both IOs in the HW channel 21 + * must be same (for now). 22 + */ 23 + 24 + #include <linux/bitfield.h> 25 + #include <linux/clk.h> 26 + #include <linux/io.h> 27 + #include <linux/limits.h> 28 + #include <linux/module.h> 29 + #include <linux/of.h> 30 + #include <linux/platform_device.h> 31 + #include <linux/pwm.h> 32 + #include <linux/reset.h> 33 + #include <linux/time.h> 34 + #include <linux/units.h> 35 + 36 + #define RZG2L_GET_CH(hwpwm) ((hwpwm) / 2) 37 + #define RZG2L_GET_CH_OFFS(ch) (0x100 * (ch)) 38 + 39 + #define RZG2L_GTCR(ch) (0x2c + RZG2L_GET_CH_OFFS(ch)) 40 + #define RZG2L_GTUDDTYC(ch) (0x30 + RZG2L_GET_CH_OFFS(ch)) 41 + #define RZG2L_GTIOR(ch) (0x34 + RZG2L_GET_CH_OFFS(ch)) 42 + #define RZG2L_GTBER(ch) (0x40 + RZG2L_GET_CH_OFFS(ch)) 43 + #define RZG2L_GTCNT(ch) (0x48 + RZG2L_GET_CH_OFFS(ch)) 44 + #define RZG2L_GTCCR(ch, sub_ch) (0x4c + RZG2L_GET_CH_OFFS(ch) + 4 * (sub_ch)) 45 + #define RZG2L_GTPR(ch) (0x64 + RZG2L_GET_CH_OFFS(ch)) 46 + 47 + #define RZG2L_GTCR_CST BIT(0) 48 + #define RZG2L_GTCR_MD GENMASK(18, 16) 49 + #define RZG2L_GTCR_TPCS GENMASK(26, 24) 50 + 51 + #define RZG2L_GTCR_MD_SAW_WAVE_PWM_MODE FIELD_PREP(RZG2L_GTCR_MD, 0) 52 + 53 + #define RZG2L_GTUDDTYC_UP BIT(0) 54 + #define RZG2L_GTUDDTYC_UDF BIT(1) 55 + #define RZG2L_GTUDDTYC_UP_COUNTING (RZG2L_GTUDDTYC_UP | RZG2L_GTUDDTYC_UDF) 56 + 57 + #define RZG2L_GTIOR_GTIOA GENMASK(4, 0) 58 + #define RZG2L_GTIOR_GTIOB GENMASK(20, 16) 59 + #define RZG2L_GTIOR_GTIOx(sub_ch) ((sub_ch) ? RZG2L_GTIOR_GTIOB : RZG2L_GTIOR_GTIOA) 60 + #define RZG2L_GTIOR_OAE BIT(8) 61 + #define RZG2L_GTIOR_OBE BIT(24) 62 + #define RZG2L_GTIOR_OxE(sub_ch) ((sub_ch) ? RZG2L_GTIOR_OBE : RZG2L_GTIOR_OAE) 63 + 64 + #define RZG2L_INIT_OUT_HI_OUT_HI_END_TOGGLE 0x1b 65 + #define RZG2L_GTIOR_GTIOA_OUT_HI_END_TOGGLE_CMP_MATCH \ 66 + (RZG2L_INIT_OUT_HI_OUT_HI_END_TOGGLE | RZG2L_GTIOR_OAE) 67 + #define RZG2L_GTIOR_GTIOB_OUT_HI_END_TOGGLE_CMP_MATCH \ 68 + (FIELD_PREP(RZG2L_GTIOR_GTIOB, RZG2L_INIT_OUT_HI_OUT_HI_END_TOGGLE) | RZG2L_GTIOR_OBE) 69 + 70 + #define RZG2L_GTIOR_GTIOx_OUT_HI_END_TOGGLE_CMP_MATCH(sub_ch) \ 71 + ((sub_ch) ? RZG2L_GTIOR_GTIOB_OUT_HI_END_TOGGLE_CMP_MATCH : \ 72 + RZG2L_GTIOR_GTIOA_OUT_HI_END_TOGGLE_CMP_MATCH) 73 + 74 + #define RZG2L_MAX_HW_CHANNELS 8 75 + #define RZG2L_CHANNELS_PER_IO 2 76 + #define RZG2L_MAX_PWM_CHANNELS (RZG2L_MAX_HW_CHANNELS * RZG2L_CHANNELS_PER_IO) 77 + #define RZG2L_MAX_SCALE_FACTOR 1024 78 + #define RZG2L_MAX_TICKS ((u64)U32_MAX * RZG2L_MAX_SCALE_FACTOR) 79 + 80 + struct rzg2l_gpt_chip { 81 + void __iomem *mmio; 82 + struct mutex lock; /* lock to protect shared channel resources */ 83 + unsigned long rate_khz; 84 + u32 period_ticks[RZG2L_MAX_HW_CHANNELS]; 85 + u32 channel_request_count[RZG2L_MAX_HW_CHANNELS]; 86 + u32 channel_enable_count[RZG2L_MAX_HW_CHANNELS]; 87 + }; 88 + 89 + static inline struct rzg2l_gpt_chip *to_rzg2l_gpt_chip(struct pwm_chip *chip) 90 + { 91 + return pwmchip_get_drvdata(chip); 92 + } 93 + 94 + static inline unsigned int rzg2l_gpt_subchannel(unsigned int hwpwm) 95 + { 96 + return hwpwm & 0x1; 97 + } 98 + 99 + static void rzg2l_gpt_write(struct rzg2l_gpt_chip *rzg2l_gpt, u32 reg, u32 data) 100 + { 101 + writel(data, rzg2l_gpt->mmio + reg); 102 + } 103 + 104 + static u32 rzg2l_gpt_read(struct rzg2l_gpt_chip *rzg2l_gpt, u32 reg) 105 + { 106 + return readl(rzg2l_gpt->mmio + reg); 107 + } 108 + 109 + static void rzg2l_gpt_modify(struct rzg2l_gpt_chip *rzg2l_gpt, u32 reg, u32 clr, 110 + u32 set) 111 + { 112 + rzg2l_gpt_write(rzg2l_gpt, reg, 113 + (rzg2l_gpt_read(rzg2l_gpt, reg) & ~clr) | set); 114 + } 115 + 116 + static u8 rzg2l_gpt_calculate_prescale(struct rzg2l_gpt_chip *rzg2l_gpt, 117 + u64 period_ticks) 118 + { 119 + u32 prescaled_period_ticks; 120 + u8 prescale; 121 + 122 + prescaled_period_ticks = period_ticks >> 32; 123 + if (prescaled_period_ticks >= 256) 124 + prescale = 5; 125 + else 126 + prescale = (fls(prescaled_period_ticks) + 1) / 2; 127 + 128 + return prescale; 129 + } 130 + 131 + static int rzg2l_gpt_request(struct pwm_chip *chip, struct pwm_device *pwm) 132 + { 133 + struct rzg2l_gpt_chip *rzg2l_gpt = to_rzg2l_gpt_chip(chip); 134 + u32 ch = RZG2L_GET_CH(pwm->hwpwm); 135 + 136 + guard(mutex)(&rzg2l_gpt->lock); 137 + rzg2l_gpt->channel_request_count[ch]++; 138 + 139 + return 0; 140 + } 141 + 142 + static void rzg2l_gpt_free(struct pwm_chip *chip, struct pwm_device *pwm) 143 + { 144 + struct rzg2l_gpt_chip *rzg2l_gpt = to_rzg2l_gpt_chip(chip); 145 + u32 ch = RZG2L_GET_CH(pwm->hwpwm); 146 + 147 + guard(mutex)(&rzg2l_gpt->lock); 148 + rzg2l_gpt->channel_request_count[ch]--; 149 + } 150 + 151 + static bool rzg2l_gpt_is_ch_enabled(struct rzg2l_gpt_chip *rzg2l_gpt, u8 hwpwm) 152 + { 153 + u8 ch = RZG2L_GET_CH(hwpwm); 154 + u32 val; 155 + 156 + val = rzg2l_gpt_read(rzg2l_gpt, RZG2L_GTCR(ch)); 157 + if (!(val & RZG2L_GTCR_CST)) 158 + return false; 159 + 160 + val = rzg2l_gpt_read(rzg2l_gpt, RZG2L_GTIOR(ch)); 161 + 162 + return val & RZG2L_GTIOR_OxE(rzg2l_gpt_subchannel(hwpwm)); 163 + } 164 + 165 + /* Caller holds the lock while calling rzg2l_gpt_enable() */ 166 + static void rzg2l_gpt_enable(struct rzg2l_gpt_chip *rzg2l_gpt, 167 + struct pwm_device *pwm) 168 + { 169 + u8 sub_ch = rzg2l_gpt_subchannel(pwm->hwpwm); 170 + u32 val = RZG2L_GTIOR_GTIOx(sub_ch) | RZG2L_GTIOR_OxE(sub_ch); 171 + u8 ch = RZG2L_GET_CH(pwm->hwpwm); 172 + 173 + /* Enable pin output */ 174 + rzg2l_gpt_modify(rzg2l_gpt, RZG2L_GTIOR(ch), val, 175 + RZG2L_GTIOR_GTIOx_OUT_HI_END_TOGGLE_CMP_MATCH(sub_ch)); 176 + 177 + if (!rzg2l_gpt->channel_enable_count[ch]) 178 + rzg2l_gpt_modify(rzg2l_gpt, RZG2L_GTCR(ch), 0, RZG2L_GTCR_CST); 179 + 180 + rzg2l_gpt->channel_enable_count[ch]++; 181 + } 182 + 183 + /* Caller holds the lock while calling rzg2l_gpt_disable() */ 184 + static void rzg2l_gpt_disable(struct rzg2l_gpt_chip *rzg2l_gpt, 185 + struct pwm_device *pwm) 186 + { 187 + u8 sub_ch = rzg2l_gpt_subchannel(pwm->hwpwm); 188 + u8 ch = RZG2L_GET_CH(pwm->hwpwm); 189 + 190 + /* Stop count, Output low on GTIOCx pin when counting stops */ 191 + rzg2l_gpt->channel_enable_count[ch]--; 192 + 193 + if (!rzg2l_gpt->channel_enable_count[ch]) 194 + rzg2l_gpt_modify(rzg2l_gpt, RZG2L_GTCR(ch), RZG2L_GTCR_CST, 0); 195 + 196 + /* Disable pin output */ 197 + rzg2l_gpt_modify(rzg2l_gpt, RZG2L_GTIOR(ch), RZG2L_GTIOR_OxE(sub_ch), 0); 198 + } 199 + 200 + static u64 rzg2l_gpt_calculate_period_or_duty(struct rzg2l_gpt_chip *rzg2l_gpt, 201 + u32 val, u8 prescale) 202 + { 203 + u64 tmp; 204 + 205 + /* 206 + * The calculation doesn't overflow an u64 because prescale ≤ 5 and so 207 + * tmp = val << (2 * prescale) * USEC_PER_SEC 208 + * < 2^32 * 2^10 * 10^6 209 + * < 2^32 * 2^10 * 2^20 210 + * = 2^62 211 + */ 212 + tmp = (u64)val << (2 * prescale); 213 + tmp *= USEC_PER_SEC; 214 + 215 + return DIV64_U64_ROUND_UP(tmp, rzg2l_gpt->rate_khz); 216 + } 217 + 218 + static int rzg2l_gpt_get_state(struct pwm_chip *chip, struct pwm_device *pwm, 219 + struct pwm_state *state) 220 + { 221 + struct rzg2l_gpt_chip *rzg2l_gpt = to_rzg2l_gpt_chip(chip); 222 + 223 + state->enabled = rzg2l_gpt_is_ch_enabled(rzg2l_gpt, pwm->hwpwm); 224 + if (state->enabled) { 225 + u32 sub_ch = rzg2l_gpt_subchannel(pwm->hwpwm); 226 + u32 ch = RZG2L_GET_CH(pwm->hwpwm); 227 + u8 prescale; 228 + u32 val; 229 + 230 + val = rzg2l_gpt_read(rzg2l_gpt, RZG2L_GTCR(ch)); 231 + prescale = FIELD_GET(RZG2L_GTCR_TPCS, val); 232 + 233 + val = rzg2l_gpt_read(rzg2l_gpt, RZG2L_GTPR(ch)); 234 + state->period = rzg2l_gpt_calculate_period_or_duty(rzg2l_gpt, val, prescale); 235 + 236 + val = rzg2l_gpt_read(rzg2l_gpt, RZG2L_GTCCR(ch, sub_ch)); 237 + state->duty_cycle = rzg2l_gpt_calculate_period_or_duty(rzg2l_gpt, val, prescale); 238 + if (state->duty_cycle > state->period) 239 + state->duty_cycle = state->period; 240 + } 241 + 242 + state->polarity = PWM_POLARITY_NORMAL; 243 + 244 + return 0; 245 + } 246 + 247 + static u32 rzg2l_gpt_calculate_pv_or_dc(u64 period_or_duty_cycle, u8 prescale) 248 + { 249 + return min_t(u64, DIV_ROUND_DOWN_ULL(period_or_duty_cycle, 1 << (2 * prescale)), 250 + U32_MAX); 251 + } 252 + 253 + /* Caller holds the lock while calling rzg2l_gpt_config() */ 254 + static int rzg2l_gpt_config(struct pwm_chip *chip, struct pwm_device *pwm, 255 + const struct pwm_state *state) 256 + { 257 + struct rzg2l_gpt_chip *rzg2l_gpt = to_rzg2l_gpt_chip(chip); 258 + u8 sub_ch = rzg2l_gpt_subchannel(pwm->hwpwm); 259 + u8 ch = RZG2L_GET_CH(pwm->hwpwm); 260 + u64 period_ticks, duty_ticks; 261 + unsigned long pv, dc; 262 + u8 prescale; 263 + 264 + /* Limit period/duty cycle to max value supported by the HW */ 265 + period_ticks = mul_u64_u64_div_u64(state->period, rzg2l_gpt->rate_khz, USEC_PER_SEC); 266 + if (period_ticks > RZG2L_MAX_TICKS) 267 + period_ticks = RZG2L_MAX_TICKS; 268 + /* 269 + * GPT counter is shared by the two IOs of a single channel, so 270 + * prescale and period can NOT be modified when there are multiple IOs 271 + * in use with different settings. 272 + */ 273 + if (rzg2l_gpt->channel_request_count[ch] > 1 && period_ticks != rzg2l_gpt->period_ticks[ch]) 274 + return -EBUSY; 275 + 276 + prescale = rzg2l_gpt_calculate_prescale(rzg2l_gpt, period_ticks); 277 + pv = rzg2l_gpt_calculate_pv_or_dc(period_ticks, prescale); 278 + 279 + duty_ticks = mul_u64_u64_div_u64(state->duty_cycle, rzg2l_gpt->rate_khz, USEC_PER_SEC); 280 + if (duty_ticks > RZG2L_MAX_TICKS) 281 + duty_ticks = RZG2L_MAX_TICKS; 282 + dc = rzg2l_gpt_calculate_pv_or_dc(duty_ticks, prescale); 283 + 284 + /* 285 + * GPT counter is shared by multiple channels, we cache the period ticks 286 + * from the first enabled channel and use the same value for both 287 + * channels. 288 + */ 289 + rzg2l_gpt->period_ticks[ch] = period_ticks; 290 + 291 + /* 292 + * Counter must be stopped before modifying mode, prescaler, timer 293 + * counter and buffer enable registers. These registers are shared 294 + * between both channels. So allow updating these registers only for the 295 + * first enabled channel. 296 + */ 297 + if (rzg2l_gpt->channel_enable_count[ch] <= 1) { 298 + rzg2l_gpt_modify(rzg2l_gpt, RZG2L_GTCR(ch), RZG2L_GTCR_CST, 0); 299 + 300 + /* GPT set operating mode (saw-wave up-counting) */ 301 + rzg2l_gpt_modify(rzg2l_gpt, RZG2L_GTCR(ch), RZG2L_GTCR_MD, 302 + RZG2L_GTCR_MD_SAW_WAVE_PWM_MODE); 303 + 304 + /* Set count direction */ 305 + rzg2l_gpt_write(rzg2l_gpt, RZG2L_GTUDDTYC(ch), RZG2L_GTUDDTYC_UP_COUNTING); 306 + 307 + /* Select count clock */ 308 + rzg2l_gpt_modify(rzg2l_gpt, RZG2L_GTCR(ch), RZG2L_GTCR_TPCS, 309 + FIELD_PREP(RZG2L_GTCR_TPCS, prescale)); 310 + 311 + /* Set period */ 312 + rzg2l_gpt_write(rzg2l_gpt, RZG2L_GTPR(ch), pv); 313 + } 314 + 315 + /* Set duty cycle */ 316 + rzg2l_gpt_write(rzg2l_gpt, RZG2L_GTCCR(ch, sub_ch), dc); 317 + 318 + if (rzg2l_gpt->channel_enable_count[ch] <= 1) { 319 + /* Set initial value for counter */ 320 + rzg2l_gpt_write(rzg2l_gpt, RZG2L_GTCNT(ch), 0); 321 + 322 + /* Set no buffer operation */ 323 + rzg2l_gpt_write(rzg2l_gpt, RZG2L_GTBER(ch), 0); 324 + 325 + /* Restart the counter after updating the registers */ 326 + rzg2l_gpt_modify(rzg2l_gpt, RZG2L_GTCR(ch), 327 + RZG2L_GTCR_CST, RZG2L_GTCR_CST); 328 + } 329 + 330 + return 0; 331 + } 332 + 333 + static int rzg2l_gpt_apply(struct pwm_chip *chip, struct pwm_device *pwm, 334 + const struct pwm_state *state) 335 + { 336 + struct rzg2l_gpt_chip *rzg2l_gpt = to_rzg2l_gpt_chip(chip); 337 + bool enabled = pwm->state.enabled; 338 + int ret; 339 + 340 + if (state->polarity != PWM_POLARITY_NORMAL) 341 + return -EINVAL; 342 + 343 + guard(mutex)(&rzg2l_gpt->lock); 344 + if (!state->enabled) { 345 + if (enabled) 346 + rzg2l_gpt_disable(rzg2l_gpt, pwm); 347 + 348 + return 0; 349 + } 350 + 351 + ret = rzg2l_gpt_config(chip, pwm, state); 352 + if (!ret && !enabled) 353 + rzg2l_gpt_enable(rzg2l_gpt, pwm); 354 + 355 + return ret; 356 + } 357 + 358 + static const struct pwm_ops rzg2l_gpt_ops = { 359 + .request = rzg2l_gpt_request, 360 + .free = rzg2l_gpt_free, 361 + .get_state = rzg2l_gpt_get_state, 362 + .apply = rzg2l_gpt_apply, 363 + }; 364 + 365 + static int rzg2l_gpt_probe(struct platform_device *pdev) 366 + { 367 + struct rzg2l_gpt_chip *rzg2l_gpt; 368 + struct device *dev = &pdev->dev; 369 + struct reset_control *rstc; 370 + struct pwm_chip *chip; 371 + unsigned long rate; 372 + struct clk *clk; 373 + int ret; 374 + 375 + chip = devm_pwmchip_alloc(dev, RZG2L_MAX_PWM_CHANNELS, sizeof(*rzg2l_gpt)); 376 + if (IS_ERR(chip)) 377 + return PTR_ERR(chip); 378 + rzg2l_gpt = to_rzg2l_gpt_chip(chip); 379 + 380 + rzg2l_gpt->mmio = devm_platform_ioremap_resource(pdev, 0); 381 + if (IS_ERR(rzg2l_gpt->mmio)) 382 + return PTR_ERR(rzg2l_gpt->mmio); 383 + 384 + rstc = devm_reset_control_get_exclusive_deasserted(dev, NULL); 385 + if (IS_ERR(rstc)) 386 + return dev_err_probe(dev, PTR_ERR(rstc), "Cannot deassert reset control\n"); 387 + 388 + clk = devm_clk_get_enabled(dev, NULL); 389 + if (IS_ERR(clk)) 390 + return dev_err_probe(dev, PTR_ERR(clk), "Cannot get clock\n"); 391 + 392 + ret = devm_clk_rate_exclusive_get(dev, clk); 393 + if (ret) 394 + return ret; 395 + 396 + rate = clk_get_rate(clk); 397 + if (!rate) 398 + return dev_err_probe(dev, -EINVAL, "The gpt clk rate is 0"); 399 + 400 + /* 401 + * Refuse clk rates > 1 GHz to prevent overflow later for computing 402 + * period and duty cycle. 403 + */ 404 + if (rate > NSEC_PER_SEC) 405 + return dev_err_probe(dev, -EINVAL, "The gpt clk rate is > 1GHz"); 406 + 407 + /* 408 + * Rate is in MHz and is always integer for peripheral clk 409 + * 2^32 * 2^10 (prescalar) * 10^6 (rate_khz) < 2^64 410 + * So make sure rate is multiple of 1000. 411 + */ 412 + rzg2l_gpt->rate_khz = rate / KILO; 413 + if (rzg2l_gpt->rate_khz * KILO != rate) 414 + return dev_err_probe(dev, -EINVAL, "Rate is not multiple of 1000"); 415 + 416 + mutex_init(&rzg2l_gpt->lock); 417 + 418 + chip->ops = &rzg2l_gpt_ops; 419 + ret = devm_pwmchip_add(dev, chip); 420 + if (ret) 421 + return dev_err_probe(dev, ret, "Failed to add PWM chip\n"); 422 + 423 + return 0; 424 + } 425 + 426 + static const struct of_device_id rzg2l_gpt_of_table[] = { 427 + { .compatible = "renesas,rzg2l-gpt", }, 428 + { /* Sentinel */ } 429 + }; 430 + MODULE_DEVICE_TABLE(of, rzg2l_gpt_of_table); 431 + 432 + static struct platform_driver rzg2l_gpt_driver = { 433 + .driver = { 434 + .name = "pwm-rzg2l-gpt", 435 + .of_match_table = rzg2l_gpt_of_table, 436 + }, 437 + .probe = rzg2l_gpt_probe, 438 + }; 439 + module_platform_driver(rzg2l_gpt_driver); 440 + 441 + MODULE_AUTHOR("Biju Das <biju.das.jz@bp.renesas.com>"); 442 + MODULE_DESCRIPTION("Renesas RZ/G2L General PWM Timer (GPT) Driver"); 443 + MODULE_LICENSE("GPL");