2016-06-22 17:22:03 -07:00
/*
* Hisilicon PMIC powerkey driver
*
* Copyright ( C ) 2013 Hisilicon Ltd .
* Copyright ( C ) 2015 , 2016 Linaro Ltd .
*
* 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/platform_device.h>
# include <linux/interrupt.h>
# include <linux/reboot.h>
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/of_irq.h>
# include <linux/input.h>
# include <linux/slab.h>
/* the held interrupt will trigger after 4 seconds */
# define MAX_HELD_TIME (4 * MSEC_PER_SEC)
static irqreturn_t hi65xx_power_press_isr ( int irq , void * q )
{
struct input_dev * input = q ;
pm_wakeup_event ( input - > dev . parent , MAX_HELD_TIME ) ;
input_report_key ( input , KEY_POWER , 1 ) ;
input_sync ( input ) ;
return IRQ_HANDLED ;
}
static irqreturn_t hi65xx_power_release_isr ( int irq , void * q )
{
struct input_dev * input = q ;
pm_wakeup_event ( input - > dev . parent , MAX_HELD_TIME ) ;
input_report_key ( input , KEY_POWER , 0 ) ;
input_sync ( input ) ;
return IRQ_HANDLED ;
}
static irqreturn_t hi65xx_restart_toggle_isr ( int irq , void * q )
{
struct input_dev * input = q ;
int value = test_bit ( KEY_RESTART , input - > key ) ;
pm_wakeup_event ( input - > dev . parent , MAX_HELD_TIME ) ;
input_report_key ( input , KEY_RESTART , ! value ) ;
input_sync ( input ) ;
return IRQ_HANDLED ;
}
static const struct {
const char * name ;
irqreturn_t ( * handler ) ( int irq , void * q ) ;
} hi65xx_irq_info [ ] = {
{ " down " , hi65xx_power_press_isr } ,
{ " up " , hi65xx_power_release_isr } ,
{ " hold 4s " , hi65xx_restart_toggle_isr } ,
} ;
static int hi65xx_powerkey_probe ( struct platform_device * pdev )
{
struct device * dev = & pdev - > dev ;
struct input_dev * input ;
int irq , i , error ;
2017-01-21 23:44:18 -08:00
input = devm_input_allocate_device ( dev ) ;
2016-06-22 17:22:03 -07:00
if ( ! input ) {
2017-01-21 23:44:18 -08:00
dev_err ( dev , " failed to allocate input device \n " ) ;
2016-06-22 17:22:03 -07:00
return - ENOMEM ;
}
input - > phys = " hisi_on/input0 " ;
input - > name = " HISI 65xx PowerOn Key " ;
input_set_capability ( input , EV_KEY , KEY_POWER ) ;
input_set_capability ( input , EV_KEY , KEY_RESTART ) ;
for ( i = 0 ; i < ARRAY_SIZE ( hi65xx_irq_info ) ; i + + ) {
irq = platform_get_irq_byname ( pdev , hi65xx_irq_info [ i ] . name ) ;
2019-08-14 10:46:38 -07:00
if ( irq < 0 )
return irq ;
2016-06-22 17:22:03 -07:00
error = devm_request_any_context_irq ( dev , irq ,
hi65xx_irq_info [ i ] . handler ,
IRQF_ONESHOT ,
hi65xx_irq_info [ i ] . name ,
input ) ;
if ( error < 0 ) {
dev_err ( dev , " couldn't request irq %s: %d \n " ,
hi65xx_irq_info [ i ] . name , error ) ;
return error ;
}
}
error = input_register_device ( input ) ;
if ( error ) {
2017-01-21 23:44:18 -08:00
dev_err ( dev , " failed to register input device: %d \n " , error ) ;
2016-06-22 17:22:03 -07:00
return error ;
}
2017-01-21 23:44:18 -08:00
device_init_wakeup ( dev , 1 ) ;
2016-06-22 17:22:03 -07:00
return 0 ;
}
static struct platform_driver hi65xx_powerkey_driver = {
. driver = {
. name = " hi65xx-powerkey " ,
} ,
. probe = hi65xx_powerkey_probe ,
} ;
module_platform_driver ( hi65xx_powerkey_driver ) ;
MODULE_AUTHOR ( " Zhiliang Xue <xuezhiliang@huawei.com " ) ;
MODULE_DESCRIPTION ( " Hisi PMIC Power key driver " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;