您尚未登录。

楼主 # 2022-03-06 01:13:19

liefyuan
会员
注册时间: 2021-05-30
已发帖子: 69
积分: 95

V3s板子 LRADC KEY按键显示的键值错误,并且显示毫无规律,求教啊!

原理图:


360截图17650103117133121.png

硬件检查:
R24电阻按键不按下时电压为:2.98v

R24电阻S1按键按下时电压为:0.19v
R25电阻S2按键按下时电压为:0.39v
R26电阻S3按键按下时电压为:0.6v
R27电阻S4按键按下时电压为:0.8v

问题:
按键与键值显示错误。

设备树文件:

#include <dt-bindings/input/input.h>

#include "sun8i-v3s-licheepi-zero.dts"

/ {
        model = "Lichee Pi Zero with Dock";
        compatible = "licheepi,licheepi-zero-dock", "licheepi,licheepi-zero",
                     "allwinner,sun8i-v3s";
};

&codec {
        allwinner,audio-routing =
                "Headphone", "HP",
                "Headphone", "HPCOM",
                "MIC1", "Mic",
                "Mic",  "HBIAS";
        status = "okay";
};

&lradc {
        vref-supply = <&reg_vcc3v0>;
        status = "okay";

        button@200 {
                label = "Volume Up";
                linux,code = <KEY_VOLUMEUP>;
                channel = <0>;
                voltage = <200000>;
        };

        button@400 {
                label = "Volume Down";
                linux,code = <KEY_VOLUMEDOWN>;
                channel = <0>;
                voltage = <400000>;
        };

        button@600 {
                label = "Select";
                linux,code = <KEY_SELECT>;
                channel = <0>;
                voltage = <600000>;
        };
        button@800 {
                label = "Start";
                linux,code = <KEY_OK>;
                channel = <0>;
                voltage = <800000>;
        };
};

&mmc1 {
        pinctrl-0 = <&mmc1_pins>;
        pinctrl-names = "default";
        broken-cd;
        bus-width = <4>;
        vmmc-supply = <&reg_vcc3v3>;
        status = "okay";
};

测试代码:https://elinux.org/images/9/93/Evtest.c

以下我是按照原理图上的S1,S2,S3,S4按键的顺序按下的,输出的信息完全不对,求教。

# ./evtest /dev/input/event0
Input driver version is 1.0.1
Input device ID: bus 0x19 vendor 0x1 product 0x1 version 0x100
Input device name: "1c22800.lradc"
Supported events:
  Event type 0 (Sync)
  Event type 1 (Key)
    Event code 114 (VolumeDown)
    Event code 115 (VolumeUp)
    Event code 352 (Ok)
    Event code 353 (Select)
Testing ... (interrupt to exit)
Event: time 17480.008424, type 1 (Key), code 114 (VolumeDown), value 1
Event: time 17480.008424, -------------- Report Sync ------------
Event: time 17480.246700, type 1 (Key), code 114 (VolumeDown), value 0
Event: time 17480.246700, -------------- Report Sync ------------
Event: time 17480.727180, type 1 (Key), code 352 (Ok), value 1
Event: time 17480.727180, -------------- Report Sync ------------
Event: time 17480.942028, type 1 (Key), code 352 (Ok), value 0
Event: time 17480.942028, -------------- Report Sync ------------
Event: time 17481.465484, type 1 (Key), code 352 (Ok), value 1
Event: time 17481.465484, -------------- Report Sync ------------
Event: time 17481.680335, type 1 (Key), code 352 (Ok), value 0
Event: time 17481.680335, -------------- Report Sync ------------
Event: time 17482.195977, type 1 (Key), code 352 (Ok), value 1
Event: time 17482.195977, -------------- Report Sync ------------
Event: time 17482.445982, type 1 (Key), code 352 (Ok), value 0
Event: time 17482.445982, -------------- Report Sync ------------

我按下S1按键再松开:

Event: time 17480.008424, type 1 (Key), code 114 (VolumeDown), value 1
Event: time 17480.008424, -------------- Report Sync ------------
Event: time 17480.246700, type 1 (Key), code 114 (VolumeDown), value 0
Event: time 17480.246700, -------------- Report Sync ------------

如上它显示的是S2按键(VolumeDown)的信息和键值,为什么呢?

我按下S2、S3、S4键都是显示的是S4按键(KEY_OK)的信息,为什么呢?

Event: time 17480.727180, type 1 (Key), code 352 (Ok), value 1
Event: time 17480.727180, -------------- Report Sync ------------
Event: time 17480.942028, type 1 (Key), code 352 (Ok), value 0
Event: time 17480.942028, -------------- Report Sync ------------


查看中断列表:

# cat /proc/interrupts
           CPU0
 19:        576     GIC-0  27 Level     arch_timer
 21:          0     GIC-0  50 Level     sun4i_timer0
 22:          0     GIC-0  82 Level     1c02000.dma-controller
 23:       5039     GIC-0  92 Level     sunxi-mmc
 24:        159     GIC-0  93 Level     sunxi-mmc
 25:          1     GIC-0 103 Level     musb-hdrc.1.auto
 26:          0     GIC-0  72 Level     1c20400.rtc
 32:          2     GIC-0  62 Level     sun4i-a10-lradc-keys
 34:        226     GIC-0  32 Level     serial
 35:         63     GIC-0  38 Level     mv64xxx_i2c
IPI0:          0  CPU wakeup interrupts
IPI1:          0  Timer broadcast interrupts
IPI2:          0  Rescheduling interrupts
IPI3:          0  Function call interrupts
IPI4:          0  CPU stop interrupts
IPI5:          0  IRQ work interrupts
IPI6:          0  completion interrupts
Err:          0

有中断:

 32:          2     GIC-0  62 Level     sun4i-a10-lradc-keys

以上就是所有的信息

离线

#1 2023-02-10 18:06:48

ldl212
会员
注册时间: 2018-04-16
已发帖子: 19
积分: 4

Re: V3s板子 LRADC KEY按键显示的键值错误,并且显示毫无规律,求教啊!

对比本目录下sun4i-lradc-key.c 与 linux-5.10/drivers/input/keyboard/sun4i-lradc-keys.c 文件
增加调试代码,查看按键实际检测到的adc值
修改sun4i-lradc-key.c文件,增加debug部分代码,根据实际检测出来的adc值 设置linux kernel 设备树的参考电压

大概检测逻辑是:实际检测出来的电压与参考电压哪个更接近 就设置为哪个键值

for (i = 0; i < lradc->chan0_map_count; i++) 
{
    diff = abs(lradc->chan0_map[i].voltage - voltage);
    if (diff < closest) {
        closest = diff;
        keycode = lradc->chan0_map[i].keycode;
        #ifdef DEBUG_INPUT_KEY
        dev_info(lradc_dev, "Debug: chan0_map %d V \n", lradc->chan0_map[i].voltage);
        #endif
    }
}

前两天看了一下,我得分压电阻变了,改了一下参考电压 ,打开以下文件的 #define DEBUG_INPUT_KEY  在按键输出的时候会有调试信息

// SPDX-License-Identifier: GPL-2.0-or-later
/*
 * Allwinner sun4i low res adc attached tablet keys driver
 *
 * Copyright (C) 2014 Hans de Goede <hdegoede@redhat.com>
 */

/*
 * Allwinnner sunxi SoCs have a lradc which is specifically designed to have
 * various (tablet) keys (ie home, back, search, etc). attached to it using
 * a resistor network. This driver is for the keys on such boards.
 *
 * There are 2 channels, currently this driver only supports channel 0 since
 * there are no boards known to use channel 1.
 */

#include <linux/err.h>
#include <linux/init.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>

#define LRADC_CTRL		0x00
#define LRADC_INTC		0x04
#define LRADC_INTS		0x08
#define LRADC_DATA0		0x0c
#define LRADC_DATA1		0x10

/* LRADC_CTRL bits */
#define FIRST_CONVERT_DLY(x)	((x) << 24) /* 8 bits */
#define CHAN_SELECT(x)		((x) << 22) /* 2 bits */
#define CONTINUE_TIME_SEL(x)	((x) << 16) /* 4 bits */
#define KEY_MODE_SEL(x)		((x) << 12) /* 2 bits */
#define LEVELA_B_CNT(x)		((x) << 8)  /* 4 bits */
#define HOLD_KEY_EN(x)		((x) << 7)
#define HOLD_EN(x)		((x) << 6)
#define LEVELB_VOL(x)		((x) << 4)  /* 2 bits */
#define SAMPLE_RATE(x)		((x) << 2)  /* 2 bits */
#define ENABLE(x)		((x) << 0)

/* LRADC_INTC and LRADC_INTS bits */
#define CHAN1_KEYUP_IRQ		BIT(12)
#define CHAN1_ALRDY_HOLD_IRQ	BIT(11)
#define CHAN1_HOLD_IRQ		BIT(10)
#define	CHAN1_KEYDOWN_IRQ	BIT(9)
#define CHAN1_DATA_IRQ		BIT(8)
#define CHAN0_KEYUP_IRQ		BIT(4)
#define CHAN0_ALRDY_HOLD_IRQ	BIT(3)
#define CHAN0_HOLD_IRQ		BIT(2)
#define	CHAN0_KEYDOWN_IRQ	BIT(1)
#define CHAN0_DATA_IRQ		BIT(0)

//#define DEBUG_INPUT_KEY
/* struct lradc_variant - Describe sun4i-a10-lradc-keys hardware variant
 * @divisor_numerator:		The numerator of lradc Vref internally divisor
 * @divisor_denominator:	The denominator of lradc Vref internally divisor
 */
struct lradc_variant {
	u8 divisor_numerator;
	u8 divisor_denominator;
};

static const struct lradc_variant lradc_variant_a10 = {
	.divisor_numerator = 2,
	.divisor_denominator = 3
};

static const struct lradc_variant r_lradc_variant_a83t = {
	.divisor_numerator = 3,
	.divisor_denominator = 4
};

struct sun4i_lradc_keymap {
	u32 voltage;
	u32 keycode;
};

struct sun4i_lradc_data {
	struct device *dev;
	struct input_dev *input;
	void __iomem *base;
	struct regulator *vref_supply;
	struct sun4i_lradc_keymap *chan0_map;
	const struct lradc_variant *variant;
	u32 chan0_map_count;
	u32 chan0_keycode;
	u32 vref;
};
// hack: just for testing
static struct device *lradc_dev;
static irqreturn_t sun4i_lradc_irq(int irq, void *dev_id)
{
	struct sun4i_lradc_data *lradc = dev_id;
	u32 i, ints, val, voltage, diff, keycode = 0, closest = 0xffffffff;

	ints  = readl(lradc->base + LRADC_INTS);

	/*
	 * lradc supports only one keypress at a time, release does not give
	 * any info as to which key was released, so we cache the keycode.
	 */

	if (ints & CHAN0_KEYUP_IRQ) {
		input_report_key(lradc->input, lradc->chan0_keycode, 0);
		lradc->chan0_keycode = 0;
	}

	if ((ints & CHAN0_KEYDOWN_IRQ) && lradc->chan0_keycode == 0) {
		val = readl(lradc->base + LRADC_DATA0) & 0x3f;
		voltage = val * lradc->vref / 63;
		// debug hack : display voltage in dmesg
		
		for (i = 0; i < lradc->chan0_map_count; i++) {
			diff = abs(lradc->chan0_map[i].voltage - voltage);
			if (diff < closest) {
				closest = diff;
				keycode = lradc->chan0_map[i].keycode;
				#ifdef DEBUG_INPUT_KEY
				dev_info(lradc_dev, "Debug: chan0_map %d V \n", lradc->chan0_map[i].voltage);
				#endif
			}
			
		}
		#ifdef DEBUG_INPUT_KEY
		printk("Debug: volatile: %u V, adc: %d,ref volatage: %d button pressed\n", voltage,val, lradc->vref);
		#endif
		//dev_info(lradc_dev, "Debug: volatile: %u V, adc: %d,ref volatage: %d button pressed\n", voltage,val, lradc->vref);
		lradc->chan0_keycode = keycode;
		input_report_key(lradc->input, lradc->chan0_keycode, 1);
	}

	input_sync(lradc->input);

	writel(ints, lradc->base + LRADC_INTS);

	return IRQ_HANDLED;
}

static int sun4i_lradc_open(struct input_dev *dev)
{
	struct sun4i_lradc_data *lradc = input_get_drvdata(dev);
	int error;

	error = regulator_enable(lradc->vref_supply);
	if (error)
		return error;

	lradc->vref = regulator_get_voltage(lradc->vref_supply) *
		      lradc->variant->divisor_numerator /
		      lradc->variant->divisor_denominator;
	/*
	 * Set sample time to 4 ms / 250 Hz. Wait 2 * 4 ms for key to
	 * stabilize on press, wait (1 + 1) * 4 ms for key release
	 */
	writel(FIRST_CONVERT_DLY(2) | LEVELA_B_CNT(1) | HOLD_EN(1) |
		SAMPLE_RATE(0) | ENABLE(1), lradc->base + LRADC_CTRL);

	writel(CHAN0_KEYUP_IRQ | CHAN0_KEYDOWN_IRQ, lradc->base + LRADC_INTC);

	return 0;
}

static void sun4i_lradc_close(struct input_dev *dev)
{
	struct sun4i_lradc_data *lradc = input_get_drvdata(dev);

	/* Disable lradc, leave other settings unchanged */
	writel(FIRST_CONVERT_DLY(2) | LEVELA_B_CNT(1) | HOLD_EN(1) |
		SAMPLE_RATE(2), lradc->base + LRADC_CTRL);
	writel(0, lradc->base + LRADC_INTC);

	regulator_disable(lradc->vref_supply);
}

static int sun4i_lradc_load_dt_keymap(struct device *dev,
				      struct sun4i_lradc_data *lradc)
{
	struct device_node *np, *pp;
	int i;
	int error;

	np = dev->of_node;
	if (!np)
		return -EINVAL;

	lradc->chan0_map_count = of_get_child_count(np);
	if (lradc->chan0_map_count == 0) {
		dev_err(dev, "keymap is missing in device tree\n");
		return -EINVAL;
	}

	lradc->chan0_map = devm_kmalloc_array(dev, lradc->chan0_map_count,
					      sizeof(struct sun4i_lradc_keymap),
					      GFP_KERNEL);
	if (!lradc->chan0_map)
		return -ENOMEM;

	i = 0;
	for_each_child_of_node(np, pp) {
		struct sun4i_lradc_keymap *map = &lradc->chan0_map[i];
		u32 channel;

		error = of_property_read_u32(pp, "channel", &channel);
		if (error || channel != 0) {
			dev_err(dev, "%pOFn: Inval channel prop\n", pp);
			of_node_put(pp);
			return -EINVAL;
		}

		error = of_property_read_u32(pp, "voltage", &map->voltage);
		if (error) {
			dev_err(dev, "%pOFn: Inval voltage prop\n", pp);
			of_node_put(pp);
			return -EINVAL;
		}

		error = of_property_read_u32(pp, "linux,code", &map->keycode);
		if (error) {
			dev_err(dev, "%pOFn: Inval linux,code prop\n", pp);
			of_node_put(pp);
			return -EINVAL;
		}

		i++;
	}

	return 0;
}

static int sun4i_lradc_probe(struct platform_device *pdev)
{
	struct sun4i_lradc_data *lradc;
	struct device *dev = &pdev->dev;
	int i;
	int error;
	// hack : just for testing
	lradc_dev = &pdev->dev;
	lradc = devm_kzalloc(dev, sizeof(struct sun4i_lradc_data), GFP_KERNEL);
	if (!lradc)
		return -ENOMEM;

	error = sun4i_lradc_load_dt_keymap(dev, lradc);
	if (error)
		return error;

	lradc->variant = of_device_get_match_data(&pdev->dev);
	if (!lradc->variant) {
		dev_err(&pdev->dev, "Missing sun4i-a10-lradc-keys variant\n");
		return -EINVAL;
	}

	lradc->vref_supply = devm_regulator_get(dev, "vref");
	if (IS_ERR(lradc->vref_supply))
		return PTR_ERR(lradc->vref_supply);

	lradc->dev = dev;
	lradc->input = devm_input_allocate_device(dev);
	if (!lradc->input)
		return -ENOMEM;

	lradc->input->name = pdev->name;
	lradc->input->phys = "sun4i_lradc/input0";
	lradc->input->open = sun4i_lradc_open;
	lradc->input->close = sun4i_lradc_close;
	lradc->input->id.bustype = BUS_HOST;
	lradc->input->id.vendor = 0x0001;
	lradc->input->id.product = 0x0001;
	lradc->input->id.version = 0x0100;

	__set_bit(EV_KEY, lradc->input->evbit);
	for (i = 0; i < lradc->chan0_map_count; i++)
		__set_bit(lradc->chan0_map[i].keycode, lradc->input->keybit);

	input_set_drvdata(lradc->input, lradc);

	lradc->base = devm_ioremap_resource(dev,
			      platform_get_resource(pdev, IORESOURCE_MEM, 0));
	if (IS_ERR(lradc->base))
		return PTR_ERR(lradc->base);

	error = devm_request_irq(dev, platform_get_irq(pdev, 0),
				 sun4i_lradc_irq, 0,
				 "sun4i-a10-lradc-keys", lradc);
	if (error)
		return error;

	error = input_register_device(lradc->input);
	if (error)
		return error;

	return 0;
}

static const struct of_device_id sun4i_lradc_of_match[] = {
	{ .compatible = "allwinner,sun4i-a10-lradc-keys",
		.data = &lradc_variant_a10 },
	{ .compatible = "allwinner,sun8i-a83t-r-lradc",
		.data = &r_lradc_variant_a83t },
	{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, sun4i_lradc_of_match);

static struct platform_driver sun4i_lradc_driver = {
	.driver = {
		.name	= "sun4i-a10-lradc-keys",
		.of_match_table = of_match_ptr(sun4i_lradc_of_match),
	},
	.probe	= sun4i_lradc_probe,
};

module_platform_driver(sun4i_lradc_driver);

MODULE_DESCRIPTION("Allwinner sun4i low res adc attached tablet keys driver");
MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
MODULE_LICENSE("GPL");

离线

页脚

工信部备案:粤ICP备20025096号 Powered by FluxBB

感谢为中文互联网持续输出优质内容的各位老铁们。 QQ: 516333132, 微信(wechat): whycan_cn (哇酷网/挖坑网/填坑网) service@whycan.cn