diff --git a/drivers/hid/i2c-hid/Makefile b/drivers/hid/i2c-hid/Makefile
index 832d8f9aaba2..099e1ce2f234 100644
--- a/drivers/hid/i2c-hid/Makefile
+++ b/drivers/hid/i2c-hid/Makefile
@@ -3,3 +3,6 @@
 #
 
 obj-$(CONFIG_I2C_HID)				+= i2c-hid.o
+
+i2c-hid-objs					=  i2c-hid-core.o
+i2c-hid-$(CONFIG_DMI)				+= i2c-hid-dmi-quirks.o
diff --git a/drivers/hid/i2c-hid/i2c-hid.c b/drivers/hid/i2c-hid/i2c-hid-core.c
similarity index 96%
rename from drivers/hid/i2c-hid/i2c-hid.c
rename to drivers/hid/i2c-hid/i2c-hid-core.c
index cc33622253aa..3cdd1e1aeb95 100644
--- a/drivers/hid/i2c-hid/i2c-hid.c
+++ b/drivers/hid/i2c-hid/i2c-hid-core.c
@@ -43,6 +43,7 @@
 #include <linux/platform_data/i2c-hid.h>
 
 #include "../hid-ids.h"
+#include "i2c-hid.h"
 
 /* quirks to control the device */
 #define I2C_HID_QUIRK_SET_PWR_WAKEUP_DEV	BIT(0)
@@ -673,6 +674,7 @@ static int i2c_hid_parse(struct hid_device *hid)
 	char *rdesc;
 	int ret;
 	int tries = 3;
+	char *use_override;
 
 	i2c_hid_dbg(ihid, "entering %s\n", __func__);
 
@@ -691,26 +693,36 @@ static int i2c_hid_parse(struct hid_device *hid)
 	if (ret)
 		return ret;
 
-	rdesc = kzalloc(rsize, GFP_KERNEL);
+	use_override = i2c_hid_get_dmi_hid_report_desc_override(&rsize);
 
-	if (!rdesc) {
-		dbg_hid("couldn't allocate rdesc memory\n");
-		return -ENOMEM;
-	}
+	if (use_override) {
+		rdesc = use_override;
+		i2c_hid_dbg(ihid, "Using a HID report descriptor override\n");
+	} else {
+		rdesc = kzalloc(rsize, GFP_KERNEL);
 
-	i2c_hid_dbg(ihid, "asking HID report descriptor\n");
+		if (!rdesc) {
+			dbg_hid("couldn't allocate rdesc memory\n");
+			return -ENOMEM;
+		}
 
-	ret = i2c_hid_command(client, &hid_report_descr_cmd, rdesc, rsize);
-	if (ret) {
-		hid_err(hid, "reading report descriptor failed\n");
-		kfree(rdesc);
-		return -EIO;
+		i2c_hid_dbg(ihid, "asking HID report descriptor\n");
+
+		ret = i2c_hid_command(client, &hid_report_descr_cmd,
+				      rdesc, rsize);
+		if (ret) {
+			hid_err(hid, "reading report descriptor failed\n");
+			kfree(rdesc);
+			return -EIO;
+		}
 	}
 
 	i2c_hid_dbg(ihid, "Report Descriptor: %*ph\n", rsize, rdesc);
 
 	ret = hid_parse_report(hid, rdesc, rsize);
-	kfree(rdesc);
+	if (!use_override)
+		kfree(rdesc);
+
 	if (ret) {
 		dbg_hid("parsing report descriptor failed\n");
 		return ret;
@@ -837,12 +849,18 @@ static int i2c_hid_fetch_hid_descriptor(struct i2c_hid *ihid)
 	int ret;
 
 	/* i2c hid fetch using a fixed descriptor size (30 bytes) */
-	i2c_hid_dbg(ihid, "Fetching the HID descriptor\n");
-	ret = i2c_hid_command(client, &hid_descr_cmd, ihid->hdesc_buffer,
-				sizeof(struct i2c_hid_desc));
-	if (ret) {
-		dev_err(&client->dev, "hid_descr_cmd failed\n");
-		return -ENODEV;
+	if (i2c_hid_get_dmi_i2c_hid_desc_override()) {
+		i2c_hid_dbg(ihid, "Using a HID descriptor override\n");
+		ihid->hdesc = *i2c_hid_get_dmi_i2c_hid_desc_override();
+	} else {
+		i2c_hid_dbg(ihid, "Fetching the HID descriptor\n");
+		ret = i2c_hid_command(client, &hid_descr_cmd,
+				      ihid->hdesc_buffer,
+				      sizeof(struct i2c_hid_desc));
+		if (ret) {
+			dev_err(&client->dev, "hid_descr_cmd failed\n");
+			return -ENODEV;
+		}
 	}
 
 	/* Validate the length of HID descriptor, the 4 first bytes:
diff --git a/drivers/hid/i2c-hid/i2c-hid-dmi-quirks.c b/drivers/hid/i2c-hid/i2c-hid-dmi-quirks.c
new file mode 100644
index 000000000000..400f076c6be3
--- /dev/null
+++ b/drivers/hid/i2c-hid/i2c-hid-dmi-quirks.c
@@ -0,0 +1,149 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/*
+ * Quirks for I2C-HID devices that do not supply proper descriptors
+ *
+ * Copyright (c) 2018 Julian Sax <jsbc@gmx.de>
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/dmi.h>
+#include <linux/mod_devicetable.h>
+
+#include "i2c-hid.h"
+
+
+struct i2c_hid_desc_override {
+	union {
+		struct i2c_hid_desc *i2c_hid_desc;
+		uint8_t             *i2c_hid_desc_buffer;
+	};
+	uint8_t              *hid_report_desc;
+	unsigned int          hid_report_desc_size;
+};
+
+
+/* descriptors for the SIPODEV SP1064 touchpad */
+static const struct i2c_hid_desc_override sipodev_desc = {
+	.i2c_hid_desc_buffer = (uint8_t [])
+	{0x1e, 0x00, 0x00, 0x01, 0xdb, 0x01, 0x21, 0x00, 0x24, 0x00,
+	 0x1b, 0x00, 0x25, 0x00, 0x11, 0x00, 0x22, 0x00, 0x23, 0x00,
+	 0x11, 0x09, 0x88, 0x52, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00},
+
+	.hid_report_desc = (uint8_t [])
+	{0x05, 0x01, 0x09, 0x02, 0xa1, 0x01, 0x85, 0x01, 0x09, 0x01,
+	 0xa1, 0x00, 0x05, 0x09, 0x19, 0x01, 0x29, 0x02, 0x25, 0x01,
+	 0x75, 0x01, 0x95, 0x02, 0x81, 0x02, 0x95, 0x06, 0x81, 0x01,
+	 0x05, 0x01, 0x09, 0x30, 0x09, 0x31, 0x15, 0x81, 0x25, 0x7f,
+	 0x75, 0x08, 0x95, 0x02, 0x81, 0x06, 0xc0, 0xc0, 0x05, 0x0d,
+	 0x09, 0x05, 0xa1, 0x01, 0x85, 0x04, 0x05, 0x0d, 0x09, 0x22,
+	 0xa1, 0x02, 0x15, 0x00, 0x25, 0x01, 0x09, 0x47, 0x09, 0x42,
+	 0x95, 0x02, 0x75, 0x01, 0x81, 0x02, 0x95, 0x01, 0x75, 0x03,
+	 0x25, 0x05, 0x09, 0x51, 0x81, 0x02, 0x75, 0x01, 0x95, 0x03,
+	 0x81, 0x03, 0x05, 0x01, 0x26, 0x44, 0x0a, 0x75, 0x10, 0x55,
+	 0x0e, 0x65, 0x11, 0x09, 0x30, 0x46, 0x1a, 0x04, 0x95, 0x01,
+	 0x81, 0x02, 0x46, 0xbc, 0x02, 0x26, 0x34, 0x05, 0x09, 0x31,
+	 0x81, 0x02, 0xc0, 0x05, 0x0d, 0x09, 0x22, 0xa1, 0x02, 0x25,
+	 0x01, 0x09, 0x47, 0x09, 0x42, 0x95, 0x02, 0x75, 0x01, 0x81,
+	 0x02, 0x95, 0x01, 0x75, 0x03, 0x25, 0x05, 0x09, 0x51, 0x81,
+	 0x02, 0x75, 0x01, 0x95, 0x03, 0x81, 0x03, 0x05, 0x01, 0x26,
+	 0x44, 0x0a, 0x75, 0x10, 0x09, 0x30, 0x46, 0x1a, 0x04, 0x95,
+	 0x01, 0x81, 0x02, 0x46, 0xbc, 0x02, 0x26, 0x34, 0x05, 0x09,
+	 0x31, 0x81, 0x02, 0xc0, 0x05, 0x0d, 0x09, 0x22, 0xa1, 0x02,
+	 0x25, 0x01, 0x09, 0x47, 0x09, 0x42, 0x95, 0x02, 0x75, 0x01,
+	 0x81, 0x02, 0x95, 0x01, 0x75, 0x03, 0x25, 0x05, 0x09, 0x51,
+	 0x81, 0x02, 0x75, 0x01, 0x95, 0x03, 0x81, 0x03, 0x05, 0x01,
+	 0x26, 0x44, 0x0a, 0x75, 0x10, 0x09, 0x30, 0x46, 0x1a, 0x04,
+	 0x95, 0x01, 0x81, 0x02, 0x46, 0xbc, 0x02, 0x26, 0x34, 0x05,
+	 0x09, 0x31, 0x81, 0x02, 0xc0, 0x05, 0x0d, 0x09, 0x22, 0xa1,
+	 0x02, 0x25, 0x01, 0x09, 0x47, 0x09, 0x42, 0x95, 0x02, 0x75,
+	 0x01, 0x81, 0x02, 0x95, 0x01, 0x75, 0x03, 0x25, 0x05, 0x09,
+	 0x51, 0x81, 0x02, 0x75, 0x01, 0x95, 0x03, 0x81, 0x03, 0x05,
+	 0x01, 0x26, 0x44, 0x0a, 0x75, 0x10, 0x09, 0x30, 0x46, 0x1a,
+	 0x04, 0x95, 0x01, 0x81, 0x02, 0x46, 0xbc, 0x02, 0x26, 0x34,
+	 0x05, 0x09, 0x31, 0x81, 0x02, 0xc0, 0x05, 0x0d, 0x55, 0x0c,
+	 0x66, 0x01, 0x10, 0x47, 0xff, 0xff, 0x00, 0x00, 0x27, 0xff,
+	 0xff, 0x00, 0x00, 0x75, 0x10, 0x95, 0x01, 0x09, 0x56, 0x81,
+	 0x02, 0x09, 0x54, 0x25, 0x7f, 0x75, 0x08, 0x81, 0x02, 0x05,
+	 0x09, 0x09, 0x01, 0x25, 0x01, 0x75, 0x01, 0x95, 0x01, 0x81,
+	 0x02, 0x95, 0x07, 0x81, 0x03, 0x05, 0x0d, 0x85, 0x02, 0x09,
+	 0x55, 0x09, 0x59, 0x75, 0x04, 0x95, 0x02, 0x25, 0x0f, 0xb1,
+	 0x02, 0x05, 0x0d, 0x85, 0x07, 0x09, 0x60, 0x75, 0x01, 0x95,
+	 0x01, 0x25, 0x01, 0xb1, 0x02, 0x95, 0x07, 0xb1, 0x03, 0x85,
+	 0x06, 0x06, 0x00, 0xff, 0x09, 0xc5, 0x26, 0xff, 0x00, 0x75,
+	 0x08, 0x96, 0x00, 0x01, 0xb1, 0x02, 0xc0, 0x06, 0x00, 0xff,
+	 0x09, 0x01, 0xa1, 0x01, 0x85, 0x0d, 0x26, 0xff, 0x00, 0x19,
+	 0x01, 0x29, 0x02, 0x75, 0x08, 0x95, 0x02, 0xb1, 0x02, 0xc0,
+	 0x05, 0x0d, 0x09, 0x0e, 0xa1, 0x01, 0x85, 0x03, 0x09, 0x22,
+	 0xa1, 0x02, 0x09, 0x52, 0x25, 0x0a, 0x95, 0x01, 0xb1, 0x02,
+	 0xc0, 0x09, 0x22, 0xa1, 0x00, 0x85, 0x05, 0x09, 0x57, 0x09,
+	 0x58, 0x75, 0x01, 0x95, 0x02, 0x25, 0x01, 0xb1, 0x02, 0x95,
+	 0x06, 0xb1, 0x03, 0xc0, 0xc0 },
+	.hid_report_desc_size = 475
+};
+
+
+static const struct dmi_system_id i2c_hid_dmi_desc_override_table[] = {
+	{
+		.ident = "Teclast F6 Pro",
+		.matches = {
+			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "TECLAST"),
+			DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "F6 Pro"),
+		},
+		.driver_data = (void *)&sipodev_desc
+	},
+	{
+		.ident = "Teclast F7",
+		.matches = {
+			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "TECLAST"),
+			DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "F7"),
+		},
+		.driver_data = (void *)&sipodev_desc
+	},
+	{
+		.ident = "Trekstor Primebook C13",
+		.matches = {
+			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "TREKSTOR"),
+			DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Primebook C13"),
+		},
+		.driver_data = (void *)&sipodev_desc
+	},
+	{
+		.ident = "Trekstor Primebook C11",
+		.matches = {
+			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "TREKSTOR"),
+			DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Primebook C11"),
+		},
+		.driver_data = (void *)&sipodev_desc
+	}
+};
+
+
+struct i2c_hid_desc *i2c_hid_get_dmi_i2c_hid_desc_override(void)
+{
+	struct i2c_hid_desc_override *override;
+	const struct dmi_system_id *system_id;
+
+	system_id = dmi_first_match(i2c_hid_dmi_desc_override_table);
+	if (!system_id)
+		return NULL;
+
+	override = system_id->driver_data;
+	return override->i2c_hid_desc;
+}
+
+char *i2c_hid_get_dmi_hid_report_desc_override(unsigned int *size)
+{
+	struct i2c_hid_desc_override *override;
+	const struct dmi_system_id *system_id;
+
+	system_id = dmi_first_match(i2c_hid_dmi_desc_override_table);
+	if (!system_id)
+		return NULL;
+
+	override = system_id->driver_data;
+	*size = override->hid_report_desc_size;
+	return override->hid_report_desc;
+}
+
diff --git a/drivers/hid/i2c-hid/i2c-hid.h b/drivers/hid/i2c-hid/i2c-hid.h
new file mode 100644
index 000000000000..c543bb5ef1c1
--- /dev/null
+++ b/drivers/hid/i2c-hid/i2c-hid.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+
+#ifndef I2C_HID_H
+#define I2C_HID_H
+
+
+#ifdef CONFIG_DMI
+struct i2c_hid_desc *i2c_hid_get_dmi_i2c_hid_desc_override(void);
+char *i2c_hid_get_dmi_hid_report_desc_override(unsigned int *size);
+#else
+static inline struct i2c_hid_desc *i2c_hid_get_dmi_i2c_hid_desc_override(void)
+{ return NULL; }
+static inline char *i2c_hid_get_dmi_hid_report_desc_override(unsigned int *size)
+{ return NULL; }
+#endif
+
+#endif
