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 {
* Also... order in the device tree actually matters here.
*/
tsc2005@0 {
compatible = "tsc2005";
compatible = "ti,tsc2005";
spi-max-frequency = <6000000>;
reg = <0>;
vio-supply = <&vio>;
reset-gpios = <&gpio4 8 GPIO_ACTIVE_HIGH>; /* 104 */
interrupts-extended = <&gpio4 4 IRQ_TYPE_EDGE_RISING>; /* 100 */
touchscreen-fuzz-x = <4>;
touchscreen-fuzz-y = <7>;
touchscreen-fuzz-pressure = <2>;
touchscreen-max-x = <4096>;
touchscreen-max-y = <4096>;
touchscreen-max-pressure = <2048>;
ti,x-plate-ohms = <280>;
ti,esd-recovery-timeout-ms = <8000>;
};
acx565akm@2 {
......
......@@ -18,7 +18,6 @@
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/pinctrl/machine.h>
#include <linux/platform_data/omap4-keypad.h>
#include <linux/platform_data/mailbox-omap.h>
#include <asm/mach-types.h>
......@@ -29,7 +28,6 @@
#include "iomap.h"
#include "omap_hwmod.h"
#include "omap_device.h"
#include "omap4-keypad.h"
#include "soc.h"
#include "common.h"
......@@ -255,37 +253,6 @@ static inline void omap_init_camera(void)
#endif
}
int __init omap4_keyboard_init(struct omap4_keypad_platform_data
*sdp4430_keypad_data, struct omap_board_data *bdata)
{
struct platform_device *pdev;
struct omap_hwmod *oh;
struct omap4_keypad_platform_data *keypad_data;
unsigned int id = -1;
char *oh_name = "kbd";
char *name = "omap4-keypad";
oh = omap_hwmod_lookup(oh_name);
if (!oh) {
pr_err("Could not look up %s\n", oh_name);
return -ENODEV;
}
keypad_data = sdp4430_keypad_data;
pdev = omap_device_build(name, id, oh, keypad_data,
sizeof(struct omap4_keypad_platform_data));
if (IS_ERR(pdev)) {
WARN(1, "Can't build omap_device for %s:%s.\n",
name, oh->name);
return PTR_ERR(pdev);
}
oh->mux = omap_hwmod_mux_init(bdata->pads, bdata->pads_cnt);
return 0;
}
#if defined(CONFIG_OMAP2PLUS_MBOX) || defined(CONFIG_OMAP2PLUS_MBOX_MODULE)
static inline void __init omap_init_mbox(void)
{
......
#ifndef ARCH_ARM_PLAT_OMAP4_KEYPAD_H
#define ARCH_ARM_PLAT_OMAP4_KEYPAD_H
struct omap_board_data;
extern int omap4_keyboard_init(struct omap4_keypad_platform_data *,
struct omap_board_data *);
#endif
......@@ -234,14 +234,6 @@ static void __init goni_radio_init(void)
/* TSP */
static struct mxt_platform_data qt602240_platform_data = {
.x_line = 17,
.y_line = 11,
.x_size = 800,
.y_size = 480,
.blen = 0x21,
.threshold = 0x28,
.voltage = 2800000, /* 2.8V */
.orient = MXT_DIAGONAL,
.irqflags = IRQF_TRIGGER_FALLING,
};
......
......@@ -629,12 +629,10 @@ static int str_to_user(const char *str, unsigned int maxlen, void __user *p)
return copy_to_user(p, str, len) ? -EFAULT : len;
}
#define OLD_KEY_MAX 0x1ff
static int handle_eviocgbit(struct input_dev *dev,
unsigned int type, unsigned int size,
void __user *p, int compat_mode)
{
static unsigned long keymax_warn_time;
unsigned long *bits;
int len;
......@@ -652,24 +650,8 @@ static int handle_eviocgbit(struct input_dev *dev,
default: return -EINVAL;
}
/*
* Work around bugs in userspace programs that like to do
* EVIOCGBIT(EV_KEY, KEY_MAX) and not realize that 'len'
* should be in bytes, not in bits.
*/
if (type == EV_KEY && size == OLD_KEY_MAX) {
len = OLD_KEY_MAX;
if (printk_timed_ratelimit(&keymax_warn_time, 10 * 1000))
pr_warning("(EVIOCGBIT): Suspicious buffer size %u, "
"limiting output to %zu bytes. See "
"http://userweb.kernel.org/~dtor/eviocgbit-bug.html\n",
OLD_KEY_MAX,
BITS_TO_LONGS(OLD_KEY_MAX) * sizeof(long));
}
return bits_to_user(bits, len, size, p, compat_mode);
}
#undef OLD_KEY_MAX
static int evdev_handle_get_keycode(struct input_dev *dev, void __user *p)
{
......
......@@ -147,6 +147,11 @@ static struct attribute_group input_polldev_attribute_group = {
.attrs = sysfs_attrs
};
static const struct attribute_group *input_polldev_attribute_groups[] = {
&input_polldev_attribute_group,
NULL
};
/**
* input_allocate_polled_device - allocate memory for polled device
*
......@@ -171,6 +176,91 @@ struct input_polled_dev *input_allocate_polled_device(void)
}
EXPORT_SYMBOL(input_allocate_polled_device);
struct input_polled_devres {
struct input_polled_dev *polldev;
};
static int devm_input_polldev_match(struct device *dev, void *res, void *data)
{
struct input_polled_devres *devres = res;
return devres->polldev == data;
}
static void devm_input_polldev_release(struct device *dev, void *res)
{
struct input_polled_devres *devres = res;
struct input_polled_dev *polldev = devres->polldev;
dev_dbg(dev, "%s: dropping reference/freeing %s\n",
__func__, dev_name(&polldev->input->dev));
input_put_device(polldev->input);
kfree(polldev);
}
static void devm_input_polldev_unregister(struct device *dev, void *res)
{
struct input_polled_devres *devres = res;
struct input_polled_dev *polldev = devres->polldev;
dev_dbg(dev, "%s: unregistering device %s\n",
__func__, dev_name(&polldev->input->dev));
input_unregister_device(polldev->input);
/*
* Note that we are still holding extra reference to the input
* device so it will stick around until devm_input_polldev_release()
* is called.
*/
}
/**
* devm_input_allocate_polled_device - allocate managed polled device
* @dev: device owning the polled device being created
*
* Returns prepared &struct input_polled_dev or %NULL.
*
* Managed polled input devices do not need to be explicitly unregistered
* or freed as it will be done automatically when owner device unbinds
* from * its driver (or binding fails). Once such managed polled device
* is allocated, it is ready to be set up and registered in the same
* fashion as regular polled input devices (using
* input_register_polled_device() function).
*
* If you want to manually unregister and free such managed polled devices,
* it can be still done by calling input_unregister_polled_device() and
* input_free_polled_device(), although it is rarely needed.
*
* NOTE: the owner device is set up as parent of input device and users
* should not override it.
*/
struct input_polled_dev *devm_input_allocate_polled_device(struct device *dev)
{
struct input_polled_dev *polldev;
struct input_polled_devres *devres;
devres = devres_alloc(devm_input_polldev_release, sizeof(*devres),
GFP_KERNEL);
if (!devres)
return NULL;
polldev = input_allocate_polled_device();
if (!polldev) {
devres_free(devres);
return NULL;
}
polldev->input->dev.parent = dev;
polldev->devres_managed = true;
devres->polldev = polldev;
devres_add(dev, devres);
return polldev;
}
EXPORT_SYMBOL(devm_input_allocate_polled_device);
/**
* input_free_polled_device - free memory allocated for polled device
* @dev: device to free
......@@ -181,7 +271,12 @@ EXPORT_SYMBOL(input_allocate_polled_device);
void input_free_polled_device(struct input_polled_dev *dev)
{
if (dev) {
input_free_device(dev->input);
if (dev->devres_managed)
WARN_ON(devres_destroy(dev->input->dev.parent,
devm_input_polldev_release,
devm_input_polldev_match,
dev));
input_put_device(dev->input);
kfree(dev);
}
}
......@@ -199,26 +294,35 @@ EXPORT_SYMBOL(input_free_polled_device);
*/
int input_register_polled_device(struct input_polled_dev *dev)
{
struct input_polled_devres *devres = NULL;
struct input_dev *input = dev->input;
int error;
if (dev->devres_managed) {
devres = devres_alloc(devm_input_polldev_unregister,
sizeof(*devres), GFP_KERNEL);
if (!devres)
return -ENOMEM;
devres->polldev = dev;
}
input_set_drvdata(input, dev);
INIT_DELAYED_WORK(&dev->work, input_polled_device_work);
if (!dev->poll_interval)
dev->poll_interval = 500;
if (!dev->poll_interval_max)
dev->poll_interval_max = dev->poll_interval;
input->open = input_open_polled_device;
input->close = input_close_polled_device;
error = input_register_device(input);
if (error)
return error;
input->dev.groups = input_polldev_attribute_groups;
error = sysfs_create_group(&input->dev.kobj,
&input_polldev_attribute_group);
error = input_register_device(input);
if (error) {
input_unregister_device(input);
devres_free(devres);
return error;
}
......@@ -231,6 +335,12 @@ int input_register_polled_device(struct input_polled_dev *dev)
*/
input_get_device(input);
if (dev->devres_managed) {
dev_dbg(input->dev.parent, "%s: registering %s with devres.\n",
__func__, dev_name(&input->dev));
devres_add(input->dev.parent, devres);
}
return 0;
}
EXPORT_SYMBOL(input_register_polled_device);
......@@ -245,8 +355,11 @@ EXPORT_SYMBOL(input_register_polled_device);
*/
void input_unregister_polled_device(struct input_polled_dev *dev)
{
sysfs_remove_group(&dev->input->dev.kobj,
&input_polldev_attribute_group);
if (dev->devres_managed)
WARN_ON(devres_destroy(dev->input->dev.parent,
devm_input_polldev_unregister,
devm_input_polldev_match,
dev));
input_unregister_device(dev->input);
}
......
......@@ -524,6 +524,17 @@ config KEYBOARD_STOWAWAY
To compile this driver as a module, choose M here: the
module will be called stowaway.
config KEYBOARD_ST_KEYSCAN
tristate "STMicroelectronics keyscan support"
depends on ARCH_STI || COMPILE_TEST
select INPUT_MATRIXKMAP
help
Say Y here if you want to use a keypad attached to the keyscan block
on some STMicroelectronics SoC devices.
To compile this driver as a module, choose M here: the
module will be called st-keyscan.
config KEYBOARD_SUNKBD
tristate "Sun Type 4 and Type 5 keyboard"
select SERIO
......@@ -578,7 +589,7 @@ config KEYBOARD_OMAP
config KEYBOARD_OMAP4
tristate "TI OMAP4+ keypad support"
depends on ARCH_OMAP2PLUS
depends on OF || ARCH_OMAP2PLUS
select INPUT_MATRIXKMAP
help
Say Y here if you want to use the OMAP4+ keypad.
......
......@@ -51,6 +51,7 @@ obj-$(CONFIG_KEYBOARD_SH_KEYSC) += sh_keysc.o
obj-$(CONFIG_KEYBOARD_SPEAR) += spear-keyboard.o
obj-$(CONFIG_KEYBOARD_STMPE) += stmpe-keypad.o
obj-$(CONFIG_KEYBOARD_STOWAWAY) += stowaway.o
obj-$(CONFIG_KEYBOARD_ST_KEYSCAN) += st-keyscan.o
obj-$(CONFIG_KEYBOARD_SUNKBD) += sunkbd.o
obj-$(CONFIG_KEYBOARD_TC3589X) += tc3589x-keypad.o
obj-$(CONFIG_KEYBOARD_TEGRA) += tegra-kbc.o
......
......@@ -12,6 +12,7 @@
#include <linux/input.h>
#include <linux/mfd/adp5520.h>
#include <linux/slab.h>
#include <linux/device.h>
struct adp5520_keys {
struct input_dev *input;
......@@ -81,7 +82,7 @@ static int adp5520_keys_probe(struct platform_device *pdev)
return -EINVAL;
}
if (pdata == NULL) {
if (!pdata) {
dev_err(&pdev->dev, "missing platform data\n");
return -EINVAL;
}
......@@ -89,17 +90,15 @@ static int adp5520_keys_probe(struct platform_device *pdev)
if (!(pdata->rows_en_mask && pdata->cols_en_mask))
return -EINVAL;
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (dev == NULL) {
dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
if (!dev) {
dev_err(&pdev->dev, "failed to alloc memory\n");
return -ENOMEM;
}
input = input_allocate_device();
if (!input) {
ret = -ENOMEM;
goto err;
}
input = devm_input_allocate_device(&pdev->dev);
if (!input)
return -ENOMEM;
dev->master = pdev->dev.parent;
dev->input = input;
......@@ -135,7 +134,7 @@ static int adp5520_keys_probe(struct platform_device *pdev)
ret = input_register_device(input);
if (ret) {
dev_err(&pdev->dev, "unable to register input device\n");
goto err;
return ret;
}
en_mask = pdata->rows_en_mask | pdata->cols_en_mask;
......@@ -157,8 +156,7 @@ static int adp5520_keys_probe(struct platform_device *pdev)
if (ret) {
dev_err(&pdev->dev, "failed to write\n");
ret = -EIO;
goto err1;
return -EIO;
}
dev->notifier.notifier_call = adp5520_keys_notifier;
......@@ -166,19 +164,11 @@ static int adp5520_keys_probe(struct platform_device *pdev)
ADP5520_KP_IEN | ADP5520_KR_IEN);
if (ret) {
dev_err(&pdev->dev, "failed to register notifier\n");
goto err1;
return ret;
}
platform_set_drvdata(pdev, dev);
return 0;
err1:
input_unregister_device(input);
input = NULL;
err:
input_free_device(input);
kfree(dev);
return ret;
}
static int adp5520_keys_remove(struct platform_device *pdev)
......@@ -188,8 +178,6 @@ static int adp5520_keys_remove(struct platform_device *pdev)
adp5520_unregister_notifier(dev->master, &dev->notifier,
ADP5520_KP_IEN | ADP5520_KR_IEN);
input_unregister_device(dev->input);
kfree(dev);
return 0;
}
......
......@@ -185,7 +185,7 @@ static int clps711x_keypad_remove(struct platform_device *pdev)
return 0;
}
static struct of_device_id clps711x_keypad_of_match[] = {
static const struct of_device_id clps711x_keypad_of_match[] = {
{ .compatible = "cirrus,clps711x-keypad", },
{ }
};
......
......@@ -424,6 +424,16 @@ static irqreturn_t gpio_keys_irq_isr(int irq, void *dev_id)
return IRQ_HANDLED;
}
static void gpio_keys_quiesce_key(void *data)
{
struct gpio_button_data *bdata = data;
if (bdata->timer_debounce)
del_timer_sync(&bdata->timer);
cancel_work_sync(&bdata->work);
}
static int gpio_keys_setup_key(struct platform_device *pdev,
struct input_dev *input,
struct gpio_button_data *bdata,
......@@ -433,7 +443,8 @@ static int gpio_keys_setup_key(struct platform_device *pdev,
struct device *dev = &pdev->dev;
irq_handler_t isr;
unsigned long irqflags;
int irq, error;
int irq;
int error;
bdata->input = input;
bdata->button = button;
......@@ -441,7 +452,8 @@ static int gpio_keys_setup_key(struct platform_device *pdev,
if (gpio_is_valid(button->gpio)) {
error = gpio_request_one(button->gpio, GPIOF_IN, desc);
error = devm_gpio_request_one(&pdev->dev, button->gpio,
GPIOF_IN, desc);
if (error < 0) {
dev_err(dev, "Failed to request GPIO %d, error %d\n",
button->gpio, error);
......@@ -463,7 +475,7 @@ static int gpio_keys_setup_key(struct platform_device *pdev,
dev_err(dev,
"Unable to get irq number for GPIO %d, error %d\n",
button->gpio, error);
goto fail;
return error;
}
bdata->irq = irq;
......@@ -496,6 +508,18 @@ static int gpio_keys_setup_key(struct platform_device *pdev,
input_set_capability(input, button->type ?: EV_KEY, button->code);
/*
* Install custom action to cancel debounce timer and
* workqueue item.
*/
error = devm_add_action(&pdev->dev, gpio_keys_quiesce_key, bdata);
if (error) {
dev_err(&pdev->dev,
"failed to register quiesce action, error: %d\n",
error);
return error;
}
/*
* If platform has specified that the button can be disabled,
* we don't want it to share the interrupt line.
......@@ -503,20 +527,15 @@ static int gpio_keys_setup_key(struct platform_device *pdev,
if (!button->can_disable)
irqflags |= IRQF_SHARED;
error = request_any_context_irq(bdata->irq, isr, irqflags, desc, bdata);
error = devm_request_any_context_irq(&pdev->dev, bdata->irq,
isr, irqflags, desc, bdata);
if (error < 0) {
dev_err(dev, "Unable to claim irq %d; error %d\n",
bdata->irq, error);
goto fail;
return error;
}
return 0;
fail:
if (gpio_is_valid(button->gpio))
gpio_free(button->gpio);
return error;
}
static void gpio_keys_report_state(struct gpio_keys_drvdata *ddata)
......@@ -578,23 +597,18 @@ gpio_keys_get_devtree_pdata(struct device *dev)
int i;
node = dev->of_node;
if (!node) {
error = -ENODEV;
goto err_out;
}
if (!node)
return ERR_PTR(-ENODEV);
nbuttons = of_get_child_count(node);
if (nbuttons == 0) {
error = -ENODEV;
goto err_out;
}
if (nbuttons == 0)
return ERR_PTR(-ENODEV);
pdata = kzalloc(sizeof(*pdata) + nbuttons * (sizeof *button),
pdata = devm_kzalloc(dev,
sizeof(*pdata) + nbuttons * sizeof(*button),
GFP_KERNEL);
if (!pdata) {
error = -ENOMEM;
goto err_out;
}
if (!pdata)
return ERR_PTR(-ENOMEM);
pdata->buttons = (struct gpio_keys_button *)(pdata + 1);
pdata->nbuttons = nbuttons;
......@@ -619,7 +633,7 @@ gpio_keys_get_devtree_pdata(struct device *dev)
dev_err(dev,
"Failed to get gpio flags, error: %d\n",
error);
goto err_free_pdata;
return ERR_PTR(error);
}
button = &pdata->buttons[i++];
......@@ -630,8 +644,7 @@ gpio_keys_get_devtree_pdata(struct device *dev)
if (of_property_read_u32(pp, "linux,code", &button->code)) {
dev_err(dev, "Button without keycode: 0x%x\n",
button->gpio);
error = -EINVAL;
goto err_free_pdata;
return ERR_PTR(-EINVAL);
}
button->desc = of_get_property(pp, "label", NULL);
......@@ -646,20 +659,13 @@ gpio_keys_get_devtree_pdata(struct device *dev)
button->debounce_interval = 5;
}
if (pdata->nbuttons == 0) {
error = -EINVAL;
goto err_free_pdata;
}
if (pdata->nbuttons == 0)
return ERR_PTR(-EINVAL);
return pdata;
err_free_pdata:
kfree(pdata);
err_out:
return ERR_PTR(error);
}
static struct of_device_id gpio_keys_of_match[] = {
static const struct of_device_id gpio_keys_of_match[] = {
{ .compatible = "gpio-keys", },
{ },
};
......@@ -675,22 +681,13 @@ gpio_keys_get_devtree_pdata(struct device *dev)
#endif
static void gpio_remove_key(struct gpio_button_data *bdata)
{
free_irq(bdata->irq, bdata);
if (bdata->timer_debounce)
del_timer_sync(&bdata->timer);
cancel_work_sync(&bdata->work);
if (gpio_is_valid(bdata->button->gpio))
gpio_free(bdata->button->gpio);
}
static int gpio_keys_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
const struct gpio_keys_platform_data *pdata = dev_get_platdata(dev);
struct gpio_keys_drvdata *ddata;
struct input_dev *input;
size_t size;
int i, error;
int wakeup = 0;
......@@ -700,14 +697,18 @@ static int gpio_keys_probe(struct platform_device *pdev)
return PTR_ERR(pdata);
}
ddata = kzalloc(sizeof(struct gpio_keys_drvdata) +
pdata->nbuttons * sizeof(struct gpio_button_data),
GFP_KERNEL);
input = input_allocate_device();
if (!ddata || !input) {
size = sizeof(struct gpio_keys_drvdata) +
pdata->nbuttons * sizeof(struct gpio_button_data);
ddata = devm_kzalloc(dev, size, GFP_KERNEL);
if (!ddata) {
dev_err(dev, "failed to allocate state\n");
error = -ENOMEM;
goto fail1;
return -ENOMEM;
}
input = devm_input_allocate_device(dev);
if (!input) {
dev_err(dev, "failed to allocate input device\n");
return -ENOMEM;
}
ddata->pdata = pdata;
......@@ -738,7 +739,7 @@ static int gpio_keys_probe(struct platform_device *pdev)
error = gpio_keys_setup_key(pdev, input, bdata, button);
if (error)
goto fail2;
return error;
if (button->wakeup)
wakeup = 1;
......@@ -748,57 +749,31 @@ static int gpio_keys_probe(struct platform_device *pdev)
if (error) {
dev_err(dev, "Unable to export keys/switches, error: %d\n",
error);
goto fail2;
return error;
}
error = input_register_device(input);
if (error) {
dev_err(dev, "Unable to register input device, error: %d\n",
error);
goto fail3;
goto err_remove_group;
}
device_init_wakeup(&pdev->dev, wakeup);
return 0;
fail3:
err_remove_group:
sysfs_remove_group(&pdev->dev.kobj, &gpio_keys_attr_group);
fail2:
while (--i >= 0)
gpio_remove_key(&ddata->data[i]);
fail1:
input_free_device(input);
kfree(ddata);
/* If we have no platform data, we allocated pdata dynamically. */
if (!dev_get_platdata(&pdev->dev))
kfree(pdata);
return error;
}
static int gpio_keys_remove(struct platform_device *pdev)
{
struct gpio_keys_drvdata *ddata = platform_get_drvdata(pdev);
struct input_dev *input = ddata->input;
int i;
sysfs_remove_group(&pdev->dev.kobj, &gpio_keys_attr_group);
device_init_wakeup(&pdev->dev, 0);
for (i = 0; i < ddata->pdata->nbuttons; i++)
gpio_remove_key(&ddata->data[i]);
input_unregister_device(input);
/* If we have no platform data, we allocated pdata dynamically. */
if (!dev_get_platdata(&pdev->dev))
kfree(ddata->pdata);
kfree(ddata);
return 0;
}
......
......@@ -120,12 +120,10 @@ static struct gpio_keys_platform_data *gpio_keys_polled_get_devtree_pdata(struct
if (nbuttons == 0)
return NULL;
pdata = kzalloc(sizeof(*pdata) + nbuttons * (sizeof *button),
pdata = devm_kzalloc(dev, sizeof(*pdata) + nbuttons * sizeof(*button),
GFP_KERNEL);
if (!pdata) {
error = -ENOMEM;
goto err_out;
}
if (!pdata)
return ERR_PTR(-ENOMEM);
pdata->buttons = (struct gpio_keys_button *)(pdata + 1);
pdata->nbuttons = nbuttons;
......@@ -151,7 +149,7 @@ static struct gpio_keys_platform_data *gpio_keys_polled_get_devtree_pdata(struct
dev_err(dev,
"Failed to get gpio flags, error: %d\n",
error);
goto err_free_pdata;
return ERR_PTR(error);
}
button = &pdata->buttons[i++];
......@@ -162,8 +160,7 @@ static struct gpio_keys_platform_data *gpio_keys_polled_get_devtree_pdata(struct
if (of_property_read_u32(pp, "linux,code", &button->code)) {
dev_err(dev, "Button without keycode: 0x%x\n",
button->gpio);
error = -EINVAL;
goto err_free_pdata;
return ERR_PTR(-EINVAL);
}
button->desc = of_get_property(pp, "label", NULL);
......@@ -178,20 +175,13 @@ static struct gpio_keys_platform_data *gpio_keys_polled_get_devtree_pdata(struct
button->debounce_interval = 5;
}
if (pdata->nbuttons == 0) {
error = -EINVAL;
goto err_free_pdata;
}
if (pdata->nbuttons == 0)
return ERR_PTR(-EINVAL);
return pdata;
err_free_pdata:
kfree(pdata);
err_out:
return ERR_PTR(error);
}
static struct of_device_id gpio_keys_polled_of_match[] = {
static const struct of_device_id gpio_keys_polled_of_match[] = {
{ .compatible = "gpio-keys-polled", },
{ },
};
......@@ -213,6 +203,7 @@ static int gpio_keys_polled_probe(struct platform_device *pdev)
struct gpio_keys_polled_dev *bdev;
struct input_polled_dev *poll_dev;
struct input_dev *input;
size_t size;
int error;
int i;
......@@ -228,24 +219,21 @@ static int gpio_keys_polled_probe(struct platform_device *pdev)
if (!pdata->poll_interval) {
dev_err(dev, "missing poll_interval value\n");
error = -EINVAL;
goto err_free_pdata;
return -EINVAL;
}
bdev = kzalloc(sizeof(struct gpio_keys_polled_dev) +
pdata->nbuttons * sizeof(struct gpio_keys_button_data),
GFP_KERNEL);
size = sizeof(struct gpio_keys_polled_dev) +
pdata->nbuttons * sizeof(struct gpio_keys_button_data);
bdev = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
if (!bdev) {
dev_err(dev, "no memory for private data\n");
error = -ENOMEM;
goto err_free_pdata;
return -ENOMEM;
}
poll_dev = input_allocate_polled_device();
poll_dev = devm_input_allocate_polled_device(&pdev->dev);
if (!poll_dev) {
dev_err(dev, "no memory for polled device\n");
error = -ENOMEM;
goto err_free_bdev;
return -ENOMEM;
}
poll_dev->private = bdev;
......@@ -258,7 +246,6 @@ static int gpio_keys_polled_probe(struct platform_device *pdev)
input->name = pdev->name;
input->phys = DRV_NAME"/input0";
input->dev.parent = &pdev->dev;
input->id.bustype = BUS_HOST;
input->id.vendor = 0x0001;
......@@ -277,16 +264,15 @@ static int gpio_keys_polled_probe(struct platform_device *pdev)
if (button->wakeup) {
dev_err(dev, DRV_NAME " does not support wakeup\n");
error = -EINVAL;
goto err_free_gpio;
return -EINVAL;
}
error = gpio_request_one(gpio, GPIOF_IN,
button->desc ?: DRV_NAME);
error = devm_gpio_request_one(&pdev->dev, gpio, GPIOF_IN,
button->desc ? : DRV_NAME);
if (error) {
dev_err(dev, "unable to claim gpio %u, err=%d\n",
gpio, error);
goto err_free_gpio;
return error;
}
bdata->can_sleep = gpio_cansleep(gpio);
......@@ -306,7 +292,7 @@ static int gpio_keys_polled_probe(struct platform_device *pdev)
if (error) {
dev_err(dev, "unable to register polled device, err=%d\n",
error);
goto err_free_gpio;
return error;
}
/* report initial state of the buttons */
......@@ -315,52 +301,10 @@ static int gpio_keys_polled_probe(struct platform_device *pdev)
&bdev->data[i]);
return 0;
err_free_gpio:
while (--i >= 0)
gpio_free(pdata->buttons[i].gpio);
input_free_polled_device(poll_dev);
err_free_bdev:
kfree(bdev);
err_free_pdata:
/* If we have no platform_data, we allocated pdata dynamically. */
if (!dev_get_platdata(&pdev->dev))
kfree(pdata);
return error;
}
static int gpio_keys_polled_remove(struct platform_device *pdev)
{
struct gpio_keys_polled_dev *bdev = platform_get_drvdata(pdev);
const struct gpio_keys_platform_data *pdata = bdev->pdata;
int i;
input_unregister_polled_device(bdev->poll_dev);
for (i = 0; i < pdata->nbuttons; i++)
gpio_free(pdata->buttons[i].gpio);
input_free_polled_device(bdev->poll_dev);
/*
* If we had no platform_data, we allocated pdata dynamically and
* must free it here.
*/
if (!dev_get_platdata(&pdev->dev))
kfree(pdata);
kfree(bdev);
return 0;
}
static struct platform_driver gpio_keys_polled_driver = {
.probe = gpio_keys_polled_probe,
.remove = gpio_keys_polled_remove,
.driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
......
......@@ -415,7 +415,7 @@ static int imx_keypad_open(struct input_dev *dev)
}
#ifdef CONFIG_OF
static struct of_device_id imx_keypad_of_match[] = {
static const struct of_device_id imx_keypad_of_match[] = {
{ .compatible = "fsl,imx21-kpp", },
{ /* sentinel */ }
};
......
......@@ -16,6 +16,7 @@
* published by the Free Software Foundation.
*/
#include <linux/device.h>
#include <linux/input.h>
#include <linux/input-polldev.h>
#include <linux/interrupt.h>
......@@ -185,14 +186,15 @@ static int jornada680kbd_probe(struct platform_device *pdev)
struct input_dev *input_dev;
int i, error;
jornadakbd = kzalloc(sizeof(struct jornadakbd), GFP_KERNEL);
jornadakbd = devm_kzalloc(&pdev->dev, sizeof(struct jornadakbd),
GFP_KERNEL);
if (!jornadakbd)
return -ENOMEM;
poll_dev = input_allocate_polled_device();
poll_dev = devm_input_allocate_polled_device(&pdev->dev);
if (!poll_dev) {
error = -ENOMEM;
goto failed;
dev_err(&pdev->dev, "failed to allocate polled input device\n");
return -ENOMEM;
}
platform_set_drvdata(pdev, jornadakbd);
......@@ -224,27 +226,10 @@ static int jornada680kbd_probe(struct platform_device *pdev)
input_set_capability(input_dev, EV_MSC, MSC_SCAN);
error = input_register_polled_device(jornadakbd->poll_dev);
if (error)
goto failed;
return 0;
failed:
printk(KERN_ERR "Jornadakbd: failed to register driver, error: %d\n",
error);
input_free_polled_device(poll_dev);
kfree(jornadakbd);
if (error) {
dev_err(&pdev->dev, "failed to register polled input device\n");
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;
}
......@@ -255,7 +240,6 @@ static struct platform_driver jornada680kbd_driver = {
.owner = THIS_MODULE,
},
.probe = jornada680kbd_probe,
.remove = jornada680kbd_remove,
};
module_platform_driver(jornada680kbd_driver);
......
......@@ -147,7 +147,7 @@ static int mcs_touchkey_probe(struct i2c_client *client,
}
dev_info(&client->dev, "Firmware version: %d\n", fw_ver);
input_dev->name = "MELPAS MCS Touchkey";
input_dev->name = "MELFAS MCS Touchkey";
input_dev->id.bustype = BUS_I2C;
input_dev->dev.parent = &client->dev;
input_dev->evbit[0] = BIT_MASK(EV_KEY);
......
......@@ -28,11 +28,10 @@
#include <linux/io.h>
#include <linux/of.h>
#include <linux/input.h>
#include <linux/input/matrix_keypad.h>
#include <linux/slab.h>
#include <linux/pm_runtime.h>
#include <linux/platform_data/omap4-keypad.h>
/* OMAP4 registers */
#define OMAP4_KBD_REVISION 0x00
#define OMAP4_KBD_SYSCONFIG 0x10
......@@ -218,7 +217,6 @@ static void omap4_keypad_close(struct input_dev *input)
pm_runtime_put_sync(input->dev.parent);
}
#ifdef CONFIG_OF
static int omap4_keypad_parse_dt(struct device *dev,
struct omap4_keypad *keypad_data)
{
......@@ -235,20 +233,9 @@ static int omap4_keypad_parse_dt(struct device *dev,
return 0;
}
#else
static inline int omap4_keypad_parse_dt(struct device *dev,
struct omap4_keypad *keypad_data)
{
return -ENOSYS;
}
#endif
static int omap4_keypad_probe(struct platform_device *pdev)
{
const struct omap4_keypad_platform_data *pdata =
dev_get_platdata(&pdev->dev);
const struct matrix_keymap_data *keymap_data =
pdata ? pdata->keymap_data : NULL;
struct omap4_keypad *keypad_data;
struct input_dev *input_dev;
struct resource *res;
......@@ -277,14 +264,9 @@ static int omap4_keypad_probe(struct platform_device *pdev)
keypad_data->irq = irq;
if (pdata) {
keypad_data->rows = pdata->rows;
keypad_data->cols = pdata->cols;
} else {
error = omap4_keypad_parse_dt(&pdev->dev, keypad_data);
if (error)
return error;
}
res = request_mem_region(res->start, resource_size(res), pdev->name);
if (!res) {
......@@ -363,7 +345,7 @@ static int omap4_keypad_probe(struct platform_device *pdev)
goto err_free_input;
}
error = matrix_keypad_build_keymap(keymap_data, NULL,
error = matrix_keypad_build_keymap(NULL, NULL,
keypad_data->rows, keypad_data->cols,
keypad_data->keymap, input_dev);
if (error) {
......@@ -434,13 +416,11 @@ static int omap4_keypad_remove(struct platform_device *pdev)
return 0;
}
#ifdef CONFIG_OF
static const struct of_device_id omap_keypad_dt_match[] = {
{ .compatible = "ti,omap4-keypad" },
{},
};
MODULE_DEVICE_TABLE(of, omap_keypad_dt_match);
#endif
#ifdef CONFIG_PM_SLEEP
static int omap4_keypad_suspend(struct device *dev)
......@@ -482,7 +462,7 @@ static struct platform_driver omap4_keypad_driver = {
.name = "omap4-keypad",
.owner = THIS_MODULE,
.pm = &omap4_keypad_pm_ops,
.of_match_table = of_match_ptr(omap_keypad_dt_match),
.of_match_table = omap_keypad_dt_match,
},
};
module_platform_driver(omap4_keypad_driver);
......
/*
* STMicroelectronics Key Scanning driver
*
* Copyright (c) 2014 STMicroelectonics Ltd.
* Author: Stuart Menefy <stuart.menefy@st.com>
*
* Based on sh_keysc.c, copyright 2008 Magnus Damm
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/input/matrix_keypad.h>
#define ST_KEYSCAN_MAXKEYS 16
#define KEYSCAN_CONFIG_OFF 0x0
#define KEYSCAN_CONFIG_ENABLE 0x1
#define KEYSCAN_DEBOUNCE_TIME_OFF 0x4
#define KEYSCAN_MATRIX_STATE_OFF 0x8
#define KEYSCAN_MATRIX_DIM_OFF 0xc
#define KEYSCAN_MATRIX_DIM_X_SHIFT 0x0
#define KEYSCAN_MATRIX_DIM_Y_SHIFT 0x2
struct st_keyscan {
void __iomem *base;
int irq;
struct clk *clk;
struct input_dev *input_dev;
unsigned long last_state;
unsigned int n_rows;
unsigned int n_cols;
unsigned int debounce_us;
};
static irqreturn_t keyscan_isr(int irq, void *dev_id)
{
struct st_keyscan *keypad = dev_id;
unsigned short *keycode = keypad->input_dev->keycode;
unsigned long state, change;
int bit_nr;
state = readl(keypad->base + KEYSCAN_MATRIX_STATE_OFF) & 0xffff;
change = keypad->last_state ^ state;
keypad->last_state = state;
for_each_set_bit(bit_nr, &change, BITS_PER_LONG)
input_report_key(keypad->input_dev,
keycode[bit_nr], state & BIT(bit_nr));
input_sync(keypad->input_dev);
return IRQ_HANDLED;
}
static int keyscan_start(struct st_keyscan *keypad)
{
int error;
error = clk_enable(keypad->clk);
if (error)
return error;
writel(keypad->debounce_us * (clk_get_rate(keypad->clk) / 1000000),
keypad->base + KEYSCAN_DEBOUNCE_TIME_OFF);
writel(((keypad->n_cols - 1) << KEYSCAN_MATRIX_DIM_X_SHIFT) |
((keypad->n_rows - 1) << KEYSCAN_MATRIX_DIM_Y_SHIFT),
keypad->base + KEYSCAN_MATRIX_DIM_OFF);
writel(KEYSCAN_CONFIG_ENABLE, keypad->base + KEYSCAN_CONFIG_OFF);
return 0;
}
static void keyscan_stop(struct st_keyscan *keypad)
{
writel(0, keypad->base + KEYSCAN_CONFIG_OFF);
clk_disable(keypad->clk);
}
static int keyscan_open(struct input_dev *dev)
{
struct st_keyscan *keypad = input_get_drvdata(dev);
return keyscan_start(keypad);
}
static void keyscan_close(struct input_dev *dev)
{
struct st_keyscan *keypad = input_get_drvdata(dev);
keyscan_stop(keypad);
}
static int keypad_matrix_key_parse_dt(struct st_keyscan *keypad_data)
{
struct device *dev = keypad_data->input_dev->dev.parent;
struct device_node *np = dev->of_node;
int error;
error = matrix_keypad_parse_of_params(dev, &keypad_data->n_rows,
&keypad_data->n_cols);
if (error) {
dev_err(dev, "failed to parse keypad params\n");
return error;
}
of_property_read_u32(np, "st,debounce-us", &keypad_data->debounce_us);
dev_dbg(dev, "n_rows=%d n_col=%d debounce=%d\n",
keypad_data->n_rows, keypad_data->n_cols,
keypad_data->debounce_us);
return 0;
}
static int keyscan_probe(struct platform_device *pdev)
{
struct st_keyscan *keypad_data;
struct input_dev *input_dev;
struct resource *res;
int error;
if (!pdev->dev.of_node) {
dev_err(&pdev->dev, "no DT data present\n");
return -EINVAL;
}
keypad_data = devm_kzalloc(&pdev->dev, sizeof(*keypad_data),
GFP_KERNEL);
if (!keypad_data)
return -ENOMEM;
input_dev = devm_input_allocate_device(&pdev->dev);
if (!input_dev) {
dev_err(&pdev->dev, "failed to allocate the input device\n");
return -ENOMEM;
}
input_dev->name = pdev->name;
input_dev->phys = "keyscan-keys/input0";
input_dev->dev.parent = &pdev->dev;
input_dev->open = keyscan_open;
input_dev->close = keyscan_close;
input_dev->id.bustype = BUS_HOST;
error = keypad_matrix_key_parse_dt(keypad_data);
if (error)
return error;
error = matrix_keypad_build_keymap(NULL, NULL,
keypad_data->n_rows,
keypad_data->n_cols,
NULL, input_dev);
if (error) {
dev_err(&pdev->dev, "failed to build keymap\n");
return error;
}
input_set_drvdata(input_dev, keypad_data);
keypad_data->input_dev = input_dev;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
keypad_data->base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(keypad_data->base))
return PTR_ERR(keypad_data->base);
keypad_data->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(keypad_data->clk)) {
dev_err(&pdev->dev, "cannot get clock\n");
return PTR_ERR(keypad_data->clk);
}
error = clk_enable(keypad_data->clk);
if (error) {
dev_err(&pdev->dev, "failed to enable clock\n");
return error;
}
keyscan_stop(keypad_data);
keypad_data->irq = platform_get_irq(pdev, 0);
if (keypad_data->irq < 0) {
dev_err(&pdev->dev, "no IRQ specified\n");
return -EINVAL;
}
error = devm_request_irq(&pdev->dev, keypad_data->irq, keyscan_isr, 0,
pdev->name, keypad_data);
if (error) {
dev_err(&pdev->dev, "failed to request IRQ\n");
return error;
}
error = input_register_device(input_dev);
if (error) {
dev_err(&pdev->dev, "failed to register input device\n");
return error;
}
platform_set_drvdata(pdev, keypad_data);
device_set_wakeup_capable(&pdev->dev, 1);
return 0;
}
static int keyscan_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct st_keyscan *keypad = platform_get_drvdata(pdev);
struct input_dev *input = keypad->input_dev;
mutex_lock(&input->mutex);
if (device_may_wakeup(dev))
enable_irq_wake(keypad->irq);
else if (input->users)
keyscan_stop(keypad);
mutex_unlock(&input->mutex);
return 0;
}
static int keyscan_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct st_keyscan *keypad = platform_get_drvdata(pdev);
struct input_dev *input = keypad->input_dev;
int retval = 0;
mutex_lock(&input->mutex);
if (device_may_wakeup(dev))
disable_irq_wake(keypad->irq);
else if (input->users)
retval = keyscan_start(keypad);
mutex_unlock(&input->mutex);
return retval;
}
static SIMPLE_DEV_PM_OPS(keyscan_dev_pm_ops, keyscan_suspend, keyscan_resume);
static const struct of_device_id keyscan_of_match[] = {
{ .compatible = "st,sti-keyscan" },
{ },
};
MODULE_DEVICE_TABLE(of, keyscan_of_match);
static struct platform_driver keyscan_device_driver = {
.probe = keyscan_probe,
.driver = {
.name = "st-keyscan",
.pm = &keyscan_dev_pm_ops,
.of_match_table = of_match_ptr(keyscan_of_match),
}
};
module_platform_driver(keyscan_device_driver);
MODULE_AUTHOR("Stuart Menefy <stuart.menefy@st.com>");
MODULE_DESCRIPTION("STMicroelectronics keyscan device driver");
MODULE_LICENSE("GPL");
......@@ -296,6 +296,65 @@ static void tc3589x_keypad_close(struct input_dev *input)
tc3589x_keypad_disable(keypad);
}
#ifdef CONFIG_OF
static const struct tc3589x_keypad_platform_data *
tc3589x_keypad_of_probe(struct device *dev)
{
struct device_node *np = dev->of_node;
struct tc3589x_keypad_platform_data *plat;
u32 cols, rows;
u32 debounce_ms;
int proplen;
if (!np)
return ERR_PTR(-ENODEV);
plat = devm_kzalloc(dev, sizeof(*plat), GFP_KERNEL);
if (!plat)
return ERR_PTR(-ENOMEM);
of_property_read_u32(np, "keypad,num-columns", &cols);
of_property_read_u32(np, "keypad,num-rows", &rows);
plat->kcol = (u8) cols;
plat->krow = (u8) rows;
if (!plat->krow || !plat->kcol ||
plat->krow > TC_KPD_ROWS || plat->kcol > TC_KPD_COLUMNS) {
dev_err(dev,
"keypad columns/rows not properly specified (%ux%u)\n",
plat->kcol, plat->krow);
return ERR_PTR(-EINVAL);
}
if (!of_get_property(np, "linux,keymap", &proplen)) {
dev_err(dev, "property linux,keymap not found\n");
return ERR_PTR(-ENOENT);
}
plat->no_autorepeat = of_property_read_bool(np, "linux,no-autorepeat");
plat->enable_wakeup = of_property_read_bool(np, "linux,wakeup");
/* The custom delay format is ms/16 */
of_property_read_u32(np, "debounce-delay-ms", &debounce_ms);
if (debounce_ms)
plat->debounce_period = debounce_ms * 16;
else
plat->debounce_period = TC_KPD_DEBOUNCE_PERIOD;
plat->settle_time = TC_KPD_SETTLE_TIME;
/* FIXME: should be property of the IRQ resource? */
plat->irqtype = IRQF_TRIGGER_FALLING;
return plat;
}
#else
static inline const struct tc3589x_keypad_platform_data *
tc3589x_keypad_of_probe(struct device *dev)
{
return ERR_PTR(-ENODEV);
}
#endif
static int tc3589x_keypad_probe(struct platform_device *pdev)
{
struct tc3589x *tc3589x = dev_get_drvdata(pdev->dev.parent);
......@@ -306,8 +365,11 @@ static int tc3589x_keypad_probe(struct platform_device *pdev)
plat = tc3589x->pdata->keypad;
if (!plat) {
plat = tc3589x_keypad_of_probe(&pdev->dev);
if (IS_ERR(plat)) {
dev_err(&pdev->dev, "invalid keypad platform data\n");
return -EINVAL;
return PTR_ERR(plat);
}
}
irq = platform_get_irq(pdev, 0);
......
......@@ -26,6 +26,7 @@
#include <linux/interrupt.h>
#include <linux/mfd/88pm860x.h>
#include <linux/slab.h>
#include <linux/device.h>
#define PM8607_WAKEUP 0x0b
......@@ -68,7 +69,8 @@ static int pm860x_onkey_probe(struct platform_device *pdev)
return -EINVAL;
}
info = kzalloc(sizeof(struct pm860x_onkey_info), GFP_KERNEL);
info = devm_kzalloc(&pdev->dev, sizeof(struct pm860x_onkey_info),
GFP_KERNEL);
if (!info)
return -ENOMEM;
info->chip = chip;
......@@ -76,11 +78,10 @@ static int pm860x_onkey_probe(struct platform_device *pdev)
info->dev = &pdev->dev;
info->irq = irq;
info->idev = input_allocate_device();
info->idev = devm_input_allocate_device(&pdev->dev);
if (!info->idev) {
dev_err(chip->dev, "Failed to allocate input dev\n");
ret = -ENOMEM;
goto out;
return -ENOMEM;
}
info->idev->name = "88pm860x_on";
......@@ -93,42 +94,22 @@ static int pm860x_onkey_probe(struct platform_device *pdev)
ret = input_register_device(info->idev);
if (ret) {
dev_err(chip->dev, "Can't register input device: %d\n", ret);
goto out_reg;
return ret;
}
ret = request_threaded_irq(info->irq, NULL, pm860x_onkey_handler,
IRQF_ONESHOT, "onkey", info);
ret = devm_request_threaded_irq(&pdev->dev, info->irq, NULL,
pm860x_onkey_handler, IRQF_ONESHOT,
"onkey", info);
if (ret < 0) {
dev_err(chip->dev, "Failed to request IRQ: #%d: %d\n",
info->irq, ret);
goto out_irq;
return ret;
}
platform_set_drvdata(pdev, info);
device_init_wakeup(&pdev->dev, 1);
return 0;
out_irq:
input_unregister_device(info->idev);
kfree(info);
return ret;
out_reg:
input_free_device(info->idev);
out:
kfree(info);
return ret;
}
static int pm860x_onkey_remove(struct platform_device *pdev)
{
struct pm860x_onkey_info *info = platform_get_drvdata(pdev);
free_irq(info->irq, info);
input_unregister_device(info->idev);
kfree(info);
return 0;
}
#ifdef CONFIG_PM_SLEEP
......@@ -161,7 +142,6 @@ static struct platform_driver pm860x_onkey_driver = {
.pm = &pm860x_onkey_pm_ops,
},
.probe = pm860x_onkey_probe,
.remove = pm860x_onkey_remove,
};
module_platform_driver(pm860x_onkey_driver);
......
......@@ -224,7 +224,7 @@ config INPUT_GP2A
config INPUT_GPIO_BEEPER
tristate "Generic GPIO Beeper support"
depends on OF_GPIO
depends on GPIOLIB
help
Say Y here if you have a beeper connected to a GPIO pin.
......
......@@ -7,6 +7,7 @@
* AB8500 Power-On Key handler
*/
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
......@@ -65,12 +66,14 @@ static int ab8500_ponkey_probe(struct platform_device *pdev)
return irq_dbr;
}
ponkey = kzalloc(sizeof(struct ab8500_ponkey), GFP_KERNEL);
input = input_allocate_device();
if (!ponkey || !input) {
error = -ENOMEM;
goto err_free_mem;
}
ponkey = devm_kzalloc(&pdev->dev, sizeof(struct ab8500_ponkey),
GFP_KERNEL);
if (!ponkey)
return -ENOMEM;
input = devm_input_allocate_device(&pdev->dev);
if (!input)
return -ENOMEM;
ponkey->idev = input;
ponkey->ab8500 = ab8500;
......@@ -82,52 +85,32 @@ static int ab8500_ponkey_probe(struct platform_device *pdev)
input_set_capability(input, EV_KEY, KEY_POWER);
error = request_any_context_irq(ponkey->irq_dbf, ab8500_ponkey_handler,
0, "ab8500-ponkey-dbf", ponkey);
error = devm_request_any_context_irq(&pdev->dev, ponkey->irq_dbf,
ab8500_ponkey_handler, 0,
"ab8500-ponkey-dbf", ponkey);
if (error < 0) {
dev_err(ab8500->dev, "Failed to request dbf IRQ#%d: %d\n",
ponkey->irq_dbf, error);
goto err_free_mem;
return error;
}
error = request_any_context_irq(ponkey->irq_dbr, ab8500_ponkey_handler,
0, "ab8500-ponkey-dbr", ponkey);
error = devm_request_any_context_irq(&pdev->dev, ponkey->irq_dbr,
ab8500_ponkey_handler, 0,
"ab8500-ponkey-dbr", ponkey);
if (error < 0) {
dev_err(ab8500->dev, "Failed to request dbr IRQ#%d: %d\n",
ponkey->irq_dbr, error);
goto err_free_dbf_irq;
return error;
}
error = input_register_device(ponkey->idev);
if (error) {
dev_err(ab8500->dev, "Can't register input device: %d\n", error);
goto err_free_dbr_irq;
return error;
}
platform_set_drvdata(pdev, ponkey);
return 0;
err_free_dbr_irq:
free_irq(ponkey->irq_dbr, ponkey);
err_free_dbf_irq:
free_irq(ponkey->irq_dbf, ponkey);
err_free_mem:
input_free_device(input);
kfree(ponkey);
return error;
}
static int ab8500_ponkey_remove(struct platform_device *pdev)
{
struct ab8500_ponkey *ponkey = platform_get_drvdata(pdev);
free_irq(ponkey->irq_dbf, ponkey);
free_irq(ponkey->irq_dbr, ponkey);
input_unregister_device(ponkey->idev);
kfree(ponkey);
return 0;
}
#ifdef CONFIG_OF
......@@ -144,7 +127,6 @@ static struct platform_driver ab8500_ponkey_driver = {
.of_match_table = of_match_ptr(ab8500_ponkey_match),
},
.probe = ab8500_ponkey_probe,
.remove = ab8500_ponkey_remove,
};
module_platform_driver(ab8500_ponkey_driver);
......
/*
* Generic GPIO beeper driver
*
* Copyright (C) 2013 Alexander Shiyan <shc_work@mail.ru>
* Copyright (C) 2013-2014 Alexander Shiyan <shc_work@mail.ru>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
......@@ -11,7 +11,8 @@
#include <linux/input.h>
#include <linux/module.h>
#include <linux/of_gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/of.h>
#include <linux/workqueue.h>
#include <linux/platform_device.h>
......@@ -19,14 +20,13 @@
struct gpio_beeper {
struct work_struct work;
int gpio;
bool active_low;
struct gpio_desc *desc;
bool beeping;
};
static void gpio_beeper_toggle(struct gpio_beeper *beep, bool on)
{
gpio_set_value_cansleep(beep->gpio, on ^ beep->active_low);
gpiod_set_value_cansleep(beep->desc, on);
}
static void gpio_beeper_work(struct work_struct *work)
......@@ -65,18 +65,16 @@ static void gpio_beeper_close(struct input_dev *input)
static int gpio_beeper_probe(struct platform_device *pdev)
{
struct gpio_beeper *beep;
enum of_gpio_flags flags;
struct input_dev *input;
unsigned long gflags;
int err;
beep = devm_kzalloc(&pdev->dev, sizeof(*beep), GFP_KERNEL);
if (!beep)
return -ENOMEM;
beep->gpio = of_get_gpio_flags(pdev->dev.of_node, 0, &flags);
if (!gpio_is_valid(beep->gpio))
return beep->gpio;
beep->desc = devm_gpiod_get(&pdev->dev, NULL);
if (IS_ERR(beep->desc))
return PTR_ERR(beep->desc);
input = devm_input_allocate_device(&pdev->dev);
if (!input)
......@@ -94,10 +92,7 @@ static int gpio_beeper_probe(struct platform_device *pdev)
input_set_capability(input, EV_SND, SND_BELL);
beep->active_low = flags & OF_GPIO_ACTIVE_LOW;
gflags = beep->active_low ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW;
err = devm_gpio_request_one(&pdev->dev, beep->gpio, gflags, pdev->name);
err = gpiod_direction_output(beep->desc, 0);
if (err)
return err;
......@@ -106,17 +101,19 @@ static int gpio_beeper_probe(struct platform_device *pdev)
return input_register_device(input);
}
static struct of_device_id gpio_beeper_of_match[] = {
#ifdef CONFIG_OF
static const struct of_device_id gpio_beeper_of_match[] = {
{ .compatible = BEEPER_MODNAME, },
{ }
};
MODULE_DEVICE_TABLE(of, gpio_beeper_of_match);
#endif
static struct platform_driver gpio_beeper_platform_driver = {
.driver = {
.name = BEEPER_MODNAME,
.owner = THIS_MODULE,
.of_match_table = gpio_beeper_of_match,
.of_match_table = of_match_ptr(gpio_beeper_of_match),
},
.probe = gpio_beeper_probe,
};
......
......@@ -1566,6 +1566,7 @@ static int ims_pcu_buffers_alloc(struct ims_pcu *pcu)
if (!pcu->urb_ctrl_buf) {
dev_err(pcu->dev,
"Failed to allocate memory for read buffer\n");
error = -ENOMEM;
goto err_free_urb_out_buf;
}
......
......@@ -26,6 +26,7 @@
#include <linux/interrupt.h>
#include <linux/mfd/max8925.h>
#include <linux/slab.h>
#include <linux/device.h>
#define SW_INPUT (1 << 7) /* 0/1 -- up/down */
#define HARDRESET_EN (1 << 7)
......@@ -81,12 +82,14 @@ static int max8925_onkey_probe(struct platform_device *pdev)
return -EINVAL;
}
info = kzalloc(sizeof(struct max8925_onkey_info), GFP_KERNEL);
input = input_allocate_device();
if (!info || !input) {
error = -ENOMEM;
goto err_free_mem;
}
info = devm_kzalloc(&pdev->dev, sizeof(struct max8925_onkey_info),
GFP_KERNEL);
if (!info)
return -ENOMEM;
input = devm_input_allocate_device(&pdev->dev);
if (!input)
return -ENOMEM;
info->idev = input;
info->i2c = chip->i2c;
......@@ -100,54 +103,33 @@ static int max8925_onkey_probe(struct platform_device *pdev)
input->dev.parent = &pdev->dev;
input_set_capability(input, EV_KEY, KEY_POWER);
error = request_threaded_irq(irq[0], NULL, max8925_onkey_handler,
IRQF_ONESHOT, "onkey-down", info);
error = devm_request_threaded_irq(&pdev->dev, irq[0], NULL,
max8925_onkey_handler, IRQF_ONESHOT,
"onkey-down", info);
if (error < 0) {
dev_err(chip->dev, "Failed to request IRQ: #%d: %d\n",
irq[0], error);
goto err_free_mem;
return error;
}
error = request_threaded_irq(irq[1], NULL, max8925_onkey_handler,
IRQF_ONESHOT, "onkey-up", info);
error = devm_request_threaded_irq(&pdev->dev, irq[1], NULL,
max8925_onkey_handler, IRQF_ONESHOT,
"onkey-up", info);
if (error < 0) {
dev_err(chip->dev, "Failed to request IRQ: #%d: %d\n",
irq[1], error);
goto err_free_irq0;
return error;
}
error = input_register_device(info->idev);
if (error) {
dev_err(chip->dev, "Can't register input device: %d\n", error);
goto err_free_irq1;
return error;
}
platform_set_drvdata(pdev, info);
device_init_wakeup(&pdev->dev, 1);
return 0;
err_free_irq1:
free_irq(irq[1], info);
err_free_irq0:
free_irq(irq[0], info);
err_free_mem:
input_free_device(input);
kfree(info);
return error;
}
static int max8925_onkey_remove(struct platform_device *pdev)
{
struct max8925_onkey_info *info = platform_get_drvdata(pdev);
struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent);
free_irq(info->irq[0] + chip->irq_base, info);
free_irq(info->irq[1] + chip->irq_base, info);
input_unregister_device(info->idev);
kfree(info);
return 0;
}
......@@ -190,7 +172,6 @@ static struct platform_driver max8925_onkey_driver = {
.pm = &max8925_onkey_pm_ops,
},
.probe = max8925_onkey_probe,
.remove = max8925_onkey_remove,
};
module_platform_driver(max8925_onkey_driver);
......
......@@ -181,11 +181,21 @@ static void max8997_haptic_enable(struct max8997_haptic *chip)
}
if (!chip->enabled) {
chip->enabled = true;
regulator_enable(chip->regulator);
error = regulator_enable(chip->regulator);
if (error) {
dev_err(chip->dev, "Failed to enable regulator\n");
goto out;
}
max8997_haptic_configure(chip);
if (chip->mode == MAX8997_EXTERNAL_MODE)
pwm_enable(chip->pwm);
if (chip->mode == MAX8997_EXTERNAL_MODE) {
error = pwm_enable(chip->pwm);
if (error) {
dev_err(chip->dev, "Failed to enable PWM\n");
regulator_disable(chip->regulator);
goto out;
}
}
chip->enabled = true;
}
out:
......
......@@ -92,15 +92,15 @@ static int pmic8xxx_pwrkey_probe(struct platform_device *pdev)
bool pull_up;
if (of_property_read_u32(pdev->dev.of_node, "debounce", &kpd_delay))
kpd_delay = 0;
kpd_delay = 15625;
pull_up = of_property_read_bool(pdev->dev.of_node, "pull-up");
if (kpd_delay > 62500) {
if (kpd_delay > 62500 || kpd_delay == 0) {
dev_err(&pdev->dev, "invalid power key trigger delay\n");
return -EINVAL;
}
pull_up = of_property_read_bool(pdev->dev.of_node, "pull-up");
regmap = dev_get_regmap(pdev->dev.parent, NULL);
if (!regmap) {
dev_err(&pdev->dev, "failed to locate regmap for the device\n");
......
......@@ -143,7 +143,7 @@ static irqreturn_t rotary_encoder_half_period_irq(int irq, void *dev_id)
}
#ifdef CONFIG_OF
static struct of_device_id rotary_encoder_of_match[] = {
static const struct of_device_id rotary_encoder_of_match[] = {
{ .compatible = "rotary-encoder", },
{ },
};
......
......@@ -17,7 +17,6 @@
#include <linux/acpi.h>
#include <linux/gpio/consumer.h>
#include <linux/gpio_keys.h>
#include <linux/input.h>
#include <linux/platform_device.h>
#include <linux/pnp.h>
......
......@@ -262,7 +262,7 @@ static int twl6040_vibra_probe(struct platform_device *pdev)
struct vibra_info *info;
int vddvibl_uV = 0;
int vddvibr_uV = 0;
int ret;
int error;
twl6040_core_node = of_find_node_by_name(twl6040_core_dev->of_node,
"vibra");
......@@ -309,12 +309,12 @@ static int twl6040_vibra_probe(struct platform_device *pdev)
mutex_init(&info->mutex);
ret = devm_request_threaded_irq(&pdev->dev, info->irq, NULL,
error = devm_request_threaded_irq(&pdev->dev, info->irq, NULL,
twl6040_vib_irq_handler, 0,
"twl6040_irq_vib", info);
if (ret) {
dev_err(info->dev, "VIB IRQ request failed: %d\n", ret);
return ret;
if (error) {
dev_err(info->dev, "VIB IRQ request failed: %d\n", error);
return error;
}
info->supplies[0].supply = "vddvibl";
......@@ -323,40 +323,40 @@ static int twl6040_vibra_probe(struct platform_device *pdev)
* When booted with Device tree the regulators are attached to the
* parent device (twl6040 MFD core)
*/
ret = regulator_bulk_get(twl6040_core_dev, ARRAY_SIZE(info->supplies),
error = devm_regulator_bulk_get(twl6040_core_dev,
ARRAY_SIZE(info->supplies),
info->supplies);
if (ret) {
dev_err(info->dev, "couldn't get regulators %d\n", ret);
return ret;
if (error) {
dev_err(info->dev, "couldn't get regulators %d\n", error);
return error;
}
if (vddvibl_uV) {
ret = regulator_set_voltage(info->supplies[0].consumer,
error = regulator_set_voltage(info->supplies[0].consumer,
vddvibl_uV, vddvibl_uV);
if (ret) {
if (error) {
dev_err(info->dev, "failed to set VDDVIBL volt %d\n",
ret);
goto err_regulator;
error);
return error;
}
}
if (vddvibr_uV) {
ret = regulator_set_voltage(info->supplies[1].consumer,
error = regulator_set_voltage(info->supplies[1].consumer,
vddvibr_uV, vddvibr_uV);
if (ret) {
if (error) {
dev_err(info->dev, "failed to set VDDVIBR volt %d\n",
ret);
goto err_regulator;
error);
return error;
}
}
INIT_WORK(&info->play_work, vibra_play_work);
info->input_dev = input_allocate_device();
if (info->input_dev == NULL) {
info->input_dev = devm_input_allocate_device(&pdev->dev);
if (!info->input_dev) {
dev_err(info->dev, "couldn't allocate input device\n");
ret = -ENOMEM;
goto err_regulator;
return -ENOMEM;
}
input_set_drvdata(info->input_dev, info);
......@@ -367,44 +367,25 @@ static int twl6040_vibra_probe(struct platform_device *pdev)
info->input_dev->close = twl6040_vibra_close;
__set_bit(FF_RUMBLE, info->input_dev->ffbit);
ret = input_ff_create_memless(info->input_dev, NULL, vibra_play);
if (ret < 0) {
error = input_ff_create_memless(info->input_dev, NULL, vibra_play);
if (error) {
dev_err(info->dev, "couldn't register vibrator to FF\n");
goto err_ialloc;
return error;
}
ret = input_register_device(info->input_dev);
if (ret < 0) {
error = input_register_device(info->input_dev);
if (error) {
dev_err(info->dev, "couldn't register input device\n");
goto err_iff;
return error;
}
platform_set_drvdata(pdev, info);
return 0;
err_iff:
input_ff_destroy(info->input_dev);
err_ialloc:
input_free_device(info->input_dev);
err_regulator:
regulator_bulk_free(ARRAY_SIZE(info->supplies), info->supplies);
return ret;
}
static int twl6040_vibra_remove(struct platform_device *pdev)
{
struct vibra_info *info = platform_get_drvdata(pdev);
input_unregister_device(info->input_dev);
regulator_bulk_free(ARRAY_SIZE(info->supplies), info->supplies);
return 0;
}
static struct platform_driver twl6040_vibra_driver = {
.probe = twl6040_vibra_probe,
.remove = twl6040_vibra_remove,
.driver = {
.name = "twl6040-vibra",
.owner = THIS_MODULE,
......
......@@ -53,7 +53,7 @@ config MOUSE_PS2_LOGIPS2PP
default y
depends on MOUSE_PS2
help
Say Y here if you have a Logictech PS/2++ mouse connected to
Say Y here if you have a Logitech PS/2++ mouse connected to
your system.
If unsure, say Y.
......
......@@ -473,8 +473,15 @@ static void elantech_report_absolute_v3(struct psmouse *psmouse,
input_report_key(dev, BTN_TOOL_FINGER, fingers == 1);
input_report_key(dev, BTN_TOOL_DOUBLETAP, fingers == 2);
input_report_key(dev, BTN_TOOL_TRIPLETAP, fingers == 3);
/* For clickpads map both buttons to BTN_LEFT */
if (etd->fw_version & 0x001000) {
input_report_key(dev, BTN_LEFT, packet[0] & 0x03);
} else {
input_report_key(dev, BTN_LEFT, packet[0] & 0x01);
input_report_key(dev, BTN_RIGHT, packet[0] & 0x02);
}
input_report_abs(dev, ABS_PRESSURE, pres);
input_report_abs(dev, ABS_TOOL_WIDTH, width);
......@@ -484,10 +491,17 @@ static void elantech_report_absolute_v3(struct psmouse *psmouse,
static void elantech_input_sync_v4(struct psmouse *psmouse)
{
struct input_dev *dev = psmouse->dev;
struct elantech_data *etd = psmouse->private;
unsigned char *packet = psmouse->packet;
/* For clickpads map both buttons to BTN_LEFT */
if (etd->fw_version & 0x001000) {
input_report_key(dev, BTN_LEFT, packet[0] & 0x03);
} else {
input_report_key(dev, BTN_LEFT, packet[0] & 0x01);
input_report_key(dev, BTN_RIGHT, packet[0] & 0x02);
}
input_mt_report_pointer_emulation(dev, true);
input_sync(dev);
}
......@@ -835,7 +849,7 @@ static int elantech_set_absolute_mode(struct psmouse *psmouse)
if (etd->set_hw_resolution)
etd->reg_10 = 0x0b;
else
etd->reg_10 = 0x03;
etd->reg_10 = 0x01;
if (elantech_write_reg(psmouse, 0x10, etd->reg_10))
rc = -1;
......@@ -1336,7 +1350,8 @@ static int elantech_reconnect(struct psmouse *psmouse)
}
/*
* Some hw_version 3 models go into error state when we try to set bit 3 of r10
* Some hw_version 3 models go into error state when we try to set
* bit 3 and/or bit 1 of r10.
*/
static const struct dmi_system_id no_hw_res_dmi_table[] = {
#if defined(CONFIG_DMI) && defined(CONFIG_X86)
......
......@@ -347,15 +347,6 @@ static int synaptics_resolution(struct psmouse *psmouse)
unsigned char resp[3];
int i;
for (i = 0; min_max_pnpid_table[i].pnp_ids; i++)
if (matches_pnp_id(psmouse, min_max_pnpid_table[i].pnp_ids)) {
priv->x_min = min_max_pnpid_table[i].x_min;
priv->x_max = min_max_pnpid_table[i].x_max;
priv->y_min = min_max_pnpid_table[i].y_min;
priv->y_max = min_max_pnpid_table[i].y_max;
return 0;
}
if (SYN_ID_MAJOR(priv->identity) < 4)
return 0;
......@@ -366,6 +357,16 @@ static int synaptics_resolution(struct psmouse *psmouse)
}
}
for (i = 0; min_max_pnpid_table[i].pnp_ids; i++) {
if (matches_pnp_id(psmouse, min_max_pnpid_table[i].pnp_ids)) {
priv->x_min = min_max_pnpid_table[i].x_min;
priv->x_max = min_max_pnpid_table[i].x_max;
priv->y_min = min_max_pnpid_table[i].y_min;
priv->y_max = min_max_pnpid_table[i].y_max;
return 0;
}
}
if (SYN_EXT_CAP_REQUESTS(priv->capabilities) >= 5 &&
SYN_CAP_MAX_DIMENSIONS(priv->ext_cap_0c)) {
if (synaptics_send_cmd(psmouse, SYN_QUE_EXT_MAX_COORDS, resp)) {
......
......@@ -203,7 +203,7 @@ static int apbps2_of_remove(struct platform_device *of_dev)
return 0;
}
static struct of_device_id apbps2_of_match[] = {
static const struct of_device_id apbps2_of_match[] = {
{ .name = "GAISLER_APBPS2", },
{ .name = "01_060", },
{}
......
......@@ -262,7 +262,7 @@ static int olpc_apsp_remove(struct platform_device *pdev)
return 0;
}
static struct of_device_id olpc_apsp_dt_ids[] = {
static const struct of_device_id olpc_apsp_dt_ids[] = {
{ .compatible = "olpc,ap-sp", },
{}
};
......
......@@ -349,6 +349,7 @@ static int wacom_parse_hid(struct usb_interface *intf,
break;
case MTTPC:
case MTTPC_B:
features->pktlen = WACOM_PKGLEN_MTTPC;
break;
......@@ -380,6 +381,16 @@ static int wacom_parse_hid(struct usb_interface *intf,
i += 12;
break;
case MTTPC_B:
features->x_max =
get_unaligned_le16(&report[i + 3]);
features->x_phy =
get_unaligned_le16(&report[i + 6]);
features->unit = report[i - 5];
features->unitExpo = report[i - 3];
i += 9;
break;
default:
features->x_max =
get_unaligned_le16(&report[i + 3]);
......@@ -430,6 +441,14 @@ static int wacom_parse_hid(struct usb_interface *intf,
i += 12;
break;
case MTTPC_B:
features->y_max =
get_unaligned_le16(&report[i + 3]);
features->y_phy =
get_unaligned_le16(&report[i + 6]);
i += 9;
break;
default:
features->y_max =
features->x_max;
......
......@@ -484,6 +484,8 @@ static int wacom_intuos_inout(struct wacom_wac *wacom)
input_report_key(input, BTN_TOUCH, 0);
input_report_abs(input, ABS_PRESSURE, 0);
input_report_abs(input, ABS_DISTANCE, wacom->features.distance_max);
if (features->quirks & WACOM_QUIRK_MULTI_INPUT)
wacom->shared->stylus_in_proximity = true;
}
/* Exit report */
......@@ -928,12 +930,12 @@ static int wacom_24hdt_irq(struct wacom_wac *wacom)
input_mt_report_slot_state(input, MT_TOOL_FINGER, touch);
if (touch) {
int t_x = le16_to_cpup((__le16 *)&data[offset + 2]);
int c_x = le16_to_cpup((__le16 *)&data[offset + 4]);
int t_y = le16_to_cpup((__le16 *)&data[offset + 6]);
int c_y = le16_to_cpup((__le16 *)&data[offset + 8]);
int w = le16_to_cpup((__le16 *)&data[offset + 10]);
int h = le16_to_cpup((__le16 *)&data[offset + 12]);
int t_x = get_unaligned_le16(&data[offset + 2]);
int c_x = get_unaligned_le16(&data[offset + 4]);
int t_y = get_unaligned_le16(&data[offset + 6]);
int c_y = get_unaligned_le16(&data[offset + 8]);
int w = get_unaligned_le16(&data[offset + 10]);
int h = get_unaligned_le16(&data[offset + 12]);
input_report_abs(input, ABS_MT_POSITION_X, t_x);
input_report_abs(input, ABS_MT_POSITION_Y, t_y);
......@@ -962,7 +964,7 @@ static int wacom_mt_touch(struct wacom_wac *wacom)
int x_offset = 0;
/* MTTPC does not support Height and Width */
if (wacom->features.type == MTTPC)
if (wacom->features.type == MTTPC || wacom->features.type == MTTPC_B)
x_offset = -4;
/*
......@@ -978,7 +980,7 @@ static int wacom_mt_touch(struct wacom_wac *wacom)
for (i = 0; i < contacts_to_send; i++) {
int offset = (WACOM_BYTES_PER_MT_PACKET + x_offset) * i + 3;
bool touch = data[offset] & 0x1;
int id = le16_to_cpup((__le16 *)&data[offset + 1]);
int id = get_unaligned_le16(&data[offset + 1]);
int slot = input_mt_get_slot_by_key(input, id);
if (slot < 0)
......@@ -987,8 +989,8 @@ static int wacom_mt_touch(struct wacom_wac *wacom)
input_mt_slot(input, slot);
input_mt_report_slot_state(input, MT_TOOL_FINGER, touch);
if (touch) {
int x = le16_to_cpup((__le16 *)&data[offset + x_offset + 7]);
int y = le16_to_cpup((__le16 *)&data[offset + x_offset + 9]);
int x = get_unaligned_le16(&data[offset + x_offset + 7]);
int y = get_unaligned_le16(&data[offset + x_offset + 9]);
input_report_abs(input, ABS_MT_POSITION_X, x);
input_report_abs(input, ABS_MT_POSITION_Y, y);
}
......@@ -1047,6 +1049,10 @@ static int wacom_tpc_single_touch(struct wacom_wac *wacom, size_t len)
prox = data[0] & 0x01;
x = get_unaligned_le16(&data[1]);
y = get_unaligned_le16(&data[3]);
} else if (len == WACOM_PKGLEN_TPC1FG_B) {
prox = data[2] & 0x01;
x = get_unaligned_le16(&data[3]);
y = get_unaligned_le16(&data[5]);
} else {
prox = data[1] & 0x01;
x = le16_to_cpup((__le16 *)&data[2]);
......@@ -1110,6 +1116,9 @@ static int wacom_tpc_irq(struct wacom_wac *wacom, size_t len)
case WACOM_PKGLEN_TPC2FG:
return wacom_tpc_mt_touch(wacom);
case WACOM_PKGLEN_PENABLED:
return wacom_tpc_pen(wacom);
default:
switch (data[0]) {
case WACOM_REPORT_TPC1FG:
......@@ -1119,6 +1128,7 @@ static int wacom_tpc_irq(struct wacom_wac *wacom, size_t len)
return wacom_tpc_single_touch(wacom, len);
case WACOM_REPORT_TPCMT:
case WACOM_REPORT_TPCMT2:
return wacom_mt_touch(wacom);
case WACOM_REPORT_PENABLED:
......@@ -1461,6 +1471,7 @@ void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len)
case TABLETPC2FG:
case MTSCREEN:
case MTTPC:
case MTTPC_B:
sync = wacom_tpc_irq(wacom_wac, len);
break;
......@@ -1565,10 +1576,10 @@ static void wacom_abs_set_axis(struct input_dev *input_dev,
struct wacom_features *features = &wacom_wac->features;
if (features->device_type == BTN_TOOL_PEN) {
input_set_abs_params(input_dev, ABS_X, 0, features->x_max,
features->x_fuzz, 0);
input_set_abs_params(input_dev, ABS_Y, 0, features->y_max,
features->y_fuzz, 0);
input_set_abs_params(input_dev, ABS_X, features->x_min,
features->x_max, features->x_fuzz, 0);
input_set_abs_params(input_dev, ABS_Y, features->y_min,
features->y_max, features->y_fuzz, 0);
input_set_abs_params(input_dev, ABS_PRESSURE, 0,
features->pressure_max, features->pressure_fuzz, 0);
......@@ -1802,6 +1813,7 @@ int wacom_setup_input_capabilities(struct input_dev *input_dev,
case MTSCREEN:
case MTTPC:
case MTTPC_B:
case TABLETPC2FG:
if (features->device_type == BTN_TOOL_FINGER) {
unsigned int flags = INPUT_MT_DIRECT;
......@@ -2123,11 +2135,11 @@ static const struct wacom_features wacom_features_0x317 =
63, INTUOSPL, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES,
.touch_max = 16 };
static const struct wacom_features wacom_features_0xF4 =
{ "Wacom Cintiq 24HD", WACOM_PKGLEN_INTUOS, 104480, 65600, 2047,
63, WACOM_24HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
{ "Wacom Cintiq 24HD", WACOM_PKGLEN_INTUOS, 104280, 65400, 2047,
63, WACOM_24HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 200, 200 };
static const struct wacom_features wacom_features_0xF8 =
{ "Wacom Cintiq 24HD touch", WACOM_PKGLEN_INTUOS, 104480, 65600, 2047, /* Pen */
63, WACOM_24HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES,
{ "Wacom Cintiq 24HD touch", WACOM_PKGLEN_INTUOS, 104280, 65400, 2047, /* Pen */
63, WACOM_24HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 200, 200,
.oVid = USB_VENDOR_ID_WACOM, .oPid = 0xf6 };
static const struct wacom_features wacom_features_0xF6 =
{ "Wacom Cintiq 24HD touch", .type = WACOM_24HDT, /* Touch */
......@@ -2142,8 +2154,8 @@ static const struct wacom_features wacom_features_0xC6 =
{ "Wacom Cintiq 12WX", WACOM_PKGLEN_INTUOS, 53020, 33440, 1023,
63, WACOM_BEE, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
static const struct wacom_features wacom_features_0x304 =
{ "Wacom Cintiq 13HD", WACOM_PKGLEN_INTUOS, 59552, 33848, 1023,
63, WACOM_13HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
{ "Wacom Cintiq 13HD", WACOM_PKGLEN_INTUOS, 59352, 33648, 1023,
63, WACOM_13HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 200, 200 };
static const struct wacom_features wacom_features_0xC7 =
{ "Wacom DTU1931", WACOM_PKGLEN_GRAPHIRE, 37832, 30305, 511,
0, PL, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
......@@ -2157,24 +2169,24 @@ static const struct wacom_features wacom_features_0xFB =
{ "Wacom DTU1031", WACOM_PKGLEN_DTUS, 22096, 13960, 511,
0, DTUS, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
static const struct wacom_features wacom_features_0x57 =
{ "Wacom DTK2241", WACOM_PKGLEN_INTUOS, 95840, 54260, 2047,
63, DTK, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES};
{ "Wacom DTK2241", WACOM_PKGLEN_INTUOS, 95640, 54060, 2047,
63, DTK, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 200, 200 };
static const struct wacom_features wacom_features_0x59 = /* Pen */
{ "Wacom DTH2242", WACOM_PKGLEN_INTUOS, 95840, 54260, 2047,
63, DTK, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES,
{ "Wacom DTH2242", WACOM_PKGLEN_INTUOS, 95640, 54060, 2047,
63, DTK, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 200, 200,
.oVid = USB_VENDOR_ID_WACOM, .oPid = 0x5D };
static const struct wacom_features wacom_features_0x5D = /* Touch */
{ "Wacom DTH2242", .type = WACOM_24HDT,
.oVid = USB_VENDOR_ID_WACOM, .oPid = 0x59, .touch_max = 10 };
static const struct wacom_features wacom_features_0xCC =
{ "Wacom Cintiq 21UX2", WACOM_PKGLEN_INTUOS, 87200, 65600, 2047,
63, WACOM_21UX2, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
{ "Wacom Cintiq 21UX2", WACOM_PKGLEN_INTUOS, 87000, 65400, 2047,
63, WACOM_21UX2, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 200, 200 };
static const struct wacom_features wacom_features_0xFA =
{ "Wacom Cintiq 22HD", WACOM_PKGLEN_INTUOS, 95840, 54260, 2047,
63, WACOM_22HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
{ "Wacom Cintiq 22HD", WACOM_PKGLEN_INTUOS, 95640, 54060, 2047,
63, WACOM_22HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 200, 200 };
static const struct wacom_features wacom_features_0x5B =
{ "Wacom Cintiq 22HDT", WACOM_PKGLEN_INTUOS, 95840, 54260, 2047,
63, WACOM_22HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES,
{ "Wacom Cintiq 22HDT", WACOM_PKGLEN_INTUOS, 95640, 54060, 2047,
63, WACOM_22HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 200, 200,
.oVid = USB_VENDOR_ID_WACOM, .oPid = 0x5e };
static const struct wacom_features wacom_features_0x5E =
{ "Wacom Cintiq 22HDT", .type = WACOM_24HDT,
......@@ -2233,9 +2245,21 @@ static const struct wacom_features wacom_features_0x10E =
static const struct wacom_features wacom_features_0x10F =
{ "Wacom ISDv4 10F", WACOM_PKGLEN_MTTPC, 27760, 15694, 255,
0, MTTPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
static const struct wacom_features wacom_features_0x116 =
{ "Wacom ISDv4 116", WACOM_PKGLEN_GRAPHIRE, 26202, 16325, 255,
0, TABLETPCE, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
static const struct wacom_features wacom_features_0x4001 =
{ "Wacom ISDv4 4001", WACOM_PKGLEN_MTTPC, 26202, 16325, 255,
0, MTTPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
static const struct wacom_features wacom_features_0x4004 =
{ "Wacom ISDv4 4004", WACOM_PKGLEN_MTTPC, 11060, 6220, 255,
0, MTTPC_B, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
static const struct wacom_features wacom_features_0x5000 =
{ "Wacom ISDv4 5000", WACOM_PKGLEN_MTTPC, 27848, 15752, 1023,
0, MTTPC_B, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
static const struct wacom_features wacom_features_0x5002 =
{ "Wacom ISDv4 5002", WACOM_PKGLEN_MTTPC, 29576, 16724, 1023,
0, MTTPC_B, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
static const struct wacom_features wacom_features_0x47 =
{ "Wacom Intuos2 6x8", WACOM_PKGLEN_INTUOS, 20320, 16240, 1023,
31, INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
......@@ -2316,8 +2340,8 @@ static const struct wacom_features wacom_features_0x6004 =
{ "ISD-V4", WACOM_PKGLEN_GRAPHIRE, 12800, 8000, 255,
0, TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
static const struct wacom_features wacom_features_0x0307 =
{ "Wacom ISDv5 307", WACOM_PKGLEN_INTUOS, 59552, 33848, 2047,
63, CINTIQ_HYBRID, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES,
{ "Wacom ISDv5 307", WACOM_PKGLEN_INTUOS, 59352, 33648, 2047,
63, CINTIQ_HYBRID, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 200, 200,
.oVid = USB_VENDOR_ID_WACOM, .oPid = 0x309 };
static const struct wacom_features wacom_features_0x0309 =
{ "Wacom ISDv5 309", .type = WACOM_24HDT, /* Touch */
......@@ -2447,6 +2471,7 @@ const struct usb_device_id wacom_ids[] = {
{ USB_DEVICE_WACOM(0x10D) },
{ USB_DEVICE_WACOM(0x10E) },
{ USB_DEVICE_WACOM(0x10F) },
{ USB_DEVICE_WACOM(0x116) },
{ USB_DEVICE_WACOM(0x300) },
{ USB_DEVICE_WACOM(0x301) },
{ USB_DEVICE_DETAILED(0x302, USB_CLASS_HID, 0, 0) },
......@@ -2457,6 +2482,9 @@ const struct usb_device_id wacom_ids[] = {
{ USB_DEVICE_DETAILED(0x315, USB_CLASS_HID, 0, 0) },
{ USB_DEVICE_DETAILED(0x317, USB_CLASS_HID, 0, 0) },
{ USB_DEVICE_WACOM(0x4001) },
{ USB_DEVICE_WACOM(0x4004) },
{ USB_DEVICE_WACOM(0x5000) },
{ USB_DEVICE_WACOM(0x5002) },
{ USB_DEVICE_WACOM(0x47) },
{ USB_DEVICE_WACOM(0xF4) },
{ USB_DEVICE_WACOM(0xF8) },
......
......@@ -22,6 +22,7 @@
#define WACOM_PKGLEN_BBFUN 9
#define WACOM_PKGLEN_INTUOS 10
#define WACOM_PKGLEN_TPC1FG 5
#define WACOM_PKGLEN_TPC1FG_B 10
#define WACOM_PKGLEN_TPC2FG 14
#define WACOM_PKGLEN_BBTOUCH 20
#define WACOM_PKGLEN_BBTOUCH3 64
......@@ -30,6 +31,7 @@
#define WACOM_PKGLEN_MTOUCH 62
#define WACOM_PKGLEN_MTTPC 40
#define WACOM_PKGLEN_DTUS 68
#define WACOM_PKGLEN_PENABLED 8
/* wacom data size per MT contact */
#define WACOM_BYTES_PER_MT_PACKET 11
......@@ -52,6 +54,7 @@
#define WACOM_REPORT_TPC1FG 6
#define WACOM_REPORT_TPC2FG 13
#define WACOM_REPORT_TPCMT 13
#define WACOM_REPORT_TPCMT2 3
#define WACOM_REPORT_TPCHID 15
#define WACOM_REPORT_TPCST 16
#define WACOM_REPORT_DTUS 17
......@@ -105,6 +108,7 @@ enum {
TABLETPC2FG,
MTSCREEN,
MTTPC,
MTTPC_B,
MAX_TYPE
};
......@@ -118,6 +122,8 @@ struct wacom_features {
int type;
int x_resolution;
int y_resolution;
int x_min;
int y_min;
int device_type;
int x_phy;
int y_phy;
......
......@@ -16,6 +16,7 @@
#include <linux/input.h>
#include <linux/mfd/88pm860x.h>
#include <linux/slab.h>
#include <linux/device.h>
#define MEAS_LEN (8)
#define ACCURATE_BIT (12)
......@@ -234,16 +235,17 @@ static int pm860x_touch_probe(struct platform_device *pdev)
if (ret)
return ret;
touch = kzalloc(sizeof(struct pm860x_touch), GFP_KERNEL);
if (touch == NULL)
touch = devm_kzalloc(&pdev->dev, sizeof(struct pm860x_touch),
GFP_KERNEL);
if (!touch)
return -ENOMEM;
platform_set_drvdata(pdev, touch);
touch->idev = input_allocate_device();
if (touch->idev == NULL) {
touch->idev = devm_input_allocate_device(&pdev->dev);
if (!touch->idev) {
dev_err(&pdev->dev, "Failed to allocate input device!\n");
ret = -ENOMEM;
goto out;
return -ENOMEM;
}
touch->idev->name = "88pm860x-touch";
......@@ -258,10 +260,11 @@ static int pm860x_touch_probe(struct platform_device *pdev)
touch->res_x = res_x;
input_set_drvdata(touch->idev, touch);
ret = request_threaded_irq(touch->irq, NULL, pm860x_touch_handler,
IRQF_ONESHOT, "touch", touch);
ret = devm_request_threaded_irq(&pdev->dev, touch->irq, NULL,
pm860x_touch_handler, IRQF_ONESHOT,
"touch", touch);
if (ret < 0)
goto out_irq;
return ret;
__set_bit(EV_ABS, touch->idev->evbit);
__set_bit(ABS_X, touch->idev->absbit);
......@@ -279,28 +282,11 @@ static int pm860x_touch_probe(struct platform_device *pdev)
ret = input_register_device(touch->idev);
if (ret < 0) {
dev_err(chip->dev, "Failed to register touch!\n");
goto out_rg;
return ret;
}
platform_set_drvdata(pdev, touch);
return 0;
out_rg:
free_irq(touch->irq, touch);
out_irq:
input_free_device(touch->idev);
out:
kfree(touch);
return ret;
}
static int pm860x_touch_remove(struct platform_device *pdev)
{
struct pm860x_touch *touch = platform_get_drvdata(pdev);
input_unregister_device(touch->idev);
free_irq(touch->irq, touch);
kfree(touch);
return 0;
}
static struct platform_driver pm860x_touch_driver = {
......@@ -309,7 +295,6 @@ static struct platform_driver pm860x_touch_driver = {
.owner = THIS_MODULE,
},
.probe = pm860x_touch_probe,
.remove = pm860x_touch_remove,
};
module_platform_driver(pm860x_touch_driver);
......
......@@ -11,6 +11,10 @@ menuconfig INPUT_TOUCHSCREEN
if INPUT_TOUCHSCREEN
config OF_TOUCHSCREEN
def_tristate INPUT
depends on INPUT && OF
config TOUCHSCREEN_88PM860X
tristate "Marvell 88PM860x touchscreen"
depends on MFD_88PM860X
......@@ -89,6 +93,7 @@ config TOUCHSCREEN_AD7879_SPI
config TOUCHSCREEN_ATMEL_MXT
tristate "Atmel mXT I2C Touchscreen"
depends on I2C
select FW_LOADER
help
Say Y here if you have Atmel mXT series I2C touchscreen,
such as AT42QT602240/ATMXT224, connected to your system.
......@@ -846,7 +851,7 @@ config TOUCHSCREEN_TSC2007
config TOUCHSCREEN_W90X900
tristate "W90P910 touchscreen driver"
depends on HAVE_CLK
depends on ARCH_W90X900
help
Say Y here if you have a W90P910 based touchscreen.
......@@ -885,6 +890,17 @@ config TOUCHSCREEN_STMPE
To compile this driver as a module, choose M here: the
module will be called stmpe-ts.
config TOUCHSCREEN_SUN4I
tristate "Allwinner sun4i resistive touchscreen controller support"
depends on ARCH_SUNXI || COMPILE_TEST
depends on HWMON
help
This selects support for the resistive touchscreen controller
found on Allwinner sunxi SoCs.
To compile this driver as a module, choose M here: the
module will be called sun4i-ts.
config TOUCHSCREEN_SUR40
tristate "Samsung SUR40 (Surface 2.0/PixelSense) touchscreen"
depends on USB
......
......@@ -6,6 +6,7 @@
wm97xx-ts-y := wm97xx-core.o
obj-$(CONFIG_OF_TOUCHSCREEN) += of_touchscreen.o
obj-$(CONFIG_TOUCHSCREEN_88PM860X) += 88pm860x-ts.o
obj-$(CONFIG_TOUCHSCREEN_AD7877) += ad7877.o
obj-$(CONFIG_TOUCHSCREEN_AD7879) += ad7879.o
......@@ -53,6 +54,7 @@ obj-$(CONFIG_TOUCHSCREEN_PIXCIR) += pixcir_i2c_ts.o
obj-$(CONFIG_TOUCHSCREEN_S3C2410) += s3c2410_ts.o
obj-$(CONFIG_TOUCHSCREEN_ST1232) += st1232.o
obj-$(CONFIG_TOUCHSCREEN_STMPE) += stmpe-ts.o
obj-$(CONFIG_TOUCHSCREEN_SUN4I) += sun4i-ts.o
obj-$(CONFIG_TOUCHSCREEN_SUR40) += sur40.o
obj-$(CONFIG_TOUCHSCREEN_TI_AM335X_TSC) += ti_am335x_tsc.o
obj-$(CONFIG_TOUCHSCREEN_TOUCHIT213) += touchit213.o
......
......@@ -210,11 +210,6 @@ static bool gpio3;
module_param(gpio3, bool, 0);
MODULE_PARM_DESC(gpio3, "If gpio3 is set to 1 AUX3 acts as GPIO3");
/*
* ad7877_read/write are only used for initial setup and for sysfs controls.
* The main traffic is done using spi_async() in the interrupt handler.
*/
static int ad7877_read(struct spi_device *spi, u16 reg)
{
struct ser_req *req;
......
......@@ -706,7 +706,7 @@ static void ads7846_read_state(struct ads7846 *ts)
m = &ts->msg[msg_idx];
error = spi_sync(ts->spi, m);
if (error) {
dev_err(&ts->spi->dev, "spi_async --> %d\n", error);
dev_err(&ts->spi->dev, "spi_sync --> %d\n", error);
packet->tc.ignore = true;
return;
}
......
......@@ -2,6 +2,8 @@
* Atmel maXTouch Touchscreen driver
*
* Copyright (C) 2010 Samsung Electronics Co.Ltd
* Copyright (C) 2012 Google, Inc.
*
* Author: Joonyoung Shim <jy0922.shim@samsung.com>
*
* This program is free software; you can redistribute it and/or modify it
......@@ -12,6 +14,8 @@
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/completion.h>
#include <linux/delay.h>
#include <linux/firmware.h>
#include <linux/i2c.h>
......@@ -25,12 +29,6 @@
#define MXT_VER_21 21
#define MXT_VER_22 22
/* Slave addresses */
#define MXT_APP_LOW 0x4a
#define MXT_APP_HIGH 0x4b
#define MXT_BOOT_LOW 0x24
#define MXT_BOOT_HIGH 0x25
/* Firmware */
#define MXT_FW_NAME "maxtouch.fw"
......@@ -83,6 +81,9 @@
#define MXT_COMMAND_REPORTALL 3
#define MXT_COMMAND_DIAGNOSTIC 5
/* Define for T6 status byte */
#define MXT_T6_STATUS_RESET (1 << 7)
/* MXT_GEN_POWER_T7 field */
#define MXT_POWER_IDLEACQINT 0
#define MXT_POWER_ACTVACQINT 1
......@@ -99,33 +100,26 @@
/* MXT_TOUCH_MULTI_T9 field */
#define MXT_TOUCH_CTRL 0
#define MXT_TOUCH_XORIGIN 1
#define MXT_TOUCH_YORIGIN 2
#define MXT_TOUCH_XSIZE 3
#define MXT_TOUCH_YSIZE 4
#define MXT_TOUCH_BLEN 6
#define MXT_TOUCH_TCHTHR 7
#define MXT_TOUCH_TCHDI 8
#define MXT_TOUCH_ORIENT 9
#define MXT_TOUCH_MOVHYSTI 11
#define MXT_TOUCH_MOVHYSTN 12
#define MXT_TOUCH_NUMTOUCH 14
#define MXT_TOUCH_MRGHYST 15
#define MXT_TOUCH_MRGTHR 16
#define MXT_TOUCH_AMPHYST 17
#define MXT_TOUCH_XRANGE_LSB 18
#define MXT_TOUCH_XRANGE_MSB 19
#define MXT_TOUCH_YRANGE_LSB 20
#define MXT_TOUCH_YRANGE_MSB 21
#define MXT_TOUCH_XLOCLIP 22
#define MXT_TOUCH_XHICLIP 23
#define MXT_TOUCH_YLOCLIP 24
#define MXT_TOUCH_YHICLIP 25
#define MXT_TOUCH_XEDGECTRL 26
#define MXT_TOUCH_XEDGEDIST 27
#define MXT_TOUCH_YEDGECTRL 28
#define MXT_TOUCH_YEDGEDIST 29
#define MXT_TOUCH_JUMPLIMIT 30
#define MXT_T9_ORIENT 9
#define MXT_T9_RANGE 18
/* MXT_TOUCH_MULTI_T9 status */
#define MXT_T9_UNGRIP (1 << 0)
#define MXT_T9_SUPPRESS (1 << 1)
#define MXT_T9_AMP (1 << 2)
#define MXT_T9_VECTOR (1 << 3)
#define MXT_T9_MOVE (1 << 4)
#define MXT_T9_RELEASE (1 << 5)
#define MXT_T9_PRESS (1 << 6)
#define MXT_T9_DETECT (1 << 7)
struct t9_range {
u16 x;
u16 y;
} __packed;
/* MXT_TOUCH_MULTI_T9 orient */
#define MXT_T9_ORIENT_SWITCH (1 << 0)
/* MXT_PROCI_GRIPFACE_T20 field */
#define MXT_GRIPFACE_CTRL 0
......@@ -174,17 +168,16 @@
/* Define for MXT_GEN_COMMAND_T6 */
#define MXT_BOOT_VALUE 0xa5
#define MXT_RESET_VALUE 0x01
#define MXT_BACKUP_VALUE 0x55
/* Delay times */
#define MXT_BACKUP_TIME 50 /* msec */
#define MXT_RESET_TIME 200 /* msec */
#define MXT_FWRESET_TIME 175 /* msec */
/* MXT_SPT_GPIOPWM_T19 field */
#define MXT_GPIO0_MASK 0x04
#define MXT_GPIO1_MASK 0x08
#define MXT_GPIO2_MASK 0x10
#define MXT_GPIO3_MASK 0x20
#define MXT_RESET_TIMEOUT 3000 /* msec */
#define MXT_CRC_TIMEOUT 1000 /* msec */
#define MXT_FW_RESET_TIME 3000 /* msec */
#define MXT_FW_CHG_TIMEOUT 300 /* msec */
/* Command to unlock bootloader */
#define MXT_UNLOCK_CMD_MSB 0xaa
......@@ -198,21 +191,8 @@
#define MXT_FRAME_CRC_PASS 0x04
#define MXT_APP_CRC_FAIL 0x40 /* valid 7 8 bit only */
#define MXT_BOOT_STATUS_MASK 0x3f
/* Touch status */
#define MXT_UNGRIP (1 << 0)
#define MXT_SUPPRESS (1 << 1)
#define MXT_AMP (1 << 2)
#define MXT_VECTOR (1 << 3)
#define MXT_MOVE (1 << 4)
#define MXT_RELEASE (1 << 5)
#define MXT_PRESS (1 << 6)
#define MXT_DETECT (1 << 7)
/* Touch orient bits */
#define MXT_XY_SWITCH (1 << 0)
#define MXT_X_INVERT (1 << 1)
#define MXT_Y_INVERT (1 << 2)
#define MXT_BOOT_EXTENDED_ID (1 << 5)
#define MXT_BOOT_ID_MASK 0x1f
/* Touchscreen absolute values */
#define MXT_MAX_AREA 0xff
......@@ -232,8 +212,8 @@ struct mxt_info {
struct mxt_object {
u8 type;
u16 start_address;
u8 size; /* Size of each instance - 1 */
u8 instances; /* Number of instances - 1 */
u8 size_minus_one;
u8 instances_minus_one;
u8 num_report_ids;
} __packed;
......@@ -250,19 +230,40 @@ struct mxt_data {
const struct mxt_platform_data *pdata;
struct mxt_object *object_table;
struct mxt_info info;
bool is_tp;
unsigned int irq;
unsigned int max_x;
unsigned int max_y;
bool in_bootloader;
u32 config_crc;
u8 bootloader_addr;
/* Cached parameters from object table */
u8 T6_reportid;
u16 T6_address;
u8 T9_reportid_min;
u8 T9_reportid_max;
u8 T19_reportid;
/* for fw update in bootloader */
struct completion bl_completion;
/* for reset handling */
struct completion reset_completion;
/* for config update handling */
struct completion crc_completion;
};
static size_t mxt_obj_size(const struct mxt_object *obj)
{
return obj->size_minus_one + 1;
}
static size_t mxt_obj_instances(const struct mxt_object *obj)
{
return obj->instances_minus_one + 1;
}
static bool mxt_object_readable(unsigned int type)
{
switch (type) {
......@@ -334,16 +335,152 @@ static void mxt_dump_message(struct device *dev,
message->reportid, 7, message->message);
}
static int mxt_check_bootloader(struct i2c_client *client,
unsigned int state)
static int mxt_wait_for_completion(struct mxt_data *data,
struct completion *comp,
unsigned int timeout_ms)
{
struct device *dev = &data->client->dev;
unsigned long timeout = msecs_to_jiffies(timeout_ms);
long ret;
ret = wait_for_completion_interruptible_timeout(comp, timeout);
if (ret < 0) {
return ret;
} else if (ret == 0) {
dev_err(dev, "Wait for completion timed out.\n");
return -ETIMEDOUT;
}
return 0;
}
static int mxt_bootloader_read(struct mxt_data *data,
u8 *val, unsigned int count)
{
int ret;
struct i2c_msg msg;
msg.addr = data->bootloader_addr;
msg.flags = data->client->flags & I2C_M_TEN;
msg.flags |= I2C_M_RD;
msg.len = count;
msg.buf = val;
ret = i2c_transfer(data->client->adapter, &msg, 1);
if (ret == 1) {
ret = 0;
} else {
ret = ret < 0 ? ret : -EIO;
dev_err(&data->client->dev, "%s: i2c recv failed (%d)\n",
__func__, ret);
}
return ret;
}
static int mxt_bootloader_write(struct mxt_data *data,
const u8 * const val, unsigned int count)
{
int ret;
struct i2c_msg msg;
msg.addr = data->bootloader_addr;
msg.flags = data->client->flags & I2C_M_TEN;
msg.len = count;
msg.buf = (u8 *)val;
ret = i2c_transfer(data->client->adapter, &msg, 1);
if (ret == 1) {
ret = 0;
} else {
ret = ret < 0 ? ret : -EIO;
dev_err(&data->client->dev, "%s: i2c send failed (%d)\n",
__func__, ret);
}
return ret;
}
static int mxt_lookup_bootloader_address(struct mxt_data *data)
{
u8 appmode = data->client->addr;
u8 bootloader;
switch (appmode) {
case 0x4a:
case 0x4b:
case 0x4c:
case 0x4d:
case 0x5a:
case 0x5b:
bootloader = appmode - 0x26;
break;
default:
dev_err(&data->client->dev,
"Appmode i2c address 0x%02x not found\n",
appmode);
return -EINVAL;
}
data->bootloader_addr = bootloader;
return 0;
}
static u8 mxt_get_bootloader_version(struct mxt_data *data, u8 val)
{
struct device *dev = &data->client->dev;
u8 buf[3];
if (val & MXT_BOOT_EXTENDED_ID) {
if (mxt_bootloader_read(data, &buf[0], 3) != 0) {
dev_err(dev, "%s: i2c failure\n", __func__);
return val;
}
dev_dbg(dev, "Bootloader ID:%d Version:%d\n", buf[1], buf[2]);
return buf[0];
} else {
dev_dbg(dev, "Bootloader ID:%d\n", val & MXT_BOOT_ID_MASK);
return val;
}
}
static int mxt_check_bootloader(struct mxt_data *data, unsigned int state)
{
struct device *dev = &data->client->dev;
u8 val;
int ret;
recheck:
if (i2c_master_recv(client, &val, 1) != 1) {
dev_err(&client->dev, "%s: i2c recv failed\n", __func__);
return -EIO;
if (state != MXT_WAITING_BOOTLOAD_CMD) {
/*
* In application update mode, the interrupt
* line signals state transitions. We must wait for the
* CHG assertion before reading the status byte.
* Once the status byte has been read, the line is deasserted.
*/
ret = mxt_wait_for_completion(data, &data->bl_completion,
MXT_FW_CHG_TIMEOUT);
if (ret) {
/*
* TODO: handle -ERESTARTSYS better by terminating
* fw update process before returning to userspace
* by writing length 0x000 to device (iff we are in
* WAITING_FRAME_DATA state).
*/
dev_err(dev, "Update wait error %d\n", ret);
return ret;
}
}
ret = mxt_bootloader_read(data, &val, 1);
if (ret)
return ret;
if (state == MXT_WAITING_BOOTLOAD_CMD)
val = mxt_get_bootloader_version(data, val);
switch (state) {
case MXT_WAITING_BOOTLOAD_CMD:
......@@ -351,43 +488,37 @@ static int mxt_check_bootloader(struct i2c_client *client,
val &= ~MXT_BOOT_STATUS_MASK;
break;
case MXT_FRAME_CRC_PASS:
if (val == MXT_FRAME_CRC_CHECK)
if (val == MXT_FRAME_CRC_CHECK) {
goto recheck;
} else if (val == MXT_FRAME_CRC_FAIL) {
dev_err(dev, "Bootloader CRC fail\n");
return -EINVAL;
}
break;
default:
return -EINVAL;
}
if (val != state) {
dev_err(&client->dev, "Unvalid bootloader mode state\n");
dev_err(dev, "Invalid bootloader state %02X != %02X\n",
val, state);
return -EINVAL;
}
return 0;
}
static int mxt_unlock_bootloader(struct i2c_client *client)
static int mxt_unlock_bootloader(struct mxt_data *data)
{
int ret;
u8 buf[2];
buf[0] = MXT_UNLOCK_CMD_LSB;
buf[1] = MXT_UNLOCK_CMD_MSB;
if (i2c_master_send(client, buf, 2) != 2) {
dev_err(&client->dev, "%s: i2c send failed\n", __func__);
return -EIO;
}
return 0;
}
static int mxt_fw_write(struct i2c_client *client,
const u8 *data, unsigned int frame_size)
{
if (i2c_master_send(client, data, frame_size) != frame_size) {
dev_err(&client->dev, "%s: i2c send failed\n", __func__);
return -EIO;
}
ret = mxt_bootloader_write(data, buf, 2);
if (ret)
return ret;
return 0;
}
......@@ -427,11 +558,6 @@ static int __mxt_read_reg(struct i2c_client *client,
return ret;
}
static int mxt_read_reg(struct i2c_client *client, u16 reg, u8 *val)
{
return __mxt_read_reg(client, reg, 1, val);
}
static int __mxt_write_reg(struct i2c_client *client, u16 reg, u16 len,
const void *val)
{
......@@ -479,7 +605,7 @@ mxt_get_object(struct mxt_data *data, u8 type)
return object;
}
dev_err(&data->client->dev, "Invalid object type\n");
dev_err(&data->client->dev, "Invalid object type T%u\n", type);
return NULL;
}
......@@ -505,7 +631,7 @@ static int mxt_write_object(struct mxt_data *data,
u16 reg;
object = mxt_get_object(data, type);
if (!object || offset >= object->size + 1)
if (!object || offset >= mxt_obj_size(object))
return -EINVAL;
reg = object->start_address;
......@@ -515,18 +641,25 @@ static int mxt_write_object(struct mxt_data *data,
static void mxt_input_button(struct mxt_data *data, struct mxt_message *message)
{
struct input_dev *input = data->input_dev;
const struct mxt_platform_data *pdata = data->pdata;
bool button;
int i;
/* Active-low switch */
for (i = 0; i < MXT_NUM_GPIO; i++) {
if (data->pdata->key_map[i] == KEY_RESERVED)
for (i = 0; i < pdata->t19_num_keys; i++) {
if (pdata->t19_keymap[i] == KEY_RESERVED)
continue;
button = !(message->message[0] & MXT_GPIO0_MASK << i);
input_report_key(input, data->pdata->key_map[i], button);
button = !(message->message[0] & (1 << i));
input_report_key(input, pdata->t19_keymap[i], button);
}
}
static void mxt_input_sync(struct input_dev *input_dev)
{
input_mt_report_pointer_emulation(input_dev, false);
input_sync(input_dev);
}
static void mxt_input_touchevent(struct mxt_data *data,
struct mxt_message *message, int id)
{
......@@ -536,44 +669,60 @@ static void mxt_input_touchevent(struct mxt_data *data,
int x;
int y;
int area;
int pressure;
int amplitude;
x = (message->message[1] << 4) | ((message->message[3] >> 4) & 0xf);
y = (message->message[2] << 4) | ((message->message[3] & 0xf));
/* Handle 10/12 bit switching */
if (data->max_x < 1024)
x = x >> 2;
x >>= 2;
if (data->max_y < 1024)
y = y >> 2;
y >>= 2;
area = message->message[4];
pressure = message->message[5];
amplitude = message->message[5];
dev_dbg(dev,
"[%u] %c%c%c%c%c%c%c%c x: %5u y: %5u area: %3u amp: %3u\n",
id,
(status & MXT_DETECT) ? 'D' : '.',
(status & MXT_PRESS) ? 'P' : '.',
(status & MXT_RELEASE) ? 'R' : '.',
(status & MXT_MOVE) ? 'M' : '.',
(status & MXT_VECTOR) ? 'V' : '.',
(status & MXT_AMP) ? 'A' : '.',
(status & MXT_SUPPRESS) ? 'S' : '.',
(status & MXT_UNGRIP) ? 'U' : '.',
x, y, area, pressure);
(status & MXT_T9_DETECT) ? 'D' : '.',
(status & MXT_T9_PRESS) ? 'P' : '.',
(status & MXT_T9_RELEASE) ? 'R' : '.',
(status & MXT_T9_MOVE) ? 'M' : '.',
(status & MXT_T9_VECTOR) ? 'V' : '.',
(status & MXT_T9_AMP) ? 'A' : '.',
(status & MXT_T9_SUPPRESS) ? 'S' : '.',
(status & MXT_T9_UNGRIP) ? 'U' : '.',
x, y, area, amplitude);
input_mt_slot(input_dev, id);
input_mt_report_slot_state(input_dev, MT_TOOL_FINGER,
status & MXT_DETECT);
if (status & MXT_DETECT) {
if (status & MXT_T9_DETECT) {
/*
* Multiple bits may be set if the host is slow to read
* the status messages, indicating all the events that
* have happened.
*/
if (status & MXT_T9_RELEASE) {
input_mt_report_slot_state(input_dev,
MT_TOOL_FINGER, 0);
mxt_input_sync(input_dev);
}
/* Touch active */
input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, 1);
input_report_abs(input_dev, ABS_MT_POSITION_X, x);
input_report_abs(input_dev, ABS_MT_POSITION_Y, y);
input_report_abs(input_dev, ABS_MT_PRESSURE, pressure);
input_report_abs(input_dev, ABS_MT_PRESSURE, amplitude);
input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR, area);
} else {
/* Touch no longer active, close out slot */
input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, 0);
}
}
static unsigned mxt_extract_T6_csum(const u8 *csum)
static u16 mxt_extract_T6_csum(const u8 *csum)
{
return csum[0] | (csum[1] << 8) | (csum[2] << 16);
}
......@@ -584,28 +733,37 @@ static bool mxt_is_T9_message(struct mxt_data *data, struct mxt_message *msg)
return (id >= data->T9_reportid_min && id <= data->T9_reportid_max);
}
static irqreturn_t mxt_interrupt(int irq, void *dev_id)
static irqreturn_t mxt_process_messages_until_invalid(struct mxt_data *data)
{
struct mxt_data *data = dev_id;
struct mxt_message message;
const u8 *payload = &message.message[0];
struct device *dev = &data->client->dev;
u8 reportid;
bool update_input = false;
u32 crc;
do {
if (mxt_read_message(data, &message)) {
dev_err(dev, "Failed to read message\n");
goto end;
return IRQ_NONE;
}
reportid = message.reportid;
if (reportid == data->T6_reportid) {
u8 status = payload[0];
unsigned csum = mxt_extract_T6_csum(&payload[1]);
crc = mxt_extract_T6_csum(&payload[1]);
if (crc != data->config_crc) {
data->config_crc = crc;
complete(&data->crc_completion);
}
dev_dbg(dev, "Status: %02x Config Checksum: %06x\n",
status, csum);
status, data->config_crc);
if (status & MXT_T6_STATUS_RESET)
complete(&data->reset_completion);
} else if (mxt_is_T9_message(data, &message)) {
int id = reportid - data->T9_reportid_min;
mxt_input_touchevent(data, &message, id);
......@@ -618,15 +776,96 @@ static irqreturn_t mxt_interrupt(int irq, void *dev_id)
}
} while (reportid != 0xff);
if (update_input) {
input_mt_report_pointer_emulation(data->input_dev, false);
input_sync(data->input_dev);
}
if (update_input)
mxt_input_sync(data->input_dev);
end:
return IRQ_HANDLED;
}
static irqreturn_t mxt_interrupt(int irq, void *dev_id)
{
struct mxt_data *data = dev_id;
if (data->in_bootloader) {
/* bootloader state transition completion */
complete(&data->bl_completion);
return IRQ_HANDLED;
}
return mxt_process_messages_until_invalid(data);
}
static int mxt_t6_command(struct mxt_data *data, u16 cmd_offset,
u8 value, bool wait)
{
u16 reg;
u8 command_register;
int timeout_counter = 0;
int ret;
reg = data->T6_address + cmd_offset;
ret = mxt_write_reg(data->client, reg, value);
if (ret)
return ret;
if (!wait)
return 0;
do {
msleep(20);
ret = __mxt_read_reg(data->client, reg, 1, &command_register);
if (ret)
return ret;
} while (command_register != 0 && timeout_counter++ <= 100);
if (timeout_counter > 100) {
dev_err(&data->client->dev, "Command failed!\n");
return -EIO;
}
return 0;
}
static int mxt_soft_reset(struct mxt_data *data)
{
struct device *dev = &data->client->dev;
int ret = 0;
dev_info(dev, "Resetting chip\n");
reinit_completion(&data->reset_completion);
ret = mxt_t6_command(data, MXT_COMMAND_RESET, MXT_RESET_VALUE, false);
if (ret)
return ret;
ret = mxt_wait_for_completion(data, &data->reset_completion,
MXT_RESET_TIMEOUT);
if (ret)
return ret;
return 0;
}
static void mxt_update_crc(struct mxt_data *data, u8 cmd, u8 value)
{
/*
* On failure, CRC is set to 0 and config will always be
* downloaded.
*/
data->config_crc = 0;
reinit_completion(&data->crc_completion);
mxt_t6_command(data, cmd, value, true);
/*
* Wait for crc message. On failure, CRC is set to 0 and config will
* always be downloaded.
*/
mxt_wait_for_completion(data, &data->crc_completion, MXT_CRC_TIMEOUT);
}
static int mxt_check_reg_init(struct mxt_data *data)
{
const struct mxt_platform_data *pdata = data->pdata;
......@@ -641,13 +880,23 @@ static int mxt_check_reg_init(struct mxt_data *data)
return 0;
}
mxt_update_crc(data, MXT_COMMAND_REPORTALL, 1);
if (data->config_crc == pdata->config_crc) {
dev_info(dev, "Config CRC 0x%06X: OK\n", data->config_crc);
return 0;
}
dev_info(dev, "Config CRC 0x%06X: does not match 0x%06X\n",
data->config_crc, pdata->config_crc);
for (i = 0; i < data->info.object_num; i++) {
object = data->object_table + i;
if (!mxt_object_writable(object->type))
continue;
size = (object->size + 1) * (object->instances + 1);
size = mxt_obj_size(object) * mxt_obj_instances(object);
if (index + size > pdata->config_length) {
dev_err(dev, "Not enough config data!\n");
return -EINVAL;
......@@ -660,6 +909,14 @@ static int mxt_check_reg_init(struct mxt_data *data)
index += size;
}
mxt_update_crc(data, MXT_COMMAND_BACKUPNV, MXT_BACKUP_VALUE);
ret = mxt_soft_reset(data);
if (ret)
return ret;
dev_info(dev, "Config successfully updated\n");
return 0;
}
......@@ -685,54 +942,6 @@ static int mxt_make_highchg(struct mxt_data *data)
return 0;
}
static void mxt_handle_pdata(struct mxt_data *data)
{
const struct mxt_platform_data *pdata = data->pdata;
u8 voltage;
/* Set touchscreen lines */
mxt_write_object(data, MXT_TOUCH_MULTI_T9, MXT_TOUCH_XSIZE,
pdata->x_line);
mxt_write_object(data, MXT_TOUCH_MULTI_T9, MXT_TOUCH_YSIZE,
pdata->y_line);
/* Set touchscreen orient */
mxt_write_object(data, MXT_TOUCH_MULTI_T9, MXT_TOUCH_ORIENT,
pdata->orient);
/* Set touchscreen burst length */
mxt_write_object(data, MXT_TOUCH_MULTI_T9,
MXT_TOUCH_BLEN, pdata->blen);
/* Set touchscreen threshold */
mxt_write_object(data, MXT_TOUCH_MULTI_T9,
MXT_TOUCH_TCHTHR, pdata->threshold);
/* Set touchscreen resolution */
mxt_write_object(data, MXT_TOUCH_MULTI_T9,
MXT_TOUCH_XRANGE_LSB, (pdata->x_size - 1) & 0xff);
mxt_write_object(data, MXT_TOUCH_MULTI_T9,
MXT_TOUCH_XRANGE_MSB, (pdata->x_size - 1) >> 8);
mxt_write_object(data, MXT_TOUCH_MULTI_T9,
MXT_TOUCH_YRANGE_LSB, (pdata->y_size - 1) & 0xff);
mxt_write_object(data, MXT_TOUCH_MULTI_T9,
MXT_TOUCH_YRANGE_MSB, (pdata->y_size - 1) >> 8);
/* Set touchscreen voltage */
if (pdata->voltage) {
if (pdata->voltage < MXT_VOLTAGE_DEFAULT) {
voltage = (MXT_VOLTAGE_DEFAULT - pdata->voltage) /
MXT_VOLTAGE_STEP;
voltage = 0xff - voltage + 1;
} else
voltage = (pdata->voltage - MXT_VOLTAGE_DEFAULT) /
MXT_VOLTAGE_STEP;
mxt_write_object(data, MXT_SPT_CTECONFIG_T28,
MXT_CTE_VOLTAGE, voltage);
}
}
static int mxt_get_info(struct mxt_data *data)
{
struct i2c_client *client = data->client;
......@@ -772,7 +981,7 @@ static int mxt_get_object_table(struct mxt_data *data)
if (object->num_report_ids) {
min_id = reportid;
reportid += object->num_report_ids *
(object->instances + 1);
mxt_obj_instances(object);
max_id = reportid - 1;
} else {
min_id = 0;
......@@ -780,13 +989,15 @@ static int mxt_get_object_table(struct mxt_data *data)
}
dev_dbg(&data->client->dev,
"Type %2d Start %3d Size %3d Instances %2d ReportIDs %3u : %3u\n",
object->type, object->start_address, object->size + 1,
object->instances + 1, min_id, max_id);
"T%u Start:%u Size:%zu Instances:%zu Report IDs:%u-%u\n",
object->type, object->start_address,
mxt_obj_size(object), mxt_obj_instances(object),
min_id, max_id);
switch (object->type) {
case MXT_GEN_COMMAND_T6:
data->T6_reportid = min_id;
data->T6_address = object->start_address;
break;
case MXT_TOUCH_MULTI_T9:
data->T9_reportid_min = min_id;
......@@ -811,12 +1022,59 @@ static void mxt_free_object_table(struct mxt_data *data)
data->T19_reportid = 0;
}
static int mxt_read_t9_resolution(struct mxt_data *data)
{
struct i2c_client *client = data->client;
int error;
struct t9_range range;
unsigned char orient;
struct mxt_object *object;
object = mxt_get_object(data, MXT_TOUCH_MULTI_T9);
if (!object)
return -EINVAL;
error = __mxt_read_reg(client,
object->start_address + MXT_T9_RANGE,
sizeof(range), &range);
if (error)
return error;
le16_to_cpus(&range.x);
le16_to_cpus(&range.y);
error = __mxt_read_reg(client,
object->start_address + MXT_T9_ORIENT,
1, &orient);
if (error)
return error;
/* Handle default values */
if (range.x == 0)
range.x = 1023;
if (range.y == 0)
range.y = 1023;
if (orient & MXT_T9_ORIENT_SWITCH) {
data->max_x = range.y;
data->max_y = range.x;
} else {
data->max_x = range.x;
data->max_y = range.y;
}
dev_dbg(&client->dev,
"Touchscreen size X%uY%u\n", data->max_x, data->max_y);
return 0;
}
static int mxt_initialize(struct mxt_data *data)
{
struct i2c_client *client = data->client;
struct mxt_info *info = &data->info;
int error;
u8 val;
error = mxt_get_info(data);
if (error)
......@@ -832,47 +1090,29 @@ static int mxt_initialize(struct mxt_data *data)
/* Get object table information */
error = mxt_get_object_table(data);
if (error)
if (error) {
dev_err(&client->dev, "Error %d reading object table\n", error);
goto err_free_object_table;
}
/* Check register init values */
error = mxt_check_reg_init(data);
if (error)
goto err_free_object_table;
mxt_handle_pdata(data);
/* Backup to memory */
mxt_write_object(data, MXT_GEN_COMMAND_T6,
MXT_COMMAND_BACKUPNV,
MXT_BACKUP_VALUE);
msleep(MXT_BACKUP_TIME);
/* Soft reset */
mxt_write_object(data, MXT_GEN_COMMAND_T6,
MXT_COMMAND_RESET, 1);
msleep(MXT_RESET_TIME);
/* Update matrix size at info struct */
error = mxt_read_reg(client, MXT_MATRIX_X_SIZE, &val);
if (error)
if (error) {
dev_err(&client->dev, "Error %d initializing configuration\n",
error);
goto err_free_object_table;
info->matrix_xsize = val;
}
error = mxt_read_reg(client, MXT_MATRIX_Y_SIZE, &val);
if (error)
error = mxt_read_t9_resolution(data);
if (error) {
dev_err(&client->dev, "Failed to initialize T9 resolution\n");
goto err_free_object_table;
info->matrix_ysize = val;
}
dev_info(&client->dev,
"Family ID: %u Variant ID: %u Major.Minor.Build: %u.%u.%02X\n",
"Family: %u Variant: %u Firmware V%u.%u.%02X Objects: %u\n",
info->family_id, info->variant_id, info->version >> 4,
info->version & 0xf, info->build);
dev_info(&client->dev,
"Matrix X Size: %u Matrix Y Size: %u Object Num: %u\n",
info->matrix_xsize, info->matrix_ysize,
info->object_num);
info->version & 0xf, info->build, info->object_num);
return 0;
......@@ -881,20 +1121,6 @@ static int mxt_initialize(struct mxt_data *data)
return error;
}
static void mxt_calc_resolution(struct mxt_data *data)
{
unsigned int max_x = data->pdata->x_size - 1;
unsigned int max_y = data->pdata->y_size - 1;
if (data->pdata->orient & MXT_XY_SWITCH) {
data->max_x = max_y;
data->max_y = max_x;
} else {
data->max_x = max_x;
data->max_y = max_y;
}
}
/* Firmware Version is returned as Major.Minor.Build */
static ssize_t mxt_fw_version_show(struct device *dev,
struct device_attribute *attr, char *buf)
......@@ -921,11 +1147,11 @@ static ssize_t mxt_show_instance(char *buf, int count,
{
int i;
if (object->instances > 0)
if (mxt_obj_instances(object) > 1)
count += scnprintf(buf + count, PAGE_SIZE - count,
"Instance %u\n", instance);
for (i = 0; i < object->size + 1; i++)
for (i = 0; i < mxt_obj_size(object); i++)
count += scnprintf(buf + count, PAGE_SIZE - count,
"\t[%2u]: %02x (%d)\n", i, val[i], val[i]);
count += scnprintf(buf + count, PAGE_SIZE - count, "\n");
......@@ -958,8 +1184,8 @@ static ssize_t mxt_object_show(struct device *dev,
count += scnprintf(buf + count, PAGE_SIZE - count,
"T%u:\n", object->type);
for (j = 0; j < object->instances + 1; j++) {
u16 size = object->size + 1;
for (j = 0; j < mxt_obj_instances(object); j++) {
u16 size = mxt_obj_size(object);
u16 addr = object->start_address + j * size;
error = __mxt_read_reg(data->client, addr, size, obuf);
......@@ -975,13 +1201,38 @@ static ssize_t mxt_object_show(struct device *dev,
return error ?: count;
}
static int mxt_check_firmware_format(struct device *dev,
const struct firmware *fw)
{
unsigned int pos = 0;
char c;
while (pos < fw->size) {
c = *(fw->data + pos);
if (c < '0' || (c > '9' && c < 'A') || c > 'F')
return 0;
pos++;
}
/*
* To convert file try:
* xxd -r -p mXTXXX__APP_VX-X-XX.enc > maxtouch.fw
*/
dev_err(dev, "Aborting: firmware file must be in binary format\n");
return -EINVAL;
}
static int mxt_load_fw(struct device *dev, const char *fn)
{
struct mxt_data *data = dev_get_drvdata(dev);
struct i2c_client *client = data->client;
const struct firmware *fw = NULL;
unsigned int frame_size;
unsigned int pos = 0;
unsigned int retry = 0;
unsigned int frame = 0;
int ret;
ret = request_firmware(&fw, fn, dev);
......@@ -990,59 +1241,91 @@ static int mxt_load_fw(struct device *dev, const char *fn)
return ret;
}
/* Check for incorrect enc file */
ret = mxt_check_firmware_format(dev, fw);
if (ret)
goto release_firmware;
ret = mxt_lookup_bootloader_address(data);
if (ret)
goto release_firmware;
/* Change to the bootloader mode */
mxt_write_object(data, MXT_GEN_COMMAND_T6,
MXT_COMMAND_RESET, MXT_BOOT_VALUE);
data->in_bootloader = true;
ret = mxt_t6_command(data, MXT_COMMAND_RESET, MXT_BOOT_VALUE, false);
if (ret)
goto release_firmware;
msleep(MXT_RESET_TIME);
/* Change to slave address of bootloader */
if (client->addr == MXT_APP_LOW)
client->addr = MXT_BOOT_LOW;
else
client->addr = MXT_BOOT_HIGH;
reinit_completion(&data->bl_completion);
ret = mxt_check_bootloader(client, MXT_WAITING_BOOTLOAD_CMD);
ret = mxt_check_bootloader(data, MXT_WAITING_BOOTLOAD_CMD);
if (ret)
goto out;
goto disable_irq;
/* Unlock bootloader */
mxt_unlock_bootloader(client);
mxt_unlock_bootloader(data);
while (pos < fw->size) {
ret = mxt_check_bootloader(client,
MXT_WAITING_FRAME_DATA);
ret = mxt_check_bootloader(data, MXT_WAITING_FRAME_DATA);
if (ret)
goto out;
goto disable_irq;
frame_size = ((*(fw->data + pos) << 8) | *(fw->data + pos + 1));
/* We should add 2 at frame size as the the firmware data is not
* included the CRC bytes.
*/
/* Take account of CRC bytes */
frame_size += 2;
/* Write one frame to device */
mxt_fw_write(client, fw->data + pos, frame_size);
ret = mxt_check_bootloader(client,
MXT_FRAME_CRC_PASS);
ret = mxt_bootloader_write(data, fw->data + pos, frame_size);
if (ret)
goto out;
goto disable_irq;
ret = mxt_check_bootloader(data, MXT_FRAME_CRC_PASS);
if (ret) {
retry++;
/* Back off by 20ms per retry */
msleep(retry * 20);
if (retry > 20) {
dev_err(dev, "Retry count exceeded\n");
goto disable_irq;
}
} else {
retry = 0;
pos += frame_size;
frame++;
}
dev_dbg(dev, "Updated %d bytes / %zd bytes\n", pos, fw->size);
if (frame % 50 == 0)
dev_dbg(dev, "Sent %d frames, %d/%zd bytes\n",
frame, pos, fw->size);
}
out:
release_firmware(fw);
/* Wait for flash. */
ret = mxt_wait_for_completion(data, &data->bl_completion,
MXT_FW_RESET_TIME);
if (ret)
goto disable_irq;
/* Change to slave address of application */
if (client->addr == MXT_BOOT_LOW)
client->addr = MXT_APP_LOW;
else
client->addr = MXT_APP_HIGH;
dev_dbg(dev, "Sent %d frames, %d bytes\n", frame, pos);
/*
* Wait for device to reset. Some bootloader versions do not assert
* the CHG line after bootloading has finished, so ignore potential
* errors.
*/
mxt_wait_for_completion(data, &data->bl_completion, MXT_FW_RESET_TIME);
data->in_bootloader = false;
disable_irq:
disable_irq(data->irq);
release_firmware:
release_firmware(fw);
return ret;
}
......@@ -1053,28 +1336,23 @@ static ssize_t mxt_update_fw_store(struct device *dev,
struct mxt_data *data = dev_get_drvdata(dev);
int error;
disable_irq(data->irq);
error = mxt_load_fw(dev, MXT_FW_NAME);
if (error) {
dev_err(dev, "The firmware update failed(%d)\n", error);
count = error;
} else {
dev_dbg(dev, "The firmware update succeeded\n");
/* Wait for reset */
msleep(MXT_FWRESET_TIME);
dev_info(dev, "The firmware update succeeded\n");
mxt_free_object_table(data);
mxt_initialize(data);
}
enable_irq(data->irq);
error = mxt_make_highchg(data);
if (error)
return error;
}
return count;
}
......@@ -1134,6 +1412,8 @@ static int mxt_probe(struct i2c_client *client,
struct input_dev *input_dev;
int error;
unsigned int num_mt_slots;
unsigned int mt_flags = 0;
int i;
if (!pdata)
return -EINVAL;
......@@ -1146,10 +1426,7 @@ static int mxt_probe(struct i2c_client *client,
goto err_free_mem;
}
data->is_tp = pdata && pdata->is_tp;
input_dev->name = (data->is_tp) ? "Atmel maXTouch Touchpad" :
"Atmel maXTouch Touchscreen";
input_dev->name = "Atmel maXTouch Touchscreen";
snprintf(data->phys, sizeof(data->phys), "i2c-%u-%04x/input0",
client->adapter->nr, client->addr);
......@@ -1165,7 +1442,9 @@ static int mxt_probe(struct i2c_client *client,
data->pdata = pdata;
data->irq = client->irq;
mxt_calc_resolution(data);
init_completion(&data->bl_completion);
init_completion(&data->reset_completion);
init_completion(&data->crc_completion);
error = mxt_initialize(data);
if (error)
......@@ -1175,20 +1454,15 @@ static int mxt_probe(struct i2c_client *client,
__set_bit(EV_KEY, input_dev->evbit);
__set_bit(BTN_TOUCH, input_dev->keybit);
if (data->is_tp) {
int i;
__set_bit(INPUT_PROP_POINTER, input_dev->propbit);
if (pdata->t19_num_keys) {
__set_bit(INPUT_PROP_BUTTONPAD, input_dev->propbit);
for (i = 0; i < MXT_NUM_GPIO; i++)
if (pdata->key_map[i] != KEY_RESERVED)
__set_bit(pdata->key_map[i], input_dev->keybit);
for (i = 0; i < pdata->t19_num_keys; i++)
if (pdata->t19_keymap[i] != KEY_RESERVED)
input_set_capability(input_dev, EV_KEY,
pdata->t19_keymap[i]);
__set_bit(BTN_TOOL_FINGER, input_dev->keybit);
__set_bit(BTN_TOOL_DOUBLETAP, input_dev->keybit);
__set_bit(BTN_TOOL_TRIPLETAP, input_dev->keybit);
__set_bit(BTN_TOOL_QUADTAP, input_dev->keybit);
__set_bit(BTN_TOOL_QUINTTAP, input_dev->keybit);
mt_flags |= INPUT_MT_POINTER;
input_abs_set_res(input_dev, ABS_X, MXT_PIXELS_PER_MM);
input_abs_set_res(input_dev, ABS_Y, MXT_PIXELS_PER_MM);
......@@ -1196,6 +1470,8 @@ static int mxt_probe(struct i2c_client *client,
MXT_PIXELS_PER_MM);
input_abs_set_res(input_dev, ABS_MT_POSITION_Y,
MXT_PIXELS_PER_MM);
input_dev->name = "Atmel maXTouch Touchpad";
}
/* For single touch */
......@@ -1208,7 +1484,7 @@ static int mxt_probe(struct i2c_client *client,
/* For multi touch */
num_mt_slots = data->T9_reportid_max - data->T9_reportid_min + 1;
error = input_mt_init_slots(input_dev, num_mt_slots, 0);
error = input_mt_init_slots(input_dev, num_mt_slots, mt_flags);
if (error)
goto err_free_object;
input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR,
......@@ -1236,12 +1512,18 @@ static int mxt_probe(struct i2c_client *client,
goto err_free_irq;
error = input_register_device(input_dev);
if (error)
if (error) {
dev_err(&client->dev, "Error %d registering input device\n",
error);
goto err_free_irq;
}
error = sysfs_create_group(&client->dev.kobj, &mxt_attr_group);
if (error)
if (error) {
dev_err(&client->dev, "Failure %d creating sysfs group\n",
error);
goto err_unregister_device;
}
return 0;
......@@ -1294,11 +1576,7 @@ static int mxt_resume(struct device *dev)
struct mxt_data *data = i2c_get_clientdata(client);
struct input_dev *input_dev = data->input_dev;
/* Soft reset */
mxt_write_object(data, MXT_GEN_COMMAND_T6,
MXT_COMMAND_RESET, 1);
msleep(MXT_RESET_TIME);
mxt_soft_reset(data);
mutex_lock(&input_dev->mutex);
......
......@@ -679,7 +679,7 @@ static const struct i2c_device_id auo_pixcir_idtable[] = {
MODULE_DEVICE_TABLE(i2c, auo_pixcir_idtable);
#ifdef CONFIG_OF
static struct of_device_id auo_pixcir_ts_dt_idtable[] = {
static const struct of_device_id auo_pixcir_ts_dt_idtable[] = {
{ .compatible = "auo,auo_pixcir_ts" },
{},
};
......
......@@ -301,10 +301,11 @@ static int da9034_touch_probe(struct platform_device *pdev)
struct da9034_touch_pdata *pdata = dev_get_platdata(&pdev->dev);
struct da9034_touch *touch;
struct input_dev *input_dev;
int ret;
int error;
touch = kzalloc(sizeof(struct da9034_touch), GFP_KERNEL);
if (touch == NULL) {
touch = devm_kzalloc(&pdev->dev, sizeof(struct da9034_touch),
GFP_KERNEL);
if (!touch) {
dev_err(&pdev->dev, "failed to allocate driver data\n");
return -ENOMEM;
}
......@@ -315,18 +316,18 @@ static int da9034_touch_probe(struct platform_device *pdev)
touch->interval_ms = pdata->interval_ms;
touch->x_inverted = pdata->x_inverted;
touch->y_inverted = pdata->y_inverted;
} else
} else {
/* fallback into default */
touch->interval_ms = 10;
}
INIT_DELAYED_WORK(&touch->tsi_work, da9034_tsi_work);
touch->notifier.notifier_call = da9034_touch_notifier;
input_dev = input_allocate_device();
input_dev = devm_input_allocate_device(&pdev->dev);
if (!input_dev) {
dev_err(&pdev->dev, "failed to allocate input device\n");
ret = -ENOMEM;
goto err_free_touch;
return -ENOMEM;
}
input_dev->name = pdev->name;
......@@ -346,26 +347,9 @@ static int da9034_touch_probe(struct platform_device *pdev)
touch->input_dev = input_dev;
input_set_drvdata(input_dev, touch);
ret = input_register_device(input_dev);
if (ret)
goto err_free_input;
platform_set_drvdata(pdev, touch);
return 0;
err_free_input:
input_free_device(input_dev);
err_free_touch:
kfree(touch);
return ret;
}
static int da9034_touch_remove(struct platform_device *pdev)
{
struct da9034_touch *touch = platform_get_drvdata(pdev);
input_unregister_device(touch->input_dev);
kfree(touch);
error = input_register_device(input_dev);
if (error)
return error;
return 0;
}
......@@ -376,7 +360,6 @@ static struct platform_driver da9034_touch_driver = {
.owner = THIS_MODULE,
},
.probe = da9034_touch_probe,
.remove = da9034_touch_remove,
};
module_platform_driver(da9034_touch_driver);
......
......@@ -271,7 +271,7 @@ static int edt_ft5x06_register_write(struct edt_ft5x06_ts_data *tsdata,
wrbuf[0] = addr;
wrbuf[1] = value;
return edt_ft5x06_ts_readwrite(tsdata->client, 3,
return edt_ft5x06_ts_readwrite(tsdata->client, 2,
wrbuf, 0, NULL);
default:
......
......@@ -262,7 +262,7 @@ static int egalax_ts_resume(struct device *dev)
static SIMPLE_DEV_PM_OPS(egalax_ts_pm_ops, egalax_ts_suspend, egalax_ts_resume);
static struct of_device_id egalax_ts_dt_ids[] = {
static const struct of_device_id egalax_ts_dt_ids[] = {
{ .compatible = "eeti,egalax_ts" },
{ /* sentinel */ }
};
......
......@@ -36,6 +36,7 @@
#include <linux/irq.h>
#include <linux/delay.h>
#include <asm/intel_scu_ipc.h>
#include <linux/device.h>
/* PMIC Interrupt registers */
#define PMIC_REG_ID1 0x00 /* PMIC ID1 register */
......@@ -580,12 +581,17 @@ static int mrstouch_probe(struct platform_device *pdev)
return -EINVAL;
}
tsdev = kzalloc(sizeof(struct mrstouch_dev), GFP_KERNEL);
input = input_allocate_device();
if (!tsdev || !input) {
tsdev = devm_kzalloc(&pdev->dev, sizeof(struct mrstouch_dev),
GFP_KERNEL);
if (!tsdev) {
dev_err(&pdev->dev, "unable to allocate memory\n");
err = -ENOMEM;
goto err_free_mem;
return -ENOMEM;
}
input = devm_input_allocate_device(&pdev->dev);
if (!input) {
dev_err(&pdev->dev, "unable to allocate input device\n");
return -ENOMEM;
}
tsdev->dev = &pdev->dev;
......@@ -598,7 +604,7 @@ static int mrstouch_probe(struct platform_device *pdev)
err = mrstouch_adc_init(tsdev);
if (err) {
dev_err(&pdev->dev, "ADC initialization failed\n");
goto err_free_mem;
return err;
}
input->name = "mrst_touchscreen";
......@@ -618,37 +624,19 @@ static int mrstouch_probe(struct platform_device *pdev)
input_set_abs_params(tsdev->input, ABS_PRESSURE,
MRST_PRESSURE_MIN, MRST_PRESSURE_MAX, 0, 0);
err = request_threaded_irq(tsdev->irq, NULL, mrstouch_pendet_irq,
IRQF_ONESHOT, "mrstouch", tsdev);
err = devm_request_threaded_irq(&pdev->dev, tsdev->irq, NULL,
mrstouch_pendet_irq, IRQF_ONESHOT,
"mrstouch", tsdev);
if (err) {
dev_err(tsdev->dev, "unable to allocate irq\n");
goto err_free_mem;
return err;
}
err = input_register_device(tsdev->input);
if (err) {
dev_err(tsdev->dev, "unable to register input device\n");
goto err_free_irq;
}
platform_set_drvdata(pdev, tsdev);
return 0;
err_free_irq:
free_irq(tsdev->irq, tsdev);
err_free_mem:
input_free_device(input);
kfree(tsdev);
return err;
}
static int mrstouch_remove(struct platform_device *pdev)
{
struct mrstouch_dev *tsdev = platform_get_drvdata(pdev);
free_irq(tsdev->irq, tsdev);
input_unregister_device(tsdev->input);
kfree(tsdev);
}
return 0;
}
......@@ -659,7 +647,6 @@ static struct platform_driver mrstouch_driver = {
.owner = THIS_MODULE,
},
.probe = mrstouch_probe,
.remove = mrstouch_remove,
};
module_platform_driver(mrstouch_driver);
......
......@@ -384,7 +384,7 @@ static const struct dev_pm_ops lpc32xx_ts_pm_ops = {
#endif
#ifdef CONFIG_OF
static struct of_device_id lpc32xx_tsc_of_match[] = {
static const struct of_device_id lpc32xx_tsc_of_match[] = {
{ .compatible = "nxp,lpc3220-tsc", },
{ },
};
......
......@@ -161,10 +161,9 @@ static irqreturn_t mcs5000_ts_interrupt(int irq, void *dev_id)
return IRQ_HANDLED;
}
static void mcs5000_ts_phys_init(struct mcs5000_ts_data *data)
static void mcs5000_ts_phys_init(struct mcs5000_ts_data *data,
const struct mcs_platform_data *platform_data)
{
const struct mcs_platform_data *platform_data =
data->platform_data;
struct i2c_client *client = data->client;
/* Touch reset & sleep mode */
......@@ -189,26 +188,30 @@ static void mcs5000_ts_phys_init(struct mcs5000_ts_data *data)
static int mcs5000_ts_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
const struct mcs_platform_data *pdata;
struct mcs5000_ts_data *data;
struct input_dev *input_dev;
int ret;
int error;
if (!dev_get_platdata(&client->dev))
pdata = dev_get_platdata(&client->dev);
if (!pdata)
return -EINVAL;
data = kzalloc(sizeof(struct mcs5000_ts_data), GFP_KERNEL);
input_dev = input_allocate_device();
if (!data || !input_dev) {
data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
if (!data) {
dev_err(&client->dev, "Failed to allocate memory\n");
ret = -ENOMEM;
goto err_free_mem;
return -ENOMEM;
}
data->client = client;
data->input_dev = input_dev;
data->platform_data = dev_get_platdata(&client->dev);
input_dev->name = "MELPAS MCS-5000 Touchscreen";
input_dev = devm_input_allocate_device(&client->dev);
if (!input_dev) {
dev_err(&client->dev, "Failed to allocate input device\n");
return -ENOMEM;
}
input_dev->name = "MELFAS MCS-5000 Touchscreen";
input_dev->id.bustype = BUS_I2C;
input_dev->dev.parent = &client->dev;
......@@ -219,43 +222,29 @@ static int mcs5000_ts_probe(struct i2c_client *client,
input_set_abs_params(input_dev, ABS_Y, 0, MCS5000_MAX_YC, 0, 0);
input_set_drvdata(input_dev, data);
data->input_dev = input_dev;
if (data->platform_data->cfg_pin)
data->platform_data->cfg_pin();
ret = request_threaded_irq(client->irq, NULL, mcs5000_ts_interrupt,
IRQF_TRIGGER_LOW | IRQF_ONESHOT, "mcs5000_ts", data);
if (pdata->cfg_pin)
pdata->cfg_pin();
if (ret < 0) {
error = devm_request_threaded_irq(&client->dev, client->irq,
NULL, mcs5000_ts_interrupt,
IRQF_TRIGGER_LOW | IRQF_ONESHOT,
"mcs5000_ts", data);
if (error) {
dev_err(&client->dev, "Failed to register interrupt\n");
goto err_free_mem;
return error;
}
ret = input_register_device(data->input_dev);
if (ret < 0)
goto err_free_irq;
error = input_register_device(data->input_dev);
if (error) {
dev_err(&client->dev, "Failed to register input device\n");
return error;
}
mcs5000_ts_phys_init(data);
mcs5000_ts_phys_init(data, pdata);
i2c_set_clientdata(client, data);
return 0;
err_free_irq:
free_irq(client->irq, data);
err_free_mem:
input_free_device(input_dev);
kfree(data);
return ret;
}
static int mcs5000_ts_remove(struct i2c_client *client)
{
struct mcs5000_ts_data *data = i2c_get_clientdata(client);
free_irq(client->irq, data);
input_unregister_device(data->input_dev);
kfree(data);
return 0;
}
......@@ -274,14 +263,15 @@ static int mcs5000_ts_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct mcs5000_ts_data *data = i2c_get_clientdata(client);
const struct mcs_platform_data *pdata = dev_get_platdata(dev);
mcs5000_ts_phys_init(data);
mcs5000_ts_phys_init(data, pdata);
return 0;
}
#endif
static SIMPLE_DEV_PM_OPS(mcs5000_ts_pm, mcs5000_ts_suspend, mcs5000_ts_resume);
#endif
static const struct i2c_device_id mcs5000_ts_id[] = {
{ "mcs5000_ts", 0 },
......@@ -291,12 +281,9 @@ MODULE_DEVICE_TABLE(i2c, mcs5000_ts_id);
static struct i2c_driver mcs5000_ts_driver = {
.probe = mcs5000_ts_probe,
.remove = mcs5000_ts_remove,
.driver = {
.name = "mcs5000_ts",
#ifdef CONFIG_PM
.pm = &mcs5000_ts_pm,
#endif
},
.id_table = mcs5000_ts_id,
};
......
......@@ -456,7 +456,7 @@ static int mms114_probe(struct i2c_client *client,
data->input_dev = input_dev;
data->pdata = pdata;
input_dev->name = "MELPAS MMS114 Touchscreen";
input_dev->name = "MELFAS MMS114 Touchscreen";
input_dev->id.bustype = BUS_I2C;
input_dev->dev.parent = &client->dev;
input_dev->open = mms114_input_open;
......@@ -570,7 +570,7 @@ static const struct i2c_device_id mms114_id[] = {
MODULE_DEVICE_TABLE(i2c, mms114_id);
#ifdef CONFIG_OF
static struct of_device_id mms114_dt_match[] = {
static const struct of_device_id mms114_dt_match[] = {
{ .compatible = "melfas,mms114" },
{ }
};
......
/*
* Generic DT helper functions for touchscreen devices
*
* Copyright (c) 2014 Sebastian Reichel <sre@kernel.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
#include <linux/of.h>
#include <linux/input.h>
#include <linux/input/touchscreen.h>
/**
* touchscreen_parse_of_params - parse common touchscreen DT properties
* @dev: device that should be parsed
*
* This function parses common DT properties for touchscreens and setups the
* input device accordingly. The function keeps previously setuped default
* values if no value is specified via DT.
*/
void touchscreen_parse_of_params(struct input_dev *dev)
{
struct device_node *np = dev->dev.parent->of_node;
struct input_absinfo *absinfo;
input_alloc_absinfo(dev);
if (!dev->absinfo)
return;
absinfo = &dev->absinfo[ABS_X];
of_property_read_u32(np, "touchscreen-size-x", &absinfo->maximum);
of_property_read_u32(np, "touchscreen-fuzz-x", &absinfo->fuzz);
absinfo = &dev->absinfo[ABS_Y];
of_property_read_u32(np, "touchscreen-size-y", &absinfo->maximum);
of_property_read_u32(np, "touchscreen-fuzz-y", &absinfo->fuzz);
absinfo = &dev->absinfo[ABS_PRESSURE];
of_property_read_u32(np, "touchscreen-max-pressure", &absinfo->maximum);
of_property_read_u32(np, "touchscreen-fuzz-pressure", &absinfo->fuzz);
}
EXPORT_SYMBOL(touchscreen_parse_of_params);
......@@ -24,12 +24,13 @@
#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/input/pixcir_ts.h>
#include <linux/gpio.h>
struct pixcir_i2c_ts_data {
struct i2c_client *client;
struct input_dev *input;
const struct pixcir_ts_platform_data *chip;
bool exiting;
bool running;
};
static void pixcir_ts_poscheck(struct pixcir_i2c_ts_data *data)
......@@ -87,11 +88,12 @@ static void pixcir_ts_poscheck(struct pixcir_i2c_ts_data *data)
static irqreturn_t pixcir_ts_isr(int irq, void *dev_id)
{
struct pixcir_i2c_ts_data *tsdata = dev_id;
const struct pixcir_ts_platform_data *pdata = tsdata->chip;
while (!tsdata->exiting) {
while (tsdata->running) {
pixcir_ts_poscheck(tsdata);
if (tsdata->chip->attb_read_val())
if (gpio_get_value(pdata->gpio_attb))
break;
msleep(20);
......@@ -100,25 +102,221 @@ static irqreturn_t pixcir_ts_isr(int irq, void *dev_id)
return IRQ_HANDLED;
}
static int pixcir_set_power_mode(struct pixcir_i2c_ts_data *ts,
enum pixcir_power_mode mode)
{
struct device *dev = &ts->client->dev;
int ret;
ret = i2c_smbus_read_byte_data(ts->client, PIXCIR_REG_POWER_MODE);
if (ret < 0) {
dev_err(dev, "%s: can't read reg 0x%x : %d\n",
__func__, PIXCIR_REG_POWER_MODE, ret);
return ret;
}
ret &= ~PIXCIR_POWER_MODE_MASK;
ret |= mode;
/* Always AUTO_IDLE */
ret |= PIXCIR_POWER_ALLOW_IDLE;
ret = i2c_smbus_write_byte_data(ts->client, PIXCIR_REG_POWER_MODE, ret);
if (ret < 0) {
dev_err(dev, "%s: can't write reg 0x%x : %d\n",
__func__, PIXCIR_REG_POWER_MODE, ret);
return ret;
}
return 0;
}
/*
* Set the interrupt mode for the device i.e. ATTB line behaviour
*
* @polarity : 1 for active high, 0 for active low.
*/
static int pixcir_set_int_mode(struct pixcir_i2c_ts_data *ts,
enum pixcir_int_mode mode, bool polarity)
{
struct device *dev = &ts->client->dev;
int ret;
ret = i2c_smbus_read_byte_data(ts->client, PIXCIR_REG_INT_MODE);
if (ret < 0) {
dev_err(dev, "%s: can't read reg 0x%x : %d\n",
__func__, PIXCIR_REG_INT_MODE, ret);
return ret;
}
ret &= ~PIXCIR_INT_MODE_MASK;
ret |= mode;
if (polarity)
ret |= PIXCIR_INT_POL_HIGH;
else
ret &= ~PIXCIR_INT_POL_HIGH;
ret = i2c_smbus_write_byte_data(ts->client, PIXCIR_REG_INT_MODE, ret);
if (ret < 0) {
dev_err(dev, "%s: can't write reg 0x%x : %d\n",
__func__, PIXCIR_REG_INT_MODE, ret);
return ret;
}
return 0;
}
/*
* Enable/disable interrupt generation
*/
static int pixcir_int_enable(struct pixcir_i2c_ts_data *ts, bool enable)
{
struct device *dev = &ts->client->dev;
int ret;
ret = i2c_smbus_read_byte_data(ts->client, PIXCIR_REG_INT_MODE);
if (ret < 0) {
dev_err(dev, "%s: can't read reg 0x%x : %d\n",
__func__, PIXCIR_REG_INT_MODE, ret);
return ret;
}
if (enable)
ret |= PIXCIR_INT_ENABLE;
else
ret &= ~PIXCIR_INT_ENABLE;
ret = i2c_smbus_write_byte_data(ts->client, PIXCIR_REG_INT_MODE, ret);
if (ret < 0) {
dev_err(dev, "%s: can't write reg 0x%x : %d\n",
__func__, PIXCIR_REG_INT_MODE, ret);
return ret;
}
return 0;
}
static int pixcir_start(struct pixcir_i2c_ts_data *ts)
{
struct device *dev = &ts->client->dev;
int error;
/* LEVEL_TOUCH interrupt with active low polarity */
error = pixcir_set_int_mode(ts, PIXCIR_INT_LEVEL_TOUCH, 0);
if (error) {
dev_err(dev, "Failed to set interrupt mode: %d\n", error);
return error;
}
ts->running = true;
mb(); /* Update status before IRQ can fire */
/* enable interrupt generation */
error = pixcir_int_enable(ts, true);
if (error) {
dev_err(dev, "Failed to enable interrupt generation: %d\n",
error);
return error;
}
return 0;
}
static int pixcir_stop(struct pixcir_i2c_ts_data *ts)
{
int error;
/* Disable interrupt generation */
error = pixcir_int_enable(ts, false);
if (error) {
dev_err(&ts->client->dev,
"Failed to disable interrupt generation: %d\n",
error);
return error;
}
/* Exit ISR if running, no more report parsing */
ts->running = false;
mb(); /* update status before we synchronize irq */
/* Wait till running ISR is complete */
synchronize_irq(ts->client->irq);
return 0;
}
static int pixcir_input_open(struct input_dev *dev)
{
struct pixcir_i2c_ts_data *ts = input_get_drvdata(dev);
return pixcir_start(ts);
}
static void pixcir_input_close(struct input_dev *dev)
{
struct pixcir_i2c_ts_data *ts = input_get_drvdata(dev);
pixcir_stop(ts);
}
#ifdef CONFIG_PM_SLEEP
static int pixcir_i2c_ts_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct pixcir_i2c_ts_data *ts = i2c_get_clientdata(client);
struct input_dev *input = ts->input;
int ret = 0;
mutex_lock(&input->mutex);
if (device_may_wakeup(&client->dev)) {
if (!input->users) {
ret = pixcir_start(ts);
if (ret) {
dev_err(dev, "Failed to start\n");
goto unlock;
}
}
if (device_may_wakeup(&client->dev))
enable_irq_wake(client->irq);
} else if (input->users) {
ret = pixcir_stop(ts);
}
return 0;
unlock:
mutex_unlock(&input->mutex);
return ret;
}
static int pixcir_i2c_ts_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct pixcir_i2c_ts_data *ts = i2c_get_clientdata(client);
struct input_dev *input = ts->input;
int ret = 0;
mutex_lock(&input->mutex);
if (device_may_wakeup(&client->dev))
if (device_may_wakeup(&client->dev)) {
disable_irq_wake(client->irq);
return 0;
if (!input->users) {
ret = pixcir_stop(ts);
if (ret) {
dev_err(dev, "Failed to stop\n");
goto unlock;
}
}
} else if (input->users) {
ret = pixcir_start(ts);
}
unlock:
mutex_unlock(&input->mutex);
return ret;
}
#endif
......@@ -130,6 +328,7 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client,
{
const struct pixcir_ts_platform_data *pdata =
dev_get_platdata(&client->dev);
struct device *dev = &client->dev;
struct pixcir_i2c_ts_data *tsdata;
struct input_dev *input;
int error;
......@@ -139,12 +338,19 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client,
return -EINVAL;
}
tsdata = kzalloc(sizeof(*tsdata), GFP_KERNEL);
input = input_allocate_device();
if (!tsdata || !input) {
dev_err(&client->dev, "Failed to allocate driver data!\n");
error = -ENOMEM;
goto err_free_mem;
if (!gpio_is_valid(pdata->gpio_attb)) {
dev_err(dev, "Invalid gpio_attb in pdata\n");
return -EINVAL;
}
tsdata = devm_kzalloc(dev, sizeof(*tsdata), GFP_KERNEL);
if (!tsdata)
return -ENOMEM;
input = devm_input_allocate_device(dev);
if (!input) {
dev_err(dev, "Failed to allocate input device\n");
return -ENOMEM;
}
tsdata->client = client;
......@@ -153,6 +359,8 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client,
input->name = client->name;
input->id.bustype = BUS_I2C;
input->open = pixcir_input_open;
input->close = pixcir_input_close;
input->dev.parent = &client->dev;
__set_bit(EV_KEY, input->evbit);
......@@ -165,44 +373,47 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client,
input_set_drvdata(input, tsdata);
error = request_threaded_irq(client->irq, NULL, pixcir_ts_isr,
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,
client->name, tsdata);
if (error) {
dev_err(&client->dev, "Unable to request touchscreen IRQ.\n");
goto err_free_mem;
dev_err(dev, "failed to request irq %d\n", client->irq);
return error;
}
/* Always be in IDLE mode to save power, device supports auto wake */
error = pixcir_set_power_mode(tsdata, PIXCIR_POWER_IDLE);
if (error) {
dev_err(dev, "Failed to set IDLE mode\n");
return error;
}
/* Stop device till opened */
error = pixcir_stop(tsdata);
if (error)
return error;
error = input_register_device(input);
if (error)
goto err_free_irq;
return error;
i2c_set_clientdata(client, tsdata);
device_init_wakeup(&client->dev, 1);
return 0;
err_free_irq:
free_irq(client->irq, tsdata);
err_free_mem:
input_free_device(input);
kfree(tsdata);
return error;
}
static int pixcir_i2c_ts_remove(struct i2c_client *client)
{
struct pixcir_i2c_ts_data *tsdata = i2c_get_clientdata(client);
device_init_wakeup(&client->dev, 0);
tsdata->exiting = true;
mb();
free_irq(client->irq, tsdata);
input_unregister_device(tsdata->input);
kfree(tsdata);
return 0;
}
......
/*
* Allwinner sunxi resistive touchscreen controller driver
*
* Copyright (C) 2013 - 2014 Hans de Goede <hdegoede@redhat.com>
*
* The hwmon parts are based on work by Corentin LABBE which is:
* Copyright (C) 2013 Corentin LABBE <clabbe.montjoie@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
/*
* The sun4i-ts controller is capable of detecting a second touch, but when a
* second touch is present then the accuracy becomes so bad the reported touch
* location is not useable.
*
* The original android driver contains some complicated heuristics using the
* aprox. distance between the 2 touches to see if the user is making a pinch
* open / close movement, and then reports emulated multi-touch events around
* the last touch coordinate (as the dual-touch coordinates are worthless).
*
* These kinds of heuristics are just asking for trouble (and don't belong
* in the kernel). So this driver offers straight forward, reliable single
* touch functionality only.
*/
#include <linux/err.h>
#include <linux/hwmon.h>
#include <linux/init.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#define TP_CTRL0 0x00
#define TP_CTRL1 0x04
#define TP_CTRL2 0x08
#define TP_CTRL3 0x0c
#define TP_INT_FIFOC 0x10
#define TP_INT_FIFOS 0x14
#define TP_TPR 0x18
#define TP_CDAT 0x1c
#define TEMP_DATA 0x20
#define TP_DATA 0x24
/* TP_CTRL0 bits */
#define ADC_FIRST_DLY(x) ((x) << 24) /* 8 bits */
#define ADC_FIRST_DLY_MODE(x) ((x) << 23)
#define ADC_CLK_SEL(x) ((x) << 22)
#define ADC_CLK_DIV(x) ((x) << 20) /* 3 bits */
#define FS_DIV(x) ((x) << 16) /* 4 bits */
#define T_ACQ(x) ((x) << 0) /* 16 bits */
/* TP_CTRL1 bits */
#define STYLUS_UP_DEBOUN(x) ((x) << 12) /* 8 bits */
#define STYLUS_UP_DEBOUN_EN(x) ((x) << 9)
#define TOUCH_PAN_CALI_EN(x) ((x) << 6)
#define TP_DUAL_EN(x) ((x) << 5)
#define TP_MODE_EN(x) ((x) << 4)
#define TP_ADC_SELECT(x) ((x) << 3)
#define ADC_CHAN_SELECT(x) ((x) << 0) /* 3 bits */
/* TP_CTRL2 bits */
#define TP_SENSITIVE_ADJUST(x) ((x) << 28) /* 4 bits */
#define TP_MODE_SELECT(x) ((x) << 26) /* 2 bits */
#define PRE_MEA_EN(x) ((x) << 24)
#define PRE_MEA_THRE_CNT(x) ((x) << 0) /* 24 bits */
/* TP_CTRL3 bits */
#define FILTER_EN(x) ((x) << 2)
#define FILTER_TYPE(x) ((x) << 0) /* 2 bits */
/* TP_INT_FIFOC irq and fifo mask / control bits */
#define TEMP_IRQ_EN(x) ((x) << 18)
#define OVERRUN_IRQ_EN(x) ((x) << 17)
#define DATA_IRQ_EN(x) ((x) << 16)
#define TP_DATA_XY_CHANGE(x) ((x) << 13)
#define FIFO_TRIG(x) ((x) << 8) /* 5 bits */
#define DATA_DRQ_EN(x) ((x) << 7)
#define FIFO_FLUSH(x) ((x) << 4)
#define TP_UP_IRQ_EN(x) ((x) << 1)
#define TP_DOWN_IRQ_EN(x) ((x) << 0)
/* TP_INT_FIFOS irq and fifo status bits */
#define TEMP_DATA_PENDING BIT(18)
#define FIFO_OVERRUN_PENDING BIT(17)
#define FIFO_DATA_PENDING BIT(16)
#define TP_IDLE_FLG BIT(2)
#define TP_UP_PENDING BIT(1)
#define TP_DOWN_PENDING BIT(0)
/* TP_TPR bits */
#define TEMP_ENABLE(x) ((x) << 16)
#define TEMP_PERIOD(x) ((x) << 0) /* t = x * 256 * 16 / clkin */
struct sun4i_ts_data {
struct device *dev;
struct input_dev *input;
void __iomem *base;
unsigned int irq;
bool ignore_fifo_data;
int temp_data;
};
static void sun4i_ts_irq_handle_input(struct sun4i_ts_data *ts, u32 reg_val)
{
u32 x, y;
if (reg_val & FIFO_DATA_PENDING) {
x = readl(ts->base + TP_DATA);
y = readl(ts->base + TP_DATA);
/* The 1st location reported after an up event is unreliable */
if (!ts->ignore_fifo_data) {
input_report_abs(ts->input, ABS_X, x);
input_report_abs(ts->input, ABS_Y, y);
/*
* The hardware has a separate down status bit, but
* that gets set before we get the first location,
* resulting in reporting a click on the old location.
*/
input_report_key(ts->input, BTN_TOUCH, 1);
input_sync(ts->input);
} else {
ts->ignore_fifo_data = false;
}
}
if (reg_val & TP_UP_PENDING) {
ts->ignore_fifo_data = true;
input_report_key(ts->input, BTN_TOUCH, 0);
input_sync(ts->input);
}
}
static irqreturn_t sun4i_ts_irq(int irq, void *dev_id)
{
struct sun4i_ts_data *ts = dev_id;
u32 reg_val;
reg_val = readl(ts->base + TP_INT_FIFOS);
if (reg_val & TEMP_DATA_PENDING)
ts->temp_data = readl(ts->base + TEMP_DATA);
if (ts->input)
sun4i_ts_irq_handle_input(ts, reg_val);
writel(reg_val, ts->base + TP_INT_FIFOS);
return IRQ_HANDLED;
}
static int sun4i_ts_open(struct input_dev *dev)
{
struct sun4i_ts_data *ts = input_get_drvdata(dev);
/* Flush, set trig level to 1, enable temp, data and up irqs */
writel(TEMP_IRQ_EN(1) | DATA_IRQ_EN(1) | FIFO_TRIG(1) | FIFO_FLUSH(1) |
TP_UP_IRQ_EN(1), ts->base + TP_INT_FIFOC);
return 0;
}
static void sun4i_ts_close(struct input_dev *dev)
{
struct sun4i_ts_data *ts = input_get_drvdata(dev);
/* Deactivate all input IRQs */
writel(TEMP_IRQ_EN(1), ts->base + TP_INT_FIFOC);
}
static ssize_t show_temp(struct device *dev, struct device_attribute *devattr,
char *buf)
{
struct sun4i_ts_data *ts = dev_get_drvdata(dev);
/* No temp_data until the first irq */
if (ts->temp_data == -1)
return -EAGAIN;
return sprintf(buf, "%d\n", (ts->temp_data - 1447) * 100);
}
static ssize_t show_temp_label(struct device *dev,
struct device_attribute *devattr, char *buf)
{
return sprintf(buf, "SoC temperature\n");
}
static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL);
static DEVICE_ATTR(temp1_label, S_IRUGO, show_temp_label, NULL);
static struct attribute *sun4i_ts_attrs[] = {
&dev_attr_temp1_input.attr,
&dev_attr_temp1_label.attr,
NULL
};
ATTRIBUTE_GROUPS(sun4i_ts);
static int sun4i_ts_probe(struct platform_device *pdev)
{
struct sun4i_ts_data *ts;
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
struct device *hwmon;
int error;
bool ts_attached;
ts = devm_kzalloc(dev, sizeof(struct sun4i_ts_data), GFP_KERNEL);
if (!ts)
return -ENOMEM;
ts->dev = dev;
ts->ignore_fifo_data = true;
ts->temp_data = -1;
ts_attached = of_property_read_bool(np, "allwinner,ts-attached");
if (ts_attached) {
ts->input = devm_input_allocate_device(dev);
if (!ts->input)
return -ENOMEM;
ts->input->name = pdev->name;
ts->input->phys = "sun4i_ts/input0";
ts->input->open = sun4i_ts_open;
ts->input->close = sun4i_ts_close;
ts->input->id.bustype = BUS_HOST;
ts->input->id.vendor = 0x0001;
ts->input->id.product = 0x0001;
ts->input->id.version = 0x0100;
ts->input->evbit[0] = BIT(EV_SYN) | BIT(EV_KEY) | BIT(EV_ABS);
__set_bit(BTN_TOUCH, ts->input->keybit);
input_set_abs_params(ts->input, ABS_X, 0, 4095, 0, 0);
input_set_abs_params(ts->input, ABS_Y, 0, 4095, 0, 0);
input_set_drvdata(ts->input, ts);
}
ts->base = devm_ioremap_resource(dev,
platform_get_resource(pdev, IORESOURCE_MEM, 0));
if (IS_ERR(ts->base))
return PTR_ERR(ts->base);
ts->irq = platform_get_irq(pdev, 0);
error = devm_request_irq(dev, ts->irq, sun4i_ts_irq, 0, "sun4i-ts", ts);
if (error)
return error;
/*
* Select HOSC clk, clkin = clk / 6, adc samplefreq = clkin / 8192,
* t_acq = clkin / (16 * 64)
*/
writel(ADC_CLK_SEL(0) | ADC_CLK_DIV(2) | FS_DIV(7) | T_ACQ(63),
ts->base + TP_CTRL0);
/*
* sensitive_adjust = 15 : max, which is not all that sensitive,
* tp_mode = 0 : only x and y coordinates, as we don't use dual touch
*/
writel(TP_SENSITIVE_ADJUST(15) | TP_MODE_SELECT(0),
ts->base + TP_CTRL2);
/* Enable median filter, type 1 : 5/3 */
writel(FILTER_EN(1) | FILTER_TYPE(1), ts->base + TP_CTRL3);
/* Enable temperature measurement, period 1953 (2 seconds) */
writel(TEMP_ENABLE(1) | TEMP_PERIOD(1953), ts->base + TP_TPR);
/*
* Set stylus up debounce to aprox 10 ms, enable debounce, and
* finally enable tp mode.
*/
writel(STYLUS_UP_DEBOUN(5) | STYLUS_UP_DEBOUN_EN(1) | TP_MODE_EN(1),
ts->base + TP_CTRL1);
hwmon = devm_hwmon_device_register_with_groups(ts->dev, "sun4i_ts",
ts, sun4i_ts_groups);
if (IS_ERR(hwmon))
return PTR_ERR(hwmon);
writel(TEMP_IRQ_EN(1), ts->base + TP_INT_FIFOC);
if (ts_attached) {
error = input_register_device(ts->input);
if (error) {
writel(0, ts->base + TP_INT_FIFOC);
return error;
}
}
platform_set_drvdata(pdev, ts);
return 0;
}
static int sun4i_ts_remove(struct platform_device *pdev)
{
struct sun4i_ts_data *ts = platform_get_drvdata(pdev);
/* Explicit unregister to avoid open/close changing the imask later */
if (ts->input)
input_unregister_device(ts->input);
/* Deactivate all IRQs */
writel(0, ts->base + TP_INT_FIFOC);
return 0;
}
static const struct of_device_id sun4i_ts_of_match[] = {
{ .compatible = "allwinner,sun4i-a10-ts", },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, sun4i_ts_of_match);
static struct platform_driver sun4i_ts_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "sun4i-ts",
.of_match_table = of_match_ptr(sun4i_ts_of_match),
},
.probe = sun4i_ts_probe,
.remove = sun4i_ts_remove,
};
module_platform_driver(sun4i_ts_driver);
MODULE_DESCRIPTION("Allwinner sun4i resistive touchscreen controller driver");
MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
MODULE_LICENSE("GPL");
......@@ -25,11 +25,15 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/input.h>
#include <linux/input/touchscreen.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/spi/spi.h>
#include <linux/spi/tsc2005.h>
#include <linux/regulator/consumer.h>
/*
* The touchscreen interface operates as follows:
......@@ -100,6 +104,11 @@
TSC2005_CFR2_AVG_7)
#define MAX_12BIT 0xfff
#define TSC2005_DEF_X_FUZZ 4
#define TSC2005_DEF_Y_FUZZ 8
#define TSC2005_DEF_P_FUZZ 2
#define TSC2005_DEF_RESISTOR 280
#define TSC2005_SPI_MAX_SPEED_HZ 10000000
#define TSC2005_PENUP_TIME_MS 40
......@@ -143,6 +152,9 @@ struct tsc2005 {
bool pen_down;
struct regulator *vio;
int reset_gpio;
void (*set_reset)(bool enable);
};
......@@ -337,6 +349,14 @@ static void tsc2005_stop_scan(struct tsc2005 *ts)
tsc2005_cmd(ts, TSC2005_CMD_STOP);
}
static void tsc2005_set_reset(struct tsc2005 *ts, bool enable)
{
if (ts->reset_gpio >= 0)
gpio_set_value(ts->reset_gpio, enable);
else if (ts->set_reset)
ts->set_reset(enable);
}
/* must be called with ts->mutex held */
static void __tsc2005_disable(struct tsc2005 *ts)
{
......@@ -355,7 +375,7 @@ static void __tsc2005_enable(struct tsc2005 *ts)
{
tsc2005_start_scan(ts);
if (ts->esd_timeout && ts->set_reset) {
if (ts->esd_timeout && (ts->set_reset || ts->reset_gpio)) {
ts->last_valid_interrupt = jiffies;
schedule_delayed_work(&ts->esd_work,
round_jiffies_relative(
......@@ -414,9 +434,9 @@ static ssize_t tsc2005_selftest_show(struct device *dev,
}
/* hardware reset */
ts->set_reset(false);
tsc2005_set_reset(ts, false);
usleep_range(100, 500); /* only 10us required */
ts->set_reset(true);
tsc2005_set_reset(ts, true);
if (!success)
goto out;
......@@ -459,7 +479,7 @@ static umode_t tsc2005_attr_is_visible(struct kobject *kobj,
umode_t mode = attr->mode;
if (attr == &dev_attr_selftest.attr) {
if (!ts->set_reset)
if (!ts->set_reset && !ts->reset_gpio)
mode = 0;
}
......@@ -509,9 +529,9 @@ static void tsc2005_esd_work(struct work_struct *work)
tsc2005_update_pen_state(ts, 0, 0, 0);
ts->set_reset(false);
tsc2005_set_reset(ts, false);
usleep_range(100, 500); /* only 10us required */
ts->set_reset(true);
tsc2005_set_reset(ts, true);
enable_irq(ts->spi->irq);
tsc2005_start_scan(ts);
......@@ -572,29 +592,47 @@ static void tsc2005_setup_spi_xfer(struct tsc2005 *ts)
static int tsc2005_probe(struct spi_device *spi)
{
const struct tsc2005_platform_data *pdata = dev_get_platdata(&spi->dev);
struct device_node *np = spi->dev.of_node;
struct tsc2005 *ts;
struct input_dev *input_dev;
unsigned int max_x, max_y, max_p;
unsigned int fudge_x, fudge_y, fudge_p;
unsigned int max_x = MAX_12BIT;
unsigned int max_y = MAX_12BIT;
unsigned int max_p = MAX_12BIT;
unsigned int fudge_x = TSC2005_DEF_X_FUZZ;
unsigned int fudge_y = TSC2005_DEF_Y_FUZZ;
unsigned int fudge_p = TSC2005_DEF_P_FUZZ;
unsigned int x_plate_ohm = TSC2005_DEF_RESISTOR;
unsigned int esd_timeout;
int error;
if (!pdata) {
dev_dbg(&spi->dev, "no platform data\n");
if (!np && !pdata) {
dev_err(&spi->dev, "no platform data\n");
return -ENODEV;
}
fudge_x = pdata->ts_x_fudge ? : 4;
fudge_y = pdata->ts_y_fudge ? : 8;
fudge_p = pdata->ts_pressure_fudge ? : 2;
max_x = pdata->ts_x_max ? : MAX_12BIT;
max_y = pdata->ts_y_max ? : MAX_12BIT;
max_p = pdata->ts_pressure_max ? : MAX_12BIT;
if (spi->irq <= 0) {
dev_dbg(&spi->dev, "no irq\n");
dev_err(&spi->dev, "no irq\n");
return -ENODEV;
}
if (pdata) {
fudge_x = pdata->ts_x_fudge;
fudge_y = pdata->ts_y_fudge;
fudge_p = pdata->ts_pressure_fudge;
max_x = pdata->ts_x_max;
max_y = pdata->ts_y_max;
max_p = pdata->ts_pressure_max;
x_plate_ohm = pdata->ts_x_plate_ohm;
esd_timeout = pdata->esd_timeout_ms;
} else {
x_plate_ohm = TSC2005_DEF_RESISTOR;
of_property_read_u32(np, "ti,x-plate-ohms", &x_plate_ohm);
esd_timeout = 0;
of_property_read_u32(np, "ti,esd-recovery-timeout-ms",
&esd_timeout);
}
spi->mode = SPI_MODE_0;
spi->bits_per_word = 8;
if (!spi->max_speed_hz)
......@@ -604,19 +642,48 @@ static int tsc2005_probe(struct spi_device *spi)
if (error)
return error;
ts = kzalloc(sizeof(*ts), GFP_KERNEL);
input_dev = input_allocate_device();
if (!ts || !input_dev) {
error = -ENOMEM;
goto err_free_mem;
}
ts = devm_kzalloc(&spi->dev, sizeof(*ts), GFP_KERNEL);
if (!ts)
return -ENOMEM;
input_dev = devm_input_allocate_device(&spi->dev);
if (!input_dev)
return -ENOMEM;
ts->spi = spi;
ts->idev = input_dev;
ts->x_plate_ohm = pdata->ts_x_plate_ohm ? : 280;
ts->esd_timeout = pdata->esd_timeout_ms;
ts->x_plate_ohm = x_plate_ohm;
ts->esd_timeout = esd_timeout;
if (np) {
ts->reset_gpio = of_get_named_gpio(np, "reset-gpios", 0);
if (ts->reset_gpio == -EPROBE_DEFER)
return ts->reset_gpio;
if (ts->reset_gpio < 0) {
dev_err(&spi->dev, "error acquiring reset gpio: %d\n",
ts->reset_gpio);
return ts->reset_gpio;
}
error = devm_gpio_request_one(&spi->dev, ts->reset_gpio, 0,
"reset-gpios");
if (error) {
dev_err(&spi->dev, "error requesting reset gpio: %d\n",
error);
return error;
}
ts->vio = devm_regulator_get(&spi->dev, "vio");
if (IS_ERR(ts->vio)) {
error = PTR_ERR(ts->vio);
dev_err(&spi->dev, "vio regulator missing (%d)", error);
return error;
}
} else {
ts->reset_gpio = -1;
ts->set_reset = pdata->set_reset;
}
mutex_init(&ts->mutex);
......@@ -641,6 +708,9 @@ static int tsc2005_probe(struct spi_device *spi)
input_set_abs_params(input_dev, ABS_Y, 0, max_y, fudge_y, 0);
input_set_abs_params(input_dev, ABS_PRESSURE, 0, max_p, fudge_p, 0);
if (np)
touchscreen_parse_of_params(input_dev);
input_dev->open = tsc2005_open;
input_dev->close = tsc2005_close;
......@@ -649,12 +719,20 @@ static int tsc2005_probe(struct spi_device *spi)
/* Ensure the touchscreen is off */
tsc2005_stop_scan(ts);
error = request_threaded_irq(spi->irq, NULL, tsc2005_irq_thread,
error = devm_request_threaded_irq(&spi->dev, spi->irq, NULL,
tsc2005_irq_thread,
IRQF_TRIGGER_RISING | IRQF_ONESHOT,
"tsc2005", ts);
if (error) {
dev_err(&spi->dev, "Failed to request irq, err: %d\n", error);
goto err_free_mem;
return error;
}
/* enable regulator for DT */
if (ts->vio) {
error = regulator_enable(ts->vio);
if (error)
return error;
}
spi_set_drvdata(spi, ts);
......@@ -662,7 +740,7 @@ static int tsc2005_probe(struct spi_device *spi)
if (error) {
dev_err(&spi->dev,
"Failed to create sysfs attributes, err: %d\n", error);
goto err_clear_drvdata;
goto disable_regulator;
}
error = input_register_device(ts->idev);
......@@ -677,11 +755,9 @@ static int tsc2005_probe(struct spi_device *spi)
err_remove_sysfs:
sysfs_remove_group(&spi->dev.kobj, &tsc2005_attr_group);
err_clear_drvdata:
free_irq(spi->irq, ts);
err_free_mem:
input_free_device(input_dev);
kfree(ts);
disable_regulator:
if (ts->vio)
regulator_disable(ts->vio);
return error;
}
......@@ -689,11 +765,10 @@ static int tsc2005_remove(struct spi_device *spi)
{
struct tsc2005 *ts = spi_get_drvdata(spi);
sysfs_remove_group(&ts->spi->dev.kobj, &tsc2005_attr_group);
sysfs_remove_group(&spi->dev.kobj, &tsc2005_attr_group);
free_irq(ts->spi->irq, ts);
input_unregister_device(ts->idev);
kfree(ts);
if (ts->vio)
regulator_disable(ts->vio);
return 0;
}
......
......@@ -880,7 +880,7 @@ static struct i2c_device_id zforce_idtable[] = {
MODULE_DEVICE_TABLE(i2c, zforce_idtable);
#ifdef CONFIG_OF
static struct of_device_id zforce_dt_idtable[] = {
static const struct of_device_id zforce_dt_idtable[] = {
{ .compatible = "neonode,zforce" },
{},
};
......
......@@ -84,21 +84,19 @@ static struct i2c_board_info tsl2563_als_device = {
I2C_BOARD_INFO("tsl2563", TAOS_ALS_I2C_ADDR),
};
static struct mxt_platform_data atmel_224s_tp_platform_data = {
.x_line = 18,
.y_line = 12,
.x_size = 102*20,
.y_size = 68*20,
.blen = 0x80, /* Gain setting is in upper 4 bits */
.threshold = 0x32,
.voltage = 0, /* 3.3V */
.orient = MXT_VERTICAL_FLIP,
.irqflags = IRQF_TRIGGER_FALLING,
.is_tp = true,
.key_map = { KEY_RESERVED,
static int mxt_t19_keys[] = {
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
BTN_LEFT },
BTN_LEFT
};
static struct mxt_platform_data atmel_224s_tp_platform_data = {
.irqflags = IRQF_TRIGGER_FALLING,
.t19_num_keys = ARRAY_SIZE(mxt_t19_keys),
.t19_keymap = mxt_t19_keys,
.config = NULL,
.config_length = 0,
};
......@@ -110,16 +108,7 @@ static struct i2c_board_info atmel_224s_tp_device = {
};
static struct mxt_platform_data atmel_1664s_platform_data = {
.x_line = 32,
.y_line = 50,
.x_size = 1700,
.y_size = 2560,
.blen = 0x89, /* Gain setting is in upper 4 bits */
.threshold = 0x28,
.voltage = 0, /* 3.3V */
.orient = MXT_ROTATED_90_COUNTER,
.irqflags = IRQF_TRIGGER_FALLING,
.is_tp = false,
.config = NULL,
.config_length = 0,
};
......
......@@ -3,29 +3,53 @@
struct device;
/**
* struct gpio_keys_button - configuration parameters
* @code: input event code (KEY_*, SW_*)
* @gpio: %-1 if this key does not support gpio
* @active_low: %true indicates that button is considered
* depressed when gpio is low
* @desc: label that will be attached to button's gpio
* @type: input event type (%EV_KEY, %EV_SW, %EV_ABS)
* @wakeup: configure the button as a wake-up source
* @debounce_interval: debounce ticks interval in msecs
* @can_disable: %true indicates that userspace is allowed to
* disable button via sysfs
* @value: axis value for %EV_ABS
* @irq: Irq number in case of interrupt keys
*/
struct gpio_keys_button {
/* Configuration parameters */
unsigned int code; /* input event code (KEY_*, SW_*) */
int gpio; /* -1 if this key does not support gpio */
unsigned int code;
int gpio;
int active_low;
const char *desc;
unsigned int type; /* input event type (EV_KEY, EV_SW, EV_ABS) */
int wakeup; /* configure the button as a wake-up source */
int debounce_interval; /* debounce ticks interval in msecs */
unsigned int type;
int wakeup;
int debounce_interval;
bool can_disable;
int value; /* axis value for EV_ABS */
unsigned int irq; /* Irq number in case of interrupt keys */
int value;
unsigned int irq;
};
/**
* struct gpio_keys_platform_data - platform data for gpio_keys driver
* @buttons: pointer to array of &gpio_keys_button structures
* describing buttons attached to the device
* @nbuttons: number of elements in @buttons array
* @poll_interval: polling interval in msecs - for polling driver only
* @rep: enable input subsystem auto repeat
* @enable: platform hook for enabling the device
* @disable: platform hook for disabling the device
* @name: input device name
*/
struct gpio_keys_platform_data {
struct gpio_keys_button *buttons;
int nbuttons;
unsigned int poll_interval; /* polling interval in msecs -
for polling driver only */
unsigned int rep:1; /* enable input subsystem auto repeat */
unsigned int poll_interval;
unsigned int rep:1;
int (*enable)(struct device *dev);
void (*disable)(struct device *dev);
const char *name; /* input device name */
const char *name;
};
#endif
......@@ -15,35 +15,14 @@
#include <linux/types.h>
/* For key_map array */
#define MXT_NUM_GPIO 4
/* Orient */
#define MXT_NORMAL 0x0
#define MXT_DIAGONAL 0x1
#define MXT_HORIZONTAL_FLIP 0x2
#define MXT_ROTATED_90_COUNTER 0x3
#define MXT_VERTICAL_FLIP 0x4
#define MXT_ROTATED_90 0x5
#define MXT_ROTATED_180 0x6
#define MXT_DIAGONAL_COUNTER 0x7
/* The platform data for the Atmel maXTouch touchscreen driver */
struct mxt_platform_data {
const u8 *config;
size_t config_length;
unsigned int x_line;
unsigned int y_line;
unsigned int x_size;
unsigned int y_size;
unsigned int blen;
unsigned int threshold;
unsigned int voltage;
unsigned char orient;
u32 config_crc;
unsigned long irqflags;
bool is_tp;
const unsigned int key_map[MXT_NUM_GPIO];
u8 t19_num_keys;
const unsigned int *t19_keymap;
};
#endif /* __LINUX_ATMEL_MXT_TS_H */
......@@ -48,9 +48,12 @@ struct input_polled_dev {
/* private: */
struct delayed_work work;
bool devres_managed;
};
struct input_polled_dev *input_allocate_polled_device(void);
struct input_polled_dev *devm_input_allocate_polled_device(struct device *dev);
void input_free_polled_device(struct input_polled_dev *dev);
int input_register_polled_device(struct input_polled_dev *dev);
void input_unregister_polled_device(struct input_polled_dev *dev);
......
#ifndef _PIXCIR_I2C_TS_H
#define _PIXCIR_I2C_TS_H
/*
* Register map
*/
#define PIXCIR_REG_POWER_MODE 51
#define PIXCIR_REG_INT_MODE 52
/*
* Power modes:
* active: max scan speed
* idle: lower scan speed with automatic transition to active on touch
* halt: datasheet says sleep but this is more like halt as the chip
* clocks are cut and it can only be brought out of this mode
* using the RESET pin.
*/
enum pixcir_power_mode {
PIXCIR_POWER_ACTIVE,
PIXCIR_POWER_IDLE,
PIXCIR_POWER_HALT,
};
#define PIXCIR_POWER_MODE_MASK 0x03
#define PIXCIR_POWER_ALLOW_IDLE (1UL << 2)
/*
* Interrupt modes:
* periodical: interrupt is asserted periodicaly
* diff coordinates: interrupt is asserted when coordinates change
* level on touch: interrupt level asserted during touch
* pulse on touch: interrupt pulse asserted druing touch
*
*/
enum pixcir_int_mode {
PIXCIR_INT_PERIODICAL,
PIXCIR_INT_DIFF_COORD,
PIXCIR_INT_LEVEL_TOUCH,
PIXCIR_INT_PULSE_TOUCH,
};
#define PIXCIR_INT_MODE_MASK 0x03
#define PIXCIR_INT_ENABLE (1UL << 3)
#define PIXCIR_INT_POL_HIGH (1UL << 2)
struct pixcir_ts_platform_data {
int (*attb_read_val)(void);
int x_max;
int y_max;
int gpio_attb; /* GPIO connected to ATTB line */
};
#endif
/*
* Copyright (c) 2014 Sebastian Reichel <sre@kernel.org>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*/
#ifndef _TOUCHSCREEN_H
#define _TOUCHSCREEN_H
#include <linux/input.h>
#ifdef CONFIG_OF
void touchscreen_parse_of_params(struct input_dev *dev);
#else
static inline void touchscreen_parse_of_params(struct input_dev *dev)
{
}
#endif
#endif
#ifndef __LINUX_INPUT_OMAP4_KEYPAD_H
#define __LINUX_INPUT_OMAP4_KEYPAD_H
#include <linux/input/matrix_keypad.h>
struct omap4_keypad_platform_data {
const struct matrix_keymap_data *keymap_data;
u8 rows;
u8 cols;
};
#endif /* __LINUX_INPUT_OMAP4_KEYPAD_H */
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