diff options
author | Philippe Langlais <philippe.langlais@stericsson.com> | 2012-06-04 19:45:28 +0800 |
---|---|---|
committer | Philippe Langlais <philippe.langlais@stericsson.com> | 2012-06-04 19:45:28 +0800 |
commit | c633be5ecf5fd7131c1af12a1d0de06655bc74cb (patch) | |
tree | 03a416d10f0285819a3223433f99f39c4d915c12 /drivers/input/misc/ab8500-ponkey.c | |
parent | bb0405fc134f29b78bf52ffe7f3ea2a3678523b5 (diff) | |
parent | 574d17466e4def02f2b3a3be8cffec312dcfc51d (diff) |
Merge topic branch 'input' into integration-linux-ux500
Diffstat (limited to 'drivers/input/misc/ab8500-ponkey.c')
-rw-r--r-- | drivers/input/misc/ab8500-ponkey.c | 213 |
1 files changed, 146 insertions, 67 deletions
diff --git a/drivers/input/misc/ab8500-ponkey.c b/drivers/input/misc/ab8500-ponkey.c index 350fd0c385d..c3c3c51d302 100644 --- a/drivers/input/misc/ab8500-ponkey.c +++ b/drivers/input/misc/ab8500-ponkey.c @@ -6,7 +6,6 @@ * * AB8500 Power-On Key handler */ - #include <linux/kernel.h> #include <linux/module.h> #include <linux/platform_device.h> @@ -14,128 +13,208 @@ #include <linux/interrupt.h> #include <linux/mfd/abx500/ab8500.h> #include <linux/slab.h> +#include <linux/mfd/abx500.h> +#include <linux/mfd/abx500/ab5500.h> + +/* Ponkey time control bits */ +#define AB5500_MCB 0x2F +#define AB5500_PONKEY_10SEC 0x0 +#define AB5500_PONKEY_5SEC 0x1 +#define AB5500_PONKEY_DISABLE 0x2 +#define AB5500_PONKEY_TMR_MASK 0x1 +#define AB5500_PONKEY_TR_MASK 0x2 + +static int ab5500_ponkey_hw_init(struct platform_device *); + +struct ab8500_ponkey_variant { + const char *irq_falling; + const char *irq_rising; + int (*hw_init)(struct platform_device *); +}; + +static const struct ab8500_ponkey_variant ab5500_onswa = { + .irq_falling = "ONSWAn_falling", + .irq_rising = "ONSWAn_rising", + .hw_init = ab5500_ponkey_hw_init, +}; + +static const struct ab8500_ponkey_variant ab8500_ponkey = { + .irq_falling = "ONKEY_DBF", + .irq_rising = "ONKEY_DBR", +}; /** - * struct ab8500_ponkey - ab8500 ponkey information + * struct ab8500_ponkey_info - 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 ab8500_ponkey_info { struct input_dev *idev; - struct ab8500 *ab8500; int irq_dbf; int irq_dbr; }; +static int ab5500_ponkey_hw_init(struct platform_device *pdev) +{ + u8 val; + struct ab5500_ponkey_platform_data *pdata; + + pdata = pdev->dev.platform_data; + if (pdata) { + switch (pdata->shutdown_secs) { + case 0: + val = AB5500_PONKEY_DISABLE; + break; + case 5: + val = AB5500_PONKEY_5SEC; + break; + case 10: + val = AB5500_PONKEY_10SEC; + break; + default: + val = AB5500_PONKEY_10SEC; + } + } else { + val = AB5500_PONKEY_10SEC; + } + return abx500_mask_and_set( + &pdev->dev, + AB5500_BANK_STARTUP, + AB5500_MCB, + AB5500_PONKEY_TMR_MASK | AB5500_PONKEY_TR_MASK, + val); +} + /* AB8500 gives us an interrupt when ONKEY is held */ static irqreturn_t ab8500_ponkey_handler(int irq, void *data) { - struct ab8500_ponkey *ponkey = data; + struct ab8500_ponkey_info *info = 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); + if (irq == info->irq_dbf) + input_report_key(info->idev, KEY_POWER, true); + else if (irq == info->irq_dbr) + input_report_key(info->idev, KEY_POWER, false); - input_sync(ponkey->idev); + input_sync(info->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; + const struct ab8500_ponkey_variant *variant; + struct ab8500_ponkey_info *info; + int irq_dbf, irq_dbr, ret; + + variant = (const struct ab8500_ponkey_variant *) + pdev->id_entry->driver_data; + + if (variant->hw_init) { + ret = variant->hw_init(pdev); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to init hw"); + return ret; + } + } - irq_dbf = platform_get_irq_byname(pdev, "ONKEY_DBF"); + irq_dbf = platform_get_irq_byname(pdev, variant->irq_falling); if (irq_dbf < 0) { - dev_err(&pdev->dev, "No IRQ for ONKEY_DBF, error=%d\n", irq_dbf); + dev_err(&pdev->dev, "No IRQ for %s: %d\n", + variant->irq_falling, irq_dbf); return irq_dbf; } - irq_dbr = platform_get_irq_byname(pdev, "ONKEY_DBR"); + irq_dbr = platform_get_irq_byname(pdev, variant->irq_rising); if (irq_dbr < 0) { - dev_err(&pdev->dev, "No IRQ for ONKEY_DBR, error=%d\n", irq_dbr); + dev_err(&pdev->dev, "No IRQ for %s: %d\n", + variant->irq_rising, 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; - } + info = kzalloc(sizeof(struct ab8500_ponkey_info), GFP_KERNEL); + if (!info) + return -ENOMEM; - ponkey->idev = input; - ponkey->ab8500 = ab8500; - ponkey->irq_dbf = irq_dbf; - ponkey->irq_dbr = irq_dbr; + info->irq_dbf = irq_dbf; + info->irq_dbr = irq_dbr; - input->name = "AB8500 POn(PowerOn) Key"; - input->dev.parent = &pdev->dev; + info->idev = input_allocate_device(); + if (!info->idev) { + dev_err(&pdev->dev, "Failed to allocate input dev\n"); + ret = -ENOMEM; + goto out; + } - input_set_capability(input, EV_KEY, KEY_POWER); + info->idev->name = "AB8500 POn(PowerOn) Key"; + 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_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; + ret = input_register_device(info->idev); + if (ret) { + dev_err(&pdev->dev, "Can't register input device: %d\n", ret); + goto out_unfreedevice; } - 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; + ret = request_threaded_irq(info->irq_dbf, NULL, ab8500_ponkey_handler, + IRQF_NO_SUSPEND, "ab8500-ponkey-dbf", + info); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to request dbf IRQ#%d: %d\n", + info->irq_dbf, ret); + goto out_unregisterdevice; } - 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; + ret = request_threaded_irq(info->irq_dbr, NULL, ab8500_ponkey_handler, + IRQF_NO_SUSPEND, "ab8500-ponkey-dbr", + info); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to request dbr IRQ#%d: %d\n", + info->irq_dbr, ret); + goto out_irq_dbf; } - platform_set_drvdata(pdev, ponkey); - return 0; + platform_set_drvdata(pdev, info); -err_free_dbr_irq: - free_irq(ponkey->irq_dbr, ponkey); -err_free_dbf_irq: - free_irq(ponkey->irq_dbf, ponkey); -err_free_mem: - input_free_device(input); - kfree(ponkey); + return 0; - return error; +out_irq_dbf: + free_irq(info->irq_dbf, info); +out_unregisterdevice: + input_unregister_device(info->idev); + info->idev = NULL; +out_unfreedevice: + input_free_device(info->idev); +out: + kfree(info); + return ret; } 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); + struct ab8500_ponkey_info *info = platform_get_drvdata(pdev); + free_irq(info->irq_dbf, info); + free_irq(info->irq_dbr, info); + input_unregister_device(info->idev); + kfree(info); return 0; } +static struct platform_device_id ab8500_ponkey_id_table[] = { + { "ab5500-onswa", (kernel_ulong_t)&ab5500_onswa, }, + { "ab8500-poweron-key", (kernel_ulong_t)&ab8500_ponkey, }, + { }, +}; +MODULE_DEVICE_TABLE(platform, ab8500_ponkey_id_table); + static struct platform_driver ab8500_ponkey_driver = { .driver = { .name = "ab8500-poweron-key", .owner = THIS_MODULE, }, + .id_table = ab8500_ponkey_id_table, .probe = ab8500_ponkey_probe, .remove = __devexit_p(ab8500_ponkey_remove), }; |