diff options
author | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2012-05-24 01:13:01 -0700 |
---|---|---|
committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2012-05-24 01:13:01 -0700 |
commit | e644dae645e167d154c0526358940986682a72b0 (patch) | |
tree | 972993c6568085b8d407fc7e13de10f4b93c651d /drivers/input/touchscreen | |
parent | 899c612d74d4a242158a4db20367388d6299c028 (diff) | |
parent | 86809173ce32ef03bd4d0389dfc72df0c805e9c4 (diff) |
Merge branch 'next' into for-linus
Diffstat (limited to 'drivers/input/touchscreen')
23 files changed, 746 insertions, 244 deletions
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 97b31a0e052..f67657b2fd5 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -187,6 +187,23 @@ config TOUCHSCREEN_DA9034 Say Y here to enable the support for the touchscreen found on Dialog Semiconductor DA9034 PMIC. + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called da9034-ts. + +config TOUCHSCREEN_DA9052 + tristate "Dialog DA9052/DA9053 TSI" + depends on PMIC_DA9052 + help + Say Y here to support the touchscreen found on Dialog Semiconductor + DA9052-BC and DA9053-AA/Bx PMICs. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called da9052_tsi. + config TOUCHSCREEN_DYNAPRO tristate "Dynapro serial touchscreen" select SERIO @@ -260,7 +277,7 @@ config TOUCHSCREEN_ILI210X config TOUCHSCREEN_S3C2410 tristate "Samsung S3C2410/generic touchscreen input driver" - depends on ARCH_S3C2410 || SAMSUNG_DEV_TS + depends on ARCH_S3C24XX || SAMSUNG_DEV_TS select S3C_ADC help Say Y here if you have the s3c2410 touchscreen. @@ -306,6 +323,18 @@ config TOUCHSCREEN_WACOM_W8001 To compile this driver as a module, choose M here: the module will be called wacom_w8001. +config TOUCHSCREEN_WACOM_I2C + tristate "Wacom Tablet support (I2C)" + depends on I2C + help + Say Y here if you want to use the I2C version of the Wacom + Pen Tablet. + + If unsure, say N. + + To compile this driver as a module, choose M here: the module + will be called wacom_i2c. + config TOUCHSCREEN_LPC32XX tristate "LPC32XX touchscreen controller" depends on ARCH_LPC32XX @@ -635,6 +664,7 @@ config TOUCHSCREEN_USB_COMPOSITE - Zytronic controllers - Elo TouchSystems 2700 IntelliTouch - EasyTouch USB Touch Controller from Data Modul + - e2i (Mimo monitors) Have a look at <http://linux.chapter7.ch/touchkit/> for a usage description and the required user-space stuff. @@ -721,7 +751,7 @@ config TOUCHSCREEN_USB_ELO config TOUCHSCREEN_USB_E2I default y - bool "e2i Touchscreen controller (e.g. from Mimo 740)" + bool "e2i Touchscreen controller (e.g. from Mimo 740)" if EXPERT depends on TOUCHSCREEN_USB_COMPOSITE config TOUCHSCREEN_USB_ZYTRONIC @@ -744,7 +774,7 @@ config TOUCHSCREEN_USB_EASYTOUCH bool "EasyTouch USB Touch controller device support" if EMBEDDED depends on TOUCHSCREEN_USB_COMPOSITE help - Say Y here if you have a EasyTouch USB Touch controller device support. + Say Y here if you have an EasyTouch USB Touch controller. If unsure, say N. config TOUCHSCREEN_TOUCHIT213 diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index 3d5cf8cbf89..eb8bfe1c1a4 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -22,6 +22,7 @@ obj-$(CONFIG_TOUCHSCREEN_CYTTSP_CORE) += cyttsp_core.o obj-$(CONFIG_TOUCHSCREEN_CYTTSP_I2C) += cyttsp_i2c.o obj-$(CONFIG_TOUCHSCREEN_CYTTSP_SPI) += cyttsp_spi.o obj-$(CONFIG_TOUCHSCREEN_DA9034) += da9034-ts.o +obj-$(CONFIG_TOUCHSCREEN_DA9052) += da9052_tsi.o obj-$(CONFIG_TOUCHSCREEN_DYNAPRO) += dynapro.o obj-$(CONFIG_TOUCHSCREEN_HAMPSHIRE) += hampshire.o obj-$(CONFIG_TOUCHSCREEN_GUNZE) += gunze.o @@ -59,6 +60,7 @@ 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 +obj-$(CONFIG_TOUCHSCREEN_WACOM_I2C) += wacom_i2c.o obj-$(CONFIG_TOUCHSCREEN_WM831X) += wm831x-ts.o obj-$(CONFIG_TOUCHSCREEN_WM97XX) += wm97xx-ts.o wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9705) += wm9705.o diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index 19d4ea65ea0..42e645062c2 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -236,7 +236,6 @@ struct mxt_object { struct mxt_message { u8 reportid; u8 message[7]; - u8 checksum; }; struct mxt_finger { @@ -326,17 +325,12 @@ static bool mxt_object_writable(unsigned int type) } static void mxt_dump_message(struct device *dev, - struct mxt_message *message) + struct mxt_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); + dev_dbg(dev, "reportid: %u\tmessage: %02x %02x %02x %02x %02x %02x %02x\n", + message->reportid, message->message[0], message->message[1], + message->message[2], message->message[3], message->message[4], + message->message[5], message->message[6]); } static int mxt_check_bootloader(struct i2c_client *client, @@ -506,7 +500,7 @@ static int mxt_write_object(struct mxt_data *data, u16 reg; object = mxt_get_object(data, type); - if (!object) + if (!object || offset >= object->size + 1) return -EINVAL; reg = object->start_address; @@ -1049,8 +1043,8 @@ static ssize_t mxt_update_fw_store(struct device *dev, return count; } -static DEVICE_ATTR(object, 0444, mxt_object_show, NULL); -static DEVICE_ATTR(update_fw, 0664, NULL, mxt_update_fw_store); +static DEVICE_ATTR(object, S_IRUGO, mxt_object_show, NULL); +static DEVICE_ATTR(update_fw, S_IWUSR, NULL, mxt_update_fw_store); static struct attribute *mxt_attrs[] = { &dev_attr_object.attr, @@ -1201,7 +1195,7 @@ static int __devexit mxt_remove(struct i2c_client *client) return 0; } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP static int mxt_suspend(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); @@ -1239,13 +1233,10 @@ static int mxt_resume(struct device *dev) return 0; } - -static const struct dev_pm_ops mxt_pm_ops = { - .suspend = mxt_suspend, - .resume = mxt_resume, -}; #endif +static SIMPLE_DEV_PM_OPS(mxt_pm_ops, mxt_suspend, mxt_resume); + static const struct i2c_device_id mxt_id[] = { { "qt602240_ts", 0 }, { "atmel_mxt_ts", 0 }, @@ -1258,9 +1249,7 @@ static struct i2c_driver mxt_driver = { .driver = { .name = "atmel_mxt_ts", .owner = THIS_MODULE, -#ifdef CONFIG_PM .pm = &mxt_pm_ops, -#endif }, .probe = mxt_probe, .remove = __devexit_p(mxt_remove), diff --git a/drivers/input/touchscreen/da9052_tsi.c b/drivers/input/touchscreen/da9052_tsi.c new file mode 100644 index 00000000000..e8df341090c --- /dev/null +++ b/drivers/input/touchscreen/da9052_tsi.c @@ -0,0 +1,370 @@ +/* + * TSI driver for Dialog DA9052 + * + * Copyright(c) 2012 Dialog Semiconductor Ltd. + * + * Author: David Dajun Chen <dchen@diasemi.com> + * + * 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 <linux/module.h> +#include <linux/input.h> +#include <linux/delay.h> +#include <linux/platform_device.h> +#include <linux/interrupt.h> + +#include <linux/mfd/da9052/reg.h> +#include <linux/mfd/da9052/da9052.h> + +#define TSI_PEN_DOWN_STATUS 0x40 + +struct da9052_tsi { + struct da9052 *da9052; + struct input_dev *dev; + struct delayed_work ts_pen_work; + struct mutex mutex; + unsigned int irq_pendwn; + unsigned int irq_datardy; + bool stopped; + bool adc_on; +}; + +static void da9052_ts_adc_toggle(struct da9052_tsi *tsi, bool on) +{ + da9052_reg_update(tsi->da9052, DA9052_TSI_CONT_A_REG, 1 << 0, on); + tsi->adc_on = on; +} + +static irqreturn_t da9052_ts_pendwn_irq(int irq, void *data) +{ + struct da9052_tsi *tsi = data; + + if (!tsi->stopped) { + /* Mask PEN_DOWN event and unmask TSI_READY event */ + disable_irq_nosync(tsi->irq_pendwn); + enable_irq(tsi->irq_datardy); + + da9052_ts_adc_toggle(tsi, true); + + schedule_delayed_work(&tsi->ts_pen_work, HZ / 50); + } + + return IRQ_HANDLED; +} + +static void da9052_ts_read(struct da9052_tsi *tsi) +{ + struct input_dev *input = tsi->dev; + int ret; + u16 x, y, z; + u8 v; + + ret = da9052_reg_read(tsi->da9052, DA9052_TSI_X_MSB_REG); + if (ret < 0) + return; + + x = (u16) ret; + + ret = da9052_reg_read(tsi->da9052, DA9052_TSI_Y_MSB_REG); + if (ret < 0) + return; + + y = (u16) ret; + + ret = da9052_reg_read(tsi->da9052, DA9052_TSI_Z_MSB_REG); + if (ret < 0) + return; + + z = (u16) ret; + + ret = da9052_reg_read(tsi->da9052, DA9052_TSI_LSB_REG); + if (ret < 0) + return; + + v = (u8) ret; + + x = ((x << 2) & 0x3fc) | (v & 0x3); + y = ((y << 2) & 0x3fc) | ((v & 0xc) >> 2); + z = ((z << 2) & 0x3fc) | ((v & 0x30) >> 4); + + input_report_key(input, BTN_TOUCH, 1); + input_report_abs(input, ABS_X, x); + input_report_abs(input, ABS_Y, y); + input_report_abs(input, ABS_PRESSURE, z); + input_sync(input); +} + +static irqreturn_t da9052_ts_datardy_irq(int irq, void *data) +{ + struct da9052_tsi *tsi = data; + + da9052_ts_read(tsi); + + return IRQ_HANDLED; +} + +static void da9052_ts_pen_work(struct work_struct *work) +{ + struct da9052_tsi *tsi = container_of(work, struct da9052_tsi, + ts_pen_work.work); + if (!tsi->stopped) { + int ret = da9052_reg_read(tsi->da9052, DA9052_TSI_LSB_REG); + if (ret < 0 || (ret & TSI_PEN_DOWN_STATUS)) { + /* Pen is still DOWN (or read error) */ + schedule_delayed_work(&tsi->ts_pen_work, HZ / 50); + } else { + struct input_dev *input = tsi->dev; + + /* Pen UP */ + da9052_ts_adc_toggle(tsi, false); + + /* Report Pen UP */ + input_report_key(input, BTN_TOUCH, 0); + input_report_abs(input, ABS_PRESSURE, 0); + input_sync(input); + + /* + * FIXME: Fixes the unhandled irq issue when quick + * pen down and pen up events occurs + */ + ret = da9052_reg_update(tsi->da9052, + DA9052_EVENT_B_REG, 0xC0, 0xC0); + if (ret < 0) + return; + + /* Mask TSI_READY event and unmask PEN_DOWN event */ + disable_irq(tsi->irq_datardy); + enable_irq(tsi->irq_pendwn); + } + } +} + +static int __devinit da9052_ts_configure_gpio(struct da9052 *da9052) +{ + int error; + + error = da9052_reg_update(da9052, DA9052_GPIO_2_3_REG, 0x30, 0); + if (error < 0) + return error; + + error = da9052_reg_update(da9052, DA9052_GPIO_4_5_REG, 0x33, 0); + if (error < 0) + return error; + + error = da9052_reg_update(da9052, DA9052_GPIO_6_7_REG, 0x33, 0); + if (error < 0) + return error; + + return 0; +} + +static int __devinit da9052_configure_tsi(struct da9052_tsi *tsi) +{ + int error; + + error = da9052_ts_configure_gpio(tsi->da9052); + if (error) + return error; + + /* Measure TSI sample every 1ms */ + error = da9052_reg_update(tsi->da9052, DA9052_ADC_CONT_REG, + 1 << 6, 1 << 6); + if (error < 0) + return error; + + /* TSI_DELAY: 3 slots, TSI_SKIP: 0 slots, TSI_MODE: XYZP */ + error = da9052_reg_update(tsi->da9052, DA9052_TSI_CONT_A_REG, 0xFC, 0xC0); + if (error < 0) + return error; + + /* Supply TSIRef through LD09 */ + error = da9052_reg_write(tsi->da9052, DA9052_LDO9_REG, 0x59); + if (error < 0) + return error; + + return 0; +} + +static int da9052_ts_input_open(struct input_dev *input_dev) +{ + struct da9052_tsi *tsi = input_get_drvdata(input_dev); + + tsi->stopped = false; + mb(); + + /* Unmask PEN_DOWN event */ + enable_irq(tsi->irq_pendwn); + + /* Enable Pen Detect Circuit */ + return da9052_reg_update(tsi->da9052, DA9052_TSI_CONT_A_REG, + 1 << 1, 1 << 1); +} + +static void da9052_ts_input_close(struct input_dev *input_dev) +{ + struct da9052_tsi *tsi = input_get_drvdata(input_dev); + + tsi->stopped = true; + mb(); + disable_irq(tsi->irq_pendwn); + cancel_delayed_work_sync(&tsi->ts_pen_work); + + if (tsi->adc_on) { + disable_irq(tsi->irq_datardy); + da9052_ts_adc_toggle(tsi, false); + + /* + * If ADC was on that means that pendwn IRQ was disabled + * twice and we need to enable it to keep enable/disable + * counter balanced. IRQ is still off though. + */ + enable_irq(tsi->irq_pendwn); + } + + /* Disable Pen Detect Circuit */ + da9052_reg_update(tsi->da9052, DA9052_TSI_CONT_A_REG, 1 << 1, 0); +} + +static int __devinit da9052_ts_probe(struct platform_device *pdev) +{ + struct da9052 *da9052; + struct da9052_tsi *tsi; + struct input_dev *input_dev; + int irq_pendwn; + int irq_datardy; + int error; + + da9052 = dev_get_drvdata(pdev->dev.parent); + if (!da9052) + return -EINVAL; + + irq_pendwn = platform_get_irq_byname(pdev, "PENDWN"); + irq_datardy = platform_get_irq_byname(pdev, "TSIRDY"); + if (irq_pendwn < 0 || irq_datardy < 0) { + dev_err(da9052->dev, "Unable to determine device interrupts\n"); + return -ENXIO; + } + + tsi = kzalloc(sizeof(struct da9052_tsi), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!tsi || !input_dev) { + error = -ENOMEM; + goto err_free_mem; + } + + tsi->da9052 = da9052; + tsi->dev = input_dev; + tsi->irq_pendwn = da9052->irq_base + irq_pendwn; + tsi->irq_datardy = da9052->irq_base + irq_datardy; + tsi->stopped = true; + INIT_DELAYED_WORK(&tsi->ts_pen_work, da9052_ts_pen_work); + + input_dev->id.version = 0x0101; + input_dev->id.vendor = 0x15B6; + input_dev->id.product = 0x9052; + input_dev->name = "Dialog DA9052 TouchScreen Driver"; + input_dev->dev.parent = &pdev->dev; + input_dev->open = da9052_ts_input_open; + input_dev->close = da9052_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, 1023, 0, 0); + input_set_abs_params(input_dev, ABS_Y, 0, 1023, 0, 0); + input_set_abs_params(input_dev, ABS_PRESSURE, 0, 1023, 0, 0); + + input_set_drvdata(input_dev, tsi); + + /* Disable Pen Detect Circuit */ + da9052_reg_update(tsi->da9052, DA9052_TSI_CONT_A_REG, 1 << 1, 0); + + /* Disable ADC */ + da9052_ts_adc_toggle(tsi, false); + + error = request_threaded_irq(tsi->irq_pendwn, + NULL, da9052_ts_pendwn_irq, + IRQF_TRIGGER_LOW | IRQF_ONESHOT, + "PENDWN", tsi); + if (error) { + dev_err(tsi->da9052->dev, + "Failed to register PENDWN IRQ %d, error = %d\n", + tsi->irq_pendwn, error); + goto err_free_mem; + } + + error = request_threaded_irq(tsi->irq_datardy, + NULL, da9052_ts_datardy_irq, + IRQF_TRIGGER_LOW | IRQF_ONESHOT, + "TSIRDY", tsi); + if (error) { + dev_err(tsi->da9052->dev, + "Failed to register TSIRDY IRQ %d, error = %d\n", + tsi->irq_datardy, error); + goto err_free_pendwn_irq; + } + + /* Mask PEN_DOWN and TSI_READY events */ + disable_irq(tsi->irq_pendwn); + disable_irq(tsi->irq_datardy); + + error = da9052_configure_tsi(tsi); + if (error) + goto err_free_datardy_irq; + + error = input_register_device(tsi->dev); + if (error) + goto err_free_datardy_irq; + + platform_set_drvdata(pdev, tsi); + + return 0; + +err_free_datardy_irq: + free_irq(tsi->irq_datardy, tsi); +err_free_pendwn_irq: + free_irq(tsi->irq_pendwn, tsi); +err_free_mem: + kfree(tsi); + input_free_device(input_dev); + + return error; +} + +static int __devexit da9052_ts_remove(struct platform_device *pdev) +{ + struct da9052_tsi *tsi = platform_get_drvdata(pdev); + + da9052_reg_write(tsi->da9052, DA9052_LDO9_REG, 0x19); + + free_irq(tsi->irq_pendwn, tsi); + free_irq(tsi->irq_datardy, tsi); + + input_unregister_device(tsi->dev); + kfree(tsi); + + platform_set_drvdata(pdev, NULL); + + return 0; +} + +static struct platform_driver da9052_tsi_driver = { + .probe = da9052_ts_probe, + .remove = __devexit_p(da9052_ts_remove), + .driver = { + .name = "da9052-tsi", + .owner = THIS_MODULE, + }, +}; + +module_platform_driver(da9052_tsi_driver); + +MODULE_DESCRIPTION("Touchscreen driver for Dialog Semiconductor DA9052"); +MODULE_AUTHOR("Anthony Olech <Anthony.Olech@diasemi.com>"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:da9052-tsi"); diff --git a/drivers/input/touchscreen/dynapro.c b/drivers/input/touchscreen/dynapro.c index 455353908bd..1809677a651 100644 --- a/drivers/input/touchscreen/dynapro.c +++ b/drivers/input/touchscreen/dynapro.c @@ -188,19 +188,4 @@ static struct serio_driver dynapro_drv = { .disconnect = dynapro_disconnect, }; -/* - * The functions for inserting/removing us as a module. - */ - -static int __init dynapro_init(void) -{ - return serio_register_driver(&dynapro_drv); -} - -static void __exit dynapro_exit(void) -{ - serio_unregister_driver(&dynapro_drv); -} - -module_init(dynapro_init); -module_exit(dynapro_exit); +module_serio_driver(dynapro_drv); diff --git a/drivers/input/touchscreen/elo.c b/drivers/input/touchscreen/elo.c index 486d31ba9c0..957423d1471 100644 --- a/drivers/input/touchscreen/elo.c +++ b/drivers/input/touchscreen/elo.c @@ -405,19 +405,4 @@ static struct serio_driver elo_drv = { .disconnect = elo_disconnect, }; -/* - * The functions for inserting/removing us as a module. - */ - -static int __init elo_init(void) -{ - return serio_register_driver(&elo_drv); -} - -static void __exit elo_exit(void) -{ - serio_unregister_driver(&elo_drv); -} - -module_init(elo_init); -module_exit(elo_exit); +module_serio_driver(elo_drv); diff --git a/drivers/input/touchscreen/fujitsu_ts.c b/drivers/input/touchscreen/fujitsu_ts.c index 80b21800355..10794ddbdf5 100644 --- a/drivers/input/touchscreen/fujitsu_ts.c +++ b/drivers/input/touchscreen/fujitsu_ts.c @@ -175,15 +175,4 @@ static struct serio_driver fujitsu_drv = { .disconnect = fujitsu_disconnect, }; -static int __init fujitsu_init(void) -{ - return serio_register_driver(&fujitsu_drv); -} - -static void __exit fujitsu_exit(void) -{ - serio_unregister_driver(&fujitsu_drv); -} - -module_init(fujitsu_init); -module_exit(fujitsu_exit); +module_serio_driver(fujitsu_drv); diff --git a/drivers/input/touchscreen/gunze.c b/drivers/input/touchscreen/gunze.c index a54f90e02ab..41c71766bf1 100644 --- a/drivers/input/touchscreen/gunze.c +++ b/drivers/input/touchscreen/gunze.c @@ -186,19 +186,4 @@ static struct serio_driver gunze_drv = { .disconnect = gunze_disconnect, }; -/* - * The functions for inserting/removing us as a module. - */ - -static int __init gunze_init(void) -{ - return serio_register_driver(&gunze_drv); -} - -static void __exit gunze_exit(void) -{ - serio_unregister_driver(&gunze_drv); -} - -module_init(gunze_init); -module_exit(gunze_exit); +module_serio_driver(gunze_drv); diff --git a/drivers/input/touchscreen/h3600_ts_input.c b/drivers/input/touchscreen/h3600_ts_input.c index 6107e563e68..b9e8686a6f1 100644 --- a/drivers/input/touchscreen/h3600_ts_input.c +++ b/drivers/input/touchscreen/h3600_ts_input.c @@ -476,19 +476,4 @@ static struct serio_driver h3600ts_drv = { .disconnect = h3600ts_disconnect, }; -/* - * The functions for inserting/removing us as a module. - */ - -static int __init h3600ts_init(void) -{ - return serio_register_driver(&h3600ts_drv); -} - -static void __exit h3600ts_exit(void) -{ - serio_unregister_driver(&h3600ts_drv); -} - -module_init(h3600ts_init); -module_exit(h3600ts_exit); +module_serio_driver(h3600ts_drv); diff --git a/drivers/input/touchscreen/hampshire.c b/drivers/input/touchscreen/hampshire.c index 2da6cc31bb2..0cc47ea98ac 100644 --- a/drivers/input/touchscreen/hampshire.c +++ b/drivers/input/touchscreen/hampshire.c @@ -187,19 +187,4 @@ static struct serio_driver hampshire_drv = { .disconnect = hampshire_disconnect, }; -/* - * The functions for inserting/removing us as a module. - */ - -static int __init hampshire_init(void) -{ - return serio_register_driver(&hampshire_drv); -} - -static void __exit hampshire_exit(void) -{ - serio_unregister_driver(&hampshire_drv); -} - -module_init(hampshire_init); -module_exit(hampshire_exit); +module_serio_driver(hampshire_drv); diff --git a/drivers/input/touchscreen/inexio.c b/drivers/input/touchscreen/inexio.c index 192ade0a0fb..a29c99c3224 100644 --- a/drivers/input/touchscreen/inexio.c +++ b/drivers/input/touchscreen/inexio.c @@ -189,19 +189,4 @@ static struct serio_driver inexio_drv = { .disconnect = inexio_disconnect, }; -/* - * The functions for inserting/removing us as a module. - */ - -static int __init inexio_init(void) -{ - return serio_register_driver(&inexio_drv); -} - -static void __exit inexio_exit(void) -{ - serio_unregister_driver(&inexio_drv); -} - -module_init(inexio_init); -module_exit(inexio_exit); +module_serio_driver(inexio_drv); diff --git a/drivers/input/touchscreen/jornada720_ts.c b/drivers/input/touchscreen/jornada720_ts.c index c3848ad2325..d9be6eac99b 100644 --- a/drivers/input/touchscreen/jornada720_ts.c +++ b/drivers/input/touchscreen/jornada720_ts.c @@ -22,6 +22,7 @@ #include <mach/hardware.h> #include <mach/jornada720.h> +#include <mach/irqs.h> MODULE_AUTHOR("Kristoffer Ericson <kristoffer.ericson@gmail.com>"); MODULE_DESCRIPTION("HP Jornada 710/720/728 touchscreen driver"); diff --git a/drivers/input/touchscreen/lpc32xx_ts.c b/drivers/input/touchscreen/lpc32xx_ts.c index afcd0691ec6..4c2b8ed3bf1 100644 --- a/drivers/input/touchscreen/lpc32xx_ts.c +++ b/drivers/input/touchscreen/lpc32xx_ts.c @@ -22,6 +22,7 @@ #include <linux/clk.h> #include <linux/io.h> #include <linux/slab.h> +#include <linux/of.h> /* * Touchscreen controller register offsets @@ -383,6 +384,14 @@ static const struct dev_pm_ops lpc32xx_ts_pm_ops = { #define LPC32XX_TS_PM_OPS NULL #endif +#ifdef CONFIG_OF +static struct of_device_id lpc32xx_tsc_of_match[] = { + { .compatible = "nxp,lpc3220-tsc", }, + { }, +}; +MODULE_DEVICE_TABLE(of, lpc32xx_tsc_of_match); +#endif + static struct platform_driver lpc32xx_ts_driver = { .probe = lpc32xx_ts_probe, .remove = __devexit_p(lpc32xx_ts_remove), @@ -390,6 +399,7 @@ static struct platform_driver lpc32xx_ts_driver = { .name = MOD_NAME, .owner = THIS_MODULE, .pm = LPC32XX_TS_PM_OPS, + .of_match_table = of_match_ptr(lpc32xx_tsc_of_match), }, }; module_platform_driver(lpc32xx_ts_driver); diff --git a/drivers/input/touchscreen/mc13783_ts.c b/drivers/input/touchscreen/mc13783_ts.c index ede02743eac..48dc5b0d26f 100644 --- a/drivers/input/touchscreen/mc13783_ts.c +++ b/drivers/input/touchscreen/mc13783_ts.c @@ -39,6 +39,7 @@ struct mc13783_ts_priv { struct delayed_work work; struct workqueue_struct *workq; unsigned int sample[4]; + struct mc13xxx_ts_platform_data *touch; }; static irqreturn_t mc13783_ts_handler(int irq, void *data) @@ -125,7 +126,9 @@ static void mc13783_ts_work(struct work_struct *work) unsigned int channel = 12; if (mc13xxx_adc_do_conversion(priv->mc13xxx, - mode, channel, priv->sample) == 0) + mode, channel, + priv->touch->ato, priv->touch->atox, + priv->sample) == 0) mc13783_ts_report_sample(priv); } @@ -179,6 +182,12 @@ static int __init mc13783_ts_probe(struct platform_device *pdev) INIT_DELAYED_WORK(&priv->work, mc13783_ts_work); priv->mc13xxx = dev_get_drvdata(pdev->dev.parent); priv->idev = idev; + priv->touch = dev_get_platdata(&pdev->dev); + if (!priv->touch) { + dev_err(&pdev->dev, "missing platform data\n"); + ret = -ENODEV; + goto err_free_mem; + } /* * We need separate workqueue because mc13783_adc_do_conversion diff --git a/drivers/input/touchscreen/mtouch.c b/drivers/input/touchscreen/mtouch.c index 9077228418b..eb66b7c37c2 100644 --- a/drivers/input/touchscreen/mtouch.c +++ b/drivers/input/touchscreen/mtouch.c @@ -202,19 +202,4 @@ static struct serio_driver mtouch_drv = { .disconnect = mtouch_disconnect, }; -/* - * The functions for inserting/removing us as a module. - */ - -static int __init mtouch_init(void) -{ - return serio_register_driver(&mtouch_drv); -} - -static void __exit mtouch_exit(void) -{ - serio_unregister_driver(&mtouch_drv); -} - -module_init(mtouch_init); -module_exit(mtouch_exit); +module_serio_driver(mtouch_drv); diff --git a/drivers/input/touchscreen/penmount.c b/drivers/input/touchscreen/penmount.c index 4c012fb2b01..4ccde45b9da 100644 --- a/drivers/input/touchscreen/penmount.c +++ b/drivers/input/touchscreen/penmount.c @@ -317,19 +317,4 @@ static struct serio_driver pm_drv = { .disconnect = pm_disconnect, }; -/* - * The functions for inserting/removing us as a module. - */ - -static int __init pm_init(void) -{ - return serio_register_driver(&pm_drv); -} - -static void __exit pm_exit(void) -{ - serio_unregister_driver(&pm_drv); -} - -module_init(pm_init); -module_exit(pm_exit); +module_serio_driver(pm_drv); diff --git a/drivers/input/touchscreen/st1232.c b/drivers/input/touchscreen/st1232.c index cbbf71b2269..6cb68a1981b 100644 --- a/drivers/input/touchscreen/st1232.c +++ b/drivers/input/touchscreen/st1232.c @@ -218,7 +218,7 @@ static int __devexit st1232_ts_remove(struct i2c_client *client) return 0; } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP static int st1232_ts_suspend(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); @@ -243,18 +243,25 @@ static int st1232_ts_resume(struct device *dev) return 0; } -static const struct dev_pm_ops st1232_ts_pm_ops = { - .suspend = st1232_ts_suspend, - .resume = st1232_ts_resume, -}; #endif +static SIMPLE_DEV_PM_OPS(st1232_ts_pm_ops, + st1232_ts_suspend, st1232_ts_resume); + static const struct i2c_device_id st1232_ts_id[] = { { ST1232_TS_NAME, 0 }, { } }; MODULE_DEVICE_TABLE(i2c, st1232_ts_id); +#ifdef CONFIG_OF +static const struct of_device_id st1232_ts_dt_ids[] __devinitconst = { + { .compatible = "sitronix,st1232", }, + { } +}; +MODULE_DEVICE_TABLE(of, st1232_ts_dt_ids); +#endif + static struct i2c_driver st1232_ts_driver = { .probe = st1232_ts_probe, .remove = __devexit_p(st1232_ts_remove), @@ -262,9 +269,8 @@ static struct i2c_driver st1232_ts_driver = { .driver = { .name = ST1232_TS_NAME, .owner = THIS_MODULE, -#ifdef CONFIG_PM + .of_match_table = of_match_ptr(st1232_ts_dt_ids), .pm = &st1232_ts_pm_ops, -#endif }, }; diff --git a/drivers/input/touchscreen/touchit213.c b/drivers/input/touchscreen/touchit213.c index d1297ba19da..5f29e5b8e1c 100644 --- a/drivers/input/touchscreen/touchit213.c +++ b/drivers/input/touchscreen/touchit213.c @@ -216,19 +216,4 @@ static struct serio_driver touchit213_drv = { .disconnect = touchit213_disconnect, }; -/* - * The functions for inserting/removing us as a module. - */ - -static int __init touchit213_init(void) -{ - return serio_register_driver(&touchit213_drv); -} - -static void __exit touchit213_exit(void) -{ - serio_unregister_driver(&touchit213_drv); -} - -module_init(touchit213_init); -module_exit(touchit213_exit); +module_serio_driver(touchit213_drv); diff --git a/drivers/input/touchscreen/touchright.c b/drivers/input/touchscreen/touchright.c index 3a5c142c2a7..8a2887daf19 100644 --- a/drivers/input/touchscreen/touchright.c +++ b/drivers/input/touchscreen/touchright.c @@ -176,19 +176,4 @@ static struct serio_driver tr_drv = { .disconnect = tr_disconnect, }; -/* - * The functions for inserting/removing us as a module. - */ - -static int __init tr_init(void) -{ - return serio_register_driver(&tr_drv); -} - -static void __exit tr_exit(void) -{ - serio_unregister_driver(&tr_drv); -} - -module_init(tr_init); -module_exit(tr_exit); +module_serio_driver(tr_drv); diff --git a/drivers/input/touchscreen/touchwin.c b/drivers/input/touchscreen/touchwin.c index 763a656a59f..588cdcb839d 100644 --- a/drivers/input/touchscreen/touchwin.c +++ b/drivers/input/touchscreen/touchwin.c @@ -183,19 +183,4 @@ static struct serio_driver tw_drv = { .disconnect = tw_disconnect, }; -/* - * The functions for inserting/removing us as a module. - */ - -static int __init tw_init(void) -{ - return serio_register_driver(&tw_drv); -} - -static void __exit tw_exit(void) -{ - serio_unregister_driver(&tw_drv); -} - -module_init(tw_init); -module_exit(tw_exit); +module_serio_driver(tw_drv); diff --git a/drivers/input/touchscreen/tsc40.c b/drivers/input/touchscreen/tsc40.c index 29d5ed4dd31..63209aaa55f 100644 --- a/drivers/input/touchscreen/tsc40.c +++ b/drivers/input/touchscreen/tsc40.c @@ -167,17 +167,7 @@ static struct serio_driver tsc_drv = { .disconnect = tsc_disconnect, }; -static int __init tsc_ser_init(void) -{ - return serio_register_driver(&tsc_drv); -} -module_init(tsc_ser_init); - -static void __exit tsc_exit(void) -{ - serio_unregister_driver(&tsc_drv); -} -module_exit(tsc_exit); +module_serio_driver(tsc_drv); MODULE_AUTHOR("Sebastian Andrzej Siewior <bigeasy@linutronix.de>"); MODULE_DESCRIPTION(DRIVER_DESC); diff --git a/drivers/input/touchscreen/wacom_i2c.c b/drivers/input/touchscreen/wacom_i2c.c new file mode 100644 index 00000000000..35572575d34 --- /dev/null +++ b/drivers/input/touchscreen/wacom_i2c.c @@ -0,0 +1,282 @@ +/* + * Wacom Penabled Driver for I2C + * + * Copyright (c) 2011 Tatsunosuke Tobita, Wacom. + * <tobita.tatsunosuke@wacom.co.jp> + * + * 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 of 2 of the License, + * or (at your option) any later version. + */ + +#include <linux/module.h> +#include <linux/input.h> +#include <linux/i2c.h> +#include <linux/slab.h> +#include <linux/irq.h> +#include <linux/interrupt.h> +#include <linux/gpio.h> +#include <asm/unaligned.h> + +#define WACOM_CMD_QUERY0 0x04 +#define WACOM_CMD_QUERY1 0x00 +#define WACOM_CMD_QUERY2 0x33 +#define WACOM_CMD_QUERY3 0x02 +#define WACOM_CMD_THROW0 0x05 +#define WACOM_CMD_THROW1 0x00 +#define WACOM_QUERY_SIZE 19 +#define WACOM_RETRY_CNT 100 + +struct wacom_features { + int x_max; + int y_max; + int pressure_max; + char fw_version; +}; + +struct wacom_i2c { + struct i2c_client *client; + struct input_dev *input; + u8 data[WACOM_QUERY_SIZE]; +}; + +static int wacom_query_device(struct i2c_client *client, + struct wacom_features *features) +{ + int ret; + u8 cmd1[] = { WACOM_CMD_QUERY0, WACOM_CMD_QUERY1, + WACOM_CMD_QUERY2, WACOM_CMD_QUERY3 }; + u8 cmd2[] = { WACOM_CMD_THROW0, WACOM_CMD_THROW1 }; + u8 data[WACOM_QUERY_SIZE]; + struct i2c_msg msgs[] = { + { + .addr = client->addr, + .flags = 0, + .len = sizeof(cmd1), + .buf = cmd1, + }, + { + .addr = client->addr, + .flags = 0, + .len = sizeof(cmd2), + .buf = cmd2, + }, + { + .addr = client->addr, + .flags = I2C_M_RD, + .len = sizeof(data), + .buf = data, + }, + }; + + ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); + if (ret < 0) + return ret; + if (ret != ARRAY_SIZE(msgs)) + return -EIO; + + features->x_max = get_unaligned_le16(&data[3]); + features->y_max = get_unaligned_le16(&data[5]); + features->pressure_max = get_unaligned_le16(&data[11]); + features->fw_version = get_unaligned_le16(&data[13]); + + dev_dbg(&client->dev, + "x_max:%d, y_max:%d, pressure:%d, fw:%d\n", + features->x_max, features->y_max, + features->pressure_max, features->fw_version); + + return 0; +} + +static irqreturn_t wacom_i2c_irq(int irq, void *dev_id) +{ + struct wacom_i2c *wac_i2c = dev_id; + struct input_dev *input = wac_i2c->input; + u8 *data = wac_i2c->data; + unsigned int x, y, pressure; + unsigned char tsw, f1, f2, ers; + int error; + + error = i2c_master_recv(wac_i2c->client, + wac_i2c->data, sizeof(wac_i2c->data)); + if (error < 0) + goto out; + + tsw = data[3] & 0x01; + ers = data[3] & 0x04; + f1 = data[3] & 0x02; + f2 = data[3] & 0x10; + x = le16_to_cpup((__le16 *)&data[4]); + y = le16_to_cpup((__le16 *)&data[6]); + pressure = le16_to_cpup((__le16 *)&data[8]); + + input_report_key(input, BTN_TOUCH, tsw || ers); + input_report_key(input, BTN_TOOL_PEN, tsw); + input_report_key(input, BTN_TOOL_RUBBER, ers); + input_report_key(input, BTN_STYLUS, f1); + input_report_key(input, BTN_STYLUS2, f2); + input_report_abs(input, ABS_X, x); + input_report_abs(input, ABS_Y, y); + input_report_abs(input, ABS_PRESSURE, pressure); + input_sync(input); + +out: + return IRQ_HANDLED; +} + +static int wacom_i2c_open(struct input_dev *dev) +{ + struct wacom_i2c *wac_i2c = input_get_drvdata(dev); + struct i2c_client *client = wac_i2c->client; + + enable_irq(client->irq); + + return 0; +} + +static void wacom_i2c_close(struct input_dev *dev) +{ + struct wacom_i2c *wac_i2c = input_get_drvdata(dev); + struct i2c_client *client = wac_i2c->client; + + disable_irq(client->irq); +} + +static int __devinit wacom_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct wacom_i2c *wac_i2c; + struct input_dev *input; + struct wacom_features features; + int error; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + dev_err(&client->dev, "i2c_check_functionality error\n"); + return -EIO; + } + + error = wacom_query_device(client, &features); + if (error) + return error; + + wac_i2c = kzalloc(sizeof(*wac_i2c), GFP_KERNEL); + input = input_allocate_device(); + if (!wac_i2c || !input) { + error = -ENOMEM; + goto err_free_mem; + } + + wac_i2c->client = client; + wac_i2c->input = input; + + input->name = "Wacom I2C Digitizer"; + input->id.bustype = BUS_I2C; + input->id.vendor = 0x56a; + input->id.version = features.fw_version; + input->dev.parent = &client->dev; + input->open = wacom_i2c_open; + input->close = wacom_i2c_close; + + input->evbit[0] |= BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); + + __set_bit(BTN_TOOL_PEN, input->keybit); + __set_bit(BTN_TOOL_RUBBER, input->keybit); + __set_bit(BTN_STYLUS, input->keybit); + __set_bit(BTN_STYLUS2, input->keybit); + __set_bit(BTN_TOUCH, input->keybit); + + input_set_abs_params(input, ABS_X, 0, features.x_max, 0, 0); + input_set_abs_params(input, ABS_Y, 0, features.y_max, 0, 0); + input_set_abs_params(input, ABS_PRESSURE, + 0, features.pressure_max, 0, 0); + + input_set_drvdata(input, wac_i2c); + + error = request_threaded_irq(client->irq, NULL, wacom_i2c_irq, + IRQF_TRIGGER_LOW | IRQF_ONESHOT, + "wacom_i2c", wac_i2c); + if (error) { + dev_err(&client->dev, + "Failed to enable IRQ, error: %d\n", error); + goto err_free_mem; + } + + /* Disable the IRQ, we'll enable it in wac_i2c_open() */ + disable_irq(client->irq); + + error = input_register_device(wac_i2c->input); + if (error) { + dev_err(&client->dev, + "Failed to register input device, error: %d\n", error); + goto err_free_irq; + } + + i2c_set_clientdata(client, wac_i2c); + return 0; + +err_free_irq: + free_irq(client->irq, wac_i2c); +err_free_mem: + input_free_device(input); + kfree(wac_i2c); + + return error; +} + +static int __devexit wacom_i2c_remove(struct i2c_client *client) +{ + struct wacom_i2c *wac_i2c = i2c_get_clientdata(client); + + free_irq(client->irq, wac_i2c); + input_unregister_device(wac_i2c->input); + kfree(wac_i2c); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int wacom_i2c_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + + disable_irq(client->irq); + + return 0; +} + +static int wacom_i2c_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + + enable_irq(client->irq); + + return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(wacom_i2c_pm, wacom_i2c_suspend, wacom_i2c_resume); + +static const struct i2c_device_id wacom_i2c_id[] = { + { "WAC_I2C_EMR", 0 }, + { }, +}; +MODULE_DEVICE_TABLE(i2c, wacom_i2c_id); + +static struct i2c_driver wacom_i2c_driver = { + .driver = { + .name = "wacom_i2c", + .owner = THIS_MODULE, + .pm = &wacom_i2c_pm, + }, + + .probe = wacom_i2c_probe, + .remove = __devexit_p(wacom_i2c_remove), + .id_table = wacom_i2c_id, +}; +module_i2c_driver(wacom_i2c_driver); + +MODULE_AUTHOR("Tatsunosuke Tobita <tobita.tatsunosuke@wacom.co.jp>"); +MODULE_DESCRIPTION("WACOM EMR I2C Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/input/touchscreen/wacom_w8001.c b/drivers/input/touchscreen/wacom_w8001.c index 1569a3934ab..8f9ad2f893b 100644 --- a/drivers/input/touchscreen/wacom_w8001.c +++ b/drivers/input/touchscreen/wacom_w8001.c @@ -594,15 +594,4 @@ static struct serio_driver w8001_drv = { .disconnect = w8001_disconnect, }; -static int __init w8001_init(void) -{ - return serio_register_driver(&w8001_drv); -} - -static void __exit w8001_exit(void) -{ - serio_unregister_driver(&w8001_drv); -} - -module_init(w8001_init); -module_exit(w8001_exit); +module_serio_driver(w8001_drv); |