658 lines
21 KiB
C
658 lines
21 KiB
C
/*
|
|
Copyright (c), 2001-2022, Shenshu Tech. Co., Ltd.
|
|
*/
|
|
|
|
#include "ot_ir.h"
|
|
#include "ot_osal.h"
|
|
#include "ot_ir_codedef.h"
|
|
#include "ot_ir_hal.h"
|
|
|
|
#ifndef NULL
|
|
#define NULL ((void *)0)
|
|
#endif
|
|
|
|
/* irq */
|
|
static uintptr_t g_ir_irq = 0;
|
|
|
|
/* io */
|
|
#define IR_REG_LENGTH 0x1000
|
|
static volatile void *g_ir_reg_base = NULL;
|
|
|
|
#define IR_ENABLE ((uintptr_t)g_ir_reg_base + 0x00)
|
|
#define IR_CONFIG ((uintptr_t)g_ir_reg_base + 0x04)
|
|
#define CNT_LEADS ((uintptr_t)g_ir_reg_base + 0x08)
|
|
#define CNT_LEADE ((uintptr_t)g_ir_reg_base + 0x0c)
|
|
#define CNT_SLEADE ((uintptr_t)g_ir_reg_base + 0x10)
|
|
#define CNT0_B ((uintptr_t)g_ir_reg_base + 0x14)
|
|
#define CNT1_B ((uintptr_t)g_ir_reg_base + 0x18)
|
|
#define IR_BUSY ((uintptr_t)g_ir_reg_base + 0x1c)
|
|
#define IR_DATAH ((uintptr_t)g_ir_reg_base + 0x20)
|
|
#define IR_DATAL ((uintptr_t)g_ir_reg_base + 0x24)
|
|
#define IR_INTM ((uintptr_t)g_ir_reg_base + 0x28)
|
|
#define IR_INTS ((uintptr_t)g_ir_reg_base + 0x2c)
|
|
#define IR_INTC ((uintptr_t)g_ir_reg_base + 0x30)
|
|
#define IR_START ((uintptr_t)g_ir_reg_base + 0x34)
|
|
|
|
/* interrupt mask */
|
|
#define INTMS_RCV (1L << 16)
|
|
#define INTMS_FRAMERR (1L << 17)
|
|
#define INTMS_OVERFLOW (1L << 18)
|
|
#define INTMS_RELEASE (1L << 19)
|
|
|
|
#define INT_MASK (INTMS_RCV | INTMS_FRAMERR | INTMS_OVERFLOW | INTMS_RELEASE)
|
|
|
|
/* define macro */
|
|
#define write_reg(addr, value) ((*(volatile unsigned int *)(addr)) = (value))
|
|
#define read_reg(addr) (*(volatile unsigned int *)(addr))
|
|
|
|
/* debug */
|
|
static int g_dbg_flag = 0;
|
|
#define OT_IR_PFX "ot_ir: "
|
|
#define ot_ir_dbg(params...) \
|
|
do { \
|
|
if (g_dbg_flag) { \
|
|
osal_printk(params); \
|
|
} \
|
|
} while (0)
|
|
|
|
/* unit is ms */
|
|
#define DEFAULT_DELAYTIME (200 * 10)
|
|
|
|
#define OT_IR_MAX_BUF 100
|
|
#define DEFAULT_BUF_LEN 8
|
|
#define BUF_HEAD g_ot_ir_dev.buf[g_ot_ir_dev.head]
|
|
#define BUF_TAIL g_ot_ir_dev.buf[g_ot_ir_dev.tail]
|
|
#define BUF_LAST g_ot_ir_dev.buf[(g_ot_ir_dev.head == 0) ? (g_ot_ir_dev.buf_len - 1) : (g_ot_ir_dev.head - 1)]
|
|
|
|
typedef struct {
|
|
ot_ir_dev_param dev_parm;
|
|
unsigned int head;
|
|
unsigned int tail;
|
|
irkey_info_s buf[OT_IR_MAX_BUF + 1]; /* 1:fifo reserve */
|
|
unsigned int buf_len;
|
|
|
|
unsigned int enable_repkey;
|
|
unsigned int repkey_checkflag;
|
|
unsigned int repkey_delaytime; /* ms */
|
|
|
|
unsigned int enable_keyup;
|
|
|
|
osal_wait_t ir_key_wait;
|
|
} ot_ir_dev_struct;
|
|
|
|
static ot_ir_dev_struct g_ot_ir_dev;
|
|
|
|
static void repkey_timeout_handler(unsigned long data);
|
|
static struct osal_timer g_repkey_timeout_timer;
|
|
static int g_need_iounmap = 0;
|
|
|
|
uintptr_t *get_ir_irq(void)
|
|
{
|
|
return &g_ir_irq;
|
|
}
|
|
|
|
volatile void **get_ir_reg_base(void)
|
|
{
|
|
return &g_ir_reg_base;
|
|
}
|
|
|
|
static void ot_ir_show_reg(void)
|
|
{
|
|
if (g_dbg_flag) {
|
|
osal_printk("OT_IR11 REG:###################################################\n");
|
|
osal_printk("%.8x ", read_reg(IR_ENABLE));
|
|
osal_printk("%.8x ", read_reg(IR_CONFIG));
|
|
osal_printk("%.8x ", read_reg(CNT_LEADS));
|
|
osal_printk("%.8x ", read_reg(CNT_LEADE));
|
|
osal_printk("%.8x ", read_reg(CNT_SLEADE));
|
|
osal_printk("%.8x ", read_reg(CNT0_B));
|
|
osal_printk("%.8x ", read_reg(CNT1_B));
|
|
osal_printk("\n");
|
|
osal_printk("%.8x ", read_reg(IR_BUSY));
|
|
osal_printk("%.8x ", read_reg(IR_DATAH));
|
|
osal_printk("%.8x ", read_reg(IR_DATAL));
|
|
osal_printk("%.8x ", read_reg(IR_INTM));
|
|
osal_printk("%.8x ", read_reg(IR_INTS));
|
|
osal_printk("%.8x ", read_reg(IR_INTC));
|
|
osal_printk("%.8x ", read_reg(IR_START));
|
|
osal_printk("\n");
|
|
}
|
|
}
|
|
|
|
static inline unsigned int inc_buf(unsigned int x, unsigned int len)
|
|
{
|
|
++x;
|
|
|
|
if (len == 0) {
|
|
return x % DEFAULT_BUF_LEN;
|
|
} else {
|
|
return x % len;
|
|
}
|
|
}
|
|
|
|
static void write_reg32(unsigned int value, unsigned int mask, const void *addr)
|
|
{
|
|
unsigned int t;
|
|
|
|
t = osal_readl((void *)addr);
|
|
t &= ~mask;
|
|
t |= value & mask;
|
|
|
|
osal_writel(t, (void *)addr);
|
|
}
|
|
|
|
static int ot_ir_enable_clock(void)
|
|
{
|
|
void *ir_crg_addr = NULL;
|
|
|
|
ir_crg_addr = osal_ioremap(IR_CRG_ADDR, (unsigned long)IR_CLOCK_REG_LENGTH);
|
|
if (ir_crg_addr == NULL) {
|
|
return -1;
|
|
}
|
|
#ifdef IR_IS_DEFAULT_RESET
|
|
write_reg32(0x0, 0x1, ir_crg_addr); /* 0x0: [1] bit for clock reset */
|
|
#endif
|
|
write_reg32(0x1 << IR_BIT, 0x1 << IR_BIT, ir_crg_addr); /* 0x1: [1] bit for clock control */
|
|
|
|
osal_iounmap((void *)ir_crg_addr);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void ot_ir_disable_clock(void)
|
|
{
|
|
void *ir_crg_addr = NULL;
|
|
|
|
ir_crg_addr = osal_ioremap(IR_CRG_ADDR, (unsigned long)IR_CLOCK_REG_LENGTH);
|
|
if (ir_crg_addr == NULL) {
|
|
return;
|
|
}
|
|
|
|
write_reg32(0x0 << IR_BIT, 0x1 << IR_BIT, ir_crg_addr); /* 0x1: [1] bit for clock control */
|
|
|
|
osal_iounmap((void *)ir_crg_addr);
|
|
}
|
|
|
|
static void ot_ir_config(void)
|
|
{
|
|
unsigned int value;
|
|
|
|
write_reg(IR_ENABLE, 0x01); /* 0x01: for IR control */
|
|
while (read_reg(IR_BUSY)) {
|
|
ot_ir_dbg("IR_BUSY. Wait...\n");
|
|
}
|
|
|
|
value = (g_ot_ir_dev.dev_parm.codetype << 14); /* 14: [15:14] bits for code type */
|
|
value |= (g_ot_ir_dev.dev_parm.code_len - 1) << 8; /* 8: [13:8] bits for code len */
|
|
value |= (g_ot_ir_dev.dev_parm.frequence - 1); /* [6:0] bits for frequence */
|
|
write_reg(IR_CONFIG, value);
|
|
|
|
value = g_ot_ir_dev.dev_parm.leads_min << 16; /* 16: [25:16] bits for min leads */
|
|
value |= g_ot_ir_dev.dev_parm.leads_max; /* [9:0] bits for max leads */
|
|
write_reg(CNT_LEADS, value);
|
|
|
|
value = g_ot_ir_dev.dev_parm.leade_min << 16; /* 16, bits [24:16] for min leads */
|
|
value |= g_ot_ir_dev.dev_parm.leade_max; /* [8:0] bits for max leads */
|
|
write_reg(CNT_LEADE, value);
|
|
|
|
value = g_ot_ir_dev.dev_parm.sleade_min << 16; /* 16, bits [24:16] for min sleade */
|
|
value |= g_ot_ir_dev.dev_parm.sleade_max; /* [8:0] bits for max sleade */
|
|
write_reg(CNT_SLEADE, value);
|
|
|
|
value = g_ot_ir_dev.dev_parm.cnt0_b_min << 16; /* 16, bits [24:16] for min cnt0 */
|
|
value |= g_ot_ir_dev.dev_parm.cnt0_b_max; /* [8:0] bits for max cnt0 */
|
|
write_reg(CNT0_B, value);
|
|
|
|
value = g_ot_ir_dev.dev_parm.cnt1_b_min << 16; /* 16, bits [24:16] for min cnt1 */
|
|
value |= g_ot_ir_dev.dev_parm.cnt1_b_max; /* [8:0] bits for max cnt1 */
|
|
write_reg(CNT1_B, value);
|
|
|
|
write_reg(IR_INTM, 0x00);
|
|
write_reg(IR_START, 0x00);
|
|
}
|
|
|
|
static void repkey_timeout_handler(unsigned long data)
|
|
{
|
|
ot_ir_unused(data);
|
|
osal_del_timer(&g_repkey_timeout_timer);
|
|
g_ot_ir_dev.repkey_checkflag = 0;
|
|
}
|
|
|
|
static void interrupt_rcv(void)
|
|
{
|
|
ot_ir_dbg("receive data interrupt. 0x%.8x-0x%.8x\n", read_reg(IR_DATAH), read_reg(IR_DATAL));
|
|
write_reg(IR_INTC, 0x01 << 0); /* 0x01: clear interrupt */
|
|
|
|
if (g_ot_ir_dev.enable_repkey) {
|
|
if ((g_ot_ir_dev.repkey_checkflag) &&
|
|
(BUF_LAST.irkey_datah == read_reg(IR_DATAH)) &&
|
|
(BUF_LAST.irkey_datal == read_reg(IR_DATAL))) {
|
|
ot_ir_dbg("repeart key [0x%.8x]-[0x%.8x] detective\n", read_reg(IR_DATAH), read_reg(IR_DATAL));
|
|
} else {
|
|
/* repeat key check */
|
|
osal_del_timer(&g_repkey_timeout_timer);
|
|
osal_set_timer(&g_repkey_timeout_timer, g_ot_ir_dev.repkey_delaytime / 10); /* 10: delaytime means ms*10 */
|
|
g_ot_ir_dev.repkey_checkflag = 1;
|
|
BUF_HEAD.irkey_datah = read_reg(IR_DATAH);
|
|
BUF_HEAD.irkey_datal = read_reg(IR_DATAL);
|
|
BUF_HEAD.irkey_state_code = OT_IR_KEY_DOWN;
|
|
g_ot_ir_dev.head = inc_buf(g_ot_ir_dev.head, g_ot_ir_dev.buf_len);
|
|
osal_wakeup(&(g_ot_ir_dev.ir_key_wait));
|
|
}
|
|
} else if (!((BUF_LAST.irkey_datah == read_reg(IR_DATAH)) &&
|
|
(BUF_LAST.irkey_datal == read_reg(IR_DATAL)) &&
|
|
(BUF_LAST.irkey_state_code == OT_IR_KEY_DOWN))) {
|
|
BUF_HEAD.irkey_datah = read_reg(IR_DATAH);
|
|
BUF_HEAD.irkey_datal = read_reg(IR_DATAL);
|
|
BUF_HEAD.irkey_state_code = OT_IR_KEY_DOWN;
|
|
g_ot_ir_dev.head = inc_buf(g_ot_ir_dev.head, g_ot_ir_dev.buf_len);
|
|
osal_wakeup(&(g_ot_ir_dev.ir_key_wait));
|
|
}
|
|
}
|
|
|
|
static int ot_ir_interrupt(int irq, void *dev_id)
|
|
{
|
|
unsigned int int_state = read_reg(IR_INTS);
|
|
|
|
ot_ir_unused(irq);
|
|
ot_ir_unused(dev_id);
|
|
if ((int_state & INT_MASK) == 0) {
|
|
return OSAL_IRQ_NONE;
|
|
}
|
|
|
|
ot_ir_dbg("Enter ot_ir_interrupt.\n");
|
|
ot_ir_show_reg();
|
|
|
|
if (int_state & INTMS_FRAMERR) {
|
|
ot_ir_dbg("frame error.\n");
|
|
write_reg(IR_INTC, 0x01 << 1); /* 1: write 0x01 to [1] bit, clear frame error interrupt */
|
|
} else if (int_state & INTMS_OVERFLOW) {
|
|
ot_ir_dbg("hardware overflow.\n");
|
|
write_reg(IR_INTC, 0x01 << 2); /* 2: write 0x01 to [2] bit, clear hardware overflow interrupt */
|
|
} else if (int_state & INTMS_RELEASE) {
|
|
ot_ir_dbg("release key interrupt.\n");
|
|
write_reg(IR_INTC, 0x01 << 3); /* 3: write 0x01 to [3] bit, clear release key interrupt */
|
|
|
|
osal_del_timer(&g_repkey_timeout_timer);
|
|
g_ot_ir_dev.repkey_checkflag = 0;
|
|
|
|
if ((g_ot_ir_dev.enable_keyup) && (BUF_LAST.irkey_state_code != OT_IR_KEY_UP)) {
|
|
BUF_HEAD = BUF_LAST;
|
|
BUF_HEAD.irkey_state_code = OT_IR_KEY_UP;
|
|
g_ot_ir_dev.head = inc_buf(g_ot_ir_dev.head, g_ot_ir_dev.buf_len);
|
|
osal_wakeup(&(g_ot_ir_dev.ir_key_wait));
|
|
}
|
|
} else if (int_state & INTMS_RCV) {
|
|
interrupt_rcv();
|
|
} else {
|
|
osal_printk("logic Error: int_mask=0x%.8x, int_state=0x%.8x.\n", read_reg(IR_INTM), int_state);
|
|
}
|
|
|
|
ot_ir_dbg("Exit ot_ir_interrupt.\n");
|
|
|
|
return OSAL_IRQ_HANDLED;
|
|
}
|
|
|
|
static long ot_ir_ioctl(unsigned int cmd, unsigned long arg, void *private_data)
|
|
{
|
|
int *p = (int *)(uintptr_t)arg;
|
|
unsigned int min_val, max_val;
|
|
|
|
ot_ir_unused(private_data);
|
|
switch (cmd) {
|
|
case IR_IOC_SET_BUF:
|
|
if ((arg > 0) && (arg <= OT_IR_MAX_BUF)) {
|
|
g_ot_ir_dev.buf_len = arg + 1;
|
|
|
|
/* need reset buf pointer */
|
|
g_ot_ir_dev.head = 0;
|
|
g_ot_ir_dev.tail = 0;
|
|
}
|
|
ot_ir_dbg("IR_IOC_SET_BUF->buf_len=%u\n", g_ot_ir_dev.buf_len);
|
|
break;
|
|
case IR_IOC_SET_ENABLE_KEYUP:
|
|
g_ot_ir_dev.enable_keyup = arg;
|
|
ot_ir_dbg("IR_IOC_SET_ENABLE_KEYUP->enable_keyup=%u\n", g_ot_ir_dev.enable_keyup);
|
|
break;
|
|
case IR_IOC_SET_ENABLE_REPKEY:
|
|
g_ot_ir_dev.enable_repkey = arg;
|
|
ot_ir_dbg("IR_IOC_SET_ENABLE_REPKEY->enable_repkey=%u\n", g_ot_ir_dev.enable_repkey);
|
|
break;
|
|
case IR_IOC_SET_REPKEY_TIMEOUTVAL:
|
|
if (arg > 0) {
|
|
g_ot_ir_dev.repkey_delaytime = arg;
|
|
}
|
|
ot_ir_dbg("IR_IOC_SET_REPKEY_TIMEOUTVAL->repkey_delaytime=%u\n", g_ot_ir_dev.repkey_delaytime);
|
|
break;
|
|
case IR_IOC_SET_FORMAT:
|
|
if (arg > 3) { /* format:[0,3] */
|
|
osal_printk("Error: IR_IOC_SET_FORMAT->invalid args=%lu\n", arg);
|
|
return -1;
|
|
}
|
|
g_ot_ir_dev.dev_parm.codetype = arg;
|
|
ot_ir_dbg("IR_IOC_SET_FORMAT->codetype=%u\n", g_ot_ir_dev.dev_parm.codetype);
|
|
break;
|
|
case IR_IOC_SET_CODELEN:
|
|
g_ot_ir_dev.dev_parm.code_len = arg;
|
|
ot_ir_dbg("IR_IOC_SET_CODELEN->code_len=%u\n", g_ot_ir_dev.dev_parm.code_len);
|
|
break;
|
|
case IR_IOC_SET_FREQ:
|
|
if ((arg <= 0) || (arg > 128)) { /* 128:max freq */
|
|
osal_printk("Error: IR_IOC_SET_FREQ->invalid args=%lu\n", arg);
|
|
return -1;
|
|
}
|
|
g_ot_ir_dev.dev_parm.frequence = arg;
|
|
ot_ir_dbg("IR_IOC_SET_FREQ->frequence=%u\n", g_ot_ir_dev.dev_parm.frequence);
|
|
break;
|
|
case IR_IOC_SET_LEADS:
|
|
if (osal_copy_from_user(&min_val, p, sizeof(unsigned int)) ||
|
|
osal_copy_from_user(&max_val, p + 1, sizeof(unsigned int))) {
|
|
return -1;
|
|
}
|
|
g_ot_ir_dev.dev_parm.leads_min = min_val;
|
|
g_ot_ir_dev.dev_parm.leads_max = max_val;
|
|
ot_ir_dbg("IR_IOC_SET_LEADS->leads_min=%u, leads_max=%u\n",
|
|
g_ot_ir_dev.dev_parm.leads_min, g_ot_ir_dev.dev_parm.leads_max);
|
|
break;
|
|
case IR_IOC_SET_LEADE:
|
|
if (osal_copy_from_user(&min_val, p, sizeof(unsigned int)) ||
|
|
osal_copy_from_user(&max_val, p + 1, sizeof(unsigned int))) {
|
|
return -1;
|
|
}
|
|
g_ot_ir_dev.dev_parm.leade_min = min_val;
|
|
g_ot_ir_dev.dev_parm.leade_max = max_val;
|
|
ot_ir_dbg("IR_IOC_SET_LEADE->leade_min=%u, leade_max=%u\n",
|
|
g_ot_ir_dev.dev_parm.leade_min, g_ot_ir_dev.dev_parm.leade_max);
|
|
break;
|
|
case IR_IOC_SET_SLEADE:
|
|
if (osal_copy_from_user(&min_val, p, sizeof(unsigned int)) ||
|
|
osal_copy_from_user(&max_val, p + 1, sizeof(unsigned int))) {
|
|
return -1;
|
|
}
|
|
g_ot_ir_dev.dev_parm.sleade_min = min_val;
|
|
g_ot_ir_dev.dev_parm.sleade_max = max_val;
|
|
ot_ir_dbg("IR_IOC_SET_SLEADE->sleade_min=%u, sleade_max=%u\n",
|
|
g_ot_ir_dev.dev_parm.sleade_min, g_ot_ir_dev.dev_parm.sleade_max);
|
|
break;
|
|
case IR_IOC_SET_CNT0_B:
|
|
if (osal_copy_from_user(&min_val, p, sizeof(unsigned int)) ||
|
|
osal_copy_from_user(&max_val, p + 1, sizeof(unsigned int))) {
|
|
return -1;
|
|
}
|
|
g_ot_ir_dev.dev_parm.cnt0_b_min = min_val;
|
|
g_ot_ir_dev.dev_parm.cnt0_b_max = max_val;
|
|
ot_ir_dbg("IR_IOC_SET_CNT0_B->cnt0_b_min=%u, cnt0_b_max=%u\n",
|
|
g_ot_ir_dev.dev_parm.cnt0_b_min, g_ot_ir_dev.dev_parm.cnt0_b_max);
|
|
break;
|
|
case IR_IOC_SET_CNT1_B:
|
|
if (osal_copy_from_user(&min_val, p, sizeof(unsigned int)) ||
|
|
osal_copy_from_user(&max_val, p + 1, sizeof(unsigned int))) {
|
|
return -1;
|
|
}
|
|
g_ot_ir_dev.dev_parm.cnt1_b_min = min_val;
|
|
g_ot_ir_dev.dev_parm.cnt1_b_max = max_val;
|
|
ot_ir_dbg("IR_IOC_SET_CNT1_B->cnt1_b_min=%u, cnt1_b_max=%u\n",
|
|
g_ot_ir_dev.dev_parm.cnt1_b_min, g_ot_ir_dev.dev_parm.cnt1_b_max);
|
|
break;
|
|
case IR_IOC_GET_CONFIG:
|
|
if (osal_copy_to_user((void *)(uintptr_t)arg, &(g_ot_ir_dev.dev_parm), sizeof(ot_ir_dev_param))) {
|
|
osal_printk("%s: copy_to_user fail!\n", __func__);
|
|
}
|
|
ot_ir_dbg("IR_IOC_GET_CONFIG\n");
|
|
break;
|
|
case IR_IOC_ENDBG:
|
|
g_dbg_flag = 1;
|
|
ot_ir_dbg("IR_IOC_ENDBG\n");
|
|
break;
|
|
case IR_IOC_DISDBG:
|
|
g_dbg_flag = 0;
|
|
ot_ir_dbg("IR_IOC_DISDBG\n");
|
|
break;
|
|
default:
|
|
osal_printk("Error: Inappropriate ioctl for device. cmd=%u\n", cmd);
|
|
return -1;
|
|
}
|
|
|
|
ot_ir_config();
|
|
return 0;
|
|
}
|
|
|
|
static int ot_ir_wait_condition_callback(const void *param)
|
|
{
|
|
ot_ir_unused(param);
|
|
return (g_ot_ir_dev.head != g_ot_ir_dev.tail);
|
|
}
|
|
|
|
static int ot_ir_read(char *buf, int count, long *f_pos, void *private_data)
|
|
{
|
|
irkey_info_s irkey_to_user;
|
|
int res = 0;
|
|
|
|
ot_ir_unused(f_pos);
|
|
ot_ir_unused(private_data);
|
|
retry :
|
|
ot_ir_dbg("Enter ot_ir_read : head=%u, tail=%u, buf_len=%u\n",
|
|
g_ot_ir_dev.head, g_ot_ir_dev.tail, g_ot_ir_dev.buf_len);
|
|
|
|
if ((g_ot_ir_dev.head) == (g_ot_ir_dev.tail)) {
|
|
res = osal_wait_event_interruptible(&(g_ot_ir_dev.ir_key_wait), ot_ir_wait_condition_callback, &g_ot_ir_dev);
|
|
if (res != 0) {
|
|
return res;
|
|
}
|
|
goto retry;
|
|
} else {
|
|
while (((g_ot_ir_dev.head) != (g_ot_ir_dev.tail)) && ((res + (int)sizeof(irkey_info_s)) <= count)) {
|
|
irkey_to_user = BUF_TAIL;
|
|
g_ot_ir_dev.tail = inc_buf(g_ot_ir_dev.tail, g_ot_ir_dev.buf_len);
|
|
if (osal_copy_to_user((buf + res), &irkey_to_user, sizeof(irkey_info_s))) {
|
|
osal_printk("%s: copy_to_user fail!\n", __func__);
|
|
}
|
|
res += sizeof(irkey_info_s);
|
|
}
|
|
}
|
|
return res;
|
|
}
|
|
|
|
static unsigned int ot_ir_select(osal_poll_t *osal_poll, void *private_data)
|
|
{
|
|
ot_ir_unused(private_data);
|
|
ot_ir_dbg("Enter ot_ir_select.\n");
|
|
if ((g_ot_ir_dev.head) != (g_ot_ir_dev.tail)) {
|
|
return 1;
|
|
}
|
|
osal_poll_wait(osal_poll, &(g_ot_ir_dev.ir_key_wait));
|
|
return 0;
|
|
}
|
|
|
|
static osal_atomic_t g_ot_ir_s_available;
|
|
|
|
static int ot_ir_open(void *private_data)
|
|
{
|
|
int ret;
|
|
|
|
ot_ir_unused(private_data);
|
|
ot_ir_dbg("Enter ot_ir_open.\n");
|
|
|
|
if (osal_atomic_dec_return(&g_ot_ir_s_available) != 0) {
|
|
ret = osal_atomic_inc_return(&g_ot_ir_s_available);
|
|
osal_printk("Error: device already open:%d.\n", ret);
|
|
return -1;
|
|
}
|
|
|
|
osal_del_timer(&g_repkey_timeout_timer);
|
|
|
|
g_dbg_flag = 0;
|
|
|
|
/* init g_ot_ir_dev */
|
|
g_ot_ir_dev.dev_parm = g_static_dev_param[0]; /* nec format */
|
|
g_ot_ir_dev.head = 0;
|
|
g_ot_ir_dev.tail = 0;
|
|
g_ot_ir_dev.buf_len = DEFAULT_BUF_LEN;
|
|
g_ot_ir_dev.enable_repkey = 1;
|
|
g_ot_ir_dev.repkey_checkflag = 0;
|
|
g_ot_ir_dev.repkey_delaytime = DEFAULT_DELAYTIME;
|
|
g_ot_ir_dev.enable_keyup = 1;
|
|
osal_wait_init(&g_ot_ir_dev.ir_key_wait);
|
|
|
|
ot_ir_config();
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int ot_ir_release(void *private_data)
|
|
{
|
|
ot_ir_unused(private_data);
|
|
ot_ir_dbg("Enter ot_ir_release.\n");
|
|
|
|
/* disable OT_IR11 */
|
|
write_reg(IR_ENABLE, 0x0);
|
|
|
|
if (osal_atomic_inc_return(&g_ot_ir_s_available) != 1) {
|
|
osal_atomic_dec_return(&g_ot_ir_s_available);
|
|
return 0;
|
|
}
|
|
|
|
osal_del_timer(&g_repkey_timeout_timer);
|
|
|
|
osal_wait_destroy(&g_ot_ir_dev.ir_key_wait);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int ot_ir_write(const char *buf, int size, long *offset, void *private_data)
|
|
{
|
|
ot_ir_unused(buf);
|
|
ot_ir_unused(size);
|
|
ot_ir_unused(offset);
|
|
ot_ir_unused(private_data);
|
|
return 0;
|
|
}
|
|
|
|
static struct osal_fileops g_ot_ir_fops = {
|
|
open : ot_ir_open,
|
|
unlocked_ioctl : ot_ir_ioctl,
|
|
poll : ot_ir_select,
|
|
read : ot_ir_read,
|
|
write : ot_ir_write,
|
|
release : ot_ir_release,
|
|
};
|
|
|
|
static struct osal_dev *g_ot_ir_miscdev = NULL;
|
|
|
|
static int ot_ir_sw_init(void)
|
|
{
|
|
int res;
|
|
|
|
if (g_ir_irq <= 0) {
|
|
g_ir_irq = OT_IR_DEVICE_IRQ_NO;
|
|
}
|
|
|
|
if (g_ir_reg_base == NULL) {
|
|
g_ir_reg_base = (volatile void *)osal_ioremap(IR_REG_BASE, IR_REG_LENGTH);
|
|
if (g_ir_reg_base == NULL) {
|
|
osal_printk("osal_ioremap err. \n");
|
|
return 1;
|
|
}
|
|
g_need_iounmap = 1;
|
|
}
|
|
|
|
res = osal_atomic_init(&g_ot_ir_s_available);
|
|
if (res != 0) {
|
|
osal_printk("Error: init atomic\n");
|
|
if (g_need_iounmap) {
|
|
osal_iounmap((void *)g_ir_reg_base);
|
|
g_need_iounmap = 0;
|
|
g_ir_reg_base = NULL;
|
|
}
|
|
return 1;
|
|
}
|
|
osal_atomic_set(&g_ot_ir_s_available, 1);
|
|
|
|
g_repkey_timeout_timer.function = repkey_timeout_handler;
|
|
res = osal_timer_init(&g_repkey_timeout_timer);
|
|
if (res != 0) {
|
|
if (g_need_iounmap) {
|
|
osal_iounmap((void *)g_ir_reg_base);
|
|
g_need_iounmap = 0;
|
|
g_ir_reg_base = NULL;
|
|
}
|
|
osal_atomic_destroy(&g_ot_ir_s_available);
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int ot_ir_init(void)
|
|
{
|
|
if (ot_ir_sw_init() != 0) {
|
|
return -1;
|
|
}
|
|
|
|
if (ot_ir_enable_clock() != 0) {
|
|
osal_printk("Error: enable clock fail\n");
|
|
goto enable_clock_fail;
|
|
}
|
|
|
|
/* disable OT_IR */
|
|
write_reg(IR_ENABLE, 0x00);
|
|
|
|
g_ot_ir_miscdev = osal_createdev(OT_IR_DEVICE_NAME);
|
|
if (g_ot_ir_miscdev == NULL) {
|
|
osal_printk("Error: can't create dev\n");
|
|
goto create_dev_fail;
|
|
}
|
|
|
|
g_ot_ir_miscdev->minor = 255; /* 255:dev_minor */
|
|
g_ot_ir_miscdev->fops = &g_ot_ir_fops;
|
|
if (osal_registerdevice(g_ot_ir_miscdev) != 0) {
|
|
osal_printk("Error: can't register\n");
|
|
goto register_device_fail;
|
|
}
|
|
|
|
if (osal_request_irq(g_ir_irq, ot_ir_interrupt, NULL, OT_IR_DEVICE_NAME, &ot_ir_interrupt) != 0) {
|
|
osal_printk("Error: request IRQ(%lu) failed\n", g_ir_irq);
|
|
goto request_irq_fail;
|
|
}
|
|
|
|
osal_printk("ot_ir init ok. ver=%s, %s.\n", __DATE__, __TIME__);
|
|
return 0;
|
|
|
|
request_irq_fail:
|
|
osal_deregisterdevice(g_ot_ir_miscdev);
|
|
register_device_fail:
|
|
osal_destroydev(g_ot_ir_miscdev);
|
|
create_dev_fail:
|
|
ot_ir_disable_clock();
|
|
enable_clock_fail:
|
|
osal_timer_destroy(&g_repkey_timeout_timer);
|
|
osal_atomic_destroy(&g_ot_ir_s_available);
|
|
if (g_need_iounmap) {
|
|
osal_iounmap((void *)g_ir_reg_base);
|
|
g_need_iounmap = 0;
|
|
g_ir_reg_base = NULL;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
void ot_ir_exit(void)
|
|
{
|
|
osal_free_irq(g_ir_irq, &ot_ir_interrupt);
|
|
|
|
osal_deregisterdevice(g_ot_ir_miscdev);
|
|
osal_destroydev(g_ot_ir_miscdev);
|
|
|
|
osal_del_timer(&g_repkey_timeout_timer);
|
|
osal_timer_destroy(&g_repkey_timeout_timer);
|
|
|
|
osal_atomic_destroy(&g_ot_ir_s_available);
|
|
if (g_need_iounmap) {
|
|
osal_iounmap((void *)g_ir_reg_base);
|
|
g_need_iounmap = 0;
|
|
g_ir_reg_base = NULL;
|
|
}
|
|
|
|
ot_ir_disable_clock();
|
|
|
|
osal_printk("ot_ir exit ok.\n");
|
|
}
|