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;
77527df5faSDmitry Torokhov 	ponkey->irq_dbf = irq_dbf;
78527df5faSDmitry Torokhov 	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