2014-12-28 07:37:37 +03:00
/*
2016-09-10 20:42:53 +03:00
* Texas Instruments ' TPS65217 and TPS65218 Power Button Input Driver
2014-12-28 07:37:37 +03:00
*
* Copyright ( C ) 2014 Texas Instruments Incorporated - http : //www.ti.com/
* Author : Felipe Balbi < balbi @ ti . com >
2016-09-10 20:42:53 +03:00
* Author : Marcin Niestroj < m . niestroj @ grinn - global . com >
2014-12-28 07:37:37 +03:00
*
* 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 .
*
* This program is distributed " as is " WITHOUT ANY WARRANTY of any
* kind , whether express or implied ; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*/
# include <linux/init.h>
# include <linux/input.h>
# include <linux/interrupt.h>
# include <linux/kernel.h>
2016-09-10 20:42:53 +03:00
# include <linux/mfd/tps65217.h>
2014-12-28 07:37:37 +03:00
# include <linux/mfd/tps65218.h>
# include <linux/module.h>
# include <linux/of.h>
# include <linux/platform_device.h>
2016-09-10 20:42:53 +03:00
# include <linux/regmap.h>
2014-12-28 07:37:37 +03:00
# include <linux/slab.h>
2016-09-10 20:42:53 +03:00
struct tps6521x_data {
unsigned int reg_status ;
unsigned int pb_mask ;
const char * name ;
} ;
static const struct tps6521x_data tps65217_data = {
. reg_status = TPS65217_REG_STATUS ,
. pb_mask = TPS65217_STATUS_PB ,
. name = " tps65217_pwrbutton " ,
} ;
static const struct tps6521x_data tps65218_data = {
. reg_status = TPS65218_REG_STATUS ,
. pb_mask = TPS65218_STATUS_PB_STATE ,
. name = " tps65218_pwrbutton " ,
} ;
struct tps6521x_pwrbutton {
2014-12-28 07:37:37 +03:00
struct device * dev ;
2016-09-10 20:42:53 +03:00
struct regmap * regmap ;
2014-12-28 07:37:37 +03:00
struct input_dev * idev ;
2016-09-10 20:42:53 +03:00
const struct tps6521x_data * data ;
char phys [ 32 ] ;
} ;
static const struct of_device_id of_tps6521x_pb_match [ ] = {
{ . compatible = " ti,tps65217-pwrbutton " , . data = & tps65217_data } ,
{ . compatible = " ti,tps65218-pwrbutton " , . data = & tps65218_data } ,
{ } ,
2014-12-28 07:37:37 +03:00
} ;
2016-09-10 20:42:53 +03:00
MODULE_DEVICE_TABLE ( of , of_tps6521x_pb_match ) ;
2014-12-28 07:37:37 +03:00
2016-09-10 20:42:53 +03:00
static irqreturn_t tps6521x_pb_irq ( int irq , void * _pwr )
2014-12-28 07:37:37 +03:00
{
2016-09-10 20:42:53 +03:00
struct tps6521x_pwrbutton * pwr = _pwr ;
const struct tps6521x_data * tps_data = pwr - > data ;
2014-12-28 07:37:37 +03:00
unsigned int reg ;
int error ;
2016-09-10 20:42:53 +03:00
error = regmap_read ( pwr - > regmap , tps_data - > reg_status , & reg ) ;
2014-12-28 07:37:37 +03:00
if ( error ) {
dev_err ( pwr - > dev , " can't read register: %d \n " , error ) ;
goto out ;
}
2016-09-10 20:42:53 +03:00
if ( reg & tps_data - > pb_mask ) {
2014-12-28 07:37:37 +03:00
input_report_key ( pwr - > idev , KEY_POWER , 1 ) ;
pm_wakeup_event ( pwr - > dev , 0 ) ;
} else {
input_report_key ( pwr - > idev , KEY_POWER , 0 ) ;
}
input_sync ( pwr - > idev ) ;
out :
return IRQ_HANDLED ;
}
2016-09-10 20:42:53 +03:00
static int tps6521x_pb_probe ( struct platform_device * pdev )
2014-12-28 07:37:37 +03:00
{
struct device * dev = & pdev - > dev ;
2016-09-10 20:42:53 +03:00
struct tps6521x_pwrbutton * pwr ;
2014-12-28 07:37:37 +03:00
struct input_dev * idev ;
2016-09-10 20:42:53 +03:00
const struct of_device_id * match ;
2014-12-28 07:37:37 +03:00
int error ;
int irq ;
2016-09-10 20:42:53 +03:00
match = of_match_node ( of_tps6521x_pb_match , pdev - > dev . of_node ) ;
if ( ! match )
return - ENXIO ;
2014-12-28 07:37:37 +03:00
pwr = devm_kzalloc ( dev , sizeof ( * pwr ) , GFP_KERNEL ) ;
if ( ! pwr )
return - ENOMEM ;
2016-09-10 20:42:53 +03:00
pwr - > data = match - > data ;
2014-12-28 07:37:37 +03:00
idev = devm_input_allocate_device ( dev ) ;
if ( ! idev )
return - ENOMEM ;
2016-09-10 20:42:53 +03:00
idev - > name = pwr - > data - > name ;
snprintf ( pwr - > phys , sizeof ( pwr - > phys ) , " %s/input0 " ,
pwr - > data - > name ) ;
idev - > phys = pwr - > phys ;
2014-12-28 07:37:37 +03:00
idev - > dev . parent = dev ;
idev - > id . bustype = BUS_I2C ;
input_set_capability ( idev , EV_KEY , KEY_POWER ) ;
2016-09-10 20:42:53 +03:00
pwr - > regmap = dev_get_regmap ( pdev - > dev . parent , NULL ) ;
2014-12-28 07:37:37 +03:00
pwr - > dev = dev ;
pwr - > idev = idev ;
platform_set_drvdata ( pdev , pwr ) ;
device_init_wakeup ( dev , true ) ;
irq = platform_get_irq ( pdev , 0 ) ;
2016-09-10 20:42:53 +03:00
if ( irq < 0 ) {
dev_err ( dev , " No IRQ resource! \n " ) ;
return - EINVAL ;
}
error = devm_request_threaded_irq ( dev , irq , NULL , tps6521x_pb_irq ,
2014-12-28 07:37:37 +03:00
IRQF_TRIGGER_RISING |
IRQF_TRIGGER_FALLING |
IRQF_ONESHOT ,
2016-09-10 20:42:53 +03:00
pwr - > data - > name , pwr ) ;
2014-12-28 07:37:37 +03:00
if ( error ) {
dev_err ( dev , " failed to request IRQ #%d: %d \n " ,
irq , error ) ;
return error ;
}
error = input_register_device ( idev ) ;
if ( error ) {
dev_err ( dev , " Can't register power button: %d \n " , error ) ;
return error ;
}
return 0 ;
}
2016-09-10 20:42:53 +03:00
static struct platform_driver tps6521x_pb_driver = {
. probe = tps6521x_pb_probe ,
2014-12-28 07:37:37 +03:00
. driver = {
2016-09-10 20:42:53 +03:00
. name = " tps6521x_pwrbutton " ,
. of_match_table = of_tps6521x_pb_match ,
2014-12-28 07:37:37 +03:00
} ,
} ;
2016-09-10 20:42:53 +03:00
module_platform_driver ( tps6521x_pb_driver ) ;
2014-12-28 07:37:37 +03:00
2016-09-10 20:42:53 +03:00
MODULE_DESCRIPTION ( " TPS6521X Power Button " ) ;
2014-12-28 07:37:37 +03:00
MODULE_LICENSE ( " GPL v2 " ) ;
MODULE_AUTHOR ( " Felipe Balbi <balbi@ti.com> " ) ;