Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 05d912cf authored by qctecmdr's avatar qctecmdr Committed by Gerrit - the friendly Code Review server
Browse files

Merge "slatecom_interface: add slatecom_interface driver"

parents 43c25dc2 8f6d9d8d
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -1229,5 +1229,14 @@ config MSM_SLATECOM
		This handle the interrupts raised by BG and notify the G-link with
		interrupt event and event data.

config MSM_SLATECOM_INTERFACE
	tristate "Driver support for Slate Communication"
	depends on MSM_SLATECOM
	help
		Create a slate_com_dev device node for user space communication.
		Single user space client can open device node for communication
		from hardware. Hardware will provide access to read
		registers and read/write AHB memory in the device.

source "drivers/soc/qcom/icnss2/Kconfig"
endmenu
+1 −0
Original line number Diff line number Diff line
@@ -111,3 +111,4 @@ obj-$(CONFIG_QCOM_QFPROM_SYS) += qfprom-sys.o
obj-$(CONFIG_RENAME_BLOCK_DEVICE) += rename_block_device.o
obj-$(CONFIG_QCOM_ADSP_MANUAL_VOTE) += adsp_vote_qmi.o adsp_lpm_voting_v01.o
obj-$(CONFIG_MSM_SLATECOM) += slatecom_spi.o
obj-$(CONFIG_MSM_SLATECOM_INTERFACE) += slatecom_interface.o
+626 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0-only
/*
 * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved.
 */
#define pr_fmt(msg) "slatecom_dev:" msg

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/version.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/uaccess.h>
#include <linux/slab.h>
#include <linux/sysfs.h>
#include <linux/kobject.h>
#include <soc/qcom/subsystem_restart.h>
#include <soc/qcom/subsystem_notif.h>
#include "slatecom.h"
#include "linux/slatecom_interface.h"
#include "slatecom_interface.h"
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/gpio.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
#include <asm/dma.h>
#include <linux/dma-mapping.h>

#include "peripheral-loader.h"
#include "../../misc/qseecom_kernel.h"
//#include "pil_slate_intf.h"

#define SLATECOM "slate_com_dev"

#define SLATEDAEMON_LDO09_LPM_VTG 0
#define SLATEDAEMON_LDO09_NPM_VTG 10000

#define SLATEDAEMON_LDO03_LPM_VTG 0
#define SLATEDAEMON_LDO03_NPM_VTG 10000

#define MPPS_DOWN_EVENT_TO_SLATE_TIMEOUT 3000
#define ADSP_DOWN_EVENT_TO_SLATE_TIMEOUT 3000
#define MAX_APP_NAME_SIZE 100

/*pil_slate_intf.h*/
#define RESULT_SUCCESS 0
#define RESULT_FAILURE -1

/* tzapp command list.*/
enum slate_tz_commands {
	SLATEPIL_RAMDUMP,
	SLATEPIL_IMAGE_LOAD,
	SLATEPIL_AUTH_MDT,
	SLATEPIL_DLOAD_CONT,
	SLATEPIL_GET_SLATE_VERSION,
	SLATEPIL_TWM_DATA,
};

/* tzapp slate request.*/
struct tzapp_slate_req {
	uint8_t tzapp_slate_cmd;
	uint8_t padding[3];
	phys_addr_t address_fw;
	size_t size_fw;
} __attribute__ ((__packed__));

/* tzapp slate response.*/
struct tzapp_slate_rsp {
	uint32_t tzapp_slate_cmd;
	uint32_t slate_info_len;
	int32_t status;
	uint32_t slate_info[100];
} __attribute__ ((__packed__));

enum {
	SSR_DOMAIN_SLATE,
	SSR_DOMAIN_MODEM,
	SSR_DOMAIN_ADSP,
	SSR_DOMAIN_MAX,
};

struct slatedaemon_priv {
	void *pil_h;
	struct qseecom_handle *qseecom_handle;
	int app_status;
	unsigned long attrs;
	u32 cmd_status;
	struct device *platform_dev;
};

struct slate_event {
	enum slate_event_type e_type;
};

struct service_info {
	const char                      name[32];
	int                             domain_id;
	void                            *handle;
	struct notifier_block           *nb;
};

static char *ssr_domains[] = {
	"slate-wear",
	"modem",
	"adsp",
};

static struct slatedaemon_priv *dev;
static unsigned int slatereset_gpio;
static  DEFINE_MUTEX(slate_char_mutex);
static  struct cdev              slate_cdev;
static  struct class             *slate_class;
struct  device                   *dev_ret;
static  dev_t                    slate_dev;
static  int                      device_open;
static  void                     *handle;
static	bool                     twm_exit;
static	bool                     slate_app_running;
static  struct   slatecom_open_config_type   config_type;
static DECLARE_COMPLETION(slate_modem_down_wait);
static DECLARE_COMPLETION(slate_adsp_down_wait);

/**
 * send_uevent(): send events to user space
 * pce : ssr event handle value
 * Return: 0 on success, standard Linux error code on error
 *
 * It adds pce value to event and broadcasts to user space.
 */
static int send_uevent(struct slate_event *pce)
{
	char event_string[32];
	char *envp[2] = { event_string, NULL };

	snprintf(event_string, ARRAY_SIZE(event_string),
			"SLATE_EVENT=%d", pce->e_type);
	return kobject_uevent_env(&dev_ret->kobj, KOBJ_CHANGE, envp);
}

static int slatecom_char_open(struct inode *inode, struct file *file)
{
	int ret;

	mutex_lock(&slate_char_mutex);
	if (device_open == 1) {
		pr_err("device is already open\n");
		mutex_unlock(&slate_char_mutex);
		return -EBUSY;
	}
	device_open++;
	handle = slatecom_open(&config_type);
	mutex_unlock(&slate_char_mutex);
	if (IS_ERR(handle)) {
		device_open = 0;
		ret = PTR_ERR(handle);
		handle = NULL;
		return ret;
	}
	return 0;
}

static int slatechar_read_cmd(struct slate_ui_data *fui_obj_msg,
		unsigned int type)
{
	void              *read_buf;
	int               ret;
	void __user       *result   = (void *)
			(uintptr_t)fui_obj_msg->result;

	read_buf = kmalloc_array(fui_obj_msg->num_of_words, sizeof(uint32_t),
			GFP_KERNEL);
	if (read_buf == NULL)
		return -ENOMEM;
	switch (type) {
	case REG_READ:
		ret = slatecom_reg_read(handle, fui_obj_msg->cmd,
				fui_obj_msg->num_of_words,
				read_buf);
		break;
	case AHB_READ:
		ret = slatecom_ahb_read(handle,
				fui_obj_msg->slate_address,
				fui_obj_msg->num_of_words,
				read_buf);
		break;
	}
	if (!ret && copy_to_user(result, read_buf,
			fui_obj_msg->num_of_words * sizeof(uint32_t))) {
		pr_err("copy to user failed\n");
		ret = -EFAULT;
	}
	kfree(read_buf);
	return ret;
}

static int slatechar_write_cmd(struct slate_ui_data *fui_obj_msg, unsigned int type)
{
	void              *write_buf;
	int               ret = -EINVAL;
	void __user       *write     = (void *)
			(uintptr_t)fui_obj_msg->write;

	write_buf = kmalloc_array(fui_obj_msg->num_of_words, sizeof(uint32_t),
			GFP_KERNEL);
	if (write_buf == NULL)
		return -ENOMEM;
	write_buf = memdup_user(write,
			fui_obj_msg->num_of_words * sizeof(uint32_t));
	if (IS_ERR(write_buf)) {
		ret = PTR_ERR(write_buf);
		kfree(write_buf);
		return ret;
	}
	switch (type) {
	case REG_WRITE:
		ret = slatecom_reg_write(handle, fui_obj_msg->cmd,
				fui_obj_msg->num_of_words,
				write_buf);
		break;
	case AHB_WRITE:
		ret = slatecom_ahb_write(handle,
				fui_obj_msg->slate_address,
				fui_obj_msg->num_of_words,
				write_buf);
		break;
	}
	kfree(write_buf);
	return ret;
}

int slate_soft_reset(void)
{
	pr_debug("do SLATE reset using gpio %d\n", slatereset_gpio);
	if (!gpio_is_valid(slatereset_gpio)) {
		pr_err("gpio %d is not valid\n", slatereset_gpio);
		return -ENXIO;
	}
	if (gpio_direction_output(slatereset_gpio, 1))
		pr_err("gpio %d direction not set\n", slatereset_gpio);

	/* Sleep for 50ms for hardware to detect signal as high */
	msleep(50);

	gpio_set_value(slatereset_gpio, 0);

	/* Sleep for 50ms for hardware to detect signal as high */
	msleep(50);
	gpio_set_value(slatereset_gpio, 1);

	return 0;
}
EXPORT_SYMBOL(slate_soft_reset);

static int modem_down2_slate(void)
{
	complete(&slate_modem_down_wait);
	return 0;
}

static int adsp_down2_slate(void)
{
	complete(&slate_adsp_down_wait);
	return 0;
}

static long slate_com_ioctl(struct file *filp,
		unsigned int ui_slatecom_cmd, unsigned long arg)
{
	int ret;
	struct slate_ui_data ui_obj_msg;

	switch (ui_slatecom_cmd) {
	case REG_READ:
	case AHB_READ:
		if (copy_from_user(&ui_obj_msg, (void __user *) arg,
				sizeof(ui_obj_msg))) {
			pr_err("The copy from user failed\n");
			ret = -EFAULT;
		}
		ret = slatechar_read_cmd(&ui_obj_msg,
				ui_slatecom_cmd);
		if (ret < 0)
			pr_err("slatechar_read_cmd failed\n");
		break;
	case AHB_WRITE:
	case REG_WRITE:
		if (copy_from_user(&ui_obj_msg, (void __user *) arg,
				sizeof(ui_obj_msg))) {
			pr_err("The copy from user failed\n");
			ret = -EFAULT;
		}
		ret = slatechar_write_cmd(&ui_obj_msg, ui_slatecom_cmd);
		if (ret < 0)
			pr_err("slatechar_write_cmd failed\n");
		break;
	case SET_SPI_FREE:
		ret = slatecom_set_spi_state(SLATECOM_SPI_FREE);
		break;
	case SET_SPI_BUSY:
		ret = slatecom_set_spi_state(SLATECOM_SPI_BUSY);
		break;
	case SLATE_SOFT_RESET:
		ret = slate_soft_reset();
		break;
	case SLATE_MODEM_DOWN2_SLATE_DONE:
		ret = modem_down2_slate();
		break;
	case SLATE_ADSP_DOWN2_SLATE_DONE:
		ret = adsp_down2_slate();
		break;
	case SLATE_TWM_EXIT:
		twm_exit = true;
		ret = 0;
		break;
	case SLATE_APP_RUNNING:
		slate_app_running = true;
		ret = 0;
		break;
	case SLATE_WEAR_LOAD:
		ret = 0;
		if (dev->pil_h) {
			pr_err("slate-wear is already loaded\n");
			ret = -EFAULT;
			break;
		}
		dev->pil_h = subsystem_get_with_fwname("slate-wear", "slate-wear");
		if (!dev->pil_h) {
			pr_err("failed to load slate-wear\n");
			ret = -EFAULT;
		}
		break;
	case SLATE_WEAR_UNLOAD:
		if (dev->pil_h) {
			subsystem_put(dev->pil_h);
			dev->pil_h = NULL;
			slate_soft_reset();
		}
		ret = 0;
		break;
	default:
		ret = -ENOIOCTLCMD;
		break;
	}
	return ret;
}

static int slatecom_char_close(struct inode *inode, struct file *file)
{
	int ret;

	mutex_lock(&slate_char_mutex);
	ret = slatecom_close(&handle);
	device_open = 0;
	mutex_unlock(&slate_char_mutex);
	return ret;
}

static int slate_daemon_probe(struct platform_device *pdev)
{
	struct device_node *node;

	node = pdev->dev.of_node;

	dev = kzalloc(sizeof(struct slatedaemon_priv), GFP_KERNEL);
	if (!dev)
		return -ENOMEM;

	dev->platform_dev = &pdev->dev;
	pr_info("%s success\n", __func__);

	return 0;
}

static const struct of_device_id slate_daemon_of_match[] = {
	{ .compatible = "qcom,slate-daemon", },
	{ }
};
MODULE_DEVICE_TABLE(of, slate_daemon_of_match);

static struct platform_driver slate_daemon_driver = {
	.probe  = slate_daemon_probe,
	.driver = {
		.name = "slate-daemon",
		.of_match_table = slate_daemon_of_match,
	},
};

static const struct file_operations fops = {
	.owner          = THIS_MODULE,
	.open           = slatecom_char_open,
	.release        = slatecom_char_close,
	.unlocked_ioctl = slate_com_ioctl,
};

/**
 *ssr_slate_cb(): callback function is called
 *by ssr framework when SLATE goes down, up and during ramdump
 *collection. It handles SLATE shutdown and power up events.
 */
static int ssr_slate_cb(struct notifier_block *this,
		unsigned long opcode, void *data)
{
	struct slate_event slatee;

	switch (opcode) {
	case SUBSYS_BEFORE_SHUTDOWN:
		pr_debug("Slate before shutdown\n");
		slatee.e_type = SLATE_BEFORE_POWER_DOWN;
		slatecom_slatedown_handler();
		slatecom_set_spi_state(SLATECOM_SPI_BUSY);
		send_uevent(&slatee);
		break;
	case SUBSYS_AFTER_SHUTDOWN:
		pr_debug("Slate after shutdown\n");
		slatee.e_type = SLATE_AFTER_POWER_DOWN;
		slatecom_slatedown_handler();
		send_uevent(&slatee);
		break;
	case SUBSYS_BEFORE_POWERUP:
		pr_debug("Slate before powerup\n");
		slatee.e_type = SLATE_BEFORE_POWER_UP;
		slatecom_slatedown_handler();
		send_uevent(&slatee);
	break;
	case SUBSYS_AFTER_POWERUP:
		pr_debug("Slate after powerup\n");
		slatecom_set_spi_state(SLATECOM_SPI_FREE);
		send_uevent(&slatee);
		break;
	}
	return NOTIFY_DONE;
}

/**
 *ssr_modem_cb(): callback function is called
 *by ssr framework when modem goes down, up and during ramdump
 *collection. It handles modem shutdown and power up events.
 */
static int ssr_modem_cb(struct notifier_block *this,
		unsigned long opcode, void *data)
{
	struct slate_event modeme;
	int ret;

	switch (opcode) {
	case SUBSYS_BEFORE_SHUTDOWN:
		modeme.e_type = MODEM_BEFORE_POWER_DOWN;
		reinit_completion(&slate_modem_down_wait);
		send_uevent(&modeme);
		ret = wait_for_completion_timeout(&slate_modem_down_wait,
			msecs_to_jiffies(MPPS_DOWN_EVENT_TO_SLATE_TIMEOUT));
		if (!ret)
			pr_err("Time out on modem down event\n");
		break;
	case SUBSYS_AFTER_POWERUP:
		modeme.e_type = MODEM_AFTER_POWER_UP;
		send_uevent(&modeme);
		break;
	}
	return NOTIFY_DONE;
}

static int ssr_adsp_cb(struct notifier_block *this,
		unsigned long opcode, void *data)
{
	struct slate_event adspe;
	int ret;

	switch (opcode) {
	case SUBSYS_BEFORE_SHUTDOWN:
		adspe.e_type = ADSP_BEFORE_POWER_DOWN;
		reinit_completion(&slate_adsp_down_wait);
		send_uevent(&adspe);
		ret = wait_for_completion_timeout(&slate_adsp_down_wait,
			msecs_to_jiffies(ADSP_DOWN_EVENT_TO_SLATE_TIMEOUT));
		if (!ret)
			pr_err("Time out on adsp down event\n");
		break;
	case SUBSYS_AFTER_POWERUP:
		adspe.e_type = ADSP_AFTER_POWER_UP;
		send_uevent(&adspe);
		break;
	}
	return NOTIFY_DONE;
}
bool is_twm_exit(void)
{
	if (twm_exit) {
		twm_exit = false;
		return true;
	}
	return false;
}
EXPORT_SYMBOL(is_twm_exit);

bool is_slate_running(void)
{
	if (slate_app_running) {
		slate_app_running = false;
		return true;
	}
	return false;
}
EXPORT_SYMBOL(is_slate_running);

static struct notifier_block ssr_modem_nb = {
	.notifier_call = ssr_modem_cb,
	.priority = 0,
};

static struct notifier_block ssr_adsp_nb = {
	.notifier_call = ssr_adsp_cb,
	.priority = 0,
};

static struct notifier_block ssr_slate_nb = {
	.notifier_call = ssr_slate_cb,
	.priority = 0,
};

static struct service_info service_data[3] = {
	{
		.name = "SSR_SLATE",
		.domain_id = SSR_DOMAIN_SLATE,
		.nb = &ssr_slate_nb,
		.handle = NULL,
	},
	{
		.name = "SSR_MODEM",
		.domain_id = SSR_DOMAIN_MODEM,
		.nb = &ssr_modem_nb,
		.handle = NULL,
	},
	{
		.name = "SSR_ADSP",
		.domain_id = SSR_DOMAIN_ADSP,
		.nb = &ssr_adsp_nb,
		.handle = NULL,
	},
};

/**
 * ssr_register checks that domain id should be in range and register
 * SSR framework for value at domain id.
 */
static void ssr_register(void)
{
	int i;

	for (i = 0; i < ARRAY_SIZE(service_data); i++) {
		if ((service_data[i].domain_id < 0) ||
				(service_data[i].domain_id >= SSR_DOMAIN_MAX)) {
			pr_err("Invalid service ID = %d\n",
					service_data[i].domain_id);
		} else {
			service_data[i].handle =
					subsys_notif_register_notifier(
					ssr_domains[service_data[i].domain_id],
					service_data[i].nb);
			if (IS_ERR_OR_NULL(service_data[i].handle)) {
				pr_err("subsys register failed for id = %d\n",
						service_data[i].domain_id);
				service_data[i].handle = NULL;
			}
		}
	}

}

static int __init init_slate_com_dev(void)
{
	int ret;

	ret = alloc_chrdev_region(&slate_dev, 0, 1, SLATECOM);
	if (ret  < 0) {
		pr_err("failed with error %d\n", ret);
		return ret;
	}
	cdev_init(&slate_cdev, &fops);

	ret = cdev_add(&slate_cdev, slate_dev, 1);
	if (ret < 0) {
		unregister_chrdev_region(slate_dev, 1);
		pr_err("device registration failed\n");
		return ret;
	}
	slate_class = class_create(THIS_MODULE, SLATECOM);
	if (IS_ERR_OR_NULL(slate_class)) {
		cdev_del(&slate_cdev);
		unregister_chrdev_region(slate_dev, 1);
		pr_err("class creation failed\n");
		return PTR_ERR(slate_class);
	}

	dev_ret = device_create(slate_class, NULL, slate_dev, NULL, SLATECOM);
	if (IS_ERR_OR_NULL(dev_ret)) {
		class_destroy(slate_class);
		cdev_del(&slate_cdev);
		unregister_chrdev_region(slate_dev, 1);
		pr_err("device create failed\n");
		return PTR_ERR(dev_ret);
	}

	if (platform_driver_register(&slate_daemon_driver))
		pr_err("%s: failed to register slate-daemon register\n", __func__);

	ssr_register();

	return 0;
}

static void __exit exit_slate_com_dev(void)
{
	device_destroy(slate_class, slate_dev);
	class_destroy(slate_class);
	cdev_del(&slate_cdev);
	unregister_chrdev_region(slate_dev, 1);
	platform_driver_unregister(&slate_daemon_driver);
}

module_init(init_slate_com_dev);
module_exit(exit_slate_com_dev);
MODULE_LICENSE("GPL v2");
+29 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0-only */
/*
 * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved.
 */
#ifndef SLATECOM_INTERFACE_H
#define SLATECOM_INTERFACE_H

/*
 * slate_soft_reset() - soft reset Blackghost
 * Return 0 on success or -Ve on error
 */
int slate_soft_reset(void);

/*
 * is_twm_exit()
 * Return true if device is booting up on TWM exit.
 * value is auto cleared once read.
 */
bool is_twm_exit(void);

/*
 * is_slate_running()
 * Return true if slate is running.
 * value is auto cleared once read.
 */
bool is_slate_running(void);

#endif /* SLATECOM_INTERFACE_H */
+87 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */
/*
 * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved.
 */
#ifndef LINUX_SLATECOM_INTERFACE_H
#define LINUX_SLATECOM_INTERFACE_H

#include <linux/types.h>

#define SLATECOM_REG_READ  0
#define SLATECOM_AHB_READ  1
#define SLATECOM_AHB_WRITE 2
#define SLATECOM_SET_SPI_FREE  3
#define SLATECOM_SET_SPI_BUSY  4
#define SLATECOM_REG_WRITE  5
#define SLATECOM_SOFT_RESET  6
#define SLATECOM_MODEM_DOWN2_SLATE  7
#define SLATECOM_TWM_EXIT  8
#define SLATECOM_SLATE_APP_RUNNING 9
#define SLATECOM_ADSP_DOWN2_SLATE  10
#define SLATECOM_SLATE_WEAR_LOAD 11
#define SLATECOM_SLATE_WEAR_UNLOAD 12
#define EXCHANGE_CODE  'V'

struct slate_ui_data {
	__u64  __user write;
	__u64  __user result;
	__u32  slate_address;
	__u32  cmd;
	__u32  num_of_words;
	__u8 __user *buffer;
};

enum slate_event_type {
	SLATE_BEFORE_POWER_DOWN = 1,
	SLATE_AFTER_POWER_DOWN,
	SLATE_BEFORE_POWER_UP,
	SLATE_AFTER_POWER_UP,
	MODEM_BEFORE_POWER_DOWN,
	MODEM_AFTER_POWER_UP,
	ADSP_BEFORE_POWER_DOWN,
	ADSP_AFTER_POWER_UP,
	TWM_SLATE_AFTER_POWER_UP,
};

#define REG_READ \
	_IOWR(EXCHANGE_CODE, SLATECOM_REG_READ, \
	struct slate_ui_data)
#define AHB_READ \
	_IOWR(EXCHANGE_CODE, SLATECOM_AHB_READ, \
	struct slate_ui_data)
#define AHB_WRITE \
	_IOW(EXCHANGE_CODE, SLATECOM_AHB_WRITE, \
	struct slate_ui_data)
#define SET_SPI_FREE \
	_IOR(EXCHANGE_CODE, SLATECOM_SET_SPI_FREE, \
	struct slate_ui_data)
#define SET_SPI_BUSY \
	_IOR(EXCHANGE_CODE, SLATECOM_SET_SPI_BUSY, \
	struct slate_ui_data)
#define REG_WRITE \
	_IOWR(EXCHANGE_CODE, SLATECOM_REG_WRITE, \
	struct slate_ui_data)
#define SLATE_SOFT_RESET \
	_IOWR(EXCHANGE_CODE, SLATECOM_SOFT_RESET, \
	struct slate_ui_data)
#define SLATE_TWM_EXIT \
	_IOWR(EXCHANGE_CODE, SLATECOM_TWM_EXIT, \
	struct slate_ui_data)
#define SLATE_APP_RUNNING \
	_IOWR(EXCHANGE_CODE, SLATECOM_SLATE_APP_RUNNING, \
	struct slate_ui_data)
#define SLATE_MODEM_DOWN2_SLATE_DONE \
	_IOWR(EXCHANGE_CODE, SLATECOM_MODEM_DOWN2_SLATE, \
	struct slate_ui_data)
#define SLATE_WEAR_LOAD \
	_IOWR(EXCHANGE_CODE, SLATECOM_SLATE_WEAR_LOAD, \
	struct slate_ui_data)
#define SLATE_WEAR_UNLOAD \
	_IOWR(EXCHANGE_CODE, SLATECOM_SLATE_WEAR_UNLOAD, \
	struct slate_ui_data)
#define SLATE_ADSP_DOWN2_SLATE_DONE \
	_IOWR(EXCHANGE_CODE, SLATECOM_ADSP_DOWN2_SLATE, \
	struct slate_ui_data)

#endif /* LINUX_SLATECOM_INTERFACE_H */