1811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg/* drivers/input/misc/gpio_matrix.c 2811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg * 3811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg * Copyright (C) 2007 Google, Inc. 4811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg * 5811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg * This software is licensed under the terms of the GNU General Public 6811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg * License version 2, as published by the Free Software Foundation, and 7811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg * may be copied, distributed, and modified under those terms. 8811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg * 9811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg * This program is distributed in the hope that it will be useful, 10811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg * but WITHOUT ANY WARRANTY; without even the implied warranty of 11811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg * GNU General Public License for more details. 13811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg * 14811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg */ 15811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg 16811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg#include <linux/kernel.h> 17811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg#include <linux/gpio.h> 18811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg#include <linux/gpio_event.h> 19811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg#include <linux/hrtimer.h> 20811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg#include <linux/interrupt.h> 21811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg#include <linux/slab.h> 22811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg#include <linux/wakelock.h> 23811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg 24811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevågstruct gpio_kp { 25811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg struct gpio_event_input_devs *input_devs; 26811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg struct gpio_event_matrix_info *keypad_info; 27811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg struct hrtimer timer; 28811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg struct wake_lock wake_lock; 29811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg int current_output; 30811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg unsigned int use_irq:1; 31811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg unsigned int key_state_changed:1; 32811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg unsigned int last_key_state_changed:1; 33811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg unsigned int some_keys_pressed:2; 34811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg unsigned int disabled_irq:1; 35811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg unsigned long keys_pressed[0]; 36811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg}; 37811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg 38811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevågstatic void clear_phantom_key(struct gpio_kp *kp, int out, int in) 39811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg{ 40811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg struct gpio_event_matrix_info *mi = kp->keypad_info; 41811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg int key_index = out * mi->ninputs + in; 42811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg unsigned short keyentry = mi->keymap[key_index]; 43811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg unsigned short keycode = keyentry & MATRIX_KEY_MASK; 44811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg unsigned short dev = keyentry >> MATRIX_CODE_BITS; 45811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg 46811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg if (!test_bit(keycode, kp->input_devs->dev[dev]->key)) { 47811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg if (mi->flags & GPIOKPF_PRINT_PHANTOM_KEYS) 48811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg pr_info("gpiomatrix: phantom key %x, %d-%d (%d-%d) " 49811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg "cleared\n", keycode, out, in, 50811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg mi->output_gpios[out], mi->input_gpios[in]); 51811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg __clear_bit(key_index, kp->keys_pressed); 52811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg } else { 53811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg if (mi->flags & GPIOKPF_PRINT_PHANTOM_KEYS) 54811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg pr_info("gpiomatrix: phantom key %x, %d-%d (%d-%d) " 55811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg "not cleared\n", keycode, out, in, 56811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg mi->output_gpios[out], mi->input_gpios[in]); 57811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg } 58811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg} 59811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg 60811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevågstatic int restore_keys_for_input(struct gpio_kp *kp, int out, int in) 61811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg{ 62811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg int rv = 0; 63811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg int key_index; 64811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg 65811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg key_index = out * kp->keypad_info->ninputs + in; 66811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg while (out < kp->keypad_info->noutputs) { 67811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg if (test_bit(key_index, kp->keys_pressed)) { 68811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg rv = 1; 69811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg clear_phantom_key(kp, out, in); 70811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg } 71811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg key_index += kp->keypad_info->ninputs; 72811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg out++; 73811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg } 74811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg return rv; 75811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg} 76811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg 77811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevågstatic void remove_phantom_keys(struct gpio_kp *kp) 78811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg{ 79811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg int out, in, inp; 80811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg int key_index; 81811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg 82811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg if (kp->some_keys_pressed < 3) 83811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg return; 84811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg 85811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg for (out = 0; out < kp->keypad_info->noutputs; out++) { 86811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg inp = -1; 87811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg key_index = out * kp->keypad_info->ninputs; 88811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg for (in = 0; in < kp->keypad_info->ninputs; in++, key_index++) { 89811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg if (test_bit(key_index, kp->keys_pressed)) { 90811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg if (inp == -1) { 91811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg inp = in; 92811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg continue; 93811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg } 94811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg if (inp >= 0) { 95811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg if (!restore_keys_for_input(kp, out + 1, 96811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg inp)) 97811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg break; 98811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg clear_phantom_key(kp, out, inp); 99811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg inp = -2; 100811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg } 101811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg restore_keys_for_input(kp, out, in); 102811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg } 103811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg } 104811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg } 105811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg} 106811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg 107811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevågstatic void report_key(struct gpio_kp *kp, int key_index, int out, int in) 108811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg{ 109811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg struct gpio_event_matrix_info *mi = kp->keypad_info; 110811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg int pressed = test_bit(key_index, kp->keys_pressed); 111811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg unsigned short keyentry = mi->keymap[key_index]; 112811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg unsigned short keycode = keyentry & MATRIX_KEY_MASK; 113811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg unsigned short dev = keyentry >> MATRIX_CODE_BITS; 114811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg 115811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg if (pressed != test_bit(keycode, kp->input_devs->dev[dev]->key)) { 116811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg if (keycode == KEY_RESERVED) { 117811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg if (mi->flags & GPIOKPF_PRINT_UNMAPPED_KEYS) 118811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg pr_info("gpiomatrix: unmapped key, %d-%d " 119811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg "(%d-%d) changed to %d\n", 120811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg out, in, mi->output_gpios[out], 121811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg mi->input_gpios[in], pressed); 122811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg } else { 123811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg if (mi->flags & GPIOKPF_PRINT_MAPPED_KEYS) 124811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg pr_info("gpiomatrix: key %x, %d-%d (%d-%d) " 125811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg "changed to %d\n", keycode, 126811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg out, in, mi->output_gpios[out], 127811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg mi->input_gpios[in], pressed); 128811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg input_report_key(kp->input_devs->dev[dev], keycode, pressed); 129811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg } 130811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg } 131811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg} 132811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg 133811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevågstatic void report_sync(struct gpio_kp *kp) 134811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg{ 135811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg int i; 136811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg 137811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg for (i = 0; i < kp->input_devs->count; i++) 138811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg input_sync(kp->input_devs->dev[i]); 139811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg} 140811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg 141811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevågstatic enum hrtimer_restart gpio_keypad_timer_func(struct hrtimer *timer) 142811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg{ 143811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg int out, in; 144811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg int key_index; 145811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg int gpio; 146811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg struct gpio_kp *kp = container_of(timer, struct gpio_kp, timer); 147811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg struct gpio_event_matrix_info *mi = kp->keypad_info; 148811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg unsigned gpio_keypad_flags = mi->flags; 149811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg unsigned polarity = !!(gpio_keypad_flags & GPIOKPF_ACTIVE_HIGH); 150811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg 151811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg out = kp->current_output; 152811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg if (out == mi->noutputs) { 153811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg out = 0; 154811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg kp->last_key_state_changed = kp->key_state_changed; 155811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg kp->key_state_changed = 0; 156811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg kp->some_keys_pressed = 0; 157811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg } else { 158811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg key_index = out * mi->ninputs; 159811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg for (in = 0; in < mi->ninputs; in++, key_index++) { 160811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg gpio = mi->input_gpios[in]; 161811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg if (gpio_get_value(gpio) ^ !polarity) { 162811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg if (kp->some_keys_pressed < 3) 163811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg kp->some_keys_pressed++; 164811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg kp->key_state_changed |= !__test_and_set_bit( 165811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg key_index, kp->keys_pressed); 166811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg } else 167811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg kp->key_state_changed |= __test_and_clear_bit( 168811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg key_index, kp->keys_pressed); 169811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg } 170811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg gpio = mi->output_gpios[out]; 171811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg if (gpio_keypad_flags & GPIOKPF_DRIVE_INACTIVE) 172811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg gpio_set_value(gpio, !polarity); 173811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg else 174811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg gpio_direction_input(gpio); 175811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg out++; 176811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg } 177811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg kp->current_output = out; 178811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg if (out < mi->noutputs) { 179811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg gpio = mi->output_gpios[out]; 180811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg if (gpio_keypad_flags & GPIOKPF_DRIVE_INACTIVE) 181811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg gpio_set_value(gpio, polarity); 182811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg else 183811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg gpio_direction_output(gpio, polarity); 184811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg hrtimer_start(timer, mi->settle_time, HRTIMER_MODE_REL); 185811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg return HRTIMER_NORESTART; 186811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg } 187811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg if (gpio_keypad_flags & GPIOKPF_DEBOUNCE) { 188811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg if (kp->key_state_changed) { 189811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg hrtimer_start(&kp->timer, mi->debounce_delay, 190811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg HRTIMER_MODE_REL); 191811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg return HRTIMER_NORESTART; 192811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg } 193811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg kp->key_state_changed = kp->last_key_state_changed; 194811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg } 195811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg if (kp->key_state_changed) { 196811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg if (gpio_keypad_flags & GPIOKPF_REMOVE_SOME_PHANTOM_KEYS) 197811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg remove_phantom_keys(kp); 198811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg key_index = 0; 199811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg for (out = 0; out < mi->noutputs; out++) 200811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg for (in = 0; in < mi->ninputs; in++, key_index++) 201811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg report_key(kp, key_index, out, in); 202811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg report_sync(kp); 203811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg } 204811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg if (!kp->use_irq || kp->some_keys_pressed) { 205811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg hrtimer_start(timer, mi->poll_time, HRTIMER_MODE_REL); 206811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg return HRTIMER_NORESTART; 207811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg } 208811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg 209811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg /* No keys are pressed, reenable interrupt */ 210811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg for (out = 0; out < mi->noutputs; out++) { 211811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg if (gpio_keypad_flags & GPIOKPF_DRIVE_INACTIVE) 212811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg gpio_set_value(mi->output_gpios[out], polarity); 213811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg else 214811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg gpio_direction_output(mi->output_gpios[out], polarity); 215811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg } 216811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg for (in = 0; in < mi->ninputs; in++) 217811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg enable_irq(gpio_to_irq(mi->input_gpios[in])); 218811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg wake_unlock(&kp->wake_lock); 219811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg return HRTIMER_NORESTART; 220811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg} 221811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg 222811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevågstatic irqreturn_t gpio_keypad_irq_handler(int irq_in, void *dev_id) 223811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg{ 224811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg int i; 225811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg struct gpio_kp *kp = dev_id; 226811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg struct gpio_event_matrix_info *mi = kp->keypad_info; 227811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg unsigned gpio_keypad_flags = mi->flags; 228811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg 229811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg if (!kp->use_irq) { 230811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg /* ignore interrupt while registering the handler */ 231811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg kp->disabled_irq = 1; 232811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg disable_irq_nosync(irq_in); 233811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg return IRQ_HANDLED; 234811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg } 235811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg 236811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg for (i = 0; i < mi->ninputs; i++) 237811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg disable_irq_nosync(gpio_to_irq(mi->input_gpios[i])); 238811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg for (i = 0; i < mi->noutputs; i++) { 239811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg if (gpio_keypad_flags & GPIOKPF_DRIVE_INACTIVE) 240811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg gpio_set_value(mi->output_gpios[i], 241811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg !(gpio_keypad_flags & GPIOKPF_ACTIVE_HIGH)); 242811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg else 243811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg gpio_direction_input(mi->output_gpios[i]); 244811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg } 245811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg wake_lock(&kp->wake_lock); 246811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg hrtimer_start(&kp->timer, ktime_set(0, 0), HRTIMER_MODE_REL); 247811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg return IRQ_HANDLED; 248811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg} 249811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg 250811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevågstatic int gpio_keypad_request_irqs(struct gpio_kp *kp) 251811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg{ 252811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg int i; 253811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg int err; 254811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg unsigned int irq; 255811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg unsigned long request_flags; 256811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg struct gpio_event_matrix_info *mi = kp->keypad_info; 257811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg 258811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg switch (mi->flags & (GPIOKPF_ACTIVE_HIGH|GPIOKPF_LEVEL_TRIGGERED_IRQ)) { 259811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg default: 260811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg request_flags = IRQF_TRIGGER_FALLING; 261811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg break; 262811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg case GPIOKPF_ACTIVE_HIGH: 263811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg request_flags = IRQF_TRIGGER_RISING; 264811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg break; 265811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg case GPIOKPF_LEVEL_TRIGGERED_IRQ: 266811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg request_flags = IRQF_TRIGGER_LOW; 267811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg break; 268811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg case GPIOKPF_LEVEL_TRIGGERED_IRQ | GPIOKPF_ACTIVE_HIGH: 269811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg request_flags = IRQF_TRIGGER_HIGH; 270811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg break; 271811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg } 272811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg 273811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg for (i = 0; i < mi->ninputs; i++) { 274811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg err = irq = gpio_to_irq(mi->input_gpios[i]); 275811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg if (err < 0) 276811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg goto err_gpio_get_irq_num_failed; 277811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg err = request_irq(irq, gpio_keypad_irq_handler, request_flags, 278811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg "gpio_kp", kp); 279811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg if (err) { 280811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg pr_err("gpiomatrix: request_irq failed for input %d, " 281811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg "irq %d\n", mi->input_gpios[i], irq); 282811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg goto err_request_irq_failed; 283811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg } 284811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg err = enable_irq_wake(irq); 285811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg if (err) { 286811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg pr_err("gpiomatrix: set_irq_wake failed for input %d, " 287811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg "irq %d\n", mi->input_gpios[i], irq); 288811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg } 289811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg disable_irq(irq); 290811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg if (kp->disabled_irq) { 291811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg kp->disabled_irq = 0; 292811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg enable_irq(irq); 293811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg } 294811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg } 295811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg return 0; 296811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg 297811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg for (i = mi->noutputs - 1; i >= 0; i--) { 298811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg free_irq(gpio_to_irq(mi->input_gpios[i]), kp); 299811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevågerr_request_irq_failed: 300811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevågerr_gpio_get_irq_num_failed: 301811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg ; 302811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg } 303811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg return err; 304811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg} 305811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg 306811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevågint gpio_event_matrix_func(struct gpio_event_input_devs *input_devs, 307811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg struct gpio_event_info *info, void **data, int func) 308811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg{ 309811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg int i; 310811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg int err; 311811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg int key_count; 312811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg struct gpio_kp *kp; 313811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg struct gpio_event_matrix_info *mi; 314811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg 315811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg mi = container_of(info, struct gpio_event_matrix_info, info); 316811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg if (func == GPIO_EVENT_FUNC_SUSPEND || func == GPIO_EVENT_FUNC_RESUME) { 317811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg /* TODO: disable scanning */ 318811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg return 0; 319811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg } 320811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg 321811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg if (func == GPIO_EVENT_FUNC_INIT) { 322811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg if (mi->keymap == NULL || 323811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg mi->input_gpios == NULL || 324811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg mi->output_gpios == NULL) { 325811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg err = -ENODEV; 326811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg pr_err("gpiomatrix: Incomplete pdata\n"); 327811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg goto err_invalid_platform_data; 328811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg } 329811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg key_count = mi->ninputs * mi->noutputs; 330811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg 331811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg *data = kp = kzalloc(sizeof(*kp) + sizeof(kp->keys_pressed[0]) * 332811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg BITS_TO_LONGS(key_count), GFP_KERNEL); 333811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg if (kp == NULL) { 334811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg err = -ENOMEM; 335811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg pr_err("gpiomatrix: Failed to allocate private data\n"); 336811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg goto err_kp_alloc_failed; 337811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg } 338811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg kp->input_devs = input_devs; 339811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg kp->keypad_info = mi; 340811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg for (i = 0; i < key_count; i++) { 341811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg unsigned short keyentry = mi->keymap[i]; 342811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg unsigned short keycode = keyentry & MATRIX_KEY_MASK; 343811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg unsigned short dev = keyentry >> MATRIX_CODE_BITS; 344811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg if (dev >= input_devs->count) { 345811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg pr_err("gpiomatrix: bad device index %d >= " 346811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg "%d for key code %d\n", 347811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg dev, input_devs->count, keycode); 348811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg err = -EINVAL; 349811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg goto err_bad_keymap; 350811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg } 351811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg if (keycode && keycode <= KEY_MAX) 352811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg input_set_capability(input_devs->dev[dev], 353811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg EV_KEY, keycode); 354811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg } 355811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg 356811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg for (i = 0; i < mi->noutputs; i++) { 357811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg err = gpio_request(mi->output_gpios[i], "gpio_kp_out"); 358811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg if (err) { 359811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg pr_err("gpiomatrix: gpio_request failed for " 360811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg "output %d\n", mi->output_gpios[i]); 361811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg goto err_request_output_gpio_failed; 362811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg } 363811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg if (gpio_cansleep(mi->output_gpios[i])) { 364811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg pr_err("gpiomatrix: unsupported output gpio %d," 365811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg " can sleep\n", mi->output_gpios[i]); 366811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg err = -EINVAL; 367811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg goto err_output_gpio_configure_failed; 368811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg } 369811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg if (mi->flags & GPIOKPF_DRIVE_INACTIVE) 370811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg err = gpio_direction_output(mi->output_gpios[i], 371811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg !(mi->flags & GPIOKPF_ACTIVE_HIGH)); 372811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg else 373811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg err = gpio_direction_input(mi->output_gpios[i]); 374811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg if (err) { 375811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg pr_err("gpiomatrix: gpio_configure failed for " 376811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg "output %d\n", mi->output_gpios[i]); 377811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg goto err_output_gpio_configure_failed; 378811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg } 379811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg } 380811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg for (i = 0; i < mi->ninputs; i++) { 381811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg err = gpio_request(mi->input_gpios[i], "gpio_kp_in"); 382811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg if (err) { 383811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg pr_err("gpiomatrix: gpio_request failed for " 384811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg "input %d\n", mi->input_gpios[i]); 385811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg goto err_request_input_gpio_failed; 386811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg } 387811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg err = gpio_direction_input(mi->input_gpios[i]); 388811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg if (err) { 389811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg pr_err("gpiomatrix: gpio_direction_input failed" 390811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg " for input %d\n", mi->input_gpios[i]); 391811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg goto err_gpio_direction_input_failed; 392811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg } 393811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg } 394811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg kp->current_output = mi->noutputs; 395811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg kp->key_state_changed = 1; 396811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg 397811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg hrtimer_init(&kp->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); 398811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg kp->timer.function = gpio_keypad_timer_func; 399811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg wake_lock_init(&kp->wake_lock, WAKE_LOCK_SUSPEND, "gpio_kp"); 400811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg err = gpio_keypad_request_irqs(kp); 401811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg kp->use_irq = err == 0; 402811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg 403811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg pr_info("GPIO Matrix Keypad Driver: Start keypad matrix for " 404811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg "%s%s in %s mode\n", input_devs->dev[0]->name, 405811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg (input_devs->count > 1) ? "..." : "", 406811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg kp->use_irq ? "interrupt" : "polling"); 407811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg 408811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg if (kp->use_irq) 409811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg wake_lock(&kp->wake_lock); 410811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg hrtimer_start(&kp->timer, ktime_set(0, 0), HRTIMER_MODE_REL); 411811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg 412811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg return 0; 413811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg } 414811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg 415811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg err = 0; 416811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg kp = *data; 417811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg 418811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg if (kp->use_irq) 419811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg for (i = mi->noutputs - 1; i >= 0; i--) 420811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg free_irq(gpio_to_irq(mi->input_gpios[i]), kp); 421811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg 422811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg hrtimer_cancel(&kp->timer); 423811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg wake_lock_destroy(&kp->wake_lock); 424811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg for (i = mi->noutputs - 1; i >= 0; i--) { 425811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevågerr_gpio_direction_input_failed: 426811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg gpio_free(mi->input_gpios[i]); 427811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevågerr_request_input_gpio_failed: 428811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg ; 429811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg } 430811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg for (i = mi->noutputs - 1; i >= 0; i--) { 431811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevågerr_output_gpio_configure_failed: 432811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg gpio_free(mi->output_gpios[i]); 433811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevågerr_request_output_gpio_failed: 434811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg ; 435811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg } 436811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevågerr_bad_keymap: 437811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg kfree(kp); 438811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevågerr_kp_alloc_failed: 439811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevågerr_invalid_platform_data: 440811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg return err; 441811868bc53546a6046d847c863739fbd6b39514bArve Hjønnevåg} 442