SmartAudio/lichee/brandy/u-boot-2014.07/drivers/ir/sunxi-ir.c

369 lines
8.4 KiB
C
Executable File

/*
* (C) Copyright 2007-2016
* Allwinnertech Technology Co., Ltd <www.allwinnertech.com>
*
* See file CREDITS for list of people who contributed to this
* project.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#include <asm/arch/intc.h>
#include <asm/arch/platform.h>
#include <common.h>
#include <fdt_support.h>
#include <sys_config.h>
#include "asm/arch/timer.h"
#include "sunxi-ir.h"
#include <sys_config_old.h>
DECLARE_GLOBAL_DATA_PTR;
DEFINE_IR_RAW_EVENT(rawir);
struct ir_raw_buffer sunxi_ir_raw;
static bool pluse_pre;
static u32 is_receiving;
extern struct timer_list ir_timer_t;
/*define ir or key mode value*/
#define EFEX_VALUE (0x81)
#define SPRITE_RECOVERY_VALUE (0X82)
#define BOOT_RECOVERY_VALUE (0x83)
#define BOOT_FACTORY_VALUE (0x84)
/*ir or key mode in sys_config*/
#define EFEX_MODE_CONFIG (0x0)
#define ONEKEY_SPRITE_RECOVERY_MODE_CONFIG (0x1)
#define RECOVERY_MODE_CONFIG (0x2)
#define FACTORY_MODE_CONFIG (0x3)
static int ir_detect_count;
static inline void ir_reset_rawbuffer(void)
{
sunxi_ir_raw.dcnt = 0;
}
static inline u8 ir_get_data(void)
{
return (u8)(readl(IR_BASE + IR_RXDAT_REG));
}
static inline u32 ir_get_intsta(void)
{
return readl(IR_BASE + IR_RXINTS_REG);
}
static inline void ir_clr_intsta(u32 bitmap)
{
u32 tmp = readl(IR_BASE + IR_RXINTS_REG);
tmp &= ~0xff;
tmp |= bitmap & 0xff;
writel(tmp, IR_BASE + IR_RXINTS_REG);
}
static void ir_mode_set(enum ir_mode set_mode)
{
u32 ctrl_reg = 0;
switch (set_mode) {
case CIR_MODE_ENABLE:
ctrl_reg = readl(IR_BASE + IR_CTRL_REG);
ctrl_reg |= IR_CIR_MODE; /*(0x3<<4) */
break;
case IR_MODULE_ENABLE:
ctrl_reg = readl(IR_BASE + IR_CTRL_REG);
ctrl_reg |= IR_ENTIRE_ENABLE; /*(0x3<<0) */
break;
default:
return;
}
writel(ctrl_reg, IR_BASE + IR_CTRL_REG);
}
static void ir_sample_config(enum ir_sample_config set_sample)
{
u32 sample_reg = 0;
sample_reg = readl(IR_BASE + IR_SPLCFG_REG);
switch (set_sample) {
case IR_SAMPLE_REG_CLEAR:
sample_reg = 0;
break;
case IR_CLK_SAMPLE:
sample_reg |= IR_SAMPLE_DEV; /*(0x3<<0) */
break;
case IR_FILTER_TH:
sample_reg |= IR_RXFILT_VAL;
break;
case IR_IDLE_TH:
sample_reg |= IR_RXIDLE_VAL;
break;
case IR_ACTIVE_TH:
sample_reg |= IR_ACTIVE_T;
sample_reg |= IR_ACTIVE_T_C;
break;
default:
return;
}
writel(sample_reg, IR_BASE + IR_SPLCFG_REG);
}
static void ir_signal_invert(void)
{
u32 reg_value;
reg_value = 0x1 << 2;
writel(reg_value, IR_BASE + IR_RXCFG_REG);
}
static void ir_irq_config(enum ir_irq_config set_irq)
{
u32 irq_reg = 0;
switch (set_irq) {
case IR_IRQ_STATUS_CLEAR:
writel(0xef, IR_BASE + IR_RXINTS_REG);
return;
case IR_IRQ_ENABLE:
irq_reg = readl(IR_BASE + IR_RXINTE_REG);
irq_reg |= IR_IRQ_STATUS;
break;
case IR_IRQ_FIFO_SIZE:
irq_reg = readl(IR_BASE + IR_RXINTE_REG);
irq_reg |= IR_FIFO_32;
break;
default:
return;
}
writel(irq_reg, IR_BASE + IR_RXINTE_REG);
}
static void ir_reg_cfg(void)
{
/* Enable IR Mode */
ir_mode_set(CIR_MODE_ENABLE);
/* Config IR Smaple Register */
ir_sample_config(IR_SAMPLE_REG_CLEAR);
ir_sample_config(IR_CLK_SAMPLE);
ir_sample_config(IR_FILTER_TH); /* Set Filter Threshold */
ir_sample_config(IR_IDLE_TH); /* Set Idle Threshold */
ir_sample_config(IR_ACTIVE_TH); /* Set Active Threshold */
/* Invert Input Signal */
ir_signal_invert();
/* Clear All Rx Interrupt Status */
ir_irq_config(IR_IRQ_STATUS_CLEAR);
/* Set Rx Interrupt Enable */
ir_irq_config(IR_IRQ_ENABLE);
ir_irq_config(IR_IRQ_FIFO_SIZE); /* Rx FIFO Threshold = FIFOsz/2; */
/* Enable IR Module */
ir_mode_set(IR_MODULE_ENABLE);
}
static int ir_raw_event_store(struct ir_raw_buffer *ir_raw,
struct ir_raw_event *ev)
{
if (ir_raw->dcnt < IR_RAW_BUF_SIZE)
memcpy(&(ir_raw->raw[ir_raw->dcnt++]), ev, sizeof(*ev));
else
printf("raw event store full\n");
return 0;
}
extern int ir_boot_recovery_mode_detect(void);
extern int ir_nec_decode(struct ir_raw_buffer *ir_raw, struct ir_raw_event ev);
unsigned long ir_packet_handle(struct ir_raw_buffer *ir_raw)
{
int i = 0, ret = 0;
int ir_press_times = 0;
int ir_work_mode = 0;
ret = script_parser_fetch("ir_boot_recovery", "ir_press_times",
(int *)&ir_press_times, sizeof(int) / 4);
if (ret) {
printf("ir_press_times not set, use default press time : 1\n");
ir_press_times = 1;
}
for (i = 0; i < ir_raw->dcnt; i++) {
ir_nec_decode(ir_raw, ir_raw->raw[i]);
}
ret = ir_boot_recovery_mode_detect();
if (!ret) {
ir_detect_count++;
}
if (ir_detect_count == ir_press_times) {
del_timer(&ir_timer_t);
ir_disable();
gd->ir_detect_status = IR_DETECT_OK;
ret =
script_parser_fetch("ir_boot_recovery", "ir_work_mode",
(int *)&ir_work_mode, sizeof(int) / 4);
if (ret) {
printf("ir_work_mode not set, use default mode: "
"android recovery mode.\n");
gd->key_pressd_value = BOOT_RECOVERY_VALUE;
} else {
switch (ir_work_mode) {
case EFEX_MODE_CONFIG:
gd->key_pressd_value = EFEX_VALUE;
break;
case ONEKEY_SPRITE_RECOVERY_MODE_CONFIG:
gd->key_pressd_value = SPRITE_RECOVERY_VALUE;
break;
case RECOVERY_MODE_CONFIG:
gd->key_pressd_value = BOOT_RECOVERY_VALUE;
break;
case FACTORY_MODE_CONFIG:
gd->key_pressd_value = BOOT_FACTORY_VALUE;
break;
}
}
}
return 0;
}
void ir_recv_irq_service(void *data)
{
u32 intsta, dcnt;
u32 i = 0;
bool pluse_now = 0;
u8 reg_data;
print_debug("IR RX IRQ Serve\n");
intsta = ir_get_intsta();
ir_clr_intsta(intsta);
dcnt = (ir_get_intsta() >> 8) & 0x7f;
print_debug("receive cnt :%d \n", dcnt);
/* Read FIFO and fill the raw event */
{
/* get the data from fifo */
for (i = 0; i < dcnt; i++) {
reg_data = ir_get_data();
pluse_now = (reg_data & 0x80) ? true : false;
if (pluse_pre == pluse_now) { /* the signal maintian */
/* the pluse or space lasting*/
rawir.duration += (u32)(reg_data & 0x7f);
print_debug("raw: %d:%d \n",
(reg_data & 0x80) >> 7,
(reg_data & 0x7f));
} else {
if (is_receiving) {
rawir.duration *= IR_SIMPLE_UNIT;
print_debug("pusle :%u, dur: %u ns\n",
rawir.pulse,
rawir.duration);
ir_raw_event_store(&sunxi_ir_raw,
&rawir);
rawir.pulse = pluse_now;
rawir.duration = (u32)(reg_data & 0x7f);
print_debug("raw: %d:%d \n",
(reg_data & 0x80) >> 7,
(reg_data & 0x7f));
} else {
/* get the first pluse signal */
rawir.pulse = pluse_now;
rawir.duration = (u32)(reg_data & 0x7f);
#ifdef CIR_24M_CLK_USED
rawir.duration +=
((IR_ACTIVE_T >> 16) + 1) *
((IR_ACTIVE_T_C >> 23) ? 128 : 1);
print_debug(
"get frist pulse,add head %d !!\n",
((IR_ACTIVE_T >> 16) + 1) *
((IR_ACTIVE_T_C >> 23) ? 128
: 1));
#endif
is_receiving = 1;
print_debug("raw: %d:%d \n",
(reg_data & 0x80) >> 7,
(reg_data & 0x7f));
}
pluse_pre = pluse_now;
}
}
}
if (intsta & IR_RXINTS_RXPE) { /* Packet End */
if (rawir.duration) {
rawir.duration *= IR_SIMPLE_UNIT;
print_debug("pusle :%u, dur: %u ns\n", rawir.pulse,
rawir.duration);
ir_raw_event_store(&sunxi_ir_raw, &rawir);
}
print_debug("handle raw data.\n");
/* handle ther decoder theread */
ir_packet_handle(&sunxi_ir_raw);
ir_reset_rawbuffer();
is_receiving = 0;
pluse_pre = false;
}
if (intsta & IR_RXINTS_RXOF) { /* FIFO Overflow */
/* flush rew buffer */
is_receiving = 0;
pluse_pre = false;
ir_reset_rawbuffer();
printf("ir_irq_service: Rx FIFO Overflow\n");
}
print_debug("ir_irq_service: end\n");
return;
}
void rc_keydown(struct ir_raw_buffer *ir_raw, u32 scancode, u8 toggle)
{
ir_raw->scancode = scancode;
}
int ir_setup(void)
{
if (fdt_set_all_pin("/soc/s_cir", "pinctrl-0")) {
printf("[ir_boot_para] ir gpio failed\n");
return -1;
}
ir_clk_cfg();
ir_reg_cfg();
ir_reset_rawbuffer();
irq_install_handler(AW_IRQ_CIR, ir_recv_irq_service, NULL);
irq_enable(AW_IRQ_CIR);
return 0;
}
void ir_disable(void)
{
irq_disable(AW_IRQ_CIR);
irq_free_handler(AW_IRQ_CIR);
}