]> Pileus Git - ~andy/linux/blobdiff - drivers/input/keyboard/gpio_keys.c
Merge tag 'scsi-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb...
[~andy/linux] / drivers / input / keyboard / gpio_keys.c
index cbb1add43d5e0b78e64d286a584abb3e799c6540..6a68041c261db45eafe9f4cadea39f1b032edb51 100644 (file)
@@ -43,11 +43,9 @@ struct gpio_button_data {
 };
 
 struct gpio_keys_drvdata {
+       const struct gpio_keys_platform_data *pdata;
        struct input_dev *input;
        struct mutex disable_lock;
-       unsigned int n_buttons;
-       int (*enable)(struct device *dev);
-       void (*disable)(struct device *dev);
        struct gpio_button_data data[0];
 };
 
@@ -171,7 +169,7 @@ static ssize_t gpio_keys_attr_show_helper(struct gpio_keys_drvdata *ddata,
        if (!bits)
                return -ENOMEM;
 
-       for (i = 0; i < ddata->n_buttons; i++) {
+       for (i = 0; i < ddata->pdata->nbuttons; i++) {
                struct gpio_button_data *bdata = &ddata->data[i];
 
                if (bdata->button->type != type)
@@ -219,7 +217,7 @@ static ssize_t gpio_keys_attr_store_helper(struct gpio_keys_drvdata *ddata,
                goto out;
 
        /* First validate */
-       for (i = 0; i < ddata->n_buttons; i++) {
+       for (i = 0; i < ddata->pdata->nbuttons; i++) {
                struct gpio_button_data *bdata = &ddata->data[i];
 
                if (bdata->button->type != type)
@@ -234,7 +232,7 @@ static ssize_t gpio_keys_attr_store_helper(struct gpio_keys_drvdata *ddata,
 
        mutex_lock(&ddata->disable_lock);
 
-       for (i = 0; i < ddata->n_buttons; i++) {
+       for (i = 0; i < ddata->pdata->nbuttons; i++) {
                struct gpio_button_data *bdata = &ddata->data[i];
 
                if (bdata->button->type != type)
@@ -346,6 +344,9 @@ static void gpio_keys_gpio_work_func(struct work_struct *work)
                container_of(work, struct gpio_button_data, work);
 
        gpio_keys_gpio_report_event(bdata);
+
+       if (bdata->button->wakeup)
+               pm_relax(bdata->input->dev.parent);
 }
 
 static void gpio_keys_gpio_timer(unsigned long _data)
@@ -361,6 +362,8 @@ static irqreturn_t gpio_keys_gpio_isr(int irq, void *dev_id)
 
        BUG_ON(irq != bdata->irq);
 
+       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));
@@ -397,6 +400,9 @@ static irqreturn_t gpio_keys_irq_isr(int irq, void *dev_id)
        spin_lock_irqsave(&bdata->lock, flags);
 
        if (!bdata->key_pressed) {
+               if (bdata->button->wakeup)
+                       pm_wakeup_event(bdata->input->dev.parent, 0);
+
                input_event(input, EV_KEY, button->code, 1);
                input_sync(input);
 
@@ -523,56 +529,64 @@ fail:
 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;
 
-       return ddata->enable ? ddata->enable(input->dev.parent) : 0;
+       return pdata->enable ? pdata->enable(input->dev.parent) : 0;
 }
 
 static void gpio_keys_close(struct input_dev *input)
 {
        struct gpio_keys_drvdata *ddata = input_get_drvdata(input);
+       const struct gpio_keys_platform_data *pdata = ddata->pdata;
 
-       if (ddata->disable)
-               ddata->disable(input->dev.parent);
+       if (pdata->disable)
+               pdata->disable(input->dev.parent);
 }
 
 /*
  * Handlers for alternative sources of platform_data
  */
+
 #ifdef CONFIG_OF
 /*
  * Translate OpenFirmware node properties into platform_data
  */
-static int gpio_keys_get_devtree_pdata(struct device *dev,
-                           struct gpio_keys_platform_data *pdata)
+static struct gpio_keys_platform_data * __devinit
+gpio_keys_get_devtree_pdata(struct device *dev)
 {
        struct device_node *node, *pp;
+       struct gpio_keys_platform_data *pdata;
+       struct gpio_keys_button *button;
+       int error;
+       int nbuttons;
        int i;
-       struct gpio_keys_button *buttons;
-       u32 reg;
 
        node = dev->of_node;
-       if (node == NULL)
-               return -ENODEV;
-
-       memset(pdata, 0, sizeof *pdata);
+       if (!node) {
+               error = -ENODEV;
+               goto err_out;
+       }
 
-       pdata->rep = !!of_get_property(node, "autorepeat", NULL);
+       nbuttons = of_get_child_count(node);
+       if (nbuttons == 0) {
+               error = -ENODEV;
+               goto err_out;
+       }
 
-       /* First count the subnodes */
-       pp = NULL;
-       while ((pp = of_get_next_child(node, pp)))
-               pdata->nbuttons++;
+       pdata = kzalloc(sizeof(*pdata) + nbuttons * (sizeof *button),
+                       GFP_KERNEL);
+       if (!pdata) {
+               error = -ENOMEM;
+               goto err_out;
+       }
 
-       if (pdata->nbuttons == 0)
-               return -ENODEV;
+       pdata->buttons = (struct gpio_keys_button *)(pdata + 1);
+       pdata->nbuttons = nbuttons;
 
-       buttons = kzalloc(pdata->nbuttons * (sizeof *buttons), GFP_KERNEL);
-       if (!buttons)
-               return -ENOMEM;
+       pdata->rep = !!of_get_property(node, "autorepeat", NULL);
 
-       pp = NULL;
        i = 0;
-       while ((pp = of_get_next_child(node, pp))) {
+       for_each_child_of_node(node, pp) {
                enum of_gpio_flags flags;
 
                if (!of_find_property(pp, "gpios", NULL)) {
@@ -580,39 +594,42 @@ static int gpio_keys_get_devtree_pdata(struct device *dev,
                        dev_warn(dev, "Found button without gpios\n");
                        continue;
                }
-               buttons[i].gpio = of_get_gpio_flags(pp, 0, &flags);
-               buttons[i].active_low = flags & OF_GPIO_ACTIVE_LOW;
 
-               if (of_property_read_u32(pp, "linux,code", &reg)) {
-                       dev_err(dev, "Button without keycode: 0x%x\n", buttons[i].gpio);
-                       goto out_fail;
-               }
-               buttons[i].code = reg;
+               button = &pdata->buttons[i++];
 
-               buttons[i].desc = of_get_property(pp, "label", NULL);
+               button->gpio = of_get_gpio_flags(pp, 0, &flags);
+               button->active_low = flags & OF_GPIO_ACTIVE_LOW;
 
-               if (of_property_read_u32(pp, "linux,input-type", &reg) == 0)
-                       buttons[i].type = reg;
-               else
-                       buttons[i].type = EV_KEY;
+               if (of_property_read_u32(pp, "linux,code", &button->code)) {
+                       dev_err(dev, "Button without keycode: 0x%x\n",
+                               button->gpio);
+                       error = -EINVAL;
+                       goto err_free_pdata;
+               }
 
-               buttons[i].wakeup = !!of_get_property(pp, "gpio-key,wakeup", NULL);
+               button->desc = of_get_property(pp, "label", NULL);
 
-               if (of_property_read_u32(pp, "debounce-interval", &reg) == 0)
-                       buttons[i].debounce_interval = reg;
-               else
-                       buttons[i].debounce_interval = 5;
+               if (of_property_read_u32(pp, "linux,input-type", &button->type))
+                       button->type = EV_KEY;
 
-               i++;
+               button->wakeup = !!of_get_property(pp, "gpio-key,wakeup", NULL);
+
+               if (of_property_read_u32(pp, "debounce-interval",
+                                        &button->debounce_interval))
+                       button->debounce_interval = 5;
        }
 
-       pdata->buttons = buttons;
+       if (pdata->nbuttons == 0) {
+               error = -EINVAL;
+               goto err_free_pdata;
+       }
 
-       return 0;
+       return pdata;
 
-out_fail:
-       kfree(buttons);
-       return -ENODEV;
+err_free_pdata:
+       kfree(pdata);
+err_out:
+       return ERR_PTR(error);
 }
 
 static struct of_device_id gpio_keys_of_match[] = {
@@ -623,14 +640,12 @@ MODULE_DEVICE_TABLE(of, gpio_keys_of_match);
 
 #else
 
-static int gpio_keys_get_devtree_pdata(struct device *dev,
-                           struct gpio_keys_platform_data *altp)
+static inline struct gpio_keys_platform_data *
+gpio_keys_get_devtree_pdata(struct device *dev)
 {
-       return -ENODEV;
+       return ERR_PTR(-ENODEV);
 }
 
-#define gpio_keys_of_match NULL
-
 #endif
 
 static void gpio_remove_key(struct gpio_button_data *bdata)
@@ -645,19 +660,17 @@ static void gpio_remove_key(struct gpio_button_data *bdata)
 
 static int __devinit gpio_keys_probe(struct platform_device *pdev)
 {
-       const struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
-       struct gpio_keys_drvdata *ddata;
        struct device *dev = &pdev->dev;
-       struct gpio_keys_platform_data alt_pdata;
+       const struct gpio_keys_platform_data *pdata = dev_get_platdata(dev);
+       struct gpio_keys_drvdata *ddata;
        struct input_dev *input;
        int i, error;
        int wakeup = 0;
 
        if (!pdata) {
-               error = gpio_keys_get_devtree_pdata(dev, &alt_pdata);
-               if (error)
-                       return error;
-               pdata = &alt_pdata;
+               pdata = gpio_keys_get_devtree_pdata(dev);
+               if (IS_ERR(pdata))
+                       return PTR_ERR(pdata);
        }
 
        ddata = kzalloc(sizeof(struct gpio_keys_drvdata) +
@@ -670,10 +683,8 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev)
                goto fail1;
        }
 
+       ddata->pdata = pdata;
        ddata->input = input;
-       ddata->n_buttons = pdata->nbuttons;
-       ddata->enable = pdata->enable;
-       ddata->disable = pdata->disable;
        mutex_init(&ddata->disable_lock);
 
        platform_set_drvdata(pdev, ddata);
@@ -742,9 +753,9 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev)
  fail1:
        input_free_device(input);
        kfree(ddata);
-       /* If we have no platform_data, we allocated buttons dynamically. */
-       if (!pdev->dev.platform_data)
-               kfree(pdata->buttons);
+       /* If we have no platform data, we allocated pdata dynamically. */
+       if (!dev_get_platdata(&pdev->dev))
+               kfree(pdata);
 
        return error;
 }
@@ -759,18 +770,14 @@ static int __devexit gpio_keys_remove(struct platform_device *pdev)
 
        device_init_wakeup(&pdev->dev, 0);
 
-       for (i = 0; i < ddata->n_buttons; i++)
+       for (i = 0; i < ddata->pdata->nbuttons; i++)
                gpio_remove_key(&ddata->data[i]);
 
        input_unregister_device(input);
 
-       /*
-        * If we had no platform_data, we allocated buttons dynamically, and
-        * must free them here. ddata->data[0].button is the pointer to the
-        * beginning of the allocated array.
-        */
-       if (!pdev->dev.platform_data)
-               kfree(ddata->data[0].button);
+       /* If we have no platform data, we allocated pdata dynamically. */
+       if (!dev_get_platdata(&pdev->dev))
+               kfree(ddata->pdata);
 
        kfree(ddata);
 
@@ -784,7 +791,7 @@ static int gpio_keys_suspend(struct device *dev)
        int i;
 
        if (device_may_wakeup(dev)) {
-               for (i = 0; i < ddata->n_buttons; i++) {
+               for (i = 0; i < ddata->pdata->nbuttons; i++) {
                        struct gpio_button_data *bdata = &ddata->data[i];
                        if (bdata->button->wakeup)
                                enable_irq_wake(bdata->irq);
@@ -799,7 +806,7 @@ static int gpio_keys_resume(struct device *dev)
        struct gpio_keys_drvdata *ddata = dev_get_drvdata(dev);
        int i;
 
-       for (i = 0; i < ddata->n_buttons; 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);
@@ -822,7 +829,7 @@ static struct platform_driver gpio_keys_device_driver = {
                .name   = "gpio-keys",
                .owner  = THIS_MODULE,
                .pm     = &gpio_keys_pm_ops,
-               .of_match_table = gpio_keys_of_match,
+               .of_match_table = of_match_ptr(gpio_keys_of_match),
        }
 };