您的位置:首页 > 运维架构 > Linux

Linux内核---31.按键驱动分析(未完成)

2016-07-04 19:29 423 查看
一. device的注册
1.0 按键设备的注册

按键设备的定义在arch/arm/mach-s3c64xx中

/* gpio buttons */

static struct gpio_keys_button gpio_buttons[] = {

    {

        .gpio        = S3C64XX_GPN(0),

        //.code        = 25,

        .code        = KEY_UP,

        .desc        = \"BUTTON1\",

        .active_low    = 1,

        .wakeup        = 0,

    },

    {

        .gpio        = S3C64XX_GPN(1),

        //.code        = 42,

        .code        = KEY_DOWN,

        .desc        = \"BUTTON2\",

        .active_low    = 1,

        .wakeup        = 0,

    },

    {

        .gpio        = S3C64XX_GPN(2),

        //.code        = 50,

        .code        = KEY_LEFT,

        .desc        = \"BUTTON3\",

        .active_low    = 1,

        .wakeup        = 0,

    },

    {

        .gpio        = S3C64XX_GPN(3),

        //.code        = 10,

        .code        = KEY_RIGHT,

        .desc        = \"BUTTON4\",

        .active_low    = 1,

        .wakeup        = 0,

    },

    {

        .gpio        = S3C64XX_GPN(4),

        //.code        = 24,

        .code        = KEY_ENTER,

        .desc        = \"BUTTON5\",

        .active_low    = 1,

        .wakeup        = 0,

    },

    {

        .gpio        = S3C64XX_GPN(5),

        //.code        = 38,

        .code        = KEY_ESC,

        .desc        = \"BUTTON6\",

        .active_low    = 1,

        .wakeup        = 0,

    }

};

static struct gpio_keys_platform_data gpio_button_data = {

    .buttons    = gpio_buttons,

    .nbuttons    = ARRAY_SIZE(gpio_buttons),

};

static struct platform_device gpio_button_device = {

    .name        = \"gpio-keys\",

    .id        = -1,

    .num_resources    = 0,

    .dev        = {

        .platform_data    = &gpio_button_data,

    }

};

static struct platform_device *smdk6410_devices[] __initdata = {

    &gpio_button_device,        //把key_button添加到总的设备列表中

}

//在arch/arm/mach-s3c64xx/mach-smdk6410.c中

static void __init smdk6410_machine_init(void)

{

    //在driver/base/platform.c中一起注册

    platform_add_devices(smdk6410_devices, ARRAY_SIZE(smdk6410_devices));

}

二. device_driver

 Device Drivers  --->

          Input device support  --->

               [*]   Keyboards  --->

                    <*>   GPIO Buttons 

                    <*>   Samsung keypad support
2.0 两个宏

#define WAIT4INT(x)              //只是针对于S3C_ADCTSC寄存器

        (((x)<<8) |              //<bit8> 0->down
1->up
interrupt signal

        S3C_ADCTSC_YM_SEN |      //<bit7> 1 = Switch
enable (YM = VSSA_ADC)

        S3C_ADCTSC_YP_SEN |      //<bit6> 1 = Switch
disable (YP=AIN5, Hi-z) 

        //XM_SEN                //<bit5> 0 = Switch
disable (XM = AIN6, Hi-z)

        S3C_ADCTSC_XP_SEN |      //<bit4> 1 = Switch
disable (XP=AIN7, Hi-z)

        //PULL_UP               //<bit3> 0 = XP
Pull-up Enable.

        //AUTO_PST              //<bit2> 0 = Normal
ADC conversion.         

        S3C_ADCTSC_XY_PST(3))    //<bit1-0> 3: Waiting for Interrupt
Mode 

#define AUTOPST     

    (S3C_ADCTSC_YM_SEN |        //1 = Switch
enable (YM = VSSA_ADC)

    S3C_ADCTSC_YP_SEN |         //1 = Switch
disable (YP=AIN5, Hi-z) 

    S3C_ADCTSC_XP_SEN |         //1 = Switch
disable (XP=AIN7, Hi-z) 

    S3C_ADCTSC_AUTO_PST |       //1 = Auto
Sequential measurement of X-position, Y-position

    S3C_ADCTSC_XY_PST(0))      
//0 = No operation mode

WAIT4INT(x) :

            当x=0时,设为等侍down中断

             当x=1时,设为等侍up中断
2.1 初始化
ok6410的touchscreen在内核源码的位置:driver/input/touchscreen/s3c-ts.c
device 与 device_driver按名字s3c-ts匹配之后,就进入s3c_ts_probe函数

static struct platform_driver s3c_ts_driver = {

    .probe = s3c_ts_probe,

    .remove = s3c_ts_remove,

    .suspend = s3c_ts_suspend,

    .resume = s3c_ts_resume,

    .driver        = {

        .owner    = THIS_MODULE,

        .name    = "s3c-ts",

    },

};

static int __init s3c_ts_init(void)

{

    return platform_driver_register(&s3c_ts_driver);

}

static void __exit s3c_ts_exit(void)

{

    platform_driver_unregister(&s3c_ts_driver);

}

module_init(s3c_ts_init);

module_exit(s3c_ts_exit);

2.2 probe函数

static int __init s3c_ts_probe(struct platform_device *pdev)

{

    struct resource *res;

    struct device *dev;

    struct input_dev *input_dev;

    struct s3c_ts_mach_info * s3c_ts_cfg;

    int ret, size;

    dev = &pdev->dev;

    res = platform_get_resource(pdev, IORESOURCE_MEM, 0);                //获取ts寄存器地址

    size = (res->end - res->start) + 1;

    ts_mem = request_mem_region(res->start, size, pdev->name);           //申请I/O内存

    ts_base = ioremap(res->start, size);   
                             //request_mem_region申请的内存在使用前要调用ioremap

    ts_clock = clk_get(&pdev->dev, "adc");   
                           //获取clock    

    clk_enable(ts_clock);                                                //在初始化时disable了ts_clock,这个地方要enable

    

                                                                //下面这几行是要把ts的配置信息写到寄存器中去

    s3c_ts_cfg = s3c_ts_get_platdata(&pdev->dev);                        //获取ts的配置信息,

                                                                         //ts的私有信息:在arch/arm/mach-s3c64xx/mach-smdk6410.c中

    //enable prescaler && 设置prescaler_value=s3c_ts_cfg->presc

    writel(S3C_ADCCON_PRSCEN | S3C_ADCCON_PRSCVL(s3c_ts_cfg->presc&0xff), ts_base+S3C_ADCCON);

   

   //s3c_ts_cfg->delay=0x10000 --> External
input clock 

    writel(s3c_ts_cfg->delay & 0xffff, ts_base+S3C_ADCDLY);

    

    //A/D converter resolution selection--> 12-bit
A/D conversion

    writel(readl(ts_base+S3C_ADCCON)|S3C_ADCCON_RESSEL_12BIT, ts_base+S3C_ADCCON);

    //设为等侍down中断模式

    writel(WAIT4INT(0), ts_base+S3C_ADCTSC);

    ts = kzalloc(sizeof(struct s3c_ts_info), GFP_KERNEL);           //下面这几行是要初始化s3c_ts_info结构体

    input_dev = input_allocate_device();

   

    ts->dev = input_dev;

    ts->dev->evbit[0] = ts->dev->evbit[0] = BIT_MASK(EV_SYN) | BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);

    ts->dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);

    if (s3c_ts_cfg->resol_bit==12) {

        input_set_abs_params(ts->dev, ABS_X, 0, 0xFFF, 0, 0);                //设置x轴的最大最小值

        input_set_abs_params(ts->dev, ABS_Y, 0, 0xFFF, 0, 0);                //设置y轴的最大最小值

    } 

    input_set_abs_params(ts->dev, ABS_PRESSURE, 0, 1, 0, 0);                 //设置Press状态的最大最小值(按下或空闲)   

    sprintf(ts->phys, "input(ts)");

    ts->dev->name = s3c_ts_name;

    ts->dev->phys = ts->phys;

    ts->dev->id.bustype = BUS_RS232;

    ts->dev->id.vendor = 0xDEAD;

    ts->dev->id.product = 0xBEEF;

    ts->dev->id.version = S3C_TSVERSION;

    ts->shift = s3c_ts_cfg->oversampling_shift;

    ts->resol_bit = s3c_ts_cfg->resol_bit;

    ts->s3c_adc_con = s3c_ts_cfg->s3c_adc_con;

    /* For IRQ_PENDUP */

    ts_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);                //获取中断号

    //申请中断,RANDOM表示设备可以看作随机的发生源

    ret = request_irq(ts_irq->start, stylus_updown, IRQF_SAMPLE_RANDOM, "s3c_updown", ts); //申请中断

   

    /* For IRQ_ADC */

    ts_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 1);  
            //获取中断号

    ret = request_irq(ts_irq->start, stylus_action, IRQF_SAMPLE_RANDOM | IRQF_SHARED, "s3c_action", ts); //申请共享中断

    

    /* All went ok, so register to the
input system */

    ret = input_register_device(ts->dev);                                    //把这个input_dev添加到input系统中

}

ts底板图:



ts连到核心板图:



TSXP --> AIN7

TSYP --> AIN5

2.3 IRQ_PENDN

static irqreturn_t stylus_updown(int irqno, void *param)

{

    unsigned long data0;

    unsigned long data1;

    if (!ADC_locked4TS())                              //进入中断函数,如果没有加锁,则加上锁

        if (s3c_ts_adc_lock(LOCK_TS))                  //如果加锁失败,则直接返回       

            return IRQ_HANDLED;        

    data0 = readl(ts_base+S3C_ADCDAT0);

    data1 = readl(ts_base+S3C_ADCDAT1);

    touch_timer_fire(0);

    if(ts->s3c_adc_con==ADC_TYPE_2) {

         //ADCCLRINTPNDNUP: INT_PNDNUP
interrupt clear

        __raw_writel(0x0, ts_base+S3C_ADCCLRWK);    

        //ADCCLRINT: Clear
ADC Interrupt

        __raw_writel(0x0, ts_base+S3C_ADCCLRINT);   

    }

    return IRQ_HANDLED;

}

2.3.1 fire

static void touch_timer_fire(unsigned long data)

{

    unsigned long data0;

    unsigned long data1;

    int pendown;

    if (!ADC_locked4TS())                       //如果当前状态是free,说明加锁失败,直接返回

        return;

    

    //这儿的数据读取,是为了判断是down还是up状态

    data0 = readl(ts_base+S3C_ADCDAT0);         //读

    data1 = readl(ts_base+S3C_ADCDAT1);         //读   

    //data0的bit15: 0->按下状态; 1->松开状态

    //如果data0与data1都不为松开状态,就是按下状态

    pendown = (!(data0 & S3C_ADCDAT0_UPDOWN)) && (!(data1 & S3C_ADCDAT1_UPDOWN));

    if (pendown) <

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: