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) <
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) <
相关文章推荐
- Linux内核---30.触摸屏驱动分析
- linux下使用tar命令
- Linux内核---29.yaffs2的ECC
- Linux内核---28.yaffs2的垃圾回收机制
- Linux内核---27.yaffs2的文件操作
- Linux内核---26.yaffs2的tnode分配与释放
- Linux内核---25.yaffs2位图
- linux awk命令详解
- Linux内核---24.yaffs2中chunk的分配与释放
- Linux内核---23.yaffs2文件系统(未完成)
- Linux内核---22.mkyaffs2image
- Linux内核---21.Linux下的dnw
- Linux内核---20.vfat文件系统分析
- Linux内核---19.S3C6410制作SD卡上的Linux文件系统
- linux sed命令详解
- Ubuntu 修复Grub引导双系统
- Ubuntu Kylin 16.04 下wps文字/wps表格/wps演示不能输入中文的解决办法
- linux ip
- linux下查看当前用户的 三个命令
- linux中sort命令