369 lines
8.4 KiB
C
Executable File
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);
|
|
}
|