15637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson/* 25637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson * drivers/input/touchscreen/jornada720_ts.c 35637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson * 45637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson * Copyright (C) 2007 Kristoffer Ericson <Kristoffer.Ericson@gmail.com> 55637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson * 65637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson * Copyright (C) 2006 Filip Zyzniewski <filip.zyzniewski@tefnet.pl> 75637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson * based on HP Jornada 56x touchscreen driver by Alex Lange <chicken@handhelds.org> 85637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson * 95637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson * This program is free software; you can redistribute it and/or modify 105637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson * it under the terms of the GNU General Public License version 2 as 115637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson * published by the Free Software Foundation. 125637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson * 135637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson * HP Jornada 710/720/729 Touchscreen Driver 145637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson */ 155637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson 165637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson#include <linux/platform_device.h> 175637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson#include <linux/init.h> 185637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson#include <linux/input.h> 195637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson#include <linux/interrupt.h> 205637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson#include <linux/module.h> 215a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 225637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson 23a09e64fbc0094e3073dbb09c3b4bfe4ab669244bRussell King#include <mach/hardware.h> 24a09e64fbc0094e3073dbb09c3b4bfe4ab669244bRussell King#include <mach/jornada720.h> 253638dd2b45ceac2e9526f0ee83b0923db3546979Rob Herring#include <mach/irqs.h> 265637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson 275637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer EricsonMODULE_AUTHOR("Kristoffer Ericson <kristoffer.ericson@gmail.com>"); 285637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer EricsonMODULE_DESCRIPTION("HP Jornada 710/720/728 touchscreen driver"); 29839cd31050096c88d929cc7c790c80cae87e2d85Al ViroMODULE_LICENSE("GPL v2"); 305637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson 315637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericsonstruct jornada_ts { 325637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson struct input_dev *dev; 335637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson int x_data[4]; /* X sample values */ 345637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson int y_data[4]; /* Y sample values */ 355637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson}; 365637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson 375637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericsonstatic void jornada720_ts_collect_data(struct jornada_ts *jornada_ts) 385637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson{ 395637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson 405637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson /* 3 low word X samples */ 415637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson jornada_ts->x_data[0] = jornada_ssp_byte(TXDUMMY); 425637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson jornada_ts->x_data[1] = jornada_ssp_byte(TXDUMMY); 435637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson jornada_ts->x_data[2] = jornada_ssp_byte(TXDUMMY); 445637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson 455637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson /* 3 low word Y samples */ 465637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson jornada_ts->y_data[0] = jornada_ssp_byte(TXDUMMY); 475637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson jornada_ts->y_data[1] = jornada_ssp_byte(TXDUMMY); 485637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson jornada_ts->y_data[2] = jornada_ssp_byte(TXDUMMY); 495637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson 505637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson /* combined x samples bits */ 515637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson jornada_ts->x_data[3] = jornada_ssp_byte(TXDUMMY); 525637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson 535637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson /* combined y samples bits */ 545637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson jornada_ts->y_data[3] = jornada_ssp_byte(TXDUMMY); 555637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson} 565637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson 575637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericsonstatic int jornada720_ts_average(int coords[4]) 585637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson{ 595637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson int coord, high_bits = coords[3]; 605637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson 615637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson coord = coords[0] | ((high_bits & 0x03) << 8); 625637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson coord += coords[1] | ((high_bits & 0x0c) << 6); 635637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson coord += coords[2] | ((high_bits & 0x30) << 4); 645637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson 655637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson return coord / 3; 665637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson} 675637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson 685637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericsonstatic irqreturn_t jornada720_ts_interrupt(int irq, void *dev_id) 695637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson{ 705637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson struct platform_device *pdev = dev_id; 715637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson struct jornada_ts *jornada_ts = platform_get_drvdata(pdev); 725637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson struct input_dev *input = jornada_ts->dev; 735637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson int x, y; 745637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson 755637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson /* If GPIO_GPIO9 is set to high then report pen up */ 765637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson if (GPLR & GPIO_GPIO(9)) { 775637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson input_report_key(input, BTN_TOUCH, 0); 785637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson input_sync(input); 795637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson } else { 805637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson jornada_ssp_start(); 815637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson 825637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson /* proper reply to request is always TXDUMMY */ 835637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson if (jornada_ssp_inout(GETTOUCHSAMPLES) == TXDUMMY) { 845637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson jornada720_ts_collect_data(jornada_ts); 855637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson 865637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson x = jornada720_ts_average(jornada_ts->x_data); 875637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson y = jornada720_ts_average(jornada_ts->y_data); 885637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson 895637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson input_report_key(input, BTN_TOUCH, 1); 905637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson input_report_abs(input, ABS_X, x); 915637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson input_report_abs(input, ABS_Y, y); 925637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson input_sync(input); 935637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson } 945637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson 955637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson jornada_ssp_end(); 965637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson } 975637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson 985637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson return IRQ_HANDLED; 995637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson} 1005637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson 1015637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericsonstatic int __devinit jornada720_ts_probe(struct platform_device *pdev) 1025637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson{ 1035637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson struct jornada_ts *jornada_ts; 1045637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson struct input_dev *input_dev; 1055637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson int error; 1065637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson 1075637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson jornada_ts = kzalloc(sizeof(struct jornada_ts), GFP_KERNEL); 1085637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson input_dev = input_allocate_device(); 1095637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson 1105637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson if (!jornada_ts || !input_dev) { 1115637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson error = -ENOMEM; 1125637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson goto fail1; 1135637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson } 1145637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson 1155637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson platform_set_drvdata(pdev, jornada_ts); 1165637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson 1175637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson jornada_ts->dev = input_dev; 1185637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson 1195637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson input_dev->name = "HP Jornada 7xx Touchscreen"; 1205637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson input_dev->phys = "jornadats/input0"; 1215637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson input_dev->id.bustype = BUS_HOST; 1225637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson input_dev->dev.parent = &pdev->dev; 1235637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson 1241577e4b70a04cce39f296cc714da5ad5d272105aKristoffer Ericson input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); 1251577e4b70a04cce39f296cc714da5ad5d272105aKristoffer Ericson input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); 1265637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson input_set_abs_params(input_dev, ABS_X, 270, 3900, 0, 0); 1275637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson input_set_abs_params(input_dev, ABS_Y, 180, 3700, 0, 0); 1285637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson 1295637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson error = request_irq(IRQ_GPIO9, 1305637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson jornada720_ts_interrupt, 131ec4665c46b11f6e444911ba73dddae6044dec909Yong Zhang IRQF_TRIGGER_RISING, 1325637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson "HP7XX Touchscreen driver", pdev); 1335637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson if (error) { 1345637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson printk(KERN_INFO "HP7XX TS : Unable to acquire irq!\n"); 1355637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson goto fail1; 1365637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson } 1375637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson 1385637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson error = input_register_device(jornada_ts->dev); 1395637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson if (error) 1405637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson goto fail2; 1415637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson 1425637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson return 0; 1435637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson 1445637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson fail2: 1455637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson free_irq(IRQ_GPIO9, pdev); 1465637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson fail1: 1475637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson platform_set_drvdata(pdev, NULL); 1485637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson input_free_device(input_dev); 1495637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson kfree(jornada_ts); 1505637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson return error; 1515637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson} 1525637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson 1535637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericsonstatic int __devexit jornada720_ts_remove(struct platform_device *pdev) 1545637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson{ 1555637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson struct jornada_ts *jornada_ts = platform_get_drvdata(pdev); 1565637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson 1575637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson free_irq(IRQ_GPIO9, pdev); 1585637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson platform_set_drvdata(pdev, NULL); 1595637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson input_unregister_device(jornada_ts->dev); 1605637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson kfree(jornada_ts); 1615637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson 1625637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson return 0; 1635637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson} 1645637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson 165d7b5247bbcfba2bc96d4b3dec9086a4f1a31363bKay Sievers/* work with hotplug and coldplug */ 166d7b5247bbcfba2bc96d4b3dec9086a4f1a31363bKay SieversMODULE_ALIAS("platform:jornada_ts"); 167d7b5247bbcfba2bc96d4b3dec9086a4f1a31363bKay Sievers 1685637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericsonstatic struct platform_driver jornada720_ts_driver = { 1695637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson .probe = jornada720_ts_probe, 1705637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson .remove = __devexit_p(jornada720_ts_remove), 1715637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson .driver = { 1725637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson .name = "jornada_ts", 173d7b5247bbcfba2bc96d4b3dec9086a4f1a31363bKay Sievers .owner = THIS_MODULE, 1745637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson }, 1755637f02a9cf84f2c00fd8a0f6561c375bb19103bKristoffer Ericson}; 176cdcc96e261909eccf596c070116c8b906a42b328JJ Dingmodule_platform_driver(jornada720_ts_driver); 177