diff options
Diffstat (limited to 'drivers/input/keyboard/matrix_keypad.c')
| -rw-r--r-- | drivers/input/keyboard/matrix_keypad.c | 108 | 
1 files changed, 80 insertions, 28 deletions
diff --git a/drivers/input/keyboard/matrix_keypad.c b/drivers/input/keyboard/matrix_keypad.c index b443e088fd3..b02e4268e18 100644 --- a/drivers/input/keyboard/matrix_keypad.c +++ b/drivers/input/keyboard/matrix_keypad.c @@ -37,6 +37,7 @@ struct matrix_keypad {  	spinlock_t lock;  	bool scan_pending;  	bool stopped; +	bool gpio_all_disabled;  };  /* @@ -87,8 +88,12 @@ static void enable_row_irqs(struct matrix_keypad *keypad)  	const struct matrix_keypad_platform_data *pdata = keypad->pdata;  	int i; -	for (i = 0; i < pdata->num_row_gpios; i++) -		enable_irq(gpio_to_irq(pdata->row_gpios[i])); +	if (pdata->clustered_irq > 0) +		enable_irq(pdata->clustered_irq); +	else { +		for (i = 0; i < pdata->num_row_gpios; i++) +			enable_irq(gpio_to_irq(pdata->row_gpios[i])); +	}  }  static void disable_row_irqs(struct matrix_keypad *keypad) @@ -96,8 +101,12 @@ static void disable_row_irqs(struct matrix_keypad *keypad)  	const struct matrix_keypad_platform_data *pdata = keypad->pdata;  	int i; -	for (i = 0; i < pdata->num_row_gpios; i++) -		disable_irq_nosync(gpio_to_irq(pdata->row_gpios[i])); +	if (pdata->clustered_irq > 0) +		disable_irq_nosync(pdata->clustered_irq); +	else { +		for (i = 0; i < pdata->num_row_gpios; i++) +			disable_irq_nosync(gpio_to_irq(pdata->row_gpios[i])); +	}  }  /* @@ -216,45 +225,69 @@ static void matrix_keypad_stop(struct input_dev *dev)  }  #ifdef CONFIG_PM -static int matrix_keypad_suspend(struct device *dev) +static void matrix_keypad_enable_wakeup(struct matrix_keypad *keypad)  { -	struct platform_device *pdev = to_platform_device(dev); -	struct matrix_keypad *keypad = platform_get_drvdata(pdev);  	const struct matrix_keypad_platform_data *pdata = keypad->pdata; +	unsigned int gpio;  	int i; -	matrix_keypad_stop(keypad->input_dev); +	if (pdata->clustered_irq > 0) { +		if (enable_irq_wake(pdata->clustered_irq) == 0) +			keypad->gpio_all_disabled = true; +	} else { -	if (device_may_wakeup(&pdev->dev)) {  		for (i = 0; i < pdata->num_row_gpios; i++) {  			if (!test_bit(i, keypad->disabled_gpios)) { -				unsigned int gpio = pdata->row_gpios[i]; +				gpio = pdata->row_gpios[i];  				if (enable_irq_wake(gpio_to_irq(gpio)) == 0)  					__set_bit(i, keypad->disabled_gpios);  			}  		}  	} - -	return 0;  } -static int matrix_keypad_resume(struct device *dev) +static void matrix_keypad_disable_wakeup(struct matrix_keypad *keypad)  { -	struct platform_device *pdev = to_platform_device(dev); -	struct matrix_keypad *keypad = platform_get_drvdata(pdev);  	const struct matrix_keypad_platform_data *pdata = keypad->pdata; +	unsigned int gpio;  	int i; -	if (device_may_wakeup(&pdev->dev)) { +	if (pdata->clustered_irq > 0) { +		if (keypad->gpio_all_disabled) { +			disable_irq_wake(pdata->clustered_irq); +			keypad->gpio_all_disabled = false; +		} +	} else {  		for (i = 0; i < pdata->num_row_gpios; i++) {  			if (test_and_clear_bit(i, keypad->disabled_gpios)) { -				unsigned int gpio = pdata->row_gpios[i]; - +				gpio = pdata->row_gpios[i];  				disable_irq_wake(gpio_to_irq(gpio));  			}  		}  	} +} + +static int matrix_keypad_suspend(struct device *dev) +{ +	struct platform_device *pdev = to_platform_device(dev); +	struct matrix_keypad *keypad = platform_get_drvdata(pdev); + +	matrix_keypad_stop(keypad->input_dev); + +	if (device_may_wakeup(&pdev->dev)) +		matrix_keypad_enable_wakeup(keypad); + +	return 0; +} + +static int matrix_keypad_resume(struct device *dev) +{ +	struct platform_device *pdev = to_platform_device(dev); +	struct matrix_keypad *keypad = platform_get_drvdata(pdev); + +	if (device_may_wakeup(&pdev->dev)) +		matrix_keypad_disable_wakeup(keypad);  	matrix_keypad_start(keypad->input_dev); @@ -296,17 +329,31 @@ static int __devinit init_matrix_gpio(struct platform_device *pdev,  		gpio_direction_input(pdata->row_gpios[i]);  	} -	for (i = 0; i < pdata->num_row_gpios; i++) { -		err = request_irq(gpio_to_irq(pdata->row_gpios[i]), +	if (pdata->clustered_irq > 0) { +		err = request_irq(pdata->clustered_irq,  				matrix_keypad_interrupt, -				IRQF_DISABLED | -				IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, +				pdata->clustered_irq_flags,  				"matrix-keypad", keypad);  		if (err) {  			dev_err(&pdev->dev, -				"Unable to acquire interrupt for GPIO line %i\n", -				pdata->row_gpios[i]); -			goto err_free_irqs; +				"Unable to acquire clustered interrupt\n"); +			goto err_free_rows; +		} +	} else { +		for (i = 0; i < pdata->num_row_gpios; i++) { +			err = request_irq(gpio_to_irq(pdata->row_gpios[i]), +					matrix_keypad_interrupt, +					IRQF_DISABLED | +					IRQF_TRIGGER_RISING | +					IRQF_TRIGGER_FALLING, +					"matrix-keypad", keypad); +			if (err) { +				dev_err(&pdev->dev, +					"Unable to acquire interrupt " +					"for GPIO line %i\n", +					pdata->row_gpios[i]); +				goto err_free_irqs; +			}  		}  	} @@ -418,11 +465,16 @@ static int __devexit matrix_keypad_remove(struct platform_device *pdev)  	device_init_wakeup(&pdev->dev, 0); -	for (i = 0; i < pdata->num_row_gpios; i++) { -		free_irq(gpio_to_irq(pdata->row_gpios[i]), keypad); -		gpio_free(pdata->row_gpios[i]); +	if (pdata->clustered_irq > 0) { +		free_irq(pdata->clustered_irq, keypad); +	} else { +		for (i = 0; i < pdata->num_row_gpios; i++) +			free_irq(gpio_to_irq(pdata->row_gpios[i]), keypad);  	} +	for (i = 0; i < pdata->num_row_gpios; i++) +		gpio_free(pdata->row_gpios[i]); +  	for (i = 0; i < pdata->num_col_gpios; i++)  		gpio_free(pdata->col_gpios[i]);  |