rk3288 按键rk_key.c

```
这里我们分析一下rk3288的按键驱动分析
//定时器执行函数
static void keys_timer(unsigned long _data)
{
   struct rk_keys_drvdata *pdata = rk_key_get_drvdata();
   struct rk_keys_button *button = (struct rk_keys_button *)_data;
   struct input_dev *input = pdata->input;
   int state;
//首先判断是否按键还是adc的类型,之后通过他们获取state
   if (button->type == TYPE_GPIO)
      state = !!((gpio_get_value(button->gpio) ? 1 : 0) ^
            button->active_low);
   else
      state = !!button->adc_state;
     //将存储的按键值和它对比,如果不一样的话就上报
   if (button->state != state) {
      button->state = state;
      input_event(input, EV_KEY, button->code, button->state);
      key_dbg(pdata, "%skey[%s]: report event[%d] state[%d]\n",
         button->type == TYPE_ADC ? "adc" : "gpio",
         button->desc, button->code, button->state);
      input_event(input, EV_KEY, button->code, button->state);
      input_sync(input);
   }
     //如果一直没有抬起的话,那么就一直重新计时
   if (state)
      mod_timer(&button->timer, jiffies + DEBOUNCE_JIFFIES);
}

static irqreturn_t keys_isr(int irq, void *dev_id)
{
   struct rk_keys_drvdata *pdata = rk_key_get_drvdata();
   struct rk_keys_button *button = (struct rk_keys_button *)dev_id;
   struct input_dev *input = pdata->input;

   BUG_ON(irq != gpio_to_irq(button->gpio));

   if (button->wakeup && pdata->in_suspend) {
      button->state = 1;
      key_dbg(pdata,
         "wakeup: %skey[%s]: report event[%d] state[%d]\n",
         (button->type == TYPE_ADC) ? "adc" : "gpio",
         button->desc, button->code, button->state);
      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;
}

static const struct of_device_id rk_key_match[] = {
   { .compatible = "rockchip,key", .data = NULL},
   {},
};
MODULE_DEVICE_TABLE(of, rk_key_match);

static int rk_key_adc_iio_read(struct rk_keys_drvdata *data)
{
   struct iio_channel *channel = data->chan;
   int val, ret;

   if (!channel)
      return INVALID_ADVALUE;
   ret = iio_read_channel_raw(channel, &val);
   if (ret < 0) {
      pr_err("read channel() error: %d\n", ret);
      return ret;
   }
   return val;
}
//adc的执行函数
static void adc_key_poll(struct work_struct *work)
{
   struct rk_keys_drvdata *ddata;
   int i, result = -1;

   ddata = container_of(work, struct rk_keys_drvdata, adc_poll_work.work);
   if (!ddata->in_suspend) {

     //读取adc的值
      result = rk_key_adc_iio_read(ddata);

     //判断

      if (result > INVALID_ADVALUE && result < EMPTY_ADVALUE)
         ddata->result = result;
      for (i = 0; i < ddata->nbuttons; i++) {
         struct rk_keys_button *button = &ddata->button[i];
          //判断是否有adc的值,如果没有的话就继续,
         if (!button->adc_value)
            continue;

          //如果没有adcvalue的值的话就不执行这里了
         if (result < button->adc_value + DRIFT_ADVALUE &&
             result > button->adc_value - DRIFT_ADVALUE)
            button->adc_state = 1;
         else
            button->adc_state = 0;


          如果有adc的值 那么首先判断是否和存储的值状态是否一样 如果不一样的话就通过定时器上报按键值

         if (button->state != button->adc_state) 

               mod_timer(&button->timer,

                 jiffies + DEBOUNCE_JIFFIES);
      }
   }

   schedule_delayed_work(&ddata->adc_poll_work, ADC_SAMPLE_JIFFIES);
}
//判断是io口还是adc按键
static int rk_key_type_get(struct device_node *node,
            struct rk_keys_button *button)
{
   u32 adc_value;

   if (!of_property_read_u32(node, "rockchip,adc_value", &adc_value))
      return TYPE_ADC;
   else if (of_get_gpio(node, 0) >= 0)
      return TYPE_GPIO;
   else
      return -1;
}
//解析设备数的函数
static int rk_keys_parse_dt(struct rk_keys_drvdata *pdata,
             struct platform_device *pdev)
{
   struct device_node *node = pdev->dev.of_node;
   struct device_node *child_node;
   struct iio_channel *chan;
   int ret, gpio, i = 0;
   u32 code, adc_value, flags;

   chan = iio_channel_get(&pdev->dev, NULL);
   if (IS_ERR(chan)) {
      dev_info(&pdev->dev, "no io-channels defined\n");
      chan = NULL;
   }
   pdata->chan = chan;

   for_each_child_of_node(node, child_node) {
      if (of_property_read_u32(child_node, "linux,code", &code)) {
         dev_err(&pdev->dev,
            "Missing linux,code property in the DT.\n");
         ret = -EINVAL;
         goto error_ret;
      }
      pdata->button[i].code = code;
      pdata->button[i].desc =
          of_get_property(child_node, "label", NULL);
      pdata->button[i].type =
          rk_key_type_get(child_node, &pdata->button[i]);
      switch (pdata->button[i].type) {
      case TYPE_GPIO:
         gpio = of_get_gpio_flags(child_node, 0, &flags);
         if (gpio < 0) {
            ret = gpio;
            if (ret != -EPROBE_DEFER)
               dev_err(&pdev->dev,
                  "Failed to get gpio flags, error: %d\n",
                  ret);
            goto error_ret;
         }

         pdata->button[i].gpio = gpio;
         pdata->button[i].active_low =
             flags & OF_GPIO_ACTIVE_LOW;
         pdata->button[i].wakeup =
             !!of_get_property(child_node, "gpio-key,wakeup",
                     NULL);
         break;

      case TYPE_ADC:
         if (of_property_read_u32
             (child_node, "rockchip,adc_value", &adc_value)) {
            dev_err(&pdev->dev,
               "Missing rockchip,adc_value property in the DT.\n");
            ret = -EINVAL;
            goto error_ret;
         }
         pdata->button[i].adc_value = adc_value;
         break;

      default:
         dev_err(&pdev->dev,
            "Error rockchip,type property in the DT.\n");
         ret = -EINVAL;
         goto error_ret;
      }
      i++;
   }

   return 0;

error_ret:
   return ret;
}

static int keys_probe(struct platform_device *pdev)
{
   struct device *dev = &pdev->dev;
   struct device_node *np = pdev->dev.of_node;
   struct rk_keys_drvdata *ddata = NULL;
   struct input_dev *input = NULL;
   int i, error = 0;
   int wakeup, key_num = 0;
     //得到设备节点
   key_num = of_get_child_count(np);
   if (key_num == 0)
      dev_info(&pdev->dev, "no key defined\n");

   ddata = devm_kzalloc(dev, sizeof(struct rk_keys_drvdata) +
              key_num * sizeof(struct rk_keys_button),
              GFP_KERNEL);
    //这里只是分配一个输入设备,之后设置输入设备 主要还是设置io中断以及版本和名子
   input = devm_input_allocate_device(dev);
   if (!ddata || !input) {
      error = -ENOMEM;
      return error;
   }
   platform_set_drvdata(pdev, ddata);

   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;
   ddata->input = input;

   /* parse info from dt */
   ddata->nbuttons = key_num;

    //解析设备数
   error = rk_keys_parse_dt(ddata, pdev);
   if (error)
      goto fail0;

   /* Enable auto repeat feature of Linux input subsystem */
   if (ddata->rep)
      __set_bit(EV_REP, input->evbit);

   for (i = 0; i < ddata->nbuttons; i++) {
      struct rk_keys_button *button = &ddata->button[i];

      if (button->code) {

          为每个按键分配一个定时器
         setup_timer(&button->timer,
                keys_timer, (unsigned long)button);
      }

      if (button->wakeup)
         wakeup = 1;

      input_set_capability(input, EV_KEY, button->code);

   }

   wake_lock_init(&ddata->wake_lock, WAKE_LOCK_SUSPEND, input->name);

   for (i = 0; i < ddata->nbuttons; i++) {
      struct rk_keys_button *button = &ddata->button[i];

      if (button->type == TYPE_GPIO) {
         int irq;
          //为io口申请这里的type即为TYPE_GPIO  而不是adc
         error =
             devm_gpio_request(dev, button->gpio,
                     button->desc ? : "keys");
         if (error < 0) {
            pr_err("gpio-keys: failed to request GPIO %d, error %d\n",
                   button->gpio, error);
            goto fail1;
         }
          //设置为输入
         error = gpio_direction_input(button->gpio);
         if (error < 0) {
            pr_err("gpio-keys: failed to configure input direction for GPIO %d, error %d\n",
                   button->gpio, error);
            gpio_free(button->gpio);
            goto fail1;
         }

         irq = gpio_to_irq(button->gpio);
         if (irq < 0) {
            error = irq;
            pr_err("gpio-keys: Unable to get irq number for GPIO %d, error %d\n",
                   button->gpio, error);
            gpio_free(button->gpio);
            goto fail1;
         }
          //申请中断
         error = devm_request_irq(dev, irq, keys_isr,
                   button->active_low ?
                   IRQF_TRIGGER_FALLING :
                   IRQF_TRIGGER_RISING,
                   button->desc ?
                   button->desc : "keys",
                   button);
         if (error) {
            pr_err("gpio-keys: Unable to claim irq %d; error %d\n",
                   irq, error);
            gpio_free(button->gpio);
            goto fail1;
         }
      }
   }

   input_set_capability(input, EV_KEY, KEY_WAKEUP);
   device_init_wakeup(dev, wakeup);
     //注册输入设备
   error = input_register_device(input);
   if (error) {
      pr_err("gpio-keys: Unable to register input device, error: %d\n",
             error);
      goto fail2;
   }
     //这里如果adc通道不为空的话那么久启动adc的定时器
   /* adc polling work */
   if (ddata->chan) {
      INIT_DELAYED_WORK(&ddata->adc_poll_work, adc_key_poll);
      schedule_delayed_work(&ddata->adc_poll_work,
                  ADC_SAMPLE_JIFFIES);
   }

   spdata = ddata;
   sinput_dev = input;
   return error;

fail2:
   device_init_wakeup(dev, 0);
fail1:
   wake_lock_destroy(&ddata->wake_lock);
   while (--i >= 0)
      del_timer_sync(&ddata->button[i].timer);
fail0:
   platform_set_drvdata(pdev, NULL);

   return error;
}

static int keys_remove(struct platform_device *pdev)
{
   struct device *dev = &pdev->dev;
   struct rk_keys_drvdata *ddata = dev_get_drvdata(dev);
   struct input_dev *input = ddata->input;
   int i;

   device_init_wakeup(dev, 0);
   for (i = 0; i < ddata->nbuttons; i++)
      del_timer_sync(&ddata->button[i].timer);
   if (ddata->chan)
      cancel_delayed_work_sync(&ddata->adc_poll_work);
   input_unregister_device(input);
   wake_lock_destroy(&ddata->wake_lock);

   sinput_dev = NULL;
   spdata = NULL;

   return 0;
}

#ifdef CONFIG_PM
static int keys_suspend(struct device *dev)
{
   struct rk_keys_drvdata *ddata = dev_get_drvdata(dev);
   int i;

   ddata->in_suspend = true;
   if (device_may_wakeup(dev)) {
      for (i = 0; i < ddata->nbuttons; i++) {
         struct rk_keys_button *button = ddata->button + i;

         if (button->wakeup)
            enable_irq_wake(gpio_to_irq(button->gpio));
      }
   }

   return 0;
}

static int keys_resume(struct device *dev)
{
   struct rk_keys_drvdata *ddata = dev_get_drvdata(dev);
   int i;

   if (device_may_wakeup(dev)) {
      for (i = 0; i < ddata->nbuttons; i++) {
         struct rk_keys_button *button = ddata->button + i;

         if (button->wakeup)
            disable_irq_wake(gpio_to_irq(button->gpio));
      }
      preempt_disable();
      /* for call resend_irqs, which may call keys_isr */
      if (local_softirq_pending())
         do_softirq();
      preempt_enable_no_resched();
   }

   ddata->in_suspend = false;

   return 0;
}

static const struct dev_pm_ops keys_pm_ops = {
   .suspend   = keys_suspend,
   .resume       = keys_resume,
};
#endif

static struct platform_driver keys_device_driver = {
   .probe    = keys_probe,
   .remove       = keys_remove,
   .driver       = {
      .name  = "rk-keypad",
      .owner = THIS_MODULE,
      .of_match_table = rk_key_match,
#ifdef CONFIG_PM
      .pm    = &keys_pm_ops,
#endif
   }
};
根据设备数匹配注册按键驱动
module_platform_driver(keys_device_driver);


“`

猜你喜欢

转载自blog.csdn.net/u012855539/article/details/77948174
今日推荐