162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (c) 2014, National Instruments Corp. All rights reserved.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Driver for NI Ettus Research USRP E3x0 Button Driver
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <linux/device.h>
962306a36Sopenharmony_ci#include <linux/kernel.h>
1062306a36Sopenharmony_ci#include <linux/module.h>
1162306a36Sopenharmony_ci#include <linux/platform_device.h>
1262306a36Sopenharmony_ci#include <linux/input.h>
1362306a36Sopenharmony_ci#include <linux/interrupt.h>
1462306a36Sopenharmony_ci#include <linux/of.h>
1562306a36Sopenharmony_ci#include <linux/slab.h>
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_cistatic irqreturn_t e3x0_button_release_handler(int irq, void *data)
1862306a36Sopenharmony_ci{
1962306a36Sopenharmony_ci	struct input_dev *idev = data;
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci	input_report_key(idev, KEY_POWER, 0);
2262306a36Sopenharmony_ci	input_sync(idev);
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci	return IRQ_HANDLED;
2562306a36Sopenharmony_ci}
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_cistatic irqreturn_t e3x0_button_press_handler(int irq, void *data)
2862306a36Sopenharmony_ci{
2962306a36Sopenharmony_ci	struct input_dev *idev = data;
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci	input_report_key(idev, KEY_POWER, 1);
3262306a36Sopenharmony_ci	pm_wakeup_event(idev->dev.parent, 0);
3362306a36Sopenharmony_ci	input_sync(idev);
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci	return IRQ_HANDLED;
3662306a36Sopenharmony_ci}
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_cistatic int e3x0_button_suspend(struct device *dev)
3962306a36Sopenharmony_ci{
4062306a36Sopenharmony_ci	struct platform_device *pdev = to_platform_device(dev);
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci	if (device_may_wakeup(dev))
4362306a36Sopenharmony_ci		enable_irq_wake(platform_get_irq_byname(pdev, "press"));
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci	return 0;
4662306a36Sopenharmony_ci}
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_cistatic int e3x0_button_resume(struct device *dev)
4962306a36Sopenharmony_ci{
5062306a36Sopenharmony_ci	struct platform_device *pdev = to_platform_device(dev);
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci	if (device_may_wakeup(dev))
5362306a36Sopenharmony_ci		disable_irq_wake(platform_get_irq_byname(pdev, "press"));
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci	return 0;
5662306a36Sopenharmony_ci}
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_cistatic DEFINE_SIMPLE_DEV_PM_OPS(e3x0_button_pm_ops,
5962306a36Sopenharmony_ci				e3x0_button_suspend, e3x0_button_resume);
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_cistatic int e3x0_button_probe(struct platform_device *pdev)
6262306a36Sopenharmony_ci{
6362306a36Sopenharmony_ci	struct input_dev *input;
6462306a36Sopenharmony_ci	int irq_press, irq_release;
6562306a36Sopenharmony_ci	int error;
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci	irq_press = platform_get_irq_byname(pdev, "press");
6862306a36Sopenharmony_ci	if (irq_press < 0)
6962306a36Sopenharmony_ci		return irq_press;
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci	irq_release = platform_get_irq_byname(pdev, "release");
7262306a36Sopenharmony_ci	if (irq_release < 0)
7362306a36Sopenharmony_ci		return irq_release;
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	input = devm_input_allocate_device(&pdev->dev);
7662306a36Sopenharmony_ci	if (!input)
7762306a36Sopenharmony_ci		return -ENOMEM;
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	input->name = "NI Ettus Research USRP E3x0 Button Driver";
8062306a36Sopenharmony_ci	input->phys = "e3x0_button/input0";
8162306a36Sopenharmony_ci	input->dev.parent = &pdev->dev;
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci	input_set_capability(input, EV_KEY, KEY_POWER);
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	error = devm_request_irq(&pdev->dev, irq_press,
8662306a36Sopenharmony_ci				 e3x0_button_press_handler, 0,
8762306a36Sopenharmony_ci				 "e3x0-button", input);
8862306a36Sopenharmony_ci	if (error) {
8962306a36Sopenharmony_ci		dev_err(&pdev->dev, "Failed to request 'press' IRQ#%d: %d\n",
9062306a36Sopenharmony_ci			irq_press, error);
9162306a36Sopenharmony_ci		return error;
9262306a36Sopenharmony_ci	}
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	error = devm_request_irq(&pdev->dev, irq_release,
9562306a36Sopenharmony_ci				 e3x0_button_release_handler, 0,
9662306a36Sopenharmony_ci				 "e3x0-button", input);
9762306a36Sopenharmony_ci	if (error) {
9862306a36Sopenharmony_ci		dev_err(&pdev->dev, "Failed to request 'release' IRQ#%d: %d\n",
9962306a36Sopenharmony_ci			irq_release, error);
10062306a36Sopenharmony_ci		return error;
10162306a36Sopenharmony_ci	}
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci	error = input_register_device(input);
10462306a36Sopenharmony_ci	if (error) {
10562306a36Sopenharmony_ci		dev_err(&pdev->dev, "Can't register input device: %d\n", error);
10662306a36Sopenharmony_ci		return error;
10762306a36Sopenharmony_ci	}
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	device_init_wakeup(&pdev->dev, 1);
11062306a36Sopenharmony_ci	return 0;
11162306a36Sopenharmony_ci}
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci#ifdef CONFIG_OF
11462306a36Sopenharmony_cistatic const struct of_device_id e3x0_button_match[] = {
11562306a36Sopenharmony_ci	{ .compatible = "ettus,e3x0-button", },
11662306a36Sopenharmony_ci	{ }
11762306a36Sopenharmony_ci};
11862306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, e3x0_button_match);
11962306a36Sopenharmony_ci#endif
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_cistatic struct platform_driver e3x0_button_driver = {
12262306a36Sopenharmony_ci	.driver		= {
12362306a36Sopenharmony_ci		.name	= "e3x0-button",
12462306a36Sopenharmony_ci		.of_match_table = of_match_ptr(e3x0_button_match),
12562306a36Sopenharmony_ci		.pm	= pm_sleep_ptr(&e3x0_button_pm_ops),
12662306a36Sopenharmony_ci	},
12762306a36Sopenharmony_ci	.probe		= e3x0_button_probe,
12862306a36Sopenharmony_ci};
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_cimodule_platform_driver(e3x0_button_driver);
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
13362306a36Sopenharmony_ciMODULE_AUTHOR("Moritz Fischer <moritz.fischer@ettus.com>");
13462306a36Sopenharmony_ciMODULE_DESCRIPTION("NI Ettus Research USRP E3x0 Button driver");
13562306a36Sopenharmony_ciMODULE_ALIAS("platform:e3x0-button");
136