blob: 4e42e07739d2d3635f3366f831046e977845cf5c [file] [log] [blame]
b.liu68a94c92025-05-24 12:53:41 +08001#include "lynq-irq.h"
2#include "mbtk_type.h"
3#include "mbtk_info_api.h"
4#include "mbtk_log.h"
5
6
7#include <ctype.h>
8#include <stdio.h>
9#include <stdlib.h>
10#include <string.h>
11#include <pthread.h>
12
13// #define _GNU_SOURCE
14
15#include <errno.h>
16#include <fcntl.h>
17#include <limits.h>
18#include <poll.h>
19
20#include <sys/ioctl.h>
21#include <sys/stat.h>
22#include <sys/sysmacros.h>
23#include <sys/types.h>
24#include <unistd.h>
25
26
27struct libirq_info {
28 unsigned int line;
29 unsigned int type;
30 int wake;
31 int fd;
32 irq_handler handler;
33 unsigned int used;
34};
35
36struct libirq_context {
37 unsigned int inited;
38 int fd;
39 pthread_t th;
40 struct libirq_info info[SC_LIBIRQ_MAX];
41};
42static struct libirq_context irq_ctx = {0};
43
44#define irq_init() irq_ctx.inited
45#define line_used(l) irq_ctx.info[l].used
46#define irq_fd(l) irq_ctx.info[l].fd
47#define libirq_fd() irq_ctx.fd
48
49static void *libirq_loop(void *arg)
50{
51 unsigned int int_status = 0;
52 int fd = libirq_fd();
53 int ret = 0;
54 int i;
55
56 while(1) {
57 ret = ioctl(fd, SC_IRQ_GET_STATUS, &int_status);
58 if (ret < 0) {
59 LOGE("libirq_loop get status failed:%d", ret);
60 } else {
61/* printf("libirq_loop get status :0x%x\n", int_status); */
62 }
63
64 for (i=0; i<SC_LIBIRQ_MAX; i++) {
65 if ((int_status & (1<<i)) && line_used(i) && irq_ctx.info[i].handler) {
66 irq_ctx.info[i].handler();
67
68 ret = ioctl(fd, SC_IRQ_CLEAR_STATUS, 0);
69 if (ret < 0) {
70 LOGE("libirq_loop clear status failed:%d", ret);
71 }
72 }
73 }
74 }
75
76 return NULL;
77}
78
79static int libirq_init_thread(void)
80{
81 int ret = 0;
82 pthread_attr_t attribute;
83
84 pthread_attr_init(&attribute);
85 pthread_attr_setstacksize(&attribute, 32*1024);
86
87 ret = pthread_create(&irq_ctx.th, &attribute, libirq_loop, NULL);
88 if(ret) {
89 return ret;
90 }
91
92 return 0;
93}
94
95/*
96 * Add a handler for an interrupt line.
97 *
98 * line : The interrupt line
99 * handler : Function to be called when the IRQ occurs.
100 * trig_type : rising edge or fallling edge
101 *
102 * return 0 if succeed, others failed
103 */
104int sc_irq_install(unsigned int line, irq_handler handler, int trig_type)
105{
106 int fd;
107 struct libirq_info *info;
108 char *usr_name;
109 int ret = 0;
110
111 if ((line >= SC_LIBIRQ_MAX) || (handler == NULL) || (trig_type >= SC_LIBIRQ_TYPE_MAX))
112 return -EINVAL;
113
114 if (line_used(line))
115 return -EEXIST;
116
117 ret = asprintf(&usr_name, "%s%d", SC_IRQ_DEV, line);
118 if (ret < 0) {
119 return -ENOMEM;
120 }
121
122 fd = open(usr_name, O_RDWR);
123 if(fd < 0) {
124 free(usr_name);
125 return -ENODEV;
126 }
127 irq_fd(line) = fd;
128 free(usr_name);
129 info = &irq_ctx.info[line];
130 info->line = line;
131 info->type = trig_type;
132 info->handler = handler;
133
134 if (ioctl(fd, SC_IRQ_INSTALL, trig_type) < 0) {
135 return -EPERM;
136 }
137
138 line_used(line) = 1;
139
140 if (!irq_init()) {
141 ret = libirq_init_thread();
142 if (ret) {
143 LOGE("libirq_init_thread, err:%d", ret);
144 return ret;
145 }
146
147 libirq_fd() = fd;
148 irq_init() = 1;
149 }
150
151 return 0;
152}
153
154/*
155 * free an interrupt allocated with sc_irq_install.
156 *
157 * line : The interrupt line
158 *
159 * return 0 if succeed, others failed
160 */
161int sc_irq_uninstall(unsigned int line)
162{
163 int fd;
164
165 if (line >= SC_LIBIRQ_MAX)
166 return -EINVAL;
167
168 if (!line_used(line))
169 return -ENODEV;
170
171 if (ioctl(irq_fd(line), SC_IRQ_UNINSTALL, 0) < 0) {
172 return -EPERM;
173 }
174
175 fd = libirq_fd();
176 if (fd)
177 close(fd);
178
179 line_used(line) = 0;
180
181 return 0;
182}
183
184/*
185 * set the irq trigger type for an irq.
186 *
187 * line : The interrupt line
188 * trig_type : edge or level type
189 *
190 * return 0 if succeed, others failed
191 */
192int sc_irq_set_type(unsigned int line, int trig_type)
193{
194 struct libirq_info *info;
195
196 if ((line >= SC_LIBIRQ_MAX) || (trig_type >= SC_LIBIRQ_TYPE_MAX))
197 return -EINVAL;
198
199 if (!line_used(line))
200 return -EEXIST;
201
202 info = &irq_ctx.info[line];
203 //if (info->type != trig_type) {
204 if (ioctl(irq_fd(line), SC_IRQ_SET_TYPE, trig_type) < 0) {
205 return -EPERM;
206 }
207 //}
208
209 info->type = trig_type;
210
211 return 0;
212}
213
214/*
215 * get the irq trigger type for an irq.
216 *
217 * line : The interrupt line
218 * trig_type : edge or level type
219 *
220 * return 0 if succeed, others failed
221 */
222int sc_irq_get_type(unsigned int line, int *trig_type)
223{
224 struct libirq_info *info;
225
226 if ((line >= SC_LIBIRQ_MAX) || !trig_type)
227 return -EINVAL;
228
229 if (!line_used(line))
230 return -EEXIST;
231
232 info = &irq_ctx.info[line];
233 *trig_type = info->type;
234
235 return 0;
236}
237
238/*
239 * control irq power management wakeup.
240 *
241 * line : The interrupt line
242 * en : enable/disable power management wakeup
243 *
244 * return 0 if succeed, others failed
245 */
246int sc_irq_set_wake(unsigned int line, int en)
247{
248 struct libirq_info *info;
249
250 if (line >= SC_LIBIRQ_MAX)
251 return -EINVAL;
252
253 if (!line_used(line))
254 return -EEXIST;
255
256 info = &irq_ctx.info[line];
257 if (info->wake != en) {
258 if (ioctl(irq_fd(line), SC_IRQ_SET_WAKE, en) < 0) {
259 return -EPERM;
260 }
261 }
262
263 info->wake = en;
264
265 return 0;
266}
267
268/*
269 * get the irq awake status for an irq.
270 *
271 * line : The interrupt line
272 * en : enable/disable power management wakeup
273 *
274 * return 0 if succeed, others failed
275 */
276int sc_irq_get_wake(unsigned int line, int *en)
277{
278 struct libirq_info *info;
279 unsigned int wake;
280
281 if (line >= SC_LIBIRQ_MAX)
282 return -EINVAL;
283
284 if (!line_used(line))
285 return -EEXIST;
286
287 if (ioctl(irq_fd(line), SC_IRQ_GET_WAKE, &wake) < 0) {
288 return -EPERM;
289 }
290
291 info = &irq_ctx.info[line];
292 info->wake = wake;
293 *en = wake;
294
295 return 0;
296}
297
298
299
300
301/*****************************************
302* @brief:lynq_irq_install
303* @param count [IN]:2
304* @param sum [OUT]:NA
305* @return :success 0, failed other
306* @todo:NA
307* @see:NA
308* @warning:NA
309******************************************/
310
311int lynq_irq_install(int line, irq_handler irq_test_handler, trig_type_e trig_type)
312{
313 int ret;
314
315 if (trig_type != 0 && trig_type != 1)
316 {
317 LOGE("lynq_irq_install error trig_type:%d", trig_type);
318 return -1;
319 }
320
321 line = line-117;
322 if (line < 0)
323 {
324 LOGE("lynq_irq_install error line:%d", line);
325 return -1;
326 }
327
328 ret = sc_irq_install(line, irq_test_handler, trig_type);
329 if (ret != 0)
330 {
331 LOGE("do_install_irq failed, ret:%d", ret);
332 return ret;
333 }
334 return 0;
335}
336
337
338/*****************************************
339* @brief:lynq_irq_uninstall
340* @param count [IN]:2
341* @param sum [OUT]:NA
342* @return :success 0, failed other
343* @todo:NA
344* @see:NA
345* @warning:NA
346******************************************/
347
348int lynq_irq_uninstall(int line)
349{
350 int ret;
351
352 line = line-117;
353 ret = sc_irq_uninstall(line);
354 if (ret != 0)
355 {
356 LOGE("unistall failed, ret:%d", ret);
357 return ret;
358 }
359 LOGI("uninstall irq(%d) ok", line);
360 return 0;
361}
362
363
364/*****************************************
365* @brief:lynq_irq_set_type
366* @param count [IN]:2
367* @param sum [OUT]:NA
368* @return :success 0, failed other
369* @todo:NA
370* @see:NA
371* @warning:NA
372******************************************/
373int lynq_irq_set_type(int line, int trig_type)
374{
375 int ret;
376
377 if (trig_type != 0 && trig_type != 1)
378 {
379 LOGE("lynq_irq_set_type error trig_type:%d", trig_type);
380 return -1;
381 }
382
383 line = line-117;
384 ret = sc_irq_set_type(line, trig_type);
385 if (ret != 0)
386 {
387 LOGE("set_type failed, ret:%d", ret);
388 return ret;
389 }
390 return 0;
391
392}
393
394/*****************************************
395* @brief:lynq_irq_get_type
396* @param count [IN]:1
397* @param sum [OUT]:NA
398* @return :success >= 0, failed other
399* @todo:NA
400* @see:NA
401* @warning:NA
402******************************************/
403int lynq_irq_get_type(int line)
404{
405 int ret;
406 int trig_type;
407
408 line = line-117;
409 ret = sc_irq_get_type(line, &trig_type);
410 if (ret != 0)
411 {
412 LOGE("get_type failed, ret:%d", ret);
413 return ret;
414 }
415 LOGI("get_type readback(%d)", trig_type);
416 return trig_type;
417}
418
419
420/*****************************************
421* @brief:lynq_irq_set_wake
422* @param count [IN]:2
423* @param sum [OUT]:NA
424* @return :success 0, failed other
425* @todo:NA
426* @see:NA
427* @warning:NA
428******************************************/
429int lynq_irq_set_wake(int line, int en)
430{
431 int ret;
432
433 if((en != 0) && (en != 1))
434 {
435 LOGE("wake_state is not 0 or 1");
436 return -1;
437 }
438
439 line = line-117;
440 ret = sc_irq_set_wake(line, en);
441 if (ret != 0)
442 {
443 LOGE("set_wake failed, ret:%d", ret);
444 return ret;
445 }
446 return 0;
447}
448
449/*****************************************
450* @brief:lynq_irq_get_wake
451* @param count [IN]:1
452* @param sum [OUT]:NA
453* @return :success >= 0, failed other
454* @todo:NA
455* @see:NA
456* @warning:NA
457******************************************/
458int lynq_irq_get_wake(int line)
459{
460 int ret;
461 int en;
462
463 line = line-117;
464 ret = sc_irq_get_wake(line, &en);
465 if (ret != 0)
466 {
467 LOGE("get_wake failed, ret:%d", ret);
468 return ret;
469 }
470 LOGI("get_wake readback(%d)", en);
471 return en;
472}
473
474
475