From 92fa369780b631a4c3b9f8fcd7ad0959579fba8d Mon Sep 17 00:00:00 2001 From: Sean Young Date: Mon, 8 Jul 2013 17:33:11 -0300 Subject: [PATCH 1/7] BACKPORT: [media] lirc: validate transmission ir data The lirc interface allows 255 u32 spaces and pulses, which are usec. If the driver can handle this (e.g. winbond-cir) you can produce hours of meaningless IR data and there is no method of interrupting it. Change-Id: I8e57017050b367006571fe2c31f58e0d59a828df Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/ir-lirc-codec.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/media/rc/ir-lirc-codec.c b/drivers/media/rc/ir-lirc-codec.c index e4561264e124..e5be920c0599 100644 --- a/drivers/media/rc/ir-lirc-codec.c +++ b/drivers/media/rc/ir-lirc-codec.c @@ -140,11 +140,20 @@ static ssize_t ir_lirc_transmit_ir(struct file *file, const char __user *buf, goto out; } + for (i = 0; i < count; i++) { + if (txbuf[i] > IR_MAX_DURATION / 1000 - duration || !txbuf[i]) { + ret = -EINVAL; + goto out; + } + + duration += txbuf[i]; + } + ret = dev->tx_ir(dev, txbuf, count); if (ret < 0) goto out; - for (i = 0; i < ret; i++) + for (duration = i = 0; i < ret; i++) duration += txbuf[i]; ret *= sizeof(unsigned int); From e66a58f112f5debd2dced76859f7635ee0fbf28e Mon Sep 17 00:00:00 2001 From: Austin Lund Date: Thu, 24 Jul 2014 07:40:20 -0300 Subject: [PATCH 2/7] BACKPORT: [media] media/rc: Send sync space information on the lirc device Userspace expects to see a long space before the first pulse is sent on the lirc device. Currently, if a long time has passed and a new packet is started, the lirc codec just returns and doesn't send anything. This makes lircd ignore many perfectly valid signals unless they are sent in quick sucession. When a reset event is delivered, we cannot know anything about the duration of the space. But it should be safe to assume it has been a long time and we just set the duration to maximum. Change-Id: Ic372e9156f9940534f20d7a8f315699ed769c1be Signed-off-by: Austin Lund Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/ir-lirc-codec.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/media/rc/ir-lirc-codec.c b/drivers/media/rc/ir-lirc-codec.c index e5be920c0599..a97bb49a2e23 100644 --- a/drivers/media/rc/ir-lirc-codec.c +++ b/drivers/media/rc/ir-lirc-codec.c @@ -42,11 +42,17 @@ static int ir_lirc_decode(struct rc_dev *dev, struct ir_raw_event ev) return -EINVAL; /* Packet start */ - if (ev.reset) - return 0; + if (ev.reset) { + /* Userspace expects a long space event before the start of + * the signal to use as a sync. This may be done with repeat + * packets and normal samples. But if a reset has been sent + * then we assume that a long time has passed, so we send a + * space with the maximum time value. */ + sample = LIRC_SPACE(LIRC_VALUE_MASK); + IR_dprintk(2, "delivering reset sync space to lirc_dev\n"); /* Carrier reports */ - if (ev.carrier_report) { + } else if (ev.carrier_report) { sample = LIRC_FREQUENCY(ev.carrier); IR_dprintk(2, "carrier report (freq: %d)\n", sample); From 1f68ffb4f1eee6cea05ff0eeb73df34c57ad278e Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Tue, 18 Nov 2014 17:22:34 -0300 Subject: [PATCH 3/7] BACKPORT: [media] media: rc: add driver for Amlogic Meson IR remote receiver Amlogic Meson SoCs include a infrared remote control receiver that can operate in two modes: "NEC" mode in which the hardware decodes frames using the NEC IR protocol, and "general" mode in which the receiver simply reports the duration of pulses and spaces for software decoding. This is a driver for the IR receiver that implements software decoding of received frames. Signed-off-by: Beniamino Galvani Acked-by: Carlo Caione Signed-off-by: Mauro Carvalho Chehab Conflicts: MAINTAINERS Change-Id: I42ac5837fa3b39939e8abe65a4aba9e748c78ce2 Signed-off-by: Dongjin Kim --- MAINTAINERS | 7 ++ drivers/media/rc/Kconfig | 11 ++ drivers/media/rc/Makefile | 1 + drivers/media/rc/meson-ir.c | 216 ++++++++++++++++++++++++++++++++++++ 4 files changed, 235 insertions(+) create mode 100644 drivers/media/rc/meson-ir.c diff --git a/MAINTAINERS b/MAINTAINERS index 48c748080c96..09ec74fb5f96 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -725,6 +725,13 @@ L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained F: arch/arm/mach-sunxi/ +ARM/Amlogic MesonX SoC support +M: Carlo Caione +L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) +S: Maintained +F: drivers/media/rc/meson-ir.c +N: meson[x68] + ARM/ATMEL AT91RM9200 AND AT91SAM ARM ARCHITECTURES M: Andrew Victor M: Nicolas Ferre diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig index 5a79c333d45e..9701e7358a9b 100644 --- a/drivers/media/rc/Kconfig +++ b/drivers/media/rc/Kconfig @@ -206,6 +206,17 @@ config IR_FINTEK To compile this driver as a module, choose M here: the module will be called fintek-cir. +config IR_MESON + tristate "Amlogic Meson IR remote receiver" + depends on RC_CORE + depends on ARCH_MESON || ARCH_MESON8B || COMPILE_TEST + ---help--- + Say Y if you want to use the IR remote receiver available + on Amlogic Meson SoCs. + + To compile this driver as a module, choose M here: the + module will be called meson-ir. + config IR_NUVOTON tristate "Nuvoton w836x7hg Consumer Infrared Transceiver" depends on PNP diff --git a/drivers/media/rc/Makefile b/drivers/media/rc/Makefile index 56bacf07b361..e715cfab19eb 100644 --- a/drivers/media/rc/Makefile +++ b/drivers/media/rc/Makefile @@ -20,6 +20,7 @@ obj-$(CONFIG_IR_IMON) += imon.o obj-$(CONFIG_IR_ITE_CIR) += ite-cir.o obj-$(CONFIG_IR_MCEUSB) += mceusb.o obj-$(CONFIG_IR_FINTEK) += fintek-cir.o +obj-$(CONFIG_IR_MESON) += meson-ir.o obj-$(CONFIG_IR_NUVOTON) += nuvoton-cir.o obj-$(CONFIG_IR_ENE) += ene_ir.o obj-$(CONFIG_IR_REDRAT3) += redrat3.o diff --git a/drivers/media/rc/meson-ir.c b/drivers/media/rc/meson-ir.c new file mode 100644 index 000000000000..4ee2b5db5443 --- /dev/null +++ b/drivers/media/rc/meson-ir.c @@ -0,0 +1,216 @@ +/* + * Driver for Amlogic Meson IR remote receiver + * + * Copyright (C) 2014 Beniamino Galvani + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define DRIVER_NAME "meson-ir" + +#define IR_DEC_LDR_ACTIVE 0x00 +#define IR_DEC_LDR_IDLE 0x04 +#define IR_DEC_LDR_REPEAT 0x08 +#define IR_DEC_BIT_0 0x0c +#define IR_DEC_REG0 0x10 +#define IR_DEC_FRAME 0x14 +#define IR_DEC_STATUS 0x18 +#define IR_DEC_REG1 0x1c + +#define REG0_RATE_MASK (BIT(11) - 1) + +#define REG1_MODE_MASK (BIT(7) | BIT(8)) +#define REG1_MODE_NEC (0 << 7) +#define REG1_MODE_GENERAL (2 << 7) + +#define REG1_TIME_IV_SHIFT 16 +#define REG1_TIME_IV_MASK ((BIT(13) - 1) << REG1_TIME_IV_SHIFT) + +#define REG1_IRQSEL_MASK (BIT(2) | BIT(3)) +#define REG1_IRQSEL_NEC_MODE (0 << 2) +#define REG1_IRQSEL_RISE_FALL (1 << 2) +#define REG1_IRQSEL_FALL (2 << 2) +#define REG1_IRQSEL_RISE (3 << 2) + +#define REG1_RESET BIT(0) +#define REG1_ENABLE BIT(15) + +#define STATUS_IR_DEC_IN BIT(8) + +#define MESON_TRATE 10 /* us */ + +struct meson_ir { + void __iomem *reg; + struct rc_dev *rc; + int irq; + spinlock_t lock; +}; + +static void meson_ir_set_mask(struct meson_ir *ir, unsigned int reg, + u32 mask, u32 value) +{ + u32 data; + + data = readl(ir->reg + reg); + data &= ~mask; + data |= (value & mask); + writel(data, ir->reg + reg); +} + +static irqreturn_t meson_ir_irq(int irqno, void *dev_id) +{ + struct meson_ir *ir = dev_id; + u32 duration; + DEFINE_IR_RAW_EVENT(rawir); + + spin_lock(&ir->lock); + + duration = readl(ir->reg + IR_DEC_REG1); + duration = (duration & REG1_TIME_IV_MASK) >> REG1_TIME_IV_SHIFT; + rawir.duration = US_TO_NS(duration * MESON_TRATE); + + rawir.pulse = !!(readl(ir->reg + IR_DEC_STATUS) & STATUS_IR_DEC_IN); + + ir_raw_event_store_with_filter(ir->rc, &rawir); + ir_raw_event_handle(ir->rc); + + spin_unlock(&ir->lock); + + return IRQ_HANDLED; +} + +static int meson_ir_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *node = dev->of_node; + struct resource *res; + const char *map_name; + struct meson_ir *ir; + int ret; + + ir = devm_kzalloc(dev, sizeof(struct meson_ir), GFP_KERNEL); + if (!ir) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + ir->reg = devm_ioremap_resource(dev, res); + if (IS_ERR(ir->reg)) { + dev_err(dev, "failed to map registers\n"); + return PTR_ERR(ir->reg); + } + + ir->irq = platform_get_irq(pdev, 0); + if (ir->irq < 0) { + dev_err(dev, "no irq resource\n"); + return ir->irq; + } + + ir->rc = rc_allocate_device(); + if (!ir->rc) { + dev_err(dev, "failed to allocate rc device\n"); + return -ENOMEM; + } + + ir->rc->priv = ir; + ir->rc->input_name = DRIVER_NAME; + ir->rc->input_phys = DRIVER_NAME "/input0"; + ir->rc->input_id.bustype = BUS_HOST; + map_name = of_get_property(node, "linux,rc-map-name", NULL); + ir->rc->map_name = map_name ? map_name : RC_MAP_EMPTY; + ir->rc->dev.parent = dev; + ir->rc->driver_type = RC_DRIVER_IR_RAW; + ir->rc->allowed_protos = RC_BIT_ALL; + ir->rc->rx_resolution = US_TO_NS(MESON_TRATE); + ir->rc->timeout = MS_TO_NS(200); + ir->rc->driver_name = DRIVER_NAME; + + spin_lock_init(&ir->lock); + platform_set_drvdata(pdev, ir); + + ret = rc_register_device(ir->rc); + if (ret) { + dev_err(dev, "failed to register rc device\n"); + goto out_free; + } + + ret = devm_request_irq(dev, ir->irq, meson_ir_irq, 0, "ir-meson", ir); + if (ret) { + dev_err(dev, "failed to request irq\n"); + goto out_unreg; + } + + /* Reset the decoder */ + meson_ir_set_mask(ir, IR_DEC_REG1, REG1_RESET, REG1_RESET); + meson_ir_set_mask(ir, IR_DEC_REG1, REG1_RESET, 0); + /* Set general operation mode */ + meson_ir_set_mask(ir, IR_DEC_REG1, REG1_MODE_MASK, REG1_MODE_GENERAL); + /* Set rate */ + meson_ir_set_mask(ir, IR_DEC_REG0, REG0_RATE_MASK, MESON_TRATE - 1); + /* IRQ on rising and falling edges */ + meson_ir_set_mask(ir, IR_DEC_REG1, REG1_IRQSEL_MASK, + REG1_IRQSEL_RISE_FALL); + /* Enable the decoder */ + meson_ir_set_mask(ir, IR_DEC_REG1, REG1_ENABLE, REG1_ENABLE); + + dev_info(dev, "receiver initialized\n"); + + return 0; +out_unreg: + rc_unregister_device(ir->rc); + ir->rc = NULL; +out_free: + rc_free_device(ir->rc); + + return ret; +} + +static int meson_ir_remove(struct platform_device *pdev) +{ + struct meson_ir *ir = platform_get_drvdata(pdev); + unsigned long flags; + + /* Disable the decoder */ + spin_lock_irqsave(&ir->lock, flags); + meson_ir_set_mask(ir, IR_DEC_REG1, REG1_ENABLE, 0); + spin_unlock_irqrestore(&ir->lock, flags); + + rc_unregister_device(ir->rc); + + return 0; +} + +static const struct of_device_id meson_ir_match[] = { + { .compatible = "amlogic,meson6-ir" }, + { }, +}; + +static struct platform_driver meson_ir_driver = { + .probe = meson_ir_probe, + .remove = meson_ir_remove, + .driver = { + .name = DRIVER_NAME, + .of_match_table = meson_ir_match, + }, +}; + +module_platform_driver(meson_ir_driver); + +MODULE_DESCRIPTION("Amlogic Meson IR remote receiver driver"); +MODULE_AUTHOR("Beniamino Galvani "); +MODULE_LICENSE("GPL v2"); From 70ee28c74fd9ad7cb86e7191d517a620fe16ba57 Mon Sep 17 00:00:00 2001 From: Dongjin Kim Date: Fri, 13 Feb 2015 07:03:35 +0900 Subject: [PATCH 4/7] media/rc: IR receive workaround for ODROID-C1 Sometimes duration read from REG1 is zero when input signal is low, therefore accurated IR receive stream is failed and not able to decode properly. Change-Id: Iff7b597c61a5c58808f3fdc2c96da42a5ebdc0b5 Signed-off-by: Dongjin Kim --- drivers/media/rc/meson-ir.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/media/rc/meson-ir.c b/drivers/media/rc/meson-ir.c index 4ee2b5db5443..d6beafc91e48 100644 --- a/drivers/media/rc/meson-ir.c +++ b/drivers/media/rc/meson-ir.c @@ -76,11 +76,19 @@ static void meson_ir_set_mask(struct meson_ir *ir, unsigned int reg, static irqreturn_t meson_ir_irq(int irqno, void *dev_id) { struct meson_ir *ir = dev_id; +#if !defined(CONFIG_MACH_MESON8B_ODROIDC) u32 duration; DEFINE_IR_RAW_EVENT(rawir); +#endif spin_lock(&ir->lock); +#if defined(CONFIG_MACH_MESON8B_ODROIDC) + ir_raw_event_store_edge(ir->rc, + (readl(ir->reg + IR_DEC_STATUS) & STATUS_IR_DEC_IN) + ? IR_PULSE : IR_SPACE); + ir_raw_event_handle(ir->rc); +#else duration = readl(ir->reg + IR_DEC_REG1); duration = (duration & REG1_TIME_IV_MASK) >> REG1_TIME_IV_SHIFT; rawir.duration = US_TO_NS(duration * MESON_TRATE); @@ -89,6 +97,7 @@ static irqreturn_t meson_ir_irq(int irqno, void *dev_id) ir_raw_event_store_with_filter(ir->rc, &rawir); ir_raw_event_handle(ir->rc); +#endif spin_unlock(&ir->lock); From caa43bd571de99ef4e329d399667743069290a62 Mon Sep 17 00:00:00 2001 From: Dongjin Kim Date: Wed, 11 Feb 2015 02:50:43 +0900 Subject: [PATCH 5/7] media: rc: meson-ir: Add new property 'pulse-inverted' This patch is to add new property 'pulse-inverted' for meson-ir, since some IR receiver's polarity is different. Change-Id: I3b6fe5c21e5243dac185b1933696c22b1f2d98b7 Signed-off-by: Dongjin Kim --- drivers/media/rc/meson-ir.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/media/rc/meson-ir.c b/drivers/media/rc/meson-ir.c index d6beafc91e48..82be948bd0b1 100644 --- a/drivers/media/rc/meson-ir.c +++ b/drivers/media/rc/meson-ir.c @@ -48,6 +48,8 @@ #define REG1_IRQSEL_FALL (2 << 2) #define REG1_IRQSEL_RISE (3 << 2) +#define REG1_POL BIT(1) + #define REG1_RESET BIT(0) #define REG1_ENABLE BIT(15) @@ -111,6 +113,7 @@ static int meson_ir_probe(struct platform_device *pdev) struct resource *res; const char *map_name; struct meson_ir *ir; + bool pulse_inverted = false; int ret; ir = devm_kzalloc(dev, sizeof(struct meson_ir), GFP_KERNEL); @@ -148,6 +151,7 @@ static int meson_ir_probe(struct platform_device *pdev) ir->rc->rx_resolution = US_TO_NS(MESON_TRATE); ir->rc->timeout = MS_TO_NS(200); ir->rc->driver_name = DRIVER_NAME; + pulse_inverted = of_property_read_bool(node, "pulse-inverted"); spin_lock_init(&ir->lock); platform_set_drvdata(pdev, ir); @@ -174,6 +178,9 @@ static int meson_ir_probe(struct platform_device *pdev) /* IRQ on rising and falling edges */ meson_ir_set_mask(ir, IR_DEC_REG1, REG1_IRQSEL_MASK, REG1_IRQSEL_RISE_FALL); + /* Set polarity Invert input polarity */ + meson_ir_set_mask(ir, IR_DEC_REG1, REG1_POL, + pulse_inverted ? REG1_POL : 0); /* Enable the decoder */ meson_ir_set_mask(ir, IR_DEC_REG1, REG1_ENABLE, REG1_ENABLE); From 94881e8bffc965e399388a7a3070b90f26f7faa0 Mon Sep 17 00:00:00 2001 From: Dongjin Kim Date: Wed, 11 Feb 2015 02:58:19 +0900 Subject: [PATCH 6/7] ODROIDC: media/rc: enable IR decode modules Change-Id: I3174f71acb115e4c6571bca3516c9b1355113236 Signed-off-by: Dongjin Kim --- arch/arm/configs/odroidc_defconfig | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/arch/arm/configs/odroidc_defconfig b/arch/arm/configs/odroidc_defconfig index e62ded6e4aa1..565316719447 100644 --- a/arch/arm/configs/odroidc_defconfig +++ b/arch/arm/configs/odroidc_defconfig @@ -2709,23 +2709,24 @@ CONFIG_RC_MAP=y CONFIG_RC_DECODERS=y CONFIG_LIRC=m CONFIG_IR_LIRC_CODEC=m -CONFIG_IR_NEC_DECODER=y -CONFIG_IR_RC5_DECODER=y -CONFIG_IR_RC6_DECODER=y -CONFIG_IR_JVC_DECODER=y -CONFIG_IR_SONY_DECODER=y -CONFIG_IR_RC5_SZ_DECODER=y -CONFIG_IR_SANYO_DECODER=y -CONFIG_IR_MCE_KBD_DECODER=y +CONFIG_IR_NEC_DECODER=m +CONFIG_IR_RC5_DECODER=m +CONFIG_IR_RC6_DECODER=m +CONFIG_IR_JVC_DECODER=m +CONFIG_IR_SONY_DECODER=m +CONFIG_IR_RC5_SZ_DECODER=m +CONFIG_IR_SANYO_DECODER=m +CONFIG_IR_MCE_KBD_DECODER=m CONFIG_RC_DEVICES=y CONFIG_RC_ATI_REMOTE=m CONFIG_IR_IMON=m CONFIG_IR_MCEUSB=m +CONFIG_IR_MESON=m CONFIG_IR_REDRAT3=m CONFIG_IR_STREAMZAP=m CONFIG_IR_IGUANA=m CONFIG_IR_TTUSBIR=m -# CONFIG_RC_LOOPBACK is not set +CONFIG_RC_LOOPBACK=m CONFIG_IR_GPIO_CIR=m CONFIG_MEDIA_USB_SUPPORT=y From 23cf8c62ee20ca85d2c4fed12a3eb26d64dbe2a7 Mon Sep 17 00:00:00 2001 From: Dongjin Kim Date: Tue, 10 Feb 2015 16:10:57 +0900 Subject: [PATCH 7/7] ARM: dts: Add support new ir device Change-Id: I4f5bca7782e69df2299671af5d9298c992c14829 Signed-off-by: Dongjin Kim --- arch/arm/boot/dts/meson8b_odroidc.dts | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/arch/arm/boot/dts/meson8b_odroidc.dts b/arch/arm/boot/dts/meson8b_odroidc.dts index 9a2ed9412055..2d0cc629a657 100755 --- a/arch/arm/boot/dts/meson8b_odroidc.dts +++ b/arch/arm/boot/dts/meson8b_odroidc.dts @@ -457,13 +457,14 @@ status = "okay"; }; - meson-remote{ - compatible = "amlogic,aml_remote"; - dev_name = "meson-remote"; + meson-ir { + compatible = "amlogic,meson6-ir"; + reg = <0xc8100580 0x20>; + interrupts = <0 15 1>; + pinctrl-names = "default"; + pinctrl-0 = <&remote_pins>; + pulse-inverted; status = "ok"; - ao_baseaddr = <0xf3100480>; - pinctrl-names="default"; - pinctrl-0=<&remote_pins>; }; spi@cc000000{