2 * 88pm860x_onkey.c - Marvell 88PM860x ONKEY driver
4 * Copyright (C) 2009-2010 Marvell International Ltd.
5 * Haojian Zhuang <haojian.zhuang@marvell.com>
7 * This file is subject to the terms and conditions of the GNU General
8 * Public License. See the file "COPYING" in the main directory of this
9 * archive for more details.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #include <linux/kernel.h>
22 #include <linux/module.h>
23 #include <linux/platform_device.h>
24 #include <linux/i2c.h>
25 #include <linux/input.h>
26 #include <linux/interrupt.h>
27 #include <linux/mfd/88pm860x.h>
28 #include <linux/slab.h>
29 #include <linux/device.h>
31 #define PM8607_WAKEUP 0x0b
33 #define LONG_ONKEY_EN (1 << 1)
34 #define ONKEY_STATUS (1 << 0)
36 struct pm860x_onkey_info
{
37 struct input_dev
*idev
;
38 struct pm860x_chip
*chip
;
39 struct i2c_client
*i2c
;
44 /* 88PM860x gives us an interrupt when ONKEY is held */
45 static irqreturn_t
pm860x_onkey_handler(int irq
, void *data
)
47 struct pm860x_onkey_info
*info
= data
;
50 ret
= pm860x_reg_read(info
->i2c
, PM8607_STATUS_2
);
52 input_report_key(info
->idev
, KEY_POWER
, ret
);
53 input_sync(info
->idev
);
55 /* Enable 8-second long onkey detection */
56 pm860x_set_bits(info
->i2c
, PM8607_WAKEUP
, 3, LONG_ONKEY_EN
);
60 static int pm860x_onkey_probe(struct platform_device
*pdev
)
62 struct pm860x_chip
*chip
= dev_get_drvdata(pdev
->dev
.parent
);
63 struct pm860x_onkey_info
*info
;
66 irq
= platform_get_irq(pdev
, 0);
68 dev_err(&pdev
->dev
, "No IRQ resource!\n");
72 info
= devm_kzalloc(&pdev
->dev
, sizeof(struct pm860x_onkey_info
),
77 info
->i2c
= (chip
->id
== CHIP_PM8607
) ? chip
->client
: chip
->companion
;
78 info
->dev
= &pdev
->dev
;
81 info
->idev
= devm_input_allocate_device(&pdev
->dev
);
83 dev_err(chip
->dev
, "Failed to allocate input dev\n");
87 info
->idev
->name
= "88pm860x_on";
88 info
->idev
->phys
= "88pm860x_on/input0";
89 info
->idev
->id
.bustype
= BUS_I2C
;
90 info
->idev
->dev
.parent
= &pdev
->dev
;
91 info
->idev
->evbit
[0] = BIT_MASK(EV_KEY
);
92 info
->idev
->keybit
[BIT_WORD(KEY_POWER
)] = BIT_MASK(KEY_POWER
);
94 ret
= input_register_device(info
->idev
);
96 dev_err(chip
->dev
, "Can't register input device: %d\n", ret
);
100 ret
= devm_request_threaded_irq(&pdev
->dev
, info
->irq
, NULL
,
101 pm860x_onkey_handler
, IRQF_ONESHOT
,
104 dev_err(chip
->dev
, "Failed to request IRQ: #%d: %d\n",
109 platform_set_drvdata(pdev
, info
);
110 device_init_wakeup(&pdev
->dev
, 1);
115 static int __maybe_unused
pm860x_onkey_suspend(struct device
*dev
)
117 struct platform_device
*pdev
= to_platform_device(dev
);
118 struct pm860x_chip
*chip
= dev_get_drvdata(pdev
->dev
.parent
);
120 if (device_may_wakeup(dev
))
121 chip
->wakeup_flag
|= 1 << PM8607_IRQ_ONKEY
;
124 static int __maybe_unused
pm860x_onkey_resume(struct device
*dev
)
126 struct platform_device
*pdev
= to_platform_device(dev
);
127 struct pm860x_chip
*chip
= dev_get_drvdata(pdev
->dev
.parent
);
129 if (device_may_wakeup(dev
))
130 chip
->wakeup_flag
&= ~(1 << PM8607_IRQ_ONKEY
);
134 static SIMPLE_DEV_PM_OPS(pm860x_onkey_pm_ops
, pm860x_onkey_suspend
, pm860x_onkey_resume
);
136 static struct platform_driver pm860x_onkey_driver
= {
138 .name
= "88pm860x-onkey",
139 .pm
= &pm860x_onkey_pm_ops
,
141 .probe
= pm860x_onkey_probe
,
143 module_platform_driver(pm860x_onkey_driver
);
145 MODULE_DESCRIPTION("Marvell 88PM860x ONKEY driver");
146 MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
147 MODULE_LICENSE("GPL");