Linux Audio

Check our new training course

Loading...
v3.1
  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 <mach/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};
 65
 66static DECLARE_TASKLET_DISABLED(kp_tasklet, omap_kp_tasklet, 0);
 67
 68static unsigned int *row_gpios;
 69static unsigned int *col_gpios;
 70
 71#ifdef CONFIG_ARCH_OMAP2
 72static void set_col_gpio_val(struct omap_kp *omap_kp, u8 value)
 73{
 74	int col;
 75
 76	for (col = 0; col < omap_kp->cols; col++)
 77		gpio_set_value(col_gpios[col], value & (1 << col));
 78}
 79
 80static u8 get_row_gpio_val(struct omap_kp *omap_kp)
 81{
 82	int row;
 83	u8 value = 0;
 84
 85	for (row = 0; row < omap_kp->rows; row++) {
 86		if (gpio_get_value(row_gpios[row]))
 87			value |= (1 << row);
 88	}
 89	return value;
 90}
 91#else
 92#define		set_col_gpio_val(x, y)	do {} while (0)
 93#define		get_row_gpio_val(x)	0
 94#endif
 95
 96static irqreturn_t omap_kp_interrupt(int irq, void *dev_id)
 97{
 98	struct omap_kp *omap_kp = dev_id;
 99
100	/* disable keyboard interrupt and schedule for handling */
101	if (cpu_is_omap24xx()) {
102		int i;
103
104		for (i = 0; i < omap_kp->rows; i++) {
105			int gpio_irq = gpio_to_irq(row_gpios[i]);
106			/*
107			 * The interrupt which we're currently handling should
108			 * be disabled _nosync() to avoid deadlocks waiting
109			 * for this handler to complete.  All others should
110			 * be disabled the regular way for SMP safety.
111			 */
112			if (gpio_irq == irq)
113				disable_irq_nosync(gpio_irq);
114			else
115				disable_irq(gpio_irq);
116		}
117	} else
118		/* disable keyboard interrupt and schedule for handling */
119		omap_writew(1, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT);
120
121	tasklet_schedule(&kp_tasklet);
122
123	return IRQ_HANDLED;
124}
125
126static void omap_kp_timer(unsigned long data)
127{
128	tasklet_schedule(&kp_tasklet);
129}
130
131static void omap_kp_scan_keypad(struct omap_kp *omap_kp, unsigned char *state)
132{
133	int col = 0;
134
135	/* read the keypad status */
136	if (cpu_is_omap24xx()) {
137		/* read the keypad status */
138		for (col = 0; col < omap_kp->cols; col++) {
139			set_col_gpio_val(omap_kp, ~(1 << col));
140			state[col] = ~(get_row_gpio_val(omap_kp)) & 0xff;
141		}
142		set_col_gpio_val(omap_kp, 0);
143
144	} else {
145		/* disable keyboard interrupt and schedule for handling */
146		omap_writew(1, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT);
147
148		/* read the keypad status */
149		omap_writew(0xff, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBC);
150		for (col = 0; col < omap_kp->cols; col++) {
151			omap_writew(~(1 << col) & 0xff,
152				    OMAP1_MPUIO_BASE + OMAP_MPUIO_KBC);
153
154			udelay(omap_kp->delay);
155
156			state[col] = ~omap_readw(OMAP1_MPUIO_BASE +
157						 OMAP_MPUIO_KBR_LATCH) & 0xff;
158		}
159		omap_writew(0x00, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBC);
160		udelay(2);
161	}
162}
163
164static void omap_kp_tasklet(unsigned long data)
165{
166	struct omap_kp *omap_kp_data = (struct omap_kp *) data;
167	unsigned short *keycodes = omap_kp_data->input->keycode;
168	unsigned int row_shift = get_count_order(omap_kp_data->cols);
169	unsigned char new_state[8], changed, key_down = 0;
170	int col, row;
171	int spurious = 0;
172
173	/* check for any changes */
174	omap_kp_scan_keypad(omap_kp_data, new_state);
175
176	/* check for changes and print those */
177	for (col = 0; col < omap_kp_data->cols; col++) {
178		changed = new_state[col] ^ keypad_state[col];
179		key_down |= new_state[col];
180		if (changed == 0)
181			continue;
182
183		for (row = 0; row < omap_kp_data->rows; row++) {
184			int key;
185			if (!(changed & (1 << row)))
186				continue;
187#ifdef NEW_BOARD_LEARNING_MODE
188			printk(KERN_INFO "omap-keypad: key %d-%d %s\n", col,
189			       row, (new_state[col] & (1 << row)) ?
190			       "pressed" : "released");
191#else
192			key = keycodes[MATRIX_SCAN_CODE(row, col, row_shift)];
193			if (key < 0) {
194				printk(KERN_WARNING
195				      "omap-keypad: Spurious key event %d-%d\n",
196				       col, row);
197				/* We scan again after a couple of seconds */
198				spurious = 1;
199				continue;
200			}
201
202			if (!(kp_cur_group == (key & GROUP_MASK) ||
203			      kp_cur_group == -1))
204				continue;
205
206			kp_cur_group = key & GROUP_MASK;
207			input_report_key(omap_kp_data->input, key & ~GROUP_MASK,
208					 new_state[col] & (1 << row));
209#endif
210		}
211	}
212	input_sync(omap_kp_data->input);
213	memcpy(keypad_state, new_state, sizeof(keypad_state));
214
215	if (key_down) {
216                int delay = HZ / 20;
217		/* some key is pressed - keep irq disabled and use timer
218		 * to poll the keypad */
219		if (spurious)
220			delay = 2 * HZ;
221		mod_timer(&omap_kp_data->timer, jiffies + delay);
222	} else {
223		/* enable interrupts */
224		if (cpu_is_omap24xx()) {
225			int i;
226			for (i = 0; i < omap_kp_data->rows; i++)
227				enable_irq(gpio_to_irq(row_gpios[i]));
228		} else {
229			omap_writew(0, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT);
230			kp_cur_group = -1;
231		}
232	}
233}
234
235static ssize_t omap_kp_enable_show(struct device *dev,
236				   struct device_attribute *attr, char *buf)
237{
238	return sprintf(buf, "%u\n", kp_enable);
239}
240
241static ssize_t omap_kp_enable_store(struct device *dev, struct device_attribute *attr,
242				    const char *buf, size_t count)
243{
244	int state;
245
246	if (sscanf(buf, "%u", &state) != 1)
247		return -EINVAL;
248
249	if ((state != 1) && (state != 0))
250		return -EINVAL;
251
252	mutex_lock(&kp_enable_mutex);
253	if (state != kp_enable) {
254		if (state)
255			enable_irq(INT_KEYBOARD);
256		else
257			disable_irq(INT_KEYBOARD);
258		kp_enable = state;
259	}
260	mutex_unlock(&kp_enable_mutex);
261
262	return strnlen(buf, count);
263}
264
265static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR, omap_kp_enable_show, omap_kp_enable_store);
266
267#ifdef CONFIG_PM
268static int omap_kp_suspend(struct platform_device *dev, pm_message_t state)
269{
270	/* Nothing yet */
271
272	return 0;
273}
274
275static int omap_kp_resume(struct platform_device *dev)
276{
277	/* Nothing yet */
278
279	return 0;
280}
281#else
282#define omap_kp_suspend	NULL
283#define omap_kp_resume	NULL
284#endif
285
286static int __devinit omap_kp_probe(struct platform_device *pdev)
287{
288	struct omap_kp *omap_kp;
289	struct input_dev *input_dev;
290	struct omap_kp_platform_data *pdata =  pdev->dev.platform_data;
291	int i, col_idx, row_idx, irq_idx, ret;
292	unsigned int row_shift, keycodemax;
293
294	if (!pdata->rows || !pdata->cols || !pdata->keymap_data) {
295		printk(KERN_ERR "No rows, cols or keymap_data from pdata\n");
296		return -EINVAL;
297	}
298
299	row_shift = get_count_order(pdata->cols);
300	keycodemax = pdata->rows << row_shift;
301
302	omap_kp = kzalloc(sizeof(struct omap_kp) +
303			keycodemax * sizeof(unsigned short), GFP_KERNEL);
304	input_dev = input_allocate_device();
305	if (!omap_kp || !input_dev) {
306		kfree(omap_kp);
307		input_free_device(input_dev);
308		return -ENOMEM;
309	}
310
311	platform_set_drvdata(pdev, omap_kp);
312
313	omap_kp->input = input_dev;
314
315	/* Disable the interrupt for the MPUIO keyboard */
316	if (!cpu_is_omap24xx())
317		omap_writew(1, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT);
318
319	input_dev->keycode      = &omap_kp[1];
320	input_dev->keycodesize  = sizeof(unsigned short);
321	input_dev->keycodemax   = keycodemax;
322
323	if (pdata->rep)
324		__set_bit(EV_REP, input_dev->evbit);
325
326	if (pdata->delay)
327		omap_kp->delay = pdata->delay;
328
329	if (pdata->row_gpios && pdata->col_gpios) {
330		row_gpios = pdata->row_gpios;
331		col_gpios = pdata->col_gpios;
332	}
333
334	omap_kp->rows = pdata->rows;
335	omap_kp->cols = pdata->cols;
336
337	if (cpu_is_omap24xx()) {
338		/* Cols: outputs */
339		for (col_idx = 0; col_idx < omap_kp->cols; col_idx++) {
340			if (gpio_request(col_gpios[col_idx], "omap_kp_col") < 0) {
341				printk(KERN_ERR "Failed to request"
342				       "GPIO%d for keypad\n",
343				       col_gpios[col_idx]);
344				goto err1;
345			}
346			gpio_direction_output(col_gpios[col_idx], 0);
347		}
348		/* Rows: inputs */
349		for (row_idx = 0; row_idx < omap_kp->rows; row_idx++) {
350			if (gpio_request(row_gpios[row_idx], "omap_kp_row") < 0) {
351				printk(KERN_ERR "Failed to request"
352				       "GPIO%d for keypad\n",
353				       row_gpios[row_idx]);
354				goto err2;
355			}
356			gpio_direction_input(row_gpios[row_idx]);
357		}
358	} else {
359		col_idx = 0;
360		row_idx = 0;
361	}
362
363	setup_timer(&omap_kp->timer, omap_kp_timer, (unsigned long)omap_kp);
364
365	/* get the irq and init timer*/
366	tasklet_enable(&kp_tasklet);
367	kp_tasklet.data = (unsigned long) omap_kp;
368
369	ret = device_create_file(&pdev->dev, &dev_attr_enable);
370	if (ret < 0)
371		goto err2;
372
373	/* setup input device */
374	__set_bit(EV_KEY, input_dev->evbit);
375	matrix_keypad_build_keymap(pdata->keymap_data, row_shift,
376			input_dev->keycode, input_dev->keybit);
377	input_dev->name = "omap-keypad";
378	input_dev->phys = "omap-keypad/input0";
379	input_dev->dev.parent = &pdev->dev;
380
381	input_dev->id.bustype = BUS_HOST;
382	input_dev->id.vendor = 0x0001;
383	input_dev->id.product = 0x0001;
384	input_dev->id.version = 0x0100;
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};
476
477static int __init omap_kp_init(void)
478{
479	printk(KERN_INFO "OMAP Keypad Driver\n");
480	return platform_driver_register(&omap_kp_driver);
481}
482
483static void __exit omap_kp_exit(void)
484{
485	platform_driver_unregister(&omap_kp_driver);
486}
487
488module_init(omap_kp_init);
489module_exit(omap_kp_exit);
490
491MODULE_AUTHOR("Timo Teräs");
492MODULE_DESCRIPTION("OMAP Keypad Driver");
493MODULE_LICENSE("GPL");
494MODULE_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");