页次: 1
对比本目录下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");
(V3s/V3x/S3/S3L/R11通吃)小智V3x开发板smallwitpi lite u-boot/linux/buildroot测试
用 ubuntu16.04 及其以上版本
多谢坛主回复,我现在用的就是 16.04 lts版本。
我刚发现我得gcc版本 是 gcc version 5.4.0 20160609 我怀疑是这方面的原因,我更换一下编译器试试
请教一下大家,licheepi-zero 5.2y的内核 ,编译后出现这样的问题
我是从 tftp下载的 内核,设备树文件,启动起来就这样了
git 了好几遍,重新编译配置了好几遍,依然还是这样
日志如下
[ 0.169924] printk: console [ttyS0] disabled
[ 0.190228] 1c28000.serial: ttyS0 at MMIO 0x1c28000 (irq = 35, base_baud = 1500000) is a U6_16550A
[ 0.748144] printk: console [ttyS0] enabled
[ 0.777464] libphy: Fixed MDIO Bus: probed
[ 0.782179] dwmac-sun8i 1c30000.ethernet: PTP uses main clock
[ 0.787980] dwmac-sun8i 1c30000.ethernet: No regulator found
[ 0.794271] dwmac-sun8i 1c30000.ethernet: Current syscon value is not the default 148000 (expect 38000)
[ 0.803758] dwmac-sun8i 1c30000.ethernet: No HW DMA feature register supported
[ 0.810998] dwmac-sun8i 1c30000.ethernet: RX Checksum Offload Engine supported
[ 0.818213] dwmac-sun8i 1c30000.ethernet: COE Type 2
[ 0.823188] dwmac-sun8i 1c30000.ethernet: TX Checksum insertion supported
[ 0.829979] dwmac-sun8i 1c30000.ethernet: Normal descriptors
[ 0.835632] dwmac-sun8i 1c30000.ethernet: Chain mode enabled
[ 0.849756] libphy: stmmac: probed
[ 0.853875] dwmac-sun8i 1c30000.ethernet: Cannot get mdio-mux node
[ 0.860276] ------------[ cut here ]------------
[ 0.864900] kernel BUG at net/core/dev.c:9241!
[ 0.869337] Internal error: Oops - BUG: 0 [#1] SMP ARM
[ 0.874468] Modules linked in:
[ 0.877528] CPU: 0 PID: 1 Comm: swapper/0 Not tainted 5.2.0-licheepi-zero+ #1
[ 0.884650] Hardware name: Allwinner sun8i Family
[ 0.889364] PC is at free_netdev+0xe0/0xe4
[ 0.893456] LR is at free_netdev+0x9c/0xe4
[ 0.897547] pc : [<c061c26c>] lr : [<c061c228>] psr: 80000013
[ 0.903794] sp : c3833df0 ip : fffff9a4 fp : 00000000
[ 0.909010] r10: c0488cbc r9 : c3833e04 r8 : c3b89c00
[ 0.914227] r7 : c0b04c48 r6 : c3b94038 r5 : c3b94000 r4 : c3b93f88
[ 0.920743] r3 : 00000001 r2 : 00000000 r1 : a0000013 r0 : c0b7440c
[ 0.927262] Flags: Nzcv IRQs on FIQs on Mode SVC_32 ISA ARM Segment none
[ 0.934386] Control: 10c5387d Table: 4000406a DAC: 00000051
[ 0.940123] Process swapper/0 (pid: 1, stack limit = 0x(ptrval))
[ 0.946120] Stack: (0xc3833df0 to 0xc3834000)
[ 0.950474] 3de0: c3b89c80 0000000c c38ba010 c04881e8
[ 0.958642] 3e00: c0b32948 c3b89800 c3a03900 16d696fd c0b84e04 c0b84e00 c38ba010 00000000
[ 0.966809] 3e20: c0b84e04 ffffffed c0b32948 00000000 00000000 c0484c10 c38ba010 c0b32948
[ 0.974977] 3e40: c0b32948 c0b04c48 00000000 c0a4bb18 00000007 c0484f90 c0b8757c c0864014
[ 0.983144] 3e60: a0000013 c38ba010 00000000 c0b32948 c0b04c48 00000000 c0a4bb18 00000007
[ 0.991312] 3e80: 00000000 c0485238 00000000 c0b32948 c38ba010 c04852c0 00000000 c0b32948
[ 0.999480] 3ea0: c0485240 c04830c0 00000000 c3808f58 c389ce34 16d696fd 00000000 c0b32948
[ 1.007647] 3ec0: c3b89780 00000000 c0b307b8 c04840b8 c0946cb8 ffffe000 c0b32948 c0b32948
[ 1.015815] 3ee0: c0b04c48 ffffe000 c0a1e60c c0485adc c0b4cf80 c0b04c48 ffffe000 c01026fc
[ 1.023983] 3f00: c09c4f7c 000000f1 000000f1 c013ae00 c09c3ca8 00000000 c0a00608 00000000
[ 1.032150] 3f20: 00000006 00000006 c090a3d4 c090a448 c090a3fc c0b04c48 c0a3a818 c3f39990
[ 1.040318] 3f40: c3f39998 16d696fd 00000000 16d696fd c0b4cf80 c0b4cf80 000000f1 c0a3a834
[ 1.048486] 3f60: c0a3a83c 00000007 00000000 c0a00f20 00000006 00000006 00000000 c0a00608
[ 1.056653] 3f80: 00000000 00000000 c07497a8 00000000 00000000 00000000 00000000 00000000
[ 1.064820] 3fa0: 00000000 c07497b0 00000000 c01010e8 00000000 00000000 00000000 00000000
[ 1.072987] 3fc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[ 1.081154] 3fe0: 00000000 00000000 00000000 00000000 00000013 00000000 00000000 00000000
[ 1.089344] [<c061c26c>] (free_netdev) from [<c04881e8>] (release_nodes+0x178/0x1f4)
[ 1.097088] [<c04881e8>] (release_nodes) from [<c0484c10>] (really_probe+0xd0/0x2d8)
[ 1.104826] [<c0484c10>] (really_probe) from [<c0484f90>] (driver_probe_device+0x60/0x168)
[ 1.113082] [<c0484f90>] (driver_probe_device) from [<c0485238>] (device_driver_attach+0x58/0x60)
[ 1.121945] [<c0485238>] (device_driver_attach) from [<c04852c0>] (__driver_attach+0x80/0xbc)
[ 1.130462] [<c04852c0>] (__driver_attach) from [<c04830c0>] (bus_for_each_dev+0x68/0xb4)
[ 1.138631] [<c04830c0>] (bus_for_each_dev) from [<c04840b8>] (bus_add_driver+0x140/0x1e8)
[ 1.146886] [<c04840b8>] (bus_add_driver) from [<c0485adc>] (driver_register+0x78/0x110)
[ 1.154971] [<c0485adc>] (driver_register) from [<c01026fc>] (do_one_initcall+0x54/0x1b8)
[ 1.163146] [<c01026fc>] (do_one_initcall) from [<c0a00f20>] (kernel_init_freeable+0x140/0x1dc)
[ 1.171841] [<c0a00f20>] (kernel_init_freeable) from [<c07497b0>] (kernel_init+0x8/0x114)
[ 1.180011] [<c07497b0>] (kernel_init) from [<c01010e8>] (ret_from_fork+0x14/0x2c)
[ 1.187568] Exception stack(0xc3833fb0 to 0xc3833ff8)
[ 1.192612] 3fa0: 00000000 00000000 00000000 00000000
[ 1.200779] 3fc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[ 1.208945] 3fe0: 00000000 00000000 00000000 00000000 00000013 00000000
[ 1.215555] Code: e19500b3 e0450000 e8bd4070 eaeeedbb (e7f001f2)
[ 1.221652] ---[ end trace a912cb4ace74eb36 ]---
[ 1.226391] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b
[ 1.234055] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]---
页次: 1