From f917e6f866e6b0304a9f4e64980c27fb85271a40 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Tue, 31 Jan 2012 10:19:50 +0100 Subject: Add pwm core support This patch adds framework support for PWM (pulse width modulation) devices. A new pwm can be registered from a hardware driver using pwmchip_add(). It can then be requested from a client driver using pwm_request(). A string is used as a unique identifier for the pwms. It should usually be initialized by the hardware drivers using dev_name(dev). The client API is the same as currently in the Linux Kernel. Signed-off-by: Sascha Hauer --- drivers/pwm/Kconfig | 12 ++++ drivers/pwm/Makefile | 1 + drivers/pwm/core.c | 163 +++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 176 insertions(+) create mode 100644 drivers/pwm/Kconfig create mode 100644 drivers/pwm/Makefile create mode 100644 drivers/pwm/core.c (limited to 'drivers/pwm') diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig new file mode 100644 index 0000000000..93c1052291 --- /dev/null +++ b/drivers/pwm/Kconfig @@ -0,0 +1,12 @@ +menuconfig PWM + bool "PWM Support" + help + This enables PWM support through the generic PWM framework. + You only need to enable this, if you also want to enable + one or more of the PWM drivers below. + + If unsure, say N. + +if PWM + +endif diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile new file mode 100644 index 0000000000..3469c3d28b --- /dev/null +++ b/drivers/pwm/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_PWM) += core.o diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c new file mode 100644 index 0000000000..af30edfd32 --- /dev/null +++ b/drivers/pwm/core.c @@ -0,0 +1,163 @@ +/* + * Generic pwmlib implementation + * + * Copyright (C) 2011 Sascha Hauer + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include +#include +#include +#include + +struct pwm_device { + struct pwm_chip *chip; + unsigned long flags; +#define FLAG_REQUESTED 0 +#define FLAG_ENABLED 1 + struct list_head node; +}; + +static LIST_HEAD(pwm_list); + +static struct pwm_device *_find_pwm(const char *devname) +{ + struct pwm_device *pwm; + + list_for_each_entry(pwm, &pwm_list, node) { + if (!strcmp(pwm->chip->devname, devname)) + return pwm; + } + + return NULL; +} + +/** + * pwmchip_add() - register a new pwm + * @chip: the pwm + * + * register a new pwm. pwm->devname must be initialized, usually + * from dev_name(dev) from the hardware driver. + */ +int pwmchip_add(struct pwm_chip *chip) +{ + struct pwm_device *pwm; + int ret = 0; + + if (_find_pwm(chip->devname)) + return -EBUSY; + + pwm = xzalloc(sizeof(*pwm)); + pwm->chip = chip; + + list_add_tail(&pwm->node, &pwm_list); + + return ret; +} +EXPORT_SYMBOL_GPL(pwmchip_add); + +/** + * pwmchip_remove() - remove a pwm + * @chip: the pwm + * + * remove a pwm. This function may return busy if the pwm is still requested. + */ +int pwmchip_remove(struct pwm_chip *chip) +{ + struct pwm_device *pwm; + + pwm = _find_pwm(chip->devname); + if (!pwm) + return -ENOENT; + + if (test_bit(FLAG_REQUESTED, &pwm->flags)) + return -EBUSY; + + list_del(&pwm->node); + + kfree(pwm); + + return 0; +} +EXPORT_SYMBOL_GPL(pwmchip_remove); + +/* + * pwm_request - request a PWM device + */ +struct pwm_device *pwm_request(const char *devname) +{ + struct pwm_device *pwm; + int ret; + + pwm = _find_pwm(devname); + if (!pwm) + return NULL; + + if (test_bit(FLAG_REQUESTED, &pwm->flags)) + return NULL; + + if (pwm->chip->ops->request) { + ret = pwm->chip->ops->request(pwm->chip); + if (ret) + return NULL; + } + + set_bit(FLAG_REQUESTED, &pwm->flags); + + return pwm; +} +EXPORT_SYMBOL_GPL(pwm_request); + +/* + * pwm_free - free a PWM device + */ +void pwm_free(struct pwm_device *pwm) +{ + if (!test_and_clear_bit(FLAG_REQUESTED, &pwm->flags)) + return; +} +EXPORT_SYMBOL_GPL(pwm_free); + +/* + * pwm_config - change a PWM device configuration + */ +int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns) +{ + return pwm->chip->ops->config(pwm->chip, duty_ns, period_ns); +} +EXPORT_SYMBOL_GPL(pwm_config); + +/* + * pwm_enable - start a PWM output toggling + */ +int pwm_enable(struct pwm_device *pwm) +{ + if (!test_and_set_bit(FLAG_ENABLED, &pwm->flags)) + return pwm->chip->ops->enable(pwm->chip); + + return 0; +} +EXPORT_SYMBOL_GPL(pwm_enable); + +/* + * pwm_disable - stop a PWM output toggling + */ +void pwm_disable(struct pwm_device *pwm) +{ + if (test_and_clear_bit(FLAG_ENABLED, &pwm->flags)) + pwm->chip->ops->disable(pwm->chip); +} +EXPORT_SYMBOL_GPL(pwm_disable); -- cgit v1.2.3