162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) ST-Ericsson SA 2010
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Author: Sundar Iyer <sundar.iyer@stericsson.com> for ST-Ericsson
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * AB8500 Power-On Key handler
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <linux/device.h>
1162306a36Sopenharmony_ci#include <linux/kernel.h>
1262306a36Sopenharmony_ci#include <linux/module.h>
1362306a36Sopenharmony_ci#include <linux/platform_device.h>
1462306a36Sopenharmony_ci#include <linux/input.h>
1562306a36Sopenharmony_ci#include <linux/interrupt.h>
1662306a36Sopenharmony_ci#include <linux/mfd/abx500/ab8500.h>
1762306a36Sopenharmony_ci#include <linux/of.h>
1862306a36Sopenharmony_ci#include <linux/slab.h>
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci/**
2162306a36Sopenharmony_ci * struct ab8500_ponkey - ab8500 ponkey information
2262306a36Sopenharmony_ci * @idev: pointer to input device
2362306a36Sopenharmony_ci * @ab8500: ab8500 parent
2462306a36Sopenharmony_ci * @irq_dbf: irq number for falling transition
2562306a36Sopenharmony_ci * @irq_dbr: irq number for rising transition
2662306a36Sopenharmony_ci */
2762306a36Sopenharmony_cistruct ab8500_ponkey {
2862306a36Sopenharmony_ci	struct input_dev	*idev;
2962306a36Sopenharmony_ci	struct ab8500		*ab8500;
3062306a36Sopenharmony_ci	int			irq_dbf;
3162306a36Sopenharmony_ci	int			irq_dbr;
3262306a36Sopenharmony_ci};
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci/* AB8500 gives us an interrupt when ONKEY is held */
3562306a36Sopenharmony_cistatic irqreturn_t ab8500_ponkey_handler(int irq, void *data)
3662306a36Sopenharmony_ci{
3762306a36Sopenharmony_ci	struct ab8500_ponkey *ponkey = data;
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci	if (irq == ponkey->irq_dbf)
4062306a36Sopenharmony_ci		input_report_key(ponkey->idev, KEY_POWER, true);
4162306a36Sopenharmony_ci	else if (irq == ponkey->irq_dbr)
4262306a36Sopenharmony_ci		input_report_key(ponkey->idev, KEY_POWER, false);
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci	input_sync(ponkey->idev);
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci	return IRQ_HANDLED;
4762306a36Sopenharmony_ci}
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_cistatic int ab8500_ponkey_probe(struct platform_device *pdev)
5062306a36Sopenharmony_ci{
5162306a36Sopenharmony_ci	struct ab8500 *ab8500 = dev_get_drvdata(pdev->dev.parent);
5262306a36Sopenharmony_ci	struct ab8500_ponkey *ponkey;
5362306a36Sopenharmony_ci	struct input_dev *input;
5462306a36Sopenharmony_ci	int irq_dbf, irq_dbr;
5562306a36Sopenharmony_ci	int error;
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci	irq_dbf = platform_get_irq_byname(pdev, "ONKEY_DBF");
5862306a36Sopenharmony_ci	if (irq_dbf < 0)
5962306a36Sopenharmony_ci		return irq_dbf;
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci	irq_dbr = platform_get_irq_byname(pdev, "ONKEY_DBR");
6262306a36Sopenharmony_ci	if (irq_dbr < 0)
6362306a36Sopenharmony_ci		return irq_dbr;
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci	ponkey = devm_kzalloc(&pdev->dev, sizeof(struct ab8500_ponkey),
6662306a36Sopenharmony_ci			      GFP_KERNEL);
6762306a36Sopenharmony_ci	if (!ponkey)
6862306a36Sopenharmony_ci		return -ENOMEM;
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci	input = devm_input_allocate_device(&pdev->dev);
7162306a36Sopenharmony_ci	if (!input)
7262306a36Sopenharmony_ci		return -ENOMEM;
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci	ponkey->idev = input;
7562306a36Sopenharmony_ci	ponkey->ab8500 = ab8500;
7662306a36Sopenharmony_ci	ponkey->irq_dbf = irq_dbf;
7762306a36Sopenharmony_ci	ponkey->irq_dbr = irq_dbr;
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	input->name = "AB8500 POn(PowerOn) Key";
8062306a36Sopenharmony_ci	input->dev.parent = &pdev->dev;
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	input_set_capability(input, EV_KEY, KEY_POWER);
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci	error = devm_request_any_context_irq(&pdev->dev, ponkey->irq_dbf,
8562306a36Sopenharmony_ci					     ab8500_ponkey_handler, 0,
8662306a36Sopenharmony_ci					     "ab8500-ponkey-dbf", ponkey);
8762306a36Sopenharmony_ci	if (error < 0) {
8862306a36Sopenharmony_ci		dev_err(ab8500->dev, "Failed to request dbf IRQ#%d: %d\n",
8962306a36Sopenharmony_ci			ponkey->irq_dbf, error);
9062306a36Sopenharmony_ci		return error;
9162306a36Sopenharmony_ci	}
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	error = devm_request_any_context_irq(&pdev->dev, ponkey->irq_dbr,
9462306a36Sopenharmony_ci					     ab8500_ponkey_handler, 0,
9562306a36Sopenharmony_ci					     "ab8500-ponkey-dbr", ponkey);
9662306a36Sopenharmony_ci	if (error < 0) {
9762306a36Sopenharmony_ci		dev_err(ab8500->dev, "Failed to request dbr IRQ#%d: %d\n",
9862306a36Sopenharmony_ci			ponkey->irq_dbr, error);
9962306a36Sopenharmony_ci		return error;
10062306a36Sopenharmony_ci	}
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci	error = input_register_device(ponkey->idev);
10362306a36Sopenharmony_ci	if (error) {
10462306a36Sopenharmony_ci		dev_err(ab8500->dev, "Can't register input device: %d\n", error);
10562306a36Sopenharmony_ci		return error;
10662306a36Sopenharmony_ci	}
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	return 0;
10962306a36Sopenharmony_ci}
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci#ifdef CONFIG_OF
11262306a36Sopenharmony_cistatic const struct of_device_id ab8500_ponkey_match[] = {
11362306a36Sopenharmony_ci	{ .compatible = "stericsson,ab8500-ponkey", },
11462306a36Sopenharmony_ci	{}
11562306a36Sopenharmony_ci};
11662306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, ab8500_ponkey_match);
11762306a36Sopenharmony_ci#endif
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_cistatic struct platform_driver ab8500_ponkey_driver = {
12062306a36Sopenharmony_ci	.driver		= {
12162306a36Sopenharmony_ci		.name	= "ab8500-poweron-key",
12262306a36Sopenharmony_ci		.of_match_table = of_match_ptr(ab8500_ponkey_match),
12362306a36Sopenharmony_ci	},
12462306a36Sopenharmony_ci	.probe		= ab8500_ponkey_probe,
12562306a36Sopenharmony_ci};
12662306a36Sopenharmony_cimodule_platform_driver(ab8500_ponkey_driver);
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
12962306a36Sopenharmony_ciMODULE_AUTHOR("Sundar Iyer <sundar.iyer@stericsson.com>");
13062306a36Sopenharmony_ciMODULE_DESCRIPTION("ST-Ericsson AB8500 Power-ON(Pon) Key driver");
131