2 * Generic pwmlib implementation
4 * Copyright (C) 2011 Sascha Hauer <s.hauer@pengutronix.de>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; see the file COPYING. If not, write to
18 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
21 #include <linux/module.h>
22 #include <linux/pwm.h>
23 #include <linux/list.h>
24 #include <linux/mutex.h>
25 #include <linux/err.h>
26 #include <linux/slab.h>
27 #include <linux/device.h>
30 struct pwm_chip *chip;
33 #define FLAG_REQUESTED 0
34 #define FLAG_ENABLED 1
35 struct list_head node;
38 static LIST_HEAD(pwm_list);
40 static DEFINE_MUTEX(pwm_lock);
42 static struct pwm_device *_find_pwm(int pwm_id)
44 struct pwm_device *pwm;
46 list_for_each_entry(pwm, &pwm_list, node) {
47 if (pwm->chip->pwm_id == pwm_id)
55 * pwmchip_add() - register a new PWM chip
56 * @chip: the PWM chip to add
58 int pwmchip_add(struct pwm_chip *chip)
60 struct pwm_device *pwm;
63 pwm = kzalloc(sizeof(*pwm), GFP_KERNEL);
69 mutex_lock(&pwm_lock);
71 if (chip->pwm_id >= 0 && _find_pwm(chip->pwm_id)) {
76 list_add_tail(&pwm->node, &pwm_list);
78 mutex_unlock(&pwm_lock);
85 EXPORT_SYMBOL_GPL(pwmchip_add);
88 * pwmchip_remove() - remove a PWM chip
89 * @chip: the PWM chip to remove
91 * Removes a PWM chip. This function may return busy if the PWM chip provides
92 * a PWM device that is still requested.
94 int pwmchip_remove(struct pwm_chip *chip)
96 struct pwm_device *pwm;
99 mutex_lock(&pwm_lock);
101 pwm = _find_pwm(chip->pwm_id);
107 if (test_bit(FLAG_REQUESTED, &pwm->flags)) {
112 list_del(&pwm->node);
116 mutex_unlock(&pwm_lock);
120 EXPORT_SYMBOL_GPL(pwmchip_remove);
123 * pwm_request() - request a PWM device
124 * @pwm_id: global PWM device index
125 * @label: PWM device label
127 struct pwm_device *pwm_request(int pwm_id, const char *label)
129 struct pwm_device *pwm;
132 mutex_lock(&pwm_lock);
134 pwm = _find_pwm(pwm_id);
136 pwm = ERR_PTR(-ENOENT);
140 if (test_bit(FLAG_REQUESTED, &pwm->flags)) {
141 pwm = ERR_PTR(-EBUSY);
145 if (!try_module_get(pwm->chip->ops->owner)) {
146 pwm = ERR_PTR(-ENODEV);
150 if (pwm->chip->ops->request) {
151 ret = pwm->chip->ops->request(pwm->chip);
159 set_bit(FLAG_REQUESTED, &pwm->flags);
164 module_put(pwm->chip->ops->owner);
166 mutex_unlock(&pwm_lock);
170 EXPORT_SYMBOL_GPL(pwm_request);
173 * pwm_free() - free a PWM device
176 void pwm_free(struct pwm_device *pwm)
178 mutex_lock(&pwm_lock);
180 if (!test_and_clear_bit(FLAG_REQUESTED, &pwm->flags)) {
181 pr_warning("PWM device already freed\n");
187 module_put(pwm->chip->ops->owner);
189 mutex_unlock(&pwm_lock);
191 EXPORT_SYMBOL_GPL(pwm_free);
194 * pwm_config() - change a PWM device configuration
196 * @duty_ns: "on" time (in nanoseconds)
197 * @period_ns: duration (in nanoseconds) of one cycle
199 int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
201 return pwm->chip->ops->config(pwm->chip, duty_ns, period_ns);
203 EXPORT_SYMBOL_GPL(pwm_config);
206 * pwm_enable() - start a PWM output toggling
209 int pwm_enable(struct pwm_device *pwm)
211 if (!test_and_set_bit(FLAG_ENABLED, &pwm->flags))
212 return pwm->chip->ops->enable(pwm->chip);
216 EXPORT_SYMBOL_GPL(pwm_enable);
219 * pwm_disable() - stop a PWM output toggling
222 void pwm_disable(struct pwm_device *pwm)
224 if (test_and_clear_bit(FLAG_ENABLED, &pwm->flags))
225 pwm->chip->ops->disable(pwm->chip);
227 EXPORT_SYMBOL_GPL(pwm_disable);