aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThierry Reding <thierry.reding@avionic-design.de>2012-03-26 02:42:48 -0400
committerThierry Reding <thierry.reding@avionic-design.de>2012-06-15 06:56:53 -0400
commit8138d2ddbcca2a100482dac390133f83c5a60f94 (patch)
tree814645a7608376af451f9721dd3da585a87bbdd6
parent62099abf67a20cfb98d4c031fb1925e10a78ee1b (diff)
pwm: Add table-based lookup for static mappings
In order to get rid of the global namespace for PWM devices, this commit provides an alternative method, similar to that of the regulator or clock frameworks, for registering a static mapping for PWM devices. This works by providing a table with a provider/consumer map in the board setup code. With the new pwm_get() and pwm_put() functions available, usage of pwm_request() and pwm_free() becomes deprecated. Reviewed-by: Shawn Guo <shawn.guo@linaro.org> Reviewed-by: Mark Brown <broonie@opensource.wolfsonmicro.com> Signed-off-by: Thierry Reding <thierry.reding@avionic-design.de>
-rw-r--r--Documentation/pwm.txt27
-rw-r--r--drivers/pwm/core.c169
-rw-r--r--include/linux/pwm.h22
3 files changed, 199 insertions, 19 deletions
diff --git a/Documentation/pwm.txt b/Documentation/pwm.txt
index 48f598acdd16..554290ebab94 100644
--- a/Documentation/pwm.txt
+++ b/Documentation/pwm.txt
@@ -12,14 +12,33 @@ this kind of flexibility the generic PWM API exists.
12Identifying PWMs 12Identifying PWMs
13---------------- 13----------------
14 14
15Users of the legacy PWM API use unique IDs to refer to PWM devices. One 15Users of the legacy PWM API use unique IDs to refer to PWM devices.
16goal of the new PWM framework is to get rid of this global namespace. 16
17Instead of referring to a PWM device via its unique ID, board setup code
18should instead register a static mapping that can be used to match PWM
19consumers to providers, as given in the following example:
20
21 static struct pwm_lookup board_pwm_lookup[] = {
22 PWM_LOOKUP("tegra-pwm", 0, "pwm-backlight", NULL),
23 };
24
25 static void __init board_init(void)
26 {
27 ...
28 pwm_add_table(board_pwm_lookup, ARRAY_SIZE(board_pwm_lookup));
29 ...
30 }
17 31
18Using PWMs 32Using PWMs
19---------- 33----------
20 34
21A PWM can be requested using pwm_request() and freed after usage with 35Legacy users can request a PWM device using pwm_request() and free it
22pwm_free(). After being requested a PWM has to be configured using 36after usage with pwm_free().
37
38New users should use the pwm_get() function and pass to it the consumer
39device or a consumer name. pwm_put() is used to free the PWM device.
40
41After being requested a PWM has to be configured using:
23 42
24int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns); 43int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns);
25 44
diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c
index aadc1d797449..a2af599e61ae 100644
--- a/drivers/pwm/core.c
+++ b/drivers/pwm/core.c
@@ -32,6 +32,8 @@
32 32
33#define MAX_PWMS 1024 33#define MAX_PWMS 1024
34 34
35static DEFINE_MUTEX(pwm_lookup_lock);
36static LIST_HEAD(pwm_lookup_list);
35static DEFINE_MUTEX(pwm_lock); 37static DEFINE_MUTEX(pwm_lock);
36static LIST_HEAD(pwm_chips); 38static LIST_HEAD(pwm_chips);
37static DECLARE_BITMAP(allocated_pwms, MAX_PWMS); 39static DECLARE_BITMAP(allocated_pwms, MAX_PWMS);
@@ -80,6 +82,29 @@ static void free_pwms(struct pwm_chip *chip)
80 chip->pwms = NULL; 82 chip->pwms = NULL;
81} 83}
82 84
85static struct pwm_chip *pwmchip_find_by_name(const char *name)
86{
87 struct pwm_chip *chip;
88
89 if (!name)
90 return NULL;
91
92 mutex_lock(&pwm_lock);
93
94 list_for_each_entry(chip, &pwm_chips, list) {
95 const char *chip_name = dev_name(chip->dev);
96
97 if (chip_name && strcmp(chip_name, name) == 0) {
98 mutex_unlock(&pwm_lock);
99 return chip;
100 }
101 }
102
103 mutex_unlock(&pwm_lock);
104
105 return NULL;
106}
107
83static int pwm_device_request(struct pwm_device *pwm, const char *label) 108static int pwm_device_request(struct pwm_device *pwm, const char *label)
84{ 109{
85 int err; 110 int err;
@@ -218,6 +243,8 @@ EXPORT_SYMBOL_GPL(pwmchip_remove);
218 * pwm_request() - request a PWM device 243 * pwm_request() - request a PWM device
219 * @pwm_id: global PWM device index 244 * @pwm_id: global PWM device index
220 * @label: PWM device label 245 * @label: PWM device label
246 *
247 * This function is deprecated, use pwm_get() instead.
221 */ 248 */
222struct pwm_device *pwm_request(int pwm, const char *label) 249struct pwm_device *pwm_request(int pwm, const char *label)
223{ 250{
@@ -281,24 +308,12 @@ EXPORT_SYMBOL_GPL(pwm_request_from_chip);
281/** 308/**
282 * pwm_free() - free a PWM device 309 * pwm_free() - free a PWM device
283 * @pwm: PWM device 310 * @pwm: PWM device
311 *
312 * This function is deprecated, use pwm_put() instead.
284 */ 313 */
285void pwm_free(struct pwm_device *pwm) 314void pwm_free(struct pwm_device *pwm)
286{ 315{
287 mutex_lock(&pwm_lock); 316 pwm_put(pwm);
288
289 if (!test_and_clear_bit(PWMF_REQUESTED, &pwm->flags)) {
290 pr_warning("PWM device already freed\n");
291 goto out;
292 }
293
294 if (pwm->chip->ops->free)
295 pwm->chip->ops->free(pwm->chip, pwm);
296
297 pwm->label = NULL;
298
299 module_put(pwm->chip->ops->owner);
300out:
301 mutex_unlock(&pwm_lock);
302} 317}
303EXPORT_SYMBOL_GPL(pwm_free); 318EXPORT_SYMBOL_GPL(pwm_free);
304 319
@@ -341,6 +356,130 @@ void pwm_disable(struct pwm_device *pwm)
341} 356}
342EXPORT_SYMBOL_GPL(pwm_disable); 357EXPORT_SYMBOL_GPL(pwm_disable);
343 358
359/**
360 * pwm_add_table() - register PWM device consumers
361 * @table: array of consumers to register
362 * @num: number of consumers in table
363 */
364void __init pwm_add_table(struct pwm_lookup *table, size_t num)
365{
366 mutex_lock(&pwm_lookup_lock);
367
368 while (num--) {
369 list_add_tail(&table->list, &pwm_lookup_list);
370 table++;
371 }
372
373 mutex_unlock(&pwm_lookup_lock);
374}
375
376/**
377 * pwm_get() - look up and request a PWM device
378 * @dev: device for PWM consumer
379 * @con_id: consumer name
380 *
381 * Look up a PWM chip and a relative index via a table supplied by board setup
382 * code (see pwm_add_table()).
383 *
384 * Once a PWM chip has been found the specified PWM device will be requested
385 * and is ready to be used.
386 */
387struct pwm_device *pwm_get(struct device *dev, const char *con_id)
388{
389 struct pwm_device *pwm = ERR_PTR(-EPROBE_DEFER);
390 const char *dev_id = dev ? dev_name(dev): NULL;
391 struct pwm_chip *chip = NULL;
392 unsigned int best = 0;
393 struct pwm_lookup *p;
394 unsigned int index;
395 unsigned int match;
396
397 /*
398 * We look up the provider in the static table typically provided by
399 * board setup code. We first try to lookup the consumer device by
400 * name. If the consumer device was passed in as NULL or if no match
401 * was found, we try to find the consumer by directly looking it up
402 * by name.
403 *
404 * If a match is found, the provider PWM chip is looked up by name
405 * and a PWM device is requested using the PWM device per-chip index.
406 *
407 * The lookup algorithm was shamelessly taken from the clock
408 * framework:
409 *
410 * We do slightly fuzzy matching here:
411 * An entry with a NULL ID is assumed to be a wildcard.
412 * If an entry has a device ID, it must match
413 * If an entry has a connection ID, it must match
414 * Then we take the most specific entry - with the following order
415 * of precedence: dev+con > dev only > con only.
416 */
417 mutex_lock(&pwm_lookup_lock);
418
419 list_for_each_entry(p, &pwm_lookup_list, list) {
420 match = 0;
421
422 if (p->dev_id) {
423 if (!dev_id || strcmp(p->dev_id, dev_id))
424 continue;
425
426 match += 2;
427 }
428
429 if (p->con_id) {
430 if (!con_id || strcmp(p->con_id, con_id))
431 continue;
432
433 match += 1;
434 }
435
436 if (match > best) {
437 chip = pwmchip_find_by_name(p->provider);
438 index = p->index;
439
440 if (match != 3)
441 best = match;
442 else
443 break;
444 }
445 }
446
447 if (chip)
448 pwm = pwm_request_from_chip(chip, index, con_id ?: dev_id);
449
450 mutex_unlock(&pwm_lookup_lock);
451
452 return pwm;
453}
454EXPORT_SYMBOL_GPL(pwm_get);
455
456/**
457 * pwm_put() - release a PWM device
458 * @pwm: PWM device
459 */
460void pwm_put(struct pwm_device *pwm)
461{
462 if (!pwm)
463 return;
464
465 mutex_lock(&pwm_lock);
466
467 if (!test_and_clear_bit(PWMF_REQUESTED, &pwm->flags)) {
468 pr_warning("PWM device already freed\n");
469 goto out;
470 }
471
472 if (pwm->chip->ops->free)
473 pwm->chip->ops->free(pwm->chip, pwm);
474
475 pwm->label = NULL;
476
477 module_put(pwm->chip->ops->owner);
478out:
479 mutex_unlock(&pwm_lock);
480}
481EXPORT_SYMBOL_GPL(pwm_put);
482
344#ifdef CONFIG_DEBUG_FS 483#ifdef CONFIG_DEBUG_FS
345static void pwm_dbg_show(struct pwm_chip *chip, struct seq_file *s) 484static void pwm_dbg_show(struct pwm_chip *chip, struct seq_file *s)
346{ 485{
diff --git a/include/linux/pwm.h b/include/linux/pwm.h
index 047cd5351a3b..2947a4fea6ad 100644
--- a/include/linux/pwm.h
+++ b/include/linux/pwm.h
@@ -115,6 +115,28 @@ int pwmchip_remove(struct pwm_chip *chip);
115struct pwm_device *pwm_request_from_chip(struct pwm_chip *chip, 115struct pwm_device *pwm_request_from_chip(struct pwm_chip *chip,
116 unsigned int index, 116 unsigned int index,
117 const char *label); 117 const char *label);
118
119struct pwm_device *pwm_get(struct device *dev, const char *consumer);
120void pwm_put(struct pwm_device *pwm);
121
122struct pwm_lookup {
123 struct list_head list;
124 const char *provider;
125 unsigned int index;
126 const char *dev_id;
127 const char *con_id;
128};
129
130#define PWM_LOOKUP(_provider, _index, _dev_id, _con_id) \
131 { \
132 .provider = _provider, \
133 .index = _index, \
134 .dev_id = _dev_id, \
135 .con_id = _con_id, \
136 }
137
138void pwm_add_table(struct pwm_lookup *table, size_t num);
139
118#endif 140#endif
119 141
120#endif /* __LINUX_PWM_H */ 142#endif /* __LINUX_PWM_H */