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

pwm: Provide a gpio device for waveform drivers

A PWM is a more general concept than an output-only GPIO. When using
duty_length = period_length the PWM looks like an active GPIO, with
duty_length = 0 like an inactive GPIO. With the waveform abstraction
there is enough control over the configuration to ensure that PWMs that
cannot generate a constant signal at both levels error out.

The pwm-pca9685 driver already provides a gpio chip. When this driver is
converted to the waveform callbacks, the gpio part can just be dropped.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@baylibre.com>
Reviewed-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
Link: https://lore.kernel.org/r/20250717151117.1828585-2-u.kleine-koenig@baylibre.com
Signed-off-by: Uwe Kleine-König <ukleinek@kernel.org>

authored by

Uwe Kleine-König and committed by
Uwe Kleine-König
e7c9b66b b871d093

+84
+9
drivers/pwm/Kconfig
··· 38 38 It is expected to introduce some runtime overhead and diagnostic 39 39 output to the kernel log, so only enable while working on a driver. 40 40 41 + config PWM_PROVIDE_GPIO 42 + bool "Provide a GPIO chip for each PWM chip" 43 + depends on GPIOLIB 44 + help 45 + Most PWMs can emit both a constant active high and a constant active 46 + low signal and so they can be used as GPIO. Say Y here to let each 47 + PWM chip provide a GPIO chip and so be easily plugged into consumers 48 + that know how to handle GPIOs but not PWMs. 49 + 41 50 config PWM_AB8500 42 51 tristate "AB8500 PWM support" 43 52 depends on AB8500_CORE && ARCH_U8500
+72
drivers/pwm/core.c
··· 2391 2391 2392 2392 static dev_t pwm_devt; 2393 2393 2394 + static int pwm_gpio_request(struct gpio_chip *gc, unsigned int offset) 2395 + { 2396 + struct pwm_chip *chip = gpiochip_get_data(gc); 2397 + struct pwm_device *pwm; 2398 + 2399 + pwm = pwm_request_from_chip(chip, offset, "pwm-gpio"); 2400 + if (IS_ERR(pwm)) 2401 + return PTR_ERR(pwm); 2402 + 2403 + return 0; 2404 + } 2405 + 2406 + static void pwm_gpio_free(struct gpio_chip *gc, unsigned int offset) 2407 + { 2408 + struct pwm_chip *chip = gpiochip_get_data(gc); 2409 + 2410 + pwm_put(&chip->pwms[offset]); 2411 + } 2412 + 2413 + static int pwm_gpio_get_direction(struct gpio_chip *gc, unsigned int offset) 2414 + { 2415 + return GPIO_LINE_DIRECTION_OUT; 2416 + } 2417 + 2418 + static int pwm_gpio_set(struct gpio_chip *gc, unsigned int offset, int value) 2419 + { 2420 + struct pwm_chip *chip = gpiochip_get_data(gc); 2421 + struct pwm_device *pwm = &chip->pwms[offset]; 2422 + int ret; 2423 + struct pwm_waveform wf = { 2424 + .period_length_ns = 1, 2425 + }; 2426 + 2427 + ret = pwm_round_waveform_might_sleep(pwm, &wf); 2428 + if (ret < 0) 2429 + return ret; 2430 + 2431 + if (value) 2432 + wf.duty_length_ns = wf.period_length_ns; 2433 + else 2434 + wf.duty_length_ns = 0; 2435 + 2436 + return pwm_set_waveform_might_sleep(pwm, &wf, true); 2437 + } 2438 + 2394 2439 /** 2395 2440 * __pwmchip_add() - register a new PWM chip 2396 2441 * @chip: the PWM chip to add ··· 2502 2457 if (ret) 2503 2458 goto err_device_add; 2504 2459 2460 + if (IS_ENABLED(CONFIG_PWM_PROVIDE_GPIO) && chip->ops->write_waveform) { 2461 + struct device *parent = pwmchip_parent(chip); 2462 + 2463 + chip->gpio = (typeof(chip->gpio)){ 2464 + .label = dev_name(parent), 2465 + .parent = parent, 2466 + .request = pwm_gpio_request, 2467 + .free = pwm_gpio_free, 2468 + .get_direction = pwm_gpio_get_direction, 2469 + .set = pwm_gpio_set, 2470 + .base = -1, 2471 + .ngpio = chip->npwm, 2472 + .can_sleep = true, 2473 + }; 2474 + 2475 + ret = gpiochip_add_data(&chip->gpio, chip); 2476 + if (ret) 2477 + goto err_gpiochip_add; 2478 + } 2479 + 2505 2480 return 0; 2506 2481 2482 + err_gpiochip_add: 2483 + 2484 + cdev_device_del(&chip->cdev, &chip->dev); 2507 2485 err_device_add: 2486 + 2508 2487 scoped_guard(pwmchip, chip) 2509 2488 chip->operational = false; 2510 2489 ··· 2549 2480 */ 2550 2481 void pwmchip_remove(struct pwm_chip *chip) 2551 2482 { 2483 + if (IS_ENABLED(CONFIG_PWM_PROVIDE_GPIO) && chip->ops->write_waveform) 2484 + gpiochip_remove(&chip->gpio); 2485 + 2552 2486 pwmchip_sysfs_unexport(chip); 2553 2487 2554 2488 scoped_guard(mutex, &pwm_lock) {
+3
include/linux/pwm.h
··· 5 5 #include <linux/cdev.h> 6 6 #include <linux/device.h> 7 7 #include <linux/err.h> 8 + #include <linux/gpio/driver.h> 8 9 #include <linux/module.h> 9 10 #include <linux/mutex.h> 10 11 #include <linux/of.h> ··· 322 321 * @npwm: number of PWMs controlled by this chip 323 322 * @of_xlate: request a PWM device given a device tree PWM specifier 324 323 * @atomic: can the driver's ->apply() be called in atomic context 324 + * @gpio: &struct gpio_chip to operate this PWM chip's lines as GPO 325 325 * @uses_pwmchip_alloc: signals if pwmchip_allow was used to allocate this chip 326 326 * @operational: signals if the chip can be used (or is already deregistered) 327 327 * @nonatomic_lock: mutex for nonatomic chips ··· 342 340 bool atomic; 343 341 344 342 /* only used internally by the PWM framework */ 343 + struct gpio_chip gpio; 345 344 bool uses_pwmchip_alloc; 346 345 bool operational; 347 346 union {