1bdbf80c8SZhangbin Tong /*
2bdbf80c8SZhangbin Tong * (C) Copyright 2017 Rockchip Electronics Co., Ltd
3bdbf80c8SZhangbin Tong *
4bdbf80c8SZhangbin Tong * SPDX-License-Identifier: GPL-2.0+
5bdbf80c8SZhangbin Tong */
6bdbf80c8SZhangbin Tong
7bdbf80c8SZhangbin Tong #include <common.h>
8*f21c060eSLei Chen #include <clk.h>
9bdbf80c8SZhangbin Tong #include <dm.h>
10bdbf80c8SZhangbin Tong #include <dm/pinctrl.h>
11bdbf80c8SZhangbin Tong #include <errno.h>
12bdbf80c8SZhangbin Tong #include <rc.h>
13bdbf80c8SZhangbin Tong #include <rockchip_ir.h>
14bdbf80c8SZhangbin Tong #include <irq-generic.h>
15bdbf80c8SZhangbin Tong #include <irq-platform.h>
16bdbf80c8SZhangbin Tong
17bdbf80c8SZhangbin Tong #include <linux/bitrev.h>
18bdbf80c8SZhangbin Tong #include <linux/input.h>
19bdbf80c8SZhangbin Tong
20bdbf80c8SZhangbin Tong #include <asm/arch/periph.h>
21bdbf80c8SZhangbin Tong #include <asm/io.h>
22*f21c060eSLei Chen #include <dm/ofnode.h>
23bdbf80c8SZhangbin Tong DECLARE_GLOBAL_DATA_PTR;
24bdbf80c8SZhangbin Tong
25bdbf80c8SZhangbin Tong static struct nec_dec nec;
26bdbf80c8SZhangbin Tong static struct rc_map *rc_map;
27bdbf80c8SZhangbin Tong
rockchip_ir_get_keycode(struct udevice * dev)28bdbf80c8SZhangbin Tong static int rockchip_ir_get_keycode(struct udevice *dev)
29bdbf80c8SZhangbin Tong {
30bdbf80c8SZhangbin Tong struct rockchip_ir_priv *priv = dev_get_priv(dev);
31bdbf80c8SZhangbin Tong
32bdbf80c8SZhangbin Tong return priv->keycode;
33bdbf80c8SZhangbin Tong }
34bdbf80c8SZhangbin Tong
rockchip_ir_get_repeat(struct udevice * dev)35bdbf80c8SZhangbin Tong static int rockchip_ir_get_repeat(struct udevice *dev)
36bdbf80c8SZhangbin Tong {
37bdbf80c8SZhangbin Tong struct rockchip_ir_priv *priv = dev_get_priv(dev);
38bdbf80c8SZhangbin Tong
39bdbf80c8SZhangbin Tong return priv->repeat;
40bdbf80c8SZhangbin Tong }
41bdbf80c8SZhangbin Tong
ir_lookup_by_scancode(struct rockchip_ir_priv * priv,u32 usercode,u32 scancode)42bdbf80c8SZhangbin Tong static int ir_lookup_by_scancode(struct rockchip_ir_priv *priv,
43bdbf80c8SZhangbin Tong u32 usercode,
44bdbf80c8SZhangbin Tong u32 scancode)
45bdbf80c8SZhangbin Tong {
46bdbf80c8SZhangbin Tong int i, j;
47bdbf80c8SZhangbin Tong
48bdbf80c8SZhangbin Tong for (i = 0; i < priv->num; i++) {
49bdbf80c8SZhangbin Tong if (rc_map[i].usercode == usercode)
50bdbf80c8SZhangbin Tong break;
51bdbf80c8SZhangbin Tong }
52bdbf80c8SZhangbin Tong for (j = 0; i < priv->num && j < rc_map[i].nbuttons; j++) {
53bdbf80c8SZhangbin Tong if (rc_map[i].scan[j].scancode == scancode) {
54bdbf80c8SZhangbin Tong if (priv->keycode == rc_map[i].scan[j].keycode)
55bdbf80c8SZhangbin Tong priv->repeat++;
56bdbf80c8SZhangbin Tong else
57bdbf80c8SZhangbin Tong priv->repeat = 0;
58bdbf80c8SZhangbin Tong priv->keycode = rc_map[i].scan[j].keycode;
59bdbf80c8SZhangbin Tong return 0;
60bdbf80c8SZhangbin Tong }
61bdbf80c8SZhangbin Tong }
62bdbf80c8SZhangbin Tong
63bdbf80c8SZhangbin Tong priv->keycode = KEY_RESERVED;
64bdbf80c8SZhangbin Tong priv->repeat = 0;
65bdbf80c8SZhangbin Tong
66bdbf80c8SZhangbin Tong return -1;
67bdbf80c8SZhangbin Tong }
68bdbf80c8SZhangbin Tong
ir_parse_keys(struct udevice * dev)69bdbf80c8SZhangbin Tong static int ir_parse_keys(struct udevice *dev)
70bdbf80c8SZhangbin Tong {
71bdbf80c8SZhangbin Tong int i, j;
72bdbf80c8SZhangbin Tong int len;
73bdbf80c8SZhangbin Tong int ret;
74*f21c060eSLei Chen u32 val;
75*f21c060eSLei Chen ofnode node;
76bdbf80c8SZhangbin Tong
77bdbf80c8SZhangbin Tong i = 0;
78*f21c060eSLei Chen dev_for_each_subnode(node, dev) {
79*f21c060eSLei Chen ret = ofnode_read_u32(node, "rockchip,usercode", &val);
80*f21c060eSLei Chen if (ret) {
81*f21c060eSLei Chen debug("unable to get usercode\n");
82*f21c060eSLei Chen return -1;
83*f21c060eSLei Chen }
84*f21c060eSLei Chen rc_map[i].usercode = val;
85*f21c060eSLei Chen if (rc_map[i].usercode == 0) {
86bdbf80c8SZhangbin Tong debug("missing usercode property in the dts\n");
87bdbf80c8SZhangbin Tong return -1;
88bdbf80c8SZhangbin Tong }
89bdbf80c8SZhangbin Tong debug("add new usercode:0x%x\n", rc_map[i].usercode);
90*f21c060eSLei Chen len = ofnode_read_size(node, "rockchip,key_table");
91bdbf80c8SZhangbin Tong len /= sizeof(u32);
92bdbf80c8SZhangbin Tong debug("len:%d\n", len);
93bdbf80c8SZhangbin Tong rc_map[i].nbuttons = len / 2;
94*f21c060eSLei Chen
95*f21c060eSLei Chen ret = ofnode_read_u32_array(node, "rockchip,key_table",
96bdbf80c8SZhangbin Tong (u32 *)rc_map[i].scan, len);
97bdbf80c8SZhangbin Tong if (ret) {
98bdbf80c8SZhangbin Tong debug("missing key_table property in the dts\n");
99bdbf80c8SZhangbin Tong return -1;
100bdbf80c8SZhangbin Tong }
101bdbf80c8SZhangbin Tong for (j = 0; j < (len / 2); j++) {
102bdbf80c8SZhangbin Tong debug("[%d],usercode=0x%x scancode=0x%x keycode=0x%x\n",
103bdbf80c8SZhangbin Tong i,
104bdbf80c8SZhangbin Tong rc_map[i].usercode,
105bdbf80c8SZhangbin Tong rc_map[i].scan[j].scancode,
106bdbf80c8SZhangbin Tong rc_map[i].scan[j].keycode);
107bdbf80c8SZhangbin Tong }
108bdbf80c8SZhangbin Tong i++;
109bdbf80c8SZhangbin Tong }
110bdbf80c8SZhangbin Tong
111bdbf80c8SZhangbin Tong return 0;
112bdbf80c8SZhangbin Tong }
113bdbf80c8SZhangbin Tong
114bdbf80c8SZhangbin Tong /**
115bdbf80c8SZhangbin Tong * ir_nec_decode() - Decode one NEC pulse or space
116bdbf80c8SZhangbin Tong * @duration: the struct ir_raw_event descriptor of the pulse/space
117bdbf80c8SZhangbin Tong */
ir_nec_decode(struct rockchip_ir_priv * priv,struct ir_raw_event * ev)118bdbf80c8SZhangbin Tong static int ir_nec_decode(struct rockchip_ir_priv *priv, struct ir_raw_event *ev)
119bdbf80c8SZhangbin Tong {
120bdbf80c8SZhangbin Tong int ret;
121bdbf80c8SZhangbin Tong u32 usercode;
122bdbf80c8SZhangbin Tong u32 scancode;
123bdbf80c8SZhangbin Tong u8 __maybe_unused address, not_address, command, not_command;
124bdbf80c8SZhangbin Tong struct nec_dec *data = &nec;
125bdbf80c8SZhangbin Tong
126bdbf80c8SZhangbin Tong switch (data->state) {
127bdbf80c8SZhangbin Tong case STATE_INACTIVE:
128bdbf80c8SZhangbin Tong if (!ev->pulse)
129bdbf80c8SZhangbin Tong break;
130bdbf80c8SZhangbin Tong
131bdbf80c8SZhangbin Tong if (!eq_margin(ev->duration, NEC_HEADER_PULSE, NEC_UNIT * 2))
132bdbf80c8SZhangbin Tong break;
133bdbf80c8SZhangbin Tong
134bdbf80c8SZhangbin Tong data->count = 0;
135bdbf80c8SZhangbin Tong data->state = STATE_HEADER_SPACE;
136bdbf80c8SZhangbin Tong return 0;
137bdbf80c8SZhangbin Tong
138bdbf80c8SZhangbin Tong case STATE_HEADER_SPACE:
139bdbf80c8SZhangbin Tong if (ev->pulse)
140bdbf80c8SZhangbin Tong break;
141bdbf80c8SZhangbin Tong
142bdbf80c8SZhangbin Tong if (eq_margin(ev->duration, NEC_HEADER_SPACE, NEC_UNIT)) {
143bdbf80c8SZhangbin Tong data->state = STATE_BIT_PULSE;
144bdbf80c8SZhangbin Tong return 0;
145bdbf80c8SZhangbin Tong }
146bdbf80c8SZhangbin Tong
147bdbf80c8SZhangbin Tong break;
148bdbf80c8SZhangbin Tong
149bdbf80c8SZhangbin Tong case STATE_BIT_PULSE:
150bdbf80c8SZhangbin Tong if (!ev->pulse)
151bdbf80c8SZhangbin Tong break;
152bdbf80c8SZhangbin Tong
153bdbf80c8SZhangbin Tong if (!eq_margin(ev->duration, NEC_BIT_PULSE, NEC_UNIT / 2))
154bdbf80c8SZhangbin Tong break;
155bdbf80c8SZhangbin Tong
156bdbf80c8SZhangbin Tong data->state = STATE_BIT_SPACE;
157bdbf80c8SZhangbin Tong return 0;
158bdbf80c8SZhangbin Tong
159bdbf80c8SZhangbin Tong case STATE_BIT_SPACE:
160bdbf80c8SZhangbin Tong if (ev->pulse)
161bdbf80c8SZhangbin Tong break;
162bdbf80c8SZhangbin Tong
163bdbf80c8SZhangbin Tong data->bits <<= 1;
164*f21c060eSLei Chen if (eq_margin(ev->duration, NEC_BIT_1_SPACE, NEC_UNIT / 2)) {
165bdbf80c8SZhangbin Tong data->bits |= 1;
166*f21c060eSLei Chen } else if (!eq_margin(ev->duration, NEC_BIT_0_SPACE,
167*f21c060eSLei Chen NEC_UNIT / 2)) {
168bdbf80c8SZhangbin Tong break;
169*f21c060eSLei Chen }
170bdbf80c8SZhangbin Tong data->count++;
171bdbf80c8SZhangbin Tong
172bdbf80c8SZhangbin Tong if (data->count == NEC_NBITS) {
173bdbf80c8SZhangbin Tong address = ((data->bits >> 24) & 0xff);
174bdbf80c8SZhangbin Tong not_address = ((data->bits >> 16) & 0xff);
175bdbf80c8SZhangbin Tong command = ((data->bits >> 8) & 0xff);
176bdbf80c8SZhangbin Tong not_command = ((data->bits >> 0) & 0xff);
177bdbf80c8SZhangbin Tong
178bdbf80c8SZhangbin Tong if ((command ^ not_command) != 0xff) {
179bdbf80c8SZhangbin Tong debug("NEC checksum error: received 0x%08x\n",
180bdbf80c8SZhangbin Tong data->bits);
181bdbf80c8SZhangbin Tong }
182bdbf80c8SZhangbin Tong usercode = address << 8 | not_address;
183bdbf80c8SZhangbin Tong scancode = command << 8 | not_command;
184*f21c060eSLei Chen
185bdbf80c8SZhangbin Tong /* change to dts format */
186bdbf80c8SZhangbin Tong usercode = bitrev16(usercode);
187bdbf80c8SZhangbin Tong scancode = (bitrev16(scancode) >> 8) & 0xFF;
188*f21c060eSLei Chen debug("usercode 0x%04x scancode 0x%04x\n",
189*f21c060eSLei Chen usercode, scancode);
190bdbf80c8SZhangbin Tong
191bdbf80c8SZhangbin Tong data->state = STATE_INACTIVE;
192bdbf80c8SZhangbin Tong ret = ir_lookup_by_scancode(priv, usercode, scancode);
193bdbf80c8SZhangbin Tong if (!ret)
194bdbf80c8SZhangbin Tong debug("keycode 0x%02x repeat 0x%x\n",
195bdbf80c8SZhangbin Tong priv->keycode, priv->repeat);
196bdbf80c8SZhangbin Tong else
197bdbf80c8SZhangbin Tong debug("ir lookup by scancode failed\n");
198bdbf80c8SZhangbin Tong } else {
199bdbf80c8SZhangbin Tong data->state = STATE_BIT_PULSE;
200bdbf80c8SZhangbin Tong }
201bdbf80c8SZhangbin Tong
202bdbf80c8SZhangbin Tong return 0;
203bdbf80c8SZhangbin Tong }
204bdbf80c8SZhangbin Tong
205bdbf80c8SZhangbin Tong debug("NEC decode failed at count %d state %d (%uus %s)\n",
206bdbf80c8SZhangbin Tong data->count, data->state, TO_US(ev->duration), TO_STR(ev->pulse));
207bdbf80c8SZhangbin Tong data->state = STATE_INACTIVE;
208bdbf80c8SZhangbin Tong
209bdbf80c8SZhangbin Tong return -1;
210bdbf80c8SZhangbin Tong }
211bdbf80c8SZhangbin Tong
rockchip_ir_irq(int irq,void * data)212bdbf80c8SZhangbin Tong static void rockchip_ir_irq(int irq, void *data)
213bdbf80c8SZhangbin Tong {
214bdbf80c8SZhangbin Tong u32 val;
215bdbf80c8SZhangbin Tong u32 cycle_hpr, cycle_lpr, cycle;
216bdbf80c8SZhangbin Tong struct ir_raw_event ev;
217bdbf80c8SZhangbin Tong struct rockchip_ir_priv *priv = (struct rockchip_ir_priv *)data;
218bdbf80c8SZhangbin Tong
219bdbf80c8SZhangbin Tong val = readl(priv->base + PWM_STA_REG(priv->id));
220bdbf80c8SZhangbin Tong cycle_hpr = readl(priv->base + PWM_HPR_REG);
221bdbf80c8SZhangbin Tong cycle_lpr = readl(priv->base + PWM_LPR_REG);
222bdbf80c8SZhangbin Tong if (val & PWM_CH_POL(priv->id)) {
223bdbf80c8SZhangbin Tong cycle = cycle_hpr;
224bdbf80c8SZhangbin Tong ev.pulse = 0;
225bdbf80c8SZhangbin Tong } else {
226bdbf80c8SZhangbin Tong cycle = cycle_lpr;
227bdbf80c8SZhangbin Tong ev.pulse = 1;
228bdbf80c8SZhangbin Tong }
229bdbf80c8SZhangbin Tong writel(PWM_CH_INT(priv->id),
230bdbf80c8SZhangbin Tong priv->base + PWM_STA_REG(priv->id));
231*f21c060eSLei Chen
232bdbf80c8SZhangbin Tong ev.duration = cycle * priv->period;
233bdbf80c8SZhangbin Tong ir_nec_decode(priv, &ev);
234bdbf80c8SZhangbin Tong }
235bdbf80c8SZhangbin Tong
rockchip_ir_hw_init(struct udevice * dev)236bdbf80c8SZhangbin Tong static void rockchip_ir_hw_init(struct udevice *dev)
237bdbf80c8SZhangbin Tong {
238bdbf80c8SZhangbin Tong unsigned long tmp;
239bdbf80c8SZhangbin Tong struct rockchip_ir_priv *priv = dev_get_priv(dev);
240bdbf80c8SZhangbin Tong
241bdbf80c8SZhangbin Tong /* Enable capture mode, non-scaled clock, prescale 1 */
242bdbf80c8SZhangbin Tong writel(REG_CTL_MD, priv->base + PWM_CTL_REG);
243bdbf80c8SZhangbin Tong
244bdbf80c8SZhangbin Tong /* Clear Interrupt Status */
245bdbf80c8SZhangbin Tong writel(PWM_CH_INT(priv->id),
246bdbf80c8SZhangbin Tong priv->base + PWM_STA_REG(priv->id));
247bdbf80c8SZhangbin Tong
248bdbf80c8SZhangbin Tong /* Enable IRQ */
249bdbf80c8SZhangbin Tong writel(PWM_CH_INT(priv->id),
250bdbf80c8SZhangbin Tong priv->base + PWM_INT_REG(priv->id));
251bdbf80c8SZhangbin Tong
252bdbf80c8SZhangbin Tong /* Enable IR Module */
253bdbf80c8SZhangbin Tong tmp = readl(priv->base + PWM_CTL_REG);
254bdbf80c8SZhangbin Tong writel(tmp | REG_CTL_EN, priv->base + PWM_CTL_REG);
255bdbf80c8SZhangbin Tong }
256bdbf80c8SZhangbin Tong
rockchip_ir_ofdata_to_platdata(struct udevice * dev)257bdbf80c8SZhangbin Tong static int rockchip_ir_ofdata_to_platdata(struct udevice *dev)
258bdbf80c8SZhangbin Tong {
259*f21c060eSLei Chen ofnode node;
260*f21c060eSLei Chen int ret;
261*f21c060eSLei Chen int subnode_num = 0;
262*f21c060eSLei Chen u32 val;
263bdbf80c8SZhangbin Tong struct rockchip_ir_priv *priv = dev_get_priv(dev);
264bdbf80c8SZhangbin Tong
265*f21c060eSLei Chen dev_for_each_subnode(node, dev) {
266*f21c060eSLei Chen ret = ofnode_read_u32(node, "rockchip,usercode", &val);
267*f21c060eSLei Chen if (!ret)
268*f21c060eSLei Chen subnode_num++;
269*f21c060eSLei Chen }
270*f21c060eSLei Chen
271*f21c060eSLei Chen priv->num = subnode_num;
272*f21c060eSLei Chen
273bdbf80c8SZhangbin Tong if (priv->num == 0) {
274bdbf80c8SZhangbin Tong debug("no ir map in dts\n");
275bdbf80c8SZhangbin Tong return -1;
276bdbf80c8SZhangbin Tong }
277*f21c060eSLei Chen priv->base = dev_read_addr(dev);
278bdbf80c8SZhangbin Tong priv->id = (priv->base >> 4) & 0xF;
279bdbf80c8SZhangbin Tong
280bdbf80c8SZhangbin Tong return 0;
281bdbf80c8SZhangbin Tong }
282bdbf80c8SZhangbin Tong
rockchip_ir_probe(struct udevice * dev)283bdbf80c8SZhangbin Tong static int rockchip_ir_probe(struct udevice *dev)
284bdbf80c8SZhangbin Tong {
285bdbf80c8SZhangbin Tong int ret;
286bdbf80c8SZhangbin Tong struct clk clk;
287bdbf80c8SZhangbin Tong struct udevice *pinctrl;
288bdbf80c8SZhangbin Tong struct rockchip_ir_priv *priv = dev_get_priv(dev);
289bdbf80c8SZhangbin Tong
290bdbf80c8SZhangbin Tong rc_map = calloc(1, priv->num * sizeof(struct rc_map));
291bdbf80c8SZhangbin Tong if (!rc_map) {
292bdbf80c8SZhangbin Tong debug("%s: failed to calloc\n", __func__);
293bdbf80c8SZhangbin Tong return -EINVAL;
294bdbf80c8SZhangbin Tong }
295bdbf80c8SZhangbin Tong
296bdbf80c8SZhangbin Tong ret = ir_parse_keys(dev);
297bdbf80c8SZhangbin Tong if (ret) {
298bdbf80c8SZhangbin Tong debug("%s: failed to parse keys\n", __func__);
299bdbf80c8SZhangbin Tong return -EINVAL;
300bdbf80c8SZhangbin Tong }
301bdbf80c8SZhangbin Tong /*
302bdbf80c8SZhangbin Tong * The PWM does not have decicated interrupt number in dts and can
303bdbf80c8SZhangbin Tong * not get periph_id by pinctrl framework, so let's init then here.
304bdbf80c8SZhangbin Tong */
305bdbf80c8SZhangbin Tong ret = uclass_get_device(UCLASS_PINCTRL, 0, &pinctrl);
306bdbf80c8SZhangbin Tong if (ret) {
307bdbf80c8SZhangbin Tong debug("%s: can't find pinctrl device\n", __func__);
308bdbf80c8SZhangbin Tong return -EINVAL;
309bdbf80c8SZhangbin Tong }
310bdbf80c8SZhangbin Tong
311bdbf80c8SZhangbin Tong ret = clk_get_by_index(dev, 0, &clk);
312bdbf80c8SZhangbin Tong if (ret) {
313bdbf80c8SZhangbin Tong debug("%s get clock fail!\n", __func__);
314bdbf80c8SZhangbin Tong return -EINVAL;
315bdbf80c8SZhangbin Tong }
316bdbf80c8SZhangbin Tong priv->freq = clk_get_rate(&clk);
317bdbf80c8SZhangbin Tong debug("%s pwm clk = %lu\n", __func__, priv->freq);
318bdbf80c8SZhangbin Tong priv->period = 1000000000 / priv->freq;
319bdbf80c8SZhangbin Tong
320bdbf80c8SZhangbin Tong irq_install_handler(IRQ_PWM,
321bdbf80c8SZhangbin Tong (interrupt_handler_t *)rockchip_ir_irq, priv);
322bdbf80c8SZhangbin Tong irq_handler_enable(IRQ_PWM);
323bdbf80c8SZhangbin Tong
324bdbf80c8SZhangbin Tong rockchip_ir_hw_init(dev);
325bdbf80c8SZhangbin Tong
326bdbf80c8SZhangbin Tong return ret;
327bdbf80c8SZhangbin Tong }
328bdbf80c8SZhangbin Tong
329bdbf80c8SZhangbin Tong static const struct dm_rc_ops rockchip_ir_ops = {
330bdbf80c8SZhangbin Tong .get_keycode = rockchip_ir_get_keycode,
331bdbf80c8SZhangbin Tong .get_repeat = rockchip_ir_get_repeat,
332bdbf80c8SZhangbin Tong };
333bdbf80c8SZhangbin Tong
334bdbf80c8SZhangbin Tong static const struct udevice_id rockchip_ir_ids[] = {
335bdbf80c8SZhangbin Tong { .compatible = "rockchip,remotectl-pwm" },
336bdbf80c8SZhangbin Tong { }
337bdbf80c8SZhangbin Tong };
338bdbf80c8SZhangbin Tong
339bdbf80c8SZhangbin Tong U_BOOT_DRIVER(rockchip_ir) = {
340bdbf80c8SZhangbin Tong .name = "rockchip_ir",
341bdbf80c8SZhangbin Tong .id = UCLASS_RC,
342bdbf80c8SZhangbin Tong .of_match = rockchip_ir_ids,
343bdbf80c8SZhangbin Tong .ofdata_to_platdata = rockchip_ir_ofdata_to_platdata,
344bdbf80c8SZhangbin Tong .probe = rockchip_ir_probe,
345bdbf80c8SZhangbin Tong .ops = &rockchip_ir_ops,
346bdbf80c8SZhangbin Tong .priv_auto_alloc_size = sizeof(struct rockchip_ir_priv),
347bdbf80c8SZhangbin Tong };
348