diff options
Diffstat (limited to 'drivers/staging/dream/gpio_matrix.c')
-rw-r--r-- | drivers/staging/dream/gpio_matrix.c | 399 |
1 files changed, 0 insertions, 399 deletions
diff --git a/drivers/staging/dream/gpio_matrix.c b/drivers/staging/dream/gpio_matrix.c deleted file mode 100644 index b377ee1..0000000 --- a/drivers/staging/dream/gpio_matrix.c +++ /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; -} |