2019-06-04 10:11:33 +02:00
// SPDX-License-Identifier: GPL-2.0-only
2007-06-14 23:32:35 -04:00
/*
* Driver for simulating a mouse on GPIO lines .
*
* Copyright ( C ) 2007 Atmel Corporation
2017-10-19 16:24:24 -07:00
* Copyright ( C ) 2017 Linus Walleij < linus . walleij @ linaro . org >
2007-06-14 23:32:35 -04:00
*/
# include <linux/module.h>
# include <linux/platform_device.h>
2019-09-17 08:56:50 -07:00
# include <linux/input.h>
2017-10-19 16:24:24 -07:00
# include <linux/gpio/consumer.h>
# include <linux/property.h>
2017-10-19 16:28:46 -07:00
# include <linux/of.h>
2017-10-19 16:19:03 -07:00
/**
2017-10-19 16:19:41 -07:00
* struct gpio_mouse
2017-10-19 16:24:24 -07:00
* @ scan_ms : the scan interval in milliseconds .
2017-10-19 16:19:03 -07:00
* @ up : GPIO line for up value .
* @ down : GPIO line for down value .
* @ left : GPIO line for left value .
* @ right : GPIO line for right value .
* @ bleft : GPIO line for left button .
* @ bmiddle : GPIO line for middle button .
* @ bright : GPIO line for right button .
*
* This struct must be added to the platform_device in the board code .
* It is used by the gpio_mouse driver to setup GPIO lines and to
* calculate mouse movement .
*/
2017-10-19 16:19:41 -07:00
struct gpio_mouse {
2017-10-19 16:24:24 -07:00
u32 scan_ms ;
struct gpio_desc * up ;
struct gpio_desc * down ;
struct gpio_desc * left ;
struct gpio_desc * right ;
struct gpio_desc * bleft ;
struct gpio_desc * bmiddle ;
struct gpio_desc * bright ;
2017-10-19 16:19:03 -07:00
} ;
2007-06-14 23:32:35 -04:00
/*
* Timer function which is run every scan_ms ms when the device is opened .
2022-06-22 14:21:00 +08:00
* The dev input variable is set to the input_dev pointer .
2007-06-14 23:32:35 -04:00
*/
2019-09-17 08:56:50 -07:00
static void gpio_mouse_scan ( struct input_dev * input )
2007-06-14 23:32:35 -04:00
{
2019-09-17 08:56:50 -07:00
struct gpio_mouse * gpio = input_get_drvdata ( input ) ;
2007-06-14 23:32:35 -04:00
int x , y ;
2017-10-19 16:24:24 -07:00
if ( gpio - > bleft )
2007-06-14 23:32:35 -04:00
input_report_key ( input , BTN_LEFT ,
2017-10-19 16:24:24 -07:00
gpiod_get_value ( gpio - > bleft ) ) ;
if ( gpio - > bmiddle )
2007-06-14 23:32:35 -04:00
input_report_key ( input , BTN_MIDDLE ,
2017-10-19 16:24:24 -07:00
gpiod_get_value ( gpio - > bmiddle ) ) ;
if ( gpio - > bright )
2007-06-14 23:32:35 -04:00
input_report_key ( input , BTN_RIGHT ,
2017-10-19 16:24:24 -07:00
gpiod_get_value ( gpio - > bright ) ) ;
2007-06-14 23:32:35 -04:00
2017-10-19 16:24:24 -07:00
x = gpiod_get_value ( gpio - > right ) - gpiod_get_value ( gpio - > left ) ;
y = gpiod_get_value ( gpio - > down ) - gpiod_get_value ( gpio - > up ) ;
2007-06-14 23:32:35 -04:00
input_report_rel ( input , REL_X , x ) ;
input_report_rel ( input , REL_Y , y ) ;
input_sync ( input ) ;
}
2012-11-23 21:38:25 -08:00
static int gpio_mouse_probe ( struct platform_device * pdev )
2007-06-14 23:32:35 -04:00
{
2017-10-19 16:19:03 -07:00
struct device * dev = & pdev - > dev ;
2017-10-19 16:19:41 -07:00
struct gpio_mouse * gmouse ;
2007-06-14 23:32:35 -04:00
struct input_dev * input ;
2019-09-17 08:56:50 -07:00
int error ;
2007-06-14 23:32:35 -04:00
2017-10-19 16:19:41 -07:00
gmouse = devm_kzalloc ( dev , sizeof ( * gmouse ) , GFP_KERNEL ) ;
if ( ! gmouse )
2017-10-19 16:19:03 -07:00
return - ENOMEM ;
2007-06-14 23:32:35 -04:00
2017-10-19 16:24:24 -07:00
/* Assign some default scanning time */
2019-09-17 08:56:50 -07:00
error = device_property_read_u32 ( dev , " scan-interval-ms " ,
& gmouse - > scan_ms ) ;
if ( error | | gmouse - > scan_ms = = 0 ) {
2017-10-19 16:24:24 -07:00
dev_warn ( dev , " invalid scan time, set to 50 ms \n " ) ;
gmouse - > scan_ms = 50 ;
2007-06-14 23:32:35 -04:00
}
2017-10-19 16:24:24 -07:00
gmouse - > up = devm_gpiod_get ( dev , " up " , GPIOD_IN ) ;
if ( IS_ERR ( gmouse - > up ) )
return PTR_ERR ( gmouse - > up ) ;
gmouse - > down = devm_gpiod_get ( dev , " down " , GPIOD_IN ) ;
if ( IS_ERR ( gmouse - > down ) )
return PTR_ERR ( gmouse - > down ) ;
gmouse - > left = devm_gpiod_get ( dev , " left " , GPIOD_IN ) ;
if ( IS_ERR ( gmouse - > left ) )
return PTR_ERR ( gmouse - > left ) ;
gmouse - > right = devm_gpiod_get ( dev , " right " , GPIOD_IN ) ;
if ( IS_ERR ( gmouse - > right ) )
return PTR_ERR ( gmouse - > right ) ;
gmouse - > bleft = devm_gpiod_get_optional ( dev , " button-left " , GPIOD_IN ) ;
if ( IS_ERR ( gmouse - > bleft ) )
return PTR_ERR ( gmouse - > bleft ) ;
gmouse - > bmiddle = devm_gpiod_get_optional ( dev , " button-middle " ,
GPIOD_IN ) ;
if ( IS_ERR ( gmouse - > bmiddle ) )
return PTR_ERR ( gmouse - > bmiddle ) ;
gmouse - > bright = devm_gpiod_get_optional ( dev , " button-right " ,
GPIOD_IN ) ;
if ( IS_ERR ( gmouse - > bright ) )
return PTR_ERR ( gmouse - > bright ) ;
2019-09-17 08:56:50 -07:00
input = devm_input_allocate_device ( dev ) ;
if ( ! input )
2017-10-19 16:24:24 -07:00
return - ENOMEM ;
2007-06-14 23:32:35 -04:00
input - > name = pdev - > name ;
input - > id . bustype = BUS_HOST ;
2019-09-17 08:56:50 -07:00
input_set_drvdata ( input , gmouse ) ;
2007-06-14 23:32:35 -04:00
input_set_capability ( input , EV_REL , REL_X ) ;
input_set_capability ( input , EV_REL , REL_Y ) ;
2017-10-19 16:24:24 -07:00
if ( gmouse - > bleft )
2007-06-14 23:32:35 -04:00
input_set_capability ( input , EV_KEY , BTN_LEFT ) ;
2017-10-19 16:24:24 -07:00
if ( gmouse - > bmiddle )
2007-06-14 23:32:35 -04:00
input_set_capability ( input , EV_KEY , BTN_MIDDLE ) ;
2017-10-19 16:24:24 -07:00
if ( gmouse - > bright )
2007-06-14 23:32:35 -04:00
input_set_capability ( input , EV_KEY , BTN_RIGHT ) ;
2019-09-17 08:56:50 -07:00
error = input_setup_polling ( input , gpio_mouse_scan ) ;
if ( error )
return error ;
input_set_poll_interval ( input , gmouse - > scan_ms ) ;
error = input_register_device ( input ) ;
if ( error ) {
2017-10-19 16:24:24 -07:00
dev_err ( dev , " could not register input device \n " ) ;
2019-09-17 08:56:50 -07:00
return error ;
2007-06-14 23:32:35 -04:00
}
2017-10-19 16:24:24 -07:00
dev_dbg ( dev , " %d ms scan time, buttons: %s%s%s \n " ,
gmouse - > scan_ms ,
gmouse - > bleft ? " " : " left " ,
gmouse - > bmiddle ? " " : " middle " ,
gmouse - > bright ? " " : " right " ) ;
2007-06-14 23:32:35 -04:00
return 0 ;
}
2017-10-19 16:28:46 -07:00
static const struct of_device_id gpio_mouse_of_match [ ] = {
{ . compatible = " gpio-mouse " , } ,
{ } ,
} ;
MODULE_DEVICE_TABLE ( of , gpio_mouse_of_match ) ;
2008-12-20 05:19:43 -05:00
static struct platform_driver gpio_mouse_device_driver = {
2009-07-07 22:11:52 -07:00
. probe = gpio_mouse_probe ,
2007-06-14 23:32:35 -04:00
. driver = {
. name = " gpio_mouse " ,
2017-10-19 16:28:46 -07:00
. of_match_table = gpio_mouse_of_match ,
2007-06-14 23:32:35 -04:00
}
} ;
2011-11-29 11:08:41 -08:00
module_platform_driver ( gpio_mouse_device_driver ) ;
2007-06-14 23:32:35 -04:00
2011-06-29 00:13:26 -07:00
MODULE_AUTHOR ( " Hans-Christian Egtvedt <egtvedt@samfundet.no> " ) ;
2007-06-14 23:32:35 -04:00
MODULE_DESCRIPTION ( " GPIO mouse driver " ) ;
MODULE_LICENSE ( " GPL " ) ;
2009-07-07 22:11:52 -07:00
MODULE_ALIAS ( " platform:gpio_mouse " ) ; /* work with hotplug and coldplug */