From b2ef9ead3ce43bf2a6645e1a1c464b366da07e8c Mon Sep 17 00:00:00 2001 From: Gary King Date: Thu, 10 Dec 2009 18:35:29 -0800 Subject: touchscreen: add a touchscreen input device driver for Tegra ODM kit adds a touchscreen input device driver using the NVIDIA Tegra's ODM kit adaptation interface for touchscreen controllers --- drivers/input/touchscreen/Kconfig | 8 + drivers/input/touchscreen/Makefile | 1 + drivers/input/touchscreen/tegra_odm.c | 327 ++++++++++++++++++++++++++++++++++ 3 files changed, 336 insertions(+) create mode 100755 drivers/input/touchscreen/tegra_odm.c (limited to 'drivers') diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index e170fea387f2..e4928aabadd1 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -212,6 +212,14 @@ config TOUCHSCREEN_SYNAPTICS_I2C_RMI help This enables support for Synaptics RMI over I2C based touchscreens. +config TOUCHSCREEN_TEGRA_ODM + boolean "NVIDIA Tegra ODM-kit based touchscreen driver" + depends on ARCH_TEGRA && MACH_TEGRA_GENERIC + default n + help + Adds a touchscreen input device for drivers written using NVIDIA's + Tegra ODM kit interface + config TOUCHSCREEN_TOUCHRIGHT tristate "Touchright serial touchscreen" select SERIO diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index ce3a1a2577d5..ed4090d84b31 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -23,6 +23,7 @@ obj-$(CONFIG_TOUCHSCREEN_HTCPEN) += htcpen.o obj-$(CONFIG_TOUCHSCREEN_USB_COMPOSITE) += usbtouchscreen.o obj-$(CONFIG_TOUCHSCREEN_PENMOUNT) += penmount.o obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI) += synaptics_i2c_rmi.o +obj-$(CONFIG_TOUCHSCREEN_TEGRA_ODM) += tegra_odm.o obj-$(CONFIG_TOUCHSCREEN_TOUCHIT213) += touchit213.o obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT) += touchright.o obj-$(CONFIG_TOUCHSCREEN_TOUCHWIN) += touchwin.o diff --git a/drivers/input/touchscreen/tegra_odm.c b/drivers/input/touchscreen/tegra_odm.c new file mode 100755 index 000000000000..bd0d1a71ebad --- /dev/null +++ b/drivers/input/touchscreen/tegra_odm.c @@ -0,0 +1,327 @@ +/* + * drivers/input/touchscreen/tegra_odm.c + * + * Touchscreen class input driver for platforms using NVIDIA's Tegra ODM kit + * driver interface + * + * Copyright (c) 2009, NVIDIA Corporation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include +#include +#include +#include +#include + +#include +#include + +struct tegra_touch_driver_data +{ + struct input_dev *input_dev; + struct task_struct *task; + NvOdmOsSemaphoreHandle semaphore; + NvOdmTouchDeviceHandle hTouchDevice; + NvBool bPollingMode; + NvU32 pollingIntervalMS; + NvOdmTouchCapabilities caps; + NvU32 MaxX; + NvU32 MinX; + NvU32 MaxY; + NvU32 MinY; +}; + +#define NVODM_TOUCH_NAME "nvodm_touch" + +#define swapv(x, y) do { typeof(x) z = x; x = y; y = z; } while (0) + +static int tegra_touch_thread(void *pdata) +{ + struct tegra_touch_driver_data *touch = + (struct tegra_touch_driver_data*)pdata; + NvOdmTouchCoordinateInfo c = {0}; + NvU32 x[2] = {0}, y[2] = {0}, i = 0; + NvBool bKeepReadingSamples; + NvU32 fingers = 0; + NvBool ToolDown[2] = {NV_FALSE, NV_FALSE}; + NvOdmTouchCapabilities *caps = &touch->caps; + NvU32 max_fingers = caps->MaxNumberOfFingerCoordReported; + + for (;;) { + if (touch->bPollingMode) + msleep(touch->pollingIntervalMS); + else + NvOdmOsSemaphoreWait(touch->semaphore); + + bKeepReadingSamples = NV_TRUE; + while (bKeepReadingSamples) { + if (!NvOdmTouchReadCoordinate(touch->hTouchDevice, &c)){ + pr_err("Couldn't read touch sample\n"); + bKeepReadingSamples = NV_FALSE; + continue; + } + + if (c.fingerstate & NvOdmTouchSampleIgnore) + goto DoneWithSample; + + fingers = c.additionalInfo.Fingers; + + switch (fingers) { + case 0: + for (i=0; iOrientation & NvOdmTouchOrientation_V_FLIP) { + y[0] = caps->YMaxPosition + + caps->YMinPosition - y[0]; + y[1] = caps->YMaxPosition + + caps->YMinPosition - y[1]; + } + if (caps->Orientation & NvOdmTouchOrientation_H_FLIP) { + x[0] = caps->XMaxPosition + + caps->XMinPosition - x[0]; + x[1] = caps->XMaxPosition + + caps->XMinPosition - x[1]; + } + + if (caps->Orientation & NvOdmTouchOrientation_XY_SWAP) { + for (i = 0; i < max_fingers; i++) + swapv(x[i],y[i]); + } + + if (c.fingerstate & NvOdmTouchSampleValidFlag) { + input_report_abs(touch->input_dev, ABS_X, x[0]); + input_report_abs(touch->input_dev, ABS_Y, y[0]); + } + + if (caps->IsPressureSupported) { + input_report_abs(touch->input_dev, + ABS_PRESSURE, + c.additionalInfo.Pressure[0]); + } + if (caps->IsWidthSupported) { + input_report_abs(touch->input_dev, + ABS_TOOL_WIDTH, + c.additionalInfo.width[0]); + } + + /* Report down or up flag */ + input_report_key(touch->input_dev, + BTN_TOUCH, ToolDown[0]); + + // report co-ordinates for the 2nd finger + if (fingers == 2) { + input_report_abs(touch->input_dev, + ABS_HAT0X, x[1]); // x + input_report_abs(touch->input_dev, + ABS_HAT0Y, y[1]); // y + input_report_key(touch->input_dev, + BTN_2, ToolDown[1]); + } + input_sync(touch->input_dev); + +DoneWithSample: + bKeepReadingSamples = NV_FALSE; + if (!touch->bPollingMode && + !NvOdmTouchHandleInterrupt(touch->hTouchDevice)) { + /* Some more data to read keep going */ + bKeepReadingSamples = NV_TRUE; + } + } + } + + return 0; +} + +static int __init tegra_touch_probe(struct platform_device *pdev) +{ + struct tegra_touch_driver_data *touch = NULL; + struct input_dev *input_dev = NULL; + int err; + NvOdmTouchCapabilities *caps; + + touch = kzalloc(sizeof(struct tegra_touch_driver_data), GFP_KERNEL); + input_dev = input_allocate_device(); + if (input_dev == NULL || touch == NULL) { + input_free_device(input_dev); + kfree(touch); + err = -ENOMEM; + pr_err("tegra_touch_probe: Failed to allocate input device\n"); + return err; + } + touch->semaphore = NvOdmOsSemaphoreCreate(0); + if (!touch->semaphore) { + err = -1; + pr_err("tegra_touch_probe: Semaphore creation failed\n"); + goto err_semaphore_create_failed; + } + + if (!NvOdmTouchDeviceOpen(&touch->hTouchDevice)) { + err = -1; + pr_err("tegra_touch_probe: NvOdmTouchDeviceOpen failed\n"); + goto err_open_failed; + } + touch->bPollingMode = NV_FALSE; + if (!NvOdmTouchEnableInterrupt(touch->hTouchDevice, touch->semaphore)) { + err = -1; + pr_err("tegra_touch_probe: Interrupt failed, polling mode\n"); + touch->bPollingMode = NV_TRUE; + touch->pollingIntervalMS = 10; + } + + touch->task = + kthread_create(tegra_touch_thread, touch, "tegra_touch_thread"); + + if(touch->task == NULL) { + err = -1; + goto err_kthread_create_failed; + } + wake_up_process( touch->task ); + + touch->input_dev = input_dev; + touch->input_dev->name = NVODM_TOUCH_NAME; + + /* Will generate sync at the end of all input */ + set_bit(EV_SYN, touch->input_dev->evbit); + + /* Event is key input type */ + set_bit(EV_KEY, touch->input_dev->evbit); + /* virtual key is BTN_TOUCH */ + set_bit(BTN_TOUCH, touch->input_dev->keybit); + /* Input values are in absoulte values */ + set_bit(EV_ABS, touch->input_dev->evbit); + + NvOdmTouchDeviceGetCapabilities(touch->hTouchDevice, &touch->caps); + + caps = &touch->caps; + + if (caps->Orientation & NvOdmTouchOrientation_XY_SWAP) { + touch->MaxY = caps->XMaxPosition; + touch->MinY = caps->XMinPosition; + touch->MaxX = caps->YMaxPosition; + touch->MinX = caps->YMinPosition; + + } else { + touch->MaxX = caps->XMaxPosition; + touch->MinX = caps->XMinPosition; + touch->MaxY = caps->YMaxPosition; + touch->MinY = caps->YMinPosition; + } + + input_set_abs_params(touch->input_dev, ABS_X, touch->MinX, + touch->MaxX, 0, 0); + input_set_abs_params(touch->input_dev, ABS_Y, touch->MinY, + touch->MaxY, 0, 0); + input_set_abs_params(touch->input_dev, ABS_HAT0X, touch->MinX, + touch->MaxX, 0, 0); + input_set_abs_params(touch->input_dev, ABS_HAT0Y, touch->MinY, + touch->MaxY, 0, 0); + + if (caps->IsPressureSupported) + input_set_abs_params(touch->input_dev, ABS_PRESSURE, 0, + caps->MaxNumberOfPressureReported, 0, 0); + if (caps->IsWidthSupported) + input_set_abs_params(touch->input_dev, ABS_TOOL_WIDTH, 0, + caps->MaxNumberOfWidthReported, 0, 0); + + platform_set_drvdata(pdev, touch); + + err = input_register_device(input_dev); + if (err) + { + pr_err("tegra_touch_probe: Unable to register input device\n"); + goto err_input_register_device_failed; + } + + printk(KERN_INFO NVODM_TOUCH_NAME + ": Successfully registered the ODM touch driver\n"); + return 0; + +err_input_register_device_failed: + NvOdmTouchDeviceClose(touch->hTouchDevice); +err_kthread_create_failed: + /* FIXME How to destroy the thread? Maybe we should use workqueues? */ +err_open_failed: + NvOdmOsSemaphoreDestroy(touch->semaphore); +err_semaphore_create_failed: + kfree(touch); + input_free_device(input_dev); + return err; +} + +static int tegra_touch_remove(struct platform_device *pdev) +{ + struct tegra_touch_driver_data *touch = platform_get_drvdata(pdev); + + /* FIXME How to destroy the thread? Maybe we should use workqueues? */ + input_unregister_device(touch->input_dev); + /* NvOsSemaphoreDestroy(touch->semaphore); */ + input_unregister_device(touch->input_dev); + kfree(touch); + return 0; +} + +static struct platform_driver tegra_touch_driver = { + .probe = tegra_touch_probe, + .remove = tegra_touch_remove, + .driver = { + .name = "tegra_touch", + }, +}; + +static int __devinit tegra_touch_init(void) +{ + return platform_driver_register(&tegra_touch_driver); +} + +static void __exit tegra_touch_exit(void) +{ + platform_driver_unregister(&tegra_touch_driver); +} + +module_init(tegra_touch_init); +module_exit(tegra_touch_exit); + +MODULE_DESCRIPTION("Tegra ODM touch driver"); + -- cgit v1.2.3