^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) * CPCAP Power Button Input Driver
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Copyright (C) 2017 Sebastian Reichel <sre@kernel.org>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * This file is subject to the terms and conditions of the GNU General
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * Public License. See the file "COPYING" in the main directory of this
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * archive for more details.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * This program is distributed in the hope that it will be useful,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) * but WITHOUT ANY WARRANTY; without even the implied warranty of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) * GNU General Public License for more details.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/errno.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <linux/input.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <linux/interrupt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <linux/regmap.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <linux/of.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #include <linux/mfd/motorola-cpcap.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #define CPCAP_IRQ_ON 23
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #define CPCAP_IRQ_ON_BITMASK (1 << (CPCAP_IRQ_ON % 16))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) struct cpcap_power_button {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) struct regmap *regmap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) struct input_dev *idev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) struct device *dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) static irqreturn_t powerbutton_irq(int irq, void *_button)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) struct cpcap_power_button *button = _button;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) int val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) val = cpcap_sense_virq(button->regmap, irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) if (val < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) dev_err(button->dev, "irq read failed: %d", val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) return IRQ_HANDLED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) pm_wakeup_event(button->dev, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) input_report_key(button->idev, KEY_POWER, val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) input_sync(button->idev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) return IRQ_HANDLED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) static int cpcap_power_button_probe(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) struct cpcap_power_button *button;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) int irq = platform_get_irq(pdev, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) button = devm_kmalloc(&pdev->dev, sizeof(*button), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) if (!button)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) button->idev = devm_input_allocate_device(&pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) if (!button->idev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) button->regmap = dev_get_regmap(pdev->dev.parent, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) if (!button->regmap)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) button->dev = &pdev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) button->idev->name = "cpcap-pwrbutton";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) button->idev->phys = "cpcap-pwrbutton/input0";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) button->idev->dev.parent = button->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) input_set_capability(button->idev, EV_KEY, KEY_POWER);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) err = devm_request_threaded_irq(&pdev->dev, irq, NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) powerbutton_irq, IRQF_ONESHOT, "cpcap_pwrbutton", button);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) if (err < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) dev_err(&pdev->dev, "IRQ request failed: %d\n", err);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) err = input_register_device(button->idev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) if (err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) dev_err(&pdev->dev, "Input register failed: %d\n", err);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) device_init_wakeup(&pdev->dev, true);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) #ifdef CONFIG_OF
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) static const struct of_device_id cpcap_pwrbutton_dt_match_table[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) { .compatible = "motorola,cpcap-pwrbutton" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) {},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) MODULE_DEVICE_TABLE(of, cpcap_pwrbutton_dt_match_table);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) static struct platform_driver cpcap_power_button_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) .probe = cpcap_power_button_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) .name = "cpcap-pwrbutton",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) .of_match_table = of_match_ptr(cpcap_pwrbutton_dt_match_table),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) module_platform_driver(cpcap_power_button_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) MODULE_ALIAS("platform:cpcap-pwrbutton");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) MODULE_DESCRIPTION("CPCAP Power Button");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) MODULE_LICENSE("GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) MODULE_AUTHOR("Sebastian Reichel <sre@kernel.org>");