| /* | 
 |  * drivers/input/touchscreen/jornada720_ts.c | 
 |  * | 
 |  * Copyright (C) 2007 Kristoffer Ericson <Kristoffer.Ericson@gmail.com> | 
 |  * | 
 |  *  Copyright (C) 2006 Filip Zyzniewski <filip.zyzniewski@tefnet.pl> | 
 |  *  based on HP Jornada 56x touchscreen driver by Alex Lange <chicken@handhelds.org> | 
 |  * | 
 |  * This program 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. | 
 |  * | 
 |  * HP Jornada 710/720/729 Touchscreen Driver | 
 |  */ | 
 |  | 
 | #include <linux/platform_device.h> | 
 | #include <linux/init.h> | 
 | #include <linux/input.h> | 
 | #include <linux/interrupt.h> | 
 | #include <linux/module.h> | 
 |  | 
 | #include <asm/hardware.h> | 
 | #include <asm/arch/jornada720.h> | 
 |  | 
 | MODULE_AUTHOR("Kristoffer Ericson <kristoffer.ericson@gmail.com>"); | 
 | MODULE_DESCRIPTION("HP Jornada 710/720/728 touchscreen driver"); | 
 | MODULE_LICENSE("GPLv2"); | 
 |  | 
 | struct jornada_ts { | 
 | 	struct input_dev *dev; | 
 | 	int x_data[4];		/* X sample values */ | 
 | 	int y_data[4];		/* Y sample values */ | 
 | }; | 
 |  | 
 | static void jornada720_ts_collect_data(struct jornada_ts *jornada_ts) | 
 | { | 
 |  | 
 |     /* 3 low word X samples */ | 
 |     jornada_ts->x_data[0] = jornada_ssp_byte(TXDUMMY); | 
 |     jornada_ts->x_data[1] = jornada_ssp_byte(TXDUMMY); | 
 |     jornada_ts->x_data[2] = jornada_ssp_byte(TXDUMMY); | 
 |  | 
 |     /* 3 low word Y samples */ | 
 |     jornada_ts->y_data[0] = jornada_ssp_byte(TXDUMMY); | 
 |     jornada_ts->y_data[1] = jornada_ssp_byte(TXDUMMY); | 
 |     jornada_ts->y_data[2] = jornada_ssp_byte(TXDUMMY); | 
 |  | 
 |     /* combined x samples bits */ | 
 |     jornada_ts->x_data[3] = jornada_ssp_byte(TXDUMMY); | 
 |  | 
 |     /* combined y samples bits */ | 
 |     jornada_ts->y_data[3] = jornada_ssp_byte(TXDUMMY); | 
 | } | 
 |  | 
 | static int jornada720_ts_average(int coords[4]) | 
 | { | 
 | 	int coord, high_bits = coords[3]; | 
 |  | 
 | 	coord  = coords[0] | ((high_bits & 0x03) << 8); | 
 | 	coord += coords[1] | ((high_bits & 0x0c) << 6); | 
 | 	coord += coords[2] | ((high_bits & 0x30) << 4); | 
 |  | 
 | 	return coord / 3; | 
 | } | 
 |  | 
 | static irqreturn_t jornada720_ts_interrupt(int irq, void *dev_id) | 
 | { | 
 | 	struct platform_device *pdev = dev_id; | 
 | 	struct jornada_ts *jornada_ts = platform_get_drvdata(pdev); | 
 | 	struct input_dev *input = jornada_ts->dev; | 
 | 	int x, y; | 
 |  | 
 | 	/* If GPIO_GPIO9 is set to high then report pen up */ | 
 | 	if (GPLR & GPIO_GPIO(9)) { | 
 | 		input_report_key(input, BTN_TOUCH, 0); | 
 | 		input_sync(input); | 
 | 	} else { | 
 | 		jornada_ssp_start(); | 
 |  | 
 | 		/* proper reply to request is always TXDUMMY */ | 
 | 		if (jornada_ssp_inout(GETTOUCHSAMPLES) == TXDUMMY) { | 
 | 			jornada720_ts_collect_data(jornada_ts); | 
 |  | 
 | 			x = jornada720_ts_average(jornada_ts->x_data); | 
 | 			y = jornada720_ts_average(jornada_ts->y_data); | 
 |  | 
 | 			input_report_key(input, BTN_TOUCH, 1); | 
 | 			input_report_abs(input, ABS_X, x); | 
 | 			input_report_abs(input, ABS_Y, y); | 
 | 			input_sync(input); | 
 | 		} | 
 |  | 
 | 		jornada_ssp_end(); | 
 | 	} | 
 |  | 
 | 	return IRQ_HANDLED; | 
 | } | 
 |  | 
 | static int __devinit jornada720_ts_probe(struct platform_device *pdev) | 
 | { | 
 | 	struct jornada_ts *jornada_ts; | 
 | 	struct input_dev *input_dev; | 
 | 	int error; | 
 |  | 
 | 	jornada_ts = kzalloc(sizeof(struct jornada_ts), GFP_KERNEL); | 
 | 	input_dev = input_allocate_device(); | 
 |  | 
 | 	if (!jornada_ts || !input_dev) { | 
 | 		error = -ENOMEM; | 
 | 		goto fail1; | 
 | 	} | 
 |  | 
 | 	platform_set_drvdata(pdev, jornada_ts); | 
 |  | 
 | 	jornada_ts->dev = input_dev; | 
 |  | 
 | 	input_dev->name = "HP Jornada 7xx Touchscreen"; | 
 | 	input_dev->phys = "jornadats/input0"; | 
 | 	input_dev->id.bustype = BUS_HOST; | 
 | 	input_dev->dev.parent = &pdev->dev; | 
 |  | 
 | 	input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); | 
 | 	input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); | 
 | 	input_set_abs_params(input_dev, ABS_X, 270, 3900, 0, 0); | 
 | 	input_set_abs_params(input_dev, ABS_Y, 180, 3700, 0, 0); | 
 |  | 
 | 	error = request_irq(IRQ_GPIO9, | 
 | 			jornada720_ts_interrupt, | 
 | 			IRQF_DISABLED | IRQF_TRIGGER_RISING, | 
 | 			"HP7XX Touchscreen driver", pdev); | 
 | 	if (error) { | 
 | 		printk(KERN_INFO "HP7XX TS : Unable to acquire irq!\n"); | 
 | 		goto fail1; | 
 | 	} | 
 |  | 
 | 	error = input_register_device(jornada_ts->dev); | 
 | 	if (error) | 
 | 		goto fail2; | 
 |  | 
 | 	return 0; | 
 |  | 
 |  fail2: | 
 | 	free_irq(IRQ_GPIO9, pdev); | 
 |  fail1: | 
 | 	platform_set_drvdata(pdev, NULL); | 
 | 	input_free_device(input_dev); | 
 | 	kfree(jornada_ts); | 
 | 	return error; | 
 | } | 
 |  | 
 | static int __devexit jornada720_ts_remove(struct platform_device *pdev) | 
 | { | 
 | 	struct jornada_ts *jornada_ts = platform_get_drvdata(pdev); | 
 |  | 
 | 	free_irq(IRQ_GPIO9, pdev); | 
 | 	platform_set_drvdata(pdev, NULL); | 
 | 	input_unregister_device(jornada_ts->dev); | 
 | 	kfree(jornada_ts); | 
 |  | 
 | 	return 0; | 
 | } | 
 |  | 
 | static struct platform_driver jornada720_ts_driver = { | 
 | 	.probe		= jornada720_ts_probe, | 
 | 	.remove		= __devexit_p(jornada720_ts_remove), | 
 | 	.driver		= { | 
 | 		.name	= "jornada_ts", | 
 | 	}, | 
 | }; | 
 |  | 
 | static int __init jornada720_ts_init(void) | 
 | { | 
 | 	return platform_driver_register(&jornada720_ts_driver); | 
 | } | 
 |  | 
 | static void __exit jornada720_ts_exit(void) | 
 | { | 
 | 	platform_driver_unregister(&jornada720_ts_driver); | 
 | } | 
 |  | 
 | module_init(jornada720_ts_init); | 
 | module_exit(jornada720_ts_exit); |