歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

OK6410矩陣鍵盤驅動 linux2.6.36

實現了4*4的矩陣鍵盤驅動,

參考文檔 http://www.linuxidc.com/Linux/2012-09/69904.htm

需要注明一點的是:

void samsung_keypad_cfg_gpio(unsigned int rows, unsigned int cols)函數的位置:

arch/arm/mach-s3c64xx/setup-keypad.c 修改方法如下:

  1. voidsamsung_keypad_cfg_gpio(unsigned int rows, unsigned int cols)  
  2.   
  3. {  
  4.   
  5. unsignedint gpio;  
  6.   
  7. unsignedint end;  
  8.   
  9.   
  10.   
  11.   
  12. /*Set all the necessary GPK pins to special-function 3: KP_ROW[x] */  
  13.   
  14. endS3C64XX_GPK(8 + rows);  
  15.   
  16. for(gpio = S3C64XX_GPK(8); gpio < end; gpio++) {  
  17.   
  18. s3c_gpio_cfgpin(gpio,S3C_GPIO_SFN(3));  
  19.   
  20. s3c_gpio_setpull(gpio,S3C_GPIO_PULL_NONE);  
  21.   
  22. }  
  23.   
  24.   
  25.   
  26. /*Set all the necessary GPL pins to special-function 3: KP_COL[x] */  
  27.   
  28. endS3C64XX_GPL(0 + cols);  
  29.   
  30. for(gpio = S3C64XX_GPL(0); gpio < end; gpio++) {  
  31.   
  32. s3c_gpio_cfgpin(gpio,S3C_GPIO_SFN(3));  
  33.   
  34. s3c_gpio_setpull(gpio,S3C_GPIO_PULL_NONE);  
  35.   
  36. }  
  37.   
  38. }  
  39.   
  40. 其中S3C_GPIO_PULL_NONE需要改成S3C_GPIO_PULL_UP  

此外,還需要修改一點,代碼原先為2*8的矩陣鍵盤,需修改為4*4的矩陣鍵盤

在arch/arm/mach-s3c64xx/mach-smdk6410.c中,在380行中修改為如下:

  1. static struct samsung_keypad_platdata smdk6410_keypad_data _initdata={  
  2.   
  3.           .keymap_data = & smdk6410_keymap_data,  
  4.   
  5.           .rows  =  4,  
  6.   
  7.           .cols    = 4,  
  8.   
  9. };  

整個代碼如下:

samsung-keypad,c :

  1. /*  
  2.  * Samsung keypad driver  
  3.  *  
  4.  * Copyright (C) 2010 Samsung Electronics Co.Ltd  
  5.  * Author: Joonyoung Shim <jy0922.shim@samsung.com>  
  6.  * Author: Donghwa Lee <dh09.lee@samsung.com>  
  7.  *  
  8.  * This program is free software; you can redistribute  it and/or modify it  
  9.  * under  the terms of  the GNU General  Public License as published by the  
  10.  * Free Software Foundation;  either version 2 of the  License, or (at your  
  11.  * option) any later version.  
  12.  */  
  13.   
  14. #include <linux/clk.h>  
  15. #include <linux/delay.h>  
  16. #include <linux/err.h>  
  17. #include <linux/init.h>  
  18. #include <linux/input.h>  
  19. #include <linux/interrupt.h>  
  20. #include <linux/io.h>  
  21. #include <linux/module.h>  
  22. #include <linux/platform_device.h>  
  23. #include <linux/slab.h>  
  24. #include <linux/sched.h>  
  25. #include <plat/keypad.h>  
  26.   
  27. #define SAMSUNG_KEYIFCON            0x00  
  28. #define SAMSUNG_KEYIFSTSCLR         0x04  
  29. #define SAMSUNG_KEYIFCOL            0x08  
  30. #define SAMSUNG_KEYIFROW            0x0c  
  31. #define SAMSUNG_KEYIFFC             0x10  
  32.   
  33. /* SAMSUNG_KEYIFCON */  
  34. #define SAMSUNG_KEYIFCON_INT_F_EN       (1 << 0)  
  35. #define SAMSUNG_KEYIFCON_INT_R_EN       (1 << 1)  
  36. #define SAMSUNG_KEYIFCON_DF_EN          (1 << 2)  
  37. #define SAMSUNG_KEYIFCON_FC_EN          (1 << 3)  
  38. #define SAMSUNG_KEYIFCON_WAKEUPEN       (1 << 4)  
  39.   
  40. /* SAMSUNG_KEYIFSTSCLR */  
  41. #define SAMSUNG_KEYIFSTSCLR_P_INT_MASK      (0xff << 0)  
  42. #define SAMSUNG_KEYIFSTSCLR_R_INT_MASK      (0xff << 8)  
  43. #define SAMSUNG_KEYIFSTSCLR_R_INT_OFFSET    8  
  44. #define S5PV210_KEYIFSTSCLR_P_INT_MASK      (0x3fff << 0)  
  45. #define S5PV210_KEYIFSTSCLR_R_INT_MASK      (0x3fff << 16)  
  46. #define S5PV210_KEYIFSTSCLR_R_INT_OFFSET    16  
  47.   
  48. /* SAMSUNG_KEYIFCOL */  
  49. #define SAMSUNG_KEYIFCOL_MASK           (0xff << 0)  
  50. #define S5PV210_KEYIFCOLEN_MASK         (0xff << 8)  
  51.   
  52. unsigned int keypad_keycode[] = {'1','2','3','4','5','6','7','8','9','A','B','C','D','E','F','G'};  
  53.   
  54. /* SAMSUNG_KEYIFROW */  
  55. #define SAMSUNG_KEYIFROW_MASK           (0xff << 0)  
  56. #define S5PV210_KEYIFROW_MASK           (0x3fff << 0)  
  57.   
  58. /* SAMSUNG_KEYIFFC */  
  59. #define SAMSUNG_KEYIFFC_MASK            (0x3ff << 0)  
  60.   
  61.   
  62.   
  63. enum samsung_keypad_type {  
  64.     KEYPAD_TYPE_SAMSUNG,  
  65.     KEYPAD_TYPE_S5PV210,  
  66. };  
  67.   
  68. struct samsung_keypad {  
  69.     struct input_dev *input_dev;  
  70.     struct clk *clk;  
  71.     void __iomem *base;  
  72.     wait_queue_head_t wait;  
  73.     bool stopped;  
  74.     int irq;  
  75.     unsigned int row_shift;  
  76.     unsigned int rows;  
  77.     unsigned int cols;  
  78.     unsigned int row_state[SAMSUNG_MAX_COLS];  
  79.     unsigned short keycodes[];  
  80. };  
  81.   
  82. static int samsung_keypad_is_s5pv210(struct device *dev)  
  83. {  
  84.     struct platform_device *pdev = to_platform_device(dev);  
  85.     enum samsung_keypad_type type =  
  86.         platform_get_device_id(pdev)->driver_data;  
  87.   
  88.     return type == KEYPAD_TYPE_S5PV210;  
  89. }  
  90.   
  91. static void samsung_keypad_scan(struct samsung_keypad *keypad,  
  92.                 unsigned int *row_state)  
  93. {  
  94. //  struct device *dev = keypad->input_dev->dev.parent;  
  95.     unsigned int col;  
  96.     unsigned int val;  
  97.   
  98. //  printk("<0>samsung_keypad_scan!\n");  
  99.   
  100.     for (col = 0; col < keypad->cols; col++) {  
  101.         /*if (samsung_keypad_is_s5pv210(dev)) {  
  102.             val = S5PV210_KEYIFCOLEN_MASK;  
  103.             val &= ~(1 << col<< 8;  
  104.         } else {*/  
  105.             val = SAMSUNG_KEYIFCOL_MASK;  
  106.             val &= ~(1 << col);  
  107.         //}  
  108.   
  109.         writel(val, keypad->base + SAMSUNG_KEYIFCOL);  
  110.         mdelay(1);  
  111.   
  112.         val = readl(keypad->base + SAMSUNG_KEYIFROW);  
  113.         row_state[col] = ~val & ((1 << keypad->rows) - 1);  
  114.     }  
  115.   
  116.     /* KEYIFCOL reg clear */  
  117.     writel(0, keypad->base + SAMSUNG_KEYIFCOL);  
  118. }  
  119.   
  120. static bool samsung_keypad_report(struct samsung_keypad *keypad,  
  121.                   unsigned int *row_state)  
  122. {  
  123.     struct input_dev *input_dev = keypad->input_dev;  
  124.     unsigned int changed;  
  125.     unsigned int pressed;  
  126.     unsigned int key_down = 0;  
  127.     unsigned int val;  
  128.     unsigned int col, row;  
  129.   
  130.   
  131.     for (col = 0; col < keypad->cols; col++) {  
  132.         changed = row_state[col] ^ keypad->row_state[col];  
  133.         key_down |= row_state[col];  
  134.         if (!changed)  
  135.             continue;  
  136.   
  137.         for (row = 0; row < keypad->rows; row++) {  
  138.             if (!(changed & (1 << row)))  
  139.                 continue;  
  140.   
  141.             pressed = row_state[col] & (1 << row);  
  142.   
  143.             printk("\n<0>samsung_keypad key %s,row:%d,col:%d\n"  
  144.                              ,(pressed ? "pressed":"released"),row,col );  
  145.   
  146.             dev_dbg(&keypad->input_dev->dev,  
  147.                 "key %s, row: %d, col: %d\n",  
  148.                 pressed ? "pressed" : "released", row, col);  
  149.   
  150.             val = MATRIX_SCAN_CODE(row, col, keypad->row_shift);  
  151.   
  152.             input_event(input_dev, EV_MSC, MSC_SCAN, val);  
  153.             input_report_key(input_dev,  
  154.                     keypad->keycodes[val], pressed);  
  155.         }  
  156.         input_sync(keypad->input_dev);  
  157.     }  
  158.   
  159.     memcpy(keypad->row_state, row_state, sizeof(keypad->row_state));  
  160.   
  161.     return key_down;  
  162. }  
  163.   
  164. static irqreturn_t samsung_keypad_irq(int irq, void *dev_id)  
  165. {  
  166.     struct samsung_keypad *keypad = dev_id;  
  167.     unsigned int row_state[SAMSUNG_MAX_COLS];  
  168.     unsigned int val;  
  169.     bool key_down;  
  170.   
  171.     do {  
  172.         val = readl(keypad->base + SAMSUNG_KEYIFSTSCLR);  
  173.         /* Clear interrupt. */  
  174.         writel(~0x0, keypad->base + SAMSUNG_KEYIFSTSCLR);  
  175.   
  176.         samsung_keypad_scan(keypad, row_state);  
  177.   
  178.         key_down = samsung_keypad_report(keypad, row_state);  
  179.         if (key_down)  
  180.             wait_event_timeout(keypad->wait, keypad->stopped,  
  181.                        msecs_to_jiffies(50));  
  182.   
  183.     } while (key_down && !keypad->stopped);  
  184.   
  185.     return IRQ_HANDLED;  
  186. }  
  187.   
  188. static void samsung_keypad_start(struct samsung_keypad *keypad)  
  189. {  
  190.     unsigned int val;  
  191.   
  192.     /* Tell IRQ thread that it may poll the device. */  
  193.     keypad->stopped = false;  
  194.   
  195.     clk_enable(keypad->clk);  
  196.   
  197.     /* Enable interrupt bits. */  
  198.     val = readl(keypad->base + SAMSUNG_KEYIFCON);  
  199.     val |= SAMSUNG_KEYIFCON_INT_F_EN | SAMSUNG_KEYIFCON_INT_R_EN;  
  200.     writel(val, keypad->base + SAMSUNG_KEYIFCON);  
  201.   
  202.     /* KEYIFCOL reg clear. */  
  203.     writel(0, keypad->base + SAMSUNG_KEYIFCOL);  
  204. }  
  205.   
  206. static void samsung_keypad_stop(struct samsung_keypad *keypad)  
  207. {  
  208.     unsigned int val;  
  209.   
  210.     /* Signal IRQ thread to stop polling and disable the handler. */  
  211.     keypad->stopped = true;  
  212.     wake_up(&keypad->wait);  
  213.     disable_irq(keypad->irq);  
  214.   
  215.     /* Clear interrupt. */  
  216.     writel(~0x0, keypad->base + SAMSUNG_KEYIFSTSCLR);  
  217.   
  218.     /* Disable interrupt bits. */  
  219.     val = readl(keypad->base + SAMSUNG_KEYIFCON);  
  220.     val &= ~(SAMSUNG_KEYIFCON_INT_F_EN | SAMSUNG_KEYIFCON_INT_R_EN);  
  221.     writel(val, keypad->base + SAMSUNG_KEYIFCON);  
  222.   
  223.     clk_disable(keypad->clk);  
  224.   
  225.     /*  
  226.      * Now that chip should not generate interrupts we can safely  
  227.      * re-enable the handler.  
  228.      */  
  229.     enable_irq(keypad->irq);  
  230. }  
  231.   
  232. static int samsung_keypad_open(struct input_dev *input_dev)  
  233. {  
  234.     printk("<0>samsung_keypad_open!\n");  
  235.     struct samsung_keypad *keypad = input_get_drvdata(input_dev);  
  236.   
  237.     samsung_keypad_start(keypad);  
  238.   
  239.     return 0;  
  240. }  
  241.   
  242. static void samsung_keypad_close(struct input_dev *input_dev)  
  243. {  
  244.     struct samsung_keypad *keypad = input_get_drvdata(input_dev);  
  245.   
  246.     samsung_keypad_stop(keypad);  
  247. }  
  248.   
  249. static int __devinit samsung_keypad_probe(struct platform_device *pdev)  
  250. {  
  251.     const struct samsung_keypad_platdata *pdata;  
  252.     const struct matrix_keymap_data *keymap_data;  
  253.     struct samsung_keypad *keypad;  
  254.     struct resource *res;  
  255.     struct input_dev *input_dev;  
  256.     unsigned int row_shift;  
  257.     unsigned int keymap_size;  
  258.     int error;  
  259.   
  260.     unsigned int key=0;  
  261.     unsigned int keycodes_size=sizeof(keypad_keycode)/sizeof(keypad_keycode[0]);  
  262.   
  263.     printk("<0>samsung_keypad_probe!\n");  
  264.   
  265.     pdata = pdev->dev.platform_data;  
  266.     if (!pdata) {  
  267.         dev_err(&pdev->dev, "no platform data defined\n");  
  268.         return -EINVAL;  
  269.     }  
  270.   
  271.     keymap_data = pdata->keymap_data;  
  272.     if (!keymap_data) {  
  273.         dev_err(&pdev->dev, "no keymap data defined\n");  
  274.         return -EINVAL;  
  275.     }  
  276.   
  277.     if (!pdata->rows || pdata->rows > SAMSUNG_MAX_ROWS)  
  278.         return -EINVAL;  
  279.   
  280.     if (!pdata->cols || pdata->cols > SAMSUNG_MAX_COLS)  
  281.         return -EINVAL;  
  282.   
  283.     /* initialize the gpio */  
  284.     if (pdata->cfg_gpio)  
  285.         pdata->cfg_gpio(pdata->rows, pdata->cols);  
  286.   
  287.     row_shift = get_count_order(pdata->cols);  
  288.     keymap_size = (pdata->rows << row_shift) * sizeof(keypad->keycodes[0]);  
  289.   
  290.     keypad = kzalloc(sizeof(*keypad) + keymap_size, GFP_KERNEL);  
  291.     input_dev = input_allocate_device();  
  292.     if (!keypad || !input_dev) {  
  293.         error = -ENOMEM;  
  294.         goto err_free_mem;  
  295.     }  
  296.   
  297.     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);  
  298.     if (!res) {  
  299.         error = -ENODEV;  
  300.         goto err_free_mem;  
  301.     }  
  302.   
  303.     keypad->base = ioremap(res->start, resource_size(res));  
  304.     if (!keypad->base) {  
  305.         error = -EBUSY;  
  306.         goto err_free_mem;  
  307.     }  
  308.   
  309.     keypad->clk = clk_get(&pdev->dev, "keypad");  
  310.     if (IS_ERR(keypad->clk)) {  
  311.         dev_err(&pdev->dev, "failed to get keypad clk\n");  
  312.         error = PTR_ERR(keypad->clk);  
  313.         goto err_unmap_base;  
  314.     }  
  315.   
  316.     keypad->input_dev = input_dev;  
  317.     keypad->row_shift = row_shift;  
  318.     keypad->rows = pdata->rows;  
  319.     keypad->cols = pdata->cols;  
  320.     init_waitqueue_head(&keypad->wait);  
  321.   
  322.     input_dev->name = pdev->name;  
  323.     input_dev->id.bustype = BUS_HOST;  
  324.     input_dev->dev.parent = &pdev->dev;  
  325.     input_set_drvdata(input_dev, keypad);  
  326.   
  327.     input_dev->open = samsung_keypad_open;  
  328.     input_dev->close = samsung_keypad_close;  
  329.   
  330.     input_dev->evbit[0] = BIT_MASK(EV_KEY);  
  331.     if (!pdata->no_autorepeat)  
  332.         input_dev->evbit[0] |= BIT_MASK(EV_REP);  
  333.   
  334.     input_set_capability(input_dev, EV_MSC, MSC_SCAN);  
  335.   
  336.     input_dev->keycode = keypad->keycodes;  
  337.     input_dev->keycodesize = sizeof(keypad->keycodes[0]);  
  338.     input_dev->keycodemax = pdata->rows << row_shift;  
  339.   
  340.     /*matrix_keypad_build_keymap(keymap_data, row_shift,  
  341.             input_dev->keycode, input_dev->keybit);*/  
  342.         for(key=0;key<keycodes_size;key++){  
  343.         int code=keypad->keycodes[key]=keypad_keycode[key];  
  344.         if(code<=0)  
  345.             continue;  
  346.         __set_bit(code,input_dev->keybit);  
  347.     }  
  348.     __clear_bit(0,input_dev->keybit);  
  349.   
  350.     keypad->irq = platform_get_irq(pdev, 0);  
  351.     if (keypad->irq < 0) {  
  352.         error = keypad->irq;  
  353.         goto err_put_clk;  
  354.     }  
  355.   
  356.     error = request_threaded_irq(keypad->irq, NULL, samsung_keypad_irq,  
  357.             IRQF_ONESHOT, dev_name(&pdev->dev), keypad);  
  358.     if (error) {  
  359.         dev_err(&pdev->dev, "failed to register keypad interrupt\n");  
  360.         goto err_put_clk;  
  361.     }  
  362.   
  363.     error = input_register_device(keypad->input_dev);  
  364.     if (error)  
  365.         goto err_free_irq;  
  366.   
  367.     device_init_wakeup(&pdev->dev, pdata->wakeup);  
  368.     platform_set_drvdata(pdev, keypad);  
  369.     return 0;  
  370.   
  371. err_free_irq:  
  372.     free_irq(keypad->irq, keypad);  
  373. err_put_clk:  
  374.     clk_put(keypad->clk);  
  375. err_unmap_base:  
  376.     iounmap(keypad->base);  
  377. err_free_mem:  
  378.     input_free_device(input_dev);  
  379.     kfree(keypad);  
  380.   
  381.     return error;  
  382. }  
  383.   
  384. static int __devexit samsung_keypad_remove(struct platform_device *pdev)  
  385. {  
  386.     struct samsung_keypad *keypad = platform_get_drvdata(pdev);  
  387.   
  388.     device_init_wakeup(&pdev->dev, 0);  
  389.     platform_set_drvdata(pdev, NULL);  
  390.   
  391.     input_unregister_device(keypad->input_dev);  
  392.   
  393.     /*  
  394.      * It is safe to free IRQ after unregistering device because  
  395.      * samsung_keypad_close will shut off interrupts.  
  396.      */  
  397.     free_irq(keypad->irq, keypad);  
  398.   
  399.     clk_put(keypad->clk);  
  400.   
  401.     iounmap(keypad->base);  
  402.     kfree(keypad);  
  403.   
  404.     return 0;  
  405. }  
  406.   
  407. #ifdef CONFIG_PM  
  408. static void samsung_keypad_toggle_wakeup(struct samsung_keypad *keypad,  
  409.                      bool enable)  
  410. {  
  411.     struct device *dev = keypad->input_dev->dev.parent;  
  412.     unsigned int val;  
  413.   
  414.     clk_enable(keypad->clk);  
  415.   
  416.     val = readl(keypad->base + SAMSUNG_KEYIFCON);  
  417.     if (enable) {  
  418.         val |= SAMSUNG_KEYIFCON_WAKEUPEN;  
  419.         if (device_may_wakeup(dev))  
  420.             enable_irq_wake(keypad->irq);  
  421.     } else {  
  422.         val &= ~SAMSUNG_KEYIFCON_WAKEUPEN;  
  423.         if (device_may_wakeup(dev))  
  424.             disable_irq_wake(keypad->irq);  
  425.     }  
  426.     writel(val, keypad->base + SAMSUNG_KEYIFCON);  
  427.   
  428.     clk_disable(keypad->clk);  
  429. }  
  430.   
  431. static int samsung_keypad_suspend(struct device *dev)  
  432. {  
  433.     struct platform_device *pdev = to_platform_device(dev);  
  434.     struct samsung_keypad *keypad = platform_get_drvdata(pdev);  
  435.     struct input_dev *input_dev = keypad->input_dev;  
  436.   
  437.     mutex_lock(&input_dev->mutex);  
  438.   
  439.     if (input_dev->users)  
  440.         samsung_keypad_stop(keypad);  
  441.   
  442.     samsung_keypad_toggle_wakeup(keypad, true);  
  443.   
  444.     mutex_unlock(&input_dev->mutex);  
  445.   
  446.     return 0;  
  447. }  
  448.   
  449. static int samsung_keypad_resume(struct device *dev)  
  450. {  
  451.     struct platform_device *pdev = to_platform_device(dev);  
  452.     struct samsung_keypad *keypad = platform_get_drvdata(pdev);  
  453.     struct input_dev *input_dev = keypad->input_dev;  
  454.   
  455.     mutex_lock(&input_dev->mutex);  
  456.   
  457.     samsung_keypad_toggle_wakeup(keypad, false);  
  458.   
  459.     if (input_dev->users)  
  460.         samsung_keypad_start(keypad);  
  461.   
  462.     mutex_unlock(&input_dev->mutex);  
  463.   
  464.     return 0;  
  465. }  
  466.   
  467. static const struct dev_pm_ops samsung_keypad_pm_ops = {  
  468.     .suspend    = samsung_keypad_suspend,  
  469.     .resume     = samsung_keypad_resume,  
  470. };  
  471. #endif  
  472.   
  473. static struct platform_device_id samsung_keypad_driver_ids[] = {  
  474.     {  
  475.         .name       = "samsung-keypad",  
  476.         .driver_data    = KEYPAD_TYPE_SAMSUNG,  
  477.     }, {  
  478.         .name       = "s5pv210-keypad",  
  479.         .driver_data    = KEYPAD_TYPE_S5PV210,  
  480.     },  
  481.     { },  
  482. };  
  483. MODULE_DEVICE_TABLE(platform, samsung_keypad_driver_ids);  
  484.   
  485. static struct platform_driver samsung_keypad_driver = {  
  486.     .probe      = samsung_keypad_probe,  
  487.     .remove     = __devexit_p(samsung_keypad_remove),  
  488.     .driver     = {  
  489.         .name   = "samsung-keypad",  
  490.         .owner  = THIS_MODULE,  
  491. #ifdef CONFIG_PM  
  492.         .pm = &samsung_keypad_pm_ops,  
  493. #endif  
  494.     },  
  495.     .id_table   = samsung_keypad_driver_ids,  
  496. };  
  497.   
  498. static int __init samsung_keypad_init(void)  
  499. {  
  500.     printk("<0>adc_drv_open and adc_init()\n");  
  501.     return platform_driver_register(&samsung_keypad_driver);  
  502. }  
  503. module_init(samsung_keypad_init);  
  504.   
  505. static void __exit samsung_keypad_exit(void)  
  506. {  
  507.     platform_driver_unregister(&samsung_keypad_driver);  
  508. }  
  509. module_exit(samsung_keypad_exit);  
  510.   
  511. MODULE_DESCRIPTION("Samsung keypad driver");  
  512. MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");  
  513. MODULE_AUTHOR("Donghwa Lee <dh09.lee@samsung.com>");  
  514. MODULE_LICENSE("GPL");  
  515. MODULE_ALIAS("platform:samsung-keypad");  
Copyright © Linux教程網 All Rights Reserved