mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-08 20:07:46 +09:00
ir: add ir learning function [1/1]
PD#SWPL-4130 Problem: No ir learning function in current source code Solution: Provide two ways to use ir learning function 1. sysfs /*start learning*/ echo 1 > /sys/class/remote/amremote/ir_learnning /*get data*/ cat /sys/class/remote/amremote/learned_pulse /*stop learning*/ echo 0 > /sys/class/remote/amremote/ir_learnning 2. ioctl /*start/stop learnning 1/0*/ REMOTE_IOC_SET_IR_LEARING /*get raw data*/ REMOTE_IOC_GET_RAW_DATA Verify: U200 and W400 Change-Id: Ibb03838402d9baa6e910b3162ffcc63b57048890 Signed-off-by: Qianggui Song <qianggui.song@amlogic.com>
This commit is contained in:
@@ -86,5 +86,10 @@ struct ir_sw_decode_para {
|
||||
#define REMOTE_IOC_SET_KEY_MAPPING_TAB _IOW('I', 4, __u32)
|
||||
#define REMOTE_IOC_SET_SW_DECODE_PARA _IOW('I', 5, __u32)
|
||||
#define REMOTE_IOC_GET_DATA_VERSION _IOR('I', 121, __u32)
|
||||
#define REMOTE_IOC_SET_IR_LEARNING _IOW('I', 6, __u32)
|
||||
#define REMOTE_IOC_GET_IR_LEARNING _IOR('I', 7, __u32)
|
||||
#define REMOTE_IOC_GET_RAW_DATA _IOR('I', 8, __u32)
|
||||
#define REMOTE_IOC_GET_SUM_CNT0 _IOR('I', 9, __u32)
|
||||
#define REMOTE_IOC_GET_SUM_CNT1 _IOR('I', 10, __u32)
|
||||
|
||||
#endif
|
||||
|
||||
@@ -48,6 +48,7 @@ static long remote_ioctl(struct file *file, unsigned int cmd,
|
||||
void __user *parg = (void __user *)arg;
|
||||
unsigned long flags;
|
||||
u32 value;
|
||||
u8 val;
|
||||
int retval = 0;
|
||||
|
||||
if (!parg) {
|
||||
@@ -133,6 +134,93 @@ static long remote_ioctl(struct file *file, unsigned int cmd,
|
||||
}
|
||||
chip->r_dev->max_frame_time = sw_data.max_frame_time;
|
||||
break;
|
||||
case REMOTE_IOC_GET_IR_LEARNING:
|
||||
if (copy_to_user(parg, &chip->r_dev->ir_learning_on,
|
||||
sizeof(u8))) {
|
||||
retval = -EFAULT;
|
||||
goto err;
|
||||
}
|
||||
break;
|
||||
|
||||
case REMOTE_IOC_SET_IR_LEARNING:
|
||||
/*reset demudolation and carrier detect*/
|
||||
if (chip->r_dev->demod_enable)
|
||||
demod_reset(chip);
|
||||
|
||||
if (copy_from_user(&val, parg, sizeof(u8))) {
|
||||
retval = -EFAULT;
|
||||
goto err;
|
||||
}
|
||||
|
||||
chip->r_dev->ir_learning_on = !!val;
|
||||
if (!!val) {
|
||||
if (remote_pulses_malloc(chip) < 0) {
|
||||
retval = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
chip->set_register_config(chip, REMOTE_TYPE_RAW_NEC);
|
||||
/*backup protocol*/
|
||||
chip->r_dev->protocol = chip->protocol;
|
||||
chip->protocol = REMOTE_TYPE_RAW_NEC;
|
||||
} else {
|
||||
chip->protocol = chip->r_dev->protocol;
|
||||
chip->set_register_config(chip, chip->protocol);
|
||||
remote_pulses_free(chip);
|
||||
chip->r_dev->ir_learning_done = false;
|
||||
}
|
||||
break;
|
||||
|
||||
case REMOTE_IOC_GET_RAW_DATA:
|
||||
if (copy_to_user(parg, chip->r_dev->pulses,
|
||||
sizeof(struct pulse_group) +
|
||||
chip->r_dev->max_learned_pulse *
|
||||
sizeof(unsigned int))) {
|
||||
retval = -EFAULT;
|
||||
goto err;
|
||||
}
|
||||
/*clear to prepear next frame*/
|
||||
memset(chip->r_dev->pulses, 0, sizeof(struct pulse_group) +
|
||||
chip->r_dev->max_learned_pulse *
|
||||
sizeof(unsigned int));
|
||||
|
||||
if (chip->r_dev->demod_enable)
|
||||
demod_reset(chip);
|
||||
|
||||
/*finish reading data ,enable state machine */
|
||||
remote_reg_update_bits(chip, MULTI_IR_ID, REG_REG1, BIT(15),
|
||||
BIT(15));
|
||||
|
||||
chip->r_dev->ir_learning_done = false;
|
||||
|
||||
break;
|
||||
|
||||
case REMOTE_IOC_GET_SUM_CNT0:
|
||||
if (chip->r_dev->demod_enable) {
|
||||
remote_reg_read(chip, MULTI_IR_ID, REG_DEMOD_SUM_CNT0,
|
||||
&value);
|
||||
if (copy_to_user(parg, &value, sizeof(u32))) {
|
||||
retval = -EFAULT;
|
||||
goto err;
|
||||
}
|
||||
} else {
|
||||
retval = -EFAULT;
|
||||
goto err;
|
||||
}
|
||||
break;
|
||||
|
||||
case REMOTE_IOC_GET_SUM_CNT1:
|
||||
if (chip->r_dev->demod_enable) {
|
||||
remote_reg_read(chip, MULTI_IR_ID, REG_DEMOD_SUM_CNT1,
|
||||
&value);
|
||||
if (copy_to_user(parg, &value, sizeof(u32))) {
|
||||
retval = -EFAULT;
|
||||
goto err;
|
||||
}
|
||||
} else {
|
||||
retval = -EFAULT;
|
||||
goto err;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
retval = -ENOTTY;
|
||||
|
||||
@@ -58,7 +58,11 @@ enum raw_event_type {
|
||||
RAW_STOP_EVENT = (1 << 3),
|
||||
};
|
||||
|
||||
|
||||
struct pulse_group {
|
||||
int len;
|
||||
/*bit 0-30 durations, bit31: level*/
|
||||
unsigned int pulse[0];
|
||||
};
|
||||
|
||||
struct remote_raw_handle;
|
||||
struct remote_dev {
|
||||
@@ -75,6 +79,19 @@ struct remote_dev {
|
||||
unsigned long delay_off;
|
||||
int led_blink;
|
||||
|
||||
/*for ir learnning feature*/
|
||||
#define MAX_LEARNED_PULSE 256
|
||||
/*ir learnning switch*/
|
||||
u8 ir_learning_on;
|
||||
u8 ir_learning_done;
|
||||
u8 demod_enable;
|
||||
u8 use_fifo;
|
||||
u8 auto_report;
|
||||
int max_learned_pulse;
|
||||
int protocol;
|
||||
struct timer_list learning_done;
|
||||
struct pulse_group *pulses;
|
||||
|
||||
struct timer_list timer_keyup;
|
||||
unsigned long keyup_jiffies;
|
||||
unsigned long keyup_delay;
|
||||
|
||||
@@ -44,10 +44,51 @@
|
||||
#include <linux/amlogic/scpi_protocol.h>
|
||||
|
||||
static void amlremote_tasklet(unsigned long data);
|
||||
|
||||
static void learning_done_workqueue(struct work_struct *work);
|
||||
static void get_fifo_data_work(struct work_struct *work);
|
||||
|
||||
DECLARE_TASKLET_DISABLED(tasklet, amlremote_tasklet, 0);
|
||||
|
||||
static void learning_done_workqueue(struct work_struct *work)
|
||||
{
|
||||
struct delayed_work *w = container_of(work, struct delayed_work, work);
|
||||
struct remote_chip *chip =
|
||||
container_of(w, struct remote_chip, ir_workqueue);
|
||||
char *envp[2] = { "LEARN_DONE", NULL};
|
||||
|
||||
kobject_uevent_env(&chip->dev->kobj, KOBJ_CHANGE, envp);
|
||||
}
|
||||
|
||||
int remote_pulses_malloc(struct remote_chip *chip)
|
||||
{
|
||||
struct remote_dev *r_dev = chip->r_dev;
|
||||
int len = r_dev->max_learned_pulse;
|
||||
int ret = 0;
|
||||
|
||||
if (r_dev->pulses) {
|
||||
dev_info(chip->dev, "ir learning pulse already exists\n");
|
||||
return -EEXIST;
|
||||
}
|
||||
|
||||
r_dev->pulses = kzalloc(sizeof(struct pulse_group) +
|
||||
len * sizeof(unsigned int), GFP_KERNEL);
|
||||
|
||||
if (!r_dev->pulses) {
|
||||
dev_err(chip->dev, "ir learning pulse alloc err\n");
|
||||
ret = -ENOMEM;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void remote_pulses_free(struct remote_chip *chip)
|
||||
{
|
||||
struct remote_dev *r_dev = chip->r_dev;
|
||||
|
||||
kfree(r_dev->pulses);
|
||||
r_dev->pulses = NULL;
|
||||
}
|
||||
|
||||
int remote_reg_read(struct remote_chip *chip, unsigned char id,
|
||||
unsigned int reg, unsigned int *val)
|
||||
{
|
||||
@@ -74,6 +115,19 @@ int remote_reg_write(struct remote_chip *chip, unsigned char id,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int remote_reg_update_bits(struct remote_chip *chip, unsigned char id,
|
||||
unsigned int reg, unsigned int mask, unsigned int val)
|
||||
{
|
||||
int orig = 0;
|
||||
|
||||
remote_reg_read(chip, id, reg, &orig);
|
||||
orig &= ~mask;
|
||||
orig |= val & mask;
|
||||
remote_reg_write(chip, id, reg, orig);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ir_scancode_sort(struct ir_map_tab *ir_map)
|
||||
{
|
||||
bool is_sorted;
|
||||
@@ -301,9 +355,64 @@ static void amlremote_tasklet(unsigned long data)
|
||||
|
||||
}
|
||||
|
||||
static void get_fifo_data_work(struct work_struct *work)
|
||||
{
|
||||
struct remote_chip *chip =
|
||||
container_of(work, struct remote_chip, fifo_work);
|
||||
struct remote_dev *r_dev = chip->r_dev;
|
||||
int val = 0;
|
||||
int is_fifo_pending = 0;
|
||||
int is_fifo_timeout = 0;
|
||||
int is_fifo_empty = 0;
|
||||
u32 duration = 0;
|
||||
|
||||
remote_reg_read(chip, MULTI_IR_ID, REG_FIFO, &val);
|
||||
is_fifo_pending = (val >> 30) & 0x01;
|
||||
is_fifo_timeout = (val >> 29) & 0x01;
|
||||
is_fifo_empty = (val >> 27) & 0x01;
|
||||
|
||||
/*disable interrupt*/
|
||||
remote_reg_update_bits(chip, MULTI_IR_ID, REG_FIFO, GENMASK(22, 23), 0);
|
||||
|
||||
if (is_fifo_pending || is_fifo_timeout) {
|
||||
/*clear state*/
|
||||
remote_reg_update_bits(chip, MULTI_IR_ID, REG_FIFO,
|
||||
GENMASK(29, 30), GENMASK(29, 30));
|
||||
|
||||
for (; !is_fifo_empty; ) {
|
||||
|
||||
remote_reg_read(chip, MULTI_IR_ID, REG_WITH, &val);
|
||||
val = val & GENMASK(12, 0);
|
||||
|
||||
duration = val;
|
||||
r_dev->pulses->pulse[r_dev->pulses->len] = duration;
|
||||
|
||||
if (r_dev->pulses->len % 2 == 1)
|
||||
r_dev->pulses->pulse[r_dev->pulses->len]
|
||||
|= BIT(31);
|
||||
|
||||
r_dev->pulses->len++;
|
||||
|
||||
remote_reg_read(chip, MULTI_IR_ID, REG_FIFO, &val);
|
||||
is_fifo_empty = (val >> 27) & 0x01;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/*enable interrupt*/
|
||||
remote_reg_update_bits(chip, MULTI_IR_ID, REG_FIFO, GENMASK(22, 23),
|
||||
GENMASK(22, 23));
|
||||
|
||||
if (r_dev->auto_report)
|
||||
mod_timer(&r_dev->learning_done,
|
||||
jiffies + msecs_to_jiffies(50));
|
||||
}
|
||||
|
||||
static irqreturn_t ir_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
struct remote_chip *rc = (struct remote_chip *)dev_id;
|
||||
struct remote_dev *r_dev = rc->r_dev;
|
||||
struct pulse_group *pgs;
|
||||
int contr_status = 0;
|
||||
int val = 0;
|
||||
u32 duration;
|
||||
@@ -313,12 +422,40 @@ static irqreturn_t ir_interrupt(int irq, void *dev_id)
|
||||
|
||||
remote_reg_read(rc, MULTI_IR_ID, REG_REG1, &val);
|
||||
val = (val & 0x1FFF0000) >> 16;
|
||||
sprintf(buf, "d:%d\n", val);
|
||||
sprintf(buf, "duration:%d\n", val);
|
||||
debug_log_printk(rc->r_dev, buf);
|
||||
/**
|
||||
*software decode multiple protocols by using Time Measurement of
|
||||
*multif-format IR controller
|
||||
*/
|
||||
|
||||
if (r_dev->ir_learning_on && !r_dev->ir_learning_done) {
|
||||
pgs = r_dev->pulses;
|
||||
if (pgs->len >= r_dev->max_learned_pulse) {
|
||||
remote_reg_update_bits(rc, MULTI_IR_ID, REG_REG1,
|
||||
BIT(15), 0);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
if (!r_dev->use_fifo) {
|
||||
if (r_dev->auto_report)
|
||||
mod_timer(&r_dev->learning_done,
|
||||
jiffies + msecs_to_jiffies(50));
|
||||
/*get pulse durations unit:10us*/
|
||||
pgs->pulse[pgs->len] = val & GENMASK(30, 0);
|
||||
/*get pulse level*/
|
||||
remote_reg_read(rc, MULTI_IR_ID, REG_STATUS, &val);
|
||||
val = !!((val >> 8) & 0x01);
|
||||
pgs->pulse[pgs->len] &= ~BIT(31);
|
||||
if (val)
|
||||
pgs->pulse[pgs->len] |= BIT(31);
|
||||
|
||||
r_dev->pulses->len++;
|
||||
} else {
|
||||
schedule_work(&rc->fifo_work);
|
||||
}
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
if (MULTI_IR_SOFTWARE_DECODE(rc->protocol)) {
|
||||
rc->ir_work = MULTI_IR_ID;
|
||||
duration = val*10*1000;
|
||||
@@ -516,6 +653,18 @@ static int ir_get_devtree_pdata(struct platform_device *pdev)
|
||||
}
|
||||
dev_info(chip->dev, "led_blink_frq = %ld\n", chip->r_dev->delay_on);
|
||||
|
||||
ret = of_property_read_bool(pdev->dev.of_node, "demod_enable");
|
||||
if (ret)
|
||||
chip->r_dev->demod_enable = 1;
|
||||
|
||||
ret = of_property_read_bool(pdev->dev.of_node, "use_fifo");
|
||||
if (ret)
|
||||
chip->r_dev->use_fifo = 1;
|
||||
|
||||
ret = of_property_read_bool(pdev->dev.of_node, "auto_report");
|
||||
if (ret)
|
||||
chip->r_dev->auto_report = 1;
|
||||
|
||||
p = devm_pinctrl_get_select_default(&pdev->dev);
|
||||
if (IS_ERR(p)) {
|
||||
dev_err(chip->dev, "pinctrl error, %ld\n", PTR_ERR(p));
|
||||
@@ -562,6 +711,47 @@ static int ir_get_devtree_pdata(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void demod_init(struct remote_chip *chip)
|
||||
{
|
||||
int val;
|
||||
unsigned int mask;
|
||||
|
||||
mask = GENMASK(29, 16) | BIT(31);
|
||||
val = BIT(31) | (0x1FF << 16);
|
||||
|
||||
remote_reg_update_bits(chip, MULTI_IR_ID, REG_DEMOD_CNTL1, mask, val);
|
||||
}
|
||||
|
||||
void demod_reset(struct remote_chip *chip)
|
||||
{
|
||||
unsigned int mask;
|
||||
|
||||
mask = BIT(30);
|
||||
remote_reg_update_bits(chip, MULTI_IR_ID, REG_DEMOD_CNTL0, mask, mask);
|
||||
}
|
||||
|
||||
static void ir_learning_done(unsigned long cookie)
|
||||
{
|
||||
|
||||
struct remote_dev *dev = (struct remote_dev *)cookie;
|
||||
struct remote_chip *chip = (struct remote_chip *) dev->platform_data;
|
||||
unsigned long flags;
|
||||
|
||||
if (dev->pulses->len < 3) {
|
||||
dev->pulses->len = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&chip->slock, flags);
|
||||
dev->ir_learning_done = true;
|
||||
spin_unlock_irqrestore(&chip->slock, flags);
|
||||
|
||||
/*data recive done*/
|
||||
remote_reg_update_bits(chip, MULTI_IR_ID, REG_REG1, BIT(15), 0);
|
||||
schedule_delayed_work(&chip->ir_workqueue, msecs_to_jiffies(100));
|
||||
|
||||
}
|
||||
|
||||
static int ir_hardware_init(struct platform_device *pdev)
|
||||
{
|
||||
int ret;
|
||||
@@ -654,6 +844,7 @@ static int remote_probe(struct platform_device *pdev)
|
||||
chip->r_dev->set_custom_code = set_custom_code;
|
||||
chip->r_dev->is_valid_custom = is_valid_custom;
|
||||
chip->r_dev->is_next_repeat = is_next_repeat;
|
||||
chip->r_dev->max_learned_pulse = MAX_LEARNED_PULSE;
|
||||
chip->set_register_config = ir_register_default_config;
|
||||
platform_set_drvdata(pdev, chip);
|
||||
|
||||
@@ -677,6 +868,11 @@ static int remote_probe(struct platform_device *pdev)
|
||||
|
||||
led_trigger_register_simple("rc_feedback", &dev->led_feedback);
|
||||
|
||||
setup_timer(&dev->learning_done, ir_learning_done, (unsigned long)dev);
|
||||
if (dev->demod_enable)
|
||||
demod_init(chip);
|
||||
INIT_DELAYED_WORK(&chip->ir_workqueue, learning_done_workqueue);
|
||||
INIT_WORK(&chip->fifo_work, get_fifo_data_work);
|
||||
return 0;
|
||||
|
||||
error_register_remote:
|
||||
@@ -760,6 +956,12 @@ static int remote_suspend(struct device *dev)
|
||||
{
|
||||
struct remote_chip *chip = dev_get_drvdata(dev);
|
||||
|
||||
if (chip->r_dev->ir_learning_on) {
|
||||
cancel_work_sync(&chip->fifo_work);
|
||||
del_timer_sync(&chip->r_dev->learning_done);
|
||||
cancel_delayed_work_sync(&chip->ir_workqueue);
|
||||
}
|
||||
|
||||
if (is_pm_freeze_mode())
|
||||
return 0;
|
||||
|
||||
|
||||
@@ -25,8 +25,13 @@
|
||||
|
||||
#define IR_DATA_IS_VALID(data) (data & 0x8)
|
||||
#define IR_CONTROLLER_BUSY(x) ((x >> 7) & 0x1)
|
||||
|
||||
#define CURSOR_MOVE_ACCELERATE {0, 2, 2, 4, 4, 6, 8, 10, 12, 14, 16, 18}
|
||||
/*bit 31: enable fifo mode
|
||||
* bit 21-23: time out/level trigger interrupt
|
||||
* bit 13-20: trigger interrupt when receive specified numbers of pulse
|
||||
* bit 0-12: trigger interrupt when time out
|
||||
*/
|
||||
#define FIFO_REG_VAL ((1 << 31) | (7 << 21) | (80 << 13) | (5000 << 0))
|
||||
|
||||
enum IR_CONTR_NUMBER {
|
||||
MULTI_IR_ID = 0,
|
||||
@@ -104,6 +109,8 @@ struct remote_chip {
|
||||
struct remote_range reg_duration;
|
||||
char *dev_name;
|
||||
int protocol;
|
||||
struct delayed_work ir_workqueue;
|
||||
struct work_struct fifo_work;
|
||||
|
||||
dev_t chr_devno;
|
||||
struct class *chr_class;
|
||||
@@ -167,27 +174,36 @@ enum {
|
||||
};
|
||||
|
||||
enum remote_reg {
|
||||
REG_LDR_ACTIVE = 0x00 << 2,
|
||||
REG_LDR_IDLE = 0x01 << 2,
|
||||
REG_LDR_REPEAT = 0x02 << 2,
|
||||
REG_BIT_0 = 0x03 << 2,
|
||||
REG_REG0 = 0x04 << 2,
|
||||
REG_FRAME = 0x05 << 2,
|
||||
REG_STATUS = 0x06 << 2,
|
||||
REG_REG1 = 0x07 << 2,
|
||||
REG_REG2 = 0x08 << 2,
|
||||
REG_DURATN2 = 0x09 << 2,
|
||||
REG_DURATN3 = 0x0a << 2,
|
||||
REG_FRAME1 = 0x0b << 2,
|
||||
REG_STATUS1 = 0x0c << 2,
|
||||
REG_STATUS2 = 0x0d << 2,
|
||||
REG_REG3 = 0x0e << 2,
|
||||
REG_FRAME_RSV0 = 0x0f << 2,
|
||||
REG_FRAME_RSV1 = 0x10 << 2,
|
||||
REG_FILTE = 0x11 << 2,
|
||||
REG_IRQ_CTL = 0x12 << 2,
|
||||
REG_WIDTH_NEW = 0x14 << 2,
|
||||
REG_REPEAT_DET = 0x15 << 2
|
||||
REG_LDR_ACTIVE = 0x00 << 2,
|
||||
REG_LDR_IDLE = 0x01 << 2,
|
||||
REG_LDR_REPEAT = 0x02 << 2,
|
||||
REG_BIT_0 = 0x03 << 2,
|
||||
REG_REG0 = 0x04 << 2,
|
||||
REG_FRAME = 0x05 << 2,
|
||||
REG_STATUS = 0x06 << 2,
|
||||
REG_REG1 = 0x07 << 2,
|
||||
REG_REG2 = 0x08 << 2,
|
||||
REG_DURATN2 = 0x09 << 2,
|
||||
REG_DURATN3 = 0x0a << 2,
|
||||
REG_FRAME1 = 0x0b << 2,
|
||||
REG_STATUS1 = 0x0c << 2,
|
||||
REG_STATUS2 = 0x0d << 2,
|
||||
REG_REG3 = 0x0e << 2,
|
||||
REG_FRAME_RSV0 = 0x0f << 2,
|
||||
REG_FRAME_RSV1 = 0x10 << 2,
|
||||
REG_IRQ_CTL = 0x12 << 2,
|
||||
REG_FIFO = 0x13 << 2,
|
||||
REG_WITH = 0x14 << 2,
|
||||
REG_REPEAT_DET = 0x15 << 2,
|
||||
REG_DEMOD_CNTL0 = 0x20 << 2,
|
||||
REG_DEMOD_CNTL1 = 0x21 << 2,
|
||||
REG_DEMOD_IIR_THD = 0x22 << 2,
|
||||
REG_DEMOD_THD0 = 0x23 << 2,
|
||||
REG_DEMOD_THD1 = 0x24 << 2,
|
||||
REG_DEMOD_SUM_CNT0 = 0x25 << 2,
|
||||
REG_DEMOD_SUM_CNT1 = 0x26 << 2,
|
||||
REG_DEMOD_CNT0 = 0x27 << 2,
|
||||
REG_DEMOD_CNT1 = 0x28 << 2
|
||||
};
|
||||
|
||||
int ir_register_default_config(struct remote_chip *chip, int type);
|
||||
@@ -199,11 +215,18 @@ int remote_reg_read(struct remote_chip *chip, unsigned char id,
|
||||
unsigned int reg, unsigned int *val);
|
||||
int remote_reg_write(struct remote_chip *chip, unsigned char id,
|
||||
unsigned int reg, unsigned int val);
|
||||
int remote_reg_update_bits(struct remote_chip *chip, unsigned char id,
|
||||
unsigned int reg, unsigned int mask, unsigned int val);
|
||||
int ir_scancode_sort(struct ir_map_tab *ir_map);
|
||||
struct ir_map_tab_list *seek_map_tab(struct remote_chip *chip, int custom_code);
|
||||
const struct aml_remote_reg_proto **ir_get_proto_reg(void);
|
||||
void ir_tab_free(struct ir_map_tab_list *ir_map_list);
|
||||
|
||||
#if defined(CONFIG_IR_HK_LIRC_HELPER)
|
||||
extern void remote_wakeup_decode_type(int dec_type);
|
||||
#endif
|
||||
int remote_pulses_malloc(struct remote_chip *chip);
|
||||
void remote_pulses_free(struct remote_chip *chip);
|
||||
void demod_reset(struct remote_chip *chip);
|
||||
void demod_init(struct remote_chip *chip);
|
||||
#endif
|
||||
|
||||
@@ -88,7 +88,7 @@ static struct remote_reg_map regs_default_nec_sw[] = {
|
||||
{ REG_LDR_IDLE, 0},
|
||||
{ REG_LDR_REPEAT, 0},
|
||||
{ REG_BIT_0, 0},
|
||||
{ REG_REG0, ((3 << 28) | (0xFA0 << 12) | (9))},
|
||||
{ REG_REG0, ((7 << 28) | (0xFA0 << 12) | (9))},
|
||||
{ REG_STATUS, 0},
|
||||
{ REG_REG1, 0x8574},
|
||||
{ REG_REG2, 0x02},
|
||||
@@ -630,6 +630,11 @@ const struct aml_remote_reg_proto *remote_reg_proto[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
const struct aml_remote_reg_proto **ir_get_proto_reg(void)
|
||||
{
|
||||
return remote_reg_proto;
|
||||
}
|
||||
|
||||
static int ir_contr_init(struct remote_chip *chip, int type, unsigned char id)
|
||||
{
|
||||
const struct aml_remote_reg_proto **reg_proto = remote_reg_proto;
|
||||
@@ -684,6 +689,11 @@ static int ir_contr_init(struct remote_chip *chip, int type, unsigned char id)
|
||||
chip->ir_contr[id].get_custom_code = (*reg_proto)->get_custom_code;
|
||||
chip->ir_contr[id].set_custom_code = (*reg_proto)->set_custom_code;
|
||||
|
||||
if (chip->r_dev->ir_learning_on && chip->r_dev->use_fifo)
|
||||
remote_reg_write(chip, id, REG_FIFO, FIFO_REG_VAL);
|
||||
else
|
||||
remote_reg_write(chip, id, REG_FIFO, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -43,16 +43,29 @@ static ssize_t protocol_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct remote_chip *chip = dev_get_drvdata(dev);
|
||||
const struct aml_remote_reg_proto **supported_proto =
|
||||
ir_get_proto_reg();
|
||||
int len;
|
||||
|
||||
if (ENABLE_LEGACY_IR(chip->protocol))
|
||||
return sprintf(buf, "protocol=%s&%s (0x%x)\n",
|
||||
len = sprintf(buf, "current protocol = %s&%s (0x%x)\n",
|
||||
chip->ir_contr[LEGACY_IR_ID].proto_name,
|
||||
chip->ir_contr[MULTI_IR_ID].proto_name,
|
||||
chip->protocol);
|
||||
else
|
||||
len = sprintf(buf, "currnet protocol = %s (0x%x)\n",
|
||||
chip->ir_contr[MULTI_IR_ID].proto_name,
|
||||
chip->protocol);
|
||||
|
||||
return sprintf(buf, "protocol=%s (0x%x)\n",
|
||||
chip->ir_contr[MULTI_IR_ID].proto_name,
|
||||
chip->protocol);
|
||||
len += sprintf(buf + len, "supported protocol:\n");
|
||||
|
||||
for ( ; (*supported_proto) != NULL ; ) {
|
||||
len += sprintf(buf + len, "%s (0x%x)\n",
|
||||
((*supported_proto)->name), ((*supported_proto)->protocol));
|
||||
supported_proto++;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static ssize_t protocol_store(struct device *dev,
|
||||
@@ -308,6 +321,169 @@ static ssize_t led_frq_store(struct device *dev,
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t ir_learning_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
|
||||
struct remote_chip *chip = dev_get_drvdata(dev);
|
||||
struct remote_dev *r_dev = chip->r_dev;
|
||||
|
||||
return sprintf(buf, "%d\n", r_dev->ir_learning_on);
|
||||
}
|
||||
|
||||
static ssize_t ir_learning_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
int ret = 0;
|
||||
int val = 0;
|
||||
|
||||
struct remote_chip *chip = dev_get_drvdata(dev);
|
||||
struct remote_dev *r_dev = chip->r_dev;
|
||||
|
||||
ret = kstrtoint(buf, 0, &val);
|
||||
if (ret != 0)
|
||||
return -EINVAL;
|
||||
if (r_dev->ir_learning_on == val)
|
||||
return count;
|
||||
|
||||
disable_irq(chip->irqno);
|
||||
mutex_lock(&chip->file_lock);
|
||||
r_dev->ir_learning_on = !!val;
|
||||
if (!!val) {
|
||||
if (r_dev->demod_enable)
|
||||
demod_reset(chip);
|
||||
|
||||
if (remote_pulses_malloc(chip) < 0) {
|
||||
mutex_unlock(&chip->file_lock);
|
||||
enable_irq(chip->irqno);
|
||||
return -ENOMEM;
|
||||
}
|
||||
chip->set_register_config(chip, REMOTE_TYPE_RAW_NEC);
|
||||
r_dev->protocol = chip->protocol;/*backup protocol*/
|
||||
chip->protocol = REMOTE_TYPE_RAW_NEC;
|
||||
} else {
|
||||
chip->protocol = r_dev->protocol;
|
||||
chip->set_register_config(chip, chip->protocol);
|
||||
remote_pulses_free(chip);
|
||||
chip->r_dev->ir_learning_done = false;
|
||||
}
|
||||
mutex_unlock(&chip->file_lock);
|
||||
enable_irq(chip->irqno);
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t learned_pulse_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
int len = 0;
|
||||
int i = 0;
|
||||
|
||||
struct remote_chip *chip = dev_get_drvdata(dev);
|
||||
struct remote_dev *r_dev = chip->r_dev;
|
||||
|
||||
if (!r_dev->pulses)
|
||||
return len;
|
||||
|
||||
disable_irq(chip->irqno);
|
||||
mutex_lock(&chip->file_lock);
|
||||
for (i = 0; i < r_dev->pulses->len; i++)
|
||||
len += sprintf(buf + len, "%lds",
|
||||
r_dev->pulses->pulse[i] & GENMASK(30, 0));
|
||||
|
||||
len += sprintf(buf + len, "\n");
|
||||
|
||||
remote_reg_update_bits(chip, MULTI_IR_ID, REG_REG1, BIT(15), BIT(15));
|
||||
|
||||
r_dev->ir_learning_done = false;
|
||||
|
||||
mutex_unlock(&chip->file_lock);
|
||||
enable_irq(chip->irqno);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static ssize_t learned_pulse_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct remote_chip *chip = dev_get_drvdata(dev);
|
||||
struct remote_dev *r_dev = chip->r_dev;
|
||||
|
||||
if (!r_dev->pulses)
|
||||
return count;
|
||||
|
||||
disable_irq(chip->irqno);
|
||||
mutex_lock(&chip->file_lock);
|
||||
if (buf[0] == 'c') {
|
||||
memset(r_dev->pulses, 0, sizeof(struct pulse_group) +
|
||||
r_dev->max_learned_pulse * sizeof(u32));
|
||||
remote_reg_update_bits(chip, MULTI_IR_ID, REG_REG1, BIT(15),
|
||||
BIT(15));
|
||||
|
||||
r_dev->ir_learning_done = false;
|
||||
}
|
||||
mutex_unlock(&chip->file_lock);
|
||||
enable_irq(chip->irqno);
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t sum_cnt0_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
int val = 0;
|
||||
struct remote_chip *chip = dev_get_drvdata(dev);
|
||||
|
||||
remote_reg_read(chip, MULTI_IR_ID, REG_DEMOD_SUM_CNT0, &val);
|
||||
|
||||
return sprintf(buf, "%d\n", val);
|
||||
}
|
||||
|
||||
static ssize_t sum_cnt1_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
|
||||
int val = 0;
|
||||
struct remote_chip *chip = dev_get_drvdata(dev);
|
||||
|
||||
remote_reg_read(chip, MULTI_IR_ID, REG_DEMOD_SUM_CNT1, &val);
|
||||
|
||||
return sprintf(buf, "%d\n", val);
|
||||
|
||||
}
|
||||
|
||||
static ssize_t use_fifo_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct remote_chip *chip = dev_get_drvdata(dev);
|
||||
|
||||
return sprintf(buf, "%d\n", chip->r_dev->use_fifo);
|
||||
}
|
||||
|
||||
static ssize_t use_fifo_store(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
int val = 0;
|
||||
int len = 0;
|
||||
struct remote_chip *chip = dev_get_drvdata(dev);
|
||||
|
||||
len = kstrtoint(buf, 0, &val);
|
||||
|
||||
if (len != 0) {
|
||||
dev_err(chip->dev, "input parameter error\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
chip->r_dev->use_fifo = val;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
DEVICE_ATTR_RW(use_fifo);
|
||||
DEVICE_ATTR_RO(sum_cnt0);
|
||||
DEVICE_ATTR_RO(sum_cnt1);
|
||||
DEVICE_ATTR_RW(learned_pulse);
|
||||
DEVICE_ATTR_RW(ir_learning);
|
||||
DEVICE_ATTR_RW(led_frq);
|
||||
DEVICE_ATTR_RW(led_blink);
|
||||
DEVICE_ATTR_RW(repeat_enable);
|
||||
@@ -326,6 +502,11 @@ static struct attribute *remote_attrs[] = {
|
||||
&dev_attr_debug_log.attr,
|
||||
&dev_attr_led_blink.attr,
|
||||
&dev_attr_led_frq.attr,
|
||||
&dev_attr_ir_learning.attr,
|
||||
&dev_attr_learned_pulse.attr,
|
||||
&dev_attr_sum_cnt0.attr,
|
||||
&dev_attr_sum_cnt1.attr,
|
||||
&dev_attr_use_fifo.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user