1 /* Copyright (c) 2019-2025 Allwinner Technology Co., Ltd. ALL rights reserved.
2 
3  * Allwinner is a trademark of Allwinner Technology Co.,Ltd., registered in
4  * the the People's Republic of China and other countries.
5  * All Allwinner Technology Co.,Ltd. trademarks are used with permission.
6 
7  * DISCLAIMER
8  * THIRD PARTY LICENCES MAY BE REQUIRED TO IMPLEMENT THE SOLUTION/PRODUCT.
9  * IF YOU NEED TO INTEGRATE THIRD PARTY¡¯S TECHNOLOGY (SONY, DTS, DOLBY, AVS OR MPEGLA, ETC.)
10  * IN ALLWINNERS¡¯SDK OR PRODUCTS, YOU SHALL BE SOLELY RESPONSIBLE TO OBTAIN
11  * ALL APPROPRIATELY REQUIRED THIRD PARTY LICENCES.
12  * ALLWINNER SHALL HAVE NO WARRANTY, INDEMNITY OR OTHER OBLIGATIONS WITH RESPECT TO MATTERS
13  * COVERED UNDER ANY REQUIRED THIRD PARTY LICENSE.
14  * YOU ARE SOLELY RESPONSIBLE FOR YOUR USAGE OF THIRD PARTY¡¯S TECHNOLOGY.
15 
16 
17  * THIS SOFTWARE IS PROVIDED BY ALLWINNER"AS IS" AND TO THE MAXIMUM EXTENT
18  * PERMITTED BY LAW, ALLWINNER EXPRESSLY DISCLAIMS ALL WARRANTIES OF ANY KIND,
19  * WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING WITHOUT LIMITATION REGARDING
20  * THE TITLE, NON-INFRINGEMENT, ACCURACY, CONDITION, COMPLETENESS, PERFORMANCE
21  * OR MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
22  * IN NO EVENT SHALL ALLWINNER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25  * LOSS OF USE, DATA, OR PROFITS, OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
27  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
29  * OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31 #include <interrupt.h>
32 #include <hal_clk.h>
33 #include <sunxi_hal_ir.h>
34 #include <init.h>
35 
36 
37 #define IRADC_ERR(fmt, arg...) printf("%s()%d " fmt, __func__, __LINE__, ##arg)
38 #define IRADC_INIT(fmt, arg...) printf("%s()%d " fmt, __func__, __LINE__, ##arg)
39 
40 #ifdef IRADC_DEBUG
41 #define IR_INFO(fmt, arg...) printf("%s()%d " fmt, __func__, __LINE__, ##arg)
42 #define IR_INFO_IRQ(fmt, arg...) __log("%s()%d " fmt, __func__, __LINE__, ##arg)
43 #else
44 #define IR_INFO(fmt, arg...)                                                  \
45     do {                                                                   \
46     } while (0);
47 #define IR_INFO_IRQ(fmt, arg...)                                                  \
48     do {                                                                   \
49     } while (0);
50 #endif
51 
52 hal_ir_t hal_ir;
53 
ir_get_data(uint32_t reg_base)54 static inline u8 ir_get_data(uint32_t reg_base)
55 {
56     return (u8)(hal_readl(reg_base + IR_RXDAT_REG) & 0xff);
57 }
58 
ir_get_intsta(uint32_t reg_base)59 static inline uint32_t ir_get_intsta(uint32_t reg_base)
60 {
61     return hal_readl(reg_base + IR_RXINTS_REG);
62 }
63 
ir_clr_intsta(uint32_t reg_base,uint32_t bitmap)64 static inline void ir_clr_intsta(uint32_t reg_base, uint32_t bitmap)
65 {
66     uint32_t tmp = hal_readl(reg_base + IR_RXINTS_REG);
67 
68     tmp &= ~0xff;
69     tmp |= bitmap & 0xff;
70     hal_writel(tmp, reg_base + IR_RXINTS_REG);
71 }
72 
ir_handler(int irq,void * dev)73 static irqreturn_t ir_handler(int irq, void *dev)
74 {
75     hal_ir_t *ir = (hal_ir_t *)dev;
76     uint32_t intsta, dcnt;
77     uint32_t i = 0;
78     uint32_t reg_data = 0;
79 
80     IR_INFO_IRQ("IR RX IRQ Serve\n");
81 
82     intsta = ir_get_intsta(ir->reg_base);
83     ir_clr_intsta(ir->reg_base, intsta);
84 
85     /* get the count of signal */
86     dcnt = (intsta >> 8) & 0x7f;
87     IR_INFO_IRQ("receive cnt :%d\n", dcnt);
88     /* Read FIFO and fill the raw event */
89     for (i = 0; i < dcnt; i++)
90     {
91         /* get the data from fifo */
92         reg_data = ir_get_data(ir->reg_base);
93         ir->callback(IR_RXINTS_RXDA, reg_data);
94     }
95 
96     if (intsta & IR_RXINTS_RXPE)
97     {
98         /* The last pulse can not call ir_raw_event_store() since miss
99          * invert level in above, manu call
100          */
101         ir->callback(IR_RXINTS_RXPE, reg_data);
102     }
103 
104     if (intsta & IR_RXINTS_RXOF)
105     {
106         /* FIFO Overflow */
107         ir->callback(IR_RXINTS_RXPE, reg_data);
108     }
109 
110     return IRQ_HANDLED;
111 }
112 
ir_mode_set(uint32_t reg_base,enum ir_mode set_mode)113 static void ir_mode_set(uint32_t reg_base, enum ir_mode set_mode)
114 {
115     uint32_t ctrl_reg = 0;
116 
117     switch (set_mode)
118     {
119         case CIR_MODE_ENABLE:
120             ctrl_reg = hal_readl(reg_base + IR_CTRL_REG);
121             ctrl_reg |= IR_CIR_MODE;
122             break;
123         case IR_MODULE_ENABLE:
124             ctrl_reg = hal_readl(reg_base + IR_CTRL_REG);
125             ctrl_reg |= IR_ENTIRE_ENABLE;
126             break;
127         case IR_BOTH_PULSE_MODE:
128             ctrl_reg = hal_readl(reg_base + IR_CTRL_REG);
129             ctrl_reg |= IR_BOTH_PULSE;
130             break;
131         case IR_LOW_PULSE_MODE:
132             ctrl_reg = hal_readl(reg_base + IR_CTRL_REG);
133             ctrl_reg |= IR_LOW_PULSE;
134             break;
135         case IR_HIGH_PULSE_MODE:
136             ctrl_reg = hal_readl(reg_base + IR_CTRL_REG);
137             ctrl_reg |= IR_HIGH_PULSE;
138             break;
139         default:
140             IRADC_ERR("ir_mode_set error!!\n");
141             return;
142     }
143     hal_writel(ctrl_reg, reg_base + IR_CTRL_REG);
144 }
145 
ir_sample_config(uint32_t reg_base,enum ir_sample_config set_sample)146 static void ir_sample_config(uint32_t reg_base,
147                              enum ir_sample_config set_sample)
148 {
149     uint32_t sample_reg = 0;
150 
151     sample_reg = hal_readl(reg_base + IR_SPLCFG_REG);
152 
153     switch (set_sample)
154     {
155         case IR_SAMPLE_REG_CLEAR:
156             sample_reg = 0;
157             break;
158         case IR_CLK_SAMPLE:
159             sample_reg |= IR_SAMPLE_DEV;
160             break;
161         case IR_FILTER_TH_NEC:
162             sample_reg |= IR_RXFILT_VAL;
163             break;
164         case IR_FILTER_TH_RC5:
165             sample_reg |= IR_RXFILT_VAL_RC5;
166             break;
167         case IR_IDLE_TH:
168             sample_reg |= IR_RXIDLE_VAL;
169             break;
170         case IR_ACTIVE_TH:
171             sample_reg |= IR_ACTIVE_T;
172             sample_reg |= IR_ACTIVE_T_C;
173             break;
174         case IR_ACTIVE_TH_SAMPLE:
175             sample_reg |= IR_ACTIVE_T_SAMPLE;
176             sample_reg &= ~IR_ACTIVE_T_C;
177             break;
178         default:
179             IRADC_ERR("config err !\n");;
180     }
181     hal_writel(sample_reg, reg_base + IR_SPLCFG_REG);
182 }
183 
ir_signal_invert(uint32_t reg_base)184 static void ir_signal_invert(uint32_t reg_base)
185 {
186     uint32_t reg_value;
187 
188     reg_value = 0x1 << 2;
189     hal_writel(reg_value, reg_base + IR_RXCFG_REG);
190 }
191 
ir_irq_config(uint32_t reg_base,enum ir_irq_config set_irq)192 static void ir_irq_config(uint32_t reg_base, enum ir_irq_config set_irq)
193 {
194     uint32_t irq_reg = 0;
195 
196     switch (set_irq)
197     {
198         case IR_IRQ_STATUS_CLEAR:
199             hal_writel(0xef, reg_base + IR_RXINTS_REG);
200             return;
201         case IR_IRQ_ENABLE:
202             irq_reg = hal_readl(reg_base + IR_RXINTE_REG);
203             irq_reg |= IR_IRQ_STATUS;
204             break;
205         case IR_IRQ_FIFO_SIZE:
206             irq_reg = hal_readl(reg_base + IR_RXINTE_REG);
207             irq_reg |= IR_FIFO_20;
208             break;
209         default:
210             return;
211     }
212     hal_writel(irq_reg, reg_base + IR_RXINTE_REG);
213 }
214 
hal_ir_reg_cfg(uint32_t reg_base)215 static void hal_ir_reg_cfg(uint32_t reg_base)
216 {
217     /* Enable IR Mode */
218     ir_mode_set(reg_base, CIR_MODE_ENABLE);
219     /* Config IR Smaple Register */
220     ir_sample_config(reg_base, IR_SAMPLE_REG_CLEAR);
221     ir_sample_config(reg_base, IR_CLK_SAMPLE);
222     ir_sample_config(reg_base, IR_IDLE_TH); /* Set Idle Threshold */
223 
224     /* rc5 Set Active Threshold */
225     ir_sample_config(reg_base, IR_ACTIVE_TH_SAMPLE);
226     ir_sample_config(reg_base, IR_FILTER_TH_NEC); /* Set Filter Threshold */
227     ir_signal_invert(reg_base);
228     /* Clear All Rx Interrupt Status */
229     ir_irq_config(reg_base, IR_IRQ_STATUS_CLEAR);
230     /* Set Rx Interrupt Enable */
231     ir_irq_config(reg_base, IR_IRQ_ENABLE);
232 
233     /* Rx FIFO Threshold = FIFOsz/2; */
234     ir_irq_config(reg_base, IR_IRQ_FIFO_SIZE);
235     /* for NEC decode which start with high level in the header so should
236      * use IR_HIGH_PULSE_MODE mode, but some ICs don't support this function
237      * therefor use IR_BOTH_PULSE_MODE mode as default
238      */
239     ir_mode_set(reg_base, IR_BOTH_PULSE_MODE);
240     /* Enable IR Module */
241     ir_mode_set(reg_base, IR_MODULE_ENABLE);
242 }
243 
244 
hal_ir_clk_init(void)245 static hal_ir_status_t hal_ir_clk_init(void)
246 {
247     int ret;
248     int32_t rate;
249     hal_clk_id_t mclk = HAL_CLK_PERIPH_IRTX;
250 
251     ret = hal_clk_set_parent(mclk, HAL_CLK_SRC_HOSC24M);
252     if (ret)
253     {
254         IRADC_ERR("[ir] clk set parent failed! return %d\n", ret);
255         return IR_CLK_ERR;
256     }
257 
258     rate = hal_clk_round_rate(mclk, IR_CLK);
259     if (rate < 0)
260     {
261         IRADC_ERR("[ir] clk round rate failed! return %ld\n", rate);
262         return IR_CLK_ERR;
263     }
264 
265     ret = hal_clk_set_rate(mclk, rate);
266     if (ret)
267     {
268         IRADC_ERR("[ir] clk set rate failed! return %d\n", ret);
269         return IR_CLK_ERR;
270     }
271 
272     rate = hal_clk_get_rate(mclk);
273     if (rate < 0)
274     {
275         IRADC_ERR("[ir] clk get rate failed! return %ld\n", rate);
276         return IR_CLK_ERR;
277     }
278 
279     ret = hal_clock_enable(mclk);
280     if (ret)
281     {
282         IRADC_ERR("[ir] couldn't enable mlck! return %d\n", ret);
283         return IR_CLK_ERR;
284     }
285 
286     return IR_OK;
287 }
288 
hal_ir_pinctrl_init(hal_ir_t * ir)289 static hal_ir_status_t hal_ir_pinctrl_init(hal_ir_t *ir)
290 {
291     int ret;
292 
293     ret = hal_gpio_pinmux_set_function(ir->pin, ir->pin_mux);
294     if (ret)
295     {
296         IRADC_ERR(
297             "[ir] PIN set function failed! return %d\n", ret);
298         return IR_PIN_ERR;
299     }
300     ret = hal_gpio_set_driving_level(ir->pin, ir->pin_drv);
301     if (ret)
302     {
303         IRADC_ERR(
304             "[ir] PIN set driving level failed! return %d\n", ret);
305         return IR_PIN_ERR;
306     }
307     return IR_OK;
308 }
309 
hal_ir_register_callback(ir_callback_t callback)310 int hal_ir_register_callback(ir_callback_t callback)
311 {
312     hal_ir_t *ir = &hal_ir;
313     ir->callback = callback;
314     return IR_OK;
315 }
316 
hal_ir_init(void)317 int hal_ir_init(void)
318 {
319     hal_ir_t *ir = &hal_ir;
320 
321     ir->reg_base = SUNXI_IRADC_PBASE;
322     ir->irq_num = SUNXI_IRQ_IRADC;
323     ir->pin = IRADC_PIN;
324     ir->pin_drv = IR_DRVSEL;
325     ir->pin_mux = IR_MUXSEL;
326     IRADC_INIT("ir init\n");
327 
328     if (hal_ir_pinctrl_init(ir))
329     {
330         IRADC_ERR("ir init pinctrl error\n");
331         return IR_PIN_ERR;
332     }
333 
334     if (hal_ir_clk_init())
335     {
336         IRADC_ERR("ir init clk error\n");
337         return IR_CLK_ERR;
338     }
339 
340     hal_ir_reg_cfg(ir->reg_base);
341     if (request_irq(ir->irq_num, ir_handler, 0, "ir", ir))
342     {
343         IRADC_ERR("ir request irq failed\n");
344         return IR_IRQ_ERR;
345     }
346     enable_irq(ir->irq_num);
347 
348     return IR_OK;
349 }
350