From 3734574cac1002e4cf037e3591cf222b1e04dfa4 Mon Sep 17 00:00:00 2001 From: Haojian Zhuang Date: Sat, 22 May 2010 00:57:26 -0700 Subject: [PATCH] Input: enable onkey driver of max8925 When ONKEY is held for 3 seconds, KEY_POWER event is reported. Signed-off-by: Haojian Zhuang Signed-off-by: Dmitry Torokhov --- drivers/input/misc/Kconfig | 10 ++ drivers/input/misc/Makefile | 1 + drivers/input/misc/max8925_onkey.c | 148 +++++++++++++++++++++++++++++ 3 files changed, 159 insertions(+) create mode 100644 drivers/input/misc/max8925_onkey.c diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index 48cdabec372a..c44b9eafc556 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -80,6 +80,16 @@ config INPUT_M68K_BEEP tristate "M68k Beeper support" depends on M68K +config INPUT_MAX8925_ONKEY + tristate "MAX8925 ONKEY support" + depends on MFD_MAX8925 + help + Support the ONKEY of MAX8925 PMICs as an input device + reporting power button status. + + To compile this driver as a module, choose M here: the module + will be called max8925_onkey. + config INPUT_APANEL tristate "Fujitsu Lifebook Application Panel buttons" depends on X86 && I2C && LEDS_CLASS diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index f9f577031e06..71fe57d8023f 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile @@ -20,6 +20,7 @@ obj-$(CONFIG_HP_SDC_RTC) += hp_sdc_rtc.o obj-$(CONFIG_INPUT_IXP4XX_BEEPER) += ixp4xx-beeper.o obj-$(CONFIG_INPUT_KEYSPAN_REMOTE) += keyspan_remote.o obj-$(CONFIG_INPUT_M68K_BEEP) += m68kspkr.o +obj-$(CONFIG_INPUT_MAX8925_ONKEY) += max8925_onkey.o obj-$(CONFIG_INPUT_PCAP) += pcap_keys.o obj-$(CONFIG_INPUT_PCF50633_PMU) += pcf50633-input.o obj-$(CONFIG_INPUT_PCF8574) += pcf8574_keypad.o diff --git a/drivers/input/misc/max8925_onkey.c b/drivers/input/misc/max8925_onkey.c new file mode 100644 index 000000000000..80af44608018 --- /dev/null +++ b/drivers/input/misc/max8925_onkey.c @@ -0,0 +1,148 @@ +/** + * max8925_onkey.c - MAX8925 ONKEY driver + * + * Copyright (C) 2009 Marvell International Ltd. + * Haojian Zhuang + * + * 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 +#include +#include +#include +#include +#include +#include +#include + +#define HARDRESET_EN (1 << 7) +#define PWREN_EN (1 << 7) + +struct max8925_onkey_info { + struct input_dev *idev; + struct i2c_client *i2c; + int irq; +}; + +/* + * MAX8925 gives us an interrupt when ONKEY is held for 3 seconds. + * 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; + + input_report_key(info->idev, KEY_POWER, 1); + input_sync(info->idev); + + /* 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; +} + +static int __devinit max8925_onkey_probe(struct platform_device *pdev) +{ + struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent); + struct max8925_onkey_info *info; + int error; + + info = kzalloc(sizeof(struct max8925_onkey_info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + info->i2c = chip->i2c; + info->irq = chip->irq_base + MAX8925_IRQ_GPM_SW_3SEC; + + info->idev = input_allocate_device(); + if (!info->idev) { + dev_err(chip->dev, "Failed to allocate input dev\n"); + error = -ENOMEM; + goto out_input; + } + + info->idev->name = "max8925_on"; + info->idev->phys = "max8925_on/input0"; + info->idev->id.bustype = BUS_I2C; + info->idev->dev.parent = &pdev->dev; + info->idev->evbit[0] = BIT_MASK(EV_KEY); + info->idev->keybit[BIT_WORD(KEY_POWER)] = BIT_MASK(KEY_POWER); + + error = request_threaded_irq(info->irq, NULL, max8925_onkey_handler, + IRQF_ONESHOT, "onkey", info); + if (error < 0) { + dev_err(chip->dev, "Failed to request IRQ: #%d: %d\n", + info->irq, error); + goto out_irq; + } + + error = input_register_device(info->idev); + if (error) { + dev_err(chip->dev, "Can't register input device: %d\n", error); + goto out; + } + + platform_set_drvdata(pdev, info); + + return 0; + +out: + free_irq(info->irq, info); +out_irq: + input_free_device(info->idev); +out_input: + kfree(info); + return error; +} + +static int __devexit max8925_onkey_remove(struct platform_device *pdev) +{ + struct max8925_onkey_info *info = platform_get_drvdata(pdev); + + free_irq(info->irq, info); + input_unregister_device(info->idev); + kfree(info); + + platform_set_drvdata(pdev, NULL); + + return 0; +} + +static struct platform_driver max8925_onkey_driver = { + .driver = { + .name = "max8925-onkey", + .owner = THIS_MODULE, + }, + .probe = max8925_onkey_probe, + .remove = __devexit_p(max8925_onkey_remove), +}; + +static int __init max8925_onkey_init(void) +{ + return platform_driver_register(&max8925_onkey_driver); +} +module_init(max8925_onkey_init); + +static void __exit max8925_onkey_exit(void) +{ + platform_driver_unregister(&max8925_onkey_driver); +} +module_exit(max8925_onkey_exit); + +MODULE_DESCRIPTION("Maxim MAX8925 ONKEY driver"); +MODULE_AUTHOR("Haojian Zhuang "); +MODULE_LICENSE("GPL"); -- 2.20.1