2007-03-16 07:58:52 +03:00
/*
2008-01-31 08:56:46 +03:00
* linux / drivers / input / keyboard / pxa27x_keypad . c
2007-03-16 07:58:52 +03:00
*
* Driver for the pxa27x matrix keyboard controller .
*
* Created : Feb 22 , 2007
* Author : Rodolfo Giometti < giometti @ linux . it >
*
* Based on a previous implementations by Kevin O ' Connor
* < kevin_at_koconnor . net > and Alex Osborne < bobofdoom @ gmail . com > and
* on some suggestions by Nicolas Pitre < nico @ cam . org > .
*
* 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/kernel.h>
# include <linux/module.h>
# include <linux/init.h>
# include <linux/interrupt.h>
# include <linux/input.h>
# include <linux/device.h>
# include <linux/platform_device.h>
2007-08-20 13:19:39 +04:00
# include <linux/clk.h>
# include <linux/err.h>
2007-03-16 07:58:52 +03:00
# include <asm/mach-types.h>
# include <asm/mach/arch.h>
# include <asm/mach/map.h>
# include <asm/arch/hardware.h>
2008-01-31 08:56:46 +03:00
# include <asm/arch/pxa27x_keypad.h>
2007-03-16 07:58:52 +03:00
2008-01-31 08:59:15 +03:00
/*
* Keypad Controller registers
*/
# define KPC 0x0000 /* Keypad Control register */
# define KPDK 0x0008 /* Keypad Direct Key register */
# define KPREC 0x0010 /* Keypad Rotary Encoder register */
# define KPMK 0x0018 /* Keypad Matrix Key register */
# define KPAS 0x0020 /* Keypad Automatic Scan register */
/* Keypad Automatic Scan Multiple Key Presser register 0-3 */
# define KPASMKP0 0x0028
# define KPASMKP1 0x0030
# define KPASMKP2 0x0038
# define KPASMKP3 0x0040
# define KPKDI 0x0048
/* bit definitions */
2008-01-31 08:58:52 +03:00
# define KPC_MKRN(n) ((((n) & 0x7) - 1) << 26) /* matrix key row number */
# define KPC_MKCN(n) ((((n) & 0x7) - 1) << 23) /* matrix key column number */
# define KPC_DKN(n) ((((n) & 0x7) - 1) << 6) /* direct key number */
2008-01-31 08:59:15 +03:00
# define KPC_AS (0x1 << 30) /* Automatic Scan bit */
# define KPC_ASACT (0x1 << 29) /* Automatic Scan on Activity */
# define KPC_MI (0x1 << 22) /* Matrix interrupt bit */
# define KPC_IMKP (0x1 << 21) /* Ignore Multiple Key Press */
# define KPC_MS(n) (0x1 << (13 + (n))) /* Matrix scan line 'n' */
# define KPC_MS_ALL (0xff << 13)
# define KPC_ME (0x1 << 12) /* Matrix Keypad Enable */
# define KPC_MIE (0x1 << 11) /* Matrix Interrupt Enable */
# define KPC_DK_DEB_SEL (0x1 << 9) /* Direct Keypad Debounce Select */
# define KPC_DI (0x1 << 5) /* Direct key interrupt bit */
# define KPC_RE_ZERO_DEB (0x1 << 4) /* Rotary Encoder Zero Debounce */
# define KPC_REE1 (0x1 << 3) /* Rotary Encoder1 Enable */
# define KPC_REE0 (0x1 << 2) /* Rotary Encoder0 Enable */
# define KPC_DE (0x1 << 1) /* Direct Keypad Enable */
# define KPC_DIE (0x1 << 0) /* Direct Keypad interrupt Enable */
2008-01-31 08:59:03 +03:00
# define KPDK_DKP (0x1 << 31)
# define KPDK_DK(n) ((n) & 0xff)
2008-01-31 08:59:15 +03:00
# define KPREC_OF1 (0x1 << 31)
# define kPREC_UF1 (0x1 << 30)
# define KPREC_OF0 (0x1 << 15)
# define KPREC_UF0 (0x1 << 14)
# define KPREC_RECOUNT0(n) ((n) & 0xff)
# define KPREC_RECOUNT1(n) (((n) >> 16) & 0xff)
# define KPMK_MKP (0x1 << 31)
# define KPAS_SO (0x1 << 31)
# define KPASMKPx_SO (0x1 << 31)
# define KPAS_MUKP(n) (((n) >> 26) & 0x1f)
# define KPAS_RP(n) (((n) >> 4) & 0xf)
# define KPAS_CP(n) ((n) & 0xf)
2007-03-16 07:58:52 +03:00
2008-01-31 08:58:37 +03:00
# define KPASMKP_MKC_MASK (0xff)
2008-01-31 08:59:15 +03:00
# define keypad_readl(off) __raw_readl(keypad->mmio_base + (off))
# define keypad_writel(off, v) __raw_writel((v), keypad->mmio_base + (off))
2008-01-31 08:58:37 +03:00
# define MAX_MATRIX_KEY_NUM (8 * 8)
struct pxa27x_keypad {
struct pxa27x_keypad_platform_data * pdata ;
struct clk * clk ;
struct input_dev * input_dev ;
2008-01-31 08:59:15 +03:00
void __iomem * mmio_base ;
2008-01-31 08:58:37 +03:00
/* matrix key code map */
unsigned int matrix_keycodes [ MAX_MATRIX_KEY_NUM ] ;
/* state row bits of each column scan */
uint32_t matrix_key_state [ MAX_MATRIX_KEY_COLS ] ;
2008-01-31 08:59:03 +03:00
uint32_t direct_key_state ;
unsigned int direct_key_mask ;
int rotary_rel_code [ 2 ] ;
int rotary_up_key [ 2 ] ;
int rotary_down_key [ 2 ] ;
2008-01-31 08:58:37 +03:00
} ;
static void pxa27x_keypad_build_keycode ( struct pxa27x_keypad * keypad )
{
struct pxa27x_keypad_platform_data * pdata = keypad - > pdata ;
struct input_dev * input_dev = keypad - > input_dev ;
unsigned int * key ;
int i ;
key = & pdata - > matrix_key_map [ 0 ] ;
for ( i = 0 ; i < pdata - > matrix_key_map_size ; i + + , key + + ) {
int row = ( ( * key ) > > 28 ) & 0xf ;
int col = ( ( * key ) > > 24 ) & 0xf ;
int code = ( * key ) & 0xffffff ;
keypad - > matrix_keycodes [ ( row < < 3 ) + col ] = code ;
set_bit ( code , input_dev - > keybit ) ;
}
2008-01-31 08:59:03 +03:00
keypad - > rotary_up_key [ 0 ] = pdata - > rotary0_up_key ;
keypad - > rotary_up_key [ 1 ] = pdata - > rotary1_up_key ;
keypad - > rotary_down_key [ 0 ] = pdata - > rotary0_down_key ;
keypad - > rotary_down_key [ 1 ] = pdata - > rotary1_down_key ;
keypad - > rotary_rel_code [ 0 ] = pdata - > rotary0_rel_code ;
keypad - > rotary_rel_code [ 1 ] = pdata - > rotary1_rel_code ;
if ( pdata - > rotary0_up_key & & pdata - > rotary0_down_key ) {
set_bit ( pdata - > rotary0_up_key , input_dev - > keybit ) ;
set_bit ( pdata - > rotary0_down_key , input_dev - > keybit ) ;
} else
set_bit ( pdata - > rotary0_rel_code , input_dev - > relbit ) ;
if ( pdata - > rotary1_up_key & & pdata - > rotary1_down_key ) {
set_bit ( pdata - > rotary1_up_key , input_dev - > keybit ) ;
set_bit ( pdata - > rotary1_down_key , input_dev - > keybit ) ;
} else
set_bit ( pdata - > rotary1_rel_code , input_dev - > relbit ) ;
2008-01-31 08:58:37 +03:00
}
static inline unsigned int lookup_matrix_keycode (
struct pxa27x_keypad * keypad , int row , int col )
{
return keypad - > matrix_keycodes [ ( row < < 3 ) + col ] ;
}
static void pxa27x_keypad_scan_matrix ( struct pxa27x_keypad * keypad )
{
struct pxa27x_keypad_platform_data * pdata = keypad - > pdata ;
int row , col , num_keys_pressed = 0 ;
uint32_t new_state [ MAX_MATRIX_KEY_COLS ] ;
2008-01-31 08:59:15 +03:00
uint32_t kpas = keypad_readl ( KPAS ) ;
2008-01-31 08:58:37 +03:00
num_keys_pressed = KPAS_MUKP ( kpas ) ;
memset ( new_state , 0 , sizeof ( new_state ) ) ;
if ( num_keys_pressed = = 0 )
goto scan ;
if ( num_keys_pressed = = 1 ) {
col = KPAS_CP ( kpas ) ;
row = KPAS_RP ( kpas ) ;
/* if invalid row/col, treat as no key pressed */
if ( col > = pdata - > matrix_key_cols | |
row > = pdata - > matrix_key_rows )
goto scan ;
new_state [ col ] = ( 1 < < row ) ;
goto scan ;
}
if ( num_keys_pressed > 1 ) {
2008-01-31 08:59:15 +03:00
uint32_t kpasmkp0 = keypad_readl ( KPASMKP0 ) ;
uint32_t kpasmkp1 = keypad_readl ( KPASMKP1 ) ;
uint32_t kpasmkp2 = keypad_readl ( KPASMKP2 ) ;
uint32_t kpasmkp3 = keypad_readl ( KPASMKP3 ) ;
2008-01-31 08:58:37 +03:00
new_state [ 0 ] = kpasmkp0 & KPASMKP_MKC_MASK ;
new_state [ 1 ] = ( kpasmkp0 > > 16 ) & KPASMKP_MKC_MASK ;
new_state [ 2 ] = kpasmkp1 & KPASMKP_MKC_MASK ;
new_state [ 3 ] = ( kpasmkp1 > > 16 ) & KPASMKP_MKC_MASK ;
new_state [ 4 ] = kpasmkp2 & KPASMKP_MKC_MASK ;
new_state [ 5 ] = ( kpasmkp2 > > 16 ) & KPASMKP_MKC_MASK ;
new_state [ 6 ] = kpasmkp3 & KPASMKP_MKC_MASK ;
new_state [ 7 ] = ( kpasmkp3 > > 16 ) & KPASMKP_MKC_MASK ;
}
scan :
for ( col = 0 ; col < pdata - > matrix_key_cols ; col + + ) {
uint32_t bits_changed ;
bits_changed = keypad - > matrix_key_state [ col ] ^ new_state [ col ] ;
if ( bits_changed = = 0 )
continue ;
for ( row = 0 ; row < pdata - > matrix_key_rows ; row + + ) {
if ( ( bits_changed & ( 1 < < row ) ) = = 0 )
continue ;
input_report_key ( keypad - > input_dev ,
lookup_matrix_keycode ( keypad , row , col ) ,
new_state [ col ] & ( 1 < < row ) ) ;
}
}
input_sync ( keypad - > input_dev ) ;
memcpy ( keypad - > matrix_key_state , new_state , sizeof ( new_state ) ) ;
}
2007-08-20 13:19:39 +04:00
2008-01-31 08:58:52 +03:00
# define DEFAULT_KPREC (0x007f007f)
2008-01-31 08:59:03 +03:00
static inline int rotary_delta ( uint32_t kprec )
{
if ( kprec & KPREC_OF0 )
return ( kprec & 0xff ) + 0x7f ;
else if ( kprec & KPREC_UF0 )
return ( kprec & 0xff ) - 0x7f - 0xff ;
else
return ( kprec & 0xff ) - 0x7f ;
}
static void report_rotary_event ( struct pxa27x_keypad * keypad , int r , int delta )
{
struct input_dev * dev = keypad - > input_dev ;
if ( delta = = 0 )
return ;
if ( keypad - > rotary_up_key [ r ] & & keypad - > rotary_down_key [ r ] ) {
int keycode = ( delta > 0 ) ? keypad - > rotary_up_key [ r ] :
keypad - > rotary_down_key [ r ] ;
/* simulate a press-n-release */
input_report_key ( dev , keycode , 1 ) ;
input_sync ( dev ) ;
input_report_key ( dev , keycode , 0 ) ;
input_sync ( dev ) ;
} else {
input_report_rel ( dev , keypad - > rotary_rel_code [ r ] , delta ) ;
input_sync ( dev ) ;
}
}
static void pxa27x_keypad_scan_rotary ( struct pxa27x_keypad * keypad )
{
struct pxa27x_keypad_platform_data * pdata = keypad - > pdata ;
uint32_t kprec ;
/* read and reset to default count value */
2008-01-31 08:59:15 +03:00
kprec = keypad_readl ( KPREC ) ;
keypad_writel ( KPREC , DEFAULT_KPREC ) ;
2008-01-31 08:59:03 +03:00
if ( pdata - > enable_rotary0 )
report_rotary_event ( keypad , 0 , rotary_delta ( kprec ) ) ;
if ( pdata - > enable_rotary1 )
report_rotary_event ( keypad , 1 , rotary_delta ( kprec > > 16 ) ) ;
}
static void pxa27x_keypad_scan_direct ( struct pxa27x_keypad * keypad )
{
struct pxa27x_keypad_platform_data * pdata = keypad - > pdata ;
unsigned int new_state ;
uint32_t kpdk , bits_changed ;
int i ;
2008-01-31 08:59:15 +03:00
kpdk = keypad_readl ( KPDK ) ;
2008-01-31 08:59:03 +03:00
if ( pdata - > enable_rotary0 | | pdata - > enable_rotary1 )
pxa27x_keypad_scan_rotary ( keypad ) ;
if ( pdata - > direct_key_map = = NULL )
return ;
new_state = KPDK_DK ( kpdk ) & keypad - > direct_key_mask ;
bits_changed = keypad - > direct_key_state ^ new_state ;
if ( bits_changed = = 0 )
return ;
for ( i = 0 ; i < pdata - > direct_key_num ; i + + ) {
if ( bits_changed & ( 1 < < i ) )
input_report_key ( keypad - > input_dev ,
pdata - > direct_key_map [ i ] ,
( new_state & ( 1 < < i ) ) ) ;
}
input_sync ( keypad - > input_dev ) ;
keypad - > direct_key_state = new_state ;
}
2008-01-31 08:56:46 +03:00
static irqreturn_t pxa27x_keypad_irq_handler ( int irq , void * dev_id )
2007-03-16 07:58:52 +03:00
{
2008-01-31 08:58:37 +03:00
struct pxa27x_keypad * keypad = dev_id ;
2008-01-31 08:59:15 +03:00
unsigned long kpc = keypad_readl ( KPC ) ;
2008-01-31 08:59:03 +03:00
if ( kpc & KPC_DI )
pxa27x_keypad_scan_direct ( keypad ) ;
2007-03-16 07:58:52 +03:00
2008-01-31 08:58:37 +03:00
if ( kpc & KPC_MI )
pxa27x_keypad_scan_matrix ( keypad ) ;
2007-03-16 07:58:52 +03:00
return IRQ_HANDLED ;
}
2008-01-31 08:58:52 +03:00
static void pxa27x_keypad_config ( struct pxa27x_keypad * keypad )
2007-03-16 07:58:52 +03:00
{
2008-01-31 08:58:52 +03:00
struct pxa27x_keypad_platform_data * pdata = keypad - > pdata ;
2008-01-31 08:59:03 +03:00
unsigned int mask = 0 , direct_key_num = 0 ;
2008-01-31 08:58:52 +03:00
unsigned long kpc = 0 ;
2008-01-31 08:58:37 +03:00
2008-01-31 08:58:52 +03:00
/* enable matrix keys with automatic scan */
if ( pdata - > matrix_key_rows & & pdata - > matrix_key_cols ) {
kpc | = KPC_ASACT | KPC_MIE | KPC_ME | KPC_MS_ALL ;
kpc | = KPC_MKRN ( pdata - > matrix_key_rows ) |
KPC_MKCN ( pdata - > matrix_key_cols ) ;
}
2007-03-16 07:58:52 +03:00
2008-01-31 08:59:03 +03:00
/* enable rotary key, debounce interval same as direct keys */
if ( pdata - > enable_rotary0 ) {
mask | = 0x03 ;
direct_key_num = 2 ;
kpc | = KPC_REE0 ;
}
if ( pdata - > enable_rotary1 ) {
mask | = 0x0c ;
direct_key_num = 4 ;
kpc | = KPC_REE1 ;
}
if ( pdata - > direct_key_num > direct_key_num )
direct_key_num = pdata - > direct_key_num ;
keypad - > direct_key_mask = ( ( 2 < < direct_key_num ) - 1 ) & ~ mask ;
/* enable direct key */
if ( direct_key_num )
kpc | = KPC_DE | KPC_DIE | KPC_DKN ( direct_key_num ) ;
2007-03-16 07:58:52 +03:00
2008-01-31 08:59:15 +03:00
keypad_writel ( KPC , kpc | KPC_RE_ZERO_DEB ) ;
keypad_writel ( KPREC , DEFAULT_KPREC ) ;
2008-01-31 08:58:52 +03:00
}
static int pxa27x_keypad_open ( struct input_dev * dev )
{
struct pxa27x_keypad * keypad = input_get_drvdata ( dev ) ;
2007-03-16 07:58:52 +03:00
/* Enable unit clock */
2008-01-31 08:58:37 +03:00
clk_enable ( keypad - > clk ) ;
2008-01-31 08:58:52 +03:00
pxa27x_keypad_config ( keypad ) ;
2007-03-16 07:58:52 +03:00
return 0 ;
}
2008-01-31 08:56:46 +03:00
static void pxa27x_keypad_close ( struct input_dev * dev )
2007-03-16 07:58:52 +03:00
{
2008-01-31 08:58:37 +03:00
struct pxa27x_keypad * keypad = input_get_drvdata ( dev ) ;
2007-03-16 07:58:52 +03:00
/* Disable clock unit */
2008-01-31 08:58:37 +03:00
clk_disable ( keypad - > clk ) ;
2007-03-16 07:58:52 +03:00
}
# ifdef CONFIG_PM
2008-01-31 08:56:46 +03:00
static int pxa27x_keypad_suspend ( struct platform_device * pdev , pm_message_t state )
2007-03-16 07:58:52 +03:00
{
2008-01-31 08:58:37 +03:00
struct pxa27x_keypad * keypad = platform_get_drvdata ( pdev ) ;
2007-03-16 07:58:52 +03:00
2008-01-31 08:58:52 +03:00
clk_disable ( keypad - > clk ) ;
2007-03-16 07:58:52 +03:00
return 0 ;
}
2008-01-31 08:56:46 +03:00
static int pxa27x_keypad_resume ( struct platform_device * pdev )
2007-03-16 07:58:52 +03:00
{
2008-01-31 08:58:37 +03:00
struct pxa27x_keypad * keypad = platform_get_drvdata ( pdev ) ;
struct input_dev * input_dev = keypad - > input_dev ;
2007-03-16 07:58:52 +03:00
mutex_lock ( & input_dev - > mutex ) ;
if ( input_dev - > users ) {
/* Enable unit clock */
2008-01-31 08:58:37 +03:00
clk_enable ( keypad - > clk ) ;
2008-01-31 08:58:52 +03:00
pxa27x_keypad_config ( keypad ) ;
2007-03-16 07:58:52 +03:00
}
mutex_unlock ( & input_dev - > mutex ) ;
return 0 ;
}
# else
2008-01-31 08:56:46 +03:00
# define pxa27x_keypad_suspend NULL
# define pxa27x_keypad_resume NULL
2007-03-16 07:58:52 +03:00
# endif
2008-01-31 08:59:15 +03:00
# define res_size(res) ((res)->end - (res)->start + 1)
2008-01-31 08:56:46 +03:00
static int __devinit pxa27x_keypad_probe ( struct platform_device * pdev )
2007-03-16 07:58:52 +03:00
{
2008-01-31 08:58:37 +03:00
struct pxa27x_keypad * keypad ;
2007-03-16 07:58:52 +03:00
struct input_dev * input_dev ;
2008-01-31 08:59:15 +03:00
struct resource * res ;
int irq , error ;
2007-03-16 07:58:52 +03:00
2008-01-31 08:58:37 +03:00
keypad = kzalloc ( sizeof ( struct pxa27x_keypad ) , GFP_KERNEL ) ;
if ( keypad = = NULL ) {
dev_err ( & pdev - > dev , " failed to allocate driver data \n " ) ;
return - ENOMEM ;
}
keypad - > pdata = pdev - > dev . platform_data ;
if ( keypad - > pdata = = NULL ) {
dev_err ( & pdev - > dev , " no platform data defined \n " ) ;
error = - EINVAL ;
goto failed_free ;
}
2008-01-31 08:59:15 +03:00
irq = platform_get_irq ( pdev , 0 ) ;
if ( irq < 0 ) {
dev_err ( & pdev - > dev , " failed to get keypad irq \n " ) ;
error = - ENXIO ;
goto failed_free ;
}
res = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
if ( res = = NULL ) {
dev_err ( & pdev - > dev , " failed to get I/O memory \n " ) ;
error = - ENXIO ;
goto failed_free ;
}
res = request_mem_region ( res - > start , res_size ( res ) , pdev - > name ) ;
if ( res = = NULL ) {
dev_err ( & pdev - > dev , " failed to request I/O memory \n " ) ;
error = - EBUSY ;
goto failed_free ;
}
keypad - > mmio_base = ioremap ( res - > start , res_size ( res ) ) ;
if ( keypad - > mmio_base = = NULL ) {
dev_err ( & pdev - > dev , " failed to remap I/O memory \n " ) ;
error = - ENXIO ;
goto failed_free_mem ;
}
2008-01-31 08:58:37 +03:00
keypad - > clk = clk_get ( & pdev - > dev , " KBDCLK " ) ;
if ( IS_ERR ( keypad - > clk ) ) {
dev_err ( & pdev - > dev , " failed to get keypad clock \n " ) ;
error = PTR_ERR ( keypad - > clk ) ;
2008-01-31 08:59:15 +03:00
goto failed_free_io ;
2007-08-20 13:19:39 +04:00
}
2007-03-16 07:58:52 +03:00
/* Create and register the input driver. */
input_dev = input_allocate_device ( ) ;
if ( ! input_dev ) {
2008-01-31 08:58:37 +03:00
dev_err ( & pdev - > dev , " failed to allocate input device \n " ) ;
2007-08-20 13:19:39 +04:00
error = - ENOMEM ;
2008-01-31 08:58:37 +03:00
goto failed_put_clk ;
2007-03-16 07:58:52 +03:00
}
2008-01-31 08:59:15 +03:00
input_dev - > name = pdev - > name ;
2007-03-16 07:58:52 +03:00
input_dev - > id . bustype = BUS_HOST ;
2008-01-31 08:56:46 +03:00
input_dev - > open = pxa27x_keypad_open ;
input_dev - > close = pxa27x_keypad_close ;
2007-04-12 09:34:58 +04:00
input_dev - > dev . parent = & pdev - > dev ;
2007-03-16 07:58:52 +03:00
2008-01-31 08:58:37 +03:00
keypad - > input_dev = input_dev ;
input_set_drvdata ( input_dev , keypad ) ;
2007-10-19 10:40:32 +04:00
input_dev - > evbit [ 0 ] = BIT_MASK ( EV_KEY ) | BIT_MASK ( EV_REP ) |
BIT_MASK ( EV_REL ) ;
2008-01-31 08:58:37 +03:00
pxa27x_keypad_build_keycode ( keypad ) ;
2008-01-31 08:59:15 +03:00
platform_set_drvdata ( pdev , keypad ) ;
2007-03-16 07:58:52 +03:00
2008-01-31 08:59:15 +03:00
error = request_irq ( irq , pxa27x_keypad_irq_handler , IRQF_DISABLED ,
pdev - > name , keypad ) ;
2007-03-16 07:58:52 +03:00
if ( error ) {
2008-01-31 08:59:15 +03:00
dev_err ( & pdev - > dev , " failed to request IRQ \n " ) ;
goto failed_free_dev ;
2007-03-16 07:58:52 +03:00
}
/* Register the input device */
error = input_register_device ( input_dev ) ;
2008-01-31 08:59:15 +03:00
if ( error ) {
dev_err ( & pdev - > dev , " failed to register input device \n " ) ;
goto failed_free_irq ;
}
2007-03-16 07:58:52 +03:00
return 0 ;
2008-01-31 08:59:15 +03:00
failed_free_irq :
free_irq ( irq , pdev ) ;
2007-03-16 07:58:52 +03:00
platform_set_drvdata ( pdev , NULL ) ;
2008-01-31 08:59:15 +03:00
failed_free_dev :
2007-03-16 07:58:52 +03:00
input_free_device ( input_dev ) ;
2008-01-31 08:58:37 +03:00
failed_put_clk :
clk_put ( keypad - > clk ) ;
2008-01-31 08:59:15 +03:00
failed_free_io :
iounmap ( keypad - > mmio_base ) ;
failed_free_mem :
release_mem_region ( res - > start , res_size ( res ) ) ;
2008-01-31 08:58:37 +03:00
failed_free :
kfree ( keypad ) ;
2007-03-16 07:58:52 +03:00
return error ;
}
2008-01-31 08:56:46 +03:00
static int __devexit pxa27x_keypad_remove ( struct platform_device * pdev )
2007-03-16 07:58:52 +03:00
{
2008-01-31 08:58:37 +03:00
struct pxa27x_keypad * keypad = platform_get_drvdata ( pdev ) ;
2008-01-31 08:59:15 +03:00
struct resource * res ;
2007-03-16 07:58:52 +03:00
2008-01-31 08:59:15 +03:00
free_irq ( platform_get_irq ( pdev , 0 ) , pdev ) ;
2007-03-16 07:58:52 +03:00
2008-01-31 08:58:37 +03:00
clk_disable ( keypad - > clk ) ;
clk_put ( keypad - > clk ) ;
input_unregister_device ( keypad - > input_dev ) ;
2008-01-31 08:59:15 +03:00
input_free_device ( keypad - > input_dev ) ;
iounmap ( keypad - > mmio_base ) ;
res = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
release_mem_region ( res - > start , res_size ( res ) ) ;
2008-01-31 08:58:37 +03:00
platform_set_drvdata ( pdev , NULL ) ;
kfree ( keypad ) ;
2007-03-16 07:58:52 +03:00
return 0 ;
}
2008-01-31 08:56:46 +03:00
static struct platform_driver pxa27x_keypad_driver = {
. probe = pxa27x_keypad_probe ,
. remove = __devexit_p ( pxa27x_keypad_remove ) ,
. suspend = pxa27x_keypad_suspend ,
. resume = pxa27x_keypad_resume ,
2007-03-16 07:58:52 +03:00
. driver = {
2008-01-31 08:59:15 +03:00
. name = " pxa27x-keypad " ,
2007-03-16 07:58:52 +03:00
} ,
} ;
2008-01-31 08:56:46 +03:00
static int __init pxa27x_keypad_init ( void )
2007-03-16 07:58:52 +03:00
{
2008-01-31 08:56:46 +03:00
return platform_driver_register ( & pxa27x_keypad_driver ) ;
2007-03-16 07:58:52 +03:00
}
2008-01-31 08:56:46 +03:00
static void __exit pxa27x_keypad_exit ( void )
2007-03-16 07:58:52 +03:00
{
2008-01-31 08:56:46 +03:00
platform_driver_unregister ( & pxa27x_keypad_driver ) ;
2007-03-16 07:58:52 +03:00
}
2008-01-31 08:56:46 +03:00
module_init ( pxa27x_keypad_init ) ;
module_exit ( pxa27x_keypad_exit ) ;
2007-03-16 07:58:52 +03:00
2008-01-31 08:56:46 +03:00
MODULE_DESCRIPTION ( " PXA27x Keypad Controller Driver " ) ;
2007-03-16 07:58:52 +03:00
MODULE_LICENSE ( " GPL " ) ;