曾经做amlogic方案时,给一个客户调试过一个编码开关的驱动,两个编码开关,使用四个GPIO口去通过中断检查。代码如下:
在BSP文件中增加如下内容:
#if defined(CONFIG_CODING_KEY_AM)
#include <linux/input.h>
#include <linux/input/coding_key.h>
#define GPIO_CODING_KEYIRQ1 ((GPIOB_bank_bit0_7(4)<<16) | GPIOB_bit_bit0_7(4))
#define GPIO_CODING_KEYIRQ2 ((GPIOB_bank_bit0_7(5)<<16) | GPIOB_bit_bit0_7(5))
#define GPIO_CODING_KEYIRQ3 ((GPIOB_bank_bit0_7(6)<<16) | GPIOB_bit_bit0_7(6))
#define GPIO_CODING_KEYIRQ4 ((GPIOB_bank_bit0_7(7)<<16) | GPIOB_bit_bit0_7(7))
int _key_coding_list[] = {KEY_DOWN,KEY_UP,KEY_RIGHT,KEY_LEFT};
static int read_key_value_num1(void)
{
int keyirq1,keyirq3;
udelay(100);
keyirq1=gpio_get_value(GPIO_CODING_KEYIRQ1);
udelay(100);
keyirq3=gpio_get_value(GPIO_CODING_KEYIRQ3);
return (keyirq1+(keyirq3<<1));
}
static int read_key_value_num2(void)
{
int keyirq2,keyirq4;
udelay(100);
keyirq2=gpio_get_value(GPIO_CODING_KEYIRQ2);
udelay(100);
keyirq4=gpio_get_value(GPIO_CODING_KEYIRQ4);
return (keyirq2+(keyirq4<<1));
}
/**
*
*编码开关说明:
*
*coding_key_init_func 是为了初始化,设置中断方式和中断号,四个用于编码开关的四个IO口
*M1 总共有8个IO口中断,分别对应INT_GPIO_0~7
*gpio_enable_edge_int 是用来设置中断触发方式和对应中断号
*因为引脚是复用脚,在使用时需要清掉其复用功能
*
*azad 2011.12.11
*
**/
static int coding_key_init_func(void)
{
/* set input mode */
CLEAR_CBUS_REG_MASK(PERIPHS_PIN_MUX_2, 1<<19);
CLEAR_CBUS_REG_MASK(PERIPHS_PIN_MUX_2, 1<<18);
CLEAR_CBUS_REG_MASK(PERIPHS_PIN_MUX_2, 1<<17);
CLEAR_CBUS_REG_MASK(PERIPHS_PIN_MUX_2, 1<<16); //clear SD_D0_C[19:16]
CLEAR_CBUS_REG_MASK(PERIPHS_PIN_MUX_6, 1<<27); //clear SPI
CLEAR_CBUS_REG_MASK(PERIPHS_PIN_MUX_2, 1<<23);
CLEAR_CBUS_REG_MASK(PERIPHS_PIN_MUX_2, 1<<22);
CLEAR_CBUS_REG_MASK(PERIPHS_PIN_MUX_2, 1<<21);
CLEAR_CBUS_REG_MASK(PERIPHS_PIN_MUX_2, 1<<20);
CLEAR_CBUS_REG_MASK(PERIPHS_PIN_MUX_11, 1<<9);
CLEAR_CBUS_REG_MASK(PERIPHS_PIN_MUX_11, 1<<8);
CLEAR_CBUS_REG_MASK(PERIPHS_PIN_MUX_11, 1<<7);
CLEAR_CBUS_REG_MASK(PERIPHS_PIN_MUX_11, 1<<6);
gpio_direction_input(GPIO_CODING_KEYIRQ1);
gpio_direction_input(GPIO_CODING_KEYIRQ2);
gpio_direction_input(GPIO_CODING_KEYIRQ3);
gpio_direction_input(GPIO_CODING_KEYIRQ4);
/* set gpio interrupt #1 source=GPIOB_4, and triggered by falling edge(=1) */
gpio_enable_edge_int(gpio_to_idx(GPIO_CODING_KEYIRQ1), 1, 1);
/* set gpio interrupt #2 source=GPIOB_5, and triggered by falling edge(=1) */
gpio_enable_edge_int(gpio_to_idx(GPIO_CODING_KEYIRQ2), 1, 2);
/* set gpio interrupt #3 source=GPIOB_6, and triggered by falling edge(=1) */
gpio_enable_edge_int(gpio_to_idx(GPIO_CODING_KEYIRQ3), 1, 3);
/* set gpio interrupt #4 source=GPIOB_7, and triggered by falling edge(=1) */
gpio_enable_edge_int(gpio_to_idx(GPIO_CODING_KEYIRQ4), 1, 4);
return 0;
}
static struct coding_key_platform_data coding_key_pdata = {
.key_code_list = &_key_coding_list[0],
.key_num = ARRAY_SIZE(_key_coding_list),
.init_irq = coding_key_init_func,
.read_key1=read_key_value_num1,
.read_key2=read_key_value_num2,
};
static struct platform_device coding_device_key = {
.name = "coding_key",
.id = 0,
.num_resources = 0,
.resource = NULL,
.dev = {
.platform_data = &coding_key_pdata,
}
};
#endif
驱动的代码如下:
/*
* linux/drivers/input/key_input/key_input.c
*
* GPIO Coding Key Driver
*
* Copyright (C) 2011 EC3 Corporation
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* author : azad Yu
*/
#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 <linux/platform_device.h>
#include <linux/mutex.h>
#include <linux/errno.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <mach/am_regs.h>
#include <mach/pinmux.h>
#include <linux/major.h>
#include <linux/slab.h>
#include <asm/uaccess.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 <linux/platform_device.h>
#include <linux/mutex.h>
#include <linux/errno.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <mach/am_regs.h>
#include <mach/pinmux.h>
#include <linux/major.h>
#include <linux/slab.h>
#include <asm/uaccess.h>
#include <linux/input/coding_key.h>
static void codingkey_tasklet(unsigned long data);
DECLARE_TASKLET_DISABLED(coding_tasklet, codingkey_tasklet, 0);
struct coding_key {
struct input_dev *input;
int major;
char name[20];
struct class *class;
struct device *dev;
struct coding_key_platform_data *pdata;
};
static struct coding_key *CodingKey = NULL;
static read_coding_key_num1(unsigned long data)
{
static unsigned char st_num1 =0;
static unsigned char cw_d_num1 = 0x03;
unsigned char sw_data_num1;
struct coding_key *coding_data=(struct coding_key *)data;
sw_data_num1=coding_data->pdata->read_key1();
if(sw_data_num1 == 0x03)
st_num1=1;
//printk("the state of the st = %d..sw_data =%d ..cw_d =%d..\n",st,sw_data,cw_d);
if(st_num1)
{
if((sw_data_num1==0x00)&&(cw_d_num1==0x02))
{
st_num1=0;
printk("================up==============\n");
input_report_key(coding_data->input, coding_data->pdata->key_code_list[0], 1);
input_report_key(coding_data->input, coding_data->pdata->key_code_list[0], 0);
}
if((sw_data_num1==0x02)&&(cw_d_num1==0x00))
{
st_num1=0;
printk("===============down=============\n");
input_report_key(coding_data->input, coding_data->pdata->key_code_list[1], 1);
input_report_key(coding_data->input, coding_data->pdata->key_code_list[1], 0);
}
}
cw_d_num1 = sw_data_num1;
}
static read_coding_key_num2(unsigned long data)
{
static unsigned char st_num2 =0;
static unsigned char cw_d_num2 = 0x03;
unsigned char sw_data_num2;
struct coding_key *coding_data=(struct coding_key *)data;
sw_data_num2=coding_data->pdata->read_key2();
if(sw_data_num2 == 0x03)
st_num2=1;
//printk("the state of the st = %d..sw_data =%d ..cw_d =%d..\n",st,sw_data,cw_d);
if(st_num2)
{
if((sw_data_num2==0x00)&&(cw_d_num2==0x02))
{
st_num2=0;
printk("================up==============\n");
input_report_key(coding_data->input, coding_data->pdata->key_code_list[2], 1);
input_report_key(coding_data->input, coding_data->pdata->key_code_list[2], 0);
}
if((sw_data_num2==0x02)&&(cw_d_num2==0x00))
{
st_num2=0;
printk("===============down=============\n");
input_report_key(coding_data->input, coding_data->pdata->key_code_list[3], 1);
input_report_key(coding_data->input, coding_data->pdata->key_code_list[3], 0);
}
}
cw_d_num2 = sw_data_num2;
}
static void codingkey_tasklet(unsigned long data)
{
read_coding_key_num1(data);
read_coding_key_num2(data);
}
static irqreturn_t coding_key_interrupt(int irq, void *dev)
{
tasklet_schedule(&coding_tasklet);
return IRQ_HANDLED;
}
static int
coding_key_open(struct inode *inode, struct file *file)
{
file->private_data = CodingKey;
return 0;
}
static int
coding_key_release(struct inode *inode, struct file *file)
{
file->private_data=NULL;
return 0;
}
static const struct file_operations coding_key_fops = {
.owner = THIS_MODULE,
.open = coding_key_open,
.ioctl = NULL,
.release = coding_key_release,
};
static int register_key_input_dev(struct coding_key *coding_data)
{
int ret=0;
strcpy(coding_data->name,"coding_key_input");
ret=register_chrdev(0, coding_data->name, &coding_key_fops);
if(ret<=0)
{
printk("register char device error\r\n");
return ret ;
}
coding_data->major=ret;
printk("key_input major:%d\r\n",ret);
coding_data->class=class_create(THIS_MODULE,coding_data->name);
coding_data->dev=device_create(coding_data->class, NULL,
MKDEV(coding_data->major,0), NULL, coding_data->name);
return ret;
}
static int __init coding_key_probe(struct platform_device *pdev)
{
struct coding_key *coding_data = NULL;
struct input_dev *input_dev = NULL;
int i,ret = 0;
struct coding_key_platform_data *pdata = pdev->dev.platform_data;
if (!pdata) {
dev_err(&pdev->dev, "platform data is required!\n");
ret = -EINVAL;
goto CATCH_ERR;
}
coding_data = kzalloc(sizeof(struct coding_key), GFP_KERNEL);
input_dev = input_allocate_device();
if (!coding_data ) {
ret = -ENOMEM;
goto CATCH_ERR;
}
CodingKey = coding_data;
platform_set_drvdata(pdev, coding_data);
coding_data->input = input_dev;
coding_data->pdata = pdata;
if(coding_data->pdata->init_irq != NULL)
{
if(coding_data->pdata->init_irq() < 0)
{
printk(KERN_ERR "coding_data->pdata->init_irq() failed.\n");
ret = -EINVAL;
goto CATCH_ERR;
}
}
/* setup input device */
set_bit(EV_KEY, input_dev->evbit);
set_bit(EV_REP, input_dev->evbit);
for(i = 0; i < pdata->key_num; i++)
{
set_bit(pdata->key_code_list[i], input_dev->keybit);
printk(KERN_INFO "Key %d registed.\n", pdata->key_code_list[i]);
}
input_dev->name = "coding_key";
input_dev->phys = "coding_key/input0";
input_dev->dev.parent = &pdev->dev;
input_dev->id.bustype = BUS_ISA;
input_dev->id.vendor = 0x0001;
input_dev->id.product = 0x0001;
input_dev->id.version = 0x0100;
input_dev->rep[REP_DELAY]=0xffffffff;
input_dev->rep[REP_PERIOD]=0xffffffff;
input_dev->keycodesize = sizeof(unsigned short);
input_dev->keycodemax = 0x1ff;
ret = input_register_device(coding_data->input);
if (ret < 0) {
printk(KERN_ERR "Unable to register key input device.\n");
ret = -EINVAL;
goto CATCH_ERR;
}
tasklet_enable(&coding_tasklet);
coding_tasklet.data = (unsigned long)CodingKey;
//ret = request_irq(INT_GPIO_1, (irq_handler_t) coding_key_interrupt, IRQF_TRIGGER_FALLING, "coding key", coding_data);
ret = request_irq(INT_GPIO_1, (irq_handler_t) coding_key_interrupt, IRQF_TRIGGER_FALLING, "coding key", NULL);
ret = request_irq(INT_GPIO_2, (irq_handler_t) coding_key_interrupt, IRQF_TRIGGER_FALLING, "coding key", NULL);
ret = request_irq(INT_GPIO_3, (irq_handler_t) coding_key_interrupt, IRQF_TRIGGER_FALLING, "coding key", NULL);
ret = request_irq(INT_GPIO_4, (irq_handler_t) coding_key_interrupt, IRQF_TRIGGER_FALLING, "coding key", NULL);
if (ret < 0) {
printk(KERN_ERR "Unable to register key input irq.\n");
ret = -EINVAL;
goto CATCH_ERR;
}
printk("Key input register input device completed.\r\n");
register_key_input_dev(CodingKey);
return 0;
CATCH_ERR:
if(input_dev)
{
input_free_device(input_dev);
}
if(coding_data)
{
kfree(coding_data);
}
return ret;
}
static int coding_key_remove(struct platform_device *pdev)
{
struct coding_key *coding_data = platform_get_drvdata(pdev);
tasklet_disable(&codingkey_tasklet);
tasklet_kill(&codingkey_tasklet);
disable_irq(INT_GPIO_1);
disable_irq(INT_GPIO_2);
disable_irq(INT_GPIO_3);
disable_irq(INT_GPIO_4);
free_irq(INT_GPIO_1, coding_key_interrupt);
free_irq(INT_GPIO_2, coding_key_interrupt);
free_irq(INT_GPIO_3, coding_key_interrupt);
free_irq(INT_GPIO_4, coding_key_interrupt);
input_unregister_device(coding_data->input);
input_free_device(coding_data->input);
unregister_chrdev(coding_data->major,coding_data->name);
if(coding_data->class)
{
if(coding_data->dev)
device_destroy(coding_data->class,MKDEV(coding_data->major,0));
class_destroy(coding_data->class);
}
kfree(coding_data);
CodingKey = NULL ;
return 0;
}
#ifdef CONFIG_PM
static int coding_key_suspend(struct platform_device *dev, pm_message_t state)
{
return 0;
}
static int coding_key_resume(struct platform_device *dev)
{
return 0;
}
#else
#define key_input_suspend NULL
#define key_input_resume NULL
#endif
static struct platform_driver coding_key_driver = {
.probe = coding_key_probe,
.remove = coding_key_remove,
.suspend = coding_key_suspend,
.resume = coding_key_resume,
.driver = {
.name = "coding_key",
},
};
static int __devinit coding_key_init(void)
{
printk(KERN_INFO "coding Key input Driver init.\n");
return platform_driver_register(&coding_key_driver);
}
static void __exit coding_key_exit(void)
{
printk(KERN_INFO "codeing Key input Driver exit.\n");
platform_driver_unregister(&coding_key_driver);
}
module_init(coding_key_init);
module_exit(coding_key_exit);
MODULE_AUTHOR("azad Yu");
MODULE_DESCRIPTION("Key Input Driver");
MODULE_LICENSE("GPL");