Commit f0c032d8 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 more input updates from Dmitry Torokhov:
 "Second round of updates for the input subsystem.

  This introduces two brand new touchscreen drivers (Colibri and
  imx6ul_tsc), some small driver fixes, and we are no longer report
  errors from evdev_flush() as users do not really have a way of
  handling errors, error codes that we were returning were not on the
  list of errors supposed to be returned by close(), and errors were
  causing issues with one of older versions of systemd"

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input:
  Input: imx_keypad - remove obsolete comment
  Input: touchscreen - add imx6ul_tsc driver support
  Input: Add touchscreen support for Colibri VF50
  Input: i8042 - lower log level for "no controller" message
  Input: evdev - do not report errors form flush()
  Input: elants_i2c - extend the calibration timeout to 12 seconds
  Input: sparcspkr - fix module autoload for OF platform drivers
  Input: regulator-haptic - fix module autoload for OF platform driver
  Input: pwm-beeper - fix module autoload for OF platform driver
  Input: ab8500-ponkey - Fix module autoload for OF platform driver
  Input: cyttsp - remove unnecessary MODULE_ALIAS()
  Input: elan_i2c - add ACPI ID "ELAN1000"
parents fa9a67ef 53431d0a
* Toradex Colibri VF50 Touchscreen driver
Required Properties:
- compatible must be toradex,vf50-touchscreen
- io-channels: adc channels being used by the Colibri VF50 module
- xp-gpios: FET gate driver for input of X+
- xm-gpios: FET gate driver for input of X-
- yp-gpios: FET gate driver for input of Y+
- ym-gpios: FET gate driver for input of Y-
- interrupt-parent: phandle for the interrupt controller
- interrupts: pen irq interrupt for touch detection
- pinctrl-names: "idle", "default", "gpios"
- pinctrl-0: pinctrl node for pen/touch detection state pinmux
- pinctrl-1: pinctrl node for X/Y and pressure measurement (ADC) state pinmux
- pinctrl-2: pinctrl node for gpios functioning as FET gate drivers
- vf50-ts-min-pressure: pressure level at which to stop measuring X/Y values
Example:
touchctrl: vf50_touchctrl {
compatible = "toradex,vf50-touchscreen";
io-channels = <&adc1 0>,<&adc0 0>,
<&adc0 1>,<&adc1 2>;
xp-gpios = <&gpio0 13 GPIO_ACTIVE_LOW>;
xm-gpios = <&gpio2 29 GPIO_ACTIVE_HIGH>;
yp-gpios = <&gpio0 12 GPIO_ACTIVE_LOW>;
ym-gpios = <&gpio0 4 GPIO_ACTIVE_HIGH>;
interrupt-parent = <&gpio0>;
interrupts = <8 IRQ_TYPE_LEVEL_LOW>;
pinctrl-names = "idle","default","gpios";
pinctrl-0 = <&pinctrl_touchctrl_idle>;
pinctrl-1 = <&pinctrl_touchctrl_default>;
pinctrl-2 = <&pinctrl_touchctrl_gpios>;
vf50-ts-min-pressure = <200>;
status = "disabled";
};
* Freescale i.MX6UL Touch Controller
Required properties:
- compatible: must be "fsl,imx6ul-tsc".
- reg: this touch controller address and the ADC2 address.
- interrupts: the interrupt of this touch controller and ADC2.
- clocks: the root clock of touch controller and ADC2.
- clock-names; must be "tsc" and "adc".
- xnur-gpio: the X- gpio this controller connect to.
This xnur-gpio returns to low once the finger leave the touch screen (The
last touch event the touch controller capture).
Optional properties:
- measure-delay-time: the value of measure delay time.
Before X-axis or Y-axis measurement, the screen need some time before
even potential distribution ready.
This value depends on the touch screen.
- pre-charge-time: the touch screen need some time to precharge.
This value depends on the touch screen.
Example:
tsc: tsc@02040000 {
compatible = "fsl,imx6ul-tsc";
reg = <0x02040000 0x4000>, <0x0219c000 0x4000>;
interrupts = <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clks IMX6UL_CLK_IPG>,
<&clks IMX6UL_CLK_ADC2>;
clock-names = "tsc", "adc";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_tsc>;
xnur-gpio = <&gpio1 3 GPIO_ACTIVE_LOW>;
measure-delay-time = <0xfff>;
pre-charge-time = <0xffff>;
status = "okay";
};
......@@ -290,19 +290,14 @@ static int evdev_flush(struct file *file, fl_owner_t id)
{
struct evdev_client *client = file->private_data;
struct evdev *evdev = client->evdev;
int retval;
retval = mutex_lock_interruptible(&evdev->mutex);
if (retval)
return retval;
mutex_lock(&evdev->mutex);
if (!evdev->exist || client->revoked)
retval = -ENODEV;
else
retval = input_flush_device(&evdev->handle, file);
if (evdev->exist && !client->revoked)
input_flush_device(&evdev->handle, file);
mutex_unlock(&evdev->mutex);
return retval;
return 0;
}
static void evdev_free(struct device *dev)
......
......@@ -5,8 +5,6 @@
* 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.
*
* <<Power management needs to be implemented>>.
*/
#include <linux/clk.h>
......
......@@ -118,6 +118,7 @@ static const struct of_device_id ab8500_ponkey_match[] = {
{ .compatible = "stericsson,ab8500-ponkey", },
{}
};
MODULE_DEVICE_TABLE(of, ab8500_ponkey_match);
#endif
static struct platform_driver ab8500_ponkey_driver = {
......
......@@ -173,6 +173,7 @@ static const struct of_device_id pwm_beeper_match[] = {
{ .compatible = "pwm-beeper", },
{ },
};
MODULE_DEVICE_TABLE(of, pwm_beeper_match);
#endif
static struct platform_driver pwm_beeper_driver = {
......
......@@ -249,6 +249,7 @@ static const struct of_device_id regulator_haptic_dt_match[] = {
{ .compatible = "regulator-haptic" },
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, regulator_haptic_dt_match);
static struct platform_driver regulator_haptic_driver = {
.probe = regulator_haptic_probe,
......
......@@ -253,6 +253,7 @@ static const struct of_device_id bbc_beep_match[] = {
},
{},
};
MODULE_DEVICE_TABLE(of, bbc_beep_match);
static struct platform_driver bbc_beep_driver = {
.driver = {
......@@ -332,6 +333,7 @@ static const struct of_device_id grover_beep_match[] = {
},
{},
};
MODULE_DEVICE_TABLE(of, grover_beep_match);
static struct platform_driver grover_beep_driver = {
.driver = {
......
......@@ -1170,6 +1170,7 @@ static const struct acpi_device_id elan_acpi_id[] = {
{ "ELAN0000", 0 },
{ "ELAN0100", 0 },
{ "ELAN0600", 0 },
{ "ELAN1000", 0 },
{ }
};
MODULE_DEVICE_TABLE(acpi, elan_acpi_id);
......
......@@ -877,7 +877,7 @@ static int __init i8042_check_aux(void)
static int i8042_controller_check(void)
{
if (i8042_flush()) {
pr_err("No controller found\n");
pr_info("No controller found\n");
return -ENODEV;
}
......
......@@ -479,6 +479,18 @@ config TOUCHSCREEN_MTOUCH
To compile this driver as a module, choose M here: the
module will be called mtouch.
config TOUCHSCREEN_IMX6UL_TSC
tristate "Freescale i.MX6UL touchscreen controller"
depends on (OF && GPIOLIB) || COMPILE_TEST
help
Say Y here if you have a Freescale i.MX6UL, and want to
use the internal touchscreen controller.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called imx6ul_tsc.
config TOUCHSCREEN_INEXIO
tristate "iNexio serial touchscreens"
select SERIO
......@@ -1040,4 +1052,16 @@ config TOUCHSCREEN_ZFORCE
To compile this driver as a module, choose M here: the
module will be called zforce_ts.
config TOUCHSCREEN_COLIBRI_VF50
tristate "Toradex Colibri on board touchscreen driver"
depends on GPIOLIB && IIO && VF610_ADC
help
Say Y here if you have a Colibri VF50 and plan to use
the on-board provided 4-wire touchscreen driver.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called colibri_vf50_ts.
endif
......@@ -38,6 +38,7 @@ obj-$(CONFIG_TOUCHSCREEN_EGALAX) += egalax_ts.o
obj-$(CONFIG_TOUCHSCREEN_FUJITSU) += fujitsu_ts.o
obj-$(CONFIG_TOUCHSCREEN_GOODIX) += goodix.o
obj-$(CONFIG_TOUCHSCREEN_ILI210X) += ili210x.o
obj-$(CONFIG_TOUCHSCREEN_IMX6UL_TSC) += imx6ul_tsc.o
obj-$(CONFIG_TOUCHSCREEN_INEXIO) += inexio.o
obj-$(CONFIG_TOUCHSCREEN_INTEL_MID) += intel-mid-touch.o
obj-$(CONFIG_TOUCHSCREEN_IPROC) += bcm_iproc_tsc.o
......@@ -85,3 +86,4 @@ obj-$(CONFIG_TOUCHSCREEN_W90X900) += w90p910_ts.o
obj-$(CONFIG_TOUCHSCREEN_SX8654) += sx8654.o
obj-$(CONFIG_TOUCHSCREEN_TPS6507X) += tps6507x-ts.o
obj-$(CONFIG_TOUCHSCREEN_ZFORCE) += zforce_ts.o
obj-$(CONFIG_TOUCHSCREEN_COLIBRI_VF50) += colibri-vf50-ts.o
/*
* Toradex Colibri VF50 Touchscreen driver
*
* Copyright 2015 Toradex AG
*
* Originally authored by Stefan Agner for 3.0 kernel
*
* 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/delay.h>
#include <linux/err.h>
#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/iio/consumer.h>
#include <linux/iio/types.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/types.h>
#define DRIVER_NAME "colibri-vf50-ts"
#define DRV_VERSION "1.0"
#define VF_ADC_MAX ((1 << 12) - 1)
#define COLI_TOUCH_MIN_DELAY_US 1000
#define COLI_TOUCH_MAX_DELAY_US 2000
#define COLI_PULLUP_MIN_DELAY_US 10000
#define COLI_PULLUP_MAX_DELAY_US 11000
#define COLI_TOUCH_NO_OF_AVGS 5
#define COLI_TOUCH_REQ_ADC_CHAN 4
struct vf50_touch_device {
struct platform_device *pdev;
struct input_dev *ts_input;
struct iio_channel *channels;
struct gpio_desc *gpio_xp;
struct gpio_desc *gpio_xm;
struct gpio_desc *gpio_yp;
struct gpio_desc *gpio_ym;
int pen_irq;
int min_pressure;
bool stop_touchscreen;
};
/*
* Enables given plates and measures touch parameters using ADC
*/
static int adc_ts_measure(struct iio_channel *channel,
struct gpio_desc *plate_p, struct gpio_desc *plate_m)
{
int i, value = 0, val = 0;
int error;
gpiod_set_value(plate_p, 1);
gpiod_set_value(plate_m, 1);
usleep_range(COLI_TOUCH_MIN_DELAY_US, COLI_TOUCH_MAX_DELAY_US);
for (i = 0; i < COLI_TOUCH_NO_OF_AVGS; i++) {
error = iio_read_channel_raw(channel, &val);
if (error < 0) {
value = error;
goto error_iio_read;
}
value += val;
}
value /= COLI_TOUCH_NO_OF_AVGS;
error_iio_read:
gpiod_set_value(plate_p, 0);
gpiod_set_value(plate_m, 0);
return value;
}
/*
* Enable touch detection using falling edge detection on XM
*/
static void vf50_ts_enable_touch_detection(struct vf50_touch_device *vf50_ts)
{
/* Enable plate YM (needs to be strong GND, high active) */
gpiod_set_value(vf50_ts->gpio_ym, 1);
/*
* Let the platform mux to idle state in order to enable
* Pull-Up on GPIO
*/
pinctrl_pm_select_idle_state(&vf50_ts->pdev->dev);
/* Wait for the pull-up to be stable on high */
usleep_range(COLI_PULLUP_MIN_DELAY_US, COLI_PULLUP_MAX_DELAY_US);
}
/*
* ADC touch screen sampling bottom half irq handler
*/
static irqreturn_t vf50_ts_irq_bh(int irq, void *private)
{
struct vf50_touch_device *vf50_ts = private;
struct device *dev = &vf50_ts->pdev->dev;
int val_x, val_y, val_z1, val_z2, val_p = 0;
bool discard_val_on_start = true;
/* Disable the touch detection plates */
gpiod_set_value(vf50_ts->gpio_ym, 0);
/* Let the platform mux to default state in order to mux as ADC */
pinctrl_pm_select_default_state(dev);
while (!vf50_ts->stop_touchscreen) {
/* X-Direction */
val_x = adc_ts_measure(&vf50_ts->channels[0],
vf50_ts->gpio_xp, vf50_ts->gpio_xm);
if (val_x < 0)
break;
/* Y-Direction */
val_y = adc_ts_measure(&vf50_ts->channels[1],
vf50_ts->gpio_yp, vf50_ts->gpio_ym);
if (val_y < 0)
break;
/*
* Touch pressure
* Measure on XP/YM
*/
val_z1 = adc_ts_measure(&vf50_ts->channels[2],
vf50_ts->gpio_yp, vf50_ts->gpio_xm);
if (val_z1 < 0)
break;
val_z2 = adc_ts_measure(&vf50_ts->channels[3],
vf50_ts->gpio_yp, vf50_ts->gpio_xm);
if (val_z2 < 0)
break;
/* Validate signal (avoid calculation using noise) */
if (val_z1 > 64 && val_x > 64) {
/*
* Calculate resistance between the plates
* lower resistance means higher pressure
*/
int r_x = (1000 * val_x) / VF_ADC_MAX;
val_p = (r_x * val_z2) / val_z1 - r_x;
} else {
val_p = 2000;
}
val_p = 2000 - val_p;
dev_dbg(dev,
"Measured values: x: %d, y: %d, z1: %d, z2: %d, p: %d\n",
val_x, val_y, val_z1, val_z2, val_p);
/*
* If touch pressure is too low, stop measuring and reenable
* touch detection
*/
if (val_p < vf50_ts->min_pressure || val_p > 2000)
break;
/*
* The pressure may not be enough for the first x and the
* second y measurement, but, the pressure is ok when the
* driver is doing the third and fourth measurement. To
* take care of this, we drop the first measurement always.
*/
if (discard_val_on_start) {
discard_val_on_start = false;
} else {
/*
* Report touch position and sleep for
* the next measurement.
*/
input_report_abs(vf50_ts->ts_input,
ABS_X, VF_ADC_MAX - val_x);
input_report_abs(vf50_ts->ts_input,
ABS_Y, VF_ADC_MAX - val_y);
input_report_abs(vf50_ts->ts_input,
ABS_PRESSURE, val_p);
input_report_key(vf50_ts->ts_input, BTN_TOUCH, 1);
input_sync(vf50_ts->ts_input);
}
usleep_range(COLI_PULLUP_MIN_DELAY_US,
COLI_PULLUP_MAX_DELAY_US);
}
/* Report no more touch, re-enable touch detection */
input_report_abs(vf50_ts->ts_input, ABS_PRESSURE, 0);
input_report_key(vf50_ts->ts_input, BTN_TOUCH, 0);
input_sync(vf50_ts->ts_input);
vf50_ts_enable_touch_detection(vf50_ts);
return IRQ_HANDLED;
}
static int vf50_ts_open(struct input_dev *dev_input)
{
struct vf50_touch_device *touchdev = input_get_drvdata(dev_input);
struct device *dev = &touchdev->pdev->dev;
dev_dbg(dev, "Input device %s opened, starting touch detection\n",
dev_input->name);
touchdev->stop_touchscreen = false;
/* Mux detection before request IRQ, wait for pull-up to settle */
vf50_ts_enable_touch_detection(touchdev);
return 0;
}
static void vf50_ts_close(struct input_dev *dev_input)
{
struct vf50_touch_device *touchdev = input_get_drvdata(dev_input);
struct device *dev = &touchdev->pdev->dev;
touchdev->stop_touchscreen = true;
/* Make sure IRQ is not running past close */
mb();
synchronize_irq(touchdev->pen_irq);
gpiod_set_value(touchdev->gpio_ym, 0);
pinctrl_pm_select_default_state(dev);
dev_dbg(dev, "Input device %s closed, disable touch detection\n",
dev_input->name);
}
static int vf50_ts_get_gpiod(struct device *dev, struct gpio_desc **gpio_d,
const char *con_id, enum gpiod_flags flags)
{
int error;
*gpio_d = devm_gpiod_get(dev, con_id, flags);
if (IS_ERR(*gpio_d)) {
error = PTR_ERR(*gpio_d);
dev_err(dev, "Could not get gpio_%s %d\n", con_id, error);
return error;
}
return 0;
}
static void vf50_ts_channel_release(void *data)
{
struct iio_channel *channels = data;
iio_channel_release_all(channels);
}
static int vf50_ts_probe(struct platform_device *pdev)
{
struct input_dev *input;
struct iio_channel *channels;
struct device *dev = &pdev->dev;
struct vf50_touch_device *touchdev;
int num_adc_channels;
int error;
channels = iio_channel_get_all(dev);
if (IS_ERR(channels))
return PTR_ERR(channels);
error = devm_add_action(dev, vf50_ts_channel_release, channels);
if (error) {
iio_channel_release_all(channels);
dev_err(dev, "Failed to register iio channel release action");
return error;
}
num_adc_channels = 0;
while (channels[num_adc_channels].indio_dev)
num_adc_channels++;
if (num_adc_channels != COLI_TOUCH_REQ_ADC_CHAN) {
dev_err(dev, "Inadequate ADC channels specified\n");
return -EINVAL;
}
touchdev = devm_kzalloc(dev, sizeof(*touchdev), GFP_KERNEL);
if (!touchdev)
return -ENOMEM;
touchdev->pdev = pdev;
touchdev->channels = channels;
error = of_property_read_u32(dev->of_node, "vf50-ts-min-pressure",
&touchdev->min_pressure);
if (error)
return error;
input = devm_input_allocate_device(dev);
if (!input) {
dev_err(dev, "Failed to allocate TS input device\n");
return -ENOMEM;
}
platform_set_drvdata(pdev, touchdev);
input->name = DRIVER_NAME;
input->id.bustype = BUS_HOST;
input->dev.parent = dev;
input->open = vf50_ts_open;
input->close = vf50_ts_close;
input_set_capability(input, EV_KEY, BTN_TOUCH);
input_set_abs_params(input, ABS_X, 0, VF_ADC_MAX, 0, 0);
input_set_abs_params(input, ABS_Y, 0, VF_ADC_MAX, 0, 0);
input_set_abs_params(input, ABS_PRESSURE, 0, VF_ADC_MAX, 0, 0);
touchdev->ts_input = input;
input_set_drvdata(input, touchdev);
error = input_register_device(input);
if (error) {
dev_err(dev, "Failed to register input device\n");
return error;
}
error = vf50_ts_get_gpiod(dev, &touchdev->gpio_xp, "xp", GPIOD_OUT_LOW);
if (error)
return error;
error = vf50_ts_get_gpiod(dev, &touchdev->gpio_xm,
"xm", GPIOD_OUT_LOW);
if (error)
return error;
error = vf50_ts_get_gpiod(dev, &touchdev->gpio_yp, "yp", GPIOD_OUT_LOW);
if (error)
return error;
error = vf50_ts_get_gpiod(dev, &touchdev->gpio_ym, "ym", GPIOD_OUT_LOW);
if (error)
return error;
touchdev->pen_irq = platform_get_irq(pdev, 0);
if (touchdev->pen_irq < 0)
return touchdev->pen_irq;
error = devm_request_threaded_irq(dev, touchdev->pen_irq,
NULL, vf50_ts_irq_bh, IRQF_ONESHOT,
"vf50 touch", touchdev);
if (error) {
dev_err(dev, "Failed to request IRQ %d: %d\n",
touchdev->pen_irq, error);
return error;
}
return 0;
}
static const struct of_device_id vf50_touch_of_match[] = {
{ .compatible = "toradex,vf50-touchscreen", },
{ }
};
MODULE_DEVICE_TABLE(of, vf50_touch_of_match);
static struct platform_driver vf50_touch_driver = {
.driver = {
.name = "toradex,vf50_touchctrl",
.of_match_table = vf50_touch_of_match,
},
.probe = vf50_ts_probe,
};
module_platform_driver(vf50_touch_driver);
MODULE_AUTHOR("Sanchayan Maity");
MODULE_DESCRIPTION("Colibri VF50 Touchscreen driver");
MODULE_LICENSE("GPL");
MODULE_VERSION(DRV_VERSION);
......@@ -86,4 +86,3 @@ module_i2c_driver(cyttsp4_i2c_driver);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Cypress TrueTouch(R) Standard Product (TTSP) I2C driver");
MODULE_AUTHOR("Cypress");
MODULE_ALIAS("i2c:cyttsp4");
......@@ -86,4 +86,3 @@ module_i2c_driver(cyttsp_i2c_driver);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Cypress TrueTouch(R) Standard Product (TTSP) I2C driver");
MODULE_AUTHOR("Cypress");
MODULE_ALIAS("i2c:cyttsp");
......@@ -102,7 +102,7 @@
#define ELAN_FW_PAGESIZE 132
/* calibration timeout definition */
#define ELAN_CALI_TIMEOUT_MSEC 10000
#define ELAN_CALI_TIMEOUT_MSEC 12000
#define ELAN_POWERON_DELAY_USEC 500
#define ELAN_RESET_DELAY_MSEC 20
......
This diff is collapsed.
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