huangcm
2025-04-07 511b111543524704f6182b374e489f5d0e51db8c
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
/*
 *  * Copyright 2000-2009
 *   * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
 *    *
 *     * SPDX-License-Identifier:    GPL-2.0+
 *     */
 
#ifndef __SUNXI_IR_H__
#define __SUNXI_IR_H__
 
extern void ir_clk_cfg(void);
 
#define MAX_IR_ADDR_NUM (32)
 
#define IR_DETECT_NULL (1)
#define IR_DETECT_OK (2)
#define IR_DETECT_END (3)
 
/* //#define SUNXI_IR_DEBUG */
 
#ifdef SUNXI_IR_DEBUG
#define print_debug(fmt, ...) printf(fmt, ##__VA_ARGS__)
#else
#define print_debug(fmt, ...)
#endif
 
#define CONFIG_FPGA_V4_PLATFORM
 
/* //Registers */
#define IR_REG(x) (x)
#define IR_CTRL_REG IR_REG(0x00) /* //IR Control */
#define IR_RXCFG_REG IR_REG(0x10) /* //Rx Config */
#define IR_RXDAT_REG IR_REG(0x20) /* //Rx Data */
#define IR_RXINTE_REG IR_REG(0x2C) /* //Rx Interrupt Enable */
#define IR_RXINTS_REG IR_REG(0x30) /* //Rx Interrupt Status */
#define IR_SPLCFG_REG IR_REG(0x34) /* //IR Sample Config */
 
#define IR_FIFO_SIZE (64) /* 64Bytes */
#if (defined CONFIG_FPGA_V4_PLATFORM) || (defined CONFIG_FPGA_V7_PLATFORM)
#define CIR_24M_CLK_USED
#endif
 
#ifdef CIR_24M_CLK_USED
#define IR_SIMPLE_UNIT (21333) /* simple in ns */
#define IR_CLK (24000000) /* fpga clk output is fixed */
#define IR_CIR_MODE (0x3 << 4) /* CIR mode enable */
#define IR_ENTIRE_ENABLE (0x3 << 0) /* IR entire enable */
#define IR_SAMPLE_DEV (0x3 << 0) /* 24MHz/512 =46875Hz (21333ns) */
#define IR_FIFO_32 (((IR_FIFO_SIZE >> 1) - 1) << 8)
#define IR_IRQ_STATUS ((0x1 << 4) | 0x3)
#else
#define IR_SIMPLE_UNIT (32000) /* simple in ns */
#define IR_CLK (8000000)
#define IR_CIR_MODE (0x3 << 4) /* CIR mode enable */
#define IR_ENTIRE_ENABLE (0x3 << 0) /* IR entire enable */
#define IR_SAMPLE_DEV (0x2 << 0) /* 4MHz/256 =31250Hz (32000ns) */
#define IR_FIFO_32 (((IR_FIFO_SIZE >> 1) - 1) << 8)
#define IR_IRQ_STATUS ((0x1 << 4) | 0x3)
#endif
 
/* //Bit Definition of IR_RXINTS_REG Register */
#define IR_RXINTS_RXOF (0x1 << 0) /* Rx FIFO Overflow */
#define IR_RXINTS_RXPE (0x1 << 1) /* Rx Packet End */
#define IR_RXINTS_RXDA (0x1 << 4) /* Rx FIFO Data Available */
#ifdef CIR_24M_CLK_USED
#define IR_RXFILT_VAL                                                          \
   (((16) & 0x3f) << 2) /* Filter Threshold = 16*21.3 = ~341us < 500us */
#define IR_RXIDLE_VAL                                                          \
   (((5) & 0xff)                                                          \
    << 8) /* Idle Threshold = (5+1)*128*21.3 = ~16.4ms > 9ms */
#define IR_ACTIVE_T ((0 & 0xff) << 16) /* Active Threshold */
#define IR_ACTIVE_T_C ((1 & 0xff) << 23) /* Active Threshold */
#else
#define IR_RXFILT_VAL                                                          \
   (((12) & 0x3f) << 2) /* Filter Threshold = 12*32 = ~384us < 500us */
#define IR_RXIDLE_VAL                                                          \
   (((2) & 0xff) << 8) /* Idle Threshold = (2+1)*128*32 = ~23.8ms > 9ms */
#define IR_ACTIVE_T ((99 & 0xff) << 16) /* Active Threshold */
#define IR_ACTIVE_T_C ((0 & 0xff) << 23) /* Active Threshold */
#endif
 
enum ir_mode {
   CIR_MODE_ENABLE,
   IR_MODULE_ENABLE,
};
 
enum ir_sample_config {
   IR_SAMPLE_REG_CLEAR,
   IR_CLK_SAMPLE,
   IR_FILTER_TH,
   IR_IDLE_TH,
   IR_ACTIVE_TH,
};
 
enum ir_irq_config {
   IR_IRQ_STATUS_CLEAR,
   IR_IRQ_ENABLE,
   IR_IRQ_FIFO_SIZE,
};
 
enum { IR_SUPLY_DISABLE = 0,
       IR_SUPLY_ENABLE,
};
 
struct ir_raw_event {
   union {
       u32 duration;
       struct {
           u32 carrier;
           u8 duty_cycle;
       };
   };
   unsigned pulse;
   unsigned reset;
   unsigned timeout;
   unsigned carrier_report;
};
 
#define DEFINE_IR_RAW_EVENT(event)                                             \
   struct ir_raw_event event = { {.duration = 0 },                        \
                     .pulse      = 0,                     \
                     .reset      = 0,                     \
                     .timeout    = 0,                     \
                     .carrier_report = 0 }
 
static inline void init_ir_raw_event(struct ir_raw_event *ev)
{
   memset(ev, 0, sizeof(*ev));
}
 
struct nec_dec {
   int state;
   unsigned count;
   u32 bits;
   bool is_nec_x;
   bool necx_repeat;
   bool curt_repeat;
};
 
struct sunxi_ir_data {
   u32 ir_addr_cnt;
   u32 ir_recoverykey[MAX_IR_ADDR_NUM];
   u32 ir_addr[MAX_IR_ADDR_NUM];
};
 
struct ir_raw_buffer {
   unsigned long dcnt; /*Packet Count*/
   struct nec_dec nec;
   u32 scancode;
#define IR_RAW_BUF_SIZE 128
   struct ir_raw_event raw[IR_RAW_BUF_SIZE];
};
 
/* macros for IR decoders */
static inline bool geq_margin(unsigned d1, unsigned d2, unsigned margin)
{
   return d1 > (d2 - margin);
}
 
static inline bool eq_margin(unsigned d1, unsigned d2, unsigned margin)
{
   return (bool)((d1 > (d2 - margin)) && (d1 < (d2 + margin)));
}
 
static inline bool is_transition(struct ir_raw_event *x, struct ir_raw_event *y)
{
   return x->pulse != y->pulse;
}
 
static inline void decrease_duration(struct ir_raw_event *ev, unsigned duration)
{
   if (duration > ev->duration)
       ev->duration = 0;
   else
       ev->duration -= duration;
}
 
/* Returns true if event is normal pulse/space event */
static inline bool is_timing_event(struct ir_raw_event ev)
{
   return !ev.carrier_report && !ev.reset;
}
 
#define TO_US(duration) DIV_ROUND_CLOSEST((duration), 1000)
#define TO_STR(is_pulse) ((is_pulse) ? "pulse" : "space")
 
void rc_keydown(struct ir_raw_buffer *ir_raw, u32 scancode, u8 toggle);
int ir_setup(void);
void ir_disable(void);
 
#endif /* end of __SUNXI_IR_H__ */