Pārlūkot izejas kodu

adding patches for 4.18.x

Jake Day 6 gadi atpakaļ
vecāks
revīzija
83a5a5b425

+ 1324 - 0
patches/4.18/acpi.patch

@@ -0,0 +1,1324 @@
+diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
+index ac4d48830415..2025f56446a0 100644
+--- a/drivers/platform/x86/Kconfig
++++ b/drivers/platform/x86/Kconfig
+@@ -1158,6 +1158,15 @@ config SURFACE_3_BUTTON
+ 	---help---
+ 	  This driver handles the power/home/volume buttons on the Microsoft Surface 3 tablet.
+ 
++config ACPI_SURFACE
++	tristate "Microsoft Surface Extras"
++	depends on ACPI
++	depends on ACPI_WMI
++	depends on INPUT
++	---help---
++	  This driver adds support for access to certain system events
++	  on Microsoft Surface devices.
++
+ config INTEL_PUNIT_IPC
+ 	tristate "Intel P-Unit IPC Driver"
+ 	---help---
+diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
+index 2ba6cb795338..8fd5b93bb20d 100644
+--- a/drivers/platform/x86/Makefile
++++ b/drivers/platform/x86/Makefile
+@@ -81,6 +81,9 @@ obj-$(CONFIG_INTEL_PMC_IPC)	+= intel_pmc_ipc.o
+ obj-$(CONFIG_SILEAD_DMI)	+= silead_dmi.o
+ obj-$(CONFIG_SURFACE_PRO3_BUTTON)	+= surfacepro3_button.o
+ obj-$(CONFIG_SURFACE_3_BUTTON)	+= surface3_button.o
++obj-$(CONFIG_ACPI_SURFACE)	+= surface_acpi.o
++obj-$(CONFIG_ACPI_SURFACE)	+= surface_i2c.o
++obj-$(CONFIG_ACPI_SURFACE)	+= surface_platform.o
+ obj-$(CONFIG_INTEL_PUNIT_IPC)  += intel_punit_ipc.o
+ obj-$(CONFIG_INTEL_BXTWC_PMIC_TMU)	+= intel_bxtwc_tmu.o
+ obj-$(CONFIG_INTEL_TELEMETRY)	+= intel_telemetry_core.o \
+diff --git a/drivers/platform/x86/surface_acpi.c b/drivers/platform/x86/surface_acpi.c
+new file mode 100644
+index 000000000000..c969bda99464
+--- /dev/null
++++ b/drivers/platform/x86/surface_acpi.c
+@@ -0,0 +1,485 @@
++/*
++ *  surface_acpi.c - Microsoft Surface ACPI Driver
++ *
++ *  This program is free software; you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License as published by
++ *  the Free Software Foundation; either version 2 of the License, or
++ *  (at your option) any later version.
++ *
++ *  This program is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  The full GNU General Public License is included in this distribution in
++ *  the file called "COPYING".
++ */
++
++#define SURFACE_ACPI_VERSION	"0.1"
++#define SURFACE_GEN_VERSION		0x08
++#define PROC_SURFACE			"surface"
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/types.h>
++#include <linux/acpi.h>
++#include <linux/power_supply.h>
++#include <linux/thermal.h>
++#include <linux/dmi.h>
++#include <linux/seq_file.h>
++#include <acpi/acpi_bus.h>
++#include <acpi/acpi_drivers.h>
++
++#include "surface_acpi.h"
++
++#define SUR_METHOD_DSM			"_DSM"
++#define SUR_METHOD_REG			"_REG"
++#define SUR_METHOD_STA			"_STA"
++#define SUR_METHOD_INI			"_INI"
++#define SUR_METHOD_CRS			"_CRS"
++
++#define SUR_QUERY_DEVICE		0x00
++#define SUR_SET_DVER			0x01
++#define SUR_GET_BOARD_REVID		0x02
++#define SUR_BAT1_STATE_CHANGE	0x03
++#define SUR_BAT1_INFO_CHANGE	0x04
++#define SUR_PSU_STATE_CHANGE	0x05
++#define SUR_PSU_INFO_CHANGE		0x06
++#define SUR_BAT2_STATE_CHANGE	0x07
++#define SUR_BAT2_INFO_CHANGE	0x08
++#define SUR_SENSOR_TRIP_POINT	0x09
++
++#define REG_AVAILABLE			0x01
++#define REG_INIT				0x09
++
++static char SURFACE_EVENT_GUID[] = "93b666c5-70c6-469f-a215-3d487c91ab3c";
++static char SUR_SAN_RQST[] = "\\_SB._SAN.RQST";
++static char SUR_SAN_RQSX[] = "\\_SB._SAN.RQSX";
++
++struct surface_acpi_dev {
++	acpi_handle handle;
++	acpi_handle rqst_handle;
++	acpi_handle rqsx_handle;
++
++	struct acpi_device *san_dev;
++	struct acpi_device *ssh_dev;
++	struct acpi_device *bat1_dev;
++	struct acpi_device *bat2_dev;
++	struct acpi_device *psu_dev;
++
++	unsigned int bat1_attached:1;
++	unsigned int bat2_attached:1;
++	unsigned int psu_registered:1;
++};
++
++static struct surface_acpi_dev *surface_acpi;
++
++static struct proc_dir_entry *surface_proc_dir;
++
++static acpi_status surface_acpi_check_status(struct acpi_device *dev)
++{
++	unsigned long long value;
++	acpi_status status;
++
++	if (acpi_has_method(dev->handle, SUR_METHOD_STA)) {
++		status = acpi_evaluate_integer(dev->handle,
++				SUR_METHOD_STA, NULL, &value);
++
++		if (ACPI_FAILURE(status)) {
++			pr_err("surface_acpi: ACPI event failure status %s\n",
++					acpi_format_exception(status));
++			return AE_ERROR;
++		}
++	}
++	else
++		return AE_NOT_FOUND;
++
++	return AE_OK;
++}
++
++static acpi_status surface_acpi_san_reg(void)
++{
++	union acpi_object in_objs[2], out_objs[1];
++	struct acpi_object_list params;
++	struct acpi_buffer results;
++	acpi_status status;
++
++	params.count = ARRAY_SIZE(in_objs);
++	params.pointer = in_objs;
++	in_objs[0].type = ACPI_TYPE_INTEGER;
++	in_objs[0].integer.value = REG_INIT;
++	in_objs[1].type = ACPI_TYPE_INTEGER;
++	in_objs[1].integer.value = REG_AVAILABLE;
++	results.length = sizeof(out_objs);
++	results.pointer = out_objs;
++
++	if (acpi_has_method(surface_acpi->handle, SUR_METHOD_REG)) {
++		status = acpi_evaluate_object(surface_acpi->handle,
++				SUR_METHOD_REG, &params, &results);
++
++		if (ACPI_FAILURE(status)) {
++			pr_err("surface_acpi: ACPI event failure status %s\n",
++					acpi_format_exception(status));
++			return AE_ERROR;
++		}
++	}
++	else
++		return AE_NOT_FOUND;
++
++	return AE_OK;
++}
++
++acpi_status surface_acpi_event_handler(u32 event)
++{
++	union acpi_object in_objs[4], out_objs[5];
++	struct acpi_object_list params;
++	struct acpi_buffer results;
++	acpi_status status;
++
++	params.count = ARRAY_SIZE(in_objs);
++	params.pointer = in_objs;
++	in_objs[0].type = ACPI_TYPE_BUFFER;
++	in_objs[0].buffer.length = sizeof(SURFACE_EVENT_GUID);
++	in_objs[0].buffer.pointer = SURFACE_EVENT_GUID;
++	in_objs[1].type = ACPI_TYPE_INTEGER;
++	in_objs[1].integer.value = SUR_QUERY_DEVICE;
++	in_objs[2].type = ACPI_TYPE_INTEGER;
++	in_objs[2].integer.value = event;
++	in_objs[3].type = ACPI_TYPE_PACKAGE;
++	in_objs[3].package.count = 0;
++	in_objs[3].package.elements = SURFACE_GEN_VERSION;
++	results.length = sizeof(out_objs);
++	results.pointer = out_objs;
++
++	if (acpi_has_method(surface_acpi->handle, SUR_METHOD_DSM)) {
++		status = acpi_evaluate_object(surface_acpi->handle,
++				SUR_METHOD_DSM, &params, &results);
++
++		if (ACPI_FAILURE(status)) {
++			pr_err("surface_acpi: ACPI event failure status %s\n",
++					acpi_format_exception(status));
++			return AE_ERROR;
++		}
++	}
++	else
++		return AE_NOT_FOUND;
++
++	return AE_OK;
++}
++EXPORT_SYMBOL(surface_acpi_event_handler);
++
++static void surface_acpi_san_load(void)
++{
++	acpi_status ret;
++
++	ret = surface_acpi_event_handler(SUR_SET_DVER);
++	if (ACPI_FAILURE(ret))
++		pr_err("surface_acpi: Error setting Driver Version\n");
++
++	ret = surface_acpi_event_handler(SUR_SENSOR_TRIP_POINT);
++	if (ACPI_FAILURE(ret))
++		pr_err("surface_acpi: Error setting Sensor Trip Point\n");
++
++	ret = surface_acpi_event_handler(SUR_BAT1_INFO_CHANGE);
++	if (ACPI_FAILURE(ret))
++		pr_err("surface_acpi: Error attaching BAT1\n");
++	else
++		surface_acpi->bat1_attached = 1;
++
++	ret = surface_acpi_event_handler(SUR_BAT2_INFO_CHANGE);
++	if (ACPI_FAILURE(ret))
++		pr_err("surface_acpi: Error attaching BAT2\n");
++	else
++		surface_acpi->bat2_attached = 1;
++
++	ret = surface_acpi_event_handler(SUR_PSU_INFO_CHANGE);
++	if (ACPI_FAILURE(ret))
++		pr_err("surface_acpi: Error registering PSU\n");
++	else
++		surface_acpi->psu_registered = 1;
++}
++
++static acpi_status surface_acpi_ssh_initialize(void)
++{
++	acpi_status status;
++
++	if (acpi_has_method(surface_acpi->ssh_dev->handle, SUR_METHOD_INI)) {
++		status = acpi_evaluate_object(surface_acpi->ssh_dev->handle,
++				SUR_METHOD_INI, NULL, NULL);
++
++		if (ACPI_FAILURE(status)) {
++			pr_err("surface_acpi: ACPI event failure status %s\n",
++					acpi_format_exception(status));
++			return AE_ERROR;
++		}
++	}
++	else
++		return AE_NOT_FOUND;
++
++	return AE_OK;
++}
++
++static int bat1_proc_show(struct seq_file *m, void *v)
++{
++	seq_printf(m, "attached: %d\n", surface_acpi->bat1_attached);
++	return 0;
++}
++
++static int bat1_proc_open(struct inode *inode, struct file *file)
++{
++	return single_open(file, bat1_proc_show, PDE_DATA(inode));
++}
++
++static const struct file_operations bat1_proc_fops = {
++	.owner		= THIS_MODULE,
++	.open		= bat1_proc_open,
++	.read		= seq_read,
++	.llseek		= seq_lseek,
++	.release	= single_release,
++};
++
++static int bat2_proc_show(struct seq_file *m, void *v)
++{
++	seq_printf(m, "attached: %d\n", surface_acpi->bat2_attached);
++	return 0;
++}
++
++static int bat2_proc_open(struct inode *inode, struct file *file)
++{
++	return single_open(file, bat2_proc_show, PDE_DATA(inode));
++}
++
++static const struct file_operations bat2_proc_fops = {
++	.owner		= THIS_MODULE,
++	.open		= bat2_proc_open,
++	.read		= seq_read,
++	.llseek		= seq_lseek,
++	.release	= single_release,
++};
++
++static int psu_proc_show(struct seq_file *m, void *v)
++{
++	seq_printf(m, "registered: %d\n", surface_acpi->psu_registered);
++	return 0;
++}
++
++static int psu_proc_open(struct inode *inode, struct file *file)
++{
++	return single_open(file, psu_proc_show, PDE_DATA(inode));
++}
++
++static const struct file_operations psu_proc_fops = {
++	.owner		= THIS_MODULE,
++	.open		= psu_proc_open,
++	.read		= seq_read,
++	.llseek		= seq_lseek,
++	.release	= single_release,
++};
++
++static int version_proc_show(struct seq_file *m, void *v)
++{
++	seq_printf(m, "driver: %s\n", SURFACE_ACPI_VERSION);
++	return 0;
++}
++
++static int version_proc_open(struct inode *inode, struct file *file)
++{
++	return single_open(file, version_proc_show, PDE_DATA(inode));
++}
++
++static const struct file_operations version_proc_fops = {
++	.owner		= THIS_MODULE,
++	.open		= version_proc_open,
++	.read		= seq_read,
++	.llseek		= seq_lseek,
++	.release	= single_release,
++};
++
++static void create_surface_proc_entries(void)
++{
++	proc_create_data("BAT1", 0, surface_proc_dir,
++			 &bat1_proc_fops, surface_acpi->bat1_attached);
++	proc_create_data("BAT2", 0, surface_proc_dir,
++			 &bat2_proc_fops, surface_acpi->bat2_attached);
++	proc_create_data("ADP1", 0, surface_proc_dir,
++			 &psu_proc_fops, surface_acpi->psu_registered);
++	proc_create_data("version", 0, surface_proc_dir,
++			 &version_proc_fops, SURFACE_ACPI_VERSION);
++}
++
++static void remove_surface_proc_entries(void)
++{
++	remove_proc_entry("BAT1", surface_proc_dir);
++	remove_proc_entry("BAT2", surface_proc_dir);
++	remove_proc_entry("ADP1", surface_proc_dir);
++	remove_proc_entry("version", surface_proc_dir);
++}
++
++static void surface_acpi_notify(struct acpi_device *dev, u32 event)
++{
++	pr_info("surface_acpi: Event received %x\n", event);
++}
++
++static void surface_acpi_register_rqst_handler(void)
++{
++	acpi_status status;
++
++	status = acpi_get_handle(NULL, SUR_SAN_RQST, &surface_acpi->rqst_handle);
++	if (ACPI_FAILURE(status)) {
++		pr_err("surface_acpi: ACPI event failure status %s\n",
++					acpi_format_exception(status));
++	}
++}
++
++static void surface_acpi_register_rqsx_handler(void)
++{
++	acpi_status status;
++
++	status = acpi_get_handle(NULL, SUR_SAN_RQSX, &surface_acpi->rqsx_handle);
++	if (ACPI_FAILURE(status)) {
++		pr_err("surface_acpi: ACPI event failure status %s\n",
++					acpi_format_exception(status));
++	}
++}
++
++static acpi_status surface_acpi_walk_callback(acpi_handle handle, u32 level,
++						void *context, void **return_value)
++{
++	struct acpi_device_info *info;
++
++	if (ACPI_SUCCESS(acpi_get_object_info(handle, &info))) {
++		pr_warn("method: name: %4.4s, args %X\n",
++			(char *)&info->name, info->param_count);
++
++		kfree(info);
++	}
++
++	return AE_OK;
++}
++
++static void surface_acpi_walk_namespace(struct acpi_device *dev)
++{
++	acpi_status status;
++
++	status = acpi_walk_namespace(ACPI_TYPE_METHOD,
++			dev->handle, 1, surface_acpi_walk_callback,
++			NULL, NULL, NULL);
++	if (ACPI_FAILURE(status))
++		pr_warn("surface_acpi: Unable to walk acpi resources\n");
++}
++
++static int surface_acpi_add(struct acpi_device *dev)
++{
++	if (!surface_acpi)
++	{
++		surface_acpi = kzalloc(sizeof(*surface_acpi), GFP_KERNEL);
++		if (!surface_acpi)
++			return AE_NO_MEMORY;
++	}
++
++	if (acpi_has_method(dev->handle, SUR_METHOD_DSM))
++	{
++		pr_info("surface_acpi: Attaching device MSHW0091\n");
++
++		surface_acpi->san_dev = dev;
++		surface_acpi->handle = dev->handle;
++
++		surface_acpi_walk_namespace(surface_acpi->san_dev);
++		surface_acpi_check_status(surface_acpi->san_dev);
++
++		surface_acpi_register_rqst_handler();
++		surface_acpi_register_rqsx_handler();
++
++		surface_acpi_san_reg();
++		surface_acpi_san_load();
++
++		create_surface_proc_entries();
++	}
++	else if (acpi_has_method(dev->handle, SUR_METHOD_CRS))
++	{
++		pr_info("surface_acpi: Attaching device MSHW0084\n");
++
++		surface_acpi->ssh_dev = dev;
++
++		surface_acpi_walk_namespace(surface_acpi->ssh_dev);
++		surface_acpi_check_status(surface_acpi->ssh_dev);
++
++		surface_acpi_ssh_initialize();
++		//surface_acpi_ssh_load();
++	}
++	else
++	{
++		pr_info("surface_acpi: Attaching device\n");
++	}
++
++	device_init_wakeup(&dev->dev, true);
++
++	return AE_OK;
++}
++
++static int surface_acpi_remove(struct acpi_device *dev)
++{
++	remove_surface_proc_entries();
++
++	return AE_OK;
++}
++
++static const struct acpi_device_id surface_device_ids[] = {
++	{"MSHW0084", 0},
++	{"MSHW0091", 0},
++	{"MSHW0124", 0},
++	{"INT3403", 0},
++	{"LNXTHERM", 0},
++	{"PNP0C0A", 0},
++	{"", 0},
++};
++MODULE_DEVICE_TABLE(acpi, surface_device_ids);
++
++static struct acpi_driver surface_acpi_driver = {
++	.name	= "surface_acpi",
++	.owner	= THIS_MODULE,
++	.ids	= surface_device_ids,
++	.flags	= ACPI_DRIVER_ALL_NOTIFY_EVENTS,
++	.ops	= {
++		.add	= surface_acpi_add,
++		.remove = surface_acpi_remove,
++		.notify = surface_acpi_notify,
++	},
++};
++
++static int __init surface_acpi_init(void)
++{
++	int ret;
++
++	pr_info("surface_acpi: Microsoft Surface ACPI Driver version %s\n",
++	       SURFACE_ACPI_VERSION);
++
++	surface_proc_dir = proc_mkdir(PROC_SURFACE, acpi_root_dir);
++	if (!surface_proc_dir) {
++		pr_err("surface_acpi: Unable to create proc dir " PROC_SURFACE "\n");
++		return -ENODEV;
++	}
++
++	ret = acpi_bus_register_driver(&surface_acpi_driver);
++	if (ret) {
++		pr_err("surface_acpi: Failed to register ACPI driver: %d\n", ret);
++		remove_proc_entry(PROC_SURFACE, acpi_root_dir);
++	}
++
++	return ret;
++}
++
++static void __exit surface_acpi_exit(void)
++{
++	acpi_bus_unregister_driver(&surface_acpi_driver);
++	if (surface_proc_dir)
++		remove_proc_entry(PROC_SURFACE, acpi_root_dir);
++}
++
++module_init(surface_acpi_init);
++module_exit(surface_acpi_exit);
++
++MODULE_AUTHOR("Jake Day");
++MODULE_DESCRIPTION("Microsoft Surface ACPI Driver");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/platform/x86/surface_acpi.h b/drivers/platform/x86/surface_acpi.h
+new file mode 100644
+index 000000000000..5b6627c4d6f1
+--- /dev/null
++++ b/drivers/platform/x86/surface_acpi.h
+@@ -0,0 +1,18 @@
++/*
++ *  surface_acpi.h - Microsoft Surface ACPI Driver
++ *
++ *  This program is free software; you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License as published by
++ *  the Free Software Foundation; either version 2 of the License, or
++ *  (at your option) any later version.
++ *
++ *  This program is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  The full GNU General Public License is included in this distribution in
++ *  the file called "COPYING".
++ */
++
++acpi_status surface_acpi_event_handler(u32 event);
+diff --git a/drivers/platform/x86/surface_i2c.c b/drivers/platform/x86/surface_i2c.c
+new file mode 100644
+index 000000000000..fb2cf0cae72f
+--- /dev/null
++++ b/drivers/platform/x86/surface_i2c.c
+@@ -0,0 +1,696 @@
++/*
++ *  surface_i2c.c - Microsoft Surface I2C Driver
++ *
++ *  This program is free software; you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License as published by
++ *  the Free Software Foundation; either version 2 of the License, or
++ *  (at your option) any later version.
++ *
++ *  This program is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  The full GNU General Public License is included in this distribution in
++ *  the file called "COPYING".
++ */
++
++#include <linux/kernel.h>
++#include <linux/i2c.h>
++#include <linux/slab.h>
++#include <linux/acpi.h>
++#include <linux/module.h>
++#include <linux/uuid.h>
++#include <linux/kthread.h>
++#include <linux/freezer.h>
++#include <asm/unaligned.h>
++
++#include "surface_acpi.h"
++
++#define POLL_INTERVAL		(HZ * 2)
++
++struct surface_i2c_data {
++	struct i2c_client *adp1;
++	struct i2c_client *bat0;
++	unsigned short notify_version;
++	struct task_struct *poll_task;
++	bool kthread_running;
++	bool charging;
++	bool bat_charging;
++	u8 trip_point;
++	s32 full_capacity;
++};
++
++struct surface_i2c_lookup {
++	struct surface_i2c_data	*cdata;
++	unsigned int n;
++	unsigned int index;
++	int addr;
++};
++
++struct surface_i2c_handler_data {
++	struct acpi_connection_info info;
++	struct i2c_client *client;
++};
++
++struct bix {
++	u32	revision;
++	u32	power_unit;
++	u32	design_capacity;
++	u32	last_full_charg_capacity;
++	u32	battery_technology;
++	u32	design_voltage;
++	u32	design_capacity_of_warning;
++	u32	design_capacity_of_low;
++	u32	cycle_count;
++	u32	measurement_accuracy;
++	u32	max_sampling_time;
++	u32	min_sampling_time;
++	u32	max_average_interval;
++	u32	min_average_interval;
++	u32	battery_capacity_granularity_1;
++	u32	battery_capacity_granularity_2;
++	char model[10];
++	char serial[10];
++	char type[10];
++	char OEM[10];
++} __packed;
++
++struct bst {
++	u32 battery_state;
++	s32 battery_present_rate;
++	u32 battery_remaining_capacity;
++	u32 battery_present_voltage;
++} __packed;
++
++struct gsb_command {
++	u8 arg0;
++	u8 arg1;
++	u8 arg2;
++} __packed;
++
++struct gsb_buffer {
++	u8 status;
++	u8 len;
++	u8 ret;
++	union {
++		struct gsb_command cmd;
++		struct bst bst;
++		struct bix bix;
++	} __packed;
++} __packed;
++
++#define ACPI_BATTERY_STATE_DISCHARGING	0x1
++#define ACPI_BATTERY_STATE_CHARGING		0x2
++#define ACPI_BATTERY_STATE_CRITICAL		0x4
++
++#define surface_i2c_CMD_DEST_BAT0		0x01
++#define surface_i2c_CMD_DEST_ADP1		0x03
++
++#define surface_i2c_CMD_BAT0_STA		0x01
++#define surface_i2c_CMD_BAT0_BIX		0x02
++#define surface_i2c_CMD_BAT0_BCT		0x03
++#define surface_i2c_CMD_BAT0_BTM		0x04
++#define surface_i2c_CMD_BAT0_BST		0x05
++#define surface_i2c_CMD_BAT0_BTP		0x06
++#define surface_i2c_CMD_ADP1_PSR		0x07
++#define surface_i2c_CMD_BAT0_PSOC		0x09
++#define surface_i2c_CMD_BAT0_PMAX		0x0A
++#define surface_i2c_CMD_BAT0_PSRC		0x0B
++#define surface_i2c_CMD_BAT0_CHGI		0x0C
++#define surface_i2c_CMD_BAT0_ARTG		0x0D
++
++#define surface_i2c_NOTIFY_GET_VERSION	0x00
++#define surface_i2c_NOTIFY_ADP1			0x01
++#define surface_i2c_NOTIFY_BAT0_BST		0x02
++#define surface_i2c_NOTIFY_BAT0_BIX		0x05
++
++#define surface_i2c_ADP1_REG_PSR		0x03
++
++#define surface_i2c_BAT0_REG_CAPACITY			0x0c
++#define surface_i2c_BAT0_REG_FULL_CHG_CAPACITY	0x0e
++#define surface_i2c_BAT0_REG_DESIGN_CAPACITY	0x40
++#define surface_i2c_BAT0_REG_VOLTAGE			0x08
++#define surface_i2c_BAT0_REG_RATE				0x14
++#define surface_i2c_BAT0_REG_OEM				0x45
++#define surface_i2c_BAT0_REG_TYPE				0x4e
++#define surface_i2c_BAT0_REG_SERIAL_NO			0x56
++#define surface_i2c_BAT0_REG_CYCLE_CNT			0x6e
++
++#define surface_i2c_EV_2_5				0x1ff
++
++static int surface_i2c_read_block(struct i2c_client *client, u8 reg, u8 *buf,
++				   int len)
++{
++	int status, i;
++
++	for (i = 0; i < len; i++) {
++		status = i2c_smbus_read_byte_data(client, reg + i);
++		if (status < 0) {
++			buf[i] = 0xff;
++			continue;
++		}
++
++		buf[i] = (u8)status;
++	}
++
++	return 0;
++}
++
++static int
++surface_i2c_notify(struct surface_i2c_data *cdata, u8 arg1, u8 arg2,
++		unsigned int *ret_value)
++{
++	/*static const guid_t surface_i2c_guid =
++	GUID_INIT(0x93b666c5, 0x70c6, 0x469f,
++		  0xa2, 0x15, 0x3d, 0x48, 0x7c, 0x91, 0xab, 0x3c);*/
++
++	struct acpi_device *adev;
++	acpi_handle handle;
++	acpi_status status;
++
++	handle = ACPI_HANDLE(&cdata->adp1->dev);
++	if (!handle || acpi_bus_get_device(handle, &adev))
++		return -ENODEV;
++
++	*ret_value = 0;
++
++	status = surface_acpi_event_handler(arg2);
++	if (ACPI_FAILURE(status)) {
++		pr_err("surface_i2c: ACPI event failure status %s\n",
++					acpi_format_exception(status));
++	}
++
++	return 0;
++}
++
++static const struct bix default_bix = {
++	.revision = 0x00,
++	.power_unit = 0x00,
++	.design_capacity = 0x1734,
++	.last_full_charg_capacity = 0x1734,
++	.battery_technology = 0x01,
++	.design_voltage = 0x1d92,
++	.design_capacity_of_warning = 0xc8,
++	.design_capacity_of_low = 0xc8,
++	.battery_capacity_granularity_1 = 0x45,
++	.battery_capacity_granularity_2 = 0x11,
++	.cycle_count = 0x01,
++	.measurement_accuracy = 0x00015F90,
++	.max_sampling_time = 0x03E8,
++	.min_sampling_time = 0x03E8,
++	.max_average_interval = 0x03E8,
++	.min_average_interval = 0x03E8,
++	.model = "PNP0C0A",
++	.serial = "1234567890",
++	.type = "SDS-BAT",
++	.OEM = "MICROSOFT",
++};
++
++static int surface_i2c_bix(struct surface_i2c_data *cdata, struct bix *bix)
++{
++	struct i2c_client *client = cdata->bat0;
++	int ret;
++	char buf[10];
++
++	*bix = default_bix;
++
++	/* get design capacity */
++	ret = i2c_smbus_read_word_data(client, surface_i2c_BAT0_REG_DESIGN_CAPACITY);
++	if (ret < 0) {
++		dev_err(&client->dev, "Error reading design capacity: %d\n", ret);
++		return ret;
++	}
++	bix->design_capacity = le16_to_cpu(ret);
++
++	/* get last full charge capacity */
++	ret = i2c_smbus_read_word_data(client, surface_i2c_BAT0_REG_FULL_CHG_CAPACITY);
++	if (ret < 0) {
++		dev_err(&client->dev, "Error reading last full charge capacity: %d\n", ret);
++		return ret;
++	}
++	bix->last_full_charg_capacity = le16_to_cpu(ret);
++
++	/* get serial number */
++	ret = surface_i2c_read_block(client, surface_i2c_BAT0_REG_SERIAL_NO,
++				      buf, 10);
++	if (ret) {
++		dev_err(&client->dev, "Error reading serial no: %d\n", ret);
++		return ret;
++	}
++	memcpy(bix->serial, buf + 7, 3);
++	memcpy(bix->serial + 3, buf, 6);
++	bix->serial[9] = '\0';
++
++	/* get cycle count */
++	ret = i2c_smbus_read_word_data(client, surface_i2c_BAT0_REG_CYCLE_CNT);
++	if (ret < 0) {
++		dev_err(&client->dev, "Error reading cycle count: %d\n", ret);
++		return ret;
++	}
++	bix->cycle_count = le16_to_cpu(ret);
++
++	/* get OEM name */
++	ret = surface_i2c_read_block(client, surface_i2c_BAT0_REG_OEM, buf, 4);
++	if (ret) {
++		dev_err(&client->dev, "Error reading cycle count: %d\n", ret);
++		return ret;
++	}
++	memcpy(bix->OEM, buf, 3);
++	bix->OEM[4] = '\0';
++
++	return 0;
++}
++
++static int surface_i2c_bst(struct surface_i2c_data *cdata, struct bst *bst)
++{
++	struct i2c_client *client = cdata->bat0;
++	int rate, capacity, voltage, state;
++	s16 tmp;
++
++	rate = i2c_smbus_read_word_data(client, surface_i2c_BAT0_REG_RATE);
++	if (rate < 0)
++		return rate;
++
++	capacity = i2c_smbus_read_word_data(client, surface_i2c_BAT0_REG_CAPACITY);
++	if (capacity < 0)
++		return capacity;
++
++	voltage = i2c_smbus_read_word_data(client, surface_i2c_BAT0_REG_VOLTAGE);
++	if (voltage < 0)
++		return voltage;
++
++	tmp = le16_to_cpu(rate);
++	bst->battery_present_rate = abs((s32)tmp);
++
++	state = 0;
++	if ((s32) tmp > 0)
++		state |= ACPI_BATTERY_STATE_CHARGING;
++	else if ((s32) tmp < 0)
++		state |= ACPI_BATTERY_STATE_DISCHARGING;
++	bst->battery_state = state;
++
++	bst->battery_remaining_capacity = le16_to_cpu(capacity);
++	bst->battery_present_voltage = le16_to_cpu(voltage);
++
++	return 0;
++}
++
++static int surface_i2c_adp_psr(struct surface_i2c_data *cdata)
++{
++	struct i2c_client *client = cdata->adp1;
++	int ret;
++
++	ret = i2c_smbus_read_byte_data(client, surface_i2c_ADP1_REG_PSR);
++	if (ret < 0)
++		return ret;
++
++	return ret;
++}
++
++static int surface_i2c_isr(struct surface_i2c_data *cdata)
++{
++	struct bst bst;
++	struct bix bix;
++	int ret;
++	bool status, bat_status;
++
++	ret = surface_i2c_adp_psr(cdata);
++	if (ret < 0)
++		return ret;
++
++	status = ret;
++
++	if (status != cdata->charging)
++		surface_i2c_notify(cdata, cdata->notify_version,
++				surface_i2c_NOTIFY_ADP1, &ret);
++
++	cdata->charging = status;
++
++	ret = surface_i2c_bst(cdata, &bst);
++	if (ret < 0)
++		return ret;
++
++	bat_status = bst.battery_state;
++
++	if (bat_status != cdata->bat_charging)
++		surface_i2c_notify(cdata, cdata->notify_version,
++				surface_i2c_NOTIFY_BAT0_BST, &ret);
++
++	cdata->bat_charging = bat_status;
++
++	ret = surface_i2c_bix(cdata, &bix);
++	if (ret < 0)
++		return ret;
++	if (bix.last_full_charg_capacity != cdata->full_capacity)
++		surface_i2c_notify(cdata, cdata->notify_version,
++				surface_i2c_NOTIFY_BAT0_BIX, &ret);
++
++	cdata->full_capacity = bix.last_full_charg_capacity;
++
++	return 0;
++}
++
++static int surface_i2c_poll_task(void *data)
++{
++	struct surface_i2c_data *cdata = data;
++	int ret = 0;
++
++	cdata->kthread_running = true;
++
++	set_freezable();
++
++	while (!kthread_should_stop()) {
++		schedule_timeout_interruptible(POLL_INTERVAL);
++		try_to_freeze();
++		ret = surface_i2c_isr(data);
++		if (ret)
++			goto out;
++	}
++
++out:
++	cdata->kthread_running = false;
++	return ret;
++}
++
++static acpi_status
++surface_i2c_space_handler(u32 function, acpi_physical_address command,
++			u32 bits, u64 *value64,
++			void *handler_context, void *region_context)
++{
++	struct gsb_buffer *gsb = (struct gsb_buffer *)value64;
++	struct surface_i2c_handler_data *data = handler_context;
++	struct acpi_connection_info *info = &data->info;
++	struct acpi_resource_i2c_serialbus *sb;
++	struct i2c_client *client = data->client;
++	struct surface_i2c_data *cdata = i2c_get_clientdata(client);
++	struct acpi_resource *ares;
++	u32 accessor_type = function >> 16;
++	acpi_status ret;
++	int status = 1;
++
++	ret = acpi_buffer_to_resource(info->connection, info->length, &ares);
++	if (ACPI_FAILURE(ret))
++		return ret;
++
++	if (!value64 || ares->type != ACPI_RESOURCE_TYPE_SERIAL_BUS) {
++		ret = AE_BAD_PARAMETER;
++		goto err;
++	}
++
++	sb = &ares->data.i2c_serial_bus;
++	if (sb->type != ACPI_RESOURCE_SERIAL_TYPE_I2C) {
++		ret = AE_BAD_PARAMETER;
++		goto err;
++	}
++
++	if (accessor_type != ACPI_GSB_ACCESS_ATTRIB_RAW_PROCESS) {
++		ret = AE_BAD_PARAMETER;
++		goto err;
++	}
++
++	if (gsb->cmd.arg0 == surface_i2c_CMD_DEST_ADP1 &&
++	    gsb->cmd.arg1 == surface_i2c_CMD_ADP1_PSR) {
++		ret = surface_i2c_adp_psr(cdata);
++		if (ret >= 0) {
++			status = ret;
++			ret = 0;
++		}
++		goto out;
++	}
++
++	if (gsb->cmd.arg0 != surface_i2c_CMD_DEST_BAT0) {
++		ret = AE_BAD_PARAMETER;
++		goto err;
++	}
++
++	switch (gsb->cmd.arg1) {
++	case surface_i2c_CMD_BAT0_STA:
++		status = 1;
++		ret = 0;
++		break;
++	case surface_i2c_CMD_BAT0_BIX:
++		status = 1;
++		ret = surface_i2c_bix(cdata, &gsb->bix);
++		break;
++	case surface_i2c_CMD_BAT0_BTP:
++		status = 1;
++		ret = 0;
++		cdata->trip_point = gsb->cmd.arg2;
++		break;
++	case surface_i2c_CMD_BAT0_BST:
++		status = 1;
++		ret = surface_i2c_bst(cdata, &gsb->bst);
++		break;
++	default:
++		pr_info("command(0x%02x) is not supported.\n", gsb->cmd.arg1);
++		ret = AE_BAD_PARAMETER;
++		goto err;
++	}
++
++ out:
++	gsb->ret = status;
++	gsb->status = 0;
++
++ err:
++	ACPI_FREE(ares);
++	return ret;
++}
++
++static int surface_i2c_install_space_handler(struct i2c_client *client)
++{
++	acpi_handle handle;
++	struct surface_i2c_handler_data *data;
++	acpi_status status;
++
++	handle = ACPI_HANDLE(&client->dev);
++
++	if (!handle)
++		return -ENODEV;
++
++	data = kzalloc(sizeof(struct surface_i2c_handler_data),
++			    GFP_KERNEL);
++	if (!data)
++		return -ENOMEM;
++
++	data->client = client;
++	status = acpi_bus_attach_private_data(handle, (void *)data);
++	if (ACPI_FAILURE(status)) {
++		kfree(data);
++		return -ENOMEM;
++	}
++
++	status = acpi_install_address_space_handler(handle,
++				ACPI_ADR_SPACE_GSBUS,
++				&surface_i2c_space_handler,
++				NULL,
++				data);
++	if (ACPI_FAILURE(status)) {
++		dev_err(&client->dev, "Error installing i2c space handler\n");
++		acpi_bus_detach_private_data(handle);
++		kfree(data);
++		return -ENOMEM;
++	}
++
++	acpi_walk_dep_device_list(handle);
++	return 0;
++}
++
++static void surface_i2c_remove_space_handler(struct i2c_client *client)
++{
++	acpi_handle handle;
++	struct surface_i2c_handler_data *data;
++	acpi_status status;
++
++	handle = ACPI_HANDLE(&client->dev);
++
++	if (!handle)
++		return;
++
++	acpi_remove_address_space_handler(handle,
++				ACPI_ADR_SPACE_GSBUS,
++				&surface_i2c_space_handler);
++
++	status = acpi_bus_get_private_data(handle, (void **)&data);
++	if (ACPI_SUCCESS(status))
++		kfree(data);
++
++	acpi_bus_detach_private_data(handle);
++}
++
++static int acpi_find_i2c(struct acpi_resource *ares, void *data)
++{
++	struct surface_i2c_lookup *lookup = data;
++
++	if (ares->type != ACPI_RESOURCE_TYPE_SERIAL_BUS)
++		return 1;
++
++	if (lookup->n++ == lookup->index && !lookup->addr)
++		lookup->addr = ares->data.i2c_serial_bus.slave_address;
++
++	return 1;
++}
++
++static int surface_i2c_resource_lookup(struct surface_i2c_data *cdata,
++					unsigned int index)
++{
++	struct i2c_client *client = cdata->adp1;
++	struct acpi_device *adev = ACPI_COMPANION(&client->dev);
++	struct surface_i2c_lookup lookup = {
++		.cdata = cdata,
++		.index = index,
++	};
++	struct list_head res_list;
++	int ret;
++
++	INIT_LIST_HEAD(&res_list);
++
++	ret = acpi_dev_get_resources(adev, &res_list, acpi_find_i2c, &lookup);
++	if (ret < 0)
++		return ret;
++
++	acpi_dev_free_resource_list(&res_list);
++
++	if (!lookup.addr)
++		return -ENOENT;
++
++	return lookup.addr;
++}
++
++static void surface_i2c_dump_registers(struct i2c_client *client,
++				    struct i2c_client *bat0)
++{
++	char rd_buf[60];
++	int error, i, c;
++	char buff[17 * 3 * 2] = {0};
++
++	dev_info(&client->dev, "dumping registers 0x00 to 0x7F:\n");
++
++	for (i = 0; i < 0x80; i += 0x20) {
++		memset(rd_buf, 0, sizeof(rd_buf));
++		error = surface_i2c_read_block(bat0, i, rd_buf, 0x20);
++		dev_info(&client->dev, " read 0x%02x: %*ph|%*ph\n",
++			 i,
++			 0x10, rd_buf,
++			 0x10, rd_buf + 0x10);
++		for (c = 0; c < 0x20; c++) {
++			if (rd_buf[c] >= 0x20 && rd_buf[c] <= 0x7e) {
++				buff[c * 3 + 0] = ' ';
++				buff[c * 3 + 1] = rd_buf[c];
++			} else {
++				buff[c * 3 + 0] = '-';
++				buff[c * 3 + 1] = '-';
++			}
++			buff[c * 3 + 2] = (c + 1) % 0x10 ? ' ' : '|';
++		}
++		buff[0x1f * 3 + 2] = '\0';
++		dev_info(&client->dev, "ascii 0x%02x: %s\n", i, buff);
++	}
++}
++
++static int surface_i2c_probe(struct i2c_client *client)
++{
++	struct device *dev = &client->dev;
++	struct i2c_client *bat0;
++	struct surface_i2c_data *data;
++	int error, version, addr;
++
++	pr_info("surface_i2c: Probing for surface i2c device...\n");
++
++	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
++	if (!data)
++		return -ENOMEM;
++
++	data->adp1 = client;
++	i2c_set_clientdata(client, data);
++
++	addr = surface_i2c_resource_lookup(data, 1);
++	if (addr < 0)
++		return addr;
++
++	bat0 = i2c_new_dummy(client->adapter, addr);
++	if (!bat0)
++		return -ENOMEM;
++
++	data->bat0 = bat0;
++	i2c_set_clientdata(bat0, data);
++
++	// debugging
++	surface_i2c_dump_registers(client, bat0);
++
++	pr_info("surface_i2c: Attaching device MSHW0124...");
++
++	error = surface_i2c_notify(data, 1, surface_i2c_NOTIFY_GET_VERSION, &version);
++	if (error)
++		goto out_err;
++
++	data->notify_version = version == surface_i2c_EV_2_5;
++
++	data->poll_task = kthread_run(surface_i2c_poll_task, data, "surface_i2c_adp");
++	if (IS_ERR(data->poll_task)) {
++		error = PTR_ERR(data->poll_task);
++		dev_err(&client->dev, "Unable to run kthread err %d\n", error);
++		goto out_err;
++	}
++
++	//error = surface_i2c_install_space_handler(client);
++	//if (error)
++	//	goto out_err;
++
++	return 0;
++
++out_err:
++	if (data->kthread_running)
++		kthread_stop(data->poll_task);
++	i2c_unregister_device(data->bat0);
++	return error;
++}
++
++static int surface_i2c_remove(struct i2c_client *client)
++{
++	struct surface_i2c_data *cdata = i2c_get_clientdata(client);
++
++	surface_i2c_remove_space_handler(client);
++
++	if (cdata->kthread_running)
++		kthread_stop(cdata->poll_task);
++
++	i2c_unregister_device(cdata->bat0);
++
++	return 0;
++}
++
++int surface_i2c_detect(struct i2c_client* client, struct i2c_board_info* board_info)
++{
++    pr_info("surface_i2c: Detecting surface_i2c device...");
++    return 0;
++}
++
++static const struct acpi_device_id surface_i2c_acpi_match[] = {
++	{ "MSHW0124", 0 },
++	{ "", 0 }
++};
++MODULE_DEVICE_TABLE(acpi, surface_i2c_acpi_match);
++
++static const struct i2c_device_id surface_i2c_id[] = {
++	{ "MSHW0124:00", 0 },
++	{ "MSHW0124:01", 0 },
++	{ "", 0 }
++};
++MODULE_DEVICE_TABLE(i2c, surface_i2c_id);
++
++static struct i2c_driver surface_i2c_driver = {
++	.probe_new = surface_i2c_probe,
++	.remove = surface_i2c_remove,
++	.detect = surface_i2c_detect,
++	.id_table = surface_i2c_id,
++	.driver = {
++		.name = "surface_i2c",
++		.acpi_match_table = ACPI_PTR(surface_i2c_acpi_match),
++	},
++};
++module_i2c_driver(surface_i2c_driver);
++
++MODULE_AUTHOR("Jake Day");
++MODULE_DESCRIPTION("Microsoft Surface I2C Driver");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/platform/x86/surface_platform.c b/drivers/platform/x86/surface_platform.c
+new file mode 100644
+index 000000000000..7a84340b04bb
+--- /dev/null
++++ b/drivers/platform/x86/surface_platform.c
+@@ -0,0 +1,67 @@
++/*
++ *  surface_platform.c - Microsoft Surface Platform Driver
++ *
++ *  This program is free software; you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License as published by
++ *  the Free Software Foundation; either version 2 of the License, or
++ *  (at your option) any later version.
++ *
++ *  This program is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  The full GNU General Public License is included in this distribution in
++ *  the file called "COPYING".
++ */
++
++#include <linux/acpi.h>
++#include <linux/gpio/consumer.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/moduleparam.h>
++#include <linux/platform_device.h>
++#include <linux/power_supply.h>
++#include <linux/thermal.h>
++#include <linux/uuid.h>
++#include <linux/workqueue.h>
++
++#include <asm/unaligned.h>
++
++struct surface_platform_data {
++	struct device *dev;
++};
++
++static int surface_platform_probe(struct platform_device *pdev)
++{
++	struct surface_platform_data *pdata;
++
++	platform_set_drvdata(pdev, pdata);
++	return 0;
++}
++
++static int surface_platform_remove(struct platform_device *pdev)
++{
++	struct surface_platform_data *pdata = platform_get_drvdata(pdev);
++}
++
++static const struct acpi_device_id surface_platform_acpi_match[] = {
++	{ "MSHW0091", 0 },
++	{ "INT3403", 0 },
++	{ "", 0 }
++};
++MODULE_DEVICE_TABLE(acpi, surface_platform_acpi_match);
++
++static struct platform_driver surface_platform_driver = {
++	.probe = surface_platform_probe,
++	.remove = surface_platform_remove,
++	.driver = {
++		.name = "surface_platform",
++		.acpi_match_table = ACPI_PTR(surface_platform_acpi_match),
++	},
++};
++module_platform_driver(surface_platform_driver);
++
++MODULE_AUTHOR("Jake Day");
++MODULE_DESCRIPTION("Microsoft Surface Platform Driver");
++MODULE_LICENSE("GPL");

+ 298 - 0
patches/4.18/buttons.patch

@@ -0,0 +1,298 @@
+diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
+index 2025f56446a0..97e612baa892 100644
+--- a/drivers/platform/x86/Kconfig
++++ b/drivers/platform/x86/Kconfig
+@@ -1158,6 +1158,11 @@ config SURFACE_3_BUTTON
+ 	---help---
+ 	  This driver handles the power/home/volume buttons on the Microsoft Surface 3 tablet.
+ 
++config SURFACEBOOK2_BUTTON
++	tristate "Power/home/volume buttons driver for Microsoft Surface Book 2/ Surface Pro (2017) tablet"
++	---help---
++	  This driver handles the power and volume buttons on the Microsoft Surface Book 2/ Surface Pro (2017) tablet.
++
+ config ACPI_SURFACE
+ 	tristate "Microsoft Surface Extras"
+ 	depends on ACPI
+diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
+index 8fd5b93bb20d..28c4cede2d91 100644
+--- a/drivers/platform/x86/Makefile
++++ b/drivers/platform/x86/Makefile
+@@ -81,6 +81,7 @@ obj-$(CONFIG_INTEL_PMC_IPC)	+= intel_pmc_ipc.o
+ obj-$(CONFIG_SILEAD_DMI)	+= silead_dmi.o
+ obj-$(CONFIG_SURFACE_PRO3_BUTTON)	+= surfacepro3_button.o
+ obj-$(CONFIG_SURFACE_3_BUTTON)	+= surface3_button.o
++obj-$(CONFIG_SURFACEBOOK2_BUTTON) += surfacebook2_button.o
+ obj-$(CONFIG_ACPI_SURFACE)	+= surface_acpi.o
+ obj-$(CONFIG_ACPI_SURFACE)	+= surface_i2c.o
+ obj-$(CONFIG_ACPI_SURFACE)	+= surface_platform.o
+diff --git a/drivers/platform/x86/surfacebook2_button.c b/drivers/platform/x86/surfacebook2_button.c
+new file mode 100644
+index 000000000000..a6b7de595090
+--- /dev/null
++++ b/drivers/platform/x86/surfacebook2_button.c
+@@ -0,0 +1,242 @@
++/*
++ * Supports for Surface Book 2 and Surface Pro (2017) power and volume
++ * buttons.
++ *
++ * Based on soc_button_array.c:
++ *
++ * (C) Copyright 2014 Intel Corporation
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; version 2
++ * of the License.
++ */
++
++#include <linux/module.h>
++#include <linux/input.h>
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/acpi.h>
++#include <linux/gpio/consumer.h>
++#include <linux/gpio_keys.h>
++#include <linux/gpio.h>
++#include <linux/platform_device.h>
++
++struct soc_button_info {
++	const char *name;
++	int acpi_index;
++	unsigned int event_type;
++	unsigned int event_code;
++	bool autorepeat;
++	bool wakeup;
++};
++
++/*
++ * Some of the buttons like volume up/down are auto repeat, while others
++ * are not. To support both, we register two platform devices, and put
++ * buttons into them based on whether the key should be auto repeat.
++ */
++#define BUTTON_TYPES			2
++#define SURFACE_METHOD_DSM		"_DSM"
++
++struct soc_button_data {
++	struct platform_device *children[BUTTON_TYPES];
++};
++
++/*
++ * Get the Nth GPIO number from the ACPI object.
++ */
++static int soc_button_lookup_gpio(struct device *dev, int acpi_index)
++{
++	struct gpio_desc *desc;
++	int gpio;
++
++	desc = gpiod_get_index(dev, NULL, acpi_index, GPIOD_ASIS);
++	if (IS_ERR(desc))
++		return PTR_ERR(desc);
++
++	gpio = desc_to_gpio(desc);
++
++	gpiod_put(desc);
++
++	return gpio;
++}
++
++static struct platform_device *
++soc_button_device_create(struct platform_device *pdev,
++			 const struct soc_button_info *button_info,
++			 bool autorepeat)
++{
++	const struct soc_button_info *info;
++	struct platform_device *pd;
++	struct gpio_keys_button *gpio_keys;
++	struct gpio_keys_platform_data *gpio_keys_pdata;
++	int n_buttons = 0;
++	int gpio;
++	int error;
++
++	for (info = button_info; info->name; info++)
++		if (info->autorepeat == autorepeat)
++			n_buttons++;
++
++	gpio_keys_pdata = devm_kzalloc(&pdev->dev,
++				       sizeof(*gpio_keys_pdata) +
++					sizeof(*gpio_keys) * n_buttons,
++				       GFP_KERNEL);
++	if (!gpio_keys_pdata)
++		return ERR_PTR(-ENOMEM);
++
++	gpio_keys = (void *)(gpio_keys_pdata + 1);
++	n_buttons = 0;
++
++	for (info = button_info; info->name; info++) {
++		if (info->autorepeat != autorepeat)
++			continue;
++
++		gpio = soc_button_lookup_gpio(&pdev->dev, info->acpi_index);
++		if (!gpio_is_valid(gpio))
++			continue;
++
++		gpio_keys[n_buttons].type = info->event_type;
++		gpio_keys[n_buttons].code = info->event_code;
++		gpio_keys[n_buttons].gpio = gpio;
++		gpio_keys[n_buttons].active_low = 1;
++		gpio_keys[n_buttons].desc = info->name;
++		gpio_keys[n_buttons].wakeup = info->wakeup;
++		/* These devices often use cheap buttons, use 50 ms debounce */
++		gpio_keys[n_buttons].debounce_interval = 50;
++		n_buttons++;
++	}
++
++	if (n_buttons == 0) {
++		error = -ENODEV;
++		goto err_free_mem;
++	}
++
++	gpio_keys_pdata->buttons = gpio_keys;
++	gpio_keys_pdata->nbuttons = n_buttons;
++	gpio_keys_pdata->rep = autorepeat;
++
++	pd = platform_device_alloc("gpio-keys", PLATFORM_DEVID_AUTO);
++	if (!pd) {
++		error = -ENOMEM;
++		goto err_free_mem;
++	}
++
++	error = platform_device_add_data(pd, gpio_keys_pdata,
++					 sizeof(*gpio_keys_pdata));
++	if (error)
++		goto err_free_pdev;
++
++	error = platform_device_add(pd);
++	if (error)
++		goto err_free_pdev;
++
++	return pd;
++
++err_free_pdev:
++	platform_device_put(pd);
++err_free_mem:
++	devm_kfree(&pdev->dev, gpio_keys_pdata);
++	return ERR_PTR(error);
++}
++
++static int soc_button_remove(struct platform_device *pdev)
++{
++	struct soc_button_data *priv = platform_get_drvdata(pdev);
++
++	int i;
++
++	for (i = 0; i < BUTTON_TYPES; i++)
++		if (priv->children[i])
++			platform_device_unregister(priv->children[i]);
++
++	return 0;
++}
++
++static int soc_button_probe(struct platform_device *pdev)
++{
++	struct device *dev = &pdev->dev;
++	const struct acpi_device_id *id;
++	struct soc_button_info *button_info;
++	struct soc_button_data *priv;
++	struct platform_device *pd;
++	int i;
++	int error;
++
++	id = acpi_match_device(dev->driver->acpi_match_table, dev);
++	if (!id)
++		return -ENODEV;
++
++	if (!acpi_has_method(ACPI_HANDLE(dev), SURFACE_METHOD_DSM))
++		return -ENODEV;
++
++	button_info = (struct soc_button_info *)id->driver_data;
++
++	error = gpiod_count(dev, NULL);
++	if (error < 0) {
++		dev_dbg(dev, "no GPIO attached, ignoring...\n");
++		return -ENODEV;
++	}
++
++	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
++	if (!priv)
++		return -ENOMEM;
++
++	platform_set_drvdata(pdev, priv);
++
++	for (i = 0; i < BUTTON_TYPES; i++) {
++		pd = soc_button_device_create(pdev, button_info, i == 0);
++		if (IS_ERR(pd)) {
++			error = PTR_ERR(pd);
++			if (error != -ENODEV) {
++				soc_button_remove(pdev);
++				return error;
++			}
++			continue;
++		}
++
++		priv->children[i] = pd;
++	}
++
++	if (!priv->children[0] && !priv->children[1])
++		return -ENODEV;
++
++	if (!id->driver_data)
++		devm_kfree(dev, button_info);
++
++	return 0;
++}
++
++/*
++ * Definition of buttons on the tablet. The ACPI index of each button
++ * is defined in section 2.8.7.2 of "Windows ACPI Design Guide for SoC
++ * Platforms"
++ */
++static struct soc_button_info soc_button_MSHW0040[] = {
++	{ "power",       0, EV_KEY, KEY_POWER,      false, true  },
++	{ "volume_up",   2, EV_KEY, KEY_VOLUMEUP,   true,  false },
++	{ "volume_down", 4, EV_KEY, KEY_VOLUMEDOWN, true,  false },
++	{ }
++};
++
++static const struct acpi_device_id soc_button_acpi_match[] = {
++	{ "MSHW0040", (unsigned long)soc_button_MSHW0040 },
++	{ }
++};
++
++MODULE_DEVICE_TABLE(acpi, soc_button_acpi_match);
++
++static struct platform_driver soc_button_driver_sb2 = {
++	.probe		= soc_button_probe,
++	.remove		= soc_button_remove,
++	.driver		= {
++		.name = "surfacebook2_button",
++		.acpi_match_table = ACPI_PTR(soc_button_acpi_match),
++	},
++};
++module_platform_driver(soc_button_driver_sb2);
++
++MODULE_AUTHOR("Maximilian Luz");
++MODULE_DESCRIPTION("Surface Book 2/Surface Pro (2017) Button Driver");
++MODULE_LICENSE("GPL v2");
+diff --git a/drivers/platform/x86/surfacepro3_button.c b/drivers/platform/x86/surfacepro3_button.c
+index 1b491690ce07..9385262b65be 100644
+--- a/drivers/platform/x86/surfacepro3_button.c
++++ b/drivers/platform/x86/surfacepro3_button.c
+@@ -22,6 +22,7 @@
+ #define SURFACE_PRO3_BUTTON_HID		"MSHW0028"
+ #define SURFACE_PRO4_BUTTON_HID		"MSHW0040"
+ #define SURFACE_BUTTON_OBJ_NAME		"VGBI"
++#define SURFACE_METHOD_DSM			"_DSM"
+ #define SURFACE_BUTTON_DEVICE_NAME	"Surface Pro 3/4 Buttons"
+ 
+ #define SURFACE_BUTTON_NOTIFY_TABLET_MODE	0xc8
+@@ -158,6 +159,9 @@ static int surface_button_add(struct acpi_device *device)
+ 	    strlen(SURFACE_BUTTON_OBJ_NAME)))
+ 		return -ENODEV;
+ 
++	if (acpi_has_method(device->handle, SURFACE_METHOD_DSM))
++		return -ENODEV;
++
+ 	button = kzalloc(sizeof(struct surface_button), GFP_KERNEL);
+ 	if (!button)
+ 		return -ENOMEM;

+ 2730 - 0
patches/4.18/cameras.patch

@@ -0,0 +1,2730 @@
+diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c
+index 8e138201330f..db38a76af80b 100644
+--- a/drivers/media/usb/uvc/uvc_driver.c
++++ b/drivers/media/usb/uvc/uvc_driver.c
+@@ -2347,6 +2347,46 @@ static const struct uvc_device_info uvc_quirk_force_y8 = {
+  * though they are compliant.
+  */
+ static const struct usb_device_id uvc_ids[] = {
++	/* Microsoft Surface Pro 3 Front */
++	{ .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
++				| USB_DEVICE_ID_MATCH_INT_INFO,
++	  .idVendor             = 0x045e,
++	  .idProduct            = 0x07be,
++	  .bInterfaceClass      = USB_CLASS_VIDEO,
++	  .bInterfaceSubClass   = 1,
++	  .bInterfaceProtocol   = 1 },
++	/* Microsoft Surface Pro 3 Rear */
++	{ .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
++				| USB_DEVICE_ID_MATCH_INT_INFO,
++	  .idVendor             = 0x045e,
++	  .idProduct            = 0x07bf,
++	  .bInterfaceClass      = USB_CLASS_VIDEO,
++	  .bInterfaceSubClass   = 1,
++	  .bInterfaceProtocol   = 1 },
++	/* Microsoft Surface Pro 4 Cam */
++	{ .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
++				| USB_DEVICE_ID_MATCH_INT_INFO,
++	  .idVendor             = 0x045e,
++	  .idProduct            = 0x090c,
++	  .bInterfaceClass      = USB_CLASS_VIDEO,
++	  .bInterfaceSubClass   = 1,
++	  .bInterfaceProtocol   = 1 },
++	/* Microsoft Surface Book Cam 1 */
++	{ .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
++				| USB_DEVICE_ID_MATCH_INT_INFO,
++	  .idVendor             = 0x045e,
++	  .idProduct            = 0x090b,
++	  .bInterfaceClass      = USB_CLASS_VIDEO,
++	  .bInterfaceSubClass   = 1,
++	  .bInterfaceProtocol   = 1 },
++	/* Microsoft Surface Book Cam 2 */
++	{ .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
++				| USB_DEVICE_ID_MATCH_INT_INFO,
++	  .idVendor             = 0x045e,
++	  .idProduct            = 0x091a,
++	  .bInterfaceClass      = USB_CLASS_VIDEO,
++	  .bInterfaceSubClass   = 1,
++	  .bInterfaceProtocol   = 1 },
+ 	/* LogiLink Wireless Webcam */
+ 	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE
+ 				| USB_DEVICE_ID_MATCH_INT_INFO,
+diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
+index e84959a8a684..6a78734cfc5a 100644
+--- a/drivers/staging/Makefile
++++ b/drivers/staging/Makefile
+@@ -54,3 +54,4 @@ obj-$(CONFIG_SOC_MT7621)	+= mt7621-dma/
+ obj-$(CONFIG_SOC_MT7621)	+= mt7621-mmc/
+ obj-$(CONFIG_SOC_MT7621)	+= mt7621-eth/
+ obj-$(CONFIG_SOC_MT7621)	+= mt7621-dts/
++obj-$(CONFIG_VIDEO_OV5693)	+= ov5693/
+diff --git a/drivers/staging/ov5693/Kconfig b/drivers/staging/ov5693/Kconfig
+new file mode 100644
+index 000000000000..9fb1bffbe9b3
+--- /dev/null
++++ b/drivers/staging/ov5693/Kconfig
+@@ -0,0 +1,11 @@
++config VIDEO_OV5693
++       tristate "Omnivision ov5693 sensor support"
++       depends on I2C && VIDEO_V4L2
++       ---help---
++         This is a Video4Linux2 sensor-level driver for the Micron
++         ov5693 5 Mpixel camera.
++
++         ov5693 is video camera sensor.
++
++         It currently only works with the atomisp driver.
++
+diff --git a/drivers/staging/ov5693/Makefile b/drivers/staging/ov5693/Makefile
+new file mode 100644
+index 000000000000..d8a63faa591f
+--- /dev/null
++++ b/drivers/staging/ov5693/Makefile
+@@ -0,0 +1,5 @@
++obj-$(CONFIG_VIDEO_OV5693) += ov569x.o
++
++ov569x-objs := ov5693.o ad5823.o
++
++ccflags-y += -Werror
+diff --git a/drivers/staging/ov5693/ad5823.c b/drivers/staging/ov5693/ad5823.c
+new file mode 100644
+index 000000000000..fcb9f5b70f9f
+--- /dev/null
++++ b/drivers/staging/ov5693/ad5823.c
+@@ -0,0 +1,219 @@
++#include <asm/intel-mid.h>
++#include <linux/bitops.h>
++#include <linux/device.h>
++#include <linux/delay.h>
++#include <linux/errno.h>
++#include <linux/fs.h>
++#include <linux/gpio.h>
++#include <linux/init.h>
++#include <linux/i2c.h>
++#include <linux/io.h>
++#include <linux/kernel.h>
++#include <linux/kmod.h>
++#include <linux/mm.h>
++#include <linux/module.h>
++#include <linux/moduleparam.h>
++#include <linux/string.h>
++#include <linux/slab.h>
++#include <linux/types.h>
++#include <media/v4l2-chip-ident.h>
++#include <media/v4l2-device.h>
++
++#include "ad5823.h"
++
++static struct ad5823_device ad5823_dev;
++static int ad5823_i2c_write(struct i2c_client *client, u8 reg, u8 val)
++{
++	struct i2c_msg msg;
++	u8 buf[2];
++	buf[0] = reg;
++	buf[1] = val;
++	msg.addr = AD5823_VCM_ADDR;
++	msg.flags = 0;
++	msg.len = AD5823_8BIT;
++	msg.buf = &buf[0];
++
++	if (i2c_transfer(client->adapter, &msg, 1) != 1)
++		return -EIO;
++	return 0;
++}
++
++static int ad5823_i2c_read(struct i2c_client *client, u8 reg, u8 *val)
++{
++	struct i2c_msg msg[2];
++	u8 buf[2];
++	buf[0] = reg;
++	buf[1] = 0;
++
++	msg[0].addr = AD5823_VCM_ADDR;
++	msg[0].flags = 0;
++	msg[0].len = AD5823_8BIT;
++	msg[0].buf = &buf[0];
++
++	msg[1].addr = AD5823_VCM_ADDR;
++	msg[1].flags = I2C_M_RD;
++	msg[1].len = AD5823_8BIT;
++	msg[1].buf = &buf[1];
++	*val = 0;
++	if (i2c_transfer(client->adapter, msg, 2) != 2)
++		return -EIO;
++	*val = buf[1];
++	return 0;
++}
++
++int ad5823_vcm_power_up(struct v4l2_subdev *sd)
++{
++	int ret = -ENODEV;
++
++	/* Enable power */
++	if (ad5823_dev.platform_data)
++		ret = ad5823_dev.platform_data->power_ctrl(sd, 1);
++	/*
++	 * waiting time requested by AD5823(vcm)
++	 */
++	usleep_range(1000, 2000);
++	return ret;
++}
++
++int ad5823_vcm_power_down(struct v4l2_subdev *sd)
++{
++	int ret = -ENODEV;
++
++	if (ad5823_dev.platform_data)
++		ret = ad5823_dev.platform_data->power_ctrl(sd, 0);
++
++	return ret;
++}
++
++
++int ad5823_t_focus_vcm(struct v4l2_subdev *sd, u16 val)
++{
++	struct i2c_client *client = v4l2_get_subdevdata(sd);
++	int ret = -EINVAL;
++	u8 vcm_code;
++	u8 vcm_mode_reg_val[4] = {
++		AD5823_ARC_RES0,
++		AD5823_ARC_RES1,
++		AD5823_ARC_RES2,
++		AD5823_ESRC
++	};
++
++	if (ad5823_dev.vcm_mode != AD5823_DIRECT) {
++		ret = ad5823_i2c_write(client, AD5823_REG_VCM_CODE_MSB,
++						AD5823_RING_CTRL_ENABLE);
++		if (ret)
++			return ret;
++
++		ret = ad5823_i2c_write(client, AD5823_REG_MODE,
++					vcm_mode_reg_val[ad5823_dev.vcm_mode]);
++		if (ret)
++			return ret;
++	} else {
++		ret = ad5823_i2c_write(client, AD5823_REG_VCM_CODE_MSB,
++						AD5823_RING_CTRL_DISABLE);
++		if (ret)
++			return ret;
++	}
++
++	ret = ad5823_i2c_read(client, AD5823_REG_VCM_CODE_MSB, &vcm_code);
++	if (ret)
++		return ret;
++
++	/* set reg VCM_CODE_MSB Bit[1:0] */
++	vcm_code = (vcm_code & VCM_CODE_MSB_MASK) | ((val >> 8) & ~VCM_CODE_MSB_MASK);
++	ret = ad5823_i2c_write(client, AD5823_REG_VCM_CODE_MSB, vcm_code);
++	if (ret)
++		return ret;
++
++	/* set reg VCM_CODE_LSB Bit[7:0] */
++	ret = ad5823_i2c_write(client, AD5823_REG_VCM_CODE_LSB,
++							(val & 0x0f));
++	if (ret)
++		return ret;
++
++	/* set required vcm move time */
++	vcm_code = AD5823_RESONANCE_PERIOD / AD5823_RESONANCE_COEF
++		   - AD5823_HIGH_FREQ_RANGE;
++	ret = ad5823_i2c_write(client, AD5823_REG_VCM_MOVE_TIME, vcm_code);
++
++	return ret;
++}
++
++int ad5823_t_focus_abs(struct v4l2_subdev *sd, s32 value)
++{
++	int ret;
++
++	value = min(value, AD5823_MAX_FOCUS_POS);
++	ret = ad5823_t_focus_vcm(sd, AD5823_MAX_FOCUS_POS - value);
++	if (ret == 0) {
++		ad5823_dev.number_of_steps = value - ad5823_dev.focus;
++		ad5823_dev.focus = value;
++		ktime_get_ts(&ad5823_dev.timestamp_t_focus_abs);
++	}
++
++	return ret;
++}
++
++int ad5823_t_focus_rel(struct v4l2_subdev *sd, s32 value)
++{
++	return ad5823_t_focus_abs(sd, ad5823_dev.focus + value);
++}
++
++int ad5823_q_focus_status(struct v4l2_subdev *sd, s32 *value)
++{
++	u32 status = 0;
++	struct timespec temptime;
++	const struct timespec timedelay = {
++		0,
++		min_t(u32, abs(ad5823_dev.number_of_steps)*DELAY_PER_STEP_NS,
++			DELAY_MAX_PER_STEP_NS),
++	};
++
++	ktime_get_ts(&temptime);
++
++	temptime = timespec_sub(temptime, (ad5823_dev.timestamp_t_focus_abs));
++
++	if (timespec_compare(&temptime, &timedelay) <= 0)
++		status = ATOMISP_FOCUS_STATUS_MOVING
++			| ATOMISP_FOCUS_HP_IN_PROGRESS;
++	else
++		status = ATOMISP_FOCUS_STATUS_ACCEPTS_NEW_MOVE
++			| ATOMISP_FOCUS_HP_COMPLETE;
++
++	*value = status;
++
++	return 0;
++}
++
++int ad5823_q_focus_abs(struct v4l2_subdev *sd, s32 *value)
++{
++	s32 val;
++
++	ad5823_q_focus_status(sd, &val);
++
++	if (val & ATOMISP_FOCUS_STATUS_MOVING)
++		*value  = ad5823_dev.focus - ad5823_dev.number_of_steps;
++	else
++		*value  = ad5823_dev.focus ;
++
++	return 0;
++}
++
++int ad5823_t_vcm_slew(struct v4l2_subdev *sd, s32 value)
++{
++	return 0;
++}
++
++int ad5823_t_vcm_timing(struct v4l2_subdev *sd, s32 value)
++{
++	return 0;
++}
++
++int ad5823_vcm_init(struct v4l2_subdev *sd)
++{
++	/* set vcm mode to ARC RES0.5 */
++	ad5823_dev.vcm_mode = AD5823_ARC_RES1;
++	ad5823_dev.platform_data = camera_get_af_platform_data();
++	return ad5823_dev.platform_data ? 0 : -ENODEV;
++}
++
+diff --git a/drivers/staging/ov5693/ad5823.h b/drivers/staging/ov5693/ad5823.h
+new file mode 100644
+index 000000000000..8b046c31f3af
+--- /dev/null
++++ b/drivers/staging/ov5693/ad5823.h
+@@ -0,0 +1,90 @@
++/*
++ * Support for AD5823 VCM.
++ *
++ * Copyright (c) 2013 Intel Corporation. All Rights Reserved.
++ *
++ * 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.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
++ * 02110-1301, USA.
++ *
++ */
++
++#ifndef __AD5823_H__
++#define __AD5823_H__
++
++#include <linux/atomisp_platform.h>
++#include <linux/types.h>
++
++
++#define AD5823_VCM_ADDR	0x0c
++
++#define AD5823_REG_RESET		0x01
++#define AD5823_REG_MODE			0x02
++#define AD5823_REG_VCM_MOVE_TIME	0x03
++#define AD5823_REG_VCM_CODE_MSB		0x04
++#define AD5823_REG_VCM_CODE_LSB		0x05
++#define AD5823_REG_VCM_THRESHOLD_MSB	0x06
++#define AD5823_REG_VCM_THRESHOLD_LSB	0x07
++
++#define AD5823_RING_CTRL_ENABLE		0x04
++#define AD5823_RING_CTRL_DISABLE	0x00
++
++#define AD5823_RESONANCE_PERIOD		100000
++#define AD5823_RESONANCE_COEF		512
++#define AD5823_HIGH_FREQ_RANGE		0x80
++
++#define VCM_CODE_MSB_MASK		0xfc
++
++enum ad5823_tok_type {
++	AD5823_8BIT  = 0x0001,
++	AD5823_16BIT = 0x0002,
++};
++
++enum ad5823_vcm_mode {
++	AD5823_ARC_RES0 = 0x0,	/* Actuator response control RES1 */
++	AD5823_ARC_RES1 = 0x1,	/* Actuator response control RES0.5 */
++	AD5823_ARC_RES2 = 0x2,	/* Actuator response control RES2 */
++	AD5823_ESRC = 0x3,	/* Enhanced slew rate control */
++	AD5823_DIRECT = 0x4,	/* Direct control */
++};
++
++/* ad5823 device structure */
++struct ad5823_device {
++	struct timespec timestamp_t_focus_abs;
++	enum ad5823_vcm_mode vcm_mode;
++	s16 number_of_steps;
++	bool initialized;		/* true if ad5823 is detected */
++	s32 focus;			/* Current focus value */
++	struct timespec focus_time;	/* Time when focus was last time set */
++	__u8 buffer[4];			/* Used for i2c transactions */
++	const struct camera_af_platform_data *platform_data;
++};
++
++#define AD5823_INVALID_CONFIG	0xffffffff
++#define AD5823_MAX_FOCUS_POS	1023
++
++
++#define DELAY_PER_STEP_NS	1000000
++#define DELAY_MAX_PER_STEP_NS	(1000000 * 1023)
++
++int ad5823_vcm_power_up(struct v4l2_subdev *sd);
++int ad5823_vcm_power_down(struct v4l2_subdev *sd);
++int ad5823_vcm_init(struct v4l2_subdev *sd);
++
++int ad5823_t_focus_vcm(struct v4l2_subdev *sd, u16 val);
++int ad5823_t_focus_abs(struct v4l2_subdev *sd, s32 value);
++int ad5823_t_focus_rel(struct v4l2_subdev *sd, s32 value);
++int ad5823_q_focus_status(struct v4l2_subdev *sd, s32 *value);
++int ad5823_q_focus_abs(struct v4l2_subdev *sd, s32 *value);
++
++#endif
+diff --git a/drivers/staging/ov5693/ov5693.c b/drivers/staging/ov5693/ov5693.c
+new file mode 100644
+index 000000000000..51d218da3722
+--- /dev/null
++++ b/drivers/staging/ov5693/ov5693.c
+@@ -0,0 +1,1461 @@
++/*
++ * Support for OmniVision OV5693 5M HD camera sensor.
++ *
++ * Copyright (c) 2013 Intel Corporation. All Rights Reserved.
++ *
++ * 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.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
++ * 02110-1301, USA.
++ *
++ */
++
++#include <linux/device.h>
++#include <linux/delay.h>
++#include <linux/errno.h>
++#include <linux/gpio.h>
++#include <linux/init.h>
++#include <linux/i2c.h>
++#include <linux/io.h>
++#include <linux/kernel.h>
++#include <linux/kmod.h>
++#include <linux/module.h>
++#include <linux/mm.h>
++#include <linux/moduleparam.h>
++#include <linux/string.h>
++#include <linux/slab.h>
++#include <linux/types.h>
++#include <media/v4l2-device.h>
++#include <media/v4l2-chip-ident.h>
++
++#include "ov5693.h"
++
++/* i2c read/write stuff */
++static int ov5693_read_reg(struct i2c_client *client,
++			   u16 data_length, u16 reg, u16 *val)
++{
++	int err;
++	struct i2c_msg msg[2];
++	unsigned char data[6];
++
++	if (!client->adapter) {
++		dev_err(&client->dev, "%s error, no client->adapter\n",
++			__func__);
++		return -ENODEV;
++	}
++
++	if (data_length != OV5693_8BIT && data_length != OV5693_16BIT
++					&& data_length != OV5693_32BIT) {
++		dev_err(&client->dev, "%s error, invalid data length\n",
++			__func__);
++		return -EINVAL;
++	}
++
++	memset(msg, 0 , sizeof(msg));
++
++	msg[0].addr = client->addr;
++	msg[0].flags = 0;
++	msg[0].len = I2C_MSG_LENGTH;
++	msg[0].buf = data;
++
++	/* high byte goes out first */
++	data[0] = (u8)(reg >> 8);
++	data[1] = (u8)(reg & 0xff);
++
++	msg[1].addr = client->addr;
++	msg[1].len = data_length;
++	msg[1].flags = I2C_M_RD;
++	msg[1].buf = data;
++
++	err = i2c_transfer(client->adapter, msg, 2);
++	if (err != 2) {
++		if (err >= 0)
++			err = -EIO;
++		dev_err(&client->dev,
++			"read from offset 0x%x error %d", reg, err);
++		return err;
++	}
++
++	*val = 0;
++	/* high byte comes first */
++	if (data_length == OV5693_8BIT)
++		*val = (u8)data[0];
++	else if (data_length == OV5693_16BIT)
++		*val = be16_to_cpu(*(u16 *)&data[0]);
++	else
++		*val = be32_to_cpu(*(u32 *)&data[0]);
++
++	return 0;
++}
++
++static int ov5693_i2c_write(struct i2c_client *client, u16 len, u8 *data)
++{
++	struct i2c_msg msg;
++	const int num_msg = 1;
++	int ret;
++
++	msg.addr = client->addr;
++	msg.flags = 0;
++	msg.len = len;
++	msg.buf = data;
++	ret = i2c_transfer(client->adapter, &msg, 1);
++
++	return ret == num_msg ? 0 : -EIO;
++}
++
++static int ov5693_write_reg(struct i2c_client *client, u16 data_length,
++							u16 reg, u16 val)
++{
++	int ret;
++	unsigned char data[4] = {0};
++	u16 *wreg = (u16 *)data;
++	const u16 len = data_length + sizeof(u16); /* 16-bit address + data */
++
++	if (data_length != OV5693_8BIT && data_length != OV5693_16BIT) {
++		dev_err(&client->dev,
++			"%s error, invalid data_length\n", __func__);
++		return -EINVAL;
++	}
++
++	/* high byte goes out first */
++	*wreg = cpu_to_be16(reg);
++
++	if (data_length == OV5693_8BIT) {
++		data[2] = (u8)(val);
++	} else {
++		/* OV5693_16BIT */
++		u16 *wdata = (u16 *)&data[2];
++		*wdata = cpu_to_be16(val);
++	}
++
++	ret = ov5693_i2c_write(client, len, data);
++	if (ret)
++		dev_err(&client->dev,
++			"write error: wrote 0x%x to offset 0x%x error %d",
++			val, reg, ret);
++
++	return ret;
++}
++
++/*
++ * ov5693_write_reg_array - Initializes a list of OV5693 registers
++ * @client: i2c driver client structure
++ * @reglist: list of registers to be written
++ *
++ * This function initializes a list of registers. When consecutive addresses
++ * are found in a row on the list, this function creates a buffer and sends
++ * consecutive data in a single i2c_transfer().
++ *
++ * __ov5693_flush_reg_array, __ov5693_buf_reg_array() and
++ * __ov5693_write_reg_is_consecutive() are internal functions to
++ * ov5693_write_reg_array_fast() and should be not used anywhere else.
++ *
++ */
++static int __ov5693_flush_reg_array(struct i2c_client *client,
++				    struct ov5693_write_ctrl *ctrl)
++{
++	u16 size;
++
++	if (ctrl->index == 0)
++		return 0;
++
++	size = sizeof(u16) + ctrl->index; /* 16-bit address + data */
++	ctrl->buffer.addr = cpu_to_be16(ctrl->buffer.addr);
++	ctrl->index = 0;
++
++	return ov5693_i2c_write(client, size, (u8 *)&ctrl->buffer);
++}
++
++static int __ov5693_buf_reg_array(struct i2c_client *client,
++				  struct ov5693_write_ctrl *ctrl,
++				  const struct ov5693_reg *next)
++{
++	int size;
++	u16 *data16;
++
++	switch (next->type) {
++	case OV5693_8BIT:
++		size = 1;
++		ctrl->buffer.data[ctrl->index] = (u8)next->val;
++		break;
++	case OV5693_16BIT:
++		size = 2;
++		data16 = (u16 *)&ctrl->buffer.data[ctrl->index];
++		*data16 = cpu_to_be16((u16)next->val);
++		break;
++	default:
++		return -EINVAL;
++	}
++
++	/* When first item is added, we need to store its starting address */
++	if (ctrl->index == 0)
++		ctrl->buffer.addr = next->reg;
++
++	ctrl->index += size;
++
++	/*
++	 * Buffer cannot guarantee free space for u32? Better flush it to avoid
++	 * possible lack of memory for next item.
++	 */
++	if (ctrl->index + sizeof(u16) >= OV5693_MAX_WRITE_BUF_SIZE)
++		return __ov5693_flush_reg_array(client, ctrl);
++
++	return 0;
++}
++
++static int __ov5693_write_reg_is_consecutive(struct i2c_client *client,
++					     struct ov5693_write_ctrl *ctrl,
++					     const struct ov5693_reg *next)
++{
++	if (ctrl->index == 0)
++		return 1;
++
++	return ctrl->buffer.addr + ctrl->index == next->reg;
++}
++
++static int ov5693_write_reg_array(struct i2c_client *client,
++				  const struct ov5693_reg *reglist)
++{
++	const struct ov5693_reg *next = reglist;
++	struct ov5693_write_ctrl ctrl;
++	int err;
++
++	ctrl.index = 0;
++	for (; next->type != OV5693_TOK_TERM; next++) {
++		switch (next->type & OV5693_TOK_MASK) {
++		case OV5693_TOK_DELAY:
++			err = __ov5693_flush_reg_array(client, &ctrl);
++			if (err)
++				return err;
++			usleep_range(next->val * 1000, (next->val + 1) * 1000);
++			break;
++		default:
++			/*
++			 * If next address is not consecutive, data needs to be
++			 * flushed before proceed.
++			 */
++			if (!__ov5693_write_reg_is_consecutive(client, &ctrl,
++								next)) {
++				err = __ov5693_flush_reg_array(client, &ctrl);
++				if (err)
++					return err;
++			}
++			err = __ov5693_buf_reg_array(client, &ctrl, next);
++			if (err) {
++				dev_err(&client->dev, "%s: write error, aborted\n",
++					 __func__);
++				return err;
++			}
++			break;
++		}
++	}
++
++	return __ov5693_flush_reg_array(client, &ctrl);
++}
++static int ov5693_g_focal(struct v4l2_subdev *sd, s32 *val)
++{
++	*val = (OV5693_FOCAL_LENGTH_NUM << 16) | OV5693_FOCAL_LENGTH_DEM;
++	return 0;
++}
++
++static int ov5693_g_fnumber(struct v4l2_subdev *sd, s32 *val)
++{
++	/*const f number for ov5693*/
++	*val = (OV5693_F_NUMBER_DEFAULT_NUM << 16) | OV5693_F_NUMBER_DEM;
++	return 0;
++}
++
++static int ov5693_g_fnumber_range(struct v4l2_subdev *sd, s32 *val)
++{
++	*val = (OV5693_F_NUMBER_DEFAULT_NUM << 24) |
++		(OV5693_F_NUMBER_DEM << 16) |
++		(OV5693_F_NUMBER_DEFAULT_NUM << 8) | OV5693_F_NUMBER_DEM;
++	return 0;
++}
++
++
++static int ov5693_get_intg_factor(struct i2c_client *client,
++				struct camera_mipi_info *info,
++				const struct ov5693_resolution *res)
++{
++	struct atomisp_sensor_mode_data *buf = &info->data;
++	unsigned int pix_clk_freq_hz;
++	u16 reg_val;
++	int ret;
++
++	if (info == NULL)
++		return -EINVAL;
++
++	/* pixel clock calculattion */
++	pix_clk_freq_hz = res->pix_clk_freq * 1000000;
++
++	buf->vt_pix_clk_freq_mhz = pix_clk_freq_hz;
++
++	/* get integration time */
++	buf->coarse_integration_time_min = OV5693_COARSE_INTG_TIME_MIN;
++	buf->coarse_integration_time_max_margin =
++					OV5693_COARSE_INTG_TIME_MAX_MARGIN;
++
++	buf->fine_integration_time_min = OV5693_FINE_INTG_TIME_MIN;
++	buf->fine_integration_time_max_margin =
++					OV5693_FINE_INTG_TIME_MAX_MARGIN;
++
++	buf->fine_integration_time_def = OV5693_FINE_INTG_TIME_MIN;
++	buf->frame_length_lines = res->lines_per_frame;
++	buf->line_length_pck = res->pixels_per_line;
++	buf->read_mode = res->bin_mode;
++
++	/* get the cropping and output resolution to ISP for this mode. */
++	ret =  ov5693_read_reg(client, OV5693_16BIT,
++					OV5693_H_CROP_START_H, &reg_val);
++	if (ret)
++		return ret;
++	buf->crop_horizontal_start = reg_val;
++
++	ret =  ov5693_read_reg(client, OV5693_16BIT,
++					OV5693_V_CROP_START_H, &reg_val);
++	if (ret)
++		return ret;
++	buf->crop_vertical_start = reg_val;
++
++	ret = ov5693_read_reg(client, OV5693_16BIT,
++					OV5693_H_CROP_END_H, &reg_val);
++	if (ret)
++		return ret;
++	buf->crop_horizontal_end = reg_val;
++
++	ret = ov5693_read_reg(client, OV5693_16BIT,
++					OV5693_V_CROP_END_H, &reg_val);
++	if (ret)
++		return ret;
++	buf->crop_vertical_end = reg_val;
++
++	ret = ov5693_read_reg(client, OV5693_16BIT,
++					OV5693_H_OUTSIZE_H, &reg_val);
++	if (ret)
++		return ret;
++	buf->output_width = reg_val;
++
++	ret = ov5693_read_reg(client, OV5693_16BIT,
++					OV5693_V_OUTSIZE_H, &reg_val);
++	if (ret)
++		return ret;
++	buf->output_height = reg_val;
++
++	/*
++	 * we can't return 0 for bin_factor, this is because camera
++	 * HAL will use them as denominator, bin_factor = 0 will
++	 * cause camera HAL crash. So we return bin_factor as this
++	 * rules:
++	 * [1]. res->bin_factor = 0, return 1 for bin_factor.
++	 * [2]. res->bin_factor > 0, return res->bin_factor.
++	 */
++	buf->binning_factor_x = res->bin_factor_x ?
++					res->bin_factor_x : 1;
++	buf->binning_factor_y = res->bin_factor_y ?
++					res->bin_factor_y : 1;
++	return 0;
++}
++
++static long __ov5693_set_exposure(struct v4l2_subdev *sd, int coarse_itg,
++				 int gain, int digitgain)
++
++{
++	struct i2c_client *client = v4l2_get_subdevdata(sd);
++	u16 vts;
++	int ret;
++
++	/*
++	 * According to spec, the low 4 bits of exposure/gain reg are
++	 * fraction bits, so need to take 4 bits left shift to align
++	 * reg integer bits.
++	 */
++	coarse_itg <<= 4;
++	gain <<= 4;
++
++	ret = ov5693_read_reg(client, OV5693_16BIT,
++					OV5693_VTS_H, &vts);
++	if (ret)
++		return ret;
++
++	if (coarse_itg + OV5693_INTEGRATION_TIME_MARGIN >= vts)
++		vts = coarse_itg + OV5693_INTEGRATION_TIME_MARGIN;
++
++	ret = ov5693_write_reg(client, OV5693_16BIT, OV5693_VTS_H, vts);
++	if (ret)
++		return ret;
++
++	/* group hold start */
++	ret = ov5693_write_reg(client, OV5693_8BIT, OV5693_GROUP_ACCESS, 0);
++	if (ret)
++		return ret;
++
++	/* set exposure */
++	ret = ov5693_write_reg(client, OV5693_8BIT,
++					OV5693_AEC_PK_EXPO_L,
++					coarse_itg & 0xff);
++	if (ret)
++		return ret;
++
++	ret = ov5693_write_reg(client, OV5693_16BIT,
++					OV5693_AEC_PK_EXPO_H,
++					(coarse_itg >> 8) & 0xfff);
++	if (ret)
++		return ret;
++
++	/* set analog gain */
++	ret = ov5693_write_reg(client, OV5693_16BIT,
++					OV5693_AGC_ADJ_H, gain);
++	if (ret)
++		return ret;
++
++	/* set digital gain */
++	ret = ov5693_write_reg(client, OV5693_16BIT,
++				OV5693_MWB_GAIN_R_H, digitgain);
++	if (ret)
++		return ret;
++
++	ret = ov5693_write_reg(client, OV5693_16BIT,
++				OV5693_MWB_GAIN_G_H, digitgain);
++	if (ret)
++		return ret;
++
++	ret = ov5693_write_reg(client, OV5693_16BIT,
++				OV5693_MWB_GAIN_B_H, digitgain);
++	if (ret)
++		return ret;
++
++	/* group hold end */
++	ret = ov5693_write_reg(client, OV5693_8BIT,
++					OV5693_GROUP_ACCESS, 0x10);
++	if (ret)
++		return ret;
++
++	/* group hold launch */
++	ret = ov5693_write_reg(client, OV5693_8BIT,
++					OV5693_GROUP_ACCESS, 0xa0);
++
++	return ret;
++}
++
++static int ov5693_set_exposure(struct v4l2_subdev *sd, int exposure,
++	int gain, int digitgain)
++{
++	struct ov5693_device *dev = to_ov5693_sensor(sd);
++	int ret;
++
++	mutex_lock(&dev->input_lock);
++	ret = __ov5693_set_exposure(sd, exposure, gain, digitgain);
++	mutex_unlock(&dev->input_lock);
++
++	return ret;
++}
++
++static long ov5693_s_exposure(struct v4l2_subdev *sd,
++			       struct atomisp_exposure *exposure)
++{
++	struct i2c_client *client = v4l2_get_subdevdata(sd);
++	int exp = exposure->integration_time[0];
++	int gain = exposure->gain[0];
++	int digitgain = exposure->gain[1];
++
++	/* we should not accept the invalid value below. */
++	if (gain == 0) {
++		dev_err(&client->dev, "%s: invalid value\n", __func__);
++		return -EINVAL;
++	}
++
++	return ov5693_set_exposure(sd, exp, gain, digitgain);
++}
++
++static long ov5693_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
++{
++
++	switch (cmd) {
++	case ATOMISP_IOC_S_EXPOSURE:
++		return ov5693_s_exposure(sd, arg);
++	default:
++		return -EINVAL;
++	}
++	return 0;
++}
++
++/* This returns the exposure time being used. This should only be used
++   for filling in EXIF data, not for actual image processing. */
++static int ov5693_q_exposure(struct v4l2_subdev *sd, s32 *value)
++{
++	struct i2c_client *client = v4l2_get_subdevdata(sd);
++	u16 reg_v, reg_v2;
++	int ret;
++
++	/* get exposure */
++	ret = ov5693_read_reg(client, OV5693_8BIT,
++					OV5693_AEC_PK_EXPO_L,
++					&reg_v);
++	if (ret)
++		goto err;
++
++	ret = ov5693_read_reg(client, OV5693_8BIT,
++					OV5693_AEC_PK_EXPO_M,
++					&reg_v2);
++	if (ret)
++		goto err;
++
++	reg_v += reg_v2 << 8;
++	ret = ov5693_read_reg(client, OV5693_8BIT,
++					OV5693_AEC_PK_EXPO_H,
++					&reg_v2);
++	if (ret)
++		goto err;
++
++	*value = (reg_v + (((u32)reg_v2 << 16))) >> 4;
++err:
++	return ret;
++}
++
++/*
++ * This below focus func don't need input_lock mutex_lock
++ * since they are just called in v4l2 s_ctrl/g_ctrl framework
++ * where mutex input_lock have been done.
++ */
++int ov5693_t_focus_abs(struct v4l2_subdev *sd, s32 value)
++{
++	struct ov5693_device *dev = to_ov5693_sensor(sd);
++	int ret = 0;
++
++	if (dev->vcm_driver && dev->vcm_driver->t_focus_abs)
++		ret = dev->vcm_driver->t_focus_abs(sd, value);
++
++	return ret;
++}
++
++int ov5693_t_focus_rel(struct v4l2_subdev *sd, s32 value)
++{
++	struct ov5693_device *dev = to_ov5693_sensor(sd);
++	int ret = 0;
++
++	if (dev->vcm_driver && dev->vcm_driver->t_focus_rel)
++		ret = dev->vcm_driver->t_focus_rel(sd, value);
++
++	return ret;
++}
++
++int ov5693_q_focus_status(struct v4l2_subdev *sd, s32 *value)
++{
++	struct ov5693_device *dev = to_ov5693_sensor(sd);
++	int ret = 0;
++
++	if (dev->vcm_driver && dev->vcm_driver->q_focus_status)
++		ret = dev->vcm_driver->q_focus_status(sd, value);
++
++	return ret;
++}
++
++int ov5693_q_focus_abs(struct v4l2_subdev *sd, s32 *value)
++{
++	struct ov5693_device *dev = to_ov5693_sensor(sd);
++	int ret = 0;
++
++	if (dev->vcm_driver && dev->vcm_driver->q_focus_abs)
++		ret = dev->vcm_driver->q_focus_abs(sd, value);
++
++	return ret;
++}
++
++/* ov5693 control set/get */
++static int ov5693_g_ctrl(struct v4l2_ctrl *ctrl)
++{
++	struct ov5693_device *dev = container_of(
++		ctrl->handler, struct ov5693_device, ctrl_handler);
++	int ret = 0;
++
++	switch (ctrl->id) {
++	case V4L2_CID_EXPOSURE_ABSOLUTE:
++		ret = ov5693_q_exposure(&dev->sd, &ctrl->val);
++		break;
++	case V4L2_CID_FOCUS_ABSOLUTE:
++		ret = ov5693_q_focus_abs(&dev->sd, &ctrl->val);
++		break;
++	case V4L2_CID_FOCUS_STATUS:
++		ret = ov5693_q_focus_status(&dev->sd, &ctrl->val);
++		break;
++	case V4L2_CID_FOCAL_ABSOLUTE:
++		ret = ov5693_g_focal(&dev->sd, &ctrl->val);
++		break;
++	case V4L2_CID_FNUMBER_ABSOLUTE:
++		ret = ov5693_g_fnumber(&dev->sd, &ctrl->val);
++		break;
++	case V4L2_CID_FNUMBER_RANGE:
++		ret = ov5693_g_fnumber_range(&dev->sd, &ctrl->val);
++		break;
++	case V4L2_CID_BIN_FACTOR_HORZ:
++		ctrl->val = dev->ov5693_res[dev->fmt_idx].bin_factor_x;
++		break;
++	case V4L2_CID_BIN_FACTOR_VERT:
++		ctrl->val = dev->ov5693_res[dev->fmt_idx].bin_factor_y;
++		break;
++	default:
++		ret = -EINVAL;
++	}
++
++	return ret;
++}
++
++static int ov5693_s_ctrl(struct v4l2_ctrl *ctrl)
++{
++	struct ov5693_device *dev = container_of(
++		ctrl->handler, struct ov5693_device, ctrl_handler);
++	int ret = 0;
++
++	if (!ctrl)
++		return -EINVAL;
++
++	switch (ctrl->id) {
++	case V4L2_CID_RUN_MODE:
++		switch (ctrl->val) {
++		case ATOMISP_RUN_MODE_VIDEO:
++			dev->ov5693_res = ov5693_res_video;
++			dev->curr_res_num = N_RES_VIDEO;
++			break;
++		case ATOMISP_RUN_MODE_STILL_CAPTURE:
++			dev->ov5693_res = ov5693_res_still;
++			dev->curr_res_num = N_RES_STILL;
++			break;
++		default:
++			dev->ov5693_res = ov5693_res_preview;
++			dev->curr_res_num = N_RES_PREVIEW;
++		}
++		break;
++	case V4L2_CID_FOCUS_ABSOLUTE:
++		ret = ov5693_t_focus_abs(&dev->sd, ctrl->val);
++		break;
++	case V4L2_CID_FOCUS_RELATIVE:
++		ret = ov5693_t_focus_rel(&dev->sd, ctrl->val);
++		break;
++	default:
++		ret = -EINVAL;
++	}
++
++	return ret;
++}
++
++static int ov5693_init(struct v4l2_subdev *sd)
++{
++	struct i2c_client *client = v4l2_get_subdevdata(sd);
++	struct ov5693_device *dev = to_ov5693_sensor(sd);
++	int ret = 0;
++
++	/* restore settings */
++	dev->ov5693_res = ov5693_res_preview;
++	dev->curr_res_num = N_RES_PREVIEW;
++
++	ret = ov5693_write_reg_array(client, ov5693_init_setting);
++	if (ret)
++		dev_err(&client->dev, "ov5693 write init setting reg err.\n");
++
++	return ret;
++}
++
++
++static int power_up(struct v4l2_subdev *sd)
++{
++	struct ov5693_device *dev = to_ov5693_sensor(sd);
++	struct i2c_client *client = v4l2_get_subdevdata(sd);
++	int ret;
++
++	if (NULL == dev->platform_data) {
++		dev_err(&client->dev,
++			"no camera_sensor_platform_data");
++		return -ENODEV;
++	}
++
++	/* power control */
++	ret = dev->platform_data->power_ctrl(sd, 1);
++	if (ret)
++		goto fail_power;
++
++	/* gpio ctrl */
++	ret = dev->platform_data->gpio_ctrl(sd, 1);
++	if (ret)
++		goto fail_power;
++
++	/* flis clock control */
++	ret = dev->platform_data->flisclk_ctrl(sd, 1);
++	if (ret)
++		goto fail_clk;
++
++	/* according to DS, 20ms is needed between PWDN and i2c access */
++	msleep(20);
++
++	return 0;
++
++fail_clk:
++	dev->platform_data->gpio_ctrl(sd, 0);
++fail_power:
++	dev->platform_data->power_ctrl(sd, 0);
++	dev_err(&client->dev, "sensor power-up failed\n");
++
++	return ret;
++}
++
++static int power_down(struct v4l2_subdev *sd)
++{
++	struct ov5693_device *dev = to_ov5693_sensor(sd);
++	struct i2c_client *client = v4l2_get_subdevdata(sd);
++	int ret = 0;
++
++	if (NULL == dev->platform_data) {
++		dev_err(&client->dev,
++			"no camera_sensor_platform_data");
++		return -ENODEV;
++	}
++
++	ret = dev->platform_data->flisclk_ctrl(sd, 0);
++	if (ret)
++		dev_err(&client->dev, "flisclk failed\n");
++
++	/* gpio ctrl */
++	ret = dev->platform_data->gpio_ctrl(sd, 0);
++	if (ret)
++		dev_err(&client->dev, "gpio failed.\n");
++
++	/* power control */
++	ret = dev->platform_data->power_ctrl(sd, 0);
++	if (ret)
++		dev_err(&client->dev, "vprog failed.\n");
++
++	return ret;
++}
++
++static int ov5693_s_power(struct v4l2_subdev *sd, int on)
++{
++	struct ov5693_device *dev = to_ov5693_sensor(sd);
++	struct i2c_client *client = v4l2_get_subdevdata(sd);
++	int ret = 0;
++
++	mutex_lock(&dev->input_lock);
++	if (on == 0) {
++		if (dev->vcm_driver && dev->vcm_driver->power_down)
++			ret = dev->vcm_driver->power_down(sd);
++		if (ret)
++			dev_err(&client->dev, "vcm power-down failed.\n");
++
++		ret = power_down(sd);
++	} else {
++		if (dev->vcm_driver && dev->vcm_driver->power_up)
++			ret = dev->vcm_driver->power_up(sd);
++		if (ret)
++			dev_err(&client->dev, "vcm power-up failed.\n");
++
++		ret = power_up(sd);
++		if (!ret)
++			ret = ov5693_init(sd);
++	}
++	mutex_unlock(&dev->input_lock);
++	return ret;
++}
++
++/*
++ * distance - calculate the distance
++ * @res: resolution
++ * @w: width
++ * @h: height
++ *
++ * Get the gap between resolution and w/h.
++ * res->width/height smaller than w/h wouldn't be considered.
++ * Returns the value of gap or -1 if fail.
++ */
++static int distance(struct ov5693_resolution *res, u32 w, u32 h)
++{
++	unsigned int w_ratio = ((res->width << RATIO_SHIFT_BITS)/w);
++	unsigned int h_ratio;
++	int match;
++
++	if (h == 0)
++		return -1;
++	h_ratio = ((res->height << RATIO_SHIFT_BITS) / h);
++	if (h_ratio == 0)
++		return -1;
++	match   = abs(((w_ratio << RATIO_SHIFT_BITS) / h_ratio)
++			- ((int)(1 << RATIO_SHIFT_BITS)));
++
++	if ((w_ratio < (int)(1 << RATIO_SHIFT_BITS))
++	    || (h_ratio < (int)(1 << RATIO_SHIFT_BITS))  ||
++		(match > LARGEST_ALLOWED_RATIO_MISMATCH))
++		return -1;
++
++	return w_ratio + h_ratio;
++}
++
++/* Return the nearest higher resolution index */
++static int nearest_resolution_index(struct v4l2_subdev *sd,
++				    int w, int h)
++{
++	struct ov5693_device *dev = to_ov5693_sensor(sd);
++	int i;
++	int idx = dev->curr_res_num-1;
++	int dist;
++	int min_dist = INT_MAX;
++	struct ov5693_resolution *tmp_res = NULL;
++
++	for (i = 0; i < dev->curr_res_num; i++) {
++		tmp_res = &dev->ov5693_res[i];
++		dist = distance(tmp_res, w, h);
++		if (dist == -1)
++			continue;
++		if (dist < min_dist) {
++			min_dist = dist;
++			idx = i;
++		}
++	}
++
++	return idx;
++}
++
++static int get_resolution_index(struct v4l2_subdev *sd,
++				int w, int h)
++{
++	struct ov5693_device *dev = to_ov5693_sensor(sd);
++	int i;
++
++	for (i = 0; i < dev->curr_res_num; i++) {
++		if (w != dev->ov5693_res[i].width)
++			continue;
++		if (h != dev->ov5693_res[i].height)
++			continue;
++
++		return i;
++	}
++
++	return -1;
++}
++
++static int __ov5693_try_mbus_fmt(struct v4l2_subdev *sd,
++				 struct v4l2_mbus_framefmt *fmt)
++{
++	struct ov5693_device *dev = to_ov5693_sensor(sd);
++	int idx;
++
++	if (!fmt)
++		return -EINVAL;
++
++	idx = nearest_resolution_index(sd, fmt->width, fmt->height);
++	fmt->width = dev->ov5693_res[idx].width;
++	fmt->height = dev->ov5693_res[idx].height;
++	fmt->code = V4L2_MBUS_FMT_SGRBG10_1X10;
++
++	return 0;
++}
++
++static int ov5693_try_mbus_fmt(struct v4l2_subdev *sd,
++				struct v4l2_mbus_framefmt *fmt)
++{
++	struct ov5693_device *dev = to_ov5693_sensor(sd);
++	int ret;
++
++	mutex_lock(&dev->input_lock);
++	ret = __ov5693_try_mbus_fmt(sd, fmt);
++	mutex_unlock(&dev->input_lock);
++
++	return ret;
++}
++
++static int ov5693_s_mbus_fmt(struct v4l2_subdev *sd,
++			     struct v4l2_mbus_framefmt *fmt)
++{
++	struct ov5693_device *dev = to_ov5693_sensor(sd);
++	struct i2c_client *client = v4l2_get_subdevdata(sd);
++	struct camera_mipi_info *ov5693_info = NULL;
++	int ret = 0;
++
++	ov5693_info = v4l2_get_subdev_hostdata(sd);
++	if (ov5693_info == NULL)
++		return -EINVAL;
++
++	mutex_lock(&dev->input_lock);
++	ret = __ov5693_try_mbus_fmt(sd, fmt);
++	if (ret == -1) {
++		dev_err(&client->dev, "try fmt fail\n");
++		goto done;
++	}
++
++	dev->fmt_idx = get_resolution_index(sd, fmt->width, fmt->height);
++	if (dev->fmt_idx == -1) {
++		dev_err(&client->dev, "get resolution fail\n");
++		goto done;
++	}
++
++	ret = ov5693_write_reg_array(client, dev->ov5693_res[dev->fmt_idx].regs);
++	if (ret) {
++		dev_err(&client->dev, "ov5693 write fmt register err.\n");
++		goto done;
++	}
++
++	ret = ov5693_get_intg_factor(client, ov5693_info,
++					&dev->ov5693_res[dev->fmt_idx]);
++	if (ret)
++		dev_err(&client->dev, "failed to get integration_factor\n");
++
++done:
++	mutex_unlock(&dev->input_lock);
++	return ret;
++}
++static int ov5693_g_mbus_fmt(struct v4l2_subdev *sd,
++			     struct v4l2_mbus_framefmt *fmt)
++{
++	struct ov5693_device *dev = to_ov5693_sensor(sd);
++
++	mutex_lock(&dev->input_lock);
++	fmt->width = dev->ov5693_res[dev->fmt_idx].width;
++	fmt->height = dev->ov5693_res[dev->fmt_idx].height;
++	fmt->code = V4L2_MBUS_FMT_SBGGR10_1X10;
++	mutex_unlock(&dev->input_lock);
++
++	return 0;
++}
++
++static int ov5693_detect(struct i2c_client *client)
++{
++	struct i2c_adapter *adapter = client->adapter;
++	int ret = 0;
++	u16 id;
++	u8 revision;
++
++	if (!i2c_check_functionality(adapter, I2C_FUNC_I2C))
++		return -ENODEV;
++
++	ret = ov5693_read_reg(client, OV5693_16BIT,
++					OV5693_SC_CMMN_CHIP_ID, &id);
++	if (ret) {
++		dev_err(&client->dev, "read sensor_id err.\n");
++		return -ENODEV;
++	}
++
++	if (id != OV5693_ID) {
++		dev_err(&client->dev, "sensor ID error\n");
++		return -ENODEV;
++	}
++
++	ret = ov5693_read_reg(client, OV5693_8BIT,
++					OV5693_SC_CMMN_SUB_ID, &id);
++	revision = (u8)id & 0x0f;
++
++	dev_dbg(&client->dev, "sensor_revision = 0x%x\n", revision);
++	dev_dbg(&client->dev, "detect ov5693 success\n");
++	return ret;
++}
++
++static int ov5693_s_stream(struct v4l2_subdev *sd, int enable)
++{
++	struct ov5693_device *dev = to_ov5693_sensor(sd);
++	struct i2c_client *client = v4l2_get_subdevdata(sd);
++	int ret;
++
++	mutex_lock(&dev->input_lock);
++
++	ret = ov5693_write_reg(client, OV5693_8BIT, OV5693_SW_STREAM,
++				enable ? OV5693_START_STREAMING :
++				OV5693_STOP_STREAMING);
++
++	mutex_unlock(&dev->input_lock);
++	return ret;
++}
++
++/* ov5693 enum frame size, frame intervals */
++static int ov5693_enum_framesizes(struct v4l2_subdev *sd,
++				  struct v4l2_frmsizeenum *fsize)
++{
++	struct ov5693_device *dev = to_ov5693_sensor(sd);
++	unsigned int index = fsize->index;
++
++	mutex_lock(&dev->input_lock);
++
++	if (index >= dev->curr_res_num) {
++		mutex_unlock(&dev->input_lock);
++		return -EINVAL;
++	}
++
++	fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
++	fsize->discrete.width = dev->ov5693_res[index].width;
++	fsize->discrete.height = dev->ov5693_res[index].height;
++
++	mutex_unlock(&dev->input_lock);
++	return 0;
++}
++
++static int ov5693_enum_frameintervals(struct v4l2_subdev *sd,
++				      struct v4l2_frmivalenum *fival)
++{
++	struct ov5693_device *dev = to_ov5693_sensor(sd);
++	unsigned int index = fival->index;
++
++	mutex_lock(&dev->input_lock);
++
++	if (index >= dev->curr_res_num) {
++		mutex_unlock(&dev->input_lock);
++		return -EINVAL;
++	}
++
++	fival->type = V4L2_FRMIVAL_TYPE_DISCRETE;
++	fival->width = dev->ov5693_res[index].width;
++	fival->height = dev->ov5693_res[index].height;
++	fival->discrete.numerator = 1;
++	fival->discrete.denominator = dev->ov5693_res[index].fps;
++
++	mutex_unlock(&dev->input_lock);
++
++	return 0;
++}
++
++static int ov5693_enum_mbus_fmt(struct v4l2_subdev *sd,
++				unsigned int index,
++				enum v4l2_mbus_pixelcode *code)
++{
++	*code = V4L2_MBUS_FMT_SBGGR10_1X10;
++
++	return 0;
++}
++
++static int ov5693_s_config(struct v4l2_subdev *sd,
++			   int irq, void *platform_data)
++{
++	struct ov5693_device *dev = to_ov5693_sensor(sd);
++	struct i2c_client *client = v4l2_get_subdevdata(sd);
++	int ret = 0;
++
++	if (platform_data == NULL)
++		return -ENODEV;
++
++	mutex_lock(&dev->input_lock);
++
++	dev->platform_data = platform_data;
++
++	ret = power_up(sd);
++	if (ret) {
++		dev_err(&client->dev, "ov5693 power-up err.\n");
++		goto fail_power_on;
++	}
++
++	ret = dev->platform_data->csi_cfg(sd, 1);
++	if (ret)
++		goto fail_csi_cfg;
++
++	/* config & detect sensor */
++	ret = ov5693_detect(client);
++	if (ret) {
++		dev_err(&client->dev, "ov5693_detect err s_config.\n");
++		goto fail_csi_cfg;
++	}
++
++	/* turn off sensor, after probed */
++	ret = power_down(sd);
++	if (ret) {
++		dev_err(&client->dev, "ov5693 power-off err.\n");
++		goto fail_csi_cfg;
++	}
++	mutex_unlock(&dev->input_lock);
++
++	return 0;
++
++fail_csi_cfg:
++	dev->platform_data->csi_cfg(sd, 0);
++fail_power_on:
++	power_down(sd);
++	dev_err(&client->dev, "sensor power-gating failed\n");
++	mutex_unlock(&dev->input_lock);
++	return ret;
++}
++
++static int ov5693_g_parm(struct v4l2_subdev *sd,
++			struct v4l2_streamparm *param)
++{
++	struct ov5693_device *dev = to_ov5693_sensor(sd);
++	struct i2c_client *client = v4l2_get_subdevdata(sd);
++
++	if (param->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
++		dev_err(&client->dev,  "unsupported buffer type.\n");
++		return -EINVAL;
++	}
++
++	memset(param, 0, sizeof(*param));
++	param->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
++
++	mutex_lock(&dev->input_lock);
++	if (dev->fmt_idx >= 0 && dev->fmt_idx < dev->curr_res_num) {
++		param->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
++		param->parm.capture.timeperframe.numerator = 1;
++		param->parm.capture.capturemode = dev->run_mode->val;
++		param->parm.capture.timeperframe.denominator =
++					dev->ov5693_res[dev->fmt_idx].fps;
++	}
++	mutex_unlock(&dev->input_lock);
++	return 0;
++}
++
++static int ov5693_g_frame_interval(struct v4l2_subdev *sd,
++				   struct v4l2_subdev_frame_interval *interval)
++{
++	struct ov5693_device *dev = to_ov5693_sensor(sd);
++
++	mutex_lock(&dev->input_lock);
++	interval->interval.numerator = 1;
++	interval->interval.denominator = dev->ov5693_res[dev->fmt_idx].fps;
++	mutex_unlock(&dev->input_lock);
++
++	return 0;
++}
++
++static int ov5693_enum_mbus_code(struct v4l2_subdev *sd,
++				struct v4l2_subdev_fh *fh,
++				struct v4l2_subdev_mbus_code_enum *code)
++{
++	code->code = V4L2_MBUS_FMT_SBGGR10_1X10;
++	return 0;
++}
++
++static int ov5693_enum_frame_size(struct v4l2_subdev *sd,
++				struct v4l2_subdev_fh *fh,
++				struct v4l2_subdev_frame_size_enum *fse)
++{
++	struct ov5693_device *dev = to_ov5693_sensor(sd);
++	int index = fse->index;
++
++	mutex_lock(&dev->input_lock);
++
++	if (index >= dev->curr_res_num) {
++		mutex_unlock(&dev->input_lock);
++		return -EINVAL;
++	}
++
++	fse->min_width = dev->ov5693_res[index].width;
++	fse->min_height = dev->ov5693_res[index].height;
++	fse->max_width = dev->ov5693_res[index].width;
++	fse->max_height = dev->ov5693_res[index].height;
++
++	mutex_unlock(&dev->input_lock);
++	return 0;
++}
++
++static int ov5693_get_pad_format(struct v4l2_subdev *sd,
++				struct v4l2_subdev_fh *fh,
++				struct v4l2_subdev_format *fmt)
++{
++	struct ov5693_device *dev = to_ov5693_sensor(sd);
++	struct v4l2_mbus_framefmt *format;
++
++	mutex_lock(&dev->input_lock);
++
++	switch (fmt->which) {
++	case V4L2_SUBDEV_FORMAT_TRY:
++		format = v4l2_subdev_get_try_format(fh, fmt->pad);
++		break;
++	case V4L2_SUBDEV_FORMAT_ACTIVE:
++		format = &dev->format;
++		break;
++	default:
++		format = NULL;
++	}
++
++	mutex_unlock(&dev->input_lock);
++
++	if (!format)
++		return -EINVAL;
++
++	fmt->format = *format;
++	return 0;
++}
++
++static int ov5693_set_pad_format(struct v4l2_subdev *sd,
++				struct v4l2_subdev_fh *fh,
++				struct v4l2_subdev_format *fmt)
++{
++	struct ov5693_device *dev = to_ov5693_sensor(sd);
++
++	mutex_lock(&dev->input_lock);
++
++	if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE)
++		dev->format = fmt->format;
++
++	mutex_unlock(&dev->input_lock);
++	return 0;
++}
++
++static int ov5693_g_skip_frames(struct v4l2_subdev *sd, u32 *frames)
++{
++	struct ov5693_device *dev = to_ov5693_sensor(sd);
++
++	mutex_lock(&dev->input_lock);
++	*frames = dev->ov5693_res[dev->fmt_idx].skip_frames;
++	mutex_unlock(&dev->input_lock);
++
++	return 0;
++}
++
++static const struct v4l2_ctrl_ops ctrl_ops = {
++	.s_ctrl = ov5693_s_ctrl,
++	.g_volatile_ctrl = ov5693_g_ctrl,
++};
++
++static const char * const ctrl_run_mode_menu[] = {
++	NULL,
++	"Video",
++	"Still capture",
++	"Continuous capture",
++	"Preview",
++};
++
++static const struct v4l2_ctrl_config ctrl_run_mode = {
++	.ops = &ctrl_ops,
++	.id = V4L2_CID_RUN_MODE,
++	.name = "run mode",
++	.type = V4L2_CTRL_TYPE_MENU,
++	.min = 1,
++	.def = 4,
++	.max = 4,
++	.qmenu = ctrl_run_mode_menu,
++};
++
++static const struct v4l2_ctrl_config ctrls[] = {
++	{
++		.ops = &ctrl_ops,
++		.id = V4L2_CID_EXPOSURE_ABSOLUTE,
++		.name = "absolute exposure",
++		.type = V4L2_CTRL_TYPE_INTEGER,
++		.min = 0x0,
++		.max = 0xffff,
++		.step = 0x01,
++		.def = 0x00,
++		.flags = 0,
++	}, {
++		.ops = &ctrl_ops,
++		.id = V4L2_CID_FOCUS_ABSOLUTE,
++		.type = V4L2_CTRL_TYPE_INTEGER,
++		.name = "focus move absolute",
++		.min = 0,
++		.max = OV5693_MAX_FOCUS_POS,
++		.step = 1,
++		.def = 0,
++		.flags = 0,
++	}, {
++		.ops = &ctrl_ops,
++		.id = V4L2_CID_FOCUS_RELATIVE,
++		.type = V4L2_CTRL_TYPE_INTEGER,
++		.name = "focus move relative",
++		.min = OV5693_MAX_FOCUS_NEG,
++		.max = OV5693_MAX_FOCUS_POS,
++		.step = 1,
++		.def = 0,
++		.flags = 0,
++	}, {
++		.ops = &ctrl_ops,
++		.id = V4L2_CID_FOCUS_STATUS,
++		.type = V4L2_CTRL_TYPE_INTEGER,
++		.name = "focus status",
++		.min = 0,
++		.max = 100,
++		.step = 1,
++		.def = 0,
++		.flags = 0,
++	}, {
++		.ops = &ctrl_ops,
++		.id = V4L2_CID_FOCAL_ABSOLUTE,
++		.type = V4L2_CTRL_TYPE_INTEGER,
++		.name = "focal length",
++		.min = OV5693_FOCAL_LENGTH_DEFAULT,
++		.max = OV5693_FOCAL_LENGTH_DEFAULT,
++		.step = 0x01,
++		.def = OV5693_FOCAL_LENGTH_DEFAULT,
++		.flags = 0,
++	}, {
++		.ops = &ctrl_ops,
++		.id = V4L2_CID_FNUMBER_ABSOLUTE,
++		.type = V4L2_CTRL_TYPE_INTEGER,
++		.name = "f-number",
++		.min = OV5693_F_NUMBER_DEFAULT,
++		.max = OV5693_F_NUMBER_DEFAULT,
++		.step = 0x01,
++		.def = OV5693_F_NUMBER_DEFAULT,
++		.flags = 0,
++	}, {
++		.ops = &ctrl_ops,
++		.id = V4L2_CID_FNUMBER_RANGE,
++		.type = V4L2_CTRL_TYPE_INTEGER,
++		.name = "f-number range",
++		.min = OV5693_F_NUMBER_RANGE,
++		.max =  OV5693_F_NUMBER_RANGE,
++		.step = 0x01,
++		.def = OV5693_F_NUMBER_RANGE,
++		.flags = 0,
++	}, {
++		.ops = &ctrl_ops,
++		.id = V4L2_CID_BIN_FACTOR_HORZ,
++		.name = "horizontal binning factor",
++		.type = V4L2_CTRL_TYPE_INTEGER,
++		.max = OV5693_BIN_FACTOR_MAX,
++		.step = 2,
++		.flags = V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_VOLATILE,
++	}, {
++		.ops = &ctrl_ops,
++		.id = V4L2_CID_BIN_FACTOR_VERT,
++		.name = "vertical binning factor",
++		.type = V4L2_CTRL_TYPE_INTEGER,
++		.max = OV5693_BIN_FACTOR_MAX,
++		.step = 2,
++		.flags = V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_VOLATILE,
++	}
++};
++
++static const struct v4l2_subdev_sensor_ops ov5693_sensor_ops = {
++	.g_skip_frames	= ov5693_g_skip_frames,
++};
++
++static const struct v4l2_subdev_video_ops ov5693_video_ops = {
++	.s_stream = ov5693_s_stream,
++	.g_parm = ov5693_g_parm,
++	.enum_framesizes = ov5693_enum_framesizes,
++	.enum_frameintervals = ov5693_enum_frameintervals,
++	.enum_mbus_fmt = ov5693_enum_mbus_fmt,
++	.try_mbus_fmt = ov5693_try_mbus_fmt,
++	.g_mbus_fmt = ov5693_g_mbus_fmt,
++	.s_mbus_fmt = ov5693_s_mbus_fmt,
++	.g_frame_interval = ov5693_g_frame_interval,
++};
++
++static const struct v4l2_subdev_core_ops ov5693_core_ops = {
++	.s_power = ov5693_s_power,
++	.queryctrl = v4l2_subdev_queryctrl,
++	.g_ctrl = v4l2_subdev_g_ctrl,
++	.s_ctrl = v4l2_subdev_s_ctrl,
++	.ioctl = ov5693_ioctl,
++};
++
++static const struct v4l2_subdev_pad_ops ov5693_pad_ops = {
++	.enum_mbus_code = ov5693_enum_mbus_code,
++	.enum_frame_size = ov5693_enum_frame_size,
++	.get_fmt = ov5693_get_pad_format,
++	.set_fmt = ov5693_set_pad_format,
++};
++
++static const struct v4l2_subdev_ops ov5693_ops = {
++	.core = &ov5693_core_ops,
++	.video = &ov5693_video_ops,
++	.pad = &ov5693_pad_ops,
++	.sensor = &ov5693_sensor_ops,
++};
++
++static int ov5693_remove(struct i2c_client *client)
++{
++	struct v4l2_subdev *sd = i2c_get_clientdata(client);
++	struct ov5693_device *dev = to_ov5693_sensor(sd);
++	dev_dbg(&client->dev, "ov5693_remove...\n");
++
++	dev->platform_data->csi_cfg(sd, 0);
++
++	v4l2_device_unregister_subdev(sd);
++	media_entity_cleanup(&dev->sd.entity);
++	devm_kfree(&client->dev, dev);
++
++	return 0;
++}
++
++static int ov5693_probe(struct i2c_client *client,
++			const struct i2c_device_id *id)
++{
++	struct ov5693_device *dev;
++	int i;
++	int ret;
++
++	dev = devm_kzalloc(&client->dev, sizeof(*dev), GFP_KERNEL);
++	if (!dev) {
++		dev_err(&client->dev, "out of memory\n");
++		return -ENOMEM;
++	}
++
++	mutex_init(&dev->input_lock);
++
++	/*
++	 * Initialize related res members of dev.
++	 */
++	dev->fmt_idx = 0;
++	dev->ov5693_res = ov5693_res_preview;
++	dev->curr_res_num = N_RES_PREVIEW;
++
++	v4l2_i2c_subdev_init(&(dev->sd), client, &ov5693_ops);
++
++	if (client->dev.platform_data) {
++		ret = ov5693_s_config(&dev->sd, client->irq,
++				       client->dev.platform_data);
++		if (ret)
++			goto out_free;
++	}
++
++	dev->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
++	dev->pad.flags = MEDIA_PAD_FL_SOURCE;
++	dev->format.code = V4L2_MBUS_FMT_SBGGR10_1X10;
++	dev->sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR;
++	dev->vcm_driver = &ov5693_vcm_ops;
++
++	ret = v4l2_ctrl_handler_init(&dev->ctrl_handler, ARRAY_SIZE(ctrls) + 1);
++	if (ret) {
++		ov5693_remove(client);
++		return ret;
++	}
++
++	dev->run_mode = v4l2_ctrl_new_custom(&dev->ctrl_handler,
++					     &ctrl_run_mode, NULL);
++
++	for (i = 0; i < ARRAY_SIZE(ctrls); i++)
++		v4l2_ctrl_new_custom(&dev->ctrl_handler, &ctrls[i], NULL);
++
++	if (dev->ctrl_handler.error) {
++		ov5693_remove(client);
++		return dev->ctrl_handler.error;
++	}
++
++	dev->ctrl_handler.lock = &dev->input_lock;
++	dev->sd.ctrl_handler = &dev->ctrl_handler;
++	v4l2_ctrl_handler_setup(&dev->ctrl_handler);
++
++	ret = media_entity_init(&dev->sd.entity, 1, &dev->pad, 0);
++	if (ret)
++		ov5693_remove(client);
++
++	/* vcm initialization */
++	if (dev->vcm_driver && dev->vcm_driver->init)
++		ret = dev->vcm_driver->init(&dev->sd);
++	if (ret) {
++		dev_err(&client->dev, "vcm init failed.\n");
++		ov5693_remove(client);
++	}
++
++	return ret;
++out_free:
++	v4l2_device_unregister_subdev(&dev->sd);
++	devm_kfree(&client->dev, dev);
++	return ret;
++}
++
++MODULE_DEVICE_TABLE(i2c, ov5693_id);
++static struct i2c_driver ov5693_driver = {
++	.driver = {
++		.owner = THIS_MODULE,
++		.name = OV5693_NAME,
++	},
++	.probe = ov5693_probe,
++	.remove = ov5693_remove,
++	.id_table = ov5693_id,
++};
++
++module_i2c_driver(ov5693_driver);
++
++MODULE_DESCRIPTION("A low-level driver for OmniVision 5693 sensors");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/staging/ov5693/ov5693.h b/drivers/staging/ov5693/ov5693.h
+new file mode 100644
+index 000000000000..79aef69666e8
+--- /dev/null
++++ b/drivers/staging/ov5693/ov5693.h
+@@ -0,0 +1,848 @@
++/*
++ * Support for OmniVision OV5693 5M HD camera sensor.
++ *
++ * Copyright (c) 2013 Intel Corporation. All Rights Reserved.
++ *
++ * 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.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
++ * 02110-1301, USA.
++ *
++ */
++
++#ifndef __OV5693_H__
++#define __OV5693_H__
++#include <linux/delay.h>
++#include <linux/i2c.h>
++#include <linux/kernel.h>
++#include <media/media-entity.h>
++#include <linux/spinlock.h>
++#include <linux/types.h>
++#include <linux/videodev2.h>
++#include <media/v4l2-subdev.h>
++#include <media/v4l2-ctrls.h>
++#include <media/v4l2-device.h>
++#include <media/v4l2-chip-ident.h>
++#include <linux/v4l2-mediabus.h>
++
++#include <linux/atomisp_platform.h>
++#include "ad5823.h"
++
++#define OV5693_NAME		"ov5693"
++
++/* Defines for register writes and register array processing */
++#define I2C_MSG_LENGTH		0x2
++
++#define OV5693_FOCAL_LENGTH_NUM	278	/*2.78mm*/
++#define OV5693_FOCAL_LENGTH_DEM	100
++#define OV5693_F_NUMBER_DEFAULT_NUM	26
++#define OV5693_F_NUMBER_DEM	10
++
++#define OV5693_MAX_FOCUS_POS	1023
++#define OV5693_MAX_FOCUS_POS	1023
++#define OV5693_MAX_FOCUS_NEG	(-1023)
++
++#define LARGEST_ALLOWED_RATIO_MISMATCH	800
++#define RATIO_SHIFT_BITS		13
++
++/*
++ * focal length bits definition:
++ * bits 31-16: numerator, bits 15-0: denominator
++ */
++#define OV5693_FOCAL_LENGTH_DEFAULT 0x1160064
++
++/*
++ * current f-number bits definition:
++ * bits 31-16: numerator, bits 15-0: denominator
++ */
++#define OV5693_F_NUMBER_DEFAULT 0x1a000a
++
++/*
++ * f-number range bits definition:
++ * bits 31-24: max f-number numerator
++ * bits 23-16: max f-number denominator
++ * bits 15-8: min f-number numerator
++ * bits 7-0: min f-number denominator
++ */
++#define OV5693_F_NUMBER_RANGE 0x1a0a1a0a
++#define OV5693_ID	0x5690
++
++#define OV5693_FINE_INTG_TIME_MIN 0
++#define OV5693_FINE_INTG_TIME_MAX_MARGIN 0
++#define OV5693_COARSE_INTG_TIME_MIN 1
++#define OV5693_COARSE_INTG_TIME_MAX_MARGIN (0xffff - 6)
++#define OV5693_INTEGRATION_TIME_MARGIN	8
++
++#define OV5693_BIN_FACTOR_MAX	2
++
++/*
++ * OV5693 System control registers
++ */
++#define OV5693_SW_RESET				0x0103
++#define OV5693_SW_STREAM			0x0100
++
++#define OV5693_SC_CMMN_CHIP_ID			0x300a
++#define OV5693_SC_CMMN_SUB_ID			0x302a /* process, version*/
++
++#define OV5693_AEC_PK_EXPO_H			0x3500
++#define OV5693_AEC_PK_EXPO_M			0x3501
++#define OV5693_AEC_PK_EXPO_L			0x3502
++#define OV5693_AGC_ADJ_H			0x350a
++#define OV5693_VTS_H				0x380e
++#define OV5693_GROUP_ACCESS			0x3208
++
++#define OV5693_MWB_GAIN_R_H			0x3400
++#define OV5693_MWB_GAIN_G_H			0x3402
++#define OV5693_MWB_GAIN_B_H			0x3404
++
++#define OV5693_H_CROP_START_H			0x3800
++#define OV5693_V_CROP_START_H			0x3802
++#define OV5693_H_CROP_END_H			0x3804
++#define OV5693_V_CROP_END_H			0x3806
++#define OV5693_H_OUTSIZE_H			0x3808
++#define OV5693_V_OUTSIZE_H			0x380a
++
++#define OV5693_START_STREAMING			0x01
++#define OV5693_STOP_STREAMING			0x00
++
++struct ov5693_vcm {
++	int (*power_up)(struct v4l2_subdev *sd);
++	int (*power_down)(struct v4l2_subdev *sd);
++	int (*init)(struct v4l2_subdev *sd);
++	int (*t_focus_vcm)(struct v4l2_subdev *sd, u16 val);
++	int (*t_focus_abs)(struct v4l2_subdev *sd, s32 value);
++	int (*t_focus_rel)(struct v4l2_subdev *sd, s32 value);
++	int (*q_focus_status)(struct v4l2_subdev *sd, s32 *value);
++	int (*q_focus_abs)(struct v4l2_subdev *sd, s32 *value);
++};
++
++struct ov5693_resolution {
++	u8 *desc;
++	const struct ov5693_reg *regs;
++	int res;
++	int width;
++	int height;
++	int fps;
++	int pix_clk_freq;
++	u16 skip_frames;
++	u16 pixels_per_line;
++	u16 lines_per_frame;
++	u8 bin_factor_x;
++	u8 bin_factor_y;
++	u8 bin_mode;
++	bool used;
++};
++
++struct ov5693_control {
++	struct v4l2_queryctrl qc;
++	int (*query)(struct v4l2_subdev *sd, s32 *value);
++	int (*tweak)(struct v4l2_subdev *sd, s32 value);
++};
++
++/*
++ * ov5693 device structure.
++ */
++struct ov5693_device {
++	struct v4l2_subdev sd;
++	struct media_pad pad;
++	struct v4l2_mbus_framefmt format;
++	struct mutex input_lock;
++
++	struct camera_sensor_platform_data *platform_data;
++	struct ov5693_vcm *vcm_driver;
++	int fmt_idx;
++	u8 res;
++	u8 type;
++
++	struct ov5693_resolution *ov5693_res;
++	int curr_res_num;
++
++	struct v4l2_ctrl_handler ctrl_handler;
++	struct v4l2_ctrl *run_mode;
++};
++
++enum ov5693_tok_type {
++	OV5693_8BIT  = 0x0001,
++	OV5693_16BIT = 0x0002,
++	OV5693_32BIT = 0x0004,
++	OV5693_TOK_TERM   = 0xf000,	/* terminating token for reg list */
++	OV5693_TOK_DELAY  = 0xfe00,	/* delay token for reg list */
++	OV5693_TOK_MASK = 0xfff0
++};
++
++/**
++ * struct ov5693_reg - MI sensor  register format
++ * @type: type of the register
++ * @reg: 16-bit offset to register
++ * @val: 8/16/32-bit register value
++ *
++ * Define a structure for sensor register initialization values
++ */
++struct ov5693_reg {
++	enum ov5693_tok_type type;
++	u16 reg;
++	u32 val;	/* @set value for read/mod/write, @mask */
++};
++
++#define to_ov5693_sensor(x) container_of(x, struct ov5693_device, sd)
++
++#define OV5693_MAX_WRITE_BUF_SIZE	30
++
++struct ov5693_write_buffer {
++	u16 addr;
++	u8 data[OV5693_MAX_WRITE_BUF_SIZE];
++};
++
++struct ov5693_write_ctrl {
++	int index;
++	struct ov5693_write_buffer buffer;
++};
++
++static const struct i2c_device_id ov5693_id[] = {
++	{OV5693_NAME, 0},
++	{}
++};
++
++/* ov5693 sensor initialization setting */
++static struct ov5693_reg const ov5693_init_setting[] = {
++	{OV5693_8BIT, 0x0103, 0x01},
++	{OV5693_8BIT, 0x3001, 0x0a},
++	{OV5693_8BIT, 0x3002, 0x80},
++	{OV5693_8BIT, 0x3006, 0x00},
++	{OV5693_8BIT, 0x3011, 0x21},
++	{OV5693_8BIT, 0x3012, 0x09},
++	{OV5693_8BIT, 0x3013, 0x10},
++	{OV5693_8BIT, 0x3014, 0x00},
++	{OV5693_8BIT, 0x3015, 0x08},
++	{OV5693_8BIT, 0x3016, 0xf0},
++	{OV5693_8BIT, 0x3017, 0xf0},
++	{OV5693_8BIT, 0x3018, 0xf0},
++	{OV5693_8BIT, 0x301b, 0xb4},
++	{OV5693_8BIT, 0x301d, 0x02},
++	{OV5693_8BIT, 0x3021, 0x00},
++	{OV5693_8BIT, 0x3022, 0x01},
++	{OV5693_8BIT, 0x3028, 0x44},
++	{OV5693_8BIT, 0x3098, 0x02},
++	{OV5693_8BIT, 0x3099, 0x19},
++	{OV5693_8BIT, 0x309a, 0x02},
++	{OV5693_8BIT, 0x309b, 0x01},
++	{OV5693_8BIT, 0x309c, 0x00},
++	{OV5693_8BIT, 0x30a0, 0xd2},
++	{OV5693_8BIT, 0x30a2, 0x01},
++	{OV5693_8BIT, 0x30b2, 0x00},
++	{OV5693_8BIT, 0x30b3, 0x7d},
++	{OV5693_8BIT, 0x30b4, 0x03},
++	{OV5693_8BIT, 0x30b5, 0x04},
++	{OV5693_8BIT, 0x30b6, 0x01},
++	{OV5693_8BIT, 0x3104, 0x21},
++	{OV5693_8BIT, 0x3106, 0x00},
++
++	/* Manual white balance */
++	{OV5693_8BIT, 0x3400, 0x04},
++	{OV5693_8BIT, 0x3401, 0x00},
++	{OV5693_8BIT, 0x3402, 0x04},
++	{OV5693_8BIT, 0x3403, 0x00},
++	{OV5693_8BIT, 0x3404, 0x04},
++	{OV5693_8BIT, 0x3405, 0x00},
++	{OV5693_8BIT, 0x3406, 0x01},
++
++	/* Manual exposure control */
++	{OV5693_8BIT, 0x3500, 0x00},
++	{OV5693_8BIT, 0x3503, 0x07},
++	{OV5693_8BIT, 0x3504, 0x00},
++	{OV5693_8BIT, 0x3505, 0x00},
++	{OV5693_8BIT, 0x3506, 0x00},
++	{OV5693_8BIT, 0x3507, 0x02},
++	{OV5693_8BIT, 0x3508, 0x00},
++
++	/* Manual gain control */
++	{OV5693_8BIT, 0x3509, 0x10},
++	{OV5693_8BIT, 0x350a, 0x00},
++	{OV5693_8BIT, 0x350b, 0x40},
++
++	{OV5693_8BIT, 0x3601, 0x0a},
++	{OV5693_8BIT, 0x3602, 0x38},
++	{OV5693_8BIT, 0x3612, 0x80},
++	{OV5693_8BIT, 0x3620, 0x54},
++	{OV5693_8BIT, 0x3621, 0xc7},
++	{OV5693_8BIT, 0x3622, 0x0f},
++	{OV5693_8BIT, 0x3625, 0x10},
++	{OV5693_8BIT, 0x3630, 0x55},
++	{OV5693_8BIT, 0x3631, 0xf4},
++	{OV5693_8BIT, 0x3632, 0x00},
++	{OV5693_8BIT, 0x3633, 0x34},
++	{OV5693_8BIT, 0x3634, 0x02},
++	{OV5693_8BIT, 0x364d, 0x0d},
++	{OV5693_8BIT, 0x364f, 0xdd},
++	{OV5693_8BIT, 0x3660, 0x04},
++	{OV5693_8BIT, 0x3662, 0x10},
++	{OV5693_8BIT, 0x3663, 0xf1},
++	{OV5693_8BIT, 0x3665, 0x00},
++	{OV5693_8BIT, 0x3666, 0x20},
++	{OV5693_8BIT, 0x3667, 0x00},
++	{OV5693_8BIT, 0x366a, 0x80},
++	{OV5693_8BIT, 0x3680, 0xe0},
++	{OV5693_8BIT, 0x3681, 0x00},
++	{OV5693_8BIT, 0x3700, 0x42},
++	{OV5693_8BIT, 0x3701, 0x14},
++	{OV5693_8BIT, 0x3702, 0xa0},
++	{OV5693_8BIT, 0x3703, 0xd8},
++	{OV5693_8BIT, 0x3704, 0x78},
++	{OV5693_8BIT, 0x3705, 0x02},
++	{OV5693_8BIT, 0x370a, 0x00},
++	{OV5693_8BIT, 0x370b, 0x20},
++	{OV5693_8BIT, 0x370c, 0x0c},
++	{OV5693_8BIT, 0x370d, 0x11},
++	{OV5693_8BIT, 0x370e, 0x00},
++	{OV5693_8BIT, 0x370f, 0x40},
++	{OV5693_8BIT, 0x3710, 0x00},
++	{OV5693_8BIT, 0x371a, 0x1c},
++	{OV5693_8BIT, 0x371b, 0x05},
++	{OV5693_8BIT, 0x371c, 0x01},
++	{OV5693_8BIT, 0x371e, 0xa1},
++	{OV5693_8BIT, 0x371f, 0x0c},
++	{OV5693_8BIT, 0x3721, 0x00},
++	{OV5693_8BIT, 0x3724, 0x10},
++	{OV5693_8BIT, 0x3726, 0x00},
++	{OV5693_8BIT, 0x372a, 0x01},
++	{OV5693_8BIT, 0x3730, 0x10},
++	{OV5693_8BIT, 0x3738, 0x22},
++	{OV5693_8BIT, 0x3739, 0xe5},
++	{OV5693_8BIT, 0x373a, 0x50},
++	{OV5693_8BIT, 0x373b, 0x02},
++	{OV5693_8BIT, 0x373c, 0x41},
++	{OV5693_8BIT, 0x373f, 0x02},
++	{OV5693_8BIT, 0x3740, 0x42},
++	{OV5693_8BIT, 0x3741, 0x02},
++	{OV5693_8BIT, 0x3742, 0x18},
++	{OV5693_8BIT, 0x3743, 0x01},
++	{OV5693_8BIT, 0x3744, 0x02},
++	{OV5693_8BIT, 0x3747, 0x10},
++	{OV5693_8BIT, 0x374c, 0x04},
++	{OV5693_8BIT, 0x3751, 0xf0},
++	{OV5693_8BIT, 0x3752, 0x00},
++	{OV5693_8BIT, 0x3753, 0x00},
++	{OV5693_8BIT, 0x3754, 0xc0},
++	{OV5693_8BIT, 0x3755, 0x00},
++	{OV5693_8BIT, 0x3756, 0x1a},
++	{OV5693_8BIT, 0x3758, 0x00},
++	{OV5693_8BIT, 0x3759, 0x0f},
++	{OV5693_8BIT, 0x376b, 0x44},
++	{OV5693_8BIT, 0x375c, 0x04},
++	{OV5693_8BIT, 0x3774, 0x10},
++	{OV5693_8BIT, 0x3776, 0x00},
++	{OV5693_8BIT, 0x377f, 0x08},
++	{OV5693_8BIT, 0x3780, 0x22},
++	{OV5693_8BIT, 0x3781, 0x0c},
++	{OV5693_8BIT, 0x3784, 0x2c},
++	{OV5693_8BIT, 0x3785, 0x1e},
++	{OV5693_8BIT, 0x378f, 0xf5},
++	{OV5693_8BIT, 0x3791, 0xb0},
++	{OV5693_8BIT, 0x3795, 0x00},
++	{OV5693_8BIT, 0x3796, 0x64},
++	{OV5693_8BIT, 0x3797, 0x11},
++	{OV5693_8BIT, 0x3798, 0x30},
++	{OV5693_8BIT, 0x3799, 0x41},
++	{OV5693_8BIT, 0x379a, 0x07},
++	{OV5693_8BIT, 0x379b, 0xb0},
++	{OV5693_8BIT, 0x379c, 0x0c},
++	{OV5693_8BIT, 0x37c5, 0x00},
++	{OV5693_8BIT, 0x37c6, 0x00},
++	{OV5693_8BIT, 0x37c7, 0x00},
++	{OV5693_8BIT, 0x37c9, 0x00},
++	{OV5693_8BIT, 0x37ca, 0x00},
++	{OV5693_8BIT, 0x37cb, 0x00},
++	{OV5693_8BIT, 0x37de, 0x00},
++	{OV5693_8BIT, 0x37df, 0x00},
++	{OV5693_8BIT, 0x3800, 0x00},
++	{OV5693_8BIT, 0x3801, 0x00},
++	{OV5693_8BIT, 0x3802, 0x00},
++	{OV5693_8BIT, 0x3804, 0x0a},
++	{OV5693_8BIT, 0x3805, 0x3f},
++	{OV5693_8BIT, 0x3810, 0x00},
++	{OV5693_8BIT, 0x3812, 0x00},
++	{OV5693_8BIT, 0x3823, 0x00},
++	{OV5693_8BIT, 0x3824, 0x00},
++	{OV5693_8BIT, 0x3825, 0x00},
++	{OV5693_8BIT, 0x3826, 0x00},
++	{OV5693_8BIT, 0x3827, 0x00},
++	{OV5693_8BIT, 0x382a, 0x04},
++	{OV5693_8BIT, 0x3a04, 0x06},
++	{OV5693_8BIT, 0x3a05, 0x14},
++	{OV5693_8BIT, 0x3a06, 0x00},
++	{OV5693_8BIT, 0x3a07, 0xfe},
++	{OV5693_8BIT, 0x3b00, 0x00},
++	{OV5693_8BIT, 0x3b02, 0x00},
++	{OV5693_8BIT, 0x3b03, 0x00},
++	{OV5693_8BIT, 0x3b04, 0x00},
++	{OV5693_8BIT, 0x3b05, 0x00},
++	{OV5693_8BIT, 0x3e07, 0x20},
++	{OV5693_8BIT, 0x4000, 0x08},
++	{OV5693_8BIT, 0x4001, 0x04},
++	{OV5693_8BIT, 0x4002, 0x45},
++	{OV5693_8BIT, 0x4004, 0x08},
++	{OV5693_8BIT, 0x4005, 0x18},
++	{OV5693_8BIT, 0x4006, 0x20},
++	{OV5693_8BIT, 0x4008, 0x24},
++	{OV5693_8BIT, 0x4009, 0x10},
++	{OV5693_8BIT, 0x400c, 0x00},
++	{OV5693_8BIT, 0x400d, 0x00},
++	{OV5693_8BIT, 0x4058, 0x00},
++	{OV5693_8BIT, 0x404e, 0x37},
++	{OV5693_8BIT, 0x404f, 0x8f},
++	{OV5693_8BIT, 0x4058, 0x00},
++	{OV5693_8BIT, 0x4101, 0xb2},
++	{OV5693_8BIT, 0x4303, 0x00},
++	{OV5693_8BIT, 0x4304, 0x08},
++	{OV5693_8BIT, 0x4307, 0x30},
++	{OV5693_8BIT, 0x4311, 0x04},
++	{OV5693_8BIT, 0x4315, 0x01},
++	{OV5693_8BIT, 0x4511, 0x05},
++	{OV5693_8BIT, 0x4512, 0x01},
++	{OV5693_8BIT, 0x4806, 0x00},
++	{OV5693_8BIT, 0x4816, 0x52},
++	{OV5693_8BIT, 0x481f, 0x30},
++	{OV5693_8BIT, 0x4826, 0x2c},
++	{OV5693_8BIT, 0x4831, 0x64},
++	{OV5693_8BIT, 0x4d00, 0x04},
++	{OV5693_8BIT, 0x4d01, 0x71},
++	{OV5693_8BIT, 0x4d02, 0xfd},
++	{OV5693_8BIT, 0x4d03, 0xf5},
++	{OV5693_8BIT, 0x4d04, 0x0c},
++	{OV5693_8BIT, 0x4d05, 0xcc},
++	{OV5693_8BIT, 0x4837, 0x0a},
++	{OV5693_8BIT, 0x5000, 0x06},
++	{OV5693_8BIT, 0x5001, 0x01},
++	{OV5693_8BIT, 0x5003, 0x20},
++	{OV5693_8BIT, 0x5046, 0x0a},
++	{OV5693_8BIT, 0x5013, 0x00},
++	{OV5693_8BIT, 0x5046, 0x0a},
++	{OV5693_8BIT, 0x5780, 0x1c},
++	{OV5693_8BIT, 0x5786, 0x20},
++	{OV5693_8BIT, 0x5787, 0x10},
++	{OV5693_8BIT, 0x5788, 0x18},
++	{OV5693_8BIT, 0x578a, 0x04},
++	{OV5693_8BIT, 0x578b, 0x02},
++	{OV5693_8BIT, 0x578c, 0x02},
++	{OV5693_8BIT, 0x578e, 0x06},
++	{OV5693_8BIT, 0x578f, 0x02},
++	{OV5693_8BIT, 0x5790, 0x02},
++	{OV5693_8BIT, 0x5791, 0xff},
++	{OV5693_8BIT, 0x5842, 0x01},
++	{OV5693_8BIT, 0x5843, 0x2b},
++	{OV5693_8BIT, 0x5844, 0x01},
++	{OV5693_8BIT, 0x5845, 0x92},
++	{OV5693_8BIT, 0x5846, 0x01},
++	{OV5693_8BIT, 0x5847, 0x8f},
++	{OV5693_8BIT, 0x5848, 0x01},
++	{OV5693_8BIT, 0x5849, 0x0c},
++	{OV5693_8BIT, 0x5e00, 0x00},
++	{OV5693_8BIT, 0x5e10, 0x0c},
++	{OV5693_8BIT, 0x0100, 0x00},
++	{OV5693_TOK_TERM, 0, 0}
++};
++
++/*
++ * Register settings for various resolution
++ */
++
++/*
++------------------------------------
++@@ FULL QSXGA (2592x1944) 15fps 33.33ms VBlank 2lane 10Bit
++100 99 2592 1944
++100 98 1 0
++102 3601 bb8 ;Pather tool use only
++c8  1 f2 ; New FPGA Board
++c8 20 22 ; New FPGA Board
++c8 10 42 ; MIPI DFGA CYCY3 Board use only
++;
++c8 f 32  ; input clock to 19.2MHz
++;
++; OV5690 setting version History
++;
++;
++; V18b
++*/
++static struct ov5693_reg const ov5693_5M_15fps[] = {
++	{OV5693_8BIT, 0x3501, 0x7b},
++	{OV5693_8BIT, 0x3502, 0x00},
++	{OV5693_8BIT, 0x3708, 0xe2},
++	{OV5693_8BIT, 0x3709, 0xc3},
++	{OV5693_8BIT, 0x3800, 0x00},	/* x_addr_start: 0 */
++	{OV5693_8BIT, 0x3801, 0x00},
++	{OV5693_8BIT, 0x3802, 0x00},	/* y_addr_start: 0 */
++	{OV5693_8BIT, 0x3803, 0x00},
++	{OV5693_8BIT, 0x3804, 0x0a},	/* x_addr_end: 2623 */
++	{OV5693_8BIT, 0x3805, 0x3f},
++	{OV5693_8BIT, 0x3806, 0x07},	/* y_addr_end: 1955 */
++	{OV5693_8BIT, 0x3807, 0xa3},
++	{OV5693_8BIT, 0x3808, 0x0a},	/* x output size: 2592 */
++	{OV5693_8BIT, 0x3809, 0x20},
++	{OV5693_8BIT, 0x380a, 0x07},	/* y output size: 1944 */
++	{OV5693_8BIT, 0x380b, 0x98},
++	{OV5693_8BIT, 0x380c, 0x0e},	/* total x output size: 3688 */
++	{OV5693_8BIT, 0x380d, 0x68},
++	{OV5693_8BIT, 0x380e, 0x0f},	/* total y output size: 3968 */
++	{OV5693_8BIT, 0x380f, 0x80},
++	{OV5693_8BIT, 0x3810, 0x00},	/* x offset: 16 */
++	{OV5693_8BIT, 0x3811, 0x10},
++	{OV5693_8BIT, 0x3812, 0x00},	/* y offset: 6 */
++	{OV5693_8BIT, 0x3813, 0x06},
++	{OV5693_8BIT, 0x3814, 0x11},
++	{OV5693_8BIT, 0x3815, 0x11},
++	{OV5693_8BIT, 0x3820, 0x00},
++	{OV5693_8BIT, 0x3821, 0x1e},
++	{OV5693_8BIT, 0x5002, 0x00},
++	{OV5693_TOK_TERM, 0, 0}
++};
++
++/*
++@@ OV5693 1940x1096 30fps 8.8ms VBlanking 2lane 10Bit(Scaling)
++100 99 1940 1096
++100 98 1 0
++102 3601 bb8 ;Pather tool use only
++102 40 0 ; HDR Mode off
++c8  1 f2 ; New FPGA Board
++c8 20 22 ; New FPGA Board
++c8 10 42 ; MIPI DFGA CYCY3 Board use only
++;
++c8 f 32  ; input clock to 19.2MHz
++;
++; OV5690 setting version History
++;
++;
++; V18b
++*/
++static struct ov5693_reg const ov5693_1080p_30fps[] = {
++	{OV5693_8BIT, 0x3501, 0x7b},
++	{OV5693_8BIT, 0x3502, 0x00},
++	{OV5693_8BIT, 0x3708, 0xe2},
++	{OV5693_8BIT, 0x3709, 0xc3},
++	{OV5693_8BIT, 0x3800, 0x00},	/* x_addr_start: 0 */
++	{OV5693_8BIT, 0x3801, 0x00},
++	{OV5693_8BIT, 0x3802, 0x00},	/* y_addr_start: 240 */
++	{OV5693_8BIT, 0x3803, 0xf0},
++	{OV5693_8BIT, 0x3804, 0x0a},	/* x_addr_end: 2591 */
++	{OV5693_8BIT, 0x3805, 0x1f},
++	{OV5693_8BIT, 0x3806, 0x06},	/* y_addr_end: 1703 */
++	{OV5693_8BIT, 0x3807, 0xa7},
++	{OV5693_8BIT, 0x3808, 0x07},	/* x output size: 1940 */
++	{OV5693_8BIT, 0x3809, 0x94},
++	{OV5693_8BIT, 0x380a, 0x04},	/* y output size: 1096 */
++	{OV5693_8BIT, 0x380b, 0x48},
++	{OV5693_8BIT, 0x380c, 0x0e},	/* total x output size: 3688 */
++	{OV5693_8BIT, 0x380d, 0x68},
++	{OV5693_8BIT, 0x380e, 0x0b},	/* total y output size: 2984 */
++	{OV5693_8BIT, 0x380f, 0xa8},
++	{OV5693_8BIT, 0x3810, 0x00},	/* x offset: 2 */
++	{OV5693_8BIT, 0x3811, 0x02},
++	{OV5693_8BIT, 0x3812, 0x00},	/* y offset: 2 */
++	{OV5693_8BIT, 0x3813, 0x02},
++	{OV5693_8BIT, 0x3814, 0x11},
++	{OV5693_8BIT, 0x3815, 0x11},
++	{OV5693_8BIT, 0x3820, 0x00},
++	{OV5693_8BIT, 0x3821, 0x1e},
++	{OV5693_8BIT, 0x5002, 0x80},
++	{OV5693_TOK_TERM, 0, 0}
++};
++
++/*
++ * 1296x736 30fps 8.8ms VBlanking 2lane 10Bit (Scaling)
++ */
++static struct ov5693_reg const ov5693_720p_30fps[] = {
++	{OV5693_8BIT, 0x3501, 0x3d},
++	{OV5693_8BIT, 0x3502, 0x00},
++	{OV5693_8BIT, 0x3708, 0xe6},
++	{OV5693_8BIT, 0x3709, 0xc7},
++	{OV5693_8BIT, 0x3800, 0x00},	/* x_addr_start: 0 */
++	{OV5693_8BIT, 0x3801, 0x00},
++	{OV5693_8BIT, 0x3802, 0x00},	/* y_addr_start: 0 */
++	{OV5693_8BIT, 0x3803, 0x00},
++	{OV5693_8BIT, 0x3804, 0x0a},	/* x_addr_end: 2623 */
++	{OV5693_8BIT, 0x3805, 0x3f},
++	{OV5693_8BIT, 0x3806, 0x07},	/* y_addr_end: 1955 */
++	{OV5693_8BIT, 0x3807, 0xa3},
++	{OV5693_8BIT, 0x3808, 0x05},	/* x output size: 1296 */
++	{OV5693_8BIT, 0x3809, 0x10},
++	{OV5693_8BIT, 0x380a, 0x02},	/* y output size: 736 */
++	{OV5693_8BIT, 0x380b, 0xe0},
++	{OV5693_8BIT, 0x380c, 0x0a},	/* total x output size: 2688 */
++	{OV5693_8BIT, 0x380d, 0x80},
++	{OV5693_8BIT, 0x380e, 0x07},	/* total y output size: 1984 */
++	{OV5693_8BIT, 0x380f, 0xc0},
++	{OV5693_8BIT, 0x3810, 0x00},	/* x offset: 8 */
++	{OV5693_8BIT, 0x3811, 0x08},
++	{OV5693_8BIT, 0x3812, 0x00},	/* y offset: 2 */
++	{OV5693_8BIT, 0x3813, 0x02},
++	{OV5693_8BIT, 0x3814, 0x31},
++	{OV5693_8BIT, 0x3815, 0x31},
++	{OV5693_8BIT, 0x3820, 0x04},
++	{OV5693_8BIT, 0x3821, 0x1f},
++	{OV5693_8BIT, 0x5002, 0x80},
++	{OV5693_TOK_TERM, 0, 0}
++};
++
++/*
++ * 736x496 30fps 8.8ms VBlanking 2lane 10Bit (Scaling)
++ */
++static struct ov5693_reg const ov5693_480p_30fps[] = {
++	{OV5693_8BIT, 0x3501, 0x3d},
++	{OV5693_8BIT, 0x3502, 0x00},
++	{OV5693_8BIT, 0x3708, 0xe6},
++	{OV5693_8BIT, 0x3709, 0xc7},
++	{OV5693_8BIT, 0x3800, 0x00},	/* x_addr_start: 0 */
++	{OV5693_8BIT, 0x3801, 0x00},
++	{OV5693_8BIT, 0x3802, 0x00},	/* y_addr_start: 7 */
++	{OV5693_8BIT, 0x3803, 0x07},
++	{OV5693_8BIT, 0x3804, 0x0a},	/* x_addr_end: 2623 */
++	{OV5693_8BIT, 0x3805, 0x3f},
++	{OV5693_8BIT, 0x3806, 0x07},	/* y_addr_end: 1955 */
++	{OV5693_8BIT, 0x3807, 0xa3},
++	{OV5693_8BIT, 0x3808, 0x02},	/* x output size: 736 */
++	{OV5693_8BIT, 0x3809, 0xe0},
++	{OV5693_8BIT, 0x380a, 0x01},	/* y output size: 496 */
++	{OV5693_8BIT, 0x380b, 0xf0},
++	{OV5693_8BIT, 0x380c, 0x0a},	/* total x output size: 2688 */
++	{OV5693_8BIT, 0x380d, 0x80},
++	{OV5693_8BIT, 0x380e, 0x07},	/* total y output size: 1984 */
++	{OV5693_8BIT, 0x380f, 0xc0},
++	{OV5693_8BIT, 0x3810, 0x00},	/* x offset: 8 */
++	{OV5693_8BIT, 0x3811, 0x08},
++	{OV5693_8BIT, 0x3812, 0x00},	/* y offset: 2 */
++	{OV5693_8BIT, 0x3813, 0x02},
++	{OV5693_8BIT, 0x3814, 0x31},
++	{OV5693_8BIT, 0x3815, 0x31},
++	{OV5693_8BIT, 0x3820, 0x04},
++	{OV5693_8BIT, 0x3821, 0x1f},
++	{OV5693_8BIT, 0x5002, 0x80},
++	{OV5693_TOK_TERM, 0, 0}
++};
++
++/*
++@@ OV5693 656x496 30fps 17ms VBlanking 2lane 10Bit(Scaling)
++100 99 656 496
++100 98 1 0
++102 3601 BB8 ;Pather tool use only
++c8  1 f2 ; New FPGA Board
++c8 20 22 ; New FPGA Board
++; OV5690 setting version History
++;
++c8 f 32  ; input clock to 19.2MHz
++;
++; V18b
++*/
++static struct ov5693_reg const ov5693_VGA_30fps[] = {
++	{OV5693_8BIT, 0x3501, 0x3d},
++	{OV5693_8BIT, 0x3502, 0x00},
++	{OV5693_8BIT, 0x3708, 0xe6},
++	{OV5693_8BIT, 0x3709, 0xc7},
++	{OV5693_8BIT, 0x3800, 0x00},	/* x_addr_start: 0 */
++	{OV5693_8BIT, 0x3801, 0x00},
++	{OV5693_8BIT, 0x3802, 0x00},	/* y_addr_start: 0 */
++	{OV5693_8BIT, 0x3803, 0x00},
++	{OV5693_8BIT, 0x3804, 0x0a},	/* x_addr_end: 2623 */
++	{OV5693_8BIT, 0x3805, 0x3f},
++	{OV5693_8BIT, 0x3806, 0x07},	/* y_addr_end: 1955 */
++	{OV5693_8BIT, 0x3807, 0xa3},
++	{OV5693_8BIT, 0x3808, 0x02},	/* x output size: 656 */
++	{OV5693_8BIT, 0x3809, 0x90},
++	{OV5693_8BIT, 0x380a, 0x01},	/* y output size: 496 */
++	{OV5693_8BIT, 0x380b, 0xf0},
++	{OV5693_8BIT, 0x380c, 0x0a},	/* total x output size: 2688 */
++	{OV5693_8BIT, 0x380d, 0x80},
++	{OV5693_8BIT, 0x380e, 0x07},	/* total y output size: 1984 */
++	{OV5693_8BIT, 0x380f, 0xc0},
++	{OV5693_8BIT, 0x3810, 0x00},	/* x offset: 13 */
++	{OV5693_8BIT, 0x3811, 0x0d},
++	{OV5693_8BIT, 0x3812, 0x00},	/* y offset: 3 */
++	{OV5693_8BIT, 0x3813, 0x03},
++	{OV5693_8BIT, 0x3814, 0x31},
++	{OV5693_8BIT, 0x3815, 0x31},
++	{OV5693_8BIT, 0x3820, 0x04},
++	{OV5693_8BIT, 0x3821, 0x1f},
++	{OV5693_8BIT, 0x5002, 0x80},
++	{OV5693_TOK_TERM, 0, 0}
++};
++
++struct ov5693_resolution ov5693_res_preview[] = {
++	{
++		.desc = "ov5693_VGA_30fps",
++		.width = 656,
++		.height = 496,
++		.fps = 30,
++		.pix_clk_freq = 81,
++		.used = 0,
++		.pixels_per_line = 2688,
++		.lines_per_frame = 1984,
++		.bin_factor_x = 2,
++		.bin_factor_y = 2,
++		.bin_mode = 0,
++		.skip_frames = 3,
++		.regs = ov5693_VGA_30fps,
++	},
++	{
++		.desc = "ov5693_1080P_30fps",
++		.width = 1940,
++		.height = 1096,
++		.fps = 30,
++		.pix_clk_freq = 81,
++		.used = 0,
++		.pixels_per_line = 3688,
++		.lines_per_frame = 2984,
++		.bin_factor_x = 0,
++		.bin_factor_y = 0,
++		.bin_mode = 0,
++		.skip_frames = 3,
++		.regs = ov5693_1080p_30fps,
++	},
++	{
++		.desc = "ov5693_5M_15fps",
++		.width = 2592,
++		.height = 1944,
++		.fps = 15,
++		.pix_clk_freq = 81,
++		.used = 0,
++		.pixels_per_line = 3688,
++		.lines_per_frame = 3968,
++		.bin_factor_x = 0,
++		.bin_factor_y = 0,
++		.bin_mode = 0,
++		.skip_frames = 3,
++		.regs = ov5693_5M_15fps,
++	},
++};
++#define N_RES_PREVIEW (ARRAY_SIZE(ov5693_res_preview))
++
++struct ov5693_resolution ov5693_res_still[] = {
++	{
++		.desc = "ov5693_VGA_30fps",
++		.width = 656,
++		.height = 496,
++		.fps = 30,
++		.pix_clk_freq = 81,
++		.used = 0,
++		.pixels_per_line = 2688,
++		.lines_per_frame = 1984,
++		.bin_factor_x = 2,
++		.bin_factor_y = 2,
++		.bin_mode = 0,
++		.skip_frames = 3,
++		.regs = ov5693_VGA_30fps,
++	},
++	{
++		.desc = "ov5693_1080P_30fps",
++		.width = 1940,
++		.height = 1096,
++		.fps = 30,
++		.pix_clk_freq = 81,
++		.used = 0,
++		.pixels_per_line = 3688,
++		.lines_per_frame = 2984,
++		.bin_factor_x = 0,
++		.bin_factor_y = 0,
++		.bin_mode = 0,
++		.skip_frames = 3,
++		.regs = ov5693_1080p_30fps,
++	},
++	{
++		.desc = "ov5693_5M_15fps",
++		.width = 2592,
++		.height = 1944,
++		.fps = 15,
++		.pix_clk_freq = 81,
++		.used = 0,
++		.pixels_per_line = 3688,
++		.lines_per_frame = 3968,
++		.bin_factor_x = 0,
++		.bin_factor_y = 0,
++		.bin_mode = 0,
++		.skip_frames = 3,
++		.regs = ov5693_5M_15fps,
++	},
++};
++#define N_RES_STILL (ARRAY_SIZE(ov5693_res_still))
++
++struct ov5693_resolution ov5693_res_video[] = {
++	{
++		.desc = "ov5693_VGA_30fps",
++		.width = 656,
++		.height = 496,
++		.fps = 30,
++		.pix_clk_freq = 81,
++		.used = 0,
++		.pixels_per_line = 2688,
++		.lines_per_frame = 1984,
++		.bin_factor_x = 2,
++		.bin_factor_y = 2,
++		.bin_mode = 0,
++		.skip_frames = 3,
++		.regs = ov5693_VGA_30fps,
++	},
++	{
++		.desc = "ov5693_480P_30fps",
++		.width = 736,
++		.height = 496,
++		.fps = 30,
++		.pix_clk_freq = 81,
++		.used = 0,
++		.pixels_per_line = 2688,
++		.lines_per_frame = 1984,
++		.bin_factor_x = 2,
++		.bin_factor_y = 2,
++		.bin_mode = 0,
++		.skip_frames = 1,
++		.regs = ov5693_480p_30fps,
++	},
++	{
++		.desc = "ov5693_720p_30fps",
++		.width = 1296,
++		.height = 736,
++		.fps = 30,
++		.pix_clk_freq = 81,
++		.used = 0,
++		.pixels_per_line = 2688,
++		.lines_per_frame = 1984,
++		.bin_factor_x = 2,
++		.bin_factor_y = 2,
++		.bin_mode = 0,
++		.skip_frames = 1,
++		.regs = ov5693_720p_30fps,
++	},
++	{
++		.desc = "ov5693_1080P_30fps",
++		.width = 1940,
++		.height = 1096,
++		.fps = 30,
++		.pix_clk_freq = 81,
++		.used = 0,
++		.pixels_per_line = 3688,
++		.lines_per_frame = 2984,
++		.bin_factor_x = 0,
++		.bin_factor_y = 0,
++		.bin_mode = 0,
++		.skip_frames = 3,
++		.regs = ov5693_1080p_30fps,
++	},
++};
++#define N_RES_VIDEO (ARRAY_SIZE(ov5693_res_video))
++
++struct ov5693_vcm ov5693_vcm_ops = {
++	.power_up = ad5823_vcm_power_up,
++	.power_down = ad5823_vcm_power_down,
++	.init = ad5823_vcm_init,
++	.t_focus_vcm = ad5823_t_focus_vcm,
++	.t_focus_abs = ad5823_t_focus_abs,
++	.t_focus_rel = ad5823_t_focus_rel,
++	.q_focus_status = ad5823_q_focus_status,
++	.q_focus_abs = ad5823_q_focus_abs,
++};
++#endif

+ 6058 - 0
patches/4.18/ipts.patch

@@ -0,0 +1,6058 @@
+diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
+index 4c6adae23e18..1171fbd3a823 100644
+--- a/drivers/gpu/drm/i915/Makefile
++++ b/drivers/gpu/drm/i915/Makefile
+@@ -154,6 +154,9 @@ i915-y += dvo_ch7017.o \
+ 	  intel_sdvo.o \
+ 	  intel_tv.o
+ 
++# intel precise touch & stylus
++i915-y  += intel_ipts.o
++
+ # Post-mortem debug and GPU hang state capture
+ i915-$(CONFIG_DRM_I915_CAPTURE_ERROR) += i915_gpu_error.o
+ i915-$(CONFIG_DRM_I915_SELFTEST) += \
+diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
+index 9c449b8d8eab..d5d91d196627 100644
+--- a/drivers/gpu/drm/i915/i915_drv.c
++++ b/drivers/gpu/drm/i915/i915_drv.c
+@@ -53,6 +53,7 @@
+ #include "i915_vgpu.h"
+ #include "intel_drv.h"
+ #include "intel_uc.h"
++#include "intel_ipts.h"
+ 
+ static struct drm_driver driver;
+ 
+@@ -717,6 +718,9 @@ static int i915_load_modeset_init(struct drm_device *dev)
+ 	/* Only enable hotplug handling once the fbdev is fully set up. */
+ 	intel_hpd_init(dev_priv);
+ 
++	if (INTEL_GEN(dev_priv) >= 9 && i915_modparams.enable_guc && i915_modparams.enable_ipts)
++        intel_ipts_init(dev);
++
+ 	return 0;
+ 
+ cleanup_gem:
+@@ -1441,6 +1445,9 @@ void i915_driver_unload(struct drm_device *dev)
+ 	struct drm_i915_private *dev_priv = to_i915(dev);
+ 	struct pci_dev *pdev = dev_priv->drm.pdev;
+ 
++	if (INTEL_GEN(dev_priv) >= 9 && i915_modparams.enable_guc && i915_modparams.enable_ipts)
++		intel_ipts_cleanup(dev);
++
+ 	i915_driver_unregister(dev_priv);
+ 
+ 	if (i915_gem_suspend(dev_priv))
+diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
+index 71e1aa54f774..62686739ff57 100644
+--- a/drivers/gpu/drm/i915/i915_drv.h
++++ b/drivers/gpu/drm/i915/i915_drv.h
+@@ -3230,6 +3230,9 @@ void i915_gem_object_do_bit_17_swizzle(struct drm_i915_gem_object *obj,
+ void i915_gem_object_save_bit_17_swizzle(struct drm_i915_gem_object *obj,
+ 					 struct sg_table *pages);
+ 
++struct i915_gem_context *
++i915_gem_context_create_ipts(struct drm_device *dev);
++
+ static inline struct i915_gem_context *
+ __i915_gem_context_lookup_rcu(struct drm_i915_file_private *file_priv, u32 id)
+ {
+diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c
+index 060335d3d9e0..525eb397c862 100644
+--- a/drivers/gpu/drm/i915/i915_gem_context.c
++++ b/drivers/gpu/drm/i915/i915_gem_context.c
+@@ -457,6 +457,18 @@ static bool needs_preempt_context(struct drm_i915_private *i915)
+ 	return HAS_LOGICAL_RING_PREEMPTION(i915);
+ }
+ 
++struct i915_gem_context *i915_gem_context_create_ipts(struct drm_device *dev)
++{
++	struct drm_i915_private *dev_priv = dev->dev_private;
++	struct i915_gem_context *ctx;
++
++	BUG_ON(!mutex_is_locked(&dev->struct_mutex));
++
++	ctx = i915_gem_create_context(dev_priv, NULL);
++
++	return ctx;
++}
++
+ int i915_gem_contexts_init(struct drm_i915_private *dev_priv)
+ {
+ 	struct i915_gem_context *ctx;
+diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
+index c16cb025755e..8fb9160d013b 100644
+--- a/drivers/gpu/drm/i915/i915_irq.c
++++ b/drivers/gpu/drm/i915/i915_irq.c
+@@ -36,6 +36,7 @@
+ #include "i915_drv.h"
+ #include "i915_trace.h"
+ #include "intel_drv.h"
++#include "intel_ipts.h"
+ 
+ /**
+  * DOC: interrupt handling
+@@ -1476,6 +1477,9 @@ gen8_cs_irq_handler(struct intel_engine_cs *engine, u32 iir)
+ 		tasklet |= USES_GUC_SUBMISSION(engine->i915);
+ 	}
+ 
++	if (iir & GT_RENDER_PIPECTL_NOTIFY_INTERRUPT)
++		intel_ipts_notify_complete();
++
+ 	if (tasklet)
+ 		tasklet_hi_schedule(&execlists->tasklet);
+ }
+@@ -3909,7 +3913,8 @@ static void gen8_gt_irq_postinstall(struct drm_i915_private *dev_priv)
+ {
+ 	/* These are interrupts we'll toggle with the ring mask register */
+ 	uint32_t gt_interrupts[] = {
+-		GT_RENDER_USER_INTERRUPT << GEN8_RCS_IRQ_SHIFT |
++		GT_RENDER_PIPECTL_NOTIFY_INTERRUPT << GEN8_RCS_IRQ_SHIFT |
++			GT_RENDER_USER_INTERRUPT << GEN8_RCS_IRQ_SHIFT |
+ 			GT_CONTEXT_SWITCH_INTERRUPT << GEN8_RCS_IRQ_SHIFT |
+ 			GT_RENDER_USER_INTERRUPT << GEN8_BCS_IRQ_SHIFT |
+ 			GT_CONTEXT_SWITCH_INTERRUPT << GEN8_BCS_IRQ_SHIFT,
+diff --git a/drivers/gpu/drm/i915/i915_params.c b/drivers/gpu/drm/i915/i915_params.c
+index 66ea3552c63e..4f54d74febc8 100644
+--- a/drivers/gpu/drm/i915/i915_params.c
++++ b/drivers/gpu/drm/i915/i915_params.c
+@@ -152,7 +152,10 @@ i915_param_named_unsafe(edp_vswing, int, 0400,
+ i915_param_named_unsafe(enable_guc, int, 0400,
+ 	"Enable GuC load for GuC submission and/or HuC load. "
+ 	"Required functionality can be selected using bitmask values. "
+-	"(-1=auto, 0=disable [default], 1=GuC submission, 2=HuC load)");
++	"(-1=auto, 0=disable, 1=GuC submission [default], 2=HuC load)");
++
++i915_param_named_unsafe(enable_ipts, bool, 0400,
++	"Enable IPTS Touchscreen and Pen support (default: true)");
+ 
+ i915_param_named(guc_log_level, int, 0400,
+ 	"GuC firmware logging level. Requires GuC to be loaded. "
+diff --git a/drivers/gpu/drm/i915/i915_params.h b/drivers/gpu/drm/i915/i915_params.h
+index 6684025b7af8..f7f0a63a87e5 100644
+--- a/drivers/gpu/drm/i915/i915_params.h
++++ b/drivers/gpu/drm/i915/i915_params.h
+@@ -47,7 +47,7 @@ struct drm_printer;
+ 	param(int, disable_power_well, -1) \
+ 	param(int, enable_ips, 1) \
+ 	param(int, invert_brightness, 0) \
+-	param(int, enable_guc, 0) \
++	param(int, enable_guc, 1) \
+ 	param(int, guc_log_level, -1) \
+ 	param(char *, guc_firmware_path, NULL) \
+ 	param(char *, huc_firmware_path, NULL) \
+@@ -70,7 +70,8 @@ struct drm_printer;
+ 	param(bool, nuclear_pageflip, false) \
+ 	param(bool, enable_dp_mst, true) \
+ 	param(bool, enable_dpcd_backlight, false) \
+-	param(bool, enable_gvt, false)
++	param(bool, enable_gvt, false) \
++	param(bool, enable_ipts, true)
+ 
+ #define MEMBER(T, member, ...) T member;
+ struct i915_params {
+diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
+index 16faea30114a..e5c1e24a6072 100644
+--- a/drivers/gpu/drm/i915/intel_dp.c
++++ b/drivers/gpu/drm/i915/intel_dp.c
+@@ -2601,8 +2601,8 @@ void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode)
+ 		return;
+ 
+ 	if (mode != DRM_MODE_DPMS_ON) {
+-		if (downstream_hpd_needs_d0(intel_dp))
+-			return;
++		//if (downstream_hpd_needs_d0(intel_dp))
++		//	return;
+ 
+ 		ret = drm_dp_dpcd_writeb(&intel_dp->aux, DP_SET_POWER,
+ 					 DP_SET_POWER_D3);
+diff --git a/drivers/gpu/drm/i915/intel_guc.h b/drivers/gpu/drm/i915/intel_guc.h
+index f1265e122d30..1303090a4bd8 100644
+--- a/drivers/gpu/drm/i915/intel_guc.h
++++ b/drivers/gpu/drm/i915/intel_guc.h
+@@ -69,6 +69,7 @@ struct intel_guc {
+ 
+ 	struct intel_guc_client *execbuf_client;
+ 	struct intel_guc_client *preempt_client;
++	struct intel_guc_client *ipts_client;
+ 
+ 	struct guc_preempt_work preempt_work[I915_NUM_ENGINES];
+ 	struct workqueue_struct *preempt_wq;
+diff --git a/drivers/gpu/drm/i915/intel_guc_submission.c b/drivers/gpu/drm/i915/intel_guc_submission.c
+index 2feb65096966..1b7b8dc27a28 100644
+--- a/drivers/gpu/drm/i915/intel_guc_submission.c
++++ b/drivers/gpu/drm/i915/intel_guc_submission.c
+@@ -94,6 +94,7 @@ static inline bool is_high_priority(struct intel_guc_client *client)
+ 
+ static int reserve_doorbell(struct intel_guc_client *client)
+ {
++	struct drm_i915_private *dev_priv = guc_to_i915(client->guc);
+ 	unsigned long offset;
+ 	unsigned long end;
+ 	u16 id;
+@@ -106,11 +107,16 @@ static int reserve_doorbell(struct intel_guc_client *client)
+ 	 * priority contexts, the second half for high-priority ones.
+ 	 */
+ 	offset = 0;
+-	end = GUC_NUM_DOORBELLS / 2;
+-	if (is_high_priority(client)) {
+-		offset = end;
+-		end += offset;
++	if (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv)) {
++		end = GUC_NUM_DOORBELLS;
+ 	}
++	else {
++		end = GUC_NUM_DOORBELLS/2;
++		if (is_high_priority(client)) {
++			offset = end;
++			end += offset;
++		}
++ 	}
+ 
+ 	id = find_next_zero_bit(client->guc->doorbell_bitmap, end, offset);
+ 	if (id == end)
+@@ -355,8 +361,14 @@ static void guc_stage_desc_init(struct intel_guc *guc,
+ 	desc = __get_stage_desc(client);
+ 	memset(desc, 0, sizeof(*desc));
+ 
+-	desc->attribute = GUC_STAGE_DESC_ATTR_ACTIVE |
+-			  GUC_STAGE_DESC_ATTR_KERNEL;
++	desc->attribute = GUC_STAGE_DESC_ATTR_ACTIVE;
++	if ((client->priority == GUC_CLIENT_PRIORITY_KMD_NORMAL) ||
++			(client->priority == GUC_CLIENT_PRIORITY_KMD_HIGH)) {
++		desc->attribute  |= GUC_STAGE_DESC_ATTR_KERNEL;
++	} else {
++		desc->attribute  |= GUC_STAGE_DESC_ATTR_PCH;
++	}
++
+ 	if (is_high_priority(client))
+ 		desc->attribute |= GUC_STAGE_DESC_ATTR_PREEMPT;
+ 	desc->stage_id = client->stage_id;
+@@ -1160,7 +1172,8 @@ static void guc_interrupts_capture(struct drm_i915_private *dev_priv)
+ 		I915_WRITE(RING_MODE_GEN7(engine), irqs);
+ 
+ 	/* route USER_INTERRUPT to Host, all others are sent to GuC. */
+-	irqs = GT_RENDER_USER_INTERRUPT << GEN8_RCS_IRQ_SHIFT |
++	irqs = (GT_RENDER_USER_INTERRUPT | GT_RENDER_PIPECTL_NOTIFY_INTERRUPT)
++							<< GEN8_RCS_IRQ_SHIFT |
+ 	       GT_RENDER_USER_INTERRUPT << GEN8_BCS_IRQ_SHIFT;
+ 	/* These three registers have the same bit definitions */
+ 	I915_WRITE(GUC_BCS_RCS_IER, ~irqs);
+@@ -1289,6 +1302,58 @@ void intel_guc_submission_disable(struct intel_guc *guc)
+ 	intel_engines_reset_default_submission(dev_priv);
+ }
+ 
++int i915_guc_ipts_submission_enable(struct drm_i915_private *dev_priv,
++				    struct i915_gem_context *ctx)
++{
++	struct intel_guc *guc = &dev_priv->guc;
++	struct intel_guc_client *client;
++	int err;
++	int ret;
++
++	/* client for execbuf submission */
++	client = guc_client_alloc(dev_priv,
++				  INTEL_INFO(dev_priv)->ring_mask,
++				  GUC_CLIENT_PRIORITY_NORMAL,
++				  ctx);
++	if (IS_ERR(client)) {
++		DRM_ERROR("Failed to create normal GuC client!\n");
++		return -ENOMEM;
++	}
++
++	guc->ipts_client = client;
++
++	err = intel_guc_sample_forcewake(guc);
++	if (err)
++		return err;
++
++	ret = create_doorbell(guc->ipts_client);
++	if (ret)
++		return ret;
++
++	return 0;
++}
++
++void i915_guc_ipts_submission_disable(struct drm_i915_private *dev_priv)
++{
++	struct intel_guc *guc = &dev_priv->guc;
++
++	if (!guc->ipts_client)
++		return;
++
++	guc_client_free(guc->ipts_client);
++	guc->ipts_client = NULL;
++}
++
++void i915_guc_ipts_reacquire_doorbell(struct drm_i915_private *dev_priv)
++{
++	struct intel_guc *guc = &dev_priv->guc;
++
++	int err = __guc_allocate_doorbell(guc, guc->ipts_client->stage_id);
++
++	if (err)
++		DRM_ERROR("Not able to reacquire IPTS doorbell\n");
++}
++
+ #if IS_ENABLED(CONFIG_DRM_I915_SELFTEST)
+ #include "selftests/intel_guc.c"
+ #endif
+diff --git a/drivers/gpu/drm/i915/intel_guc_submission.h b/drivers/gpu/drm/i915/intel_guc_submission.h
+index fb081cefef93..71fc7986585a 100644
+--- a/drivers/gpu/drm/i915/intel_guc_submission.h
++++ b/drivers/gpu/drm/i915/intel_guc_submission.h
+@@ -79,5 +79,9 @@ void intel_guc_submission_disable(struct intel_guc *guc);
+ void intel_guc_submission_fini(struct intel_guc *guc);
+ int intel_guc_preempt_work_create(struct intel_guc *guc);
+ void intel_guc_preempt_work_destroy(struct intel_guc *guc);
++int i915_guc_ipts_submission_enable(struct drm_i915_private *dev_priv,
++				    struct i915_gem_context *ctx);
++void i915_guc_ipts_submission_disable(struct drm_i915_private *dev_priv);
++void i915_guc_ipts_reacquire_doorbell(struct drm_i915_private *dev_priv);
+ 
+ #endif
+diff --git a/drivers/gpu/drm/i915/intel_ipts.c b/drivers/gpu/drm/i915/intel_ipts.c
+new file mode 100644
+index 000000000000..f8cc5eaf033d
+--- /dev/null
++++ b/drivers/gpu/drm/i915/intel_ipts.c
+@@ -0,0 +1,627 @@
++/*
++ * Copyright  2016 Intel Corporation
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a
++ * copy of this software and associated documentation files (the "Software"),
++ * to deal in the Software without restriction, including without limitation
++ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
++ * and/or sell copies of the Software, and to permit persons to whom the
++ * Software is furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice (including the next
++ * paragraph) shall be included in all copies or substantial portions of the
++ * Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
++ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
++ * IN THE SOFTWARE.
++ *
++ */
++#include <linux/kernel.h>
++#include <linux/types.h>
++#include <linux/module.h>
++#include <linux/intel_ipts_if.h>
++#include <drm/drmP.h>
++
++#include "intel_guc_submission.h"
++#include "i915_drv.h"
++
++#define SUPPORTED_IPTS_INTERFACE_VERSION	1
++
++#define REACQUIRE_DB_THRESHOLD			8
++#define DB_LOST_CHECK_STEP1_INTERVAL		2000	/* ms */
++#define DB_LOST_CHECK_STEP2_INTERVAL		500	/* ms */
++
++/* intel IPTS ctx for ipts support */
++typedef struct intel_ipts {
++	struct drm_device *dev;
++	struct i915_gem_context *ipts_context;
++	intel_ipts_callback_t ipts_clbks;
++
++	/* buffers' list */
++	struct {
++		spinlock_t       lock;
++		struct list_head list;
++	} buffers;
++
++	void *data;
++
++	struct delayed_work reacquire_db_work;
++	intel_ipts_wq_info_t wq_info;
++	u32	old_tail;
++	u32	old_head;
++	bool	need_reacquire_db;
++
++	bool	connected;
++	bool	initialized;
++} intel_ipts_t;
++
++intel_ipts_t intel_ipts;
++
++typedef struct intel_ipts_object {
++	struct list_head list;
++	struct drm_i915_gem_object *gem_obj;
++	void	*cpu_addr;
++} intel_ipts_object_t;
++
++static intel_ipts_object_t *ipts_object_create(size_t size, u32 flags)
++{
++	struct drm_i915_private *dev_priv = to_i915(intel_ipts.dev);
++	intel_ipts_object_t *obj = NULL;
++	struct drm_i915_gem_object *gem_obj = NULL;
++	int ret = 0;
++
++	obj = kzalloc(sizeof(*obj), GFP_KERNEL);
++	if (!obj)
++		return NULL;
++
++	size = roundup(size, PAGE_SIZE);
++	if (size == 0) {
++		ret = -EINVAL;
++		goto err_out;
++	}
++
++	/* Allocate the new object */
++	gem_obj = i915_gem_object_create(dev_priv, size);
++	if (gem_obj == NULL) {
++		ret = -ENOMEM;
++		goto err_out;
++	}
++
++	if (flags & IPTS_BUF_FLAG_CONTIGUOUS) {
++		ret = i915_gem_object_attach_phys(gem_obj, PAGE_SIZE);
++		if (ret) {
++			pr_info(">> ipts no contiguous : %d\n", ret);
++			goto err_out;
++		}
++	}
++
++	obj->gem_obj = gem_obj;
++
++	spin_lock(&intel_ipts.buffers.lock);
++	list_add_tail(&obj->list, &intel_ipts.buffers.list);
++	spin_unlock(&intel_ipts.buffers.lock);
++
++	return obj;
++
++err_out:
++	if (gem_obj)
++		i915_gem_free_object(&gem_obj->base);
++
++	if (obj)
++		kfree(obj);
++
++	return NULL;
++}
++
++static void ipts_object_free(intel_ipts_object_t* obj)
++{
++	spin_lock(&intel_ipts.buffers.lock);
++	list_del(&obj->list);
++	spin_unlock(&intel_ipts.buffers.lock);
++
++	i915_gem_free_object(&obj->gem_obj->base);
++	kfree(obj);
++}
++
++static int ipts_object_pin(intel_ipts_object_t* obj,
++					struct i915_gem_context *ipts_ctx)
++{
++	struct i915_address_space *vm = NULL;
++	struct i915_vma *vma = NULL;
++	struct drm_i915_private *dev_priv = to_i915(intel_ipts.dev);
++	int ret = 0;
++
++	if (ipts_ctx->ppgtt) {
++		vm = &ipts_ctx->ppgtt->base;
++	} else {
++		vm = &dev_priv->ggtt.base;
++	}
++
++	vma = i915_vma_instance(obj->gem_obj, vm, NULL);
++	if (IS_ERR(vma)) {
++		DRM_ERROR("cannot find or create vma\n");
++		return -1;
++	}
++
++	ret = i915_vma_pin(vma, 0, PAGE_SIZE, PIN_USER);
++
++	return ret;
++}
++
++static void ipts_object_unpin(intel_ipts_object_t *obj)
++{
++	/* TBD: Add support */
++}
++
++static void* ipts_object_map(intel_ipts_object_t *obj)
++{
++
++	return i915_gem_object_pin_map(obj->gem_obj, I915_MAP_WB);
++}
++
++static void ipts_object_unmap(intel_ipts_object_t* obj)
++{
++	i915_gem_object_unpin_map(obj->gem_obj);
++	obj->cpu_addr = NULL;
++}
++
++static int create_ipts_context(void)
++{
++	struct i915_gem_context *ipts_ctx = NULL;
++	struct drm_i915_private *dev_priv = to_i915(intel_ipts.dev);
++	struct intel_ring *pin_ret;
++	int ret = 0;
++
++	/* Initialize the context right away.*/
++	ret = i915_mutex_lock_interruptible(intel_ipts.dev);
++	if (ret) {
++		DRM_ERROR("i915_mutex_lock_interruptible failed \n");
++		return ret;
++	}
++
++	ipts_ctx = i915_gem_context_create_ipts(intel_ipts.dev);
++	if (IS_ERR(ipts_ctx)) {
++		DRM_ERROR("Failed to create IPTS context (error %ld)\n",
++			  PTR_ERR(ipts_ctx));
++		ret = PTR_ERR(ipts_ctx);
++		goto err_unlock;
++	}
++
++	ret = execlists_context_deferred_alloc(ipts_ctx, dev_priv->engine[RCS]);
++	if (ret) {
++		DRM_DEBUG("lr context allocation failed : %d\n", ret);
++		goto err_ctx;
++	}
++
++	pin_ret = execlists_context_pin(dev_priv->engine[RCS], ipts_ctx);
++	if (IS_ERR(pin_ret)) {
++		DRM_DEBUG("lr context pinning failed :  %ld\n", PTR_ERR(pin_ret));
++		goto err_ctx;
++	}
++
++	/* Release the mutex */
++	mutex_unlock(&intel_ipts.dev->struct_mutex);
++
++	spin_lock_init(&intel_ipts.buffers.lock);
++	INIT_LIST_HEAD(&intel_ipts.buffers.list);
++
++	intel_ipts.ipts_context = ipts_ctx;
++
++	return 0;
++
++err_ctx:
++	if (ipts_ctx)
++		i915_gem_context_put(ipts_ctx);
++
++err_unlock:
++	mutex_unlock(&intel_ipts.dev->struct_mutex);
++
++	return ret;
++}
++
++static void destroy_ipts_context(void)
++{
++	struct i915_gem_context *ipts_ctx = NULL;
++	struct drm_i915_private *dev_priv = to_i915(intel_ipts.dev);
++	int ret = 0;
++
++	ipts_ctx = intel_ipts.ipts_context;
++
++	/* Initialize the context right away.*/
++	ret = i915_mutex_lock_interruptible(intel_ipts.dev);
++	if (ret) {
++		DRM_ERROR("i915_mutex_lock_interruptible failed \n");
++		return;
++	}
++
++	execlists_context_unpin(dev_priv->engine[RCS], ipts_ctx);
++	i915_gem_context_put(ipts_ctx);
++
++	mutex_unlock(&intel_ipts.dev->struct_mutex);
++}
++
++int intel_ipts_notify_complete(void)
++{
++	if (intel_ipts.ipts_clbks.workload_complete)
++		intel_ipts.ipts_clbks.workload_complete(intel_ipts.data);
++
++	return 0;
++}
++
++int intel_ipts_notify_backlight_status(bool backlight_on)
++{
++	if (intel_ipts.ipts_clbks.notify_gfx_status) {
++		if (backlight_on) {
++			intel_ipts.ipts_clbks.notify_gfx_status(
++						IPTS_NOTIFY_STA_BACKLIGHT_ON,
++						intel_ipts.data);
++			schedule_delayed_work(&intel_ipts.reacquire_db_work,
++				msecs_to_jiffies(DB_LOST_CHECK_STEP1_INTERVAL));
++		} else {
++			intel_ipts.ipts_clbks.notify_gfx_status(
++						IPTS_NOTIFY_STA_BACKLIGHT_OFF,
++						intel_ipts.data);
++			cancel_delayed_work(&intel_ipts.reacquire_db_work);
++		}
++	}
++
++	return 0;
++}
++
++static void intel_ipts_reacquire_db(intel_ipts_t *intel_ipts_p)
++{
++	int ret = 0;
++
++	ret = i915_mutex_lock_interruptible(intel_ipts_p->dev);
++	if (ret) {
++		DRM_ERROR("i915_mutex_lock_interruptible failed \n");
++		return;
++	}
++
++	/* Reacquire the doorbell */
++	i915_guc_ipts_reacquire_doorbell(intel_ipts_p->dev->dev_private);
++
++	mutex_unlock(&intel_ipts_p->dev->struct_mutex);
++
++	return;
++}
++
++static int intel_ipts_get_wq_info(uint64_t gfx_handle,
++						intel_ipts_wq_info_t *wq_info)
++{
++	if (gfx_handle != (uint64_t)&intel_ipts) {
++		DRM_ERROR("invalid gfx handle\n");
++		return -EINVAL;
++	}
++
++	*wq_info = intel_ipts.wq_info;
++
++	intel_ipts_reacquire_db(&intel_ipts);
++	schedule_delayed_work(&intel_ipts.reacquire_db_work,
++				msecs_to_jiffies(DB_LOST_CHECK_STEP1_INTERVAL));
++
++	return 0;
++}
++
++static int set_wq_info(void)
++{
++	struct drm_i915_private *dev_priv = to_i915(intel_ipts.dev);
++	struct intel_guc *guc = &dev_priv->guc;
++	struct intel_guc_client *client;
++	struct guc_process_desc *desc;
++	void *base = NULL;
++	intel_ipts_wq_info_t *wq_info;
++	u64 phy_base = 0;
++
++	wq_info = &intel_ipts.wq_info;
++
++	client = guc->ipts_client;
++	if (!client) {
++		DRM_ERROR("IPTS GuC client is NOT available\n");
++		return -EINVAL;
++	}
++
++	base = client->vaddr;
++	desc = (struct guc_process_desc *)((u64)base + client->proc_desc_offset);
++
++	desc->wq_base_addr = (u64)base + GUC_DB_SIZE;
++	desc->db_base_addr = (u64)base + client->doorbell_offset;
++
++	/* IPTS expects physical addresses to pass it to ME */
++	phy_base = sg_dma_address(client->vma->pages->sgl);
++
++	wq_info->db_addr = desc->db_base_addr;
++        wq_info->db_phy_addr = phy_base + client->doorbell_offset;
++        wq_info->db_cookie_offset = offsetof(struct guc_doorbell_info, cookie);
++        wq_info->wq_addr = desc->wq_base_addr;
++        wq_info->wq_phy_addr = phy_base + GUC_DB_SIZE;
++        wq_info->wq_head_addr = (u64)&desc->head;
++        wq_info->wq_head_phy_addr = phy_base + client->proc_desc_offset +
++					offsetof(struct guc_process_desc, head);
++        wq_info->wq_tail_addr = (u64)&desc->tail;
++        wq_info->wq_tail_phy_addr = phy_base + client->proc_desc_offset +
++					offsetof(struct guc_process_desc, tail);
++        wq_info->wq_size = desc->wq_size_bytes;
++
++	return 0;
++}
++
++static int intel_ipts_init_wq(void)
++{
++	int ret = 0;
++
++	ret = i915_mutex_lock_interruptible(intel_ipts.dev);
++	if (ret) {
++		DRM_ERROR("i915_mutex_lock_interruptible failed\n");
++		return ret;
++	}
++
++	/* disable IPTS submission */
++	i915_guc_ipts_submission_disable(intel_ipts.dev->dev_private);
++
++	/* enable IPTS submission */
++	ret = i915_guc_ipts_submission_enable(intel_ipts.dev->dev_private,
++							intel_ipts.ipts_context);
++	if (ret) {
++		DRM_ERROR("i915_guc_ipts_submission_enable failed : %d\n", ret);
++		goto out;
++        }
++
++	ret = set_wq_info();
++	if (ret) {
++		DRM_ERROR("set_wq_info failed\n");
++		goto out;
++	}
++
++out:
++	mutex_unlock(&intel_ipts.dev->struct_mutex);
++
++	return ret;
++}
++
++static void intel_ipts_release_wq(void)
++{
++	int ret = 0;
++
++	ret = i915_mutex_lock_interruptible(intel_ipts.dev);
++	if (ret) {
++		DRM_ERROR("i915_mutex_lock_interruptible failed\n");
++		return;
++	}
++
++	/* disable IPTS submission */
++	i915_guc_ipts_submission_disable(intel_ipts.dev->dev_private);
++
++	mutex_unlock(&intel_ipts.dev->struct_mutex);
++}
++
++static int intel_ipts_map_buffer(u64 gfx_handle, intel_ipts_mapbuffer_t *mapbuf)
++{
++	intel_ipts_object_t* obj;
++	struct i915_gem_context *ipts_ctx = NULL;
++	struct drm_i915_private *dev_priv = to_i915(intel_ipts.dev);
++	struct i915_address_space *vm = NULL;
++	struct i915_vma *vma = NULL;
++	int ret = 0;
++
++	if (gfx_handle != (uint64_t)&intel_ipts) {
++		DRM_ERROR("invalid gfx handle\n");
++		return -EINVAL;
++	}
++
++	/* Acquire mutex first */
++	ret = i915_mutex_lock_interruptible(intel_ipts.dev);
++	if (ret) {
++		DRM_ERROR("i915_mutex_lock_interruptible failed \n");
++		return -EINVAL;
++	}
++
++	obj = ipts_object_create(mapbuf->size, mapbuf->flags);
++	if (!obj)
++		return -ENOMEM;
++
++	ipts_ctx = intel_ipts.ipts_context;
++	ret = ipts_object_pin(obj, ipts_ctx);
++	if (ret) {
++		DRM_ERROR("Not able to pin iTouch obj\n");
++		ipts_object_free(obj);
++		mutex_unlock(&intel_ipts.dev->struct_mutex);
++		return -ENOMEM;
++	}
++
++	if (mapbuf->flags & IPTS_BUF_FLAG_CONTIGUOUS) {
++		obj->cpu_addr = obj->gem_obj->phys_handle->vaddr;
++	} else {
++		obj->cpu_addr = ipts_object_map(obj);
++	}
++
++	if (ipts_ctx->ppgtt) {
++		vm = &ipts_ctx->ppgtt->base;
++	} else {
++		vm = &dev_priv->ggtt.base;
++	}
++
++	vma = i915_vma_instance(obj->gem_obj, vm, NULL);
++	if (IS_ERR(vma)) {
++		DRM_ERROR("cannot find or create vma\n");
++		return -EINVAL;
++	}
++
++	mapbuf->gfx_addr = (void*)vma->node.start;
++	mapbuf->cpu_addr = (void*)obj->cpu_addr;
++	mapbuf->buf_handle = (u64)obj;
++	if (mapbuf->flags & IPTS_BUF_FLAG_CONTIGUOUS) {
++		mapbuf->phy_addr = (u64)obj->gem_obj->phys_handle->busaddr;
++	}
++
++	/* Release the mutex */
++	mutex_unlock(&intel_ipts.dev->struct_mutex);
++
++	return 0;
++}
++
++static int intel_ipts_unmap_buffer(uint64_t gfx_handle, uint64_t buf_handle)
++{
++	intel_ipts_object_t* obj = (intel_ipts_object_t*)buf_handle;
++
++	if (gfx_handle != (uint64_t)&intel_ipts) {
++		DRM_ERROR("invalid gfx handle\n");
++		return -EINVAL;
++	}
++
++	if (!obj->gem_obj->phys_handle)
++		ipts_object_unmap(obj);
++	ipts_object_unpin(obj);
++	ipts_object_free(obj);
++
++	return 0;
++}
++
++int intel_ipts_connect(intel_ipts_connect_t *ipts_connect)
++{
++	struct drm_i915_private *dev_priv = to_i915(intel_ipts.dev);
++	int ret = 0;
++
++	if (!intel_ipts.initialized)
++		return -EIO;
++
++	if (ipts_connect && ipts_connect->if_version <=
++					SUPPORTED_IPTS_INTERFACE_VERSION) {
++
++		/* return gpu operations for ipts */
++		ipts_connect->ipts_ops.get_wq_info = intel_ipts_get_wq_info;
++		ipts_connect->ipts_ops.map_buffer = intel_ipts_map_buffer;
++		ipts_connect->ipts_ops.unmap_buffer = intel_ipts_unmap_buffer;
++		ipts_connect->gfx_version = INTEL_INFO(dev_priv)->gen;
++		ipts_connect->gfx_handle = (uint64_t)&intel_ipts;
++
++		/* save callback and data */
++		intel_ipts.data = ipts_connect->data;
++		intel_ipts.ipts_clbks = ipts_connect->ipts_cb;
++
++		intel_ipts.connected = true;
++	} else {
++		ret = -EINVAL;
++	}
++
++	return ret;
++}
++EXPORT_SYMBOL_GPL(intel_ipts_connect);
++
++void intel_ipts_disconnect(uint64_t gfx_handle)
++{
++	if (!intel_ipts.initialized)
++		return;
++
++	if (gfx_handle != (uint64_t)&intel_ipts ||
++					intel_ipts.connected == false) {
++		DRM_ERROR("invalid gfx handle\n");
++		return;
++	}
++
++	intel_ipts.data = 0;
++	memset(&intel_ipts.ipts_clbks, 0, sizeof(intel_ipts_callback_t));
++
++	intel_ipts.connected = false;
++}
++EXPORT_SYMBOL_GPL(intel_ipts_disconnect);
++
++static void reacquire_db_work_func(struct work_struct *work)
++{
++	struct delayed_work *d_work = container_of(work, struct delayed_work,
++							work);
++	intel_ipts_t *intel_ipts_p = container_of(d_work, intel_ipts_t,
++							reacquire_db_work);
++	u32 head;
++	u32 tail;
++	u32 size;
++	u32 load;
++
++	head = *(u32*)intel_ipts_p->wq_info.wq_head_addr;
++	tail = *(u32*)intel_ipts_p->wq_info.wq_tail_addr;
++	size = intel_ipts_p->wq_info.wq_size;
++
++	if (head >= tail)
++		load = head - tail;
++	else
++		load = head + size - tail;
++
++	if (load < REACQUIRE_DB_THRESHOLD) {
++		intel_ipts_p->need_reacquire_db = false;
++		goto reschedule_work;
++	}
++
++	if (intel_ipts_p->need_reacquire_db) {
++		if (intel_ipts_p->old_head == head && intel_ipts_p->old_tail == tail)
++			intel_ipts_reacquire_db(intel_ipts_p);
++		intel_ipts_p->need_reacquire_db = false;
++	} else {
++		intel_ipts_p->old_head = head;
++		intel_ipts_p->old_tail = tail;
++		intel_ipts_p->need_reacquire_db = true;
++
++		/* recheck */
++		schedule_delayed_work(&intel_ipts_p->reacquire_db_work,
++				msecs_to_jiffies(DB_LOST_CHECK_STEP2_INTERVAL));
++		return;
++	}
++
++reschedule_work:
++	schedule_delayed_work(&intel_ipts_p->reacquire_db_work,
++				msecs_to_jiffies(DB_LOST_CHECK_STEP1_INTERVAL));
++}
++
++/**
++ * intel_ipts_init - Initialize ipts support
++ * @dev: drm device
++ *
++ * Setup the required structures for ipts.
++ */
++int intel_ipts_init(struct drm_device *dev)
++{
++	int ret = 0;
++
++	pr_info("ipts: initializing ipts\n");
++
++	intel_ipts.dev = dev;
++	INIT_DELAYED_WORK(&intel_ipts.reacquire_db_work, reacquire_db_work_func);
++
++	ret = create_ipts_context();
++	if (ret)
++		return -ENOMEM;
++
++	ret = intel_ipts_init_wq();
++	if (ret)
++		return ret;
++
++	intel_ipts.initialized = true;
++	DRM_DEBUG_DRIVER("Intel iTouch framework initialized\n");
++
++	return ret;
++}
++
++void intel_ipts_cleanup(struct drm_device *dev)
++{
++	intel_ipts_object_t *obj, *n;
++
++	if (intel_ipts.dev == dev) {
++		list_for_each_entry_safe(obj, n, &intel_ipts.buffers.list, list) {
++			list_del(&obj->list);
++
++			if (!obj->gem_obj->phys_handle)
++				ipts_object_unmap(obj);
++			ipts_object_unpin(obj);
++			i915_gem_free_object(&obj->gem_obj->base);
++			kfree(obj);
++		}
++
++		intel_ipts_release_wq();
++		destroy_ipts_context();
++		cancel_delayed_work(&intel_ipts.reacquire_db_work);
++	}
++}
+diff --git a/drivers/gpu/drm/i915/intel_ipts.h b/drivers/gpu/drm/i915/intel_ipts.h
+new file mode 100644
+index 000000000000..a6965d102417
+--- /dev/null
++++ b/drivers/gpu/drm/i915/intel_ipts.h
+@@ -0,0 +1,34 @@
++/*
++ * Copyright © 2016 Intel Corporation
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a
++ * copy of this software and associated documentation files (the "Software"),
++ * to deal in the Software without restriction, including without limitation
++ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
++ * and/or sell copies of the Software, and to permit persons to whom the
++ * Software is furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice (including the next
++ * paragraph) shall be included in all copies or substantial portions of the
++ * Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
++ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
++ * IN THE SOFTWARE.
++ *
++ */
++#ifndef _INTEL_IPTS_H_
++#define _INTEL_IPTS_H_
++
++struct drm_device;
++
++int intel_ipts_init(struct drm_device *dev);
++void intel_ipts_cleanup(struct drm_device *dev);
++int intel_ipts_notify_backlight_status(bool backlight_on);
++int intel_ipts_notify_complete(void);
++
++#endif //_INTEL_IPTS_H_
+diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c
+index 7c4c8fb1dae4..88cab775a4d2 100644
+--- a/drivers/gpu/drm/i915/intel_lrc.c
++++ b/drivers/gpu/drm/i915/intel_lrc.c
+@@ -163,8 +163,6 @@
+ #define WA_TAIL_DWORDS 2
+ #define WA_TAIL_BYTES (sizeof(u32) * WA_TAIL_DWORDS)
+ 
+-static int execlists_context_deferred_alloc(struct i915_gem_context *ctx,
+-					    struct intel_engine_cs *engine);
+ static void execlists_init_reg_state(u32 *reg_state,
+ 				     struct i915_gem_context *ctx,
+ 				     struct intel_engine_cs *engine,
+@@ -1345,7 +1343,7 @@ static int __context_pin(struct i915_gem_context *ctx, struct i915_vma *vma)
+ 	return i915_vma_pin(vma, 0, GEN8_LR_CONTEXT_ALIGN, flags);
+ }
+ 
+-static struct intel_ring *
++struct intel_ring *
+ execlists_context_pin(struct intel_engine_cs *engine,
+ 		      struct i915_gem_context *ctx)
+ {
+@@ -1399,7 +1397,7 @@ execlists_context_pin(struct intel_engine_cs *engine,
+ 	return ERR_PTR(ret);
+ }
+ 
+-static void execlists_context_unpin(struct intel_engine_cs *engine,
++void execlists_context_unpin(struct intel_engine_cs *engine,
+ 				    struct i915_gem_context *ctx)
+ {
+ 	struct intel_context *ce = to_intel_context(ctx, engine);
+@@ -2364,6 +2362,9 @@ int logical_render_ring_init(struct intel_engine_cs *engine)
+ 
+ 	logical_ring_setup(engine);
+ 
++	engine->irq_keep_mask |= GT_RENDER_PIPECTL_NOTIFY_INTERRUPT
++							<< GEN8_RCS_IRQ_SHIFT;
++
+ 	if (HAS_L3_DPF(dev_priv))
+ 		engine->irq_keep_mask |= GT_RENDER_L3_PARITY_ERROR_INTERRUPT;
+ 
+@@ -2628,7 +2629,7 @@ populate_lr_context(struct i915_gem_context *ctx,
+ 	return ret;
+ }
+ 
+-static int execlists_context_deferred_alloc(struct i915_gem_context *ctx,
++int execlists_context_deferred_alloc(struct i915_gem_context *ctx,
+ 					    struct intel_engine_cs *engine)
+ {
+ 	struct drm_i915_gem_object *ctx_obj;
+diff --git a/drivers/gpu/drm/i915/intel_lrc.h b/drivers/gpu/drm/i915/intel_lrc.h
+index 4ec7d8dd13c8..7b63b5b6d6bc 100644
+--- a/drivers/gpu/drm/i915/intel_lrc.h
++++ b/drivers/gpu/drm/i915/intel_lrc.h
+@@ -111,4 +111,12 @@ intel_lr_context_descriptor(struct i915_gem_context *ctx,
+ 	return to_intel_context(ctx, engine)->lrc_desc;
+ }
+ 
++struct intel_ring *
++execlists_context_pin(struct intel_engine_cs *engine,
++		      struct i915_gem_context *ctx);
++void execlists_context_unpin(struct intel_engine_cs *engine,
++				    struct i915_gem_context *ctx);
++int execlists_context_deferred_alloc(struct i915_gem_context *ctx,
++					    struct intel_engine_cs *engine);
++
+ #endif /* _INTEL_LRC_H_ */
+diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c
+index b443278e569c..4e44ae7c3387 100644
+--- a/drivers/gpu/drm/i915/intel_panel.c
++++ b/drivers/gpu/drm/i915/intel_panel.c
+@@ -34,6 +34,7 @@
+ #include <linux/moduleparam.h>
+ #include <linux/pwm.h>
+ #include "intel_drv.h"
++#include "intel_ipts.h"
+ 
+ #define CRC_PMIC_PWM_PERIOD_NS	21333
+ 
+@@ -679,6 +680,9 @@ static void lpt_disable_backlight(const struct drm_connector_state *old_conn_sta
+ 	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+ 	u32 tmp;
+ 
++	if (INTEL_GEN(dev_priv) >= 9 && i915_modparams.enable_guc && i915_modparams.enable_ipts)
++		intel_ipts_notify_backlight_status(false);
++
+ 	intel_panel_actually_set_backlight(old_conn_state, 0);
+ 
+ 	/*
+@@ -866,6 +870,9 @@ static void lpt_enable_backlight(const struct intel_crtc_state *crtc_state,
+ 
+ 	/* This won't stick until the above enable. */
+ 	intel_panel_actually_set_backlight(conn_state, panel->backlight.level);
++
++	if (INTEL_GEN(dev_priv) >= 9 && i915_modparams.enable_guc && i915_modparams.enable_ipts)
++		intel_ipts_notify_backlight_status(true);
+ }
+ 
+ static void pch_enable_backlight(const struct intel_crtc_state *crtc_state,
+diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
+index 45968f7970f8..a0e053c4dc1c 100644
+--- a/drivers/hid/hid-multitouch.c
++++ b/drivers/hid/hid-multitouch.c
+@@ -151,6 +151,7 @@ struct mt_device {
+ 
+ static void mt_post_parse_default_settings(struct mt_device *td);
+ static void mt_post_parse(struct mt_device *td);
++static int cc_seen = 0;
+ 
+ /* classes of device behavior */
+ #define MT_CLS_DEFAULT				0x0001
+@@ -614,8 +615,12 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
+ 			if (field->index >= field->report->maxfield ||
+ 			    usage->usage_index >= field->report_count)
+ 				return 1;
+-			td->cc_index = field->index;
+-			td->cc_value_index = usage->usage_index;
++
++			if(cc_seen != 1) {
++				td->cc_index = field->index;
++				td->cc_value_index = usage->usage_index;
++				cc_seen++;
++			}
+ 			return 1;
+ 		case HID_DG_AZIMUTH:
+ 			hid_map_usage(hi, usage, bit, max,
+@@ -666,6 +671,16 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
+ 	return 0;
+ }
+ 
++static int mt_touch_input_mapped(struct hid_device *hdev, struct hid_input *hi,
++		struct hid_field *field, struct hid_usage *usage,
++		unsigned long **bit, int *max)
++{
++	if (usage->type == EV_KEY || usage->type == EV_ABS)
++		set_bit(usage->type, hi->input->evbit);
++
++	return -1;
++}
++
+ static int mt_compute_slot(struct mt_device *td, struct input_dev *input)
+ {
+ 	__s32 quirks = td->mtclass.quirks;
+@@ -1062,9 +1077,11 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
+ 	    field->application != HID_DG_TOUCHSCREEN &&
+ 	    field->application != HID_DG_PEN &&
+ 	    field->application != HID_DG_TOUCHPAD &&
++		field->application != HID_GD_MOUSE &&
+ 	    field->application != HID_GD_KEYBOARD &&
+ 	    field->application != HID_GD_SYSTEM_CONTROL &&
+ 	    field->application != HID_CP_CONSUMER_CONTROL &&
++		field->logical != HID_DG_TOUCHSCREEN &&
+ 	    field->application != HID_GD_WIRELESS_RADIO_CTLS &&
+ 	    !(field->application == HID_VD_ASUS_CUSTOM_MEDIA_KEYS &&
+ 	      td->mtclass.quirks & MT_QUIRK_ASUS_CUSTOM_UP))
+@@ -1127,10 +1144,8 @@ static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi,
+ 		return 0;
+ 
+ 	if (field->application == HID_DG_TOUCHSCREEN ||
+-	    field->application == HID_DG_TOUCHPAD) {
+-		/* We own these mappings, tell hid-input to ignore them */
+-		return -1;
+-	}
++	    field->application == HID_DG_TOUCHPAD)
++		return mt_touch_input_mapped(hdev, hi, field, usage, bit, max);
+ 
+ 	/* let hid-core decide for the others */
+ 	return 0;
+@@ -1315,6 +1330,7 @@ static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi)
+ 			suffix = "Pen";
+ 			/* force BTN_STYLUS to allow tablet matching in udev */
+ 			__set_bit(BTN_STYLUS, hi->input->keybit);
++            __set_bit(INPUT_PROP_DIRECT, hi->input->propbit);
+ 		}
+ 	}
+ 
+@@ -1330,12 +1346,13 @@ static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi)
+ 			/* already handled by hid core */
+ 			break;
+ 		case HID_DG_TOUCHSCREEN:
+-			/* we do not set suffix = "Touchscreen" */
++			suffix = "Touchscreen";
+ 			hi->input->name = hdev->name;
+ 			break;
+ 		case HID_DG_STYLUS:
+ 			/* force BTN_STYLUS to allow tablet matching in udev */
+ 			__set_bit(BTN_STYLUS, hi->input->keybit);
++            __set_bit(INPUT_PROP_DIRECT, hi->input->propbit);
+ 			break;
+ 		case HID_VD_ASUS_CUSTOM_MEDIA_KEYS:
+ 			suffix = "Custom Media Keys";
+@@ -1452,6 +1469,7 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
+ 	td->cc_index = -1;
+ 	td->scantime_index = -1;
+ 	td->mt_report_id = -1;
++	cc_seen = 0;
+ 	hid_set_drvdata(hdev, td);
+ 
+ 	td->fields = devm_kzalloc(&hdev->dev, sizeof(struct mt_fields),
+diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
+index 3726eacdf65d..77263b5f5915 100644
+--- a/drivers/misc/Kconfig
++++ b/drivers/misc/Kconfig
+@@ -520,6 +520,7 @@ source "drivers/misc/ti-st/Kconfig"
+ source "drivers/misc/lis3lv02d/Kconfig"
+ source "drivers/misc/altera-stapl/Kconfig"
+ source "drivers/misc/mei/Kconfig"
++source "drivers/misc/ipts/Kconfig"
+ source "drivers/misc/vmw_vmci/Kconfig"
+ source "drivers/misc/mic/Kconfig"
+ source "drivers/misc/genwqe/Kconfig"
+diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
+index af22bbc3d00c..eb1eb0d58c32 100644
+--- a/drivers/misc/Makefile
++++ b/drivers/misc/Makefile
+@@ -44,6 +44,7 @@ obj-y				+= lis3lv02d/
+ obj-$(CONFIG_USB_SWITCH_FSA9480) += fsa9480.o
+ obj-$(CONFIG_ALTERA_STAPL)	+=altera-stapl/
+ obj-$(CONFIG_INTEL_MEI)		+= mei/
++obj-$(CONFIG_INTEL_IPTS)	+= ipts/
+ obj-$(CONFIG_VMWARE_VMCI)	+= vmw_vmci/
+ obj-$(CONFIG_LATTICE_ECP3_CONFIG)	+= lattice-ecp3-config.o
+ obj-$(CONFIG_SRAM)		+= sram.o
+diff --git a/drivers/misc/ipts/Kconfig b/drivers/misc/ipts/Kconfig
+new file mode 100644
+index 000000000000..360ed3861b82
+--- /dev/null
++++ b/drivers/misc/ipts/Kconfig
+@@ -0,0 +1,9 @@
++config INTEL_IPTS
++	tristate "Intel Precise Touch & Stylus"
++	select INTEL_MEI
++	depends on X86 && PCI && HID
++	help
++	  Intel Precise Touch & Stylus support
++	  Supported SoCs:
++	  Intel Skylake
++	  Intel Kabylake
+diff --git a/drivers/misc/ipts/Makefile b/drivers/misc/ipts/Makefile
+new file mode 100644
+index 000000000000..1783e9cf13c9
+--- /dev/null
++++ b/drivers/misc/ipts/Makefile
+@@ -0,0 +1,13 @@
++#
++# Makefile - Intel Precise Touch & Stylus device driver
++# Copyright (c) 2016, Intel Corporation.
++#
++
++obj-$(CONFIG_INTEL_IPTS)+= intel-ipts.o
++intel-ipts-objs += ipts-mei.o
++intel-ipts-objs += ipts-hid.o
++intel-ipts-objs += ipts-msg-handler.o
++intel-ipts-objs += ipts-kernel.o
++intel-ipts-objs += ipts-resource.o
++intel-ipts-objs += ipts-gfx.o
++intel-ipts-$(CONFIG_DEBUG_FS) += ipts-dbgfs.o
+diff --git a/drivers/misc/ipts/ipts-binary-spec.h b/drivers/misc/ipts/ipts-binary-spec.h
+new file mode 100644
+index 000000000000..87d4bc4133c4
+--- /dev/null
++++ b/drivers/misc/ipts/ipts-binary-spec.h
+@@ -0,0 +1,118 @@
++/*
++ *
++ * Intel Precise Touch & Stylus binary spec
++ * Copyright (c) 2016 Intel Corporation.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms and conditions of the GNU General Public License,
++ * version 2, as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
++ * more details.
++ *
++ */
++
++#ifndef _IPTS_BINARY_SPEC_H
++#define _IPTS_BINARY_SPEC_H
++
++#define IPTS_BIN_HEADER_VERSION 2
++
++#pragma pack(1)
++
++/* we support 16 output buffers(1:feedback, 15:HID) */
++#define  MAX_NUM_OUTPUT_BUFFERS 16
++
++typedef enum {
++	IPTS_BIN_KERNEL,
++	IPTS_BIN_RO_DATA,
++	IPTS_BIN_RW_DATA,
++	IPTS_BIN_SENSOR_FRAME,
++	IPTS_BIN_OUTPUT,
++	IPTS_BIN_DYNAMIC_STATE_HEAP,
++	IPTS_BIN_PATCH_LOCATION_LIST,
++	IPTS_BIN_ALLOCATION_LIST,
++	IPTS_BIN_COMMAND_BUFFER_PACKET,
++	IPTS_BIN_TAG,
++} ipts_bin_res_type_t;
++
++typedef struct ipts_bin_header {
++	char str[4];
++	unsigned int version;
++
++#if IPTS_BIN_HEADER_VERSION > 1
++	unsigned int gfxcore;
++	unsigned int revid;
++#endif
++} ipts_bin_header_t;
++
++typedef struct ipts_bin_alloc {
++	unsigned int handle;
++	unsigned int reserved;
++} ipts_bin_alloc_t;
++
++typedef struct ipts_bin_alloc_list {
++	unsigned int num;
++	ipts_bin_alloc_t alloc[];
++} ipts_bin_alloc_list_t;
++
++typedef struct ipts_bin_cmdbuf {
++	unsigned int size;
++	char data[];
++} ipts_bin_cmdbuf_t;
++
++typedef struct ipts_bin_res {
++	unsigned int handle;
++	ipts_bin_res_type_t type;
++	unsigned int initialize;
++	unsigned int aligned_size;
++	unsigned int size;
++	char data[];
++} ipts_bin_res_t;
++
++typedef enum {
++	IPTS_INPUT,
++	IPTS_OUTPUT,
++	IPTS_CONFIGURATION,
++	IPTS_CALIBRATION,
++	IPTS_FEATURE,
++} ipts_bin_io_buffer_type_t;
++
++typedef struct ipts_bin_io_header {
++	char str[10];
++	unsigned short type;
++} ipts_bin_io_header_t;
++
++typedef struct ipts_bin_res_list {
++	unsigned int num;
++	ipts_bin_res_t res[];
++} ipts_bin_res_list_t;
++
++typedef struct ipts_bin_patch {
++	unsigned int index;
++	unsigned int reserved1[2];
++	unsigned int alloc_offset;
++	unsigned int patch_offset;
++	unsigned int reserved2;
++} ipts_bin_patch_t;
++
++typedef struct ipts_bin_patch_list {
++	unsigned int num;
++	ipts_bin_patch_t patch[];
++} ipts_bin_patch_list_t;
++
++typedef struct ipts_bin_guc_wq_info {
++	unsigned int batch_offset;
++	unsigned int size;
++	char data[];
++} ipts_bin_guc_wq_info_t;
++
++typedef struct ipts_bin_bufid_patch {
++	unsigned int imm_offset;
++	unsigned int mem_offset;
++} ipts_bin_bufid_patch_t;
++
++#pragma pack()
++
++#endif /* _IPTS_BINARY_SPEC_H */
+diff --git a/drivers/misc/ipts/ipts-dbgfs.c b/drivers/misc/ipts/ipts-dbgfs.c
+new file mode 100644
+index 000000000000..1c5c92f7d4ba
+--- /dev/null
++++ b/drivers/misc/ipts/ipts-dbgfs.c
+@@ -0,0 +1,152 @@
++/*
++ * Intel Precise Touch & Stylus device driver
++ * Copyright (c) 2016, Intel Corporation.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms and conditions of the GNU General Public License,
++ * version 2, as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
++ * more details.
++ *
++ */
++#include <linux/debugfs.h>
++#include <linux/ctype.h>
++#include <linux/uaccess.h>
++
++#include "ipts.h"
++#include "ipts-sensor-regs.h"
++#include "ipts-msg-handler.h"
++#include "ipts-state.h"
++
++const char sensor_mode_fmt[] = "sensor mode : %01d\n";
++const char ipts_status_fmt[] = "sensor mode : %01d\nipts state : %01d\n";
++
++static ssize_t ipts_dbgfs_mode_read(struct file *fp, char __user *ubuf,
++						size_t cnt, loff_t *ppos)
++{
++	ipts_info_t *ipts = fp->private_data;
++	char mode[80];
++	int len = 0;
++
++	if (cnt < sizeof(sensor_mode_fmt) - 3)
++		return -EINVAL;
++
++	len = scnprintf(mode, 80, sensor_mode_fmt, ipts->sensor_mode);
++	if (len < 0)
++		return -EIO;
++
++	return simple_read_from_buffer(ubuf, cnt, ppos, mode, len);
++}
++
++static ssize_t ipts_dbgfs_mode_write(struct file *fp, const char __user *ubuf,
++						size_t cnt, loff_t *ppos)
++{
++	ipts_info_t *ipts = fp->private_data;
++	ipts_state_t state;
++	int sensor_mode, len;
++	char mode[3];
++
++	if (cnt == 0 || cnt > 3)
++		return -EINVAL;
++
++	state = ipts_get_state(ipts);
++	if (state != IPTS_STA_RAW_DATA_STARTED && state != IPTS_STA_HID_STARTED) {
++		return -EIO;
++	}
++
++	len = cnt;
++	if (copy_from_user(mode, ubuf, len))
++		return -EFAULT;
++
++	while(len > 0 && (isspace(mode[len-1]) || mode[len-1] == '\n'))
++		len--;
++	mode[len] = '\0';
++
++	if (sscanf(mode, "%d", &sensor_mode) != 1)
++		return -EINVAL;
++
++	if (sensor_mode != TOUCH_SENSOR_MODE_RAW_DATA &&
++					sensor_mode != TOUCH_SENSOR_MODE_HID) {
++		return -EINVAL;
++	}
++
++	if (sensor_mode == ipts->sensor_mode)
++		return 0;
++
++	ipts_switch_sensor_mode(ipts, sensor_mode);
++
++	return cnt;
++}
++
++static const struct file_operations ipts_mode_dbgfs_fops = {
++        .open = simple_open,
++        .read = ipts_dbgfs_mode_read,
++        .write = ipts_dbgfs_mode_write,
++        .llseek = generic_file_llseek,
++};
++
++static ssize_t ipts_dbgfs_status_read(struct file *fp, char __user *ubuf,
++						size_t cnt, loff_t *ppos)
++{
++	ipts_info_t *ipts = fp->private_data;
++	char status[256];
++	int len = 0;
++
++	if (cnt < sizeof(ipts_status_fmt) - 3)
++		return -EINVAL;
++
++	len = scnprintf(status, 256, ipts_status_fmt, ipts->sensor_mode,
++						     ipts->state);
++	if (len < 0)
++		return -EIO;
++
++	return simple_read_from_buffer(ubuf, cnt, ppos, status, len);
++}
++
++static const struct file_operations ipts_status_dbgfs_fops = {
++        .open = simple_open,
++        .read = ipts_dbgfs_status_read,
++        .llseek = generic_file_llseek,
++};
++
++void ipts_dbgfs_deregister(ipts_info_t* ipts)
++{
++	if (!ipts->dbgfs_dir)
++		return;
++
++	debugfs_remove_recursive(ipts->dbgfs_dir);
++	ipts->dbgfs_dir = NULL;
++}
++
++int ipts_dbgfs_register(ipts_info_t* ipts, const char *name)
++{
++	struct dentry *dir, *f;
++
++	dir = debugfs_create_dir(name, NULL);
++	if (!dir)
++		return -ENOMEM;
++
++        f = debugfs_create_file("mode", S_IRUSR | S_IWUSR, dir,
++                                ipts, &ipts_mode_dbgfs_fops);
++        if (!f) {
++                ipts_err(ipts, "debugfs mode creation failed\n");
++                goto err;
++        }
++
++        f = debugfs_create_file("status", S_IRUSR, dir,
++                                ipts, &ipts_status_dbgfs_fops);
++        if (!f) {
++                ipts_err(ipts, "debugfs status creation failed\n");
++                goto err;
++        }
++
++	ipts->dbgfs_dir = dir;
++
++	return 0;
++err:
++	ipts_dbgfs_deregister(ipts);
++	return -ENODEV;
++}
+diff --git a/drivers/misc/ipts/ipts-gfx.c b/drivers/misc/ipts/ipts-gfx.c
+new file mode 100644
+index 000000000000..51727770e75d
+--- /dev/null
++++ b/drivers/misc/ipts/ipts-gfx.c
+@@ -0,0 +1,184 @@
++/*
++ *
++ * Intel Integrated Touch Gfx Interface Layer
++ * Copyright (c) 2016 Intel Corporation.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms and conditions of the GNU General Public License,
++ * version 2, as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
++ * more details.
++ *
++ */
++#include <linux/kthread.h>
++#include <linux/delay.h>
++#include <linux/intel_ipts_if.h>
++
++#include "ipts.h"
++#include "ipts-msg-handler.h"
++#include "ipts-state.h"
++
++static void gfx_processing_complete(void *data)
++{
++	ipts_info_t *ipts = data;
++
++	if (ipts_get_state(ipts) == IPTS_STA_RAW_DATA_STARTED) {
++		schedule_work(&ipts->raw_data_work);
++		return;
++	}
++
++	ipts_dbg(ipts, "not ready to handle gfx event\n");
++}
++
++static void notify_gfx_status(u32 status, void *data)
++{
++	ipts_info_t *ipts = data;
++
++	ipts->gfx_status = status;
++	schedule_work(&ipts->gfx_status_work);
++}
++
++static int connect_gfx(ipts_info_t *ipts)
++{
++	int ret = 0;
++	intel_ipts_connect_t ipts_connect;
++
++	ipts_connect.if_version = IPTS_INTERFACE_V1;
++	ipts_connect.ipts_cb.workload_complete = gfx_processing_complete;
++	ipts_connect.ipts_cb.notify_gfx_status = notify_gfx_status;
++	ipts_connect.data = (void*)ipts;
++
++	ret = intel_ipts_connect(&ipts_connect);
++	if (ret)
++		return ret;
++
++	/* TODO: gfx version check */
++	ipts->gfx_info.gfx_handle = ipts_connect.gfx_handle;
++	ipts->gfx_info.ipts_ops = ipts_connect.ipts_ops;
++
++	return ret;
++}
++
++static void disconnect_gfx(ipts_info_t *ipts)
++{
++	intel_ipts_disconnect(ipts->gfx_info.gfx_handle);
++}
++
++#ifdef RUN_DBG_THREAD
++#include "../mei/mei_dev.h"
++
++static struct task_struct *dbg_thread;
++
++static void ipts_print_dbg_info(ipts_info_t* ipts)
++{
++        char fw_sts_str[MEI_FW_STATUS_STR_SZ];
++	u32 *db, *head, *tail;
++	intel_ipts_wq_info_t* wq_info;
++
++	wq_info = &ipts->resource.wq_info;
++
++	mei_fw_status_str(ipts->cldev->bus, fw_sts_str, MEI_FW_STATUS_STR_SZ);
++	pr_info(">> tdt : fw status : %s\n", fw_sts_str);
++
++	db = (u32*)wq_info->db_addr;
++	head = (u32*)wq_info->wq_head_addr;
++	tail = (u32*)wq_info->wq_tail_addr;
++	pr_info(">> == DB s:%x, c:%x ==\n", *db, *(db+1));
++	pr_info(">> == WQ h:%u, t:%u ==\n", *head, *tail);
++}
++
++static int ipts_dbg_thread(void *data)
++{
++	ipts_info_t *ipts = (ipts_info_t *)data;
++
++	pr_info(">> start debug thread\n");
++
++	while (!kthread_should_stop()) {
++		if (ipts_get_state(ipts) != IPTS_STA_RAW_DATA_STARTED) {
++			pr_info("state is not IPTS_STA_RAW_DATA_STARTED : %d\n",
++							ipts_get_state(ipts));
++			msleep(5000);
++			continue;
++		}
++
++		ipts_print_dbg_info(ipts);
++
++		msleep(3000);
++	}
++
++	return 0;
++}
++#endif
++
++int ipts_open_gpu(ipts_info_t *ipts)
++{
++	int ret = 0;
++
++	ret = connect_gfx(ipts);
++	if (ret) {
++		ipts_dbg(ipts, "cannot connect GPU\n");
++		return ret;
++	}
++
++	ret = ipts->gfx_info.ipts_ops.get_wq_info(ipts->gfx_info.gfx_handle,
++							&ipts->resource.wq_info);
++	if (ret) {
++		ipts_dbg(ipts, "error in get_wq_info\n");
++		return ret;
++	}
++
++#ifdef	RUN_DBG_THREAD
++	dbg_thread = kthread_run(ipts_dbg_thread, (void *)ipts, "ipts_debug");
++#endif
++
++	return 0;
++}
++
++void ipts_close_gpu(ipts_info_t *ipts)
++{
++	disconnect_gfx(ipts);
++
++#ifdef	RUN_DBG_THREAD
++	kthread_stop(dbg_thread);
++#endif
++}
++
++intel_ipts_mapbuffer_t *ipts_map_buffer(ipts_info_t *ipts, u32 size, u32 flags)
++{
++	intel_ipts_mapbuffer_t *buf;
++	u64 handle;
++	int ret;
++
++	buf = devm_kzalloc(&ipts->cldev->dev, sizeof(*buf), GFP_KERNEL);
++	if (!buf)
++		return NULL;
++
++	buf->size = size;
++	buf->flags = flags;
++
++	handle = ipts->gfx_info.gfx_handle;
++	ret = ipts->gfx_info.ipts_ops.map_buffer(handle, buf);
++	if (ret) {
++		devm_kfree(&ipts->cldev->dev, buf);
++		return NULL;
++	}
++
++	return buf;
++}
++
++void ipts_unmap_buffer(ipts_info_t *ipts, intel_ipts_mapbuffer_t *buf)
++{
++	u64 handle;
++	int ret;
++
++	if (!buf)
++		return;
++
++	handle = ipts->gfx_info.gfx_handle;
++	ret = ipts->gfx_info.ipts_ops.unmap_buffer(handle, buf->buf_handle);
++
++	devm_kfree(&ipts->cldev->dev, buf);
++}
+diff --git a/drivers/misc/ipts/ipts-gfx.h b/drivers/misc/ipts/ipts-gfx.h
+new file mode 100644
+index 000000000000..03a5f3551ddf
+--- /dev/null
++++ b/drivers/misc/ipts/ipts-gfx.h
+@@ -0,0 +1,24 @@
++/*
++ * Intel Precise Touch & Stylus gpu wrapper
++ * Copyright (c) 2016, Intel Corporation.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms and conditions of the GNU General Public License,
++ * version 2, as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
++ * more details.
++ */
++
++
++#ifndef _IPTS_GFX_H_
++#define _IPTS_GFX_H_
++
++int ipts_open_gpu(ipts_info_t *ipts);
++void ipts_close_gpu(ipts_info_t *ipts);
++intel_ipts_mapbuffer_t *ipts_map_buffer(ipts_info_t *ipts, u32 size, u32 flags);
++void ipts_unmap_buffer(ipts_info_t *ipts, intel_ipts_mapbuffer_t *buf);
++
++#endif // _IPTS_GFX_H_
+diff --git a/drivers/misc/ipts/ipts-hid.c b/drivers/misc/ipts/ipts-hid.c
+new file mode 100644
+index 000000000000..3b3be6177648
+--- /dev/null
++++ b/drivers/misc/ipts/ipts-hid.c
+@@ -0,0 +1,456 @@
++/*
++ * Intel Precise Touch & Stylus HID driver
++ *
++ * Copyright (c) 2016, Intel Corporation.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms and conditions of the GNU General Public License,
++ * version 2, as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
++ * more details.
++ */
++
++#include <linux/module.h>
++#include <linux/firmware.h>
++#include <linux/hid.h>
++#include <linux/vmalloc.h>
++
++#include "ipts.h"
++#include "ipts-resource.h"
++#include "ipts-sensor-regs.h"
++#include "ipts-msg-handler.h"
++
++#define BUS_MEI				0x44
++
++#define	HID_DESC_INTEL	"intel/ipts/intel_desc.bin"
++#define	HID_DESC_VENDOR	"intel/ipts/vendor_desc.bin"
++MODULE_FIRMWARE(HID_DESC_INTEL);
++MODULE_FIRMWARE(HID_DESC_VENDOR);
++
++typedef enum output_buffer_payload_type {
++	OUTPUT_BUFFER_PAYLOAD_ERROR = 0,
++	OUTPUT_BUFFER_PAYLOAD_HID_INPUT_REPORT,
++	OUTPUT_BUFFER_PAYLOAD_HID_FEATURE_REPORT,
++	OUTPUT_BUFFER_PAYLOAD_KERNEL_LOAD,
++	OUTPUT_BUFFER_PAYLOAD_FEEDBACK_BUFFER
++} output_buffer_payload_type_t;
++
++typedef struct kernel_output_buffer_header {
++	u16 length;
++	u8 payload_type;
++	u8 reserved1;
++	touch_hid_private_data_t hid_private_data;
++	u8 reserved2[28];
++	u8 data[0];
++} kernel_output_buffer_header_t;
++
++typedef struct kernel_output_payload_error {
++	u16 severity;
++	u16 source;
++	u8 code[4];
++	char string[128];
++} kernel_output_payload_error_t;
++
++static int ipts_hid_get_hid_descriptor(ipts_info_t *ipts, u8 **desc, int *size)
++{
++	u8 *buf;
++	int hid_size = 0, ret = 0;
++	const struct firmware *intel_desc = NULL;
++	const struct firmware *vendor_desc = NULL;
++	const char *intel_desc_path = HID_DESC_INTEL;
++	const char *vendor_desc_path = HID_DESC_VENDOR;
++
++	ret = request_firmware(&intel_desc, intel_desc_path, &ipts->cldev->dev);
++	if (ret) {
++		goto no_hid;
++	}
++	hid_size = intel_desc->size;
++
++	ret = request_firmware(&vendor_desc, vendor_desc_path, &ipts->cldev->dev);
++	if (ret) {
++		ipts_dbg(ipts, "error in reading HID Vendor Descriptor\n");
++	} else {
++		hid_size += vendor_desc->size;
++	}
++
++	ipts_dbg(ipts, "hid size = %d\n", hid_size);
++	buf = vmalloc(hid_size);
++	if (buf == NULL) {
++		ret = -ENOMEM;
++		goto no_mem;
++	}
++
++	memcpy(buf, intel_desc->data, intel_desc->size);
++	if (vendor_desc) {
++		memcpy(&buf[intel_desc->size], vendor_desc->data,
++							vendor_desc->size);
++		release_firmware(vendor_desc);
++	}
++
++	release_firmware(intel_desc);
++
++	*desc = buf;
++	*size = hid_size;
++
++	return 0;
++no_mem :
++	if (vendor_desc)
++		release_firmware(vendor_desc);
++	release_firmware(intel_desc);
++
++no_hid :
++	return ret;
++}
++
++static int ipts_hid_parse(struct hid_device *hid)
++{
++	ipts_info_t *ipts = hid->driver_data;
++	int ret = 0, size;
++	u8 *buf;
++
++	ipts_dbg(ipts, "ipts_hid_parse() start\n");
++	ret = ipts_hid_get_hid_descriptor(ipts, &buf, &size);
++	if (ret != 0) {
++		ipts_dbg(ipts, "ipts_hid_ipts_get_hid_descriptor ret %d\n", ret);
++		return -EIO;
++	}
++
++	ret = hid_parse_report(hid, buf, size);
++	vfree(buf);
++	if (ret) {
++		ipts_err(ipts, "hid_parse_report error : %d\n", ret);
++		goto out;
++	}
++
++	ipts->hid_desc_ready = true;
++out:
++	return ret;
++}
++
++static int ipts_hid_start(struct hid_device *hid)
++{
++	return 0;
++}
++
++static void ipts_hid_stop(struct hid_device *hid)
++{
++	return;
++}
++
++static int ipts_hid_open(struct hid_device *hid)
++{
++	return 0;
++}
++
++static void ipts_hid_close(struct hid_device *hid)
++{
++	ipts_info_t *ipts = hid->driver_data;
++
++	ipts->hid_desc_ready = false;
++
++	return;
++}
++
++static int ipts_hid_send_hid2me_feedback(ipts_info_t *ipts, u32 fb_data_type,
++							__u8 *buf, size_t count)
++{
++	ipts_buffer_info_t *fb_buf;
++	touch_feedback_hdr_t *feedback;
++	u8 *payload;
++	int header_size;
++	ipts_state_t state;
++
++	header_size = sizeof(touch_feedback_hdr_t);
++
++	if (count > ipts->resource.hid2me_buffer_size - header_size)
++		return -EINVAL;
++
++	state = ipts_get_state(ipts);
++	if (state != IPTS_STA_RAW_DATA_STARTED && state != IPTS_STA_HID_STARTED)
++		return 0;
++
++	fb_buf = ipts_get_hid2me_buffer(ipts);
++	feedback = (touch_feedback_hdr_t *)fb_buf->addr;
++	payload = fb_buf->addr + header_size;
++	memset(feedback, 0, header_size);
++
++	feedback->feedback_data_type = fb_data_type;
++	feedback->feedback_cmd_type = TOUCH_FEEDBACK_CMD_TYPE_NONE;
++	feedback->payload_size_bytes = count;
++	feedback->buffer_id = TOUCH_HID_2_ME_BUFFER_ID;
++	feedback->protocol_ver = 0;
++	feedback->reserved[0] = 0xAC;
++
++	/* copy payload */
++	memcpy(payload, buf, count);
++
++	ipts_send_feedback(ipts, TOUCH_HID_2_ME_BUFFER_ID, 0);
++
++	return 0;
++}
++
++static int ipts_hid_raw_request(struct hid_device *hid,
++				unsigned char report_number, __u8 *buf,
++				size_t count, unsigned char report_type,
++				int reqtype)
++{
++	ipts_info_t *ipts = hid->driver_data;
++	u32 fb_data_type;
++
++	ipts_dbg(ipts, "hid raw request => report %d, request %d\n",
++						 (int)report_type, reqtype);
++
++	if (report_type != HID_FEATURE_REPORT)
++		return 0;
++
++	switch (reqtype) {
++		case HID_REQ_GET_REPORT:
++			fb_data_type = TOUCH_FEEDBACK_DATA_TYPE_GET_FEATURES;
++			break;
++		case HID_REQ_SET_REPORT:
++			fb_data_type = TOUCH_FEEDBACK_DATA_TYPE_SET_FEATURES;
++			break;
++		default:
++			ipts_err(ipts, "raw request not supprted: %d\n", reqtype);
++			return -EIO;
++	}
++
++	return ipts_hid_send_hid2me_feedback(ipts, fb_data_type, buf, count);
++}
++
++static int ipts_hid_output_report(struct hid_device *hid,
++					__u8 *buf, size_t count)
++{
++	ipts_info_t *ipts = hid->driver_data;
++	u32 fb_data_type;
++
++	ipts_dbg(ipts, "hid output report\n");
++
++	fb_data_type = TOUCH_FEEDBACK_DATA_TYPE_OUTPUT_REPORT;
++
++	return ipts_hid_send_hid2me_feedback(ipts, fb_data_type, buf, count);
++}
++
++static struct hid_ll_driver ipts_hid_ll_driver = {
++	.parse = ipts_hid_parse,
++	.start = ipts_hid_start,
++	.stop = ipts_hid_stop,
++	.open = ipts_hid_open,
++	.close = ipts_hid_close,
++	.raw_request = ipts_hid_raw_request,
++	.output_report = ipts_hid_output_report,
++};
++
++int ipts_hid_init(ipts_info_t *ipts)
++{
++	int ret = 0;
++	struct hid_device *hid;
++
++	hid = hid_allocate_device();
++	if (IS_ERR(hid)) {
++		ret = PTR_ERR(hid);
++		goto err_dev;
++	}
++
++	hid->driver_data = ipts;
++	hid->ll_driver = &ipts_hid_ll_driver;
++	hid->dev.parent = &ipts->cldev->dev;
++	hid->bus = BUS_MEI;
++	hid->version = ipts->device_info.fw_rev;
++	hid->vendor = ipts->device_info.vendor_id;
++	hid->product = ipts->device_info.device_id;
++
++	snprintf(hid->phys, sizeof(hid->phys), "heci3");
++	snprintf(hid->name, sizeof(hid->name),
++		 "%s %04hX:%04hX", "ipts", hid->vendor, hid->product);
++
++	ret = hid_add_device(hid);
++	if (ret) {
++		if (ret != -ENODEV)
++			ipts_err(ipts, "can't add hid device: %d\n", ret);
++		goto err_mem_free;
++	}
++
++	ipts->hid = hid;
++
++	return 0;
++
++err_mem_free:
++	hid_destroy_device(hid);
++err_dev:
++	return ret;
++}
++
++void ipts_hid_release(ipts_info_t *ipts)
++{
++	if (!ipts->hid)
++			return;
++	hid_destroy_device(ipts->hid);
++}
++
++int ipts_handle_hid_data(ipts_info_t *ipts,
++			touch_sensor_hid_ready_for_data_rsp_data_t *hid_rsp)
++{
++	touch_raw_data_hdr_t *raw_header;
++	ipts_buffer_info_t *buffer_info;
++	touch_feedback_hdr_t *feedback;
++	u8 *raw_data;
++	int touch_data_buffer_index;
++	int transaction_id;
++	int ret = 0;
++
++	touch_data_buffer_index = (int)hid_rsp->touch_data_buffer_index;
++	buffer_info = ipts_get_touch_data_buffer_hid(ipts);
++	raw_header = (touch_raw_data_hdr_t *)buffer_info->addr;
++	transaction_id = raw_header->hid_private_data.transaction_id;
++
++	raw_data = (u8*)raw_header + sizeof(touch_raw_data_hdr_t);
++	if (raw_header->data_type == TOUCH_RAW_DATA_TYPE_HID_REPORT) {
++		memcpy(ipts->hid_input_report, raw_data,
++				raw_header->raw_data_size_bytes);
++
++		ret = hid_input_report(ipts->hid, HID_INPUT_REPORT,
++					(u8*)ipts->hid_input_report,
++					raw_header->raw_data_size_bytes, 1);
++		if (ret) {
++			ipts_err(ipts, "error in hid_input_report : %d\n", ret);
++		}
++	} else if (raw_header->data_type == TOUCH_RAW_DATA_TYPE_GET_FEATURES) {
++		/* TODO: implement together with "get feature ioctl" */
++	} else if (raw_header->data_type == TOUCH_RAW_DATA_TYPE_ERROR) {
++		touch_error_t *touch_err = (touch_error_t *)raw_data;
++
++		ipts_err(ipts, "error type : %d, me fw error : %x, err reg : %x\n",
++				touch_err->touch_error_type,
++				touch_err->touch_me_fw_error.value,
++				touch_err->touch_error_register.reg_value);
++	}
++
++	/* send feedback data for HID mode */
++        buffer_info = ipts_get_feedback_buffer(ipts, touch_data_buffer_index);
++	feedback = (touch_feedback_hdr_t *)buffer_info->addr;
++	memset(feedback, 0, sizeof(touch_feedback_hdr_t));
++	feedback->feedback_cmd_type = TOUCH_FEEDBACK_CMD_TYPE_NONE;
++	feedback->payload_size_bytes = 0;
++	feedback->buffer_id = touch_data_buffer_index;
++	feedback->protocol_ver = 0;
++	feedback->reserved[0] = 0xAC;
++
++	ret = ipts_send_feedback(ipts, touch_data_buffer_index, transaction_id);
++
++	return ret;
++}
++
++static int handle_outputs(ipts_info_t *ipts, int parallel_idx)
++{
++	kernel_output_buffer_header_t *out_buf_hdr;
++	ipts_buffer_info_t *output_buf, *fb_buf = NULL;
++	u8 *input_report, *payload;
++	u32 transaction_id;
++	int i, payload_size, ret = 0, header_size;
++
++	header_size = sizeof(kernel_output_buffer_header_t);
++	output_buf = ipts_get_output_buffers_by_parallel_id(ipts, parallel_idx);
++	for (i = 0; i < ipts->resource.num_of_outputs; i++) {
++		out_buf_hdr = (kernel_output_buffer_header_t*)output_buf[i].addr;
++		if (out_buf_hdr->length < header_size)
++			continue;
++
++		payload_size = out_buf_hdr->length - header_size;
++		payload = out_buf_hdr->data;
++
++		switch(out_buf_hdr->payload_type) {
++			case OUTPUT_BUFFER_PAYLOAD_HID_INPUT_REPORT:
++				input_report = ipts->hid_input_report;
++				memcpy(input_report, payload, payload_size);
++				hid_input_report(ipts->hid, HID_INPUT_REPORT,
++						input_report, payload_size, 1);
++				break;
++			case OUTPUT_BUFFER_PAYLOAD_HID_FEATURE_REPORT:
++				ipts_dbg(ipts, "output hid feature report\n");
++				break;
++			case OUTPUT_BUFFER_PAYLOAD_KERNEL_LOAD:
++				ipts_dbg(ipts, "output kernel load\n");
++				break;
++			case OUTPUT_BUFFER_PAYLOAD_FEEDBACK_BUFFER:
++			{
++				/* send feedback data for raw data mode */
++                                fb_buf = ipts_get_feedback_buffer(ipts,
++								parallel_idx);
++				transaction_id = out_buf_hdr->
++						hid_private_data.transaction_id;
++				memcpy(fb_buf->addr, payload, payload_size);
++				break;
++			}
++			case OUTPUT_BUFFER_PAYLOAD_ERROR:
++			{
++				kernel_output_payload_error_t *err_payload;
++
++				if (payload_size == 0)
++					break;
++
++				err_payload =
++					(kernel_output_payload_error_t*)payload;
++
++				ipts_err(ipts, "error : severity : %d,"
++						" source : %d,"
++						" code : %d:%d:%d:%d\n"
++						"string %s\n",
++						err_payload->severity,
++						err_payload->source,
++						err_payload->code[0],
++						err_payload->code[1],
++						err_payload->code[2],
++						err_payload->code[3],
++						err_payload->string);
++				
++				break;
++			}
++			default:
++				ipts_err(ipts, "invalid output buffer payload\n");
++				break;
++		}
++	}
++
++	if (fb_buf) {
++		ret = ipts_send_feedback(ipts, parallel_idx, transaction_id);
++		if (ret)
++			return ret;
++	}
++
++	return 0;
++}
++
++static int handle_output_buffers(ipts_info_t *ipts, int cur_idx, int end_idx)
++{
++	int max_num_of_buffers = ipts_get_num_of_parallel_buffers(ipts);
++
++	do {
++		cur_idx++; /* cur_idx has last completed so starts with +1 */
++		cur_idx %= max_num_of_buffers;
++		handle_outputs(ipts, cur_idx);
++	} while (cur_idx != end_idx);
++
++	return 0;
++}
++
++int ipts_handle_processed_data(ipts_info_t *ipts)
++{
++	int ret = 0;
++	int current_buffer_idx;
++	int last_buffer_idx;
++
++	current_buffer_idx = *ipts->last_submitted_id;
++	last_buffer_idx = ipts->last_buffer_completed;
++
++	if (current_buffer_idx == last_buffer_idx)
++		return 0;
++
++	ipts->last_buffer_completed = current_buffer_idx;
++	handle_output_buffers(ipts, last_buffer_idx, current_buffer_idx);
++
++	return ret;
++}
+diff --git a/drivers/misc/ipts/ipts-hid.h b/drivers/misc/ipts/ipts-hid.h
+new file mode 100644
+index 000000000000..f1b22c912df7
+--- /dev/null
++++ b/drivers/misc/ipts/ipts-hid.h
+@@ -0,0 +1,34 @@
++/*
++ * Intel Precise Touch & Stylus HID definition
++ *
++ * Copyright (c) 2016, Intel Corporation.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms and conditions of the GNU General Public License,
++ * version 2, as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
++ * more details.
++ */
++
++#ifndef _IPTS_HID_H_
++#define	_IPTS_HID_H_
++
++#define	BUS_MEI				0x44
++
++#if 0 /* TODO : we have special report ID. will implement them */
++#define WRITE_CHANNEL_REPORT_ID		0xa
++#define READ_CHANNEL_REPORT_ID		0xb
++#define CONFIG_CHANNEL_REPORT_ID	0xd
++#define VENDOR_INFO_REPORT_ID		0xF
++#define SINGLE_TOUCH_REPORT_ID		0x40
++#endif
++
++int ipts_hid_init(ipts_info_t *ipts);
++void ipts_hid_release(ipts_info_t *ipts);
++int ipts_handle_hid_data(ipts_info_t *ipts,
++			touch_sensor_hid_ready_for_data_rsp_data_t *hid_rsp);
++
++#endif /* _IPTS_HID_H_ */
+diff --git a/drivers/misc/ipts/ipts-kernel.c b/drivers/misc/ipts/ipts-kernel.c
+new file mode 100644
+index 000000000000..ca5e24ce579e
+--- /dev/null
++++ b/drivers/misc/ipts/ipts-kernel.c
+@@ -0,0 +1,1050 @@
++#include <linux/module.h>
++#include <linux/firmware.h>
++#include <linux/vmalloc.h>
++#include <linux/intel_ipts_if.h>
++
++#include "ipts.h"
++#include "ipts-resource.h"
++#include "ipts-binary-spec.h"
++#include "ipts-state.h"
++#include "ipts-msg-handler.h"
++#include "ipts-gfx.h"
++
++#define MAX_IOCL_FILE_NAME_LEN		80
++#define MAX_IOCL_FILE_PATH_LEN		256
++
++#pragma pack(1)
++typedef struct bin_data_file_info {
++    u32 io_buffer_type;
++    u32 flags;
++    char file_name[MAX_IOCL_FILE_NAME_LEN];
++} bin_data_file_info_t;
++
++typedef struct bin_fw_info {
++	char fw_name[MAX_IOCL_FILE_NAME_LEN];
++
++	/* list of parameters to load a kernel */
++	s32 vendor_output;	/* output index. -1 for no use */
++	u32 num_of_data_files;
++	bin_data_file_info_t data_file[];
++} bin_fw_info_t;
++
++typedef struct bin_fw_list {
++	u32 num_of_fws;
++	bin_fw_info_t fw_info[];
++} bin_fw_list_t;
++#pragma pack()
++
++/* OpenCL kernel */
++typedef struct bin_workload {
++	int cmdbuf_index;
++	int iobuf_input;
++	int iobuf_output[MAX_NUM_OUTPUT_BUFFERS];
++} bin_workload_t;
++
++typedef struct bin_buffer {
++	unsigned int handle;
++	intel_ipts_mapbuffer_t *buf;
++	bool no_unmap;	/* only releasing vendor kernel unmaps output buffers */
++} bin_buffer_t;
++
++typedef struct bin_alloc_info {
++	bin_buffer_t *buffs;
++	int num_of_allocations;
++	int num_of_outputs;
++
++	int num_of_buffers;
++} bin_alloc_info_t;
++
++typedef struct bin_guc_wq_item {
++	unsigned int batch_offset;
++	unsigned int size;
++	char data[];
++} bin_guc_wq_item_t;
++
++typedef struct bin_kernel_info {
++	bin_workload_t *wl;
++	bin_alloc_info_t *alloc_info;
++	bin_guc_wq_item_t *guc_wq_item;
++	ipts_bin_bufid_patch_t bufid_patch;
++
++	bool is_vendor; /* 1: vendor, 0: postprocessing */
++} bin_kernel_info_t;
++
++typedef struct bin_kernel_list {
++	intel_ipts_mapbuffer_t *bufid_buf;
++	int num_of_kernels;
++	bin_kernel_info_t kernels[];
++} bin_kernel_list_t;
++
++typedef struct bin_parse_info {
++	u8 *data;
++	int size;
++	int parsed;
++
++	bin_fw_info_t *fw_info;
++
++	/* only used by postprocessing */
++	bin_kernel_info_t *vendor_kernel;
++	u32 interested_vendor_output; /* interested vendor output index */
++} bin_parse_info_t;
++
++#define BDW_SURFACE_BASE_ADDRESS		0x6101000e
++#define SURFACE_STATE_OFFSET_WORD		4
++#define SBA_OFFSET_BYTES			16384
++#define LASTSUBMITID_DEFAULT_VALUE		-1
++
++#define IPTS_FW_PATH_FMT			"intel/ipts/%s"
++#define IPTS_FW_CONFIG_FILE			"intel/ipts/ipts_fw_config.bin"
++
++MODULE_FIRMWARE(IPTS_FW_CONFIG_FILE);
++
++#define IPTS_INPUT_ON				((u32)1 << IPTS_INPUT)
++#define IPTS_OUTPUT_ON				((u32)1 << IPTS_OUTPUT)
++#define IPTS_CONFIGURATION_ON			((u32)1 << IPTS_CONFIGURATION)
++#define IPTS_CALIBRATION_ON			((u32)1 << IPTS_CALIBRATION)
++#define IPTS_FEATURE_ON				((u32)1 << IPTS_FEATURE)
++
++#define	DATA_FILE_FLAG_SHARE			0x00000001
++#define	DATA_FILE_FLAG_ALLOC_CONTIGUOUS		0x00000002
++
++static int bin_read_fw(ipts_info_t *ipts, const char *fw_name,
++						u8* data, int size)
++{
++	const struct firmware *fw = NULL;
++	char fw_path[MAX_IOCL_FILE_PATH_LEN];
++	int ret = 0;
++
++	snprintf(fw_path, MAX_IOCL_FILE_PATH_LEN, IPTS_FW_PATH_FMT, fw_name);
++	ret = request_firmware(&fw, fw_path, &ipts->cldev->dev);
++	if (ret) {
++		ipts_err(ipts, "cannot read fw %s\n", fw_path);
++		return ret;
++	}
++
++	if (fw->size > size) {
++		ipts_dbg(ipts, "too small buffer to contain fw data\n");
++		ret = -EINVAL;
++		goto rel_return;
++	}
++
++	memcpy(data, fw->data, fw->size);
++
++rel_return:
++	release_firmware(fw);
++
++	return ret;
++}
++
++
++static bin_data_file_info_t* bin_get_data_file_info(bin_fw_info_t* fw_info,
++							u32 io_buffer_type)
++{
++	int i;
++
++	for (i = 0; i < fw_info->num_of_data_files; i++) {
++		if (fw_info->data_file[i].io_buffer_type == io_buffer_type)
++			break;
++	}
++
++	if (i == fw_info->num_of_data_files)
++		return NULL;
++
++	return &fw_info->data_file[i];
++}
++
++static inline bool is_shared_data(const bin_data_file_info_t *data_file)
++{
++	if (data_file)
++		return (!!(data_file->flags & DATA_FILE_FLAG_SHARE));
++
++	return false;
++}
++
++static inline bool is_alloc_cont_data(const bin_data_file_info_t *data_file)
++{
++	if (data_file)
++		return (!!(data_file->flags & DATA_FILE_FLAG_ALLOC_CONTIGUOUS));
++
++	return false;
++}
++
++static inline bool is_parsing_vendor_kernel(const bin_parse_info_t *parse_info)
++{
++	/* vendor_kernel == null while loading itself(vendor kernel) */
++	return parse_info->vendor_kernel == NULL;
++}
++
++static int bin_read_allocation_list(ipts_info_t *ipts,
++					bin_parse_info_t *parse_info,
++					bin_alloc_info_t *alloc_info)
++{
++	ipts_bin_alloc_list_t *alloc_list;
++	int alloc_idx, parallel_idx, num_of_parallels, buf_idx, num_of_buffers;
++	int parsed, size;
++
++	parsed = parse_info->parsed;
++	size = parse_info->size;
++
++	alloc_list = (ipts_bin_alloc_list_t *)&parse_info->data[parsed];
++
++	/* validation check */
++	if (sizeof(alloc_list->num) > size - parsed)
++		return -EINVAL;
++
++	/* read the number of aloocations */
++	parsed += sizeof(alloc_list->num);
++
++	/* validation check */
++	if (sizeof(alloc_list->alloc[0]) * alloc_list->num > size - parsed)
++		return -EINVAL;
++
++	num_of_parallels = ipts_get_num_of_parallel_buffers(ipts);
++	num_of_buffers = num_of_parallels * alloc_list->num + num_of_parallels;
++
++	alloc_info->buffs = vmalloc(sizeof(bin_buffer_t) * num_of_buffers);
++	if (alloc_info->buffs == NULL)
++		return -ENOMEM;
++
++	memset(alloc_info->buffs, 0, sizeof(bin_buffer_t) * num_of_buffers);
++	for (alloc_idx = 0; alloc_idx < alloc_list->num; alloc_idx++) {
++		for (parallel_idx = 0; parallel_idx < num_of_parallels;
++								parallel_idx++) {
++			buf_idx = alloc_idx + (parallel_idx * alloc_list->num);
++			alloc_info->buffs[buf_idx].handle =
++					alloc_list->alloc[alloc_idx].handle;
++
++		}
++
++		parsed += sizeof(alloc_list->alloc[0]);
++	}
++
++	parse_info->parsed = parsed;
++	alloc_info->num_of_allocations = alloc_list->num;
++	alloc_info->num_of_buffers = num_of_buffers;
++
++	ipts_dbg(ipts, "number of allocations = %d, buffers = %d\n",
++						alloc_info->num_of_allocations,
++						alloc_info->num_of_buffers);
++
++	return 0;
++}
++
++static void patch_SBA(u32 *buf_addr, u64 gpu_addr, int size)
++{
++	u64 *stateBase;
++	u64 SBA;
++	u32 inst;
++	int i;
++
++	SBA = gpu_addr + SBA_OFFSET_BYTES;
++
++	for (i = 0; i < size/4; i++) {
++		inst = buf_addr[i];
++		if (inst == BDW_SURFACE_BASE_ADDRESS) {
++			stateBase = (u64*)&buf_addr[i + SURFACE_STATE_OFFSET_WORD];
++			*stateBase |= SBA;
++			*stateBase |= 0x01; // enable
++			break;
++		}
++	}
++}
++
++static int bin_read_cmd_buffer(ipts_info_t *ipts,
++					bin_parse_info_t *parse_info,
++					bin_alloc_info_t *alloc_info,
++					bin_workload_t *wl)
++{
++	ipts_bin_cmdbuf_t *cmd;
++	intel_ipts_mapbuffer_t *buf;
++	int cmdbuf_idx, size, parsed, parallel_idx, num_of_parallels;
++
++	size = parse_info->size;
++	parsed = parse_info->parsed;
++
++	cmd = (ipts_bin_cmdbuf_t *)&parse_info->data[parsed];
++
++	if (sizeof(cmd->size) > size - parsed)
++		return -EINVAL;
++
++	parsed += sizeof(cmd->size);
++	if (cmd->size > size - parsed)
++		return -EINVAL;
++
++	ipts_dbg(ipts, "cmd buf size = %d\n", cmd->size);
++		
++	num_of_parallels = ipts_get_num_of_parallel_buffers(ipts);
++	/* command buffers are located after the other allocations */
++	cmdbuf_idx = num_of_parallels * alloc_info->num_of_allocations;
++	for (parallel_idx = 0; parallel_idx < num_of_parallels; parallel_idx++) {
++		buf = ipts_map_buffer(ipts, cmd->size, 0);
++		if (buf == NULL)
++			return -ENOMEM;
++
++		ipts_dbg(ipts, "cmd_idx[%d] = %d, g:0x%p, c:0x%p\n", parallel_idx,
++					cmdbuf_idx, buf->gfx_addr, buf->cpu_addr);
++
++		memcpy((void *)buf->cpu_addr, &(cmd->data[0]), cmd->size);
++		patch_SBA(buf->cpu_addr, (u64)buf->gfx_addr, cmd->size);
++		alloc_info->buffs[cmdbuf_idx].buf = buf;
++		wl[parallel_idx].cmdbuf_index = cmdbuf_idx;
++
++		cmdbuf_idx++;
++	}
++
++	parsed += cmd->size;
++	parse_info->parsed = parsed;
++
++	return 0;
++}
++
++static int bin_find_alloc(ipts_info_t *ipts,
++					bin_alloc_info_t *alloc_info,
++					u32 handle)
++{
++	int i;
++
++	for (i = 0; i < alloc_info->num_of_allocations; i++) {
++		if (alloc_info->buffs[i].handle == handle)
++			return i;
++	}
++
++	return -1;
++}
++
++static intel_ipts_mapbuffer_t* bin_get_vendor_kernel_output(
++						bin_parse_info_t *parse_info,
++						int parallel_idx)
++{
++	bin_kernel_info_t *vendor = parse_info->vendor_kernel;
++	bin_alloc_info_t *alloc_info;
++	int buf_idx, vendor_output_idx;
++
++	alloc_info = vendor->alloc_info;
++	vendor_output_idx = parse_info->interested_vendor_output;
++
++	if (vendor_output_idx >= alloc_info->num_of_outputs)
++		return NULL;
++
++	buf_idx = vendor->wl[parallel_idx].iobuf_output[vendor_output_idx];
++	return alloc_info->buffs[buf_idx].buf;
++}
++
++static int bin_read_res_list(ipts_info_t *ipts,
++					bin_parse_info_t *parse_info,
++					bin_alloc_info_t *alloc_info,
++					bin_workload_t *wl)
++{
++	ipts_bin_res_list_t *res_list;
++	ipts_bin_res_t *res;
++	intel_ipts_mapbuffer_t *buf;
++	bin_data_file_info_t *data_file;
++	u8 *bin_data;
++	int i, size, parsed, parallel_idx, num_of_parallels, output_idx = -1;
++	int buf_idx, num_of_alloc;
++	u32 buf_size, flags, io_buf_type;
++	bool initialize;
++	
++	parsed = parse_info->parsed;
++	size = parse_info->size;
++	bin_data = parse_info->data;
++
++	res_list = (ipts_bin_res_list_t *)&parse_info->data[parsed];
++	if (sizeof(res_list->num) > (size - parsed))
++		return -EINVAL;
++	parsed += sizeof(res_list->num);
++	num_of_parallels = ipts_get_num_of_parallel_buffers(ipts);
++
++	ipts_dbg(ipts, "number of resources %u\n", res_list->num);
++	for (i = 0; i < res_list->num; i++) {
++		initialize = false; 
++		io_buf_type = 0;
++		flags = 0;
++
++		/* initial data */
++		data_file = NULL;
++
++		res = (ipts_bin_res_t *)(&(bin_data[parsed]));
++		if (sizeof(res[0]) > (size - parsed)) {
++			return -EINVAL;
++		}
++
++		ipts_dbg(ipts, "Resource(%d):handle 0x%08x type %u init %u"
++				" size %u alsigned %u\n",
++				i, res->handle, res->type, res->initialize,
++				res->size, res->aligned_size);
++                parsed += sizeof(res[0]);
++
++		if (res->initialize) {
++			if (res->size > (size - parsed)) {
++				return -EINVAL;
++			}
++			parsed += res->size;
++		}
++
++		initialize = res->initialize;
++		if (initialize && res->size > sizeof(ipts_bin_io_header_t)) {
++			ipts_bin_io_header_t *io_hdr;
++			io_hdr = (ipts_bin_io_header_t *)(&res->data[0]);
++			if (strncmp(io_hdr->str, "INTELTOUCH", 10) == 0) {
++				data_file = bin_get_data_file_info(
++							parse_info->fw_info,
++							(u32)io_hdr->type);
++				switch (io_hdr->type) {
++				case IPTS_INPUT:
++					ipts_dbg(ipts, "input detected\n");
++					io_buf_type = IPTS_INPUT_ON;
++					flags = IPTS_BUF_FLAG_CONTIGUOUS;
++					break;
++				case IPTS_OUTPUT:
++					ipts_dbg(ipts, "output detected\n");
++					io_buf_type = IPTS_OUTPUT_ON;
++					output_idx++;
++					break;
++				default:
++					if ((u32)io_hdr->type > 31) {
++						ipts_err(ipts,
++							"invalid io buffer : %u\n",
++							(u32)io_hdr->type);
++						continue;
++					}
++
++					if (is_alloc_cont_data(data_file))
++						flags = IPTS_BUF_FLAG_CONTIGUOUS;
++
++					io_buf_type = ((u32)1 << (u32)io_hdr->type);
++					ipts_dbg(ipts, "special io buffer %u\n",
++								io_hdr->type);
++					break;
++				}
++
++				initialize = false;
++			}
++		}
++
++		num_of_alloc = alloc_info->num_of_allocations;
++		buf_idx = bin_find_alloc(ipts, alloc_info, res->handle);
++		if (buf_idx == -1) {
++			ipts_dbg(ipts, "cannot find alloc info\n");
++			return -EINVAL;
++		}
++		for (parallel_idx = 0; parallel_idx < num_of_parallels;
++					parallel_idx++, buf_idx += num_of_alloc) {
++			if (!res->aligned_size)
++				continue;
++
++			if (!(parallel_idx == 0 ||
++				    (io_buf_type && !is_shared_data(data_file))))
++				continue;
++
++			buf_size = res->aligned_size;
++			if (io_buf_type & IPTS_INPUT_ON) {
++				buf_size = max_t(u32,
++						ipts->device_info.frame_size,
++						buf_size);
++				wl[parallel_idx].iobuf_input = buf_idx;
++			} else if (io_buf_type & IPTS_OUTPUT_ON) {
++				wl[parallel_idx].iobuf_output[output_idx] = buf_idx;
++
++				if (!is_parsing_vendor_kernel(parse_info) &&
++								output_idx > 0) {
++					ipts_err(ipts,
++						"postproc with more than one inout"
++						" is not supported : %d\n", output_idx);
++					return -EINVAL;
++				}
++			}
++
++			if (!is_parsing_vendor_kernel(parse_info) &&
++						io_buf_type & IPTS_OUTPUT_ON) {
++				buf = bin_get_vendor_kernel_output(
++								parse_info,
++								parallel_idx);
++				alloc_info->buffs[buf_idx].no_unmap = true;
++			} else
++				buf = ipts_map_buffer(ipts, buf_size, flags);
++
++			if (buf == NULL) {
++				ipts_dbg(ipts, "ipts_map_buffer failed\n");
++				return -ENOMEM;
++			}
++
++			if (initialize) {
++				memcpy((void *)buf->cpu_addr, &(res->data[0]),
++								res->size);
++			} else {
++				if (data_file && strlen(data_file->file_name)) {
++					bin_read_fw(ipts, data_file->file_name,
++                                                        buf->cpu_addr, buf_size);
++				} else if (is_parsing_vendor_kernel(parse_info) ||
++						!(io_buf_type & IPTS_OUTPUT_ON)) {
++					memset((void *)buf->cpu_addr, 0, res->size);
++				}
++			}
++
++			alloc_info->buffs[buf_idx].buf = buf;
++		}
++	}
++
++        alloc_info->num_of_outputs = output_idx + 1;
++	parse_info->parsed = parsed;
++
++	return 0;
++}
++
++static int bin_read_patch_list(ipts_info_t *ipts,
++					bin_parse_info_t *parse_info,
++					bin_alloc_info_t *alloc_info,
++					bin_workload_t *wl)
++{
++	ipts_bin_patch_list_t *patch_list;
++	ipts_bin_patch_t *patch;
++	intel_ipts_mapbuffer_t *cmd = NULL;
++	u8 *batch;
++	int parsed, size, i, parallel_idx, num_of_parallels, cmd_idx, buf_idx;
++	unsigned int gtt_offset;
++
++	parsed = parse_info->parsed;
++	size = parse_info->size;
++	patch_list = (ipts_bin_patch_list_t *)&parse_info->data[parsed];
++
++	if (sizeof(patch_list->num) > (size - parsed)) {
++		return -EFAULT;
++	}
++	parsed += sizeof(patch_list->num);
++
++	num_of_parallels = ipts_get_num_of_parallel_buffers(ipts);
++	patch = (ipts_bin_patch_t *)(&patch_list->patch[0]);
++	for (i = 0; i < patch_list->num; i++) {
++		if (sizeof(patch_list->patch[0]) > (size - parsed)) {
++			return -EFAULT;
++		}
++
++		for (parallel_idx = 0; parallel_idx < num_of_parallels;
++								parallel_idx++) {
++			cmd_idx = wl[parallel_idx].cmdbuf_index;
++			buf_idx = patch[i].index + parallel_idx *
++						alloc_info->num_of_allocations;
++
++			if (alloc_info->buffs[buf_idx].buf == NULL) {
++				/* buffer shared */
++				buf_idx = patch[i].index;
++			}
++
++			cmd = alloc_info->buffs[cmd_idx].buf;
++			batch = (char *)(u64)cmd->cpu_addr;
++
++			gtt_offset = 0;
++			if(alloc_info->buffs[buf_idx].buf != NULL) {
++				gtt_offset = (u32)(u64)
++					alloc_info->buffs[buf_idx].buf->gfx_addr;
++			} 
++			gtt_offset += patch[i].alloc_offset;
++
++			batch += patch[i].patch_offset;
++			*(u32*)batch = gtt_offset;
++		}
++
++		parsed += sizeof(patch_list->patch[0]);
++	}
++
++	parse_info->parsed = parsed;
++
++	return 0;
++}
++
++static int bin_read_guc_wq_item(ipts_info_t *ipts,
++					bin_parse_info_t *parse_info,
++					bin_guc_wq_item_t **guc_wq_item)
++{
++	ipts_bin_guc_wq_info_t *bin_guc_wq;
++	bin_guc_wq_item_t *item;
++	u8 *wi_data;
++	int size, parsed, hdr_size, wi_size;
++	int i, batch_offset;
++	
++	parsed = parse_info->parsed;
++	size = parse_info->size;
++	bin_guc_wq = (ipts_bin_guc_wq_info_t *)&parse_info->data[parsed];
++
++	wi_size = bin_guc_wq->size;
++	wi_data = bin_guc_wq->data;
++	batch_offset = bin_guc_wq->batch_offset;
++	ipts_dbg(ipts, "wi size = %d, bt offset = %d\n", wi_size, batch_offset);
++	for (i = 0; i < wi_size / sizeof(u32); i++) {
++		ipts_dbg(ipts, "wi[%d] = 0x%08x\n", i, *((u32*)wi_data + i));
++	}
++	hdr_size = sizeof(bin_guc_wq->size) + sizeof(bin_guc_wq->batch_offset);
++
++	if (hdr_size > (size - parsed)) {
++		return -EINVAL;
++	}
++	parsed += hdr_size;
++
++	item = vmalloc(sizeof(bin_guc_wq_item_t) + wi_size);
++	if (item == NULL)
++		return -ENOMEM;
++
++	item->size = wi_size;
++	item->batch_offset = batch_offset;
++	memcpy(item->data, wi_data, wi_size);
++
++	*guc_wq_item = item;
++
++	parsed += wi_size;
++	parse_info->parsed = parsed;
++
++	return 0;
++}
++
++static int bin_setup_guc_workqueue(ipts_info_t *ipts,
++					bin_kernel_list_t *kernel_list)
++{
++	bin_alloc_info_t *alloc_info;
++	bin_workload_t *wl;
++	bin_kernel_info_t *kernel;
++	u8 *wq_start, *wq_addr, *wi_data;
++	bin_buffer_t *bin_buf;
++	int wq_size, wi_size, parallel_idx, cmd_idx, k_idx, iter_size;
++	int i, num_of_parallels, batch_offset, k_num, total_workload;
++	
++	wq_addr = (u8*)ipts->resource.wq_info.wq_addr;
++	wq_size = ipts->resource.wq_info.wq_size;
++	num_of_parallels = ipts_get_num_of_parallel_buffers(ipts);
++	total_workload = ipts_get_wq_item_size(ipts);
++	k_num = kernel_list->num_of_kernels;
++
++	iter_size = total_workload * num_of_parallels;
++	if (wq_size % iter_size) {
++		ipts_err(ipts, "wq item cannot fit into wq\n");
++		return -EINVAL;
++	}
++
++	wq_start = wq_addr;
++	for (parallel_idx = 0; parallel_idx < num_of_parallels;
++							parallel_idx++) {
++		kernel = &kernel_list->kernels[0];
++		for (k_idx = 0; k_idx < k_num; k_idx++, kernel++) {
++			wl = kernel->wl;
++			alloc_info = kernel->alloc_info;
++
++			batch_offset = kernel->guc_wq_item->batch_offset;
++			wi_size = kernel->guc_wq_item->size;
++			wi_data = &kernel->guc_wq_item->data[0];
++			
++			cmd_idx = wl[parallel_idx].cmdbuf_index;
++			bin_buf = &alloc_info->buffs[cmd_idx];
++
++			/* Patch the WQ Data with proper batch buffer offset */
++			*(u32*)(wi_data + batch_offset) =
++				(u32)(unsigned long)(bin_buf->buf->gfx_addr);
++
++			memcpy(wq_addr, wi_data, wi_size);
++
++			wq_addr += wi_size;
++		}
++	}
++
++	for (i = 0; i < (wq_size / iter_size) - 1; i++) {
++		memcpy(wq_addr, wq_start, iter_size);
++		wq_addr += iter_size;
++	}
++
++	return 0;
++}
++
++static int bin_read_bufid_patch(ipts_info_t *ipts,
++					bin_parse_info_t *parse_info,
++					ipts_bin_bufid_patch_t *bufid_patch)
++{
++	ipts_bin_bufid_patch_t *patch;
++	int size, parsed;
++
++	parsed = parse_info->parsed;
++	size = parse_info->size;
++	patch = (ipts_bin_bufid_patch_t *)&parse_info->data[parsed];
++
++	if (sizeof(ipts_bin_bufid_patch_t) > (size - parsed)) {
++		ipts_dbg(ipts, "invalid bufid info\n");
++		return -EINVAL;
++	}
++	parsed += sizeof(ipts_bin_bufid_patch_t);
++
++	memcpy(bufid_patch, patch, sizeof(ipts_bin_bufid_patch_t));
++
++	parse_info->parsed = parsed;
++
++	return 0;
++}
++
++static int bin_setup_bufid_buffer(ipts_info_t *ipts, bin_kernel_list_t *kernel_list)
++{
++	intel_ipts_mapbuffer_t *buf, *cmd_buf;
++	bin_kernel_info_t *last_kernel;
++	bin_alloc_info_t *alloc_info;
++	bin_workload_t *wl;
++	u8 *batch;
++	int parallel_idx, num_of_parallels, cmd_idx;
++	u32 mem_offset, imm_offset;
++
++	buf = ipts_map_buffer(ipts, PAGE_SIZE, 0);
++	if (!buf) {
++		return -ENOMEM;
++	}
++
++	last_kernel = &kernel_list->kernels[kernel_list->num_of_kernels - 1];
++
++	mem_offset = last_kernel->bufid_patch.mem_offset;
++	imm_offset = last_kernel->bufid_patch.imm_offset;
++	wl = last_kernel->wl;
++	alloc_info = last_kernel->alloc_info;
++
++	/* Initialize the buffer with default value */
++        *((u32*)buf->cpu_addr) = LASTSUBMITID_DEFAULT_VALUE;
++	ipts->current_buffer_index = LASTSUBMITID_DEFAULT_VALUE;
++	ipts->last_buffer_completed = LASTSUBMITID_DEFAULT_VALUE;
++	ipts->last_submitted_id = (int*)buf->cpu_addr;
++
++	num_of_parallels = ipts_get_num_of_parallel_buffers(ipts);
++	for (parallel_idx = 0; parallel_idx < num_of_parallels; parallel_idx++) {
++		cmd_idx = wl[parallel_idx].cmdbuf_index;
++		cmd_buf = alloc_info->buffs[cmd_idx].buf;
++		batch = (u8*)(u64)cmd_buf->cpu_addr;
++
++		*((u32*)(batch + mem_offset)) = (u32)(u64)(buf->gfx_addr);
++                *((u32*)(batch + imm_offset)) = parallel_idx;
++	}
++
++	kernel_list->bufid_buf = buf;
++
++	return 0;
++}
++
++static void unmap_buffers(ipts_info_t *ipts, bin_alloc_info_t *alloc_info)
++{
++	bin_buffer_t *buffs;
++	int i, num_of_buffers;
++
++	num_of_buffers = alloc_info->num_of_buffers;
++	buffs = &alloc_info->buffs[0];
++
++	for (i = 0; i < num_of_buffers; i++) {
++		if (buffs[i].no_unmap != true && buffs[i].buf != NULL)
++			ipts_unmap_buffer(ipts, buffs[i].buf);
++	}
++}
++
++static int load_kernel(ipts_info_t *ipts, bin_parse_info_t *parse_info,
++						bin_kernel_info_t *kernel)
++{
++	ipts_bin_header_t *hdr;
++	bin_workload_t *wl;
++	bin_alloc_info_t *alloc_info;
++	bin_guc_wq_item_t *guc_wq_item = NULL;
++	ipts_bin_bufid_patch_t bufid_patch;
++	int num_of_parallels, ret;
++
++	num_of_parallels = ipts_get_num_of_parallel_buffers(ipts);
++
++        /* check header version and magic numbers */
++	hdr = (ipts_bin_header_t *)parse_info->data;
++	if (hdr->version != IPTS_BIN_HEADER_VERSION ||
++					strncmp(hdr->str, "IOCL", 4) != 0) {
++		ipts_err(ipts, "binary header is not correct version = %d, "
++				"string = %c%c%c%c\n", hdr->version,
++				hdr->str[0], hdr->str[1],
++				hdr->str[2], hdr->str[3] );
++		return -EINVAL;
++	}
++
++	parse_info->parsed = sizeof(ipts_bin_header_t);
++	wl = vmalloc(sizeof(bin_workload_t) * num_of_parallels);
++	if (wl == NULL)
++		return -ENOMEM;
++	memset(wl, 0, sizeof(bin_workload_t) * num_of_parallels);
++
++	alloc_info = vmalloc(sizeof(bin_alloc_info_t));
++	if (alloc_info == NULL) {
++		vfree(wl);
++		return -ENOMEM;
++	}
++	memset(alloc_info, 0, sizeof(bin_alloc_info_t));
++
++        ipts_dbg(ipts, "kernel setup(size : %d)\n", parse_info->size);
++
++	ret = bin_read_allocation_list(ipts, parse_info, alloc_info);
++	if (ret) {
++        	ipts_dbg(ipts, "error read_allocation_list\n");
++		goto setup_error;
++	}
++
++	ret = bin_read_cmd_buffer(ipts, parse_info, alloc_info, wl);
++	if (ret) {
++        	ipts_dbg(ipts, "error read_cmd_buffer\n");
++		goto setup_error;
++	}
++
++	ret = bin_read_res_list(ipts, parse_info, alloc_info, wl);
++	if (ret) {
++        	ipts_dbg(ipts, "error read_res_list\n");
++		goto setup_error;
++	}
++
++	ret = bin_read_patch_list(ipts, parse_info, alloc_info, wl);
++	if (ret) {
++        	ipts_dbg(ipts, "error read_patch_list\n");
++		goto setup_error;
++	}
++
++	ret = bin_read_guc_wq_item(ipts, parse_info, &guc_wq_item);
++	if (ret) {
++        	ipts_dbg(ipts, "error read_guc_workqueue\n");
++		goto setup_error;
++	}
++
++	memset(&bufid_patch, 0, sizeof(bufid_patch));
++	ret = bin_read_bufid_patch(ipts, parse_info, &bufid_patch);
++	if (ret) {
++        	ipts_dbg(ipts, "error read_bufid_patch\n");
++		goto setup_error;
++	}
++
++	kernel->wl = wl;
++	kernel->alloc_info = alloc_info;
++	kernel->is_vendor = is_parsing_vendor_kernel(parse_info);
++	kernel->guc_wq_item = guc_wq_item;
++	memcpy(&kernel->bufid_patch, &bufid_patch, sizeof(bufid_patch));
++
++        return 0;
++
++setup_error:
++	vfree(guc_wq_item);
++
++	unmap_buffers(ipts, alloc_info);
++
++	vfree(alloc_info->buffs);
++	vfree(alloc_info);
++	vfree(wl);
++
++	return ret;
++}
++
++void bin_setup_input_output(ipts_info_t *ipts, bin_kernel_list_t *kernel_list)
++{
++	bin_kernel_info_t *vendor_kernel;
++	bin_workload_t *wl;
++	intel_ipts_mapbuffer_t *buf;
++	bin_alloc_info_t *alloc_info;
++	int parallel_idx, num_of_parallels, i, buf_idx;
++
++	vendor_kernel = &kernel_list->kernels[0];
++
++	wl = vendor_kernel->wl;
++	alloc_info = vendor_kernel->alloc_info;
++	ipts->resource.num_of_outputs = alloc_info->num_of_outputs;
++	num_of_parallels = ipts_get_num_of_parallel_buffers(ipts);
++
++	for (parallel_idx = 0; parallel_idx < num_of_parallels; parallel_idx++) {
++		buf_idx = wl[parallel_idx].iobuf_input;
++		buf = alloc_info->buffs[buf_idx].buf;
++
++		ipts_dbg(ipts, "in_buf[%d](%d) c:%p, p:%p, g:%p\n",
++					parallel_idx, buf_idx, (void*)buf->cpu_addr,
++					(void*)buf->phy_addr, (void*)buf->gfx_addr);
++
++		ipts_set_input_buffer(ipts, parallel_idx, buf->cpu_addr,
++								buf->phy_addr);
++
++		for (i = 0; i < alloc_info->num_of_outputs; i++) {
++			buf_idx = wl[parallel_idx].iobuf_output[i];
++			buf = alloc_info->buffs[buf_idx].buf;
++
++			ipts_dbg(ipts, "out_buf[%d][%d] c:%p, p:%p, g:%p\n",
++					parallel_idx, i, (void*)buf->cpu_addr,
++					(void*)buf->phy_addr, (void*)buf->gfx_addr);
++
++			ipts_set_output_buffer(ipts, parallel_idx, i,
++					buf->cpu_addr, buf->phy_addr);
++		}
++	}
++}
++
++static void unload_kernel(ipts_info_t *ipts, bin_kernel_info_t *kernel)
++{
++	bin_alloc_info_t *alloc_info = kernel->alloc_info;
++	bin_guc_wq_item_t *guc_wq_item = kernel->guc_wq_item;
++
++	if (guc_wq_item) {
++		vfree(guc_wq_item);
++	}
++
++	if (alloc_info) {
++		unmap_buffers(ipts, alloc_info);
++
++		vfree(alloc_info->buffs);
++		vfree(alloc_info);
++	}
++}
++
++static int setup_kernel(ipts_info_t *ipts, bin_fw_list_t *fw_list)
++{
++	bin_kernel_list_t *kernel_list = NULL;
++	bin_kernel_info_t *kernel = NULL;
++	const struct firmware *fw = NULL;
++	bin_workload_t *wl;
++	bin_fw_info_t *fw_info;
++	char *fw_name, *fw_data;
++	bin_parse_info_t parse_info;
++	int ret = 0, kernel_idx = 0, num_of_kernels = 0;
++	int vendor_output_idx, total_workload = 0;
++	char fw_path[MAX_IOCL_FILE_PATH_LEN];
++
++	num_of_kernels = fw_list->num_of_fws;
++	kernel_list = vmalloc(sizeof(*kernel) * num_of_kernels + sizeof(*kernel_list));
++	if (kernel_list == NULL)
++		return -ENOMEM;
++
++	memset(kernel_list, 0, sizeof(*kernel) * num_of_kernels + sizeof(*kernel_list));
++	kernel_list->num_of_kernels = num_of_kernels;
++	kernel = &kernel_list->kernels[0];
++
++	fw_data = (char *)&fw_list->fw_info[0];
++	for (kernel_idx = 0; kernel_idx < num_of_kernels; kernel_idx++) {
++		fw_info = (bin_fw_info_t *)fw_data;
++		fw_name = &fw_info->fw_name[0];
++		vendor_output_idx = fw_info->vendor_output;
++		snprintf(fw_path, MAX_IOCL_FILE_PATH_LEN, IPTS_FW_PATH_FMT, fw_name);
++		ret = request_firmware(&fw, (const char *)fw_path, &ipts->cldev->dev);
++		if (ret) {
++			ipts_err(ipts, "cannot read fw %s\n", fw_path);
++			goto error_exit;
++		}
++
++		parse_info.data = (u8*)fw->data;
++		parse_info.size = fw->size;
++		parse_info.parsed = 0;
++		parse_info.fw_info = fw_info;
++		parse_info.vendor_kernel = (kernel_idx == 0) ? NULL : &kernel[0];
++		parse_info.interested_vendor_output = vendor_output_idx;
++
++		ret = load_kernel(ipts, &parse_info, &kernel[kernel_idx]);
++		if (ret) {
++			ipts_err(ipts, "do_setup_kernel error : %d\n", ret);
++			release_firmware(fw);
++			goto error_exit;
++		}
++
++		release_firmware(fw);
++
++		total_workload += kernel[kernel_idx].guc_wq_item->size;
++
++		/* advance to the next kernel */
++		fw_data += sizeof(bin_fw_info_t);
++		fw_data += sizeof(bin_data_file_info_t) * fw_info->num_of_data_files;
++	}
++
++	ipts_set_wq_item_size(ipts, total_workload);
++	
++	ret = bin_setup_guc_workqueue(ipts, kernel_list);
++	if (ret) {
++        	ipts_dbg(ipts, "error setup_guc_workqueue\n");
++		goto error_exit;
++	}
++
++	ret = bin_setup_bufid_buffer(ipts, kernel_list);
++	if (ret) {
++        	ipts_dbg(ipts, "error setup_lastbubmit_buffer\n");
++		goto error_exit;
++	}
++
++	bin_setup_input_output(ipts, kernel_list);
++
++	/* workload is not needed during run-time so free them */
++	for (kernel_idx = 0; kernel_idx < num_of_kernels; kernel_idx++) {
++		wl = kernel[kernel_idx].wl;
++		vfree(wl);
++	}
++
++	ipts->kernel_handle = (u64)kernel_list;
++
++	return 0;
++
++error_exit:
++
++	for (kernel_idx = 0; kernel_idx < num_of_kernels; kernel_idx++) {
++		wl = kernel[kernel_idx].wl;
++		vfree(wl);
++		unload_kernel(ipts, &kernel[kernel_idx]);
++	}
++
++	vfree(kernel_list);
++
++	return ret;
++}
++
++
++static void release_kernel(ipts_info_t *ipts)
++{
++	bin_kernel_list_t *kernel_list;
++	bin_kernel_info_t *kernel;
++	int k_idx, k_num;
++
++	kernel_list = (bin_kernel_list_t *)ipts->kernel_handle;
++	k_num = kernel_list->num_of_kernels;
++	kernel = &kernel_list->kernels[0];
++
++	for (k_idx = 0; k_idx < k_num; k_idx++) {
++		unload_kernel(ipts, kernel);
++		kernel++;
++	}	
++
++	ipts_unmap_buffer(ipts, kernel_list->bufid_buf);
++
++	vfree(kernel_list);
++	ipts->kernel_handle = 0;
++}
++
++int ipts_init_kernels(ipts_info_t *ipts)
++{
++	const struct firmware *config_fw = NULL;
++	const char *config_fw_path = IPTS_FW_CONFIG_FILE;
++	bin_fw_list_t *fw_list;
++	int ret;
++
++	ret = ipts_open_gpu(ipts);
++	if (ret) {
++		ipts_err(ipts, "open gpu error : %d\n", ret);
++		return ret;
++	}
++
++	ret = request_firmware(&config_fw, config_fw_path, &ipts->cldev->dev);
++	if (ret) {
++		ipts_err(ipts, "request firmware error : %d\n", ret);
++		goto close_gpu;
++	}
++
++	fw_list = (bin_fw_list_t *)config_fw->data;
++	ret = setup_kernel(ipts, fw_list);
++	if (ret) {
++		ipts_err(ipts, "setup kernel error : %d\n", ret);
++		goto close_firmware;
++	}
++
++	release_firmware(config_fw);
++
++	return ret;
++
++close_firmware:
++	release_firmware(config_fw);
++
++close_gpu:
++	ipts_close_gpu(ipts);
++
++	return ret;
++}
++
++void ipts_release_kernels(ipts_info_t *ipts)
++{
++	release_kernel(ipts);
++	ipts_close_gpu(ipts);
++}
+diff --git a/drivers/misc/ipts/ipts-kernel.h b/drivers/misc/ipts/ipts-kernel.h
+new file mode 100644
+index 000000000000..0e7f1393b807
+--- /dev/null
++++ b/drivers/misc/ipts/ipts-kernel.h
+@@ -0,0 +1,23 @@
++/*
++ *
++ * Intel Precise Touch & Stylus Linux driver
++ * Copyright (c) 2016, Intel Corporation.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms and conditions of the GNU General Public License,
++ * version 2, as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
++ * more details.
++ *
++ */
++
++#ifndef _ITPS_GFX_H
++#define _ITPS_GFX_H
++
++int ipts_init_kernels(ipts_info_t *ipts);
++void ipts_release_kernels(ipts_info_t *ipts);
++
++#endif
+diff --git a/drivers/misc/ipts/ipts-mei-msgs.h b/drivers/misc/ipts/ipts-mei-msgs.h
+new file mode 100644
+index 000000000000..8ca146800a47
+--- /dev/null
++++ b/drivers/misc/ipts/ipts-mei-msgs.h
+@@ -0,0 +1,585 @@
++/*
++ * Precise Touch HECI Message
++ *
++ * Copyright (c) 2013-2016, Intel Corporation.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms and conditions of the GNU General Public License,
++ * version 2, as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
++ * more details.
++ */
++
++#ifndef _IPTS_MEI_MSGS_H_
++#define _IPTS_MEI_MSGS_H_
++
++#include "ipts-sensor-regs.h"
++
++#pragma pack(1)
++
++
++// Initial protocol version
++#define TOUCH_HECI_CLIENT_PROTOCOL_VERSION      10
++
++// GUID that identifies the Touch HECI client.
++#define TOUCH_HECI_CLIENT_GUID  \
++            {0x3e8d0870, 0x271a, 0x4208, {0x8e, 0xb5, 0x9a, 0xcb, 0x94, 0x02, 0xae, 0x04}}
++
++
++// define C_ASSERT macro to check structure size and fail compile for unexpected mismatch
++#ifndef C_ASSERT
++#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1]
++#endif
++
++
++// General Type Defines for compatibility with HID driver and BIOS
++#ifndef BIT0
++#define BIT0 1
++#endif
++#ifndef BIT1
++#define BIT1 2
++#endif
++#ifndef BIT2
++#define BIT2 4
++#endif
++
++
++#define TOUCH_SENSOR_GET_DEVICE_INFO_CMD        0x00000001
++#define TOUCH_SENSOR_GET_DEVICE_INFO_RSP        0x80000001
++
++
++#define TOUCH_SENSOR_SET_MODE_CMD               0x00000002
++#define TOUCH_SENSOR_SET_MODE_RSP               0x80000002
++
++
++#define TOUCH_SENSOR_SET_MEM_WINDOW_CMD         0x00000003
++#define TOUCH_SENSOR_SET_MEM_WINDOW_RSP         0x80000003
++
++
++#define TOUCH_SENSOR_QUIESCE_IO_CMD             0x00000004
++#define TOUCH_SENSOR_QUIESCE_IO_RSP             0x80000004
++
++
++#define TOUCH_SENSOR_HID_READY_FOR_DATA_CMD     0x00000005
++#define TOUCH_SENSOR_HID_READY_FOR_DATA_RSP     0x80000005
++
++
++#define TOUCH_SENSOR_FEEDBACK_READY_CMD         0x00000006
++#define TOUCH_SENSOR_FEEDBACK_READY_RSP         0x80000006
++
++
++#define TOUCH_SENSOR_CLEAR_MEM_WINDOW_CMD       0x00000007
++#define TOUCH_SENSOR_CLEAR_MEM_WINDOW_RSP       0x80000007
++
++
++#define TOUCH_SENSOR_NOTIFY_DEV_READY_CMD       0x00000008
++#define TOUCH_SENSOR_NOTIFY_DEV_READY_RSP       0x80000008
++
++
++#define TOUCH_SENSOR_SET_POLICIES_CMD           0x00000009
++#define TOUCH_SENSOR_SET_POLICIES_RSP           0x80000009
++
++
++#define TOUCH_SENSOR_GET_POLICIES_CMD           0x0000000A
++#define TOUCH_SENSOR_GET_POLICIES_RSP           0x8000000A
++
++
++#define TOUCH_SENSOR_RESET_CMD                  0x0000000B
++#define TOUCH_SENSOR_RESET_RSP                  0x8000000B
++
++
++#define TOUCH_SENSOR_READ_ALL_REGS_CMD          0x0000000C
++#define TOUCH_SENSOR_READ_ALL_REGS_RSP          0x8000000C
++
++
++#define TOUCH_SENSOR_CMD_ERROR_RSP              0x8FFFFFFF  // M2H: ME sends this message to indicate previous command was unrecognized/unsupported
++
++
++
++//*******************************************************************
++//
++// Touch Sensor Status Codes
++//
++//*******************************************************************
++typedef enum touch_status
++{
++    TOUCH_STATUS_SUCCESS = 0,               //  0 Requested operation was successful
++    TOUCH_STATUS_INVALID_PARAMS,            //  1 Invalid parameter(s) sent
++    TOUCH_STATUS_ACCESS_DENIED,             //  2 Unable to validate address range
++    TOUCH_STATUS_CMD_SIZE_ERROR,            //  3 HECI message incorrect size for specified command
++    TOUCH_STATUS_NOT_READY,                 //  4 Memory window not set or device is not armed for operation
++    TOUCH_STATUS_REQUEST_OUTSTANDING,       //  5 There is already an outstanding message of the same type, must wait for response before sending another request of that type
++    TOUCH_STATUS_NO_SENSOR_FOUND,           //  6 Sensor could not be found. Either no sensor is connected, the sensor has not yet initialized, or the system is improperly configured.
++    TOUCH_STATUS_OUT_OF_MEMORY,             //  7 Not enough memory/storage for requested operation
++    TOUCH_STATUS_INTERNAL_ERROR,            //  8 Unexpected error occurred
++    TOUCH_STATUS_SENSOR_DISABLED,           //  9 Used in TOUCH_SENSOR_HID_READY_FOR_DATA_RSP to indicate sensor has been disabled or reset and must be reinitialized.
++    TOUCH_STATUS_COMPAT_CHECK_FAIL,         // 10 Used to indicate compatibility revision check between sensor and ME failed, or protocol ver between ME/HID/Kernels failed.
++    TOUCH_STATUS_SENSOR_EXPECTED_RESET,     // 11 Indicates sensor went through a reset initiated by ME
++    TOUCH_STATUS_SENSOR_UNEXPECTED_RESET,   // 12 Indicates sensor went through an unexpected reset
++    TOUCH_STATUS_RESET_FAILED,              // 13 Requested sensor reset failed to complete
++    TOUCH_STATUS_TIMEOUT,                   // 14 Operation timed out
++    TOUCH_STATUS_TEST_MODE_FAIL,            // 15 Test mode pattern did not match expected values
++    TOUCH_STATUS_SENSOR_FAIL_FATAL,         // 16 Indicates sensor reported fatal error during reset sequence. Further progress is not possible.
++    TOUCH_STATUS_SENSOR_FAIL_NONFATAL,      // 17 Indicates sensor reported non-fatal error during reset sequence. HID/BIOS logs error and attempts to continue.
++    TOUCH_STATUS_INVALID_DEVICE_CAPS,       // 18 Indicates sensor reported invalid capabilities, such as not supporting required minimum frequency or I/O mode.
++    TOUCH_STATUS_QUIESCE_IO_IN_PROGRESS,    // 19 Indicates that command cannot be complete until ongoing Quiesce I/O flow has completed.
++    TOUCH_STATUS_MAX                        // 20 Invalid value, never returned
++} touch_status_t;
++C_ASSERT(sizeof(touch_status_t) == 4);
++
++
++
++//*******************************************************************
++//
++// Defines for message structures used for Host to ME communication
++//
++//*******************************************************************
++
++
++typedef enum touch_sensor_mode
++{
++    TOUCH_SENSOR_MODE_HID = 0,          // Set mode to HID mode
++    TOUCH_SENSOR_MODE_RAW_DATA,         // Set mode to Raw Data mode
++    TOUCH_SENSOR_MODE_SENSOR_DEBUG = 4, // Used like TOUCH_SENSOR_MODE_HID but data coming from sensor is not necessarily a HID packet.
++    TOUCH_SENSOR_MODE_MAX               // Invalid value
++} touch_sensor_mode_t;
++C_ASSERT(sizeof(touch_sensor_mode_t) == 4);
++
++typedef struct touch_sensor_set_mode_cmd_data
++{
++    touch_sensor_mode_t	sensor_mode;     // Indicate desired sensor mode
++    u32					Reserved[3];    // For future expansion
++} touch_sensor_set_mode_cmd_data_t;
++C_ASSERT(sizeof(touch_sensor_set_mode_cmd_data_t) == 16);
++
++
++#define TOUCH_SENSOR_MAX_DATA_BUFFERS   16
++#define TOUCH_HID_2_ME_BUFFER_ID        TOUCH_SENSOR_MAX_DATA_BUFFERS
++#define TOUCH_HID_2_ME_BUFFER_SIZE_MAX  1024
++#define TOUCH_INVALID_BUFFER_ID         0xFF
++
++typedef struct touch_sensor_set_mem_window_cmd_data
++{
++    u32  touch_data_buffer_addr_lower[TOUCH_SENSOR_MAX_DATA_BUFFERS];    // Lower 32 bits of Touch Data Buffer physical address. Size of each buffer should be TOUCH_SENSOR_GET_DEVICE_INFO_RSP_DATA.FrameSize
++    u32  touch_data_buffer_addr_upper[TOUCH_SENSOR_MAX_DATA_BUFFERS];    // Upper 32 bits of Touch Data Buffer physical address. Size of each buffer should be TOUCH_SENSOR_GET_DEVICE_INFO_RSP_DATA.FrameSize
++    u32  tail_offset_addr_lower;                                        // Lower 32 bits of Tail Offset physical address
++    u32  tail_offset_addr_upper;                                        // Upper 32 bits of Tail Offset physical address, always 32 bit, increment by WorkQueueItemSize
++    u32  doorbell_cookie_addr_lower;                                    // Lower 32 bits of Doorbell register physical address
++    u32  doorbell_cookie_addr_upper;                                    // Upper 32 bits of Doorbell register physical address, always 32 bit, increment as integer, rollover to 1
++    u32  feedback_buffer_addr_lower[TOUCH_SENSOR_MAX_DATA_BUFFERS];     // Lower 32 bits of Feedback Buffer physical address. Size of each buffer should be TOUCH_SENSOR_GET_DEVICE_INFO_RSP_DATA.FeedbackSize
++    u32  feedback_buffer_addr_upper[TOUCH_SENSOR_MAX_DATA_BUFFERS];     // Upper 32 bits of Feedback Buffer physical address. Size of each buffer should be TOUCH_SENSOR_GET_DEVICE_INFO_RSP_DATA.FeedbackSize
++    u32  hid2me_buffer_addr_lower;                                      // Lower 32 bits of dedicated HID to ME communication buffer. Size is Hid2MeBufferSize.
++    u32  hid2me_buffer_addr_upper;                                      // Upper 32 bits of dedicated HID to ME communication buffer. Size is Hid2MeBufferSize.
++    u32  hid2me_buffer_size;                                           // Size in bytes of Hid2MeBuffer, can be no bigger than TOUCH_HID_2_ME_BUFFER_SIZE_MAX
++    u8   reserved1;                                                  // For future expansion
++    u8   work_queue_item_size;                                          // Size in bytes of the GuC Work Queue Item pointed to by TailOffset
++    u16  work_queue_size;                                              // Size in bytes of the entire GuC Work Queue
++    u32  reserved[8];                                                // For future expansion
++} touch_sensor_set_mem_window_cmd_data_t;
++C_ASSERT(sizeof(touch_sensor_set_mem_window_cmd_data_t) == 320);
++
++
++#define TOUCH_SENSOR_QUIESCE_FLAG_GUC_RESET BIT0   // indicates GuC got reset and ME must re-read GuC data such as TailOffset and Doorbell Cookie values
++
++typedef struct touch_sensor_quiesce_io_cmd_data
++{
++    u32  quiesce_flags;   // Optionally set TOUCH_SENSOR_QUIESCE_FLAG_GUC_RESET
++    u32  reserved[2];
++} touch_sensor_quiesce_io_cmd_data_t;
++C_ASSERT(sizeof(touch_sensor_quiesce_io_cmd_data_t) == 12);
++
++
++typedef struct touch_sensor_feedback_ready_cmd_data
++{
++    u8   feedback_index;  // Index value from 0 to TOUCH_HID_2_ME_BUFFER_ID used to indicate which Feedback Buffer to use. Using special value TOUCH_HID_2_ME_BUFFER_ID
++                            // is an indication to ME to get feedback data from the Hid2Me buffer instead of one of the standard Feedback buffers.
++    u8   reserved1[3];   // For future expansion
++    u32  transaction_id;  // Transaction ID that was originally passed to host in TOUCH_HID_PRIVATE_DATA. Used to track round trip of a given transaction for performance measurements.
++    u32  reserved2[2];   // For future expansion
++} touch_sensor_feedback_ready_cmd_data_t;
++C_ASSERT(sizeof(touch_sensor_feedback_ready_cmd_data_t) == 16);
++
++
++#define TOUCH_DEFAULT_DOZE_TIMER_SECONDS    30
++
++typedef enum touch_freq_override
++{
++    TOUCH_FREQ_OVERRIDE_NONE,   // Do not apply any override
++    TOUCH_FREQ_OVERRIDE_10MHZ,  // Force frequency to 10MHz (not currently supported)
++    TOUCH_FREQ_OVERRIDE_17MHZ,  // Force frequency to 17MHz
++    TOUCH_FREQ_OVERRIDE_30MHZ,  // Force frequency to 30MHz
++    TOUCH_FREQ_OVERRIDE_50MHZ,  // Force frequency to 50MHz (not currently supported)
++    TOUCH_FREQ_OVERRIDE_MAX     // Invalid value
++} touch_freq_override_t;
++C_ASSERT(sizeof(touch_freq_override_t) == 4);
++
++typedef enum touch_spi_io_mode_override
++{
++    TOUCH_SPI_IO_MODE_OVERRIDE_NONE,    // Do not apply any override
++    TOUCH_SPI_IO_MODE_OVERRIDE_SINGLE,  // Force Single I/O
++    TOUCH_SPI_IO_MODE_OVERRIDE_DUAL,    // Force Dual I/O
++    TOUCH_SPI_IO_MODE_OVERRIDE_QUAD,    // Force Quad I/O
++    TOUCH_SPI_IO_MODE_OVERRIDE_MAX      // Invalid value
++} touch_spi_io_mode_override_t;
++C_ASSERT(sizeof(touch_spi_io_mode_override_t) == 4);
++
++// Debug Policy bits used by TOUCH_POLICY_DATA.DebugOverride
++#define TOUCH_DBG_POLICY_OVERRIDE_STARTUP_TIMER_DIS BIT0    // Disable sensor startup timer
++#define TOUCH_DBG_POLICY_OVERRIDE_SYNC_BYTE_DIS     BIT1    // Disable Sync Byte check
++#define TOUCH_DBG_POLICY_OVERRIDE_ERR_RESET_DIS     BIT2    // Disable error resets
++
++typedef struct touch_policy_data
++{
++    u32                      reserved0;          // For future expansion.
++    u32                      doze_timer     :16;  // Value in seconds, after which ME will put the sensor into Doze power state if no activity occurs. Set
++                                                    // to 0 to disable Doze mode (not recommended). Value will be set to TOUCH_DEFAULT_DOZE_TIMER_SECONDS by
++                                                    // default.
++    touch_freq_override_t         freq_override  :3;   // Override frequency requested by sensor
++    touch_spi_io_mode_override_t  spi_io_override :3;   // Override IO mode requested by sensor
++    u32                      reserved1     :10;  // For future expansion
++    u32                      reserved2;          // For future expansion
++    u32                      debug_override;      // Normally all bits will be zero. Bits will be defined as needed for enabling special debug features
++} touch_policy_data_t;
++C_ASSERT(sizeof(touch_policy_data_t) == 16);
++
++typedef struct touch_sensor_set_policies_cmd_data
++{
++    touch_policy_data_t           policy_data;         // Contains the desired policy to be set
++} touch_sensor_set_policies_cmd_data_t;
++C_ASSERT(sizeof(touch_sensor_set_policies_cmd_data_t) == 16);
++
++
++typedef enum touch_sensor_reset_type
++{
++    TOUCH_SENSOR_RESET_TYPE_HARD,   // Hardware Reset using dedicated GPIO pin
++    TOUCH_SENSOR_RESET_TYPE_SOFT,   // Software Reset using command written over SPI interface
++    TOUCH_SENSOR_RESET_TYPE_MAX     // Invalid value
++} touch_sensor_reset_type_t;
++C_ASSERT(sizeof(touch_sensor_reset_type_t) == 4);
++
++typedef struct touch_sensor_reset_cmd_data
++{
++    touch_sensor_reset_type_t reset_type;  // Indicate desired reset type
++    u32                  reserved;   // For future expansion
++} touch_sensor_reset_cmd_data_t;
++C_ASSERT(sizeof(touch_sensor_reset_cmd_data_t) == 8);
++
++
++//
++// Host to ME message
++//
++typedef struct touch_sensor_msg_h2m
++{
++    u32  command_code;
++    union
++    {
++        touch_sensor_set_mode_cmd_data_t        set_mode_cmd_data;
++        touch_sensor_set_mem_window_cmd_data_t  set_window_cmd_data;
++        touch_sensor_quiesce_io_cmd_data_t      quiesce_io_cmd_data;
++        touch_sensor_feedback_ready_cmd_data_t  feedback_ready_cmd_data;
++        touch_sensor_set_policies_cmd_data_t    set_policies_cmd_data;
++        touch_sensor_reset_cmd_data_t           reset_cmd_data;
++    } h2m_data;
++} touch_sensor_msg_h2m_t;
++C_ASSERT(sizeof(touch_sensor_msg_h2m_t) == 324);
++
++
++//*******************************************************************
++//
++// Defines for message structures used for ME to Host communication
++//
++//*******************************************************************
++
++// I/O mode values used by TOUCH_SENSOR_GET_DEVICE_INFO_RSP_DATA.
++typedef enum touch_spi_io_mode
++{
++    TOUCH_SPI_IO_MODE_SINGLE = 0,   // Sensor set for Single I/O SPI
++    TOUCH_SPI_IO_MODE_DUAL,         // Sensor set for Dual I/O SPI
++    TOUCH_SPI_IO_MODE_QUAD,         // Sensor set for Quad I/O SPI
++    TOUCH_SPI_IO_MODE_MAX           // Invalid value
++} touch_spi_io_mode_t;
++C_ASSERT(sizeof(touch_spi_io_mode_t) == 4);
++
++//
++// TOUCH_SENSOR_GET_DEVICE_INFO_RSP code is sent in response to TOUCH_SENSOR_GET_DEVICE_INFO_CMD. This code will be followed
++// by TOUCH_SENSOR_GET_DEVICE_INFO_RSP_DATA.
++//
++// Possible Status values:
++//      TOUCH_STATUS_SUCCESS:               Command was processed successfully and sensor details are reported.
++//      TOUCH_STATUS_CMD_SIZE_ERROR:        Command sent did not match expected size. Other fields will not contain valid data.
++//      TOUCH_STATUS_NO_SENSOR_FOUND:       Sensor has not yet been detected. Other fields will not contain valid data.
++//      TOUCH_STATUS_INVALID_DEVICE_CAPS:   Indicates sensor does not support minimum required Frequency or I/O Mode. ME firmware will choose best possible option for the errant
++//                                          field. Caller should attempt to continue.
++//      TOUCH_STATUS_COMPAT_CHECK_FAIL:     Indicates TouchIC/ME compatibility mismatch. Caller should attempt to continue.
++//
++typedef struct touch_sensor_get_device_info_rsp_data
++{
++    u16				vendor_id;               // Touch Sensor vendor ID
++    u16              device_id;               // Touch Sensor device ID
++    u32              hw_rev;                  // Touch Sensor Hardware Revision
++    u32              fw_rev;                  // Touch Sensor Firmware Revision
++    u32              frame_size;              // Max size of one frame returned by Touch IC in bytes. This data will be TOUCH_RAW_DATA_HDR followed
++                                                // by a payload. The payload can be raw data or a HID structure depending on mode.
++    u32              feedback_size;           // Max size of one Feedback structure in bytes
++    touch_sensor_mode_t	sensor_mode;             // Current operating mode of the sensor
++    u32              max_touch_points  :8;     // Maximum number of simultaneous touch points that can be reported by sensor
++    touch_freq_t          spi_frequency    :8;     // SPI bus Frequency supported by sensor and ME firmware
++    touch_spi_io_mode_t   spi_io_mode       :8;     // SPI bus I/O Mode supported by sensor and ME firmware
++    u32              reserved0       :8;     // For future expansion
++    u8               sensor_minor_eds_rev;      // Minor version number of EDS spec supported by sensor (from Compat Rev ID Reg)
++    u8               sensor_major_eds_rev;      // Major version number of EDS spec supported by sensor (from Compat Rev ID Reg)
++    u8               me_minor_eds_rev;          // Minor version number of EDS spec supported by ME
++    u8               me_major_eds_rev;          // Major version number of EDS spec supported by ME
++    u8               sensor_eds_intf_rev;       // EDS Interface Revision Number supported by sensor (from Compat Rev ID Reg)
++    u8               me_eds_intf_rev;           // EDS Interface Revision Number supported by ME
++    u8               kernel_compat_ver;        // EU Kernel Compatibility Version  (from Compat Rev ID Reg)
++    u8               reserved1;              // For future expansion
++    u32              reserved2[2];           // For future expansion
++} touch_sensor_get_device_info_rsp_data_t;
++C_ASSERT(sizeof(touch_sensor_get_device_info_rsp_data_t) == 44);
++
++
++//
++// TOUCH_SENSOR_SET_MODE_RSP code is sent in response to TOUCH_SENSOR_SET_MODE_CMD. This code will be followed
++// by TOUCH_SENSOR_SET_MODE_RSP_DATA.
++//
++// Possible Status values:
++//      TOUCH_STATUS_SUCCESS:           Command was processed successfully and mode was set.
++//      TOUCH_STATUS_CMD_SIZE_ERROR:    Command sent did not match expected size. Other fields will not contain valid data.
++//      TOUCH_STATUS_INVALID_PARAMS:    Input parameters are out of range.
++//
++typedef struct touch_sensor_set_mode_rsp_data
++{
++    u32          reserved[3];    // For future expansion
++} touch_sensor_set_mode_rsp_data_t;
++C_ASSERT(sizeof(touch_sensor_set_mode_rsp_data_t) == 12);
++
++
++//
++// TOUCH_SENSOR_SET_MEM_WINDOW_RSP code is sent in response to TOUCH_SENSOR_SET_MEM_WINDOW_CMD. This code will be followed
++// by TOUCH_SENSOR_SET_MEM_WINDOW_RSP_DATA.
++//
++// Possible Status values:
++//      TOUCH_STATUS_SUCCESS:           Command was processed successfully and memory window was set.
++//      TOUCH_STATUS_CMD_SIZE_ERROR:    Command sent did not match expected size. Other fields will not contain valid data.
++//      TOUCH_STATUS_INVALID_PARAMS:    Input parameters are out of range.
++//      TOUCH_STATUS_ACCESS_DENIED:     Unable to map host address ranges for DMA.
++//      TOUCH_STATUS_OUT_OF_MEMORY:     Unable to allocate enough space for needed buffers.
++//
++typedef struct touch_sensor_set_mem_window_rsp_data
++{
++    u32          reserved[3];    // For future expansion
++} touch_sensor_set_mem_window_rsp_data_t;
++C_ASSERT(sizeof(touch_sensor_set_mem_window_rsp_data_t) == 12);
++
++
++//
++// TOUCH_SENSOR_QUIESCE_IO_RSP code is sent in response to TOUCH_SENSOR_QUIESCE_IO_CMD. This code will be followed
++// by TOUCH_SENSOR_QUIESCE_IO_RSP_DATA.
++//
++// Possible Status values:
++//      TOUCH_STATUS_SUCCESS:                   Command was processed successfully and touch flow has stopped.
++//      TOUCH_STATUS_CMD_SIZE_ERROR:            Command sent did not match expected size. Other fields will not contain valid data.
++//      TOUCH_STATUS_QUIESCE_IO_IN_PROGRESS:    Indicates that Quiesce I/O is already in progress and this command cannot be accepted at this time.
++//      TOUCH_STATIS_TIMEOUT:                   Indicates ME timed out waiting for Quiesce I/O flow to complete.
++//
++typedef struct touch_sensor_quiesce_io_rsp_data
++{
++    u32          reserved[3];    // For future expansion
++} touch_sensor_quiesce_io_rsp_data_t;
++C_ASSERT(sizeof(touch_sensor_quiesce_io_rsp_data_t) == 12);
++
++
++// Reset Reason values used in TOUCH_SENSOR_HID_READY_FOR_DATA_RSP_DATA
++typedef enum touch_reset_reason
++{
++    TOUCH_RESET_REASON_UNKNOWN = 0,         // Reason for sensor reset is not known
++    TOUCH_RESET_REASON_FEEDBACK_REQUEST,    // Reset was requested as part of TOUCH_SENSOR_FEEDBACK_READY_CMD
++    TOUCH_RESET_REASON_HECI_REQUEST,        // Reset was requested via TOUCH_SENSOR_RESET_CMD
++    TOUCH_RESET_REASON_MAX
++} touch_reset_reason_t;
++C_ASSERT(sizeof(touch_reset_reason_t) == 4);
++
++//
++// TOUCH_SENSOR_HID_READY_FOR_DATA_RSP code is sent in response to TOUCH_SENSOR_HID_READY_FOR_DATA_CMD. This code will be followed
++// by TOUCH_SENSOR_HID_READY_FOR_DATA_RSP_DATA.
++//
++// Possible Status values:
++//      TOUCH_STATUS_SUCCESS:                   Command was processed successfully and HID data was sent by DMA. This will only be sent in HID mode.
++//      TOUCH_STATUS_CMD_SIZE_ERROR:            Command sent did not match expected size. Other fields will not contain valid data.
++//      TOUCH_STATUS_REQUEST_OUTSTANDING:       Previous request is still outstanding, ME FW cannot handle another request for the same command.
++//      TOUCH_STATUS_NOT_READY:                 Indicates memory window has not yet been set by BIOS/HID.
++//      TOUCH_STATUS_SENSOR_DISABLED:           Indicates that ME to HID communication has been stopped either by TOUCH_SENSOR_QUIESCE_IO_CMD or TOUCH_SENSOR_CLEAR_MEM_WINDOW_CMD.
++//      TOUCH_STATUS_SENSOR_UNEXPECTED_RESET:   Sensor signaled a Reset Interrupt. ME did not expect this and has no info about why this occurred.
++//      TOUCH_STATUS_SENSOR_EXPECTED_RESET:     Sensor signaled a Reset Interrupt. ME either directly requested this reset, or it was expected as part of a defined flow in the EDS.
++//      TOUCH_STATUS_QUIESCE_IO_IN_PROGRESS:    Indicates that Quiesce I/O is already in progress and this command cannot be accepted at this time.
++//      TOUCH_STATUS_TIMEOUT:                   Sensor did not generate a reset interrupt in the time allotted. Could indicate sensor is not connected or malfunctioning.
++//
++typedef struct touch_sensor_hid_ready_for_data_rsp_data
++{
++    u32          data_size;               // Size of the data the ME DMA'd into a RawDataBuffer. Valid only when Status == TOUCH_STATUS_SUCCESS
++    u8           touch_data_buffer_index;   // Index to indicate which RawDataBuffer was used. Valid only when Status == TOUCH_STATUS_SUCCESS
++    u8           reset_reason;            // If Status is TOUCH_STATUS_SENSOR_EXPECTED_RESET, ME will provide the cause. See TOUCH_RESET_REASON.
++    u8           reserved1[2];           // For future expansion
++    u32          reserved2[5];           // For future expansion
++} touch_sensor_hid_ready_for_data_rsp_data_t;
++C_ASSERT(sizeof(touch_sensor_hid_ready_for_data_rsp_data_t) == 28);
++
++
++//
++// TOUCH_SENSOR_FEEDBACK_READY_RSP code is sent in response to TOUCH_SENSOR_FEEDBACK_READY_CMD. This code will be followed
++// by TOUCH_SENSOR_FEEDBACK_READY_RSP_DATA.
++//
++// Possible Status values:
++//      TOUCH_STATUS_SUCCESS:           Command was processed successfully and any feedback or commands were sent to sensor.
++//      TOUCH_STATUS_CMD_SIZE_ERROR:    Command sent did not match expected size. Other fields will not contain valid data.
++//      TOUCH_STATUS_INVALID_PARAMS:    Input parameters are out of range.
++//      TOUCH_STATUS_COMPAT_CHECK_FAIL  Indicates ProtocolVer does not match ME supported version. (non-fatal error)
++//      TOUCH_STATUS_INTERNAL_ERROR:    Unexpected error occurred. This should not normally be seen.
++//      TOUCH_STATUS_OUT_OF_MEMORY:     Insufficient space to store Calibration Data
++//
++typedef struct touch_sensor_feedback_ready_rsp_data
++{
++    u8           feedback_index;  // Index value from 0 to TOUCH_SENSOR_MAX_DATA_BUFFERS used to indicate which Feedback Buffer to use
++    u8           reserved1[3];   // For future expansion
++    u32          reserved2[6];   // For future expansion
++} touch_sensor_feedback_ready_rsp_data_t;
++C_ASSERT(sizeof(touch_sensor_feedback_ready_rsp_data_t) == 28);
++
++
++//
++// TOUCH_SENSOR_CLEAR_MEM_WINDOW_RSP code is sent in response to TOUCH_SENSOR_CLEAR_MEM_WINDOW_CMD. This code will be followed
++// by TOUCH_SENSOR_CLEAR_MEM_WINDOW_RSP_DATA.
++//
++// Possible Status values:
++//      TOUCH_STATUS_SUCCESS:                   Command was processed successfully and memory window was set.
++//      TOUCH_STATUS_CMD_SIZE_ERROR:            Command sent did not match expected size. Other fields will not contain valid data.
++//      TOUCH_STATUS_INVALID_PARAMS:            Input parameters are out of range.
++//      TOUCH_STATUS_QUIESCE_IO_IN_PROGRESS:    Indicates that Quiesce I/O is already in progress and this command cannot be accepted at this time.
++//
++typedef struct touch_sensor_clear_mem_window_rsp_data
++{
++    u32          reserved[3];    // For future expansion
++} touch_sensor_clear_mem_window_rsp_data_t;
++C_ASSERT(sizeof(touch_sensor_clear_mem_window_rsp_data_t) == 12);
++
++
++//
++// TOUCH_SENSOR_NOTIFY_DEV_READY_RSP code is sent in response to TOUCH_SENSOR_NOTIFY_DEV_READY_CMD. This code will be followed
++// by TOUCH_SENSOR_NOTIFY_DEV_READY_RSP_DATA.
++//
++// Possible Status values:
++//      TOUCH_STATUS_SUCCESS:               Command was processed successfully and sensor has been detected by ME FW.
++//      TOUCH_STATUS_CMD_SIZE_ERROR:        Command sent did not match expected size.
++//      TOUCH_STATUS_REQUEST_OUTSTANDING:   Previous request is still outstanding, ME FW cannot handle another request for the same command.
++//      TOUCH_STATUS_TIMEOUT:               Sensor did not generate a reset interrupt in the time allotted. Could indicate sensor is not connected or malfunctioning.
++//      TOUCH_STATUS_SENSOR_FAIL_FATAL:     Sensor indicated a fatal error, further operation is not possible. Error details can be found in ErrReg.
++//      TOUCH_STATUS_SENSOR_FAIL_NONFATAL:  Sensor indicated a non-fatal error. Error should be logged by caller and init flow can continue. Error details can be found in ErrReg.
++//
++typedef struct touch_sensor_notify_dev_ready_rsp_data
++{
++    touch_err_reg_t   err_reg;         // Value of sensor Error Register, field is only valid for Status == TOUCH_STATUS_SENSOR_FAIL_FATAL or TOUCH_STATUS_SENSOR_FAIL_NONFATAL
++    u32          reserved[2];    // For future expansion
++} touch_sensor_notify_dev_ready_rsp_data_t;
++C_ASSERT(sizeof(touch_sensor_notify_dev_ready_rsp_data_t) == 12);
++
++
++//
++// TOUCH_SENSOR_SET_POLICIES_RSP code is sent in response to TOUCH_SENSOR_SET_POLICIES_CMD. This code will be followed
++// by TOUCH_SENSOR_SET_POLICIES_RSP_DATA.
++//
++// Possible Status values:
++//      TOUCH_STATUS_SUCCESS:           Command was processed successfully and new policies were set.
++//      TOUCH_STATUS_CMD_SIZE_ERROR:    Command sent did not match expected size. Other fields will not contain valid data.
++//      TOUCH_STATUS_INVALID_PARAMS:    Input parameters are out of range.
++//
++typedef struct touch_sensor_set_policies_rsp_data
++{
++    u32          reserved[3];    // For future expansion
++} touch_sensor_set_policies_rsp_data_t;
++C_ASSERT(sizeof(touch_sensor_set_policies_rsp_data_t) == 12);
++
++
++//
++// TOUCH_SENSOR_GET_POLICIES_RSP code is sent in response to TOUCH_SENSOR_GET_POLICIES_CMD. This code will be followed
++// by TOUCH_SENSOR_GET_POLICIES_RSP_DATA.
++//
++// Possible Status values:
++//      TOUCH_STATUS_SUCCESS:           Command was processed successfully and new policies were set.
++//      TOUCH_STATUS_CMD_SIZE_ERROR:    Command sent did not match expected size. Other fields will not contain valid data.
++//
++typedef struct touch_sensor_get_policies_rsp_data
++{
++    touch_policy_data_t   policy_data;         // Contains the current policy
++} touch_sensor_get_policies_rsp_data_t;
++C_ASSERT(sizeof(touch_sensor_get_policies_rsp_data_t) == 16);
++
++
++//
++// TOUCH_SENSOR_RESET_RSP code is sent in response to TOUCH_SENSOR_RESET_CMD. This code will be followed
++// by TOUCH_SENSOR_RESET_RSP_DATA.
++//
++// Possible Status values:
++//      TOUCH_STATUS_SUCCESS:                   Command was processed successfully and sensor reset was completed.
++//      TOUCH_STATUS_CMD_SIZE_ERROR:            Command sent did not match expected size. Other fields will not contain valid data.
++//      TOUCH_STATUS_INVALID_PARAMS:            Input parameters are out of range.
++//      TOUCH_STATUS_TIMEOUT:                   Sensor did not generate a reset interrupt in the time allotted. Could indicate sensor is not connected or malfunctioning.
++//      TOUCH_STATUS_RESET_FAILED:              Sensor generated an invalid or unexpected interrupt.
++//      TOUCH_STATUS_QUIESCE_IO_IN_PROGRESS:    Indicates that Quiesce I/O is already in progress and this command cannot be accepted at this time.
++//
++typedef struct touch_sensor_reset_rsp_data
++{
++    u32          reserved[3];    // For future expansion
++} touch_sensor_reset_rsp_data_t;
++C_ASSERT(sizeof(touch_sensor_reset_rsp_data_t) == 12);
++
++
++//
++// TOUCH_SENSOR_READ_ALL_REGS_RSP code is sent in response to TOUCH_SENSOR_READ_ALL_REGS_CMD. This code will be followed
++// by TOUCH_SENSOR_READ_ALL_REGS_RSP_DATA.
++//
++// Possible Status values:
++//      TOUCH_STATUS_SUCCESS:           Command was processed successfully and new policies were set.
++//      TOUCH_STATUS_CMD_SIZE_ERROR:    Command sent did not match expected size. Other fields will not contain valid data.
++//
++typedef struct touch_sensor_read_all_regs_rsp_data
++{
++    touch_reg_block_t sensor_regs; // Returns first 64 bytes of register space used for normal touch operation. Does not include test mode register.
++    u32          reserved[4];
++} touch_sensor_read_all_regs_rsp_data_t;
++C_ASSERT(sizeof(touch_sensor_read_all_regs_rsp_data_t) == 80);
++
++//
++// ME to Host Message
++//
++typedef struct touch_sensor_msg_m2h
++{
++    u32  command_code;
++    touch_status_t	status;
++    union
++    {
++        touch_sensor_get_device_info_rsp_data_t     device_info_rsp_data;
++        touch_sensor_set_mode_rsp_data_t            set_mode_rsp_data;
++        touch_sensor_set_mem_window_rsp_data_t      set_mem_window_rsp_data;
++        touch_sensor_quiesce_io_rsp_data_t          quiesce_io_rsp_data;
++        touch_sensor_hid_ready_for_data_rsp_data_t  hid_ready_for_data_rsp_data;
++        touch_sensor_feedback_ready_rsp_data_t      feedback_ready_rsp_data;
++        touch_sensor_clear_mem_window_rsp_data_t    clear_mem_window_rsp_data;
++        touch_sensor_notify_dev_ready_rsp_data_t    notify_dev_ready_rsp_data;
++        touch_sensor_set_policies_rsp_data_t        set_policies_rsp_data;
++        touch_sensor_get_policies_rsp_data_t        get_policies_rsp_data;
++        touch_sensor_reset_rsp_data_t               reset_rsp_data;
++	touch_sensor_read_all_regs_rsp_data_t       read_all_regs_rsp_data;
++    } m2h_data;
++} touch_sensor_msg_m2h_t;
++C_ASSERT(sizeof(touch_sensor_msg_m2h_t) == 88);
++
++
++#define TOUCH_MSG_SIZE_MAX_BYTES    (MAX(sizeof(touch_sensor_msg_m2h_t), sizeof(touch_sensor_msg_h2m_t)))
++
++#pragma pack()
++
++#endif // _IPTS_MEI_MSGS_H_
+diff --git a/drivers/misc/ipts/ipts-mei.c b/drivers/misc/ipts/ipts-mei.c
+new file mode 100644
+index 000000000000..39667e75dafd
+--- /dev/null
++++ b/drivers/misc/ipts/ipts-mei.c
+@@ -0,0 +1,282 @@
++/*
++ * MEI client driver for Intel Precise Touch and Stylus
++ *
++ * Copyright (c) 2016, Intel Corporation.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms and conditions of the GNU General Public License,
++ * version 2, as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
++ * more details.
++ */
++
++#include <linux/mei_cl_bus.h>
++#include <linux/module.h>
++#include <linux/mod_devicetable.h>
++#include <linux/hid.h>
++#include <linux/dma-mapping.h>
++#include <linux/kthread.h>
++#include <linux/intel_ipts_if.h>
++
++#include "ipts.h"
++#include "ipts-hid.h"
++#include "ipts-msg-handler.h"
++#include "ipts-mei-msgs.h"
++#include "ipts-binary-spec.h"
++#include "ipts-state.h"
++
++#define IPTS_DRIVER_NAME	"ipts"
++#define IPTS_MEI_UUID		UUID_LE(0x3e8d0870, 0x271a, 0x4208, \
++				0x8e, 0xb5, 0x9a, 0xcb, 0x94, 0x02, 0xae, 0x04)
++
++static struct mei_cl_device_id ipts_mei_cl_tbl[] = {
++	{ "", IPTS_MEI_UUID, MEI_CL_VERSION_ANY},
++	{}
++};
++
++static ssize_t sensor_mode_show(struct device *dev,
++				struct device_attribute *attr, char *buf)
++{
++	ipts_info_t *ipts;
++	ipts = dev_get_drvdata(dev);
++
++	return sprintf(buf, "%d\n", ipts->sensor_mode);
++}
++
++//TODO: Verify the function implementation
++static ssize_t sensor_mode_store(struct device *dev,
++				struct device_attribute *attr, const char *buf,
++				size_t count)
++{
++	int ret;
++	long val;
++	ipts_info_t *ipts;
++
++	ipts = dev_get_drvdata(dev);
++	ret = kstrtol(buf, 10, &val);
++	if (ret)
++	   return ret;
++
++	ipts_dbg(ipts, "try sensor mode = %ld\n", val);
++
++	switch (val) {
++		case TOUCH_SENSOR_MODE_HID:
++			break;
++		case TOUCH_SENSOR_MODE_RAW_DATA:
++			break;
++		default:
++			ipts_err(ipts, "sensor mode %ld is not supported\n", val);
++	}
++
++	return count;
++}
++
++static ssize_t device_info_show(struct device *dev,
++				struct device_attribute *attr, char *buf)
++{
++	ipts_info_t *ipts;
++
++	ipts = dev_get_drvdata(dev);
++	return sprintf(buf, "vendor id = 0x%04hX\n"
++				"device id = 0x%04hX\n"
++				"HW rev = 0x%08X\n"
++				"firmware rev = 0x%08X\n",
++			ipts->device_info.vendor_id, ipts->device_info.device_id,
++			ipts->device_info.hw_rev, ipts->device_info.fw_rev);
++}
++
++static DEVICE_ATTR_RW(sensor_mode);
++static DEVICE_ATTR_RO(device_info);
++
++static struct attribute *ipts_attrs[] = {
++	&dev_attr_sensor_mode.attr,
++	&dev_attr_device_info.attr,
++	NULL
++};
++
++static const struct attribute_group ipts_grp = {
++	.attrs = ipts_attrs,
++};
++
++MODULE_DEVICE_TABLE(mei, ipts_mei_cl_tbl);
++
++static void raw_data_work_func(struct work_struct *work)
++{
++	ipts_info_t *ipts = container_of(work, ipts_info_t, raw_data_work);
++
++	ipts_handle_processed_data(ipts);
++}
++
++static void gfx_status_work_func(struct work_struct *work)
++{
++	ipts_info_t *ipts = container_of(work, ipts_info_t, gfx_status_work);
++	ipts_state_t state;
++	int status = ipts->gfx_status;
++
++	ipts_dbg(ipts, "notify gfx status : %d\n", status);
++
++	state = ipts_get_state(ipts);
++
++	if (state == IPTS_STA_RAW_DATA_STARTED || state == IPTS_STA_HID_STARTED) {
++		if (status == IPTS_NOTIFY_STA_BACKLIGHT_ON &&
++					ipts->display_status == false) {
++			ipts_send_sensor_clear_mem_window_cmd(ipts);
++			ipts->display_status = true;
++		} else if (status == IPTS_NOTIFY_STA_BACKLIGHT_OFF &&
++					ipts->display_status == true) {
++			ipts_send_sensor_quiesce_io_cmd(ipts);
++			ipts->display_status = false;
++		}
++	}
++}
++
++/* event loop */
++static int ipts_mei_cl_event_thread(void *data)
++{
++	ipts_info_t *ipts = (ipts_info_t *)data;
++	struct mei_cl_device *cldev = ipts->cldev;
++	ssize_t msg_len;
++	touch_sensor_msg_m2h_t m2h_msg;
++
++	while (!kthread_should_stop()) {
++		msg_len = mei_cldev_recv(cldev, (u8*)&m2h_msg, sizeof(m2h_msg));
++		if (msg_len <= 0) {
++			ipts_err(ipts, "error in reading m2h msg\n");
++			continue;
++		}
++
++		if (ipts_handle_resp(ipts, &m2h_msg, msg_len) != 0) {
++			ipts_err(ipts, "error in handling resp msg\n");
++		}
++	}
++
++	ipts_dbg(ipts, "!! end event loop !!\n");
++
++	return 0;
++}
++
++static void init_work_func(struct work_struct *work)
++{
++	ipts_info_t *ipts = container_of(work, ipts_info_t, init_work);
++
++	ipts->sensor_mode = TOUCH_SENSOR_MODE_RAW_DATA;
++	ipts->display_status = true;
++
++	ipts_start(ipts);
++}
++
++static int ipts_mei_cl_probe(struct mei_cl_device *cldev,
++			const struct mei_cl_device_id *id)
++{
++	int ret = 0;
++	ipts_info_t *ipts = NULL;
++
++	pr_info("probing Intel Precise Touch & Stylus\n");
++
++	// setup the DMA BIT mask, the system will choose the best possible
++	if (dma_coerce_mask_and_coherent(&cldev->dev, DMA_BIT_MASK(64)) == 0) {
++		pr_info("IPTS using DMA_BIT_MASK(64)\n");
++	} else if (dma_coerce_mask_and_coherent(&cldev->dev,
++						DMA_BIT_MASK(32)) == 0) {
++		pr_info("IPTS using  DMA_BIT_MASK(32)\n");
++	} else {
++		pr_err("IPTS: No suitable DMA available\n");
++		return -EFAULT;
++	}
++
++	ret = mei_cldev_enable(cldev);
++	if (ret < 0) {
++		pr_err("cannot enable IPTS\n");
++		return ret;
++	}
++
++	ipts = devm_kzalloc(&cldev->dev, sizeof(ipts_info_t), GFP_KERNEL);
++	if (ipts == NULL) {
++		ret = -ENOMEM;
++		goto disable_mei;
++	}
++	ipts->cldev = cldev;
++	mei_cldev_set_drvdata(cldev, ipts);
++
++	ipts->event_loop = kthread_run(ipts_mei_cl_event_thread, (void*)ipts,
++							"ipts_event_thread");
++
++	if(ipts_dbgfs_register(ipts, "ipts"))
++		pr_debug("cannot register debugfs for IPTS\n");
++
++	INIT_WORK(&ipts->init_work, init_work_func);
++	INIT_WORK(&ipts->raw_data_work, raw_data_work_func);
++	INIT_WORK(&ipts->gfx_status_work, gfx_status_work_func);
++
++	ret = sysfs_create_group(&cldev->dev.kobj, &ipts_grp);
++	if (ret != 0) {
++		pr_debug("cannot create sysfs for IPTS\n");
++	}
++
++	schedule_work(&ipts->init_work);
++
++	return 0;
++
++disable_mei :
++	mei_cldev_disable(cldev);
++	
++	return ret;
++}
++
++static int ipts_mei_cl_remove(struct mei_cl_device *cldev)
++{
++	ipts_info_t *ipts = mei_cldev_get_drvdata(cldev);
++
++	ipts_stop(ipts);
++
++	sysfs_remove_group(&cldev->dev.kobj, &ipts_grp);
++	ipts_hid_release(ipts);
++	ipts_dbgfs_deregister(ipts);
++	mei_cldev_disable(cldev);
++
++	kthread_stop(ipts->event_loop);
++
++	pr_info("IPTS removed\n");
++
++	return 0;
++}
++
++static struct mei_cl_driver ipts_mei_cl_driver = {
++	.id_table = ipts_mei_cl_tbl,
++	.name = IPTS_DRIVER_NAME,
++	.probe = ipts_mei_cl_probe,
++	.remove = ipts_mei_cl_remove,
++};
++
++static int ipts_mei_cl_init(void)
++{
++	int ret;
++
++	pr_info("IPTS %s() is called\n", __func__);
++
++	ret = mei_cldev_driver_register(&ipts_mei_cl_driver);
++	if (ret) {
++		pr_err("unable to register IPTS mei client driver\n");
++		return ret;
++	}
++
++	return 0;
++}
++
++static void __exit ipts_mei_cl_exit(void)
++{
++	pr_info("IPTS %s() is called\n", __func__);
++
++	mei_cldev_driver_unregister(&ipts_mei_cl_driver);
++}
++
++module_init(ipts_mei_cl_init);
++module_exit(ipts_mei_cl_exit);
++
++MODULE_DESCRIPTION
++	("Intel(R) Management Engine Interface Client Driver for "\
++	"Intel Precision Touch and Sylus");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/misc/ipts/ipts-msg-handler.c b/drivers/misc/ipts/ipts-msg-handler.c
+new file mode 100644
+index 000000000000..1396ecc7197f
+--- /dev/null
++++ b/drivers/misc/ipts/ipts-msg-handler.c
+@@ -0,0 +1,431 @@
++#include <linux/mei_cl_bus.h>
++
++#include "ipts.h"
++#include "ipts-hid.h"
++#include "ipts-resource.h"
++#include "ipts-mei-msgs.h"
++
++int ipts_handle_cmd(ipts_info_t *ipts, u32 cmd, void *data, int data_size)
++{
++	int ret = 0;
++	touch_sensor_msg_h2m_t h2m_msg;
++	int len = 0;
++
++	memset(&h2m_msg, 0, sizeof(h2m_msg));
++
++	h2m_msg.command_code = cmd;
++	len = sizeof(h2m_msg.command_code) + data_size;
++	if (data != NULL && data_size != 0)
++		memcpy(&h2m_msg.h2m_data, data, data_size); /* copy payload */
++
++	ret = mei_cldev_send(ipts->cldev, (u8*)&h2m_msg, len);
++	if (ret < 0) {
++		ipts_err(ipts, "mei_cldev_send() error 0x%X:%d\n",
++							cmd, ret);
++		return ret;
++	}
++
++	return 0;
++}
++
++int ipts_send_feedback(ipts_info_t *ipts, int buffer_idx, u32 transaction_id)
++{
++	int ret;
++	int cmd_len;
++	touch_sensor_feedback_ready_cmd_data_t fb_ready_cmd;
++
++	cmd_len = sizeof(touch_sensor_feedback_ready_cmd_data_t);
++	memset(&fb_ready_cmd, 0, cmd_len);
++
++	fb_ready_cmd.feedback_index = buffer_idx;
++	fb_ready_cmd.transaction_id = transaction_id;
++
++	ret = ipts_handle_cmd(ipts, TOUCH_SENSOR_FEEDBACK_READY_CMD,
++				&fb_ready_cmd, cmd_len);
++
++	return ret;
++}
++
++int ipts_send_sensor_quiesce_io_cmd(ipts_info_t *ipts)
++{
++	int ret;
++	int cmd_len;
++	touch_sensor_quiesce_io_cmd_data_t quiesce_io_cmd;
++
++	cmd_len = sizeof(touch_sensor_quiesce_io_cmd_data_t);
++	memset(&quiesce_io_cmd, 0, cmd_len);
++
++	ret = ipts_handle_cmd(ipts, TOUCH_SENSOR_QUIESCE_IO_CMD,
++				&quiesce_io_cmd, cmd_len);
++
++	return ret;
++}
++
++int ipts_send_sensor_hid_ready_for_data_cmd(ipts_info_t *ipts)
++{
++	return ipts_handle_cmd(ipts, TOUCH_SENSOR_HID_READY_FOR_DATA_CMD, NULL, 0);
++}
++
++int ipts_send_sensor_clear_mem_window_cmd(ipts_info_t *ipts)
++{
++	return ipts_handle_cmd(ipts, TOUCH_SENSOR_CLEAR_MEM_WINDOW_CMD, NULL, 0);
++}
++
++static int check_validity(touch_sensor_msg_m2h_t *m2h_msg, u32 msg_len)
++{
++	int ret = 0;
++	int valid_msg_len = sizeof(m2h_msg->command_code);
++	u32 cmd_code = m2h_msg->command_code;
++
++	switch (cmd_code) {
++		case TOUCH_SENSOR_SET_MODE_RSP:
++			valid_msg_len +=
++				sizeof(touch_sensor_set_mode_rsp_data_t);
++			break;
++		case TOUCH_SENSOR_SET_MEM_WINDOW_RSP:
++			valid_msg_len +=
++				sizeof(touch_sensor_set_mem_window_rsp_data_t);
++			break;
++		case TOUCH_SENSOR_QUIESCE_IO_RSP:
++			valid_msg_len +=
++				sizeof(touch_sensor_quiesce_io_rsp_data_t);
++			break;
++		case TOUCH_SENSOR_HID_READY_FOR_DATA_RSP:
++			valid_msg_len +=
++				sizeof(touch_sensor_hid_ready_for_data_rsp_data_t);
++			break;
++		case TOUCH_SENSOR_FEEDBACK_READY_RSP:
++			valid_msg_len +=
++				sizeof(touch_sensor_feedback_ready_rsp_data_t);
++			break;
++		case TOUCH_SENSOR_CLEAR_MEM_WINDOW_RSP:
++			valid_msg_len +=
++				sizeof(touch_sensor_clear_mem_window_rsp_data_t);
++			break;
++		case TOUCH_SENSOR_NOTIFY_DEV_READY_RSP:
++			valid_msg_len +=
++				sizeof(touch_sensor_notify_dev_ready_rsp_data_t);
++			break;
++		case TOUCH_SENSOR_SET_POLICIES_RSP:
++			valid_msg_len +=
++				sizeof(touch_sensor_set_policies_rsp_data_t);
++			break;
++		case TOUCH_SENSOR_GET_POLICIES_RSP:
++			valid_msg_len +=
++				sizeof(touch_sensor_get_policies_rsp_data_t);
++			break;
++		case TOUCH_SENSOR_RESET_RSP:
++			valid_msg_len +=
++				sizeof(touch_sensor_reset_rsp_data_t);
++			break;
++	}
++
++	if (valid_msg_len != msg_len) {
++		return -EINVAL;
++	}
++
++	return ret;
++}
++
++int ipts_start(ipts_info_t *ipts)
++{
++	int ret = 0;
++	/* TODO : check if we need to do SET_POLICIES_CMD
++	we need to do this when protocol version doesn't match with reported one
++	how we keep vendor specific data is the first thing to solve */
++
++	ipts_set_state(ipts, IPTS_STA_INIT);
++	ipts->num_of_parallel_data_buffers = TOUCH_SENSOR_MAX_DATA_BUFFERS;
++
++	ipts->sensor_mode = TOUCH_SENSOR_MODE_RAW_DATA; /* start with RAW_DATA */
++
++	ret = ipts_handle_cmd(ipts, TOUCH_SENSOR_NOTIFY_DEV_READY_CMD, NULL, 0);
++
++	return ret;
++}
++
++void ipts_stop(ipts_info_t *ipts)
++{
++	ipts_state_t old_state;
++
++	old_state = ipts_get_state(ipts);
++	ipts_set_state(ipts, IPTS_STA_STOPPING);
++
++	if (old_state < IPTS_STA_RESOURCE_READY)
++		return;
++
++	if (old_state == IPTS_STA_RAW_DATA_STARTED ||
++					old_state == IPTS_STA_HID_STARTED) {
++        	ipts_free_default_resource(ipts);
++		ipts_free_raw_data_resource(ipts);
++
++		return;
++	}
++}
++
++int ipts_restart(ipts_info_t *ipts)
++{
++	int ret = 0;
++
++	ipts_dbg(ipts, "ipts restart\n");
++
++	ipts_stop(ipts);
++
++	ipts->retry++;
++	if (ipts->retry == IPTS_MAX_RETRY && 
++			ipts->sensor_mode == TOUCH_SENSOR_MODE_RAW_DATA) {
++		/* try with HID mode */
++		ipts->sensor_mode = TOUCH_SENSOR_MODE_HID;
++	} else if (ipts->retry > IPTS_MAX_RETRY) {
++		return -EPERM;
++	}
++
++	ipts_send_sensor_quiesce_io_cmd(ipts);
++	ipts->restart = true;
++
++	return ret;
++}
++
++int ipts_switch_sensor_mode(ipts_info_t *ipts, int new_sensor_mode)
++{
++	int ret = 0;
++
++        ipts->new_sensor_mode = new_sensor_mode;
++	ipts->switch_sensor_mode = true;
++        ret = ipts_send_sensor_quiesce_io_cmd(ipts);
++
++	return ret;
++}
++
++#define rsp_failed(ipts, cmd, status) ipts_err(ipts, \
++				"0x%08x failed status = %d\n", cmd, status);
++
++int ipts_handle_resp(ipts_info_t *ipts, touch_sensor_msg_m2h_t *m2h_msg,
++								u32 msg_len)
++{
++	int ret = 0;
++	int rsp_status = 0;
++	int cmd_status = 0;
++	int cmd_len = 0;
++	u32 cmd;
++
++	if (!check_validity(m2h_msg, msg_len)) {
++		ipts_err(ipts, "wrong rsp\n");
++		return -EINVAL;
++	}
++
++	rsp_status = m2h_msg->status;
++	cmd = m2h_msg->command_code;
++
++	switch (cmd) {
++		case TOUCH_SENSOR_NOTIFY_DEV_READY_RSP:
++			if (rsp_status != 0 &&
++			  rsp_status != TOUCH_STATUS_SENSOR_FAIL_NONFATAL) {
++				rsp_failed(ipts, cmd, rsp_status);
++				break;
++			}
++
++			cmd_status = ipts_handle_cmd(ipts,
++					TOUCH_SENSOR_GET_DEVICE_INFO_CMD,
++					NULL, 0);
++			break;
++		case TOUCH_SENSOR_GET_DEVICE_INFO_RSP:
++			if (rsp_status != 0 &&
++			  rsp_status != TOUCH_STATUS_COMPAT_CHECK_FAIL) {
++				rsp_failed(ipts, cmd, rsp_status);
++				break;
++			}
++
++			memcpy(&ipts->device_info,
++				&m2h_msg->m2h_data.device_info_rsp_data,
++				sizeof(touch_sensor_get_device_info_rsp_data_t));
++
++			/*
++			    TODO : support raw_request during HID init.
++			    Although HID init happens here, technically most of
++			    reports (for both direction) can be issued only
++			    after SET_MEM_WINDOWS_CMD since they may require
++			    ME or touch IC. If ipts vendor requires raw_request
++			    during HID init, we need to consider to move HID init.
++			*/
++			if (ipts->hid_desc_ready == false) {
++				ret = ipts_hid_init(ipts);
++				if (ret)
++					break;
++			}
++
++			cmd_status = ipts_send_sensor_clear_mem_window_cmd(ipts);
++
++			break;
++		case TOUCH_SENSOR_CLEAR_MEM_WINDOW_RSP:
++		{
++			touch_sensor_set_mode_cmd_data_t sensor_mode_cmd;
++
++			if (rsp_status != 0 &&
++					rsp_status != TOUCH_STATUS_TIMEOUT) {
++				rsp_failed(ipts, cmd, rsp_status);
++				break;
++			}
++
++			/* allocate default resource : common & hid only */
++			if (!ipts_is_default_resource_ready(ipts)) {
++				ret = ipts_allocate_default_resource(ipts);
++				if (ret)
++					break;
++			}
++
++			if (ipts->sensor_mode == TOUCH_SENSOR_MODE_RAW_DATA &&
++					!ipts_is_raw_data_resource_ready(ipts)) {
++				ret = ipts_allocate_raw_data_resource(ipts);
++				if (ret) {
++					ipts_free_default_resource(ipts);
++					break;
++				}
++			}
++
++			ipts_set_state(ipts, IPTS_STA_RESOURCE_READY);
++
++			cmd_len = sizeof(touch_sensor_set_mode_cmd_data_t);
++			memset(&sensor_mode_cmd, 0, cmd_len);
++			sensor_mode_cmd.sensor_mode = ipts->sensor_mode;
++			cmd_status = ipts_handle_cmd(ipts,
++				TOUCH_SENSOR_SET_MODE_CMD,
++				&sensor_mode_cmd, cmd_len);
++			break;
++		}
++		case TOUCH_SENSOR_SET_MODE_RSP:
++		{
++			touch_sensor_set_mem_window_cmd_data_t smw_cmd;
++
++			if (rsp_status != 0) {
++				rsp_failed(ipts, cmd, rsp_status);
++				break;
++			}
++
++			cmd_len = sizeof(touch_sensor_set_mem_window_cmd_data_t);
++			memset(&smw_cmd, 0, cmd_len);
++			ipts_get_set_mem_window_cmd_data(ipts, &smw_cmd);
++			cmd_status = ipts_handle_cmd(ipts,
++				TOUCH_SENSOR_SET_MEM_WINDOW_CMD,
++				&smw_cmd, cmd_len);
++			break;
++		}
++		case TOUCH_SENSOR_SET_MEM_WINDOW_RSP:
++			if (rsp_status != 0) {
++				rsp_failed(ipts, cmd, rsp_status);
++				break;
++			}
++
++			cmd_status = ipts_send_sensor_hid_ready_for_data_cmd(ipts);
++			if (cmd_status)
++				break;
++
++			if (ipts->sensor_mode == TOUCH_SENSOR_MODE_HID) {
++				ipts_set_state(ipts, IPTS_STA_HID_STARTED);
++			} else if (ipts->sensor_mode == TOUCH_SENSOR_MODE_RAW_DATA) {
++				ipts_set_state(ipts, IPTS_STA_RAW_DATA_STARTED);
++			}
++
++			ipts_err(ipts, "touch enabled %d\n", ipts_get_state(ipts));
++
++			break;
++		case TOUCH_SENSOR_HID_READY_FOR_DATA_RSP:
++		{
++			touch_sensor_hid_ready_for_data_rsp_data_t *hid_data;
++			ipts_state_t state;
++
++			if (rsp_status != 0 &&
++				  rsp_status != TOUCH_STATUS_SENSOR_DISABLED) {
++				rsp_failed(ipts, cmd, rsp_status);
++				break;
++			}
++
++			state = ipts_get_state(ipts);
++			if (ipts->sensor_mode == TOUCH_SENSOR_MODE_HID &&
++						state == IPTS_STA_HID_STARTED) {
++
++				hid_data = &m2h_msg->m2h_data.hid_ready_for_data_rsp_data;
++
++				/* HID mode only uses buffer 0 */
++				if (hid_data->touch_data_buffer_index != 0)
++					break;
++
++				/* handle hid data */
++				ipts_handle_hid_data(ipts, hid_data);
++			}
++
++			break;
++		}
++		case TOUCH_SENSOR_FEEDBACK_READY_RSP:
++			if (rsp_status != 0 &&
++			  rsp_status != TOUCH_STATUS_COMPAT_CHECK_FAIL) {
++				rsp_failed(ipts, cmd, rsp_status);
++				break;
++			}
++
++			if (m2h_msg->m2h_data.feedback_ready_rsp_data.
++					feedback_index == TOUCH_HID_2_ME_BUFFER_ID)
++				break;
++
++			if (ipts->sensor_mode == TOUCH_SENSOR_MODE_HID) {
++				cmd_status = ipts_handle_cmd(ipts,
++					TOUCH_SENSOR_HID_READY_FOR_DATA_CMD,
++					NULL, 0);
++			}
++
++			/* reset retry since we are getting touch data */
++			ipts->retry = 0;
++
++			break;
++		case TOUCH_SENSOR_QUIESCE_IO_RSP:
++		{
++			ipts_state_t state;
++
++			if (rsp_status != 0) {
++				rsp_failed(ipts, cmd, rsp_status);
++				break;
++			}
++
++			state = ipts_get_state(ipts);
++			if (state == IPTS_STA_STOPPING && ipts->restart) {
++				ipts_dbg(ipts, "restart\n");
++			        ipts_start(ipts);
++				ipts->restart = 0;
++				break;
++			}
++
++			/* support sysfs debug node for switch sensor mode */
++			if (ipts->switch_sensor_mode) {
++				ipts_set_state(ipts, IPTS_STA_INIT);
++				ipts->sensor_mode = ipts->new_sensor_mode;
++				ipts->switch_sensor_mode = false;
++
++				ipts_send_sensor_clear_mem_window_cmd(ipts);
++			}
++
++			break;
++		}
++	}
++
++	/* handle error in rsp_status */
++	if (rsp_status != 0) {
++		switch (rsp_status) {
++			case TOUCH_STATUS_SENSOR_EXPECTED_RESET:
++			case TOUCH_STATUS_SENSOR_UNEXPECTED_RESET:
++				ipts_dbg(ipts, "sensor reset %d\n", rsp_status);
++				ipts_restart(ipts);
++				break;
++			default:
++				ipts_dbg(ipts, "cmd : 0x%08x, status %d\n",
++								cmd,
++								rsp_status);
++				break;
++		}
++	}
++
++	if (cmd_status) {
++		ipts_restart(ipts);
++	}
++
++	return ret;
++}
+diff --git a/drivers/misc/ipts/ipts-msg-handler.h b/drivers/misc/ipts/ipts-msg-handler.h
+new file mode 100644
+index 000000000000..b8e27d30c63e
+--- /dev/null
++++ b/drivers/misc/ipts/ipts-msg-handler.h
+@@ -0,0 +1,32 @@
++/*
++ *
++ * Intel Precise Touch & Stylus ME message handler
++ * Copyright (c) 2016, Intel Corporation.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms and conditions of the GNU General Public License,
++ * version 2, as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
++ * more details.
++ *
++ */
++
++#ifndef _IPTS_MSG_HANDLER_H
++#define _IPTS_MSG_HANDLER_H
++
++int ipts_handle_cmd(ipts_info_t *ipts, u32 cmd, void *data, int data_size);
++int ipts_start(ipts_info_t *ipts);
++void ipts_stop(ipts_info_t *ipts);
++int ipts_switch_sensor_mode(ipts_info_t *ipts, int new_sensor_mode);
++int ipts_handle_resp(ipts_info_t *ipts, touch_sensor_msg_m2h_t *m2h_msg,
++                        					u32 msg_len);
++int ipts_handle_processed_data(ipts_info_t *ipts);
++int ipts_send_feedback(ipts_info_t *ipts, int buffer_idx, u32 transaction_id);
++int ipts_send_sensor_quiesce_io_cmd(ipts_info_t *ipts);
++int ipts_send_sensor_hid_ready_for_data_cmd(ipts_info_t *ipts);
++int ipts_send_sensor_clear_mem_window_cmd(ipts_info_t *ipts);
++
++#endif /* _IPTS_MSG_HANDLER_H */
+diff --git a/drivers/misc/ipts/ipts-resource.c b/drivers/misc/ipts/ipts-resource.c
+new file mode 100644
+index 000000000000..47607ef7c461
+--- /dev/null
++++ b/drivers/misc/ipts/ipts-resource.c
+@@ -0,0 +1,277 @@
++#include <linux/dma-mapping.h>
++
++#include "ipts.h"
++#include "ipts-mei-msgs.h"
++#include "ipts-kernel.h"
++
++static void free_common_resource(ipts_info_t *ipts)
++{
++	char *addr;
++	ipts_buffer_info_t *feedback_buffer;
++	dma_addr_t dma_addr;
++	u32 buffer_size;
++	int i, num_of_parallels;
++
++	if (ipts->resource.me2hid_buffer) {
++		devm_kfree(&ipts->cldev->dev, ipts->resource.me2hid_buffer);
++		ipts->resource.me2hid_buffer = 0;
++	}
++
++	addr = ipts->resource.hid2me_buffer.addr;
++	dma_addr = ipts->resource.hid2me_buffer.dma_addr;
++	buffer_size = ipts->resource.hid2me_buffer_size;
++
++	if (ipts->resource.hid2me_buffer.addr) {
++		dmam_free_coherent(&ipts->cldev->dev, buffer_size, addr, dma_addr);
++		ipts->resource.hid2me_buffer.addr = 0;
++		ipts->resource.hid2me_buffer.dma_addr = 0;
++		ipts->resource.hid2me_buffer_size = 0;
++	}
++
++	feedback_buffer = ipts->resource.feedback_buffer;
++	num_of_parallels = ipts_get_num_of_parallel_buffers(ipts);
++	for (i = 0; i < num_of_parallels; i++) {
++		if (feedback_buffer[i].addr) {
++			dmam_free_coherent(&ipts->cldev->dev,
++				ipts->device_info.feedback_size,
++				feedback_buffer[i].addr,
++				feedback_buffer[i].dma_addr);
++			feedback_buffer[i].addr = 0;
++			feedback_buffer[i].dma_addr = 0;
++		}
++	}
++}
++
++static int allocate_common_resource(ipts_info_t *ipts)
++{
++	char *addr, *me2hid_addr;
++	ipts_buffer_info_t *feedback_buffer;
++	dma_addr_t dma_addr;
++	int i, ret = 0, num_of_parallels;
++	u32 buffer_size;
++
++	buffer_size = ipts->device_info.feedback_size;
++
++	addr = dmam_alloc_coherent(&ipts->cldev->dev,
++			buffer_size,
++			&dma_addr,
++			GFP_ATOMIC|__GFP_ZERO);
++	if (addr == NULL)
++		return -ENOMEM;
++
++	me2hid_addr = devm_kzalloc(&ipts->cldev->dev, buffer_size, GFP_KERNEL);
++	if (me2hid_addr == NULL) {
++		ret = -ENOMEM;
++		goto release_resource;
++	}
++
++	ipts->resource.hid2me_buffer.addr = addr;
++	ipts->resource.hid2me_buffer.dma_addr = dma_addr;
++	ipts->resource.hid2me_buffer_size = buffer_size;
++	ipts->resource.me2hid_buffer = me2hid_addr;
++
++	feedback_buffer = ipts->resource.feedback_buffer;
++	num_of_parallels = ipts_get_num_of_parallel_buffers(ipts);
++	for (i = 0; i < num_of_parallels; i++) {
++		feedback_buffer[i].addr = dmam_alloc_coherent(&ipts->cldev->dev,
++				ipts->device_info.feedback_size,
++				&feedback_buffer[i].dma_addr,
++				GFP_ATOMIC|__GFP_ZERO);
++
++		if (feedback_buffer[i].addr == NULL) {
++			ret = -ENOMEM;
++			goto release_resource;
++		}
++	}
++
++	return 0;
++
++release_resource:
++	free_common_resource(ipts);
++
++	return ret;
++}
++
++void ipts_free_raw_data_resource(ipts_info_t *ipts)
++{
++	if (ipts_is_raw_data_resource_ready(ipts)) {
++		ipts->resource.raw_data_resource_ready = false;
++
++		ipts_release_kernels(ipts);
++	}
++}
++
++static int allocate_hid_resource(ipts_info_t *ipts)
++{
++	ipts_buffer_info_t *buffer_hid;
++
++	/* hid mode uses only one touch data buffer */
++	buffer_hid = &ipts->resource.touch_data_buffer_hid;
++	buffer_hid->addr = dmam_alloc_coherent(&ipts->cldev->dev,
++				ipts->device_info.frame_size,
++				&buffer_hid->dma_addr,
++				GFP_ATOMIC|__GFP_ZERO);
++	if (buffer_hid->addr == NULL) {
++		return -ENOMEM;
++	}
++
++	return 0;
++}
++
++static void free_hid_resource(ipts_info_t *ipts)
++{
++	ipts_buffer_info_t *buffer_hid;
++
++	buffer_hid = &ipts->resource.touch_data_buffer_hid;
++	if (buffer_hid->addr) {
++		dmam_free_coherent(&ipts->cldev->dev,
++				ipts->device_info.frame_size,
++				buffer_hid->addr,
++				buffer_hid->dma_addr);
++		buffer_hid->addr = 0;
++		buffer_hid->dma_addr = 0;
++	}
++}
++
++int ipts_allocate_default_resource(ipts_info_t *ipts)
++{
++	int ret;
++
++	ret = allocate_common_resource(ipts);
++	if (ret) {
++		ipts_dbg(ipts, "cannot allocate common resource\n");
++		return ret;
++	}
++
++	ret = allocate_hid_resource(ipts);
++	if (ret) {
++		ipts_dbg(ipts, "cannot allocate hid resource\n");
++		free_common_resource(ipts);
++		return ret;
++	}
++
++	ipts->resource.default_resource_ready = true;
++
++	return 0;
++}
++
++void ipts_free_default_resource(ipts_info_t *ipts)
++{
++	if (ipts_is_default_resource_ready(ipts)) {
++		ipts->resource.default_resource_ready = false;
++
++		free_hid_resource(ipts);
++		free_common_resource(ipts);
++	}
++}
++
++int ipts_allocate_raw_data_resource(ipts_info_t *ipts)
++{
++	int ret = 0;
++
++	ret = ipts_init_kernels(ipts);
++	if (ret) {
++		return ret;
++	}
++
++	ipts->resource.raw_data_resource_ready = true;
++
++	return 0;
++}
++
++static void get_hid_only_smw_cmd_data(ipts_info_t *ipts,
++				touch_sensor_set_mem_window_cmd_data_t *data,
++				ipts_resource_t *resrc)
++{
++	ipts_buffer_info_t *touch_buf;
++	ipts_buffer_info_t *feedback_buf;
++
++	touch_buf = &resrc->touch_data_buffer_hid;
++	feedback_buf = &resrc->feedback_buffer[0];
++
++	data->touch_data_buffer_addr_lower[0] =
++				lower_32_bits(touch_buf->dma_addr);
++	data->touch_data_buffer_addr_upper[0] =
++				upper_32_bits(touch_buf->dma_addr);
++	data->feedback_buffer_addr_lower[0] =
++				lower_32_bits(feedback_buf->dma_addr);
++	data->feedback_buffer_addr_upper[0] =
++				upper_32_bits(feedback_buf->dma_addr);
++}
++
++static void get_raw_data_only_smw_cmd_data(ipts_info_t *ipts,
++				touch_sensor_set_mem_window_cmd_data_t *data,
++				ipts_resource_t *resrc)
++{
++	u64 wq_tail_phy_addr;
++	u64 cookie_phy_addr;
++	ipts_buffer_info_t *touch_buf;
++	ipts_buffer_info_t *feedback_buf;
++	int i, num_of_parallels;
++
++	touch_buf = resrc->touch_data_buffer_raw;
++	feedback_buf = resrc->feedback_buffer;
++
++	num_of_parallels = ipts_get_num_of_parallel_buffers(ipts);
++	for (i = 0; i < num_of_parallels; i++) {
++		data->touch_data_buffer_addr_lower[i] =
++					lower_32_bits(touch_buf[i].dma_addr);
++		data->touch_data_buffer_addr_upper[i] =
++					upper_32_bits(touch_buf[i].dma_addr);
++		data->feedback_buffer_addr_lower[i] =
++					lower_32_bits(feedback_buf[i].dma_addr);
++		data->feedback_buffer_addr_upper[i] =
++					upper_32_bits(feedback_buf[i].dma_addr);
++	}
++
++	wq_tail_phy_addr = resrc->wq_info.wq_tail_phy_addr;
++	data->tail_offset_addr_lower = lower_32_bits(wq_tail_phy_addr);
++	data->tail_offset_addr_upper = upper_32_bits(wq_tail_phy_addr);
++
++	cookie_phy_addr = resrc->wq_info.db_phy_addr +
++						resrc->wq_info.db_cookie_offset;
++	data->doorbell_cookie_addr_lower = lower_32_bits(cookie_phy_addr);
++	data->doorbell_cookie_addr_upper = upper_32_bits(cookie_phy_addr);
++	data->work_queue_size = resrc->wq_info.wq_size;
++
++	data->work_queue_item_size = resrc->wq_item_size;
++}
++
++void ipts_get_set_mem_window_cmd_data(ipts_info_t *ipts,
++				touch_sensor_set_mem_window_cmd_data_t *data)
++{
++	ipts_resource_t *resrc = &ipts->resource;
++
++	if (ipts->sensor_mode == TOUCH_SENSOR_MODE_RAW_DATA)
++		get_raw_data_only_smw_cmd_data(ipts, data, resrc);
++	else if (ipts->sensor_mode == TOUCH_SENSOR_MODE_HID)
++		get_hid_only_smw_cmd_data(ipts, data, resrc);
++
++	/* hid2me is common for "raw data" and "hid" */
++	data->hid2me_buffer_addr_lower =
++				lower_32_bits(resrc->hid2me_buffer.dma_addr);
++	data->hid2me_buffer_addr_upper =
++				upper_32_bits(resrc->hid2me_buffer.dma_addr);
++	data->hid2me_buffer_size = resrc->hid2me_buffer_size;
++}
++
++void ipts_set_input_buffer(ipts_info_t *ipts, int parallel_idx,
++						u8* cpu_addr, u64 dma_addr)
++{
++	ipts_buffer_info_t *touch_buf;
++
++	touch_buf = ipts->resource.touch_data_buffer_raw;
++	touch_buf[parallel_idx].dma_addr = dma_addr;
++	touch_buf[parallel_idx].addr = cpu_addr;
++}
++
++void ipts_set_output_buffer(ipts_info_t *ipts, int parallel_idx, int output_idx,
++						u8* cpu_addr, u64 dma_addr)
++{
++	ipts_buffer_info_t *output_buf;
++
++	output_buf = &ipts->resource.raw_data_mode_output_buffer[parallel_idx][output_idx];
++
++	output_buf->dma_addr = dma_addr;
++	output_buf->addr = cpu_addr;
++}
+diff --git a/drivers/misc/ipts/ipts-resource.h b/drivers/misc/ipts/ipts-resource.h
+new file mode 100644
+index 000000000000..7d66ac72b475
+--- /dev/null
++++ b/drivers/misc/ipts/ipts-resource.h
+@@ -0,0 +1,30 @@
++/*
++ * Intel Precise Touch & Stylus state codes
++ *
++ * Copyright (c) 2016, Intel Corporation.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms and conditions of the GNU General Public License,
++ * version 2, as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
++ * more details.
++ */
++
++#ifndef _IPTS_RESOURCE_H_
++#define _IPTS_RESOURCE_H_
++
++int ipts_allocate_default_resource(ipts_info_t *ipts);
++void ipts_free_default_resource(ipts_info_t *ipts);
++int ipts_allocate_raw_data_resource(ipts_info_t *ipts);
++void ipts_free_raw_data_resource(ipts_info_t *ipts);
++void ipts_get_set_mem_window_cmd_data(ipts_info_t *ipts,
++				touch_sensor_set_mem_window_cmd_data_t *data);
++void ipts_set_input_buffer(ipts_info_t *ipts, int parallel_idx,
++						u8* cpu_addr, u64 dma_addr);
++void ipts_set_output_buffer(ipts_info_t *ipts, int parallel_idx, int output_idx,
++						u8* cpu_addr, u64 dma_addr);
++
++#endif // _IPTS_RESOURCE_H_
+diff --git a/drivers/misc/ipts/ipts-sensor-regs.h b/drivers/misc/ipts/ipts-sensor-regs.h
+new file mode 100644
+index 000000000000..96812b0eb980
+--- /dev/null
++++ b/drivers/misc/ipts/ipts-sensor-regs.h
+@@ -0,0 +1,700 @@
++/*
++ * Touch Sensor Register definition
++ *
++ * Copyright (c) 2013-2016, Intel Corporation.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms and conditions of the GNU General Public License,
++ * version 2, as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
++ * more details.
++ */
++
++
++#ifndef _TOUCH_SENSOR_REGS_H
++#define _TOUCH_SENSOR_REGS_H
++
++#pragma pack(1)
++
++// define C_ASSERT macro to check structure size and fail compile for unexpected mismatch
++#ifndef C_ASSERT
++#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1]
++#endif
++
++//
++// Compatibility versions for this header file
++//
++#define TOUCH_EDS_REV_MINOR     0
++#define TOUCH_EDS_REV_MAJOR     1
++#define TOUCH_EDS_INTF_REV      1
++#define TOUCH_PROTOCOL_VER      0
++
++
++//
++// Offset 00h: TOUCH_STS: Status Register
++// This register is read by the SPI Controller immediately following an interrupt.
++//
++#define TOUCH_STS_REG_OFFSET                0x00
++
++typedef enum touch_sts_reg_int_type
++{
++    TOUCH_STS_REG_INT_TYPE_DATA_AVAIL = 0,  // Touch Data Available
++    TOUCH_STS_REG_INT_TYPE_RESET_OCCURRED,  // Reset Occurred
++    TOUCH_STS_REG_INT_TYPE_ERROR_OCCURRED,  // Error Occurred
++    TOUCH_STS_REG_INT_TYPE_VENDOR_DATA,     // Vendor specific data, treated same as raw frame
++    TOUCH_STS_REG_INT_TYPE_GET_FEATURES,    // Get Features response data available
++    TOUCH_STS_REG_INT_TYPE_MAX
++} touch_sts_reg_int_type_t;
++C_ASSERT(sizeof(touch_sts_reg_int_type_t) == 4);
++
++typedef enum touch_sts_reg_pwr_state
++{
++    TOUCH_STS_REG_PWR_STATE_SLEEP = 0,  // Sleep
++    TOUCH_STS_REG_PWR_STATE_DOZE,       // Doze
++    TOUCH_STS_REG_PWR_STATE_ARMED,      // Armed
++    TOUCH_STS_REG_PWR_STATE_SENSING,    // Sensing
++    TOUCH_STS_REG_PWR_STATE_MAX
++} touch_sts_reg_pwr_state_t;
++C_ASSERT(sizeof(touch_sts_reg_pwr_state_t) == 4);
++
++typedef enum touch_sts_reg_init_state
++{
++    TOUCH_STS_REG_INIT_STATE_READY_FOR_OP = 0,  // Ready for normal operation
++    TOUCH_STS_REG_INIT_STATE_FW_NEEDED,         // Touch IC needs its Firmware loaded
++    TOUCH_STS_REG_INIT_STATE_DATA_NEEDED,       // Touch IC needs its Data loaded
++    TOUCH_STS_REG_INIT_STATE_INIT_ERROR,        // Error info in TOUCH_ERR_REG
++    TOUCH_STS_REG_INIT_STATE_MAX
++} touch_sts_reg_init_state_t;
++C_ASSERT(sizeof(touch_sts_reg_init_state_t) == 4);
++
++#define TOUCH_SYNC_BYTE_VALUE   0x5A
++
++typedef union touch_sts_reg
++{
++    u32  reg_value;
++
++    struct
++    {
++        // When set, this indicates the hardware has data that needs to be read.
++        u32  int_status           :1;
++        // see TOUCH_STS_REG_INT_TYPE
++        u32  int_type             :4;
++        // see TOUCH_STS_REG_PWR_STATE
++        u32  pwr_state            :2;
++        // see TOUCH_STS_REG_INIT_STATE
++        u32  init_state           :2;
++        // Busy bit indicates that sensor cannot accept writes at this time
++        u32  busy                :1;
++        // Reserved
++        u32  reserved            :14;
++        // Synchronization bit, should always be TOUCH_SYNC_BYTE_VALUE
++        u32  sync_byte            :8;
++    } fields;
++} touch_sts_reg_t;
++C_ASSERT(sizeof(touch_sts_reg_t) == 4);
++
++
++//
++// Offset 04h: TOUCH_FRAME_CHAR: Frame Characteristics Register
++// This registers describes the characteristics of each data frame read by the SPI Controller in
++// response to a touch interrupt.
++//
++#define TOUCH_FRAME_CHAR_REG_OFFSET         0x04
++
++typedef union touch_frame_char_reg
++{
++    u32  reg_value;
++
++    struct
++    {
++        // Micro-Frame Size (MFS):  Indicates the size of a touch micro-frame in byte increments.
++        // When a micro-frame is to be read for processing (in data mode), this is the total number of
++        // bytes that must be read per interrupt, split into multiple read commands no longer than RPS.
++        // Maximum micro-frame size is 256KB.
++        u32  microframe_size      :18;
++        // Micro-Frames per Frame (MFPF): Indicates the number of micro-frames per frame. If a
++        // sensor's frame does not contain micro-frames this value will be 1. Valid values are 1-31.
++        u32  microframes_per_frame :5;
++        // Micro-Frame Index (MFI): Indicates the index of the micro-frame within a frame. This allows
++        // the SPI Controller to maintain synchronization with the sensor and determine when the final
++        // micro-frame has arrived. Valid values are 1-31.
++        u32  microframe_index     :5;
++        // HID/Raw Data: This bit describes whether the data from the sensor is Raw data or a HID
++        // report. When set, the data is a HID report.
++        u32  hid_report           :1;
++        // Reserved
++        u32  reserved            :3;
++    } fields;
++} touch_frame_char_reg_t;
++C_ASSERT(sizeof(touch_frame_char_reg_t) == 4);
++
++
++//
++// Offset 08h: Touch Error Register
++//
++#define TOUCH_ERR_REG_OFFSET                0x08
++
++// bit definition is vendor specific
++typedef union touch_err_reg
++{
++    u32  reg_value;
++
++    struct
++    {
++        u32  invalid_fw           :1;
++        u32  invalid_data        :1;
++        u32  self_test_failed       :1;
++        u32  reserved            :12;
++        u32  fatal_error          :1;
++        u32  vendor_errors        :16;
++    } fields;
++} touch_err_reg_t;
++C_ASSERT(sizeof(touch_err_reg_t) == 4);
++
++
++//
++// Offset 0Ch: RESERVED
++// This register is reserved for future use.
++//
++
++
++//
++// Offset 10h: Touch Identification Register
++//
++#define TOUCH_ID_REG_OFFSET                 0x10
++
++#define TOUCH_ID_REG_VALUE                  0x43495424
++
++// expected value is "$TIC" or 0x43495424
++typedef u32  touch_id_reg_t;
++C_ASSERT(sizeof(touch_id_reg_t) == 4);
++
++
++//
++// Offset 14h: TOUCH_DATA_SZ: Touch Data Size Register
++// This register describes the maximum size of frames and feedback data
++//
++#define TOUCH_DATA_SZ_REG_OFFSET            0x14
++
++#define TOUCH_MAX_FRAME_SIZE_INCREMENT      64
++#define TOUCH_MAX_FEEDBACK_SIZE_INCREMENT   64
++
++#define TOUCH_SENSOR_MAX_FRAME_SIZE         (32 * 1024)     // Max allowed frame size 32KB
++#define TOUCH_SENSOR_MAX_FEEDBACK_SIZE      (16 * 1024)     // Max allowed feedback size 16KB
++
++typedef union touch_data_sz_reg
++{
++    u32  reg_value;
++
++    struct
++    {
++        // This value describes the maximum frame size in 64byte increments.
++        u32  max_frame_size        :12;
++        // This value describes the maximum feedback size in 64byte increments.
++        u32  max_feedback_size     :8;
++        // Reserved
++        u32  reserved            :12;
++    } fields;
++} touch_data_sz_reg_t;
++C_ASSERT(sizeof(touch_data_sz_reg_t) == 4);
++
++
++//
++// Offset 18h: TOUCH_CAPABILITIES: Touch Capabilities Register
++// This register informs the host as to the capabilities of the touch IC.
++//
++#define TOUCH_CAPS_REG_OFFSET               0x18
++
++typedef enum touch_caps_reg_read_delay_time
++{
++    TOUCH_CAPS_REG_READ_DELAY_TIME_0,
++    TOUCH_CAPS_REG_READ_DELAY_TIME_10uS,
++    TOUCH_CAPS_REG_READ_DELAY_TIME_50uS,
++    TOUCH_CAPS_REG_READ_DELAY_TIME_100uS,
++    TOUCH_CAPS_REG_READ_DELAY_TIME_150uS,
++    TOUCH_CAPS_REG_READ_DELAY_TIME_250uS,
++    TOUCH_CAPS_REG_READ_DELAY_TIME_500uS,
++    TOUCH_CAPS_REG_READ_DELAY_TIME_1mS,
++} touch_caps_reg_read_delay_time_t;
++C_ASSERT(sizeof(touch_caps_reg_read_delay_time_t) == 4);
++
++#define TOUCH_BULK_DATA_MAX_WRITE_INCREMENT 64
++
++typedef union touch_caps_reg
++{
++    u32  reg_value;
++
++    struct
++    {
++        // Reserved for future frequency
++        u32  reserved0           :1;
++        // 17 MHz (14 MHz on Atom) Supported: 0b - Not supported, 1b - Supported
++        u32  supported_17Mhz      :1;
++        // 30 MHz (25MHz on Atom) Supported: 0b - Not supported, 1b - Supported
++        u32  supported_30Mhz      :1;
++        // 50 MHz Supported: 0b - Not supported, 1b - Supported
++        u32  supported_50Mhz      :1;
++        // Reserved
++        u32  reserved1           :4;
++        // Single I/O Supported: 0b - Not supported, 1b - Supported
++        u32  supported_single_io   :1;
++        // Dual I/O Supported: 0b - Not supported, 1b - Supported
++        u32  supported_dual_io     :1;
++        // Quad I/O Supported: 0b - Not supported, 1b - Supported
++        u32  supported_quad_io     :1;
++        // Bulk Data Area Max Write Size: The amount of data the SPI Controller can write to the bulk
++        // data area before it has to poll the busy bit. This field is in multiples of 64 bytes. The
++        // SPI Controller will write the amount of data specified in this field, then check and wait
++        // for the Status.Busy bit to be zero before writing the next data chunk. This field is 6 bits
++        // long, allowing for 4KB of contiguous writes w/o a poll of the busy bit. If this field is
++        // 0x00 the Touch IC has no limit in the amount of data the SPI Controller can write to the
++        // bulk data area.
++        u32  bulk_data_max_write    :6;
++        // Read Delay Timer Value: This field describes the delay the SPI Controller will initiate when
++        // a read interrupt follows a write data command. Uses values from TOUCH_CAPS_REG_READ_DELAY_TIME
++        u32  read_delay_timer_value :3;
++        // Reserved
++        u32  reserved2           :4;
++        // Maximum Touch Points: A byte value based on the HID descriptor definition.
++        u32  max_touch_points      :8;
++    } fields;
++} touch_caps_reg_t;
++C_ASSERT(sizeof(touch_caps_reg_t) == 4);
++
++
++//
++// Offset 1Ch: TOUCH_CFG: Touch Configuration Register
++// This register allows the SPI Controller to configure the touch sensor as needed during touch
++// operations.
++//
++#define TOUCH_CFG_REG_OFFSET                0x1C
++
++typedef enum touch_cfg_reg_bulk_xfer_size
++{
++    TOUCH_CFG_REG_BULK_XFER_SIZE_4B  = 0,   // Bulk Data Transfer Size is 4 bytes
++    TOUCH_CFG_REG_BULK_XFER_SIZE_8B,        // Bulk Data Transfer Size is 8 bytes
++    TOUCH_CFG_REG_BULK_XFER_SIZE_16B,       // Bulk Data Transfer Size is 16 bytes
++    TOUCH_CFG_REG_BULK_XFER_SIZE_32B,       // Bulk Data Transfer Size is 32 bytes
++    TOUCH_CFG_REG_BULK_XFER_SIZE_64B,       // Bulk Data Transfer Size is 64 bytes
++    TOUCH_CFG_REG_BULK_XFER_SIZE_MAX
++} touch_cfg_reg_bulk_xfer_size_t;
++C_ASSERT(sizeof(touch_cfg_reg_bulk_xfer_size_t) == 4);
++
++// Frequency values used by TOUCH_CFG_REG and TOUCH_SENSOR_GET_DEVICE_INFO_RSP_DATA.
++typedef enum touch_freq
++{
++    TOUCH_FREQ_RSVD = 0,    // Reserved value
++    TOUCH_FREQ_17MHZ,       // Sensor set for 17MHz operation (14MHz on Atom)
++    TOUCH_FREQ_30MHZ,       // Sensor set for 30MHz operation (25MHz on Atom)
++    TOUCH_FREQ_MAX          // Invalid value
++} touch_freq_t;
++C_ASSERT(sizeof(touch_freq_t) == 4);
++
++typedef union touch_cfg_reg
++{
++    u32  reg_value;
++
++    struct
++    {
++        // Touch Enable (TE):  This bit is used as a HW semaphore for the Touch IC to guarantee to the
++        // SPI Controller to that (when 0) no sensing operations will occur and only the Reset
++        // interrupt will be generated. When TE is cleared by the SPI Controller:
++        //  - TICs must flush all output buffers
++        //  - TICs must De-assert any pending interrupt
++        //  - ME must throw away any partial frame and pending interrupt must be cleared/not serviced.
++        // The SPI Controller will only modify the configuration of the TIC when TE is cleared. TE is
++        // defaulted to 0h on a power-on reset.
++        u32  touch_enable         :1;
++        // Data/HID Packet Mode (DHPM): Raw Data Mode: 0h, HID Packet Mode: 1h
++        u32  dhpm                :1;
++        // Bulk Data Transfer Size: This field represents the amount of data written to the Bulk Data
++        // Area (SPI Offset 0x1000-0x2FFF) in a single SPI write protocol
++        u32  bulk_xfer_size        :4;
++        // Frequency Select: Frequency for the TouchIC to run at. Use values from TOUCH_FREQ
++        u32  freq_select          :3;
++        // Reserved
++        u32  reserved            :23;
++    } fields;
++} touch_cfg_reg_t;
++C_ASSERT(sizeof(touch_cfg_reg_t) == 4);
++
++
++//
++// Offset 20h: TOUCH_CMD: Touch Command Register
++// This register is used for sending commands to the Touch IC.
++//
++#define TOUCH_CMD_REG_OFFSET                0x20
++
++typedef enum touch_cmd_reg_code
++{
++    TOUCH_CMD_REG_CODE_NOP = 0,             // No Operation
++    TOUCH_CMD_REG_CODE_SOFT_RESET,          // Soft Reset
++    TOUCH_CMD_REG_CODE_PREP_4_READ,         // Prepare All Registers for Read
++    TOUCH_CMD_REG_CODE_GEN_TEST_PACKETS,    // Generate Test Packets according to value in TOUCH_TEST_CTRL_REG
++    TOUCH_CMD_REG_CODE_MAX
++} touch_cmd_reg_code_t;
++C_ASSERT(sizeof(touch_cmd_reg_code_t) == 4);
++
++typedef union touch_cmd_reg
++{
++    u32  reg_value;
++
++    struct
++    {
++        // Command Code: See TOUCH_CMD_REG_CODE
++        u32  command_code :8;
++        // Reserved
++        u32  reserved    :24;
++    } fields;
++} touch_cmd_reg_t;
++C_ASSERT(sizeof(touch_cmd_reg_t) == 4);
++
++
++//
++// Offset 24h: Power Management Control
++// This register is used for active power management. The Touch IC is allowed to mover from Doze or
++// Armed to Sensing after a touch has occurred. All other transitions will be made at the request
++// of the SPI Controller.
++//
++#define TOUCH_PWR_MGMT_CTRL_REG_OFFSET      0x24
++
++typedef enum touch_pwr_mgmt_ctrl_reg_cmd
++{
++    TOUCH_PWR_MGMT_CTRL_REG_CMD_NOP = 0,    // No change to power state
++    TOUCH_PWR_MGMT_CTRL_REG_CMD_SLEEP,      // Sleep   - set when the system goes into connected standby
++    TOUCH_PWR_MGMT_CTRL_REG_CMD_DOZE,       // Doze    - set after 300 seconds of inactivity
++    TOUCH_PWR_MGMT_CTRL_REG_CMD_ARMED,      // Armed   - Set by FW when a "finger off" message is received from the EUs
++    TOUCH_PWR_MGMT_CTRL_REG_CMD_SENSING,    // Sensing - not typically set by FW
++    TOUCH_PWR_MGMT_CTRL_REG_CMD_MAX         // Values will result in no change to the power state of the Touch IC
++} touch_pwr_mgmt_ctrl_reg_cmd_t;
++C_ASSERT(sizeof(touch_pwr_mgmt_ctrl_reg_cmd_t) == 4);
++
++typedef union touch_pwr_mgmt_ctrl_reg
++{
++    u32  reg_value;
++
++    struct
++    {
++        // Power State Command: See TOUCH_PWR_MGMT_CTRL_REG_CMD
++        u32  pwr_state_cmd         :3;
++        // Reserved
++        u32  reserved            :29;
++    } fields;
++} touch_pwr_mgmt_ctrl_reg_t;
++C_ASSERT(sizeof(touch_pwr_mgmt_ctrl_reg_t) == 4);
++
++
++//
++// Offset 28h: Vendor HW Information Register
++// This register is used to relay Intel-assigned vendor ID information to the SPI Controller, which
++// may be forwarded to SW running on the host CPU.
++//
++#define TOUCH_VEN_HW_INFO_REG_OFFSET        0x28
++
++typedef union touch_ven_hw_info_reg
++{
++    u32  reg_value;
++
++    struct
++    {
++        // Touch Sensor Vendor ID
++        u32  vendor_id            :16;
++        // Touch Sensor Device ID
++        u32  device_id            :16;
++    } fields;
++} touch_ven_hw_info_reg_t;
++C_ASSERT(sizeof(touch_ven_hw_info_reg_t) == 4);
++
++
++//
++// Offset 2Ch: HW Revision ID Register
++// This register is used to relay vendor HW revision information to the SPI Controller which may be
++// forwarded to SW running on the host CPU.
++//
++#define TOUCH_HW_REV_REG_OFFSET             0x2C
++
++typedef u32  touch_hw_rev_reg_t;   // bit definition is vendor specific
++C_ASSERT(sizeof(touch_hw_rev_reg_t) == 4);
++
++
++//
++// Offset 30h: FW Revision ID Register
++// This register is used to relay vendor FW revision information to the SPI Controller which may be
++// forwarded to SW running on the host CPU.
++//
++#define TOUCH_FW_REV_REG_OFFSET             0x30
++
++typedef u32  touch_fw_rev_reg_t;    // bit definition is vendor specific
++C_ASSERT(sizeof(touch_fw_rev_reg_t) == 4);
++
++
++//
++// Offset 34h: Compatibility Revision ID Register
++// This register is used to relay vendor compatibility information to the SPI Controller which may
++// be forwarded to SW running on the host CPU. Compatibility Information is a numeric value given
++// by Intel to the Touch IC vendor based on the major and minor revision of the EDS supported. From
++// a nomenclature point of view in an x.y revision number of the EDS, the major version is the value
++// of x and the minor version is the value of y. For example, a Touch IC supporting an EDS version
++// of 0.61 would contain a major version of 0 and a minor version of 61 in the register.
++//
++#define TOUCH_COMPAT_REV_REG_OFFSET             0x34
++
++typedef union touch_compat_rev_reg
++{
++    u32  reg_value;
++
++    struct
++    {
++        // EDS Minor Revision
++        u8   minor;
++        // EDS Major Revision
++        u8   major;
++        // Interface Revision Number (from EDS)
++        u8   intf_rev;
++        // EU Kernel Compatibility Version - vendor specific value
++        u8   kernel_compat_ver;
++    } fields;
++} touch_compat_rev_reg_t;
++C_ASSERT(sizeof(touch_compat_rev_reg_t) == 4);
++
++
++//
++// Touch Register Block is the full set of registers from offset 0x00h to 0x3F
++// This is the entire set of registers needed for normal touch operation. It does not include test
++// registers such as TOUCH_TEST_CTRL_REG
++//
++#define TOUCH_REG_BLOCK_OFFSET              TOUCH_STS_REG_OFFSET
++
++typedef struct touch_reg_block
++{
++    touch_sts_reg_t         sts_reg;         // 0x00
++    touch_frame_char_reg_t  frame_char_reg;   // 0x04
++    touch_err_reg_t         error_reg;       // 0x08
++    u32                  reserved0;      // 0x0C
++    touch_id_reg_t          id_reg;          // 0x10
++    touch_data_sz_reg_t     data_size_reg;    // 0x14
++    touch_caps_reg_t        caps_reg;        // 0x18
++    touch_cfg_reg_t         cfg_reg;         // 0x1C
++    touch_cmd_reg_t         cmd_reg;         // 0x20
++    touch_pwr_mgmt_ctrl_reg_t  pwm_mgme_ctrl_reg; // 0x24
++    touch_ven_hw_info_reg_t ven_hw_info_reg;   // 0x28
++    touch_hw_rev_reg_t      hw_rev_reg;       // 0x2C
++    touch_fw_rev_reg_t      fw_rev_reg;       // 0x30
++    touch_compat_rev_reg_t  compat_rev_reg;   // 0x34
++    u32                  reserved1;      // 0x38
++    u32                  reserved2;      // 0x3C
++} touch_reg_block_t;
++C_ASSERT(sizeof(touch_reg_block_t) == 64);
++
++
++//
++// Offset 40h: Test Control Register
++// This register
++//
++#define TOUCH_TEST_CTRL_REG_OFFSET              0x40
++
++typedef union touch_test_ctrl_reg
++{
++    u32  reg_value;
++
++    struct
++    {
++        // Size of Test Frame in Raw Data Mode: This field specifies the test frame size in raw data
++        // mode in multiple of 64 bytes. For example, if this field value is 16, the test frame size
++        // will be 16x64 = 1K.
++        u32  raw_test_frame_size    :16;
++        // Number of Raw Data Frames or HID Report Packets Generation. This field represents the number
++        // of test frames or HID reports to be generated when test mode is enabled. When multiple
++        // packets/frames are generated, they need be generated at 100 Hz frequency, i.e. 10ms per
++        // packet/frame.
++        u32  num_test_frames       :16;
++    } fields;
++} touch_test_ctrl_reg_t;
++C_ASSERT(sizeof(touch_test_ctrl_reg_t) == 4);
++
++
++//
++// Offsets 0x000 to 0xFFF are reserved for Intel-defined Registers
++//
++#define TOUCH_REGISTER_LIMIT                0xFFF
++
++
++//
++// Data Window: Address 0x1000-0x1FFFF
++// The data window is reserved for writing and reading large quantities of data to and from the
++// sensor.
++//
++#define TOUCH_DATA_WINDOW_OFFSET            0x1000
++#define TOUCH_DATA_WINDOW_LIMIT             0x1FFFF
++
++#define TOUCH_SENSOR_MAX_OFFSET             TOUCH_DATA_WINDOW_LIMIT
++
++
++//
++// The following data structures represent the headers defined in the Data Structures chapter of the
++// Intel Integrated Touch EDS
++//
++
++// Enumeration used in TOUCH_RAW_DATA_HDR
++typedef enum touch_raw_data_types
++{
++    TOUCH_RAW_DATA_TYPE_FRAME = 0,
++    TOUCH_RAW_DATA_TYPE_ERROR,          // RawData will be the TOUCH_ERROR struct below
++    TOUCH_RAW_DATA_TYPE_VENDOR_DATA,    // Set when InterruptType is Vendor Data
++    TOUCH_RAW_DATA_TYPE_HID_REPORT,
++    TOUCH_RAW_DATA_TYPE_GET_FEATURES,
++    TOUCH_RAW_DATA_TYPE_MAX
++} touch_raw_data_types_t;
++C_ASSERT(sizeof(touch_raw_data_types_t) == 4);
++
++// Private data structure. Kernels must copy to HID driver buffer
++typedef struct touch_hid_private_data
++{
++    u32  transaction_id;
++    u8   reserved[28];
++} touch_hid_private_data_t;
++C_ASSERT(sizeof(touch_hid_private_data_t) == 32);
++
++// This is the data structure sent from the PCH FW to the EU kernel
++typedef struct touch_raw_data_hdr
++{
++    u32                  data_type;           // use values from TOUCH_RAW_DATA_TYPES
++    u32                  raw_data_size_bytes;   // The size in bytes of the raw data read from the
++                                                // sensor, does not include TOUCH_RAW_DATA_HDR. Will
++                                                // be the sum of all uFrames, or size of TOUCH_ERROR
++                                                // for if DataType is TOUCH_RAW_DATA_TYPE_ERROR
++    u32                  buffer_id;           // An ID to qualify with the feedback data to track
++                                                // buffer usage
++    u32                  protocol_ver;        // Must match protocol version of the EDS
++    u8                   kernel_compat_id;     // Copied from the Compatibility Revision ID Reg
++    u8                   reserved[15];       // Padding to extend header to full 64 bytes and
++                                                // allow for growth
++    touch_hid_private_data_t  hid_private_data;     // Private data structure. Kernels must copy to HID
++                                                // driver buffer
++} touch_raw_data_hdr_t;
++C_ASSERT(sizeof(touch_raw_data_hdr_t) == 64);
++
++typedef struct touch_raw_data
++{
++    touch_raw_data_hdr_t  header;
++    u8               raw_data[1]; // used to access the raw data as an array and keep the
++                                    // compilers happy. Actual size of this array is
++                                    // Header.RawDataSizeBytes
++} touch_raw_data_t;
++
++
++// The following section describes the data passed in TOUCH_RAW_DATA.RawData when DataType equals
++// TOUCH_RAW_DATA_TYPE_ERROR
++// Note: This data structure is also applied to HID mode
++typedef enum touch_err_types
++{
++    TOUCH_RAW_DATA_ERROR = 0,
++    TOUCH_RAW_ERROR_MAX
++} touch_err_types_t;
++C_ASSERT(sizeof(touch_err_types_t) == 4);
++
++typedef union touch_me_fw_error
++{
++    u32  value;
++
++    struct
++    {
++        u32 invalid_frame_characteristics : 1;
++        u32 microframe_index_invalid      : 1;
++        u32 reserved                    : 30;
++    } fields;
++} touch_me_fw_error_t;
++C_ASSERT(sizeof(touch_me_fw_error_t) == 4);
++
++typedef struct touch_error
++{
++    u8			touch_error_type; // This must be a value from TOUCH_ERROR_TYPES
++    u8			reserved[3];
++    touch_me_fw_error_t	touch_me_fw_error;
++    touch_err_reg_t	touch_error_register; // Contains the value copied from the Touch Error Reg
++} touch_error_t;
++C_ASSERT(sizeof(touch_error_t) == 12);
++
++// Enumeration used in TOUCH_FEEDBACK_BUFFER
++typedef enum touch_feedback_cmd_types
++{
++    TOUCH_FEEDBACK_CMD_TYPE_NONE = 0,
++    TOUCH_FEEDBACK_CMD_TYPE_SOFT_RESET,
++    TOUCH_FEEDBACK_CMD_TYPE_GOTO_ARMED,
++    TOUCH_FEEDBACK_CMD_TYPE_GOTO_SENSING,
++    TOUCH_FEEDBACK_CMD_TYPE_GOTO_SLEEP,
++    TOUCH_FEEDBACK_CMD_TYPE_GOTO_DOZE,
++    TOUCH_FEEDBACK_CMD_TYPE_HARD_RESET,
++    TOUCH_FEEDBACK_CMD_TYPE_MAX
++} touch_feedback_cmd_types_t;
++C_ASSERT(sizeof(touch_feedback_cmd_types_t) == 4);
++
++// Enumeration used in TOUCH_FEEDBACK_HDR
++typedef enum touch_feedback_data_types
++{
++    TOUCH_FEEDBACK_DATA_TYPE_FEEDBACK = 0,  // This is vendor specific feedback to be written to the sensor
++    TOUCH_FEEDBACK_DATA_TYPE_SET_FEATURES,  // This is a set features command to be written to the sensor
++    TOUCH_FEEDBACK_DATA_TYPE_GET_FEATURES,  // This is a get features command to be written to the sensor
++    TOUCH_FEEDBACK_DATA_TYPE_OUTPUT_REPORT, // This is a HID output report to be written to the sensor
++    TOUCH_FEEDBACK_DATA_TYPE_STORE_DATA,    // This is calibration data to be written to system flash
++    TOUCH_FEEDBACK_DATA_TYPE_MAX
++} touch_feedback_data_types_t;
++C_ASSERT(sizeof(touch_feedback_data_types_t) == 4);
++
++// This is the data structure sent from the EU kernels back to the ME FW.
++// In addition to "feedback" data, the FW can execute a "command" described by the command type parameter.
++// Any payload data will always be sent to the TIC first, then any command will be issued.
++typedef struct touch_feedback_hdr
++{
++    u32  feedback_cmd_type;    // use values from TOUCH_FEEDBACK_CMD_TYPES
++    u32  payload_size_bytes;   // The amount of data to be written to the sensor, not including the header
++    u32  buffer_id;           // The ID of the raw data buffer that generated this feedback data
++    u32  protocol_ver;        // Must match protocol version of the EDS
++    u32  feedback_data_type;   // use values from TOUCH_FEEDBACK_DATA_TYPES. This is not relevant if PayloadSizeBytes is 0
++    u32  spi_offest;          // The offset from TOUCH_DATA_WINDOW_OFFSET at which to write the Payload data. Maximum offset is 0x1EFFF.
++    u8   reserved[40];       // Padding to extend header to full 64 bytes and allow for growth
++} touch_feedback_hdr_t;
++C_ASSERT(sizeof(touch_feedback_hdr_t) == 64);
++
++typedef struct touch_feedback_buffer
++{
++    touch_feedback_hdr_t  Header;
++    u8               feedback_data[1];    // used to access the feedback data as an array and keep the compilers happy. Actual size of this array is Header.PayloadSizeBytes
++} touch_feedback_buffer_t;
++
++
++//
++// This data structure describes the header prepended to all data
++// written to the touch IC at the bulk data write (TOUCH_DATA_WINDOW_OFFSET + TOUCH_FEEDBACK_HDR.SpiOffest) address.
++typedef enum touch_write_data_type
++{
++    TOUCH_WRITE_DATA_TYPE_FW_LOAD = 0,
++    TOUCH_WRITE_DATA_TYPE_DATA_LOAD,
++    TOUCH_WRITE_DATA_TYPE_FEEDBACK,
++    TOUCH_WRITE_DATA_TYPE_SET_FEATURES,
++    TOUCH_WRITE_DATA_TYPE_GET_FEATURES,
++    TOUCH_WRITE_DATA_TYPE_OUTPUT_REPORT,
++    TOUCH_WRITE_DATA_TYPE_NO_DATA_USE_DEFAULTS,
++    TOUCH_WRITE_DATA_TYPE_MAX
++} touch_write_data_type_t;
++C_ASSERT(sizeof(touch_write_data_type_t) == 4);
++
++typedef struct touch_write_hdr
++{
++    u32  write_data_type;   // Use values from TOUCH_WRITE_DATA_TYPE
++    u32  write_data_len;    // This field designates the amount of data to follow
++} touch_write_hdr_t;
++C_ASSERT(sizeof(touch_write_hdr_t) == 8);
++
++typedef struct touch_write_data
++{
++    touch_write_hdr_t header;
++    u8           write_data[1];   // used to access the write data as an array and keep the compilers happy. Actual size of this array is Header.WriteDataLen
++} touch_write_data_t;
++
++#pragma pack()
++
++#endif // _TOUCH_SENSOR_REGS_H
+diff --git a/drivers/misc/ipts/ipts-state.h b/drivers/misc/ipts/ipts-state.h
+new file mode 100644
+index 000000000000..39a2eaf5f004
+--- /dev/null
++++ b/drivers/misc/ipts/ipts-state.h
+@@ -0,0 +1,29 @@
++/*
++ * Intel Precise Touch & Stylus state codes
++ *
++ * Copyright (c) 2016, Intel Corporation.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms and conditions of the GNU General Public License,
++ * version 2, as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
++ * more details.
++ */
++
++#ifndef _IPTS_STATE_H_
++#define _IPTS_STATE_H_
++
++/* ipts driver states */
++typedef enum ipts_state {
++	IPTS_STA_NONE,
++	IPTS_STA_INIT,
++	IPTS_STA_RESOURCE_READY,
++	IPTS_STA_HID_STARTED,
++	IPTS_STA_RAW_DATA_STARTED,
++	IPTS_STA_STOPPING
++} ipts_state_t;
++
++#endif // _IPTS_STATE_H_
+diff --git a/drivers/misc/ipts/ipts.h b/drivers/misc/ipts/ipts.h
+new file mode 100644
+index 000000000000..1fcd02146b50
+--- /dev/null
++++ b/drivers/misc/ipts/ipts.h
+@@ -0,0 +1,200 @@
++/*
++ *
++ * Intel Management Engine Interface (Intel MEI) Client Driver for IPTS
++ * Copyright (c) 2016, Intel Corporation.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms and conditions of the GNU General Public License,
++ * version 2, as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
++ * more details.
++ *
++ */
++
++#ifndef _IPTS_H_
++#define _IPTS_H_
++
++#include <linux/types.h>
++#include <linux/mei_cl_bus.h>
++#include <linux/hid.h>
++#include <linux/intel_ipts_if.h>
++
++#include "ipts-mei-msgs.h"
++#include "ipts-state.h"
++#include "ipts-binary-spec.h"
++
++//#define ENABLE_IPTS_DEBUG		/* enable IPTS debug */
++
++#ifdef ENABLE_IPTS_DEBUG
++
++#define ipts_info(ipts, format, arg...) do {\
++	dev_info(&ipts->cldev->dev, format, ##arg);\
++} while (0)
++
++#define ipts_dbg(ipts, format, arg...) do {\
++	dev_info(&ipts->cldev->dev, format, ##arg);\
++} while (0)
++
++//#define RUN_DBG_THREAD
++
++#else
++
++#define ipts_info(ipts, format, arg...) do {} while(0);
++#define ipts_dbg(ipts, format, arg...) do {} while(0);
++
++#endif
++
++#define ipts_err(ipts, format, arg...) do {\
++	dev_err(&ipts->cldev->dev, format, ##arg);\
++} while (0)
++
++#define HID_PARALLEL_DATA_BUFFERS	TOUCH_SENSOR_MAX_DATA_BUFFERS
++
++#define IPTS_MAX_RETRY			3
++
++typedef struct ipts_buffer_info {
++	char *addr;
++	dma_addr_t dma_addr;
++} ipts_buffer_info_t;
++
++typedef struct ipts_gfx_info {
++	u64     gfx_handle;
++	intel_ipts_ops_t ipts_ops;
++} ipts_gfx_info_t;
++
++typedef struct ipts_resource {
++	/* ME & Gfx resource */
++	ipts_buffer_info_t touch_data_buffer_raw[HID_PARALLEL_DATA_BUFFERS];
++	ipts_buffer_info_t touch_data_buffer_hid;
++
++	ipts_buffer_info_t feedback_buffer[HID_PARALLEL_DATA_BUFFERS];
++
++	ipts_buffer_info_t hid2me_buffer;
++	u32 hid2me_buffer_size;
++
++	u8 wq_item_size;
++	intel_ipts_wq_info_t wq_info;
++
++	/* ME2HID buffer */
++	char *me2hid_buffer;
++
++	/* Gfx specific resource */
++	ipts_buffer_info_t raw_data_mode_output_buffer
++	    [HID_PARALLEL_DATA_BUFFERS][MAX_NUM_OUTPUT_BUFFERS];
++
++	int num_of_outputs;
++
++	bool default_resource_ready;
++	bool raw_data_resource_ready;
++} ipts_resource_t;
++
++typedef struct ipts_info {
++	struct mei_cl_device *cldev;
++	struct hid_device *hid;
++
++	struct work_struct init_work;
++	struct work_struct raw_data_work;
++	struct work_struct gfx_status_work;
++
++	struct task_struct *event_loop;
++
++#if IS_ENABLED(CONFIG_DEBUG_FS)
++        struct dentry *dbgfs_dir;
++#endif
++
++	ipts_state_t	state;
++
++	touch_sensor_mode_t	sensor_mode;
++	touch_sensor_get_device_info_rsp_data_t device_info;
++	ipts_resource_t	resource;
++	u8		hid_input_report[HID_MAX_BUFFER_SIZE];
++	int		num_of_parallel_data_buffers;
++	bool		hid_desc_ready;
++
++	int current_buffer_index;
++	int last_buffer_completed;
++	int *last_submitted_id;
++
++	ipts_gfx_info_t gfx_info;
++	u64		kernel_handle;
++	int             gfx_status;
++	bool		display_status;
++
++	bool		switch_sensor_mode;
++	touch_sensor_mode_t	new_sensor_mode;
++
++	int		retry;
++	bool		restart;
++} ipts_info_t;
++
++#if IS_ENABLED(CONFIG_DEBUG_FS)
++int ipts_dbgfs_register(ipts_info_t *ipts, const char *name);
++void ipts_dbgfs_deregister(ipts_info_t *ipts);
++#else
++static int ipts_dbgfs_register(ipts_info_t *ipts, const char *name);
++static void ipts_dbgfs_deregister(ipts_info_t *ipts);
++#endif /* CONFIG_DEBUG_FS */
++
++/* inline functions */
++static inline void ipts_set_state(ipts_info_t *ipts, ipts_state_t state)
++{
++	ipts->state = state;
++}
++
++static inline ipts_state_t ipts_get_state(const ipts_info_t *ipts)
++{
++	return ipts->state;
++}
++
++static inline bool ipts_is_default_resource_ready(const ipts_info_t *ipts)
++{
++	return ipts->resource.default_resource_ready;
++}
++
++static inline bool ipts_is_raw_data_resource_ready(const ipts_info_t *ipts)
++{
++	return ipts->resource.raw_data_resource_ready;
++}
++
++static inline ipts_buffer_info_t* ipts_get_feedback_buffer(ipts_info_t *ipts,
++								int buffer_idx)
++{
++	return &ipts->resource.feedback_buffer[buffer_idx];
++}
++
++static inline ipts_buffer_info_t* ipts_get_touch_data_buffer_hid(ipts_info_t *ipts)
++{
++	return &ipts->resource.touch_data_buffer_hid;
++}
++
++static inline ipts_buffer_info_t* ipts_get_output_buffers_by_parallel_id(
++							ipts_info_t *ipts,
++                                                        int parallel_idx)
++{
++	return &ipts->resource.raw_data_mode_output_buffer[parallel_idx][0];
++}
++
++static inline ipts_buffer_info_t* ipts_get_hid2me_buffer(ipts_info_t *ipts)
++{
++	return &ipts->resource.hid2me_buffer;
++}
++
++static inline void ipts_set_wq_item_size(ipts_info_t *ipts, u8 size)
++{
++	ipts->resource.wq_item_size = size;
++}
++
++static inline u8 ipts_get_wq_item_size(const ipts_info_t *ipts)
++{
++	return ipts->resource.wq_item_size;
++}
++
++static inline int ipts_get_num_of_parallel_buffers(const ipts_info_t *ipts)
++{
++	return ipts->num_of_parallel_data_buffers;
++}
++
++#endif // _IPTS_H_
+diff --git a/drivers/misc/mei/hw-me-regs.h b/drivers/misc/mei/hw-me-regs.h
+index e4b10b2d1a08..883b185c9dbe 100644
+--- a/drivers/misc/mei/hw-me-regs.h
++++ b/drivers/misc/mei/hw-me-regs.h
+@@ -119,6 +119,7 @@
+ 
+ #define MEI_DEV_ID_SPT        0x9D3A  /* Sunrise Point */
+ #define MEI_DEV_ID_SPT_2      0x9D3B  /* Sunrise Point 2 */
++#define MEI_DEV_ID_SPT_4      0x9D3E  /* Sunrise Point 4 */
+ #define MEI_DEV_ID_SPT_H      0xA13A  /* Sunrise Point H */
+ #define MEI_DEV_ID_SPT_H_2    0xA13B  /* Sunrise Point H 2 */
+ 
+diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c
+index ea4e152270a3..4d301ba3f867 100644
+--- a/drivers/misc/mei/pci-me.c
++++ b/drivers/misc/mei/pci-me.c
+@@ -86,6 +86,7 @@ static const struct pci_device_id mei_me_pci_tbl[] = {
+ 
+ 	{MEI_PCI_DEVICE(MEI_DEV_ID_SPT, MEI_ME_PCH8_CFG)},
+ 	{MEI_PCI_DEVICE(MEI_DEV_ID_SPT_2, MEI_ME_PCH8_CFG)},
++	{MEI_PCI_DEVICE(MEI_DEV_ID_SPT_4, MEI_ME_PCH8_CFG)},
+ 	{MEI_PCI_DEVICE(MEI_DEV_ID_SPT_H, MEI_ME_PCH8_SPS_CFG)},
+ 	{MEI_PCI_DEVICE(MEI_DEV_ID_SPT_H_2, MEI_ME_PCH8_SPS_CFG)},
+ 	{MEI_PCI_DEVICE(MEI_DEV_ID_LBG, MEI_ME_PCH8_CFG)},
+diff --git a/include/linux/intel_ipts_if.h b/include/linux/intel_ipts_if.h
+new file mode 100644
+index 000000000000..f329bbfb8079
+--- /dev/null
++++ b/include/linux/intel_ipts_if.h
+@@ -0,0 +1,75 @@
++/*
++ *
++ * GFX interface to support Intel Precise Touch & Stylus
++ * Copyright (c) 2016 Intel Corporation.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms and conditions of the GNU General Public License,
++ * version 2, as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
++ * more details.
++ *
++ */
++
++#ifndef INTEL_IPTS_IF_H
++#define INTEL_IPTS_IF_H
++
++enum {
++	IPTS_INTERFACE_V1 = 1,
++};
++
++#define IPTS_BUF_FLAG_CONTIGUOUS	0x01
++
++#define IPTS_NOTIFY_STA_BACKLIGHT_OFF	0x00
++#define IPTS_NOTIFY_STA_BACKLIGHT_ON	0x01
++
++typedef struct intel_ipts_mapbuffer {
++	u32	size;
++	u32	flags;
++	void	*gfx_addr;
++	void	*cpu_addr;
++	u64	buf_handle;
++	u64	phy_addr;
++} intel_ipts_mapbuffer_t;
++
++typedef struct intel_ipts_wq_info {
++	u64 db_addr;
++	u64 db_phy_addr;
++	u32 db_cookie_offset;
++	u32 wq_size;
++	u64 wq_addr;
++	u64 wq_phy_addr;
++	u64 wq_head_addr;	/* head of wq is managed by GPU */
++	u64 wq_head_phy_addr;	/* head of wq is managed by GPU */
++	u64 wq_tail_addr;	/* tail of wq is managed by CSME */
++	u64 wq_tail_phy_addr;	/* tail of wq is managed by CSME */
++} intel_ipts_wq_info_t;
++
++typedef struct intel_ipts_ops {
++	int (*get_wq_info)(uint64_t gfx_handle, intel_ipts_wq_info_t *wq_info);
++	int (*map_buffer)(uint64_t gfx_handle, intel_ipts_mapbuffer_t *mapbuffer);
++	int (*unmap_buffer)(uint64_t gfx_handle, uint64_t buf_handle);
++} intel_ipts_ops_t;
++
++typedef struct intel_ipts_callback {
++        void (*workload_complete)(void *data);
++        void (*notify_gfx_status)(u32 status, void *data);
++} intel_ipts_callback_t;
++
++typedef struct intel_ipts_connect {
++        intel_ipts_callback_t ipts_cb;	/* input : callback addresses */
++	void *data;			/* input : callback data */
++        u32 if_version;			/* input : interface version */
++
++        u32 gfx_version;		/* output : gfx version */
++        u64 gfx_handle;			/* output : gfx handle */
++	intel_ipts_ops_t ipts_ops;	/* output : gfx ops for IPTS */
++} intel_ipts_connect_t;
++
++int intel_ipts_connect(intel_ipts_connect_t *ipts_connect);
++void intel_ipts_disconnect(uint64_t gfx_handle);
++
++#endif // INTEL_IPTS_IF_H

+ 555 - 0
patches/4.18/keyboards_and_covers.patch

@@ -0,0 +1,555 @@
+diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
+index c7981ddd8776..914a19b4290a 100644
+--- a/drivers/hid/hid-ids.h
++++ b/drivers/hid/hid-ids.h
+@@ -793,11 +793,21 @@
+ #define USB_DEVICE_ID_MS_DIGITAL_MEDIA_3KV1 0x0732
+ #define USB_DEVICE_ID_MS_DIGITAL_MEDIA_600  0x0750
+ #define USB_DEVICE_ID_MS_COMFORT_MOUSE_4500	0x076c
+-#define USB_DEVICE_ID_MS_COMFORT_KEYBOARD 0x00e3
+-#define USB_DEVICE_ID_MS_SURFACE_PRO_2   0x0799
+-#define USB_DEVICE_ID_MS_TOUCH_COVER_2   0x07a7
+-#define USB_DEVICE_ID_MS_TYPE_COVER_2    0x07a9
+-#define USB_DEVICE_ID_MS_POWER_COVER     0x07da
++#define USB_DEVICE_ID_MS_COMFORT_KEYBOARD	0x00e3
++#define USB_DEVICE_ID_MS_SURFACE_PRO_2		0x0799
++#define USB_DEVICE_ID_MS_TOUCH_COVER_2		0x07a7
++#define USB_DEVICE_ID_MS_TYPE_COVER_2		0x07a9
++#define USB_DEVICE_ID_MS_TYPE_COVER_3		0x07de
++#define USB_DEVICE_ID_MS_TYPE_COVER_PRO_3	0x07dc
++#define USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_1	0x07de
++#define USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_2	0x07e2
++#define USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_JP	0x07dd
++#define USB_DEVICE_ID_MS_TYPE_COVER_PRO_4	0x07e8
++#define USB_DEVICE_ID_MS_TYPE_COVER_PRO_4_1	0x07e4
++#define USB_DEVICE_ID_MS_SURFACE_BOOK		0x07cd
++#define USB_DEVICE_ID_MS_SURFACE_BOOK_2		0x0922
++#define USB_DEVICE_ID_MS_SURFACE_LAPTOP		0xf001
++#define USB_DEVICE_ID_MS_POWER_COVER		0x07da
+ 
+ #define USB_VENDOR_ID_MOJO		0x8282
+ #define USB_DEVICE_ID_RETRO_ADAPTER	0x3201
+diff --git a/drivers/hid/hid-microsoft.c b/drivers/hid/hid-microsoft.c
+index 96e7d3231d2f..e55097221eec 100644
+--- a/drivers/hid/hid-microsoft.c
++++ b/drivers/hid/hid-microsoft.c
+@@ -278,7 +278,8 @@ static const struct hid_device_id ms_devices[] = {
+ 		.driver_data = MS_HIDINPUT },
+ 	{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_COMFORT_KEYBOARD),
+ 		.driver_data = MS_ERGONOMY},
+-
++	{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_SURFACE_LAPTOP),
++		.driver_data = MS_HIDINPUT},
+ 	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_BT),
+ 		.driver_data = MS_PRESENTER },
+ 	{ }
+diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
+index a0e053c4dc1c..5298793b1eaf 100644
+--- a/drivers/hid/hid-multitouch.c
++++ b/drivers/hid/hid-multitouch.c
+@@ -1754,6 +1754,58 @@ static const struct hid_device_id mt_devices[] = {
+ 		HID_USB_DEVICE(USB_VENDOR_ID_LG,
+ 			USB_DEVICE_ID_LG_MELFAS_MT) },
+ 
++	/* Microsoft Touch Cover */
++	{ .driver_data = MT_CLS_EXPORT_ALL_INPUTS,
++		MT_USB_DEVICE(USB_VENDOR_ID_MICROSOFT,
++		USB_DEVICE_ID_MS_TOUCH_COVER_2) },
++
++	/* Microsoft Type Cover */
++	{ .driver_data = MT_CLS_EXPORT_ALL_INPUTS,
++		MT_USB_DEVICE(USB_VENDOR_ID_MICROSOFT,
++			USB_DEVICE_ID_MS_TYPE_COVER_2) },
++	{ .driver_data = MT_CLS_EXPORT_ALL_INPUTS,
++		MT_USB_DEVICE(USB_VENDOR_ID_MICROSOFT,
++			USB_DEVICE_ID_MS_TYPE_COVER_3) },
++	{ .driver_data = MT_CLS_EXPORT_ALL_INPUTS,
++		MT_USB_DEVICE(USB_VENDOR_ID_MICROSOFT,
++			USB_DEVICE_ID_MS_TYPE_COVER_PRO_3) },
++	{ .driver_data = MT_CLS_EXPORT_ALL_INPUTS,
++		MT_USB_DEVICE(USB_VENDOR_ID_MICROSOFT,
++			USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_1) },
++	{ .driver_data = MT_CLS_EXPORT_ALL_INPUTS,
++		MT_USB_DEVICE(USB_VENDOR_ID_MICROSOFT,
++			USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_2) },
++	{ .driver_data = MT_CLS_EXPORT_ALL_INPUTS,
++		MT_USB_DEVICE(USB_VENDOR_ID_MICROSOFT,
++			USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_JP) },
++	{ .driver_data = MT_CLS_EXPORT_ALL_INPUTS,
++		MT_USB_DEVICE(USB_VENDOR_ID_MICROSOFT,
++			USB_DEVICE_ID_MS_TYPE_COVER_PRO_4) },
++	{ .driver_data = MT_CLS_EXPORT_ALL_INPUTS,
++		MT_USB_DEVICE(USB_VENDOR_ID_MICROSOFT,
++			USB_DEVICE_ID_MS_TYPE_COVER_PRO_4_1) },
++
++	/* Microsoft Surface Book */
++	{ .driver_data = MT_CLS_EXPORT_ALL_INPUTS,
++		MT_USB_DEVICE(USB_VENDOR_ID_MICROSOFT,
++		USB_DEVICE_ID_MS_SURFACE_BOOK) },
++
++	/* Microsoft Surface Book 2 */
++	{ .driver_data = MT_CLS_EXPORT_ALL_INPUTS,
++		MT_USB_DEVICE(USB_VENDOR_ID_MICROSOFT,
++		USB_DEVICE_ID_MS_SURFACE_BOOK_2) },
++
++	/* Microsoft Surface Laptop */
++	{ .driver_data = MT_CLS_EXPORT_ALL_INPUTS,
++		HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY,
++			USB_VENDOR_ID_MICROSOFT,
++			USB_DEVICE_ID_MS_SURFACE_LAPTOP) },
++
++	/* Microsoft Power Cover */
++	{ .driver_data = MT_CLS_EXPORT_ALL_INPUTS,
++		MT_USB_DEVICE(USB_VENDOR_ID_MICROSOFT,
++		USB_DEVICE_ID_MS_POWER_COVER) },
++
+ 	/* MosArt panels */
+ 	{ .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE,
+ 		MT_USB_DEVICE(USB_VENDOR_ID_ASUS,
+diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c
+index 249d49b6b16c..28fa76011df3 100644
+--- a/drivers/hid/hid-quirks.c
++++ b/drivers/hid/hid-quirks.c
+@@ -111,6 +111,16 @@ static const struct hid_device_id hid_quirks[] = {
+ 	{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_SURFACE_PRO_2), HID_QUIRK_NO_INIT_REPORTS },
+ 	{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TOUCH_COVER_2), HID_QUIRK_NO_INIT_REPORTS },
+ 	{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_2), HID_QUIRK_NO_INIT_REPORTS },
++	{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3), HID_QUIRK_NO_INIT_REPORTS },
++	{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3), HID_QUIRK_NO_INIT_REPORTS },
++	{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_1), HID_QUIRK_NO_INIT_REPORTS },
++	{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_2), HID_QUIRK_NO_INIT_REPORTS },
++	{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_JP), HID_QUIRK_NO_INIT_REPORTS },
++	{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_4), HID_QUIRK_NO_INIT_REPORTS },
++	{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_4_1), HID_QUIRK_NO_INIT_REPORTS },
++	{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_SURFACE_BOOK), HID_QUIRK_NO_INIT_REPORTS },
++	{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_SURFACE_BOOK_2), HID_QUIRK_NO_INIT_REPORTS },
++	{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_SURFACE_LAPTOP), HID_QUIRK_ALWAYS_POLL },
+ 	{ HID_USB_DEVICE(USB_VENDOR_ID_MOJO, USB_DEVICE_ID_RETRO_ADAPTER), HID_QUIRK_MULTI_INPUT },
+ 	{ HID_USB_DEVICE(USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GT683R_LED_PANEL), HID_QUIRK_NO_INIT_REPORTS },
+ 	{ HID_USB_DEVICE(USB_VENDOR_ID_MULTIPLE_1781, USB_DEVICE_ID_RAPHNET_4NES4SNES_OLD), HID_QUIRK_MULTI_INPUT },
+diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
+index 28c4cede2d91..4afa91fdb4da 100644
+--- a/drivers/platform/x86/Makefile
++++ b/drivers/platform/x86/Makefile
+@@ -85,6 +85,8 @@ obj-$(CONFIG_SURFACEBOOK2_BUTTON) += surfacebook2_button.o
+ obj-$(CONFIG_ACPI_SURFACE)	+= surface_acpi.o
+ obj-$(CONFIG_ACPI_SURFACE)	+= surface_i2c.o
+ obj-$(CONFIG_ACPI_SURFACE)	+= surface_platform.o
++obj-$(CONFIG_ACPI_SURFACE)	+= surface_vhf.o
++obj-$(CONFIG_ACPI_SURFACE)	+= surface_vhf_keyboard.o
+ obj-$(CONFIG_INTEL_PUNIT_IPC)  += intel_punit_ipc.o
+ obj-$(CONFIG_INTEL_BXTWC_PMIC_TMU)	+= intel_bxtwc_tmu.o
+ obj-$(CONFIG_INTEL_TELEMETRY)	+= intel_telemetry_core.o \
+diff --git a/drivers/platform/x86/surface_vhf.c b/drivers/platform/x86/surface_vhf.c
+new file mode 100644
+index 000000000000..2e9f2a670455
+--- /dev/null
++++ b/drivers/platform/x86/surface_vhf.c
+@@ -0,0 +1,328 @@
++/*
++ *  surface_vhf.c - Microsoft Surface Virtual HID Framework Driver
++ *
++ *  This program is free software; you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License as published by
++ *  the Free Software Foundation; either version 2 of the License, or
++ *  (at your option) any later version.
++ *
++ *  This program is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ * The full GNU General Public License is included in the distribution in
++ * the file called "COPYING".
++ */
++
++#include <linux/acpi.h>
++#include <linux/dmi.h>
++#include <linux/device.h>
++#include <linux/hid.h>
++#include <linux/input.h>
++#include <linux/input/sparse-keymap.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/hid-sensor-hub.h>
++#include <linux/suspend.h>
++#include <linux/clk.h>
++#include <linux/errno.h>
++#include <linux/init.h>
++#include <linux/interrupt.h>
++#include <linux/io.h>
++#include <linux/irq.h>
++#include <linux/pm_wakeup.h>
++#include <linux/slab.h>
++#include <linux/types.h>
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Jake Day");
++
++#define STATUS_REG	0x0C
++#define DATA_REG	0x10
++#define DATA_AVAIL	0x2
++
++static const struct acpi_device_id surface_vhf_ids[] = {
++	{"MSHW0096", 0},
++	{"", 0},
++};
++
++struct surface_kbd {
++	struct input_dev *input;
++	struct resource *res;
++	void __iomem *io_base;
++	struct clk *clk;
++	unsigned short keycodes[256];
++};
++
++struct kbd_platform_data {
++	const struct matrix_keymap_data *keymap;
++	bool rep;
++};
++
++static const struct key_entry surface_vhf_keymap[] = {
++	{ KE_KEY, 1, { KEY_ESC } },
++	{ KE_KEY, 2, { KEY_F1 } },
++	{ KE_KEY, 3, { KEY_F2 } },
++	{ KE_KEY, 4, { KEY_F3 } },
++	{ KE_KEY, 5, { KEY_F4 } },
++	{ KE_KEY, 6, { KEY_F5 } },
++	{ KE_KEY, 7, { KEY_F6 } },
++	{ KE_KEY, 8, { KEY_F7 } },
++	{ KE_KEY, 9, { KEY_F8 } },
++	{ KE_KEY, 10, { KEY_F9 } },
++	{ KE_KEY, 11, { KEY_F10 } },
++	{ KE_KEY, 12, { KEY_F11 } },
++	{ KE_KEY, 13, { KEY_F12 } },
++	{ KE_KEY, 14, { KEY_POWER } },
++	{ KE_KEY, 15, { KEY_DELETE } },
++	{ KE_KEY, 16, { KEY_GRAVE } },
++	{ KE_KEY, 17, { KEY_1 } },
++	{ KE_KEY, 18, { KEY_2 } },
++	{ KE_KEY, 19, { KEY_3 } },
++	{ KE_KEY, 20, { KEY_4 } },
++	{ KE_KEY, 21, { KEY_5 } },
++	{ KE_KEY, 23, { KEY_6 } },
++	{ KE_KEY, 23, { KEY_7 } },
++	{ KE_KEY, 24, { KEY_8 } },
++	{ KE_KEY, 25, { KEY_9 } },
++	{ KE_KEY, 26, { KEY_0 } },
++	{ KE_KEY, 27, { KEY_MINUS } },
++	{ KE_KEY, 28, { KEY_EQUAL } },
++	{ KE_KEY, 29, { KEY_BACKSPACE } },
++	{ KE_KEY, 30, { KEY_TAB } },
++	{ KE_KEY, 31, { KEY_Q } },
++	{ KE_KEY, 32, { KEY_W } },
++	{ KE_KEY, 33, { KEY_E } },
++	{ KE_KEY, 34, { KEY_R } },
++	{ KE_KEY, 35, { KEY_T } },
++	{ KE_KEY, 36, { KEY_Y } },
++	{ KE_KEY, 37, { KEY_U } },
++	{ KE_KEY, 38, { KEY_I } },
++	{ KE_KEY, 39, { KEY_O } },
++	{ KE_KEY, 40, { KEY_P } },
++	{ KE_KEY, 41, { KEY_LEFTBRACE } },
++	{ KE_KEY, 42, { KEY_RIGHTBRACE } },
++	{ KE_KEY, 43, { KEY_BACKSLASH } },
++	{ KE_KEY, 44, { KEY_CAPSLOCK } },
++	{ KE_KEY, 45, { KEY_A } },
++	{ KE_KEY, 46, { KEY_S } },
++	{ KE_KEY, 47, { KEY_D } },
++	{ KE_KEY, 48, { KEY_F } },
++	{ KE_KEY, 49, { KEY_G } },
++	{ KE_KEY, 50, { KEY_H } },
++	{ KE_KEY, 51, { KEY_J } },
++	{ KE_KEY, 52, { KEY_K } },
++	{ KE_KEY, 53, { KEY_L } },
++	{ KE_KEY, 54, { KEY_SEMICOLON } },
++	{ KE_KEY, 55, { KEY_APOSTROPHE } },
++	{ KE_KEY, 56, { KEY_ENTER } },
++	{ KE_KEY, 57, { KEY_LEFTSHIFT } },
++	{ KE_KEY, 58, { KEY_Z } },
++	{ KE_KEY, 59, { KEY_X } },
++	{ KE_KEY, 60, { KEY_C } },
++	{ KE_KEY, 61, { KEY_V } },
++	{ KE_KEY, 62, { KEY_B } },
++	{ KE_KEY, 63, { KEY_N } },
++	{ KE_KEY, 64, { KEY_M } },
++	{ KE_KEY, 65, { KEY_COMMA } },
++	{ KE_KEY, 66, { KEY_DOT } },
++	{ KE_KEY, 67, { KEY_SLASH } },
++	{ KE_KEY, 68, { KEY_RIGHTSHIFT } },
++	{ KE_KEY, 69, { KEY_LEFTCTRL } },
++	{ KE_KEY, 70, { KEY_FN } },
++	{ KE_KEY, 71, { KEY_KPASTERISK } },
++	{ KE_KEY, 72, { KEY_LEFTALT } },
++	{ KE_KEY, 73, { KEY_SPACE } },
++	{ KE_KEY, 74, { KEY_RIGHTALT } },
++	{ KE_KEY, 75, { KEY_MENU } },
++	{ KE_KEY, 76, { KEY_LEFT } },
++	{ KE_KEY, 77, { KEY_UP } },
++	{ KE_KEY, 78, { KEY_DOWN } },
++	{ KE_KEY, 79, { KEY_RIGHT } },
++	{ KE_END },
++};
++
++
++static irqreturn_t surface_kbd_interrupt(int irq, void *dev_id)
++{
++	struct surface_kbd *kbd = dev_id;
++	struct input_dev *input = kbd->input;
++	unsigned int key;
++	u8 sts, val;
++
++	sts = readb(kbd->io_base + STATUS_REG);
++	if (!(sts & DATA_AVAIL))
++		return IRQ_NONE;
++
++	val = readb(kbd->io_base + DATA_REG);
++	key = kbd->keycodes[val];
++
++	input_event(input, EV_MSC, MSC_SCAN, val);
++	input_report_key(input, key, 1);
++	input_sync(input);
++
++	writeb(0, kbd->io_base + STATUS_REG);
++
++	return IRQ_HANDLED;
++}
++
++static int surface_vhf_probe(struct platform_device *pdev)
++{
++	struct resource *res;
++	struct surface_kbd *kbd;
++	struct input_dev *input_dev;
++	int error;
++	int ret;
++	int irq;
++
++	pr_info("Surface VHF found\n");
++
++	pr_info("Surface VHF resources: %u\n", pdev->num_resources);
++
++	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++	if (!res) {
++		dev_err(&pdev->dev, "Surface VHF: No keyboard resource defined\n");
++		return -EBUSY;
++	}
++
++	irq = platform_get_irq(pdev, 0);
++	if (irq < 0) {
++		dev_err(&pdev->dev, "not able to get irq for the device\n");
++		return irq;
++	}
++
++	kbd = kzalloc(sizeof(*kbd), GFP_KERNEL);
++	input_dev = input_allocate_device();
++	if (!kbd || !input_dev) {
++		dev_err(&pdev->dev, "Surface VHF: Out of memory\n");
++		error = -ENOMEM;
++		goto err_free_mem;
++	}
++
++	kbd->input = input_dev;
++
++	/*kbd->res = request_mem_region(res->start, resource_size(res),
++				      pdev->name);
++	if (!kbd->res) {
++		dev_err(&pdev->dev, "keyboard region already claimed\n");
++		error = -EBUSY;
++		goto err_free_mem;
++	}*/
++
++	kbd->io_base = ioremap(res->start, resource_size(res));
++	if (!kbd->io_base) {
++		dev_err(&pdev->dev, "Surface VHF: ioremap failed for kbd region\n");
++		error = -ENOMEM;
++		goto err_release_mem_region;
++	}
++
++	kbd->clk = clk_get(&pdev->dev, NULL);
++	if (IS_ERR(kbd->clk)) {
++		error = PTR_ERR(kbd->clk);
++		goto err_iounmap;
++	}
++
++	input_dev->name = "Surface Laptop Keyboard";
++	input_dev->phys = "keyboard/input0";
++	input_dev->dev.parent = &pdev->dev;
++	input_dev->id.bustype = BUS_HOST;
++	input_dev->id.vendor = 0x045e;
++	input_dev->id.product = 0xf001;
++	input_dev->id.version = 0x0001;
++
++	__set_bit(EV_KEY, input_dev->evbit);
++	input_set_capability(input_dev, EV_MSC, MSC_SCAN);
++
++	input_dev->keycode = kbd->keycodes;
++	input_dev->keycodesize = sizeof(kbd->keycodes[0]);
++	input_dev->keycodemax = ARRAY_SIZE(kbd->keycodes);
++
++	input_set_drvdata(input_dev, kbd);
++
++	ret = sparse_keymap_setup(input_dev, surface_vhf_keymap, NULL);
++	if (ret)
++		return ret;
++
++	error = request_irq(irq, surface_kbd_interrupt, 0, "keyboard", kbd);
++	if (error) {
++		dev_err(&pdev->dev, "Surface VHF: Request_irq fail\n");
++		goto err_put_clk;
++	}
++
++	error = input_register_device(input_dev);
++	if (error) {
++		dev_err(&pdev->dev, "Surface VHF: Unable to register keyboard device\n");
++		return 0;
++	}
++
++	device_init_wakeup(&pdev->dev, 1);
++	platform_set_drvdata(pdev, kbd);
++
++	return 0;
++
++/*err_free_irq:
++	free_irq(kbd->irq, kbd);*/
++err_put_clk:
++	clk_put(kbd->clk);
++err_iounmap:
++	iounmap(kbd->io_base);
++err_release_mem_region:
++	release_mem_region(res->start, resource_size(res));
++err_free_mem:
++	input_free_device(input_dev);
++	kfree(kbd);
++
++	return error;
++}
++
++static int surface_vhf_remove(struct platform_device *pdev)
++{
++	device_init_wakeup(&pdev->dev, false);
++
++	return 0;
++}
++
++static struct platform_driver surface_vhf_driver = {
++	.driver = {
++		.name = "surface_vhf",
++		.acpi_match_table = surface_vhf_ids,
++	},
++	.probe = surface_vhf_probe,
++	.remove = surface_vhf_remove,
++};
++MODULE_DEVICE_TABLE(acpi, surface_vhf_ids);
++
++static acpi_status __init
++check_acpi_dev(acpi_handle handle, u32 lvl, void *context, void **rv)
++{
++	const struct acpi_device_id *ids = context;
++	struct acpi_device *dev;
++
++	if (acpi_bus_get_device(handle, &dev) != 0)
++		return AE_OK;
++
++	if (acpi_match_device_ids(dev, ids) == 0)
++		if (acpi_create_platform_device(dev, NULL))
++			dev_info(&dev->dev,
++				 "Surface VHF: Created platform device\n");
++
++	return AE_OK;
++}
++
++static int __init surface_vhf_init(void)
++{
++	acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
++			    ACPI_UINT32_MAX, check_acpi_dev, NULL,
++			    (void *)surface_vhf_ids, NULL);
++
++	return platform_driver_register(&surface_vhf_driver);
++}
++module_init(surface_vhf_init);
++
++static void __exit surface_vhf_exit(void)
++{
++	platform_driver_unregister(&surface_vhf_driver);
++}
++module_exit(surface_vhf_exit);
+diff --git a/drivers/platform/x86/surface_vhf_keyboard.c b/drivers/platform/x86/surface_vhf_keyboard.c
+new file mode 100644
+index 000000000000..c619d599e4ea
+--- /dev/null
++++ b/drivers/platform/x86/surface_vhf_keyboard.c
+@@ -0,0 +1,73 @@
++/*
++ *  surface_vhf_keyboard.c - Microsoft Surface Virtual HID Framework Keyboard Device
++ *
++ *  This program is free software; you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License as published by
++ *  the Free Software Foundation; either version 2 of the License, or
++ *  (at your option) any later version.
++ *
++ *  This program is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ * The full GNU General Public License is included in the distribution in
++ * the file called "COPYING".
++ */
++
++#include <linux/acpi.h>
++#include <linux/dmi.h>
++#include <linux/device.h>
++#include <linux/hid.h>
++#include <linux/input.h>
++#include <linux/input/sparse-keymap.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/hid-sensor-hub.h>
++#include <linux/suspend.h>
++#include <linux/clk.h>
++#include <linux/errno.h>
++#include <linux/init.h>
++#include <linux/interrupt.h>
++#include <linux/io.h>
++#include <linux/irq.h>
++#include <linux/pm_wakeup.h>
++#include <linux/slab.h>
++#include <linux/types.h>
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Jake Day");
++
++static struct resource surface_vhf_keyboard_resources[] = {
++	{
++		.start	= 0x1a7bbaf9,
++		.end	= 0x2d356b9e,
++		.flags	= IORESOURCE_MEM,
++		.name	= "io-memory"
++	},
++	{
++		.start	= 21,
++		.end	= 21,
++		.flags	= IORESOURCE_IRQ,
++		.name	= "irq",
++	}
++};
++
++static struct platform_device surface_vhf_keyboard = {
++	.name 		= "surface_vhf",
++	.resource	= surface_vhf_keyboard_resources,
++	.num_resources	= ARRAY_SIZE(surface_vhf_keyboard_resources),
++};
++
++static int __init surface_hid_init(void)
++{
++	return platform_device_register(&surface_vhf_keyboard);
++}
++module_init(surface_hid_init);
++
++static void __exit surface_hid_exit(void)
++{
++	platform_device_unregister(&surface_vhf_keyboard);
++}
++module_exit(surface_hid_exit);

+ 14 - 0
patches/4.18/sdcard_reader.patch

@@ -0,0 +1,14 @@
+diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
+index 1fb266809966..916a323ca79f 100644
+--- a/drivers/usb/core/hub.c
++++ b/drivers/usb/core/hub.c
+@@ -4098,7 +4098,8 @@ void usb_enable_lpm(struct usb_device *udev)
+ 	if (!udev || !udev->parent ||
+ 			udev->speed < USB_SPEED_SUPER ||
+ 			!udev->lpm_capable ||
+-			udev->state < USB_STATE_DEFAULT)
++			udev->state < USB_STATE_DEFAULT ||
++			!udev->bos || !udev->bos->ss_cap)
+ 		return;
+ 
+ 	udev->lpm_disable_count--;

+ 30 - 0
patches/4.18/surfacedock.patch

@@ -0,0 +1,30 @@
+diff --git a/drivers/net/usb/cdc_ether.c b/drivers/net/usb/cdc_ether.c
+index 5c42cf81a08b..5eb92c3f3ea3 100644
+--- a/drivers/net/usb/cdc_ether.c
++++ b/drivers/net/usb/cdc_ether.c
+@@ -807,13 +807,6 @@ static const struct usb_device_id	products[] = {
+ 	.driver_info = 0,
+ },
+ 
+-/* Microsoft Surface 3 dock (based on Realtek RTL8153) */
+-{
+-	USB_DEVICE_AND_INTERFACE_INFO(MICROSOFT_VENDOR_ID, 0x07c6, USB_CLASS_COMM,
+-			USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE),
+-	.driver_info = 0,
+-},
+-
+ 	/* TP-LINK UE300 USB 3.0 Ethernet Adapters (based on Realtek RTL8153) */
+ {
+ 	USB_DEVICE_AND_INTERFACE_INFO(TPLINK_VENDOR_ID, 0x0601, USB_CLASS_COMM,
+diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c
+index 2a58607a6aea..954220498d53 100644
+--- a/drivers/net/usb/r8152.c
++++ b/drivers/net/usb/r8152.c
+@@ -5323,7 +5323,6 @@ static const struct usb_device_id rtl8152_table[] = {
+ 	{REALTEK_USB_DEVICE(VENDOR_ID_REALTEK, 0x8152)},
+ 	{REALTEK_USB_DEVICE(VENDOR_ID_REALTEK, 0x8153)},
+ 	{REALTEK_USB_DEVICE(VENDOR_ID_MICROSOFT, 0x07ab)},
+-	{REALTEK_USB_DEVICE(VENDOR_ID_MICROSOFT, 0x07c6)},
+ 	{REALTEK_USB_DEVICE(VENDOR_ID_SAMSUNG, 0xa101)},
+ 	{REALTEK_USB_DEVICE(VENDOR_ID_LENOVO,  0x304f)},
+ 	{REALTEK_USB_DEVICE(VENDOR_ID_LENOVO,  0x3062)},

+ 3 - 0
patches/4.18/wifi.patch

@@ -0,0 +1,3 @@
+diff --git a/scripts/leaking_addresses.pl b/scripts/leaking_addresses.pl
+old mode 100755
+new mode 100644