Amlogic A311D 驱动分析系列(二)-ADC键盘

本系列文章基于Amlogic A311D SDK中的驱动,将我之前阅读代码的一些收获进行总结,算是学习笔记吧。

这一章分析adc键盘驱动

代码adc_keypad.c

1.dts配置


	adc_keypad {
		compatible = "amlogic, adc_keypad";
		status = "okay";
		key_name = "vol-", "vol+", "enter";//键值名
		key_num = <3>;//键值数量
		io-channels = <&saradc SARADC_CH2>;//ADC通道,可以加多个通道
		io-channel-names = "key-chan-2";//ADC通道对应的名字
		key_chan = <SARADC_CH2 SARADC_CH2 SARADC_CH2>;//单个键值对应的ADC通道,可以对应不同的通道
		key_code = <114 115 28>;//上报的键值
		key_val = <143 266 389>; //val=voltage/1800mV*1023//对应的ADC值
		key_tolerance = <40 40 40>;//测量范围
	};

2.驱动分析

adc_keypad注册为platform_driver

platform_driver驱动编写流程大致如下--

xxx_probe--对应meson_adc_kp_probe

读取dts获得配置--meson_adc_kp_get_devtree_pdata

进行相关操作-创建轮询线程。

2.1 meson_adc_kp_probe

static int meson_adc_kp_probe(struct platform_device *pdev)
{
	struct meson_adc_kp *kp;
	struct input_dev *input;
	int ret = 0;
    //发生数据给bl301-这里要分析一下
	send_data_to_bl301();
    //ADC keypad是否使能-从uboot传入
	kernel_keypad_enable_mode_enable();

	kp = kzalloc(sizeof(struct meson_adc_kp), GFP_KERNEL);
	if (!kp)
		return -ENOMEM;

	platform_set_drvdata(pdev, kp);
	mutex_init(&kp->kp_lock);
	INIT_LIST_HEAD(&kp->adckey_head);
	kp->report_code = 0;
	kp->prev_code = 0;
	kp->count = 0;
    //初始化dts
	ret = meson_adc_kp_get_devtree_pdata(pdev, kp);
	if (ret)
		goto err;

	/*alloc input poll device*/
	kp->poll_dev = devm_input_allocate_polled_device(&pdev->dev);
	if (!kp->poll_dev) {
		dev_err(&pdev->dev, "alloc input poll device failed!\n");
		ret = -ENOMEM;
		goto err;
	}
      
    //创建轮询设备
	kp->poll_dev->poll = meson_adc_kp_poll;
	kp->poll_dev->poll_interval = kp->poll_period;
	kp->poll_dev->private = kp;
	input = kp->poll_dev->input;
    
    //注册input
	set_bit(EV_KEY, input->evbit);
	set_bit(EV_REP, input->evbit);
	meson_adc_kp_init_keybit(kp);

	input->name = "adc_keypad";
	input->phys = "adc_keypad/input0";
	input->dev.parent = &pdev->dev;

	input->id.bustype = BUS_ISA;
	input->id.vendor = 0x0001;
	input->id.product = 0x0001;
	input->id.version = 0x0100;

	input->rep[REP_DELAY] = 0xffffffff;
	input->rep[REP_PERIOD] = 0xffffffff;

	input->keycodesize = sizeof(unsigned short);
	input->keycodemax = 0x1ff;

	/*init class*/
    //初始化class节点
	kp->kp_class.name = DRIVE_NAME;
	kp->kp_class.owner = THIS_MODULE;
	kp->kp_class.class_attrs = meson_adckey_attrs;
	ret = class_register(&kp->kp_class);
	if (ret) {
		dev_err(&pdev->dev, "fail to create adc keypad class.\n");
		goto err;
	}

	/*register input poll device*/
    //注册轮询设备
    //注册后系统会自动轮询
	ret = input_register_polled_device(kp->poll_dev);
	if (ret) {
		dev_err(&pdev->dev,
			 "unable to register keypad input poll device.\n");
		goto err1;
	}

	return ret;

err1:
	class_unregister(&kp->kp_class);
err:
	meson_adc_kp_list_free(kp);
	kfree(kp);
	return ret;
}

2.2 键值的轮询

static int meson_adc_kp_search_key(struct meson_adc_kp *kp)
{
	struct adc_key *key;
	int value, i;

	mutex_lock(&kp->kp_lock);
    //根据按键数量读取adc值
	for (i = 0; i < kp->chan_num; i++) {
		if (iio_read_channel_processed(kp->pchan[kp->chan[i]],
				&value) >= 0) {
			if (value < 0)
				continue;
            //查询当前adc值是否在范围内,并有对应键值
			list_for_each_entry(key, &kp->adckey_head, list) {
				if ((key->chan == kp->chan[i])
				&& (value >= key->value - key->tolerance)
				&& (value <= key->value + key->tolerance)) {
					mutex_unlock(&kp->kp_lock);
					return key->code;
				}
			}
		}
	}
	mutex_unlock(&kp->kp_lock);
	return KEY_RESERVED;
}

static void meson_adc_kp_poll(struct input_polled_dev *dev)
{
	struct meson_adc_kp *kp = dev->private;
    //读取adc值,并最终转换为code值
	int code = meson_adc_kp_search_key(kp);
    
    //上报按键松开
	if (kp->report_code && kp->report_code != code) {
		dev_info(&kp->poll_dev->input->dev,
				"key %d up\n", kp->report_code);
		input_report_key(kp->poll_dev->input, kp->report_code, 0);
		input_sync(kp->poll_dev->input);
		kp->report_code = 0;
	}

	if (code) {
        //过滤抖动
		if (kp->count > 0 && code != kp->prev_code)
			kp->count = 0;

		if (kp->count < KEY_JITTER_COUNT)
			kp->count++;
		else {
            //上报按键
			if (keypad_enable_flag && kp->report_code != code) {
				dev_info(&kp->poll_dev->input->dev,
					"key %d down\n", code);
				input_report_key(kp->poll_dev->input, code, 1);
				input_sync(kp->poll_dev->input);
				kp->report_code = code;
			}
			kp->count = 0;
		}
		kp->prev_code = code;
	}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值