编码开关驱动

曾经做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");




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值