Commit f4f9b8fc authored by Linus Torvalds's avatar Linus Torvalds

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

Pull input 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
  ...
parents 9894e6d9 a292241c
* 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) >;
};
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;
};
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
* 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 @@ &mcspi1 { ...@@ -651,9 +651,24 @@ &mcspi1 {
* Also... order in the device tree actually matters here. * Also... order in the device tree actually matters here.
*/ */
tsc2005@0 { tsc2005@0 {
compatible = "tsc2005"; compatible = "ti,tsc2005";
spi-max-frequency = <6000000>; spi-max-frequency = <6000000>;
reg = <0>; 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 { acx565akm@2 {
......
...@@ -18,7 +18,6 @@ ...@@ -18,7 +18,6 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/pinctrl/machine.h> #include <linux/pinctrl/machine.h>
#include <linux/platform_data/omap4-keypad.h>
#include <linux/platform_data/mailbox-omap.h> #include <linux/platform_data/mailbox-omap.h>
#include <asm/mach-types.h> #include <asm/mach-types.h>
...@@ -29,7 +28,6 @@ ...@@ -29,7 +28,6 @@
#include "iomap.h" #include "iomap.h"
#include "omap_hwmod.h" #include "omap_hwmod.h"
#include "omap_device.h" #include "omap_device.h"
#include "omap4-keypad.h"
#include "soc.h" #include "soc.h"
#include "common.h" #include "common.h"
...@@ -255,37 +253,6 @@ static inline void omap_init_camera(void) ...@@ -255,37 +253,6 @@ static inline void omap_init_camera(void)
#endif #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) #if defined(CONFIG_OMAP2PLUS_MBOX) || defined(CONFIG_OMAP2PLUS_MBOX_MODULE)
static inline void __init omap_init_mbox(void) static inline void __init omap_init_mbox(void)
{ {
......
#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) ...@@ -234,14 +234,6 @@ static void __init goni_radio_init(void)
/* TSP */ /* TSP */
static struct mxt_platform_data qt602240_platform_data = { 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, .irqflags = IRQF_TRIGGER_FALLING,
}; };
......
...@@ -629,12 +629,10 @@ static int str_to_user(const char *str, unsigned int maxlen, void __user *p) ...@@ -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; return copy_to_user(p, str, len) ? -EFAULT : len;
} }
#define OLD_KEY_MAX 0x1ff
static int handle_eviocgbit(struct input_dev *dev, static int handle_eviocgbit(struct input_dev *dev,
unsigned int type, unsigned int size, unsigned int type, unsigned int size,
void __user *p, int compat_mode) void __user *p, int compat_mode)
{ {
static unsigned long keymax_warn_time;
unsigned long *bits; unsigned long *bits;
int len; int len;
...@@ -652,24 +650,8 @@ static int handle_eviocgbit(struct input_dev *dev, ...@@ -652,24 +650,8 @@ static int handle_eviocgbit(struct input_dev *dev,
default: return -EINVAL; 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); 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) 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 = { ...@@ -147,6 +147,11 @@ static struct attribute_group input_polldev_attribute_group = {
.attrs = sysfs_attrs .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 * input_allocate_polled_device - allocate memory for polled device
* *
...@@ -171,6 +176,91 @@ struct input_polled_dev *input_allocate_polled_device(void) ...@@ -171,6 +176,91 @@ struct input_polled_dev *input_allocate_polled_device(void)
} }
EXPORT_SYMBOL(input_allocate_polled_device); 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 * input_free_polled_device - free memory allocated for polled device
* @dev: device to free * @dev: device to free
...@@ -181,7 +271,12 @@ EXPORT_SYMBOL(input_allocate_polled_device); ...@@ -181,7 +271,12 @@ EXPORT_SYMBOL(input_allocate_polled_device);
void input_free_polled_device(struct input_polled_dev *dev) void input_free_polled_device(struct input_polled_dev *dev)
{ {
if (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); kfree(dev);
} }
} }
...@@ -199,26 +294,35 @@ EXPORT_SYMBOL(input_free_polled_device); ...@@ -199,26 +294,35 @@ EXPORT_SYMBOL(input_free_polled_device);
*/ */
int input_register_polled_device(struct input_polled_dev *dev) int input_register_polled_device(struct input_polled_dev *dev)
{ {
struct input_polled_devres *devres = NULL;
struct input_dev *input = dev->input; struct input_dev *input = dev->input;
int error; 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); input_set_drvdata(input, dev);
INIT_DELAYED_WORK(&dev->work, input_polled_device_work); INIT_DELAYED_WORK(&dev->work, input_polled_device_work);
if (!dev->poll_interval) if (!dev->poll_interval)
dev->poll_interval = 500; dev->poll_interval = 500;
if (!dev->poll_interval_max) if (!dev->poll_interval_max)
dev->poll_interval_max = dev->poll_interval; dev->poll_interval_max = dev->poll_interval;
input->open = input_open_polled_device; input->open = input_open_polled_device;
input->close = input_close_polled_device; input->close = input_close_polled_device;
error = input_register_device(input); input->dev.groups = input_polldev_attribute_groups;
if (error)
return error;
error = sysfs_create_group(&input->dev.kobj, error = input_register_device(input);
&input_polldev_attribute_group);
if (error) { if (error) {
input_unregister_device(input); devres_free(devres);
return error; return error;
} }
...@@ -231,6 +335,12 @@ int input_register_polled_device(struct input_polled_dev *dev) ...@@ -231,6 +335,12 @@ int input_register_polled_device(struct input_polled_dev *dev)
*/ */
input_get_device(input); 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; return 0;
} }
EXPORT_SYMBOL(input_register_polled_device); EXPORT_SYMBOL(input_register_polled_device);
...@@ -245,8 +355,11 @@ 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) void input_unregister_polled_device(struct input_polled_dev *dev)
{ {
sysfs_remove_group(&dev->input->dev.kobj, if (dev->devres_managed)
&input_polldev_attribute_group); WARN_ON(devres_destroy(dev->input->dev.parent,
devm_input_polldev_unregister,
devm_input_polldev_match,
dev));
input_unregister_device(dev->input); input_unregister_device(dev->input);
} }
......
...@@ -524,6 +524,17 @@ config KEYBOARD_STOWAWAY ...@@ -524,6 +524,17 @@ config KEYBOARD_STOWAWAY
To compile this driver as a module, choose M here: the To compile this driver as a module, choose M here: the
module will be called stowaway. 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 config KEYBOARD_SUNKBD
tristate "Sun Type 4 and Type 5 keyboard" tristate "Sun Type 4 and Type 5 keyboard"
select SERIO select SERIO
...@@ -578,7 +589,7 @@ config KEYBOARD_OMAP ...@@ -578,7 +589,7 @@ config KEYBOARD_OMAP
config KEYBOARD_OMAP4 config KEYBOARD_OMAP4
tristate "TI OMAP4+ keypad support" tristate "TI OMAP4+ keypad support"
depends on ARCH_OMAP2PLUS depends on OF || ARCH_OMAP2PLUS
select INPUT_MATRIXKMAP select INPUT_MATRIXKMAP
help help
Say Y here if you want to use the OMAP4+ keypad. Say Y here if you want to use the OMAP4+ keypad.
......
...@@ -51,6 +51,7 @@ obj-$(CONFIG_KEYBOARD_SH_KEYSC) += sh_keysc.o ...@@ -51,6 +51,7 @@ obj-$(CONFIG_KEYBOARD_SH_KEYSC) += sh_keysc.o
obj-$(CONFIG_KEYBOARD_SPEAR) += spear-keyboard.o obj-$(CONFIG_KEYBOARD_SPEAR) += spear-keyboard.o
obj-$(CONFIG_KEYBOARD_STMPE) += stmpe-keypad.o obj-$(CONFIG_KEYBOARD_STMPE) += stmpe-keypad.o
obj-$(CONFIG_KEYBOARD_STOWAWAY) += stowaway.o obj-$(CONFIG_KEYBOARD_STOWAWAY) += stowaway.o
obj-$(CONFIG_KEYBOARD_ST_KEYSCAN) += st-keyscan.o
obj-$(CONFIG_KEYBOARD_SUNKBD) += sunkbd.o obj-$(CONFIG_KEYBOARD_SUNKBD) += sunkbd.o
obj-$(CONFIG_KEYBOARD_TC3589X) += tc3589x-keypad.o obj-$(CONFIG_KEYBOARD_TC3589X) += tc3589x-keypad.o
obj-$(CONFIG_KEYBOARD_TEGRA) += tegra-kbc.o obj-$(CONFIG_KEYBOARD_TEGRA) += tegra-kbc.o
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include <linux/input.h> #include <linux/input.h>
#include <linux/mfd/adp5520.h> #include <linux/mfd/adp5520.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/device.h>
struct adp5520_keys { struct adp5520_keys {
struct input_dev *input; struct input_dev *input;
...@@ -81,7 +82,7 @@ static int adp5520_keys_probe(struct platform_device *pdev) ...@@ -81,7 +82,7 @@ static int adp5520_keys_probe(struct platform_device *pdev)
return -EINVAL; return -EINVAL;
} }
if (pdata == NULL) { if (!pdata) {
dev_err(&pdev->dev, "missing platform data\n"); dev_err(&pdev->dev, "missing platform data\n");
return -EINVAL; return -EINVAL;
} }
...@@ -89,17 +90,15 @@ static int adp5520_keys_probe(struct platform_device *pdev) ...@@ -89,17 +90,15 @@ static int adp5520_keys_probe(struct platform_device *pdev)
if (!(pdata->rows_en_mask && pdata->cols_en_mask)) if (!(pdata->rows_en_mask && pdata->cols_en_mask))
return -EINVAL; return -EINVAL;
dev = kzalloc(sizeof(*dev), GFP_KERNEL); dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
if (dev == NULL) { if (!dev) {
dev_err(&pdev->dev, "failed to alloc memory\n"); dev_err(&pdev->dev, "failed to alloc memory\n");
return -ENOMEM; return -ENOMEM;
} }
input = input_allocate_device(); input = devm_input_allocate_device(&pdev->dev);
if (!input) { if (!input)
ret = -ENOMEM; return -ENOMEM;
goto err;
}
dev->master = pdev->dev.parent; dev->master = pdev->dev.parent;
dev->input = input; dev->input = input;
...@@ -135,7 +134,7 @@ static int adp5520_keys_probe(struct platform_device *pdev) ...@@ -135,7 +134,7 @@ static int adp5520_keys_probe(struct platform_device *pdev)
ret = input_register_device(input); ret = input_register_device(input);
if (ret) { if (ret) {
dev_err(&pdev->dev, "unable to register input device\n"); dev_err(&pdev->dev, "unable to register input device\n");
goto err; return ret;
} }
en_mask = pdata->rows_en_mask | pdata->cols_en_mask; en_mask = pdata->rows_en_mask | pdata->cols_en_mask;
...@@ -157,8 +156,7 @@ static int adp5520_keys_probe(struct platform_device *pdev) ...@@ -157,8 +156,7 @@ static int adp5520_keys_probe(struct platform_device *pdev)
if (ret) { if (ret) {
dev_err(&pdev->dev, "failed to write\n"); dev_err(&pdev->dev, "failed to write\n");
ret = -EIO; return -EIO;
goto err1;
} }
dev->notifier.notifier_call = adp5520_keys_notifier; dev->notifier.notifier_call = adp5520_keys_notifier;
...@@ -166,19 +164,11 @@ static int adp5520_keys_probe(struct platform_device *pdev) ...@@ -166,19 +164,11 @@ static int adp5520_keys_probe(struct platform_device *pdev)
ADP5520_KP_IEN | ADP5520_KR_IEN); ADP5520_KP_IEN | ADP5520_KR_IEN);
if (ret) { if (ret) {
dev_err(&pdev->dev, "failed to register notifier\n"); dev_err(&pdev->dev, "failed to register notifier\n");
goto err1; return ret;
} }
platform_set_drvdata(pdev, dev); platform_set_drvdata(pdev, dev);
return 0; 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) static int adp5520_keys_remove(struct platform_device *pdev)
...@@ -188,8 +178,6 @@ 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_unregister_notifier(dev->master, &dev->notifier,
ADP5520_KP_IEN | ADP5520_KR_IEN); ADP5520_KP_IEN | ADP5520_KR_IEN);
input_unregister_device(dev->input);
kfree(dev);
return 0; return 0;
} }
......
...@@ -185,7 +185,7 @@ static int clps711x_keypad_remove(struct platform_device *pdev) ...@@ -185,7 +185,7 @@ static int clps711x_keypad_remove(struct platform_device *pdev)
return 0; 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", }, { .compatible = "cirrus,clps711x-keypad", },
{ } { }
}; };
......
...@@ -424,6 +424,16 @@ static irqreturn_t gpio_keys_irq_isr(int irq, void *dev_id) ...@@ -424,6 +424,16 @@ static irqreturn_t gpio_keys_irq_isr(int irq, void *dev_id)
return IRQ_HANDLED; 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, static int gpio_keys_setup_key(struct platform_device *pdev,
struct input_dev *input, struct input_dev *input,
struct gpio_button_data *bdata, struct gpio_button_data *bdata,
...@@ -433,7 +443,8 @@ static int gpio_keys_setup_key(struct platform_device *pdev, ...@@ -433,7 +443,8 @@ static int gpio_keys_setup_key(struct platform_device *pdev,
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
irq_handler_t isr; irq_handler_t isr;
unsigned long irqflags; unsigned long irqflags;
int irq, error; int irq;
int error;
bdata->input = input; bdata->input = input;
bdata->button = button; bdata->button = button;
...@@ -441,7 +452,8 @@ static int gpio_keys_setup_key(struct platform_device *pdev, ...@@ -441,7 +452,8 @@ static int gpio_keys_setup_key(struct platform_device *pdev,
if (gpio_is_valid(button->gpio)) { 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) { if (error < 0) {
dev_err(dev, "Failed to request GPIO %d, error %d\n", dev_err(dev, "Failed to request GPIO %d, error %d\n",
button->gpio, error); button->gpio, error);
...@@ -463,7 +475,7 @@ static int gpio_keys_setup_key(struct platform_device *pdev, ...@@ -463,7 +475,7 @@ static int gpio_keys_setup_key(struct platform_device *pdev,
dev_err(dev, dev_err(dev,
"Unable to get irq number for GPIO %d, error %d\n", "Unable to get irq number for GPIO %d, error %d\n",
button->gpio, error); button->gpio, error);
goto fail; return error;
} }
bdata->irq = irq; bdata->irq = irq;
...@@ -496,6 +508,18 @@ static int gpio_keys_setup_key(struct platform_device *pdev, ...@@ -496,6 +508,18 @@ static int gpio_keys_setup_key(struct platform_device *pdev,
input_set_capability(input, button->type ?: EV_KEY, button->code); 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, * If platform has specified that the button can be disabled,
* we don't want it to share the interrupt line. * we don't want it to share the interrupt line.
...@@ -503,20 +527,15 @@ static int gpio_keys_setup_key(struct platform_device *pdev, ...@@ -503,20 +527,15 @@ static int gpio_keys_setup_key(struct platform_device *pdev,
if (!button->can_disable) if (!button->can_disable)
irqflags |= IRQF_SHARED; 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) { if (error < 0) {
dev_err(dev, "Unable to claim irq %d; error %d\n", dev_err(dev, "Unable to claim irq %d; error %d\n",
bdata->irq, error); bdata->irq, error);
goto fail; return error;
} }
return 0; 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) static void gpio_keys_report_state(struct gpio_keys_drvdata *ddata)
...@@ -578,23 +597,18 @@ gpio_keys_get_devtree_pdata(struct device *dev) ...@@ -578,23 +597,18 @@ gpio_keys_get_devtree_pdata(struct device *dev)
int i; int i;
node = dev->of_node; node = dev->of_node;
if (!node) { if (!node)
error = -ENODEV; return ERR_PTR(-ENODEV);
goto err_out;
}
nbuttons = of_get_child_count(node); nbuttons = of_get_child_count(node);
if (nbuttons == 0) { if (nbuttons == 0)
error = -ENODEV; return ERR_PTR(-ENODEV);
goto err_out;
}
pdata = kzalloc(sizeof(*pdata) + nbuttons * (sizeof *button), pdata = devm_kzalloc(dev,
sizeof(*pdata) + nbuttons * sizeof(*button),
GFP_KERNEL); GFP_KERNEL);
if (!pdata) { if (!pdata)
error = -ENOMEM; return ERR_PTR(-ENOMEM);
goto err_out;
}
pdata->buttons = (struct gpio_keys_button *)(pdata + 1); pdata->buttons = (struct gpio_keys_button *)(pdata + 1);
pdata->nbuttons = nbuttons; pdata->nbuttons = nbuttons;
...@@ -619,7 +633,7 @@ gpio_keys_get_devtree_pdata(struct device *dev) ...@@ -619,7 +633,7 @@ gpio_keys_get_devtree_pdata(struct device *dev)
dev_err(dev, dev_err(dev,
"Failed to get gpio flags, error: %d\n", "Failed to get gpio flags, error: %d\n",
error); error);
goto err_free_pdata; return ERR_PTR(error);
} }
button = &pdata->buttons[i++]; button = &pdata->buttons[i++];
...@@ -630,8 +644,7 @@ gpio_keys_get_devtree_pdata(struct device *dev) ...@@ -630,8 +644,7 @@ gpio_keys_get_devtree_pdata(struct device *dev)
if (of_property_read_u32(pp, "linux,code", &button->code)) { if (of_property_read_u32(pp, "linux,code", &button->code)) {
dev_err(dev, "Button without keycode: 0x%x\n", dev_err(dev, "Button without keycode: 0x%x\n",
button->gpio); button->gpio);
error = -EINVAL; return ERR_PTR(-EINVAL);
goto err_free_pdata;
} }
button->desc = of_get_property(pp, "label", NULL); button->desc = of_get_property(pp, "label", NULL);
...@@ -646,20 +659,13 @@ gpio_keys_get_devtree_pdata(struct device *dev) ...@@ -646,20 +659,13 @@ gpio_keys_get_devtree_pdata(struct device *dev)
button->debounce_interval = 5; button->debounce_interval = 5;
} }
if (pdata->nbuttons == 0) { if (pdata->nbuttons == 0)
error = -EINVAL; return ERR_PTR(-EINVAL);
goto err_free_pdata;
}
return pdata; 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", }, { .compatible = "gpio-keys", },
{ }, { },
}; };
...@@ -675,22 +681,13 @@ gpio_keys_get_devtree_pdata(struct device *dev) ...@@ -675,22 +681,13 @@ gpio_keys_get_devtree_pdata(struct device *dev)
#endif #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) static int gpio_keys_probe(struct platform_device *pdev)
{ {
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
const struct gpio_keys_platform_data *pdata = dev_get_platdata(dev); const struct gpio_keys_platform_data *pdata = dev_get_platdata(dev);
struct gpio_keys_drvdata *ddata; struct gpio_keys_drvdata *ddata;
struct input_dev *input; struct input_dev *input;
size_t size;
int i, error; int i, error;
int wakeup = 0; int wakeup = 0;
...@@ -700,14 +697,18 @@ static int gpio_keys_probe(struct platform_device *pdev) ...@@ -700,14 +697,18 @@ static int gpio_keys_probe(struct platform_device *pdev)
return PTR_ERR(pdata); return PTR_ERR(pdata);
} }
ddata = kzalloc(sizeof(struct gpio_keys_drvdata) + size = sizeof(struct gpio_keys_drvdata) +
pdata->nbuttons * sizeof(struct gpio_button_data), pdata->nbuttons * sizeof(struct gpio_button_data);
GFP_KERNEL); ddata = devm_kzalloc(dev, size, GFP_KERNEL);
input = input_allocate_device(); if (!ddata) {
if (!ddata || !input) {
dev_err(dev, "failed to allocate state\n"); dev_err(dev, "failed to allocate state\n");
error = -ENOMEM; return -ENOMEM;
goto fail1; }
input = devm_input_allocate_device(dev);
if (!input) {
dev_err(dev, "failed to allocate input device\n");
return -ENOMEM;
} }
ddata->pdata = pdata; ddata->pdata = pdata;
...@@ -738,7 +739,7 @@ static int gpio_keys_probe(struct platform_device *pdev) ...@@ -738,7 +739,7 @@ static int gpio_keys_probe(struct platform_device *pdev)
error = gpio_keys_setup_key(pdev, input, bdata, button); error = gpio_keys_setup_key(pdev, input, bdata, button);
if (error) if (error)
goto fail2; return error;
if (button->wakeup) if (button->wakeup)
wakeup = 1; wakeup = 1;
...@@ -748,57 +749,31 @@ static int gpio_keys_probe(struct platform_device *pdev) ...@@ -748,57 +749,31 @@ static int gpio_keys_probe(struct platform_device *pdev)
if (error) { if (error) {
dev_err(dev, "Unable to export keys/switches, error: %d\n", dev_err(dev, "Unable to export keys/switches, error: %d\n",
error); error);
goto fail2; return error;
} }
error = input_register_device(input); error = input_register_device(input);
if (error) { if (error) {
dev_err(dev, "Unable to register input device, error: %d\n", dev_err(dev, "Unable to register input device, error: %d\n",
error); error);
goto fail3; goto err_remove_group;
} }
device_init_wakeup(&pdev->dev, wakeup); device_init_wakeup(&pdev->dev, wakeup);
return 0; return 0;
fail3: err_remove_group:
sysfs_remove_group(&pdev->dev.kobj, &gpio_keys_attr_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; return error;
} }
static int gpio_keys_remove(struct platform_device *pdev) 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); sysfs_remove_group(&pdev->dev.kobj, &gpio_keys_attr_group);
device_init_wakeup(&pdev->dev, 0); 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; return 0;
} }
......
...@@ -120,12 +120,10 @@ static struct gpio_keys_platform_data *gpio_keys_polled_get_devtree_pdata(struct ...@@ -120,12 +120,10 @@ static struct gpio_keys_platform_data *gpio_keys_polled_get_devtree_pdata(struct
if (nbuttons == 0) if (nbuttons == 0)
return NULL; return NULL;
pdata = kzalloc(sizeof(*pdata) + nbuttons * (sizeof *button), pdata = devm_kzalloc(dev, sizeof(*pdata) + nbuttons * sizeof(*button),
GFP_KERNEL); GFP_KERNEL);
if (!pdata) { if (!pdata)
error = -ENOMEM; return ERR_PTR(-ENOMEM);
goto err_out;
}
pdata->buttons = (struct gpio_keys_button *)(pdata + 1); pdata->buttons = (struct gpio_keys_button *)(pdata + 1);
pdata->nbuttons = nbuttons; pdata->nbuttons = nbuttons;
...@@ -151,7 +149,7 @@ static struct gpio_keys_platform_data *gpio_keys_polled_get_devtree_pdata(struct ...@@ -151,7 +149,7 @@ static struct gpio_keys_platform_data *gpio_keys_polled_get_devtree_pdata(struct
dev_err(dev, dev_err(dev,
"Failed to get gpio flags, error: %d\n", "Failed to get gpio flags, error: %d\n",
error); error);
goto err_free_pdata; return ERR_PTR(error);
} }
button = &pdata->buttons[i++]; button = &pdata->buttons[i++];
...@@ -162,8 +160,7 @@ static struct gpio_keys_platform_data *gpio_keys_polled_get_devtree_pdata(struct ...@@ -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)) { if (of_property_read_u32(pp, "linux,code", &button->code)) {
dev_err(dev, "Button without keycode: 0x%x\n", dev_err(dev, "Button without keycode: 0x%x\n",
button->gpio); button->gpio);
error = -EINVAL; return ERR_PTR(-EINVAL);
goto err_free_pdata;
} }
button->desc = of_get_property(pp, "label", NULL); 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 ...@@ -178,20 +175,13 @@ static struct gpio_keys_platform_data *gpio_keys_polled_get_devtree_pdata(struct
button->debounce_interval = 5; button->debounce_interval = 5;
} }
if (pdata->nbuttons == 0) { if (pdata->nbuttons == 0)
error = -EINVAL; return ERR_PTR(-EINVAL);
goto err_free_pdata;
}
return pdata; 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", }, { .compatible = "gpio-keys-polled", },
{ }, { },
}; };
...@@ -213,6 +203,7 @@ static int gpio_keys_polled_probe(struct platform_device *pdev) ...@@ -213,6 +203,7 @@ static int gpio_keys_polled_probe(struct platform_device *pdev)
struct gpio_keys_polled_dev *bdev; struct gpio_keys_polled_dev *bdev;
struct input_polled_dev *poll_dev; struct input_polled_dev *poll_dev;
struct input_dev *input; struct input_dev *input;
size_t size;
int error; int error;
int i; int i;
...@@ -228,24 +219,21 @@ static int gpio_keys_polled_probe(struct platform_device *pdev) ...@@ -228,24 +219,21 @@ static int gpio_keys_polled_probe(struct platform_device *pdev)
if (!pdata->poll_interval) { if (!pdata->poll_interval) {
dev_err(dev, "missing poll_interval value\n"); dev_err(dev, "missing poll_interval value\n");
error = -EINVAL; return -EINVAL;
goto err_free_pdata;
} }
bdev = kzalloc(sizeof(struct gpio_keys_polled_dev) + size = sizeof(struct gpio_keys_polled_dev) +
pdata->nbuttons * sizeof(struct gpio_keys_button_data), pdata->nbuttons * sizeof(struct gpio_keys_button_data);
GFP_KERNEL); bdev = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
if (!bdev) { if (!bdev) {
dev_err(dev, "no memory for private data\n"); dev_err(dev, "no memory for private data\n");
error = -ENOMEM; return -ENOMEM;
goto err_free_pdata;
} }
poll_dev = input_allocate_polled_device(); poll_dev = devm_input_allocate_polled_device(&pdev->dev);
if (!poll_dev) { if (!poll_dev) {
dev_err(dev, "no memory for polled device\n"); dev_err(dev, "no memory for polled device\n");
error = -ENOMEM; return -ENOMEM;
goto err_free_bdev;
} }
poll_dev->private = bdev; poll_dev->private = bdev;
...@@ -258,7 +246,6 @@ static int gpio_keys_polled_probe(struct platform_device *pdev) ...@@ -258,7 +246,6 @@ static int gpio_keys_polled_probe(struct platform_device *pdev)
input->name = pdev->name; input->name = pdev->name;
input->phys = DRV_NAME"/input0"; input->phys = DRV_NAME"/input0";
input->dev.parent = &pdev->dev;
input->id.bustype = BUS_HOST; input->id.bustype = BUS_HOST;
input->id.vendor = 0x0001; input->id.vendor = 0x0001;
...@@ -277,16 +264,15 @@ static int gpio_keys_polled_probe(struct platform_device *pdev) ...@@ -277,16 +264,15 @@ static int gpio_keys_polled_probe(struct platform_device *pdev)
if (button->wakeup) { if (button->wakeup) {
dev_err(dev, DRV_NAME " does not support wakeup\n"); dev_err(dev, DRV_NAME " does not support wakeup\n");
error = -EINVAL; return -EINVAL;
goto err_free_gpio;
} }
error = gpio_request_one(gpio, GPIOF_IN, error = devm_gpio_request_one(&pdev->dev, gpio, GPIOF_IN,
button->desc ?: DRV_NAME); button->desc ? : DRV_NAME);
if (error) { if (error) {
dev_err(dev, "unable to claim gpio %u, err=%d\n", dev_err(dev, "unable to claim gpio %u, err=%d\n",
gpio, error); gpio, error);
goto err_free_gpio; return error;
} }
bdata->can_sleep = gpio_cansleep(gpio); bdata->can_sleep = gpio_cansleep(gpio);
...@@ -306,7 +292,7 @@ static int gpio_keys_polled_probe(struct platform_device *pdev) ...@@ -306,7 +292,7 @@ static int gpio_keys_polled_probe(struct platform_device *pdev)
if (error) { if (error) {
dev_err(dev, "unable to register polled device, err=%d\n", dev_err(dev, "unable to register polled device, err=%d\n",
error); error);
goto err_free_gpio; return error;
} }
/* report initial state of the buttons */ /* report initial state of the buttons */
...@@ -315,52 +301,10 @@ static int gpio_keys_polled_probe(struct platform_device *pdev) ...@@ -315,52 +301,10 @@ static int gpio_keys_polled_probe(struct platform_device *pdev)
&bdev->data[i]); &bdev->data[i]);
return 0; 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 = { static struct platform_driver gpio_keys_polled_driver = {
.probe = gpio_keys_polled_probe, .probe = gpio_keys_polled_probe,
.remove = gpio_keys_polled_remove,
.driver = { .driver = {
.name = DRV_NAME, .name = DRV_NAME,
.owner = THIS_MODULE, .owner = THIS_MODULE,
......
...@@ -415,7 +415,7 @@ static int imx_keypad_open(struct input_dev *dev) ...@@ -415,7 +415,7 @@ static int imx_keypad_open(struct input_dev *dev)
} }
#ifdef CONFIG_OF #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", }, { .compatible = "fsl,imx21-kpp", },
{ /* sentinel */ } { /* sentinel */ }
}; };
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
* published by the Free Software Foundation. * published by the Free Software Foundation.
*/ */
#include <linux/device.h>
#include <linux/input.h> #include <linux/input.h>
#include <linux/input-polldev.h> #include <linux/input-polldev.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
...@@ -185,14 +186,15 @@ static int jornada680kbd_probe(struct platform_device *pdev) ...@@ -185,14 +186,15 @@ static int jornada680kbd_probe(struct platform_device *pdev)
struct input_dev *input_dev; struct input_dev *input_dev;
int i, error; int i, error;
jornadakbd = kzalloc(sizeof(struct jornadakbd), GFP_KERNEL); jornadakbd = devm_kzalloc(&pdev->dev, sizeof(struct jornadakbd),
GFP_KERNEL);
if (!jornadakbd) if (!jornadakbd)
return -ENOMEM; return -ENOMEM;
poll_dev = input_allocate_polled_device(); poll_dev = devm_input_allocate_polled_device(&pdev->dev);
if (!poll_dev) { if (!poll_dev) {
error = -ENOMEM; dev_err(&pdev->dev, "failed to allocate polled input device\n");
goto failed; return -ENOMEM;
} }
platform_set_drvdata(pdev, jornadakbd); platform_set_drvdata(pdev, jornadakbd);
...@@ -224,27 +226,10 @@ static int jornada680kbd_probe(struct platform_device *pdev) ...@@ -224,27 +226,10 @@ static int jornada680kbd_probe(struct platform_device *pdev)
input_set_capability(input_dev, EV_MSC, MSC_SCAN); input_set_capability(input_dev, EV_MSC, MSC_SCAN);
error = input_register_polled_device(jornadakbd->poll_dev); error = input_register_polled_device(jornadakbd->poll_dev);
if (error) if (error) {
goto failed; dev_err(&pdev->dev, "failed to register polled input device\n");
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; 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);
return 0; return 0;
} }
...@@ -255,7 +240,6 @@ static struct platform_driver jornada680kbd_driver = { ...@@ -255,7 +240,6 @@ static struct platform_driver jornada680kbd_driver = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
}, },
.probe = jornada680kbd_probe, .probe = jornada680kbd_probe,
.remove = jornada680kbd_remove,
}; };
module_platform_driver(jornada680kbd_driver); module_platform_driver(jornada680kbd_driver);
......
...@@ -147,7 +147,7 @@ static int mcs_touchkey_probe(struct i2c_client *client, ...@@ -147,7 +147,7 @@ static int mcs_touchkey_probe(struct i2c_client *client,
} }
dev_info(&client->dev, "Firmware version: %d\n", fw_ver); 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->id.bustype = BUS_I2C;
input_dev->dev.parent = &client->dev; input_dev->dev.parent = &client->dev;
input_dev->evbit[0] = BIT_MASK(EV_KEY); input_dev->evbit[0] = BIT_MASK(EV_KEY);
......
...@@ -28,11 +28,10 @@ ...@@ -28,11 +28,10 @@
#include <linux/io.h> #include <linux/io.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/input.h> #include <linux/input.h>
#include <linux/input/matrix_keypad.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/platform_data/omap4-keypad.h>
/* OMAP4 registers */ /* OMAP4 registers */
#define OMAP4_KBD_REVISION 0x00 #define OMAP4_KBD_REVISION 0x00
#define OMAP4_KBD_SYSCONFIG 0x10 #define OMAP4_KBD_SYSCONFIG 0x10
...@@ -218,7 +217,6 @@ static void omap4_keypad_close(struct input_dev *input) ...@@ -218,7 +217,6 @@ static void omap4_keypad_close(struct input_dev *input)
pm_runtime_put_sync(input->dev.parent); pm_runtime_put_sync(input->dev.parent);
} }
#ifdef CONFIG_OF
static int omap4_keypad_parse_dt(struct device *dev, static int omap4_keypad_parse_dt(struct device *dev,
struct omap4_keypad *keypad_data) struct omap4_keypad *keypad_data)
{ {
...@@ -235,20 +233,9 @@ static int omap4_keypad_parse_dt(struct device *dev, ...@@ -235,20 +233,9 @@ static int omap4_keypad_parse_dt(struct device *dev,
return 0; 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) 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 omap4_keypad *keypad_data;
struct input_dev *input_dev; struct input_dev *input_dev;
struct resource *res; struct resource *res;
...@@ -277,14 +264,9 @@ static int omap4_keypad_probe(struct platform_device *pdev) ...@@ -277,14 +264,9 @@ static int omap4_keypad_probe(struct platform_device *pdev)
keypad_data->irq = irq; 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); error = omap4_keypad_parse_dt(&pdev->dev, keypad_data);
if (error) if (error)
return error; return error;
}
res = request_mem_region(res->start, resource_size(res), pdev->name); res = request_mem_region(res->start, resource_size(res), pdev->name);
if (!res) { if (!res) {
...@@ -363,7 +345,7 @@ static int omap4_keypad_probe(struct platform_device *pdev) ...@@ -363,7 +345,7 @@ static int omap4_keypad_probe(struct platform_device *pdev)
goto err_free_input; 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->rows, keypad_data->cols,
keypad_data->keymap, input_dev); keypad_data->keymap, input_dev);
if (error) { if (error) {
...@@ -434,13 +416,11 @@ static int omap4_keypad_remove(struct platform_device *pdev) ...@@ -434,13 +416,11 @@ static int omap4_keypad_remove(struct platform_device *pdev)
return 0; return 0;
} }
#ifdef CONFIG_OF
static const struct of_device_id omap_keypad_dt_match[] = { static const struct of_device_id omap_keypad_dt_match[] = {
{ .compatible = "ti,omap4-keypad" }, { .compatible = "ti,omap4-keypad" },
{}, {},
}; };
MODULE_DEVICE_TABLE(of, omap_keypad_dt_match); MODULE_DEVICE_TABLE(of, omap_keypad_dt_match);
#endif
#ifdef CONFIG_PM_SLEEP #ifdef CONFIG_PM_SLEEP
static int omap4_keypad_suspend(struct device *dev) static int omap4_keypad_suspend(struct device *dev)
...@@ -482,7 +462,7 @@ static struct platform_driver omap4_keypad_driver = { ...@@ -482,7 +462,7 @@ static struct platform_driver omap4_keypad_driver = {
.name = "omap4-keypad", .name = "omap4-keypad",
.owner = THIS_MODULE, .owner = THIS_MODULE,
.pm = &omap4_keypad_pm_ops, .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); module_platform_driver(omap4_keypad_driver);
......
/*
* 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) ...@@ -296,6 +296,65 @@ static void tc3589x_keypad_close(struct input_dev *input)
tc3589x_keypad_disable(keypad); 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) static int tc3589x_keypad_probe(struct platform_device *pdev)
{ {
struct tc3589x *tc3589x = dev_get_drvdata(pdev->dev.parent); struct tc3589x *tc3589x = dev_get_drvdata(pdev->dev.parent);
...@@ -306,8 +365,11 @@ static int tc3589x_keypad_probe(struct platform_device *pdev) ...@@ -306,8 +365,11 @@ static int tc3589x_keypad_probe(struct platform_device *pdev)
plat = tc3589x->pdata->keypad; plat = tc3589x->pdata->keypad;
if (!plat) { if (!plat) {
plat = tc3589x_keypad_of_probe(&pdev->dev);
if (IS_ERR(plat)) {
dev_err(&pdev->dev, "invalid keypad platform data\n"); dev_err(&pdev->dev, "invalid keypad platform data\n");
return -EINVAL; return PTR_ERR(plat);
}
} }
irq = platform_get_irq(pdev, 0); irq = platform_get_irq(pdev, 0);
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/mfd/88pm860x.h> #include <linux/mfd/88pm860x.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/device.h>
#define PM8607_WAKEUP 0x0b #define PM8607_WAKEUP 0x0b
...@@ -68,7 +69,8 @@ static int pm860x_onkey_probe(struct platform_device *pdev) ...@@ -68,7 +69,8 @@ static int pm860x_onkey_probe(struct platform_device *pdev)
return -EINVAL; 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) if (!info)
return -ENOMEM; return -ENOMEM;
info->chip = chip; info->chip = chip;
...@@ -76,11 +78,10 @@ static int pm860x_onkey_probe(struct platform_device *pdev) ...@@ -76,11 +78,10 @@ static int pm860x_onkey_probe(struct platform_device *pdev)
info->dev = &pdev->dev; info->dev = &pdev->dev;
info->irq = irq; info->irq = irq;
info->idev = input_allocate_device(); info->idev = devm_input_allocate_device(&pdev->dev);
if (!info->idev) { if (!info->idev) {
dev_err(chip->dev, "Failed to allocate input dev\n"); dev_err(chip->dev, "Failed to allocate input dev\n");
ret = -ENOMEM; return -ENOMEM;
goto out;
} }
info->idev->name = "88pm860x_on"; info->idev->name = "88pm860x_on";
...@@ -93,42 +94,22 @@ static int pm860x_onkey_probe(struct platform_device *pdev) ...@@ -93,42 +94,22 @@ static int pm860x_onkey_probe(struct platform_device *pdev)
ret = input_register_device(info->idev); ret = input_register_device(info->idev);
if (ret) { if (ret) {
dev_err(chip->dev, "Can't register input device: %d\n", 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, ret = devm_request_threaded_irq(&pdev->dev, info->irq, NULL,
IRQF_ONESHOT, "onkey", info); pm860x_onkey_handler, IRQF_ONESHOT,
"onkey", info);
if (ret < 0) { if (ret < 0) {
dev_err(chip->dev, "Failed to request IRQ: #%d: %d\n", dev_err(chip->dev, "Failed to request IRQ: #%d: %d\n",
info->irq, ret); info->irq, ret);
goto out_irq; return ret;
} }
platform_set_drvdata(pdev, info); platform_set_drvdata(pdev, info);
device_init_wakeup(&pdev->dev, 1); device_init_wakeup(&pdev->dev, 1);
return 0; 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 #ifdef CONFIG_PM_SLEEP
...@@ -161,7 +142,6 @@ static struct platform_driver pm860x_onkey_driver = { ...@@ -161,7 +142,6 @@ static struct platform_driver pm860x_onkey_driver = {
.pm = &pm860x_onkey_pm_ops, .pm = &pm860x_onkey_pm_ops,
}, },
.probe = pm860x_onkey_probe, .probe = pm860x_onkey_probe,
.remove = pm860x_onkey_remove,
}; };
module_platform_driver(pm860x_onkey_driver); module_platform_driver(pm860x_onkey_driver);
......
...@@ -224,7 +224,7 @@ config INPUT_GP2A ...@@ -224,7 +224,7 @@ config INPUT_GP2A
config INPUT_GPIO_BEEPER config INPUT_GPIO_BEEPER
tristate "Generic GPIO Beeper support" tristate "Generic GPIO Beeper support"
depends on OF_GPIO depends on GPIOLIB
help help
Say Y here if you have a beeper connected to a GPIO pin. Say Y here if you have a beeper connected to a GPIO pin.
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
* AB8500 Power-On Key handler * AB8500 Power-On Key handler
*/ */
#include <linux/device.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
...@@ -65,12 +66,14 @@ static int ab8500_ponkey_probe(struct platform_device *pdev) ...@@ -65,12 +66,14 @@ static int ab8500_ponkey_probe(struct platform_device *pdev)
return irq_dbr; return irq_dbr;
} }
ponkey = kzalloc(sizeof(struct ab8500_ponkey), GFP_KERNEL); ponkey = devm_kzalloc(&pdev->dev, sizeof(struct ab8500_ponkey),
input = input_allocate_device(); GFP_KERNEL);
if (!ponkey || !input) { if (!ponkey)
error = -ENOMEM; return -ENOMEM;
goto err_free_mem;
} input = devm_input_allocate_device(&pdev->dev);
if (!input)
return -ENOMEM;
ponkey->idev = input; ponkey->idev = input;
ponkey->ab8500 = ab8500; ponkey->ab8500 = ab8500;
...@@ -82,52 +85,32 @@ static int ab8500_ponkey_probe(struct platform_device *pdev) ...@@ -82,52 +85,32 @@ static int ab8500_ponkey_probe(struct platform_device *pdev)
input_set_capability(input, EV_KEY, KEY_POWER); input_set_capability(input, EV_KEY, KEY_POWER);
error = request_any_context_irq(ponkey->irq_dbf, ab8500_ponkey_handler, error = devm_request_any_context_irq(&pdev->dev, ponkey->irq_dbf,
0, "ab8500-ponkey-dbf", ponkey); ab8500_ponkey_handler, 0,
"ab8500-ponkey-dbf", ponkey);
if (error < 0) { if (error < 0) {
dev_err(ab8500->dev, "Failed to request dbf IRQ#%d: %d\n", dev_err(ab8500->dev, "Failed to request dbf IRQ#%d: %d\n",
ponkey->irq_dbf, error); ponkey->irq_dbf, error);
goto err_free_mem; return error;
} }
error = request_any_context_irq(ponkey->irq_dbr, ab8500_ponkey_handler, error = devm_request_any_context_irq(&pdev->dev, ponkey->irq_dbr,
0, "ab8500-ponkey-dbr", ponkey); ab8500_ponkey_handler, 0,
"ab8500-ponkey-dbr", ponkey);
if (error < 0) { if (error < 0) {
dev_err(ab8500->dev, "Failed to request dbr IRQ#%d: %d\n", dev_err(ab8500->dev, "Failed to request dbr IRQ#%d: %d\n",
ponkey->irq_dbr, error); ponkey->irq_dbr, error);
goto err_free_dbf_irq; return error;
} }
error = input_register_device(ponkey->idev); error = input_register_device(ponkey->idev);
if (error) { if (error) {
dev_err(ab8500->dev, "Can't register input device: %d\n", 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); platform_set_drvdata(pdev, ponkey);
return 0; 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 #ifdef CONFIG_OF
...@@ -144,7 +127,6 @@ static struct platform_driver ab8500_ponkey_driver = { ...@@ -144,7 +127,6 @@ static struct platform_driver ab8500_ponkey_driver = {
.of_match_table = of_match_ptr(ab8500_ponkey_match), .of_match_table = of_match_ptr(ab8500_ponkey_match),
}, },
.probe = ab8500_ponkey_probe, .probe = ab8500_ponkey_probe,
.remove = ab8500_ponkey_remove,
}; };
module_platform_driver(ab8500_ponkey_driver); module_platform_driver(ab8500_ponkey_driver);
......
/* /*
* Generic GPIO beeper driver * 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 * 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 * it under the terms of the GNU General Public License as published by
...@@ -11,7 +11,8 @@ ...@@ -11,7 +11,8 @@
#include <linux/input.h> #include <linux/input.h>
#include <linux/module.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/workqueue.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
...@@ -19,14 +20,13 @@ ...@@ -19,14 +20,13 @@
struct gpio_beeper { struct gpio_beeper {
struct work_struct work; struct work_struct work;
int gpio; struct gpio_desc *desc;
bool active_low;
bool beeping; bool beeping;
}; };
static void gpio_beeper_toggle(struct gpio_beeper *beep, bool on) 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) static void gpio_beeper_work(struct work_struct *work)
...@@ -65,18 +65,16 @@ static void gpio_beeper_close(struct input_dev *input) ...@@ -65,18 +65,16 @@ static void gpio_beeper_close(struct input_dev *input)
static int gpio_beeper_probe(struct platform_device *pdev) static int gpio_beeper_probe(struct platform_device *pdev)
{ {
struct gpio_beeper *beep; struct gpio_beeper *beep;
enum of_gpio_flags flags;
struct input_dev *input; struct input_dev *input;
unsigned long gflags;
int err; int err;
beep = devm_kzalloc(&pdev->dev, sizeof(*beep), GFP_KERNEL); beep = devm_kzalloc(&pdev->dev, sizeof(*beep), GFP_KERNEL);
if (!beep) if (!beep)
return -ENOMEM; return -ENOMEM;
beep->gpio = of_get_gpio_flags(pdev->dev.of_node, 0, &flags); beep->desc = devm_gpiod_get(&pdev->dev, NULL);
if (!gpio_is_valid(beep->gpio)) if (IS_ERR(beep->desc))
return beep->gpio; return PTR_ERR(beep->desc);
input = devm_input_allocate_device(&pdev->dev); input = devm_input_allocate_device(&pdev->dev);
if (!input) if (!input)
...@@ -94,10 +92,7 @@ static int gpio_beeper_probe(struct platform_device *pdev) ...@@ -94,10 +92,7 @@ static int gpio_beeper_probe(struct platform_device *pdev)
input_set_capability(input, EV_SND, SND_BELL); input_set_capability(input, EV_SND, SND_BELL);
beep->active_low = flags & OF_GPIO_ACTIVE_LOW; err = gpiod_direction_output(beep->desc, 0);
gflags = beep->active_low ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW;
err = devm_gpio_request_one(&pdev->dev, beep->gpio, gflags, pdev->name);
if (err) if (err)
return err; return err;
...@@ -106,17 +101,19 @@ static int gpio_beeper_probe(struct platform_device *pdev) ...@@ -106,17 +101,19 @@ static int gpio_beeper_probe(struct platform_device *pdev)
return input_register_device(input); 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, }, { .compatible = BEEPER_MODNAME, },
{ } { }
}; };
MODULE_DEVICE_TABLE(of, gpio_beeper_of_match); MODULE_DEVICE_TABLE(of, gpio_beeper_of_match);
#endif
static struct platform_driver gpio_beeper_platform_driver = { static struct platform_driver gpio_beeper_platform_driver = {
.driver = { .driver = {
.name = BEEPER_MODNAME, .name = BEEPER_MODNAME,
.owner = THIS_MODULE, .owner = THIS_MODULE,
.of_match_table = gpio_beeper_of_match, .of_match_table = of_match_ptr(gpio_beeper_of_match),
}, },
.probe = gpio_beeper_probe, .probe = gpio_beeper_probe,
}; };
......
...@@ -1566,6 +1566,7 @@ static int ims_pcu_buffers_alloc(struct ims_pcu *pcu) ...@@ -1566,6 +1566,7 @@ static int ims_pcu_buffers_alloc(struct ims_pcu *pcu)
if (!pcu->urb_ctrl_buf) { if (!pcu->urb_ctrl_buf) {
dev_err(pcu->dev, dev_err(pcu->dev,
"Failed to allocate memory for read buffer\n"); "Failed to allocate memory for read buffer\n");
error = -ENOMEM;
goto err_free_urb_out_buf; goto err_free_urb_out_buf;
} }
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/mfd/max8925.h> #include <linux/mfd/max8925.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/device.h>
#define SW_INPUT (1 << 7) /* 0/1 -- up/down */ #define SW_INPUT (1 << 7) /* 0/1 -- up/down */
#define HARDRESET_EN (1 << 7) #define HARDRESET_EN (1 << 7)
...@@ -81,12 +82,14 @@ static int max8925_onkey_probe(struct platform_device *pdev) ...@@ -81,12 +82,14 @@ static int max8925_onkey_probe(struct platform_device *pdev)
return -EINVAL; return -EINVAL;
} }
info = kzalloc(sizeof(struct max8925_onkey_info), GFP_KERNEL); info = devm_kzalloc(&pdev->dev, sizeof(struct max8925_onkey_info),
input = input_allocate_device(); GFP_KERNEL);
if (!info || !input) { if (!info)
error = -ENOMEM; return -ENOMEM;
goto err_free_mem;
} input = devm_input_allocate_device(&pdev->dev);
if (!input)
return -ENOMEM;
info->idev = input; info->idev = input;
info->i2c = chip->i2c; info->i2c = chip->i2c;
...@@ -100,54 +103,33 @@ static int max8925_onkey_probe(struct platform_device *pdev) ...@@ -100,54 +103,33 @@ static int max8925_onkey_probe(struct platform_device *pdev)
input->dev.parent = &pdev->dev; input->dev.parent = &pdev->dev;
input_set_capability(input, EV_KEY, KEY_POWER); input_set_capability(input, EV_KEY, KEY_POWER);
error = request_threaded_irq(irq[0], NULL, max8925_onkey_handler, error = devm_request_threaded_irq(&pdev->dev, irq[0], NULL,
IRQF_ONESHOT, "onkey-down", info); max8925_onkey_handler, IRQF_ONESHOT,
"onkey-down", info);
if (error < 0) { if (error < 0) {
dev_err(chip->dev, "Failed to request IRQ: #%d: %d\n", dev_err(chip->dev, "Failed to request IRQ: #%d: %d\n",
irq[0], error); irq[0], error);
goto err_free_mem; return error;
} }
error = request_threaded_irq(irq[1], NULL, max8925_onkey_handler, error = devm_request_threaded_irq(&pdev->dev, irq[1], NULL,
IRQF_ONESHOT, "onkey-up", info); max8925_onkey_handler, IRQF_ONESHOT,
"onkey-up", info);
if (error < 0) { if (error < 0) {
dev_err(chip->dev, "Failed to request IRQ: #%d: %d\n", dev_err(chip->dev, "Failed to request IRQ: #%d: %d\n",
irq[1], error); irq[1], error);
goto err_free_irq0; return error;
} }
error = input_register_device(info->idev); error = input_register_device(info->idev);
if (error) { if (error) {
dev_err(chip->dev, "Can't register input device: %d\n", error); dev_err(chip->dev, "Can't register input device: %d\n", error);
goto err_free_irq1; return error;
} }
platform_set_drvdata(pdev, info); platform_set_drvdata(pdev, info);
device_init_wakeup(&pdev->dev, 1); 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; return 0;
} }
...@@ -190,7 +172,6 @@ static struct platform_driver max8925_onkey_driver = { ...@@ -190,7 +172,6 @@ static struct platform_driver max8925_onkey_driver = {
.pm = &max8925_onkey_pm_ops, .pm = &max8925_onkey_pm_ops,
}, },
.probe = max8925_onkey_probe, .probe = max8925_onkey_probe,
.remove = max8925_onkey_remove,
}; };
module_platform_driver(max8925_onkey_driver); module_platform_driver(max8925_onkey_driver);
......
...@@ -181,11 +181,21 @@ static void max8997_haptic_enable(struct max8997_haptic *chip) ...@@ -181,11 +181,21 @@ static void max8997_haptic_enable(struct max8997_haptic *chip)
} }
if (!chip->enabled) { if (!chip->enabled) {
chip->enabled = true; error = regulator_enable(chip->regulator);
regulator_enable(chip->regulator); if (error) {
dev_err(chip->dev, "Failed to enable regulator\n");
goto out;
}
max8997_haptic_configure(chip); max8997_haptic_configure(chip);
if (chip->mode == MAX8997_EXTERNAL_MODE) if (chip->mode == MAX8997_EXTERNAL_MODE) {
pwm_enable(chip->pwm); 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: out:
......
...@@ -92,15 +92,15 @@ static int pmic8xxx_pwrkey_probe(struct platform_device *pdev) ...@@ -92,15 +92,15 @@ static int pmic8xxx_pwrkey_probe(struct platform_device *pdev)
bool pull_up; bool pull_up;
if (of_property_read_u32(pdev->dev.of_node, "debounce", &kpd_delay)) 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 || kpd_delay == 0) {
if (kpd_delay > 62500) {
dev_err(&pdev->dev, "invalid power key trigger delay\n"); dev_err(&pdev->dev, "invalid power key trigger delay\n");
return -EINVAL; return -EINVAL;
} }
pull_up = of_property_read_bool(pdev->dev.of_node, "pull-up");
regmap = dev_get_regmap(pdev->dev.parent, NULL); regmap = dev_get_regmap(pdev->dev.parent, NULL);
if (!regmap) { if (!regmap) {
dev_err(&pdev->dev, "failed to locate regmap for the device\n"); 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) ...@@ -143,7 +143,7 @@ static irqreturn_t rotary_encoder_half_period_irq(int irq, void *dev_id)
} }
#ifdef CONFIG_OF #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", }, { .compatible = "rotary-encoder", },
{ }, { },
}; };
......
...@@ -17,7 +17,6 @@ ...@@ -17,7 +17,6 @@
#include <linux/acpi.h> #include <linux/acpi.h>
#include <linux/gpio/consumer.h> #include <linux/gpio/consumer.h>
#include <linux/gpio_keys.h> #include <linux/gpio_keys.h>
#include <linux/input.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/pnp.h> #include <linux/pnp.h>
......
...@@ -262,7 +262,7 @@ static int twl6040_vibra_probe(struct platform_device *pdev) ...@@ -262,7 +262,7 @@ static int twl6040_vibra_probe(struct platform_device *pdev)
struct vibra_info *info; struct vibra_info *info;
int vddvibl_uV = 0; int vddvibl_uV = 0;
int vddvibr_uV = 0; int vddvibr_uV = 0;
int ret; int error;
twl6040_core_node = of_find_node_by_name(twl6040_core_dev->of_node, twl6040_core_node = of_find_node_by_name(twl6040_core_dev->of_node,
"vibra"); "vibra");
...@@ -309,12 +309,12 @@ static int twl6040_vibra_probe(struct platform_device *pdev) ...@@ -309,12 +309,12 @@ static int twl6040_vibra_probe(struct platform_device *pdev)
mutex_init(&info->mutex); mutex_init(&info->mutex);
ret = devm_request_threaded_irq(&pdev->dev, info->irq, NULL, error = devm_request_threaded_irq(&pdev->dev, info->irq, NULL,
twl6040_vib_irq_handler, 0, twl6040_vib_irq_handler, 0,
"twl6040_irq_vib", info); "twl6040_irq_vib", info);
if (ret) { if (error) {
dev_err(info->dev, "VIB IRQ request failed: %d\n", ret); dev_err(info->dev, "VIB IRQ request failed: %d\n", error);
return ret; return error;
} }
info->supplies[0].supply = "vddvibl"; info->supplies[0].supply = "vddvibl";
...@@ -323,40 +323,40 @@ static int twl6040_vibra_probe(struct platform_device *pdev) ...@@ -323,40 +323,40 @@ static int twl6040_vibra_probe(struct platform_device *pdev)
* When booted with Device tree the regulators are attached to the * When booted with Device tree the regulators are attached to the
* parent device (twl6040 MFD core) * parent device (twl6040 MFD core)
*/ */
ret = regulator_bulk_get(twl6040_core_dev, ARRAY_SIZE(info->supplies), error = devm_regulator_bulk_get(twl6040_core_dev,
ARRAY_SIZE(info->supplies),
info->supplies); info->supplies);
if (ret) { if (error) {
dev_err(info->dev, "couldn't get regulators %d\n", ret); dev_err(info->dev, "couldn't get regulators %d\n", error);
return ret; return error;
} }
if (vddvibl_uV) { if (vddvibl_uV) {
ret = regulator_set_voltage(info->supplies[0].consumer, error = regulator_set_voltage(info->supplies[0].consumer,
vddvibl_uV, vddvibl_uV); vddvibl_uV, vddvibl_uV);
if (ret) { if (error) {
dev_err(info->dev, "failed to set VDDVIBL volt %d\n", dev_err(info->dev, "failed to set VDDVIBL volt %d\n",
ret); error);
goto err_regulator; return error;
} }
} }
if (vddvibr_uV) { if (vddvibr_uV) {
ret = regulator_set_voltage(info->supplies[1].consumer, error = regulator_set_voltage(info->supplies[1].consumer,
vddvibr_uV, vddvibr_uV); vddvibr_uV, vddvibr_uV);
if (ret) { if (error) {
dev_err(info->dev, "failed to set VDDVIBR volt %d\n", dev_err(info->dev, "failed to set VDDVIBR volt %d\n",
ret); error);
goto err_regulator; return error;
} }
} }
INIT_WORK(&info->play_work, vibra_play_work); INIT_WORK(&info->play_work, vibra_play_work);
info->input_dev = input_allocate_device(); info->input_dev = devm_input_allocate_device(&pdev->dev);
if (info->input_dev == NULL) { if (!info->input_dev) {
dev_err(info->dev, "couldn't allocate input device\n"); dev_err(info->dev, "couldn't allocate input device\n");
ret = -ENOMEM; return -ENOMEM;
goto err_regulator;
} }
input_set_drvdata(info->input_dev, info); input_set_drvdata(info->input_dev, info);
...@@ -367,44 +367,25 @@ static int twl6040_vibra_probe(struct platform_device *pdev) ...@@ -367,44 +367,25 @@ static int twl6040_vibra_probe(struct platform_device *pdev)
info->input_dev->close = twl6040_vibra_close; info->input_dev->close = twl6040_vibra_close;
__set_bit(FF_RUMBLE, info->input_dev->ffbit); __set_bit(FF_RUMBLE, info->input_dev->ffbit);
ret = input_ff_create_memless(info->input_dev, NULL, vibra_play); error = input_ff_create_memless(info->input_dev, NULL, vibra_play);
if (ret < 0) { if (error) {
dev_err(info->dev, "couldn't register vibrator to FF\n"); dev_err(info->dev, "couldn't register vibrator to FF\n");
goto err_ialloc; return error;
} }
ret = input_register_device(info->input_dev); error = input_register_device(info->input_dev);
if (ret < 0) { if (error) {
dev_err(info->dev, "couldn't register input device\n"); dev_err(info->dev, "couldn't register input device\n");
goto err_iff; return error;
} }
platform_set_drvdata(pdev, info); 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; return 0;
} }
static struct platform_driver twl6040_vibra_driver = { static struct platform_driver twl6040_vibra_driver = {
.probe = twl6040_vibra_probe, .probe = twl6040_vibra_probe,
.remove = twl6040_vibra_remove,
.driver = { .driver = {
.name = "twl6040-vibra", .name = "twl6040-vibra",
.owner = THIS_MODULE, .owner = THIS_MODULE,
......
...@@ -53,7 +53,7 @@ config MOUSE_PS2_LOGIPS2PP ...@@ -53,7 +53,7 @@ config MOUSE_PS2_LOGIPS2PP
default y default y
depends on MOUSE_PS2 depends on MOUSE_PS2
help 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. your system.
If unsure, say Y. If unsure, say Y.
......
...@@ -473,8 +473,15 @@ static void elantech_report_absolute_v3(struct psmouse *psmouse, ...@@ -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_FINGER, fingers == 1);
input_report_key(dev, BTN_TOOL_DOUBLETAP, fingers == 2); input_report_key(dev, BTN_TOOL_DOUBLETAP, fingers == 2);
input_report_key(dev, BTN_TOOL_TRIPLETAP, fingers == 3); input_report_key(dev, BTN_TOOL_TRIPLETAP, fingers == 3);
/* 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_LEFT, packet[0] & 0x01);
input_report_key(dev, BTN_RIGHT, packet[0] & 0x02); input_report_key(dev, BTN_RIGHT, packet[0] & 0x02);
}
input_report_abs(dev, ABS_PRESSURE, pres); input_report_abs(dev, ABS_PRESSURE, pres);
input_report_abs(dev, ABS_TOOL_WIDTH, width); input_report_abs(dev, ABS_TOOL_WIDTH, width);
...@@ -484,10 +491,17 @@ static void elantech_report_absolute_v3(struct psmouse *psmouse, ...@@ -484,10 +491,17 @@ static void elantech_report_absolute_v3(struct psmouse *psmouse,
static void elantech_input_sync_v4(struct psmouse *psmouse) static void elantech_input_sync_v4(struct psmouse *psmouse)
{ {
struct input_dev *dev = psmouse->dev; struct input_dev *dev = psmouse->dev;
struct elantech_data *etd = psmouse->private;
unsigned char *packet = psmouse->packet; unsigned char *packet = psmouse->packet;
/* 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_LEFT, packet[0] & 0x01);
input_report_key(dev, BTN_RIGHT, packet[0] & 0x02); input_report_key(dev, BTN_RIGHT, packet[0] & 0x02);
}
input_mt_report_pointer_emulation(dev, true); input_mt_report_pointer_emulation(dev, true);
input_sync(dev); input_sync(dev);
} }
...@@ -835,7 +849,7 @@ static int elantech_set_absolute_mode(struct psmouse *psmouse) ...@@ -835,7 +849,7 @@ static int elantech_set_absolute_mode(struct psmouse *psmouse)
if (etd->set_hw_resolution) if (etd->set_hw_resolution)
etd->reg_10 = 0x0b; etd->reg_10 = 0x0b;
else else
etd->reg_10 = 0x03; etd->reg_10 = 0x01;
if (elantech_write_reg(psmouse, 0x10, etd->reg_10)) if (elantech_write_reg(psmouse, 0x10, etd->reg_10))
rc = -1; rc = -1;
...@@ -1336,7 +1350,8 @@ static int elantech_reconnect(struct psmouse *psmouse) ...@@ -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[] = { static const struct dmi_system_id no_hw_res_dmi_table[] = {
#if defined(CONFIG_DMI) && defined(CONFIG_X86) #if defined(CONFIG_DMI) && defined(CONFIG_X86)
......
...@@ -347,15 +347,6 @@ static int synaptics_resolution(struct psmouse *psmouse) ...@@ -347,15 +347,6 @@ static int synaptics_resolution(struct psmouse *psmouse)
unsigned char resp[3]; unsigned char resp[3];
int i; 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) if (SYN_ID_MAJOR(priv->identity) < 4)
return 0; return 0;
...@@ -366,6 +357,16 @@ static int synaptics_resolution(struct psmouse *psmouse) ...@@ -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 && if (SYN_EXT_CAP_REQUESTS(priv->capabilities) >= 5 &&
SYN_CAP_MAX_DIMENSIONS(priv->ext_cap_0c)) { SYN_CAP_MAX_DIMENSIONS(priv->ext_cap_0c)) {
if (synaptics_send_cmd(psmouse, SYN_QUE_EXT_MAX_COORDS, resp)) { 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) ...@@ -203,7 +203,7 @@ static int apbps2_of_remove(struct platform_device *of_dev)
return 0; return 0;
} }
static struct of_device_id apbps2_of_match[] = { static const struct of_device_id apbps2_of_match[] = {
{ .name = "GAISLER_APBPS2", }, { .name = "GAISLER_APBPS2", },
{ .name = "01_060", }, { .name = "01_060", },
{} {}
......
...@@ -262,7 +262,7 @@ static int olpc_apsp_remove(struct platform_device *pdev) ...@@ -262,7 +262,7 @@ static int olpc_apsp_remove(struct platform_device *pdev)
return 0; 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", }, { .compatible = "olpc,ap-sp", },
{} {}
}; };
......
...@@ -349,6 +349,7 @@ static int wacom_parse_hid(struct usb_interface *intf, ...@@ -349,6 +349,7 @@ static int wacom_parse_hid(struct usb_interface *intf,
break; break;
case MTTPC: case MTTPC:
case MTTPC_B:
features->pktlen = WACOM_PKGLEN_MTTPC; features->pktlen = WACOM_PKGLEN_MTTPC;
break; break;
...@@ -380,6 +381,16 @@ static int wacom_parse_hid(struct usb_interface *intf, ...@@ -380,6 +381,16 @@ static int wacom_parse_hid(struct usb_interface *intf,
i += 12; i += 12;
break; 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: default:
features->x_max = features->x_max =
get_unaligned_le16(&report[i + 3]); get_unaligned_le16(&report[i + 3]);
...@@ -430,6 +441,14 @@ static int wacom_parse_hid(struct usb_interface *intf, ...@@ -430,6 +441,14 @@ static int wacom_parse_hid(struct usb_interface *intf,
i += 12; i += 12;
break; 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: default:
features->y_max = features->y_max =
features->x_max; features->x_max;
......
This diff is collapsed.
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#define WACOM_PKGLEN_BBFUN 9 #define WACOM_PKGLEN_BBFUN 9
#define WACOM_PKGLEN_INTUOS 10 #define WACOM_PKGLEN_INTUOS 10
#define WACOM_PKGLEN_TPC1FG 5 #define WACOM_PKGLEN_TPC1FG 5
#define WACOM_PKGLEN_TPC1FG_B 10
#define WACOM_PKGLEN_TPC2FG 14 #define WACOM_PKGLEN_TPC2FG 14
#define WACOM_PKGLEN_BBTOUCH 20 #define WACOM_PKGLEN_BBTOUCH 20
#define WACOM_PKGLEN_BBTOUCH3 64 #define WACOM_PKGLEN_BBTOUCH3 64
...@@ -30,6 +31,7 @@ ...@@ -30,6 +31,7 @@
#define WACOM_PKGLEN_MTOUCH 62 #define WACOM_PKGLEN_MTOUCH 62
#define WACOM_PKGLEN_MTTPC 40 #define WACOM_PKGLEN_MTTPC 40
#define WACOM_PKGLEN_DTUS 68 #define WACOM_PKGLEN_DTUS 68
#define WACOM_PKGLEN_PENABLED 8
/* wacom data size per MT contact */ /* wacom data size per MT contact */
#define WACOM_BYTES_PER_MT_PACKET 11 #define WACOM_BYTES_PER_MT_PACKET 11
...@@ -52,6 +54,7 @@ ...@@ -52,6 +54,7 @@
#define WACOM_REPORT_TPC1FG 6 #define WACOM_REPORT_TPC1FG 6
#define WACOM_REPORT_TPC2FG 13 #define WACOM_REPORT_TPC2FG 13
#define WACOM_REPORT_TPCMT 13 #define WACOM_REPORT_TPCMT 13
#define WACOM_REPORT_TPCMT2 3
#define WACOM_REPORT_TPCHID 15 #define WACOM_REPORT_TPCHID 15
#define WACOM_REPORT_TPCST 16 #define WACOM_REPORT_TPCST 16
#define WACOM_REPORT_DTUS 17 #define WACOM_REPORT_DTUS 17
...@@ -105,6 +108,7 @@ enum { ...@@ -105,6 +108,7 @@ enum {
TABLETPC2FG, TABLETPC2FG,
MTSCREEN, MTSCREEN,
MTTPC, MTTPC,
MTTPC_B,
MAX_TYPE MAX_TYPE
}; };
...@@ -118,6 +122,8 @@ struct wacom_features { ...@@ -118,6 +122,8 @@ struct wacom_features {
int type; int type;
int x_resolution; int x_resolution;
int y_resolution; int y_resolution;
int x_min;
int y_min;
int device_type; int device_type;
int x_phy; int x_phy;
int y_phy; int y_phy;
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <linux/input.h> #include <linux/input.h>
#include <linux/mfd/88pm860x.h> #include <linux/mfd/88pm860x.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/device.h>
#define MEAS_LEN (8) #define MEAS_LEN (8)
#define ACCURATE_BIT (12) #define ACCURATE_BIT (12)
...@@ -234,16 +235,17 @@ static int pm860x_touch_probe(struct platform_device *pdev) ...@@ -234,16 +235,17 @@ static int pm860x_touch_probe(struct platform_device *pdev)
if (ret) if (ret)
return ret; return ret;
touch = kzalloc(sizeof(struct pm860x_touch), GFP_KERNEL); touch = devm_kzalloc(&pdev->dev, sizeof(struct pm860x_touch),
if (touch == NULL) GFP_KERNEL);
if (!touch)
return -ENOMEM; return -ENOMEM;
platform_set_drvdata(pdev, touch); platform_set_drvdata(pdev, touch);
touch->idev = input_allocate_device(); touch->idev = devm_input_allocate_device(&pdev->dev);
if (touch->idev == NULL) { if (!touch->idev) {
dev_err(&pdev->dev, "Failed to allocate input device!\n"); dev_err(&pdev->dev, "Failed to allocate input device!\n");
ret = -ENOMEM; return -ENOMEM;
goto out;
} }
touch->idev->name = "88pm860x-touch"; touch->idev->name = "88pm860x-touch";
...@@ -258,10 +260,11 @@ static int pm860x_touch_probe(struct platform_device *pdev) ...@@ -258,10 +260,11 @@ static int pm860x_touch_probe(struct platform_device *pdev)
touch->res_x = res_x; touch->res_x = res_x;
input_set_drvdata(touch->idev, touch); input_set_drvdata(touch->idev, touch);
ret = request_threaded_irq(touch->irq, NULL, pm860x_touch_handler, ret = devm_request_threaded_irq(&pdev->dev, touch->irq, NULL,
IRQF_ONESHOT, "touch", touch); pm860x_touch_handler, IRQF_ONESHOT,
"touch", touch);
if (ret < 0) if (ret < 0)
goto out_irq; return ret;
__set_bit(EV_ABS, touch->idev->evbit); __set_bit(EV_ABS, touch->idev->evbit);
__set_bit(ABS_X, touch->idev->absbit); __set_bit(ABS_X, touch->idev->absbit);
...@@ -279,28 +282,11 @@ static int pm860x_touch_probe(struct platform_device *pdev) ...@@ -279,28 +282,11 @@ static int pm860x_touch_probe(struct platform_device *pdev)
ret = input_register_device(touch->idev); ret = input_register_device(touch->idev);
if (ret < 0) { if (ret < 0) {
dev_err(chip->dev, "Failed to register touch!\n"); dev_err(chip->dev, "Failed to register touch!\n");
goto out_rg; return ret;
} }
platform_set_drvdata(pdev, touch); platform_set_drvdata(pdev, touch);
return 0; 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 = { static struct platform_driver pm860x_touch_driver = {
...@@ -309,7 +295,6 @@ static struct platform_driver pm860x_touch_driver = { ...@@ -309,7 +295,6 @@ static struct platform_driver pm860x_touch_driver = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
}, },
.probe = pm860x_touch_probe, .probe = pm860x_touch_probe,
.remove = pm860x_touch_remove,
}; };
module_platform_driver(pm860x_touch_driver); module_platform_driver(pm860x_touch_driver);
......
...@@ -11,6 +11,10 @@ menuconfig INPUT_TOUCHSCREEN ...@@ -11,6 +11,10 @@ menuconfig INPUT_TOUCHSCREEN
if INPUT_TOUCHSCREEN if INPUT_TOUCHSCREEN
config OF_TOUCHSCREEN
def_tristate INPUT
depends on INPUT && OF
config TOUCHSCREEN_88PM860X config TOUCHSCREEN_88PM860X
tristate "Marvell 88PM860x touchscreen" tristate "Marvell 88PM860x touchscreen"
depends on MFD_88PM860X depends on MFD_88PM860X
...@@ -89,6 +93,7 @@ config TOUCHSCREEN_AD7879_SPI ...@@ -89,6 +93,7 @@ config TOUCHSCREEN_AD7879_SPI
config TOUCHSCREEN_ATMEL_MXT config TOUCHSCREEN_ATMEL_MXT
tristate "Atmel mXT I2C Touchscreen" tristate "Atmel mXT I2C Touchscreen"
depends on I2C depends on I2C
select FW_LOADER
help help
Say Y here if you have Atmel mXT series I2C touchscreen, Say Y here if you have Atmel mXT series I2C touchscreen,
such as AT42QT602240/ATMXT224, connected to your system. such as AT42QT602240/ATMXT224, connected to your system.
...@@ -846,7 +851,7 @@ config TOUCHSCREEN_TSC2007 ...@@ -846,7 +851,7 @@ config TOUCHSCREEN_TSC2007
config TOUCHSCREEN_W90X900 config TOUCHSCREEN_W90X900
tristate "W90P910 touchscreen driver" tristate "W90P910 touchscreen driver"
depends on HAVE_CLK depends on ARCH_W90X900
help help
Say Y here if you have a W90P910 based touchscreen. Say Y here if you have a W90P910 based touchscreen.
...@@ -885,6 +890,17 @@ config TOUCHSCREEN_STMPE ...@@ -885,6 +890,17 @@ config TOUCHSCREEN_STMPE
To compile this driver as a module, choose M here: the To compile this driver as a module, choose M here: the
module will be called stmpe-ts. 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 config TOUCHSCREEN_SUR40
tristate "Samsung SUR40 (Surface 2.0/PixelSense) touchscreen" tristate "Samsung SUR40 (Surface 2.0/PixelSense) touchscreen"
depends on USB depends on USB
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
wm97xx-ts-y := wm97xx-core.o wm97xx-ts-y := wm97xx-core.o
obj-$(CONFIG_OF_TOUCHSCREEN) += of_touchscreen.o
obj-$(CONFIG_TOUCHSCREEN_88PM860X) += 88pm860x-ts.o obj-$(CONFIG_TOUCHSCREEN_88PM860X) += 88pm860x-ts.o
obj-$(CONFIG_TOUCHSCREEN_AD7877) += ad7877.o obj-$(CONFIG_TOUCHSCREEN_AD7877) += ad7877.o
obj-$(CONFIG_TOUCHSCREEN_AD7879) += ad7879.o obj-$(CONFIG_TOUCHSCREEN_AD7879) += ad7879.o
...@@ -53,6 +54,7 @@ obj-$(CONFIG_TOUCHSCREEN_PIXCIR) += pixcir_i2c_ts.o ...@@ -53,6 +54,7 @@ obj-$(CONFIG_TOUCHSCREEN_PIXCIR) += pixcir_i2c_ts.o
obj-$(CONFIG_TOUCHSCREEN_S3C2410) += s3c2410_ts.o obj-$(CONFIG_TOUCHSCREEN_S3C2410) += s3c2410_ts.o
obj-$(CONFIG_TOUCHSCREEN_ST1232) += st1232.o obj-$(CONFIG_TOUCHSCREEN_ST1232) += st1232.o
obj-$(CONFIG_TOUCHSCREEN_STMPE) += stmpe-ts.o obj-$(CONFIG_TOUCHSCREEN_STMPE) += stmpe-ts.o
obj-$(CONFIG_TOUCHSCREEN_SUN4I) += sun4i-ts.o
obj-$(CONFIG_TOUCHSCREEN_SUR40) += sur40.o obj-$(CONFIG_TOUCHSCREEN_SUR40) += sur40.o
obj-$(CONFIG_TOUCHSCREEN_TI_AM335X_TSC) += ti_am335x_tsc.o obj-$(CONFIG_TOUCHSCREEN_TI_AM335X_TSC) += ti_am335x_tsc.o
obj-$(CONFIG_TOUCHSCREEN_TOUCHIT213) += touchit213.o obj-$(CONFIG_TOUCHSCREEN_TOUCHIT213) += touchit213.o
......
...@@ -210,11 +210,6 @@ static bool gpio3; ...@@ -210,11 +210,6 @@ static bool gpio3;
module_param(gpio3, bool, 0); module_param(gpio3, bool, 0);
MODULE_PARM_DESC(gpio3, "If gpio3 is set to 1 AUX3 acts as GPIO3"); 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) static int ad7877_read(struct spi_device *spi, u16 reg)
{ {
struct ser_req *req; struct ser_req *req;
......
...@@ -706,7 +706,7 @@ static void ads7846_read_state(struct ads7846 *ts) ...@@ -706,7 +706,7 @@ static void ads7846_read_state(struct ads7846 *ts)
m = &ts->msg[msg_idx]; m = &ts->msg[msg_idx];
error = spi_sync(ts->spi, m); error = spi_sync(ts->spi, m);
if (error) { 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; packet->tc.ignore = true;
return; return;
} }
......
This diff is collapsed.
...@@ -679,7 +679,7 @@ static const struct i2c_device_id auo_pixcir_idtable[] = { ...@@ -679,7 +679,7 @@ static const struct i2c_device_id auo_pixcir_idtable[] = {
MODULE_DEVICE_TABLE(i2c, auo_pixcir_idtable); MODULE_DEVICE_TABLE(i2c, auo_pixcir_idtable);
#ifdef CONFIG_OF #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" }, { .compatible = "auo,auo_pixcir_ts" },
{}, {},
}; };
......
...@@ -301,10 +301,11 @@ static int da9034_touch_probe(struct platform_device *pdev) ...@@ -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_pdata *pdata = dev_get_platdata(&pdev->dev);
struct da9034_touch *touch; struct da9034_touch *touch;
struct input_dev *input_dev; struct input_dev *input_dev;
int ret; int error;
touch = kzalloc(sizeof(struct da9034_touch), GFP_KERNEL); touch = devm_kzalloc(&pdev->dev, sizeof(struct da9034_touch),
if (touch == NULL) { GFP_KERNEL);
if (!touch) {
dev_err(&pdev->dev, "failed to allocate driver data\n"); dev_err(&pdev->dev, "failed to allocate driver data\n");
return -ENOMEM; return -ENOMEM;
} }
...@@ -315,18 +316,18 @@ static int da9034_touch_probe(struct platform_device *pdev) ...@@ -315,18 +316,18 @@ static int da9034_touch_probe(struct platform_device *pdev)
touch->interval_ms = pdata->interval_ms; touch->interval_ms = pdata->interval_ms;
touch->x_inverted = pdata->x_inverted; touch->x_inverted = pdata->x_inverted;
touch->y_inverted = pdata->y_inverted; touch->y_inverted = pdata->y_inverted;
} else } else {
/* fallback into default */ /* fallback into default */
touch->interval_ms = 10; touch->interval_ms = 10;
}
INIT_DELAYED_WORK(&touch->tsi_work, da9034_tsi_work); INIT_DELAYED_WORK(&touch->tsi_work, da9034_tsi_work);
touch->notifier.notifier_call = da9034_touch_notifier; touch->notifier.notifier_call = da9034_touch_notifier;
input_dev = input_allocate_device(); input_dev = devm_input_allocate_device(&pdev->dev);
if (!input_dev) { if (!input_dev) {
dev_err(&pdev->dev, "failed to allocate input device\n"); dev_err(&pdev->dev, "failed to allocate input device\n");
ret = -ENOMEM; return -ENOMEM;
goto err_free_touch;
} }
input_dev->name = pdev->name; input_dev->name = pdev->name;
...@@ -346,26 +347,9 @@ static int da9034_touch_probe(struct platform_device *pdev) ...@@ -346,26 +347,9 @@ static int da9034_touch_probe(struct platform_device *pdev)
touch->input_dev = input_dev; touch->input_dev = input_dev;
input_set_drvdata(input_dev, touch); input_set_drvdata(input_dev, touch);
ret = input_register_device(input_dev); error = input_register_device(input_dev);
if (ret) if (error)
goto err_free_input; return error;
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);
return 0; return 0;
} }
...@@ -376,7 +360,6 @@ static struct platform_driver da9034_touch_driver = { ...@@ -376,7 +360,6 @@ static struct platform_driver da9034_touch_driver = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
}, },
.probe = da9034_touch_probe, .probe = da9034_touch_probe,
.remove = da9034_touch_remove,
}; };
module_platform_driver(da9034_touch_driver); module_platform_driver(da9034_touch_driver);
......
...@@ -271,7 +271,7 @@ static int edt_ft5x06_register_write(struct edt_ft5x06_ts_data *tsdata, ...@@ -271,7 +271,7 @@ static int edt_ft5x06_register_write(struct edt_ft5x06_ts_data *tsdata,
wrbuf[0] = addr; wrbuf[0] = addr;
wrbuf[1] = value; wrbuf[1] = value;
return edt_ft5x06_ts_readwrite(tsdata->client, 3, return edt_ft5x06_ts_readwrite(tsdata->client, 2,
wrbuf, 0, NULL); wrbuf, 0, NULL);
default: default:
......
...@@ -262,7 +262,7 @@ static int egalax_ts_resume(struct device *dev) ...@@ -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 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" }, { .compatible = "eeti,egalax_ts" },
{ /* sentinel */ } { /* sentinel */ }
}; };
......
...@@ -36,6 +36,7 @@ ...@@ -36,6 +36,7 @@
#include <linux/irq.h> #include <linux/irq.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <asm/intel_scu_ipc.h> #include <asm/intel_scu_ipc.h>
#include <linux/device.h>
/* PMIC Interrupt registers */ /* PMIC Interrupt registers */
#define PMIC_REG_ID1 0x00 /* PMIC ID1 register */ #define PMIC_REG_ID1 0x00 /* PMIC ID1 register */
...@@ -580,12 +581,17 @@ static int mrstouch_probe(struct platform_device *pdev) ...@@ -580,12 +581,17 @@ static int mrstouch_probe(struct platform_device *pdev)
return -EINVAL; return -EINVAL;
} }
tsdev = kzalloc(sizeof(struct mrstouch_dev), GFP_KERNEL); tsdev = devm_kzalloc(&pdev->dev, sizeof(struct mrstouch_dev),
input = input_allocate_device(); GFP_KERNEL);
if (!tsdev || !input) { if (!tsdev) {
dev_err(&pdev->dev, "unable to allocate memory\n"); dev_err(&pdev->dev, "unable to allocate memory\n");
err = -ENOMEM; return -ENOMEM;
goto err_free_mem; }
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; tsdev->dev = &pdev->dev;
...@@ -598,7 +604,7 @@ static int mrstouch_probe(struct platform_device *pdev) ...@@ -598,7 +604,7 @@ static int mrstouch_probe(struct platform_device *pdev)
err = mrstouch_adc_init(tsdev); err = mrstouch_adc_init(tsdev);
if (err) { if (err) {
dev_err(&pdev->dev, "ADC initialization failed\n"); dev_err(&pdev->dev, "ADC initialization failed\n");
goto err_free_mem; return err;
} }
input->name = "mrst_touchscreen"; input->name = "mrst_touchscreen";
...@@ -618,37 +624,19 @@ static int mrstouch_probe(struct platform_device *pdev) ...@@ -618,37 +624,19 @@ static int mrstouch_probe(struct platform_device *pdev)
input_set_abs_params(tsdev->input, ABS_PRESSURE, input_set_abs_params(tsdev->input, ABS_PRESSURE,
MRST_PRESSURE_MIN, MRST_PRESSURE_MAX, 0, 0); MRST_PRESSURE_MIN, MRST_PRESSURE_MAX, 0, 0);
err = request_threaded_irq(tsdev->irq, NULL, mrstouch_pendet_irq, err = devm_request_threaded_irq(&pdev->dev, tsdev->irq, NULL,
IRQF_ONESHOT, "mrstouch", tsdev); mrstouch_pendet_irq, IRQF_ONESHOT,
"mrstouch", tsdev);
if (err) { if (err) {
dev_err(tsdev->dev, "unable to allocate irq\n"); dev_err(tsdev->dev, "unable to allocate irq\n");
goto err_free_mem; return err;
} }
err = input_register_device(tsdev->input); err = input_register_device(tsdev->input);
if (err) { if (err) {
dev_err(tsdev->dev, "unable to register input device\n"); dev_err(tsdev->dev, "unable to register input device\n");
goto err_free_irq;
}
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; 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; return 0;
} }
...@@ -659,7 +647,6 @@ static struct platform_driver mrstouch_driver = { ...@@ -659,7 +647,6 @@ static struct platform_driver mrstouch_driver = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
}, },
.probe = mrstouch_probe, .probe = mrstouch_probe,
.remove = mrstouch_remove,
}; };
module_platform_driver(mrstouch_driver); module_platform_driver(mrstouch_driver);
......
...@@ -384,7 +384,7 @@ static const struct dev_pm_ops lpc32xx_ts_pm_ops = { ...@@ -384,7 +384,7 @@ static const struct dev_pm_ops lpc32xx_ts_pm_ops = {
#endif #endif
#ifdef CONFIG_OF #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", }, { .compatible = "nxp,lpc3220-tsc", },
{ }, { },
}; };
......
...@@ -161,10 +161,9 @@ static irqreturn_t mcs5000_ts_interrupt(int irq, void *dev_id) ...@@ -161,10 +161,9 @@ static irqreturn_t mcs5000_ts_interrupt(int irq, void *dev_id)
return IRQ_HANDLED; 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; struct i2c_client *client = data->client;
/* Touch reset & sleep mode */ /* Touch reset & sleep mode */
...@@ -189,26 +188,30 @@ static void mcs5000_ts_phys_init(struct mcs5000_ts_data *data) ...@@ -189,26 +188,30 @@ static void mcs5000_ts_phys_init(struct mcs5000_ts_data *data)
static int mcs5000_ts_probe(struct i2c_client *client, 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 mcs5000_ts_data *data;
struct input_dev *input_dev; 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; return -EINVAL;
data = kzalloc(sizeof(struct mcs5000_ts_data), GFP_KERNEL); data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
input_dev = input_allocate_device(); if (!data) {
if (!data || !input_dev) {
dev_err(&client->dev, "Failed to allocate memory\n"); dev_err(&client->dev, "Failed to allocate memory\n");
ret = -ENOMEM; return -ENOMEM;
goto err_free_mem;
} }
data->client = client; 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->id.bustype = BUS_I2C;
input_dev->dev.parent = &client->dev; input_dev->dev.parent = &client->dev;
...@@ -219,43 +222,29 @@ static int mcs5000_ts_probe(struct i2c_client *client, ...@@ -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_abs_params(input_dev, ABS_Y, 0, MCS5000_MAX_YC, 0, 0);
input_set_drvdata(input_dev, data); input_set_drvdata(input_dev, data);
data->input_dev = input_dev;
if (data->platform_data->cfg_pin) if (pdata->cfg_pin)
data->platform_data->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"); dev_err(&client->dev, "Failed to register interrupt\n");
goto err_free_mem; return error;
} }
ret = input_register_device(data->input_dev); error = input_register_device(data->input_dev);
if (ret < 0) if (error) {
goto err_free_irq; 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); 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; return 0;
} }
...@@ -274,14 +263,15 @@ static int mcs5000_ts_resume(struct device *dev) ...@@ -274,14 +263,15 @@ static int mcs5000_ts_resume(struct device *dev)
{ {
struct i2c_client *client = to_i2c_client(dev); struct i2c_client *client = to_i2c_client(dev);
struct mcs5000_ts_data *data = i2c_get_clientdata(client); 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; return 0;
} }
#endif
static SIMPLE_DEV_PM_OPS(mcs5000_ts_pm, mcs5000_ts_suspend, mcs5000_ts_resume); static SIMPLE_DEV_PM_OPS(mcs5000_ts_pm, mcs5000_ts_suspend, mcs5000_ts_resume);
#endif
static const struct i2c_device_id mcs5000_ts_id[] = { static const struct i2c_device_id mcs5000_ts_id[] = {
{ "mcs5000_ts", 0 }, { "mcs5000_ts", 0 },
...@@ -291,12 +281,9 @@ MODULE_DEVICE_TABLE(i2c, mcs5000_ts_id); ...@@ -291,12 +281,9 @@ MODULE_DEVICE_TABLE(i2c, mcs5000_ts_id);
static struct i2c_driver mcs5000_ts_driver = { static struct i2c_driver mcs5000_ts_driver = {
.probe = mcs5000_ts_probe, .probe = mcs5000_ts_probe,
.remove = mcs5000_ts_remove,
.driver = { .driver = {
.name = "mcs5000_ts", .name = "mcs5000_ts",
#ifdef CONFIG_PM
.pm = &mcs5000_ts_pm, .pm = &mcs5000_ts_pm,
#endif
}, },
.id_table = mcs5000_ts_id, .id_table = mcs5000_ts_id,
}; };
......
...@@ -456,7 +456,7 @@ static int mms114_probe(struct i2c_client *client, ...@@ -456,7 +456,7 @@ static int mms114_probe(struct i2c_client *client,
data->input_dev = input_dev; data->input_dev = input_dev;
data->pdata = pdata; data->pdata = pdata;
input_dev->name = "MELPAS MMS114 Touchscreen"; input_dev->name = "MELFAS MMS114 Touchscreen";
input_dev->id.bustype = BUS_I2C; input_dev->id.bustype = BUS_I2C;
input_dev->dev.parent = &client->dev; input_dev->dev.parent = &client->dev;
input_dev->open = mms114_input_open; input_dev->open = mms114_input_open;
...@@ -570,7 +570,7 @@ static const struct i2c_device_id mms114_id[] = { ...@@ -570,7 +570,7 @@ static const struct i2c_device_id mms114_id[] = {
MODULE_DEVICE_TABLE(i2c, mms114_id); MODULE_DEVICE_TABLE(i2c, mms114_id);
#ifdef CONFIG_OF #ifdef CONFIG_OF
static struct of_device_id mms114_dt_match[] = { static const struct of_device_id mms114_dt_match[] = {
{ .compatible = "melfas,mms114" }, { .compatible = "melfas,mms114" },
{ } { }
}; };
......
/*
* 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 @@ ...@@ -24,12 +24,13 @@
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/input.h> #include <linux/input.h>
#include <linux/input/pixcir_ts.h> #include <linux/input/pixcir_ts.h>
#include <linux/gpio.h>
struct pixcir_i2c_ts_data { struct pixcir_i2c_ts_data {
struct i2c_client *client; struct i2c_client *client;
struct input_dev *input; struct input_dev *input;
const struct pixcir_ts_platform_data *chip; const struct pixcir_ts_platform_data *chip;
bool exiting; bool running;
}; };
static void pixcir_ts_poscheck(struct pixcir_i2c_ts_data *data) 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) ...@@ -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) static irqreturn_t pixcir_ts_isr(int irq, void *dev_id)
{ {
struct pixcir_i2c_ts_data *tsdata = 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); pixcir_ts_poscheck(tsdata);
if (tsdata->chip->attb_read_val()) if (gpio_get_value(pdata->gpio_attb))
break; break;
msleep(20); msleep(20);
...@@ -100,25 +102,221 @@ static irqreturn_t pixcir_ts_isr(int irq, void *dev_id) ...@@ -100,25 +102,221 @@ static irqreturn_t pixcir_ts_isr(int irq, void *dev_id)
return IRQ_HANDLED; 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 #ifdef CONFIG_PM_SLEEP
static int pixcir_i2c_ts_suspend(struct device *dev) static int pixcir_i2c_ts_suspend(struct device *dev)
{ {
struct i2c_client *client = to_i2c_client(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); 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) static int pixcir_i2c_ts_resume(struct device *dev)
{ {
struct i2c_client *client = to_i2c_client(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 (device_may_wakeup(&client->dev)) {
disable_irq_wake(client->irq); 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 #endif
...@@ -130,6 +328,7 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client, ...@@ -130,6 +328,7 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client,
{ {
const struct pixcir_ts_platform_data *pdata = const struct pixcir_ts_platform_data *pdata =
dev_get_platdata(&client->dev); dev_get_platdata(&client->dev);
struct device *dev = &client->dev;
struct pixcir_i2c_ts_data *tsdata; struct pixcir_i2c_ts_data *tsdata;
struct input_dev *input; struct input_dev *input;
int error; int error;
...@@ -139,12 +338,19 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client, ...@@ -139,12 +338,19 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client,
return -EINVAL; return -EINVAL;
} }
tsdata = kzalloc(sizeof(*tsdata), GFP_KERNEL); if (!gpio_is_valid(pdata->gpio_attb)) {
input = input_allocate_device(); dev_err(dev, "Invalid gpio_attb in pdata\n");
if (!tsdata || !input) { return -EINVAL;
dev_err(&client->dev, "Failed to allocate driver data!\n"); }
error = -ENOMEM;
goto err_free_mem; 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; tsdata->client = client;
...@@ -153,6 +359,8 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client, ...@@ -153,6 +359,8 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client,
input->name = client->name; input->name = client->name;
input->id.bustype = BUS_I2C; input->id.bustype = BUS_I2C;
input->open = pixcir_input_open;
input->close = pixcir_input_close;
input->dev.parent = &client->dev; input->dev.parent = &client->dev;
__set_bit(EV_KEY, input->evbit); __set_bit(EV_KEY, input->evbit);
...@@ -165,44 +373,47 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client, ...@@ -165,44 +373,47 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client,
input_set_drvdata(input, tsdata); input_set_drvdata(input, tsdata);
error = request_threaded_irq(client->irq, NULL, pixcir_ts_isr, error = devm_gpio_request_one(dev, pdata->gpio_attb,
GPIOF_DIR_IN, "pixcir_i2c_attb");
if (error) {
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, IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
client->name, tsdata); client->name, tsdata);
if (error) { if (error) {
dev_err(&client->dev, "Unable to request touchscreen IRQ.\n"); dev_err(dev, "failed to request irq %d\n", client->irq);
goto err_free_mem; 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); error = input_register_device(input);
if (error) if (error)
goto err_free_irq; return error;
i2c_set_clientdata(client, tsdata); i2c_set_clientdata(client, tsdata);
device_init_wakeup(&client->dev, 1); device_init_wakeup(&client->dev, 1);
return 0; 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) 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); device_init_wakeup(&client->dev, 0);
tsdata->exiting = true;
mb();
free_irq(client->irq, tsdata);
input_unregister_device(tsdata->input);
kfree(tsdata);
return 0; return 0;
} }
......
/*
* 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");
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment