diff options
Diffstat (limited to 'drivers/input/keyboard/gpio_keys.c')
| -rw-r--r-- | drivers/input/keyboard/gpio_keys.c | 536 | 
1 files changed, 374 insertions, 162 deletions
diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c index 6069abe31e4..8c98e97f8e4 100644 --- a/drivers/input/keyboard/gpio_keys.c +++ b/drivers/input/keyboard/gpio_keys.c @@ -2,6 +2,7 @@   * Driver for keys on GPIO lines capable of generating interrupts.   *   * Copyright 2005 Phil Blundell + * Copyright 2010, 2011 David Jander <david@protonic.nl>   *   * This program is free software; you can redistribute it and/or modify   * it under the terms of the GNU General Public License version 2 as @@ -25,22 +26,27 @@  #include <linux/gpio_keys.h>  #include <linux/workqueue.h>  #include <linux/gpio.h> +#include <linux/of.h> +#include <linux/of_platform.h> +#include <linux/of_gpio.h> +#include <linux/spinlock.h>  struct gpio_button_data { -	struct gpio_keys_button *button; +	const struct gpio_keys_button *button;  	struct input_dev *input;  	struct timer_list timer;  	struct work_struct work; -	int timer_debounce;	/* in msecs */ +	unsigned int timer_debounce;	/* in msecs */ +	unsigned int irq; +	spinlock_t lock;  	bool disabled; +	bool key_pressed;  };  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];  }; @@ -111,7 +117,7 @@ static void gpio_keys_disable_button(struct gpio_button_data *bdata)  		/*  		 * Disable IRQ and possible debouncing timer.  		 */ -		disable_irq(gpio_to_irq(bdata->button->gpio)); +		disable_irq(bdata->irq);  		if (bdata->timer_debounce)  			del_timer_sync(&bdata->timer); @@ -132,7 +138,7 @@ static void gpio_keys_disable_button(struct gpio_button_data *bdata)  static void gpio_keys_enable_button(struct gpio_button_data *bdata)  {  	if (bdata->disabled) { -		enable_irq(gpio_to_irq(bdata->button->gpio)); +		enable_irq(bdata->irq);  		bdata->disabled = false;  	}  } @@ -164,7 +170,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) @@ -192,7 +198,7 @@ static ssize_t gpio_keys_attr_show_helper(struct gpio_keys_drvdata *ddata,   * @type: button type (%EV_KEY, %EV_SW)   *   * This function parses stringified bitmap from @buf and disables/enables - * GPIO buttons accordinly. Returns 0 on success and negative error + * GPIO buttons accordingly. Returns 0 on success and negative error   * on failure.   */  static ssize_t gpio_keys_attr_store_helper(struct gpio_keys_drvdata *ddata, @@ -212,7 +218,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) @@ -227,7 +233,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) @@ -317,39 +323,48 @@ static struct attribute_group gpio_keys_attr_group = {  	.attrs = gpio_keys_attrs,  }; -static void gpio_keys_report_event(struct gpio_button_data *bdata) +static void gpio_keys_gpio_report_event(struct gpio_button_data *bdata)  { -	struct gpio_keys_button *button = bdata->button; +	const struct gpio_keys_button *button = bdata->button;  	struct input_dev *input = bdata->input;  	unsigned int type = button->type ?: EV_KEY; -	int state = (gpio_get_value(button->gpio) ? 1 : 0) ^ button->active_low; +	int state = (gpio_get_value_cansleep(button->gpio) ? 1 : 0) ^ button->active_low; -	input_event(input, type, button->code, !!state); +	if (type == EV_ABS) { +		if (state) +			input_event(input, type, button->code, button->value); +	} else { +		input_event(input, type, button->code, !!state); +	}  	input_sync(input);  } -static void gpio_keys_work_func(struct work_struct *work) +static void gpio_keys_gpio_work_func(struct work_struct *work)  {  	struct gpio_button_data *bdata =  		container_of(work, struct gpio_button_data, work); -	gpio_keys_report_event(bdata); +	gpio_keys_gpio_report_event(bdata); + +	if (bdata->button->wakeup) +		pm_relax(bdata->input->dev.parent);  } -static void gpio_keys_timer(unsigned long _data) +static void gpio_keys_gpio_timer(unsigned long _data)  { -	struct gpio_button_data *data = (struct gpio_button_data *)_data; +	struct gpio_button_data *bdata = (struct gpio_button_data *)_data; -	schedule_work(&data->work); +	schedule_work(&bdata->work);  } -static irqreturn_t gpio_keys_isr(int irq, void *dev_id) +static irqreturn_t gpio_keys_gpio_isr(int irq, void *dev_id)  {  	struct gpio_button_data *bdata = dev_id; -	struct gpio_keys_button *button = bdata->button; -	BUG_ON(irq != gpio_to_irq(button->gpio)); +	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)); @@ -359,50 +374,152 @@ static irqreturn_t gpio_keys_isr(int irq, void *dev_id)  	return IRQ_HANDLED;  } -static int __devinit gpio_keys_setup_key(struct platform_device *pdev, -					 struct gpio_button_data *bdata, -					 struct gpio_keys_button *button) +static void gpio_keys_irq_timer(unsigned long _data) +{ +	struct gpio_button_data *bdata = (struct gpio_button_data *)_data; +	struct input_dev *input = bdata->input; +	unsigned long flags; + +	spin_lock_irqsave(&bdata->lock, flags); +	if (bdata->key_pressed) { +		input_event(input, EV_KEY, bdata->button->code, 0); +		input_sync(input); +		bdata->key_pressed = false; +	} +	spin_unlock_irqrestore(&bdata->lock, flags); +} + +static irqreturn_t gpio_keys_irq_isr(int irq, void *dev_id)  { -	char *desc = button->desc ? button->desc : "gpio_keys"; +	struct gpio_button_data *bdata = dev_id; +	const struct gpio_keys_button *button = bdata->button; +	struct input_dev *input = bdata->input; +	unsigned long flags; + +	BUG_ON(irq != bdata->irq); + +	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); + +		if (!bdata->timer_debounce) { +			input_event(input, EV_KEY, button->code, 0); +			input_sync(input); +			goto out; +		} + +		bdata->key_pressed = true; +	} + +	if (bdata->timer_debounce) +		mod_timer(&bdata->timer, +			jiffies + msecs_to_jiffies(bdata->timer_debounce)); +out: +	spin_unlock_irqrestore(&bdata->lock, flags); +	return IRQ_HANDLED; +} + +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); +} + +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; +	irq_handler_t isr;  	unsigned long irqflags; -	int irq, error; +	int irq; +	int error; -	setup_timer(&bdata->timer, gpio_keys_timer, (unsigned long)bdata); -	INIT_WORK(&bdata->work, gpio_keys_work_func); +	bdata->input = input; +	bdata->button = button; +	spin_lock_init(&bdata->lock); -	error = gpio_request(button->gpio, desc); -	if (error < 0) { -		dev_err(dev, "failed to request GPIO %d, error %d\n", -			button->gpio, error); -		goto fail2; -	} +	if (gpio_is_valid(button->gpio)) { -	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 fail3; -	} +		error = devm_gpio_request_one(&pdev->dev, button->gpio, +					      GPIOF_IN, desc); +		if (error < 0) { +			dev_err(dev, "Failed to request GPIO %d, error %d\n", +				button->gpio, error); +			return error; +		} + +		if (button->debounce_interval) { +			error = gpio_set_debounce(button->gpio, +					button->debounce_interval * 1000); +			/* use timer if gpiolib doesn't provide debounce */ +			if (error < 0) +				bdata->timer_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; +		} +		bdata->irq = irq; + +		INIT_WORK(&bdata->work, gpio_keys_gpio_work_func); +		setup_timer(&bdata->timer, +			    gpio_keys_gpio_timer, (unsigned long)bdata); + +		isr = gpio_keys_gpio_isr; +		irqflags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING; -	if (button->debounce_interval) { -		error = gpio_set_debounce(button->gpio, -					  button->debounce_interval * 1000); -		/* use timer if gpiolib doesn't provide debounce */ -		if (error < 0) -			bdata->timer_debounce = button->debounce_interval; +	} else { +		if (!button->irq) { +			dev_err(dev, "No IRQ specified\n"); +			return -EINVAL; +		} +		bdata->irq = button->irq; + +		if (button->type && button->type != EV_KEY) { +			dev_err(dev, "Only EV_KEY allowed for IRQ buttons.\n"); +			return -EINVAL; +		} + +		bdata->timer_debounce = button->debounce_interval; +		setup_timer(&bdata->timer, +			    gpio_keys_irq_timer, (unsigned long)bdata); + +		isr = gpio_keys_irq_isr; +		irqflags = 0;  	} -	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); -		goto fail3; +	input_set_capability(input, button->type ?: EV_KEY, button->code); + +	/* +	 * Install custom action to cancel debounce timer and +	 * workqueue item. +	 */ +	error = devm_add_action(&pdev->dev, gpio_keys_quiesce_key, bdata); +	if (error) { +		dev_err(&pdev->dev, +			"failed to register quiesce action, error: %d\n", +			error); +		return error;  	} -	irqflags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING;  	/*  	 * If platform has specified that the button can be disabled,  	 * we don't want it to share the interrupt line. @@ -410,65 +527,198 @@ static int __devinit gpio_keys_setup_key(struct platform_device *pdev,  	if (!button->can_disable)  		irqflags |= IRQF_SHARED; -	error = request_irq(irq, gpio_keys_isr, irqflags, desc, bdata); -	if (error) { +	error = devm_request_any_context_irq(&pdev->dev, bdata->irq, +					     isr, irqflags, desc, bdata); +	if (error < 0) {  		dev_err(dev, "Unable to claim irq %d; error %d\n", -			irq, error); -		goto fail3; +			bdata->irq, error); +		return error;  	}  	return 0; +} -fail3: -	gpio_free(button->gpio); -fail2: -	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 ddata->enable ? ddata->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)  {  	struct gpio_keys_drvdata *ddata = input_get_drvdata(input); +	const struct gpio_keys_platform_data *pdata = ddata->pdata; + +	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 struct gpio_keys_platform_data * +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; + +	node = dev->of_node; +	if (!node) +		return ERR_PTR(-ENODEV); + +	nbuttons = of_get_child_count(node); +	if (nbuttons == 0) +		return ERR_PTR(-ENODEV); + +	pdata = devm_kzalloc(dev, +			     sizeof(*pdata) + nbuttons * sizeof(*button), +			     GFP_KERNEL); +	if (!pdata) +		return ERR_PTR(-ENOMEM); + +	pdata->buttons = (struct gpio_keys_button *)(pdata + 1); +	pdata->nbuttons = nbuttons; + +	pdata->rep = !!of_get_property(node, "autorepeat", NULL); + +	i = 0; +	for_each_child_of_node(node, pp) { +		int gpio; +		enum of_gpio_flags flags; + +		if (!of_find_property(pp, "gpios", NULL)) { +			pdata->nbuttons--; +			dev_warn(dev, "Found button without gpios\n"); +			continue; +		} -	if (ddata->disable) -		ddata->disable(input->dev.parent); +		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); +			return ERR_PTR(error); +		} + +		button = &pdata->buttons[i++]; + +		button->gpio = gpio; +		button->active_low = flags & OF_GPIO_ACTIVE_LOW; + +		if (of_property_read_u32(pp, "linux,code", &button->code)) { +			dev_err(dev, "Button without keycode: 0x%x\n", +				button->gpio); +			return ERR_PTR(-EINVAL); +		} + +		button->desc = of_get_property(pp, "label", NULL); + +		if (of_property_read_u32(pp, "linux,input-type", &button->type)) +			button->type = EV_KEY; + +		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; +	} + +	if (pdata->nbuttons == 0) +		return ERR_PTR(-EINVAL); + +	return pdata;  } -static int __devinit gpio_keys_probe(struct platform_device *pdev) +static const struct of_device_id gpio_keys_of_match[] = { +	{ .compatible = "gpio-keys", }, +	{ }, +}; +MODULE_DEVICE_TABLE(of, gpio_keys_of_match); + +#else + +static inline struct gpio_keys_platform_data * +gpio_keys_get_devtree_pdata(struct device *dev) +{ +	return ERR_PTR(-ENODEV); +} + +#endif + +static int gpio_keys_probe(struct platform_device *pdev)  { -	struct gpio_keys_platform_data *pdata = pdev->dev.platform_data; -	struct gpio_keys_drvdata *ddata;  	struct device *dev = &pdev->dev; +	const struct gpio_keys_platform_data *pdata = dev_get_platdata(dev); +	struct gpio_keys_drvdata *ddata;  	struct input_dev *input; +	size_t size;  	int i, error;  	int wakeup = 0; -	ddata = kzalloc(sizeof(struct gpio_keys_drvdata) + -			pdata->nbuttons * sizeof(struct gpio_button_data), -			GFP_KERNEL); -	input = input_allocate_device(); -	if (!ddata || !input) { +	if (!pdata) { +		pdata = gpio_keys_get_devtree_pdata(dev); +		if (IS_ERR(pdata)) +			return PTR_ERR(pdata); +	} + +	size = sizeof(struct gpio_keys_drvdata) + +			pdata->nbuttons * sizeof(struct gpio_button_data); +	ddata = devm_kzalloc(dev, size, GFP_KERNEL); +	if (!ddata) {  		dev_err(dev, "failed to allocate state\n"); -		error = -ENOMEM; -		goto fail1; +		return -ENOMEM; +	} + +	input = devm_input_allocate_device(dev); +	if (!input) { +		dev_err(dev, "failed to allocate input device\n"); +		return -ENOMEM;  	} +	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);  	input_set_drvdata(input, ddata); -	input->name = pdev->name; +	input->name = pdata->name ? : pdev->name;  	input->phys = "gpio-keys/input0";  	input->dev.parent = &pdev->dev;  	input->open = gpio_keys_open; @@ -484,106 +734,67 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev)  		__set_bit(EV_REP, input->evbit);  	for (i = 0; i < pdata->nbuttons; i++) { -		struct gpio_keys_button *button = &pdata->buttons[i]; +		const struct gpio_keys_button *button = &pdata->buttons[i];  		struct gpio_button_data *bdata = &ddata->data[i]; -		unsigned int type = button->type ?: EV_KEY; - -		bdata->input = input; -		bdata->button = button; -		error = gpio_keys_setup_key(pdev, bdata, button); +		error = gpio_keys_setup_key(pdev, input, bdata, button);  		if (error) -			goto fail2; +			return error;  		if (button->wakeup)  			wakeup = 1; - -		input_set_capability(input, type, button->code);  	}  	error = sysfs_create_group(&pdev->dev.kobj, &gpio_keys_attr_group);  	if (error) {  		dev_err(dev, "Unable to export keys/switches, error: %d\n",  			error); -		goto fail2; +		return error;  	}  	error = input_register_device(input);  	if (error) {  		dev_err(dev, "Unable to register input device, error: %d\n",  			error); -		goto fail3; +		goto err_remove_group;  	} -	/* get current state of buttons */ -	for (i = 0; i < pdata->nbuttons; i++) -		gpio_keys_report_event(&ddata->data[i]); -	input_sync(input); -  	device_init_wakeup(&pdev->dev, wakeup);  	return 0; - fail3: +err_remove_group:  	sysfs_remove_group(&pdev->dev.kobj, &gpio_keys_attr_group); - fail2: -	while (--i >= 0) { -		free_irq(gpio_to_irq(pdata->buttons[i].gpio), &ddata->data[i]); -		if (ddata->data[i].timer_debounce) -			del_timer_sync(&ddata->data[i].timer); -		cancel_work_sync(&ddata->data[i].work); -		gpio_free(pdata->buttons[i].gpio); -	} - -	platform_set_drvdata(pdev, NULL); - fail1: -	input_free_device(input); -	kfree(ddata); -  	return error;  } -static int __devexit gpio_keys_remove(struct platform_device *pdev) +static int gpio_keys_remove(struct platform_device *pdev)  { -	struct gpio_keys_platform_data *pdata = pdev->dev.platform_data; -	struct gpio_keys_drvdata *ddata = platform_get_drvdata(pdev); -	struct input_dev *input = ddata->input; -	int i; -  	sysfs_remove_group(&pdev->dev.kobj, &gpio_keys_attr_group);  	device_init_wakeup(&pdev->dev, 0); -	for (i = 0; i < pdata->nbuttons; i++) { -		int irq = gpio_to_irq(pdata->buttons[i].gpio); -		free_irq(irq, &ddata->data[i]); -		if (ddata->data[i].timer_debounce) -			del_timer_sync(&ddata->data[i].timer); -		cancel_work_sync(&ddata->data[i].work); -		gpio_free(pdata->buttons[i].gpio); -	} - -	input_unregister_device(input); -  	return 0;  } - -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  static int gpio_keys_suspend(struct device *dev)  { -	struct platform_device *pdev = to_platform_device(dev); -	struct gpio_keys_platform_data *pdata = pdev->dev.platform_data; +	struct gpio_keys_drvdata *ddata = dev_get_drvdata(dev); +	struct input_dev *input = ddata->input;  	int i; -	if (device_may_wakeup(&pdev->dev)) { -		for (i = 0; i < pdata->nbuttons; i++) { -			struct gpio_keys_button *button = &pdata->buttons[i]; -			if (button->wakeup) { -				int irq = gpio_to_irq(button->gpio); -				enable_irq_wake(irq); -			} +	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) +				enable_irq_wake(bdata->irq);  		} +	} else { +		mutex_lock(&input->mutex); +		if (input->users) +			gpio_keys_close(input); +		mutex_unlock(&input->mutex);  	}  	return 0; @@ -591,41 +802,42 @@ static int gpio_keys_suspend(struct device *dev)  static int gpio_keys_resume(struct device *dev)  { -	struct platform_device *pdev = to_platform_device(dev); -	struct gpio_keys_drvdata *ddata = platform_get_drvdata(pdev); -	struct gpio_keys_platform_data *pdata = pdev->dev.platform_data; +	struct gpio_keys_drvdata *ddata = dev_get_drvdata(dev); +	struct input_dev *input = ddata->input; +	int error = 0;  	int i; -	for (i = 0; i < pdata->nbuttons; i++) { - -		struct gpio_keys_button *button = &pdata->buttons[i]; -		if (button->wakeup && device_may_wakeup(&pdev->dev)) { -			int irq = gpio_to_irq(button->gpio); -			disable_irq_wake(irq); +	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);  		} - -		gpio_keys_report_event(&ddata->data[i]); +	} 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;  } - -static const struct dev_pm_ops gpio_keys_pm_ops = { -	.suspend	= gpio_keys_suspend, -	.resume		= gpio_keys_resume, -};  #endif +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, -#ifdef CONFIG_PM  		.pm	= &gpio_keys_pm_ops, -#endif +		.of_match_table = of_match_ptr(gpio_keys_of_match),  	}  }; @@ -639,10 +851,10 @@ static void __exit gpio_keys_exit(void)  	platform_driver_unregister(&gpio_keys_device_driver);  } -module_init(gpio_keys_init); +late_initcall(gpio_keys_init);  module_exit(gpio_keys_exit);  MODULE_LICENSE("GPL");  MODULE_AUTHOR("Phil Blundell <pb@handhelds.org>"); -MODULE_DESCRIPTION("Keyboard driver for CPU GPIOs"); +MODULE_DESCRIPTION("Keyboard driver for GPIOs");  MODULE_ALIAS("platform:gpio-keys");  | 
