^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) // Copyright (C) STMicroelectronics 2018
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) // Author: Pascal Paillet <p.paillet@st.com> for STMicroelectronics.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) #include <linux/input.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) #include <linux/interrupt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #include <linux/mfd/stpmic1.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/of.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/property.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/regmap.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) * struct stpmic1_onkey - OnKey data
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) * @input_dev: pointer to input device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) * @irq_falling: irq that we are hooked on to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) * @irq_rising: irq that we are hooked on to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) struct stpmic1_onkey {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) struct input_dev *input_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) int irq_falling;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) int irq_rising;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) static irqreturn_t onkey_falling_irq(int irq, void *ponkey)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) struct stpmic1_onkey *onkey = ponkey;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) struct input_dev *input_dev = onkey->input_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) input_report_key(input_dev, KEY_POWER, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) pm_wakeup_event(input_dev->dev.parent, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) input_sync(input_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) return IRQ_HANDLED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) static irqreturn_t onkey_rising_irq(int irq, void *ponkey)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) struct stpmic1_onkey *onkey = ponkey;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) struct input_dev *input_dev = onkey->input_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) input_report_key(input_dev, KEY_POWER, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) pm_wakeup_event(input_dev->dev.parent, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) input_sync(input_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) return IRQ_HANDLED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) static int stpmic1_onkey_probe(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) struct stpmic1 *pmic = dev_get_drvdata(pdev->dev.parent);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) struct device *dev = &pdev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) struct input_dev *input_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) struct stpmic1_onkey *onkey;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) unsigned int val, reg = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) int error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) onkey = devm_kzalloc(dev, sizeof(*onkey), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) if (!onkey)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) onkey->irq_falling = platform_get_irq_byname(pdev, "onkey-falling");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) if (onkey->irq_falling < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) return onkey->irq_falling;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) onkey->irq_rising = platform_get_irq_byname(pdev, "onkey-rising");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) if (onkey->irq_rising < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) return onkey->irq_rising;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) if (!device_property_read_u32(dev, "power-off-time-sec", &val)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) if (val > 0 && val <= 16) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) dev_dbg(dev, "power-off-time=%d seconds\n", val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) reg |= PONKEY_PWR_OFF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) reg |= ((16 - val) & PONKEY_TURNOFF_TIMER_MASK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) dev_err(dev, "power-off-time-sec out of range\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) if (device_property_present(dev, "st,onkey-clear-cc-flag"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) reg |= PONKEY_CC_FLAG_CLEAR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) error = regmap_update_bits(pmic->regmap, PKEY_TURNOFF_CR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) PONKEY_TURNOFF_MASK, reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) if (error) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) dev_err(dev, "PKEY_TURNOFF_CR write failed: %d\n", error);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) return error;
^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) if (device_property_present(dev, "st,onkey-pu-inactive")) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) error = regmap_update_bits(pmic->regmap, PADS_PULL_CR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) PONKEY_PU_INACTIVE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) PONKEY_PU_INACTIVE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) if (error) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) dev_err(dev, "ONKEY Pads configuration failed: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) error);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) return error;
^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)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) input_dev = devm_input_allocate_device(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) if (!input_dev) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) dev_err(dev, "Can't allocate Pwr Onkey Input Device\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) input_dev->name = "pmic_onkey";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) input_dev->phys = "pmic_onkey/input0";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) input_set_capability(input_dev, EV_KEY, KEY_POWER);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) onkey->input_dev = input_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) /* interrupt is nested in a thread */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) error = devm_request_threaded_irq(dev, onkey->irq_falling, NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) onkey_falling_irq, IRQF_ONESHOT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) dev_name(dev), onkey);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) if (error) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) dev_err(dev, "Can't get IRQ Onkey Falling: %d\n", error);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) error = devm_request_threaded_irq(dev, onkey->irq_rising, NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) onkey_rising_irq, IRQF_ONESHOT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) dev_name(dev), onkey);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) if (error) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) dev_err(dev, "Can't get IRQ Onkey Rising: %d\n", error);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) error = input_register_device(input_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) if (error) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) dev_err(dev, "Can't register power button: %d\n", error);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) platform_set_drvdata(pdev, onkey);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) device_init_wakeup(dev, true);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) static int __maybe_unused stpmic1_onkey_suspend(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) struct platform_device *pdev = to_platform_device(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) struct stpmic1_onkey *onkey = platform_get_drvdata(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) if (device_may_wakeup(dev)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) enable_irq_wake(onkey->irq_falling);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) enable_irq_wake(onkey->irq_rising);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) static int __maybe_unused stpmic1_onkey_resume(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) struct platform_device *pdev = to_platform_device(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) struct stpmic1_onkey *onkey = platform_get_drvdata(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) if (device_may_wakeup(dev)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) disable_irq_wake(onkey->irq_falling);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) disable_irq_wake(onkey->irq_rising);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) static SIMPLE_DEV_PM_OPS(stpmic1_onkey_pm,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) stpmic1_onkey_suspend,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) stpmic1_onkey_resume);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) static const struct of_device_id of_stpmic1_onkey_match[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) { .compatible = "st,stpmic1-onkey" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) { },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) MODULE_DEVICE_TABLE(of, of_stpmic1_onkey_match);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) static struct platform_driver stpmic1_onkey_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) .probe = stpmic1_onkey_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) .name = "stpmic1_onkey",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) .of_match_table = of_match_ptr(of_stpmic1_onkey_match),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) .pm = &stpmic1_onkey_pm,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) module_platform_driver(stpmic1_onkey_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) MODULE_DESCRIPTION("Onkey driver for STPMIC1");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) MODULE_AUTHOR("Pascal Paillet <p.paillet@st.com>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) MODULE_LICENSE("GPL v2");