S: Supported
F: drivers/acpi/fan.c
- - ACPI PROCESSOR AGGREGATOR DRIVER
- - M: Shaohua Li <shaohua.li@intel.com>
- - L: linux-acpi@vger.kernel.org
- - W: http://www.lesswatts.org/projects/acpi/
- - S: Supported
- - F: drivers/acpi/acpi_pad.c
- -
ACPI THERMAL DRIVER
M: Zhang Rui <rui.zhang@intel.com>
L: linux-acpi@vger.kernel.org
ARM/INTEL IOP32X ARM ARCHITECTURE
M: Lennert Buytenhek <kernel@wantstofly.org>
- - M: Dan Williams <dan.j.williams@intel.com>
+ + M: Dan Williams <djbw@fb.com>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
S: Maintained
ARM/INTEL IOP33X ARM ARCHITECTURE
- - M: Dan Williams <dan.j.williams@intel.com>
+ + M: Dan Williams <djbw@fb.com>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
S: Maintained
ARM/INTEL IOP13XX ARM ARCHITECTURE
M: Lennert Buytenhek <kernel@wantstofly.org>
- - M: Dan Williams <dan.j.williams@intel.com>
+ + M: Dan Williams <djbw@fb.com>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
S: Maintained
ARM/INTEL IQ81342EX MACHINE SUPPORT
M: Lennert Buytenhek <kernel@wantstofly.org>
- - M: Dan Williams <dan.j.williams@intel.com>
+ + M: Dan Williams <djbw@fb.com>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
S: Maintained
ARM/INTEL XSC3 (MANZANO) ARM CORE
M: Lennert Buytenhek <kernel@wantstofly.org>
- - M: Dan Williams <dan.j.williams@intel.com>
+ + M: Dan Williams <djbw@fb.com>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
S: Maintained
ARM/NOMADIK ARCHITECTURE
M: Alessandro Rubini <rubini@unipv.it>
- - M: Linus Walleij <linus.walleij@stericsson.com>
+ + M: Linus Walleij <linus.walleij@linaro.org>
M: STEricsson <STEricsson_nomadik_linux@list.st.com>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
S: Maintained
F: arch/arm/mach-nomadik/
F: arch/arm/plat-nomadik/
F: drivers/i2c/busses/i2c-nomadik.c
- - T: git git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-stericsson.git
+ + T: git git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-nomadik.git
ARM/OPENMOKO NEO FREERUNNER (GTA02) MACHINE SUPPORT
M: Nelson Castillo <arhuaco@freaks-unidos.net>
F: drivers/video/nuc900fb.c
ARM/U300 MACHINE SUPPORT
- - M: Linus Walleij <linus.walleij@stericsson.com>
+ + M: Linus Walleij <linus.walleij@linaro.org>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
S: Supported
F: arch/arm/mach-u300/
ARM/Ux500 ARM ARCHITECTURE
M: Srinidhi Kasagar <srinidhi.kasagar@stericsson.com>
- - M: Linus Walleij <linus.walleij@stericsson.com>
+ + M: Linus Walleij <linus.walleij@linaro.org>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
S: Maintained
F: arch/arm/mach-ux500/
+ + F: drivers/clocksource/clksrc-dbx500-prcmu.c
F: drivers/dma/ste_dma40*
+ + F: drivers/hwspinlock/u8500_hsem.c
F: drivers/mfd/abx500*
F: drivers/mfd/ab8500*
- - F: drivers/mfd/stmpe*
+ + F: drivers/mfd/dbx500*
+ + F: drivers/mfd/db8500*
+ + F: drivers/pinctrl/pinctrl-nomadik*
F: drivers/rtc/rtc-ab8500.c
+ + F: drivers/rtc/rtc-pl031.c
T: git git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-stericsson.git
ARM/VFP SUPPORT
F: arch/arm/mach-pxa/vpac270.c
F: arch/arm/mach-pxa/include/mach/vpac270.h
+ + ARM/VT8500 ARM ARCHITECTURE
+ + M: Tony Prisk <linux@prisktech.co.nz>
+ + L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+ + S: Maintained
+ + F: arch/arm/mach-vt8500/
+ + F: drivers/video/vt8500lcdfb.*
+ + F: drivers/video/wm8505fb*
+ + F: drivers/video/wmt_ge_rops.*
+ + F: drivers/tty/serial/vt8500_serial.c
+ + F: drivers/rtc/rtc-vt8500-c
+ +
ARM/ZIPIT Z2 SUPPORT
M: Marek Vasut <marek.vasut@gmail.com>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
F: drivers/hwmon/asb100.c
ASYNCHRONOUS TRANSFERS/TRANSFORMS (IOAT) API
- - M: Dan Williams <dan.j.williams@intel.com>
+ + M: Dan Williams <djbw@fb.com>
W: http://sourceforge.net/projects/xscaleiop
- - S: Supported
+ + S: Maintained
F: Documentation/crypto/async-tx-api.txt
F: crypto/async_tx/
F: drivers/dma/
S: Supported
F: drivers/i2c/busses/i2c-bfin-twi.c
+ + BLINKM RGB LED DRIVER
+ + M: Jan-Simon Moeller <jansimon.moeller@gmx.de>
+ + S: Maintained
+ + F: drivers/leds/leds-blinkm.c
+ +
BLOCK LAYER
M: Jens Axboe <axboe@kernel.dk>
T: git git://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux-block.git
F: arch/powerpc/platforms/cell/
CEPH DISTRIBUTED FILE SYSTEM CLIENT
- - M: Sage Weil <sage@newdream.net>
+ + M: Sage Weil <sage@inktank.com>
L: ceph-devel@vger.kernel.org
- - W: http://ceph.newdream.net/
+ + W: http://ceph.com/
T: git git://git.kernel.org/pub/scm/linux/kernel/git/sage/ceph-client.git
S: Supported
F: Documentation/filesystems/ceph.txt
F: fs/ceph
F: net/ceph
F: include/linux/ceph
+ + F: include/linux/crush
CERTIFIED WIRELESS USB (WUSB) SUBSYSTEM:
L: linux-usb@vger.kernel.org
F: drivers/scsi/tmscsim.*
DC395x SCSI driver
- - M: Oliver Neukum <oliver@neukum.name>
+ + M: Oliver Neukum <oliver@neukum.org>
M: Ali Akcaagac <aliakc@web.de>
M: Jamie Lenehan <lenehan@twibble.org>
W: http://twibble.org/dist/dc395x/
DMA GENERIC OFFLOAD ENGINE SUBSYSTEM
M: Vinod Koul <vinod.koul@intel.com>
- - M: Dan Williams <dan.j.williams@intel.com>
+ + M: Dan Williams <djbw@fb.com>
S: Supported
F: drivers/dma/
F: include/linux/dma*
S: Supported
F: security/integrity/evm/
+ + EXTERNAL CONNECTOR SUBSYSTEM (EXTCON)
+ + M: MyungJoo Ham <myungjoo.ham@samsung.com>
+ + M: Chanwoo Choi <cw00.choi@samsung.com>
+ + L: linux-kernel@vger.kernel.org
+ + S: Maintained
+ + F: drivers/extcon/
+ + F: Documentation/extcon/
+ +
EXYNOS DP DRIVER
M: Jingoo Han <jg1.han@samsung.com>
L: linux-fbdev@vger.kernel.org
S: Maintained
F: drivers/video/exynos/exynos_dp*
+ + F: include/video/exynos_dp*
EXYNOS MIPI DISPLAY DRIVERS
M: Inki Dae <inki.dae@samsung.com>
GPIO SUBSYSTEM
M: Grant Likely <grant.likely@secretlab.ca>
- - M: Linus Walleij <linus.walleij@stericsson.com>
+ + M: Linus Walleij <linus.walleij@linaro.org>
S: Maintained
T: git git://git.secretlab.ca/git/linux-2.6.git
F: Documentation/gpio.txt
F: drivers/media/video/gspca/t613.c
GSPCA USB WEBCAM DRIVER
- - M: Jean-Francois Moine <moinejf@free.fr>
- - W: http://moinejf.free.fr
+ + M: Hans de Goede <hdegoede@redhat.com>
L: linux-media@vger.kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media.git
S: Maintained
L: linux-i2c@vger.kernel.org
W: http://i2c.wiki.kernel.org/
T: quilt kernel.org/pub/linux/kernel/people/jdelvare/linux-2.6/jdelvare-i2c/
- - ---T: git git://git.fluff.org/bjdooks/linux.git
+ + +++T: git git://git.pengutronix.de/git/wsa/linux.git
S: Maintained
F: Documentation/i2c/
F: drivers/i2c/
INTEL C600 SERIES SAS CONTROLLER DRIVER
M: Intel SCU Linux support <intel-linux-scu@intel.com>
- - M: Dan Williams <dan.j.williams@intel.com>
M: Dave Jiang <dave.jiang@intel.com>
M: Ed Nadolski <edmund.nadolski@intel.com>
L: linux-scsi@vger.kernel.org
F: arch/x86/kernel/microcode_intel.c
INTEL I/OAT DMA DRIVER
- - M: Dan Williams <dan.j.williams@intel.com>
- - S: Supported
+ + M: Dan Williams <djbw@fb.com>
+ + S: Maintained
F: drivers/dma/ioat*
INTEL IOMMU (VT-d)
F: include/linux/intel-iommu.h
INTEL IOP-ADMA DMA DRIVER
- - M: Dan Williams <dan.j.williams@intel.com>
- - S: Maintained
+ + M: Dan Williams <djbw@fb.com>
+ + S: Odd fixes
F: drivers/dma/iop-adma.c
INTEL IXP4XX QMGR, NPE, ETHERNET and HSS SUPPORT
F: drivers/net/wireless/ipw2x00/
INTEL(R) TRUSTED EXECUTION TECHNOLOGY (TXT)
- - ---M: Joseph Cihula <joseph.cihula@intel.com>
+ + +++M: Richard L Maliszewski <richard.l.maliszewski@intel.com>
+ + +++M: Gang Wei <gang.wei@intel.com>
M: Shane Wang <shane.wang@intel.com>
L: tboot-devel@lists.sourceforge.net
W: http://tboot.sourceforge.net
- - ---T: Mercurial http://www.bughost.org/repos.hg/tboot.hg
+ + +++T: hg http://tboot.hg.sourceforge.net:8000/hgroot/tboot/tboot
S: Supported
F: Documentation/intel_txt.txt
F: include/linux/tboot.h
F: arch/microblaze/
MICROTEK X6 SCANNER
- - M: Oliver Neukum <oliver@neukum.name>
+ + M: Oliver Neukum <oliver@neukum.org>
S: Maintained
F: drivers/usb/image/microtek.*
F: drivers/usb/*/*omap*
F: arch/arm/*omap*/usb*
+ + OMAP GPIO DRIVER
+ + M: Santosh Shilimkar <santosh.shilimkar@ti.com>
+ + M: Kevin Hilman <khilman@ti.com>
+ + L: linux-omap@vger.kernel.org
+ + S: Maintained
+ + F: drivers/gpio/gpio-omap.c
+ +
OMFS FILESYSTEM
M: Bob Copeland <me@bobcopeland.com>
L: linux-karma-devel@lists.sourceforge.net
M: Bjorn Helgaas <bhelgaas@google.com>
L: linux-pci@vger.kernel.org
Q: http://patchwork.ozlabs.org/project/linux-pci/list/
- - T: git git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/linux.git
+ + T: git git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci.git
S: Supported
F: Documentation/PCI/
F: drivers/pci/
S: Maintained
F: drivers/mtd/devices/phram.c
+++ ++++PICOLCD HID DRIVER
+++ ++++M: Bruno Prémont <bonbons@linux-vserver.org>
+++ ++++L: linux-input@vger.kernel.org
+++ ++++S: Maintained
+++ ++++F: drivers/hid/hid-picolcd*
+++ ++++
PICOXCELL SUPPORT
M: Jamie Iles <jamie@jamieiles.com>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
M: Linus Walleij <linus.walleij@linaro.org>
S: Maintained
F: drivers/pinctrl/
+ + F: include/linux/pinctrl/
PIN CONTROLLER - ST SPEAR
- - M: Viresh Kumar <viresh.linux@gmail.com>
+ + M: Viresh Kumar <viresh.linux@gmail.com>
L: spear-devel@list.st.com
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
W: http://www.st.com/spear
S: Maintained
- - F: driver/pinctrl/spear/
+ + F: drivers/pinctrl/spear/
PKTCDVD DRIVER
M: Peter Osterlund <petero2@telia.com>
F: Documentation/video4linux/README.pvrusb2
F: drivers/media/video/pvrusb2/
+ + PWM SUBSYSTEM
+ + M: Thierry Reding <thierry.reding@avionic-design.de>
+ + L: linux-kernel@vger.kernel.org
+ + S: Maintained
+ + W: http://gitorious.org/linux-pwm
+ + T: git git://gitorious.org/linux-pwm/linux-pwm.git
+ + F: Documentation/pwm.txt
+ + F: Documentation/devicetree/bindings/pwm/
+ + F: include/linux/pwm.h
+ + F: include/linux/of_pwm.h
+ + F: drivers/pwm/
+ +
PXA2xx/PXA3xx SUPPORT
M: Eric Miao <eric.y.miao@gmail.com>
M: Russell King <linux@arm.linux.org.uk>
F: arch/hexagon/
RADOS BLOCK DEVICE (RBD)
- - F: include/linux/qnxtypes.h
- - M: Yehuda Sadeh <yehuda@hq.newdream.net>
- - M: Sage Weil <sage@newdream.net>
+ + M: Yehuda Sadeh <yehuda@inktank.com>
+ + M: Sage Weil <sage@inktank.com>
+ + M: Alex Elder <elder@inktank.com>
M: ceph-devel@vger.kernel.org
+ + W: http://ceph.com/
+ + T: git git://git.kernel.org/pub/scm/linux/kernel/git/sage/ceph-client.git
S: Supported
F: drivers/block/rbd.c
F: drivers/block/rbd_types.h
F: drivers/block/brd.c
RANDOM NUMBER DRIVER
- - M: Matt Mackall <mpm@selenic.com>
+ + M: Theodore Ts'o" <tytso@mit.edu>
S: Maintained
F: drivers/char/random.c
REMOTE PROCESSOR (REMOTEPROC) SUBSYSTEM
M: Ohad Ben-Cohen <ohad@wizery.com>
+ + T: git git://git.kernel.org/pub/scm/linux/kernel/git/ohad/remoteproc.git
S: Maintained
F: drivers/remoteproc/
F: Documentation/remoteproc.txt
S: Maintained
F: drivers/video/s3c-fb.c
+ + SAMSUNG MULTIFUNCTION DEVICE DRIVERS
+ + M: Sangbeom Kim <sbkim73@samsung.com>
+ + L: linux-kernel@vger.kernel.org
+ + S: Supported
+ + F: drivers/mfd/sec*.c
+ + F: drivers/regulator/s2m*.c
+ + F: drivers/regulator/s5m*.c
+ + F: drivers/rtc/rtc-sec.c
+ + F: include/linux/mfd/samsung/
+ +
SERIAL DRIVERS
M: Alan Cox <alan@linux.intel.com>
L: linux-serial@vger.kernel.org
F: drivers/hwmon/smm665.c
SMSC EMC2103 HARDWARE MONITOR DRIVER
- - M: Steve Glendinning <steve.glendinning@smsc.com>
+ + M: Steve Glendinning <steve.glendinning@shawell.net>
L: lm-sensors@lm-sensors.org
- - S: Supported
+ + S: Maintained
F: Documentation/hwmon/emc2103
F: drivers/hwmon/emc2103.c
F: drivers/hwmon/smsc47b397.c
SMSC911x ETHERNET DRIVER
- - M: Steve Glendinning <steve.glendinning@smsc.com>
+ + M: Steve Glendinning <steve.glendinning@shawell.net>
L: netdev@vger.kernel.org
- - S: Supported
+ + S: Maintained
F: include/linux/smsc911x.h
F: drivers/net/ethernet/smsc/smsc911x.*
SMSC9420 PCI ETHERNET DRIVER
- - M: Steve Glendinning <steve.glendinning@smsc.com>
+ + M: Steve Glendinning <steve.glendinning@shawell.net>
L: netdev@vger.kernel.org
- - S: Supported
+ + S: Maintained
F: drivers/net/ethernet/smsc/smsc9420.*
SMSC UFX6000 and UFX7000 USB to VGA DRIVER
- - M: Steve Glendinning <steve.glendinning@smsc.com>
+ + M: Steve Glendinning <steve.glendinning@shawell.net>
L: linux-fbdev@vger.kernel.org
- - S: Supported
+ + S: Maintained
F: drivers/video/smscufx.c
SN-IA64 (Itanium) SUB-PLATFORM
TI LM49xxx FAMILY ASoC CODEC DRIVERS
M: M R Swami Reddy <mr.swami.reddy@ti.com>
+ + M: Vishwas A Deshpande <vishwas.a.deshpande@ti.com>
L: alsa-devel@alsa-project.org (moderated for non-subscribers)
S: Maintained
F: sound/soc/codecs/lm49453*
+ + F: sound/soc/codecs/isabelle*
TI TWL4030 SERIES SOC CODEC DRIVER
M: Peter Ujfalusi <peter.ujfalusi@ti.com>
F: include/mtd/ubi-user.h
USB ACM DRIVER
- - M: Oliver Neukum <oliver@neukum.name>
+ + M: Oliver Neukum <oliver@neukum.org>
L: linux-usb@vger.kernel.org
S: Maintained
F: Documentation/usb/acm.txt
F: drivers/block/ub.c
USB CDC ETHERNET DRIVER
- - M: Oliver Neukum <oliver@neukum.name>
+ + M: Oliver Neukum <oliver@neukum.org>
L: linux-usb@vger.kernel.org
S: Maintained
F: drivers/net/usb/cdc_*.c
F: include/linux/usb/isp116x.h
USB KAWASAKI LSI DRIVER
- - M: Oliver Neukum <oliver@neukum.name>
+ + M: Oliver Neukum <oliver@neukum.org>
L: linux-usb@vger.kernel.org
S: Maintained
F: drivers/usb/serial/kl5kusb105.*
S: Supported
F: drivers/usb/serial/whiteheat*
+ + USB SMSC75XX ETHERNET DRIVER
+ + M: Steve Glendinning <steve.glendinning@shawell.net>
+ + L: netdev@vger.kernel.org
+ + S: Maintained
+ + F: drivers/net/usb/smsc75xx.*
+ +
USB SMSC95XX ETHERNET DRIVER
- - M: Steve Glendinning <steve.glendinning@smsc.com>
+ + M: Steve Glendinning <steve.glendinning@shawell.net>
L: netdev@vger.kernel.org
- - S: Supported
+ + S: Maintained
F: drivers/net/usb/smsc95xx.*
USB SN9C1xx DRIVER
S: Maintained
F: Documentation/virtual/uml/
F: arch/um/
+ + F: arch/x86/um/
F: fs/hostfs/
F: fs/hppfs/
F: Documentation/filesystems/vfat.txt
F: fs/fat/
+ + VFIO DRIVER
+ + M: Alex Williamson <alex.williamson@redhat.com>
+ + L: kvm@vger.kernel.org
+ + S: Maintained
+ + F: Documentation/vfio.txt
+ + F: drivers/vfio/
+ + F: include/linux/vfio.h
+ +
VIDEOBUF2 FRAMEWORK
M: Pawel Osciak <pawel@osciak.com>
M: Marek Szyprowski <m.szyprowski@samsung.com>
S: Supported
F: Documentation/hwmon/wm83??
F: arch/arm/mach-s3c64xx/mach-crag6410*
+ + F: drivers/clk/clk-wm83*.c
+ + F: drivers/extcon/extcon-arizona.c
F: drivers/leds/leds-wm83*.c
+ + F: drivers/gpio/gpio-*wm*.c
+ + F: drivers/gpio/gpio-arizona.c
F: drivers/hwmon/wm83??-hwmon.c
F: drivers/input/misc/wm831x-on.c
F: drivers/input/touchscreen/wm831x-ts.c
F: drivers/input/touchscreen/wm97*.c
- - F: drivers/mfd/wm8*.c
+ + F: drivers/mfd/arizona*
+ + F: drivers/mfd/wm*.c
F: drivers/power/wm83*.c
F: drivers/rtc/rtc-wm83*.c
F: drivers/regulator/wm8*.c
F: drivers/video/backlight/wm83*_bl.c
F: drivers/watchdog/wm83*_wdt.c
+ + F: include/linux/mfd/arizona/
F: include/linux/mfd/wm831x/
F: include/linux/mfd/wm8350/
F: include/linux/mfd/wm8400*
F: include/linux/wm97xx.h
F: include/sound/wm????.h
+ + F: sound/soc/codecs/arizona.?
F: sound/soc/codecs/wm*
WORKQUEUE
---help---
Provide access to PicoLCD's GPO pins via leds class.
+++ ++++config HID_PICOLCD_CIR
+++ ++++ bool "CIR via RC class" if EXPERT
+++ ++++ default !EXPERT
+++ ++++ depends on HID_PICOLCD
+++ ++++ depends on HID_PICOLCD=RC_CORE || RC_CORE=y
+++ ++++ ---help---
+++ ++++ Provide access to PicoLCD's CIR interface via remote control (LIRC).
+++ ++++
config HID_PRIMAX
tristate "Primax non-fully HID-compliant devices"
depends on USB_HID
Support for Primax devices that are not fully compliant with the
HID standard.
++++ +++config HID_PS3REMOTE
++++ +++ tristate "Sony PS3 BD Remote Control"
++++ +++ depends on BT_HIDP
++++ +++ ---help---
++++ +++ Support for the Sony PS3 Blue-ray Disk Remote Control and Logitech
++++ +++ Harmony Adapter for PS3, which connect over Bluetooth.
++++ +++
++++ +++ Support for the 6-axis controllers is provided by HID_SONY.
++++ +++
config HID_ROCCAT
tristate "Roccat device support"
depends on USB_HID
tristate "Sony PS3 controller"
depends on USB_HID
---help---
---- --- Support for Sony PS3 controller.
++++ +++ Support for Sony PS3 6-axis controllers.
++++ +++
++++ +++ Support for the Sony PS3 BD Remote is provided by HID_PS3REMOTE.
config HID_SPEEDLINK
tristate "Speedlink VAD Cezanne mouse support"
obj-$(CONFIG_HID_PANTHERLORD) += hid-pl.o
obj-$(CONFIG_HID_PETALYNX) += hid-petalynx.o
obj-$(CONFIG_HID_PICOLCD) += hid-picolcd.o
+++ ++++hid-picolcd-y += hid-picolcd_core.o
+++ ++++ifdef CONFIG_HID_PICOLCD_FB
+++ ++++hid-picolcd-y += hid-picolcd_fb.o
+++ ++++endif
+++ ++++ifdef CONFIG_HID_PICOLCD_BACKLIGHT
+++ ++++hid-picolcd-y += hid-picolcd_backlight.o
+++ ++++endif
+++ ++++ifdef CONFIG_HID_PICOLCD_LCD
+++ ++++hid-picolcd-y += hid-picolcd_lcd.o
+++ ++++endif
+++ ++++ifdef CONFIG_HID_PICOLCD_LEDS
+++ ++++hid-picolcd-y += hid-picolcd_leds.o
+++ ++++endif
+++ ++++ifdef CONFIG_HID_PICOLCD_CIR
+++ ++++hid-picolcd-y += hid-picolcd_cir.o
+++ ++++endif
+++ ++++ifdef CONFIG_DEBUG_FS
+++ ++++hid-picolcd-y += hid-picolcd_debugfs.o
+++ ++++endif
+++ ++++
obj-$(CONFIG_HID_PRIMAX) += hid-primax.o
++++ +++obj-$(CONFIG_HID_PS3REMOTE) += hid-ps3remote.o
obj-$(CONFIG_HID_ROCCAT) += hid-roccat.o hid-roccat-common.o \
hid-roccat-arvo.o hid-roccat-isku.o hid-roccat-kone.o \
hid-roccat-koneplus.o hid-roccat-kovaplus.o hid-roccat-pyra.o \
struct hid_driver *hdrv = hid->driver;
int ret;
- -- hid_dump_input(hid, usage, value);
+ ++ if (!list_empty(&hid->debug_list))
+ ++ hid_dump_input(hid, usage, value);
if (hdrv && hdrv->event && hid_match_usage(hid, usage)) {
ret = hdrv->event(hid, field, usage, value);
{ HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_EASYPEN_M610X) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LABTEC, USB_DEVICE_ID_LABTEC_WIRELESS_KEYBOARD) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LCPOWER, USB_DEVICE_ID_LCPOWER_LC1000 ) },
- -- { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_TPKBD) },
+ ++ #if IS_ENABLED(CONFIG_HID_LENOVO_TPKBD)
+ ++ { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_TPKBD) },
+ ++ #endif
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER_2) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RECEIVER) },
++++ +++ { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_PS3) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_DESKTOP) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_EDGE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_MINI) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ORTEK, USB_DEVICE_ID_ORTEK_WKB2000) },
{ HID_USB_DEVICE(USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_PRIMAX, USB_DEVICE_ID_PRIMAX_KEYBOARD) },
- - { HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_PIXART_IMAGING_INC_OPTICAL_TOUCH_SCREEN) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_ARVO) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_ISKU) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_WIRELESS_KBD_MOUSE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SKYCABLE, USB_DEVICE_ID_SKYCABLE_WIRELESS_PRESENTER) },
++++ +++ { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_BDREMOTE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_NAVIGATION_CONTROLLER) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) },
{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U) },
{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP1062) },
{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_WIRELESS_TABLET_TWHL850) },
+++++ ++ { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_TWHA60) },
{ HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_SMARTJOY_PLUS) },
{ HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_SUPER_JOY_BOX_3) },
{ HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_DUAL_USB_JOYPAD) },
{ HID_USB_DEVICE(USB_VENDOR_ID_GRETAGMACBETH, USB_DEVICE_ID_GRETAGMACBETH_HUEY) },
{ HID_USB_DEVICE(USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_POWERMATE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_SOUNDKNOB) },
+ + { HID_USB_DEVICE(USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_RADIOSHARK) },
{ HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_90) },
{ HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_100) },
{ HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_101) },
#define USB_VENDOR_ID_EMS 0x2006
#define USB_DEVICE_ID_EMS_TRIO_LINKER_PLUS_II 0x0118
+++++++#define USB_VENDOR_ID_FLATFROG 0x25b5
+++++++#define USB_DEVICE_ID_MULTITOUCH_3200 0x0002
+++++++
#define USB_VENDOR_ID_ESSENTIAL_REALITY 0x0d7f
#define USB_DEVICE_ID_ESSENTIAL_REALITY_P5 0x0100
#define USB_VENDOR_ID_GRIFFIN 0x077d
#define USB_DEVICE_ID_POWERMATE 0x0410
#define USB_DEVICE_ID_SOUNDKNOB 0x04AA
+ + #define USB_DEVICE_ID_RADIOSHARK 0x627a
#define USB_VENDOR_ID_GTCO 0x078c
#define USB_DEVICE_ID_GTCO_90 0x0090
#define USB_DEVICE_ID_LOGITECH_RECEIVER 0xc101
#define USB_DEVICE_ID_LOGITECH_HARMONY_FIRST 0xc110
#define USB_DEVICE_ID_LOGITECH_HARMONY_LAST 0xc14f
++++ +++#define USB_DEVICE_ID_LOGITECH_HARMONY_PS3 0x0306
#define USB_DEVICE_ID_LOGITECH_RUMBLEPAD_CORD 0xc20a
#define USB_DEVICE_ID_LOGITECH_RUMBLEPAD 0xc211
#define USB_DEVICE_ID_LOGITECH_EXTREME_3D 0xc215
#define USB_VENDOR_ID_SONY 0x054c
#define USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE 0x024b
++++ +++#define USB_DEVICE_ID_SONY_PS3_BDREMOTE 0x0306
#define USB_DEVICE_ID_SONY_PS3_CONTROLLER 0x0268
#define USB_DEVICE_ID_SONY_NAVIGATION_CONTROLLER 0x042f
#define USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U 0x0005
#define USB_DEVICE_ID_UCLOGIC_TABLET_WP1062 0x0064
#define USB_DEVICE_ID_UCLOGIC_WIRELESS_TABLET_TWHL850 0x0522
+++++ ++#define USB_DEVICE_ID_UCLOGIC_TABLET_TWHA60 0x0781
#define USB_VENDOR_ID_UNITEC 0x227d
#define USB_DEVICE_ID_UNITEC_USB_TOUCH_0709 0x0709
switch (psmouse->packet[0] >> FSP_PKT_TYPE_SHIFT) {
case FSP_PKT_TYPE_ABS:
+ + +++
+ + +++ if ((packet[0] == 0x48 || packet[0] == 0x49) &&
+ + +++ packet[1] == 0 && packet[2] == 0) {
+ + +++ /*
+ + +++ * Ignore coordinate noise when finger leaving the
+ + +++ * surface, otherwise cursor may jump to upper-left
+ + +++ * corner.
+ + +++ */
+ + +++ packet[3] &= 0xf0;
+ + +++ }
+ + +++
abs_x = GET_ABS_X(packet);
abs_y = GET_ABS_Y(packet);
input_set_abs_params(dev, ABS_X, 0, abs_x, 0, 0);
input_set_abs_params(dev, ABS_Y, 0, abs_y, 0, 0);
------- input_mt_init_slots(dev, 2);
+++++++ input_mt_init_slots(dev, 2, 0);
input_set_abs_params(dev, ABS_MT_POSITION_X, 0, abs_x, 0, 0);
input_set_abs_params(dev, ABS_MT_POSITION_Y, 0, abs_y, 0, 0);
}
input_report_abs(input, ABS_X, le16_to_cpup((__le16 *)&data[2]));
input_report_abs(input, ABS_Y, le16_to_cpup((__le16 *)&data[4]));
if (wacom->tool[0] != BTN_TOOL_MOUSE) {
- - input_report_abs(input, ABS_PRESSURE, data[6] | ((data[7] & 0x01) << 8));
+ + input_report_abs(input, ABS_PRESSURE, data[6] | ((data[7] & 0x03) << 8));
input_report_key(input, BTN_TOUCH, data[1] & 0x01);
input_report_key(input, BTN_STYLUS, data[1] & 0x02);
input_report_key(input, BTN_STYLUS2, data[1] & 0x04);
t = (data[6] << 2) | ((data[7] >> 6) & 3);
if ((features->type >= INTUOS4S && features->type <= INTUOS4L) ||
(features->type >= INTUOS5S && features->type <= INTUOS5L) ||
- - features->type == WACOM_21UX2 || features->type == WACOM_24HD) {
+ + (features->type >= WACOM_21UX2 && features->type <= WACOM_24HD)) {
t = (t << 1) | (data[1] & 1);
}
input_report_abs(input, ABS_PRESSURE, t);
input_report_abs(input, ABS_MISC, 0);
}
} else {
- - if (features->type == WACOM_21UX2) {
+ + if (features->type == WACOM_21UX2 || features->type == WACOM_22HD) {
input_report_key(input, BTN_0, (data[5] & 0x01));
input_report_key(input, BTN_1, (data[6] & 0x01));
input_report_key(input, BTN_2, (data[6] & 0x02));
input_report_key(input, BTN_Z, (data[8] & 0x20));
input_report_key(input, BTN_BASE, (data[8] & 0x40));
input_report_key(input, BTN_BASE2, (data[8] & 0x80));
+ +
+ + if (features->type == WACOM_22HD) {
+ + input_report_key(input, KEY_PROG1, data[9] & 0x01);
+ + input_report_key(input, KEY_PROG2, data[9] & 0x02);
+ + input_report_key(input, KEY_PROG3, data[9] & 0x04);
+ + }
} else {
input_report_key(input, BTN_0, (data[5] & 0x01));
input_report_key(input, BTN_1, (data[5] & 0x02));
prox = data[0] & 0x01;
x = get_unaligned_le16(&data[1]);
y = get_unaligned_le16(&data[3]);
- - } else { /* with capacity */
+ + } else {
prox = data[1] & 0x01;
x = le16_to_cpup((__le16 *)&data[2]);
y = le16_to_cpup((__le16 *)&data[4]);
case WACOM_REPORT_TPC1FG:
case WACOM_REPORT_TPCHID:
case WACOM_REPORT_TPCST:
+ + case WACOM_REPORT_TPC1FGE:
return wacom_tpc_single_touch(wacom, len);
case WACOM_REPORT_TPCMT:
case CINTIQ:
case WACOM_BEE:
case WACOM_21UX2:
+ + case WACOM_22HD:
case WACOM_24HD:
sync = wacom_intuos_irq(wacom_wac);
break;
break;
case TABLETPC:
+ + case TABLETPCE:
case TABLETPC2FG:
case MTSCREEN:
sync = wacom_tpc_irq(wacom_wac, len);
}
/* these device have multiple inputs */
- - if (features->type == TABLETPC || features->type == TABLETPC2FG ||
- - features->type == BAMBOO_PT || features->type == WIRELESS ||
- - (features->type >= INTUOS5S && features->type <= INTUOS5L) ||
- - features->type == MTSCREEN)
+ + if (features->type >= WIRELESS ||
+ + (features->type >= INTUOS5S && features->type <= INTUOS5L))
features->quirks |= WACOM_QUIRK_MULTI_INPUT;
/* quirk for bamboo touch with 2 low res touches */
wacom_setup_cintiq(wacom_wac);
break;
+ + case WACOM_22HD:
+ + __set_bit(KEY_PROG1, input_dev->keybit);
+ + __set_bit(KEY_PROG2, input_dev->keybit);
+ + __set_bit(KEY_PROG3, input_dev->keybit);
+ + /* fall through */
+ +
case WACOM_21UX2:
__set_bit(BTN_A, input_dev->keybit);
__set_bit(BTN_B, input_dev->keybit);
__set_bit(BTN_TOOL_TRIPLETAP, input_dev->keybit);
__set_bit(BTN_TOOL_QUADTAP, input_dev->keybit);
------- input_mt_init_slots(input_dev, features->touch_max);
+++++++ input_mt_init_slots(input_dev, features->touch_max, 0);
input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR,
0, 255, 0, 0);
__set_bit(INPUT_PROP_POINTER, input_dev->propbit);
break;
- - case TABLETPC2FG:
case MTSCREEN:
if (features->device_type == BTN_TOOL_FINGER) {
- -
wacom_wac->slots = kmalloc(features->touch_max *
sizeof(int),
GFP_KERNEL);
for (i = 0; i < features->touch_max; i++)
wacom_wac->slots[i] = -1;
+ + }
+ + /* fall through */
- - input_mt_init_slots(input_dev, features->touch_max);
+ + case TABLETPC2FG:
+ + if (features->device_type == BTN_TOOL_FINGER) {
-- -- - input_mt_init_slots(input_dev, features->touch_max);
+++++++ input_mt_init_slots(input_dev, features->touch_max, 0);
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,
/* fall through */
case TABLETPC:
+ + case TABLETPCE:
__clear_bit(ABS_MISC, input_dev->absbit);
__set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
__set_bit(BTN_TOOL_FINGER, input_dev->keybit);
__set_bit(BTN_TOOL_DOUBLETAP, input_dev->keybit);
------- input_mt_init_slots(input_dev, features->touch_max);
+++++++ input_mt_init_slots(input_dev, features->touch_max, 0);
if (features->pktlen == WACOM_PKGLEN_BBTOUCH3) {
__set_bit(BTN_TOOL_TRIPLETAP,
{ "Wacom Intuos5 M", WACOM_PKGLEN_INTUOS, 44704, 27940, 2047,
63, INTUOS5, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
static const struct wacom_features wacom_features_0xF4 =
- - --- { "Wacom Cintiq 24HD", WACOM_PKGLEN_INTUOS, 104480, 65600, 2047,
+ + +++ { "Wacom Cintiq 24HD", WACOM_PKGLEN_INTUOS, 104480, 65600, 2047,
+ + +++ 63, WACOM_24HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
+ + +++static const struct wacom_features wacom_features_0xF8 =
+ + +++ { "Wacom Cintiq 24HD touch", WACOM_PKGLEN_INTUOS, 104480, 65600, 2047,
63, WACOM_24HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
static const struct wacom_features wacom_features_0x3F =
{ "Wacom Cintiq 21UX", WACOM_PKGLEN_INTUOS, 87200, 65600, 1023,
static const struct wacom_features wacom_features_0xCC =
{ "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_0xFA =
+ + { "Wacom Cintiq 22HD", WACOM_PKGLEN_INTUOS, 95840, 54260, 2047,
+ + 63, WACOM_22HD, 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_INTUOS_RES, WACOM_INTUOS_RES };
static const struct wacom_features wacom_features_0xEC =
{ "Wacom ISDv4 EC", WACOM_PKGLEN_GRAPHIRE, 25710, 14500, 255,
0, TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+ + static const struct wacom_features wacom_features_0xED =
+ + { "Wacom ISDv4 ED", WACOM_PKGLEN_GRAPHIRE, 26202, 16325, 255,
+ + 0, TABLETPCE, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+ + static const struct wacom_features wacom_features_0xEF =
+ + { "Wacom ISDv4 EF", WACOM_PKGLEN_GRAPHIRE, 26202, 16325, 255,
+ + 0, TABLETPC, 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 };
{ USB_DEVICE_WACOM(0xE5) },
{ USB_DEVICE_WACOM(0xE6) },
{ USB_DEVICE_WACOM(0xEC) },
+ + { USB_DEVICE_WACOM(0xED) },
+ + { USB_DEVICE_WACOM(0xEF) },
{ USB_DEVICE_WACOM(0x47) },
{ USB_DEVICE_WACOM(0xF4) },
+ + +++ { USB_DEVICE_WACOM(0xF8) },
+ + { USB_DEVICE_WACOM(0xFA) },
{ USB_DEVICE_LENOVO(0x6004) },
{ }
};
--- /dev/null
--- /dev/null
- - - error = copy_to_user(buf, tsdata->raw_buffer + *off, read);
- - - if (!error)
- - - *off += read;
+ + /*
+ + * Copyright (C) 2012 Simon Budig, <simon.budig@kernelconcepts.de>
+ + *
+ + * This software is licensed under the terms of the GNU General Public
+ + * License version 2, as published by the Free Software Foundation, and
+ + * may be copied, distributed, and modified under those terms.
+ + *
+ + * 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 library; if not, write to the Free Software
+ + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ + */
+ +
+ + /*
+ + * This is a driver for the EDT "Polytouch" family of touch controllers
+ + * based on the FocalTech FT5x06 line of chips.
+ + *
+ + * Development of this driver has been sponsored by Glyn:
+ + * http://www.glyn.com/Products/Displays
+ + */
+ +
+ + #include <linux/module.h>
+ + #include <linux/ratelimit.h>
+ + #include <linux/interrupt.h>
+ + #include <linux/input.h>
+ + #include <linux/i2c.h>
+ + #include <linux/uaccess.h>
+ + #include <linux/delay.h>
+ + #include <linux/debugfs.h>
+ + #include <linux/slab.h>
+ + #include <linux/gpio.h>
+ + #include <linux/input/mt.h>
+ + #include <linux/input/edt-ft5x06.h>
+ +
+ + #define MAX_SUPPORT_POINTS 5
+ +
+ + #define WORK_REGISTER_THRESHOLD 0x00
+ + #define WORK_REGISTER_REPORT_RATE 0x08
+ + #define WORK_REGISTER_GAIN 0x30
+ + #define WORK_REGISTER_OFFSET 0x31
+ + #define WORK_REGISTER_NUM_X 0x33
+ + #define WORK_REGISTER_NUM_Y 0x34
+ +
+ + #define WORK_REGISTER_OPMODE 0x3c
+ + #define FACTORY_REGISTER_OPMODE 0x01
+ +
+ + #define TOUCH_EVENT_DOWN 0x00
+ + #define TOUCH_EVENT_UP 0x01
+ + #define TOUCH_EVENT_ON 0x02
+ + #define TOUCH_EVENT_RESERVED 0x03
+ +
+ + #define EDT_NAME_LEN 23
+ + #define EDT_SWITCH_MODE_RETRIES 10
+ + #define EDT_SWITCH_MODE_DELAY 5 /* msec */
+ + #define EDT_RAW_DATA_RETRIES 100
+ + #define EDT_RAW_DATA_DELAY 1 /* msec */
+ +
+ + struct edt_ft5x06_ts_data {
+ + struct i2c_client *client;
+ + struct input_dev *input;
+ + u16 num_x;
+ + u16 num_y;
+ +
+ + #if defined(CONFIG_DEBUG_FS)
+ + struct dentry *debug_dir;
+ + u8 *raw_buffer;
+ + size_t raw_bufsize;
+ + #endif
+ +
+ + struct mutex mutex;
+ + bool factory_mode;
+ + int threshold;
+ + int gain;
+ + int offset;
+ + int report_rate;
+ +
+ + char name[EDT_NAME_LEN];
+ + };
+ +
+ + static int edt_ft5x06_ts_readwrite(struct i2c_client *client,
+ + u16 wr_len, u8 *wr_buf,
+ + u16 rd_len, u8 *rd_buf)
+ + {
+ + struct i2c_msg wrmsg[2];
+ + int i = 0;
+ + int ret;
+ +
+ + if (wr_len) {
+ + wrmsg[i].addr = client->addr;
+ + wrmsg[i].flags = 0;
+ + wrmsg[i].len = wr_len;
+ + wrmsg[i].buf = wr_buf;
+ + i++;
+ + }
+ + if (rd_len) {
+ + wrmsg[i].addr = client->addr;
+ + wrmsg[i].flags = I2C_M_RD;
+ + wrmsg[i].len = rd_len;
+ + wrmsg[i].buf = rd_buf;
+ + i++;
+ + }
+ +
+ + ret = i2c_transfer(client->adapter, wrmsg, i);
+ + if (ret < 0)
+ + return ret;
+ + if (ret != i)
+ + return -EIO;
+ +
+ + return 0;
+ + }
+ +
+ + static bool edt_ft5x06_ts_check_crc(struct edt_ft5x06_ts_data *tsdata,
+ + u8 *buf, int buflen)
+ + {
+ + int i;
+ + u8 crc = 0;
+ +
+ + for (i = 0; i < buflen - 1; i++)
+ + crc ^= buf[i];
+ +
+ + if (crc != buf[buflen-1]) {
+ + dev_err_ratelimited(&tsdata->client->dev,
+ + "crc error: 0x%02x expected, got 0x%02x\n",
+ + crc, buf[buflen-1]);
+ + return false;
+ + }
+ +
+ + return true;
+ + }
+ +
+ + static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id)
+ + {
+ + struct edt_ft5x06_ts_data *tsdata = dev_id;
+ + struct device *dev = &tsdata->client->dev;
+ + u8 cmd = 0xf9;
+ + u8 rdbuf[26];
+ + int i, type, x, y, id;
+ + int error;
+ +
+ + memset(rdbuf, 0, sizeof(rdbuf));
+ +
+ + error = edt_ft5x06_ts_readwrite(tsdata->client,
+ + sizeof(cmd), &cmd,
+ + sizeof(rdbuf), rdbuf);
+ + if (error) {
+ + dev_err_ratelimited(dev, "Unable to fetch data, error: %d\n",
+ + error);
+ + goto out;
+ + }
+ +
+ + if (rdbuf[0] != 0xaa || rdbuf[1] != 0xaa || rdbuf[2] != 26) {
+ + dev_err_ratelimited(dev, "Unexpected header: %02x%02x%02x!\n",
+ + rdbuf[0], rdbuf[1], rdbuf[2]);
+ + goto out;
+ + }
+ +
+ + if (!edt_ft5x06_ts_check_crc(tsdata, rdbuf, 26))
+ + goto out;
+ +
+ + for (i = 0; i < MAX_SUPPORT_POINTS; i++) {
+ + u8 *buf = &rdbuf[i * 4 + 5];
+ + bool down;
+ +
+ + type = buf[0] >> 6;
+ + /* ignore Reserved events */
+ + if (type == TOUCH_EVENT_RESERVED)
+ + continue;
+ +
+ + x = ((buf[0] << 8) | buf[1]) & 0x0fff;
+ + y = ((buf[2] << 8) | buf[3]) & 0x0fff;
+ + id = (buf[2] >> 4) & 0x0f;
+ + down = (type != TOUCH_EVENT_UP);
+ +
+ + input_mt_slot(tsdata->input, id);
+ + input_mt_report_slot_state(tsdata->input, MT_TOOL_FINGER, down);
+ +
+ + if (!down)
+ + continue;
+ +
+ + input_report_abs(tsdata->input, ABS_MT_POSITION_X, x);
+ + input_report_abs(tsdata->input, ABS_MT_POSITION_Y, y);
+ + }
+ +
+ + input_mt_report_pointer_emulation(tsdata->input, true);
+ + input_sync(tsdata->input);
+ +
+ + out:
+ + return IRQ_HANDLED;
+ + }
+ +
+ + static int edt_ft5x06_register_write(struct edt_ft5x06_ts_data *tsdata,
+ + u8 addr, u8 value)
+ + {
+ + u8 wrbuf[4];
+ +
+ + wrbuf[0] = tsdata->factory_mode ? 0xf3 : 0xfc;
+ + wrbuf[1] = tsdata->factory_mode ? addr & 0x7f : addr & 0x3f;
+ + wrbuf[2] = value;
+ + wrbuf[3] = wrbuf[0] ^ wrbuf[1] ^ wrbuf[2];
+ +
+ + return edt_ft5x06_ts_readwrite(tsdata->client, 4, wrbuf, 0, NULL);
+ + }
+ +
+ + static int edt_ft5x06_register_read(struct edt_ft5x06_ts_data *tsdata,
+ + u8 addr)
+ + {
+ + u8 wrbuf[2], rdbuf[2];
+ + int error;
+ +
+ + wrbuf[0] = tsdata->factory_mode ? 0xf3 : 0xfc;
+ + wrbuf[1] = tsdata->factory_mode ? addr & 0x7f : addr & 0x3f;
+ + wrbuf[1] |= tsdata->factory_mode ? 0x80 : 0x40;
+ +
+ + error = edt_ft5x06_ts_readwrite(tsdata->client, 2, wrbuf, 2, rdbuf);
+ + if (error)
+ + return error;
+ +
+ + if ((wrbuf[0] ^ wrbuf[1] ^ rdbuf[0]) != rdbuf[1]) {
+ + dev_err(&tsdata->client->dev,
+ + "crc error: 0x%02x expected, got 0x%02x\n",
+ + wrbuf[0] ^ wrbuf[1] ^ rdbuf[0], rdbuf[1]);
+ + return -EIO;
+ + }
+ +
+ + return rdbuf[0];
+ + }
+ +
+ + struct edt_ft5x06_attribute {
+ + struct device_attribute dattr;
+ + size_t field_offset;
+ + u8 limit_low;
+ + u8 limit_high;
+ + u8 addr;
+ + };
+ +
+ + #define EDT_ATTR(_field, _mode, _addr, _limit_low, _limit_high) \
+ + struct edt_ft5x06_attribute edt_ft5x06_attr_##_field = { \
+ + .dattr = __ATTR(_field, _mode, \
+ + edt_ft5x06_setting_show, \
+ + edt_ft5x06_setting_store), \
+ + .field_offset = \
+ + offsetof(struct edt_ft5x06_ts_data, _field), \
+ + .limit_low = _limit_low, \
+ + .limit_high = _limit_high, \
+ + .addr = _addr, \
+ + }
+ +
+ + static ssize_t edt_ft5x06_setting_show(struct device *dev,
+ + struct device_attribute *dattr,
+ + char *buf)
+ + {
+ + struct i2c_client *client = to_i2c_client(dev);
+ + struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(client);
+ + struct edt_ft5x06_attribute *attr =
+ + container_of(dattr, struct edt_ft5x06_attribute, dattr);
+ + u8 *field = (u8 *)((char *)tsdata + attr->field_offset);
+ + int val;
+ + size_t count = 0;
+ + int error = 0;
+ +
+ + mutex_lock(&tsdata->mutex);
+ +
+ + if (tsdata->factory_mode) {
+ + error = -EIO;
+ + goto out;
+ + }
+ +
+ + val = edt_ft5x06_register_read(tsdata, attr->addr);
+ + if (val < 0) {
+ + error = val;
+ + dev_err(&tsdata->client->dev,
+ + "Failed to fetch attribute %s, error %d\n",
+ + dattr->attr.name, error);
+ + goto out;
+ + }
+ +
+ + if (val != *field) {
+ + dev_warn(&tsdata->client->dev,
+ + "%s: read (%d) and stored value (%d) differ\n",
+ + dattr->attr.name, val, *field);
+ + *field = val;
+ + }
+ +
+ + count = scnprintf(buf, PAGE_SIZE, "%d\n", val);
+ + out:
+ + mutex_unlock(&tsdata->mutex);
+ + return error ?: count;
+ + }
+ +
+ + static ssize_t edt_ft5x06_setting_store(struct device *dev,
+ + struct device_attribute *dattr,
+ + const char *buf, size_t count)
+ + {
+ + struct i2c_client *client = to_i2c_client(dev);
+ + struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(client);
+ + struct edt_ft5x06_attribute *attr =
+ + container_of(dattr, struct edt_ft5x06_attribute, dattr);
+ + u8 *field = (u8 *)((char *)tsdata + attr->field_offset);
+ + unsigned int val;
+ + int error;
+ +
+ + mutex_lock(&tsdata->mutex);
+ +
+ + if (tsdata->factory_mode) {
+ + error = -EIO;
+ + goto out;
+ + }
+ +
+ + error = kstrtouint(buf, 0, &val);
+ + if (error)
+ + goto out;
+ +
+ + if (val < attr->limit_low || val > attr->limit_high) {
+ + error = -ERANGE;
+ + goto out;
+ + }
+ +
+ + error = edt_ft5x06_register_write(tsdata, attr->addr, val);
+ + if (error) {
+ + dev_err(&tsdata->client->dev,
+ + "Failed to update attribute %s, error: %d\n",
+ + dattr->attr.name, error);
+ + goto out;
+ + }
+ +
+ + *field = val;
+ +
+ + out:
+ + mutex_unlock(&tsdata->mutex);
+ + return error ?: count;
+ + }
+ +
+ + static EDT_ATTR(gain, S_IWUSR | S_IRUGO, WORK_REGISTER_GAIN, 0, 31);
+ + static EDT_ATTR(offset, S_IWUSR | S_IRUGO, WORK_REGISTER_OFFSET, 0, 31);
+ + static EDT_ATTR(threshold, S_IWUSR | S_IRUGO,
+ + WORK_REGISTER_THRESHOLD, 20, 80);
+ + static EDT_ATTR(report_rate, S_IWUSR | S_IRUGO,
+ + WORK_REGISTER_REPORT_RATE, 3, 14);
+ +
+ + static struct attribute *edt_ft5x06_attrs[] = {
+ + &edt_ft5x06_attr_gain.dattr.attr,
+ + &edt_ft5x06_attr_offset.dattr.attr,
+ + &edt_ft5x06_attr_threshold.dattr.attr,
+ + &edt_ft5x06_attr_report_rate.dattr.attr,
+ + NULL
+ + };
+ +
+ + static const struct attribute_group edt_ft5x06_attr_group = {
+ + .attrs = edt_ft5x06_attrs,
+ + };
+ +
+ + #ifdef CONFIG_DEBUG_FS
+ + static int edt_ft5x06_factory_mode(struct edt_ft5x06_ts_data *tsdata)
+ + {
+ + struct i2c_client *client = tsdata->client;
+ + int retries = EDT_SWITCH_MODE_RETRIES;
+ + int ret;
+ + int error;
+ +
+ + disable_irq(client->irq);
+ +
+ + if (!tsdata->raw_buffer) {
+ + tsdata->raw_bufsize = tsdata->num_x * tsdata->num_y *
+ + sizeof(u16);
+ + tsdata->raw_buffer = kzalloc(tsdata->raw_bufsize, GFP_KERNEL);
+ + if (!tsdata->raw_buffer) {
+ + error = -ENOMEM;
+ + goto err_out;
+ + }
+ + }
+ +
+ + /* mode register is 0x3c when in the work mode */
+ + error = edt_ft5x06_register_write(tsdata, WORK_REGISTER_OPMODE, 0x03);
+ + if (error) {
+ + dev_err(&client->dev,
+ + "failed to switch to factory mode, error %d\n", error);
+ + goto err_out;
+ + }
+ +
+ + tsdata->factory_mode = true;
+ + do {
+ + mdelay(EDT_SWITCH_MODE_DELAY);
+ + /* mode register is 0x01 when in factory mode */
+ + ret = edt_ft5x06_register_read(tsdata, FACTORY_REGISTER_OPMODE);
+ + if (ret == 0x03)
+ + break;
+ + } while (--retries > 0);
+ +
+ + if (retries == 0) {
+ + dev_err(&client->dev, "not in factory mode after %dms.\n",
+ + EDT_SWITCH_MODE_RETRIES * EDT_SWITCH_MODE_DELAY);
+ + error = -EIO;
+ + goto err_out;
+ + }
+ +
+ + return 0;
+ +
+ + err_out:
+ + kfree(tsdata->raw_buffer);
+ + tsdata->raw_buffer = NULL;
+ + tsdata->factory_mode = false;
+ + enable_irq(client->irq);
+ +
+ + return error;
+ + }
+ +
+ + static int edt_ft5x06_work_mode(struct edt_ft5x06_ts_data *tsdata)
+ + {
+ + struct i2c_client *client = tsdata->client;
+ + int retries = EDT_SWITCH_MODE_RETRIES;
+ + int ret;
+ + int error;
+ +
+ + /* mode register is 0x01 when in the factory mode */
+ + error = edt_ft5x06_register_write(tsdata, FACTORY_REGISTER_OPMODE, 0x1);
+ + if (error) {
+ + dev_err(&client->dev,
+ + "failed to switch to work mode, error: %d\n", error);
+ + return error;
+ + }
+ +
+ + tsdata->factory_mode = false;
+ +
+ + do {
+ + mdelay(EDT_SWITCH_MODE_DELAY);
+ + /* mode register is 0x01 when in factory mode */
+ + ret = edt_ft5x06_register_read(tsdata, WORK_REGISTER_OPMODE);
+ + if (ret == 0x01)
+ + break;
+ + } while (--retries > 0);
+ +
+ + if (retries == 0) {
+ + dev_err(&client->dev, "not in work mode after %dms.\n",
+ + EDT_SWITCH_MODE_RETRIES * EDT_SWITCH_MODE_DELAY);
+ + tsdata->factory_mode = true;
+ + return -EIO;
+ + }
+ +
+ + if (tsdata->raw_buffer)
+ + kfree(tsdata->raw_buffer);
+ + tsdata->raw_buffer = NULL;
+ +
+ + /* restore parameters */
+ + edt_ft5x06_register_write(tsdata, WORK_REGISTER_THRESHOLD,
+ + tsdata->threshold);
+ + edt_ft5x06_register_write(tsdata, WORK_REGISTER_GAIN,
+ + tsdata->gain);
+ + edt_ft5x06_register_write(tsdata, WORK_REGISTER_OFFSET,
+ + tsdata->offset);
+ + edt_ft5x06_register_write(tsdata, WORK_REGISTER_REPORT_RATE,
+ + tsdata->report_rate);
+ +
+ + enable_irq(client->irq);
+ +
+ + return 0;
+ + }
+ +
+ + static int edt_ft5x06_debugfs_mode_get(void *data, u64 *mode)
+ + {
+ + struct edt_ft5x06_ts_data *tsdata = data;
+ +
+ + *mode = tsdata->factory_mode;
+ +
+ + return 0;
+ + };
+ +
+ + static int edt_ft5x06_debugfs_mode_set(void *data, u64 mode)
+ + {
+ + struct edt_ft5x06_ts_data *tsdata = data;
+ + int retval = 0;
+ +
+ + if (mode > 1)
+ + return -ERANGE;
+ +
+ + mutex_lock(&tsdata->mutex);
+ +
+ + if (mode != tsdata->factory_mode) {
+ + retval = mode ? edt_ft5x06_factory_mode(tsdata) :
+ + edt_ft5x06_work_mode(tsdata);
+ + }
+ +
+ + mutex_unlock(&tsdata->mutex);
+ +
+ + return retval;
+ + };
+ +
+ + DEFINE_SIMPLE_ATTRIBUTE(debugfs_mode_fops, edt_ft5x06_debugfs_mode_get,
+ + edt_ft5x06_debugfs_mode_set, "%llu\n");
+ +
+ + static int edt_ft5x06_debugfs_raw_data_open(struct inode *inode,
+ + struct file *file)
+ + {
+ + file->private_data = inode->i_private;
+ +
+ + return 0;
+ + }
+ +
+ + static ssize_t edt_ft5x06_debugfs_raw_data_read(struct file *file,
+ + char __user *buf, size_t count, loff_t *off)
+ + {
+ + struct edt_ft5x06_ts_data *tsdata = file->private_data;
+ + struct i2c_client *client = tsdata->client;
+ + int retries = EDT_RAW_DATA_RETRIES;
+ + int val, i, error;
+ + size_t read = 0;
+ + int colbytes;
+ + char wrbuf[3];
+ + u8 *rdbuf;
+ +
+ + if (*off < 0 || *off >= tsdata->raw_bufsize)
+ + return 0;
+ +
+ + mutex_lock(&tsdata->mutex);
+ +
+ + if (!tsdata->factory_mode || !tsdata->raw_buffer) {
+ + error = -EIO;
+ + goto out;
+ + }
+ +
+ + error = edt_ft5x06_register_write(tsdata, 0x08, 0x01);
+ + if (error) {
+ + dev_dbg(&client->dev,
+ + "failed to write 0x08 register, error %d\n", error);
+ + goto out;
+ + }
+ +
+ + do {
+ + msleep(EDT_RAW_DATA_DELAY);
+ + val = edt_ft5x06_register_read(tsdata, 0x08);
+ + if (val < 1)
+ + break;
+ + } while (--retries > 0);
+ +
+ + if (val < 0) {
+ + error = val;
+ + dev_dbg(&client->dev,
+ + "failed to read 0x08 register, error %d\n", error);
+ + goto out;
+ + }
+ +
+ + if (retries == 0) {
+ + dev_dbg(&client->dev,
+ + "timed out waiting for register to settle\n");
+ + error = -ETIMEDOUT;
+ + goto out;
+ + }
+ +
+ + rdbuf = tsdata->raw_buffer;
+ + colbytes = tsdata->num_y * sizeof(u16);
+ +
+ + wrbuf[0] = 0xf5;
+ + wrbuf[1] = 0x0e;
+ + for (i = 0; i < tsdata->num_x; i++) {
+ + wrbuf[2] = i; /* column index */
+ + error = edt_ft5x06_ts_readwrite(tsdata->client,
+ + sizeof(wrbuf), wrbuf,
+ + colbytes, rdbuf);
+ + if (error)
+ + goto out;
+ +
+ + rdbuf += colbytes;
+ + }
+ +
+ + read = min_t(size_t, count, tsdata->raw_bufsize - *off);
-- -- - error = input_mt_init_slots(input, MAX_SUPPORT_POINTS);
+ + +++ if (copy_to_user(buf, tsdata->raw_buffer + *off, read)) {
+ + +++ error = -EFAULT;
+ + +++ goto out;
+ + +++ }
+ + +++
+ + +++ *off += read;
+ + out:
+ + mutex_unlock(&tsdata->mutex);
+ + return error ?: read;
+ + };
+ +
+ +
+ + static const struct file_operations debugfs_raw_data_fops = {
+ + .open = edt_ft5x06_debugfs_raw_data_open,
+ + .read = edt_ft5x06_debugfs_raw_data_read,
+ + };
+ +
+ + static void __devinit
+ + edt_ft5x06_ts_prepare_debugfs(struct edt_ft5x06_ts_data *tsdata,
+ + const char *debugfs_name)
+ + {
+ + tsdata->debug_dir = debugfs_create_dir(debugfs_name, NULL);
+ + if (!tsdata->debug_dir)
+ + return;
+ +
+ + debugfs_create_u16("num_x", S_IRUSR, tsdata->debug_dir, &tsdata->num_x);
+ + debugfs_create_u16("num_y", S_IRUSR, tsdata->debug_dir, &tsdata->num_y);
+ +
+ + debugfs_create_file("mode", S_IRUSR | S_IWUSR,
+ + tsdata->debug_dir, tsdata, &debugfs_mode_fops);
+ + debugfs_create_file("raw_data", S_IRUSR,
+ + tsdata->debug_dir, tsdata, &debugfs_raw_data_fops);
+ + }
+ +
+ + static void __devexit
+ + edt_ft5x06_ts_teardown_debugfs(struct edt_ft5x06_ts_data *tsdata)
+ + {
+ + if (tsdata->debug_dir)
+ + debugfs_remove_recursive(tsdata->debug_dir);
+ + +++ kfree(tsdata->raw_buffer);
+ + }
+ +
+ + #else
+ +
+ + static inline void
+ + edt_ft5x06_ts_prepare_debugfs(struct edt_ft5x06_ts_data *tsdata,
+ + const char *debugfs_name)
+ + {
+ + }
+ +
+ + static inline void
+ + edt_ft5x06_ts_teardown_debugfs(struct edt_ft5x06_ts_data *tsdata)
+ + {
+ + }
+ +
+ + #endif /* CONFIG_DEBUGFS */
+ +
+ +
+ +
+ + static int __devinit edt_ft5x06_ts_reset(struct i2c_client *client,
+ + int reset_pin)
+ + {
+ + int error;
+ +
+ + if (gpio_is_valid(reset_pin)) {
+ + /* this pulls reset down, enabling the low active reset */
+ + error = gpio_request_one(reset_pin, GPIOF_OUT_INIT_LOW,
+ + "edt-ft5x06 reset");
+ + if (error) {
+ + dev_err(&client->dev,
+ + "Failed to request GPIO %d as reset pin, error %d\n",
+ + reset_pin, error);
+ + return error;
+ + }
+ +
+ + mdelay(50);
+ + gpio_set_value(reset_pin, 1);
+ + mdelay(100);
+ + }
+ +
+ + return 0;
+ + }
+ +
+ + static int __devinit edt_ft5x06_ts_identify(struct i2c_client *client,
+ + char *model_name,
+ + char *fw_version)
+ + {
+ + u8 rdbuf[EDT_NAME_LEN];
+ + char *p;
+ + int error;
+ +
+ + error = edt_ft5x06_ts_readwrite(client, 1, "\xbb",
+ + EDT_NAME_LEN - 1, rdbuf);
+ + if (error)
+ + return error;
+ +
+ + /* remove last '$' end marker */
+ + rdbuf[EDT_NAME_LEN - 1] = '\0';
+ + if (rdbuf[EDT_NAME_LEN - 2] == '$')
+ + rdbuf[EDT_NAME_LEN - 2] = '\0';
+ +
+ + /* look for Model/Version separator */
+ + p = strchr(rdbuf, '*');
+ + if (p)
+ + *p++ = '\0';
+ +
+ + strlcpy(model_name, rdbuf + 1, EDT_NAME_LEN);
+ + strlcpy(fw_version, p ? p : "", EDT_NAME_LEN);
+ +
+ + return 0;
+ + }
+ +
+ + #define EDT_ATTR_CHECKSET(name, reg) \
+ + if (pdata->name >= edt_ft5x06_attr_##name.limit_low && \
+ + pdata->name <= edt_ft5x06_attr_##name.limit_high) \
+ + edt_ft5x06_register_write(tsdata, reg, pdata->name)
+ +
+ + static void __devinit
+ + edt_ft5x06_ts_get_defaults(struct edt_ft5x06_ts_data *tsdata,
+ + const struct edt_ft5x06_platform_data *pdata)
+ + {
+ + if (!pdata->use_parameters)
+ + return;
+ +
+ + /* pick up defaults from the platform data */
+ + EDT_ATTR_CHECKSET(threshold, WORK_REGISTER_THRESHOLD);
+ + EDT_ATTR_CHECKSET(gain, WORK_REGISTER_GAIN);
+ + EDT_ATTR_CHECKSET(offset, WORK_REGISTER_OFFSET);
+ + EDT_ATTR_CHECKSET(report_rate, WORK_REGISTER_REPORT_RATE);
+ + }
+ +
+ + static void __devinit
+ + edt_ft5x06_ts_get_parameters(struct edt_ft5x06_ts_data *tsdata)
+ + {
+ + tsdata->threshold = edt_ft5x06_register_read(tsdata,
+ + WORK_REGISTER_THRESHOLD);
+ + tsdata->gain = edt_ft5x06_register_read(tsdata, WORK_REGISTER_GAIN);
+ + tsdata->offset = edt_ft5x06_register_read(tsdata, WORK_REGISTER_OFFSET);
+ + tsdata->report_rate = edt_ft5x06_register_read(tsdata,
+ + WORK_REGISTER_REPORT_RATE);
+ + tsdata->num_x = edt_ft5x06_register_read(tsdata, WORK_REGISTER_NUM_X);
+ + tsdata->num_y = edt_ft5x06_register_read(tsdata, WORK_REGISTER_NUM_Y);
+ + }
+ +
+ + static int __devinit edt_ft5x06_ts_probe(struct i2c_client *client,
+ + const struct i2c_device_id *id)
+ + {
+ + const struct edt_ft5x06_platform_data *pdata =
+ + client->dev.platform_data;
+ + struct edt_ft5x06_ts_data *tsdata;
+ + struct input_dev *input;
+ + int error;
+ + char fw_version[EDT_NAME_LEN];
+ +
+ + dev_dbg(&client->dev, "probing for EDT FT5x06 I2C\n");
+ +
+ + if (!pdata) {
+ + dev_err(&client->dev, "no platform data?\n");
+ + return -EINVAL;
+ + }
+ +
+ + error = edt_ft5x06_ts_reset(client, pdata->reset_pin);
+ + if (error)
+ + return error;
+ +
+ + if (gpio_is_valid(pdata->irq_pin)) {
+ + error = gpio_request_one(pdata->irq_pin,
+ + GPIOF_IN, "edt-ft5x06 irq");
+ + if (error) {
+ + dev_err(&client->dev,
+ + "Failed to request GPIO %d, error %d\n",
+ + pdata->irq_pin, error);
+ + return error;
+ + }
+ + }
+ +
+ + tsdata = kzalloc(sizeof(*tsdata), GFP_KERNEL);
+ + input = input_allocate_device();
+ + if (!tsdata || !input) {
+ + dev_err(&client->dev, "failed to allocate driver data.\n");
+ + error = -ENOMEM;
+ + goto err_free_mem;
+ + }
+ +
+ + mutex_init(&tsdata->mutex);
+ + tsdata->client = client;
+ + tsdata->input = input;
+ + tsdata->factory_mode = false;
+ +
+ + error = edt_ft5x06_ts_identify(client, tsdata->name, fw_version);
+ + if (error) {
+ + dev_err(&client->dev, "touchscreen probe failed\n");
+ + goto err_free_mem;
+ + }
+ +
+ + edt_ft5x06_ts_get_defaults(tsdata, pdata);
+ + edt_ft5x06_ts_get_parameters(tsdata);
+ +
+ + dev_dbg(&client->dev,
+ + "Model \"%s\", Rev. \"%s\", %dx%d sensors\n",
+ + tsdata->name, fw_version, tsdata->num_x, tsdata->num_y);
+ +
+ + input->name = tsdata->name;
+ + input->id.bustype = BUS_I2C;
+ + input->dev.parent = &client->dev;
+ +
+ + __set_bit(EV_SYN, input->evbit);
+ + __set_bit(EV_KEY, input->evbit);
+ + __set_bit(EV_ABS, input->evbit);
+ + __set_bit(BTN_TOUCH, input->keybit);
+ + input_set_abs_params(input, ABS_X, 0, tsdata->num_x * 64 - 1, 0, 0);
+ + input_set_abs_params(input, ABS_Y, 0, tsdata->num_y * 64 - 1, 0, 0);
+ + input_set_abs_params(input, ABS_MT_POSITION_X,
+ + 0, tsdata->num_x * 64 - 1, 0, 0);
+ + input_set_abs_params(input, ABS_MT_POSITION_Y,
+ + 0, tsdata->num_y * 64 - 1, 0, 0);
- - - kfree(tsdata->raw_buffer);
+++++++ error = input_mt_init_slots(input, MAX_SUPPORT_POINTS, 0);
+ + if (error) {
+ + dev_err(&client->dev, "Unable to init MT slots.\n");
+ + goto err_free_mem;
+ + }
+ +
+ + input_set_drvdata(input, tsdata);
+ + i2c_set_clientdata(client, tsdata);
+ +
+ + error = request_threaded_irq(client->irq, NULL, edt_ft5x06_ts_isr,
+ + IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+ + client->name, tsdata);
+ + if (error) {
+ + dev_err(&client->dev, "Unable to request touchscreen IRQ.\n");
+ + goto err_free_mem;
+ + }
+ +
+ + error = sysfs_create_group(&client->dev.kobj, &edt_ft5x06_attr_group);
+ + if (error)
+ + goto err_free_irq;
+ +
+ + error = input_register_device(input);
+ + if (error)
+ + goto err_remove_attrs;
+ +
+ + edt_ft5x06_ts_prepare_debugfs(tsdata, dev_driver_string(&client->dev));
+ + device_init_wakeup(&client->dev, 1);
+ +
+ + dev_dbg(&client->dev,
+ + "EDT FT5x06 initialized: IRQ pin %d, Reset pin %d.\n",
+ + pdata->irq_pin, pdata->reset_pin);
+ +
+ + return 0;
+ +
+ + err_remove_attrs:
+ + sysfs_remove_group(&client->dev.kobj, &edt_ft5x06_attr_group);
+ + err_free_irq:
+ + free_irq(client->irq, tsdata);
+ + err_free_mem:
+ + input_free_device(input);
+ + kfree(tsdata);
+ +
+ + if (gpio_is_valid(pdata->irq_pin))
+ + gpio_free(pdata->irq_pin);
+ +
+ + return error;
+ + }
+ +
+ + static int __devexit edt_ft5x06_ts_remove(struct i2c_client *client)
+ + {
+ + const struct edt_ft5x06_platform_data *pdata =
+ + dev_get_platdata(&client->dev);
+ + struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(client);
+ +
+ + edt_ft5x06_ts_teardown_debugfs(tsdata);
+ + sysfs_remove_group(&client->dev.kobj, &edt_ft5x06_attr_group);
+ +
+ + free_irq(client->irq, tsdata);
+ + input_unregister_device(tsdata->input);
+ +
+ + if (gpio_is_valid(pdata->irq_pin))
+ + gpio_free(pdata->irq_pin);
+ + if (gpio_is_valid(pdata->reset_pin))
+ + gpio_free(pdata->reset_pin);
+ +
+ + kfree(tsdata);
+ +
+ + return 0;
+ + }
+ +
+ + #ifdef CONFIG_PM_SLEEP
+ + static int edt_ft5x06_ts_suspend(struct device *dev)
+ + {
+ + struct i2c_client *client = to_i2c_client(dev);
+ +
+ + if (device_may_wakeup(dev))
+ + enable_irq_wake(client->irq);
+ +
+ + return 0;
+ + }
+ +
+ + static int edt_ft5x06_ts_resume(struct device *dev)
+ + {
+ + struct i2c_client *client = to_i2c_client(dev);
+ +
+ + if (device_may_wakeup(dev))
+ + disable_irq_wake(client->irq);
+ +
+ + return 0;
+ + }
+ + #endif
+ +
+ + static SIMPLE_DEV_PM_OPS(edt_ft5x06_ts_pm_ops,
+ + edt_ft5x06_ts_suspend, edt_ft5x06_ts_resume);
+ +
+ + static const struct i2c_device_id edt_ft5x06_ts_id[] = {
+ + { "edt-ft5x06", 0 },
+ + { }
+ + };
+ + MODULE_DEVICE_TABLE(i2c, edt_ft5x06_ts_id);
+ +
+ + static struct i2c_driver edt_ft5x06_ts_driver = {
+ + .driver = {
+ + .owner = THIS_MODULE,
+ + .name = "edt_ft5x06",
+ + .pm = &edt_ft5x06_ts_pm_ops,
+ + },
+ + .id_table = edt_ft5x06_ts_id,
+ + .probe = edt_ft5x06_ts_probe,
+ + .remove = __devexit_p(edt_ft5x06_ts_remove),
+ + };
+ +
+ + module_i2c_driver(edt_ft5x06_ts_driver);
+ +
+ + MODULE_AUTHOR("Simon Budig <simon.budig@kernelconcepts.de>");
+ + MODULE_DESCRIPTION("EDT FT5x06 I2C Touchscreen Driver");
+ + MODULE_LICENSE("GPL");