It is expected to introduce some runtime overhead and diagnostic
output to the kernel log, so only enable while working on a driver.
+config PWM_PROVIDE_GPIO
+ bool "Provide a GPIO chip for each PWM chip"
+ depends on GPIOLIB
+ help
+ Most PWMs can emit both a constant active high and a constant active
+ low signal and so they can be used as GPIO. Say Y here to let each
+ PWM chip provide a GPIO chip and so be easily plugged into consumers
+ that know how to handle GPIOs but not PWMs.
+
config PWM_AB8500
tristate "AB8500 PWM support"
depends on AB8500_CORE && ARCH_U8500
static dev_t pwm_devt;
+static int pwm_gpio_request(struct gpio_chip *gc, unsigned int offset)
+{
+ struct pwm_chip *chip = gpiochip_get_data(gc);
+ struct pwm_device *pwm;
+
+ pwm = pwm_request_from_chip(chip, offset, "pwm-gpio");
+ if (IS_ERR(pwm))
+ return PTR_ERR(pwm);
+
+ return 0;
+}
+
+static void pwm_gpio_free(struct gpio_chip *gc, unsigned int offset)
+{
+ struct pwm_chip *chip = gpiochip_get_data(gc);
+
+ pwm_put(&chip->pwms[offset]);
+}
+
+static int pwm_gpio_get_direction(struct gpio_chip *gc, unsigned int offset)
+{
+ return GPIO_LINE_DIRECTION_OUT;
+}
+
+static int pwm_gpio_set(struct gpio_chip *gc, unsigned int offset, int value)
+{
+ struct pwm_chip *chip = gpiochip_get_data(gc);
+ struct pwm_device *pwm = &chip->pwms[offset];
+ int ret;
+ struct pwm_waveform wf = {
+ .period_length_ns = 1,
+ };
+
+ ret = pwm_round_waveform_might_sleep(pwm, &wf);
+ if (ret < 0)
+ return ret;
+
+ if (value)
+ wf.duty_length_ns = wf.period_length_ns;
+ else
+ wf.duty_length_ns = 0;
+
+ return pwm_set_waveform_might_sleep(pwm, &wf, true);
+}
+
/**
* __pwmchip_add() - register a new PWM chip
* @chip: the PWM chip to add
if (ret)
goto err_device_add;
+ if (IS_ENABLED(CONFIG_PWM_PROVIDE_GPIO) && chip->ops->write_waveform) {
+ struct device *parent = pwmchip_parent(chip);
+
+ chip->gpio = (typeof(chip->gpio)){
+ .label = dev_name(parent),
+ .parent = parent,
+ .request = pwm_gpio_request,
+ .free = pwm_gpio_free,
+ .get_direction = pwm_gpio_get_direction,
+ .set = pwm_gpio_set,
+ .base = -1,
+ .ngpio = chip->npwm,
+ .can_sleep = true,
+ };
+
+ ret = gpiochip_add_data(&chip->gpio, chip);
+ if (ret)
+ goto err_gpiochip_add;
+ }
+
return 0;
+err_gpiochip_add:
+
+ cdev_device_del(&chip->cdev, &chip->dev);
err_device_add:
+
scoped_guard(pwmchip, chip)
chip->operational = false;
*/
void pwmchip_remove(struct pwm_chip *chip)
{
+ if (IS_ENABLED(CONFIG_PWM_PROVIDE_GPIO) && chip->ops->write_waveform)
+ gpiochip_remove(&chip->gpio);
+
pwmchip_sysfs_unexport(chip);
scoped_guard(mutex, &pwm_lock) {
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/err.h>
+#include <linux/gpio/driver.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of.h>
* @npwm: number of PWMs controlled by this chip
* @of_xlate: request a PWM device given a device tree PWM specifier
* @atomic: can the driver's ->apply() be called in atomic context
+ * @gpio: &struct gpio_chip to operate this PWM chip's lines as GPO
* @uses_pwmchip_alloc: signals if pwmchip_allow was used to allocate this chip
* @operational: signals if the chip can be used (or is already deregistered)
* @nonatomic_lock: mutex for nonatomic chips
bool atomic;
/* only used internally by the PWM framework */
+ struct gpio_chip gpio;
bool uses_pwmchip_alloc;
bool operational;
union {