linux/drivers/media/rc/zx-irdec.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Copyright (C) 2017 Sanechips Technology Co., Ltd.
   4 * Copyright 2017 Linaro Ltd.
   5 */
   6
   7#include <linux/device.h>
   8#include <linux/err.h>
   9#include <linux/interrupt.h>
  10#include <linux/io.h>
  11#include <linux/module.h>
  12#include <linux/of_platform.h>
  13#include <linux/platform_device.h>
  14
  15#include <media/rc-core.h>
  16
  17#define DRIVER_NAME             "zx-irdec"
  18
  19#define ZX_IR_ENABLE            0x04
  20#define ZX_IREN                 BIT(0)
  21#define ZX_IR_CTRL              0x08
  22#define ZX_DEGL_MASK            GENMASK(21, 20)
  23#define ZX_DEGL_VALUE(x)        (((x) << 20) & ZX_DEGL_MASK)
  24#define ZX_WDBEGIN_MASK         GENMASK(18, 8)
  25#define ZX_WDBEGIN_VALUE(x)     (((x) << 8) & ZX_WDBEGIN_MASK)
  26#define ZX_IR_INTEN             0x10
  27#define ZX_IR_INTSTCLR          0x14
  28#define ZX_IR_CODE              0x30
  29#define ZX_IR_CNUM              0x34
  30#define ZX_NECRPT               BIT(16)
  31
  32struct zx_irdec {
  33        void __iomem *base;
  34        struct rc_dev *rcd;
  35};
  36
  37static void zx_irdec_set_mask(struct zx_irdec *irdec, unsigned int reg,
  38                              u32 mask, u32 value)
  39{
  40        u32 data;
  41
  42        data = readl(irdec->base + reg);
  43        data &= ~mask;
  44        data |= value & mask;
  45        writel(data, irdec->base + reg);
  46}
  47
  48static irqreturn_t zx_irdec_irq(int irq, void *dev_id)
  49{
  50        struct zx_irdec *irdec = dev_id;
  51        u8 address, not_address;
  52        u8 command, not_command;
  53        u32 rawcode, scancode;
  54        enum rc_proto rc_proto;
  55
  56        /* Clear interrupt */
  57        writel(1, irdec->base + ZX_IR_INTSTCLR);
  58
  59        /* Check repeat frame */
  60        if (readl(irdec->base + ZX_IR_CNUM) & ZX_NECRPT) {
  61                rc_repeat(irdec->rcd);
  62                goto done;
  63        }
  64
  65        rawcode = readl(irdec->base + ZX_IR_CODE);
  66        not_command = (rawcode >> 24) & 0xff;
  67        command = (rawcode >> 16) & 0xff;
  68        not_address = (rawcode >> 8) & 0xff;
  69        address = rawcode & 0xff;
  70
  71        scancode = ir_nec_bytes_to_scancode(address, not_address,
  72                                            command, not_command,
  73                                            &rc_proto);
  74        rc_keydown(irdec->rcd, rc_proto, scancode, 0);
  75
  76done:
  77        return IRQ_HANDLED;
  78}
  79
  80static int zx_irdec_probe(struct platform_device *pdev)
  81{
  82        struct device *dev = &pdev->dev;
  83        struct zx_irdec *irdec;
  84        struct resource *res;
  85        struct rc_dev *rcd;
  86        int irq;
  87        int ret;
  88
  89        irdec = devm_kzalloc(dev, sizeof(*irdec), GFP_KERNEL);
  90        if (!irdec)
  91                return -ENOMEM;
  92
  93        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  94        irdec->base = devm_ioremap_resource(dev, res);
  95        if (IS_ERR(irdec->base))
  96                return PTR_ERR(irdec->base);
  97
  98        irq = platform_get_irq(pdev, 0);
  99        if (irq < 0)
 100                return irq;
 101
 102        rcd = devm_rc_allocate_device(dev, RC_DRIVER_SCANCODE);
 103        if (!rcd) {
 104                dev_err(dev, "failed to allocate rc device\n");
 105                return -ENOMEM;
 106        }
 107
 108        irdec->rcd = rcd;
 109
 110        rcd->priv = irdec;
 111        rcd->input_phys = DRIVER_NAME "/input0";
 112        rcd->input_id.bustype = BUS_HOST;
 113        rcd->map_name = RC_MAP_ZX_IRDEC;
 114        rcd->allowed_protocols = RC_PROTO_BIT_NEC | RC_PROTO_BIT_NECX |
 115                                                        RC_PROTO_BIT_NEC32;
 116        rcd->driver_name = DRIVER_NAME;
 117        rcd->device_name = DRIVER_NAME;
 118
 119        platform_set_drvdata(pdev, irdec);
 120
 121        ret = devm_rc_register_device(dev, rcd);
 122        if (ret) {
 123                dev_err(dev, "failed to register rc device\n");
 124                return ret;
 125        }
 126
 127        ret = devm_request_irq(dev, irq, zx_irdec_irq, 0, NULL, irdec);
 128        if (ret) {
 129                dev_err(dev, "failed to request irq\n");
 130                return ret;
 131        }
 132
 133        /*
 134         * Initialize deglitch level and watchdog counter beginner as
 135         * recommended by vendor BSP code.
 136         */
 137        zx_irdec_set_mask(irdec, ZX_IR_CTRL, ZX_DEGL_MASK, ZX_DEGL_VALUE(0));
 138        zx_irdec_set_mask(irdec, ZX_IR_CTRL, ZX_WDBEGIN_MASK,
 139                          ZX_WDBEGIN_VALUE(0x21c));
 140
 141        /* Enable interrupt */
 142        writel(1, irdec->base + ZX_IR_INTEN);
 143
 144        /* Enable the decoder */
 145        zx_irdec_set_mask(irdec, ZX_IR_ENABLE, ZX_IREN, ZX_IREN);
 146
 147        return 0;
 148}
 149
 150static int zx_irdec_remove(struct platform_device *pdev)
 151{
 152        struct zx_irdec *irdec = platform_get_drvdata(pdev);
 153
 154        /* Disable the decoder */
 155        zx_irdec_set_mask(irdec, ZX_IR_ENABLE, ZX_IREN, 0);
 156
 157        /* Disable interrupt */
 158        writel(0, irdec->base + ZX_IR_INTEN);
 159
 160        return 0;
 161}
 162
 163static const struct of_device_id zx_irdec_match[] = {
 164        { .compatible = "zte,zx296718-irdec" },
 165        { },
 166};
 167MODULE_DEVICE_TABLE(of, zx_irdec_match);
 168
 169static struct platform_driver zx_irdec_driver = {
 170        .probe = zx_irdec_probe,
 171        .remove = zx_irdec_remove,
 172        .driver = {
 173                .name = DRIVER_NAME,
 174                .of_match_table = zx_irdec_match,
 175        },
 176};
 177module_platform_driver(zx_irdec_driver);
 178
 179MODULE_DESCRIPTION("ZTE ZX IR remote control driver");
 180MODULE_AUTHOR("Shawn Guo <shawn.guo@linaro.org>");
 181MODULE_LICENSE("GPL v2");
 182