On Fri, Mar 06, 2015 at 10:21:55AM -0800, Dmitry Torokhov wrote: > On Fri, Mar 06, 2015 at 07:21:38PM +0100, Sébastien Szymanski wrote: > > Signed-off-by: Sébastien Szymanski <sebastien.szymanski@xxxxxxxxxxxx> > > --- > > drivers/input/touchscreen/Kconfig | 11 ++ > > drivers/input/touchscreen/Makefile | 1 + > > drivers/input/touchscreen/sx8654.c | 285 +++++++++++++++++++++++++++++++++++++ > > 3 files changed, 297 insertions(+) > > create mode 100644 drivers/input/touchscreen/sx8654.c > > > > diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig > > index 5891752..6f713fd0 100644 > > --- a/drivers/input/touchscreen/Kconfig > > +++ b/drivers/input/touchscreen/Kconfig > > @@ -961,6 +961,17 @@ config TOUCHSCREEN_SUR40 > > To compile this driver as a module, choose M here: the > > module will be called sur40. > > > > +config TOUCHSCREEN_SX8654 > > + tristate "Semtech SX8654 touchscreen" > > + depends on I2C && OF > > Does it have to depend on OF? I do not see anything OF-specific there... > > No need to resumbit. Applied with some cosmetic edits and DT bindings folded into this patch. Thank you. > > > + help > > + Say Y here if you have a Semtech SX8654 touchscreen controller. > > + > > + If unsure, say N > > + > > + To compile this driver as a module, choose M here: the > > + module will be called sx8654. > > + > > config TOUCHSCREEN_TPS6507X > > tristate "TPS6507x based touchscreens" > > depends on I2C > > diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile > > index 0242fea..a06a752 100644 > > --- a/drivers/input/touchscreen/Makefile > > +++ b/drivers/input/touchscreen/Makefile > > @@ -79,5 +79,6 @@ obj-$(CONFIG_TOUCHSCREEN_WM97XX_ATMEL) += atmel-wm97xx.o > > obj-$(CONFIG_TOUCHSCREEN_WM97XX_MAINSTONE) += mainstone-wm97xx.o > > obj-$(CONFIG_TOUCHSCREEN_WM97XX_ZYLONITE) += zylonite-wm97xx.o > > obj-$(CONFIG_TOUCHSCREEN_W90X900) += w90p910_ts.o > > +obj-$(CONFIG_TOUCHSCREEN_SX8654) += sx8654.o > > obj-$(CONFIG_TOUCHSCREEN_TPS6507X) += tps6507x-ts.o > > obj-$(CONFIG_TOUCHSCREEN_ZFORCE) += zforce_ts.o > > diff --git a/drivers/input/touchscreen/sx8654.c b/drivers/input/touchscreen/sx8654.c > > new file mode 100644 > > index 0000000..58cc478 > > --- /dev/null > > +++ b/drivers/input/touchscreen/sx8654.c > > @@ -0,0 +1,285 @@ > > +/* > > + * drivers/input/touchscreen/sx8654.c > > + * > > + * Copyright (c) 2015 Armadeus Systems > > + * Sébastien Szymanski <sebastien.szymanski@xxxxxxxxxxxx> > > + * > > + * Using code from: > > + * - sx865x.c > > + * Copyright (c) 2013 U-MoBo Srl > > + * Pierluigi Passaro <p.passaro@xxxxxxxxxx> > > + * - sx8650.c > > + * Copyright (c) 2009 Wayne Roberts > > + * - tsc2007.c > > + * Copyright (c) 2008 Kwangwoo Lee > > + * - ads7846.c > > + * Copyright (c) 2005 David Brownell > > + * Copyright (c) 2006 Nokia Corporation > > + * - corgi_ts.c > > + * Copyright (C) 2004-2005 Richard Purdie > > + * - omap_ts.[hc], ads7846.h, ts_osk.c > > + * Copyright (C) 2002 MontaVista Software > > + * Copyright (C) 2004 Texas Instruments > > + * Copyright (C) 2005 Dirk Behme > > + * > > + * 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/input.h> > > +#include <linux/module.h> > > +#include <linux/of.h> > > +#include <linux/i2c.h> > > +#include <linux/interrupt.h> > > +#include <linux/irq.h> > > + > > +/* register addresses */ > > +#define I2C_REG_TOUCH0 0x00 > > +#define I2C_REG_TOUCH1 0x01 > > +#define I2C_REG_CHANMASK 0x04 > > +#define I2C_REG_IRQMASK 0x22 > > +#define I2C_REG_IRQSRC 0x23 > > +#define I2C_REG_SOFTRESET 0x3f > > + > > +/* commands */ > > +#define CMD_READ_REGISTER 0x40 > > +#define CMD_MANUAL 0xc0 > > +#define CMD_PENTRG 0xe0 > > + > > +/* value for I2C_REG_SOFTRESET */ > > +#define SOFTRESET_VALUE 0xde > > + > > +/* bits for I2C_REG_IRQSRC */ > > +#define IRQ_PENTOUCH_TOUCHCONVDONE 0x08 > > +#define IRQ_PENRELEASE 0x04 > > + > > +/* bits for RegTouch1 */ > > +#define CONDIRQ 0x20 > > +#define FILT_7SA 0x03 > > + > > +/* bits for I2C_REG_CHANMASK */ > > +#define CONV_X 0x80 > > +#define CONV_Y 0x40 > > + > > +/* coordinates rate: higher nibble of CTRL0 register */ > > +#define RATE_MANUAL 0x00 > > +#define RATE_5000CPS 0xf0 > > + > > +/* power delay: lower nibble of CTRL0 register */ > > +#define POWDLY_1_1MS 0x0b > > + > > +#define MAX_12BIT ((1 << 12) - 1) > > + > > +struct sx8654 { > > + struct input_dev *input; > > + struct i2c_client *client; > > +}; > > + > > +static irqreturn_t sx8654_irq(int irq, void *handle) > > +{ > > + struct sx8654 *sx8654 = handle; > > + u8 irqsrc; > > + u8 data[4]; > > + unsigned int x, y; > > + int retval; > > + > > + irqsrc = i2c_smbus_read_byte_data(sx8654->client, > > + (CMD_READ_REGISTER | I2C_REG_IRQSRC)); > > + dev_dbg(&sx8654->client->dev, "irqsrc = 0x%x", irqsrc); > > + > > + if (irqsrc < 0) > > + goto out; > > + > > + if (irqsrc & IRQ_PENRELEASE) { > > + dev_dbg(&sx8654->client->dev, "pen release interrupt"); > > + > > + input_report_key(sx8654->input, BTN_TOUCH, 0); > > + input_sync(sx8654->input); > > + } > > + > > + if (irqsrc & IRQ_PENTOUCH_TOUCHCONVDONE) { > > + dev_dbg(&sx8654->client->dev, "pen touch interrupt"); > > + > > + retval = i2c_master_recv(sx8654->client, data, sizeof(data)); > > + if (retval != sizeof(data)) > > + goto out; > > + > > + /* invalid data */ > > + if (unlikely(data[0] & 0x80 || data[2] & 0x80)) > > + goto out; > > + > > + x = ((data[0] & 0xf) << 8) | (data[1]); > > + y = ((data[2] & 0xf) << 8) | (data[3]); > > + > > + input_report_abs(sx8654->input, ABS_X, x); > > + input_report_abs(sx8654->input, ABS_Y, y); > > + input_report_key(sx8654->input, BTN_TOUCH, 1); > > + input_sync(sx8654->input); > > + > > + dev_dbg(&sx8654->client->dev, "point(%4d,%4d)\n", x, y); > > + } > > + > > +out: > > + return IRQ_HANDLED; > > +} > > + > > +static int sx8654_open(struct input_dev *dev) > > +{ > > + struct sx8654 *sx8654 = input_get_drvdata(dev); > > + struct i2c_client *client = sx8654->client; > > + int error; > > + > > + /* enable pen trigger mode */ > > + error = i2c_smbus_write_byte_data(client, I2C_REG_TOUCH0, > > + (RATE_5000CPS | POWDLY_1_1MS)); > > + if (error < 0) { > > + dev_err(&client->dev, "writing to I2C_REG_TOUCH0 failed"); > > + return -EIO; > > + } > > + > > + error = i2c_smbus_write_byte(client, CMD_PENTRG); > > + if (error < 0) { > > + dev_err(&client->dev, "writing command CMD_PENTRG failed"); > > + return -EIO; > > + } > > + > > + enable_irq(client->irq); > > + > > + return 0; > > +} > > + > > +static void sx8654_close(struct input_dev *dev) > > +{ > > + struct sx8654 *sx8654 = input_get_drvdata(dev); > > + struct i2c_client *client = sx8654->client; > > + int error; > > + > > + disable_irq(client->irq); > > + > > + /* enable manual mode mode */ > > + error = i2c_smbus_write_byte(client, CMD_MANUAL); > > + if (error < 0) { > > + dev_err(&client->dev, "writing command CMD_MANUAL failed"); > > + return; > > + } > > + > > + error = i2c_smbus_write_byte_data(client, I2C_REG_TOUCH0, 0); > > + if (error < 0) { > > + dev_err(&client->dev, "writing to I2C_REG_TOUCH0 failed"); > > + return; > > + } > > +} > > + > > +static int sx8654_probe(struct i2c_client *client, > > + const struct i2c_device_id *id) > > +{ > > + struct sx8654 *sx8654; > > + struct input_dev *input; > > + int error; > > + > > + if (!i2c_check_functionality(client->adapter, > > + I2C_FUNC_SMBUS_READ_WORD_DATA)) > > + return -ENXIO; > > + > > + sx8654 = devm_kzalloc(&client->dev, sizeof(*sx8654), GFP_KERNEL); > > + if (!sx8654) > > + return -ENOMEM; > > + > > + input = devm_input_allocate_device(&client->dev); > > + if (!sx8654) > > + return -ENOMEM; > > + > > + input->name = "SX8654 I2C Touchscreen"; > > + input->id.bustype = BUS_I2C; > > + input->dev.parent = &client->dev; > > + input->open = sx8654_open; > > + input->close = sx8654_close; > > + > > + __set_bit(INPUT_PROP_DIRECT, input->propbit); > > + input_set_capability(input, EV_KEY, BTN_TOUCH); > > + input_set_abs_params(input, ABS_X, 0, MAX_12BIT, 0, 0); > > + input_set_abs_params(input, ABS_Y, 0, MAX_12BIT, 0, 0); > > + > > + sx8654->client = client; > > + sx8654->input = input; > > + > > + input_set_drvdata(sx8654->input, sx8654); > > + > > + error = i2c_smbus_write_byte_data(client, I2C_REG_SOFTRESET, > > + SOFTRESET_VALUE); > > + if (error < 0) { > > + dev_err(&client->dev, "writing softreset value failed"); > > + return -EIO; > > + } > > + > > + error = i2c_smbus_write_byte_data(client, I2C_REG_CHANMASK, > > + (CONV_X | CONV_Y)); > > + if (error < 0) { > > + dev_err(&client->dev, "writing to I2C_REG_CHANMASK failed"); > > + return -EIO; > > + } > > + > > + error = i2c_smbus_write_byte_data(client, I2C_REG_IRQMASK, > > + (IRQ_PENTOUCH_TOUCHCONVDONE | > > + IRQ_PENRELEASE)); > > + if (error < 0) { > > + dev_err(&client->dev, "writing to I2C_REG_IRQMASK failed"); > > + return -EIO; > > + } > > + > > + error = i2c_smbus_write_byte_data(client, I2C_REG_TOUCH1, > > + (CONDIRQ | FILT_7SA)); > > + if (error < 0) { > > + dev_err(&client->dev, "writing to I2C_REG_TOUCH1 failed"); > > + return -EIO; > > + } > > + > > + error = devm_request_threaded_irq(&client->dev, client->irq, > > + NULL, sx8654_irq, > > + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, > > + client->name, sx8654); > > + if (error) { > > + dev_err(&client->dev, > > + "Failed to enable IRQ %d, error: %d\n", > > + client->irq, error); > > + return error; > > + } > > + > > + /* Disable the IRQ, we'll enable it in sx8654_open() */ > > + disable_irq(client->irq); > > + > > + error = input_register_device(sx8654->input); > > + if (error) > > + return error; > > + > > + i2c_set_clientdata(client, sx8654); > > + return 0; > > +} > > + > > +static const struct of_device_id sx8654_of_match[] = { > > + { .compatible = "semtech,sx8654", }, > > + { }, > > +}; > > +MODULE_DEVICE_TABLE(of, sx8654_of_match); > > + > > +static const struct i2c_device_id sx8654_id_table[] = { > > + { "semtech_sx8654", 0 }, > > + { }, > > +}; > > +MODULE_DEVICE_TABLE(i2c, sx8654_id_table); > > + > > +static struct i2c_driver sx8654_driver = { > > + .driver = { > > + .name = "sx8654", > > + .of_match_table = sx8654_of_match, > > + }, > > + > > + .id_table = sx8654_id_table, > > + .probe = sx8654_probe, > > +}; > > +module_i2c_driver(sx8654_driver); > > + > > +MODULE_AUTHOR("Sébastien Szymanski <sebastien.szymanski@xxxxxxxxxxxx>"); > > +MODULE_DESCRIPTION("Semtech SX8654 I2C Touchscreen Driver"); > > +MODULE_LICENSE("GPL"); > > -- > > 2.0.5 > > > > -- > Dmitry -- Dmitry -- To unsubscribe from this list: send the line "unsubscribe linux-input" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html