1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright (C) 2015 Mans Rullgard <mans@mansr.com>
6 #include <linux/input.h>
7 #include <linux/module.h>
8 #include <linux/platform_device.h>
9 #include <linux/interrupt.h>
11 #include <linux/clk.h>
13 #include <media/rc-core.h>
15 #define DRIVER_NAME "tango-ir"
17 #define IR_NEC_CTRL 0x00
18 #define IR_NEC_DATA 0x04
20 #define IR_RC5_CLK_DIV 0x0c
21 #define IR_RC5_DATA 0x10
24 #define NEC_TIME_BASE 560
25 #define RC5_TIME_BASE 1778
28 #define RC6_CLKDIV 0x04
29 #define RC6_DATA0 0x08
30 #define RC6_DATA1 0x0c
31 #define RC6_DATA2 0x10
32 #define RC6_DATA3 0x14
33 #define RC6_DATA4 0x18
35 #define RC6_CARRIER 36000
36 #define RC6_TIME_BASE 16
38 #define NEC_CAP(n) ((n) << 24)
39 #define GPIO_SEL(n) ((n) << 16)
40 #define DISABLE_NEC (BIT(4) | BIT(8))
41 #define ENABLE_RC5 (BIT(0) | BIT(9))
42 #define ENABLE_RC6 (BIT(0) | BIT(7))
43 #define ACK_IR_INT (BIT(0) | BIT(1))
44 #define ACK_RC6_INT (BIT(31))
46 #define NEC_ANY (RC_PROTO_BIT_NEC | RC_PROTO_BIT_NECX | RC_PROTO_BIT_NEC32)
49 void __iomem
*rc5_base
;
50 void __iomem
*rc6_base
;
55 static void tango_ir_handle_nec(struct tango_ir
*ir
)
60 v
= readl_relaxed(ir
->rc5_base
+ IR_NEC_DATA
);
66 code
= ir_nec_bytes_to_scancode(v
, v
>> 8, v
>> 16, v
>> 24, &proto
);
67 rc_keydown(ir
->rc
, proto
, code
, 0);
70 static void tango_ir_handle_rc5(struct tango_ir
*ir
)
72 u32 data
, field
, toggle
, addr
, cmd
, code
;
74 data
= readl_relaxed(ir
->rc5_base
+ IR_RC5_DATA
);
78 field
= data
>> 12 & 1;
79 toggle
= data
>> 11 & 1;
80 addr
= data
>> 6 & 0x1f;
81 cmd
= (data
& 0x3f) | (field
^ 1) << 6;
83 code
= RC_SCANCODE_RC5(addr
, cmd
);
84 rc_keydown(ir
->rc
, RC_PROTO_RC5
, code
, toggle
);
87 static void tango_ir_handle_rc6(struct tango_ir
*ir
)
89 u32 data0
, data1
, toggle
, mode
, addr
, cmd
, code
;
91 data0
= readl_relaxed(ir
->rc6_base
+ RC6_DATA0
);
92 data1
= readl_relaxed(ir
->rc6_base
+ RC6_DATA1
);
94 mode
= data0
>> 1 & 7;
102 code
= RC_SCANCODE_RC6_0(addr
, cmd
);
103 rc_keydown(ir
->rc
, RC_PROTO_RC6_0
, code
, toggle
);
106 static irqreturn_t
tango_ir_irq(int irq
, void *dev_id
)
108 struct tango_ir
*ir
= dev_id
;
109 unsigned int rc5_stat
;
110 unsigned int rc6_stat
;
112 rc5_stat
= readl_relaxed(ir
->rc5_base
+ IR_INT
);
113 writel_relaxed(rc5_stat
, ir
->rc5_base
+ IR_INT
);
115 rc6_stat
= readl_relaxed(ir
->rc6_base
+ RC6_CTRL
);
116 writel_relaxed(rc6_stat
, ir
->rc6_base
+ RC6_CTRL
);
118 if (!(rc5_stat
& 3) && !(rc6_stat
& BIT(31)))
121 if (rc5_stat
& BIT(0))
122 tango_ir_handle_rc5(ir
);
124 if (rc5_stat
& BIT(1))
125 tango_ir_handle_nec(ir
);
127 if (rc6_stat
& BIT(31))
128 tango_ir_handle_rc6(ir
);
133 static int tango_change_protocol(struct rc_dev
*dev
, u64
*rc_type
)
135 struct tango_ir
*ir
= dev
->priv
;
136 u32 rc5_ctrl
= DISABLE_NEC
;
139 if (*rc_type
& NEC_ANY
)
142 if (*rc_type
& RC_PROTO_BIT_RC5
)
143 rc5_ctrl
|= ENABLE_RC5
;
145 if (*rc_type
& RC_PROTO_BIT_RC6_0
)
146 rc6_ctrl
= ENABLE_RC6
;
148 writel_relaxed(rc5_ctrl
, ir
->rc5_base
+ IR_CTRL
);
149 writel_relaxed(rc6_ctrl
, ir
->rc6_base
+ RC6_CTRL
);
154 static int tango_ir_probe(struct platform_device
*pdev
)
156 const char *map_name
= RC_MAP_TANGO
;
157 struct device
*dev
= &pdev
->dev
;
160 struct resource
*rc5_res
;
161 struct resource
*rc6_res
;
166 rc5_res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
170 rc6_res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 1);
174 irq
= platform_get_irq(pdev
, 0);
178 ir
= devm_kzalloc(dev
, sizeof(*ir
), GFP_KERNEL
);
182 ir
->rc5_base
= devm_ioremap_resource(dev
, rc5_res
);
183 if (IS_ERR(ir
->rc5_base
))
184 return PTR_ERR(ir
->rc5_base
);
186 ir
->rc6_base
= devm_ioremap_resource(dev
, rc6_res
);
187 if (IS_ERR(ir
->rc6_base
))
188 return PTR_ERR(ir
->rc6_base
);
190 ir
->clk
= devm_clk_get(dev
, NULL
);
192 return PTR_ERR(ir
->clk
);
194 rc
= devm_rc_allocate_device(dev
, RC_DRIVER_SCANCODE
);
198 of_property_read_string(dev
->of_node
, "linux,rc-map-name", &map_name
);
200 rc
->device_name
= DRIVER_NAME
;
201 rc
->driver_name
= DRIVER_NAME
;
202 rc
->input_phys
= DRIVER_NAME
"/input0";
203 rc
->map_name
= map_name
;
204 rc
->allowed_protocols
= NEC_ANY
| RC_PROTO_BIT_RC5
| RC_PROTO_BIT_RC6_0
;
205 rc
->change_protocol
= tango_change_protocol
;
209 err
= clk_prepare_enable(ir
->clk
);
213 clkrate
= clk_get_rate(ir
->clk
);
215 clkdiv
= clkrate
* NEC_TIME_BASE
;
216 do_div(clkdiv
, 1000000);
218 val
= NEC_CAP(31) | GPIO_SEL(12) | clkdiv
;
219 writel_relaxed(val
, ir
->rc5_base
+ IR_NEC_CTRL
);
221 clkdiv
= clkrate
* RC5_TIME_BASE
;
222 do_div(clkdiv
, 1000000);
224 writel_relaxed(DISABLE_NEC
, ir
->rc5_base
+ IR_CTRL
);
225 writel_relaxed(clkdiv
, ir
->rc5_base
+ IR_RC5_CLK_DIV
);
226 writel_relaxed(ACK_IR_INT
, ir
->rc5_base
+ IR_INT
);
228 clkdiv
= clkrate
* RC6_TIME_BASE
;
229 do_div(clkdiv
, RC6_CARRIER
);
231 writel_relaxed(ACK_RC6_INT
, ir
->rc6_base
+ RC6_CTRL
);
232 writel_relaxed((clkdiv
>> 2) << 18 | clkdiv
, ir
->rc6_base
+ RC6_CLKDIV
);
234 err
= devm_request_irq(dev
, irq
, tango_ir_irq
, IRQF_SHARED
,
239 err
= devm_rc_register_device(dev
, rc
);
243 platform_set_drvdata(pdev
, ir
);
247 clk_disable_unprepare(ir
->clk
);
251 static int tango_ir_remove(struct platform_device
*pdev
)
253 struct tango_ir
*ir
= platform_get_drvdata(pdev
);
255 clk_disable_unprepare(ir
->clk
);
259 static const struct of_device_id tango_ir_dt_ids
[] = {
260 { .compatible
= "sigma,smp8642-ir" },
263 MODULE_DEVICE_TABLE(of
, tango_ir_dt_ids
);
265 static struct platform_driver tango_ir_driver
= {
266 .probe
= tango_ir_probe
,
267 .remove
= tango_ir_remove
,
270 .of_match_table
= tango_ir_dt_ids
,
273 module_platform_driver(tango_ir_driver
);
275 MODULE_DESCRIPTION("SMP86xx IR decoder driver");
276 MODULE_AUTHOR("Mans Rullgard <mans@mansr.com>");
277 MODULE_LICENSE("GPL");