Commit eea43ed8 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 layer updates from Dmitry Torokhov:

 - evdev interface has been adjusted to extend the life of timestamps on
   32 bit systems to the year of 2108

 - Synaptics RMI4 driver's PS/2 guest handling ha beed updated to
   improve chances of detecting trackpoints on the pass-through port

 - mms114 touchcsreen controller driver has been updated to support
   generic device properties and work with mms152 cntrollers

 - Goodix driver now supports generic touchscreen properties

 - couple of drivers for AVR32 architecture are gone as the architecture
   support has been removed from the kernel

 - gpio-tilt driver has been removed as there are no mainline users and
   the driver itself is using legacy APIs and relies on platform data

 - MODULE_LINECSE/MODULE_VERSION cleanups

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input: (45 commits)
  Input: goodix - use generic touchscreen_properties
  Input: mms114 - fix typo in definition
  Input: mms114 - use BIT() macro instead of explicit shifting
  Input: mms114 - replace mdelay with msleep
  Input: mms114 - add support for mms152
  Input: mms114 - drop platform data and use generic APIs
  Input: mms114 - mark as direct input device
  Input: mms114 - do not clobber interrupt trigger
  Input: edt-ft5x06 - fix error handling for factory mode on non-M06
  Input: stmfts - set IRQ_NOAUTOEN to the irq flag
  Input: auo-pixcir-ts - delete an unnecessary return statement
  Input: auo-pixcir-ts - remove custom log for a failed memory allocation
  Input: da9052_tsi - remove unused mutex
  Input: docs - use PROPERTY_ENTRY_U32() directly
  Input: synaptics-rmi4 - log when we create a guest serio port
  Input: synaptics-rmi4 - unmask F03 interrupts when port is opened
  Input: synaptics-rmi4 - do not delete interrupt memory too early
  Input: ad7877 - use managed resource allocations
  Input: stmfts,s6sy671 - add SPDX identifier
  Input: remove atmel-wm97xx touchscreen driver
  ...
parents f6cff79f d67ad78e
* MELFAS MMS114 touchscreen controller
* MELFAS MMS114/MMS152 touchscreen controller
Required properties:
- compatible: must be "melfas,mms114"
- compatible: should be one of:
- "melfas,mms114"
- "melfas,mms152"
- reg: I2C address of the chip
- interrupts: interrupt to which the chip is connected
- x-size: horizontal resolution of touchscreen
- y-size: vertical resolution of touchscreen
- touchscreen-size-x: See [1]
- touchscreen-size-y: See [1]
Optional properties:
- contact-threshold:
- moving-threshold:
- x-invert: invert X axis
- y-invert: invert Y axis
- touchscreen-fuzz-x: See [1]
- touchscreen-fuzz-y: See [1]
- touchscreen-fuzz-pressure: See [1]
- touchscreen-inverted-x: See [1]
- touchscreen-inverted-y: See [1]
- touchscreen-swapped-x-y: See [1]
[1]: Documentation/devicetree/bindings/input/touchscreen/touchscreen.txt
Example:
......@@ -22,12 +28,13 @@ Example:
compatible = "melfas,mms114";
reg = <0x48>;
interrupts = <39 0>;
x-size = <720>;
y-size = <1280>;
contact-threshold = <10>;
moving-threshold = <10>;
x-invert;
y-invert;
touchscreen-size-x = <720>;
touchscreen-size-y = <1280>;
touchscreen-fuzz-x = <10>;
touchscreen-fuzz-y = <10>;
touchscreen-fuzz-pressure = <10>;
touchscreen-inverted-x;
touchscreen-inverted-y;
};
/* ... */
......
......@@ -23,6 +23,8 @@ Optional properties:
- touchscreen-inverted-y : See touchscreen.txt
- touchscreen-swapped-x-y : See touchscreen.txt
- silead,max-fingers : maximum number of fingers the touchscreen can detect
- silead,home-button : Boolean, set to true on devices which have a
capacitive home-button build into the touchscreen
- vddio-supply : regulator phandle for controller VDDIO
- avdd-supply : regulator phandle for controller AVDD
......
......@@ -28,11 +28,6 @@ hardware descriptions such as device tree or ACPI:
- gpio-beeper: drivers/input/misc/gpio-beeper.c is used to provide a beep from
an external speaker connected to a GPIO line.
- gpio-tilt-polled: drivers/input/misc/gpio_tilt_polled.c provides tilt
detection switches using GPIO, which is useful for your homebrewn pinball
machine if for nothing else. It can detect different tilt angles of the
monitored object.
- extcon-gpio: drivers/extcon/extcon-gpio.c is used when you need to read an
external connector status, such as a headset line for an audio driver or an
HDMI connector. It will provide a better userspace sysfs interface than GPIO.
......
Driver for tilt-switches connected via GPIOs
============================================
Generic driver to read data from tilt switches connected via gpios.
Orientation can be provided by one or more than one tilt switches,
i.e. each tilt switch providing one axis, and the number of axes
is also not limited.
Data structures
---------------
The array of struct gpio in the gpios field is used to list the gpios
that represent the current tilt state.
The array of struct gpio_tilt_axis describes the axes that are reported
to the input system. The values set therein are used for the
input_set_abs_params calls needed to init the axes.
The array of struct gpio_tilt_state maps gpio states to the corresponding
values to report. The gpio state is represented as a bitfield where the
bit-index corresponds to the index of the gpio in the struct gpio array.
In the same manner the values stored in the axes array correspond to
the elements of the gpio_tilt_axis-array.
Example
-------
Example configuration for a single TS1003 tilt switch that rotates around
one axis in 4 steps and emits the current tilt via two GPIOs::
static int sg060_tilt_enable(struct device *dev) {
/* code to enable the sensors */
};
static void sg060_tilt_disable(struct device *dev) {
/* code to disable the sensors */
};
static struct gpio sg060_tilt_gpios[] = {
{ SG060_TILT_GPIO_SENSOR1, GPIOF_IN, "tilt_sensor1" },
{ SG060_TILT_GPIO_SENSOR2, GPIOF_IN, "tilt_sensor2" },
};
static struct gpio_tilt_state sg060_tilt_states[] = {
{
.gpios = (0 << 1) | (0 << 0),
.axes = (int[]) {
0,
},
}, {
.gpios = (0 << 1) | (1 << 0),
.axes = (int[]) {
1, /* 90 degrees */
},
}, {
.gpios = (1 << 1) | (1 << 0),
.axes = (int[]) {
2, /* 180 degrees */
},
}, {
.gpios = (1 << 1) | (0 << 0),
.axes = (int[]) {
3, /* 270 degrees */
},
},
};
static struct gpio_tilt_axis sg060_tilt_axes[] = {
{
.axis = ABS_RY,
.min = 0,
.max = 3,
.fuzz = 0,
.flat = 0,
},
};
static struct gpio_tilt_platform_data sg060_tilt_pdata= {
.gpios = sg060_tilt_gpios,
.nr_gpios = ARRAY_SIZE(sg060_tilt_gpios),
.axes = sg060_tilt_axes,
.nr_axes = ARRAY_SIZE(sg060_tilt_axes),
.states = sg060_tilt_states,
.nr_states = ARRAY_SIZE(sg060_tilt_states),
.debounce_interval = 100,
.poll_interval = 1000,
.enable = sg060_tilt_enable,
.disable = sg060_tilt_disable,
};
static struct platform_device sg060_device_tilt = {
.name = "gpio-tilt-polled",
.id = -1,
.dev = {
.platform_data = &sg060_tilt_pdata,
},
};
......@@ -108,9 +108,9 @@ example below:
};
static const struct property_entry rotary_encoder_properties[] __initconst = {
PROPERTY_ENTRY_INTEGER("rotary-encoder,steps-per-period", u32, 24),
PROPERTY_ENTRY_INTEGER("linux,axis", u32, ABS_X),
PROPERTY_ENTRY_INTEGER("rotary-encoder,relative_axis", u32, 0),
PROPERTY_ENTRY_U32("rotary-encoder,steps-per-period", 24),
PROPERTY_ENTRY_U32("linux,axis", ABS_X),
PROPERTY_ENTRY_U32("rotary-encoder,relative_axis", 0),
{ },
};
......
......@@ -31,7 +31,7 @@ To enable force feedback, you have to:
Before you start, let me WARN you that some devices shake violently during the
initialisation phase. This happens for example with my "AVB Top Shot Pegasus".
To stop this annoying behaviour, move you joystick to its limits. Anyway, you
To stop this annoying behaviour, move your joystick to its limits. Anyway, you
should keep a hand on your device, in order to avoid it to break down if
something goes wrong.
......@@ -121,7 +121,7 @@ uploaded, but not played.
The content of effect may be modified. In particular, its field "id" is set
to the unique id assigned by the driver. This data is required for performing
some operations (removing an effect, controlling the playback).
This if field must be set to -1 by the user in order to tell the driver to
The "id" field must be set to -1 by the user in order to tell the driver to
allocate a new effect.
Effects are file descriptor specific.
......@@ -178,7 +178,7 @@ Control of playing is done with write(). Below is an example:
stop.code = effect.id;
stop.value = 0;
write(fd, (const void*) &play, sizeof(stop));
write(fd, (const void*) &stop, sizeof(stop));
Setting the gain
----------------
......
......@@ -135,10 +135,7 @@ static void __evdev_flush_queue(struct evdev_client *client, unsigned int type)
continue;
} else if (head != i) {
/* move entry to fill the gap */
client->buffer[head].time = ev->time;
client->buffer[head].type = ev->type;
client->buffer[head].code = ev->code;
client->buffer[head].value = ev->value;
client->buffer[head] = *ev;
}
num++;
......@@ -157,6 +154,7 @@ static void __evdev_queue_syn_dropped(struct evdev_client *client)
{
struct input_event ev;
ktime_t time;
struct timespec64 ts;
time = client->clk_type == EV_CLK_REAL ?
ktime_get_real() :
......@@ -164,7 +162,9 @@ static void __evdev_queue_syn_dropped(struct evdev_client *client)
ktime_get() :
ktime_get_boottime();
ev.time = ktime_to_timeval(time);
ts = ktime_to_timespec64(time);
ev.input_event_sec = ts.tv_sec;
ev.input_event_usec = ts.tv_nsec / NSEC_PER_USEC;
ev.type = EV_SYN;
ev.code = SYN_DROPPED;
ev.value = 0;
......@@ -241,7 +241,10 @@ static void __pass_event(struct evdev_client *client,
*/
client->tail = (client->head - 2) & (client->bufsize - 1);
client->buffer[client->tail].time = event->time;
client->buffer[client->tail].input_event_sec =
event->input_event_sec;
client->buffer[client->tail].input_event_usec =
event->input_event_usec;
client->buffer[client->tail].type = EV_SYN;
client->buffer[client->tail].code = SYN_DROPPED;
client->buffer[client->tail].value = 0;
......@@ -262,12 +265,15 @@ static void evdev_pass_values(struct evdev_client *client,
struct evdev *evdev = client->evdev;
const struct input_value *v;
struct input_event event;
struct timespec64 ts;
bool wakeup = false;
if (client->revoked)
return;
event.time = ktime_to_timeval(ev_time[client->clk_type]);
ts = ktime_to_timespec64(ev_time[client->clk_type]);
event.input_event_sec = ts.tv_sec;
event.input_event_usec = ts.tv_nsec / NSEC_PER_USEC;
/* Interrupts are disabled, just acquire the lock. */
spin_lock(&client->buffer_lock);
......
......@@ -24,8 +24,8 @@ int input_event_from_user(const char __user *buffer,
sizeof(struct input_event_compat)))
return -EFAULT;
event->time.tv_sec = compat_event.time.tv_sec;
event->time.tv_usec = compat_event.time.tv_usec;
event->input_event_sec = compat_event.sec;
event->input_event_usec = compat_event.usec;
event->type = compat_event.type;
event->code = compat_event.code;
event->value = compat_event.value;
......@@ -44,8 +44,8 @@ int input_event_to_user(char __user *buffer,
if (in_compat_syscall() && !COMPAT_USE_64BIT_TIME) {
struct input_event_compat compat_event;
compat_event.time.tv_sec = event->time.tv_sec;
compat_event.time.tv_usec = event->time.tv_usec;
compat_event.sec = event->input_event_sec;
compat_event.usec = event->input_event_usec;
compat_event.type = event->type;
compat_event.code = event->code;
compat_event.value = event->value;
......
......@@ -18,7 +18,8 @@
#ifdef CONFIG_COMPAT
struct input_event_compat {
struct compat_timeval time;
compat_ulong_t sec;
compat_ulong_t usec;
__u16 type;
__u16 code;
__s32 value;
......
......@@ -20,7 +20,6 @@
MODULE_AUTHOR("Dmitry Torokhov <dtor@mail.ru>");
MODULE_DESCRIPTION("Generic implementation of a polled input device");
MODULE_LICENSE("GPL v2");
MODULE_VERSION("0.1");
static void input_polldev_queue_work(struct input_polled_dev *dev)
{
......
......@@ -84,9 +84,6 @@
#include <linux/usb/input.h>
#include <linux/usb/quirks.h>
#define DRIVER_AUTHOR "Marko Friedemann <mfr@bmx-chemnitz.de>"
#define DRIVER_DESC "X-Box pad driver"
#define XPAD_PKT_LEN 64
/* xbox d-pads should map to buttons, as is required for DDR pads
......@@ -1943,6 +1940,6 @@ static struct usb_driver xpad_driver = {
module_usb_driver(xpad_driver);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_AUTHOR("Marko Friedemann <mfr@bmx-chemnitz.de>");
MODULE_DESCRIPTION("X-Box pad driver");
MODULE_LICENSE("GPL");
......@@ -697,6 +697,5 @@ module_platform_driver(pmic8xxx_kp_driver);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("PMIC8XXX keypad driver");
MODULE_VERSION("1.0");
MODULE_ALIAS("platform:pmic8xxx_keypad");
MODULE_AUTHOR("Trilok Soni <tsoni@codeaurora.org>");
......@@ -268,20 +268,6 @@ config INPUT_GPIO_BEEPER
To compile this driver as a module, choose M here: the
module will be called gpio-beeper.
config INPUT_GPIO_TILT_POLLED
tristate "Polled GPIO tilt switch"
depends on GPIOLIB || COMPILE_TEST
select INPUT_POLLDEV
help
This driver implements support for tilt switches connected
to GPIO pins that are not capable of generating interrupts.
The list of gpios to use and the mapping of their states
to specific angles is done via platform data.
To compile this driver as a module, choose M here: the
module will be called gpio_tilt_polled.
config INPUT_GPIO_DECODER
tristate "Polled GPIO Decoder Input driver"
depends on GPIOLIB || COMPILE_TEST
......@@ -468,7 +454,7 @@ config INPUT_TPS65218_PWRBUTTON
tristate "TPS65218 Power button driver"
depends on (MFD_TPS65217 || MFD_TPS65218)
help
Say Y here if you want to enable power buttong reporting for
Say Y here if you want to enable power button reporting for
TPS65217 and TPS65218 Power Management IC devices.
To compile this driver as a module, choose M here. The module will
......
......@@ -36,7 +36,6 @@ obj-$(CONFIG_INPUT_DRV2665_HAPTICS) += drv2665.o
obj-$(CONFIG_INPUT_DRV2667_HAPTICS) += drv2667.o
obj-$(CONFIG_INPUT_GP2A) += gp2ap002a00f.o
obj-$(CONFIG_INPUT_GPIO_BEEPER) += gpio-beeper.o
obj-$(CONFIG_INPUT_GPIO_TILT_POLLED) += gpio_tilt_polled.o
obj-$(CONFIG_INPUT_GPIO_DECODER) += gpio_decoder.o
obj-$(CONFIG_INPUT_HISI_POWERKEY) += hisi_powerkey.o
obj-$(CONFIG_HP_SDC_RTC) += hp_sdc_rtc.o
......
......@@ -26,7 +26,6 @@
#include <linux/leds.h>
#define APANEL_NAME "Fujitsu Application Panel"
#define APANEL_VERSION "1.3.1"
#define APANEL "apanel"
/* How often we poll keys - msecs */
......@@ -345,7 +344,6 @@ module_exit(apanel_cleanup);
MODULE_AUTHOR("Stephen Hemminger <shemminger@linux-foundation.org>");
MODULE_DESCRIPTION(APANEL_NAME " driver");
MODULE_LICENSE("GPL");
MODULE_VERSION(APANEL_VERSION);
MODULE_ALIAS("dmi:*:svnFUJITSU:pnLifeBook*:pvr*:rvnFUJITSU:*");
MODULE_ALIAS("dmi:*:svnFUJITSU:pnLifebook*:pvr*:rvnFUJITSU:*");
......@@ -14,10 +14,8 @@
#include <linux/module.h>
#define DRIVER_DESC "ATI/Philips USB RF remote driver"
#define DRIVER_VERSION "0.3"
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_VERSION(DRIVER_VERSION);
MODULE_AUTHOR("Ville Syrjala <syrjala@sci.fi>");
MODULE_LICENSE("GPL");
......
/*
* Driver for tilt switches connected via GPIO lines
* not capable of generating interrupts
*
* Copyright (C) 2011 Heiko Stuebner <heiko@sntech.de>
*
* based on: drivers/input/keyboard/gpio_keys_polled.c
*
* Copyright (C) 2007-2010 Gabor Juhos <juhosg@openwrt.org>
* Copyright (C) 2010 Nuno Goncalves <nunojpg@gmail.com>
*
* 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/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/input-polldev.h>
#include <linux/ioport.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
#include <linux/input/gpio_tilt.h>
#define DRV_NAME "gpio-tilt-polled"
struct gpio_tilt_polled_dev {
struct input_polled_dev *poll_dev;
struct device *dev;
const struct gpio_tilt_platform_data *pdata;
int last_state;
int threshold;
int count;
};
static void gpio_tilt_polled_poll(struct input_polled_dev *dev)
{
struct gpio_tilt_polled_dev *tdev = dev->private;
const struct gpio_tilt_platform_data *pdata = tdev->pdata;
struct input_dev *input = dev->input;
struct gpio_tilt_state *tilt_state = NULL;
int state, i;
if (tdev->count < tdev->threshold) {
tdev->count++;
} else {
state = 0;
for (i = 0; i < pdata->nr_gpios; i++)
state |= (!!gpio_get_value(pdata->gpios[i].gpio) << i);
if (state != tdev->last_state) {
for (i = 0; i < pdata->nr_states; i++)
if (pdata->states[i].gpios == state)
tilt_state = &pdata->states[i];
if (tilt_state) {
for (i = 0; i < pdata->nr_axes; i++)
input_report_abs(input,
pdata->axes[i].axis,
tilt_state->axes[i]);
input_sync(input);
}
tdev->count = 0;
tdev->last_state = state;
}
}
}
static void gpio_tilt_polled_open(struct input_polled_dev *dev)
{
struct gpio_tilt_polled_dev *tdev = dev->private;
const struct gpio_tilt_platform_data *pdata = tdev->pdata;
if (pdata->enable)
pdata->enable(tdev->dev);
/* report initial state of the axes */
tdev->last_state = -1;
tdev->count = tdev->threshold;
gpio_tilt_polled_poll(tdev->poll_dev);
}
static void gpio_tilt_polled_close(struct input_polled_dev *dev)
{
struct gpio_tilt_polled_dev *tdev = dev->private;
const struct gpio_tilt_platform_data *pdata = tdev->pdata;
if (pdata->disable)
pdata->disable(tdev->dev);
}
static int gpio_tilt_polled_probe(struct platform_device *pdev)
{
const struct gpio_tilt_platform_data *pdata =
dev_get_platdata(&pdev->dev);
struct device *dev = &pdev->dev;
struct gpio_tilt_polled_dev *tdev;
struct input_polled_dev *poll_dev;
struct input_dev *input;
int error, i;
if (!pdata || !pdata->poll_interval)
return -EINVAL;
tdev = kzalloc(sizeof(struct gpio_tilt_polled_dev), GFP_KERNEL);
if (!tdev) {
dev_err(dev, "no memory for private data\n");
return -ENOMEM;
}
error = gpio_request_array(pdata->gpios, pdata->nr_gpios);
if (error) {
dev_err(dev,
"Could not request tilt GPIOs: %d\n", error);
goto err_free_tdev;
}
poll_dev = input_allocate_polled_device();
if (!poll_dev) {
dev_err(dev, "no memory for polled device\n");
error = -ENOMEM;
goto err_free_gpios;
}
poll_dev->private = tdev;
poll_dev->poll = gpio_tilt_polled_poll;
poll_dev->poll_interval = pdata->poll_interval;
poll_dev->open = gpio_tilt_polled_open;
poll_dev->close = gpio_tilt_polled_close;
input = poll_dev->input;
input->name = pdev->name;
input->phys = DRV_NAME"/input0";
input->dev.parent = dev;
input->id.bustype = BUS_HOST;
input->id.vendor = 0x0001;
input->id.product = 0x0001;
input->id.version = 0x0100;
__set_bit(EV_ABS, input->evbit);
for (i = 0; i < pdata->nr_axes; i++)
input_set_abs_params(input, pdata->axes[i].axis,
pdata->axes[i].min, pdata->axes[i].max,
pdata->axes[i].fuzz, pdata->axes[i].flat);
tdev->threshold = DIV_ROUND_UP(pdata->debounce_interval,
pdata->poll_interval);
tdev->poll_dev = poll_dev;
tdev->dev = dev;
tdev->pdata = pdata;
error = input_register_polled_device(poll_dev);
if (error) {
dev_err(dev, "unable to register polled device, err=%d\n",
error);
goto err_free_polldev;
}
platform_set_drvdata(pdev, tdev);
return 0;
err_free_polldev:
input_free_polled_device(poll_dev);
err_free_gpios:
gpio_free_array(pdata->gpios, pdata->nr_gpios);
err_free_tdev:
kfree(tdev);
return error;
}
static int gpio_tilt_polled_remove(struct platform_device *pdev)
{
struct gpio_tilt_polled_dev *tdev = platform_get_drvdata(pdev);
const struct gpio_tilt_platform_data *pdata = tdev->pdata;
input_unregister_polled_device(tdev->poll_dev);
input_free_polled_device(tdev->poll_dev);
gpio_free_array(pdata->gpios, pdata->nr_gpios);
kfree(tdev);
return 0;
}
static struct platform_driver gpio_tilt_polled_driver = {
.probe = gpio_tilt_polled_probe,
.remove = gpio_tilt_polled_remove,
.driver = {
.name = DRV_NAME,
},
};
module_platform_driver(gpio_tilt_polled_driver);
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Heiko Stuebner <heiko@sntech.de>");
MODULE_DESCRIPTION("Polled GPIO tilt driver");
MODULE_ALIAS("platform:" DRV_NAME);
......@@ -17,11 +17,6 @@
#include <linux/module.h>
#include <linux/usb/input.h>
#define DRIVER_VERSION "v0.1"
#define DRIVER_AUTHOR "Michael Downey <downey@zymeta.com>"
#define DRIVER_DESC "Driver for the USB Keyspan remote control."
#define DRIVER_LICENSE "GPL"
/* Parameters that can be passed to the driver. */
static int debug;
module_param(debug, int, 0444);
......@@ -590,6 +585,6 @@ static struct usb_driver keyspan_driver =
module_usb_driver(keyspan_driver);
MODULE_DEVICE_TABLE(usb, keyspan_table);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE(DRIVER_LICENSE);
MODULE_AUTHOR("Michael Downey <downey@zymeta.com>");
MODULE_DESCRIPTION("Driver for the USB Keyspan remote control.");
MODULE_LICENSE("GPL");
......@@ -84,11 +84,14 @@ static int uinput_dev_event(struct input_dev *dev,
unsigned int type, unsigned int code, int value)
{
struct uinput_device *udev = input_get_drvdata(dev);
struct timespec64 ts;
udev->buff[udev->head].type = type;
udev->buff[udev->head].code = code;
udev->buff[udev->head].value = value;
do_gettimeofday(&udev->buff[udev->head].time);
ktime_get_ts64(&ts);
udev->buff[udev->head].input_event_sec = ts.tv_sec;
udev->buff[udev->head].input_event_usec = ts.tv_nsec / NSEC_PER_USEC;
udev->head = (udev->head + 1) % UINPUT_BUFFER_SIZE;
wake_up_interruptible(&udev->waitq);
......@@ -1085,4 +1088,3 @@ MODULE_ALIAS("devname:" UINPUT_NAME);
MODULE_AUTHOR("Aristeu Sergio Rozanski Filho");
MODULE_DESCRIPTION("User level driver support for input subsystem");
MODULE_LICENSE("GPL");
MODULE_VERSION("0.3");
......@@ -56,8 +56,6 @@
#include "yealink.h"
#define DRIVER_VERSION "yld-20051230"
#define DRIVER_AUTHOR "Henk Vergonet"
#define DRIVER_DESC "Yealink phone driver"
#define YEALINK_POLLING_FREQUENCY 10 /* in [Hz] */
......@@ -1006,6 +1004,6 @@ module_usb_driver(yealink_driver);
MODULE_DEVICE_TABLE (usb, usb_table);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_AUTHOR("Henk Vergonet");
MODULE_DESCRIPTION("Yealink phone driver");
MODULE_LICENSE("GPL");
......@@ -740,7 +740,7 @@ static ssize_t cyapa_show_suspend_scanrate(struct device *dev,
char *buf)
{
struct cyapa *cyapa = dev_get_drvdata(dev);
u8 pwr_cmd = cyapa->suspend_power_mode;
u8 pwr_cmd;
u16 sleep_time;
int len;
int error;
......
......@@ -136,49 +136,6 @@ static const u8 bl_exit[] = { 0x00, 0xff, 0xa5, 0x00, 0x01, 0x02, 0x03, 0x04,
0x05, 0x06, 0x07 };
/* for byte read/write command */
#define CMD_RESET 0
#define CMD_POWER_MODE 1
#define CMD_DEV_STATUS 2
#define CMD_REPORT_MAX_BASELINE 3
#define CMD_REPORT_MIN_BASELINE 4
#define SMBUS_BYTE_CMD(cmd) (((cmd) & 0x3f) << 1)
#define CYAPA_SMBUS_RESET SMBUS_BYTE_CMD(CMD_RESET)
#define CYAPA_SMBUS_POWER_MODE SMBUS_BYTE_CMD(CMD_POWER_MODE)
#define CYAPA_SMBUS_DEV_STATUS SMBUS_BYTE_CMD(CMD_DEV_STATUS)
#define CYAPA_SMBUS_MAX_BASELINE SMBUS_BYTE_CMD(CMD_REPORT_MAX_BASELINE)
#define CYAPA_SMBUS_MIN_BASELINE SMBUS_BYTE_CMD(CMD_REPORT_MIN_BASELINE)
/* for group registers read/write command */
#define REG_GROUP_DATA 0
#define REG_GROUP_CMD 2
#define REG_GROUP_QUERY 3
#define SMBUS_GROUP_CMD(grp) (0x80 | (((grp) & 0x07) << 3))
#define CYAPA_SMBUS_GROUP_DATA SMBUS_GROUP_CMD(REG_GROUP_DATA)
#define CYAPA_SMBUS_GROUP_CMD SMBUS_GROUP_CMD(REG_GROUP_CMD)
#define CYAPA_SMBUS_GROUP_QUERY SMBUS_GROUP_CMD(REG_GROUP_QUERY)
/* for register block read/write command */
#define CMD_BL_STATUS 0
#define CMD_BL_HEAD 1
#define CMD_BL_CMD 2
#define CMD_BL_DATA 3
#define CMD_BL_ALL 4
#define CMD_BLK_PRODUCT_ID 5
#define CMD_BLK_HEAD 6
#define SMBUS_BLOCK_CMD(cmd) (0xc0 | (((cmd) & 0x1f) << 1))
/* register block read/write command in bootloader mode */
#define CYAPA_SMBUS_BL_STATUS SMBUS_BLOCK_CMD(CMD_BL_STATUS)
#define CYAPA_SMBUS_BL_HEAD SMBUS_BLOCK_CMD(CMD_BL_HEAD)
#define CYAPA_SMBUS_BL_CMD SMBUS_BLOCK_CMD(CMD_BL_CMD)
#define CYAPA_SMBUS_BL_DATA SMBUS_BLOCK_CMD(CMD_BL_DATA)
#define CYAPA_SMBUS_BL_ALL SMBUS_BLOCK_CMD(CMD_BL_ALL)
/* register block read/write command in operational mode */
#define CYAPA_SMBUS_BLK_PRODUCT_ID SMBUS_BLOCK_CMD(CMD_BLK_PRODUCT_ID)
#define CYAPA_SMBUS_BLK_HEAD SMBUS_BLOCK_CMD(CMD_BLK_HEAD)
/* for byte read/write command */
#define CMD_RESET 0
#define CMD_POWER_MODE 1
......
......@@ -42,7 +42,6 @@
#include "elan_i2c.h"
#define DRIVER_NAME "elan_i2c"
#define ELAN_DRIVER_VERSION "1.6.3"
#define ELAN_VENDOR_ID 0x04f3
#define ETP_MAX_PRESSURE 255
#define ETP_FWIDTH_REDUCE 90
......@@ -1294,4 +1293,3 @@ module_i2c_driver(elan_driver);
MODULE_AUTHOR("Duson Lin <dusonlin@emc.com.tw>");
MODULE_DESCRIPTION("Elan I2C/SMBus Touchpad driver");
MODULE_LICENSE("GPL");
MODULE_VERSION(ELAN_DRIVER_VERSION);
......@@ -975,6 +975,21 @@ static void psmouse_apply_defaults(struct psmouse *psmouse)
psmouse->pt_deactivate = NULL;
}
static bool psmouse_do_detect(int (*detect)(struct psmouse *, bool),
struct psmouse *psmouse, bool allow_passthrough,
bool set_properties)
{
if (psmouse->ps2dev.serio->id.type == SERIO_PS_PSTHRU &&
!allow_passthrough) {
return false;
}
if (set_properties)
psmouse_apply_defaults(psmouse);
return detect(psmouse, set_properties) == 0;
}
static bool psmouse_try_protocol(struct psmouse *psmouse,
enum psmouse_type type,
unsigned int *max_proto,
......@@ -986,15 +1001,8 @@ static bool psmouse_try_protocol(struct psmouse *psmouse,
if (!proto)
return false;
if (psmouse->ps2dev.serio->id.type == SERIO_PS_PSTHRU &&
!proto->try_passthru) {
return false;
}
if (set_properties)
psmouse_apply_defaults(psmouse);
if (proto->detect(psmouse, set_properties) != 0)
if (!psmouse_do_detect(proto->detect, psmouse, proto->try_passthru,
set_properties))
return false;
if (set_properties && proto->init && init_allowed) {
......@@ -1027,8 +1035,8 @@ static int psmouse_extensions(struct psmouse *psmouse,
* Always check for focaltech, this is safe as it uses pnp-id
* matching.
*/
if (psmouse_try_protocol(psmouse, PSMOUSE_FOCALTECH,
&max_proto, set_properties, false)) {
if (psmouse_do_detect(focaltech_detect,
psmouse, false, set_properties)) {
if (max_proto > PSMOUSE_IMEX &&
IS_ENABLED(CONFIG_MOUSE_PS2_FOCALTECH) &&
(!set_properties || focaltech_init(psmouse) == 0)) {
......@@ -1074,8 +1082,8 @@ static int psmouse_extensions(struct psmouse *psmouse,
* probing for IntelliMouse.
*/
if (max_proto > PSMOUSE_PS2 &&
psmouse_try_protocol(psmouse, PSMOUSE_SYNAPTICS, &max_proto,
set_properties, false)) {
psmouse_do_detect(synaptics_detect,
psmouse, false, set_properties)) {
synaptics_hardware = true;
if (max_proto > PSMOUSE_IMEX) {
......
......@@ -1281,6 +1281,16 @@ static void set_input_params(struct psmouse *psmouse,
INPUT_MT_POINTER |
(cr48_profile_sensor ?
INPUT_MT_TRACK : INPUT_MT_SEMI_MT));
/*
* For semi-mt devices we send ABS_X/Y ourselves instead of
* input_mt_report_pointer_emulation. But
* input_mt_init_slots() resets the fuzz to 0, leading to a
* filtered ABS_MT_POSITION_X but an unfiltered ABS_X
* position. Let's re-initialize ABS_X/Y here.
*/
if (!cr48_profile_sensor)
set_abs_position_params(dev, &priv->info, ABS_X, ABS_Y);
}
if (SYN_CAP_PALMDETECT(info->capabilities))
......
......@@ -427,4 +427,3 @@ MODULE_AUTHOR("Christopher Heiny <cheiny@synaptics.com");
MODULE_AUTHOR("Andrew Duggan <aduggan@synaptics.com");
MODULE_DESCRIPTION("RMI bus");
MODULE_LICENSE("GPL");
MODULE_VERSION(RMI_DRIVER_VERSION);
......@@ -41,6 +41,13 @@ void rmi_free_function_list(struct rmi_device *rmi_dev)
rmi_dbg(RMI_DEBUG_CORE, &rmi_dev->dev, "Freeing function list\n");
/* Doing it in the reverse order so F01 will be removed last */
list_for_each_entry_safe_reverse(fn, tmp,
&data->function_list, node) {
list_del(&fn->node);
rmi_unregister_function(fn);
}
devm_kfree(&rmi_dev->dev, data->irq_memory);
data->irq_memory = NULL;
data->irq_status = NULL;
......@@ -50,13 +57,6 @@ void rmi_free_function_list(struct rmi_device *rmi_dev)
data->f01_container = NULL;
data->f34_container = NULL;
/* Doing it in the reverse order so F01 will be removed last */
list_for_each_entry_safe_reverse(fn, tmp,
&data->function_list, node) {
list_del(&fn->node);
rmi_unregister_function(fn);
}
}
static int reset_one_function(struct rmi_function *fn)
......
......@@ -16,8 +16,6 @@
#include <linux/input.h>
#include "rmi_bus.h"
#define RMI_DRIVER_VERSION "2.0"
#define SYNAPTICS_INPUT_DEVICE_NAME "Synaptics RMI4 Touch Sensor"
#define SYNAPTICS_VENDOR_ID 0x06cb
......
......@@ -32,6 +32,7 @@ struct f03_data {
struct rmi_function *fn;
struct serio *serio;
bool serio_registered;
unsigned int overwrite_buttons;
......@@ -138,6 +139,37 @@ static int rmi_f03_initialize(struct f03_data *f03)
return 0;
}
static int rmi_f03_pt_open(struct serio *serio)
{
struct f03_data *f03 = serio->port_data;
struct rmi_function *fn = f03->fn;
const u8 ob_len = f03->rx_queue_length * RMI_F03_OB_SIZE;
const u16 data_addr = fn->fd.data_base_addr + RMI_F03_OB_OFFSET;
u8 obs[RMI_F03_QUEUE_LENGTH * RMI_F03_OB_SIZE];
int error;
/*
* Consume any pending data. Some devices like to spam with
* 0xaa 0x00 announcements which may confuse us as we try to
* probe the device.
*/
error = rmi_read_block(fn->rmi_dev, data_addr, &obs, ob_len);
if (!error)
rmi_dbg(RMI_DEBUG_FN, &fn->dev,
"%s: Consumed %*ph (%d) from PS2 guest\n",
__func__, ob_len, obs, ob_len);
return fn->rmi_dev->driver->set_irq_bits(fn->rmi_dev, fn->irq_mask);
}
static void rmi_f03_pt_close(struct serio *serio)
{
struct f03_data *f03 = serio->port_data;
struct rmi_function *fn = f03->fn;
fn->rmi_dev->driver->clear_irq_bits(fn->rmi_dev, fn->irq_mask);
}
static int rmi_f03_register_pt(struct f03_data *f03)
{
struct serio *serio;
......@@ -148,16 +180,19 @@ static int rmi_f03_register_pt(struct f03_data *f03)
serio->id.type = SERIO_PS_PSTHRU;
serio->write = rmi_f03_pt_write;
serio->open = rmi_f03_pt_open;
serio->close = rmi_f03_pt_close;
serio->port_data = f03;
strlcpy(serio->name, "Synaptics RMI4 PS/2 pass-through",
sizeof(serio->name));
strlcpy(serio->phys, "synaptics-rmi4-pt/serio1",
sizeof(serio->phys));
strlcpy(serio->name, "RMI4 PS/2 pass-through", sizeof(serio->name));
snprintf(serio->phys, sizeof(serio->phys), "%s/serio0",
dev_name(&f03->fn->dev));
serio->dev.parent = &f03->fn->dev;
f03->serio = serio;
printk(KERN_INFO "serio: %s port at %s\n",
serio->name, dev_name(&f03->fn->dev));
serio_register_port(serio);
return 0;
......@@ -184,17 +219,27 @@ static int rmi_f03_probe(struct rmi_function *fn)
f03->device_count);
dev_set_drvdata(dev, f03);
error = rmi_f03_register_pt(f03);
if (error)
return error;
return 0;
}
static int rmi_f03_config(struct rmi_function *fn)
{
fn->rmi_dev->driver->set_irq_bits(fn->rmi_dev, fn->irq_mask);
struct f03_data *f03 = dev_get_drvdata(&fn->dev);
int error;
if (!f03->serio_registered) {
error = rmi_f03_register_pt(f03);
if (error)
return error;
f03->serio_registered = true;
} else {
/*
* We must be re-configuring the sensor, just enable
* interrupts for this function.
*/
fn->rmi_dev->driver->set_irq_bits(fn->rmi_dev, fn->irq_mask);
}
return 0;
}
......@@ -204,7 +249,7 @@ static int rmi_f03_attention(struct rmi_function *fn, unsigned long *irq_bits)
struct rmi_device *rmi_dev = fn->rmi_dev;
struct rmi_driver_data *drvdata = dev_get_drvdata(&rmi_dev->dev);
struct f03_data *f03 = dev_get_drvdata(&fn->dev);
u16 data_addr = fn->fd.data_base_addr;
const u16 data_addr = fn->fd.data_base_addr + RMI_F03_OB_OFFSET;
const u8 ob_len = f03->rx_queue_length * RMI_F03_OB_SIZE;
u8 obs[RMI_F03_QUEUE_LENGTH * RMI_F03_OB_SIZE];
u8 ob_status;
......@@ -226,8 +271,7 @@ static int rmi_f03_attention(struct rmi_function *fn, unsigned long *irq_bits)
drvdata->attn_data.size -= ob_len;
} else {
/* Grab all of the data registers, and check them for data */
error = rmi_read_block(fn->rmi_dev, data_addr + RMI_F03_OB_OFFSET,
&obs, ob_len);
error = rmi_read_block(fn->rmi_dev, data_addr, &obs, ob_len);
if (error) {
dev_err(&fn->dev,
"%s: Failed to read F03 output buffers: %d\n",
......@@ -266,7 +310,8 @@ static void rmi_f03_remove(struct rmi_function *fn)
{
struct f03_data *f03 = dev_get_drvdata(&fn->dev);
serio_unregister_port(f03->serio);
if (f03->serio_registered)
serio_unregister_port(f03->serio);
}
struct rmi_function_handler rmi_f03_handler = {
......
......@@ -11,7 +11,6 @@
#include <linux/rmi.h>
#include <linux/firmware.h>
#include <asm/unaligned.h>
#include <asm/unaligned.h>
#include <linux/bitops.h>
#include "rmi_driver.h"
......
......@@ -391,4 +391,3 @@ MODULE_AUTHOR("Christopher Heiny <cheiny@synaptics.com>");
MODULE_AUTHOR("Andrew Duggan <aduggan@synaptics.com>");
MODULE_DESCRIPTION("RMI I2C driver");
MODULE_LICENSE("GPL");
MODULE_VERSION(RMI_DRIVER_VERSION);
......@@ -528,4 +528,3 @@ MODULE_AUTHOR("Christopher Heiny <cheiny@synaptics.com>");
MODULE_AUTHOR("Andrew Duggan <aduggan@synaptics.com>");
MODULE_DESCRIPTION("RMI SPI driver");
MODULE_LICENSE("GPL");
MODULE_VERSION(RMI_DRIVER_VERSION);
......@@ -96,16 +96,6 @@ config SERIO_RPCKBD
To compile this driver as a module, choose M here: the
module will be called rpckbd.
config SERIO_AT32PSIF
tristate "AVR32 PSIF PS/2 keyboard and mouse controller"
depends on AVR32
help
Say Y here if you want to use the PSIF peripheral on AVR32 devices
and connect a PS/2 keyboard and/or mouse to it.
To compile this driver as a module, choose M here: the module will
be called at32psif.
config SERIO_AMBAKMI
tristate "AMBA KMI keyboard controller"
depends on ARM_AMBA
......
......@@ -13,7 +13,6 @@ obj-$(CONFIG_SERIO_CT82C710) += ct82c710.o
obj-$(CONFIG_SERIO_RPCKBD) += rpckbd.o
obj-$(CONFIG_SERIO_SA1111) += sa1111ps2.o
obj-$(CONFIG_SERIO_AMBAKMI) += ambakmi.o
obj-$(CONFIG_SERIO_AT32PSIF) += at32psif.o
obj-$(CONFIG_SERIO_Q40KBD) += q40kbd.o
obj-$(CONFIG_SERIO_GSCPS2) += gscps2.o
obj-$(CONFIG_HP_SDC) += hp_sdc.o
......
/*
* Copyright (C) 2007 Atmel Corporation
*
* Driver for the AT32AP700X PS/2 controller (PSIF).
*
* 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/kernel.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/init.h>
#include <linux/serio.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/clk.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
/* PSIF register offsets */
#define PSIF_CR 0x00
#define PSIF_RHR 0x04
#define PSIF_THR 0x08
#define PSIF_SR 0x10
#define PSIF_IER 0x14
#define PSIF_IDR 0x18
#define PSIF_IMR 0x1c
#define PSIF_PSR 0x24
/* Bitfields in control register. */
#define PSIF_CR_RXDIS_OFFSET 1
#define PSIF_CR_RXDIS_SIZE 1
#define PSIF_CR_RXEN_OFFSET 0
#define PSIF_CR_RXEN_SIZE 1
#define PSIF_CR_SWRST_OFFSET 15
#define PSIF_CR_SWRST_SIZE 1
#define PSIF_CR_TXDIS_OFFSET 9
#define PSIF_CR_TXDIS_SIZE 1
#define PSIF_CR_TXEN_OFFSET 8
#define PSIF_CR_TXEN_SIZE 1
/* Bitfields in interrupt disable, enable, mask and status register. */
#define PSIF_NACK_OFFSET 8
#define PSIF_NACK_SIZE 1
#define PSIF_OVRUN_OFFSET 5
#define PSIF_OVRUN_SIZE 1
#define PSIF_PARITY_OFFSET 9
#define PSIF_PARITY_SIZE 1
#define PSIF_RXRDY_OFFSET 4
#define PSIF_RXRDY_SIZE 1
#define PSIF_TXEMPTY_OFFSET 1
#define PSIF_TXEMPTY_SIZE 1
#define PSIF_TXRDY_OFFSET 0
#define PSIF_TXRDY_SIZE 1
/* Bitfields in prescale register. */
#define PSIF_PSR_PRSCV_OFFSET 0
#define PSIF_PSR_PRSCV_SIZE 12
/* Bitfields in receive hold register. */
#define PSIF_RHR_RXDATA_OFFSET 0
#define PSIF_RHR_RXDATA_SIZE 8
/* Bitfields in transmit hold register. */
#define PSIF_THR_TXDATA_OFFSET 0
#define PSIF_THR_TXDATA_SIZE 8
/* Bit manipulation macros */
#define PSIF_BIT(name) \
(1 << PSIF_##name##_OFFSET)
#define PSIF_BF(name, value) \
(((value) & ((1 << PSIF_##name##_SIZE) - 1)) \
<< PSIF_##name##_OFFSET)
#define PSIF_BFEXT(name, value) \
(((value) >> PSIF_##name##_OFFSET) \
& ((1 << PSIF_##name##_SIZE) - 1))
#define PSIF_BFINS(name, value, old) \
(((old) & ~(((1 << PSIF_##name##_SIZE) - 1) \
<< PSIF_##name##_OFFSET)) \
| PSIF_BF(name, value))
/* Register access macros */
#define psif_readl(port, reg) \
__raw_readl((port)->regs + PSIF_##reg)
#define psif_writel(port, reg, value) \
__raw_writel((value), (port)->regs + PSIF_##reg)
struct psif {
struct platform_device *pdev;
struct clk *pclk;
struct serio *io;
void __iomem *regs;
unsigned int irq;
/* Prevent concurrent writes to PSIF THR. */
spinlock_t lock;
bool open;
};
static irqreturn_t psif_interrupt(int irq, void *_ptr)
{
struct psif *psif = _ptr;
int retval = IRQ_NONE;
unsigned int io_flags = 0;
unsigned long status;
status = psif_readl(psif, SR);
if (status & PSIF_BIT(RXRDY)) {
unsigned char val = (unsigned char) psif_readl(psif, RHR);
if (status & PSIF_BIT(PARITY))
io_flags |= SERIO_PARITY;
if (status & PSIF_BIT(OVRUN))
dev_err(&psif->pdev->dev, "overrun read error\n");
serio_interrupt(psif->io, val, io_flags);
retval = IRQ_HANDLED;
}
return retval;
}
static int psif_write(struct serio *io, unsigned char val)
{
struct psif *psif = io->port_data;
unsigned long flags;
int timeout = 10;
int retval = 0;
spin_lock_irqsave(&psif->lock, flags);
while (!(psif_readl(psif, SR) & PSIF_BIT(TXEMPTY)) && timeout--)
udelay(50);
if (timeout >= 0) {
psif_writel(psif, THR, val);
} else {
dev_dbg(&psif->pdev->dev, "timeout writing to THR\n");
retval = -EBUSY;
}
spin_unlock_irqrestore(&psif->lock, flags);
return retval;
}
static int psif_open(struct serio *io)
{
struct psif *psif = io->port_data;
int retval;
retval = clk_enable(psif->pclk);
if (retval)
return retval;
psif_writel(psif, CR, PSIF_BIT(CR_TXEN) | PSIF_BIT(CR_RXEN));
psif_writel(psif, IER, PSIF_BIT(RXRDY));
psif->open = true;
return retval;
}
static void psif_close(struct serio *io)
{
struct psif *psif = io->port_data;
psif->open = false;
psif_writel(psif, IDR, ~0UL);
psif_writel(psif, CR, PSIF_BIT(CR_TXDIS) | PSIF_BIT(CR_RXDIS));
clk_disable(psif->pclk);
}
static void psif_set_prescaler(struct psif *psif)
{
unsigned long prscv;
unsigned long rate = clk_get_rate(psif->pclk);
/* PRSCV = Pulse length (100 us) * PSIF module frequency. */
prscv = 100 * (rate / 1000000UL);
if (prscv > ((1<<PSIF_PSR_PRSCV_SIZE) - 1)) {
prscv = (1<<PSIF_PSR_PRSCV_SIZE) - 1;
dev_dbg(&psif->pdev->dev, "pclk too fast, "
"prescaler set to max\n");
}
clk_enable(psif->pclk);
psif_writel(psif, PSR, prscv);
clk_disable(psif->pclk);
}
static int __init psif_probe(struct platform_device *pdev)
{
struct resource *regs;
struct psif *psif;
struct serio *io;
struct clk *pclk;
int irq;
int ret;
psif = kzalloc(sizeof(struct psif), GFP_KERNEL);
if (!psif)
return -ENOMEM;
psif->pdev = pdev;
io = kzalloc(sizeof(struct serio), GFP_KERNEL);
if (!io) {
ret = -ENOMEM;
goto out_free_psif;
}
psif->io = io;
regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!regs) {
dev_dbg(&pdev->dev, "no mmio resources defined\n");
ret = -ENOMEM;
goto out_free_io;
}
psif->regs = ioremap(regs->start, resource_size(regs));
if (!psif->regs) {
ret = -ENOMEM;
dev_dbg(&pdev->dev, "could not map I/O memory\n");
goto out_free_io;
}
pclk = clk_get(&pdev->dev, "pclk");
if (IS_ERR(pclk)) {
dev_dbg(&pdev->dev, "could not get peripheral clock\n");
ret = PTR_ERR(pclk);
goto out_iounmap;
}
psif->pclk = pclk;
/* Reset the PSIF to enter at a known state. */
ret = clk_enable(pclk);
if (ret) {
dev_dbg(&pdev->dev, "could not enable pclk\n");
goto out_put_clk;
}
psif_writel(psif, CR, PSIF_BIT(CR_SWRST));
clk_disable(pclk);
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
dev_dbg(&pdev->dev, "could not get irq\n");
ret = -ENXIO;
goto out_put_clk;
}
ret = request_irq(irq, psif_interrupt, IRQF_SHARED, "at32psif", psif);
if (ret) {
dev_dbg(&pdev->dev, "could not request irq %d\n", irq);
goto out_put_clk;
}
psif->irq = irq;
io->id.type = SERIO_8042;
io->write = psif_write;
io->open = psif_open;
io->close = psif_close;
snprintf(io->name, sizeof(io->name), "AVR32 PS/2 port%d", pdev->id);
snprintf(io->phys, sizeof(io->phys), "at32psif/serio%d", pdev->id);
io->port_data = psif;
io->dev.parent = &pdev->dev;
psif_set_prescaler(psif);
spin_lock_init(&psif->lock);
serio_register_port(psif->io);
platform_set_drvdata(pdev, psif);
dev_info(&pdev->dev, "Atmel AVR32 PSIF PS/2 driver on 0x%08x irq %d\n",
(int)psif->regs, psif->irq);
return 0;
out_put_clk:
clk_put(psif->pclk);
out_iounmap:
iounmap(psif->regs);
out_free_io:
kfree(io);
out_free_psif:
kfree(psif);
return ret;
}
static int __exit psif_remove(struct platform_device *pdev)
{
struct psif *psif = platform_get_drvdata(pdev);
psif_writel(psif, IDR, ~0UL);
psif_writel(psif, CR, PSIF_BIT(CR_TXDIS) | PSIF_BIT(CR_RXDIS));
serio_unregister_port(psif->io);
iounmap(psif->regs);
free_irq(psif->irq, psif);
clk_put(psif->pclk);
kfree(psif);
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int psif_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct psif *psif = platform_get_drvdata(pdev);
if (psif->open) {
psif_writel(psif, CR, PSIF_BIT(CR_RXDIS) | PSIF_BIT(CR_TXDIS));
clk_disable(psif->pclk);
}
return 0;
}
static int psif_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct psif *psif = platform_get_drvdata(pdev);
if (psif->open) {
clk_enable(psif->pclk);
psif_set_prescaler(psif);
psif_writel(psif, CR, PSIF_BIT(CR_RXEN) | PSIF_BIT(CR_TXEN));
}
return 0;
}
#endif
static SIMPLE_DEV_PM_OPS(psif_pm_ops, psif_suspend, psif_resume);
static struct platform_driver psif_driver = {
.remove = __exit_p(psif_remove),
.driver = {
.name = "atmel_psif",
.pm = &psif_pm_ops,
},
};
module_platform_driver_probe(psif_driver, psif_probe);
MODULE_AUTHOR("Hans-Christian Egtvedt <egtvedt@samfundet.no>");
MODULE_DESCRIPTION("Atmel AVR32 PSIF PS/2 driver");
MODULE_LICENSE("GPL");
......@@ -274,14 +274,12 @@ static int hilse_match(hil_mlc *mlc, int unused)
/* An LCV used to prevent runaway loops, forces 5 second sleep when reset. */
static int hilse_init_lcv(hil_mlc *mlc, int unused)
{
struct timeval tv;
time64_t now = ktime_get_seconds();
do_gettimeofday(&tv);
if (mlc->lcv && (tv.tv_sec - mlc->lcv_tv.tv_sec) < 5)
if (mlc->lcv && (now - mlc->lcv_time) < 5)
return -1;
mlc->lcv_tv = tv;
mlc->lcv_time = now;
mlc->lcv = 0;
return 0;
......@@ -604,8 +602,8 @@ static inline void hilse_setup_input(hil_mlc *mlc, const struct hilse_node *node
BUG();
}
mlc->istarted = 1;
mlc->intimeout = node->arg;
do_gettimeofday(&(mlc->instart));
mlc->intimeout = usecs_to_jiffies(node->arg);
mlc->instart = jiffies;
mlc->icount = 15;
memset(mlc->ipacket, 0, 16 * sizeof(hil_packet));
BUG_ON(down_trylock(&mlc->isem));
......@@ -710,7 +708,7 @@ static int hilse_donode(hil_mlc *mlc)
break;
}
mlc->ostarted = 0;
do_gettimeofday(&(mlc->instart));
mlc->instart = jiffies;
write_unlock_irqrestore(&mlc->lock, flags);
nextidx = HILSEN_NEXT;
break;
......@@ -731,18 +729,14 @@ static int hilse_donode(hil_mlc *mlc)
#endif
while (nextidx & HILSEN_SCHED) {
struct timeval tv;
unsigned long now = jiffies;
if (!sched_long)
goto sched;
do_gettimeofday(&tv);
tv.tv_usec += USEC_PER_SEC * (tv.tv_sec - mlc->instart.tv_sec);
tv.tv_usec -= mlc->instart.tv_usec;
if (tv.tv_usec >= mlc->intimeout) goto sched;
tv.tv_usec = (mlc->intimeout - tv.tv_usec) * HZ / USEC_PER_SEC;
if (!tv.tv_usec) goto sched;
mod_timer(&hil_mlcs_kicker, jiffies + tv.tv_usec);
if (time_after(now, mlc->instart + mlc->intimeout))
goto sched;
mod_timer(&hil_mlcs_kicker, mlc->instart + mlc->intimeout);
break;
sched:
tasklet_schedule(&hil_mlcs_tasklet);
......
......@@ -193,7 +193,7 @@ static void hp_sdc_take(int irq, void *dev_id, uint8_t status, uint8_t data)
curr->seq[curr->idx++] = status;
curr->seq[curr->idx++] = data;
hp_sdc.rqty -= 2;
do_gettimeofday(&hp_sdc.rtv);
hp_sdc.rtime = ktime_get();
if (hp_sdc.rqty <= 0) {
/* All data has been gathered. */
......@@ -306,13 +306,10 @@ static void hp_sdc_tasklet(unsigned long foo)
write_lock_irq(&hp_sdc.rtq_lock);
if (hp_sdc.rcurr >= 0) {
struct timeval tv;
ktime_t now = ktime_get();
do_gettimeofday(&tv);
if (tv.tv_sec > hp_sdc.rtv.tv_sec)
tv.tv_usec += USEC_PER_SEC;
if (tv.tv_usec - hp_sdc.rtv.tv_usec > HP_SDC_MAX_REG_DELAY) {
if (ktime_after(now, ktime_add_us(hp_sdc.rtime,
HP_SDC_MAX_REG_DELAY))) {
hp_sdc_transaction *curr;
uint8_t tmp;
......@@ -321,8 +318,8 @@ static void hp_sdc_tasklet(unsigned long foo)
* we'll need to figure out a way to communicate
* it back to the application. and be less verbose.
*/
printk(KERN_WARNING PREFIX "read timeout (%ius)!\n",
(int)(tv.tv_usec - hp_sdc.rtv.tv_usec));
printk(KERN_WARNING PREFIX "read timeout (%lldus)!\n",
ktime_us_delta(now, hp_sdc.rtime));
curr->idx += hp_sdc.rqty;
hp_sdc.rqty = 0;
tmp = curr->seq[curr->actidx];
......@@ -551,7 +548,7 @@ unsigned long hp_sdc_put(void)
/* Start a new read */
hp_sdc.rqty = curr->seq[curr->idx];
do_gettimeofday(&hp_sdc.rtv);
hp_sdc.rtime = ktime_get();
curr->idx++;
/* Still need to lock here in case of spurious irq. */
write_lock_irq(&hp_sdc.rtq_lock);
......
......@@ -149,7 +149,6 @@ static int hp_sdc_mlc_in(hil_mlc *mlc, suseconds_t timeout)
/* Try to down the semaphore */
if (down_trylock(&mlc->isem)) {
struct timeval tv;
if (priv->emtestmode) {
mlc->ipacket[0] =
HIL_ERR_INT | (mlc->opacket &
......@@ -160,9 +159,7 @@ static int hp_sdc_mlc_in(hil_mlc *mlc, suseconds_t timeout)
/* printk(KERN_DEBUG PREFIX ">[%x]\n", mlc->ipacket[0]); */
goto wasup;
}
do_gettimeofday(&tv);
tv.tv_usec += USEC_PER_SEC * (tv.tv_sec - mlc->instart.tv_sec);
if (tv.tv_usec - mlc->instart.tv_usec > mlc->intimeout) {
if (time_after(jiffies, mlc->instart + mlc->intimeout)) {
/* printk("!%i %i",
tv.tv_usec - mlc->instart.tv_usec,
mlc->intimeout);
......
......@@ -21,7 +21,6 @@
MODULE_AUTHOR("Dmitry Torokhov <dtor@mail.ru>");
MODULE_DESCRIPTION("Generic support for sparse keymaps");
MODULE_LICENSE("GPL v2");
MODULE_VERSION("0.1");
static unsigned int sparse_keymap_get_key_index(struct input_dev *dev,
const struct key_entry *k)
......
......@@ -30,17 +30,9 @@
#include <linux/module.h>
#include <linux/usb/input.h>
/*
* Version Information
*/
#define DRIVER_VERSION "v3.2"
#define DRIVER_DESC "USB Acecad Flair tablet driver"
#define DRIVER_LICENSE "GPL"
#define DRIVER_AUTHOR "Edouard TISSERANT <edouard.tisserant@wanadoo.fr>"
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE(DRIVER_LICENSE);
MODULE_AUTHOR("Edouard TISSERANT <edouard.tisserant@wanadoo.fr>");
MODULE_DESCRIPTION("USB Acecad Flair tablet driver");
MODULE_LICENSE("GPL");
#define USB_VENDOR_ID_ACECAD 0x0460
#define USB_DEVICE_ID_FLAIR 0x0004
......
......@@ -78,13 +78,6 @@
#include <linux/uaccess.h>
#include <asm/unaligned.h>
/*
* Version Information
*/
#define DRIVER_VERSION "v2.3 (May 2, 2007)"
#define DRIVER_AUTHOR "Bryan W. Headley/Chris Atenasio/Cedric Brun/Rene van Paassen"
#define DRIVER_DESC "Aiptek HyperPen USB Tablet Driver (Linux 2.6.x)"
/*
* Aiptek status packet:
*
......@@ -1941,8 +1934,8 @@ static struct usb_driver aiptek_driver = {
module_usb_driver(aiptek_driver);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_AUTHOR("Bryan W. Headley/Chris Atenasio/Cedric Brun/Rene van Paassen");
MODULE_DESCRIPTION("Aiptek HyperPen USB Tablet Driver");
MODULE_LICENSE("GPL");
module_param(programmableDelay, int, 0);
......
......@@ -28,13 +28,9 @@
#include <linux/module.h>
#include <linux/usb/input.h>
#define DRIVER_AUTHOR "Xing Wei <weixing@hanwang.com.cn>"
#define DRIVER_DESC "USB Hanwang tablet driver"
#define DRIVER_LICENSE "GPL"
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE(DRIVER_LICENSE);
MODULE_AUTHOR("Xing Wei <weixing@hanwang.com.cn>");
MODULE_DESCRIPTION("USB Hanwang tablet driver");
MODULE_LICENSE("GPL");
#define USB_VENDOR_ID_HANWANG 0x0b57
#define HANWANG_TABLET_INT_CLASS 0x0003
......
......@@ -5,21 +5,12 @@
#include <asm/unaligned.h>
/*
* Version Information
* v0.0.1 - Original, extremely basic version, 2.4.xx only
* v0.0.2 - Updated, works with 2.5.62 and 2.4.20;
* - added pressure-threshold modules param code from
* Alex Perry <alex.perry@ieee.org>
* Pressure-threshold modules param code from Alex Perry <alex.perry@ieee.org>
*/
#define DRIVER_VERSION "v0.0.2"
#define DRIVER_AUTHOR "Josh Myer <josh@joshisanerd.com>"
#define DRIVER_DESC "USB KB Gear JamStudio Tablet driver"
#define DRIVER_LICENSE "GPL"
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE(DRIVER_LICENSE);
MODULE_AUTHOR("Josh Myer <josh@joshisanerd.com>");
MODULE_DESCRIPTION("USB KB Gear JamStudio Tablet driver");
MODULE_LICENSE("GPL");
#define USB_VENDOR_ID_KBGEAR 0x084e
......
......@@ -795,21 +795,6 @@ config TOUCHSCREEN_WM9713
Say Y here to enable support for the Wolfson Microelectronics
WM9713 touchscreen controller.
config TOUCHSCREEN_WM97XX_ATMEL
tristate "WM97xx Atmel accelerated touch"
depends on TOUCHSCREEN_WM97XX && AVR32
help
Say Y here for support for streaming mode with WM97xx touchscreens
on Atmel AT91 or AVR32 systems with an AC97C module.
Be aware that this will use channel B in the controller for
streaming data, this must not conflict with other AC97C drivers.
If unsure, say N.
To compile this driver as a module, choose M here: the module will
be called atmel-wm97xx.
config TOUCHSCREEN_WM97XX_MAINSTONE
tristate "WM97xx Mainstone/Palm accelerated touch"
depends on TOUCHSCREEN_WM97XX && ARCH_PXA
......
......@@ -97,7 +97,6 @@ obj-$(CONFIG_TOUCHSCREEN_WM97XX) += wm97xx-ts.o
wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9705) += wm9705.o
wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9712) += wm9712.o
wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9713) += wm9713.o
obj-$(CONFIG_TOUCHSCREEN_WM97XX_ATMEL) += atmel-wm97xx.o
obj-$(CONFIG_TOUCHSCREEN_WM97XX_MAINSTONE) += mainstone-wm97xx.o
obj-$(CONFIG_TOUCHSCREEN_WM97XX_ZYLONITE) += zylonite-wm97xx.o
obj-$(CONFIG_TOUCHSCREEN_W90X900) += w90p910_ts.o
......
......@@ -417,8 +417,10 @@ static irqreturn_t ad7877_irq(int irq, void *handle)
return IRQ_HANDLED;
}
static void ad7877_disable(struct ad7877 *ts)
static void ad7877_disable(void *data)
{
struct ad7877 *ts = data;
mutex_lock(&ts->mutex);
if (!ts->disabled) {
......@@ -707,12 +709,17 @@ static int ad7877_probe(struct spi_device *spi)
return err;
}
ts = kzalloc(sizeof(struct ad7877), GFP_KERNEL);
input_dev = input_allocate_device();
if (!ts || !input_dev) {
err = -ENOMEM;
goto err_free_mem;
}
ts = devm_kzalloc(&spi->dev, sizeof(struct ad7877), GFP_KERNEL);
if (!ts)
return -ENOMEM;
input_dev = devm_input_allocate_device(&spi->dev);
if (!input_dev)
return -ENOMEM;
err = devm_add_action_or_reset(&spi->dev, ad7877_disable, ts);
if (err)
return err;
spi_set_drvdata(spi, ts);
ts->spi = spi;
......@@ -761,11 +768,10 @@ static int ad7877_probe(struct spi_device *spi)
verify = ad7877_read(spi, AD7877_REG_SEQ1);
if (verify != AD7877_MM_SEQUENCE){
if (verify != AD7877_MM_SEQUENCE) {
dev_err(&spi->dev, "%s: Failed to probe %s\n",
dev_name(&spi->dev), input_dev->name);
err = -ENODEV;
goto err_free_mem;
return -ENODEV;
}
if (gpio3)
......@@ -775,47 +781,21 @@ static int ad7877_probe(struct spi_device *spi)
/* Request AD7877 /DAV GPIO interrupt */
err = request_threaded_irq(spi->irq, NULL, ad7877_irq,
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
spi->dev.driver->name, ts);
err = devm_request_threaded_irq(&spi->dev, spi->irq, NULL, ad7877_irq,
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
spi->dev.driver->name, ts);
if (err) {
dev_dbg(&spi->dev, "irq %d busy?\n", spi->irq);
goto err_free_mem;
return err;
}
err = sysfs_create_group(&spi->dev.kobj, &ad7877_attr_group);
err = devm_device_add_group(&spi->dev, &ad7877_attr_group);
if (err)
goto err_free_irq;
return err;
err = input_register_device(input_dev);
if (err)
goto err_remove_attr_group;
return 0;
err_remove_attr_group:
sysfs_remove_group(&spi->dev.kobj, &ad7877_attr_group);
err_free_irq:
free_irq(spi->irq, ts);
err_free_mem:
input_free_device(input_dev);
kfree(ts);
return err;
}
static int ad7877_remove(struct spi_device *spi)
{
struct ad7877 *ts = spi_get_drvdata(spi);
sysfs_remove_group(&spi->dev.kobj, &ad7877_attr_group);
ad7877_disable(ts);
free_irq(ts->spi->irq, ts);
input_unregister_device(ts->input);
kfree(ts);
dev_dbg(&spi->dev, "unregistered touchscreen\n");
return err;
return 0;
}
......@@ -846,7 +826,6 @@ static struct spi_driver ad7877_driver = {
.pm = &ad7877_pm,
},
.probe = ad7877_probe,
.remove = ad7877_remove,
};
module_spi_driver(ad7877_driver);
......
/*
* Atmel AT91 and AVR32 continuous touch screen driver for Wolfson WM97xx AC97
* codecs.
*
* Copyright (C) 2008 - 2009 Atmel Corporation
*
* 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/moduleparam.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/wm97xx.h>
#include <linux/timer.h>
#include <linux/gpio.h>
#include <linux/io.h>
#include <linux/slab.h>
#define AC97C_ICA 0x10
#define AC97C_CBRHR 0x30
#define AC97C_CBSR 0x38
#define AC97C_CBMR 0x3c
#define AC97C_IER 0x54
#define AC97C_IDR 0x58
#define AC97C_RXRDY (1 << 4)
#define AC97C_OVRUN (1 << 5)
#define AC97C_CMR_SIZE_20 (0 << 16)
#define AC97C_CMR_SIZE_18 (1 << 16)
#define AC97C_CMR_SIZE_16 (2 << 16)
#define AC97C_CMR_SIZE_10 (3 << 16)
#define AC97C_CMR_CEM_LITTLE (1 << 18)
#define AC97C_CMR_CEM_BIG (0 << 18)
#define AC97C_CMR_CENA (1 << 21)
#define AC97C_INT_CBEVT (1 << 4)
#define AC97C_SR_CAEVT (1 << 3)
#define AC97C_CH_MASK(slot) \
(0x7 << (3 * (slot - 3)))
#define AC97C_CH_ASSIGN(slot, channel) \
(AC97C_CHANNEL_##channel << (3 * (slot - 3)))
#define AC97C_CHANNEL_NONE 0x0
#define AC97C_CHANNEL_B 0x2
#define ac97c_writel(chip, reg, val) \
__raw_writel((val), (chip)->regs + AC97C_##reg)
#define ac97c_readl(chip, reg) \
__raw_readl((chip)->regs + AC97C_##reg)
#ifdef CONFIG_CPU_AT32AP700X
#define ATMEL_WM97XX_AC97C_IOMEM (0xfff02800)
#define ATMEL_WM97XX_AC97C_IRQ (29)
#define ATMEL_WM97XX_GPIO_DEFAULT (32+16) /* Pin 16 on port B. */
#else
#error Unknown CPU, this driver only supports AT32AP700X CPUs.
#endif
struct continuous {
u16 id; /* codec id */
u8 code; /* continuous code */
u8 reads; /* number of coord reads per read cycle */
u32 speed; /* number of coords per second */
};
#define WM_READS(sp) ((sp / HZ) + 1)
static const struct continuous cinfo[] = {
{WM9705_ID2, 0, WM_READS(94), 94},
{WM9705_ID2, 1, WM_READS(188), 188},
{WM9705_ID2, 2, WM_READS(375), 375},
{WM9705_ID2, 3, WM_READS(750), 750},
{WM9712_ID2, 0, WM_READS(94), 94},
{WM9712_ID2, 1, WM_READS(188), 188},
{WM9712_ID2, 2, WM_READS(375), 375},
{WM9712_ID2, 3, WM_READS(750), 750},
{WM9713_ID2, 0, WM_READS(94), 94},
{WM9713_ID2, 1, WM_READS(120), 120},
{WM9713_ID2, 2, WM_READS(154), 154},
{WM9713_ID2, 3, WM_READS(188), 188},
};
/* Continuous speed index. */
static int sp_idx;
/*
* Pen sampling frequency (Hz) in continuous mode.
*/
static int cont_rate = 188;
module_param(cont_rate, int, 0);
MODULE_PARM_DESC(cont_rate, "Sampling rate in continuous mode (Hz)");
/*
* Pen down detection.
*
* This driver can either poll or use an interrupt to indicate a pen down
* event. If the irq request fails then it will fall back to polling mode.
*/
static int pen_int = 1;
module_param(pen_int, int, 0);
MODULE_PARM_DESC(pen_int, "Pen down detection (1 = interrupt, 0 = polling)");
/*
* Pressure readback.
*
* Set to 1 to read back pen down pressure.
*/
static int pressure;
module_param(pressure, int, 0);
MODULE_PARM_DESC(pressure, "Pressure readback (1 = pressure, 0 = no pressure)");
/*
* AC97 touch data slot.
*
* Touch screen readback data ac97 slot.
*/
static int ac97_touch_slot = 5;
module_param(ac97_touch_slot, int, 0);
MODULE_PARM_DESC(ac97_touch_slot, "Touch screen data slot AC97 number");
/*
* GPIO line number.
*
* Set to GPIO number where the signal from the WM97xx device is hooked up.
*/
static int atmel_gpio_line = ATMEL_WM97XX_GPIO_DEFAULT;
module_param(atmel_gpio_line, int, 0);
MODULE_PARM_DESC(atmel_gpio_line, "GPIO line number connected to WM97xx");
struct atmel_wm97xx {
struct wm97xx *wm;
struct timer_list pen_timer;
void __iomem *regs;
unsigned long ac97c_irq;
unsigned long gpio_pen;
unsigned long gpio_irq;
unsigned short x;
unsigned short y;
};
static irqreturn_t atmel_wm97xx_channel_b_interrupt(int irq, void *dev_id)
{
struct atmel_wm97xx *atmel_wm97xx = dev_id;
struct wm97xx *wm = atmel_wm97xx->wm;
int status = ac97c_readl(atmel_wm97xx, CBSR);
irqreturn_t retval = IRQ_NONE;
if (status & AC97C_OVRUN) {
dev_dbg(&wm->touch_dev->dev, "AC97C overrun\n");
ac97c_readl(atmel_wm97xx, CBRHR);
retval = IRQ_HANDLED;
} else if (status & AC97C_RXRDY) {
u16 data;
u16 value;
u16 source;
u16 pen_down;
data = ac97c_readl(atmel_wm97xx, CBRHR);
value = data & 0x0fff;
source = data & WM97XX_ADCSEL_MASK;
pen_down = (data & WM97XX_PEN_DOWN) >> 8;
if (source == WM97XX_ADCSEL_X)
atmel_wm97xx->x = value;
if (source == WM97XX_ADCSEL_Y)
atmel_wm97xx->y = value;
if (!pressure && source == WM97XX_ADCSEL_Y) {
input_report_abs(wm->input_dev, ABS_X, atmel_wm97xx->x);
input_report_abs(wm->input_dev, ABS_Y, atmel_wm97xx->y);
input_report_key(wm->input_dev, BTN_TOUCH, pen_down);
input_sync(wm->input_dev);
} else if (pressure && source == WM97XX_ADCSEL_PRES) {
input_report_abs(wm->input_dev, ABS_X, atmel_wm97xx->x);
input_report_abs(wm->input_dev, ABS_Y, atmel_wm97xx->y);
input_report_abs(wm->input_dev, ABS_PRESSURE, value);
input_report_key(wm->input_dev, BTN_TOUCH, value);
input_sync(wm->input_dev);
}
retval = IRQ_HANDLED;
}
return retval;
}
static void atmel_wm97xx_acc_pen_up(struct wm97xx *wm)
{
struct atmel_wm97xx *atmel_wm97xx = platform_get_drvdata(wm->touch_dev);
struct input_dev *input_dev = wm->input_dev;
int pen_down = gpio_get_value(atmel_wm97xx->gpio_pen);
if (pen_down != 0) {
mod_timer(&atmel_wm97xx->pen_timer,
jiffies + msecs_to_jiffies(1));
} else {
if (pressure)
input_report_abs(input_dev, ABS_PRESSURE, 0);
input_report_key(input_dev, BTN_TOUCH, 0);
input_sync(input_dev);
}
}
static void atmel_wm97xx_pen_timer(struct timer_list *t)
{
struct atmel_wm97xx *atmel_wm97xx = from_timer(atmel_wm97xx, t,
pen_timer);
atmel_wm97xx_acc_pen_up(atmel_wm97xx->wm);
}
static int atmel_wm97xx_acc_startup(struct wm97xx *wm)
{
struct atmel_wm97xx *atmel_wm97xx = platform_get_drvdata(wm->touch_dev);
int idx = 0;
if (wm->ac97 == NULL)
return -ENODEV;
for (idx = 0; idx < ARRAY_SIZE(cinfo); idx++) {
if (wm->id != cinfo[idx].id)
continue;
sp_idx = idx;
if (cont_rate <= cinfo[idx].speed)
break;
}
wm->acc_rate = cinfo[sp_idx].code;
wm->acc_slot = ac97_touch_slot;
dev_info(&wm->touch_dev->dev, "atmel accelerated touchscreen driver, "
"%d samples/sec\n", cinfo[sp_idx].speed);
if (pen_int) {
unsigned long reg;
wm->pen_irq = atmel_wm97xx->gpio_irq;
switch (wm->id) {
case WM9712_ID2: /* Fall through. */
case WM9713_ID2:
/*
* Use GPIO 13 (PEN_DOWN) to assert GPIO line 3
* (PENDOWN).
*/
wm97xx_config_gpio(wm, WM97XX_GPIO_13, WM97XX_GPIO_IN,
WM97XX_GPIO_POL_HIGH,
WM97XX_GPIO_STICKY,
WM97XX_GPIO_WAKE);
wm97xx_config_gpio(wm, WM97XX_GPIO_3, WM97XX_GPIO_OUT,
WM97XX_GPIO_POL_HIGH,
WM97XX_GPIO_NOTSTICKY,
WM97XX_GPIO_NOWAKE);
case WM9705_ID2: /* Fall through. */
/*
* Enable touch data slot in AC97 controller channel B.
*/
reg = ac97c_readl(atmel_wm97xx, ICA);
reg &= ~AC97C_CH_MASK(wm->acc_slot);
reg |= AC97C_CH_ASSIGN(wm->acc_slot, B);
ac97c_writel(atmel_wm97xx, ICA, reg);
/*
* Enable channel and interrupt for RXRDY and OVERRUN.
*/
ac97c_writel(atmel_wm97xx, CBMR, AC97C_CMR_CENA
| AC97C_CMR_CEM_BIG
| AC97C_CMR_SIZE_16
| AC97C_OVRUN
| AC97C_RXRDY);
/* Dummy read to empty RXRHR. */
ac97c_readl(atmel_wm97xx, CBRHR);
/*
* Enable interrupt for channel B in the AC97
* controller.
*/
ac97c_writel(atmel_wm97xx, IER, AC97C_INT_CBEVT);
break;
default:
dev_err(&wm->touch_dev->dev, "pen down irq not "
"supported on this device\n");
pen_int = 0;
break;
}
}
return 0;
}
static void atmel_wm97xx_acc_shutdown(struct wm97xx *wm)
{
if (pen_int) {
struct atmel_wm97xx *atmel_wm97xx =
platform_get_drvdata(wm->touch_dev);
unsigned long ica;
switch (wm->id & 0xffff) {
case WM9705_ID2: /* Fall through. */
case WM9712_ID2: /* Fall through. */
case WM9713_ID2:
/* Disable slot and turn off channel B interrupts. */
ica = ac97c_readl(atmel_wm97xx, ICA);
ica &= ~AC97C_CH_MASK(wm->acc_slot);
ac97c_writel(atmel_wm97xx, ICA, ica);
ac97c_writel(atmel_wm97xx, IDR, AC97C_INT_CBEVT);
ac97c_writel(atmel_wm97xx, CBMR, 0);
wm->pen_irq = 0;
break;
default:
dev_err(&wm->touch_dev->dev, "unknown codec\n");
break;
}
}
}
static void atmel_wm97xx_irq_enable(struct wm97xx *wm, int enable)
{
/* Intentionally left empty. */
}
static struct wm97xx_mach_ops atmel_mach_ops = {
.acc_enabled = 1,
.acc_pen_up = atmel_wm97xx_acc_pen_up,
.acc_startup = atmel_wm97xx_acc_startup,
.acc_shutdown = atmel_wm97xx_acc_shutdown,
.irq_enable = atmel_wm97xx_irq_enable,
.irq_gpio = WM97XX_GPIO_3,
};
static int __init atmel_wm97xx_probe(struct platform_device *pdev)
{
struct wm97xx *wm = platform_get_drvdata(pdev);
struct atmel_wm97xx *atmel_wm97xx;
int ret;
atmel_wm97xx = kzalloc(sizeof(struct atmel_wm97xx), GFP_KERNEL);
if (!atmel_wm97xx)
return -ENOMEM;
atmel_wm97xx->wm = wm;
atmel_wm97xx->regs = (void *)ATMEL_WM97XX_AC97C_IOMEM;
atmel_wm97xx->ac97c_irq = ATMEL_WM97XX_AC97C_IRQ;
atmel_wm97xx->gpio_pen = atmel_gpio_line;
atmel_wm97xx->gpio_irq = gpio_to_irq(atmel_wm97xx->gpio_pen);
timer_setup(&atmel_wm97xx->pen_timer, atmel_wm97xx_pen_timer, 0);
ret = request_irq(atmel_wm97xx->ac97c_irq,
atmel_wm97xx_channel_b_interrupt,
IRQF_SHARED, "atmel-wm97xx-ch-b", atmel_wm97xx);
if (ret) {
dev_dbg(&pdev->dev, "could not request ac97c irq\n");
goto err;
}
platform_set_drvdata(pdev, atmel_wm97xx);
ret = wm97xx_register_mach_ops(wm, &atmel_mach_ops);
if (ret)
goto err_irq;
return ret;
err_irq:
free_irq(atmel_wm97xx->ac97c_irq, atmel_wm97xx);
err:
kfree(atmel_wm97xx);
return ret;
}
static int __exit atmel_wm97xx_remove(struct platform_device *pdev)
{
struct atmel_wm97xx *atmel_wm97xx = platform_get_drvdata(pdev);
struct wm97xx *wm = atmel_wm97xx->wm;
ac97c_writel(atmel_wm97xx, IDR, AC97C_INT_CBEVT);
free_irq(atmel_wm97xx->ac97c_irq, atmel_wm97xx);
del_timer_sync(&atmel_wm97xx->pen_timer);
wm97xx_unregister_mach_ops(wm);
kfree(atmel_wm97xx);
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int atmel_wm97xx_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct atmel_wm97xx *atmel_wm97xx = platform_get_drvdata(pdev);
ac97c_writel(atmel_wm97xx, IDR, AC97C_INT_CBEVT);
disable_irq(atmel_wm97xx->gpio_irq);
del_timer_sync(&atmel_wm97xx->pen_timer);
return 0;
}
static int atmel_wm97xx_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct atmel_wm97xx *atmel_wm97xx = platform_get_drvdata(pdev);
struct wm97xx *wm = atmel_wm97xx->wm;
if (wm->input_dev->users) {
enable_irq(atmel_wm97xx->gpio_irq);
ac97c_writel(atmel_wm97xx, IER, AC97C_INT_CBEVT);
}
return 0;
}
#endif
static SIMPLE_DEV_PM_OPS(atmel_wm97xx_pm_ops,
atmel_wm97xx_suspend, atmel_wm97xx_resume);
static struct platform_driver atmel_wm97xx_driver = {
.remove = __exit_p(atmel_wm97xx_remove),
.driver = {
.name = "wm97xx-touch",
.pm = &atmel_wm97xx_pm_ops,
},
};
module_platform_driver_probe(atmel_wm97xx_driver, atmel_wm97xx_probe);
MODULE_AUTHOR("Hans-Christian Egtvedt <egtvedt@samfundet.no>");
MODULE_DESCRIPTION("wm97xx continuous touch driver for Atmel AT91 and AVR32");
MODULE_LICENSE("GPL");
......@@ -408,8 +408,6 @@ static void auo_pixcir_input_close(struct input_dev *dev)
struct auo_pixcir_ts *ts = input_get_drvdata(dev);
auo_pixcir_stop(ts);
return;
}
static int __maybe_unused auo_pixcir_suspend(struct device *dev)
......@@ -487,10 +485,8 @@ static struct auo_pixcir_ts_platdata *auo_pixcir_parse_dt(struct device *dev)
return ERR_PTR(-ENOENT);
pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata) {
dev_err(dev, "failed to allocate platform data\n");
if (!pdata)
return ERR_PTR(-ENOMEM);
}
pdata->gpio_int = of_get_gpio(np, 0);
if (!gpio_is_valid(pdata->gpio_int)) {
......
......@@ -28,7 +28,6 @@
#include <linux/types.h>
#define DRIVER_NAME "colibri-vf50-ts"
#define DRV_VERSION "1.0"
#define VF_ADC_MAX ((1 << 12) - 1)
......@@ -382,4 +381,3 @@ module_platform_driver(vf50_touch_driver);
MODULE_AUTHOR("Sanchayan Maity");
MODULE_DESCRIPTION("Colibri VF50 Touchscreen driver");
MODULE_LICENSE("GPL");
MODULE_VERSION(DRV_VERSION);
......@@ -26,7 +26,6 @@ struct da9052_tsi {
struct da9052 *da9052;
struct input_dev *dev;
struct delayed_work ts_pen_work;
struct mutex mutex;
bool stopped;
bool adc_on;
};
......
......@@ -511,6 +511,12 @@ static int edt_ft5x06_factory_mode(struct edt_ft5x06_ts_data *tsdata)
int ret;
int error;
if (tsdata->version != EDT_M06) {
dev_err(&client->dev,
"No factory mode support for non-M06 devices\n");
return -EINVAL;
}
disable_irq(client->irq);
if (!tsdata->raw_buffer) {
......@@ -524,9 +530,6 @@ static int edt_ft5x06_factory_mode(struct edt_ft5x06_ts_data *tsdata)
}
/* mode register is 0x3c when in the work mode */
if (tsdata->version != EDT_M06)
goto m09_out;
error = edt_ft5x06_register_write(tsdata, WORK_REGISTER_OPMODE, 0x03);
if (error) {
dev_err(&client->dev,
......@@ -559,11 +562,6 @@ static int edt_ft5x06_factory_mode(struct edt_ft5x06_ts_data *tsdata)
enable_irq(client->irq);
return error;
m09_out:
dev_err(&client->dev, "No factory mode support for M09/M12/GENERIC_FT\n");
return -EINVAL;
}
static int edt_ft5x06_work_mode(struct edt_ft5x06_ts_data *tsdata)
......
......@@ -45,7 +45,6 @@
/* Device, Driver information */
#define DEVICE_NAME "elants_i2c"
#define DRV_VERSION "1.0.9"
/* Convert from rows or columns into resolution */
#define ELAN_TS_RESOLUTION(n, m) (((n) - 1) * (m))
......@@ -1406,5 +1405,4 @@ module_i2c_driver(elants_i2c_driver);
MODULE_AUTHOR("Scott Liu <scott.liu@emc.com.tw>");
MODULE_DESCRIPTION("Elan I2c Touchscreen driver");
MODULE_VERSION(DRV_VERSION);
MODULE_LICENSE("GPL");
......@@ -22,6 +22,7 @@
#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/input/mt.h>
#include <linux/input/touchscreen.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/irq.h>
......@@ -43,11 +44,7 @@ struct goodix_ts_data {
struct i2c_client *client;
struct input_dev *input_dev;
const struct goodix_chip_data *chip;
int abs_x_max;
int abs_y_max;
bool swapped_x_y;
bool inverted_x;
bool inverted_y;
struct touchscreen_properties prop;
unsigned int max_touch_num;
unsigned int int_trigger_type;
struct gpio_desc *gpiod_int;
......@@ -160,7 +157,7 @@ static int goodix_i2c_read(struct i2c_client *client,
u16 reg, u8 *buf, int len)
{
struct i2c_msg msgs[2];
u16 wbuf = cpu_to_be16(reg);
__be16 wbuf = cpu_to_be16(reg);
int ret;
msgs[0].flags = 0;
......@@ -295,18 +292,10 @@ static void goodix_ts_report_touch(struct goodix_ts_data *ts, u8 *coor_data)
int input_y = get_unaligned_le16(&coor_data[3]);
int input_w = get_unaligned_le16(&coor_data[5]);
/* Inversions have to happen before axis swapping */
if (ts->inverted_x)
input_x = ts->abs_x_max - input_x;
if (ts->inverted_y)
input_y = ts->abs_y_max - input_y;
if (ts->swapped_x_y)
swap(input_x, input_y);
input_mt_slot(ts->input_dev, id);
input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, true);
input_report_abs(ts->input_dev, ABS_MT_POSITION_X, input_x);
input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, input_y);
touchscreen_report_pos(ts->input_dev, &ts->prop,
input_x, input_y, true);
input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, input_w);
input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, input_w);
}
......@@ -579,44 +568,27 @@ static int goodix_get_gpio_config(struct goodix_ts_data *ts)
static void goodix_read_config(struct goodix_ts_data *ts)
{
u8 config[GOODIX_CONFIG_MAX_LENGTH];
int x_max, y_max;
int error;
error = goodix_i2c_read(ts->client, ts->chip->config_addr,
config, ts->chip->config_len);
if (error) {
dev_warn(&ts->client->dev,
"Error reading config (%d), using defaults\n",
dev_warn(&ts->client->dev, "Error reading config: %d\n",
error);
ts->abs_x_max = GOODIX_MAX_WIDTH;
ts->abs_y_max = GOODIX_MAX_HEIGHT;
if (ts->swapped_x_y)
swap(ts->abs_x_max, ts->abs_y_max);
ts->int_trigger_type = GOODIX_INT_TRIGGER;
ts->max_touch_num = GOODIX_MAX_CONTACTS;
return;
}
ts->abs_x_max = get_unaligned_le16(&config[RESOLUTION_LOC]);
ts->abs_y_max = get_unaligned_le16(&config[RESOLUTION_LOC + 2]);
if (ts->swapped_x_y)
swap(ts->abs_x_max, ts->abs_y_max);
ts->int_trigger_type = config[TRIGGER_LOC] & 0x03;
ts->max_touch_num = config[MAX_CONTACTS_LOC] & 0x0f;
if (!ts->abs_x_max || !ts->abs_y_max || !ts->max_touch_num) {
dev_err(&ts->client->dev,
"Invalid config, using defaults\n");
ts->abs_x_max = GOODIX_MAX_WIDTH;
ts->abs_y_max = GOODIX_MAX_HEIGHT;
if (ts->swapped_x_y)
swap(ts->abs_x_max, ts->abs_y_max);
ts->max_touch_num = GOODIX_MAX_CONTACTS;
}
if (dmi_check_system(rotated_screen)) {
ts->inverted_x = true;
ts->inverted_y = true;
dev_dbg(&ts->client->dev,
"Applying '180 degrees rotated screen' quirk\n");
x_max = get_unaligned_le16(&config[RESOLUTION_LOC]);
y_max = get_unaligned_le16(&config[RESOLUTION_LOC + 2]);
if (x_max && y_max) {
input_abs_set_max(ts->input_dev, ABS_MT_POSITION_X, x_max - 1);
input_abs_set_max(ts->input_dev, ABS_MT_POSITION_Y, y_max - 1);
}
}
......@@ -676,32 +648,28 @@ static int goodix_i2c_test(struct i2c_client *client)
}
/**
* goodix_request_input_dev - Allocate, populate and register the input device
* goodix_configure_dev - Finish device initialization
*
* @ts: our goodix_ts_data pointer
*
* Must be called during probe
* Must be called from probe to finish initialization of the device.
* Contains the common initialization code for both devices that
* declare gpio pins and devices that do not. It is either called
* directly from probe or from request_firmware_wait callback.
*/
static int goodix_request_input_dev(struct goodix_ts_data *ts)
static int goodix_configure_dev(struct goodix_ts_data *ts)
{
int error;
ts->int_trigger_type = GOODIX_INT_TRIGGER;
ts->max_touch_num = GOODIX_MAX_CONTACTS;
ts->input_dev = devm_input_allocate_device(&ts->client->dev);
if (!ts->input_dev) {
dev_err(&ts->client->dev, "Failed to allocate input device.");
return -ENOMEM;
}
input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X,
0, ts->abs_x_max, 0, 0);
input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y,
0, ts->abs_y_max, 0, 0);
input_set_abs_params(ts->input_dev, ABS_MT_WIDTH_MAJOR, 0, 255, 0, 0);
input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0);
input_mt_init_slots(ts->input_dev, ts->max_touch_num,
INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED);
ts->input_dev->name = "Goodix Capacitive TouchScreen";
ts->input_dev->phys = "input/ts";
ts->input_dev->id.bustype = BUS_I2C;
......@@ -712,42 +680,49 @@ static int goodix_request_input_dev(struct goodix_ts_data *ts)
/* Capacitive Windows/Home button on some devices */
input_set_capability(ts->input_dev, EV_KEY, KEY_LEFTMETA);
error = input_register_device(ts->input_dev);
if (error) {
dev_err(&ts->client->dev,
"Failed to register input device: %d", error);
return error;
}
input_set_capability(ts->input_dev, EV_ABS, ABS_MT_POSITION_X);
input_set_capability(ts->input_dev, EV_ABS, ABS_MT_POSITION_Y);
input_set_abs_params(ts->input_dev, ABS_MT_WIDTH_MAJOR, 0, 255, 0, 0);
input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0);
return 0;
}
/* Read configuration and apply touchscreen parameters */
goodix_read_config(ts);
/**
* goodix_configure_dev - Finish device initialization
*
* @ts: our goodix_ts_data pointer
*
* Must be called from probe to finish initialization of the device.
* Contains the common initialization code for both devices that
* declare gpio pins and devices that do not. It is either called
* directly from probe or from request_firmware_wait callback.
*/
static int goodix_configure_dev(struct goodix_ts_data *ts)
{
int error;
/* Try overriding touchscreen parameters via device properties */
touchscreen_parse_properties(ts->input_dev, true, &ts->prop);
ts->swapped_x_y = device_property_read_bool(&ts->client->dev,
"touchscreen-swapped-x-y");
ts->inverted_x = device_property_read_bool(&ts->client->dev,
"touchscreen-inverted-x");
ts->inverted_y = device_property_read_bool(&ts->client->dev,
"touchscreen-inverted-y");
if (!ts->prop.max_x || !ts->prop.max_y || !ts->max_touch_num) {
dev_err(&ts->client->dev, "Invalid config, using defaults\n");
ts->prop.max_x = GOODIX_MAX_WIDTH - 1;
ts->prop.max_y = GOODIX_MAX_HEIGHT - 1;
ts->max_touch_num = GOODIX_MAX_CONTACTS;
input_abs_set_max(ts->input_dev,
ABS_MT_POSITION_X, ts->prop.max_x);
input_abs_set_max(ts->input_dev,
ABS_MT_POSITION_Y, ts->prop.max_y);
}
goodix_read_config(ts);
if (dmi_check_system(rotated_screen)) {
ts->prop.invert_x = true;
ts->prop.invert_y = true;
dev_dbg(&ts->client->dev,
"Applying '180 degrees rotated screen' quirk\n");
}
error = goodix_request_input_dev(ts);
if (error)
error = input_mt_init_slots(ts->input_dev, ts->max_touch_num,
INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED);
if (error) {
dev_err(&ts->client->dev,
"Failed to initialize MT slots: %d", error);
return error;
}
error = input_register_device(ts->input_dev);
if (error) {
dev_err(&ts->client->dev,
"Failed to register input device: %d", error);
return error;
}
ts->irq_flags = goodix_irq_flags[ts->int_trigger_type] | IRQF_ONESHOT;
error = goodix_request_irq(ts);
......@@ -878,8 +853,10 @@ static int __maybe_unused goodix_suspend(struct device *dev)
int error;
/* We need gpio pins to suspend/resume */
if (!ts->gpiod_int || !ts->gpiod_rst)
if (!ts->gpiod_int || !ts->gpiod_rst) {
disable_irq(client->irq);
return 0;
}
wait_for_completion(&ts->firmware_loading_complete);
......@@ -919,8 +896,10 @@ static int __maybe_unused goodix_resume(struct device *dev)
struct goodix_ts_data *ts = i2c_get_clientdata(client);
int error;
if (!ts->gpiod_int || !ts->gpiod_rst)
if (!ts->gpiod_int || !ts->gpiod_rst) {
enable_irq(client->irq);
return 0;
}
/*
* Exit sleep mode by outputting HIGH level to INT pin
......
......@@ -1611,6 +1611,5 @@ static struct i2c_driver mip4_driver = {
module_i2c_driver(mip4_driver);
MODULE_DESCRIPTION("MELFAS MIP4 Touchscreen");
MODULE_VERSION("2016.10.31");
MODULE_AUTHOR("Sangwon Jee <jeesw@melfas.com>");
MODULE_LICENSE("GPL");
......@@ -10,17 +10,18 @@
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/i2c.h>
#include <linux/input/mt.h>
#include <linux/input/touchscreen.h>
#include <linux/interrupt.h>
#include <linux/platform_data/mms114.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
/* Write only registers */
#define MMS114_MODE_CONTROL 0x01
#define MMS114_OPERATION_MODE_MASK 0xE
#define MMS114_ACTIVE (1 << 1)
#define MMS114_ACTIVE BIT(1)
#define MMS114_XY_RESOLUTION_H 0x02
#define MMS114_X_RESOLUTION 0x03
......@@ -30,9 +31,12 @@
/* Read only registers */
#define MMS114_PACKET_SIZE 0x0F
#define MMS114_INFOMATION 0x10
#define MMS114_INFORMATION 0x10
#define MMS114_TSP_REV 0xF0
#define MMS152_FW_REV 0xE1
#define MMS152_COMPAT_GROUP 0xF2
/* Minimum delay time is 50us between stop and start signal of i2c */
#define MMS114_I2C_DELAY 50
......@@ -50,12 +54,20 @@
#define MMS114_TYPE_TOUCHSCREEN 1
#define MMS114_TYPE_TOUCHKEY 2
enum mms_type {
TYPE_MMS114 = 114,
TYPE_MMS152 = 152,
};
struct mms114_data {
struct i2c_client *client;
struct input_dev *input_dev;
struct regulator *core_reg;
struct regulator *io_reg;
const struct mms114_platform_data *pdata;
struct touchscreen_properties props;
enum mms_type type;
unsigned int contact_threshold;
unsigned int moving_threshold;
/* Use cache data for mode control register(write only) */
u8 cache_mode_control;
......@@ -143,7 +155,6 @@ static int mms114_write_reg(struct mms114_data *data, unsigned int reg,
static void mms114_process_mt(struct mms114_data *data, struct mms114_touch *touch)
{
const struct mms114_platform_data *pdata = data->pdata;
struct i2c_client *client = data->client;
struct input_dev *input_dev = data->input_dev;
unsigned int id;
......@@ -163,16 +174,6 @@ static void mms114_process_mt(struct mms114_data *data, struct mms114_touch *tou
id = touch->id - 1;
x = touch->x_lo | touch->x_hi << 8;
y = touch->y_lo | touch->y_hi << 8;
if (x > pdata->x_size || y > pdata->y_size) {
dev_dbg(&client->dev,
"Wrong touch coordinates (%d, %d)\n", x, y);
return;
}
if (pdata->x_invert)
x = pdata->x_size - x;
if (pdata->y_invert)
y = pdata->y_size - y;
dev_dbg(&client->dev,
"id: %d, type: %d, pressed: %d, x: %d, y: %d, width: %d, strength: %d\n",
......@@ -183,9 +184,8 @@ static void mms114_process_mt(struct mms114_data *data, struct mms114_touch *tou
input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, touch->pressed);
if (touch->pressed) {
touchscreen_report_pos(input_dev, &data->props, x, y, true);
input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR, touch->width);
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, touch->strength);
}
}
......@@ -213,7 +213,7 @@ static irqreturn_t mms114_interrupt(int irq, void *dev_id)
touch_size = packet_size / MMS114_PACKET_NUM;
error = __mms114_read_reg(data, MMS114_INFOMATION, packet_size,
error = __mms114_read_reg(data, MMS114_INFORMATION, packet_size,
(u8 *)touch);
if (error < 0)
goto out;
......@@ -249,21 +249,40 @@ static int mms114_get_version(struct mms114_data *data)
{
struct device *dev = &data->client->dev;
u8 buf[6];
int group;
int error;
error = __mms114_read_reg(data, MMS114_TSP_REV, 6, buf);
if (error < 0)
return error;
switch (data->type) {
case TYPE_MMS152:
error = __mms114_read_reg(data, MMS152_FW_REV, 3, buf);
if (error)
return error;
group = i2c_smbus_read_byte_data(data->client,
MMS152_COMPAT_GROUP);
if (group < 0)
return group;
dev_info(dev, "TSP FW Rev: bootloader 0x%x / core 0x%x / config 0x%x, Compat group: %c\n",
buf[0], buf[1], buf[2], group);
break;
case TYPE_MMS114:
error = __mms114_read_reg(data, MMS114_TSP_REV, 6, buf);
if (error)
return error;
dev_info(dev, "TSP Rev: 0x%x, HW Rev: 0x%x, Firmware Ver: 0x%x\n",
buf[0], buf[1], buf[3]);
dev_info(dev, "TSP Rev: 0x%x, HW Rev: 0x%x, Firmware Ver: 0x%x\n",
buf[0], buf[1], buf[3]);
break;
}
return 0;
}
static int mms114_setup_regs(struct mms114_data *data)
{
const struct mms114_platform_data *pdata = data->pdata;
const struct touchscreen_properties *props = &data->props;
int val;
int error;
......@@ -271,36 +290,40 @@ static int mms114_setup_regs(struct mms114_data *data)
if (error < 0)
return error;
/* MMS152 has no configuration or power on registers */
if (data->type == TYPE_MMS152)
return 0;
error = mms114_set_active(data, true);
if (error < 0)
return error;
val = (pdata->x_size >> 8) & 0xf;
val |= ((pdata->y_size >> 8) & 0xf) << 4;
val = (props->max_x >> 8) & 0xf;
val |= ((props->max_y >> 8) & 0xf) << 4;
error = mms114_write_reg(data, MMS114_XY_RESOLUTION_H, val);
if (error < 0)
return error;
val = pdata->x_size & 0xff;
val = props->max_x & 0xff;
error = mms114_write_reg(data, MMS114_X_RESOLUTION, val);
if (error < 0)
return error;
val = pdata->y_size & 0xff;
val = props->max_x & 0xff;
error = mms114_write_reg(data, MMS114_Y_RESOLUTION, val);
if (error < 0)
return error;
if (pdata->contact_threshold) {
if (data->contact_threshold) {
error = mms114_write_reg(data, MMS114_CONTACT_THRESHOLD,
pdata->contact_threshold);
data->contact_threshold);
if (error < 0)
return error;
}
if (pdata->moving_threshold) {
if (data->moving_threshold) {
error = mms114_write_reg(data, MMS114_MOVING_THRESHOLD,
pdata->moving_threshold);
data->moving_threshold);
if (error < 0)
return error;
}
......@@ -326,7 +349,7 @@ static int mms114_start(struct mms114_data *data)
return error;
}
mdelay(MMS114_POWERON_DELAY);
msleep(MMS114_POWERON_DELAY);
error = mms114_setup_regs(data);
if (error < 0) {
......@@ -335,9 +358,6 @@ static int mms114_start(struct mms114_data *data)
return error;
}
if (data->pdata->cfg_pin)
data->pdata->cfg_pin(true);
enable_irq(client->irq);
return 0;
......@@ -350,9 +370,6 @@ static void mms114_stop(struct mms114_data *data)
disable_irq(client->irq);
if (data->pdata->cfg_pin)
data->pdata->cfg_pin(false);
error = regulator_disable(data->io_reg);
if (error)
dev_warn(&client->dev, "Failed to disable vdd: %d\n", error);
......@@ -376,67 +393,44 @@ static void mms114_input_close(struct input_dev *dev)
mms114_stop(data);
}
#ifdef CONFIG_OF
static struct mms114_platform_data *mms114_parse_dt(struct device *dev)
static int mms114_parse_legacy_bindings(struct mms114_data *data)
{
struct mms114_platform_data *pdata;
struct device_node *np = dev->of_node;
if (!np)
return NULL;
struct device *dev = &data->client->dev;
struct touchscreen_properties *props = &data->props;
pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata) {
dev_err(dev, "failed to allocate platform data\n");
return NULL;
if (device_property_read_u32(dev, "x-size", &props->max_x)) {
dev_dbg(dev, "failed to get legacy x-size property\n");
return -EINVAL;
}
if (of_property_read_u32(np, "x-size", &pdata->x_size)) {
dev_err(dev, "failed to get x-size property\n");
return NULL;
if (device_property_read_u32(dev, "y-size", &props->max_y)) {
dev_dbg(dev, "failed to get legacy y-size property\n");
return -EINVAL;
}
if (of_property_read_u32(np, "y-size", &pdata->y_size)) {
dev_err(dev, "failed to get y-size property\n");
return NULL;
}
device_property_read_u32(dev, "contact-threshold",
&data->contact_threshold);
device_property_read_u32(dev, "moving-threshold",
&data->moving_threshold);
of_property_read_u32(np, "contact-threshold",
&pdata->contact_threshold);
of_property_read_u32(np, "moving-threshold",
&pdata->moving_threshold);
if (device_property_read_bool(dev, "x-invert"))
props->invert_x = true;
if (device_property_read_bool(dev, "y-invert"))
props->invert_y = true;
if (of_find_property(np, "x-invert", NULL))
pdata->x_invert = true;
if (of_find_property(np, "y-invert", NULL))
pdata->y_invert = true;
props->swap_x_y = false;
return pdata;
}
#else
static inline struct mms114_platform_data *mms114_parse_dt(struct device *dev)
{
return NULL;
return 0;
}
#endif
static int mms114_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
const struct mms114_platform_data *pdata;
struct mms114_data *data;
struct input_dev *input_dev;
const void *match_data;
int error;
pdata = dev_get_platdata(&client->dev);
if (!pdata)
pdata = mms114_parse_dt(&client->dev);
if (!pdata) {
dev_err(&client->dev, "Need platform data\n");
return -EINVAL;
}
if (!i2c_check_functionality(client->adapter,
I2C_FUNC_PROTOCOL_MANGLING)) {
dev_err(&client->dev,
......@@ -454,29 +448,63 @@ static int mms114_probe(struct i2c_client *client,
data->client = client;
data->input_dev = input_dev;
data->pdata = pdata;
input_dev->name = "MELFAS MMS114 Touchscreen";
/* FIXME: switch to device_get_match_data() when available */
match_data = of_device_get_match_data(&client->dev);
if (!match_data)
return -EINVAL;
data->type = (enum mms_type)match_data;
input_set_capability(input_dev, EV_ABS, ABS_MT_POSITION_X);
input_set_capability(input_dev, EV_ABS, ABS_MT_POSITION_Y);
input_set_abs_params(input_dev, ABS_MT_PRESSURE, 0, 255, 0, 0);
input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR,
0, MMS114_MAX_AREA, 0, 0);
touchscreen_parse_properties(input_dev, true, &data->props);
if (!data->props.max_x || !data->props.max_y) {
dev_dbg(&client->dev,
"missing X/Y size properties, trying legacy bindings\n");
error = mms114_parse_legacy_bindings(data);
if (error)
return error;
input_set_abs_params(input_dev, ABS_MT_POSITION_X,
0, data->props.max_x, 0, 0);
input_set_abs_params(input_dev, ABS_MT_POSITION_Y,
0, data->props.max_y, 0, 0);
}
if (data->type == TYPE_MMS114) {
/*
* The firmware handles movement and pressure fuzz, so
* don't duplicate that in software.
*/
data->moving_threshold = input_abs_get_fuzz(input_dev,
ABS_MT_POSITION_X);
data->contact_threshold = input_abs_get_fuzz(input_dev,
ABS_MT_PRESSURE);
input_abs_set_fuzz(input_dev, ABS_MT_POSITION_X, 0);
input_abs_set_fuzz(input_dev, ABS_MT_POSITION_Y, 0);
input_abs_set_fuzz(input_dev, ABS_MT_PRESSURE, 0);
}
input_dev->name = devm_kasprintf(&client->dev, GFP_KERNEL,
"MELFAS MMS%d Touchscreen",
data->type);
if (!input_dev->name)
return -ENOMEM;
input_dev->id.bustype = BUS_I2C;
input_dev->dev.parent = &client->dev;
input_dev->open = mms114_input_open;
input_dev->close = mms114_input_close;
__set_bit(EV_ABS, input_dev->evbit);
__set_bit(EV_KEY, input_dev->evbit);
__set_bit(BTN_TOUCH, input_dev->keybit);
input_set_abs_params(input_dev, ABS_X, 0, data->pdata->x_size, 0, 0);
input_set_abs_params(input_dev, ABS_Y, 0, data->pdata->y_size, 0, 0);
/* For multi touch */
input_mt_init_slots(input_dev, MMS114_MAX_TOUCH, 0);
input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR,
0, MMS114_MAX_AREA, 0, 0);
input_set_abs_params(input_dev, ABS_MT_POSITION_X,
0, data->pdata->x_size, 0, 0);
input_set_abs_params(input_dev, ABS_MT_POSITION_Y,
0, data->pdata->y_size, 0, 0);
input_set_abs_params(input_dev, ABS_MT_PRESSURE, 0, 255, 0, 0);
error = input_mt_init_slots(input_dev, MMS114_MAX_TOUCH,
INPUT_MT_DIRECT);
if (error)
return error;
input_set_drvdata(input_dev, data);
i2c_set_clientdata(client, data);
......@@ -497,9 +525,9 @@ static int mms114_probe(struct i2c_client *client,
return error;
}
error = devm_request_threaded_irq(&client->dev, client->irq, NULL,
mms114_interrupt, IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
dev_name(&client->dev), data);
error = devm_request_threaded_irq(&client->dev, client->irq,
NULL, mms114_interrupt, IRQF_ONESHOT,
dev_name(&client->dev), data);
if (error) {
dev_err(&client->dev, "Failed to register interrupt\n");
return error;
......@@ -569,7 +597,13 @@ MODULE_DEVICE_TABLE(i2c, mms114_id);
#ifdef CONFIG_OF
static const struct of_device_id mms114_dt_match[] = {
{ .compatible = "melfas,mms114" },
{
.compatible = "melfas,mms114",
.data = (void *)TYPE_MMS114,
}, {
.compatible = "melfas,mms152",
.data = (void *)TYPE_MMS152,
},
{ }
};
MODULE_DEVICE_TABLE(of, mms114_dt_match);
......
......@@ -752,13 +752,20 @@ static int raydium_i2c_fw_update(struct raydium_data *ts)
{
struct i2c_client *client = ts->client;
const struct firmware *fw = NULL;
const char *fw_file = "raydium.fw";
char *fw_file;
int error;
fw_file = kasprintf(GFP_KERNEL, "raydium_%#04x.fw",
le32_to_cpu(ts->info.hw_ver));
if (!fw_file)
return -ENOMEM;
dev_dbg(&client->dev, "firmware name: %s\n", fw_file);
error = request_firmware(&fw, fw_file, &client->dev);
if (error) {
dev_err(&client->dev, "Unable to open firmware %s\n", fw_file);
return error;
goto out_free_fw_file;
}
disable_irq(client->irq);
......@@ -787,6 +794,9 @@ static int raydium_i2c_fw_update(struct raydium_data *ts)
release_firmware(fw);
out_free_fw_file:
kfree(fw_file);
return error;
}
......
......@@ -56,7 +56,7 @@
#define SILEAD_POINT_Y_MSB_OFF 0x01
#define SILEAD_POINT_X_OFF 0x02
#define SILEAD_POINT_X_MSB_OFF 0x03
#define SILEAD_TOUCH_ID_MASK 0xF0
#define SILEAD_EXTRA_DATA_MASK 0xF0
#define SILEAD_CMD_SLEEP_MIN 10000
#define SILEAD_CMD_SLEEP_MAX 20000
......@@ -109,6 +109,9 @@ static int silead_ts_request_input_dev(struct silead_ts_data *data)
INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED |
INPUT_MT_TRACK);
if (device_property_read_bool(dev, "silead,home-button"))
input_set_capability(data->input, EV_KEY, KEY_LEFTMETA);
data->input->name = SILEAD_TS_NAME;
data->input->phys = "input/ts";
data->input->id.bustype = BUS_I2C;
......@@ -139,7 +142,8 @@ static void silead_ts_read_data(struct i2c_client *client)
struct input_dev *input = data->input;
struct device *dev = &client->dev;
u8 *bufp, buf[SILEAD_TS_DATA_LEN];
int touch_nr, error, i;
int touch_nr, softbutton, error, i;
bool softbutton_pressed = false;
error = i2c_smbus_read_i2c_block_data(client, SILEAD_REG_DATA,
SILEAD_TS_DATA_LEN, buf);
......@@ -148,21 +152,40 @@ static void silead_ts_read_data(struct i2c_client *client)
return;
}
touch_nr = buf[0];
if (touch_nr > data->max_fingers) {
if (buf[0] > data->max_fingers) {
dev_warn(dev, "More touches reported then supported %d > %d\n",
touch_nr, data->max_fingers);
touch_nr = data->max_fingers;
buf[0], data->max_fingers);
buf[0] = data->max_fingers;
}
touch_nr = 0;
bufp = buf + SILEAD_POINT_DATA_LEN;
for (i = 0; i < touch_nr; i++, bufp += SILEAD_POINT_DATA_LEN) {
/* Bits 4-7 are the touch id */
data->id[i] = (bufp[SILEAD_POINT_X_MSB_OFF] &
SILEAD_TOUCH_ID_MASK) >> 4;
touchscreen_set_mt_pos(&data->pos[i], &data->prop,
for (i = 0; i < buf[0]; i++, bufp += SILEAD_POINT_DATA_LEN) {
softbutton = (bufp[SILEAD_POINT_Y_MSB_OFF] &
SILEAD_EXTRA_DATA_MASK) >> 4;
if (softbutton) {
/*
* For now only respond to softbutton == 0x01, some
* tablets *without* a capacative button send 0x04
* when crossing the edges of the screen.
*/
if (softbutton == 0x01)
softbutton_pressed = true;
continue;
}
/*
* Bits 4-7 are the touch id, note not all models have
* hardware touch ids so atm we don't use these.
*/
data->id[touch_nr] = (bufp[SILEAD_POINT_X_MSB_OFF] &
SILEAD_EXTRA_DATA_MASK) >> 4;
touchscreen_set_mt_pos(&data->pos[touch_nr], &data->prop,
get_unaligned_le16(&bufp[SILEAD_POINT_X_OFF]) & 0xfff,
get_unaligned_le16(&bufp[SILEAD_POINT_Y_OFF]) & 0xfff);
touch_nr++;
}
input_mt_assign_slots(input, data->slots, data->pos, touch_nr, 0);
......@@ -178,6 +201,7 @@ static void silead_ts_read_data(struct i2c_client *client)
}
input_mt_sync_frame(input);
input_report_key(input, KEY_LEFTMETA, softbutton_pressed);
input_sync(input);
}
......
......@@ -682,6 +682,14 @@ static int stmfts_probe(struct i2c_client *client,
input_set_drvdata(sdata->input, sdata);
/*
* stmfts_power_on expects interrupt to be disabled, but
* at this point the device is still off and I do not trust
* the status of the irq line that can generate some spurious
* interrupts. To be on the safe side it's better to not enable
* the interrupts during their request.
*/
irq_set_status_flags(client->irq, IRQ_NOAUTOEN);
err = devm_request_threaded_irq(&client->dev, client->irq,
NULL, stmfts_irq_handler,
IRQF_ONESHOT,
......@@ -689,9 +697,6 @@ static int stmfts_probe(struct i2c_client *client,
if (err)
return err;
/* stmfts_power_on expects interrupt to be disabled */
disable_irq(client->irq);
dev_dbg(&client->dev, "initializing ST-Microelectronics FTS...\n");
err = stmfts_power_on(sdata);
......
......@@ -55,11 +55,6 @@
#include <linux/usb/input.h>
#include <linux/hid.h>
#define DRIVER_VERSION "v0.6"
#define DRIVER_AUTHOR "Daniel Ritz <daniel.ritz@gmx.ch>"
#define DRIVER_DESC "USB Touchscreen Driver"
static bool swap_xy;
module_param(swap_xy, bool, 0644);
MODULE_PARM_DESC(swap_xy, "If set X and Y axes are swapped.");
......@@ -1763,8 +1758,8 @@ static struct usb_driver usbtouch_driver = {
module_usb_driver(usbtouch_driver);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_AUTHOR("Daniel Ritz <daniel.ritz@gmx.ch>");
MODULE_DESCRIPTION("USB Touchscreen Driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("touchkitusb");
......
......@@ -23,7 +23,6 @@
#include <asm/unaligned.h>
#define WDT87XX_NAME "wdt87xx_i2c"
#define WDT87XX_DRV_VER "0.9.8"
#define WDT87XX_FW_NAME "wdt87xx_fw.bin"
#define WDT87XX_CFG_NAME "wdt87xx_cfg.bin"
......@@ -1183,5 +1182,4 @@ module_i2c_driver(wdt87xx_driver);
MODULE_AUTHOR("HN Chen <hn.chen@weidahitech.com>");
MODULE_DESCRIPTION("WeidaHiTech WDT87XX Touchscreen driver");
MODULE_VERSION(WDT87XX_DRV_VER);
MODULE_LICENSE("GPL");
......@@ -144,12 +144,12 @@ struct hil_mlc {
hil_packet ipacket[16];
hil_packet imatch;
int icount;
struct timeval instart;
suseconds_t intimeout;
unsigned long instart;
unsigned long intimeout;
int ddi; /* Last operational device id */
int lcv; /* LCV to throttle loops */
struct timeval lcv_tv; /* Time loop was started */
time64_t lcv_time; /* Time loop was started */
int di_map[7]; /* Maps below items to live devs */
struct hil_mlc_devinfo di[HIL_MLC_DEVMEM];
......
......@@ -281,7 +281,7 @@ typedef struct {
hp_sdc_transaction *tq[HP_SDC_QUEUE_LEN]; /* All pending read/writes */
int rcurr, rqty; /* Current read transact in process */
struct timeval rtv; /* Time when current read started */
ktime_t rtime; /* Time when current read started */
int wcurr; /* Current write transact in process */
int dev_err; /* carries status from registration */
......
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _INPUT_GPIO_TILT_H
#define _INPUT_GPIO_TILT_H
/**
* struct gpio_tilt_axis - Axis used by the tilt switch
* @axis: Constant describing the axis, e.g. ABS_X
* @min: minimum value for abs_param
* @max: maximum value for abs_param
* @fuzz: fuzz value for abs_param
* @flat: flat value for abs_param
*/
struct gpio_tilt_axis {
int axis;
int min;
int max;
int fuzz;
int flat;
};
/**
* struct gpio_tilt_state - state description
* @gpios: bitfield of gpio target-states for the value
* @axes: array containing the axes settings for the gpio state
* The array indizes must correspond to the axes defined
* in platform_data
*
* This structure describes a supported axis settings
* and the necessary gpio-state which represent it.
*
* The n-th bit in the bitfield describes the state of the n-th GPIO
* from the gpios-array defined in gpio_regulator_config below.
*/
struct gpio_tilt_state {
int gpios;
int *axes;
};
/**
* struct gpio_tilt_platform_data
* @gpios: Array containing the gpios determining the tilt state
* @nr_gpios: Number of gpios
* @axes: Array of gpio_tilt_axis descriptions
* @nr_axes: Number of axes
* @states: Array of gpio_tilt_state entries describing
* the gpio state for specific tilts
* @nr_states: Number of states available
* @debounce_interval: debounce ticks interval in msecs
* @poll_interval: polling interval in msecs - for polling driver only
* @enable: callback to enable the tilt switch
* @disable: callback to disable the tilt switch
*
* This structure contains gpio-tilt-switch configuration
* information that must be passed by platform code to the
* gpio-tilt input driver.
*/
struct gpio_tilt_platform_data {
struct gpio *gpios;
int nr_gpios;
struct gpio_tilt_axis *axes;
int nr_axes;
struct gpio_tilt_state *states;
int nr_states;
int debounce_interval;
unsigned int poll_interval;
int (*enable)(struct device *dev);
void (*disable)(struct device *dev);
};
#endif
/*
* Copyright (C) 2012 Samsung Electronics Co.Ltd
* Author: Joonyoung Shim <jy0922.shim@samsung.com>
*
* 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 Foundationr
*/
#ifndef __LINUX_MMS114_H
#define __LINUX_MMS114_H
struct mms114_platform_data {
unsigned int x_size;
unsigned int y_size;
unsigned int contact_threshold;
unsigned int moving_threshold;
bool x_invert;
bool y_invert;
void (*cfg_pin)(bool);
};
#endif /* __LINUX_MMS114_H */
......@@ -21,10 +21,21 @@
/*
* The event structure itself
* Note that __USE_TIME_BITS64 is defined by libc based on
* application's request to use 64 bit time_t.
*/
struct input_event {
#if (__BITS_PER_LONG != 32 || !defined(__USE_TIME_BITS64)) && !defined(__KERNEL)
struct timeval time;
#define input_event_sec time.tv_sec
#define input_event_usec time.tv_usec
#else
__kernel_ulong_t __sec;
__kernel_ulong_t __usec;
#define input_event_sec __sec
#define input_event_usec __usec
#endif
__u16 type;
__u16 code;
__s32 value;
......
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