162f0f079SAndrey Smirnov // SPDX-License-Identifier: GPL-2.0+
262f0f079SAndrey Smirnov //
362f0f079SAndrey Smirnov // Power Button driver for RAVE SP
462f0f079SAndrey Smirnov //
562f0f079SAndrey Smirnov // Copyright (C) 2017 Zodiac Inflight Innovations
662f0f079SAndrey Smirnov //
762f0f079SAndrey Smirnov //
862f0f079SAndrey Smirnov 
962f0f079SAndrey Smirnov #include <linux/input.h>
1062f0f079SAndrey Smirnov #include <linux/kernel.h>
1162f0f079SAndrey Smirnov #include <linux/module.h>
1262f0f079SAndrey Smirnov #include <linux/mfd/rave-sp.h>
1362f0f079SAndrey Smirnov #include <linux/platform_device.h>
1462f0f079SAndrey Smirnov 
1562f0f079SAndrey Smirnov #define RAVE_SP_EVNT_BUTTON_PRESS	(RAVE_SP_EVNT_BASE + 0x00)
1662f0f079SAndrey Smirnov 
1762f0f079SAndrey Smirnov struct rave_sp_power_button {
1862f0f079SAndrey Smirnov 	struct input_dev *idev;
1962f0f079SAndrey Smirnov 	struct notifier_block nb;
2062f0f079SAndrey Smirnov };
2162f0f079SAndrey Smirnov 
rave_sp_power_button_event(struct notifier_block * nb,unsigned long action,void * data)2262f0f079SAndrey Smirnov static int rave_sp_power_button_event(struct notifier_block *nb,
2362f0f079SAndrey Smirnov 				      unsigned long action, void *data)
2462f0f079SAndrey Smirnov {
2562f0f079SAndrey Smirnov 	struct rave_sp_power_button *pb =
2662f0f079SAndrey Smirnov 		container_of(nb, struct rave_sp_power_button, nb);
2762f0f079SAndrey Smirnov 	const u8 event = rave_sp_action_unpack_event(action);
2862f0f079SAndrey Smirnov 	const u8 value = rave_sp_action_unpack_value(action);
2962f0f079SAndrey Smirnov 	struct input_dev *idev = pb->idev;
3062f0f079SAndrey Smirnov 
3162f0f079SAndrey Smirnov 	if (event == RAVE_SP_EVNT_BUTTON_PRESS) {
3262f0f079SAndrey Smirnov 		input_report_key(idev, KEY_POWER, value);
3362f0f079SAndrey Smirnov 		input_sync(idev);
3462f0f079SAndrey Smirnov 
3562f0f079SAndrey Smirnov 		return NOTIFY_STOP;
3662f0f079SAndrey Smirnov 	}
3762f0f079SAndrey Smirnov 
3862f0f079SAndrey Smirnov 	return NOTIFY_DONE;
3962f0f079SAndrey Smirnov }
4062f0f079SAndrey Smirnov 
rave_sp_pwrbutton_probe(struct platform_device * pdev)4162f0f079SAndrey Smirnov static int rave_sp_pwrbutton_probe(struct platform_device *pdev)
4262f0f079SAndrey Smirnov {
4362f0f079SAndrey Smirnov 	struct device *dev = &pdev->dev;
4462f0f079SAndrey Smirnov 	struct rave_sp_power_button *pb;
4562f0f079SAndrey Smirnov 	struct input_dev *idev;
4662f0f079SAndrey Smirnov 	int error;
4762f0f079SAndrey Smirnov 
4862f0f079SAndrey Smirnov 	pb = devm_kzalloc(dev, sizeof(*pb), GFP_KERNEL);
4962f0f079SAndrey Smirnov 	if (!pb)
5062f0f079SAndrey Smirnov 		return -ENOMEM;
5162f0f079SAndrey Smirnov 
5262f0f079SAndrey Smirnov 	idev = devm_input_allocate_device(dev);
5362f0f079SAndrey Smirnov 	if (!idev)
5462f0f079SAndrey Smirnov 		return -ENOMEM;
5562f0f079SAndrey Smirnov 
5662f0f079SAndrey Smirnov 	idev->name = pdev->name;
5762f0f079SAndrey Smirnov 
5862f0f079SAndrey Smirnov 	input_set_capability(idev, EV_KEY, KEY_POWER);
5962f0f079SAndrey Smirnov 
6062f0f079SAndrey Smirnov 	error = input_register_device(idev);
6162f0f079SAndrey Smirnov 	if (error)
6262f0f079SAndrey Smirnov 		return error;
6362f0f079SAndrey Smirnov 
6462f0f079SAndrey Smirnov 	pb->idev = idev;
6562f0f079SAndrey Smirnov 	pb->nb.notifier_call = rave_sp_power_button_event;
6662f0f079SAndrey Smirnov 	pb->nb.priority = 128;
6762f0f079SAndrey Smirnov 
6862f0f079SAndrey Smirnov 	error = devm_rave_sp_register_event_notifier(dev, &pb->nb);
6962f0f079SAndrey Smirnov 	if (error)
7062f0f079SAndrey Smirnov 		return error;
7162f0f079SAndrey Smirnov 
7262f0f079SAndrey Smirnov 	return 0;
7362f0f079SAndrey Smirnov }
7462f0f079SAndrey Smirnov 
7562f0f079SAndrey Smirnov static const struct of_device_id rave_sp_pwrbutton_of_match[] = {
7662f0f079SAndrey Smirnov 	{ .compatible = "zii,rave-sp-pwrbutton" },
7762f0f079SAndrey Smirnov 	{}
7862f0f079SAndrey Smirnov };
7962f0f079SAndrey Smirnov 
8062f0f079SAndrey Smirnov static struct platform_driver rave_sp_pwrbutton_driver = {
8162f0f079SAndrey Smirnov 	.probe = rave_sp_pwrbutton_probe,
8262f0f079SAndrey Smirnov 	.driver	= {
8362f0f079SAndrey Smirnov 		.name = KBUILD_MODNAME,
8462f0f079SAndrey Smirnov 		.of_match_table = rave_sp_pwrbutton_of_match,
8562f0f079SAndrey Smirnov 	},
8662f0f079SAndrey Smirnov };
8762f0f079SAndrey Smirnov module_platform_driver(rave_sp_pwrbutton_driver);
8862f0f079SAndrey Smirnov 
8962f0f079SAndrey Smirnov MODULE_DEVICE_TABLE(of, rave_sp_pwrbutton_of_match);
9062f0f079SAndrey Smirnov MODULE_LICENSE("GPL");
9162f0f079SAndrey Smirnov MODULE_AUTHOR("Andrey Vostrikov <andrey.vostrikov@cogentembedded.com>");
9262f0f079SAndrey Smirnov MODULE_AUTHOR("Nikita Yushchenko <nikita.yoush@cogentembedded.com>");
9362f0f079SAndrey Smirnov MODULE_AUTHOR("Andrey Smirnov <andrew.smirnov@gmail.com>");
9462f0f079SAndrey Smirnov MODULE_DESCRIPTION("RAVE SP Power Button driver");
95