2017-03-21 23:50:42 +01:00
/**
* CPCAP Power Button Input Driver
*
* Copyright ( C ) 2017 Sebastian Reichel < sre @ kernel . org >
*
* This file is subject to the terms and conditions of the GNU General
* Public License . See the file " COPYING " in the main directory of this
* archive for more details .
*
* 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 .
*/
# include <linux/module.h>
# include <linux/init.h>
# include <linux/kernel.h>
# include <linux/errno.h>
# include <linux/input.h>
# include <linux/interrupt.h>
# include <linux/regmap.h>
# include <linux/of.h>
# include <linux/platform_device.h>
# include <linux/mfd/motorola-cpcap.h>
# define CPCAP_IRQ_ON 23
# define CPCAP_IRQ_ON_BITMASK (1 << (CPCAP_IRQ_ON % 16))
struct cpcap_power_button {
struct regmap * regmap ;
struct input_dev * idev ;
struct device * dev ;
} ;
static irqreturn_t powerbutton_irq ( int irq , void * _button )
{
struct cpcap_power_button * button = _button ;
int val ;
val = cpcap_sense_virq ( button - > regmap , irq ) ;
if ( val < 0 ) {
dev_err ( button - > dev , " irq read failed: %d " , val ) ;
return IRQ_HANDLED ;
}
pm_wakeup_event ( button - > dev , 0 ) ;
input_report_key ( button - > idev , KEY_POWER , val ) ;
input_sync ( button - > idev ) ;
return IRQ_HANDLED ;
}
static int cpcap_power_button_probe ( struct platform_device * pdev )
{
struct cpcap_power_button * button ;
2021-09-05 18:57:32 -07:00
int irq ;
2017-03-21 23:50:42 +01:00
int err ;
2021-09-05 18:57:32 -07:00
irq = platform_get_irq ( pdev , 0 ) ;
if ( irq < 0 )
return irq ;
2017-03-21 23:50:42 +01:00
button = devm_kmalloc ( & pdev - > dev , sizeof ( * button ) , GFP_KERNEL ) ;
if ( ! button )
return - ENOMEM ;
button - > idev = devm_input_allocate_device ( & pdev - > dev ) ;
if ( ! button - > idev )
return - ENOMEM ;
button - > regmap = dev_get_regmap ( pdev - > dev . parent , NULL ) ;
if ( ! button - > regmap )
return - ENODEV ;
button - > dev = & pdev - > dev ;
button - > idev - > name = " cpcap-pwrbutton " ;
button - > idev - > phys = " cpcap-pwrbutton/input0 " ;
input_set_capability ( button - > idev , EV_KEY , KEY_POWER ) ;
err = devm_request_threaded_irq ( & pdev - > dev , irq , NULL ,
powerbutton_irq , IRQF_ONESHOT , " cpcap_pwrbutton " , button ) ;
if ( err < 0 ) {
dev_err ( & pdev - > dev , " IRQ request failed: %d \n " , err ) ;
return err ;
}
err = input_register_device ( button - > idev ) ;
if ( err ) {
dev_err ( & pdev - > dev , " Input register failed: %d \n " , err ) ;
return err ;
}
device_init_wakeup ( & pdev - > dev , true ) ;
return 0 ;
}
# ifdef CONFIG_OF
static const struct of_device_id cpcap_pwrbutton_dt_match_table [ ] = {
{ . compatible = " motorola,cpcap-pwrbutton " } ,
{ } ,
} ;
MODULE_DEVICE_TABLE ( of , cpcap_pwrbutton_dt_match_table ) ;
# endif
static struct platform_driver cpcap_power_button_driver = {
. probe = cpcap_power_button_probe ,
. driver = {
. name = " cpcap-pwrbutton " ,
. of_match_table = of_match_ptr ( cpcap_pwrbutton_dt_match_table ) ,
} ,
} ;
module_platform_driver ( cpcap_power_button_driver ) ;
MODULE_ALIAS ( " platform:cpcap-pwrbutton " ) ;
MODULE_DESCRIPTION ( " CPCAP Power Button " ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_AUTHOR ( " Sebastian Reichel <sre@kernel.org> " ) ;