2010-12-07 04:14:47 +03:00
/*
* Driver for buttons on GPIO lines not capable of generating interrupts
*
* Copyright ( C ) 2007 - 2010 Gabor Juhos < juhosg @ openwrt . org >
* Copyright ( C ) 2010 Nuno Goncalves < nunojpg @ gmail . com >
*
* This file was based on : / drivers / input / misc / cobalt_btns . c
* Copyright ( C ) 2007 Yoichi Yuasa < yoichi_yuasa @ tripeaks . co . jp >
*
* also was based on : / drivers / input / keyboard / gpio_keys . c
* Copyright 2005 Phil Blundell
*
* 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/slab.h>
# include <linux/input.h>
# include <linux/input-polldev.h>
# include <linux/ioport.h>
# include <linux/platform_device.h>
# include <linux/gpio.h>
2014-10-22 01:30:25 +04:00
# include <linux/gpio/consumer.h>
2010-12-07 04:14:47 +03:00
# include <linux/gpio_keys.h>
2014-10-21 15:34:00 +04:00
# include <linux/property.h>
2010-12-07 04:14:47 +03:00
# define DRV_NAME "gpio-keys-polled"
struct gpio_keys_button_data {
2016-02-24 02:32:14 +03:00
struct gpio_desc * gpiod ;
2010-12-07 04:14:47 +03:00
int last_state ;
int count ;
int threshold ;
} ;
struct gpio_keys_polled_dev {
struct input_polled_dev * poll_dev ;
struct device * dev ;
2012-07-30 09:48:33 +04:00
const struct gpio_keys_platform_data * pdata ;
2015-10-15 02:44:35 +03:00
unsigned long rel_axis_seen [ BITS_TO_LONGS ( REL_CNT ) ] ;
unsigned long abs_axis_seen [ BITS_TO_LONGS ( ABS_CNT ) ] ;
2010-12-07 04:14:47 +03:00
struct gpio_keys_button_data data [ 0 ] ;
} ;
2015-10-15 02:44:35 +03:00
static void gpio_keys_button_event ( struct input_polled_dev * dev ,
2016-02-24 02:32:14 +03:00
const struct gpio_keys_button * button ,
2015-10-15 02:44:35 +03:00
int state )
{
struct gpio_keys_polled_dev * bdev = dev - > private ;
struct input_dev * input = dev - > input ;
unsigned int type = button - > type ? : EV_KEY ;
if ( type = = EV_REL ) {
if ( state ) {
input_event ( input , type , button - > code , button - > value ) ;
__set_bit ( button - > code , bdev - > rel_axis_seen ) ;
}
} else if ( type = = EV_ABS ) {
if ( state ) {
input_event ( input , type , button - > code , button - > value ) ;
__set_bit ( button - > code , bdev - > abs_axis_seen ) ;
}
} else {
input_event ( input , type , button - > code , state ) ;
input_sync ( input ) ;
}
}
static void gpio_keys_polled_check_state ( struct input_polled_dev * dev ,
2016-02-24 02:32:14 +03:00
const struct gpio_keys_button * button ,
2010-12-07 04:14:47 +03:00
struct gpio_keys_button_data * bdata )
{
int state ;
2016-10-20 02:36:19 +03:00
state = gpiod_get_value_cansleep ( bdata - > gpiod ) ;
if ( state < 0 ) {
dev_err ( dev - > input - > dev . parent ,
" failed to get gpio state: %d \n " , state ) ;
} else {
gpio_keys_button_event ( dev , button , state ) ;
2010-12-07 04:14:47 +03:00
2016-10-20 02:36:19 +03:00
if ( state ! = bdata - > last_state ) {
bdata - > count = 0 ;
bdata - > last_state = state ;
}
2010-12-07 04:14:47 +03:00
}
}
static void gpio_keys_polled_poll ( struct input_polled_dev * dev )
{
struct gpio_keys_polled_dev * bdev = dev - > private ;
2012-07-30 09:48:33 +04:00
const struct gpio_keys_platform_data * pdata = bdev - > pdata ;
2010-12-07 04:14:47 +03:00
struct input_dev * input = dev - > input ;
int i ;
2015-10-15 02:44:35 +03:00
memset ( bdev - > rel_axis_seen , 0 , sizeof ( bdev - > rel_axis_seen ) ) ;
memset ( bdev - > abs_axis_seen , 0 , sizeof ( bdev - > abs_axis_seen ) ) ;
2012-07-30 09:48:33 +04:00
for ( i = 0 ; i < pdata - > nbuttons ; i + + ) {
2010-12-07 04:14:47 +03:00
struct gpio_keys_button_data * bdata = & bdev - > data [ i ] ;
2015-10-15 02:44:35 +03:00
if ( bdata - > count < bdata - > threshold ) {
2010-12-07 04:14:47 +03:00
bdata - > count + + ;
2015-10-15 02:44:35 +03:00
gpio_keys_button_event ( dev , & pdata - > buttons [ i ] ,
bdata - > last_state ) ;
} else {
gpio_keys_polled_check_state ( dev , & pdata - > buttons [ i ] ,
2010-12-07 04:14:47 +03:00
bdata ) ;
2015-10-15 02:44:35 +03:00
}
}
for_each_set_bit ( i , input - > relbit , REL_CNT ) {
if ( ! test_bit ( i , bdev - > rel_axis_seen ) )
input_event ( input , EV_REL , i , 0 ) ;
}
for_each_set_bit ( i , input - > absbit , ABS_CNT ) {
if ( ! test_bit ( i , bdev - > abs_axis_seen ) )
input_event ( input , EV_ABS , i , 0 ) ;
2010-12-07 04:14:47 +03:00
}
2015-10-15 02:44:35 +03:00
input_sync ( input ) ;
2010-12-07 04:14:47 +03:00
}
static void gpio_keys_polled_open ( struct input_polled_dev * dev )
{
struct gpio_keys_polled_dev * bdev = dev - > private ;
2012-07-30 09:48:33 +04:00
const struct gpio_keys_platform_data * pdata = bdev - > pdata ;
2010-12-07 04:14:47 +03:00
if ( pdata - > enable )
pdata - > enable ( bdev - > dev ) ;
}
static void gpio_keys_polled_close ( struct input_polled_dev * dev )
{
struct gpio_keys_polled_dev * bdev = dev - > private ;
2012-07-30 09:48:33 +04:00
const struct gpio_keys_platform_data * pdata = bdev - > pdata ;
2010-12-07 04:14:47 +03:00
if ( pdata - > disable )
pdata - > disable ( bdev - > dev ) ;
}
2016-02-24 02:32:14 +03:00
static struct gpio_keys_platform_data *
gpio_keys_polled_get_devtree_pdata ( struct device * dev )
2012-08-01 09:08:45 +04:00
{
struct gpio_keys_platform_data * pdata ;
struct gpio_keys_button * button ;
2014-10-21 15:34:00 +04:00
struct fwnode_handle * child ;
2012-08-01 09:08:45 +04:00
int nbuttons ;
2014-10-21 15:34:00 +04:00
nbuttons = device_get_child_node_count ( dev ) ;
2012-08-01 09:08:45 +04:00
if ( nbuttons = = 0 )
2016-02-24 02:32:14 +03:00
return ERR_PTR ( - EINVAL ) ;
2012-08-01 09:08:45 +04:00
2014-04-28 21:48:49 +04:00
pdata = devm_kzalloc ( dev , sizeof ( * pdata ) + nbuttons * sizeof ( * button ) ,
GFP_KERNEL ) ;
if ( ! pdata )
return ERR_PTR ( - ENOMEM ) ;
2012-08-01 09:08:45 +04:00
2016-02-24 02:32:14 +03:00
button = ( struct gpio_keys_button * ) ( pdata + 1 ) ;
pdata - > buttons = button ;
pdata - > nbuttons = nbuttons ;
2012-08-01 09:08:45 +04:00
2014-10-21 15:34:00 +04:00
pdata - > rep = device_property_present ( dev , " autorepeat " ) ;
device_property_read_u32 ( dev , " poll-interval " , & pdata - > poll_interval ) ;
2012-08-01 09:08:45 +04:00
2014-10-21 15:34:00 +04:00
device_for_each_child_node ( dev , child ) {
2016-02-24 02:32:14 +03:00
if ( fwnode_property_read_u32 ( child , " linux,code " ,
& button - > code ) ) {
dev_err ( dev , " button without keycode \n " ) ;
2014-10-21 15:34:00 +04:00
fwnode_handle_put ( child ) ;
2014-04-28 21:48:49 +04:00
return ERR_PTR ( - EINVAL ) ;
2012-08-01 09:08:45 +04:00
}
2014-10-21 15:34:00 +04:00
fwnode_property_read_string ( child , " label " , & button - > desc ) ;
2012-08-01 09:08:45 +04:00
2014-10-21 15:34:00 +04:00
if ( fwnode_property_read_u32 ( child , " linux,input-type " ,
& button - > type ) )
2012-08-01 09:08:45 +04:00
button - > type = EV_KEY ;
2015-10-15 02:44:35 +03:00
if ( fwnode_property_read_u32 ( child , " linux,input-value " ,
( u32 * ) & button - > value ) )
button - > value = 1 ;
2015-07-16 22:10:05 +03:00
button - > wakeup =
fwnode_property_read_bool ( child , " wakeup-source " ) | |
/* legacy name */
fwnode_property_read_bool ( child , " gpio-key,wakeup " ) ;
2012-08-01 09:08:45 +04:00
2014-10-21 15:34:00 +04:00
if ( fwnode_property_read_u32 ( child , " debounce-interval " ,
& button - > debounce_interval ) )
2012-08-01 09:08:45 +04:00
button - > debounce_interval = 5 ;
2016-02-24 02:32:14 +03:00
button + + ;
}
2012-08-01 09:08:45 +04:00
return pdata ;
}
2015-10-15 02:44:35 +03:00
static void gpio_keys_polled_set_abs_params ( struct input_dev * input ,
const struct gpio_keys_platform_data * pdata , unsigned int code )
{
int i , min = 0 , max = 0 ;
for ( i = 0 ; i < pdata - > nbuttons ; i + + ) {
2016-02-24 02:32:14 +03:00
const struct gpio_keys_button * button = & pdata - > buttons [ i ] ;
2015-10-15 02:44:35 +03:00
if ( button - > type ! = EV_ABS | | button - > code ! = code )
continue ;
if ( button - > value < min )
min = button - > value ;
if ( button - > value > max )
max = button - > value ;
}
2016-02-24 02:32:14 +03:00
2015-10-15 02:44:35 +03:00
input_set_abs_params ( input , code , min , max , 0 , 0 ) ;
}
2014-05-07 23:58:36 +04:00
static const struct of_device_id gpio_keys_polled_of_match [ ] = {
2012-08-01 09:08:45 +04:00
{ . compatible = " gpio-keys-polled " , } ,
{ } ,
} ;
MODULE_DEVICE_TABLE ( of , gpio_keys_polled_of_match ) ;
2012-11-24 09:38:25 +04:00
static int gpio_keys_polled_probe ( struct platform_device * pdev )
2010-12-07 04:14:47 +03:00
{
struct device * dev = & pdev - > dev ;
2016-02-24 02:32:14 +03:00
struct fwnode_handle * child = NULL ;
2012-07-30 09:48:33 +04:00
const struct gpio_keys_platform_data * pdata = dev_get_platdata ( dev ) ;
2010-12-07 04:14:47 +03:00
struct gpio_keys_polled_dev * bdev ;
struct input_polled_dev * poll_dev ;
struct input_dev * input ;
2014-04-28 21:48:49 +04:00
size_t size ;
2010-12-07 04:14:47 +03:00
int error ;
int i ;
2012-08-01 09:08:45 +04:00
if ( ! pdata ) {
pdata = gpio_keys_polled_get_devtree_pdata ( dev ) ;
if ( IS_ERR ( pdata ) )
return PTR_ERR ( pdata ) ;
}
if ( ! pdata - > poll_interval ) {
dev_err ( dev , " missing poll_interval value \n " ) ;
2014-04-28 21:48:49 +04:00
return - EINVAL ;
2012-08-01 09:08:45 +04:00
}
2010-12-07 04:14:47 +03:00
2014-04-28 21:48:49 +04:00
size = sizeof ( struct gpio_keys_polled_dev ) +
pdata - > nbuttons * sizeof ( struct gpio_keys_button_data ) ;
2017-01-22 10:40:45 +03:00
bdev = devm_kzalloc ( dev , size , GFP_KERNEL ) ;
2010-12-07 04:14:47 +03:00
if ( ! bdev ) {
dev_err ( dev , " no memory for private data \n " ) ;
2014-04-28 21:48:49 +04:00
return - ENOMEM ;
2010-12-07 04:14:47 +03:00
}
2017-01-22 10:40:45 +03:00
poll_dev = devm_input_allocate_polled_device ( dev ) ;
2010-12-07 04:14:47 +03:00
if ( ! poll_dev ) {
dev_err ( dev , " no memory for polled device \n " ) ;
2014-04-28 21:48:49 +04:00
return - ENOMEM ;
2010-12-07 04:14:47 +03:00
}
poll_dev - > private = bdev ;
poll_dev - > poll = gpio_keys_polled_poll ;
poll_dev - > poll_interval = pdata - > poll_interval ;
poll_dev - > open = gpio_keys_polled_open ;
poll_dev - > close = gpio_keys_polled_close ;
input = poll_dev - > input ;
input - > name = pdev - > name ;
input - > phys = DRV_NAME " /input0 " ;
input - > id . bustype = BUS_HOST ;
input - > id . vendor = 0x0001 ;
input - > id . product = 0x0001 ;
input - > id . version = 0x0100 ;
2012-11-29 20:57:17 +04:00
__set_bit ( EV_KEY , input - > evbit ) ;
if ( pdata - > rep )
__set_bit ( EV_REP , input - > evbit ) ;
2010-12-07 04:14:47 +03:00
for ( i = 0 ; i < pdata - > nbuttons ; i + + ) {
2016-02-24 02:32:14 +03:00
const struct gpio_keys_button * button = & pdata - > buttons [ i ] ;
2010-12-07 04:14:47 +03:00
struct gpio_keys_button_data * bdata = & bdev - > data [ i ] ;
unsigned int type = button - > type ? : EV_KEY ;
if ( button - > wakeup ) {
dev_err ( dev , DRV_NAME " does not support wakeup \n " ) ;
2016-02-24 02:32:14 +03:00
fwnode_handle_put ( child ) ;
2014-04-28 21:48:49 +04:00
return - EINVAL ;
2010-12-07 04:14:47 +03:00
}
2016-02-24 02:32:14 +03:00
if ( ! dev_get_platdata ( dev ) ) {
/* No legacy static platform data */
child = device_get_next_child_node ( dev , child ) ;
if ( ! child ) {
dev_err ( dev , " missing child device node \n " ) ;
return - EINVAL ;
}
2017-02-02 16:53:10 +03:00
bdata - > gpiod = devm_fwnode_get_gpiod_from_child ( dev ,
NULL , child ,
GPIOD_IN ,
button - > desc ) ;
2016-02-24 02:32:14 +03:00
if ( IS_ERR ( bdata - > gpiod ) ) {
error = PTR_ERR ( bdata - > gpiod ) ;
if ( error ! = - EPROBE_DEFER )
dev_err ( dev ,
" failed to get gpio: %d \n " ,
error ) ;
fwnode_handle_put ( child ) ;
return error ;
}
} else if ( gpio_is_valid ( button - > gpio ) ) {
/*
* Legacy GPIO number so request the GPIO here and
* convert it to descriptor .
*/
2015-08-20 22:00:19 +03:00
unsigned flags = GPIOF_IN ;
2014-10-22 01:30:25 +04:00
if ( button - > active_low )
flags | = GPIOF_ACTIVE_LOW ;
2017-01-22 10:40:45 +03:00
error = devm_gpio_request_one ( dev , button - > gpio ,
2014-10-22 01:30:25 +04:00
flags , button - > desc ? : DRV_NAME ) ;
if ( error ) {
2016-02-24 02:32:14 +03:00
dev_err ( dev ,
" unable to claim gpio %u, err=%d \n " ,
2014-10-22 01:30:25 +04:00
button - > gpio , error ) ;
return error ;
}
2016-02-24 02:32:14 +03:00
bdata - > gpiod = gpio_to_desc ( button - > gpio ) ;
if ( ! bdata - > gpiod ) {
dev_err ( dev ,
" unable to convert gpio %u to descriptor \n " ,
button - > gpio ) ;
return - EINVAL ;
}
2010-12-07 04:14:47 +03:00
}
bdata - > last_state = - 1 ;
bdata - > threshold = DIV_ROUND_UP ( button - > debounce_interval ,
pdata - > poll_interval ) ;
input_set_capability ( input , type , button - > code ) ;
2015-10-15 02:44:35 +03:00
if ( type = = EV_ABS )
gpio_keys_polled_set_abs_params ( input , pdata ,
button - > code ) ;
2010-12-07 04:14:47 +03:00
}
2016-02-24 02:32:14 +03:00
fwnode_handle_put ( child ) ;
2010-12-07 04:14:47 +03:00
bdev - > poll_dev = poll_dev ;
bdev - > dev = dev ;
bdev - > pdata = pdata ;
error = input_register_polled_device ( poll_dev ) ;
if ( error ) {
dev_err ( dev , " unable to register polled device, err=%d \n " ,
error ) ;
2014-04-28 21:48:49 +04:00
return error ;
2010-12-07 04:14:47 +03:00
}
/* report initial state of the buttons */
for ( i = 0 ; i < pdata - > nbuttons ; i + + )
2015-10-15 02:44:35 +03:00
gpio_keys_polled_check_state ( poll_dev , & pdata - > buttons [ i ] ,
2012-08-01 09:08:45 +04:00
& bdev - > data [ i ] ) ;
2010-12-07 04:14:47 +03:00
2015-10-15 02:44:35 +03:00
input_sync ( input ) ;
2010-12-07 04:14:47 +03:00
return 0 ;
}
static struct platform_driver gpio_keys_polled_driver = {
. probe = gpio_keys_polled_probe ,
. driver = {
. name = DRV_NAME ,
2014-10-21 15:34:00 +04:00
. of_match_table = gpio_keys_polled_of_match ,
2010-12-07 04:14:47 +03:00
} ,
} ;
2011-11-29 23:08:39 +04:00
module_platform_driver ( gpio_keys_polled_driver ) ;
2010-12-07 04:14:47 +03:00
MODULE_LICENSE ( " GPL v2 " ) ;
MODULE_AUTHOR ( " Gabor Juhos <juhosg@openwrt.org> " ) ;
MODULE_DESCRIPTION ( " Polled GPIO Buttons driver " ) ;
MODULE_ALIAS ( " platform: " DRV_NAME ) ;