Merge branch 'next' into for-linus

Prepare input updates for 3.16.
This commit is contained in:
Dmitry Torokhov
2014-06-07 23:24:07 -07:00
10907 changed files with 617511 additions and 257910 deletions

View File

@@ -16,6 +16,7 @@
#include <linux/input.h>
#include <linux/mfd/88pm860x.h>
#include <linux/slab.h>
#include <linux/device.h>
#define MEAS_LEN (8)
#define ACCURATE_BIT (12)
@@ -234,16 +235,17 @@ static int pm860x_touch_probe(struct platform_device *pdev)
if (ret)
return ret;
touch = kzalloc(sizeof(struct pm860x_touch), GFP_KERNEL);
if (touch == NULL)
touch = devm_kzalloc(&pdev->dev, sizeof(struct pm860x_touch),
GFP_KERNEL);
if (!touch)
return -ENOMEM;
platform_set_drvdata(pdev, touch);
touch->idev = input_allocate_device();
if (touch->idev == NULL) {
touch->idev = devm_input_allocate_device(&pdev->dev);
if (!touch->idev) {
dev_err(&pdev->dev, "Failed to allocate input device!\n");
ret = -ENOMEM;
goto out;
return -ENOMEM;
}
touch->idev->name = "88pm860x-touch";
@@ -258,10 +260,11 @@ static int pm860x_touch_probe(struct platform_device *pdev)
touch->res_x = res_x;
input_set_drvdata(touch->idev, touch);
ret = request_threaded_irq(touch->irq, NULL, pm860x_touch_handler,
IRQF_ONESHOT, "touch", touch);
ret = devm_request_threaded_irq(&pdev->dev, touch->irq, NULL,
pm860x_touch_handler, IRQF_ONESHOT,
"touch", touch);
if (ret < 0)
goto out_irq;
return ret;
__set_bit(EV_ABS, touch->idev->evbit);
__set_bit(ABS_X, touch->idev->absbit);
@@ -279,28 +282,11 @@ static int pm860x_touch_probe(struct platform_device *pdev)
ret = input_register_device(touch->idev);
if (ret < 0) {
dev_err(chip->dev, "Failed to register touch!\n");
goto out_rg;
return ret;
}
platform_set_drvdata(pdev, touch);
return 0;
out_rg:
free_irq(touch->irq, touch);
out_irq:
input_free_device(touch->idev);
out:
kfree(touch);
return ret;
}
static int pm860x_touch_remove(struct platform_device *pdev)
{
struct pm860x_touch *touch = platform_get_drvdata(pdev);
input_unregister_device(touch->idev);
free_irq(touch->irq, touch);
kfree(touch);
return 0;
}
static struct platform_driver pm860x_touch_driver = {
@@ -309,7 +295,6 @@ static struct platform_driver pm860x_touch_driver = {
.owner = THIS_MODULE,
},
.probe = pm860x_touch_probe,
.remove = pm860x_touch_remove,
};
module_platform_driver(pm860x_touch_driver);

View File

@@ -11,6 +11,10 @@ menuconfig INPUT_TOUCHSCREEN
if INPUT_TOUCHSCREEN
config OF_TOUCHSCREEN
def_tristate INPUT
depends on INPUT && OF
config TOUCHSCREEN_88PM860X
tristate "Marvell 88PM860x touchscreen"
depends on MFD_88PM860X
@@ -89,6 +93,7 @@ config TOUCHSCREEN_AD7879_SPI
config TOUCHSCREEN_ATMEL_MXT
tristate "Atmel mXT I2C Touchscreen"
depends on I2C
select FW_LOADER
help
Say Y here if you have Atmel mXT series I2C touchscreen,
such as AT42QT602240/ATMXT224, connected to your system.
@@ -858,7 +863,7 @@ config TOUCHSCREEN_TSC2007
config TOUCHSCREEN_W90X900
tristate "W90P910 touchscreen driver"
depends on HAVE_CLK
depends on ARCH_W90X900
help
Say Y here if you have a W90P910 based touchscreen.
@@ -897,6 +902,17 @@ config TOUCHSCREEN_STMPE
To compile this driver as a module, choose M here: the
module will be called stmpe-ts.
config TOUCHSCREEN_SUN4I
tristate "Allwinner sun4i resistive touchscreen controller support"
depends on ARCH_SUNXI || COMPILE_TEST
depends on HWMON
help
This selects support for the resistive touchscreen controller
found on Allwinner sunxi SoCs.
To compile this driver as a module, choose M here: the
module will be called sun4i-ts.
config TOUCHSCREEN_SUR40
tristate "Samsung SUR40 (Surface 2.0/PixelSense) touchscreen"
depends on USB

View File

@@ -6,6 +6,7 @@
wm97xx-ts-y := wm97xx-core.o
obj-$(CONFIG_OF_TOUCHSCREEN) += of_touchscreen.o
obj-$(CONFIG_TOUCHSCREEN_88PM860X) += 88pm860x-ts.o
obj-$(CONFIG_TOUCHSCREEN_AD7877) += ad7877.o
obj-$(CONFIG_TOUCHSCREEN_AD7879) += ad7879.o
@@ -54,6 +55,7 @@ obj-$(CONFIG_TOUCHSCREEN_PIXCIR) += pixcir_i2c_ts.o
obj-$(CONFIG_TOUCHSCREEN_S3C2410) += s3c2410_ts.o
obj-$(CONFIG_TOUCHSCREEN_ST1232) += st1232.o
obj-$(CONFIG_TOUCHSCREEN_STMPE) += stmpe-ts.o
obj-$(CONFIG_TOUCHSCREEN_SUN4I) += sun4i-ts.o
obj-$(CONFIG_TOUCHSCREEN_SUR40) += sur40.o
obj-$(CONFIG_TOUCHSCREEN_TI_AM335X_TSC) += ti_am335x_tsc.o
obj-$(CONFIG_TOUCHSCREEN_TOUCHIT213) += touchit213.o

View File

@@ -210,11 +210,6 @@ static bool gpio3;
module_param(gpio3, bool, 0);
MODULE_PARM_DESC(gpio3, "If gpio3 is set to 1 AUX3 acts as GPIO3");
/*
* ad7877_read/write are only used for initial setup and for sysfs controls.
* The main traffic is done using spi_async() in the interrupt handler.
*/
static int ad7877_read(struct spi_device *spi, u16 reg)
{
struct ser_req *req;

View File

@@ -706,7 +706,7 @@ static void ads7846_read_state(struct ads7846 *ts)
m = &ts->msg[msg_idx];
error = spi_sync(ts->spi, m);
if (error) {
dev_err(&ts->spi->dev, "spi_async --> %d\n", error);
dev_err(&ts->spi->dev, "spi_sync --> %d\n", error);
packet->tc.ignore = true;
return;
}

File diff suppressed because it is too large Load Diff

View File

@@ -679,7 +679,7 @@ static const struct i2c_device_id auo_pixcir_idtable[] = {
MODULE_DEVICE_TABLE(i2c, auo_pixcir_idtable);
#ifdef CONFIG_OF
static struct of_device_id auo_pixcir_ts_dt_idtable[] = {
static const struct of_device_id auo_pixcir_ts_dt_idtable[] = {
{ .compatible = "auo,auo_pixcir_ts" },
{},
};

View File

@@ -301,10 +301,11 @@ static int da9034_touch_probe(struct platform_device *pdev)
struct da9034_touch_pdata *pdata = dev_get_platdata(&pdev->dev);
struct da9034_touch *touch;
struct input_dev *input_dev;
int ret;
int error;
touch = kzalloc(sizeof(struct da9034_touch), GFP_KERNEL);
if (touch == NULL) {
touch = devm_kzalloc(&pdev->dev, sizeof(struct da9034_touch),
GFP_KERNEL);
if (!touch) {
dev_err(&pdev->dev, "failed to allocate driver data\n");
return -ENOMEM;
}
@@ -315,18 +316,18 @@ static int da9034_touch_probe(struct platform_device *pdev)
touch->interval_ms = pdata->interval_ms;
touch->x_inverted = pdata->x_inverted;
touch->y_inverted = pdata->y_inverted;
} else
} else {
/* fallback into default */
touch->interval_ms = 10;
}
INIT_DELAYED_WORK(&touch->tsi_work, da9034_tsi_work);
touch->notifier.notifier_call = da9034_touch_notifier;
input_dev = input_allocate_device();
input_dev = devm_input_allocate_device(&pdev->dev);
if (!input_dev) {
dev_err(&pdev->dev, "failed to allocate input device\n");
ret = -ENOMEM;
goto err_free_touch;
return -ENOMEM;
}
input_dev->name = pdev->name;
@@ -346,26 +347,9 @@ static int da9034_touch_probe(struct platform_device *pdev)
touch->input_dev = input_dev;
input_set_drvdata(input_dev, touch);
ret = input_register_device(input_dev);
if (ret)
goto err_free_input;
platform_set_drvdata(pdev, touch);
return 0;
err_free_input:
input_free_device(input_dev);
err_free_touch:
kfree(touch);
return ret;
}
static int da9034_touch_remove(struct platform_device *pdev)
{
struct da9034_touch *touch = platform_get_drvdata(pdev);
input_unregister_device(touch->input_dev);
kfree(touch);
error = input_register_device(input_dev);
if (error)
return error;
return 0;
}
@@ -376,7 +360,6 @@ static struct platform_driver da9034_touch_driver = {
.owner = THIS_MODULE,
},
.probe = da9034_touch_probe,
.remove = da9034_touch_remove,
};
module_platform_driver(da9034_touch_driver);

View File

@@ -271,7 +271,7 @@ static int edt_ft5x06_register_write(struct edt_ft5x06_ts_data *tsdata,
wrbuf[0] = addr;
wrbuf[1] = value;
return edt_ft5x06_ts_readwrite(tsdata->client, 3,
return edt_ft5x06_ts_readwrite(tsdata->client, 2,
wrbuf, 0, NULL);
default:

View File

@@ -262,7 +262,7 @@ static int egalax_ts_resume(struct device *dev)
static SIMPLE_DEV_PM_OPS(egalax_ts_pm_ops, egalax_ts_suspend, egalax_ts_resume);
static struct of_device_id egalax_ts_dt_ids[] = {
static const struct of_device_id egalax_ts_dt_ids[] = {
{ .compatible = "eeti,egalax_ts" },
{ /* sentinel */ }
};

View File

@@ -36,6 +36,7 @@
#include <linux/irq.h>
#include <linux/delay.h>
#include <asm/intel_scu_ipc.h>
#include <linux/device.h>
/* PMIC Interrupt registers */
#define PMIC_REG_ID1 0x00 /* PMIC ID1 register */
@@ -580,12 +581,17 @@ static int mrstouch_probe(struct platform_device *pdev)
return -EINVAL;
}
tsdev = kzalloc(sizeof(struct mrstouch_dev), GFP_KERNEL);
input = input_allocate_device();
if (!tsdev || !input) {
tsdev = devm_kzalloc(&pdev->dev, sizeof(struct mrstouch_dev),
GFP_KERNEL);
if (!tsdev) {
dev_err(&pdev->dev, "unable to allocate memory\n");
err = -ENOMEM;
goto err_free_mem;
return -ENOMEM;
}
input = devm_input_allocate_device(&pdev->dev);
if (!input) {
dev_err(&pdev->dev, "unable to allocate input device\n");
return -ENOMEM;
}
tsdev->dev = &pdev->dev;
@@ -598,7 +604,7 @@ static int mrstouch_probe(struct platform_device *pdev)
err = mrstouch_adc_init(tsdev);
if (err) {
dev_err(&pdev->dev, "ADC initialization failed\n");
goto err_free_mem;
return err;
}
input->name = "mrst_touchscreen";
@@ -618,38 +624,20 @@ static int mrstouch_probe(struct platform_device *pdev)
input_set_abs_params(tsdev->input, ABS_PRESSURE,
MRST_PRESSURE_MIN, MRST_PRESSURE_MAX, 0, 0);
err = request_threaded_irq(tsdev->irq, NULL, mrstouch_pendet_irq,
IRQF_ONESHOT, "mrstouch", tsdev);
err = devm_request_threaded_irq(&pdev->dev, tsdev->irq, NULL,
mrstouch_pendet_irq, IRQF_ONESHOT,
"mrstouch", tsdev);
if (err) {
dev_err(tsdev->dev, "unable to allocate irq\n");
goto err_free_mem;
return err;
}
err = input_register_device(tsdev->input);
if (err) {
dev_err(tsdev->dev, "unable to register input device\n");
goto err_free_irq;
return err;
}
platform_set_drvdata(pdev, tsdev);
return 0;
err_free_irq:
free_irq(tsdev->irq, tsdev);
err_free_mem:
input_free_device(input);
kfree(tsdev);
return err;
}
static int mrstouch_remove(struct platform_device *pdev)
{
struct mrstouch_dev *tsdev = platform_get_drvdata(pdev);
free_irq(tsdev->irq, tsdev);
input_unregister_device(tsdev->input);
kfree(tsdev);
return 0;
}
@@ -659,7 +647,6 @@ static struct platform_driver mrstouch_driver = {
.owner = THIS_MODULE,
},
.probe = mrstouch_probe,
.remove = mrstouch_remove,
};
module_platform_driver(mrstouch_driver);

View File

@@ -384,7 +384,7 @@ static const struct dev_pm_ops lpc32xx_ts_pm_ops = {
#endif
#ifdef CONFIG_OF
static struct of_device_id lpc32xx_tsc_of_match[] = {
static const struct of_device_id lpc32xx_tsc_of_match[] = {
{ .compatible = "nxp,lpc3220-tsc", },
{ },
};

View File

@@ -161,10 +161,9 @@ static irqreturn_t mcs5000_ts_interrupt(int irq, void *dev_id)
return IRQ_HANDLED;
}
static void mcs5000_ts_phys_init(struct mcs5000_ts_data *data)
static void mcs5000_ts_phys_init(struct mcs5000_ts_data *data,
const struct mcs_platform_data *platform_data)
{
const struct mcs_platform_data *platform_data =
data->platform_data;
struct i2c_client *client = data->client;
/* Touch reset & sleep mode */
@@ -187,28 +186,32 @@ static void mcs5000_ts_phys_init(struct mcs5000_ts_data *data)
}
static int mcs5000_ts_probe(struct i2c_client *client,
const struct i2c_device_id *id)
const struct i2c_device_id *id)
{
const struct mcs_platform_data *pdata;
struct mcs5000_ts_data *data;
struct input_dev *input_dev;
int ret;
int error;
if (!dev_get_platdata(&client->dev))
pdata = dev_get_platdata(&client->dev);
if (!pdata)
return -EINVAL;
data = kzalloc(sizeof(struct mcs5000_ts_data), GFP_KERNEL);
input_dev = input_allocate_device();
if (!data || !input_dev) {
data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
if (!data) {
dev_err(&client->dev, "Failed to allocate memory\n");
ret = -ENOMEM;
goto err_free_mem;
return -ENOMEM;
}
data->client = client;
data->input_dev = input_dev;
data->platform_data = dev_get_platdata(&client->dev);
input_dev->name = "MELPAS MCS-5000 Touchscreen";
input_dev = devm_input_allocate_device(&client->dev);
if (!input_dev) {
dev_err(&client->dev, "Failed to allocate input device\n");
return -ENOMEM;
}
input_dev->name = "MELFAS MCS-5000 Touchscreen";
input_dev->id.bustype = BUS_I2C;
input_dev->dev.parent = &client->dev;
@@ -219,43 +222,29 @@ static int mcs5000_ts_probe(struct i2c_client *client,
input_set_abs_params(input_dev, ABS_Y, 0, MCS5000_MAX_YC, 0, 0);
input_set_drvdata(input_dev, data);
data->input_dev = input_dev;
if (data->platform_data->cfg_pin)
data->platform_data->cfg_pin();
if (pdata->cfg_pin)
pdata->cfg_pin();
ret = request_threaded_irq(client->irq, NULL, mcs5000_ts_interrupt,
IRQF_TRIGGER_LOW | IRQF_ONESHOT, "mcs5000_ts", data);
if (ret < 0) {
error = devm_request_threaded_irq(&client->dev, client->irq,
NULL, mcs5000_ts_interrupt,
IRQF_TRIGGER_LOW | IRQF_ONESHOT,
"mcs5000_ts", data);
if (error) {
dev_err(&client->dev, "Failed to register interrupt\n");
goto err_free_mem;
return error;
}
ret = input_register_device(data->input_dev);
if (ret < 0)
goto err_free_irq;
error = input_register_device(data->input_dev);
if (error) {
dev_err(&client->dev, "Failed to register input device\n");
return error;
}
mcs5000_ts_phys_init(data);
mcs5000_ts_phys_init(data, pdata);
i2c_set_clientdata(client, data);
return 0;
err_free_irq:
free_irq(client->irq, data);
err_free_mem:
input_free_device(input_dev);
kfree(data);
return ret;
}
static int mcs5000_ts_remove(struct i2c_client *client)
{
struct mcs5000_ts_data *data = i2c_get_clientdata(client);
free_irq(client->irq, data);
input_unregister_device(data->input_dev);
kfree(data);
return 0;
}
@@ -274,14 +263,15 @@ static int mcs5000_ts_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct mcs5000_ts_data *data = i2c_get_clientdata(client);
const struct mcs_platform_data *pdata = dev_get_platdata(dev);
mcs5000_ts_phys_init(data);
mcs5000_ts_phys_init(data, pdata);
return 0;
}
#endif
static SIMPLE_DEV_PM_OPS(mcs5000_ts_pm, mcs5000_ts_suspend, mcs5000_ts_resume);
#endif
static const struct i2c_device_id mcs5000_ts_id[] = {
{ "mcs5000_ts", 0 },
@@ -291,12 +281,9 @@ MODULE_DEVICE_TABLE(i2c, mcs5000_ts_id);
static struct i2c_driver mcs5000_ts_driver = {
.probe = mcs5000_ts_probe,
.remove = mcs5000_ts_remove,
.driver = {
.name = "mcs5000_ts",
#ifdef CONFIG_PM
.pm = &mcs5000_ts_pm,
#endif
},
.id_table = mcs5000_ts_id,
};

View File

@@ -456,7 +456,7 @@ static int mms114_probe(struct i2c_client *client,
data->input_dev = input_dev;
data->pdata = pdata;
input_dev->name = "MELPAS MMS114 Touchscreen";
input_dev->name = "MELFAS MMS114 Touchscreen";
input_dev->id.bustype = BUS_I2C;
input_dev->dev.parent = &client->dev;
input_dev->open = mms114_input_open;
@@ -570,7 +570,7 @@ static const struct i2c_device_id mms114_id[] = {
MODULE_DEVICE_TABLE(i2c, mms114_id);
#ifdef CONFIG_OF
static struct of_device_id mms114_dt_match[] = {
static const struct of_device_id mms114_dt_match[] = {
{ .compatible = "melfas,mms114" },
{ }
};

View File

@@ -0,0 +1,45 @@
/*
* Generic DT helper functions for touchscreen devices
*
* Copyright (c) 2014 Sebastian Reichel <sre@kernel.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
#include <linux/of.h>
#include <linux/input.h>
#include <linux/input/touchscreen.h>
/**
* touchscreen_parse_of_params - parse common touchscreen DT properties
* @dev: device that should be parsed
*
* This function parses common DT properties for touchscreens and setups the
* input device accordingly. The function keeps previously setuped default
* values if no value is specified via DT.
*/
void touchscreen_parse_of_params(struct input_dev *dev)
{
struct device_node *np = dev->dev.parent->of_node;
struct input_absinfo *absinfo;
input_alloc_absinfo(dev);
if (!dev->absinfo)
return;
absinfo = &dev->absinfo[ABS_X];
of_property_read_u32(np, "touchscreen-size-x", &absinfo->maximum);
of_property_read_u32(np, "touchscreen-fuzz-x", &absinfo->fuzz);
absinfo = &dev->absinfo[ABS_Y];
of_property_read_u32(np, "touchscreen-size-y", &absinfo->maximum);
of_property_read_u32(np, "touchscreen-fuzz-y", &absinfo->fuzz);
absinfo = &dev->absinfo[ABS_PRESSURE];
of_property_read_u32(np, "touchscreen-max-pressure", &absinfo->maximum);
of_property_read_u32(np, "touchscreen-fuzz-pressure", &absinfo->fuzz);
}
EXPORT_SYMBOL(touchscreen_parse_of_params);

View File

@@ -24,12 +24,13 @@
#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/input/pixcir_ts.h>
#include <linux/gpio.h>
struct pixcir_i2c_ts_data {
struct i2c_client *client;
struct input_dev *input;
const struct pixcir_ts_platform_data *chip;
bool exiting;
bool running;
};
static void pixcir_ts_poscheck(struct pixcir_i2c_ts_data *data)
@@ -87,11 +88,12 @@ static void pixcir_ts_poscheck(struct pixcir_i2c_ts_data *data)
static irqreturn_t pixcir_ts_isr(int irq, void *dev_id)
{
struct pixcir_i2c_ts_data *tsdata = dev_id;
const struct pixcir_ts_platform_data *pdata = tsdata->chip;
while (!tsdata->exiting) {
while (tsdata->running) {
pixcir_ts_poscheck(tsdata);
if (tsdata->chip->attb_read_val())
if (gpio_get_value(pdata->gpio_attb))
break;
msleep(20);
@@ -100,25 +102,221 @@ static irqreturn_t pixcir_ts_isr(int irq, void *dev_id)
return IRQ_HANDLED;
}
static int pixcir_set_power_mode(struct pixcir_i2c_ts_data *ts,
enum pixcir_power_mode mode)
{
struct device *dev = &ts->client->dev;
int ret;
ret = i2c_smbus_read_byte_data(ts->client, PIXCIR_REG_POWER_MODE);
if (ret < 0) {
dev_err(dev, "%s: can't read reg 0x%x : %d\n",
__func__, PIXCIR_REG_POWER_MODE, ret);
return ret;
}
ret &= ~PIXCIR_POWER_MODE_MASK;
ret |= mode;
/* Always AUTO_IDLE */
ret |= PIXCIR_POWER_ALLOW_IDLE;
ret = i2c_smbus_write_byte_data(ts->client, PIXCIR_REG_POWER_MODE, ret);
if (ret < 0) {
dev_err(dev, "%s: can't write reg 0x%x : %d\n",
__func__, PIXCIR_REG_POWER_MODE, ret);
return ret;
}
return 0;
}
/*
* Set the interrupt mode for the device i.e. ATTB line behaviour
*
* @polarity : 1 for active high, 0 for active low.
*/
static int pixcir_set_int_mode(struct pixcir_i2c_ts_data *ts,
enum pixcir_int_mode mode, bool polarity)
{
struct device *dev = &ts->client->dev;
int ret;
ret = i2c_smbus_read_byte_data(ts->client, PIXCIR_REG_INT_MODE);
if (ret < 0) {
dev_err(dev, "%s: can't read reg 0x%x : %d\n",
__func__, PIXCIR_REG_INT_MODE, ret);
return ret;
}
ret &= ~PIXCIR_INT_MODE_MASK;
ret |= mode;
if (polarity)
ret |= PIXCIR_INT_POL_HIGH;
else
ret &= ~PIXCIR_INT_POL_HIGH;
ret = i2c_smbus_write_byte_data(ts->client, PIXCIR_REG_INT_MODE, ret);
if (ret < 0) {
dev_err(dev, "%s: can't write reg 0x%x : %d\n",
__func__, PIXCIR_REG_INT_MODE, ret);
return ret;
}
return 0;
}
/*
* Enable/disable interrupt generation
*/
static int pixcir_int_enable(struct pixcir_i2c_ts_data *ts, bool enable)
{
struct device *dev = &ts->client->dev;
int ret;
ret = i2c_smbus_read_byte_data(ts->client, PIXCIR_REG_INT_MODE);
if (ret < 0) {
dev_err(dev, "%s: can't read reg 0x%x : %d\n",
__func__, PIXCIR_REG_INT_MODE, ret);
return ret;
}
if (enable)
ret |= PIXCIR_INT_ENABLE;
else
ret &= ~PIXCIR_INT_ENABLE;
ret = i2c_smbus_write_byte_data(ts->client, PIXCIR_REG_INT_MODE, ret);
if (ret < 0) {
dev_err(dev, "%s: can't write reg 0x%x : %d\n",
__func__, PIXCIR_REG_INT_MODE, ret);
return ret;
}
return 0;
}
static int pixcir_start(struct pixcir_i2c_ts_data *ts)
{
struct device *dev = &ts->client->dev;
int error;
/* LEVEL_TOUCH interrupt with active low polarity */
error = pixcir_set_int_mode(ts, PIXCIR_INT_LEVEL_TOUCH, 0);
if (error) {
dev_err(dev, "Failed to set interrupt mode: %d\n", error);
return error;
}
ts->running = true;
mb(); /* Update status before IRQ can fire */
/* enable interrupt generation */
error = pixcir_int_enable(ts, true);
if (error) {
dev_err(dev, "Failed to enable interrupt generation: %d\n",
error);
return error;
}
return 0;
}
static int pixcir_stop(struct pixcir_i2c_ts_data *ts)
{
int error;
/* Disable interrupt generation */
error = pixcir_int_enable(ts, false);
if (error) {
dev_err(&ts->client->dev,
"Failed to disable interrupt generation: %d\n",
error);
return error;
}
/* Exit ISR if running, no more report parsing */
ts->running = false;
mb(); /* update status before we synchronize irq */
/* Wait till running ISR is complete */
synchronize_irq(ts->client->irq);
return 0;
}
static int pixcir_input_open(struct input_dev *dev)
{
struct pixcir_i2c_ts_data *ts = input_get_drvdata(dev);
return pixcir_start(ts);
}
static void pixcir_input_close(struct input_dev *dev)
{
struct pixcir_i2c_ts_data *ts = input_get_drvdata(dev);
pixcir_stop(ts);
}
#ifdef CONFIG_PM_SLEEP
static int pixcir_i2c_ts_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct pixcir_i2c_ts_data *ts = i2c_get_clientdata(client);
struct input_dev *input = ts->input;
int ret = 0;
mutex_lock(&input->mutex);
if (device_may_wakeup(&client->dev)) {
if (!input->users) {
ret = pixcir_start(ts);
if (ret) {
dev_err(dev, "Failed to start\n");
goto unlock;
}
}
if (device_may_wakeup(&client->dev))
enable_irq_wake(client->irq);
} else if (input->users) {
ret = pixcir_stop(ts);
}
return 0;
unlock:
mutex_unlock(&input->mutex);
return ret;
}
static int pixcir_i2c_ts_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct pixcir_i2c_ts_data *ts = i2c_get_clientdata(client);
struct input_dev *input = ts->input;
int ret = 0;
if (device_may_wakeup(&client->dev))
mutex_lock(&input->mutex);
if (device_may_wakeup(&client->dev)) {
disable_irq_wake(client->irq);
return 0;
if (!input->users) {
ret = pixcir_stop(ts);
if (ret) {
dev_err(dev, "Failed to stop\n");
goto unlock;
}
}
} else if (input->users) {
ret = pixcir_start(ts);
}
unlock:
mutex_unlock(&input->mutex);
return ret;
}
#endif
@@ -130,6 +328,7 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client,
{
const struct pixcir_ts_platform_data *pdata =
dev_get_platdata(&client->dev);
struct device *dev = &client->dev;
struct pixcir_i2c_ts_data *tsdata;
struct input_dev *input;
int error;
@@ -139,12 +338,19 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client,
return -EINVAL;
}
tsdata = kzalloc(sizeof(*tsdata), GFP_KERNEL);
input = input_allocate_device();
if (!tsdata || !input) {
dev_err(&client->dev, "Failed to allocate driver data!\n");
error = -ENOMEM;
goto err_free_mem;
if (!gpio_is_valid(pdata->gpio_attb)) {
dev_err(dev, "Invalid gpio_attb in pdata\n");
return -EINVAL;
}
tsdata = devm_kzalloc(dev, sizeof(*tsdata), GFP_KERNEL);
if (!tsdata)
return -ENOMEM;
input = devm_input_allocate_device(dev);
if (!input) {
dev_err(dev, "Failed to allocate input device\n");
return -ENOMEM;
}
tsdata->client = client;
@@ -153,6 +359,8 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client,
input->name = client->name;
input->id.bustype = BUS_I2C;
input->open = pixcir_input_open;
input->close = pixcir_input_close;
input->dev.parent = &client->dev;
__set_bit(EV_KEY, input->evbit);
@@ -165,44 +373,47 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client,
input_set_drvdata(input, tsdata);
error = request_threaded_irq(client->irq, NULL, pixcir_ts_isr,
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
client->name, tsdata);
error = devm_gpio_request_one(dev, pdata->gpio_attb,
GPIOF_DIR_IN, "pixcir_i2c_attb");
if (error) {
dev_err(&client->dev, "Unable to request touchscreen IRQ.\n");
goto err_free_mem;
dev_err(dev, "Failed to request ATTB gpio\n");
return error;
}
error = devm_request_threaded_irq(dev, client->irq, NULL, pixcir_ts_isr,
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
client->name, tsdata);
if (error) {
dev_err(dev, "failed to request irq %d\n", client->irq);
return error;
}
/* Always be in IDLE mode to save power, device supports auto wake */
error = pixcir_set_power_mode(tsdata, PIXCIR_POWER_IDLE);
if (error) {
dev_err(dev, "Failed to set IDLE mode\n");
return error;
}
/* Stop device till opened */
error = pixcir_stop(tsdata);
if (error)
return error;
error = input_register_device(input);
if (error)
goto err_free_irq;
return error;
i2c_set_clientdata(client, tsdata);
device_init_wakeup(&client->dev, 1);
return 0;
err_free_irq:
free_irq(client->irq, tsdata);
err_free_mem:
input_free_device(input);
kfree(tsdata);
return error;
}
static int pixcir_i2c_ts_remove(struct i2c_client *client)
{
struct pixcir_i2c_ts_data *tsdata = i2c_get_clientdata(client);
device_init_wakeup(&client->dev, 0);
tsdata->exiting = true;
mb();
free_irq(client->irq, tsdata);
input_unregister_device(tsdata->input);
kfree(tsdata);
return 0;
}

View File

@@ -134,7 +134,8 @@ static irqreturn_t st1232_ts_irq_handler(int irq, void *dev_id)
} else if (!ts->low_latency_req.dev) {
/* First contact, request 100 us latency. */
dev_pm_qos_add_ancestor_request(&ts->client->dev,
&ts->low_latency_req, 100);
&ts->low_latency_req,
DEV_PM_QOS_RESUME_LATENCY, 100);
}
/* SYN_REPORT */

View File

@@ -0,0 +1,339 @@
/*
* Allwinner sunxi resistive touchscreen controller driver
*
* Copyright (C) 2013 - 2014 Hans de Goede <hdegoede@redhat.com>
*
* The hwmon parts are based on work by Corentin LABBE which is:
* Copyright (C) 2013 Corentin LABBE <clabbe.montjoie@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
/*
* The sun4i-ts controller is capable of detecting a second touch, but when a
* second touch is present then the accuracy becomes so bad the reported touch
* location is not useable.
*
* The original android driver contains some complicated heuristics using the
* aprox. distance between the 2 touches to see if the user is making a pinch
* open / close movement, and then reports emulated multi-touch events around
* the last touch coordinate (as the dual-touch coordinates are worthless).
*
* These kinds of heuristics are just asking for trouble (and don't belong
* in the kernel). So this driver offers straight forward, reliable single
* touch functionality only.
*/
#include <linux/err.h>
#include <linux/hwmon.h>
#include <linux/init.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#define TP_CTRL0 0x00
#define TP_CTRL1 0x04
#define TP_CTRL2 0x08
#define TP_CTRL3 0x0c
#define TP_INT_FIFOC 0x10
#define TP_INT_FIFOS 0x14
#define TP_TPR 0x18
#define TP_CDAT 0x1c
#define TEMP_DATA 0x20
#define TP_DATA 0x24
/* TP_CTRL0 bits */
#define ADC_FIRST_DLY(x) ((x) << 24) /* 8 bits */
#define ADC_FIRST_DLY_MODE(x) ((x) << 23)
#define ADC_CLK_SEL(x) ((x) << 22)
#define ADC_CLK_DIV(x) ((x) << 20) /* 3 bits */
#define FS_DIV(x) ((x) << 16) /* 4 bits */
#define T_ACQ(x) ((x) << 0) /* 16 bits */
/* TP_CTRL1 bits */
#define STYLUS_UP_DEBOUN(x) ((x) << 12) /* 8 bits */
#define STYLUS_UP_DEBOUN_EN(x) ((x) << 9)
#define TOUCH_PAN_CALI_EN(x) ((x) << 6)
#define TP_DUAL_EN(x) ((x) << 5)
#define TP_MODE_EN(x) ((x) << 4)
#define TP_ADC_SELECT(x) ((x) << 3)
#define ADC_CHAN_SELECT(x) ((x) << 0) /* 3 bits */
/* TP_CTRL2 bits */
#define TP_SENSITIVE_ADJUST(x) ((x) << 28) /* 4 bits */
#define TP_MODE_SELECT(x) ((x) << 26) /* 2 bits */
#define PRE_MEA_EN(x) ((x) << 24)
#define PRE_MEA_THRE_CNT(x) ((x) << 0) /* 24 bits */
/* TP_CTRL3 bits */
#define FILTER_EN(x) ((x) << 2)
#define FILTER_TYPE(x) ((x) << 0) /* 2 bits */
/* TP_INT_FIFOC irq and fifo mask / control bits */
#define TEMP_IRQ_EN(x) ((x) << 18)
#define OVERRUN_IRQ_EN(x) ((x) << 17)
#define DATA_IRQ_EN(x) ((x) << 16)
#define TP_DATA_XY_CHANGE(x) ((x) << 13)
#define FIFO_TRIG(x) ((x) << 8) /* 5 bits */
#define DATA_DRQ_EN(x) ((x) << 7)
#define FIFO_FLUSH(x) ((x) << 4)
#define TP_UP_IRQ_EN(x) ((x) << 1)
#define TP_DOWN_IRQ_EN(x) ((x) << 0)
/* TP_INT_FIFOS irq and fifo status bits */
#define TEMP_DATA_PENDING BIT(18)
#define FIFO_OVERRUN_PENDING BIT(17)
#define FIFO_DATA_PENDING BIT(16)
#define TP_IDLE_FLG BIT(2)
#define TP_UP_PENDING BIT(1)
#define TP_DOWN_PENDING BIT(0)
/* TP_TPR bits */
#define TEMP_ENABLE(x) ((x) << 16)
#define TEMP_PERIOD(x) ((x) << 0) /* t = x * 256 * 16 / clkin */
struct sun4i_ts_data {
struct device *dev;
struct input_dev *input;
void __iomem *base;
unsigned int irq;
bool ignore_fifo_data;
int temp_data;
};
static void sun4i_ts_irq_handle_input(struct sun4i_ts_data *ts, u32 reg_val)
{
u32 x, y;
if (reg_val & FIFO_DATA_PENDING) {
x = readl(ts->base + TP_DATA);
y = readl(ts->base + TP_DATA);
/* The 1st location reported after an up event is unreliable */
if (!ts->ignore_fifo_data) {
input_report_abs(ts->input, ABS_X, x);
input_report_abs(ts->input, ABS_Y, y);
/*
* The hardware has a separate down status bit, but
* that gets set before we get the first location,
* resulting in reporting a click on the old location.
*/
input_report_key(ts->input, BTN_TOUCH, 1);
input_sync(ts->input);
} else {
ts->ignore_fifo_data = false;
}
}
if (reg_val & TP_UP_PENDING) {
ts->ignore_fifo_data = true;
input_report_key(ts->input, BTN_TOUCH, 0);
input_sync(ts->input);
}
}
static irqreturn_t sun4i_ts_irq(int irq, void *dev_id)
{
struct sun4i_ts_data *ts = dev_id;
u32 reg_val;
reg_val = readl(ts->base + TP_INT_FIFOS);
if (reg_val & TEMP_DATA_PENDING)
ts->temp_data = readl(ts->base + TEMP_DATA);
if (ts->input)
sun4i_ts_irq_handle_input(ts, reg_val);
writel(reg_val, ts->base + TP_INT_FIFOS);
return IRQ_HANDLED;
}
static int sun4i_ts_open(struct input_dev *dev)
{
struct sun4i_ts_data *ts = input_get_drvdata(dev);
/* Flush, set trig level to 1, enable temp, data and up irqs */
writel(TEMP_IRQ_EN(1) | DATA_IRQ_EN(1) | FIFO_TRIG(1) | FIFO_FLUSH(1) |
TP_UP_IRQ_EN(1), ts->base + TP_INT_FIFOC);
return 0;
}
static void sun4i_ts_close(struct input_dev *dev)
{
struct sun4i_ts_data *ts = input_get_drvdata(dev);
/* Deactivate all input IRQs */
writel(TEMP_IRQ_EN(1), ts->base + TP_INT_FIFOC);
}
static ssize_t show_temp(struct device *dev, struct device_attribute *devattr,
char *buf)
{
struct sun4i_ts_data *ts = dev_get_drvdata(dev);
/* No temp_data until the first irq */
if (ts->temp_data == -1)
return -EAGAIN;
return sprintf(buf, "%d\n", (ts->temp_data - 1447) * 100);
}
static ssize_t show_temp_label(struct device *dev,
struct device_attribute *devattr, char *buf)
{
return sprintf(buf, "SoC temperature\n");
}
static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL);
static DEVICE_ATTR(temp1_label, S_IRUGO, show_temp_label, NULL);
static struct attribute *sun4i_ts_attrs[] = {
&dev_attr_temp1_input.attr,
&dev_attr_temp1_label.attr,
NULL
};
ATTRIBUTE_GROUPS(sun4i_ts);
static int sun4i_ts_probe(struct platform_device *pdev)
{
struct sun4i_ts_data *ts;
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
struct device *hwmon;
int error;
bool ts_attached;
ts = devm_kzalloc(dev, sizeof(struct sun4i_ts_data), GFP_KERNEL);
if (!ts)
return -ENOMEM;
ts->dev = dev;
ts->ignore_fifo_data = true;
ts->temp_data = -1;
ts_attached = of_property_read_bool(np, "allwinner,ts-attached");
if (ts_attached) {
ts->input = devm_input_allocate_device(dev);
if (!ts->input)
return -ENOMEM;
ts->input->name = pdev->name;
ts->input->phys = "sun4i_ts/input0";
ts->input->open = sun4i_ts_open;
ts->input->close = sun4i_ts_close;
ts->input->id.bustype = BUS_HOST;
ts->input->id.vendor = 0x0001;
ts->input->id.product = 0x0001;
ts->input->id.version = 0x0100;
ts->input->evbit[0] = BIT(EV_SYN) | BIT(EV_KEY) | BIT(EV_ABS);
__set_bit(BTN_TOUCH, ts->input->keybit);
input_set_abs_params(ts->input, ABS_X, 0, 4095, 0, 0);
input_set_abs_params(ts->input, ABS_Y, 0, 4095, 0, 0);
input_set_drvdata(ts->input, ts);
}
ts->base = devm_ioremap_resource(dev,
platform_get_resource(pdev, IORESOURCE_MEM, 0));
if (IS_ERR(ts->base))
return PTR_ERR(ts->base);
ts->irq = platform_get_irq(pdev, 0);
error = devm_request_irq(dev, ts->irq, sun4i_ts_irq, 0, "sun4i-ts", ts);
if (error)
return error;
/*
* Select HOSC clk, clkin = clk / 6, adc samplefreq = clkin / 8192,
* t_acq = clkin / (16 * 64)
*/
writel(ADC_CLK_SEL(0) | ADC_CLK_DIV(2) | FS_DIV(7) | T_ACQ(63),
ts->base + TP_CTRL0);
/*
* sensitive_adjust = 15 : max, which is not all that sensitive,
* tp_mode = 0 : only x and y coordinates, as we don't use dual touch
*/
writel(TP_SENSITIVE_ADJUST(15) | TP_MODE_SELECT(0),
ts->base + TP_CTRL2);
/* Enable median filter, type 1 : 5/3 */
writel(FILTER_EN(1) | FILTER_TYPE(1), ts->base + TP_CTRL3);
/* Enable temperature measurement, period 1953 (2 seconds) */
writel(TEMP_ENABLE(1) | TEMP_PERIOD(1953), ts->base + TP_TPR);
/*
* Set stylus up debounce to aprox 10 ms, enable debounce, and
* finally enable tp mode.
*/
writel(STYLUS_UP_DEBOUN(5) | STYLUS_UP_DEBOUN_EN(1) | TP_MODE_EN(1),
ts->base + TP_CTRL1);
hwmon = devm_hwmon_device_register_with_groups(ts->dev, "sun4i_ts",
ts, sun4i_ts_groups);
if (IS_ERR(hwmon))
return PTR_ERR(hwmon);
writel(TEMP_IRQ_EN(1), ts->base + TP_INT_FIFOC);
if (ts_attached) {
error = input_register_device(ts->input);
if (error) {
writel(0, ts->base + TP_INT_FIFOC);
return error;
}
}
platform_set_drvdata(pdev, ts);
return 0;
}
static int sun4i_ts_remove(struct platform_device *pdev)
{
struct sun4i_ts_data *ts = platform_get_drvdata(pdev);
/* Explicit unregister to avoid open/close changing the imask later */
if (ts->input)
input_unregister_device(ts->input);
/* Deactivate all IRQs */
writel(0, ts->base + TP_INT_FIFOC);
return 0;
}
static const struct of_device_id sun4i_ts_of_match[] = {
{ .compatible = "allwinner,sun4i-a10-ts", },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, sun4i_ts_of_match);
static struct platform_driver sun4i_ts_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "sun4i-ts",
.of_match_table = of_match_ptr(sun4i_ts_of_match),
},
.probe = sun4i_ts_probe,
.remove = sun4i_ts_remove,
};
module_platform_driver(sun4i_ts_driver);
MODULE_DESCRIPTION("Allwinner sun4i resistive touchscreen controller driver");
MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
MODULE_LICENSE("GPL");

View File

@@ -25,11 +25,15 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/input.h>
#include <linux/input/touchscreen.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/spi/spi.h>
#include <linux/spi/tsc2005.h>
#include <linux/regulator/consumer.h>
/*
* The touchscreen interface operates as follows:
@@ -100,6 +104,11 @@
TSC2005_CFR2_AVG_7)
#define MAX_12BIT 0xfff
#define TSC2005_DEF_X_FUZZ 4
#define TSC2005_DEF_Y_FUZZ 8
#define TSC2005_DEF_P_FUZZ 2
#define TSC2005_DEF_RESISTOR 280
#define TSC2005_SPI_MAX_SPEED_HZ 10000000
#define TSC2005_PENUP_TIME_MS 40
@@ -143,6 +152,9 @@ struct tsc2005 {
bool pen_down;
struct regulator *vio;
int reset_gpio;
void (*set_reset)(bool enable);
};
@@ -337,6 +349,14 @@ static void tsc2005_stop_scan(struct tsc2005 *ts)
tsc2005_cmd(ts, TSC2005_CMD_STOP);
}
static void tsc2005_set_reset(struct tsc2005 *ts, bool enable)
{
if (ts->reset_gpio >= 0)
gpio_set_value(ts->reset_gpio, enable);
else if (ts->set_reset)
ts->set_reset(enable);
}
/* must be called with ts->mutex held */
static void __tsc2005_disable(struct tsc2005 *ts)
{
@@ -355,7 +375,7 @@ static void __tsc2005_enable(struct tsc2005 *ts)
{
tsc2005_start_scan(ts);
if (ts->esd_timeout && ts->set_reset) {
if (ts->esd_timeout && (ts->set_reset || ts->reset_gpio)) {
ts->last_valid_interrupt = jiffies;
schedule_delayed_work(&ts->esd_work,
round_jiffies_relative(
@@ -414,9 +434,9 @@ static ssize_t tsc2005_selftest_show(struct device *dev,
}
/* hardware reset */
ts->set_reset(false);
tsc2005_set_reset(ts, false);
usleep_range(100, 500); /* only 10us required */
ts->set_reset(true);
tsc2005_set_reset(ts, true);
if (!success)
goto out;
@@ -459,7 +479,7 @@ static umode_t tsc2005_attr_is_visible(struct kobject *kobj,
umode_t mode = attr->mode;
if (attr == &dev_attr_selftest.attr) {
if (!ts->set_reset)
if (!ts->set_reset && !ts->reset_gpio)
mode = 0;
}
@@ -509,9 +529,9 @@ static void tsc2005_esd_work(struct work_struct *work)
tsc2005_update_pen_state(ts, 0, 0, 0);
ts->set_reset(false);
tsc2005_set_reset(ts, false);
usleep_range(100, 500); /* only 10us required */
ts->set_reset(true);
tsc2005_set_reset(ts, true);
enable_irq(ts->spi->irq);
tsc2005_start_scan(ts);
@@ -572,29 +592,47 @@ static void tsc2005_setup_spi_xfer(struct tsc2005 *ts)
static int tsc2005_probe(struct spi_device *spi)
{
const struct tsc2005_platform_data *pdata = dev_get_platdata(&spi->dev);
struct device_node *np = spi->dev.of_node;
struct tsc2005 *ts;
struct input_dev *input_dev;
unsigned int max_x, max_y, max_p;
unsigned int fudge_x, fudge_y, fudge_p;
unsigned int max_x = MAX_12BIT;
unsigned int max_y = MAX_12BIT;
unsigned int max_p = MAX_12BIT;
unsigned int fudge_x = TSC2005_DEF_X_FUZZ;
unsigned int fudge_y = TSC2005_DEF_Y_FUZZ;
unsigned int fudge_p = TSC2005_DEF_P_FUZZ;
unsigned int x_plate_ohm = TSC2005_DEF_RESISTOR;
unsigned int esd_timeout;
int error;
if (!pdata) {
dev_dbg(&spi->dev, "no platform data\n");
if (!np && !pdata) {
dev_err(&spi->dev, "no platform data\n");
return -ENODEV;
}
fudge_x = pdata->ts_x_fudge ? : 4;
fudge_y = pdata->ts_y_fudge ? : 8;
fudge_p = pdata->ts_pressure_fudge ? : 2;
max_x = pdata->ts_x_max ? : MAX_12BIT;
max_y = pdata->ts_y_max ? : MAX_12BIT;
max_p = pdata->ts_pressure_max ? : MAX_12BIT;
if (spi->irq <= 0) {
dev_dbg(&spi->dev, "no irq\n");
dev_err(&spi->dev, "no irq\n");
return -ENODEV;
}
if (pdata) {
fudge_x = pdata->ts_x_fudge;
fudge_y = pdata->ts_y_fudge;
fudge_p = pdata->ts_pressure_fudge;
max_x = pdata->ts_x_max;
max_y = pdata->ts_y_max;
max_p = pdata->ts_pressure_max;
x_plate_ohm = pdata->ts_x_plate_ohm;
esd_timeout = pdata->esd_timeout_ms;
} else {
x_plate_ohm = TSC2005_DEF_RESISTOR;
of_property_read_u32(np, "ti,x-plate-ohms", &x_plate_ohm);
esd_timeout = 0;
of_property_read_u32(np, "ti,esd-recovery-timeout-ms",
&esd_timeout);
}
spi->mode = SPI_MODE_0;
spi->bits_per_word = 8;
if (!spi->max_speed_hz)
@@ -604,19 +642,48 @@ static int tsc2005_probe(struct spi_device *spi)
if (error)
return error;
ts = kzalloc(sizeof(*ts), GFP_KERNEL);
input_dev = input_allocate_device();
if (!ts || !input_dev) {
error = -ENOMEM;
goto err_free_mem;
}
ts = devm_kzalloc(&spi->dev, sizeof(*ts), GFP_KERNEL);
if (!ts)
return -ENOMEM;
input_dev = devm_input_allocate_device(&spi->dev);
if (!input_dev)
return -ENOMEM;
ts->spi = spi;
ts->idev = input_dev;
ts->x_plate_ohm = pdata->ts_x_plate_ohm ? : 280;
ts->esd_timeout = pdata->esd_timeout_ms;
ts->set_reset = pdata->set_reset;
ts->x_plate_ohm = x_plate_ohm;
ts->esd_timeout = esd_timeout;
if (np) {
ts->reset_gpio = of_get_named_gpio(np, "reset-gpios", 0);
if (ts->reset_gpio == -EPROBE_DEFER)
return ts->reset_gpio;
if (ts->reset_gpio < 0) {
dev_err(&spi->dev, "error acquiring reset gpio: %d\n",
ts->reset_gpio);
return ts->reset_gpio;
}
error = devm_gpio_request_one(&spi->dev, ts->reset_gpio, 0,
"reset-gpios");
if (error) {
dev_err(&spi->dev, "error requesting reset gpio: %d\n",
error);
return error;
}
ts->vio = devm_regulator_get(&spi->dev, "vio");
if (IS_ERR(ts->vio)) {
error = PTR_ERR(ts->vio);
dev_err(&spi->dev, "vio regulator missing (%d)", error);
return error;
}
} else {
ts->reset_gpio = -1;
ts->set_reset = pdata->set_reset;
}
mutex_init(&ts->mutex);
@@ -641,6 +708,9 @@ static int tsc2005_probe(struct spi_device *spi)
input_set_abs_params(input_dev, ABS_Y, 0, max_y, fudge_y, 0);
input_set_abs_params(input_dev, ABS_PRESSURE, 0, max_p, fudge_p, 0);
if (np)
touchscreen_parse_of_params(input_dev);
input_dev->open = tsc2005_open;
input_dev->close = tsc2005_close;
@@ -649,12 +719,20 @@ static int tsc2005_probe(struct spi_device *spi)
/* Ensure the touchscreen is off */
tsc2005_stop_scan(ts);
error = request_threaded_irq(spi->irq, NULL, tsc2005_irq_thread,
IRQF_TRIGGER_RISING | IRQF_ONESHOT,
"tsc2005", ts);
error = devm_request_threaded_irq(&spi->dev, spi->irq, NULL,
tsc2005_irq_thread,
IRQF_TRIGGER_RISING | IRQF_ONESHOT,
"tsc2005", ts);
if (error) {
dev_err(&spi->dev, "Failed to request irq, err: %d\n", error);
goto err_free_mem;
return error;
}
/* enable regulator for DT */
if (ts->vio) {
error = regulator_enable(ts->vio);
if (error)
return error;
}
spi_set_drvdata(spi, ts);
@@ -662,7 +740,7 @@ static int tsc2005_probe(struct spi_device *spi)
if (error) {
dev_err(&spi->dev,
"Failed to create sysfs attributes, err: %d\n", error);
goto err_clear_drvdata;
goto disable_regulator;
}
error = input_register_device(ts->idev);
@@ -677,11 +755,9 @@ static int tsc2005_probe(struct spi_device *spi)
err_remove_sysfs:
sysfs_remove_group(&spi->dev.kobj, &tsc2005_attr_group);
err_clear_drvdata:
free_irq(spi->irq, ts);
err_free_mem:
input_free_device(input_dev);
kfree(ts);
disable_regulator:
if (ts->vio)
regulator_disable(ts->vio);
return error;
}
@@ -689,11 +765,10 @@ static int tsc2005_remove(struct spi_device *spi)
{
struct tsc2005 *ts = spi_get_drvdata(spi);
sysfs_remove_group(&ts->spi->dev.kobj, &tsc2005_attr_group);
sysfs_remove_group(&spi->dev.kobj, &tsc2005_attr_group);
free_irq(ts->spi->irq, ts);
input_unregister_device(ts->idev);
kfree(ts);
if (ts->vio)
regulator_disable(ts->vio);
return 0;
}

View File

@@ -880,7 +880,7 @@ static struct i2c_device_id zforce_idtable[] = {
MODULE_DEVICE_TABLE(i2c, zforce_idtable);
#ifdef CONFIG_OF
static struct of_device_id zforce_dt_idtable[] = {
static const struct of_device_id zforce_dt_idtable[] = {
{ .compatible = "neonode,zforce" },
{},
};