diff options
-rw-r--r-- | drivers/media/rc/img-ir/img-ir-core.c | 176 | ||||
-rw-r--r-- | drivers/media/rc/img-ir/img-ir.h | 166 |
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 | |||
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"); | ||
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 | |||
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_ */ | ||