Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 // Copyright (C) STMicroelectronics 2018
0003 // Author: Pascal Paillet <p.paillet@st.com> for STMicroelectronics.
0004 
0005 #include <linux/input.h>
0006 #include <linux/interrupt.h>
0007 #include <linux/mfd/stpmic1.h>
0008 #include <linux/module.h>
0009 #include <linux/of.h>
0010 #include <linux/platform_device.h>
0011 #include <linux/property.h>
0012 #include <linux/regmap.h>
0013 
0014 /**
0015  * struct stpmic1_onkey - OnKey data
0016  * @input_dev:      pointer to input device
0017  * @irq_falling:    irq that we are hooked on to
0018  * @irq_rising:     irq that we are hooked on to
0019  */
0020 struct stpmic1_onkey {
0021     struct input_dev *input_dev;
0022     int irq_falling;
0023     int irq_rising;
0024 };
0025 
0026 static irqreturn_t onkey_falling_irq(int irq, void *ponkey)
0027 {
0028     struct stpmic1_onkey *onkey = ponkey;
0029     struct input_dev *input_dev = onkey->input_dev;
0030 
0031     input_report_key(input_dev, KEY_POWER, 1);
0032     pm_wakeup_event(input_dev->dev.parent, 0);
0033     input_sync(input_dev);
0034 
0035     return IRQ_HANDLED;
0036 }
0037 
0038 static irqreturn_t onkey_rising_irq(int irq, void *ponkey)
0039 {
0040     struct stpmic1_onkey *onkey = ponkey;
0041     struct input_dev *input_dev = onkey->input_dev;
0042 
0043     input_report_key(input_dev, KEY_POWER, 0);
0044     pm_wakeup_event(input_dev->dev.parent, 0);
0045     input_sync(input_dev);
0046 
0047     return IRQ_HANDLED;
0048 }
0049 
0050 static int stpmic1_onkey_probe(struct platform_device *pdev)
0051 {
0052     struct stpmic1 *pmic = dev_get_drvdata(pdev->dev.parent);
0053     struct device *dev = &pdev->dev;
0054     struct input_dev *input_dev;
0055     struct stpmic1_onkey *onkey;
0056     unsigned int val, reg = 0;
0057     int error;
0058 
0059     onkey = devm_kzalloc(dev, sizeof(*onkey), GFP_KERNEL);
0060     if (!onkey)
0061         return -ENOMEM;
0062 
0063     onkey->irq_falling = platform_get_irq_byname(pdev, "onkey-falling");
0064     if (onkey->irq_falling < 0)
0065         return onkey->irq_falling;
0066 
0067     onkey->irq_rising = platform_get_irq_byname(pdev, "onkey-rising");
0068     if (onkey->irq_rising < 0)
0069         return onkey->irq_rising;
0070 
0071     if (!device_property_read_u32(dev, "power-off-time-sec", &val)) {
0072         if (val > 0 && val <= 16) {
0073             dev_dbg(dev, "power-off-time=%d seconds\n", val);
0074             reg |= PONKEY_PWR_OFF;
0075             reg |= ((16 - val) & PONKEY_TURNOFF_TIMER_MASK);
0076         } else {
0077             dev_err(dev, "power-off-time-sec out of range\n");
0078             return -EINVAL;
0079         }
0080     }
0081 
0082     if (device_property_present(dev, "st,onkey-clear-cc-flag"))
0083         reg |= PONKEY_CC_FLAG_CLEAR;
0084 
0085     error = regmap_update_bits(pmic->regmap, PKEY_TURNOFF_CR,
0086                    PONKEY_TURNOFF_MASK, reg);
0087     if (error) {
0088         dev_err(dev, "PKEY_TURNOFF_CR write failed: %d\n", error);
0089         return error;
0090     }
0091 
0092     if (device_property_present(dev, "st,onkey-pu-inactive")) {
0093         error = regmap_update_bits(pmic->regmap, PADS_PULL_CR,
0094                        PONKEY_PU_INACTIVE,
0095                        PONKEY_PU_INACTIVE);
0096         if (error) {
0097             dev_err(dev, "ONKEY Pads configuration failed: %d\n",
0098                 error);
0099             return error;
0100         }
0101     }
0102 
0103     input_dev = devm_input_allocate_device(dev);
0104     if (!input_dev) {
0105         dev_err(dev, "Can't allocate Pwr Onkey Input Device\n");
0106         return -ENOMEM;
0107     }
0108 
0109     input_dev->name = "pmic_onkey";
0110     input_dev->phys = "pmic_onkey/input0";
0111 
0112     input_set_capability(input_dev, EV_KEY, KEY_POWER);
0113 
0114     onkey->input_dev = input_dev;
0115 
0116     /* interrupt is nested in a thread */
0117     error = devm_request_threaded_irq(dev, onkey->irq_falling, NULL,
0118                       onkey_falling_irq, IRQF_ONESHOT,
0119                       dev_name(dev), onkey);
0120     if (error) {
0121         dev_err(dev, "Can't get IRQ Onkey Falling: %d\n", error);
0122         return error;
0123     }
0124 
0125     error = devm_request_threaded_irq(dev, onkey->irq_rising, NULL,
0126                       onkey_rising_irq, IRQF_ONESHOT,
0127                       dev_name(dev), onkey);
0128     if (error) {
0129         dev_err(dev, "Can't get IRQ Onkey Rising: %d\n", error);
0130         return error;
0131     }
0132 
0133     error = input_register_device(input_dev);
0134     if (error) {
0135         dev_err(dev, "Can't register power button: %d\n", error);
0136         return error;
0137     }
0138 
0139     platform_set_drvdata(pdev, onkey);
0140     device_init_wakeup(dev, true);
0141 
0142     return 0;
0143 }
0144 
0145 static int __maybe_unused stpmic1_onkey_suspend(struct device *dev)
0146 {
0147     struct platform_device *pdev = to_platform_device(dev);
0148     struct stpmic1_onkey *onkey = platform_get_drvdata(pdev);
0149 
0150     if (device_may_wakeup(dev)) {
0151         enable_irq_wake(onkey->irq_falling);
0152         enable_irq_wake(onkey->irq_rising);
0153     }
0154     return 0;
0155 }
0156 
0157 static int __maybe_unused stpmic1_onkey_resume(struct device *dev)
0158 {
0159     struct platform_device *pdev = to_platform_device(dev);
0160     struct stpmic1_onkey *onkey = platform_get_drvdata(pdev);
0161 
0162     if (device_may_wakeup(dev)) {
0163         disable_irq_wake(onkey->irq_falling);
0164         disable_irq_wake(onkey->irq_rising);
0165     }
0166     return 0;
0167 }
0168 
0169 static SIMPLE_DEV_PM_OPS(stpmic1_onkey_pm,
0170              stpmic1_onkey_suspend,
0171              stpmic1_onkey_resume);
0172 
0173 static const struct of_device_id of_stpmic1_onkey_match[] = {
0174     { .compatible = "st,stpmic1-onkey" },
0175     { },
0176 };
0177 
0178 MODULE_DEVICE_TABLE(of, of_stpmic1_onkey_match);
0179 
0180 static struct platform_driver stpmic1_onkey_driver = {
0181     .probe  = stpmic1_onkey_probe,
0182     .driver = {
0183         .name   = "stpmic1_onkey",
0184         .of_match_table = of_match_ptr(of_stpmic1_onkey_match),
0185         .pm = &stpmic1_onkey_pm,
0186     },
0187 };
0188 module_platform_driver(stpmic1_onkey_driver);
0189 
0190 MODULE_DESCRIPTION("Onkey driver for STPMIC1");
0191 MODULE_AUTHOR("Pascal Paillet <p.paillet@st.com>");
0192 MODULE_LICENSE("GPL v2");