diff --git a/drivers/input/touchscreen/ili210x.c b/drivers/input/touchscreen/ili210x.c
index 30576a5f2f045..894f74dba5abf 100644
--- a/drivers/input/touchscreen/ili210x.c
+++ b/drivers/input/touchscreen/ili210x.c
@@ -22,6 +22,12 @@
 /* Touchscreen commands */
 #define REG_TOUCHDATA		0x10
 #define REG_PANEL_INFO		0x20
+#define REG_FIRMWARE_VERSION	0x40
+#define REG_PROTOCOL_VERSION	0x42
+#define REG_KERNEL_VERSION	0x61
+#define REG_IC_MODE		0xc0
+#define REG_IC_MODE_AP		0x5a
+#define REG_IC_MODE_BL		0x55
 #define REG_CALIBRATE		0xcc
 
 struct ili2xxx_chip {
@@ -43,6 +49,7 @@ struct ili210x {
 	struct input_dev *input;
 	struct gpio_desc *reset_gpio;
 	struct touchscreen_properties prop;
+	struct mutex lock;
 	const struct ili2xxx_chip *chip;
 	bool stop;
 };
@@ -307,7 +314,9 @@ static irqreturn_t ili210x_irq(int irq, void *irq_data)
 	int error;
 
 	do {
+		mutex_lock(&priv->lock);
 		error = chip->get_touch_data(client, touchdata);
+		mutex_unlock(&priv->lock);
 		if (error) {
 			dev_err(&client->dev,
 				"Unable to get touch data: %d\n", error);
@@ -323,6 +332,108 @@ static irqreturn_t ili210x_irq(int irq, void *irq_data)
 	return IRQ_HANDLED;
 }
 
+static ssize_t ili251x_firmware_version_show(struct device *dev,
+					     struct device_attribute *attr,
+					     char *buf)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct ili210x *priv = i2c_get_clientdata(client);
+	u8 fw[8];
+	int ret;
+
+	/* Get firmware version */
+	mutex_lock(&priv->lock);
+	ret = priv->chip->read_reg(client, REG_FIRMWARE_VERSION,
+				   &fw, sizeof(fw));
+	mutex_unlock(&priv->lock);
+
+	if (ret)
+		return ret;
+
+	if (!ret) {
+		ret = scnprintf(buf, PAGE_SIZE,
+				"%02x%02x.%02x%02x.%02x%02x.%02x%02x\n",
+				fw[0], fw[1], fw[2], fw[3],
+				fw[4], fw[5], fw[6], fw[7]);
+	}
+
+	return ret;
+}
+static DEVICE_ATTR(firmware_version, 0444, ili251x_firmware_version_show, NULL);
+
+static ssize_t ili251x_kernel_version_show(struct device *dev,
+					   struct device_attribute *attr,
+					   char *buf)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct ili210x *priv = i2c_get_clientdata(client);
+	u8 kv[5];
+	int ret;
+
+	/* Get kernel version */
+	mutex_lock(&priv->lock);
+	ret = priv->chip->read_reg(client, REG_KERNEL_VERSION,
+				   &kv, sizeof(kv));
+	mutex_unlock(&priv->lock);
+
+	if (ret)
+		return ret;
+
+	return scnprintf(buf, PAGE_SIZE, "%02x.%02x.%02x.%02x.%02x\n",
+			 kv[0], kv[1], kv[2], kv[3], kv[4]);
+}
+static DEVICE_ATTR(kernel_version, 0444, ili251x_kernel_version_show, NULL);
+
+static ssize_t ili251x_protocol_version_show(struct device *dev,
+					     struct device_attribute *attr,
+					     char *buf)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct ili210x *priv = i2c_get_clientdata(client);
+	u8 pv[2];
+	int ret;
+
+	/* Get protocol version */
+	mutex_lock(&priv->lock);
+	ret = priv->chip->read_reg(client, REG_PROTOCOL_VERSION,
+				   &pv, sizeof(pv));
+	mutex_unlock(&priv->lock);
+
+	if (ret)
+		return ret;
+
+	return scnprintf(buf, PAGE_SIZE, "%02x.%02x\n", pv[0], pv[1]);
+}
+static DEVICE_ATTR(protocol_version, 0444, ili251x_protocol_version_show, NULL);
+
+static ssize_t ili251x_mode_show(struct device *dev,
+				 struct device_attribute *attr, char *buf)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct ili210x *priv = i2c_get_clientdata(client);
+	char *mode = "AP";
+	u8 md[2];
+	int ret;
+
+	/* Get mode */
+	mutex_lock(&priv->lock);
+	ret = priv->chip->read_reg(client, REG_IC_MODE, &md, sizeof(md));
+	mutex_unlock(&priv->lock);
+
+	if (ret)
+		return ret;
+
+	if (md[0] == REG_IC_MODE_AP)		/* Application Mode */
+		mode = "AP";
+	else if (md[0] == REG_IC_MODE_BL)	/* BootLoader Mode */
+		mode = "BL";
+	else					/* Unknown Mode */
+		mode = "??";
+
+	return scnprintf(buf, PAGE_SIZE, "%02x.%02x:%s\n", md[0], md[1], mode);
+}
+static DEVICE_ATTR(mode, 0444, ili251x_mode_show, NULL);
+
 static ssize_t ili210x_calibrate(struct device *dev,
 				 struct device_attribute *attr,
 				 const char *buf, size_t count)
@@ -351,22 +462,34 @@ static DEVICE_ATTR(calibrate, S_IWUSR, NULL, ili210x_calibrate);
 
 static struct attribute *ili210x_attributes[] = {
 	&dev_attr_calibrate.attr,
+	&dev_attr_firmware_version.attr,
+	&dev_attr_kernel_version.attr,
+	&dev_attr_protocol_version.attr,
+	&dev_attr_mode.attr,
 	NULL,
 };
 
-static umode_t ili210x_calibrate_visible(struct kobject *kobj,
+static umode_t ili210x_attributes_visible(struct kobject *kobj,
 					  struct attribute *attr, int index)
 {
 	struct device *dev = kobj_to_dev(kobj);
 	struct i2c_client *client = to_i2c_client(dev);
 	struct ili210x *priv = i2c_get_clientdata(client);
 
-	return priv->chip->has_calibrate_reg ? attr->mode : 0;
+	/* Calibrate is present on all ILI2xxx which have calibrate register */
+	if (attr == &dev_attr_calibrate.attr)
+		return priv->chip->has_calibrate_reg ? attr->mode : 0;
+
+	/* Firmware/Kernel/Protocol/BootMode is implememted only for ILI251x */
+	if (priv->chip != &ili251x_chip)
+		return 0;
+
+	return attr->mode;
 }
 
 static const struct attribute_group ili210x_attr_group = {
 	.attrs = ili210x_attributes,
-	.is_visible = ili210x_calibrate_visible,
+	.is_visible = ili210x_attributes_visible,
 };
 
 static void ili210x_power_down(void *data)
@@ -437,6 +560,7 @@ static int ili210x_i2c_probe(struct i2c_client *client,
 	priv->input = input;
 	priv->reset_gpio = reset_gpio;
 	priv->chip = chip;
+	mutex_init(&priv->lock);
 	i2c_set_clientdata(client, priv);
 
 	/* Setup input device */
