
一、设备树
1 2 3 4 5 6 7 8 9 10 11 12 13
| adc-keys { compatible = "adc-keys"; io-channels = <&saradc 2>; io-channel-names = "buttons"; poll-interval = <100>; keyup-threshold-microvolt = <1800000>; adc-power-key { linux,code = <KEY_POWER>; label = "power key"; press-threshold-microvolt = <0>; }; };
|
二、上报键值
最关键的上报按键事件的代码:adc-keys.c:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| 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); if (unlikely(ret < 0)) { value = st->keyup_voltage; } else { for (i = 0; i < st->num_keys; i++) { diff = abs(st->map[i].voltage - value); if (diff < closest) { closest = diff; keycode = st->map[i].keycode; } } } 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; }
|
三、使用实例
①修改设备树:
1 2 3 4 5
| adc_demo: adc_demo { status = "okay"; compatible = "firefly,rk3399-adc"; io-channels = <&saradc 0>; };
|
②编写驱动程序:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
| #include <linux/iio/types.h> #include <linux/input.h> #include <linux/input-polldev.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/of.h> #include <linux/platform_device.h> #include <linux/property.h> #include <linux/slab.h> #include <linux/delay.h> #include <linux/err.h> #include <linux/gpio.h> #include <linux/gpio/consumer.h> #include <linux/iio/consumer.h> #include <linux/interrupt.h> #include <linux/pinctrl/consumer.h>
static struct delayed_work adc_poll_work; static struct iio_channel *chan;
static void firefly_demo_adc_poll (struct work_struct *work) { int val,ret; int Vresult;
ret = iio_read_channel_raw(chan, &val); Vresult = (1800 * val) / 1023; printk("the adc channel voltage is %d mV\n",Vresult); schedule_delayed_work(&adc_poll_work,msecs_to_jiffies(1000)); }
static int firefly_adc_probe(struct platform_device *pdev) { printk("firefly_adc_probe!\n"); chan = iio_channel_get(&(pdev->dev), NULL); if (IS_ERR(chan)){ chan = NULL; printk("%s() have not set adc chan\n", __FUNCTION__); return -1; }
if (chan) { INIT_DELAYED_WORK(&adc_poll_work, firefly_demo_adc_poll); schedule_delayed_work(&adc_poll_work,msecs_to_jiffies(1000)); } return 0; }
static int firefly_adc_remove(struct platform_device *pdev) { printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__); 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) { printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__); return platform_driver_register(&firefly_adc_driver); }
static void __exit firefly_adc_exit(void) { printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__); platform_driver_unregister(&firefly_adc_driver); }
module_init(firefly_adc_init); module_exit(firefly_adc_exit);
MODULE_LICENSE("GPL");
|