2010-05-22 11:57:26 +04:00
/**
2012-03-06 21:10:21 +04:00
* MAX8925 ONKEY driver
2010-05-22 11:57:26 +04:00
*
* Copyright ( C ) 2009 Marvell International Ltd .
* Haojian Zhuang < haojian . zhuang @ marvell . com >
*
* 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 .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*/
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/platform_device.h>
# include <linux/i2c.h>
# include <linux/input.h>
# include <linux/interrupt.h>
# include <linux/mfd/max8925.h>
# include <linux/slab.h>
2014-05-29 11:21:56 +04:00
# include <linux/device.h>
2010-05-22 11:57:26 +04:00
2010-09-08 17:44:35 +04:00
# define SW_INPUT (1 << 7) /* 0/1 -- up/down */
2010-05-22 11:57:26 +04:00
# define HARDRESET_EN (1 << 7)
# define PWREN_EN (1 << 7)
struct max8925_onkey_info {
struct input_dev * idev ;
struct i2c_client * i2c ;
2010-09-08 17:44:35 +04:00
struct device * dev ;
2012-03-06 21:10:21 +04:00
unsigned int irq [ 2 ] ;
2010-05-22 11:57:26 +04:00
} ;
/*
2010-09-08 17:44:35 +04:00
* MAX8925 gives us an interrupt when ONKEY is pressed or released .
2010-05-22 11:57:26 +04:00
* max8925_set_bits ( ) operates I2C bus and may sleep . So implement
* it in thread IRQ handler .
*/
static irqreturn_t max8925_onkey_handler ( int irq , void * data )
{
struct max8925_onkey_info * info = data ;
2012-03-06 21:10:21 +04:00
int state ;
state = max8925_reg_read ( info - > i2c , MAX8925_ON_OFF_STATUS ) ;
input_report_key ( info - > idev , KEY_POWER , state & SW_INPUT ) ;
2010-05-22 11:57:26 +04:00
input_sync ( info - > idev ) ;
2012-03-06 21:10:21 +04:00
dev_dbg ( info - > dev , " onkey state:%d \n " , state ) ;
2010-09-08 17:44:35 +04:00
2010-05-22 11:57:26 +04:00
/* Enable hardreset to halt if system isn't shutdown on time */
max8925_set_bits ( info - > i2c , MAX8925_SYSENSEL ,
HARDRESET_EN , HARDRESET_EN ) ;
return IRQ_HANDLED ;
}
2012-11-24 09:38:25 +04:00
static int max8925_onkey_probe ( struct platform_device * pdev )
2010-05-22 11:57:26 +04:00
{
struct max8925_chip * chip = dev_get_drvdata ( pdev - > dev . parent ) ;
struct max8925_onkey_info * info ;
2012-03-06 21:10:21 +04:00
struct input_dev * input ;
2010-09-08 17:44:35 +04:00
int irq [ 2 ] , error ;
irq [ 0 ] = platform_get_irq ( pdev , 0 ) ;
if ( irq [ 0 ] < 0 ) {
dev_err ( & pdev - > dev , " No IRQ resource! \n " ) ;
return - EINVAL ;
}
2012-03-06 21:10:21 +04:00
2010-09-08 17:44:35 +04:00
irq [ 1 ] = platform_get_irq ( pdev , 1 ) ;
if ( irq [ 1 ] < 0 ) {
dev_err ( & pdev - > dev , " No IRQ resource! \n " ) ;
return - EINVAL ;
}
2010-05-22 11:57:26 +04:00
2014-05-29 11:21:56 +04:00
info = devm_kzalloc ( & pdev - > dev , sizeof ( struct max8925_onkey_info ) ,
GFP_KERNEL ) ;
if ( ! info )
return - ENOMEM ;
input = devm_input_allocate_device ( & pdev - > dev ) ;
if ( ! input )
return - ENOMEM ;
2010-05-22 11:57:26 +04:00
2012-03-06 21:10:21 +04:00
info - > idev = input ;
2010-05-22 11:57:26 +04:00
info - > i2c = chip - > i2c ;
2010-09-08 17:44:35 +04:00
info - > dev = & pdev - > dev ;
2012-03-06 21:10:21 +04:00
info - > irq [ 0 ] = irq [ 0 ] ;
info - > irq [ 1 ] = irq [ 1 ] ;
input - > name = " max8925_on " ;
input - > phys = " max8925_on/input0 " ;
input - > id . bustype = BUS_I2C ;
input - > dev . parent = & pdev - > dev ;
input_set_capability ( input , EV_KEY , KEY_POWER ) ;
2014-05-29 11:21:56 +04:00
error = devm_request_threaded_irq ( & pdev - > dev , irq [ 0 ] , NULL ,
max8925_onkey_handler , IRQF_ONESHOT ,
" onkey-down " , info ) ;
2010-09-08 17:44:35 +04:00
if ( error < 0 ) {
dev_err ( chip - > dev , " Failed to request IRQ: #%d: %d \n " ,
irq [ 0 ] , error ) ;
2014-05-29 11:21:56 +04:00
return error ;
2010-09-08 17:44:35 +04:00
}
2012-03-06 21:10:21 +04:00
2014-05-29 11:21:56 +04:00
error = devm_request_threaded_irq ( & pdev - > dev , irq [ 1 ] , NULL ,
max8925_onkey_handler , IRQF_ONESHOT ,
" onkey-up " , info ) ;
2010-09-08 17:44:35 +04:00
if ( error < 0 ) {
dev_err ( chip - > dev , " Failed to request IRQ: #%d: %d \n " ,
irq [ 1 ] , error ) ;
2014-05-29 11:21:56 +04:00
return error ;
2010-09-08 17:44:35 +04:00
}
2010-05-22 11:57:26 +04:00
error = input_register_device ( info - > idev ) ;
if ( error ) {
dev_err ( chip - > dev , " Can't register input device: %d \n " , error ) ;
2014-05-29 11:21:56 +04:00
return error ;
2010-05-22 11:57:26 +04:00
}
platform_set_drvdata ( pdev , info ) ;
2012-03-06 21:10:21 +04:00
device_init_wakeup ( & pdev - > dev , 1 ) ;
2010-05-22 11:57:26 +04:00
return 0 ;
}
2014-11-02 10:02:46 +03:00
static int __maybe_unused max8925_onkey_suspend ( struct device * dev )
2012-03-06 10:24:54 +04:00
{
struct platform_device * pdev = to_platform_device ( dev ) ;
struct max8925_onkey_info * info = platform_get_drvdata ( pdev ) ;
struct max8925_chip * chip = dev_get_drvdata ( pdev - > dev . parent ) ;
if ( device_may_wakeup ( dev ) ) {
2012-03-06 21:10:21 +04:00
chip - > wakeup_flag | = 1 < < info - > irq [ 0 ] ;
chip - > wakeup_flag | = 1 < < info - > irq [ 1 ] ;
2012-03-06 10:24:54 +04:00
}
return 0 ;
}
2014-11-02 10:02:46 +03:00
static int __maybe_unused max8925_onkey_resume ( struct device * dev )
2012-03-06 10:24:54 +04:00
{
struct platform_device * pdev = to_platform_device ( dev ) ;
struct max8925_onkey_info * info = platform_get_drvdata ( pdev ) ;
struct max8925_chip * chip = dev_get_drvdata ( pdev - > dev . parent ) ;
if ( device_may_wakeup ( dev ) ) {
2012-03-06 21:10:21 +04:00
chip - > wakeup_flag & = ~ ( 1 < < info - > irq [ 0 ] ) ;
chip - > wakeup_flag & = ~ ( 1 < < info - > irq [ 1 ] ) ;
2012-03-06 10:24:54 +04:00
}
return 0 ;
}
static SIMPLE_DEV_PM_OPS ( max8925_onkey_pm_ops , max8925_onkey_suspend , max8925_onkey_resume ) ;
2010-05-22 11:57:26 +04:00
static struct platform_driver max8925_onkey_driver = {
. driver = {
. name = " max8925-onkey " ,
2012-03-06 10:24:54 +04:00
. pm = & max8925_onkey_pm_ops ,
2010-05-22 11:57:26 +04:00
} ,
. probe = max8925_onkey_probe ,
} ;
2011-11-29 23:08:40 +04:00
module_platform_driver ( max8925_onkey_driver ) ;
2010-05-22 11:57:26 +04:00
MODULE_DESCRIPTION ( " Maxim MAX8925 ONKEY driver " ) ;
MODULE_AUTHOR ( " Haojian Zhuang <haojian.zhuang@marvell.com> " ) ;
MODULE_LICENSE ( " GPL " ) ;