cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

stpmic1_onkey.c (4995B)


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