2012-03-14 08:35:51 +04:00
/*
2012-05-11 09:37:08 +04:00
* Helpers for matrix keyboard bindings
2012-03-14 08:35:51 +04:00
*
* Copyright ( C ) 2012 Google , Inc
*
* Author :
* Olof Johansson < olof @ lixom . net >
*
* 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 .
*/
2012-05-11 09:37:15 +04:00
# include <linux/device.h>
2016-11-11 23:43:12 +03:00
# include <linux/export.h>
2012-11-05 22:32:55 +04:00
# include <linux/gfp.h>
2012-03-14 08:35:51 +04:00
# include <linux/input.h>
2012-05-11 09:37:08 +04:00
# include <linux/input/matrix_keypad.h>
2016-11-11 23:43:12 +03:00
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/property.h>
# include <linux/slab.h>
# include <linux/types.h>
2012-05-11 09:37:08 +04:00
2012-05-11 09:37:15 +04:00
static bool matrix_keypad_map_key ( struct input_dev * input_dev ,
unsigned int rows , unsigned int cols ,
unsigned int row_shift , unsigned int key )
{
2012-05-24 12:10:20 +04:00
unsigned short * keymap = input_dev - > keycode ;
2012-05-11 09:37:15 +04:00
unsigned int row = KEY_ROW ( key ) ;
unsigned int col = KEY_COL ( key ) ;
unsigned short code = KEY_VAL ( key ) ;
if ( row > = rows | | col > = cols ) {
dev_err ( input_dev - > dev . parent ,
" %s: invalid keymap entry 0x%x (row: %d, col: %d, rows: %d, cols: %d) \n " ,
__func__ , key , row , col , rows , cols ) ;
return false ;
}
keymap [ MATRIX_SCAN_CODE ( row , col , row_shift ) ] = code ;
__set_bit ( code , input_dev - > keybit ) ;
return true ;
}
2016-11-11 23:43:12 +03:00
/**
* matrix_keypad_parse_properties ( ) - Read properties of matrix keypad
*
* @ dev : Device containing properties
* @ rows : Returns number of matrix rows
* @ cols : Returns number of matrix columns
* @ return 0 if OK , < 0 on error
*/
int matrix_keypad_parse_properties ( struct device * dev ,
unsigned int * rows , unsigned int * cols )
2013-02-26 02:08:40 +04:00
{
2016-11-11 23:43:12 +03:00
* rows = * cols = 0 ;
device_property_read_u32 ( dev , " keypad,num-rows " , rows ) ;
device_property_read_u32 ( dev , " keypad,num-columns " , cols ) ;
2013-02-26 02:08:40 +04:00
if ( ! * rows | | ! * cols ) {
dev_err ( dev , " number of keypad rows/columns not specified \n " ) ;
return - EINVAL ;
}
return 0 ;
}
2016-11-11 23:43:12 +03:00
EXPORT_SYMBOL_GPL ( matrix_keypad_parse_properties ) ;
2013-02-26 02:08:40 +04:00
2016-11-11 23:43:12 +03:00
static int matrix_keypad_parse_keymap ( const char * propname ,
unsigned int rows , unsigned int cols ,
struct input_dev * input_dev )
2012-05-11 09:37:15 +04:00
{
struct device * dev = input_dev - > dev . parent ;
unsigned int row_shift = get_count_order ( cols ) ;
unsigned int max_keys = rows < < row_shift ;
2016-11-11 23:43:12 +03:00
u32 * keys ;
int i ;
int size ;
int retval ;
2012-05-11 09:37:15 +04:00
if ( ! propname )
propname = " linux,keymap " ;
2016-11-11 23:43:12 +03:00
size = device_property_read_u32_array ( dev , propname , NULL , 0 ) ;
if ( size < = 0 ) {
dev_err ( dev , " missing or malformed property %s: %d \n " ,
propname , size ) ;
return size < 0 ? size : - EINVAL ;
2012-05-11 09:37:15 +04:00
}
2016-11-11 23:43:12 +03:00
if ( size > max_keys ) {
dev_err ( dev , " %s size overflow (%d vs max %u) \n " ,
propname , size , max_keys ) ;
2012-05-11 09:37:15 +04:00
return - EINVAL ;
}
2016-11-11 23:43:12 +03:00
keys = kmalloc_array ( size , sizeof ( u32 ) , GFP_KERNEL ) ;
if ( ! keys )
return - ENOMEM ;
retval = device_property_read_u32_array ( dev , propname , keys , size ) ;
if ( retval ) {
dev_err ( dev , " failed to read %s property: %d \n " ,
propname , retval ) ;
goto out ;
2012-05-11 09:37:15 +04:00
}
for ( i = 0 ; i < size ; i + + ) {
if ( ! matrix_keypad_map_key ( input_dev , rows , cols ,
2016-11-11 23:43:12 +03:00
row_shift , keys [ i ] ) ) {
retval = - EINVAL ;
goto out ;
}
2012-05-11 09:37:15 +04:00
}
2016-11-11 23:43:12 +03:00
retval = 0 ;
out :
kfree ( keys ) ;
return retval ;
2012-05-11 09:37:15 +04:00
}
2012-05-11 09:37:08 +04:00
/**
* matrix_keypad_build_keymap - convert platform keymap into matrix keymap
* @ keymap_data : keymap supplied by the platform code
* @ keymap_name : name of device tree property containing keymap ( if device
* tree support is enabled ) .
* @ rows : number of rows in target keymap array
* @ cols : number of cols in target keymap array
* @ keymap : expanded version of keymap that is suitable for use by
* matrix keyboard driver
* @ input_dev : input devices for which we are setting up the keymap
*
* This function converts platform keymap ( encoded with KEY ( ) macro ) into
* an array of keycodes that is suitable for using in a standard matrix
* keyboard driver that uses row and col as indices .
2012-05-11 09:37:15 +04:00
*
* If @ keymap_data is not supplied and device tree support is enabled
* it will attempt load the keymap from property specified by @ keymap_name
* argument ( or " linux,keymap " if @ keymap_name is % NULL ) .
*
2012-11-05 22:32:55 +04:00
* If @ keymap is % NULL the function will automatically allocate managed
* block of memory to store the keymap . This memory will be associated with
* the parent device and automatically freed when device unbinds from the
* driver .
*
2012-05-11 09:37:15 +04:00
* Callers are expected to set up input_dev - > dev . parent before calling this
* function .
2012-05-11 09:37:08 +04:00
*/
int matrix_keypad_build_keymap ( const struct matrix_keymap_data * keymap_data ,
const char * keymap_name ,
unsigned int rows , unsigned int cols ,
unsigned short * keymap ,
struct input_dev * input_dev )
{
unsigned int row_shift = get_count_order ( cols ) ;
2012-11-05 22:32:55 +04:00
size_t max_keys = rows < < row_shift ;
2012-05-11 09:37:08 +04:00
int i ;
2012-05-11 09:37:15 +04:00
int error ;
2012-05-11 09:37:08 +04:00
2012-11-05 22:32:55 +04:00
if ( WARN_ON ( ! input_dev - > dev . parent ) )
return - EINVAL ;
if ( ! keymap ) {
keymap = devm_kzalloc ( input_dev - > dev . parent ,
max_keys * sizeof ( * keymap ) ,
GFP_KERNEL ) ;
if ( ! keymap ) {
dev_err ( input_dev - > dev . parent ,
" Unable to allocate memory for keymap " ) ;
return - ENOMEM ;
}
}
2012-05-11 09:37:08 +04:00
input_dev - > keycode = keymap ;
input_dev - > keycodesize = sizeof ( * keymap ) ;
2012-11-05 22:32:55 +04:00
input_dev - > keycodemax = max_keys ;
2012-05-11 09:37:08 +04:00
__set_bit ( EV_KEY , input_dev - > evbit ) ;
2012-05-11 09:37:15 +04:00
if ( keymap_data ) {
for ( i = 0 ; i < keymap_data - > keymap_size ; i + + ) {
unsigned int key = keymap_data - > keymap [ i ] ;
2012-05-11 09:37:08 +04:00
2012-05-11 09:37:15 +04:00
if ( ! matrix_keypad_map_key ( input_dev , rows , cols ,
row_shift , key ) )
return - EINVAL ;
2012-05-11 09:37:08 +04:00
}
2012-05-11 09:37:15 +04:00
} else {
2016-11-11 23:43:12 +03:00
error = matrix_keypad_parse_keymap ( keymap_name , rows , cols ,
input_dev ) ;
2012-05-11 09:37:15 +04:00
if ( error )
return error ;
2012-05-11 09:37:08 +04:00
}
2012-05-11 09:37:15 +04:00
2012-05-11 09:37:08 +04:00
__clear_bit ( KEY_RESERVED , input_dev - > keybit ) ;
return 0 ;
}
EXPORT_SYMBOL ( matrix_keypad_build_keymap ) ;
2012-12-11 00:18:20 +04:00
MODULE_LICENSE ( " GPL " ) ;