xref: /linux/drivers/pwm/pwm-airoha.c (revision d30c1683aaecb93d2ab95685dc4300a33d3cea7a)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright 2022 Markus Gothe <markus.gothe@genexis.eu>
4  * Copyright 2025 Christian Marangi <ansuelsmth@gmail.com>
5  *
6  *  Limitations:
7  *  - Only 8 concurrent waveform generators are available for 8 combinations of
8  *    duty_cycle and period. Waveform generators are shared between 16 GPIO
9  *    pins and 17 SIPO GPIO pins.
10  *  - Supports only normal polarity.
11  *  - On configuration the currently running period is completed.
12  *  - Minimum supported period is 4 ms
13  *  - Maximum supported period is 1s
14  */
15 
16 #include <linux/array_size.h>
17 #include <linux/bitfield.h>
18 #include <linux/bitmap.h>
19 #include <linux/err.h>
20 #include <linux/io.h>
21 #include <linux/iopoll.h>
22 #include <linux/math64.h>
23 #include <linux/mfd/syscon.h>
24 #include <linux/module.h>
25 #include <linux/mod_devicetable.h>
26 #include <linux/platform_device.h>
27 #include <linux/pwm.h>
28 #include <linux/regmap.h>
29 #include <linux/types.h>
30 
31 #define AIROHA_PWM_REG_SGPIO_LED_DATA		0x0024
32 #define AIROHA_PWM_SGPIO_LED_DATA_SHIFT_FLAG	BIT(31)
33 #define AIROHA_PWM_SGPIO_LED_DATA_DATA		GENMASK(16, 0)
34 
35 #define AIROHA_PWM_REG_SGPIO_CLK_DIVR		0x0028
36 #define AIROHA_PWM_SGPIO_CLK_DIVR		GENMASK(1, 0)
37 #define AIROHA_PWM_SGPIO_CLK_DIVR_32		FIELD_PREP_CONST(AIROHA_PWM_SGPIO_CLK_DIVR, 3)
38 #define AIROHA_PWM_SGPIO_CLK_DIVR_16		FIELD_PREP_CONST(AIROHA_PWM_SGPIO_CLK_DIVR, 2)
39 #define AIROHA_PWM_SGPIO_CLK_DIVR_8		FIELD_PREP_CONST(AIROHA_PWM_SGPIO_CLK_DIVR, 1)
40 #define AIROHA_PWM_SGPIO_CLK_DIVR_4		FIELD_PREP_CONST(AIROHA_PWM_SGPIO_CLK_DIVR, 0)
41 
42 #define AIROHA_PWM_REG_SGPIO_CLK_DLY		0x002c
43 
44 #define AIROHA_PWM_REG_SIPO_FLASH_MODE_CFG	0x0030
45 #define AIROHA_PWM_SERIAL_GPIO_FLASH_MODE	BIT(1)
46 #define AIROHA_PWM_SERIAL_GPIO_MODE_74HC164	BIT(0)
47 
48 #define AIROHA_PWM_REG_GPIO_FLASH_PRD_SET(_n)	(0x003c + (4 * (_n)))
49 #define AIROHA_PWM_REG_GPIO_FLASH_PRD_SHIFT(_n) (16 * (_n))
50 #define AIROHA_PWM_GPIO_FLASH_PRD_LOW		GENMASK(15, 8)
51 #define AIROHA_PWM_GPIO_FLASH_PRD_HIGH		GENMASK(7, 0)
52 
53 #define AIROHA_PWM_REG_GPIO_FLASH_MAP(_n)	(0x004c + (4 * (_n)))
54 #define AIROHA_PWM_REG_GPIO_FLASH_MAP_SHIFT(_n) (4 * (_n))
55 #define AIROHA_PWM_GPIO_FLASH_EN		BIT(3)
56 #define AIROHA_PWM_GPIO_FLASH_SET_ID		GENMASK(2, 0)
57 
58 /* Register map is equal to GPIO flash map */
59 #define AIROHA_PWM_REG_SIPO_FLASH_MAP(_n)	(0x0054 + (4 * (_n)))
60 
61 #define AIROHA_PWM_REG_CYCLE_CFG_VALUE(_n)	(0x0098 + (4 * (_n)))
62 #define AIROHA_PWM_REG_CYCLE_CFG_SHIFT(_n)	(8 * (_n))
63 #define AIROHA_PWM_WAVE_GEN_CYCLE		GENMASK(7, 0)
64 
65 /* GPIO/SIPO flash map handles 8 pins in one register */
66 #define AIROHA_PWM_PINS_PER_FLASH_MAP		8
67 /* Cycle(Period) registers handles 4 generators in one 32-bit register */
68 #define AIROHA_PWM_BUCKET_PER_CYCLE_CFG		4
69 /* Flash(Duty) producer handles 2 generators in one 32-bit register */
70 #define AIROHA_PWM_BUCKET_PER_FLASH_PROD	2
71 
72 #define AIROHA_PWM_NUM_BUCKETS			8
73 /*
74  * The first 16 GPIO pins, GPIO0-GPIO15, are mapped into 16 PWM channels, 0-15.
75  * The SIPO GPIO pins are 17 pins which are mapped into 17 PWM channels, 16-32.
76  * However, we've only got 8 concurrent waveform generators and can therefore
77  * only use up to 8 different combinations of duty cycle and period at a time.
78  */
79 #define AIROHA_PWM_NUM_GPIO			16
80 #define AIROHA_PWM_NUM_SIPO			17
81 #define AIROHA_PWM_MAX_CHANNELS			(AIROHA_PWM_NUM_GPIO + AIROHA_PWM_NUM_SIPO)
82 
83 struct airoha_pwm_bucket {
84 	/* Concurrent access protected by PWM core */
85 	int used;
86 	u32 period_ticks;
87 	u32 duty_ticks;
88 };
89 
90 struct airoha_pwm {
91 	struct regmap *regmap;
92 
93 	DECLARE_BITMAP(initialized, AIROHA_PWM_MAX_CHANNELS);
94 
95 	struct airoha_pwm_bucket buckets[AIROHA_PWM_NUM_BUCKETS];
96 
97 	/* Cache bucket used by each pwm channel */
98 	u8 channel_bucket[AIROHA_PWM_MAX_CHANNELS];
99 };
100 
101 /* The PWM hardware supports periods between 4 ms and 1 s */
102 #define AIROHA_PWM_PERIOD_TICK_NS	(4 * NSEC_PER_MSEC)
103 #define AIROHA_PWM_PERIOD_MAX_NS	(1 * NSEC_PER_SEC)
104 /* It is represented internally as 1/250 s between 1 and 250. Unit is ticks. */
105 #define AIROHA_PWM_PERIOD_MIN		1
106 #define AIROHA_PWM_PERIOD_MAX		250
107 /* Duty cycle is relative with 255 corresponding to 100% */
108 #define AIROHA_PWM_DUTY_FULL		255
109 
110 static void airoha_pwm_get_flash_map_addr_and_shift(unsigned int hwpwm,
111 						    u32 *addr, u32 *shift)
112 {
113 	unsigned int offset, hwpwm_bit;
114 
115 	if (hwpwm >= AIROHA_PWM_NUM_GPIO) {
116 		unsigned int sipohwpwm = hwpwm - AIROHA_PWM_NUM_GPIO;
117 
118 		offset = sipohwpwm / AIROHA_PWM_PINS_PER_FLASH_MAP;
119 		hwpwm_bit = sipohwpwm % AIROHA_PWM_PINS_PER_FLASH_MAP;
120 
121 		/* One FLASH_MAP register handles 8 pins */
122 		*shift = AIROHA_PWM_REG_GPIO_FLASH_MAP_SHIFT(hwpwm_bit);
123 		*addr = AIROHA_PWM_REG_SIPO_FLASH_MAP(offset);
124 	} else {
125 		offset = hwpwm / AIROHA_PWM_PINS_PER_FLASH_MAP;
126 		hwpwm_bit = hwpwm % AIROHA_PWM_PINS_PER_FLASH_MAP;
127 
128 		/* One FLASH_MAP register handles 8 pins */
129 		*shift = AIROHA_PWM_REG_GPIO_FLASH_MAP_SHIFT(hwpwm_bit);
130 		*addr = AIROHA_PWM_REG_GPIO_FLASH_MAP(offset);
131 	}
132 }
133 
134 static u32 airoha_pwm_get_period_ticks_from_ns(u32 period_ns)
135 {
136 	return period_ns / AIROHA_PWM_PERIOD_TICK_NS;
137 }
138 
139 static u32 airoha_pwm_get_duty_ticks_from_ns(u32 period_ns, u32 duty_ns)
140 {
141 	return mul_u64_u32_div(duty_ns, AIROHA_PWM_DUTY_FULL, period_ns);
142 }
143 
144 static u32 airoha_pwm_get_period_ns_from_ticks(u32 period_tick)
145 {
146 	return period_tick * AIROHA_PWM_PERIOD_TICK_NS;
147 }
148 
149 static u32 airoha_pwm_get_duty_ns_from_ticks(u32 period_tick, u32 duty_tick)
150 {
151 	u32 period_ns = period_tick * AIROHA_PWM_PERIOD_TICK_NS;
152 
153 	/*
154 	 * Overflow can't occur in multiplication as duty_tick is just 8 bit
155 	 * and period_ns is clamped to AIROHA_PWM_PERIOD_MAX_NS and fit in a
156 	 * u64.
157 	 */
158 	return DIV_U64_ROUND_UP(duty_tick * period_ns, AIROHA_PWM_DUTY_FULL);
159 }
160 
161 static int airoha_pwm_get_bucket(struct airoha_pwm *pc, int bucket,
162 				 u64 *period_ns, u64 *duty_ns)
163 {
164 	struct regmap *map = pc->regmap;
165 	u32 period_tick, duty_tick;
166 	unsigned int offset;
167 	u32 shift, val;
168 	int ret;
169 
170 	offset = bucket / AIROHA_PWM_BUCKET_PER_CYCLE_CFG;
171 	shift = bucket % AIROHA_PWM_BUCKET_PER_CYCLE_CFG;
172 	shift = AIROHA_PWM_REG_CYCLE_CFG_SHIFT(shift);
173 
174 	ret = regmap_read(map, AIROHA_PWM_REG_CYCLE_CFG_VALUE(offset), &val);
175 	if (ret)
176 		return ret;
177 
178 	period_tick = FIELD_GET(AIROHA_PWM_WAVE_GEN_CYCLE, val >> shift);
179 	*period_ns = airoha_pwm_get_period_ns_from_ticks(period_tick);
180 
181 	offset = bucket / AIROHA_PWM_BUCKET_PER_FLASH_PROD;
182 	shift = bucket % AIROHA_PWM_BUCKET_PER_FLASH_PROD;
183 	shift = AIROHA_PWM_REG_GPIO_FLASH_PRD_SHIFT(shift);
184 
185 	ret = regmap_read(map, AIROHA_PWM_REG_GPIO_FLASH_PRD_SET(offset),
186 			  &val);
187 	if (ret)
188 		return ret;
189 
190 	duty_tick = FIELD_GET(AIROHA_PWM_GPIO_FLASH_PRD_HIGH, val >> shift);
191 	*duty_ns = airoha_pwm_get_duty_ns_from_ticks(period_tick, duty_tick);
192 
193 	return 0;
194 }
195 
196 static int airoha_pwm_get_generator(struct airoha_pwm *pc, u32 duty_ticks,
197 				    u32 period_ticks)
198 {
199 	int best = -ENOENT, unused = -ENOENT;
200 	u32 duty_ns, best_duty_ns = 0;
201 	u32 best_period_ticks = 0;
202 	unsigned int i;
203 
204 	duty_ns = airoha_pwm_get_duty_ns_from_ticks(period_ticks, duty_ticks);
205 
206 	for (i = 0; i < ARRAY_SIZE(pc->buckets); i++) {
207 		struct airoha_pwm_bucket *bucket = &pc->buckets[i];
208 		u32 bucket_period_ticks = bucket->period_ticks;
209 		u32 bucket_duty_ticks = bucket->duty_ticks;
210 
211 		/* If found, save an unused bucket to return it later */
212 		if (!bucket->used) {
213 			unused = i;
214 			continue;
215 		}
216 
217 		/* We found a matching bucket, exit early */
218 		if (duty_ticks == bucket_duty_ticks &&
219 		    period_ticks == bucket_period_ticks)
220 			return i;
221 
222 		/*
223 		 * Unlike duty cycle zero, which can be handled by
224 		 * disabling PWM, a generator is needed for full duty
225 		 * cycle but it can be reused regardless of period
226 		 */
227 		if (duty_ticks == AIROHA_PWM_DUTY_FULL &&
228 		    bucket_duty_ticks == AIROHA_PWM_DUTY_FULL)
229 			return i;
230 
231 		/*
232 		 * With an unused bucket available, skip searching for
233 		 * a bucket to recycle (closer to the requested period/duty)
234 		 */
235 		if (unused >= 0)
236 			continue;
237 
238 		/* Ignore bucket with invalid period */
239 		if (bucket_period_ticks > period_ticks)
240 			continue;
241 
242 		/*
243 		 * Search for a bucket closer to the requested period
244 		 * that has the maximal possible period that isn't bigger
245 		 * than the requested period. For that period pick the maximal
246 		 * duty cycle that isn't bigger than the requested duty_cycle.
247 		 */
248 		if (bucket_period_ticks >= best_period_ticks) {
249 			u32 bucket_duty_ns = airoha_pwm_get_duty_ns_from_ticks(bucket_period_ticks,
250 									       bucket_duty_ticks);
251 
252 			/* Skip bucket that goes over the requested duty */
253 			if (bucket_duty_ns > duty_ns)
254 				continue;
255 
256 			if (bucket_duty_ns > best_duty_ns) {
257 				best_period_ticks = bucket_period_ticks;
258 				best_duty_ns = bucket_duty_ns;
259 				best = i;
260 			}
261 		}
262 	}
263 
264 	/* Return an unused bucket or the best one found (if ever) */
265 	return unused >= 0 ? unused : best;
266 }
267 
268 static void airoha_pwm_release_bucket_config(struct airoha_pwm *pc,
269 					     unsigned int hwpwm)
270 {
271 	int bucket;
272 
273 	/* Nothing to clear, PWM channel never used */
274 	if (!test_bit(hwpwm, pc->initialized))
275 		return;
276 
277 	bucket = pc->channel_bucket[hwpwm];
278 	pc->buckets[bucket].used--;
279 }
280 
281 static int airoha_pwm_apply_bucket_config(struct airoha_pwm *pc, unsigned int bucket,
282 					  u32 duty_ticks, u32 period_ticks)
283 {
284 	u32 mask, shift, val;
285 	u32 offset;
286 	int ret;
287 
288 	offset = bucket / AIROHA_PWM_BUCKET_PER_CYCLE_CFG;
289 	shift = bucket % AIROHA_PWM_BUCKET_PER_CYCLE_CFG;
290 	shift = AIROHA_PWM_REG_CYCLE_CFG_SHIFT(shift);
291 
292 	/* Configure frequency divisor */
293 	mask = AIROHA_PWM_WAVE_GEN_CYCLE << shift;
294 	val = FIELD_PREP(AIROHA_PWM_WAVE_GEN_CYCLE, period_ticks) << shift;
295 	ret = regmap_update_bits(pc->regmap, AIROHA_PWM_REG_CYCLE_CFG_VALUE(offset),
296 				 mask, val);
297 	if (ret)
298 		return ret;
299 
300 	offset = bucket / AIROHA_PWM_BUCKET_PER_FLASH_PROD;
301 	shift = bucket % AIROHA_PWM_BUCKET_PER_FLASH_PROD;
302 	shift = AIROHA_PWM_REG_GPIO_FLASH_PRD_SHIFT(shift);
303 
304 	/* Configure duty cycle */
305 	mask = AIROHA_PWM_GPIO_FLASH_PRD_HIGH << shift;
306 	val = FIELD_PREP(AIROHA_PWM_GPIO_FLASH_PRD_HIGH, duty_ticks) << shift;
307 	ret = regmap_update_bits(pc->regmap, AIROHA_PWM_REG_GPIO_FLASH_PRD_SET(offset),
308 				 mask, val);
309 	if (ret)
310 		return ret;
311 
312 	mask = AIROHA_PWM_GPIO_FLASH_PRD_LOW << shift;
313 	val = FIELD_PREP(AIROHA_PWM_GPIO_FLASH_PRD_LOW,
314 			 AIROHA_PWM_DUTY_FULL - duty_ticks) << shift;
315 	return regmap_update_bits(pc->regmap, AIROHA_PWM_REG_GPIO_FLASH_PRD_SET(offset),
316 				  mask, val);
317 }
318 
319 static int airoha_pwm_consume_generator(struct airoha_pwm *pc,
320 					u32 duty_ticks, u32 period_ticks,
321 					unsigned int hwpwm)
322 {
323 	bool config_bucket = false;
324 	int bucket, ret;
325 
326 	/*
327 	 * Search for a bucket that already satisfies duty and period
328 	 * or an unused one.
329 	 * If not found, -ENOENT is returned.
330 	 */
331 	bucket = airoha_pwm_get_generator(pc, duty_ticks, period_ticks);
332 	if (bucket < 0)
333 		return bucket;
334 
335 	/* Release previous used bucket (if any) */
336 	airoha_pwm_release_bucket_config(pc, hwpwm);
337 
338 	if (!pc->buckets[bucket].used)
339 		config_bucket = true;
340 	pc->buckets[bucket].used++;
341 
342 	if (config_bucket) {
343 		pc->buckets[bucket].period_ticks = period_ticks;
344 		pc->buckets[bucket].duty_ticks = duty_ticks;
345 		ret = airoha_pwm_apply_bucket_config(pc, bucket,
346 						     duty_ticks,
347 						     period_ticks);
348 		if (ret) {
349 			pc->buckets[bucket].used--;
350 			return ret;
351 		}
352 	}
353 
354 	return bucket;
355 }
356 
357 static int airoha_pwm_sipo_init(struct airoha_pwm *pc)
358 {
359 	u32 val;
360 	int ret;
361 
362 	ret = regmap_clear_bits(pc->regmap, AIROHA_PWM_REG_SIPO_FLASH_MODE_CFG,
363 				AIROHA_PWM_SERIAL_GPIO_MODE_74HC164);
364 	if (ret)
365 		return ret;
366 
367 	/* Configure shift register chip clock timings, use 32x divisor */
368 	ret = regmap_write(pc->regmap, AIROHA_PWM_REG_SGPIO_CLK_DIVR,
369 			   AIROHA_PWM_SGPIO_CLK_DIVR_32);
370 	if (ret)
371 		return ret;
372 
373 	/*
374 	 * Configure the shift register chip clock delay. This needs
375 	 * to be configured based on the chip characteristics when the SoC
376 	 * apply the shift register configuration.
377 	 * This doesn't affect actual PWM operation and is only specific to
378 	 * the shift register chip.
379 	 *
380 	 * For 74HC164 we set it to 0.
381 	 *
382 	 * For reference, the actual delay applied is the internal clock
383 	 * feed to the SGPIO chip + 1.
384 	 *
385 	 * From documentation is specified that clock delay should not be
386 	 * greater than (AIROHA_PWM_REG_SGPIO_CLK_DIVR / 2) - 1.
387 	 */
388 	ret = regmap_write(pc->regmap, AIROHA_PWM_REG_SGPIO_CLK_DLY, 0);
389 	if (ret)
390 		return ret;
391 
392 	/*
393 	 * It is necessary to explicitly shift out all zeros after muxing
394 	 * to initialize the shift register before enabling PWM
395 	 * mode because in PWM mode SIPO will not start shifting until
396 	 * it needs to output a non-zero value (bit 31 of led_data
397 	 * indicates shifting in progress and it must return to zero
398 	 * before led_data can be written or PWM mode can be set).
399 	 */
400 	ret = regmap_read_poll_timeout(pc->regmap, AIROHA_PWM_REG_SGPIO_LED_DATA, val,
401 				       !(val & AIROHA_PWM_SGPIO_LED_DATA_SHIFT_FLAG),
402 				       10, 200 * USEC_PER_MSEC);
403 	if (ret)
404 		return ret;
405 
406 	ret = regmap_clear_bits(pc->regmap, AIROHA_PWM_REG_SGPIO_LED_DATA,
407 				AIROHA_PWM_SGPIO_LED_DATA_DATA);
408 	if (ret)
409 		return ret;
410 	ret = regmap_read_poll_timeout(pc->regmap, AIROHA_PWM_REG_SGPIO_LED_DATA, val,
411 				       !(val & AIROHA_PWM_SGPIO_LED_DATA_SHIFT_FLAG),
412 				       10, 200 * USEC_PER_MSEC);
413 	if (ret)
414 		return ret;
415 
416 	/* Set SIPO in PWM mode */
417 	return regmap_set_bits(pc->regmap, AIROHA_PWM_REG_SIPO_FLASH_MODE_CFG,
418 			       AIROHA_PWM_SERIAL_GPIO_FLASH_MODE);
419 }
420 
421 static int airoha_pwm_config_flash_map(struct airoha_pwm *pc,
422 				       unsigned int hwpwm, int index)
423 {
424 	unsigned int addr;
425 	u32 shift;
426 	int ret;
427 
428 	airoha_pwm_get_flash_map_addr_and_shift(hwpwm, &addr, &shift);
429 
430 	/* negative index means disable PWM channel */
431 	if (index < 0) {
432 		/*
433 		 * If we need to disable the PWM, we just put low the
434 		 * GPIO. No need to setup buckets.
435 		 */
436 		return regmap_clear_bits(pc->regmap, addr,
437 					 AIROHA_PWM_GPIO_FLASH_EN << shift);
438 	}
439 
440 	ret = regmap_update_bits(pc->regmap, addr,
441 				 AIROHA_PWM_GPIO_FLASH_SET_ID << shift,
442 				 FIELD_PREP(AIROHA_PWM_GPIO_FLASH_SET_ID, index) << shift);
443 	if (ret)
444 		return ret;
445 
446 	return regmap_set_bits(pc->regmap, addr, AIROHA_PWM_GPIO_FLASH_EN << shift);
447 }
448 
449 static int airoha_pwm_config(struct airoha_pwm *pc, struct pwm_device *pwm,
450 			     u32 period_ticks, u32 duty_ticks)
451 {
452 	unsigned int hwpwm = pwm->hwpwm;
453 	int bucket, ret;
454 
455 	bucket = airoha_pwm_consume_generator(pc, duty_ticks, period_ticks,
456 					      hwpwm);
457 	if (bucket < 0)
458 		return bucket;
459 
460 	ret = airoha_pwm_config_flash_map(pc, hwpwm, bucket);
461 	if (ret) {
462 		pc->buckets[bucket].used--;
463 		return ret;
464 	}
465 
466 	__set_bit(hwpwm, pc->initialized);
467 	pc->channel_bucket[hwpwm] = bucket;
468 
469 	/*
470 	 * SIPO are special GPIO attached to a shift register chip. The handling
471 	 * of this chip is internal to the SoC that takes care of applying the
472 	 * values based on the flash map. To apply a new flash map, it's needed
473 	 * to trigger a refresh on the shift register chip.
474 	 * If a SIPO is getting configuring , always reinit the shift register
475 	 * chip to make sure the correct flash map is applied.
476 	 * Skip reconfiguring the shift register if the related hwpwm
477 	 * is disabled (as it doesn't need to be mapped).
478 	 */
479 	if (hwpwm >= AIROHA_PWM_NUM_GPIO) {
480 		ret = airoha_pwm_sipo_init(pc);
481 		if (ret) {
482 			airoha_pwm_release_bucket_config(pc, hwpwm);
483 			return ret;
484 		}
485 	}
486 
487 	return 0;
488 }
489 
490 static void airoha_pwm_disable(struct airoha_pwm *pc, struct pwm_device *pwm)
491 {
492 	/* Disable PWM and release the bucket */
493 	airoha_pwm_config_flash_map(pc, pwm->hwpwm, -1);
494 	airoha_pwm_release_bucket_config(pc, pwm->hwpwm);
495 
496 	__clear_bit(pwm->hwpwm, pc->initialized);
497 
498 	/* If no SIPO is used, disable the shift register chip */
499 	if (!bitmap_read(pc->initialized,
500 			 AIROHA_PWM_NUM_GPIO, AIROHA_PWM_NUM_SIPO))
501 		regmap_clear_bits(pc->regmap, AIROHA_PWM_REG_SIPO_FLASH_MODE_CFG,
502 				  AIROHA_PWM_SERIAL_GPIO_FLASH_MODE);
503 }
504 
505 static int airoha_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
506 			    const struct pwm_state *state)
507 {
508 	struct airoha_pwm *pc = pwmchip_get_drvdata(chip);
509 	u32 period_ticks, duty_ticks;
510 	u32 period_ns, duty_ns;
511 
512 	if (!state->enabled) {
513 		airoha_pwm_disable(pc, pwm);
514 		return 0;
515 	}
516 
517 	/* Only normal polarity is supported */
518 	if (state->polarity == PWM_POLARITY_INVERSED)
519 		return -EINVAL;
520 
521 	/* Exit early if period is less than minimum supported */
522 	if (state->period < AIROHA_PWM_PERIOD_TICK_NS)
523 		return -EINVAL;
524 
525 	/* Clamp period to MAX supported value */
526 	if (state->period > AIROHA_PWM_PERIOD_MAX_NS)
527 		period_ns = AIROHA_PWM_PERIOD_MAX_NS;
528 	else
529 		period_ns = state->period;
530 
531 	/* Validate duty to configured period */
532 	if (state->duty_cycle > period_ns)
533 		duty_ns = period_ns;
534 	else
535 		duty_ns = state->duty_cycle;
536 
537 	/* Convert period ns to ticks */
538 	period_ticks = airoha_pwm_get_period_ticks_from_ns(period_ns);
539 	/* Convert period ticks to ns again for cosistent duty tick calculation */
540 	period_ns = airoha_pwm_get_period_ns_from_ticks(period_ticks);
541 	duty_ticks = airoha_pwm_get_duty_ticks_from_ns(period_ns, duty_ns);
542 
543 	return airoha_pwm_config(pc, pwm, period_ticks, duty_ticks);
544 }
545 
546 static int airoha_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
547 				struct pwm_state *state)
548 {
549 	struct airoha_pwm *pc = pwmchip_get_drvdata(chip);
550 	int ret, hwpwm = pwm->hwpwm;
551 	u32 addr, shift, val;
552 	u8 bucket;
553 
554 	airoha_pwm_get_flash_map_addr_and_shift(hwpwm, &addr, &shift);
555 
556 	ret = regmap_read(pc->regmap, addr, &val);
557 	if (ret)
558 		return ret;
559 
560 	state->enabled = FIELD_GET(AIROHA_PWM_GPIO_FLASH_EN, val >> shift);
561 	if (!state->enabled)
562 		return 0;
563 
564 	state->polarity = PWM_POLARITY_NORMAL;
565 
566 	bucket = FIELD_GET(AIROHA_PWM_GPIO_FLASH_SET_ID, val >> shift);
567 	return airoha_pwm_get_bucket(pc, bucket, &state->period,
568 				     &state->duty_cycle);
569 }
570 
571 static const struct pwm_ops airoha_pwm_ops = {
572 	.apply = airoha_pwm_apply,
573 	.get_state = airoha_pwm_get_state,
574 };
575 
576 static int airoha_pwm_probe(struct platform_device *pdev)
577 {
578 	struct device *dev = &pdev->dev;
579 	struct airoha_pwm *pc;
580 	struct pwm_chip *chip;
581 	int ret;
582 
583 	chip = devm_pwmchip_alloc(dev, AIROHA_PWM_MAX_CHANNELS, sizeof(*pc));
584 	if (IS_ERR(chip))
585 		return PTR_ERR(chip);
586 
587 	chip->ops = &airoha_pwm_ops;
588 	pc = pwmchip_get_drvdata(chip);
589 
590 	pc->regmap = device_node_to_regmap(dev_of_node(dev->parent));
591 	if (IS_ERR(pc->regmap))
592 		return dev_err_probe(dev, PTR_ERR(pc->regmap), "Failed to get PWM regmap\n");
593 
594 	ret = devm_pwmchip_add(dev, chip);
595 	if (ret)
596 		return dev_err_probe(dev, ret, "Failed to add PWM chip\n");
597 
598 	return 0;
599 }
600 
601 static const struct of_device_id airoha_pwm_of_match[] = {
602 	{ .compatible = "airoha,en7581-pwm" },
603 	{ /* sentinel */ }
604 };
605 MODULE_DEVICE_TABLE(of, airoha_pwm_of_match);
606 
607 static struct platform_driver airoha_pwm_driver = {
608 	.driver = {
609 		.name = "pwm-airoha",
610 		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
611 		.of_match_table = airoha_pwm_of_match,
612 	},
613 	.probe = airoha_pwm_probe,
614 };
615 module_platform_driver(airoha_pwm_driver);
616 
617 MODULE_AUTHOR("Lorenzo Bianconi <lorenzo@kernel.org>");
618 MODULE_AUTHOR("Markus Gothe <markus.gothe@genexis.eu>");
619 MODULE_AUTHOR("Benjamin Larsson <benjamin.larsson@genexis.eu>");
620 MODULE_AUTHOR("Christian Marangi <ansuelsmth@gmail.com>");
621 MODULE_DESCRIPTION("Airoha EN7581 PWM driver");
622 MODULE_LICENSE("GPL");
623