rockchip的adc按键驱动

设备树:

vi rk3399pro-firefly-core.dtsi +55
adc-keys {
        compatible = "adc-keys";
        io-channels = <&saradc 2>;               //adc选用的是saradc通道2
        io-channel-names = "buttons";
        poll-interval = <100>;
        keyup-threshold-microvolt = <1800000>;   //表示按键抬起,saradc通道2的电压(单位微伏)。
        adc-power-key {
                linux,code = <KEY_POWER>;        //按键上报的键值
                label = "power key";
                press-threshold-microvolt = <0>; //表示按键按下,saradc通道2的电压。
        };
};

最关键的上报按键事件的代码:adc-keys.c

static void adc_keys_poll(struct input_polled_dev *dev)
{
	struct adc_keys_state *st = dev->private;
	int i, value, ret;
	u32 diff, closest = 0xffffffff;
	int keycode = 0;

	ret = iio_read_channel_processed(st->channel, &value);//读取adc通道值
	if (unlikely(ret < 0)) {
		/* Forcibly release key if any was pressed */
	    // 如果未按下任何键,则强制释放键
		value = st->keyup_voltage;
	} else {
		for (i = 0; i < st->num_keys; i++) {
			//st->map[i].voltage = "press-threshold-microvolt" = 设备树设定的按下时adc值
			diff = abs(st->map[i].voltage - value); 
			if (diff < closest) {//找出最接近的键值
				closest = diff;
				keycode = st->map[i].keycode;
			}
		}
	}
	//如果adc的值与开路电压的adc的误差比上面的最小误差都小,那么判定为未按下按键
	if (abs(st->keyup_voltage - value) < closest)
		keycode = 0;
	//如果上一次有键值,并且这次的键值和上次不一样,就说明上一次的按键已经松开
	//并且这次检测,又有新的按键被按下,就先发送上次键值的松开事件
	if (st->last_key && st->last_key != keycode)
		input_report_key(dev->input, st->last_key, 0);
    //再发送新的键值的按下事件
	if (keycode)
		input_report_key(dev->input, keycode, 1);

	input_sync(dev->input);
	st->last_key = keycode;
}

如果我们自己要用adc:

设备树:

adc_demo: adc_demo {
        status = "okay";
        compatible = "firefly,rk3399-adc";
        io-channels = <&saradc 0>;
};

驱动代码:

......
#include <linux/iio/types.h>
#include <linux/iio/consumer.h>

static struct delayed_work	adc_poll_work;  //定义一个工作队列
static struct iio_channel *chan;	    	//定义 IIO 通道结构体

static void firefly_demo_adc_poll (struct work_struct *work)
{
	int val,ret;
	int Vresult;
	/*
	使用标准电压将 AD 转换的值转换为用户所需要的电压值。其计算公式如下:
	Vref / (2^n-1) = Vresult / raw
	Vref 为标准电压
	n 为 AD 转换的位数
	Vresult 为用户所需要的采集电压
	raw 为 AD 采集的原始数据
	例如,标准电压为 1.8V,AD 采集位数为 10 位,AD 采集到的原始数据为 568,则:
	Vresult = (1800mv * 568) / 1023;
	*/
	ret = iio_read_channel_raw(chan, &val);    //获取adc通道的原始数据
	//Vresult = (1800 * val) / 1023;
	Vresult = (1800 * val) / 1023;
	printk("the adc channel voltage is %d mV\n",Vresult);
	schedule_delayed_work(&adc_poll_work,msecs_to_jiffies(1000));//1秒后调用队列
}

static int firefly_adc_probe(struct platform_device *pdev)
{
     chan = iio_channel_get(&(pdev->dev), NULL); //获取要使用的adc通道
     if (chan) {
		INIT_DELAYED_WORK(&adc_poll_work, firefly_demo_adc_poll);//初始化工作队列
		schedule_delayed_work(&adc_poll_work,msecs_to_jiffies(1000));//1秒后调用队列
     }
     return 0;
}

static int firefly_adc_remove(struct platform_device *pdev)
{
	iio_channel_release(chan);
	cancel_delayed_work_sync(&adc_poll_work);
	return 0;
}

static const struct of_device_id firefly_adc_match[] = {
     { .compatible = "firefly,rk3399-adc" },
     {},
};

static struct platform_driver firefly_adc_driver = {
    .probe      = firefly_adc_probe,
    .remove     = firefly_adc_remove,
    .driver     = {
        .name   = "firefly_adc",
        .owner  = THIS_MODULE,
        .of_match_table = firefly_adc_match,
        },
};

static int __init firefly_adc_init(void)
{
	return platform_driver_register(&firefly_adc_driver);
}

static void __exit firefly_adc_exit(void)
{
	platform_driver_unregister(&firefly_adc_driver);
}

module_init(firefly_adc_init);
module_exit(firefly_adc_exit);

MODULE_LICENSE("GPL");

  • 5
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

内核分析笔记

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值