]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - drivers/staging/dream/gpio_matrix.c
Merge branch 'master' into tk71
[mv-sheeva.git] / drivers / staging / dream / gpio_matrix.c
diff --git a/drivers/staging/dream/gpio_matrix.c b/drivers/staging/dream/gpio_matrix.c
deleted file mode 100644 (file)
index b377ee1..0000000
+++ /dev/null
@@ -1,399 +0,0 @@
-/* drivers/input/misc/gpio_matrix.c
- *
- * Copyright (C) 2007 Google, Inc.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/gpio.h>
-#include <linux/gpio_event.h>
-#include <linux/hrtimer.h>
-#include <linux/interrupt.h>
-
-struct gpio_kp {
-       struct input_dev *input_dev;
-       struct gpio_event_matrix_info *keypad_info;
-       struct hrtimer timer;
-       int current_output;
-       unsigned int use_irq:1;
-       unsigned int key_state_changed:1;
-       unsigned int last_key_state_changed:1;
-       unsigned int some_keys_pressed:2;
-       unsigned long keys_pressed[0];
-};
-
-static void clear_phantom_key(struct gpio_kp *kp, int out, int in)
-{
-       struct gpio_event_matrix_info *mi = kp->keypad_info;
-       int key_index = out * mi->ninputs + in;
-       unsigned short keycode = mi->keymap[key_index];;
-
-       if (!test_bit(keycode, kp->input_dev->key)) {
-               if (mi->flags & GPIOKPF_PRINT_PHANTOM_KEYS)
-                       pr_info("gpiomatrix: phantom key %x, %d-%d (%d-%d) "
-                               "cleared\n", keycode, out, in,
-                               mi->output_gpios[out], mi->input_gpios[in]);
-               __clear_bit(key_index, kp->keys_pressed);
-       } else {
-               if (mi->flags & GPIOKPF_PRINT_PHANTOM_KEYS)
-                       pr_info("gpiomatrix: phantom key %x, %d-%d (%d-%d) "
-                               "not cleared\n", keycode, out, in,
-                               mi->output_gpios[out], mi->input_gpios[in]);
-       }
-}
-
-static int restore_keys_for_input(struct gpio_kp *kp, int out, int in)
-{
-       int rv = 0;
-       int key_index;
-
-       key_index = out * kp->keypad_info->ninputs + in;
-       while (out < kp->keypad_info->noutputs) {
-               if (test_bit(key_index, kp->keys_pressed)) {
-                       rv = 1;
-                       clear_phantom_key(kp, out, in);
-               }
-               key_index += kp->keypad_info->ninputs;
-               out++;
-       }
-       return rv;
-}
-
-static void remove_phantom_keys(struct gpio_kp *kp)
-{
-       int out, in, inp;
-       int key_index;
-
-       if (kp->some_keys_pressed < 3)
-               return;
-
-       for (out = 0; out < kp->keypad_info->noutputs; out++) {
-               inp = -1;
-               key_index = out * kp->keypad_info->ninputs;
-               for (in = 0; in < kp->keypad_info->ninputs; in++, key_index++) {
-                       if (test_bit(key_index, kp->keys_pressed)) {
-                               if (inp == -1) {
-                                       inp = in;
-                                       continue;
-                               }
-                               if (inp >= 0) {
-                                       if (!restore_keys_for_input(kp, out + 1,
-                                                                       inp))
-                                               break;
-                                       clear_phantom_key(kp, out, inp);
-                                       inp = -2;
-                               }
-                               restore_keys_for_input(kp, out, in);
-                       }
-               }
-       }
-}
-
-static void report_key(struct gpio_kp *kp, int key_index, int out, int in)
-{
-       struct gpio_event_matrix_info *mi = kp->keypad_info;
-       int pressed = test_bit(key_index, kp->keys_pressed);
-       unsigned short keycode = mi->keymap[key_index];
-       if (pressed != test_bit(keycode, kp->input_dev->key)) {
-               if (keycode == KEY_RESERVED) {
-                       if (mi->flags & GPIOKPF_PRINT_UNMAPPED_KEYS)
-                               pr_info("gpiomatrix: unmapped key, %d-%d "
-                                       "(%d-%d) changed to %d\n",
-                                       out, in, mi->output_gpios[out],
-                                       mi->input_gpios[in], pressed);
-               } else {
-                       if (mi->flags & GPIOKPF_PRINT_MAPPED_KEYS)
-                               pr_info("gpiomatrix: key %x, %d-%d (%d-%d) "
-                                       "changed to %d\n", keycode,
-                                       out, in, mi->output_gpios[out],
-                                       mi->input_gpios[in], pressed);
-                       input_report_key(kp->input_dev, keycode, pressed);
-               }
-       }
-}
-
-static enum hrtimer_restart gpio_keypad_timer_func(struct hrtimer *timer)
-{
-       int out, in;
-       int key_index;
-       int gpio;
-       struct gpio_kp *kp = container_of(timer, struct gpio_kp, timer);
-       struct gpio_event_matrix_info *mi = kp->keypad_info;
-       unsigned gpio_keypad_flags = mi->flags;
-       unsigned polarity = !!(gpio_keypad_flags & GPIOKPF_ACTIVE_HIGH);
-
-       out = kp->current_output;
-       if (out == mi->noutputs) {
-               out = 0;
-               kp->last_key_state_changed = kp->key_state_changed;
-               kp->key_state_changed = 0;
-               kp->some_keys_pressed = 0;
-       } else {
-               key_index = out * mi->ninputs;
-               for (in = 0; in < mi->ninputs; in++, key_index++) {
-                       gpio = mi->input_gpios[in];
-                       if (gpio_get_value(gpio) ^ !polarity) {
-                               if (kp->some_keys_pressed < 3)
-                                       kp->some_keys_pressed++;
-                               kp->key_state_changed |= !__test_and_set_bit(
-                                               key_index, kp->keys_pressed);
-                       } else
-                               kp->key_state_changed |= __test_and_clear_bit(
-                                               key_index, kp->keys_pressed);
-               }
-               gpio = mi->output_gpios[out];
-               if (gpio_keypad_flags & GPIOKPF_DRIVE_INACTIVE)
-                       gpio_set_value(gpio, !polarity);
-               else
-                       gpio_direction_input(gpio);
-               out++;
-       }
-       kp->current_output = out;
-       if (out < mi->noutputs) {
-               gpio = mi->output_gpios[out];
-               if (gpio_keypad_flags & GPIOKPF_DRIVE_INACTIVE)
-                       gpio_set_value(gpio, polarity);
-               else
-                       gpio_direction_output(gpio, polarity);
-               hrtimer_start(timer, mi->settle_time, HRTIMER_MODE_REL);
-               return HRTIMER_NORESTART;
-       }
-       if (gpio_keypad_flags & GPIOKPF_DEBOUNCE) {
-               if (kp->key_state_changed) {
-                       hrtimer_start(&kp->timer, mi->debounce_delay,
-                                     HRTIMER_MODE_REL);
-                       return HRTIMER_NORESTART;
-               }
-               kp->key_state_changed = kp->last_key_state_changed;
-       }
-       if (kp->key_state_changed) {
-               if (gpio_keypad_flags & GPIOKPF_REMOVE_SOME_PHANTOM_KEYS)
-                       remove_phantom_keys(kp);
-               key_index = 0;
-               for (out = 0; out < mi->noutputs; out++)
-                       for (in = 0; in < mi->ninputs; in++, key_index++)
-                               report_key(kp, key_index, out, in);
-       }
-       if (!kp->use_irq || kp->some_keys_pressed) {
-               hrtimer_start(timer, mi->poll_time, HRTIMER_MODE_REL);
-               return HRTIMER_NORESTART;
-       }
-
-       /* No keys are pressed, reenable interrupt */
-       for (out = 0; out < mi->noutputs; out++) {
-               if (gpio_keypad_flags & GPIOKPF_DRIVE_INACTIVE)
-                       gpio_set_value(mi->output_gpios[out], polarity);
-               else
-                       gpio_direction_output(mi->output_gpios[out], polarity);
-       }
-       for (in = 0; in < mi->ninputs; in++)
-               enable_irq(gpio_to_irq(mi->input_gpios[in]));
-       return HRTIMER_NORESTART;
-}
-
-static irqreturn_t gpio_keypad_irq_handler(int irq_in, void *dev_id)
-{
-       int i;
-       struct gpio_kp *kp = dev_id;
-       struct gpio_event_matrix_info *mi = kp->keypad_info;
-       unsigned gpio_keypad_flags = mi->flags;
-
-       if (!kp->use_irq) /* ignore interrupt while registering the handler */
-               return IRQ_HANDLED;
-
-       for (i = 0; i < mi->ninputs; i++)
-               disable_irq(gpio_to_irq(mi->input_gpios[i]));
-       for (i = 0; i < mi->noutputs; i++) {
-               if (gpio_keypad_flags & GPIOKPF_DRIVE_INACTIVE)
-                       gpio_set_value(mi->output_gpios[i],
-                               !(gpio_keypad_flags & GPIOKPF_ACTIVE_HIGH));
-               else
-                       gpio_direction_input(mi->output_gpios[i]);
-       }
-       hrtimer_start(&kp->timer, ktime_set(0, 0), HRTIMER_MODE_REL);
-       return IRQ_HANDLED;
-}
-
-static int gpio_keypad_request_irqs(struct gpio_kp *kp)
-{
-       int i;
-       int err;
-       unsigned int irq;
-       unsigned long request_flags;
-       struct gpio_event_matrix_info *mi = kp->keypad_info;
-
-       switch (mi->flags & (GPIOKPF_ACTIVE_HIGH|GPIOKPF_LEVEL_TRIGGERED_IRQ)) {
-       default:
-               request_flags = IRQF_TRIGGER_FALLING;
-               break;
-       case GPIOKPF_ACTIVE_HIGH:
-               request_flags = IRQF_TRIGGER_RISING;
-               break;
-       case GPIOKPF_LEVEL_TRIGGERED_IRQ:
-               request_flags = IRQF_TRIGGER_LOW;
-               break;
-       case GPIOKPF_LEVEL_TRIGGERED_IRQ | GPIOKPF_ACTIVE_HIGH:
-               request_flags = IRQF_TRIGGER_HIGH;
-               break;
-       }
-
-       for (i = 0; i < mi->ninputs; i++) {
-               err = irq = gpio_to_irq(mi->input_gpios[i]);
-               if (err < 0)
-                       goto err_gpio_get_irq_num_failed;
-               err = request_irq(irq, gpio_keypad_irq_handler, request_flags,
-                                 "gpio_kp", kp);
-               if (err) {
-                       pr_err("gpiomatrix: request_irq failed for input %d, "
-                               "irq %d\n", mi->input_gpios[i], irq);
-                       goto err_request_irq_failed;
-               }
-               err = set_irq_wake(irq, 1);
-               if (err) {
-                       pr_err("gpiomatrix: set_irq_wake failed for input %d, "
-                               "irq %d\n", mi->input_gpios[i], irq);
-               }
-               disable_irq(irq);
-       }
-       return 0;
-
-       for (i = mi->noutputs - 1; i >= 0; i--) {
-               free_irq(gpio_to_irq(mi->input_gpios[i]), kp);
-err_request_irq_failed:
-err_gpio_get_irq_num_failed:
-               ;
-       }
-       return err;
-}
-
-int gpio_event_matrix_func(struct input_dev *input_dev,
-       struct gpio_event_info *info, void **data, int func)
-{
-       int i;
-       int err;
-       int key_count;
-       struct gpio_kp *kp;
-       struct gpio_event_matrix_info *mi;
-
-       mi = container_of(info, struct gpio_event_matrix_info, info);
-       if (func == GPIO_EVENT_FUNC_SUSPEND || func == GPIO_EVENT_FUNC_RESUME) {
-               /* TODO: disable scanning */
-               return 0;
-       }
-
-       if (func == GPIO_EVENT_FUNC_INIT) {
-               if (mi->keymap == NULL ||
-                  mi->input_gpios == NULL ||
-                  mi->output_gpios == NULL) {
-                       err = -ENODEV;
-                       pr_err("gpiomatrix: Incomplete pdata\n");
-                       goto err_invalid_platform_data;
-               }
-               key_count = mi->ninputs * mi->noutputs;
-
-               *data = kp = kzalloc(sizeof(*kp) + sizeof(kp->keys_pressed[0]) *
-                                    BITS_TO_LONGS(key_count), GFP_KERNEL);
-               if (kp == NULL) {
-                       err = -ENOMEM;
-                       pr_err("gpiomatrix: Failed to allocate private data\n");
-                       goto err_kp_alloc_failed;
-               }
-               kp->input_dev = input_dev;
-               kp->keypad_info = mi;
-               set_bit(EV_KEY, input_dev->evbit);
-               for (i = 0; i < key_count; i++) {
-                       if (mi->keymap[i])
-                               set_bit(mi->keymap[i] & KEY_MAX,
-                                       input_dev->keybit);
-               }
-
-               for (i = 0; i < mi->noutputs; i++) {
-                       if (gpio_cansleep(mi->output_gpios[i])) {
-                               pr_err("gpiomatrix: unsupported output gpio %d,"
-                                       " can sleep\n", mi->output_gpios[i]);
-                               err = -EINVAL;
-                               goto err_request_output_gpio_failed;
-                       }
-                       err = gpio_request(mi->output_gpios[i], "gpio_kp_out");
-                       if (err) {
-                               pr_err("gpiomatrix: gpio_request failed for "
-                                       "output %d\n", mi->output_gpios[i]);
-                               goto err_request_output_gpio_failed;
-                       }
-                       if (mi->flags & GPIOKPF_DRIVE_INACTIVE)
-                               err = gpio_direction_output(mi->output_gpios[i],
-                                       !(mi->flags & GPIOKPF_ACTIVE_HIGH));
-                       else
-                               err = gpio_direction_input(mi->output_gpios[i]);
-                       if (err) {
-                               pr_err("gpiomatrix: gpio_configure failed for "
-                                       "output %d\n", mi->output_gpios[i]);
-                               goto err_output_gpio_configure_failed;
-                       }
-               }
-               for (i = 0; i < mi->ninputs; i++) {
-                       err = gpio_request(mi->input_gpios[i], "gpio_kp_in");
-                       if (err) {
-                               pr_err("gpiomatrix: gpio_request failed for "
-                                       "input %d\n", mi->input_gpios[i]);
-                               goto err_request_input_gpio_failed;
-                       }
-                       err = gpio_direction_input(mi->input_gpios[i]);
-                       if (err) {
-                               pr_err("gpiomatrix: gpio_direction_input failed"
-                                       " for input %d\n", mi->input_gpios[i]);
-                               goto err_gpio_direction_input_failed;
-                       }
-               }
-               kp->current_output = mi->noutputs;
-               kp->key_state_changed = 1;
-
-               hrtimer_init(&kp->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
-               kp->timer.function = gpio_keypad_timer_func;
-               err = gpio_keypad_request_irqs(kp);
-               kp->use_irq = err == 0;
-
-               pr_info("GPIO Matrix Keypad Driver: Start keypad matrix for %s "
-                       "in %s mode\n", input_dev->name,
-                       kp->use_irq ? "interrupt" : "polling");
-
-               hrtimer_start(&kp->timer, ktime_set(0, 0), HRTIMER_MODE_REL);
-
-               return 0;
-       }
-
-       err = 0;
-       kp = *data;
-
-       if (kp->use_irq)
-               for (i = mi->noutputs - 1; i >= 0; i--)
-                       free_irq(gpio_to_irq(mi->input_gpios[i]), kp);
-
-       hrtimer_cancel(&kp->timer);
-       for (i = mi->noutputs - 1; i >= 0; i--) {
-err_gpio_direction_input_failed:
-               gpio_free(mi->input_gpios[i]);
-err_request_input_gpio_failed:
-               ;
-       }
-       for (i = mi->noutputs - 1; i >= 0; i--) {
-err_output_gpio_configure_failed:
-               gpio_free(mi->output_gpios[i]);
-err_request_output_gpio_failed:
-               ;
-       }
-       kfree(kp);
-err_kp_alloc_failed:
-err_invalid_platform_data:
-       return err;
-}