Commit 8691c130 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input

Pull input subsystem updates from Dmitry Torokhov:
 "You will get the following new drivers:

   - Qualcomm PM8941 power key drver
   - ChipOne icn8318 touchscreen controller driver
   - Broadcom iProc touchscreen and keypad drivers
   - Semtech SX8654 I2C touchscreen controller driver

  ALPS driver now supports newer SS4 devices; Elantech got a fix that
  should make it work on some ASUS laptops; and a slew of other
  enhancements and random fixes"

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input: (51 commits)
  Input: alps - non interleaved V2 dualpoint has separate stick button bits
  Input: alps - fix touchpad buttons getting stuck when used with trackpoint
  Input: atkbd - document "no new force-release quirks" policy
  Input: ALPS - make alps_get_pkt_id_ss4_v2() and others static
  Input: ALPS - V7 devices can report 5-finger taps
  Input: ALPS - add support for SS4 touchpad devices
  Input: ALPS - refactor alps_set_abs_params_mt()
  Input: elantech - fix absolute mode setting on some ASUS laptops
  Input: atmel_mxt_ts - split out touchpad initialisation logic
  Input: atmel_mxt_ts - implement support for T100 touch object
  Input: cros_ec_keyb - fix clearing keyboard state on wakeup
  Input: gscps2 - drop pci_ids dependency
  Input: synaptics - allocate 3 slots to keep stability in image sensors
  Input: Revert "Revert "synaptics - use dmax in input_mt_assign_slots""
  Input: MT - make slot assignment work for overcovered solutions
  mfd: tc3589x: enforce device-tree only mode
  Input: tc3589x - localize platform data
  Input: tsc2007 - Convert msecs to jiffies only once
  Input: edt-ft5x06 - remove EV_SYN event report
  Input: edt-ft5x06 - allow to setting the maximum axes value through the DT
  ...
parents c3a416a6 85a36858
* Broadcom Keypad Controller device tree bindings
Broadcom Keypad controller is used to interface a SoC with a matrix-type
keypad device. The keypad controller supports multiple row and column lines.
A key can be placed at each intersection of a unique row and a unique column.
The keypad controller can sense a key-press and key-release and report the
event using a interrupt to the cpu.
This binding is based on the matrix-keymap binding with the following
changes:
keypad,num-rows and keypad,num-columns are required.
Required SoC Specific Properties:
- compatible: should be "brcm,bcm-keypad"
- reg: physical base address of the controller and length of memory mapped
region.
- interrupts: The interrupt number to the cpu.
Board Specific Properties:
- keypad,num-rows: Number of row lines connected to the keypad
controller.
- keypad,num-columns: Number of column lines connected to the
keypad controller.
- col-debounce-filter-period: The debounce period for the Column filter.
KEYPAD_DEBOUNCE_1_ms = 0
KEYPAD_DEBOUNCE_2_ms = 1
KEYPAD_DEBOUNCE_4_ms = 2
KEYPAD_DEBOUNCE_8_ms = 3
KEYPAD_DEBOUNCE_16_ms = 4
KEYPAD_DEBOUNCE_32_ms = 5
KEYPAD_DEBOUNCE_64_ms = 6
KEYPAD_DEBOUNCE_128_ms = 7
- status-debounce-filter-period: The debounce period for the Status filter.
KEYPAD_DEBOUNCE_1_ms = 0
KEYPAD_DEBOUNCE_2_ms = 1
KEYPAD_DEBOUNCE_4_ms = 2
KEYPAD_DEBOUNCE_8_ms = 3
KEYPAD_DEBOUNCE_16_ms = 4
KEYPAD_DEBOUNCE_32_ms = 5
KEYPAD_DEBOUNCE_64_ms = 6
KEYPAD_DEBOUNCE_128_ms = 7
- row-output-enabled: An optional property indicating whether the row or
column is being used as output. If specified the row is being used
as the output. Else defaults to column.
- pull-up-enabled: An optional property indicating the Keypad scan mode.
If specified implies the keypad scan pull-up has been enabled.
- autorepeat: Boolean, Enable auto repeat feature of Linux input
subsystem (optional).
- linux,keymap: The keymap for keys as described in the binding document
devicetree/bindings/input/matrix-keymap.txt.
Example:
#include "dt-bindings/input/input.h"
/ {
keypad: keypad@180ac000 {
/* Required SoC specific properties */
compatible = "brcm,bcm-keypad";
/* Required Board specific properties */
keypad,num-rows = <5>;
keypad,num-columns = <5>;
status = "okay";
linux,keymap = <MATRIX_KEY(0x00, 0x02, KEY_F) /* key_forward */
MATRIX_KEY(0x00, 0x03, KEY_HOME) /* key_home */
MATRIX_KEY(0x00, 0x04, KEY_M) /* key_message */
MATRIX_KEY(0x01, 0x00, KEY_A) /* key_contacts */
MATRIX_KEY(0x01, 0x01, KEY_1) /* key_1 */
MATRIX_KEY(0x01, 0x02, KEY_2) /* key_2 */
MATRIX_KEY(0x01, 0x03, KEY_3) /* key_3 */
MATRIX_KEY(0x01, 0x04, KEY_S) /* key_speaker */
MATRIX_KEY(0x02, 0x00, KEY_P) /* key_phone */
MATRIX_KEY(0x02, 0x01, KEY_4) /* key_4 */
MATRIX_KEY(0x02, 0x02, KEY_5) /* key_5 */
MATRIX_KEY(0x02, 0x03, KEY_6) /* key_6 */
MATRIX_KEY(0x02, 0x04, KEY_VOLUMEUP) /* key_vol_up */
MATRIX_KEY(0x03, 0x00, KEY_C) /* key_call_log */
MATRIX_KEY(0x03, 0x01, KEY_7) /* key_7 */
MATRIX_KEY(0x03, 0x02, KEY_8) /* key_8 */
MATRIX_KEY(0x03, 0x03, KEY_9) /* key_9 */
MATRIX_KEY(0x03, 0x04, KEY_VOLUMEDOWN) /* key_vol_down */
MATRIX_KEY(0x04, 0x00, KEY_H) /* key_headset */
MATRIX_KEY(0x04, 0x01, KEY_KPASTERISK) /* key_* */
MATRIX_KEY(0x04, 0x02, KEY_0) /* key_0 */
MATRIX_KEY(0x04, 0x03, KEY_GRAVE) /* key_# */
MATRIX_KEY(0x04, 0x04, KEY_MUTE) /* key_mute */
>;
/* Optional board specific properties */
col-debounce-filter-period = <5>;
row-output-enabled;
pull-up-enabled;
};
};
Qualcomm PM8941 PMIC Power Key
PROPERTIES
- compatible:
Usage: required
Value type: <string>
Definition: must be one of:
"qcom,pm8941-pwrkey"
- reg:
Usage: required
Value type: <prop-encoded-array>
Definition: base address of registers for block
- interrupts:
Usage: required
Value type: <prop-encoded-array>
Definition: key change interrupt; The format of the specifier is
defined by the binding document describing the node's
interrupt parent.
- debounce:
Usage: optional
Value type: <u32>
Definition: time in microseconds that key must be pressed or released
for state change interrupt to trigger.
- bias-pull-up:
Usage: optional
Value type: <empty>
Definition: presence of this property indicates that the KPDPWR_N pin
should be configured for pull up.
EXAMPLE
pwrkey@800 {
compatible = "qcom,pm8941-pwrkey";
reg = <0x800>;
interrupts = <0x0 0x8 0 IRQ_TYPE_EDGE_BOTH>;
debounce = <15625>;
bias-pull-up;
};
* Broadcom's IPROC Touchscreen Controller
Required properties:
- compatible: must be "brcm,iproc-touchscreen"
- reg: physical base address of the controller and length of memory mapped
region.
- clocks: The clock provided by the SOC to driver the tsc
- clock-name: name for the clock
- interrupts: The touchscreen controller's interrupt
Optional properties:
- scanning_period: Time between scans. Each step is 1024 us. Valid 1-256.
- debounce_timeout: Each step is 512 us. Valid 0-255
- settling_timeout: The settling duration (in ms) is the amount of time
the tsc waits to allow the voltage to settle after
turning on the drivers in detection mode.
Valid values: 0-11
0 = 0.008 ms
1 = 0.01 ms
2 = 0.02 ms
3 = 0.04 ms
4 = 0.08 ms
5 = 0.16 ms
6 = 0.32 ms
7 = 0.64 ms
8 = 1.28 ms
9 = 2.56 ms
10 = 5.12 ms
11 = 10.24 ms
- touch_timeout: The continuous number of scan periods in which touch is
not detected before the controller returns to idle state.
Valid values 0-255.
- average_data: Number of data samples which are averaged before a final
data point is placed into the FIFO
Valid values 0-7
0 = 1 sample
1 = 2 samples
2 = 4 samples
3 = 8 samples
4 = 16 samples
5 = 32 samples
6 = 64 samples
7 = 128 samples
- fifo_threshold: Interrupt is generated whenever the number of fifo
entries exceeds this value
Valid values 0-31
- touchscreen-size-x: horizontal resolution of touchscreen (in pixels)
- touchscreen-size-y: vertical resolution of touchscreen (in pixels)
- touchscreen-fuzz-x: horizontal noise value of the absolute input
device (in pixels)
- touchscreen-fuzz-y: vertical noise value of the absolute input
device (in pixels)
- touchscreen-inverted-x: X axis is inverted (boolean)
- touchscreen-inverted-y: Y axis is inverted (boolean)
Example:
touchscreen: tsc@0x180A6000 {
compatible = "brcm,iproc-touchscreen";
#address-cells = <1>;
#size-cells = <1>;
reg = <0x180A6000 0x40>;
clocks = <&adc_clk>;
clock-names = "tsc_clk";
interrupts = <GIC_SPI 164 IRQ_TYPE_LEVEL_HIGH>;
scanning_period = <5>;
debounce_timeout = <40>;
settling_timeout = <7>;
touch_timeout = <10>;
average_data = <5>;
fifo_threshold = <1>;
/* Touchscreen is rotated 180 degrees. */
touchscreen-inverted-x;
touchscreen-inverted-y;
};
* ChipOne icn8318 I2C touchscreen controller
Required properties:
- compatible : "chipone,icn8318"
- reg : I2C slave address of the chip (0x40)
- interrupt-parent : a phandle pointing to the interrupt controller
serving the interrupt for this chip
- interrupts : interrupt specification for the icn8318 interrupt
- wake-gpios : GPIO specification for the WAKE input
- touchscreen-size-x : horizontal resolution of touchscreen (in pixels)
- touchscreen-size-y : vertical resolution of touchscreen (in pixels)
Optional properties:
- pinctrl-names : should be "default"
- pinctrl-0: : a phandle pointing to the pin settings for the
control gpios
- touchscreen-fuzz-x : horizontal noise value of the absolute input
device (in pixels)
- touchscreen-fuzz-y : vertical noise value of the absolute input
device (in pixels)
- touchscreen-inverted-x : X axis is inverted (boolean)
- touchscreen-inverted-y : Y axis is inverted (boolean)
- touchscreen-swapped-x-y : X and Y axis are swapped (boolean)
Swapping is done after inverting the axis
Example:
i2c@00000000 {
/* ... */
chipone_icn8318@40 {
compatible = "chipone,icn8318";
reg = <0x40>;
interrupt-parent = <&pio>;
interrupts = <9 IRQ_TYPE_EDGE_FALLING>; /* EINT9 (PG9) */
pinctrl-names = "default";
pinctrl-0 = <&ts_wake_pin_p66>;
wake-gpios = <&pio 1 3 GPIO_ACTIVE_HIGH>; /* PB3 */
touchscreen-size-x = <800>;
touchscreen-size-y = <480>;
touchscreen-inverted-x;
touchscreen-swapped-x-y;
};
/* ... */
};
Device tree bindings for Goodix GT9xx series touchscreen controller
Required properties:
- compatible : Should be "goodix,gt911"
or "goodix,gt9110"
or "goodix,gt912"
or "goodix,gt927"
or "goodix,gt9271"
or "goodix,gt928"
or "goodix,gt967"
- reg : I2C address of the chip. Should be 0x5d or 0x14
- interrupt-parent : Interrupt controller to which the chip is connected
- interrupts : Interrupt to which the chip is connected
Example:
i2c@00000000 {
/* ... */
gt928@5d {
compatible = "goodix,gt928";
reg = <0x5d>;
interrupt-parent = <&gpio>;
interrupts = <0 0>;
};
/* ... */
};
...@@ -2,14 +2,27 @@ sun4i resistive touchscreen controller ...@@ -2,14 +2,27 @@ sun4i resistive touchscreen controller
-------------------------------------- --------------------------------------
Required properties: Required properties:
- compatible: "allwinner,sun4i-a10-ts" or "allwinner,sun6i-a31-ts" - compatible: "allwinner,sun4i-a10-ts", "allwinner,sun5i-a13-ts" or
"allwinner,sun6i-a31-ts"
- reg: mmio address range of the chip - reg: mmio address range of the chip
- interrupts: interrupt to which the chip is connected - interrupts: interrupt to which the chip is connected
- #thermal-sensor-cells: shall be 0 - #thermal-sensor-cells: shall be 0
Optional properties: Optional properties:
- allwinner,ts-attached: boolean indicating that an actual touchscreen is - allwinner,ts-attached : boolean indicating that an actual touchscreen
attached to the controller is attached to the controller
- allwinner,tp-sensitive-adjust : integer (4 bits)
adjust sensitivity of pen down detection
between 0 (least sensitive) and 15
(defaults to 15)
- allwinner,filter-type : integer (2 bits)
select median and averaging filter
samples used for median / averaging filter
0: 4/2
1: 5/3
2: 8/4
3: 16/8
(defaults to 1)
Example: Example:
...@@ -19,4 +32,7 @@ Example: ...@@ -19,4 +32,7 @@ Example:
interrupts = <29>; interrupts = <29>;
allwinner,ts-attached; allwinner,ts-attached;
#thermal-sensor-cells = <0>; #thermal-sensor-cells = <0>;
/* sensitive/noisy touch panel */
allwinner,tp-sensitive-adjust = <0>;
allwinner,filter-type = <3>;
}; };
* Semtech SX8654 I2C Touchscreen Controller
Required properties:
- compatible: must be "semtech,sx8654"
- reg: i2c slave address
- interrupt-parent: the phandle for the interrupt controller
- interrupts: touch controller interrupt
Example:
sx8654@48 {
compatible = "semtech,sx8654";
reg = <0x48>;
interrupt-parent = <&gpio6>;
interrupts = <3 IRQ_TYPE_EDGE_FALLING>;
};
...@@ -16,6 +16,8 @@ Optional properties for Touchscreens: ...@@ -16,6 +16,8 @@ Optional properties for Touchscreens:
controller) controller)
- touchscreen-inverted-x : X axis is inverted (boolean) - touchscreen-inverted-x : X axis is inverted (boolean)
- touchscreen-inverted-y : Y axis is inverted (boolean) - touchscreen-inverted-y : Y axis is inverted (boolean)
- touchscreen-swapped-x-y : X and Y axis are swapped (boolean)
Swapping is done after inverting the axis
Deprecated properties for Touchscreens: Deprecated properties for Touchscreens:
- x-size : deprecated name for touchscreen-size-x - x-size : deprecated name for touchscreen-size-x
......
...@@ -37,6 +37,7 @@ capella Capella Microsystems, Inc ...@@ -37,6 +37,7 @@ capella Capella Microsystems, Inc
cavium Cavium, Inc. cavium Cavium, Inc.
cdns Cadence Design Systems Inc. cdns Cadence Design Systems Inc.
chipidea Chipidea, Inc chipidea Chipidea, Inc
chipone ChipOne
chipspark ChipSPARK chipspark ChipSPARK
chrp Common Hardware Reference Platform chrp Common Hardware Reference Platform
chunghwa Chunghwa Picture Tubes Ltd. chunghwa Chunghwa Picture Tubes Ltd.
...@@ -78,6 +79,7 @@ geniatech Geniatech, Inc. ...@@ -78,6 +79,7 @@ geniatech Geniatech, Inc.
giantplus Giantplus Technology Co., Ltd. giantplus Giantplus Technology Co., Ltd.
globalscale Globalscale Technologies, Inc. globalscale Globalscale Technologies, Inc.
gmt Global Mixed-mode Technology, Inc. gmt Global Mixed-mode Technology, Inc.
goodix Shenzhen Huiding Technology Co., Ltd.
google Google, Inc. google Google, Inc.
gumstix Gumstix, Inc. gumstix Gumstix, Inc.
gw Gateworks Corporation gw Gateworks Corporation
......
...@@ -2525,6 +2525,13 @@ L: linux-usb@vger.kernel.org ...@@ -2525,6 +2525,13 @@ L: linux-usb@vger.kernel.org
S: Maintained S: Maintained
F: drivers/usb/chipidea/ F: drivers/usb/chipidea/
CHIPONE ICN8318 I2C TOUCHSCREEN DRIVER
M: Hans de Goede <hdegoede@redhat.com>
L: linux-input@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/input/touchscreen/chipone_icn8318.txt
F: drivers/input/touchscreen/chipone_icn8318.c
CHROME HARDWARE PLATFORM SUPPORT CHROME HARDWARE PLATFORM SUPPORT
M: Olof Johansson <olof@lixom.net> M: Olof Johansson <olof@lixom.net>
S: Maintained S: Maintained
......
...@@ -815,7 +815,7 @@ static const char *keys[KEY_MAX + 1] = { ...@@ -815,7 +815,7 @@ static const char *keys[KEY_MAX + 1] = {
[KEY_DELETEFILE] = "DeleteFile", [KEY_XFER] = "X-fer", [KEY_DELETEFILE] = "DeleteFile", [KEY_XFER] = "X-fer",
[KEY_PROG1] = "Prog1", [KEY_PROG2] = "Prog2", [KEY_PROG1] = "Prog1", [KEY_PROG2] = "Prog2",
[KEY_WWW] = "WWW", [KEY_MSDOS] = "MSDOS", [KEY_WWW] = "WWW", [KEY_MSDOS] = "MSDOS",
[KEY_COFFEE] = "Coffee", [KEY_DIRECTION] = "Direction", [KEY_COFFEE] = "Coffee", [KEY_ROTATE_DISPLAY] = "RotateDisplay",
[KEY_CYCLEWINDOWS] = "CycleWindows", [KEY_MAIL] = "Mail", [KEY_CYCLEWINDOWS] = "CycleWindows", [KEY_MAIL] = "Mail",
[KEY_BOOKMARKS] = "Bookmarks", [KEY_COMPUTER] = "Computer", [KEY_BOOKMARKS] = "Bookmarks", [KEY_COMPUTER] = "Computer",
[KEY_BACK] = "Back", [KEY_FORWARD] = "Forward", [KEY_BACK] = "Back", [KEY_FORWARD] = "Forward",
......
...@@ -368,28 +368,36 @@ static void input_mt_set_slots(struct input_mt *mt, ...@@ -368,28 +368,36 @@ static void input_mt_set_slots(struct input_mt *mt,
int *slots, int num_pos) int *slots, int num_pos)
{ {
struct input_mt_slot *s; struct input_mt_slot *s;
int *w = mt->red, *p; int *w = mt->red, j;
for (p = slots; p != slots + num_pos; p++) for (j = 0; j != num_pos; j++)
*p = -1; slots[j] = -1;
for (s = mt->slots; s != mt->slots + mt->num_slots; s++) { for (s = mt->slots; s != mt->slots + mt->num_slots; s++) {
if (!input_mt_is_active(s)) if (!input_mt_is_active(s))
continue; continue;
for (p = slots; p != slots + num_pos; p++)
if (*w++ < 0) for (j = 0; j != num_pos; j++) {
*p = s - mt->slots; if (w[j] < 0) {
slots[j] = s - mt->slots;
break;
}
}
w += num_pos;
} }
for (s = mt->slots; s != mt->slots + mt->num_slots; s++) { for (s = mt->slots; s != mt->slots + mt->num_slots; s++) {
if (input_mt_is_active(s)) if (input_mt_is_active(s))
continue; continue;
for (p = slots; p != slots + num_pos; p++)
if (*p < 0) { for (j = 0; j != num_pos; j++) {
*p = s - mt->slots; if (slots[j] < 0) {
slots[j] = s - mt->slots;
break; break;
} }
} }
}
} }
/** /**
......
...@@ -588,6 +588,16 @@ config KEYBOARD_DAVINCI ...@@ -588,6 +588,16 @@ config KEYBOARD_DAVINCI
To compile this driver as a module, choose M here: the To compile this driver as a module, choose M here: the
module will be called davinci_keyscan. module will be called davinci_keyscan.
config KEYBOARD_IPAQ_MICRO
tristate "Buttons on Micro SoC (iPaq h3100,h3600,h3700)"
depends on MFD_IPAQ_MICRO
help
Say Y to enable support for the buttons attached to
Micro peripheral controller on iPAQ h3100/h3600/h3700
To compile this driver as a module, choose M here: the
module will be called ipaq-micro-keys.
config KEYBOARD_OMAP config KEYBOARD_OMAP
tristate "TI OMAP keypad support" tristate "TI OMAP keypad support"
depends on ARCH_OMAP1 depends on ARCH_OMAP1
...@@ -686,4 +696,15 @@ config KEYBOARD_CAP11XX ...@@ -686,4 +696,15 @@ config KEYBOARD_CAP11XX
To compile this driver as a module, choose M here: the To compile this driver as a module, choose M here: the
module will be called cap11xx. module will be called cap11xx.
config KEYBOARD_BCM
tristate "Broadcom keypad driver"
depends on OF && HAVE_CLK
select INPUT_MATRIXKMAP
default ARCH_BCM_CYGNUS
help
Say Y here if you want to use Broadcom keypad.
To compile this driver as a module, choose M here: the
module will be called bcm-keypad.
endif endif
...@@ -10,6 +10,7 @@ obj-$(CONFIG_KEYBOARD_ADP5589) += adp5589-keys.o ...@@ -10,6 +10,7 @@ obj-$(CONFIG_KEYBOARD_ADP5589) += adp5589-keys.o
obj-$(CONFIG_KEYBOARD_AMIGA) += amikbd.o obj-$(CONFIG_KEYBOARD_AMIGA) += amikbd.o
obj-$(CONFIG_KEYBOARD_ATARI) += atakbd.o obj-$(CONFIG_KEYBOARD_ATARI) += atakbd.o
obj-$(CONFIG_KEYBOARD_ATKBD) += atkbd.o obj-$(CONFIG_KEYBOARD_ATKBD) += atkbd.o
obj-$(CONFIG_KEYBOARD_BCM) += bcm-keypad.o
obj-$(CONFIG_KEYBOARD_BFIN) += bf54x-keys.o obj-$(CONFIG_KEYBOARD_BFIN) += bf54x-keys.o
obj-$(CONFIG_KEYBOARD_CAP11XX) += cap11xx.o obj-$(CONFIG_KEYBOARD_CAP11XX) += cap11xx.o
obj-$(CONFIG_KEYBOARD_CLPS711X) += clps711x-keypad.o obj-$(CONFIG_KEYBOARD_CLPS711X) += clps711x-keypad.o
...@@ -23,6 +24,7 @@ obj-$(CONFIG_KEYBOARD_TCA6416) += tca6416-keypad.o ...@@ -23,6 +24,7 @@ obj-$(CONFIG_KEYBOARD_TCA6416) += tca6416-keypad.o
obj-$(CONFIG_KEYBOARD_TCA8418) += tca8418_keypad.o obj-$(CONFIG_KEYBOARD_TCA8418) += tca8418_keypad.o
obj-$(CONFIG_KEYBOARD_HIL) += hil_kbd.o obj-$(CONFIG_KEYBOARD_HIL) += hil_kbd.o
obj-$(CONFIG_KEYBOARD_HIL_OLD) += hilkbd.o obj-$(CONFIG_KEYBOARD_HIL_OLD) += hilkbd.o
obj-$(CONFIG_KEYBOARD_IPAQ_MICRO) += ipaq-micro-keys.o
obj-$(CONFIG_KEYBOARD_IMX) += imx_keypad.o obj-$(CONFIG_KEYBOARD_IMX) += imx_keypad.o
obj-$(CONFIG_KEYBOARD_HP6XX) += jornada680_kbd.o obj-$(CONFIG_KEYBOARD_HP6XX) += jornada680_kbd.o
obj-$(CONFIG_KEYBOARD_HP7XX) += jornada720_kbd.o obj-$(CONFIG_KEYBOARD_HP7XX) += jornada720_kbd.o
......
...@@ -1653,6 +1653,12 @@ static int __init atkbd_deactivate_fixup(const struct dmi_system_id *id) ...@@ -1653,6 +1653,12 @@ static int __init atkbd_deactivate_fixup(const struct dmi_system_id *id)
return 1; return 1;
} }
/*
* NOTE: do not add any more "force release" quirks to this table. The
* task of adjusting list of keys that should be "released" automatically
* by the driver is now delegated to userspace tools, such as udev, so
* submit such quirks there.
*/
static const struct dmi_system_id atkbd_dmi_quirk_table[] __initconst = { static const struct dmi_system_id atkbd_dmi_quirk_table[] __initconst = {
{ {
.matches = { .matches = {
......
This diff is collapsed.
...@@ -338,7 +338,7 @@ static int cros_ec_keyb_resume(struct device *dev) ...@@ -338,7 +338,7 @@ static int cros_ec_keyb_resume(struct device *dev)
* wake source (e.g. the lid is open and the user might press a key to * wake source (e.g. the lid is open and the user might press a key to
* wake) then the key scan buffer should be preserved. * wake) then the key scan buffer should be preserved.
*/ */
if (ckdev->ec->was_wake_device) if (!ckdev->ec->was_wake_device)
cros_ec_keyb_clear_keyboard(ckdev); cros_ec_keyb_clear_keyboard(ckdev);
return 0; return 0;
......
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* h3600 atmel micro companion support, key subdevice
* based on previous kernel 2.4 version
* Author : Alessandro Gardich <gremlin@gremlin.it>
* Author : Linus Walleij <linus.walleij@linaro.org>
*
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/interrupt.h>
#include <linux/sched.h>
#include <linux/pm.h>
#include <linux/sysctl.h>
#include <linux/proc_fs.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/input.h>
#include <linux/platform_device.h>
#include <linux/mfd/ipaq-micro.h>
struct ipaq_micro_keys {
struct ipaq_micro *micro;
struct input_dev *input;
u16 *codes;
};
static const u16 micro_keycodes[] = {
KEY_RECORD, /* 1: Record button */
KEY_CALENDAR, /* 2: Calendar */
KEY_ADDRESSBOOK, /* 3: Contacts (looks like Outlook) */
KEY_MAIL, /* 4: Envelope (Q on older iPAQs) */
KEY_HOMEPAGE, /* 5: Start (looks like swoopy arrow) */
KEY_UP, /* 6: Up */
KEY_RIGHT, /* 7: Right */
KEY_LEFT, /* 8: Left */
KEY_DOWN, /* 9: Down */
};
static void micro_key_receive(void *data, int len, unsigned char *msg)
{
struct ipaq_micro_keys *keys = data;
int key, down;
down = 0x80 & msg[0];
key = 0x7f & msg[0];
if (key < ARRAY_SIZE(micro_keycodes)) {
input_report_key(keys->input, keys->codes[key], down);
input_sync(keys->input);
}
}
static void micro_key_start(struct ipaq_micro_keys *keys)
{
spin_lock(&keys->micro->lock);
keys->micro->key = micro_key_receive;
keys->micro->key_data = keys;
spin_unlock(&keys->micro->lock);
}
static void micro_key_stop(struct ipaq_micro_keys *keys)
{
spin_lock(&keys->micro->lock);
keys->micro->key = NULL;
keys->micro->key_data = NULL;
spin_unlock(&keys->micro->lock);
}
static int micro_key_open(struct input_dev *input)
{
struct ipaq_micro_keys *keys = input_get_drvdata(input);
micro_key_start(keys);
return 0;
}
static void micro_key_close(struct input_dev *input)
{
struct ipaq_micro_keys *keys = input_get_drvdata(input);
micro_key_stop(keys);
}
static int micro_key_probe(struct platform_device *pdev)
{
struct ipaq_micro_keys *keys;
int error;
int i;
keys = devm_kzalloc(&pdev->dev, sizeof(*keys), GFP_KERNEL);
if (!keys)
return -ENOMEM;
keys->micro = dev_get_drvdata(pdev->dev.parent);
keys->input = devm_input_allocate_device(&pdev->dev);
if (!keys->input)
return -ENOMEM;
keys->input->keycodesize = sizeof(micro_keycodes[0]);
keys->input->keycodemax = ARRAY_SIZE(micro_keycodes);
keys->codes = devm_kmemdup(&pdev->dev, micro_keycodes,
keys->input->keycodesize * keys->input->keycodemax,
GFP_KERNEL);
keys->input->keycode = keys->codes;
__set_bit(EV_KEY, keys->input->evbit);
for (i = 0; i < ARRAY_SIZE(micro_keycodes); i++)
__set_bit(micro_keycodes[i], keys->input->keybit);
keys->input->name = "h3600 micro keys";
keys->input->open = micro_key_open;
keys->input->close = micro_key_close;
input_set_drvdata(keys->input, keys);
error = input_register_device(keys->input);
if (error)
return error;
platform_set_drvdata(pdev, keys);
return 0;
}
static int __maybe_unused micro_key_suspend(struct device *dev)
{
struct ipaq_micro_keys *keys = dev_get_drvdata(dev);
micro_key_stop(keys);
return 0;
}
static int __maybe_unused micro_key_resume(struct device *dev)
{
struct ipaq_micro_keys *keys = dev_get_drvdata(dev);
struct input_dev *input = keys->input;
mutex_lock(&input->mutex);
if (input->users)
micro_key_start(keys);
mutex_unlock(&input->mutex);
return 0;
}
static SIMPLE_DEV_PM_OPS(micro_key_dev_pm_ops,
micro_key_suspend, micro_key_resume);
static struct platform_driver micro_key_device_driver = {
.driver = {
.name = "ipaq-micro-keys",
.pm = &micro_key_dev_pm_ops,
},
.probe = micro_key_probe,
};
module_platform_driver(micro_key_device_driver);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("driver for iPAQ Atmel micro keys");
MODULE_ALIAS("platform:ipaq-micro-keys");
...@@ -69,6 +69,28 @@ ...@@ -69,6 +69,28 @@
#define TC3589x_EVT_INT_CLR 0x2 #define TC3589x_EVT_INT_CLR 0x2
#define TC3589x_KBD_INT_CLR 0x1 #define TC3589x_KBD_INT_CLR 0x1
/**
* struct tc35893_keypad_platform_data - platform specific keypad data
* @keymap_data: matrix scan code table for keycodes
* @krow: mask for available rows, value is 0xFF
* @kcol: mask for available columns, value is 0xFF
* @debounce_period: platform specific debounce time
* @settle_time: platform specific settle down time
* @irqtype: type of interrupt, falling or rising edge
* @enable_wakeup: specifies if keypad event can wake up system from sleep
* @no_autorepeat: flag for auto repetition
*/
struct tc3589x_keypad_platform_data {
const struct matrix_keymap_data *keymap_data;
u8 krow;
u8 kcol;
u8 debounce_period;
u8 settle_time;
unsigned long irqtype;
bool enable_wakeup;
bool no_autorepeat;
};
/** /**
* struct tc_keypad - data structure used by keypad driver * struct tc_keypad - data structure used by keypad driver
* @tc3589x: pointer to tc35893 * @tc3589x: pointer to tc35893
...@@ -354,14 +376,11 @@ static int tc3589x_keypad_probe(struct platform_device *pdev) ...@@ -354,14 +376,11 @@ static int tc3589x_keypad_probe(struct platform_device *pdev)
const struct tc3589x_keypad_platform_data *plat; const struct tc3589x_keypad_platform_data *plat;
int error, irq; int error, irq;
plat = tc3589x->pdata->keypad;
if (!plat) {
plat = tc3589x_keypad_of_probe(&pdev->dev); plat = tc3589x_keypad_of_probe(&pdev->dev);
if (IS_ERR(plat)) { if (IS_ERR(plat)) {
dev_err(&pdev->dev, "invalid keypad platform data\n"); dev_err(&pdev->dev, "invalid keypad platform data\n");
return PTR_ERR(plat); return PTR_ERR(plat);
} }
}
irq = platform_get_irq(pdev, 0); irq = platform_get_irq(pdev, 0);
if (irq < 0) if (irq < 0)
......
...@@ -115,6 +115,18 @@ config INPUT_PCSPKR ...@@ -115,6 +115,18 @@ config INPUT_PCSPKR
To compile this driver as a module, choose M here: the To compile this driver as a module, choose M here: the
module will be called pcspkr. module will be called pcspkr.
config INPUT_PM8941_PWRKEY
tristate "Qualcomm PM8941 power key support"
depends on MFD_SPMI_PMIC
help
Say Y here if you want support for the power key usually found
on boards using a Qualcomm PM8941 compatible PMIC.
If unsure, say Y.
To compile this driver as a module, choose M here: the module
will be called pm8941-pwrkey.
config INPUT_PM8XXX_VIBRATOR config INPUT_PM8XXX_VIBRATOR
tristate "Qualcomm PM8XXX vibrator support" tristate "Qualcomm PM8XXX vibrator support"
depends on MFD_PM8XXX depends on MFD_PM8XXX
...@@ -165,6 +177,18 @@ config INPUT_MAX77693_HAPTIC ...@@ -165,6 +177,18 @@ config INPUT_MAX77693_HAPTIC
To compile this driver as module, choose M here: the To compile this driver as module, choose M here: the
module will be called max77693-haptic. module will be called max77693-haptic.
config INPUT_MAX77843_HAPTIC
tristate "MAXIM MAX77843 haptic controller support"
depends on MFD_MAX77843 && REGULATOR
select INPUT_FF_MEMLESS
help
This option enables support for the haptic controller on
MAXIM MAX77843 chip. The driver supports ff-memless interface
from input framework.
To compile this driver as module, choose M here: the
module will be called max77843-haptic.
config INPUT_MAX8925_ONKEY config INPUT_MAX8925_ONKEY
tristate "MAX8925 ONKEY support" tristate "MAX8925 ONKEY support"
depends on MFD_MAX8925 depends on MFD_MAX8925
......
...@@ -39,6 +39,7 @@ obj-$(CONFIG_INPUT_KEYSPAN_REMOTE) += keyspan_remote.o ...@@ -39,6 +39,7 @@ obj-$(CONFIG_INPUT_KEYSPAN_REMOTE) += keyspan_remote.o
obj-$(CONFIG_INPUT_KXTJ9) += kxtj9.o obj-$(CONFIG_INPUT_KXTJ9) += kxtj9.o
obj-$(CONFIG_INPUT_M68K_BEEP) += m68kspkr.o obj-$(CONFIG_INPUT_M68K_BEEP) += m68kspkr.o
obj-$(CONFIG_INPUT_MAX77693_HAPTIC) += max77693-haptic.o obj-$(CONFIG_INPUT_MAX77693_HAPTIC) += max77693-haptic.o
obj-$(CONFIG_INPUT_MAX77843_HAPTIC) += max77843-haptic.o
obj-$(CONFIG_INPUT_MAX8925_ONKEY) += max8925_onkey.o obj-$(CONFIG_INPUT_MAX8925_ONKEY) += max8925_onkey.o
obj-$(CONFIG_INPUT_MAX8997_HAPTIC) += max8997_haptic.o obj-$(CONFIG_INPUT_MAX8997_HAPTIC) += max8997_haptic.o
obj-$(CONFIG_INPUT_MC13783_PWRBUTTON) += mc13783-pwrbutton.o obj-$(CONFIG_INPUT_MC13783_PWRBUTTON) += mc13783-pwrbutton.o
...@@ -49,6 +50,7 @@ obj-$(CONFIG_INPUT_PCAP) += pcap_keys.o ...@@ -49,6 +50,7 @@ obj-$(CONFIG_INPUT_PCAP) += pcap_keys.o
obj-$(CONFIG_INPUT_PCF50633_PMU) += pcf50633-input.o obj-$(CONFIG_INPUT_PCF50633_PMU) += pcf50633-input.o
obj-$(CONFIG_INPUT_PCF8574) += pcf8574_keypad.o obj-$(CONFIG_INPUT_PCF8574) += pcf8574_keypad.o
obj-$(CONFIG_INPUT_PCSPKR) += pcspkr.o obj-$(CONFIG_INPUT_PCSPKR) += pcspkr.o
obj-$(CONFIG_INPUT_PM8941_PWRKEY) += pm8941-pwrkey.o
obj-$(CONFIG_INPUT_PM8XXX_VIBRATOR) += pm8xxx-vibrator.o obj-$(CONFIG_INPUT_PM8XXX_VIBRATOR) += pm8xxx-vibrator.o
obj-$(CONFIG_INPUT_PMIC8XXX_PWRKEY) += pmic8xxx-pwrkey.o obj-$(CONFIG_INPUT_PMIC8XXX_PWRKEY) += pmic8xxx-pwrkey.o
obj-$(CONFIG_INPUT_POWERMATE) += powermate.o obj-$(CONFIG_INPUT_POWERMATE) += powermate.o
......
/*
* MAXIM MAX77693 Haptic device driver
*
* Copyright (C) 2015 Samsung Electronics
* Author: Jaewon Kim <jaewon02.kim@samsung.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/err.h>
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/input.h>
#include <linux/mfd/max77843-private.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/pwm.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#include <linux/workqueue.h>
#define MAX_MAGNITUDE_SHIFT 16
enum max77843_haptic_motor_type {
MAX77843_HAPTIC_ERM = 0,
MAX77843_HAPTIC_LRA,
};
enum max77843_haptic_pwm_divisor {
MAX77843_HAPTIC_PWM_DIVISOR_32 = 0,
MAX77843_HAPTIC_PWM_DIVISOR_64,
MAX77843_HAPTIC_PWM_DIVISOR_128,
MAX77843_HAPTIC_PWM_DIVISOR_256,
};
struct max77843_haptic {
struct regmap *regmap_haptic;
struct device *dev;
struct input_dev *input_dev;
struct pwm_device *pwm_dev;
struct regulator *motor_reg;
struct work_struct work;
struct mutex mutex;
unsigned int magnitude;
unsigned int pwm_duty;
bool active;
bool suspended;
enum max77843_haptic_motor_type type;
enum max77843_haptic_pwm_divisor pwm_divisor;
};
static int max77843_haptic_set_duty_cycle(struct max77843_haptic *haptic)
{
int delta = (haptic->pwm_dev->period + haptic->pwm_duty) / 2;
int error;
error = pwm_config(haptic->pwm_dev, delta, haptic->pwm_dev->period);
if (error) {
dev_err(haptic->dev, "failed to configure pwm: %d\n", error);
return error;
}
return 0;
}
static int max77843_haptic_bias(struct max77843_haptic *haptic, bool on)
{
int error;
error = regmap_update_bits(haptic->regmap_haptic,
MAX77843_SYS_REG_MAINCTRL1,
MAX77843_MAINCTRL1_BIASEN_MASK,
on << MAINCTRL1_BIASEN_SHIFT);
if (error) {
dev_err(haptic->dev, "failed to %s bias: %d\n",
on ? "enable" : "disable", error);
return error;
}
return 0;
}
static int max77843_haptic_config(struct max77843_haptic *haptic, bool enable)
{
unsigned int value;
int error;
value = (haptic->type << MCONFIG_MODE_SHIFT) |
(enable << MCONFIG_MEN_SHIFT) |
(haptic->pwm_divisor << MCONFIG_PDIV_SHIFT);
error = regmap_write(haptic->regmap_haptic,
MAX77843_HAP_REG_MCONFIG, value);
if (error) {
dev_err(haptic->dev,
"failed to update haptic config: %d\n", error);
return error;
}
return 0;
}
static int max77843_haptic_enable(struct max77843_haptic *haptic)
{
int error;
if (haptic->active)
return 0;
error = pwm_enable(haptic->pwm_dev);
if (error) {
dev_err(haptic->dev,
"failed to enable pwm device: %d\n", error);
return error;
}
error = max77843_haptic_config(haptic, true);
if (error)
goto err_config;
haptic->active = true;
return 0;
err_config:
pwm_disable(haptic->pwm_dev);
return error;
}
static int max77843_haptic_disable(struct max77843_haptic *haptic)
{
int error;
if (!haptic->active)
return 0;
error = max77843_haptic_config(haptic, false);
if (error)
return error;
pwm_disable(haptic->pwm_dev);
haptic->active = false;
return 0;
}
static void max77843_haptic_play_work(struct work_struct *work)
{
struct max77843_haptic *haptic =
container_of(work, struct max77843_haptic, work);
int error;
mutex_lock(&haptic->mutex);
if (haptic->suspended)
goto out_unlock;
if (haptic->magnitude) {
error = max77843_haptic_set_duty_cycle(haptic);
if (error) {
dev_err(haptic->dev,
"failed to set duty cycle: %d\n", error);
goto out_unlock;
}
error = max77843_haptic_enable(haptic);
if (error)
dev_err(haptic->dev,
"cannot enable haptic: %d\n", error);
} else {
error = max77843_haptic_disable(haptic);
if (error)
dev_err(haptic->dev,
"cannot disable haptic: %d\n", error);
}
out_unlock:
mutex_unlock(&haptic->mutex);
}
static int max77843_haptic_play_effect(struct input_dev *dev, void *data,
struct ff_effect *effect)
{
struct max77843_haptic *haptic = input_get_drvdata(dev);
u64 period_mag_multi;
haptic->magnitude = effect->u.rumble.strong_magnitude;
if (!haptic->magnitude)
haptic->magnitude = effect->u.rumble.weak_magnitude;
period_mag_multi = (u64)haptic->pwm_dev->period * haptic->magnitude;
haptic->pwm_duty = (unsigned int)(period_mag_multi >>
MAX_MAGNITUDE_SHIFT);
schedule_work(&haptic->work);
return 0;
}
static int max77843_haptic_open(struct input_dev *dev)
{
struct max77843_haptic *haptic = input_get_drvdata(dev);
int error;
error = max77843_haptic_bias(haptic, true);
if (error)
return error;
error = regulator_enable(haptic->motor_reg);
if (error) {
dev_err(haptic->dev,
"failed to enable regulator: %d\n", error);
return error;
}
return 0;
}
static void max77843_haptic_close(struct input_dev *dev)
{
struct max77843_haptic *haptic = input_get_drvdata(dev);
int error;
cancel_work_sync(&haptic->work);
max77843_haptic_disable(haptic);
error = regulator_disable(haptic->motor_reg);
if (error)
dev_err(haptic->dev,
"failed to disable regulator: %d\n", error);
max77843_haptic_bias(haptic, false);
}
static int max77843_haptic_probe(struct platform_device *pdev)
{
struct max77843 *max77843 = dev_get_drvdata(pdev->dev.parent);
struct max77843_haptic *haptic;
int error;
haptic = devm_kzalloc(&pdev->dev, sizeof(*haptic), GFP_KERNEL);
if (!haptic)
return -ENOMEM;
haptic->regmap_haptic = max77843->regmap;
haptic->dev = &pdev->dev;
haptic->type = MAX77843_HAPTIC_LRA;
haptic->pwm_divisor = MAX77843_HAPTIC_PWM_DIVISOR_128;
INIT_WORK(&haptic->work, max77843_haptic_play_work);
mutex_init(&haptic->mutex);
haptic->pwm_dev = devm_pwm_get(&pdev->dev, NULL);
if (IS_ERR(haptic->pwm_dev)) {
dev_err(&pdev->dev, "failed to get pwm device\n");
return PTR_ERR(haptic->pwm_dev);
}
haptic->motor_reg = devm_regulator_get_exclusive(&pdev->dev, "haptic");
if (IS_ERR(haptic->motor_reg)) {
dev_err(&pdev->dev, "failed to get regulator\n");
return PTR_ERR(haptic->motor_reg);
}
haptic->input_dev = devm_input_allocate_device(&pdev->dev);
if (!haptic->input_dev) {
dev_err(&pdev->dev, "failed to allocate input device\n");
return -ENOMEM;
}
haptic->input_dev->name = "max77843-haptic";
haptic->input_dev->id.version = 1;
haptic->input_dev->dev.parent = &pdev->dev;
haptic->input_dev->open = max77843_haptic_open;
haptic->input_dev->close = max77843_haptic_close;
input_set_drvdata(haptic->input_dev, haptic);
input_set_capability(haptic->input_dev, EV_FF, FF_RUMBLE);
error = input_ff_create_memless(haptic->input_dev, NULL,
max77843_haptic_play_effect);
if (error) {
dev_err(&pdev->dev, "failed to create force-feedback\n");
return error;
}
error = input_register_device(haptic->input_dev);
if (error) {
dev_err(&pdev->dev, "failed to register input device\n");
return error;
}
platform_set_drvdata(pdev, haptic);
return 0;
}
static int __maybe_unused max77843_haptic_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct max77843_haptic *haptic = platform_get_drvdata(pdev);
int error;
error = mutex_lock_interruptible(&haptic->mutex);
if (error)
return error;
max77843_haptic_disable(haptic);
haptic->suspended = true;
mutex_unlock(&haptic->mutex);
return 0;
}
static int __maybe_unused max77843_haptic_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct max77843_haptic *haptic = platform_get_drvdata(pdev);
unsigned int magnitude;
mutex_lock(&haptic->mutex);
haptic->suspended = false;
magnitude = ACCESS_ONCE(haptic->magnitude);
if (magnitude)
max77843_haptic_enable(haptic);
mutex_unlock(&haptic->mutex);
return 0;
}
static SIMPLE_DEV_PM_OPS(max77843_haptic_pm_ops,
max77843_haptic_suspend, max77843_haptic_resume);
static struct platform_driver max77843_haptic_driver = {
.driver = {
.name = "max77843-haptic",
.pm = &max77843_haptic_pm_ops,
},
.probe = max77843_haptic_probe,
};
module_platform_driver(max77843_haptic_driver);
MODULE_AUTHOR("Jaewon Kim <jaewon02.kim@samsung.com>");
MODULE_DESCRIPTION("MAXIM MAX77843 Haptic driver");
MODULE_LICENSE("GPL");
...@@ -174,12 +174,13 @@ static int mma8450_probe(struct i2c_client *c, ...@@ -174,12 +174,13 @@ static int mma8450_probe(struct i2c_client *c,
struct mma8450 *m; struct mma8450 *m;
int err; int err;
m = kzalloc(sizeof(struct mma8450), GFP_KERNEL); m = devm_kzalloc(&c->dev, sizeof(*m), GFP_KERNEL);
idev = input_allocate_polled_device(); if (!m)
if (!m || !idev) { return -ENOMEM;
err = -ENOMEM;
goto err_free_mem; idev = devm_input_allocate_polled_device(&c->dev);
} if (!idev)
return -ENOMEM;
m->client = c; m->client = c;
m->idev = idev; m->idev = idev;
...@@ -187,7 +188,6 @@ static int mma8450_probe(struct i2c_client *c, ...@@ -187,7 +188,6 @@ static int mma8450_probe(struct i2c_client *c,
idev->private = m; idev->private = m;
idev->input->name = MMA8450_DRV_NAME; idev->input->name = MMA8450_DRV_NAME;
idev->input->id.bustype = BUS_I2C; idev->input->id.bustype = BUS_I2C;
idev->input->dev.parent = &c->dev;
idev->poll = mma8450_poll; idev->poll = mma8450_poll;
idev->poll_interval = POLL_INTERVAL; idev->poll_interval = POLL_INTERVAL;
idev->poll_interval_max = POLL_INTERVAL_MAX; idev->poll_interval_max = POLL_INTERVAL_MAX;
...@@ -202,28 +202,11 @@ static int mma8450_probe(struct i2c_client *c, ...@@ -202,28 +202,11 @@ static int mma8450_probe(struct i2c_client *c,
err = input_register_polled_device(idev); err = input_register_polled_device(idev);
if (err) { if (err) {
dev_err(&c->dev, "failed to register polled input device\n"); dev_err(&c->dev, "failed to register polled input device\n");
goto err_free_mem; return err;
} }
i2c_set_clientdata(c, m); i2c_set_clientdata(c, m);
return 0;
err_free_mem:
input_free_polled_device(idev);
kfree(m);
return err;
}
static int mma8450_remove(struct i2c_client *c)
{
struct mma8450 *m = i2c_get_clientdata(c);
struct input_polled_dev *idev = m->idev;
input_unregister_polled_device(idev);
input_free_polled_device(idev);
kfree(m);
return 0; return 0;
} }
...@@ -242,11 +225,9 @@ MODULE_DEVICE_TABLE(of, mma8450_dt_ids); ...@@ -242,11 +225,9 @@ MODULE_DEVICE_TABLE(of, mma8450_dt_ids);
static struct i2c_driver mma8450_driver = { static struct i2c_driver mma8450_driver = {
.driver = { .driver = {
.name = MMA8450_DRV_NAME, .name = MMA8450_DRV_NAME,
.owner = THIS_MODULE,
.of_match_table = mma8450_dt_ids, .of_match_table = mma8450_dt_ids,
}, },
.probe = mma8450_probe, .probe = mma8450_probe,
.remove = mma8450_remove,
.id_table = mma8450_id, .id_table = mma8450_id,
}; };
......
...@@ -304,7 +304,7 @@ static SIMPLE_DEV_PM_OPS(palmas_pwron_pm, ...@@ -304,7 +304,7 @@ static SIMPLE_DEV_PM_OPS(palmas_pwron_pm,
palmas_pwron_suspend, palmas_pwron_resume); palmas_pwron_suspend, palmas_pwron_resume);
#ifdef CONFIG_OF #ifdef CONFIG_OF
static struct of_device_id of_palmas_pwr_match[] = { static const struct of_device_id of_palmas_pwr_match[] = {
{ .compatible = "ti,palmas-pwrbutton" }, { .compatible = "ti,palmas-pwrbutton" },
{ }, { },
}; };
......
/*
* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
* Copyright (c) 2014, Sony Mobile Communications Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* 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.
*/
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/log2.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/reboot.h>
#include <linux/regmap.h>
#define PON_REV2 0x01
#define PON_RT_STS 0x10
#define PON_KPDPWR_N_SET BIT(0)
#define PON_PS_HOLD_RST_CTL 0x5a
#define PON_PS_HOLD_RST_CTL2 0x5b
#define PON_PS_HOLD_ENABLE BIT(7)
#define PON_PS_HOLD_TYPE_MASK 0x0f
#define PON_PS_HOLD_TYPE_SHUTDOWN 4
#define PON_PS_HOLD_TYPE_HARD_RESET 7
#define PON_PULL_CTL 0x70
#define PON_KPDPWR_PULL_UP BIT(1)
#define PON_DBC_CTL 0x71
#define PON_DBC_DELAY_MASK 0x7
struct pm8941_pwrkey {
struct device *dev;
int irq;
u32 baseaddr;
struct regmap *regmap;
struct input_dev *input;
unsigned int revision;
struct notifier_block reboot_notifier;
};
static int pm8941_reboot_notify(struct notifier_block *nb,
unsigned long code, void *unused)
{
struct pm8941_pwrkey *pwrkey = container_of(nb, struct pm8941_pwrkey,
reboot_notifier);
unsigned int enable_reg;
unsigned int reset_type;
int error;
/* PMICs with revision 0 have the enable bit in same register as ctrl */
if (pwrkey->revision == 0)
enable_reg = PON_PS_HOLD_RST_CTL;
else
enable_reg = PON_PS_HOLD_RST_CTL2;
error = regmap_update_bits(pwrkey->regmap,
pwrkey->baseaddr + enable_reg,
PON_PS_HOLD_ENABLE,
0);
if (error)
dev_err(pwrkey->dev,
"unable to clear ps hold reset enable: %d\n",
error);
/*
* Updates of PON_PS_HOLD_ENABLE requires 3 sleep cycles between
* writes.
*/
usleep_range(100, 1000);
switch (code) {
case SYS_HALT:
case SYS_POWER_OFF:
reset_type = PON_PS_HOLD_TYPE_SHUTDOWN;
break;
case SYS_RESTART:
default:
reset_type = PON_PS_HOLD_TYPE_HARD_RESET;
break;
};
error = regmap_update_bits(pwrkey->regmap,
pwrkey->baseaddr + PON_PS_HOLD_RST_CTL,
PON_PS_HOLD_TYPE_MASK,
reset_type);
if (error)
dev_err(pwrkey->dev, "unable to set ps hold reset type: %d\n",
error);
error = regmap_update_bits(pwrkey->regmap,
pwrkey->baseaddr + enable_reg,
PON_PS_HOLD_ENABLE,
PON_PS_HOLD_ENABLE);
if (error)
dev_err(pwrkey->dev, "unable to re-set enable: %d\n", error);
return NOTIFY_DONE;
}
static irqreturn_t pm8941_pwrkey_irq(int irq, void *_data)
{
struct pm8941_pwrkey *pwrkey = _data;
unsigned int sts;
int error;
error = regmap_read(pwrkey->regmap,
pwrkey->baseaddr + PON_RT_STS, &sts);
if (error)
return IRQ_HANDLED;
input_report_key(pwrkey->input, KEY_POWER, !!(sts & PON_KPDPWR_N_SET));
input_sync(pwrkey->input);
return IRQ_HANDLED;
}
static int __maybe_unused pm8941_pwrkey_suspend(struct device *dev)
{
struct pm8941_pwrkey *pwrkey = dev_get_drvdata(dev);
if (device_may_wakeup(dev))
enable_irq_wake(pwrkey->irq);
return 0;
}
static int __maybe_unused pm8941_pwrkey_resume(struct device *dev)
{
struct pm8941_pwrkey *pwrkey = dev_get_drvdata(dev);
if (device_may_wakeup(dev))
disable_irq_wake(pwrkey->irq);
return 0;
}
static SIMPLE_DEV_PM_OPS(pm8941_pwr_key_pm_ops,
pm8941_pwrkey_suspend, pm8941_pwrkey_resume);
static int pm8941_pwrkey_probe(struct platform_device *pdev)
{
struct pm8941_pwrkey *pwrkey;
bool pull_up;
u32 req_delay;
int error;
if (of_property_read_u32(pdev->dev.of_node, "debounce", &req_delay))
req_delay = 15625;
if (req_delay > 2000000 || req_delay == 0) {
dev_err(&pdev->dev, "invalid debounce time: %u\n", req_delay);
return -EINVAL;
}
pull_up = of_property_read_bool(pdev->dev.of_node, "bias-pull-up");
pwrkey = devm_kzalloc(&pdev->dev, sizeof(*pwrkey), GFP_KERNEL);
if (!pwrkey)
return -ENOMEM;
pwrkey->dev = &pdev->dev;
pwrkey->regmap = dev_get_regmap(pdev->dev.parent, NULL);
if (!pwrkey->regmap) {
dev_err(&pdev->dev, "failed to locate regmap\n");
return -ENODEV;
}
pwrkey->irq = platform_get_irq(pdev, 0);
if (pwrkey->irq < 0) {
dev_err(&pdev->dev, "failed to get irq\n");
return pwrkey->irq;
}
error = of_property_read_u32(pdev->dev.of_node, "reg",
&pwrkey->baseaddr);
if (error)
return error;
error = regmap_read(pwrkey->regmap, pwrkey->baseaddr + PON_REV2,
&pwrkey->revision);
if (error) {
dev_err(&pdev->dev, "failed to set debounce: %d\n", error);
return error;
}
pwrkey->input = devm_input_allocate_device(&pdev->dev);
if (!pwrkey->input) {
dev_dbg(&pdev->dev, "unable to allocate input device\n");
return -ENOMEM;
}
input_set_capability(pwrkey->input, EV_KEY, KEY_POWER);
pwrkey->input->name = "pm8941_pwrkey";
pwrkey->input->phys = "pm8941_pwrkey/input0";
req_delay = (req_delay << 6) / USEC_PER_SEC;
req_delay = ilog2(req_delay);
error = regmap_update_bits(pwrkey->regmap,
pwrkey->baseaddr + PON_DBC_CTL,
PON_DBC_DELAY_MASK,
req_delay);
if (error) {
dev_err(&pdev->dev, "failed to set debounce: %d\n", error);
return error;
}
error = regmap_update_bits(pwrkey->regmap,
pwrkey->baseaddr + PON_PULL_CTL,
PON_KPDPWR_PULL_UP,
pull_up ? PON_KPDPWR_PULL_UP : 0);
if (error) {
dev_err(&pdev->dev, "failed to set pull: %d\n", error);
return error;
}
error = devm_request_threaded_irq(&pdev->dev, pwrkey->irq,
NULL, pm8941_pwrkey_irq,
IRQF_ONESHOT,
"pm8941_pwrkey", pwrkey);
if (error) {
dev_err(&pdev->dev, "failed requesting IRQ: %d\n", error);
return error;
}
error = input_register_device(pwrkey->input);
if (error) {
dev_err(&pdev->dev, "failed to register input device: %d\n",
error);
return error;
}
pwrkey->reboot_notifier.notifier_call = pm8941_reboot_notify,
error = register_reboot_notifier(&pwrkey->reboot_notifier);
if (error) {
dev_err(&pdev->dev, "failed to register reboot notifier: %d\n",
error);
return error;
}
platform_set_drvdata(pdev, pwrkey);
device_init_wakeup(&pdev->dev, 1);
return 0;
}
static int pm8941_pwrkey_remove(struct platform_device *pdev)
{
struct pm8941_pwrkey *pwrkey = platform_get_drvdata(pdev);
device_init_wakeup(&pdev->dev, 0);
unregister_reboot_notifier(&pwrkey->reboot_notifier);
return 0;
}
static const struct of_device_id pm8941_pwr_key_id_table[] = {
{ .compatible = "qcom,pm8941-pwrkey" },
{ }
};
MODULE_DEVICE_TABLE(of, pm8941_pwr_key_id_table);
static struct platform_driver pm8941_pwrkey_driver = {
.probe = pm8941_pwrkey_probe,
.remove = pm8941_pwrkey_remove,
.driver = {
.name = "pm8941-pwrkey",
.pm = &pm8941_pwr_key_pm_ops,
.of_match_table = of_match_ptr(pm8941_pwr_key_id_table),
},
};
module_platform_driver(pm8941_pwrkey_driver);
MODULE_DESCRIPTION("PM8941 Power Key driver");
MODULE_LICENSE("GPL v2");
...@@ -50,7 +50,6 @@ static int pwm_beeper_event(struct input_dev *input, ...@@ -50,7 +50,6 @@ static int pwm_beeper_event(struct input_dev *input,
} }
if (value == 0) { if (value == 0) {
pwm_config(beeper->pwm, 0, 0);
pwm_disable(beeper->pwm); pwm_disable(beeper->pwm);
} else { } else {
period = HZ_TO_NANOSECONDS(value); period = HZ_TO_NANOSECONDS(value);
...@@ -169,12 +168,6 @@ static int __maybe_unused pwm_beeper_resume(struct device *dev) ...@@ -169,12 +168,6 @@ static int __maybe_unused pwm_beeper_resume(struct device *dev)
static SIMPLE_DEV_PM_OPS(pwm_beeper_pm_ops, static SIMPLE_DEV_PM_OPS(pwm_beeper_pm_ops,
pwm_beeper_suspend, pwm_beeper_resume); pwm_beeper_suspend, pwm_beeper_resume);
#ifdef CONFIG_PM_SLEEP
#define PWM_BEEPER_PM_OPS (&pwm_beeper_pm_ops)
#else
#define PWM_BEEPER_PM_OPS NULL
#endif
#ifdef CONFIG_OF #ifdef CONFIG_OF
static const struct of_device_id pwm_beeper_match[] = { static const struct of_device_id pwm_beeper_match[] = {
{ .compatible = "pwm-beeper", }, { .compatible = "pwm-beeper", },
...@@ -187,7 +180,7 @@ static struct platform_driver pwm_beeper_driver = { ...@@ -187,7 +180,7 @@ static struct platform_driver pwm_beeper_driver = {
.remove = pwm_beeper_remove, .remove = pwm_beeper_remove,
.driver = { .driver = {
.name = "pwm-beeper", .name = "pwm-beeper",
.pm = PWM_BEEPER_PM_OPS, .pm = &pwm_beeper_pm_ops,
.of_match_table = of_match_ptr(pwm_beeper_match), .of_match_table = of_match_ptr(pwm_beeper_match),
}, },
}; };
......
...@@ -245,7 +245,7 @@ static int __maybe_unused regulator_haptic_resume(struct device *dev) ...@@ -245,7 +245,7 @@ static int __maybe_unused regulator_haptic_resume(struct device *dev)
static SIMPLE_DEV_PM_OPS(regulator_haptic_pm_ops, static SIMPLE_DEV_PM_OPS(regulator_haptic_pm_ops,
regulator_haptic_suspend, regulator_haptic_resume); regulator_haptic_suspend, regulator_haptic_resume);
static struct of_device_id regulator_haptic_dt_match[] = { static const struct of_device_id regulator_haptic_dt_match[] = {
{ .compatible = "regulator-haptic" }, { .compatible = "regulator-haptic" },
{ /* sentinel */ }, { /* sentinel */ },
}; };
......
...@@ -106,7 +106,7 @@ static int tps65218_pwron_probe(struct platform_device *pdev) ...@@ -106,7 +106,7 @@ static int tps65218_pwron_probe(struct platform_device *pdev)
return 0; return 0;
} }
static struct of_device_id of_tps65218_pwr_match[] = { static const struct of_device_id of_tps65218_pwr_match[] = {
{ .compatible = "ti,tps65218-pwrbutton" }, { .compatible = "ti,tps65218-pwrbutton" },
{ }, { },
}; };
......
This diff is collapsed.
...@@ -22,13 +22,89 @@ ...@@ -22,13 +22,89 @@
#define ALPS_PROTO_V5 0x500 #define ALPS_PROTO_V5 0x500
#define ALPS_PROTO_V6 0x600 #define ALPS_PROTO_V6 0x600
#define ALPS_PROTO_V7 0x700 /* t3btl t4s */ #define ALPS_PROTO_V7 0x700 /* t3btl t4s */
#define ALPS_PROTO_V8 0x800 /* SS4btl SS4s */
#define MAX_TOUCHES 2 #define MAX_TOUCHES 4
#define DOLPHIN_COUNT_PER_ELECTRODE 64 #define DOLPHIN_COUNT_PER_ELECTRODE 64
#define DOLPHIN_PROFILE_XOFFSET 8 /* x-electrode offset */ #define DOLPHIN_PROFILE_XOFFSET 8 /* x-electrode offset */
#define DOLPHIN_PROFILE_YOFFSET 1 /* y-electrode offset */ #define DOLPHIN_PROFILE_YOFFSET 1 /* y-electrode offset */
/*
* enum SS4_PACKET_ID - defines the packet type for V8
* SS4_PACKET_ID_IDLE: There's no finger and no button activity.
* SS4_PACKET_ID_ONE: There's one finger on touchpad
* or there's button activities.
* SS4_PACKET_ID_TWO: There's two or more fingers on touchpad
* SS4_PACKET_ID_MULTI: There's three or more fingers on touchpad
*/
enum SS4_PACKET_ID {
SS4_PACKET_ID_IDLE = 0,
SS4_PACKET_ID_ONE,
SS4_PACKET_ID_TWO,
SS4_PACKET_ID_MULTI,
};
#define SS4_COUNT_PER_ELECTRODE 256
#define SS4_NUMSENSOR_XOFFSET 7
#define SS4_NUMSENSOR_YOFFSET 7
#define SS4_MIN_PITCH_MM 50
#define SS4_MASK_NORMAL_BUTTONS 0x07
#define SS4_1F_X_V2(_b) ((_b[0] & 0x0007) | \
((_b[1] << 3) & 0x0078) | \
((_b[1] << 2) & 0x0380) | \
((_b[2] << 5) & 0x1C00) \
)
#define SS4_1F_Y_V2(_b) (((_b[2]) & 0x000F) | \
((_b[3] >> 2) & 0x0030) | \
((_b[4] << 6) & 0x03C0) | \
((_b[4] << 5) & 0x0C00) \
)
#define SS4_1F_Z_V2(_b) (((_b[5]) & 0x0F) | \
((_b[5] >> 1) & 0x70) | \
((_b[4]) & 0x80) \
)
#define SS4_1F_LFB_V2(_b) (((_b[2] >> 4) & 0x01) == 0x01)
#define SS4_MF_LF_V2(_b, _i) ((_b[1 + (_i) * 3] & 0x0004) == 0x0004)
#define SS4_BTN_V2(_b) ((_b[0] >> 5) & SS4_MASK_NORMAL_BUTTONS)
#define SS4_STD_MF_X_V2(_b, _i) (((_b[0 + (_i) * 3] << 5) & 0x00E0) | \
((_b[1 + _i * 3] << 5) & 0x1F00) \
)
#define SS4_STD_MF_Y_V2(_b, _i) (((_b[1 + (_i) * 3] << 3) & 0x0010) | \
((_b[2 + (_i) * 3] << 5) & 0x01E0) | \
((_b[2 + (_i) * 3] << 4) & 0x0E00) \
)
#define SS4_BTL_MF_X_V2(_b, _i) (SS4_STD_MF_X_V2(_b, _i) | \
((_b[0 + (_i) * 3] >> 3) & 0x0010) \
)
#define SS4_BTL_MF_Y_V2(_b, _i) (SS4_STD_MF_Y_V2(_b, _i) | \
((_b[0 + (_i) * 3] >> 3) & 0x0008) \
)
#define SS4_MF_Z_V2(_b, _i) (((_b[1 + (_i) * 3]) & 0x0001) | \
((_b[1 + (_i) * 3] >> 1) & 0x0002) \
)
#define SS4_IS_MF_CONTINUE(_b) ((_b[2] & 0x10) == 0x10)
#define SS4_IS_5F_DETECTED(_b) ((_b[2] & 0x10) == 0x10)
#define SS4_MFPACKET_NO_AX 8160 /* X-Coordinate value */
#define SS4_MFPACKET_NO_AY 4080 /* Y-Coordinate value */
#define SS4_MFPACKET_NO_AX_BL 8176 /* Buttonless X-Coordinate value */
#define SS4_MFPACKET_NO_AY_BL 4088 /* Buttonless Y-Coordinate value */
/* /*
* enum V7_PACKET_ID - defines the packet type for V7 * enum V7_PACKET_ID - defines the packet type for V7
* V7_PACKET_ID_IDLE: There's no finger and no button activity. * V7_PACKET_ID_IDLE: There's no finger and no button activity.
......
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
*/ */
#ifndef _ELAN_I2C_H #ifndef _ELAN_I2C_H
#define _ELAN_i2C_H #define _ELAN_I2C_H
#include <linux/types.h> #include <linux/types.h>
......
...@@ -99,7 +99,7 @@ static int elan_enable_power(struct elan_tp_data *data) ...@@ -99,7 +99,7 @@ static int elan_enable_power(struct elan_tp_data *data)
error = regulator_enable(data->vcc); error = regulator_enable(data->vcc);
if (error) { if (error) {
dev_err(&data->client->dev, dev_err(&data->client->dev,
"Failed to enable regulator: %d\n", error); "failed to enable regulator: %d\n", error);
return error; return error;
} }
...@@ -111,6 +111,7 @@ static int elan_enable_power(struct elan_tp_data *data) ...@@ -111,6 +111,7 @@ static int elan_enable_power(struct elan_tp_data *data)
msleep(30); msleep(30);
} while (--repeat > 0); } while (--repeat > 0);
dev_err(&data->client->dev, "failed to enable power: %d\n", error);
return error; return error;
} }
...@@ -125,7 +126,7 @@ static int elan_disable_power(struct elan_tp_data *data) ...@@ -125,7 +126,7 @@ static int elan_disable_power(struct elan_tp_data *data)
error = regulator_disable(data->vcc); error = regulator_disable(data->vcc);
if (error) { if (error) {
dev_err(&data->client->dev, dev_err(&data->client->dev,
"Failed to disable regulator: %d\n", "failed to disable regulator: %d\n",
error); error);
/* Attempt to power the chip back up */ /* Attempt to power the chip back up */
data->ops->power_control(data->client, true); data->ops->power_control(data->client, true);
...@@ -138,6 +139,7 @@ static int elan_disable_power(struct elan_tp_data *data) ...@@ -138,6 +139,7 @@ static int elan_disable_power(struct elan_tp_data *data)
msleep(30); msleep(30);
} while (--repeat > 0); } while (--repeat > 0);
dev_err(&data->client->dev, "failed to disable power: %d\n", error);
return error; return error;
} }
...@@ -196,7 +198,6 @@ static int elan_initialize(struct elan_tp_data *data) ...@@ -196,7 +198,6 @@ static int elan_initialize(struct elan_tp_data *data)
if (!error) if (!error)
return 0; return 0;
repeat--;
msleep(30); msleep(30);
} while (--repeat > 0); } while (--repeat > 0);
...@@ -1084,16 +1085,18 @@ static int __maybe_unused elan_resume(struct device *dev) ...@@ -1084,16 +1085,18 @@ static int __maybe_unused elan_resume(struct device *dev)
} }
error = elan_enable_power(data); error = elan_enable_power(data);
if (error) if (error) {
dev_err(dev, "power up when resuming failed: %d\n", error); dev_err(dev, "power up when resuming failed: %d\n", error);
goto err;
}
error = elan_initialize(data); error = elan_initialize(data);
if (error) if (error)
dev_err(dev, "initialize when resuming failed: %d\n", error); dev_err(dev, "initialize when resuming failed: %d\n", error);
err:
enable_irq(data->client->irq); enable_irq(data->client->irq);
return error;
return 0;
} }
static SIMPLE_DEV_PM_OPS(elan_pm_ops, elan_suspend, elan_resume); static SIMPLE_DEV_PM_OPS(elan_pm_ops, elan_suspend, elan_resume);
......
...@@ -117,7 +117,15 @@ static int elan_i2c_write_cmd(struct i2c_client *client, u16 reg, u16 cmd) ...@@ -117,7 +117,15 @@ static int elan_i2c_write_cmd(struct i2c_client *client, u16 reg, u16 cmd)
int ret; int ret;
ret = i2c_transfer(client->adapter, &msg, 1); ret = i2c_transfer(client->adapter, &msg, 1);
return ret == 1 ? 0 : (ret < 0 ? ret : -EIO); if (ret != 1) {
if (ret >= 0)
ret = -EIO;
dev_err(&client->dev, "writing cmd (0x%04x) failed: %d\n",
reg, ret);
return ret;
}
return 0;
} }
static int elan_i2c_initialize(struct i2c_client *client) static int elan_i2c_initialize(struct i2c_client *client)
......
...@@ -892,6 +892,21 @@ static psmouse_ret_t elantech_process_byte(struct psmouse *psmouse) ...@@ -892,6 +892,21 @@ static psmouse_ret_t elantech_process_byte(struct psmouse *psmouse)
return PSMOUSE_FULL_PACKET; return PSMOUSE_FULL_PACKET;
} }
/*
* This writes the reg_07 value again to the hardware at the end of every
* set_rate call because the register loses its value. reg_07 allows setting
* absolute mode on v4 hardware
*/
static void elantech_set_rate_restore_reg_07(struct psmouse *psmouse,
unsigned int rate)
{
struct elantech_data *etd = psmouse->private;
etd->original_set_rate(psmouse, rate);
if (elantech_write_reg(psmouse, 0x07, etd->reg_07))
psmouse_err(psmouse, "restoring reg_07 failed\n");
}
/* /*
* Put the touchpad into absolute mode * Put the touchpad into absolute mode
*/ */
...@@ -1094,6 +1109,8 @@ static int elantech_get_resolution_v4(struct psmouse *psmouse, ...@@ -1094,6 +1109,8 @@ static int elantech_get_resolution_v4(struct psmouse *psmouse,
* Asus K53SV 0x450f01 78, 15, 0c 2 hw buttons * Asus K53SV 0x450f01 78, 15, 0c 2 hw buttons
* Asus G46VW 0x460f02 00, 18, 0c 2 hw buttons * Asus G46VW 0x460f02 00, 18, 0c 2 hw buttons
* Asus G750JX 0x360f00 00, 16, 0c 2 hw buttons * Asus G750JX 0x360f00 00, 16, 0c 2 hw buttons
* Asus TP500LN 0x381f17 10, 14, 0e clickpad
* Asus X750JN 0x381f17 10, 14, 0e clickpad
* Asus UX31 0x361f00 20, 15, 0e clickpad * Asus UX31 0x361f00 20, 15, 0e clickpad
* Asus UX32VD 0x361f02 00, 15, 0e clickpad * Asus UX32VD 0x361f02 00, 15, 0e clickpad
* Avatar AVIU-145A2 0x361f00 ? clickpad * Avatar AVIU-145A2 0x361f00 ? clickpad
...@@ -1635,6 +1652,11 @@ int elantech_init(struct psmouse *psmouse) ...@@ -1635,6 +1652,11 @@ int elantech_init(struct psmouse *psmouse)
goto init_fail; goto init_fail;
} }
if (etd->fw_version == 0x381f17) {
etd->original_set_rate = psmouse->set_rate;
psmouse->set_rate = elantech_set_rate_restore_reg_07;
}
if (elantech_set_input_params(psmouse)) { if (elantech_set_input_params(psmouse)) {
psmouse_err(psmouse, "failed to query touchpad range.\n"); psmouse_err(psmouse, "failed to query touchpad range.\n");
goto init_fail; goto init_fail;
......
...@@ -142,6 +142,7 @@ struct elantech_data { ...@@ -142,6 +142,7 @@ struct elantech_data {
struct finger_pos mt[ETP_MAX_FINGERS]; struct finger_pos mt[ETP_MAX_FINGERS];
unsigned char parity[256]; unsigned char parity[256];
int (*send_cmd)(struct psmouse *psmouse, unsigned char c, unsigned char *param); int (*send_cmd)(struct psmouse *psmouse, unsigned char c, unsigned char *param);
void (*original_set_rate)(struct psmouse *psmouse, unsigned int rate);
}; };
#ifdef CONFIG_MOUSE_PS2_ELANTECH #ifdef CONFIG_MOUSE_PS2_ELANTECH
......
...@@ -474,19 +474,45 @@ static int psmouse_poll(struct psmouse *psmouse) ...@@ -474,19 +474,45 @@ static int psmouse_poll(struct psmouse *psmouse)
PSMOUSE_CMD_POLL | (psmouse->pktsize << 8)); PSMOUSE_CMD_POLL | (psmouse->pktsize << 8));
} }
static bool psmouse_check_pnp_id(const char *id, const char * const ids[])
{
int i;
for (i = 0; ids[i]; i++)
if (!strcasecmp(id, ids[i]))
return true;
return false;
}
/* /*
* psmouse_matches_pnp_id - check if psmouse matches one of the passed in ids. * psmouse_matches_pnp_id - check if psmouse matches one of the passed in ids.
*/ */
bool psmouse_matches_pnp_id(struct psmouse *psmouse, const char * const ids[]) bool psmouse_matches_pnp_id(struct psmouse *psmouse, const char * const ids[])
{ {
int i; struct serio *serio = psmouse->ps2dev.serio;
char *p, *fw_id_copy, *save_ptr;
bool found = false;
if (!strncmp(psmouse->ps2dev.serio->firmware_id, "PNP:", 4)) if (strncmp(serio->firmware_id, "PNP: ", 5))
for (i = 0; ids[i]; i++) return false;
if (strstr(psmouse->ps2dev.serio->firmware_id, ids[i]))
return true;
fw_id_copy = kstrndup(&serio->firmware_id[5],
sizeof(serio->firmware_id) - 5,
GFP_KERNEL);
if (!fw_id_copy)
return false; return false;
save_ptr = fw_id_copy;
while ((p = strsep(&fw_id_copy, " ")) != NULL) {
if (psmouse_check_pnp_id(p, ids)) {
found = true;
break;
}
}
kfree(save_ptr);
return found;
} }
/* /*
......
...@@ -67,6 +67,9 @@ ...@@ -67,6 +67,9 @@
#define X_MAX_POSITIVE 8176 #define X_MAX_POSITIVE 8176
#define Y_MAX_POSITIVE 8176 #define Y_MAX_POSITIVE 8176
/* maximum ABS_MT_POSITION displacement (in mm) */
#define DMAX 10
/***************************************************************************** /*****************************************************************************
* Stuff we need even when we do not want native Synaptics support * Stuff we need even when we do not want native Synaptics support
****************************************************************************/ ****************************************************************************/
...@@ -203,6 +206,13 @@ static const char * const topbuttonpad_pnp_ids[] = { ...@@ -203,6 +206,13 @@ static const char * const topbuttonpad_pnp_ids[] = {
NULL NULL
}; };
/* This list has been kindly provided by Synaptics. */
static const char * const forcepad_pnp_ids[] = {
"SYN300D",
"SYN3014",
NULL
};
/***************************************************************************** /*****************************************************************************
* Synaptics communications functions * Synaptics communications functions
****************************************************************************/ ****************************************************************************/
...@@ -687,8 +697,6 @@ static void synaptics_parse_ext_buttons(const unsigned char buf[], ...@@ -687,8 +697,6 @@ static void synaptics_parse_ext_buttons(const unsigned char buf[],
hw->ext_buttons |= (buf[5] & ext_mask) << ext_bits; hw->ext_buttons |= (buf[5] & ext_mask) << ext_bits;
} }
static bool is_forcepad;
static int synaptics_parse_hw_state(const unsigned char buf[], static int synaptics_parse_hw_state(const unsigned char buf[],
struct synaptics_data *priv, struct synaptics_data *priv,
struct synaptics_hw_state *hw) struct synaptics_hw_state *hw)
...@@ -718,7 +726,7 @@ static int synaptics_parse_hw_state(const unsigned char buf[], ...@@ -718,7 +726,7 @@ static int synaptics_parse_hw_state(const unsigned char buf[],
hw->left = (buf[0] & 0x01) ? 1 : 0; hw->left = (buf[0] & 0x01) ? 1 : 0;
hw->right = (buf[0] & 0x02) ? 1 : 0; hw->right = (buf[0] & 0x02) ? 1 : 0;
if (is_forcepad) { if (priv->is_forcepad) {
/* /*
* ForcePads, like Clickpads, use middle button * ForcePads, like Clickpads, use middle button
* bits to report primary button clicks. * bits to report primary button clicks.
...@@ -917,7 +925,7 @@ static void synaptics_report_mt_data(struct psmouse *psmouse, ...@@ -917,7 +925,7 @@ static void synaptics_report_mt_data(struct psmouse *psmouse,
pos[i].y = synaptics_invert_y(hw[i]->y); pos[i].y = synaptics_invert_y(hw[i]->y);
} }
input_mt_assign_slots(dev, slot, pos, nsemi, 0); input_mt_assign_slots(dev, slot, pos, nsemi, DMAX * priv->x_res);
for (i = 0; i < nsemi; i++) { for (i = 0; i < nsemi; i++) {
input_mt_slot(dev, slot[i]); input_mt_slot(dev, slot[i]);
...@@ -1186,7 +1194,7 @@ static void set_input_params(struct psmouse *psmouse, ...@@ -1186,7 +1194,7 @@ static void set_input_params(struct psmouse *psmouse,
ABS_MT_POSITION_Y); ABS_MT_POSITION_Y);
/* Image sensors can report per-contact pressure */ /* Image sensors can report per-contact pressure */
input_set_abs_params(dev, ABS_MT_PRESSURE, 0, 255, 0, 0); input_set_abs_params(dev, ABS_MT_PRESSURE, 0, 255, 0, 0);
input_mt_init_slots(dev, 2, INPUT_MT_POINTER | INPUT_MT_TRACK); input_mt_init_slots(dev, 3, INPUT_MT_POINTER | INPUT_MT_TRACK);
/* Image sensors can signal 4 and 5 finger clicks */ /* Image sensors can signal 4 and 5 finger clicks */
__set_bit(BTN_TOOL_QUADTAP, dev->keybit); __set_bit(BTN_TOOL_QUADTAP, dev->keybit);
...@@ -1418,29 +1426,11 @@ static const struct dmi_system_id __initconst cr48_dmi_table[] = { ...@@ -1418,29 +1426,11 @@ static const struct dmi_system_id __initconst cr48_dmi_table[] = {
{ } { }
}; };
static const struct dmi_system_id forcepad_dmi_table[] __initconst = {
#if defined(CONFIG_DMI) && defined(CONFIG_X86)
{
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
DMI_MATCH(DMI_PRODUCT_NAME, "HP EliteBook Folio 1040 G1"),
},
},
#endif
{ }
};
void __init synaptics_module_init(void) void __init synaptics_module_init(void)
{ {
impaired_toshiba_kbc = dmi_check_system(toshiba_dmi_table); impaired_toshiba_kbc = dmi_check_system(toshiba_dmi_table);
broken_olpc_ec = dmi_check_system(olpc_dmi_table); broken_olpc_ec = dmi_check_system(olpc_dmi_table);
cr48_profile_sensor = dmi_check_system(cr48_dmi_table); cr48_profile_sensor = dmi_check_system(cr48_dmi_table);
/*
* Unfortunately ForcePad capability is not exported over PS/2,
* so we have to resort to checking DMI.
*/
is_forcepad = dmi_check_system(forcepad_dmi_table);
} }
static int __synaptics_init(struct psmouse *psmouse, bool absolute_mode) static int __synaptics_init(struct psmouse *psmouse, bool absolute_mode)
...@@ -1475,6 +1465,12 @@ static int __synaptics_init(struct psmouse *psmouse, bool absolute_mode) ...@@ -1475,6 +1465,12 @@ static int __synaptics_init(struct psmouse *psmouse, bool absolute_mode)
if (SYN_ID_DISGEST_SUPPORTED(priv->identity)) if (SYN_ID_DISGEST_SUPPORTED(priv->identity))
priv->disable_gesture = true; priv->disable_gesture = true;
/*
* Unfortunately ForcePad capability is not exported over PS/2,
* so we have to resort to checking PNP IDs.
*/
priv->is_forcepad = psmouse_matches_pnp_id(psmouse, forcepad_pnp_ids);
if (synaptics_set_mode(psmouse)) { if (synaptics_set_mode(psmouse)) {
psmouse_err(psmouse, "Unable to initialize device.\n"); psmouse_err(psmouse, "Unable to initialize device.\n");
goto init_fail; goto init_fail;
......
...@@ -196,6 +196,7 @@ struct synaptics_data { ...@@ -196,6 +196,7 @@ struct synaptics_data {
unsigned long press_start; unsigned long press_start;
bool press; bool press;
bool report_press; bool report_press;
bool is_forcepad;
}; };
void synaptics_module_init(void); void synaptics_module_init(void);
......
...@@ -31,7 +31,6 @@ ...@@ -31,7 +31,6 @@
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/ioport.h> #include <linux/ioport.h>
#include <linux/pci_ids.h>
#include <asm/irq.h> #include <asm/irq.h>
#include <asm/io.h> #include <asm/io.h>
......
...@@ -1162,13 +1162,32 @@ static int i8042_controller_resume(bool force_reset) ...@@ -1162,13 +1162,32 @@ static int i8042_controller_resume(bool force_reset)
static int i8042_pm_suspend(struct device *dev) static int i8042_pm_suspend(struct device *dev)
{ {
int i;
i8042_controller_reset(true); i8042_controller_reset(true);
/* Set up serio interrupts for system wakeup. */
for (i = 0; i < I8042_NUM_PORTS; i++) {
struct serio *serio = i8042_ports[i].serio;
if (serio && device_may_wakeup(&serio->dev))
enable_irq_wake(i8042_ports[i].irq);
}
return 0; return 0;
} }
static int i8042_pm_resume(struct device *dev) static int i8042_pm_resume(struct device *dev)
{ {
int i;
for (i = 0; i < I8042_NUM_PORTS; i++) {
struct serio *serio = i8042_ports[i].serio;
if (serio && device_may_wakeup(&serio->dev))
disable_irq_wake(i8042_ports[i].irq);
}
/* /*
* On resume from S2R we always try to reset the controller * On resume from S2R we always try to reset the controller
* to bring it in a sane state. (In case of S2D we expect * to bring it in a sane state. (In case of S2D we expect
...@@ -1300,13 +1319,16 @@ static void __init i8042_register_ports(void) ...@@ -1300,13 +1319,16 @@ static void __init i8042_register_ports(void)
int i; int i;
for (i = 0; i < I8042_NUM_PORTS; i++) { for (i = 0; i < I8042_NUM_PORTS; i++) {
if (i8042_ports[i].serio) { struct serio *serio = i8042_ports[i].serio;
if (serio) {
printk(KERN_INFO "serio: %s at %#lx,%#lx irq %d\n", printk(KERN_INFO "serio: %s at %#lx,%#lx irq %d\n",
i8042_ports[i].serio->name, serio->name,
(unsigned long) I8042_DATA_REG, (unsigned long) I8042_DATA_REG,
(unsigned long) I8042_COMMAND_REG, (unsigned long) I8042_COMMAND_REG,
i8042_ports[i].irq); i8042_ports[i].irq);
serio_register_port(i8042_ports[i].serio); serio_register_port(serio);
device_set_wakeup_capable(&serio->dev, true);
} }
} }
} }
......
...@@ -140,6 +140,19 @@ config TOUCHSCREEN_BU21013 ...@@ -140,6 +140,19 @@ config TOUCHSCREEN_BU21013
To compile this driver as a module, choose M here: the To compile this driver as a module, choose M here: the
module will be called bu21013_ts. module will be called bu21013_ts.
config TOUCHSCREEN_CHIPONE_ICN8318
tristate "chipone icn8318 touchscreen controller"
depends on GPIOLIB
depends on I2C
depends on OF
help
Say Y here if you have a ChipOne icn8318 based I2C touchscreen.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called chipone_icn8318.
config TOUCHSCREEN_CY8CTMG110 config TOUCHSCREEN_CY8CTMG110
tristate "cy8ctmg110 touchscreen" tristate "cy8ctmg110 touchscreen"
depends on I2C depends on I2C
...@@ -297,11 +310,12 @@ config TOUCHSCREEN_FUJITSU ...@@ -297,11 +310,12 @@ config TOUCHSCREEN_FUJITSU
config TOUCHSCREEN_GOODIX config TOUCHSCREEN_GOODIX
tristate "Goodix I2C touchscreen" tristate "Goodix I2C touchscreen"
depends on I2C && ACPI depends on I2C
help help
Say Y here if you have the Goodix touchscreen (such as one Say Y here if you have the Goodix touchscreen (such as one
installed in Onda v975w tablets) connected to your installed in Onda v975w tablets) connected to your
system. system. It also supports 5-finger chip models, which can be
found on ARM tablets, like Wexler TAB7200 and MSI Primo73.
If unsure, say N. If unsure, say N.
...@@ -323,6 +337,18 @@ config TOUCHSCREEN_ILI210X ...@@ -323,6 +337,18 @@ config TOUCHSCREEN_ILI210X
To compile this driver as a module, choose M here: the To compile this driver as a module, choose M here: the
module will be called ili210x. module will be called ili210x.
config TOUCHSCREEN_IPROC
tristate "IPROC touch panel driver support"
depends on ARCH_BCM_IPROC || COMPILE_TEST
help
Say Y here if you want to add support for the IPROC touch
controller to your system.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called bcm_iproc_tsc.
config TOUCHSCREEN_S3C2410 config TOUCHSCREEN_S3C2410
tristate "Samsung S3C2410/generic touchscreen input driver" tristate "Samsung S3C2410/generic touchscreen input driver"
depends on ARCH_S3C24XX || SAMSUNG_DEV_TS depends on ARCH_S3C24XX || SAMSUNG_DEV_TS
...@@ -962,6 +988,17 @@ config TOUCHSCREEN_SUR40 ...@@ -962,6 +988,17 @@ config TOUCHSCREEN_SUR40
To compile this driver as a module, choose M here: the To compile this driver as a module, choose M here: the
module will be called sur40. module will be called sur40.
config TOUCHSCREEN_SX8654
tristate "Semtech SX8654 touchscreen"
depends on I2C
help
Say Y here if you have a Semtech SX8654 touchscreen controller.
If unsure, say N
To compile this driver as a module, choose M here: the
module will be called sx8654.
config TOUCHSCREEN_TPS6507X config TOUCHSCREEN_TPS6507X
tristate "TPS6507x based touchscreens" tristate "TPS6507x based touchscreens"
depends on I2C depends on I2C
......
...@@ -17,6 +17,7 @@ obj-$(CONFIG_TOUCHSCREEN_AR1021_I2C) += ar1021_i2c.o ...@@ -17,6 +17,7 @@ obj-$(CONFIG_TOUCHSCREEN_AR1021_I2C) += ar1021_i2c.o
obj-$(CONFIG_TOUCHSCREEN_ATMEL_MXT) += atmel_mxt_ts.o obj-$(CONFIG_TOUCHSCREEN_ATMEL_MXT) += atmel_mxt_ts.o
obj-$(CONFIG_TOUCHSCREEN_AUO_PIXCIR) += auo-pixcir-ts.o obj-$(CONFIG_TOUCHSCREEN_AUO_PIXCIR) += auo-pixcir-ts.o
obj-$(CONFIG_TOUCHSCREEN_BU21013) += bu21013_ts.o obj-$(CONFIG_TOUCHSCREEN_BU21013) += bu21013_ts.o
obj-$(CONFIG_TOUCHSCREEN_CHIPONE_ICN8318) += chipone_icn8318.o
obj-$(CONFIG_TOUCHSCREEN_CY8CTMG110) += cy8ctmg110_ts.o obj-$(CONFIG_TOUCHSCREEN_CY8CTMG110) += cy8ctmg110_ts.o
obj-$(CONFIG_TOUCHSCREEN_CYTTSP_CORE) += cyttsp_core.o obj-$(CONFIG_TOUCHSCREEN_CYTTSP_CORE) += cyttsp_core.o
obj-$(CONFIG_TOUCHSCREEN_CYTTSP_I2C) += cyttsp_i2c.o cyttsp_i2c_common.o obj-$(CONFIG_TOUCHSCREEN_CYTTSP_I2C) += cyttsp_i2c.o cyttsp_i2c_common.o
...@@ -39,6 +40,7 @@ obj-$(CONFIG_TOUCHSCREEN_GOODIX) += goodix.o ...@@ -39,6 +40,7 @@ obj-$(CONFIG_TOUCHSCREEN_GOODIX) += goodix.o
obj-$(CONFIG_TOUCHSCREEN_ILI210X) += ili210x.o obj-$(CONFIG_TOUCHSCREEN_ILI210X) += ili210x.o
obj-$(CONFIG_TOUCHSCREEN_INEXIO) += inexio.o obj-$(CONFIG_TOUCHSCREEN_INEXIO) += inexio.o
obj-$(CONFIG_TOUCHSCREEN_INTEL_MID) += intel-mid-touch.o obj-$(CONFIG_TOUCHSCREEN_INTEL_MID) += intel-mid-touch.o
obj-$(CONFIG_TOUCHSCREEN_IPROC) += bcm_iproc_tsc.o
obj-$(CONFIG_TOUCHSCREEN_LPC32XX) += lpc32xx_ts.o obj-$(CONFIG_TOUCHSCREEN_LPC32XX) += lpc32xx_ts.o
obj-$(CONFIG_TOUCHSCREEN_MAX11801) += max11801_ts.o obj-$(CONFIG_TOUCHSCREEN_MAX11801) += max11801_ts.o
obj-$(CONFIG_TOUCHSCREEN_MC13783) += mc13783_ts.o obj-$(CONFIG_TOUCHSCREEN_MC13783) += mc13783_ts.o
...@@ -79,5 +81,6 @@ obj-$(CONFIG_TOUCHSCREEN_WM97XX_ATMEL) += atmel-wm97xx.o ...@@ -79,5 +81,6 @@ obj-$(CONFIG_TOUCHSCREEN_WM97XX_ATMEL) += atmel-wm97xx.o
obj-$(CONFIG_TOUCHSCREEN_WM97XX_MAINSTONE) += mainstone-wm97xx.o obj-$(CONFIG_TOUCHSCREEN_WM97XX_MAINSTONE) += mainstone-wm97xx.o
obj-$(CONFIG_TOUCHSCREEN_WM97XX_ZYLONITE) += zylonite-wm97xx.o obj-$(CONFIG_TOUCHSCREEN_WM97XX_ZYLONITE) += zylonite-wm97xx.o
obj-$(CONFIG_TOUCHSCREEN_W90X900) += w90p910_ts.o obj-$(CONFIG_TOUCHSCREEN_W90X900) += w90p910_ts.o
obj-$(CONFIG_TOUCHSCREEN_SX8654) += sx8654.o
obj-$(CONFIG_TOUCHSCREEN_TPS6507X) += tps6507x-ts.o obj-$(CONFIG_TOUCHSCREEN_TPS6507X) += tps6507x-ts.o
obj-$(CONFIG_TOUCHSCREEN_ZFORCE) += zforce_ts.o obj-$(CONFIG_TOUCHSCREEN_ZFORCE) += zforce_ts.o
...@@ -157,7 +157,7 @@ static const struct i2c_device_id ar1021_i2c_id[] = { ...@@ -157,7 +157,7 @@ static const struct i2c_device_id ar1021_i2c_id[] = {
}; };
MODULE_DEVICE_TABLE(i2c, ar1021_i2c_id); MODULE_DEVICE_TABLE(i2c, ar1021_i2c_id);
static struct of_device_id ar1021_i2c_of_match[] = { static const struct of_device_id ar1021_i2c_of_match[] = {
{ .compatible = "microchip,ar1021-i2c", }, { .compatible = "microchip,ar1021-i2c", },
{ } { }
}; };
......
This diff is collapsed.
This diff is collapsed.
/*
* Driver for ChipOne icn8318 i2c touchscreen controller
*
* Copyright (c) 2015 Red Hat Inc.
*
* 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.
*
* Red Hat authors:
* Hans de Goede <hdegoede@redhat.com>
*/
#include <linux/gpio/consumer.h>
#include <linux/interrupt.h>
#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/input/mt.h>
#include <linux/module.h>
#include <linux/of.h>
#define ICN8318_REG_POWER 4
#define ICN8318_REG_TOUCHDATA 16
#define ICN8318_POWER_ACTIVE 0
#define ICN8318_POWER_MONITOR 1
#define ICN8318_POWER_HIBERNATE 2
#define ICN8318_MAX_TOUCHES 5
struct icn8318_touch {
__u8 slot;
__be16 x;
__be16 y;
__u8 pressure; /* Seems more like finger width then pressure really */
__u8 event;
/* The difference between 2 and 3 is unclear */
#define ICN8318_EVENT_NO_DATA 1 /* No finger seen yet since wakeup */
#define ICN8318_EVENT_UPDATE1 2 /* New or updated coordinates */
#define ICN8318_EVENT_UPDATE2 3 /* New or updated coordinates */
#define ICN8318_EVENT_END 4 /* Finger lifted */
} __packed;
struct icn8318_touch_data {
__u8 softbutton;
__u8 touch_count;
struct icn8318_touch touches[ICN8318_MAX_TOUCHES];
} __packed;
struct icn8318_data {
struct i2c_client *client;
struct input_dev *input;
struct gpio_desc *wake_gpio;
u32 max_x;
u32 max_y;
bool invert_x;
bool invert_y;
bool swap_x_y;
};
static int icn8318_read_touch_data(struct i2c_client *client,
struct icn8318_touch_data *touch_data)
{
u8 reg = ICN8318_REG_TOUCHDATA;
struct i2c_msg msg[2] = {
{
.addr = client->addr,
.len = 1,
.buf = &reg
},
{
.addr = client->addr,
.flags = I2C_M_RD,
.len = sizeof(struct icn8318_touch_data),
.buf = (u8 *)touch_data
}
};
return i2c_transfer(client->adapter, msg, 2);
}
static inline bool icn8318_touch_active(u8 event)
{
return (event == ICN8318_EVENT_UPDATE1) ||
(event == ICN8318_EVENT_UPDATE2);
}
static irqreturn_t icn8318_irq(int irq, void *dev_id)
{
struct icn8318_data *data = dev_id;
struct device *dev = &data->client->dev;
struct icn8318_touch_data touch_data;
int i, ret, x, y;
ret = icn8318_read_touch_data(data->client, &touch_data);
if (ret < 0) {
dev_err(dev, "Error reading touch data: %d\n", ret);
return IRQ_HANDLED;
}
if (touch_data.softbutton) {
/*
* Other data is invalid when a softbutton is pressed.
* This needs some extra devicetree bindings to map the icn8318
* softbutton codes to evdev codes. Currently no known devices
* use this.
*/
return IRQ_HANDLED;
}
if (touch_data.touch_count > ICN8318_MAX_TOUCHES) {
dev_warn(dev, "Too much touches %d > %d\n",
touch_data.touch_count, ICN8318_MAX_TOUCHES);
touch_data.touch_count = ICN8318_MAX_TOUCHES;
}
for (i = 0; i < touch_data.touch_count; i++) {
struct icn8318_touch *touch = &touch_data.touches[i];
bool act = icn8318_touch_active(touch->event);
input_mt_slot(data->input, touch->slot);
input_mt_report_slot_state(data->input, MT_TOOL_FINGER, act);
if (!act)
continue;
x = be16_to_cpu(touch->x);
y = be16_to_cpu(touch->y);
if (data->invert_x)
x = data->max_x - x;
if (data->invert_y)
y = data->max_y - y;
if (!data->swap_x_y) {
input_event(data->input, EV_ABS, ABS_MT_POSITION_X, x);
input_event(data->input, EV_ABS, ABS_MT_POSITION_Y, y);
} else {
input_event(data->input, EV_ABS, ABS_MT_POSITION_X, y);
input_event(data->input, EV_ABS, ABS_MT_POSITION_Y, x);
}
}
input_mt_sync_frame(data->input);
input_sync(data->input);
return IRQ_HANDLED;
}
static int icn8318_start(struct input_dev *dev)
{
struct icn8318_data *data = input_get_drvdata(dev);
enable_irq(data->client->irq);
gpiod_set_value_cansleep(data->wake_gpio, 1);
return 0;
}
static void icn8318_stop(struct input_dev *dev)
{
struct icn8318_data *data = input_get_drvdata(dev);
disable_irq(data->client->irq);
i2c_smbus_write_byte_data(data->client, ICN8318_REG_POWER,
ICN8318_POWER_HIBERNATE);
gpiod_set_value_cansleep(data->wake_gpio, 0);
}
#ifdef CONFIG_PM_SLEEP
static int icn8318_suspend(struct device *dev)
{
struct icn8318_data *data = i2c_get_clientdata(to_i2c_client(dev));
mutex_lock(&data->input->mutex);
if (data->input->users)
icn8318_stop(data->input);
mutex_unlock(&data->input->mutex);
return 0;
}
static int icn8318_resume(struct device *dev)
{
struct icn8318_data *data = i2c_get_clientdata(to_i2c_client(dev));
mutex_lock(&data->input->mutex);
if (data->input->users)
icn8318_start(data->input);
mutex_unlock(&data->input->mutex);
return 0;
}
#endif
static SIMPLE_DEV_PM_OPS(icn8318_pm_ops, icn8318_suspend, icn8318_resume);
static int icn8318_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct device *dev = &client->dev;
struct device_node *np = dev->of_node;
struct icn8318_data *data;
struct input_dev *input;
u32 fuzz_x = 0, fuzz_y = 0;
int error;
if (!client->irq) {
dev_err(dev, "Error no irq specified\n");
return -EINVAL;
}
data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
data->wake_gpio = devm_gpiod_get(dev, "wake", GPIOD_OUT_LOW);
if (IS_ERR(data->wake_gpio)) {
error = PTR_ERR(data->wake_gpio);
if (error != -EPROBE_DEFER)
dev_err(dev, "Error getting wake gpio: %d\n", error);
return error;
}
if (of_property_read_u32(np, "touchscreen-size-x", &data->max_x) ||
of_property_read_u32(np, "touchscreen-size-y", &data->max_y)) {
dev_err(dev, "Error touchscreen-size-x and/or -y missing\n");
return -EINVAL;
}
/* Optional */
of_property_read_u32(np, "touchscreen-fuzz-x", &fuzz_x);
of_property_read_u32(np, "touchscreen-fuzz-y", &fuzz_y);
data->invert_x = of_property_read_bool(np, "touchscreen-inverted-x");
data->invert_y = of_property_read_bool(np, "touchscreen-inverted-y");
data->swap_x_y = of_property_read_bool(np, "touchscreen-swapped-x-y");
input = devm_input_allocate_device(dev);
if (!input)
return -ENOMEM;
input->name = client->name;
input->id.bustype = BUS_I2C;
input->open = icn8318_start;
input->close = icn8318_stop;
input->dev.parent = dev;
if (!data->swap_x_y) {
input_set_abs_params(input, ABS_MT_POSITION_X, 0,
data->max_x, fuzz_x, 0);
input_set_abs_params(input, ABS_MT_POSITION_Y, 0,
data->max_y, fuzz_y, 0);
} else {
input_set_abs_params(input, ABS_MT_POSITION_X, 0,
data->max_y, fuzz_y, 0);
input_set_abs_params(input, ABS_MT_POSITION_Y, 0,
data->max_x, fuzz_x, 0);
}
error = input_mt_init_slots(input, ICN8318_MAX_TOUCHES,
INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED);
if (error)
return error;
data->client = client;
data->input = input;
input_set_drvdata(input, data);
error = devm_request_threaded_irq(dev, client->irq, NULL, icn8318_irq,
IRQF_ONESHOT, client->name, data);
if (error) {
dev_err(dev, "Error requesting irq: %d\n", error);
return error;
}
/* Stop device till opened */
icn8318_stop(data->input);
error = input_register_device(input);
if (error)
return error;
i2c_set_clientdata(client, data);
return 0;
}
static const struct of_device_id icn8318_of_match[] = {
{ .compatible = "chipone,icn8318" },
{ }
};
MODULE_DEVICE_TABLE(of, icn8318_of_match);
/* This is useless for OF-enabled devices, but it is needed by I2C subsystem */
static const struct i2c_device_id icn8318_i2c_id[] = {
{ },
};
MODULE_DEVICE_TABLE(i2c, icn8318_i2c_id);
static struct i2c_driver icn8318_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "chipone_icn8318",
.pm = &icn8318_pm_ops,
.of_match_table = icn8318_of_match,
},
.probe = icn8318_probe,
.id_table = icn8318_i2c_id,
};
module_i2c_driver(icn8318_driver);
MODULE_DESCRIPTION("ChipOne icn8318 I2C Touchscreen Driver");
MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
MODULE_LICENSE("GPL");
...@@ -37,6 +37,7 @@ ...@@ -37,6 +37,7 @@
#include <linux/gpio.h> #include <linux/gpio.h>
#include <linux/of_gpio.h> #include <linux/of_gpio.h>
#include <linux/input/mt.h> #include <linux/input/mt.h>
#include <linux/input/touchscreen.h>
#include <linux/input/edt-ft5x06.h> #include <linux/input/edt-ft5x06.h>
#define MAX_SUPPORT_POINTS 5 #define MAX_SUPPORT_POINTS 5
...@@ -1034,7 +1035,6 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client, ...@@ -1034,7 +1035,6 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client,
input->id.bustype = BUS_I2C; input->id.bustype = BUS_I2C;
input->dev.parent = &client->dev; input->dev.parent = &client->dev;
__set_bit(EV_SYN, input->evbit);
__set_bit(EV_KEY, input->evbit); __set_bit(EV_KEY, input->evbit);
__set_bit(EV_ABS, input->evbit); __set_bit(EV_ABS, input->evbit);
__set_bit(BTN_TOUCH, input->keybit); __set_bit(BTN_TOUCH, input->keybit);
...@@ -1044,6 +1044,10 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client, ...@@ -1044,6 +1044,10 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client,
0, tsdata->num_x * 64 - 1, 0, 0); 0, tsdata->num_x * 64 - 1, 0, 0);
input_set_abs_params(input, ABS_MT_POSITION_Y, input_set_abs_params(input, ABS_MT_POSITION_Y,
0, tsdata->num_y * 64 - 1, 0, 0); 0, tsdata->num_y * 64 - 1, 0, 0);
if (!pdata)
touchscreen_parse_of_params(input);
error = input_mt_init_slots(input, MAX_SUPPORT_POINTS, 0); error = input_mt_init_slots(input, MAX_SUPPORT_POINTS, 0);
if (error) { if (error) {
dev_err(&client->dev, "Unable to init MT slots.\n"); dev_err(&client->dev, "Unable to init MT slots.\n");
......
...@@ -98,7 +98,6 @@ ...@@ -98,7 +98,6 @@
#define MAX_FW_UPDATE_RETRIES 30 #define MAX_FW_UPDATE_RETRIES 30
#define ELAN_FW_PAGESIZE 132 #define ELAN_FW_PAGESIZE 132
#define ELAN_FW_FILENAME "elants_i2c.bin"
/* calibration timeout definition */ /* calibration timeout definition */
#define ELAN_CALI_TIMEOUT_MSEC 10000 #define ELAN_CALI_TIMEOUT_MSEC 10000
...@@ -697,12 +696,19 @@ static int elants_i2c_fw_update(struct elants_data *ts) ...@@ -697,12 +696,19 @@ static int elants_i2c_fw_update(struct elants_data *ts)
{ {
struct i2c_client *client = ts->client; struct i2c_client *client = ts->client;
const struct firmware *fw; const struct firmware *fw;
char *fw_name;
int error; int error;
error = request_firmware(&fw, ELAN_FW_FILENAME, &client->dev); fw_name = kasprintf(GFP_KERNEL, "elants_i2c_%4x.bin", ts->hw_version);
if (!fw_name)
return -ENOMEM;
dev_info(&client->dev, "requesting fw name = %s\n", fw_name);
error = request_firmware(&fw, fw_name, &client->dev);
kfree(fw_name);
if (error) { if (error) {
dev_err(&client->dev, "failed to request firmware %s: %d\n", dev_err(&client->dev, "failed to request firmware: %d\n",
ELAN_FW_FILENAME, error); error);
return error; return error;
} }
......
...@@ -23,6 +23,8 @@ ...@@ -23,6 +23,8 @@
#include <linux/irq.h> #include <linux/irq.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/acpi.h>
#include <linux/of.h>
#include <asm/unaligned.h> #include <asm/unaligned.h>
struct goodix_ts_data { struct goodix_ts_data {
...@@ -48,6 +50,7 @@ struct goodix_ts_data { ...@@ -48,6 +50,7 @@ struct goodix_ts_data {
#define GOODIX_REG_VERSION 0x8140 #define GOODIX_REG_VERSION 0x8140
#define RESOLUTION_LOC 1 #define RESOLUTION_LOC 1
#define MAX_CONTACTS_LOC 5
#define TRIGGER_LOC 6 #define TRIGGER_LOC 6
static const unsigned long goodix_irq_flags[] = { static const unsigned long goodix_irq_flags[] = {
...@@ -99,7 +102,7 @@ static int goodix_ts_read_input_report(struct goodix_ts_data *ts, u8 *data) ...@@ -99,7 +102,7 @@ static int goodix_ts_read_input_report(struct goodix_ts_data *ts, u8 *data)
} }
touch_num = data[0] & 0x0f; touch_num = data[0] & 0x0f;
if (touch_num > GOODIX_MAX_CONTACTS) if (touch_num > ts->max_touch_num)
return -EPROTO; return -EPROTO;
if (touch_num > 1) { if (touch_num > 1) {
...@@ -141,7 +144,7 @@ static void goodix_ts_report_touch(struct goodix_ts_data *ts, u8 *coor_data) ...@@ -141,7 +144,7 @@ static void goodix_ts_report_touch(struct goodix_ts_data *ts, u8 *coor_data)
*/ */
static void goodix_process_events(struct goodix_ts_data *ts) static void goodix_process_events(struct goodix_ts_data *ts)
{ {
u8 point_data[1 + GOODIX_CONTACT_SIZE * GOODIX_MAX_CONTACTS]; u8 point_data[1 + GOODIX_CONTACT_SIZE * ts->max_touch_num];
int touch_num; int touch_num;
int i; int i;
...@@ -202,21 +205,23 @@ static void goodix_read_config(struct goodix_ts_data *ts) ...@@ -202,21 +205,23 @@ static void goodix_read_config(struct goodix_ts_data *ts)
ts->abs_x_max = GOODIX_MAX_WIDTH; ts->abs_x_max = GOODIX_MAX_WIDTH;
ts->abs_y_max = GOODIX_MAX_HEIGHT; ts->abs_y_max = GOODIX_MAX_HEIGHT;
ts->int_trigger_type = GOODIX_INT_TRIGGER; ts->int_trigger_type = GOODIX_INT_TRIGGER;
ts->max_touch_num = GOODIX_MAX_CONTACTS;
return; return;
} }
ts->abs_x_max = get_unaligned_le16(&config[RESOLUTION_LOC]); ts->abs_x_max = get_unaligned_le16(&config[RESOLUTION_LOC]);
ts->abs_y_max = get_unaligned_le16(&config[RESOLUTION_LOC + 2]); ts->abs_y_max = get_unaligned_le16(&config[RESOLUTION_LOC + 2]);
ts->int_trigger_type = (config[TRIGGER_LOC]) & 0x03; ts->int_trigger_type = config[TRIGGER_LOC] & 0x03;
if (!ts->abs_x_max || !ts->abs_y_max) { ts->max_touch_num = config[MAX_CONTACTS_LOC] & 0x0f;
if (!ts->abs_x_max || !ts->abs_y_max || !ts->max_touch_num) {
dev_err(&ts->client->dev, dev_err(&ts->client->dev,
"Invalid config, using defaults\n"); "Invalid config, using defaults\n");
ts->abs_x_max = GOODIX_MAX_WIDTH; ts->abs_x_max = GOODIX_MAX_WIDTH;
ts->abs_y_max = GOODIX_MAX_HEIGHT; ts->abs_y_max = GOODIX_MAX_HEIGHT;
ts->max_touch_num = GOODIX_MAX_CONTACTS;
} }
} }
/** /**
* goodix_read_version - Read goodix touchscreen version * goodix_read_version - Read goodix touchscreen version
* *
...@@ -295,7 +300,7 @@ static int goodix_request_input_dev(struct goodix_ts_data *ts) ...@@ -295,7 +300,7 @@ static int goodix_request_input_dev(struct goodix_ts_data *ts)
input_set_abs_params(ts->input_dev, ABS_MT_WIDTH_MAJOR, 0, 255, 0, 0); input_set_abs_params(ts->input_dev, ABS_MT_WIDTH_MAJOR, 0, 255, 0, 0);
input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0); input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0);
input_mt_init_slots(ts->input_dev, GOODIX_MAX_CONTACTS, input_mt_init_slots(ts->input_dev, ts->max_touch_num,
INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED); INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED);
ts->input_dev->name = "Goodix Capacitive TouchScreen"; ts->input_dev->name = "Goodix Capacitive TouchScreen";
...@@ -372,11 +377,27 @@ static const struct i2c_device_id goodix_ts_id[] = { ...@@ -372,11 +377,27 @@ static const struct i2c_device_id goodix_ts_id[] = {
{ } { }
}; };
#ifdef CONFIG_ACPI
static const struct acpi_device_id goodix_acpi_match[] = { static const struct acpi_device_id goodix_acpi_match[] = {
{ "GDIX1001", 0 }, { "GDIX1001", 0 },
{ } { }
}; };
MODULE_DEVICE_TABLE(acpi, goodix_acpi_match); MODULE_DEVICE_TABLE(acpi, goodix_acpi_match);
#endif
#ifdef CONFIG_OF
static const struct of_device_id goodix_of_match[] = {
{ .compatible = "goodix,gt911" },
{ .compatible = "goodix,gt9110" },
{ .compatible = "goodix,gt912" },
{ .compatible = "goodix,gt927" },
{ .compatible = "goodix,gt9271" },
{ .compatible = "goodix,gt928" },
{ .compatible = "goodix,gt967" },
{ }
};
MODULE_DEVICE_TABLE(of, goodix_of_match);
#endif
static struct i2c_driver goodix_ts_driver = { static struct i2c_driver goodix_ts_driver = {
.probe = goodix_ts_probe, .probe = goodix_ts_probe,
...@@ -384,7 +405,8 @@ static struct i2c_driver goodix_ts_driver = { ...@@ -384,7 +405,8 @@ static struct i2c_driver goodix_ts_driver = {
.driver = { .driver = {
.name = "Goodix-TS", .name = "Goodix-TS",
.owner = THIS_MODULE, .owner = THIS_MODULE,
.acpi_match_table = goodix_acpi_match, .acpi_match_table = ACPI_PTR(goodix_acpi_match),
.of_match_table = of_match_ptr(goodix_of_match),
}, },
}; };
module_i2c_driver(goodix_ts_driver); module_i2c_driver(goodix_ts_driver);
......
...@@ -11,8 +11,41 @@ ...@@ -11,8 +11,41 @@
#include <linux/of.h> #include <linux/of.h>
#include <linux/input.h> #include <linux/input.h>
#include <linux/input/mt.h>
#include <linux/input/touchscreen.h> #include <linux/input/touchscreen.h>
static u32 of_get_optional_u32(struct device_node *np,
const char *property)
{
u32 val = 0;
of_property_read_u32(np, property, &val);
return val;
}
static void touchscreen_set_params(struct input_dev *dev,
unsigned long axis,
int max, int fuzz)
{
struct input_absinfo *absinfo;
if (!test_bit(axis, dev->absbit)) {
/*
* Emit a warning only if the axis is not a multitouch
* axis, which might not be set by the driver.
*/
if (!input_is_mt_axis(axis))
dev_warn(&dev->dev,
"DT specifies parameters but the axis is not set up\n");
return;
}
absinfo = &dev->absinfo[axis];
absinfo->maximum = max;
absinfo->fuzz = fuzz;
}
/** /**
* touchscreen_parse_of_params - parse common touchscreen DT properties * touchscreen_parse_of_params - parse common touchscreen DT properties
* @dev: device that should be parsed * @dev: device that should be parsed
...@@ -24,22 +57,31 @@ ...@@ -24,22 +57,31 @@
void touchscreen_parse_of_params(struct input_dev *dev) void touchscreen_parse_of_params(struct input_dev *dev)
{ {
struct device_node *np = dev->dev.parent->of_node; struct device_node *np = dev->dev.parent->of_node;
struct input_absinfo *absinfo; u32 maximum, fuzz;
input_alloc_absinfo(dev); input_alloc_absinfo(dev);
if (!dev->absinfo) if (!dev->absinfo)
return; return;
absinfo = &dev->absinfo[ABS_X]; maximum = of_get_optional_u32(np, "touchscreen-size-x");
of_property_read_u32(np, "touchscreen-size-x", &absinfo->maximum); fuzz = of_get_optional_u32(np, "touchscreen-fuzz-x");
of_property_read_u32(np, "touchscreen-fuzz-x", &absinfo->fuzz); if (maximum || fuzz) {
touchscreen_set_params(dev, ABS_X, maximum, fuzz);
touchscreen_set_params(dev, ABS_MT_POSITION_X, maximum, fuzz);
}
absinfo = &dev->absinfo[ABS_Y]; maximum = of_get_optional_u32(np, "touchscreen-size-y");
of_property_read_u32(np, "touchscreen-size-y", &absinfo->maximum); fuzz = of_get_optional_u32(np, "touchscreen-fuzz-y");
of_property_read_u32(np, "touchscreen-fuzz-y", &absinfo->fuzz); if (maximum || fuzz) {
touchscreen_set_params(dev, ABS_Y, maximum, fuzz);
touchscreen_set_params(dev, ABS_MT_POSITION_Y, maximum, fuzz);
}
absinfo = &dev->absinfo[ABS_PRESSURE]; maximum = of_get_optional_u32(np, "touchscreen-max-pressure");
of_property_read_u32(np, "touchscreen-max-pressure", &absinfo->maximum); fuzz = of_get_optional_u32(np, "touchscreen-fuzz-pressure");
of_property_read_u32(np, "touchscreen-fuzz-pressure", &absinfo->fuzz); if (maximum || fuzz) {
touchscreen_set_params(dev, ABS_PRESSURE, maximum, fuzz);
touchscreen_set_params(dev, ABS_MT_PRESSURE, maximum, fuzz);
}
} }
EXPORT_SYMBOL(touchscreen_parse_of_params); EXPORT_SYMBOL(touchscreen_parse_of_params);
...@@ -30,6 +30,10 @@ ...@@ -30,6 +30,10 @@
* These kinds of heuristics are just asking for trouble (and don't belong * These kinds of heuristics are just asking for trouble (and don't belong
* in the kernel). So this driver offers straight forward, reliable single * in the kernel). So this driver offers straight forward, reliable single
* touch functionality only. * touch functionality only.
*
* s.a. A20 User Manual "1.15 TP" (Documentation/arm/sunxi/README)
* (looks like the description in the A20 User Manual v1.3 is better
* than the one in the A10 User Manual v.1.5)
*/ */
#include <linux/err.h> #include <linux/err.h>
...@@ -193,7 +197,7 @@ static int sun4i_get_temp(const struct sun4i_ts_data *ts, long *temp) ...@@ -193,7 +197,7 @@ static int sun4i_get_temp(const struct sun4i_ts_data *ts, long *temp)
if (ts->temp_data == -1) if (ts->temp_data == -1)
return -EAGAIN; return -EAGAIN;
*temp = (ts->temp_data - ts->temp_offset) * ts->temp_step; *temp = ts->temp_data * ts->temp_step - ts->temp_offset;
return 0; return 0;
} }
...@@ -246,6 +250,8 @@ static int sun4i_ts_probe(struct platform_device *pdev) ...@@ -246,6 +250,8 @@ static int sun4i_ts_probe(struct platform_device *pdev)
int error; int error;
u32 reg; u32 reg;
bool ts_attached; bool ts_attached;
u32 tp_sensitive_adjust = 15;
u32 filter_type = 1;
ts = devm_kzalloc(dev, sizeof(struct sun4i_ts_data), GFP_KERNEL); ts = devm_kzalloc(dev, sizeof(struct sun4i_ts_data), GFP_KERNEL);
if (!ts) if (!ts)
...@@ -255,22 +261,31 @@ static int sun4i_ts_probe(struct platform_device *pdev) ...@@ -255,22 +261,31 @@ static int sun4i_ts_probe(struct platform_device *pdev)
ts->ignore_fifo_data = true; ts->ignore_fifo_data = true;
ts->temp_data = -1; ts->temp_data = -1;
if (of_device_is_compatible(np, "allwinner,sun6i-a31-ts")) { if (of_device_is_compatible(np, "allwinner,sun6i-a31-ts")) {
/* Allwinner SDK has temperature = -271 + (value / 6) (C) */ /* Allwinner SDK has temperature (C) = (value / 6) - 271 */
ts->temp_offset = 1626; ts->temp_offset = 271000;
ts->temp_step = 167; ts->temp_step = 167;
} else if (of_device_is_compatible(np, "allwinner,sun4i-a10-ts")) {
/*
* The A10 temperature sensor has quite a wide spread, these
* parameters are based on the averaging of the calibration
* results of 4 completely different boards, with a spread of
* temp_step from 0.096 - 0.170 and temp_offset from 176 - 331.
*/
ts->temp_offset = 257000;
ts->temp_step = 133;
} else { } else {
/* /*
* The user manuals do not contain the formula for calculating * The user manuals do not contain the formula for calculating
* the temperature. The formula used here is from the AXP209, * the temperature. The formula used here is from the AXP209,
* which is designed by X-Powers, an affiliate of Allwinner: * which is designed by X-Powers, an affiliate of Allwinner:
* *
* temperature = -144.7 + (value * 0.1) * temperature (C) = (value * 0.1) - 144.7
* *
* Allwinner does not have any documentation whatsoever for * Allwinner does not have any documentation whatsoever for
* this hardware. Moreover, it is claimed that the sensor * this hardware. Moreover, it is claimed that the sensor
* is inaccurate and cannot work properly. * is inaccurate and cannot work properly.
*/ */
ts->temp_offset = 1447; ts->temp_offset = 144700;
ts->temp_step = 100; ts->temp_step = 100;
} }
...@@ -313,14 +328,20 @@ static int sun4i_ts_probe(struct platform_device *pdev) ...@@ -313,14 +328,20 @@ static int sun4i_ts_probe(struct platform_device *pdev)
ts->base + TP_CTRL0); ts->base + TP_CTRL0);
/* /*
* sensitive_adjust = 15 : max, which is not all that sensitive, * tp_sensitive_adjust is an optional property
* tp_mode = 0 : only x and y coordinates, as we don't use dual touch * tp_mode = 0 : only x and y coordinates, as we don't use dual touch
*/ */
writel(TP_SENSITIVE_ADJUST(15) | TP_MODE_SELECT(0), of_property_read_u32(np, "allwinner,tp-sensitive-adjust",
&tp_sensitive_adjust);
writel(TP_SENSITIVE_ADJUST(tp_sensitive_adjust) | TP_MODE_SELECT(0),
ts->base + TP_CTRL2); ts->base + TP_CTRL2);
/* Enable median filter, type 1 : 5/3 */ /*
writel(FILTER_EN(1) | FILTER_TYPE(1), ts->base + TP_CTRL3); * Enable median and averaging filter, optional property for
* filter type.
*/
of_property_read_u32(np, "allwinner,filter-type", &filter_type);
writel(FILTER_EN(1) | FILTER_TYPE(filter_type), ts->base + TP_CTRL3);
/* Enable temperature measurement, period 1953 (2 seconds) */ /* Enable temperature measurement, period 1953 (2 seconds) */
writel(TEMP_ENABLE(1) | TEMP_PERIOD(1953), ts->base + TP_TPR); writel(TEMP_ENABLE(1) | TEMP_PERIOD(1953), ts->base + TP_TPR);
...@@ -330,10 +351,10 @@ static int sun4i_ts_probe(struct platform_device *pdev) ...@@ -330,10 +351,10 @@ static int sun4i_ts_probe(struct platform_device *pdev)
* finally enable tp mode. * finally enable tp mode.
*/ */
reg = STYLUS_UP_DEBOUN(5) | STYLUS_UP_DEBOUN_EN(1); reg = STYLUS_UP_DEBOUN(5) | STYLUS_UP_DEBOUN_EN(1);
if (of_device_is_compatible(np, "allwinner,sun4i-a10-ts")) if (of_device_is_compatible(np, "allwinner,sun6i-a31-ts"))
reg |= TP_MODE_EN(1);
else
reg |= SUN6I_TP_MODE_EN(1); reg |= SUN6I_TP_MODE_EN(1);
else
reg |= TP_MODE_EN(1);
writel(reg, ts->base + TP_CTRL1); writel(reg, ts->base + TP_CTRL1);
/* /*
...@@ -383,6 +404,7 @@ static int sun4i_ts_remove(struct platform_device *pdev) ...@@ -383,6 +404,7 @@ static int sun4i_ts_remove(struct platform_device *pdev)
static const struct of_device_id sun4i_ts_of_match[] = { static const struct of_device_id sun4i_ts_of_match[] = {
{ .compatible = "allwinner,sun4i-a10-ts", }, { .compatible = "allwinner,sun4i-a10-ts", },
{ .compatible = "allwinner,sun5i-a13-ts", },
{ .compatible = "allwinner,sun6i-a31-ts", }, { .compatible = "allwinner,sun6i-a31-ts", },
{ /* sentinel */ } { /* sentinel */ }
}; };
......
/*
* Driver for Semtech SX8654 I2C touchscreen controller.
*
* Copyright (c) 2015 Armadeus Systems
* Sébastien Szymanski <sebastien.szymanski@armadeus.com>
*
* Using code from:
* - sx865x.c
* Copyright (c) 2013 U-MoBo Srl
* Pierluigi Passaro <p.passaro@u-mobo.com>
* - sx8650.c
* Copyright (c) 2009 Wayne Roberts
* - tsc2007.c
* Copyright (c) 2008 Kwangwoo Lee
* - ads7846.c
* Copyright (c) 2005 David Brownell
* Copyright (c) 2006 Nokia Corporation
* - corgi_ts.c
* Copyright (C) 2004-2005 Richard Purdie
* - omap_ts.[hc], ads7846.h, ts_osk.c
* Copyright (C) 2002 MontaVista Software
* Copyright (C) 2004 Texas Instruments
* Copyright (C) 2005 Dirk Behme
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/input.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
/* register addresses */
#define I2C_REG_TOUCH0 0x00
#define I2C_REG_TOUCH1 0x01
#define I2C_REG_CHANMASK 0x04
#define I2C_REG_IRQMASK 0x22
#define I2C_REG_IRQSRC 0x23
#define I2C_REG_SOFTRESET 0x3f
/* commands */
#define CMD_READ_REGISTER 0x40
#define CMD_MANUAL 0xc0
#define CMD_PENTRG 0xe0
/* value for I2C_REG_SOFTRESET */
#define SOFTRESET_VALUE 0xde
/* bits for I2C_REG_IRQSRC */
#define IRQ_PENTOUCH_TOUCHCONVDONE 0x08
#define IRQ_PENRELEASE 0x04
/* bits for RegTouch1 */
#define CONDIRQ 0x20
#define FILT_7SA 0x03
/* bits for I2C_REG_CHANMASK */
#define CONV_X 0x80
#define CONV_Y 0x40
/* coordinates rate: higher nibble of CTRL0 register */
#define RATE_MANUAL 0x00
#define RATE_5000CPS 0xf0
/* power delay: lower nibble of CTRL0 register */
#define POWDLY_1_1MS 0x0b
#define MAX_12BIT ((1 << 12) - 1)
struct sx8654 {
struct input_dev *input;
struct i2c_client *client;
};
static irqreturn_t sx8654_irq(int irq, void *handle)
{
struct sx8654 *sx8654 = handle;
int irqsrc;
u8 data[4];
unsigned int x, y;
int retval;
irqsrc = i2c_smbus_read_byte_data(sx8654->client,
CMD_READ_REGISTER | I2C_REG_IRQSRC);
dev_dbg(&sx8654->client->dev, "irqsrc = 0x%x", irqsrc);
if (irqsrc < 0)
goto out;
if (irqsrc & IRQ_PENRELEASE) {
dev_dbg(&sx8654->client->dev, "pen release interrupt");
input_report_key(sx8654->input, BTN_TOUCH, 0);
input_sync(sx8654->input);
}
if (irqsrc & IRQ_PENTOUCH_TOUCHCONVDONE) {
dev_dbg(&sx8654->client->dev, "pen touch interrupt");
retval = i2c_master_recv(sx8654->client, data, sizeof(data));
if (retval != sizeof(data))
goto out;
/* invalid data */
if (unlikely(data[0] & 0x80 || data[2] & 0x80))
goto out;
x = ((data[0] & 0xf) << 8) | (data[1]);
y = ((data[2] & 0xf) << 8) | (data[3]);
input_report_abs(sx8654->input, ABS_X, x);
input_report_abs(sx8654->input, ABS_Y, y);
input_report_key(sx8654->input, BTN_TOUCH, 1);
input_sync(sx8654->input);
dev_dbg(&sx8654->client->dev, "point(%4d,%4d)\n", x, y);
}
out:
return IRQ_HANDLED;
}
static int sx8654_open(struct input_dev *dev)
{
struct sx8654 *sx8654 = input_get_drvdata(dev);
struct i2c_client *client = sx8654->client;
int error;
/* enable pen trigger mode */
error = i2c_smbus_write_byte_data(client, I2C_REG_TOUCH0,
RATE_5000CPS | POWDLY_1_1MS);
if (error) {
dev_err(&client->dev, "writing to I2C_REG_TOUCH0 failed");
return error;
}
error = i2c_smbus_write_byte(client, CMD_PENTRG);
if (error) {
dev_err(&client->dev, "writing command CMD_PENTRG failed");
return error;
}
enable_irq(client->irq);
return 0;
}
static void sx8654_close(struct input_dev *dev)
{
struct sx8654 *sx8654 = input_get_drvdata(dev);
struct i2c_client *client = sx8654->client;
int error;
disable_irq(client->irq);
/* enable manual mode mode */
error = i2c_smbus_write_byte(client, CMD_MANUAL);
if (error) {
dev_err(&client->dev, "writing command CMD_MANUAL failed");
return;
}
error = i2c_smbus_write_byte_data(client, I2C_REG_TOUCH0, 0);
if (error) {
dev_err(&client->dev, "writing to I2C_REG_TOUCH0 failed");
return;
}
}
static int sx8654_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct sx8654 *sx8654;
struct input_dev *input;
int error;
if (!i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_READ_WORD_DATA))
return -ENXIO;
sx8654 = devm_kzalloc(&client->dev, sizeof(*sx8654), GFP_KERNEL);
if (!sx8654)
return -ENOMEM;
input = devm_input_allocate_device(&client->dev);
if (!sx8654)
return -ENOMEM;
input->name = "SX8654 I2C Touchscreen";
input->id.bustype = BUS_I2C;
input->dev.parent = &client->dev;
input->open = sx8654_open;
input->close = sx8654_close;
__set_bit(INPUT_PROP_DIRECT, input->propbit);
input_set_capability(input, EV_KEY, BTN_TOUCH);
input_set_abs_params(input, ABS_X, 0, MAX_12BIT, 0, 0);
input_set_abs_params(input, ABS_Y, 0, MAX_12BIT, 0, 0);
sx8654->client = client;
sx8654->input = input;
input_set_drvdata(sx8654->input, sx8654);
error = i2c_smbus_write_byte_data(client, I2C_REG_SOFTRESET,
SOFTRESET_VALUE);
if (error) {
dev_err(&client->dev, "writing softreset value failed");
return error;
}
error = i2c_smbus_write_byte_data(client, I2C_REG_CHANMASK,
CONV_X | CONV_Y);
if (error) {
dev_err(&client->dev, "writing to I2C_REG_CHANMASK failed");
return error;
}
error = i2c_smbus_write_byte_data(client, I2C_REG_IRQMASK,
IRQ_PENTOUCH_TOUCHCONVDONE |
IRQ_PENRELEASE);
if (error) {
dev_err(&client->dev, "writing to I2C_REG_IRQMASK failed");
return error;
}
error = i2c_smbus_write_byte_data(client, I2C_REG_TOUCH1,
CONDIRQ | FILT_7SA);
if (error) {
dev_err(&client->dev, "writing to I2C_REG_TOUCH1 failed");
return error;
}
error = devm_request_threaded_irq(&client->dev, client->irq,
NULL, sx8654_irq,
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
client->name, sx8654);
if (error) {
dev_err(&client->dev,
"Failed to enable IRQ %d, error: %d\n",
client->irq, error);
return error;
}
/* Disable the IRQ, we'll enable it in sx8654_open() */
disable_irq(client->irq);
error = input_register_device(sx8654->input);
if (error)
return error;
i2c_set_clientdata(client, sx8654);
return 0;
}
#ifdef CONFIG_OF
static const struct of_device_id sx8654_of_match[] = {
{ .compatible = "semtech,sx8654", },
{ },
};
MODULE_DEVICE_TABLE(of, sx8654_of_match);
#endif
static const struct i2c_device_id sx8654_id_table[] = {
{ "semtech_sx8654", 0 },
{ },
};
MODULE_DEVICE_TABLE(i2c, sx8654_id_table);
static struct i2c_driver sx8654_driver = {
.driver = {
.name = "sx8654",
.of_match_table = of_match_ptr(sx8654_of_match),
},
.id_table = sx8654_id_table,
.probe = sx8654_probe,
};
module_i2c_driver(sx8654_driver);
MODULE_AUTHOR("Sébastien Szymanski <sebastien.szymanski@armadeus.com>");
MODULE_DESCRIPTION("Semtech SX8654 I2C Touchscreen Driver");
MODULE_LICENSE("GPL");
This diff is collapsed.
This diff is collapsed.
...@@ -59,7 +59,7 @@ static unsigned short keymap_Lifebook_Tseries[KEYMAP_LEN] __initdata = { ...@@ -59,7 +59,7 @@ static unsigned short keymap_Lifebook_Tseries[KEYMAP_LEN] __initdata = {
KEY_RESERVED, KEY_RESERVED,
KEY_SCROLLDOWN, KEY_SCROLLDOWN,
KEY_SCROLLUP, KEY_SCROLLUP,
KEY_DIRECTION, KEY_ROTATE_DISPLAY,
KEY_LEFTCTRL, KEY_LEFTCTRL,
KEY_BRIGHTNESSUP, KEY_BRIGHTNESSUP,
KEY_BRIGHTNESSDOWN, KEY_BRIGHTNESSDOWN,
...@@ -116,7 +116,7 @@ static unsigned short keymap_Lifebook_U810[KEYMAP_LEN] __initdata = { ...@@ -116,7 +116,7 @@ static unsigned short keymap_Lifebook_U810[KEYMAP_LEN] __initdata = {
KEY_RESERVED, KEY_RESERVED,
KEY_PROG1, KEY_PROG1,
KEY_PROG2, KEY_PROG2,
KEY_DIRECTION, KEY_ROTATE_DISPLAY,
KEY_RESERVED, KEY_RESERVED,
KEY_RESERVED, KEY_RESERVED,
KEY_RESERVED, KEY_RESERVED,
...@@ -153,7 +153,7 @@ static unsigned short keymap_Stylistic_ST5xxx[KEYMAP_LEN] __initdata = { ...@@ -153,7 +153,7 @@ static unsigned short keymap_Stylistic_ST5xxx[KEYMAP_LEN] __initdata = {
KEY_RESERVED, KEY_RESERVED,
KEY_RESERVED, KEY_RESERVED,
KEY_MAIL, KEY_MAIL,
KEY_DIRECTION, KEY_ROTATE_DISPLAY,
KEY_ESC, KEY_ESC,
KEY_ENTER, KEY_ENTER,
KEY_BRIGHTNESSUP, KEY_BRIGHTNESSUP,
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment