diff options
-rw-r--r-- | drivers/input/misc/Kconfig | 10 | ||||
-rw-r--r-- | drivers/input/misc/Makefile | 1 | ||||
-rw-r--r-- | drivers/input/misc/ab8500-ponkey.c | 157 | ||||
-rw-r--r-- | drivers/mfd/ab8500-core.c | 20 |
4 files changed, 188 insertions, 0 deletions
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index b49e2337972..b99b8cbde02 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -22,6 +22,16 @@ config INPUT_88PM860X_ONKEY To compile this driver as a module, choose M here: the module will be called 88pm860x_onkey. +config INPUT_AB8500_PONKEY + tristate "AB8500 Pon (PowerOn) Key" + depends on AB8500_CORE + help + Say Y here to use the PowerOn Key for ST-Ericsson's AB8500 + Mix-Sig PMIC. + + To compile this driver as a module, choose M here: the module + will be called ab8500-ponkey. + config INPUT_AD714X tristate "Analog Devices AD714x Capacitance Touch Sensor" help diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index 19ccca78fa7..1fe1f6c8b73 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile @@ -5,6 +5,7 @@ # Each configuration option enables a list of files. obj-$(CONFIG_INPUT_88PM860X_ONKEY) += 88pm860x_onkey.o +obj-$(CONFIG_INPUT_AB8500_PONKEY) += ab8500-ponkey.o obj-$(CONFIG_INPUT_AD714X) += ad714x.o obj-$(CONFIG_INPUT_AD714X_I2C) += ad714x-i2c.o obj-$(CONFIG_INPUT_AD714X_SPI) += ad714x-spi.o diff --git a/drivers/input/misc/ab8500-ponkey.c b/drivers/input/misc/ab8500-ponkey.c new file mode 100644 index 00000000000..98f8ede504b --- /dev/null +++ b/drivers/input/misc/ab8500-ponkey.c @@ -0,0 +1,157 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * License Terms: GNU General Public License v2 + * Author: Sundar Iyer <sundar.iyer@stericsson.com> for ST-Ericsson + * + * AB8500 Power-On Key handler + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/input.h> +#include <linux/interrupt.h> +#include <linux/mfd/ab8500.h> +#include <linux/slab.h> + +/** + * struct ab8500_ponkey - ab8500 ponkey information + * @input_dev: pointer to input device + * @ab8500: ab8500 parent + * @irq_dbf: irq number for falling transition + * @irq_dbr: irq number for rising transition + */ +struct ab8500_ponkey { + struct input_dev *idev; + struct ab8500 *ab8500; + int irq_dbf; + int irq_dbr; +}; + +/* AB8500 gives us an interrupt when ONKEY is held */ +static irqreturn_t ab8500_ponkey_handler(int irq, void *data) +{ + struct ab8500_ponkey *ponkey = data; + + if (irq == ponkey->irq_dbf) + input_report_key(ponkey->idev, KEY_POWER, true); + else if (irq == ponkey->irq_dbr) + input_report_key(ponkey->idev, KEY_POWER, false); + + input_sync(ponkey->idev); + + return IRQ_HANDLED; +} + +static int __devinit ab8500_ponkey_probe(struct platform_device *pdev) +{ + struct ab8500 *ab8500 = dev_get_drvdata(pdev->dev.parent); + struct ab8500_ponkey *ponkey; + struct input_dev *input; + int irq_dbf, irq_dbr; + int error; + + irq_dbf = platform_get_irq_byname(pdev, "ONKEY_DBF"); + if (irq_dbf < 0) { + dev_err(&pdev->dev, "No IRQ for ONKEY_DBF, error=%d\n", irq_dbf); + return irq_dbf; + } + + irq_dbr = platform_get_irq_byname(pdev, "ONKEY_DBR"); + if (irq_dbr < 0) { + dev_err(&pdev->dev, "No IRQ for ONKEY_DBR, error=%d\n", irq_dbr); + return irq_dbr; + } + + ponkey = kzalloc(sizeof(struct ab8500_ponkey), GFP_KERNEL); + input = input_allocate_device(); + if (!ponkey || !input) { + error = -ENOMEM; + goto err_free_mem; + } + + ponkey->idev = input; + ponkey->ab8500 = ab8500; + ponkey->irq_dbf = irq_dbf; + ponkey->irq_dbr = irq_dbr; + + input->name = "AB8500 POn(PowerOn) Key"; + input->dev.parent = &pdev->dev; + + input_set_capability(input, EV_KEY, KEY_POWER); + + error = request_any_context_irq(ponkey->irq_dbf, ab8500_ponkey_handler, + 0, "ab8500-ponkey-dbf", ponkey); + if (error < 0) { + dev_err(ab8500->dev, "Failed to request dbf IRQ#%d: %d\n", + ponkey->irq_dbf, error); + goto err_free_mem; + } + + error = request_any_context_irq(ponkey->irq_dbr, ab8500_ponkey_handler, + 0, "ab8500-ponkey-dbr", ponkey); + if (error < 0) { + dev_err(ab8500->dev, "Failed to request dbr IRQ#%d: %d\n", + ponkey->irq_dbr, error); + goto err_free_dbf_irq; + } + + error = input_register_device(ponkey->idev); + if (error) { + dev_err(ab8500->dev, "Can't register input device: %d\n", error); + goto err_free_dbr_irq; + } + + platform_set_drvdata(pdev, ponkey); + return 0; + +err_free_dbr_irq: + free_irq(ponkey->irq_dbf, ponkey); +err_free_dbf_irq: + free_irq(ponkey->irq_dbf, ponkey); +err_free_mem: + input_free_device(input); + kfree(ponkey); + + return error; +} + +static int __devexit ab8500_ponkey_remove(struct platform_device *pdev) +{ + struct ab8500_ponkey *ponkey = platform_get_drvdata(pdev); + + free_irq(ponkey->irq_dbf, ponkey); + free_irq(ponkey->irq_dbr, ponkey); + input_unregister_device(ponkey->idev); + kfree(ponkey); + + platform_set_drvdata(pdev, NULL); + + return 0; +} + +static struct platform_driver ab8500_ponkey_driver = { + .driver = { + .name = "ab8500-poweron-key", + .owner = THIS_MODULE, + }, + .probe = ab8500_ponkey_probe, + .remove = __devexit_p(ab8500_ponkey_remove), +}; + +static int __init ab8500_ponkey_init(void) +{ + return platform_driver_register(&ab8500_ponkey_driver); +} +module_init(ab8500_ponkey_init); + +static void __exit ab8500_ponkey_exit(void) +{ + platform_driver_unregister(&ab8500_ponkey_driver); +} +module_exit(ab8500_ponkey_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Sundar Iyer <sundar.iyer@stericsson.com>"); +MODULE_DESCRIPTION("ST-Ericsson AB8500 Power-ON(Pon) Key driver"); diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c index defa786dee3..b8c4b80e4c4 100644 --- a/drivers/mfd/ab8500-core.c +++ b/drivers/mfd/ab8500-core.c @@ -338,6 +338,21 @@ static struct resource ab8500_rtc_resources[] = { }, }; +static struct resource ab8500_poweronkey_db_resources[] = { + { + .name = "ONKEY_DBF", + .start = AB8500_INT_PON_KEY1DB_F, + .end = AB8500_INT_PON_KEY1DB_F, + .flags = IORESOURCE_IRQ, + }, + { + .name = "ONKEY_DBR", + .start = AB8500_INT_PON_KEY1DB_R, + .end = AB8500_INT_PON_KEY1DB_R, + .flags = IORESOURCE_IRQ, + }, +}; + static struct mfd_cell ab8500_devs[] = { { .name = "ab8500-gpadc", @@ -354,6 +369,11 @@ static struct mfd_cell ab8500_devs[] = { { .name = "ab8500-usb", }, { .name = "ab8500-pwm", }, { .name = "ab8500-regulator", }, + { + .name = "ab8500-poweron-key", + .num_resources = ARRAY_SIZE(ab8500_poweronkey_db_resources), + .resources = ab8500_poweronkey_db_resources, + }, }; int __devinit ab8500_init(struct ab8500 *ab8500) |