177686517SSundar R Iyer /* 277686517SSundar R Iyer * Copyright (C) ST-Ericsson SA 2010 377686517SSundar R Iyer * 477686517SSundar R Iyer * License Terms: GNU General Public License v2 577686517SSundar R Iyer * Author: Sundar Iyer <sundar.iyer@stericsson.com> for ST-Ericsson 677686517SSundar R Iyer * 777686517SSundar R Iyer * AB8500 Power-On Key handler 877686517SSundar R Iyer */ 977686517SSundar R Iyer 1077686517SSundar R Iyer #include <linux/kernel.h> 1177686517SSundar R Iyer #include <linux/module.h> 1277686517SSundar R Iyer #include <linux/platform_device.h> 1377686517SSundar R Iyer #include <linux/input.h> 1477686517SSundar R Iyer #include <linux/interrupt.h> 15ee66e653SLinus Walleij #include <linux/mfd/abx500/ab8500.h> 1603ecd229SLee Jones #include <linux/of.h> 1777686517SSundar R Iyer #include <linux/slab.h> 1877686517SSundar R Iyer 1977686517SSundar R Iyer /** 2077686517SSundar R Iyer * struct ab8500_ponkey - ab8500 ponkey information 2177686517SSundar R Iyer * @input_dev: pointer to input device 2277686517SSundar R Iyer * @ab8500: ab8500 parent 2377686517SSundar R Iyer * @irq_dbf: irq number for falling transition 2477686517SSundar R Iyer * @irq_dbr: irq number for rising transition 2577686517SSundar R Iyer */ 2677686517SSundar R Iyer struct ab8500_ponkey { 2777686517SSundar R Iyer struct input_dev *idev; 2877686517SSundar R Iyer struct ab8500 *ab8500; 2977686517SSundar R Iyer int irq_dbf; 3077686517SSundar R Iyer int irq_dbr; 3177686517SSundar R Iyer }; 3277686517SSundar R Iyer 3377686517SSundar R Iyer /* AB8500 gives us an interrupt when ONKEY is held */ 3477686517SSundar R Iyer static irqreturn_t ab8500_ponkey_handler(int irq, void *data) 3577686517SSundar R Iyer { 3677686517SSundar R Iyer struct ab8500_ponkey *ponkey = data; 3777686517SSundar R Iyer 3877686517SSundar R Iyer if (irq == ponkey->irq_dbf) 3977686517SSundar R Iyer input_report_key(ponkey->idev, KEY_POWER, true); 4077686517SSundar R Iyer else if (irq == ponkey->irq_dbr) 4177686517SSundar R Iyer input_report_key(ponkey->idev, KEY_POWER, false); 4277686517SSundar R Iyer 4377686517SSundar R Iyer input_sync(ponkey->idev); 4477686517SSundar R Iyer 4577686517SSundar R Iyer return IRQ_HANDLED; 4677686517SSundar R Iyer } 4777686517SSundar R Iyer 4877686517SSundar R Iyer static int __devinit ab8500_ponkey_probe(struct platform_device *pdev) 4977686517SSundar R Iyer { 5077686517SSundar R Iyer struct ab8500 *ab8500 = dev_get_drvdata(pdev->dev.parent); 5177686517SSundar R Iyer struct ab8500_ponkey *ponkey; 5277686517SSundar R Iyer struct input_dev *input; 5377686517SSundar R Iyer int irq_dbf, irq_dbr; 5477686517SSundar R Iyer int error; 5577686517SSundar R Iyer 5677686517SSundar R Iyer irq_dbf = platform_get_irq_byname(pdev, "ONKEY_DBF"); 5777686517SSundar R Iyer if (irq_dbf < 0) { 5877686517SSundar R Iyer dev_err(&pdev->dev, "No IRQ for ONKEY_DBF, error=%d\n", irq_dbf); 5977686517SSundar R Iyer return irq_dbf; 6077686517SSundar R Iyer } 6177686517SSundar R Iyer 6277686517SSundar R Iyer irq_dbr = platform_get_irq_byname(pdev, "ONKEY_DBR"); 6377686517SSundar R Iyer if (irq_dbr < 0) { 6477686517SSundar R Iyer dev_err(&pdev->dev, "No IRQ for ONKEY_DBR, error=%d\n", irq_dbr); 6577686517SSundar R Iyer return irq_dbr; 6677686517SSundar R Iyer } 6777686517SSundar R Iyer 6877686517SSundar R Iyer ponkey = kzalloc(sizeof(struct ab8500_ponkey), GFP_KERNEL); 6977686517SSundar R Iyer input = input_allocate_device(); 7077686517SSundar R Iyer if (!ponkey || !input) { 7177686517SSundar R Iyer error = -ENOMEM; 7277686517SSundar R Iyer goto err_free_mem; 7377686517SSundar R Iyer } 7477686517SSundar R Iyer 7577686517SSundar R Iyer ponkey->idev = input; 7677686517SSundar R Iyer ponkey->ab8500 = ab8500; 7777686517SSundar R Iyer ponkey->irq_dbf = irq_dbf; 7877686517SSundar R Iyer ponkey->irq_dbr = irq_dbr; 7977686517SSundar R Iyer 8077686517SSundar R Iyer input->name = "AB8500 POn(PowerOn) Key"; 8177686517SSundar R Iyer input->dev.parent = &pdev->dev; 8277686517SSundar R Iyer 8377686517SSundar R Iyer input_set_capability(input, EV_KEY, KEY_POWER); 8477686517SSundar R Iyer 8577686517SSundar R Iyer error = request_any_context_irq(ponkey->irq_dbf, ab8500_ponkey_handler, 8677686517SSundar R Iyer 0, "ab8500-ponkey-dbf", ponkey); 8777686517SSundar R Iyer if (error < 0) { 8877686517SSundar R Iyer dev_err(ab8500->dev, "Failed to request dbf IRQ#%d: %d\n", 8977686517SSundar R Iyer ponkey->irq_dbf, error); 9077686517SSundar R Iyer goto err_free_mem; 9177686517SSundar R Iyer } 9277686517SSundar R Iyer 9377686517SSundar R Iyer error = request_any_context_irq(ponkey->irq_dbr, ab8500_ponkey_handler, 9477686517SSundar R Iyer 0, "ab8500-ponkey-dbr", ponkey); 9577686517SSundar R Iyer if (error < 0) { 9677686517SSundar R Iyer dev_err(ab8500->dev, "Failed to request dbr IRQ#%d: %d\n", 9777686517SSundar R Iyer ponkey->irq_dbr, error); 9877686517SSundar R Iyer goto err_free_dbf_irq; 9977686517SSundar R Iyer } 10077686517SSundar R Iyer 10177686517SSundar R Iyer error = input_register_device(ponkey->idev); 10277686517SSundar R Iyer if (error) { 10377686517SSundar R Iyer dev_err(ab8500->dev, "Can't register input device: %d\n", error); 10477686517SSundar R Iyer goto err_free_dbr_irq; 10577686517SSundar R Iyer } 10677686517SSundar R Iyer 10777686517SSundar R Iyer platform_set_drvdata(pdev, ponkey); 10877686517SSundar R Iyer return 0; 10977686517SSundar R Iyer 11077686517SSundar R Iyer err_free_dbr_irq: 111c5fb514dSNicolas Kaiser free_irq(ponkey->irq_dbr, ponkey); 11277686517SSundar R Iyer err_free_dbf_irq: 11377686517SSundar R Iyer free_irq(ponkey->irq_dbf, ponkey); 11477686517SSundar R Iyer err_free_mem: 11577686517SSundar R Iyer input_free_device(input); 11677686517SSundar R Iyer kfree(ponkey); 11777686517SSundar R Iyer 11877686517SSundar R Iyer return error; 11977686517SSundar R Iyer } 12077686517SSundar R Iyer 12177686517SSundar R Iyer static int __devexit ab8500_ponkey_remove(struct platform_device *pdev) 12277686517SSundar R Iyer { 12377686517SSundar R Iyer struct ab8500_ponkey *ponkey = platform_get_drvdata(pdev); 12477686517SSundar R Iyer 12577686517SSundar R Iyer free_irq(ponkey->irq_dbf, ponkey); 12677686517SSundar R Iyer free_irq(ponkey->irq_dbr, ponkey); 12777686517SSundar R Iyer input_unregister_device(ponkey->idev); 12877686517SSundar R Iyer kfree(ponkey); 12977686517SSundar R Iyer 13077686517SSundar R Iyer platform_set_drvdata(pdev, NULL); 13177686517SSundar R Iyer 13277686517SSundar R Iyer return 0; 13377686517SSundar R Iyer } 13477686517SSundar R Iyer 13503ecd229SLee Jones #ifdef CONFIG_OF 13603ecd229SLee Jones static const struct of_device_id ab8500_ponkey_match[] = { 13703ecd229SLee Jones { .compatible = "stericsson,ab8500-ponkey", }, 13803ecd229SLee Jones {} 13903ecd229SLee Jones }; 14003ecd229SLee Jones #endif 14103ecd229SLee Jones 14277686517SSundar R Iyer static struct platform_driver ab8500_ponkey_driver = { 14377686517SSundar R Iyer .driver = { 14477686517SSundar R Iyer .name = "ab8500-poweron-key", 14577686517SSundar R Iyer .owner = THIS_MODULE, 14603ecd229SLee Jones .of_match_table = of_match_ptr(ab8500_ponkey_match), 14777686517SSundar R Iyer }, 14877686517SSundar R Iyer .probe = ab8500_ponkey_probe, 14977686517SSundar R Iyer .remove = __devexit_p(ab8500_ponkey_remove), 15077686517SSundar R Iyer }; 151840a746bSJJ Ding module_platform_driver(ab8500_ponkey_driver); 15277686517SSundar R Iyer 15377686517SSundar R Iyer MODULE_LICENSE("GPL v2"); 15477686517SSundar R Iyer MODULE_AUTHOR("Sundar Iyer <sundar.iyer@stericsson.com>"); 15577686517SSundar R Iyer MODULE_DESCRIPTION("ST-Ericsson AB8500 Power-ON(Pon) Key driver"); 156