Commit 718749d5 authored by Linus Torvalds's avatar Linus Torvalds

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

Pull input updates from Dmitry Torokhov:
 "The first round of updates for the input subsystem.

  A few new drivers (power button handler for AXP20x PMIC, tps65218
  power button driver, sun4i keys driver, regulator haptic driver, NI
  Ettus Research USRP E3x0 button, Alwinner A10/A20 PS/2 controller).

  Updates to Synaptics and ALPS touchpad drivers (with more to come
  later), brand new Focaltech PS/2 support, update to Cypress driver to
  handle Gen5 (in addition to Gen3) devices, and number of other fixups
  to various drivers as well as input core"

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input: (54 commits)
  Input: elan_i2c - fix wrong %p extension
  Input: evdev - do not queue SYN_DROPPED if queue is empty
  Input: gscps2 - fix MODULE_DEVICE_TABLE invocation
  Input: synaptics - use dmax in input_mt_assign_slots
  Input: pxa27x_keypad - remove unnecessary ARM includes
  Input: ti_am335x_tsc - replace delta filtering with median filtering
  ARM: dts: AM335x: Make charge delay a DT parameter for TSC
  Input: ti_am335x_tsc - read charge delay from DT
  Input: ti_am335x_tsc - remove udelay in interrupt handler
  Input: ti_am335x_tsc - interchange touchscreen and ADC steps
  Input: MT - add support for balanced slot assignment
  Input: drv2667 - remove wrong and unneeded drv2667-haptics modalias
  Input: drv260x - remove wrong and unneeded drv260x-haptics modalias
  Input: cap11xx - remove wrong and unneeded cap11xx modalias
  Input: sun4i-ts - add support for touchpanel controller on A31
  Input: serio - add support for Alwinner A10/A20 PS/2 controller
  Input: gtco - use sign_extend32() for sign extension
  Input: elan_i2c - verify firmware signature applying it
  Input: elantech - remove stale comment from Kconfig
  Input: cyapa - off by one in cyapa_update_fw_store()
  ...
parents e0c84537 4ba24fef
What: /sys/class/input/input(x)/device/startup
Date: March 2014
Contact: Carlo Caione <carlo@caione.org>
Description: Startup time in us. Board is powered on if the button is pressed
for more than <startup_time>
What: /sys/class/input/input(x)/device/shutdown
Date: March 2014
Contact: Carlo Caione <carlo@caione.org>
Description: Shutdown time in us. Board is powered off if the button is pressed
for more than <shutdown_time>
National Instruments Ettus Research USRP E3x0 button driver
This module is part of the NI Ettus Research USRP E3x0 SDR.
This module provides a simple power button event via two interrupts.
Required properties:
- compatible: should be one of the following
- "ettus,e3x0-button": For devices such as the NI Ettus Research USRP E3x0
- interrupt-parent:
- a phandle to the interrupt controller that it is attached to.
- interrupts: should be one of the following
- <0 30 1>, <0 31 1>: For devices such as the NI Ettus Research USRP E3x0
- interrupt-names: should be one of the following
- "press", "release": For devices such as the NI Ettus Research USRP E3x0
Note: Interrupt numbers might vary depending on the FPGA configuration.
Example:
button {
compatible = "ettus,e3x0-button";
interrupt-parent = <&intc>;
interrupts = <0 30 1>, <0 31 1>;
interrupt-names = "press", "release";
}
* Regulator Haptic Device Tree Bindings
Required Properties:
- compatible : Should be "regulator-haptic"
- haptic-supply : Power supply to the haptic motor.
[*] refer Documentation/devicetree/bindings/regulator/regulator.txt
- max-microvolt : The maximum voltage value supplied to the haptic motor.
[The unit of the voltage is a micro]
- min-microvolt : The minimum voltage value supplied to the haptic motor.
[The unit of the voltage is a micro]
Example:
haptics {
compatible = "regulator-haptic";
haptic-supply = <&motor_regulator>;
max-microvolt = <2700000>;
min-microvolt = <1100000>;
};
Allwinner sun4i low res adc attached tablet keys
------------------------------------------------
Required properties:
- compatible: "allwinner,sun4i-a10-lradc-keys"
- reg: mmio address range of the chip
- interrupts: interrupt to which the chip is connected
- vref-supply: powersupply for the lradc reference voltage
Each key is represented as a sub-node of "allwinner,sun4i-a10-lradc-keys":
Required subnode-properties:
- label: Descriptive name of the key.
- linux,code: Keycode to emit.
- channel: Channel this key is attached to, mut be 0 or 1.
- voltage: Voltage in µV at lradc input when this key is pressed.
Example:
#include <dt-bindings/input/input.h>
lradc: lradc@01c22800 {
compatible = "allwinner,sun4i-a10-lradc-keys";
reg = <0x01c22800 0x100>;
interrupts = <31>;
vref-supply = <&reg_vcc3v0>;
button@191 {
label = "Volume Up";
linux,code = <KEY_VOLUMEUP>;
channel = <0>;
voltage = <191274>;
};
button@392 {
label = "Volume Down";
linux,code = <KEY_VOLUMEDOWN>;
channel = <0>;
voltage = <392644>;
};
button@601 {
label = "Menu";
linux,code = <KEY_MENU>;
channel = <0>;
voltage = <601151>;
};
button@795 {
label = "Enter";
linux,code = <KEY_ENTER>;
channel = <0>;
voltage = <795090>;
};
button@987 {
label = "Home";
linux,code = <KEY_HOMEPAGE>;
channel = <0>;
voltage = <987387>;
};
};
......@@ -2,9 +2,10 @@ sun4i resistive touchscreen controller
--------------------------------------
Required properties:
- compatible: "allwinner,sun4i-a10-ts"
- compatible: "allwinner,sun4i-a10-ts" or "allwinner,sun6i-a31-ts"
- reg: mmio address range of the chip
- interrupts: interrupt to which the chip is connected
- #thermal-sensor-cells: shall be 0
Optional properties:
- allwinner,ts-attached: boolean indicating that an actual touchscreen is
......@@ -17,4 +18,5 @@ Example:
reg = <0x01c25000 0x100>;
interrupts = <29>;
allwinner,ts-attached;
#thermal-sensor-cells = <0>;
};
......@@ -28,6 +28,20 @@ Required properties:
ti,adc-channels: List of analog inputs available for ADC.
AIN0 = 0, AIN1 = 1 and so on till AIN7 = 7.
Optional properties:
- child "tsc"
ti,charge-delay: Length of touch screen charge delay step in terms of
ADC clock cycles. Charge delay value should be large
in order to avoid false pen-up events. This value
effects the overall sampling speed, hence need to be
kept as low as possible, while avoiding false pen-up
event. Start from a lower value, say 0x400, and
increase value until false pen-up events are avoided.
The pen-up detection happens immediately after the
charge step, so this does in fact function as a
hardware knob for adjusting the amount of "settling
time".
Example:
tscadc: tscadc@44e0d000 {
compatible = "ti,am3359-tscadc";
......@@ -36,6 +50,7 @@ Example:
ti,x-plate-resistance = <200>;
ti,coordiante-readouts = <5>;
ti,wire-config = <0x00 0x11 0x22 0x33>;
ti,charge-delay = <0x400>;
};
adc {
......
Texas Instruments TPS65218 power button
This driver provides a simple power button event via an Interrupt.
Required properties:
- compatible: should be "ti,tps65218-pwrbutton"
- interrupts: should be one of the following
- <3 IRQ_TYPE_EDGE_BOTH>: For controllers compatible with tps65218
Example:
&tps {
power-button {
compatible = "ti,tps65218-pwrbutton";
interrupts = <3 IRQ_TYPE_EDGE_BOTH>;
};
};
* Device tree bindings for Allwinner A10, A20 PS2 host controller
A20 PS2 is dual role controller (PS2 host and PS2 device). These bindings are
for PS2 A10/A20 host controller. IBM compliant IBM PS2 and AT-compatible keyboard
and mouse can be connected.
Required properties:
- reg : Offset and length of the register set for the device.
- compatible : Should be as of the following:
- "allwinner,sun4i-a10-ps2"
- interrupts : The interrupt line connected to the PS2.
- clocks : The gate clk connected to the PS2.
Example:
ps20: ps2@0x01c2a000 {
compatible = "allwinner,sun4i-a10-ps2";
reg = <0x01c2a000 0x400>;
interrupts = <0 62 4>;
clocks = <&apb1_gates 6>;
status = "disabled";
};
......@@ -54,6 +54,7 @@ epcos EPCOS AG
epfl Ecole Polytechnique Fédérale de Lausanne
epson Seiko Epson Corp.
est ESTeem Wireless Modems
ettus NI Ettus Research
eukrea Eukréa Electromatique
everest Everest Semiconductor Co. Ltd.
excito Excito
......
......@@ -3479,6 +3479,14 @@ M: "Maciej W. Rozycki" <macro@linux-mips.org>
S: Maintained
F: drivers/tty/serial/dz.*
E3X0 POWER BUTTON DRIVER
M: Moritz Fischer <moritz.fischer@ettus.com>
L: usrp-users@lists.ettus.com
W: http://www.ettus.com
S: Supported
F: drivers/input/misc/e3x0-button.c
F: Documentation/devicetree/bindings/input/e3x0-button.txt
E4000 MEDIA DRIVER
M: Antti Palosaari <crope@iki.fi>
L: linux-media@vger.kernel.org
......@@ -9281,6 +9289,13 @@ F: arch/m68k/sun3*/
F: arch/m68k/include/asm/sun3*
F: drivers/net/ethernet/i825xx/sun3*
SUN4I LOW RES ADC ATTACHED TABLET KEYS DRIVER
M: Hans de Goede <hdegoede@redhat.com>
L: linux-input@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/input/sun4i-lradc-keys.txt
F: drivers/input/keyboard/sun4i-lradc-keys.c
SUNDANCE NETWORK DRIVER
M: Denis Kirjanov <kda@linux-powerpc.org>
L: netdev@vger.kernel.org
......
......@@ -648,6 +648,7 @@ tsc {
ti,x-plate-resistance = <200>;
ti,coordinate-readouts = <5>;
ti,wire-config = <0x00 0x11 0x22 0x33>;
ti,charge-delay = <0x400>;
};
adc {
......
......@@ -86,19 +86,18 @@ static void tiadc_step_config(struct iio_dev *indio_dev)
{
struct tiadc_device *adc_dev = iio_priv(indio_dev);
unsigned int stepconfig;
int i, steps;
int i, steps = 0;
/*
* There are 16 configurable steps and 8 analog input
* lines available which are shared between Touchscreen and ADC.
*
* Steps backwards i.e. from 16 towards 0 are used by ADC
* Steps forwards i.e. from 0 towards 16 are used by ADC
* depending on number of input lines needed.
* Channel would represent which analog input
* needs to be given to ADC to digitalize data.
*/
steps = TOTAL_STEPS - adc_dev->channels;
if (iio_buffer_enabled(indio_dev))
stepconfig = STEPCONFIG_AVG_16 | STEPCONFIG_FIFO1
| STEPCONFIG_MODE_SWCNT;
......
......@@ -62,26 +62,6 @@ struct evdev_client {
struct input_event buffer[];
};
static int evdev_set_clk_type(struct evdev_client *client, unsigned int clkid)
{
switch (clkid) {
case CLOCK_REALTIME:
client->clk_type = EV_CLK_REAL;
break;
case CLOCK_MONOTONIC:
client->clk_type = EV_CLK_MONO;
break;
case CLOCK_BOOTTIME:
client->clk_type = EV_CLK_BOOT;
break;
default:
return -EINVAL;
}
return 0;
}
/* flush queued events of type @type, caller must hold client->buffer_lock */
static void __evdev_flush_queue(struct evdev_client *client, unsigned int type)
{
......@@ -128,10 +108,8 @@ static void __evdev_flush_queue(struct evdev_client *client, unsigned int type)
client->head = head;
}
/* queue SYN_DROPPED event */
static void evdev_queue_syn_dropped(struct evdev_client *client)
static void __evdev_queue_syn_dropped(struct evdev_client *client)
{
unsigned long flags;
struct input_event ev;
ktime_t time;
......@@ -146,8 +124,6 @@ static void evdev_queue_syn_dropped(struct evdev_client *client)
ev.code = SYN_DROPPED;
ev.value = 0;
spin_lock_irqsave(&client->buffer_lock, flags);
client->buffer[client->head++] = ev;
client->head &= client->bufsize - 1;
......@@ -156,8 +132,53 @@ static void evdev_queue_syn_dropped(struct evdev_client *client)
client->tail = (client->head - 1) & (client->bufsize - 1);
client->packet_head = client->tail;
}
}
static void evdev_queue_syn_dropped(struct evdev_client *client)
{
unsigned long flags;
spin_lock_irqsave(&client->buffer_lock, flags);
__evdev_queue_syn_dropped(client);
spin_unlock_irqrestore(&client->buffer_lock, flags);
}
static int evdev_set_clk_type(struct evdev_client *client, unsigned int clkid)
{
unsigned long flags;
if (client->clk_type == clkid)
return 0;
switch (clkid) {
case CLOCK_REALTIME:
client->clk_type = EV_CLK_REAL;
break;
case CLOCK_MONOTONIC:
client->clk_type = EV_CLK_MONO;
break;
case CLOCK_BOOTTIME:
client->clk_type = EV_CLK_BOOT;
break;
default:
return -EINVAL;
}
/*
* Flush pending events and queue SYN_DROPPED event,
* but only if the queue is not empty.
*/
spin_lock_irqsave(&client->buffer_lock, flags);
if (client->head != client->tail) {
client->packet_head = client->head = client->tail;
__evdev_queue_syn_dropped(client);
}
spin_unlock_irqrestore(&client->buffer_lock, flags);
return 0;
}
static void __pass_event(struct evdev_client *client,
......
......@@ -293,7 +293,7 @@ void input_mt_sync_frame(struct input_dev *dev)
}
EXPORT_SYMBOL(input_mt_sync_frame);
static int adjust_dual(int *begin, int step, int *end, int eq)
static int adjust_dual(int *begin, int step, int *end, int eq, int mu)
{
int f, *p, s, c;
......@@ -311,9 +311,10 @@ static int adjust_dual(int *begin, int step, int *end, int eq)
s = *p;
c = (f + s + 1) / 2;
if (c == 0 || (c > 0 && !eq))
if (c == 0 || (c > mu && (!eq || mu > 0)))
return 0;
if (s < 0)
/* Improve convergence for positive matrices by penalizing overcovers */
if (s < 0 && mu <= 0)
c *= 2;
for (p = begin; p != end; p += step)
......@@ -322,23 +323,24 @@ static int adjust_dual(int *begin, int step, int *end, int eq)
return (c < s && s <= 0) || (f >= 0 && f < c);
}
static void find_reduced_matrix(int *w, int nr, int nc, int nrc)
static void find_reduced_matrix(int *w, int nr, int nc, int nrc, int mu)
{
int i, k, sum;
for (k = 0; k < nrc; k++) {
for (i = 0; i < nr; i++)
adjust_dual(w + i, nr, w + i + nrc, nr <= nc);
adjust_dual(w + i, nr, w + i + nrc, nr <= nc, mu);
sum = 0;
for (i = 0; i < nrc; i += nr)
sum += adjust_dual(w + i, 1, w + i + nr, nc <= nr);
sum += adjust_dual(w + i, 1, w + i + nr, nc <= nr, mu);
if (!sum)
break;
}
}
static int input_mt_set_matrix(struct input_mt *mt,
const struct input_mt_pos *pos, int num_pos)
const struct input_mt_pos *pos, int num_pos,
int mu)
{
const struct input_mt_pos *p;
struct input_mt_slot *s;
......@@ -352,7 +354,7 @@ static int input_mt_set_matrix(struct input_mt *mt,
y = input_mt_get_value(s, ABS_MT_POSITION_Y);
for (p = pos; p != pos + num_pos; p++) {
int dx = x - p->x, dy = y - p->y;
*w++ = dx * dx + dy * dy;
*w++ = dx * dx + dy * dy - mu;
}
}
......@@ -393,17 +395,24 @@ static void input_mt_set_slots(struct input_mt *mt,
* @slots: the slot assignment to be filled
* @pos: the position array to match
* @num_pos: number of positions
* @dmax: maximum ABS_MT_POSITION displacement (zero for infinite)
*
* Performs a best match against the current contacts and returns
* the slot assignment list. New contacts are assigned to unused
* slots.
*
* The assignments are balanced so that all coordinate displacements are
* below the euclidian distance dmax. If no such assignment can be found,
* some contacts are assigned to unused slots.
*
* Returns zero on success, or negative error in case of failure.
*/
int input_mt_assign_slots(struct input_dev *dev, int *slots,
const struct input_mt_pos *pos, int num_pos)
const struct input_mt_pos *pos, int num_pos,
int dmax)
{
struct input_mt *mt = dev->mt;
int mu = 2 * dmax * dmax;
int nrc;
if (!mt || !mt->red)
......@@ -413,8 +422,8 @@ int input_mt_assign_slots(struct input_dev *dev, int *slots,
if (num_pos < 1)
return 0;
nrc = input_mt_set_matrix(mt, pos, num_pos);
find_reduced_matrix(mt->red, num_pos, nrc / num_pos, nrc);
nrc = input_mt_set_matrix(mt, pos, num_pos, mu);
find_reduced_matrix(mt->red, num_pos, nrc / num_pos, nrc, mu);
input_mt_set_slots(mt, slots, num_pos);
return 0;
......
......@@ -100,23 +100,24 @@ static unsigned int input_to_handler(struct input_handle *handle,
struct input_value *end = vals;
struct input_value *v;
for (v = vals; v != vals + count; v++) {
if (handler->filter &&
handler->filter(handle, v->type, v->code, v->value))
continue;
if (end != v)
*end = *v;
end++;
if (handler->filter) {
for (v = vals; v != vals + count; v++) {
if (handler->filter(handle, v->type, v->code, v->value))
continue;
if (end != v)
*end = *v;
end++;
}
count = end - vals;
}
count = end - vals;
if (!count)
return 0;
if (handler->events)
handler->events(handle, vals, count);
else if (handler->event)
for (v = vals; v != end; v++)
for (v = vals; v != vals + count; v++)
handler->event(handle, v->type, v->code, v->value);
return count;
......@@ -143,8 +144,11 @@ static void input_pass_values(struct input_dev *dev,
count = input_to_handler(handle, vals, count);
} else {
list_for_each_entry_rcu(handle, &dev->h_list, d_node)
if (handle->open)
if (handle->open) {
count = input_to_handler(handle, vals, count);
if (!count)
break;
}
}
rcu_read_unlock();
......@@ -152,12 +156,14 @@ static void input_pass_values(struct input_dev *dev,
add_input_randomness(vals->type, vals->code, vals->value);
/* trigger auto repeat for key events */
for (v = vals; v != vals + count; v++) {
if (v->type == EV_KEY && v->value != 2) {
if (v->value)
input_start_autorepeat(dev, v->code);
else
input_stop_autorepeat(dev);
if (test_bit(EV_REP, dev->evbit) && test_bit(EV_KEY, dev->evbit)) {
for (v = vals; v != vals + count; v++) {
if (v->type == EV_KEY && v->value != 2) {
if (v->value)
input_start_autorepeat(dev, v->code);
else
input_stop_autorepeat(dev);
}
}
}
}
......
......@@ -568,6 +568,16 @@ config KEYBOARD_STMPE
To compile this driver as a module, choose M here: the module will be
called stmpe-keypad.
config KEYBOARD_SUN4I_LRADC
tristate "Allwinner sun4i low res adc attached tablet keys support"
depends on ARCH_SUNXI
help
This selects support for the Allwinner low res adc attached tablet
keys found on Allwinner sunxi SoCs.
To compile this driver as a module, choose M here: the
module will be called sun4i-lradc-keys.
config KEYBOARD_DAVINCI
tristate "TI DaVinci Key Scan"
depends on ARCH_DAVINCI_DM365
......
......@@ -53,6 +53,7 @@ obj-$(CONFIG_KEYBOARD_SPEAR) += spear-keyboard.o
obj-$(CONFIG_KEYBOARD_STMPE) += stmpe-keypad.o
obj-$(CONFIG_KEYBOARD_STOWAWAY) += stowaway.o
obj-$(CONFIG_KEYBOARD_ST_KEYSCAN) += st-keyscan.o
obj-$(CONFIG_KEYBOARD_SUN4I_LRADC) += sun4i-lradc-keys.o
obj-$(CONFIG_KEYBOARD_SUNKBD) += sunkbd.o
obj-$(CONFIG_KEYBOARD_TC3589X) += tc3589x-keypad.o
obj-$(CONFIG_KEYBOARD_TEGRA) += tegra-kbc.o
......
......@@ -170,7 +170,7 @@ static unsigned char atakbd_keycode[0x72] = { /* American layout */
[93] = KEY_KPASTERISK,
[94] = KEY_KPPLUS,
[95] = KEY_HELP,
[96] = KEY_BACKSLASH, /* FIXME: '<' */
[96] = KEY_102ND,
[97] = KEY_KPASTERISK, /* FIXME */
[98] = KEY_KPSLASH,
[99] = KEY_KPLEFTPAREN,
......
......@@ -370,7 +370,6 @@ static struct i2c_driver cap11xx_i2c_driver = {
module_i2c_driver(cap11xx_i2c_driver);
MODULE_ALIAS("platform:cap11xx");
MODULE_DESCRIPTION("Microchip CAP11XX driver");
MODULE_AUTHOR("Daniel Mack <linux@zonque.org>");
MODULE_LICENSE("GPL v2");
......@@ -448,8 +448,7 @@ static int imx_keypad_probe(struct platform_device *pdev)
return -ENOMEM;
}
keypad = devm_kzalloc(&pdev->dev, sizeof(struct imx_keypad),
GFP_KERNEL);
keypad = devm_kzalloc(&pdev->dev, sizeof(*keypad), GFP_KERNEL);
if (!keypad) {
dev_err(&pdev->dev, "not enough memory for driver data\n");
return -ENOMEM;
......
......@@ -20,6 +20,7 @@
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/input.h>
#include <linux/io.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
......@@ -28,10 +29,6 @@
#include <linux/slab.h>
#include <linux/of.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
#include <mach/hardware.h>
#include <linux/platform_data/keypad-pxa27x.h>
/*
* Keypad Controller registers
......
/*
* Allwinner sun4i low res adc attached tablet keys driver
*
* Copyright (C) 2014 Hans de Goede <hdegoede@redhat.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
/*
* Allwinnner sunxi SoCs have a lradc which is specifically designed to have
* various (tablet) keys (ie home, back, search, etc). attached to it using
* a resistor network. This driver is for the keys on such boards.
*
* There are 2 channels, currently this driver only supports channel 0 since
* there are no boards known to use channel 1.
*/
#include <linux/err.h>
#include <linux/init.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#define LRADC_CTRL 0x00
#define LRADC_INTC 0x04
#define LRADC_INTS 0x08
#define LRADC_DATA0 0x0c
#define LRADC_DATA1 0x10
/* LRADC_CTRL bits */
#define FIRST_CONVERT_DLY(x) ((x) << 24) /* 8 bits */
#define CHAN_SELECT(x) ((x) << 22) /* 2 bits */
#define CONTINUE_TIME_SEL(x) ((x) << 16) /* 4 bits */
#define KEY_MODE_SEL(x) ((x) << 12) /* 2 bits */
#define LEVELA_B_CNT(x) ((x) << 8) /* 4 bits */
#define HOLD_EN(x) ((x) << 6)
#define LEVELB_VOL(x) ((x) << 4) /* 2 bits */
#define SAMPLE_RATE(x) ((x) << 2) /* 2 bits */
#define ENABLE(x) ((x) << 0)
/* LRADC_INTC and LRADC_INTS bits */
#define CHAN1_KEYUP_IRQ BIT(12)
#define CHAN1_ALRDY_HOLD_IRQ BIT(11)
#define CHAN1_HOLD_IRQ BIT(10)
#define CHAN1_KEYDOWN_IRQ BIT(9)
#define CHAN1_DATA_IRQ BIT(8)
#define CHAN0_KEYUP_IRQ BIT(4)
#define CHAN0_ALRDY_HOLD_IRQ BIT(3)
#define CHAN0_HOLD_IRQ BIT(2)
#define CHAN0_KEYDOWN_IRQ BIT(1)
#define CHAN0_DATA_IRQ BIT(0)
struct sun4i_lradc_keymap {
u32 voltage;
u32 keycode;
};
struct sun4i_lradc_data {
struct device *dev;
struct input_dev *input;
void __iomem *base;
struct regulator *vref_supply;
struct sun4i_lradc_keymap *chan0_map;
u32 chan0_map_count;
u32 chan0_keycode;
u32 vref;
};
static irqreturn_t sun4i_lradc_irq(int irq, void *dev_id)
{
struct sun4i_lradc_data *lradc = dev_id;
u32 i, ints, val, voltage, diff, keycode = 0, closest = 0xffffffff;
ints = readl(lradc->base + LRADC_INTS);
/*
* lradc supports only one keypress at a time, release does not give
* any info as to which key was released, so we cache the keycode.
*/
if (ints & CHAN0_KEYUP_IRQ) {
input_report_key(lradc->input, lradc->chan0_keycode, 0);
lradc->chan0_keycode = 0;
}
if ((ints & CHAN0_KEYDOWN_IRQ) && lradc->chan0_keycode == 0) {
val = readl(lradc->base + LRADC_DATA0) & 0x3f;
voltage = val * lradc->vref / 63;
for (i = 0; i < lradc->chan0_map_count; i++) {
diff = abs(lradc->chan0_map[i].voltage - voltage);
if (diff < closest) {
closest = diff;
keycode = lradc->chan0_map[i].keycode;
}
}
lradc->chan0_keycode = keycode;
input_report_key(lradc->input, lradc->chan0_keycode, 1);
}
input_sync(lradc->input);
writel(ints, lradc->base + LRADC_INTS);
return IRQ_HANDLED;
}
static int sun4i_lradc_open(struct input_dev *dev)
{
struct sun4i_lradc_data *lradc = input_get_drvdata(dev);
int error;
error = regulator_enable(lradc->vref_supply);
if (error)
return error;
/* lradc Vref internally is divided by 2/3 */
lradc->vref = regulator_get_voltage(lradc->vref_supply) * 2 / 3;
/*
* Set sample time to 4 ms / 250 Hz. Wait 2 * 4 ms for key to
* stabilize on press, wait (1 + 1) * 4 ms for key release
*/
writel(FIRST_CONVERT_DLY(2) | LEVELA_B_CNT(1) | HOLD_EN(1) |
SAMPLE_RATE(0) | ENABLE(1), lradc->base + LRADC_CTRL);
writel(CHAN0_KEYUP_IRQ | CHAN0_KEYDOWN_IRQ, lradc->base + LRADC_INTC);
return 0;
}
static void sun4i_lradc_close(struct input_dev *dev)
{
struct sun4i_lradc_data *lradc = input_get_drvdata(dev);
/* Disable lradc, leave other settings unchanged */
writel(FIRST_CONVERT_DLY(2) | LEVELA_B_CNT(1) | HOLD_EN(1) |
SAMPLE_RATE(2), lradc->base + LRADC_CTRL);
writel(0, lradc->base + LRADC_INTC);
regulator_disable(lradc->vref_supply);
}
static int sun4i_lradc_load_dt_keymap(struct device *dev,
struct sun4i_lradc_data *lradc)
{
struct device_node *np, *pp;
int i;
int error;
np = dev->of_node;
if (!np)
return -EINVAL;
lradc->chan0_map_count = of_get_child_count(np);
if (lradc->chan0_map_count == 0) {
dev_err(dev, "keymap is missing in device tree\n");
return -EINVAL;
}
lradc->chan0_map = devm_kmalloc_array(dev, lradc->chan0_map_count,
sizeof(struct sun4i_lradc_keymap),
GFP_KERNEL);
if (!lradc->chan0_map)
return -ENOMEM;
i = 0;
for_each_child_of_node(np, pp) {
struct sun4i_lradc_keymap *map = &lradc->chan0_map[i];
u32 channel;
error = of_property_read_u32(pp, "channel", &channel);
if (error || channel != 0) {
dev_err(dev, "%s: Inval channel prop\n", pp->name);
return -EINVAL;
}
error = of_property_read_u32(pp, "voltage", &map->voltage);
if (error) {
dev_err(dev, "%s: Inval voltage prop\n", pp->name);
return -EINVAL;
}
error = of_property_read_u32(pp, "linux,code", &map->keycode);
if (error) {
dev_err(dev, "%s: Inval linux,code prop\n", pp->name);
return -EINVAL;
}
i++;
}
return 0;
}
static int sun4i_lradc_probe(struct platform_device *pdev)
{
struct sun4i_lradc_data *lradc;
struct device *dev = &pdev->dev;
int i;
int error;
lradc = devm_kzalloc(dev, sizeof(struct sun4i_lradc_data), GFP_KERNEL);
if (!lradc)
return -ENOMEM;
error = sun4i_lradc_load_dt_keymap(dev, lradc);
if (error)
return error;
lradc->vref_supply = devm_regulator_get(dev, "vref");
if (IS_ERR(lradc->vref_supply))
return PTR_ERR(lradc->vref_supply);
lradc->dev = dev;
lradc->input = devm_input_allocate_device(dev);
if (!lradc->input)
return -ENOMEM;
lradc->input->name = pdev->name;
lradc->input->phys = "sun4i_lradc/input0";
lradc->input->open = sun4i_lradc_open;
lradc->input->close = sun4i_lradc_close;
lradc->input->id.bustype = BUS_HOST;
lradc->input->id.vendor = 0x0001;
lradc->input->id.product = 0x0001;
lradc->input->id.version = 0x0100;
__set_bit(EV_KEY, lradc->input->evbit);
for (i = 0; i < lradc->chan0_map_count; i++)
__set_bit(lradc->chan0_map[i].keycode, lradc->input->keybit);
input_set_drvdata(lradc->input, lradc);
lradc->base = devm_ioremap_resource(dev,
platform_get_resource(pdev, IORESOURCE_MEM, 0));
if (IS_ERR(lradc->base))
return PTR_ERR(lradc->base);
error = devm_request_irq(dev, platform_get_irq(pdev, 0),
sun4i_lradc_irq, 0,
"sun4i-a10-lradc-keys", lradc);
if (error)
return error;
error = input_register_device(lradc->input);
if (error)
return error;
platform_set_drvdata(pdev, lradc);
return 0;
}
static const struct of_device_id sun4i_lradc_of_match[] = {
{ .compatible = "allwinner,sun4i-a10-lradc-keys", },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, sun4i_lradc_of_match);
static struct platform_driver sun4i_lradc_driver = {
.driver = {
.name = "sun4i-a10-lradc-keys",
.of_match_table = of_match_ptr(sun4i_lradc_of_match),
},
.probe = sun4i_lradc_probe,
};
module_platform_driver(sun4i_lradc_driver);
MODULE_DESCRIPTION("Allwinner sun4i low res adc attached tablet keys driver");
MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
MODULE_LICENSE("GPL");
......@@ -93,6 +93,16 @@ config INPUT_BMA150
To compile this driver as a module, choose M here: the
module will be called bma150.
config INPUT_E3X0_BUTTON
tristate "NI Ettus Research USRP E3x0 Button support."
default n
help
Say Y here to enable support for the NI Ettus Research
USRP E3x0 Button.
To compile this driver as a module, choose M here: the
module will be called e3x0_button.
config INPUT_PCSPKR
tristate "PC Speaker support"
depends on PCSPKR_PLATFORM
......@@ -394,6 +404,18 @@ config INPUT_CM109
To compile this driver as a module, choose M here: the module will be
called cm109.
config INPUT_REGULATOR_HAPTIC
tristate "Regulator haptics support"
depends on REGULATOR
select INPUT_FF_MEMLESS
help
This option enables device driver support for the haptic controlled
by a regulator. This driver supports ff-memless interface
from input framework.
To compile this driver as a module, choose M here: the
module will be called regulator-haptic.
config INPUT_RETU_PWRBUTTON
tristate "Retu Power button Driver"
depends on MFD_RETU
......@@ -404,6 +426,27 @@ config INPUT_RETU_PWRBUTTON
To compile this driver as a module, choose M here. The module will
be called retu-pwrbutton.
config INPUT_TPS65218_PWRBUTTON
tristate "TPS65218 Power button driver"
depends on MFD_TPS65218
help
Say Y here if you want to enable power buttong reporting for
the TPS65218 Power Management IC device.
To compile this driver as a module, choose M here. The module will
be called tps65218-pwrbutton.
config INPUT_AXP20X_PEK
tristate "X-Powers AXP20X power button driver"
depends on MFD_AXP20X
help
Say Y here if you want to enable power key reporting via the
AXP20X PMIC.
To compile this driver as a module, choose M here. The module will
be called axp20x-pek.
config INPUT_TWL4030_PWRBUTTON
tristate "TWL4030 Power button Driver"
depends on TWL4030_CORE
......
......@@ -26,6 +26,7 @@ obj-$(CONFIG_INPUT_COBALT_BTNS) += cobalt_btns.o
obj-$(CONFIG_INPUT_DA9052_ONKEY) += da9052_onkey.o
obj-$(CONFIG_INPUT_DA9055_ONKEY) += da9055_onkey.o
obj-$(CONFIG_INPUT_DM355EVM) += dm355evm_keys.o
obj-$(CONFIG_INPUT_E3X0_BUTTON) += e3x0-button.o
obj-$(CONFIG_INPUT_DRV260X_HAPTICS) += drv260x.o
obj-$(CONFIG_INPUT_DRV2667_HAPTICS) += drv2667.o
obj-$(CONFIG_INPUT_GP2A) += gp2ap002a00f.o
......@@ -53,12 +54,15 @@ obj-$(CONFIG_INPUT_PMIC8XXX_PWRKEY) += pmic8xxx-pwrkey.o
obj-$(CONFIG_INPUT_POWERMATE) += powermate.o
obj-$(CONFIG_INPUT_PWM_BEEPER) += pwm-beeper.o
obj-$(CONFIG_INPUT_RB532_BUTTON) += rb532_button.o
obj-$(CONFIG_INPUT_REGULATOR_HAPTIC) += regulator-haptic.o
obj-$(CONFIG_INPUT_RETU_PWRBUTTON) += retu-pwrbutton.o
obj-$(CONFIG_INPUT_AXP20X_PEK) += axp20x-pek.o
obj-$(CONFIG_INPUT_GPIO_ROTARY_ENCODER) += rotary_encoder.o
obj-$(CONFIG_INPUT_SGI_BTNS) += sgi_btns.o
obj-$(CONFIG_INPUT_SIRFSOC_ONKEY) += sirfsoc-onkey.o
obj-$(CONFIG_INPUT_SOC_BUTTON_ARRAY) += soc_button_array.o
obj-$(CONFIG_INPUT_SPARCSPKR) += sparcspkr.o
obj-$(CONFIG_INPUT_TPS65218_PWRBUTTON) += tps65218-pwrbutton.o
obj-$(CONFIG_INPUT_TWL4030_PWRBUTTON) += twl4030-pwrbutton.o
obj-$(CONFIG_INPUT_TWL4030_VIBRA) += twl4030-vibra.o
obj-$(CONFIG_INPUT_TWL6040_VIBRA) += twl6040-vibra.o
......
/*
* axp20x power button driver.
*
* Copyright (C) 2013 Carlo Caione <carlo@caione.org>
*
* This file is subject to the terms and conditions of the GNU General
* Public License. See the file "COPYING" in the main directory of this
* archive for more details.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/errno.h>
#include <linux/irq.h>
#include <linux/init.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/mfd/axp20x.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/slab.h>
#define AXP20X_PEK_STARTUP_MASK (0xc0)
#define AXP20X_PEK_SHUTDOWN_MASK (0x03)
struct axp20x_pek {
struct axp20x_dev *axp20x;
struct input_dev *input;
int irq_dbr;
int irq_dbf;
};
struct axp20x_time {
unsigned int time;
unsigned int idx;
};
static const struct axp20x_time startup_time[] = {
{ .time = 128, .idx = 0 },
{ .time = 1000, .idx = 2 },
{ .time = 3000, .idx = 1 },
{ .time = 2000, .idx = 3 },
};
static const struct axp20x_time shutdown_time[] = {
{ .time = 4000, .idx = 0 },
{ .time = 6000, .idx = 1 },
{ .time = 8000, .idx = 2 },
{ .time = 10000, .idx = 3 },
};
struct axp20x_pek_ext_attr {
const struct axp20x_time *p_time;
unsigned int mask;
};
static struct axp20x_pek_ext_attr axp20x_pek_startup_ext_attr = {
.p_time = startup_time,
.mask = AXP20X_PEK_STARTUP_MASK,
};
static struct axp20x_pek_ext_attr axp20x_pek_shutdown_ext_attr = {
.p_time = shutdown_time,
.mask = AXP20X_PEK_SHUTDOWN_MASK,
};
static struct axp20x_pek_ext_attr *get_axp_ext_attr(struct device_attribute *attr)
{
return container_of(attr, struct dev_ext_attribute, attr)->var;
}
static ssize_t axp20x_show_ext_attr(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct axp20x_pek *axp20x_pek = dev_get_drvdata(dev);
struct axp20x_pek_ext_attr *axp20x_ea = get_axp_ext_attr(attr);
unsigned int val;
int ret, i;
ret = regmap_read(axp20x_pek->axp20x->regmap, AXP20X_PEK_KEY, &val);
if (ret != 0)
return ret;
val &= axp20x_ea->mask;
val >>= ffs(axp20x_ea->mask) - 1;
for (i = 0; i < 4; i++)
if (val == axp20x_ea->p_time[i].idx)
val = axp20x_ea->p_time[i].time;
return sprintf(buf, "%u\n", val);
}
static ssize_t axp20x_store_ext_attr(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct axp20x_pek *axp20x_pek = dev_get_drvdata(dev);
struct axp20x_pek_ext_attr *axp20x_ea = get_axp_ext_attr(attr);
char val_str[20];
size_t len;
int ret, i;
unsigned int val, idx = 0;
unsigned int best_err = UINT_MAX;
val_str[sizeof(val_str) - 1] = '\0';
strncpy(val_str, buf, sizeof(val_str) - 1);
len = strlen(val_str);
if (len && val_str[len - 1] == '\n')
val_str[len - 1] = '\0';
ret = kstrtouint(val_str, 10, &val);
if (ret)
return ret;
for (i = 3; i >= 0; i--) {
unsigned int err;
err = abs(axp20x_ea->p_time[i].time - val);
if (err < best_err) {
best_err = err;
idx = axp20x_ea->p_time[i].idx;
}
if (!err)
break;
}
idx <<= ffs(axp20x_ea->mask) - 1;
ret = regmap_update_bits(axp20x_pek->axp20x->regmap,
AXP20X_PEK_KEY,
axp20x_ea->mask, idx);
if (ret != 0)
return -EINVAL;
return count;
}
static struct dev_ext_attribute axp20x_dev_attr_startup = {
.attr = __ATTR(startup, 0644, axp20x_show_ext_attr, axp20x_store_ext_attr),
.var = &axp20x_pek_startup_ext_attr,
};
static struct dev_ext_attribute axp20x_dev_attr_shutdown = {
.attr = __ATTR(shutdown, 0644, axp20x_show_ext_attr, axp20x_store_ext_attr),
.var = &axp20x_pek_shutdown_ext_attr,
};
static struct attribute *axp20x_attributes[] = {
&axp20x_dev_attr_startup.attr.attr,
&axp20x_dev_attr_shutdown.attr.attr,
NULL,
};
static const struct attribute_group axp20x_attribute_group = {
.attrs = axp20x_attributes,
};
static irqreturn_t axp20x_pek_irq(int irq, void *pwr)
{
struct input_dev *idev = pwr;
struct axp20x_pek *axp20x_pek = input_get_drvdata(idev);
if (irq == axp20x_pek->irq_dbr)
input_report_key(idev, KEY_POWER, true);
else if (irq == axp20x_pek->irq_dbf)
input_report_key(idev, KEY_POWER, false);
input_sync(idev);
return IRQ_HANDLED;
}
static void axp20x_remove_sysfs_group(void *_data)
{
struct device *dev = _data;
sysfs_remove_group(&dev->kobj, &axp20x_attribute_group);
}
static int axp20x_pek_probe(struct platform_device *pdev)
{
struct axp20x_pek *axp20x_pek;
struct axp20x_dev *axp20x;
struct input_dev *idev;
int error;
axp20x_pek = devm_kzalloc(&pdev->dev, sizeof(struct axp20x_pek),
GFP_KERNEL);
if (!axp20x_pek)
return -ENOMEM;
axp20x_pek->axp20x = dev_get_drvdata(pdev->dev.parent);
axp20x = axp20x_pek->axp20x;
axp20x_pek->irq_dbr = platform_get_irq_byname(pdev, "PEK_DBR");
if (axp20x_pek->irq_dbr < 0) {
dev_err(&pdev->dev, "No IRQ for PEK_DBR, error=%d\n",
axp20x_pek->irq_dbr);
return axp20x_pek->irq_dbr;
}
axp20x_pek->irq_dbr = regmap_irq_get_virq(axp20x->regmap_irqc,
axp20x_pek->irq_dbr);
axp20x_pek->irq_dbf = platform_get_irq_byname(pdev, "PEK_DBF");
if (axp20x_pek->irq_dbf < 0) {
dev_err(&pdev->dev, "No IRQ for PEK_DBF, error=%d\n",
axp20x_pek->irq_dbf);
return axp20x_pek->irq_dbf;
}
axp20x_pek->irq_dbf = regmap_irq_get_virq(axp20x->regmap_irqc,
axp20x_pek->irq_dbf);
axp20x_pek->input = devm_input_allocate_device(&pdev->dev);
if (!axp20x_pek->input)
return -ENOMEM;
idev = axp20x_pek->input;
idev->name = "axp20x-pek";
idev->phys = "m1kbd/input2";
idev->dev.parent = &pdev->dev;
input_set_capability(idev, EV_KEY, KEY_POWER);
input_set_drvdata(idev, axp20x_pek);
error = devm_request_any_context_irq(&pdev->dev, axp20x_pek->irq_dbr,
axp20x_pek_irq, 0,
"axp20x-pek-dbr", idev);
if (error < 0) {
dev_err(axp20x->dev, "Failed to request dbr IRQ#%d: %d\n",
axp20x_pek->irq_dbr, error);
return error;
}
error = devm_request_any_context_irq(&pdev->dev, axp20x_pek->irq_dbf,
axp20x_pek_irq, 0,
"axp20x-pek-dbf", idev);
if (error < 0) {
dev_err(axp20x->dev, "Failed to request dbf IRQ#%d: %d\n",
axp20x_pek->irq_dbf, error);
return error;
}
error = sysfs_create_group(&pdev->dev.kobj, &axp20x_attribute_group);
if (error) {
dev_err(axp20x->dev, "Failed to create sysfs attributes: %d\n",
error);
return error;
}
error = devm_add_action(&pdev->dev,
axp20x_remove_sysfs_group, &pdev->dev);
if (error) {
axp20x_remove_sysfs_group(&pdev->dev);
dev_err(&pdev->dev, "Failed to add sysfs cleanup action: %d\n",
error);
return error;
}
error = input_register_device(idev);
if (error) {
dev_err(axp20x->dev, "Can't register input device: %d\n",
error);
return error;
}
platform_set_drvdata(pdev, axp20x_pek);
return 0;
}
static struct platform_driver axp20x_pek_driver = {
.probe = axp20x_pek_probe,
.driver = {
.name = "axp20x-pek",
},
};
module_platform_driver(axp20x_pek_driver);
MODULE_DESCRIPTION("axp20x Power Button");
MODULE_AUTHOR("Carlo Caione <carlo@caione.org>");
MODULE_LICENSE("GPL");
......@@ -733,7 +733,6 @@ static struct i2c_driver drv260x_driver = {
};
module_i2c_driver(drv260x_driver);
MODULE_ALIAS("platform:drv260x-haptics");
MODULE_DESCRIPTION("TI DRV260x haptics driver");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Dan Murphy <dmurphy@ti.com>");
......@@ -492,7 +492,6 @@ static struct i2c_driver drv2667_driver = {
};
module_i2c_driver(drv2667_driver);
MODULE_ALIAS("platform:drv2667-haptics");
MODULE_DESCRIPTION("TI DRV2667 haptics driver");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Dan Murphy <dmurphy@ti.com>");
/*
* Copyright (c) 2014, National Instruments Corp. All rights reserved.
*
* Driver for NI Ettus Research USRP E3x0 Button Driver
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/of.h>
#include <linux/slab.h>
static irqreturn_t e3x0_button_release_handler(int irq, void *data)
{
struct input_dev *idev = data;
input_report_key(idev, KEY_POWER, 0);
input_sync(idev);
return IRQ_HANDLED;
}
static irqreturn_t e3x0_button_press_handler(int irq, void *data)
{
struct input_dev *idev = data;
input_report_key(idev, KEY_POWER, 1);
pm_wakeup_event(idev->dev.parent, 0);
input_sync(idev);
return IRQ_HANDLED;
}
static int __maybe_unused e3x0_button_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
if (device_may_wakeup(dev))
enable_irq_wake(platform_get_irq_byname(pdev, "press"));
return 0;
}
static int __maybe_unused e3x0_button_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
if (device_may_wakeup(dev))
disable_irq_wake(platform_get_irq_byname(pdev, "press"));
return 0;
}
static SIMPLE_DEV_PM_OPS(e3x0_button_pm_ops,
e3x0_button_suspend, e3x0_button_resume);
static int e3x0_button_probe(struct platform_device *pdev)
{
struct input_dev *input;
int irq_press, irq_release;
int error;
irq_press = platform_get_irq_byname(pdev, "press");
if (irq_press < 0) {
dev_err(&pdev->dev, "No IRQ for 'press', error=%d\n",
irq_press);
return irq_press;
}
irq_release = platform_get_irq_byname(pdev, "release");
if (irq_release < 0) {
dev_err(&pdev->dev, "No IRQ for 'release', error=%d\n",
irq_release);
return irq_release;
}
input = devm_input_allocate_device(&pdev->dev);
if (!input)
return -ENOMEM;
input->name = "NI Ettus Research USRP E3x0 Button Driver";
input->phys = "e3x0_button/input0";
input->dev.parent = &pdev->dev;
input_set_capability(input, EV_KEY, KEY_POWER);
error = devm_request_irq(&pdev->dev, irq_press,
e3x0_button_press_handler, 0,
"e3x0-button", input);
if (error) {
dev_err(&pdev->dev, "Failed to request 'press' IRQ#%d: %d\n",
irq_press, error);
return error;
}
error = devm_request_irq(&pdev->dev, irq_release,
e3x0_button_release_handler, 0,
"e3x0-button", input);
if (error) {
dev_err(&pdev->dev, "Failed to request 'release' IRQ#%d: %d\n",
irq_release, error);
return error;
}
error = input_register_device(input);
if (error) {
dev_err(&pdev->dev, "Can't register input device: %d\n", error);
return error;
}
platform_set_drvdata(pdev, input);
device_init_wakeup(&pdev->dev, 1);
return 0;
}
static int e3x0_button_remove(struct platform_device *pdev)
{
device_init_wakeup(&pdev->dev, 0);
return 0;
}
#ifdef CONFIG_OF
static const struct of_device_id e3x0_button_match[] = {
{ .compatible = "ettus,e3x0-button", },
{ }
};
MODULE_DEVICE_TABLE(of, e3x0_button_match);
#endif
static struct platform_driver e3x0_button_driver = {
.driver = {
.name = "e3x0-button",
.of_match_table = of_match_ptr(e3x0_button_match),
.pm = &e3x0_button_pm_ops,
},
.probe = e3x0_button_probe,
.remove = e3x0_button_remove,
};
module_platform_driver(e3x0_button_driver);
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Moritz Fischer <moritz.fischer@ettus.com>");
MODULE_DESCRIPTION("NI Ettus Research USRP E3x0 Button driver");
MODULE_ALIAS("platform:e3x0-button");
/*
* Regulator haptic driver
*
* Copyright (c) 2014 Samsung Electronics Co., Ltd.
* Author: Jaewon Kim <jaewon02.kim@samsung.com>
* Author: Hyunhee Kim <hyunhee.kim@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 Foundation.
*/
#include <linux/input.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_data/regulator-haptic.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#define MAX_MAGNITUDE_SHIFT 16
struct regulator_haptic {
struct device *dev;
struct input_dev *input_dev;
struct regulator *regulator;
struct work_struct work;
struct mutex mutex;
bool active;
bool suspended;
unsigned int max_volt;
unsigned int min_volt;
unsigned int magnitude;
};
static int regulator_haptic_toggle(struct regulator_haptic *haptic, bool on)
{
int error;
if (haptic->active != on) {
error = on ? regulator_enable(haptic->regulator) :
regulator_disable(haptic->regulator);
if (error) {
dev_err(haptic->dev,
"failed to switch regulator %s: %d\n",
on ? "on" : "off", error);
return error;
}
haptic->active = on;
}
return 0;
}
static int regulator_haptic_set_voltage(struct regulator_haptic *haptic,
unsigned int magnitude)
{
u64 volt_mag_multi;
unsigned int intensity;
int error;
volt_mag_multi = (u64)(haptic->max_volt - haptic->min_volt) * magnitude;
intensity = (unsigned int)(volt_mag_multi >> MAX_MAGNITUDE_SHIFT);
error = regulator_set_voltage(haptic->regulator,
intensity + haptic->min_volt,
haptic->max_volt);
if (error) {
dev_err(haptic->dev, "cannot set regulator voltage to %d: %d\n",
intensity + haptic->min_volt, error);
return error;
}
regulator_haptic_toggle(haptic, !!magnitude);
return 0;
}
static void regulator_haptic_work(struct work_struct *work)
{
struct regulator_haptic *haptic = container_of(work,
struct regulator_haptic, work);
mutex_lock(&haptic->mutex);
if (!haptic->suspended)
regulator_haptic_set_voltage(haptic, haptic->magnitude);
mutex_unlock(&haptic->mutex);
}
static int regulator_haptic_play_effect(struct input_dev *input, void *data,
struct ff_effect *effect)
{
struct regulator_haptic *haptic = input_get_drvdata(input);
haptic->magnitude = effect->u.rumble.strong_magnitude;
if (!haptic->magnitude)
haptic->magnitude = effect->u.rumble.weak_magnitude;
schedule_work(&haptic->work);
return 0;
}
static void regulator_haptic_close(struct input_dev *input)
{
struct regulator_haptic *haptic = input_get_drvdata(input);
cancel_work_sync(&haptic->work);
regulator_haptic_set_voltage(haptic, 0);
}
static int __maybe_unused
regulator_haptic_parse_dt(struct device *dev, struct regulator_haptic *haptic)
{
struct device_node *node;
int error;
node = dev->of_node;
if(!node) {
dev_err(dev, "Missing dveice tree data\n");
return -EINVAL;
}
error = of_property_read_u32(node, "max-microvolt", &haptic->max_volt);
if (error) {
dev_err(dev, "cannot parse max-microvolt\n");
return error;
}
error = of_property_read_u32(node, "min-microvolt", &haptic->min_volt);
if (error) {
dev_err(dev, "cannot parse min-microvolt\n");
return error;
}
return 0;
}
static int regulator_haptic_probe(struct platform_device *pdev)
{
const struct regulator_haptic_data *pdata = dev_get_platdata(&pdev->dev);
struct regulator_haptic *haptic;
struct input_dev *input_dev;
int error;
haptic = devm_kzalloc(&pdev->dev, sizeof(*haptic), GFP_KERNEL);
if (!haptic)
return -ENOMEM;
platform_set_drvdata(pdev, haptic);
haptic->dev = &pdev->dev;
mutex_init(&haptic->mutex);
INIT_WORK(&haptic->work, regulator_haptic_work);
if (pdata) {
haptic->max_volt = pdata->max_volt;
haptic->min_volt = pdata->min_volt;
} else if (IS_ENABLED(CONFIG_OF)) {
error = regulator_haptic_parse_dt(&pdev->dev, haptic);
if (error)
return error;
} else {
dev_err(&pdev->dev, "Missing platform data\n");
return -EINVAL;
}
haptic->regulator = devm_regulator_get_exclusive(&pdev->dev, "haptic");
if (IS_ERR(haptic->regulator)) {
dev_err(&pdev->dev, "failed to get regulator\n");
return PTR_ERR(haptic->regulator);
}
input_dev = devm_input_allocate_device(&pdev->dev);
if (!input_dev)
return -ENOMEM;
haptic->input_dev = input_dev;
haptic->input_dev->name = "regulator-haptic";
haptic->input_dev->dev.parent = &pdev->dev;
haptic->input_dev->close = regulator_haptic_close;
input_set_drvdata(haptic->input_dev, haptic);
input_set_capability(haptic->input_dev, EV_FF, FF_RUMBLE);
error = input_ff_create_memless(input_dev, NULL,
regulator_haptic_play_effect);
if (error) {
dev_err(&pdev->dev, "failed to create force-feedback\n");
return error;
}
error = input_register_device(haptic->input_dev);
if (error) {
dev_err(&pdev->dev, "failed to register input device\n");
return error;
}
return 0;
}
static int __maybe_unused regulator_haptic_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct regulator_haptic *haptic = platform_get_drvdata(pdev);
int error;
error = mutex_lock_interruptible(&haptic->mutex);
if (error)
return error;
regulator_haptic_set_voltage(haptic, 0);
haptic->suspended = true;
mutex_unlock(&haptic->mutex);
return 0;
}
static int __maybe_unused regulator_haptic_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct regulator_haptic *haptic = platform_get_drvdata(pdev);
unsigned int magnitude;
mutex_lock(&haptic->mutex);
haptic->suspended = false;
magnitude = ACCESS_ONCE(haptic->magnitude);
if (magnitude)
regulator_haptic_set_voltage(haptic, magnitude);
mutex_unlock(&haptic->mutex);
return 0;
}
static SIMPLE_DEV_PM_OPS(regulator_haptic_pm_ops,
regulator_haptic_suspend, regulator_haptic_resume);
static struct of_device_id regulator_haptic_dt_match[] = {
{ .compatible = "regulator-haptic" },
{ /* sentinel */ },
};
static struct platform_driver regulator_haptic_driver = {
.probe = regulator_haptic_probe,
.driver = {
.name = "regulator-haptic",
.of_match_table = regulator_haptic_dt_match,
.pm = &regulator_haptic_pm_ops,
},
};
module_platform_driver(regulator_haptic_driver);
MODULE_AUTHOR("Jaewon Kim <jaewon02.kim@samsung.com>");
MODULE_AUTHOR("Hyunhee Kim <hyunhee.kim@samsung.com>");
MODULE_DESCRIPTION("Regulator haptic driver");
MODULE_LICENSE("GPL");
/*
* Texas Instruments' TPS65218 Power Button Input Driver
*
* Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/
* Author: Felipe Balbi <balbi@ti.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.
*
* This program is distributed "as is" WITHOUT ANY WARRANTY of any
* kind, whether express or implied; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/init.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/mfd/tps65218.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
struct tps65218_pwrbutton {
struct device *dev;
struct tps65218 *tps;
struct input_dev *idev;
};
static irqreturn_t tps65218_pwr_irq(int irq, void *_pwr)
{
struct tps65218_pwrbutton *pwr = _pwr;
unsigned int reg;
int error;
error = tps65218_reg_read(pwr->tps, TPS65218_REG_STATUS, &reg);
if (error) {
dev_err(pwr->dev, "can't read register: %d\n", error);
goto out;
}
if (reg & TPS65218_STATUS_PB_STATE) {
input_report_key(pwr->idev, KEY_POWER, 1);
pm_wakeup_event(pwr->dev, 0);
} else {
input_report_key(pwr->idev, KEY_POWER, 0);
}
input_sync(pwr->idev);
out:
return IRQ_HANDLED;
}
static int tps65218_pwron_probe(struct platform_device *pdev)
{
struct tps65218 *tps = dev_get_drvdata(pdev->dev.parent);
struct device *dev = &pdev->dev;
struct tps65218_pwrbutton *pwr;
struct input_dev *idev;
int error;
int irq;
pwr = devm_kzalloc(dev, sizeof(*pwr), GFP_KERNEL);
if (!pwr)
return -ENOMEM;
idev = devm_input_allocate_device(dev);
if (!idev)
return -ENOMEM;
idev->name = "tps65218_pwrbutton";
idev->phys = "tps65218_pwrbutton/input0";
idev->dev.parent = dev;
idev->id.bustype = BUS_I2C;
input_set_capability(idev, EV_KEY, KEY_POWER);
pwr->tps = tps;
pwr->dev = dev;
pwr->idev = idev;
platform_set_drvdata(pdev, pwr);
device_init_wakeup(dev, true);
irq = platform_get_irq(pdev, 0);
error = devm_request_threaded_irq(dev, irq, NULL, tps65218_pwr_irq,
IRQF_TRIGGER_RISING |
IRQF_TRIGGER_FALLING |
IRQF_ONESHOT,
"tps65218-pwrbutton", pwr);
if (error) {
dev_err(dev, "failed to request IRQ #%d: %d\n",
irq, error);
return error;
}
error= input_register_device(idev);
if (error) {
dev_err(dev, "Can't register power button: %d\n", error);
return error;
}
return 0;
}
static struct of_device_id of_tps65218_pwr_match[] = {
{ .compatible = "ti,tps65218-pwrbutton" },
{ },
};
MODULE_DEVICE_TABLE(of, of_tps65218_pwr_match);
static struct platform_driver tps65218_pwron_driver = {
.probe = tps65218_pwron_probe,
.driver = {
.name = "tps65218_pwrbutton",
.of_match_table = of_tps65218_pwr_match,
},
};
module_platform_driver(tps65218_pwron_driver);
MODULE_DESCRIPTION("TPS65218 Power Button");
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
......@@ -105,19 +105,12 @@ config MOUSE_PS2_ELANTECH
Say Y here if you have an Elantech PS/2 touchpad connected
to your system.
Note that if you enable this driver you will need an updated
X.org Synaptics driver that does not require ABS_PRESSURE
reports from the touchpad (i.e. post 1.5.0 version). You can
grab a patch for the driver here:
http://userweb.kernel.org/~dtor/synaptics-no-abspressure.patch
If unsure, say N.
This driver exposes some configuration registers via sysfs
entries. For further information,
see <file:Documentation/input/elantech.txt>.
If unsure, say N.
config MOUSE_PS2_SENTELIC
bool "Sentelic Finger Sensing Pad PS/2 protocol extension"
depends on MOUSE_PS2
......@@ -146,6 +139,16 @@ config MOUSE_PS2_OLPC
If unsure, say N.
config MOUSE_PS2_FOCALTECH
bool "FocalTech PS/2 mouse protocol extension" if EXPERT
default y
depends on MOUSE_PS2
help
Say Y here if you have a FocalTech PS/2 TouchPad connected to
your system.
If unsure, say Y.
config MOUSE_SERIAL
tristate "Serial mouse"
select SERIO
......@@ -206,6 +209,7 @@ config MOUSE_BCM5974
config MOUSE_CYAPA
tristate "Cypress APA I2C Trackpad support"
depends on I2C
select CRC_ITU_T
help
This driver adds support for Cypress All Points Addressable (APA)
I2C Trackpads, including the ones used in 2012 Samsung Chromebooks.
......
......@@ -8,7 +8,7 @@ obj-$(CONFIG_MOUSE_AMIGA) += amimouse.o
obj-$(CONFIG_MOUSE_APPLETOUCH) += appletouch.o
obj-$(CONFIG_MOUSE_ATARI) += atarimouse.o
obj-$(CONFIG_MOUSE_BCM5974) += bcm5974.o
obj-$(CONFIG_MOUSE_CYAPA) += cyapa.o
obj-$(CONFIG_MOUSE_CYAPA) += cyapatp.o
obj-$(CONFIG_MOUSE_ELAN_I2C) += elan_i2c.o
obj-$(CONFIG_MOUSE_GPIO) += gpio_mouse.o
obj-$(CONFIG_MOUSE_INPORT) += inport.o
......@@ -24,6 +24,7 @@ obj-$(CONFIG_MOUSE_SYNAPTICS_I2C) += synaptics_i2c.o
obj-$(CONFIG_MOUSE_SYNAPTICS_USB) += synaptics_usb.o
obj-$(CONFIG_MOUSE_VSXXXAA) += vsxxxaa.o
cyapatp-objs := cyapa.o cyapa_gen3.o cyapa_gen5.o
psmouse-objs := psmouse-base.o synaptics.o focaltech.o
psmouse-$(CONFIG_MOUSE_PS2_ALPS) += alps.o
......
......@@ -435,7 +435,7 @@ static void alps_report_mt_data(struct psmouse *psmouse, int n)
struct alps_fields *f = &priv->f;
int i, slot[MAX_TOUCHES];
input_mt_assign_slots(dev, slot, f->mt, n);
input_mt_assign_slots(dev, slot, f->mt, n, 0);
for (i = 0; i < n; i++)
alps_set_slot(dev, slot[i], f->mt[i].x, f->mt[i].y);
......@@ -475,6 +475,13 @@ static void alps_process_trackstick_packet_v3(struct psmouse *psmouse)
struct input_dev *dev = priv->dev2;
int x, y, z, left, right, middle;
/* It should be a DualPoint when received trackstick packet */
if (!(priv->flags & ALPS_DUALPOINT)) {
psmouse_warn(psmouse,
"Rejected trackstick packet from non DualPoint device");
return;
}
/* Sanity check packet */
if (!(packet[0] & 0x40)) {
psmouse_dbg(psmouse, "Bad trackstick packet, discarding\n");
......@@ -699,7 +706,8 @@ static void alps_process_touchpad_packet_v3_v5(struct psmouse *psmouse)
alps_report_semi_mt_data(psmouse, fingers);
if (!(priv->quirks & ALPS_QUIRK_TRACKSTICK_BUTTONS)) {
if ((priv->flags & ALPS_DUALPOINT) &&
!(priv->quirks & ALPS_QUIRK_TRACKSTICK_BUTTONS)) {
input_report_key(dev2, BTN_LEFT, f->ts_left);
input_report_key(dev2, BTN_RIGHT, f->ts_right);
input_report_key(dev2, BTN_MIDDLE, f->ts_middle);
......@@ -743,8 +751,11 @@ static void alps_process_packet_v6(struct psmouse *psmouse)
*/
if (packet[5] == 0x7F) {
/* It should be a DualPoint when received Trackpoint packet */
if (!(priv->flags & ALPS_DUALPOINT))
if (!(priv->flags & ALPS_DUALPOINT)) {
psmouse_warn(psmouse,
"Rejected trackstick packet from non DualPoint device");
return;
}
/* Trackpoint packet */
x = packet[1] | ((packet[3] & 0x20) << 2);
......@@ -1026,6 +1037,13 @@ static void alps_process_trackstick_packet_v7(struct psmouse *psmouse)
struct input_dev *dev2 = priv->dev2;
int x, y, z, left, right, middle;
/* It should be a DualPoint when received trackstick packet */
if (!(priv->flags & ALPS_DUALPOINT)) {
psmouse_warn(psmouse,
"Rejected trackstick packet from non DualPoint device");
return;
}
/*
* b7 b6 b5 b4 b3 b2 b1 b0
* Byte0 0 1 0 0 1 0 0 0
......@@ -2443,14 +2461,24 @@ int alps_init(struct psmouse *psmouse)
dev1->keybit[BIT_WORD(BTN_MIDDLE)] |= BIT_MASK(BTN_MIDDLE);
}
if (priv->flags & ALPS_DUALPOINT) {
/*
* format of input device name is: "protocol vendor name"
* see function psmouse_switch_protocol() in psmouse-base.c
*/
dev2->name = "AlpsPS/2 ALPS DualPoint Stick";
dev2->id.product = PSMOUSE_ALPS;
dev2->id.version = priv->proto_version;
} else {
dev2->name = "PS/2 ALPS Mouse";
dev2->id.product = PSMOUSE_PS2;
dev2->id.version = 0x0000;
}
snprintf(priv->phys, sizeof(priv->phys), "%s/input1", psmouse->ps2dev.serio->phys);
dev2->phys = priv->phys;
dev2->name = (priv->flags & ALPS_DUALPOINT) ?
"DualPoint Stick" : "ALPS PS/2 Device";
dev2->id.bustype = BUS_I8042;
dev2->id.vendor = 0x0002;
dev2->id.product = PSMOUSE_ALPS;
dev2->id.version = 0x0000;
dev2->dev.parent = &psmouse->ps2dev.serio->dev;
dev2->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
......
......@@ -564,7 +564,7 @@ static int report_tp_state(struct bcm5974 *dev, int size)
dev->index[n++] = &f[i];
}
input_mt_assign_slots(input, dev->slots, dev->pos, n);
input_mt_assign_slots(input, dev->slots, dev->pos, n, 0);
for (i = 0; i < n; i++)
report_finger_data(input, dev->slots[i],
......
This diff is collapsed.
/*
* Cypress APA trackpad with I2C interface
*
* Author: Dudley Du <dudl@cypress.com>
*
* Copyright (C) 2014 Cypress Semiconductor, Inc.
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file COPYING in the main directory of this archive for
* more details.
*/
#ifndef _CYAPA_H
#define _CYAPA_H
#include <linux/firmware.h>
/* APA trackpad firmware generation number. */
#define CYAPA_GEN_UNKNOWN 0x00 /* unknown protocol. */
#define CYAPA_GEN3 0x03 /* support MT-protocol B with tracking ID. */
#define CYAPA_GEN5 0x05 /* support TrueTouch GEN5 trackpad device. */
#define CYAPA_NAME "Cypress APA Trackpad (cyapa)"
/*
* Macros for SMBus communication
*/
#define SMBUS_READ 0x01
#define SMBUS_WRITE 0x00
#define SMBUS_ENCODE_IDX(cmd, idx) ((cmd) | (((idx) & 0x03) << 1))
#define SMBUS_ENCODE_RW(cmd, rw) ((cmd) | ((rw) & 0x01))
#define SMBUS_BYTE_BLOCK_CMD_MASK 0x80
#define SMBUS_GROUP_BLOCK_CMD_MASK 0x40
/* Commands for read/write registers of Cypress trackpad */
#define CYAPA_CMD_SOFT_RESET 0x00
#define CYAPA_CMD_POWER_MODE 0x01
#define CYAPA_CMD_DEV_STATUS 0x02
#define CYAPA_CMD_GROUP_DATA 0x03
#define CYAPA_CMD_GROUP_CMD 0x04
#define CYAPA_CMD_GROUP_QUERY 0x05
#define CYAPA_CMD_BL_STATUS 0x06
#define CYAPA_CMD_BL_HEAD 0x07
#define CYAPA_CMD_BL_CMD 0x08
#define CYAPA_CMD_BL_DATA 0x09
#define CYAPA_CMD_BL_ALL 0x0a
#define CYAPA_CMD_BLK_PRODUCT_ID 0x0b
#define CYAPA_CMD_BLK_HEAD 0x0c
#define CYAPA_CMD_MAX_BASELINE 0x0d
#define CYAPA_CMD_MIN_BASELINE 0x0e
#define BL_HEAD_OFFSET 0x00
#define BL_DATA_OFFSET 0x10
#define BL_STATUS_SIZE 3 /* Length of gen3 bootloader status registers */
#define CYAPA_REG_MAP_SIZE 256
/*
* Gen3 Operational Device Status Register
*
* bit 7: Valid interrupt source
* bit 6 - 4: Reserved
* bit 3 - 2: Power status
* bit 1 - 0: Device status
*/
#define REG_OP_STATUS 0x00
#define OP_STATUS_SRC 0x80
#define OP_STATUS_POWER 0x0c
#define OP_STATUS_DEV 0x03
#define OP_STATUS_MASK (OP_STATUS_SRC | OP_STATUS_POWER | OP_STATUS_DEV)
/*
* Operational Finger Count/Button Flags Register
*
* bit 7 - 4: Number of touched finger
* bit 3: Valid data
* bit 2: Middle Physical Button
* bit 1: Right Physical Button
* bit 0: Left physical Button
*/
#define REG_OP_DATA1 0x01
#define OP_DATA_VALID 0x08
#define OP_DATA_MIDDLE_BTN 0x04
#define OP_DATA_RIGHT_BTN 0x02
#define OP_DATA_LEFT_BTN 0x01
#define OP_DATA_BTN_MASK (OP_DATA_MIDDLE_BTN | OP_DATA_RIGHT_BTN | \
OP_DATA_LEFT_BTN)
/*
* Write-only command file register used to issue commands and
* parameters to the bootloader.
* The default value read from it is always 0x00.
*/
#define REG_BL_FILE 0x00
#define BL_FILE 0x00
/*
* Bootloader Status Register
*
* bit 7: Busy
* bit 6 - 5: Reserved
* bit 4: Bootloader running
* bit 3 - 2: Reserved
* bit 1: Watchdog Reset
* bit 0: Checksum valid
*/
#define REG_BL_STATUS 0x01
#define BL_STATUS_REV_6_5 0x60
#define BL_STATUS_BUSY 0x80
#define BL_STATUS_RUNNING 0x10
#define BL_STATUS_REV_3_2 0x0c
#define BL_STATUS_WATCHDOG 0x02
#define BL_STATUS_CSUM_VALID 0x01
#define BL_STATUS_REV_MASK (BL_STATUS_WATCHDOG | BL_STATUS_REV_3_2 | \
BL_STATUS_REV_6_5)
/*
* Bootloader Error Register
*
* bit 7: Invalid
* bit 6: Invalid security key
* bit 5: Bootloading
* bit 4: Command checksum
* bit 3: Flash protection error
* bit 2: Flash checksum error
* bit 1 - 0: Reserved
*/
#define REG_BL_ERROR 0x02
#define BL_ERROR_INVALID 0x80
#define BL_ERROR_INVALID_KEY 0x40
#define BL_ERROR_BOOTLOADING 0x20
#define BL_ERROR_CMD_CSUM 0x10
#define BL_ERROR_FLASH_PROT 0x08
#define BL_ERROR_FLASH_CSUM 0x04
#define BL_ERROR_RESERVED 0x03
#define BL_ERROR_NO_ERR_IDLE 0x00
#define BL_ERROR_NO_ERR_ACTIVE (BL_ERROR_BOOTLOADING)
#define CAPABILITY_BTN_SHIFT 3
#define CAPABILITY_LEFT_BTN_MASK (0x01 << 3)
#define CAPABILITY_RIGHT_BTN_MASK (0x01 << 4)
#define CAPABILITY_MIDDLE_BTN_MASK (0x01 << 5)
#define CAPABILITY_BTN_MASK (CAPABILITY_LEFT_BTN_MASK | \
CAPABILITY_RIGHT_BTN_MASK | \
CAPABILITY_MIDDLE_BTN_MASK)
#define PWR_MODE_MASK 0xfc
#define PWR_MODE_FULL_ACTIVE (0x3f << 2)
#define PWR_MODE_IDLE (0x03 << 2) /* Default rt suspend scanrate: 30ms */
#define PWR_MODE_SLEEP (0x05 << 2) /* Default suspend scanrate: 50ms */
#define PWR_MODE_BTN_ONLY (0x01 << 2)
#define PWR_MODE_OFF (0x00 << 2)
#define PWR_STATUS_MASK 0x0c
#define PWR_STATUS_ACTIVE (0x03 << 2)
#define PWR_STATUS_IDLE (0x02 << 2)
#define PWR_STATUS_BTN_ONLY (0x01 << 2)
#define PWR_STATUS_OFF (0x00 << 2)
#define AUTOSUSPEND_DELAY 2000 /* unit : ms */
#define UNINIT_SLEEP_TIME 0xFFFF
#define UNINIT_PWR_MODE 0xFF
#define BTN_ONLY_MODE_NAME "buttononly"
#define OFF_MODE_NAME "off"
/* The touch.id is used as the MT slot id, thus max MT slot is 15 */
#define CYAPA_MAX_MT_SLOTS 15
struct cyapa;
typedef bool (*cb_sort)(struct cyapa *, u8 *, int);
struct cyapa_dev_ops {
int (*check_fw)(struct cyapa *, const struct firmware *);
int (*bl_enter)(struct cyapa *);
int (*bl_activate)(struct cyapa *);
int (*bl_initiate)(struct cyapa *, const struct firmware *);
int (*update_fw)(struct cyapa *, const struct firmware *);
int (*bl_deactivate)(struct cyapa *);
ssize_t (*show_baseline)(struct device *,
struct device_attribute *, char *);
ssize_t (*calibrate_store)(struct device *,
struct device_attribute *, const char *, size_t);
int (*initialize)(struct cyapa *cyapa);
int (*state_parse)(struct cyapa *cyapa, u8 *reg_status, int len);
int (*operational_check)(struct cyapa *cyapa);
int (*irq_handler)(struct cyapa *);
bool (*irq_cmd_handler)(struct cyapa *);
int (*sort_empty_output_data)(struct cyapa *,
u8 *, int *, cb_sort);
int (*set_power_mode)(struct cyapa *, u8, u16);
};
struct cyapa_gen5_cmd_states {
struct mutex cmd_lock;
struct completion cmd_ready;
atomic_t cmd_issued;
u8 in_progress_cmd;
bool is_irq_mode;
cb_sort resp_sort_func;
u8 *resp_data;
int *resp_len;
u8 irq_cmd_buf[CYAPA_REG_MAP_SIZE];
u8 empty_buf[CYAPA_REG_MAP_SIZE];
};
union cyapa_cmd_states {
struct cyapa_gen5_cmd_states gen5;
};
enum cyapa_state {
CYAPA_STATE_NO_DEVICE,
CYAPA_STATE_BL_BUSY,
CYAPA_STATE_BL_IDLE,
CYAPA_STATE_BL_ACTIVE,
CYAPA_STATE_OP,
CYAPA_STATE_GEN5_BL,
CYAPA_STATE_GEN5_APP,
};
/* The main device structure */
struct cyapa {
enum cyapa_state state;
u8 status[BL_STATUS_SIZE];
bool operational; /* true: ready for data reporting; false: not. */
struct i2c_client *client;
struct input_dev *input;
char phys[32]; /* Device physical location */
bool irq_wake; /* Irq wake is enabled */
bool smbus;
/* power mode settings */
u8 suspend_power_mode;
u16 suspend_sleep_time;
u8 runtime_suspend_power_mode;
u16 runtime_suspend_sleep_time;
u8 dev_pwr_mode;
u16 dev_sleep_time;
/* Read from query data region. */
char product_id[16];
u8 fw_maj_ver; /* Firmware major version. */
u8 fw_min_ver; /* Firmware minor version. */
u8 btn_capability;
u8 gen;
int max_abs_x;
int max_abs_y;
int physical_size_x;
int physical_size_y;
/* Used in ttsp and truetouch based trackpad devices. */
u8 x_origin; /* X Axis Origin: 0 = left side; 1 = rigth side. */
u8 y_origin; /* Y Axis Origin: 0 = top; 1 = bottom. */
int electrodes_x; /* Number of electrodes on the X Axis*/
int electrodes_y; /* Number of electrodes on the Y Axis*/
int electrodes_rx; /* Number of Rx electrodes */
int aligned_electrodes_rx; /* 4 aligned */
int max_z;
/*
* Used to synchronize the access or update the device state.
* And since update firmware and read firmware image process will take
* quite long time, maybe more than 10 seconds, so use mutex_lock
* to sync and wait other interface and detecting are done or ready.
*/
struct mutex state_sync_lock;
const struct cyapa_dev_ops *ops;
union cyapa_cmd_states cmd_states;
};
ssize_t cyapa_i2c_reg_read_block(struct cyapa *cyapa, u8 reg, size_t len,
u8 *values);
ssize_t cyapa_smbus_read_block(struct cyapa *cyapa, u8 cmd, size_t len,
u8 *values);
ssize_t cyapa_read_block(struct cyapa *cyapa, u8 cmd_idx, u8 *values);
int cyapa_poll_state(struct cyapa *cyapa, unsigned int timeout);
u8 cyapa_sleep_time_to_pwr_cmd(u16 sleep_time);
u16 cyapa_pwr_cmd_to_sleep_time(u8 pwr_mode);
extern const char product_id[];
extern const struct cyapa_dev_ops cyapa_gen3_ops;
extern const struct cyapa_dev_ops cyapa_gen5_ops;
#endif
This diff is collapsed.
This diff is collapsed.
......@@ -538,7 +538,7 @@ static void cypress_process_packet(struct psmouse *psmouse, bool zero_pkt)
pos[i].y = contact->y;
}
input_mt_assign_slots(input, slots, pos, n);
input_mt_assign_slots(input, slots, pos, n, 0);
for (i = 0; i < n; i++) {
contact = &report_data.contacts[i];
......
......@@ -4,7 +4,6 @@
* Copyright (c) 2013 ELAN Microelectronics Corp.
*
* Author: 林政維 (Duson Lin) <dusonlin@emc.com.tw>
* Version: 1.5.5
*
* Based on cyapa driver:
* copyright (c) 2011-2012 Cypress Semiconductor, Inc.
......@@ -33,8 +32,9 @@
#define ETP_FW_IAP_PAGE_ERR (1 << 5)
#define ETP_FW_IAP_INTF_ERR (1 << 4)
#define ETP_FW_PAGE_SIZE 64
#define ETP_FW_PAGE_COUNT 768
#define ETP_FW_SIZE (ETP_FW_PAGE_SIZE * ETP_FW_PAGE_COUNT)
#define ETP_FW_VAILDPAGE_COUNT 768
#define ETP_FW_SIGNATURE_SIZE 6
#define ETP_FW_SIGNATURE_ADDRESS 0xBFFA
struct i2c_client;
struct completion;
......
......@@ -4,7 +4,7 @@
* Copyright (c) 2013 ELAN Microelectronics Corp.
*
* Author: 林政維 (Duson Lin) <dusonlin@emc.com.tw>
* Version: 1.5.5
* Version: 1.5.6
*
* Based on cyapa driver:
* copyright (c) 2011-2012 Cypress Semiconductor, Inc.
......@@ -40,7 +40,7 @@
#include "elan_i2c.h"
#define DRIVER_NAME "elan_i2c"
#define ELAN_DRIVER_VERSION "1.5.5"
#define ELAN_DRIVER_VERSION "1.5.6"
#define ETP_PRESSURE_OFFSET 25
#define ETP_MAX_PRESSURE 255
#define ETP_FWIDTH_REDUCE 90
......@@ -312,7 +312,7 @@ static int __elan_update_firmware(struct elan_tp_data *data,
iap_start_addr = get_unaligned_le16(&fw->data[ETP_IAP_START_ADDR * 2]);
boot_page_count = (iap_start_addr * 2) / ETP_FW_PAGE_SIZE;
for (i = boot_page_count; i < ETP_FW_PAGE_COUNT; i++) {
for (i = boot_page_count; i < ETP_FW_VAILDPAGE_COUNT; i++) {
u16 checksum = 0;
const u8 *page = &fw->data[i * ETP_FW_PAGE_SIZE];
......@@ -434,10 +434,11 @@ static ssize_t elan_sysfs_update_fw(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
struct elan_tp_data *data = i2c_get_clientdata(client);
struct elan_tp_data *data = dev_get_drvdata(dev);
const struct firmware *fw;
int error;
const u8 *fw_signature;
static const u8 signature[] = {0xAA, 0x55, 0xCC, 0x33, 0xFF, 0xFF};
error = request_firmware(&fw, ETP_FW_NAME, dev);
if (error) {
......@@ -446,10 +447,12 @@ static ssize_t elan_sysfs_update_fw(struct device *dev,
return error;
}
/* Firmware must be exactly PAGE_NUM * PAGE_SIZE bytes */
if (fw->size != ETP_FW_SIZE) {
dev_err(dev, "invalid firmware size = %zu, expected %d.\n",
fw->size, ETP_FW_SIZE);
/* Firmware file must match signature data */
fw_signature = &fw->data[ETP_FW_SIGNATURE_ADDRESS];
if (memcmp(fw_signature, signature, sizeof(signature)) != 0) {
dev_err(dev, "signature mismatch (expected %*ph, got %*ph)\n",
(int)sizeof(signature), signature,
(int)sizeof(signature), fw_signature);
error = -EBADF;
goto out_release_fw;
}
......
......@@ -4,7 +4,6 @@
* Copyright (c) 2013 ELAN Microelectronics Corp.
*
* Author: 林政維 (Duson Lin) <dusonlin@emc.com.tw>
* Version: 1.5.5
*
* Based on cyapa driver:
* copyright (c) 2011-2012 Cypress Semiconductor, Inc.
......
......@@ -4,7 +4,6 @@
* Copyright (c) 2013 ELAN Microelectronics Corp.
*
* Author: 林政維 (Duson Lin) <dusonlin@emc.com.tw>
* Version: 1.5.5
*
* Based on cyapa driver:
* copyright (c) 2011-2012 Cypress Semiconductor, Inc.
......@@ -71,7 +70,7 @@ static int elan_smbus_initialize(struct i2c_client *client)
/* compare hello packet */
if (memcmp(values, check, ETP_SMBUS_HELLOPACKET_LEN)) {
dev_err(&client->dev, "hello packet fail [%*px]\n",
dev_err(&client->dev, "hello packet fail [%*ph]\n",
ETP_SMBUS_HELLOPACKET_LEN, values);
return -ENXIO;
}
......
This diff is collapsed.
......@@ -2,6 +2,7 @@
* Focaltech TouchPad PS/2 mouse driver
*
* Copyright (c) 2014 Red Hat Inc.
* Copyright (c) 2014 Mathias Gottschlag <mgottschlag@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
......@@ -18,5 +19,6 @@
int focaltech_detect(struct psmouse *psmouse, bool set_properties);
int focaltech_init(struct psmouse *psmouse);
bool focaltech_supported(void);
#endif
......@@ -725,16 +725,19 @@ static int psmouse_extensions(struct psmouse *psmouse,
/* Always check for focaltech, this is safe as it uses pnp-id matching */
if (psmouse_do_detect(focaltech_detect, psmouse, set_properties) == 0) {
if (!set_properties || focaltech_init(psmouse) == 0) {
/*
* Not supported yet, use bare protocol.
* Note that we need to also restrict
* psmouse_max_proto so that psmouse_initialize()
* does not try to reset rate and resolution,
* because even that upsets the device.
*/
psmouse_max_proto = PSMOUSE_PS2;
return PSMOUSE_PS2;
if (max_proto > PSMOUSE_IMEX) {
if (!set_properties || focaltech_init(psmouse) == 0) {
if (focaltech_supported())
return PSMOUSE_FOCALTECH;
/*
* Note that we need to also restrict
* psmouse_max_proto so that psmouse_initialize()
* does not try to reset rate and resolution,
* because even that upsets the device.
*/
psmouse_max_proto = PSMOUSE_PS2;
return PSMOUSE_PS2;
}
}
}
......@@ -1063,6 +1066,15 @@ static const struct psmouse_protocol psmouse_protocols[] = {
.alias = "cortps",
.detect = cortron_detect,
},
#ifdef CONFIG_MOUSE_PS2_FOCALTECH
{
.type = PSMOUSE_FOCALTECH,
.name = "FocalTechPS/2",
.alias = "focaltech",
.detect = focaltech_detect,
.init = focaltech_init,
},
#endif
{
.type = PSMOUSE_AUTO,
.name = "auto",
......
......@@ -96,6 +96,7 @@ enum psmouse_type {
PSMOUSE_FSP,
PSMOUSE_SYNAPTICS_RELATIVE,
PSMOUSE_CYPRESS,
PSMOUSE_FOCALTECH,
PSMOUSE_AUTO /* This one should always be last */
};
......
This diff is collapsed.
......@@ -118,16 +118,6 @@
/* amount to fuzz position data when touchpad reports reduced filtering */
#define SYN_REDUCED_FILTER_FUZZ 8
/*
* A structure to describe which internal touchpad finger slots are being
* reported in raw packets.
*/
struct synaptics_mt_state {
int count; /* num fingers being tracked */
int sgm; /* which slot is reported by sgm pkt */
int agm; /* which slot is reported by agm pkt*/
};
/*
* A structure to describe the state of the touchpad hardware (buttons and pad)
*/
......@@ -143,9 +133,6 @@ struct synaptics_hw_state {
unsigned int down:1;
unsigned char ext_buttons;
signed char scroll;
/* As reported in last AGM-CONTACT packets */
struct synaptics_mt_state mt_state;
};
struct synaptics_data {
......@@ -170,15 +157,12 @@ struct synaptics_data {
struct serio *pt_port; /* Pass-through serio port */
struct synaptics_mt_state mt_state; /* Current mt finger state */
bool mt_state_lost; /* mt_state may be incorrect */
/*
* Last received Advanced Gesture Mode (AGM) packet. An AGM packet
* contains position data for a second contact, at half resolution.
*/
struct synaptics_hw_state agm;
bool agm_pending; /* new AGM packet received */
unsigned int agm_count; /* finger count reported by agm */
/* ForcePad handling */
unsigned long press_start;
......
......@@ -281,4 +281,14 @@ config HYPERV_KEYBOARD
To compile this driver as a module, choose M here: the module will
be called hyperv_keyboard.
config SERIO_SUN4I_PS2
tristate "Allwinner A10 PS/2 controller support"
depends on ARCH_SUNXI || COMPILE_TEST
help
This selects support for the PS/2 Host Controller on
Allwinner A10.
To compile this driver as a module, choose M here: the
module will be called sun4i-ps2.
endif
......@@ -29,3 +29,4 @@ obj-$(CONFIG_SERIO_ARC_PS2) += arc_ps2.o
obj-$(CONFIG_SERIO_APBPS2) += apbps2.o
obj-$(CONFIG_SERIO_OLPC_APSP) += olpc_apsp.o
obj-$(CONFIG_HYPERV_KEYBOARD) += hyperv-keyboard.o
obj-$(CONFIG_SERIO_SUN4I_PS2) += sun4i-ps2.o
......@@ -40,7 +40,6 @@
MODULE_AUTHOR("Laurent Canet <canetl@esiee.fr>, Thibaut Varene <varenet@parisc-linux.org>, Helge Deller <deller@gmx.de>");
MODULE_DESCRIPTION("HP GSC PS2 port driver");
MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(parisc, gscps2_device_tbl);
#define PFX "gscps2.c: "
......@@ -439,6 +438,7 @@ static struct parisc_device_id gscps2_device_tbl[] = {
#endif
{ 0, } /* 0 terminated list */
};
MODULE_DEVICE_TABLE(parisc, gscps2_device_tbl);
static struct parisc_driver parisc_ps2_driver = {
.name = "gsc_ps2",
......
This diff is collapsed.
......@@ -59,7 +59,7 @@ Scott Hill shill@gtcocalcomp.com
#include <asm/uaccess.h>
#include <asm/unaligned.h>
#include <asm/byteorder.h>
#include <linux/bitops.h>
#include <linux/usb/input.h>
......@@ -614,7 +614,6 @@ static void gtco_urb_callback(struct urb *urbinfo)
struct input_dev *inputdev;
int rc;
u32 val = 0;
s8 valsigned = 0;
char le_buffer[2];
inputdev = device->inputdevice;
......@@ -665,20 +664,11 @@ static void gtco_urb_callback(struct urb *urbinfo)
/* Fall thru */
case 4:
/* Tilt */
input_report_abs(inputdev, ABS_TILT_X,
sign_extend32(device->buffer[6], 6));
/* Sign extend these 7 bit numbers. */
if (device->buffer[6] & 0x40)
device->buffer[6] |= 0x80;
if (device->buffer[7] & 0x40)
device->buffer[7] |= 0x80;
valsigned = (device->buffer[6]);
input_report_abs(inputdev, ABS_TILT_X, (s32)valsigned);
valsigned = (device->buffer[7]);
input_report_abs(inputdev, ABS_TILT_Y, (s32)valsigned);
input_report_abs(inputdev, ABS_TILT_Y,
sign_extend32(device->buffer[7], 6));
/* Fall thru */
case 2:
......
......@@ -33,10 +33,8 @@
#include <linux/delay.h>
#include <linux/uaccess.h>
#include <linux/buffer_head.h>
#include <linux/version.h>
#include <linux/slab.h>
#include <linux/firmware.h>
#include <linux/version.h>
#include <linux/input/mt.h>
#include <linux/acpi.h>
#include <linux/of.h>
......
......@@ -126,7 +126,7 @@ static void pixcir_ts_report(struct pixcir_i2c_ts_data *ts,
pos[i].y = touch->y;
}
input_mt_assign_slots(ts->input, slots, pos, n);
input_mt_assign_slots(ts->input, slots, pos, n, 0);
}
for (i = 0; i < n; i++) {
......
This diff is collapsed.
This diff is collapsed.
......@@ -119,7 +119,8 @@ struct input_mt_pos {
};
int input_mt_assign_slots(struct input_dev *dev, int *slots,
const struct input_mt_pos *pos, int num_pos);
const struct input_mt_pos *pos, int num_pos,
int dmax);
int input_mt_get_slot_by_key(struct input_dev *dev, int key);
......
......@@ -52,6 +52,7 @@
/* IRQ enable */
#define IRQENB_HW_PEN BIT(0)
#define IRQENB_EOS BIT(1)
#define IRQENB_FIFO0THRES BIT(2)
#define IRQENB_FIFO0OVRRUN BIT(3)
#define IRQENB_FIFO0UNDRFLW BIT(4)
......@@ -107,7 +108,7 @@
/* Charge delay */
#define CHARGEDLY_OPEN_MASK (0x3FFFF << 0)
#define CHARGEDLY_OPEN(val) ((val) << 0)
#define CHARGEDLY_OPENDLY CHARGEDLY_OPEN(1)
#define CHARGEDLY_OPENDLY CHARGEDLY_OPEN(0x400)
/* Control register */
#define CNTRLREG_TSCSSENB BIT(0)
......
/*
* Regulator Haptic Platform Data
*
* Copyright (c) 2014 Samsung Electronics Co., Ltd.
* Author: Jaewon Kim <jaewon02.kim@samsung.com>
* Author: Hyunhee Kim <hyunhee.kim@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 Foundation.
*/
#ifndef _REGULATOR_HAPTIC_H
#define _REGULATOR_HAPTIC_H
/*
* struct regulator_haptic_data - Platform device data
*
* @max_volt: maximum voltage value supplied to the haptic motor.
* <The unit of the voltage is a micro>
* @min_volt: minimum voltage value supplied to the haptic motor.
* <The unit of the voltage is a micro>
*/
struct regulator_haptic_data {
unsigned int max_volt;
unsigned int min_volt;
};
#endif /* _REGULATOR_HAPTIC_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment