2013-02-25 14:08:41 -08:00
/*
* ChromeOS EC keyboard driver
*
* Copyright ( C ) 2012 Google , Inc
*
* This software is licensed under the terms of the GNU General Public
* License version 2 , as published by the Free Software Foundation , and
* may be copied , distributed , and modified under those terms .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* This driver uses the Chrome OS EC byte - level message - based protocol for
* communicating the keyboard state ( which keys are pressed ) from a keyboard EC
* to the AP over some bus ( such as i2c , lpc , spi ) . The EC does debouncing ,
* but everything else ( including deghosting ) is done here . The main
* motivation for this is to keep the EC firmware as simple as possible , since
* it cannot be easily upgraded and EC flash / IRAM space is relatively
* expensive .
*/
# include <linux/module.h>
2014-09-03 16:56:12 -07:00
# include <linux/bitops.h>
2013-02-25 14:08:41 -08:00
# include <linux/i2c.h>
# include <linux/input.h>
2014-06-18 11:14:07 -07:00
# include <linux/interrupt.h>
2013-02-25 14:08:41 -08:00
# include <linux/kernel.h>
2016-08-10 19:05:25 +02:00
# include <linux/notifier.h>
2013-02-25 14:08:41 -08:00
# include <linux/platform_device.h>
# include <linux/slab.h>
2017-04-03 11:53:41 -07:00
# include <linux/sysrq.h>
2013-02-25 14:08:41 -08:00
# include <linux/input/matrix_keypad.h>
# include <linux/mfd/cros_ec.h>
# include <linux/mfd/cros_ec_commands.h>
2017-01-20 11:14:15 +01:00
# include <asm/unaligned.h>
2013-02-25 14:08:41 -08:00
/*
* @ rows : Number of rows in the keypad
* @ cols : Number of columns in the keypad
* @ row_shift : log2 or number of rows , rounded up
* @ keymap_data : Matrix keymap data used to convert to keyscan values
* @ ghost_filter : true to enable the matrix key - ghosting filter
2014-09-03 16:56:12 -07:00
* @ valid_keys : bitmap of existing keys for each matrix column
2013-12-29 16:52:46 -08:00
* @ old_kb_state : bitmap of keys pressed last scan
2013-02-25 14:08:41 -08:00
* @ dev : Device pointer
* @ ec : Top level ChromeOS device to use to talk to EC
2017-01-20 11:14:15 +01:00
* @ idev : The input device for the matrix keys .
* @ bs_idev : The input device for non - matrix buttons and switches ( or NULL ) .
2016-08-10 19:05:25 +02:00
* @ notifier : interrupt event notifier for transport devices
2013-02-25 14:08:41 -08:00
*/
struct cros_ec_keyb {
unsigned int rows ;
unsigned int cols ;
int row_shift ;
const struct matrix_keymap_data * keymap_data ;
bool ghost_filter ;
2014-09-03 16:56:12 -07:00
uint8_t * valid_keys ;
2013-12-29 16:52:46 -08:00
uint8_t * old_kb_state ;
2013-02-25 14:08:41 -08:00
struct device * dev ;
struct cros_ec_device * ec ;
2017-01-20 11:14:15 +01:00
struct input_dev * idev ;
struct input_dev * bs_idev ;
2016-08-10 19:05:25 +02:00
struct notifier_block notifier ;
2013-02-25 14:08:41 -08:00
} ;
2017-01-20 11:14:15 +01:00
/**
* cros_ec_bs_map - Struct mapping Linux keycodes to EC button / switch bitmap
* # defines
*
* @ ev_type : The type of the input event to generate ( e . g . , EV_KEY ) .
* @ code : A linux keycode
* @ bit : A # define like EC_MKBP_POWER_BUTTON or EC_MKBP_LID_OPEN
* @ inverted : If the # define and EV_SW have opposite meanings , this is true .
* Only applicable to switches .
*/
struct cros_ec_bs_map {
unsigned int ev_type ;
unsigned int code ;
u8 bit ;
bool inverted ;
} ;
/* cros_ec_keyb_bs - Map EC button/switch #defines into kernel ones */
static const struct cros_ec_bs_map cros_ec_keyb_bs [ ] = {
/* Buttons */
{
. ev_type = EV_KEY ,
. code = KEY_POWER ,
. bit = EC_MKBP_POWER_BUTTON ,
} ,
{
. ev_type = EV_KEY ,
. code = KEY_VOLUMEUP ,
. bit = EC_MKBP_VOL_UP ,
} ,
{
. ev_type = EV_KEY ,
. code = KEY_VOLUMEDOWN ,
. bit = EC_MKBP_VOL_DOWN ,
} ,
/* Switches */
{
. ev_type = EV_SW ,
. code = SW_LID ,
. bit = EC_MKBP_LID_OPEN ,
. inverted = true ,
} ,
2017-01-27 11:52:35 +01:00
{
. ev_type = EV_SW ,
. code = SW_TABLET_MODE ,
. bit = EC_MKBP_TABLET_MODE ,
} ,
2017-01-20 11:14:15 +01:00
} ;
2013-02-25 14:08:41 -08:00
/*
* Returns true when there is at least one combination of pressed keys that
* results in ghosting .
*/
static bool cros_ec_keyb_has_ghosting ( struct cros_ec_keyb * ckdev , uint8_t * buf )
{
2014-09-03 16:56:12 -07:00
int col1 , col2 , buf1 , buf2 ;
struct device * dev = ckdev - > dev ;
uint8_t * valid_keys = ckdev - > valid_keys ;
2013-02-25 14:08:41 -08:00
/*
* Ghosting happens if for any pressed key X there are other keys
* pressed both in the same row and column of X as , for instance ,
* in the following diagram :
*
* . . Y . g .
* . . . . . .
* . . . . . .
* . . X . Z .
*
* In this case only X , Y , and Z are pressed , but g appears to be
* pressed too ( see Wikipedia ) .
*/
2014-09-03 16:56:12 -07:00
for ( col1 = 0 ; col1 < ckdev - > cols ; col1 + + ) {
buf1 = buf [ col1 ] & valid_keys [ col1 ] ;
for ( col2 = col1 + 1 ; col2 < ckdev - > cols ; col2 + + ) {
buf2 = buf [ col2 ] & valid_keys [ col2 ] ;
if ( hweight8 ( buf1 & buf2 ) > 1 ) {
dev_dbg ( dev , " ghost found at: B[%02d]:0x%02x & B[%02d]:0x%02x " ,
col1 , buf1 , col2 , buf2 ) ;
return true ;
}
}
}
2013-02-25 14:08:41 -08:00
return false ;
}
2014-09-03 16:56:12 -07:00
2013-02-25 14:08:41 -08:00
/*
* Compares the new keyboard state to the old one and produces key
* press / release events accordingly . The keyboard state is 13 bytes ( one byte
* per column )
*/
static void cros_ec_keyb_process ( struct cros_ec_keyb * ckdev ,
uint8_t * kb_state , int len )
{
struct input_dev * idev = ckdev - > idev ;
int col , row ;
int new_state ;
2013-12-29 16:52:46 -08:00
int old_state ;
2013-02-25 14:08:41 -08:00
int num_cols ;
num_cols = len ;
if ( ckdev - > ghost_filter & & cros_ec_keyb_has_ghosting ( ckdev , kb_state ) ) {
/*
* Simple - minded solution : ignore this state . The obvious
* improvement is to only ignore changes to keys involved in
* the ghosting , but process the other changes .
*/
dev_dbg ( ckdev - > dev , " ghosting found \n " ) ;
return ;
}
for ( col = 0 ; col < ckdev - > cols ; col + + ) {
for ( row = 0 ; row < ckdev - > rows ; row + + ) {
int pos = MATRIX_SCAN_CODE ( row , col , ckdev - > row_shift ) ;
const unsigned short * keycodes = idev - > keycode ;
new_state = kb_state [ col ] & ( 1 < < row ) ;
2013-12-29 16:52:46 -08:00
old_state = ckdev - > old_kb_state [ col ] & ( 1 < < row ) ;
if ( new_state ! = old_state ) {
2013-02-25 14:08:41 -08:00
dev_dbg ( ckdev - > dev ,
" changed: [r%d c%d]: byte %02x \n " ,
row , col , new_state ) ;
2013-12-29 16:52:46 -08:00
input_report_key ( idev , keycodes [ pos ] ,
new_state ) ;
2013-02-25 14:08:41 -08:00
}
}
2013-12-29 16:52:46 -08:00
ckdev - > old_kb_state [ col ] = kb_state [ col ] ;
2013-02-25 14:08:41 -08:00
}
input_sync ( ckdev - > idev ) ;
}
2017-01-20 11:14:15 +01:00
/**
* cros_ec_keyb_report_bs - Report non - matrixed buttons or switches
*
* This takes a bitmap of buttons or switches from the EC and reports events ,
* syncing at the end .
*
* @ ckdev : The keyboard device .
* @ ev_type : The input event type ( e . g . , EV_KEY ) .
* @ mask : A bitmap of buttons from the EC .
*/
static void cros_ec_keyb_report_bs ( struct cros_ec_keyb * ckdev ,
unsigned int ev_type , u32 mask )
2013-02-25 14:08:41 -08:00
{
2017-01-20 11:14:15 +01:00
struct input_dev * idev = ckdev - > bs_idev ;
int i ;
2013-02-25 14:08:41 -08:00
2017-01-20 11:14:15 +01:00
for ( i = 0 ; i < ARRAY_SIZE ( cros_ec_keyb_bs ) ; i + + ) {
const struct cros_ec_bs_map * map = & cros_ec_keyb_bs [ i ] ;
2014-06-18 11:14:07 -07:00
2017-01-20 11:14:15 +01:00
if ( map - > ev_type ! = ev_type )
continue ;
2014-06-18 11:14:07 -07:00
2017-01-20 11:14:15 +01:00
input_event ( idev , ev_type , map - > code ,
! ! ( mask & BIT ( map - > bit ) ) ^ map - > inverted ) ;
}
input_sync ( idev ) ;
2014-06-18 11:14:07 -07:00
}
2016-08-10 19:05:25 +02:00
static int cros_ec_keyb_work ( struct notifier_block * nb ,
unsigned long queued_during_suspend , void * _notify )
2014-06-18 11:14:07 -07:00
{
2016-08-10 19:05:25 +02:00
struct cros_ec_keyb * ckdev = container_of ( nb , struct cros_ec_keyb ,
notifier ) ;
2017-01-20 11:14:15 +01:00
u32 val ;
unsigned int ev_type ;
2014-06-18 11:14:07 -07:00
2017-01-20 11:14:15 +01:00
switch ( ckdev - > ec - > event_data . event_type ) {
case EC_MKBP_EVENT_KEY_MATRIX :
/*
* If EC is not the wake source , discard key state changes
* during suspend .
*/
if ( queued_during_suspend )
return NOTIFY_OK ;
if ( ckdev - > ec - > event_size ! = ckdev - > cols ) {
dev_err ( ckdev - > dev ,
" Discarded incomplete key matrix event. \n " ) ;
return NOTIFY_OK ;
}
cros_ec_keyb_process ( ckdev ,
ckdev - > ec - > event_data . data . key_matrix ,
ckdev - > ec - > event_size ) ;
break ;
2017-04-03 11:53:41 -07:00
case EC_MKBP_EVENT_SYSRQ :
val = get_unaligned_le32 ( & ckdev - > ec - > event_data . data . sysrq ) ;
dev_dbg ( ckdev - > dev , " sysrq code from EC: %#x \n " , val ) ;
handle_sysrq ( val ) ;
break ;
2017-01-20 11:14:15 +01:00
case EC_MKBP_EVENT_BUTTON :
case EC_MKBP_EVENT_SWITCH :
/*
* If EC is not the wake source , discard key state
* changes during suspend . Switches will be re - checked in
* cros_ec_keyb_resume ( ) to be sure nothing is lost .
*/
if ( queued_during_suspend )
return NOTIFY_OK ;
if ( ckdev - > ec - > event_data . event_type = = EC_MKBP_EVENT_BUTTON ) {
val = get_unaligned_le32 (
& ckdev - > ec - > event_data . data . buttons ) ;
ev_type = EV_KEY ;
} else {
val = get_unaligned_le32 (
& ckdev - > ec - > event_data . data . switches ) ;
ev_type = EV_SW ;
}
cros_ec_keyb_report_bs ( ckdev , ev_type , val ) ;
break ;
2014-06-18 11:14:07 -07:00
2017-01-20 11:14:15 +01:00
default :
2016-08-10 19:05:25 +02:00
return NOTIFY_DONE ;
}
2017-01-20 11:14:15 +01:00
2016-08-10 19:05:25 +02:00
return NOTIFY_OK ;
2013-02-25 14:08:41 -08:00
}
2014-09-03 16:56:12 -07:00
/*
* Walks keycodes flipping bit in buffer COLUMNS deep where bit is ROW . Used by
* ghosting logic to ignore NULL or virtual keys .
*/
static void cros_ec_keyb_compute_valid_keys ( struct cros_ec_keyb * ckdev )
{
int row , col ;
int row_shift = ckdev - > row_shift ;
unsigned short * keymap = ckdev - > idev - > keycode ;
unsigned short code ;
BUG_ON ( ckdev - > idev - > keycodesize ! = sizeof ( * keymap ) ) ;
for ( col = 0 ; col < ckdev - > cols ; col + + ) {
for ( row = 0 ; row < ckdev - > rows ; row + + ) {
code = keymap [ MATRIX_SCAN_CODE ( row , col , row_shift ) ] ;
if ( code & & ( code ! = KEY_BATTERY ) )
ckdev - > valid_keys [ col ] | = 1 < < row ;
}
dev_dbg ( ckdev - > dev , " valid_keys[%02d] = 0x%02x \n " ,
col , ckdev - > valid_keys [ col ] ) ;
}
}
2017-01-20 11:14:15 +01:00
/**
* cros_ec_keyb_info - Wrap the EC command EC_CMD_MKBP_INFO
*
* This wraps the EC_CMD_MKBP_INFO , abstracting out all of the marshalling and
* unmarshalling and different version nonsense into something simple .
*
* @ ec_dev : The EC device
* @ info_type : Either EC_MKBP_INFO_SUPPORTED or EC_MKBP_INFO_CURRENT .
* @ event_type : Either EC_MKBP_EVENT_BUTTON or EC_MKBP_EVENT_SWITCH . Actually
* in some cases this could be EC_MKBP_EVENT_KEY_MATRIX or
* EC_MKBP_EVENT_HOST_EVENT too but we don ' t use in this driver .
* @ result : Where we ' ll store the result ; a union
* @ result_size : The size of the result . Expected to be the size of one of
* the elements in the union .
*
* Returns 0 if no error or - error upon error .
*/
static int cros_ec_keyb_info ( struct cros_ec_device * ec_dev ,
enum ec_mkbp_info_type info_type ,
enum ec_mkbp_event event_type ,
union ec_response_get_next_data * result ,
size_t result_size )
2013-02-25 14:08:41 -08:00
{
2017-01-20 11:14:15 +01:00
struct ec_params_mkbp_info * params ;
struct cros_ec_command * msg ;
int ret ;
msg = kzalloc ( sizeof ( * msg ) + max_t ( size_t , result_size ,
sizeof ( * params ) ) , GFP_KERNEL ) ;
if ( ! msg )
return - ENOMEM ;
msg - > command = EC_CMD_MKBP_INFO ;
msg - > version = 1 ;
msg - > outsize = sizeof ( * params ) ;
msg - > insize = result_size ;
params = ( struct ec_params_mkbp_info * ) msg - > data ;
params - > info_type = info_type ;
params - > event_type = event_type ;
ret = cros_ec_cmd_xfer ( ec_dev , msg ) ;
if ( ret < 0 ) {
dev_warn ( ec_dev - > dev , " Transfer error %d/%d: %d \n " ,
( int ) info_type , ( int ) event_type , ret ) ;
} else if ( msg - > result = = EC_RES_INVALID_VERSION ) {
/* With older ECs we just return 0 for everything */
memset ( result , 0 , result_size ) ;
ret = 0 ;
} else if ( msg - > result ! = EC_RES_SUCCESS ) {
dev_warn ( ec_dev - > dev , " Error getting info %d/%d: %d \n " ,
( int ) info_type , ( int ) event_type , msg - > result ) ;
ret = - EPROTO ;
} else if ( ret ! = result_size ) {
dev_warn ( ec_dev - > dev , " Wrong size %d/%d: %d != %zu \n " ,
( int ) info_type , ( int ) event_type ,
ret , result_size ) ;
ret = - EPROTO ;
} else {
memcpy ( result , msg - > data , result_size ) ;
ret = 0 ;
}
kfree ( msg ) ;
return ret ;
}
/**
* cros_ec_keyb_query_switches - Query the state of switches and report
*
* This will ask the EC about the current state of switches and report to the
* kernel . Note that we don ' t query for buttons because they are more
* transitory and we ' ll get an update on the next release / press .
*
* @ ckdev : The keyboard device
*
* Returns 0 if no error or - error upon error .
*/
static int cros_ec_keyb_query_switches ( struct cros_ec_keyb * ckdev )
{
struct cros_ec_device * ec_dev = ckdev - > ec ;
union ec_response_get_next_data event_data = { } ;
int ret ;
ret = cros_ec_keyb_info ( ec_dev , EC_MKBP_INFO_CURRENT ,
EC_MKBP_EVENT_SWITCH , & event_data ,
sizeof ( event_data . switches ) ) ;
if ( ret )
return ret ;
cros_ec_keyb_report_bs ( ckdev , EV_SW ,
get_unaligned_le32 ( & event_data . switches ) ) ;
return 0 ;
}
/**
* cros_ec_keyb_resume - Resume the keyboard
*
* We use the resume notification as a chance to query the EC for switches .
*
* @ dev : The keyboard device
*
* Returns 0 if no error or - error upon error .
*/
static __maybe_unused int cros_ec_keyb_resume ( struct device * dev )
{
struct cros_ec_keyb * ckdev = dev_get_drvdata ( dev ) ;
if ( ckdev - > bs_idev )
return cros_ec_keyb_query_switches ( ckdev ) ;
return 0 ;
}
/**
* cros_ec_keyb_register_bs - Register non - matrix buttons / switches
*
* Handles all the bits of the keyboard driver related to non - matrix buttons
* and switches , including asking the EC about which are present and telling
* the kernel to expect them .
*
* If this device has no support for buttons and switches we ' ll return no error
* but the ckdev - > bs_idev will remain NULL when this function exits .
*
* @ ckdev : The keyboard device
*
* Returns 0 if no error or - error upon error .
*/
static int cros_ec_keyb_register_bs ( struct cros_ec_keyb * ckdev )
{
struct cros_ec_device * ec_dev = ckdev - > ec ;
struct device * dev = ckdev - > dev ;
2013-02-25 14:08:41 -08:00
struct input_dev * idev ;
2017-01-20 11:14:15 +01:00
union ec_response_get_next_data event_data = { } ;
const char * phys ;
u32 buttons ;
u32 switches ;
int ret ;
int i ;
ret = cros_ec_keyb_info ( ec_dev , EC_MKBP_INFO_SUPPORTED ,
EC_MKBP_EVENT_BUTTON , & event_data ,
sizeof ( event_data . buttons ) ) ;
if ( ret )
return ret ;
buttons = get_unaligned_le32 ( & event_data . buttons ) ;
ret = cros_ec_keyb_info ( ec_dev , EC_MKBP_INFO_SUPPORTED ,
EC_MKBP_EVENT_SWITCH , & event_data ,
sizeof ( event_data . switches ) ) ;
if ( ret )
return ret ;
switches = get_unaligned_le32 ( & event_data . switches ) ;
if ( ! buttons & & ! switches )
return 0 ;
2013-02-25 14:08:41 -08:00
2017-01-20 11:14:15 +01:00
/*
* We call the non - matrix buttons / switches ' input1 ' , if present .
* Allocate phys before input dev , to ensure correct tear - down
* ordering .
*/
phys = devm_kasprintf ( dev , GFP_KERNEL , " %s/input1 " , ec_dev - > phys_name ) ;
if ( ! phys )
return - ENOMEM ;
2013-02-25 14:08:41 -08:00
2017-01-20 11:14:15 +01:00
idev = devm_input_allocate_device ( dev ) ;
if ( ! idev )
2013-02-25 14:08:41 -08:00
return - ENOMEM ;
2016-11-11 12:43:12 -08:00
2017-01-20 11:14:15 +01:00
idev - > name = " cros_ec_buttons " ;
idev - > phys = phys ;
__set_bit ( EV_REP , idev - > evbit ) ;
idev - > id . bustype = BUS_VIRTUAL ;
idev - > id . version = 1 ;
idev - > id . product = 0 ;
idev - > dev . parent = dev ;
input_set_drvdata ( idev , ckdev ) ;
ckdev - > bs_idev = idev ;
for ( i = 0 ; i < ARRAY_SIZE ( cros_ec_keyb_bs ) ; i + + ) {
const struct cros_ec_bs_map * map = & cros_ec_keyb_bs [ i ] ;
if ( buttons & BIT ( map - > bit ) )
input_set_capability ( idev , map - > ev_type , map - > code ) ;
}
ret = cros_ec_keyb_query_switches ( ckdev ) ;
if ( ret ) {
dev_err ( dev , " cannot query switches \n " ) ;
return ret ;
}
ret = input_register_device ( ckdev - > bs_idev ) ;
if ( ret ) {
dev_err ( dev , " cannot register input device \n " ) ;
return ret ;
}
return 0 ;
}
/**
* cros_ec_keyb_register_bs - Register matrix keys
*
* Handles all the bits of the keyboard driver related to matrix keys .
*
* @ ckdev : The keyboard device
*
* Returns 0 if no error or - error upon error .
*/
static int cros_ec_keyb_register_matrix ( struct cros_ec_keyb * ckdev )
{
struct cros_ec_device * ec_dev = ckdev - > ec ;
struct device * dev = ckdev - > dev ;
struct input_dev * idev ;
const char * phys ;
int err ;
2016-11-11 12:43:12 -08:00
err = matrix_keypad_parse_properties ( dev , & ckdev - > rows , & ckdev - > cols ) ;
2013-02-25 14:08:41 -08:00
if ( err )
return err ;
2014-09-03 16:56:12 -07:00
2016-07-25 13:47:52 -07:00
ckdev - > valid_keys = devm_kzalloc ( dev , ckdev - > cols , GFP_KERNEL ) ;
2014-09-03 16:56:12 -07:00
if ( ! ckdev - > valid_keys )
return - ENOMEM ;
2016-07-25 13:47:52 -07:00
ckdev - > old_kb_state = devm_kzalloc ( dev , ckdev - > cols , GFP_KERNEL ) ;
2013-12-29 16:52:46 -08:00
if ( ! ckdev - > old_kb_state )
return - ENOMEM ;
2013-02-25 14:08:41 -08:00
2017-01-20 11:14:15 +01:00
/*
* We call the keyboard matrix ' input0 ' . Allocate phys before input
* dev , to ensure correct tear - down ordering .
*/
phys = devm_kasprintf ( dev , GFP_KERNEL , " %s/input0 " , ec_dev - > phys_name ) ;
if ( ! phys )
return - ENOMEM ;
2016-07-25 13:47:52 -07:00
idev = devm_input_allocate_device ( dev ) ;
2013-02-25 14:08:41 -08:00
if ( ! idev )
return - ENOMEM ;
2015-06-09 13:04:47 +02:00
idev - > name = CROS_EC_DEV_NAME ;
2017-01-20 11:14:15 +01:00
idev - > phys = phys ;
2013-02-25 14:08:41 -08:00
__set_bit ( EV_REP , idev - > evbit ) ;
idev - > id . bustype = BUS_VIRTUAL ;
idev - > id . version = 1 ;
idev - > id . product = 0 ;
2016-07-25 13:47:52 -07:00
idev - > dev . parent = dev ;
2013-02-25 14:08:41 -08:00
2017-01-20 11:14:15 +01:00
ckdev - > ghost_filter = of_property_read_bool ( dev - > of_node ,
2013-02-25 14:08:41 -08:00
" google,needs-ghost-filter " ) ;
err = matrix_keypad_build_keymap ( NULL , NULL , ckdev - > rows , ckdev - > cols ,
NULL , idev ) ;
if ( err ) {
dev_err ( dev , " cannot build key matrix \n " ) ;
return err ;
}
ckdev - > row_shift = get_count_order ( ckdev - > cols ) ;
input_set_capability ( idev , EV_MSC , MSC_SCAN ) ;
input_set_drvdata ( idev , ckdev ) ;
ckdev - > idev = idev ;
2014-09-03 16:56:12 -07:00
cros_ec_keyb_compute_valid_keys ( ckdev ) ;
2013-02-25 14:08:41 -08:00
err = input_register_device ( ckdev - > idev ) ;
if ( err ) {
dev_err ( dev , " cannot register input device \n " ) ;
return err ;
}
return 0 ;
}
2017-01-20 11:14:15 +01:00
static int cros_ec_keyb_probe ( struct platform_device * pdev )
{
struct cros_ec_device * ec = dev_get_drvdata ( pdev - > dev . parent ) ;
struct device * dev = & pdev - > dev ;
struct cros_ec_keyb * ckdev ;
int err ;
if ( ! dev - > of_node )
return - ENODEV ;
ckdev = devm_kzalloc ( dev , sizeof ( * ckdev ) , GFP_KERNEL ) ;
if ( ! ckdev )
return - ENOMEM ;
ckdev - > ec = ec ;
ckdev - > dev = dev ;
dev_set_drvdata ( dev , ckdev ) ;
err = cros_ec_keyb_register_matrix ( ckdev ) ;
if ( err ) {
dev_err ( dev , " cannot register matrix inputs: %d \n " , err ) ;
return err ;
}
err = cros_ec_keyb_register_bs ( ckdev ) ;
if ( err ) {
dev_err ( dev , " cannot register non-matrix inputs: %d \n " , err ) ;
return err ;
}
ckdev - > notifier . notifier_call = cros_ec_keyb_work ;
err = blocking_notifier_chain_register ( & ckdev - > ec - > event_notifier ,
& ckdev - > notifier ) ;
if ( err ) {
dev_err ( dev , " cannot register notifier: %d \n " , err ) ;
return err ;
}
return 0 ;
}
static int cros_ec_keyb_remove ( struct platform_device * pdev )
{
struct cros_ec_keyb * ckdev = dev_get_drvdata ( & pdev - > dev ) ;
blocking_notifier_chain_unregister ( & ckdev - > ec - > event_notifier ,
& ckdev - > notifier ) ;
return 0 ;
}
2014-10-08 11:38:21 -07:00
# ifdef CONFIG_OF
static const struct of_device_id cros_ec_keyb_of_match [ ] = {
{ . compatible = " google,cros-ec-keyb " } ,
{ } ,
} ;
MODULE_DEVICE_TABLE ( of , cros_ec_keyb_of_match ) ;
# endif
2017-05-11 10:14:06 -07:00
static SIMPLE_DEV_PM_OPS ( cros_ec_keyb_pm_ops , NULL , cros_ec_keyb_resume ) ;
2017-01-20 11:14:15 +01:00
2013-02-25 14:08:41 -08:00
static struct platform_driver cros_ec_keyb_driver = {
. probe = cros_ec_keyb_probe ,
2017-01-20 11:14:15 +01:00
. remove = cros_ec_keyb_remove ,
2013-02-25 14:08:41 -08:00
. driver = {
. name = " cros-ec-keyb " ,
2014-10-08 11:38:21 -07:00
. of_match_table = of_match_ptr ( cros_ec_keyb_of_match ) ,
2017-01-20 11:14:15 +01:00
. pm = & cros_ec_keyb_pm_ops ,
2013-02-25 14:08:41 -08:00
} ,
} ;
module_platform_driver ( cros_ec_keyb_driver ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_DESCRIPTION ( " ChromeOS EC keyboard driver " ) ;
MODULE_ALIAS ( " platform:cros-ec-keyb " ) ;