Commit 73f10274 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.

  Just new drivers and existing driver fixes, no core changes except for
  the new uinput IOCTL to allow userspace to fetch sysfs name of the
  input device that was created"

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input: (43 commits)
  Input: edt-ft5x06 - add a missing condition
  Input: appletouch - fix jumps when additional fingers are detected
  Input: appletouch - implement sensor data smoothing
  Input: add driver for SOC button array
  Input: pm8xxx-vibrator - add DT match table
  Input: pmic8xxx-pwrkey - migrate to DT
  Input: pmic8xxx-keypad - migrate to DT
  Input: pmic8xxx-keypad - migrate to regmap APIs
  Input: pmic8xxx-keypad - migrate to devm_* APIs
  Input: pmic8xxx-keypad - fix build by removing gpio configuration
  Input: add new driver for ARM CLPS711X keypad
  Input: edt-ft5x06 - add support for M09 firmware version
  Input: edt-ft5x06 - ignore touchdown events
  Input: edt-ft5x06 - adjust delays to conform datasheet
  Input: edt-ft5x06 - add DT support
  Input: edt-ft5x06 - several cleanups; no functional change
  Input: appletouch - dial back fuzz setting
  Input: remove obsolete tnetv107x drivers
  Input: sirfsoc-onkey - set the capability of reporting KEY_POWER
  Input: da9052_onkey - use correct register bit for key status
  ...
parents 877f075a 692d9655
* Cirrus Logic CLPS711X matrix keypad device tree bindings
Required Properties:
- compatible: Shall contain "cirrus,clps711x-keypad".
- row-gpios: List of GPIOs used as row lines.
- poll-interval: Poll interval time in milliseconds.
- linux,keymap: The definition can be found at
bindings/input/matrix-keymap.txt.
Optional Properties:
- autorepeat: Enable autorepeat feature.
Example:
keypad {
compatible = "cirrus,ep7312-keypad", "cirrus,clps711x-keypad";
autorepeat;
poll-interval = <120>;
row-gpios = <&porta 0 0>,
<&porta 1 0>;
linux,keymap = <
MATRIX_KEY(0, 0, KEY_UP)
MATRIX_KEY(0, 1, KEY_DOWN)
MATRIX_KEY(1, 0, KEY_LEFT)
MATRIX_KEY(1, 1, KEY_RIGHT)
>;
};
Qualcomm PM8xxx PMIC Keypad
PROPERTIES
- compatible:
Usage: required
Value type: <string>
Definition: must be one of:
"qcom,pm8058-keypad"
"qcom,pm8921-keypad"
- reg:
Usage: required
Value type: <prop-encoded-array>
Definition: address of keypad control register
- interrupts:
Usage: required
Value type: <prop-encoded-array>
Definition: the first interrupt specifies the key sense interrupt
and the second interrupt specifies the key stuck interrupt.
The format of the specifier is defined by the binding
document describing the node's interrupt parent.
- linux,keymap:
Usage: required
Value type: <prop-encoded-array>
Definition: the linux keymap. More information can be found in
input/matrix-keymap.txt.
- linux,keypad-no-autorepeat:
Usage: optional
Value type: <bool>
Definition: don't enable autorepeat feature.
- linux,keypad-wakeup:
Usage: optional
Value type: <bool>
Definition: use any event on keypad as wakeup event.
- keypad,num-rows:
Usage: required
Value type: <u32>
Definition: number of rows in the keymap. More information can be found
in input/matrix-keymap.txt.
- keypad,num-columns:
Usage: required
Value type: <u32>
Definition: number of columns in the keymap. More information can be
found in input/matrix-keymap.txt.
- debounce:
Usage: optional
Value type: <u32>
Definition: time in microseconds that key must be pressed or release
for key sense interrupt to trigger.
- scan-delay:
Usage: optional
Value type: <u32>
Definition: time in microseconds to pause between successive scans
of the matrix array.
- row-hold:
Usage: optional
Value type: <u32>
Definition: time in nanoseconds to pause between scans of each row in
the matrix array.
EXAMPLE
keypad@148 {
compatible = "qcom,pm8921-keypad";
reg = <0x148>;
interrupt-parent = <&pmicintc>;
interrupts = <74 1>, <75 1>;
linux,keymap = <
MATRIX_KEY(0, 0, KEY_VOLUMEUP)
MATRIX_KEY(0, 1, KEY_VOLUMEDOWN)
MATRIX_KEY(0, 2, KEY_CAMERA_FOCUS)
MATRIX_KEY(0, 3, KEY_CAMERA)
>;
keypad,num-rows = <1>;
keypad,num-columns = <5>;
debounce = <15>;
scan-delay = <32>;
row-hold = <91500>;
};
Qualcomm PM8xxx PMIC Power Key
PROPERTIES
- compatible:
Usage: required
Value type: <string>
Definition: must be one of:
"qcom,pm8058-pwrkey"
"qcom,pm8921-pwrkey"
- reg:
Usage: required
Value type: <prop-encoded-array>
Definition: address of power key control register
- interrupts:
Usage: required
Value type: <prop-encoded-array>
Definition: the first interrupt specifies the key release interrupt
and the second interrupt specifies the key press interrupt.
The format of the specifier is defined by the binding
document describing the node's interrupt parent.
- debounce:
Usage: optional
Value type: <u32>
Definition: time in microseconds that key must be pressed or release
for state change interrupt to trigger.
- pull-up:
Usage: optional
Value type: <empty>
Definition: presence of this property indicates that the KPDPWR_N pin
should be configured for pull up.
EXAMPLE
pwrkey@1c {
compatible = "qcom,pm8921-pwrkey";
reg = <0x1c>;
interrupt-parent = <&pmicintc>;
interrupts = <50 1>, <51 1>;
debounce = <15625>;
pull-up;
};
Qualcomm PM8xxx PMIC Vibrator
PROPERTIES
- compatible:
Usage: required
Value type: <string>
Definition: must be one of:
"qcom,pm8058-vib"
"qcom,pm8921-vib"
- reg:
Usage: required
Value type: <prop-encoded-array>
Definition: address of vibration control register
EXAMPLE
vibrator@4a {
compatible = "qcom,pm8058-vib";
reg = <0x4a>;
};
FocalTech EDT-FT5x06 Polytouch driver
=====================================
There are 3 variants of the chip for various touch panel sizes
FT5206GE1 2.8" .. 3.8"
FT5306DE4 4.3" .. 7"
FT5406EE8 7" .. 8.9"
The software interface is identical for all those chips, so that
currently there is no need for the driver to distinguish between the
different chips. Nevertheless distinct compatible strings are used so
that a distinction can be added if necessary without changing the DT
bindings.
Required properties:
- compatible: "edt,edt-ft5206"
or: "edt,edt-ft5306"
or: "edt,edt-ft5406"
- reg: I2C slave address of the chip (0x38)
- interrupt-parent: a phandle pointing to the interrupt controller
serving the interrupt for this chip
- interrupts: interrupt specification for the touchdetect
interrupt
Optional properties:
- reset-gpios: GPIO specification for the RESET input
- wake-gpios: GPIO specification for the WAKE input
- pinctrl-names: should be "default"
- pinctrl-0: a phandle pointing to the pin settings for the
control gpios
- threshold: allows setting the "click"-threshold in the range
from 20 to 80.
- gain: allows setting the sensitivity in the range from 0 to
31. Note that lower values indicate higher
sensitivity.
- offset: allows setting the edge compensation in the range from
0 to 31.
Example:
polytouch: edt-ft5x06@38 {
compatible = "edt,edt-ft5406", "edt,edt-ft5x06";
reg = <0x38>;
pinctrl-names = "default";
pinctrl-0 = <&edt_ft5x06_pins>;
interrupt-parent = <&gpio2>;
interrupts = <5 0>;
reset-gpios = <&gpio2 6 1>;
wake-gpios = <&gpio4 9 0>;
};
* Neonode infrared touchscreen controller
Required properties:
- compatible: must be "neonode,zforce"
- reg: I2C address of the chip
- interrupts: interrupt to which the chip is connected
- gpios: gpios the chip is connected to
first one is the interrupt gpio and second one the reset gpio
- x-size: horizontal resolution of touchscreen
- y-size: vertical resolution of touchscreen
Example:
i2c@00000000 {
/* ... */
zforce_ts@50 {
compatible = "neonode,zforce";
reg = <0x50>;
interrupts = <2 0>;
gpios = <&gpio5 6 0>, /* INT */
<&gpio5 9 0>; /* RST */
x-size = <800>;
y-size = <600>;
};
/* ... */
};
......@@ -151,6 +151,18 @@ config KEYBOARD_BFIN
To compile this driver as a module, choose M here: the
module will be called bf54x-keys.
config KEYBOARD_CLPS711X
tristate "CLPS711X Keypad support"
depends on OF_GPIO && (ARCH_CLPS711X || COMPILE_TEST)
select INPUT_MATRIXKMAP
select INPUT_POLLDEV
help
Say Y here to enable the matrix keypad on the Cirrus Logic
CLPS711X CPUs.
To compile this driver as a module, choose M here: the
module will be called clps711x-keypad.
config KEYBOARD_LKKBD
tristate "DECstation/VAXstation LK201/LK401 keyboard"
select SERIO
......@@ -595,16 +607,6 @@ config KEYBOARD_TC3589X
To compile this driver as a module, choose M here: the
module will be called tc3589x-keypad.
config KEYBOARD_TNETV107X
tristate "TI TNETV107X keypad support"
depends on ARCH_DAVINCI_TNETV107X
select INPUT_MATRIXKMAP
help
Say Y here if you want to use the TNETV107X keypad.
To compile this driver as a module, choose M here: the
module will be called tnetv107x-keypad.
config KEYBOARD_TWL4030
tristate "TI TWL4030/TWL5030/TPS659x0 keypad support"
depends on TWL4030_CORE
......
......@@ -11,6 +11,7 @@ obj-$(CONFIG_KEYBOARD_AMIGA) += amikbd.o
obj-$(CONFIG_KEYBOARD_ATARI) += atakbd.o
obj-$(CONFIG_KEYBOARD_ATKBD) += atkbd.o
obj-$(CONFIG_KEYBOARD_BFIN) += bf54x-keys.o
obj-$(CONFIG_KEYBOARD_CLPS711X) += clps711x-keypad.o
obj-$(CONFIG_KEYBOARD_CROS_EC) += cros_ec_keyb.o
obj-$(CONFIG_KEYBOARD_DAVINCI) += davinci_keyscan.o
obj-$(CONFIG_KEYBOARD_EP93XX) += ep93xx_keypad.o
......@@ -53,7 +54,6 @@ obj-$(CONFIG_KEYBOARD_STOWAWAY) += stowaway.o
obj-$(CONFIG_KEYBOARD_SUNKBD) += sunkbd.o
obj-$(CONFIG_KEYBOARD_TC3589X) += tc3589x-keypad.o
obj-$(CONFIG_KEYBOARD_TEGRA) += tegra-kbc.o
obj-$(CONFIG_KEYBOARD_TNETV107X) += tnetv107x-keypad.o
obj-$(CONFIG_KEYBOARD_TWL4030) += twl4030_keypad.o
obj-$(CONFIG_KEYBOARD_XTKBD) += xtkbd.o
obj-$(CONFIG_KEYBOARD_W90P910) += w90p910_keypad.o
/*
* Cirrus Logic CLPS711X Keypad driver
*
* Copyright (C) 2014 Alexander Shiyan <shc_work@mail.ru>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#include <linux/input.h>
#include <linux/input-polldev.h>
#include <linux/module.h>
#include <linux/of_gpio.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/sched.h>
#include <linux/input/matrix_keypad.h>
#include <linux/mfd/syscon.h>
#include <linux/mfd/syscon/clps711x.h>
#define CLPS711X_KEYPAD_COL_COUNT 8
struct clps711x_gpio_data {
struct gpio_desc *desc;
DECLARE_BITMAP(last_state, CLPS711X_KEYPAD_COL_COUNT);
};
struct clps711x_keypad_data {
struct regmap *syscon;
int row_count;
unsigned int row_shift;
struct clps711x_gpio_data *gpio_data;
};
static void clps711x_keypad_poll(struct input_polled_dev *dev)
{
const unsigned short *keycodes = dev->input->keycode;
struct clps711x_keypad_data *priv = dev->private;
bool sync = false;
int col, row;
for (col = 0; col < CLPS711X_KEYPAD_COL_COUNT; col++) {
/* Assert column */
regmap_update_bits(priv->syscon, SYSCON_OFFSET,
SYSCON1_KBDSCAN_MASK,
SYSCON1_KBDSCAN(8 + col));
/* Scan rows */
for (row = 0; row < priv->row_count; row++) {
struct clps711x_gpio_data *data = &priv->gpio_data[row];
bool state, state1;
/* Read twice for protection against fluctuations */
do {
state = gpiod_get_value_cansleep(data->desc);
cond_resched();
state1 = gpiod_get_value_cansleep(data->desc);
} while (state != state1);
if (test_bit(col, data->last_state) != state) {
int code = MATRIX_SCAN_CODE(row, col,
priv->row_shift);
if (state) {
set_bit(col, data->last_state);
input_event(dev->input, EV_MSC,
MSC_SCAN, code);
} else {
clear_bit(col, data->last_state);
}
if (keycodes[code])
input_report_key(dev->input,
keycodes[code], state);
sync = true;
}
}
/* Set all columns to low */
regmap_update_bits(priv->syscon, SYSCON_OFFSET,
SYSCON1_KBDSCAN_MASK, SYSCON1_KBDSCAN(1));
}
if (sync)
input_sync(dev->input);
}
static int clps711x_keypad_probe(struct platform_device *pdev)
{
struct clps711x_keypad_data *priv;
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
struct input_polled_dev *poll_dev;
u32 poll_interval;
int i, err;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
priv->syscon =
syscon_regmap_lookup_by_compatible("cirrus,clps711x-syscon1");
if (IS_ERR(priv->syscon))
return PTR_ERR(priv->syscon);
priv->row_count = of_gpio_named_count(np, "row-gpios");
if (priv->row_count < 1)
return -EINVAL;
priv->gpio_data = devm_kzalloc(dev,
sizeof(*priv->gpio_data) * priv->row_count,
GFP_KERNEL);
if (!priv->gpio_data)
return -ENOMEM;
priv->row_shift = get_count_order(CLPS711X_KEYPAD_COL_COUNT);
for (i = 0; i < priv->row_count; i++) {
struct clps711x_gpio_data *data = &priv->gpio_data[i];
data->desc = devm_gpiod_get_index(dev, "row", i);
if (!data->desc)
return -EINVAL;
if (IS_ERR(data->desc))
return PTR_ERR(data->desc);
gpiod_direction_input(data->desc);
}
err = of_property_read_u32(np, "poll-interval", &poll_interval);
if (err)
return err;
poll_dev = input_allocate_polled_device();
if (!poll_dev)
return -ENOMEM;
poll_dev->private = priv;
poll_dev->poll = clps711x_keypad_poll;
poll_dev->poll_interval = poll_interval;
poll_dev->input->name = pdev->name;
poll_dev->input->dev.parent = dev;
poll_dev->input->id.bustype = BUS_HOST;
poll_dev->input->id.vendor = 0x0001;
poll_dev->input->id.product = 0x0001;
poll_dev->input->id.version = 0x0100;
err = matrix_keypad_build_keymap(NULL, NULL, priv->row_count,
CLPS711X_KEYPAD_COL_COUNT,
NULL, poll_dev->input);
if (err)
goto out_err;
input_set_capability(poll_dev->input, EV_MSC, MSC_SCAN);
if (of_property_read_bool(np, "autorepeat"))
__set_bit(EV_REP, poll_dev->input->evbit);
platform_set_drvdata(pdev, poll_dev);
/* Set all columns to low */
regmap_update_bits(priv->syscon, SYSCON_OFFSET, SYSCON1_KBDSCAN_MASK,
SYSCON1_KBDSCAN(1));
err = input_register_polled_device(poll_dev);
if (err)
goto out_err;
return 0;
out_err:
input_free_polled_device(poll_dev);
return err;
}
static int clps711x_keypad_remove(struct platform_device *pdev)
{
struct input_polled_dev *poll_dev = platform_get_drvdata(pdev);
input_unregister_polled_device(poll_dev);
input_free_polled_device(poll_dev);
return 0;
}
static struct of_device_id clps711x_keypad_of_match[] = {
{ .compatible = "cirrus,clps711x-keypad", },
{ }
};
MODULE_DEVICE_TABLE(of, clps711x_keypad_of_match);
static struct platform_driver clps711x_keypad_driver = {
.driver = {
.name = "clps711x-keypad",
.owner = THIS_MODULE,
.of_match_table = clps711x_keypad_of_match,
},
.probe = clps711x_keypad_probe,
.remove = clps711x_keypad_remove,
};
module_platform_driver(clps711x_keypad_driver);
MODULE_AUTHOR("Alexander Shiyan <shc_work@mail.ru>");
MODULE_DESCRIPTION("Cirrus Logic CLPS711X Keypad driver");
MODULE_LICENSE("GPL");
......@@ -439,7 +439,7 @@ static int imx_keypad_probe(struct platform_device *pdev)
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
dev_err(&pdev->dev, "no irq defined in platform data\n");
return -EINVAL;
return irq;
}
input_dev = devm_input_allocate_device(&pdev->dev);
......@@ -449,7 +449,7 @@ static int imx_keypad_probe(struct platform_device *pdev)
}
keypad = devm_kzalloc(&pdev->dev, sizeof(struct imx_keypad),
GFP_KERNEL);
GFP_KERNEL);
if (!keypad) {
dev_err(&pdev->dev, "not enough memory for driver data\n");
return -ENOMEM;
......
This diff is collapsed.
/*
* Texas Instruments TNETV107X Keypad Driver
*
* Copyright (C) 2010 Texas Instruments
*
* 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.
*
* 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/kernel.h>
#include <linux/err.h>
#include <linux/errno.h>
#include <linux/input.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/clk.h>
#include <linux/input/matrix_keypad.h>
#include <linux/module.h>
#define BITS(x) (BIT(x) - 1)
#define KEYPAD_ROWS 9
#define KEYPAD_COLS 9
#define DEBOUNCE_MIN 0x400ul
#define DEBOUNCE_MAX 0x3ffffffful
struct keypad_regs {
u32 rev;
u32 mode;
u32 mask;
u32 pol;
u32 dclock;
u32 rclock;
u32 stable_cnt;
u32 in_en;
u32 out;
u32 out_en;
u32 in;
u32 lock;
u32 pres[3];
};
#define keypad_read(kp, reg) __raw_readl(&(kp)->regs->reg)
#define keypad_write(kp, reg, val) __raw_writel(val, &(kp)->regs->reg)
struct keypad_data {
struct input_dev *input_dev;
struct resource *res;
struct keypad_regs __iomem *regs;
struct clk *clk;
struct device *dev;
spinlock_t lock;
int irq_press;
int irq_release;
int rows, cols, row_shift;
int debounce_ms, active_low;
u32 prev_keys[3];
unsigned short keycodes[];
};
static irqreturn_t keypad_irq(int irq, void *data)
{
struct keypad_data *kp = data;
int i, bit, val, row, col, code;
unsigned long flags;
u32 curr_keys[3];
u32 change;
spin_lock_irqsave(&kp->lock, flags);
memset(curr_keys, 0, sizeof(curr_keys));
if (irq == kp->irq_press)
for (i = 0; i < 3; i++)
curr_keys[i] = keypad_read(kp, pres[i]);
for (i = 0; i < 3; i++) {
change = curr_keys[i] ^ kp->prev_keys[i];
while (change) {
bit = fls(change) - 1;
change ^= BIT(bit);
val = curr_keys[i] & BIT(bit);
bit += i * 32;
row = bit / KEYPAD_COLS;
col = bit % KEYPAD_COLS;
code = MATRIX_SCAN_CODE(row, col, kp->row_shift);
input_event(kp->input_dev, EV_MSC, MSC_SCAN, code);
input_report_key(kp->input_dev, kp->keycodes[code],
val);
}
}
input_sync(kp->input_dev);
memcpy(kp->prev_keys, curr_keys, sizeof(curr_keys));
if (irq == kp->irq_press)
keypad_write(kp, lock, 0); /* Allow hardware updates */
spin_unlock_irqrestore(&kp->lock, flags);
return IRQ_HANDLED;
}
static int keypad_start(struct input_dev *dev)
{
struct keypad_data *kp = input_get_drvdata(dev);
unsigned long mask, debounce, clk_rate_khz;
unsigned long flags;
clk_enable(kp->clk);
clk_rate_khz = clk_get_rate(kp->clk) / 1000;
spin_lock_irqsave(&kp->lock, flags);
/* Initialize device registers */
keypad_write(kp, mode, 0);
mask = BITS(kp->rows) << KEYPAD_COLS;
mask |= BITS(kp->cols);
keypad_write(kp, mask, ~mask);
keypad_write(kp, pol, kp->active_low ? 0 : 0x3ffff);
keypad_write(kp, stable_cnt, 3);
debounce = kp->debounce_ms * clk_rate_khz;
debounce = clamp(debounce, DEBOUNCE_MIN, DEBOUNCE_MAX);
keypad_write(kp, dclock, debounce);
keypad_write(kp, rclock, 4 * debounce);
keypad_write(kp, in_en, 1);
spin_unlock_irqrestore(&kp->lock, flags);
return 0;
}
static void keypad_stop(struct input_dev *dev)
{
struct keypad_data *kp = input_get_drvdata(dev);
synchronize_irq(kp->irq_press);
synchronize_irq(kp->irq_release);
clk_disable(kp->clk);
}
static int keypad_probe(struct platform_device *pdev)
{
const struct matrix_keypad_platform_data *pdata;
const struct matrix_keymap_data *keymap_data;
struct device *dev = &pdev->dev;
struct keypad_data *kp;
int error = 0, sz, row_shift;
u32 rev = 0;
pdata = dev_get_platdata(&pdev->dev);
if (!pdata) {
dev_err(dev, "cannot find device data\n");
return -EINVAL;
}
keymap_data = pdata->keymap_data;
if (!keymap_data) {
dev_err(dev, "cannot find keymap data\n");
return -EINVAL;
}
row_shift = get_count_order(pdata->num_col_gpios);
sz = offsetof(struct keypad_data, keycodes);
sz += (pdata->num_row_gpios << row_shift) * sizeof(kp->keycodes[0]);
kp = kzalloc(sz, GFP_KERNEL);
if (!kp) {
dev_err(dev, "cannot allocate device info\n");
return -ENOMEM;
}
kp->dev = dev;
kp->rows = pdata->num_row_gpios;
kp->cols = pdata->num_col_gpios;
kp->row_shift = row_shift;
platform_set_drvdata(pdev, kp);
spin_lock_init(&kp->lock);
kp->irq_press = platform_get_irq_byname(pdev, "press");
kp->irq_release = platform_get_irq_byname(pdev, "release");
if (kp->irq_press < 0 || kp->irq_release < 0) {
dev_err(dev, "cannot determine device interrupts\n");
error = -ENODEV;
goto error_res;
}
kp->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!kp->res) {
dev_err(dev, "cannot determine register area\n");
error = -ENODEV;
goto error_res;
}
if (!request_mem_region(kp->res->start, resource_size(kp->res),
pdev->name)) {
dev_err(dev, "cannot claim register memory\n");
kp->res = NULL;
error = -EINVAL;
goto error_res;
}
kp->regs = ioremap(kp->res->start, resource_size(kp->res));
if (!kp->regs) {
dev_err(dev, "cannot map register memory\n");
error = -ENOMEM;
goto error_map;
}
kp->clk = clk_get(dev, NULL);
if (IS_ERR(kp->clk)) {
dev_err(dev, "cannot claim device clock\n");
error = PTR_ERR(kp->clk);
goto error_clk;
}
error = request_threaded_irq(kp->irq_press, NULL, keypad_irq,
IRQF_ONESHOT, dev_name(dev), kp);
if (error < 0) {
dev_err(kp->dev, "Could not allocate keypad press key irq\n");
goto error_irq_press;
}
error = request_threaded_irq(kp->irq_release, NULL, keypad_irq,
IRQF_ONESHOT, dev_name(dev), kp);
if (error < 0) {
dev_err(kp->dev, "Could not allocate keypad release key irq\n");
goto error_irq_release;
}
kp->input_dev = input_allocate_device();
if (!kp->input_dev) {
dev_err(dev, "cannot allocate input device\n");
error = -ENOMEM;
goto error_input;
}
kp->input_dev->name = pdev->name;
kp->input_dev->dev.parent = &pdev->dev;
kp->input_dev->open = keypad_start;
kp->input_dev->close = keypad_stop;
clk_enable(kp->clk);
rev = keypad_read(kp, rev);
kp->input_dev->id.bustype = BUS_HOST;
kp->input_dev->id.product = ((rev >> 8) & 0x07);
kp->input_dev->id.version = ((rev >> 16) & 0xfff);
clk_disable(kp->clk);
error = matrix_keypad_build_keymap(keymap_data, NULL,
kp->rows, kp->cols,
kp->keycodes, kp->input_dev);
if (error) {
dev_err(dev, "Failed to build keymap\n");
goto error_reg;
}
if (!pdata->no_autorepeat)
kp->input_dev->evbit[0] |= BIT_MASK(EV_REP);
input_set_capability(kp->input_dev, EV_MSC, MSC_SCAN);
input_set_drvdata(kp->input_dev, kp);
error = input_register_device(kp->input_dev);
if (error < 0) {
dev_err(dev, "Could not register input device\n");
goto error_reg;
}
return 0;
error_reg:
input_free_device(kp->input_dev);
error_input:
free_irq(kp->irq_release, kp);
error_irq_release:
free_irq(kp->irq_press, kp);
error_irq_press:
clk_put(kp->clk);
error_clk:
iounmap(kp->regs);
error_map:
release_mem_region(kp->res->start, resource_size(kp->res));
error_res:
kfree(kp);
return error;
}
static int keypad_remove(struct platform_device *pdev)
{
struct keypad_data *kp = platform_get_drvdata(pdev);
free_irq(kp->irq_press, kp);
free_irq(kp->irq_release, kp);
input_unregister_device(kp->input_dev);
clk_put(kp->clk);
iounmap(kp->regs);
release_mem_region(kp->res->start, resource_size(kp->res));
kfree(kp);
return 0;
}
static struct platform_driver keypad_driver = {
.probe = keypad_probe,
.remove = keypad_remove,
.driver.name = "tnetv107x-keypad",
.driver.owner = THIS_MODULE,
};
module_platform_driver(keypad_driver);
MODULE_AUTHOR("Cyril Chemparathy");
MODULE_DESCRIPTION("TNETV107X Keypad Driver");
MODULE_ALIAS("platform:tnetv107x-keypad");
MODULE_LICENSE("GPL");
......@@ -269,7 +269,7 @@ config INPUT_COBALT_BTNS
config INPUT_WISTRON_BTNS
tristate "x86 Wistron laptop button interface"
depends on X86 && !X86_64
depends on X86_32
select INPUT_POLLDEV
select INPUT_SPARSEKMAP
select NEW_LEDS
......@@ -666,4 +666,14 @@ config INPUT_IDEAPAD_SLIDEBAR
To compile this driver as a module, choose M here: the
module will be called ideapad_slidebar.
config INPUT_SOC_BUTTON_ARRAY
tristate "Windows-compatible SoC Button Array"
depends on KEYBOARD_GPIO
help
Say Y here if you have a SoC-based tablet that originally
runs Windows 8.
To compile this driver as a module, choose M here: the
module will be called soc_button_array.
endif
......@@ -53,6 +53,7 @@ obj-$(CONFIG_INPUT_RETU_PWRBUTTON) += retu-pwrbutton.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_TWL4030_PWRBUTTON) += twl4030-pwrbutton.o
obj-$(CONFIG_INPUT_TWL4030_VIBRA) += twl4030-vibra.o
......
......@@ -51,6 +51,8 @@ struct ims_pcu_backlight {
#define IMS_PCU_BL_VERSION_LEN (9 + 1)
#define IMS_PCU_BL_RESET_REASON_LEN (2 + 1)
#define IMS_PCU_PCU_B_DEVICE_ID 5
#define IMS_PCU_BUF_SIZE 128
struct ims_pcu {
......@@ -68,6 +70,9 @@ struct ims_pcu {
char bl_version[IMS_PCU_BL_VERSION_LEN];
char reset_reason[IMS_PCU_BL_RESET_REASON_LEN];
int update_firmware_status;
u8 device_id;
u8 ofn_reg_addr;
struct usb_interface *ctrl_intf;
......@@ -371,6 +376,8 @@ static void ims_pcu_destroy_gamepad(struct ims_pcu *pcu)
#define IMS_PCU_CMD_GET_DEVICE_ID 0xae
#define IMS_PCU_CMD_SPECIAL_INFO 0xb0
#define IMS_PCU_CMD_BOOTLOADER 0xb1 /* Pass data to bootloader */
#define IMS_PCU_CMD_OFN_SET_CONFIG 0xb3
#define IMS_PCU_CMD_OFN_GET_CONFIG 0xb4
/* PCU responses */
#define IMS_PCU_RSP_STATUS 0xc0
......@@ -389,6 +396,9 @@ static void ims_pcu_destroy_gamepad(struct ims_pcu *pcu)
#define IMS_PCU_RSP_GET_DEVICE_ID 0xce
#define IMS_PCU_RSP_SPECIAL_INFO 0xd0
#define IMS_PCU_RSP_BOOTLOADER 0xd1 /* Bootloader response */
#define IMS_PCU_RSP_OFN_SET_CONFIG 0xd2
#define IMS_PCU_RSP_OFN_GET_CONFIG 0xd3
#define IMS_PCU_RSP_EVNT_BUTTONS 0xe0 /* Unsolicited, button state */
#define IMS_PCU_GAMEPAD_MASK 0x0001ff80UL /* Bits 7 through 16 */
......@@ -1256,6 +1266,225 @@ static struct attribute_group ims_pcu_attr_group = {
.attrs = ims_pcu_attrs,
};
/* Support for a separate OFN attribute group */
#define OFN_REG_RESULT_OFFSET 2
static int ims_pcu_read_ofn_config(struct ims_pcu *pcu, u8 addr, u8 *data)
{
int error;
s16 result;
error = ims_pcu_execute_command(pcu, OFN_GET_CONFIG,
&addr, sizeof(addr));
if (error)
return error;
result = (s16)get_unaligned_le16(pcu->cmd_buf + OFN_REG_RESULT_OFFSET);
if (result < 0)
return -EIO;
/* We only need LSB */
*data = pcu->cmd_buf[OFN_REG_RESULT_OFFSET];
return 0;
}
static int ims_pcu_write_ofn_config(struct ims_pcu *pcu, u8 addr, u8 data)
{
u8 buffer[] = { addr, data };
int error;
s16 result;
error = ims_pcu_execute_command(pcu, OFN_SET_CONFIG,
&buffer, sizeof(buffer));
if (error)
return error;
result = (s16)get_unaligned_le16(pcu->cmd_buf + OFN_REG_RESULT_OFFSET);
if (result < 0)
return -EIO;
return 0;
}
static ssize_t ims_pcu_ofn_reg_data_show(struct device *dev,
struct device_attribute *dattr,
char *buf)
{
struct usb_interface *intf = to_usb_interface(dev);
struct ims_pcu *pcu = usb_get_intfdata(intf);
int error;
u8 data;
mutex_lock(&pcu->cmd_mutex);
error = ims_pcu_read_ofn_config(pcu, pcu->ofn_reg_addr, &data);
mutex_unlock(&pcu->cmd_mutex);
if (error)
return error;
return scnprintf(buf, PAGE_SIZE, "%x\n", data);
}
static ssize_t ims_pcu_ofn_reg_data_store(struct device *dev,
struct device_attribute *dattr,
const char *buf, size_t count)
{
struct usb_interface *intf = to_usb_interface(dev);
struct ims_pcu *pcu = usb_get_intfdata(intf);
int error;
u8 value;
error = kstrtou8(buf, 0, &value);
if (error)
return error;
mutex_lock(&pcu->cmd_mutex);
error = ims_pcu_write_ofn_config(pcu, pcu->ofn_reg_addr, value);
mutex_unlock(&pcu->cmd_mutex);
return error ?: count;
}
static DEVICE_ATTR(reg_data, S_IRUGO | S_IWUSR,
ims_pcu_ofn_reg_data_show, ims_pcu_ofn_reg_data_store);
static ssize_t ims_pcu_ofn_reg_addr_show(struct device *dev,
struct device_attribute *dattr,
char *buf)
{
struct usb_interface *intf = to_usb_interface(dev);
struct ims_pcu *pcu = usb_get_intfdata(intf);
int error;
mutex_lock(&pcu->cmd_mutex);
error = scnprintf(buf, PAGE_SIZE, "%x\n", pcu->ofn_reg_addr);
mutex_unlock(&pcu->cmd_mutex);
return error;
}
static ssize_t ims_pcu_ofn_reg_addr_store(struct device *dev,
struct device_attribute *dattr,
const char *buf, size_t count)
{
struct usb_interface *intf = to_usb_interface(dev);
struct ims_pcu *pcu = usb_get_intfdata(intf);
int error;
u8 value;
error = kstrtou8(buf, 0, &value);
if (error)
return error;
mutex_lock(&pcu->cmd_mutex);
pcu->ofn_reg_addr = value;
mutex_unlock(&pcu->cmd_mutex);
return error ?: count;
}
static DEVICE_ATTR(reg_addr, S_IRUGO | S_IWUSR,
ims_pcu_ofn_reg_addr_show, ims_pcu_ofn_reg_addr_store);
struct ims_pcu_ofn_bit_attribute {
struct device_attribute dattr;
u8 addr;
u8 nr;
};
static ssize_t ims_pcu_ofn_bit_show(struct device *dev,
struct device_attribute *dattr,
char *buf)
{
struct usb_interface *intf = to_usb_interface(dev);
struct ims_pcu *pcu = usb_get_intfdata(intf);
struct ims_pcu_ofn_bit_attribute *attr =
container_of(dattr, struct ims_pcu_ofn_bit_attribute, dattr);
int error;
u8 data;
mutex_lock(&pcu->cmd_mutex);
error = ims_pcu_read_ofn_config(pcu, attr->addr, &data);
mutex_unlock(&pcu->cmd_mutex);
if (error)
return error;
return scnprintf(buf, PAGE_SIZE, "%d\n", !!(data & (1 << attr->nr)));
}
static ssize_t ims_pcu_ofn_bit_store(struct device *dev,
struct device_attribute *dattr,
const char *buf, size_t count)
{
struct usb_interface *intf = to_usb_interface(dev);
struct ims_pcu *pcu = usb_get_intfdata(intf);
struct ims_pcu_ofn_bit_attribute *attr =
container_of(dattr, struct ims_pcu_ofn_bit_attribute, dattr);
int error;
int value;
u8 data;
error = kstrtoint(buf, 0, &value);
if (error)
return error;
if (value > 1)
return -EINVAL;
mutex_lock(&pcu->cmd_mutex);
error = ims_pcu_read_ofn_config(pcu, attr->addr, &data);
if (!error) {
if (value)
data |= 1U << attr->nr;
else
data &= ~(1U << attr->nr);
error = ims_pcu_write_ofn_config(pcu, attr->addr, data);
}
mutex_unlock(&pcu->cmd_mutex);
return error ?: count;
}
#define IMS_PCU_OFN_BIT_ATTR(_field, _addr, _nr) \
struct ims_pcu_ofn_bit_attribute ims_pcu_ofn_attr_##_field = { \
.dattr = __ATTR(_field, S_IWUSR | S_IRUGO, \
ims_pcu_ofn_bit_show, ims_pcu_ofn_bit_store), \
.addr = _addr, \
.nr = _nr, \
}
static IMS_PCU_OFN_BIT_ATTR(engine_enable, 0x60, 7);
static IMS_PCU_OFN_BIT_ATTR(speed_enable, 0x60, 6);
static IMS_PCU_OFN_BIT_ATTR(assert_enable, 0x60, 5);
static IMS_PCU_OFN_BIT_ATTR(xyquant_enable, 0x60, 4);
static IMS_PCU_OFN_BIT_ATTR(xyscale_enable, 0x60, 1);
static IMS_PCU_OFN_BIT_ATTR(scale_x2, 0x63, 6);
static IMS_PCU_OFN_BIT_ATTR(scale_y2, 0x63, 7);
static struct attribute *ims_pcu_ofn_attrs[] = {
&dev_attr_reg_data.attr,
&dev_attr_reg_addr.attr,
&ims_pcu_ofn_attr_engine_enable.dattr.attr,
&ims_pcu_ofn_attr_speed_enable.dattr.attr,
&ims_pcu_ofn_attr_assert_enable.dattr.attr,
&ims_pcu_ofn_attr_xyquant_enable.dattr.attr,
&ims_pcu_ofn_attr_xyscale_enable.dattr.attr,
&ims_pcu_ofn_attr_scale_x2.dattr.attr,
&ims_pcu_ofn_attr_scale_y2.dattr.attr,
NULL
};
static struct attribute_group ims_pcu_ofn_attr_group = {
.name = "ofn",
.attrs = ims_pcu_ofn_attrs,
};
static void ims_pcu_irq(struct urb *urb)
{
struct ims_pcu *pcu = urb->context;
......@@ -1624,7 +1853,6 @@ static int ims_pcu_init_application_mode(struct ims_pcu *pcu)
static atomic_t device_no = ATOMIC_INIT(0);
const struct ims_pcu_device_info *info;
u8 device_id;
int error;
error = ims_pcu_get_device_info(pcu);
......@@ -1633,7 +1861,7 @@ static int ims_pcu_init_application_mode(struct ims_pcu *pcu)
return error;
}
error = ims_pcu_identify_type(pcu, &device_id);
error = ims_pcu_identify_type(pcu, &pcu->device_id);
if (error) {
dev_err(pcu->dev,
"Failed to identify device, error: %d\n", error);
......@@ -1645,9 +1873,9 @@ static int ims_pcu_init_application_mode(struct ims_pcu *pcu)
return 0;
}
if (device_id >= ARRAY_SIZE(ims_pcu_device_info) ||
!ims_pcu_device_info[device_id].keymap) {
dev_err(pcu->dev, "Device ID %d is not valid\n", device_id);
if (pcu->device_id >= ARRAY_SIZE(ims_pcu_device_info) ||
!ims_pcu_device_info[pcu->device_id].keymap) {
dev_err(pcu->dev, "Device ID %d is not valid\n", pcu->device_id);
/* Same as above, punt to userspace */
return 0;
}
......@@ -1655,11 +1883,21 @@ static int ims_pcu_init_application_mode(struct ims_pcu *pcu)
/* Device appears to be operable, complete initialization */
pcu->device_no = atomic_inc_return(&device_no) - 1;
/*
* PCU-B devices, both GEN_1 and GEN_2 do not have OFN sensor
*/
if (pcu->device_id != IMS_PCU_PCU_B_DEVICE_ID) {
error = sysfs_create_group(&pcu->dev->kobj,
&ims_pcu_ofn_attr_group);
if (error)
return error;
}
error = ims_pcu_setup_backlight(pcu);
if (error)
return error;
info = &ims_pcu_device_info[device_id];
info = &ims_pcu_device_info[pcu->device_id];
error = ims_pcu_setup_buttons(pcu, info->keymap, info->keymap_len);
if (error)
goto err_destroy_backlight;
......@@ -1674,10 +1912,10 @@ static int ims_pcu_init_application_mode(struct ims_pcu *pcu)
return 0;
err_destroy_backlight:
ims_pcu_destroy_backlight(pcu);
err_destroy_buttons:
ims_pcu_destroy_buttons(pcu);
err_destroy_backlight:
ims_pcu_destroy_backlight(pcu);
return error;
}
......@@ -1691,6 +1929,10 @@ static void ims_pcu_destroy_application_mode(struct ims_pcu *pcu)
ims_pcu_destroy_gamepad(pcu);
ims_pcu_destroy_buttons(pcu);
ims_pcu_destroy_backlight(pcu);
if (pcu->device_id != IMS_PCU_PCU_B_DEVICE_ID)
sysfs_remove_group(&pcu->dev->kobj,
&ims_pcu_ofn_attr_group);
}
}
......
......@@ -142,7 +142,6 @@ static int pm8xxx_vib_play_effect(struct input_dev *dev, void *data,
}
static int pm8xxx_vib_probe(struct platform_device *pdev)
{
struct pm8xxx_vib *vib;
struct input_dev *input_dev;
......@@ -214,12 +213,20 @@ static int pm8xxx_vib_suspend(struct device *dev)
static SIMPLE_DEV_PM_OPS(pm8xxx_vib_pm_ops, pm8xxx_vib_suspend, NULL);
static const struct of_device_id pm8xxx_vib_id_table[] = {
{ .compatible = "qcom,pm8058-vib" },
{ .compatible = "qcom,pm8921-vib" },
{ }
};
MODULE_DEVICE_TABLE(of, pm8xxx_vib_id_table);
static struct platform_driver pm8xxx_vib_driver = {
.probe = pm8xxx_vib_probe,
.driver = {
.name = "pm8xxx-vib",
.owner = THIS_MODULE,
.pm = &pm8xxx_vib_pm_ops,
.of_match_table = pm8xxx_vib_id_table,
},
};
module_platform_driver(pm8xxx_vib_driver);
......
......@@ -19,8 +19,7 @@
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/log2.h>
#include <linux/input/pmic8xxx-pwrkey.h>
#include <linux/of.h>
#define PON_CNTL_1 0x1C
#define PON_CNTL_PULL_UP BIT(7)
......@@ -89,15 +88,15 @@ static int pmic8xxx_pwrkey_probe(struct platform_device *pdev)
unsigned int pon_cntl;
struct regmap *regmap;
struct pmic8xxx_pwrkey *pwrkey;
const struct pm8xxx_pwrkey_platform_data *pdata =
dev_get_platdata(&pdev->dev);
u32 kpd_delay;
bool pull_up;
if (!pdata) {
dev_err(&pdev->dev, "power key platform data not supplied\n");
return -EINVAL;
}
if (of_property_read_u32(pdev->dev.of_node, "debounce", &kpd_delay))
kpd_delay = 0;
if (pdata->kpd_trigger_delay_us > 62500) {
pull_up = of_property_read_bool(pdev->dev.of_node, "pull-up");
if (kpd_delay > 62500) {
dev_err(&pdev->dev, "invalid power key trigger delay\n");
return -EINVAL;
}
......@@ -125,7 +124,7 @@ static int pmic8xxx_pwrkey_probe(struct platform_device *pdev)
pwr->name = "pmic8xxx_pwrkey";
pwr->phys = "pmic8xxx_pwrkey/input0";
delay = (pdata->kpd_trigger_delay_us << 10) / USEC_PER_SEC;
delay = (kpd_delay << 10) / USEC_PER_SEC;
delay = 1 + ilog2(delay);
err = regmap_read(regmap, PON_CNTL_1, &pon_cntl);
......@@ -136,7 +135,7 @@ static int pmic8xxx_pwrkey_probe(struct platform_device *pdev)
pon_cntl &= ~PON_CNTL_TRIG_DELAY_MASK;
pon_cntl |= (delay & PON_CNTL_TRIG_DELAY_MASK);
if (pdata->pull_up)
if (pull_up)
pon_cntl |= PON_CNTL_PULL_UP;
else
pon_cntl &= ~PON_CNTL_PULL_UP;
......@@ -172,7 +171,7 @@ static int pmic8xxx_pwrkey_probe(struct platform_device *pdev)
}
platform_set_drvdata(pdev, pwrkey);
device_init_wakeup(&pdev->dev, pdata->wakeup);
device_init_wakeup(&pdev->dev, 1);
return 0;
}
......@@ -184,13 +183,21 @@ static int pmic8xxx_pwrkey_remove(struct platform_device *pdev)
return 0;
}
static const struct of_device_id pm8xxx_pwr_key_id_table[] = {
{ .compatible = "qcom,pm8058-pwrkey" },
{ .compatible = "qcom,pm8921-pwrkey" },
{ }
};
MODULE_DEVICE_TABLE(of, pm8xxx_pwr_key_id_table);
static struct platform_driver pmic8xxx_pwrkey_driver = {
.probe = pmic8xxx_pwrkey_probe,
.remove = pmic8xxx_pwrkey_remove,
.driver = {
.name = PM8XXX_PWRKEY_DEV_NAME,
.name = "pm8xxx-pwrkey",
.owner = THIS_MODULE,
.pm = &pm8xxx_pwr_key_pm_ops,
.of_match_table = pm8xxx_pwr_key_id_table,
},
};
module_platform_driver(pmic8xxx_pwrkey_driver);
......
/*
* Power key driver for SiRF PrimaII
*
* Copyright (c) 2013 Cambridge Silicon Radio Limited, a CSR plc group company.
* Copyright (c) 2013 - 2014 Cambridge Silicon Radio Limited, a CSR plc group
* company.
*
* Licensed under GPLv2 or later.
*/
......@@ -13,16 +14,41 @@
#include <linux/input.h>
#include <linux/rtc/sirfsoc_rtciobrg.h>
#include <linux/of.h>
#include <linux/workqueue.h>
struct sirfsoc_pwrc_drvdata {
u32 pwrc_base;
struct input_dev *input;
struct delayed_work work;
};
#define PWRC_ON_KEY_BIT (1 << 0)
#define PWRC_INT_STATUS 0xc
#define PWRC_INT_MASK 0x10
#define PWRC_PIN_STATUS 0x14
#define PWRC_KEY_DETECT_UP_TIME 20 /* ms*/
static int sirfsoc_pwrc_is_on_key_down(struct sirfsoc_pwrc_drvdata *pwrcdrv)
{
u32 state = sirfsoc_rtc_iobrg_readl(pwrcdrv->pwrc_base +
PWRC_PIN_STATUS);
return !(state & PWRC_ON_KEY_BIT); /* ON_KEY is active low */
}
static void sirfsoc_pwrc_report_event(struct work_struct *work)
{
struct sirfsoc_pwrc_drvdata *pwrcdrv =
container_of(work, struct sirfsoc_pwrc_drvdata, work.work);
if (sirfsoc_pwrc_is_on_key_down(pwrcdrv)) {
schedule_delayed_work(&pwrcdrv->work,
msecs_to_jiffies(PWRC_KEY_DETECT_UP_TIME));
} else {
input_event(pwrcdrv->input, EV_KEY, KEY_POWER, 0);
input_sync(pwrcdrv->input);
}
}
static irqreturn_t sirfsoc_pwrc_isr(int irq, void *dev_id)
{
......@@ -34,21 +60,44 @@ static irqreturn_t sirfsoc_pwrc_isr(int irq, void *dev_id)
sirfsoc_rtc_iobrg_writel(int_status & ~PWRC_ON_KEY_BIT,
pwrcdrv->pwrc_base + PWRC_INT_STATUS);
/*
* For a typical Linux system, we report KEY_SUSPEND to trigger apm-power.c
* to queue a SUSPEND APM event
*/
input_event(pwrcdrv->input, EV_PWR, KEY_SUSPEND, 1);
input_event(pwrcdrv->input, EV_KEY, KEY_POWER, 1);
input_sync(pwrcdrv->input);
/*
* Todo: report KEY_POWER event for Android platforms, Android PowerManager
* will handle the suspend and powerdown/hibernation
*/
schedule_delayed_work(&pwrcdrv->work,
msecs_to_jiffies(PWRC_KEY_DETECT_UP_TIME));
return IRQ_HANDLED;
}
static void sirfsoc_pwrc_toggle_interrupts(struct sirfsoc_pwrc_drvdata *pwrcdrv,
bool enable)
{
u32 int_mask;
int_mask = sirfsoc_rtc_iobrg_readl(pwrcdrv->pwrc_base + PWRC_INT_MASK);
if (enable)
int_mask |= PWRC_ON_KEY_BIT;
else
int_mask &= ~PWRC_ON_KEY_BIT;
sirfsoc_rtc_iobrg_writel(int_mask, pwrcdrv->pwrc_base + PWRC_INT_MASK);
}
static int sirfsoc_pwrc_open(struct input_dev *input)
{
struct sirfsoc_pwrc_drvdata *pwrcdrv = input_get_drvdata(input);
sirfsoc_pwrc_toggle_interrupts(pwrcdrv, true);
return 0;
}
static void sirfsoc_pwrc_close(struct input_dev *input)
{
struct sirfsoc_pwrc_drvdata *pwrcdrv = input_get_drvdata(input);
sirfsoc_pwrc_toggle_interrupts(pwrcdrv, false);
cancel_delayed_work_sync(&pwrcdrv->work);
}
static const struct of_device_id sirfsoc_pwrc_of_match[] = {
{ .compatible = "sirf,prima2-pwrc" },
{},
......@@ -70,7 +119,7 @@ static int sirfsoc_pwrc_probe(struct platform_device *pdev)
}
/*
* we can't use of_iomap because pwrc is not mapped in memory,
* We can't use of_iomap because pwrc is not mapped in memory,
* the so-called base address is only offset in rtciobrg
*/
error = of_property_read_u32(np, "reg", &pwrcdrv->pwrc_base);
......@@ -86,11 +135,22 @@ static int sirfsoc_pwrc_probe(struct platform_device *pdev)
pwrcdrv->input->name = "sirfsoc pwrckey";
pwrcdrv->input->phys = "pwrc/input0";
pwrcdrv->input->evbit[0] = BIT_MASK(EV_PWR);
pwrcdrv->input->evbit[0] = BIT_MASK(EV_KEY);
input_set_capability(pwrcdrv->input, EV_KEY, KEY_POWER);
INIT_DELAYED_WORK(&pwrcdrv->work, sirfsoc_pwrc_report_event);
pwrcdrv->input->open = sirfsoc_pwrc_open;
pwrcdrv->input->close = sirfsoc_pwrc_close;
input_set_drvdata(pwrcdrv->input, pwrcdrv);
/* Make sure the device is quiesced */
sirfsoc_pwrc_toggle_interrupts(pwrcdrv, false);
irq = platform_get_irq(pdev, 0);
error = devm_request_irq(&pdev->dev, irq,
sirfsoc_pwrc_isr, IRQF_SHARED,
sirfsoc_pwrc_isr, 0,
"sirfsoc_pwrc_int", pwrcdrv);
if (error) {
dev_err(&pdev->dev, "unable to claim irq %d, error: %d\n",
......@@ -98,11 +158,6 @@ static int sirfsoc_pwrc_probe(struct platform_device *pdev)
return error;
}
sirfsoc_rtc_iobrg_writel(
sirfsoc_rtc_iobrg_readl(pwrcdrv->pwrc_base + PWRC_INT_MASK) |
PWRC_ON_KEY_BIT,
pwrcdrv->pwrc_base + PWRC_INT_MASK);
error = input_register_device(pwrcdrv->input);
if (error) {
dev_err(&pdev->dev,
......@@ -111,7 +166,7 @@ static int sirfsoc_pwrc_probe(struct platform_device *pdev)
return error;
}
platform_set_drvdata(pdev, pwrcdrv);
dev_set_drvdata(&pdev->dev, pwrcdrv);
device_init_wakeup(&pdev->dev, 1);
return 0;
......@@ -125,25 +180,25 @@ static int sirfsoc_pwrc_remove(struct platform_device *pdev)
}
#ifdef CONFIG_PM_SLEEP
static int pwrc_resume(struct device *dev)
static int sirfsoc_pwrc_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct sirfsoc_pwrc_drvdata *pwrcdrv = platform_get_drvdata(pdev);
struct sirfsoc_pwrc_drvdata *pwrcdrv = dev_get_drvdata(dev);
struct input_dev *input = pwrcdrv->input;
/*
* Do not mask pwrc interrupt as we want pwrc work as a wakeup source
* if users touch X_ONKEY_B, see arch/arm/mach-prima2/pm.c
*/
sirfsoc_rtc_iobrg_writel(
sirfsoc_rtc_iobrg_readl(
pwrcdrv->pwrc_base + PWRC_INT_MASK) | PWRC_ON_KEY_BIT,
pwrcdrv->pwrc_base + PWRC_INT_MASK);
mutex_lock(&input->mutex);
if (input->users)
sirfsoc_pwrc_toggle_interrupts(pwrcdrv, true);
mutex_unlock(&input->mutex);
return 0;
}
#endif
static SIMPLE_DEV_PM_OPS(sirfsoc_pwrc_pm_ops, NULL, pwrc_resume);
static SIMPLE_DEV_PM_OPS(sirfsoc_pwrc_pm_ops, NULL, sirfsoc_pwrc_resume);
static struct platform_driver sirfsoc_pwrc_driver = {
.probe = sirfsoc_pwrc_probe,
......
/*
* Supports for the button array on SoC tablets originally running
* Windows 8.
*
* (C) Copyright 2014 Intel Corporation
*
* 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.
*/
#include <linux/module.h>
#include <linux/input.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/acpi.h>
#include <linux/gpio/consumer.h>
#include <linux/gpio_keys.h>
#include <linux/input.h>
#include <linux/platform_device.h>
#include <linux/pnp.h>
/*
* Definition of buttons on the tablet. The ACPI index of each button
* is defined in section 2.8.7.2 of "Windows ACPI Design Guide for SoC
* Platforms"
*/
#define MAX_NBUTTONS 5
struct soc_button_info {
const char *name;
int acpi_index;
unsigned int event_type;
unsigned int event_code;
bool autorepeat;
bool wakeup;
};
/*
* Some of the buttons like volume up/down are auto repeat, while others
* are not. To support both, we register two platform devices, and put
* buttons into them based on whether the key should be auto repeat.
*/
#define BUTTON_TYPES 2
struct soc_button_data {
struct platform_device *children[BUTTON_TYPES];
};
/*
* Get the Nth GPIO number from the ACPI object.
*/
static int soc_button_lookup_gpio(struct device *dev, int acpi_index)
{
struct gpio_desc *desc;
int gpio;
desc = gpiod_get_index(dev, KBUILD_MODNAME, acpi_index);
if (IS_ERR(desc))
return PTR_ERR(desc);
gpio = desc_to_gpio(desc);
gpiod_put(desc);
return gpio;
}
static struct platform_device *
soc_button_device_create(struct pnp_dev *pdev,
const struct soc_button_info *button_info,
bool autorepeat)
{
const struct soc_button_info *info;
struct platform_device *pd;
struct gpio_keys_button *gpio_keys;
struct gpio_keys_platform_data *gpio_keys_pdata;
int n_buttons = 0;
int gpio;
int error;
gpio_keys_pdata = devm_kzalloc(&pdev->dev,
sizeof(*gpio_keys_pdata) +
sizeof(*gpio_keys) * MAX_NBUTTONS,
GFP_KERNEL);
gpio_keys = (void *)(gpio_keys_pdata + 1);
for (info = button_info; info->name; info++) {
if (info->autorepeat != autorepeat)
continue;
gpio = soc_button_lookup_gpio(&pdev->dev, info->acpi_index);
if (gpio < 0)
continue;
gpio_keys[n_buttons].type = info->event_type;
gpio_keys[n_buttons].code = info->event_code;
gpio_keys[n_buttons].gpio = gpio;
gpio_keys[n_buttons].active_low = 1;
gpio_keys[n_buttons].desc = info->name;
gpio_keys[n_buttons].wakeup = info->wakeup;
n_buttons++;
}
if (n_buttons == 0) {
error = -ENODEV;
goto err_free_mem;
}
gpio_keys_pdata->buttons = gpio_keys;
gpio_keys_pdata->nbuttons = n_buttons;
gpio_keys_pdata->rep = autorepeat;
pd = platform_device_alloc("gpio-keys", PLATFORM_DEVID_AUTO);
if (!pd) {
error = -ENOMEM;
goto err_free_mem;
}
error = platform_device_add_data(pd, gpio_keys_pdata,
sizeof(*gpio_keys_pdata));
if (error)
goto err_free_pdev;
error = platform_device_add(pd);
if (error)
goto err_free_pdev;
return pd;
err_free_pdev:
platform_device_put(pd);
err_free_mem:
devm_kfree(&pdev->dev, gpio_keys_pdata);
return ERR_PTR(error);
}
static void soc_button_remove(struct pnp_dev *pdev)
{
struct soc_button_data *priv = pnp_get_drvdata(pdev);
int i;
for (i = 0; i < BUTTON_TYPES; i++)
if (priv->children[i])
platform_device_unregister(priv->children[i]);
}
static int soc_button_pnp_probe(struct pnp_dev *pdev,
const struct pnp_device_id *id)
{
const struct soc_button_info *button_info = (void *)id->driver_data;
struct soc_button_data *priv;
struct platform_device *pd;
int i;
int error;
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
pnp_set_drvdata(pdev, priv);
for (i = 0; i < BUTTON_TYPES; i++) {
pd = soc_button_device_create(pdev, button_info, i == 0);
if (IS_ERR(pd)) {
error = PTR_ERR(pd);
if (error != -ENODEV) {
soc_button_remove(pdev);
return error;
}
}
priv->children[i] = pd;
}
if (!priv->children[0] && !priv->children[1])
return -ENODEV;
return 0;
}
static struct soc_button_info soc_button_PNP0C40[] = {
{ "power", 0, EV_KEY, KEY_POWER, false, true },
{ "home", 1, EV_KEY, KEY_HOME, false, true },
{ "volume_up", 2, EV_KEY, KEY_VOLUMEUP, true, false },
{ "volume_down", 3, EV_KEY, KEY_VOLUMEDOWN, true, false },
{ "rotation_lock", 4, EV_SW, SW_ROTATE_LOCK, false, false },
{ }
};
static const struct pnp_device_id soc_button_pnp_match[] = {
{ .id = "PNP0C40", .driver_data = (long)soc_button_PNP0C40 },
{ .id = "" }
};
MODULE_DEVICE_TABLE(pnp, soc_button_pnp_match);
static struct pnp_driver soc_button_pnp_driver = {
.name = KBUILD_MODNAME,
.id_table = soc_button_pnp_match,
.probe = soc_button_pnp_probe,
.remove = soc_button_remove,
};
static int __init soc_button_init(void)
{
return pnp_register_driver(&soc_button_pnp_driver);
}
static void __exit soc_button_exit(void)
{
pnp_unregister_driver(&soc_button_pnp_driver);
}
module_init(soc_button_init);
module_exit(soc_button_exit);
MODULE_LICENSE("GPL");
......@@ -20,6 +20,8 @@
* Author: Aristeu Sergio Rozanski Filho <aris@cathedrallabs.org>
*
* Changes/Revisions:
* 0.4 01/09/2014 (Benjamin Tissoires <benjamin.tissoires@redhat.com>)
* - add UI_GET_SYSNAME ioctl
* 0.3 09/04/2006 (Anssi Hannula <anssi.hannula@gmail.com>)
* - updated ff support for the changes in kernel interface
* - added MODULE_VERSION
......@@ -670,6 +672,31 @@ static int uinput_ff_upload_from_user(const char __user *buffer,
__ret; \
})
static int uinput_str_to_user(void __user *dest, const char *str,
unsigned int maxlen)
{
char __user *p = dest;
int len, ret;
if (!str)
return -ENOENT;
if (maxlen == 0)
return -EINVAL;
len = strlen(str) + 1;
if (len > maxlen)
len = maxlen;
ret = copy_to_user(p, str, len);
if (ret)
return -EFAULT;
/* force terminating '\0' */
ret = put_user(0, p + len - 1);
return ret ? -EFAULT : len;
}
static long uinput_ioctl_handler(struct file *file, unsigned int cmd,
unsigned long arg, void __user *p)
{
......@@ -679,6 +706,8 @@ static long uinput_ioctl_handler(struct file *file, unsigned int cmd,
struct uinput_ff_erase ff_erase;
struct uinput_request *req;
char *phys;
const char *name;
unsigned int size;
retval = mutex_lock_interruptible(&udev->mutex);
if (retval)
......@@ -693,51 +722,51 @@ static long uinput_ioctl_handler(struct file *file, unsigned int cmd,
switch (cmd) {
case UI_DEV_CREATE:
retval = uinput_create_device(udev);
break;
goto out;
case UI_DEV_DESTROY:
uinput_destroy_device(udev);
break;
goto out;
case UI_SET_EVBIT:
retval = uinput_set_bit(arg, evbit, EV_MAX);
break;
goto out;
case UI_SET_KEYBIT:
retval = uinput_set_bit(arg, keybit, KEY_MAX);
break;
goto out;
case UI_SET_RELBIT:
retval = uinput_set_bit(arg, relbit, REL_MAX);
break;
goto out;
case UI_SET_ABSBIT:
retval = uinput_set_bit(arg, absbit, ABS_MAX);
break;
goto out;
case UI_SET_MSCBIT:
retval = uinput_set_bit(arg, mscbit, MSC_MAX);
break;
goto out;
case UI_SET_LEDBIT:
retval = uinput_set_bit(arg, ledbit, LED_MAX);
break;
goto out;
case UI_SET_SNDBIT:
retval = uinput_set_bit(arg, sndbit, SND_MAX);
break;
goto out;
case UI_SET_FFBIT:
retval = uinput_set_bit(arg, ffbit, FF_MAX);
break;
goto out;
case UI_SET_SWBIT:
retval = uinput_set_bit(arg, swbit, SW_MAX);
break;
goto out;
case UI_SET_PROPBIT:
retval = uinput_set_bit(arg, propbit, INPUT_PROP_MAX);
break;
goto out;
case UI_SET_PHYS:
if (udev->state == UIST_CREATED) {
......@@ -753,18 +782,18 @@ static long uinput_ioctl_handler(struct file *file, unsigned int cmd,
kfree(udev->dev->phys);
udev->dev->phys = phys;
break;
goto out;
case UI_BEGIN_FF_UPLOAD:
retval = uinput_ff_upload_from_user(p, &ff_up);
if (retval)
break;
goto out;
req = uinput_request_find(udev, ff_up.request_id);
if (!req || req->code != UI_FF_UPLOAD ||
!req->u.upload.effect) {
retval = -EINVAL;
break;
goto out;
}
ff_up.retval = 0;
......@@ -775,65 +804,77 @@ static long uinput_ioctl_handler(struct file *file, unsigned int cmd,
memset(&ff_up.old, 0, sizeof(struct ff_effect));
retval = uinput_ff_upload_to_user(p, &ff_up);
break;
goto out;
case UI_BEGIN_FF_ERASE:
if (copy_from_user(&ff_erase, p, sizeof(ff_erase))) {
retval = -EFAULT;
break;
goto out;
}
req = uinput_request_find(udev, ff_erase.request_id);
if (!req || req->code != UI_FF_ERASE) {
retval = -EINVAL;
break;
goto out;
}
ff_erase.retval = 0;
ff_erase.effect_id = req->u.effect_id;
if (copy_to_user(p, &ff_erase, sizeof(ff_erase))) {
retval = -EFAULT;
break;
goto out;
}
break;
goto out;
case UI_END_FF_UPLOAD:
retval = uinput_ff_upload_from_user(p, &ff_up);
if (retval)
break;
goto out;
req = uinput_request_find(udev, ff_up.request_id);
if (!req || req->code != UI_FF_UPLOAD ||
!req->u.upload.effect) {
retval = -EINVAL;
break;
goto out;
}
req->retval = ff_up.retval;
uinput_request_done(udev, req);
break;
goto out;
case UI_END_FF_ERASE:
if (copy_from_user(&ff_erase, p, sizeof(ff_erase))) {
retval = -EFAULT;
break;
goto out;
}
req = uinput_request_find(udev, ff_erase.request_id);
if (!req || req->code != UI_FF_ERASE) {
retval = -EINVAL;
break;
goto out;
}
req->retval = ff_erase.retval;
uinput_request_done(udev, req);
break;
goto out;
}
default:
retval = -EINVAL;
size = _IOC_SIZE(cmd);
/* Now check variable-length commands */
switch (cmd & ~IOCSIZE_MASK) {
case UI_GET_SYSNAME(0):
if (udev->state != UIST_CREATED) {
retval = -ENOENT;
goto out;
}
name = dev_name(&udev->dev->dev);
retval = uinput_str_to_user(p, name, size);
goto out;
}
retval = -EINVAL;
out:
mutex_unlock(&udev->mutex);
return retval;
......
......@@ -277,6 +277,16 @@ static struct key_entry keymap_fs_amilo_pro_v3505[] __initdata = {
{ KE_END, 0 }
};
static struct key_entry keymap_fs_amilo_pro_v8210[] __initdata = {
{ KE_KEY, 0x01, {KEY_HELP} }, /* Fn+F1 */
{ KE_KEY, 0x06, {KEY_DISPLAYTOGGLE} }, /* Fn+F4 */
{ KE_BLUETOOTH, 0x30 }, /* Fn+F10 */
{ KE_KEY, 0x31, {KEY_MAIL} }, /* mail button */
{ KE_KEY, 0x36, {KEY_WWW} }, /* www button */
{ KE_WIFI, 0x78 }, /* satelite dish button */
{ KE_END, FE_WIFI_LED }
};
static struct key_entry keymap_fujitsu_n3510[] __initdata = {
{ KE_KEY, 0x11, {KEY_PROG1} },
{ KE_KEY, 0x12, {KEY_PROG2} },
......@@ -653,6 +663,15 @@ static const struct dmi_system_id dmi_ids[] __initconst = {
},
.driver_data = keymap_fs_amilo_pro_v3505
},
{
/* Fujitsu-Siemens Amilo Pro Edition V8210 */
.callback = dmi_matched,
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pro Series V8210"),
},
.driver_data = keymap_fs_amilo_pro_v8210
},
{
/* Fujitsu-Siemens Amilo M7400 */
.callback = dmi_matched,
......
This diff is collapsed.
......@@ -263,7 +263,7 @@ config SERIO_APBPS2
config SERIO_OLPC_APSP
tristate "OLPC AP-SP input support"
depends on OF
depends on OLPC || COMPILE_TEST
help
Say Y here if you want support for the keyboard and touchpad included
in the OLPC XO-1.75 and XO-4 laptops.
......
......@@ -984,7 +984,7 @@ static void hp_sdc_exit(void)
free_irq(hp_sdc.irq, &hp_sdc);
write_unlock_irq(&hp_sdc.lock);
del_timer(&hp_sdc.kicker);
del_timer_sync(&hp_sdc.kicker);
tasklet_kill(&hp_sdc.task);
......
......@@ -848,7 +848,7 @@ static int gtco_probe(struct usb_interface *usbinterface,
gtco->inputdevice = input_dev;
/* Save interface information */
gtco->usbdev = usb_get_dev(interface_to_usbdev(usbinterface));
gtco->usbdev = interface_to_usbdev(usbinterface);
gtco->intf = usbinterface;
/* Allocate some data for incoming reports */
......
......@@ -514,15 +514,6 @@ config TOUCHSCREEN_MIGOR
To compile this driver as a module, choose M here: the
module will be called migor_ts.
config TOUCHSCREEN_TNETV107X
tristate "TI TNETV107X touchscreen support"
depends on ARCH_DAVINCI_TNETV107X
help
Say Y here if you want to use the TNETV107X touchscreen.
To compile this driver as a module, choose M here: the
module will be called tnetv107x-ts.
config TOUCHSCREEN_TOUCHRIGHT
tristate "Touchright serial touchscreen"
select SERIO
......
......@@ -56,7 +56,6 @@ obj-$(CONFIG_TOUCHSCREEN_ST1232) += st1232.o
obj-$(CONFIG_TOUCHSCREEN_STMPE) += stmpe-ts.o
obj-$(CONFIG_TOUCHSCREEN_SUR40) += sur40.o
obj-$(CONFIG_TOUCHSCREEN_TI_AM335X_TSC) += ti_am335x_tsc.o
obj-$(CONFIG_TOUCHSCREEN_TNETV107X) += tnetv107x-ts.o
obj-$(CONFIG_TOUCHSCREEN_TOUCHIT213) += touchit213.o
obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT) += touchright.o
obj-$(CONFIG_TOUCHSCREEN_TOUCHWIN) += touchwin.o
......
This diff is collapsed.
/*
* Texas Instruments TNETV107X Touchscreen Driver
*
* Copyright (C) 2010 Texas Instruments
*
* 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.
*
* 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/module.h>
#include <linux/kernel.h>
#include <linux/err.h>
#include <linux/errno.h>
#include <linux/input.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/ctype.h>
#include <linux/io.h>
#include <linux/clk.h>
#include <mach/tnetv107x.h>
#define TSC_PENUP_POLL (HZ / 5)
#define IDLE_TIMEOUT 100 /* msec */
/*
* The first and last samples of a touch interval are usually garbage and need
* to be filtered out with these devices. The following definitions control
* the number of samples skipped.
*/
#define TSC_HEAD_SKIP 1
#define TSC_TAIL_SKIP 1
#define TSC_SKIP (TSC_HEAD_SKIP + TSC_TAIL_SKIP + 1)
#define TSC_SAMPLES (TSC_SKIP + 1)
/* Register Offsets */
struct tsc_regs {
u32 rev;
u32 tscm;
u32 bwcm;
u32 swc;
u32 adcchnl;
u32 adcdata;
u32 chval[4];
};
/* TSC Mode Configuration Register (tscm) bits */
#define WMODE BIT(0)
#define TSKIND BIT(1)
#define ZMEASURE_EN BIT(2)
#define IDLE BIT(3)
#define TSC_EN BIT(4)
#define STOP BIT(5)
#define ONE_SHOT BIT(6)
#define SINGLE BIT(7)
#define AVG BIT(8)
#define AVGNUM(x) (((x) & 0x03) << 9)
#define PVSTC(x) (((x) & 0x07) << 11)
#define PON BIT(14)
#define PONBG BIT(15)
#define AFERST BIT(16)
/* ADC DATA Capture Register bits */
#define DATA_VALID BIT(16)
/* Register Access Macros */
#define tsc_read(ts, reg) __raw_readl(&(ts)->regs->reg)
#define tsc_write(ts, reg, val) __raw_writel(val, &(ts)->regs->reg);
#define tsc_set_bits(ts, reg, val) \
tsc_write(ts, reg, tsc_read(ts, reg) | (val))
#define tsc_clr_bits(ts, reg, val) \
tsc_write(ts, reg, tsc_read(ts, reg) & ~(val))
struct sample {
int x, y, p;
};
struct tsc_data {
struct input_dev *input_dev;
struct resource *res;
struct tsc_regs __iomem *regs;
struct timer_list timer;
spinlock_t lock;
struct clk *clk;
struct device *dev;
int sample_count;
struct sample samples[TSC_SAMPLES];
int tsc_irq;
};
static int tsc_read_sample(struct tsc_data *ts, struct sample* sample)
{
int x, y, z1, z2, t, p = 0;
u32 val;
val = tsc_read(ts, chval[0]);
if (val & DATA_VALID)
x = val & 0xffff;
else
return -EINVAL;
y = tsc_read(ts, chval[1]) & 0xffff;
z1 = tsc_read(ts, chval[2]) & 0xffff;
z2 = tsc_read(ts, chval[3]) & 0xffff;
if (z1) {
t = ((600 * x) * (z2 - z1));
p = t / (u32) (z1 << 12);
if (p < 0)
p = 0;
}
sample->x = x;
sample->y = y;
sample->p = p;
return 0;
}
static void tsc_poll(unsigned long data)
{
struct tsc_data *ts = (struct tsc_data *)data;
unsigned long flags;
int i, val, x, y, p;
spin_lock_irqsave(&ts->lock, flags);
if (ts->sample_count >= TSC_SKIP) {
input_report_abs(ts->input_dev, ABS_PRESSURE, 0);
input_report_key(ts->input_dev, BTN_TOUCH, 0);
input_sync(ts->input_dev);
} else if (ts->sample_count > 0) {
/*
* A touch event lasted less than our skip count. Salvage and
* report anyway.
*/
for (i = 0, val = 0; i < ts->sample_count; i++)
val += ts->samples[i].x;
x = val / ts->sample_count;
for (i = 0, val = 0; i < ts->sample_count; i++)
val += ts->samples[i].y;
y = val / ts->sample_count;
for (i = 0, val = 0; i < ts->sample_count; i++)
val += ts->samples[i].p;
p = val / ts->sample_count;
input_report_abs(ts->input_dev, ABS_X, x);
input_report_abs(ts->input_dev, ABS_Y, y);
input_report_abs(ts->input_dev, ABS_PRESSURE, p);
input_report_key(ts->input_dev, BTN_TOUCH, 1);
input_sync(ts->input_dev);
}
ts->sample_count = 0;
spin_unlock_irqrestore(&ts->lock, flags);
}
static irqreturn_t tsc_irq(int irq, void *dev_id)
{
struct tsc_data *ts = (struct tsc_data *)dev_id;
struct sample *sample;
int index;
spin_lock(&ts->lock);
index = ts->sample_count % TSC_SAMPLES;
sample = &ts->samples[index];
if (tsc_read_sample(ts, sample) < 0)
goto out;
if (++ts->sample_count >= TSC_SKIP) {
index = (ts->sample_count - TSC_TAIL_SKIP - 1) % TSC_SAMPLES;
sample = &ts->samples[index];
input_report_abs(ts->input_dev, ABS_X, sample->x);
input_report_abs(ts->input_dev, ABS_Y, sample->y);
input_report_abs(ts->input_dev, ABS_PRESSURE, sample->p);
if (ts->sample_count == TSC_SKIP)
input_report_key(ts->input_dev, BTN_TOUCH, 1);
input_sync(ts->input_dev);
}
mod_timer(&ts->timer, jiffies + TSC_PENUP_POLL);
out:
spin_unlock(&ts->lock);
return IRQ_HANDLED;
}
static int tsc_start(struct input_dev *dev)
{
struct tsc_data *ts = input_get_drvdata(dev);
unsigned long timeout = jiffies + msecs_to_jiffies(IDLE_TIMEOUT);
u32 val;
clk_enable(ts->clk);
/* Go to idle mode, before any initialization */
while (time_after(timeout, jiffies)) {
if (tsc_read(ts, tscm) & IDLE)
break;
}
if (time_before(timeout, jiffies)) {
dev_warn(ts->dev, "timeout waiting for idle\n");
clk_disable(ts->clk);
return -EIO;
}
/* Configure TSC Control register*/
val = (PONBG | PON | PVSTC(4) | ONE_SHOT | ZMEASURE_EN);
tsc_write(ts, tscm, val);
/* Bring TSC out of reset: Clear AFE reset bit */
val &= ~(AFERST);
tsc_write(ts, tscm, val);
/* Configure all pins for hardware control*/
tsc_write(ts, bwcm, 0);
/* Finally enable the TSC */
tsc_set_bits(ts, tscm, TSC_EN);
return 0;
}
static void tsc_stop(struct input_dev *dev)
{
struct tsc_data *ts = input_get_drvdata(dev);
tsc_clr_bits(ts, tscm, TSC_EN);
synchronize_irq(ts->tsc_irq);
del_timer_sync(&ts->timer);
clk_disable(ts->clk);
}
static int tsc_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct tsc_data *ts;
int error = 0;
u32 rev = 0;
ts = kzalloc(sizeof(struct tsc_data), GFP_KERNEL);
if (!ts) {
dev_err(dev, "cannot allocate device info\n");
return -ENOMEM;
}
ts->dev = dev;
spin_lock_init(&ts->lock);
setup_timer(&ts->timer, tsc_poll, (unsigned long)ts);
platform_set_drvdata(pdev, ts);
ts->tsc_irq = platform_get_irq(pdev, 0);
if (ts->tsc_irq < 0) {
dev_err(dev, "cannot determine device interrupt\n");
error = -ENODEV;
goto error_res;
}
ts->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!ts->res) {
dev_err(dev, "cannot determine register area\n");
error = -ENODEV;
goto error_res;
}
if (!request_mem_region(ts->res->start, resource_size(ts->res),
pdev->name)) {
dev_err(dev, "cannot claim register memory\n");
ts->res = NULL;
error = -EINVAL;
goto error_res;
}
ts->regs = ioremap(ts->res->start, resource_size(ts->res));
if (!ts->regs) {
dev_err(dev, "cannot map register memory\n");
error = -ENOMEM;
goto error_map;
}
ts->clk = clk_get(dev, NULL);
if (IS_ERR(ts->clk)) {
dev_err(dev, "cannot claim device clock\n");
error = PTR_ERR(ts->clk);
goto error_clk;
}
error = request_threaded_irq(ts->tsc_irq, NULL, tsc_irq, IRQF_ONESHOT,
dev_name(dev), ts);
if (error < 0) {
dev_err(ts->dev, "Could not allocate ts irq\n");
goto error_irq;
}
ts->input_dev = input_allocate_device();
if (!ts->input_dev) {
dev_err(dev, "cannot allocate input device\n");
error = -ENOMEM;
goto error_input;
}
input_set_drvdata(ts->input_dev, ts);
ts->input_dev->name = pdev->name;
ts->input_dev->id.bustype = BUS_HOST;
ts->input_dev->dev.parent = &pdev->dev;
ts->input_dev->open = tsc_start;
ts->input_dev->close = tsc_stop;
clk_enable(ts->clk);
rev = tsc_read(ts, rev);
ts->input_dev->id.product = ((rev >> 8) & 0x07);
ts->input_dev->id.version = ((rev >> 16) & 0xfff);
clk_disable(ts->clk);
__set_bit(EV_KEY, ts->input_dev->evbit);
__set_bit(EV_ABS, ts->input_dev->evbit);
__set_bit(BTN_TOUCH, ts->input_dev->keybit);
input_set_abs_params(ts->input_dev, ABS_X, 0, 0xffff, 5, 0);
input_set_abs_params(ts->input_dev, ABS_Y, 0, 0xffff, 5, 0);
input_set_abs_params(ts->input_dev, ABS_PRESSURE, 0, 4095, 128, 0);
error = input_register_device(ts->input_dev);
if (error < 0) {
dev_err(dev, "failed input device registration\n");
goto error_reg;
}
return 0;
error_reg:
input_free_device(ts->input_dev);
error_input:
free_irq(ts->tsc_irq, ts);
error_irq:
clk_put(ts->clk);
error_clk:
iounmap(ts->regs);
error_map:
release_mem_region(ts->res->start, resource_size(ts->res));
error_res:
kfree(ts);
return error;
}
static int tsc_remove(struct platform_device *pdev)
{
struct tsc_data *ts = platform_get_drvdata(pdev);
input_unregister_device(ts->input_dev);
free_irq(ts->tsc_irq, ts);
clk_put(ts->clk);
iounmap(ts->regs);
release_mem_region(ts->res->start, resource_size(ts->res));
kfree(ts);
return 0;
}
static struct platform_driver tsc_driver = {
.probe = tsc_probe,
.remove = tsc_remove,
.driver.name = "tnetv107x-ts",
.driver.owner = THIS_MODULE,
};
module_platform_driver(tsc_driver);
MODULE_AUTHOR("Cyril Chemparathy");
MODULE_DESCRIPTION("TNETV107X Touchscreen Driver");
MODULE_ALIAS("platform:tnetv107x-ts");
MODULE_LICENSE("GPL");
......@@ -29,10 +29,13 @@
#include <linux/sysfs.h>
#include <linux/input/mt.h>
#include <linux/platform_data/zforce_ts.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#define WAIT_TIMEOUT msecs_to_jiffies(1000)
#define FRAME_START 0xee
#define FRAME_MAXSIZE 257
/* Offsets of the different parts of the payload the controller sends */
#define PAYLOAD_HEADER 0
......@@ -64,7 +67,7 @@
#define RESPONSE_STATUS 0X1e
/*
* Notifications are send by the touch controller without
* Notifications are sent by the touch controller without
* being requested by the driver and include for example
* touch indications
*/
......@@ -103,8 +106,8 @@ struct zforce_point {
* @suspended device suspended
* @access_mutex serialize i2c-access, to keep multipart reads together
* @command_done completion to wait for the command result
* @command_mutex serialize commands send to the ic
* @command_waiting the id of the command that that is currently waiting
* @command_mutex serialize commands sent to the ic
* @command_waiting the id of the command that is currently waiting
* for a result
* @command_result returned result of the command
*/
......@@ -235,7 +238,8 @@ static int zforce_scan_frequency(struct zforce_ts *ts, u16 idle, u16 finger,
(finger & 0xff), ((finger >> 8) & 0xff),
(stylus & 0xff), ((stylus >> 8) & 0xff) };
dev_dbg(&client->dev, "set scan frequency to (idle: %d, finger: %d, stylus: %d)\n",
dev_dbg(&client->dev,
"set scan frequency to (idle: %d, finger: %d, stylus: %d)\n",
idle, finger, stylus);
return zforce_send_wait(ts, &buf[0], ARRAY_SIZE(buf));
......@@ -255,7 +259,7 @@ static int zforce_setconfig(struct zforce_ts *ts, char b1)
static int zforce_start(struct zforce_ts *ts)
{
struct i2c_client *client = ts->client;
const struct zforce_ts_platdata *pdata = dev_get_platdata(&client->dev);
const struct zforce_ts_platdata *pdata = ts->pdata;
int ret;
dev_dbg(&client->dev, "starting device\n");
......@@ -326,13 +330,14 @@ static int zforce_stop(struct zforce_ts *ts)
static int zforce_touch_event(struct zforce_ts *ts, u8 *payload)
{
struct i2c_client *client = ts->client;
const struct zforce_ts_platdata *pdata = dev_get_platdata(&client->dev);
const struct zforce_ts_platdata *pdata = ts->pdata;
struct zforce_point point;
int count, i, num = 0;
count = payload[0];
if (count > ZFORCE_REPORT_POINTS) {
dev_warn(&client->dev, "to many coordinates %d, expected max %d\n",
dev_warn(&client->dev,
"too many coordinates %d, expected max %d\n",
count, ZFORCE_REPORT_POINTS);
count = ZFORCE_REPORT_POINTS;
}
......@@ -421,7 +426,7 @@ static int zforce_read_packet(struct zforce_ts *ts, u8 *buf)
goto unlock;
}
if (buf[PAYLOAD_LENGTH] <= 0 || buf[PAYLOAD_LENGTH] > 255) {
if (buf[PAYLOAD_LENGTH] == 0) {
dev_err(&client->dev, "invalid payload length: %d\n",
buf[PAYLOAD_LENGTH]);
ret = -EIO;
......@@ -471,9 +476,9 @@ static irqreturn_t zforce_irq_thread(int irq, void *dev_id)
{
struct zforce_ts *ts = dev_id;
struct i2c_client *client = ts->client;
const struct zforce_ts_platdata *pdata = dev_get_platdata(&client->dev);
const struct zforce_ts_platdata *pdata = ts->pdata;
int ret;
u8 payload_buffer[512];
u8 payload_buffer[FRAME_MAXSIZE];
u8 *payload;
/*
......@@ -494,8 +499,8 @@ static irqreturn_t zforce_irq_thread(int irq, void *dev_id)
while (!gpio_get_value(pdata->gpio_int)) {
ret = zforce_read_packet(ts, payload_buffer);
if (ret < 0) {
dev_err(&client->dev, "could not read packet, ret: %d\n",
ret);
dev_err(&client->dev,
"could not read packet, ret: %d\n", ret);
break;
}
......@@ -539,7 +544,8 @@ static irqreturn_t zforce_irq_thread(int irq, void *dev_id)
payload[RESPONSE_DATA + 4];
ts->version_rev = (payload[RESPONSE_DATA + 7] << 8) |
payload[RESPONSE_DATA + 6];
dev_dbg(&ts->client->dev, "Firmware Version %04x:%04x %04x:%04x\n",
dev_dbg(&ts->client->dev,
"Firmware Version %04x:%04x %04x:%04x\n",
ts->version_major, ts->version_minor,
ts->version_build, ts->version_rev);
......@@ -552,7 +558,8 @@ static irqreturn_t zforce_irq_thread(int irq, void *dev_id)
break;
default:
dev_err(&ts->client->dev, "unrecognized response id: 0x%x\n",
dev_err(&ts->client->dev,
"unrecognized response id: 0x%x\n",
payload[RESPONSE_ID]);
break;
}
......@@ -618,7 +625,8 @@ static int zforce_suspend(struct device *dev)
enable_irq_wake(client->irq);
} else if (input->users) {
dev_dbg(&client->dev, "suspend without being a wakeup source\n");
dev_dbg(&client->dev,
"suspend without being a wakeup source\n");
ret = zforce_stop(ts);
if (ret)
......@@ -684,6 +692,45 @@ static void zforce_reset(void *data)
gpio_set_value(ts->pdata->gpio_rst, 0);
}
static struct zforce_ts_platdata *zforce_parse_dt(struct device *dev)
{
struct zforce_ts_platdata *pdata;
struct device_node *np = dev->of_node;
if (!np)
return ERR_PTR(-ENOENT);
pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata) {
dev_err(dev, "failed to allocate platform data\n");
return ERR_PTR(-ENOMEM);
}
pdata->gpio_int = of_get_gpio(np, 0);
if (!gpio_is_valid(pdata->gpio_int)) {
dev_err(dev, "failed to get interrupt gpio\n");
return ERR_PTR(-EINVAL);
}
pdata->gpio_rst = of_get_gpio(np, 1);
if (!gpio_is_valid(pdata->gpio_rst)) {
dev_err(dev, "failed to get reset gpio\n");
return ERR_PTR(-EINVAL);
}
if (of_property_read_u32(np, "x-size", &pdata->x_max)) {
dev_err(dev, "failed to get x-size property\n");
return ERR_PTR(-EINVAL);
}
if (of_property_read_u32(np, "y-size", &pdata->y_max)) {
dev_err(dev, "failed to get y-size property\n");
return ERR_PTR(-EINVAL);
}
return pdata;
}
static int zforce_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
......@@ -692,8 +739,11 @@ static int zforce_probe(struct i2c_client *client,
struct input_dev *input_dev;
int ret;
if (!pdata)
return -EINVAL;
if (!pdata) {
pdata = zforce_parse_dt(&client->dev);
if (IS_ERR(pdata))
return PTR_ERR(pdata);
}
ts = devm_kzalloc(&client->dev, sizeof(struct zforce_ts), GFP_KERNEL);
if (!ts)
......@@ -798,7 +848,7 @@ static int zforce_probe(struct i2c_client *client,
return ret;
}
/* this gets the firmware version among other informations */
/* this gets the firmware version among other information */
ret = zforce_command_wait(ts, COMMAND_STATUS);
if (ret < 0) {
dev_err(&client->dev, "couldn't get status, %d\n", ret);
......@@ -829,11 +879,20 @@ static struct i2c_device_id zforce_idtable[] = {
};
MODULE_DEVICE_TABLE(i2c, zforce_idtable);
#ifdef CONFIG_OF
static struct of_device_id zforce_dt_idtable[] = {
{ .compatible = "neonode,zforce" },
{},
};
MODULE_DEVICE_TABLE(of, zforce_dt_idtable);
#endif
static struct i2c_driver zforce_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "zforce-ts",
.pm = &zforce_pm_ops,
.of_match_table = of_match_ptr(zforce_dt_idtable),
},
.probe = zforce_probe,
.id_table = zforce_idtable,
......
/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* 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.
*/
#ifndef __PMIC8XXX_KEYPAD_H__
#define __PMIC8XXX_KEYPAD_H__
#include <linux/input/matrix_keypad.h>
#define PM8XXX_KEYPAD_DEV_NAME "pm8xxx-keypad"
/**
* struct pm8xxx_keypad_platform_data - platform data for keypad
* @keymap_data - matrix keymap data
* @input_name - input device name
* @input_phys_device - input device name
* @num_cols - number of columns of keypad
* @num_rows - number of row of keypad
* @debounce_ms - debounce period in milliseconds
* @scan_delay_ms - scan delay in milliseconds
* @row_hold_ns - row hold period in nanoseconds
* @wakeup - configure keypad as wakeup
* @rep - enable or disable key repeat bit
*/
struct pm8xxx_keypad_platform_data {
const struct matrix_keymap_data *keymap_data;
const char *input_name;
const char *input_phys_device;
unsigned int num_cols;
unsigned int num_rows;
unsigned int rows_gpio_start;
unsigned int cols_gpio_start;
unsigned int debounce_ms;
unsigned int scan_delay_ms;
unsigned int row_hold_ns;
bool wakeup;
bool rep;
};
#endif /*__PMIC8XXX_KEYPAD_H__ */
/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* 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.
*/
#ifndef __PMIC8XXX_PWRKEY_H__
#define __PMIC8XXX_PWRKEY_H__
#define PM8XXX_PWRKEY_DEV_NAME "pm8xxx-pwrkey"
/**
* struct pm8xxx_pwrkey_platform_data - platform data for pwrkey driver
* @pull up: power on register control for pull up/down configuration
* @kpd_trigger_delay_us: time delay for power key state change interrupt
* trigger.
* @wakeup: configure power key as wakeup source
*/
struct pm8xxx_pwrkey_platform_data {
bool pull_up;
u32 kpd_trigger_delay_us;
u32 wakeup;
};
#endif /* __PMIC8XXX_PWRKEY_H__ */
/* arch/arm/plat-samsung/include/plat/ts.h
*
/*
* Copyright (c) 2005 Arnaud Patard <arnaud.patard@rtp-net.org>
*
* This program is free software; you can redistribute it and/or modify
......@@ -7,14 +6,14 @@
* published by the Free Software Foundation.
*/
#ifndef __ASM_ARM_TS_H
#define __ASM_ARM_TS_H
#ifndef __TOUCHSCREEN_S3C2410_H
#define __TOUCHSCREEN_S3C2410_H
struct s3c2410_ts_mach_info {
int delay;
int presc;
int oversampling_shift;
void (*cfg_gpio)(struct platform_device *dev);
int delay;
int presc;
int oversampling_shift;
void (*cfg_gpio)(struct platform_device *dev);
};
extern void s3c24xx_ts_set_platdata(struct s3c2410_ts_mach_info *);
......@@ -22,4 +21,4 @@ extern void s3c24xx_ts_set_platdata(struct s3c2410_ts_mach_info *);
/* defined by architecture to configure gpio */
extern void s3c24xx_ts_cfg_gpio(struct platform_device *dev);
#endif /* __ASM_ARM_TS_H */
#endif /*__TOUCHSCREEN_S3C2410_H */
......@@ -20,6 +20,8 @@
* Author: Aristeu Sergio Rozanski Filho <aris@cathedrallabs.org>
*
* Changes/Revisions:
* 0.4 01/09/2014 (Benjamin Tissoires <benjamin.tissoires@redhat.com>)
* - add UI_GET_SYSNAME ioctl
* 0.3 24/05/2006 (Anssi Hannula <anssi.hannulagmail.com>)
* - update ff support for the changes in kernel interface
* - add UINPUT_VERSION
......
......@@ -20,6 +20,8 @@
* Author: Aristeu Sergio Rozanski Filho <aris@cathedrallabs.org>
*
* Changes/Revisions:
* 0.4 01/09/2014 (Benjamin Tissoires <benjamin.tissoires@redhat.com>)
* - add UI_GET_SYSNAME ioctl
* 0.3 24/05/2006 (Anssi Hannula <anssi.hannulagmail.com>)
* - update ff support for the changes in kernel interface
* - add UINPUT_VERSION
......@@ -35,7 +37,7 @@
#include <linux/types.h>
#include <linux/input.h>
#define UINPUT_VERSION 3
#define UINPUT_VERSION 4
struct uinput_ff_upload {
......@@ -73,6 +75,15 @@ struct uinput_ff_erase {
#define UI_BEGIN_FF_ERASE _IOWR(UINPUT_IOCTL_BASE, 202, struct uinput_ff_erase)
#define UI_END_FF_ERASE _IOW(UINPUT_IOCTL_BASE, 203, struct uinput_ff_erase)
/**
* UI_GET_SYSNAME - get the sysfs name of the created uinput device
*
* @return the sysfs name of the created virtual input device.
* The complete sysfs path is then /sys/devices/virtual/input/--NAME--
* Usually, it is in the form "inputN"
*/
#define UI_GET_SYSNAME(len) _IOC(_IOC_READ, UINPUT_IOCTL_BASE, 300, len)
/*
* To write a force-feedback-capable driver, the upload_effect
* and erase_effect callbacks in input_dev must be implemented.
......
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