blob: c6050aee62e823236e79837d4906af6f8e0e7985 [file] [log] [blame]
#include "lynq-irq.h"
#include "mbtk_type.h"
#include "mbtk_info_api.h"
#include "mbtk_log.h"
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#define _GNU_SOURCE
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <poll.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/sysmacros.h>
#include <sys/types.h>
#include <unistd.h>
struct libirq_info {
unsigned int line;
unsigned int type;
int wake;
int fd;
irq_handler handler;
unsigned int used;
};
struct libirq_context {
unsigned int inited;
int fd;
pthread_t th;
struct libirq_info info[SC_LIBIRQ_MAX];
};
static struct libirq_context irq_ctx = {0};
#define irq_init() irq_ctx.inited
#define line_used(l) irq_ctx.info[l].used
#define irq_fd(l) irq_ctx.info[l].fd
#define libirq_fd() irq_ctx.fd
static void *libirq_loop(void *arg)
{
unsigned int int_status = 0;
int fd = libirq_fd();
int ret = 0;
int i;
while(1) {
ret = ioctl(fd, SC_IRQ_GET_STATUS, &int_status);
if (ret < 0) {
LOGE("libirq_loop get status failed:%d", ret);
} else {
/* printf("libirq_loop get status :0x%x\n", int_status); */
}
for (i=0; i<SC_LIBIRQ_MAX; i++) {
if ((int_status & (1<<i)) && line_used(i) && irq_ctx.info[i].handler) {
irq_ctx.info[i].handler();
ret = ioctl(fd, SC_IRQ_CLEAR_STATUS, 0);
if (ret < 0) {
LOGE("libirq_loop clear status failed:%d", ret);
}
}
}
}
return NULL;
}
static int libirq_init_thread(void)
{
int ret = 0;
pthread_attr_t attribute;
pthread_attr_init(&attribute);
pthread_attr_setstacksize(&attribute, 32*1024);
ret = pthread_create(&irq_ctx.th, &attribute, libirq_loop, NULL);
if(ret) {
return ret;
}
return 0;
}
/*
* Add a handler for an interrupt line.
*
* line : The interrupt line
* handler : Function to be called when the IRQ occurs.
* trig_type : rising edge or fallling edge
*
* return 0 if succeed, others failed
*/
int sc_irq_install(unsigned int line, irq_handler handler, int trig_type)
{
int fd;
struct libirq_info *info;
char *usr_name;
int ret = 0;
if ((line >= SC_LIBIRQ_MAX) || (handler == NULL) || (trig_type >= SC_LIBIRQ_TYPE_MAX))
return -EINVAL;
if (line_used(line))
return -EEXIST;
ret = asprintf(&usr_name, "%s%d", SC_IRQ_DEV, line);
if (ret < 0) {
return -ENOMEM;
}
fd = open(usr_name, O_RDWR);
if(fd < 0) {
free(usr_name);
return -ENODEV;
}
irq_fd(line) = fd;
free(usr_name);
info = &irq_ctx.info[line];
info->line = line;
info->type = trig_type;
info->handler = handler;
if (ioctl(fd, SC_IRQ_INSTALL, trig_type) < 0) {
return -EPERM;
}
line_used(line) = 1;
if (!irq_init()) {
ret = libirq_init_thread();
if (ret) {
LOGE("libirq_init_thread, err:%d", ret);
return ret;
}
libirq_fd() = fd;
irq_init() = 1;
}
return 0;
}
/*
* free an interrupt allocated with sc_irq_install.
*
* line : The interrupt line
*
* return 0 if succeed, others failed
*/
int sc_irq_uninstall(unsigned int line)
{
int fd;
if (line >= SC_LIBIRQ_MAX)
return -EINVAL;
if (!line_used(line))
return -ENODEV;
if (ioctl(irq_fd(line), SC_IRQ_UNINSTALL, 0) < 0) {
return -EPERM;
}
fd = libirq_fd();
if (fd)
close(fd);
line_used(line) = 0;
return 0;
}
/*
* set the irq trigger type for an irq.
*
* line : The interrupt line
* trig_type : edge or level type
*
* return 0 if succeed, others failed
*/
int sc_irq_set_type(unsigned int line, int trig_type)
{
struct libirq_info *info;
if ((line >= SC_LIBIRQ_MAX) || (trig_type >= SC_LIBIRQ_TYPE_MAX))
return -EINVAL;
if (!line_used(line))
return -EEXIST;
info = &irq_ctx.info[line];
if (info->type != trig_type) {
if (ioctl(irq_fd(line), SC_IRQ_SET_TYPE, trig_type) < 0) {
return -EPERM;
}
}
info->type = trig_type;
return 0;
}
/*
* get the irq trigger type for an irq.
*
* line : The interrupt line
* trig_type : edge or level type
*
* return 0 if succeed, others failed
*/
int sc_irq_get_type(unsigned int line, int *trig_type)
{
struct libirq_info *info;
if ((line >= SC_LIBIRQ_MAX) || !trig_type)
return -EINVAL;
if (!line_used(line))
return -EEXIST;
info = &irq_ctx.info[line];
*trig_type = info->type;
return 0;
}
/*
* control irq power management wakeup.
*
* line : The interrupt line
* en : enable/disable power management wakeup
*
* return 0 if succeed, others failed
*/
int sc_irq_set_wake(unsigned int line, int en)
{
struct libirq_info *info;
if (line >= SC_LIBIRQ_MAX)
return -EINVAL;
if (!line_used(line))
return -EEXIST;
info = &irq_ctx.info[line];
if (info->wake != en) {
if (ioctl(irq_fd(line), SC_IRQ_SET_WAKE, en) < 0) {
return -EPERM;
}
}
info->wake = en;
return 0;
}
/*
* get the irq awake status for an irq.
*
* line : The interrupt line
* en : enable/disable power management wakeup
*
* return 0 if succeed, others failed
*/
int sc_irq_get_wake(unsigned int line, int *en)
{
struct libirq_info *info;
unsigned int wake;
if (line >= SC_LIBIRQ_MAX)
return -EINVAL;
if (!line_used(line))
return -EEXIST;
if (ioctl(irq_fd(line), SC_IRQ_GET_WAKE, &wake) < 0) {
return -EPERM;
}
info = &irq_ctx.info[line];
info->wake = wake;
*en = wake;
return 0;
}
/*****************************************
* @brief:lynq_irq_install
* @param count [IN]:2
* @param sum [OUT]:NA
* @return :success 0, failed other
* @todo:NA
* @see:NA
* @warning:NA
******************************************/
int lynq_irq_install(int line, irq_handler irq_test_handler, trig_type_e trig_type)
{
int ret;
if(trig_type < 0)
{
return -1;
}
#if defined(MBTK_PROJECT_T108)
if (trig_type != 0 && trig_type != 1)
{
LOGE("lynq_irq_install error trig_type:%d", trig_type);
return -1;
}
line = line-117;
if (line < 0)
{
LOGE("lynq_irq_install error line:%d", line);
return -1;
}
#endif
ret = sc_irq_install(line, irq_test_handler, trig_type);
if (ret != 0)
{
LOGE("do_install_irq failed, ret:%d", ret);
return ret;
}
return 0;
}
/*****************************************
* @brief:lynq_irq_uninstall
* @param count [IN]:2
* @param sum [OUT]:NA
* @return :success 0, failed other
* @todo:NA
* @see:NA
* @warning:NA
******************************************/
int lynq_irq_uninstall(int line)
{
#if defined(MBTK_PROJECT_T108)
line = line-117;
#endif
int ret;
ret = sc_irq_uninstall(line);
if (ret != 0)
{
LOGE("unistall failed, ret:%d", ret);
return ret;
}
LOGI("uninstall irq(%d) ok", line);
return 0;
}
/*****************************************
* @brief:lynq_irq_set_type
* @param count [IN]:2
* @param sum [OUT]:NA
* @return :success 0, failed other
* @todo:NA
* @see:NA
* @warning:NA
******************************************/
int lynq_irq_set_type(int line, int trig_type)
{
#if defined(MBTK_PROJECT_T108)
line = line-117;
if (trig_type != 0 && trig_type != 1)
{
LOGE("lynq_irq_set_type error trig_type:%d", trig_type);
return -1;
}
#endif
int ret;
if(trig_type < 0)
{
return -1;
}
ret = sc_irq_set_type(line, trig_type);
if (ret != 0)
{
LOGE("set_type failed, ret:%d", ret);
return ret;
}
return 0;
}
/*****************************************
* @brief:lynq_irq_get_type
* @param count [IN]:1
* @param sum [OUT]:NA
* @return :success >= 0, failed other
* @todo:NA
* @see:NA
* @warning:NA
******************************************/
int lynq_irq_get_type(int line)
{
#if defined(MBTK_PROJECT_T108)
line = line-117;
#endif
int ret;
int trig_type;
ret = sc_irq_get_type(line, &trig_type);
if (ret != 0)
{
LOGE("get_type failed, ret:%d", ret);
return ret;
}
LOGI("get_type readback(%d)", trig_type);
return trig_type;
}
/*****************************************
* @brief:lynq_irq_set_wake
* @param count [IN]:2
* @param sum [OUT]:NA
* @return :success 0, failed other
* @todo:NA
* @see:NA
* @warning:NA
******************************************/
int lynq_irq_set_wake(int line, int en)
{
#if defined(MBTK_PROJECT_T108)
line = line-117;
#endif
int ret;
if((en != 0) && (en != 1))
{
LOGE("wake_state is not 0 or 1");
return -1;
}
ret = sc_irq_set_wake(line, en);
if (ret != 0)
{
LOGE("set_wake failed, ret:%d", ret);
return ret;
}
return 0;
}
/*****************************************
* @brief:lynq_irq_get_wake
* @param count [IN]:1
* @param sum [OUT]:NA
* @return :success >= 0, failed other
* @todo:NA
* @see:NA
* @warning:NA
******************************************/
int lynq_irq_get_wake(int line)
{
#if defined(MBTK_PROJECT_T108)
line = line-117;
#endif
int ret;
int en;
ret = sc_irq_get_wake(line, &en);
if (ret != 0)
{
LOGE("get_wake failed, ret:%d", ret);
return ret;
}
LOGI("get_wake readback(%d)", en);
return en;
}