Skip to content

Commit 160a8f8

Browse files
James Hoganmchehab
James Hogan
authored andcommitted
[media] rc: img-ir: add base driver
Add base driver for the ImgTec Infrared decoder block. The driver is split into separate components for raw (software) decode and hardware decoder which are in following commits. Signed-off-by: James Hogan <[email protected]> Signed-off-by: Mauro Carvalho Chehab <[email protected]>
1 parent f99baba commit 160a8f8

File tree

2 files changed

+342
-0
lines changed

2 files changed

+342
-0
lines changed

drivers/media/rc/img-ir/img-ir-core.c

Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
/*
2+
* ImgTec IR Decoder found in PowerDown Controller.
3+
*
4+
* Copyright 2010-2014 Imagination Technologies Ltd.
5+
*
6+
* This contains core img-ir code for setting up the driver. The two interfaces
7+
* (raw and hardware decode) are handled separately.
8+
*/
9+
10+
#include <linux/clk.h>
11+
#include <linux/init.h>
12+
#include <linux/interrupt.h>
13+
#include <linux/io.h>
14+
#include <linux/module.h>
15+
#include <linux/platform_device.h>
16+
#include <linux/slab.h>
17+
#include <linux/spinlock.h>
18+
#include "img-ir.h"
19+
20+
static irqreturn_t img_ir_isr(int irq, void *dev_id)
21+
{
22+
struct img_ir_priv *priv = dev_id;
23+
u32 irq_status;
24+
25+
spin_lock(&priv->lock);
26+
/* we have to clear irqs before reading */
27+
irq_status = img_ir_read(priv, IMG_IR_IRQ_STATUS);
28+
img_ir_write(priv, IMG_IR_IRQ_CLEAR, irq_status);
29+
30+
/* don't handle valid data irqs if we're only interested in matches */
31+
irq_status &= img_ir_read(priv, IMG_IR_IRQ_ENABLE);
32+
33+
/* hand off edge interrupts to raw decode handler */
34+
if (irq_status & IMG_IR_IRQ_EDGE && img_ir_raw_enabled(&priv->raw))
35+
img_ir_isr_raw(priv, irq_status);
36+
37+
/* hand off hardware match interrupts to hardware decode handler */
38+
if (irq_status & (IMG_IR_IRQ_DATA_MATCH |
39+
IMG_IR_IRQ_DATA_VALID |
40+
IMG_IR_IRQ_DATA2_VALID) &&
41+
img_ir_hw_enabled(&priv->hw))
42+
img_ir_isr_hw(priv, irq_status);
43+
44+
spin_unlock(&priv->lock);
45+
return IRQ_HANDLED;
46+
}
47+
48+
static void img_ir_setup(struct img_ir_priv *priv)
49+
{
50+
/* start off with interrupts disabled */
51+
img_ir_write(priv, IMG_IR_IRQ_ENABLE, 0);
52+
53+
img_ir_setup_raw(priv);
54+
img_ir_setup_hw(priv);
55+
56+
if (!IS_ERR(priv->clk))
57+
clk_prepare_enable(priv->clk);
58+
}
59+
60+
static void img_ir_ident(struct img_ir_priv *priv)
61+
{
62+
u32 core_rev = img_ir_read(priv, IMG_IR_CORE_REV);
63+
64+
dev_info(priv->dev,
65+
"IMG IR Decoder (%d.%d.%d.%d) probed successfully\n",
66+
(core_rev & IMG_IR_DESIGNER) >> IMG_IR_DESIGNER_SHIFT,
67+
(core_rev & IMG_IR_MAJOR_REV) >> IMG_IR_MAJOR_REV_SHIFT,
68+
(core_rev & IMG_IR_MINOR_REV) >> IMG_IR_MINOR_REV_SHIFT,
69+
(core_rev & IMG_IR_MAINT_REV) >> IMG_IR_MAINT_REV_SHIFT);
70+
dev_info(priv->dev, "Modes:%s%s\n",
71+
img_ir_hw_enabled(&priv->hw) ? " hardware" : "",
72+
img_ir_raw_enabled(&priv->raw) ? " raw" : "");
73+
}
74+
75+
static int img_ir_probe(struct platform_device *pdev)
76+
{
77+
struct img_ir_priv *priv;
78+
struct resource *res_regs;
79+
int irq, error, error2;
80+
81+
/* Get resources from platform device */
82+
irq = platform_get_irq(pdev, 0);
83+
if (irq < 0) {
84+
dev_err(&pdev->dev, "cannot find IRQ resource\n");
85+
return irq;
86+
}
87+
88+
/* Private driver data */
89+
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
90+
if (!priv) {
91+
dev_err(&pdev->dev, "cannot allocate device data\n");
92+
return -ENOMEM;
93+
}
94+
platform_set_drvdata(pdev, priv);
95+
priv->dev = &pdev->dev;
96+
spin_lock_init(&priv->lock);
97+
98+
/* Ioremap the registers */
99+
res_regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
100+
priv->reg_base = devm_ioremap_resource(&pdev->dev, res_regs);
101+
if (IS_ERR(priv->reg_base))
102+
return PTR_ERR(priv->reg_base);
103+
104+
/* Get core clock */
105+
priv->clk = devm_clk_get(&pdev->dev, "core");
106+
if (IS_ERR(priv->clk))
107+
dev_warn(&pdev->dev, "cannot get core clock resource\n");
108+
/*
109+
* The driver doesn't need to know about the system ("sys") or power
110+
* modulation ("mod") clocks yet
111+
*/
112+
113+
/* Set up raw & hw decoder */
114+
error = img_ir_probe_raw(priv);
115+
error2 = img_ir_probe_hw(priv);
116+
if (error && error2)
117+
return (error == -ENODEV) ? error2 : error;
118+
119+
/* Get the IRQ */
120+
priv->irq = irq;
121+
error = request_irq(priv->irq, img_ir_isr, 0, "img-ir", priv);
122+
if (error) {
123+
dev_err(&pdev->dev, "cannot register IRQ %u\n",
124+
priv->irq);
125+
error = -EIO;
126+
goto err_irq;
127+
}
128+
129+
img_ir_ident(priv);
130+
img_ir_setup(priv);
131+
132+
return 0;
133+
134+
err_irq:
135+
img_ir_remove_hw(priv);
136+
img_ir_remove_raw(priv);
137+
return error;
138+
}
139+
140+
static int img_ir_remove(struct platform_device *pdev)
141+
{
142+
struct img_ir_priv *priv = platform_get_drvdata(pdev);
143+
144+
free_irq(priv->irq, img_ir_isr);
145+
img_ir_remove_hw(priv);
146+
img_ir_remove_raw(priv);
147+
148+
if (!IS_ERR(priv->clk))
149+
clk_disable_unprepare(priv->clk);
150+
return 0;
151+
}
152+
153+
static SIMPLE_DEV_PM_OPS(img_ir_pmops, img_ir_suspend, img_ir_resume);
154+
155+
static const struct of_device_id img_ir_match[] = {
156+
{ .compatible = "img,ir-rev1" },
157+
{}
158+
};
159+
MODULE_DEVICE_TABLE(of, img_ir_match);
160+
161+
static struct platform_driver img_ir_driver = {
162+
.driver = {
163+
.name = "img-ir",
164+
.owner = THIS_MODULE,
165+
.of_match_table = img_ir_match,
166+
.pm = &img_ir_pmops,
167+
},
168+
.probe = img_ir_probe,
169+
.remove = img_ir_remove,
170+
};
171+
172+
module_platform_driver(img_ir_driver);
173+
174+
MODULE_AUTHOR("Imagination Technologies Ltd.");
175+
MODULE_DESCRIPTION("ImgTec IR");
176+
MODULE_LICENSE("GPL");

drivers/media/rc/img-ir/img-ir.h

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
/*
2+
* ImgTec IR Decoder found in PowerDown Controller.
3+
*
4+
* Copyright 2010-2014 Imagination Technologies Ltd.
5+
*/
6+
7+
#ifndef _IMG_IR_H_
8+
#define _IMG_IR_H_
9+
10+
#include <linux/io.h>
11+
#include <linux/spinlock.h>
12+
13+
#include "img-ir-raw.h"
14+
#include "img-ir-hw.h"
15+
16+
/* registers */
17+
18+
/* relative to the start of the IR block of registers */
19+
#define IMG_IR_CONTROL 0x00
20+
#define IMG_IR_STATUS 0x04
21+
#define IMG_IR_DATA_LW 0x08
22+
#define IMG_IR_DATA_UP 0x0c
23+
#define IMG_IR_LEAD_SYMB_TIMING 0x10
24+
#define IMG_IR_S00_SYMB_TIMING 0x14
25+
#define IMG_IR_S01_SYMB_TIMING 0x18
26+
#define IMG_IR_S10_SYMB_TIMING 0x1c
27+
#define IMG_IR_S11_SYMB_TIMING 0x20
28+
#define IMG_IR_FREE_SYMB_TIMING 0x24
29+
#define IMG_IR_POW_MOD_PARAMS 0x28
30+
#define IMG_IR_POW_MOD_ENABLE 0x2c
31+
#define IMG_IR_IRQ_MSG_DATA_LW 0x30
32+
#define IMG_IR_IRQ_MSG_DATA_UP 0x34
33+
#define IMG_IR_IRQ_MSG_MASK_LW 0x38
34+
#define IMG_IR_IRQ_MSG_MASK_UP 0x3c
35+
#define IMG_IR_IRQ_ENABLE 0x40
36+
#define IMG_IR_IRQ_STATUS 0x44
37+
#define IMG_IR_IRQ_CLEAR 0x48
38+
#define IMG_IR_IRCORE_ID 0xf0
39+
#define IMG_IR_CORE_REV 0xf4
40+
#define IMG_IR_CORE_DES1 0xf8
41+
#define IMG_IR_CORE_DES2 0xfc
42+
43+
44+
/* field masks */
45+
46+
/* IMG_IR_CONTROL */
47+
#define IMG_IR_DECODEN 0x40000000
48+
#define IMG_IR_CODETYPE 0x30000000
49+
#define IMG_IR_CODETYPE_SHIFT 28
50+
#define IMG_IR_HDRTOG 0x08000000
51+
#define IMG_IR_LDRDEC 0x04000000
52+
#define IMG_IR_DECODINPOL 0x02000000 /* active high */
53+
#define IMG_IR_BITORIEN 0x01000000 /* MSB first */
54+
#define IMG_IR_D1VALIDSEL 0x00008000
55+
#define IMG_IR_BITINV 0x00000040 /* don't invert */
56+
#define IMG_IR_DECODEND2 0x00000010
57+
#define IMG_IR_BITORIEND2 0x00000002 /* MSB first */
58+
#define IMG_IR_BITINVD2 0x00000001 /* don't invert */
59+
60+
/* IMG_IR_STATUS */
61+
#define IMG_IR_RXDVALD2 0x00001000
62+
#define IMG_IR_IRRXD 0x00000400
63+
#define IMG_IR_TOGSTATE 0x00000200
64+
#define IMG_IR_RXDVAL 0x00000040
65+
#define IMG_IR_RXDLEN 0x0000003f
66+
#define IMG_IR_RXDLEN_SHIFT 0
67+
68+
/* IMG_IR_LEAD_SYMB_TIMING, IMG_IR_Sxx_SYMB_TIMING */
69+
#define IMG_IR_PD_MAX 0xff000000
70+
#define IMG_IR_PD_MAX_SHIFT 24
71+
#define IMG_IR_PD_MIN 0x00ff0000
72+
#define IMG_IR_PD_MIN_SHIFT 16
73+
#define IMG_IR_W_MAX 0x0000ff00
74+
#define IMG_IR_W_MAX_SHIFT 8
75+
#define IMG_IR_W_MIN 0x000000ff
76+
#define IMG_IR_W_MIN_SHIFT 0
77+
78+
/* IMG_IR_FREE_SYMB_TIMING */
79+
#define IMG_IR_MAXLEN 0x0007e000
80+
#define IMG_IR_MAXLEN_SHIFT 13
81+
#define IMG_IR_MINLEN 0x00001f00
82+
#define IMG_IR_MINLEN_SHIFT 8
83+
#define IMG_IR_FT_MIN 0x000000ff
84+
#define IMG_IR_FT_MIN_SHIFT 0
85+
86+
/* IMG_IR_POW_MOD_PARAMS */
87+
#define IMG_IR_PERIOD_LEN 0x3f000000
88+
#define IMG_IR_PERIOD_LEN_SHIFT 24
89+
#define IMG_IR_PERIOD_DUTY 0x003f0000
90+
#define IMG_IR_PERIOD_DUTY_SHIFT 16
91+
#define IMG_IR_STABLE_STOP 0x00003f00
92+
#define IMG_IR_STABLE_STOP_SHIFT 8
93+
#define IMG_IR_STABLE_START 0x0000003f
94+
#define IMG_IR_STABLE_START_SHIFT 0
95+
96+
/* IMG_IR_POW_MOD_ENABLE */
97+
#define IMG_IR_POWER_OUT_EN 0x00000002
98+
#define IMG_IR_POWER_MOD_EN 0x00000001
99+
100+
/* IMG_IR_IRQ_ENABLE, IMG_IR_IRQ_STATUS, IMG_IR_IRQ_CLEAR */
101+
#define IMG_IR_IRQ_DEC2_ERR 0x00000080
102+
#define IMG_IR_IRQ_DEC_ERR 0x00000040
103+
#define IMG_IR_IRQ_ACT_LEVEL 0x00000020
104+
#define IMG_IR_IRQ_FALL_EDGE 0x00000010
105+
#define IMG_IR_IRQ_RISE_EDGE 0x00000008
106+
#define IMG_IR_IRQ_DATA_MATCH 0x00000004
107+
#define IMG_IR_IRQ_DATA2_VALID 0x00000002
108+
#define IMG_IR_IRQ_DATA_VALID 0x00000001
109+
#define IMG_IR_IRQ_ALL 0x000000ff
110+
#define IMG_IR_IRQ_EDGE (IMG_IR_IRQ_FALL_EDGE | IMG_IR_IRQ_RISE_EDGE)
111+
112+
/* IMG_IR_CORE_ID */
113+
#define IMG_IR_CORE_ID 0x00ff0000
114+
#define IMG_IR_CORE_ID_SHIFT 16
115+
#define IMG_IR_CORE_CONFIG 0x0000ffff
116+
#define IMG_IR_CORE_CONFIG_SHIFT 0
117+
118+
/* IMG_IR_CORE_REV */
119+
#define IMG_IR_DESIGNER 0xff000000
120+
#define IMG_IR_DESIGNER_SHIFT 24
121+
#define IMG_IR_MAJOR_REV 0x00ff0000
122+
#define IMG_IR_MAJOR_REV_SHIFT 16
123+
#define IMG_IR_MINOR_REV 0x0000ff00
124+
#define IMG_IR_MINOR_REV_SHIFT 8
125+
#define IMG_IR_MAINT_REV 0x000000ff
126+
#define IMG_IR_MAINT_REV_SHIFT 0
127+
128+
struct device;
129+
struct clk;
130+
131+
/**
132+
* struct img_ir_priv - Private driver data.
133+
* @dev: Platform device.
134+
* @irq: IRQ number.
135+
* @clk: Input clock.
136+
* @reg_base: Iomem base address of IR register block.
137+
* @lock: Protects IR registers and variables in this struct.
138+
* @raw: Driver data for raw decoder.
139+
* @hw: Driver data for hardware decoder.
140+
*/
141+
struct img_ir_priv {
142+
struct device *dev;
143+
int irq;
144+
struct clk *clk;
145+
void __iomem *reg_base;
146+
spinlock_t lock;
147+
148+
struct img_ir_priv_raw raw;
149+
struct img_ir_priv_hw hw;
150+
};
151+
152+
/* Hardware access */
153+
154+
static inline void img_ir_write(struct img_ir_priv *priv,
155+
unsigned int reg_offs, unsigned int data)
156+
{
157+
iowrite32(data, priv->reg_base + reg_offs);
158+
}
159+
160+
static inline unsigned int img_ir_read(struct img_ir_priv *priv,
161+
unsigned int reg_offs)
162+
{
163+
return ioread32(priv->reg_base + reg_offs);
164+
}
165+
166+
#endif /* _IMG_IR_H_ */

0 commit comments

Comments
 (0)