#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/serio.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/arch/regs-gpio.h>
struct s3c_adc_regs {
unsigned long adccon;
unsigned long adctsc;
unsigned long adcdly;
unsigned long adcdat0;
unsigned long adcdat1;
};
static struct input_dev *s3c_ts_dev;
static struct s3c_adc_regs *s3c_adc_regs;
static struct timer_list s3c_ts_timer;
//等待触摸笔的按下
static void enter_wait_pen_down(void)
{
s3c_adc_regs->adctsc = (1<<7) | (1<<6) | (0<<5) | (1 << 4) | (0 << 3) | (3<<0);
}
static void enter_wait_pen_up(void)
{
s3c_adc_regs->adctsc = (1<<8) | (1<<7) | (1<<6) | (0<<5) | (1 << 4) | (0 << 3) | (3<<0);
}
//测量xy的值
static void enter_measure_xy_mode(void)
{
s3c_adc_regs->adctsc = (1<<7) | (1<<6) | (1<<4) | (1<<3) | (1<<2);
}
static void start_adc(void)
{
s3c_adc_regs->adccon |= (1<<0);
}
//时间函数,时间到的时间,自动启动xy的转换,开始adc
static void s3c_ts_timer_function(unsigned long h)
{
enter_measure_xy_mode();
start_adc();
}
static irqreturn_t pen_down_up_isr(int irq, void *devid)
{
static int cnt = 0;
if (s3c_adc_regs->adcdat0 & (1<<15))
{
//printk("pen_down_up_isr up: %d\n", ++cnt);
/* 进入"等待中断模式": 等待按下 */
enter_wait_pen_down();
/*上报事件 ,完成一次上报事件*/
input_event(s3c_ts_dev, EV_ABS, ABS_PRESSURE, 0);
input_event(s3c_ts_dev, EV_KEY, BTN_TOUCH, 0);
input_sync(s3c_ts_dev);
}
else
{
#if 0
printk("pen_down_up_isr down: %d\n", ++cnt);
/* 进入"等待中断模式": 等待松开 */
s3c_adc_regs->adctsc = (1<<8) | (1<<7) | (1<<6) | (0<<5) | (1 << 4) | (0 << 3) | (3<<0);
#endif
//printk("pen_down_up_isr down: %d\n", ++cnt);
enter_measure_xy_mode();
start_adc();
}
return IRQ_HANDLED;
}
// 过滤 让定位更准确
static int s3c_ts_filtering(int *px, int *py)
{
int avr_x, avr_y;
int dx, dy;
#define FILTER_LIMIT 25
avr_x = (px[0] + px[1]) / 2;
avr_y = (py[0] + py[1]) / 2;
dx = (px[2] > avr_x) ? (px[2] - avr_x) : (avr_x - px[2]);
dy = (py[2] > avr_y) ? (py[2] - avr_y) : (avr_y - py[2]);
if ((dx > FILTER_LIMIT) || (dy > FILTER_LIMIT))
return 0;
avr_x = (px[1] + px[2]) / 2;
avr_y = (py[1] + py[2]) / 2;
dx = (px[3] > avr_x) ? (px[3] - avr_x) : (avr_x - px[3]);
dy = (py[3] > avr_y) ? (py[3] - avr_y) : (avr_y - py[3]);
if ((dx > FILTER_LIMIT) || (dy > FILTER_LIMIT))
return 0;
return 1;
}
static irqreturn_t adc_isr(int irq, void *devid)
{
static int cnt = 0;
static int xs[4];
static int ys[4];
static int x = 0, y = 0;
// static int pre_x = 0, pre_y = 0;
int data0, data1;
//printk("adc_isr : %d\n", ++cnt);
data0 = s3c_adc_regs->adcdat0;
data1 = s3c_adc_regs->adcdat1;
if (data0 & (1<<15))
{
/* 已经松开 */
enter_wait_pen_down();
input_event(s3c_ts_dev, EV_ABS, ABS_PRESSURE, 0);
input_event(s3c_ts_dev, EV_KEY, BTN_TOUCH, 0);
input_sync(s3c_ts_dev);
x = y = cnt = 0;
}
else
{
//printk("x = %d, y = %d\n", x, y);
x += (data0 & 0x3ff);
y += (data1 & 0x3ff);
xs[cnt] = (data0 & 0x3ff);
ys[cnt] = (data0 & 0x3ff);
cnt++;
if (cnt == 4)
{
if (s3c_ts_filtering(xs, ys))
{
input_event(s3c_ts_dev, EV_ABS, ABS_X, x/4);
input_event(s3c_ts_dev, EV_ABS, ABS_Y, y/4);
input_event(s3c_ts_dev, EV_ABS, ABS_PRESSURE, 1);
input_event(s3c_ts_dev, EV_KEY, BTN_TOUCH, 1);
input_sync(s3c_ts_dev);
}
x = y = cnt = 0;
/* 进入"等待中断模式": 等待松开 */
enter_wait_pen_up();
mod_timer(&s3c_ts_timer, jiffies + HZ/100);
}
else
{
enter_measure_xy_mode();
start_adc();
}
}
return IRQ_HANDLED;
}
static int s3c_ts_init(void)
{
unsigned long *gpgcon = ioremap(0x56000060, 4);
/* 1. 分配一个input_dev结构体 */
s3c_ts_dev = input_allocate_device();
/* 2. 设置 */
/* 2.1 能产生哪类事件 */
__set_bit(EV_KEY, s3c_ts_dev->evbit);
__set_bit(EV_ABS, s3c_ts_dev->evbit);
/* 2.1 能产生这类事件里的哪些 */
__set_bit(BTN_TOUCH, s3c_ts_dev->keybit);
/*触摸屏的初始化*/
input_set_abs_params(s3c_ts_dev, ABS_X, 0, 0x3FF, 0, 0);
input_set_abs_params(s3c_ts_dev, ABS_Y, 0, 0x3FF, 0, 0);
input_set_abs_params(s3c_ts_dev, ABS_PRESSURE, 0, 1, 0, 0);
s3c_ts_dev->name = "s3c_ts";
/* 3. 注册 */
input_register_device(s3c_ts_dev);
/* 4. 硬件相关的操作 */
/* CLKCON 的使能*/
clk_enable(clk_get(NULL, "adc"));
/* 配置引脚用于触摸屏 */
*gpgcon |= 0xff000000;
iounmap(gpgcon);
s3c_adc_regs = ioremap(0x58000000, 1024);
/* bit14: A/D converter prescaler enable
* bit[13:6]: A/D converter prescaler value,
* ADC CLK = PCLK/(49+1)
*/
s3c_adc_regs->adccon = (1<<14) | (49 << 6);
s3c_adc_regs->adcdly = 0xffff;
//添加定时器
init_timer(&s3c_ts_timer);
s3c_ts_timer.expires = 0;
s3c_ts_timer.function = s3c_ts_timer_function;
add_timer(&s3c_ts_timer);
/* 进入"等待中断模式": 等待按下 */
enter_wait_pen_down();
request_irq(IRQ_TC, pen_down_up_isr, IRQF_SHARED, "touch_pen", 1);
request_irq(IRQ_ADC, adc_isr, IRQF_SHARED, "adc_done", 1);
return 0;
}
static void s3c_ts_exit(void)
{
free_irq(IRQ_ADC, 1);
free_irq(IRQ_TC, 1);
input_unregister_device(s3c_ts_dev);
input_free_device(s3c_ts_dev);
}
module_init(s3c_ts_init);
module_exit(s3c_ts_exit);
MODULE_LICENSE("GPL");
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/init.h>
#include <linux/serio.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/arch/regs-gpio.h>
struct s3c_adc_regs {
unsigned long adccon;
unsigned long adctsc;
unsigned long adcdly;
unsigned long adcdat0;
unsigned long adcdat1;
};
static struct input_dev *s3c_ts_dev;
static struct s3c_adc_regs *s3c_adc_regs;
static struct timer_list s3c_ts_timer;
//等待触摸笔的按下
static void enter_wait_pen_down(void)
{
s3c_adc_regs->adctsc = (1<<7) | (1<<6) | (0<<5) | (1 << 4) | (0 << 3) | (3<<0);
}
static void enter_wait_pen_up(void)
{
s3c_adc_regs->adctsc = (1<<8) | (1<<7) | (1<<6) | (0<<5) | (1 << 4) | (0 << 3) | (3<<0);
}
//测量xy的值
static void enter_measure_xy_mode(void)
{
s3c_adc_regs->adctsc = (1<<7) | (1<<6) | (1<<4) | (1<<3) | (1<<2);
}
static void start_adc(void)
{
s3c_adc_regs->adccon |= (1<<0);
}
//时间函数,时间到的时间,自动启动xy的转换,开始adc
static void s3c_ts_timer_function(unsigned long h)
{
enter_measure_xy_mode();
start_adc();
}
static irqreturn_t pen_down_up_isr(int irq, void *devid)
{
static int cnt = 0;
if (s3c_adc_regs->adcdat0 & (1<<15))
{
//printk("pen_down_up_isr up: %d\n", ++cnt);
/* 进入"等待中断模式": 等待按下 */
enter_wait_pen_down();
/*上报事件 ,完成一次上报事件*/
input_event(s3c_ts_dev, EV_ABS, ABS_PRESSURE, 0);
input_event(s3c_ts_dev, EV_KEY, BTN_TOUCH, 0);
input_sync(s3c_ts_dev);
}
else
{
#if 0
printk("pen_down_up_isr down: %d\n", ++cnt);
/* 进入"等待中断模式": 等待松开 */
s3c_adc_regs->adctsc = (1<<8) | (1<<7) | (1<<6) | (0<<5) | (1 << 4) | (0 << 3) | (3<<0);
#endif
//printk("pen_down_up_isr down: %d\n", ++cnt);
enter_measure_xy_mode();
start_adc();
}
return IRQ_HANDLED;
}
// 过滤 让定位更准确
static int s3c_ts_filtering(int *px, int *py)
{
int avr_x, avr_y;
int dx, dy;
#define FILTER_LIMIT 25
avr_x = (px[0] + px[1]) / 2;
avr_y = (py[0] + py[1]) / 2;
dx = (px[2] > avr_x) ? (px[2] - avr_x) : (avr_x - px[2]);
dy = (py[2] > avr_y) ? (py[2] - avr_y) : (avr_y - py[2]);
if ((dx > FILTER_LIMIT) || (dy > FILTER_LIMIT))
return 0;
avr_x = (px[1] + px[2]) / 2;
avr_y = (py[1] + py[2]) / 2;
dx = (px[3] > avr_x) ? (px[3] - avr_x) : (avr_x - px[3]);
dy = (py[3] > avr_y) ? (py[3] - avr_y) : (avr_y - py[3]);
if ((dx > FILTER_LIMIT) || (dy > FILTER_LIMIT))
return 0;
return 1;
}
static irqreturn_t adc_isr(int irq, void *devid)
{
static int cnt = 0;
static int xs[4];
static int ys[4];
static int x = 0, y = 0;
// static int pre_x = 0, pre_y = 0;
int data0, data1;
//printk("adc_isr : %d\n", ++cnt);
data0 = s3c_adc_regs->adcdat0;
data1 = s3c_adc_regs->adcdat1;
if (data0 & (1<<15))
{
/* 已经松开 */
enter_wait_pen_down();
input_event(s3c_ts_dev, EV_ABS, ABS_PRESSURE, 0);
input_event(s3c_ts_dev, EV_KEY, BTN_TOUCH, 0);
input_sync(s3c_ts_dev);
x = y = cnt = 0;
}
else
{
//printk("x = %d, y = %d\n", x, y);
x += (data0 & 0x3ff);
y += (data1 & 0x3ff);
xs[cnt] = (data0 & 0x3ff);
ys[cnt] = (data0 & 0x3ff);
cnt++;
if (cnt == 4)
{
if (s3c_ts_filtering(xs, ys))
{
input_event(s3c_ts_dev, EV_ABS, ABS_X, x/4);
input_event(s3c_ts_dev, EV_ABS, ABS_Y, y/4);
input_event(s3c_ts_dev, EV_ABS, ABS_PRESSURE, 1);
input_event(s3c_ts_dev, EV_KEY, BTN_TOUCH, 1);
input_sync(s3c_ts_dev);
}
x = y = cnt = 0;
/* 进入"等待中断模式": 等待松开 */
enter_wait_pen_up();
mod_timer(&s3c_ts_timer, jiffies + HZ/100);
}
else
{
enter_measure_xy_mode();
start_adc();
}
}
return IRQ_HANDLED;
}
static int s3c_ts_init(void)
{
unsigned long *gpgcon = ioremap(0x56000060, 4);
/* 1. 分配一个input_dev结构体 */
s3c_ts_dev = input_allocate_device();
/* 2. 设置 */
/* 2.1 能产生哪类事件 */
__set_bit(EV_KEY, s3c_ts_dev->evbit);
__set_bit(EV_ABS, s3c_ts_dev->evbit);
/* 2.1 能产生这类事件里的哪些 */
__set_bit(BTN_TOUCH, s3c_ts_dev->keybit);
/*触摸屏的初始化*/
input_set_abs_params(s3c_ts_dev, ABS_X, 0, 0x3FF, 0, 0);
input_set_abs_params(s3c_ts_dev, ABS_Y, 0, 0x3FF, 0, 0);
input_set_abs_params(s3c_ts_dev, ABS_PRESSURE, 0, 1, 0, 0);
s3c_ts_dev->name = "s3c_ts";
/* 3. 注册 */
input_register_device(s3c_ts_dev);
/* 4. 硬件相关的操作 */
/* CLKCON 的使能*/
clk_enable(clk_get(NULL, "adc"));
/* 配置引脚用于触摸屏 */
*gpgcon |= 0xff000000;
iounmap(gpgcon);
s3c_adc_regs = ioremap(0x58000000, 1024);
/* bit14: A/D converter prescaler enable
* bit[13:6]: A/D converter prescaler value,
* ADC CLK = PCLK/(49+1)
*/
s3c_adc_regs->adccon = (1<<14) | (49 << 6);
s3c_adc_regs->adcdly = 0xffff;
//添加定时器
init_timer(&s3c_ts_timer);
s3c_ts_timer.expires = 0;
s3c_ts_timer.function = s3c_ts_timer_function;
add_timer(&s3c_ts_timer);
/* 进入"等待中断模式": 等待按下 */
enter_wait_pen_down();
request_irq(IRQ_TC, pen_down_up_isr, IRQF_SHARED, "touch_pen", 1);
request_irq(IRQ_ADC, adc_isr, IRQF_SHARED, "adc_done", 1);
return 0;
}
static void s3c_ts_exit(void)
{
free_irq(IRQ_ADC, 1);
free_irq(IRQ_TC, 1);
input_unregister_device(s3c_ts_dev);
input_free_device(s3c_ts_dev);
}
module_init(s3c_ts_init);
module_exit(s3c_ts_exit);
MODULE_LICENSE("GPL");