📄 omap24xx-keypad.c
字号:
/* * linux/drivers/input/keyboard/omap24xx-keypad.c * * Copyright (C) 2004 Texas Instruments Inc * Author: TI * * Keypad driver for OMAP24xx * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * */#include <linux/config.h>#include <linux/module.h>#include <linux/init.h>#include <linux/interrupt.h>#include <linux/types.h>#include <linux/input.h>#include <linux/kernel.h>#include <linux/delay.h>#include <asm/arch/irqs.h>#include <asm/arch/hardware.h>#include <asm/io.h>#include <asm/errno.h>#include <asm/arch/mux.h>#include <asm/arch/gpio.h>#include <asm/arch/sys_info.h>#include <asm/irq.h>#include "omap24xx-keypad.h"#define INT_GPIO_IRQ_NO(n) (IH_GPIO_BASE+n)//#define DEBUG#if defined(CONFIG_MACH_OMAP_H4)/* values for 2420 IP board, init will update for 2422 and Menelaus */static unsigned int row_gpio_num[NUM_ROWS] = { 88, 89, 124, 11, 6, 96 };static unsigned int col_gpio_num[NUM_COLS] = { 90, 91, 100, 36, 12, 97, 98 };#else#error "Define a valid OMAP24xx platform"#endifstatic void omap_kp_tasklet(unsigned long);static void omap_kp_timer(unsigned long);static struct input_dev omap_kp_dev;static unsigned char previous_state[NUM_COLS];static struct timer_list kp_timer;DECLARE_TASKLET(kp_tasklet, omap_kp_tasklet, 0);#define KEY(col, row, val) (((col) << 28) | ((row) << 24) | (val))static int keymap[] = { KEY(0, 0, KEY_LEFT), KEY(0, 1, KEY_RIGHT), KEY(0, 2, KEY_A), KEY(0, 3, KEY_B), KEY(0, 4, KEY_C),// KEY(0, 5, KEY_D), KEY(1, 0, KEY_DOWN), KEY(1, 1, KEY_UP), KEY(1, 2, KEY_E), KEY(1, 3, KEY_F), KEY(1, 4, KEY_G),// KEY(1, 5, KEY_H), KEY(2, 0, KEY_ENTER), KEY(2, 1, KEY_I), KEY(2, 2, KEY_J), KEY(2, 3, KEY_K), KEY(2, 4, KEY_3),// KEY(2, 5, KEY_HOME), KEY(3, 0, KEY_M), KEY(3, 1, KEY_N), KEY(3, 2, KEY_O), KEY(3, 3, KEY_P), KEY(3, 4, KEY_Q),// KEY(3, 5, KEY_END), KEY(4, 0, KEY_R), KEY(4, 1, KEY_4), KEY(4, 2, KEY_T), KEY(4, 3, KEY_U), KEY(4, 4, KEY_ENTER),// KEY(4, 5, KEY_ESC), KEY(5, 0, KEY_V), KEY(5, 1, KEY_W), KEY(5, 2, KEY_L), KEY(5, 3, KEY_S), KEY(5, 4, KEY_ENTER),// KEY(5, 5, KEY_ESC), KEY(6, 0, KEY_X), KEY(6, 1, KEY_Y), KEY(6, 2, KEY_Z), KEY(6, 3, KEY_1), KEY(6, 4, KEY_2),// KEY(6, 5, KEY_ESC), 0};char *switch_name[NUM_ROWS][NUM_COLS] = { {"S2_L", "S2_D", "S2_S", "S3", "S4", "S23", "NC"}, {"S2_R", "S2_U", "S5", "S6", "S7", "S24", "NC"}, {"S8", "S9", "S10", "S11", "S12", "S25", "NC"}, {"S13", "S14", "S15", "S16", "S17", "S26", "NC"}, {"S18", "S19", "S20", "S21", "S22", "S27", "NC"}, {"NC", "NC", "NC", "NC", "NC", "NC", "NC"},};static irqreturn_t omap_kp_interrupt(int irq, void *dev_id, struct pt_regs *regs){ int i; for (i = 0; i < NUM_ROWS; i++) disable_irq(INT_GPIO_IRQ_NO(row_gpio_num[i])); tasklet_schedule(&kp_tasklet); return IRQ_HANDLED;}static void omap_kp_timer(unsigned long data){ tasklet_schedule(&kp_tasklet);}/* * this function configures the keypad column GPIO pins * to drive high or low * value - bit 0 of "value" corresponds to 1st keypad column GPIO pin level * bit 1 of "value" corresponds to 2nd keypad column GPIO pin level **/static void set_col_gpio_val(u8 value){ int col; for (col = 0; col < NUM_COLS; col++) { if (value & (1 << col)) omap_set_gpio_dataout(col_gpio_num[col], 1); else omap_set_gpio_dataout(col_gpio_num[col], 0); }}/* * this function returns the keypad row GPIO pin levels(high or low) * value - bit 0 of "value" corresponds to 1st keypad row GPIO pin level * bit 1 of "value" corresponds to 2nd keypad row GPIO pin level **/static u8 get_row_gpio_val(void){ int row; u8 value = 0; for (row = 0; row < NUM_ROWS; row++) { if (omap_get_gpio_datain(row_gpio_num[row])) value |= (1 << row); } return value;}/* * this function reads the keypad row GPIO pin levels while driving the * keypad column GPIO pins * the column GPIO pins are driven with one column pin level low and others high * and for all the sequence */static void omap_kp_scan_keypad(unsigned char *state){ int col = 0; /* read the keypad status */ for (col = 0; col < NUM_COLS; col++) { set_col_gpio_val(~(1 << col)); state[col] = ~(get_row_gpio_val()) & ROW_MASK; } set_col_gpio_val(0);}static inline int omap_kp_find_key(int col, int row){ int i, key; key = KEY(col, row, 0); for (i = 0; keymap[i] != 0; i++) { if ((keymap[i] & 0xff000000) == key) { return keymap[i] & 0x00ffffff; } } return -1;}static void omap_kp_tasklet(unsigned long data){ unsigned char present_state[NUM_COLS], changed, key_down = 0; int i, col, row, key; /* check for any changes */ omap_kp_scan_keypad(present_state); /* check for changes and print those */ for (col = 0; col < NUM_COLS; col++) { changed = present_state[col] ^ previous_state[col]; key_down |= present_state[col]; if (changed == 0) continue; for (row = 0; row < NUM_ROWS; row++) { if (!(changed & (1 << row))) continue;#ifdef DEBUG printk(KERN_INFO "key %s %s\n", switch_name[row][col], (present_state[col] & (1 << row)) ? "press" : "release");#endif key = omap_kp_find_key(col, row); if (key < 0) { printk(KERN_WARNING "omap-keypad: Spurious key event %d-%d\n", col, row); continue; } input_report_key(&omap_kp_dev, key, present_state[col] & (1 << row)); } } memcpy(previous_state, present_state, sizeof(previous_state)); if (key_down) { /* some key is pressed - keep irq disabled and use timer * to poll the keypad */ mod_timer(&kp_timer, jiffies + SCAN_RATE); } else { for (i = 0; i < NUM_ROWS; i++) enable_irq(INT_GPIO_IRQ_NO(row_gpio_num[i])); }}static void setup_kbd_pin_mux(void){ u32 cpu = get_cpu_type(); u32 board = get_board_type(); /*configure the mux registers, update any gpio numbers */ /* Row signals */ omap2_cfg_reg(T19_242X_IM_KBR0); omap2_cfg_reg(R19_242X_IM_KBR1); omap2_cfg_reg(V18_242X_IM_KBR2); omap2_cfg_reg(M21_242X_IM_KBR3); omap2_cfg_reg(E5__242X_IM_KBR4); if((cpu == CPU_2420) && (board == BOARD_H4_MENELAUS)){ omap2_cfg_reg(B3__2420__M_KBR5); row_gpio_num[5] = 0; }else omap2_cfg_reg(M18_2420_I__2422_IM_KBR5); /* Column signals */ omap2_cfg_reg(R20_242X_IM_KBC0); omap2_cfg_reg(M14_242X_IM_KBC1); if(board == BOARD_H4_MENELAUS){ omap2_cfg_reg(AA4_242X__M_KBC2); col_gpio_num[2] = 15; }else omap2_cfg_reg(H19_242X_I_KBC2); omap2_cfg_reg(V17_242X_IM_KBC3); omap2_cfg_reg(P21_242X_IM_KBC4); omap2_cfg_reg(L14_242X_IM_KBC5); if((cpu == CPU_2420) && (board == BOARD_H4_MENELAUS)){ omap2_cfg_reg(B13_2420_M_KBC6); col_gpio_num[6] = 38; }else omap2_cfg_reg(N19_2420_I_2422_IM_KBC6);}static int init_kbd_pin_func(void){ int i; /* Cols: outputs */ for (i = 0; i < NUM_COLS; i++) omap_set_gpio_direction(col_gpio_num[i], 0); /* Rows: inputs */ for (i = 0; i < NUM_ROWS; i++) omap_set_gpio_direction(row_gpio_num[i], 1); omap_kp_scan_keypad(previous_state); for (i = 0; i < NUM_ROWS; i++) { omap_set_gpio_edge_ctrl(row_gpio_num[i], OMAP_GPIO_FALLING_EDGE); if (request_irq (INT_GPIO_IRQ_NO(row_gpio_num[i]), omap_kp_interrupt, 0, "omap-keypad", NULL) < 0) { printk(KERN_INFO "request_irq failed for irq no=%d\n", INT_GPIO_IRQ_NO(row_gpio_num[i])); return -EINVAL; } } return(0);}static int __init omap_kp_init(void){ int i, ret = 0; printk(KERN_INFO "OMAP24xx Keypad Driver\n"); init_timer(&kp_timer); kp_timer.function = omap_kp_timer; /* setup input device */ set_bit(EV_KEY, omap_kp_dev.evbit); /* setup for auto repeat feature */ set_bit(EV_REP, omap_kp_dev.evbit); for (i = 0; keymap[i] != 0; i++) set_bit(keymap[i] & 0x00ffffff, omap_kp_dev.keybit); omap_kp_dev.name = "omap24xx-keypad"; input_register_device(&omap_kp_dev); setup_kbd_pin_mux(); ret = init_kbd_pin_func(); return ret;}static void __exit omap_kp_exit(void){ int i; for (i = 0; i < NUM_ROWS; i++) free_irq(INT_GPIO_IRQ_NO(row_gpio_num[i]), NULL); /* disable keypad interrupt handling */ tasklet_disable(&kp_tasklet); del_timer_sync(&kp_timer); /* unregister everything */ input_unregister_device(&omap_kp_dev);}module_init(omap_kp_init);module_exit(omap_kp_exit);MODULE_AUTHOR("TI");MODULE_DESCRIPTION("OMAP24XX Keypad Driver");MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -