Merge git://git.infradead.org/mtd-2.6
[pandora-kernel.git] / drivers / gpio / gpiolib.c
index 6a6bd56..21da9c1 100644 (file)
@@ -57,9 +57,9 @@ struct gpio_desc {
 #define FLAG_TRIG_RISE 6       /* trigger on rising edge */
 #define FLAG_ACTIVE_LOW        7       /* sysfs value has active low */
 
-#define PDESC_ID_SHIFT 16      /* add new flags before this one */
+#define ID_SHIFT       16      /* add new flags before this one */
 
-#define GPIO_FLAGS_MASK                ((1 << PDESC_ID_SHIFT) - 1)
+#define GPIO_FLAGS_MASK                ((1 << ID_SHIFT) - 1)
 #define GPIO_TRIGGER_MASK      (BIT(FLAG_TRIG_FALL) | BIT(FLAG_TRIG_RISE))
 
 #ifdef CONFIG_DEBUG_FS
@@ -69,12 +69,7 @@ struct gpio_desc {
 static struct gpio_desc gpio_desc[ARCH_NR_GPIOS];
 
 #ifdef CONFIG_GPIO_SYSFS
-struct poll_desc {
-       struct work_struct      work;
-       struct sysfs_dirent     *value_sd;
-};
-
-static struct idr pdesc_idr;
+static DEFINE_IDR(dirent_idr);
 #endif
 
 static inline void desc_set_label(struct gpio_desc *d, const char *label)
@@ -325,24 +320,16 @@ static const DEVICE_ATTR(value, 0644,
 
 static irqreturn_t gpio_sysfs_irq(int irq, void *priv)
 {
-       struct work_struct      *work = priv;
+       struct sysfs_dirent     *value_sd = priv;
 
-       schedule_work(work);
+       sysfs_notify_dirent(value_sd);
        return IRQ_HANDLED;
 }
 
-static void gpio_notify_sysfs(struct work_struct *work)
-{
-       struct poll_desc        *pdesc;
-
-       pdesc = container_of(work, struct poll_desc, work);
-       sysfs_notify_dirent(pdesc->value_sd);
-}
-
 static int gpio_setup_irq(struct gpio_desc *desc, struct device *dev,
                unsigned long gpio_flags)
 {
-       struct poll_desc        *pdesc;
+       struct sysfs_dirent     *value_sd;
        unsigned long           irq_flags;
        int                     ret, irq, id;
 
@@ -353,18 +340,16 @@ static int gpio_setup_irq(struct gpio_desc *desc, struct device *dev,
        if (irq < 0)
                return -EIO;
 
-       id = desc->flags >> PDESC_ID_SHIFT;
-       pdesc = idr_find(&pdesc_idr, id);
-       if (pdesc) {
-               free_irq(irq, &pdesc->work);
-               cancel_work_sync(&pdesc->work);
-       }
+       id = desc->flags >> ID_SHIFT;
+       value_sd = idr_find(&dirent_idr, id);
+       if (value_sd)
+               free_irq(irq, value_sd);
 
        desc->flags &= ~GPIO_TRIGGER_MASK;
 
        if (!gpio_flags) {
                ret = 0;
-               goto free_sd;
+               goto free_id;
        }
 
        irq_flags = IRQF_SHARED;
@@ -375,55 +360,46 @@ static int gpio_setup_irq(struct gpio_desc *desc, struct device *dev,
                irq_flags |= test_bit(FLAG_ACTIVE_LOW, &desc->flags) ?
                        IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING;
 
-       if (!pdesc) {
-               pdesc = kmalloc(sizeof(*pdesc), GFP_KERNEL);
-               if (!pdesc) {
-                       ret = -ENOMEM;
+       if (!value_sd) {
+               value_sd = sysfs_get_dirent(dev->kobj.sd, NULL, "value");
+               if (!value_sd) {
+                       ret = -ENODEV;
                        goto err_out;
                }
 
                do {
                        ret = -ENOMEM;
-                       if (idr_pre_get(&pdesc_idr, GFP_KERNEL))
-                               ret = idr_get_new_above(&pdesc_idr,
-                                               pdesc, 1, &id);
+                       if (idr_pre_get(&dirent_idr, GFP_KERNEL))
+                               ret = idr_get_new_above(&dirent_idr, value_sd,
+                                                       1, &id);
                } while (ret == -EAGAIN);
 
                if (ret)
-                       goto free_mem;
+                       goto free_sd;
 
                desc->flags &= GPIO_FLAGS_MASK;
-               desc->flags |= (unsigned long)id << PDESC_ID_SHIFT;
+               desc->flags |= (unsigned long)id << ID_SHIFT;
 
-               if (desc->flags >> PDESC_ID_SHIFT != id) {
+               if (desc->flags >> ID_SHIFT != id) {
                        ret = -ERANGE;
                        goto free_id;
                }
-
-               pdesc->value_sd = sysfs_get_dirent(dev->kobj.sd, NULL, "value");
-               if (!pdesc->value_sd) {
-                       ret = -ENODEV;
-                       goto free_id;
-               }
-               INIT_WORK(&pdesc->work, gpio_notify_sysfs);
        }
 
-       ret = request_irq(irq, gpio_sysfs_irq, irq_flags,
-                       "gpiolib", &pdesc->work);
-       if (ret)
-               goto free_sd;
+       ret = request_any_context_irq(irq, gpio_sysfs_irq, irq_flags,
+                               "gpiolib", value_sd);
+       if (ret < 0)
+               goto free_id;
 
        desc->flags |= gpio_flags;
        return 0;
 
-free_sd:
-       if (pdesc)
-               sysfs_put(pdesc->value_sd);
 free_id:
-       idr_remove(&pdesc_idr, id);
+       idr_remove(&dirent_idr, id);
        desc->flags &= GPIO_FLAGS_MASK;
-free_mem:
-       kfree(pdesc);
+free_sd:
+       if (value_sd)
+               sysfs_put(value_sd);
 err_out:
        return ret;
 }
@@ -994,8 +970,6 @@ static int __init gpiolib_sysfs_init(void)
        unsigned long   flags;
        unsigned        gpio;
 
-       idr_init(&pdesc_idr);
-
        status = class_register(&gpio_class);
        if (status < 0)
                return status;
@@ -1272,7 +1246,7 @@ void gpio_free(unsigned gpio)
        if (chip && test_bit(FLAG_REQUESTED, &desc->flags)) {
                if (chip->free) {
                        spin_unlock_irqrestore(&gpio_lock, flags);
-                       might_sleep_if(extra_checks && chip->can_sleep);
+                       might_sleep_if(chip->can_sleep);
                        chip->free(chip, gpio - chip->base);
                        spin_lock_irqsave(&gpio_lock, flags);
                }
@@ -1410,7 +1384,7 @@ int gpio_direction_input(unsigned gpio)
 
        spin_unlock_irqrestore(&gpio_lock, flags);
 
-       might_sleep_if(extra_checks && chip->can_sleep);
+       might_sleep_if(chip->can_sleep);
 
        if (status) {
                status = chip->request(chip, gpio);
@@ -1463,7 +1437,7 @@ int gpio_direction_output(unsigned gpio, int value)
 
        spin_unlock_irqrestore(&gpio_lock, flags);
 
-       might_sleep_if(extra_checks && chip->can_sleep);
+       might_sleep_if(chip->can_sleep);
 
        if (status) {
                status = chip->request(chip, gpio);
@@ -1521,7 +1495,7 @@ int gpio_set_debounce(unsigned gpio, unsigned debounce)
 
        spin_unlock_irqrestore(&gpio_lock, flags);
 
-       might_sleep_if(extra_checks && chip->can_sleep);
+       might_sleep_if(chip->can_sleep);
 
        return chip->set_debounce(chip, gpio, debounce);
 
@@ -1571,7 +1545,7 @@ int __gpio_get_value(unsigned gpio)
        struct gpio_chip        *chip;
 
        chip = gpio_to_chip(gpio);
-       WARN_ON(extra_checks && chip->can_sleep);
+       WARN_ON(chip->can_sleep);
        return chip->get ? chip->get(chip, gpio - chip->base) : 0;
 }
 EXPORT_SYMBOL_GPL(__gpio_get_value);
@@ -1590,7 +1564,7 @@ void __gpio_set_value(unsigned gpio, int value)
        struct gpio_chip        *chip;
 
        chip = gpio_to_chip(gpio);
-       WARN_ON(extra_checks && chip->can_sleep);
+       WARN_ON(chip->can_sleep);
        chip->set(chip, gpio - chip->base, value);
 }
 EXPORT_SYMBOL_GPL(__gpio_set_value);