aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/rc
diff options
context:
space:
mode:
authorJames Hogan <james.hogan@imgtec.com>2014-02-28 18:28:52 -0500
committerMauro Carvalho Chehab <m.chehab@samsung.com>2014-03-11 14:10:56 -0400
commit160a8f8aec4da4b68842784be3e7296e8c9860dc (patch)
treea257dcb5f3c0bbdc6b48b2bac10bd0cfefc4eb3c /drivers/media/rc
parentf99bababe0ac3f4d6f8b0368a22600f0ba24042b (diff)
[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 <james.hogan@imgtec.com> Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
Diffstat (limited to 'drivers/media/rc')
-rw-r--r--drivers/media/rc/img-ir/img-ir-core.c176
-rw-r--r--drivers/media/rc/img-ir/img-ir.h166
2 files changed, 342 insertions, 0 deletions
diff --git a/drivers/media/rc/img-ir/img-ir-core.c b/drivers/media/rc/img-ir/img-ir-core.c
new file mode 100644
index 000000000000..6b7834834fb8
--- /dev/null
+++ b/drivers/media/rc/img-ir/img-ir-core.c
@@ -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
20static 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
48static 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
60static 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
75static 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
134err_irq:
135 img_ir_remove_hw(priv);
136 img_ir_remove_raw(priv);
137 return error;
138}
139
140static 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
153static SIMPLE_DEV_PM_OPS(img_ir_pmops, img_ir_suspend, img_ir_resume);
154
155static const struct of_device_id img_ir_match[] = {
156 { .compatible = "img,ir-rev1" },
157 {}
158};
159MODULE_DEVICE_TABLE(of, img_ir_match);
160
161static 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
172module_platform_driver(img_ir_driver);
173
174MODULE_AUTHOR("Imagination Technologies Ltd.");
175MODULE_DESCRIPTION("ImgTec IR");
176MODULE_LICENSE("GPL");
diff --git a/drivers/media/rc/img-ir/img-ir.h b/drivers/media/rc/img-ir/img-ir.h
new file mode 100644
index 000000000000..afb189394af9
--- /dev/null
+++ b/drivers/media/rc/img-ir/img-ir.h
@@ -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
128struct device;
129struct 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 */
141struct 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
154static 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
160static 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_ */