blob: d795dcdecdc5fd5a6439b13f7f9f253f0025b165 [file] [log] [blame]
/*
* drivers/amlogic/input/remote/sysfs.c
*
* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
*
* 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 <linux/module.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/types.h>
#include <linux/input.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/mutex.h>
#include <linux/errno.h>
#include <asm/irq.h>
#include <linux/io.h>
#include <linux/major.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/pinctrl/consumer.h>
#include <linux/of_platform.h>
#include <linux/amlogic/cpu_version.h>
#include <linux/of_address.h>
#include "remote_meson.h"
#include <linux/amlogic/iomap.h>
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))
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 len;
}
static ssize_t protocol_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
int ret;
int protocol;
unsigned long flags;
struct remote_chip *chip = dev_get_drvdata(dev);
ret = kstrtoint(buf, 0, &protocol);
if (ret != 0) {
dev_err(chip->dev, "input parameter error\n");
return -EINVAL;
}
spin_lock_irqsave(&chip->slock, flags);
chip->protocol = protocol;
chip->set_register_config(chip, chip->protocol);
if (MULTI_IR_SOFTWARE_DECODE(chip->r_dev->rc_type) &&
!MULTI_IR_SOFTWARE_DECODE(chip->protocol)) {
remote_raw_event_unregister(chip->r_dev); /*raw->no raw*/
dev_info(chip->dev, "remote_raw_event_unregister\n");
} else if (!MULTI_IR_SOFTWARE_DECODE(chip->r_dev->rc_type) &&
MULTI_IR_SOFTWARE_DECODE(chip->protocol)) {
remote_raw_init();
remote_raw_event_register(chip->r_dev); /*no raw->raw*/
}
chip->r_dev->rc_type = chip->protocol;
spin_unlock_irqrestore(&chip->slock, flags);
return count;
}
static ssize_t keymap_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct remote_chip *chip = dev_get_drvdata(dev);
struct ir_map_tab_list *map_tab;
unsigned long flags;
int i, len;
spin_lock_irqsave(&chip->slock, flags);
map_tab = seek_map_tab(chip, chip->sys_custom_code);
if (!map_tab) {
dev_err(chip->dev, "please set valid keymap name first\n");
spin_unlock_irqrestore(&chip->slock, flags);
return 0;
}
len = sprintf(buf, "custom_code=0x%x\n", map_tab->tab.custom_code);
len += sprintf(buf+len, "custom_name=%s\n", map_tab->tab.custom_name);
len += sprintf(buf+len, "release_delay=%d\n",
map_tab->tab.release_delay);
len += sprintf(buf+len, "map_size=%d\n", map_tab->tab.map_size);
len += sprintf(buf+len, "fn_key_scancode = 0x%x\n",
map_tab->tab.cursor_code.fn_key_scancode);
len += sprintf(buf+len, "cursor_left_scancode = 0x%x\n",
map_tab->tab.cursor_code.cursor_left_scancode);
len += sprintf(buf+len, "cursor_right_scancode = 0x%x\n",
map_tab->tab.cursor_code.cursor_right_scancode);
len += sprintf(buf+len, "cursor_up_scancode = 0x%x\n",
map_tab->tab.cursor_code.cursor_up_scancode);
len += sprintf(buf+len, "cursor_down_scancode = 0x%x\n",
map_tab->tab.cursor_code.cursor_down_scancode);
len += sprintf(buf+len, "cursor_ok_scancode = 0x%x\n",
map_tab->tab.cursor_code.cursor_ok_scancode);
len += sprintf(buf+len, "keycode scancode\n");
for (i = 0; i < map_tab->tab.map_size; i++) {
len += sprintf(buf+len, "%4d %4d\n",
map_tab->tab.codemap[i].map.keycode,
map_tab->tab.codemap[i].map.scancode);
}
spin_unlock_irqrestore(&chip->slock, flags);
return len;
}
static ssize_t keymap_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct remote_chip *chip = dev_get_drvdata(dev);
int ret;
int value;
ret = kstrtoint(buf, 0, &value);
if (ret != 0) {
dev_err(chip->dev, "keymap_store input err\n");
return -EINVAL;
}
chip->sys_custom_code = value;
return count;
}
static ssize_t debug_enable_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
int debug_enable;
debug_enable = remote_debug_get_enable();
return sprintf(buf, "%d\n", debug_enable);
}
static ssize_t debug_enable_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
int debug_enable;
int ret;
ret = kstrtoint(buf, 0, &debug_enable);
if (ret != 0)
return -EINVAL;
remote_debug_set_enable(debug_enable);
return count;
}
static ssize_t enable_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
int enable;
enable = remote_get_enable();
return sprintf(buf, "%d\n", enable);
}
static ssize_t enable_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct remote_chip *chip = dev_get_drvdata(dev);
unsigned int val;
int enable;
int ret;
int cnt;
ret = kstrtoint(buf, 0, &enable);
if ((ret != 0) || ((enable != 0) && (enable != 1)))
return -EINVAL;
for (cnt = 0; cnt < (ENABLE_LEGACY_IR(chip->protocol) ? 2 : 1); cnt++) {
if (enable) {
remote_reg_read(chip, cnt, REG_FRAME, &val);
remote_reg_update_bits(chip, cnt, REG_REG1,
BIT(15), BIT(15));
} else {
remote_reg_update_bits(chip, cnt, REG_REG1, BIT(15), 0);
}
}
remote_set_enable(enable);
return count;
}
int debug_log_printk(struct remote_dev *dev, const char *fmt)
{
char *p;
int len;
len = strlen(fmt) + 1;
if (len > dev->debug_buffer_size)
return 0;
if (dev->debug_current + len > dev->debug_buffer_size)
dev->debug_current = 0;
p = (char *)(dev->debug_buffer+dev->debug_current);
strcpy(p, fmt);
dev->debug_current += (len-1);
return 0;
}
static ssize_t debug_log_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;
if (!r_dev->debug_buffer)
return 0;
return sprintf(buf, r_dev->debug_buffer);
}
static ssize_t debug_log_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->debug_buffer)
return 0;
if (buf[0] == 'c') {
r_dev->debug_buffer[0] = 0;
r_dev->debug_current = 0;
}
return count;
}
static ssize_t repeat_enable_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct remote_chip *chip = dev_get_drvdata(dev);
return sprintf(buf, "%u\n", chip->repeat_enable);
}
static ssize_t repeat_enable_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
int ret;
int val;
struct remote_chip *chip = dev_get_drvdata(dev);
ret = kstrtoint(buf, 0, &val);
if (ret != 0)
return -EINVAL;
chip->repeat_enable = val;
return count;
}
static ssize_t map_tables_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct remote_chip *chip = dev_get_drvdata(dev);
struct ir_map_tab_list *ir_map;
unsigned long flags;
int len = 0;
int cnt = 0;
spin_lock_irqsave(&chip->slock, flags);
list_for_each_entry(ir_map, &chip->map_tab_head, list) {
len += sprintf(buf+len, "%d. 0x%x,%s\n",
cnt, ir_map->tab.custom_code, ir_map->tab.custom_name);
cnt++;
}
spin_unlock_irqrestore(&chip->slock, flags);
return len;
}
static ssize_t led_blink_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, "%u\n", r_dev->led_blink);
}
static ssize_t led_blink_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;
r_dev->led_blink = val;
return count;
}
static ssize_t led_frq_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, "%ld\n", r_dev->delay_on);
}
static ssize_t led_frq_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;
r_dev->delay_off = val;
r_dev->delay_on = val;
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;
irq_set_affinity(chip->irqno,
cpumask_of(chip->irq_cpumask));
} 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);
DEVICE_ATTR_RW(protocol);
DEVICE_ATTR_RW(keymap);
DEVICE_ATTR_RW(debug_enable);
DEVICE_ATTR_RW(enable);
DEVICE_ATTR_RW(debug_log);
DEVICE_ATTR_RO(map_tables);
static struct attribute *remote_attrs[] = {
&dev_attr_protocol.attr,
&dev_attr_map_tables.attr,
&dev_attr_keymap.attr,
&dev_attr_debug_enable.attr,
&dev_attr_enable.attr,
&dev_attr_repeat_enable.attr,
&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,
};
ATTRIBUTE_GROUPS(remote);
static struct class remote_class = {
.name = "remote",
.owner = THIS_MODULE,
.dev_groups = remote_groups,
};
int ir_sys_device_attribute_init(struct remote_chip *chip)
{
struct device *dev;
int err;
err = class_register(&remote_class);
if (unlikely(err))
return err;
dev = device_create(&remote_class, NULL,
chip->chr_devno, chip, chip->dev_name);
if (IS_ERR_OR_NULL(dev))
return -1;
return 0;
}
EXPORT_SYMBOL_GPL(ir_sys_device_attribute_init);
void ir_sys_device_attribute_sys(struct remote_chip *chip)
{
device_destroy(&remote_class, chip->chr_devno);
}
EXPORT_SYMBOL_GPL(ir_sys_device_attribute_sys);