mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-11 20:48:49 +08:00
Input: matrix_keypad - add support for clustered irq
This one adds support of a combined irq source for the whole matrix keypad. This can be useful if all rows and columns of the keypad are e.g. connected to a GPIO expander, which only has one interrupt line for all events on every single GPIO. Signed-off-by: Luotao Fu <l.fu@pengutronix.de> Acked-by: Eric Miao <eric.y.miao@gmail.com> Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
This commit is contained in:
parent
1719ec4136
commit
fb76dd10b9
@ -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,25 +225,58 @@ 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void matrix_keypad_disable_wakeup(struct matrix_keypad *keypad)
|
||||
{
|
||||
const struct matrix_keypad_platform_data *pdata = keypad->pdata;
|
||||
unsigned int gpio;
|
||||
int i;
|
||||
|
||||
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)) {
|
||||
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;
|
||||
}
|
||||
@ -243,18 +285,9 @@ static int matrix_keypad_resume(struct device *dev)
|
||||
{
|
||||
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;
|
||||
int i;
|
||||
|
||||
if (device_may_wakeup(&pdev->dev)) {
|
||||
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];
|
||||
|
||||
disable_irq_wake(gpio_to_irq(gpio));
|
||||
}
|
||||
}
|
||||
}
|
||||
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]);
|
||||
|
||||
|
@ -41,6 +41,9 @@ struct matrix_keymap_data {
|
||||
* @col_scan_delay_us: delay, measured in microseconds, that is
|
||||
* needed before we can keypad after activating column gpio
|
||||
* @debounce_ms: debounce interval in milliseconds
|
||||
* @clustered_irq: may be specified if interrupts of all row/column GPIOs
|
||||
* are bundled to one single irq
|
||||
* @clustered_irq_flags: flags that are needed for the clustered irq
|
||||
* @active_low: gpio polarity
|
||||
* @wakeup: controls whether the device should be set up as wakeup
|
||||
* source
|
||||
@ -63,6 +66,9 @@ struct matrix_keypad_platform_data {
|
||||
/* key debounce interval in milli-second */
|
||||
unsigned int debounce_ms;
|
||||
|
||||
unsigned int clustered_irq;
|
||||
unsigned int clustered_irq_flags;
|
||||
|
||||
bool active_low;
|
||||
bool wakeup;
|
||||
bool no_autorepeat;
|
||||
|
Loading…
Reference in New Issue
Block a user