2006-11-24 00:42:50 -05:00
/*
* Keyboard driver for the AAED - 2000 dev board
*
* Copyright ( c ) 2006 Nicolas Bellido Y Ortega
*
* Based on corgikbd . c
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation .
*
*/
# include <linux/delay.h>
# include <linux/platform_device.h>
# include <linux/init.h>
2007-05-03 01:02:07 -04:00
# include <linux/input-polldev.h>
2006-11-24 00:42:50 -05:00
# include <linux/interrupt.h>
# include <linux/jiffies.h>
# include <linux/module.h>
# include <linux/slab.h>
2008-08-05 16:14:15 +01:00
# include <mach/hardware.h>
# include <mach/aaed2000.h>
2006-11-24 00:42:50 -05:00
# define KB_ROWS 12
# define KB_COLS 8
# define KB_ROWMASK(r) (1 << (r))
# define SCANCODE(r,c) (((c) * KB_ROWS) + (r))
# define NR_SCANCODES (KB_COLS * KB_ROWS)
# define SCAN_INTERVAL (50) /* ms */
# define KB_ACTIVATE_DELAY (20) /* us */
static unsigned char aaedkbd_keycode [ NR_SCANCODES ] = {
KEY_9 , KEY_0 , KEY_MINUS , KEY_EQUAL , KEY_BACKSPACE , 0 , KEY_SPACE , KEY_KP6 , 0 , KEY_KPDOT , 0 , 0 ,
KEY_K , KEY_M , KEY_O , KEY_DOT , KEY_SLASH , 0 , KEY_F , 0 , 0 , 0 , KEY_LEFTSHIFT , 0 ,
KEY_I , KEY_P , KEY_LEFTBRACE , KEY_RIGHTBRACE , KEY_BACKSLASH , 0 , 0 , 0 , 0 , 0 , KEY_RIGHTSHIFT , 0 ,
KEY_8 , KEY_L , KEY_SEMICOLON , KEY_APOSTROPHE , KEY_ENTER , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
KEY_J , KEY_H , KEY_B , KEY_KP8 , KEY_KP4 , 0 , KEY_C , KEY_D , KEY_S , KEY_A , 0 , KEY_CAPSLOCK ,
KEY_Y , KEY_U , KEY_N , KEY_T , 0 , 0 , KEY_R , KEY_E , KEY_W , KEY_Q , 0 , KEY_TAB ,
KEY_7 , KEY_6 , KEY_G , 0 , KEY_5 , 0 , KEY_4 , KEY_3 , KEY_2 , KEY_1 , 0 , KEY_GRAVE ,
0 , 0 , KEY_COMMA , 0 , KEY_KP2 , 0 , KEY_V , KEY_LEFTALT , KEY_X , KEY_Z , 0 , KEY_LEFTCTRL
} ;
struct aaedkbd {
unsigned char keycode [ ARRAY_SIZE ( aaedkbd_keycode ) ] ;
2007-05-03 01:02:07 -04:00
struct input_polled_dev * poll_dev ;
2006-11-24 00:42:50 -05:00
int kbdscan_state [ KB_COLS ] ;
int kbdscan_count [ KB_COLS ] ;
} ;
# define KBDSCAN_STABLE_COUNT 2
static void aaedkbd_report_col ( struct aaedkbd * aaedkbd ,
unsigned int col , unsigned int rowd )
{
unsigned int scancode , pressed ;
unsigned int row ;
for ( row = 0 ; row < KB_ROWS ; row + + ) {
scancode = SCANCODE ( row , col ) ;
pressed = rowd & KB_ROWMASK ( row ) ;
2007-05-03 01:02:07 -04:00
input_report_key ( aaedkbd - > poll_dev - > input ,
aaedkbd - > keycode [ scancode ] , pressed ) ;
2006-11-24 00:42:50 -05:00
}
}
/* Scan the hardware keyboard and push any changes up through the input layer */
2007-05-03 01:02:07 -04:00
static void aaedkbd_poll ( struct input_polled_dev * dev )
2006-11-24 00:42:50 -05:00
{
2007-05-03 01:02:07 -04:00
struct aaedkbd * aaedkbd = dev - > private ;
2006-11-24 00:42:50 -05:00
unsigned int col , rowd ;
col = 0 ;
do {
AAEC_GPIO_KSCAN = col + 8 ;
udelay ( KB_ACTIVATE_DELAY ) ;
rowd = AAED_EXT_GPIO & AAED_EGPIO_KBD_SCAN ;
if ( rowd ! = aaedkbd - > kbdscan_state [ col ] ) {
aaedkbd - > kbdscan_count [ col ] = 0 ;
aaedkbd - > kbdscan_state [ col ] = rowd ;
} else if ( + + aaedkbd - > kbdscan_count [ col ] > = KBDSCAN_STABLE_COUNT ) {
aaedkbd_report_col ( aaedkbd , col , rowd ) ;
col + + ;
}
} while ( col < KB_COLS ) ;
AAEC_GPIO_KSCAN = 0x07 ;
2007-05-03 01:02:07 -04:00
input_sync ( dev - > input ) ;
2006-11-24 00:42:50 -05:00
}
static int __devinit aaedkbd_probe ( struct platform_device * pdev )
{
struct aaedkbd * aaedkbd ;
2007-05-03 01:02:07 -04:00
struct input_polled_dev * poll_dev ;
2006-11-24 00:42:50 -05:00
struct input_dev * input_dev ;
int i ;
int error ;
aaedkbd = kzalloc ( sizeof ( struct aaedkbd ) , GFP_KERNEL ) ;
2007-05-03 01:02:07 -04:00
poll_dev = input_allocate_polled_device ( ) ;
if ( ! aaedkbd | | ! poll_dev ) {
2006-11-24 00:42:50 -05:00
error = - ENOMEM ;
goto fail ;
}
platform_set_drvdata ( pdev , aaedkbd ) ;
2007-05-03 01:02:07 -04:00
aaedkbd - > poll_dev = poll_dev ;
2006-11-24 00:42:50 -05:00
memcpy ( aaedkbd - > keycode , aaedkbd_keycode , sizeof ( aaedkbd - > keycode ) ) ;
2007-05-03 01:02:07 -04:00
poll_dev - > private = aaedkbd ;
poll_dev - > poll = aaedkbd_poll ;
poll_dev - > poll_interval = SCAN_INTERVAL ;
input_dev = poll_dev - > input ;
2006-11-24 00:42:50 -05:00
input_dev - > name = " AAED-2000 Keyboard " ;
input_dev - > phys = " aaedkbd/input0 " ;
input_dev - > id . bustype = BUS_HOST ;
input_dev - > id . vendor = 0x0001 ;
input_dev - > id . product = 0x0001 ;
input_dev - > id . version = 0x0100 ;
2007-04-12 01:34:58 -04:00
input_dev - > dev . parent = & pdev - > dev ;
2007-10-18 23:40:32 -07:00
input_dev - > evbit [ 0 ] = BIT_MASK ( EV_KEY ) | BIT_MASK ( EV_REP ) ;
2006-11-24 00:42:50 -05:00
input_dev - > keycode = aaedkbd - > keycode ;
input_dev - > keycodesize = sizeof ( unsigned char ) ;
input_dev - > keycodemax = ARRAY_SIZE ( aaedkbd_keycode ) ;
for ( i = 0 ; i < ARRAY_SIZE ( aaedkbd_keycode ) ; i + + )
set_bit ( aaedkbd - > keycode [ i ] , input_dev - > keybit ) ;
clear_bit ( 0 , input_dev - > keybit ) ;
2007-05-03 01:02:07 -04:00
error = input_register_polled_device ( aaedkbd - > poll_dev ) ;
2006-11-24 00:42:50 -05:00
if ( error )
goto fail ;
return 0 ;
fail : kfree ( aaedkbd ) ;
2007-05-03 01:02:07 -04:00
input_free_polled_device ( poll_dev ) ;
2006-11-24 00:42:50 -05:00
return error ;
}
static int __devexit aaedkbd_remove ( struct platform_device * pdev )
{
struct aaedkbd * aaedkbd = platform_get_drvdata ( pdev ) ;
2007-05-03 01:02:07 -04:00
input_unregister_polled_device ( aaedkbd - > poll_dev ) ;
input_free_polled_device ( aaedkbd - > poll_dev ) ;
2006-11-24 00:42:50 -05:00
kfree ( aaedkbd ) ;
return 0 ;
}
2008-04-18 00:24:42 -04:00
/* work with hotplug and coldplug */
MODULE_ALIAS ( " platform:aaed2000-keyboard " ) ;
2006-11-24 00:42:50 -05:00
static struct platform_driver aaedkbd_driver = {
. probe = aaedkbd_probe ,
. remove = __devexit_p ( aaedkbd_remove ) ,
. driver = {
. name = " aaed2000-keyboard " ,
2008-04-18 00:24:42 -04:00
. owner = THIS_MODULE ,
2006-11-24 00:42:50 -05:00
} ,
} ;
static int __init aaedkbd_init ( void )
{
return platform_driver_register ( & aaedkbd_driver ) ;
}
static void __exit aaedkbd_exit ( void )
{
platform_driver_unregister ( & aaedkbd_driver ) ;
}
module_init ( aaedkbd_init ) ;
module_exit ( aaedkbd_exit ) ;
MODULE_AUTHOR ( " Nicolas Bellido Y Ortega " ) ;
MODULE_DESCRIPTION ( " AAED-2000 Keyboard Driver " ) ;
2008-05-21 06:32:11 +01:00
MODULE_LICENSE ( " GPL v2 " ) ;