mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-24 12:44:11 +08:00
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
Pull input updates from Dmitry Torokhov: "A big update to the Atmel touchscreen driver, devm support for polled input devices, several drivers have been converted to using managed resources, and assorted driver fixes" * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input: (87 commits) Input: synaptics - fix resolution for manually provided min/max Input: atmel_mxt_ts - fix invalid return from mxt_get_bootloader_version Input: max8997_haptic - add error handling for regulator and pwm Input: elantech - don't set bit 1 of reg_10 when the no_hw_res quirk is set Input: elantech - deal with clickpads reporting right button events Input: edt-ft5x06 - fix an i2c write for M09 support Input: omap-keypad - remove platform data support ARM: OMAP2+: remove unused omap4-keypad file and code Input: ab8500-ponkey - switch to using managed resources Input: max8925_onkey - switch to using managed resources Input: 88pm860x-ts - switch to using managed resources Input: 88pm860x_onkey - switch to using managed resources Input: intel-mid-touch - switch to using managed resources Input: wacom - process outbound for newer Cintiqs Input: wacom - set stylus_in_proximity when pen is in range DTS: ARM: OMAP3-N900: Add tsc2005 support Input: tsc2005 - add DT support Input: add common DT binding for touchscreens Input: jornada680_kbd - switch top using managed resources Input: adp5520-keys - switch to using managed resources ...
This commit is contained in:
commit
f4f9b8fc73
60
Documentation/devicetree/bindings/input/st-keyscan.txt
Normal file
60
Documentation/devicetree/bindings/input/st-keyscan.txt
Normal file
@ -0,0 +1,60 @@
|
||||
* ST Keyscan controller Device Tree bindings
|
||||
|
||||
The ST keyscan controller Device Tree binding is based on the
|
||||
matrix-keymap.
|
||||
|
||||
Required properties:
|
||||
- compatible: "st,sti-keyscan"
|
||||
|
||||
- reg: Register base address and size of st-keyscan controller.
|
||||
|
||||
- interrupts: Interrupt number for the st-keyscan controller.
|
||||
|
||||
- clocks: Must contain one entry, for the module clock.
|
||||
See ../clocks/clock-bindings.txt for details.
|
||||
|
||||
- pinctrl: Should specify pin control groups used for this controller.
|
||||
See ../pinctrl/pinctrl-bindings.txt for details.
|
||||
|
||||
- linux,keymap: The keymap for keys as described in the binding document
|
||||
devicetree/bindings/input/matrix-keymap.txt.
|
||||
|
||||
- keypad,num-rows: Number of row lines connected to the keypad controller.
|
||||
|
||||
- keypad,num-columns: Number of column lines connected to the keypad
|
||||
controller.
|
||||
|
||||
Optional property:
|
||||
- st,debounce_us: Debouncing interval time in microseconds
|
||||
|
||||
Example:
|
||||
|
||||
keyscan: keyscan@fe4b0000 {
|
||||
compatible = "st,sti-keyscan";
|
||||
reg = <0xfe4b0000 0x2000>;
|
||||
interrupts = <GIC_SPI 212 IRQ_TYPE_NONE>;
|
||||
clocks = <&CLK_SYSIN>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pinctrl_keyscan>;
|
||||
|
||||
keypad,num-rows = <4>;
|
||||
keypad,num-columns = <4>;
|
||||
st,debounce_us = <5000>;
|
||||
|
||||
linux,keymap = < MATRIX_KEY(0x00, 0x00, KEY_F13)
|
||||
MATRIX_KEY(0x00, 0x01, KEY_F9)
|
||||
MATRIX_KEY(0x00, 0x02, KEY_F5)
|
||||
MATRIX_KEY(0x00, 0x03, KEY_F1)
|
||||
MATRIX_KEY(0x01, 0x00, KEY_F14)
|
||||
MATRIX_KEY(0x01, 0x01, KEY_F10)
|
||||
MATRIX_KEY(0x01, 0x02, KEY_F6)
|
||||
MATRIX_KEY(0x01, 0x03, KEY_F2)
|
||||
MATRIX_KEY(0x02, 0x00, KEY_F15)
|
||||
MATRIX_KEY(0x02, 0x01, KEY_F11)
|
||||
MATRIX_KEY(0x02, 0x02, KEY_F7)
|
||||
MATRIX_KEY(0x02, 0x03, KEY_F3)
|
||||
MATRIX_KEY(0x03, 0x00, KEY_F16)
|
||||
MATRIX_KEY(0x03, 0x01, KEY_F12)
|
||||
MATRIX_KEY(0x03, 0x02, KEY_F8)
|
||||
MATRIX_KEY(0x03, 0x03, KEY_F4) >;
|
||||
};
|
@ -0,0 +1,20 @@
|
||||
sun4i resistive touchscreen controller
|
||||
--------------------------------------
|
||||
|
||||
Required properties:
|
||||
- compatible: "allwinner,sun4i-a10-ts"
|
||||
- reg: mmio address range of the chip
|
||||
- interrupts: interrupt to which the chip is connected
|
||||
|
||||
Optional properties:
|
||||
- allwinner,ts-attached: boolean indicating that an actual touchscreen is
|
||||
attached to the controller
|
||||
|
||||
Example:
|
||||
|
||||
rtp: rtp@01c25000 {
|
||||
compatible = "allwinner,sun4i-a10-ts";
|
||||
reg = <0x01c25000 0x100>;
|
||||
interrupts = <29>;
|
||||
allwinner,ts-attached;
|
||||
};
|
@ -0,0 +1,27 @@
|
||||
General Touchscreen Properties:
|
||||
|
||||
Optional properties for Touchscreens:
|
||||
- touchscreen-size-x : horizontal resolution of touchscreen
|
||||
(in pixels)
|
||||
- touchscreen-size-y : vertical resolution of touchscreen
|
||||
(in pixels)
|
||||
- touchscreen-max-pressure : maximum reported pressure (arbitrary range
|
||||
dependent on the controller)
|
||||
- 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-fuzz-pressure : pressure noise value of the absolute input
|
||||
device (arbitrary range dependent on the
|
||||
controller)
|
||||
- touchscreen-inverted-x : X axis is inverted (boolean)
|
||||
- touchscreen-inverted-y : Y axis is inverted (boolean)
|
||||
|
||||
Deprecated properties for Touchscreens:
|
||||
- x-size : deprecated name for touchscreen-size-x
|
||||
- y-size : deprecated name for touchscreen-size-y
|
||||
- moving-threshold : deprecated name for a combination of
|
||||
touchscreen-fuzz-x and touchscreen-fuzz-y
|
||||
- contact-threshold : deprecated name for touchscreen-fuzz-pressure
|
||||
- x-invert : deprecated name for touchscreen-inverted-x
|
||||
- y-invert : deprecated name for touchscreen-inverted-y
|
@ -0,0 +1,42 @@
|
||||
* Texas Instruments tsc2005 touchscreen controller
|
||||
|
||||
Required properties:
|
||||
- compatible : "ti,tsc2005"
|
||||
- reg : SPI device address
|
||||
- spi-max-frequency : Maximal SPI speed
|
||||
- interrupts : IRQ specifier
|
||||
- reset-gpios : GPIO specifier
|
||||
- vio-supply : Regulator specifier
|
||||
|
||||
Optional properties:
|
||||
- ti,x-plate-ohms : integer, resistance of the touchscreen's X plates
|
||||
in ohm (defaults to 280)
|
||||
- ti,esd-recovery-timeout-ms : integer, if the touchscreen does not respond after
|
||||
the configured time (in milli seconds), the driver
|
||||
will reset it. This is disabled by default.
|
||||
- properties defined in touchscreen.txt
|
||||
|
||||
Example:
|
||||
|
||||
&mcspi1 {
|
||||
tsc2005@0 {
|
||||
compatible = "ti,tsc2005";
|
||||
spi-max-frequency = <6000000>;
|
||||
reg = <0>;
|
||||
|
||||
vio-supply = <&vio>;
|
||||
|
||||
reset-gpios = <&gpio4 8 GPIO_ACTIVE_HIGH>; /* 104 */
|
||||
interrupts-extended = <&gpio4 4 IRQ_TYPE_EDGE_RISING>; /* 100 */
|
||||
|
||||
touchscreen-fuzz-x = <4>;
|
||||
touchscreen-fuzz-y = <7>;
|
||||
touchscreen-fuzz-pressure = <2>;
|
||||
touchscreen-max-x = <4096>;
|
||||
touchscreen-max-y = <4096>;
|
||||
touchscreen-max-pressure = <2048>;
|
||||
|
||||
ti,x-plate-ohms = <280>;
|
||||
ti,esd-recovery-timeout-ms = <8000>;
|
||||
};
|
||||
}
|
@ -651,9 +651,24 @@
|
||||
* Also... order in the device tree actually matters here.
|
||||
*/
|
||||
tsc2005@0 {
|
||||
compatible = "tsc2005";
|
||||
compatible = "ti,tsc2005";
|
||||
spi-max-frequency = <6000000>;
|
||||
reg = <0>;
|
||||
|
||||
vio-supply = <&vio>;
|
||||
|
||||
reset-gpios = <&gpio4 8 GPIO_ACTIVE_HIGH>; /* 104 */
|
||||
interrupts-extended = <&gpio4 4 IRQ_TYPE_EDGE_RISING>; /* 100 */
|
||||
|
||||
touchscreen-fuzz-x = <4>;
|
||||
touchscreen-fuzz-y = <7>;
|
||||
touchscreen-fuzz-pressure = <2>;
|
||||
touchscreen-max-x = <4096>;
|
||||
touchscreen-max-y = <4096>;
|
||||
touchscreen-max-pressure = <2048>;
|
||||
|
||||
ti,x-plate-ohms = <280>;
|
||||
ti,esd-recovery-timeout-ms = <8000>;
|
||||
};
|
||||
|
||||
acx565akm@2 {
|
||||
|
@ -18,7 +18,6 @@
|
||||
#include <linux/slab.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/pinctrl/machine.h>
|
||||
#include <linux/platform_data/omap4-keypad.h>
|
||||
#include <linux/platform_data/mailbox-omap.h>
|
||||
|
||||
#include <asm/mach-types.h>
|
||||
@ -29,7 +28,6 @@
|
||||
#include "iomap.h"
|
||||
#include "omap_hwmod.h"
|
||||
#include "omap_device.h"
|
||||
#include "omap4-keypad.h"
|
||||
|
||||
#include "soc.h"
|
||||
#include "common.h"
|
||||
@ -255,37 +253,6 @@ static inline void omap_init_camera(void)
|
||||
#endif
|
||||
}
|
||||
|
||||
int __init omap4_keyboard_init(struct omap4_keypad_platform_data
|
||||
*sdp4430_keypad_data, struct omap_board_data *bdata)
|
||||
{
|
||||
struct platform_device *pdev;
|
||||
struct omap_hwmod *oh;
|
||||
struct omap4_keypad_platform_data *keypad_data;
|
||||
unsigned int id = -1;
|
||||
char *oh_name = "kbd";
|
||||
char *name = "omap4-keypad";
|
||||
|
||||
oh = omap_hwmod_lookup(oh_name);
|
||||
if (!oh) {
|
||||
pr_err("Could not look up %s\n", oh_name);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
keypad_data = sdp4430_keypad_data;
|
||||
|
||||
pdev = omap_device_build(name, id, oh, keypad_data,
|
||||
sizeof(struct omap4_keypad_platform_data));
|
||||
|
||||
if (IS_ERR(pdev)) {
|
||||
WARN(1, "Can't build omap_device for %s:%s.\n",
|
||||
name, oh->name);
|
||||
return PTR_ERR(pdev);
|
||||
}
|
||||
oh->mux = omap_hwmod_mux_init(bdata->pads, bdata->pads_cnt);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_OMAP2PLUS_MBOX) || defined(CONFIG_OMAP2PLUS_MBOX_MODULE)
|
||||
static inline void __init omap_init_mbox(void)
|
||||
{
|
||||
|
@ -1,8 +0,0 @@
|
||||
#ifndef ARCH_ARM_PLAT_OMAP4_KEYPAD_H
|
||||
#define ARCH_ARM_PLAT_OMAP4_KEYPAD_H
|
||||
|
||||
struct omap_board_data;
|
||||
|
||||
extern int omap4_keyboard_init(struct omap4_keypad_platform_data *,
|
||||
struct omap_board_data *);
|
||||
#endif
|
@ -234,14 +234,6 @@ static void __init goni_radio_init(void)
|
||||
|
||||
/* TSP */
|
||||
static struct mxt_platform_data qt602240_platform_data = {
|
||||
.x_line = 17,
|
||||
.y_line = 11,
|
||||
.x_size = 800,
|
||||
.y_size = 480,
|
||||
.blen = 0x21,
|
||||
.threshold = 0x28,
|
||||
.voltage = 2800000, /* 2.8V */
|
||||
.orient = MXT_DIAGONAL,
|
||||
.irqflags = IRQF_TRIGGER_FALLING,
|
||||
};
|
||||
|
||||
|
@ -629,12 +629,10 @@ static int str_to_user(const char *str, unsigned int maxlen, void __user *p)
|
||||
return copy_to_user(p, str, len) ? -EFAULT : len;
|
||||
}
|
||||
|
||||
#define OLD_KEY_MAX 0x1ff
|
||||
static int handle_eviocgbit(struct input_dev *dev,
|
||||
unsigned int type, unsigned int size,
|
||||
void __user *p, int compat_mode)
|
||||
{
|
||||
static unsigned long keymax_warn_time;
|
||||
unsigned long *bits;
|
||||
int len;
|
||||
|
||||
@ -652,24 +650,8 @@ static int handle_eviocgbit(struct input_dev *dev,
|
||||
default: return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Work around bugs in userspace programs that like to do
|
||||
* EVIOCGBIT(EV_KEY, KEY_MAX) and not realize that 'len'
|
||||
* should be in bytes, not in bits.
|
||||
*/
|
||||
if (type == EV_KEY && size == OLD_KEY_MAX) {
|
||||
len = OLD_KEY_MAX;
|
||||
if (printk_timed_ratelimit(&keymax_warn_time, 10 * 1000))
|
||||
pr_warning("(EVIOCGBIT): Suspicious buffer size %u, "
|
||||
"limiting output to %zu bytes. See "
|
||||
"http://userweb.kernel.org/~dtor/eviocgbit-bug.html\n",
|
||||
OLD_KEY_MAX,
|
||||
BITS_TO_LONGS(OLD_KEY_MAX) * sizeof(long));
|
||||
}
|
||||
|
||||
return bits_to_user(bits, len, size, p, compat_mode);
|
||||
}
|
||||
#undef OLD_KEY_MAX
|
||||
|
||||
static int evdev_handle_get_keycode(struct input_dev *dev, void __user *p)
|
||||
{
|
||||
|
@ -147,6 +147,11 @@ static struct attribute_group input_polldev_attribute_group = {
|
||||
.attrs = sysfs_attrs
|
||||
};
|
||||
|
||||
static const struct attribute_group *input_polldev_attribute_groups[] = {
|
||||
&input_polldev_attribute_group,
|
||||
NULL
|
||||
};
|
||||
|
||||
/**
|
||||
* input_allocate_polled_device - allocate memory for polled device
|
||||
*
|
||||
@ -171,6 +176,91 @@ struct input_polled_dev *input_allocate_polled_device(void)
|
||||
}
|
||||
EXPORT_SYMBOL(input_allocate_polled_device);
|
||||
|
||||
struct input_polled_devres {
|
||||
struct input_polled_dev *polldev;
|
||||
};
|
||||
|
||||
static int devm_input_polldev_match(struct device *dev, void *res, void *data)
|
||||
{
|
||||
struct input_polled_devres *devres = res;
|
||||
|
||||
return devres->polldev == data;
|
||||
}
|
||||
|
||||
static void devm_input_polldev_release(struct device *dev, void *res)
|
||||
{
|
||||
struct input_polled_devres *devres = res;
|
||||
struct input_polled_dev *polldev = devres->polldev;
|
||||
|
||||
dev_dbg(dev, "%s: dropping reference/freeing %s\n",
|
||||
__func__, dev_name(&polldev->input->dev));
|
||||
|
||||
input_put_device(polldev->input);
|
||||
kfree(polldev);
|
||||
}
|
||||
|
||||
static void devm_input_polldev_unregister(struct device *dev, void *res)
|
||||
{
|
||||
struct input_polled_devres *devres = res;
|
||||
struct input_polled_dev *polldev = devres->polldev;
|
||||
|
||||
dev_dbg(dev, "%s: unregistering device %s\n",
|
||||
__func__, dev_name(&polldev->input->dev));
|
||||
input_unregister_device(polldev->input);
|
||||
|
||||
/*
|
||||
* Note that we are still holding extra reference to the input
|
||||
* device so it will stick around until devm_input_polldev_release()
|
||||
* is called.
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
* devm_input_allocate_polled_device - allocate managed polled device
|
||||
* @dev: device owning the polled device being created
|
||||
*
|
||||
* Returns prepared &struct input_polled_dev or %NULL.
|
||||
*
|
||||
* Managed polled input devices do not need to be explicitly unregistered
|
||||
* or freed as it will be done automatically when owner device unbinds
|
||||
* from * its driver (or binding fails). Once such managed polled device
|
||||
* is allocated, it is ready to be set up and registered in the same
|
||||
* fashion as regular polled input devices (using
|
||||
* input_register_polled_device() function).
|
||||
*
|
||||
* If you want to manually unregister and free such managed polled devices,
|
||||
* it can be still done by calling input_unregister_polled_device() and
|
||||
* input_free_polled_device(), although it is rarely needed.
|
||||
*
|
||||
* NOTE: the owner device is set up as parent of input device and users
|
||||
* should not override it.
|
||||
*/
|
||||
struct input_polled_dev *devm_input_allocate_polled_device(struct device *dev)
|
||||
{
|
||||
struct input_polled_dev *polldev;
|
||||
struct input_polled_devres *devres;
|
||||
|
||||
devres = devres_alloc(devm_input_polldev_release, sizeof(*devres),
|
||||
GFP_KERNEL);
|
||||
if (!devres)
|
||||
return NULL;
|
||||
|
||||
polldev = input_allocate_polled_device();
|
||||
if (!polldev) {
|
||||
devres_free(devres);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
polldev->input->dev.parent = dev;
|
||||
polldev->devres_managed = true;
|
||||
|
||||
devres->polldev = polldev;
|
||||
devres_add(dev, devres);
|
||||
|
||||
return polldev;
|
||||
}
|
||||
EXPORT_SYMBOL(devm_input_allocate_polled_device);
|
||||
|
||||
/**
|
||||
* input_free_polled_device - free memory allocated for polled device
|
||||
* @dev: device to free
|
||||
@ -181,7 +271,12 @@ EXPORT_SYMBOL(input_allocate_polled_device);
|
||||
void input_free_polled_device(struct input_polled_dev *dev)
|
||||
{
|
||||
if (dev) {
|
||||
input_free_device(dev->input);
|
||||
if (dev->devres_managed)
|
||||
WARN_ON(devres_destroy(dev->input->dev.parent,
|
||||
devm_input_polldev_release,
|
||||
devm_input_polldev_match,
|
||||
dev));
|
||||
input_put_device(dev->input);
|
||||
kfree(dev);
|
||||
}
|
||||
}
|
||||
@ -199,26 +294,35 @@ EXPORT_SYMBOL(input_free_polled_device);
|
||||
*/
|
||||
int input_register_polled_device(struct input_polled_dev *dev)
|
||||
{
|
||||
struct input_polled_devres *devres = NULL;
|
||||
struct input_dev *input = dev->input;
|
||||
int error;
|
||||
|
||||
if (dev->devres_managed) {
|
||||
devres = devres_alloc(devm_input_polldev_unregister,
|
||||
sizeof(*devres), GFP_KERNEL);
|
||||
if (!devres)
|
||||
return -ENOMEM;
|
||||
|
||||
devres->polldev = dev;
|
||||
}
|
||||
|
||||
input_set_drvdata(input, dev);
|
||||
INIT_DELAYED_WORK(&dev->work, input_polled_device_work);
|
||||
|
||||
if (!dev->poll_interval)
|
||||
dev->poll_interval = 500;
|
||||
if (!dev->poll_interval_max)
|
||||
dev->poll_interval_max = dev->poll_interval;
|
||||
|
||||
input->open = input_open_polled_device;
|
||||
input->close = input_close_polled_device;
|
||||
|
||||
error = input_register_device(input);
|
||||
if (error)
|
||||
return error;
|
||||
input->dev.groups = input_polldev_attribute_groups;
|
||||
|
||||
error = sysfs_create_group(&input->dev.kobj,
|
||||
&input_polldev_attribute_group);
|
||||
error = input_register_device(input);
|
||||
if (error) {
|
||||
input_unregister_device(input);
|
||||
devres_free(devres);
|
||||
return error;
|
||||
}
|
||||
|
||||
@ -231,6 +335,12 @@ int input_register_polled_device(struct input_polled_dev *dev)
|
||||
*/
|
||||
input_get_device(input);
|
||||
|
||||
if (dev->devres_managed) {
|
||||
dev_dbg(input->dev.parent, "%s: registering %s with devres.\n",
|
||||
__func__, dev_name(&input->dev));
|
||||
devres_add(input->dev.parent, devres);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(input_register_polled_device);
|
||||
@ -245,8 +355,11 @@ EXPORT_SYMBOL(input_register_polled_device);
|
||||
*/
|
||||
void input_unregister_polled_device(struct input_polled_dev *dev)
|
||||
{
|
||||
sysfs_remove_group(&dev->input->dev.kobj,
|
||||
&input_polldev_attribute_group);
|
||||
if (dev->devres_managed)
|
||||
WARN_ON(devres_destroy(dev->input->dev.parent,
|
||||
devm_input_polldev_unregister,
|
||||
devm_input_polldev_match,
|
||||
dev));
|
||||
|
||||
input_unregister_device(dev->input);
|
||||
}
|
||||
|
@ -524,6 +524,17 @@ config KEYBOARD_STOWAWAY
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called stowaway.
|
||||
|
||||
config KEYBOARD_ST_KEYSCAN
|
||||
tristate "STMicroelectronics keyscan support"
|
||||
depends on ARCH_STI || COMPILE_TEST
|
||||
select INPUT_MATRIXKMAP
|
||||
help
|
||||
Say Y here if you want to use a keypad attached to the keyscan block
|
||||
on some STMicroelectronics SoC devices.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called st-keyscan.
|
||||
|
||||
config KEYBOARD_SUNKBD
|
||||
tristate "Sun Type 4 and Type 5 keyboard"
|
||||
select SERIO
|
||||
@ -578,7 +589,7 @@ config KEYBOARD_OMAP
|
||||
|
||||
config KEYBOARD_OMAP4
|
||||
tristate "TI OMAP4+ keypad support"
|
||||
depends on ARCH_OMAP2PLUS
|
||||
depends on OF || ARCH_OMAP2PLUS
|
||||
select INPUT_MATRIXKMAP
|
||||
help
|
||||
Say Y here if you want to use the OMAP4+ keypad.
|
||||
|
@ -51,6 +51,7 @@ obj-$(CONFIG_KEYBOARD_SH_KEYSC) += sh_keysc.o
|
||||
obj-$(CONFIG_KEYBOARD_SPEAR) += spear-keyboard.o
|
||||
obj-$(CONFIG_KEYBOARD_STMPE) += stmpe-keypad.o
|
||||
obj-$(CONFIG_KEYBOARD_STOWAWAY) += stowaway.o
|
||||
obj-$(CONFIG_KEYBOARD_ST_KEYSCAN) += st-keyscan.o
|
||||
obj-$(CONFIG_KEYBOARD_SUNKBD) += sunkbd.o
|
||||
obj-$(CONFIG_KEYBOARD_TC3589X) += tc3589x-keypad.o
|
||||
obj-$(CONFIG_KEYBOARD_TEGRA) += tegra-kbc.o
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include <linux/input.h>
|
||||
#include <linux/mfd/adp5520.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/device.h>
|
||||
|
||||
struct adp5520_keys {
|
||||
struct input_dev *input;
|
||||
@ -81,7 +82,7 @@ static int adp5520_keys_probe(struct platform_device *pdev)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (pdata == NULL) {
|
||||
if (!pdata) {
|
||||
dev_err(&pdev->dev, "missing platform data\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -89,17 +90,15 @@ static int adp5520_keys_probe(struct platform_device *pdev)
|
||||
if (!(pdata->rows_en_mask && pdata->cols_en_mask))
|
||||
return -EINVAL;
|
||||
|
||||
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
|
||||
if (dev == NULL) {
|
||||
dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
|
||||
if (!dev) {
|
||||
dev_err(&pdev->dev, "failed to alloc memory\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
input = input_allocate_device();
|
||||
if (!input) {
|
||||
ret = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
input = devm_input_allocate_device(&pdev->dev);
|
||||
if (!input)
|
||||
return -ENOMEM;
|
||||
|
||||
dev->master = pdev->dev.parent;
|
||||
dev->input = input;
|
||||
@ -135,7 +134,7 @@ static int adp5520_keys_probe(struct platform_device *pdev)
|
||||
ret = input_register_device(input);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "unable to register input device\n");
|
||||
goto err;
|
||||
return ret;
|
||||
}
|
||||
|
||||
en_mask = pdata->rows_en_mask | pdata->cols_en_mask;
|
||||
@ -157,8 +156,7 @@ static int adp5520_keys_probe(struct platform_device *pdev)
|
||||
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to write\n");
|
||||
ret = -EIO;
|
||||
goto err1;
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
dev->notifier.notifier_call = adp5520_keys_notifier;
|
||||
@ -166,19 +164,11 @@ static int adp5520_keys_probe(struct platform_device *pdev)
|
||||
ADP5520_KP_IEN | ADP5520_KR_IEN);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to register notifier\n");
|
||||
goto err1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, dev);
|
||||
return 0;
|
||||
|
||||
err1:
|
||||
input_unregister_device(input);
|
||||
input = NULL;
|
||||
err:
|
||||
input_free_device(input);
|
||||
kfree(dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int adp5520_keys_remove(struct platform_device *pdev)
|
||||
@ -188,8 +178,6 @@ static int adp5520_keys_remove(struct platform_device *pdev)
|
||||
adp5520_unregister_notifier(dev->master, &dev->notifier,
|
||||
ADP5520_KP_IEN | ADP5520_KR_IEN);
|
||||
|
||||
input_unregister_device(dev->input);
|
||||
kfree(dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -185,7 +185,7 @@ static int clps711x_keypad_remove(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct of_device_id clps711x_keypad_of_match[] = {
|
||||
static const struct of_device_id clps711x_keypad_of_match[] = {
|
||||
{ .compatible = "cirrus,clps711x-keypad", },
|
||||
{ }
|
||||
};
|
||||
|
@ -424,6 +424,16 @@ out:
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static void gpio_keys_quiesce_key(void *data)
|
||||
{
|
||||
struct gpio_button_data *bdata = data;
|
||||
|
||||
if (bdata->timer_debounce)
|
||||
del_timer_sync(&bdata->timer);
|
||||
|
||||
cancel_work_sync(&bdata->work);
|
||||
}
|
||||
|
||||
static int gpio_keys_setup_key(struct platform_device *pdev,
|
||||
struct input_dev *input,
|
||||
struct gpio_button_data *bdata,
|
||||
@ -433,7 +443,8 @@ static int gpio_keys_setup_key(struct platform_device *pdev,
|
||||
struct device *dev = &pdev->dev;
|
||||
irq_handler_t isr;
|
||||
unsigned long irqflags;
|
||||
int irq, error;
|
||||
int irq;
|
||||
int error;
|
||||
|
||||
bdata->input = input;
|
||||
bdata->button = button;
|
||||
@ -441,7 +452,8 @@ static int gpio_keys_setup_key(struct platform_device *pdev,
|
||||
|
||||
if (gpio_is_valid(button->gpio)) {
|
||||
|
||||
error = gpio_request_one(button->gpio, GPIOF_IN, desc);
|
||||
error = devm_gpio_request_one(&pdev->dev, button->gpio,
|
||||
GPIOF_IN, desc);
|
||||
if (error < 0) {
|
||||
dev_err(dev, "Failed to request GPIO %d, error %d\n",
|
||||
button->gpio, error);
|
||||
@ -463,7 +475,7 @@ static int gpio_keys_setup_key(struct platform_device *pdev,
|
||||
dev_err(dev,
|
||||
"Unable to get irq number for GPIO %d, error %d\n",
|
||||
button->gpio, error);
|
||||
goto fail;
|
||||
return error;
|
||||
}
|
||||
bdata->irq = irq;
|
||||
|
||||
@ -496,6 +508,18 @@ static int gpio_keys_setup_key(struct platform_device *pdev,
|
||||
|
||||
input_set_capability(input, button->type ?: EV_KEY, button->code);
|
||||
|
||||
/*
|
||||
* Install custom action to cancel debounce timer and
|
||||
* workqueue item.
|
||||
*/
|
||||
error = devm_add_action(&pdev->dev, gpio_keys_quiesce_key, bdata);
|
||||
if (error) {
|
||||
dev_err(&pdev->dev,
|
||||
"failed to register quiesce action, error: %d\n",
|
||||
error);
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
* If platform has specified that the button can be disabled,
|
||||
* we don't want it to share the interrupt line.
|
||||
@ -503,20 +527,15 @@ static int gpio_keys_setup_key(struct platform_device *pdev,
|
||||
if (!button->can_disable)
|
||||
irqflags |= IRQF_SHARED;
|
||||
|
||||
error = request_any_context_irq(bdata->irq, isr, irqflags, desc, bdata);
|
||||
error = devm_request_any_context_irq(&pdev->dev, bdata->irq,
|
||||
isr, irqflags, desc, bdata);
|
||||
if (error < 0) {
|
||||
dev_err(dev, "Unable to claim irq %d; error %d\n",
|
||||
bdata->irq, error);
|
||||
goto fail;
|
||||
return error;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
if (gpio_is_valid(button->gpio))
|
||||
gpio_free(button->gpio);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
static void gpio_keys_report_state(struct gpio_keys_drvdata *ddata)
|
||||
@ -578,23 +597,18 @@ gpio_keys_get_devtree_pdata(struct device *dev)
|
||||
int i;
|
||||
|
||||
node = dev->of_node;
|
||||
if (!node) {
|
||||
error = -ENODEV;
|
||||
goto err_out;
|
||||
}
|
||||
if (!node)
|
||||
return ERR_PTR(-ENODEV);
|
||||
|
||||
nbuttons = of_get_child_count(node);
|
||||
if (nbuttons == 0) {
|
||||
error = -ENODEV;
|
||||
goto err_out;
|
||||
}
|
||||
if (nbuttons == 0)
|
||||
return ERR_PTR(-ENODEV);
|
||||
|
||||
pdata = kzalloc(sizeof(*pdata) + nbuttons * (sizeof *button),
|
||||
GFP_KERNEL);
|
||||
if (!pdata) {
|
||||
error = -ENOMEM;
|
||||
goto err_out;
|
||||
}
|
||||
pdata = devm_kzalloc(dev,
|
||||
sizeof(*pdata) + nbuttons * sizeof(*button),
|
||||
GFP_KERNEL);
|
||||
if (!pdata)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
pdata->buttons = (struct gpio_keys_button *)(pdata + 1);
|
||||
pdata->nbuttons = nbuttons;
|
||||
@ -619,7 +633,7 @@ gpio_keys_get_devtree_pdata(struct device *dev)
|
||||
dev_err(dev,
|
||||
"Failed to get gpio flags, error: %d\n",
|
||||
error);
|
||||
goto err_free_pdata;
|
||||
return ERR_PTR(error);
|
||||
}
|
||||
|
||||
button = &pdata->buttons[i++];
|
||||
@ -630,8 +644,7 @@ gpio_keys_get_devtree_pdata(struct device *dev)
|
||||
if (of_property_read_u32(pp, "linux,code", &button->code)) {
|
||||
dev_err(dev, "Button without keycode: 0x%x\n",
|
||||
button->gpio);
|
||||
error = -EINVAL;
|
||||
goto err_free_pdata;
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
button->desc = of_get_property(pp, "label", NULL);
|
||||
@ -646,20 +659,13 @@ gpio_keys_get_devtree_pdata(struct device *dev)
|
||||
button->debounce_interval = 5;
|
||||
}
|
||||
|
||||
if (pdata->nbuttons == 0) {
|
||||
error = -EINVAL;
|
||||
goto err_free_pdata;
|
||||
}
|
||||
if (pdata->nbuttons == 0)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
return pdata;
|
||||
|
||||
err_free_pdata:
|
||||
kfree(pdata);
|
||||
err_out:
|
||||
return ERR_PTR(error);
|
||||
}
|
||||
|
||||
static struct of_device_id gpio_keys_of_match[] = {
|
||||
static const struct of_device_id gpio_keys_of_match[] = {
|
||||
{ .compatible = "gpio-keys", },
|
||||
{ },
|
||||
};
|
||||
@ -675,22 +681,13 @@ gpio_keys_get_devtree_pdata(struct device *dev)
|
||||
|
||||
#endif
|
||||
|
||||
static void gpio_remove_key(struct gpio_button_data *bdata)
|
||||
{
|
||||
free_irq(bdata->irq, bdata);
|
||||
if (bdata->timer_debounce)
|
||||
del_timer_sync(&bdata->timer);
|
||||
cancel_work_sync(&bdata->work);
|
||||
if (gpio_is_valid(bdata->button->gpio))
|
||||
gpio_free(bdata->button->gpio);
|
||||
}
|
||||
|
||||
static int gpio_keys_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
const struct gpio_keys_platform_data *pdata = dev_get_platdata(dev);
|
||||
struct gpio_keys_drvdata *ddata;
|
||||
struct input_dev *input;
|
||||
size_t size;
|
||||
int i, error;
|
||||
int wakeup = 0;
|
||||
|
||||
@ -700,14 +697,18 @@ static int gpio_keys_probe(struct platform_device *pdev)
|
||||
return PTR_ERR(pdata);
|
||||
}
|
||||
|
||||
ddata = kzalloc(sizeof(struct gpio_keys_drvdata) +
|
||||
pdata->nbuttons * sizeof(struct gpio_button_data),
|
||||
GFP_KERNEL);
|
||||
input = input_allocate_device();
|
||||
if (!ddata || !input) {
|
||||
size = sizeof(struct gpio_keys_drvdata) +
|
||||
pdata->nbuttons * sizeof(struct gpio_button_data);
|
||||
ddata = devm_kzalloc(dev, size, GFP_KERNEL);
|
||||
if (!ddata) {
|
||||
dev_err(dev, "failed to allocate state\n");
|
||||
error = -ENOMEM;
|
||||
goto fail1;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
input = devm_input_allocate_device(dev);
|
||||
if (!input) {
|
||||
dev_err(dev, "failed to allocate input device\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ddata->pdata = pdata;
|
||||
@ -738,7 +739,7 @@ static int gpio_keys_probe(struct platform_device *pdev)
|
||||
|
||||
error = gpio_keys_setup_key(pdev, input, bdata, button);
|
||||
if (error)
|
||||
goto fail2;
|
||||
return error;
|
||||
|
||||
if (button->wakeup)
|
||||
wakeup = 1;
|
||||
@ -748,57 +749,31 @@ static int gpio_keys_probe(struct platform_device *pdev)
|
||||
if (error) {
|
||||
dev_err(dev, "Unable to export keys/switches, error: %d\n",
|
||||
error);
|
||||
goto fail2;
|
||||
return error;
|
||||
}
|
||||
|
||||
error = input_register_device(input);
|
||||
if (error) {
|
||||
dev_err(dev, "Unable to register input device, error: %d\n",
|
||||
error);
|
||||
goto fail3;
|
||||
goto err_remove_group;
|
||||
}
|
||||
|
||||
device_init_wakeup(&pdev->dev, wakeup);
|
||||
|
||||
return 0;
|
||||
|
||||
fail3:
|
||||
err_remove_group:
|
||||
sysfs_remove_group(&pdev->dev.kobj, &gpio_keys_attr_group);
|
||||
fail2:
|
||||
while (--i >= 0)
|
||||
gpio_remove_key(&ddata->data[i]);
|
||||
|
||||
fail1:
|
||||
input_free_device(input);
|
||||
kfree(ddata);
|
||||
/* If we have no platform data, we allocated pdata dynamically. */
|
||||
if (!dev_get_platdata(&pdev->dev))
|
||||
kfree(pdata);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
static int gpio_keys_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct gpio_keys_drvdata *ddata = platform_get_drvdata(pdev);
|
||||
struct input_dev *input = ddata->input;
|
||||
int i;
|
||||
|
||||
sysfs_remove_group(&pdev->dev.kobj, &gpio_keys_attr_group);
|
||||
|
||||
device_init_wakeup(&pdev->dev, 0);
|
||||
|
||||
for (i = 0; i < ddata->pdata->nbuttons; i++)
|
||||
gpio_remove_key(&ddata->data[i]);
|
||||
|
||||
input_unregister_device(input);
|
||||
|
||||
/* If we have no platform data, we allocated pdata dynamically. */
|
||||
if (!dev_get_platdata(&pdev->dev))
|
||||
kfree(ddata->pdata);
|
||||
|
||||
kfree(ddata);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -120,12 +120,10 @@ static struct gpio_keys_platform_data *gpio_keys_polled_get_devtree_pdata(struct
|
||||
if (nbuttons == 0)
|
||||
return NULL;
|
||||
|
||||
pdata = kzalloc(sizeof(*pdata) + nbuttons * (sizeof *button),
|
||||
GFP_KERNEL);
|
||||
if (!pdata) {
|
||||
error = -ENOMEM;
|
||||
goto err_out;
|
||||
}
|
||||
pdata = devm_kzalloc(dev, sizeof(*pdata) + nbuttons * sizeof(*button),
|
||||
GFP_KERNEL);
|
||||
if (!pdata)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
pdata->buttons = (struct gpio_keys_button *)(pdata + 1);
|
||||
pdata->nbuttons = nbuttons;
|
||||
@ -151,7 +149,7 @@ static struct gpio_keys_platform_data *gpio_keys_polled_get_devtree_pdata(struct
|
||||
dev_err(dev,
|
||||
"Failed to get gpio flags, error: %d\n",
|
||||
error);
|
||||
goto err_free_pdata;
|
||||
return ERR_PTR(error);
|
||||
}
|
||||
|
||||
button = &pdata->buttons[i++];
|
||||
@ -162,8 +160,7 @@ static struct gpio_keys_platform_data *gpio_keys_polled_get_devtree_pdata(struct
|
||||
if (of_property_read_u32(pp, "linux,code", &button->code)) {
|
||||
dev_err(dev, "Button without keycode: 0x%x\n",
|
||||
button->gpio);
|
||||
error = -EINVAL;
|
||||
goto err_free_pdata;
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
button->desc = of_get_property(pp, "label", NULL);
|
||||
@ -178,20 +175,13 @@ static struct gpio_keys_platform_data *gpio_keys_polled_get_devtree_pdata(struct
|
||||
button->debounce_interval = 5;
|
||||
}
|
||||
|
||||
if (pdata->nbuttons == 0) {
|
||||
error = -EINVAL;
|
||||
goto err_free_pdata;
|
||||
}
|
||||
if (pdata->nbuttons == 0)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
return pdata;
|
||||
|
||||
err_free_pdata:
|
||||
kfree(pdata);
|
||||
err_out:
|
||||
return ERR_PTR(error);
|
||||
}
|
||||
|
||||
static struct of_device_id gpio_keys_polled_of_match[] = {
|
||||
static const struct of_device_id gpio_keys_polled_of_match[] = {
|
||||
{ .compatible = "gpio-keys-polled", },
|
||||
{ },
|
||||
};
|
||||
@ -213,6 +203,7 @@ static int gpio_keys_polled_probe(struct platform_device *pdev)
|
||||
struct gpio_keys_polled_dev *bdev;
|
||||
struct input_polled_dev *poll_dev;
|
||||
struct input_dev *input;
|
||||
size_t size;
|
||||
int error;
|
||||
int i;
|
||||
|
||||
@ -228,24 +219,21 @@ static int gpio_keys_polled_probe(struct platform_device *pdev)
|
||||
|
||||
if (!pdata->poll_interval) {
|
||||
dev_err(dev, "missing poll_interval value\n");
|
||||
error = -EINVAL;
|
||||
goto err_free_pdata;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
bdev = kzalloc(sizeof(struct gpio_keys_polled_dev) +
|
||||
pdata->nbuttons * sizeof(struct gpio_keys_button_data),
|
||||
GFP_KERNEL);
|
||||
size = sizeof(struct gpio_keys_polled_dev) +
|
||||
pdata->nbuttons * sizeof(struct gpio_keys_button_data);
|
||||
bdev = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
|
||||
if (!bdev) {
|
||||
dev_err(dev, "no memory for private data\n");
|
||||
error = -ENOMEM;
|
||||
goto err_free_pdata;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
poll_dev = input_allocate_polled_device();
|
||||
poll_dev = devm_input_allocate_polled_device(&pdev->dev);
|
||||
if (!poll_dev) {
|
||||
dev_err(dev, "no memory for polled device\n");
|
||||
error = -ENOMEM;
|
||||
goto err_free_bdev;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
poll_dev->private = bdev;
|
||||
@ -258,7 +246,6 @@ static int gpio_keys_polled_probe(struct platform_device *pdev)
|
||||
|
||||
input->name = pdev->name;
|
||||
input->phys = DRV_NAME"/input0";
|
||||
input->dev.parent = &pdev->dev;
|
||||
|
||||
input->id.bustype = BUS_HOST;
|
||||
input->id.vendor = 0x0001;
|
||||
@ -277,16 +264,15 @@ static int gpio_keys_polled_probe(struct platform_device *pdev)
|
||||
|
||||
if (button->wakeup) {
|
||||
dev_err(dev, DRV_NAME " does not support wakeup\n");
|
||||
error = -EINVAL;
|
||||
goto err_free_gpio;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
error = gpio_request_one(gpio, GPIOF_IN,
|
||||
button->desc ?: DRV_NAME);
|
||||
error = devm_gpio_request_one(&pdev->dev, gpio, GPIOF_IN,
|
||||
button->desc ? : DRV_NAME);
|
||||
if (error) {
|
||||
dev_err(dev, "unable to claim gpio %u, err=%d\n",
|
||||
gpio, error);
|
||||
goto err_free_gpio;
|
||||
return error;
|
||||
}
|
||||
|
||||
bdata->can_sleep = gpio_cansleep(gpio);
|
||||
@ -306,7 +292,7 @@ static int gpio_keys_polled_probe(struct platform_device *pdev)
|
||||
if (error) {
|
||||
dev_err(dev, "unable to register polled device, err=%d\n",
|
||||
error);
|
||||
goto err_free_gpio;
|
||||
return error;
|
||||
}
|
||||
|
||||
/* report initial state of the buttons */
|
||||
@ -315,52 +301,10 @@ static int gpio_keys_polled_probe(struct platform_device *pdev)
|
||||
&bdev->data[i]);
|
||||
|
||||
return 0;
|
||||
|
||||
err_free_gpio:
|
||||
while (--i >= 0)
|
||||
gpio_free(pdata->buttons[i].gpio);
|
||||
|
||||
input_free_polled_device(poll_dev);
|
||||
|
||||
err_free_bdev:
|
||||
kfree(bdev);
|
||||
|
||||
err_free_pdata:
|
||||
/* If we have no platform_data, we allocated pdata dynamically. */
|
||||
if (!dev_get_platdata(&pdev->dev))
|
||||
kfree(pdata);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
static int gpio_keys_polled_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct gpio_keys_polled_dev *bdev = platform_get_drvdata(pdev);
|
||||
const struct gpio_keys_platform_data *pdata = bdev->pdata;
|
||||
int i;
|
||||
|
||||
input_unregister_polled_device(bdev->poll_dev);
|
||||
|
||||
for (i = 0; i < pdata->nbuttons; i++)
|
||||
gpio_free(pdata->buttons[i].gpio);
|
||||
|
||||
input_free_polled_device(bdev->poll_dev);
|
||||
|
||||
/*
|
||||
* If we had no platform_data, we allocated pdata dynamically and
|
||||
* must free it here.
|
||||
*/
|
||||
if (!dev_get_platdata(&pdev->dev))
|
||||
kfree(pdata);
|
||||
|
||||
kfree(bdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver gpio_keys_polled_driver = {
|
||||
.probe = gpio_keys_polled_probe,
|
||||
.remove = gpio_keys_polled_remove,
|
||||
.driver = {
|
||||
.name = DRV_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
|
@ -415,7 +415,7 @@ open_err:
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static struct of_device_id imx_keypad_of_match[] = {
|
||||
static const struct of_device_id imx_keypad_of_match[] = {
|
||||
{ .compatible = "fsl,imx21-kpp", },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
@ -16,6 +16,7 @@
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/input-polldev.h>
|
||||
#include <linux/interrupt.h>
|
||||
@ -185,14 +186,15 @@ static int jornada680kbd_probe(struct platform_device *pdev)
|
||||
struct input_dev *input_dev;
|
||||
int i, error;
|
||||
|
||||
jornadakbd = kzalloc(sizeof(struct jornadakbd), GFP_KERNEL);
|
||||
jornadakbd = devm_kzalloc(&pdev->dev, sizeof(struct jornadakbd),
|
||||
GFP_KERNEL);
|
||||
if (!jornadakbd)
|
||||
return -ENOMEM;
|
||||
|
||||
poll_dev = input_allocate_polled_device();
|
||||
poll_dev = devm_input_allocate_polled_device(&pdev->dev);
|
||||
if (!poll_dev) {
|
||||
error = -ENOMEM;
|
||||
goto failed;
|
||||
dev_err(&pdev->dev, "failed to allocate polled input device\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, jornadakbd);
|
||||
@ -224,27 +226,10 @@ static int jornada680kbd_probe(struct platform_device *pdev)
|
||||
input_set_capability(input_dev, EV_MSC, MSC_SCAN);
|
||||
|
||||
error = input_register_polled_device(jornadakbd->poll_dev);
|
||||
if (error)
|
||||
goto failed;
|
||||
|
||||
return 0;
|
||||
|
||||
failed:
|
||||
printk(KERN_ERR "Jornadakbd: failed to register driver, error: %d\n",
|
||||
error);
|
||||
input_free_polled_device(poll_dev);
|
||||
kfree(jornadakbd);
|
||||
return error;
|
||||
|
||||
}
|
||||
|
||||
static int jornada680kbd_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct jornadakbd *jornadakbd = platform_get_drvdata(pdev);
|
||||
|
||||
input_unregister_polled_device(jornadakbd->poll_dev);
|
||||
input_free_polled_device(jornadakbd->poll_dev);
|
||||
kfree(jornadakbd);
|
||||
if (error) {
|
||||
dev_err(&pdev->dev, "failed to register polled input device\n");
|
||||
return error;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -255,7 +240,6 @@ static struct platform_driver jornada680kbd_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = jornada680kbd_probe,
|
||||
.remove = jornada680kbd_remove,
|
||||
};
|
||||
module_platform_driver(jornada680kbd_driver);
|
||||
|
||||
|
@ -147,7 +147,7 @@ static int mcs_touchkey_probe(struct i2c_client *client,
|
||||
}
|
||||
dev_info(&client->dev, "Firmware version: %d\n", fw_ver);
|
||||
|
||||
input_dev->name = "MELPAS MCS Touchkey";
|
||||
input_dev->name = "MELFAS MCS Touchkey";
|
||||
input_dev->id.bustype = BUS_I2C;
|
||||
input_dev->dev.parent = &client->dev;
|
||||
input_dev->evbit[0] = BIT_MASK(EV_KEY);
|
||||
|
@ -28,11 +28,10 @@
|
||||
#include <linux/io.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/input/matrix_keypad.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
|
||||
#include <linux/platform_data/omap4-keypad.h>
|
||||
|
||||
/* OMAP4 registers */
|
||||
#define OMAP4_KBD_REVISION 0x00
|
||||
#define OMAP4_KBD_SYSCONFIG 0x10
|
||||
@ -218,7 +217,6 @@ static void omap4_keypad_close(struct input_dev *input)
|
||||
pm_runtime_put_sync(input->dev.parent);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static int omap4_keypad_parse_dt(struct device *dev,
|
||||
struct omap4_keypad *keypad_data)
|
||||
{
|
||||
@ -235,20 +233,9 @@ static int omap4_keypad_parse_dt(struct device *dev,
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
static inline int omap4_keypad_parse_dt(struct device *dev,
|
||||
struct omap4_keypad *keypad_data)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int omap4_keypad_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct omap4_keypad_platform_data *pdata =
|
||||
dev_get_platdata(&pdev->dev);
|
||||
const struct matrix_keymap_data *keymap_data =
|
||||
pdata ? pdata->keymap_data : NULL;
|
||||
struct omap4_keypad *keypad_data;
|
||||
struct input_dev *input_dev;
|
||||
struct resource *res;
|
||||
@ -277,14 +264,9 @@ static int omap4_keypad_probe(struct platform_device *pdev)
|
||||
|
||||
keypad_data->irq = irq;
|
||||
|
||||
if (pdata) {
|
||||
keypad_data->rows = pdata->rows;
|
||||
keypad_data->cols = pdata->cols;
|
||||
} else {
|
||||
error = omap4_keypad_parse_dt(&pdev->dev, keypad_data);
|
||||
if (error)
|
||||
return error;
|
||||
}
|
||||
error = omap4_keypad_parse_dt(&pdev->dev, keypad_data);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
res = request_mem_region(res->start, resource_size(res), pdev->name);
|
||||
if (!res) {
|
||||
@ -363,7 +345,7 @@ static int omap4_keypad_probe(struct platform_device *pdev)
|
||||
goto err_free_input;
|
||||
}
|
||||
|
||||
error = matrix_keypad_build_keymap(keymap_data, NULL,
|
||||
error = matrix_keypad_build_keymap(NULL, NULL,
|
||||
keypad_data->rows, keypad_data->cols,
|
||||
keypad_data->keymap, input_dev);
|
||||
if (error) {
|
||||
@ -434,13 +416,11 @@ static int omap4_keypad_remove(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id omap_keypad_dt_match[] = {
|
||||
{ .compatible = "ti,omap4-keypad" },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, omap_keypad_dt_match);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int omap4_keypad_suspend(struct device *dev)
|
||||
@ -482,7 +462,7 @@ static struct platform_driver omap4_keypad_driver = {
|
||||
.name = "omap4-keypad",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &omap4_keypad_pm_ops,
|
||||
.of_match_table = of_match_ptr(omap_keypad_dt_match),
|
||||
.of_match_table = omap_keypad_dt_match,
|
||||
},
|
||||
};
|
||||
module_platform_driver(omap4_keypad_driver);
|
||||
|
274
drivers/input/keyboard/st-keyscan.c
Normal file
274
drivers/input/keyboard/st-keyscan.c
Normal file
@ -0,0 +1,274 @@
|
||||
/*
|
||||
* STMicroelectronics Key Scanning driver
|
||||
*
|
||||
* Copyright (c) 2014 STMicroelectonics Ltd.
|
||||
* Author: Stuart Menefy <stuart.menefy@st.com>
|
||||
*
|
||||
* Based on sh_keysc.c, copyright 2008 Magnus Damm
|
||||
*
|
||||
* 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/module.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/input/matrix_keypad.h>
|
||||
|
||||
#define ST_KEYSCAN_MAXKEYS 16
|
||||
|
||||
#define KEYSCAN_CONFIG_OFF 0x0
|
||||
#define KEYSCAN_CONFIG_ENABLE 0x1
|
||||
#define KEYSCAN_DEBOUNCE_TIME_OFF 0x4
|
||||
#define KEYSCAN_MATRIX_STATE_OFF 0x8
|
||||
#define KEYSCAN_MATRIX_DIM_OFF 0xc
|
||||
#define KEYSCAN_MATRIX_DIM_X_SHIFT 0x0
|
||||
#define KEYSCAN_MATRIX_DIM_Y_SHIFT 0x2
|
||||
|
||||
struct st_keyscan {
|
||||
void __iomem *base;
|
||||
int irq;
|
||||
struct clk *clk;
|
||||
struct input_dev *input_dev;
|
||||
unsigned long last_state;
|
||||
unsigned int n_rows;
|
||||
unsigned int n_cols;
|
||||
unsigned int debounce_us;
|
||||
};
|
||||
|
||||
static irqreturn_t keyscan_isr(int irq, void *dev_id)
|
||||
{
|
||||
struct st_keyscan *keypad = dev_id;
|
||||
unsigned short *keycode = keypad->input_dev->keycode;
|
||||
unsigned long state, change;
|
||||
int bit_nr;
|
||||
|
||||
state = readl(keypad->base + KEYSCAN_MATRIX_STATE_OFF) & 0xffff;
|
||||
change = keypad->last_state ^ state;
|
||||
keypad->last_state = state;
|
||||
|
||||
for_each_set_bit(bit_nr, &change, BITS_PER_LONG)
|
||||
input_report_key(keypad->input_dev,
|
||||
keycode[bit_nr], state & BIT(bit_nr));
|
||||
|
||||
input_sync(keypad->input_dev);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int keyscan_start(struct st_keyscan *keypad)
|
||||
{
|
||||
int error;
|
||||
|
||||
error = clk_enable(keypad->clk);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
writel(keypad->debounce_us * (clk_get_rate(keypad->clk) / 1000000),
|
||||
keypad->base + KEYSCAN_DEBOUNCE_TIME_OFF);
|
||||
|
||||
writel(((keypad->n_cols - 1) << KEYSCAN_MATRIX_DIM_X_SHIFT) |
|
||||
((keypad->n_rows - 1) << KEYSCAN_MATRIX_DIM_Y_SHIFT),
|
||||
keypad->base + KEYSCAN_MATRIX_DIM_OFF);
|
||||
|
||||
writel(KEYSCAN_CONFIG_ENABLE, keypad->base + KEYSCAN_CONFIG_OFF);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void keyscan_stop(struct st_keyscan *keypad)
|
||||
{
|
||||
writel(0, keypad->base + KEYSCAN_CONFIG_OFF);
|
||||
|
||||
clk_disable(keypad->clk);
|
||||
}
|
||||
|
||||
static int keyscan_open(struct input_dev *dev)
|
||||
{
|
||||
struct st_keyscan *keypad = input_get_drvdata(dev);
|
||||
|
||||
return keyscan_start(keypad);
|
||||
}
|
||||
|
||||
static void keyscan_close(struct input_dev *dev)
|
||||
{
|
||||
struct st_keyscan *keypad = input_get_drvdata(dev);
|
||||
|
||||
keyscan_stop(keypad);
|
||||
}
|
||||
|
||||
static int keypad_matrix_key_parse_dt(struct st_keyscan *keypad_data)
|
||||
{
|
||||
struct device *dev = keypad_data->input_dev->dev.parent;
|
||||
struct device_node *np = dev->of_node;
|
||||
int error;
|
||||
|
||||
error = matrix_keypad_parse_of_params(dev, &keypad_data->n_rows,
|
||||
&keypad_data->n_cols);
|
||||
if (error) {
|
||||
dev_err(dev, "failed to parse keypad params\n");
|
||||
return error;
|
||||
}
|
||||
|
||||
of_property_read_u32(np, "st,debounce-us", &keypad_data->debounce_us);
|
||||
|
||||
dev_dbg(dev, "n_rows=%d n_col=%d debounce=%d\n",
|
||||
keypad_data->n_rows, keypad_data->n_cols,
|
||||
keypad_data->debounce_us);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int keyscan_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct st_keyscan *keypad_data;
|
||||
struct input_dev *input_dev;
|
||||
struct resource *res;
|
||||
int error;
|
||||
|
||||
if (!pdev->dev.of_node) {
|
||||
dev_err(&pdev->dev, "no DT data present\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
keypad_data = devm_kzalloc(&pdev->dev, sizeof(*keypad_data),
|
||||
GFP_KERNEL);
|
||||
if (!keypad_data)
|
||||
return -ENOMEM;
|
||||
|
||||
input_dev = devm_input_allocate_device(&pdev->dev);
|
||||
if (!input_dev) {
|
||||
dev_err(&pdev->dev, "failed to allocate the input device\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
input_dev->name = pdev->name;
|
||||
input_dev->phys = "keyscan-keys/input0";
|
||||
input_dev->dev.parent = &pdev->dev;
|
||||
input_dev->open = keyscan_open;
|
||||
input_dev->close = keyscan_close;
|
||||
|
||||
input_dev->id.bustype = BUS_HOST;
|
||||
|
||||
error = keypad_matrix_key_parse_dt(keypad_data);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
error = matrix_keypad_build_keymap(NULL, NULL,
|
||||
keypad_data->n_rows,
|
||||
keypad_data->n_cols,
|
||||
NULL, input_dev);
|
||||
if (error) {
|
||||
dev_err(&pdev->dev, "failed to build keymap\n");
|
||||
return error;
|
||||
}
|
||||
|
||||
input_set_drvdata(input_dev, keypad_data);
|
||||
|
||||
keypad_data->input_dev = input_dev;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
keypad_data->base = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(keypad_data->base))
|
||||
return PTR_ERR(keypad_data->base);
|
||||
|
||||
keypad_data->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(keypad_data->clk)) {
|
||||
dev_err(&pdev->dev, "cannot get clock\n");
|
||||
return PTR_ERR(keypad_data->clk);
|
||||
}
|
||||
|
||||
error = clk_enable(keypad_data->clk);
|
||||
if (error) {
|
||||
dev_err(&pdev->dev, "failed to enable clock\n");
|
||||
return error;
|
||||
}
|
||||
|
||||
keyscan_stop(keypad_data);
|
||||
|
||||
keypad_data->irq = platform_get_irq(pdev, 0);
|
||||
if (keypad_data->irq < 0) {
|
||||
dev_err(&pdev->dev, "no IRQ specified\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
error = devm_request_irq(&pdev->dev, keypad_data->irq, keyscan_isr, 0,
|
||||
pdev->name, keypad_data);
|
||||
if (error) {
|
||||
dev_err(&pdev->dev, "failed to request IRQ\n");
|
||||
return error;
|
||||
}
|
||||
|
||||
error = input_register_device(input_dev);
|
||||
if (error) {
|
||||
dev_err(&pdev->dev, "failed to register input device\n");
|
||||
return error;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, keypad_data);
|
||||
|
||||
device_set_wakeup_capable(&pdev->dev, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int keyscan_suspend(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct st_keyscan *keypad = platform_get_drvdata(pdev);
|
||||
struct input_dev *input = keypad->input_dev;
|
||||
|
||||
mutex_lock(&input->mutex);
|
||||
|
||||
if (device_may_wakeup(dev))
|
||||
enable_irq_wake(keypad->irq);
|
||||
else if (input->users)
|
||||
keyscan_stop(keypad);
|
||||
|
||||
mutex_unlock(&input->mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int keyscan_resume(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct st_keyscan *keypad = platform_get_drvdata(pdev);
|
||||
struct input_dev *input = keypad->input_dev;
|
||||
int retval = 0;
|
||||
|
||||
mutex_lock(&input->mutex);
|
||||
|
||||
if (device_may_wakeup(dev))
|
||||
disable_irq_wake(keypad->irq);
|
||||
else if (input->users)
|
||||
retval = keyscan_start(keypad);
|
||||
|
||||
mutex_unlock(&input->mutex);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(keyscan_dev_pm_ops, keyscan_suspend, keyscan_resume);
|
||||
|
||||
static const struct of_device_id keyscan_of_match[] = {
|
||||
{ .compatible = "st,sti-keyscan" },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, keyscan_of_match);
|
||||
|
||||
static struct platform_driver keyscan_device_driver = {
|
||||
.probe = keyscan_probe,
|
||||
.driver = {
|
||||
.name = "st-keyscan",
|
||||
.pm = &keyscan_dev_pm_ops,
|
||||
.of_match_table = of_match_ptr(keyscan_of_match),
|
||||
}
|
||||
};
|
||||
|
||||
module_platform_driver(keyscan_device_driver);
|
||||
|
||||
MODULE_AUTHOR("Stuart Menefy <stuart.menefy@st.com>");
|
||||
MODULE_DESCRIPTION("STMicroelectronics keyscan device driver");
|
||||
MODULE_LICENSE("GPL");
|
@ -296,6 +296,65 @@ static void tc3589x_keypad_close(struct input_dev *input)
|
||||
tc3589x_keypad_disable(keypad);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct tc3589x_keypad_platform_data *
|
||||
tc3589x_keypad_of_probe(struct device *dev)
|
||||
{
|
||||
struct device_node *np = dev->of_node;
|
||||
struct tc3589x_keypad_platform_data *plat;
|
||||
u32 cols, rows;
|
||||
u32 debounce_ms;
|
||||
int proplen;
|
||||
|
||||
if (!np)
|
||||
return ERR_PTR(-ENODEV);
|
||||
|
||||
plat = devm_kzalloc(dev, sizeof(*plat), GFP_KERNEL);
|
||||
if (!plat)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
of_property_read_u32(np, "keypad,num-columns", &cols);
|
||||
of_property_read_u32(np, "keypad,num-rows", &rows);
|
||||
plat->kcol = (u8) cols;
|
||||
plat->krow = (u8) rows;
|
||||
if (!plat->krow || !plat->kcol ||
|
||||
plat->krow > TC_KPD_ROWS || plat->kcol > TC_KPD_COLUMNS) {
|
||||
dev_err(dev,
|
||||
"keypad columns/rows not properly specified (%ux%u)\n",
|
||||
plat->kcol, plat->krow);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
if (!of_get_property(np, "linux,keymap", &proplen)) {
|
||||
dev_err(dev, "property linux,keymap not found\n");
|
||||
return ERR_PTR(-ENOENT);
|
||||
}
|
||||
|
||||
plat->no_autorepeat = of_property_read_bool(np, "linux,no-autorepeat");
|
||||
plat->enable_wakeup = of_property_read_bool(np, "linux,wakeup");
|
||||
|
||||
/* The custom delay format is ms/16 */
|
||||
of_property_read_u32(np, "debounce-delay-ms", &debounce_ms);
|
||||
if (debounce_ms)
|
||||
plat->debounce_period = debounce_ms * 16;
|
||||
else
|
||||
plat->debounce_period = TC_KPD_DEBOUNCE_PERIOD;
|
||||
|
||||
plat->settle_time = TC_KPD_SETTLE_TIME;
|
||||
/* FIXME: should be property of the IRQ resource? */
|
||||
plat->irqtype = IRQF_TRIGGER_FALLING;
|
||||
|
||||
return plat;
|
||||
}
|
||||
#else
|
||||
static inline const struct tc3589x_keypad_platform_data *
|
||||
tc3589x_keypad_of_probe(struct device *dev)
|
||||
{
|
||||
return ERR_PTR(-ENODEV);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static int tc3589x_keypad_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct tc3589x *tc3589x = dev_get_drvdata(pdev->dev.parent);
|
||||
@ -306,8 +365,11 @@ static int tc3589x_keypad_probe(struct platform_device *pdev)
|
||||
|
||||
plat = tc3589x->pdata->keypad;
|
||||
if (!plat) {
|
||||
dev_err(&pdev->dev, "invalid keypad platform data\n");
|
||||
return -EINVAL;
|
||||
plat = tc3589x_keypad_of_probe(&pdev->dev);
|
||||
if (IS_ERR(plat)) {
|
||||
dev_err(&pdev->dev, "invalid keypad platform data\n");
|
||||
return PTR_ERR(plat);
|
||||
}
|
||||
}
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/mfd/88pm860x.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/device.h>
|
||||
|
||||
#define PM8607_WAKEUP 0x0b
|
||||
|
||||
@ -68,7 +69,8 @@ static int pm860x_onkey_probe(struct platform_device *pdev)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
info = kzalloc(sizeof(struct pm860x_onkey_info), GFP_KERNEL);
|
||||
info = devm_kzalloc(&pdev->dev, sizeof(struct pm860x_onkey_info),
|
||||
GFP_KERNEL);
|
||||
if (!info)
|
||||
return -ENOMEM;
|
||||
info->chip = chip;
|
||||
@ -76,11 +78,10 @@ static int pm860x_onkey_probe(struct platform_device *pdev)
|
||||
info->dev = &pdev->dev;
|
||||
info->irq = irq;
|
||||
|
||||
info->idev = input_allocate_device();
|
||||
info->idev = devm_input_allocate_device(&pdev->dev);
|
||||
if (!info->idev) {
|
||||
dev_err(chip->dev, "Failed to allocate input dev\n");
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
info->idev->name = "88pm860x_on";
|
||||
@ -93,42 +94,22 @@ static int pm860x_onkey_probe(struct platform_device *pdev)
|
||||
ret = input_register_device(info->idev);
|
||||
if (ret) {
|
||||
dev_err(chip->dev, "Can't register input device: %d\n", ret);
|
||||
goto out_reg;
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = request_threaded_irq(info->irq, NULL, pm860x_onkey_handler,
|
||||
IRQF_ONESHOT, "onkey", info);
|
||||
ret = devm_request_threaded_irq(&pdev->dev, info->irq, NULL,
|
||||
pm860x_onkey_handler, IRQF_ONESHOT,
|
||||
"onkey", info);
|
||||
if (ret < 0) {
|
||||
dev_err(chip->dev, "Failed to request IRQ: #%d: %d\n",
|
||||
info->irq, ret);
|
||||
goto out_irq;
|
||||
return ret;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, info);
|
||||
device_init_wakeup(&pdev->dev, 1);
|
||||
|
||||
return 0;
|
||||
|
||||
out_irq:
|
||||
input_unregister_device(info->idev);
|
||||
kfree(info);
|
||||
return ret;
|
||||
|
||||
out_reg:
|
||||
input_free_device(info->idev);
|
||||
out:
|
||||
kfree(info);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int pm860x_onkey_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct pm860x_onkey_info *info = platform_get_drvdata(pdev);
|
||||
|
||||
free_irq(info->irq, info);
|
||||
input_unregister_device(info->idev);
|
||||
kfree(info);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
@ -161,7 +142,6 @@ static struct platform_driver pm860x_onkey_driver = {
|
||||
.pm = &pm860x_onkey_pm_ops,
|
||||
},
|
||||
.probe = pm860x_onkey_probe,
|
||||
.remove = pm860x_onkey_remove,
|
||||
};
|
||||
module_platform_driver(pm860x_onkey_driver);
|
||||
|
||||
|
@ -224,7 +224,7 @@ config INPUT_GP2A
|
||||
|
||||
config INPUT_GPIO_BEEPER
|
||||
tristate "Generic GPIO Beeper support"
|
||||
depends on OF_GPIO
|
||||
depends on GPIOLIB
|
||||
help
|
||||
Say Y here if you have a beeper connected to a GPIO pin.
|
||||
|
||||
|
@ -7,6 +7,7 @@
|
||||
* AB8500 Power-On Key handler
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
@ -65,12 +66,14 @@ static int ab8500_ponkey_probe(struct platform_device *pdev)
|
||||
return irq_dbr;
|
||||
}
|
||||
|
||||
ponkey = kzalloc(sizeof(struct ab8500_ponkey), GFP_KERNEL);
|
||||
input = input_allocate_device();
|
||||
if (!ponkey || !input) {
|
||||
error = -ENOMEM;
|
||||
goto err_free_mem;
|
||||
}
|
||||
ponkey = devm_kzalloc(&pdev->dev, sizeof(struct ab8500_ponkey),
|
||||
GFP_KERNEL);
|
||||
if (!ponkey)
|
||||
return -ENOMEM;
|
||||
|
||||
input = devm_input_allocate_device(&pdev->dev);
|
||||
if (!input)
|
||||
return -ENOMEM;
|
||||
|
||||
ponkey->idev = input;
|
||||
ponkey->ab8500 = ab8500;
|
||||
@ -82,52 +85,32 @@ static int ab8500_ponkey_probe(struct platform_device *pdev)
|
||||
|
||||
input_set_capability(input, EV_KEY, KEY_POWER);
|
||||
|
||||
error = request_any_context_irq(ponkey->irq_dbf, ab8500_ponkey_handler,
|
||||
0, "ab8500-ponkey-dbf", ponkey);
|
||||
error = devm_request_any_context_irq(&pdev->dev, ponkey->irq_dbf,
|
||||
ab8500_ponkey_handler, 0,
|
||||
"ab8500-ponkey-dbf", ponkey);
|
||||
if (error < 0) {
|
||||
dev_err(ab8500->dev, "Failed to request dbf IRQ#%d: %d\n",
|
||||
ponkey->irq_dbf, error);
|
||||
goto err_free_mem;
|
||||
return error;
|
||||
}
|
||||
|
||||
error = request_any_context_irq(ponkey->irq_dbr, ab8500_ponkey_handler,
|
||||
0, "ab8500-ponkey-dbr", ponkey);
|
||||
error = devm_request_any_context_irq(&pdev->dev, ponkey->irq_dbr,
|
||||
ab8500_ponkey_handler, 0,
|
||||
"ab8500-ponkey-dbr", ponkey);
|
||||
if (error < 0) {
|
||||
dev_err(ab8500->dev, "Failed to request dbr IRQ#%d: %d\n",
|
||||
ponkey->irq_dbr, error);
|
||||
goto err_free_dbf_irq;
|
||||
return error;
|
||||
}
|
||||
|
||||
error = input_register_device(ponkey->idev);
|
||||
if (error) {
|
||||
dev_err(ab8500->dev, "Can't register input device: %d\n", error);
|
||||
goto err_free_dbr_irq;
|
||||
return error;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, ponkey);
|
||||
return 0;
|
||||
|
||||
err_free_dbr_irq:
|
||||
free_irq(ponkey->irq_dbr, ponkey);
|
||||
err_free_dbf_irq:
|
||||
free_irq(ponkey->irq_dbf, ponkey);
|
||||
err_free_mem:
|
||||
input_free_device(input);
|
||||
kfree(ponkey);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
static int ab8500_ponkey_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct ab8500_ponkey *ponkey = platform_get_drvdata(pdev);
|
||||
|
||||
free_irq(ponkey->irq_dbf, ponkey);
|
||||
free_irq(ponkey->irq_dbr, ponkey);
|
||||
input_unregister_device(ponkey->idev);
|
||||
kfree(ponkey);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
@ -144,7 +127,6 @@ static struct platform_driver ab8500_ponkey_driver = {
|
||||
.of_match_table = of_match_ptr(ab8500_ponkey_match),
|
||||
},
|
||||
.probe = ab8500_ponkey_probe,
|
||||
.remove = ab8500_ponkey_remove,
|
||||
};
|
||||
module_platform_driver(ab8500_ponkey_driver);
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Generic GPIO beeper driver
|
||||
*
|
||||
* Copyright (C) 2013 Alexander Shiyan <shc_work@mail.ru>
|
||||
* Copyright (C) 2013-2014 Alexander Shiyan <shc_work@mail.ru>
|
||||
*
|
||||
* 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
|
||||
@ -11,7 +11,8 @@
|
||||
|
||||
#include <linux/input.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
@ -19,14 +20,13 @@
|
||||
|
||||
struct gpio_beeper {
|
||||
struct work_struct work;
|
||||
int gpio;
|
||||
bool active_low;
|
||||
struct gpio_desc *desc;
|
||||
bool beeping;
|
||||
};
|
||||
|
||||
static void gpio_beeper_toggle(struct gpio_beeper *beep, bool on)
|
||||
{
|
||||
gpio_set_value_cansleep(beep->gpio, on ^ beep->active_low);
|
||||
gpiod_set_value_cansleep(beep->desc, on);
|
||||
}
|
||||
|
||||
static void gpio_beeper_work(struct work_struct *work)
|
||||
@ -65,18 +65,16 @@ static void gpio_beeper_close(struct input_dev *input)
|
||||
static int gpio_beeper_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct gpio_beeper *beep;
|
||||
enum of_gpio_flags flags;
|
||||
struct input_dev *input;
|
||||
unsigned long gflags;
|
||||
int err;
|
||||
|
||||
beep = devm_kzalloc(&pdev->dev, sizeof(*beep), GFP_KERNEL);
|
||||
if (!beep)
|
||||
return -ENOMEM;
|
||||
|
||||
beep->gpio = of_get_gpio_flags(pdev->dev.of_node, 0, &flags);
|
||||
if (!gpio_is_valid(beep->gpio))
|
||||
return beep->gpio;
|
||||
beep->desc = devm_gpiod_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(beep->desc))
|
||||
return PTR_ERR(beep->desc);
|
||||
|
||||
input = devm_input_allocate_device(&pdev->dev);
|
||||
if (!input)
|
||||
@ -94,10 +92,7 @@ static int gpio_beeper_probe(struct platform_device *pdev)
|
||||
|
||||
input_set_capability(input, EV_SND, SND_BELL);
|
||||
|
||||
beep->active_low = flags & OF_GPIO_ACTIVE_LOW;
|
||||
gflags = beep->active_low ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW;
|
||||
|
||||
err = devm_gpio_request_one(&pdev->dev, beep->gpio, gflags, pdev->name);
|
||||
err = gpiod_direction_output(beep->desc, 0);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
@ -106,17 +101,19 @@ static int gpio_beeper_probe(struct platform_device *pdev)
|
||||
return input_register_device(input);
|
||||
}
|
||||
|
||||
static struct of_device_id gpio_beeper_of_match[] = {
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id gpio_beeper_of_match[] = {
|
||||
{ .compatible = BEEPER_MODNAME, },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, gpio_beeper_of_match);
|
||||
#endif
|
||||
|
||||
static struct platform_driver gpio_beeper_platform_driver = {
|
||||
.driver = {
|
||||
.name = BEEPER_MODNAME,
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = gpio_beeper_of_match,
|
||||
.of_match_table = of_match_ptr(gpio_beeper_of_match),
|
||||
},
|
||||
.probe = gpio_beeper_probe,
|
||||
};
|
||||
|
@ -1566,6 +1566,7 @@ static int ims_pcu_buffers_alloc(struct ims_pcu *pcu)
|
||||
if (!pcu->urb_ctrl_buf) {
|
||||
dev_err(pcu->dev,
|
||||
"Failed to allocate memory for read buffer\n");
|
||||
error = -ENOMEM;
|
||||
goto err_free_urb_out_buf;
|
||||
}
|
||||
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/mfd/max8925.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/device.h>
|
||||
|
||||
#define SW_INPUT (1 << 7) /* 0/1 -- up/down */
|
||||
#define HARDRESET_EN (1 << 7)
|
||||
@ -81,12 +82,14 @@ static int max8925_onkey_probe(struct platform_device *pdev)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
info = kzalloc(sizeof(struct max8925_onkey_info), GFP_KERNEL);
|
||||
input = input_allocate_device();
|
||||
if (!info || !input) {
|
||||
error = -ENOMEM;
|
||||
goto err_free_mem;
|
||||
}
|
||||
info = devm_kzalloc(&pdev->dev, sizeof(struct max8925_onkey_info),
|
||||
GFP_KERNEL);
|
||||
if (!info)
|
||||
return -ENOMEM;
|
||||
|
||||
input = devm_input_allocate_device(&pdev->dev);
|
||||
if (!input)
|
||||
return -ENOMEM;
|
||||
|
||||
info->idev = input;
|
||||
info->i2c = chip->i2c;
|
||||
@ -100,54 +103,33 @@ static int max8925_onkey_probe(struct platform_device *pdev)
|
||||
input->dev.parent = &pdev->dev;
|
||||
input_set_capability(input, EV_KEY, KEY_POWER);
|
||||
|
||||
error = request_threaded_irq(irq[0], NULL, max8925_onkey_handler,
|
||||
IRQF_ONESHOT, "onkey-down", info);
|
||||
error = devm_request_threaded_irq(&pdev->dev, irq[0], NULL,
|
||||
max8925_onkey_handler, IRQF_ONESHOT,
|
||||
"onkey-down", info);
|
||||
if (error < 0) {
|
||||
dev_err(chip->dev, "Failed to request IRQ: #%d: %d\n",
|
||||
irq[0], error);
|
||||
goto err_free_mem;
|
||||
return error;
|
||||
}
|
||||
|
||||
error = request_threaded_irq(irq[1], NULL, max8925_onkey_handler,
|
||||
IRQF_ONESHOT, "onkey-up", info);
|
||||
error = devm_request_threaded_irq(&pdev->dev, irq[1], NULL,
|
||||
max8925_onkey_handler, IRQF_ONESHOT,
|
||||
"onkey-up", info);
|
||||
if (error < 0) {
|
||||
dev_err(chip->dev, "Failed to request IRQ: #%d: %d\n",
|
||||
irq[1], error);
|
||||
goto err_free_irq0;
|
||||
return error;
|
||||
}
|
||||
|
||||
error = input_register_device(info->idev);
|
||||
if (error) {
|
||||
dev_err(chip->dev, "Can't register input device: %d\n", error);
|
||||
goto err_free_irq1;
|
||||
return error;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, info);
|
||||
device_init_wakeup(&pdev->dev, 1);
|
||||
|
||||
return 0;
|
||||
|
||||
err_free_irq1:
|
||||
free_irq(irq[1], info);
|
||||
err_free_irq0:
|
||||
free_irq(irq[0], info);
|
||||
err_free_mem:
|
||||
input_free_device(input);
|
||||
kfree(info);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
static int max8925_onkey_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct max8925_onkey_info *info = platform_get_drvdata(pdev);
|
||||
struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent);
|
||||
|
||||
free_irq(info->irq[0] + chip->irq_base, info);
|
||||
free_irq(info->irq[1] + chip->irq_base, info);
|
||||
input_unregister_device(info->idev);
|
||||
kfree(info);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -190,7 +172,6 @@ static struct platform_driver max8925_onkey_driver = {
|
||||
.pm = &max8925_onkey_pm_ops,
|
||||
},
|
||||
.probe = max8925_onkey_probe,
|
||||
.remove = max8925_onkey_remove,
|
||||
};
|
||||
module_platform_driver(max8925_onkey_driver);
|
||||
|
||||
|
@ -181,11 +181,21 @@ static void max8997_haptic_enable(struct max8997_haptic *chip)
|
||||
}
|
||||
|
||||
if (!chip->enabled) {
|
||||
chip->enabled = true;
|
||||
regulator_enable(chip->regulator);
|
||||
error = regulator_enable(chip->regulator);
|
||||
if (error) {
|
||||
dev_err(chip->dev, "Failed to enable regulator\n");
|
||||
goto out;
|
||||
}
|
||||
max8997_haptic_configure(chip);
|
||||
if (chip->mode == MAX8997_EXTERNAL_MODE)
|
||||
pwm_enable(chip->pwm);
|
||||
if (chip->mode == MAX8997_EXTERNAL_MODE) {
|
||||
error = pwm_enable(chip->pwm);
|
||||
if (error) {
|
||||
dev_err(chip->dev, "Failed to enable PWM\n");
|
||||
regulator_disable(chip->regulator);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
chip->enabled = true;
|
||||
}
|
||||
|
||||
out:
|
||||
|
@ -92,15 +92,15 @@ static int pmic8xxx_pwrkey_probe(struct platform_device *pdev)
|
||||
bool pull_up;
|
||||
|
||||
if (of_property_read_u32(pdev->dev.of_node, "debounce", &kpd_delay))
|
||||
kpd_delay = 0;
|
||||
kpd_delay = 15625;
|
||||
|
||||
pull_up = of_property_read_bool(pdev->dev.of_node, "pull-up");
|
||||
|
||||
if (kpd_delay > 62500) {
|
||||
if (kpd_delay > 62500 || kpd_delay == 0) {
|
||||
dev_err(&pdev->dev, "invalid power key trigger delay\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
pull_up = of_property_read_bool(pdev->dev.of_node, "pull-up");
|
||||
|
||||
regmap = dev_get_regmap(pdev->dev.parent, NULL);
|
||||
if (!regmap) {
|
||||
dev_err(&pdev->dev, "failed to locate regmap for the device\n");
|
||||
|
@ -143,7 +143,7 @@ static irqreturn_t rotary_encoder_half_period_irq(int irq, void *dev_id)
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static struct of_device_id rotary_encoder_of_match[] = {
|
||||
static const struct of_device_id rotary_encoder_of_match[] = {
|
||||
{ .compatible = "rotary-encoder", },
|
||||
{ },
|
||||
};
|
||||
|
@ -17,7 +17,6 @@
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/gpio_keys.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pnp.h>
|
||||
|
||||
|
@ -262,7 +262,7 @@ static int twl6040_vibra_probe(struct platform_device *pdev)
|
||||
struct vibra_info *info;
|
||||
int vddvibl_uV = 0;
|
||||
int vddvibr_uV = 0;
|
||||
int ret;
|
||||
int error;
|
||||
|
||||
twl6040_core_node = of_find_node_by_name(twl6040_core_dev->of_node,
|
||||
"vibra");
|
||||
@ -309,12 +309,12 @@ static int twl6040_vibra_probe(struct platform_device *pdev)
|
||||
|
||||
mutex_init(&info->mutex);
|
||||
|
||||
ret = devm_request_threaded_irq(&pdev->dev, info->irq, NULL,
|
||||
twl6040_vib_irq_handler, 0,
|
||||
"twl6040_irq_vib", info);
|
||||
if (ret) {
|
||||
dev_err(info->dev, "VIB IRQ request failed: %d\n", ret);
|
||||
return ret;
|
||||
error = devm_request_threaded_irq(&pdev->dev, info->irq, NULL,
|
||||
twl6040_vib_irq_handler, 0,
|
||||
"twl6040_irq_vib", info);
|
||||
if (error) {
|
||||
dev_err(info->dev, "VIB IRQ request failed: %d\n", error);
|
||||
return error;
|
||||
}
|
||||
|
||||
info->supplies[0].supply = "vddvibl";
|
||||
@ -323,40 +323,40 @@ static int twl6040_vibra_probe(struct platform_device *pdev)
|
||||
* When booted with Device tree the regulators are attached to the
|
||||
* parent device (twl6040 MFD core)
|
||||
*/
|
||||
ret = regulator_bulk_get(twl6040_core_dev, ARRAY_SIZE(info->supplies),
|
||||
info->supplies);
|
||||
if (ret) {
|
||||
dev_err(info->dev, "couldn't get regulators %d\n", ret);
|
||||
return ret;
|
||||
error = devm_regulator_bulk_get(twl6040_core_dev,
|
||||
ARRAY_SIZE(info->supplies),
|
||||
info->supplies);
|
||||
if (error) {
|
||||
dev_err(info->dev, "couldn't get regulators %d\n", error);
|
||||
return error;
|
||||
}
|
||||
|
||||
if (vddvibl_uV) {
|
||||
ret = regulator_set_voltage(info->supplies[0].consumer,
|
||||
vddvibl_uV, vddvibl_uV);
|
||||
if (ret) {
|
||||
error = regulator_set_voltage(info->supplies[0].consumer,
|
||||
vddvibl_uV, vddvibl_uV);
|
||||
if (error) {
|
||||
dev_err(info->dev, "failed to set VDDVIBL volt %d\n",
|
||||
ret);
|
||||
goto err_regulator;
|
||||
error);
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
if (vddvibr_uV) {
|
||||
ret = regulator_set_voltage(info->supplies[1].consumer,
|
||||
vddvibr_uV, vddvibr_uV);
|
||||
if (ret) {
|
||||
error = regulator_set_voltage(info->supplies[1].consumer,
|
||||
vddvibr_uV, vddvibr_uV);
|
||||
if (error) {
|
||||
dev_err(info->dev, "failed to set VDDVIBR volt %d\n",
|
||||
ret);
|
||||
goto err_regulator;
|
||||
error);
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
INIT_WORK(&info->play_work, vibra_play_work);
|
||||
|
||||
info->input_dev = input_allocate_device();
|
||||
if (info->input_dev == NULL) {
|
||||
info->input_dev = devm_input_allocate_device(&pdev->dev);
|
||||
if (!info->input_dev) {
|
||||
dev_err(info->dev, "couldn't allocate input device\n");
|
||||
ret = -ENOMEM;
|
||||
goto err_regulator;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
input_set_drvdata(info->input_dev, info);
|
||||
@ -367,44 +367,25 @@ static int twl6040_vibra_probe(struct platform_device *pdev)
|
||||
info->input_dev->close = twl6040_vibra_close;
|
||||
__set_bit(FF_RUMBLE, info->input_dev->ffbit);
|
||||
|
||||
ret = input_ff_create_memless(info->input_dev, NULL, vibra_play);
|
||||
if (ret < 0) {
|
||||
error = input_ff_create_memless(info->input_dev, NULL, vibra_play);
|
||||
if (error) {
|
||||
dev_err(info->dev, "couldn't register vibrator to FF\n");
|
||||
goto err_ialloc;
|
||||
return error;
|
||||
}
|
||||
|
||||
ret = input_register_device(info->input_dev);
|
||||
if (ret < 0) {
|
||||
error = input_register_device(info->input_dev);
|
||||
if (error) {
|
||||
dev_err(info->dev, "couldn't register input device\n");
|
||||
goto err_iff;
|
||||
return error;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, info);
|
||||
|
||||
return 0;
|
||||
|
||||
err_iff:
|
||||
input_ff_destroy(info->input_dev);
|
||||
err_ialloc:
|
||||
input_free_device(info->input_dev);
|
||||
err_regulator:
|
||||
regulator_bulk_free(ARRAY_SIZE(info->supplies), info->supplies);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int twl6040_vibra_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct vibra_info *info = platform_get_drvdata(pdev);
|
||||
|
||||
input_unregister_device(info->input_dev);
|
||||
regulator_bulk_free(ARRAY_SIZE(info->supplies), info->supplies);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver twl6040_vibra_driver = {
|
||||
.probe = twl6040_vibra_probe,
|
||||
.remove = twl6040_vibra_remove,
|
||||
.driver = {
|
||||
.name = "twl6040-vibra",
|
||||
.owner = THIS_MODULE,
|
||||
|
@ -53,7 +53,7 @@ config MOUSE_PS2_LOGIPS2PP
|
||||
default y
|
||||
depends on MOUSE_PS2
|
||||
help
|
||||
Say Y here if you have a Logictech PS/2++ mouse connected to
|
||||
Say Y here if you have a Logitech PS/2++ mouse connected to
|
||||
your system.
|
||||
|
||||
If unsure, say Y.
|
||||
|
@ -473,8 +473,15 @@ static void elantech_report_absolute_v3(struct psmouse *psmouse,
|
||||
input_report_key(dev, BTN_TOOL_FINGER, fingers == 1);
|
||||
input_report_key(dev, BTN_TOOL_DOUBLETAP, fingers == 2);
|
||||
input_report_key(dev, BTN_TOOL_TRIPLETAP, fingers == 3);
|
||||
input_report_key(dev, BTN_LEFT, packet[0] & 0x01);
|
||||
input_report_key(dev, BTN_RIGHT, packet[0] & 0x02);
|
||||
|
||||
/* For clickpads map both buttons to BTN_LEFT */
|
||||
if (etd->fw_version & 0x001000) {
|
||||
input_report_key(dev, BTN_LEFT, packet[0] & 0x03);
|
||||
} else {
|
||||
input_report_key(dev, BTN_LEFT, packet[0] & 0x01);
|
||||
input_report_key(dev, BTN_RIGHT, packet[0] & 0x02);
|
||||
}
|
||||
|
||||
input_report_abs(dev, ABS_PRESSURE, pres);
|
||||
input_report_abs(dev, ABS_TOOL_WIDTH, width);
|
||||
|
||||
@ -484,10 +491,17 @@ static void elantech_report_absolute_v3(struct psmouse *psmouse,
|
||||
static void elantech_input_sync_v4(struct psmouse *psmouse)
|
||||
{
|
||||
struct input_dev *dev = psmouse->dev;
|
||||
struct elantech_data *etd = psmouse->private;
|
||||
unsigned char *packet = psmouse->packet;
|
||||
|
||||
input_report_key(dev, BTN_LEFT, packet[0] & 0x01);
|
||||
input_report_key(dev, BTN_RIGHT, packet[0] & 0x02);
|
||||
/* For clickpads map both buttons to BTN_LEFT */
|
||||
if (etd->fw_version & 0x001000) {
|
||||
input_report_key(dev, BTN_LEFT, packet[0] & 0x03);
|
||||
} else {
|
||||
input_report_key(dev, BTN_LEFT, packet[0] & 0x01);
|
||||
input_report_key(dev, BTN_RIGHT, packet[0] & 0x02);
|
||||
}
|
||||
|
||||
input_mt_report_pointer_emulation(dev, true);
|
||||
input_sync(dev);
|
||||
}
|
||||
@ -835,7 +849,7 @@ static int elantech_set_absolute_mode(struct psmouse *psmouse)
|
||||
if (etd->set_hw_resolution)
|
||||
etd->reg_10 = 0x0b;
|
||||
else
|
||||
etd->reg_10 = 0x03;
|
||||
etd->reg_10 = 0x01;
|
||||
|
||||
if (elantech_write_reg(psmouse, 0x10, etd->reg_10))
|
||||
rc = -1;
|
||||
@ -1336,7 +1350,8 @@ static int elantech_reconnect(struct psmouse *psmouse)
|
||||
}
|
||||
|
||||
/*
|
||||
* Some hw_version 3 models go into error state when we try to set bit 3 of r10
|
||||
* Some hw_version 3 models go into error state when we try to set
|
||||
* bit 3 and/or bit 1 of r10.
|
||||
*/
|
||||
static const struct dmi_system_id no_hw_res_dmi_table[] = {
|
||||
#if defined(CONFIG_DMI) && defined(CONFIG_X86)
|
||||
|
@ -347,15 +347,6 @@ static int synaptics_resolution(struct psmouse *psmouse)
|
||||
unsigned char resp[3];
|
||||
int i;
|
||||
|
||||
for (i = 0; min_max_pnpid_table[i].pnp_ids; i++)
|
||||
if (matches_pnp_id(psmouse, min_max_pnpid_table[i].pnp_ids)) {
|
||||
priv->x_min = min_max_pnpid_table[i].x_min;
|
||||
priv->x_max = min_max_pnpid_table[i].x_max;
|
||||
priv->y_min = min_max_pnpid_table[i].y_min;
|
||||
priv->y_max = min_max_pnpid_table[i].y_max;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (SYN_ID_MAJOR(priv->identity) < 4)
|
||||
return 0;
|
||||
|
||||
@ -366,6 +357,16 @@ static int synaptics_resolution(struct psmouse *psmouse)
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; min_max_pnpid_table[i].pnp_ids; i++) {
|
||||
if (matches_pnp_id(psmouse, min_max_pnpid_table[i].pnp_ids)) {
|
||||
priv->x_min = min_max_pnpid_table[i].x_min;
|
||||
priv->x_max = min_max_pnpid_table[i].x_max;
|
||||
priv->y_min = min_max_pnpid_table[i].y_min;
|
||||
priv->y_max = min_max_pnpid_table[i].y_max;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (SYN_EXT_CAP_REQUESTS(priv->capabilities) >= 5 &&
|
||||
SYN_CAP_MAX_DIMENSIONS(priv->ext_cap_0c)) {
|
||||
if (synaptics_send_cmd(psmouse, SYN_QUE_EXT_MAX_COORDS, resp)) {
|
||||
|
@ -203,7 +203,7 @@ static int apbps2_of_remove(struct platform_device *of_dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct of_device_id apbps2_of_match[] = {
|
||||
static const struct of_device_id apbps2_of_match[] = {
|
||||
{ .name = "GAISLER_APBPS2", },
|
||||
{ .name = "01_060", },
|
||||
{}
|
||||
|
@ -262,7 +262,7 @@ static int olpc_apsp_remove(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct of_device_id olpc_apsp_dt_ids[] = {
|
||||
static const struct of_device_id olpc_apsp_dt_ids[] = {
|
||||
{ .compatible = "olpc,ap-sp", },
|
||||
{}
|
||||
};
|
||||
|
@ -349,6 +349,7 @@ static int wacom_parse_hid(struct usb_interface *intf,
|
||||
break;
|
||||
|
||||
case MTTPC:
|
||||
case MTTPC_B:
|
||||
features->pktlen = WACOM_PKGLEN_MTTPC;
|
||||
break;
|
||||
|
||||
@ -380,6 +381,16 @@ static int wacom_parse_hid(struct usb_interface *intf,
|
||||
i += 12;
|
||||
break;
|
||||
|
||||
case MTTPC_B:
|
||||
features->x_max =
|
||||
get_unaligned_le16(&report[i + 3]);
|
||||
features->x_phy =
|
||||
get_unaligned_le16(&report[i + 6]);
|
||||
features->unit = report[i - 5];
|
||||
features->unitExpo = report[i - 3];
|
||||
i += 9;
|
||||
break;
|
||||
|
||||
default:
|
||||
features->x_max =
|
||||
get_unaligned_le16(&report[i + 3]);
|
||||
@ -430,6 +441,14 @@ static int wacom_parse_hid(struct usb_interface *intf,
|
||||
i += 12;
|
||||
break;
|
||||
|
||||
case MTTPC_B:
|
||||
features->y_max =
|
||||
get_unaligned_le16(&report[i + 3]);
|
||||
features->y_phy =
|
||||
get_unaligned_le16(&report[i + 6]);
|
||||
i += 9;
|
||||
break;
|
||||
|
||||
default:
|
||||
features->y_max =
|
||||
features->x_max;
|
||||
|
@ -484,6 +484,8 @@ static int wacom_intuos_inout(struct wacom_wac *wacom)
|
||||
input_report_key(input, BTN_TOUCH, 0);
|
||||
input_report_abs(input, ABS_PRESSURE, 0);
|
||||
input_report_abs(input, ABS_DISTANCE, wacom->features.distance_max);
|
||||
if (features->quirks & WACOM_QUIRK_MULTI_INPUT)
|
||||
wacom->shared->stylus_in_proximity = true;
|
||||
}
|
||||
|
||||
/* Exit report */
|
||||
@ -928,12 +930,12 @@ static int wacom_24hdt_irq(struct wacom_wac *wacom)
|
||||
input_mt_report_slot_state(input, MT_TOOL_FINGER, touch);
|
||||
|
||||
if (touch) {
|
||||
int t_x = le16_to_cpup((__le16 *)&data[offset + 2]);
|
||||
int c_x = le16_to_cpup((__le16 *)&data[offset + 4]);
|
||||
int t_y = le16_to_cpup((__le16 *)&data[offset + 6]);
|
||||
int c_y = le16_to_cpup((__le16 *)&data[offset + 8]);
|
||||
int w = le16_to_cpup((__le16 *)&data[offset + 10]);
|
||||
int h = le16_to_cpup((__le16 *)&data[offset + 12]);
|
||||
int t_x = get_unaligned_le16(&data[offset + 2]);
|
||||
int c_x = get_unaligned_le16(&data[offset + 4]);
|
||||
int t_y = get_unaligned_le16(&data[offset + 6]);
|
||||
int c_y = get_unaligned_le16(&data[offset + 8]);
|
||||
int w = get_unaligned_le16(&data[offset + 10]);
|
||||
int h = get_unaligned_le16(&data[offset + 12]);
|
||||
|
||||
input_report_abs(input, ABS_MT_POSITION_X, t_x);
|
||||
input_report_abs(input, ABS_MT_POSITION_Y, t_y);
|
||||
@ -962,7 +964,7 @@ static int wacom_mt_touch(struct wacom_wac *wacom)
|
||||
int x_offset = 0;
|
||||
|
||||
/* MTTPC does not support Height and Width */
|
||||
if (wacom->features.type == MTTPC)
|
||||
if (wacom->features.type == MTTPC || wacom->features.type == MTTPC_B)
|
||||
x_offset = -4;
|
||||
|
||||
/*
|
||||
@ -978,7 +980,7 @@ static int wacom_mt_touch(struct wacom_wac *wacom)
|
||||
for (i = 0; i < contacts_to_send; i++) {
|
||||
int offset = (WACOM_BYTES_PER_MT_PACKET + x_offset) * i + 3;
|
||||
bool touch = data[offset] & 0x1;
|
||||
int id = le16_to_cpup((__le16 *)&data[offset + 1]);
|
||||
int id = get_unaligned_le16(&data[offset + 1]);
|
||||
int slot = input_mt_get_slot_by_key(input, id);
|
||||
|
||||
if (slot < 0)
|
||||
@ -987,8 +989,8 @@ static int wacom_mt_touch(struct wacom_wac *wacom)
|
||||
input_mt_slot(input, slot);
|
||||
input_mt_report_slot_state(input, MT_TOOL_FINGER, touch);
|
||||
if (touch) {
|
||||
int x = le16_to_cpup((__le16 *)&data[offset + x_offset + 7]);
|
||||
int y = le16_to_cpup((__le16 *)&data[offset + x_offset + 9]);
|
||||
int x = get_unaligned_le16(&data[offset + x_offset + 7]);
|
||||
int y = get_unaligned_le16(&data[offset + x_offset + 9]);
|
||||
input_report_abs(input, ABS_MT_POSITION_X, x);
|
||||
input_report_abs(input, ABS_MT_POSITION_Y, y);
|
||||
}
|
||||
@ -1047,6 +1049,10 @@ static int wacom_tpc_single_touch(struct wacom_wac *wacom, size_t len)
|
||||
prox = data[0] & 0x01;
|
||||
x = get_unaligned_le16(&data[1]);
|
||||
y = get_unaligned_le16(&data[3]);
|
||||
} else if (len == WACOM_PKGLEN_TPC1FG_B) {
|
||||
prox = data[2] & 0x01;
|
||||
x = get_unaligned_le16(&data[3]);
|
||||
y = get_unaligned_le16(&data[5]);
|
||||
} else {
|
||||
prox = data[1] & 0x01;
|
||||
x = le16_to_cpup((__le16 *)&data[2]);
|
||||
@ -1110,6 +1116,9 @@ static int wacom_tpc_irq(struct wacom_wac *wacom, size_t len)
|
||||
case WACOM_PKGLEN_TPC2FG:
|
||||
return wacom_tpc_mt_touch(wacom);
|
||||
|
||||
case WACOM_PKGLEN_PENABLED:
|
||||
return wacom_tpc_pen(wacom);
|
||||
|
||||
default:
|
||||
switch (data[0]) {
|
||||
case WACOM_REPORT_TPC1FG:
|
||||
@ -1119,6 +1128,7 @@ static int wacom_tpc_irq(struct wacom_wac *wacom, size_t len)
|
||||
return wacom_tpc_single_touch(wacom, len);
|
||||
|
||||
case WACOM_REPORT_TPCMT:
|
||||
case WACOM_REPORT_TPCMT2:
|
||||
return wacom_mt_touch(wacom);
|
||||
|
||||
case WACOM_REPORT_PENABLED:
|
||||
@ -1461,6 +1471,7 @@ void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len)
|
||||
case TABLETPC2FG:
|
||||
case MTSCREEN:
|
||||
case MTTPC:
|
||||
case MTTPC_B:
|
||||
sync = wacom_tpc_irq(wacom_wac, len);
|
||||
break;
|
||||
|
||||
@ -1565,10 +1576,10 @@ static void wacom_abs_set_axis(struct input_dev *input_dev,
|
||||
struct wacom_features *features = &wacom_wac->features;
|
||||
|
||||
if (features->device_type == BTN_TOOL_PEN) {
|
||||
input_set_abs_params(input_dev, ABS_X, 0, features->x_max,
|
||||
features->x_fuzz, 0);
|
||||
input_set_abs_params(input_dev, ABS_Y, 0, features->y_max,
|
||||
features->y_fuzz, 0);
|
||||
input_set_abs_params(input_dev, ABS_X, features->x_min,
|
||||
features->x_max, features->x_fuzz, 0);
|
||||
input_set_abs_params(input_dev, ABS_Y, features->y_min,
|
||||
features->y_max, features->y_fuzz, 0);
|
||||
input_set_abs_params(input_dev, ABS_PRESSURE, 0,
|
||||
features->pressure_max, features->pressure_fuzz, 0);
|
||||
|
||||
@ -1802,6 +1813,7 @@ int wacom_setup_input_capabilities(struct input_dev *input_dev,
|
||||
|
||||
case MTSCREEN:
|
||||
case MTTPC:
|
||||
case MTTPC_B:
|
||||
case TABLETPC2FG:
|
||||
if (features->device_type == BTN_TOOL_FINGER) {
|
||||
unsigned int flags = INPUT_MT_DIRECT;
|
||||
@ -2123,11 +2135,11 @@ static const struct wacom_features wacom_features_0x317 =
|
||||
63, INTUOSPL, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES,
|
||||
.touch_max = 16 };
|
||||
static const struct wacom_features wacom_features_0xF4 =
|
||||
{ "Wacom Cintiq 24HD", WACOM_PKGLEN_INTUOS, 104480, 65600, 2047,
|
||||
63, WACOM_24HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
|
||||
{ "Wacom Cintiq 24HD", WACOM_PKGLEN_INTUOS, 104280, 65400, 2047,
|
||||
63, WACOM_24HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 200, 200 };
|
||||
static const struct wacom_features wacom_features_0xF8 =
|
||||
{ "Wacom Cintiq 24HD touch", WACOM_PKGLEN_INTUOS, 104480, 65600, 2047, /* Pen */
|
||||
63, WACOM_24HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES,
|
||||
{ "Wacom Cintiq 24HD touch", WACOM_PKGLEN_INTUOS, 104280, 65400, 2047, /* Pen */
|
||||
63, WACOM_24HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 200, 200,
|
||||
.oVid = USB_VENDOR_ID_WACOM, .oPid = 0xf6 };
|
||||
static const struct wacom_features wacom_features_0xF6 =
|
||||
{ "Wacom Cintiq 24HD touch", .type = WACOM_24HDT, /* Touch */
|
||||
@ -2142,8 +2154,8 @@ static const struct wacom_features wacom_features_0xC6 =
|
||||
{ "Wacom Cintiq 12WX", WACOM_PKGLEN_INTUOS, 53020, 33440, 1023,
|
||||
63, WACOM_BEE, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
|
||||
static const struct wacom_features wacom_features_0x304 =
|
||||
{ "Wacom Cintiq 13HD", WACOM_PKGLEN_INTUOS, 59552, 33848, 1023,
|
||||
63, WACOM_13HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
|
||||
{ "Wacom Cintiq 13HD", WACOM_PKGLEN_INTUOS, 59352, 33648, 1023,
|
||||
63, WACOM_13HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 200, 200 };
|
||||
static const struct wacom_features wacom_features_0xC7 =
|
||||
{ "Wacom DTU1931", WACOM_PKGLEN_GRAPHIRE, 37832, 30305, 511,
|
||||
0, PL, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
|
||||
@ -2157,24 +2169,24 @@ static const struct wacom_features wacom_features_0xFB =
|
||||
{ "Wacom DTU1031", WACOM_PKGLEN_DTUS, 22096, 13960, 511,
|
||||
0, DTUS, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
|
||||
static const struct wacom_features wacom_features_0x57 =
|
||||
{ "Wacom DTK2241", WACOM_PKGLEN_INTUOS, 95840, 54260, 2047,
|
||||
63, DTK, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES};
|
||||
{ "Wacom DTK2241", WACOM_PKGLEN_INTUOS, 95640, 54060, 2047,
|
||||
63, DTK, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 200, 200 };
|
||||
static const struct wacom_features wacom_features_0x59 = /* Pen */
|
||||
{ "Wacom DTH2242", WACOM_PKGLEN_INTUOS, 95840, 54260, 2047,
|
||||
63, DTK, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES,
|
||||
{ "Wacom DTH2242", WACOM_PKGLEN_INTUOS, 95640, 54060, 2047,
|
||||
63, DTK, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 200, 200,
|
||||
.oVid = USB_VENDOR_ID_WACOM, .oPid = 0x5D };
|
||||
static const struct wacom_features wacom_features_0x5D = /* Touch */
|
||||
{ "Wacom DTH2242", .type = WACOM_24HDT,
|
||||
.oVid = USB_VENDOR_ID_WACOM, .oPid = 0x59, .touch_max = 10 };
|
||||
static const struct wacom_features wacom_features_0xCC =
|
||||
{ "Wacom Cintiq 21UX2", WACOM_PKGLEN_INTUOS, 87200, 65600, 2047,
|
||||
63, WACOM_21UX2, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
|
||||
{ "Wacom Cintiq 21UX2", WACOM_PKGLEN_INTUOS, 87000, 65400, 2047,
|
||||
63, WACOM_21UX2, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 200, 200 };
|
||||
static const struct wacom_features wacom_features_0xFA =
|
||||
{ "Wacom Cintiq 22HD", WACOM_PKGLEN_INTUOS, 95840, 54260, 2047,
|
||||
63, WACOM_22HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
|
||||
{ "Wacom Cintiq 22HD", WACOM_PKGLEN_INTUOS, 95640, 54060, 2047,
|
||||
63, WACOM_22HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 200, 200 };
|
||||
static const struct wacom_features wacom_features_0x5B =
|
||||
{ "Wacom Cintiq 22HDT", WACOM_PKGLEN_INTUOS, 95840, 54260, 2047,
|
||||
63, WACOM_22HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES,
|
||||
{ "Wacom Cintiq 22HDT", WACOM_PKGLEN_INTUOS, 95640, 54060, 2047,
|
||||
63, WACOM_22HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 200, 200,
|
||||
.oVid = USB_VENDOR_ID_WACOM, .oPid = 0x5e };
|
||||
static const struct wacom_features wacom_features_0x5E =
|
||||
{ "Wacom Cintiq 22HDT", .type = WACOM_24HDT,
|
||||
@ -2233,9 +2245,21 @@ static const struct wacom_features wacom_features_0x10E =
|
||||
static const struct wacom_features wacom_features_0x10F =
|
||||
{ "Wacom ISDv4 10F", WACOM_PKGLEN_MTTPC, 27760, 15694, 255,
|
||||
0, MTTPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
|
||||
static const struct wacom_features wacom_features_0x116 =
|
||||
{ "Wacom ISDv4 116", WACOM_PKGLEN_GRAPHIRE, 26202, 16325, 255,
|
||||
0, TABLETPCE, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
|
||||
static const struct wacom_features wacom_features_0x4001 =
|
||||
{ "Wacom ISDv4 4001", WACOM_PKGLEN_MTTPC, 26202, 16325, 255,
|
||||
0, MTTPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
|
||||
static const struct wacom_features wacom_features_0x4004 =
|
||||
{ "Wacom ISDv4 4004", WACOM_PKGLEN_MTTPC, 11060, 6220, 255,
|
||||
0, MTTPC_B, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
|
||||
static const struct wacom_features wacom_features_0x5000 =
|
||||
{ "Wacom ISDv4 5000", WACOM_PKGLEN_MTTPC, 27848, 15752, 1023,
|
||||
0, MTTPC_B, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
|
||||
static const struct wacom_features wacom_features_0x5002 =
|
||||
{ "Wacom ISDv4 5002", WACOM_PKGLEN_MTTPC, 29576, 16724, 1023,
|
||||
0, MTTPC_B, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
|
||||
static const struct wacom_features wacom_features_0x47 =
|
||||
{ "Wacom Intuos2 6x8", WACOM_PKGLEN_INTUOS, 20320, 16240, 1023,
|
||||
31, INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
|
||||
@ -2316,8 +2340,8 @@ static const struct wacom_features wacom_features_0x6004 =
|
||||
{ "ISD-V4", WACOM_PKGLEN_GRAPHIRE, 12800, 8000, 255,
|
||||
0, TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
|
||||
static const struct wacom_features wacom_features_0x0307 =
|
||||
{ "Wacom ISDv5 307", WACOM_PKGLEN_INTUOS, 59552, 33848, 2047,
|
||||
63, CINTIQ_HYBRID, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES,
|
||||
{ "Wacom ISDv5 307", WACOM_PKGLEN_INTUOS, 59352, 33648, 2047,
|
||||
63, CINTIQ_HYBRID, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 200, 200,
|
||||
.oVid = USB_VENDOR_ID_WACOM, .oPid = 0x309 };
|
||||
static const struct wacom_features wacom_features_0x0309 =
|
||||
{ "Wacom ISDv5 309", .type = WACOM_24HDT, /* Touch */
|
||||
@ -2447,6 +2471,7 @@ const struct usb_device_id wacom_ids[] = {
|
||||
{ USB_DEVICE_WACOM(0x10D) },
|
||||
{ USB_DEVICE_WACOM(0x10E) },
|
||||
{ USB_DEVICE_WACOM(0x10F) },
|
||||
{ USB_DEVICE_WACOM(0x116) },
|
||||
{ USB_DEVICE_WACOM(0x300) },
|
||||
{ USB_DEVICE_WACOM(0x301) },
|
||||
{ USB_DEVICE_DETAILED(0x302, USB_CLASS_HID, 0, 0) },
|
||||
@ -2457,6 +2482,9 @@ const struct usb_device_id wacom_ids[] = {
|
||||
{ USB_DEVICE_DETAILED(0x315, USB_CLASS_HID, 0, 0) },
|
||||
{ USB_DEVICE_DETAILED(0x317, USB_CLASS_HID, 0, 0) },
|
||||
{ USB_DEVICE_WACOM(0x4001) },
|
||||
{ USB_DEVICE_WACOM(0x4004) },
|
||||
{ USB_DEVICE_WACOM(0x5000) },
|
||||
{ USB_DEVICE_WACOM(0x5002) },
|
||||
{ USB_DEVICE_WACOM(0x47) },
|
||||
{ USB_DEVICE_WACOM(0xF4) },
|
||||
{ USB_DEVICE_WACOM(0xF8) },
|
||||
|
@ -22,6 +22,7 @@
|
||||
#define WACOM_PKGLEN_BBFUN 9
|
||||
#define WACOM_PKGLEN_INTUOS 10
|
||||
#define WACOM_PKGLEN_TPC1FG 5
|
||||
#define WACOM_PKGLEN_TPC1FG_B 10
|
||||
#define WACOM_PKGLEN_TPC2FG 14
|
||||
#define WACOM_PKGLEN_BBTOUCH 20
|
||||
#define WACOM_PKGLEN_BBTOUCH3 64
|
||||
@ -30,6 +31,7 @@
|
||||
#define WACOM_PKGLEN_MTOUCH 62
|
||||
#define WACOM_PKGLEN_MTTPC 40
|
||||
#define WACOM_PKGLEN_DTUS 68
|
||||
#define WACOM_PKGLEN_PENABLED 8
|
||||
|
||||
/* wacom data size per MT contact */
|
||||
#define WACOM_BYTES_PER_MT_PACKET 11
|
||||
@ -52,6 +54,7 @@
|
||||
#define WACOM_REPORT_TPC1FG 6
|
||||
#define WACOM_REPORT_TPC2FG 13
|
||||
#define WACOM_REPORT_TPCMT 13
|
||||
#define WACOM_REPORT_TPCMT2 3
|
||||
#define WACOM_REPORT_TPCHID 15
|
||||
#define WACOM_REPORT_TPCST 16
|
||||
#define WACOM_REPORT_DTUS 17
|
||||
@ -105,6 +108,7 @@ enum {
|
||||
TABLETPC2FG,
|
||||
MTSCREEN,
|
||||
MTTPC,
|
||||
MTTPC_B,
|
||||
MAX_TYPE
|
||||
};
|
||||
|
||||
@ -118,6 +122,8 @@ struct wacom_features {
|
||||
int type;
|
||||
int x_resolution;
|
||||
int y_resolution;
|
||||
int x_min;
|
||||
int y_min;
|
||||
int device_type;
|
||||
int x_phy;
|
||||
int y_phy;
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include <linux/input.h>
|
||||
#include <linux/mfd/88pm860x.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/device.h>
|
||||
|
||||
#define MEAS_LEN (8)
|
||||
#define ACCURATE_BIT (12)
|
||||
@ -234,16 +235,17 @@ static int pm860x_touch_probe(struct platform_device *pdev)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
touch = kzalloc(sizeof(struct pm860x_touch), GFP_KERNEL);
|
||||
if (touch == NULL)
|
||||
touch = devm_kzalloc(&pdev->dev, sizeof(struct pm860x_touch),
|
||||
GFP_KERNEL);
|
||||
if (!touch)
|
||||
return -ENOMEM;
|
||||
|
||||
platform_set_drvdata(pdev, touch);
|
||||
|
||||
touch->idev = input_allocate_device();
|
||||
if (touch->idev == NULL) {
|
||||
touch->idev = devm_input_allocate_device(&pdev->dev);
|
||||
if (!touch->idev) {
|
||||
dev_err(&pdev->dev, "Failed to allocate input device!\n");
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
touch->idev->name = "88pm860x-touch";
|
||||
@ -258,10 +260,11 @@ static int pm860x_touch_probe(struct platform_device *pdev)
|
||||
touch->res_x = res_x;
|
||||
input_set_drvdata(touch->idev, touch);
|
||||
|
||||
ret = request_threaded_irq(touch->irq, NULL, pm860x_touch_handler,
|
||||
IRQF_ONESHOT, "touch", touch);
|
||||
ret = devm_request_threaded_irq(&pdev->dev, touch->irq, NULL,
|
||||
pm860x_touch_handler, IRQF_ONESHOT,
|
||||
"touch", touch);
|
||||
if (ret < 0)
|
||||
goto out_irq;
|
||||
return ret;
|
||||
|
||||
__set_bit(EV_ABS, touch->idev->evbit);
|
||||
__set_bit(ABS_X, touch->idev->absbit);
|
||||
@ -279,28 +282,11 @@ static int pm860x_touch_probe(struct platform_device *pdev)
|
||||
ret = input_register_device(touch->idev);
|
||||
if (ret < 0) {
|
||||
dev_err(chip->dev, "Failed to register touch!\n");
|
||||
goto out_rg;
|
||||
return ret;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, touch);
|
||||
return 0;
|
||||
out_rg:
|
||||
free_irq(touch->irq, touch);
|
||||
out_irq:
|
||||
input_free_device(touch->idev);
|
||||
out:
|
||||
kfree(touch);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int pm860x_touch_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct pm860x_touch *touch = platform_get_drvdata(pdev);
|
||||
|
||||
input_unregister_device(touch->idev);
|
||||
free_irq(touch->irq, touch);
|
||||
kfree(touch);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver pm860x_touch_driver = {
|
||||
@ -309,7 +295,6 @@ static struct platform_driver pm860x_touch_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = pm860x_touch_probe,
|
||||
.remove = pm860x_touch_remove,
|
||||
};
|
||||
module_platform_driver(pm860x_touch_driver);
|
||||
|
||||
|
@ -11,6 +11,10 @@ menuconfig INPUT_TOUCHSCREEN
|
||||
|
||||
if INPUT_TOUCHSCREEN
|
||||
|
||||
config OF_TOUCHSCREEN
|
||||
def_tristate INPUT
|
||||
depends on INPUT && OF
|
||||
|
||||
config TOUCHSCREEN_88PM860X
|
||||
tristate "Marvell 88PM860x touchscreen"
|
||||
depends on MFD_88PM860X
|
||||
@ -89,6 +93,7 @@ config TOUCHSCREEN_AD7879_SPI
|
||||
config TOUCHSCREEN_ATMEL_MXT
|
||||
tristate "Atmel mXT I2C Touchscreen"
|
||||
depends on I2C
|
||||
select FW_LOADER
|
||||
help
|
||||
Say Y here if you have Atmel mXT series I2C touchscreen,
|
||||
such as AT42QT602240/ATMXT224, connected to your system.
|
||||
@ -846,7 +851,7 @@ config TOUCHSCREEN_TSC2007
|
||||
|
||||
config TOUCHSCREEN_W90X900
|
||||
tristate "W90P910 touchscreen driver"
|
||||
depends on HAVE_CLK
|
||||
depends on ARCH_W90X900
|
||||
help
|
||||
Say Y here if you have a W90P910 based touchscreen.
|
||||
|
||||
@ -885,6 +890,17 @@ config TOUCHSCREEN_STMPE
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called stmpe-ts.
|
||||
|
||||
config TOUCHSCREEN_SUN4I
|
||||
tristate "Allwinner sun4i resistive touchscreen controller support"
|
||||
depends on ARCH_SUNXI || COMPILE_TEST
|
||||
depends on HWMON
|
||||
help
|
||||
This selects support for the resistive touchscreen controller
|
||||
found on Allwinner sunxi SoCs.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called sun4i-ts.
|
||||
|
||||
config TOUCHSCREEN_SUR40
|
||||
tristate "Samsung SUR40 (Surface 2.0/PixelSense) touchscreen"
|
||||
depends on USB
|
||||
|
@ -6,6 +6,7 @@
|
||||
|
||||
wm97xx-ts-y := wm97xx-core.o
|
||||
|
||||
obj-$(CONFIG_OF_TOUCHSCREEN) += of_touchscreen.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_88PM860X) += 88pm860x-ts.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_AD7877) += ad7877.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_AD7879) += ad7879.o
|
||||
@ -53,6 +54,7 @@ obj-$(CONFIG_TOUCHSCREEN_PIXCIR) += pixcir_i2c_ts.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_S3C2410) += s3c2410_ts.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_ST1232) += st1232.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_STMPE) += stmpe-ts.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_SUN4I) += sun4i-ts.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_SUR40) += sur40.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_TI_AM335X_TSC) += ti_am335x_tsc.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_TOUCHIT213) += touchit213.o
|
||||
|
@ -210,11 +210,6 @@ static bool gpio3;
|
||||
module_param(gpio3, bool, 0);
|
||||
MODULE_PARM_DESC(gpio3, "If gpio3 is set to 1 AUX3 acts as GPIO3");
|
||||
|
||||
/*
|
||||
* ad7877_read/write are only used for initial setup and for sysfs controls.
|
||||
* The main traffic is done using spi_async() in the interrupt handler.
|
||||
*/
|
||||
|
||||
static int ad7877_read(struct spi_device *spi, u16 reg)
|
||||
{
|
||||
struct ser_req *req;
|
||||
|
@ -706,7 +706,7 @@ static void ads7846_read_state(struct ads7846 *ts)
|
||||
m = &ts->msg[msg_idx];
|
||||
error = spi_sync(ts->spi, m);
|
||||
if (error) {
|
||||
dev_err(&ts->spi->dev, "spi_async --> %d\n", error);
|
||||
dev_err(&ts->spi->dev, "spi_sync --> %d\n", error);
|
||||
packet->tc.ignore = true;
|
||||
return;
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -679,7 +679,7 @@ static const struct i2c_device_id auo_pixcir_idtable[] = {
|
||||
MODULE_DEVICE_TABLE(i2c, auo_pixcir_idtable);
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static struct of_device_id auo_pixcir_ts_dt_idtable[] = {
|
||||
static const struct of_device_id auo_pixcir_ts_dt_idtable[] = {
|
||||
{ .compatible = "auo,auo_pixcir_ts" },
|
||||
{},
|
||||
};
|
||||
|
@ -301,10 +301,11 @@ static int da9034_touch_probe(struct platform_device *pdev)
|
||||
struct da9034_touch_pdata *pdata = dev_get_platdata(&pdev->dev);
|
||||
struct da9034_touch *touch;
|
||||
struct input_dev *input_dev;
|
||||
int ret;
|
||||
int error;
|
||||
|
||||
touch = kzalloc(sizeof(struct da9034_touch), GFP_KERNEL);
|
||||
if (touch == NULL) {
|
||||
touch = devm_kzalloc(&pdev->dev, sizeof(struct da9034_touch),
|
||||
GFP_KERNEL);
|
||||
if (!touch) {
|
||||
dev_err(&pdev->dev, "failed to allocate driver data\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
@ -315,18 +316,18 @@ static int da9034_touch_probe(struct platform_device *pdev)
|
||||
touch->interval_ms = pdata->interval_ms;
|
||||
touch->x_inverted = pdata->x_inverted;
|
||||
touch->y_inverted = pdata->y_inverted;
|
||||
} else
|
||||
} else {
|
||||
/* fallback into default */
|
||||
touch->interval_ms = 10;
|
||||
}
|
||||
|
||||
INIT_DELAYED_WORK(&touch->tsi_work, da9034_tsi_work);
|
||||
touch->notifier.notifier_call = da9034_touch_notifier;
|
||||
|
||||
input_dev = input_allocate_device();
|
||||
input_dev = devm_input_allocate_device(&pdev->dev);
|
||||
if (!input_dev) {
|
||||
dev_err(&pdev->dev, "failed to allocate input device\n");
|
||||
ret = -ENOMEM;
|
||||
goto err_free_touch;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
input_dev->name = pdev->name;
|
||||
@ -346,26 +347,9 @@ static int da9034_touch_probe(struct platform_device *pdev)
|
||||
touch->input_dev = input_dev;
|
||||
input_set_drvdata(input_dev, touch);
|
||||
|
||||
ret = input_register_device(input_dev);
|
||||
if (ret)
|
||||
goto err_free_input;
|
||||
|
||||
platform_set_drvdata(pdev, touch);
|
||||
return 0;
|
||||
|
||||
err_free_input:
|
||||
input_free_device(input_dev);
|
||||
err_free_touch:
|
||||
kfree(touch);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int da9034_touch_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct da9034_touch *touch = platform_get_drvdata(pdev);
|
||||
|
||||
input_unregister_device(touch->input_dev);
|
||||
kfree(touch);
|
||||
error = input_register_device(input_dev);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -376,7 +360,6 @@ static struct platform_driver da9034_touch_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = da9034_touch_probe,
|
||||
.remove = da9034_touch_remove,
|
||||
};
|
||||
module_platform_driver(da9034_touch_driver);
|
||||
|
||||
|
@ -271,7 +271,7 @@ static int edt_ft5x06_register_write(struct edt_ft5x06_ts_data *tsdata,
|
||||
wrbuf[0] = addr;
|
||||
wrbuf[1] = value;
|
||||
|
||||
return edt_ft5x06_ts_readwrite(tsdata->client, 3,
|
||||
return edt_ft5x06_ts_readwrite(tsdata->client, 2,
|
||||
wrbuf, 0, NULL);
|
||||
|
||||
default:
|
||||
|
@ -262,7 +262,7 @@ static int egalax_ts_resume(struct device *dev)
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(egalax_ts_pm_ops, egalax_ts_suspend, egalax_ts_resume);
|
||||
|
||||
static struct of_device_id egalax_ts_dt_ids[] = {
|
||||
static const struct of_device_id egalax_ts_dt_ids[] = {
|
||||
{ .compatible = "eeti,egalax_ts" },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
@ -36,6 +36,7 @@
|
||||
#include <linux/irq.h>
|
||||
#include <linux/delay.h>
|
||||
#include <asm/intel_scu_ipc.h>
|
||||
#include <linux/device.h>
|
||||
|
||||
/* PMIC Interrupt registers */
|
||||
#define PMIC_REG_ID1 0x00 /* PMIC ID1 register */
|
||||
@ -580,12 +581,17 @@ static int mrstouch_probe(struct platform_device *pdev)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
tsdev = kzalloc(sizeof(struct mrstouch_dev), GFP_KERNEL);
|
||||
input = input_allocate_device();
|
||||
if (!tsdev || !input) {
|
||||
tsdev = devm_kzalloc(&pdev->dev, sizeof(struct mrstouch_dev),
|
||||
GFP_KERNEL);
|
||||
if (!tsdev) {
|
||||
dev_err(&pdev->dev, "unable to allocate memory\n");
|
||||
err = -ENOMEM;
|
||||
goto err_free_mem;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
input = devm_input_allocate_device(&pdev->dev);
|
||||
if (!input) {
|
||||
dev_err(&pdev->dev, "unable to allocate input device\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
tsdev->dev = &pdev->dev;
|
||||
@ -598,7 +604,7 @@ static int mrstouch_probe(struct platform_device *pdev)
|
||||
err = mrstouch_adc_init(tsdev);
|
||||
if (err) {
|
||||
dev_err(&pdev->dev, "ADC initialization failed\n");
|
||||
goto err_free_mem;
|
||||
return err;
|
||||
}
|
||||
|
||||
input->name = "mrst_touchscreen";
|
||||
@ -618,38 +624,20 @@ static int mrstouch_probe(struct platform_device *pdev)
|
||||
input_set_abs_params(tsdev->input, ABS_PRESSURE,
|
||||
MRST_PRESSURE_MIN, MRST_PRESSURE_MAX, 0, 0);
|
||||
|
||||
err = request_threaded_irq(tsdev->irq, NULL, mrstouch_pendet_irq,
|
||||
IRQF_ONESHOT, "mrstouch", tsdev);
|
||||
err = devm_request_threaded_irq(&pdev->dev, tsdev->irq, NULL,
|
||||
mrstouch_pendet_irq, IRQF_ONESHOT,
|
||||
"mrstouch", tsdev);
|
||||
if (err) {
|
||||
dev_err(tsdev->dev, "unable to allocate irq\n");
|
||||
goto err_free_mem;
|
||||
return err;
|
||||
}
|
||||
|
||||
err = input_register_device(tsdev->input);
|
||||
if (err) {
|
||||
dev_err(tsdev->dev, "unable to register input device\n");
|
||||
goto err_free_irq;
|
||||
return err;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, tsdev);
|
||||
return 0;
|
||||
|
||||
err_free_irq:
|
||||
free_irq(tsdev->irq, tsdev);
|
||||
err_free_mem:
|
||||
input_free_device(input);
|
||||
kfree(tsdev);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int mrstouch_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct mrstouch_dev *tsdev = platform_get_drvdata(pdev);
|
||||
|
||||
free_irq(tsdev->irq, tsdev);
|
||||
input_unregister_device(tsdev->input);
|
||||
kfree(tsdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -659,7 +647,6 @@ static struct platform_driver mrstouch_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = mrstouch_probe,
|
||||
.remove = mrstouch_remove,
|
||||
};
|
||||
module_platform_driver(mrstouch_driver);
|
||||
|
||||
|
@ -384,7 +384,7 @@ static const struct dev_pm_ops lpc32xx_ts_pm_ops = {
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static struct of_device_id lpc32xx_tsc_of_match[] = {
|
||||
static const struct of_device_id lpc32xx_tsc_of_match[] = {
|
||||
{ .compatible = "nxp,lpc3220-tsc", },
|
||||
{ },
|
||||
};
|
||||
|
@ -161,10 +161,9 @@ static irqreturn_t mcs5000_ts_interrupt(int irq, void *dev_id)
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static void mcs5000_ts_phys_init(struct mcs5000_ts_data *data)
|
||||
static void mcs5000_ts_phys_init(struct mcs5000_ts_data *data,
|
||||
const struct mcs_platform_data *platform_data)
|
||||
{
|
||||
const struct mcs_platform_data *platform_data =
|
||||
data->platform_data;
|
||||
struct i2c_client *client = data->client;
|
||||
|
||||
/* Touch reset & sleep mode */
|
||||
@ -187,28 +186,32 @@ static void mcs5000_ts_phys_init(struct mcs5000_ts_data *data)
|
||||
}
|
||||
|
||||
static int mcs5000_ts_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
const struct mcs_platform_data *pdata;
|
||||
struct mcs5000_ts_data *data;
|
||||
struct input_dev *input_dev;
|
||||
int ret;
|
||||
int error;
|
||||
|
||||
if (!dev_get_platdata(&client->dev))
|
||||
pdata = dev_get_platdata(&client->dev);
|
||||
if (!pdata)
|
||||
return -EINVAL;
|
||||
|
||||
data = kzalloc(sizeof(struct mcs5000_ts_data), GFP_KERNEL);
|
||||
input_dev = input_allocate_device();
|
||||
if (!data || !input_dev) {
|
||||
data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
|
||||
if (!data) {
|
||||
dev_err(&client->dev, "Failed to allocate memory\n");
|
||||
ret = -ENOMEM;
|
||||
goto err_free_mem;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
data->client = client;
|
||||
data->input_dev = input_dev;
|
||||
data->platform_data = dev_get_platdata(&client->dev);
|
||||
|
||||
input_dev->name = "MELPAS MCS-5000 Touchscreen";
|
||||
input_dev = devm_input_allocate_device(&client->dev);
|
||||
if (!input_dev) {
|
||||
dev_err(&client->dev, "Failed to allocate input device\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
input_dev->name = "MELFAS MCS-5000 Touchscreen";
|
||||
input_dev->id.bustype = BUS_I2C;
|
||||
input_dev->dev.parent = &client->dev;
|
||||
|
||||
@ -219,43 +222,29 @@ static int mcs5000_ts_probe(struct i2c_client *client,
|
||||
input_set_abs_params(input_dev, ABS_Y, 0, MCS5000_MAX_YC, 0, 0);
|
||||
|
||||
input_set_drvdata(input_dev, data);
|
||||
data->input_dev = input_dev;
|
||||
|
||||
if (data->platform_data->cfg_pin)
|
||||
data->platform_data->cfg_pin();
|
||||
if (pdata->cfg_pin)
|
||||
pdata->cfg_pin();
|
||||
|
||||
ret = request_threaded_irq(client->irq, NULL, mcs5000_ts_interrupt,
|
||||
IRQF_TRIGGER_LOW | IRQF_ONESHOT, "mcs5000_ts", data);
|
||||
|
||||
if (ret < 0) {
|
||||
error = devm_request_threaded_irq(&client->dev, client->irq,
|
||||
NULL, mcs5000_ts_interrupt,
|
||||
IRQF_TRIGGER_LOW | IRQF_ONESHOT,
|
||||
"mcs5000_ts", data);
|
||||
if (error) {
|
||||
dev_err(&client->dev, "Failed to register interrupt\n");
|
||||
goto err_free_mem;
|
||||
return error;
|
||||
}
|
||||
|
||||
ret = input_register_device(data->input_dev);
|
||||
if (ret < 0)
|
||||
goto err_free_irq;
|
||||
error = input_register_device(data->input_dev);
|
||||
if (error) {
|
||||
dev_err(&client->dev, "Failed to register input device\n");
|
||||
return error;
|
||||
}
|
||||
|
||||
mcs5000_ts_phys_init(data);
|
||||
mcs5000_ts_phys_init(data, pdata);
|
||||
i2c_set_clientdata(client, data);
|
||||
|
||||
return 0;
|
||||
|
||||
err_free_irq:
|
||||
free_irq(client->irq, data);
|
||||
err_free_mem:
|
||||
input_free_device(input_dev);
|
||||
kfree(data);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mcs5000_ts_remove(struct i2c_client *client)
|
||||
{
|
||||
struct mcs5000_ts_data *data = i2c_get_clientdata(client);
|
||||
|
||||
free_irq(client->irq, data);
|
||||
input_unregister_device(data->input_dev);
|
||||
kfree(data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -274,14 +263,15 @@ static int mcs5000_ts_resume(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct mcs5000_ts_data *data = i2c_get_clientdata(client);
|
||||
const struct mcs_platform_data *pdata = dev_get_platdata(dev);
|
||||
|
||||
mcs5000_ts_phys_init(data);
|
||||
mcs5000_ts_phys_init(data, pdata);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(mcs5000_ts_pm, mcs5000_ts_suspend, mcs5000_ts_resume);
|
||||
#endif
|
||||
|
||||
static const struct i2c_device_id mcs5000_ts_id[] = {
|
||||
{ "mcs5000_ts", 0 },
|
||||
@ -291,12 +281,9 @@ MODULE_DEVICE_TABLE(i2c, mcs5000_ts_id);
|
||||
|
||||
static struct i2c_driver mcs5000_ts_driver = {
|
||||
.probe = mcs5000_ts_probe,
|
||||
.remove = mcs5000_ts_remove,
|
||||
.driver = {
|
||||
.name = "mcs5000_ts",
|
||||
#ifdef CONFIG_PM
|
||||
.pm = &mcs5000_ts_pm,
|
||||
#endif
|
||||
},
|
||||
.id_table = mcs5000_ts_id,
|
||||
};
|
||||
|
@ -456,7 +456,7 @@ static int mms114_probe(struct i2c_client *client,
|
||||
data->input_dev = input_dev;
|
||||
data->pdata = pdata;
|
||||
|
||||
input_dev->name = "MELPAS MMS114 Touchscreen";
|
||||
input_dev->name = "MELFAS MMS114 Touchscreen";
|
||||
input_dev->id.bustype = BUS_I2C;
|
||||
input_dev->dev.parent = &client->dev;
|
||||
input_dev->open = mms114_input_open;
|
||||
@ -570,7 +570,7 @@ static const struct i2c_device_id mms114_id[] = {
|
||||
MODULE_DEVICE_TABLE(i2c, mms114_id);
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static struct of_device_id mms114_dt_match[] = {
|
||||
static const struct of_device_id mms114_dt_match[] = {
|
||||
{ .compatible = "melfas,mms114" },
|
||||
{ }
|
||||
};
|
||||
|
45
drivers/input/touchscreen/of_touchscreen.c
Normal file
45
drivers/input/touchscreen/of_touchscreen.c
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Generic DT helper functions for touchscreen devices
|
||||
*
|
||||
* Copyright (c) 2014 Sebastian Reichel <sre@kernel.org>
|
||||
*
|
||||
* 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/of.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/input/touchscreen.h>
|
||||
|
||||
/**
|
||||
* touchscreen_parse_of_params - parse common touchscreen DT properties
|
||||
* @dev: device that should be parsed
|
||||
*
|
||||
* This function parses common DT properties for touchscreens and setups the
|
||||
* input device accordingly. The function keeps previously setuped default
|
||||
* values if no value is specified via DT.
|
||||
*/
|
||||
void touchscreen_parse_of_params(struct input_dev *dev)
|
||||
{
|
||||
struct device_node *np = dev->dev.parent->of_node;
|
||||
struct input_absinfo *absinfo;
|
||||
|
||||
input_alloc_absinfo(dev);
|
||||
if (!dev->absinfo)
|
||||
return;
|
||||
|
||||
absinfo = &dev->absinfo[ABS_X];
|
||||
of_property_read_u32(np, "touchscreen-size-x", &absinfo->maximum);
|
||||
of_property_read_u32(np, "touchscreen-fuzz-x", &absinfo->fuzz);
|
||||
|
||||
absinfo = &dev->absinfo[ABS_Y];
|
||||
of_property_read_u32(np, "touchscreen-size-y", &absinfo->maximum);
|
||||
of_property_read_u32(np, "touchscreen-fuzz-y", &absinfo->fuzz);
|
||||
|
||||
absinfo = &dev->absinfo[ABS_PRESSURE];
|
||||
of_property_read_u32(np, "touchscreen-max-pressure", &absinfo->maximum);
|
||||
of_property_read_u32(np, "touchscreen-fuzz-pressure", &absinfo->fuzz);
|
||||
}
|
||||
EXPORT_SYMBOL(touchscreen_parse_of_params);
|
@ -24,12 +24,13 @@
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/input/pixcir_ts.h>
|
||||
#include <linux/gpio.h>
|
||||
|
||||
struct pixcir_i2c_ts_data {
|
||||
struct i2c_client *client;
|
||||
struct input_dev *input;
|
||||
const struct pixcir_ts_platform_data *chip;
|
||||
bool exiting;
|
||||
bool running;
|
||||
};
|
||||
|
||||
static void pixcir_ts_poscheck(struct pixcir_i2c_ts_data *data)
|
||||
@ -87,11 +88,12 @@ static void pixcir_ts_poscheck(struct pixcir_i2c_ts_data *data)
|
||||
static irqreturn_t pixcir_ts_isr(int irq, void *dev_id)
|
||||
{
|
||||
struct pixcir_i2c_ts_data *tsdata = dev_id;
|
||||
const struct pixcir_ts_platform_data *pdata = tsdata->chip;
|
||||
|
||||
while (!tsdata->exiting) {
|
||||
while (tsdata->running) {
|
||||
pixcir_ts_poscheck(tsdata);
|
||||
|
||||
if (tsdata->chip->attb_read_val())
|
||||
if (gpio_get_value(pdata->gpio_attb))
|
||||
break;
|
||||
|
||||
msleep(20);
|
||||
@ -100,25 +102,221 @@ static irqreturn_t pixcir_ts_isr(int irq, void *dev_id)
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int pixcir_set_power_mode(struct pixcir_i2c_ts_data *ts,
|
||||
enum pixcir_power_mode mode)
|
||||
{
|
||||
struct device *dev = &ts->client->dev;
|
||||
int ret;
|
||||
|
||||
ret = i2c_smbus_read_byte_data(ts->client, PIXCIR_REG_POWER_MODE);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "%s: can't read reg 0x%x : %d\n",
|
||||
__func__, PIXCIR_REG_POWER_MODE, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret &= ~PIXCIR_POWER_MODE_MASK;
|
||||
ret |= mode;
|
||||
|
||||
/* Always AUTO_IDLE */
|
||||
ret |= PIXCIR_POWER_ALLOW_IDLE;
|
||||
|
||||
ret = i2c_smbus_write_byte_data(ts->client, PIXCIR_REG_POWER_MODE, ret);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "%s: can't write reg 0x%x : %d\n",
|
||||
__func__, PIXCIR_REG_POWER_MODE, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the interrupt mode for the device i.e. ATTB line behaviour
|
||||
*
|
||||
* @polarity : 1 for active high, 0 for active low.
|
||||
*/
|
||||
static int pixcir_set_int_mode(struct pixcir_i2c_ts_data *ts,
|
||||
enum pixcir_int_mode mode, bool polarity)
|
||||
{
|
||||
struct device *dev = &ts->client->dev;
|
||||
int ret;
|
||||
|
||||
ret = i2c_smbus_read_byte_data(ts->client, PIXCIR_REG_INT_MODE);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "%s: can't read reg 0x%x : %d\n",
|
||||
__func__, PIXCIR_REG_INT_MODE, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret &= ~PIXCIR_INT_MODE_MASK;
|
||||
ret |= mode;
|
||||
|
||||
if (polarity)
|
||||
ret |= PIXCIR_INT_POL_HIGH;
|
||||
else
|
||||
ret &= ~PIXCIR_INT_POL_HIGH;
|
||||
|
||||
ret = i2c_smbus_write_byte_data(ts->client, PIXCIR_REG_INT_MODE, ret);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "%s: can't write reg 0x%x : %d\n",
|
||||
__func__, PIXCIR_REG_INT_MODE, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Enable/disable interrupt generation
|
||||
*/
|
||||
static int pixcir_int_enable(struct pixcir_i2c_ts_data *ts, bool enable)
|
||||
{
|
||||
struct device *dev = &ts->client->dev;
|
||||
int ret;
|
||||
|
||||
ret = i2c_smbus_read_byte_data(ts->client, PIXCIR_REG_INT_MODE);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "%s: can't read reg 0x%x : %d\n",
|
||||
__func__, PIXCIR_REG_INT_MODE, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (enable)
|
||||
ret |= PIXCIR_INT_ENABLE;
|
||||
else
|
||||
ret &= ~PIXCIR_INT_ENABLE;
|
||||
|
||||
ret = i2c_smbus_write_byte_data(ts->client, PIXCIR_REG_INT_MODE, ret);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "%s: can't write reg 0x%x : %d\n",
|
||||
__func__, PIXCIR_REG_INT_MODE, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pixcir_start(struct pixcir_i2c_ts_data *ts)
|
||||
{
|
||||
struct device *dev = &ts->client->dev;
|
||||
int error;
|
||||
|
||||
/* LEVEL_TOUCH interrupt with active low polarity */
|
||||
error = pixcir_set_int_mode(ts, PIXCIR_INT_LEVEL_TOUCH, 0);
|
||||
if (error) {
|
||||
dev_err(dev, "Failed to set interrupt mode: %d\n", error);
|
||||
return error;
|
||||
}
|
||||
|
||||
ts->running = true;
|
||||
mb(); /* Update status before IRQ can fire */
|
||||
|
||||
/* enable interrupt generation */
|
||||
error = pixcir_int_enable(ts, true);
|
||||
if (error) {
|
||||
dev_err(dev, "Failed to enable interrupt generation: %d\n",
|
||||
error);
|
||||
return error;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pixcir_stop(struct pixcir_i2c_ts_data *ts)
|
||||
{
|
||||
int error;
|
||||
|
||||
/* Disable interrupt generation */
|
||||
error = pixcir_int_enable(ts, false);
|
||||
if (error) {
|
||||
dev_err(&ts->client->dev,
|
||||
"Failed to disable interrupt generation: %d\n",
|
||||
error);
|
||||
return error;
|
||||
}
|
||||
|
||||
/* Exit ISR if running, no more report parsing */
|
||||
ts->running = false;
|
||||
mb(); /* update status before we synchronize irq */
|
||||
|
||||
/* Wait till running ISR is complete */
|
||||
synchronize_irq(ts->client->irq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pixcir_input_open(struct input_dev *dev)
|
||||
{
|
||||
struct pixcir_i2c_ts_data *ts = input_get_drvdata(dev);
|
||||
|
||||
return pixcir_start(ts);
|
||||
}
|
||||
|
||||
static void pixcir_input_close(struct input_dev *dev)
|
||||
{
|
||||
struct pixcir_i2c_ts_data *ts = input_get_drvdata(dev);
|
||||
|
||||
pixcir_stop(ts);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int pixcir_i2c_ts_suspend(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct pixcir_i2c_ts_data *ts = i2c_get_clientdata(client);
|
||||
struct input_dev *input = ts->input;
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&input->mutex);
|
||||
|
||||
if (device_may_wakeup(&client->dev)) {
|
||||
if (!input->users) {
|
||||
ret = pixcir_start(ts);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to start\n");
|
||||
goto unlock;
|
||||
}
|
||||
}
|
||||
|
||||
if (device_may_wakeup(&client->dev))
|
||||
enable_irq_wake(client->irq);
|
||||
} else if (input->users) {
|
||||
ret = pixcir_stop(ts);
|
||||
}
|
||||
|
||||
return 0;
|
||||
unlock:
|
||||
mutex_unlock(&input->mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int pixcir_i2c_ts_resume(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct pixcir_i2c_ts_data *ts = i2c_get_clientdata(client);
|
||||
struct input_dev *input = ts->input;
|
||||
int ret = 0;
|
||||
|
||||
if (device_may_wakeup(&client->dev))
|
||||
mutex_lock(&input->mutex);
|
||||
|
||||
if (device_may_wakeup(&client->dev)) {
|
||||
disable_irq_wake(client->irq);
|
||||
|
||||
return 0;
|
||||
if (!input->users) {
|
||||
ret = pixcir_stop(ts);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to stop\n");
|
||||
goto unlock;
|
||||
}
|
||||
}
|
||||
} else if (input->users) {
|
||||
ret = pixcir_start(ts);
|
||||
}
|
||||
|
||||
unlock:
|
||||
mutex_unlock(&input->mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -130,6 +328,7 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client,
|
||||
{
|
||||
const struct pixcir_ts_platform_data *pdata =
|
||||
dev_get_platdata(&client->dev);
|
||||
struct device *dev = &client->dev;
|
||||
struct pixcir_i2c_ts_data *tsdata;
|
||||
struct input_dev *input;
|
||||
int error;
|
||||
@ -139,12 +338,19 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
tsdata = kzalloc(sizeof(*tsdata), GFP_KERNEL);
|
||||
input = input_allocate_device();
|
||||
if (!tsdata || !input) {
|
||||
dev_err(&client->dev, "Failed to allocate driver data!\n");
|
||||
error = -ENOMEM;
|
||||
goto err_free_mem;
|
||||
if (!gpio_is_valid(pdata->gpio_attb)) {
|
||||
dev_err(dev, "Invalid gpio_attb in pdata\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
tsdata = devm_kzalloc(dev, sizeof(*tsdata), GFP_KERNEL);
|
||||
if (!tsdata)
|
||||
return -ENOMEM;
|
||||
|
||||
input = devm_input_allocate_device(dev);
|
||||
if (!input) {
|
||||
dev_err(dev, "Failed to allocate input device\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
tsdata->client = client;
|
||||
@ -153,6 +359,8 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client,
|
||||
|
||||
input->name = client->name;
|
||||
input->id.bustype = BUS_I2C;
|
||||
input->open = pixcir_input_open;
|
||||
input->close = pixcir_input_close;
|
||||
input->dev.parent = &client->dev;
|
||||
|
||||
__set_bit(EV_KEY, input->evbit);
|
||||
@ -165,44 +373,47 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client,
|
||||
|
||||
input_set_drvdata(input, tsdata);
|
||||
|
||||
error = request_threaded_irq(client->irq, NULL, pixcir_ts_isr,
|
||||
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
|
||||
client->name, tsdata);
|
||||
error = devm_gpio_request_one(dev, pdata->gpio_attb,
|
||||
GPIOF_DIR_IN, "pixcir_i2c_attb");
|
||||
if (error) {
|
||||
dev_err(&client->dev, "Unable to request touchscreen IRQ.\n");
|
||||
goto err_free_mem;
|
||||
dev_err(dev, "Failed to request ATTB gpio\n");
|
||||
return error;
|
||||
}
|
||||
|
||||
error = devm_request_threaded_irq(dev, client->irq, NULL, pixcir_ts_isr,
|
||||
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
|
||||
client->name, tsdata);
|
||||
if (error) {
|
||||
dev_err(dev, "failed to request irq %d\n", client->irq);
|
||||
return error;
|
||||
}
|
||||
|
||||
/* Always be in IDLE mode to save power, device supports auto wake */
|
||||
error = pixcir_set_power_mode(tsdata, PIXCIR_POWER_IDLE);
|
||||
if (error) {
|
||||
dev_err(dev, "Failed to set IDLE mode\n");
|
||||
return error;
|
||||
}
|
||||
|
||||
/* Stop device till opened */
|
||||
error = pixcir_stop(tsdata);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
error = input_register_device(input);
|
||||
if (error)
|
||||
goto err_free_irq;
|
||||
return error;
|
||||
|
||||
i2c_set_clientdata(client, tsdata);
|
||||
device_init_wakeup(&client->dev, 1);
|
||||
|
||||
return 0;
|
||||
|
||||
err_free_irq:
|
||||
free_irq(client->irq, tsdata);
|
||||
err_free_mem:
|
||||
input_free_device(input);
|
||||
kfree(tsdata);
|
||||
return error;
|
||||
}
|
||||
|
||||
static int pixcir_i2c_ts_remove(struct i2c_client *client)
|
||||
{
|
||||
struct pixcir_i2c_ts_data *tsdata = i2c_get_clientdata(client);
|
||||
|
||||
device_init_wakeup(&client->dev, 0);
|
||||
|
||||
tsdata->exiting = true;
|
||||
mb();
|
||||
free_irq(client->irq, tsdata);
|
||||
|
||||
input_unregister_device(tsdata->input);
|
||||
kfree(tsdata);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
339
drivers/input/touchscreen/sun4i-ts.c
Normal file
339
drivers/input/touchscreen/sun4i-ts.c
Normal file
@ -0,0 +1,339 @@
|
||||
/*
|
||||
* Allwinner sunxi resistive touchscreen controller driver
|
||||
*
|
||||
* Copyright (C) 2013 - 2014 Hans de Goede <hdegoede@redhat.com>
|
||||
*
|
||||
* The hwmon parts are based on work by Corentin LABBE which is:
|
||||
* Copyright (C) 2013 Corentin LABBE <clabbe.montjoie@gmail.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.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The sun4i-ts controller is capable of detecting a second touch, but when a
|
||||
* second touch is present then the accuracy becomes so bad the reported touch
|
||||
* location is not useable.
|
||||
*
|
||||
* The original android driver contains some complicated heuristics using the
|
||||
* aprox. distance between the 2 touches to see if the user is making a pinch
|
||||
* open / close movement, and then reports emulated multi-touch events around
|
||||
* the last touch coordinate (as the dual-touch coordinates are worthless).
|
||||
*
|
||||
* These kinds of heuristics are just asking for trouble (and don't belong
|
||||
* in the kernel). So this driver offers straight forward, reliable single
|
||||
* touch functionality only.
|
||||
*/
|
||||
|
||||
#include <linux/err.h>
|
||||
#include <linux/hwmon.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#define TP_CTRL0 0x00
|
||||
#define TP_CTRL1 0x04
|
||||
#define TP_CTRL2 0x08
|
||||
#define TP_CTRL3 0x0c
|
||||
#define TP_INT_FIFOC 0x10
|
||||
#define TP_INT_FIFOS 0x14
|
||||
#define TP_TPR 0x18
|
||||
#define TP_CDAT 0x1c
|
||||
#define TEMP_DATA 0x20
|
||||
#define TP_DATA 0x24
|
||||
|
||||
/* TP_CTRL0 bits */
|
||||
#define ADC_FIRST_DLY(x) ((x) << 24) /* 8 bits */
|
||||
#define ADC_FIRST_DLY_MODE(x) ((x) << 23)
|
||||
#define ADC_CLK_SEL(x) ((x) << 22)
|
||||
#define ADC_CLK_DIV(x) ((x) << 20) /* 3 bits */
|
||||
#define FS_DIV(x) ((x) << 16) /* 4 bits */
|
||||
#define T_ACQ(x) ((x) << 0) /* 16 bits */
|
||||
|
||||
/* TP_CTRL1 bits */
|
||||
#define STYLUS_UP_DEBOUN(x) ((x) << 12) /* 8 bits */
|
||||
#define STYLUS_UP_DEBOUN_EN(x) ((x) << 9)
|
||||
#define TOUCH_PAN_CALI_EN(x) ((x) << 6)
|
||||
#define TP_DUAL_EN(x) ((x) << 5)
|
||||
#define TP_MODE_EN(x) ((x) << 4)
|
||||
#define TP_ADC_SELECT(x) ((x) << 3)
|
||||
#define ADC_CHAN_SELECT(x) ((x) << 0) /* 3 bits */
|
||||
|
||||
/* TP_CTRL2 bits */
|
||||
#define TP_SENSITIVE_ADJUST(x) ((x) << 28) /* 4 bits */
|
||||
#define TP_MODE_SELECT(x) ((x) << 26) /* 2 bits */
|
||||
#define PRE_MEA_EN(x) ((x) << 24)
|
||||
#define PRE_MEA_THRE_CNT(x) ((x) << 0) /* 24 bits */
|
||||
|
||||
/* TP_CTRL3 bits */
|
||||
#define FILTER_EN(x) ((x) << 2)
|
||||
#define FILTER_TYPE(x) ((x) << 0) /* 2 bits */
|
||||
|
||||
/* TP_INT_FIFOC irq and fifo mask / control bits */
|
||||
#define TEMP_IRQ_EN(x) ((x) << 18)
|
||||
#define OVERRUN_IRQ_EN(x) ((x) << 17)
|
||||
#define DATA_IRQ_EN(x) ((x) << 16)
|
||||
#define TP_DATA_XY_CHANGE(x) ((x) << 13)
|
||||
#define FIFO_TRIG(x) ((x) << 8) /* 5 bits */
|
||||
#define DATA_DRQ_EN(x) ((x) << 7)
|
||||
#define FIFO_FLUSH(x) ((x) << 4)
|
||||
#define TP_UP_IRQ_EN(x) ((x) << 1)
|
||||
#define TP_DOWN_IRQ_EN(x) ((x) << 0)
|
||||
|
||||
/* TP_INT_FIFOS irq and fifo status bits */
|
||||
#define TEMP_DATA_PENDING BIT(18)
|
||||
#define FIFO_OVERRUN_PENDING BIT(17)
|
||||
#define FIFO_DATA_PENDING BIT(16)
|
||||
#define TP_IDLE_FLG BIT(2)
|
||||
#define TP_UP_PENDING BIT(1)
|
||||
#define TP_DOWN_PENDING BIT(0)
|
||||
|
||||
/* TP_TPR bits */
|
||||
#define TEMP_ENABLE(x) ((x) << 16)
|
||||
#define TEMP_PERIOD(x) ((x) << 0) /* t = x * 256 * 16 / clkin */
|
||||
|
||||
struct sun4i_ts_data {
|
||||
struct device *dev;
|
||||
struct input_dev *input;
|
||||
void __iomem *base;
|
||||
unsigned int irq;
|
||||
bool ignore_fifo_data;
|
||||
int temp_data;
|
||||
};
|
||||
|
||||
static void sun4i_ts_irq_handle_input(struct sun4i_ts_data *ts, u32 reg_val)
|
||||
{
|
||||
u32 x, y;
|
||||
|
||||
if (reg_val & FIFO_DATA_PENDING) {
|
||||
x = readl(ts->base + TP_DATA);
|
||||
y = readl(ts->base + TP_DATA);
|
||||
/* The 1st location reported after an up event is unreliable */
|
||||
if (!ts->ignore_fifo_data) {
|
||||
input_report_abs(ts->input, ABS_X, x);
|
||||
input_report_abs(ts->input, ABS_Y, y);
|
||||
/*
|
||||
* The hardware has a separate down status bit, but
|
||||
* that gets set before we get the first location,
|
||||
* resulting in reporting a click on the old location.
|
||||
*/
|
||||
input_report_key(ts->input, BTN_TOUCH, 1);
|
||||
input_sync(ts->input);
|
||||
} else {
|
||||
ts->ignore_fifo_data = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (reg_val & TP_UP_PENDING) {
|
||||
ts->ignore_fifo_data = true;
|
||||
input_report_key(ts->input, BTN_TOUCH, 0);
|
||||
input_sync(ts->input);
|
||||
}
|
||||
}
|
||||
|
||||
static irqreturn_t sun4i_ts_irq(int irq, void *dev_id)
|
||||
{
|
||||
struct sun4i_ts_data *ts = dev_id;
|
||||
u32 reg_val;
|
||||
|
||||
reg_val = readl(ts->base + TP_INT_FIFOS);
|
||||
|
||||
if (reg_val & TEMP_DATA_PENDING)
|
||||
ts->temp_data = readl(ts->base + TEMP_DATA);
|
||||
|
||||
if (ts->input)
|
||||
sun4i_ts_irq_handle_input(ts, reg_val);
|
||||
|
||||
writel(reg_val, ts->base + TP_INT_FIFOS);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int sun4i_ts_open(struct input_dev *dev)
|
||||
{
|
||||
struct sun4i_ts_data *ts = input_get_drvdata(dev);
|
||||
|
||||
/* Flush, set trig level to 1, enable temp, data and up irqs */
|
||||
writel(TEMP_IRQ_EN(1) | DATA_IRQ_EN(1) | FIFO_TRIG(1) | FIFO_FLUSH(1) |
|
||||
TP_UP_IRQ_EN(1), ts->base + TP_INT_FIFOC);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sun4i_ts_close(struct input_dev *dev)
|
||||
{
|
||||
struct sun4i_ts_data *ts = input_get_drvdata(dev);
|
||||
|
||||
/* Deactivate all input IRQs */
|
||||
writel(TEMP_IRQ_EN(1), ts->base + TP_INT_FIFOC);
|
||||
}
|
||||
|
||||
static ssize_t show_temp(struct device *dev, struct device_attribute *devattr,
|
||||
char *buf)
|
||||
{
|
||||
struct sun4i_ts_data *ts = dev_get_drvdata(dev);
|
||||
|
||||
/* No temp_data until the first irq */
|
||||
if (ts->temp_data == -1)
|
||||
return -EAGAIN;
|
||||
|
||||
return sprintf(buf, "%d\n", (ts->temp_data - 1447) * 100);
|
||||
}
|
||||
|
||||
static ssize_t show_temp_label(struct device *dev,
|
||||
struct device_attribute *devattr, char *buf)
|
||||
{
|
||||
return sprintf(buf, "SoC temperature\n");
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL);
|
||||
static DEVICE_ATTR(temp1_label, S_IRUGO, show_temp_label, NULL);
|
||||
|
||||
static struct attribute *sun4i_ts_attrs[] = {
|
||||
&dev_attr_temp1_input.attr,
|
||||
&dev_attr_temp1_label.attr,
|
||||
NULL
|
||||
};
|
||||
ATTRIBUTE_GROUPS(sun4i_ts);
|
||||
|
||||
static int sun4i_ts_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct sun4i_ts_data *ts;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *np = dev->of_node;
|
||||
struct device *hwmon;
|
||||
int error;
|
||||
bool ts_attached;
|
||||
|
||||
ts = devm_kzalloc(dev, sizeof(struct sun4i_ts_data), GFP_KERNEL);
|
||||
if (!ts)
|
||||
return -ENOMEM;
|
||||
|
||||
ts->dev = dev;
|
||||
ts->ignore_fifo_data = true;
|
||||
ts->temp_data = -1;
|
||||
|
||||
ts_attached = of_property_read_bool(np, "allwinner,ts-attached");
|
||||
if (ts_attached) {
|
||||
ts->input = devm_input_allocate_device(dev);
|
||||
if (!ts->input)
|
||||
return -ENOMEM;
|
||||
|
||||
ts->input->name = pdev->name;
|
||||
ts->input->phys = "sun4i_ts/input0";
|
||||
ts->input->open = sun4i_ts_open;
|
||||
ts->input->close = sun4i_ts_close;
|
||||
ts->input->id.bustype = BUS_HOST;
|
||||
ts->input->id.vendor = 0x0001;
|
||||
ts->input->id.product = 0x0001;
|
||||
ts->input->id.version = 0x0100;
|
||||
ts->input->evbit[0] = BIT(EV_SYN) | BIT(EV_KEY) | BIT(EV_ABS);
|
||||
__set_bit(BTN_TOUCH, ts->input->keybit);
|
||||
input_set_abs_params(ts->input, ABS_X, 0, 4095, 0, 0);
|
||||
input_set_abs_params(ts->input, ABS_Y, 0, 4095, 0, 0);
|
||||
input_set_drvdata(ts->input, ts);
|
||||
}
|
||||
|
||||
ts->base = devm_ioremap_resource(dev,
|
||||
platform_get_resource(pdev, IORESOURCE_MEM, 0));
|
||||
if (IS_ERR(ts->base))
|
||||
return PTR_ERR(ts->base);
|
||||
|
||||
ts->irq = platform_get_irq(pdev, 0);
|
||||
error = devm_request_irq(dev, ts->irq, sun4i_ts_irq, 0, "sun4i-ts", ts);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
/*
|
||||
* Select HOSC clk, clkin = clk / 6, adc samplefreq = clkin / 8192,
|
||||
* t_acq = clkin / (16 * 64)
|
||||
*/
|
||||
writel(ADC_CLK_SEL(0) | ADC_CLK_DIV(2) | FS_DIV(7) | T_ACQ(63),
|
||||
ts->base + TP_CTRL0);
|
||||
|
||||
/*
|
||||
* sensitive_adjust = 15 : max, which is not all that sensitive,
|
||||
* tp_mode = 0 : only x and y coordinates, as we don't use dual touch
|
||||
*/
|
||||
writel(TP_SENSITIVE_ADJUST(15) | TP_MODE_SELECT(0),
|
||||
ts->base + TP_CTRL2);
|
||||
|
||||
/* Enable median filter, type 1 : 5/3 */
|
||||
writel(FILTER_EN(1) | FILTER_TYPE(1), ts->base + TP_CTRL3);
|
||||
|
||||
/* Enable temperature measurement, period 1953 (2 seconds) */
|
||||
writel(TEMP_ENABLE(1) | TEMP_PERIOD(1953), ts->base + TP_TPR);
|
||||
|
||||
/*
|
||||
* Set stylus up debounce to aprox 10 ms, enable debounce, and
|
||||
* finally enable tp mode.
|
||||
*/
|
||||
writel(STYLUS_UP_DEBOUN(5) | STYLUS_UP_DEBOUN_EN(1) | TP_MODE_EN(1),
|
||||
ts->base + TP_CTRL1);
|
||||
|
||||
hwmon = devm_hwmon_device_register_with_groups(ts->dev, "sun4i_ts",
|
||||
ts, sun4i_ts_groups);
|
||||
if (IS_ERR(hwmon))
|
||||
return PTR_ERR(hwmon);
|
||||
|
||||
writel(TEMP_IRQ_EN(1), ts->base + TP_INT_FIFOC);
|
||||
|
||||
if (ts_attached) {
|
||||
error = input_register_device(ts->input);
|
||||
if (error) {
|
||||
writel(0, ts->base + TP_INT_FIFOC);
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, ts);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sun4i_ts_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct sun4i_ts_data *ts = platform_get_drvdata(pdev);
|
||||
|
||||
/* Explicit unregister to avoid open/close changing the imask later */
|
||||
if (ts->input)
|
||||
input_unregister_device(ts->input);
|
||||
|
||||
/* Deactivate all IRQs */
|
||||
writel(0, ts->base + TP_INT_FIFOC);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id sun4i_ts_of_match[] = {
|
||||
{ .compatible = "allwinner,sun4i-a10-ts", },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, sun4i_ts_of_match);
|
||||
|
||||
static struct platform_driver sun4i_ts_driver = {
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "sun4i-ts",
|
||||
.of_match_table = of_match_ptr(sun4i_ts_of_match),
|
||||
},
|
||||
.probe = sun4i_ts_probe,
|
||||
.remove = sun4i_ts_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(sun4i_ts_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Allwinner sun4i resistive touchscreen controller driver");
|
||||
MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
|
||||
MODULE_LICENSE("GPL");
|
@ -25,11 +25,15 @@
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/input/touchscreen.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/spi/tsc2005.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
|
||||
/*
|
||||
* The touchscreen interface operates as follows:
|
||||
@ -100,6 +104,11 @@
|
||||
TSC2005_CFR2_AVG_7)
|
||||
|
||||
#define MAX_12BIT 0xfff
|
||||
#define TSC2005_DEF_X_FUZZ 4
|
||||
#define TSC2005_DEF_Y_FUZZ 8
|
||||
#define TSC2005_DEF_P_FUZZ 2
|
||||
#define TSC2005_DEF_RESISTOR 280
|
||||
|
||||
#define TSC2005_SPI_MAX_SPEED_HZ 10000000
|
||||
#define TSC2005_PENUP_TIME_MS 40
|
||||
|
||||
@ -143,6 +152,9 @@ struct tsc2005 {
|
||||
|
||||
bool pen_down;
|
||||
|
||||
struct regulator *vio;
|
||||
|
||||
int reset_gpio;
|
||||
void (*set_reset)(bool enable);
|
||||
};
|
||||
|
||||
@ -337,6 +349,14 @@ static void tsc2005_stop_scan(struct tsc2005 *ts)
|
||||
tsc2005_cmd(ts, TSC2005_CMD_STOP);
|
||||
}
|
||||
|
||||
static void tsc2005_set_reset(struct tsc2005 *ts, bool enable)
|
||||
{
|
||||
if (ts->reset_gpio >= 0)
|
||||
gpio_set_value(ts->reset_gpio, enable);
|
||||
else if (ts->set_reset)
|
||||
ts->set_reset(enable);
|
||||
}
|
||||
|
||||
/* must be called with ts->mutex held */
|
||||
static void __tsc2005_disable(struct tsc2005 *ts)
|
||||
{
|
||||
@ -355,7 +375,7 @@ static void __tsc2005_enable(struct tsc2005 *ts)
|
||||
{
|
||||
tsc2005_start_scan(ts);
|
||||
|
||||
if (ts->esd_timeout && ts->set_reset) {
|
||||
if (ts->esd_timeout && (ts->set_reset || ts->reset_gpio)) {
|
||||
ts->last_valid_interrupt = jiffies;
|
||||
schedule_delayed_work(&ts->esd_work,
|
||||
round_jiffies_relative(
|
||||
@ -414,9 +434,9 @@ static ssize_t tsc2005_selftest_show(struct device *dev,
|
||||
}
|
||||
|
||||
/* hardware reset */
|
||||
ts->set_reset(false);
|
||||
tsc2005_set_reset(ts, false);
|
||||
usleep_range(100, 500); /* only 10us required */
|
||||
ts->set_reset(true);
|
||||
tsc2005_set_reset(ts, true);
|
||||
|
||||
if (!success)
|
||||
goto out;
|
||||
@ -459,7 +479,7 @@ static umode_t tsc2005_attr_is_visible(struct kobject *kobj,
|
||||
umode_t mode = attr->mode;
|
||||
|
||||
if (attr == &dev_attr_selftest.attr) {
|
||||
if (!ts->set_reset)
|
||||
if (!ts->set_reset && !ts->reset_gpio)
|
||||
mode = 0;
|
||||
}
|
||||
|
||||
@ -509,9 +529,9 @@ static void tsc2005_esd_work(struct work_struct *work)
|
||||
|
||||
tsc2005_update_pen_state(ts, 0, 0, 0);
|
||||
|
||||
ts->set_reset(false);
|
||||
tsc2005_set_reset(ts, false);
|
||||
usleep_range(100, 500); /* only 10us required */
|
||||
ts->set_reset(true);
|
||||
tsc2005_set_reset(ts, true);
|
||||
|
||||
enable_irq(ts->spi->irq);
|
||||
tsc2005_start_scan(ts);
|
||||
@ -572,29 +592,47 @@ static void tsc2005_setup_spi_xfer(struct tsc2005 *ts)
|
||||
static int tsc2005_probe(struct spi_device *spi)
|
||||
{
|
||||
const struct tsc2005_platform_data *pdata = dev_get_platdata(&spi->dev);
|
||||
struct device_node *np = spi->dev.of_node;
|
||||
|
||||
struct tsc2005 *ts;
|
||||
struct input_dev *input_dev;
|
||||
unsigned int max_x, max_y, max_p;
|
||||
unsigned int fudge_x, fudge_y, fudge_p;
|
||||
unsigned int max_x = MAX_12BIT;
|
||||
unsigned int max_y = MAX_12BIT;
|
||||
unsigned int max_p = MAX_12BIT;
|
||||
unsigned int fudge_x = TSC2005_DEF_X_FUZZ;
|
||||
unsigned int fudge_y = TSC2005_DEF_Y_FUZZ;
|
||||
unsigned int fudge_p = TSC2005_DEF_P_FUZZ;
|
||||
unsigned int x_plate_ohm = TSC2005_DEF_RESISTOR;
|
||||
unsigned int esd_timeout;
|
||||
int error;
|
||||
|
||||
if (!pdata) {
|
||||
dev_dbg(&spi->dev, "no platform data\n");
|
||||
if (!np && !pdata) {
|
||||
dev_err(&spi->dev, "no platform data\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
fudge_x = pdata->ts_x_fudge ? : 4;
|
||||
fudge_y = pdata->ts_y_fudge ? : 8;
|
||||
fudge_p = pdata->ts_pressure_fudge ? : 2;
|
||||
max_x = pdata->ts_x_max ? : MAX_12BIT;
|
||||
max_y = pdata->ts_y_max ? : MAX_12BIT;
|
||||
max_p = pdata->ts_pressure_max ? : MAX_12BIT;
|
||||
|
||||
if (spi->irq <= 0) {
|
||||
dev_dbg(&spi->dev, "no irq\n");
|
||||
dev_err(&spi->dev, "no irq\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (pdata) {
|
||||
fudge_x = pdata->ts_x_fudge;
|
||||
fudge_y = pdata->ts_y_fudge;
|
||||
fudge_p = pdata->ts_pressure_fudge;
|
||||
max_x = pdata->ts_x_max;
|
||||
max_y = pdata->ts_y_max;
|
||||
max_p = pdata->ts_pressure_max;
|
||||
x_plate_ohm = pdata->ts_x_plate_ohm;
|
||||
esd_timeout = pdata->esd_timeout_ms;
|
||||
} else {
|
||||
x_plate_ohm = TSC2005_DEF_RESISTOR;
|
||||
of_property_read_u32(np, "ti,x-plate-ohms", &x_plate_ohm);
|
||||
esd_timeout = 0;
|
||||
of_property_read_u32(np, "ti,esd-recovery-timeout-ms",
|
||||
&esd_timeout);
|
||||
}
|
||||
|
||||
spi->mode = SPI_MODE_0;
|
||||
spi->bits_per_word = 8;
|
||||
if (!spi->max_speed_hz)
|
||||
@ -604,19 +642,48 @@ static int tsc2005_probe(struct spi_device *spi)
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
ts = kzalloc(sizeof(*ts), GFP_KERNEL);
|
||||
input_dev = input_allocate_device();
|
||||
if (!ts || !input_dev) {
|
||||
error = -ENOMEM;
|
||||
goto err_free_mem;
|
||||
}
|
||||
ts = devm_kzalloc(&spi->dev, sizeof(*ts), GFP_KERNEL);
|
||||
if (!ts)
|
||||
return -ENOMEM;
|
||||
|
||||
input_dev = devm_input_allocate_device(&spi->dev);
|
||||
if (!input_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
ts->spi = spi;
|
||||
ts->idev = input_dev;
|
||||
|
||||
ts->x_plate_ohm = pdata->ts_x_plate_ohm ? : 280;
|
||||
ts->esd_timeout = pdata->esd_timeout_ms;
|
||||
ts->set_reset = pdata->set_reset;
|
||||
ts->x_plate_ohm = x_plate_ohm;
|
||||
ts->esd_timeout = esd_timeout;
|
||||
|
||||
if (np) {
|
||||
ts->reset_gpio = of_get_named_gpio(np, "reset-gpios", 0);
|
||||
if (ts->reset_gpio == -EPROBE_DEFER)
|
||||
return ts->reset_gpio;
|
||||
if (ts->reset_gpio < 0) {
|
||||
dev_err(&spi->dev, "error acquiring reset gpio: %d\n",
|
||||
ts->reset_gpio);
|
||||
return ts->reset_gpio;
|
||||
}
|
||||
|
||||
error = devm_gpio_request_one(&spi->dev, ts->reset_gpio, 0,
|
||||
"reset-gpios");
|
||||
if (error) {
|
||||
dev_err(&spi->dev, "error requesting reset gpio: %d\n",
|
||||
error);
|
||||
return error;
|
||||
}
|
||||
|
||||
ts->vio = devm_regulator_get(&spi->dev, "vio");
|
||||
if (IS_ERR(ts->vio)) {
|
||||
error = PTR_ERR(ts->vio);
|
||||
dev_err(&spi->dev, "vio regulator missing (%d)", error);
|
||||
return error;
|
||||
}
|
||||
} else {
|
||||
ts->reset_gpio = -1;
|
||||
ts->set_reset = pdata->set_reset;
|
||||
}
|
||||
|
||||
mutex_init(&ts->mutex);
|
||||
|
||||
@ -641,6 +708,9 @@ static int tsc2005_probe(struct spi_device *spi)
|
||||
input_set_abs_params(input_dev, ABS_Y, 0, max_y, fudge_y, 0);
|
||||
input_set_abs_params(input_dev, ABS_PRESSURE, 0, max_p, fudge_p, 0);
|
||||
|
||||
if (np)
|
||||
touchscreen_parse_of_params(input_dev);
|
||||
|
||||
input_dev->open = tsc2005_open;
|
||||
input_dev->close = tsc2005_close;
|
||||
|
||||
@ -649,12 +719,20 @@ static int tsc2005_probe(struct spi_device *spi)
|
||||
/* Ensure the touchscreen is off */
|
||||
tsc2005_stop_scan(ts);
|
||||
|
||||
error = request_threaded_irq(spi->irq, NULL, tsc2005_irq_thread,
|
||||
IRQF_TRIGGER_RISING | IRQF_ONESHOT,
|
||||
"tsc2005", ts);
|
||||
error = devm_request_threaded_irq(&spi->dev, spi->irq, NULL,
|
||||
tsc2005_irq_thread,
|
||||
IRQF_TRIGGER_RISING | IRQF_ONESHOT,
|
||||
"tsc2005", ts);
|
||||
if (error) {
|
||||
dev_err(&spi->dev, "Failed to request irq, err: %d\n", error);
|
||||
goto err_free_mem;
|
||||
return error;
|
||||
}
|
||||
|
||||
/* enable regulator for DT */
|
||||
if (ts->vio) {
|
||||
error = regulator_enable(ts->vio);
|
||||
if (error)
|
||||
return error;
|
||||
}
|
||||
|
||||
spi_set_drvdata(spi, ts);
|
||||
@ -662,7 +740,7 @@ static int tsc2005_probe(struct spi_device *spi)
|
||||
if (error) {
|
||||
dev_err(&spi->dev,
|
||||
"Failed to create sysfs attributes, err: %d\n", error);
|
||||
goto err_clear_drvdata;
|
||||
goto disable_regulator;
|
||||
}
|
||||
|
||||
error = input_register_device(ts->idev);
|
||||
@ -677,11 +755,9 @@ static int tsc2005_probe(struct spi_device *spi)
|
||||
|
||||
err_remove_sysfs:
|
||||
sysfs_remove_group(&spi->dev.kobj, &tsc2005_attr_group);
|
||||
err_clear_drvdata:
|
||||
free_irq(spi->irq, ts);
|
||||
err_free_mem:
|
||||
input_free_device(input_dev);
|
||||
kfree(ts);
|
||||
disable_regulator:
|
||||
if (ts->vio)
|
||||
regulator_disable(ts->vio);
|
||||
return error;
|
||||
}
|
||||
|
||||
@ -689,11 +765,10 @@ static int tsc2005_remove(struct spi_device *spi)
|
||||
{
|
||||
struct tsc2005 *ts = spi_get_drvdata(spi);
|
||||
|
||||
sysfs_remove_group(&ts->spi->dev.kobj, &tsc2005_attr_group);
|
||||
sysfs_remove_group(&spi->dev.kobj, &tsc2005_attr_group);
|
||||
|
||||
free_irq(ts->spi->irq, ts);
|
||||
input_unregister_device(ts->idev);
|
||||
kfree(ts);
|
||||
if (ts->vio)
|
||||
regulator_disable(ts->vio);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -880,7 +880,7 @@ static struct i2c_device_id zforce_idtable[] = {
|
||||
MODULE_DEVICE_TABLE(i2c, zforce_idtable);
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static struct of_device_id zforce_dt_idtable[] = {
|
||||
static const struct of_device_id zforce_dt_idtable[] = {
|
||||
{ .compatible = "neonode,zforce" },
|
||||
{},
|
||||
};
|
||||
|
@ -84,21 +84,19 @@ static struct i2c_board_info tsl2563_als_device = {
|
||||
I2C_BOARD_INFO("tsl2563", TAOS_ALS_I2C_ADDR),
|
||||
};
|
||||
|
||||
static int mxt_t19_keys[] = {
|
||||
KEY_RESERVED,
|
||||
KEY_RESERVED,
|
||||
KEY_RESERVED,
|
||||
KEY_RESERVED,
|
||||
KEY_RESERVED,
|
||||
BTN_LEFT
|
||||
};
|
||||
|
||||
static struct mxt_platform_data atmel_224s_tp_platform_data = {
|
||||
.x_line = 18,
|
||||
.y_line = 12,
|
||||
.x_size = 102*20,
|
||||
.y_size = 68*20,
|
||||
.blen = 0x80, /* Gain setting is in upper 4 bits */
|
||||
.threshold = 0x32,
|
||||
.voltage = 0, /* 3.3V */
|
||||
.orient = MXT_VERTICAL_FLIP,
|
||||
.irqflags = IRQF_TRIGGER_FALLING,
|
||||
.is_tp = true,
|
||||
.key_map = { KEY_RESERVED,
|
||||
KEY_RESERVED,
|
||||
KEY_RESERVED,
|
||||
BTN_LEFT },
|
||||
.t19_num_keys = ARRAY_SIZE(mxt_t19_keys),
|
||||
.t19_keymap = mxt_t19_keys,
|
||||
.config = NULL,
|
||||
.config_length = 0,
|
||||
};
|
||||
@ -110,16 +108,7 @@ static struct i2c_board_info atmel_224s_tp_device = {
|
||||
};
|
||||
|
||||
static struct mxt_platform_data atmel_1664s_platform_data = {
|
||||
.x_line = 32,
|
||||
.y_line = 50,
|
||||
.x_size = 1700,
|
||||
.y_size = 2560,
|
||||
.blen = 0x89, /* Gain setting is in upper 4 bits */
|
||||
.threshold = 0x28,
|
||||
.voltage = 0, /* 3.3V */
|
||||
.orient = MXT_ROTATED_90_COUNTER,
|
||||
.irqflags = IRQF_TRIGGER_FALLING,
|
||||
.is_tp = false,
|
||||
.config = NULL,
|
||||
.config_length = 0,
|
||||
};
|
||||
|
@ -3,29 +3,53 @@
|
||||
|
||||
struct device;
|
||||
|
||||
/**
|
||||
* struct gpio_keys_button - configuration parameters
|
||||
* @code: input event code (KEY_*, SW_*)
|
||||
* @gpio: %-1 if this key does not support gpio
|
||||
* @active_low: %true indicates that button is considered
|
||||
* depressed when gpio is low
|
||||
* @desc: label that will be attached to button's gpio
|
||||
* @type: input event type (%EV_KEY, %EV_SW, %EV_ABS)
|
||||
* @wakeup: configure the button as a wake-up source
|
||||
* @debounce_interval: debounce ticks interval in msecs
|
||||
* @can_disable: %true indicates that userspace is allowed to
|
||||
* disable button via sysfs
|
||||
* @value: axis value for %EV_ABS
|
||||
* @irq: Irq number in case of interrupt keys
|
||||
*/
|
||||
struct gpio_keys_button {
|
||||
/* Configuration parameters */
|
||||
unsigned int code; /* input event code (KEY_*, SW_*) */
|
||||
int gpio; /* -1 if this key does not support gpio */
|
||||
unsigned int code;
|
||||
int gpio;
|
||||
int active_low;
|
||||
const char *desc;
|
||||
unsigned int type; /* input event type (EV_KEY, EV_SW, EV_ABS) */
|
||||
int wakeup; /* configure the button as a wake-up source */
|
||||
int debounce_interval; /* debounce ticks interval in msecs */
|
||||
unsigned int type;
|
||||
int wakeup;
|
||||
int debounce_interval;
|
||||
bool can_disable;
|
||||
int value; /* axis value for EV_ABS */
|
||||
unsigned int irq; /* Irq number in case of interrupt keys */
|
||||
int value;
|
||||
unsigned int irq;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct gpio_keys_platform_data - platform data for gpio_keys driver
|
||||
* @buttons: pointer to array of &gpio_keys_button structures
|
||||
* describing buttons attached to the device
|
||||
* @nbuttons: number of elements in @buttons array
|
||||
* @poll_interval: polling interval in msecs - for polling driver only
|
||||
* @rep: enable input subsystem auto repeat
|
||||
* @enable: platform hook for enabling the device
|
||||
* @disable: platform hook for disabling the device
|
||||
* @name: input device name
|
||||
*/
|
||||
struct gpio_keys_platform_data {
|
||||
struct gpio_keys_button *buttons;
|
||||
int nbuttons;
|
||||
unsigned int poll_interval; /* polling interval in msecs -
|
||||
for polling driver only */
|
||||
unsigned int rep:1; /* enable input subsystem auto repeat */
|
||||
unsigned int poll_interval;
|
||||
unsigned int rep:1;
|
||||
int (*enable)(struct device *dev);
|
||||
void (*disable)(struct device *dev);
|
||||
const char *name; /* input device name */
|
||||
const char *name;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -15,35 +15,14 @@
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
/* For key_map array */
|
||||
#define MXT_NUM_GPIO 4
|
||||
|
||||
/* Orient */
|
||||
#define MXT_NORMAL 0x0
|
||||
#define MXT_DIAGONAL 0x1
|
||||
#define MXT_HORIZONTAL_FLIP 0x2
|
||||
#define MXT_ROTATED_90_COUNTER 0x3
|
||||
#define MXT_VERTICAL_FLIP 0x4
|
||||
#define MXT_ROTATED_90 0x5
|
||||
#define MXT_ROTATED_180 0x6
|
||||
#define MXT_DIAGONAL_COUNTER 0x7
|
||||
|
||||
/* The platform data for the Atmel maXTouch touchscreen driver */
|
||||
struct mxt_platform_data {
|
||||
const u8 *config;
|
||||
size_t config_length;
|
||||
|
||||
unsigned int x_line;
|
||||
unsigned int y_line;
|
||||
unsigned int x_size;
|
||||
unsigned int y_size;
|
||||
unsigned int blen;
|
||||
unsigned int threshold;
|
||||
unsigned int voltage;
|
||||
unsigned char orient;
|
||||
u32 config_crc;
|
||||
unsigned long irqflags;
|
||||
bool is_tp;
|
||||
const unsigned int key_map[MXT_NUM_GPIO];
|
||||
u8 t19_num_keys;
|
||||
const unsigned int *t19_keymap;
|
||||
};
|
||||
|
||||
#endif /* __LINUX_ATMEL_MXT_TS_H */
|
||||
|
@ -48,9 +48,12 @@ struct input_polled_dev {
|
||||
|
||||
/* private: */
|
||||
struct delayed_work work;
|
||||
|
||||
bool devres_managed;
|
||||
};
|
||||
|
||||
struct input_polled_dev *input_allocate_polled_device(void);
|
||||
struct input_polled_dev *devm_input_allocate_polled_device(struct device *dev);
|
||||
void input_free_polled_device(struct input_polled_dev *dev);
|
||||
int input_register_polled_device(struct input_polled_dev *dev);
|
||||
void input_unregister_polled_device(struct input_polled_dev *dev);
|
||||
|
@ -1,10 +1,52 @@
|
||||
#ifndef _PIXCIR_I2C_TS_H
|
||||
#define _PIXCIR_I2C_TS_H
|
||||
|
||||
/*
|
||||
* Register map
|
||||
*/
|
||||
#define PIXCIR_REG_POWER_MODE 51
|
||||
#define PIXCIR_REG_INT_MODE 52
|
||||
|
||||
/*
|
||||
* Power modes:
|
||||
* active: max scan speed
|
||||
* idle: lower scan speed with automatic transition to active on touch
|
||||
* halt: datasheet says sleep but this is more like halt as the chip
|
||||
* clocks are cut and it can only be brought out of this mode
|
||||
* using the RESET pin.
|
||||
*/
|
||||
enum pixcir_power_mode {
|
||||
PIXCIR_POWER_ACTIVE,
|
||||
PIXCIR_POWER_IDLE,
|
||||
PIXCIR_POWER_HALT,
|
||||
};
|
||||
|
||||
#define PIXCIR_POWER_MODE_MASK 0x03
|
||||
#define PIXCIR_POWER_ALLOW_IDLE (1UL << 2)
|
||||
|
||||
/*
|
||||
* Interrupt modes:
|
||||
* periodical: interrupt is asserted periodicaly
|
||||
* diff coordinates: interrupt is asserted when coordinates change
|
||||
* level on touch: interrupt level asserted during touch
|
||||
* pulse on touch: interrupt pulse asserted druing touch
|
||||
*
|
||||
*/
|
||||
enum pixcir_int_mode {
|
||||
PIXCIR_INT_PERIODICAL,
|
||||
PIXCIR_INT_DIFF_COORD,
|
||||
PIXCIR_INT_LEVEL_TOUCH,
|
||||
PIXCIR_INT_PULSE_TOUCH,
|
||||
};
|
||||
|
||||
#define PIXCIR_INT_MODE_MASK 0x03
|
||||
#define PIXCIR_INT_ENABLE (1UL << 3)
|
||||
#define PIXCIR_INT_POL_HIGH (1UL << 2)
|
||||
|
||||
struct pixcir_ts_platform_data {
|
||||
int (*attb_read_val)(void);
|
||||
int x_max;
|
||||
int y_max;
|
||||
int gpio_attb; /* GPIO connected to ATTB line */
|
||||
};
|
||||
|
||||
#endif
|
||||
|
22
include/linux/input/touchscreen.h
Normal file
22
include/linux/input/touchscreen.h
Normal file
@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Sebastian Reichel <sre@kernel.org>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _TOUCHSCREEN_H
|
||||
#define _TOUCHSCREEN_H
|
||||
|
||||
#include <linux/input.h>
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
void touchscreen_parse_of_params(struct input_dev *dev);
|
||||
#else
|
||||
static inline void touchscreen_parse_of_params(struct input_dev *dev)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -1,13 +0,0 @@
|
||||
#ifndef __LINUX_INPUT_OMAP4_KEYPAD_H
|
||||
#define __LINUX_INPUT_OMAP4_KEYPAD_H
|
||||
|
||||
#include <linux/input/matrix_keypad.h>
|
||||
|
||||
struct omap4_keypad_platform_data {
|
||||
const struct matrix_keymap_data *keymap_data;
|
||||
|
||||
u8 rows;
|
||||
u8 cols;
|
||||
};
|
||||
|
||||
#endif /* __LINUX_INPUT_OMAP4_KEYPAD_H */
|
Loading…
Reference in New Issue
Block a user