lin
2025-04-14 e0c033f30287744d392a8d700693b1c0b78afc7c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
/*
 *  * Copyright 2000-2009
 *   * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
 *    *
 *     * SPDX-License-Identifier:    GPL-2.0+
 *     */
 
 
#include <common.h>
#include <asm/io.h>
#include <asm/arch/cpu.h>
#include <asm/arch/gic.h>
#include <sys_config.h>
#include <fdt_support.h>
 
#include "sunxi-ir.h"
#include "asm/arch/timer.h"
 
DECLARE_GLOBAL_DATA_PTR;
 
DEFINE_IR_RAW_EVENT(rawir);
 
struct ir_raw_buffer sunxi_ir_raw;
 
static bool pluse_pre;
static u32 is_receiving;
 
extern struct timer_list ir_timer_t;
 
static inline void ir_reset_rawbuffer(void)
{
   sunxi_ir_raw.dcnt = 0;
}
 
static inline u8 ir_get_data(void)
{
   return (u8)(readl(IR_BASE + IR_RXDAT_REG));
}
 
static inline u32 ir_get_intsta(void)
{
   return readl(IR_BASE + IR_RXINTS_REG);
}
 
static inline void ir_clr_intsta(u32 bitmap)
{
   u32 tmp = readl(IR_BASE + IR_RXINTS_REG);
 
   tmp &= ~0xff;
   tmp |= bitmap & 0xff;
   writel(tmp, IR_BASE + IR_RXINTS_REG);
}
 
static void ir_mode_set(enum ir_mode set_mode)
{
   u32 ctrl_reg = 0;
 
   switch (set_mode) {
   case CIR_MODE_ENABLE:
       ctrl_reg = readl(IR_BASE + IR_CTRL_REG);
       ctrl_reg |= IR_CIR_MODE; /* //(0x3<<4) */
       break;
 
   case IR_MODULE_ENABLE:
       ctrl_reg = readl(IR_BASE + IR_CTRL_REG);
       ctrl_reg |= IR_ENTIRE_ENABLE; /* //(0x3<<0) */
       break;
 
   default:
       return;
   }
 
   writel(ctrl_reg, IR_BASE + IR_CTRL_REG);
}
 
static void ir_sample_config(enum ir_sample_config set_sample)
{
   u32 sample_reg = 0;
 
   sample_reg = readl(IR_BASE + IR_SPLCFG_REG);
 
   switch (set_sample) {
   case IR_SAMPLE_REG_CLEAR:
       sample_reg = 0;
       break;
   case IR_CLK_SAMPLE:
       sample_reg |= IR_SAMPLE_DEV; /* //(0x3<<0) */
       break;
   case IR_FILTER_TH:
       sample_reg |= IR_RXFILT_VAL;
       break;
   case IR_IDLE_TH:
       sample_reg |= IR_RXIDLE_VAL;
       break;
   case IR_ACTIVE_TH:
       sample_reg |= IR_ACTIVE_T;
       sample_reg |= IR_ACTIVE_T_C;
       break;
   default:
       return;
   }
 
   writel(sample_reg, IR_BASE + IR_SPLCFG_REG);
}
 
static void ir_signal_invert(void)
{
   u32 reg_value;
 
   reg_value = 0x1 << 2;
   writel(reg_value, IR_BASE + IR_RXCFG_REG);
}
 
static void ir_irq_config(enum ir_irq_config set_irq)
{
   u32 irq_reg = 0;
 
   switch (set_irq) {
   case IR_IRQ_STATUS_CLEAR:
       writel(0xef, IR_BASE + IR_RXINTS_REG);
       return;
   case IR_IRQ_ENABLE:
       irq_reg = readl(IR_BASE + IR_RXINTE_REG);
       irq_reg |= IR_IRQ_STATUS;
       break;
   case IR_IRQ_FIFO_SIZE:
       irq_reg = readl(IR_BASE + IR_RXINTE_REG);
       irq_reg |= IR_FIFO_32;
       break;
   default:
       return;
   }
 
   writel(irq_reg, IR_BASE + IR_RXINTE_REG);
}
 
static void ir_reg_cfg(void)
{
   /* Enable IR Mode */
   ir_mode_set(CIR_MODE_ENABLE);
   /* Config IR Smaple Register */
   ir_sample_config(IR_SAMPLE_REG_CLEAR);
   ir_sample_config(IR_CLK_SAMPLE);
   ir_sample_config(IR_FILTER_TH); /* Set Filter Threshold */
   ir_sample_config(IR_IDLE_TH); /* Set Idle Threshold */
   ir_sample_config(IR_ACTIVE_TH); /* Set Active Threshold */
   /* Invert Input Signal */
   ir_signal_invert();
   /* Clear All Rx Interrupt Status */
   ir_irq_config(IR_IRQ_STATUS_CLEAR);
   /* Set Rx Interrupt Enable */
   ir_irq_config(IR_IRQ_ENABLE);
   ir_irq_config(IR_IRQ_FIFO_SIZE); /* Rx FIFO Threshold = FIFOsz/2; */
   /* Enable IR Module */
   ir_mode_set(IR_MODULE_ENABLE);
}
 
static int ir_raw_event_store(struct ir_raw_buffer *ir_raw,
                 struct ir_raw_event *ev)
{
   if (ir_raw->dcnt < IR_RAW_BUF_SIZE)
       memcpy(&(ir_raw->raw[ir_raw->dcnt++]), ev, sizeof(*ev));
   else
       print_debug("raw event store full\n");
 
   return 0;
}
 
__weak unsigned long ir_packet_handle(struct ir_raw_buffer *ir_raw)
{
   return 0;
}
 
void ir_recv_irq_service(void *data)
{
   u32 intsta, dcnt;
   u32 i      = 0;
   bool pluse_now = 0;
   u8 reg_data;
 
   print_debug("IR RX IRQ Serve\n");
 
   intsta = ir_get_intsta();
   ir_clr_intsta(intsta);
 
   dcnt = (ir_get_intsta() >> 8) & 0x7f;
   print_debug("receive cnt :%d \n", dcnt);
 
   /* Read FIFO and fill the raw event */
   {
       /* get the data from fifo */
       for (i = 0; i < dcnt; i++) {
           reg_data  = ir_get_data();
           pluse_now = (reg_data & 0x80) ? true : false;
 
           if (pluse_pre == pluse_now) { /* the signal maintian */
               /* the pluse or space lasting*/
               rawir.duration += (u32)(reg_data & 0x7f);
               print_debug("raw: %d:%d \n",
                       (reg_data & 0x80) >> 7,
                       (reg_data & 0x7f));
           } else {
               if (is_receiving) {
                   rawir.duration *= IR_SIMPLE_UNIT;
                   print_debug("pusle :%d, dur: %u ns\n",
                           rawir.pulse,
                           rawir.duration);
                   ir_raw_event_store(&sunxi_ir_raw,
                              &rawir);
                   rawir.pulse    = pluse_now;
                   rawir.duration = (u32)(reg_data & 0x7f);
                   print_debug("raw: %d:%d \n",
                           (reg_data & 0x80) >> 7,
                           (reg_data & 0x7f));
               } else {
                   /* get the first pluse signal */
                   rawir.pulse    = pluse_now;
                   rawir.duration = (u32)(reg_data & 0x7f);
#ifdef CIR_24M_CLK_USED
                   rawir.duration +=
                       ((IR_ACTIVE_T >> 16) + 1) *
                       ((IR_ACTIVE_T_C >> 23) ? 128 :
                                    1);
                   print_debug(
                       "get frist pulse,add head %d !!\n",
                       ((IR_ACTIVE_T >> 16) + 1) *
                           ((IR_ACTIVE_T_C >> 23) ?
                                128 :
                                1));
#endif
                   is_receiving = 1;
                   print_debug("raw: %d:%d \n",
                           (reg_data & 0x80) >> 7,
                           (reg_data & 0x7f));
               }
               pluse_pre = pluse_now;
           }
       }
   }
 
   if (intsta & IR_RXINTS_RXPE) { /* Packet End */
       if (rawir.duration) {
           rawir.duration *= IR_SIMPLE_UNIT;
           print_debug("pusle :%d, dur: %u ns\n", rawir.pulse,
                   rawir.duration);
           ir_raw_event_store(&sunxi_ir_raw, &rawir);
       }
 
       print_debug("handle raw data.\n");
       /* handle ther decoder theread */
       ir_packet_handle(&sunxi_ir_raw);
       ir_reset_rawbuffer();
       is_receiving = 0;
       pluse_pre    = false;
   }
 
   if (intsta & IR_RXINTS_RXOF) { /* FIFO Overflow */
       /* flush rew buffer */
       is_receiving = 0;
       pluse_pre    = false;
       ir_reset_rawbuffer();
       printf("ir_irq_service: Rx FIFO Overflow\n");
   }
 
   print_debug("ir_irq_service: end\n");
   return;
}
 
void rc_keydown(struct ir_raw_buffer *ir_raw, u32 scancode, u8 toggle)
{
   ir_raw->scancode = scancode;
}
 
int ir_setup(void)
{
   if (fdt_set_all_pin("/soc/s_cir", "pinctrl-0")) {
       printf("[ir_boot_para] ir gpio failed\n");
       return -1;
   }
 
   ir_clk_cfg();
   ir_reg_cfg();
 
   ir_reset_rawbuffer();
   irq_install_handler(AW_IRQ_CIR, ir_recv_irq_service, NULL);
   irq_enable(AW_IRQ_CIR);
   return 0;
}
 
void ir_disable(void)
{
   irq_disable(AW_IRQ_CIR);
   irq_free_handler(AW_IRQ_CIR);
}