diff options
| -rw-r--r-- | drivers/input/keyboard/Kconfig | 13 | ||||
| -rw-r--r-- | drivers/input/keyboard/Makefile | 1 | ||||
| -rw-r--r-- | drivers/input/keyboard/matrix_keypad.c | 453 | ||||
| -rw-r--r-- | include/linux/input/matrix_keypad.h | 65 |
4 files changed, 530 insertions, 2 deletions
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index d2df1030675..a6b989a9dc0 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig | |||
| @@ -158,7 +158,16 @@ config KEYBOARD_GPIO | |||
| 158 | with configuration data saying which GPIOs are used. | 158 | with configuration data saying which GPIOs are used. |
| 159 | 159 | ||
| 160 | To compile this driver as a module, choose M here: the | 160 | To compile this driver as a module, choose M here: the |
| 161 | module will be called gpio-keys. | 161 | module will be called gpio_keys. |
| 162 | |||
| 163 | config KEYBOARD_MATRIX | ||
| 164 | tristate "GPIO driven matrix keypad support" | ||
| 165 | depends on GENERIC_GPIO | ||
| 166 | help | ||
| 167 | Enable support for GPIO driven matrix keypad. | ||
| 168 | |||
| 169 | To compile this driver as a module, choose M here: the | ||
| 170 | module will be called matrix_keypad. | ||
| 162 | 171 | ||
| 163 | config KEYBOARD_HIL_OLD | 172 | config KEYBOARD_HIL_OLD |
| 164 | tristate "HP HIL keyboard support (simple driver)" | 173 | tristate "HP HIL keyboard support (simple driver)" |
| @@ -254,7 +263,7 @@ config KEYBOARD_PXA27x | |||
| 254 | tristate "PXA27x/PXA3xx keypad support" | 263 | tristate "PXA27x/PXA3xx keypad support" |
| 255 | depends on PXA27x || PXA3xx | 264 | depends on PXA27x || PXA3xx |
| 256 | help | 265 | help |
| 257 | Enable support for PXA27x/PXA3xx keypad controller | 266 | Enable support for PXA27x/PXA3xx keypad controller. |
| 258 | 267 | ||
| 259 | To compile this driver as a module, choose M here: the | 268 | To compile this driver as a module, choose M here: the |
| 260 | module will be called pxa27x_keypad. | 269 | module will be called pxa27x_keypad. |
diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile index 632efbc18c4..b5b5eae9724 100644 --- a/drivers/input/keyboard/Makefile +++ b/drivers/input/keyboard/Makefile | |||
| @@ -20,6 +20,7 @@ obj-$(CONFIG_KEYBOARD_LKKBD) += lkkbd.o | |||
| 20 | obj-$(CONFIG_KEYBOARD_LM8323) += lm8323.o | 20 | obj-$(CONFIG_KEYBOARD_LM8323) += lm8323.o |
| 21 | obj-$(CONFIG_KEYBOARD_LOCOMO) += locomokbd.o | 21 | obj-$(CONFIG_KEYBOARD_LOCOMO) += locomokbd.o |
| 22 | obj-$(CONFIG_KEYBOARD_MAPLE) += maple_keyb.o | 22 | obj-$(CONFIG_KEYBOARD_MAPLE) += maple_keyb.o |
| 23 | obj-$(CONFIG_KEYBOARD_MATRIX) += matrix_keypad.o | ||
| 23 | obj-$(CONFIG_KEYBOARD_NEWTON) += newtonkbd.o | 24 | obj-$(CONFIG_KEYBOARD_NEWTON) += newtonkbd.o |
| 24 | obj-$(CONFIG_KEYBOARD_OMAP) += omap-keypad.o | 25 | obj-$(CONFIG_KEYBOARD_OMAP) += omap-keypad.o |
| 25 | obj-$(CONFIG_KEYBOARD_PXA27x) += pxa27x_keypad.o | 26 | obj-$(CONFIG_KEYBOARD_PXA27x) += pxa27x_keypad.o |
diff --git a/drivers/input/keyboard/matrix_keypad.c b/drivers/input/keyboard/matrix_keypad.c new file mode 100644 index 00000000000..e9b2e7cb05b --- /dev/null +++ b/drivers/input/keyboard/matrix_keypad.c | |||
| @@ -0,0 +1,453 @@ | |||
| 1 | /* | ||
| 2 | * GPIO driven matrix keyboard driver | ||
| 3 | * | ||
| 4 | * Copyright (c) 2008 Marek Vasut <marek.vasut@gmail.com> | ||
| 5 | * | ||
| 6 | * Based on corgikbd.c | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or modify | ||
| 9 | * it under the terms of the GNU General Public License version 2 as | ||
| 10 | * published by the Free Software Foundation. | ||
| 11 | * | ||
| 12 | */ | ||
| 13 | |||
| 14 | #include <linux/types.h> | ||
| 15 | #include <linux/delay.h> | ||
| 16 | #include <linux/platform_device.h> | ||
| 17 | #include <linux/init.h> | ||
| 18 | #include <linux/input.h> | ||
| 19 | #include <linux/irq.h> | ||
| 20 | #include <linux/interrupt.h> | ||
| 21 | #include <linux/jiffies.h> | ||
| 22 | #include <linux/module.h> | ||
| 23 | #include <linux/gpio.h> | ||
| 24 | #include <linux/input/matrix_keypad.h> | ||
| 25 | |||
| 26 | struct matrix_keypad { | ||
| 27 | const struct matrix_keypad_platform_data *pdata; | ||
| 28 | struct input_dev *input_dev; | ||
| 29 | unsigned short *keycodes; | ||
| 30 | |||
| 31 | uint32_t last_key_state[MATRIX_MAX_COLS]; | ||
| 32 | struct delayed_work work; | ||
| 33 | bool scan_pending; | ||
| 34 | bool stopped; | ||
| 35 | spinlock_t lock; | ||
| 36 | }; | ||
| 37 | |||
| 38 | /* | ||
| 39 | * NOTE: normally the GPIO has to be put into HiZ when de-activated to cause | ||
| 40 | * minmal side effect when scanning other columns, here it is configured to | ||
| 41 | * be input, and it should work on most platforms. | ||
| 42 | */ | ||
| 43 | static void __activate_col(const struct matrix_keypad_platform_data *pdata, | ||
| 44 | int col, bool on) | ||
| 45 | { | ||
| 46 | bool level_on = !pdata->active_low; | ||
| 47 | |||
| 48 | if (on) { | ||
| 49 | gpio_direction_output(pdata->col_gpios[col], level_on); | ||
| 50 | } else { | ||
| 51 | gpio_set_value_cansleep(pdata->col_gpios[col], !level_on); | ||
| 52 | gpio_direction_input(pdata->col_gpios[col]); | ||
| 53 | } | ||
| 54 | } | ||
| 55 | |||
| 56 | static void activate_col(const struct matrix_keypad_platform_data *pdata, | ||
| 57 | int col, bool on) | ||
| 58 | { | ||
| 59 | __activate_col(pdata, col, on); | ||
| 60 | |||
| 61 | if (on && pdata->col_scan_delay_us) | ||
| 62 | udelay(pdata->col_scan_delay_us); | ||
| 63 | } | ||
| 64 | |||
| 65 | static void activate_all_cols(const struct matrix_keypad_platform_data *pdata, | ||
| 66 | bool on) | ||
| 67 | { | ||
| 68 | int col; | ||
| 69 | |||
| 70 | for (col = 0; col < pdata->num_col_gpios; col++) | ||
| 71 | __activate_col(pdata, col, on); | ||
| 72 | } | ||
| 73 | |||
| 74 | static bool row_asserted(const struct matrix_keypad_platform_data *pdata, | ||
| 75 | int row) | ||
| 76 | { | ||
| 77 | return gpio_get_value_cansleep(pdata->row_gpios[row]) ? | ||
| 78 | !pdata->active_low : pdata->active_low; | ||
| 79 | } | ||
| 80 | |||
| 81 | static void enable_row_irqs(struct matrix_keypad *keypad) | ||
| 82 | { | ||
| 83 | const struct matrix_keypad_platform_data *pdata = keypad->pdata; | ||
| 84 | int i; | ||
| 85 | |||
| 86 | for (i = 0; i < pdata->num_row_gpios; i++) | ||
| 87 | enable_irq(gpio_to_irq(pdata->row_gpios[i])); | ||
| 88 | } | ||
| 89 | |||
| 90 | static void disable_row_irqs(struct matrix_keypad *keypad) | ||
| 91 | { | ||
| 92 | const struct matrix_keypad_platform_data *pdata = keypad->pdata; | ||
| 93 | int i; | ||
| 94 | |||
| 95 | for (i = 0; i < pdata->num_row_gpios; i++) | ||
| 96 | disable_irq_nosync(gpio_to_irq(pdata->row_gpios[i])); | ||
| 97 | } | ||
| 98 | |||
| 99 | /* | ||
| 100 | * This gets the keys from keyboard and reports it to input subsystem | ||
| 101 | */ | ||
| 102 | static void matrix_keypad_scan(struct work_struct *work) | ||
| 103 | { | ||
| 104 | struct matrix_keypad *keypad = | ||
| 105 | container_of(work, struct matrix_keypad, work.work); | ||
| 106 | struct input_dev *input_dev = keypad->input_dev; | ||
| 107 | const struct matrix_keypad_platform_data *pdata = keypad->pdata; | ||
| 108 | uint32_t new_state[MATRIX_MAX_COLS]; | ||
| 109 | int row, col, code; | ||
| 110 | |||
| 111 | /* de-activate all columns for scanning */ | ||
| 112 | activate_all_cols(pdata, false); | ||
| 113 | |||
| 114 | memset(new_state, 0, sizeof(new_state)); | ||
| 115 | |||
| 116 | /* assert each column and read the row status out */ | ||
| 117 | for (col = 0; col < pdata->num_col_gpios; col++) { | ||
| 118 | |||
| 119 | activate_col(pdata, col, true); | ||
| 120 | |||
| 121 | for (row = 0; row < pdata->num_row_gpios; row++) | ||
| 122 | new_state[col] |= | ||
| 123 | row_asserted(pdata, row) ? (1 << row) : 0; | ||
| 124 | |||
| 125 | activate_col(pdata, col, false); | ||
| 126 | } | ||
| 127 | |||
| 128 | for (col = 0; col < pdata->num_col_gpios; col++) { | ||
| 129 | uint32_t bits_changed; | ||
| 130 | |||
| 131 | bits_changed = keypad->last_key_state[col] ^ new_state[col]; | ||
| 132 | if (bits_changed == 0) | ||
| 133 | continue; | ||
| 134 | |||
| 135 | for (row = 0; row < pdata->num_row_gpios; row++) { | ||
| 136 | if ((bits_changed & (1 << row)) == 0) | ||
| 137 | continue; | ||
| 138 | |||
| 139 | code = (row << 4) + col; | ||
| 140 | input_event(input_dev, EV_MSC, MSC_SCAN, code); | ||
| 141 | input_report_key(input_dev, | ||
| 142 | keypad->keycodes[code], | ||
| 143 | new_state[col] & (1 << row)); | ||
| 144 | } | ||
| 145 | } | ||
| 146 | input_sync(input_dev); | ||
| 147 | |||
| 148 | memcpy(keypad->last_key_state, new_state, sizeof(new_state)); | ||
| 149 | |||
| 150 | activate_all_cols(pdata, true); | ||
| 151 | |||
| 152 | /* Enable IRQs again */ | ||
| 153 | spin_lock_irq(&keypad->lock); | ||
| 154 | keypad->scan_pending = false; | ||
| 155 | enable_row_irqs(keypad); | ||
| 156 | spin_unlock_irq(&keypad->lock); | ||
| 157 | } | ||
| 158 | |||
| 159 | static irqreturn_t matrix_keypad_interrupt(int irq, void *id) | ||
| 160 | { | ||
| 161 | struct matrix_keypad *keypad = id; | ||
| 162 | unsigned long flags; | ||
| 163 | |||
| 164 | spin_lock_irqsave(&keypad->lock, flags); | ||
| 165 | |||
| 166 | /* | ||
| 167 | * See if another IRQ beaten us to it and scheduled the | ||
| 168 | * scan already. In that case we should not try to | ||
| 169 | * disable IRQs again. | ||
| 170 | */ | ||
| 171 | if (unlikely(keypad->scan_pending || keypad->stopped)) | ||
| 172 | goto out; | ||
| 173 | |||
| 174 | disable_row_irqs(keypad); | ||
| 175 | keypad->scan_pending = true; | ||
| 176 | schedule_delayed_work(&keypad->work, | ||
| 177 | msecs_to_jiffies(keypad->pdata->debounce_ms)); | ||
| 178 | |||
| 179 | out: | ||
| 180 | spin_unlock_irqrestore(&keypad->lock, flags); | ||
| 181 | return IRQ_HANDLED; | ||
| 182 | } | ||
| 183 | |||
| 184 | static int matrix_keypad_start(struct input_dev *dev) | ||
| 185 | { | ||
| 186 | struct matrix_keypad *keypad = input_get_drvdata(dev); | ||
| 187 | |||
| 188 | keypad->stopped = false; | ||
| 189 | mb(); | ||
| 190 | |||
| 191 | /* | ||
| 192 | * Schedule an immediate key scan to capture current key state; | ||
| 193 | * columns will be activated and IRQs be enabled after the scan. | ||
| 194 | */ | ||
| 195 | schedule_delayed_work(&keypad->work, 0); | ||
| 196 | |||
| 197 | return 0; | ||
| 198 | } | ||
| 199 | |||
| 200 | static void matrix_keypad_stop(struct input_dev *dev) | ||
| 201 | { | ||
| 202 | struct matrix_keypad *keypad = input_get_drvdata(dev); | ||
| 203 | |||
| 204 | keypad->stopped = true; | ||
| 205 | mb(); | ||
| 206 | flush_work(&keypad->work.work); | ||
| 207 | /* | ||
| 208 | * matrix_keypad_scan() will leave IRQs enabled; | ||
| 209 | * we should disable them now. | ||
| 210 | */ | ||
| 211 | disable_row_irqs(keypad); | ||
| 212 | } | ||
| 213 | |||
| 214 | #ifdef CONFIG_PM | ||
| 215 | static int matrix_keypad_suspend(struct platform_device *pdev, pm_message_t state) | ||
| 216 | { | ||
| 217 | struct matrix_keypad *keypad = platform_get_drvdata(pdev); | ||
| 218 | const struct matrix_keypad_platform_data *pdata = keypad->pdata; | ||
| 219 | int i; | ||
| 220 | |||
| 221 | matrix_keypad_stop(keypad->input_dev); | ||
| 222 | |||
| 223 | if (device_may_wakeup(&pdev->dev)) | ||
| 224 | for (i = 0; i < pdata->num_row_gpios; i++) | ||
| 225 | enable_irq_wake(gpio_to_irq(pdata->row_gpios[i])); | ||
| 226 | |||
| 227 | return 0; | ||
| 228 | } | ||
| 229 | |||
| 230 | static int matrix_keypad_resume(struct platform_device *pdev) | ||
| 231 | { | ||
| 232 | struct matrix_keypad *keypad = platform_get_drvdata(pdev); | ||
| 233 | const struct matrix_keypad_platform_data *pdata = keypad->pdata; | ||
| 234 | int i; | ||
| 235 | |||
| 236 | if (device_may_wakeup(&pdev->dev)) | ||
| 237 | for (i = 0; i < pdata->num_row_gpios; i++) | ||
| 238 | disable_irq_wake(gpio_to_irq(pdata->row_gpios[i])); | ||
| 239 | |||
| 240 | matrix_keypad_start(keypad->input_dev); | ||
| 241 | |||
| 242 | return 0; | ||
| 243 | } | ||
| 244 | #else | ||
| 245 | #define matrix_keypad_suspend NULL | ||
| 246 | #define matrix_keypad_resume NULL | ||
| 247 | #endif | ||
| 248 | |||
| 249 | static int __devinit init_matrix_gpio(struct platform_device *pdev, | ||
| 250 | struct matrix_keypad *keypad) | ||
| 251 | { | ||
| 252 | const struct matrix_keypad_platform_data *pdata = keypad->pdata; | ||
| 253 | int i, err = -EINVAL; | ||
| 254 | |||
| 255 | /* initialized strobe lines as outputs, activated */ | ||
| 256 | for (i = 0; i < pdata->num_col_gpios; i++) { | ||
| 257 | err = gpio_request(pdata->col_gpios[i], "matrix_kbd_col"); | ||
| 258 | if (err) { | ||
| 259 | dev_err(&pdev->dev, | ||
| 260 | "failed to request GPIO%d for COL%d\n", | ||
| 261 | pdata->col_gpios[i], i); | ||
| 262 | goto err_free_cols; | ||
| 263 | } | ||
| 264 | |||
| 265 | gpio_direction_output(pdata->col_gpios[i], !pdata->active_low); | ||
| 266 | } | ||
| 267 | |||
| 268 | for (i = 0; i < pdata->num_row_gpios; i++) { | ||
| 269 | err = gpio_request(pdata->row_gpios[i], "matrix_kbd_row"); | ||
| 270 | if (err) { | ||
| 271 | dev_err(&pdev->dev, | ||
| 272 | "failed to request GPIO%d for ROW%d\n", | ||
| 273 | pdata->row_gpios[i], i); | ||
| 274 | goto err_free_rows; | ||
| 275 | } | ||
| 276 | |||
| 277 | gpio_direction_input(pdata->row_gpios[i]); | ||
| 278 | } | ||
| 279 | |||
| 280 | for (i = 0; i < pdata->num_row_gpios; i++) { | ||
| 281 | err = request_irq(gpio_to_irq(pdata->row_gpios[i]), | ||
| 282 | matrix_keypad_interrupt, | ||
| 283 | IRQF_DISABLED | | ||
| 284 | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, | ||
| 285 | "matrix-keypad", keypad); | ||
| 286 | if (err) { | ||
| 287 | dev_err(&pdev->dev, | ||
| 288 | "Unable to acquire interrupt for GPIO line %i\n", | ||
| 289 | pdata->row_gpios[i]); | ||
| 290 | goto err_free_irqs; | ||
| 291 | } | ||
| 292 | } | ||
| 293 | |||
| 294 | /* initialized as disabled - enabled by input->open */ | ||
| 295 | disable_row_irqs(keypad); | ||
| 296 | return 0; | ||
| 297 | |||
| 298 | err_free_irqs: | ||
| 299 | while (--i >= 0) | ||
| 300 | free_irq(gpio_to_irq(pdata->row_gpios[i]), keypad); | ||
| 301 | i = pdata->num_row_gpios; | ||
| 302 | err_free_rows: | ||
| 303 | while (--i >= 0) | ||
| 304 | gpio_free(pdata->row_gpios[i]); | ||
| 305 | i = pdata->num_col_gpios; | ||
| 306 | err_free_cols: | ||
| 307 | while (--i >= 0) | ||
| 308 | gpio_free(pdata->col_gpios[i]); | ||
| 309 | |||
| 310 | return err; | ||
| 311 | } | ||
| 312 | |||
| 313 | static int __devinit matrix_keypad_probe(struct platform_device *pdev) | ||
| 314 | { | ||
| 315 | const struct matrix_keypad_platform_data *pdata; | ||
| 316 | const struct matrix_keymap_data *keymap_data; | ||
| 317 | struct matrix_keypad *keypad; | ||
| 318 | struct input_dev *input_dev; | ||
| 319 | unsigned short *keycodes; | ||
| 320 | int i; | ||
| 321 | int err; | ||
| 322 | |||
| 323 | pdata = pdev->dev.platform_data; | ||
| 324 | if (!pdata) { | ||
| 325 | dev_err(&pdev->dev, "no platform data defined\n"); | ||
| 326 | return -EINVAL; | ||
| 327 | } | ||
| 328 | |||
| 329 | keymap_data = pdata->keymap_data; | ||
| 330 | if (!keymap_data) { | ||
| 331 | dev_err(&pdev->dev, "no keymap data defined\n"); | ||
| 332 | return -EINVAL; | ||
| 333 | } | ||
| 334 | |||
| 335 | if (!keymap_data->max_keymap_size) { | ||
| 336 | dev_err(&pdev->dev, "invalid keymap data supplied\n"); | ||
| 337 | return -EINVAL; | ||
| 338 | } | ||
| 339 | |||
| 340 | keypad = kzalloc(sizeof(struct matrix_keypad), GFP_KERNEL); | ||
| 341 | keycodes = kzalloc(keymap_data->max_keymap_size * | ||
| 342 | sizeof(keypad->keycodes), | ||
| 343 | GFP_KERNEL); | ||
| 344 | input_dev = input_allocate_device(); | ||
| 345 | if (!keypad || !keycodes || !input_dev) { | ||
| 346 | err = -ENOMEM; | ||
| 347 | goto err_free_mem; | ||
| 348 | } | ||
| 349 | |||
| 350 | keypad->input_dev = input_dev; | ||
| 351 | keypad->pdata = pdata; | ||
| 352 | keypad->keycodes = keycodes; | ||
| 353 | keypad->stopped = true; | ||
| 354 | INIT_DELAYED_WORK(&keypad->work, matrix_keypad_scan); | ||
| 355 | spin_lock_init(&keypad->lock); | ||
| 356 | |||
| 357 | input_dev->name = pdev->name; | ||
| 358 | input_dev->id.bustype = BUS_HOST; | ||
| 359 | input_dev->dev.parent = &pdev->dev; | ||
| 360 | input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP); | ||
| 361 | input_dev->open = matrix_keypad_start; | ||
| 362 | input_dev->close = matrix_keypad_stop; | ||
| 363 | |||
| 364 | input_dev->keycode = keycodes; | ||
| 365 | input_dev->keycodesize = sizeof(*keycodes); | ||
| 366 | input_dev->keycodemax = keymap_data->max_keymap_size; | ||
| 367 | |||
| 368 | for (i = 0; i < keymap_data->keymap_size; i++) { | ||
| 369 | unsigned int key = keymap_data->keymap[i]; | ||
| 370 | unsigned int row = KEY_ROW(key); | ||
| 371 | unsigned int col = KEY_COL(key); | ||
| 372 | unsigned short code = KEY_VAL(key); | ||
| 373 | |||
| 374 | keycodes[(row << 4) + col] = code; | ||
| 375 | __set_bit(code, input_dev->keybit); | ||
| 376 | } | ||
| 377 | __clear_bit(KEY_RESERVED, input_dev->keybit); | ||
| 378 | |||
| 379 | input_set_capability(input_dev, EV_MSC, MSC_SCAN); | ||
| 380 | input_set_drvdata(input_dev, keypad); | ||
| 381 | |||
| 382 | err = init_matrix_gpio(pdev, keypad); | ||
| 383 | if (err) | ||
| 384 | goto err_free_mem; | ||
| 385 | |||
| 386 | err = input_register_device(keypad->input_dev); | ||
| 387 | if (err) | ||
| 388 | goto err_free_mem; | ||
| 389 | |||
| 390 | device_init_wakeup(&pdev->dev, pdata->wakeup); | ||
| 391 | platform_set_drvdata(pdev, keypad); | ||
| 392 | |||
| 393 | return 0; | ||
| 394 | |||
| 395 | err_free_mem: | ||
| 396 | input_free_device(input_dev); | ||
| 397 | kfree(keycodes); | ||
| 398 | kfree(keypad); | ||
| 399 | return err; | ||
| 400 | } | ||
| 401 | |||
| 402 | static int __devexit matrix_keypad_remove(struct platform_device *pdev) | ||
| 403 | { | ||
| 404 | struct matrix_keypad *keypad = platform_get_drvdata(pdev); | ||
| 405 | const struct matrix_keypad_platform_data *pdata = keypad->pdata; | ||
| 406 | int i; | ||
| 407 | |||
| 408 | device_init_wakeup(&pdev->dev, 0); | ||
| 409 | |||
| 410 | for (i = 0; i < pdata->num_row_gpios; i++) { | ||
| 411 | free_irq(gpio_to_irq(pdata->row_gpios[i]), keypad); | ||
| 412 | gpio_free(pdata->row_gpios[i]); | ||
| 413 | } | ||
| 414 | |||
| 415 | for (i = 0; i < pdata->num_col_gpios; i++) | ||
| 416 | gpio_free(pdata->col_gpios[i]); | ||
| 417 | |||
| 418 | input_unregister_device(keypad->input_dev); | ||
| 419 | platform_set_drvdata(pdev, NULL); | ||
| 420 | kfree(keypad->keycodes); | ||
| 421 | kfree(keypad); | ||
| 422 | |||
| 423 | return 0; | ||
| 424 | } | ||
| 425 | |||
| 426 | static struct platform_driver matrix_keypad_driver = { | ||
| 427 | .probe = matrix_keypad_probe, | ||
| 428 | .remove = __devexit_p(matrix_keypad_remove), | ||
| 429 | .suspend = matrix_keypad_suspend, | ||
| 430 | .resume = matrix_keypad_resume, | ||
| 431 | .driver = { | ||
| 432 | .name = "matrix-keypad", | ||
| 433 | .owner = THIS_MODULE, | ||
| 434 | }, | ||
| 435 | }; | ||
| 436 | |||
| 437 | static int __init matrix_keypad_init(void) | ||
| 438 | { | ||
| 439 | return platform_driver_register(&matrix_keypad_driver); | ||
| 440 | } | ||
| 441 | |||
| 442 | static void __exit matrix_keypad_exit(void) | ||
| 443 | { | ||
| 444 | platform_driver_unregister(&matrix_keypad_driver); | ||
| 445 | } | ||
| 446 | |||
| 447 | module_init(matrix_keypad_init); | ||
| 448 | module_exit(matrix_keypad_exit); | ||
| 449 | |||
| 450 | MODULE_AUTHOR("Marek Vasut <marek.vasut@gmail.com>"); | ||
| 451 | MODULE_DESCRIPTION("GPIO Driven Matrix Keypad Driver"); | ||
| 452 | MODULE_LICENSE("GPL v2"); | ||
| 453 | MODULE_ALIAS("platform:matrix-keypad"); | ||
diff --git a/include/linux/input/matrix_keypad.h b/include/linux/input/matrix_keypad.h new file mode 100644 index 00000000000..7964516c695 --- /dev/null +++ b/include/linux/input/matrix_keypad.h | |||
| @@ -0,0 +1,65 @@ | |||
| 1 | #ifndef _MATRIX_KEYPAD_H | ||
| 2 | #define _MATRIX_KEYPAD_H | ||
| 3 | |||
| 4 | #include <linux/types.h> | ||
| 5 | #include <linux/input.h> | ||
| 6 | |||
| 7 | #define MATRIX_MAX_ROWS 16 | ||
| 8 | #define MATRIX_MAX_COLS 16 | ||
| 9 | |||
| 10 | #define KEY(row, col, val) ((((row) & (MATRIX_MAX_ROWS - 1)) << 24) |\ | ||
| 11 | (((col) & (MATRIX_MAX_COLS - 1)) << 16) |\ | ||
| 12 | (val & 0xffff)) | ||
| 13 | |||
| 14 | #define KEY_ROW(k) (((k) >> 24) & 0xff) | ||
| 15 | #define KEY_COL(k) (((k) >> 16) & 0xff) | ||
| 16 | #define KEY_VAL(k) ((k) & 0xffff) | ||
| 17 | |||
| 18 | /** | ||
| 19 | * struct matrix_keymap_data - keymap for matrix keyboards | ||
| 20 | * @keymap: pointer to array of uint32 values encoded with KEY() macro | ||
| 21 | * representing keymap | ||
| 22 | * @keymap_size: number of entries (initialized) in this keymap | ||
| 23 | * @max_keymap_size: maximum size of keymap supported by the device | ||
| 24 | * | ||
| 25 | * This structure is supposed to be used by platform code to supply | ||
| 26 | * keymaps to drivers that implement matrix-like keypads/keyboards. | ||
| 27 | */ | ||
| 28 | struct matrix_keymap_data { | ||
| 29 | const uint32_t *keymap; | ||
| 30 | unsigned int keymap_size; | ||
| 31 | unsigned int max_keymap_size; | ||
| 32 | }; | ||
| 33 | |||
| 34 | /** | ||
| 35 | * struct matrix_keypad_platform_data - platform-dependent keypad data | ||
| 36 | * @keymap_data: pointer to &matrix_keymap_data | ||
| 37 | * @row_gpios: array of gpio numbers reporesenting rows | ||
| 38 | * @col_gpios: array of gpio numbers reporesenting colums | ||
| 39 | * @num_row_gpios: actual number of row gpios used by device | ||
| 40 | * @num_col_gpios: actual number of col gpios used by device | ||
| 41 | * @col_scan_delay_us: delay, measured in microseconds, that is | ||
| 42 | * needed before we can keypad after activating column gpio | ||
| 43 | * @debounce_ms: debounce interval in milliseconds | ||
| 44 | * | ||
| 45 | * This structure represents platform-specific data that use used by | ||
| 46 | * matrix_keypad driver to perform proper initialization. | ||
| 47 | */ | ||
| 48 | struct matrix_keypad_platform_data { | ||
| 49 | const struct matrix_keymap_data *keymap_data; | ||
| 50 | |||
| 51 | unsigned int row_gpios[MATRIX_MAX_ROWS]; | ||
| 52 | unsigned int col_gpios[MATRIX_MAX_COLS]; | ||
| 53 | unsigned int num_row_gpios; | ||
| 54 | unsigned int num_col_gpios; | ||
| 55 | |||
| 56 | unsigned int col_scan_delay_us; | ||
| 57 | |||
| 58 | /* key debounce interval in milli-second */ | ||
| 59 | unsigned int debounce_ms; | ||
| 60 | |||
| 61 | bool active_low; | ||
| 62 | bool wakeup; | ||
| 63 | }; | ||
| 64 | |||
| 65 | #endif /* _MATRIX_KEYPAD_H */ | ||
