1. 电阻屏原理
电阻屏X层上X-到X+和Y-到Y+的电阻是均匀分布的。
当计算触摸点时分为两步:
1、计算Y坐标,在Y+电极施加驱动电压V,Y-接地,芯片通过X+测量接触点的电压。
由于ITO层均匀导电,触点电压与V电压之比等于触点Y坐标与屏高度之比。
2、计算X坐标,在X+电极施加驱动电压V, X-电极接地,Y+做为引出端测量得到接触点的电压,由于ITO层均匀导电,触点电压与Vdrive电压之比等于触点X坐标与屏宽度之比。
测得的电压通常由ADC转化为数字信号,再进行简单处理就可以做为坐标判断触点的实际位置。
2. ADC
2.1 Device:
/* TSc controller */
static struct tsc_data am335x_touchscreen_data = {
.wires = 4,
.x_plate_resistance = 600,
.steps_to_configure = 5,
};
static struct adc_data am335x_adc_data = {
.adc_channels = 4,
};
static struct mfd_tscadc_board tscadc = {
.tsc_init = &am335x_touchscreen_data,
.adc_init = &am335x_adc_data,
};
创建了对应的Platform Device:mfd_tscadc_init() -》 am33xx_register_mfd_tscadc() -》 omap_device_build() -》 omap_device_build_ss() -》 omap_device_register()
2.2 Driver:
kernelarcharmplat-omapomap_device.c中定义了driver:
static struct platform_driver ti_tscadc_driver = {
.driver = {
.name = “ti_tscadc”,
.owner = THIS_MODULE,
},
.probe = ti_tscadc_probe,
.remove = __devexit_p(ti_tscadc_remove),
.suspend = tscadc_suspend,
.resume = tscadc_resume,
};
↓
static int __devinit ti_tscadc_probe(struct platform_device *pdev)
{
/* 解析出Touch Screen Controller的配置:
其中4路ADC用来做为电阻式触摸屏控制器
*/
/* TSC Cell */
if (pdata-》tsc_init) {
cell = &tscadc-》cells[children];
cell-》name = “tsc”;
cell-》platform_data = tscadc;
cell-》pdata_size = sizeof(*tscadc);
children++;
}
/* 解析出ADC的配置:
另外4路ADC用来做独立的ADC使用
*/
/* ADC Cell */
if (pdata-》adc_init) {
cell = &tscadc-》cells[children];
cell-》name = “tiadc”;
cell-》platform_data = tscadc;
cell-》pdata_size = sizeof(*tscadc);
children++;
}
/* 创建TSC和ADC对应的Platform Device */
err = mfd_add_devices(&pdev-》dev, pdev-》id, tscadc-》cells,
children, NULL, 0);
}
3. TouchSceen
触摸屏设备对应event1和touchscreen0:
root@am335x-evm:~# ls /dev/input/event1
/dev/input/event1
root@am335x-evm:~# ls -l /dev/input/touchscreen0
lrwxrwxrwx 1 root root 6 Jan 1 00:03 /dev/input/touchscreen0 -》 event1
/dev/input/event1读取出的数据是原始的ADC数据,它的最大值为2^12。需要经过tslib根据fb的分辨率转换以后,才能得到需要使用的X、Y轴的坐标值。
3.1 Device
在kernelarcharmplat-omapomap_device.c驱动的ti_tscadc_probe函数中创建了TSC的Platform Device。
3.2 Driver
drivers/input/touchscreen/ti_tsc.c:
static struct platform_driver ti_tsc_driver = {
.probe = tscadc_probe,
.remove = __devexit_p(tscadc_remove),
.driver = {
.name = “tsc”,
.owner = THIS_MODULE,
},
.suspend = tsc_suspend,
.resume = tsc_resume,
};
↓
初始化时注册input_device,对应/sys/class/input/input0/:
static int __devinit tscadc_probe(struct platform_device *pdev)
{
input_dev = input_allocate_device();
input_dev-》name = “ti-tsc”;
input_dev-》dev.parent = &pdev-》dev;
input_dev-》evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
input_dev-》keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
input_set_abs_params(input_dev, ABS_X, 0, MAX_12BIT, 0, 0);
input_set_abs_params(input_dev, ABS_Y, 0, MAX_12BIT, 0, 0);
input_set_abs_params(input_dev, ABS_PRESSURE, 0, MAX_12BIT, 0, 0);
/* register to the input system */
err = input_register_device(input_dev);
}
中断时上报input_event:
static irqreturn_t tscadc_interrupt(int irq, void *dev)
{
/*
* Sample found inconsistent by debouncing
* or pressure is beyond the maximum.
* Don‘t report it to user space.
*/
/* 上报电阻触摸屏的X、Y、Z值。
X、Y为坐标值,Z为压力值
*/
if (pen == 0) {
if ((diffx 《 15) && (diffy 《 15)
&& (z 《= MAX_12BIT)) {
input_report_abs(input_dev, ABS_X,
val_x);
input_report_abs(input_dev, ABS_Y,
val_y);
input_report_abs(input_dev, ABS_PRESSURE,
z);
input_report_key(input_dev, BTN_TOUCH,
1);
input_sync(input_dev);
}
}
status = tscadc_readl(ts_dev, TSCADC_REG_RAWIRQSTATUS);
if (status & TSCADC_IRQENB_PENUP) {
/* Pen up event */
fsm = tscadc_readl(ts_dev, TSCADC_REG_ADCFSM);
if (fsm == 0x10) {
pen = 1;
bckup_x = 0;
bckup_y = 0;
input_report_key(input_dev, BTN_TOUCH, 0);
input_report_abs(input_dev, ABS_PRESSURE, 0);
input_sync(input_dev);
} else {
pen = 0;
}
irqclr |= TSCADC_IRQENB_PENUP;
}
}
3.3 uDev
Udev就是在用户空间接收内核sysfs netlink热插拔消息的程序,而内核态调用用户空间程序的方式调用的是“/***in/hotplug”,后一种方式已经被淘汰。
用户空间对热插拔消息的处理有几类动作:
1、创建或者移除设备的设备节点;如果设备有devt属性,即“/sys/class/” 路径下包含“dev”文件属性的内核设备,发生增加或移除操作时,udev会帮其在用户空间“/dev”路径下增加或移除设备节点。2、根据规则文件,给设备改名、创建符号链接等。3、根据规则文件,调用外部程序。例如,调用modprobe插入驱动。 /etc/udev/rules.d/local.rules:
# Create a symlink to any touchscreen input deviceSUBSYSTEM, KERNEL, ATTRS{modalias}==“input:*-e0*,3,*a0,1
4. KeyBoard
键盘设备对应event0:
root@am335x-evm:~# ls /dev/input/event0
/dev/input/event0
4.1 Device
kernelarcharmmach-omap2board-am335xevm.c中定义了device:
/* Matrix GPIO Keypad Support for profile-0 only: TODO */
/* pinmux for keypad device */
static struct pinmux_config matrix_keypad_pin_mux[] = {
{”gpmc_a7.gpio1_23“, OMAP_MUX_MODE7 | AM33XX_PIN_INPUT}, //T15
{”gpmc_a10.gpio1_26“, OMAP_MUX_MODE7 | AM33XX_PIN_INPUT}, //T16
{”gpmc_a2.gpio1_18“, OMAP_MUX_MODE7 | AM33XX_PIN_INPUT}, //U14
{”gpmc_a8.gpio1_24“, OMAP_MUX_MODE7 | AM33XX_PIN_OUTPUT}, //V16
{”gpmc_a6.gpio1_22“, OMAP_MUX_MODE7 | AM33XX_PIN_OUTPUT}, //U15
{”gpmc_a5.gpio1_21“, OMAP_MUX_MODE7 | AM33XX_PIN_OUTPUT}, //V15
{”gpmc_a1.gpio1_17“, OMAP_MUX_MODE7 | AM33XX_PIN_OUTPUT}, //V14
{”gpmc_a4.gpio1_20“, OMAP_MUX_MODE7 | AM33XX_PIN_OUTPUT}, //R14
{”gpmc_a3.gpio1_19“, OMAP_MUX_MODE7 | AM33XX_PIN_OUTPUT}, //T14
{”mcasp0_axr0.gpio3_16“, OMAP_MUX_MODE7 | AM33XX_PIN_OUTPUT}, //D12
// {”ecap0_in_pwm0_out.gpio0_7“, OMAP_MUX_MODE7 | AM33XX_PIN_OUTPUT}, //C18. hx del 12.13
{”uart1_rxd.gpio0_14“, OMAP_MUX_MODE7 | AM33XX_PIN_OUTPUT},//D16
{NULL, 0},
};
/* Keys mapping */
static const uint32_t am335x_evm_matrix_keys[] = {
KEY(0, 0, KEY_F1), KEY(0, 1, KEY_F2), KEY(0, 2, KEY_F3), KEY(0, 3, KEY_F4), KEY(0, 4, KEY_1), KEY(0, 5, KEY_2), KEY(0, 6, KEY_3), KEY(0, 7, KEY_0),
KEY(1, 0, KEY_F5), KEY(1, 1, KEY_F6), KEY(1, 2, KEY_F7), KEY(1, 3, KEY_BACKSPACE), KEY(1, 4, KEY_4), KEY(1, 5, KEY_5), KEY(1, 6, KEY_6), KEY(1, 7, KEY_MINUS),
KEY(2, 0, KEY_F9), KEY(2, 1, KEY_ENTER), KEY(2, 2, KEY_F11), KEY(2, 3, KEY_F12), KEY(2, 4, KEY_7), KEY(2, 5, KEY_8), KEY(2, 6, KEY_9), KEY(2, 7, KEY_DOT),
};
const struct matrix_keymap_data am335x_evm_keymap_data = {
.keymap = am335x_evm_matrix_keys,
.keymap_size = ARRAY_SIZE(am335x_evm_matrix_keys),
};
static const unsigned int am335x_evm_keypad_row_gpios[] = {
GPIO_TO_PIN(1, 18), GPIO_TO_PIN(1, 26), GPIO_TO_PIN(1, 23)
};
static const unsigned int am335x_evm_keypad_col_gpios[] = {
GPIO_TO_PIN(1, 24), GPIO_TO_PIN(1, 22), GPIO_TO_PIN(1, 21), GPIO_TO_PIN(1, 17),
GPIO_TO_PIN(1, 20), GPIO_TO_PIN(1, 19), GPIO_TO_PIN(3, 16), GPIO_TO_PIN(0, 14)
};
static struct matrix_keypad_platform_data am335x_evm_keypad_platform_data = {
.keymap_data = &am335x_evm_keymap_data,
.row_gpios = am335x_evm_keypad_row_gpios,
.num_row_gpios = ARRAY_SIZE(am335x_evm_keypad_row_gpios),
.col_gpios = am335x_evm_keypad_col_gpios,
.num_col_gpios = ARRAY_SIZE(am335x_evm_keypad_col_gpios),
.active_low = false,
.debounce_ms = 5,
.col_scan_delay_us = 2,
};
static struct platform_device am335x_evm_keyboard = {
.name = ”matrix-keypad“,
.id = -1,
.dev = {
.platform_data = &am335x_evm_keypad_platform_data,
},
};
static void matrix_keypad_init(int evm_id, int profile)
{
int err;
setup_pin_mux(matrix_keypad_pin_mux);
err = platform_device_register(&am335x_evm_keyboard);
if (err) {
pr_err(”failed to register matrix keypad (2x3) devicen“);
}
}
4.2 Driver
kerneldriversinputkeyboardmatrix_keypad.c:
static struct platform_driver matrix_keypad_driver = {
.probe = matrix_keypad_probe,
.remove = __devexit_p(matrix_keypad_remove),
.driver = {
.name = ”matrix-keypad“,
.owner = THIS_MODULE,
#ifdef CONFIG_PM
.pm = &matrix_keypad_pm_ops,
#endif
},
};
↓
1. 电阻屏原理
电阻屏X层上X-到X+和Y-到Y+的电阻是均匀分布的。
当计算触摸点时分为两步:
1、计算Y坐标,在Y+电极施加驱动电压V,Y-接地,芯片通过X+测量接触点的电压。
由于ITO层均匀导电,触点电压与V电压之比等于触点Y坐标与屏高度之比。
2、计算X坐标,在X+电极施加驱动电压V, X-电极接地,Y+做为引出端测量得到接触点的电压,由于ITO层均匀导电,触点电压与Vdrive电压之比等于触点X坐标与屏宽度之比。
测得的电压通常由ADC转化为数字信号,再进行简单处理就可以做为坐标判断触点的实际位置。
2. ADC
2.1 Device:
/* TSc controller */
static struct tsc_data am335x_touchscreen_data = {
.wires = 4,
.x_plate_resistance = 600,
.steps_to_configure = 5,
};
static struct adc_data am335x_adc_data = {
.adc_channels = 4,
};
static struct mfd_tscadc_board tscadc = {
.tsc_init = &am335x_touchscreen_data,
.adc_init = &am335x_adc_data,
};
创建了对应的Platform Device:mfd_tscadc_init() -》 am33xx_register_mfd_tscadc() -》 omap_device_build() -》 omap_device_build_ss() -》 omap_device_register()
2.2 Driver:
kernelarcharmplat-omapomap_device.c中定义了driver:
static struct platform_driver ti_tscadc_driver = {
.driver = {
.name = “ti_tscadc”,
.owner = THIS_MODULE,
},
.probe = ti_tscadc_probe,
.remove = __devexit_p(ti_tscadc_remove),
.suspend = tscadc_suspend,
.resume = tscadc_resume,
};
↓
static int __devinit ti_tscadc_probe(struct platform_device *pdev)
{
/* 解析出Touch Screen Controller的配置:
其中4路ADC用来做为电阻式触摸屏控制器
*/
/* TSC Cell */
if (pdata-》tsc_init) {
cell = &tscadc-》cells[children];
cell-》name = “tsc”;
cell-》platform_data = tscadc;
cell-》pdata_size = sizeof(*tscadc);
children++;
}
/* 解析出ADC的配置:
另外4路ADC用来做独立的ADC使用
*/
/* ADC Cell */
if (pdata-》adc_init) {
cell = &tscadc-》cells[children];
cell-》name = “tiadc”;
cell-》platform_data = tscadc;
cell-》pdata_size = sizeof(*tscadc);
children++;
}
/* 创建TSC和ADC对应的Platform Device */
err = mfd_add_devices(&pdev-》dev, pdev-》id, tscadc-》cells,
children, NULL, 0);
}
3. TouchSceen
触摸屏设备对应event1和touchscreen0:
root@am335x-evm:~# ls /dev/input/event1
/dev/input/event1
root@am335x-evm:~# ls -l /dev/input/touchscreen0
lrwxrwxrwx 1 root root 6 Jan 1 00:03 /dev/input/touchscreen0 -》 event1
/dev/input/event1读取出的数据是原始的ADC数据,它的最大值为2^12。需要经过tslib根据fb的分辨率转换以后,才能得到需要使用的X、Y轴的坐标值。
3.1 Device
在kernelarcharmplat-omapomap_device.c驱动的ti_tscadc_probe函数中创建了TSC的Platform Device。
3.2 Driver
drivers/input/touchscreen/ti_tsc.c:
static struct platform_driver ti_tsc_driver = {
.probe = tscadc_probe,
.remove = __devexit_p(tscadc_remove),
.driver = {
.name = “tsc”,
.owner = THIS_MODULE,
},
.suspend = tsc_suspend,
.resume = tsc_resume,
};
↓
初始化时注册input_device,对应/sys/class/input/input0/:
static int __devinit tscadc_probe(struct platform_device *pdev)
{
input_dev = input_allocate_device();
input_dev-》name = “ti-tsc”;
input_dev-》dev.parent = &pdev-》dev;
input_dev-》evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
input_dev-》keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
input_set_abs_params(input_dev, ABS_X, 0, MAX_12BIT, 0, 0);
input_set_abs_params(input_dev, ABS_Y, 0, MAX_12BIT, 0, 0);
input_set_abs_params(input_dev, ABS_PRESSURE, 0, MAX_12BIT, 0, 0);
/* register to the input system */
err = input_register_device(input_dev);
}
中断时上报input_event:
static irqreturn_t tscadc_interrupt(int irq, void *dev)
{
/*
* Sample found inconsistent by debouncing
* or pressure is beyond the maximum.
* Don‘t report it to user space.
*/
/* 上报电阻触摸屏的X、Y、Z值。
X、Y为坐标值,Z为压力值
*/
if (pen == 0) {
if ((diffx 《 15) && (diffy 《 15)
&& (z 《= MAX_12BIT)) {
input_report_abs(input_dev, ABS_X,
val_x);
input_report_abs(input_dev, ABS_Y,
val_y);
input_report_abs(input_dev, ABS_PRESSURE,
z);
input_report_key(input_dev, BTN_TOUCH,
1);
input_sync(input_dev);
}
}
status = tscadc_readl(ts_dev, TSCADC_REG_RAWIRQSTATUS);
if (status & TSCADC_IRQENB_PENUP) {
/* Pen up event */
fsm = tscadc_readl(ts_dev, TSCADC_REG_ADCFSM);
if (fsm == 0x10) {
pen = 1;
bckup_x = 0;
bckup_y = 0;
input_report_key(input_dev, BTN_TOUCH, 0);
input_report_abs(input_dev, ABS_PRESSURE, 0);
input_sync(input_dev);
} else {
pen = 0;
}
irqclr |= TSCADC_IRQENB_PENUP;
}
}
3.3 uDev
Udev就是在用户空间接收内核sysfs netlink热插拔消息的程序,而内核态调用用户空间程序的方式调用的是“/***in/hotplug”,后一种方式已经被淘汰。
用户空间对热插拔消息的处理有几类动作:
1、创建或者移除设备的设备节点;如果设备有devt属性,即“/sys/class/” 路径下包含“dev”文件属性的内核设备,发生增加或移除操作时,udev会帮其在用户空间“/dev”路径下增加或移除设备节点。2、根据规则文件,给设备改名、创建符号链接等。3、根据规则文件,调用外部程序。例如,调用modprobe插入驱动。 /etc/udev/rules.d/local.rules:
# Create a symlink to any touchscreen input deviceSUBSYSTEM, KERNEL, ATTRS{modalias}==“input:*-e0*,3,*a0,1
4. KeyBoard
键盘设备对应event0:
root@am335x-evm:~# ls /dev/input/event0
/dev/input/event0
4.1 Device
kernelarcharmmach-omap2board-am335xevm.c中定义了device:
/* Matrix GPIO Keypad Support for profile-0 only: TODO */
/* pinmux for keypad device */
static struct pinmux_config matrix_keypad_pin_mux[] = {
{”gpmc_a7.gpio1_23“, OMAP_MUX_MODE7 | AM33XX_PIN_INPUT}, //T15
{”gpmc_a10.gpio1_26“, OMAP_MUX_MODE7 | AM33XX_PIN_INPUT}, //T16
{”gpmc_a2.gpio1_18“, OMAP_MUX_MODE7 | AM33XX_PIN_INPUT}, //U14
{”gpmc_a8.gpio1_24“, OMAP_MUX_MODE7 | AM33XX_PIN_OUTPUT}, //V16
{”gpmc_a6.gpio1_22“, OMAP_MUX_MODE7 | AM33XX_PIN_OUTPUT}, //U15
{”gpmc_a5.gpio1_21“, OMAP_MUX_MODE7 | AM33XX_PIN_OUTPUT}, //V15
{”gpmc_a1.gpio1_17“, OMAP_MUX_MODE7 | AM33XX_PIN_OUTPUT}, //V14
{”gpmc_a4.gpio1_20“, OMAP_MUX_MODE7 | AM33XX_PIN_OUTPUT}, //R14
{”gpmc_a3.gpio1_19“, OMAP_MUX_MODE7 | AM33XX_PIN_OUTPUT}, //T14
{”mcasp0_axr0.gpio3_16“, OMAP_MUX_MODE7 | AM33XX_PIN_OUTPUT}, //D12
// {”ecap0_in_pwm0_out.gpio0_7“, OMAP_MUX_MODE7 | AM33XX_PIN_OUTPUT}, //C18. hx del 12.13
{”uart1_rxd.gpio0_14“, OMAP_MUX_MODE7 | AM33XX_PIN_OUTPUT},//D16
{NULL, 0},
};
/* Keys mapping */
static const uint32_t am335x_evm_matrix_keys[] = {
KEY(0, 0, KEY_F1), KEY(0, 1, KEY_F2), KEY(0, 2, KEY_F3), KEY(0, 3, KEY_F4), KEY(0, 4, KEY_1), KEY(0, 5, KEY_2), KEY(0, 6, KEY_3), KEY(0, 7, KEY_0),
KEY(1, 0, KEY_F5), KEY(1, 1, KEY_F6), KEY(1, 2, KEY_F7), KEY(1, 3, KEY_BACKSPACE), KEY(1, 4, KEY_4), KEY(1, 5, KEY_5), KEY(1, 6, KEY_6), KEY(1, 7, KEY_MINUS),
KEY(2, 0, KEY_F9), KEY(2, 1, KEY_ENTER), KEY(2, 2, KEY_F11), KEY(2, 3, KEY_F12), KEY(2, 4, KEY_7), KEY(2, 5, KEY_8), KEY(2, 6, KEY_9), KEY(2, 7, KEY_DOT),
};
const struct matrix_keymap_data am335x_evm_keymap_data = {
.keymap = am335x_evm_matrix_keys,
.keymap_size = ARRAY_SIZE(am335x_evm_matrix_keys),
};
static const unsigned int am335x_evm_keypad_row_gpios[] = {
GPIO_TO_PIN(1, 18), GPIO_TO_PIN(1, 26), GPIO_TO_PIN(1, 23)
};
static const unsigned int am335x_evm_keypad_col_gpios[] = {
GPIO_TO_PIN(1, 24), GPIO_TO_PIN(1, 22), GPIO_TO_PIN(1, 21), GPIO_TO_PIN(1, 17),
GPIO_TO_PIN(1, 20), GPIO_TO_PIN(1, 19), GPIO_TO_PIN(3, 16), GPIO_TO_PIN(0, 14)
};
static struct matrix_keypad_platform_data am335x_evm_keypad_platform_data = {
.keymap_data = &am335x_evm_keymap_data,
.row_gpios = am335x_evm_keypad_row_gpios,
.num_row_gpios = ARRAY_SIZE(am335x_evm_keypad_row_gpios),
.col_gpios = am335x_evm_keypad_col_gpios,
.num_col_gpios = ARRAY_SIZE(am335x_evm_keypad_col_gpios),
.active_low = false,
.debounce_ms = 5,
.col_scan_delay_us = 2,
};
static struct platform_device am335x_evm_keyboard = {
.name = ”matrix-keypad“,
.id = -1,
.dev = {
.platform_data = &am335x_evm_keypad_platform_data,
},
};
static void matrix_keypad_init(int evm_id, int profile)
{
int err;
setup_pin_mux(matrix_keypad_pin_mux);
err = platform_device_register(&am335x_evm_keyboard);
if (err) {
pr_err(”failed to register matrix keypad (2x3) devicen“);
}
}
4.2 Driver
kerneldriversinputkeyboardmatrix_keypad.c:
static struct platform_driver matrix_keypad_driver = {
.probe = matrix_keypad_probe,
.remove = __devexit_p(matrix_keypad_remove),
.driver = {
.name = ”matrix-keypad“,
.owner = THIS_MODULE,
#ifdef CONFIG_PM
.pm = &matrix_keypad_pm_ops,
#endif
},
};
↓
举报