h3600_ts_input.c 12.8 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 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 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
/*
 * $Id: h3600_ts_input.c,v 1.4 2002/01/23 06:39:37 jsimmons Exp $
 *
 *  Copyright (c) 2001 "Crazy" James Simmons jsimmons@transvirtual.com
 *
 *  Sponsored by Transvirtual Technology.
 *
 *  Derived from the code in h3600_ts.[ch] by Charles Flynn
 */

/*
 * Driver for the h3600 Touch Screen and other Atmel controlled devices.
 */

/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 *
 * Should you need to contact me, the author, you can do so by
 * e-mail - mail your message to <jsimmons@transvirtual.com>.
 */

#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/serio.h>
#include <linux/init.h>
#include <linux/delay.h>

/* SA1100 serial defines */
#include <asm/arch/hardware.h>
#include <asm/arch/irqs.h>

#define DRIVER_DESC	"H3600 touchscreen driver"

MODULE_AUTHOR("James Simmons <jsimmons@transvirtual.com>");
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");

/*
 * Definitions & global arrays.
 */

/* The start and end of frame characters SOF and EOF */
#define CHAR_SOF                0x02
#define CHAR_EOF                0x03
#define FRAME_OVERHEAD          3       /* CHAR_SOF,CHAR_EOF,LENGTH = 3 */

/*
        Atmel events and response IDs contained in frame.
        Programmer has no control over these numbers.
        TODO there are holes - specifically  1,7,0x0a
*/
#define VERSION_ID              0       /* Get Version (request/respose) */
#define KEYBD_ID                2       /* Keyboard (event) */
#define TOUCHS_ID               3       /* Touch Screen (event)*/
#define EEPROM_READ_ID          4       /* (request/response) */
#define EEPROM_WRITE_ID         5       /* (request/response) */
#define THERMAL_ID              6       /* (request/response) */
#define NOTIFY_LED_ID           8       /* (request/response) */
#define BATTERY_ID              9       /* (request/response) */
#define SPI_READ_ID             0x0b    /* ( request/response) */
#define SPI_WRITE_ID            0x0c    /* ( request/response) */
#define FLITE_ID                0x0d    /* backlight ( request/response) */
#define STX_ID                  0xa1    /* extension pack status (req/resp) */

#define MAX_ID                  14

#define H3600_MAX_LENGTH 16
#define H3600_KEY 0xf

#define H3600_SCANCODE_RECORD	1	 /* 1 -> record button */
#define H3600_SCANCODE_CALENDAR 2	 /* 2 -> calendar */
#define H3600_SCANCODE_CONTACTS 3	 /* 3 -> contact */
#define H3600_SCANCODE_Q	4	 /* 4 -> Q button */
#define	H3600_SCANCODE_START	5	 /* 5 -> start menu */
#define	H3600_SCANCODE_UP	6	 /* 6 -> up */
91 92 93
#define H3600_SCANCODE_RIGHT	7	 /* 7 -> right */
#define H3600_SCANCODE_LEFT	8	 /* 8 -> left */
#define H3600_SCANCODE_DOWN	9	 /* 9 -> down */
L
Linus Torvalds 已提交
94 95 96 97 98

/*
 * Per-touchscreen data.
 */
struct h3600_dev {
99
	struct input_dev *dev;
L
Linus Torvalds 已提交
100 101 102 103 104 105 106 107 108 109 110
	struct serio *serio;
	unsigned char event;	/* event ID from packet */
	unsigned char chksum;
	unsigned char len;
	unsigned char idx;
	unsigned char buf[H3600_MAX_LENGTH];
	char phys[32];
};

static irqreturn_t action_button_handler(int irq, void *dev_id, struct pt_regs *regs)
{
111
	int down = (GPLR & GPIO_BITSY_ACTION_BUTTON) ? 0 : 1;
L
Linus Torvalds 已提交
112 113 114 115 116 117 118 119 120 121 122
	struct input_dev *dev = (struct input_dev *) dev_id;

	input_regs(dev, regs);
	input_report_key(dev, KEY_ENTER, down);
	input_sync(dev);

	return IRQ_HANDLED;
}

static irqreturn_t npower_button_handler(int irq, void *dev_id, struct pt_regs *regs)
{
123
	int down = (GPLR & GPIO_BITSY_NPOWER_BUTTON) ? 0 : 1;
L
Linus Torvalds 已提交
124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
	struct input_dev *dev = (struct input_dev *) dev_id;

	/*
	 * This interrupt is only called when we release the key. So we have
	 * to fake a key press.
	 */
	input_regs(dev, regs);
	input_report_key(dev, KEY_SUSPEND, 1);
	input_report_key(dev, KEY_SUSPEND, down);
	input_sync(dev);

	return IRQ_HANDLED;
}

#ifdef CONFIG_PM

static int flite_brightness = 25;

enum flite_pwr {
143 144
	FLITE_PWR_OFF = 0,
	FLITE_PWR_ON = 1
L
Linus Torvalds 已提交
145 146 147 148 149 150 151 152 153 154
};

/*
 * h3600_flite_power: enables or disables power to frontlight, using last bright */
unsigned int h3600_flite_power(struct input_dev *dev, enum flite_pwr pwr)
{
	unsigned char brightness = (pwr == FLITE_PWR_OFF) ? 0 : flite_brightness;
	struct h3600_dev *ts = dev->private;

	/* Must be in this order */
155
	ts->serio->write(ts->serio, 1);
L
Linus Torvalds 已提交
156
	ts->serio->write(ts->serio, pwr);
157
	ts->serio->write(ts->serio, brightness);
L
Linus Torvalds 已提交
158 159 160 161 162 163 164 165 166 167 168 169
	return 0;
}

#endif

/*
 * This function translates the native event packets to linux input event
 * packets. Some packets coming from serial are not touchscreen related. In
 * this case we send them off to be processed elsewhere.
 */
static void h3600ts_process_packet(struct h3600_dev *ts, struct pt_regs *regs)
{
170
	struct input_dev *dev = ts->dev;
L
Linus Torvalds 已提交
171 172 173 174 175
	static int touched = 0;
	int key, down = 0;

	input_regs(dev, regs);

176 177 178 179 180
	switch (ts->event) {
		/*
		   Buttons - returned as a single byte
			7 6 5 4 3 2 1 0
			S x x x N N N N
L
Linus Torvalds 已提交
181

182 183 184
		   S       switch state ( 0=pressed 1=released)
		   x       Unused.
		   NNNN    switch number 0-15
L
Linus Torvalds 已提交
185

186 187 188
		   Note: This is true for non interrupt generated key events.
		*/
		case KEYBD_ID:
L
Linus Torvalds 已提交
189 190 191 192 193 194 195 196 197 198 199
			down = (ts->buf[0] & 0x80) ? 0 : 1;

			switch (ts->buf[0] & 0x7f) {
				case H3600_SCANCODE_RECORD:
					key = KEY_RECORD;
					break;
				case H3600_SCANCODE_CALENDAR:
					key = KEY_PROG1;
                                        break;
				case H3600_SCANCODE_CONTACTS:
					key = KEY_PROG2;
200
					break;
L
Linus Torvalds 已提交
201 202
				case H3600_SCANCODE_Q:
					key = KEY_Q;
203
					break;
L
Linus Torvalds 已提交
204 205
				case H3600_SCANCODE_START:
					key = KEY_PROG3;
206
					break;
L
Linus Torvalds 已提交
207 208
				case H3600_SCANCODE_UP:
					key = KEY_UP;
209
					break;
L
Linus Torvalds 已提交
210 211
				case H3600_SCANCODE_RIGHT:
					key = KEY_RIGHT;
212
					break;
L
Linus Torvalds 已提交
213 214
				case H3600_SCANCODE_LEFT:
					key = KEY_LEFT;
215
					break;
L
Linus Torvalds 已提交
216 217
				case H3600_SCANCODE_DOWN:
					key = KEY_DOWN;
218
					break;
L
Linus Torvalds 已提交
219 220 221
				default:
					key = 0;
			}
222 223 224 225 226 227 228 229 230 231 232 233
			if (key)
				input_report_key(dev, key, down);
			break;
		/*
		 * Native touchscreen event data is formatted as shown below:-
		 *
		 *      +-------+-------+-------+-------+
		 *      | Xmsb  | Xlsb  | Ymsb  | Ylsb  |
		 *      +-------+-------+-------+-------+
		 *       byte 0    1       2       3
		 */
		case TOUCHS_ID:
L
Linus Torvalds 已提交
234 235 236 237 238 239 240 241 242
			if (!touched) {
				input_report_key(dev, BTN_TOUCH, 1);
				touched = 1;
			}

			if (ts->len) {
				unsigned short x, y;

				x = ts->buf[0]; x <<= 8; x += ts->buf[1];
243
				y = ts->buf[2]; y <<= 8; y += ts->buf[3];
L
Linus Torvalds 已提交
244

245 246
				input_report_abs(dev, ABS_X, x);
				input_report_abs(dev, ABS_Y, y);
L
Linus Torvalds 已提交
247
			} else {
248
				input_report_key(dev, BTN_TOUCH, 0);
L
Linus Torvalds 已提交
249 250
				touched = 0;
			}
251
			break;
L
Linus Torvalds 已提交
252 253 254
		default:
			/* Send a non input event elsewhere */
			break;
255
	}
L
Linus Torvalds 已提交
256 257 258 259 260 261 262 263

	input_sync(dev);
}

/*
 * h3600ts_event() handles events from the input module.
 */
static int h3600ts_event(struct input_dev *dev, unsigned int type,
264
			 unsigned int code, int value)
L
Linus Torvalds 已提交
265
{
266
#if 0
L
Linus Torvalds 已提交
267 268 269 270 271 272 273 274 275
	struct h3600_dev *ts = dev->private;

	switch (type) {
		case EV_LED: {
		//	ts->serio->write(ts->serio, SOME_CMD);
			return 0;
		}
	}
	return -1;
276 277
#endif
	return 0;
L
Linus Torvalds 已提交
278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305
}

/*
        Frame format
  byte    1       2               3              len + 4
        +-------+---------------+---------------+--=------------+
        |SOF    |id     |len    | len bytes     | Chksum        |
        +-------+---------------+---------------+--=------------+
  bit   0     7  8    11 12   15 16

        +-------+---------------+-------+
        |SOF    |id     |0      |Chksum | - Note Chksum does not include SOF
        +-------+---------------+-------+
  bit   0     7  8    11 12   15 16

*/

static int state;

/* decode States  */
#define STATE_SOF       0       /* start of FRAME */
#define STATE_ID        1       /* state where we decode the ID & len */
#define STATE_DATA      2       /* state where we decode data */
#define STATE_EOF       3       /* state where we decode checksum or EOF */

static irqreturn_t h3600ts_interrupt(struct serio *serio, unsigned char data,
                                     unsigned int flags, struct pt_regs *regs)
{
306
	struct h3600_dev *ts = serio_get_drvdata(serio);
L
Linus Torvalds 已提交
307 308

	/*
309 310
	 * We have a new frame coming in.
	 */
L
Linus Torvalds 已提交
311 312
	switch (state) {
		case STATE_SOF:
313 314
			if (data == CHAR_SOF)
				state = STATE_ID;
L
Linus Torvalds 已提交
315
			break;
316
		case STATE_ID:
L
Linus Torvalds 已提交
317 318 319 320 321
			ts->event = (data & 0xf0) >> 4;
			ts->len = (data & 0xf);
			ts->idx = 0;
			if (ts->event >= MAX_ID) {
				state = STATE_SOF;
322
				break;
L
Linus Torvalds 已提交
323 324
			}
			ts->chksum = data;
325
			state = (ts->len > 0) ? STATE_DATA : STATE_EOF;
L
Linus Torvalds 已提交
326 327 328 329
			break;
		case STATE_DATA:
			ts->chksum += data;
			ts->buf[ts->idx]= data;
330 331
			if (++ts->idx == ts->len)
				state = STATE_EOF;
L
Linus Torvalds 已提交
332 333
			break;
		case STATE_EOF:
334 335
			state = STATE_SOF;
			if (data == CHAR_EOF || data == ts->chksum)
L
Linus Torvalds 已提交
336
				h3600ts_process_packet(ts, regs);
337 338 339 340
			break;
		default:
			printk("Error3\n");
			break;
L
Linus Torvalds 已提交
341 342 343 344 345 346 347 348 349 350 351 352 353
	}

	return IRQ_HANDLED;
}

/*
 * h3600ts_connect() is the routine that is called when someone adds a
 * new serio device that supports H3600 protocol and registers it as
 * an input device.
 */
static int h3600ts_connect(struct serio *serio, struct serio_driver *drv)
{
	struct h3600_dev *ts;
354
	struct input_dev *input_dev;
L
Linus Torvalds 已提交
355 356
	int err;

357 358 359 360 361 362
	ts = kzalloc(sizeof(struct h3600_dev), GFP_KERNEL);
	input_dev = input_allocate_device();
	if (!ts || !input_dev) {
		err = -ENOMEM;
		goto fail1;
	}
L
Linus Torvalds 已提交
363

364 365 366
	ts->serio = serio;
	ts->dev = input_dev;
	sprintf(ts->phys, "%s/input0", serio->phys);
L
Linus Torvalds 已提交
367

368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395
	input_dev->name = "H3600 TouchScreen";
	input_dev->phys = ts->phys;
	input_dev->id.bustype = BUS_RS232;
	input_dev->id.vendor = SERIO_H3600;
	input_dev->id.product = 0x0666;  /* FIXME !!! We can ask the hardware */
	input_dev->id.version = 0x0100;
	input_dev->cdev.dev = &serio->dev;
	input_dev->private = ts;

	input_dev->event = h3600ts_event;

	input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_LED) | BIT(EV_PWR);
	input_dev->ledbit[0] = BIT(LED_SLEEP);
	input_set_abs_params(input_dev, ABS_X, 60, 985, 0, 0);
	input_set_abs_params(input_dev, ABS_Y, 35, 1024, 0, 0);

	set_bit(KEY_RECORD, input_dev->keybit);
	set_bit(KEY_Q, input_dev->keybit);
	set_bit(KEY_PROG1, input_dev->keybit);
	set_bit(KEY_PROG2, input_dev->keybit);
	set_bit(KEY_PROG3, input_dev->keybit);
	set_bit(KEY_UP, input_dev->keybit);
	set_bit(KEY_RIGHT, input_dev->keybit);
	set_bit(KEY_LEFT, input_dev->keybit);
	set_bit(KEY_DOWN, input_dev->keybit);
	set_bit(KEY_ENTER, input_dev->keybit);
	set_bit(KEY_SUSPEND, input_dev->keybit);
	set_bit(BTN_TOUCH, input_dev->keybit);
L
Linus Torvalds 已提交
396 397

	/* Device specific stuff */
398 399
	set_GPIO_IRQ_edge(GPIO_BITSY_ACTION_BUTTON, GPIO_BOTH_EDGES);
	set_GPIO_IRQ_edge(GPIO_BITSY_NPOWER_BUTTON, GPIO_RISING_EDGE);
L
Linus Torvalds 已提交
400

401
	if (request_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, action_button_handler,
402
			SA_SHIRQ | SA_INTERRUPT, "h3600_action", &ts->dev)) {
L
Linus Torvalds 已提交
403
		printk(KERN_ERR "h3600ts.c: Could not allocate Action Button IRQ!\n");
404 405
		err = -EBUSY;
		goto fail2;
L
Linus Torvalds 已提交
406 407
	}

408
	if (request_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, npower_button_handler,
409
			SA_SHIRQ | SA_INTERRUPT, "h3600_suspend", &ts->dev)) {
L
Linus Torvalds 已提交
410
		printk(KERN_ERR "h3600ts.c: Could not allocate Power Button IRQ!\n");
411 412
		err = -EBUSY;
		goto fail3;
L
Linus Torvalds 已提交
413 414 415 416 417
	}

	serio_set_drvdata(serio, ts);

	err = serio_open(serio, drv);
418
	if (err)
L
Linus Torvalds 已提交
419 420 421
		return err;

	//h3600_flite_control(1, 25);     /* default brightness */
422
	input_register_device(ts->dev);
L
Linus Torvalds 已提交
423 424

	return 0;
425 426 427 428 429 430 431

fail3:	free_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, ts->dev);
fail2:	free_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, ts->dev);
fail1:	serio_set_drvdata(serio, NULL);
	input_free_device(input_dev);
	kfree(ts);
	return err;
L
Linus Torvalds 已提交
432 433 434 435 436 437 438 439 440 441 442 443
}

/*
 * h3600ts_disconnect() is the opposite of h3600ts_connect()
 */

static void h3600ts_disconnect(struct serio *serio)
{
	struct h3600_dev *ts = serio_get_drvdata(serio);

	free_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, &ts->dev);
	free_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, &ts->dev);
444 445
	input_get_device(ts->dev);
	input_unregister_device(ts->dev);
L
Linus Torvalds 已提交
446 447
	serio_close(serio);
	serio_set_drvdata(serio, NULL);
448
	input_put_device(ts->dev);
L
Linus Torvalds 已提交
449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495
	kfree(ts);
}

/*
 * The serio driver structure.
 */

static struct serio_device_id h3600ts_serio_ids[] = {
	{
		.type	= SERIO_RS232,
		.proto	= SERIO_H3600,
		.id	= SERIO_ANY,
		.extra	= SERIO_ANY,
	},
	{ 0 }
};

MODULE_DEVICE_TABLE(serio, h3600ts_serio_ids);

static struct serio_driver h3600ts_drv = {
	.driver		= {
		.name	= "h3600ts",
	},
	.description	= DRIVER_DESC,
	.id_table	= h3600ts_serio_ids,
	.interrupt	= h3600ts_interrupt,
	.connect	= h3600ts_connect,
	.disconnect	= h3600ts_disconnect,
};

/*
 * The functions for inserting/removing us as a module.
 */

static int __init h3600ts_init(void)
{
	serio_register_driver(&h3600ts_drv);
	return 0;
}

static void __exit h3600ts_exit(void)
{
	serio_unregister_driver(&h3600ts_drv);
}

module_init(h3600ts_init);
module_exit(h3600ts_exit);