Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
[pandora-kernel.git] / drivers / input / keyboard / gpio_keys.c
index d4dd78a..883d6ae 100644 (file)
 struct gpio_button_data {
        const struct gpio_keys_button *button;
        struct input_dev *input;
-       struct timer_list timer;
-       struct work_struct work;
-       unsigned int timer_debounce;    /* in msecs */
+
+       struct timer_list release_timer;
+       unsigned int release_delay;     /* in msecs, for IRQ-only buttons */
+
+       struct delayed_work work;
+       unsigned int software_debounce; /* in msecs, for GPIO-driven buttons */
+
        unsigned int irq;
        spinlock_t lock;
        bool disabled;
@@ -116,11 +120,14 @@ static void gpio_keys_disable_button(struct gpio_button_data *bdata)
 {
        if (!bdata->disabled) {
                /*
-                * Disable IRQ and possible debouncing timer.
+                * Disable IRQ and associated timer/work structure.
                 */
                disable_irq(bdata->irq);
-               if (bdata->timer_debounce)
-                       del_timer_sync(&bdata->timer);
+
+               if (gpio_is_valid(bdata->button->gpio))
+                       cancel_delayed_work_sync(&bdata->work);
+               else
+                       del_timer_sync(&bdata->release_timer);
 
                bdata->disabled = true;
        }
@@ -343,7 +350,7 @@ static void gpio_keys_gpio_report_event(struct gpio_button_data *bdata)
 static void gpio_keys_gpio_work_func(struct work_struct *work)
 {
        struct gpio_button_data *bdata =
-               container_of(work, struct gpio_button_data, work);
+               container_of(work, struct gpio_button_data, work.work);
 
        gpio_keys_gpio_report_event(bdata);
 
@@ -351,13 +358,6 @@ static void gpio_keys_gpio_work_func(struct work_struct *work)
                pm_relax(bdata->input->dev.parent);
 }
 
-static void gpio_keys_gpio_timer(unsigned long _data)
-{
-       struct gpio_button_data *bdata = (struct gpio_button_data *)_data;
-
-       schedule_work(&bdata->work);
-}
-
 static irqreturn_t gpio_keys_gpio_isr(int irq, void *dev_id)
 {
        struct gpio_button_data *bdata = dev_id;
@@ -366,11 +366,10 @@ static irqreturn_t gpio_keys_gpio_isr(int irq, void *dev_id)
 
        if (bdata->button->wakeup)
                pm_stay_awake(bdata->input->dev.parent);
-       if (bdata->timer_debounce)
-               mod_timer(&bdata->timer,
-                       jiffies + msecs_to_jiffies(bdata->timer_debounce));
-       else
-               schedule_work(&bdata->work);
+
+       mod_delayed_work(system_wq,
+                        &bdata->work,
+                        msecs_to_jiffies(bdata->software_debounce));
 
        return IRQ_HANDLED;
 }
@@ -408,7 +407,7 @@ static irqreturn_t gpio_keys_irq_isr(int irq, void *dev_id)
                input_event(input, EV_KEY, button->code, 1);
                input_sync(input);
 
-               if (!bdata->timer_debounce) {
+               if (!bdata->release_delay) {
                        input_event(input, EV_KEY, button->code, 0);
                        input_sync(input);
                        goto out;
@@ -417,9 +416,9 @@ static irqreturn_t gpio_keys_irq_isr(int irq, void *dev_id)
                bdata->key_pressed = true;
        }
 
-       if (bdata->timer_debounce)
-               mod_timer(&bdata->timer,
-                       jiffies + msecs_to_jiffies(bdata->timer_debounce));
+       if (bdata->release_delay)
+               mod_timer(&bdata->release_timer,
+                       jiffies + msecs_to_jiffies(bdata->release_delay));
 out:
        spin_unlock_irqrestore(&bdata->lock, flags);
        return IRQ_HANDLED;
@@ -429,10 +428,10 @@ static void gpio_keys_quiesce_key(void *data)
 {
        struct gpio_button_data *bdata = data;
 
-       if (bdata->timer_debounce)
-               del_timer_sync(&bdata->timer);
-
-       cancel_work_sync(&bdata->work);
+       if (gpio_is_valid(bdata->button->gpio))
+               cancel_delayed_work_sync(&bdata->work);
+       else
+               del_timer_sync(&bdata->release_timer);
 }
 
 static int gpio_keys_setup_key(struct platform_device *pdev,
@@ -466,23 +465,25 @@ static int gpio_keys_setup_key(struct platform_device *pdev,
                                        button->debounce_interval * 1000);
                        /* use timer if gpiolib doesn't provide debounce */
                        if (error < 0)
-                               bdata->timer_debounce =
+                               bdata->software_debounce =
                                                button->debounce_interval;
                }
 
-               irq = gpio_to_irq(button->gpio);
-               if (irq < 0) {
-                       error = irq;
-                       dev_err(dev,
-                               "Unable to get irq number for GPIO %d, error %d\n",
-                               button->gpio, error);
-                       return error;
+               if (button->irq) {
+                       bdata->irq = button->irq;
+               } else {
+                       irq = gpio_to_irq(button->gpio);
+                       if (irq < 0) {
+                               error = irq;
+                               dev_err(dev,
+                                       "Unable to get irq number for GPIO %d, error %d\n",
+                                       button->gpio, error);
+                               return error;
+                       }
+                       bdata->irq = irq;
                }
-               bdata->irq = irq;
 
-               INIT_WORK(&bdata->work, gpio_keys_gpio_work_func);
-               setup_timer(&bdata->timer,
-                           gpio_keys_gpio_timer, (unsigned long)bdata);
+               INIT_DELAYED_WORK(&bdata->work, gpio_keys_gpio_work_func);
 
                isr = gpio_keys_gpio_isr;
                irqflags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING;
@@ -499,8 +500,8 @@ static int gpio_keys_setup_key(struct platform_device *pdev,
                        return -EINVAL;
                }
 
-               bdata->timer_debounce = button->debounce_interval;
-               setup_timer(&bdata->timer,
+               bdata->release_delay = button->debounce_interval;
+               setup_timer(&bdata->release_timer,
                            gpio_keys_irq_timer, (unsigned long)bdata);
 
                isr = gpio_keys_irq_isr;
@@ -510,7 +511,7 @@ static int gpio_keys_setup_key(struct platform_device *pdev,
        input_set_capability(input, button->type ?: EV_KEY, button->code);
 
        /*
-        * Install custom action to cancel debounce timer and
+        * Install custom action to cancel release timer and
         * workqueue item.
         */
        error = devm_add_action(&pdev->dev, gpio_keys_quiesce_key, bdata);
@@ -618,33 +619,30 @@ gpio_keys_get_devtree_pdata(struct device *dev)
 
        i = 0;
        for_each_child_of_node(node, pp) {
-               int gpio = -1;
                enum of_gpio_flags flags;
 
                button = &pdata->buttons[i++];
 
-               if (!of_find_property(pp, "gpios", NULL)) {
-                       button->irq = irq_of_parse_and_map(pp, 0);
-                       if (button->irq == 0) {
-                               i--;
-                               pdata->nbuttons--;
-                               dev_warn(dev, "Found button without gpios or irqs\n");
-                               continue;
-                       }
-               } else {
-                       gpio = of_get_gpio_flags(pp, 0, &flags);
-                       if (gpio < 0) {
-                               error = gpio;
+               button->gpio = of_get_gpio_flags(pp, 0, &flags);
+               if (button->gpio < 0) {
+                       error = button->gpio;
+                       if (error != -ENOENT) {
                                if (error != -EPROBE_DEFER)
                                        dev_err(dev,
                                                "Failed to get gpio flags, error: %d\n",
                                                error);
                                return ERR_PTR(error);
                        }
+               } else {
+                       button->active_low = flags & OF_GPIO_ACTIVE_LOW;
                }
 
-               button->gpio = gpio;
-               button->active_low = flags & OF_GPIO_ACTIVE_LOW;
+               button->irq = irq_of_parse_and_map(pp, 0);
+
+               if (!gpio_is_valid(button->gpio) && !button->irq) {
+                       dev_err(dev, "Found button without gpios or irqs\n");
+                       return ERR_PTR(-EINVAL);
+               }
 
                if (of_property_read_u32(pp, "linux,code", &button->code)) {
                        dev_err(dev, "Button without keycode: 0x%x\n",
@@ -659,6 +657,8 @@ gpio_keys_get_devtree_pdata(struct device *dev)
 
                button->wakeup = !!of_get_property(pp, "gpio-key,wakeup", NULL);
 
+               button->can_disable = !!of_get_property(pp, "linux,can-disable", NULL);
+
                if (of_property_read_u32(pp, "debounce-interval",
                                         &button->debounce_interval))
                        button->debounce_interval = 5;