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(val: data, addr: rzg2l_gpt->mmio + reg); |
102 | } |
103 | |
104 | static u32 rzg2l_gpt_read(struct rzg2l_gpt_chip *rzg2l_gpt, u32 reg) |
105 | { |
106 | return readl(addr: 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 | data: (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(x: 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)(T: &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)(T: &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(hwpwm: 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), clr: 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), clr: 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(hwpwm: 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, set: 0); |
195 | |
196 | /* Disable pin output */ |
197 | rzg2l_gpt_modify(rzg2l_gpt, RZG2L_GTIOR(ch), RZG2L_GTIOR_OxE(sub_ch), set: 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, hwpwm: pwm->hwpwm); |
224 | if (state->enabled) { |
225 | u32 sub_ch = rzg2l_gpt_subchannel(hwpwm: 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(hwpwm: 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(a: state->period, mul: 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) { |
274 | if (period_ticks < rzg2l_gpt->period_ticks[ch]) |
275 | return -EBUSY; |
276 | else |
277 | period_ticks = rzg2l_gpt->period_ticks[ch]; |
278 | } |
279 | |
280 | prescale = rzg2l_gpt_calculate_prescale(rzg2l_gpt, period_ticks); |
281 | pv = rzg2l_gpt_calculate_pv_or_dc(period_or_duty_cycle: period_ticks, prescale); |
282 | |
283 | duty_ticks = mul_u64_u64_div_u64(a: state->duty_cycle, mul: rzg2l_gpt->rate_khz, USEC_PER_SEC); |
284 | if (duty_ticks > period_ticks) |
285 | duty_ticks = period_ticks; |
286 | dc = rzg2l_gpt_calculate_pv_or_dc(period_or_duty_cycle: duty_ticks, prescale); |
287 | |
288 | /* |
289 | * GPT counter is shared by multiple channels, we cache the period ticks |
290 | * from the first enabled channel and use the same value for both |
291 | * channels. |
292 | */ |
293 | rzg2l_gpt->period_ticks[ch] = period_ticks; |
294 | |
295 | /* |
296 | * Counter must be stopped before modifying mode, prescaler, timer |
297 | * counter and buffer enable registers. These registers are shared |
298 | * between both channels. So allow updating these registers only for the |
299 | * first enabled channel. |
300 | */ |
301 | if (rzg2l_gpt->channel_enable_count[ch] <= 1) { |
302 | rzg2l_gpt_modify(rzg2l_gpt, RZG2L_GTCR(ch), RZG2L_GTCR_CST, set: 0); |
303 | |
304 | /* GPT set operating mode (saw-wave up-counting) */ |
305 | rzg2l_gpt_modify(rzg2l_gpt, RZG2L_GTCR(ch), RZG2L_GTCR_MD, |
306 | RZG2L_GTCR_MD_SAW_WAVE_PWM_MODE); |
307 | |
308 | /* Set count direction */ |
309 | rzg2l_gpt_write(rzg2l_gpt, RZG2L_GTUDDTYC(ch), RZG2L_GTUDDTYC_UP_COUNTING); |
310 | |
311 | /* Select count clock */ |
312 | rzg2l_gpt_modify(rzg2l_gpt, RZG2L_GTCR(ch), RZG2L_GTCR_TPCS, |
313 | FIELD_PREP(RZG2L_GTCR_TPCS, prescale)); |
314 | |
315 | /* Set period */ |
316 | rzg2l_gpt_write(rzg2l_gpt, RZG2L_GTPR(ch), data: pv); |
317 | } |
318 | |
319 | /* Set duty cycle */ |
320 | rzg2l_gpt_write(rzg2l_gpt, RZG2L_GTCCR(ch, sub_ch), data: dc); |
321 | |
322 | if (rzg2l_gpt->channel_enable_count[ch] <= 1) { |
323 | /* Set initial value for counter */ |
324 | rzg2l_gpt_write(rzg2l_gpt, RZG2L_GTCNT(ch), data: 0); |
325 | |
326 | /* Set no buffer operation */ |
327 | rzg2l_gpt_write(rzg2l_gpt, RZG2L_GTBER(ch), data: 0); |
328 | |
329 | /* Restart the counter after updating the registers */ |
330 | rzg2l_gpt_modify(rzg2l_gpt, RZG2L_GTCR(ch), |
331 | RZG2L_GTCR_CST, RZG2L_GTCR_CST); |
332 | } |
333 | |
334 | return 0; |
335 | } |
336 | |
337 | static int rzg2l_gpt_apply(struct pwm_chip *chip, struct pwm_device *pwm, |
338 | const struct pwm_state *state) |
339 | { |
340 | struct rzg2l_gpt_chip *rzg2l_gpt = to_rzg2l_gpt_chip(chip); |
341 | bool enabled = pwm->state.enabled; |
342 | int ret; |
343 | |
344 | if (state->polarity != PWM_POLARITY_NORMAL) |
345 | return -EINVAL; |
346 | |
347 | guard(mutex)(T: &rzg2l_gpt->lock); |
348 | if (!state->enabled) { |
349 | if (enabled) |
350 | rzg2l_gpt_disable(rzg2l_gpt, pwm); |
351 | |
352 | return 0; |
353 | } |
354 | |
355 | ret = rzg2l_gpt_config(chip, pwm, state); |
356 | if (!ret && !enabled) |
357 | rzg2l_gpt_enable(rzg2l_gpt, pwm); |
358 | |
359 | return ret; |
360 | } |
361 | |
362 | static const struct pwm_ops rzg2l_gpt_ops = { |
363 | .request = rzg2l_gpt_request, |
364 | .free = rzg2l_gpt_free, |
365 | .get_state = rzg2l_gpt_get_state, |
366 | .apply = rzg2l_gpt_apply, |
367 | }; |
368 | |
369 | static int rzg2l_gpt_probe(struct platform_device *pdev) |
370 | { |
371 | struct rzg2l_gpt_chip *rzg2l_gpt; |
372 | struct device *dev = &pdev->dev; |
373 | struct reset_control *rstc; |
374 | struct pwm_chip *chip; |
375 | unsigned long rate; |
376 | struct clk *clk; |
377 | int ret; |
378 | |
379 | chip = devm_pwmchip_alloc(parent: dev, RZG2L_MAX_PWM_CHANNELS, sizeof_priv: sizeof(*rzg2l_gpt)); |
380 | if (IS_ERR(ptr: chip)) |
381 | return PTR_ERR(ptr: chip); |
382 | rzg2l_gpt = to_rzg2l_gpt_chip(chip); |
383 | |
384 | rzg2l_gpt->mmio = devm_platform_ioremap_resource(pdev, index: 0); |
385 | if (IS_ERR(ptr: rzg2l_gpt->mmio)) |
386 | return PTR_ERR(ptr: rzg2l_gpt->mmio); |
387 | |
388 | rstc = devm_reset_control_get_exclusive_deasserted(dev, NULL); |
389 | if (IS_ERR(ptr: rstc)) |
390 | return dev_err_probe(dev, err: PTR_ERR(ptr: rstc), fmt: "Cannot deassert reset control\n"); |
391 | |
392 | clk = devm_clk_get_enabled(dev, NULL); |
393 | if (IS_ERR(ptr: clk)) |
394 | return dev_err_probe(dev, err: PTR_ERR(ptr: clk), fmt: "Cannot get clock\n"); |
395 | |
396 | ret = devm_clk_rate_exclusive_get(dev, clk); |
397 | if (ret) |
398 | return ret; |
399 | |
400 | rate = clk_get_rate(clk); |
401 | if (!rate) |
402 | return dev_err_probe(dev, err: -EINVAL, fmt: "The gpt clk rate is 0"); |
403 | |
404 | /* |
405 | * Refuse clk rates > 1 GHz to prevent overflow later for computing |
406 | * period and duty cycle. |
407 | */ |
408 | if (rate > NSEC_PER_SEC) |
409 | return dev_err_probe(dev, err: -EINVAL, fmt: "The gpt clk rate is > 1GHz"); |
410 | |
411 | /* |
412 | * Rate is in MHz and is always integer for peripheral clk |
413 | * 2^32 * 2^10 (prescalar) * 10^6 (rate_khz) < 2^64 |
414 | * So make sure rate is multiple of 1000. |
415 | */ |
416 | rzg2l_gpt->rate_khz = rate / KILO; |
417 | if (rzg2l_gpt->rate_khz * KILO != rate) |
418 | return dev_err_probe(dev, err: -EINVAL, fmt: "Rate is not multiple of 1000"); |
419 | |
420 | mutex_init(&rzg2l_gpt->lock); |
421 | |
422 | chip->ops = &rzg2l_gpt_ops; |
423 | ret = devm_pwmchip_add(dev, chip); |
424 | if (ret) |
425 | return dev_err_probe(dev, err: ret, fmt: "Failed to add PWM chip\n"); |
426 | |
427 | return 0; |
428 | } |
429 | |
430 | static const struct of_device_id rzg2l_gpt_of_table[] = { |
431 | { .compatible = "renesas,rzg2l-gpt", }, |
432 | { /* Sentinel */ } |
433 | }; |
434 | MODULE_DEVICE_TABLE(of, rzg2l_gpt_of_table); |
435 | |
436 | static struct platform_driver rzg2l_gpt_driver = { |
437 | .driver = { |
438 | .name = "pwm-rzg2l-gpt", |
439 | .of_match_table = rzg2l_gpt_of_table, |
440 | }, |
441 | .probe = rzg2l_gpt_probe, |
442 | }; |
443 | module_platform_driver(rzg2l_gpt_driver); |
444 | |
445 | MODULE_AUTHOR("Biju Das <biju.das.jz@bp.renesas.com>"); |
446 | MODULE_DESCRIPTION("Renesas RZ/G2L General PWM Timer (GPT) Driver"); |
447 | MODULE_LICENSE("GPL"); |
448 |
Definitions
- rzg2l_gpt_chip
- to_rzg2l_gpt_chip
- rzg2l_gpt_subchannel
- rzg2l_gpt_write
- rzg2l_gpt_read
- rzg2l_gpt_modify
- rzg2l_gpt_calculate_prescale
- rzg2l_gpt_request
- rzg2l_gpt_free
- rzg2l_gpt_is_ch_enabled
- rzg2l_gpt_enable
- rzg2l_gpt_disable
- rzg2l_gpt_calculate_period_or_duty
- rzg2l_gpt_get_state
- rzg2l_gpt_calculate_pv_or_dc
- rzg2l_gpt_config
- rzg2l_gpt_apply
- rzg2l_gpt_ops
- rzg2l_gpt_probe
- rzg2l_gpt_of_table
Improve your Profiling and Debugging skills
Find out more