• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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