深圳市友坚恒天科技有限公司

新闻中心

行业新闻

友坚UT4412BV03开发板矩阵键盘驱动分析

时间:2015-05-12     点击:加载中   【打印此页】  【关闭

UT4412BV03矩阵键盘驱动分析

一.友坚UT4412BV03开发板外接了一个3*3的矩阵键盘,通过对矩阵键盘的驱动的编写来实现按键的功能linux内核中已经包含了一个矩阵键盘的驱动,用户只需要简单修改就能实现按键的功能。

UT4412BV03矩阵键盘原理图

如图:在默认倩况下,矩阵键盘的行线被电阻上拉到高电平。如果某个按键被按下则其对应的行线和列线都为低电平

 

 

软件流程图

 

二.矩阵键盘驱动分析

 1. 矩阵键盘对应的IO管脚的初始化

      linux/arch/arm/mach-exynos/setup-keypad.c

void samsung_keypad_cfg_gpio(unsigned int rows, unsigned int cols)

{

 if (rows > 8) { 

  /* Set all the necessary GPX2 pins: KP_ROW[0~7] */

  s3c_gpio_cfgall_range(EXYNOS4_GPX2(0), 8,

     S3C_GPIO_SFN(3), S3C_GPIO_PULL_UP);

  /* Set all the necessary GPX3 pins: KP_ROW[8~] */

  s3c_gpio_cfgall_range(EXYNOS4_GPX3(0), (rows - 8),

      S3C_GPIO_SFN(3), S3C_GPIO_PULL_UP);

 } else {

  /* Set all the necessary GPX2 pins: KP_ROW[x] */

  s3c_gpio_cfgall_range(EXYNOS4_GPX2(0), rows,

      S3C_GPIO_SFN(3), S3C_GPIO_PULL_UP);

 }

 /* Set all the necessary GPX1 pins to special-function 3: KP_COL[x] */

 s3c_gpio_cfgrange_nopull(EXYNOS4_GPX1(0), cols, S3C_GPIO_SFN(3));

}

2.矩阵键盘平台设备和平台资源的初始化

linux/arch/arm/plat-samsung/dev-keypad.c

static struct resource samsung_keypad_resources[] = {

 [0] = {

  .start = SAMSUNG_PA_KEYPAD,

  .end = SAMSUNG_PA_KEYPAD + 0x20 - 1,

  .flags = IORESOURCE_MEM,

 },

 [1] = {

  .start = IRQ_KEYPAD,

  .end = IRQ_KEYPAD,

  .flags = IORESOURCE_IRQ,

 },

};

struct platform_device samsung_device_keypad = {

 .name = "samsung-keypad",

 .id = -1,

 .num_resources = ARRAY_SIZE(samsung_keypad_resources),

 .resource = samsung_keypad_resources,

};

3.  SamSung-keypd.c矩阵键盘驱动分析

//填充一个平台驱动结构体

 static struct platform_driver samsung_keypad_driver = {

 .probe = samsung_keypad_probe,  //按键探测函数,驱动注册后最先执行的函数

 .remove = __devexit_p(samsung_keypad_remove),

 .driver = {

  .name = "samsung-keypad",  //平台驱动的名字

  .owner = THIS_MODULE,

#ifdef CONFIG_PM

  .pm = &samsung_keypad_pm_ops,

#endif

 },

 .id_table = samsung_keypad_driver_ids,

};

//注册一个平台驱动

static int __init samsung_keypad_init(void)

{

 return platform_driver_register(&samsung_keypad_driver);

}

//驱动注册后最先执行的探测函数分析

static int __devinit samsung_keypad_probe(struct platform_device *pdev)

{

 const struct samsung_keypad_platdata *pdata;

 const struct matrix_keymap_data *keymap_data;

 struct samsung_keypad *keypad;

 struct resource *res;

 struct input_dev *input_dev;

 unsigned int row_shift;

 unsigned int keymap_size;

 int error;

#ifdef CONFIG_WAKELOCK_KEEP

 wake_lock_init(&s_ut_wake_lock2,  WAKE_LOCK_SUSPEND, "hold wake buttom");

 keep_wakeup_timeout(2);

#endif

 pdata = pdev->dev.platform_data;  //获取平台私有数据

 if (!pdata) {

  dev_err(&pdev->dev, "no platform data defined\n");

  return -EINVAL;

 }

 keymap_data = pdata->keymap_data;

 if (!keymap_data) {

  dev_err(&pdev->dev, "no keymap data defined\n");

  return -EINVAL;

 }

 if (!pdata->rows || pdata->rows > SAMSUNG_MAX_ROWS)

  return -EINVAL;

 if (!pdata->cols || pdata->cols > SAMSUNG_MAX_COLS)

  return -EINVAL;

 /* initialize the gpio */

 if (pdata->cfg_gpio)

 //调用GPIO初始化函数,设置对应引脚为按键模式

  pdata->cfg_gpio(pdata->rows, pdata->cols);

 row_shift = get_count_order(pdata->cols);

 keymap_size = (pdata->rows << row_shift) * sizeof(keypad->keycodes[0]);

 keypad = kzalloc(sizeof(*keypad) + keymap_size, GFP_KERNEL);

 input_dev = input_allocate_device();

 if (!keypad || !input_dev) {

  error = -ENOMEM;

  goto err_free_mem;

 }

 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);

 if (!res) {

  error = -ENODEV;

  goto err_free_mem;

 }

 keypad->base = ioremap(res->start, resource_size(res));

 if (!keypad->base) {

  error = -EBUSY;

  goto err_free_mem;

 }

 keypad->clk = clk_get(&pdev->dev, "keypad");

 if (IS_ERR(keypad->clk)) {

  dev_err(&pdev->dev, "failed to get keypad clk\n");

  error = PTR_ERR(keypad->clk);

  goto err_unmap_base;

 }

//初始化keypad结构体

 keypad->input_dev = input_dev;

 keypad->row_shift = row_shift;

 keypad->rows = pdata->rows;

 keypad->cols = pdata->cols;

 init_waitqueue_head(&keypad->wait);

 input_dev->name = pdev->name;

 input_dev->id.bustype = BUS_HOST;

 input_dev->dev.parent = &pdev->dev;

 input_set_drvdata(input_dev, keypad);

 input_dev->open = samsung_keypad_open;

 input_dev->close = samsung_keypad_close;

 input_dev->evbit[0] = BIT_MASK(EV_KEY);  //表示输入设备为按键

 if (!pdata->no_autorepeat)

  input_dev->evbit[0] |= BIT_MASK(EV_REP);

 input_set_capability(input_dev, EV_MSC, MSC_SCAN);

 input_dev->keycode = keypad->keycodes;

 input_dev->keycodesize = sizeof(keypad->keycodes[0]);

 input_dev->keycodemax = pdata->rows << row_shift;

 matrix_keypad_build_keymap(keymap_data, row_shift,

   input_dev->keycode, input_dev->keybit);

 keypad->irq = platform_get_irq(pdev, 0);

 if (keypad->irq < 0) {

  error = keypad->irq;

  goto err_put_clk;

 }

//注册一个按键中断,当有按键按下时,将触发samsung_keypad_irq函数的执行

 error = request_threaded_irq(keypad->irq, NULL, samsung_keypad_irq,

   IRQF_ONESHOT, dev_name(&pdev->dev), keypad);

 if (error) {

  dev_err(&pdev->dev, "failed to register keypad interrupt\n");

  goto err_put_clk;

 }

 error = input_register_device(keypad->input_dev);

 if (error)

  goto err_free_irq;

 device_init_wakeup(&pdev->dev, pdata->wakeup);

 platform_set_drvdata(pdev, keypad);

 return 0;

err_free_irq:

 free_irq(keypad->irq, keypad);

err_put_clk:

 clk_put(keypad->clk);

err_unmap_base:

 iounmap(keypad->base);

err_free_mem:

 input_free_device(input_dev);

 kfree(keypad);

 return error;

}

//矩阵键盘按键使能函数

static void samsung_keypad_start(struct samsung_keypad *keypad)

{

 unsigned int val;

 /* Tell IRQ thread that it may poll the device. */

 keypad->stopped = false;

 clk_enable(keypad->clk);

 /* Enable interrupt bits. */

 val = readl(keypad->base + SAMSUNG_KEYIFCON);

//使能按键在上升沿和下降沿出发按键中断

 val |= SAMSUNG_KEYIFCON_INT_F_EN | SAMSUNG_KEYIFCON_INT_R_EN;

 writel(val, keypad->base + SAMSUNG_KEYIFCON);

 /* KEYIFCOL reg clear. */

//KEYIFCOL寄存器写零,使每个行输入引脚为正常输入模式

 writel(0, keypad->base + SAMSUNG_KEYIFCOL);

}

//按键中断函数

static irqreturn_t samsung_keypad_irq(int irq, void *dev_id)

{

 struct samsung_keypad *keypad = dev_id;

 unsigned int row_state[SAMSUNG_MAX_COLS];

 unsigned int val;

 bool key_down;

 do {

  val = readl(keypad->base + SAMSUNG_KEYIFSTSCLR);

  //清除中断标志位

  writel(~0x0, keypad->base + SAMSUNG_KEYIFSTSCLR);

 //调用按键扫描函数

  samsung_keypad_scan(keypad, row_state);

//按键值上报到android用户空间

  key_down = samsung_keypad_report(keypad, row_state);

  if (key_down)

  //当按键按下时调用下面函数来达到消斗动作用

   wait_event_timeout(keypad->wait, keypad->stopped,

        msecs_to_jiffies(50));

 } while (key_down && !keypad->stopped); //等待按键释放

 return IRQ_HANDLED;

 

4.按键值的定义

  // linux/arch/arm/mach-exynos/mach-smdk4x12.c

按键值定义在input.h中,并且最终按键值要和android中定义的键值匹配才行

static uint32_t smdk4x12_keymap0[] __initdata = {

                  158                                172                                      108

  KEY(0, 0, KEY_BACK),        KEY(0, 1, KEY_HOMEPAGE),  KEY(0, 2, KEY_DOWN),

                  114                                 139                                     115

  KEY(1, 0, KEY_VOLUMEDOWN),  KEY(1, 1, KEY_MENU),      KEY(1, 2, KEY_VOLUMEUP),

                  103                                 105                                      106

  KEY(2, 0, KEY_UP),          KEY(2, 1, KEY_LEFT),      KEY(2, 2, KEY_RIGHT),

};

static struct matrix_keymap_data smdk4x12_keymap_data0 __initdata = {

 .keymap = smdk4x12_keymap0,

 .keymap_size = ARRAY_SIZE(smdk4x12_keymap0),

};

static struct samsung_keypad_platdata smdk4x12_keypad_data0 __initdata = {

 .keymap_data = &smdk4x12_keymap_data0,

 .rows = 3,  //3行

 .cols = 3,  //3列

};

android代码中定义的按键值如下

kernel中定义的键值要和android中定义的键值一一对应

/device/samsung/smdk4x12$

key 103      DPAD_UP                   WAKE_DROPPED

key 3          DPAD_CENTER           WAKE_DROPPED

key 108      DPAD_DOWN             WAKE_DROPPED

key 106      DPAD_RIGHT               WAKE_DROPPED

key 105      DPAD_LEFT                  WAKE_DROPPED

key 114      VOLUME_DOWN          WAKE

key 172      HOME                            WAKE_DROPPED

key 139      MENU                             WAKE_DROPPED

key 115      VOLUME_UP                   WAKE

key 158      BACK                               WAKE_DROPPED

  • 服务电话:
  • 0755-86038900
  • 新浪微博腾讯微博
  •  
  • 扫一扫
  • © 2014-2016 深圳市友坚恒兴科技有限公司. All Right Reserved. 粤ICP备15032578号-1    技术支持:贝尔利网络