1 /*
2 * Copyright (C) 2021 HiSilicon (Shanghai) Technologies CO., LIMITED.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 */
18
19 #include "hiir.h"
20 #include "hi_osal.h"
21 #include "hiir_codedef.h"
22 #include "hi_ir_hal.h"
23
24 #ifndef NULL
25 #define NULL ((void *)0)
26 #endif
27
28 /* irq */
29 unsigned int g_ir_irq = 0;
30
31 /* io */
32 #define IR_REG_LENGTH 0x1000
33 volatile void *g_ir_reg_base = NULL;
34
35 #define GPIO_CFG_ADDR 0x112F0094
36
37 #define IR_ENABLE ((uintptr_t)g_ir_reg_base + 0x00)
38 #define IR_CONFIG ((uintptr_t)g_ir_reg_base + 0x04)
39 #define CNT_LEADS ((uintptr_t)g_ir_reg_base + 0x08)
40 #define CNT_LEADE ((uintptr_t)g_ir_reg_base + 0x0c)
41 #define CNT_SLEADE ((uintptr_t)g_ir_reg_base + 0x10)
42 #define CNT0_B ((uintptr_t)g_ir_reg_base + 0x14)
43 #define CNT1_B ((uintptr_t)g_ir_reg_base + 0x18)
44 #define IR_BUSY ((uintptr_t)g_ir_reg_base + 0x1c)
45 #define IR_DATAH ((uintptr_t)g_ir_reg_base + 0x20)
46 #define IR_DATAL ((uintptr_t)g_ir_reg_base + 0x24)
47 #define IR_INTM ((uintptr_t)g_ir_reg_base + 0x28)
48 #define IR_INTS ((uintptr_t)g_ir_reg_base + 0x2c)
49 #define IR_INTC ((uintptr_t)g_ir_reg_base + 0x30)
50 #define IR_START ((uintptr_t)g_ir_reg_base + 0x34)
51
52 /* interrupt mask */
53 #define INTMS_RCV (1L << 16)
54 #define INTMS_FRAMERR (1L << 17)
55 #define INTMS_OVERFLOW (1L << 18)
56 #define INTMS_RELEASE (1L << 19)
57
58 #define INT_MASK (INTMS_RCV | INTMS_FRAMERR | INTMS_OVERFLOW | INTMS_RELEASE)
59
60 /* define macro */
61 #define write_reg(addr, value) ((*(volatile unsigned int *)(addr)) = value)
62 #define read_reg(addr) (*(volatile unsigned int *)(addr))
63
64 /* debug */
65 static int g_dbg_flag = 0;
66 #define HIIR_PFX "hiir: "
67 #define hiir_dbg(params...) \
68 do { \
69 if (g_dbg_flag) { \
70 osal_printk(params); \
71 } \
72 } while (0);
73
74 /* unit is ms */
75 #define DEFAULT_DELAYTIME (200 * 10)
76
77 #define HI_IR_MAX_BUF 100
78 #define DEFAULT_BUF_LEN 8
79 #define BUF_HEAD g_hiir_dev.buf[g_hiir_dev.head]
80 #define BUF_TAIL g_hiir_dev.buf[g_hiir_dev.tail]
81 #define BUF_LAST g_hiir_dev.buf[(g_hiir_dev.head == 0) ? (g_hiir_dev.buf_len - 1) : (g_hiir_dev.head - 1)]
82
83 typedef struct {
84 hiir_dev_param dev_parm;
85 unsigned int head;
86 unsigned int tail;
87 irkey_info_s buf[HI_IR_MAX_BUF + 1]; /* 1:fifo reserve */
88 unsigned int buf_len;
89
90 unsigned int enable_repkey;
91 unsigned int repkey_checkflag;
92 unsigned int repkey_delaytime; /* ms */
93
94 unsigned int enable_keyup;
95
96 osal_wait_t ir_key_wait;
97 } hiir_dev_struct;
98
99 static hiir_dev_struct g_hiir_dev;
100
101 static void repkey_timeout_handler(unsigned long data);
102 static struct osal_timer g_repkey_timeout_timer;
103 static int g_need_iounmap = 0;
104
hiir_show_reg(void)105 static void hiir_show_reg(void)
106 {
107 if (g_dbg_flag) {
108 osal_printk("HIIR11 REG:###################################################\n");
109 osal_printk("%.8x ", read_reg(IR_ENABLE));
110 osal_printk("%.8x ", read_reg(IR_CONFIG));
111 osal_printk("%.8x ", read_reg(CNT_LEADS));
112 osal_printk("%.8x ", read_reg(CNT_LEADE));
113 osal_printk("%.8x ", read_reg(CNT_SLEADE));
114 osal_printk("%.8x ", read_reg(CNT0_B));
115 osal_printk("%.8x ", read_reg(CNT1_B));
116 osal_printk("\n");
117 osal_printk("%.8x ", read_reg(IR_BUSY));
118 osal_printk("%.8x ", read_reg(IR_DATAH));
119 osal_printk("%.8x ", read_reg(IR_DATAL));
120 osal_printk("%.8x ", read_reg(IR_INTM));
121 osal_printk("%.8x ", read_reg(IR_INTS));
122 osal_printk("%.8x ", read_reg(IR_INTC));
123 osal_printk("%.8x ", read_reg(IR_START));
124 osal_printk("\n");
125 }
126 }
127
inc_buf(unsigned int x,unsigned int len)128 static inline unsigned int inc_buf(unsigned int x, unsigned int len)
129 {
130 ++x;
131
132 if (len == 0) {
133 return x % DEFAULT_BUF_LEN;
134 } else {
135 return x % len;
136 }
137 }
138
write_reg32(unsigned int value,unsigned int mask,const void * addr)139 static void write_reg32(unsigned int value, unsigned int mask, const void *addr)
140 {
141 unsigned int t;
142
143 t = osal_readl((void *)addr);
144 t &= ~mask;
145 t |= value & mask;
146
147 osal_writel(t, (void *)addr);
148 }
149
hiir_enable_clock(void)150 static int hiir_enable_clock(void)
151 {
152 void *ir_crg_addr = NULL;
153
154 ir_crg_addr = osal_ioremap(IR_CRG_ADDR, (unsigned long)IR_CLOCK_REG_LENGTH);
155 if (ir_crg_addr == NULL) {
156 return -1;
157 }
158
159 write_reg32(0x1 << IR_BIT, 0x1 << IR_BIT, ir_crg_addr); /* 0x1: [1] bit for clock control */
160
161 osal_iounmap((void *)ir_crg_addr, (unsigned long)IR_CLOCK_REG_LENGTH);
162
163 return 0;
164 }
165
hiir_disable_clock(void)166 static void hiir_disable_clock(void)
167 {
168 void *ir_crg_addr = NULL;
169
170 ir_crg_addr = osal_ioremap(IR_CRG_ADDR, (unsigned long)IR_CLOCK_REG_LENGTH);
171 if (ir_crg_addr == NULL) {
172 return;
173 }
174
175 write_reg32(0x0 << IR_BIT, 0x1 << IR_BIT, ir_crg_addr); /* 0x1: [1] bit for clock control */
176
177 osal_iounmap((void *)ir_crg_addr, (unsigned long)IR_CLOCK_REG_LENGTH);
178 }
179
hiir_config(void)180 static void hiir_config(void)
181 {
182 unsigned int value;
183
184 write_reg(IR_ENABLE, 0x01); /* 0x01: for IR control */
185 while (read_reg(IR_BUSY)) {
186 hiir_dbg("IR_BUSY. Wait...\n");
187 }
188
189 value = (g_hiir_dev.dev_parm.codetype << 14); /* 14: [15:14] bits for code type */
190 value |= (g_hiir_dev.dev_parm.code_len - 1) << 8; /* 8: [13:8] bits for code len */
191 value |= (g_hiir_dev.dev_parm.frequence - 1); /* [6:0] bits for frequence */
192 write_reg(IR_CONFIG, value);
193
194 value = g_hiir_dev.dev_parm.leads_min << 16; /* 16: [25:16] bits for min leads */
195 value |= g_hiir_dev.dev_parm.leads_max; /* [9:0] bits for max leads */
196 write_reg(CNT_LEADS, value);
197
198 value = g_hiir_dev.dev_parm.leade_min << 16; /* 16, bits [24:16] for min leads */
199 value |= g_hiir_dev.dev_parm.leade_max; /* [8:0] bits for max leads */
200 write_reg(CNT_LEADE, value);
201
202 value = g_hiir_dev.dev_parm.sleade_min << 16; /* 16, bits [24:16] for min sleade */
203 value |= g_hiir_dev.dev_parm.sleade_max; /* [8:0] bits for max sleade */
204 write_reg(CNT_SLEADE, value);
205
206 value = g_hiir_dev.dev_parm.cnt0_b_min << 16; /* 16, bits [24:16] for min cnt0 */
207 value |= g_hiir_dev.dev_parm.cnt0_b_max; /* [8:0] bits for max cnt0 */
208 write_reg(CNT0_B, value);
209
210 value = g_hiir_dev.dev_parm.cnt1_b_min << 16; /* 16, bits [24:16] for min cnt1 */
211 value |= g_hiir_dev.dev_parm.cnt1_b_max; /* [8:0] bits for max cnt1 */
212 write_reg(CNT1_B, value);
213
214 write_reg(IR_INTM, 0x00);
215 write_reg(IR_START, 0x00);
216 }
217
repkey_timeout_handler(unsigned long data)218 static void repkey_timeout_handler(unsigned long data)
219 {
220 hi_ir_unused(data);
221
222 osal_del_timer(&g_repkey_timeout_timer);
223 g_hiir_dev.repkey_checkflag = 0;
224 }
225
interrupt_rcv(void)226 static void interrupt_rcv(void)
227 {
228 hiir_dbg("receive data interrupt. 0x%.8x-0x%.8x\n", read_reg(IR_DATAH), read_reg(IR_DATAL));
229 write_reg(IR_INTC, 0x01 << 0); /* 0x01: clear interrupt */
230
231 if (g_hiir_dev.enable_repkey) {
232 if ((g_hiir_dev.repkey_checkflag) &&
233 (BUF_LAST.irkey_datah == read_reg(IR_DATAH)) &&
234 (BUF_LAST.irkey_datal == read_reg(IR_DATAL))) {
235 hiir_dbg("repeart key [0x%.8x]-[0x%.8x] detective\n", read_reg(IR_DATAH), read_reg(IR_DATAL));
236 } else {
237 /* repeat key check */
238 osal_del_timer(&g_repkey_timeout_timer);
239 osal_set_timer(&g_repkey_timeout_timer, g_hiir_dev.repkey_delaytime / 10); /* 10: delaytime means ms*10 */
240 g_hiir_dev.repkey_checkflag = 1;
241 BUF_HEAD.irkey_datah = read_reg(IR_DATAH);
242 BUF_HEAD.irkey_datal = read_reg(IR_DATAL);
243 BUF_HEAD.irkey_state_code = HIIR_KEY_DOWN;
244 g_hiir_dev.head = inc_buf(g_hiir_dev.head, g_hiir_dev.buf_len);
245 osal_wakeup(&(g_hiir_dev.ir_key_wait));
246 }
247 } else if (!((BUF_LAST.irkey_datah == read_reg(IR_DATAH)) &&
248 (BUF_LAST.irkey_datal == read_reg(IR_DATAL)) &&
249 (BUF_LAST.irkey_state_code == HIIR_KEY_DOWN))) {
250 BUF_HEAD.irkey_datah = read_reg(IR_DATAH);
251 BUF_HEAD.irkey_datal = read_reg(IR_DATAL);
252 BUF_HEAD.irkey_state_code = HIIR_KEY_DOWN;
253 g_hiir_dev.head = inc_buf(g_hiir_dev.head, g_hiir_dev.buf_len);
254 osal_wakeup(&(g_hiir_dev.ir_key_wait));
255 }
256 }
257
hiir_interrupt(int irq,void * dev_id)258 static int hiir_interrupt(int irq, void *dev_id)
259 {
260 unsigned int int_state = read_reg(IR_INTS);
261 hi_ir_unused(irq);
262 hi_ir_unused(dev_id);
263
264 if ((int_state & INT_MASK) == 0) {
265 return OSAL_IRQ_NONE;
266 }
267
268 hiir_dbg("Enter hiir_interrupt.\n");
269 hiir_show_reg();
270
271 if (int_state & INTMS_FRAMERR) {
272 hiir_dbg("frame error.\n");
273 write_reg(IR_INTC, 0x01 << 1); /* 1: write 0x01 to [1] bit, clear frame error interrupt */
274 } else if (int_state & INTMS_OVERFLOW) {
275 hiir_dbg("hardware overflow.\n");
276 write_reg(IR_INTC, 0x01 << 2); /* 2: write 0x01 to [2] bit, clear hardware overflow interrupt */
277 } else if (int_state & INTMS_RELEASE) {
278 hiir_dbg("release key interrupt.\n");
279 write_reg(IR_INTC, 0x01 << 3); /* 3: write 0x01 to [3] bit, clear release key interrupt */
280
281 osal_del_timer(&g_repkey_timeout_timer);
282 g_hiir_dev.repkey_checkflag = 0;
283
284 if ((g_hiir_dev.enable_keyup) && (BUF_LAST.irkey_state_code != HIIR_KEY_UP)) {
285 BUF_HEAD = BUF_LAST;
286 BUF_HEAD.irkey_state_code = HIIR_KEY_UP;
287 g_hiir_dev.head = inc_buf(g_hiir_dev.head, g_hiir_dev.buf_len);
288 osal_wakeup(&(g_hiir_dev.ir_key_wait));
289 }
290 } else if (int_state & INTMS_RCV) {
291 interrupt_rcv();
292 } else {
293 osal_printk("logic Error: int_mask=0x%.8x, int_state=0x%.8x.\n", read_reg(IR_INTM), int_state);
294 }
295
296 hiir_dbg("Exit hiir_interrupt.\n");
297
298 return OSAL_IRQ_HANDLED;
299 }
300
hiir_ioctl(unsigned int cmd,unsigned long arg,void * private_data)301 static long hiir_ioctl(unsigned int cmd, unsigned long arg, void *private_data)
302 {
303 int *p = (int *)(uintptr_t)arg;
304 unsigned int min_val, max_val;
305 hi_ir_unused(private_data);
306
307 switch (cmd) {
308 case IR_IOC_SET_BUF:
309 if ((arg > 0) && (arg <= HI_IR_MAX_BUF)) {
310 g_hiir_dev.buf_len = arg + 1;
311
312 /* need reset buf pointrt */
313 g_hiir_dev.head = 0;
314 g_hiir_dev.tail = 0;
315 }
316 hiir_dbg("IR_IOC_SET_BUF->buf_len=%u\n", g_hiir_dev.buf_len);
317 break;
318 case IR_IOC_SET_ENABLE_KEYUP:
319 g_hiir_dev.enable_keyup = arg;
320 hiir_dbg("IR_IOC_SET_ENABLE_KEYUP->enable_keyup=%u\n", g_hiir_dev.enable_keyup);
321 break;
322 case IR_IOC_SET_ENABLE_REPKEY:
323 g_hiir_dev.enable_repkey = arg;
324 hiir_dbg("IR_IOC_SET_ENABLE_REPKEY->enable_repkey=%u\n", g_hiir_dev.enable_repkey);
325 break;
326 case IR_IOC_SET_REPKEY_TIMEOUTVAL:
327 if (arg > 0) {
328 g_hiir_dev.repkey_delaytime = arg;
329 }
330 hiir_dbg("IR_IOC_SET_REPKEY_TIMEOUTVAL->repkey_delaytime=%u\n", g_hiir_dev.repkey_delaytime);
331 break;
332 case IR_IOC_SET_FORMAT:
333 if (arg > 3) { /* format:[0,3] */
334 osal_printk("Error: IR_IOC_SET_FORMAT->invalid args=%lu\n", arg);
335 return -1;
336 }
337 g_hiir_dev.dev_parm.codetype = arg;
338 hiir_dbg("IR_IOC_SET_FORMAT->codetype=%u\n", g_hiir_dev.dev_parm.codetype);
339 break;
340 case IR_IOC_SET_CODELEN:
341 g_hiir_dev.dev_parm.code_len = arg;
342 hiir_dbg("IR_IOC_SET_CODELEN->code_len=%u\n", g_hiir_dev.dev_parm.code_len);
343 break;
344 case IR_IOC_SET_FREQ:
345 if ((arg <= 0) || (arg > 128)) { /* 128:max freq */
346 osal_printk("Error: IR_IOC_SET_FREQ->invalid args=%lu\n", arg);
347 return -1;
348 }
349 g_hiir_dev.dev_parm.frequence = arg;
350 hiir_dbg("IR_IOC_SET_FREQ->frequence=%u\n", g_hiir_dev.dev_parm.frequence);
351 break;
352 case IR_IOC_SET_LEADS:
353 if (osal_copy_from_user(&min_val, p, sizeof(int)) || osal_copy_from_user(&max_val, p + 1, sizeof(int))) {
354 return -1;
355 }
356 g_hiir_dev.dev_parm.leads_min = min_val;
357 g_hiir_dev.dev_parm.leads_max = max_val;
358 hiir_dbg("IR_IOC_SET_LEADS->leads_min=%u, leads_max=%u\n",
359 g_hiir_dev.dev_parm.leads_min, g_hiir_dev.dev_parm.leads_max);
360 break;
361 case IR_IOC_SET_LEADE:
362 if (osal_copy_from_user(&min_val, p, sizeof(int)) || osal_copy_from_user(&max_val, p + 1, sizeof(int))) {
363 return -1;
364 }
365 g_hiir_dev.dev_parm.leade_min = min_val;
366 g_hiir_dev.dev_parm.leade_max = max_val;
367 hiir_dbg("IR_IOC_SET_LEADE->leade_min=%u, leade_max=%u\n",
368 g_hiir_dev.dev_parm.leade_min, g_hiir_dev.dev_parm.leade_max);
369 break;
370 case IR_IOC_SET_SLEADE:
371 if (osal_copy_from_user(&min_val, p, sizeof(int)) || osal_copy_from_user(&max_val, p + 1, sizeof(int))) {
372 return -1;
373 }
374 g_hiir_dev.dev_parm.sleade_min = min_val;
375 g_hiir_dev.dev_parm.sleade_max = max_val;
376 hiir_dbg("IR_IOC_SET_SLEADE->sleade_min=%u, sleade_max=%u\n",
377 g_hiir_dev.dev_parm.sleade_min, g_hiir_dev.dev_parm.sleade_max);
378 break;
379 case IR_IOC_SET_CNT0_B:
380 if (osal_copy_from_user(&min_val, p, sizeof(int)) || osal_copy_from_user(&max_val, p + 1, sizeof(int))) {
381 return -1;
382 }
383 g_hiir_dev.dev_parm.cnt0_b_min = min_val;
384 g_hiir_dev.dev_parm.cnt0_b_max = max_val;
385 hiir_dbg("IR_IOC_SET_CNT0_B->cnt0_b_min=%u, cnt0_b_max=%u\n",
386 g_hiir_dev.dev_parm.cnt0_b_min, g_hiir_dev.dev_parm.cnt0_b_max);
387 break;
388 case IR_IOC_SET_CNT1_B:
389 if (osal_copy_from_user(&min_val, p, sizeof(int)) || osal_copy_from_user(&max_val, p + 1, sizeof(int))) {
390 return -1;
391 }
392 g_hiir_dev.dev_parm.cnt1_b_min = min_val;
393 g_hiir_dev.dev_parm.cnt1_b_max = max_val;
394 hiir_dbg("IR_IOC_SET_CNT1_B->cnt1_b_min=%u, cnt1_b_max=%u\n",
395 g_hiir_dev.dev_parm.cnt1_b_min, g_hiir_dev.dev_parm.cnt1_b_max);
396 break;
397 case IR_IOC_GET_CONFIG:
398 if (osal_copy_to_user((void *)(uintptr_t)arg, &(g_hiir_dev.dev_parm), sizeof(hiir_dev_param))) {
399 osal_printk("%s: copy_to_user fail!\n", __func__);
400 }
401 hiir_dbg("IR_IOC_GET_CONFIG\n");
402 break;
403 case IR_IOC_ENDBG:
404 g_dbg_flag = 1;
405 hiir_dbg("IR_IOC_ENDBG\n");
406 break;
407 case IR_IOC_DISDBG:
408 g_dbg_flag = 0;
409 hiir_dbg("IR_IOC_DISDBG\n");
410 break;
411 default:
412 osal_printk("Error: Inappropriate ioctl for device. cmd=%u\n", cmd);
413 return -1;
414 }
415
416 hiir_config();
417 return 0;
418 }
419
hiir_wait_condition_callback(const void * param)420 static int hiir_wait_condition_callback(const void *param)
421 {
422 hi_ir_unused(param);
423
424 return (g_hiir_dev.head != g_hiir_dev.tail);
425 }
426
hiir_read(char * buf,int count,long * f_pos,void * private_data)427 static int hiir_read(char *buf, int count, long *f_pos, void *private_data)
428 {
429 irkey_info_s irkey_to_user;
430 int res = 0;
431 hi_ir_unused(f_pos);
432 hi_ir_unused(private_data);
433
434 retry :
435 hiir_dbg("Enter hiir_read : head=%u, tail=%u, buf_len=%u\n", g_hiir_dev.head, g_hiir_dev.tail, g_hiir_dev.buf_len);
436
437 if ((g_hiir_dev.head) == (g_hiir_dev.tail)) {
438 res = osal_wait_event_interruptible(&(g_hiir_dev.ir_key_wait), hiir_wait_condition_callback, &g_hiir_dev);
439 if (res != 0) {
440 return res;
441 }
442 goto retry;
443 } else {
444 while (((g_hiir_dev.head) != (g_hiir_dev.tail)) && ((res + (int)sizeof(irkey_info_s)) <= count)) {
445 irkey_to_user = BUF_TAIL;
446 g_hiir_dev.tail = inc_buf(g_hiir_dev.tail, g_hiir_dev.buf_len);
447 if (osal_copy_to_user((buf + res), &irkey_to_user, sizeof(irkey_info_s))) {
448 osal_printk("%s: copy_to_user fail!\n", __func__);
449 }
450 res += sizeof(irkey_info_s);
451 }
452 }
453 return res;
454 }
455
hiir_select(osal_poll_t * osal_poll,void * private_data)456 static unsigned int hiir_select(osal_poll_t *osal_poll, void *private_data)
457 {
458 hi_ir_unused(private_data);
459
460 hiir_dbg("Enter hiir_select.\n");
461 if ((g_hiir_dev.head) != (g_hiir_dev.tail)) {
462 return 1;
463 }
464 osal_poll_wait(osal_poll, &(g_hiir_dev.ir_key_wait));
465 return 0;
466 }
467
468 static osal_atomic_t g_hiir_s_available;
469
hiir_open(void * private_data)470 static int hiir_open(void *private_data)
471 {
472 int ret;
473 hi_ir_unused(private_data);
474
475 hiir_dbg("Enter hiir_open.\n");
476
477 if (osal_atomic_dec_return(&g_hiir_s_available) != 0) {
478 ret = osal_atomic_inc_return(&g_hiir_s_available);
479 osal_printk("Error: device already open:%d.\n", ret);
480 return -1;
481 }
482
483 osal_del_timer(&g_repkey_timeout_timer);
484
485 g_dbg_flag = 0;
486
487 /* init g_hiir_dev */
488 g_hiir_dev.dev_parm = g_static_dev_param[0]; /* nec format */
489 g_hiir_dev.head = 0;
490 g_hiir_dev.tail = 0;
491 g_hiir_dev.buf_len = DEFAULT_BUF_LEN;
492 g_hiir_dev.enable_repkey = 1;
493 g_hiir_dev.repkey_checkflag = 0;
494 g_hiir_dev.repkey_delaytime = DEFAULT_DELAYTIME;
495 g_hiir_dev.enable_keyup = 1;
496 osal_wait_init(&g_hiir_dev.ir_key_wait);
497
498 hiir_config();
499
500 return 0;
501 }
502
hiir_release(void * private_data)503 static int hiir_release(void *private_data)
504 {
505 hi_ir_unused(private_data);
506
507 hiir_dbg("Enter hiir_release.\n");
508
509 /* disable HIIR11 */
510 write_reg(IR_ENABLE, 0x0);
511
512 if (osal_atomic_inc_return(&g_hiir_s_available) != 1) {
513 osal_atomic_dec_return(&g_hiir_s_available);
514 return 0;
515 }
516
517 osal_del_timer(&g_repkey_timeout_timer);
518
519 osal_wait_destroy(&g_hiir_dev.ir_key_wait);
520
521 return 0;
522 }
523
524 static struct osal_fileops g_hiir_fops = {
525 open : hiir_open,
526 unlocked_ioctl : hiir_ioctl,
527 poll : hiir_select,
528 read : hiir_read,
529 release : hiir_release,
530 };
531
532 static struct osal_dev *g_hiir_miscdev = NULL;
533
hiir_sw_init(void)534 static int hiir_sw_init(void)
535 {
536 int res;
537
538 if (g_ir_irq <= 0) {
539 g_ir_irq = HIIR_DEVICE_IRQ_NO;
540 }
541
542 if (g_ir_reg_base == NULL) {
543 g_ir_reg_base = (volatile void *)osal_ioremap(IR_REG_BASE, IR_REG_LENGTH);
544 if (g_ir_reg_base == NULL) {
545 osal_printk("osal_ioremap err. \n");
546 return 1;
547 }
548 g_need_iounmap = 1;
549 }
550
551 res = osal_atomic_init(&g_hiir_s_available);
552 if (res != 0) {
553 osal_printk("Error: init atomic\n");
554 if (g_need_iounmap) {
555 osal_iounmap(((void *)g_ir_reg_base), IR_REG_LENGTH);
556 g_need_iounmap = 0;
557 g_ir_reg_base = NULL;
558 }
559 return 1;
560 }
561 osal_atomic_set(&g_hiir_s_available, 1);
562
563 g_repkey_timeout_timer.function = repkey_timeout_handler;
564 res = osal_timer_init(&g_repkey_timeout_timer);
565 if (res != 0) {
566 if (g_need_iounmap) {
567 osal_iounmap(((void *)g_ir_reg_base), IR_REG_LENGTH);
568 g_need_iounmap = 0;
569 g_ir_reg_base = NULL;
570 }
571 osal_atomic_destroy(&g_hiir_s_available);
572 return 1;
573 }
574 return 0;
575 }
576
577 /* Configure the pin as IR of the IR pin_IN */
init_ir_io(void)578 static int init_ir_io(void)
579 {
580 unsigned int value;
581 void* io_addr_virtual = osal_ioremap_nocache(GPIO_CFG_ADDR, 0x10);
582
583 if (io_addr_virtual == NULL) {
584 osal_printk("ioremap gpiogroup0 failed!\n");
585 return -1;
586 }
587 value = read_reg(io_addr_virtual);
588 value |= 0x01;
589 write_reg(io_addr_virtual, value);
590 osal_iounmap(io_addr_virtual, 0x10);
591 return 0;
592 }
593
hiir_init(void)594 int hiir_init(void)
595 {
596 int ret;
597
598 if (hiir_sw_init() != 0) {
599 return -1;
600 }
601 /* disable HIIR */
602 write_reg(IR_ENABLE, 0x00);
603 if (hiir_enable_clock() != 0) {
604 osal_printk("Error: enable clock fail\n");
605 goto enable_clock_fail;
606 }
607 ret = init_ir_io();
608 if (ret < 0) {
609 osal_printk("init_ir_io fail.\n");
610 goto cteate_dev_fail;
611 }
612 g_hiir_miscdev = osal_createdev(HIIR_DEVICE_NAME);
613 if (g_hiir_miscdev == NULL) {
614 osal_printk("Error: can't create dev\n");
615 goto cteate_dev_fail;
616 }
617
618 g_hiir_miscdev->minor = 255; /* 255:dev_minor */
619 g_hiir_miscdev->fops = &g_hiir_fops;
620 if (osal_registerdevice(g_hiir_miscdev) != 0) {
621 osal_printk("Error: can't register\n");
622 goto register_drvice_fail;
623 }
624
625 if (osal_request_irq(g_ir_irq, hiir_interrupt, NULL, HIIR_DEVICE_NAME, &hiir_interrupt) != 0) {
626 osal_printk("Error: request IRQ(%u) failed\n", g_ir_irq);
627 goto request_irq_fail;
628 }
629
630 osal_printk("hiir init ok. ver=%s, %s.\n", __DATE__, __TIME__);
631 return 0;
632
633 request_irq_fail:
634 osal_deregisterdevice(g_hiir_miscdev);
635 register_drvice_fail:
636 osal_destroydev(g_hiir_miscdev);
637 cteate_dev_fail:
638 hiir_disable_clock();
639 enable_clock_fail:
640 osal_timer_destroy(&g_repkey_timeout_timer);
641 osal_atomic_destroy(&g_hiir_s_available);
642 if (g_need_iounmap) {
643 osal_iounmap(((void *)g_ir_reg_base), IR_REG_LENGTH);
644 g_need_iounmap = 0;
645 g_ir_reg_base = NULL;
646 }
647 return -1;
648 }
649
hiir_exit(void)650 void hiir_exit(void)
651 {
652 osal_free_irq(g_ir_irq, &hiir_interrupt);
653
654 osal_deregisterdevice(g_hiir_miscdev);
655 osal_destroydev(g_hiir_miscdev);
656
657 osal_del_timer(&g_repkey_timeout_timer);
658 osal_timer_destroy(&g_repkey_timeout_timer);
659
660 osal_atomic_destroy(&g_hiir_s_available);
661 if (g_need_iounmap) {
662 osal_iounmap(((void *)g_ir_reg_base), IR_REG_LENGTH);
663 g_need_iounmap = 0;
664 g_ir_reg_base = NULL;
665 }
666
667 hiir_disable_clock();
668
669 osal_printk("hiir exit ok.\n");
670 }
671