📄 omap-tsc2101-ts.c
字号:
/* * linux/sound/oss/omap-audio.c * * Touch Screen driver for the OMAP processors * * Copyright (C) 2004 Texas Instruments, Inc. * * * This package is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. * History: * * 2004-10-28 Srinath - Ported to 2420 * * 2004-11-16 Srianth - Changed from polling mode to interrupt mode on 1710 and 1610 * * 2004-11-23 Srinath - Added support for Power Management *//************************************************************************** * INCLUDES * **********************************************************************/#include <linux/errno.h>#include <linux/kernel.h>#include <linux/module.h>#include <linux/slab.h>#include <linux/input.h>#include <linux/init.h>#include <linux/wait.h>#include <linux/interrupt.h>#include <linux/suspend.h>#include <linux/device.h>#include <asm/mach-types.h>#include <asm/arch/gpio.h>#include <asm/arch/mux.h>#include <asm/arch/hardware.h>#include <asm/hardware/tsc2101.h>#include <../drivers/ssi/omap-tsc2101.h>/******************************************************************************* * MACROS *****************************************************************************/#define OMAP_TSC2101_NAME "omap_tsc2101_ts"#define OMAP_TSC2101_XRES 500#define TOUCHSCREEN_DATA_REGISTERS_PAGE 0x0#define TOUCHSCREEN_CONTROL_REGISTERS_PAGE 0x1#define OMAP_TSC2101_READ_MAX 0x4#define TSC2101_GETSTATUS(ret) (((ret) >> 11) & 0x1)#define TSC2101_MASKVAL 0xFFF#define TSC2101_PRESSUREVAL(x) ((x) << 12)#if CONFIG_ARCH_OMAP16XX#define OMAP_1710_GPIO_NUM 48#define OMAP_1610_GPIO_NUM 4#elif CONFIG_ARCH_OMAP24XX#define OMAP_24XX_GPIO_NUM 93#endif/*************************************************************************** * FUNCTION PROTOTYPES **************************************************************************/static void omap_tsc2101_ts_tasklet(unsigned long);static int omap_tsc2101_ts_read_buf(void);static int omap_tsc2101_ts_buf_empty(void);static irqreturn_t omap_tsc2101_ts_handler(int irq, void *dev_id, struct pt_regs *regs);static int omap_tsc2101_ts_probe(struct device *dev);static int omap_tsc2101_ts_remove(struct device *dev);static int omap_tsc2101_ts_suspend(struct device *dev, u32 state, u32 level);static int omap_tsc2101_ts_resume(struct device *dev, u32 level);static void omap_tsc2101_ts_disable(void);static void omap_tsc2101_ts_enable(void);/**************************************************************************** * DATA STRUCTURES ***************************************************************************//* Tasklet Declaration */DECLARE_TASKLET(omap_tsc2101_ts, omap_tsc2101_ts_tasklet, 0);static struct { struct input_dev inputdevice; int touched; int irq; int xres;} tsc2101_ts;/* Device Information */static struct platform_device omap_tsc2101_ts_device = { .name = OMAP_TSC2101_NAME, .id = 0,};/* Driver Information */static struct device_driver omap_tsc2101_ts_driver = { .name = OMAP_TSC2101_NAME, .bus = &platform_bus_type, .probe = omap_tsc2101_ts_probe, .remove = omap_tsc2101_ts_remove, .suspend = omap_tsc2101_ts_suspend, .resume = omap_tsc2101_ts_resume,};/*********************************************************************************** omap_tsc2101_ts_buf_empty(void) : Function to read the TSC status register * **********************************************************************************/static int omap_tsc2101_ts_buf_empty(void){ int ret = 0; /* Read the status register */ ret = omap_tsc2101_read(TOUCHSCREEN_CONTROL_REGISTERS_PAGE, TSC2101_TS_STATUS); /* Check for avialbality of data in status register */ ret = TSC2101_GETSTATUS(ret); return !ret;}/********************************************************************************** * omap_tsc2101_ts_read_buf(void) : Function to read the TSC data registers* *********************************************************************************/static int omap_tsc2101_ts_read_buf(void){ u16 values[OMAP_TSC2101_READ_MAX] = { 0, 0, 0, 0 }; s32 t, p = 0; int i; /* Read X, Y, Z1 and Z2 */ omap_tsc2101_reads(TOUCHSCREEN_DATA_REGISTERS_PAGE, TSC2101_TS_X, values, OMAP_TSC2101_READ_MAX); for (i = 0; i < OMAP_TSC2101_READ_MAX; i++) values[i] &= TSC2101_MASKVAL; input_report_abs(&(tsc2101_ts.inputdevice), ABS_X, values[TSC2101_TS_X]); input_report_abs(&(tsc2101_ts.inputdevice), ABS_Y, values[TSC2101_TS_Y]); /* Calculate Pressure */ if (values[TSC2101_TS_Z1] != 0) { t = ((tsc2101_ts.xres * values[TSC2101_TS_X]) * (values[TSC2101_TS_Z2] - values[TSC2101_TS_Z1])); p = t / (u32) (TSC2101_PRESSUREVAL(values[TSC2101_TS_Z1])); if (p < 0) p = 0; } input_report_abs(&(tsc2101_ts.inputdevice), ABS_PRESSURE, p); input_sync(&(tsc2101_ts.inputdevice)); return 0;}/*********************************************************************************** omap_tsc2101_ts_tasklet(unsigned long nothing) : Tasklet Function ***********************************************************************************/static void omap_tsc2101_ts_tasklet(unsigned long nothing){ if (!omap_tsc2101_ts_buf_empty()) { /* Pen down */ if (!tsc2101_ts.touched) { input_report_key(&(tsc2101_ts.inputdevice), BTN_TOUCH, 1); } tsc2101_ts.touched = 1; omap_tsc2101_ts_read_buf(); } else { /* Pen up */ if (tsc2101_ts.touched) { tsc2101_ts.touched = 0; input_report_key(&(tsc2101_ts.inputdevice), BTN_TOUCH, 0); } } return;}/*********************************************************************************** omap_tsc2101_ts_handler(int irq, void *dev_id,* struct pt_regs *regs) : Interrupt Handler************************************************************************************/static irqreturn_t omap_tsc2101_ts_handler(int irq, void *dev_id, struct pt_regs *regs){ /* Schedule Takslet */ tasklet_schedule(&omap_tsc2101_ts); return IRQ_HANDLED;}/*********************************************************************************** omap_tsc2101_ts_enable(void) : Function to configure the TSC Codec*********************************************************************************/static void omap_tsc2101_ts_enable(void){ int ret = omap_tsc2101_enable(); if (ret) { printk(KERN_ERR "FAILED TO INITIALIZE TSC CODEC\n"); return; } /* PINTDAV is data available only */ omap_tsc2101_write(TOUCHSCREEN_CONTROL_REGISTERS_PAGE, TSC2101_TS_STATUS, TSC2101_DATA_AVAILABLE); /* disable buffer mode */ omap_tsc2101_write(TOUCHSCREEN_CONTROL_REGISTERS_PAGE, TSC2101_TS_BUFFER_CTRL, TSC2101_BUFFERMODE_DISABLE); /* use internal reference, 100 usec power-up delay, * power down between conversions, 1.25V internal reference */ omap_tsc2101_write(TOUCHSCREEN_CONTROL_REGISTERS_PAGE, TSC2101_TS_REF_CTRL, TSC2101_REF_POWERUP); /* enable touch detection, 84usec precharge time, 32 usec sense time */ omap_tsc2101_write(TOUCHSCREEN_CONTROL_REGISTERS_PAGE, TSC2101_TS_CONFIG_CTRL, TSC2101_ENABLE_TOUCHDETECT); /* 1 msec conversion delays and MCLK selected */ omap_tsc2101_write(TOUCHSCREEN_CONTROL_REGISTERS_PAGE, TSC2101_TS_PROG_DELAY, TSC2101_PRG_DELAY); /* * TSC2101-controlled conversions * 12-bit samples * continuous X,Y,Z1,Z2 scan mode * average (mean) 4 samples per coordinate * 1 MHz internal conversion clock * 500 usec panel voltage stabilization delay * */ omap_tsc2101_write(TOUCHSCREEN_CONTROL_REGISTERS_PAGE, TSC2101_TS_ADC_CTRL, TSC2101_ADC_CONTROL); return;}/*********************************************************************************** omap_tsc2101_ts_disable(void) : Function to shutdown TSC Codec*********************************************************************************/static void omap_tsc2101_ts_disable(void){ tasklet_kill(&omap_tsc2101_ts); /* stop conversions and power down */ omap_tsc2101_write(TOUCHSCREEN_CONTROL_REGISTERS_PAGE, TSC2101_TS_ADC_CTRL, TSC2101_ADC_POWERDOWN); omap_tsc2101_disable(); return;}/*********************************************************************************** omap_tsc2101_ts_probe(): The TSC driver probe function***********************************************************************************/static int omap_tsc2101_ts_probe(struct device *dev){ memset(&tsc2101_ts, 0, sizeof(tsc2101_ts)); tsc2101_ts.xres = OMAP_TSC2101_XRES;#ifdef CONFIG_ARCH_OMAP16XX if (machine_is_omap_h3()) { tsc2101_ts.irq = OMAP_GPIO_IRQ(OMAP_1710_GPIO_NUM); /* Configure GPIO for Pen IRQ */ omap_cfg_reg(W19_1610_GPIO48); if (omap_request_gpio(OMAP_1710_GPIO_NUM) != 0) { printk(KERN_ERR "omap_tsc2101_ts.c: Could not reserve GPIO!\n"); return -EINVAL; }; omap_set_gpio_direction(OMAP_1710_GPIO_NUM, 1); omap_set_gpio_edge_ctrl(OMAP_1710_GPIO_NUM, OMAP_GPIO_FALLING_EDGE); } else if (machine_is_omap_h2()) { tsc2101_ts.irq = OMAP_GPIO_IRQ(OMAP_1610_GPIO_NUM); /* Configure GPIO for Pen IRQ */ omap_cfg_reg(P20_1610_GPIO4); if (omap_request_gpio(OMAP_1610_GPIO_NUM) != 0) { printk(KERN_ERR "omap_tsc2101_ts.c: Could not reserve GPIO!\n"); return -EINVAL; }; omap_set_gpio_direction(OMAP_1610_GPIO_NUM, 1); omap_set_gpio_edge_ctrl(OMAP_1610_GPIO_NUM, OMAP_GPIO_FALLING_EDGE); } else { printk(KERN_ERR "omap_tsc2101_ts.c: Unsupported platform!\n"); return -EINVAL; }#endif#ifdef CONFIG_ARCH_OMAP24XX tsc2101_ts.irq = OMAP_GPIO_IRQ_NO(OMAP_24XX_GPIO_NUM); omap2_cfg_reg(P20_2420_TSC_IRQ); if (omap_request_gpio(OMAP_24XX_GPIO_NUM) != 0) { printk(KERN_ERR "omap_tsc2101_ts.c: Could not reserve GPIO!\n"); return -EINVAL; }; omap_set_gpio_direction(OMAP_24XX_GPIO_NUM, OMAP2420_DIR_INPUT); omap_set_gpio_edge_ctrl(OMAP_24XX_GPIO_NUM, OMAP_GPIO_FALLING_EDGE);#endif /* Request irq */ if (request_irq(tsc2101_ts.irq, omap_tsc2101_ts_handler, SA_INTERRUPT | SA_SAMPLE_RANDOM, "omap_tsc2101_ts", &tsc2101_ts)) { printk(KERN_ERR "omap_tsc2101_ts.c: Could not allocate pen IRQ!\n"); tsc2101_ts.irq = -1; } init_input_dev(&(tsc2101_ts.inputdevice)); tsc2101_ts.inputdevice.name = OMAP_TSC2101_NAME; tsc2101_ts.inputdevice.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); tsc2101_ts.inputdevice.keybit[LONG(BTN_TOUCH)] |= BIT(BTN_TOUCH); tsc2101_ts.inputdevice.absbit[0] = BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE); input_register_device(&(tsc2101_ts.inputdevice)); /* Enable the TSC */ omap_tsc2101_ts_enable(); return 0;}/*********************************************************************************** omap_tsc2101_ts_remove(): Function to handle removal operations***********************************************************************************/static int omap_tsc2101_ts_remove(struct device *dev){ omap_tsc2101_ts_disable(); input_unregister_device(&tsc2101_ts.inputdevice);#ifdef CONFIG_ARCH_16XX free_irq(tsc2101_ts.irq, &tsc2101_ts); if (machine_is_omap_h2()) omap_free_gpio(OMAP_1610_GPIO_NUM); else if (machine_is_omap_h3()) omap_free_gpio(OMAP_1710_GPIO_NUM); else { printk(KERN_ERR "omap_tsc2101_ts.c: Unsupported platform!\n"); return -EINVAL; }#endif#ifdef CONFIG_ARCH_OMAP24XX omap_free_gpio(OMAP_24XX_GPIO_NUM);#endif return 0;}/*********************************************************************************** omap_tsc2101_ts_suspend(): Function to handle suspend operations**********************************************************************************/static int omap_tsc2101_ts_suspend(struct device *dev, u32 state, u32 level){ if (level != 3) { return 0; } omap_tsc2101_ts_disable(); return 0;}/*********************************************************************************** omap_tsc2101_ts_resume : Function to handle resume operations**********************************************************************************/static int omap_tsc2101_ts_resume(struct device *dev, u32 level){ if (level != 0) { return 0; } omap_tsc2101_ts_enable(); return 0;}/*********************************************************************************** omap_tsc2101_ts_init(): TSC driver init function**********************************************************************************/static int __init omap_tsc2101_ts_init(void){ int ret; ret = platform_device_register(&omap_tsc2101_ts_device); if (ret != 0) return -ENODEV; ret = driver_register(&omap_tsc2101_ts_driver); if (ret == 0) return 0; platform_device_unregister(&omap_tsc2101_ts_device); return -ENODEV;}/*********************************************************************************** omap_tsc2101_ts_exitt(): TSC driver exit function**********************************************************************************/static void __exit omap_tsc2101_ts_exit(void){ driver_unregister(&omap_tsc2101_ts_driver); platform_device_unregister(&omap_tsc2101_ts_device);}module_init(omap_tsc2101_ts_init);module_exit(omap_tsc2101_ts_exit);MODULE_AUTHOR("Texas Instruments");MODULE_DESCRIPTION("Touch screen Driver for OMAP processors");MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -