Merge branch 'next' into for-linus

Prepare input updates for 4.15 merge window.
This commit is contained in:
Dmitry Torokhov
2017-11-13 17:10:13 -08:00
28314 changed files with 1440897 additions and 571954 deletions

View File

@@ -316,6 +316,16 @@ config TOUCHSCREEN_EGALAX_SERIAL
To compile this driver as a module, choose M here: the
module will be called egalax_ts_serial.
config TOUCHSCREEN_EXC3000
tristate "EETI EXC3000 multi-touch panel support"
depends on I2C
help
Say Y here to enable support for I2C connected EETI
EXC3000 multi-touch panels.
To compile this driver as a module, choose M here: the
module will be called exc3000.
config TOUCHSCREEN_FUJITSU
tristate "Fujitsu serial touchscreen"
select SERIO
@@ -344,6 +354,17 @@ config TOUCHSCREEN_GOODIX
To compile this driver as a module, choose M here: the
module will be called goodix.
config TOUCHSCREEN_HIDEEP
tristate "HiDeep Touch IC"
depends on I2C
help
Say Y here if you have a touchscreen using HiDeep.
If unsure, say N.
To compile this driver as a moudle, choose M here : the
module will be called hideep_ts.
config TOUCHSCREEN_ILI210X
tristate "Ilitek ILI210X based touchscreen"
depends on I2C
@@ -383,6 +404,17 @@ config TOUCHSCREEN_S3C2410
To compile this driver as a module, choose M here: the
module will be called s3c2410_ts.
config TOUCHSCREEN_S6SY761
tristate "Samsung S6SY761 Touchscreen driver"
depends on I2C
help
Say Y if you have the Samsung S6SY761 driver
If unsure, say N
To compile this driver as module, choose M here: the
module will be called s6sy761.
config TOUCHSCREEN_GUNZE
tristate "Gunze AHL-51S touchscreen"
select SERIO
@@ -949,7 +981,7 @@ config TOUCHSCREEN_USB_NEXIO
config TOUCHSCREEN_USB_EASYTOUCH
default y
bool "EasyTouch USB Touch controller device support" if EMBEDDED
bool "EasyTouch USB Touch controller device support" if EXPERT
depends on TOUCHSCREEN_USB_COMPOSITE
help
Say Y here if you have an EasyTouch USB Touch controller.

View File

@@ -1,3 +1,4 @@
# SPDX-License-Identifier: GPL-2.0
#
# Makefile for the touchscreen drivers.
#
@@ -37,8 +38,10 @@ obj-$(CONFIG_TOUCHSCREEN_ELAN) += elants_i2c.o
obj-$(CONFIG_TOUCHSCREEN_ELO) += elo.o
obj-$(CONFIG_TOUCHSCREEN_EGALAX) += egalax_ts.o
obj-$(CONFIG_TOUCHSCREEN_EGALAX_SERIAL) += egalax_ts_serial.o
obj-$(CONFIG_TOUCHSCREEN_EXC3000) += exc3000.o
obj-$(CONFIG_TOUCHSCREEN_FUJITSU) += fujitsu_ts.o
obj-$(CONFIG_TOUCHSCREEN_GOODIX) += goodix.o
obj-$(CONFIG_TOUCHSCREEN_HIDEEP) += hideep.o
obj-$(CONFIG_TOUCHSCREEN_ILI210X) += ili210x.o
obj-$(CONFIG_TOUCHSCREEN_IMX6UL_TSC) += imx6ul_tsc.o
obj-$(CONFIG_TOUCHSCREEN_INEXIO) += inexio.o
@@ -64,6 +67,7 @@ obj-$(CONFIG_TOUCHSCREEN_PENMOUNT) += penmount.o
obj-$(CONFIG_TOUCHSCREEN_PIXCIR) += pixcir_i2c_ts.o
obj-$(CONFIG_TOUCHSCREEN_RM_TS) += raydium_i2c_ts.o
obj-$(CONFIG_TOUCHSCREEN_S3C2410) += s3c2410_ts.o
obj-$(CONFIG_TOUCHSCREEN_S6SY761) += s6sy761.o
obj-$(CONFIG_TOUCHSCREEN_SILEAD) += silead.o
obj-$(CONFIG_TOUCHSCREEN_SIS_I2C) += sis_i2c.o
obj-$(CONFIG_TOUCHSCREEN_ST1232) += st1232.o

View File

@@ -385,9 +385,9 @@ static inline void ad7877_ts_event_release(struct ad7877 *ts)
input_sync(input_dev);
}
static void ad7877_timer(unsigned long handle)
static void ad7877_timer(struct timer_list *t)
{
struct ad7877 *ts = (void *)handle;
struct ad7877 *ts = from_timer(ts, t, timer);
unsigned long flags;
spin_lock_irqsave(&ts->lock, flags);
@@ -718,7 +718,7 @@ static int ad7877_probe(struct spi_device *spi)
ts->spi = spi;
ts->input = input_dev;
setup_timer(&ts->timer, ad7877_timer, (unsigned long) ts);
timer_setup(&ts->timer, ad7877_timer, 0);
mutex_init(&ts->mutex);
spin_lock_init(&ts->lock);

View File

@@ -237,9 +237,9 @@ static void ad7879_ts_event_release(struct ad7879 *ts)
input_sync(input_dev);
}
static void ad7879_timer(unsigned long handle)
static void ad7879_timer(struct timer_list *t)
{
struct ad7879 *ts = (void *)handle;
struct ad7879 *ts = from_timer(ts, t, timer);
ad7879_ts_event_release(ts);
}
@@ -524,13 +524,6 @@ static int ad7879_parse_dt(struct device *dev, struct ad7879 *ts)
return 0;
}
static void ad7879_cleanup_sysfs(void *_ts)
{
struct ad7879 *ts = _ts;
sysfs_remove_group(&ts->dev->kobj, &ad7879_attr_group);
}
int ad7879_probe(struct device *dev, struct regmap *regmap,
int irq, u16 bustype, u8 devid)
{
@@ -577,7 +570,7 @@ int ad7879_probe(struct device *dev, struct regmap *regmap,
ts->irq = irq;
ts->regmap = regmap;
setup_timer(&ts->timer, ad7879_timer, (unsigned long) ts);
timer_setup(&ts->timer, ad7879_timer, 0);
snprintf(ts->phys, sizeof(ts->phys), "%s/input0", dev_name(dev));
input_dev->name = "AD7879 Touchscreen";
@@ -658,11 +651,7 @@ int ad7879_probe(struct device *dev, struct regmap *regmap,
__ad7879_disable(ts);
err = sysfs_create_group(&dev->kobj, &ad7879_attr_group);
if (err)
return err;
err = devm_add_action_or_reset(dev, ad7879_cleanup_sysfs, ts);
err = devm_device_add_group(dev, &ad7879_attr_group);
if (err)
return err;

View File

@@ -208,9 +208,12 @@ static void atmel_wm97xx_acc_pen_up(struct wm97xx *wm)
}
}
static void atmel_wm97xx_pen_timer(unsigned long data)
static void atmel_wm97xx_pen_timer(struct timer_list *t)
{
atmel_wm97xx_acc_pen_up((struct wm97xx *)data);
struct atmel_wm97xx *atmel_wm97xx = from_timer(atmel_wm97xx, t,
pen_timer);
atmel_wm97xx_acc_pen_up(atmel_wm97xx->wm);
}
static int atmel_wm97xx_acc_startup(struct wm97xx *wm)
@@ -348,8 +351,7 @@ static int __init atmel_wm97xx_probe(struct platform_device *pdev)
atmel_wm97xx->gpio_pen = atmel_gpio_line;
atmel_wm97xx->gpio_irq = gpio_to_irq(atmel_wm97xx->gpio_pen);
setup_timer(&atmel_wm97xx->pen_timer, atmel_wm97xx_pen_timer,
(unsigned long)wm);
timer_setup(&atmel_wm97xx->pen_timer, atmel_wm97xx_pen_timer, 0);
ret = request_irq(atmel_wm97xx->ac97c_irq,
atmel_wm97xx_channel_b_interrupt,

View File

@@ -201,13 +201,21 @@ static int cyttsp4_si_get_cydata(struct cyttsp4 *cd)
void *p;
int rc;
if (si->si_ofs.test_ofs <= si->si_ofs.cydata_ofs) {
dev_err(cd->dev,
"%s: invalid offset test_ofs: %zu, cydata_ofs: %zu\n",
__func__, si->si_ofs.test_ofs, si->si_ofs.cydata_ofs);
return -EINVAL;
}
si->si_ofs.cydata_size = si->si_ofs.test_ofs - si->si_ofs.cydata_ofs;
dev_dbg(cd->dev, "%s: cydata size: %zd\n", __func__,
si->si_ofs.cydata_size);
p = krealloc(si->si_ptrs.cydata, si->si_ofs.cydata_size, GFP_KERNEL);
if (p == NULL) {
dev_err(cd->dev, "%s: fail alloc cydata memory\n", __func__);
dev_err(cd->dev, "%s: failed to allocate cydata memory\n",
__func__);
return -ENOMEM;
}
si->si_ptrs.cydata = p;
@@ -270,11 +278,19 @@ static int cyttsp4_si_get_test_data(struct cyttsp4 *cd)
void *p;
int rc;
if (si->si_ofs.pcfg_ofs <= si->si_ofs.test_ofs) {
dev_err(cd->dev,
"%s: invalid offset pcfg_ofs: %zu, test_ofs: %zu\n",
__func__, si->si_ofs.pcfg_ofs, si->si_ofs.test_ofs);
return -EINVAL;
}
si->si_ofs.test_size = si->si_ofs.pcfg_ofs - si->si_ofs.test_ofs;
p = krealloc(si->si_ptrs.test, si->si_ofs.test_size, GFP_KERNEL);
if (p == NULL) {
dev_err(cd->dev, "%s: fail alloc test memory\n", __func__);
dev_err(cd->dev, "%s: failed to allocate test memory\n",
__func__);
return -ENOMEM;
}
si->si_ptrs.test = p;
@@ -321,14 +337,20 @@ static int cyttsp4_si_get_pcfg_data(struct cyttsp4 *cd)
void *p;
int rc;
if (si->si_ofs.opcfg_ofs <= si->si_ofs.pcfg_ofs) {
dev_err(cd->dev,
"%s: invalid offset opcfg_ofs: %zu, pcfg_ofs: %zu\n",
__func__, si->si_ofs.opcfg_ofs, si->si_ofs.pcfg_ofs);
return -EINVAL;
}
si->si_ofs.pcfg_size = si->si_ofs.opcfg_ofs - si->si_ofs.pcfg_ofs;
p = krealloc(si->si_ptrs.pcfg, si->si_ofs.pcfg_size, GFP_KERNEL);
if (p == NULL) {
rc = -ENOMEM;
dev_err(cd->dev, "%s: fail alloc pcfg memory r=%d\n",
__func__, rc);
return rc;
dev_err(cd->dev, "%s: failed to allocate pcfg memory\n",
__func__);
return -ENOMEM;
}
si->si_ptrs.pcfg = p;
@@ -367,13 +389,20 @@ static int cyttsp4_si_get_opcfg_data(struct cyttsp4 *cd)
void *p;
int rc;
if (si->si_ofs.ddata_ofs <= si->si_ofs.opcfg_ofs) {
dev_err(cd->dev,
"%s: invalid offset ddata_ofs: %zu, opcfg_ofs: %zu\n",
__func__, si->si_ofs.ddata_ofs, si->si_ofs.opcfg_ofs);
return -EINVAL;
}
si->si_ofs.opcfg_size = si->si_ofs.ddata_ofs - si->si_ofs.opcfg_ofs;
p = krealloc(si->si_ptrs.opcfg, si->si_ofs.opcfg_size, GFP_KERNEL);
if (p == NULL) {
dev_err(cd->dev, "%s: fail alloc opcfg memory\n", __func__);
rc = -ENOMEM;
goto cyttsp4_si_get_opcfg_data_exit;
dev_err(cd->dev, "%s: failed to allocate opcfg memory\n",
__func__);
return -ENOMEM;
}
si->si_ptrs.opcfg = p;
@@ -382,7 +411,7 @@ static int cyttsp4_si_get_opcfg_data(struct cyttsp4 *cd)
if (rc < 0) {
dev_err(cd->dev, "%s: fail read opcfg data r=%d\n",
__func__, rc);
goto cyttsp4_si_get_opcfg_data_exit;
return rc;
}
si->si_ofs.cmd_ofs = si->si_ptrs.opcfg->cmd_ofs;
si->si_ofs.rep_ofs = si->si_ptrs.opcfg->rep_ofs;
@@ -447,8 +476,7 @@ static int cyttsp4_si_get_opcfg_data(struct cyttsp4 *cd)
cyttsp4_pr_buf(cd->dev, cd->pr_buf, (u8 *)si->si_ptrs.opcfg,
si->si_ofs.opcfg_size, "sysinfo_opcfg_data");
cyttsp4_si_get_opcfg_data_exit:
return rc;
return 0;
}
static int cyttsp4_si_get_ddata(struct cyttsp4 *cd)
@@ -1237,9 +1265,9 @@ static void cyttsp4_stop_wd_timer(struct cyttsp4 *cd)
del_timer_sync(&cd->watchdog_timer);
}
static void cyttsp4_watchdog_timer(unsigned long handle)
static void cyttsp4_watchdog_timer(struct timer_list *t)
{
struct cyttsp4 *cd = (struct cyttsp4 *)handle;
struct cyttsp4 *cd = from_timer(cd, t, watchdog_timer);
dev_vdbg(cd->dev, "%s: Watchdog timer triggered\n", __func__);
@@ -2074,8 +2102,7 @@ struct cyttsp4 *cyttsp4_probe(const struct cyttsp4_bus_ops *ops,
}
/* Setup watchdog timer */
setup_timer(&cd->watchdog_timer, cyttsp4_watchdog_timer,
(unsigned long)cd);
timer_setup(&cd->watchdog_timer, cyttsp4_watchdog_timer, 0);
/*
* call startup directly to ensure that the device

View File

@@ -70,8 +70,10 @@
#define EDT_RAW_DATA_DELAY 1000 /* usec */
enum edt_ver {
M06,
M09,
EDT_M06,
EDT_M09,
EDT_M12,
GENERIC_FT,
};
struct edt_reg_addr {
@@ -179,14 +181,16 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id)
int error;
switch (tsdata->version) {
case M06:
case EDT_M06:
cmd = 0xf9; /* tell the controller to send touch data */
offset = 5; /* where the actual touch data starts */
tplen = 4; /* data comes in so called frames */
crclen = 1; /* length of the crc data */
break;
case M09:
case EDT_M09:
case EDT_M12:
case GENERIC_FT:
cmd = 0x0;
offset = 3;
tplen = 6;
@@ -209,8 +213,8 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id)
goto out;
}
/* M09 does not send header or CRC */
if (tsdata->version == M06) {
/* M09/M12 does not send header or CRC */
if (tsdata->version == EDT_M06) {
if (rdbuf[0] != 0xaa || rdbuf[1] != 0xaa ||
rdbuf[2] != datalen) {
dev_err_ratelimited(dev,
@@ -233,7 +237,7 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id)
continue;
/* M06 sometimes sends bogus coordinates in TOUCH_DOWN */
if (tsdata->version == M06 && type == TOUCH_EVENT_DOWN)
if (tsdata->version == EDT_M06 && type == TOUCH_EVENT_DOWN)
continue;
x = ((buf[0] << 8) | buf[1]) & 0x0fff;
@@ -264,14 +268,16 @@ static int edt_ft5x06_register_write(struct edt_ft5x06_ts_data *tsdata,
u8 wrbuf[4];
switch (tsdata->version) {
case M06:
case EDT_M06:
wrbuf[0] = tsdata->factory_mode ? 0xf3 : 0xfc;
wrbuf[1] = tsdata->factory_mode ? addr & 0x7f : addr & 0x3f;
wrbuf[2] = value;
wrbuf[3] = wrbuf[0] ^ wrbuf[1] ^ wrbuf[2];
return edt_ft5x06_ts_readwrite(tsdata->client, 4,
wrbuf, 0, NULL);
case M09:
case EDT_M09:
case EDT_M12:
case GENERIC_FT:
wrbuf[0] = addr;
wrbuf[1] = value;
@@ -290,7 +296,7 @@ static int edt_ft5x06_register_read(struct edt_ft5x06_ts_data *tsdata,
int error;
switch (tsdata->version) {
case M06:
case EDT_M06:
wrbuf[0] = tsdata->factory_mode ? 0xf3 : 0xfc;
wrbuf[1] = tsdata->factory_mode ? addr & 0x7f : addr & 0x3f;
wrbuf[1] |= tsdata->factory_mode ? 0x80 : 0x40;
@@ -309,7 +315,9 @@ static int edt_ft5x06_register_read(struct edt_ft5x06_ts_data *tsdata,
}
break;
case M09:
case EDT_M09:
case EDT_M12:
case GENERIC_FT:
wrbuf[0] = addr;
error = edt_ft5x06_ts_readwrite(tsdata->client, 1,
wrbuf, 1, rdbuf);
@@ -368,11 +376,13 @@ static ssize_t edt_ft5x06_setting_show(struct device *dev,
}
switch (tsdata->version) {
case M06:
case EDT_M06:
addr = attr->addr_m06;
break;
case M09:
case EDT_M09:
case EDT_M12:
case GENERIC_FT:
addr = attr->addr_m09;
break;
@@ -437,11 +447,13 @@ static ssize_t edt_ft5x06_setting_store(struct device *dev,
}
switch (tsdata->version) {
case M06:
case EDT_M06:
addr = attr->addr_m06;
break;
case M09:
case EDT_M09:
case EDT_M12:
case GENERIC_FT:
addr = attr->addr_m09;
break;
@@ -466,14 +478,18 @@ out:
return error ?: count;
}
/* m06, m09: range 0-31, m12: range 0-5 */
static EDT_ATTR(gain, S_IWUSR | S_IRUGO, WORK_REGISTER_GAIN,
M09_REGISTER_GAIN, 0, 31);
/* m06, m09: range 0-31, m12: range 0-16 */
static EDT_ATTR(offset, S_IWUSR | S_IRUGO, WORK_REGISTER_OFFSET,
M09_REGISTER_OFFSET, 0, 31);
/* m06: range 20 to 80, m09: range 0 to 30, m12: range 1 to 255... */
static EDT_ATTR(threshold, S_IWUSR | S_IRUGO, WORK_REGISTER_THRESHOLD,
M09_REGISTER_THRESHOLD, 0, 80);
M09_REGISTER_THRESHOLD, 0, 255);
/* m06: range 3 to 14, m12: (0x64: 100Hz) */
static EDT_ATTR(report_rate, S_IWUSR | S_IRUGO, WORK_REGISTER_REPORT_RATE,
NO_REGISTER, 3, 14);
NO_REGISTER, 0, 255);
static struct attribute *edt_ft5x06_attrs[] = {
&edt_ft5x06_attr_gain.dattr.attr,
@@ -508,7 +524,7 @@ static int edt_ft5x06_factory_mode(struct edt_ft5x06_ts_data *tsdata)
}
/* mode register is 0x3c when in the work mode */
if (tsdata->version == M09)
if (tsdata->version != EDT_M06)
goto m09_out;
error = edt_ft5x06_register_write(tsdata, WORK_REGISTER_OPMODE, 0x03);
@@ -545,7 +561,7 @@ err_out:
return error;
m09_out:
dev_err(&client->dev, "No factory mode support for M09\n");
dev_err(&client->dev, "No factory mode support for M09/M12/GENERIC_FT\n");
return -EINVAL;
}
@@ -770,16 +786,17 @@ static int edt_ft5x06_ts_identify(struct i2c_client *client,
* to have garbage in there
*/
memset(rdbuf, 0, sizeof(rdbuf));
error = edt_ft5x06_ts_readwrite(client, 1, "\xbb",
error = edt_ft5x06_ts_readwrite(client, 1, "\xBB",
EDT_NAME_LEN - 1, rdbuf);
if (error)
return error;
/* if we find something consistent, stay with that assumption
* at least M09 won't send 3 bytes here
/* Probe content for something consistent.
* M06 starts with a response byte, M12 gives the data directly.
* M09/Generic does not provide model number information.
*/
if (!(strncasecmp(rdbuf + 1, "EP0", 3))) {
tsdata->version = M06;
if (!strncasecmp(rdbuf + 1, "EP0", 3)) {
tsdata->version = EDT_M06;
/* remove last '$' end marker */
rdbuf[EDT_NAME_LEN - 1] = '\0';
@@ -792,9 +809,31 @@ static int edt_ft5x06_ts_identify(struct i2c_client *client,
*p++ = '\0';
strlcpy(model_name, rdbuf + 1, EDT_NAME_LEN);
strlcpy(fw_version, p ? p : "", EDT_NAME_LEN);
} else if (!strncasecmp(rdbuf, "EP0", 3)) {
tsdata->version = EDT_M12;
/* remove last '$' end marker */
rdbuf[EDT_NAME_LEN - 2] = '\0';
if (rdbuf[EDT_NAME_LEN - 3] == '$')
rdbuf[EDT_NAME_LEN - 3] = '\0';
/* look for Model/Version separator */
p = strchr(rdbuf, '*');
if (p)
*p++ = '\0';
strlcpy(model_name, rdbuf, EDT_NAME_LEN);
strlcpy(fw_version, p ? p : "", EDT_NAME_LEN);
} else {
/* since there are only two versions around (M06, M09) */
tsdata->version = M09;
/* If it is not an EDT M06/M12 touchscreen, then the model
* detection is a bit hairy. The different ft5x06
* firmares around don't reliably implement the
* identification registers. Well, we'll take a shot.
*
* The main difference between generic focaltec based
* touches and EDT M09 is that we know how to retrieve
* the max coordinates for the latter.
*/
tsdata->version = GENERIC_FT;
error = edt_ft5x06_ts_readwrite(client, 1, "\xA6",
2, rdbuf);
@@ -808,8 +847,34 @@ static int edt_ft5x06_ts_identify(struct i2c_client *client,
if (error)
return error;
snprintf(model_name, EDT_NAME_LEN, "EP0%i%i0M09",
rdbuf[0] >> 4, rdbuf[0] & 0x0F);
/* This "model identification" is not exact. Unfortunately
* not all firmwares for the ft5x06 put useful values in
* the identification registers.
*/
switch (rdbuf[0]) {
case 0x35: /* EDT EP0350M09 */
case 0x43: /* EDT EP0430M09 */
case 0x50: /* EDT EP0500M09 */
case 0x57: /* EDT EP0570M09 */
case 0x70: /* EDT EP0700M09 */
tsdata->version = EDT_M09;
snprintf(model_name, EDT_NAME_LEN, "EP0%i%i0M09",
rdbuf[0] >> 4, rdbuf[0] & 0x0F);
break;
case 0xa1: /* EDT EP1010ML00 */
tsdata->version = EDT_M09;
snprintf(model_name, EDT_NAME_LEN, "EP%i%i0ML00",
rdbuf[0] >> 4, rdbuf[0] & 0x0F);
break;
case 0x5a: /* Solomon Goldentek Display */
snprintf(model_name, EDT_NAME_LEN, "GKTW50SCED1R0");
break;
default:
snprintf(model_name, EDT_NAME_LEN,
"generic ft5x06 (%02x)",
rdbuf[0]);
break;
}
}
return 0;
@@ -853,8 +918,17 @@ edt_ft5x06_ts_get_parameters(struct edt_ft5x06_ts_data *tsdata)
if (reg_addr->reg_report_rate != NO_REGISTER)
tsdata->report_rate = edt_ft5x06_register_read(tsdata,
reg_addr->reg_report_rate);
tsdata->num_x = edt_ft5x06_register_read(tsdata, reg_addr->reg_num_x);
tsdata->num_y = edt_ft5x06_register_read(tsdata, reg_addr->reg_num_y);
if (tsdata->version == EDT_M06 ||
tsdata->version == EDT_M09 ||
tsdata->version == EDT_M12) {
tsdata->num_x = edt_ft5x06_register_read(tsdata,
reg_addr->reg_num_x);
tsdata->num_y = edt_ft5x06_register_read(tsdata,
reg_addr->reg_num_y);
} else {
tsdata->num_x = -1;
tsdata->num_y = -1;
}
}
static void
@@ -863,7 +937,7 @@ edt_ft5x06_ts_set_regs(struct edt_ft5x06_ts_data *tsdata)
struct edt_reg_addr *reg_addr = &tsdata->reg_addr;
switch (tsdata->version) {
case M06:
case EDT_M06:
reg_addr->reg_threshold = WORK_REGISTER_THRESHOLD;
reg_addr->reg_report_rate = WORK_REGISTER_REPORT_RATE;
reg_addr->reg_gain = WORK_REGISTER_GAIN;
@@ -872,7 +946,8 @@ edt_ft5x06_ts_set_regs(struct edt_ft5x06_ts_data *tsdata)
reg_addr->reg_num_y = WORK_REGISTER_NUM_Y;
break;
case M09:
case EDT_M09:
case EDT_M12:
reg_addr->reg_threshold = M09_REGISTER_THRESHOLD;
reg_addr->reg_report_rate = NO_REGISTER;
reg_addr->reg_gain = M09_REGISTER_GAIN;
@@ -880,6 +955,13 @@ edt_ft5x06_ts_set_regs(struct edt_ft5x06_ts_data *tsdata)
reg_addr->reg_num_x = M09_REGISTER_NUM_X;
reg_addr->reg_num_y = M09_REGISTER_NUM_Y;
break;
case GENERIC_FT:
/* this is a guesswork */
reg_addr->reg_threshold = M09_REGISTER_THRESHOLD;
reg_addr->reg_gain = M09_REGISTER_GAIN;
reg_addr->reg_offset = M09_REGISTER_OFFSET;
break;
}
}
@@ -969,10 +1051,20 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client,
input->id.bustype = BUS_I2C;
input->dev.parent = &client->dev;
input_set_abs_params(input, ABS_MT_POSITION_X,
0, tsdata->num_x * 64 - 1, 0, 0);
input_set_abs_params(input, ABS_MT_POSITION_Y,
0, tsdata->num_y * 64 - 1, 0, 0);
if (tsdata->version == EDT_M06 ||
tsdata->version == EDT_M09 ||
tsdata->version == EDT_M12) {
input_set_abs_params(input, ABS_MT_POSITION_X,
0, tsdata->num_x * 64 - 1, 0, 0);
input_set_abs_params(input, ABS_MT_POSITION_Y,
0, tsdata->num_y * 64 - 1, 0, 0);
} else {
/* Unknown maximum values. Specify via devicetree */
input_set_abs_params(input, ABS_MT_POSITION_X,
0, 65535, 0, 0);
input_set_abs_params(input, ABS_MT_POSITION_Y,
0, 65535, 0, 0);
}
touchscreen_parse_properties(input, true, &tsdata->prop);
@@ -998,13 +1090,13 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client,
return error;
}
error = sysfs_create_group(&client->dev.kobj, &edt_ft5x06_attr_group);
error = devm_device_add_group(&client->dev, &edt_ft5x06_attr_group);
if (error)
return error;
error = input_register_device(input);
if (error)
goto err_remove_attrs;
return error;
edt_ft5x06_ts_prepare_debugfs(tsdata, dev_driver_string(&client->dev));
device_init_wakeup(&client->dev, 1);
@@ -1016,10 +1108,6 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client,
tsdata->reset_gpio ? desc_to_gpio(tsdata->reset_gpio) : -1);
return 0;
err_remove_attrs:
sysfs_remove_group(&client->dev.kobj, &edt_ft5x06_attr_group);
return error;
}
static int edt_ft5x06_ts_remove(struct i2c_client *client)
@@ -1027,7 +1115,6 @@ static int edt_ft5x06_ts_remove(struct i2c_client *client)
struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(client);
edt_ft5x06_ts_teardown_debugfs(tsdata);
sysfs_remove_group(&client->dev.kobj, &edt_ft5x06_attr_group);
return 0;
}

View File

@@ -1070,13 +1070,6 @@ static const struct attribute_group elants_attribute_group = {
.attrs = elants_attributes,
};
static void elants_i2c_remove_sysfs_group(void *_data)
{
struct elants_data *ts = _data;
sysfs_remove_group(&ts->client->dev.kobj, &elants_attribute_group);
}
static int elants_i2c_power_on(struct elants_data *ts)
{
int error;
@@ -1289,23 +1282,13 @@ static int elants_i2c_probe(struct i2c_client *client,
if (!client->dev.of_node)
device_init_wakeup(&client->dev, true);
error = sysfs_create_group(&client->dev.kobj, &elants_attribute_group);
error = devm_device_add_group(&client->dev, &elants_attribute_group);
if (error) {
dev_err(&client->dev, "failed to create sysfs attributes: %d\n",
error);
return error;
}
error = devm_add_action(&client->dev,
elants_i2c_remove_sysfs_group, ts);
if (error) {
elants_i2c_remove_sysfs_group(ts);
dev_err(&client->dev,
"Failed to add sysfs cleanup action: %d\n",
error);
return error;
}
return 0;
}

View File

@@ -0,0 +1,223 @@
/*
* Driver for I2C connected EETI EXC3000 multiple touch controller
*
* Copyright (C) 2017 Ahmet Inan <inan@distec.de>
*
* minimal implementation based on egalax_ts.c and egalax_i2c.c
*
* 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/bitops.h>
#include <linux/device.h>
#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/input/mt.h>
#include <linux/input/touchscreen.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/timer.h>
#include <asm/unaligned.h>
#define EXC3000_NUM_SLOTS 10
#define EXC3000_SLOTS_PER_FRAME 5
#define EXC3000_LEN_FRAME 66
#define EXC3000_LEN_POINT 10
#define EXC3000_MT_EVENT 6
#define EXC3000_TIMEOUT_MS 100
struct exc3000_data {
struct i2c_client *client;
struct input_dev *input;
struct touchscreen_properties prop;
struct timer_list timer;
u8 buf[2 * EXC3000_LEN_FRAME];
};
static void exc3000_report_slots(struct input_dev *input,
struct touchscreen_properties *prop,
const u8 *buf, int num)
{
for (; num--; buf += EXC3000_LEN_POINT) {
if (buf[0] & BIT(0)) {
input_mt_slot(input, buf[1]);
input_mt_report_slot_state(input, MT_TOOL_FINGER, true);
touchscreen_report_pos(input, prop,
get_unaligned_le16(buf + 2),
get_unaligned_le16(buf + 4),
true);
}
}
}
static void exc3000_timer(struct timer_list *t)
{
struct exc3000_data *data = from_timer(data, t, timer);
input_mt_sync_frame(data->input);
input_sync(data->input);
}
static int exc3000_read_frame(struct i2c_client *client, u8 *buf)
{
int ret;
ret = i2c_master_send(client, "'", 2);
if (ret < 0)
return ret;
if (ret != 2)
return -EIO;
ret = i2c_master_recv(client, buf, EXC3000_LEN_FRAME);
if (ret < 0)
return ret;
if (ret != EXC3000_LEN_FRAME)
return -EIO;
if (get_unaligned_le16(buf) != EXC3000_LEN_FRAME ||
buf[2] != EXC3000_MT_EVENT)
return -EINVAL;
return 0;
}
static int exc3000_read_data(struct i2c_client *client,
u8 *buf, int *n_slots)
{
int error;
error = exc3000_read_frame(client, buf);
if (error)
return error;
*n_slots = buf[3];
if (!*n_slots || *n_slots > EXC3000_NUM_SLOTS)
return -EINVAL;
if (*n_slots > EXC3000_SLOTS_PER_FRAME) {
/* Read 2nd frame to get the rest of the contacts. */
error = exc3000_read_frame(client, buf + EXC3000_LEN_FRAME);
if (error)
return error;
/* 2nd chunk must have number of contacts set to 0. */
if (buf[EXC3000_LEN_FRAME + 3] != 0)
return -EINVAL;
}
return 0;
}
static irqreturn_t exc3000_interrupt(int irq, void *dev_id)
{
struct exc3000_data *data = dev_id;
struct input_dev *input = data->input;
u8 *buf = data->buf;
int slots, total_slots;
int error;
error = exc3000_read_data(data->client, buf, &total_slots);
if (error) {
/* Schedule a timer to release "stuck" contacts */
mod_timer(&data->timer,
jiffies + msecs_to_jiffies(EXC3000_TIMEOUT_MS));
goto out;
}
/*
* We read full state successfully, no contacts will be "stuck".
*/
del_timer_sync(&data->timer);
while (total_slots > 0) {
slots = min(total_slots, EXC3000_SLOTS_PER_FRAME);
exc3000_report_slots(input, &data->prop, buf + 4, slots);
total_slots -= slots;
buf += EXC3000_LEN_FRAME;
}
input_mt_sync_frame(input);
input_sync(input);
out:
return IRQ_HANDLED;
}
static int exc3000_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct exc3000_data *data;
struct input_dev *input;
int error;
data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
data->client = client;
timer_setup(&data->timer, exc3000_timer, 0);
input = devm_input_allocate_device(&client->dev);
if (!input)
return -ENOMEM;
data->input = input;
input->name = "EETI EXC3000 Touch Screen";
input->id.bustype = BUS_I2C;
input_set_abs_params(input, ABS_MT_POSITION_X, 0, 4095, 0, 0);
input_set_abs_params(input, ABS_MT_POSITION_Y, 0, 4095, 0, 0);
touchscreen_parse_properties(input, true, &data->prop);
error = input_mt_init_slots(input, EXC3000_NUM_SLOTS,
INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED);
if (error)
return error;
error = input_register_device(input);
if (error)
return error;
error = devm_request_threaded_irq(&client->dev, client->irq,
NULL, exc3000_interrupt, IRQF_ONESHOT,
client->name, data);
if (error)
return error;
return 0;
}
static const struct i2c_device_id exc3000_id[] = {
{ "exc3000", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, exc3000_id);
#ifdef CONFIG_OF
static const struct of_device_id exc3000_of_match[] = {
{ .compatible = "eeti,exc3000" },
{ }
};
MODULE_DEVICE_TABLE(of, exc3000_of_match);
#endif
static struct i2c_driver exc3000_driver = {
.driver = {
.name = "exc3000",
.of_match_table = of_match_ptr(exc3000_of_match),
},
.id_table = exc3000_id,
.probe = exc3000_probe,
};
module_i2c_driver(exc3000_driver);
MODULE_AUTHOR("Ahmet Inan <inan@distec.de>");
MODULE_DESCRIPTION("I2C connected EETI EXC3000 multiple touch controller driver");
MODULE_LICENSE("GPL v2");

View File

@@ -31,9 +31,18 @@
#include <linux/of.h>
#include <asm/unaligned.h>
struct goodix_ts_data;
struct goodix_chip_data {
u16 config_addr;
int config_len;
int (*check_config)(struct goodix_ts_data *, const struct firmware *);
};
struct goodix_ts_data {
struct i2c_client *client;
struct input_dev *input_dev;
const struct goodix_chip_data *chip;
int abs_x_max;
int abs_y_max;
bool swapped_x_y;
@@ -41,7 +50,6 @@ struct goodix_ts_data {
bool inverted_y;
unsigned int max_touch_num;
unsigned int int_trigger_type;
int cfg_len;
struct gpio_desc *gpiod_int;
struct gpio_desc *gpiod_rst;
u16 id;
@@ -69,7 +77,8 @@ struct goodix_ts_data {
#define GOODIX_CMD_SCREEN_OFF 0x05
#define GOODIX_READ_COOR_ADDR 0x814E
#define GOODIX_REG_CONFIG_DATA 0x8047
#define GOODIX_GT1X_REG_CONFIG_DATA 0x8050
#define GOODIX_GT9X_REG_CONFIG_DATA 0x8047
#define GOODIX_REG_ID 0x8140
#define GOODIX_BUFFER_STATUS_READY BIT(7)
@@ -79,6 +88,35 @@ struct goodix_ts_data {
#define MAX_CONTACTS_LOC 5
#define TRIGGER_LOC 6
static int goodix_check_cfg_8(struct goodix_ts_data *ts,
const struct firmware *cfg);
static int goodix_check_cfg_16(struct goodix_ts_data *ts,
const struct firmware *cfg);
static const struct goodix_chip_data gt1x_chip_data = {
.config_addr = GOODIX_GT1X_REG_CONFIG_DATA,
.config_len = GOODIX_CONFIG_MAX_LENGTH,
.check_config = goodix_check_cfg_16,
};
static const struct goodix_chip_data gt911_chip_data = {
.config_addr = GOODIX_GT9X_REG_CONFIG_DATA,
.config_len = GOODIX_CONFIG_911_LENGTH,
.check_config = goodix_check_cfg_8,
};
static const struct goodix_chip_data gt967_chip_data = {
.config_addr = GOODIX_GT9X_REG_CONFIG_DATA,
.config_len = GOODIX_CONFIG_967_LENGTH,
.check_config = goodix_check_cfg_8,
};
static const struct goodix_chip_data gt9x_chip_data = {
.config_addr = GOODIX_GT9X_REG_CONFIG_DATA,
.config_len = GOODIX_CONFIG_MAX_LENGTH,
.check_config = goodix_check_cfg_8,
};
static const unsigned long goodix_irq_flags[] = {
IRQ_TYPE_EDGE_RISING,
IRQ_TYPE_EDGE_FALLING,
@@ -177,22 +215,25 @@ static int goodix_i2c_write_u8(struct i2c_client *client, u16 reg, u8 value)
return goodix_i2c_write(client, reg, &value, sizeof(value));
}
static int goodix_get_cfg_len(u16 id)
static const struct goodix_chip_data *goodix_get_chip_data(u16 id)
{
switch (id) {
case 1151:
return &gt1x_chip_data;
case 911:
case 9271:
case 9110:
case 927:
case 928:
return GOODIX_CONFIG_911_LENGTH;
return &gt911_chip_data;
case 912:
case 967:
return GOODIX_CONFIG_967_LENGTH;
return &gt967_chip_data;
default:
return GOODIX_CONFIG_MAX_LENGTH;
return &gt9x_chip_data;
}
}
@@ -332,25 +373,12 @@ static int goodix_request_irq(struct goodix_ts_data *ts)
ts->irq_flags, ts->client->name, ts);
}
/**
* goodix_check_cfg - Checks if config fw is valid
*
* @ts: goodix_ts_data pointer
* @cfg: firmware config data
*/
static int goodix_check_cfg(struct goodix_ts_data *ts,
const struct firmware *cfg)
static int goodix_check_cfg_8(struct goodix_ts_data *ts,
const struct firmware *cfg)
{
int i, raw_cfg_len;
int i, raw_cfg_len = cfg->size - 2;
u8 check_sum = 0;
if (cfg->size > GOODIX_CONFIG_MAX_LENGTH) {
dev_err(&ts->client->dev,
"The length of the config fw is not correct");
return -EINVAL;
}
raw_cfg_len = cfg->size - 2;
for (i = 0; i < raw_cfg_len; i++)
check_sum += cfg->data[i];
check_sum = (~check_sum) + 1;
@@ -369,6 +397,48 @@ static int goodix_check_cfg(struct goodix_ts_data *ts,
return 0;
}
static int goodix_check_cfg_16(struct goodix_ts_data *ts,
const struct firmware *cfg)
{
int i, raw_cfg_len = cfg->size - 3;
u16 check_sum = 0;
for (i = 0; i < raw_cfg_len; i += 2)
check_sum += get_unaligned_be16(&cfg->data[i]);
check_sum = (~check_sum) + 1;
if (check_sum != get_unaligned_be16(&cfg->data[raw_cfg_len])) {
dev_err(&ts->client->dev,
"The checksum of the config fw is not correct");
return -EINVAL;
}
if (cfg->data[raw_cfg_len + 2] != 1) {
dev_err(&ts->client->dev,
"Config fw must have Config_Fresh register set");
return -EINVAL;
}
return 0;
}
/**
* goodix_check_cfg - Checks if config fw is valid
*
* @ts: goodix_ts_data pointer
* @cfg: firmware config data
*/
static int goodix_check_cfg(struct goodix_ts_data *ts,
const struct firmware *cfg)
{
if (cfg->size > GOODIX_CONFIG_MAX_LENGTH) {
dev_err(&ts->client->dev,
"The length of the config fw is not correct");
return -EINVAL;
}
return ts->chip->check_config(ts, cfg);
}
/**
* goodix_send_cfg - Write fw config to device
*
@@ -384,7 +454,7 @@ static int goodix_send_cfg(struct goodix_ts_data *ts,
if (error)
return error;
error = goodix_i2c_write(ts->client, GOODIX_REG_CONFIG_DATA, cfg->data,
error = goodix_i2c_write(ts->client, ts->chip->config_addr, cfg->data,
cfg->size);
if (error) {
dev_err(&ts->client->dev, "Failed to write config data: %d",
@@ -511,8 +581,8 @@ static void goodix_read_config(struct goodix_ts_data *ts)
u8 config[GOODIX_CONFIG_MAX_LENGTH];
int error;
error = goodix_i2c_read(ts->client, GOODIX_REG_CONFIG_DATA,
config, ts->cfg_len);
error = goodix_i2c_read(ts->client, ts->chip->config_addr,
config, ts->chip->config_len);
if (error) {
dev_warn(&ts->client->dev,
"Error reading config (%d), using defaults\n",
@@ -592,7 +662,7 @@ static int goodix_i2c_test(struct i2c_client *client)
u8 test;
while (retry++ < 2) {
error = goodix_i2c_read(client, GOODIX_REG_CONFIG_DATA,
error = goodix_i2c_read(client, GOODIX_REG_ID,
&test, 1);
if (!error)
return 0;
@@ -762,7 +832,7 @@ static int goodix_ts_probe(struct i2c_client *client,
return error;
}
ts->cfg_len = goodix_get_cfg_len(ts->id);
ts->chip = goodix_get_chip_data(ts->id);
if (ts->gpiod_int && ts->gpiod_rst) {
/* update device config */
@@ -891,6 +961,7 @@ MODULE_DEVICE_TABLE(acpi, goodix_acpi_match);
#ifdef CONFIG_OF
static const struct of_device_id goodix_of_match[] = {
{ .compatible = "goodix,gt1151" },
{ .compatible = "goodix,gt911" },
{ .compatible = "goodix,gt9110" },
{ .compatible = "goodix,gt912" },

File diff suppressed because it is too large Load Diff

View File

@@ -219,7 +219,7 @@ static struct isa_driver htcpen_isa_driver = {
}
};
static struct dmi_system_id htcshift_dmi_table[] __initdata = {
static const struct dmi_system_id htcshift_dmi_table[] __initconst = {
{
.ident = "Shift",
.matches = {

View File

@@ -1433,13 +1433,6 @@ static const struct attribute_group mip4_attr_group = {
.attrs = mip4_attrs,
};
static void mip4_sysfs_remove(void *_data)
{
struct mip4_ts *ts = _data;
sysfs_remove_group(&ts->client->dev.kobj, &mip4_attr_group);
}
static int mip4_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
struct mip4_ts *ts;
@@ -1535,21 +1528,13 @@ static int mip4_probe(struct i2c_client *client, const struct i2c_device_id *id)
return error;
}
error = sysfs_create_group(&client->dev.kobj, &mip4_attr_group);
error = devm_device_add_group(&client->dev, &mip4_attr_group);
if (error) {
dev_err(&client->dev,
"Failed to create sysfs attribute group: %d\n", error);
return error;
}
error = devm_add_action(&client->dev, mip4_sysfs_remove, ts);
if (error) {
mip4_sysfs_remove(ts);
dev_err(&client->dev,
"Failed to install sysfs remoce action: %d\n", error);
return error;
}
return 0;
}

View File

@@ -584,7 +584,7 @@ static void mxs_lradc_ts_hw_init(struct mxs_lradc_ts *ts)
static int mxs_lradc_ts_register(struct mxs_lradc_ts *ts)
{
struct input_dev *input = ts->ts_input;
struct input_dev *input;
struct device *dev = ts->dev;
input = devm_input_allocate_device(dev);

View File

@@ -943,13 +943,6 @@ static const struct attribute_group raydium_i2c_attribute_group = {
.attrs = raydium_i2c_attributes,
};
static void raydium_i2c_remove_sysfs_group(void *_data)
{
struct raydium_data *ts = _data;
sysfs_remove_group(&ts->client->dev.kobj, &raydium_i2c_attribute_group);
}
static int raydium_i2c_power_on(struct raydium_data *ts)
{
int error;
@@ -1120,7 +1113,7 @@ static int raydium_i2c_probe(struct i2c_client *client,
return error;
}
error = sysfs_create_group(&client->dev.kobj,
error = devm_device_add_group(&client->dev,
&raydium_i2c_attribute_group);
if (error) {
dev_err(&client->dev, "failed to create sysfs attributes: %d\n",
@@ -1128,15 +1121,6 @@ static int raydium_i2c_probe(struct i2c_client *client,
return error;
}
error = devm_add_action(&client->dev,
raydium_i2c_remove_sysfs_group, ts);
if (error) {
raydium_i2c_remove_sysfs_group(ts);
dev_err(&client->dev,
"Failed to add sysfs cleanup action: %d\n", error);
return error;
}
return 0;
}

View File

@@ -1103,13 +1103,6 @@ static void rohm_ts_close(struct input_dev *input_dev)
ts->initialized = false;
}
static void rohm_ts_remove_sysfs_group(void *_dev)
{
struct device *dev = _dev;
sysfs_remove_group(&dev->kobj, &rohm_ts_attr_group);
}
static int rohm_bu21023_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
@@ -1180,20 +1173,12 @@ static int rohm_bu21023_i2c_probe(struct i2c_client *client,
return error;
}
error = sysfs_create_group(&dev->kobj, &rohm_ts_attr_group);
error = devm_device_add_group(dev, &rohm_ts_attr_group);
if (error) {
dev_err(dev, "failed to create sysfs group: %d\n", error);
return error;
}
error = devm_add_action(dev, rohm_ts_remove_sysfs_group, dev);
if (error) {
rohm_ts_remove_sysfs_group(dev);
dev_err(dev, "Failed to add sysfs cleanup action: %d\n",
error);
return error;
}
return error;
}

View File

@@ -0,0 +1,559 @@
/*
* Copyright (c) 2017 Samsung Electronics Co., Ltd.
* Author: Andi Shyti <andi.shyti@samsung.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Samsung S6SY761 Touchscreen device driver
*/
#include <asm/unaligned.h>
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/input/mt.h>
#include <linux/input/touchscreen.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/module.h>
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
/* commands */
#define S6SY761_SENSE_ON 0x10
#define S6SY761_SENSE_OFF 0x11
#define S6SY761_TOUCH_FUNCTION 0x30 /* R/W for get/set */
#define S6SY761_FIRMWARE_INTEGRITY 0x21
#define S6SY761_PANEL_INFO 0x23
#define S6SY761_DEVICE_ID 0x52
#define S6SY761_BOOT_STATUS 0x55
#define S6SY761_READ_ONE_EVENT 0x60
#define S6SY761_READ_ALL_EVENT 0x61
#define S6SY761_CLEAR_EVENT_STACK 0x62
#define S6SY761_APPLICATION_MODE 0xe4
/* events */
#define S6SY761_EVENT_INFO 0x02
#define S6SY761_EVENT_VENDOR_INFO 0x07
/* info */
#define S6SY761_INFO_BOOT_COMPLETE 0x00
/* firmware status */
#define S6SY761_FW_OK 0x80
/*
* the functionalities are put as a reference
* as in the device I am using none of them
* works therefore not used in this driver yet.
*/
/* touchscreen functionalities */
#define S6SY761_MASK_TOUCH BIT(0)
#define S6SY761_MASK_HOVER BIT(1)
#define S6SY761_MASK_COVER BIT(2)
#define S6SY761_MASK_GLOVE BIT(3)
#define S6SY761_MASK_STYLUS BIT(4)
#define S6SY761_MASK_PALM BIT(5)
#define S6SY761_MASK_WET BIT(6)
#define S6SY761_MASK_PROXIMITY BIT(7)
/* boot status (BS) */
#define S6SY761_BS_BOOT_LOADER 0x10
#define S6SY761_BS_APPLICATION 0x20
/* event id */
#define S6SY761_EVENT_ID_COORDINATE 0x00
#define S6SY761_EVENT_ID_STATUS 0x01
/* event register masks */
#define S6SY761_MASK_TOUCH_STATE 0xc0 /* byte 0 */
#define S6SY761_MASK_TID 0x3c
#define S6SY761_MASK_EID 0x03
#define S6SY761_MASK_X 0xf0 /* byte 3 */
#define S6SY761_MASK_Y 0x0f
#define S6SY761_MASK_Z 0x3f /* byte 6 */
#define S6SY761_MASK_LEFT_EVENTS 0x3f /* byte 7 */
#define S6SY761_MASK_TOUCH_TYPE 0xc0 /* MSB in byte 6, LSB in byte 7 */
/* event touch state values */
#define S6SY761_TS_NONE 0x00
#define S6SY761_TS_PRESS 0x01
#define S6SY761_TS_MOVE 0x02
#define S6SY761_TS_RELEASE 0x03
/* application modes */
#define S6SY761_APP_NORMAL 0x0
#define S6SY761_APP_LOW_POWER 0x1
#define S6SY761_APP_TEST 0x2
#define S6SY761_APP_FLASH 0x3
#define S6SY761_APP_SLEEP 0x4
#define S6SY761_EVENT_SIZE 8
#define S6SY761_EVENT_COUNT 32
#define S6SY761_DEVID_SIZE 3
#define S6SY761_PANEL_ID_SIZE 11
#define S6SY761_TS_STATUS_SIZE 5
#define S6SY761_MAX_FINGERS 10
#define S6SY761_DEV_NAME "s6sy761"
enum s6sy761_regulators {
S6SY761_REGULATOR_VDD,
S6SY761_REGULATOR_AVDD,
};
struct s6sy761_data {
struct i2c_client *client;
struct regulator_bulk_data regulators[2];
struct input_dev *input;
struct touchscreen_properties prop;
u8 data[S6SY761_EVENT_SIZE * S6SY761_EVENT_COUNT];
u16 devid;
u8 tx_channel;
};
/*
* We can't simply use i2c_smbus_read_i2c_block_data because we
* need to read more than 255 bytes
*/
static int s6sy761_read_events(struct s6sy761_data *sdata, u16 n_events)
{
u8 cmd = S6SY761_READ_ALL_EVENT;
struct i2c_msg msgs[2] = {
{
.addr = sdata->client->addr,
.len = 1,
.buf = &cmd,
},
{
.addr = sdata->client->addr,
.flags = I2C_M_RD,
.len = (n_events * S6SY761_EVENT_SIZE),
.buf = sdata->data + S6SY761_EVENT_SIZE,
},
};
int ret;
ret = i2c_transfer(sdata->client->adapter, msgs, ARRAY_SIZE(msgs));
if (ret < 0)
return ret;
return ret == ARRAY_SIZE(msgs) ? 0 : -EIO;
}
static void s6sy761_report_coordinates(struct s6sy761_data *sdata,
u8 *event, u8 tid)
{
u8 major = event[4];
u8 minor = event[5];
u8 z = event[6] & S6SY761_MASK_Z;
u16 x = (event[1] << 3) | ((event[3] & S6SY761_MASK_X) >> 4);
u16 y = (event[2] << 3) | (event[3] & S6SY761_MASK_Y);
input_mt_slot(sdata->input, tid);
input_mt_report_slot_state(sdata->input, MT_TOOL_FINGER, true);
input_report_abs(sdata->input, ABS_MT_POSITION_X, x);
input_report_abs(sdata->input, ABS_MT_POSITION_Y, y);
input_report_abs(sdata->input, ABS_MT_TOUCH_MAJOR, major);
input_report_abs(sdata->input, ABS_MT_TOUCH_MINOR, minor);
input_report_abs(sdata->input, ABS_MT_PRESSURE, z);
input_sync(sdata->input);
}
static void s6sy761_report_release(struct s6sy761_data *sdata,
u8 *event, u8 tid)
{
input_mt_slot(sdata->input, tid);
input_mt_report_slot_state(sdata->input, MT_TOOL_FINGER, false);
input_sync(sdata->input);
}
static void s6sy761_handle_coordinates(struct s6sy761_data *sdata, u8 *event)
{
u8 tid;
u8 touch_state;
if (unlikely(!(event[0] & S6SY761_MASK_TID)))
return;
tid = ((event[0] & S6SY761_MASK_TID) >> 2) - 1;
touch_state = (event[0] & S6SY761_MASK_TOUCH_STATE) >> 6;
switch (touch_state) {
case S6SY761_TS_NONE:
break;
case S6SY761_TS_RELEASE:
s6sy761_report_release(sdata, event, tid);
break;
case S6SY761_TS_PRESS:
case S6SY761_TS_MOVE:
s6sy761_report_coordinates(sdata, event, tid);
break;
}
}
static void s6sy761_handle_events(struct s6sy761_data *sdata, u8 n_events)
{
int i;
for (i = 0; i < n_events; i++) {
u8 *event = &sdata->data[i * S6SY761_EVENT_SIZE];
u8 event_id = event[0] & S6SY761_MASK_EID;
if (!event[0])
return;
switch (event_id) {
case S6SY761_EVENT_ID_COORDINATE:
s6sy761_handle_coordinates(sdata, event);
break;
case S6SY761_EVENT_ID_STATUS:
break;
default:
break;
}
}
}
static irqreturn_t s6sy761_irq_handler(int irq, void *dev)
{
struct s6sy761_data *sdata = dev;
int ret;
u8 n_events;
ret = i2c_smbus_read_i2c_block_data(sdata->client,
S6SY761_READ_ONE_EVENT,
S6SY761_EVENT_SIZE,
sdata->data);
if (ret < 0) {
dev_err(&sdata->client->dev, "failed to read events\n");
return IRQ_HANDLED;
}
if (!sdata->data[0])
return IRQ_HANDLED;
n_events = sdata->data[7] & S6SY761_MASK_LEFT_EVENTS;
if (unlikely(n_events > S6SY761_EVENT_COUNT - 1))
return IRQ_HANDLED;
if (n_events) {
ret = s6sy761_read_events(sdata, n_events);
if (ret < 0) {
dev_err(&sdata->client->dev, "failed to read events\n");
return IRQ_HANDLED;
}
}
s6sy761_handle_events(sdata, n_events + 1);
return IRQ_HANDLED;
}
static int s6sy761_input_open(struct input_dev *dev)
{
struct s6sy761_data *sdata = input_get_drvdata(dev);
return i2c_smbus_write_byte(sdata->client, S6SY761_SENSE_ON);
}
static void s6sy761_input_close(struct input_dev *dev)
{
struct s6sy761_data *sdata = input_get_drvdata(dev);
int ret;
ret = i2c_smbus_write_byte(sdata->client, S6SY761_SENSE_OFF);
if (ret)
dev_err(&sdata->client->dev, "failed to turn off sensing\n");
}
static ssize_t s6sy761_sysfs_devid(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct s6sy761_data *sdata = dev_get_drvdata(dev);
return sprintf(buf, "%#x\n", sdata->devid);
}
static DEVICE_ATTR(devid, 0444, s6sy761_sysfs_devid, NULL);
static struct attribute *s6sy761_sysfs_attrs[] = {
&dev_attr_devid.attr,
NULL
};
static struct attribute_group s6sy761_attribute_group = {
.attrs = s6sy761_sysfs_attrs
};
static int s6sy761_power_on(struct s6sy761_data *sdata)
{
u8 buffer[S6SY761_EVENT_SIZE];
u8 event;
int ret;
ret = regulator_bulk_enable(ARRAY_SIZE(sdata->regulators),
sdata->regulators);
if (ret)
return ret;
msleep(140);
/* double check whether the touch is functional */
ret = i2c_smbus_read_i2c_block_data(sdata->client,
S6SY761_READ_ONE_EVENT,
S6SY761_EVENT_SIZE,
buffer);
if (ret < 0)
return ret;
event = (buffer[0] >> 2) & 0xf;
if ((event != S6SY761_EVENT_INFO &&
event != S6SY761_EVENT_VENDOR_INFO) ||
buffer[1] != S6SY761_INFO_BOOT_COMPLETE) {
return -ENODEV;
}
ret = i2c_smbus_read_byte_data(sdata->client, S6SY761_BOOT_STATUS);
if (ret < 0)
return ret;
/* for some reasons the device might be stuck in the bootloader */
if (ret != S6SY761_BS_APPLICATION)
return -ENODEV;
/* enable touch functionality */
ret = i2c_smbus_write_word_data(sdata->client,
S6SY761_TOUCH_FUNCTION,
S6SY761_MASK_TOUCH);
if (ret)
return ret;
return 0;
}
static int s6sy761_hw_init(struct s6sy761_data *sdata,
unsigned int *max_x, unsigned int *max_y)
{
u8 buffer[S6SY761_PANEL_ID_SIZE]; /* larger read size */
int ret;
ret = s6sy761_power_on(sdata);
if (ret)
return ret;
ret = i2c_smbus_read_i2c_block_data(sdata->client,
S6SY761_DEVICE_ID,
S6SY761_DEVID_SIZE,
buffer);
if (ret < 0)
return ret;
sdata->devid = get_unaligned_be16(buffer + 1);
ret = i2c_smbus_read_i2c_block_data(sdata->client,
S6SY761_PANEL_INFO,
S6SY761_PANEL_ID_SIZE,
buffer);
if (ret < 0)
return ret;
*max_x = get_unaligned_be16(buffer);
*max_y = get_unaligned_be16(buffer + 2);
/* if no tx channels defined, at least keep one */
sdata->tx_channel = max_t(u8, buffer[8], 1);
ret = i2c_smbus_read_byte_data(sdata->client,
S6SY761_FIRMWARE_INTEGRITY);
if (ret < 0)
return ret;
else if (ret != S6SY761_FW_OK)
return -ENODEV;
return 0;
}
static void s6sy761_power_off(void *data)
{
struct s6sy761_data *sdata = data;
disable_irq(sdata->client->irq);
regulator_bulk_disable(ARRAY_SIZE(sdata->regulators),
sdata->regulators);
}
static int s6sy761_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct s6sy761_data *sdata;
unsigned int max_x, max_y;
int err;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C |
I2C_FUNC_SMBUS_BYTE_DATA |
I2C_FUNC_SMBUS_I2C_BLOCK))
return -ENODEV;
sdata = devm_kzalloc(&client->dev, sizeof(*sdata), GFP_KERNEL);
if (!sdata)
return -ENOMEM;
i2c_set_clientdata(client, sdata);
sdata->client = client;
sdata->regulators[S6SY761_REGULATOR_VDD].supply = "vdd";
sdata->regulators[S6SY761_REGULATOR_AVDD].supply = "avdd";
err = devm_regulator_bulk_get(&client->dev,
ARRAY_SIZE(sdata->regulators),
sdata->regulators);
if (err)
return err;
err = devm_add_action_or_reset(&client->dev, s6sy761_power_off, sdata);
if (err)
return err;
err = s6sy761_hw_init(sdata, &max_x, &max_y);
if (err)
return err;
sdata->input = devm_input_allocate_device(&client->dev);
if (!sdata->input)
return -ENOMEM;
sdata->input->name = S6SY761_DEV_NAME;
sdata->input->id.bustype = BUS_I2C;
sdata->input->open = s6sy761_input_open;
sdata->input->close = s6sy761_input_close;
input_set_abs_params(sdata->input, ABS_MT_POSITION_X, 0, max_x, 0, 0);
input_set_abs_params(sdata->input, ABS_MT_POSITION_Y, 0, max_y, 0, 0);
input_set_abs_params(sdata->input, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0);
input_set_abs_params(sdata->input, ABS_MT_TOUCH_MINOR, 0, 255, 0, 0);
input_set_abs_params(sdata->input, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0);
input_set_abs_params(sdata->input, ABS_MT_TOUCH_MINOR, 0, 255, 0, 0);
input_set_abs_params(sdata->input, ABS_MT_PRESSURE, 0, 255, 0, 0);
touchscreen_parse_properties(sdata->input, true, &sdata->prop);
if (!input_abs_get_max(sdata->input, ABS_X) ||
!input_abs_get_max(sdata->input, ABS_Y)) {
dev_warn(&client->dev, "the axis have not been set\n");
}
err = input_mt_init_slots(sdata->input, sdata->tx_channel,
INPUT_MT_DIRECT);
if (err)
return err;
input_set_drvdata(sdata->input, sdata);
err = input_register_device(sdata->input);
if (err)
return err;
err = devm_request_threaded_irq(&client->dev, client->irq, NULL,
s6sy761_irq_handler,
IRQF_TRIGGER_LOW | IRQF_ONESHOT,
"s6sy761_irq", sdata);
if (err)
return err;
err = devm_device_add_group(&client->dev, &s6sy761_attribute_group);
if (err)
return err;
pm_runtime_enable(&client->dev);
return 0;
}
static int s6sy761_remove(struct i2c_client *client)
{
pm_runtime_disable(&client->dev);
return 0;
}
static int __maybe_unused s6sy761_runtime_suspend(struct device *dev)
{
struct s6sy761_data *sdata = dev_get_drvdata(dev);
return i2c_smbus_write_byte_data(sdata->client,
S6SY761_APPLICATION_MODE, S6SY761_APP_SLEEP);
}
static int __maybe_unused s6sy761_runtime_resume(struct device *dev)
{
struct s6sy761_data *sdata = dev_get_drvdata(dev);
return i2c_smbus_write_byte_data(sdata->client,
S6SY761_APPLICATION_MODE, S6SY761_APP_NORMAL);
}
static int __maybe_unused s6sy761_suspend(struct device *dev)
{
struct s6sy761_data *sdata = dev_get_drvdata(dev);
s6sy761_power_off(sdata);
return 0;
}
static int __maybe_unused s6sy761_resume(struct device *dev)
{
struct s6sy761_data *sdata = dev_get_drvdata(dev);
enable_irq(sdata->client->irq);
return s6sy761_power_on(sdata);
}
static const struct dev_pm_ops s6sy761_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(s6sy761_suspend, s6sy761_resume)
SET_RUNTIME_PM_OPS(s6sy761_runtime_suspend,
s6sy761_runtime_resume, NULL)
};
#ifdef CONFIG_OF
static const struct of_device_id s6sy761_of_match[] = {
{ .compatible = "samsung,s6sy761", },
{ },
};
MODULE_DEVICE_TABLE(of, s6sy761_of_match);
#endif
static const struct i2c_device_id s6sy761_id[] = {
{ "s6sy761", 0 },
{ },
};
MODULE_DEVICE_TABLE(i2c, s6sy761_id);
static struct i2c_driver s6sy761_driver = {
.driver = {
.name = S6SY761_DEV_NAME,
.of_match_table = of_match_ptr(s6sy761_of_match),
.pm = &s6sy761_pm_ops,
},
.probe = s6sy761_probe,
.remove = s6sy761_remove,
.id_table = s6sy761_id,
};
module_i2c_driver(s6sy761_driver);
MODULE_AUTHOR("Andi Shyti <andi.shyti@samsung.com>");
MODULE_DESCRIPTION("Samsung S6SY761 Touch Screen");
MODULE_LICENSE("GPL v2");

View File

@@ -29,7 +29,6 @@
#include <linux/pm_qos.h>
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/platform_data/st1232_pdata.h>
#define ST1232_TS_NAME "st1232-ts"
@@ -152,10 +151,9 @@ static void st1232_ts_power(struct st1232_ts_data *ts, bool poweron)
}
static int st1232_ts_probe(struct i2c_client *client,
const struct i2c_device_id *id)
const struct i2c_device_id *id)
{
struct st1232_ts_data *ts;
struct st1232_pdata *pdata = dev_get_platdata(&client->dev);
struct input_dev *input_dev;
int error;
@@ -180,13 +178,7 @@ static int st1232_ts_probe(struct i2c_client *client,
ts->client = client;
ts->input_dev = input_dev;
if (pdata)
ts->reset_gpio = pdata->reset_gpio;
else if (client->dev.of_node)
ts->reset_gpio = of_get_gpio(client->dev.of_node, 0);
else
ts->reset_gpio = -ENODEV;
ts->reset_gpio = of_get_gpio(client->dev.of_node, 0);
if (gpio_is_valid(ts->reset_gpio)) {
error = devm_gpio_request(&client->dev, ts->reset_gpio, NULL);
if (error) {
@@ -281,13 +273,11 @@ static const struct i2c_device_id st1232_ts_id[] = {
};
MODULE_DEVICE_TABLE(i2c, st1232_ts_id);
#ifdef CONFIG_OF
static const struct of_device_id st1232_ts_dt_ids[] = {
{ .compatible = "sitronix,st1232", },
{ }
};
MODULE_DEVICE_TABLE(of, st1232_ts_dt_ids);
#endif
static struct i2c_driver st1232_ts_driver = {
.probe = st1232_ts_probe,
@@ -295,7 +285,7 @@ static struct i2c_driver st1232_ts_driver = {
.id_table = st1232_ts_id,
.driver = {
.name = ST1232_TS_NAME,
.of_match_table = of_match_ptr(st1232_ts_dt_ids),
.of_match_table = st1232_ts_dt_ids,
.pm = &st1232_ts_pm_ops,
},
};

View File

@@ -725,8 +725,7 @@ static int stmfts_probe(struct i2c_client *client,
}
}
err = sysfs_create_group(&sdata->client->dev.kobj,
&stmfts_attribute_group);
err = devm_device_add_group(&client->dev, &stmfts_attribute_group);
if (err)
return err;
@@ -738,7 +737,6 @@ static int stmfts_probe(struct i2c_client *client,
static int stmfts_remove(struct i2c_client *client)
{
pm_runtime_disable(&client->dev);
sysfs_remove_group(&client->dev.kobj, &stmfts_attribute_group);
return 0;
}

View File

@@ -202,9 +202,9 @@ out:
return IRQ_HANDLED;
}
static void tsc200x_penup_timer(unsigned long data)
static void tsc200x_penup_timer(struct timer_list *t)
{
struct tsc200x *ts = (struct tsc200x *)data;
struct tsc200x *ts = from_timer(ts, t, penup_timer);
unsigned long flags;
spin_lock_irqsave(&ts->lock, flags);
@@ -506,7 +506,7 @@ int tsc200x_probe(struct device *dev, int irq, const struct input_id *tsc_id,
mutex_init(&ts->mutex);
spin_lock_init(&ts->lock);
setup_timer(&ts->penup_timer, tsc200x_penup_timer, (unsigned long)ts);
timer_setup(&ts->penup_timer, tsc200x_penup_timer, 0);
INIT_DELAYED_WORK(&ts->esd_work, tsc200x_esd_work);

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _TSC200X_CORE_H
#define _TSC200X_CORE_H

View File

@@ -146,9 +146,9 @@ static irqreturn_t w90p910_ts_interrupt(int irq, void *dev_id)
return IRQ_HANDLED;
}
static void w90p910_check_pen_up(unsigned long data)
static void w90p910_check_pen_up(struct timer_list *t)
{
struct w90p910_ts *w90p910_ts = (struct w90p910_ts *) data;
struct w90p910_ts *w90p910_ts = from_timer(w90p910_ts, t, timer);
unsigned long flags;
spin_lock_irqsave(&w90p910_ts->lock, flags);
@@ -232,8 +232,7 @@ static int w90x900ts_probe(struct platform_device *pdev)
w90p910_ts->input = input_dev;
w90p910_ts->state = TS_IDLE;
spin_lock_init(&w90p910_ts->lock);
setup_timer(&w90p910_ts->timer, w90p910_check_pen_up,
(unsigned long)w90p910_ts);
timer_setup(&w90p910_ts->timer, w90p910_check_pen_up, 0);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {

View File

@@ -1106,7 +1106,7 @@ static int wdt87xx_ts_probe(struct i2c_client *client,
return error;
}
error = sysfs_create_group(&client->dev.kobj, &wdt87xx_attr_group);
error = devm_device_add_group(&client->dev, &wdt87xx_attr_group);
if (error) {
dev_err(&client->dev, "create sysfs failed: %d\n", error);
return error;
@@ -1115,13 +1115,6 @@ static int wdt87xx_ts_probe(struct i2c_client *client,
return 0;
}
static int wdt87xx_ts_remove(struct i2c_client *client)
{
sysfs_remove_group(&client->dev.kobj, &wdt87xx_attr_group);
return 0;
}
static int __maybe_unused wdt87xx_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
@@ -1179,7 +1172,6 @@ MODULE_DEVICE_TABLE(acpi, wdt87xx_acpi_id);
static struct i2c_driver wdt87xx_driver = {
.probe = wdt87xx_ts_probe,
.remove = wdt87xx_ts_remove,
.id_table = wdt87xx_dev_id,
.driver = {
.name = WDT87XX_NAME,