210 lines
4.9 KiB
C
210 lines
4.9 KiB
C
#include "key/key_driver.h"
|
|
#include "device/gpio.h"
|
|
#include "asm/rdec.h"
|
|
#include "app_config.h"
|
|
|
|
#if TCFG_RDEC_KEY_ENABLE
|
|
|
|
/* #define RDEC_DEBUG_ENABLE */
|
|
#ifdef RDEC_DEBUG_ENABLE
|
|
#define rdec_debug(fmt, ...) printf("[RDEC] "fmt, ##__VA_ARGS__)
|
|
#else
|
|
#define rdec_debug(...)
|
|
#endif
|
|
|
|
#define rdec_error(fmt, ...) printf("[RDEC] ERR: "fmt, ##__VA_ARGS__)
|
|
|
|
struct rdec {
|
|
const struct rdec_platform_data *user_data;
|
|
};
|
|
|
|
static struct rdec _rdec;
|
|
|
|
#define __this (&_rdec)
|
|
|
|
static const u8 rdec_hw_sin0[RDEC_MODULE_NUM] = {IO_PORTC_09};
|
|
static const u8 rdec_hw_sin1[RDEC_MODULE_NUM] = {IO_PORTC_10};
|
|
static const u8 rdec_int_index[RDEC_MODULE_NUM] = {IRQ_RDEC_IDX};
|
|
|
|
extern int gpio_rdec_inputchannel(u32 gpio, u8 sel, u8 mode);
|
|
|
|
static JL_RDEC_TypeDef *rdec_get_reg(u8 index)
|
|
{
|
|
switch (index) {
|
|
case RDEC0:
|
|
return JL_RDEC;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static void __rdec_port_init(u8 port)
|
|
{
|
|
gpio_set_pull_down(port, 0);
|
|
gpio_set_pull_up(port, 1);
|
|
gpio_set_die(port, 1);
|
|
gpio_set_direction(port, 1);
|
|
}
|
|
|
|
static void rdec_port_init(const struct rdec_device *rdec)
|
|
{
|
|
switch (rdec->index) {
|
|
case RDEC0:
|
|
if (rdec->sin_port0 == rdec_hw_sin0[0]) {
|
|
JL_IOMAP->CON1 &= ~BIT(12);
|
|
} else {
|
|
gpio_rdec_inputchannel(rdec->sin_port0, 0, 1);
|
|
}
|
|
|
|
if (rdec->sin_port1 == rdec_hw_sin1[0]) {
|
|
JL_IOMAP->CON1 &= ~BIT(13);
|
|
} else {
|
|
gpio_rdec_inputchannel(rdec->sin_port1, 1, 1);
|
|
}
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
|
|
__rdec_port_init(rdec->sin_port0);
|
|
__rdec_port_init(rdec->sin_port1);
|
|
}
|
|
|
|
static u8 rdec_get_key_value(u8 index, u8 key_num)
|
|
{
|
|
for (u8 i = 0; i < __this->user_data->num; i++) {
|
|
if (index == __this->user_data->rdec[i].index) {
|
|
if (key_num == 0) {
|
|
return __this->user_data->rdec[i].key_value0;
|
|
} else if (key_num == 1) {
|
|
return __this->user_data->rdec[i].key_value1;
|
|
}
|
|
}
|
|
}
|
|
return 0xFF;
|
|
}
|
|
|
|
___interrupt
|
|
static void rdec_isr(void)
|
|
{
|
|
u8 i;
|
|
s8 rdat = 0;
|
|
u8 key_value;
|
|
JL_RDEC_TypeDef *reg = NULL;
|
|
|
|
for (i = 0; i < RDEC_MODULE_NUM; i++) {
|
|
reg = rdec_get_reg(i);
|
|
if (reg->CON & BIT(7)) {
|
|
rdat = reg->DAT;
|
|
reg->CON |= BIT(6); //clr pending, DAT reg will reset as well
|
|
if (rdat < 0) {
|
|
key_value = rdec_get_key_value(i, 0);
|
|
} else if (rdat > 0) {
|
|
key_value = rdec_get_key_value(i, 1);
|
|
} else {
|
|
key_value = 0xFF;
|
|
}
|
|
if (key_value != 0xFF) {
|
|
//TODO: notify rdec event
|
|
rdec_debug("RDEC%d isr, key_value: %d, dat: %d", i, key_value, rdat);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
s8 get_rdec_rdat(int i)
|
|
{
|
|
JL_RDEC_TypeDef *reg = NULL;
|
|
s8 _rdat = 0;
|
|
reg = rdec_get_reg(i);
|
|
if (reg->CON & BIT(7)) {
|
|
_rdat = reg->DAT;
|
|
reg->CON |= BIT(6);
|
|
}
|
|
if (_rdat != 0) {
|
|
rdec_debug("RDEC: %d , dat: %d", i, _rdat);
|
|
}
|
|
return _rdat;
|
|
}
|
|
|
|
static void log_rdec_info(void)
|
|
{
|
|
JL_RDEC_TypeDef *reg = NULL;
|
|
|
|
for (u8 i = 0; i < RDEC_MODULE_NUM; i++) {
|
|
reg = rdec_get_reg(i);
|
|
rdec_debug("RDEC%d CON = 0x%x", i, reg->CON);
|
|
}
|
|
}
|
|
|
|
static int rdec_param_cfg_check(const struct rdec_platform_data *user_data)
|
|
{
|
|
const struct rdec_device *rdec;
|
|
|
|
u8 input_ch6_sta = 0;
|
|
u8 input_ch7_sta = 0;
|
|
|
|
if (user_data->enable == 0) {
|
|
rdec_error("rdec not enable");
|
|
}
|
|
//port check
|
|
for (u8 i = 0; i < user_data->num; i++) {
|
|
rdec = &(user_data->rdec[i]);
|
|
ASSERT(rdec->index < RDEC_MODULE_NUM, "RDEC cfg index err");
|
|
|
|
if (rdec->sin_port0 != rdec_hw_sin0[rdec->index]) {
|
|
input_ch6_sta++;
|
|
}
|
|
if (rdec->sin_port1 != rdec_hw_sin1[rdec->index]) {
|
|
input_ch7_sta++;
|
|
}
|
|
}
|
|
|
|
if ((input_ch6_sta >= 2) || (input_ch7_sta >= 2)) {
|
|
rdec_error("rdec input channel not enough");
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int rdec_init(const struct rdec_platform_data *user_data)
|
|
{
|
|
JL_RDEC_TypeDef *reg = NULL;
|
|
const struct rdec_device *rdec;
|
|
|
|
if (user_data == NULL) {
|
|
return -1;
|
|
}
|
|
|
|
if (rdec_param_cfg_check(user_data)) {
|
|
return -1;
|
|
}
|
|
|
|
for (u8 i = 0; i < user_data->num; i++) {
|
|
rdec = &(user_data->rdec[i]);
|
|
|
|
rdec_port_init(rdec);
|
|
//module init
|
|
reg = rdec_get_reg(rdec->index);
|
|
reg->CON = 0;
|
|
reg->CON |= (0xf << 2); //2^15, lsb = 53MHz, 2^15 / 53us = 618us = 0.618ms
|
|
reg->CON &= ~BIT(1); //pol = 0, io should pull up
|
|
//reg->CON |= BIT(1); //pol = 1, io should pull down
|
|
reg->CON |= BIT(6); //clear pending
|
|
reg->CON |= BIT(0); //RDECx EN
|
|
|
|
/* request_irq(rdec_int_index[rdec->index], 1, rdec_isr, 0); */
|
|
}
|
|
|
|
__this->user_data = user_data;
|
|
|
|
log_rdec_info();
|
|
|
|
return 0;
|
|
}
|
|
|
|
#endif
|