pwm: Replace PWM chip unique base by unique ID
[linux-2.6-microblaze.git] / drivers / pwm / core.c
index 24bb796..ebe404d 100644 (file)
@@ -8,6 +8,7 @@
 
 #include <linux/acpi.h>
 #include <linux/module.h>
+#include <linux/idr.h>
 #include <linux/of.h>
 #include <linux/pwm.h>
 #include <linux/list.h>
 #define CREATE_TRACE_POINTS
 #include <trace/events/pwm.h>
 
-#define MAX_PWMS 1024
-
 static DEFINE_MUTEX(pwm_lookup_lock);
 static LIST_HEAD(pwm_lookup_list);
 
-/* protects access to pwm_chips and allocated_pwms */
+/* protects access to pwm_chips */
 static DEFINE_MUTEX(pwm_lock);
 
-static LIST_HEAD(pwm_chips);
-static DECLARE_BITMAP(allocated_pwms, MAX_PWMS);
-
-/* Called with pwm_lock held */
-static int alloc_pwms(unsigned int count)
-{
-       unsigned int start;
-
-       start = bitmap_find_next_zero_area(allocated_pwms, MAX_PWMS, 0,
-                                          count, 0);
-
-       if (start + count > MAX_PWMS)
-               return -ENOSPC;
-
-       bitmap_set(allocated_pwms, start, count);
-
-       return start;
-}
-
-/* Called with pwm_lock held */
-static void free_pwms(struct pwm_chip *chip)
-{
-       bitmap_clear(allocated_pwms, chip->base, chip->npwm);
-
-       kfree(chip->pwms);
-       chip->pwms = NULL;
-}
+static DEFINE_IDR(pwm_chips);
 
 static struct pwm_chip *pwmchip_find_by_name(const char *name)
 {
        struct pwm_chip *chip;
+       unsigned long id, tmp;
 
        if (!name)
                return NULL;
 
        mutex_lock(&pwm_lock);
 
-       list_for_each_entry(chip, &pwm_chips, list) {
+       idr_for_each_entry_ul(&pwm_chips, chip, tmp, id) {
                const char *chip_name = dev_name(chip->dev);
 
                if (chip_name && strcmp(chip_name, name) == 0) {
@@ -252,14 +226,14 @@ int __pwmchip_add(struct pwm_chip *chip, struct module *owner)
 
        mutex_lock(&pwm_lock);
 
-       ret = alloc_pwms(chip->npwm);
+       ret = idr_alloc(&pwm_chips, chip, 0, 0, GFP_KERNEL);
        if (ret < 0) {
                mutex_unlock(&pwm_lock);
                kfree(chip->pwms);
                return ret;
        }
 
-       chip->base = ret;
+       chip->id = ret;
 
        for (i = 0; i < chip->npwm; i++) {
                pwm = &chip->pwms[i];
@@ -268,8 +242,6 @@ int __pwmchip_add(struct pwm_chip *chip, struct module *owner)
                pwm->hwpwm = i;
        }
 
-       list_add(&chip->list, &pwm_chips);
-
        mutex_unlock(&pwm_lock);
 
        if (IS_ENABLED(CONFIG_OF))
@@ -296,11 +268,11 @@ void pwmchip_remove(struct pwm_chip *chip)
 
        mutex_lock(&pwm_lock);
 
-       list_del_init(&chip->list);
-
-       free_pwms(chip);
+       idr_remove(&pwm_chips, chip->id);
 
        mutex_unlock(&pwm_lock);
+
+       kfree(chip->pwms);
 }
 EXPORT_SYMBOL_GPL(pwmchip_remove);
 
@@ -596,10 +568,11 @@ EXPORT_SYMBOL_GPL(pwm_adjust_config);
 static struct pwm_chip *fwnode_to_pwmchip(struct fwnode_handle *fwnode)
 {
        struct pwm_chip *chip;
+       unsigned long id, tmp;
 
        mutex_lock(&pwm_lock);
 
-       list_for_each_entry(chip, &pwm_chips, list)
+       idr_for_each_entry_ul(&pwm_chips, chip, tmp, id)
                if (chip->dev && device_match_fwnode(chip->dev, fwnode)) {
                        mutex_unlock(&pwm_lock);
                        return chip;
@@ -1057,17 +1030,27 @@ static void pwm_dbg_show(struct pwm_chip *chip, struct seq_file *s)
 
 static void *pwm_seq_start(struct seq_file *s, loff_t *pos)
 {
+       unsigned long id = *pos;
+       void *ret;
+
        mutex_lock(&pwm_lock);
        s->private = "";
 
-       return seq_list_start(&pwm_chips, *pos);
+       ret = idr_get_next_ul(&pwm_chips, &id);
+       *pos = id;
+       return ret;
 }
 
 static void *pwm_seq_next(struct seq_file *s, void *v, loff_t *pos)
 {
+       unsigned long id = *pos + 1;
+       void *ret;
+
        s->private = "\n";
 
-       return seq_list_next(v, &pwm_chips, pos);
+       ret = idr_get_next_ul(&pwm_chips, &id);
+       *pos = id;
+       return ret;
 }
 
 static void pwm_seq_stop(struct seq_file *s, void *v)
@@ -1077,7 +1060,7 @@ static void pwm_seq_stop(struct seq_file *s, void *v)
 
 static int pwm_seq_show(struct seq_file *s, void *v)
 {
-       struct pwm_chip *chip = list_entry(v, struct pwm_chip, list);
+       struct pwm_chip *chip = v;
 
        seq_printf(s, "%s%s/%s, %d PWM device%s\n", (char *)s->private,
                   chip->dev->bus ? chip->dev->bus->name : "no-bus",