From fccdd7c4aeb7ed639b51126941545bc5b3824dab Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 20 Jan 2011 22:47:47 -0800 Subject: Input: ad7877 - convert to dev_pm_ops There is a move to deprecate bus-specific PM operations and move to using dev_pm_ops instead in order to reduce the amount of boilerplate code in buses and facilitate updates to the PM core. Do this move for the ad7879 SPI driver. Signed-off-by: Mark Brown Acked-by: Michael Hennerich Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/ad7877.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/ad7877.c b/drivers/input/touchscreen/ad7877.c index a1952fcc083e..714d4e0f9f95 100644 --- a/drivers/input/touchscreen/ad7877.c +++ b/drivers/input/touchscreen/ad7877.c @@ -41,6 +41,7 @@ #include #include #include +#include #include #include #include @@ -826,39 +827,37 @@ static int __devexit ad7877_remove(struct spi_device *spi) return 0; } -#ifdef CONFIG_PM -static int ad7877_suspend(struct spi_device *spi, pm_message_t message) +#ifdef CONFIG_PM_SLEEP +static int ad7877_suspend(struct device *dev) { - struct ad7877 *ts = dev_get_drvdata(&spi->dev); + struct ad7877 *ts = dev_get_drvdata(dev); ad7877_disable(ts); return 0; } -static int ad7877_resume(struct spi_device *spi) +static int ad7877_resume(struct device *dev) { - struct ad7877 *ts = dev_get_drvdata(&spi->dev); + struct ad7877 *ts = dev_get_drvdata(dev); ad7877_enable(ts); return 0; } -#else -#define ad7877_suspend NULL -#define ad7877_resume NULL #endif +static SIMPLE_DEV_PM_OPS(ad7877_pm, ad7877_suspend, ad7877_resume); + static struct spi_driver ad7877_driver = { .driver = { .name = "ad7877", .bus = &spi_bus_type, .owner = THIS_MODULE, + .pm = &ad7877_pm, }, .probe = ad7877_probe, .remove = __devexit_p(ad7877_remove), - .suspend = ad7877_suspend, - .resume = ad7877_resume, }; static int __init ad7877_init(void) -- cgit v1.2.3 From c7848c8e1a26ca6075d6cb538657f5381afcadc4 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 20 Jan 2011 22:48:44 -0800 Subject: Input: ad7879 - convert SPI to dev_pm_ops There is a move to deprecate bus-specific PM operations and move to using dev_pm_ops instead in order to reduce the amount of boilerplate code in buses and facilitate updates to the PM core. Do this move for the ad7879 SPI driver. Signed-off-by: Mark Brown Acked-by: Michael Hennerich Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/ad7879-spi.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/ad7879-spi.c b/drivers/input/touchscreen/ad7879-spi.c index 59c6e68c4325..ddf732f3cafc 100644 --- a/drivers/input/touchscreen/ad7879-spi.c +++ b/drivers/input/touchscreen/ad7879-spi.c @@ -7,6 +7,7 @@ */ #include /* BUS_SPI */ +#include #include #include "ad7879.h" @@ -20,9 +21,10 @@ #define AD7879_WRITECMD(reg) (AD7879_CMD(reg)) #define AD7879_READCMD(reg) (AD7879_CMD(reg) | AD7879_CMD_READ) -#ifdef CONFIG_PM -static int ad7879_spi_suspend(struct spi_device *spi, pm_message_t message) +#ifdef CONFIG_PM_SLEEP +static int ad7879_spi_suspend(struct device *dev) { + struct spi_device *spi = to_spi_device(dev); struct ad7879 *ts = spi_get_drvdata(spi); ad7879_suspend(ts); @@ -30,19 +32,19 @@ static int ad7879_spi_suspend(struct spi_device *spi, pm_message_t message) return 0; } -static int ad7879_spi_resume(struct spi_device *spi) +static int ad7879_spi_resume(struct device *dev) { + struct spi_device *spi = to_spi_device(dev); struct ad7879 *ts = spi_get_drvdata(spi); ad7879_resume(ts); return 0; } -#else -# define ad7879_spi_suspend NULL -# define ad7879_spi_resume NULL #endif +static SIMPLE_DEV_PM_OPS(ad7879_spi_pm, ad7879_spi_suspend, ad7879_spi_resume); + /* * ad7879_read/write are only used for initial setup and for sysfs controls. * The main traffic is done in ad7879_collect(). @@ -173,11 +175,10 @@ static struct spi_driver ad7879_spi_driver = { .name = "ad7879", .bus = &spi_bus_type, .owner = THIS_MODULE, + .pm = &ad7879_spi_pm, }, .probe = ad7879_spi_probe, .remove = __devexit_p(ad7879_spi_remove), - .suspend = ad7879_spi_suspend, - .resume = ad7879_spi_resume, }; static int __init ad7879_spi_init(void) -- cgit v1.2.3 From 3c36e719033ddc09aded770472cbdb477fcb4479 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 20 Jan 2011 22:51:26 -0800 Subject: Input: ads7846 - convert to dev_pm_ops There is a move to deprecate bus-specific PM operations and move to using dev_pm_ops instead in order to reduce the amount of boilerplate code in buses and facilitate updates to the PM core. Do this move for the ads7846 driver. Signed-off-by: Mark Brown Acked-by: Michael Hennerich Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/ads7846.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c index 14ea54b78e46..b31e90f0d44b 100644 --- a/drivers/input/touchscreen/ads7846.c +++ b/drivers/input/touchscreen/ads7846.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -892,9 +893,10 @@ static irqreturn_t ads7846_irq(int irq, void *handle) return IRQ_HANDLED; } -static int ads7846_suspend(struct spi_device *spi, pm_message_t message) +#ifdef CONFIG_PM_SLEEP +static int ads7846_suspend(struct device *dev) { - struct ads7846 *ts = dev_get_drvdata(&spi->dev); + struct ads7846 *ts = dev_get_drvdata(dev); mutex_lock(&ts->lock); @@ -914,9 +916,9 @@ static int ads7846_suspend(struct spi_device *spi, pm_message_t message) return 0; } -static int ads7846_resume(struct spi_device *spi) +static int ads7846_resume(struct device *dev) { - struct ads7846 *ts = dev_get_drvdata(&spi->dev); + struct ads7846 *ts = dev_get_drvdata(dev); mutex_lock(&ts->lock); @@ -935,6 +937,9 @@ static int ads7846_resume(struct spi_device *spi) return 0; } +#endif + +static SIMPLE_DEV_PM_OPS(ads7846_pm, ads7846_suspend, ads7846_resume); static int __devinit ads7846_setup_pendown(struct spi_device *spi, struct ads7846 *ts) { @@ -1402,11 +1407,10 @@ static struct spi_driver ads7846_driver = { .name = "ads7846", .bus = &spi_bus_type, .owner = THIS_MODULE, + .pm = &ads7846_pm, }, .probe = ads7846_probe, .remove = __devexit_p(ads7846_remove), - .suspend = ads7846_suspend, - .resume = ads7846_resume, }; static int __init ads7846_init(void) -- cgit v1.2.3 From 00cfa730db0d8378685148e6365b9cec7384b275 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sun, 30 Jan 2011 12:31:30 -0800 Subject: Input: wm831x - add driver for Wolfson WM831x PMIC touchscreen controllers Some of the WM831x series of PMICs from Wolfson Microelectronics include a resistive touchscreen controller. Implement support for these controllers within the input API. Platform data is supported to allow configuration of system parameters such as selection between four and five wire touchscreens and for specification of optional direct to CPU IRQs for sample availability and for pen down. Use of this feature for at least the data IRQ is strongly recommended. Thanks to Julien Boibessot for extensive testing and detailed feedback. Signed-off-by: Mark Brown Tested-by: Julien Boibessot Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/Kconfig | 10 + drivers/input/touchscreen/Makefile | 1 + drivers/input/touchscreen/wm831x-ts.c | 355 ++++++++++++++++++++++++++++++++++ 3 files changed, 366 insertions(+) create mode 100644 drivers/input/touchscreen/wm831x-ts.c (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 07ac77d393a4..ec5ee98fa6f6 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -423,6 +423,16 @@ config TOUCHSCREEN_UCB1400 To compile this driver as a module, choose M here: the module will be called ucb1400_ts. +config TOUCHSCREEN_WM831X + tristate "Support for WM831x touchscreen controllers" + depends on MFD_WM831X + help + This enables support for the touchscreen controller on the WM831x + series of PMICs. + + To compile this driver as a module, choose M here: the + module will be called wm831x-ts. + config TOUCHSCREEN_WM97XX tristate "Support for WM97xx AC97 touchscreen controllers" depends on AC97_BUS diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index 718bcc814952..e8dcfab7c2dc 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -48,6 +48,7 @@ obj-$(CONFIG_TOUCHSCREEN_TOUCHWIN) += touchwin.o obj-$(CONFIG_TOUCHSCREEN_TSC2007) += tsc2007.o obj-$(CONFIG_TOUCHSCREEN_UCB1400) += ucb1400_ts.o obj-$(CONFIG_TOUCHSCREEN_WACOM_W8001) += wacom_w8001.o +obj-$(CONFIG_TOUCHSCREEN_WM831X) += wm831x-ts.o obj-$(CONFIG_TOUCHSCREEN_WM97XX) += wm97xx-ts.o wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9705) += wm9705.o wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9712) += wm9712.o diff --git a/drivers/input/touchscreen/wm831x-ts.c b/drivers/input/touchscreen/wm831x-ts.c new file mode 100644 index 000000000000..a6121bdb635d --- /dev/null +++ b/drivers/input/touchscreen/wm831x-ts.c @@ -0,0 +1,355 @@ +/* + * Touchscreen driver for WM831x PMICs + * + * Copyright 2011 Wolfson Microelectronics plc. + * Author: Mark Brown + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * R16424 (0x4028) - Touch Control 1 + */ +#define WM831X_TCH_ENA 0x8000 /* TCH_ENA */ +#define WM831X_TCH_CVT_ENA 0x4000 /* TCH_CVT_ENA */ +#define WM831X_TCH_SLPENA 0x1000 /* TCH_SLPENA */ +#define WM831X_TCH_Z_ENA 0x0400 /* TCH_Z_ENA */ +#define WM831X_TCH_Y_ENA 0x0200 /* TCH_Y_ENA */ +#define WM831X_TCH_X_ENA 0x0100 /* TCH_X_ENA */ +#define WM831X_TCH_DELAY_MASK 0x00E0 /* TCH_DELAY - [7:5] */ +#define WM831X_TCH_DELAY_SHIFT 5 /* TCH_DELAY - [7:5] */ +#define WM831X_TCH_DELAY_WIDTH 3 /* TCH_DELAY - [7:5] */ +#define WM831X_TCH_RATE_MASK 0x001F /* TCH_RATE - [4:0] */ +#define WM831X_TCH_RATE_SHIFT 0 /* TCH_RATE - [4:0] */ +#define WM831X_TCH_RATE_WIDTH 5 /* TCH_RATE - [4:0] */ + +/* + * R16425 (0x4029) - Touch Control 2 + */ +#define WM831X_TCH_PD_WK 0x2000 /* TCH_PD_WK */ +#define WM831X_TCH_5WIRE 0x1000 /* TCH_5WIRE */ +#define WM831X_TCH_PDONLY 0x0800 /* TCH_PDONLY */ +#define WM831X_TCH_ISEL 0x0100 /* TCH_ISEL */ +#define WM831X_TCH_RPU_MASK 0x000F /* TCH_RPU - [3:0] */ +#define WM831X_TCH_RPU_SHIFT 0 /* TCH_RPU - [3:0] */ +#define WM831X_TCH_RPU_WIDTH 4 /* TCH_RPU - [3:0] */ + +/* + * R16426-8 (0x402A-C) - Touch Data X/Y/X + */ +#define WM831X_TCH_PD 0x8000 /* TCH_PD1 */ +#define WM831X_TCH_DATA_MASK 0x0FFF /* TCH_DATA - [11:0] */ +#define WM831X_TCH_DATA_SHIFT 0 /* TCH_DATA - [11:0] */ +#define WM831X_TCH_DATA_WIDTH 12 /* TCH_DATA - [11:0] */ + +struct wm831x_ts { + struct input_dev *input_dev; + struct wm831x *wm831x; + unsigned int data_irq; + unsigned int pd_irq; + bool pressure; + bool pen_down; +}; + +static irqreturn_t wm831x_ts_data_irq(int irq, void *irq_data) +{ + struct wm831x_ts *wm831x_ts = irq_data; + struct wm831x *wm831x = wm831x_ts->wm831x; + static int data_types[] = { ABS_X, ABS_Y, ABS_PRESSURE }; + u16 data[3]; + int count = wm831x_ts->pressure ? 3 : 2; + int i, ret; + + wm831x_set_bits(wm831x, WM831X_INTERRUPT_STATUS_1, + WM831X_TCHDATA_EINT, WM831X_TCHDATA_EINT); + + ret = wm831x_bulk_read(wm831x, WM831X_TOUCH_DATA_X, count, + data); + if (ret != 0) { + dev_err(wm831x->dev, "Failed to read touch data: %d\n", + ret); + return IRQ_NONE; + } + + /* + * We get a pen down reading on every reading, report pen up if any + * individual reading does so. + */ + wm831x_ts->pen_down = true; + for (i = 0; i < count; i++) { + if (!(data[i] & WM831X_TCH_PD)) { + wm831x_ts->pen_down = false; + continue; + } + input_report_abs(wm831x_ts->input_dev, data_types[i], + data[i] & WM831X_TCH_DATA_MASK); + } + + if (!wm831x_ts->pen_down) { + disable_irq_nosync(wm831x_ts->data_irq); + + /* Don't need data any more */ + wm831x_set_bits(wm831x, WM831X_TOUCH_CONTROL_1, + WM831X_TCH_X_ENA | WM831X_TCH_Y_ENA | + WM831X_TCH_Z_ENA, 0); + + /* Flush any final samples that arrived while reading */ + wm831x_set_bits(wm831x, WM831X_INTERRUPT_STATUS_1, + WM831X_TCHDATA_EINT, WM831X_TCHDATA_EINT); + + wm831x_bulk_read(wm831x, WM831X_TOUCH_DATA_X, count, data); + + if (wm831x_ts->pressure) + input_report_abs(wm831x_ts->input_dev, + ABS_PRESSURE, 0); + + input_report_key(wm831x_ts->input_dev, BTN_TOUCH, 0); + } + + input_sync(wm831x_ts->input_dev); + + return IRQ_HANDLED; +} + +static irqreturn_t wm831x_ts_pen_down_irq(int irq, void *irq_data) +{ + struct wm831x_ts *wm831x_ts = irq_data; + struct wm831x *wm831x = wm831x_ts->wm831x; + int ena; + + /* Start collecting data */ + ena = wm831x_ts->pressure ? WM831X_TCH_Z_ENA : 0; + + wm831x_set_bits(wm831x, WM831X_TOUCH_CONTROL_1, + WM831X_TCH_X_ENA | WM831X_TCH_Y_ENA | WM831X_TCH_Z_ENA, + WM831X_TCH_X_ENA | WM831X_TCH_Y_ENA | ena); + + input_report_key(wm831x_ts->input_dev, BTN_TOUCH, 1); + input_sync(wm831x_ts->input_dev); + + wm831x_set_bits(wm831x, WM831X_INTERRUPT_STATUS_1, + WM831X_TCHPD_EINT, WM831X_TCHPD_EINT); + + wm831x_ts->pen_down = true; + enable_irq(wm831x_ts->data_irq); + + return IRQ_HANDLED; +} + +static int wm831x_ts_input_open(struct input_dev *idev) +{ + struct wm831x_ts *wm831x_ts = input_get_drvdata(idev); + struct wm831x *wm831x = wm831x_ts->wm831x; + + wm831x_set_bits(wm831x, WM831X_TOUCH_CONTROL_1, + WM831X_TCH_ENA, WM831X_TCH_ENA); + + wm831x_set_bits(wm831x, WM831X_TOUCH_CONTROL_1, + WM831X_TCH_CVT_ENA, WM831X_TCH_CVT_ENA); + + return 0; +} + +static void wm831x_ts_input_close(struct input_dev *idev) +{ + struct wm831x_ts *wm831x_ts = input_get_drvdata(idev); + struct wm831x *wm831x = wm831x_ts->wm831x; + + wm831x_set_bits(wm831x, WM831X_TOUCH_CONTROL_1, + WM831X_TCH_ENA | WM831X_TCH_CVT_ENA | + WM831X_TCH_X_ENA | WM831X_TCH_Y_ENA | + WM831X_TCH_Z_ENA, 0); + + if (wm831x_ts->pen_down) + disable_irq(wm831x_ts->data_irq); +} + +static __devinit int wm831x_ts_probe(struct platform_device *pdev) +{ + struct wm831x_ts *wm831x_ts; + struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent); + struct wm831x_pdata *core_pdata = dev_get_platdata(pdev->dev.parent); + struct wm831x_touch_pdata *pdata = + core_pdata ? core_pdata->touch : NULL; + struct input_dev *input_dev; + int error; + + wm831x_ts = kzalloc(sizeof(struct wm831x_ts), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!wm831x_ts || !input_dev) { + error = -ENOMEM; + goto err_alloc; + } + + wm831x_ts->wm831x = wm831x; + wm831x_ts->input_dev = input_dev; + + /* + * If we have a direct IRQ use it, otherwise use the interrupt + * from the WM831x IRQ controller. + */ + if (pdata && pdata->data_irq) + wm831x_ts->data_irq = pdata->data_irq; + else + wm831x_ts->data_irq = platform_get_irq_byname(pdev, "TCHDATA"); + + if (pdata && pdata->pd_irq) + wm831x_ts->pd_irq = pdata->pd_irq; + else + wm831x_ts->pd_irq = platform_get_irq_byname(pdev, "TCHPD"); + + wm831x_ts->pressure = pdata && pdata->pressure; + + /* Five wire touchscreens can't report pressure */ + if (pdata && pdata->fivewire) { + wm831x_set_bits(wm831x, WM831X_TOUCH_CONTROL_2, + WM831X_TCH_5WIRE, WM831X_TCH_5WIRE); + + /* Pressure measurements are not possible for five wire mode */ + WARN_ON(pdata->pressure && pdata->fivewire); + wm831x_ts->pressure = false; + } else { + wm831x_set_bits(wm831x, WM831X_TOUCH_CONTROL_2, + WM831X_TCH_5WIRE, 0); + } + + if (pdata) { + switch (pdata->isel) { + default: + dev_err(&pdev->dev, "Unsupported ISEL setting: %d\n", + pdata->isel); + /* Fall through */ + case 200: + case 0: + wm831x_set_bits(wm831x, WM831X_TOUCH_CONTROL_2, + WM831X_TCH_ISEL, 0); + break; + case 400: + wm831x_set_bits(wm831x, WM831X_TOUCH_CONTROL_2, + WM831X_TCH_ISEL, WM831X_TCH_ISEL); + break; + } + } + + wm831x_set_bits(wm831x, WM831X_TOUCH_CONTROL_2, + WM831X_TCH_PDONLY, 0); + + /* Default to 96 samples/sec */ + wm831x_set_bits(wm831x, WM831X_TOUCH_CONTROL_1, + WM831X_TCH_RATE_MASK, 6); + + error = request_threaded_irq(wm831x_ts->data_irq, + NULL, wm831x_ts_data_irq, + IRQF_ONESHOT, + "Touchscreen data", wm831x_ts); + if (error) { + dev_err(&pdev->dev, "Failed to request data IRQ %d: %d\n", + wm831x_ts->data_irq, error); + goto err_alloc; + } + disable_irq(wm831x_ts->data_irq); + + error = request_threaded_irq(wm831x_ts->pd_irq, + NULL, wm831x_ts_pen_down_irq, + IRQF_ONESHOT, + "Touchscreen pen down", wm831x_ts); + if (error) { + dev_err(&pdev->dev, "Failed to request pen down IRQ %d: %d\n", + wm831x_ts->pd_irq, error); + goto err_data_irq; + } + + /* set up touch configuration */ + input_dev->name = "WM831x touchscreen"; + input_dev->phys = "wm831x"; + input_dev->open = wm831x_ts_input_open; + input_dev->close = wm831x_ts_input_close; + + __set_bit(EV_ABS, input_dev->evbit); + __set_bit(EV_KEY, input_dev->evbit); + __set_bit(BTN_TOUCH, input_dev->keybit); + + input_set_abs_params(input_dev, ABS_X, 0, 4095, 5, 0); + input_set_abs_params(input_dev, ABS_Y, 0, 4095, 5, 0); + if (wm831x_ts->pressure) + input_set_abs_params(input_dev, ABS_PRESSURE, 0, 4095, 5, 0); + + input_set_drvdata(input_dev, wm831x_ts); + input_dev->dev.parent = &pdev->dev; + + error = input_register_device(input_dev); + if (error) + goto err_pd_irq; + + platform_set_drvdata(pdev, wm831x_ts); + return 0; + +err_pd_irq: + free_irq(wm831x_ts->pd_irq, wm831x_ts); +err_data_irq: + free_irq(wm831x_ts->data_irq, wm831x_ts); +err_alloc: + input_free_device(input_dev); + kfree(wm831x_ts); + + return error; +} + +static __devexit int wm831x_ts_remove(struct platform_device *pdev) +{ + struct wm831x_ts *wm831x_ts = platform_get_drvdata(pdev); + + free_irq(wm831x_ts->pd_irq, wm831x_ts); + free_irq(wm831x_ts->data_irq, wm831x_ts); + input_unregister_device(wm831x_ts->input_dev); + kfree(wm831x_ts); + + platform_set_drvdata(pdev, NULL); + return 0; +} + +static struct platform_driver wm831x_ts_driver = { + .driver = { + .name = "wm831x-touch", + .owner = THIS_MODULE, + }, + .probe = wm831x_ts_probe, + .remove = __devexit_p(wm831x_ts_remove), +}; + +static int __init wm831x_ts_init(void) +{ + return platform_driver_register(&wm831x_ts_driver); +} +module_init(wm831x_ts_init); + +static void __exit wm831x_ts_exit(void) +{ + platform_driver_unregister(&wm831x_ts_driver); +} +module_exit(wm831x_ts_exit); + +/* Module information */ +MODULE_AUTHOR("Mark Brown "); +MODULE_DESCRIPTION("WM831x PMIC touchscreen driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:wm831x-touch"); -- cgit v1.2.3 From 723d928417bffff6467da155d8ebbbe016464012 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 31 Jan 2011 21:09:25 -0800 Subject: Input: wm831x-ts - remove use of ternary operator While being applied the driver was modified to add use of the ternary operator. Write the conditionals out longhand as I find it terribly unhelpful for legibility. Signed-off-by: Mark Brown Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/wm831x-ts.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/wm831x-ts.c b/drivers/input/touchscreen/wm831x-ts.c index a6121bdb635d..1022f715d3c2 100644 --- a/drivers/input/touchscreen/wm831x-ts.c +++ b/drivers/input/touchscreen/wm831x-ts.c @@ -76,9 +76,14 @@ static irqreturn_t wm831x_ts_data_irq(int irq, void *irq_data) struct wm831x *wm831x = wm831x_ts->wm831x; static int data_types[] = { ABS_X, ABS_Y, ABS_PRESSURE }; u16 data[3]; - int count = wm831x_ts->pressure ? 3 : 2; + int count; int i, ret; + if (wm831x_ts->pressure) + count = 3; + else + count = 2; + wm831x_set_bits(wm831x, WM831X_INTERRUPT_STATUS_1, WM831X_TCHDATA_EINT, WM831X_TCHDATA_EINT); @@ -134,10 +139,11 @@ static irqreturn_t wm831x_ts_pen_down_irq(int irq, void *irq_data) { struct wm831x_ts *wm831x_ts = irq_data; struct wm831x *wm831x = wm831x_ts->wm831x; - int ena; + int ena = 0; /* Start collecting data */ - ena = wm831x_ts->pressure ? WM831X_TCH_Z_ENA : 0; + if (wm831x_ts->pressure) + ena |= WM831X_TCH_Z_ENA; wm831x_set_bits(wm831x, WM831X_TOUCH_CONTROL_1, WM831X_TCH_X_ENA | WM831X_TCH_Y_ENA | WM831X_TCH_Z_ENA, @@ -188,11 +194,13 @@ static __devinit int wm831x_ts_probe(struct platform_device *pdev) struct wm831x_ts *wm831x_ts; struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent); struct wm831x_pdata *core_pdata = dev_get_platdata(pdev->dev.parent); - struct wm831x_touch_pdata *pdata = - core_pdata ? core_pdata->touch : NULL; + struct wm831x_touch_pdata *pdata = NULL; struct input_dev *input_dev; int error; + if (core_pdata) + pdata = core_pdata->touch; + wm831x_ts = kzalloc(sizeof(struct wm831x_ts), GFP_KERNEL); input_dev = input_allocate_device(); if (!wm831x_ts || !input_dev) { -- cgit v1.2.3 From aebd636bd60e2dda0ebc907dd5f7f4a45174411c Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 31 Jan 2011 21:06:39 -0800 Subject: Input: switch completely over to the new versions of get/setkeycode All users of old style get/setkeycode methids have been converted so it is time to retire them. Acked-by: Mauro Carvalho Chehab Acked-by: Jiri Kosina Signed-off-by: Dmitry Torokhov --- drivers/input/input.c | 55 +++++----------------------------------- drivers/input/misc/ati_remote2.c | 4 +-- drivers/input/sparse-keymap.c | 4 +-- 3 files changed, 11 insertions(+), 52 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/input.c b/drivers/input/input.c index 7985114beac7..ee2959bd322c 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -806,22 +806,9 @@ int input_get_keycode(struct input_dev *dev, struct input_keymap_entry *ke) int retval; spin_lock_irqsave(&dev->event_lock, flags); - - if (dev->getkeycode) { - /* - * Support for legacy drivers, that don't implement the new - * ioctls - */ - u32 scancode = ke->index; - - memcpy(ke->scancode, &scancode, sizeof(scancode)); - ke->len = sizeof(scancode); - retval = dev->getkeycode(dev, scancode, &ke->keycode); - } else { - retval = dev->getkeycode_new(dev, ke); - } - + retval = dev->getkeycode(dev, ke); spin_unlock_irqrestore(&dev->event_lock, flags); + return retval; } EXPORT_SYMBOL(input_get_keycode); @@ -846,35 +833,7 @@ int input_set_keycode(struct input_dev *dev, spin_lock_irqsave(&dev->event_lock, flags); - if (dev->setkeycode) { - /* - * Support for legacy drivers, that don't implement the new - * ioctls - */ - unsigned int scancode; - - retval = input_scancode_to_scalar(ke, &scancode); - if (retval) - goto out; - - /* - * We need to know the old scancode, in order to generate a - * keyup effect, if the set operation happens successfully - */ - if (!dev->getkeycode) { - retval = -EINVAL; - goto out; - } - - retval = dev->getkeycode(dev, scancode, &old_keycode); - if (retval) - goto out; - - retval = dev->setkeycode(dev, scancode, ke->keycode); - } else { - retval = dev->setkeycode_new(dev, ke, &old_keycode); - } - + retval = dev->setkeycode(dev, ke, &old_keycode); if (retval) goto out; @@ -1861,11 +1820,11 @@ int input_register_device(struct input_dev *dev) dev->rep[REP_PERIOD] = 33; } - if (!dev->getkeycode && !dev->getkeycode_new) - dev->getkeycode_new = input_default_getkeycode; + if (!dev->getkeycode) + dev->getkeycode = input_default_getkeycode; - if (!dev->setkeycode && !dev->setkeycode_new) - dev->setkeycode_new = input_default_setkeycode; + if (!dev->setkeycode) + dev->setkeycode = input_default_setkeycode; dev_set_name(&dev->dev, "input%ld", (unsigned long) atomic_inc_return(&input_no) - 1); diff --git a/drivers/input/misc/ati_remote2.c b/drivers/input/misc/ati_remote2.c index 0b0e9be63542..9ccdb82d869a 100644 --- a/drivers/input/misc/ati_remote2.c +++ b/drivers/input/misc/ati_remote2.c @@ -612,8 +612,8 @@ static int ati_remote2_input_init(struct ati_remote2 *ar2) idev->open = ati_remote2_open; idev->close = ati_remote2_close; - idev->getkeycode_new = ati_remote2_getkeycode; - idev->setkeycode_new = ati_remote2_setkeycode; + idev->getkeycode = ati_remote2_getkeycode; + idev->setkeycode = ati_remote2_setkeycode; idev->name = ar2->name; idev->phys = ar2->phys; diff --git a/drivers/input/sparse-keymap.c b/drivers/input/sparse-keymap.c index 7729e547ba65..337bf51bc984 100644 --- a/drivers/input/sparse-keymap.c +++ b/drivers/input/sparse-keymap.c @@ -210,8 +210,8 @@ int sparse_keymap_setup(struct input_dev *dev, dev->keycode = map; dev->keycodemax = map_size; - dev->getkeycode_new = sparse_keymap_getkeycode; - dev->setkeycode_new = sparse_keymap_setkeycode; + dev->getkeycode = sparse_keymap_getkeycode; + dev->setkeycode = sparse_keymap_setkeycode; return 0; -- cgit v1.2.3 From 2546bcc2d64c3bd0e7cb802cb8fc6cf757c6be0b Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 31 Jan 2011 21:06:34 -0800 Subject: Input: input-polldev - fix a couple of typos Signed-off-by: Dmitry Torokhov --- drivers/input/input-polldev.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/input-polldev.c b/drivers/input/input-polldev.c index 0559e309bac9..3037842a60d8 100644 --- a/drivers/input/input-polldev.c +++ b/drivers/input/input-polldev.c @@ -192,7 +192,7 @@ static struct attribute_group input_polldev_attribute_group = { }; /** - * input_allocate_polled_device - allocated memory polled device + * input_allocate_polled_device - allocate memory for polled device * * The function allocates memory for a polled device and also * for an input device associated with this polled device. @@ -239,7 +239,7 @@ EXPORT_SYMBOL(input_free_polled_device); * with input layer. The device should be allocated with call to * input_allocate_polled_device(). Callers should also set up poll() * method and set up capabilities (id, name, phys, bits) of the - * corresponing input_dev structure. + * corresponding input_dev structure. */ int input_register_polled_device(struct input_polled_dev *dev) { -- cgit v1.2.3 From 964de52147c2842092642512e6f654fc2ab51408 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 2 Feb 2011 23:21:58 -0800 Subject: Input: qt602240_ts - rename to atmel_mxt_ts Since the driver will be supporting whole range of Atmels mXT touchscreen controllers we better rename it to atmel_mxt_ts. Acked-by: Iiro Valkonen Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/Kconfig | 24 +- drivers/input/touchscreen/Makefile | 2 +- drivers/input/touchscreen/atmel_mxt_ts.c | 1406 ++++++++++++++++++++++++++++++ drivers/input/touchscreen/qt602240_ts.c | 1406 ------------------------------ 4 files changed, 1419 insertions(+), 1419 deletions(-) create mode 100644 drivers/input/touchscreen/atmel_mxt_ts.c delete mode 100644 drivers/input/touchscreen/qt602240_ts.c (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 258e43e98ec3..2fbd3d39b7eb 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -86,6 +86,18 @@ config TOUCHSCREEN_AD7879_SPI To compile this driver as a module, choose M here: the module will be called ad7879-spi. +config TOUCHSCREEN_ATMEL_MXT + tristate "Atmel mXT I2C Touchscreen" + depends on I2C + help + Say Y here if you have Atmel mXT series I2C touchscreen, + such as AT42QT602240/ATMXT224, connected to your system. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called atmel_mxt_ts. + config TOUCHSCREEN_BITSY tristate "Compaq iPAQ H3600 (Bitsy) touchscreen" depends on SA1100_BITSY @@ -339,18 +351,6 @@ config TOUCHSCREEN_PENMOUNT To compile this driver as a module, choose M here: the module will be called penmount. -config TOUCHSCREEN_QT602240 - tristate "QT602240 I2C Touchscreen" - depends on I2C - help - Say Y here if you have the AT42QT602240/ATMXT224 I2C touchscreen - connected to your system. - - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called qt602240_ts. - config TOUCHSCREEN_MIGOR tristate "Renesas MIGO-R touchscreen" depends on SH_MIGOR && I2C diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index e8dcfab7c2dc..756156409b83 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -12,6 +12,7 @@ obj-$(CONFIG_TOUCHSCREEN_AD7879) += ad7879.o obj-$(CONFIG_TOUCHSCREEN_AD7879_I2C) += ad7879-i2c.o obj-$(CONFIG_TOUCHSCREEN_AD7879_SPI) += ad7879-spi.o obj-$(CONFIG_TOUCHSCREEN_ADS7846) += ads7846.o +obj-$(CONFIG_TOUCHSCREEN_ATMEL_MXT) += atmel_mxt_ts.o obj-$(CONFIG_TOUCHSCREEN_ATMEL_TSADCC) += atmel_tsadcc.o obj-$(CONFIG_TOUCHSCREEN_BITSY) += h3600_ts_input.o obj-$(CONFIG_TOUCHSCREEN_BU21013) += bu21013_ts.o @@ -37,7 +38,6 @@ obj-$(CONFIG_TOUCHSCREEN_HTCPEN) += htcpen.o obj-$(CONFIG_TOUCHSCREEN_USB_COMPOSITE) += usbtouchscreen.o obj-$(CONFIG_TOUCHSCREEN_PCAP) += pcap_ts.o obj-$(CONFIG_TOUCHSCREEN_PENMOUNT) += penmount.o -obj-$(CONFIG_TOUCHSCREEN_QT602240) += qt602240_ts.o obj-$(CONFIG_TOUCHSCREEN_S3C2410) += s3c2410_ts.o obj-$(CONFIG_TOUCHSCREEN_ST1232) += st1232.o obj-$(CONFIG_TOUCHSCREEN_STMPE) += stmpe-ts.o diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c new file mode 100644 index 000000000000..47067789b747 --- /dev/null +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -0,0 +1,1406 @@ +/* + * AT42QT602240/ATMXT224 Touchscreen driver + * + * Copyright (C) 2010 Samsung Electronics Co.Ltd + * Author: Joonyoung Shim + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Version */ +#define QT602240_VER_20 20 +#define QT602240_VER_21 21 +#define QT602240_VER_22 22 + +/* Slave addresses */ +#define QT602240_APP_LOW 0x4a +#define QT602240_APP_HIGH 0x4b +#define QT602240_BOOT_LOW 0x24 +#define QT602240_BOOT_HIGH 0x25 + +/* Firmware */ +#define QT602240_FW_NAME "qt602240.fw" + +/* Registers */ +#define QT602240_FAMILY_ID 0x00 +#define QT602240_VARIANT_ID 0x01 +#define QT602240_VERSION 0x02 +#define QT602240_BUILD 0x03 +#define QT602240_MATRIX_X_SIZE 0x04 +#define QT602240_MATRIX_Y_SIZE 0x05 +#define QT602240_OBJECT_NUM 0x06 +#define QT602240_OBJECT_START 0x07 + +#define QT602240_OBJECT_SIZE 6 + +/* Object types */ +#define QT602240_DEBUG_DIAGNOSTIC 37 +#define QT602240_GEN_MESSAGE 5 +#define QT602240_GEN_COMMAND 6 +#define QT602240_GEN_POWER 7 +#define QT602240_GEN_ACQUIRE 8 +#define QT602240_TOUCH_MULTI 9 +#define QT602240_TOUCH_KEYARRAY 15 +#define QT602240_TOUCH_PROXIMITY 23 +#define QT602240_PROCI_GRIPFACE 20 +#define QT602240_PROCG_NOISE 22 +#define QT602240_PROCI_ONETOUCH 24 +#define QT602240_PROCI_TWOTOUCH 27 +#define QT602240_SPT_COMMSCONFIG 18 /* firmware ver 21 over */ +#define QT602240_SPT_GPIOPWM 19 +#define QT602240_SPT_SELFTEST 25 +#define QT602240_SPT_CTECONFIG 28 +#define QT602240_SPT_USERDATA 38 /* firmware ver 21 over */ + +/* QT602240_GEN_COMMAND field */ +#define QT602240_COMMAND_RESET 0 +#define QT602240_COMMAND_BACKUPNV 1 +#define QT602240_COMMAND_CALIBRATE 2 +#define QT602240_COMMAND_REPORTALL 3 +#define QT602240_COMMAND_DIAGNOSTIC 5 + +/* QT602240_GEN_POWER field */ +#define QT602240_POWER_IDLEACQINT 0 +#define QT602240_POWER_ACTVACQINT 1 +#define QT602240_POWER_ACTV2IDLETO 2 + +/* QT602240_GEN_ACQUIRE field */ +#define QT602240_ACQUIRE_CHRGTIME 0 +#define QT602240_ACQUIRE_TCHDRIFT 2 +#define QT602240_ACQUIRE_DRIFTST 3 +#define QT602240_ACQUIRE_TCHAUTOCAL 4 +#define QT602240_ACQUIRE_SYNC 5 +#define QT602240_ACQUIRE_ATCHCALST 6 +#define QT602240_ACQUIRE_ATCHCALSTHR 7 + +/* QT602240_TOUCH_MULTI field */ +#define QT602240_TOUCH_CTRL 0 +#define QT602240_TOUCH_XORIGIN 1 +#define QT602240_TOUCH_YORIGIN 2 +#define QT602240_TOUCH_XSIZE 3 +#define QT602240_TOUCH_YSIZE 4 +#define QT602240_TOUCH_BLEN 6 +#define QT602240_TOUCH_TCHTHR 7 +#define QT602240_TOUCH_TCHDI 8 +#define QT602240_TOUCH_ORIENT 9 +#define QT602240_TOUCH_MOVHYSTI 11 +#define QT602240_TOUCH_MOVHYSTN 12 +#define QT602240_TOUCH_NUMTOUCH 14 +#define QT602240_TOUCH_MRGHYST 15 +#define QT602240_TOUCH_MRGTHR 16 +#define QT602240_TOUCH_AMPHYST 17 +#define QT602240_TOUCH_XRANGE_LSB 18 +#define QT602240_TOUCH_XRANGE_MSB 19 +#define QT602240_TOUCH_YRANGE_LSB 20 +#define QT602240_TOUCH_YRANGE_MSB 21 +#define QT602240_TOUCH_XLOCLIP 22 +#define QT602240_TOUCH_XHICLIP 23 +#define QT602240_TOUCH_YLOCLIP 24 +#define QT602240_TOUCH_YHICLIP 25 +#define QT602240_TOUCH_XEDGECTRL 26 +#define QT602240_TOUCH_XEDGEDIST 27 +#define QT602240_TOUCH_YEDGECTRL 28 +#define QT602240_TOUCH_YEDGEDIST 29 +#define QT602240_TOUCH_JUMPLIMIT 30 /* firmware ver 22 over */ + +/* QT602240_PROCI_GRIPFACE field */ +#define QT602240_GRIPFACE_CTRL 0 +#define QT602240_GRIPFACE_XLOGRIP 1 +#define QT602240_GRIPFACE_XHIGRIP 2 +#define QT602240_GRIPFACE_YLOGRIP 3 +#define QT602240_GRIPFACE_YHIGRIP 4 +#define QT602240_GRIPFACE_MAXTCHS 5 +#define QT602240_GRIPFACE_SZTHR1 7 +#define QT602240_GRIPFACE_SZTHR2 8 +#define QT602240_GRIPFACE_SHPTHR1 9 +#define QT602240_GRIPFACE_SHPTHR2 10 +#define QT602240_GRIPFACE_SUPEXTTO 11 + +/* QT602240_PROCI_NOISE field */ +#define QT602240_NOISE_CTRL 0 +#define QT602240_NOISE_OUTFLEN 1 +#define QT602240_NOISE_GCAFUL_LSB 3 +#define QT602240_NOISE_GCAFUL_MSB 4 +#define QT602240_NOISE_GCAFLL_LSB 5 +#define QT602240_NOISE_GCAFLL_MSB 6 +#define QT602240_NOISE_ACTVGCAFVALID 7 +#define QT602240_NOISE_NOISETHR 8 +#define QT602240_NOISE_FREQHOPSCALE 10 +#define QT602240_NOISE_FREQ0 11 +#define QT602240_NOISE_FREQ1 12 +#define QT602240_NOISE_FREQ2 13 +#define QT602240_NOISE_FREQ3 14 +#define QT602240_NOISE_FREQ4 15 +#define QT602240_NOISE_IDLEGCAFVALID 16 + +/* QT602240_SPT_COMMSCONFIG */ +#define QT602240_COMMS_CTRL 0 +#define QT602240_COMMS_CMD 1 + +/* QT602240_SPT_CTECONFIG field */ +#define QT602240_CTE_CTRL 0 +#define QT602240_CTE_CMD 1 +#define QT602240_CTE_MODE 2 +#define QT602240_CTE_IDLEGCAFDEPTH 3 +#define QT602240_CTE_ACTVGCAFDEPTH 4 +#define QT602240_CTE_VOLTAGE 5 /* firmware ver 21 over */ + +#define QT602240_VOLTAGE_DEFAULT 2700000 +#define QT602240_VOLTAGE_STEP 10000 + +/* Define for QT602240_GEN_COMMAND */ +#define QT602240_BOOT_VALUE 0xa5 +#define QT602240_BACKUP_VALUE 0x55 +#define QT602240_BACKUP_TIME 25 /* msec */ +#define QT602240_RESET_TIME 65 /* msec */ + +#define QT602240_FWRESET_TIME 175 /* msec */ + +/* Command to unlock bootloader */ +#define QT602240_UNLOCK_CMD_MSB 0xaa +#define QT602240_UNLOCK_CMD_LSB 0xdc + +/* Bootloader mode status */ +#define QT602240_WAITING_BOOTLOAD_CMD 0xc0 /* valid 7 6 bit only */ +#define QT602240_WAITING_FRAME_DATA 0x80 /* valid 7 6 bit only */ +#define QT602240_FRAME_CRC_CHECK 0x02 +#define QT602240_FRAME_CRC_FAIL 0x03 +#define QT602240_FRAME_CRC_PASS 0x04 +#define QT602240_APP_CRC_FAIL 0x40 /* valid 7 8 bit only */ +#define QT602240_BOOT_STATUS_MASK 0x3f + +/* Touch status */ +#define QT602240_SUPPRESS (1 << 1) +#define QT602240_AMP (1 << 2) +#define QT602240_VECTOR (1 << 3) +#define QT602240_MOVE (1 << 4) +#define QT602240_RELEASE (1 << 5) +#define QT602240_PRESS (1 << 6) +#define QT602240_DETECT (1 << 7) + +/* Touchscreen absolute values */ +#define QT602240_MAX_XC 0x3ff +#define QT602240_MAX_YC 0x3ff +#define QT602240_MAX_AREA 0xff + +#define QT602240_MAX_FINGER 10 + +/* Initial register values recommended from chip vendor */ +static const u8 init_vals_ver_20[] = { + /* QT602240_GEN_COMMAND(6) */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* QT602240_GEN_POWER(7) */ + 0x20, 0xff, 0x32, + /* QT602240_GEN_ACQUIRE(8) */ + 0x08, 0x05, 0x05, 0x00, 0x00, 0x00, 0x05, 0x14, + /* QT602240_TOUCH_MULTI(9) */ + 0x00, 0x00, 0x00, 0x11, 0x0a, 0x00, 0x00, 0x00, 0x02, 0x00, + 0x00, 0x01, 0x01, 0x0e, 0x0a, 0x0a, 0x0a, 0x0a, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x64, + /* QT602240_TOUCH_KEYARRAY(15) */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, + /* QT602240_SPT_GPIOPWM(19) */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, + /* QT602240_PROCI_GRIPFACE(20) */ + 0x00, 0x64, 0x64, 0x64, 0x64, 0x00, 0x00, 0x1e, 0x14, 0x04, + 0x1e, 0x00, + /* QT602240_PROCG_NOISE(22) */ + 0x05, 0x00, 0x00, 0x19, 0x00, 0xe7, 0xff, 0x04, 0x32, 0x00, + 0x01, 0x0a, 0x0f, 0x14, 0x00, 0x00, 0xe8, + /* QT602240_TOUCH_PROXIMITY(23) */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + /* QT602240_PROCI_ONETOUCH(24) */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* QT602240_SPT_SELFTEST(25) */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + /* QT602240_PROCI_TWOTOUCH(27) */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* QT602240_SPT_CTECONFIG(28) */ + 0x00, 0x00, 0x00, 0x04, 0x08, +}; + +static const u8 init_vals_ver_21[] = { + /* QT602240_GEN_COMMAND(6) */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* QT602240_GEN_POWER(7) */ + 0x20, 0xff, 0x32, + /* QT602240_GEN_ACQUIRE(8) */ + 0x0a, 0x00, 0x05, 0x00, 0x00, 0x00, 0x09, 0x23, + /* QT602240_TOUCH_MULTI(9) */ + 0x00, 0x00, 0x00, 0x13, 0x0b, 0x00, 0x00, 0x00, 0x02, 0x00, + 0x00, 0x01, 0x01, 0x0e, 0x0a, 0x0a, 0x0a, 0x0a, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* QT602240_TOUCH_KEYARRAY(15) */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, + /* QT602240_SPT_GPIOPWM(19) */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* QT602240_PROCI_GRIPFACE(20) */ + 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x28, 0x04, + 0x0f, 0x0a, + /* QT602240_PROCG_NOISE(22) */ + 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x23, 0x00, + 0x00, 0x05, 0x0f, 0x19, 0x23, 0x2d, 0x03, + /* QT602240_TOUCH_PROXIMITY(23) */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + /* QT602240_PROCI_ONETOUCH(24) */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* QT602240_SPT_SELFTEST(25) */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + /* QT602240_PROCI_TWOTOUCH(27) */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* QT602240_SPT_CTECONFIG(28) */ + 0x00, 0x00, 0x00, 0x08, 0x10, 0x00, +}; + +static const u8 init_vals_ver_22[] = { + /* QT602240_GEN_COMMAND(6) */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* QT602240_GEN_POWER(7) */ + 0x20, 0xff, 0x32, + /* QT602240_GEN_ACQUIRE(8) */ + 0x0a, 0x00, 0x05, 0x00, 0x00, 0x00, 0x09, 0x23, + /* QT602240_TOUCH_MULTI(9) */ + 0x00, 0x00, 0x00, 0x13, 0x0b, 0x00, 0x00, 0x00, 0x02, 0x00, + 0x00, 0x01, 0x01, 0x0e, 0x0a, 0x0a, 0x0a, 0x0a, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, + /* QT602240_TOUCH_KEYARRAY(15) */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, + /* QT602240_SPT_GPIOPWM(19) */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* QT602240_PROCI_GRIPFACE(20) */ + 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x28, 0x04, + 0x0f, 0x0a, + /* QT602240_PROCG_NOISE(22) */ + 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x23, 0x00, + 0x00, 0x05, 0x0f, 0x19, 0x23, 0x2d, 0x03, + /* QT602240_TOUCH_PROXIMITY(23) */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + /* QT602240_PROCI_ONETOUCH(24) */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* QT602240_SPT_SELFTEST(25) */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + /* QT602240_PROCI_TWOTOUCH(27) */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* QT602240_SPT_CTECONFIG(28) */ + 0x00, 0x00, 0x00, 0x08, 0x10, 0x00, +}; + +struct qt602240_info { + u8 family_id; + u8 variant_id; + u8 version; + u8 build; + u8 matrix_xsize; + u8 matrix_ysize; + u8 object_num; +}; + +struct qt602240_object { + u8 type; + u16 start_address; + u8 size; + u8 instances; + u8 num_report_ids; + + /* to map object and message */ + u8 max_reportid; +}; + +struct qt602240_message { + u8 reportid; + u8 message[7]; + u8 checksum; +}; + +struct qt602240_finger { + int status; + int x; + int y; + int area; +}; + +/* Each client has this additional data */ +struct qt602240_data { + struct i2c_client *client; + struct input_dev *input_dev; + const struct qt602240_platform_data *pdata; + struct qt602240_object *object_table; + struct qt602240_info info; + struct qt602240_finger finger[QT602240_MAX_FINGER]; + unsigned int irq; +}; + +static bool qt602240_object_readable(unsigned int type) +{ + switch (type) { + case QT602240_GEN_MESSAGE: + case QT602240_GEN_COMMAND: + case QT602240_GEN_POWER: + case QT602240_GEN_ACQUIRE: + case QT602240_TOUCH_MULTI: + case QT602240_TOUCH_KEYARRAY: + case QT602240_TOUCH_PROXIMITY: + case QT602240_PROCI_GRIPFACE: + case QT602240_PROCG_NOISE: + case QT602240_PROCI_ONETOUCH: + case QT602240_PROCI_TWOTOUCH: + case QT602240_SPT_COMMSCONFIG: + case QT602240_SPT_GPIOPWM: + case QT602240_SPT_SELFTEST: + case QT602240_SPT_CTECONFIG: + case QT602240_SPT_USERDATA: + return true; + default: + return false; + } +} + +static bool qt602240_object_writable(unsigned int type) +{ + switch (type) { + case QT602240_GEN_COMMAND: + case QT602240_GEN_POWER: + case QT602240_GEN_ACQUIRE: + case QT602240_TOUCH_MULTI: + case QT602240_TOUCH_KEYARRAY: + case QT602240_TOUCH_PROXIMITY: + case QT602240_PROCI_GRIPFACE: + case QT602240_PROCG_NOISE: + case QT602240_PROCI_ONETOUCH: + case QT602240_PROCI_TWOTOUCH: + case QT602240_SPT_GPIOPWM: + case QT602240_SPT_SELFTEST: + case QT602240_SPT_CTECONFIG: + return true; + default: + return false; + } +} + +static void qt602240_dump_message(struct device *dev, + struct qt602240_message *message) +{ + dev_dbg(dev, "reportid:\t0x%x\n", message->reportid); + dev_dbg(dev, "message1:\t0x%x\n", message->message[0]); + dev_dbg(dev, "message2:\t0x%x\n", message->message[1]); + dev_dbg(dev, "message3:\t0x%x\n", message->message[2]); + dev_dbg(dev, "message4:\t0x%x\n", message->message[3]); + dev_dbg(dev, "message5:\t0x%x\n", message->message[4]); + dev_dbg(dev, "message6:\t0x%x\n", message->message[5]); + dev_dbg(dev, "message7:\t0x%x\n", message->message[6]); + dev_dbg(dev, "checksum:\t0x%x\n", message->checksum); +} + +static int qt602240_check_bootloader(struct i2c_client *client, + unsigned int state) +{ + u8 val; + +recheck: + if (i2c_master_recv(client, &val, 1) != 1) { + dev_err(&client->dev, "%s: i2c recv failed\n", __func__); + return -EIO; + } + + switch (state) { + case QT602240_WAITING_BOOTLOAD_CMD: + case QT602240_WAITING_FRAME_DATA: + val &= ~QT602240_BOOT_STATUS_MASK; + break; + case QT602240_FRAME_CRC_PASS: + if (val == QT602240_FRAME_CRC_CHECK) + goto recheck; + break; + default: + return -EINVAL; + } + + if (val != state) { + dev_err(&client->dev, "Unvalid bootloader mode state\n"); + return -EINVAL; + } + + return 0; +} + +static int qt602240_unlock_bootloader(struct i2c_client *client) +{ + u8 buf[2]; + + buf[0] = QT602240_UNLOCK_CMD_LSB; + buf[1] = QT602240_UNLOCK_CMD_MSB; + + if (i2c_master_send(client, buf, 2) != 2) { + dev_err(&client->dev, "%s: i2c send failed\n", __func__); + return -EIO; + } + + return 0; +} + +static int qt602240_fw_write(struct i2c_client *client, + const u8 *data, unsigned int frame_size) +{ + if (i2c_master_send(client, data, frame_size) != frame_size) { + dev_err(&client->dev, "%s: i2c send failed\n", __func__); + return -EIO; + } + + return 0; +} + +static int __qt602240_read_reg(struct i2c_client *client, + u16 reg, u16 len, void *val) +{ + struct i2c_msg xfer[2]; + u8 buf[2]; + + buf[0] = reg & 0xff; + buf[1] = (reg >> 8) & 0xff; + + /* Write register */ + xfer[0].addr = client->addr; + xfer[0].flags = 0; + xfer[0].len = 2; + xfer[0].buf = buf; + + /* Read data */ + xfer[1].addr = client->addr; + xfer[1].flags = I2C_M_RD; + xfer[1].len = len; + xfer[1].buf = val; + + if (i2c_transfer(client->adapter, xfer, 2) != 2) { + dev_err(&client->dev, "%s: i2c transfer failed\n", __func__); + return -EIO; + } + + return 0; +} + +static int qt602240_read_reg(struct i2c_client *client, u16 reg, u8 *val) +{ + return __qt602240_read_reg(client, reg, 1, val); +} + +static int qt602240_write_reg(struct i2c_client *client, u16 reg, u8 val) +{ + u8 buf[3]; + + buf[0] = reg & 0xff; + buf[1] = (reg >> 8) & 0xff; + buf[2] = val; + + if (i2c_master_send(client, buf, 3) != 3) { + dev_err(&client->dev, "%s: i2c send failed\n", __func__); + return -EIO; + } + + return 0; +} + +static int qt602240_read_object_table(struct i2c_client *client, + u16 reg, u8 *object_buf) +{ + return __qt602240_read_reg(client, reg, QT602240_OBJECT_SIZE, + object_buf); +} + +static struct qt602240_object * +qt602240_get_object(struct qt602240_data *data, u8 type) +{ + struct qt602240_object *object; + int i; + + for (i = 0; i < data->info.object_num; i++) { + object = data->object_table + i; + if (object->type == type) + return object; + } + + dev_err(&data->client->dev, "Invalid object type\n"); + return NULL; +} + +static int qt602240_read_message(struct qt602240_data *data, + struct qt602240_message *message) +{ + struct qt602240_object *object; + u16 reg; + + object = qt602240_get_object(data, QT602240_GEN_MESSAGE); + if (!object) + return -EINVAL; + + reg = object->start_address; + return __qt602240_read_reg(data->client, reg, + sizeof(struct qt602240_message), message); +} + +static int qt602240_read_object(struct qt602240_data *data, + u8 type, u8 offset, u8 *val) +{ + struct qt602240_object *object; + u16 reg; + + object = qt602240_get_object(data, type); + if (!object) + return -EINVAL; + + reg = object->start_address; + return __qt602240_read_reg(data->client, reg + offset, 1, val); +} + +static int qt602240_write_object(struct qt602240_data *data, + u8 type, u8 offset, u8 val) +{ + struct qt602240_object *object; + u16 reg; + + object = qt602240_get_object(data, type); + if (!object) + return -EINVAL; + + reg = object->start_address; + return qt602240_write_reg(data->client, reg + offset, val); +} + +static void qt602240_input_report(struct qt602240_data *data, int single_id) +{ + struct qt602240_finger *finger = data->finger; + struct input_dev *input_dev = data->input_dev; + int status = finger[single_id].status; + int finger_num = 0; + int id; + + for (id = 0; id < QT602240_MAX_FINGER; id++) { + if (!finger[id].status) + continue; + + input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR, + finger[id].status != QT602240_RELEASE ? + finger[id].area : 0); + input_report_abs(input_dev, ABS_MT_POSITION_X, + finger[id].x); + input_report_abs(input_dev, ABS_MT_POSITION_Y, + finger[id].y); + input_mt_sync(input_dev); + + if (finger[id].status == QT602240_RELEASE) + finger[id].status = 0; + else + finger_num++; + } + + input_report_key(input_dev, BTN_TOUCH, finger_num > 0); + + if (status != QT602240_RELEASE) { + input_report_abs(input_dev, ABS_X, finger[single_id].x); + input_report_abs(input_dev, ABS_Y, finger[single_id].y); + } + + input_sync(input_dev); +} + +static void qt602240_input_touchevent(struct qt602240_data *data, + struct qt602240_message *message, int id) +{ + struct qt602240_finger *finger = data->finger; + struct device *dev = &data->client->dev; + u8 status = message->message[0]; + int x; + int y; + int area; + + /* Check the touch is present on the screen */ + if (!(status & QT602240_DETECT)) { + if (status & QT602240_RELEASE) { + dev_dbg(dev, "[%d] released\n", id); + + finger[id].status = QT602240_RELEASE; + qt602240_input_report(data, id); + } + return; + } + + /* Check only AMP detection */ + if (!(status & (QT602240_PRESS | QT602240_MOVE))) + return; + + x = (message->message[1] << 2) | ((message->message[3] & ~0x3f) >> 6); + y = (message->message[2] << 2) | ((message->message[3] & ~0xf3) >> 2); + area = message->message[4]; + + dev_dbg(dev, "[%d] %s x: %d, y: %d, area: %d\n", id, + status & QT602240_MOVE ? "moved" : "pressed", + x, y, area); + + finger[id].status = status & QT602240_MOVE ? + QT602240_MOVE : QT602240_PRESS; + finger[id].x = x; + finger[id].y = y; + finger[id].area = area; + + qt602240_input_report(data, id); +} + +static irqreturn_t qt602240_interrupt(int irq, void *dev_id) +{ + struct qt602240_data *data = dev_id; + struct qt602240_message message; + struct qt602240_object *object; + struct device *dev = &data->client->dev; + int id; + u8 reportid; + u8 max_reportid; + u8 min_reportid; + + do { + if (qt602240_read_message(data, &message)) { + dev_err(dev, "Failed to read message\n"); + goto end; + } + + reportid = message.reportid; + + /* whether reportid is thing of QT602240_TOUCH_MULTI */ + object = qt602240_get_object(data, QT602240_TOUCH_MULTI); + if (!object) + goto end; + + max_reportid = object->max_reportid; + min_reportid = max_reportid - object->num_report_ids + 1; + id = reportid - min_reportid; + + if (reportid >= min_reportid && reportid <= max_reportid) + qt602240_input_touchevent(data, &message, id); + else + qt602240_dump_message(dev, &message); + } while (reportid != 0xff); + +end: + return IRQ_HANDLED; +} + +static int qt602240_check_reg_init(struct qt602240_data *data) +{ + struct qt602240_object *object; + struct device *dev = &data->client->dev; + int index = 0; + int i, j; + u8 version = data->info.version; + u8 *init_vals; + + switch (version) { + case QT602240_VER_20: + init_vals = (u8 *)init_vals_ver_20; + break; + case QT602240_VER_21: + init_vals = (u8 *)init_vals_ver_21; + break; + case QT602240_VER_22: + init_vals = (u8 *)init_vals_ver_22; + break; + default: + dev_err(dev, "Firmware version %d doesn't support\n", version); + return -EINVAL; + } + + for (i = 0; i < data->info.object_num; i++) { + object = data->object_table + i; + + if (!qt602240_object_writable(object->type)) + continue; + + for (j = 0; j < object->size + 1; j++) + qt602240_write_object(data, object->type, j, + init_vals[index + j]); + + index += object->size + 1; + } + + return 0; +} + +static int qt602240_check_matrix_size(struct qt602240_data *data) +{ + const struct qt602240_platform_data *pdata = data->pdata; + struct device *dev = &data->client->dev; + int mode = -1; + int error; + u8 val; + + dev_dbg(dev, "Number of X lines: %d\n", pdata->x_line); + dev_dbg(dev, "Number of Y lines: %d\n", pdata->y_line); + + switch (pdata->x_line) { + case 0 ... 15: + if (pdata->y_line <= 14) + mode = 0; + break; + case 16: + if (pdata->y_line <= 12) + mode = 1; + if (pdata->y_line == 13 || pdata->y_line == 14) + mode = 0; + break; + case 17: + if (pdata->y_line <= 11) + mode = 2; + if (pdata->y_line == 12 || pdata->y_line == 13) + mode = 1; + break; + case 18: + if (pdata->y_line <= 10) + mode = 3; + if (pdata->y_line == 11 || pdata->y_line == 12) + mode = 2; + break; + case 19: + if (pdata->y_line <= 9) + mode = 4; + if (pdata->y_line == 10 || pdata->y_line == 11) + mode = 3; + break; + case 20: + mode = 4; + } + + if (mode < 0) { + dev_err(dev, "Invalid X/Y lines\n"); + return -EINVAL; + } + + error = qt602240_read_object(data, QT602240_SPT_CTECONFIG, + QT602240_CTE_MODE, &val); + if (error) + return error; + + if (mode == val) + return 0; + + /* Change the CTE configuration */ + qt602240_write_object(data, QT602240_SPT_CTECONFIG, + QT602240_CTE_CTRL, 1); + qt602240_write_object(data, QT602240_SPT_CTECONFIG, + QT602240_CTE_MODE, mode); + qt602240_write_object(data, QT602240_SPT_CTECONFIG, + QT602240_CTE_CTRL, 0); + + return 0; +} + +static int qt602240_make_highchg(struct qt602240_data *data) +{ + struct device *dev = &data->client->dev; + int count = 10; + int error; + u8 val; + + /* Read dummy message to make high CHG pin */ + do { + error = qt602240_read_object(data, QT602240_GEN_MESSAGE, 0, &val); + if (error) + return error; + } while ((val != 0xff) && --count); + + if (!count) { + dev_err(dev, "CHG pin isn't cleared\n"); + return -EBUSY; + } + + return 0; +} + +static void qt602240_handle_pdata(struct qt602240_data *data) +{ + const struct qt602240_platform_data *pdata = data->pdata; + u8 voltage; + + /* Set touchscreen lines */ + qt602240_write_object(data, QT602240_TOUCH_MULTI, QT602240_TOUCH_XSIZE, + pdata->x_line); + qt602240_write_object(data, QT602240_TOUCH_MULTI, QT602240_TOUCH_YSIZE, + pdata->y_line); + + /* Set touchscreen orient */ + qt602240_write_object(data, QT602240_TOUCH_MULTI, QT602240_TOUCH_ORIENT, + pdata->orient); + + /* Set touchscreen burst length */ + qt602240_write_object(data, QT602240_TOUCH_MULTI, + QT602240_TOUCH_BLEN, pdata->blen); + + /* Set touchscreen threshold */ + qt602240_write_object(data, QT602240_TOUCH_MULTI, + QT602240_TOUCH_TCHTHR, pdata->threshold); + + /* Set touchscreen resolution */ + qt602240_write_object(data, QT602240_TOUCH_MULTI, + QT602240_TOUCH_XRANGE_LSB, (pdata->x_size - 1) & 0xff); + qt602240_write_object(data, QT602240_TOUCH_MULTI, + QT602240_TOUCH_XRANGE_MSB, (pdata->x_size - 1) >> 8); + qt602240_write_object(data, QT602240_TOUCH_MULTI, + QT602240_TOUCH_YRANGE_LSB, (pdata->y_size - 1) & 0xff); + qt602240_write_object(data, QT602240_TOUCH_MULTI, + QT602240_TOUCH_YRANGE_MSB, (pdata->y_size - 1) >> 8); + + /* Set touchscreen voltage */ + if (data->info.version >= QT602240_VER_21 && pdata->voltage) { + if (pdata->voltage < QT602240_VOLTAGE_DEFAULT) { + voltage = (QT602240_VOLTAGE_DEFAULT - pdata->voltage) / + QT602240_VOLTAGE_STEP; + voltage = 0xff - voltage + 1; + } else + voltage = (pdata->voltage - QT602240_VOLTAGE_DEFAULT) / + QT602240_VOLTAGE_STEP; + + qt602240_write_object(data, QT602240_SPT_CTECONFIG, + QT602240_CTE_VOLTAGE, voltage); + } +} + +static int qt602240_get_info(struct qt602240_data *data) +{ + struct i2c_client *client = data->client; + struct qt602240_info *info = &data->info; + int error; + u8 val; + + error = qt602240_read_reg(client, QT602240_FAMILY_ID, &val); + if (error) + return error; + info->family_id = val; + + error = qt602240_read_reg(client, QT602240_VARIANT_ID, &val); + if (error) + return error; + info->variant_id = val; + + error = qt602240_read_reg(client, QT602240_VERSION, &val); + if (error) + return error; + info->version = val; + + error = qt602240_read_reg(client, QT602240_BUILD, &val); + if (error) + return error; + info->build = val; + + error = qt602240_read_reg(client, QT602240_OBJECT_NUM, &val); + if (error) + return error; + info->object_num = val; + + return 0; +} + +static int qt602240_get_object_table(struct qt602240_data *data) +{ + int error; + int i; + u16 reg; + u8 reportid = 0; + u8 buf[QT602240_OBJECT_SIZE]; + + for (i = 0; i < data->info.object_num; i++) { + struct qt602240_object *object = data->object_table + i; + + reg = QT602240_OBJECT_START + QT602240_OBJECT_SIZE * i; + error = qt602240_read_object_table(data->client, reg, buf); + if (error) + return error; + + object->type = buf[0]; + object->start_address = (buf[2] << 8) | buf[1]; + object->size = buf[3]; + object->instances = buf[4]; + object->num_report_ids = buf[5]; + + if (object->num_report_ids) { + reportid += object->num_report_ids * + (object->instances + 1); + object->max_reportid = reportid; + } + } + + return 0; +} + +static int qt602240_initialize(struct qt602240_data *data) +{ + struct i2c_client *client = data->client; + struct qt602240_info *info = &data->info; + int error; + u8 val; + + error = qt602240_get_info(data); + if (error) + return error; + + data->object_table = kcalloc(info->object_num, + sizeof(struct qt602240_object), + GFP_KERNEL); + if (!data->object_table) { + dev_err(&client->dev, "Failed to allocate memory\n"); + return -ENOMEM; + } + + /* Get object table information */ + error = qt602240_get_object_table(data); + if (error) + return error; + + /* Check register init values */ + error = qt602240_check_reg_init(data); + if (error) + return error; + + /* Check X/Y matrix size */ + error = qt602240_check_matrix_size(data); + if (error) + return error; + + error = qt602240_make_highchg(data); + if (error) + return error; + + qt602240_handle_pdata(data); + + /* Backup to memory */ + qt602240_write_object(data, QT602240_GEN_COMMAND, + QT602240_COMMAND_BACKUPNV, + QT602240_BACKUP_VALUE); + msleep(QT602240_BACKUP_TIME); + + /* Soft reset */ + qt602240_write_object(data, QT602240_GEN_COMMAND, + QT602240_COMMAND_RESET, 1); + msleep(QT602240_RESET_TIME); + + /* Update matrix size at info struct */ + error = qt602240_read_reg(client, QT602240_MATRIX_X_SIZE, &val); + if (error) + return error; + info->matrix_xsize = val; + + error = qt602240_read_reg(client, QT602240_MATRIX_Y_SIZE, &val); + if (error) + return error; + info->matrix_ysize = val; + + dev_info(&client->dev, + "Family ID: %d Variant ID: %d Version: %d Build: %d\n", + info->family_id, info->variant_id, info->version, + info->build); + + dev_info(&client->dev, + "Matrix X Size: %d Matrix Y Size: %d Object Num: %d\n", + info->matrix_xsize, info->matrix_ysize, + info->object_num); + + return 0; +} + +static ssize_t qt602240_object_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct qt602240_data *data = dev_get_drvdata(dev); + struct qt602240_object *object; + int count = 0; + int i, j; + int error; + u8 val; + + for (i = 0; i < data->info.object_num; i++) { + object = data->object_table + i; + + count += sprintf(buf + count, + "Object Table Element %d(Type %d)\n", + i + 1, object->type); + + if (!qt602240_object_readable(object->type)) { + count += sprintf(buf + count, "\n"); + continue; + } + + for (j = 0; j < object->size + 1; j++) { + error = qt602240_read_object(data, + object->type, j, &val); + if (error) + return error; + + count += sprintf(buf + count, + " Byte %d: 0x%x (%d)\n", j, val, val); + } + + count += sprintf(buf + count, "\n"); + } + + return count; +} + +static int qt602240_load_fw(struct device *dev, const char *fn) +{ + struct qt602240_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; + const struct firmware *fw = NULL; + unsigned int frame_size; + unsigned int pos = 0; + int ret; + + ret = request_firmware(&fw, fn, dev); + if (ret) { + dev_err(dev, "Unable to open firmware %s\n", fn); + return ret; + } + + /* Change to the bootloader mode */ + qt602240_write_object(data, QT602240_GEN_COMMAND, + QT602240_COMMAND_RESET, QT602240_BOOT_VALUE); + msleep(QT602240_RESET_TIME); + + /* Change to slave address of bootloader */ + if (client->addr == QT602240_APP_LOW) + client->addr = QT602240_BOOT_LOW; + else + client->addr = QT602240_BOOT_HIGH; + + ret = qt602240_check_bootloader(client, QT602240_WAITING_BOOTLOAD_CMD); + if (ret) + goto out; + + /* Unlock bootloader */ + qt602240_unlock_bootloader(client); + + while (pos < fw->size) { + ret = qt602240_check_bootloader(client, + QT602240_WAITING_FRAME_DATA); + if (ret) + goto out; + + frame_size = ((*(fw->data + pos) << 8) | *(fw->data + pos + 1)); + + /* We should add 2 at frame size as the the firmware data is not + * included the CRC bytes. + */ + frame_size += 2; + + /* Write one frame to device */ + qt602240_fw_write(client, fw->data + pos, frame_size); + + ret = qt602240_check_bootloader(client, + QT602240_FRAME_CRC_PASS); + if (ret) + goto out; + + pos += frame_size; + + dev_dbg(dev, "Updated %d bytes / %zd bytes\n", pos, fw->size); + } + +out: + release_firmware(fw); + + /* Change to slave address of application */ + if (client->addr == QT602240_BOOT_LOW) + client->addr = QT602240_APP_LOW; + else + client->addr = QT602240_APP_HIGH; + + return ret; +} + +static ssize_t qt602240_update_fw_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct qt602240_data *data = dev_get_drvdata(dev); + unsigned int version; + int error; + + if (sscanf(buf, "%u", &version) != 1) { + dev_err(dev, "Invalid values\n"); + return -EINVAL; + } + + if (data->info.version < QT602240_VER_21 || version < QT602240_VER_21) { + dev_err(dev, "FW update supported starting with version 21\n"); + return -EINVAL; + } + + disable_irq(data->irq); + + error = qt602240_load_fw(dev, QT602240_FW_NAME); + if (error) { + dev_err(dev, "The firmware update failed(%d)\n", error); + count = error; + } else { + dev_dbg(dev, "The firmware update succeeded\n"); + + /* Wait for reset */ + msleep(QT602240_FWRESET_TIME); + + kfree(data->object_table); + data->object_table = NULL; + + qt602240_initialize(data); + } + + enable_irq(data->irq); + + return count; +} + +static DEVICE_ATTR(object, 0444, qt602240_object_show, NULL); +static DEVICE_ATTR(update_fw, 0664, NULL, qt602240_update_fw_store); + +static struct attribute *qt602240_attrs[] = { + &dev_attr_object.attr, + &dev_attr_update_fw.attr, + NULL +}; + +static const struct attribute_group qt602240_attr_group = { + .attrs = qt602240_attrs, +}; + +static void qt602240_start(struct qt602240_data *data) +{ + /* Touch enable */ + qt602240_write_object(data, + QT602240_TOUCH_MULTI, QT602240_TOUCH_CTRL, 0x83); +} + +static void qt602240_stop(struct qt602240_data *data) +{ + /* Touch disable */ + qt602240_write_object(data, + QT602240_TOUCH_MULTI, QT602240_TOUCH_CTRL, 0); +} + +static int qt602240_input_open(struct input_dev *dev) +{ + struct qt602240_data *data = input_get_drvdata(dev); + + qt602240_start(data); + + return 0; +} + +static void qt602240_input_close(struct input_dev *dev) +{ + struct qt602240_data *data = input_get_drvdata(dev); + + qt602240_stop(data); +} + +static int __devinit qt602240_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct qt602240_data *data; + struct input_dev *input_dev; + int error; + + if (!client->dev.platform_data) + return -EINVAL; + + data = kzalloc(sizeof(struct qt602240_data), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!data || !input_dev) { + dev_err(&client->dev, "Failed to allocate memory\n"); + error = -ENOMEM; + goto err_free_mem; + } + + input_dev->name = "AT42QT602240/ATMXT224 Touchscreen"; + input_dev->id.bustype = BUS_I2C; + input_dev->dev.parent = &client->dev; + input_dev->open = qt602240_input_open; + input_dev->close = qt602240_input_close; + + __set_bit(EV_ABS, input_dev->evbit); + __set_bit(EV_KEY, input_dev->evbit); + __set_bit(BTN_TOUCH, input_dev->keybit); + + /* For single touch */ + input_set_abs_params(input_dev, ABS_X, + 0, QT602240_MAX_XC, 0, 0); + input_set_abs_params(input_dev, ABS_Y, + 0, QT602240_MAX_YC, 0, 0); + + /* For multi touch */ + input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, + 0, QT602240_MAX_AREA, 0, 0); + input_set_abs_params(input_dev, ABS_MT_POSITION_X, + 0, QT602240_MAX_XC, 0, 0); + input_set_abs_params(input_dev, ABS_MT_POSITION_Y, + 0, QT602240_MAX_YC, 0, 0); + + input_set_drvdata(input_dev, data); + + data->client = client; + data->input_dev = input_dev; + data->pdata = client->dev.platform_data; + data->irq = client->irq; + + i2c_set_clientdata(client, data); + + error = qt602240_initialize(data); + if (error) + goto err_free_object; + + error = request_threaded_irq(client->irq, NULL, qt602240_interrupt, + IRQF_TRIGGER_FALLING, client->dev.driver->name, data); + if (error) { + dev_err(&client->dev, "Failed to register interrupt\n"); + goto err_free_object; + } + + error = input_register_device(input_dev); + if (error) + goto err_free_irq; + + error = sysfs_create_group(&client->dev.kobj, &qt602240_attr_group); + if (error) + goto err_unregister_device; + + return 0; + +err_unregister_device: + input_unregister_device(input_dev); + input_dev = NULL; +err_free_irq: + free_irq(client->irq, data); +err_free_object: + kfree(data->object_table); +err_free_mem: + input_free_device(input_dev); + kfree(data); + return error; +} + +static int __devexit qt602240_remove(struct i2c_client *client) +{ + struct qt602240_data *data = i2c_get_clientdata(client); + + sysfs_remove_group(&client->dev.kobj, &qt602240_attr_group); + free_irq(data->irq, data); + input_unregister_device(data->input_dev); + kfree(data->object_table); + kfree(data); + + return 0; +} + +#ifdef CONFIG_PM +static int qt602240_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct qt602240_data *data = i2c_get_clientdata(client); + struct input_dev *input_dev = data->input_dev; + + mutex_lock(&input_dev->mutex); + + if (input_dev->users) + qt602240_stop(data); + + mutex_unlock(&input_dev->mutex); + + return 0; +} + +static int qt602240_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct qt602240_data *data = i2c_get_clientdata(client); + struct input_dev *input_dev = data->input_dev; + + /* Soft reset */ + qt602240_write_object(data, QT602240_GEN_COMMAND, + QT602240_COMMAND_RESET, 1); + + msleep(QT602240_RESET_TIME); + + mutex_lock(&input_dev->mutex); + + if (input_dev->users) + qt602240_start(data); + + mutex_unlock(&input_dev->mutex); + + return 0; +} + +static const struct dev_pm_ops qt602240_pm_ops = { + .suspend = qt602240_suspend, + .resume = qt602240_resume, +}; +#endif + +static const struct i2c_device_id qt602240_id[] = { + { "qt602240_ts", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, qt602240_id); + +static struct i2c_driver qt602240_driver = { + .driver = { + .name = "qt602240_ts", + .owner = THIS_MODULE, +#ifdef CONFIG_PM + .pm = &qt602240_pm_ops, +#endif + }, + .probe = qt602240_probe, + .remove = __devexit_p(qt602240_remove), + .id_table = qt602240_id, +}; + +static int __init qt602240_init(void) +{ + return i2c_add_driver(&qt602240_driver); +} + +static void __exit qt602240_exit(void) +{ + i2c_del_driver(&qt602240_driver); +} + +module_init(qt602240_init); +module_exit(qt602240_exit); + +/* Module information */ +MODULE_AUTHOR("Joonyoung Shim "); +MODULE_DESCRIPTION("AT42QT602240/ATMXT224 Touchscreen driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/input/touchscreen/qt602240_ts.c b/drivers/input/touchscreen/qt602240_ts.c deleted file mode 100644 index 4dcb0e872f6a..000000000000 --- a/drivers/input/touchscreen/qt602240_ts.c +++ /dev/null @@ -1,1406 +0,0 @@ -/* - * AT42QT602240/ATMXT224 Touchscreen driver - * - * Copyright (C) 2010 Samsung Electronics Co.Ltd - * Author: Joonyoung Shim - * - * 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. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* Version */ -#define QT602240_VER_20 20 -#define QT602240_VER_21 21 -#define QT602240_VER_22 22 - -/* Slave addresses */ -#define QT602240_APP_LOW 0x4a -#define QT602240_APP_HIGH 0x4b -#define QT602240_BOOT_LOW 0x24 -#define QT602240_BOOT_HIGH 0x25 - -/* Firmware */ -#define QT602240_FW_NAME "qt602240.fw" - -/* Registers */ -#define QT602240_FAMILY_ID 0x00 -#define QT602240_VARIANT_ID 0x01 -#define QT602240_VERSION 0x02 -#define QT602240_BUILD 0x03 -#define QT602240_MATRIX_X_SIZE 0x04 -#define QT602240_MATRIX_Y_SIZE 0x05 -#define QT602240_OBJECT_NUM 0x06 -#define QT602240_OBJECT_START 0x07 - -#define QT602240_OBJECT_SIZE 6 - -/* Object types */ -#define QT602240_DEBUG_DIAGNOSTIC 37 -#define QT602240_GEN_MESSAGE 5 -#define QT602240_GEN_COMMAND 6 -#define QT602240_GEN_POWER 7 -#define QT602240_GEN_ACQUIRE 8 -#define QT602240_TOUCH_MULTI 9 -#define QT602240_TOUCH_KEYARRAY 15 -#define QT602240_TOUCH_PROXIMITY 23 -#define QT602240_PROCI_GRIPFACE 20 -#define QT602240_PROCG_NOISE 22 -#define QT602240_PROCI_ONETOUCH 24 -#define QT602240_PROCI_TWOTOUCH 27 -#define QT602240_SPT_COMMSCONFIG 18 /* firmware ver 21 over */ -#define QT602240_SPT_GPIOPWM 19 -#define QT602240_SPT_SELFTEST 25 -#define QT602240_SPT_CTECONFIG 28 -#define QT602240_SPT_USERDATA 38 /* firmware ver 21 over */ - -/* QT602240_GEN_COMMAND field */ -#define QT602240_COMMAND_RESET 0 -#define QT602240_COMMAND_BACKUPNV 1 -#define QT602240_COMMAND_CALIBRATE 2 -#define QT602240_COMMAND_REPORTALL 3 -#define QT602240_COMMAND_DIAGNOSTIC 5 - -/* QT602240_GEN_POWER field */ -#define QT602240_POWER_IDLEACQINT 0 -#define QT602240_POWER_ACTVACQINT 1 -#define QT602240_POWER_ACTV2IDLETO 2 - -/* QT602240_GEN_ACQUIRE field */ -#define QT602240_ACQUIRE_CHRGTIME 0 -#define QT602240_ACQUIRE_TCHDRIFT 2 -#define QT602240_ACQUIRE_DRIFTST 3 -#define QT602240_ACQUIRE_TCHAUTOCAL 4 -#define QT602240_ACQUIRE_SYNC 5 -#define QT602240_ACQUIRE_ATCHCALST 6 -#define QT602240_ACQUIRE_ATCHCALSTHR 7 - -/* QT602240_TOUCH_MULTI field */ -#define QT602240_TOUCH_CTRL 0 -#define QT602240_TOUCH_XORIGIN 1 -#define QT602240_TOUCH_YORIGIN 2 -#define QT602240_TOUCH_XSIZE 3 -#define QT602240_TOUCH_YSIZE 4 -#define QT602240_TOUCH_BLEN 6 -#define QT602240_TOUCH_TCHTHR 7 -#define QT602240_TOUCH_TCHDI 8 -#define QT602240_TOUCH_ORIENT 9 -#define QT602240_TOUCH_MOVHYSTI 11 -#define QT602240_TOUCH_MOVHYSTN 12 -#define QT602240_TOUCH_NUMTOUCH 14 -#define QT602240_TOUCH_MRGHYST 15 -#define QT602240_TOUCH_MRGTHR 16 -#define QT602240_TOUCH_AMPHYST 17 -#define QT602240_TOUCH_XRANGE_LSB 18 -#define QT602240_TOUCH_XRANGE_MSB 19 -#define QT602240_TOUCH_YRANGE_LSB 20 -#define QT602240_TOUCH_YRANGE_MSB 21 -#define QT602240_TOUCH_XLOCLIP 22 -#define QT602240_TOUCH_XHICLIP 23 -#define QT602240_TOUCH_YLOCLIP 24 -#define QT602240_TOUCH_YHICLIP 25 -#define QT602240_TOUCH_XEDGECTRL 26 -#define QT602240_TOUCH_XEDGEDIST 27 -#define QT602240_TOUCH_YEDGECTRL 28 -#define QT602240_TOUCH_YEDGEDIST 29 -#define QT602240_TOUCH_JUMPLIMIT 30 /* firmware ver 22 over */ - -/* QT602240_PROCI_GRIPFACE field */ -#define QT602240_GRIPFACE_CTRL 0 -#define QT602240_GRIPFACE_XLOGRIP 1 -#define QT602240_GRIPFACE_XHIGRIP 2 -#define QT602240_GRIPFACE_YLOGRIP 3 -#define QT602240_GRIPFACE_YHIGRIP 4 -#define QT602240_GRIPFACE_MAXTCHS 5 -#define QT602240_GRIPFACE_SZTHR1 7 -#define QT602240_GRIPFACE_SZTHR2 8 -#define QT602240_GRIPFACE_SHPTHR1 9 -#define QT602240_GRIPFACE_SHPTHR2 10 -#define QT602240_GRIPFACE_SUPEXTTO 11 - -/* QT602240_PROCI_NOISE field */ -#define QT602240_NOISE_CTRL 0 -#define QT602240_NOISE_OUTFLEN 1 -#define QT602240_NOISE_GCAFUL_LSB 3 -#define QT602240_NOISE_GCAFUL_MSB 4 -#define QT602240_NOISE_GCAFLL_LSB 5 -#define QT602240_NOISE_GCAFLL_MSB 6 -#define QT602240_NOISE_ACTVGCAFVALID 7 -#define QT602240_NOISE_NOISETHR 8 -#define QT602240_NOISE_FREQHOPSCALE 10 -#define QT602240_NOISE_FREQ0 11 -#define QT602240_NOISE_FREQ1 12 -#define QT602240_NOISE_FREQ2 13 -#define QT602240_NOISE_FREQ3 14 -#define QT602240_NOISE_FREQ4 15 -#define QT602240_NOISE_IDLEGCAFVALID 16 - -/* QT602240_SPT_COMMSCONFIG */ -#define QT602240_COMMS_CTRL 0 -#define QT602240_COMMS_CMD 1 - -/* QT602240_SPT_CTECONFIG field */ -#define QT602240_CTE_CTRL 0 -#define QT602240_CTE_CMD 1 -#define QT602240_CTE_MODE 2 -#define QT602240_CTE_IDLEGCAFDEPTH 3 -#define QT602240_CTE_ACTVGCAFDEPTH 4 -#define QT602240_CTE_VOLTAGE 5 /* firmware ver 21 over */ - -#define QT602240_VOLTAGE_DEFAULT 2700000 -#define QT602240_VOLTAGE_STEP 10000 - -/* Define for QT602240_GEN_COMMAND */ -#define QT602240_BOOT_VALUE 0xa5 -#define QT602240_BACKUP_VALUE 0x55 -#define QT602240_BACKUP_TIME 25 /* msec */ -#define QT602240_RESET_TIME 65 /* msec */ - -#define QT602240_FWRESET_TIME 175 /* msec */ - -/* Command to unlock bootloader */ -#define QT602240_UNLOCK_CMD_MSB 0xaa -#define QT602240_UNLOCK_CMD_LSB 0xdc - -/* Bootloader mode status */ -#define QT602240_WAITING_BOOTLOAD_CMD 0xc0 /* valid 7 6 bit only */ -#define QT602240_WAITING_FRAME_DATA 0x80 /* valid 7 6 bit only */ -#define QT602240_FRAME_CRC_CHECK 0x02 -#define QT602240_FRAME_CRC_FAIL 0x03 -#define QT602240_FRAME_CRC_PASS 0x04 -#define QT602240_APP_CRC_FAIL 0x40 /* valid 7 8 bit only */ -#define QT602240_BOOT_STATUS_MASK 0x3f - -/* Touch status */ -#define QT602240_SUPPRESS (1 << 1) -#define QT602240_AMP (1 << 2) -#define QT602240_VECTOR (1 << 3) -#define QT602240_MOVE (1 << 4) -#define QT602240_RELEASE (1 << 5) -#define QT602240_PRESS (1 << 6) -#define QT602240_DETECT (1 << 7) - -/* Touchscreen absolute values */ -#define QT602240_MAX_XC 0x3ff -#define QT602240_MAX_YC 0x3ff -#define QT602240_MAX_AREA 0xff - -#define QT602240_MAX_FINGER 10 - -/* Initial register values recommended from chip vendor */ -static const u8 init_vals_ver_20[] = { - /* QT602240_GEN_COMMAND(6) */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* QT602240_GEN_POWER(7) */ - 0x20, 0xff, 0x32, - /* QT602240_GEN_ACQUIRE(8) */ - 0x08, 0x05, 0x05, 0x00, 0x00, 0x00, 0x05, 0x14, - /* QT602240_TOUCH_MULTI(9) */ - 0x00, 0x00, 0x00, 0x11, 0x0a, 0x00, 0x00, 0x00, 0x02, 0x00, - 0x00, 0x01, 0x01, 0x0e, 0x0a, 0x0a, 0x0a, 0x0a, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x64, - /* QT602240_TOUCH_KEYARRAY(15) */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, - /* QT602240_SPT_GPIOPWM(19) */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, - /* QT602240_PROCI_GRIPFACE(20) */ - 0x00, 0x64, 0x64, 0x64, 0x64, 0x00, 0x00, 0x1e, 0x14, 0x04, - 0x1e, 0x00, - /* QT602240_PROCG_NOISE(22) */ - 0x05, 0x00, 0x00, 0x19, 0x00, 0xe7, 0xff, 0x04, 0x32, 0x00, - 0x01, 0x0a, 0x0f, 0x14, 0x00, 0x00, 0xe8, - /* QT602240_TOUCH_PROXIMITY(23) */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, - /* QT602240_PROCI_ONETOUCH(24) */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* QT602240_SPT_SELFTEST(25) */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - /* QT602240_PROCI_TWOTOUCH(27) */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* QT602240_SPT_CTECONFIG(28) */ - 0x00, 0x00, 0x00, 0x04, 0x08, -}; - -static const u8 init_vals_ver_21[] = { - /* QT602240_GEN_COMMAND(6) */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* QT602240_GEN_POWER(7) */ - 0x20, 0xff, 0x32, - /* QT602240_GEN_ACQUIRE(8) */ - 0x0a, 0x00, 0x05, 0x00, 0x00, 0x00, 0x09, 0x23, - /* QT602240_TOUCH_MULTI(9) */ - 0x00, 0x00, 0x00, 0x13, 0x0b, 0x00, 0x00, 0x00, 0x02, 0x00, - 0x00, 0x01, 0x01, 0x0e, 0x0a, 0x0a, 0x0a, 0x0a, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* QT602240_TOUCH_KEYARRAY(15) */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, - /* QT602240_SPT_GPIOPWM(19) */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* QT602240_PROCI_GRIPFACE(20) */ - 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x28, 0x04, - 0x0f, 0x0a, - /* QT602240_PROCG_NOISE(22) */ - 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x23, 0x00, - 0x00, 0x05, 0x0f, 0x19, 0x23, 0x2d, 0x03, - /* QT602240_TOUCH_PROXIMITY(23) */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, - /* QT602240_PROCI_ONETOUCH(24) */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* QT602240_SPT_SELFTEST(25) */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - /* QT602240_PROCI_TWOTOUCH(27) */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* QT602240_SPT_CTECONFIG(28) */ - 0x00, 0x00, 0x00, 0x08, 0x10, 0x00, -}; - -static const u8 init_vals_ver_22[] = { - /* QT602240_GEN_COMMAND(6) */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* QT602240_GEN_POWER(7) */ - 0x20, 0xff, 0x32, - /* QT602240_GEN_ACQUIRE(8) */ - 0x0a, 0x00, 0x05, 0x00, 0x00, 0x00, 0x09, 0x23, - /* QT602240_TOUCH_MULTI(9) */ - 0x00, 0x00, 0x00, 0x13, 0x0b, 0x00, 0x00, 0x00, 0x02, 0x00, - 0x00, 0x01, 0x01, 0x0e, 0x0a, 0x0a, 0x0a, 0x0a, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, - /* QT602240_TOUCH_KEYARRAY(15) */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, - /* QT602240_SPT_GPIOPWM(19) */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* QT602240_PROCI_GRIPFACE(20) */ - 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x28, 0x04, - 0x0f, 0x0a, - /* QT602240_PROCG_NOISE(22) */ - 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x23, 0x00, - 0x00, 0x05, 0x0f, 0x19, 0x23, 0x2d, 0x03, - /* QT602240_TOUCH_PROXIMITY(23) */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, - /* QT602240_PROCI_ONETOUCH(24) */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* QT602240_SPT_SELFTEST(25) */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - /* QT602240_PROCI_TWOTOUCH(27) */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* QT602240_SPT_CTECONFIG(28) */ - 0x00, 0x00, 0x00, 0x08, 0x10, 0x00, -}; - -struct qt602240_info { - u8 family_id; - u8 variant_id; - u8 version; - u8 build; - u8 matrix_xsize; - u8 matrix_ysize; - u8 object_num; -}; - -struct qt602240_object { - u8 type; - u16 start_address; - u8 size; - u8 instances; - u8 num_report_ids; - - /* to map object and message */ - u8 max_reportid; -}; - -struct qt602240_message { - u8 reportid; - u8 message[7]; - u8 checksum; -}; - -struct qt602240_finger { - int status; - int x; - int y; - int area; -}; - -/* Each client has this additional data */ -struct qt602240_data { - struct i2c_client *client; - struct input_dev *input_dev; - const struct qt602240_platform_data *pdata; - struct qt602240_object *object_table; - struct qt602240_info info; - struct qt602240_finger finger[QT602240_MAX_FINGER]; - unsigned int irq; -}; - -static bool qt602240_object_readable(unsigned int type) -{ - switch (type) { - case QT602240_GEN_MESSAGE: - case QT602240_GEN_COMMAND: - case QT602240_GEN_POWER: - case QT602240_GEN_ACQUIRE: - case QT602240_TOUCH_MULTI: - case QT602240_TOUCH_KEYARRAY: - case QT602240_TOUCH_PROXIMITY: - case QT602240_PROCI_GRIPFACE: - case QT602240_PROCG_NOISE: - case QT602240_PROCI_ONETOUCH: - case QT602240_PROCI_TWOTOUCH: - case QT602240_SPT_COMMSCONFIG: - case QT602240_SPT_GPIOPWM: - case QT602240_SPT_SELFTEST: - case QT602240_SPT_CTECONFIG: - case QT602240_SPT_USERDATA: - return true; - default: - return false; - } -} - -static bool qt602240_object_writable(unsigned int type) -{ - switch (type) { - case QT602240_GEN_COMMAND: - case QT602240_GEN_POWER: - case QT602240_GEN_ACQUIRE: - case QT602240_TOUCH_MULTI: - case QT602240_TOUCH_KEYARRAY: - case QT602240_TOUCH_PROXIMITY: - case QT602240_PROCI_GRIPFACE: - case QT602240_PROCG_NOISE: - case QT602240_PROCI_ONETOUCH: - case QT602240_PROCI_TWOTOUCH: - case QT602240_SPT_GPIOPWM: - case QT602240_SPT_SELFTEST: - case QT602240_SPT_CTECONFIG: - return true; - default: - return false; - } -} - -static void qt602240_dump_message(struct device *dev, - struct qt602240_message *message) -{ - dev_dbg(dev, "reportid:\t0x%x\n", message->reportid); - dev_dbg(dev, "message1:\t0x%x\n", message->message[0]); - dev_dbg(dev, "message2:\t0x%x\n", message->message[1]); - dev_dbg(dev, "message3:\t0x%x\n", message->message[2]); - dev_dbg(dev, "message4:\t0x%x\n", message->message[3]); - dev_dbg(dev, "message5:\t0x%x\n", message->message[4]); - dev_dbg(dev, "message6:\t0x%x\n", message->message[5]); - dev_dbg(dev, "message7:\t0x%x\n", message->message[6]); - dev_dbg(dev, "checksum:\t0x%x\n", message->checksum); -} - -static int qt602240_check_bootloader(struct i2c_client *client, - unsigned int state) -{ - u8 val; - -recheck: - if (i2c_master_recv(client, &val, 1) != 1) { - dev_err(&client->dev, "%s: i2c recv failed\n", __func__); - return -EIO; - } - - switch (state) { - case QT602240_WAITING_BOOTLOAD_CMD: - case QT602240_WAITING_FRAME_DATA: - val &= ~QT602240_BOOT_STATUS_MASK; - break; - case QT602240_FRAME_CRC_PASS: - if (val == QT602240_FRAME_CRC_CHECK) - goto recheck; - break; - default: - return -EINVAL; - } - - if (val != state) { - dev_err(&client->dev, "Unvalid bootloader mode state\n"); - return -EINVAL; - } - - return 0; -} - -static int qt602240_unlock_bootloader(struct i2c_client *client) -{ - u8 buf[2]; - - buf[0] = QT602240_UNLOCK_CMD_LSB; - buf[1] = QT602240_UNLOCK_CMD_MSB; - - if (i2c_master_send(client, buf, 2) != 2) { - dev_err(&client->dev, "%s: i2c send failed\n", __func__); - return -EIO; - } - - return 0; -} - -static int qt602240_fw_write(struct i2c_client *client, - const u8 *data, unsigned int frame_size) -{ - if (i2c_master_send(client, data, frame_size) != frame_size) { - dev_err(&client->dev, "%s: i2c send failed\n", __func__); - return -EIO; - } - - return 0; -} - -static int __qt602240_read_reg(struct i2c_client *client, - u16 reg, u16 len, void *val) -{ - struct i2c_msg xfer[2]; - u8 buf[2]; - - buf[0] = reg & 0xff; - buf[1] = (reg >> 8) & 0xff; - - /* Write register */ - xfer[0].addr = client->addr; - xfer[0].flags = 0; - xfer[0].len = 2; - xfer[0].buf = buf; - - /* Read data */ - xfer[1].addr = client->addr; - xfer[1].flags = I2C_M_RD; - xfer[1].len = len; - xfer[1].buf = val; - - if (i2c_transfer(client->adapter, xfer, 2) != 2) { - dev_err(&client->dev, "%s: i2c transfer failed\n", __func__); - return -EIO; - } - - return 0; -} - -static int qt602240_read_reg(struct i2c_client *client, u16 reg, u8 *val) -{ - return __qt602240_read_reg(client, reg, 1, val); -} - -static int qt602240_write_reg(struct i2c_client *client, u16 reg, u8 val) -{ - u8 buf[3]; - - buf[0] = reg & 0xff; - buf[1] = (reg >> 8) & 0xff; - buf[2] = val; - - if (i2c_master_send(client, buf, 3) != 3) { - dev_err(&client->dev, "%s: i2c send failed\n", __func__); - return -EIO; - } - - return 0; -} - -static int qt602240_read_object_table(struct i2c_client *client, - u16 reg, u8 *object_buf) -{ - return __qt602240_read_reg(client, reg, QT602240_OBJECT_SIZE, - object_buf); -} - -static struct qt602240_object * -qt602240_get_object(struct qt602240_data *data, u8 type) -{ - struct qt602240_object *object; - int i; - - for (i = 0; i < data->info.object_num; i++) { - object = data->object_table + i; - if (object->type == type) - return object; - } - - dev_err(&data->client->dev, "Invalid object type\n"); - return NULL; -} - -static int qt602240_read_message(struct qt602240_data *data, - struct qt602240_message *message) -{ - struct qt602240_object *object; - u16 reg; - - object = qt602240_get_object(data, QT602240_GEN_MESSAGE); - if (!object) - return -EINVAL; - - reg = object->start_address; - return __qt602240_read_reg(data->client, reg, - sizeof(struct qt602240_message), message); -} - -static int qt602240_read_object(struct qt602240_data *data, - u8 type, u8 offset, u8 *val) -{ - struct qt602240_object *object; - u16 reg; - - object = qt602240_get_object(data, type); - if (!object) - return -EINVAL; - - reg = object->start_address; - return __qt602240_read_reg(data->client, reg + offset, 1, val); -} - -static int qt602240_write_object(struct qt602240_data *data, - u8 type, u8 offset, u8 val) -{ - struct qt602240_object *object; - u16 reg; - - object = qt602240_get_object(data, type); - if (!object) - return -EINVAL; - - reg = object->start_address; - return qt602240_write_reg(data->client, reg + offset, val); -} - -static void qt602240_input_report(struct qt602240_data *data, int single_id) -{ - struct qt602240_finger *finger = data->finger; - struct input_dev *input_dev = data->input_dev; - int status = finger[single_id].status; - int finger_num = 0; - int id; - - for (id = 0; id < QT602240_MAX_FINGER; id++) { - if (!finger[id].status) - continue; - - input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR, - finger[id].status != QT602240_RELEASE ? - finger[id].area : 0); - input_report_abs(input_dev, ABS_MT_POSITION_X, - finger[id].x); - input_report_abs(input_dev, ABS_MT_POSITION_Y, - finger[id].y); - input_mt_sync(input_dev); - - if (finger[id].status == QT602240_RELEASE) - finger[id].status = 0; - else - finger_num++; - } - - input_report_key(input_dev, BTN_TOUCH, finger_num > 0); - - if (status != QT602240_RELEASE) { - input_report_abs(input_dev, ABS_X, finger[single_id].x); - input_report_abs(input_dev, ABS_Y, finger[single_id].y); - } - - input_sync(input_dev); -} - -static void qt602240_input_touchevent(struct qt602240_data *data, - struct qt602240_message *message, int id) -{ - struct qt602240_finger *finger = data->finger; - struct device *dev = &data->client->dev; - u8 status = message->message[0]; - int x; - int y; - int area; - - /* Check the touch is present on the screen */ - if (!(status & QT602240_DETECT)) { - if (status & QT602240_RELEASE) { - dev_dbg(dev, "[%d] released\n", id); - - finger[id].status = QT602240_RELEASE; - qt602240_input_report(data, id); - } - return; - } - - /* Check only AMP detection */ - if (!(status & (QT602240_PRESS | QT602240_MOVE))) - return; - - x = (message->message[1] << 2) | ((message->message[3] & ~0x3f) >> 6); - y = (message->message[2] << 2) | ((message->message[3] & ~0xf3) >> 2); - area = message->message[4]; - - dev_dbg(dev, "[%d] %s x: %d, y: %d, area: %d\n", id, - status & QT602240_MOVE ? "moved" : "pressed", - x, y, area); - - finger[id].status = status & QT602240_MOVE ? - QT602240_MOVE : QT602240_PRESS; - finger[id].x = x; - finger[id].y = y; - finger[id].area = area; - - qt602240_input_report(data, id); -} - -static irqreturn_t qt602240_interrupt(int irq, void *dev_id) -{ - struct qt602240_data *data = dev_id; - struct qt602240_message message; - struct qt602240_object *object; - struct device *dev = &data->client->dev; - int id; - u8 reportid; - u8 max_reportid; - u8 min_reportid; - - do { - if (qt602240_read_message(data, &message)) { - dev_err(dev, "Failed to read message\n"); - goto end; - } - - reportid = message.reportid; - - /* whether reportid is thing of QT602240_TOUCH_MULTI */ - object = qt602240_get_object(data, QT602240_TOUCH_MULTI); - if (!object) - goto end; - - max_reportid = object->max_reportid; - min_reportid = max_reportid - object->num_report_ids + 1; - id = reportid - min_reportid; - - if (reportid >= min_reportid && reportid <= max_reportid) - qt602240_input_touchevent(data, &message, id); - else - qt602240_dump_message(dev, &message); - } while (reportid != 0xff); - -end: - return IRQ_HANDLED; -} - -static int qt602240_check_reg_init(struct qt602240_data *data) -{ - struct qt602240_object *object; - struct device *dev = &data->client->dev; - int index = 0; - int i, j; - u8 version = data->info.version; - u8 *init_vals; - - switch (version) { - case QT602240_VER_20: - init_vals = (u8 *)init_vals_ver_20; - break; - case QT602240_VER_21: - init_vals = (u8 *)init_vals_ver_21; - break; - case QT602240_VER_22: - init_vals = (u8 *)init_vals_ver_22; - break; - default: - dev_err(dev, "Firmware version %d doesn't support\n", version); - return -EINVAL; - } - - for (i = 0; i < data->info.object_num; i++) { - object = data->object_table + i; - - if (!qt602240_object_writable(object->type)) - continue; - - for (j = 0; j < object->size + 1; j++) - qt602240_write_object(data, object->type, j, - init_vals[index + j]); - - index += object->size + 1; - } - - return 0; -} - -static int qt602240_check_matrix_size(struct qt602240_data *data) -{ - const struct qt602240_platform_data *pdata = data->pdata; - struct device *dev = &data->client->dev; - int mode = -1; - int error; - u8 val; - - dev_dbg(dev, "Number of X lines: %d\n", pdata->x_line); - dev_dbg(dev, "Number of Y lines: %d\n", pdata->y_line); - - switch (pdata->x_line) { - case 0 ... 15: - if (pdata->y_line <= 14) - mode = 0; - break; - case 16: - if (pdata->y_line <= 12) - mode = 1; - if (pdata->y_line == 13 || pdata->y_line == 14) - mode = 0; - break; - case 17: - if (pdata->y_line <= 11) - mode = 2; - if (pdata->y_line == 12 || pdata->y_line == 13) - mode = 1; - break; - case 18: - if (pdata->y_line <= 10) - mode = 3; - if (pdata->y_line == 11 || pdata->y_line == 12) - mode = 2; - break; - case 19: - if (pdata->y_line <= 9) - mode = 4; - if (pdata->y_line == 10 || pdata->y_line == 11) - mode = 3; - break; - case 20: - mode = 4; - } - - if (mode < 0) { - dev_err(dev, "Invalid X/Y lines\n"); - return -EINVAL; - } - - error = qt602240_read_object(data, QT602240_SPT_CTECONFIG, - QT602240_CTE_MODE, &val); - if (error) - return error; - - if (mode == val) - return 0; - - /* Change the CTE configuration */ - qt602240_write_object(data, QT602240_SPT_CTECONFIG, - QT602240_CTE_CTRL, 1); - qt602240_write_object(data, QT602240_SPT_CTECONFIG, - QT602240_CTE_MODE, mode); - qt602240_write_object(data, QT602240_SPT_CTECONFIG, - QT602240_CTE_CTRL, 0); - - return 0; -} - -static int qt602240_make_highchg(struct qt602240_data *data) -{ - struct device *dev = &data->client->dev; - int count = 10; - int error; - u8 val; - - /* Read dummy message to make high CHG pin */ - do { - error = qt602240_read_object(data, QT602240_GEN_MESSAGE, 0, &val); - if (error) - return error; - } while ((val != 0xff) && --count); - - if (!count) { - dev_err(dev, "CHG pin isn't cleared\n"); - return -EBUSY; - } - - return 0; -} - -static void qt602240_handle_pdata(struct qt602240_data *data) -{ - const struct qt602240_platform_data *pdata = data->pdata; - u8 voltage; - - /* Set touchscreen lines */ - qt602240_write_object(data, QT602240_TOUCH_MULTI, QT602240_TOUCH_XSIZE, - pdata->x_line); - qt602240_write_object(data, QT602240_TOUCH_MULTI, QT602240_TOUCH_YSIZE, - pdata->y_line); - - /* Set touchscreen orient */ - qt602240_write_object(data, QT602240_TOUCH_MULTI, QT602240_TOUCH_ORIENT, - pdata->orient); - - /* Set touchscreen burst length */ - qt602240_write_object(data, QT602240_TOUCH_MULTI, - QT602240_TOUCH_BLEN, pdata->blen); - - /* Set touchscreen threshold */ - qt602240_write_object(data, QT602240_TOUCH_MULTI, - QT602240_TOUCH_TCHTHR, pdata->threshold); - - /* Set touchscreen resolution */ - qt602240_write_object(data, QT602240_TOUCH_MULTI, - QT602240_TOUCH_XRANGE_LSB, (pdata->x_size - 1) & 0xff); - qt602240_write_object(data, QT602240_TOUCH_MULTI, - QT602240_TOUCH_XRANGE_MSB, (pdata->x_size - 1) >> 8); - qt602240_write_object(data, QT602240_TOUCH_MULTI, - QT602240_TOUCH_YRANGE_LSB, (pdata->y_size - 1) & 0xff); - qt602240_write_object(data, QT602240_TOUCH_MULTI, - QT602240_TOUCH_YRANGE_MSB, (pdata->y_size - 1) >> 8); - - /* Set touchscreen voltage */ - if (data->info.version >= QT602240_VER_21 && pdata->voltage) { - if (pdata->voltage < QT602240_VOLTAGE_DEFAULT) { - voltage = (QT602240_VOLTAGE_DEFAULT - pdata->voltage) / - QT602240_VOLTAGE_STEP; - voltage = 0xff - voltage + 1; - } else - voltage = (pdata->voltage - QT602240_VOLTAGE_DEFAULT) / - QT602240_VOLTAGE_STEP; - - qt602240_write_object(data, QT602240_SPT_CTECONFIG, - QT602240_CTE_VOLTAGE, voltage); - } -} - -static int qt602240_get_info(struct qt602240_data *data) -{ - struct i2c_client *client = data->client; - struct qt602240_info *info = &data->info; - int error; - u8 val; - - error = qt602240_read_reg(client, QT602240_FAMILY_ID, &val); - if (error) - return error; - info->family_id = val; - - error = qt602240_read_reg(client, QT602240_VARIANT_ID, &val); - if (error) - return error; - info->variant_id = val; - - error = qt602240_read_reg(client, QT602240_VERSION, &val); - if (error) - return error; - info->version = val; - - error = qt602240_read_reg(client, QT602240_BUILD, &val); - if (error) - return error; - info->build = val; - - error = qt602240_read_reg(client, QT602240_OBJECT_NUM, &val); - if (error) - return error; - info->object_num = val; - - return 0; -} - -static int qt602240_get_object_table(struct qt602240_data *data) -{ - int error; - int i; - u16 reg; - u8 reportid = 0; - u8 buf[QT602240_OBJECT_SIZE]; - - for (i = 0; i < data->info.object_num; i++) { - struct qt602240_object *object = data->object_table + i; - - reg = QT602240_OBJECT_START + QT602240_OBJECT_SIZE * i; - error = qt602240_read_object_table(data->client, reg, buf); - if (error) - return error; - - object->type = buf[0]; - object->start_address = (buf[2] << 8) | buf[1]; - object->size = buf[3]; - object->instances = buf[4]; - object->num_report_ids = buf[5]; - - if (object->num_report_ids) { - reportid += object->num_report_ids * - (object->instances + 1); - object->max_reportid = reportid; - } - } - - return 0; -} - -static int qt602240_initialize(struct qt602240_data *data) -{ - struct i2c_client *client = data->client; - struct qt602240_info *info = &data->info; - int error; - u8 val; - - error = qt602240_get_info(data); - if (error) - return error; - - data->object_table = kcalloc(info->object_num, - sizeof(struct qt602240_object), - GFP_KERNEL); - if (!data->object_table) { - dev_err(&client->dev, "Failed to allocate memory\n"); - return -ENOMEM; - } - - /* Get object table information */ - error = qt602240_get_object_table(data); - if (error) - return error; - - /* Check register init values */ - error = qt602240_check_reg_init(data); - if (error) - return error; - - /* Check X/Y matrix size */ - error = qt602240_check_matrix_size(data); - if (error) - return error; - - error = qt602240_make_highchg(data); - if (error) - return error; - - qt602240_handle_pdata(data); - - /* Backup to memory */ - qt602240_write_object(data, QT602240_GEN_COMMAND, - QT602240_COMMAND_BACKUPNV, - QT602240_BACKUP_VALUE); - msleep(QT602240_BACKUP_TIME); - - /* Soft reset */ - qt602240_write_object(data, QT602240_GEN_COMMAND, - QT602240_COMMAND_RESET, 1); - msleep(QT602240_RESET_TIME); - - /* Update matrix size at info struct */ - error = qt602240_read_reg(client, QT602240_MATRIX_X_SIZE, &val); - if (error) - return error; - info->matrix_xsize = val; - - error = qt602240_read_reg(client, QT602240_MATRIX_Y_SIZE, &val); - if (error) - return error; - info->matrix_ysize = val; - - dev_info(&client->dev, - "Family ID: %d Variant ID: %d Version: %d Build: %d\n", - info->family_id, info->variant_id, info->version, - info->build); - - dev_info(&client->dev, - "Matrix X Size: %d Matrix Y Size: %d Object Num: %d\n", - info->matrix_xsize, info->matrix_ysize, - info->object_num); - - return 0; -} - -static ssize_t qt602240_object_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct qt602240_data *data = dev_get_drvdata(dev); - struct qt602240_object *object; - int count = 0; - int i, j; - int error; - u8 val; - - for (i = 0; i < data->info.object_num; i++) { - object = data->object_table + i; - - count += sprintf(buf + count, - "Object Table Element %d(Type %d)\n", - i + 1, object->type); - - if (!qt602240_object_readable(object->type)) { - count += sprintf(buf + count, "\n"); - continue; - } - - for (j = 0; j < object->size + 1; j++) { - error = qt602240_read_object(data, - object->type, j, &val); - if (error) - return error; - - count += sprintf(buf + count, - " Byte %d: 0x%x (%d)\n", j, val, val); - } - - count += sprintf(buf + count, "\n"); - } - - return count; -} - -static int qt602240_load_fw(struct device *dev, const char *fn) -{ - struct qt602240_data *data = dev_get_drvdata(dev); - struct i2c_client *client = data->client; - const struct firmware *fw = NULL; - unsigned int frame_size; - unsigned int pos = 0; - int ret; - - ret = request_firmware(&fw, fn, dev); - if (ret) { - dev_err(dev, "Unable to open firmware %s\n", fn); - return ret; - } - - /* Change to the bootloader mode */ - qt602240_write_object(data, QT602240_GEN_COMMAND, - QT602240_COMMAND_RESET, QT602240_BOOT_VALUE); - msleep(QT602240_RESET_TIME); - - /* Change to slave address of bootloader */ - if (client->addr == QT602240_APP_LOW) - client->addr = QT602240_BOOT_LOW; - else - client->addr = QT602240_BOOT_HIGH; - - ret = qt602240_check_bootloader(client, QT602240_WAITING_BOOTLOAD_CMD); - if (ret) - goto out; - - /* Unlock bootloader */ - qt602240_unlock_bootloader(client); - - while (pos < fw->size) { - ret = qt602240_check_bootloader(client, - QT602240_WAITING_FRAME_DATA); - if (ret) - goto out; - - frame_size = ((*(fw->data + pos) << 8) | *(fw->data + pos + 1)); - - /* We should add 2 at frame size as the the firmware data is not - * included the CRC bytes. - */ - frame_size += 2; - - /* Write one frame to device */ - qt602240_fw_write(client, fw->data + pos, frame_size); - - ret = qt602240_check_bootloader(client, - QT602240_FRAME_CRC_PASS); - if (ret) - goto out; - - pos += frame_size; - - dev_dbg(dev, "Updated %d bytes / %zd bytes\n", pos, fw->size); - } - -out: - release_firmware(fw); - - /* Change to slave address of application */ - if (client->addr == QT602240_BOOT_LOW) - client->addr = QT602240_APP_LOW; - else - client->addr = QT602240_APP_HIGH; - - return ret; -} - -static ssize_t qt602240_update_fw_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct qt602240_data *data = dev_get_drvdata(dev); - unsigned int version; - int error; - - if (sscanf(buf, "%u", &version) != 1) { - dev_err(dev, "Invalid values\n"); - return -EINVAL; - } - - if (data->info.version < QT602240_VER_21 || version < QT602240_VER_21) { - dev_err(dev, "FW update supported starting with version 21\n"); - return -EINVAL; - } - - disable_irq(data->irq); - - error = qt602240_load_fw(dev, QT602240_FW_NAME); - if (error) { - dev_err(dev, "The firmware update failed(%d)\n", error); - count = error; - } else { - dev_dbg(dev, "The firmware update succeeded\n"); - - /* Wait for reset */ - msleep(QT602240_FWRESET_TIME); - - kfree(data->object_table); - data->object_table = NULL; - - qt602240_initialize(data); - } - - enable_irq(data->irq); - - return count; -} - -static DEVICE_ATTR(object, 0444, qt602240_object_show, NULL); -static DEVICE_ATTR(update_fw, 0664, NULL, qt602240_update_fw_store); - -static struct attribute *qt602240_attrs[] = { - &dev_attr_object.attr, - &dev_attr_update_fw.attr, - NULL -}; - -static const struct attribute_group qt602240_attr_group = { - .attrs = qt602240_attrs, -}; - -static void qt602240_start(struct qt602240_data *data) -{ - /* Touch enable */ - qt602240_write_object(data, - QT602240_TOUCH_MULTI, QT602240_TOUCH_CTRL, 0x83); -} - -static void qt602240_stop(struct qt602240_data *data) -{ - /* Touch disable */ - qt602240_write_object(data, - QT602240_TOUCH_MULTI, QT602240_TOUCH_CTRL, 0); -} - -static int qt602240_input_open(struct input_dev *dev) -{ - struct qt602240_data *data = input_get_drvdata(dev); - - qt602240_start(data); - - return 0; -} - -static void qt602240_input_close(struct input_dev *dev) -{ - struct qt602240_data *data = input_get_drvdata(dev); - - qt602240_stop(data); -} - -static int __devinit qt602240_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct qt602240_data *data; - struct input_dev *input_dev; - int error; - - if (!client->dev.platform_data) - return -EINVAL; - - data = kzalloc(sizeof(struct qt602240_data), GFP_KERNEL); - input_dev = input_allocate_device(); - if (!data || !input_dev) { - dev_err(&client->dev, "Failed to allocate memory\n"); - error = -ENOMEM; - goto err_free_mem; - } - - input_dev->name = "AT42QT602240/ATMXT224 Touchscreen"; - input_dev->id.bustype = BUS_I2C; - input_dev->dev.parent = &client->dev; - input_dev->open = qt602240_input_open; - input_dev->close = qt602240_input_close; - - __set_bit(EV_ABS, input_dev->evbit); - __set_bit(EV_KEY, input_dev->evbit); - __set_bit(BTN_TOUCH, input_dev->keybit); - - /* For single touch */ - input_set_abs_params(input_dev, ABS_X, - 0, QT602240_MAX_XC, 0, 0); - input_set_abs_params(input_dev, ABS_Y, - 0, QT602240_MAX_YC, 0, 0); - - /* For multi touch */ - input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, - 0, QT602240_MAX_AREA, 0, 0); - input_set_abs_params(input_dev, ABS_MT_POSITION_X, - 0, QT602240_MAX_XC, 0, 0); - input_set_abs_params(input_dev, ABS_MT_POSITION_Y, - 0, QT602240_MAX_YC, 0, 0); - - input_set_drvdata(input_dev, data); - - data->client = client; - data->input_dev = input_dev; - data->pdata = client->dev.platform_data; - data->irq = client->irq; - - i2c_set_clientdata(client, data); - - error = qt602240_initialize(data); - if (error) - goto err_free_object; - - error = request_threaded_irq(client->irq, NULL, qt602240_interrupt, - IRQF_TRIGGER_FALLING, client->dev.driver->name, data); - if (error) { - dev_err(&client->dev, "Failed to register interrupt\n"); - goto err_free_object; - } - - error = input_register_device(input_dev); - if (error) - goto err_free_irq; - - error = sysfs_create_group(&client->dev.kobj, &qt602240_attr_group); - if (error) - goto err_unregister_device; - - return 0; - -err_unregister_device: - input_unregister_device(input_dev); - input_dev = NULL; -err_free_irq: - free_irq(client->irq, data); -err_free_object: - kfree(data->object_table); -err_free_mem: - input_free_device(input_dev); - kfree(data); - return error; -} - -static int __devexit qt602240_remove(struct i2c_client *client) -{ - struct qt602240_data *data = i2c_get_clientdata(client); - - sysfs_remove_group(&client->dev.kobj, &qt602240_attr_group); - free_irq(data->irq, data); - input_unregister_device(data->input_dev); - kfree(data->object_table); - kfree(data); - - return 0; -} - -#ifdef CONFIG_PM -static int qt602240_suspend(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct qt602240_data *data = i2c_get_clientdata(client); - struct input_dev *input_dev = data->input_dev; - - mutex_lock(&input_dev->mutex); - - if (input_dev->users) - qt602240_stop(data); - - mutex_unlock(&input_dev->mutex); - - return 0; -} - -static int qt602240_resume(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct qt602240_data *data = i2c_get_clientdata(client); - struct input_dev *input_dev = data->input_dev; - - /* Soft reset */ - qt602240_write_object(data, QT602240_GEN_COMMAND, - QT602240_COMMAND_RESET, 1); - - msleep(QT602240_RESET_TIME); - - mutex_lock(&input_dev->mutex); - - if (input_dev->users) - qt602240_start(data); - - mutex_unlock(&input_dev->mutex); - - return 0; -} - -static const struct dev_pm_ops qt602240_pm_ops = { - .suspend = qt602240_suspend, - .resume = qt602240_resume, -}; -#endif - -static const struct i2c_device_id qt602240_id[] = { - { "qt602240_ts", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, qt602240_id); - -static struct i2c_driver qt602240_driver = { - .driver = { - .name = "qt602240_ts", - .owner = THIS_MODULE, -#ifdef CONFIG_PM - .pm = &qt602240_pm_ops, -#endif - }, - .probe = qt602240_probe, - .remove = __devexit_p(qt602240_remove), - .id_table = qt602240_id, -}; - -static int __init qt602240_init(void) -{ - return i2c_add_driver(&qt602240_driver); -} - -static void __exit qt602240_exit(void) -{ - i2c_del_driver(&qt602240_driver); -} - -module_init(qt602240_init); -module_exit(qt602240_exit); - -/* Module information */ -MODULE_AUTHOR("Joonyoung Shim "); -MODULE_DESCRIPTION("AT42QT602240/ATMXT224 Touchscreen driver"); -MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 7686b108d8ef5c32f429d5228798636f3a1caf5a Mon Sep 17 00:00:00 2001 From: Iiro Valkonen Date: Wed, 2 Feb 2011 23:21:58 -0800 Subject: Input: atmel_mxt_ts - get rid of qt602240 prefixes in names Change prefixes from qt602240 to mxt to reflect that the driver supports whole line of mXT touchscreens. Signed-off-by: Iiro Valkonen Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/atmel_mxt_ts.c | 929 ++++++++++++++++--------------- 1 file changed, 465 insertions(+), 464 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index 47067789b747..5dca78a00c94 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -1,5 +1,5 @@ /* - * AT42QT602240/ATMXT224 Touchscreen driver + * Atmel maXTouch Touchscreen driver * * Copyright (C) 2010 Samsung Electronics Co.Ltd * Author: Joonyoung Shim @@ -22,300 +22,300 @@ #include /* Version */ -#define QT602240_VER_20 20 -#define QT602240_VER_21 21 -#define QT602240_VER_22 22 +#define MXT_VER_20 20 +#define MXT_VER_21 21 +#define MXT_VER_22 22 /* Slave addresses */ -#define QT602240_APP_LOW 0x4a -#define QT602240_APP_HIGH 0x4b -#define QT602240_BOOT_LOW 0x24 -#define QT602240_BOOT_HIGH 0x25 +#define MXT_APP_LOW 0x4a +#define MXT_APP_HIGH 0x4b +#define MXT_BOOT_LOW 0x24 +#define MXT_BOOT_HIGH 0x25 /* Firmware */ -#define QT602240_FW_NAME "qt602240.fw" +#define MXT_FW_NAME "maxtouch.fw" /* Registers */ -#define QT602240_FAMILY_ID 0x00 -#define QT602240_VARIANT_ID 0x01 -#define QT602240_VERSION 0x02 -#define QT602240_BUILD 0x03 -#define QT602240_MATRIX_X_SIZE 0x04 -#define QT602240_MATRIX_Y_SIZE 0x05 -#define QT602240_OBJECT_NUM 0x06 -#define QT602240_OBJECT_START 0x07 +#define MXT_FAMILY_ID 0x00 +#define MXT_VARIANT_ID 0x01 +#define MXT_VERSION 0x02 +#define MXT_BUILD 0x03 +#define MXT_MATRIX_X_SIZE 0x04 +#define MXT_MATRIX_Y_SIZE 0x05 +#define MXT_OBJECT_NUM 0x06 +#define MXT_OBJECT_START 0x07 -#define QT602240_OBJECT_SIZE 6 +#define MXT_OBJECT_SIZE 6 /* Object types */ -#define QT602240_DEBUG_DIAGNOSTIC 37 -#define QT602240_GEN_MESSAGE 5 -#define QT602240_GEN_COMMAND 6 -#define QT602240_GEN_POWER 7 -#define QT602240_GEN_ACQUIRE 8 -#define QT602240_TOUCH_MULTI 9 -#define QT602240_TOUCH_KEYARRAY 15 -#define QT602240_TOUCH_PROXIMITY 23 -#define QT602240_PROCI_GRIPFACE 20 -#define QT602240_PROCG_NOISE 22 -#define QT602240_PROCI_ONETOUCH 24 -#define QT602240_PROCI_TWOTOUCH 27 -#define QT602240_SPT_COMMSCONFIG 18 /* firmware ver 21 over */ -#define QT602240_SPT_GPIOPWM 19 -#define QT602240_SPT_SELFTEST 25 -#define QT602240_SPT_CTECONFIG 28 -#define QT602240_SPT_USERDATA 38 /* firmware ver 21 over */ - -/* QT602240_GEN_COMMAND field */ -#define QT602240_COMMAND_RESET 0 -#define QT602240_COMMAND_BACKUPNV 1 -#define QT602240_COMMAND_CALIBRATE 2 -#define QT602240_COMMAND_REPORTALL 3 -#define QT602240_COMMAND_DIAGNOSTIC 5 - -/* QT602240_GEN_POWER field */ -#define QT602240_POWER_IDLEACQINT 0 -#define QT602240_POWER_ACTVACQINT 1 -#define QT602240_POWER_ACTV2IDLETO 2 - -/* QT602240_GEN_ACQUIRE field */ -#define QT602240_ACQUIRE_CHRGTIME 0 -#define QT602240_ACQUIRE_TCHDRIFT 2 -#define QT602240_ACQUIRE_DRIFTST 3 -#define QT602240_ACQUIRE_TCHAUTOCAL 4 -#define QT602240_ACQUIRE_SYNC 5 -#define QT602240_ACQUIRE_ATCHCALST 6 -#define QT602240_ACQUIRE_ATCHCALSTHR 7 - -/* QT602240_TOUCH_MULTI field */ -#define QT602240_TOUCH_CTRL 0 -#define QT602240_TOUCH_XORIGIN 1 -#define QT602240_TOUCH_YORIGIN 2 -#define QT602240_TOUCH_XSIZE 3 -#define QT602240_TOUCH_YSIZE 4 -#define QT602240_TOUCH_BLEN 6 -#define QT602240_TOUCH_TCHTHR 7 -#define QT602240_TOUCH_TCHDI 8 -#define QT602240_TOUCH_ORIENT 9 -#define QT602240_TOUCH_MOVHYSTI 11 -#define QT602240_TOUCH_MOVHYSTN 12 -#define QT602240_TOUCH_NUMTOUCH 14 -#define QT602240_TOUCH_MRGHYST 15 -#define QT602240_TOUCH_MRGTHR 16 -#define QT602240_TOUCH_AMPHYST 17 -#define QT602240_TOUCH_XRANGE_LSB 18 -#define QT602240_TOUCH_XRANGE_MSB 19 -#define QT602240_TOUCH_YRANGE_LSB 20 -#define QT602240_TOUCH_YRANGE_MSB 21 -#define QT602240_TOUCH_XLOCLIP 22 -#define QT602240_TOUCH_XHICLIP 23 -#define QT602240_TOUCH_YLOCLIP 24 -#define QT602240_TOUCH_YHICLIP 25 -#define QT602240_TOUCH_XEDGECTRL 26 -#define QT602240_TOUCH_XEDGEDIST 27 -#define QT602240_TOUCH_YEDGECTRL 28 -#define QT602240_TOUCH_YEDGEDIST 29 -#define QT602240_TOUCH_JUMPLIMIT 30 /* firmware ver 22 over */ - -/* QT602240_PROCI_GRIPFACE field */ -#define QT602240_GRIPFACE_CTRL 0 -#define QT602240_GRIPFACE_XLOGRIP 1 -#define QT602240_GRIPFACE_XHIGRIP 2 -#define QT602240_GRIPFACE_YLOGRIP 3 -#define QT602240_GRIPFACE_YHIGRIP 4 -#define QT602240_GRIPFACE_MAXTCHS 5 -#define QT602240_GRIPFACE_SZTHR1 7 -#define QT602240_GRIPFACE_SZTHR2 8 -#define QT602240_GRIPFACE_SHPTHR1 9 -#define QT602240_GRIPFACE_SHPTHR2 10 -#define QT602240_GRIPFACE_SUPEXTTO 11 - -/* QT602240_PROCI_NOISE field */ -#define QT602240_NOISE_CTRL 0 -#define QT602240_NOISE_OUTFLEN 1 -#define QT602240_NOISE_GCAFUL_LSB 3 -#define QT602240_NOISE_GCAFUL_MSB 4 -#define QT602240_NOISE_GCAFLL_LSB 5 -#define QT602240_NOISE_GCAFLL_MSB 6 -#define QT602240_NOISE_ACTVGCAFVALID 7 -#define QT602240_NOISE_NOISETHR 8 -#define QT602240_NOISE_FREQHOPSCALE 10 -#define QT602240_NOISE_FREQ0 11 -#define QT602240_NOISE_FREQ1 12 -#define QT602240_NOISE_FREQ2 13 -#define QT602240_NOISE_FREQ3 14 -#define QT602240_NOISE_FREQ4 15 -#define QT602240_NOISE_IDLEGCAFVALID 16 - -/* QT602240_SPT_COMMSCONFIG */ -#define QT602240_COMMS_CTRL 0 -#define QT602240_COMMS_CMD 1 - -/* QT602240_SPT_CTECONFIG field */ -#define QT602240_CTE_CTRL 0 -#define QT602240_CTE_CMD 1 -#define QT602240_CTE_MODE 2 -#define QT602240_CTE_IDLEGCAFDEPTH 3 -#define QT602240_CTE_ACTVGCAFDEPTH 4 -#define QT602240_CTE_VOLTAGE 5 /* firmware ver 21 over */ - -#define QT602240_VOLTAGE_DEFAULT 2700000 -#define QT602240_VOLTAGE_STEP 10000 - -/* Define for QT602240_GEN_COMMAND */ -#define QT602240_BOOT_VALUE 0xa5 -#define QT602240_BACKUP_VALUE 0x55 -#define QT602240_BACKUP_TIME 25 /* msec */ -#define QT602240_RESET_TIME 65 /* msec */ - -#define QT602240_FWRESET_TIME 175 /* msec */ +#define MXT_DEBUG_DIAGNOSTIC 37 +#define MXT_GEN_MESSAGE 5 +#define MXT_GEN_COMMAND 6 +#define MXT_GEN_POWER 7 +#define MXT_GEN_ACQUIRE 8 +#define MXT_TOUCH_MULTI 9 +#define MXT_TOUCH_KEYARRAY 15 +#define MXT_TOUCH_PROXIMITY 23 +#define MXT_PROCI_GRIPFACE 20 +#define MXT_PROCG_NOISE 22 +#define MXT_PROCI_ONETOUCH 24 +#define MXT_PROCI_TWOTOUCH 27 +#define MXT_SPT_COMMSCONFIG 18 /* firmware ver 21 over */ +#define MXT_SPT_GPIOPWM 19 +#define MXT_SPT_SELFTEST 25 +#define MXT_SPT_CTECONFIG 28 +#define MXT_SPT_USERDATA 38 /* firmware ver 21 over */ + +/* MXT_GEN_COMMAND field */ +#define MXT_COMMAND_RESET 0 +#define MXT_COMMAND_BACKUPNV 1 +#define MXT_COMMAND_CALIBRATE 2 +#define MXT_COMMAND_REPORTALL 3 +#define MXT_COMMAND_DIAGNOSTIC 5 + +/* MXT_GEN_POWER field */ +#define MXT_POWER_IDLEACQINT 0 +#define MXT_POWER_ACTVACQINT 1 +#define MXT_POWER_ACTV2IDLETO 2 + +/* MXT_GEN_ACQUIRE field */ +#define MXT_ACQUIRE_CHRGTIME 0 +#define MXT_ACQUIRE_TCHDRIFT 2 +#define MXT_ACQUIRE_DRIFTST 3 +#define MXT_ACQUIRE_TCHAUTOCAL 4 +#define MXT_ACQUIRE_SYNC 5 +#define MXT_ACQUIRE_ATCHCALST 6 +#define MXT_ACQUIRE_ATCHCALSTHR 7 + +/* MXT_TOUCH_MULTI field */ +#define MXT_TOUCH_CTRL 0 +#define MXT_TOUCH_XORIGIN 1 +#define MXT_TOUCH_YORIGIN 2 +#define MXT_TOUCH_XSIZE 3 +#define MXT_TOUCH_YSIZE 4 +#define MXT_TOUCH_BLEN 6 +#define MXT_TOUCH_TCHTHR 7 +#define MXT_TOUCH_TCHDI 8 +#define MXT_TOUCH_ORIENT 9 +#define MXT_TOUCH_MOVHYSTI 11 +#define MXT_TOUCH_MOVHYSTN 12 +#define MXT_TOUCH_NUMTOUCH 14 +#define MXT_TOUCH_MRGHYST 15 +#define MXT_TOUCH_MRGTHR 16 +#define MXT_TOUCH_AMPHYST 17 +#define MXT_TOUCH_XRANGE_LSB 18 +#define MXT_TOUCH_XRANGE_MSB 19 +#define MXT_TOUCH_YRANGE_LSB 20 +#define MXT_TOUCH_YRANGE_MSB 21 +#define MXT_TOUCH_XLOCLIP 22 +#define MXT_TOUCH_XHICLIP 23 +#define MXT_TOUCH_YLOCLIP 24 +#define MXT_TOUCH_YHICLIP 25 +#define MXT_TOUCH_XEDGECTRL 26 +#define MXT_TOUCH_XEDGEDIST 27 +#define MXT_TOUCH_YEDGECTRL 28 +#define MXT_TOUCH_YEDGEDIST 29 +#define MXT_TOUCH_JUMPLIMIT 30 /* firmware ver 22 over */ + +/* MXT_PROCI_GRIPFACE field */ +#define MXT_GRIPFACE_CTRL 0 +#define MXT_GRIPFACE_XLOGRIP 1 +#define MXT_GRIPFACE_XHIGRIP 2 +#define MXT_GRIPFACE_YLOGRIP 3 +#define MXT_GRIPFACE_YHIGRIP 4 +#define MXT_GRIPFACE_MAXTCHS 5 +#define MXT_GRIPFACE_SZTHR1 7 +#define MXT_GRIPFACE_SZTHR2 8 +#define MXT_GRIPFACE_SHPTHR1 9 +#define MXT_GRIPFACE_SHPTHR2 10 +#define MXT_GRIPFACE_SUPEXTTO 11 + +/* MXT_PROCI_NOISE field */ +#define MXT_NOISE_CTRL 0 +#define MXT_NOISE_OUTFLEN 1 +#define MXT_NOISE_GCAFUL_LSB 3 +#define MXT_NOISE_GCAFUL_MSB 4 +#define MXT_NOISE_GCAFLL_LSB 5 +#define MXT_NOISE_GCAFLL_MSB 6 +#define MXT_NOISE_ACTVGCAFVALID 7 +#define MXT_NOISE_NOISETHR 8 +#define MXT_NOISE_FREQHOPSCALE 10 +#define MXT_NOISE_FREQ0 11 +#define MXT_NOISE_FREQ1 12 +#define MXT_NOISE_FREQ2 13 +#define MXT_NOISE_FREQ3 14 +#define MXT_NOISE_FREQ4 15 +#define MXT_NOISE_IDLEGCAFVALID 16 + +/* MXT_SPT_COMMSCONFIG */ +#define MXT_COMMS_CTRL 0 +#define MXT_COMMS_CMD 1 + +/* MXT_SPT_CTECONFIG field */ +#define MXT_CTE_CTRL 0 +#define MXT_CTE_CMD 1 +#define MXT_CTE_MODE 2 +#define MXT_CTE_IDLEGCAFDEPTH 3 +#define MXT_CTE_ACTVGCAFDEPTH 4 +#define MXT_CTE_VOLTAGE 5 /* firmware ver 21 over */ + +#define MXT_VOLTAGE_DEFAULT 2700000 +#define MXT_VOLTAGE_STEP 10000 + +/* Define for MXT_GEN_COMMAND */ +#define MXT_BOOT_VALUE 0xa5 +#define MXT_BACKUP_VALUE 0x55 +#define MXT_BACKUP_TIME 25 /* msec */ +#define MXT_RESET_TIME 65 /* msec */ + +#define MXT_FWRESET_TIME 175 /* msec */ /* Command to unlock bootloader */ -#define QT602240_UNLOCK_CMD_MSB 0xaa -#define QT602240_UNLOCK_CMD_LSB 0xdc +#define MXT_UNLOCK_CMD_MSB 0xaa +#define MXT_UNLOCK_CMD_LSB 0xdc /* Bootloader mode status */ -#define QT602240_WAITING_BOOTLOAD_CMD 0xc0 /* valid 7 6 bit only */ -#define QT602240_WAITING_FRAME_DATA 0x80 /* valid 7 6 bit only */ -#define QT602240_FRAME_CRC_CHECK 0x02 -#define QT602240_FRAME_CRC_FAIL 0x03 -#define QT602240_FRAME_CRC_PASS 0x04 -#define QT602240_APP_CRC_FAIL 0x40 /* valid 7 8 bit only */ -#define QT602240_BOOT_STATUS_MASK 0x3f +#define MXT_WAITING_BOOTLOAD_CMD 0xc0 /* valid 7 6 bit only */ +#define MXT_WAITING_FRAME_DATA 0x80 /* valid 7 6 bit only */ +#define MXT_FRAME_CRC_CHECK 0x02 +#define MXT_FRAME_CRC_FAIL 0x03 +#define MXT_FRAME_CRC_PASS 0x04 +#define MXT_APP_CRC_FAIL 0x40 /* valid 7 8 bit only */ +#define MXT_BOOT_STATUS_MASK 0x3f /* Touch status */ -#define QT602240_SUPPRESS (1 << 1) -#define QT602240_AMP (1 << 2) -#define QT602240_VECTOR (1 << 3) -#define QT602240_MOVE (1 << 4) -#define QT602240_RELEASE (1 << 5) -#define QT602240_PRESS (1 << 6) -#define QT602240_DETECT (1 << 7) +#define MXT_SUPPRESS (1 << 1) +#define MXT_AMP (1 << 2) +#define MXT_VECTOR (1 << 3) +#define MXT_MOVE (1 << 4) +#define MXT_RELEASE (1 << 5) +#define MXT_PRESS (1 << 6) +#define MXT_DETECT (1 << 7) /* Touchscreen absolute values */ -#define QT602240_MAX_XC 0x3ff -#define QT602240_MAX_YC 0x3ff -#define QT602240_MAX_AREA 0xff +#define MXT_MAX_XC 0x3ff +#define MXT_MAX_YC 0x3ff +#define MXT_MAX_AREA 0xff -#define QT602240_MAX_FINGER 10 +#define MXT_MAX_FINGER 10 /* Initial register values recommended from chip vendor */ static const u8 init_vals_ver_20[] = { - /* QT602240_GEN_COMMAND(6) */ + /* MXT_GEN_COMMAND(6) */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* QT602240_GEN_POWER(7) */ + /* MXT_GEN_POWER(7) */ 0x20, 0xff, 0x32, - /* QT602240_GEN_ACQUIRE(8) */ + /* MXT_GEN_ACQUIRE(8) */ 0x08, 0x05, 0x05, 0x00, 0x00, 0x00, 0x05, 0x14, - /* QT602240_TOUCH_MULTI(9) */ + /* MXT_TOUCH_MULTI(9) */ 0x00, 0x00, 0x00, 0x11, 0x0a, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x01, 0x01, 0x0e, 0x0a, 0x0a, 0x0a, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x64, - /* QT602240_TOUCH_KEYARRAY(15) */ + /* MXT_TOUCH_KEYARRAY(15) */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* QT602240_SPT_GPIOPWM(19) */ + /* MXT_SPT_GPIOPWM(19) */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* QT602240_PROCI_GRIPFACE(20) */ + /* MXT_PROCI_GRIPFACE(20) */ 0x00, 0x64, 0x64, 0x64, 0x64, 0x00, 0x00, 0x1e, 0x14, 0x04, 0x1e, 0x00, - /* QT602240_PROCG_NOISE(22) */ + /* MXT_PROCG_NOISE(22) */ 0x05, 0x00, 0x00, 0x19, 0x00, 0xe7, 0xff, 0x04, 0x32, 0x00, 0x01, 0x0a, 0x0f, 0x14, 0x00, 0x00, 0xe8, - /* QT602240_TOUCH_PROXIMITY(23) */ + /* MXT_TOUCH_PROXIMITY(23) */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* QT602240_PROCI_ONETOUCH(24) */ + /* MXT_PROCI_ONETOUCH(24) */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* QT602240_SPT_SELFTEST(25) */ + /* MXT_SPT_SELFTEST(25) */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* QT602240_PROCI_TWOTOUCH(27) */ + /* MXT_PROCI_TWOTOUCH(27) */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* QT602240_SPT_CTECONFIG(28) */ + /* MXT_SPT_CTECONFIG(28) */ 0x00, 0x00, 0x00, 0x04, 0x08, }; static const u8 init_vals_ver_21[] = { - /* QT602240_GEN_COMMAND(6) */ + /* MXT_GEN_COMMAND(6) */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* QT602240_GEN_POWER(7) */ + /* MXT_GEN_POWER(7) */ 0x20, 0xff, 0x32, - /* QT602240_GEN_ACQUIRE(8) */ + /* MXT_GEN_ACQUIRE(8) */ 0x0a, 0x00, 0x05, 0x00, 0x00, 0x00, 0x09, 0x23, - /* QT602240_TOUCH_MULTI(9) */ + /* MXT_TOUCH_MULTI(9) */ 0x00, 0x00, 0x00, 0x13, 0x0b, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x01, 0x01, 0x0e, 0x0a, 0x0a, 0x0a, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* QT602240_TOUCH_KEYARRAY(15) */ + /* MXT_TOUCH_KEYARRAY(15) */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* QT602240_SPT_GPIOPWM(19) */ + /* MXT_SPT_GPIOPWM(19) */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* QT602240_PROCI_GRIPFACE(20) */ + /* MXT_PROCI_GRIPFACE(20) */ 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x28, 0x04, 0x0f, 0x0a, - /* QT602240_PROCG_NOISE(22) */ + /* MXT_PROCG_NOISE(22) */ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x23, 0x00, 0x00, 0x05, 0x0f, 0x19, 0x23, 0x2d, 0x03, - /* QT602240_TOUCH_PROXIMITY(23) */ + /* MXT_TOUCH_PROXIMITY(23) */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* QT602240_PROCI_ONETOUCH(24) */ + /* MXT_PROCI_ONETOUCH(24) */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* QT602240_SPT_SELFTEST(25) */ + /* MXT_SPT_SELFTEST(25) */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* QT602240_PROCI_TWOTOUCH(27) */ + /* MXT_PROCI_TWOTOUCH(27) */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* QT602240_SPT_CTECONFIG(28) */ + /* MXT_SPT_CTECONFIG(28) */ 0x00, 0x00, 0x00, 0x08, 0x10, 0x00, }; static const u8 init_vals_ver_22[] = { - /* QT602240_GEN_COMMAND(6) */ + /* MXT_GEN_COMMAND(6) */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* QT602240_GEN_POWER(7) */ + /* MXT_GEN_POWER(7) */ 0x20, 0xff, 0x32, - /* QT602240_GEN_ACQUIRE(8) */ + /* MXT_GEN_ACQUIRE(8) */ 0x0a, 0x00, 0x05, 0x00, 0x00, 0x00, 0x09, 0x23, - /* QT602240_TOUCH_MULTI(9) */ + /* MXT_TOUCH_MULTI(9) */ 0x00, 0x00, 0x00, 0x13, 0x0b, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x01, 0x01, 0x0e, 0x0a, 0x0a, 0x0a, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* QT602240_TOUCH_KEYARRAY(15) */ + /* MXT_TOUCH_KEYARRAY(15) */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* QT602240_SPT_GPIOPWM(19) */ + /* MXT_SPT_GPIOPWM(19) */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* QT602240_PROCI_GRIPFACE(20) */ + /* MXT_PROCI_GRIPFACE(20) */ 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x28, 0x04, 0x0f, 0x0a, - /* QT602240_PROCG_NOISE(22) */ + /* MXT_PROCG_NOISE(22) */ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x23, 0x00, 0x00, 0x05, 0x0f, 0x19, 0x23, 0x2d, 0x03, - /* QT602240_TOUCH_PROXIMITY(23) */ + /* MXT_TOUCH_PROXIMITY(23) */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* QT602240_PROCI_ONETOUCH(24) */ + /* MXT_PROCI_ONETOUCH(24) */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* QT602240_SPT_SELFTEST(25) */ + /* MXT_SPT_SELFTEST(25) */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* QT602240_PROCI_TWOTOUCH(27) */ + /* MXT_PROCI_TWOTOUCH(27) */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* QT602240_SPT_CTECONFIG(28) */ + /* MXT_SPT_CTECONFIG(28) */ 0x00, 0x00, 0x00, 0x08, 0x10, 0x00, }; -struct qt602240_info { +struct mxt_info { u8 family_id; u8 variant_id; u8 version; @@ -325,7 +325,7 @@ struct qt602240_info { u8 object_num; }; -struct qt602240_object { +struct mxt_object { u8 type; u16 start_address; u8 size; @@ -336,13 +336,13 @@ struct qt602240_object { u8 max_reportid; }; -struct qt602240_message { +struct mxt_message { u8 reportid; u8 message[7]; u8 checksum; }; -struct qt602240_finger { +struct mxt_finger { int status; int x; int y; @@ -350,65 +350,65 @@ struct qt602240_finger { }; /* Each client has this additional data */ -struct qt602240_data { +struct mxt_data { struct i2c_client *client; struct input_dev *input_dev; - const struct qt602240_platform_data *pdata; - struct qt602240_object *object_table; - struct qt602240_info info; - struct qt602240_finger finger[QT602240_MAX_FINGER]; + const struct mxt_platform_data *pdata; + struct mxt_object *object_table; + struct mxt_info info; + struct mxt_finger finger[MXT_MAX_FINGER]; unsigned int irq; }; -static bool qt602240_object_readable(unsigned int type) +static bool mxt_object_readable(unsigned int type) { switch (type) { - case QT602240_GEN_MESSAGE: - case QT602240_GEN_COMMAND: - case QT602240_GEN_POWER: - case QT602240_GEN_ACQUIRE: - case QT602240_TOUCH_MULTI: - case QT602240_TOUCH_KEYARRAY: - case QT602240_TOUCH_PROXIMITY: - case QT602240_PROCI_GRIPFACE: - case QT602240_PROCG_NOISE: - case QT602240_PROCI_ONETOUCH: - case QT602240_PROCI_TWOTOUCH: - case QT602240_SPT_COMMSCONFIG: - case QT602240_SPT_GPIOPWM: - case QT602240_SPT_SELFTEST: - case QT602240_SPT_CTECONFIG: - case QT602240_SPT_USERDATA: + case MXT_GEN_MESSAGE: + case MXT_GEN_COMMAND: + case MXT_GEN_POWER: + case MXT_GEN_ACQUIRE: + case MXT_TOUCH_MULTI: + case MXT_TOUCH_KEYARRAY: + case MXT_TOUCH_PROXIMITY: + case MXT_PROCI_GRIPFACE: + case MXT_PROCG_NOISE: + case MXT_PROCI_ONETOUCH: + case MXT_PROCI_TWOTOUCH: + case MXT_SPT_COMMSCONFIG: + case MXT_SPT_GPIOPWM: + case MXT_SPT_SELFTEST: + case MXT_SPT_CTECONFIG: + case MXT_SPT_USERDATA: return true; default: return false; } } -static bool qt602240_object_writable(unsigned int type) +static bool mxt_object_writable(unsigned int type) { switch (type) { - case QT602240_GEN_COMMAND: - case QT602240_GEN_POWER: - case QT602240_GEN_ACQUIRE: - case QT602240_TOUCH_MULTI: - case QT602240_TOUCH_KEYARRAY: - case QT602240_TOUCH_PROXIMITY: - case QT602240_PROCI_GRIPFACE: - case QT602240_PROCG_NOISE: - case QT602240_PROCI_ONETOUCH: - case QT602240_PROCI_TWOTOUCH: - case QT602240_SPT_GPIOPWM: - case QT602240_SPT_SELFTEST: - case QT602240_SPT_CTECONFIG: + case MXT_GEN_COMMAND: + case MXT_GEN_POWER: + case MXT_GEN_ACQUIRE: + case MXT_TOUCH_MULTI: + case MXT_TOUCH_KEYARRAY: + case MXT_TOUCH_PROXIMITY: + case MXT_PROCI_GRIPFACE: + case MXT_PROCG_NOISE: + case MXT_PROCI_ONETOUCH: + case MXT_PROCI_TWOTOUCH: + case MXT_SPT_GPIOPWM: + case MXT_SPT_SELFTEST: + case MXT_SPT_CTECONFIG: return true; default: return false; } } -static void qt602240_dump_message(struct device *dev, - struct qt602240_message *message) +static void mxt_dump_message(struct device *dev, + struct mxt_message *message) { dev_dbg(dev, "reportid:\t0x%x\n", message->reportid); dev_dbg(dev, "message1:\t0x%x\n", message->message[0]); @@ -421,7 +421,7 @@ static void qt602240_dump_message(struct device *dev, dev_dbg(dev, "checksum:\t0x%x\n", message->checksum); } -static int qt602240_check_bootloader(struct i2c_client *client, +static int mxt_check_bootloader(struct i2c_client *client, unsigned int state) { u8 val; @@ -433,12 +433,12 @@ recheck: } switch (state) { - case QT602240_WAITING_BOOTLOAD_CMD: - case QT602240_WAITING_FRAME_DATA: - val &= ~QT602240_BOOT_STATUS_MASK; + case MXT_WAITING_BOOTLOAD_CMD: + case MXT_WAITING_FRAME_DATA: + val &= ~MXT_BOOT_STATUS_MASK; break; - case QT602240_FRAME_CRC_PASS: - if (val == QT602240_FRAME_CRC_CHECK) + case MXT_FRAME_CRC_PASS: + if (val == MXT_FRAME_CRC_CHECK) goto recheck; break; default: @@ -453,12 +453,12 @@ recheck: return 0; } -static int qt602240_unlock_bootloader(struct i2c_client *client) +static int mxt_unlock_bootloader(struct i2c_client *client) { u8 buf[2]; - buf[0] = QT602240_UNLOCK_CMD_LSB; - buf[1] = QT602240_UNLOCK_CMD_MSB; + buf[0] = MXT_UNLOCK_CMD_LSB; + buf[1] = MXT_UNLOCK_CMD_MSB; if (i2c_master_send(client, buf, 2) != 2) { dev_err(&client->dev, "%s: i2c send failed\n", __func__); @@ -468,7 +468,7 @@ static int qt602240_unlock_bootloader(struct i2c_client *client) return 0; } -static int qt602240_fw_write(struct i2c_client *client, +static int mxt_fw_write(struct i2c_client *client, const u8 *data, unsigned int frame_size) { if (i2c_master_send(client, data, frame_size) != frame_size) { @@ -479,7 +479,7 @@ static int qt602240_fw_write(struct i2c_client *client, return 0; } -static int __qt602240_read_reg(struct i2c_client *client, +static int __mxt_read_reg(struct i2c_client *client, u16 reg, u16 len, void *val) { struct i2c_msg xfer[2]; @@ -508,12 +508,12 @@ static int __qt602240_read_reg(struct i2c_client *client, return 0; } -static int qt602240_read_reg(struct i2c_client *client, u16 reg, u8 *val) +static int mxt_read_reg(struct i2c_client *client, u16 reg, u8 *val) { - return __qt602240_read_reg(client, reg, 1, val); + return __mxt_read_reg(client, reg, 1, val); } -static int qt602240_write_reg(struct i2c_client *client, u16 reg, u8 val) +static int mxt_write_reg(struct i2c_client *client, u16 reg, u8 val) { u8 buf[3]; @@ -529,17 +529,17 @@ static int qt602240_write_reg(struct i2c_client *client, u16 reg, u8 val) return 0; } -static int qt602240_read_object_table(struct i2c_client *client, +static int mxt_read_object_table(struct i2c_client *client, u16 reg, u8 *object_buf) { - return __qt602240_read_reg(client, reg, QT602240_OBJECT_SIZE, + return __mxt_read_reg(client, reg, MXT_OBJECT_SIZE, object_buf); } -static struct qt602240_object * -qt602240_get_object(struct qt602240_data *data, u8 type) +static struct mxt_object * +mxt_get_object(struct mxt_data *data, u8 type) { - struct qt602240_object *object; + struct mxt_object *object; int i; for (i = 0; i < data->info.object_num; i++) { @@ -552,63 +552,63 @@ qt602240_get_object(struct qt602240_data *data, u8 type) return NULL; } -static int qt602240_read_message(struct qt602240_data *data, - struct qt602240_message *message) +static int mxt_read_message(struct mxt_data *data, + struct mxt_message *message) { - struct qt602240_object *object; + struct mxt_object *object; u16 reg; - object = qt602240_get_object(data, QT602240_GEN_MESSAGE); + object = mxt_get_object(data, MXT_GEN_MESSAGE); if (!object) return -EINVAL; reg = object->start_address; - return __qt602240_read_reg(data->client, reg, - sizeof(struct qt602240_message), message); + return __mxt_read_reg(data->client, reg, + sizeof(struct mxt_message), message); } -static int qt602240_read_object(struct qt602240_data *data, +static int mxt_read_object(struct mxt_data *data, u8 type, u8 offset, u8 *val) { - struct qt602240_object *object; + struct mxt_object *object; u16 reg; - object = qt602240_get_object(data, type); + object = mxt_get_object(data, type); if (!object) return -EINVAL; reg = object->start_address; - return __qt602240_read_reg(data->client, reg + offset, 1, val); + return __mxt_read_reg(data->client, reg + offset, 1, val); } -static int qt602240_write_object(struct qt602240_data *data, +static int mxt_write_object(struct mxt_data *data, u8 type, u8 offset, u8 val) { - struct qt602240_object *object; + struct mxt_object *object; u16 reg; - object = qt602240_get_object(data, type); + object = mxt_get_object(data, type); if (!object) return -EINVAL; reg = object->start_address; - return qt602240_write_reg(data->client, reg + offset, val); + return mxt_write_reg(data->client, reg + offset, val); } -static void qt602240_input_report(struct qt602240_data *data, int single_id) +static void mxt_input_report(struct mxt_data *data, int single_id) { - struct qt602240_finger *finger = data->finger; + struct mxt_finger *finger = data->finger; struct input_dev *input_dev = data->input_dev; int status = finger[single_id].status; int finger_num = 0; int id; - for (id = 0; id < QT602240_MAX_FINGER; id++) { + for (id = 0; id < MXT_MAX_FINGER; id++) { if (!finger[id].status) continue; input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR, - finger[id].status != QT602240_RELEASE ? + finger[id].status != MXT_RELEASE ? finger[id].area : 0); input_report_abs(input_dev, ABS_MT_POSITION_X, finger[id].x); @@ -616,7 +616,7 @@ static void qt602240_input_report(struct qt602240_data *data, int single_id) finger[id].y); input_mt_sync(input_dev); - if (finger[id].status == QT602240_RELEASE) + if (finger[id].status == MXT_RELEASE) finger[id].status = 0; else finger_num++; @@ -624,7 +624,7 @@ static void qt602240_input_report(struct qt602240_data *data, int single_id) input_report_key(input_dev, BTN_TOUCH, finger_num > 0); - if (status != QT602240_RELEASE) { + if (status != MXT_RELEASE) { input_report_abs(input_dev, ABS_X, finger[single_id].x); input_report_abs(input_dev, ABS_Y, finger[single_id].y); } @@ -632,10 +632,10 @@ static void qt602240_input_report(struct qt602240_data *data, int single_id) input_sync(input_dev); } -static void qt602240_input_touchevent(struct qt602240_data *data, - struct qt602240_message *message, int id) +static void mxt_input_touchevent(struct mxt_data *data, + struct mxt_message *message, int id) { - struct qt602240_finger *finger = data->finger; + struct mxt_finger *finger = data->finger; struct device *dev = &data->client->dev; u8 status = message->message[0]; int x; @@ -643,18 +643,18 @@ static void qt602240_input_touchevent(struct qt602240_data *data, int area; /* Check the touch is present on the screen */ - if (!(status & QT602240_DETECT)) { - if (status & QT602240_RELEASE) { + if (!(status & MXT_DETECT)) { + if (status & MXT_RELEASE) { dev_dbg(dev, "[%d] released\n", id); - finger[id].status = QT602240_RELEASE; - qt602240_input_report(data, id); + finger[id].status = MXT_RELEASE; + mxt_input_report(data, id); } return; } /* Check only AMP detection */ - if (!(status & (QT602240_PRESS | QT602240_MOVE))) + if (!(status & (MXT_PRESS | MXT_MOVE))) return; x = (message->message[1] << 2) | ((message->message[3] & ~0x3f) >> 6); @@ -662,23 +662,23 @@ static void qt602240_input_touchevent(struct qt602240_data *data, area = message->message[4]; dev_dbg(dev, "[%d] %s x: %d, y: %d, area: %d\n", id, - status & QT602240_MOVE ? "moved" : "pressed", + status & MXT_MOVE ? "moved" : "pressed", x, y, area); - finger[id].status = status & QT602240_MOVE ? - QT602240_MOVE : QT602240_PRESS; + finger[id].status = status & MXT_MOVE ? + MXT_MOVE : MXT_PRESS; finger[id].x = x; finger[id].y = y; finger[id].area = area; - qt602240_input_report(data, id); + mxt_input_report(data, id); } -static irqreturn_t qt602240_interrupt(int irq, void *dev_id) +static irqreturn_t mxt_interrupt(int irq, void *dev_id) { - struct qt602240_data *data = dev_id; - struct qt602240_message message; - struct qt602240_object *object; + struct mxt_data *data = dev_id; + struct mxt_message message; + struct mxt_object *object; struct device *dev = &data->client->dev; int id; u8 reportid; @@ -686,15 +686,15 @@ static irqreturn_t qt602240_interrupt(int irq, void *dev_id) u8 min_reportid; do { - if (qt602240_read_message(data, &message)) { + if (mxt_read_message(data, &message)) { dev_err(dev, "Failed to read message\n"); goto end; } reportid = message.reportid; - /* whether reportid is thing of QT602240_TOUCH_MULTI */ - object = qt602240_get_object(data, QT602240_TOUCH_MULTI); + /* whether reportid is thing of MXT_TOUCH_MULTI */ + object = mxt_get_object(data, MXT_TOUCH_MULTI); if (!object) goto end; @@ -703,18 +703,18 @@ static irqreturn_t qt602240_interrupt(int irq, void *dev_id) id = reportid - min_reportid; if (reportid >= min_reportid && reportid <= max_reportid) - qt602240_input_touchevent(data, &message, id); + mxt_input_touchevent(data, &message, id); else - qt602240_dump_message(dev, &message); + mxt_dump_message(dev, &message); } while (reportid != 0xff); end: return IRQ_HANDLED; } -static int qt602240_check_reg_init(struct qt602240_data *data) +static int mxt_check_reg_init(struct mxt_data *data) { - struct qt602240_object *object; + struct mxt_object *object; struct device *dev = &data->client->dev; int index = 0; int i, j; @@ -722,13 +722,13 @@ static int qt602240_check_reg_init(struct qt602240_data *data) u8 *init_vals; switch (version) { - case QT602240_VER_20: + case MXT_VER_20: init_vals = (u8 *)init_vals_ver_20; break; - case QT602240_VER_21: + case MXT_VER_21: init_vals = (u8 *)init_vals_ver_21; break; - case QT602240_VER_22: + case MXT_VER_22: init_vals = (u8 *)init_vals_ver_22; break; default: @@ -739,11 +739,11 @@ static int qt602240_check_reg_init(struct qt602240_data *data) for (i = 0; i < data->info.object_num; i++) { object = data->object_table + i; - if (!qt602240_object_writable(object->type)) + if (!mxt_object_writable(object->type)) continue; for (j = 0; j < object->size + 1; j++) - qt602240_write_object(data, object->type, j, + mxt_write_object(data, object->type, j, init_vals[index + j]); index += object->size + 1; @@ -752,9 +752,9 @@ static int qt602240_check_reg_init(struct qt602240_data *data) return 0; } -static int qt602240_check_matrix_size(struct qt602240_data *data) +static int mxt_check_matrix_size(struct mxt_data *data) { - const struct qt602240_platform_data *pdata = data->pdata; + const struct mxt_platform_data *pdata = data->pdata; struct device *dev = &data->client->dev; int mode = -1; int error; @@ -801,8 +801,8 @@ static int qt602240_check_matrix_size(struct qt602240_data *data) return -EINVAL; } - error = qt602240_read_object(data, QT602240_SPT_CTECONFIG, - QT602240_CTE_MODE, &val); + error = mxt_read_object(data, MXT_SPT_CTECONFIG, + MXT_CTE_MODE, &val); if (error) return error; @@ -810,17 +810,17 @@ static int qt602240_check_matrix_size(struct qt602240_data *data) return 0; /* Change the CTE configuration */ - qt602240_write_object(data, QT602240_SPT_CTECONFIG, - QT602240_CTE_CTRL, 1); - qt602240_write_object(data, QT602240_SPT_CTECONFIG, - QT602240_CTE_MODE, mode); - qt602240_write_object(data, QT602240_SPT_CTECONFIG, - QT602240_CTE_CTRL, 0); + mxt_write_object(data, MXT_SPT_CTECONFIG, + MXT_CTE_CTRL, 1); + mxt_write_object(data, MXT_SPT_CTECONFIG, + MXT_CTE_MODE, mode); + mxt_write_object(data, MXT_SPT_CTECONFIG, + MXT_CTE_CTRL, 0); return 0; } -static int qt602240_make_highchg(struct qt602240_data *data) +static int mxt_make_highchg(struct mxt_data *data) { struct device *dev = &data->client->dev; int count = 10; @@ -829,7 +829,7 @@ static int qt602240_make_highchg(struct qt602240_data *data) /* Read dummy message to make high CHG pin */ do { - error = qt602240_read_object(data, QT602240_GEN_MESSAGE, 0, &val); + error = mxt_read_object(data, MXT_GEN_MESSAGE, 0, &val); if (error) return error; } while ((val != 0xff) && --count); @@ -842,82 +842,82 @@ static int qt602240_make_highchg(struct qt602240_data *data) return 0; } -static void qt602240_handle_pdata(struct qt602240_data *data) +static void mxt_handle_pdata(struct mxt_data *data) { - const struct qt602240_platform_data *pdata = data->pdata; + const struct mxt_platform_data *pdata = data->pdata; u8 voltage; /* Set touchscreen lines */ - qt602240_write_object(data, QT602240_TOUCH_MULTI, QT602240_TOUCH_XSIZE, + mxt_write_object(data, MXT_TOUCH_MULTI, MXT_TOUCH_XSIZE, pdata->x_line); - qt602240_write_object(data, QT602240_TOUCH_MULTI, QT602240_TOUCH_YSIZE, + mxt_write_object(data, MXT_TOUCH_MULTI, MXT_TOUCH_YSIZE, pdata->y_line); /* Set touchscreen orient */ - qt602240_write_object(data, QT602240_TOUCH_MULTI, QT602240_TOUCH_ORIENT, + mxt_write_object(data, MXT_TOUCH_MULTI, MXT_TOUCH_ORIENT, pdata->orient); /* Set touchscreen burst length */ - qt602240_write_object(data, QT602240_TOUCH_MULTI, - QT602240_TOUCH_BLEN, pdata->blen); + mxt_write_object(data, MXT_TOUCH_MULTI, + MXT_TOUCH_BLEN, pdata->blen); /* Set touchscreen threshold */ - qt602240_write_object(data, QT602240_TOUCH_MULTI, - QT602240_TOUCH_TCHTHR, pdata->threshold); + mxt_write_object(data, MXT_TOUCH_MULTI, + MXT_TOUCH_TCHTHR, pdata->threshold); /* Set touchscreen resolution */ - qt602240_write_object(data, QT602240_TOUCH_MULTI, - QT602240_TOUCH_XRANGE_LSB, (pdata->x_size - 1) & 0xff); - qt602240_write_object(data, QT602240_TOUCH_MULTI, - QT602240_TOUCH_XRANGE_MSB, (pdata->x_size - 1) >> 8); - qt602240_write_object(data, QT602240_TOUCH_MULTI, - QT602240_TOUCH_YRANGE_LSB, (pdata->y_size - 1) & 0xff); - qt602240_write_object(data, QT602240_TOUCH_MULTI, - QT602240_TOUCH_YRANGE_MSB, (pdata->y_size - 1) >> 8); + mxt_write_object(data, MXT_TOUCH_MULTI, + MXT_TOUCH_XRANGE_LSB, (pdata->x_size - 1) & 0xff); + mxt_write_object(data, MXT_TOUCH_MULTI, + MXT_TOUCH_XRANGE_MSB, (pdata->x_size - 1) >> 8); + mxt_write_object(data, MXT_TOUCH_MULTI, + MXT_TOUCH_YRANGE_LSB, (pdata->y_size - 1) & 0xff); + mxt_write_object(data, MXT_TOUCH_MULTI, + MXT_TOUCH_YRANGE_MSB, (pdata->y_size - 1) >> 8); /* Set touchscreen voltage */ - if (data->info.version >= QT602240_VER_21 && pdata->voltage) { - if (pdata->voltage < QT602240_VOLTAGE_DEFAULT) { - voltage = (QT602240_VOLTAGE_DEFAULT - pdata->voltage) / - QT602240_VOLTAGE_STEP; + if (data->info.version >= MXT_VER_21 && pdata->voltage) { + if (pdata->voltage < MXT_VOLTAGE_DEFAULT) { + voltage = (MXT_VOLTAGE_DEFAULT - pdata->voltage) / + MXT_VOLTAGE_STEP; voltage = 0xff - voltage + 1; } else - voltage = (pdata->voltage - QT602240_VOLTAGE_DEFAULT) / - QT602240_VOLTAGE_STEP; + voltage = (pdata->voltage - MXT_VOLTAGE_DEFAULT) / + MXT_VOLTAGE_STEP; - qt602240_write_object(data, QT602240_SPT_CTECONFIG, - QT602240_CTE_VOLTAGE, voltage); + mxt_write_object(data, MXT_SPT_CTECONFIG, + MXT_CTE_VOLTAGE, voltage); } } -static int qt602240_get_info(struct qt602240_data *data) +static int mxt_get_info(struct mxt_data *data) { struct i2c_client *client = data->client; - struct qt602240_info *info = &data->info; + struct mxt_info *info = &data->info; int error; u8 val; - error = qt602240_read_reg(client, QT602240_FAMILY_ID, &val); + error = mxt_read_reg(client, MXT_FAMILY_ID, &val); if (error) return error; info->family_id = val; - error = qt602240_read_reg(client, QT602240_VARIANT_ID, &val); + error = mxt_read_reg(client, MXT_VARIANT_ID, &val); if (error) return error; info->variant_id = val; - error = qt602240_read_reg(client, QT602240_VERSION, &val); + error = mxt_read_reg(client, MXT_VERSION, &val); if (error) return error; info->version = val; - error = qt602240_read_reg(client, QT602240_BUILD, &val); + error = mxt_read_reg(client, MXT_BUILD, &val); if (error) return error; info->build = val; - error = qt602240_read_reg(client, QT602240_OBJECT_NUM, &val); + error = mxt_read_reg(client, MXT_OBJECT_NUM, &val); if (error) return error; info->object_num = val; @@ -925,19 +925,19 @@ static int qt602240_get_info(struct qt602240_data *data) return 0; } -static int qt602240_get_object_table(struct qt602240_data *data) +static int mxt_get_object_table(struct mxt_data *data) { int error; int i; u16 reg; u8 reportid = 0; - u8 buf[QT602240_OBJECT_SIZE]; + u8 buf[MXT_OBJECT_SIZE]; for (i = 0; i < data->info.object_num; i++) { - struct qt602240_object *object = data->object_table + i; + struct mxt_object *object = data->object_table + i; - reg = QT602240_OBJECT_START + QT602240_OBJECT_SIZE * i; - error = qt602240_read_object_table(data->client, reg, buf); + reg = MXT_OBJECT_START + MXT_OBJECT_SIZE * i; + error = mxt_read_object_table(data->client, reg, buf); if (error) return error; @@ -957,19 +957,19 @@ static int qt602240_get_object_table(struct qt602240_data *data) return 0; } -static int qt602240_initialize(struct qt602240_data *data) +static int mxt_initialize(struct mxt_data *data) { struct i2c_client *client = data->client; - struct qt602240_info *info = &data->info; + struct mxt_info *info = &data->info; int error; u8 val; - error = qt602240_get_info(data); + error = mxt_get_info(data); if (error) return error; data->object_table = kcalloc(info->object_num, - sizeof(struct qt602240_object), + sizeof(struct mxt_object), GFP_KERNEL); if (!data->object_table) { dev_err(&client->dev, "Failed to allocate memory\n"); @@ -977,44 +977,44 @@ static int qt602240_initialize(struct qt602240_data *data) } /* Get object table information */ - error = qt602240_get_object_table(data); + error = mxt_get_object_table(data); if (error) return error; /* Check register init values */ - error = qt602240_check_reg_init(data); + error = mxt_check_reg_init(data); if (error) return error; /* Check X/Y matrix size */ - error = qt602240_check_matrix_size(data); + error = mxt_check_matrix_size(data); if (error) return error; - error = qt602240_make_highchg(data); + error = mxt_make_highchg(data); if (error) return error; - qt602240_handle_pdata(data); + mxt_handle_pdata(data); /* Backup to memory */ - qt602240_write_object(data, QT602240_GEN_COMMAND, - QT602240_COMMAND_BACKUPNV, - QT602240_BACKUP_VALUE); - msleep(QT602240_BACKUP_TIME); + mxt_write_object(data, MXT_GEN_COMMAND, + MXT_COMMAND_BACKUPNV, + MXT_BACKUP_VALUE); + msleep(MXT_BACKUP_TIME); /* Soft reset */ - qt602240_write_object(data, QT602240_GEN_COMMAND, - QT602240_COMMAND_RESET, 1); - msleep(QT602240_RESET_TIME); + mxt_write_object(data, MXT_GEN_COMMAND, + MXT_COMMAND_RESET, 1); + msleep(MXT_RESET_TIME); /* Update matrix size at info struct */ - error = qt602240_read_reg(client, QT602240_MATRIX_X_SIZE, &val); + error = mxt_read_reg(client, MXT_MATRIX_X_SIZE, &val); if (error) return error; info->matrix_xsize = val; - error = qt602240_read_reg(client, QT602240_MATRIX_Y_SIZE, &val); + error = mxt_read_reg(client, MXT_MATRIX_Y_SIZE, &val); if (error) return error; info->matrix_ysize = val; @@ -1032,11 +1032,11 @@ static int qt602240_initialize(struct qt602240_data *data) return 0; } -static ssize_t qt602240_object_show(struct device *dev, +static ssize_t mxt_object_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct qt602240_data *data = dev_get_drvdata(dev); - struct qt602240_object *object; + struct mxt_data *data = dev_get_drvdata(dev); + struct mxt_object *object; int count = 0; int i, j; int error; @@ -1049,13 +1049,13 @@ static ssize_t qt602240_object_show(struct device *dev, "Object Table Element %d(Type %d)\n", i + 1, object->type); - if (!qt602240_object_readable(object->type)) { + if (!mxt_object_readable(object->type)) { count += sprintf(buf + count, "\n"); continue; } for (j = 0; j < object->size + 1; j++) { - error = qt602240_read_object(data, + error = mxt_read_object(data, object->type, j, &val); if (error) return error; @@ -1070,9 +1070,9 @@ static ssize_t qt602240_object_show(struct device *dev, return count; } -static int qt602240_load_fw(struct device *dev, const char *fn) +static int mxt_load_fw(struct device *dev, const char *fn) { - struct qt602240_data *data = dev_get_drvdata(dev); + struct mxt_data *data = dev_get_drvdata(dev); struct i2c_client *client = data->client; const struct firmware *fw = NULL; unsigned int frame_size; @@ -1086,26 +1086,26 @@ static int qt602240_load_fw(struct device *dev, const char *fn) } /* Change to the bootloader mode */ - qt602240_write_object(data, QT602240_GEN_COMMAND, - QT602240_COMMAND_RESET, QT602240_BOOT_VALUE); - msleep(QT602240_RESET_TIME); + mxt_write_object(data, MXT_GEN_COMMAND, + MXT_COMMAND_RESET, MXT_BOOT_VALUE); + msleep(MXT_RESET_TIME); /* Change to slave address of bootloader */ - if (client->addr == QT602240_APP_LOW) - client->addr = QT602240_BOOT_LOW; + if (client->addr == MXT_APP_LOW) + client->addr = MXT_BOOT_LOW; else - client->addr = QT602240_BOOT_HIGH; + client->addr = MXT_BOOT_HIGH; - ret = qt602240_check_bootloader(client, QT602240_WAITING_BOOTLOAD_CMD); + ret = mxt_check_bootloader(client, MXT_WAITING_BOOTLOAD_CMD); if (ret) goto out; /* Unlock bootloader */ - qt602240_unlock_bootloader(client); + mxt_unlock_bootloader(client); while (pos < fw->size) { - ret = qt602240_check_bootloader(client, - QT602240_WAITING_FRAME_DATA); + ret = mxt_check_bootloader(client, + MXT_WAITING_FRAME_DATA); if (ret) goto out; @@ -1117,10 +1117,10 @@ static int qt602240_load_fw(struct device *dev, const char *fn) frame_size += 2; /* Write one frame to device */ - qt602240_fw_write(client, fw->data + pos, frame_size); + mxt_fw_write(client, fw->data + pos, frame_size); - ret = qt602240_check_bootloader(client, - QT602240_FRAME_CRC_PASS); + ret = mxt_check_bootloader(client, + MXT_FRAME_CRC_PASS); if (ret) goto out; @@ -1133,19 +1133,19 @@ out: release_firmware(fw); /* Change to slave address of application */ - if (client->addr == QT602240_BOOT_LOW) - client->addr = QT602240_APP_LOW; + if (client->addr == MXT_BOOT_LOW) + client->addr = MXT_APP_LOW; else - client->addr = QT602240_APP_HIGH; + client->addr = MXT_APP_HIGH; return ret; } -static ssize_t qt602240_update_fw_store(struct device *dev, +static ssize_t mxt_update_fw_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct qt602240_data *data = dev_get_drvdata(dev); + struct mxt_data *data = dev_get_drvdata(dev); unsigned int version; int error; @@ -1154,14 +1154,14 @@ static ssize_t qt602240_update_fw_store(struct device *dev, return -EINVAL; } - if (data->info.version < QT602240_VER_21 || version < QT602240_VER_21) { + if (data->info.version < MXT_VER_21 || version < MXT_VER_21) { dev_err(dev, "FW update supported starting with version 21\n"); return -EINVAL; } disable_irq(data->irq); - error = qt602240_load_fw(dev, QT602240_FW_NAME); + error = mxt_load_fw(dev, MXT_FW_NAME); if (error) { dev_err(dev, "The firmware update failed(%d)\n", error); count = error; @@ -1169,12 +1169,12 @@ static ssize_t qt602240_update_fw_store(struct device *dev, dev_dbg(dev, "The firmware update succeeded\n"); /* Wait for reset */ - msleep(QT602240_FWRESET_TIME); + msleep(MXT_FWRESET_TIME); kfree(data->object_table); data->object_table = NULL; - qt602240_initialize(data); + mxt_initialize(data); } enable_irq(data->irq); @@ -1182,60 +1182,60 @@ static ssize_t qt602240_update_fw_store(struct device *dev, return count; } -static DEVICE_ATTR(object, 0444, qt602240_object_show, NULL); -static DEVICE_ATTR(update_fw, 0664, NULL, qt602240_update_fw_store); +static DEVICE_ATTR(object, 0444, mxt_object_show, NULL); +static DEVICE_ATTR(update_fw, 0664, NULL, mxt_update_fw_store); -static struct attribute *qt602240_attrs[] = { +static struct attribute *mxt_attrs[] = { &dev_attr_object.attr, &dev_attr_update_fw.attr, NULL }; -static const struct attribute_group qt602240_attr_group = { - .attrs = qt602240_attrs, +static const struct attribute_group mxt_attr_group = { + .attrs = mxt_attrs, }; -static void qt602240_start(struct qt602240_data *data) +static void mxt_start(struct mxt_data *data) { /* Touch enable */ - qt602240_write_object(data, - QT602240_TOUCH_MULTI, QT602240_TOUCH_CTRL, 0x83); + mxt_write_object(data, + MXT_TOUCH_MULTI, MXT_TOUCH_CTRL, 0x83); } -static void qt602240_stop(struct qt602240_data *data) +static void mxt_stop(struct mxt_data *data) { /* Touch disable */ - qt602240_write_object(data, - QT602240_TOUCH_MULTI, QT602240_TOUCH_CTRL, 0); + mxt_write_object(data, + MXT_TOUCH_MULTI, MXT_TOUCH_CTRL, 0); } -static int qt602240_input_open(struct input_dev *dev) +static int mxt_input_open(struct input_dev *dev) { - struct qt602240_data *data = input_get_drvdata(dev); + struct mxt_data *data = input_get_drvdata(dev); - qt602240_start(data); + mxt_start(data); return 0; } -static void qt602240_input_close(struct input_dev *dev) +static void mxt_input_close(struct input_dev *dev) { - struct qt602240_data *data = input_get_drvdata(dev); + struct mxt_data *data = input_get_drvdata(dev); - qt602240_stop(data); + mxt_stop(data); } -static int __devinit qt602240_probe(struct i2c_client *client, +static int __devinit mxt_probe(struct i2c_client *client, const struct i2c_device_id *id) { - struct qt602240_data *data; + struct mxt_data *data; struct input_dev *input_dev; int error; if (!client->dev.platform_data) return -EINVAL; - data = kzalloc(sizeof(struct qt602240_data), GFP_KERNEL); + data = kzalloc(sizeof(struct mxt_data), GFP_KERNEL); input_dev = input_allocate_device(); if (!data || !input_dev) { dev_err(&client->dev, "Failed to allocate memory\n"); @@ -1243,11 +1243,11 @@ static int __devinit qt602240_probe(struct i2c_client *client, goto err_free_mem; } - input_dev->name = "AT42QT602240/ATMXT224 Touchscreen"; + input_dev->name = "Atmel maXTouch Touchscreen"; input_dev->id.bustype = BUS_I2C; input_dev->dev.parent = &client->dev; - input_dev->open = qt602240_input_open; - input_dev->close = qt602240_input_close; + input_dev->open = mxt_input_open; + input_dev->close = mxt_input_close; __set_bit(EV_ABS, input_dev->evbit); __set_bit(EV_KEY, input_dev->evbit); @@ -1255,17 +1255,17 @@ static int __devinit qt602240_probe(struct i2c_client *client, /* For single touch */ input_set_abs_params(input_dev, ABS_X, - 0, QT602240_MAX_XC, 0, 0); + 0, MXT_MAX_XC, 0, 0); input_set_abs_params(input_dev, ABS_Y, - 0, QT602240_MAX_YC, 0, 0); + 0, MXT_MAX_YC, 0, 0); /* For multi touch */ input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, - 0, QT602240_MAX_AREA, 0, 0); + 0, MXT_MAX_AREA, 0, 0); input_set_abs_params(input_dev, ABS_MT_POSITION_X, - 0, QT602240_MAX_XC, 0, 0); + 0, MXT_MAX_XC, 0, 0); input_set_abs_params(input_dev, ABS_MT_POSITION_Y, - 0, QT602240_MAX_YC, 0, 0); + 0, MXT_MAX_YC, 0, 0); input_set_drvdata(input_dev, data); @@ -1276,11 +1276,11 @@ static int __devinit qt602240_probe(struct i2c_client *client, i2c_set_clientdata(client, data); - error = qt602240_initialize(data); + error = mxt_initialize(data); if (error) goto err_free_object; - error = request_threaded_irq(client->irq, NULL, qt602240_interrupt, + error = request_threaded_irq(client->irq, NULL, mxt_interrupt, IRQF_TRIGGER_FALLING, client->dev.driver->name, data); if (error) { dev_err(&client->dev, "Failed to register interrupt\n"); @@ -1291,7 +1291,7 @@ static int __devinit qt602240_probe(struct i2c_client *client, if (error) goto err_free_irq; - error = sysfs_create_group(&client->dev.kobj, &qt602240_attr_group); + error = sysfs_create_group(&client->dev.kobj, &mxt_attr_group); if (error) goto err_unregister_device; @@ -1310,11 +1310,11 @@ err_free_mem: return error; } -static int __devexit qt602240_remove(struct i2c_client *client) +static int __devexit mxt_remove(struct i2c_client *client) { - struct qt602240_data *data = i2c_get_clientdata(client); + struct mxt_data *data = i2c_get_clientdata(client); - sysfs_remove_group(&client->dev.kobj, &qt602240_attr_group); + sysfs_remove_group(&client->dev.kobj, &mxt_attr_group); free_irq(data->irq, data); input_unregister_device(data->input_dev); kfree(data->object_table); @@ -1324,83 +1324,84 @@ static int __devexit qt602240_remove(struct i2c_client *client) } #ifdef CONFIG_PM -static int qt602240_suspend(struct device *dev) +static int mxt_suspend(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); - struct qt602240_data *data = i2c_get_clientdata(client); + struct mxt_data *data = i2c_get_clientdata(client); struct input_dev *input_dev = data->input_dev; mutex_lock(&input_dev->mutex); if (input_dev->users) - qt602240_stop(data); + mxt_stop(data); mutex_unlock(&input_dev->mutex); return 0; } -static int qt602240_resume(struct device *dev) +static int mxt_resume(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); - struct qt602240_data *data = i2c_get_clientdata(client); + struct mxt_data *data = i2c_get_clientdata(client); struct input_dev *input_dev = data->input_dev; /* Soft reset */ - qt602240_write_object(data, QT602240_GEN_COMMAND, - QT602240_COMMAND_RESET, 1); + mxt_write_object(data, MXT_GEN_COMMAND, + MXT_COMMAND_RESET, 1); - msleep(QT602240_RESET_TIME); + msleep(MXT_RESET_TIME); mutex_lock(&input_dev->mutex); if (input_dev->users) - qt602240_start(data); + mxt_start(data); mutex_unlock(&input_dev->mutex); return 0; } -static const struct dev_pm_ops qt602240_pm_ops = { - .suspend = qt602240_suspend, - .resume = qt602240_resume, +static const struct dev_pm_ops mxt_pm_ops = { + .suspend = mxt_suspend, + .resume = mxt_resume, }; #endif -static const struct i2c_device_id qt602240_id[] = { +static const struct i2c_device_id mxt_id[] = { { "qt602240_ts", 0 }, + { "atmel_mxt_ts", 0 }, { } }; -MODULE_DEVICE_TABLE(i2c, qt602240_id); +MODULE_DEVICE_TABLE(i2c, mxt_id); -static struct i2c_driver qt602240_driver = { +static struct i2c_driver mxt_driver = { .driver = { - .name = "qt602240_ts", + .name = "atmel_mxt_ts", .owner = THIS_MODULE, #ifdef CONFIG_PM - .pm = &qt602240_pm_ops, + .pm = &mxt_pm_ops, #endif }, - .probe = qt602240_probe, - .remove = __devexit_p(qt602240_remove), - .id_table = qt602240_id, + .probe = mxt_probe, + .remove = __devexit_p(mxt_remove), + .id_table = mxt_id, }; -static int __init qt602240_init(void) +static int __init mxt_init(void) { - return i2c_add_driver(&qt602240_driver); + return i2c_add_driver(&mxt_driver); } -static void __exit qt602240_exit(void) +static void __exit mxt_exit(void) { - i2c_del_driver(&qt602240_driver); + i2c_del_driver(&mxt_driver); } -module_init(qt602240_init); -module_exit(qt602240_exit); +module_init(mxt_init); +module_exit(mxt_exit); /* Module information */ MODULE_AUTHOR("Joonyoung Shim "); -MODULE_DESCRIPTION("AT42QT602240/ATMXT224 Touchscreen driver"); +MODULE_DESCRIPTION("Atmel maXTouch Touchscreen driver"); MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 26cdb1ae76f842e895ef4d09796a9101a7f8746b Mon Sep 17 00:00:00 2001 From: Iiro Valkonen Date: Fri, 4 Feb 2011 00:51:05 -0800 Subject: Input: atmel_mxt_ts - read whole message to make CHG low Read the whole message, as reading just the first byte isn't always guaranteed to clear the message. Signed-off-by: Iiro Valkonen Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/atmel_mxt_ts.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index 5dca78a00c94..162a3bf019e4 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -823,16 +823,16 @@ static int mxt_check_matrix_size(struct mxt_data *data) static int mxt_make_highchg(struct mxt_data *data) { struct device *dev = &data->client->dev; + struct mxt_message message; int count = 10; int error; - u8 val; /* Read dummy message to make high CHG pin */ do { - error = mxt_read_object(data, MXT_GEN_MESSAGE, 0, &val); + error = mxt_read_message(data, &message); if (error) return error; - } while ((val != 0xff) && --count); + } while (message.reportid != 0xff && --count); if (!count) { dev_err(dev, "CHG pin isn't cleared\n"); -- cgit v1.2.3 From 5d9d6e91b835796c21fbd7ce479880e5181be112 Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Fri, 11 Feb 2011 01:10:44 -0800 Subject: Input: uinput - fix setting up device name The check for non-empty device name was botched since we tried to account for extra space for the terminating zero at the same time. Convert to kstrndup() to avoid this problem. Signed-off-by: David Herrmann Acked-by: Aristeu Rozanski Signed-off-by: Dmitry Torokhov --- drivers/input/misc/uinput.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c index 82542a1c1098..c0888e3d2fb4 100644 --- a/drivers/input/misc/uinput.c +++ b/drivers/input/misc/uinput.c @@ -347,8 +347,7 @@ static int uinput_setup_device(struct uinput_device *udev, const char __user *bu { struct uinput_user_dev *user_dev; struct input_dev *dev; - char *name; - int i, size; + int i; int retval; if (count != sizeof(struct uinput_user_dev)) @@ -373,19 +372,19 @@ static int uinput_setup_device(struct uinput_device *udev, const char __user *bu udev->ff_effects_max = user_dev->ff_effects_max; - size = strnlen(user_dev->name, UINPUT_MAX_NAME_SIZE) + 1; - if (!size) { + /* Ensure name is filled in */ + if (!user_dev->name[0]) { retval = -EINVAL; goto exit; } kfree(dev->name); - dev->name = name = kmalloc(size, GFP_KERNEL); - if (!name) { + dev->name = kstrndup(user_dev->name, UINPUT_MAX_NAME_SIZE, + GFP_KERNEL); + if (!dev->name) { retval = -ENOMEM; goto exit; } - strlcpy(name, user_dev->name, size); dev->id.bustype = user_dev->id.bustype; dev->id.vendor = user_dev->id.vendor; -- cgit v1.2.3 From 4dfcc271d587465f0d181c7636453ba4d0ec8acc Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 11 Feb 2011 01:10:45 -0800 Subject: Input: uinput - use memdup_user() and friends Instead of open-coding copying of data structures from userspace use memdup_user() and strndup_user(). Note that this introduces change in behavior because driver used to truncate 'phys' longer than 1024 bytes, but now it will refuse to set 'phys' that long. Arguably trying to set such 'phys' is suspect anyways. Signed-off-by: Dmitry Torokhov --- drivers/input/misc/uinput.c | 35 ++++++++++------------------------- 1 file changed, 10 insertions(+), 25 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c index c0888e3d2fb4..7f8331f45bad 100644 --- a/drivers/input/misc/uinput.c +++ b/drivers/input/misc/uinput.c @@ -361,14 +361,9 @@ static int uinput_setup_device(struct uinput_device *udev, const char __user *bu dev = udev->dev; - user_dev = kmalloc(sizeof(struct uinput_user_dev), GFP_KERNEL); - if (!user_dev) - return -ENOMEM; - - if (copy_from_user(user_dev, buffer, sizeof(struct uinput_user_dev))) { - retval = -EFAULT; - goto exit; - } + user_dev = memdup_user(buffer, sizeof(struct uinput_user_dev)); + if (!IS_ERR(user_dev)) + return PTR_ERR(user_dev); udev->ff_effects_max = user_dev->ff_effects_max; @@ -621,7 +616,6 @@ static long uinput_ioctl_handler(struct file *file, unsigned int cmd, struct uinput_ff_upload ff_up; struct uinput_ff_erase ff_erase; struct uinput_request *req; - int length; char *phys; retval = mutex_lock_interruptible(&udev->mutex); @@ -688,24 +682,15 @@ static long uinput_ioctl_handler(struct file *file, unsigned int cmd, retval = -EINVAL; goto out; } - length = strnlen_user(p, 1024); - if (length <= 0) { - retval = -EFAULT; - break; + + phys = strndup_user(p, 1024); + if (IS_ERR(phys)) { + retval = PTR_ERR(phys); + goto out; } + kfree(udev->dev->phys); - udev->dev->phys = phys = kmalloc(length, GFP_KERNEL); - if (!phys) { - retval = -ENOMEM; - break; - } - if (copy_from_user(phys, p, length)) { - udev->dev->phys = NULL; - kfree(phys); - retval = -EFAULT; - break; - } - phys[length - 1] = '\0'; + udev->dev->phys = phys; break; case UI_BEGIN_FF_UPLOAD: -- cgit v1.2.3 From 6b7cfd193a00ba72efb19a05c486f96ae9297d0b Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 11 Feb 2011 08:49:05 -0800 Subject: Input: ad714x-i2c - convert to dev_pm_ops There is a general move to convert drivers to use dev_pm_ops rather than bus specific PM operations in order to facilitate core work. Do this conversion for ad714x-i2c. Signed-off-by: Mark Brown Acked-by: Michael Hennerich Signed-off-by: Dmitry Torokhov --- drivers/input/misc/ad714x-i2c.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/misc/ad714x-i2c.c b/drivers/input/misc/ad714x-i2c.c index 2bef8fa56c94..e21deb1baa8a 100644 --- a/drivers/input/misc/ad714x-i2c.c +++ b/drivers/input/misc/ad714x-i2c.c @@ -10,23 +10,23 @@ #include #include #include +#include #include "ad714x.h" #ifdef CONFIG_PM -static int ad714x_i2c_suspend(struct i2c_client *client, pm_message_t message) +static int ad714x_i2c_suspend(struct device *dev) { - return ad714x_disable(i2c_get_clientdata(client)); + return ad714x_disable(i2c_get_clientdata(to_i2c_client(dev))); } -static int ad714x_i2c_resume(struct i2c_client *client) +static int ad714x_i2c_resume(struct device *dev) { - return ad714x_enable(i2c_get_clientdata(client)); + return ad714x_enable(i2c_get_clientdata(to_i2c_client(dev))); } -#else -# define ad714x_i2c_suspend NULL -# define ad714x_i2c_resume NULL #endif +static SIMPLE_DEV_PM_OPS(ad714x_i2c_pm, ad714x_i2c_suspend, ad714x_i2c_resume); + static int ad714x_i2c_write(struct device *dev, unsigned short reg, unsigned short data) { @@ -114,11 +114,10 @@ MODULE_DEVICE_TABLE(i2c, ad714x_id); static struct i2c_driver ad714x_i2c_driver = { .driver = { .name = "ad714x_captouch", + .pm = &ad714x_i2c_pm, }, .probe = ad714x_i2c_probe, .remove = __devexit_p(ad714x_i2c_remove), - .suspend = ad714x_i2c_suspend, - .resume = ad714x_i2c_resume, .id_table = ad714x_id, }; -- cgit v1.2.3 From a257090cd4e26b96667a15262f322e51f6582507 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 11 Feb 2011 08:49:37 -0800 Subject: Input: ad714x-spi - convert to dev_pm_ops There is a general move to convert drivers to use dev_pm_ops rather than bus specific PM operations in order to facilitate core work. Do this conversion for ad714x-spi. Signed-off-by: Mark Brown Acked-by: Michael Hennerich Signed-off-by: Dmitry Torokhov --- drivers/input/misc/ad714x-spi.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/misc/ad714x-spi.c b/drivers/input/misc/ad714x-spi.c index 7f8dedfd1bfe..4120dd549305 100644 --- a/drivers/input/misc/ad714x-spi.c +++ b/drivers/input/misc/ad714x-spi.c @@ -9,6 +9,7 @@ #include /* BUS_I2C */ #include #include +#include #include #include "ad714x.h" @@ -16,20 +17,19 @@ #define AD714x_SPI_READ BIT(10) #ifdef CONFIG_PM -static int ad714x_spi_suspend(struct spi_device *spi, pm_message_t message) +static int ad714x_spi_suspend(struct device *dev) { - return ad714x_disable(spi_get_drvdata(spi)); + return ad714x_disable(spi_get_drvdata(to_spi_device(dev))); } -static int ad714x_spi_resume(struct spi_device *spi) +static int ad714x_spi_resume(struct device *dev) { - return ad714x_enable(spi_get_drvdata(spi)); + return ad714x_enable(spi_get_drvdata(to_spi_device(dev))); } -#else -# define ad714x_spi_suspend NULL -# define ad714x_spi_resume NULL #endif +static SIMPLE_DEV_PM_OPS(ad714x_spi_pm, ad714x_spi_suspend, ad714x_spi_resume); + static int ad714x_spi_read(struct device *dev, unsigned short reg, unsigned short *data) { @@ -79,11 +79,10 @@ static struct spi_driver ad714x_spi_driver = { .driver = { .name = "ad714x_captouch", .owner = THIS_MODULE, + .pm = &ad714x_spi_pm, }, .probe = ad714x_spi_probe, .remove = __devexit_p(ad714x_spi_remove), - .suspend = ad714x_spi_suspend, - .resume = ad714x_spi_resume, }; static __init int ad714x_spi_init(void) -- cgit v1.2.3 From 65b0c03852d75e4d7d0bc282344b1500fe471725 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 11 Feb 2011 08:50:37 -0800 Subject: Input: lm8323 - convert to dev_pm_ops There is a general move away from bus specific PM operations to using dev_pm_ops in order to facilicate core improvements. Update lm8323 to the new model. Signed-off-by: Mark Brown Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/lm8323.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/keyboard/lm8323.c b/drivers/input/keyboard/lm8323.c index f7c2a166576b..b732870ecc89 100644 --- a/drivers/input/keyboard/lm8323.c +++ b/drivers/input/keyboard/lm8323.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -802,8 +803,9 @@ static int __devexit lm8323_remove(struct i2c_client *client) * We don't need to explicitly suspend the chip, as it already switches off * when there's no activity. */ -static int lm8323_suspend(struct i2c_client *client, pm_message_t mesg) +static int lm8323_suspend(struct device *dev) { + struct i2c_client *client = to_i2c_client(dev); struct lm8323_chip *lm = i2c_get_clientdata(client); int i; @@ -821,8 +823,9 @@ static int lm8323_suspend(struct i2c_client *client, pm_message_t mesg) return 0; } -static int lm8323_resume(struct i2c_client *client) +static int lm8323_resume(struct device *dev) { + struct i2c_client *client = to_i2c_client(dev); struct lm8323_chip *lm = i2c_get_clientdata(client); int i; @@ -839,11 +842,10 @@ static int lm8323_resume(struct i2c_client *client) return 0; } -#else -#define lm8323_suspend NULL -#define lm8323_resume NULL #endif +static SIMPLE_DEV_PM_OPS(lm8323_pm_ops, lm8323_suspend, lm8323_resume); + static const struct i2c_device_id lm8323_id[] = { { "lm8323", 0 }, { } @@ -852,11 +854,10 @@ static const struct i2c_device_id lm8323_id[] = { static struct i2c_driver lm8323_i2c_driver = { .driver = { .name = "lm8323", + .pm = &lm8323_pm_ops, }, .probe = lm8323_probe, .remove = __devexit_p(lm8323_remove), - .suspend = lm8323_suspend, - .resume = lm8323_resume, .id_table = lm8323_id, }; MODULE_DEVICE_TABLE(i2c, lm8323_id); -- cgit v1.2.3 From 76e2c68f3214c3a641b9e489cdaea035bfbc8060 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 11 Feb 2011 08:51:13 -0800 Subject: Input: max7359 - convert to dev_pm_ops There is a general move to convert drivers to use dev_pm_ops rather than bus specific ops to facilitate core work. Do this conversion for max7359. Signed-off-by: Mark Brown Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/max7359_keypad.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/keyboard/max7359_keypad.c b/drivers/input/keyboard/max7359_keypad.c index 9091ff5ea808..5afe35ad24d3 100644 --- a/drivers/input/keyboard/max7359_keypad.c +++ b/drivers/input/keyboard/max7359_keypad.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -271,8 +272,10 @@ static int __devexit max7359_remove(struct i2c_client *client) } #ifdef CONFIG_PM -static int max7359_suspend(struct i2c_client *client, pm_message_t mesg) +static int max7359_suspend(struct device *dev) { + struct i2c_client *client = to_i2c_client(dev); + max7359_fall_deepsleep(client); if (device_may_wakeup(&client->dev)) @@ -281,8 +284,10 @@ static int max7359_suspend(struct i2c_client *client, pm_message_t mesg) return 0; } -static int max7359_resume(struct i2c_client *client) +static int max7359_resume(struct device *dev) { + struct i2c_client *client = to_i2c_client(dev); + if (device_may_wakeup(&client->dev)) disable_irq_wake(client->irq); @@ -291,11 +296,10 @@ static int max7359_resume(struct i2c_client *client) return 0; } -#else -#define max7359_suspend NULL -#define max7359_resume NULL #endif +static SIMPLE_DEV_PM_OPS(max7359_pm, max7359_suspend, max7359_resume); + static const struct i2c_device_id max7359_ids[] = { { "max7359", 0 }, { } @@ -305,11 +309,10 @@ MODULE_DEVICE_TABLE(i2c, max7359_ids); static struct i2c_driver max7359_i2c_driver = { .driver = { .name = "max7359", + .pm = &max7359_pm, }, .probe = max7359_probe, .remove = __devexit_p(max7359_remove), - .suspend = max7359_suspend, - .resume = max7359_resume, .id_table = max7359_ids, }; -- cgit v1.2.3 From fbb899356d4a6b6080ab3d9656914938db49449e Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 11 Feb 2011 08:51:52 -0800 Subject: Input: adxl34x-i2c - convert to dev_pm_ops There is a general move to convert drivers to use dev_pm_ops rather than bus specific ones in order to facilitate core development. Do this conversion for adxl34x-i2c. Signed-off-by: Mark Brown Acked-by: Michael Hennerich Signed-off-by: Dmitry Torokhov --- drivers/input/misc/adxl34x-i2c.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/misc/adxl34x-i2c.c b/drivers/input/misc/adxl34x-i2c.c index 0779724af7e7..ccacf2bb06a4 100644 --- a/drivers/input/misc/adxl34x-i2c.c +++ b/drivers/input/misc/adxl34x-i2c.c @@ -11,6 +11,7 @@ #include #include #include +#include #include "adxl34x.h" static int adxl34x_smbus_read(struct device *dev, unsigned char reg) @@ -105,8 +106,9 @@ static int __devexit adxl34x_i2c_remove(struct i2c_client *client) } #ifdef CONFIG_PM -static int adxl34x_i2c_suspend(struct i2c_client *client, pm_message_t message) +static int adxl34x_i2c_suspend(struct device *dev) { + struct i2c_client *client = to_i2c_client(dev); struct adxl34x *ac = i2c_get_clientdata(client); adxl34x_suspend(ac); @@ -114,19 +116,20 @@ static int adxl34x_i2c_suspend(struct i2c_client *client, pm_message_t message) return 0; } -static int adxl34x_i2c_resume(struct i2c_client *client) +static int adxl34x_i2c_resume(struct device *dev) { + struct i2c_client *client = to_i2c_client(dev); struct adxl34x *ac = i2c_get_clientdata(client); adxl34x_resume(ac); return 0; } -#else -# define adxl34x_i2c_suspend NULL -# define adxl34x_i2c_resume NULL #endif +static SIMPLE_DEV_PM_OPS(adxl34x_i2c_pm, adxl34x_i2c_suspend, + adxl34x_i2c_resume); + static const struct i2c_device_id adxl34x_id[] = { { "adxl34x", 0 }, { } @@ -138,11 +141,10 @@ static struct i2c_driver adxl34x_driver = { .driver = { .name = "adxl34x", .owner = THIS_MODULE, + .pm = &adxl34x_i2c_pm, }, .probe = adxl34x_i2c_probe, .remove = __devexit_p(adxl34x_i2c_remove), - .suspend = adxl34x_i2c_suspend, - .resume = adxl34x_i2c_resume, .id_table = adxl34x_id, }; -- cgit v1.2.3 From 4d1ac94e2e3cd15f06ffc74efa42d6572fdf7689 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 11 Feb 2011 09:22:40 -0800 Subject: Input: adxl34x-spi - convert to dev_pm_ops There is a general move to convert drivers to use dev_pm_ops rather than bus specific ones in order to facilitate core development. Do this conversion for adxl34x-spi. Signed-off-by: Mark Brown Acked-by: Michael Hennerich Signed-off-by: Dmitry Torokhov --- drivers/input/misc/adxl34x-spi.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/misc/adxl34x-spi.c b/drivers/input/misc/adxl34x-spi.c index 782de9e89828..5231add66a65 100644 --- a/drivers/input/misc/adxl34x-spi.c +++ b/drivers/input/misc/adxl34x-spi.c @@ -10,6 +10,7 @@ #include /* BUS_SPI */ #include #include +#include #include #include "adxl34x.h" @@ -94,8 +95,9 @@ static int __devexit adxl34x_spi_remove(struct spi_device *spi) } #ifdef CONFIG_PM -static int adxl34x_spi_suspend(struct spi_device *spi, pm_message_t message) +static int adxl34x_spi_suspend(struct device *dev) { + struct spi_device *spi = to_spi_device(dev); struct adxl34x *ac = dev_get_drvdata(&spi->dev); adxl34x_suspend(ac); @@ -103,29 +105,29 @@ static int adxl34x_spi_suspend(struct spi_device *spi, pm_message_t message) return 0; } -static int adxl34x_spi_resume(struct spi_device *spi) +static int adxl34x_spi_resume(struct device *dev) { + struct spi_device *spi = to_spi_device(dev); struct adxl34x *ac = dev_get_drvdata(&spi->dev); adxl34x_resume(ac); return 0; } -#else -# define adxl34x_spi_suspend NULL -# define adxl34x_spi_resume NULL #endif +static SIMPLE_DEV_PM_OPS(adxl34x_spi_pm, adxl34x_spi_suspend, + adxl34x_spi_resume); + static struct spi_driver adxl34x_driver = { .driver = { .name = "adxl34x", .bus = &spi_bus_type, .owner = THIS_MODULE, + .pm = &adxl34x_spi_pm, }, .probe = adxl34x_spi_probe, .remove = __devexit_p(adxl34x_spi_remove), - .suspend = adxl34x_spi_suspend, - .resume = adxl34x_spi_resume, }; static int __init adxl34x_spi_init(void) -- cgit v1.2.3 From 3dcab3bdd9cbf45433fc4e1514f3144638652e2b Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 11 Feb 2011 08:53:04 -0800 Subject: Input: adxl34x - fix references to adx134x The adxl34x SPI driver has what appears to be a typo referring to the device as adx134x with the numeral 1 rather than letter l. This appears to be an error so convert. Signed-off-by: Mark Brown Acked-by: Michael Hennerich Signed-off-by: Dmitry Torokhov --- drivers/input/misc/adxl34x-spi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/misc/adxl34x-spi.c b/drivers/input/misc/adxl34x-spi.c index 5231add66a65..f29de22fdda0 100644 --- a/drivers/input/misc/adxl34x-spi.c +++ b/drivers/input/misc/adxl34x-spi.c @@ -58,7 +58,7 @@ static int adxl34x_spi_read_block(struct device *dev, return (status < 0) ? status : 0; } -static const struct adxl34x_bus_ops adx134x_spi_bops = { +static const struct adxl34x_bus_ops adxl34x_spi_bops = { .bustype = BUS_SPI, .write = adxl34x_spi_write, .read = adxl34x_spi_read, @@ -77,7 +77,7 @@ static int __devinit adxl34x_spi_probe(struct spi_device *spi) ac = adxl34x_probe(&spi->dev, spi->irq, spi->max_speed_hz > MAX_FREQ_NO_FIFODELAY, - &adx134x_spi_bops); + &adxl34x_spi_bops); if (IS_ERR(ac)) return PTR_ERR(ac); -- cgit v1.2.3 From 87b2c7df329e547c1905e0b7e13bfce09cfa5cfe Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 11 Feb 2011 08:53:33 -0800 Subject: Input: synaptics_i2c - convert to dev_pm_ops There is a general move to convert drivers to dev_pm_ops rather than bus specific PM ops in order to facilitate core development. Do this converison for synaptics-i2c. Signed-off-by: Mark Brown Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/synaptics_i2c.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/mouse/synaptics_i2c.c b/drivers/input/mouse/synaptics_i2c.c index 0ae62f0bcb32..f6aa26d305ed 100644 --- a/drivers/input/mouse/synaptics_i2c.c +++ b/drivers/input/mouse/synaptics_i2c.c @@ -18,6 +18,7 @@ #include #include #include +#include #define DRIVER_NAME "synaptics_i2c" /* maximum product id is 15 characters */ @@ -619,8 +620,9 @@ static int __devexit synaptics_i2c_remove(struct i2c_client *client) } #ifdef CONFIG_PM -static int synaptics_i2c_suspend(struct i2c_client *client, pm_message_t mesg) +static int synaptics_i2c_suspend(struct device *dev) { + struct i2c_client *client = to_i2c_client(dev); struct synaptics_i2c *touch = i2c_get_clientdata(client); cancel_delayed_work_sync(&touch->dwork); @@ -631,9 +633,10 @@ static int synaptics_i2c_suspend(struct i2c_client *client, pm_message_t mesg) return 0; } -static int synaptics_i2c_resume(struct i2c_client *client) +static int synaptics_i2c_resume(struct device *dev) { int ret; + struct i2c_client *client = to_i2c_client(dev); struct synaptics_i2c *touch = i2c_get_clientdata(client); ret = synaptics_i2c_reset_config(client); @@ -645,11 +648,11 @@ static int synaptics_i2c_resume(struct i2c_client *client) return 0; } -#else -#define synaptics_i2c_suspend NULL -#define synaptics_i2c_resume NULL #endif +static SIMPLE_DEV_PM_OPS(synaptics_i2c_pm, synaptics_i2c_suspend, + synaptics_i2c_resume); + static const struct i2c_device_id synaptics_i2c_id_table[] = { { "synaptics_i2c", 0 }, { }, @@ -660,13 +663,12 @@ static struct i2c_driver synaptics_i2c_driver = { .driver = { .name = DRIVER_NAME, .owner = THIS_MODULE, + .pm = &synaptics_i2c_pm, }, .probe = synaptics_i2c_probe, .remove = __devexit_p(synaptics_i2c_remove), - .suspend = synaptics_i2c_suspend, - .resume = synaptics_i2c_resume, .id_table = synaptics_i2c_id_table, }; -- cgit v1.2.3 From 46ee2a05a466ca7e34d65fe3feba195d62109362 Mon Sep 17 00:00:00 2001 From: Chris Leech Date: Tue, 15 Feb 2011 13:36:52 -0800 Subject: Input: atmel_mxt_ts - add mXT224 identifier to id_table "mXT224" is used in the Intel mid firmware in SFI tables to identify the presence of this I2C device. Signed-off-by: Chris Leech Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/atmel_mxt_ts.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index 162a3bf019e4..fe8902e1f010 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -1371,6 +1371,7 @@ static const struct dev_pm_ops mxt_pm_ops = { static const struct i2c_device_id mxt_id[] = { { "qt602240_ts", 0 }, { "atmel_mxt_ts", 0 }, + { "mXT224", 0 }, { } }; MODULE_DEVICE_TABLE(i2c, mxt_id); -- cgit v1.2.3 From 71749f5c66e797a39600dae9de58aab3858dc488 Mon Sep 17 00:00:00 2001 From: Iiro Valkonen Date: Tue, 15 Feb 2011 13:36:52 -0800 Subject: Input: atmel_mxt_ts - allow board code to suppliy controller config As there is no common configuration settings that would work in every situation, remove the fixed config data from driver code and add config data to platform data. Signed-off-by: Iiro Valkonen Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/atmel_mxt_ts.c | 148 +++---------------------------- 1 file changed, 13 insertions(+), 135 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index fe8902e1f010..52032ef3d3ab 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -199,122 +199,6 @@ #define MXT_MAX_FINGER 10 -/* Initial register values recommended from chip vendor */ -static const u8 init_vals_ver_20[] = { - /* MXT_GEN_COMMAND(6) */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* MXT_GEN_POWER(7) */ - 0x20, 0xff, 0x32, - /* MXT_GEN_ACQUIRE(8) */ - 0x08, 0x05, 0x05, 0x00, 0x00, 0x00, 0x05, 0x14, - /* MXT_TOUCH_MULTI(9) */ - 0x00, 0x00, 0x00, 0x11, 0x0a, 0x00, 0x00, 0x00, 0x02, 0x00, - 0x00, 0x01, 0x01, 0x0e, 0x0a, 0x0a, 0x0a, 0x0a, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x64, - /* MXT_TOUCH_KEYARRAY(15) */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, - /* MXT_SPT_GPIOPWM(19) */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, - /* MXT_PROCI_GRIPFACE(20) */ - 0x00, 0x64, 0x64, 0x64, 0x64, 0x00, 0x00, 0x1e, 0x14, 0x04, - 0x1e, 0x00, - /* MXT_PROCG_NOISE(22) */ - 0x05, 0x00, 0x00, 0x19, 0x00, 0xe7, 0xff, 0x04, 0x32, 0x00, - 0x01, 0x0a, 0x0f, 0x14, 0x00, 0x00, 0xe8, - /* MXT_TOUCH_PROXIMITY(23) */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, - /* MXT_PROCI_ONETOUCH(24) */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* MXT_SPT_SELFTEST(25) */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - /* MXT_PROCI_TWOTOUCH(27) */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* MXT_SPT_CTECONFIG(28) */ - 0x00, 0x00, 0x00, 0x04, 0x08, -}; - -static const u8 init_vals_ver_21[] = { - /* MXT_GEN_COMMAND(6) */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* MXT_GEN_POWER(7) */ - 0x20, 0xff, 0x32, - /* MXT_GEN_ACQUIRE(8) */ - 0x0a, 0x00, 0x05, 0x00, 0x00, 0x00, 0x09, 0x23, - /* MXT_TOUCH_MULTI(9) */ - 0x00, 0x00, 0x00, 0x13, 0x0b, 0x00, 0x00, 0x00, 0x02, 0x00, - 0x00, 0x01, 0x01, 0x0e, 0x0a, 0x0a, 0x0a, 0x0a, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* MXT_TOUCH_KEYARRAY(15) */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, - /* MXT_SPT_GPIOPWM(19) */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* MXT_PROCI_GRIPFACE(20) */ - 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x28, 0x04, - 0x0f, 0x0a, - /* MXT_PROCG_NOISE(22) */ - 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x23, 0x00, - 0x00, 0x05, 0x0f, 0x19, 0x23, 0x2d, 0x03, - /* MXT_TOUCH_PROXIMITY(23) */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, - /* MXT_PROCI_ONETOUCH(24) */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* MXT_SPT_SELFTEST(25) */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - /* MXT_PROCI_TWOTOUCH(27) */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* MXT_SPT_CTECONFIG(28) */ - 0x00, 0x00, 0x00, 0x08, 0x10, 0x00, -}; - -static const u8 init_vals_ver_22[] = { - /* MXT_GEN_COMMAND(6) */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* MXT_GEN_POWER(7) */ - 0x20, 0xff, 0x32, - /* MXT_GEN_ACQUIRE(8) */ - 0x0a, 0x00, 0x05, 0x00, 0x00, 0x00, 0x09, 0x23, - /* MXT_TOUCH_MULTI(9) */ - 0x00, 0x00, 0x00, 0x13, 0x0b, 0x00, 0x00, 0x00, 0x02, 0x00, - 0x00, 0x01, 0x01, 0x0e, 0x0a, 0x0a, 0x0a, 0x0a, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, - /* MXT_TOUCH_KEYARRAY(15) */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, - /* MXT_SPT_GPIOPWM(19) */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* MXT_PROCI_GRIPFACE(20) */ - 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x28, 0x04, - 0x0f, 0x0a, - /* MXT_PROCG_NOISE(22) */ - 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x23, 0x00, - 0x00, 0x05, 0x0f, 0x19, 0x23, 0x2d, 0x03, - /* MXT_TOUCH_PROXIMITY(23) */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, - /* MXT_PROCI_ONETOUCH(24) */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* MXT_SPT_SELFTEST(25) */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - /* MXT_PROCI_TWOTOUCH(27) */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* MXT_SPT_CTECONFIG(28) */ - 0x00, 0x00, 0x00, 0x08, 0x10, 0x00, -}; - struct mxt_info { u8 family_id; u8 variant_id; @@ -714,26 +598,15 @@ end: static int mxt_check_reg_init(struct mxt_data *data) { + const struct mxt_platform_data *pdata = data->pdata; struct mxt_object *object; struct device *dev = &data->client->dev; int index = 0; - int i, j; - u8 version = data->info.version; - u8 *init_vals; + int i, j, config_offset; - switch (version) { - case MXT_VER_20: - init_vals = (u8 *)init_vals_ver_20; - break; - case MXT_VER_21: - init_vals = (u8 *)init_vals_ver_21; - break; - case MXT_VER_22: - init_vals = (u8 *)init_vals_ver_22; - break; - default: - dev_err(dev, "Firmware version %d doesn't support\n", version); - return -EINVAL; + if (!pdata->config) { + dev_dbg(dev, "No cfg data defined, skipping reg init\n"); + return 0; } for (i = 0; i < data->info.object_num; i++) { @@ -742,10 +615,15 @@ static int mxt_check_reg_init(struct mxt_data *data) if (!mxt_object_writable(object->type)) continue; - for (j = 0; j < object->size + 1; j++) + for (j = 0; j < object->size + 1; j++) { + config_offset = index + j; + if (config_offset > pdata->config_length) { + dev_err(dev, "Not enough config data!\n"); + return -EINVAL; + } mxt_write_object(data, object->type, j, - init_vals[index + j]); - + pdata->config[config_offset]); + } index += object->size + 1; } -- cgit v1.2.3 From 919ed895f0b4227da26ea1b0a1347db5010f105e Mon Sep 17 00:00:00 2001 From: Iiro Valkonen Date: Tue, 15 Feb 2011 13:36:52 -0800 Subject: Input: atmel_mxt_ts - allow board code to specify IRQ flags Different board have different requirements/setups so let's be more flexible. Signed-off-by: Iiro Valkonen Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/atmel_mxt_ts.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index 52032ef3d3ab..d2e5864ca096 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -1106,11 +1106,12 @@ static void mxt_input_close(struct input_dev *dev) static int __devinit mxt_probe(struct i2c_client *client, const struct i2c_device_id *id) { + const struct mxt_platform_data *pdata = client->dev.platform_data; struct mxt_data *data; struct input_dev *input_dev; int error; - if (!client->dev.platform_data) + if (!pdata) return -EINVAL; data = kzalloc(sizeof(struct mxt_data), GFP_KERNEL); @@ -1149,7 +1150,7 @@ static int __devinit mxt_probe(struct i2c_client *client, data->client = client; data->input_dev = input_dev; - data->pdata = client->dev.platform_data; + data->pdata = pdata; data->irq = client->irq; i2c_set_clientdata(client, data); @@ -1159,7 +1160,7 @@ static int __devinit mxt_probe(struct i2c_client *client, goto err_free_object; error = request_threaded_irq(client->irq, NULL, mxt_interrupt, - IRQF_TRIGGER_FALLING, client->dev.driver->name, data); + pdata->irqflags, client->dev.driver->name, data); if (error) { dev_err(&client->dev, "Failed to register interrupt\n"); goto err_free_object; -- cgit v1.2.3 From 163d27706bb91a648cc292151fc072e1e8cd4b4d Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 18 Feb 2011 08:30:52 -0800 Subject: Input: uinput - reversed test in uinput_setup_device() The test here is reversed. It should be if (IS_ERR()) instead of if (!IS_ERR()). Signed-off-by: Dan Carpenter Signed-off-by: Dmitry Torokhov --- drivers/input/misc/uinput.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/input') diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c index 7f8331f45bad..364bdf43a381 100644 --- a/drivers/input/misc/uinput.c +++ b/drivers/input/misc/uinput.c @@ -362,7 +362,7 @@ static int uinput_setup_device(struct uinput_device *udev, const char __user *bu dev = udev->dev; user_dev = memdup_user(buffer, sizeof(struct uinput_user_dev)); - if (!IS_ERR(user_dev)) + if (IS_ERR(user_dev)) return PTR_ERR(user_dev); udev->ff_effects_max = user_dev->ff_effects_max; -- cgit v1.2.3 From 5ad567ffbaf208bd35bff4341906346c1a1d4574 Mon Sep 17 00:00:00 2001 From: Abraham Arce Date: Tue, 22 Feb 2011 22:25:59 -0800 Subject: Input: omap4-keypad - wire up runtime PM handling Enable Runtime PM functionality in OMAP4 driver based on the following assumptions: - keyboard controller in wakeup domain so it is always on and power impact is minimal; - in OMAP4 the device control is at module/device level and ick/fclk level control is difficult so cutting of clocks will prevent interrupts. Signed-off-by: Abraham Arce Signed-off-by: Shubhrajyoti D Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/omap4-keypad.c | 74 ++++++++++++++++++++++++++--------- 1 file changed, 55 insertions(+), 19 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/keyboard/omap4-keypad.c b/drivers/input/keyboard/omap4-keypad.c index 45bd0977d006..c51a3c4a7feb 100644 --- a/drivers/input/keyboard/omap4-keypad.c +++ b/drivers/input/keyboard/omap4-keypad.c @@ -29,6 +29,7 @@ #include #include #include +#include #include @@ -80,20 +81,6 @@ struct omap4_keypad { unsigned short keymap[]; }; -static void __devinit omap4_keypad_config(struct omap4_keypad *keypad_data) -{ - __raw_writel(OMAP4_VAL_FUNCTIONALCFG, - keypad_data->base + OMAP4_KBD_CTRL); - __raw_writel(OMAP4_VAL_DEBOUNCINGTIME, - keypad_data->base + OMAP4_KBD_DEBOUNCINGTIME); - __raw_writel(OMAP4_VAL_IRQDISABLE, - keypad_data->base + OMAP4_KBD_IRQSTATUS); - __raw_writel(OMAP4_DEF_IRQENABLE_EVENTEN | OMAP4_DEF_IRQENABLE_LONGKEY, - keypad_data->base + OMAP4_KBD_IRQENABLE); - __raw_writel(OMAP4_DEF_WUP_EVENT_ENA | OMAP4_DEF_WUP_LONG_KEY_ENA, - keypad_data->base + OMAP4_KBD_WAKEUPENABLE); -} - /* Interrupt handler */ static irqreturn_t omap4_keypad_interrupt(int irq, void *dev_id) { @@ -144,6 +131,49 @@ static irqreturn_t omap4_keypad_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } +static int omap4_keypad_open(struct input_dev *input) +{ + struct omap4_keypad *keypad_data = input_get_drvdata(input); + + pm_runtime_get_sync(input->dev.parent); + + disable_irq(keypad_data->irq); + + __raw_writel(OMAP4_VAL_FUNCTIONALCFG, + keypad_data->base + OMAP4_KBD_CTRL); + __raw_writel(OMAP4_VAL_DEBOUNCINGTIME, + keypad_data->base + OMAP4_KBD_DEBOUNCINGTIME); + __raw_writel(OMAP4_VAL_IRQDISABLE, + keypad_data->base + OMAP4_KBD_IRQSTATUS); + __raw_writel(OMAP4_DEF_IRQENABLE_EVENTEN | OMAP4_DEF_IRQENABLE_LONGKEY, + keypad_data->base + OMAP4_KBD_IRQENABLE); + __raw_writel(OMAP4_DEF_WUP_EVENT_ENA | OMAP4_DEF_WUP_LONG_KEY_ENA, + keypad_data->base + OMAP4_KBD_WAKEUPENABLE); + + enable_irq(keypad_data->irq); + + return 0; +} + +static void omap4_keypad_close(struct input_dev *input) +{ + struct omap4_keypad *keypad_data = input_get_drvdata(input); + + disable_irq(keypad_data->irq); + + /* Disable interrupts */ + __raw_writel(OMAP4_VAL_IRQDISABLE, + keypad_data->base + OMAP4_KBD_IRQENABLE); + + /* clear pending interrupts */ + __raw_writel(__raw_readl(keypad_data->base + OMAP4_KBD_IRQSTATUS), + keypad_data->base + OMAP4_KBD_IRQSTATUS); + + enable_irq(keypad_data->irq); + + pm_runtime_put_sync(input->dev.parent); +} + static int __devinit omap4_keypad_probe(struct platform_device *pdev) { const struct omap4_keypad_platform_data *pdata; @@ -225,6 +255,9 @@ static int __devinit omap4_keypad_probe(struct platform_device *pdev) input_dev->id.product = 0x0001; input_dev->id.version = 0x0001; + input_dev->open = omap4_keypad_open; + input_dev->close = omap4_keypad_close; + input_dev->keycode = keypad_data->keymap; input_dev->keycodesize = sizeof(keypad_data->keymap[0]); input_dev->keycodemax = max_keys; @@ -239,8 +272,6 @@ static int __devinit omap4_keypad_probe(struct platform_device *pdev) matrix_keypad_build_keymap(pdata->keymap_data, row_shift, input_dev->keycode, input_dev->keybit); - omap4_keypad_config(keypad_data); - error = request_irq(keypad_data->irq, omap4_keypad_interrupt, IRQF_TRIGGER_RISING, "omap4-keypad", keypad_data); @@ -249,17 +280,19 @@ static int __devinit omap4_keypad_probe(struct platform_device *pdev) goto err_free_input; } + pm_runtime_enable(&pdev->dev); + error = input_register_device(keypad_data->input); if (error < 0) { dev_err(&pdev->dev, "failed to register input device\n"); - goto err_free_irq; + goto err_pm_disable; } - platform_set_drvdata(pdev, keypad_data); return 0; -err_free_irq: +err_pm_disable: + pm_runtime_disable(&pdev->dev); free_irq(keypad_data->irq, keypad_data); err_free_input: input_free_device(input_dev); @@ -278,6 +311,9 @@ static int __devexit omap4_keypad_remove(struct platform_device *pdev) struct resource *res; free_irq(keypad_data->irq, keypad_data); + + pm_runtime_disable(&pdev->dev); + input_unregister_device(keypad_data->input); iounmap(keypad_data->base); -- cgit v1.2.3 From adf779c1ee1d5556ebd83e39a7189022d4ebce3a Mon Sep 17 00:00:00 2001 From: Heungjun Kim Date: Wed, 23 Feb 2011 21:40:11 -0800 Subject: Input: mcs_touchkey - add support for suspend/resume This adds support for system-level suspend/resume to the driver. Signed-off-by: Heungjun Kim Signed-off-by: Kyungmin Park Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/mcs_touchkey.c | 48 ++++++++++++++++++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) (limited to 'drivers/input') diff --git a/drivers/input/keyboard/mcs_touchkey.c b/drivers/input/keyboard/mcs_touchkey.c index 63b849d7e90b..03fa59a0b220 100644 --- a/drivers/input/keyboard/mcs_touchkey.c +++ b/drivers/input/keyboard/mcs_touchkey.c @@ -1,5 +1,5 @@ /* - * mcs_touchkey.c - Touchkey driver for MELFAS MCS5000/5080 controller + * Touchkey driver for MELFAS MCS5000/5080 controller * * Copyright (C) 2010 Samsung Electronics Co.Ltd * Author: HeungJun Kim @@ -19,6 +19,7 @@ #include #include #include +#include /* MCS5000 Touchkey */ #define MCS5000_TOUCHKEY_STATUS 0x04 @@ -45,6 +46,8 @@ struct mcs_touchkey_chip { }; struct mcs_touchkey_data { + void (*poweron)(bool); + struct i2c_client *client; struct input_dev *input_dev; struct mcs_touchkey_chip chip; @@ -169,6 +172,11 @@ static int __devinit mcs_touchkey_probe(struct i2c_client *client, if (pdata->cfg_pin) pdata->cfg_pin(); + if (pdata->poweron) { + data->poweron = pdata->poweron; + data->poweron(true); + } + error = request_threaded_irq(client->irq, NULL, mcs_touchkey_interrupt, IRQF_TRIGGER_FALLING, client->dev.driver->name, data); if (error) { @@ -196,12 +204,49 @@ static int __devexit mcs_touchkey_remove(struct i2c_client *client) struct mcs_touchkey_data *data = i2c_get_clientdata(client); free_irq(client->irq, data); + if (data->poweron) + data->poweron(false); input_unregister_device(data->input_dev); kfree(data); return 0; } +#ifdef CONFIG_PM_SLEEP +static int mcs_touchkey_suspend(struct device *dev) +{ + struct mcs_touchkey_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; + + /* Disable the work */ + disable_irq(client->irq); + + /* Finally turn off the power */ + if (data->poweron) + data->poweron(false); + + return 0; +} + +static int mcs_touchkey_resume(struct device *dev) +{ + struct mcs_touchkey_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; + + /* Enable the device first */ + if (data->poweron) + data->poweron(true); + + /* Enable irq again */ + enable_irq(client->irq); + + return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(mcs_touchkey_pm_ops, + mcs_touchkey_suspend, mcs_touchkey_resume); + static const struct i2c_device_id mcs_touchkey_id[] = { { "mcs5000_touchkey", MCS5000_TOUCHKEY }, { "mcs5080_touchkey", MCS5080_TOUCHKEY }, @@ -213,6 +258,7 @@ static struct i2c_driver mcs_touchkey_driver = { .driver = { .name = "mcs_touchkey", .owner = THIS_MODULE, + .pm = &mcs_touchkey_pm_ops, }, .probe = mcs_touchkey_probe, .remove = __devexit_p(mcs_touchkey_remove), -- cgit v1.2.3 From 5f62615ef5e50b0ad6c125fe1e38f2ac675012e2 Mon Sep 17 00:00:00 2001 From: HeungJun Kim Date: Wed, 23 Feb 2011 21:42:49 -0800 Subject: Input: mcs_touchkey - add shutdown handler The MCS50XX series has a HW bug that requires explicit chip power down. If chip is not powered down before shutting the system down the control pins (powerup, interrupt) are pulled up and residue current continues flowing into the chips making them continue consuming power. Signed-off-by: Heungjun Kim Signed-off-by: Kyungmin Park Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/mcs_touchkey.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers/input') diff --git a/drivers/input/keyboard/mcs_touchkey.c b/drivers/input/keyboard/mcs_touchkey.c index 03fa59a0b220..af1aab324a4c 100644 --- a/drivers/input/keyboard/mcs_touchkey.c +++ b/drivers/input/keyboard/mcs_touchkey.c @@ -212,6 +212,14 @@ static int __devexit mcs_touchkey_remove(struct i2c_client *client) return 0; } +static void mcs_touchkey_shutdown(struct i2c_client *client) +{ + struct mcs_touchkey_data *data = i2c_get_clientdata(client); + + if (data->poweron) + data->poweron(false); +} + #ifdef CONFIG_PM_SLEEP static int mcs_touchkey_suspend(struct device *dev) { @@ -262,6 +270,7 @@ static struct i2c_driver mcs_touchkey_driver = { }, .probe = mcs_touchkey_probe, .remove = __devexit_p(mcs_touchkey_remove), + .shutdown = mcs_touchkey_shutdown, .id_table = mcs_touchkey_id, }; -- cgit v1.2.3 From 0d3c07378bb7d423302d7cb0dcd3fa5a26c40220 Mon Sep 17 00:00:00 2001 From: Iiro Valkonen Date: Wed, 23 Feb 2011 21:07:20 -0800 Subject: Input: atmel_mxt_ts - remove matrix size check The mxt_check_matrix_size() is currently setting the CTE mode to match xline/yline information that is in the platform data, but it does not take into account for example the fact that we could have a key array in use too (key array would use some x/y lines as well). It would be better to simply rely on the configuration data, and make sure that the CTE mode set in there matches the touch object (touchscreen, key array, proximity) configuration (which are set in the config data too). Signed-off-by: Iiro Valkonen Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/atmel_mxt_ts.c | 73 -------------------------------- 1 file changed, 73 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index d2e5864ca096..6264ba80c38c 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -630,74 +630,6 @@ static int mxt_check_reg_init(struct mxt_data *data) return 0; } -static int mxt_check_matrix_size(struct mxt_data *data) -{ - const struct mxt_platform_data *pdata = data->pdata; - struct device *dev = &data->client->dev; - int mode = -1; - int error; - u8 val; - - dev_dbg(dev, "Number of X lines: %d\n", pdata->x_line); - dev_dbg(dev, "Number of Y lines: %d\n", pdata->y_line); - - switch (pdata->x_line) { - case 0 ... 15: - if (pdata->y_line <= 14) - mode = 0; - break; - case 16: - if (pdata->y_line <= 12) - mode = 1; - if (pdata->y_line == 13 || pdata->y_line == 14) - mode = 0; - break; - case 17: - if (pdata->y_line <= 11) - mode = 2; - if (pdata->y_line == 12 || pdata->y_line == 13) - mode = 1; - break; - case 18: - if (pdata->y_line <= 10) - mode = 3; - if (pdata->y_line == 11 || pdata->y_line == 12) - mode = 2; - break; - case 19: - if (pdata->y_line <= 9) - mode = 4; - if (pdata->y_line == 10 || pdata->y_line == 11) - mode = 3; - break; - case 20: - mode = 4; - } - - if (mode < 0) { - dev_err(dev, "Invalid X/Y lines\n"); - return -EINVAL; - } - - error = mxt_read_object(data, MXT_SPT_CTECONFIG, - MXT_CTE_MODE, &val); - if (error) - return error; - - if (mode == val) - return 0; - - /* Change the CTE configuration */ - mxt_write_object(data, MXT_SPT_CTECONFIG, - MXT_CTE_CTRL, 1); - mxt_write_object(data, MXT_SPT_CTECONFIG, - MXT_CTE_MODE, mode); - mxt_write_object(data, MXT_SPT_CTECONFIG, - MXT_CTE_CTRL, 0); - - return 0; -} - static int mxt_make_highchg(struct mxt_data *data) { struct device *dev = &data->client->dev; @@ -864,11 +796,6 @@ static int mxt_initialize(struct mxt_data *data) if (error) return error; - /* Check X/Y matrix size */ - error = mxt_check_matrix_size(data); - if (error) - return error; - error = mxt_make_highchg(data); if (error) return error; -- cgit v1.2.3 From 5063511539bbb436ae8e4f75409561ef547f8516 Mon Sep 17 00:00:00 2001 From: Henrik Rydberg Date: Fri, 25 Feb 2011 09:33:13 -0800 Subject: Input: bcm5974 - Report button also for zero fingers With the current code, pressing the integrated button with an isolating tool does not result in any button report. Fixed with this this patch. Signed-off-by: Henrik Rydberg Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/bcm5974.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/mouse/bcm5974.c b/drivers/input/mouse/bcm5974.c index b95231763911..d24837210f04 100644 --- a/drivers/input/mouse/bcm5974.c +++ b/drivers/input/mouse/bcm5974.c @@ -390,10 +390,6 @@ static int report_tp_state(struct bcm5974 *dev, int size) ptest = int2bound(&c->p, raw_p); origin = raw2int(f->origin); - /* set the integrated button if applicable */ - if (c->tp_type == TYPE2) - ibt = raw2int(dev->tp_data[BUTTON_TYPE2]); - /* while tracking finger still valid, count all fingers */ if (ptest > PRESSURE_LOW && origin) { abs_p = ptest; @@ -412,6 +408,10 @@ static int report_tp_state(struct bcm5974 *dev, int size) } } + /* set the integrated button if applicable */ + if (c->tp_type == TYPE2) + ibt = raw2int(dev->tp_data[BUTTON_TYPE2]); + if (dev->fingers < nmin) dev->fingers = nmin; if (dev->fingers > nmax) -- cgit v1.2.3 From 439581ec07fa9cf3f519dd461a2cf41cfd3adcb4 Mon Sep 17 00:00:00 2001 From: Peter Korsgaard Date: Fri, 25 Feb 2011 09:30:46 -0800 Subject: Input: evdev - fix evdev_write return value on partial writes As was recently brought up on the busybox list (http://lists.busybox.net/pipermail/busybox/2011-January/074565.html), evdev_write doesn't properly check the count argument, which will lead to a return value > count on partial writes if the remaining bytes are accessible - causing userspace confusion. Fix it by only handling each full input_event structure and return -EINVAL if less than 1 struct was written, similar to how it is done in evdev_read. Reported-by: Baruch Siach Signed-off-by: Peter Korsgaard Acked-by: Henrik Rydberg Signed-off-by: Dmitry Torokhov --- drivers/input/evdev.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index c8471a2552e7..7f42d3a454d2 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c @@ -321,6 +321,9 @@ static ssize_t evdev_write(struct file *file, const char __user *buffer, struct input_event event; int retval; + if (count < input_event_size()) + return -EINVAL; + retval = mutex_lock_interruptible(&evdev->mutex); if (retval) return retval; @@ -330,17 +333,16 @@ static ssize_t evdev_write(struct file *file, const char __user *buffer, goto out; } - while (retval < count) { - + do { if (input_event_from_user(buffer + retval, &event)) { retval = -EFAULT; goto out; } + retval += input_event_size(); input_inject_event(&evdev->handle, event.type, event.code, event.value); - retval += input_event_size(); - } + } while (retval + input_event_size() <= count); out: mutex_unlock(&evdev->mutex); -- cgit v1.2.3 From 4fc193814b3a269c1ea89aefdb56d4f957680d44 Mon Sep 17 00:00:00 2001 From: Ping Cheng Date: Sat, 12 Mar 2011 20:33:33 -0800 Subject: Input: wacom - do not send 2FGT Tablet PC events in TAP format 2FGT Tablet PC touch events were processed in _TAP_ format. Remove them so we can change to _MT_ format. Signed-off-by: Ping Cheng Signed-off-by: Dmitry Torokhov --- drivers/input/tablet/wacom_wac.c | 84 ++++------------------------------------ drivers/input/tablet/wacom_wac.h | 5 +-- 2 files changed, 10 insertions(+), 79 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c index 367fa82a607e..5488c6172621 100644 --- a/drivers/input/tablet/wacom_wac.c +++ b/drivers/input/tablet/wacom_wac.c @@ -675,40 +675,6 @@ static int wacom_intuos_irq(struct wacom_wac *wacom) return 1; } - -static void wacom_tpc_finger_in(struct wacom_wac *wacom, char *data, int idx) -{ - struct input_dev *input = wacom->input; - int finger = idx + 1; - int x = le16_to_cpup((__le16 *)&data[finger * 2]) & 0x7fff; - int y = le16_to_cpup((__le16 *)&data[4 + finger * 2]) & 0x7fff; - - /* - * Work around input core suppressing "duplicate" events since - * we are abusing ABS_X/ABS_Y to transmit multi-finger data. - * This should go away once we switch to true multitouch - * protocol. - */ - if (wacom->last_finger != finger) { - if (x == input_abs_get_val(input, ABS_X)) - x++; - - if (y == input_abs_get_val(input, ABS_Y)) - y++; - } - - input_report_abs(input, ABS_X, x); - input_report_abs(input, ABS_Y, y); - input_report_abs(input, ABS_MISC, wacom->id[0]); - input_report_key(input, wacom->tool[finger], 1); - if (!idx) - input_report_key(input, BTN_TOUCH, 1); - input_event(input, EV_MSC, MSC_SERIAL, finger); - input_sync(input); - - wacom->last_finger = finger; -} - static void wacom_tpc_touch_out(struct wacom_wac *wacom, int idx) { struct input_dev *input = wacom->input; @@ -731,7 +697,6 @@ static void wacom_tpc_touch_in(struct wacom_wac *wacom, size_t len) wacom->tool[1] = BTN_TOOL_DOUBLETAP; wacom->id[0] = TOUCH_DEVICE_ID; - wacom->tool[2] = BTN_TOOL_TRIPLETAP; if (len != WACOM_PKGLEN_TPC1FG) { @@ -746,18 +711,6 @@ static void wacom_tpc_touch_in(struct wacom_wac *wacom, size_t len) input_report_key(input, wacom->tool[1], 1); input_sync(input); break; - - case WACOM_REPORT_TPC2FG: - if (data[1] & 0x01) - wacom_tpc_finger_in(wacom, data, 0); - else if (wacom->id[1] & 0x01) - wacom_tpc_touch_out(wacom, 0); - - if (data[1] & 0x02) - wacom_tpc_finger_in(wacom, data, 1); - else if (wacom->id[1] & 0x02) - wacom_tpc_touch_out(wacom, 1); - break; } } else { input_report_abs(input, ABS_X, get_unaligned_le16(&data[1])); @@ -779,47 +732,26 @@ static int wacom_tpc_irq(struct wacom_wac *wacom, size_t len) dbg("wacom_tpc_irq: received report #%d", data[0]); - if (len == WACOM_PKGLEN_TPC1FG || /* single touch */ - data[0] == WACOM_REPORT_TPC1FG || /* single touch */ - data[0] == WACOM_REPORT_TPC2FG) { /* 2FG touch */ + if (len == WACOM_PKGLEN_TPC1FG || + data[0] == WACOM_REPORT_TPC1FG) { /* single touch */ if (wacom->shared->stylus_in_proximity) { if (wacom->id[1] & 0x01) wacom_tpc_touch_out(wacom, 0); - if (wacom->id[1] & 0x02) - wacom_tpc_touch_out(wacom, 1); - wacom->id[1] = 0; return 0; } - if (len == WACOM_PKGLEN_TPC1FG) { /* with touch */ + if (len == WACOM_PKGLEN_TPC1FG) prox = data[0] & 0x01; - } else { /* with capacity */ - if (data[0] == WACOM_REPORT_TPC1FG) - /* single touch */ - prox = data[1] & 0x01; - else - /* 2FG touch data */ - prox = data[1] & 0x03; - } + else /* with capacity */ + prox = data[1] & 0x01; - if (prox) { - if (!wacom->id[1]) - wacom->last_finger = 1; + if (prox) wacom_tpc_touch_in(wacom, len); - } else { - if (data[0] == WACOM_REPORT_TPC2FG) { - /* 2FGT out-prox */ - if (wacom->id[1] & 0x01) - wacom_tpc_touch_out(wacom, 0); - - if (wacom->id[1] & 0x02) - wacom_tpc_touch_out(wacom, 1); - } else - /* one finger touch */ - wacom_tpc_touch_out(wacom, 0); + else { + wacom_tpc_touch_out(wacom, 0); wacom->id[0] = 0; } diff --git a/drivers/input/tablet/wacom_wac.h b/drivers/input/tablet/wacom_wac.h index b1310ec9720c..8f747dd1214e 100644 --- a/drivers/input/tablet/wacom_wac.h +++ b/drivers/input/tablet/wacom_wac.h @@ -93,10 +93,9 @@ struct wacom_shared { struct wacom_wac { char name[64]; unsigned char *data; - int tool[3]; - int id[3]; + int tool[2]; + int id[2]; __u32 serial[2]; - int last_finger; struct wacom_features features; struct wacom_shared *shared; struct input_dev *input; -- cgit v1.2.3 From 8aa9a9ac89baa0e423da0211e0883d28165697e0 Mon Sep 17 00:00:00 2001 From: Ping Cheng Date: Sat, 12 Mar 2011 20:34:11 -0800 Subject: Input: wacom - process pen data in its own routine So it would be easier for patch reviewers to follow the data path. Reviewed-by: Henrik Rydberg Reviewed-by: Chris Bagwell Signed-off-by: Ping Cheng Signed-off-by: Dmitry Torokhov --- drivers/input/tablet/wacom_wac.c | 73 ++++++++++++++++++++++------------------ 1 file changed, 40 insertions(+), 33 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c index 5488c6172621..15bab99a4c7e 100644 --- a/drivers/input/tablet/wacom_wac.c +++ b/drivers/input/tablet/wacom_wac.c @@ -722,13 +722,47 @@ static void wacom_tpc_touch_in(struct wacom_wac *wacom, size_t len) } } -static int wacom_tpc_irq(struct wacom_wac *wacom, size_t len) +static int wacom_tpc_pen(struct wacom_wac *wacom) { struct wacom_features *features = &wacom->features; char *data = wacom->data; struct input_dev *input = wacom->input; - int prox = 0, pressure; - int retval = 0; + int prox, pressure; + + prox = data[1] & 0x20; + + if (!wacom->shared->stylus_in_proximity) { /* first in prox */ + /* Going into proximity select tool */ + wacom->tool[0] = (data[1] & 0x0c) ? BTN_TOOL_RUBBER : BTN_TOOL_PEN; + if (wacom->tool[0] == BTN_TOOL_PEN) + wacom->id[0] = STYLUS_DEVICE_ID; + else + wacom->id[0] = ERASER_DEVICE_ID; + + wacom->shared->stylus_in_proximity = true; + } + input_report_key(input, BTN_STYLUS, data[1] & 0x02); + input_report_key(input, BTN_STYLUS2, data[1] & 0x10); + input_report_abs(input, ABS_X, le16_to_cpup((__le16 *)&data[2])); + input_report_abs(input, ABS_Y, le16_to_cpup((__le16 *)&data[4])); + pressure = ((data[7] & 0x01) << 8) | data[6]; + if (pressure < 0) + pressure = features->pressure_max + pressure + 1; + input_report_abs(input, ABS_PRESSURE, pressure); + input_report_key(input, BTN_TOUCH, data[1] & 0x05); + if (!prox) { /* out-prox */ + wacom->id[0] = 0; + wacom->shared->stylus_in_proximity = false; + } + input_report_key(input, wacom->tool[0], prox); + + return 1; +} + +static int wacom_tpc_irq(struct wacom_wac *wacom, size_t len) +{ + char *data = wacom->data; + int prox = 0; dbg("wacom_tpc_irq: received report #%d", data[0]); @@ -757,37 +791,10 @@ static int wacom_tpc_irq(struct wacom_wac *wacom, size_t len) } /* keep prox bit to send proper out-prox event */ wacom->id[1] = prox; - } else if (data[0] == WACOM_REPORT_PENABLED) { /* Penabled */ - prox = data[1] & 0x20; - - if (!wacom->shared->stylus_in_proximity) { /* first in prox */ - /* Going into proximity select tool */ - wacom->tool[0] = (data[1] & 0x0c) ? BTN_TOOL_RUBBER : BTN_TOOL_PEN; - if (wacom->tool[0] == BTN_TOOL_PEN) - wacom->id[0] = STYLUS_DEVICE_ID; - else - wacom->id[0] = ERASER_DEVICE_ID; + } else if (data[0] == WACOM_REPORT_PENABLED) + return wacom_tpc_pen(wacom); - wacom->shared->stylus_in_proximity = true; - } - input_report_key(input, BTN_STYLUS, data[1] & 0x02); - input_report_key(input, BTN_STYLUS2, data[1] & 0x10); - input_report_abs(input, ABS_X, le16_to_cpup((__le16 *)&data[2])); - input_report_abs(input, ABS_Y, le16_to_cpup((__le16 *)&data[4])); - pressure = ((data[7] & 0x01) << 8) | data[6]; - if (pressure < 0) - pressure = features->pressure_max + pressure + 1; - input_report_abs(input, ABS_PRESSURE, pressure); - input_report_key(input, BTN_TOUCH, data[1] & 0x05); - if (!prox) { /* out-prox */ - wacom->id[0] = 0; - wacom->shared->stylus_in_proximity = false; - } - input_report_key(input, wacom->tool[0], prox); - input_report_abs(input, ABS_MISC, wacom->id[0]); - retval = 1; - } - return retval; + return 0; } static int wacom_bpt_touch(struct wacom_wac *wacom) -- cgit v1.2.3 From a43c7c53835ba1ff4e488806d0f8b98e9dce9b0e Mon Sep 17 00:00:00 2001 From: Ping Cheng Date: Sat, 12 Mar 2011 20:34:42 -0800 Subject: Input: wacom - support one finger touch the touchscreen way There are two types of 1FGT devices supported in wacom_wac.c. Changing them to follow the existing touchscreen format, i.e., only report BTN_TOUCH as a valid tool type. Touch data will be ignored if pen is in proximity. This requires a touch up event sent if touch was down when pen comes in. The touch up event should be sent before any pen events are emitted. Otherwise, two pointers would race for the cursor. However, we can not send a touch up inside wacom_tpc_pen since pen and touch are on different logical port. That is why we have to check if touch is up before sending pen events. Reviewed-by: Henrik Rydberg Reviewed-by: Chris Bagwell Signed-off-by: Ping Cheng Signed-off-by: Dmitry Torokhov --- drivers/input/tablet/wacom_wac.c | 139 ++++++++++++++------------------------- drivers/input/tablet/wacom_wac.h | 1 + 2 files changed, 50 insertions(+), 90 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c index 15bab99a4c7e..adf8946e8f0d 100644 --- a/drivers/input/tablet/wacom_wac.c +++ b/drivers/input/tablet/wacom_wac.c @@ -675,51 +675,37 @@ static int wacom_intuos_irq(struct wacom_wac *wacom) return 1; } -static void wacom_tpc_touch_out(struct wacom_wac *wacom, int idx) -{ - struct input_dev *input = wacom->input; - int finger = idx + 1; - - input_report_abs(input, ABS_X, 0); - input_report_abs(input, ABS_Y, 0); - input_report_abs(input, ABS_MISC, 0); - input_report_key(input, wacom->tool[finger], 0); - if (!idx) - input_report_key(input, BTN_TOUCH, 0); - input_event(input, EV_MSC, MSC_SERIAL, finger); - input_sync(input); -} - -static void wacom_tpc_touch_in(struct wacom_wac *wacom, size_t len) +static int wacom_tpc_single_touch(struct wacom_wac *wacom, size_t len) { char *data = wacom->data; struct input_dev *input = wacom->input; + bool prox; + int x = 0, y = 0; - wacom->tool[1] = BTN_TOOL_DOUBLETAP; - wacom->id[0] = TOUCH_DEVICE_ID; + if (!wacom->shared->stylus_in_proximity) { + if (len == WACOM_PKGLEN_TPC1FG) { + prox = data[0] & 0x01; + x = get_unaligned_le16(&data[1]); + y = get_unaligned_le16(&data[3]); + } else { /* with capacity */ + prox = data[1] & 0x01; + x = le16_to_cpup((__le16 *)&data[2]); + y = le16_to_cpup((__le16 *)&data[4]); + } + } else + /* force touch out when pen is in prox */ + prox = 0; - if (len != WACOM_PKGLEN_TPC1FG) { + if (prox) { + input_report_abs(input, ABS_X, x); + input_report_abs(input, ABS_Y, y); + } + input_report_key(input, BTN_TOUCH, prox); - switch (data[0]) { + /* keep touch state for pen events */ + wacom->shared->touch_down = prox; - case WACOM_REPORT_TPC1FG: - input_report_abs(input, ABS_X, le16_to_cpup((__le16 *)&data[2])); - input_report_abs(input, ABS_Y, le16_to_cpup((__le16 *)&data[4])); - input_report_abs(input, ABS_PRESSURE, le16_to_cpup((__le16 *)&data[6])); - input_report_key(input, BTN_TOUCH, le16_to_cpup((__le16 *)&data[6])); - input_report_abs(input, ABS_MISC, wacom->id[0]); - input_report_key(input, wacom->tool[1], 1); - input_sync(input); - break; - } - } else { - input_report_abs(input, ABS_X, get_unaligned_le16(&data[1])); - input_report_abs(input, ABS_Y, get_unaligned_le16(&data[3])); - input_report_key(input, BTN_TOUCH, 1); - input_report_abs(input, ABS_MISC, wacom->id[1]); - input_report_key(input, wacom->tool[1], 1); - input_sync(input); - } + return 1; } static int wacom_tpc_pen(struct wacom_wac *wacom) @@ -727,71 +713,43 @@ static int wacom_tpc_pen(struct wacom_wac *wacom) struct wacom_features *features = &wacom->features; char *data = wacom->data; struct input_dev *input = wacom->input; - int prox, pressure; - - prox = data[1] & 0x20; + int pressure; + bool prox = data[1] & 0x20; - if (!wacom->shared->stylus_in_proximity) { /* first in prox */ + if (!wacom->shared->stylus_in_proximity) /* first in prox */ /* Going into proximity select tool */ wacom->tool[0] = (data[1] & 0x0c) ? BTN_TOOL_RUBBER : BTN_TOOL_PEN; - if (wacom->tool[0] == BTN_TOOL_PEN) - wacom->id[0] = STYLUS_DEVICE_ID; - else - wacom->id[0] = ERASER_DEVICE_ID; - wacom->shared->stylus_in_proximity = true; - } - input_report_key(input, BTN_STYLUS, data[1] & 0x02); - input_report_key(input, BTN_STYLUS2, data[1] & 0x10); - input_report_abs(input, ABS_X, le16_to_cpup((__le16 *)&data[2])); - input_report_abs(input, ABS_Y, le16_to_cpup((__le16 *)&data[4])); - pressure = ((data[7] & 0x01) << 8) | data[6]; - if (pressure < 0) - pressure = features->pressure_max + pressure + 1; - input_report_abs(input, ABS_PRESSURE, pressure); - input_report_key(input, BTN_TOUCH, data[1] & 0x05); - if (!prox) { /* out-prox */ - wacom->id[0] = 0; - wacom->shared->stylus_in_proximity = false; + /* keep pen state for touch events */ + wacom->shared->stylus_in_proximity = prox; + + /* send pen events only when touch is up or forced out */ + if (!wacom->shared->touch_down) { + input_report_key(input, BTN_STYLUS, data[1] & 0x02); + input_report_key(input, BTN_STYLUS2, data[1] & 0x10); + input_report_abs(input, ABS_X, le16_to_cpup((__le16 *)&data[2])); + input_report_abs(input, ABS_Y, le16_to_cpup((__le16 *)&data[4])); + pressure = ((data[7] & 0x01) << 8) | data[6]; + if (pressure < 0) + pressure = features->pressure_max + pressure + 1; + input_report_abs(input, ABS_PRESSURE, pressure); + input_report_key(input, BTN_TOUCH, data[1] & 0x05); + input_report_key(input, wacom->tool[0], prox); + return 1; } - input_report_key(input, wacom->tool[0], prox); - return 1; + return 0; } static int wacom_tpc_irq(struct wacom_wac *wacom, size_t len) { char *data = wacom->data; - int prox = 0; dbg("wacom_tpc_irq: received report #%d", data[0]); - if (len == WACOM_PKGLEN_TPC1FG || - data[0] == WACOM_REPORT_TPC1FG) { /* single touch */ - - if (wacom->shared->stylus_in_proximity) { - if (wacom->id[1] & 0x01) - wacom_tpc_touch_out(wacom, 0); - - wacom->id[1] = 0; - return 0; - } - - if (len == WACOM_PKGLEN_TPC1FG) - prox = data[0] & 0x01; - else /* with capacity */ - prox = data[1] & 0x01; - - if (prox) - wacom_tpc_touch_in(wacom, len); - else { - wacom_tpc_touch_out(wacom, 0); - - wacom->id[0] = 0; - } - /* keep prox bit to send proper out-prox event */ - wacom->id[1] = prox; - } else if (data[0] == WACOM_REPORT_PENABLED) + if (len == WACOM_PKGLEN_TPC1FG || data[0] == WACOM_REPORT_TPC1FG) + return wacom_tpc_single_touch(wacom, len); + else if (data[0] == WACOM_REPORT_PENABLED) return wacom_tpc_pen(wacom); return 0; @@ -1172,6 +1130,8 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev, /* fall through */ case TABLETPC: + __clear_bit(ABS_MISC, input_dev->absbit); + if (features->device_type == BTN_TOOL_DOUBLETAP || features->device_type == BTN_TOOL_TRIPLETAP) { input_abs_set_res(input_dev, ABS_X, @@ -1180,7 +1140,6 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev, input_abs_set_res(input_dev, ABS_Y, wacom_calculate_touch_res(features->y_max, features->y_phy)); - __set_bit(BTN_TOOL_DOUBLETAP, input_dev->keybit); } if (features->device_type != BTN_TOOL_PEN) diff --git a/drivers/input/tablet/wacom_wac.h b/drivers/input/tablet/wacom_wac.h index 8f747dd1214e..835f756b150c 100644 --- a/drivers/input/tablet/wacom_wac.h +++ b/drivers/input/tablet/wacom_wac.h @@ -88,6 +88,7 @@ struct wacom_features { struct wacom_shared { bool stylus_in_proximity; + bool touch_down; }; struct wacom_wac { -- cgit v1.2.3 From 84eb5aa6ccb2a62c40722b8c5fb1338ea12155a3 Mon Sep 17 00:00:00 2001 From: Ping Cheng Date: Sat, 12 Mar 2011 20:35:18 -0800 Subject: Input: wacom - support 2FGT in MT format Reviewed-by: Henrik Rydberg Reviewed-by: Chris Bagwell Signed-off-by: Ping Cheng Signed-off-by: Dmitry Torokhov --- drivers/input/tablet/wacom_sys.c | 12 ++++---- drivers/input/tablet/wacom_wac.c | 59 ++++++++++++++++++++++++++++++++-------- 2 files changed, 53 insertions(+), 18 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/tablet/wacom_sys.c b/drivers/input/tablet/wacom_sys.c index fc381498b798..b97665f9765e 100644 --- a/drivers/input/tablet/wacom_sys.c +++ b/drivers/input/tablet/wacom_sys.c @@ -193,16 +193,16 @@ static int wacom_parse_hid(struct usb_interface *intf, struct hid_descriptor *hi case HID_USAGE_X: if (usage == WCM_DESKTOP) { if (finger) { - features->device_type = BTN_TOOL_DOUBLETAP; + features->device_type = BTN_TOOL_FINGER; if (features->type == TABLETPC2FG) { /* need to reset back */ features->pktlen = WACOM_PKGLEN_TPC2FG; - features->device_type = BTN_TOOL_TRIPLETAP; + features->device_type = BTN_TOOL_DOUBLETAP; } if (features->type == BAMBOO_PT) { /* need to reset back */ features->pktlen = WACOM_PKGLEN_BBTOUCH; - features->device_type = BTN_TOOL_TRIPLETAP; + features->device_type = BTN_TOOL_DOUBLETAP; features->x_phy = get_unaligned_le16(&report[i + 5]); features->x_max = @@ -241,11 +241,11 @@ static int wacom_parse_hid(struct usb_interface *intf, struct hid_descriptor *hi case HID_USAGE_Y: if (usage == WCM_DESKTOP) { if (finger) { - features->device_type = BTN_TOOL_DOUBLETAP; + features->device_type = BTN_TOOL_FINGER; if (features->type == TABLETPC2FG) { /* need to reset back */ features->pktlen = WACOM_PKGLEN_TPC2FG; - features->device_type = BTN_TOOL_TRIPLETAP; + features->device_type = BTN_TOOL_DOUBLETAP; features->y_max = get_unaligned_le16(&report[i + 3]); features->y_phy = @@ -254,7 +254,7 @@ static int wacom_parse_hid(struct usb_interface *intf, struct hid_descriptor *hi } else if (features->type == BAMBOO_PT) { /* need to reset back */ features->pktlen = WACOM_PKGLEN_BBTOUCH; - features->device_type = BTN_TOOL_TRIPLETAP; + features->device_type = BTN_TOOL_DOUBLETAP; features->y_phy = get_unaligned_le16(&report[i + 3]); features->y_max = diff --git a/drivers/input/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c index adf8946e8f0d..5597637cfd41 100644 --- a/drivers/input/tablet/wacom_wac.c +++ b/drivers/input/tablet/wacom_wac.c @@ -675,6 +675,37 @@ static int wacom_intuos_irq(struct wacom_wac *wacom) return 1; } +static int wacom_tpc_mt_touch(struct wacom_wac *wacom) +{ + struct input_dev *input = wacom->input; + unsigned char *data = wacom->data; + int contact_with_no_pen_down_count = 0; + int i; + + for (i = 0; i < 2; i++) { + int p = data[1] & (1 << i); + bool touch = p && !wacom->shared->stylus_in_proximity; + + input_mt_slot(input, i); + input_mt_report_slot_state(input, MT_TOOL_FINGER, touch); + if (touch) { + int x = le16_to_cpup((__le16 *)&data[i * 2 + 2]) & 0x7fff; + int y = le16_to_cpup((__le16 *)&data[i * 2 + 6]) & 0x7fff; + + input_report_abs(input, ABS_MT_POSITION_X, x); + input_report_abs(input, ABS_MT_POSITION_Y, y); + contact_with_no_pen_down_count++; + } + } + + /* keep touch state for pen event */ + wacom->shared->touch_down = (contact_with_no_pen_down_count > 0); + + input_mt_report_pointer_emulation(input, true); + + return 1; +} + static int wacom_tpc_single_touch(struct wacom_wac *wacom, size_t len) { char *data = wacom->data; @@ -749,6 +780,8 @@ static int wacom_tpc_irq(struct wacom_wac *wacom, size_t len) if (len == WACOM_PKGLEN_TPC1FG || data[0] == WACOM_REPORT_TPC1FG) return wacom_tpc_single_touch(wacom, len); + else if (data[0] == WACOM_REPORT_TPC2FG) + return wacom_tpc_mt_touch(wacom); else if (data[0] == WACOM_REPORT_PENABLED) return wacom_tpc_pen(wacom); @@ -975,7 +1008,7 @@ void wacom_setup_device_quirks(struct wacom_features *features) { /* touch device found but size is not defined. use default */ - if (features->device_type == BTN_TOOL_DOUBLETAP && !features->x_max) { + if (features->device_type == BTN_TOOL_FINGER && !features->x_max) { features->x_max = 1023; features->y_max = 1023; } @@ -987,7 +1020,7 @@ void wacom_setup_device_quirks(struct wacom_features *features) /* quirks for bamboo touch */ if (features->type == BAMBOO_PT && - features->device_type == BTN_TOOL_TRIPLETAP) { + features->device_type == BTN_TOOL_DOUBLETAP) { features->x_max <<= 5; features->y_max <<= 5; features->x_fuzz <<= 5; @@ -1123,28 +1156,30 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev, break; case TABLETPC2FG: - if (features->device_type == BTN_TOOL_TRIPLETAP) { - __set_bit(BTN_TOOL_TRIPLETAP, input_dev->keybit); - input_set_capability(input_dev, EV_MSC, MSC_SERIAL); + if (features->device_type == BTN_TOOL_DOUBLETAP) { + + input_mt_init_slots(input_dev, 2); + input_set_abs_params(input_dev, ABS_MT_TOOL_TYPE, + 0, MT_TOOL_MAX, 0, 0); + input_set_abs_params(input_dev, ABS_MT_POSITION_X, + 0, features->x_max, 0, 0); + input_set_abs_params(input_dev, ABS_MT_POSITION_Y, + 0, features->y_max, 0, 0); } /* fall through */ case TABLETPC: __clear_bit(ABS_MISC, input_dev->absbit); - if (features->device_type == BTN_TOOL_DOUBLETAP || - features->device_type == BTN_TOOL_TRIPLETAP) { + if (features->device_type != BTN_TOOL_PEN) { input_abs_set_res(input_dev, ABS_X, wacom_calculate_touch_res(features->x_max, features->x_phy)); input_abs_set_res(input_dev, ABS_Y, wacom_calculate_touch_res(features->y_max, features->y_phy)); - } - - if (features->device_type != BTN_TOOL_PEN) break; /* no need to process stylus stuff */ - + } /* fall through */ case PL: @@ -1162,7 +1197,7 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev, case BAMBOO_PT: __clear_bit(ABS_MISC, input_dev->absbit); - if (features->device_type == BTN_TOOL_TRIPLETAP) { + if (features->device_type == BTN_TOOL_DOUBLETAP) { __set_bit(BTN_LEFT, input_dev->keybit); __set_bit(BTN_FORWARD, input_dev->keybit); __set_bit(BTN_BACK, input_dev->keybit); -- cgit v1.2.3 From 47340bd9fefb571888836da942b5aee0e85e959c Mon Sep 17 00:00:00 2001 From: Andy Botting Date: Sat, 12 Mar 2011 20:27:22 -0800 Subject: Input: bcm5974 - add support for MacBookPro8 This patch add multitouch support for the MacBookPro8,1 and MacBookPro8,2 models. Cc: stable@kernel.org Signed-off-by: Andy Botting Signed-off-by: Henrik Rydberg Acked-by: Jiri Kosina Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/bcm5974.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'drivers/input') diff --git a/drivers/input/mouse/bcm5974.c b/drivers/input/mouse/bcm5974.c index ee82851afe3e..318531424848 100644 --- a/drivers/input/mouse/bcm5974.c +++ b/drivers/input/mouse/bcm5974.c @@ -63,6 +63,10 @@ #define USB_DEVICE_ID_APPLE_WELLSPRING4A_ANSI 0x0242 #define USB_DEVICE_ID_APPLE_WELLSPRING4A_ISO 0x0243 #define USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS 0x0244 +/* Macbook8 (unibody, March 2011) */ +#define USB_DEVICE_ID_APPLE_WELLSPRING5_ANSI 0x0245 +#define USB_DEVICE_ID_APPLE_WELLSPRING5_ISO 0x0246 +#define USB_DEVICE_ID_APPLE_WELLSPRING5_JIS 0x0247 #define BCM5974_DEVICE(prod) { \ .match_flags = (USB_DEVICE_ID_MATCH_DEVICE | \ @@ -96,6 +100,10 @@ static const struct usb_device_id bcm5974_table[] = { BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING4A_ANSI), BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING4A_ISO), BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS), + /* MacbookPro8 */ + BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING5_ANSI), + BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING5_ISO), + BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING5_JIS), /* Terminating entry */ {} }; @@ -274,6 +282,18 @@ static const struct bcm5974_config bcm5974_config_table[] = { { DIM_X, DIM_X / SN_COORD, -4616, 5112 }, { DIM_Y, DIM_Y / SN_COORD, -142, 5234 } }, + { + USB_DEVICE_ID_APPLE_WELLSPRING5_ANSI, + USB_DEVICE_ID_APPLE_WELLSPRING5_ISO, + USB_DEVICE_ID_APPLE_WELLSPRING5_JIS, + HAS_INTEGRATED_BUTTON, + 0x84, sizeof(struct bt_data), + 0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS, + { DIM_PRESSURE, DIM_PRESSURE / SN_PRESSURE, 0, 300 }, + { DIM_WIDTH, DIM_WIDTH / SN_WIDTH, 0, 2048 }, + { DIM_X, DIM_X / SN_COORD, -4415, 5050 }, + { DIM_Y, DIM_Y / SN_COORD, -55, 6680 } + }, {} }; -- cgit v1.2.3 From 23c483d29fcbc35591131019660b2630cc6629ae Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sat, 12 Mar 2011 20:48:34 -0800 Subject: Input: wm831x-ts - default pressure measurements on tslib expects pressure measurements so enable them by default for better compatibility. Signed-off-by: Mark Brown Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/wm831x-ts.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/wm831x-ts.c b/drivers/input/touchscreen/wm831x-ts.c index 1022f715d3c2..3db0c29f3b05 100644 --- a/drivers/input/touchscreen/wm831x-ts.c +++ b/drivers/input/touchscreen/wm831x-ts.c @@ -225,7 +225,10 @@ static __devinit int wm831x_ts_probe(struct platform_device *pdev) else wm831x_ts->pd_irq = platform_get_irq_byname(pdev, "TCHPD"); - wm831x_ts->pressure = pdata && pdata->pressure; + if (pdata) + wm831x_ts->pressure = pdata->pressure; + else + wm831x_ts->pressure = true; /* Five wire touchscreens can't report pressure */ if (pdata && pdata->fivewire) { -- cgit v1.2.3 From bd7e4e85f3b8e5c7ea2f09d0b3350b264e339a14 Mon Sep 17 00:00:00 2001 From: Bo Shen Date: Sun, 13 Mar 2011 23:34:59 -0700 Subject: Input: add Atmel AT42QT1070 keypad driver The AT42QT1070 QTouch sensor supports up to 7 keys. The driver has been tested on Atmel AT91SAM9M10-G45-EK board, and it should work fine on other platforms. Signed-off-by: Bo Shen Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/Kconfig | 10 ++ drivers/input/keyboard/Makefile | 1 + drivers/input/keyboard/qt1070.c | 276 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 287 insertions(+) create mode 100644 drivers/input/keyboard/qt1070.c (limited to 'drivers/input') diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index c7a92028f450..b16bed038f72 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig @@ -112,6 +112,16 @@ config KEYBOARD_ATKBD_RDI_KEYCODES right-hand column will be interpreted as the key shown in the left-hand column. +config KEYBOARD_QT1070 + tristate "Atmel AT42QT1070 Touch Sensor Chip" + depends on I2C + help + Say Y here if you want to use Atmel AT42QT1070 QTouch + Sensor chip as input device. + + To compile this driver as a module, choose M here: + the module will be called qt1070 + config KEYBOARD_QT2160 tristate "Atmel AT42QT2160 Touch Sensor Chip" depends on I2C && EXPERIMENTAL diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile index 468c627a2844..878e6c20deb0 100644 --- a/drivers/input/keyboard/Makefile +++ b/drivers/input/keyboard/Makefile @@ -34,6 +34,7 @@ obj-$(CONFIG_KEYBOARD_OMAP4) += omap4-keypad.o obj-$(CONFIG_KEYBOARD_OPENCORES) += opencores-kbd.o obj-$(CONFIG_KEYBOARD_PXA27x) += pxa27x_keypad.o obj-$(CONFIG_KEYBOARD_PXA930_ROTARY) += pxa930_rotary.o +obj-$(CONFIG_KEYBOARD_QT1070) += qt1070.o obj-$(CONFIG_KEYBOARD_QT2160) += qt2160.o obj-$(CONFIG_KEYBOARD_SAMSUNG) += samsung-keypad.o obj-$(CONFIG_KEYBOARD_SH_KEYSC) += sh_keysc.o diff --git a/drivers/input/keyboard/qt1070.c b/drivers/input/keyboard/qt1070.c new file mode 100644 index 000000000000..fba8404c7297 --- /dev/null +++ b/drivers/input/keyboard/qt1070.c @@ -0,0 +1,276 @@ +/* + * Atmel AT42QT1070 QTouch Sensor Controller + * + * Copyright (C) 2011 Atmel + * + * Authors: Bo Shen + * + * Base on AT42QT2160 driver by: + * Raphael Derosso Pereira + * Copyright (C) 2009 + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Address for each register */ +#define CHIP_ID 0x00 +#define QT1070_CHIP_ID 0x2E + +#define FW_VERSION 0x01 +#define QT1070_FW_VERSION 0x15 + +#define DET_STATUS 0x02 + +#define KEY_STATUS 0x03 + +/* Calibrate */ +#define CALIBRATE_CMD 0x38 +#define QT1070_CAL_TIME 200 + +/* Reset */ +#define RESET 0x39 +#define QT1070_RESET_TIME 255 + +/* AT42QT1070 support up to 7 keys */ +static const unsigned short qt1070_key2code[] = { + KEY_0, KEY_1, KEY_2, KEY_3, + KEY_4, KEY_5, KEY_6, +}; + +struct qt1070_data { + struct i2c_client *client; + struct input_dev *input; + unsigned int irq; + unsigned short keycodes[ARRAY_SIZE(qt1070_key2code)]; + u8 last_keys; +}; + +static int qt1070_read(struct i2c_client *client, u8 reg) +{ + int ret; + + ret = i2c_smbus_read_byte_data(client, reg); + if (ret < 0) + dev_err(&client->dev, + "can not read register, returned %d\n", ret); + + return ret; +} + +static int qt1070_write(struct i2c_client *client, u8 reg, u8 data) +{ + int ret; + + ret = i2c_smbus_write_byte_data(client, reg, data); + if (ret < 0) + dev_err(&client->dev, + "can not write register, returned %d\n", ret); + + return ret; +} + +static bool __devinit qt1070_identify(struct i2c_client *client) +{ + int id, ver; + + /* Read Chip ID */ + id = qt1070_read(client, CHIP_ID); + if (id != QT1070_CHIP_ID) { + dev_err(&client->dev, "ID %d not supported\n", id); + return false; + } + + /* Read firmware version */ + ver = qt1070_read(client, FW_VERSION); + if (ver < 0) { + dev_err(&client->dev, "could not read the firmware version\n"); + return false; + } + + dev_info(&client->dev, "AT42QT1070 firmware version %x\n", ver); + + return true; +} + +static irqreturn_t qt1070_interrupt(int irq, void *dev_id) +{ + struct qt1070_data *data = dev_id; + struct i2c_client *client = data->client; + struct input_dev *input = data->input; + int i; + u8 new_keys, keyval, mask = 0x01; + + /* Read the detected status register, thus clearing interrupt */ + qt1070_read(client, DET_STATUS); + + /* Read which key changed */ + new_keys = qt1070_read(client, KEY_STATUS); + + for (i = 0; i < ARRAY_SIZE(qt1070_key2code); i++) { + keyval = new_keys & mask; + if ((data->last_keys & mask) != keyval) + input_report_key(input, data->keycodes[i], keyval); + mask <<= 1; + } + input_sync(input); + + data->last_keys = new_keys; + return IRQ_HANDLED; +} + +static int __devinit qt1070_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct qt1070_data *data; + struct input_dev *input; + int i; + int err; + + err = i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE); + if (!err) { + dev_err(&client->dev, "%s adapter not supported\n", + dev_driver_string(&client->adapter->dev)); + return -ENODEV; + } + + if (!client->irq) { + dev_err(&client->dev, "please assign the irq to this device\n"); + return -EINVAL; + } + + /* Identify the qt1070 chip */ + if (!qt1070_identify(client)) + return -ENODEV; + + data = kzalloc(sizeof(struct qt1070_data), GFP_KERNEL); + input = input_allocate_device(); + if (!data || !input) { + dev_err(&client->dev, "insufficient memory\n"); + err = -ENOMEM; + goto err_free_mem; + } + + data->client = client; + data->input = input; + data->irq = client->irq; + + input->name = "AT42QT1070 QTouch Sensor"; + input->dev.parent = &client->dev; + input->id.bustype = BUS_I2C; + + /* Add the keycode */ + input->keycode = data->keycodes; + input->keycodesize = sizeof(data->keycodes[0]); + input->keycodemax = ARRAY_SIZE(qt1070_key2code); + + __set_bit(EV_KEY, input->evbit); + + for (i = 0; i < ARRAY_SIZE(qt1070_key2code); i++) { + data->keycodes[i] = qt1070_key2code[i]; + __set_bit(qt1070_key2code[i], input->keybit); + } + + /* Calibrate device */ + qt1070_write(client, CALIBRATE_CMD, 1); + msleep(QT1070_CAL_TIME); + + /* Soft reset */ + qt1070_write(client, RESET, 1); + msleep(QT1070_RESET_TIME); + + err = request_threaded_irq(client->irq, NULL, qt1070_interrupt, + IRQF_TRIGGER_NONE, client->dev.driver->name, data); + if (err) { + dev_err(&client->dev, "fail to request irq\n"); + goto err_free_mem; + } + + /* Register the input device */ + err = input_register_device(data->input); + if (err) { + dev_err(&client->dev, "Failed to register input device\n"); + goto err_free_irq; + } + + i2c_set_clientdata(client, data); + + /* Read to clear the chang line */ + qt1070_read(client, DET_STATUS); + + return 0; + +err_free_irq: + free_irq(client->irq, data); +err_free_mem: + input_free_device(input); + kfree(data); + return err; +} + +static int __devexit qt1070_remove(struct i2c_client *client) +{ + struct qt1070_data *data = i2c_get_clientdata(client); + + /* Release IRQ */ + free_irq(client->irq, data); + + input_unregister_device(data->input); + kfree(data); + + i2c_set_clientdata(client, NULL); + + return 0; +} + +static const struct i2c_device_id qt1070_id[] = { + { "qt1070", 0 }, + { }, +}; + +static struct i2c_driver qt1070_driver = { + .driver = { + .name = "qt1070", + .owner = THIS_MODULE, + }, + .id_table = qt1070_id, + .probe = qt1070_probe, + .remove = __devexit_p(qt1070_remove), +}; + +static int __init qt1070_init(void) +{ + return i2c_add_driver(&qt1070_driver); +} +module_init(qt1070_init); + +static void __exit qt1070_exit(void) +{ + i2c_del_driver(&qt1070_driver); +} +module_exit(qt1070_exit); + +MODULE_AUTHOR("Bo Shen "); +MODULE_DESCRIPTION("Driver for AT42QT1070 QTouch sensor"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From e7cbb90ad244b9d3ba5c6d57aec05d6c73df0a98 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 14 Mar 2011 21:39:09 -0700 Subject: Input: wm831x-ts - ensure the controller is in a known state on open Explicitly set all the enable bits when opening the device just in case something left the device in an unexpected state. Signed-off-by: Mark Brown Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/wm831x-ts.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/wm831x-ts.c b/drivers/input/touchscreen/wm831x-ts.c index 3db0c29f3b05..6ae054f8e0aa 100644 --- a/drivers/input/touchscreen/wm831x-ts.c +++ b/drivers/input/touchscreen/wm831x-ts.c @@ -167,7 +167,9 @@ static int wm831x_ts_input_open(struct input_dev *idev) struct wm831x *wm831x = wm831x_ts->wm831x; wm831x_set_bits(wm831x, WM831X_TOUCH_CONTROL_1, - WM831X_TCH_ENA, WM831X_TCH_ENA); + WM831X_TCH_ENA | WM831X_TCH_CVT_ENA | + WM831X_TCH_X_ENA | WM831X_TCH_Y_ENA | + WM831X_TCH_Z_ENA, WM831X_TCH_ENA); wm831x_set_bits(wm831x, WM831X_TOUCH_CONTROL_1, WM831X_TCH_CVT_ENA, WM831X_TCH_CVT_ENA); -- cgit v1.2.3 From 979a72dad9c6649486e35a84324af8e81936af03 Mon Sep 17 00:00:00 2001 From: Joonyoung Shim Date: Mon, 14 Mar 2011 21:41:34 -0700 Subject: Input: atmel_mxt_ts - remove firmware version check Atmel touchscreen chips have different firmware version with each chip, so we cannot distinguish attribute of chip by firmware version. Signed-off-by: Joonyoung Shim Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/atmel_mxt_ts.c | 21 +++++---------------- 1 file changed, 5 insertions(+), 16 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index 6264ba80c38c..0986fa46e9df 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -60,11 +60,11 @@ #define MXT_PROCG_NOISE 22 #define MXT_PROCI_ONETOUCH 24 #define MXT_PROCI_TWOTOUCH 27 -#define MXT_SPT_COMMSCONFIG 18 /* firmware ver 21 over */ +#define MXT_SPT_COMMSCONFIG 18 #define MXT_SPT_GPIOPWM 19 #define MXT_SPT_SELFTEST 25 #define MXT_SPT_CTECONFIG 28 -#define MXT_SPT_USERDATA 38 /* firmware ver 21 over */ +#define MXT_SPT_USERDATA 38 /* MXT_GEN_COMMAND field */ #define MXT_COMMAND_RESET 0 @@ -115,7 +115,7 @@ #define MXT_TOUCH_XEDGEDIST 27 #define MXT_TOUCH_YEDGECTRL 28 #define MXT_TOUCH_YEDGEDIST 29 -#define MXT_TOUCH_JUMPLIMIT 30 /* firmware ver 22 over */ +#define MXT_TOUCH_JUMPLIMIT 30 /* MXT_PROCI_GRIPFACE field */ #define MXT_GRIPFACE_CTRL 0 @@ -157,7 +157,7 @@ #define MXT_CTE_MODE 2 #define MXT_CTE_IDLEGCAFDEPTH 3 #define MXT_CTE_ACTVGCAFDEPTH 4 -#define MXT_CTE_VOLTAGE 5 /* firmware ver 21 over */ +#define MXT_CTE_VOLTAGE 5 #define MXT_VOLTAGE_DEFAULT 2700000 #define MXT_VOLTAGE_STEP 10000 @@ -686,7 +686,7 @@ static void mxt_handle_pdata(struct mxt_data *data) MXT_TOUCH_YRANGE_MSB, (pdata->y_size - 1) >> 8); /* Set touchscreen voltage */ - if (data->info.version >= MXT_VER_21 && pdata->voltage) { + if (pdata->voltage) { if (pdata->voltage < MXT_VOLTAGE_DEFAULT) { voltage = (MXT_VOLTAGE_DEFAULT - pdata->voltage) / MXT_VOLTAGE_STEP; @@ -951,19 +951,8 @@ static ssize_t mxt_update_fw_store(struct device *dev, const char *buf, size_t count) { struct mxt_data *data = dev_get_drvdata(dev); - unsigned int version; int error; - if (sscanf(buf, "%u", &version) != 1) { - dev_err(dev, "Invalid values\n"); - return -EINVAL; - } - - if (data->info.version < MXT_VER_21 || version < MXT_VER_21) { - dev_err(dev, "FW update supported starting with version 21\n"); - return -EINVAL; - } - disable_irq(data->irq); error = mxt_load_fw(dev, MXT_FW_NAME); -- cgit v1.2.3 From 4c75de32eb9fcaa14925e2e444748f8b71e4f6fc Mon Sep 17 00:00:00 2001 From: Joonyoung Shim Date: Mon, 14 Mar 2011 21:41:40 -0700 Subject: Input: atmel_mxt_ts - add objects of mXT1386 chip Atmel mXT1386 chip is operated by atmel_mxt_ts driver and it has some different objects. Signed-off-by: Joonyoung Shim Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/atmel_mxt_ts.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index 0986fa46e9df..4012436633b1 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -60,11 +60,15 @@ #define MXT_PROCG_NOISE 22 #define MXT_PROCI_ONETOUCH 24 #define MXT_PROCI_TWOTOUCH 27 +#define MXT_PROCI_GRIP 40 +#define MXT_PROCI_PALM 41 #define MXT_SPT_COMMSCONFIG 18 #define MXT_SPT_GPIOPWM 19 #define MXT_SPT_SELFTEST 25 #define MXT_SPT_CTECONFIG 28 #define MXT_SPT_USERDATA 38 +#define MXT_SPT_DIGITIZER 43 +#define MXT_SPT_MESSAGECOUNT 44 /* MXT_GEN_COMMAND field */ #define MXT_COMMAND_RESET 0 @@ -258,6 +262,8 @@ static bool mxt_object_readable(unsigned int type) case MXT_PROCG_NOISE: case MXT_PROCI_ONETOUCH: case MXT_PROCI_TWOTOUCH: + case MXT_PROCI_GRIP: + case MXT_PROCI_PALM: case MXT_SPT_COMMSCONFIG: case MXT_SPT_GPIOPWM: case MXT_SPT_SELFTEST: @@ -282,6 +288,8 @@ static bool mxt_object_writable(unsigned int type) case MXT_PROCG_NOISE: case MXT_PROCI_ONETOUCH: case MXT_PROCI_TWOTOUCH: + case MXT_PROCI_GRIP: + case MXT_PROCI_PALM: case MXT_SPT_GPIOPWM: case MXT_SPT_SELFTEST: case MXT_SPT_CTECONFIG: -- cgit v1.2.3 From 64dcddd888998f7db9929e19fc063e75e3ea21f5 Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Tue, 15 Mar 2011 22:32:39 -0700 Subject: Input: tca6416-keypad - suspend/resume wakeup support Extend the tca6416 driver to use enable_irq_wake() and disable_irq_wake() in the suspend/resume hooks. This makes it possible to wake up from suspend-to-ram using a tca6416 key on the sh7372 mackerel board. Signed-off-by: Magnus Damm Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/tca6416-keypad.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) (limited to 'drivers/input') diff --git a/drivers/input/keyboard/tca6416-keypad.c b/drivers/input/keyboard/tca6416-keypad.c index 800fbccf1f0f..3afea3f89718 100644 --- a/drivers/input/keyboard/tca6416-keypad.c +++ b/drivers/input/keyboard/tca6416-keypad.c @@ -297,6 +297,7 @@ static int __devinit tca6416_keypad_probe(struct i2c_client *client, } i2c_set_clientdata(client, chip); + device_init_wakeup(&client->dev, 1); return 0; @@ -326,10 +327,37 @@ static int __devexit tca6416_keypad_remove(struct i2c_client *client) return 0; } +#ifdef CONFIG_PM_SLEEP +static int tca6416_keypad_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct tca6416_keypad_chip *chip = i2c_get_clientdata(client); + + if (device_may_wakeup(dev)) + enable_irq_wake(chip->irqnum); + + return 0; +} + +static int tca6416_keypad_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct tca6416_keypad_chip *chip = i2c_get_clientdata(client); + + if (device_may_wakeup(dev)) + disable_irq_wake(chip->irqnum); + + return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(tca6416_keypad_dev_pm_ops, + tca6416_keypad_suspend, tca6416_keypad_resume); static struct i2c_driver tca6416_keypad_driver = { .driver = { .name = "tca6416-keypad", + .pm = &tca6416_keypad_dev_pm_ops, }, .probe = tca6416_keypad_probe, .remove = __devexit_p(tca6416_keypad_remove), -- cgit v1.2.3 From 53a2b81c4e659d894aadc56715c8d8a9afa60d67 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Tue, 15 Mar 2011 23:18:00 -0700 Subject: Input: tc3589x-keypad - fix 'double const' warning Also rearrange driver structure initializer a bit. Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/tc3589x-keypad.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/keyboard/tc3589x-keypad.c b/drivers/input/keyboard/tc3589x-keypad.c index dbbe761778d2..99122f59e988 100644 --- a/drivers/input/keyboard/tc3589x-keypad.c +++ b/drivers/input/keyboard/tc3589x-keypad.c @@ -402,7 +402,7 @@ static int __devexit tc3589x_keypad_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP static int tc3589x_keypad_suspend(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); @@ -439,19 +439,19 @@ static int tc3589x_keypad_resume(struct device *dev) return 0; } - -static const SIMPLE_DEV_PM_OPS(tc3589x_keypad_dev_pm_ops, - tc3589x_keypad_suspend, tc3589x_keypad_resume); #endif +static SIMPLE_DEV_PM_OPS(tc3589x_keypad_dev_pm_ops, + tc3589x_keypad_suspend, tc3589x_keypad_resume); + static struct platform_driver tc3589x_keypad_driver = { - .driver.name = "tc3589x-keypad", - .driver.owner = THIS_MODULE, -#ifdef CONFIG_PM - .driver.pm = &tc3589x_keypad_dev_pm_ops, -#endif - .probe = tc3589x_keypad_probe, - .remove = __devexit_p(tc3589x_keypad_remove), + .driver = { + .name = "tc3589x-keypad", + .owner = THIS_MODULE, + .pm = &tc3589x_keypad_dev_pm_ops, + }, + .probe = tc3589x_keypad_probe, + .remove = __devexit_p(tc3589x_keypad_remove), }; static int __init tc3589x_keypad_init(void) -- cgit v1.2.3 From 8c3c283e6bf463ab498d6e7823aff6c4762314b6 Mon Sep 17 00:00:00 2001 From: Olaf Hering Date: Wed, 16 Mar 2011 22:11:46 -0700 Subject: Input: xen-kbdfront - advertise either absolute or relative coordinates A virtualized display device is usually viewed with the vncviewer application, either by 'xm vnc domU' or with vncviewer localhost:port. vncviewer and the RFB protocol provides absolute coordinates to the virtual display. These coordinates are either passed through to a PV guest or converted to relative coordinates for a HVM guest. A PV guest receives these coordinates and passes them to the kernels evdev driver. There it can be picked up by applications such as the xorg-input drivers. Using absolute coordinates avoids issues such as guest mouse pointer not tracking host mouse pointer due to wrong mouse acceleration settings in the guests X display. Advertise either absolute or relative coordinates to the input system and the evdev driver, depending on what dom0 provides. The xorg-input driver prefers relative coordinates even if a devices provides both. Signed-off-by: Olaf Hering Signed-off-by: Stefano Stabellini Signed-off-by: Dmitry Torokhov --- drivers/input/xen-kbdfront.c | 44 ++++++++++++++++++++++++-------------------- 1 file changed, 24 insertions(+), 20 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/xen-kbdfront.c b/drivers/input/xen-kbdfront.c index 7f85a862ad11..53e62732ee96 100644 --- a/drivers/input/xen-kbdfront.c +++ b/drivers/input/xen-kbdfront.c @@ -110,7 +110,7 @@ static irqreturn_t input_handler(int rq, void *dev_id) static int __devinit xenkbd_probe(struct xenbus_device *dev, const struct xenbus_device_id *id) { - int ret, i; + int ret, i, abs; struct xenkbd_info *info; struct input_dev *kbd, *ptr; @@ -128,6 +128,11 @@ static int __devinit xenkbd_probe(struct xenbus_device *dev, if (!info->page) goto error_nomem; + if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-abs-pointer", "%d", &abs) < 0) + abs = 0; + if (abs) + xenbus_printf(XBT_NIL, dev->nodename, "request-abs-pointer", "1"); + /* keyboard */ kbd = input_allocate_device(); if (!kbd) @@ -137,11 +142,12 @@ static int __devinit xenkbd_probe(struct xenbus_device *dev, kbd->id.bustype = BUS_PCI; kbd->id.vendor = 0x5853; kbd->id.product = 0xffff; - kbd->evbit[0] = BIT(EV_KEY); + + __set_bit(EV_KEY, kbd->evbit); for (i = KEY_ESC; i < KEY_UNKNOWN; i++) - set_bit(i, kbd->keybit); + __set_bit(i, kbd->keybit); for (i = KEY_OK; i < KEY_MAX; i++) - set_bit(i, kbd->keybit); + __set_bit(i, kbd->keybit); ret = input_register_device(kbd); if (ret) { @@ -160,12 +166,20 @@ static int __devinit xenkbd_probe(struct xenbus_device *dev, ptr->id.bustype = BUS_PCI; ptr->id.vendor = 0x5853; ptr->id.product = 0xfffe; - ptr->evbit[0] = BIT(EV_KEY) | BIT(EV_REL) | BIT(EV_ABS); + + if (abs) { + __set_bit(EV_ABS, ptr->evbit); + input_set_abs_params(ptr, ABS_X, 0, XENFB_WIDTH, 0, 0); + input_set_abs_params(ptr, ABS_Y, 0, XENFB_HEIGHT, 0, 0); + } else { + input_set_capability(ptr, EV_REL, REL_X); + input_set_capability(ptr, EV_REL, REL_Y); + } + input_set_capability(ptr, EV_REL, REL_WHEEL); + + __set_bit(EV_KEY, ptr->evbit); for (i = BTN_LEFT; i <= BTN_TASK; i++) - set_bit(i, ptr->keybit); - ptr->relbit[0] = BIT(REL_X) | BIT(REL_Y) | BIT(REL_WHEEL); - input_set_abs_params(ptr, ABS_X, 0, XENFB_WIDTH, 0, 0); - input_set_abs_params(ptr, ABS_Y, 0, XENFB_HEIGHT, 0, 0); + __set_bit(i, ptr->keybit); ret = input_register_device(ptr); if (ret) { @@ -272,7 +286,7 @@ static void xenkbd_backend_changed(struct xenbus_device *dev, enum xenbus_state backend_state) { struct xenkbd_info *info = dev_get_drvdata(&dev->dev); - int ret, val; + int val; switch (backend_state) { case XenbusStateInitialising: @@ -285,16 +299,6 @@ static void xenkbd_backend_changed(struct xenbus_device *dev, case XenbusStateInitWait: InitWait: - ret = xenbus_scanf(XBT_NIL, info->xbdev->otherend, - "feature-abs-pointer", "%d", &val); - if (ret < 0) - val = 0; - if (val) { - ret = xenbus_printf(XBT_NIL, info->xbdev->nodename, - "request-abs-pointer", "1"); - if (ret) - pr_warning("can't request abs-pointer\n"); - } xenbus_switch_state(dev, XenbusStateConnected); break; -- cgit v1.2.3 From 0a4dfa5ddb5fc0aff331e255da282b01a74a6cd3 Mon Sep 17 00:00:00 2001 From: Daniel De Graaf Date: Wed, 16 Mar 2011 22:52:42 -0700 Subject: Input: xen-kbdfront - add grant reference for shared page Without a grant reference, full access to the domain's memory is required to use the shared page. Add an additional parameter in xenstore to allow grant mapping to be used. Signed-off-by: Daniel De Graaf Signed-off-by: Konrad Rzeszutek Wilk Acked-by: Ian Campbell Signed-off-by: Dmitry Torokhov --- drivers/input/xen-kbdfront.c | 39 ++++++++++++++++++++++++++++----------- 1 file changed, 28 insertions(+), 11 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/xen-kbdfront.c b/drivers/input/xen-kbdfront.c index 53e62732ee96..7077f9bf5ead 100644 --- a/drivers/input/xen-kbdfront.c +++ b/drivers/input/xen-kbdfront.c @@ -11,12 +11,6 @@ * more details. */ -/* - * TODO: - * - * Switch to grant tables together with xen-fbfront.c. - */ - #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include @@ -30,6 +24,8 @@ #include #include #include +#include +#include #include #include #include @@ -38,6 +34,7 @@ struct xenkbd_info { struct input_dev *kbd; struct input_dev *ptr; struct xenkbd_page *page; + int gref; int irq; struct xenbus_device *xbdev; char phys[32]; @@ -122,6 +119,7 @@ static int __devinit xenkbd_probe(struct xenbus_device *dev, dev_set_drvdata(&dev->dev, info); info->xbdev = dev; info->irq = -1; + info->gref = -1; snprintf(info->phys, sizeof(info->phys), "xenbus/%s", dev->nodename); info->page = (void *)__get_free_page(GFP_KERNEL | __GFP_ZERO); @@ -232,15 +230,20 @@ static int xenkbd_connect_backend(struct xenbus_device *dev, int ret, evtchn; struct xenbus_transaction xbt; + ret = gnttab_grant_foreign_access(dev->otherend_id, + virt_to_mfn(info->page), 0); + if (ret < 0) + return ret; + info->gref = ret; + ret = xenbus_alloc_evtchn(dev, &evtchn); if (ret) - return ret; + goto error_grant; ret = bind_evtchn_to_irqhandler(evtchn, input_handler, 0, dev->devicetype, info); if (ret < 0) { - xenbus_free_evtchn(dev, evtchn); xenbus_dev_fatal(dev, ret, "bind_evtchn_to_irqhandler"); - return ret; + goto error_evtchan; } info->irq = ret; @@ -248,10 +251,13 @@ static int xenkbd_connect_backend(struct xenbus_device *dev, ret = xenbus_transaction_start(&xbt); if (ret) { xenbus_dev_fatal(dev, ret, "starting transaction"); - return ret; + goto error_irqh; } ret = xenbus_printf(xbt, dev->nodename, "page-ref", "%lu", virt_to_mfn(info->page)); + if (ret) + goto error_xenbus; + ret = xenbus_printf(xbt, dev->nodename, "page-gref", "%u", info->gref); if (ret) goto error_xenbus; ret = xenbus_printf(xbt, dev->nodename, "event-channel", "%u", @@ -263,7 +269,7 @@ static int xenkbd_connect_backend(struct xenbus_device *dev, if (ret == -EAGAIN) goto again; xenbus_dev_fatal(dev, ret, "completing transaction"); - return ret; + goto error_irqh; } xenbus_switch_state(dev, XenbusStateInitialised); @@ -272,6 +278,14 @@ static int xenkbd_connect_backend(struct xenbus_device *dev, error_xenbus: xenbus_transaction_end(xbt, 1); xenbus_dev_fatal(dev, ret, "writing xenstore"); + error_irqh: + unbind_from_irqhandler(info->irq, info); + info->irq = -1; + error_evtchan: + xenbus_free_evtchn(dev, evtchn); + error_grant: + gnttab_end_foreign_access_ref(info->gref, 0); + info->gref = -1; return ret; } @@ -280,6 +294,9 @@ static void xenkbd_disconnect_backend(struct xenkbd_info *info) if (info->irq >= 0) unbind_from_irqhandler(info->irq, info); info->irq = -1; + if (info->gref >= 0) + gnttab_end_foreign_access_ref(info->gref, 0); + info->gref = -1; } static void xenkbd_backend_changed(struct xenbus_device *dev, -- cgit v1.2.3 From 49851ca04c7f941ef6f5ca04751b0e0fefe9d50d Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 16 Mar 2011 22:56:03 -0700 Subject: Input: xen-kbdfront - move to drivers/input/misc drivers/input is reserved for input core code and input handlers with drivers belonging to one of the sub-directories. Signed-off-by: Dmitry Torokhov --- drivers/input/Kconfig | 10 - drivers/input/Makefile | 2 - drivers/input/misc/Kconfig | 13 ++ drivers/input/misc/Makefile | 1 + drivers/input/misc/xen-kbdfront.c | 385 ++++++++++++++++++++++++++++++++++++++ drivers/input/xen-kbdfront.c | 385 -------------------------------------- 6 files changed, 399 insertions(+), 397 deletions(-) create mode 100644 drivers/input/misc/xen-kbdfront.c delete mode 100644 drivers/input/xen-kbdfront.c (limited to 'drivers/input') diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig index 1903c0f5b925..23e82e46656d 100644 --- a/drivers/input/Kconfig +++ b/drivers/input/Kconfig @@ -161,16 +161,6 @@ config INPUT_APMPOWER To compile this driver as a module, choose M here: the module will be called apm-power. -config XEN_KBDDEV_FRONTEND - tristate "Xen virtual keyboard and mouse support" - depends on XEN_FBDEV_FRONTEND - default y - select XEN_XENBUS_FRONTEND - help - This driver implements the front-end of the Xen virtual - keyboard and mouse device driver. It communicates with a back-end - in another domain. - comment "Input Device Drivers" source "drivers/input/keyboard/Kconfig" diff --git a/drivers/input/Makefile b/drivers/input/Makefile index 09614ce74961..0c789490e0b3 100644 --- a/drivers/input/Makefile +++ b/drivers/input/Makefile @@ -24,5 +24,3 @@ obj-$(CONFIG_INPUT_TOUCHSCREEN) += touchscreen/ obj-$(CONFIG_INPUT_MISC) += misc/ obj-$(CONFIG_INPUT_APMPOWER) += apm-power.o - -obj-$(CONFIG_XEN_KBDDEV_FRONTEND) += xen-kbdfront.o diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index b0c6772851a9..f9cf0881b0e3 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -454,4 +454,17 @@ config INPUT_CMA3000_I2C To compile this driver as a module, choose M here: the module will be called cma3000_d0x_i2c. +config INPUT_XEN_KBDDEV_FRONTEND + tristate "Xen virtual keyboard and mouse support" + depends on XEN_FBDEV_FRONTEND + default y + select XEN_XENBUS_FRONTEND + help + This driver implements the front-end of the Xen virtual + keyboard and mouse device driver. It communicates with a back-end + in another domain. + + To compile this driver as a module, choose M here: the + module will be called xen-kbdfront. + endif diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index 9b4797112c9a..e3f7984e6274 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile @@ -42,5 +42,6 @@ obj-$(CONFIG_INPUT_TWL4030_VIBRA) += twl4030-vibra.o obj-$(CONFIG_INPUT_UINPUT) += uinput.o obj-$(CONFIG_INPUT_WISTRON_BTNS) += wistron_btns.o obj-$(CONFIG_INPUT_WM831X_ON) += wm831x-on.o +obj-$(CONFIG_INPUT_XEN_KBDDEV_FRONTEND) += xen-kbdfront.o obj-$(CONFIG_INPUT_YEALINK) += yealink.o diff --git a/drivers/input/misc/xen-kbdfront.c b/drivers/input/misc/xen-kbdfront.c new file mode 100644 index 000000000000..7077f9bf5ead --- /dev/null +++ b/drivers/input/misc/xen-kbdfront.c @@ -0,0 +1,385 @@ +/* + * Xen para-virtual input device + * + * Copyright (C) 2005 Anthony Liguori + * Copyright (C) 2006-2008 Red Hat, Inc., Markus Armbruster + * + * Based on linux/drivers/input/mouse/sermouse.c + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +struct xenkbd_info { + struct input_dev *kbd; + struct input_dev *ptr; + struct xenkbd_page *page; + int gref; + int irq; + struct xenbus_device *xbdev; + char phys[32]; +}; + +static int xenkbd_remove(struct xenbus_device *); +static int xenkbd_connect_backend(struct xenbus_device *, struct xenkbd_info *); +static void xenkbd_disconnect_backend(struct xenkbd_info *); + +/* + * Note: if you need to send out events, see xenfb_do_update() for how + * to do that. + */ + +static irqreturn_t input_handler(int rq, void *dev_id) +{ + struct xenkbd_info *info = dev_id; + struct xenkbd_page *page = info->page; + __u32 cons, prod; + + prod = page->in_prod; + if (prod == page->in_cons) + return IRQ_HANDLED; + rmb(); /* ensure we see ring contents up to prod */ + for (cons = page->in_cons; cons != prod; cons++) { + union xenkbd_in_event *event; + struct input_dev *dev; + event = &XENKBD_IN_RING_REF(page, cons); + + dev = info->ptr; + switch (event->type) { + case XENKBD_TYPE_MOTION: + input_report_rel(dev, REL_X, event->motion.rel_x); + input_report_rel(dev, REL_Y, event->motion.rel_y); + if (event->motion.rel_z) + input_report_rel(dev, REL_WHEEL, + -event->motion.rel_z); + break; + case XENKBD_TYPE_KEY: + dev = NULL; + if (test_bit(event->key.keycode, info->kbd->keybit)) + dev = info->kbd; + if (test_bit(event->key.keycode, info->ptr->keybit)) + dev = info->ptr; + if (dev) + input_report_key(dev, event->key.keycode, + event->key.pressed); + else + pr_warning("unhandled keycode 0x%x\n", + event->key.keycode); + break; + case XENKBD_TYPE_POS: + input_report_abs(dev, ABS_X, event->pos.abs_x); + input_report_abs(dev, ABS_Y, event->pos.abs_y); + if (event->pos.rel_z) + input_report_rel(dev, REL_WHEEL, + -event->pos.rel_z); + break; + } + if (dev) + input_sync(dev); + } + mb(); /* ensure we got ring contents */ + page->in_cons = cons; + notify_remote_via_irq(info->irq); + + return IRQ_HANDLED; +} + +static int __devinit xenkbd_probe(struct xenbus_device *dev, + const struct xenbus_device_id *id) +{ + int ret, i, abs; + struct xenkbd_info *info; + struct input_dev *kbd, *ptr; + + info = kzalloc(sizeof(*info), GFP_KERNEL); + if (!info) { + xenbus_dev_fatal(dev, -ENOMEM, "allocating info structure"); + return -ENOMEM; + } + dev_set_drvdata(&dev->dev, info); + info->xbdev = dev; + info->irq = -1; + info->gref = -1; + snprintf(info->phys, sizeof(info->phys), "xenbus/%s", dev->nodename); + + info->page = (void *)__get_free_page(GFP_KERNEL | __GFP_ZERO); + if (!info->page) + goto error_nomem; + + if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-abs-pointer", "%d", &abs) < 0) + abs = 0; + if (abs) + xenbus_printf(XBT_NIL, dev->nodename, "request-abs-pointer", "1"); + + /* keyboard */ + kbd = input_allocate_device(); + if (!kbd) + goto error_nomem; + kbd->name = "Xen Virtual Keyboard"; + kbd->phys = info->phys; + kbd->id.bustype = BUS_PCI; + kbd->id.vendor = 0x5853; + kbd->id.product = 0xffff; + + __set_bit(EV_KEY, kbd->evbit); + for (i = KEY_ESC; i < KEY_UNKNOWN; i++) + __set_bit(i, kbd->keybit); + for (i = KEY_OK; i < KEY_MAX; i++) + __set_bit(i, kbd->keybit); + + ret = input_register_device(kbd); + if (ret) { + input_free_device(kbd); + xenbus_dev_fatal(dev, ret, "input_register_device(kbd)"); + goto error; + } + info->kbd = kbd; + + /* pointing device */ + ptr = input_allocate_device(); + if (!ptr) + goto error_nomem; + ptr->name = "Xen Virtual Pointer"; + ptr->phys = info->phys; + ptr->id.bustype = BUS_PCI; + ptr->id.vendor = 0x5853; + ptr->id.product = 0xfffe; + + if (abs) { + __set_bit(EV_ABS, ptr->evbit); + input_set_abs_params(ptr, ABS_X, 0, XENFB_WIDTH, 0, 0); + input_set_abs_params(ptr, ABS_Y, 0, XENFB_HEIGHT, 0, 0); + } else { + input_set_capability(ptr, EV_REL, REL_X); + input_set_capability(ptr, EV_REL, REL_Y); + } + input_set_capability(ptr, EV_REL, REL_WHEEL); + + __set_bit(EV_KEY, ptr->evbit); + for (i = BTN_LEFT; i <= BTN_TASK; i++) + __set_bit(i, ptr->keybit); + + ret = input_register_device(ptr); + if (ret) { + input_free_device(ptr); + xenbus_dev_fatal(dev, ret, "input_register_device(ptr)"); + goto error; + } + info->ptr = ptr; + + ret = xenkbd_connect_backend(dev, info); + if (ret < 0) + goto error; + + return 0; + + error_nomem: + ret = -ENOMEM; + xenbus_dev_fatal(dev, ret, "allocating device memory"); + error: + xenkbd_remove(dev); + return ret; +} + +static int xenkbd_resume(struct xenbus_device *dev) +{ + struct xenkbd_info *info = dev_get_drvdata(&dev->dev); + + xenkbd_disconnect_backend(info); + memset(info->page, 0, PAGE_SIZE); + return xenkbd_connect_backend(dev, info); +} + +static int xenkbd_remove(struct xenbus_device *dev) +{ + struct xenkbd_info *info = dev_get_drvdata(&dev->dev); + + xenkbd_disconnect_backend(info); + if (info->kbd) + input_unregister_device(info->kbd); + if (info->ptr) + input_unregister_device(info->ptr); + free_page((unsigned long)info->page); + kfree(info); + return 0; +} + +static int xenkbd_connect_backend(struct xenbus_device *dev, + struct xenkbd_info *info) +{ + int ret, evtchn; + struct xenbus_transaction xbt; + + ret = gnttab_grant_foreign_access(dev->otherend_id, + virt_to_mfn(info->page), 0); + if (ret < 0) + return ret; + info->gref = ret; + + ret = xenbus_alloc_evtchn(dev, &evtchn); + if (ret) + goto error_grant; + ret = bind_evtchn_to_irqhandler(evtchn, input_handler, + 0, dev->devicetype, info); + if (ret < 0) { + xenbus_dev_fatal(dev, ret, "bind_evtchn_to_irqhandler"); + goto error_evtchan; + } + info->irq = ret; + + again: + ret = xenbus_transaction_start(&xbt); + if (ret) { + xenbus_dev_fatal(dev, ret, "starting transaction"); + goto error_irqh; + } + ret = xenbus_printf(xbt, dev->nodename, "page-ref", "%lu", + virt_to_mfn(info->page)); + if (ret) + goto error_xenbus; + ret = xenbus_printf(xbt, dev->nodename, "page-gref", "%u", info->gref); + if (ret) + goto error_xenbus; + ret = xenbus_printf(xbt, dev->nodename, "event-channel", "%u", + evtchn); + if (ret) + goto error_xenbus; + ret = xenbus_transaction_end(xbt, 0); + if (ret) { + if (ret == -EAGAIN) + goto again; + xenbus_dev_fatal(dev, ret, "completing transaction"); + goto error_irqh; + } + + xenbus_switch_state(dev, XenbusStateInitialised); + return 0; + + error_xenbus: + xenbus_transaction_end(xbt, 1); + xenbus_dev_fatal(dev, ret, "writing xenstore"); + error_irqh: + unbind_from_irqhandler(info->irq, info); + info->irq = -1; + error_evtchan: + xenbus_free_evtchn(dev, evtchn); + error_grant: + gnttab_end_foreign_access_ref(info->gref, 0); + info->gref = -1; + return ret; +} + +static void xenkbd_disconnect_backend(struct xenkbd_info *info) +{ + if (info->irq >= 0) + unbind_from_irqhandler(info->irq, info); + info->irq = -1; + if (info->gref >= 0) + gnttab_end_foreign_access_ref(info->gref, 0); + info->gref = -1; +} + +static void xenkbd_backend_changed(struct xenbus_device *dev, + enum xenbus_state backend_state) +{ + struct xenkbd_info *info = dev_get_drvdata(&dev->dev); + int val; + + switch (backend_state) { + case XenbusStateInitialising: + case XenbusStateInitialised: + case XenbusStateReconfiguring: + case XenbusStateReconfigured: + case XenbusStateUnknown: + case XenbusStateClosed: + break; + + case XenbusStateInitWait: +InitWait: + xenbus_switch_state(dev, XenbusStateConnected); + break; + + case XenbusStateConnected: + /* + * Work around xenbus race condition: If backend goes + * through InitWait to Connected fast enough, we can + * get Connected twice here. + */ + if (dev->state != XenbusStateConnected) + goto InitWait; /* no InitWait seen yet, fudge it */ + + /* Set input abs params to match backend screen res */ + if (xenbus_scanf(XBT_NIL, info->xbdev->otherend, + "width", "%d", &val) > 0) + input_set_abs_params(info->ptr, ABS_X, 0, val, 0, 0); + + if (xenbus_scanf(XBT_NIL, info->xbdev->otherend, + "height", "%d", &val) > 0) + input_set_abs_params(info->ptr, ABS_Y, 0, val, 0, 0); + + break; + + case XenbusStateClosing: + xenbus_frontend_closed(dev); + break; + } +} + +static const struct xenbus_device_id xenkbd_ids[] = { + { "vkbd" }, + { "" } +}; + +static struct xenbus_driver xenkbd_driver = { + .name = "vkbd", + .owner = THIS_MODULE, + .ids = xenkbd_ids, + .probe = xenkbd_probe, + .remove = xenkbd_remove, + .resume = xenkbd_resume, + .otherend_changed = xenkbd_backend_changed, +}; + +static int __init xenkbd_init(void) +{ + if (!xen_pv_domain()) + return -ENODEV; + + /* Nothing to do if running in dom0. */ + if (xen_initial_domain()) + return -ENODEV; + + return xenbus_register_frontend(&xenkbd_driver); +} + +static void __exit xenkbd_cleanup(void) +{ + xenbus_unregister_driver(&xenkbd_driver); +} + +module_init(xenkbd_init); +module_exit(xenkbd_cleanup); + +MODULE_DESCRIPTION("Xen virtual keyboard/pointer device frontend"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("xen:vkbd"); diff --git a/drivers/input/xen-kbdfront.c b/drivers/input/xen-kbdfront.c deleted file mode 100644 index 7077f9bf5ead..000000000000 --- a/drivers/input/xen-kbdfront.c +++ /dev/null @@ -1,385 +0,0 @@ -/* - * Xen para-virtual input device - * - * Copyright (C) 2005 Anthony Liguori - * Copyright (C) 2006-2008 Red Hat, Inc., Markus Armbruster - * - * Based on linux/drivers/input/mouse/sermouse.c - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file COPYING in the main directory of this archive for - * more details. - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -struct xenkbd_info { - struct input_dev *kbd; - struct input_dev *ptr; - struct xenkbd_page *page; - int gref; - int irq; - struct xenbus_device *xbdev; - char phys[32]; -}; - -static int xenkbd_remove(struct xenbus_device *); -static int xenkbd_connect_backend(struct xenbus_device *, struct xenkbd_info *); -static void xenkbd_disconnect_backend(struct xenkbd_info *); - -/* - * Note: if you need to send out events, see xenfb_do_update() for how - * to do that. - */ - -static irqreturn_t input_handler(int rq, void *dev_id) -{ - struct xenkbd_info *info = dev_id; - struct xenkbd_page *page = info->page; - __u32 cons, prod; - - prod = page->in_prod; - if (prod == page->in_cons) - return IRQ_HANDLED; - rmb(); /* ensure we see ring contents up to prod */ - for (cons = page->in_cons; cons != prod; cons++) { - union xenkbd_in_event *event; - struct input_dev *dev; - event = &XENKBD_IN_RING_REF(page, cons); - - dev = info->ptr; - switch (event->type) { - case XENKBD_TYPE_MOTION: - input_report_rel(dev, REL_X, event->motion.rel_x); - input_report_rel(dev, REL_Y, event->motion.rel_y); - if (event->motion.rel_z) - input_report_rel(dev, REL_WHEEL, - -event->motion.rel_z); - break; - case XENKBD_TYPE_KEY: - dev = NULL; - if (test_bit(event->key.keycode, info->kbd->keybit)) - dev = info->kbd; - if (test_bit(event->key.keycode, info->ptr->keybit)) - dev = info->ptr; - if (dev) - input_report_key(dev, event->key.keycode, - event->key.pressed); - else - pr_warning("unhandled keycode 0x%x\n", - event->key.keycode); - break; - case XENKBD_TYPE_POS: - input_report_abs(dev, ABS_X, event->pos.abs_x); - input_report_abs(dev, ABS_Y, event->pos.abs_y); - if (event->pos.rel_z) - input_report_rel(dev, REL_WHEEL, - -event->pos.rel_z); - break; - } - if (dev) - input_sync(dev); - } - mb(); /* ensure we got ring contents */ - page->in_cons = cons; - notify_remote_via_irq(info->irq); - - return IRQ_HANDLED; -} - -static int __devinit xenkbd_probe(struct xenbus_device *dev, - const struct xenbus_device_id *id) -{ - int ret, i, abs; - struct xenkbd_info *info; - struct input_dev *kbd, *ptr; - - info = kzalloc(sizeof(*info), GFP_KERNEL); - if (!info) { - xenbus_dev_fatal(dev, -ENOMEM, "allocating info structure"); - return -ENOMEM; - } - dev_set_drvdata(&dev->dev, info); - info->xbdev = dev; - info->irq = -1; - info->gref = -1; - snprintf(info->phys, sizeof(info->phys), "xenbus/%s", dev->nodename); - - info->page = (void *)__get_free_page(GFP_KERNEL | __GFP_ZERO); - if (!info->page) - goto error_nomem; - - if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-abs-pointer", "%d", &abs) < 0) - abs = 0; - if (abs) - xenbus_printf(XBT_NIL, dev->nodename, "request-abs-pointer", "1"); - - /* keyboard */ - kbd = input_allocate_device(); - if (!kbd) - goto error_nomem; - kbd->name = "Xen Virtual Keyboard"; - kbd->phys = info->phys; - kbd->id.bustype = BUS_PCI; - kbd->id.vendor = 0x5853; - kbd->id.product = 0xffff; - - __set_bit(EV_KEY, kbd->evbit); - for (i = KEY_ESC; i < KEY_UNKNOWN; i++) - __set_bit(i, kbd->keybit); - for (i = KEY_OK; i < KEY_MAX; i++) - __set_bit(i, kbd->keybit); - - ret = input_register_device(kbd); - if (ret) { - input_free_device(kbd); - xenbus_dev_fatal(dev, ret, "input_register_device(kbd)"); - goto error; - } - info->kbd = kbd; - - /* pointing device */ - ptr = input_allocate_device(); - if (!ptr) - goto error_nomem; - ptr->name = "Xen Virtual Pointer"; - ptr->phys = info->phys; - ptr->id.bustype = BUS_PCI; - ptr->id.vendor = 0x5853; - ptr->id.product = 0xfffe; - - if (abs) { - __set_bit(EV_ABS, ptr->evbit); - input_set_abs_params(ptr, ABS_X, 0, XENFB_WIDTH, 0, 0); - input_set_abs_params(ptr, ABS_Y, 0, XENFB_HEIGHT, 0, 0); - } else { - input_set_capability(ptr, EV_REL, REL_X); - input_set_capability(ptr, EV_REL, REL_Y); - } - input_set_capability(ptr, EV_REL, REL_WHEEL); - - __set_bit(EV_KEY, ptr->evbit); - for (i = BTN_LEFT; i <= BTN_TASK; i++) - __set_bit(i, ptr->keybit); - - ret = input_register_device(ptr); - if (ret) { - input_free_device(ptr); - xenbus_dev_fatal(dev, ret, "input_register_device(ptr)"); - goto error; - } - info->ptr = ptr; - - ret = xenkbd_connect_backend(dev, info); - if (ret < 0) - goto error; - - return 0; - - error_nomem: - ret = -ENOMEM; - xenbus_dev_fatal(dev, ret, "allocating device memory"); - error: - xenkbd_remove(dev); - return ret; -} - -static int xenkbd_resume(struct xenbus_device *dev) -{ - struct xenkbd_info *info = dev_get_drvdata(&dev->dev); - - xenkbd_disconnect_backend(info); - memset(info->page, 0, PAGE_SIZE); - return xenkbd_connect_backend(dev, info); -} - -static int xenkbd_remove(struct xenbus_device *dev) -{ - struct xenkbd_info *info = dev_get_drvdata(&dev->dev); - - xenkbd_disconnect_backend(info); - if (info->kbd) - input_unregister_device(info->kbd); - if (info->ptr) - input_unregister_device(info->ptr); - free_page((unsigned long)info->page); - kfree(info); - return 0; -} - -static int xenkbd_connect_backend(struct xenbus_device *dev, - struct xenkbd_info *info) -{ - int ret, evtchn; - struct xenbus_transaction xbt; - - ret = gnttab_grant_foreign_access(dev->otherend_id, - virt_to_mfn(info->page), 0); - if (ret < 0) - return ret; - info->gref = ret; - - ret = xenbus_alloc_evtchn(dev, &evtchn); - if (ret) - goto error_grant; - ret = bind_evtchn_to_irqhandler(evtchn, input_handler, - 0, dev->devicetype, info); - if (ret < 0) { - xenbus_dev_fatal(dev, ret, "bind_evtchn_to_irqhandler"); - goto error_evtchan; - } - info->irq = ret; - - again: - ret = xenbus_transaction_start(&xbt); - if (ret) { - xenbus_dev_fatal(dev, ret, "starting transaction"); - goto error_irqh; - } - ret = xenbus_printf(xbt, dev->nodename, "page-ref", "%lu", - virt_to_mfn(info->page)); - if (ret) - goto error_xenbus; - ret = xenbus_printf(xbt, dev->nodename, "page-gref", "%u", info->gref); - if (ret) - goto error_xenbus; - ret = xenbus_printf(xbt, dev->nodename, "event-channel", "%u", - evtchn); - if (ret) - goto error_xenbus; - ret = xenbus_transaction_end(xbt, 0); - if (ret) { - if (ret == -EAGAIN) - goto again; - xenbus_dev_fatal(dev, ret, "completing transaction"); - goto error_irqh; - } - - xenbus_switch_state(dev, XenbusStateInitialised); - return 0; - - error_xenbus: - xenbus_transaction_end(xbt, 1); - xenbus_dev_fatal(dev, ret, "writing xenstore"); - error_irqh: - unbind_from_irqhandler(info->irq, info); - info->irq = -1; - error_evtchan: - xenbus_free_evtchn(dev, evtchn); - error_grant: - gnttab_end_foreign_access_ref(info->gref, 0); - info->gref = -1; - return ret; -} - -static void xenkbd_disconnect_backend(struct xenkbd_info *info) -{ - if (info->irq >= 0) - unbind_from_irqhandler(info->irq, info); - info->irq = -1; - if (info->gref >= 0) - gnttab_end_foreign_access_ref(info->gref, 0); - info->gref = -1; -} - -static void xenkbd_backend_changed(struct xenbus_device *dev, - enum xenbus_state backend_state) -{ - struct xenkbd_info *info = dev_get_drvdata(&dev->dev); - int val; - - switch (backend_state) { - case XenbusStateInitialising: - case XenbusStateInitialised: - case XenbusStateReconfiguring: - case XenbusStateReconfigured: - case XenbusStateUnknown: - case XenbusStateClosed: - break; - - case XenbusStateInitWait: -InitWait: - xenbus_switch_state(dev, XenbusStateConnected); - break; - - case XenbusStateConnected: - /* - * Work around xenbus race condition: If backend goes - * through InitWait to Connected fast enough, we can - * get Connected twice here. - */ - if (dev->state != XenbusStateConnected) - goto InitWait; /* no InitWait seen yet, fudge it */ - - /* Set input abs params to match backend screen res */ - if (xenbus_scanf(XBT_NIL, info->xbdev->otherend, - "width", "%d", &val) > 0) - input_set_abs_params(info->ptr, ABS_X, 0, val, 0, 0); - - if (xenbus_scanf(XBT_NIL, info->xbdev->otherend, - "height", "%d", &val) > 0) - input_set_abs_params(info->ptr, ABS_Y, 0, val, 0, 0); - - break; - - case XenbusStateClosing: - xenbus_frontend_closed(dev); - break; - } -} - -static const struct xenbus_device_id xenkbd_ids[] = { - { "vkbd" }, - { "" } -}; - -static struct xenbus_driver xenkbd_driver = { - .name = "vkbd", - .owner = THIS_MODULE, - .ids = xenkbd_ids, - .probe = xenkbd_probe, - .remove = xenkbd_remove, - .resume = xenkbd_resume, - .otherend_changed = xenkbd_backend_changed, -}; - -static int __init xenkbd_init(void) -{ - if (!xen_pv_domain()) - return -ENODEV; - - /* Nothing to do if running in dom0. */ - if (xen_initial_domain()) - return -ENODEV; - - return xenbus_register_frontend(&xenkbd_driver); -} - -static void __exit xenkbd_cleanup(void) -{ - xenbus_unregister_driver(&xenkbd_driver); -} - -module_init(xenkbd_init); -module_exit(xenkbd_cleanup); - -MODULE_DESCRIPTION("Xen virtual keyboard/pointer device frontend"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("xen:vkbd"); -- cgit v1.2.3 From 37bd44694c7215e3e46e6ee4a930d197325a7168 Mon Sep 17 00:00:00 2001 From: Lauri Leukkunen Date: Wed, 16 Mar 2011 22:07:36 -0700 Subject: Input: introduce tsc2005 driver Discussions: http://www.mail-archive.com/linux-omap@vger.kernel.org/msg26748.html Introduce a driver for the Texas Instruments TSC2005 touchscreen controller (http://focus.ti.com/docs/prod/folders/print/tsc2005.html). The patch is based on a driver by Lauri Leukkunen, with modifications by David Brownell, Phil Carmody, Imre Deak, Hiroshi DOYU, Ari Kauppi, Tony Lindgren, Jarkko Nikula, Eero Nurkkala and Roman Tereshonkov. Signed-off-by: Lauri Leukkunen [aaro.koskinen@nokia.com: patch description, rebasing & cleanup] Signed-off-by: Aaro Koskinen [ext-srikar.1.bhavanarayana@nokia.com: various fixes] Signed-off-by: Srikar Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/Kconfig | 11 + drivers/input/touchscreen/Makefile | 1 + drivers/input/touchscreen/tsc2005.c | 713 ++++++++++++++++++++++++++++++++++++ 3 files changed, 725 insertions(+) create mode 100644 drivers/input/touchscreen/tsc2005.c (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 06ea8da95c62..30703ad363f3 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -629,6 +629,17 @@ config TOUCHSCREEN_TOUCHIT213 To compile this driver as a module, choose M here: the module will be called touchit213. +config TOUCHSCREEN_TSC2005 + tristate "TSC2005 based touchscreens" + depends on SPI_MASTER + help + Say Y here if you have a TSC2005 based touchscreen. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called tsc2005. + config TOUCHSCREEN_TSC2007 tristate "TSC2007 based touchscreens" depends on I2C diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index 7cc1b4f4b677..34b26ad65cee 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -44,6 +44,7 @@ obj-$(CONFIG_TOUCHSCREEN_TNETV107X) += tnetv107x-ts.o obj-$(CONFIG_TOUCHSCREEN_TOUCHIT213) += touchit213.o obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT) += touchright.o obj-$(CONFIG_TOUCHSCREEN_TOUCHWIN) += touchwin.o +obj-$(CONFIG_TOUCHSCREEN_TSC2005) += tsc2005.o obj-$(CONFIG_TOUCHSCREEN_TSC2007) += tsc2007.o obj-$(CONFIG_TOUCHSCREEN_UCB1400) += ucb1400_ts.o obj-$(CONFIG_TOUCHSCREEN_WACOM_W8001) += wacom_w8001.o diff --git a/drivers/input/touchscreen/tsc2005.c b/drivers/input/touchscreen/tsc2005.c new file mode 100644 index 000000000000..f95f968f18e1 --- /dev/null +++ b/drivers/input/touchscreen/tsc2005.c @@ -0,0 +1,713 @@ +/* + * TSC2005 touchscreen driver + * + * Copyright (C) 2006-2010 Nokia Corporation + * + * Author: Lauri Leukkunen + * based on TSC2301 driver by Klaus K. Pedersen + * + * 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 + * + */ + +#include +#include +#include +#include +#include +#include +#include + +/* + * The touchscreen interface operates as follows: + * + * 1) Pen is pressed against the touchscreen. + * 2) TSC2005 performs AD conversion. + * 3) After the conversion is done TSC2005 drives DAV line down. + * 4) GPIO IRQ is received and tsc2005_irq_thread() is scheduled. + * 5) tsc2005_irq_thread() queues up an spi transfer to fetch the x, y, z1, z2 + * values. + * 6) tsc2005_irq_thread() reports coordinates to input layer and sets up + * tsc2005_penup_timer() to be called after TSC2005_PENUP_TIME_MS (40ms). + * 7) When the penup timer expires, there have not been touch or DAV interrupts + * during the last 40ms which means the pen has been lifted. + * + * ESD recovery via a hardware reset is done if the TSC2005 doesn't respond + * after a configurable period (in ms) of activity. If esd_timeout is 0, the + * watchdog is disabled. + */ + +/* control byte 1 */ +#define TSC2005_CMD 0x80 +#define TSC2005_CMD_NORMAL 0x00 +#define TSC2005_CMD_STOP 0x01 +#define TSC2005_CMD_12BIT 0x04 + +/* control byte 0 */ +#define TSC2005_REG_READ 0x0001 +#define TSC2005_REG_PND0 0x0002 +#define TSC2005_REG_X 0x0000 +#define TSC2005_REG_Y 0x0008 +#define TSC2005_REG_Z1 0x0010 +#define TSC2005_REG_Z2 0x0018 +#define TSC2005_REG_TEMP_HIGH 0x0050 +#define TSC2005_REG_CFR0 0x0060 +#define TSC2005_REG_CFR1 0x0068 +#define TSC2005_REG_CFR2 0x0070 + +/* configuration register 0 */ +#define TSC2005_CFR0_PRECHARGE_276US 0x0040 +#define TSC2005_CFR0_STABTIME_1MS 0x0300 +#define TSC2005_CFR0_CLOCK_1MHZ 0x1000 +#define TSC2005_CFR0_RESOLUTION12 0x2000 +#define TSC2005_CFR0_PENMODE 0x8000 +#define TSC2005_CFR0_INITVALUE (TSC2005_CFR0_STABTIME_1MS | \ + TSC2005_CFR0_CLOCK_1MHZ | \ + TSC2005_CFR0_RESOLUTION12 | \ + TSC2005_CFR0_PRECHARGE_276US | \ + TSC2005_CFR0_PENMODE) + +/* bits common to both read and write of configuration register 0 */ +#define TSC2005_CFR0_RW_MASK 0x3fff + +/* configuration register 1 */ +#define TSC2005_CFR1_BATCHDELAY_4MS 0x0003 +#define TSC2005_CFR1_INITVALUE TSC2005_CFR1_BATCHDELAY_4MS + +/* configuration register 2 */ +#define TSC2005_CFR2_MAVE_Z 0x0004 +#define TSC2005_CFR2_MAVE_Y 0x0008 +#define TSC2005_CFR2_MAVE_X 0x0010 +#define TSC2005_CFR2_AVG_7 0x0800 +#define TSC2005_CFR2_MEDIUM_15 0x3000 +#define TSC2005_CFR2_INITVALUE (TSC2005_CFR2_MAVE_X | \ + TSC2005_CFR2_MAVE_Y | \ + TSC2005_CFR2_MAVE_Z | \ + TSC2005_CFR2_MEDIUM_15 | \ + TSC2005_CFR2_AVG_7) + +#define MAX_12BIT 0xfff +#define TSC2005_SPI_MAX_SPEED_HZ 10000000 +#define TSC2005_PENUP_TIME_MS 40 + +struct tsc2005_spi_rd { + struct spi_transfer spi_xfer; + u32 spi_tx; + u32 spi_rx; +}; + +struct tsc2005 { + struct spi_device *spi; + + struct spi_message spi_read_msg; + struct tsc2005_spi_rd spi_x; + struct tsc2005_spi_rd spi_y; + struct tsc2005_spi_rd spi_z1; + struct tsc2005_spi_rd spi_z2; + + struct input_dev *idev; + char phys[32]; + + struct mutex mutex; + + /* raw copy of previous x,y,z */ + int in_x; + int in_y; + int in_z1; + int in_z2; + + struct timer_list penup_timer; + struct work_struct penup_work; + + unsigned int esd_timeout; + struct timer_list esd_timer; + struct work_struct esd_work; + + unsigned int x_plate_ohm; + + bool disabled; + unsigned int disable_depth; + unsigned int pen_down; + + void (*set_reset)(bool enable); +}; + +static void tsc2005_cmd(struct tsc2005 *ts, u8 cmd) +{ + u8 tx; + struct spi_message msg; + struct spi_transfer xfer = { 0 }; + + tx = TSC2005_CMD | TSC2005_CMD_12BIT | cmd; + + xfer.tx_buf = &tx; + xfer.rx_buf = NULL; + xfer.len = 1; + xfer.bits_per_word = 8; + + spi_message_init(&msg); + spi_message_add_tail(&xfer, &msg); + spi_sync(ts->spi, &msg); +} + +static void tsc2005_write(struct tsc2005 *ts, u8 reg, u16 value) +{ + u32 tx; + struct spi_message msg; + struct spi_transfer xfer = { 0 }; + + tx = (reg | TSC2005_REG_PND0) << 16; + tx |= value; + + xfer.tx_buf = &tx; + xfer.rx_buf = NULL; + xfer.len = 4; + xfer.bits_per_word = 24; + + spi_message_init(&msg); + spi_message_add_tail(&xfer, &msg); + spi_sync(ts->spi, &msg); +} + +static void tsc2005_setup_read(struct tsc2005_spi_rd *rd, u8 reg, bool last) +{ + rd->spi_tx = (reg | TSC2005_REG_READ) << 16; + rd->spi_xfer.tx_buf = &rd->spi_tx; + rd->spi_xfer.rx_buf = &rd->spi_rx; + rd->spi_xfer.len = 4; + rd->spi_xfer.bits_per_word = 24; + rd->spi_xfer.cs_change = !last; +} + +static void tsc2005_read(struct tsc2005 *ts, u8 reg, u16 *value) +{ + struct spi_message msg; + struct tsc2005_spi_rd spi_rd = { { 0 }, 0, 0 }; + + tsc2005_setup_read(&spi_rd, reg, 1); + + spi_message_init(&msg); + spi_message_add_tail(&spi_rd.spi_xfer, &msg); + spi_sync(ts->spi, &msg); + *value = spi_rd.spi_rx; +} + +static void tsc2005_update_pen_state(struct tsc2005 *ts, + int x, int y, int pressure) +{ + if (pressure) { + input_report_abs(ts->idev, ABS_X, x); + input_report_abs(ts->idev, ABS_Y, y); + input_report_abs(ts->idev, ABS_PRESSURE, pressure); + if (!ts->pen_down) { + input_report_key(ts->idev, BTN_TOUCH, !!pressure); + ts->pen_down = 1; + } + } else { + input_report_abs(ts->idev, ABS_PRESSURE, 0); + if (ts->pen_down) { + input_report_key(ts->idev, BTN_TOUCH, 0); + ts->pen_down = 0; + } + } + input_sync(ts->idev); + dev_dbg(&ts->spi->dev, "point(%4d,%4d), pressure (%4d)\n", x, y, + pressure); +} + +static irqreturn_t tsc2005_irq_handler(int irq, void *dev_id) +{ + struct tsc2005 *ts = dev_id; + + /* update the penup timer only if it's pending */ + mod_timer_pending(&ts->penup_timer, + jiffies + msecs_to_jiffies(TSC2005_PENUP_TIME_MS)); + + return IRQ_WAKE_THREAD; +} + +static irqreturn_t tsc2005_irq_thread(int irq, void *_ts) +{ + struct tsc2005 *ts = _ts; + unsigned int pressure; + u32 x; + u32 y; + u32 z1; + u32 z2; + + mutex_lock(&ts->mutex); + + if (unlikely(ts->disable_depth)) + goto out; + + /* read the coordinates */ + spi_sync(ts->spi, &ts->spi_read_msg); + x = ts->spi_x.spi_rx; + y = ts->spi_y.spi_rx; + z1 = ts->spi_z1.spi_rx; + z2 = ts->spi_z2.spi_rx; + + /* validate position */ + if (unlikely(x > MAX_12BIT || y > MAX_12BIT)) + goto out; + + /* skip coords if the pressure components are out of range */ + if (unlikely(z1 == 0 || z2 > MAX_12BIT || z1 >= z2)) + goto out; + + /* skip point if this is a pen down with the exact same values as + * the value before pen-up - that implies SPI fed us stale data + */ + if (!ts->pen_down && + ts->in_x == x && + ts->in_y == y && + ts->in_z1 == z1 && + ts->in_z2 == z2) + goto out; + + /* At this point we are happy we have a valid and useful reading. + * Remember it for later comparisons. We may now begin downsampling + */ + ts->in_x = x; + ts->in_y = y; + ts->in_z1 = z1; + ts->in_z2 = z2; + + /* compute touch pressure resistance using equation #1 */ + pressure = x * (z2 - z1) / z1; + pressure = pressure * ts->x_plate_ohm / 4096; + if (unlikely(pressure > MAX_12BIT)) + goto out; + + tsc2005_update_pen_state(ts, x, y, pressure); + + /* set the penup timer */ + mod_timer(&ts->penup_timer, + jiffies + msecs_to_jiffies(TSC2005_PENUP_TIME_MS)); + + if (!ts->esd_timeout) + goto out; + + /* update the watchdog timer */ + mod_timer(&ts->esd_timer, + round_jiffies(jiffies + msecs_to_jiffies(ts->esd_timeout))); + +out: + mutex_unlock(&ts->mutex); + return IRQ_HANDLED; +} + +static void tsc2005_penup_timer(unsigned long data) +{ + struct tsc2005 *ts = (struct tsc2005 *)data; + + schedule_work(&ts->penup_work); +} + +static void tsc2005_penup_work(struct work_struct *work) +{ + struct tsc2005 *ts = container_of(work, struct tsc2005, penup_work); + + mutex_lock(&ts->mutex); + tsc2005_update_pen_state(ts, 0, 0, 0); + mutex_unlock(&ts->mutex); +} + +static void tsc2005_start_scan(struct tsc2005 *ts) +{ + tsc2005_write(ts, TSC2005_REG_CFR0, TSC2005_CFR0_INITVALUE); + tsc2005_write(ts, TSC2005_REG_CFR1, TSC2005_CFR1_INITVALUE); + tsc2005_write(ts, TSC2005_REG_CFR2, TSC2005_CFR2_INITVALUE); + tsc2005_cmd(ts, TSC2005_CMD_NORMAL); +} + +static void tsc2005_stop_scan(struct tsc2005 *ts) +{ + tsc2005_cmd(ts, TSC2005_CMD_STOP); +} + +/* must be called with mutex held */ +static void tsc2005_disable(struct tsc2005 *ts) +{ + if (ts->disable_depth++ != 0) + return; + disable_irq(ts->spi->irq); + if (ts->esd_timeout) + del_timer_sync(&ts->esd_timer); + del_timer_sync(&ts->penup_timer); + tsc2005_stop_scan(ts); +} + +/* must be called with mutex held */ +static void tsc2005_enable(struct tsc2005 *ts) +{ + if (--ts->disable_depth != 0) + return; + tsc2005_start_scan(ts); + enable_irq(ts->spi->irq); + if (!ts->esd_timeout) + return; + mod_timer(&ts->esd_timer, + round_jiffies(jiffies + msecs_to_jiffies(ts->esd_timeout))); +} + +static ssize_t tsc2005_disable_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct tsc2005 *ts = dev_get_drvdata(dev); + + return sprintf(buf, "%u\n", ts->disabled); +} + +static ssize_t tsc2005_disable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct tsc2005 *ts = dev_get_drvdata(dev); + unsigned long res; + int i; + + if (strict_strtoul(buf, 10, &res) < 0) + return -EINVAL; + i = res ? 1 : 0; + + mutex_lock(&ts->mutex); + if (i == ts->disabled) + goto out; + ts->disabled = i; + if (i) + tsc2005_disable(ts); + else + tsc2005_enable(ts); +out: + mutex_unlock(&ts->mutex); + return count; +} +static DEVICE_ATTR(disable, 0664, tsc2005_disable_show, tsc2005_disable_store); + +static ssize_t tsc2005_selftest_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tsc2005 *ts = dev_get_drvdata(dev); + u16 temp_high; + u16 temp_high_orig; + u16 temp_high_test; + unsigned int result; + + if (!ts->set_reset) { + dev_warn(&ts->spi->dev, + "unable to selftest: no reset function\n"); + result = 0; + goto out; + } + + mutex_lock(&ts->mutex); + + /* + * Test TSC2005 communications via temp high register. + */ + tsc2005_disable(ts); + result = 1; + tsc2005_read(ts, TSC2005_REG_TEMP_HIGH, &temp_high_orig); + temp_high_test = (temp_high_orig - 1) & MAX_12BIT; + tsc2005_write(ts, TSC2005_REG_TEMP_HIGH, temp_high_test); + tsc2005_read(ts, TSC2005_REG_TEMP_HIGH, &temp_high); + if (temp_high != temp_high_test) { + dev_warn(dev, "selftest failed: %d != %d\n", + temp_high, temp_high_test); + result = 0; + } + + /* hardware reset */ + ts->set_reset(0); + usleep_range(100, 500); /* only 10us required */ + ts->set_reset(1); + tsc2005_enable(ts); + + /* test that the reset really happened */ + tsc2005_read(ts, TSC2005_REG_TEMP_HIGH, &temp_high); + if (temp_high != temp_high_orig) { + dev_warn(dev, "selftest failed after reset: %d != %d\n", + temp_high, temp_high_orig); + result = 0; + } + + mutex_unlock(&ts->mutex); + +out: + return sprintf(buf, "%u\n", result); +} +static DEVICE_ATTR(selftest, S_IRUGO, tsc2005_selftest_show, NULL); + +static void tsc2005_esd_timer(unsigned long data) +{ + struct tsc2005 *ts = (struct tsc2005 *)data; + + schedule_work(&ts->esd_work); +} + +static void tsc2005_esd_work(struct work_struct *work) +{ + struct tsc2005 *ts = container_of(work, struct tsc2005, esd_work); + u16 r; + + mutex_lock(&ts->mutex); + + if (ts->disable_depth) + goto out; + + /* + * If we cannot read our known value from configuration register 0 then + * reset the controller as if from power-up and start scanning again. + */ + tsc2005_read(ts, TSC2005_REG_CFR0, &r); + if ((r ^ TSC2005_CFR0_INITVALUE) & TSC2005_CFR0_RW_MASK) { + dev_info(&ts->spi->dev, "TSC2005 not responding - resetting\n"); + ts->set_reset(0); + tsc2005_update_pen_state(ts, 0, 0, 0); + usleep_range(100, 500); /* only 10us required */ + ts->set_reset(1); + tsc2005_start_scan(ts); + } + + /* re-arm the watchdog */ + mod_timer(&ts->esd_timer, + round_jiffies(jiffies + msecs_to_jiffies(ts->esd_timeout))); + +out: + mutex_unlock(&ts->mutex); +} + +static void __devinit tsc2005_setup_spi_xfer(struct tsc2005 *ts) +{ + tsc2005_setup_read(&ts->spi_x, TSC2005_REG_X, 0); + tsc2005_setup_read(&ts->spi_y, TSC2005_REG_Y, 0); + tsc2005_setup_read(&ts->spi_z1, TSC2005_REG_Z1, 0); + tsc2005_setup_read(&ts->spi_z2, TSC2005_REG_Z2, 1); + + spi_message_init(&ts->spi_read_msg); + spi_message_add_tail(&ts->spi_x.spi_xfer, &ts->spi_read_msg); + spi_message_add_tail(&ts->spi_y.spi_xfer, &ts->spi_read_msg); + spi_message_add_tail(&ts->spi_z1.spi_xfer, &ts->spi_read_msg); + spi_message_add_tail(&ts->spi_z2.spi_xfer, &ts->spi_read_msg); +} + +static struct attribute *tsc2005_attrs[] = { + &dev_attr_disable.attr, + &dev_attr_selftest.attr, + NULL +}; + +static struct attribute_group tsc2005_attr_group = { + .attrs = tsc2005_attrs, +}; + +static int __devinit tsc2005_setup(struct tsc2005 *ts, + struct tsc2005_platform_data *pdata) +{ + int r; + int fudge_x; + int fudge_y; + int fudge_p; + int p_max; + int x_max; + int y_max; + + mutex_init(&ts->mutex); + + tsc2005_setup_spi_xfer(ts); + + init_timer(&ts->penup_timer); + setup_timer(&ts->penup_timer, tsc2005_penup_timer, (unsigned long)ts); + INIT_WORK(&ts->penup_work, tsc2005_penup_work); + + fudge_x = pdata->ts_x_fudge ? : 4; + fudge_y = pdata->ts_y_fudge ? : 8; + fudge_p = pdata->ts_pressure_fudge ? : 2; + x_max = pdata->ts_x_max ? : MAX_12BIT; + y_max = pdata->ts_y_max ? : MAX_12BIT; + p_max = pdata->ts_pressure_max ? : MAX_12BIT; + ts->x_plate_ohm = pdata->ts_x_plate_ohm ? : 280; + ts->esd_timeout = pdata->esd_timeout_ms; + ts->set_reset = pdata->set_reset; + + ts->idev = input_allocate_device(); + if (ts->idev == NULL) + return -ENOMEM; + ts->idev->name = "TSC2005 touchscreen"; + snprintf(ts->phys, sizeof(ts->phys), "%s/input-ts", + dev_name(&ts->spi->dev)); + ts->idev->phys = ts->phys; + ts->idev->evbit[0] = BIT(EV_ABS) | BIT(EV_KEY); + ts->idev->absbit[0] = BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE); + ts->idev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); + + input_set_abs_params(ts->idev, ABS_X, 0, x_max, fudge_x, 0); + input_set_abs_params(ts->idev, ABS_Y, 0, y_max, fudge_y, 0); + input_set_abs_params(ts->idev, ABS_PRESSURE, 0, p_max, fudge_p, 0); + + r = request_threaded_irq(ts->spi->irq, tsc2005_irq_handler, + tsc2005_irq_thread, IRQF_TRIGGER_RISING, + "tsc2005", ts); + if (r) { + dev_err(&ts->spi->dev, "request_threaded_irq(): %d\n", r); + goto err1; + } + set_irq_wake(ts->spi->irq, 1); + + r = input_register_device(ts->idev); + if (r) { + dev_err(&ts->spi->dev, "input_register_device(): %d\n", r); + goto err2; + } + + r = sysfs_create_group(&ts->spi->dev.kobj, &tsc2005_attr_group); + if (r) + dev_warn(&ts->spi->dev, "sysfs entry creation failed: %d\n", r); + + tsc2005_start_scan(ts); + + if (!ts->esd_timeout || !ts->set_reset) + goto done; + + /* start the optional ESD watchdog */ + setup_timer(&ts->esd_timer, tsc2005_esd_timer, (unsigned long)ts); + INIT_WORK(&ts->esd_work, tsc2005_esd_work); + mod_timer(&ts->esd_timer, + round_jiffies(jiffies + msecs_to_jiffies(ts->esd_timeout))); + +done: + return 0; + +err2: + free_irq(ts->spi->irq, ts); + +err1: + input_free_device(ts->idev); + return r; +} + +static int __devinit tsc2005_probe(struct spi_device *spi) +{ + struct tsc2005_platform_data *pdata = spi->dev.platform_data; + struct tsc2005 *ts; + int r; + + if (spi->irq < 0) { + dev_dbg(&spi->dev, "no irq\n"); + return -ENODEV; + } + + if (!pdata) { + dev_dbg(&spi->dev, "no platform data\n"); + return -ENODEV; + } + + ts = kzalloc(sizeof(*ts), GFP_KERNEL); + if (ts == NULL) + return -ENOMEM; + + dev_set_drvdata(&spi->dev, ts); + ts->spi = spi; + spi->dev.power.power_state = PMSG_ON; + spi->mode = SPI_MODE_0; + spi->bits_per_word = 8; + if (!spi->max_speed_hz) + spi->max_speed_hz = TSC2005_SPI_MAX_SPEED_HZ; + spi_setup(spi); + + r = tsc2005_setup(ts, pdata); + if (r) + kfree(ts); + return r; +} + +static int __devexit tsc2005_remove(struct spi_device *spi) +{ + struct tsc2005 *ts = dev_get_drvdata(&spi->dev); + + mutex_lock(&ts->mutex); + tsc2005_disable(ts); + mutex_unlock(&ts->mutex); + + if (ts->esd_timeout) + del_timer_sync(&ts->esd_timer); + del_timer_sync(&ts->penup_timer); + + flush_work(&ts->esd_work); + flush_work(&ts->penup_work); + + sysfs_remove_group(&ts->spi->dev.kobj, &tsc2005_attr_group); + free_irq(ts->spi->irq, ts); + input_unregister_device(ts->idev); + kfree(ts); + + return 0; +} + +#ifdef CONFIG_PM +static int tsc2005_suspend(struct spi_device *spi, pm_message_t mesg) +{ + struct tsc2005 *ts = dev_get_drvdata(&spi->dev); + + mutex_lock(&ts->mutex); + tsc2005_disable(ts); + mutex_unlock(&ts->mutex); + + return 0; +} + +static int tsc2005_resume(struct spi_device *spi) +{ + struct tsc2005 *ts = dev_get_drvdata(&spi->dev); + + mutex_lock(&ts->mutex); + tsc2005_enable(ts); + mutex_unlock(&ts->mutex); + + return 0; +} +#endif + +static struct spi_driver tsc2005_driver = { + .driver = { + .name = "tsc2005", + .owner = THIS_MODULE, + }, +#ifdef CONFIG_PM + .suspend = tsc2005_suspend, + .resume = tsc2005_resume, +#endif + .probe = tsc2005_probe, + .remove = __devexit_p(tsc2005_remove), +}; + +static int __init tsc2005_init(void) +{ + printk(KERN_INFO "TSC2005 driver initializing\n"); + return spi_register_driver(&tsc2005_driver); +} +module_init(tsc2005_init); + +static void __exit tsc2005_exit(void) +{ + spi_unregister_driver(&tsc2005_driver); +} +module_exit(tsc2005_exit); + +MODULE_AUTHOR("Lauri Leukkunen "); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:tsc2005"); -- cgit v1.2.3 From 6b007d62fabb279b51c784c7c8abc6848b66a917 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 16 Mar 2011 22:08:08 -0700 Subject: Input: tsc2005 - use spi_get/set_drvdata() Instead of peeking into underlying device and using dev_get/set_drvdata(), let's use SPI layer's implementation to access driver-private data (which may be different from driver-core private data). Tested-by: Aaro Koskinen Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/tsc2005.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/tsc2005.c b/drivers/input/touchscreen/tsc2005.c index f95f968f18e1..5dad30a4b153 100644 --- a/drivers/input/touchscreen/tsc2005.c +++ b/drivers/input/touchscreen/tsc2005.c @@ -366,7 +366,8 @@ static void tsc2005_enable(struct tsc2005 *ts) static ssize_t tsc2005_disable_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct tsc2005 *ts = dev_get_drvdata(dev); + struct spi_device *spi = to_spi_device(dev); + struct tsc2005 *ts = spi_get_drvdata(spi); return sprintf(buf, "%u\n", ts->disabled); } @@ -375,7 +376,8 @@ static ssize_t tsc2005_disable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct tsc2005 *ts = dev_get_drvdata(dev); + struct spi_device *spi = to_spi_device(dev); + struct tsc2005 *ts = spi_get_drvdata(spi); unsigned long res; int i; @@ -401,7 +403,8 @@ static ssize_t tsc2005_selftest_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct tsc2005 *ts = dev_get_drvdata(dev); + struct spi_device *spi = to_spi_device(dev); + struct tsc2005 *ts = spi_get_drvdata(spi); u16 temp_high; u16 temp_high_orig; u16 temp_high_test; @@ -620,7 +623,7 @@ static int __devinit tsc2005_probe(struct spi_device *spi) if (ts == NULL) return -ENOMEM; - dev_set_drvdata(&spi->dev, ts); + spi_set_drvdata(spi, ts); ts->spi = spi; spi->dev.power.power_state = PMSG_ON; spi->mode = SPI_MODE_0; @@ -637,7 +640,7 @@ static int __devinit tsc2005_probe(struct spi_device *spi) static int __devexit tsc2005_remove(struct spi_device *spi) { - struct tsc2005 *ts = dev_get_drvdata(&spi->dev); + struct tsc2005 *ts = spi_get_drvdata(spi); mutex_lock(&ts->mutex); tsc2005_disable(ts); @@ -661,7 +664,8 @@ static int __devexit tsc2005_remove(struct spi_device *spi) #ifdef CONFIG_PM static int tsc2005_suspend(struct spi_device *spi, pm_message_t mesg) { - struct tsc2005 *ts = dev_get_drvdata(&spi->dev); + struct spi_device *spi = to_spi_device(dev); + struct tsc2005 *ts = spi_get_drvdata(spi); mutex_lock(&ts->mutex); tsc2005_disable(ts); @@ -672,7 +676,8 @@ static int tsc2005_suspend(struct spi_device *spi, pm_message_t mesg) static int tsc2005_resume(struct spi_device *spi) { - struct tsc2005 *ts = dev_get_drvdata(&spi->dev); + struct spi_device *spi = to_spi_device(dev); + struct tsc2005 *ts = spi_get_drvdata(spi); mutex_lock(&ts->mutex); tsc2005_enable(ts); -- cgit v1.2.3 From 3ff8ff53aae7b7e46dec6a50c29b8a022ec299ba Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 16 Mar 2011 22:08:26 -0700 Subject: Input: tsc2005 - convert to using dev_pm_ops Newer code should not be using legacy suspend/resume methods but rather supply dev_pm_ops structure as it allows better control over power management. Tested-by: Aaro Koskinen Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/tsc2005.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/tsc2005.c b/drivers/input/touchscreen/tsc2005.c index 5dad30a4b153..109efbffe5ad 100644 --- a/drivers/input/touchscreen/tsc2005.c +++ b/drivers/input/touchscreen/tsc2005.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -661,8 +662,8 @@ static int __devexit tsc2005_remove(struct spi_device *spi) return 0; } -#ifdef CONFIG_PM -static int tsc2005_suspend(struct spi_device *spi, pm_message_t mesg) +#ifdef CONFIG_PM_SLEEP +static int tsc2005_suspend(struct device *dev) { struct spi_device *spi = to_spi_device(dev); struct tsc2005 *ts = spi_get_drvdata(spi); @@ -674,7 +675,7 @@ static int tsc2005_suspend(struct spi_device *spi, pm_message_t mesg) return 0; } -static int tsc2005_resume(struct spi_device *spi) +static int tsc2005_resume(struct device *dev) { struct spi_device *spi = to_spi_device(dev); struct tsc2005 *ts = spi_get_drvdata(spi); @@ -687,17 +688,16 @@ static int tsc2005_resume(struct spi_device *spi) } #endif +static SIMPLE_DEV_PM_OPS(tsc2005_pm_ops, tsc2005_suspend, tsc2005_resume); + static struct spi_driver tsc2005_driver = { - .driver = { - .name = "tsc2005", - .owner = THIS_MODULE, + .driver = { + .name = "tsc2005", + .owner = THIS_MODULE, + .pm = &tsc2005_pm_ops, }, -#ifdef CONFIG_PM - .suspend = tsc2005_suspend, - .resume = tsc2005_resume, -#endif - .probe = tsc2005_probe, - .remove = __devexit_p(tsc2005_remove), + .probe = tsc2005_probe, + .remove = __devexit_p(tsc2005_remove), }; static int __init tsc2005_init(void) -- cgit v1.2.3 From ef5a672f8d67c45fe2739c3a98a4e41d96b5cabc Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 16 Mar 2011 22:08:39 -0700 Subject: Input: tsc2005 - remove incorrect module alias TSC2005 is not a platform driver so it should not define "platform:tsc2005" module alias. Tested-by: Aaro Koskinen Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/tsc2005.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/tsc2005.c b/drivers/input/touchscreen/tsc2005.c index 109efbffe5ad..8c2e02402f32 100644 --- a/drivers/input/touchscreen/tsc2005.c +++ b/drivers/input/touchscreen/tsc2005.c @@ -715,4 +715,3 @@ module_exit(tsc2005_exit); MODULE_AUTHOR("Lauri Leukkunen "); MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:tsc2005"); -- cgit v1.2.3 From bcd11879fb5c84b3ca9167022b4c2b66d0935c52 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 16 Mar 2011 22:08:53 -0700 Subject: Input: tsc2005 - remove driver banner message The boot process is noisy as it is and input core already announces all new device so let's get rid of the banner message in the driver. Tested-by: Aaro Koskinen Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/tsc2005.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/tsc2005.c b/drivers/input/touchscreen/tsc2005.c index 8c2e02402f32..2435235db627 100644 --- a/drivers/input/touchscreen/tsc2005.c +++ b/drivers/input/touchscreen/tsc2005.c @@ -702,7 +702,6 @@ static struct spi_driver tsc2005_driver = { static int __init tsc2005_init(void) { - printk(KERN_INFO "TSC2005 driver initializing\n"); return spi_register_driver(&tsc2005_driver); } module_init(tsc2005_init); -- cgit v1.2.3 From b88aa494c27552e6fa94e4abaa5ea4f9b2f170a8 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 16 Mar 2011 22:09:03 -0700 Subject: Input: tsc2005 - add module description Add proper module description so that it would show in 'modinfo' output. Tested-by: Aaro Koskinen Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/tsc2005.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/tsc2005.c b/drivers/input/touchscreen/tsc2005.c index 2435235db627..596fd1f01b22 100644 --- a/drivers/input/touchscreen/tsc2005.c +++ b/drivers/input/touchscreen/tsc2005.c @@ -713,4 +713,5 @@ static void __exit tsc2005_exit(void) module_exit(tsc2005_exit); MODULE_AUTHOR("Lauri Leukkunen "); +MODULE_DESCRIPTION("TSC2005 Touchscreen Driver"); MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 2721a89ac41f2e7705484c1582c293c4eee5344d Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 16 Mar 2011 22:09:09 -0700 Subject: Input: tsc2005 - clear driver data after unbinding We should not leave garbage pointers in driver structure after we unbind it from the device or if bind fails. Tested-by: Aaro Koskinen Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/tsc2005.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/tsc2005.c b/drivers/input/touchscreen/tsc2005.c index 596fd1f01b22..732c81e9a3e6 100644 --- a/drivers/input/touchscreen/tsc2005.c +++ b/drivers/input/touchscreen/tsc2005.c @@ -634,8 +634,10 @@ static int __devinit tsc2005_probe(struct spi_device *spi) spi_setup(spi); r = tsc2005_setup(ts, pdata); - if (r) + if (r) { kfree(ts); + spi_set_drvdata(spi, NULL); + } return r; } @@ -659,6 +661,7 @@ static int __devexit tsc2005_remove(struct spi_device *spi) input_unregister_device(ts->idev); kfree(ts); + spi_set_drvdata(spi, NULL); return 0; } -- cgit v1.2.3 From b4b480a8d643cbdef6f925e55759c18a674fa454 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 16 Mar 2011 22:09:25 -0700 Subject: Input: tsc2005 - set up parent device Set up SPI device as parent of the input device so it gets placed into proper place in sysfs tree. Tested-by: Aaro Koskinen Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/tsc2005.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/tsc2005.c b/drivers/input/touchscreen/tsc2005.c index 732c81e9a3e6..e294648a97c9 100644 --- a/drivers/input/touchscreen/tsc2005.c +++ b/drivers/input/touchscreen/tsc2005.c @@ -555,6 +555,7 @@ static int __devinit tsc2005_setup(struct tsc2005 *ts, snprintf(ts->phys, sizeof(ts->phys), "%s/input-ts", dev_name(&ts->spi->dev)); ts->idev->phys = ts->phys; + ts->idev->dev.parent = &ts->spi->dev; ts->idev->evbit[0] = BIT(EV_ABS) | BIT(EV_KEY); ts->idev->absbit[0] = BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE); ts->idev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); -- cgit v1.2.3 From f8a67139c68eb8a58907906622c9aa02cd6a1dd1 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 16 Mar 2011 22:09:32 -0700 Subject: Input: tsc2005 - set up bus type in input device We know what bus we are residing on (SPI) so let's make this data available to the users. Tested-by: Aaro Koskinen Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/tsc2005.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/tsc2005.c b/drivers/input/touchscreen/tsc2005.c index e294648a97c9..09cbcb0b19fe 100644 --- a/drivers/input/touchscreen/tsc2005.c +++ b/drivers/input/touchscreen/tsc2005.c @@ -555,6 +555,7 @@ static int __devinit tsc2005_setup(struct tsc2005 *ts, snprintf(ts->phys, sizeof(ts->phys), "%s/input-ts", dev_name(&ts->spi->dev)); ts->idev->phys = ts->phys; + ts->idev->id.bustype = BUS_SPI; ts->idev->dev.parent = &ts->spi->dev; ts->idev->evbit[0] = BIT(EV_ABS) | BIT(EV_KEY); ts->idev->absbit[0] = BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE); -- cgit v1.2.3 From 99bb892d8a3f4f384d61e5d20499247a7cdd3d74 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 16 Mar 2011 22:09:38 -0700 Subject: Input: tsc2005 - rework driver initialization code We need to make sure we have time/work initialized before requesting and enabling interrupts, otherwise we might start using them way too early. Tested-by: Aaro Koskinen Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/tsc2005.c | 215 ++++++++++++++++++------------------ 1 file changed, 105 insertions(+), 110 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/tsc2005.c b/drivers/input/touchscreen/tsc2005.c index 09cbcb0b19fe..de170e9dc54a 100644 --- a/drivers/input/touchscreen/tsc2005.c +++ b/drivers/input/touchscreen/tsc2005.c @@ -495,6 +495,16 @@ out: mutex_unlock(&ts->mutex); } +static struct attribute *tsc2005_attrs[] = { + &dev_attr_disable.attr, + &dev_attr_selftest.attr, + NULL +}; + +static struct attribute_group tsc2005_attr_group = { + .attrs = tsc2005_attrs, +}; + static void __devinit tsc2005_setup_spi_xfer(struct tsc2005 *ts) { tsc2005_setup_read(&ts->spi_x, TSC2005_REG_X, 0); @@ -509,144 +519,130 @@ static void __devinit tsc2005_setup_spi_xfer(struct tsc2005 *ts) spi_message_add_tail(&ts->spi_z2.spi_xfer, &ts->spi_read_msg); } -static struct attribute *tsc2005_attrs[] = { - &dev_attr_disable.attr, - &dev_attr_selftest.attr, - NULL -}; - -static struct attribute_group tsc2005_attr_group = { - .attrs = tsc2005_attrs, -}; - -static int __devinit tsc2005_setup(struct tsc2005 *ts, - struct tsc2005_platform_data *pdata) +static int __devinit tsc2005_probe(struct spi_device *spi) { - int r; - int fudge_x; - int fudge_y; - int fudge_p; - int p_max; - int x_max; - int y_max; + const struct tsc2005_platform_data *pdata = spi->dev.platform_data; + struct tsc2005 *ts; + struct input_dev *input_dev; + unsigned int max_x, max_y, max_p; + unsigned int fudge_x, fudge_y, fudge_p; + int error; - mutex_init(&ts->mutex); + if (!pdata) { + dev_dbg(&spi->dev, "no platform data\n"); + return -ENODEV; + } - tsc2005_setup_spi_xfer(ts); + fudge_x = pdata->ts_x_fudge ? : 4; + fudge_y = pdata->ts_y_fudge ? : 8; + fudge_p = pdata->ts_pressure_fudge ? : 2; + max_x = pdata->ts_x_max ? : MAX_12BIT; + max_y = pdata->ts_y_max ? : MAX_12BIT; + max_p = pdata->ts_pressure_max ? : MAX_12BIT; - init_timer(&ts->penup_timer); - setup_timer(&ts->penup_timer, tsc2005_penup_timer, (unsigned long)ts); - INIT_WORK(&ts->penup_work, tsc2005_penup_work); + if (spi->irq <= 0) { + dev_dbg(&spi->dev, "no irq\n"); + return -ENODEV; + } - fudge_x = pdata->ts_x_fudge ? : 4; - fudge_y = pdata->ts_y_fudge ? : 8; - fudge_p = pdata->ts_pressure_fudge ? : 2; - x_max = pdata->ts_x_max ? : MAX_12BIT; - y_max = pdata->ts_y_max ? : MAX_12BIT; - p_max = pdata->ts_pressure_max ? : MAX_12BIT; - ts->x_plate_ohm = pdata->ts_x_plate_ohm ? : 280; - ts->esd_timeout = pdata->esd_timeout_ms; - ts->set_reset = pdata->set_reset; + spi->mode = SPI_MODE_0; + spi->bits_per_word = 8; + if (!spi->max_speed_hz) + spi->max_speed_hz = TSC2005_SPI_MAX_SPEED_HZ; - ts->idev = input_allocate_device(); - if (ts->idev == NULL) - return -ENOMEM; - ts->idev->name = "TSC2005 touchscreen"; - snprintf(ts->phys, sizeof(ts->phys), "%s/input-ts", - dev_name(&ts->spi->dev)); - ts->idev->phys = ts->phys; - ts->idev->id.bustype = BUS_SPI; - ts->idev->dev.parent = &ts->spi->dev; - ts->idev->evbit[0] = BIT(EV_ABS) | BIT(EV_KEY); - ts->idev->absbit[0] = BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE); - ts->idev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); - - input_set_abs_params(ts->idev, ABS_X, 0, x_max, fudge_x, 0); - input_set_abs_params(ts->idev, ABS_Y, 0, y_max, fudge_y, 0); - input_set_abs_params(ts->idev, ABS_PRESSURE, 0, p_max, fudge_p, 0); - - r = request_threaded_irq(ts->spi->irq, tsc2005_irq_handler, - tsc2005_irq_thread, IRQF_TRIGGER_RISING, - "tsc2005", ts); - if (r) { - dev_err(&ts->spi->dev, "request_threaded_irq(): %d\n", r); - goto err1; - } - set_irq_wake(ts->spi->irq, 1); + error = spi_setup(spi); + if (error) + return error; - r = input_register_device(ts->idev); - if (r) { - dev_err(&ts->spi->dev, "input_register_device(): %d\n", r); - goto err2; + ts = kzalloc(sizeof(*ts), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!ts || !input_dev) { + error = -ENOMEM; + goto err_free_mem; } - r = sysfs_create_group(&ts->spi->dev.kobj, &tsc2005_attr_group); - if (r) - dev_warn(&ts->spi->dev, "sysfs entry creation failed: %d\n", r); + ts->spi = spi; + ts->idev = input_dev; + + ts->x_plate_ohm = pdata->ts_x_plate_ohm ? : 280; + ts->esd_timeout = pdata->esd_timeout_ms; + ts->set_reset = pdata->set_reset; - tsc2005_start_scan(ts); + mutex_init(&ts->mutex); - if (!ts->esd_timeout || !ts->set_reset) - goto done; + setup_timer(&ts->penup_timer, tsc2005_penup_timer, (unsigned long)ts); + INIT_WORK(&ts->penup_work, tsc2005_penup_work); - /* start the optional ESD watchdog */ setup_timer(&ts->esd_timer, tsc2005_esd_timer, (unsigned long)ts); INIT_WORK(&ts->esd_work, tsc2005_esd_work); - mod_timer(&ts->esd_timer, - round_jiffies(jiffies + msecs_to_jiffies(ts->esd_timeout))); - -done: - return 0; -err2: - free_irq(ts->spi->irq, ts); - -err1: - input_free_device(ts->idev); - return r; -} - -static int __devinit tsc2005_probe(struct spi_device *spi) -{ - struct tsc2005_platform_data *pdata = spi->dev.platform_data; - struct tsc2005 *ts; - int r; + tsc2005_setup_spi_xfer(ts); - if (spi->irq < 0) { - dev_dbg(&spi->dev, "no irq\n"); - return -ENODEV; + snprintf(ts->phys, sizeof(ts->phys), + "%s/input-ts", dev_name(&spi->dev)); + + input_dev->name = "TSC2005 touchscreen"; + input_dev->phys = ts->phys; + input_dev->id.bustype = BUS_SPI; + input_dev->dev.parent = &spi->dev; + input_dev->evbit[0] = BIT(EV_ABS) | BIT(EV_KEY); + input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); + + input_set_abs_params(input_dev, ABS_X, 0, max_x, fudge_x, 0); + input_set_abs_params(input_dev, ABS_Y, 0, max_y, fudge_y, 0); + input_set_abs_params(input_dev, ABS_PRESSURE, 0, max_p, fudge_p, 0); + + error = request_threaded_irq(spi->irq, + tsc2005_irq_handler, tsc2005_irq_thread, + IRQF_TRIGGER_RISING, "tsc2005", ts); + if (error) { + dev_err(&spi->dev, "Failed to request irq, err: %d\n", error); + goto err_free_mem; } - if (!pdata) { - dev_dbg(&spi->dev, "no platform data\n"); - return -ENODEV; + spi_set_drvdata(spi, ts); + error = sysfs_create_group(&spi->dev.kobj, &tsc2005_attr_group); + if (error) { + dev_err(&spi->dev, + "Failed to create sysfs attributes, err: %d\n", error); + goto err_clear_drvdata; } - ts = kzalloc(sizeof(*ts), GFP_KERNEL); - if (ts == NULL) - return -ENOMEM; + error = input_register_device(ts->idev); + if (error) { + dev_err(&spi->dev, + "Failed to register input device, err: %d\n", error); + goto err_remove_sysfs; + } - spi_set_drvdata(spi, ts); - ts->spi = spi; - spi->dev.power.power_state = PMSG_ON; - spi->mode = SPI_MODE_0; - spi->bits_per_word = 8; - if (!spi->max_speed_hz) - spi->max_speed_hz = TSC2005_SPI_MAX_SPEED_HZ; - spi_setup(spi); + tsc2005_start_scan(ts); - r = tsc2005_setup(ts, pdata); - if (r) { - kfree(ts); - spi_set_drvdata(spi, NULL); + if (ts->esd_timeout && ts->set_reset) { + /* start the optional ESD watchdog */ + mod_timer(&ts->esd_timer, round_jiffies(jiffies + + msecs_to_jiffies(ts->esd_timeout))); } - return r; + + set_irq_wake(spi->irq, 1); + return 0; + +err_remove_sysfs: + sysfs_remove_group(&spi->dev.kobj, &tsc2005_attr_group); +err_clear_drvdata: + spi_set_drvdata(spi, NULL); + free_irq(spi->irq, ts); +err_free_mem: + input_free_device(input_dev); + kfree(ts); + return error; } static int __devexit tsc2005_remove(struct spi_device *spi) { struct tsc2005 *ts = spi_get_drvdata(spi); + sysfs_remove_group(&ts->spi->dev.kobj, &tsc2005_attr_group); + mutex_lock(&ts->mutex); tsc2005_disable(ts); mutex_unlock(&ts->mutex); @@ -658,7 +654,6 @@ static int __devexit tsc2005_remove(struct spi_device *spi) flush_work(&ts->esd_work); flush_work(&ts->penup_work); - sysfs_remove_group(&ts->spi->dev.kobj, &tsc2005_attr_group); free_irq(ts->spi->irq, ts); input_unregister_device(ts->idev); kfree(ts); -- cgit v1.2.3 From 8dbcc432c2b4adf4ff7183afc5f2b42276b2a987 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 16 Mar 2011 22:10:37 -0700 Subject: Input: tsc2005 - hide selftest attribute if we can't reset If implementation to perform self-test/reset has not been provided by the platform code hide 'selftest' sysfs attribute instead of returning error when someone tries to use it. Tested-by: Aaro Koskinen Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/tsc2005.c | 46 ++++++++++++++++++++++--------------- 1 file changed, 28 insertions(+), 18 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/tsc2005.c b/drivers/input/touchscreen/tsc2005.c index de170e9dc54a..bc7e2f974b7e 100644 --- a/drivers/input/touchscreen/tsc2005.c +++ b/drivers/input/touchscreen/tsc2005.c @@ -411,13 +411,6 @@ static ssize_t tsc2005_selftest_show(struct device *dev, u16 temp_high_test; unsigned int result; - if (!ts->set_reset) { - dev_warn(&ts->spi->dev, - "unable to selftest: no reset function\n"); - result = 0; - goto out; - } - mutex_lock(&ts->mutex); /* @@ -451,11 +444,38 @@ static ssize_t tsc2005_selftest_show(struct device *dev, mutex_unlock(&ts->mutex); -out: return sprintf(buf, "%u\n", result); } + static DEVICE_ATTR(selftest, S_IRUGO, tsc2005_selftest_show, NULL); +static struct attribute *tsc2005_attrs[] = { + &dev_attr_disable.attr, + &dev_attr_selftest.attr, + NULL +}; + +static mode_t tsc2005_attr_is_visible(struct kobject *kobj, + struct attribute *attr, int n) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct spi_device *spi = to_spi_device(dev); + struct tsc2005 *ts = spi_get_drvdata(spi); + mode_t mode = attr->mode; + + if (attr == &dev_attr_selftest.attr) { + if (!ts->set_reset) + mode = 0; + } + + return mode; +} + +static const struct attribute_group tsc2005_attr_group = { + .is_visible = tsc2005_attr_is_visible, + .attrs = tsc2005_attrs, +}; + static void tsc2005_esd_timer(unsigned long data) { struct tsc2005 *ts = (struct tsc2005 *)data; @@ -495,16 +515,6 @@ out: mutex_unlock(&ts->mutex); } -static struct attribute *tsc2005_attrs[] = { - &dev_attr_disable.attr, - &dev_attr_selftest.attr, - NULL -}; - -static struct attribute_group tsc2005_attr_group = { - .attrs = tsc2005_attrs, -}; - static void __devinit tsc2005_setup_spi_xfer(struct tsc2005 *ts) { tsc2005_setup_read(&ts->spi_x, TSC2005_REG_X, 0); -- cgit v1.2.3 From c8b6846a7559e64d7ac4ba1ccdba05f3ee2e34e8 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 16 Mar 2011 22:10:46 -0700 Subject: Input: tsc2005 - use true/false for boolean variables Tested-by: Aaro Koskinen Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/tsc2005.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/tsc2005.c b/drivers/input/touchscreen/tsc2005.c index bc7e2f974b7e..f457cb95b95b 100644 --- a/drivers/input/touchscreen/tsc2005.c +++ b/drivers/input/touchscreen/tsc2005.c @@ -140,7 +140,8 @@ struct tsc2005 { bool disabled; unsigned int disable_depth; - unsigned int pen_down; + + bool pen_down; void (*set_reset)(bool enable); }; @@ -197,7 +198,7 @@ static void tsc2005_read(struct tsc2005 *ts, u8 reg, u16 *value) struct spi_message msg; struct tsc2005_spi_rd spi_rd = { { 0 }, 0, 0 }; - tsc2005_setup_read(&spi_rd, reg, 1); + tsc2005_setup_read(&spi_rd, reg, true); spi_message_init(&msg); spi_message_add_tail(&spi_rd.spi_xfer, &msg); @@ -214,13 +215,13 @@ static void tsc2005_update_pen_state(struct tsc2005 *ts, input_report_abs(ts->idev, ABS_PRESSURE, pressure); if (!ts->pen_down) { input_report_key(ts->idev, BTN_TOUCH, !!pressure); - ts->pen_down = 1; + ts->pen_down = true; } } else { input_report_abs(ts->idev, ABS_PRESSURE, 0); if (ts->pen_down) { input_report_key(ts->idev, BTN_TOUCH, 0); - ts->pen_down = 0; + ts->pen_down = false; } } input_sync(ts->idev); @@ -429,9 +430,9 @@ static ssize_t tsc2005_selftest_show(struct device *dev, } /* hardware reset */ - ts->set_reset(0); + ts->set_reset(false); usleep_range(100, 500); /* only 10us required */ - ts->set_reset(1); + ts->set_reset(true); tsc2005_enable(ts); /* test that the reset really happened */ @@ -500,10 +501,10 @@ static void tsc2005_esd_work(struct work_struct *work) tsc2005_read(ts, TSC2005_REG_CFR0, &r); if ((r ^ TSC2005_CFR0_INITVALUE) & TSC2005_CFR0_RW_MASK) { dev_info(&ts->spi->dev, "TSC2005 not responding - resetting\n"); - ts->set_reset(0); + ts->set_reset(false); tsc2005_update_pen_state(ts, 0, 0, 0); usleep_range(100, 500); /* only 10us required */ - ts->set_reset(1); + ts->set_reset(true); tsc2005_start_scan(ts); } @@ -517,10 +518,10 @@ out: static void __devinit tsc2005_setup_spi_xfer(struct tsc2005 *ts) { - tsc2005_setup_read(&ts->spi_x, TSC2005_REG_X, 0); - tsc2005_setup_read(&ts->spi_y, TSC2005_REG_Y, 0); - tsc2005_setup_read(&ts->spi_z1, TSC2005_REG_Z1, 0); - tsc2005_setup_read(&ts->spi_z2, TSC2005_REG_Z2, 1); + tsc2005_setup_read(&ts->spi_x, TSC2005_REG_X, false); + tsc2005_setup_read(&ts->spi_y, TSC2005_REG_Y, false); + tsc2005_setup_read(&ts->spi_z1, TSC2005_REG_Z1, false); + tsc2005_setup_read(&ts->spi_z2, TSC2005_REG_Z2, true); spi_message_init(&ts->spi_read_msg); spi_message_add_tail(&ts->spi_x.spi_xfer, &ts->spi_read_msg); -- cgit v1.2.3 From 9a6e180af78247e3a7680460240bb450c39d3a5b Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 16 Mar 2011 22:10:52 -0700 Subject: Input: tsc2005 - do not use 0 in place of NULL Sparse in unhappy when people use 0 instead of NULL for pointers so let's rework the way we initialize spi_transfer structure in tsc2005_cmd() and tsc2005_write(). Tested-by: Aaro Koskinen Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/tsc2005.c | 36 ++++++++++++++++-------------------- 1 file changed, 16 insertions(+), 20 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/tsc2005.c b/drivers/input/touchscreen/tsc2005.c index f457cb95b95b..289057e1b9a2 100644 --- a/drivers/input/touchscreen/tsc2005.c +++ b/drivers/input/touchscreen/tsc2005.c @@ -148,16 +148,13 @@ struct tsc2005 { static void tsc2005_cmd(struct tsc2005 *ts, u8 cmd) { - u8 tx; + u8 tx = TSC2005_CMD | TSC2005_CMD_12BIT | cmd; + struct spi_transfer xfer = { + .tx_buf = &tx, + .len = 1, + .bits_per_word = 8, + }; struct spi_message msg; - struct spi_transfer xfer = { 0 }; - - tx = TSC2005_CMD | TSC2005_CMD_12BIT | cmd; - - xfer.tx_buf = &tx; - xfer.rx_buf = NULL; - xfer.len = 1; - xfer.bits_per_word = 8; spi_message_init(&msg); spi_message_add_tail(&xfer, &msg); @@ -166,17 +163,13 @@ static void tsc2005_cmd(struct tsc2005 *ts, u8 cmd) static void tsc2005_write(struct tsc2005 *ts, u8 reg, u16 value) { - u32 tx; + u32 tx = ((reg | TSC2005_REG_PND0) << 16) | value; + struct spi_transfer xfer = { + .tx_buf = &tx, + .len = 4, + .bits_per_word = 24, + }; struct spi_message msg; - struct spi_transfer xfer = { 0 }; - - tx = (reg | TSC2005_REG_PND0) << 16; - tx |= value; - - xfer.tx_buf = &tx; - xfer.rx_buf = NULL; - xfer.len = 4; - xfer.bits_per_word = 24; spi_message_init(&msg); spi_message_add_tail(&xfer, &msg); @@ -185,6 +178,8 @@ static void tsc2005_write(struct tsc2005 *ts, u8 reg, u16 value) static void tsc2005_setup_read(struct tsc2005_spi_rd *rd, u8 reg, bool last) { + memset(rd, 0, sizeof(*rd)); + rd->spi_tx = (reg | TSC2005_REG_READ) << 16; rd->spi_xfer.tx_buf = &rd->spi_tx; rd->spi_xfer.rx_buf = &rd->spi_rx; @@ -195,14 +190,15 @@ static void tsc2005_setup_read(struct tsc2005_spi_rd *rd, u8 reg, bool last) static void tsc2005_read(struct tsc2005 *ts, u8 reg, u16 *value) { + struct tsc2005_spi_rd spi_rd; struct spi_message msg; - struct tsc2005_spi_rd spi_rd = { { 0 }, 0, 0 }; tsc2005_setup_read(&spi_rd, reg, true); spi_message_init(&msg); spi_message_add_tail(&spi_rd.spi_xfer, &msg); spi_sync(ts->spi, &msg); + *value = spi_rd.spi_rx; } -- cgit v1.2.3 From 80cc2f0c928ddf58051f2809e1c2e7d0172d0291 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 16 Mar 2011 22:11:08 -0700 Subject: Input: tsc2005 - don't use work for 'pen up' handling We do not need process context to send input events so let's switch to a regular timer. I am going to get rid of taking ts->mutex in tsc2005_irq_thread() later. Tested-by: Aaro Koskinen Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/tsc2005.c | 58 +++++++++++++++++-------------------- 1 file changed, 27 insertions(+), 31 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/tsc2005.c b/drivers/input/touchscreen/tsc2005.c index 289057e1b9a2..dc309da59fca 100644 --- a/drivers/input/touchscreen/tsc2005.c +++ b/drivers/input/touchscreen/tsc2005.c @@ -129,8 +129,8 @@ struct tsc2005 { int in_z1; int in_z2; + spinlock_t lock; struct timer_list penup_timer; - struct work_struct penup_work; unsigned int esd_timeout; struct timer_list esd_timer; @@ -239,11 +239,10 @@ static irqreturn_t tsc2005_irq_handler(int irq, void *dev_id) static irqreturn_t tsc2005_irq_thread(int irq, void *_ts) { struct tsc2005 *ts = _ts; + unsigned long flags; unsigned int pressure; - u32 x; - u32 y; - u32 z1; - u32 z2; + u32 x, y; + u32 z1, z2; mutex_lock(&ts->mutex); @@ -261,46 +260,50 @@ static irqreturn_t tsc2005_irq_thread(int irq, void *_ts) if (unlikely(x > MAX_12BIT || y > MAX_12BIT)) goto out; - /* skip coords if the pressure components are out of range */ + /* Skip reading if the pressure components are out of range */ if (unlikely(z1 == 0 || z2 > MAX_12BIT || z1 >= z2)) goto out; - /* skip point if this is a pen down with the exact same values as + /* + * Skip point if this is a pen down with the exact same values as * the value before pen-up - that implies SPI fed us stale data */ if (!ts->pen_down && - ts->in_x == x && - ts->in_y == y && - ts->in_z1 == z1 && - ts->in_z2 == z2) + ts->in_x == x && ts->in_y == y && + ts->in_z1 == z1 && ts->in_z2 == z2) { goto out; + } - /* At this point we are happy we have a valid and useful reading. - * Remember it for later comparisons. We may now begin downsampling - */ + /* + * At this point we are happy we have a valid and useful reading. + * Remember it for later comparisons. We may now begin downsampling. + */ ts->in_x = x; ts->in_y = y; ts->in_z1 = z1; ts->in_z2 = z2; - /* compute touch pressure resistance using equation #1 */ + /* Compute touch pressure resistance using equation #1 */ pressure = x * (z2 - z1) / z1; pressure = pressure * ts->x_plate_ohm / 4096; if (unlikely(pressure > MAX_12BIT)) goto out; + spin_lock_irqsave(&ts->lock, flags); + tsc2005_update_pen_state(ts, x, y, pressure); /* set the penup timer */ mod_timer(&ts->penup_timer, jiffies + msecs_to_jiffies(TSC2005_PENUP_TIME_MS)); - if (!ts->esd_timeout) - goto out; + if (ts->esd_timeout && ts->set_reset) { + /* update the watchdog timer */ + mod_timer(&ts->esd_timer, round_jiffies(jiffies + + msecs_to_jiffies(ts->esd_timeout))); + } - /* update the watchdog timer */ - mod_timer(&ts->esd_timer, - round_jiffies(jiffies + msecs_to_jiffies(ts->esd_timeout))); + spin_unlock_irqrestore(&ts->lock, flags); out: mutex_unlock(&ts->mutex); @@ -310,17 +313,11 @@ out: static void tsc2005_penup_timer(unsigned long data) { struct tsc2005 *ts = (struct tsc2005 *)data; + unsigned long flags; - schedule_work(&ts->penup_work); -} - -static void tsc2005_penup_work(struct work_struct *work) -{ - struct tsc2005 *ts = container_of(work, struct tsc2005, penup_work); - - mutex_lock(&ts->mutex); + spin_lock_irqsave(&ts->lock, flags); tsc2005_update_pen_state(ts, 0, 0, 0); - mutex_unlock(&ts->mutex); + spin_unlock_irqrestore(&ts->lock, flags); } static void tsc2005_start_scan(struct tsc2005 *ts) @@ -577,8 +574,8 @@ static int __devinit tsc2005_probe(struct spi_device *spi) mutex_init(&ts->mutex); + spin_lock_init(&ts->lock); setup_timer(&ts->penup_timer, tsc2005_penup_timer, (unsigned long)ts); - INIT_WORK(&ts->penup_work, tsc2005_penup_work); setup_timer(&ts->esd_timer, tsc2005_esd_timer, (unsigned long)ts); INIT_WORK(&ts->esd_work, tsc2005_esd_work); @@ -659,7 +656,6 @@ static int __devexit tsc2005_remove(struct spi_device *spi) del_timer_sync(&ts->penup_timer); flush_work(&ts->esd_work); - flush_work(&ts->penup_work); free_irq(ts->spi->irq, ts); input_unregister_device(ts->idev); -- cgit v1.2.3 From dacb650f125c7dc7ead9735d081bc078325b6d23 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 16 Mar 2011 22:11:14 -0700 Subject: Input: tsc2005 - do not rearm timer in hardirq handler We will most likely rearm it yet again the IRQ thread so doing it here is pointless. Tested-by: Aaro Koskinen Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/tsc2005.c | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/tsc2005.c b/drivers/input/touchscreen/tsc2005.c index dc309da59fca..7a7653390187 100644 --- a/drivers/input/touchscreen/tsc2005.c +++ b/drivers/input/touchscreen/tsc2005.c @@ -225,17 +225,6 @@ static void tsc2005_update_pen_state(struct tsc2005 *ts, pressure); } -static irqreturn_t tsc2005_irq_handler(int irq, void *dev_id) -{ - struct tsc2005 *ts = dev_id; - - /* update the penup timer only if it's pending */ - mod_timer_pending(&ts->penup_timer, - jiffies + msecs_to_jiffies(TSC2005_PENUP_TIME_MS)); - - return IRQ_WAKE_THREAD; -} - static irqreturn_t tsc2005_irq_thread(int irq, void *_ts) { struct tsc2005 *ts = _ts; @@ -596,8 +585,7 @@ static int __devinit tsc2005_probe(struct spi_device *spi) input_set_abs_params(input_dev, ABS_Y, 0, max_y, fudge_y, 0); input_set_abs_params(input_dev, ABS_PRESSURE, 0, max_p, fudge_p, 0); - error = request_threaded_irq(spi->irq, - tsc2005_irq_handler, tsc2005_irq_thread, + error = request_threaded_irq(spi->irq, NULL, tsc2005_irq_thread, IRQF_TRIGGER_RISING, "tsc2005", ts); if (error) { dev_err(&spi->dev, "Failed to request irq, err: %d\n", error); -- cgit v1.2.3 From 71f80045d48f259ea423bae3c14c2361e010a9ce Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 16 Mar 2011 22:11:25 -0700 Subject: Input: tsc2005 - handle read errors from SPI layer Tested-by: Aaro Koskinen Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/tsc2005.c | 100 +++++++++++++++++++++++++++++------- 1 file changed, 81 insertions(+), 19 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/tsc2005.c b/drivers/input/touchscreen/tsc2005.c index 7a7653390187..5a15919ec4c7 100644 --- a/drivers/input/touchscreen/tsc2005.c +++ b/drivers/input/touchscreen/tsc2005.c @@ -146,7 +146,7 @@ struct tsc2005 { void (*set_reset)(bool enable); }; -static void tsc2005_cmd(struct tsc2005 *ts, u8 cmd) +static int tsc2005_cmd(struct tsc2005 *ts, u8 cmd) { u8 tx = TSC2005_CMD | TSC2005_CMD_12BIT | cmd; struct spi_transfer xfer = { @@ -155,13 +155,22 @@ static void tsc2005_cmd(struct tsc2005 *ts, u8 cmd) .bits_per_word = 8, }; struct spi_message msg; + int error; spi_message_init(&msg); spi_message_add_tail(&xfer, &msg); - spi_sync(ts->spi, &msg); + + error = spi_sync(ts->spi, &msg); + if (error) { + dev_err(&ts->spi->dev, "%s: failed, command: %x, error: %d\n", + __func__, cmd, error); + return error; + } + + return 0; } -static void tsc2005_write(struct tsc2005 *ts, u8 reg, u16 value) +static int tsc2005_write(struct tsc2005 *ts, u8 reg, u16 value) { u32 tx = ((reg | TSC2005_REG_PND0) << 16) | value; struct spi_transfer xfer = { @@ -170,10 +179,20 @@ static void tsc2005_write(struct tsc2005 *ts, u8 reg, u16 value) .bits_per_word = 24, }; struct spi_message msg; + int error; spi_message_init(&msg); spi_message_add_tail(&xfer, &msg); - spi_sync(ts->spi, &msg); + + error = spi_sync(ts->spi, &msg); + if (error) { + dev_err(&ts->spi->dev, + "%s: failed, register: %x, value: %x, error: %d\n", + __func__, reg, value, error); + return error; + } + + return 0; } static void tsc2005_setup_read(struct tsc2005_spi_rd *rd, u8 reg, bool last) @@ -188,18 +207,23 @@ static void tsc2005_setup_read(struct tsc2005_spi_rd *rd, u8 reg, bool last) rd->spi_xfer.cs_change = !last; } -static void tsc2005_read(struct tsc2005 *ts, u8 reg, u16 *value) +static int tsc2005_read(struct tsc2005 *ts, u8 reg, u16 *value) { struct tsc2005_spi_rd spi_rd; struct spi_message msg; + int error; tsc2005_setup_read(&spi_rd, reg, true); spi_message_init(&msg); spi_message_add_tail(&spi_rd.spi_xfer, &msg); - spi_sync(ts->spi, &msg); + + error = spi_sync(ts->spi, &msg); + if (error) + return error; *value = spi_rd.spi_rx; + return 0; } static void tsc2005_update_pen_state(struct tsc2005 *ts, @@ -232,6 +256,7 @@ static irqreturn_t tsc2005_irq_thread(int irq, void *_ts) unsigned int pressure; u32 x, y; u32 z1, z2; + int error; mutex_lock(&ts->mutex); @@ -239,7 +264,10 @@ static irqreturn_t tsc2005_irq_thread(int irq, void *_ts) goto out; /* read the coordinates */ - spi_sync(ts->spi, &ts->spi_read_msg); + error = spi_sync(ts->spi, &ts->spi_read_msg); + if (unlikely(error)) + goto out; + x = ts->spi_x.spi_rx; y = ts->spi_y.spi_rx; z1 = ts->spi_z1.spi_rx; @@ -392,7 +420,8 @@ static ssize_t tsc2005_selftest_show(struct device *dev, u16 temp_high; u16 temp_high_orig; u16 temp_high_test; - unsigned int result; + bool success = true; + int error; mutex_lock(&ts->mutex); @@ -400,34 +429,65 @@ static ssize_t tsc2005_selftest_show(struct device *dev, * Test TSC2005 communications via temp high register. */ tsc2005_disable(ts); - result = 1; - tsc2005_read(ts, TSC2005_REG_TEMP_HIGH, &temp_high_orig); + + error = tsc2005_read(ts, TSC2005_REG_TEMP_HIGH, &temp_high_orig); + if (error) { + dev_warn(dev, "selftest failed: read error %d\n", error); + success = false; + goto out; + } + temp_high_test = (temp_high_orig - 1) & MAX_12BIT; - tsc2005_write(ts, TSC2005_REG_TEMP_HIGH, temp_high_test); - tsc2005_read(ts, TSC2005_REG_TEMP_HIGH, &temp_high); + + error = tsc2005_write(ts, TSC2005_REG_TEMP_HIGH, temp_high_test); + if (error) { + dev_warn(dev, "selftest failed: write error %d\n", error); + success = false; + goto out; + } + + error = tsc2005_read(ts, TSC2005_REG_TEMP_HIGH, &temp_high); + if (error) { + dev_warn(dev, "selftest failed: read error %d after write\n", + error); + success = false; + goto out; + } + if (temp_high != temp_high_test) { dev_warn(dev, "selftest failed: %d != %d\n", temp_high, temp_high_test); - result = 0; + success = false; } /* hardware reset */ ts->set_reset(false); usleep_range(100, 500); /* only 10us required */ ts->set_reset(true); - tsc2005_enable(ts); + + if (!success) + goto out; /* test that the reset really happened */ - tsc2005_read(ts, TSC2005_REG_TEMP_HIGH, &temp_high); + error = tsc2005_read(ts, TSC2005_REG_TEMP_HIGH, &temp_high); + if (error) { + dev_warn(dev, "selftest failed: read error %d after reset\n", + error); + success = false; + goto out; + } + if (temp_high != temp_high_orig) { dev_warn(dev, "selftest failed after reset: %d != %d\n", temp_high, temp_high_orig); - result = 0; + success = false; } +out: + tsc2005_enable(ts); mutex_unlock(&ts->mutex); - return sprintf(buf, "%u\n", result); + return sprintf(buf, "%d\n", success); } static DEVICE_ATTR(selftest, S_IRUGO, tsc2005_selftest_show, NULL); @@ -469,6 +529,7 @@ static void tsc2005_esd_timer(unsigned long data) static void tsc2005_esd_work(struct work_struct *work) { struct tsc2005 *ts = container_of(work, struct tsc2005, esd_work); + int error; u16 r; mutex_lock(&ts->mutex); @@ -480,8 +541,9 @@ static void tsc2005_esd_work(struct work_struct *work) * If we cannot read our known value from configuration register 0 then * reset the controller as if from power-up and start scanning again. */ - tsc2005_read(ts, TSC2005_REG_CFR0, &r); - if ((r ^ TSC2005_CFR0_INITVALUE) & TSC2005_CFR0_RW_MASK) { + error = tsc2005_read(ts, TSC2005_REG_CFR0, &r); + if (error || + ((r ^ TSC2005_CFR0_INITVALUE) & TSC2005_CFR0_RW_MASK)) { dev_info(&ts->spi->dev, "TSC2005 not responding - resetting\n"); ts->set_reset(false); tsc2005_update_pen_state(ts, 0, 0, 0); -- cgit v1.2.3 From 0b950d3d7ce4c1e870b8efc4ae0faaf0ef53532c Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 16 Mar 2011 22:11:34 -0700 Subject: Input: tsc2005 - add open/close Introduce open and close methods for the input device to keep the device powered down when it is not in use. Also rework interaction between interrupt thread and starting/shutting off/resetting the device: instead of taking a mutex in the intterrupt thread and elsewhere disable interrupts before transitioning the device in a new state. The ESD handling is also separated from the IRQ thread; we poll regularly at a given interval and simply skip reads if we see that valid interrupt happened not so long ago. This allows us not cancel and reschedule ESD work from interrupt context all the time. Tested-by: Aaro Koskinen Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/tsc2005.c | 218 ++++++++++++++++++++---------------- 1 file changed, 124 insertions(+), 94 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/tsc2005.c b/drivers/input/touchscreen/tsc2005.c index 5a15919ec4c7..3e1c9c297f33 100644 --- a/drivers/input/touchscreen/tsc2005.c +++ b/drivers/input/touchscreen/tsc2005.c @@ -133,13 +133,14 @@ struct tsc2005 { struct timer_list penup_timer; unsigned int esd_timeout; - struct timer_list esd_timer; - struct work_struct esd_work; + struct delayed_work esd_work; + unsigned long last_valid_interrupt; unsigned int x_plate_ohm; bool disabled; - unsigned int disable_depth; + bool opened; + bool suspended; bool pen_down; @@ -258,11 +259,6 @@ static irqreturn_t tsc2005_irq_thread(int irq, void *_ts) u32 z1, z2; int error; - mutex_lock(&ts->mutex); - - if (unlikely(ts->disable_depth)) - goto out; - /* read the coordinates */ error = spi_sync(ts->spi, &ts->spi_read_msg); if (unlikely(error)) @@ -309,21 +305,13 @@ static irqreturn_t tsc2005_irq_thread(int irq, void *_ts) spin_lock_irqsave(&ts->lock, flags); tsc2005_update_pen_state(ts, x, y, pressure); - - /* set the penup timer */ mod_timer(&ts->penup_timer, jiffies + msecs_to_jiffies(TSC2005_PENUP_TIME_MS)); - if (ts->esd_timeout && ts->set_reset) { - /* update the watchdog timer */ - mod_timer(&ts->esd_timer, round_jiffies(jiffies + - msecs_to_jiffies(ts->esd_timeout))); - } - spin_unlock_irqrestore(&ts->lock, flags); + ts->last_valid_interrupt = jiffies; out: - mutex_unlock(&ts->mutex); return IRQ_HANDLED; } @@ -350,29 +338,31 @@ static void tsc2005_stop_scan(struct tsc2005 *ts) tsc2005_cmd(ts, TSC2005_CMD_STOP); } -/* must be called with mutex held */ -static void tsc2005_disable(struct tsc2005 *ts) +/* must be called with ts->mutex held */ +static void __tsc2005_disable(struct tsc2005 *ts) { - if (ts->disable_depth++ != 0) - return; + tsc2005_stop_scan(ts); + disable_irq(ts->spi->irq); - if (ts->esd_timeout) - del_timer_sync(&ts->esd_timer); del_timer_sync(&ts->penup_timer); - tsc2005_stop_scan(ts); + + cancel_delayed_work_sync(&ts->esd_work); + + enable_irq(ts->spi->irq); } -/* must be called with mutex held */ -static void tsc2005_enable(struct tsc2005 *ts) +/* must be called with ts->mutex held */ +static void __tsc2005_enable(struct tsc2005 *ts) { - if (--ts->disable_depth != 0) - return; tsc2005_start_scan(ts); - enable_irq(ts->spi->irq); - if (!ts->esd_timeout) - return; - mod_timer(&ts->esd_timer, - round_jiffies(jiffies + msecs_to_jiffies(ts->esd_timeout))); + + if (ts->esd_timeout && ts->set_reset) { + ts->last_valid_interrupt = jiffies; + schedule_delayed_work(&ts->esd_work, + round_jiffies(jiffies + + msecs_to_jiffies(ts->esd_timeout))); + } + } static ssize_t tsc2005_disable_show(struct device *dev, @@ -390,23 +380,29 @@ static ssize_t tsc2005_disable_store(struct device *dev, { struct spi_device *spi = to_spi_device(dev); struct tsc2005 *ts = spi_get_drvdata(spi); - unsigned long res; - int i; + unsigned long val; + int error; - if (strict_strtoul(buf, 10, &res) < 0) - return -EINVAL; - i = res ? 1 : 0; + error = strict_strtoul(buf, 10, &val); + if (error) + return error; mutex_lock(&ts->mutex); - if (i == ts->disabled) - goto out; - ts->disabled = i; - if (i) - tsc2005_disable(ts); - else - tsc2005_enable(ts); -out: + + if (!ts->suspended && ts->opened) { + if (val) { + if (!ts->disabled) + __tsc2005_disable(ts); + } else { + if (ts->disabled) + __tsc2005_enable(ts); + } + } + + ts->disabled = !!val; + mutex_unlock(&ts->mutex); + return count; } static DEVICE_ATTR(disable, 0664, tsc2005_disable_show, tsc2005_disable_store); @@ -428,7 +424,7 @@ static ssize_t tsc2005_selftest_show(struct device *dev, /* * Test TSC2005 communications via temp high register. */ - tsc2005_disable(ts); + __tsc2005_disable(ts); error = tsc2005_read(ts, TSC2005_REG_TEMP_HIGH, &temp_high_orig); if (error) { @@ -484,7 +480,7 @@ static ssize_t tsc2005_selftest_show(struct device *dev, } out: - tsc2005_enable(ts); + __tsc2005_enable(ts); mutex_unlock(&ts->mutex); return sprintf(buf, "%d\n", success); @@ -519,44 +515,79 @@ static const struct attribute_group tsc2005_attr_group = { .attrs = tsc2005_attrs, }; -static void tsc2005_esd_timer(unsigned long data) -{ - struct tsc2005 *ts = (struct tsc2005 *)data; - - schedule_work(&ts->esd_work); -} - static void tsc2005_esd_work(struct work_struct *work) { - struct tsc2005 *ts = container_of(work, struct tsc2005, esd_work); + struct tsc2005 *ts = container_of(work, struct tsc2005, esd_work.work); int error; u16 r; mutex_lock(&ts->mutex); - if (ts->disable_depth) + if (time_is_after_jiffies(ts->last_valid_interrupt + + msecs_to_jiffies(ts->esd_timeout))) goto out; - /* - * If we cannot read our known value from configuration register 0 then - * reset the controller as if from power-up and start scanning again. - */ + /* We should be able to read register without disabling interrupts. */ error = tsc2005_read(ts, TSC2005_REG_CFR0, &r); - if (error || - ((r ^ TSC2005_CFR0_INITVALUE) & TSC2005_CFR0_RW_MASK)) { - dev_info(&ts->spi->dev, "TSC2005 not responding - resetting\n"); - ts->set_reset(false); - tsc2005_update_pen_state(ts, 0, 0, 0); - usleep_range(100, 500); /* only 10us required */ - ts->set_reset(true); - tsc2005_start_scan(ts); + if (!error && + !((r ^ TSC2005_CFR0_INITVALUE) & TSC2005_CFR0_RW_MASK)) { + goto out; } - /* re-arm the watchdog */ - mod_timer(&ts->esd_timer, - round_jiffies(jiffies + msecs_to_jiffies(ts->esd_timeout))); + /* + * If we could not read our known value from configuration register 0 + * then we should reset the controller as if from power-up and start + * scanning again. + */ + dev_info(&ts->spi->dev, "TSC2005 not responding - resetting\n"); + + disable_irq(ts->spi->irq); + del_timer_sync(&ts->penup_timer); + + tsc2005_update_pen_state(ts, 0, 0, 0); + + ts->set_reset(false); + usleep_range(100, 500); /* only 10us required */ + ts->set_reset(true); + + enable_irq(ts->spi->irq); + tsc2005_start_scan(ts); out: + /* re-arm the watchdog */ + schedule_delayed_work(&ts->esd_work, + round_jiffies(jiffies + + msecs_to_jiffies(ts->esd_timeout))); + mutex_unlock(&ts->mutex); +} + +static int tsc2005_open(struct input_dev *input) +{ + struct tsc2005 *ts = input_get_drvdata(input); + + mutex_lock(&ts->mutex); + + if (!ts->suspended && !ts->disabled) + __tsc2005_enable(ts); + + ts->opened = true; + + mutex_unlock(&ts->mutex); + + return 0; +} + +static void tsc2005_close(struct input_dev *input) +{ + struct tsc2005 *ts = input_get_drvdata(input); + + mutex_lock(&ts->mutex); + + if (!ts->suspended && !ts->disabled) + __tsc2005_disable(ts); + + ts->opened = false; + mutex_unlock(&ts->mutex); } @@ -628,8 +659,7 @@ static int __devinit tsc2005_probe(struct spi_device *spi) spin_lock_init(&ts->lock); setup_timer(&ts->penup_timer, tsc2005_penup_timer, (unsigned long)ts); - setup_timer(&ts->esd_timer, tsc2005_esd_timer, (unsigned long)ts); - INIT_WORK(&ts->esd_work, tsc2005_esd_work); + INIT_DELAYED_WORK(&ts->esd_work, tsc2005_esd_work); tsc2005_setup_spi_xfer(ts); @@ -647,6 +677,14 @@ static int __devinit tsc2005_probe(struct spi_device *spi) input_set_abs_params(input_dev, ABS_Y, 0, max_y, fudge_y, 0); input_set_abs_params(input_dev, ABS_PRESSURE, 0, max_p, fudge_p, 0); + input_dev->open = tsc2005_open; + input_dev->close = tsc2005_close; + + input_set_drvdata(input_dev, ts); + + /* Ensure the touchscreen is off */ + tsc2005_stop_scan(ts); + error = request_threaded_irq(spi->irq, NULL, tsc2005_irq_thread, IRQF_TRIGGER_RISING, "tsc2005", ts); if (error) { @@ -669,14 +707,6 @@ static int __devinit tsc2005_probe(struct spi_device *spi) goto err_remove_sysfs; } - tsc2005_start_scan(ts); - - if (ts->esd_timeout && ts->set_reset) { - /* start the optional ESD watchdog */ - mod_timer(&ts->esd_timer, round_jiffies(jiffies + - msecs_to_jiffies(ts->esd_timeout))); - } - set_irq_wake(spi->irq, 1); return 0; @@ -697,16 +727,6 @@ static int __devexit tsc2005_remove(struct spi_device *spi) sysfs_remove_group(&ts->spi->dev.kobj, &tsc2005_attr_group); - mutex_lock(&ts->mutex); - tsc2005_disable(ts); - mutex_unlock(&ts->mutex); - - if (ts->esd_timeout) - del_timer_sync(&ts->esd_timer); - del_timer_sync(&ts->penup_timer); - - flush_work(&ts->esd_work); - free_irq(ts->spi->irq, ts); input_unregister_device(ts->idev); kfree(ts); @@ -722,7 +742,12 @@ static int tsc2005_suspend(struct device *dev) struct tsc2005 *ts = spi_get_drvdata(spi); mutex_lock(&ts->mutex); - tsc2005_disable(ts); + + if (!ts->suspended && !ts->disabled && ts->opened) + __tsc2005_disable(ts); + + ts->suspended = true; + mutex_unlock(&ts->mutex); return 0; @@ -734,7 +759,12 @@ static int tsc2005_resume(struct device *dev) struct tsc2005 *ts = spi_get_drvdata(spi); mutex_lock(&ts->mutex); - tsc2005_enable(ts); + + if (ts->suspended && !ts->disabled && ts->opened) + __tsc2005_enable(ts); + + ts->suspended = false; + mutex_unlock(&ts->mutex); return 0; -- cgit v1.2.3 From 5cb81d19bae47adcb073a5e5a3bc40dd252f239e Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 16 Mar 2011 22:11:41 -0700 Subject: Input: tsc2005 - remove 'disable' sysfs attribute I believe that enable/disable functionality should not be implemented on the individual driver level but rather in device core, potentially reusing parts of PM framework. Therefore the driver-specific "disable" attribute is removed from the mainline driver. Tested-by: Aaro Koskinen Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/tsc2005.c | 52 +++---------------------------------- 1 file changed, 4 insertions(+), 48 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/tsc2005.c b/drivers/input/touchscreen/tsc2005.c index 3e1c9c297f33..87420616efa4 100644 --- a/drivers/input/touchscreen/tsc2005.c +++ b/drivers/input/touchscreen/tsc2005.c @@ -138,7 +138,6 @@ struct tsc2005 { unsigned int x_plate_ohm; - bool disabled; bool opened; bool suspended; @@ -365,48 +364,6 @@ static void __tsc2005_enable(struct tsc2005 *ts) } -static ssize_t tsc2005_disable_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct spi_device *spi = to_spi_device(dev); - struct tsc2005 *ts = spi_get_drvdata(spi); - - return sprintf(buf, "%u\n", ts->disabled); -} - -static ssize_t tsc2005_disable_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct spi_device *spi = to_spi_device(dev); - struct tsc2005 *ts = spi_get_drvdata(spi); - unsigned long val; - int error; - - error = strict_strtoul(buf, 10, &val); - if (error) - return error; - - mutex_lock(&ts->mutex); - - if (!ts->suspended && ts->opened) { - if (val) { - if (!ts->disabled) - __tsc2005_disable(ts); - } else { - if (ts->disabled) - __tsc2005_enable(ts); - } - } - - ts->disabled = !!val; - - mutex_unlock(&ts->mutex); - - return count; -} -static DEVICE_ATTR(disable, 0664, tsc2005_disable_show, tsc2005_disable_store); - static ssize_t tsc2005_selftest_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -489,7 +446,6 @@ out: static DEVICE_ATTR(selftest, S_IRUGO, tsc2005_selftest_show, NULL); static struct attribute *tsc2005_attrs[] = { - &dev_attr_disable.attr, &dev_attr_selftest.attr, NULL }; @@ -567,7 +523,7 @@ static int tsc2005_open(struct input_dev *input) mutex_lock(&ts->mutex); - if (!ts->suspended && !ts->disabled) + if (!ts->suspended) __tsc2005_enable(ts); ts->opened = true; @@ -583,7 +539,7 @@ static void tsc2005_close(struct input_dev *input) mutex_lock(&ts->mutex); - if (!ts->suspended && !ts->disabled) + if (!ts->suspended) __tsc2005_disable(ts); ts->opened = false; @@ -743,7 +699,7 @@ static int tsc2005_suspend(struct device *dev) mutex_lock(&ts->mutex); - if (!ts->suspended && !ts->disabled && ts->opened) + if (!ts->suspended && ts->opened) __tsc2005_disable(ts); ts->suspended = true; @@ -760,7 +716,7 @@ static int tsc2005_resume(struct device *dev) mutex_lock(&ts->mutex); - if (ts->suspended && !ts->disabled && ts->opened) + if (ts->suspended && ts->opened) __tsc2005_enable(ts); ts->suspended = false; -- cgit v1.2.3 From 0638d56fbb6cf8367fcf01a1febf6a191b0e0704 Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Thu, 17 Feb 2011 19:07:20 -0800 Subject: mfd: mfd_cell is now implicitly available to twl4030 drivers The cell's platform_data is now accessed with a helper function; change clients to use that, and remove the now-unused data_size. Signed-off-by: Andres Salomon Acked-by: Peter Ujfalusi Signed-off-by: Samuel Ortiz --- drivers/input/misc/twl4030-vibra.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/input') diff --git a/drivers/input/misc/twl4030-vibra.c b/drivers/input/misc/twl4030-vibra.c index 014dd4ad0d4f..6a11694e3fc7 100644 --- a/drivers/input/misc/twl4030-vibra.c +++ b/drivers/input/misc/twl4030-vibra.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -196,7 +197,7 @@ static SIMPLE_DEV_PM_OPS(twl4030_vibra_pm_ops, static int __devinit twl4030_vibra_probe(struct platform_device *pdev) { - struct twl4030_codec_vibra_data *pdata = pdev->dev.platform_data; + struct twl4030_codec_vibra_data *pdata = mfd_get_data(pdev); struct vibra_info *info; int ret; -- cgit v1.2.3 From c9f560b3d0222f6a6e3faeda324e786e230e4f20 Mon Sep 17 00:00:00 2001 From: Haojian Zhuang Date: Mon, 7 Mar 2011 23:43:12 +0800 Subject: mfd: Adopt mfd_data in 88pm860x input driver Copy 88pm860x platform data into different mfd_data structure for onkey/touch/codec/power driver. So move the identification of device node from those drivers to mfd driver. Signed-off-by: Haojian Zhuang Signed-off-by: Samuel Ortiz --- drivers/input/misc/88pm860x_onkey.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/input') diff --git a/drivers/input/misc/88pm860x_onkey.c b/drivers/input/misc/88pm860x_onkey.c index 4cc82826ea6b..3dca3c14510e 100644 --- a/drivers/input/misc/88pm860x_onkey.c +++ b/drivers/input/misc/88pm860x_onkey.c @@ -74,7 +74,7 @@ static int __devinit pm860x_onkey_probe(struct platform_device *pdev) info->chip = chip; info->i2c = (chip->id == CHIP_PM8607) ? chip->client : chip->companion; info->dev = &pdev->dev; - info->irq = irq + chip->irq_base; + info->irq = irq; info->idev = input_allocate_device(); if (!info->idev) { -- cgit v1.2.3 From ddca6a31345cbea8c7c907e6b7e016339cbb6342 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 21 Mar 2011 02:37:07 -0700 Subject: Input: tsc2005 - driver should depend on GENERIC_HARDIRQS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit drivers/input/touchscreen/tsc2005.c: In function ‘tsc2005_probe’: drivers/input/touchscreen/tsc2005.c:666: error: implicit declaration of function ‘set_irq_wake’ In addition, migrate from set_irq_wake() (marked "do not use" as of commit a0cd9ca2b907d7ee26575e7b63ac92dad768a75e ("genirq: Namespace cleanup")) to irq_set_irq_wake(). Signed-off-by: Geert Uytterhoeven Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/Kconfig | 2 +- drivers/input/touchscreen/tsc2005.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 112ec55f2939..434fd800cd24 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -641,7 +641,7 @@ config TOUCHSCREEN_TOUCHIT213 config TOUCHSCREEN_TSC2005 tristate "TSC2005 based touchscreens" - depends on SPI_MASTER + depends on SPI_MASTER && GENERIC_HARDIRQS help Say Y here if you have a TSC2005 based touchscreen. diff --git a/drivers/input/touchscreen/tsc2005.c b/drivers/input/touchscreen/tsc2005.c index 87420616efa4..437b9cdddf82 100644 --- a/drivers/input/touchscreen/tsc2005.c +++ b/drivers/input/touchscreen/tsc2005.c @@ -663,7 +663,7 @@ static int __devinit tsc2005_probe(struct spi_device *spi) goto err_remove_sysfs; } - set_irq_wake(spi->irq, 1); + irq_set_irq_wake(spi->irq, 1); return 0; err_remove_sysfs: -- cgit v1.2.3 From 903427955b9ffe1ca4b76c510089774c3b7a4a8a Mon Sep 17 00:00:00 2001 From: Aaro Koskinen Date: Wed, 23 Mar 2011 23:45:11 -0700 Subject: Input: tsc2005 - use relative jiffies to schedule the watchdog Use relative jiffies to schedule the watchdog. Otherwise it will run like a mad one. Signed-off-by: Aaro Koskinen Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/tsc2005.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/tsc2005.c b/drivers/input/touchscreen/tsc2005.c index 437b9cdddf82..2a9a7260fe8e 100644 --- a/drivers/input/touchscreen/tsc2005.c +++ b/drivers/input/touchscreen/tsc2005.c @@ -358,7 +358,7 @@ static void __tsc2005_enable(struct tsc2005 *ts) if (ts->esd_timeout && ts->set_reset) { ts->last_valid_interrupt = jiffies; schedule_delayed_work(&ts->esd_work, - round_jiffies(jiffies + + round_jiffies_relative( msecs_to_jiffies(ts->esd_timeout))); } @@ -512,7 +512,7 @@ static void tsc2005_esd_work(struct work_struct *work) out: /* re-arm the watchdog */ schedule_delayed_work(&ts->esd_work, - round_jiffies(jiffies + + round_jiffies_relative( msecs_to_jiffies(ts->esd_timeout))); mutex_unlock(&ts->mutex); } -- cgit v1.2.3 From a0fa2206f550066d6948d43c5401e973e5f7d320 Mon Sep 17 00:00:00 2001 From: Aaro Koskinen Date: Wed, 23 Mar 2011 23:48:19 -0700 Subject: Input: tsc2005 - fix locking issue Commit 0b950d3 (Input: tsc2005 - add open/close) introduced a locking issue with the ESD watchdog: __tsc2005_disable() is calling cancel_delayed_work_sync() with mutex held, and the work also needs the same mutex. Fix the problem by using mutex_trylock() in tsc2005_esd_work(). If the mutex is taken, we know we are in the middle of disable or enable and the watchdog check can be skipped. Signed-off-by: Aaro Koskinen Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/tsc2005.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/tsc2005.c b/drivers/input/touchscreen/tsc2005.c index 2a9a7260fe8e..cbf0ff322676 100644 --- a/drivers/input/touchscreen/tsc2005.c +++ b/drivers/input/touchscreen/tsc2005.c @@ -477,7 +477,14 @@ static void tsc2005_esd_work(struct work_struct *work) int error; u16 r; - mutex_lock(&ts->mutex); + if (!mutex_trylock(&ts->mutex)) { + /* + * If the mutex is taken, it means that disable or enable is in + * progress. In that case just reschedule the work. If the work + * is not needed, it will be canceled by disable. + */ + goto reschedule; + } if (time_is_after_jiffies(ts->last_valid_interrupt + msecs_to_jiffies(ts->esd_timeout))) @@ -510,11 +517,12 @@ static void tsc2005_esd_work(struct work_struct *work) tsc2005_start_scan(ts); out: + mutex_unlock(&ts->mutex); +reschedule: /* re-arm the watchdog */ schedule_delayed_work(&ts->esd_work, round_jiffies_relative( msecs_to_jiffies(ts->esd_timeout))); - mutex_unlock(&ts->mutex); } static int tsc2005_open(struct input_dev *input) -- cgit v1.2.3 From 7b824bbdd6210155bac9e1a1d795f94f8f2927b2 Mon Sep 17 00:00:00 2001 From: Ping Cheng Date: Sat, 26 Mar 2011 21:16:04 -0700 Subject: Input: wacom - constify wacom_features for a new missed Bamboo models Signed-off-by: Ping Cheng Signed-off-by: Dmitry Torokhov --- drivers/input/tablet/wacom_wac.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c index 5597637cfd41..ba6e17c5e254 100644 --- a/drivers/input/tablet/wacom_wac.c +++ b/drivers/input/tablet/wacom_wac.c @@ -1366,23 +1366,23 @@ static const struct wacom_features wacom_features_0xE3 = { "Wacom ISDv4 E3", WACOM_PKGLEN_TPC2FG, 26202, 16325, 255, 0, TABLETPC2FG }; static const struct wacom_features wacom_features_0x47 = { "Wacom Intuos2 6x8", WACOM_PKGLEN_INTUOS, 20320, 16240, 1023, 31, INTUOS }; -static struct wacom_features wacom_features_0xD0 = +static const struct wacom_features wacom_features_0xD0 = { "Wacom Bamboo 2FG", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023, 63, BAMBOO_PT }; -static struct wacom_features wacom_features_0xD1 = +static const struct wacom_features wacom_features_0xD1 = { "Wacom Bamboo 2FG 4x5", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023, 63, BAMBOO_PT }; -static struct wacom_features wacom_features_0xD2 = +static const struct wacom_features wacom_features_0xD2 = { "Wacom Bamboo Craft", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023, 63, BAMBOO_PT }; -static struct wacom_features wacom_features_0xD3 = +static const struct wacom_features wacom_features_0xD3 = { "Wacom Bamboo 2FG 6x8", WACOM_PKGLEN_BBFUN, 21648, 13530, 1023, 63, BAMBOO_PT }; static const struct wacom_features wacom_features_0xD4 = { "Wacom Bamboo Pen", WACOM_PKGLEN_BBFUN, 14720, 9200, 255, 63, BAMBOO_PT }; -static struct wacom_features wacom_features_0xD6 = +static const struct wacom_features wacom_features_0xD6 = { "Wacom BambooPT 2FG 4x5", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023, 63, BAMBOO_PT }; -static struct wacom_features wacom_features_0xD7 = +static const struct wacom_features wacom_features_0xD7 = { "Wacom BambooPT 2FG Small", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023, 63, BAMBOO_PT }; -static struct wacom_features wacom_features_0xD8 = +static const struct wacom_features wacom_features_0xD8 = { "Wacom Bamboo Comic 2FG", WACOM_PKGLEN_BBFUN, 21648, 13530, 1023, 63, BAMBOO_PT }; -static struct wacom_features wacom_features_0xDA = +static const struct wacom_features wacom_features_0xDA = { "Wacom Bamboo 2FG 4x5 SE", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023, 63, BAMBOO_PT }; static struct wacom_features wacom_features_0xDB = { "Wacom Bamboo 2FG 6x8 SE", WACOM_PKGLEN_BBFUN, 21648, 13530, 1023, 63, BAMBOO_PT }; -- cgit v1.2.3 From e35fb8c1db2d6fc92783d492e458d19b06502742 Mon Sep 17 00:00:00 2001 From: Ping Cheng Date: Sat, 26 Mar 2011 21:16:05 -0700 Subject: Input: wacom - report resolution for pen devices Touch resolution is reported to the userland by retrieving the value from the HID descriptor. But pen resolution is not since it can not be retrieved. The current Wacom X driver has a resolution table. To centralize the source of these values, the resolution entries are added in the wacom_features struct for x and y coordinates respectively. The values are then reported to the userland. Signed-off-by: Ping Cheng Signed-off-by: Dmitry Torokhov --- drivers/input/tablet/wacom_wac.c | 271 ++++++++++++++++++++++++++------------- drivers/input/tablet/wacom_wac.h | 2 + 2 files changed, 181 insertions(+), 92 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c index ba6e17c5e254..c87d94ff6ae4 100644 --- a/drivers/input/tablet/wacom_wac.c +++ b/drivers/input/tablet/wacom_wac.c @@ -16,6 +16,14 @@ #include "wacom.h" #include +/* resolution for penabled devices */ +#define WACOM_PL_RES 20 +#define WACOM_PENPRTN_RES 40 +#define WACOM_VOLITO_RES 50 +#define WACOM_GRAPHIRE_RES 80 +#define WACOM_INTUOS_RES 100 +#define WACOM_INTUOS3_RES 200 + static int wacom_penpartner_irq(struct wacom_wac *wacom) { unsigned char *data = wacom->data; @@ -1055,6 +1063,19 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev, input_set_abs_params(input_dev, ABS_PRESSURE, 0, features->pressure_max, features->pressure_fuzz, 0); + if (features->device_type == BTN_TOOL_PEN) { + /* penabled devices have fixed resolution for each model */ + input_abs_set_res(input_dev, ABS_X, features->x_resolution); + input_abs_set_res(input_dev, ABS_Y, features->y_resolution); + } else { + input_abs_set_res(input_dev, ABS_X, + wacom_calculate_touch_res(features->x_max, + features->x_phy)); + input_abs_set_res(input_dev, ABS_Y, + wacom_calculate_touch_res(features->y_max, + features->y_phy)); + } + __set_bit(ABS_MISC, input_dev->absbit); switch (wacom_wac->features.type) { @@ -1171,15 +1192,9 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev, case TABLETPC: __clear_bit(ABS_MISC, input_dev->absbit); - if (features->device_type != BTN_TOOL_PEN) { - input_abs_set_res(input_dev, ABS_X, - wacom_calculate_touch_res(features->x_max, - features->x_phy)); - input_abs_set_res(input_dev, ABS_Y, - wacom_calculate_touch_res(features->y_max, - features->y_phy)); + if (features->device_type != BTN_TOOL_PEN) break; /* no need to process stylus stuff */ - } + /* fall through */ case PL: @@ -1216,12 +1231,6 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev, input_set_abs_params(input_dev, ABS_MT_PRESSURE, 0, features->pressure_max, features->pressure_fuzz, 0); - input_abs_set_res(input_dev, ABS_X, - wacom_calculate_touch_res(features->x_max, - features->x_phy)); - input_abs_set_res(input_dev, ABS_Y, - wacom_calculate_touch_res(features->y_max, - features->y_phy)); } else if (features->device_type == BTN_TOOL_PEN) { __set_bit(BTN_TOOL_RUBBER, input_dev->keybit); __set_bit(BTN_TOOL_PEN, input_dev->keybit); @@ -1233,161 +1242,239 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev, } static const struct wacom_features wacom_features_0x00 = - { "Wacom Penpartner", WACOM_PKGLEN_PENPRTN, 5040, 3780, 255, 0, PENPARTNER }; + { "Wacom Penpartner", WACOM_PKGLEN_PENPRTN, 5040, 3780, 255, + 0, PENPARTNER, WACOM_PENPRTN_RES, WACOM_PENPRTN_RES }; static const struct wacom_features wacom_features_0x10 = - { "Wacom Graphire", WACOM_PKGLEN_GRAPHIRE, 10206, 7422, 511, 63, GRAPHIRE }; + { "Wacom Graphire", WACOM_PKGLEN_GRAPHIRE, 10206, 7422, 511, + 63, GRAPHIRE, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES }; static const struct wacom_features wacom_features_0x11 = - { "Wacom Graphire2 4x5", WACOM_PKGLEN_GRAPHIRE, 10206, 7422, 511, 63, GRAPHIRE }; + { "Wacom Graphire2 4x5", WACOM_PKGLEN_GRAPHIRE, 10206, 7422, 511, + 63, GRAPHIRE, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES }; static const struct wacom_features wacom_features_0x12 = - { "Wacom Graphire2 5x7", WACOM_PKGLEN_GRAPHIRE, 13918, 10206, 511, 63, GRAPHIRE }; + { "Wacom Graphire2 5x7", WACOM_PKGLEN_GRAPHIRE, 13918, 10206, 511, + 63, GRAPHIRE, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES }; static const struct wacom_features wacom_features_0x13 = - { "Wacom Graphire3", WACOM_PKGLEN_GRAPHIRE, 10208, 7424, 511, 63, GRAPHIRE }; + { "Wacom Graphire3", WACOM_PKGLEN_GRAPHIRE, 10208, 7424, 511, + 63, GRAPHIRE, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES }; static const struct wacom_features wacom_features_0x14 = - { "Wacom Graphire3 6x8", WACOM_PKGLEN_GRAPHIRE, 16704, 12064, 511, 63, GRAPHIRE }; + { "Wacom Graphire3 6x8", WACOM_PKGLEN_GRAPHIRE, 16704, 12064, 511, + 63, GRAPHIRE, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES }; static const struct wacom_features wacom_features_0x15 = - { "Wacom Graphire4 4x5", WACOM_PKGLEN_GRAPHIRE, 10208, 7424, 511, 63, WACOM_G4 }; + { "Wacom Graphire4 4x5", WACOM_PKGLEN_GRAPHIRE, 10208, 7424, 511, + 63, WACOM_G4, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES }; static const struct wacom_features wacom_features_0x16 = - { "Wacom Graphire4 6x8", WACOM_PKGLEN_GRAPHIRE, 16704, 12064, 511, 63, WACOM_G4 }; + { "Wacom Graphire4 6x8", WACOM_PKGLEN_GRAPHIRE, 16704, 12064, 511, + 63, WACOM_G4, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES }; static const struct wacom_features wacom_features_0x17 = - { "Wacom BambooFun 4x5", WACOM_PKGLEN_BBFUN, 14760, 9225, 511, 63, WACOM_MO }; + { "Wacom BambooFun 4x5", WACOM_PKGLEN_BBFUN, 14760, 9225, 511, + 63, WACOM_MO, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0x18 = - { "Wacom BambooFun 6x8", WACOM_PKGLEN_BBFUN, 21648, 13530, 511, 63, WACOM_MO }; + { "Wacom BambooFun 6x8", WACOM_PKGLEN_BBFUN, 21648, 13530, 511, + 63, WACOM_MO, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0x19 = - { "Wacom Bamboo1 Medium", WACOM_PKGLEN_GRAPHIRE, 16704, 12064, 511, 63, GRAPHIRE }; + { "Wacom Bamboo1 Medium", WACOM_PKGLEN_GRAPHIRE, 16704, 12064, 511, + 63, GRAPHIRE, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES }; static const struct wacom_features wacom_features_0x60 = - { "Wacom Volito", WACOM_PKGLEN_GRAPHIRE, 5104, 3712, 511, 63, GRAPHIRE }; + { "Wacom Volito", WACOM_PKGLEN_GRAPHIRE, 5104, 3712, 511, + 63, GRAPHIRE, WACOM_VOLITO_RES, WACOM_VOLITO_RES }; static const struct wacom_features wacom_features_0x61 = - { "Wacom PenStation2", WACOM_PKGLEN_GRAPHIRE, 3250, 2320, 255, 63, GRAPHIRE }; + { "Wacom PenStation2", WACOM_PKGLEN_GRAPHIRE, 3250, 2320, 255, + 63, GRAPHIRE, WACOM_VOLITO_RES, WACOM_VOLITO_RES }; static const struct wacom_features wacom_features_0x62 = - { "Wacom Volito2 4x5", WACOM_PKGLEN_GRAPHIRE, 5104, 3712, 511, 63, GRAPHIRE }; + { "Wacom Volito2 4x5", WACOM_PKGLEN_GRAPHIRE, 5104, 3712, 511, + 63, GRAPHIRE, WACOM_VOLITO_RES, WACOM_VOLITO_RES }; static const struct wacom_features wacom_features_0x63 = - { "Wacom Volito2 2x3", WACOM_PKGLEN_GRAPHIRE, 3248, 2320, 511, 63, GRAPHIRE }; + { "Wacom Volito2 2x3", WACOM_PKGLEN_GRAPHIRE, 3248, 2320, 511, + 63, GRAPHIRE, WACOM_VOLITO_RES, WACOM_VOLITO_RES }; static const struct wacom_features wacom_features_0x64 = - { "Wacom PenPartner2", WACOM_PKGLEN_GRAPHIRE, 3250, 2320, 511, 63, GRAPHIRE }; + { "Wacom PenPartner2", WACOM_PKGLEN_GRAPHIRE, 3250, 2320, 511, + 63, GRAPHIRE, WACOM_VOLITO_RES, WACOM_VOLITO_RES }; static const struct wacom_features wacom_features_0x65 = - { "Wacom Bamboo", WACOM_PKGLEN_BBFUN, 14760, 9225, 511, 63, WACOM_MO }; + { "Wacom Bamboo", WACOM_PKGLEN_BBFUN, 14760, 9225, 511, + 63, WACOM_MO, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0x69 = - { "Wacom Bamboo1", WACOM_PKGLEN_GRAPHIRE, 5104, 3712, 511, 63, GRAPHIRE }; + { "Wacom Bamboo1", WACOM_PKGLEN_GRAPHIRE, 5104, 3712, 511, + 63, GRAPHIRE, WACOM_PENPRTN_RES, WACOM_PENPRTN_RES }; static const struct wacom_features wacom_features_0x20 = - { "Wacom Intuos 4x5", WACOM_PKGLEN_INTUOS, 12700, 10600, 1023, 31, INTUOS }; + { "Wacom Intuos 4x5", WACOM_PKGLEN_INTUOS, 12700, 10600, 1023, + 31, INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0x21 = - { "Wacom Intuos 6x8", WACOM_PKGLEN_INTUOS, 20320, 16240, 1023, 31, INTUOS }; + { "Wacom Intuos 6x8", WACOM_PKGLEN_INTUOS, 20320, 16240, 1023, + 31, INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0x22 = - { "Wacom Intuos 9x12", WACOM_PKGLEN_INTUOS, 30480, 24060, 1023, 31, INTUOS }; + { "Wacom Intuos 9x12", WACOM_PKGLEN_INTUOS, 30480, 24060, 1023, + 31, INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0x23 = - { "Wacom Intuos 12x12", WACOM_PKGLEN_INTUOS, 30480, 31680, 1023, 31, INTUOS }; + { "Wacom Intuos 12x12", WACOM_PKGLEN_INTUOS, 30480, 31680, 1023, + 31, INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0x24 = - { "Wacom Intuos 12x18", WACOM_PKGLEN_INTUOS, 45720, 31680, 1023, 31, INTUOS }; + { "Wacom Intuos 12x18", WACOM_PKGLEN_INTUOS, 45720, 31680, 1023, + 31, INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0x30 = - { "Wacom PL400", WACOM_PKGLEN_GRAPHIRE, 5408, 4056, 255, 0, PL }; + { "Wacom PL400", WACOM_PKGLEN_GRAPHIRE, 5408, 4056, 255, + 0, PL, WACOM_PL_RES, WACOM_PL_RES }; static const struct wacom_features wacom_features_0x31 = - { "Wacom PL500", WACOM_PKGLEN_GRAPHIRE, 6144, 4608, 255, 0, PL }; + { "Wacom PL500", WACOM_PKGLEN_GRAPHIRE, 6144, 4608, 255, + 0, PL, WACOM_PL_RES, WACOM_PL_RES }; static const struct wacom_features wacom_features_0x32 = - { "Wacom PL600", WACOM_PKGLEN_GRAPHIRE, 6126, 4604, 255, 0, PL }; + { "Wacom PL600", WACOM_PKGLEN_GRAPHIRE, 6126, 4604, 255, + 0, PL, WACOM_PL_RES, WACOM_PL_RES }; static const struct wacom_features wacom_features_0x33 = - { "Wacom PL600SX", WACOM_PKGLEN_GRAPHIRE, 6260, 5016, 255, 0, PL }; + { "Wacom PL600SX", WACOM_PKGLEN_GRAPHIRE, 6260, 5016, 255, + 0, PL, WACOM_PL_RES, WACOM_PL_RES }; static const struct wacom_features wacom_features_0x34 = - { "Wacom PL550", WACOM_PKGLEN_GRAPHIRE, 6144, 4608, 511, 0, PL }; + { "Wacom PL550", WACOM_PKGLEN_GRAPHIRE, 6144, 4608, 511, + 0, PL, WACOM_PL_RES, WACOM_PL_RES }; static const struct wacom_features wacom_features_0x35 = - { "Wacom PL800", WACOM_PKGLEN_GRAPHIRE, 7220, 5780, 511, 0, PL }; + { "Wacom PL800", WACOM_PKGLEN_GRAPHIRE, 7220, 5780, 511, + 0, PL, WACOM_PL_RES, WACOM_PL_RES }; static const struct wacom_features wacom_features_0x37 = - { "Wacom PL700", WACOM_PKGLEN_GRAPHIRE, 6758, 5406, 511, 0, PL }; + { "Wacom PL700", WACOM_PKGLEN_GRAPHIRE, 6758, 5406, 511, + 0, PL, WACOM_PL_RES, WACOM_PL_RES }; static const struct wacom_features wacom_features_0x38 = - { "Wacom PL510", WACOM_PKGLEN_GRAPHIRE, 6282, 4762, 511, 0, PL }; + { "Wacom PL510", WACOM_PKGLEN_GRAPHIRE, 6282, 4762, 511, + 0, PL, WACOM_PL_RES, WACOM_PL_RES }; static const struct wacom_features wacom_features_0x39 = - { "Wacom DTU710", WACOM_PKGLEN_GRAPHIRE, 34080, 27660, 511, 0, PL }; + { "Wacom DTU710", WACOM_PKGLEN_GRAPHIRE, 34080, 27660, 511, + 0, PL, WACOM_PL_RES, WACOM_PL_RES }; static const struct wacom_features wacom_features_0xC4 = - { "Wacom DTF521", WACOM_PKGLEN_GRAPHIRE, 6282, 4762, 511, 0, PL }; + { "Wacom DTF521", WACOM_PKGLEN_GRAPHIRE, 6282, 4762, 511, + 0, PL, WACOM_PL_RES, WACOM_PL_RES }; static const struct wacom_features wacom_features_0xC0 = - { "Wacom DTF720", WACOM_PKGLEN_GRAPHIRE, 6858, 5506, 511, 0, PL }; + { "Wacom DTF720", WACOM_PKGLEN_GRAPHIRE, 6858, 5506, 511, + 0, PL, WACOM_PL_RES, WACOM_PL_RES }; static const struct wacom_features wacom_features_0xC2 = - { "Wacom DTF720a", WACOM_PKGLEN_GRAPHIRE, 6858, 5506, 511, 0, PL }; + { "Wacom DTF720a", WACOM_PKGLEN_GRAPHIRE, 6858, 5506, 511, + 0, PL, WACOM_PL_RES, WACOM_PL_RES }; static const struct wacom_features wacom_features_0x03 = - { "Wacom Cintiq Partner", WACOM_PKGLEN_GRAPHIRE, 20480, 15360, 511, 0, PTU }; + { "Wacom Cintiq Partner", WACOM_PKGLEN_GRAPHIRE, 20480, 15360, 511, + 0, PTU, WACOM_PL_RES, WACOM_PL_RES }; static const struct wacom_features wacom_features_0x41 = - { "Wacom Intuos2 4x5", WACOM_PKGLEN_INTUOS, 12700, 10600, 1023, 31, INTUOS }; + { "Wacom Intuos2 4x5", WACOM_PKGLEN_INTUOS, 12700, 10600, 1023, + 31, INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0x42 = - { "Wacom Intuos2 6x8", WACOM_PKGLEN_INTUOS, 20320, 16240, 1023, 31, INTUOS }; + { "Wacom Intuos2 6x8", WACOM_PKGLEN_INTUOS, 20320, 16240, 1023, + 31, INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0x43 = - { "Wacom Intuos2 9x12", WACOM_PKGLEN_INTUOS, 30480, 24060, 1023, 31, INTUOS }; + { "Wacom Intuos2 9x12", WACOM_PKGLEN_INTUOS, 30480, 24060, 1023, + 31, INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0x44 = - { "Wacom Intuos2 12x12", WACOM_PKGLEN_INTUOS, 30480, 31680, 1023, 31, INTUOS }; + { "Wacom Intuos2 12x12", WACOM_PKGLEN_INTUOS, 30480, 31680, 1023, + 31, INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0x45 = - { "Wacom Intuos2 12x18", WACOM_PKGLEN_INTUOS, 45720, 31680, 1023, 31, INTUOS }; + { "Wacom Intuos2 12x18", WACOM_PKGLEN_INTUOS, 45720, 31680, 1023, + 31, INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0xB0 = - { "Wacom Intuos3 4x5", WACOM_PKGLEN_INTUOS, 25400, 20320, 1023, 63, INTUOS3S }; + { "Wacom Intuos3 4x5", WACOM_PKGLEN_INTUOS, 25400, 20320, 1023, + 63, INTUOS3S, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; static const struct wacom_features wacom_features_0xB1 = - { "Wacom Intuos3 6x8", WACOM_PKGLEN_INTUOS, 40640, 30480, 1023, 63, INTUOS3 }; + { "Wacom Intuos3 6x8", WACOM_PKGLEN_INTUOS, 40640, 30480, 1023, + 63, INTUOS3, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; static const struct wacom_features wacom_features_0xB2 = - { "Wacom Intuos3 9x12", WACOM_PKGLEN_INTUOS, 60960, 45720, 1023, 63, INTUOS3 }; + { "Wacom Intuos3 9x12", WACOM_PKGLEN_INTUOS, 60960, 45720, 1023, + 63, INTUOS3, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; static const struct wacom_features wacom_features_0xB3 = - { "Wacom Intuos3 12x12", WACOM_PKGLEN_INTUOS, 60960, 60960, 1023, 63, INTUOS3L }; + { "Wacom Intuos3 12x12", WACOM_PKGLEN_INTUOS, 60960, 60960, 1023, + 63, INTUOS3L, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; static const struct wacom_features wacom_features_0xB4 = - { "Wacom Intuos3 12x19", WACOM_PKGLEN_INTUOS, 97536, 60960, 1023, 63, INTUOS3L }; + { "Wacom Intuos3 12x19", WACOM_PKGLEN_INTUOS, 97536, 60960, 1023, + 63, INTUOS3L, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; static const struct wacom_features wacom_features_0xB5 = - { "Wacom Intuos3 6x11", WACOM_PKGLEN_INTUOS, 54204, 31750, 1023, 63, INTUOS3 }; + { "Wacom Intuos3 6x11", WACOM_PKGLEN_INTUOS, 54204, 31750, 1023, + 63, INTUOS3, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; static const struct wacom_features wacom_features_0xB7 = - { "Wacom Intuos3 4x6", WACOM_PKGLEN_INTUOS, 31496, 19685, 1023, 63, INTUOS3S }; + { "Wacom Intuos3 4x6", WACOM_PKGLEN_INTUOS, 31496, 19685, 1023, + 63, INTUOS3S, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; static const struct wacom_features wacom_features_0xB8 = - { "Wacom Intuos4 4x6", WACOM_PKGLEN_INTUOS, 31496, 19685, 2047, 63, INTUOS4S }; + { "Wacom Intuos4 4x6", WACOM_PKGLEN_INTUOS, 31496, 19685, 2047, + 63, INTUOS4S, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; static const struct wacom_features wacom_features_0xB9 = - { "Wacom Intuos4 6x9", WACOM_PKGLEN_INTUOS, 44704, 27940, 2047, 63, INTUOS4 }; + { "Wacom Intuos4 6x9", WACOM_PKGLEN_INTUOS, 44704, 27940, 2047, + 63, INTUOS4, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; static const struct wacom_features wacom_features_0xBA = - { "Wacom Intuos4 8x13", WACOM_PKGLEN_INTUOS, 65024, 40640, 2047, 63, INTUOS4L }; + { "Wacom Intuos4 8x13", WACOM_PKGLEN_INTUOS, 65024, 40640, 2047, + 63, INTUOS4L, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; static const struct wacom_features wacom_features_0xBB = - { "Wacom Intuos4 12x19", WACOM_PKGLEN_INTUOS, 97536, 60960, 2047, 63, INTUOS4L }; + { "Wacom Intuos4 12x19", WACOM_PKGLEN_INTUOS, 97536, 60960, 2047, + 63, INTUOS4L, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; static const struct wacom_features wacom_features_0xBC = - { "Wacom Intuos4 WL", WACOM_PKGLEN_INTUOS, 40840, 25400, 2047, 63, INTUOS4 }; + { "Wacom Intuos4 WL", WACOM_PKGLEN_INTUOS, 40840, 25400, 2047, + 63, INTUOS4, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; static const struct wacom_features wacom_features_0x3F = - { "Wacom Cintiq 21UX", WACOM_PKGLEN_INTUOS, 87200, 65600, 1023, 63, CINTIQ }; + { "Wacom Cintiq 21UX", WACOM_PKGLEN_INTUOS, 87200, 65600, 1023, + 63, CINTIQ, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; static const struct wacom_features wacom_features_0xC5 = - { "Wacom Cintiq 20WSX", WACOM_PKGLEN_INTUOS, 86680, 54180, 1023, 63, WACOM_BEE }; + { "Wacom Cintiq 20WSX", WACOM_PKGLEN_INTUOS, 86680, 54180, 1023, + 63, WACOM_BEE, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; static const struct wacom_features wacom_features_0xC6 = - { "Wacom Cintiq 12WX", WACOM_PKGLEN_INTUOS, 53020, 33440, 1023, 63, WACOM_BEE }; + { "Wacom Cintiq 12WX", WACOM_PKGLEN_INTUOS, 53020, 33440, 1023, + 63, WACOM_BEE, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; static const struct wacom_features wacom_features_0xC7 = - { "Wacom DTU1931", WACOM_PKGLEN_GRAPHIRE, 37832, 30305, 511, 0, PL }; + { "Wacom DTU1931", WACOM_PKGLEN_GRAPHIRE, 37832, 30305, 511, + 0, PL, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0xCE = - { "Wacom DTU2231", WACOM_PKGLEN_GRAPHIRE, 47864, 27011, 511, 0, DTU }; + { "Wacom DTU2231", WACOM_PKGLEN_GRAPHIRE, 47864, 27011, 511, + 0, DTU, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0xF0 = - { "Wacom DTU1631", WACOM_PKGLEN_GRAPHIRE, 34623, 19553, 511, 0, DTU }; + { "Wacom DTU1631", WACOM_PKGLEN_GRAPHIRE, 34623, 19553, 511, + 0, DTU, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0xCC = - { "Wacom Cintiq 21UX2", WACOM_PKGLEN_INTUOS, 87200, 65600, 2047, 63, WACOM_21UX2 }; + { "Wacom Cintiq 21UX2", WACOM_PKGLEN_INTUOS, 87200, 65600, 2047, + 63, WACOM_21UX2, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; static const struct wacom_features wacom_features_0x90 = - { "Wacom ISDv4 90", WACOM_PKGLEN_GRAPHIRE, 26202, 16325, 255, 0, TABLETPC }; + { "Wacom ISDv4 90", WACOM_PKGLEN_GRAPHIRE, 26202, 16325, 255, + 0, TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0x93 = - { "Wacom ISDv4 93", WACOM_PKGLEN_GRAPHIRE, 26202, 16325, 255, 0, TABLETPC }; + { "Wacom ISDv4 93", WACOM_PKGLEN_GRAPHIRE, 26202, 16325, 255, + 0, TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0x9A = - { "Wacom ISDv4 9A", WACOM_PKGLEN_GRAPHIRE, 26202, 16325, 255, 0, TABLETPC }; + { "Wacom ISDv4 9A", WACOM_PKGLEN_GRAPHIRE, 26202, 16325, 255, + 0, TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0x9F = - { "Wacom ISDv4 9F", WACOM_PKGLEN_GRAPHIRE, 26202, 16325, 255, 0, TABLETPC }; + { "Wacom ISDv4 9F", WACOM_PKGLEN_GRAPHIRE, 26202, 16325, 255, + 0, TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0xE2 = - { "Wacom ISDv4 E2", WACOM_PKGLEN_TPC2FG, 26202, 16325, 255, 0, TABLETPC2FG }; + { "Wacom ISDv4 E2", WACOM_PKGLEN_TPC2FG, 26202, 16325, 255, + 0, TABLETPC2FG, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0xE3 = - { "Wacom ISDv4 E3", WACOM_PKGLEN_TPC2FG, 26202, 16325, 255, 0, TABLETPC2FG }; + { "Wacom ISDv4 E3", WACOM_PKGLEN_TPC2FG, 26202, 16325, 255, + 0, TABLETPC2FG, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0x47 = - { "Wacom Intuos2 6x8", WACOM_PKGLEN_INTUOS, 20320, 16240, 1023, 31, INTUOS }; + { "Wacom Intuos2 6x8", WACOM_PKGLEN_INTUOS, 20320, 16240, 1023, + 31, INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0xD0 = - { "Wacom Bamboo 2FG", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023, 63, BAMBOO_PT }; + { "Wacom Bamboo 2FG", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023, + 63, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0xD1 = - { "Wacom Bamboo 2FG 4x5", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023, 63, BAMBOO_PT }; + { "Wacom Bamboo 2FG 4x5", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023, + 63, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0xD2 = - { "Wacom Bamboo Craft", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023, 63, BAMBOO_PT }; + { "Wacom Bamboo Craft", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023, + 63, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0xD3 = - { "Wacom Bamboo 2FG 6x8", WACOM_PKGLEN_BBFUN, 21648, 13530, 1023, 63, BAMBOO_PT }; + { "Wacom Bamboo 2FG 6x8", WACOM_PKGLEN_BBFUN, 21648, 13530, 1023, + 63, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0xD4 = - { "Wacom Bamboo Pen", WACOM_PKGLEN_BBFUN, 14720, 9200, 255, 63, BAMBOO_PT }; + { "Wacom Bamboo Pen", WACOM_PKGLEN_BBFUN, 14720, 9200, 255, + 63, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0xD6 = - { "Wacom BambooPT 2FG 4x5", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023, 63, BAMBOO_PT }; + { "Wacom BambooPT 2FG 4x5", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023, + 63, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0xD7 = - { "Wacom BambooPT 2FG Small", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023, 63, BAMBOO_PT }; + { "Wacom BambooPT 2FG Small", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023, + 63, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0xD8 = - { "Wacom Bamboo Comic 2FG", WACOM_PKGLEN_BBFUN, 21648, 13530, 1023, 63, BAMBOO_PT }; + { "Wacom Bamboo Comic 2FG", WACOM_PKGLEN_BBFUN, 21648, 13530, 1023, + 63, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0xDA = - { "Wacom Bamboo 2FG 4x5 SE", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023, 63, BAMBOO_PT }; + { "Wacom Bamboo 2FG 4x5 SE", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023, + 63, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static struct wacom_features wacom_features_0xDB = - { "Wacom Bamboo 2FG 6x8 SE", WACOM_PKGLEN_BBFUN, 21648, 13530, 1023, 63, BAMBOO_PT }; + { "Wacom Bamboo 2FG 6x8 SE", WACOM_PKGLEN_BBFUN, 21648, 13530, 1023, + 63, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0x6004 = - { "ISD-V4", WACOM_PKGLEN_GRAPHIRE, 12800, 8000, 255, 0, TABLETPC }; + { "ISD-V4", WACOM_PKGLEN_GRAPHIRE, 12800, 8000, 255, + 0, TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; #define USB_DEVICE_WACOM(prod) \ USB_DEVICE(USB_VENDOR_ID_WACOM, prod), \ diff --git a/drivers/input/tablet/wacom_wac.h b/drivers/input/tablet/wacom_wac.h index 835f756b150c..53eb71b68330 100644 --- a/drivers/input/tablet/wacom_wac.h +++ b/drivers/input/tablet/wacom_wac.h @@ -74,6 +74,8 @@ struct wacom_features { int pressure_max; int distance_max; int type; + int x_resolution; + int y_resolution; int device_type; int x_phy; int y_phy; -- cgit v1.2.3 From d51ca07634b8a441f731e087e93775a67d629a8c Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Sat, 26 Mar 2011 22:52:25 -0700 Subject: Input: h3600_ts_input - fix a spelling error Signed-off-by: Sylvestre Ledru Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/h3600_ts_input.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/h3600_ts_input.c b/drivers/input/touchscreen/h3600_ts_input.c index b4d7f63deff1..efa06882de00 100644 --- a/drivers/input/touchscreen/h3600_ts_input.c +++ b/drivers/input/touchscreen/h3600_ts_input.c @@ -62,7 +62,7 @@ MODULE_LICENSE("GPL"); Programmer has no control over these numbers. TODO there are holes - specifically 1,7,0x0a */ -#define VERSION_ID 0 /* Get Version (request/respose) */ +#define VERSION_ID 0 /* Get Version (request/response) */ #define KEYBD_ID 2 /* Keyboard (event) */ #define TOUCHS_ID 3 /* Touch Screen (event)*/ #define EEPROM_READ_ID 4 /* (request/response) */ -- cgit v1.2.3 From f3cf5c4fedbe13880cd80a9fa1aebae79ebef20e Mon Sep 17 00:00:00 2001 From: Seth Forshee Date: Sat, 26 Mar 2011 22:53:34 -0700 Subject: Input: sparse-keymap - report scancodes with key events Scancodes are useful debugging aids when incorrect keycodes are being sent, as is common with laptop hotkeys. Signed-off-by: Seth Forshee Signed-off-by: Dmitry Torokhov --- drivers/input/sparse-keymap.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/input') diff --git a/drivers/input/sparse-keymap.c b/drivers/input/sparse-keymap.c index 337bf51bc984..74bca5d2f6dc 100644 --- a/drivers/input/sparse-keymap.c +++ b/drivers/input/sparse-keymap.c @@ -208,6 +208,11 @@ int sparse_keymap_setup(struct input_dev *dev, } } + if (test_bit(EV_KEY, dev->evbit)) { + __set_bit(EV_MSC, dev->evbit); + __set_bit(MSC_SCAN, dev->mscbit); + } + dev->keycode = map; dev->keycodemax = map_size; dev->getkeycode = sparse_keymap_getkeycode; @@ -268,6 +273,7 @@ void sparse_keymap_report_entry(struct input_dev *dev, const struct key_entry *k { switch (ke->type) { case KE_KEY: + input_event(dev, EV_MSC, MSC_SCAN, ke->code); input_report_key(dev, ke->keycode, value); input_sync(dev); if (value && autorelease) { -- cgit v1.2.3 From 170531bae648c0ef8d56b44dc5bd8d67717b0db9 Mon Sep 17 00:00:00 2001 From: Seth Forshee Date: Sat, 26 Mar 2011 22:53:34 -0700 Subject: Input: sparse-keymap - report KEY_UNKNOWN for unknown scan codes This allows for debugging non-functional keys easily from userspace. Signed-off-by: Seth Forshee Signed-off-by: Dmitry Torokhov --- drivers/input/sparse-keymap.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers/input') diff --git a/drivers/input/sparse-keymap.c b/drivers/input/sparse-keymap.c index 74bca5d2f6dc..fdb6a3976f94 100644 --- a/drivers/input/sparse-keymap.c +++ b/drivers/input/sparse-keymap.c @@ -209,6 +209,7 @@ int sparse_keymap_setup(struct input_dev *dev, } if (test_bit(EV_KEY, dev->evbit)) { + __set_bit(KEY_UNKNOWN, dev->keybit); __set_bit(EV_MSC, dev->evbit); __set_bit(MSC_SCAN, dev->mscbit); } @@ -311,12 +312,19 @@ bool sparse_keymap_report_event(struct input_dev *dev, unsigned int code, { const struct key_entry *ke = sparse_keymap_entry_from_scancode(dev, code); + struct key_entry unknown_ke; if (ke) { sparse_keymap_report_entry(dev, ke, value, autorelease); return true; } + /* Report an unknown key event as a debugging aid */ + unknown_ke.type = KE_KEY; + unknown_ke.code = code; + unknown_ke.keycode = KEY_UNKNOWN; + sparse_keymap_report_entry(dev, &unknown_ke, value, true); + return false; } EXPORT_SYMBOL(sparse_keymap_report_event); -- cgit v1.2.3 From dced35aeb0367dda2636ee9ee914bda14510dcc9 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 28 Mar 2011 17:49:12 +0200 Subject: drivers: Final irq namespace conversion Scripted with coccinelle. Signed-off-by: Thomas Gleixner --- drivers/input/keyboard/lm8323.c | 4 ++-- drivers/input/serio/ams_delta_serio.c | 2 +- drivers/input/touchscreen/mainstone-wm97xx.c | 2 +- drivers/input/touchscreen/zylonite-wm97xx.c | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/keyboard/lm8323.c b/drivers/input/keyboard/lm8323.c index b732870ecc89..71f744a8e686 100644 --- a/drivers/input/keyboard/lm8323.c +++ b/drivers/input/keyboard/lm8323.c @@ -809,7 +809,7 @@ static int lm8323_suspend(struct device *dev) struct lm8323_chip *lm = i2c_get_clientdata(client); int i; - set_irq_wake(client->irq, 0); + irq_set_irq_wake(client->irq, 0); disable_irq(client->irq); mutex_lock(&lm->lock); @@ -838,7 +838,7 @@ static int lm8323_resume(struct device *dev) led_classdev_resume(&lm->pwm[i].cdev); enable_irq(client->irq); - set_irq_wake(client->irq, 1); + irq_set_irq_wake(client->irq, 1); return 0; } diff --git a/drivers/input/serio/ams_delta_serio.c b/drivers/input/serio/ams_delta_serio.c index ebe955325677..4b2a42f9f0bb 100644 --- a/drivers/input/serio/ams_delta_serio.c +++ b/drivers/input/serio/ams_delta_serio.c @@ -149,7 +149,7 @@ static int __init ams_delta_serio_init(void) * at FIQ level, switch back from edge to simple interrupt handler * to avoid bad interaction. */ - set_irq_handler(gpio_to_irq(AMS_DELTA_GPIO_PIN_KEYBRD_CLK), + irq_set_handler(gpio_to_irq(AMS_DELTA_GPIO_PIN_KEYBRD_CLK), handle_simple_irq); serio_register_port(ams_delta_serio); diff --git a/drivers/input/touchscreen/mainstone-wm97xx.c b/drivers/input/touchscreen/mainstone-wm97xx.c index b6b8b1c7ecea..3242e7076258 100644 --- a/drivers/input/touchscreen/mainstone-wm97xx.c +++ b/drivers/input/touchscreen/mainstone-wm97xx.c @@ -219,7 +219,7 @@ static int wm97xx_acc_startup(struct wm97xx *wm) } wm->pen_irq = gpio_to_irq(irq); - set_irq_type(wm->pen_irq, IRQ_TYPE_EDGE_BOTH); + irq_set_irq_type(wm->pen_irq, IRQ_TYPE_EDGE_BOTH); } else /* pen irq not supported */ pen_int = 0; diff --git a/drivers/input/touchscreen/zylonite-wm97xx.c b/drivers/input/touchscreen/zylonite-wm97xx.c index 048849867643..5b0f15ec874a 100644 --- a/drivers/input/touchscreen/zylonite-wm97xx.c +++ b/drivers/input/touchscreen/zylonite-wm97xx.c @@ -193,7 +193,7 @@ static int zylonite_wm97xx_probe(struct platform_device *pdev) gpio_touch_irq = mfp_to_gpio(MFP_PIN_GPIO26); wm->pen_irq = IRQ_GPIO(gpio_touch_irq); - set_irq_type(IRQ_GPIO(gpio_touch_irq), IRQ_TYPE_EDGE_BOTH); + irq_set_irq_type(IRQ_GPIO(gpio_touch_irq), IRQ_TYPE_EDGE_BOTH); wm97xx_config_gpio(wm, WM97XX_GPIO_13, WM97XX_GPIO_IN, WM97XX_GPIO_POL_HIGH, -- cgit v1.2.3 From a718d79cc0e0c2f0aa82ba2c54383a18f15b7738 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Wed, 30 Mar 2011 22:25:34 -0700 Subject: Input: uinput - allow for 0/0 min/max on absolute axes. Some devices provide absolute axes with min/max of 0/0 (e.g. wacom's ABS_MISC axis). Current uinput restrictions do not allow duplication of these devices and require hacks in userspace to work around this. If the kernel accepts physical devices with a min/max of 0/0, uinput shouldn't disallow the same range. Signed-off-by: Peter Hutterer Signed-off-by: Dmitry Torokhov --- drivers/input/misc/uinput.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers/input') diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c index 364bdf43a381..736056897e50 100644 --- a/drivers/input/misc/uinput.c +++ b/drivers/input/misc/uinput.c @@ -302,10 +302,14 @@ static int uinput_validate_absbits(struct input_dev *dev) int retval = 0; for (cnt = 0; cnt < ABS_CNT; cnt++) { + int min, max; if (!test_bit(cnt, dev->absbit)) continue; - if (input_abs_get_max(dev, cnt) <= input_abs_get_min(dev, cnt)) { + min = input_abs_get_min(dev, cnt); + max = input_abs_get_max(dev, cnt); + + if ((min != 0 || max != 0) && max <= min) { printk(KERN_DEBUG "%s: invalid abs[%02x] min:%d max:%d\n", UINPUT_NAME, cnt, -- cgit v1.2.3 From 799a2a215ed7f9398a8d528767e64b8e39904105 Mon Sep 17 00:00:00 2001 From: Rajeev Kumar Date: Wed, 30 Mar 2011 22:33:42 -0700 Subject: Input: spear-keyboard - fix inverted condition in interrupt handler We should return IRQ_NONE from interrupt handler in case keyboard does not report DATA_AVAIL condition. Signed-off-by: Rajeev Kumar Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/spear-keyboard.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/input') diff --git a/drivers/input/keyboard/spear-keyboard.c b/drivers/input/keyboard/spear-keyboard.c index bee03d64c453..d712dffd2157 100644 --- a/drivers/input/keyboard/spear-keyboard.c +++ b/drivers/input/keyboard/spear-keyboard.c @@ -69,7 +69,7 @@ static irqreturn_t spear_kbd_interrupt(int irq, void *dev_id) u8 sts, val; sts = readb(kbd->io_base + STATUS_REG); - if (sts & DATA_AVAIL) + if (!(sts & DATA_AVAIL)) return IRQ_NONE; if (kbd->last_key != KEY_RESERVED) { -- cgit v1.2.3 From 708748670c7c6dd5bd3b141473086e6937e72737 Mon Sep 17 00:00:00 2001 From: Jan Beulich Date: Thu, 31 Mar 2011 00:01:58 -0700 Subject: Input: synaptics - fix crash in synaptics_module_init() 'struct dmi_system_id' arrays must always have a terminator to keep dmi_check_system() from looking at data (and possibly crashing) it isn't supposed to look at. The issue went unnoticed until ef8313bb1a22e7d2125d9d758aa8a81f1de91d81, but was introduced about a year earlier with 7705d548cbe33f18ea7713b9a07aa11047aaeca4 (which also similarly changed lifebook.c, but the problem there got eliminated shortly afterwards). The first hunk therefore is a stable candidate back to 2.6.33, while the full change is needed only on 2.6.38. Signed-off-by: Jan Beulich Cc: stable@kernel.org Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/synaptics.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index aa186cf6c514..e06e045bf907 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c @@ -836,8 +836,8 @@ static const struct dmi_system_id __initconst toshiba_dmi_table[] = { }, }, - { } #endif + { } }; static bool broken_olpc_ec; @@ -851,8 +851,8 @@ static const struct dmi_system_id __initconst olpc_dmi_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "XO"), }, }, - { } #endif + { } }; void __init synaptics_module_init(void) -- cgit v1.2.3 From a2a94e7323dad972f23b9000cab150026c929b9f Mon Sep 17 00:00:00 2001 From: Paul Bolle Date: Thu, 31 Mar 2011 00:11:48 -0700 Subject: Input: i8042 - downgrade selftest error message to dbg() On a "really fragile" laptop I noticed a single i8042.c: i8042 controller selftest failed. (0x1 != 0x55) error in the log. But there's no reason to print this message at KERN_ERR level each time that loop fails, especially since the message telling about the overall selftest failure is printed at KERN_INFO level (on X86). Add an actual error message for non-X86 systems, where a selftest failure is (apparently) more serious. Remove a space in an another error message. Signed-off-by: Paul Bolle Signed-off-by: Dmitry Torokhov --- drivers/input/serio/i8042.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c index ac4c93689ab9..d37a48e099d0 100644 --- a/drivers/input/serio/i8042.c +++ b/drivers/input/serio/i8042.c @@ -869,15 +869,15 @@ static int i8042_controller_selftest(void) do { if (i8042_command(¶m, I8042_CMD_CTL_TEST)) { - pr_err("i8042 controller self test timeout\n"); + pr_err("i8042 controller selftest timeout\n"); return -ENODEV; } if (param == I8042_RET_CTL_TEST) return 0; - pr_err("i8042 controller selftest failed. (%#x != %#x)\n", - param, I8042_RET_CTL_TEST); + dbg("i8042 controller selftest: %#x != %#x\n", + param, I8042_RET_CTL_TEST); msleep(50); } while (i++ < 5); @@ -891,6 +891,7 @@ static int i8042_controller_selftest(void) pr_info("giving up on controller selftest, continuing anyway...\n"); return 0; #else + pr_err("i8042 controller selftest failed\n"); return -EIO; #endif } -- cgit v1.2.3 From 25985edcedea6396277003854657b5f3cb31a628 Mon Sep 17 00:00:00 2001 From: Lucas De Marchi Date: Wed, 30 Mar 2011 22:57:33 -0300 Subject: Fix common misspellings Fixes generated by 'codespell' and manually reviewed. Signed-off-by: Lucas De Marchi --- drivers/input/joydev.c | 4 ++-- drivers/input/joystick/a3d.c | 4 ++-- drivers/input/keyboard/davinci_keyscan.c | 2 +- drivers/input/misc/adxl34x.c | 2 +- drivers/input/misc/keyspan_remote.c | 2 +- drivers/input/misc/wistron_btns.c | 2 +- drivers/input/mouse/bcm5974.c | 2 +- drivers/input/mouse/synaptics_i2c.c | 2 +- drivers/input/mouse/vsxxxaa.c | 2 +- drivers/input/serio/hp_sdc.c | 2 +- drivers/input/serio/xilinx_ps2.c | 2 +- drivers/input/touchscreen/intel-mid-touch.c | 2 +- drivers/input/touchscreen/ucb1400_ts.c | 2 +- drivers/input/touchscreen/wm9705.c | 2 +- drivers/input/touchscreen/wm9712.c | 2 +- drivers/input/touchscreen/wm9713.c | 2 +- drivers/input/touchscreen/wm97xx-core.c | 4 ++-- 17 files changed, 20 insertions(+), 20 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c index 3182c9cd1b0e..5688b5c88f24 100644 --- a/drivers/input/joydev.c +++ b/drivers/input/joydev.c @@ -758,7 +758,7 @@ static void joydev_remove_chrdev(struct joydev *joydev) } /* - * Mark device non-existant. This disables writes, ioctls and + * Mark device non-existent. This disables writes, ioctls and * prevents new users from opening the device. Already posted * blocking reads will stay, however new ones will fail. */ @@ -777,7 +777,7 @@ static void joydev_cleanup(struct joydev *joydev) joydev_hangup(joydev); joydev_remove_chrdev(joydev); - /* joydev is marked dead so noone else accesses joydev->open */ + /* joydev is marked dead so no one else accesses joydev->open */ if (joydev->open) input_close_device(handle); } diff --git a/drivers/input/joystick/a3d.c b/drivers/input/joystick/a3d.c index d259b41354b8..1639ab2b94b7 100644 --- a/drivers/input/joystick/a3d.c +++ b/drivers/input/joystick/a3d.c @@ -3,7 +3,7 @@ */ /* - * FP-Gaming Assasin 3D joystick driver for Linux + * FP-Gaming Assassin 3D joystick driver for Linux */ /* @@ -34,7 +34,7 @@ #include #include -#define DRIVER_DESC "FP-Gaming Assasin 3D joystick driver" +#define DRIVER_DESC "FP-Gaming Assassin 3D joystick driver" MODULE_AUTHOR("Vojtech Pavlik "); MODULE_DESCRIPTION(DRIVER_DESC); diff --git a/drivers/input/keyboard/davinci_keyscan.c b/drivers/input/keyboard/davinci_keyscan.c index a91ee941b5c1..cd89d17162a3 100644 --- a/drivers/input/keyboard/davinci_keyscan.c +++ b/drivers/input/keyboard/davinci_keyscan.c @@ -5,7 +5,7 @@ * * Author: Miguel Aguilar * - * Intial Code: Sandeep Paulraj + * Initial Code: Sandeep Paulraj * * 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 diff --git a/drivers/input/misc/adxl34x.c b/drivers/input/misc/adxl34x.c index de5900d50788..144ddbdeb9b3 100644 --- a/drivers/input/misc/adxl34x.c +++ b/drivers/input/misc/adxl34x.c @@ -716,7 +716,7 @@ struct adxl34x *adxl34x_probe(struct device *dev, int irq, pdata = dev->platform_data; if (!pdata) { dev_dbg(dev, - "No platfrom data: Using default initialization\n"); + "No platform data: Using default initialization\n"); pdata = &adxl34x_default_init; } diff --git a/drivers/input/misc/keyspan_remote.c b/drivers/input/misc/keyspan_remote.c index a93c525475c6..fc62256c963f 100644 --- a/drivers/input/misc/keyspan_remote.c +++ b/drivers/input/misc/keyspan_remote.c @@ -312,7 +312,7 @@ static void keyspan_check_data(struct usb_keyspan *remote) remote->data.tester = remote->data.tester >> 5; remote->data.bits_left -= 5; } else { - err("Bad message recieved, no stop bit found.\n"); + err("Bad message received, no stop bit found.\n"); } dev_dbg(&remote->udev->dev, diff --git a/drivers/input/misc/wistron_btns.c b/drivers/input/misc/wistron_btns.c index 12501de0c5cd..52b419348983 100644 --- a/drivers/input/misc/wistron_btns.c +++ b/drivers/input/misc/wistron_btns.c @@ -274,7 +274,7 @@ static struct key_entry keymap_fs_amilo_pro_v3505[] __initdata = { { KE_BLUETOOTH, 0x30 }, /* Fn+F10 */ { KE_KEY, 0x31, {KEY_MAIL} }, /* mail button */ { KE_KEY, 0x36, {KEY_WWW} }, /* www button */ - { KE_WIFI, 0x78 }, /* satelite dish button */ + { KE_WIFI, 0x78 }, /* satellite dish button */ { KE_END, 0 } }; diff --git a/drivers/input/mouse/bcm5974.c b/drivers/input/mouse/bcm5974.c index 3aead91bacc8..3126983c004a 100644 --- a/drivers/input/mouse/bcm5974.c +++ b/drivers/input/mouse/bcm5974.c @@ -639,7 +639,7 @@ exit: * device, resulting in trackpad malfunction under certain * circumstances. To get around this problem, there is at least one * example that utilizes the USB_QUIRK_RESET_RESUME quirk in order to - * recieve a reset_resume request rather than the normal resume. + * receive a reset_resume request rather than the normal resume. * Since the implementation of reset_resume is equal to mode switch * plus start_traffic, it seems easier to always do the switch when * starting traffic on the device. diff --git a/drivers/input/mouse/synaptics_i2c.c b/drivers/input/mouse/synaptics_i2c.c index f6aa26d305ed..cba3c84d2f21 100644 --- a/drivers/input/mouse/synaptics_i2c.c +++ b/drivers/input/mouse/synaptics_i2c.c @@ -462,7 +462,7 @@ static void synaptics_i2c_work_handler(struct work_struct *work) * While interrupt driven, there is no real need to poll the device. * But touchpads are very sensitive, so there could be errors * related to physical environment and the attention line isn't - * neccesarily asserted. In such case we can lose the touchpad. + * necessarily asserted. In such case we can lose the touchpad. * We poll the device once in THREAD_IRQ_SLEEP_SECS and * if error is detected, we try to reset and reconfigure the touchpad. */ diff --git a/drivers/input/mouse/vsxxxaa.c b/drivers/input/mouse/vsxxxaa.c index bf2c0c80d6cc..eb9a3cfbeefa 100644 --- a/drivers/input/mouse/vsxxxaa.c +++ b/drivers/input/mouse/vsxxxaa.c @@ -334,7 +334,7 @@ static void vsxxxaa_handle_POR_packet(struct vsxxxaa *mouse) * M: manufacturer location code * R: revision code * E: Error code. If it's in the range of 0x00..0x1f, only some - * minor problem occured. Errors >= 0x20 are considered bad + * minor problem occurred. Errors >= 0x20 are considered bad * and the device may not work properly... * D: <0010> == mouse, <0100> == tablet */ diff --git a/drivers/input/serio/hp_sdc.c b/drivers/input/serio/hp_sdc.c index 8c0b51c31424..42206205e4f5 100644 --- a/drivers/input/serio/hp_sdc.c +++ b/drivers/input/serio/hp_sdc.c @@ -955,7 +955,7 @@ static int __init hp_sdc_init_hppa(struct parisc_device *d) INIT_DELAYED_WORK(&moduleloader_work, request_module_delayed); ret = hp_sdc_init(); - /* after successfull initialization give SDC some time to settle + /* after successful initialization give SDC some time to settle * and then load the hp_sdc_mlc upper layer driver */ if (!ret) schedule_delayed_work(&moduleloader_work, diff --git a/drivers/input/serio/xilinx_ps2.c b/drivers/input/serio/xilinx_ps2.c index 7540bafc95cf..80baa53da5b1 100644 --- a/drivers/input/serio/xilinx_ps2.c +++ b/drivers/input/serio/xilinx_ps2.c @@ -225,7 +225,7 @@ static void sxps2_close(struct serio *pserio) /** * xps2_of_probe - probe method for the PS/2 device. * @of_dev: pointer to OF device structure - * @match: pointer to the stucture used for matching a device + * @match: pointer to the structure used for matching a device * * This function probes the PS/2 device in the device tree. * It initializes the driver data structure and the hardware. diff --git a/drivers/input/touchscreen/intel-mid-touch.c b/drivers/input/touchscreen/intel-mid-touch.c index c0307b22d86f..66c96bfc5522 100644 --- a/drivers/input/touchscreen/intel-mid-touch.c +++ b/drivers/input/touchscreen/intel-mid-touch.c @@ -542,7 +542,7 @@ static int __devinit mrstouch_adc_init(struct mrstouch_dev *tsdev) * ADC power on, start, enable PENDET and set loop delay * ADC loop delay is set to 4.5 ms approximately * Loop delay more than this results in jitter in adc readings - * Setting loop delay to 0 (continous loop) in MAXIM stops PENDET + * Setting loop delay to 0 (continuous loop) in MAXIM stops PENDET * interrupt generation sometimes. */ diff --git a/drivers/input/touchscreen/ucb1400_ts.c b/drivers/input/touchscreen/ucb1400_ts.c index 028a5363eea1..3b5b5df04dd6 100644 --- a/drivers/input/touchscreen/ucb1400_ts.c +++ b/drivers/input/touchscreen/ucb1400_ts.c @@ -6,7 +6,7 @@ * Copyright: MontaVista Software, Inc. * * Spliting done by: Marek Vasut - * If something doesnt work and it worked before spliting, e-mail me, + * If something doesn't work and it worked before spliting, e-mail me, * dont bother Nicolas please ;-) * * This program is free software; you can redistribute it and/or modify diff --git a/drivers/input/touchscreen/wm9705.c b/drivers/input/touchscreen/wm9705.c index 6b5be742c27d..98e61175d3f5 100644 --- a/drivers/input/touchscreen/wm9705.c +++ b/drivers/input/touchscreen/wm9705.c @@ -306,7 +306,7 @@ static int wm9705_acc_enable(struct wm97xx *wm, int enable) dig2 = wm->dig[2]; if (enable) { - /* continous mode */ + /* continuous mode */ if (wm->mach_ops->acc_startup && (ret = wm->mach_ops->acc_startup(wm)) < 0) return ret; diff --git a/drivers/input/touchscreen/wm9712.c b/drivers/input/touchscreen/wm9712.c index 7490b05c3566..2bc2fb801009 100644 --- a/drivers/input/touchscreen/wm9712.c +++ b/drivers/input/touchscreen/wm9712.c @@ -419,7 +419,7 @@ static int wm9712_acc_enable(struct wm97xx *wm, int enable) dig2 = wm->dig[2]; if (enable) { - /* continous mode */ + /* continuous mode */ if (wm->mach_ops->acc_startup) { ret = wm->mach_ops->acc_startup(wm); if (ret < 0) diff --git a/drivers/input/touchscreen/wm9713.c b/drivers/input/touchscreen/wm9713.c index 238b5132712e..73ec99568f12 100644 --- a/drivers/input/touchscreen/wm9713.c +++ b/drivers/input/touchscreen/wm9713.c @@ -431,7 +431,7 @@ static int wm9713_acc_enable(struct wm97xx *wm, int enable) dig3 = wm->dig[2]; if (enable) { - /* continous mode */ + /* continuous mode */ if (wm->mach_ops->acc_startup && (ret = wm->mach_ops->acc_startup(wm)) < 0) return ret; diff --git a/drivers/input/touchscreen/wm97xx-core.c b/drivers/input/touchscreen/wm97xx-core.c index 6b75c9f660ae..5dbe73af2f8f 100644 --- a/drivers/input/touchscreen/wm97xx-core.c +++ b/drivers/input/touchscreen/wm97xx-core.c @@ -335,7 +335,7 @@ static void wm97xx_pen_irq_worker(struct work_struct *work) */ if (!wm->mach_ops->acc_enabled || wm->mach_ops->acc_pen_down) { if (wm->pen_is_down && !pen_was_down) { - /* Data is not availiable immediately on pen down */ + /* Data is not available immediately on pen down */ queue_delayed_work(wm->ts_workq, &wm->ts_reader, 1); } @@ -354,7 +354,7 @@ static void wm97xx_pen_irq_worker(struct work_struct *work) * Codec PENDOWN irq handler * * We have to disable the codec interrupt in the handler because it - * can take upto 1ms to clear the interrupt source. We schedule a task + * can take up to 1ms to clear the interrupt source. We schedule a task * in a work queue to do the actual interaction with the chip. The * interrupt is then enabled again in the slow handler when the source * has been cleared. -- cgit v1.2.3 From 26fcd2a7618db6c16be6aa3e56c0f3c25381e5a3 Mon Sep 17 00:00:00 2001 From: Manoj Iyer Date: Thu, 31 Mar 2011 22:39:43 -0700 Subject: Input: wacom - add support for Lenovo tablet ID (0xE6) Signed-off-by: Manoj Iyer Acked-by: Ping Cheng Signed-off-by: Dmitry Torokhov --- drivers/input/tablet/wacom_wac.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/input') diff --git a/drivers/input/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c index c87d94ff6ae4..08ba5ad9c9be 100644 --- a/drivers/input/tablet/wacom_wac.c +++ b/drivers/input/tablet/wacom_wac.c @@ -1439,6 +1439,9 @@ static const struct wacom_features wacom_features_0xE2 = static const struct wacom_features wacom_features_0xE3 = { "Wacom ISDv4 E3", WACOM_PKGLEN_TPC2FG, 26202, 16325, 255, 0, TABLETPC2FG, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; +static const struct wacom_features wacom_features_0xE6 = + { "Wacom ISDv4 E6", WACOM_PKGLEN_TPC2FG, 27760, 15694, 255, + 0, TABLETPC2FG, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0x47 = { "Wacom Intuos2 6x8", WACOM_PKGLEN_INTUOS, 20320, 16240, 1023, 31, INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; @@ -1561,6 +1564,7 @@ const struct usb_device_id wacom_ids[] = { { USB_DEVICE_WACOM(0x9F) }, { USB_DEVICE_WACOM(0xE2) }, { USB_DEVICE_WACOM(0xE3) }, + { USB_DEVICE_WACOM(0xE6) }, { USB_DEVICE_WACOM(0x47) }, { USB_DEVICE_LENOVO(0x6004) }, { } -- cgit v1.2.3 From e28e1d93e9591d21e440f5210a9b4317c59445df Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sat, 2 Apr 2011 21:20:24 -0700 Subject: Input: rpckbd - fix a leak of the IRQ during init failure In rpckbd_open prror path, free_irq() was using NULL rather than the driver data as the data pointer so free_irq() wouldn't have matched. Signed-off-by: Axel Lin Signed-off-by: Dmitry Torokhov --- drivers/input/serio/rpckbd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/input') diff --git a/drivers/input/serio/rpckbd.c b/drivers/input/serio/rpckbd.c index 9da6fbcaaa7e..7ec3c97dc1b9 100644 --- a/drivers/input/serio/rpckbd.c +++ b/drivers/input/serio/rpckbd.c @@ -90,7 +90,7 @@ static int rpckbd_open(struct serio *port) if (request_irq(IRQ_KEYBOARDTX, rpckbd_tx, 0, "rpckbd", port) != 0) { printk(KERN_ERR "rpckbd.c: Could not allocate keyboard transmit IRQ\n"); - free_irq(IRQ_KEYBOARDRX, NULL); + free_irq(IRQ_KEYBOARDRX, port); return -EBUSY; } -- cgit v1.2.3 From 8f74c0661c42104b3e3d2c032bc61efde15360ad Mon Sep 17 00:00:00 2001 From: Shubhrajyoti D Date: Wed, 6 Apr 2011 15:31:22 -0700 Subject: Input: twl4030_keypad - avoid potential NULL-pointer dereference Signed-off-by: Shubhrajyoti D Acked-by: Axel Lin Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/twl4030_keypad.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/input') diff --git a/drivers/input/keyboard/twl4030_keypad.c b/drivers/input/keyboard/twl4030_keypad.c index 09bef79d9da1..cc06c4b2f920 100644 --- a/drivers/input/keyboard/twl4030_keypad.c +++ b/drivers/input/keyboard/twl4030_keypad.c @@ -338,7 +338,7 @@ static int __devinit twl4030_kp_probe(struct platform_device *pdev) u8 reg; int error; - if (!pdata || !pdata->rows || !pdata->cols || + if (!pdata || !pdata->rows || !pdata->cols || !pdata->keymap_data || pdata->rows > TWL4030_MAX_ROWS || pdata->cols > TWL4030_MAX_COLS) { dev_err(&pdev->dev, "Invalid platform_data\n"); return -EINVAL; -- cgit v1.2.3 From 908433833cac977563e9bef8b206990d846876b4 Mon Sep 17 00:00:00 2001 From: Christoph Fritz Date: Wed, 6 Apr 2011 15:33:16 -0700 Subject: Input: h3600_ts - fix error handling at connect In case of an error in h3600ts_connect(), deconstruct in correct order and with the right calls. Signed-off-by: Christoph Fritz Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/h3600_ts_input.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/h3600_ts_input.c b/drivers/input/touchscreen/h3600_ts_input.c index efa06882de00..45f93d0f5592 100644 --- a/drivers/input/touchscreen/h3600_ts_input.c +++ b/drivers/input/touchscreen/h3600_ts_input.c @@ -399,31 +399,34 @@ static int h3600ts_connect(struct serio *serio, struct serio_driver *drv) IRQF_SHARED | IRQF_DISABLED, "h3600_action", &ts->dev)) { printk(KERN_ERR "h3600ts.c: Could not allocate Action Button IRQ!\n"); err = -EBUSY; - goto fail2; + goto fail1; } if (request_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, npower_button_handler, IRQF_SHARED | IRQF_DISABLED, "h3600_suspend", &ts->dev)) { printk(KERN_ERR "h3600ts.c: Could not allocate Power Button IRQ!\n"); err = -EBUSY; - goto fail3; + goto fail2; } serio_set_drvdata(serio, ts); err = serio_open(serio, drv); if (err) - return err; + goto fail3; //h3600_flite_control(1, 25); /* default brightness */ - input_register_device(ts->dev); + err = input_register_device(ts->dev); + if (err) + goto fail4; return 0; -fail3: free_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, ts->dev); +fail4: serio_close(serio); +fail3: serio_set_drvdata(serio, NULL); + 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); +fail1: input_free_device(input_dev); kfree(ts); return err; } -- cgit v1.2.3 From c68b2081250a87ba9b9a173faa5a600cc684602e Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Mon, 11 Apr 2011 23:50:02 -0700 Subject: Input: twl4030_keypad - fix potential NULL dereference in twl4030_kp_probe() We should first check whether platform data is NULL or not, before dereferencing it to get the keymap. Signed-off-by: Axel Lin Reviewed-by: Felipe Balbi Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/twl4030_keypad.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/input') diff --git a/drivers/input/keyboard/twl4030_keypad.c b/drivers/input/keyboard/twl4030_keypad.c index cc06c4b2f920..a26922cf0e84 100644 --- a/drivers/input/keyboard/twl4030_keypad.c +++ b/drivers/input/keyboard/twl4030_keypad.c @@ -332,7 +332,7 @@ static int __devinit twl4030_kp_program(struct twl4030_keypad *kp) static int __devinit twl4030_kp_probe(struct platform_device *pdev) { struct twl4030_keypad_data *pdata = pdev->dev.platform_data; - const struct matrix_keymap_data *keymap_data = pdata->keymap_data; + const struct matrix_keymap_data *keymap_data; struct twl4030_keypad *kp; struct input_dev *input; u8 reg; @@ -344,6 +344,8 @@ static int __devinit twl4030_kp_probe(struct platform_device *pdev) return -EINVAL; } + keymap_data = pdata->keymap_data; + kp = kzalloc(sizeof(*kp), GFP_KERNEL); input = input_allocate_device(); if (!kp || !input) { -- cgit v1.2.3 From 9fb0f14e31b6101a0cc69a333b43541044f9b0a6 Mon Sep 17 00:00:00 2001 From: Jeff Brown Date: Tue, 12 Apr 2011 23:29:38 -0700 Subject: Input: evdev - indicate buffer overrun with SYN_DROPPED Add a new EV_SYN code, SYN_DROPPED, to inform the client when input events have been dropped from the evdev input buffer due to a buffer overrun. The client should use this event as a hint to reset its state or ignore all following events until the next packet begins. Signed-off-by: Jeff Brown [dtor@mail.ru: Implement Henrik's suggestion and drop old events in case of overflow.] Signed-off-by: Dmitry Torokhov --- drivers/input/evdev.c | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index 7f42d3a454d2..88d8e4cb419a 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c @@ -39,13 +39,13 @@ struct evdev { }; struct evdev_client { - int head; - int tail; + unsigned int head; + unsigned int tail; spinlock_t buffer_lock; /* protects access to buffer, head and tail */ struct fasync_struct *fasync; struct evdev *evdev; struct list_head node; - int bufsize; + unsigned int bufsize; struct input_event buffer[]; }; @@ -55,16 +55,25 @@ static DEFINE_MUTEX(evdev_table_mutex); static void evdev_pass_event(struct evdev_client *client, struct input_event *event) { - /* - * Interrupts are disabled, just acquire the lock. - * Make sure we don't leave with the client buffer - * "empty" by having client->head == client->tail. - */ + /* Interrupts are disabled, just acquire the lock. */ spin_lock(&client->buffer_lock); - do { - client->buffer[client->head++] = *event; - client->head &= client->bufsize - 1; - } while (client->head == client->tail); + + client->buffer[client->head++] = *event; + client->head &= client->bufsize - 1; + + if (unlikely(client->head == client->tail)) { + /* + * This effectively "drops" all unconsumed events, leaving + * EV_SYN/SYN_DROPPED plus the newest event in the queue. + */ + client->tail = (client->head - 2) & (client->bufsize - 1); + + client->buffer[client->tail].time = event->time; + client->buffer[client->tail].type = EV_SYN; + client->buffer[client->tail].code = SYN_DROPPED; + client->buffer[client->tail].value = 0; + } + spin_unlock(&client->buffer_lock); if (event->type == EV_SYN) -- cgit v1.2.3 From 80b4895aa4578e9372d76cd4063f82d0c3994d77 Mon Sep 17 00:00:00 2001 From: Jeff Brown Date: Mon, 18 Apr 2011 10:08:02 -0700 Subject: Input: estimate number of events per packet Calculate a default based on the number of ABS axes, REL axes, and MT slots for the device during input device registration. Signed-off-by: Jeff Brown Reviewed-by: Henrik Rydberg Signed-off-by: Dmitry Torokhov --- drivers/input/input.c | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) (limited to 'drivers/input') diff --git a/drivers/input/input.c b/drivers/input/input.c index d6e8bd8a851c..ebbceedc92f4 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -1746,6 +1746,42 @@ void input_set_capability(struct input_dev *dev, unsigned int type, unsigned int } EXPORT_SYMBOL(input_set_capability); +static unsigned int input_estimate_events_per_packet(struct input_dev *dev) +{ + int mt_slots; + int i; + unsigned int events; + + if (dev->mtsize) { + mt_slots = dev->mtsize; + } else if (test_bit(ABS_MT_TRACKING_ID, dev->absbit)) { + mt_slots = dev->absinfo[ABS_MT_TRACKING_ID].maximum - + dev->absinfo[ABS_MT_TRACKING_ID].minimum + 1, + clamp(mt_slots, 2, 32); + } else if (test_bit(ABS_MT_POSITION_X, dev->absbit)) { + mt_slots = 2; + } else { + mt_slots = 0; + } + + events = mt_slots + 1; /* count SYN_MT_REPORT and SYN_REPORT */ + + for (i = 0; i < ABS_CNT; i++) { + if (test_bit(i, dev->absbit)) { + if (input_is_mt_axis(i)) + events += mt_slots; + else + events++; + } + } + + for (i = 0; i < REL_CNT; i++) + if (test_bit(i, dev->relbit)) + events++; + + return events; +} + #define INPUT_CLEANSE_BITMASK(dev, type, bits) \ do { \ if (!test_bit(EV_##type, dev->evbit)) \ @@ -1793,6 +1829,10 @@ int input_register_device(struct input_dev *dev) /* Make sure that bitmasks not mentioned in dev->evbit are clean. */ input_cleanse_bitmasks(dev); + if (!dev->hint_events_per_packet) + dev->hint_events_per_packet = + input_estimate_events_per_packet(dev); + /* * If delay and period are pre-set by the driver, then autorepeating * is handled by the driver itself and we don't do it in input.c. -- cgit v1.2.3 From c36b58e8a9112017c2bcc322cc98e71241814303 Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Mon, 18 Apr 2011 10:17:17 -0700 Subject: Input: xen-kbdfront - fix mouse getting stuck after save/restore Mouse gets "stuck" after restore of PV guest but buttons are in working condition. If driver has been configured for ABS coordinates at start it will get XENKBD_TYPE_POS events and then suddenly after restore it'll start getting XENKBD_TYPE_MOTION events, that will be dropped later and they won't get into user-space. Regression was introduced by hunk 5 and 6 of 5ea5254aa0ad269cfbd2875c973ef25ab5b5e9db ("Input: xen-kbdfront - advertise either absolute or relative coordinates"). Driver on restore should ask xen for request-abs-pointer again if it is available. So restore parts that did it before 5ea5254. Acked-by: Olaf Hering Signed-off-by: Igor Mammedov [v1: Expanded the commit description] Signed-off-by: Konrad Rzeszutek Wilk Signed-off-by: Dmitry Torokhov --- drivers/input/misc/xen-kbdfront.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'drivers/input') diff --git a/drivers/input/misc/xen-kbdfront.c b/drivers/input/misc/xen-kbdfront.c index 7077f9bf5ead..62bae99424e6 100644 --- a/drivers/input/misc/xen-kbdfront.c +++ b/drivers/input/misc/xen-kbdfront.c @@ -303,7 +303,7 @@ static void xenkbd_backend_changed(struct xenbus_device *dev, enum xenbus_state backend_state) { struct xenkbd_info *info = dev_get_drvdata(&dev->dev); - int val; + int ret, val; switch (backend_state) { case XenbusStateInitialising: @@ -316,6 +316,17 @@ static void xenkbd_backend_changed(struct xenbus_device *dev, case XenbusStateInitWait: InitWait: + ret = xenbus_scanf(XBT_NIL, info->xbdev->otherend, + "feature-abs-pointer", "%d", &val); + if (ret < 0) + val = 0; + if (val) { + ret = xenbus_printf(XBT_NIL, info->xbdev->nodename, + "request-abs-pointer", "1"); + if (ret) + pr_warning("xenkbd: can't request abs-pointer"); + } + xenbus_switch_state(dev, XenbusStateConnected); break; -- cgit v1.2.3 From f5346668150c37094b42cc2d07ec5fd1451eb980 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 27 Apr 2011 23:08:34 -0700 Subject: Input: wm831x-ts - fix races with IRQ management If the WM831x pen down and data IRQs run in parallel it is possible for the data and pen down IRQs to deadlock themselves as one is part way through disabling its operation while the other is part way through enabling. Fix this by always disabling the pen down interrupt while data is active and vice versa. When a changeover is required we disable the IRQ that is to be stopped then schedule work that will enable the new IRQ. We need to handle the data flow in the data IRQ as the readback from the device needs to be ordered correctly with the IRQ for robust operation. This also fixes an issue when using the built in IRQs due to enable_irq() not being valid from interrupt context on an interrupt controller with bus operations like the built in IRQ controller - this issue may also have affected other interrupt controllers. We can't rely on having the data and pen down IRQs available via GPIOs on the CPU on every system. Signed-off-by: Mark Brown Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/wm831x-ts.c | 54 +++++++++++++++++++++++++++++++---- 1 file changed, 49 insertions(+), 5 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/wm831x-ts.c b/drivers/input/touchscreen/wm831x-ts.c index 6ae054f8e0aa..b9373012b3e6 100644 --- a/drivers/input/touchscreen/wm831x-ts.c +++ b/drivers/input/touchscreen/wm831x-ts.c @@ -68,8 +68,23 @@ struct wm831x_ts { unsigned int pd_irq; bool pressure; bool pen_down; + struct work_struct pd_data_work; }; +static void wm831x_pd_data_work(struct work_struct *work) +{ + struct wm831x_ts *wm831x_ts = + container_of(work, struct wm831x_ts, pd_data_work); + + if (wm831x_ts->pen_down) { + enable_irq(wm831x_ts->data_irq); + dev_dbg(wm831x_ts->wm831x->dev, "IRQ PD->DATA done\n"); + } else { + enable_irq(wm831x_ts->pd_irq); + dev_dbg(wm831x_ts->wm831x->dev, "IRQ DATA->PD done\n"); + } +} + static irqreturn_t wm831x_ts_data_irq(int irq, void *irq_data) { struct wm831x_ts *wm831x_ts = irq_data; @@ -110,6 +125,9 @@ static irqreturn_t wm831x_ts_data_irq(int irq, void *irq_data) } if (!wm831x_ts->pen_down) { + /* Switch from data to pen down */ + dev_dbg(wm831x->dev, "IRQ DATA->PD\n"); + disable_irq_nosync(wm831x_ts->data_irq); /* Don't need data any more */ @@ -128,6 +146,8 @@ static irqreturn_t wm831x_ts_data_irq(int irq, void *irq_data) ABS_PRESSURE, 0); input_report_key(wm831x_ts->input_dev, BTN_TOUCH, 0); + + schedule_work(&wm831x_ts->pd_data_work); } input_sync(wm831x_ts->input_dev); @@ -141,6 +161,11 @@ static irqreturn_t wm831x_ts_pen_down_irq(int irq, void *irq_data) struct wm831x *wm831x = wm831x_ts->wm831x; int ena = 0; + if (wm831x_ts->pen_down) + return IRQ_HANDLED; + + disable_irq_nosync(wm831x_ts->pd_irq); + /* Start collecting data */ if (wm831x_ts->pressure) ena |= WM831X_TCH_Z_ENA; @@ -156,7 +181,10 @@ static irqreturn_t wm831x_ts_pen_down_irq(int irq, void *irq_data) WM831X_TCHPD_EINT, WM831X_TCHPD_EINT); wm831x_ts->pen_down = true; - enable_irq(wm831x_ts->data_irq); + + /* Switch from pen down to data */ + dev_dbg(wm831x->dev, "IRQ PD->DATA\n"); + schedule_work(&wm831x_ts->pd_data_work); return IRQ_HANDLED; } @@ -182,13 +210,28 @@ static void wm831x_ts_input_close(struct input_dev *idev) struct wm831x_ts *wm831x_ts = input_get_drvdata(idev); struct wm831x *wm831x = wm831x_ts->wm831x; + /* Shut the controller down, disabling all other functionality too */ wm831x_set_bits(wm831x, WM831X_TOUCH_CONTROL_1, - WM831X_TCH_ENA | WM831X_TCH_CVT_ENA | - WM831X_TCH_X_ENA | WM831X_TCH_Y_ENA | - WM831X_TCH_Z_ENA, 0); + WM831X_TCH_ENA | WM831X_TCH_X_ENA | + WM831X_TCH_Y_ENA | WM831X_TCH_Z_ENA, 0); - if (wm831x_ts->pen_down) + /* Make sure any pending IRQs are done, the above will prevent + * new ones firing. + */ + synchronize_irq(wm831x_ts->data_irq); + synchronize_irq(wm831x_ts->pd_irq); + + /* Make sure the IRQ completion work is quiesced */ + flush_work_sync(&wm831x_ts->pd_data_work); + + /* If we ended up with the pen down then make sure we revert back + * to pen detection state for the next time we start up. + */ + if (wm831x_ts->pen_down) { disable_irq(wm831x_ts->data_irq); + enable_irq(wm831x_ts->pd_irq); + wm831x_ts->pen_down = false; + } } static __devinit int wm831x_ts_probe(struct platform_device *pdev) @@ -212,6 +255,7 @@ static __devinit int wm831x_ts_probe(struct platform_device *pdev) wm831x_ts->wm831x = wm831x; wm831x_ts->input_dev = input_dev; + INIT_WORK(&wm831x_ts->pd_data_work, wm831x_pd_data_work); /* * If we have a direct IRQ use it, otherwise use the interrupt -- cgit v1.2.3 From acad9853b95df6a3887f52e0ec88e4a77119ee28 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 27 Apr 2011 23:08:51 -0700 Subject: Input: wm831x-ts - allow IRQ flags to be specified This allows maximum flexibility for configuring the direct GPIO based interrupts. Signed-off-by: Mark Brown Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/wm831x-ts.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/wm831x-ts.c b/drivers/input/touchscreen/wm831x-ts.c index b9373012b3e6..78e8705df20d 100644 --- a/drivers/input/touchscreen/wm831x-ts.c +++ b/drivers/input/touchscreen/wm831x-ts.c @@ -241,7 +241,7 @@ static __devinit int wm831x_ts_probe(struct platform_device *pdev) struct wm831x_pdata *core_pdata = dev_get_platdata(pdev->dev.parent); struct wm831x_touch_pdata *pdata = NULL; struct input_dev *input_dev; - int error; + int error, irqf; if (core_pdata) pdata = core_pdata->touch; @@ -314,9 +314,14 @@ static __devinit int wm831x_ts_probe(struct platform_device *pdev) wm831x_set_bits(wm831x, WM831X_TOUCH_CONTROL_1, WM831X_TCH_RATE_MASK, 6); + if (pdata && pdata->data_irqf) + irqf = pdata->data_irqf; + else + irqf = IRQF_TRIGGER_HIGH; + error = request_threaded_irq(wm831x_ts->data_irq, NULL, wm831x_ts_data_irq, - IRQF_ONESHOT, + irqf | IRQF_ONESHOT, "Touchscreen data", wm831x_ts); if (error) { dev_err(&pdev->dev, "Failed to request data IRQ %d: %d\n", @@ -325,9 +330,14 @@ static __devinit int wm831x_ts_probe(struct platform_device *pdev) } disable_irq(wm831x_ts->data_irq); + if (pdata && pdata->pd_irqf) + irqf = pdata->pd_irqf; + else + irqf = IRQF_TRIGGER_HIGH; + error = request_threaded_irq(wm831x_ts->pd_irq, NULL, wm831x_ts_pen_down_irq, - IRQF_ONESHOT, + irqf | IRQF_ONESHOT, "Touchscreen pen down", wm831x_ts); if (error) { dev_err(&pdev->dev, "Failed to request pen down IRQ %d: %d\n", -- cgit v1.2.3 From bf283707d5fb174ec09215ae19860ad04ba7b67a Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 27 Apr 2011 23:09:26 -0700 Subject: Input: wm831x-ts - move BTN_TOUCH reporting to data transfer Don't report BTN_TOUCH until we've got data as some less robust applications can be confused by getting a touch event by itself and it doesn't seem unreasonable for them to expect coordinates along with a touch. Signed-off-by: Mark Brown Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/wm831x-ts.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/wm831x-ts.c b/drivers/input/touchscreen/wm831x-ts.c index 78e8705df20d..9175d49d2546 100644 --- a/drivers/input/touchscreen/wm831x-ts.c +++ b/drivers/input/touchscreen/wm831x-ts.c @@ -148,6 +148,8 @@ static irqreturn_t wm831x_ts_data_irq(int irq, void *irq_data) input_report_key(wm831x_ts->input_dev, BTN_TOUCH, 0); schedule_work(&wm831x_ts->pd_data_work); + } else { + input_report_key(wm831x_ts->input_dev, BTN_TOUCH, 1); } input_sync(wm831x_ts->input_dev); @@ -174,9 +176,6 @@ static irqreturn_t wm831x_ts_pen_down_irq(int irq, void *irq_data) WM831X_TCH_X_ENA | WM831X_TCH_Y_ENA | WM831X_TCH_Z_ENA, WM831X_TCH_X_ENA | WM831X_TCH_Y_ENA | ena); - input_report_key(wm831x_ts->input_dev, BTN_TOUCH, 1); - input_sync(wm831x_ts->input_dev); - wm831x_set_bits(wm831x, WM831X_INTERRUPT_STATUS_1, WM831X_TCHPD_EINT, WM831X_TCHPD_EINT); -- cgit v1.2.3 From 1dbe7dada2d03d1313183d439068f1f951a91244 Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Thu, 5 May 2011 08:40:14 -0700 Subject: Input: ads7846 - make transfer buffers DMA safe req.sample needs its own cacheline otherwise accessing req.msg fetches it in again. Note: This effect doesn't occur if the underlying SPI driver doesn't use DMA at all. Signed-off-by: Alexander Stein Acked-by: Jonathan Cameron Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/ads7846.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c index c24946f51256..ab51a8dbdb5a 100644 --- a/drivers/input/touchscreen/ads7846.c +++ b/drivers/input/touchscreen/ads7846.c @@ -281,17 +281,25 @@ struct ser_req { u8 command; u8 ref_off; u16 scratch; - __be16 sample; struct spi_message msg; struct spi_transfer xfer[6]; + /* + * DMA (thus cache coherency maintenance) requires the + * transfer buffers to live in their own cache lines. + */ + __be16 sample ____cacheline_aligned; }; struct ads7845_ser_req { u8 command[3]; u8 pwrdown[3]; - u8 sample[3]; struct spi_message msg; struct spi_transfer xfer[2]; + /* + * DMA (thus cache coherency maintenance) requires the + * transfer buffers to live in their own cache lines. + */ + u8 sample[3] ____cacheline_aligned; }; static int ads7846_read12_ser(struct device *dev, unsigned command) -- cgit v1.2.3 From 28350e330cfab46b60a1dbf763b678d859f9f3d9 Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Thu, 5 May 2011 08:40:46 -0700 Subject: Input: ads7846 - remove unused variable from struct ads7845_ser_req Signed-off-by: Alexander Stein Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/ads7846.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c index ab51a8dbdb5a..1de1c19dad30 100644 --- a/drivers/input/touchscreen/ads7846.c +++ b/drivers/input/touchscreen/ads7846.c @@ -292,7 +292,6 @@ struct ser_req { struct ads7845_ser_req { u8 command[3]; - u8 pwrdown[3]; struct spi_message msg; struct spi_transfer xfer[2]; /* -- cgit v1.2.3