Merge branch 'next' into for-linus
Prepare input updates for 3.16.
This commit is contained in:
@@ -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);
|
||||
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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;
|
||||
|
@@ -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
@@ -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" },
|
||||
{},
|
||||
};
|
||||
|
@@ -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);
|
||||
|
||||
|
@@ -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:
|
||||
|
@@ -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 */ }
|
||||
};
|
||||
|
@@ -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);
|
||||
|
||||
|
@@ -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", },
|
||||
{ },
|
||||
};
|
||||
|
@@ -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,
|
||||
};
|
||||
|
@@ -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" },
|
||||
{ }
|
||||
};
|
||||
|
45
drivers/input/touchscreen/of_touchscreen.c
Normal file
45
drivers/input/touchscreen/of_touchscreen.c
Normal 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);
|
@@ -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;
|
||||
}
|
||||
|
||||
|
@@ -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 */
|
||||
|
339
drivers/input/touchscreen/sun4i-ts.c
Normal file
339
drivers/input/touchscreen/sun4i-ts.c
Normal 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");
|
@@ -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;
|
||||
}
|
||||
|
@@ -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" },
|
||||
{},
|
||||
};
|
||||
|
Reference in New Issue
Block a user