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