diff --git a/Documentation/devicetree/bindings/input/touchscreen/exc3000.txt b/Documentation/devicetree/bindings/input/touchscreen/exc3000.txt
new file mode 100644
index 00000000000000..1dcff4a43eaa8d
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/touchscreen/exc3000.txt
@@ -0,0 +1,27 @@
+* EETI EXC3000 Multiple Touch Controller
+
+Required properties:
+- compatible: must be "eeti,exc3000"
+- reg: i2c slave address
+- interrupt-parent: the phandle for the interrupt controller
+- interrupts: touch controller interrupt
+- touchscreen-size-x: See touchscreen.txt
+- touchscreen-size-y: See touchscreen.txt
+
+Optional properties:
+- touchscreen-inverted-x: See touchscreen.txt
+- touchscreen-inverted-y: See touchscreen.txt
+- touchscreen-swapped-x-y: See touchscreen.txt
+
+Example:
+
+ touchscreen@2a {
+ compatible = "eeti,exc3000";
+ reg = <0x2a>;
+ interrupt-parent = <&gpio1>;
+ interrupts = <9 IRQ_TYPE_LEVEL_LOW>;
+ touchscreen-size-x = <4096>;
+ touchscreen-size-y = <4096>;
+ touchscreen-inverted-x;
+ touchscreen-swapped-x-y;
+ };
diff --git a/arch/arm/boot/dts/overlays/Makefile b/arch/arm/boot/dts/overlays/Makefile
index 8090fee1d5a49c..bc997af7066578 100644
--- a/arch/arm/boot/dts/overlays/Makefile
+++ b/arch/arm/boot/dts/overlays/Makefile
@@ -26,6 +26,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \
dwc2.dtbo \
enc28j60.dtbo \
enc28j60-spi2.dtbo \
+ exc3000.dtbo \
fe-pi-audio.dtbo \
goodix.dtbo \
googlevoicehat-soundcard.dtbo \
diff --git a/arch/arm/boot/dts/overlays/README b/arch/arm/boot/dts/overlays/README
index 1cf89d6423ac01..afc7eea8ced47c 100644
--- a/arch/arm/boot/dts/overlays/README
+++ b/arch/arm/boot/dts/overlays/README
@@ -468,6 +468,18 @@ Params: int_pin GPIO used for INT (default 39)
speed SPI bus speed (default 12000000)
+Name: exc3000
+Info: Enables I2C connected EETI EXC3000 multiple touch controller using
+ GPIO 4 (pin 7 on GPIO header) for interrupt.
+Load: dtoverlay=exc3000,=
+Params: interrupt GPIO used for interrupt (default 4)
+ sizex Touchscreen size x (default 4096)
+ sizey Touchscreen size y (default 4096)
+ invx Touchscreen inverted x axis
+ invy Touchscreen inverted y axis
+ swapxy Touchscreen swapped x y axis
+
+
Name: fe-pi-audio
Info: Configures the Fe-Pi Audio Sound Card
Load: dtoverlay=fe-pi-audio
diff --git a/arch/arm/boot/dts/overlays/exc3000-overlay.dts b/arch/arm/boot/dts/overlays/exc3000-overlay.dts
new file mode 100644
index 00000000000000..c5694033d03f31
--- /dev/null
+++ b/arch/arm/boot/dts/overlays/exc3000-overlay.dts
@@ -0,0 +1,48 @@
+// Device tree overlay for I2C connected EETI EXC3000 multiple touch controller
+/dts-v1/;
+/plugin/;
+
+/ {
+ compatible = "brcm,bcm2708";
+
+ fragment@0 {
+ target = <&gpio>;
+ __overlay__ {
+ exc3000_pins: exc3000_pins {
+ brcm,pins = <4>; // interrupt
+ brcm,function = <0>; // in
+ brcm,pull = <2>; // pull-up
+ };
+ };
+ };
+
+ fragment@1 {
+ target = <&i2c1>;
+ __overlay__ {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "okay";
+
+ exc3000: exc3000@2a {
+ compatible = "eeti,exc3000";
+ reg = <0x2a>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&exc3000_pins>;
+ interrupt-parent = <&gpio>;
+ interrupts = <4 8>; // active low level-sensitive
+ touchscreen-size-x = <4096>;
+ touchscreen-size-y = <4096>;
+ };
+ };
+ };
+
+ __overrides__ {
+ interrupt = <&exc3000_pins>,"brcm,pins:0",
+ <&exc3000>,"interrupts:0";
+ sizex = <&exc3000>,"touchscreen-size-x:0";
+ sizey = <&exc3000>,"touchscreen-size-y:0";
+ invx = <&exc3000>,"touchscreen-inverted-x?";
+ invy = <&exc3000>,"touchscreen-inverted-y?";
+ swapxy = <&exc3000>,"touchscreen-swapped-x-y?";
+ };
+};
diff --git a/arch/arm/configs/bcm2709_defconfig b/arch/arm/configs/bcm2709_defconfig
index 8800a1081bb726..aab56f885f3e2c 100644
--- a/arch/arm/configs/bcm2709_defconfig
+++ b/arch/arm/configs/bcm2709_defconfig
@@ -573,6 +573,7 @@ CONFIG_JOYSTICK_RPISENSE=m
CONFIG_INPUT_TOUCHSCREEN=y
CONFIG_TOUCHSCREEN_ADS7846=m
CONFIG_TOUCHSCREEN_EGALAX=m
+CONFIG_TOUCHSCREEN_EXC3000=m
CONFIG_TOUCHSCREEN_GOODIX=m
CONFIG_TOUCHSCREEN_EDT_FT5X06=m
CONFIG_TOUCHSCREEN_RPI_FT5406=m
diff --git a/arch/arm/configs/bcmrpi_defconfig b/arch/arm/configs/bcmrpi_defconfig
index 28266427f843a3..ce5f5b66cb38c7 100644
--- a/arch/arm/configs/bcmrpi_defconfig
+++ b/arch/arm/configs/bcmrpi_defconfig
@@ -569,6 +569,7 @@ CONFIG_JOYSTICK_RPISENSE=m
CONFIG_INPUT_TOUCHSCREEN=y
CONFIG_TOUCHSCREEN_ADS7846=m
CONFIG_TOUCHSCREEN_EGALAX=m
+CONFIG_TOUCHSCREEN_EXC3000=m
CONFIG_TOUCHSCREEN_GOODIX=m
CONFIG_TOUCHSCREEN_EDT_FT5X06=m
CONFIG_TOUCHSCREEN_RPI_FT5406=m
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 0bf78ff1ae888a..9ea2d9287b38cf 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -314,6 +314,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
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index f720bc30ada9c2..48118379fee7cc 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -38,6 +38,7 @@ 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_ILI210X) += ili210x.o
diff --git a/drivers/input/touchscreen/exc3000.c b/drivers/input/touchscreen/exc3000.c
new file mode 100644
index 00000000000000..bed0db6999050c
--- /dev/null
+++ b/drivers/input/touchscreen/exc3000.c
@@ -0,0 +1,223 @@
+/*
+ * Driver for I2C connected EETI EXC3000 multiple touch controller
+ *
+ * Copyright (C) 2017 Ahmet Inan
+ *
+ * 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
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#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(unsigned long d)
+{
+ struct exc3000_data *data = (void *)d;
+
+ 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;
+ setup_timer(&data->timer, exc3000_timer, (unsigned long)data);
+
+ 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 ");
+MODULE_DESCRIPTION("I2C connected EETI EXC3000 multiple touch controller driver");
+MODULE_LICENSE("GPL v2");