Resguardo inicial

This commit is contained in:
lastdragon
2026-09-06 12:53:21 -06:00
parent 662efe3c2a
commit ad2088d178
94853 changed files with 43200404 additions and 0 deletions
@@ -0,0 +1,79 @@
# SPDX-License-Identifier: GPL-2.0-only
config IR_IMG
tristate "ImgTec IR Decoder"
depends on RC_CORE
depends on MIPS || COMPILE_TEST
select IR_IMG_HW if !IR_IMG_RAW
help
Say Y or M here if you want to use the ImgTec infrared decoder
functionality found in SoCs such as TZ1090.
config IR_IMG_RAW
bool "Raw decoder"
depends on IR_IMG
help
Say Y here to enable the raw mode driver which passes raw IR signal
changes to the IR raw decoders for software decoding. This is much
less reliable (due to lack of timestamps) and consumes more
processing power than using hardware decode, but can be useful for
testing, debug, and to make more protocols available.
config IR_IMG_HW
bool "Hardware decoder"
depends on IR_IMG
help
Say Y here to enable the hardware decode driver which decodes the IR
signals in hardware. This is more reliable, consumes less processing
power since only a single interrupt is received for each scancode,
and allows an IR scancode to be used as a wake event.
config IR_IMG_NEC
bool "NEC protocol support"
depends on IR_IMG_HW
select BITREVERSE
help
Say Y here to enable support for the NEC, extended NEC, and 32-bit
NEC protocols in the ImgTec infrared decoder block.
config IR_IMG_JVC
bool "JVC protocol support"
depends on IR_IMG_HW
help
Say Y here to enable support for the JVC protocol in the ImgTec
infrared decoder block.
config IR_IMG_SONY
bool "Sony protocol support"
depends on IR_IMG_HW
help
Say Y here to enable support for the Sony protocol in the ImgTec
infrared decoder block.
config IR_IMG_SHARP
bool "Sharp protocol support"
depends on IR_IMG_HW
help
Say Y here to enable support for the Sharp protocol in the ImgTec
infrared decoder block.
config IR_IMG_SANYO
bool "Sanyo protocol support"
depends on IR_IMG_HW
help
Say Y here to enable support for the Sanyo protocol (used by Sanyo,
Aiwa, Chinon remotes) in the ImgTec infrared decoder block.
config IR_IMG_RC5
bool "Philips RC5 protocol support"
depends on IR_IMG_HW
help
Say Y here to enable support for the RC5 protocol in the ImgTec
infrared decoder block.
config IR_IMG_RC6
bool "Philips RC6 protocol support"
depends on IR_IMG_HW
help
Say Y here to enable support for the RC6 protocol in the ImgTec
infrared decoder block.
Note: This version only supports mode 0.
@@ -0,0 +1,14 @@
# SPDX-License-Identifier: GPL-2.0
img-ir-y := img-ir-core.o
img-ir-$(CONFIG_IR_IMG_RAW) += img-ir-raw.o
img-ir-$(CONFIG_IR_IMG_HW) += img-ir-hw.o
img-ir-$(CONFIG_IR_IMG_NEC) += img-ir-nec.o
img-ir-$(CONFIG_IR_IMG_JVC) += img-ir-jvc.o
img-ir-$(CONFIG_IR_IMG_SONY) += img-ir-sony.o
img-ir-$(CONFIG_IR_IMG_SHARP) += img-ir-sharp.o
img-ir-$(CONFIG_IR_IMG_SANYO) += img-ir-sanyo.o
img-ir-$(CONFIG_IR_IMG_RC5) += img-ir-rc5.o
img-ir-$(CONFIG_IR_IMG_RC6) += img-ir-rc6.o
img-ir-objs := $(img-ir-y)
obj-$(CONFIG_IR_IMG) += img-ir.o
@@ -0,0 +1,191 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* ImgTec IR Decoder found in PowerDown Controller.
*
* Copyright 2010-2014 Imagination Technologies Ltd.
*
* This contains core img-ir code for setting up the driver. The two interfaces
* (raw and hardware decode) are handled separately.
*/
#include <linux/clk.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include "img-ir.h"
static irqreturn_t img_ir_isr(int irq, void *dev_id)
{
struct img_ir_priv *priv = dev_id;
u32 irq_status;
spin_lock(&priv->lock);
/* we have to clear irqs before reading */
irq_status = img_ir_read(priv, IMG_IR_IRQ_STATUS);
img_ir_write(priv, IMG_IR_IRQ_CLEAR, irq_status);
/* don't handle valid data irqs if we're only interested in matches */
irq_status &= img_ir_read(priv, IMG_IR_IRQ_ENABLE);
/* hand off edge interrupts to raw decode handler */
if (irq_status & IMG_IR_IRQ_EDGE && img_ir_raw_enabled(&priv->raw))
img_ir_isr_raw(priv, irq_status);
/* hand off hardware match interrupts to hardware decode handler */
if (irq_status & (IMG_IR_IRQ_DATA_MATCH |
IMG_IR_IRQ_DATA_VALID |
IMG_IR_IRQ_DATA2_VALID) &&
img_ir_hw_enabled(&priv->hw))
img_ir_isr_hw(priv, irq_status);
spin_unlock(&priv->lock);
return IRQ_HANDLED;
}
static void img_ir_setup(struct img_ir_priv *priv)
{
/* start off with interrupts disabled */
img_ir_write(priv, IMG_IR_IRQ_ENABLE, 0);
img_ir_setup_raw(priv);
img_ir_setup_hw(priv);
if (!IS_ERR(priv->clk))
clk_prepare_enable(priv->clk);
}
static void img_ir_ident(struct img_ir_priv *priv)
{
u32 core_rev = img_ir_read(priv, IMG_IR_CORE_REV);
dev_info(priv->dev,
"IMG IR Decoder (%d.%d.%d.%d) probed successfully\n",
(core_rev & IMG_IR_DESIGNER) >> IMG_IR_DESIGNER_SHIFT,
(core_rev & IMG_IR_MAJOR_REV) >> IMG_IR_MAJOR_REV_SHIFT,
(core_rev & IMG_IR_MINOR_REV) >> IMG_IR_MINOR_REV_SHIFT,
(core_rev & IMG_IR_MAINT_REV) >> IMG_IR_MAINT_REV_SHIFT);
dev_info(priv->dev, "Modes:%s%s\n",
img_ir_hw_enabled(&priv->hw) ? " hardware" : "",
img_ir_raw_enabled(&priv->raw) ? " raw" : "");
}
static int img_ir_probe(struct platform_device *pdev)
{
struct img_ir_priv *priv;
int irq, error, error2;
/* Get resources from platform device */
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;
/* Private driver data */
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
platform_set_drvdata(pdev, priv);
priv->dev = &pdev->dev;
spin_lock_init(&priv->lock);
/* Ioremap the registers */
priv->reg_base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(priv->reg_base))
return PTR_ERR(priv->reg_base);
/* Get core clock */
priv->clk = devm_clk_get(&pdev->dev, "core");
if (IS_ERR(priv->clk))
dev_warn(&pdev->dev, "cannot get core clock resource\n");
/* Get sys clock */
priv->sys_clk = devm_clk_get(&pdev->dev, "sys");
if (IS_ERR(priv->sys_clk))
dev_warn(&pdev->dev, "cannot get sys clock resource\n");
/*
* Enabling the system clock before the register interface is
* accessed. ISR shouldn't get called with Sys Clock disabled,
* hence exiting probe with an error.
*/
if (!IS_ERR(priv->sys_clk)) {
error = clk_prepare_enable(priv->sys_clk);
if (error) {
dev_err(&pdev->dev, "cannot enable sys clock\n");
return error;
}
}
/* Set up raw & hw decoder */
error = img_ir_probe_raw(priv);
error2 = img_ir_probe_hw(priv);
if (error && error2) {
if (error == -ENODEV)
error = error2;
goto err_probe;
}
/* Get the IRQ */
priv->irq = irq;
error = request_irq(priv->irq, img_ir_isr, 0, "img-ir", priv);
if (error) {
dev_err(&pdev->dev, "cannot register IRQ %u\n",
priv->irq);
error = -EIO;
goto err_irq;
}
img_ir_ident(priv);
img_ir_setup(priv);
return 0;
err_irq:
img_ir_remove_hw(priv);
img_ir_remove_raw(priv);
err_probe:
if (!IS_ERR(priv->sys_clk))
clk_disable_unprepare(priv->sys_clk);
return error;
}
static void img_ir_remove(struct platform_device *pdev)
{
struct img_ir_priv *priv = platform_get_drvdata(pdev);
free_irq(priv->irq, priv);
img_ir_remove_hw(priv);
img_ir_remove_raw(priv);
if (!IS_ERR(priv->clk))
clk_disable_unprepare(priv->clk);
if (!IS_ERR(priv->sys_clk))
clk_disable_unprepare(priv->sys_clk);
}
static SIMPLE_DEV_PM_OPS(img_ir_pmops, img_ir_suspend, img_ir_resume);
static const struct of_device_id img_ir_match[] = {
{ .compatible = "img,ir-rev1" },
{}
};
MODULE_DEVICE_TABLE(of, img_ir_match);
static struct platform_driver img_ir_driver = {
.driver = {
.name = "img-ir",
.of_match_table = img_ir_match,
.pm = &img_ir_pmops,
},
.probe = img_ir_probe,
.remove = img_ir_remove,
};
module_platform_driver(img_ir_driver);
MODULE_AUTHOR("Imagination Technologies Ltd.");
MODULE_DESCRIPTION("ImgTec IR");
MODULE_LICENSE("GPL");
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,297 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* ImgTec IR Hardware Decoder found in PowerDown Controller.
*
* Copyright 2010-2014 Imagination Technologies Ltd.
*/
#ifndef _IMG_IR_HW_H_
#define _IMG_IR_HW_H_
#include <linux/kernel.h>
#include <media/rc-core.h>
/* constants */
#define IMG_IR_CODETYPE_PULSELEN 0x0 /* Sony */
#define IMG_IR_CODETYPE_PULSEDIST 0x1 /* NEC, Toshiba, Micom, Sharp */
#define IMG_IR_CODETYPE_BIPHASE 0x2 /* RC-5/6 */
#define IMG_IR_CODETYPE_2BITPULSEPOS 0x3 /* RC-MM */
/* Timing information */
/**
* struct img_ir_control - Decoder control settings
* @decoden: Primary decoder enable
* @code_type: Decode type (see IMG_IR_CODETYPE_*)
* @hdrtog: Detect header toggle symbol after leader symbol
* @ldrdec: Don't discard leader if maximum width reached
* @decodinpol: Decoder input polarity (1=active high)
* @bitorien: Bit orientation (1=MSB first)
* @d1validsel: Decoder 2 takes over if it detects valid data
* @bitinv: Bit inversion switch (1=don't invert)
* @decodend2: Secondary decoder enable (no leader symbol)
* @bitoriend2: Bit orientation (1=MSB first)
* @bitinvd2: Secondary decoder bit inversion switch (1=don't invert)
*/
struct img_ir_control {
unsigned decoden:1;
unsigned code_type:2;
unsigned hdrtog:1;
unsigned ldrdec:1;
unsigned decodinpol:1;
unsigned bitorien:1;
unsigned d1validsel:1;
unsigned bitinv:1;
unsigned decodend2:1;
unsigned bitoriend2:1;
unsigned bitinvd2:1;
};
/**
* struct img_ir_timing_range - range of timing values
* @min: Minimum timing value
* @max: Maximum timing value (if < @min, this will be set to @min during
* preprocessing step, so it is normally not explicitly initialised
* and is taken care of by the tolerance)
*/
struct img_ir_timing_range {
u16 min;
u16 max;
};
/**
* struct img_ir_symbol_timing - timing data for a symbol
* @pulse: Timing range for the length of the pulse in this symbol
* @space: Timing range for the length of the space in this symbol
*/
struct img_ir_symbol_timing {
struct img_ir_timing_range pulse;
struct img_ir_timing_range space;
};
/**
* struct img_ir_free_timing - timing data for free time symbol
* @minlen: Minimum number of bits of data
* @maxlen: Maximum number of bits of data
* @ft_min: Minimum free time after message
*/
struct img_ir_free_timing {
/* measured in bits */
u8 minlen;
u8 maxlen;
u16 ft_min;
};
/**
* struct img_ir_timings - Timing values.
* @ldr: Leader symbol timing data
* @s00: Zero symbol timing data for primary decoder
* @s01: One symbol timing data for primary decoder
* @s10: Zero symbol timing data for secondary (no leader symbol) decoder
* @s11: One symbol timing data for secondary (no leader symbol) decoder
* @ft: Free time symbol timing data
*/
struct img_ir_timings {
struct img_ir_symbol_timing ldr, s00, s01, s10, s11;
struct img_ir_free_timing ft;
};
/**
* struct img_ir_filter - Filter IR events.
* @data: Data to match.
* @mask: Mask of bits to compare.
* @minlen: Additional minimum number of bits.
* @maxlen: Additional maximum number of bits.
*/
struct img_ir_filter {
u64 data;
u64 mask;
u8 minlen;
u8 maxlen;
};
/**
* struct img_ir_timing_regvals - Calculated timing register values.
* @ldr: Leader symbol timing register value
* @s00: Zero symbol timing register value for primary decoder
* @s01: One symbol timing register value for primary decoder
* @s10: Zero symbol timing register value for secondary decoder
* @s11: One symbol timing register value for secondary decoder
* @ft: Free time symbol timing register value
*/
struct img_ir_timing_regvals {
u32 ldr, s00, s01, s10, s11, ft;
};
#define IMG_IR_SCANCODE 0 /* new scancode */
#define IMG_IR_REPEATCODE 1 /* repeat the previous code */
/**
* struct img_ir_scancode_req - Scancode request data.
* @protocol: Protocol code of received message (defaults to
* RC_PROTO_UNKNOWN).
* @scancode: Scan code of received message (must be written by
* handler if IMG_IR_SCANCODE is returned).
* @toggle: Toggle bit (defaults to 0).
*/
struct img_ir_scancode_req {
enum rc_proto protocol;
u32 scancode;
u8 toggle;
};
/**
* struct img_ir_decoder - Decoder settings for an IR protocol.
* @type: Protocol types bitmap.
* @tolerance: Timing tolerance as a percentage (default 10%).
* @unit: Unit of timings in nanoseconds (default 1 us).
* @timings: Primary timings
* @rtimings: Additional override timings while waiting for repeats.
* @repeat: Maximum repeat interval (always in milliseconds).
* @control: Control flags.
*
* @scancode: Pointer to function to convert the IR data into a scancode (it
* must be safe to execute in interrupt context).
* Returns IMG_IR_SCANCODE to emit new scancode.
* Returns IMG_IR_REPEATCODE to repeat previous code.
* Returns -errno (e.g. -EINVAL) on error.
* @filter: Pointer to function to convert scancode filter to raw hardware
* filter. The minlen and maxlen fields will have been initialised
* to the maximum range.
*/
struct img_ir_decoder {
/* core description */
u64 type;
unsigned int tolerance;
unsigned int unit;
struct img_ir_timings timings;
struct img_ir_timings rtimings;
unsigned int repeat;
struct img_ir_control control;
/* scancode logic */
int (*scancode)(int len, u64 raw, u64 enabled_protocols,
struct img_ir_scancode_req *request);
int (*filter)(const struct rc_scancode_filter *in,
struct img_ir_filter *out, u64 protocols);
};
extern struct img_ir_decoder img_ir_nec;
extern struct img_ir_decoder img_ir_jvc;
extern struct img_ir_decoder img_ir_sony;
extern struct img_ir_decoder img_ir_sharp;
extern struct img_ir_decoder img_ir_sanyo;
extern struct img_ir_decoder img_ir_rc5;
extern struct img_ir_decoder img_ir_rc6;
/**
* struct img_ir_reg_timings - Reg values for decoder timings at clock rate.
* @ctrl: Processed control register value.
* @timings: Processed primary timings.
* @rtimings: Processed repeat timings.
*/
struct img_ir_reg_timings {
u32 ctrl;
struct img_ir_timing_regvals timings;
struct img_ir_timing_regvals rtimings;
};
struct img_ir_priv;
#ifdef CONFIG_IR_IMG_HW
enum img_ir_mode {
IMG_IR_M_NORMAL,
IMG_IR_M_REPEATING,
#ifdef CONFIG_PM_SLEEP
IMG_IR_M_WAKE,
#endif
};
/**
* struct img_ir_priv_hw - Private driver data for hardware decoder.
* @ct_quirks: Quirk bits for each code type.
* @rdev: Remote control device
* @clk_nb: Notifier block for clock notify events.
* @end_timer: Timer until repeat timeout.
* @suspend_timer: Timer to re-enable protocol.
* @decoder: Current decoder settings.
* @enabled_protocols: Currently enabled protocols.
* @clk_hz: Current core clock rate in Hz.
* @reg_timings: Timing reg values for decoder at clock rate.
* @flags: IMG_IR_F_*.
* @filters: HW filters (derived from scancode filters).
* @mode: Current decode mode.
* @stopping: Indicates that decoder is being taken down and timers
* should not be restarted.
* @suspend_irqen: Saved IRQ enable mask over suspend.
* @quirk_suspend_irq: Saved IRQ enable mask over quirk suspend timer.
*/
struct img_ir_priv_hw {
unsigned int ct_quirks[4];
struct rc_dev *rdev;
struct notifier_block clk_nb;
struct timer_list end_timer;
struct timer_list suspend_timer;
const struct img_ir_decoder *decoder;
u64 enabled_protocols;
unsigned long clk_hz;
struct img_ir_reg_timings reg_timings;
unsigned int flags;
struct img_ir_filter filters[RC_FILTER_MAX];
enum img_ir_mode mode;
bool stopping;
u32 suspend_irqen;
u32 quirk_suspend_irq;
};
static inline bool img_ir_hw_enabled(struct img_ir_priv_hw *hw)
{
return hw->rdev;
};
void img_ir_isr_hw(struct img_ir_priv *priv, u32 irq_status);
void img_ir_setup_hw(struct img_ir_priv *priv);
int img_ir_probe_hw(struct img_ir_priv *priv);
void img_ir_remove_hw(struct img_ir_priv *priv);
#ifdef CONFIG_PM_SLEEP
int img_ir_suspend(struct device *dev);
int img_ir_resume(struct device *dev);
#else
#define img_ir_suspend NULL
#define img_ir_resume NULL
#endif
#else
struct img_ir_priv_hw {
};
static inline bool img_ir_hw_enabled(struct img_ir_priv_hw *hw)
{
return false;
};
static inline void img_ir_isr_hw(struct img_ir_priv *priv, u32 irq_status)
{
}
static inline void img_ir_setup_hw(struct img_ir_priv *priv)
{
}
static inline int img_ir_probe_hw(struct img_ir_priv *priv)
{
return -ENODEV;
}
static inline void img_ir_remove_hw(struct img_ir_priv *priv)
{
}
#define img_ir_suspend NULL
#define img_ir_resume NULL
#endif /* CONFIG_IR_IMG_HW */
#endif /* _IMG_IR_HW_H_ */
@@ -0,0 +1,84 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* ImgTec IR Decoder setup for JVC protocol.
*
* Copyright 2012-2014 Imagination Technologies Ltd.
*/
#include "img-ir-hw.h"
/* Convert JVC data to a scancode */
static int img_ir_jvc_scancode(int len, u64 raw, u64 enabled_protocols,
struct img_ir_scancode_req *request)
{
unsigned int cust, data;
if (len != 16)
return -EINVAL;
cust = (raw >> 0) & 0xff;
data = (raw >> 8) & 0xff;
request->protocol = RC_PROTO_JVC;
request->scancode = cust << 8 | data;
return IMG_IR_SCANCODE;
}
/* Convert JVC scancode to JVC data filter */
static int img_ir_jvc_filter(const struct rc_scancode_filter *in,
struct img_ir_filter *out, u64 protocols)
{
unsigned int cust, data;
unsigned int cust_m, data_m;
cust = (in->data >> 8) & 0xff;
cust_m = (in->mask >> 8) & 0xff;
data = (in->data >> 0) & 0xff;
data_m = (in->mask >> 0) & 0xff;
out->data = cust | data << 8;
out->mask = cust_m | data_m << 8;
return 0;
}
/*
* JVC decoder
* See also http://www.sbprojects.com/knowledge/ir/jvc.php
* http://support.jvc.com/consumer/support/documents/RemoteCodes.pdf
*/
struct img_ir_decoder img_ir_jvc = {
.type = RC_PROTO_BIT_JVC,
.control = {
.decoden = 1,
.code_type = IMG_IR_CODETYPE_PULSEDIST,
},
/* main timings */
.unit = 527500, /* 527.5 us */
.timings = {
/* leader symbol */
.ldr = {
.pulse = { 16 /* 8.44 ms */ },
.space = { 8 /* 4.22 ms */ },
},
/* 0 symbol */
.s00 = {
.pulse = { 1 /* 527.5 us +-60 us */ },
.space = { 1 /* 527.5 us */ },
},
/* 1 symbol */
.s01 = {
.pulse = { 1 /* 527.5 us +-60 us */ },
.space = { 3 /* 1.5825 ms +-40 us */ },
},
/* free time */
.ft = {
.minlen = 16,
.maxlen = 16,
.ft_min = 10, /* 5.275 ms */
},
},
/* scancode logic */
.scancode = img_ir_jvc_scancode,
.filter = img_ir_jvc_filter,
};
@@ -0,0 +1,173 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* ImgTec IR Decoder setup for NEC protocol.
*
* Copyright 2010-2014 Imagination Technologies Ltd.
*/
#include "img-ir-hw.h"
#include <linux/bitrev.h>
#include <linux/log2.h>
/* Convert NEC data to a scancode */
static int img_ir_nec_scancode(int len, u64 raw, u64 enabled_protocols,
struct img_ir_scancode_req *request)
{
unsigned int addr, addr_inv, data, data_inv;
/* a repeat code has no data */
if (!len)
return IMG_IR_REPEATCODE;
if (len != 32)
return -EINVAL;
/* raw encoding: ddDDaaAA */
addr = (raw >> 0) & 0xff;
addr_inv = (raw >> 8) & 0xff;
data = (raw >> 16) & 0xff;
data_inv = (raw >> 24) & 0xff;
if ((data_inv ^ data) != 0xff) {
/* 32-bit NEC (used by Apple and TiVo remotes) */
/* scan encoding: as transmitted, MSBit = first received bit */
request->scancode = bitrev8(addr) << 24 |
bitrev8(addr_inv) << 16 |
bitrev8(data) << 8 |
bitrev8(data_inv);
request->protocol = RC_PROTO_NEC32;
} else if ((addr_inv ^ addr) != 0xff) {
/* Extended NEC */
/* scan encoding: AAaaDD */
request->scancode = addr << 16 |
addr_inv << 8 |
data;
request->protocol = RC_PROTO_NECX;
} else {
/* Normal NEC */
/* scan encoding: AADD */
request->scancode = addr << 8 |
data;
request->protocol = RC_PROTO_NEC;
}
return IMG_IR_SCANCODE;
}
/* Convert NEC scancode to NEC data filter */
static int img_ir_nec_filter(const struct rc_scancode_filter *in,
struct img_ir_filter *out, u64 protocols)
{
unsigned int addr, addr_inv, data, data_inv;
unsigned int addr_m, addr_inv_m, data_m, data_inv_m;
data = in->data & 0xff;
data_m = in->mask & 0xff;
protocols &= RC_PROTO_BIT_NEC | RC_PROTO_BIT_NECX | RC_PROTO_BIT_NEC32;
/*
* If only one bit is set, we were requested to do an exact
* protocol. This should be the case for wakeup filters; for
* normal filters, guess the protocol from the scancode.
*/
if (!is_power_of_2(protocols)) {
if ((in->data | in->mask) & 0xff000000)
protocols = RC_PROTO_BIT_NEC32;
else if ((in->data | in->mask) & 0x00ff0000)
protocols = RC_PROTO_BIT_NECX;
else
protocols = RC_PROTO_BIT_NEC;
}
if (protocols == RC_PROTO_BIT_NEC32) {
/* 32-bit NEC (used by Apple and TiVo remotes) */
/* scan encoding: as transmitted, MSBit = first received bit */
addr = bitrev8(in->data >> 24);
addr_m = bitrev8(in->mask >> 24);
addr_inv = bitrev8(in->data >> 16);
addr_inv_m = bitrev8(in->mask >> 16);
data = bitrev8(in->data >> 8);
data_m = bitrev8(in->mask >> 8);
data_inv = bitrev8(in->data >> 0);
data_inv_m = bitrev8(in->mask >> 0);
} else if (protocols == RC_PROTO_BIT_NECX) {
/* Extended NEC */
/* scan encoding AAaaDD */
addr = (in->data >> 16) & 0xff;
addr_m = (in->mask >> 16) & 0xff;
addr_inv = (in->data >> 8) & 0xff;
addr_inv_m = (in->mask >> 8) & 0xff;
data_inv = data ^ 0xff;
data_inv_m = data_m;
} else {
/* Normal NEC */
/* scan encoding: AADD */
addr = (in->data >> 8) & 0xff;
addr_m = (in->mask >> 8) & 0xff;
addr_inv = addr ^ 0xff;
addr_inv_m = addr_m;
data_inv = data ^ 0xff;
data_inv_m = data_m;
}
/* raw encoding: ddDDaaAA */
out->data = data_inv << 24 |
data << 16 |
addr_inv << 8 |
addr;
out->mask = data_inv_m << 24 |
data_m << 16 |
addr_inv_m << 8 |
addr_m;
return 0;
}
/*
* NEC decoder
* See also http://www.sbprojects.com/knowledge/ir/nec.php
* http://wiki.altium.com/display/ADOH/NEC+Infrared+Transmission+Protocol
*/
struct img_ir_decoder img_ir_nec = {
.type = RC_PROTO_BIT_NEC | RC_PROTO_BIT_NECX | RC_PROTO_BIT_NEC32,
.control = {
.decoden = 1,
.code_type = IMG_IR_CODETYPE_PULSEDIST,
},
/* main timings */
.unit = 562500, /* 562.5 us */
.timings = {
/* leader symbol */
.ldr = {
.pulse = { 16 /* 9ms */ },
.space = { 8 /* 4.5ms */ },
},
/* 0 symbol */
.s00 = {
.pulse = { 1 /* 562.5 us */ },
.space = { 1 /* 562.5 us */ },
},
/* 1 symbol */
.s01 = {
.pulse = { 1 /* 562.5 us */ },
.space = { 3 /* 1687.5 us */ },
},
/* free time */
.ft = {
.minlen = 32,
.maxlen = 32,
.ft_min = 10, /* 5.625 ms */
},
},
/* repeat codes */
.repeat = 108, /* 108 ms */
.rtimings = {
/* leader symbol */
.ldr = {
.space = { 4 /* 2.25 ms */ },
},
/* free time */
.ft = {
.minlen = 0, /* repeat code has no data */
.maxlen = 0,
},
},
/* scancode logic */
.scancode = img_ir_nec_scancode,
.filter = img_ir_nec_filter,
};
@@ -0,0 +1,152 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* ImgTec IR Raw Decoder found in PowerDown Controller.
*
* Copyright 2010-2014 Imagination Technologies Ltd.
*
* This ties into the input subsystem using the RC-core in raw mode. Raw IR
* signal edges are reported and decoded by generic software decoders.
*/
#include <linux/spinlock.h>
#include <media/rc-core.h>
#include "img-ir.h"
#define ECHO_TIMEOUT_MS 150 /* ms between echos */
/* must be called with priv->lock held */
static void img_ir_refresh_raw(struct img_ir_priv *priv, u32 irq_status)
{
struct img_ir_priv_raw *raw = &priv->raw;
struct rc_dev *rc_dev = priv->raw.rdev;
int multiple;
u32 ir_status;
/* find whether both rise and fall was detected */
multiple = ((irq_status & IMG_IR_IRQ_EDGE) == IMG_IR_IRQ_EDGE);
/*
* If so, we need to see if the level has actually changed.
* If it's just noise that we didn't have time to process,
* there's no point reporting it.
*/
ir_status = img_ir_read(priv, IMG_IR_STATUS) & IMG_IR_IRRXD;
if (multiple && ir_status == raw->last_status)
return;
raw->last_status = ir_status;
/* report the edge to the IR raw decoders */
if (ir_status) /* low */
ir_raw_event_store_edge(rc_dev, false);
else /* high */
ir_raw_event_store_edge(rc_dev, true);
ir_raw_event_handle(rc_dev);
}
/* called with priv->lock held */
void img_ir_isr_raw(struct img_ir_priv *priv, u32 irq_status)
{
struct img_ir_priv_raw *raw = &priv->raw;
/* check not removing */
if (!raw->rdev)
return;
img_ir_refresh_raw(priv, irq_status);
/* start / push back the echo timer */
mod_timer(&raw->timer, jiffies + msecs_to_jiffies(ECHO_TIMEOUT_MS));
}
/*
* Echo timer callback function.
* The raw decoders expect to get a final sample even if there are no edges, in
* order to be assured of the final space. If there are no edges for a certain
* time we use this timer to emit a final sample to satisfy them.
*/
static void img_ir_echo_timer(struct timer_list *t)
{
struct img_ir_priv *priv = timer_container_of(priv, t, raw.timer);
spin_lock_irq(&priv->lock);
/* check not removing */
if (priv->raw.rdev)
/*
* It's safe to pass irq_status=0 since it's only used to check
* for double edges.
*/
img_ir_refresh_raw(priv, 0);
spin_unlock_irq(&priv->lock);
}
void img_ir_setup_raw(struct img_ir_priv *priv)
{
u32 irq_en;
if (!priv->raw.rdev)
return;
/* clear and enable edge interrupts */
spin_lock_irq(&priv->lock);
irq_en = img_ir_read(priv, IMG_IR_IRQ_ENABLE);
irq_en |= IMG_IR_IRQ_EDGE;
img_ir_write(priv, IMG_IR_IRQ_CLEAR, IMG_IR_IRQ_EDGE);
img_ir_write(priv, IMG_IR_IRQ_ENABLE, irq_en);
spin_unlock_irq(&priv->lock);
}
int img_ir_probe_raw(struct img_ir_priv *priv)
{
struct img_ir_priv_raw *raw = &priv->raw;
struct rc_dev *rdev;
int error;
/* Set up the echo timer */
timer_setup(&raw->timer, img_ir_echo_timer, 0);
/* Allocate raw decoder */
raw->rdev = rdev = rc_allocate_device(RC_DRIVER_IR_RAW);
if (!rdev) {
dev_err(priv->dev, "cannot allocate raw input device\n");
return -ENOMEM;
}
rdev->priv = priv;
rdev->map_name = RC_MAP_EMPTY;
rdev->device_name = "IMG Infrared Decoder Raw";
/* Register raw decoder */
error = rc_register_device(rdev);
if (error) {
dev_err(priv->dev, "failed to register raw IR input device\n");
rc_free_device(rdev);
raw->rdev = NULL;
return error;
}
return 0;
}
void img_ir_remove_raw(struct img_ir_priv *priv)
{
struct img_ir_priv_raw *raw = &priv->raw;
struct rc_dev *rdev = raw->rdev;
u32 irq_en;
if (!rdev)
return;
rc_unregister_device(rdev);
/* switch off and disable raw (edge) interrupts */
spin_lock_irq(&priv->lock);
raw->rdev = NULL;
irq_en = img_ir_read(priv, IMG_IR_IRQ_ENABLE);
irq_en &= ~IMG_IR_IRQ_EDGE;
img_ir_write(priv, IMG_IR_IRQ_ENABLE, irq_en);
img_ir_write(priv, IMG_IR_IRQ_CLEAR, IMG_IR_IRQ_EDGE);
spin_unlock_irq(&priv->lock);
rc_free_device(rdev);
timer_delete_sync(&raw->timer);
}
@@ -0,0 +1,61 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* ImgTec IR Raw Decoder found in PowerDown Controller.
*
* Copyright 2010-2014 Imagination Technologies Ltd.
*/
#ifndef _IMG_IR_RAW_H_
#define _IMG_IR_RAW_H_
struct img_ir_priv;
#ifdef CONFIG_IR_IMG_RAW
/**
* struct img_ir_priv_raw - Private driver data for raw decoder.
* @rdev: Raw remote control device
* @timer: Timer to echo samples to keep soft decoders happy.
* @last_status: Last raw status bits.
*/
struct img_ir_priv_raw {
struct rc_dev *rdev;
struct timer_list timer;
u32 last_status;
};
static inline bool img_ir_raw_enabled(struct img_ir_priv_raw *raw)
{
return raw->rdev;
};
void img_ir_isr_raw(struct img_ir_priv *priv, u32 irq_status);
void img_ir_setup_raw(struct img_ir_priv *priv);
int img_ir_probe_raw(struct img_ir_priv *priv);
void img_ir_remove_raw(struct img_ir_priv *priv);
#else
struct img_ir_priv_raw {
};
static inline bool img_ir_raw_enabled(struct img_ir_priv_raw *raw)
{
return false;
};
static inline void img_ir_isr_raw(struct img_ir_priv *priv, u32 irq_status)
{
}
static inline void img_ir_setup_raw(struct img_ir_priv *priv)
{
}
static inline int img_ir_probe_raw(struct img_ir_priv *priv)
{
return -ENODEV;
}
static inline void img_ir_remove_raw(struct img_ir_priv *priv)
{
}
#endif /* CONFIG_IR_IMG_RAW */
#endif /* _IMG_IR_RAW_H_ */
@@ -0,0 +1,84 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* ImgTec IR Decoder setup for Philips RC-5 protocol.
*
* Copyright 2012-2014 Imagination Technologies Ltd.
*/
#include "img-ir-hw.h"
/* Convert RC5 data to a scancode */
static int img_ir_rc5_scancode(int len, u64 raw, u64 enabled_protocols,
struct img_ir_scancode_req *request)
{
unsigned int addr, cmd, tgl, start;
/* Quirk in the decoder shifts everything by 2 to the left. */
raw >>= 2;
start = (raw >> 13) & 0x01;
tgl = (raw >> 11) & 0x01;
addr = (raw >> 6) & 0x1f;
cmd = raw & 0x3f;
/*
* 12th bit is used to extend the command in extended RC5 and has
* no effect on standard RC5.
*/
cmd += ((raw >> 12) & 0x01) ? 0 : 0x40;
if (!start)
return -EINVAL;
request->protocol = RC_PROTO_RC5;
request->scancode = addr << 8 | cmd;
request->toggle = tgl;
return IMG_IR_SCANCODE;
}
/* Convert RC5 scancode to RC5 data filter */
static int img_ir_rc5_filter(const struct rc_scancode_filter *in,
struct img_ir_filter *out, u64 protocols)
{
/* Not supported by the hw. */
return -EINVAL;
}
/*
* RC-5 decoder
* see http://www.sbprojects.com/knowledge/ir/rc5.php
*/
struct img_ir_decoder img_ir_rc5 = {
.type = RC_PROTO_BIT_RC5,
.control = {
.bitoriend2 = 1,
.code_type = IMG_IR_CODETYPE_BIPHASE,
.decodend2 = 1,
},
/* main timings */
.tolerance = 16,
.unit = 888888, /* 1/36k*32=888.888microseconds */
.timings = {
/* 10 symbol */
.s10 = {
.pulse = { 1 },
.space = { 1 },
},
/* 11 symbol */
.s11 = {
.pulse = { 1 },
.space = { 1 },
},
/* free time */
.ft = {
.minlen = 14,
.maxlen = 14,
.ft_min = 5,
},
},
/* scancode logic */
.scancode = img_ir_rc5_scancode,
.filter = img_ir_rc5_filter,
};
@@ -0,0 +1,113 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* ImgTec IR Decoder setup for Philips RC-6 protocol.
*
* Copyright 2012-2014 Imagination Technologies Ltd.
*/
#include "img-ir-hw.h"
/* Convert RC6 data to a scancode */
static int img_ir_rc6_scancode(int len, u64 raw, u64 enabled_protocols,
struct img_ir_scancode_req *request)
{
unsigned int addr, cmd, mode, trl1, trl2;
/*
* Due to a side effect of the decoder handling the double length
* Trailer bit, the header information is a bit scrambled, and the
* raw data is shifted incorrectly.
* This workaround effectively recovers the header bits.
*
* The Header field should look like this:
*
* StartBit ModeBit2 ModeBit1 ModeBit0 TrailerBit
*
* But what we get is:
*
* ModeBit2 ModeBit1 ModeBit0 TrailerBit1 TrailerBit2
*
* The start bit is not important to recover the scancode.
*/
raw >>= 27;
trl1 = (raw >> 17) & 0x01;
trl2 = (raw >> 16) & 0x01;
mode = (raw >> 18) & 0x07;
addr = (raw >> 8) & 0xff;
cmd = raw & 0xff;
/*
* Due to the above explained irregularity the trailer bits cannot
* have the same value.
*/
if (trl1 == trl2)
return -EINVAL;
/* Only mode 0 supported for now */
if (mode)
return -EINVAL;
request->protocol = RC_PROTO_RC6_0;
request->scancode = addr << 8 | cmd;
request->toggle = trl2;
return IMG_IR_SCANCODE;
}
/* Convert RC6 scancode to RC6 data filter */
static int img_ir_rc6_filter(const struct rc_scancode_filter *in,
struct img_ir_filter *out, u64 protocols)
{
/* Not supported by the hw. */
return -EINVAL;
}
/*
* RC-6 decoder
* see http://www.sbprojects.com/knowledge/ir/rc6.php
*/
struct img_ir_decoder img_ir_rc6 = {
.type = RC_PROTO_BIT_RC6_0,
.control = {
.bitorien = 1,
.code_type = IMG_IR_CODETYPE_BIPHASE,
.decoden = 1,
.decodinpol = 1,
},
/* main timings */
.tolerance = 20,
/*
* Due to a quirk in the img-ir decoder, default header values do
* not work, the values described below were extracted from
* successful RTL test cases.
*/
.timings = {
/* leader symbol */
.ldr = {
.pulse = { 650 },
.space = { 660 },
},
/* 0 symbol */
.s00 = {
.pulse = { 370 },
.space = { 370 },
},
/* 01 symbol */
.s01 = {
.pulse = { 370 },
.space = { 370 },
},
/* free time */
.ft = {
.minlen = 21,
.maxlen = 21,
.ft_min = 2666, /* 2.666 ms */
},
},
/* scancode logic */
.scancode = img_ir_rc6_scancode,
.filter = img_ir_rc6_filter,
};
@@ -0,0 +1,125 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* ImgTec IR Decoder setup for Sanyo protocol.
*
* Copyright 2012-2014 Imagination Technologies Ltd.
*
* From ir-sanyo-decoder.c:
*
* This protocol uses the NEC protocol timings. However, data is formatted as:
* 13 bits Custom Code
* 13 bits NOT(Custom Code)
* 8 bits Key data
* 8 bits NOT(Key data)
*
* According with LIRC, this protocol is used on Sanyo, Aiwa and Chinon
* Information for this protocol is available at the Sanyo LC7461 datasheet.
*/
#include "img-ir-hw.h"
/* Convert Sanyo data to a scancode */
static int img_ir_sanyo_scancode(int len, u64 raw, u64 enabled_protocols,
struct img_ir_scancode_req *request)
{
unsigned int addr, addr_inv, data, data_inv;
/* a repeat code has no data */
if (!len)
return IMG_IR_REPEATCODE;
if (len != 42)
return -EINVAL;
addr = (raw >> 0) & 0x1fff;
addr_inv = (raw >> 13) & 0x1fff;
data = (raw >> 26) & 0xff;
data_inv = (raw >> 34) & 0xff;
/* Validate data */
if ((data_inv ^ data) != 0xff)
return -EINVAL;
/* Validate address */
if ((addr_inv ^ addr) != 0x1fff)
return -EINVAL;
/* Normal Sanyo */
request->protocol = RC_PROTO_SANYO;
request->scancode = addr << 8 | data;
return IMG_IR_SCANCODE;
}
/* Convert Sanyo scancode to Sanyo data filter */
static int img_ir_sanyo_filter(const struct rc_scancode_filter *in,
struct img_ir_filter *out, u64 protocols)
{
unsigned int addr, addr_inv, data, data_inv;
unsigned int addr_m, data_m;
data = in->data & 0xff;
data_m = in->mask & 0xff;
data_inv = data ^ 0xff;
if (in->data & 0xff700000)
return -EINVAL;
addr = (in->data >> 8) & 0x1fff;
addr_m = (in->mask >> 8) & 0x1fff;
addr_inv = addr ^ 0x1fff;
out->data = (u64)data_inv << 34 |
(u64)data << 26 |
addr_inv << 13 |
addr;
out->mask = (u64)data_m << 34 |
(u64)data_m << 26 |
addr_m << 13 |
addr_m;
return 0;
}
/* Sanyo decoder */
struct img_ir_decoder img_ir_sanyo = {
.type = RC_PROTO_BIT_SANYO,
.control = {
.decoden = 1,
.code_type = IMG_IR_CODETYPE_PULSEDIST,
},
/* main timings */
.unit = 562500, /* 562.5 us */
.timings = {
/* leader symbol */
.ldr = {
.pulse = { 16 /* 9ms */ },
.space = { 8 /* 4.5ms */ },
},
/* 0 symbol */
.s00 = {
.pulse = { 1 /* 562.5 us */ },
.space = { 1 /* 562.5 us */ },
},
/* 1 symbol */
.s01 = {
.pulse = { 1 /* 562.5 us */ },
.space = { 3 /* 1687.5 us */ },
},
/* free time */
.ft = {
.minlen = 42,
.maxlen = 42,
.ft_min = 10, /* 5.625 ms */
},
},
/* repeat codes */
.repeat = 108, /* 108 ms */
.rtimings = {
/* leader symbol */
.ldr = {
.space = { 4 /* 2.25 ms */ },
},
/* free time */
.ft = {
.minlen = 0, /* repeat code has no data */
.maxlen = 0,
},
},
/* scancode logic */
.scancode = img_ir_sanyo_scancode,
.filter = img_ir_sanyo_filter,
};
@@ -0,0 +1,102 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* ImgTec IR Decoder setup for Sharp protocol.
*
* Copyright 2012-2014 Imagination Technologies Ltd.
*/
#include "img-ir-hw.h"
/* Convert Sharp data to a scancode */
static int img_ir_sharp_scancode(int len, u64 raw, u64 enabled_protocols,
struct img_ir_scancode_req *request)
{
unsigned int addr, cmd, exp, chk;
if (len != 15)
return -EINVAL;
addr = (raw >> 0) & 0x1f;
cmd = (raw >> 5) & 0xff;
exp = (raw >> 13) & 0x1;
chk = (raw >> 14) & 0x1;
/* validate data */
if (!exp)
return -EINVAL;
if (chk)
/* probably the second half of the message */
return -EINVAL;
request->protocol = RC_PROTO_SHARP;
request->scancode = addr << 8 | cmd;
return IMG_IR_SCANCODE;
}
/* Convert Sharp scancode to Sharp data filter */
static int img_ir_sharp_filter(const struct rc_scancode_filter *in,
struct img_ir_filter *out, u64 protocols)
{
unsigned int addr, cmd, exp = 0, chk = 0;
unsigned int addr_m, cmd_m, exp_m = 0, chk_m = 0;
addr = (in->data >> 8) & 0x1f;
addr_m = (in->mask >> 8) & 0x1f;
cmd = (in->data >> 0) & 0xff;
cmd_m = (in->mask >> 0) & 0xff;
if (cmd_m) {
/* if filtering commands, we can only match the first part */
exp = 1;
exp_m = 1;
chk = 0;
chk_m = 1;
}
out->data = addr |
cmd << 5 |
exp << 13 |
chk << 14;
out->mask = addr_m |
cmd_m << 5 |
exp_m << 13 |
chk_m << 14;
return 0;
}
/*
* Sharp decoder
* See also http://www.sbprojects.com/knowledge/ir/sharp.php
*/
struct img_ir_decoder img_ir_sharp = {
.type = RC_PROTO_BIT_SHARP,
.control = {
.decoden = 0,
.decodend2 = 1,
.code_type = IMG_IR_CODETYPE_PULSEDIST,
.d1validsel = 1,
},
/* main timings */
.tolerance = 20, /* 20% */
.timings = {
/* 0 symbol */
.s10 = {
.pulse = { 320 /* 320 us */ },
.space = { 680 /* 1 ms period */ },
},
/* 1 symbol */
.s11 = {
.pulse = { 320 /* 320 us */ },
.space = { 1680 /* 2 ms period */ },
},
/* free time */
.ft = {
.minlen = 15,
.maxlen = 15,
.ft_min = 5000, /* 5 ms */
},
},
/* scancode logic */
.scancode = img_ir_sharp_scancode,
.filter = img_ir_sharp_filter,
};
@@ -0,0 +1,161 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* ImgTec IR Decoder setup for Sony (SIRC) protocol.
*
* Copyright 2012-2014 Imagination Technologies Ltd.
*/
#include "img-ir-hw.h"
/* Convert Sony data to a scancode */
static int img_ir_sony_scancode(int len, u64 raw, u64 enabled_protocols,
struct img_ir_scancode_req *request)
{
unsigned int dev, subdev, func;
switch (len) {
case 12:
if (!(enabled_protocols & RC_PROTO_BIT_SONY12))
return -EINVAL;
func = raw & 0x7f; /* first 7 bits */
raw >>= 7;
dev = raw & 0x1f; /* next 5 bits */
subdev = 0;
request->protocol = RC_PROTO_SONY12;
break;
case 15:
if (!(enabled_protocols & RC_PROTO_BIT_SONY15))
return -EINVAL;
func = raw & 0x7f; /* first 7 bits */
raw >>= 7;
dev = raw & 0xff; /* next 8 bits */
subdev = 0;
request->protocol = RC_PROTO_SONY15;
break;
case 20:
if (!(enabled_protocols & RC_PROTO_BIT_SONY20))
return -EINVAL;
func = raw & 0x7f; /* first 7 bits */
raw >>= 7;
dev = raw & 0x1f; /* next 5 bits */
raw >>= 5;
subdev = raw & 0xff; /* next 8 bits */
request->protocol = RC_PROTO_SONY20;
break;
default:
return -EINVAL;
}
request->scancode = dev << 16 | subdev << 8 | func;
return IMG_IR_SCANCODE;
}
/* Convert NEC scancode to NEC data filter */
static int img_ir_sony_filter(const struct rc_scancode_filter *in,
struct img_ir_filter *out, u64 protocols)
{
unsigned int dev, subdev, func;
unsigned int dev_m, subdev_m, func_m;
unsigned int len = 0;
dev = (in->data >> 16) & 0xff;
dev_m = (in->mask >> 16) & 0xff;
subdev = (in->data >> 8) & 0xff;
subdev_m = (in->mask >> 8) & 0xff;
func = (in->data >> 0) & 0x7f;
func_m = (in->mask >> 0) & 0x7f;
protocols &= RC_PROTO_BIT_SONY12 | RC_PROTO_BIT_SONY15 |
RC_PROTO_BIT_SONY20;
/*
* If only one bit is set, we were requested to do an exact
* protocol. This should be the case for wakeup filters; for
* normal filters, guess the protocol from the scancode.
*/
if (!is_power_of_2(protocols)) {
if (subdev & subdev_m)
protocols = RC_PROTO_BIT_SONY20;
else if (dev & dev_m & 0xe0)
protocols = RC_PROTO_BIT_SONY15;
else
protocols = RC_PROTO_BIT_SONY12;
}
if (protocols == RC_PROTO_BIT_SONY20) {
/* can't encode subdev and higher device bits */
if (dev & dev_m & 0xe0)
return -EINVAL;
len = 20;
dev_m &= 0x1f;
} else if (protocols == RC_PROTO_BIT_SONY15) {
len = 15;
subdev_m = 0;
} else {
/*
* The hardware mask cannot distinguish high device bits and low
* extended bits, so logically AND those bits of the masks
* together.
*/
subdev_m &= (dev_m >> 5) | 0xf8;
dev_m &= 0x1f;
}
/* ensure there aren't any bits straying between fields */
dev &= dev_m;
subdev &= subdev_m;
/* write the hardware filter */
out->data = func |
dev << 7 |
subdev << 15;
out->mask = func_m |
dev_m << 7 |
subdev_m << 15;
if (len) {
out->minlen = len;
out->maxlen = len;
}
return 0;
}
/*
* Sony SIRC decoder
* See also http://www.sbprojects.com/knowledge/ir/sirc.php
* http://picprojects.org.uk/projects/sirc/sonysirc.pdf
*/
struct img_ir_decoder img_ir_sony = {
.type = RC_PROTO_BIT_SONY12 | RC_PROTO_BIT_SONY15 | RC_PROTO_BIT_SONY20,
.control = {
.decoden = 1,
.code_type = IMG_IR_CODETYPE_PULSELEN,
},
/* main timings */
.unit = 600000, /* 600 us */
.timings = {
/* leader symbol */
.ldr = {
.pulse = { 4 /* 2.4 ms */ },
.space = { 1 /* 600 us */ },
},
/* 0 symbol */
.s00 = {
.pulse = { 1 /* 600 us */ },
.space = { 1 /* 600 us */ },
},
/* 1 symbol */
.s01 = {
.pulse = { 2 /* 1.2 ms */ },
.space = { 1 /* 600 us */ },
},
/* free time */
.ft = {
.minlen = 12,
.maxlen = 20,
.ft_min = 10, /* 6 ms */
},
},
/* scancode logic */
.scancode = img_ir_sony_scancode,
.filter = img_ir_sony_filter,
};
@@ -0,0 +1,169 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* ImgTec IR Decoder found in PowerDown Controller.
*
* Copyright 2010-2014 Imagination Technologies Ltd.
*/
#ifndef _IMG_IR_H_
#define _IMG_IR_H_
#include <linux/io.h>
#include <linux/spinlock.h>
#include "img-ir-raw.h"
#include "img-ir-hw.h"
/* registers */
/* relative to the start of the IR block of registers */
#define IMG_IR_CONTROL 0x00
#define IMG_IR_STATUS 0x04
#define IMG_IR_DATA_LW 0x08
#define IMG_IR_DATA_UP 0x0c
#define IMG_IR_LEAD_SYMB_TIMING 0x10
#define IMG_IR_S00_SYMB_TIMING 0x14
#define IMG_IR_S01_SYMB_TIMING 0x18
#define IMG_IR_S10_SYMB_TIMING 0x1c
#define IMG_IR_S11_SYMB_TIMING 0x20
#define IMG_IR_FREE_SYMB_TIMING 0x24
#define IMG_IR_POW_MOD_PARAMS 0x28
#define IMG_IR_POW_MOD_ENABLE 0x2c
#define IMG_IR_IRQ_MSG_DATA_LW 0x30
#define IMG_IR_IRQ_MSG_DATA_UP 0x34
#define IMG_IR_IRQ_MSG_MASK_LW 0x38
#define IMG_IR_IRQ_MSG_MASK_UP 0x3c
#define IMG_IR_IRQ_ENABLE 0x40
#define IMG_IR_IRQ_STATUS 0x44
#define IMG_IR_IRQ_CLEAR 0x48
#define IMG_IR_IRCORE_ID 0xf0
#define IMG_IR_CORE_REV 0xf4
#define IMG_IR_CORE_DES1 0xf8
#define IMG_IR_CORE_DES2 0xfc
/* field masks */
/* IMG_IR_CONTROL */
#define IMG_IR_DECODEN 0x40000000
#define IMG_IR_CODETYPE 0x30000000
#define IMG_IR_CODETYPE_SHIFT 28
#define IMG_IR_HDRTOG 0x08000000
#define IMG_IR_LDRDEC 0x04000000
#define IMG_IR_DECODINPOL 0x02000000 /* active high */
#define IMG_IR_BITORIEN 0x01000000 /* MSB first */
#define IMG_IR_D1VALIDSEL 0x00008000
#define IMG_IR_BITINV 0x00000040 /* don't invert */
#define IMG_IR_DECODEND2 0x00000010
#define IMG_IR_BITORIEND2 0x00000002 /* MSB first */
#define IMG_IR_BITINVD2 0x00000001 /* don't invert */
/* IMG_IR_STATUS */
#define IMG_IR_RXDVALD2 0x00001000
#define IMG_IR_IRRXD 0x00000400
#define IMG_IR_TOGSTATE 0x00000200
#define IMG_IR_RXDVAL 0x00000040
#define IMG_IR_RXDLEN 0x0000003f
#define IMG_IR_RXDLEN_SHIFT 0
/* IMG_IR_LEAD_SYMB_TIMING, IMG_IR_Sxx_SYMB_TIMING */
#define IMG_IR_PD_MAX 0xff000000
#define IMG_IR_PD_MAX_SHIFT 24
#define IMG_IR_PD_MIN 0x00ff0000
#define IMG_IR_PD_MIN_SHIFT 16
#define IMG_IR_W_MAX 0x0000ff00
#define IMG_IR_W_MAX_SHIFT 8
#define IMG_IR_W_MIN 0x000000ff
#define IMG_IR_W_MIN_SHIFT 0
/* IMG_IR_FREE_SYMB_TIMING */
#define IMG_IR_MAXLEN 0x0007e000
#define IMG_IR_MAXLEN_SHIFT 13
#define IMG_IR_MINLEN 0x00001f00
#define IMG_IR_MINLEN_SHIFT 8
#define IMG_IR_FT_MIN 0x000000ff
#define IMG_IR_FT_MIN_SHIFT 0
/* IMG_IR_POW_MOD_PARAMS */
#define IMG_IR_PERIOD_LEN 0x3f000000
#define IMG_IR_PERIOD_LEN_SHIFT 24
#define IMG_IR_PERIOD_DUTY 0x003f0000
#define IMG_IR_PERIOD_DUTY_SHIFT 16
#define IMG_IR_STABLE_STOP 0x00003f00
#define IMG_IR_STABLE_STOP_SHIFT 8
#define IMG_IR_STABLE_START 0x0000003f
#define IMG_IR_STABLE_START_SHIFT 0
/* IMG_IR_POW_MOD_ENABLE */
#define IMG_IR_POWER_OUT_EN 0x00000002
#define IMG_IR_POWER_MOD_EN 0x00000001
/* IMG_IR_IRQ_ENABLE, IMG_IR_IRQ_STATUS, IMG_IR_IRQ_CLEAR */
#define IMG_IR_IRQ_DEC2_ERR 0x00000080
#define IMG_IR_IRQ_DEC_ERR 0x00000040
#define IMG_IR_IRQ_ACT_LEVEL 0x00000020
#define IMG_IR_IRQ_FALL_EDGE 0x00000010
#define IMG_IR_IRQ_RISE_EDGE 0x00000008
#define IMG_IR_IRQ_DATA_MATCH 0x00000004
#define IMG_IR_IRQ_DATA2_VALID 0x00000002
#define IMG_IR_IRQ_DATA_VALID 0x00000001
#define IMG_IR_IRQ_ALL 0x000000ff
#define IMG_IR_IRQ_EDGE (IMG_IR_IRQ_FALL_EDGE | IMG_IR_IRQ_RISE_EDGE)
/* IMG_IR_CORE_ID */
#define IMG_IR_CORE_ID 0x00ff0000
#define IMG_IR_CORE_ID_SHIFT 16
#define IMG_IR_CORE_CONFIG 0x0000ffff
#define IMG_IR_CORE_CONFIG_SHIFT 0
/* IMG_IR_CORE_REV */
#define IMG_IR_DESIGNER 0xff000000
#define IMG_IR_DESIGNER_SHIFT 24
#define IMG_IR_MAJOR_REV 0x00ff0000
#define IMG_IR_MAJOR_REV_SHIFT 16
#define IMG_IR_MINOR_REV 0x0000ff00
#define IMG_IR_MINOR_REV_SHIFT 8
#define IMG_IR_MAINT_REV 0x000000ff
#define IMG_IR_MAINT_REV_SHIFT 0
struct device;
struct clk;
/**
* struct img_ir_priv - Private driver data.
* @dev: Platform device.
* @irq: IRQ number.
* @clk: Input clock.
* @sys_clk: System clock.
* @reg_base: Iomem base address of IR register block.
* @lock: Protects IR registers and variables in this struct.
* @raw: Driver data for raw decoder.
* @hw: Driver data for hardware decoder.
*/
struct img_ir_priv {
struct device *dev;
int irq;
struct clk *clk;
struct clk *sys_clk;
void __iomem *reg_base;
spinlock_t lock;
struct img_ir_priv_raw raw;
struct img_ir_priv_hw hw;
};
/* Hardware access */
static inline void img_ir_write(struct img_ir_priv *priv,
unsigned int reg_offs, unsigned int data)
{
iowrite32(data, priv->reg_base + reg_offs);
}
static inline unsigned int img_ir_read(struct img_ir_priv *priv,
unsigned int reg_offs)
{
return ioread32(priv->reg_base + reg_offs);
}
#endif /* _IMG_IR_H_ */