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

meson-ir.c (6253B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Driver for Amlogic Meson IR remote receiver
      4 *
      5 * Copyright (C) 2014 Beniamino Galvani <b.galvani@gmail.com>
      6 */
      7
      8#include <linux/device.h>
      9#include <linux/err.h>
     10#include <linux/interrupt.h>
     11#include <linux/io.h>
     12#include <linux/module.h>
     13#include <linux/of_platform.h>
     14#include <linux/platform_device.h>
     15#include <linux/spinlock.h>
     16#include <linux/bitfield.h>
     17
     18#include <media/rc-core.h>
     19
     20#define DRIVER_NAME		"meson-ir"
     21
     22/* valid on all Meson platforms */
     23#define IR_DEC_LDR_ACTIVE	0x00
     24#define IR_DEC_LDR_IDLE		0x04
     25#define IR_DEC_LDR_REPEAT	0x08
     26#define IR_DEC_BIT_0		0x0c
     27#define IR_DEC_REG0		0x10
     28#define IR_DEC_FRAME		0x14
     29#define IR_DEC_STATUS		0x18
     30#define IR_DEC_REG1		0x1c
     31/* only available on Meson 8b and newer */
     32#define IR_DEC_REG2		0x20
     33
     34#define REG0_RATE_MASK		GENMASK(11, 0)
     35
     36#define DECODE_MODE_NEC		0x0
     37#define DECODE_MODE_RAW		0x2
     38
     39/* Meson 6b uses REG1 to configure the mode */
     40#define REG1_MODE_MASK		GENMASK(8, 7)
     41#define REG1_MODE_SHIFT		7
     42
     43/* Meson 8b / GXBB use REG2 to configure the mode */
     44#define REG2_MODE_MASK		GENMASK(3, 0)
     45#define REG2_MODE_SHIFT		0
     46
     47#define REG1_TIME_IV_MASK	GENMASK(28, 16)
     48
     49#define REG1_IRQSEL_MASK	GENMASK(3, 2)
     50#define REG1_IRQSEL_NEC_MODE	0
     51#define REG1_IRQSEL_RISE_FALL	1
     52#define REG1_IRQSEL_FALL	2
     53#define REG1_IRQSEL_RISE	3
     54
     55#define REG1_RESET		BIT(0)
     56#define REG1_ENABLE		BIT(15)
     57
     58#define STATUS_IR_DEC_IN	BIT(8)
     59
     60#define MESON_TRATE		10	/* us */
     61
     62struct meson_ir {
     63	void __iomem	*reg;
     64	struct rc_dev	*rc;
     65	spinlock_t	lock;
     66};
     67
     68static void meson_ir_set_mask(struct meson_ir *ir, unsigned int reg,
     69			      u32 mask, u32 value)
     70{
     71	u32 data;
     72
     73	data = readl(ir->reg + reg);
     74	data &= ~mask;
     75	data |= (value & mask);
     76	writel(data, ir->reg + reg);
     77}
     78
     79static irqreturn_t meson_ir_irq(int irqno, void *dev_id)
     80{
     81	struct meson_ir *ir = dev_id;
     82	u32 duration, status;
     83	struct ir_raw_event rawir = {};
     84
     85	spin_lock(&ir->lock);
     86
     87	duration = readl_relaxed(ir->reg + IR_DEC_REG1);
     88	duration = FIELD_GET(REG1_TIME_IV_MASK, duration);
     89	rawir.duration = duration * MESON_TRATE;
     90
     91	status = readl_relaxed(ir->reg + IR_DEC_STATUS);
     92	rawir.pulse = !!(status & STATUS_IR_DEC_IN);
     93
     94	ir_raw_event_store_with_timeout(ir->rc, &rawir);
     95
     96	spin_unlock(&ir->lock);
     97
     98	return IRQ_HANDLED;
     99}
    100
    101static int meson_ir_probe(struct platform_device *pdev)
    102{
    103	struct device *dev = &pdev->dev;
    104	struct device_node *node = dev->of_node;
    105	const char *map_name;
    106	struct meson_ir *ir;
    107	int irq, ret;
    108
    109	ir = devm_kzalloc(dev, sizeof(struct meson_ir), GFP_KERNEL);
    110	if (!ir)
    111		return -ENOMEM;
    112
    113	ir->reg = devm_platform_ioremap_resource(pdev, 0);
    114	if (IS_ERR(ir->reg))
    115		return PTR_ERR(ir->reg);
    116
    117	irq = platform_get_irq(pdev, 0);
    118	if (irq < 0)
    119		return irq;
    120
    121	ir->rc = devm_rc_allocate_device(dev, RC_DRIVER_IR_RAW);
    122	if (!ir->rc) {
    123		dev_err(dev, "failed to allocate rc device\n");
    124		return -ENOMEM;
    125	}
    126
    127	ir->rc->priv = ir;
    128	ir->rc->device_name = DRIVER_NAME;
    129	ir->rc->input_phys = DRIVER_NAME "/input0";
    130	ir->rc->input_id.bustype = BUS_HOST;
    131	map_name = of_get_property(node, "linux,rc-map-name", NULL);
    132	ir->rc->map_name = map_name ? map_name : RC_MAP_EMPTY;
    133	ir->rc->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER;
    134	ir->rc->rx_resolution = MESON_TRATE;
    135	ir->rc->min_timeout = 1;
    136	ir->rc->timeout = IR_DEFAULT_TIMEOUT;
    137	ir->rc->max_timeout = 10 * IR_DEFAULT_TIMEOUT;
    138	ir->rc->driver_name = DRIVER_NAME;
    139
    140	spin_lock_init(&ir->lock);
    141	platform_set_drvdata(pdev, ir);
    142
    143	ret = devm_rc_register_device(dev, ir->rc);
    144	if (ret) {
    145		dev_err(dev, "failed to register rc device\n");
    146		return ret;
    147	}
    148
    149	ret = devm_request_irq(dev, irq, meson_ir_irq, 0, NULL, ir);
    150	if (ret) {
    151		dev_err(dev, "failed to request irq\n");
    152		return ret;
    153	}
    154
    155	/* Reset the decoder */
    156	meson_ir_set_mask(ir, IR_DEC_REG1, REG1_RESET, REG1_RESET);
    157	meson_ir_set_mask(ir, IR_DEC_REG1, REG1_RESET, 0);
    158
    159	/* Set general operation mode (= raw/software decoding) */
    160	if (of_device_is_compatible(node, "amlogic,meson6-ir"))
    161		meson_ir_set_mask(ir, IR_DEC_REG1, REG1_MODE_MASK,
    162				  FIELD_PREP(REG1_MODE_MASK, DECODE_MODE_RAW));
    163	else
    164		meson_ir_set_mask(ir, IR_DEC_REG2, REG2_MODE_MASK,
    165				  FIELD_PREP(REG2_MODE_MASK, DECODE_MODE_RAW));
    166
    167	/* Set rate */
    168	meson_ir_set_mask(ir, IR_DEC_REG0, REG0_RATE_MASK, MESON_TRATE - 1);
    169	/* IRQ on rising and falling edges */
    170	meson_ir_set_mask(ir, IR_DEC_REG1, REG1_IRQSEL_MASK,
    171			  FIELD_PREP(REG1_IRQSEL_MASK, REG1_IRQSEL_RISE_FALL));
    172	/* Enable the decoder */
    173	meson_ir_set_mask(ir, IR_DEC_REG1, REG1_ENABLE, REG1_ENABLE);
    174
    175	dev_info(dev, "receiver initialized\n");
    176
    177	return 0;
    178}
    179
    180static int meson_ir_remove(struct platform_device *pdev)
    181{
    182	struct meson_ir *ir = platform_get_drvdata(pdev);
    183	unsigned long flags;
    184
    185	/* Disable the decoder */
    186	spin_lock_irqsave(&ir->lock, flags);
    187	meson_ir_set_mask(ir, IR_DEC_REG1, REG1_ENABLE, 0);
    188	spin_unlock_irqrestore(&ir->lock, flags);
    189
    190	return 0;
    191}
    192
    193static void meson_ir_shutdown(struct platform_device *pdev)
    194{
    195	struct device *dev = &pdev->dev;
    196	struct device_node *node = dev->of_node;
    197	struct meson_ir *ir = platform_get_drvdata(pdev);
    198	unsigned long flags;
    199
    200	spin_lock_irqsave(&ir->lock, flags);
    201
    202	/*
    203	 * Set operation mode to NEC/hardware decoding to give
    204	 * bootloader a chance to power the system back on
    205	 */
    206	if (of_device_is_compatible(node, "amlogic,meson6-ir"))
    207		meson_ir_set_mask(ir, IR_DEC_REG1, REG1_MODE_MASK,
    208				  DECODE_MODE_NEC << REG1_MODE_SHIFT);
    209	else
    210		meson_ir_set_mask(ir, IR_DEC_REG2, REG2_MODE_MASK,
    211				  DECODE_MODE_NEC << REG2_MODE_SHIFT);
    212
    213	/* Set rate to default value */
    214	meson_ir_set_mask(ir, IR_DEC_REG0, REG0_RATE_MASK, 0x13);
    215
    216	spin_unlock_irqrestore(&ir->lock, flags);
    217}
    218
    219static const struct of_device_id meson_ir_match[] = {
    220	{ .compatible = "amlogic,meson6-ir" },
    221	{ .compatible = "amlogic,meson8b-ir" },
    222	{ .compatible = "amlogic,meson-gxbb-ir" },
    223	{ },
    224};
    225MODULE_DEVICE_TABLE(of, meson_ir_match);
    226
    227static struct platform_driver meson_ir_driver = {
    228	.probe		= meson_ir_probe,
    229	.remove		= meson_ir_remove,
    230	.shutdown	= meson_ir_shutdown,
    231	.driver = {
    232		.name		= DRIVER_NAME,
    233		.of_match_table	= meson_ir_match,
    234	},
    235};
    236
    237module_platform_driver(meson_ir_driver);
    238
    239MODULE_DESCRIPTION("Amlogic Meson IR remote receiver driver");
    240MODULE_AUTHOR("Beniamino Galvani <b.galvani@gmail.com>");
    241MODULE_LICENSE("GPL v2");