[RK3288][Android6.0] 系统按键驱动流程分析

怀抱观古今,寝食展戏谑。这篇文章主要讲述[RK3288][Android6.0] 系统按键驱动流程分析相关的知识,希望能为你提供帮助。
本文转载自:http://blog.csdn.net/kris_fei/article/details/77894406
Rockchip的按键驱动位于  kernel/drivers/input/keyboard/rk_keys.c
【[RK3288][Android6.0] 系统按键驱动流程分析】默认支持的keys在dts中定义:

[RK3288][Android6.0] 系统按键驱动流程分析

文章图片

其中power key作为普通gpio,具有唤醒功能。而其他按键比如,volume up/down 可以通过adc精确读取到gpio的电压值,原理图如下:
[RK3288][Android6.0] 系统按键驱动流程分析

文章图片
 
[RK3288][Android6.0] 系统按键驱动流程分析

文章图片

和一般的按键一样,驱动是通过内核input子系统来将keys注册供用户空间使用
static int keys_probe(struct platform_device *pdev) { input = devm_input_allocate_device(dev); input-> name = "rk29-keypad"; /* pdev-> name; */ input-> phys = "gpio-keys/input0"; input-> dev.parent = dev; input-> id.bustype = BUS_HOST; input-> id.vendor = 0x0001; input-> id.product = 0x0001; input-> id.version = 0x0100; error = input_register_device(input); }

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
dts keys的解析通过rk_keys_parse_dt()实现。而每个key都会注册一个定时器函数来处理状态变化并通知用户空间。
for (i = 0; i < ddata-> nbuttons; i++) { if (button-> code) { setup_timer(& button-> timer, keys_timer, (unsigned long)button); } }

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
keys_timer():
static void keys_timer(unsigned long _data) { //普通gpio直接读取 if (button-> type == TYPE_GPIO) state = !!((gpio_get_value(button-> gpio) ? 1 : 0) ^ button-> active_low); else //adc转成bool状态值 state = !!button-> adc_state; //状态变化上报事件 if (button-> state != state) { button-> state = state; input_event(input, EV_KEY, button-> code, button-> state); input_event(input, EV_KEY, button-> code, button-> state); input_sync(input); } //10ms后启动定时器 if (state) mod_timer(& button-> timer, jiffies + DEBOUNCE_JIFFIES); }

定时器会处理普通gpio和adc两种类型的按键,当状态变化时,会向用户空间上报当前事件、键值、状态。默认开机时,定时器处理函数因为检测不到状态变化而关闭退出。
定时器的开启有两个地方会被调用: 
1.系统开机会启一个工作队列,每100ms周期性调用一次检测有没有按键触发
static void adc_key_poll(struct work_struct *work) { if (!ddata-> in_suspend) { //读取adc电压 result = rk_key_adc_iio_read(ddata); for (i = 0; i < ddata-> nbuttons; i++) { //允许值有一定范围的漂移 if (result < button-> adc_value + DRIFT_ADVALUE & & result > button-> adc_value - DRIFT_ADVALUE) button-> adc_state = 1; else button-> adc_state = 0; if (button-> state != button-> adc_state) mod_timer(& button-> timer, jiffies + DEBOUNCE_JIFFIES); } } //周期性调用。ADC_SAMPLE_JIFFIES为100ms schedule_delayed_work(& ddata-> adc_poll_work, ADC_SAMPLE_JIFFIES); }

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
2.  power key唤醒时中断处理会被触发
static irqreturn_t keys_isr(int irq, void *dev_id) { //上报power key事件 if (button-> wakeup & & pdata-> in_suspend) { button-> state = 1; input_event(input, EV_KEY, button-> code, button-> state); input_sync(input); } if (button-> wakeup) wake_lock_timeout(& pdata-> wake_lock, WAKE_LOCK_JIFFIES); mod_timer(& button-> timer, jiffies + DEBOUNCE_JIFFIES); return IRQ_HANDLED; }


    推荐阅读