touch.c 8.0 KB
Newer Older
1 2
#include <rthw.h>
#include <rtthread.h>
B
bernard.xiong 已提交
3
#include <s3c24x0.h>
4
#include <rtgui/rtgui_system.h>
A
 
aganhx@gmail.com 已提交
5
#include <rtgui/rtgui_server.h>
qiuyiuestc's avatar
qiuyiuestc 已提交
6
#include <rtgui/event.h>
7

8 9
#include "touch.h"

10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
/* ADCCON Register Bits */
#define S3C2410_ADCCON_ECFLG		(1<<15)
#define S3C2410_ADCCON_PRSCEN		(1<<14)
#define S3C2410_ADCCON_PRSCVL(x)	(((x)&0xFF)<<6)
#define S3C2410_ADCCON_PRSCVLMASK	(0xFF<<6)
#define S3C2410_ADCCON_SELMUX(x)	(((x)&0x7)<<3)
#define S3C2410_ADCCON_MUXMASK		(0x7<<3)
#define S3C2410_ADCCON_STDBM		(1<<2)
#define S3C2410_ADCCON_READ_START	(1<<1)
#define S3C2410_ADCCON_ENABLE_START	(1<<0)
#define S3C2410_ADCCON_STARTMASK	(0x3<<0)

/* ADCTSC Register Bits */
#define S3C2410_ADCTSC_UD_SEN		(1<<8) /* ghcstop add for s3c2440a */
#define S3C2410_ADCTSC_YM_SEN		(1<<7)
#define S3C2410_ADCTSC_YP_SEN		(1<<6)
#define S3C2410_ADCTSC_XM_SEN		(1<<5)
#define S3C2410_ADCTSC_XP_SEN		(1<<4)
#define S3C2410_ADCTSC_PULL_UP_DISABLE	(1<<3)
#define S3C2410_ADCTSC_AUTO_PST		(1<<2)
#define S3C2410_ADCTSC_XY_PST(x)	(((x)&0x3)<<0)

/* ADCDAT0 Bits */
#define S3C2410_ADCDAT0_UPDOWN		(1<<15)
#define S3C2410_ADCDAT0_AUTO_PST	(1<<14)
#define S3C2410_ADCDAT0_XY_PST		(0x3<<12)
#define S3C2410_ADCDAT0_XPDATA_MASK	(0x03FF)

/* ADCDAT1 Bits */
#define S3C2410_ADCDAT1_UPDOWN		(1<<15)
#define S3C2410_ADCDAT1_AUTO_PST	(1<<14)
#define S3C2410_ADCDAT1_XY_PST		(0x3<<12)
#define S3C2410_ADCDAT1_YPDATA_MASK	(0x03FF)

#define WAIT4INT(x)  (((x)<<8) | \
		     S3C2410_ADCTSC_YM_SEN | S3C2410_ADCTSC_YP_SEN | S3C2410_ADCTSC_XP_SEN | \
		     S3C2410_ADCTSC_XY_PST(3))

#define AUTOPST	     (S3C2410_ADCTSC_YM_SEN | S3C2410_ADCTSC_YP_SEN | S3C2410_ADCTSC_XP_SEN | \
		     S3C2410_ADCTSC_AUTO_PST | S3C2410_ADCTSC_XY_PST(0))

51 52 53 54 55
#define X_MIN		74
#define X_MAX		934
#define Y_MIN		89
#define Y_MAX		920

56 57 58 59 60 61 62 63 64 65 66 67 68 69
struct s3c2410ts
{
	long xp;
	long yp;
	int count;
	int shift;

	int delay;
	int presc;

	char phys[32];
};
static struct s3c2410ts ts;

70
struct rtgui_touch_device
71
{
72
    struct rt_device parent;
73

74 75
    rt_timer_t poll_timer;
    rt_uint16_t x, y;
76

77 78
    rt_bool_t calibrating;
    rt_touch_calibration_func_t calibration_func;
79

80 81 82 83 84
    rt_uint16_t min_x, max_x;
    rt_uint16_t min_y, max_y;
};
static struct rtgui_touch_device *touch = RT_NULL;
static int first_down_report;
85

86 87 88
static void report_touch_input(int updown)
{
	struct rtgui_event_mouse emouse;
89 90

	/* set emouse button */
qiuyiuestc's avatar
qiuyiuestc 已提交
91
	emouse.button = RTGUI_MOUSE_BUTTON_LEFT;
92 93
	emouse.parent.sender = RT_NULL;
	
94 95
	if (updown)
	{
96 97 98
		ts.xp = ts.xp / ts.count;
		ts.yp = ts.yp / ts.count;;

qiuyiuestc's avatar
qiuyiuestc 已提交
99 100 101 102 103 104 105 106 107 108
		if ((touch->calibrating == RT_TRUE) && (touch->calibration_func != RT_NULL))
		{
			touch->x = ts.xp;
			touch->y = ts.yp;
		}
		else
		{	
			touch->x = 240 * (ts.xp-touch->min_x)/(touch->max_x-touch->min_x);
			touch->y = 320 - (320*(ts.yp-touch->min_y)/(touch->max_y-touch->min_y));
		}
109 110 111 112 113 114 115 116 117 118 119 120 121

		emouse.x = touch->x;
		emouse.y = touch->y;
		if(first_down_report == 1)
		{
			emouse.parent.type = RTGUI_EVENT_MOUSE_BUTTON;
			emouse.button |= RTGUI_MOUSE_BUTTON_DOWN;
		}
		else
		{	
			emouse.parent.type = RTGUI_EVENT_MOUSE_MOTION;
			emouse.button = 0;
		}	
122 123 124
	}
	else
	{
125 126 127 128 129 130 131 132 133
		emouse.x = touch->x;
		emouse.y = touch->y;	
		emouse.parent.type = RTGUI_EVENT_MOUSE_BUTTON;
		emouse.button |= RTGUI_MOUSE_BUTTON_UP;
		if ((touch->calibrating == RT_TRUE) && (touch->calibration_func != RT_NULL))
		{
			/* callback function */
			touch->calibration_func(emouse.x, emouse.y);
		}
134 135
	}

136 137 138 139 140 141 142 143 144 145
	/*	
		rt_kprintf("touch %s: ts.x: %d, ts.y: %d\n", updown? "down" : "up",
		touch->x, touch->y);
	*/
	
	/* send event to server */
	if (touch->calibrating != RT_TRUE)
	{	
		rtgui_server_post_event((&emouse.parent), sizeof(emouse));
	}	
146 147
}

148
static void touch_timer_fire(void* parameter)
149
{
150 151 152 153 154 155 156 157 158 159
  	rt_uint32_t data0;
  	rt_uint32_t data1;
	int updown;

  	data0 = ADCDAT0;
  	data1 = ADCDAT1;

 	updown = (!(data0 & S3C2410_ADCDAT0_UPDOWN)) && (!(data1 & S3C2410_ADCDAT0_UPDOWN));

 	if (updown)
160
	{
161
 		if (ts.count != 0)
162
		{
163 164 165 166 167 168
			report_touch_input(updown);
 		}

 		ts.xp = 0;
 		ts.yp = 0;
 		ts.count = 0;
169

170 171 172
 		ADCTSC = S3C2410_ADCTSC_PULL_UP_DISABLE | AUTOPST;
 		ADCCON |= S3C2410_ADCCON_ENABLE_START;
 	}
173 174
}

175
static void s3c2410_adc_stylus_action(void)
176 177 178 179 180 181
{
	rt_uint32_t data0;
	rt_uint32_t data1;

	data0 = ADCDAT0;
	data1 = ADCDAT1;
182
	
183 184 185 186 187 188 189 190 191 192 193
	ts.xp += data0 & S3C2410_ADCDAT0_XPDATA_MASK;
	ts.yp += data1 & S3C2410_ADCDAT1_YPDATA_MASK;
	ts.count++;

	if (ts.count < (1<<ts.shift))
	{
		ADCTSC = S3C2410_ADCTSC_PULL_UP_DISABLE | AUTOPST;
		ADCCON |= S3C2410_ADCCON_ENABLE_START;
	}
	else
	{
194 195 196 197 198 199 200 201 202 203
		if (first_down_report)
		{
			report_touch_input(1);
			ts.xp = 0;
			ts.yp = 0;
			ts.count = 0;
			first_down_report = 0;
		}
		/* start timer */
		rt_timer_start(touch->poll_timer);
204 205
		ADCTSC = WAIT4INT(1);
	}
206 207

	SUBSRCPND |= BIT_SUB_ADC;
208 209
}

210
static void s3c2410_intc_stylus_updown(void)
211 212 213 214 215 216 217 218 219 220
{
	rt_uint32_t data0;
	rt_uint32_t data1;
	int updown;

	data0 = ADCDAT0;
	data1 = ADCDAT1;

	updown = (!(data0 & S3C2410_ADCDAT0_UPDOWN)) && (!(data1 & S3C2410_ADCDAT0_UPDOWN));

221 222
	/* rt_kprintf("stylus: %s\n", updown? "down" : "up"); */

223 224
	if (updown) 
	{
225 226
		touch_timer_fire(0);
	}	
227 228
	else
	{
229 230 231
		/* stop timer */
		rt_timer_stop(touch->poll_timer);
		first_down_report = 1;
232 233
		if (ts.xp >= 0 && ts.yp >= 0)
		{
234
			report_touch_input(updown);
235
		}
236
		ts.count = 0;
237 238
		ADCTSC = WAIT4INT(0);
	}
239 240

	SUBSRCPND |= BIT_SUB_TC;
241 242
}

243
static void rt_touch_handler(int irqno)
244
{
qiuyiuestc's avatar
qiuyiuestc 已提交
245
	if (SUBSRCPND & BIT_SUB_ADC)
246 247 248 249 250
	{
		/* INT_SUB_ADC */
		s3c2410_adc_stylus_action();
	}

qiuyiuestc's avatar
qiuyiuestc 已提交
251
	if (SUBSRCPND & BIT_SUB_TC)
252 253 254 255 256 257
	{
		/* INT_SUB_TC */
		s3c2410_intc_stylus_updown();
	}

	/* clear interrupt */
A
 
aganhx@gmail.com 已提交
258
	INTPND |= (rt_uint32_t)(1 << INTADC);
259 260
}

261 262
/* RT-Thread Device Interface */
static rt_err_t rtgui_touch_init (rt_device_t dev)
263 264 265 266
{
	/* init touch screen structure */
	rt_memset(&ts, 0, sizeof(struct s3c2410ts));

267 268
	ts.delay = 50000;
	ts.presc = 9;
269
	ts.shift = 2;
270 271
	ts.count = 0;
	ts.xp = ts.yp = 0;
272 273 274 275 276 277 278 279 280

	ADCCON = S3C2410_ADCCON_PRSCEN | S3C2410_ADCCON_PRSCVL(ts.presc);
	ADCDLY = ts.delay;

	ADCTSC = WAIT4INT(0);

	rt_hw_interrupt_install(INTADC, rt_touch_handler, RT_NULL);
	rt_hw_interrupt_umask(INTADC);

281 282 283 284 285 286
	/* clear interrupt */
	INTPND |= (rt_uint32_t)(1 << INTADC);
	
	SUBSRCPND |= BIT_SUB_TC;
	SUBSRCPND |= BIT_SUB_ADC;

287 288 289 290 291
	/* install interrupt handler */
	INTSUBMSK &= ~BIT_SUB_ADC;
	INTSUBMSK &= ~BIT_SUB_TC;

	first_down_report = 1;
292 293 294 295 296 297

	return RT_EOK;
}

static rt_err_t rtgui_touch_control (rt_device_t dev, rt_uint8_t cmd, void *args)
{
qiuyiuestc's avatar
qiuyiuestc 已提交
298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329
	switch (cmd)
	{
	case RT_TOUCH_CALIBRATION:
		touch->calibrating = RT_TRUE;
		touch->calibration_func = (rt_touch_calibration_func_t)args;
		break;

	case RT_TOUCH_NORMAL:
		touch->calibrating = RT_FALSE;
		break;

	case RT_TOUCH_CALIBRATION_DATA:
	{
		struct calibration_data* data;

		data = (struct calibration_data*) args;

		//update
		touch->min_x = data->min_x;
		touch->max_x = data->max_x;
		touch->min_y = data->max_y;
		touch->max_y = data->min_y;

		/*
			rt_kprintf("min_x = %d, max_x = %d, min_y = %d, max_y = %d\n",
				touch->min_x, touch->max_x, touch->min_y, touch->max_y);
		*/		
	}
	break;
	}

	return RT_EOK;
330 331 332 333
}

void rtgui_touch_hw_init(void)
{
qiuyiuestc's avatar
qiuyiuestc 已提交
334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356
	touch = (struct rtgui_touch_device*)rt_malloc (sizeof(struct rtgui_touch_device));
	if (touch == RT_NULL) return; /* no memory yet */

	/* clear device structure */
	rt_memset(&(touch->parent), 0, sizeof(struct rt_device));
	touch->calibrating = RT_FALSE;
	touch->min_x = X_MIN;
	touch->max_x = X_MAX;
	touch->min_y = Y_MIN;
	touch->max_y = X_MAX;

	/* init device structure */
	touch->parent.type = RT_Device_Class_Unknown;
	touch->parent.init = rtgui_touch_init;
	touch->parent.control = rtgui_touch_control;
	touch->parent.private = RT_NULL;

	/* create 1/8 second timer */
	touch->poll_timer = rt_timer_create("touch", touch_timer_fire, RT_NULL,
	                                    RT_TICK_PER_SECOND/8, RT_TIMER_FLAG_PERIODIC);

	/* register touch device to RT-Thread */
	rt_device_register(&(touch->parent), "touch", RT_DEVICE_FLAG_RDWR);
357
}
qiuyiuestc's avatar
qiuyiuestc 已提交
358