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

gpio-ir-recv.c (5062B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
      3 */
      4
      5#include <linux/kernel.h>
      6#include <linux/init.h>
      7#include <linux/module.h>
      8#include <linux/interrupt.h>
      9#include <linux/gpio/consumer.h>
     10#include <linux/slab.h>
     11#include <linux/of.h>
     12#include <linux/of_gpio.h>
     13#include <linux/platform_device.h>
     14#include <linux/pm_runtime.h>
     15#include <linux/pm_qos.h>
     16#include <linux/irq.h>
     17#include <media/rc-core.h>
     18
     19#define GPIO_IR_DEVICE_NAME	"gpio_ir_recv"
     20
     21struct gpio_rc_dev {
     22	struct rc_dev *rcdev;
     23	struct gpio_desc *gpiod;
     24	int irq;
     25	struct device *pmdev;
     26	struct pm_qos_request qos;
     27};
     28
     29static irqreturn_t gpio_ir_recv_irq(int irq, void *dev_id)
     30{
     31	int val;
     32	struct gpio_rc_dev *gpio_dev = dev_id;
     33	struct device *pmdev = gpio_dev->pmdev;
     34
     35	/*
     36	 * For some cpuidle systems, not all:
     37	 * Respond to interrupt taking more latency when cpu in idle.
     38	 * Invoke asynchronous pm runtime get from interrupt context,
     39	 * this may introduce a millisecond delay to call resume callback,
     40	 * where to disable cpuilde.
     41	 *
     42	 * Two issues lead to fail to decode first frame, one is latency to
     43	 * respond to interrupt, another is delay introduced by async api.
     44	 */
     45	if (pmdev)
     46		pm_runtime_get(pmdev);
     47
     48	val = gpiod_get_value(gpio_dev->gpiod);
     49	if (val >= 0)
     50		ir_raw_event_store_edge(gpio_dev->rcdev, val == 1);
     51
     52	if (pmdev) {
     53		pm_runtime_mark_last_busy(pmdev);
     54		pm_runtime_put_autosuspend(pmdev);
     55	}
     56
     57	return IRQ_HANDLED;
     58}
     59
     60static int gpio_ir_recv_probe(struct platform_device *pdev)
     61{
     62	struct device *dev = &pdev->dev;
     63	struct device_node *np = dev->of_node;
     64	struct gpio_rc_dev *gpio_dev;
     65	struct rc_dev *rcdev;
     66	u32 period = 0;
     67	int rc;
     68
     69	if (!np)
     70		return -ENODEV;
     71
     72	gpio_dev = devm_kzalloc(dev, sizeof(*gpio_dev), GFP_KERNEL);
     73	if (!gpio_dev)
     74		return -ENOMEM;
     75
     76	gpio_dev->gpiod = devm_gpiod_get(dev, NULL, GPIOD_IN);
     77	if (IS_ERR(gpio_dev->gpiod)) {
     78		rc = PTR_ERR(gpio_dev->gpiod);
     79		/* Just try again if this happens */
     80		if (rc != -EPROBE_DEFER)
     81			dev_err(dev, "error getting gpio (%d)\n", rc);
     82		return rc;
     83	}
     84	gpio_dev->irq = gpiod_to_irq(gpio_dev->gpiod);
     85	if (gpio_dev->irq < 0)
     86		return gpio_dev->irq;
     87
     88	rcdev = devm_rc_allocate_device(dev, RC_DRIVER_IR_RAW);
     89	if (!rcdev)
     90		return -ENOMEM;
     91
     92	rcdev->priv = gpio_dev;
     93	rcdev->device_name = GPIO_IR_DEVICE_NAME;
     94	rcdev->input_phys = GPIO_IR_DEVICE_NAME "/input0";
     95	rcdev->input_id.bustype = BUS_HOST;
     96	rcdev->input_id.vendor = 0x0001;
     97	rcdev->input_id.product = 0x0001;
     98	rcdev->input_id.version = 0x0100;
     99	rcdev->dev.parent = dev;
    100	rcdev->driver_name = KBUILD_MODNAME;
    101	rcdev->min_timeout = 1;
    102	rcdev->timeout = IR_DEFAULT_TIMEOUT;
    103	rcdev->max_timeout = 10 * IR_DEFAULT_TIMEOUT;
    104	rcdev->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER;
    105	rcdev->map_name = of_get_property(np, "linux,rc-map-name", NULL);
    106	if (!rcdev->map_name)
    107		rcdev->map_name = RC_MAP_EMPTY;
    108
    109	gpio_dev->rcdev = rcdev;
    110
    111	rc = devm_rc_register_device(dev, rcdev);
    112	if (rc < 0) {
    113		dev_err(dev, "failed to register rc device (%d)\n", rc);
    114		return rc;
    115	}
    116
    117	of_property_read_u32(np, "linux,autosuspend-period", &period);
    118	if (period) {
    119		gpio_dev->pmdev = dev;
    120		pm_runtime_set_autosuspend_delay(dev, period);
    121		pm_runtime_use_autosuspend(dev);
    122		pm_runtime_set_suspended(dev);
    123		pm_runtime_enable(dev);
    124	}
    125
    126	platform_set_drvdata(pdev, gpio_dev);
    127
    128	return devm_request_irq(dev, gpio_dev->irq, gpio_ir_recv_irq,
    129				IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
    130				"gpio-ir-recv-irq", gpio_dev);
    131}
    132
    133#ifdef CONFIG_PM
    134static int gpio_ir_recv_suspend(struct device *dev)
    135{
    136	struct gpio_rc_dev *gpio_dev = dev_get_drvdata(dev);
    137
    138	if (device_may_wakeup(dev))
    139		enable_irq_wake(gpio_dev->irq);
    140	else
    141		disable_irq(gpio_dev->irq);
    142
    143	return 0;
    144}
    145
    146static int gpio_ir_recv_resume(struct device *dev)
    147{
    148	struct gpio_rc_dev *gpio_dev = dev_get_drvdata(dev);
    149
    150	if (device_may_wakeup(dev))
    151		disable_irq_wake(gpio_dev->irq);
    152	else
    153		enable_irq(gpio_dev->irq);
    154
    155	return 0;
    156}
    157
    158static int gpio_ir_recv_runtime_suspend(struct device *dev)
    159{
    160	struct gpio_rc_dev *gpio_dev = dev_get_drvdata(dev);
    161
    162	cpu_latency_qos_remove_request(&gpio_dev->qos);
    163
    164	return 0;
    165}
    166
    167static int gpio_ir_recv_runtime_resume(struct device *dev)
    168{
    169	struct gpio_rc_dev *gpio_dev = dev_get_drvdata(dev);
    170
    171	cpu_latency_qos_add_request(&gpio_dev->qos, 0);
    172
    173	return 0;
    174}
    175
    176static const struct dev_pm_ops gpio_ir_recv_pm_ops = {
    177	.suspend        = gpio_ir_recv_suspend,
    178	.resume         = gpio_ir_recv_resume,
    179	.runtime_suspend = gpio_ir_recv_runtime_suspend,
    180	.runtime_resume  = gpio_ir_recv_runtime_resume,
    181};
    182#endif
    183
    184static const struct of_device_id gpio_ir_recv_of_match[] = {
    185	{ .compatible = "gpio-ir-receiver", },
    186	{ },
    187};
    188MODULE_DEVICE_TABLE(of, gpio_ir_recv_of_match);
    189
    190static struct platform_driver gpio_ir_recv_driver = {
    191	.probe  = gpio_ir_recv_probe,
    192	.driver = {
    193		.name   = KBUILD_MODNAME,
    194		.of_match_table = of_match_ptr(gpio_ir_recv_of_match),
    195#ifdef CONFIG_PM
    196		.pm	= &gpio_ir_recv_pm_ops,
    197#endif
    198	},
    199};
    200module_platform_driver(gpio_ir_recv_driver);
    201
    202MODULE_DESCRIPTION("GPIO IR Receiver driver");
    203MODULE_LICENSE("GPL v2");