forked from Minki/linux
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 ...
This commit is contained in:
commit
eea43ed86f
@ -1,17 +1,23 @@
|
||||
* 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.
|
||||
|
@ -1,103 +0,0 @@
|
||||
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");
|
||||
|
||||
|
@ -1,210 +0,0 @@
|
||||
/*
|
||||
* 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;
|
||||
|
@ -175,49 +175,6 @@ static const u8 bl_exit[] = { 0x00, 0xff, 0xa5, 0x00, 0x01, 0x02, 0x03, 0x04,
|
||||
#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
|
||||
#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)
|
||||
|
@ -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)
|
||||
{
|
||||
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,6 +310,7 @@ static void rmi_f03_remove(struct rmi_function *fn)
|
||||
{
|
||||
struct f03_data *f03 = dev_get_drvdata(&fn->dev);
|
||||
|
||||
if (f03->serio_registered)
|
||||
serio_unregister_port(f03->serio);
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -1,357 +0,0 @@
|
||||
/*
|
||||
* 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 @@ out:
|
||||
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,
|
||||
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 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);
|
||||
|
@ -1,436 +0,0 @@
|
||||
/*
|
||||
* 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 @@ err_out:
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -675,53 +647,6 @@ static int goodix_i2c_test(struct i2c_client *client)
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
* goodix_request_input_dev - Allocate, populate and register the input device
|
||||
*
|
||||
* @ts: our goodix_ts_data pointer
|
||||
*
|
||||
* Must be called during probe
|
||||
*/
|
||||
static int goodix_request_input_dev(struct goodix_ts_data *ts)
|
||||
{
|
||||
int error;
|
||||
|
||||
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;
|
||||
ts->input_dev->id.vendor = 0x0416;
|
||||
ts->input_dev->id.product = ts->id;
|
||||
ts->input_dev->id.version = ts->version;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* goodix_configure_dev - Finish device initialization
|
||||
*
|
||||
@ -736,18 +661,68 @@ static int goodix_configure_dev(struct goodix_ts_data *ts)
|
||||
{
|
||||
int error;
|
||||
|
||||
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");
|
||||
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;
|
||||
}
|
||||
|
||||
ts->input_dev->name = "Goodix Capacitive TouchScreen";
|
||||
ts->input_dev->phys = "input/ts";
|
||||
ts->input_dev->id.bustype = BUS_I2C;
|
||||
ts->input_dev->id.vendor = 0x0416;
|
||||
ts->input_dev->id.product = ts->id;
|
||||
ts->input_dev->id.version = ts->version;
|
||||
|
||||
/* Capacitive Windows/Home button on some devices */
|
||||
input_set_capability(ts->input_dev, EV_KEY, KEY_LEFTMETA);
|
||||
|
||||
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);
|
||||
|
||||
/* Read configuration and apply touchscreen parameters */
|
||||
goodix_read_config(ts);
|
||||
|
||||
error = goodix_request_input_dev(ts);
|
||||
if (error)
|
||||
/* Try overriding touchscreen parameters via device properties */
|
||||
touchscreen_parse_properties(ts->input_dev, true, &ts->prop);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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 = 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;
|
||||
|
||||
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 < 0)
|
||||
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]);
|
||||
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;
|
||||
struct device *dev = &data->client->dev;
|
||||
struct touchscreen_properties *props = &data->props;
|
||||
|
||||
if (!np)
|
||||
return NULL;
|
||||
|
||||
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;
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
static inline struct mms114_platform_data *mms114_parse_dt(struct device *dev)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
#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,8 +525,8 @@ 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,
|
||||
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");
|
||||
@ -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 @@ out_enable_irq:
|
||||
|
||||
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 */
|
||||
|
@ -1,74 +0,0 @@
|
||||
/* 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
|
@ -1,24 +0,0 @@
|
||||
/*
|
||||
* 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;
|
||||
|
Loading…
Reference in New Issue
Block a user