⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mgc270kpd.c

📁 这是pxa270下的键盘驱动程序
💻 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 + -