aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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_ */