From b480c8fb30ffbcc72698947e3f5feaa3a06a04f4 Mon Sep 17 00:00:00 2001 From: Qianggui Song Date: Fri, 18 Jan 2019 11:26:47 +0800 Subject: [PATCH] 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 --- drivers/amlogic/input/remote/rc_common.h | 5 + drivers/amlogic/input/remote/remote_cdev.c | 88 ++++++++++++ drivers/amlogic/input/remote/remote_core.h | 19 ++- drivers/amlogic/input/remote/remote_meson.c | 206 ++++++++++++++++++++++++++- drivers/amlogic/input/remote/remote_meson.h | 68 ++++++--- drivers/amlogic/input/remote/remote_regmap.c | 12 +- drivers/amlogic/input/remote/sysfs.c | 189 +++++++++++++++++++++++- 7 files changed, 556 insertions(+), 31 deletions(-) diff --git a/drivers/amlogic/input/remote/rc_common.h b/drivers/amlogic/input/remote/rc_common.h index 3420355..fdc6b8f 100644 --- a/drivers/amlogic/input/remote/rc_common.h +++ b/drivers/amlogic/input/remote/rc_common.h @@ -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 diff --git a/drivers/amlogic/input/remote/remote_cdev.c b/drivers/amlogic/input/remote/remote_cdev.c index 60d1be2..ea996e3 100644 --- a/drivers/amlogic/input/remote/remote_cdev.c +++ b/drivers/amlogic/input/remote/remote_cdev.c @@ -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) { @@ -126,6 +127,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; diff --git a/drivers/amlogic/input/remote/remote_core.h b/drivers/amlogic/input/remote/remote_core.h index 6b2d623..b0f7251 100644 --- a/drivers/amlogic/input/remote/remote_core.h +++ b/drivers/amlogic/input/remote/remote_core.h @@ -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; diff --git a/drivers/amlogic/input/remote/remote_meson.c b/drivers/amlogic/input/remote/remote_meson.c index 6a7e416..ea1f0ca 100644 --- a/drivers/amlogic/input/remote/remote_meson.c +++ b/drivers/amlogic/input/remote/remote_meson.c @@ -43,10 +43,51 @@ #include 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) { @@ -73,6 +114,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; @@ -300,9 +354,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; @@ -312,12 +421,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; @@ -505,6 +642,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)); @@ -551,6 +700,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; @@ -643,6 +833,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); @@ -666,6 +857,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: @@ -745,6 +941,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; diff --git a/drivers/amlogic/input/remote/remote_meson.h b/drivers/amlogic/input/remote/remote_meson.h index 60437d1..aa7538a 100644 --- a/drivers/amlogic/input/remote/remote_meson.h +++ b/drivers/amlogic/input/remote/remote_meson.h @@ -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,8 +215,14 @@ 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); - +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 diff --git a/drivers/amlogic/input/remote/remote_regmap.c b/drivers/amlogic/input/remote/remote_regmap.c index 93c9697..f1b506c 100644 --- a/drivers/amlogic/input/remote/remote_regmap.c +++ b/drivers/amlogic/input/remote/remote_regmap.c @@ -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}, @@ -569,6 +569,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; @@ -623,6 +628,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; } diff --git a/drivers/amlogic/input/remote/sysfs.c b/drivers/amlogic/input/remote/sysfs.c index b7df3e5..5bd084c 100644 --- a/drivers/amlogic/input/remote/sysfs.c +++ b/drivers/amlogic/input/remote/sysfs.c @@ -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); + + 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 sprintf(buf, "protocol=%s (0x%x)\n", - chip->ir_contr[MULTI_IR_ID].proto_name, - chip->protocol); + 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, }; -- 2.7.4