]> Pileus Git - ~andy/linux/blobdiff - drivers/input/keyboard/gpio_keys.c
Input: gpio_keys - defer probing if GPIO probing is deferred
[~andy/linux] / drivers / input / keyboard / gpio_keys.c
index 6a68041c261db45eafe9f4cadea39f1b032edb51..b29ca651a3951e568527e4c7a041f101bba06c3a 100644 (file)
@@ -423,10 +423,10 @@ out:
        return IRQ_HANDLED;
 }
 
-static int __devinit gpio_keys_setup_key(struct platform_device *pdev,
-                                        struct input_dev *input,
-                                        struct gpio_button_data *bdata,
-                                        const struct gpio_keys_button *button)
+static int gpio_keys_setup_key(struct platform_device *pdev,
+                               struct input_dev *input,
+                               struct gpio_button_data *bdata,
+                               const struct gpio_keys_button *button)
 {
        const char *desc = button->desc ? button->desc : "gpio_keys";
        struct device *dev = &pdev->dev;
@@ -440,21 +440,13 @@ static int __devinit gpio_keys_setup_key(struct platform_device *pdev,
 
        if (gpio_is_valid(button->gpio)) {
 
-               error = gpio_request(button->gpio, desc);
+               error = gpio_request_one(button->gpio, GPIOF_IN, desc);
                if (error < 0) {
                        dev_err(dev, "Failed to request GPIO %d, error %d\n",
                                button->gpio, error);
                        return error;
                }
 
-               error = gpio_direction_input(button->gpio);
-               if (error < 0) {
-                       dev_err(dev,
-                               "Failed to configure direction for GPIO %d, error %d\n",
-                               button->gpio, error);
-                       goto fail;
-               }
-
                if (button->debounce_interval) {
                        error = gpio_set_debounce(button->gpio,
                                        button->debounce_interval * 1000);
@@ -526,12 +518,35 @@ fail:
        return error;
 }
 
+static void gpio_keys_report_state(struct gpio_keys_drvdata *ddata)
+{
+       struct input_dev *input = ddata->input;
+       int i;
+
+       for (i = 0; i < ddata->pdata->nbuttons; i++) {
+               struct gpio_button_data *bdata = &ddata->data[i];
+               if (gpio_is_valid(bdata->button->gpio))
+                       gpio_keys_gpio_report_event(bdata);
+       }
+       input_sync(input);
+}
+
 static int gpio_keys_open(struct input_dev *input)
 {
        struct gpio_keys_drvdata *ddata = input_get_drvdata(input);
        const struct gpio_keys_platform_data *pdata = ddata->pdata;
+       int error;
 
-       return pdata->enable ? pdata->enable(input->dev.parent) : 0;
+       if (pdata->enable) {
+               error = pdata->enable(input->dev.parent);
+               if (error)
+                       return error;
+       }
+
+       /* Report current state of buttons that are connected to GPIOs */
+       gpio_keys_report_state(ddata);
+
+       return 0;
 }
 
 static void gpio_keys_close(struct input_dev *input)
@@ -551,7 +566,7 @@ static void gpio_keys_close(struct input_dev *input)
 /*
  * Translate OpenFirmware node properties into platform_data
  */
-static struct gpio_keys_platform_data * __devinit
+static struct gpio_keys_platform_data *
 gpio_keys_get_devtree_pdata(struct device *dev)
 {
        struct device_node *node, *pp;
@@ -587,6 +602,7 @@ gpio_keys_get_devtree_pdata(struct device *dev)
 
        i = 0;
        for_each_child_of_node(node, pp) {
+               int gpio;
                enum of_gpio_flags flags;
 
                if (!of_find_property(pp, "gpios", NULL)) {
@@ -595,9 +611,19 @@ gpio_keys_get_devtree_pdata(struct device *dev)
                        continue;
                }
 
+               gpio = of_get_gpio_flags(pp, 0, &flags);
+               if (gpio < 0) {
+                       error = gpio;
+                       if (error != -EPROBE_DEFER)
+                               dev_err(dev,
+                                       "Failed to get gpio flags, error: %d\n",
+                                       error);
+                       goto err_free_pdata;
+               }
+
                button = &pdata->buttons[i++];
 
-               button->gpio = of_get_gpio_flags(pp, 0, &flags);
+               button->gpio = gpio;
                button->active_low = flags & OF_GPIO_ACTIVE_LOW;
 
                if (of_property_read_u32(pp, "linux,code", &button->code)) {
@@ -658,7 +684,7 @@ static void gpio_remove_key(struct gpio_button_data *bdata)
                gpio_free(bdata->button->gpio);
 }
 
-static int __devinit gpio_keys_probe(struct platform_device *pdev)
+static int gpio_keys_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        const struct gpio_keys_platform_data *pdata = dev_get_platdata(dev);
@@ -731,14 +757,6 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev)
                goto fail3;
        }
 
-       /* get current state of buttons that are connected to GPIOs */
-       for (i = 0; i < pdata->nbuttons; i++) {
-               struct gpio_button_data *bdata = &ddata->data[i];
-               if (gpio_is_valid(bdata->button->gpio))
-                       gpio_keys_gpio_report_event(bdata);
-       }
-       input_sync(input);
-
        device_init_wakeup(&pdev->dev, wakeup);
 
        return 0;
@@ -760,7 +778,7 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev)
        return error;
 }
 
-static int __devexit gpio_keys_remove(struct platform_device *pdev)
+static int gpio_keys_remove(struct platform_device *pdev)
 {
        struct gpio_keys_drvdata *ddata = platform_get_drvdata(pdev);
        struct input_dev *input = ddata->input;
@@ -788,6 +806,7 @@ static int __devexit gpio_keys_remove(struct platform_device *pdev)
 static int gpio_keys_suspend(struct device *dev)
 {
        struct gpio_keys_drvdata *ddata = dev_get_drvdata(dev);
+       struct input_dev *input = ddata->input;
        int i;
 
        if (device_may_wakeup(dev)) {
@@ -796,6 +815,11 @@ static int gpio_keys_suspend(struct device *dev)
                        if (bdata->button->wakeup)
                                enable_irq_wake(bdata->irq);
                }
+       } else {
+               mutex_lock(&input->mutex);
+               if (input->users)
+                       gpio_keys_close(input);
+               mutex_unlock(&input->mutex);
        }
 
        return 0;
@@ -804,18 +828,27 @@ static int gpio_keys_suspend(struct device *dev)
 static int gpio_keys_resume(struct device *dev)
 {
        struct gpio_keys_drvdata *ddata = dev_get_drvdata(dev);
+       struct input_dev *input = ddata->input;
+       int error = 0;
        int i;
 
-       for (i = 0; i < ddata->pdata->nbuttons; i++) {
-               struct gpio_button_data *bdata = &ddata->data[i];
-               if (bdata->button->wakeup && device_may_wakeup(dev))
-                       disable_irq_wake(bdata->irq);
-
-               if (gpio_is_valid(bdata->button->gpio))
-                       gpio_keys_gpio_report_event(bdata);
+       if (device_may_wakeup(dev)) {
+               for (i = 0; i < ddata->pdata->nbuttons; i++) {
+                       struct gpio_button_data *bdata = &ddata->data[i];
+                       if (bdata->button->wakeup)
+                               disable_irq_wake(bdata->irq);
+               }
+       } else {
+               mutex_lock(&input->mutex);
+               if (input->users)
+                       error = gpio_keys_open(input);
+               mutex_unlock(&input->mutex);
        }
-       input_sync(ddata->input);
 
+       if (error)
+               return error;
+
+       gpio_keys_report_state(ddata);
        return 0;
 }
 #endif
@@ -824,7 +857,7 @@ static SIMPLE_DEV_PM_OPS(gpio_keys_pm_ops, gpio_keys_suspend, gpio_keys_resume);
 
 static struct platform_driver gpio_keys_device_driver = {
        .probe          = gpio_keys_probe,
-       .remove         = __devexit_p(gpio_keys_remove),
+       .remove         = gpio_keys_remove,
        .driver         = {
                .name   = "gpio-keys",
                .owner  = THIS_MODULE,