📄 mgc270kpd.c
字号:
/* * Keypad driver for MagicARM270, by Abing, GUANGZHOU ZHIYUAN * * Copyright (c) 2006 GUANGZHOU ZHIYUAN ELECTRONICS CO.LTD * * 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/delay.h>#include <linux/platform_device.h>#include <linux/init.h>#include <linux/input.h>#include <linux/interrupt.h>#include <linux/jiffies.h>#include <linux/module.h>#include <linux/slab.h>#include <asm/arch/mainstone.h>#include <asm/arch/hardware.h>#include <asm/arch/pxa-regs.h>#define MGC270_KEY_STROBE_NUM 4#define MGC270_KEY_SENSE_NUM 4#define KB_ROWS 4#define KB_COLS 4#define KB_ROWMASK(r) (1 << (r))#define SCANCODE(r,c) ((r*4) + (c))#define NR_SCANCODES (0x10)#define SCAN_INTERVAL (50) /* ms */#define HINGE_SCAN_INTERVAL (150) /* ms *///#define SPITZ_KEY_SYNC KEY_F9static unsigned char mgc270kpd_keycode[NR_SCANCODES] = { KEY_0, KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7, KEY_8, KEY_9, KEY_A, KEY_B, KEY_C, KEY_D, KEY_E, KEY_F,};static int mgc270kpd_strobes[] = { 103, 104, 105, 106};static int mgc270kpd_senses[] = { 100, 101, 102, 97};#define MGC270_GPIO_G3_STROBE_BIT 0x00000780#define MGC270_GPIO_G3_SENSE_BIT 0x00000072struct mgc270kpd { unsigned char keycode[ARRAY_SIZE(mgc270kpd_keycode)]; struct input_dev *input; char phys[32]; spinlock_t lock; struct timer_list timer;};#define KB_DISCHARGE_DELAY 10#define KB_ACTIVATE_DELAY 10/* Helper functions for reading the keypad matrix * Note: We should really be using pxa_gpio_mode to alter GPDR but it * requires a function call per GPIO bit which is excessive * when we need to access 11 bits at once, multiple times. * These functions must be called within local_irq_save()/local_irq_restore() * or similar. */static inline void mgc270kpd_discharge_all(void){ /* STROBE All Low */ GPCR3 = MGC270_GPIO_G3_STROBE_BIT; GPDR3 &= ~MGC270_GPIO_G3_STROBE_BIT;}static inline void mgc270kpd_activate_all(void){ /* STROBE ALL -> High */ GPSR3 = MGC270_GPIO_G3_STROBE_BIT; GPDR3 |= MGC270_GPIO_G3_STROBE_BIT; udelay(KB_DISCHARGE_DELAY); /* Clear any interrupts we may have triggered when altering the GPIO lines */ GEDR3 = MGC270_GPIO_G3_SENSE_BIT;}static inline void mgc270kpd_activate_col(int col){ int gpio = mgc270kpd_strobes[col]; GPDR3 &= ~MGC270_GPIO_G3_STROBE_BIT; GPSR(gpio) = GPIO_bit(gpio); GPDR(gpio) |= GPIO_bit(gpio);}static inline void mgc270kpd_reset_col(int col){ int gpio = mgc270kpd_strobes[col]; GPDR3 &= ~MGC270_GPIO_G3_STROBE_BIT; GPCR(gpio) = GPIO_bit(gpio); GPDR(gpio) |= GPIO_bit(gpio);}static inline int mgc270kpd_get_row_status(int col){ return ((GPLR3 >> 4) & 0x07) | ((GPLR3 << 2) & 0x08);}/* * The MagicARM270 keypad only generates interrupts when a key is pressed. * When a key is pressed, we enable a timer which then scans the * keypad to detect when the key is released. *//* Scan the hardware keypad and push any changes up through the input layer */static void mgc270kpd_scankeypad(struct mgc270kpd *mgc270kpd_data, struct pt_regs *regs){ unsigned int row, col, rowd; unsigned long flags; unsigned int num_pressed; spin_lock_irqsave(&mgc270kpd_data->lock, flags); input_regs(mgc270kpd_data->input, regs); num_pressed = 0; for (col = 0; col < KB_COLS; col++) { /* * Discharge the output driver capacitatance * in the keypad matrix. (Yes it is significant..) */ mgc270kpd_discharge_all(); udelay(KB_DISCHARGE_DELAY); mgc270kpd_activate_col(col); udelay(KB_ACTIVATE_DELAY); //rowd = ~mgc270kpd_get_row_status(col); rowd = mgc270kpd_get_row_status(col); for (row = 0; row < KB_ROWS; row++) { unsigned int scancode, pressed; scancode = SCANCODE(row, col); pressed = rowd & KB_ROWMASK(row); input_report_key(mgc270kpd_data->input, mgc270kpd_data->keycode[scancode], pressed); if (pressed) num_pressed++; } mgc270kpd_reset_col(col); } mgc270kpd_activate_all(); input_sync(mgc270kpd_data->input); /* if any keys are pressed, enable the timer */ if (num_pressed) mod_timer(&mgc270kpd_data->timer, jiffies + msecs_to_jiffies(SCAN_INTERVAL)); spin_unlock_irqrestore(&mgc270kpd_data->lock, flags);}/* * mgc270 keypad interrupt handler. */static irqreturn_t mgc270kpd_interrupt(int irq, void *dev_id, struct pt_regs *regs){ struct mgc270kpd *mgc270kpd_data = dev_id; if (!timer_pending(&mgc270kpd_data->timer)) { /** wait chattering delay **/ udelay(20); mgc270kpd_scankeypad(mgc270kpd_data, regs); } return IRQ_HANDLED;}/* * mgc270 timer checking for released keys */static void mgc270kpd_timer_callback(unsigned long data){ struct mgc270kpd *mgc270kpd_data = (struct mgc270kpd *) data; mgc270kpd_scankeypad(mgc270kpd_data, NULL);}static int __init mgc270kpd_probe(struct platform_device *dev){ struct mgc270kpd *mgc270kpd; struct input_dev *input_dev; int i; mgc270kpd = kzalloc(sizeof(struct mgc270kpd), GFP_KERNEL); if (!mgc270kpd) return -ENOMEM; input_dev = input_allocate_device(); if (!input_dev) { kfree(mgc270kpd); return -ENOMEM; } platform_set_drvdata(dev, mgc270kpd); strcpy(mgc270kpd->phys, "mgc270kpd/input0"); spin_lock_init(&mgc270kpd->lock); /* Init Keyboard rescan timer */ init_timer(&mgc270kpd->timer); mgc270kpd->timer.function = mgc270kpd_timer_callback; mgc270kpd->timer.data = (unsigned long) mgc270kpd; mgc270kpd->input = input_dev; input_dev->private = mgc270kpd; input_dev->name = "MagicARM270 Keypad"; input_dev->phys = mgc270kpd->phys; input_dev->cdev.dev = &dev->dev; input_dev->id.bustype = BUS_HOST; input_dev->id.vendor = 0x0001; input_dev->id.product = 0x0001; input_dev->id.version = 0x0100; input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP) | BIT(EV_PWR) | BIT(EV_SW); input_dev->keycode = mgc270kpd->keycode; input_dev->keycodesize = sizeof(unsigned char); input_dev->keycodemax = ARRAY_SIZE(mgc270kpd_keycode); memcpy(mgc270kpd->keycode, mgc270kpd_keycode, sizeof(mgc270kpd->keycode)); for (i = 0; i < ARRAY_SIZE(mgc270kpd_keycode); i++) set_bit(mgc270kpd->keycode[i], input_dev->keybit); clear_bit(0, input_dev->keybit); set_bit(SW_LID, input_dev->swbit); set_bit(SW_TABLET_MODE, input_dev->swbit); set_bit(SW_HEADPHONE_INSERT, input_dev->swbit); input_register_device(input_dev); /* Setup sense interrupts - RisingEdge Detect, sense lines as inputs */ for (i = 0; i < MGC270_KEY_SENSE_NUM; i++) { pxa_gpio_mode(mgc270kpd_senses[i] | GPIO_IN); if (request_irq(IRQ_GPIO(mgc270kpd_senses[i]), mgc270kpd_interrupt, IRQF_DISABLED|IRQF_TRIGGER_RISING, "Mgc270kpd Sense", mgc270kpd)) printk(KERN_WARNING "mgc270kpd: Can't get Sense IRQ: %d!\n", i); } /* Set Strobe lines as outputs - set high */ for (i = 0; i < MGC270_KEY_STROBE_NUM; i++) pxa_gpio_mode(mgc270kpd_strobes[i] | GPIO_OUT | GPIO_DFLT_HIGH); printk(KERN_INFO "input: MagicARM270 Keypad Registered\n"); return 0;}static int mgc270kpd_remove(struct platform_device *dev){ int i; struct mgc270kpd *mgc270kpd = platform_get_drvdata(dev); for (i = 0; i < MGC270_KEY_SENSE_NUM; i++) free_irq(IRQ_GPIO(mgc270kpd_senses[i]), mgc270kpd); del_timer_sync(&mgc270kpd->timer); input_unregister_device(mgc270kpd->input); kfree(mgc270kpd); return 0;}static struct platform_driver mgc270kpd_driver = { .probe = mgc270kpd_probe, .remove = mgc270kpd_remove, .driver = { .name = "mgc270-keypad", },};static int __devinit mgc270kpd_init(void){ return platform_driver_register(&mgc270kpd_driver);}static void __exit mgc270kpd_exit(void){ platform_driver_unregister(&mgc270kpd_driver);}module_init(mgc270kpd_init);module_exit(mgc270kpd_exit);MODULE_AUTHOR("Chenxibing <Linux@zlgmcu.com>");MODULE_DESCRIPTION("MagicARM270 Keypad Driver");MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -