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