Linux Audio

Check our new training course

Loading...
v6.2
  1// SPDX-License-Identifier: GPL-2.0-or-later
  2/*
  3 * linux/drivers/input/keyboard/omap-keypad.c
  4 *
  5 * OMAP Keypad Driver
  6 *
  7 * Copyright (C) 2003 Nokia Corporation
  8 * Written by Timo Teräs <ext-timo.teras@nokia.com>
  9 *
 10 * Added support for H2 & H3 Keypad
 11 * Copyright (C) 2004 Texas Instruments
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 12 */
 13
 14#include <linux/module.h>
 
 15#include <linux/interrupt.h>
 16#include <linux/types.h>
 17#include <linux/input.h>
 18#include <linux/kernel.h>
 19#include <linux/delay.h>
 20#include <linux/platform_device.h>
 21#include <linux/mutex.h>
 22#include <linux/errno.h>
 23#include <linux/slab.h>
 24#include <linux/gpio.h>
 25#include <linux/platform_data/gpio-omap.h>
 26#include <linux/platform_data/keypad-omap.h>
 27#include <linux/soc/ti/omap1-io.h>
 
 
 
 28
 29#undef NEW_BOARD_LEARNING_MODE
 30
 31static void omap_kp_tasklet(unsigned long);
 32static void omap_kp_timer(struct timer_list *);
 33
 34static unsigned char keypad_state[8];
 35static DEFINE_MUTEX(kp_enable_mutex);
 36static int kp_enable = 1;
 37static int kp_cur_group = -1;
 38
 39struct omap_kp {
 40	struct input_dev *input;
 41	struct timer_list timer;
 42	int irq;
 43	unsigned int rows;
 44	unsigned int cols;
 45	unsigned long delay;
 46	unsigned int debounce;
 47	unsigned short keymap[];
 48};
 49
 50static DECLARE_TASKLET_DISABLED_OLD(kp_tasklet, omap_kp_tasklet);
 51
 52static unsigned int *row_gpios;
 53static unsigned int *col_gpios;
 54
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 55static irqreturn_t omap_kp_interrupt(int irq, void *dev_id)
 56{
 
 
 57	/* disable keyboard interrupt and schedule for handling */
 58	omap_writew(1, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 59
 60	tasklet_schedule(&kp_tasklet);
 61
 62	return IRQ_HANDLED;
 63}
 64
 65static void omap_kp_timer(struct timer_list *unused)
 66{
 67	tasklet_schedule(&kp_tasklet);
 68}
 69
 70static void omap_kp_scan_keypad(struct omap_kp *omap_kp, unsigned char *state)
 71{
 72	int col = 0;
 73
 74	/* disable keyboard interrupt and schedule for handling */
 75	omap_writew(1, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT);
 76
 77	/* read the keypad status */
 78	omap_writew(0xff, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBC);
 79	for (col = 0; col < omap_kp->cols; col++) {
 80		omap_writew(~(1 << col) & 0xff,
 81			    OMAP1_MPUIO_BASE + OMAP_MPUIO_KBC);
 
 
 
 82
 83		udelay(omap_kp->delay);
 
 
 84
 85		state[col] = ~omap_readw(OMAP1_MPUIO_BASE +
 86					 OMAP_MPUIO_KBR_LATCH) & 0xff;
 
 
 
 
 
 
 
 
 
 
 
 87	}
 88	omap_writew(0x00, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBC);
 89	udelay(2);
 90}
 91
 92static void omap_kp_tasklet(unsigned long data)
 93{
 94	struct omap_kp *omap_kp_data = (struct omap_kp *) data;
 95	unsigned short *keycodes = omap_kp_data->input->keycode;
 96	unsigned int row_shift = get_count_order(omap_kp_data->cols);
 97	unsigned char new_state[8], changed, key_down = 0;
 98	int col, row;
 
 99
100	/* check for any changes */
101	omap_kp_scan_keypad(omap_kp_data, new_state);
102
103	/* check for changes and print those */
104	for (col = 0; col < omap_kp_data->cols; col++) {
105		changed = new_state[col] ^ keypad_state[col];
106		key_down |= new_state[col];
107		if (changed == 0)
108			continue;
109
110		for (row = 0; row < omap_kp_data->rows; row++) {
111			int key;
112			if (!(changed & (1 << row)))
113				continue;
114#ifdef NEW_BOARD_LEARNING_MODE
115			printk(KERN_INFO "omap-keypad: key %d-%d %s\n", col,
116			       row, (new_state[col] & (1 << row)) ?
117			       "pressed" : "released");
118#else
119			key = keycodes[MATRIX_SCAN_CODE(row, col, row_shift)];
 
 
 
 
 
 
 
 
120
121			if (!(kp_cur_group == (key & GROUP_MASK) ||
122			      kp_cur_group == -1))
123				continue;
124
125			kp_cur_group = key & GROUP_MASK;
126			input_report_key(omap_kp_data->input, key & ~GROUP_MASK,
127					 new_state[col] & (1 << row));
128#endif
129		}
130	}
131	input_sync(omap_kp_data->input);
132	memcpy(keypad_state, new_state, sizeof(keypad_state));
133
134	if (key_down) {
 
135		/* some key is pressed - keep irq disabled and use timer
136		 * to poll the keypad */
137		mod_timer(&omap_kp_data->timer, jiffies + HZ / 20);
 
 
138	} else {
139		/* enable interrupts */
140		omap_writew(0, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT);
141		kp_cur_group = -1;
 
 
 
 
 
 
142	}
143}
144
145static ssize_t omap_kp_enable_show(struct device *dev,
146				   struct device_attribute *attr, char *buf)
147{
148	return sprintf(buf, "%u\n", kp_enable);
149}
150
151static ssize_t omap_kp_enable_store(struct device *dev, struct device_attribute *attr,
152				    const char *buf, size_t count)
153{
154	struct omap_kp *omap_kp = dev_get_drvdata(dev);
155	int state;
156
157	if (sscanf(buf, "%u", &state) != 1)
158		return -EINVAL;
159
160	if ((state != 1) && (state != 0))
161		return -EINVAL;
162
163	mutex_lock(&kp_enable_mutex);
164	if (state != kp_enable) {
165		if (state)
166			enable_irq(omap_kp->irq);
167		else
168			disable_irq(omap_kp->irq);
169		kp_enable = state;
170	}
171	mutex_unlock(&kp_enable_mutex);
172
173	return strnlen(buf, count);
174}
175
176static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR, omap_kp_enable_show, omap_kp_enable_store);
177
178static int omap_kp_probe(struct platform_device *pdev)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
179{
180	struct omap_kp *omap_kp;
181	struct input_dev *input_dev;
182	struct omap_kp_platform_data *pdata = dev_get_platdata(&pdev->dev);
183	int i, col_idx, row_idx, ret;
184	unsigned int row_shift, keycodemax;
185
186	if (!pdata->rows || !pdata->cols || !pdata->keymap_data) {
187		printk(KERN_ERR "No rows, cols or keymap_data from pdata\n");
188		return -EINVAL;
189	}
190
191	row_shift = get_count_order(pdata->cols);
192	keycodemax = pdata->rows << row_shift;
193
194	omap_kp = kzalloc(struct_size(omap_kp, keymap, keycodemax), GFP_KERNEL);
 
195	input_dev = input_allocate_device();
196	if (!omap_kp || !input_dev) {
197		kfree(omap_kp);
198		input_free_device(input_dev);
199		return -ENOMEM;
200	}
201
202	platform_set_drvdata(pdev, omap_kp);
203
204	omap_kp->input = input_dev;
205
206	/* Disable the interrupt for the MPUIO keyboard */
207	omap_writew(1, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT);
 
208
209	if (pdata->delay)
210		omap_kp->delay = pdata->delay;
211
212	if (pdata->row_gpios && pdata->col_gpios) {
213		row_gpios = pdata->row_gpios;
214		col_gpios = pdata->col_gpios;
215	}
216
217	omap_kp->rows = pdata->rows;
218	omap_kp->cols = pdata->cols;
219
220	col_idx = 0;
221	row_idx = 0;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
222
223	timer_setup(&omap_kp->timer, omap_kp_timer, 0);
224
225	/* get the irq and init timer*/
226	kp_tasklet.data = (unsigned long) omap_kp;
227	tasklet_enable(&kp_tasklet);
 
228
229	ret = device_create_file(&pdev->dev, &dev_attr_enable);
230	if (ret < 0)
231		goto err2;
232
233	/* setup input device */
234	input_dev->name = "omap-keypad";
235	input_dev->phys = "omap-keypad/input0";
236	input_dev->dev.parent = &pdev->dev;
237
238	input_dev->id.bustype = BUS_HOST;
239	input_dev->id.vendor = 0x0001;
240	input_dev->id.product = 0x0001;
241	input_dev->id.version = 0x0100;
242
243	if (pdata->rep)
244		__set_bit(EV_REP, input_dev->evbit);
245
246	ret = matrix_keypad_build_keymap(pdata->keymap_data, NULL,
247					 pdata->rows, pdata->cols,
248					 omap_kp->keymap, input_dev);
249	if (ret < 0)
250		goto err3;
251
252	ret = input_register_device(omap_kp->input);
253	if (ret < 0) {
254		printk(KERN_ERR "Unable to register omap-keypad input device\n");
255		goto err3;
256	}
257
258	if (pdata->dbounce)
259		omap_writew(0xff, OMAP1_MPUIO_BASE + OMAP_MPUIO_GPIO_DEBOUNCING);
260
261	/* scan current status and enable interrupt */
262	omap_kp_scan_keypad(omap_kp, keypad_state);
263	omap_kp->irq = platform_get_irq(pdev, 0);
264	if (omap_kp->irq >= 0) {
265		if (request_irq(omap_kp->irq, omap_kp_interrupt, 0,
266				"omap-keypad", omap_kp) < 0)
267			goto err4;
 
 
 
 
 
 
 
 
 
 
 
268	}
269	omap_writew(0, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT);
270
271	return 0;
272
 
 
273err4:
274	input_unregister_device(omap_kp->input);
275	input_dev = NULL;
276err3:
277	device_remove_file(&pdev->dev, &dev_attr_enable);
278err2:
279	for (i = row_idx - 1; i >= 0; i--)
280		gpio_free(row_gpios[i]);
281	for (i = col_idx - 1; i >= 0; i--)
 
282		gpio_free(col_gpios[i]);
283
284	kfree(omap_kp);
285	input_free_device(input_dev);
286
287	return -EINVAL;
288}
289
290static int omap_kp_remove(struct platform_device *pdev)
291{
292	struct omap_kp *omap_kp = platform_get_drvdata(pdev);
293
294	/* disable keypad interrupt handling */
295	tasklet_disable(&kp_tasklet);
296	omap_writew(1, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT);
297	free_irq(omap_kp->irq, omap_kp);
 
 
 
 
 
 
 
 
 
 
298
299	timer_shutdown_sync(&omap_kp->timer);
300	tasklet_kill(&kp_tasklet);
301
302	/* unregister everything */
303	input_unregister_device(omap_kp->input);
304
305	kfree(omap_kp);
306
307	return 0;
308}
309
310static struct platform_driver omap_kp_driver = {
311	.probe		= omap_kp_probe,
312	.remove		= omap_kp_remove,
 
 
313	.driver		= {
314		.name	= "omap-keypad",
 
315	},
316};
317module_platform_driver(omap_kp_driver);
318
319MODULE_AUTHOR("Timo Teräs");
320MODULE_DESCRIPTION("OMAP Keypad Driver");
321MODULE_LICENSE("GPL");
322MODULE_ALIAS("platform:omap-keypad");
v3.5.6
 
  1/*
  2 * linux/drivers/input/keyboard/omap-keypad.c
  3 *
  4 * OMAP Keypad Driver
  5 *
  6 * Copyright (C) 2003 Nokia Corporation
  7 * Written by Timo Teräs <ext-timo.teras@nokia.com>
  8 *
  9 * Added support for H2 & H3 Keypad
 10 * Copyright (C) 2004 Texas Instruments
 11 *
 12 * This program is free software; you can redistribute it and/or modify
 13 * it under the terms of the GNU General Public License as published by
 14 * the Free Software Foundation; either version 2 of the License, or
 15 * (at your option) any later version.
 16 *
 17 * This program is distributed in the hope that it will be useful,
 18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 20 * GNU General Public License for more details.
 21 *
 22 * You should have received a copy of the GNU General Public License
 23 * along with this program; if not, write to the Free Software
 24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 25 */
 26
 27#include <linux/module.h>
 28#include <linux/init.h>
 29#include <linux/interrupt.h>
 30#include <linux/types.h>
 31#include <linux/input.h>
 32#include <linux/kernel.h>
 33#include <linux/delay.h>
 34#include <linux/platform_device.h>
 35#include <linux/mutex.h>
 36#include <linux/errno.h>
 37#include <linux/slab.h>
 38#include <asm/gpio.h>
 39#include <plat/keypad.h>
 40#include <plat/menelaus.h>
 41#include <asm/irq.h>
 42#include <mach/hardware.h>
 43#include <asm/io.h>
 44#include <plat/mux.h>
 45
 46#undef NEW_BOARD_LEARNING_MODE
 47
 48static void omap_kp_tasklet(unsigned long);
 49static void omap_kp_timer(unsigned long);
 50
 51static unsigned char keypad_state[8];
 52static DEFINE_MUTEX(kp_enable_mutex);
 53static int kp_enable = 1;
 54static int kp_cur_group = -1;
 55
 56struct omap_kp {
 57	struct input_dev *input;
 58	struct timer_list timer;
 59	int irq;
 60	unsigned int rows;
 61	unsigned int cols;
 62	unsigned long delay;
 63	unsigned int debounce;
 64	unsigned short keymap[];
 65};
 66
 67static DECLARE_TASKLET_DISABLED(kp_tasklet, omap_kp_tasklet, 0);
 68
 69static unsigned int *row_gpios;
 70static unsigned int *col_gpios;
 71
 72#ifdef CONFIG_ARCH_OMAP2
 73static void set_col_gpio_val(struct omap_kp *omap_kp, u8 value)
 74{
 75	int col;
 76
 77	for (col = 0; col < omap_kp->cols; col++)
 78		gpio_set_value(col_gpios[col], value & (1 << col));
 79}
 80
 81static u8 get_row_gpio_val(struct omap_kp *omap_kp)
 82{
 83	int row;
 84	u8 value = 0;
 85
 86	for (row = 0; row < omap_kp->rows; row++) {
 87		if (gpio_get_value(row_gpios[row]))
 88			value |= (1 << row);
 89	}
 90	return value;
 91}
 92#else
 93#define		set_col_gpio_val(x, y)	do {} while (0)
 94#define		get_row_gpio_val(x)	0
 95#endif
 96
 97static irqreturn_t omap_kp_interrupt(int irq, void *dev_id)
 98{
 99	struct omap_kp *omap_kp = dev_id;
100
101	/* disable keyboard interrupt and schedule for handling */
102	if (cpu_is_omap24xx()) {
103		int i;
104
105		for (i = 0; i < omap_kp->rows; i++) {
106			int gpio_irq = gpio_to_irq(row_gpios[i]);
107			/*
108			 * The interrupt which we're currently handling should
109			 * be disabled _nosync() to avoid deadlocks waiting
110			 * for this handler to complete.  All others should
111			 * be disabled the regular way for SMP safety.
112			 */
113			if (gpio_irq == irq)
114				disable_irq_nosync(gpio_irq);
115			else
116				disable_irq(gpio_irq);
117		}
118	} else
119		/* disable keyboard interrupt and schedule for handling */
120		omap_writew(1, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT);
121
122	tasklet_schedule(&kp_tasklet);
123
124	return IRQ_HANDLED;
125}
126
127static void omap_kp_timer(unsigned long data)
128{
129	tasklet_schedule(&kp_tasklet);
130}
131
132static void omap_kp_scan_keypad(struct omap_kp *omap_kp, unsigned char *state)
133{
134	int col = 0;
135
 
 
 
136	/* read the keypad status */
137	if (cpu_is_omap24xx()) {
138		/* read the keypad status */
139		for (col = 0; col < omap_kp->cols; col++) {
140			set_col_gpio_val(omap_kp, ~(1 << col));
141			state[col] = ~(get_row_gpio_val(omap_kp)) & 0xff;
142		}
143		set_col_gpio_val(omap_kp, 0);
144
145	} else {
146		/* disable keyboard interrupt and schedule for handling */
147		omap_writew(1, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT);
148
149		/* read the keypad status */
150		omap_writew(0xff, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBC);
151		for (col = 0; col < omap_kp->cols; col++) {
152			omap_writew(~(1 << col) & 0xff,
153				    OMAP1_MPUIO_BASE + OMAP_MPUIO_KBC);
154
155			udelay(omap_kp->delay);
156
157			state[col] = ~omap_readw(OMAP1_MPUIO_BASE +
158						 OMAP_MPUIO_KBR_LATCH) & 0xff;
159		}
160		omap_writew(0x00, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBC);
161		udelay(2);
162	}
 
 
163}
164
165static void omap_kp_tasklet(unsigned long data)
166{
167	struct omap_kp *omap_kp_data = (struct omap_kp *) data;
168	unsigned short *keycodes = omap_kp_data->input->keycode;
169	unsigned int row_shift = get_count_order(omap_kp_data->cols);
170	unsigned char new_state[8], changed, key_down = 0;
171	int col, row;
172	int spurious = 0;
173
174	/* check for any changes */
175	omap_kp_scan_keypad(omap_kp_data, new_state);
176
177	/* check for changes and print those */
178	for (col = 0; col < omap_kp_data->cols; col++) {
179		changed = new_state[col] ^ keypad_state[col];
180		key_down |= new_state[col];
181		if (changed == 0)
182			continue;
183
184		for (row = 0; row < omap_kp_data->rows; row++) {
185			int key;
186			if (!(changed & (1 << row)))
187				continue;
188#ifdef NEW_BOARD_LEARNING_MODE
189			printk(KERN_INFO "omap-keypad: key %d-%d %s\n", col,
190			       row, (new_state[col] & (1 << row)) ?
191			       "pressed" : "released");
192#else
193			key = keycodes[MATRIX_SCAN_CODE(row, col, row_shift)];
194			if (key < 0) {
195				printk(KERN_WARNING
196				      "omap-keypad: Spurious key event %d-%d\n",
197				       col, row);
198				/* We scan again after a couple of seconds */
199				spurious = 1;
200				continue;
201			}
202
203			if (!(kp_cur_group == (key & GROUP_MASK) ||
204			      kp_cur_group == -1))
205				continue;
206
207			kp_cur_group = key & GROUP_MASK;
208			input_report_key(omap_kp_data->input, key & ~GROUP_MASK,
209					 new_state[col] & (1 << row));
210#endif
211		}
212	}
213	input_sync(omap_kp_data->input);
214	memcpy(keypad_state, new_state, sizeof(keypad_state));
215
216	if (key_down) {
217                int delay = HZ / 20;
218		/* some key is pressed - keep irq disabled and use timer
219		 * to poll the keypad */
220		if (spurious)
221			delay = 2 * HZ;
222		mod_timer(&omap_kp_data->timer, jiffies + delay);
223	} else {
224		/* enable interrupts */
225		if (cpu_is_omap24xx()) {
226			int i;
227			for (i = 0; i < omap_kp_data->rows; i++)
228				enable_irq(gpio_to_irq(row_gpios[i]));
229		} else {
230			omap_writew(0, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT);
231			kp_cur_group = -1;
232		}
233	}
234}
235
236static ssize_t omap_kp_enable_show(struct device *dev,
237				   struct device_attribute *attr, char *buf)
238{
239	return sprintf(buf, "%u\n", kp_enable);
240}
241
242static ssize_t omap_kp_enable_store(struct device *dev, struct device_attribute *attr,
243				    const char *buf, size_t count)
244{
 
245	int state;
246
247	if (sscanf(buf, "%u", &state) != 1)
248		return -EINVAL;
249
250	if ((state != 1) && (state != 0))
251		return -EINVAL;
252
253	mutex_lock(&kp_enable_mutex);
254	if (state != kp_enable) {
255		if (state)
256			enable_irq(INT_KEYBOARD);
257		else
258			disable_irq(INT_KEYBOARD);
259		kp_enable = state;
260	}
261	mutex_unlock(&kp_enable_mutex);
262
263	return strnlen(buf, count);
264}
265
266static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR, omap_kp_enable_show, omap_kp_enable_store);
267
268#ifdef CONFIG_PM
269static int omap_kp_suspend(struct platform_device *dev, pm_message_t state)
270{
271	/* Nothing yet */
272
273	return 0;
274}
275
276static int omap_kp_resume(struct platform_device *dev)
277{
278	/* Nothing yet */
279
280	return 0;
281}
282#else
283#define omap_kp_suspend	NULL
284#define omap_kp_resume	NULL
285#endif
286
287static int __devinit omap_kp_probe(struct platform_device *pdev)
288{
289	struct omap_kp *omap_kp;
290	struct input_dev *input_dev;
291	struct omap_kp_platform_data *pdata =  pdev->dev.platform_data;
292	int i, col_idx, row_idx, irq_idx, ret;
293	unsigned int row_shift, keycodemax;
294
295	if (!pdata->rows || !pdata->cols || !pdata->keymap_data) {
296		printk(KERN_ERR "No rows, cols or keymap_data from pdata\n");
297		return -EINVAL;
298	}
299
300	row_shift = get_count_order(pdata->cols);
301	keycodemax = pdata->rows << row_shift;
302
303	omap_kp = kzalloc(sizeof(struct omap_kp) +
304			keycodemax * sizeof(unsigned short), GFP_KERNEL);
305	input_dev = input_allocate_device();
306	if (!omap_kp || !input_dev) {
307		kfree(omap_kp);
308		input_free_device(input_dev);
309		return -ENOMEM;
310	}
311
312	platform_set_drvdata(pdev, omap_kp);
313
314	omap_kp->input = input_dev;
315
316	/* Disable the interrupt for the MPUIO keyboard */
317	if (!cpu_is_omap24xx())
318		omap_writew(1, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT);
319
320	if (pdata->delay)
321		omap_kp->delay = pdata->delay;
322
323	if (pdata->row_gpios && pdata->col_gpios) {
324		row_gpios = pdata->row_gpios;
325		col_gpios = pdata->col_gpios;
326	}
327
328	omap_kp->rows = pdata->rows;
329	omap_kp->cols = pdata->cols;
330
331	if (cpu_is_omap24xx()) {
332		/* Cols: outputs */
333		for (col_idx = 0; col_idx < omap_kp->cols; col_idx++) {
334			if (gpio_request(col_gpios[col_idx], "omap_kp_col") < 0) {
335				printk(KERN_ERR "Failed to request"
336				       "GPIO%d for keypad\n",
337				       col_gpios[col_idx]);
338				goto err1;
339			}
340			gpio_direction_output(col_gpios[col_idx], 0);
341		}
342		/* Rows: inputs */
343		for (row_idx = 0; row_idx < omap_kp->rows; row_idx++) {
344			if (gpio_request(row_gpios[row_idx], "omap_kp_row") < 0) {
345				printk(KERN_ERR "Failed to request"
346				       "GPIO%d for keypad\n",
347				       row_gpios[row_idx]);
348				goto err2;
349			}
350			gpio_direction_input(row_gpios[row_idx]);
351		}
352	} else {
353		col_idx = 0;
354		row_idx = 0;
355	}
356
357	setup_timer(&omap_kp->timer, omap_kp_timer, (unsigned long)omap_kp);
358
359	/* get the irq and init timer*/
 
360	tasklet_enable(&kp_tasklet);
361	kp_tasklet.data = (unsigned long) omap_kp;
362
363	ret = device_create_file(&pdev->dev, &dev_attr_enable);
364	if (ret < 0)
365		goto err2;
366
367	/* setup input device */
368	input_dev->name = "omap-keypad";
369	input_dev->phys = "omap-keypad/input0";
370	input_dev->dev.parent = &pdev->dev;
371
372	input_dev->id.bustype = BUS_HOST;
373	input_dev->id.vendor = 0x0001;
374	input_dev->id.product = 0x0001;
375	input_dev->id.version = 0x0100;
376
377	if (pdata->rep)
378		__set_bit(EV_REP, input_dev->evbit);
379
380	ret = matrix_keypad_build_keymap(pdata->keymap_data, NULL,
381					 pdata->rows, pdata->cols,
382					 omap_kp->keymap, input_dev);
383	if (ret < 0)
384		goto err3;
385
386	ret = input_register_device(omap_kp->input);
387	if (ret < 0) {
388		printk(KERN_ERR "Unable to register omap-keypad input device\n");
389		goto err3;
390	}
391
392	if (pdata->dbounce)
393		omap_writew(0xff, OMAP1_MPUIO_BASE + OMAP_MPUIO_GPIO_DEBOUNCING);
394
395	/* scan current status and enable interrupt */
396	omap_kp_scan_keypad(omap_kp, keypad_state);
397	if (!cpu_is_omap24xx()) {
398		omap_kp->irq = platform_get_irq(pdev, 0);
399		if (omap_kp->irq >= 0) {
400			if (request_irq(omap_kp->irq, omap_kp_interrupt, 0,
401					"omap-keypad", omap_kp) < 0)
402				goto err4;
403		}
404		omap_writew(0, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT);
405	} else {
406		for (irq_idx = 0; irq_idx < omap_kp->rows; irq_idx++) {
407			if (request_irq(gpio_to_irq(row_gpios[irq_idx]),
408					omap_kp_interrupt,
409					IRQF_TRIGGER_FALLING,
410					"omap-keypad", omap_kp) < 0)
411				goto err5;
412		}
413	}
 
 
414	return 0;
415err5:
416	for (i = irq_idx - 1; i >=0; i--)
417		free_irq(row_gpios[i], omap_kp);
418err4:
419	input_unregister_device(omap_kp->input);
420	input_dev = NULL;
421err3:
422	device_remove_file(&pdev->dev, &dev_attr_enable);
423err2:
424	for (i = row_idx - 1; i >=0; i--)
425		gpio_free(row_gpios[i]);
426err1:
427	for (i = col_idx - 1; i >=0; i--)
428		gpio_free(col_gpios[i]);
429
430	kfree(omap_kp);
431	input_free_device(input_dev);
432
433	return -EINVAL;
434}
435
436static int __devexit omap_kp_remove(struct platform_device *pdev)
437{
438	struct omap_kp *omap_kp = platform_get_drvdata(pdev);
439
440	/* disable keypad interrupt handling */
441	tasklet_disable(&kp_tasklet);
442	if (cpu_is_omap24xx()) {
443		int i;
444		for (i = 0; i < omap_kp->cols; i++)
445			gpio_free(col_gpios[i]);
446		for (i = 0; i < omap_kp->rows; i++) {
447			gpio_free(row_gpios[i]);
448			free_irq(gpio_to_irq(row_gpios[i]), omap_kp);
449		}
450	} else {
451		omap_writew(1, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT);
452		free_irq(omap_kp->irq, omap_kp);
453	}
454
455	del_timer_sync(&omap_kp->timer);
456	tasklet_kill(&kp_tasklet);
457
458	/* unregister everything */
459	input_unregister_device(omap_kp->input);
460
461	kfree(omap_kp);
462
463	return 0;
464}
465
466static struct platform_driver omap_kp_driver = {
467	.probe		= omap_kp_probe,
468	.remove		= __devexit_p(omap_kp_remove),
469	.suspend	= omap_kp_suspend,
470	.resume		= omap_kp_resume,
471	.driver		= {
472		.name	= "omap-keypad",
473		.owner	= THIS_MODULE,
474	},
475};
476module_platform_driver(omap_kp_driver);
477
478MODULE_AUTHOR("Timo Teräs");
479MODULE_DESCRIPTION("OMAP Keypad Driver");
480MODULE_LICENSE("GPL");
481MODULE_ALIAS("platform:omap-keypad");