pwm: Allow chips to support multiple PWMs
[deliverable/linux.git] / drivers / pwm / core.c
1 /*
2 * Generic pwmlib implementation
3 *
4 * Copyright (C) 2011 Sascha Hauer <s.hauer@pengutronix.de>
5 * Copyright (C) 2011-2012 Avionic Design GmbH
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2, or (at your option)
10 * any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; see the file COPYING. If not, write to
19 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 #include <linux/module.h>
23 #include <linux/pwm.h>
24 #include <linux/radix-tree.h>
25 #include <linux/list.h>
26 #include <linux/mutex.h>
27 #include <linux/err.h>
28 #include <linux/slab.h>
29 #include <linux/device.h>
30
31 #define MAX_PWMS 1024
32
33 static DEFINE_MUTEX(pwm_lock);
34 static LIST_HEAD(pwm_chips);
35 static DECLARE_BITMAP(allocated_pwms, MAX_PWMS);
36 static RADIX_TREE(pwm_tree, GFP_KERNEL);
37
38 static struct pwm_device *pwm_to_device(unsigned int pwm)
39 {
40 return radix_tree_lookup(&pwm_tree, pwm);
41 }
42
43 static int alloc_pwms(int pwm, unsigned int count)
44 {
45 unsigned int from = 0;
46 unsigned int start;
47
48 if (pwm >= MAX_PWMS)
49 return -EINVAL;
50
51 if (pwm >= 0)
52 from = pwm;
53
54 start = bitmap_find_next_zero_area(allocated_pwms, MAX_PWMS, from,
55 count, 0);
56
57 if (pwm >= 0 && start != pwm)
58 return -EEXIST;
59
60 if (start + count > MAX_PWMS)
61 return -ENOSPC;
62
63 return start;
64 }
65
66 static void free_pwms(struct pwm_chip *chip)
67 {
68 unsigned int i;
69
70 for (i = 0; i < chip->npwm; i++) {
71 struct pwm_device *pwm = &chip->pwms[i];
72 radix_tree_delete(&pwm_tree, pwm->pwm);
73 }
74
75 bitmap_clear(allocated_pwms, chip->base, chip->npwm);
76
77 kfree(chip->pwms);
78 chip->pwms = NULL;
79 }
80
81 static int pwm_device_request(struct pwm_device *pwm, const char *label)
82 {
83 int err;
84
85 if (test_bit(PWMF_REQUESTED, &pwm->flags))
86 return -EBUSY;
87
88 if (!try_module_get(pwm->chip->ops->owner))
89 return -ENODEV;
90
91 if (pwm->chip->ops->request) {
92 err = pwm->chip->ops->request(pwm->chip, pwm);
93 if (err) {
94 module_put(pwm->chip->ops->owner);
95 return err;
96 }
97 }
98
99 set_bit(PWMF_REQUESTED, &pwm->flags);
100 pwm->label = label;
101
102 return 0;
103 }
104
105 /**
106 * pwm_set_chip_data() - set private chip data for a PWM
107 * @pwm: PWM device
108 * @data: pointer to chip-specific data
109 */
110 int pwm_set_chip_data(struct pwm_device *pwm, void *data)
111 {
112 if (!pwm)
113 return -EINVAL;
114
115 pwm->chip_data = data;
116
117 return 0;
118 }
119
120 /**
121 * pwm_get_chip_data() - get private chip data for a PWM
122 * @pwm: PWM device
123 */
124 void *pwm_get_chip_data(struct pwm_device *pwm)
125 {
126 return pwm ? pwm->chip_data : NULL;
127 }
128
129 /**
130 * pwmchip_add() - register a new PWM chip
131 * @chip: the PWM chip to add
132 *
133 * Register a new PWM chip. If chip->base < 0 then a dynamically assigned base
134 * will be used.
135 */
136 int pwmchip_add(struct pwm_chip *chip)
137 {
138 struct pwm_device *pwm;
139 unsigned int i;
140 int ret;
141
142 if (!chip || !chip->dev || !chip->ops || !chip->ops->config ||
143 !chip->ops->enable || !chip->ops->disable)
144 return -EINVAL;
145
146 mutex_lock(&pwm_lock);
147
148 ret = alloc_pwms(chip->base, chip->npwm);
149 if (ret < 0)
150 goto out;
151
152 chip->pwms = kzalloc(chip->npwm * sizeof(*pwm), GFP_KERNEL);
153 if (!chip->pwms) {
154 ret = -ENOMEM;
155 goto out;
156 }
157
158 chip->base = ret;
159
160 for (i = 0; i < chip->npwm; i++) {
161 pwm = &chip->pwms[i];
162
163 pwm->chip = chip;
164 pwm->pwm = chip->base + i;
165 pwm->hwpwm = i;
166
167 radix_tree_insert(&pwm_tree, pwm->pwm, pwm);
168 }
169
170 bitmap_set(allocated_pwms, chip->base, chip->npwm);
171
172 INIT_LIST_HEAD(&chip->list);
173 list_add(&chip->list, &pwm_chips);
174
175 ret = 0;
176
177 out:
178 mutex_unlock(&pwm_lock);
179 return ret;
180 }
181 EXPORT_SYMBOL_GPL(pwmchip_add);
182
183 /**
184 * pwmchip_remove() - remove a PWM chip
185 * @chip: the PWM chip to remove
186 *
187 * Removes a PWM chip. This function may return busy if the PWM chip provides
188 * a PWM device that is still requested.
189 */
190 int pwmchip_remove(struct pwm_chip *chip)
191 {
192 unsigned int i;
193 int ret = 0;
194
195 mutex_lock(&pwm_lock);
196
197 for (i = 0; i < chip->npwm; i++) {
198 struct pwm_device *pwm = &chip->pwms[i];
199
200 if (test_bit(PWMF_REQUESTED, &pwm->flags)) {
201 ret = -EBUSY;
202 goto out;
203 }
204 }
205
206 list_del_init(&chip->list);
207 free_pwms(chip);
208
209 out:
210 mutex_unlock(&pwm_lock);
211 return ret;
212 }
213 EXPORT_SYMBOL_GPL(pwmchip_remove);
214
215 /**
216 * pwm_request() - request a PWM device
217 * @pwm_id: global PWM device index
218 * @label: PWM device label
219 */
220 struct pwm_device *pwm_request(int pwm, const char *label)
221 {
222 struct pwm_device *dev;
223 int err;
224
225 if (pwm < 0 || pwm >= MAX_PWMS)
226 return ERR_PTR(-EINVAL);
227
228 mutex_lock(&pwm_lock);
229
230 dev = pwm_to_device(pwm);
231 if (!dev) {
232 dev = ERR_PTR(-EPROBE_DEFER);
233 goto out;
234 }
235
236 err = pwm_device_request(dev, label);
237 if (err < 0)
238 dev = ERR_PTR(err);
239
240 out:
241 mutex_unlock(&pwm_lock);
242
243 return dev;
244 }
245 EXPORT_SYMBOL_GPL(pwm_request);
246
247 /**
248 * pwm_request_from_chip() - request a PWM device relative to a PWM chip
249 * @chip: PWM chip
250 * @index: per-chip index of the PWM to request
251 * @label: a literal description string of this PWM
252 *
253 * Returns the PWM at the given index of the given PWM chip. A negative error
254 * code is returned if the index is not valid for the specified PWM chip or
255 * if the PWM device cannot be requested.
256 */
257 struct pwm_device *pwm_request_from_chip(struct pwm_chip *chip,
258 unsigned int index,
259 const char *label)
260 {
261 struct pwm_device *pwm;
262 int err;
263
264 if (!chip || index >= chip->npwm)
265 return ERR_PTR(-EINVAL);
266
267 mutex_lock(&pwm_lock);
268 pwm = &chip->pwms[index];
269
270 err = pwm_device_request(pwm, label);
271 if (err < 0)
272 pwm = ERR_PTR(err);
273
274 mutex_unlock(&pwm_lock);
275 return pwm;
276 }
277 EXPORT_SYMBOL_GPL(pwm_request_from_chip);
278
279 /**
280 * pwm_free() - free a PWM device
281 * @pwm: PWM device
282 */
283 void pwm_free(struct pwm_device *pwm)
284 {
285 mutex_lock(&pwm_lock);
286
287 if (!test_and_clear_bit(PWMF_REQUESTED, &pwm->flags)) {
288 pr_warning("PWM device already freed\n");
289 goto out;
290 }
291
292 if (pwm->chip->ops->free)
293 pwm->chip->ops->free(pwm->chip, pwm);
294
295 pwm->label = NULL;
296
297 module_put(pwm->chip->ops->owner);
298 out:
299 mutex_unlock(&pwm_lock);
300 }
301 EXPORT_SYMBOL_GPL(pwm_free);
302
303 /**
304 * pwm_config() - change a PWM device configuration
305 * @pwm: PWM device
306 * @duty_ns: "on" time (in nanoseconds)
307 * @period_ns: duration (in nanoseconds) of one cycle
308 */
309 int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
310 {
311 if (!pwm || period_ns == 0 || duty_ns > period_ns)
312 return -EINVAL;
313
314 return pwm->chip->ops->config(pwm->chip, pwm, duty_ns, period_ns);
315 }
316 EXPORT_SYMBOL_GPL(pwm_config);
317
318 /**
319 * pwm_enable() - start a PWM output toggling
320 * @pwm: PWM device
321 */
322 int pwm_enable(struct pwm_device *pwm)
323 {
324 if (pwm && !test_and_set_bit(PWMF_ENABLED, &pwm->flags))
325 return pwm->chip->ops->enable(pwm->chip, pwm);
326
327 return pwm ? 0 : -EINVAL;
328 }
329 EXPORT_SYMBOL_GPL(pwm_enable);
330
331 /**
332 * pwm_disable() - stop a PWM output toggling
333 * @pwm: PWM device
334 */
335 void pwm_disable(struct pwm_device *pwm)
336 {
337 if (pwm && test_and_clear_bit(PWMF_ENABLED, &pwm->flags))
338 pwm->chip->ops->disable(pwm->chip, pwm);
339 }
340 EXPORT_SYMBOL_GPL(pwm_disable);
This page took 0.049265 seconds and 5 git commands to generate.