18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * MIPI SyS-T framing protocol for STM devices.
48c2ecf20Sopenharmony_ci * Copyright (c) 2018, Intel Corporation.
58c2ecf20Sopenharmony_ci */
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_ci#include <linux/configfs.h>
88c2ecf20Sopenharmony_ci#include <linux/module.h>
98c2ecf20Sopenharmony_ci#include <linux/device.h>
108c2ecf20Sopenharmony_ci#include <linux/slab.h>
118c2ecf20Sopenharmony_ci#include <linux/uuid.h>
128c2ecf20Sopenharmony_ci#include <linux/stm.h>
138c2ecf20Sopenharmony_ci#include "stm.h"
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_cienum sys_t_message_type {
168c2ecf20Sopenharmony_ci	MIPI_SYST_TYPE_BUILD	= 0,
178c2ecf20Sopenharmony_ci	MIPI_SYST_TYPE_SHORT32,
188c2ecf20Sopenharmony_ci	MIPI_SYST_TYPE_STRING,
198c2ecf20Sopenharmony_ci	MIPI_SYST_TYPE_CATALOG,
208c2ecf20Sopenharmony_ci	MIPI_SYST_TYPE_RAW	= 6,
218c2ecf20Sopenharmony_ci	MIPI_SYST_TYPE_SHORT64,
228c2ecf20Sopenharmony_ci	MIPI_SYST_TYPE_CLOCK,
238c2ecf20Sopenharmony_ci};
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_cienum sys_t_message_severity {
268c2ecf20Sopenharmony_ci	MIPI_SYST_SEVERITY_MAX	= 0,
278c2ecf20Sopenharmony_ci	MIPI_SYST_SEVERITY_FATAL,
288c2ecf20Sopenharmony_ci	MIPI_SYST_SEVERITY_ERROR,
298c2ecf20Sopenharmony_ci	MIPI_SYST_SEVERITY_WARNING,
308c2ecf20Sopenharmony_ci	MIPI_SYST_SEVERITY_INFO,
318c2ecf20Sopenharmony_ci	MIPI_SYST_SEVERITY_USER1,
328c2ecf20Sopenharmony_ci	MIPI_SYST_SEVERITY_USER2,
338c2ecf20Sopenharmony_ci	MIPI_SYST_SEVERITY_DEBUG,
348c2ecf20Sopenharmony_ci};
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_cienum sys_t_message_build_subtype {
378c2ecf20Sopenharmony_ci	MIPI_SYST_BUILD_ID_COMPACT32 = 0,
388c2ecf20Sopenharmony_ci	MIPI_SYST_BUILD_ID_COMPACT64,
398c2ecf20Sopenharmony_ci	MIPI_SYST_BUILD_ID_LONG,
408c2ecf20Sopenharmony_ci};
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_cienum sys_t_message_clock_subtype {
438c2ecf20Sopenharmony_ci	MIPI_SYST_CLOCK_TRANSPORT_SYNC = 1,
448c2ecf20Sopenharmony_ci};
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_cienum sys_t_message_string_subtype {
478c2ecf20Sopenharmony_ci	MIPI_SYST_STRING_GENERIC	= 1,
488c2ecf20Sopenharmony_ci	MIPI_SYST_STRING_FUNCTIONENTER,
498c2ecf20Sopenharmony_ci	MIPI_SYST_STRING_FUNCTIONEXIT,
508c2ecf20Sopenharmony_ci	MIPI_SYST_STRING_INVALIDPARAM	= 5,
518c2ecf20Sopenharmony_ci	MIPI_SYST_STRING_ASSERT		= 7,
528c2ecf20Sopenharmony_ci	MIPI_SYST_STRING_PRINTF_32	= 11,
538c2ecf20Sopenharmony_ci	MIPI_SYST_STRING_PRINTF_64	= 12,
548c2ecf20Sopenharmony_ci};
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci#define MIPI_SYST_TYPE(t)		((u32)(MIPI_SYST_TYPE_ ## t))
578c2ecf20Sopenharmony_ci#define MIPI_SYST_SEVERITY(s)		((u32)(MIPI_SYST_SEVERITY_ ## s) << 4)
588c2ecf20Sopenharmony_ci#define MIPI_SYST_OPT_LOC		BIT(8)
598c2ecf20Sopenharmony_ci#define MIPI_SYST_OPT_LEN		BIT(9)
608c2ecf20Sopenharmony_ci#define MIPI_SYST_OPT_CHK		BIT(10)
618c2ecf20Sopenharmony_ci#define MIPI_SYST_OPT_TS		BIT(11)
628c2ecf20Sopenharmony_ci#define MIPI_SYST_UNIT(u)		((u32)(u) << 12)
638c2ecf20Sopenharmony_ci#define MIPI_SYST_ORIGIN(o)		((u32)(o) << 16)
648c2ecf20Sopenharmony_ci#define MIPI_SYST_OPT_GUID		BIT(23)
658c2ecf20Sopenharmony_ci#define MIPI_SYST_SUBTYPE(s)		((u32)(MIPI_SYST_ ## s) << 24)
668c2ecf20Sopenharmony_ci#define MIPI_SYST_UNITLARGE(u)		(MIPI_SYST_UNIT(u & 0xf) | \
678c2ecf20Sopenharmony_ci					 MIPI_SYST_ORIGIN(u >> 4))
688c2ecf20Sopenharmony_ci#define MIPI_SYST_TYPES(t, s)		(MIPI_SYST_TYPE(t) | \
698c2ecf20Sopenharmony_ci					 MIPI_SYST_SUBTYPE(t ## _ ## s))
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci#define DATA_HEADER	(MIPI_SYST_TYPES(STRING, GENERIC)	| \
728c2ecf20Sopenharmony_ci			 MIPI_SYST_SEVERITY(INFO)		| \
738c2ecf20Sopenharmony_ci			 MIPI_SYST_OPT_GUID)
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci#define CLOCK_SYNC_HEADER	(MIPI_SYST_TYPES(CLOCK, TRANSPORT_SYNC)	| \
768c2ecf20Sopenharmony_ci				 MIPI_SYST_SEVERITY(MAX))
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_cistruct sys_t_policy_node {
798c2ecf20Sopenharmony_ci	uuid_t		uuid;
808c2ecf20Sopenharmony_ci	bool		do_len;
818c2ecf20Sopenharmony_ci	unsigned long	ts_interval;
828c2ecf20Sopenharmony_ci	unsigned long	clocksync_interval;
838c2ecf20Sopenharmony_ci};
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_cistruct sys_t_output {
868c2ecf20Sopenharmony_ci	struct sys_t_policy_node	node;
878c2ecf20Sopenharmony_ci	unsigned long	ts_jiffies;
888c2ecf20Sopenharmony_ci	unsigned long	clocksync_jiffies;
898c2ecf20Sopenharmony_ci};
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_cistatic void sys_t_policy_node_init(void *priv)
928c2ecf20Sopenharmony_ci{
938c2ecf20Sopenharmony_ci	struct sys_t_policy_node *pn = priv;
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci	generate_random_uuid(pn->uuid.b);
968c2ecf20Sopenharmony_ci}
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_cistatic int sys_t_output_open(void *priv, struct stm_output *output)
998c2ecf20Sopenharmony_ci{
1008c2ecf20Sopenharmony_ci	struct sys_t_policy_node *pn = priv;
1018c2ecf20Sopenharmony_ci	struct sys_t_output *opriv;
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci	opriv = kzalloc(sizeof(*opriv), GFP_ATOMIC);
1048c2ecf20Sopenharmony_ci	if (!opriv)
1058c2ecf20Sopenharmony_ci		return -ENOMEM;
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci	memcpy(&opriv->node, pn, sizeof(opriv->node));
1088c2ecf20Sopenharmony_ci	output->pdrv_private = opriv;
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ci	return 0;
1118c2ecf20Sopenharmony_ci}
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_cistatic void sys_t_output_close(struct stm_output *output)
1148c2ecf20Sopenharmony_ci{
1158c2ecf20Sopenharmony_ci	kfree(output->pdrv_private);
1168c2ecf20Sopenharmony_ci}
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_cistatic ssize_t sys_t_policy_uuid_show(struct config_item *item,
1198c2ecf20Sopenharmony_ci				      char *page)
1208c2ecf20Sopenharmony_ci{
1218c2ecf20Sopenharmony_ci	struct sys_t_policy_node *pn = to_pdrv_policy_node(item);
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci	return sprintf(page, "%pU\n", &pn->uuid);
1248c2ecf20Sopenharmony_ci}
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_cistatic ssize_t
1278c2ecf20Sopenharmony_cisys_t_policy_uuid_store(struct config_item *item, const char *page,
1288c2ecf20Sopenharmony_ci			size_t count)
1298c2ecf20Sopenharmony_ci{
1308c2ecf20Sopenharmony_ci	struct mutex *mutexp = &item->ci_group->cg_subsys->su_mutex;
1318c2ecf20Sopenharmony_ci	struct sys_t_policy_node *pn = to_pdrv_policy_node(item);
1328c2ecf20Sopenharmony_ci	int ret;
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ci	mutex_lock(mutexp);
1358c2ecf20Sopenharmony_ci	ret = uuid_parse(page, &pn->uuid);
1368c2ecf20Sopenharmony_ci	mutex_unlock(mutexp);
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci	return ret < 0 ? ret : count;
1398c2ecf20Sopenharmony_ci}
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ciCONFIGFS_ATTR(sys_t_policy_, uuid);
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_cistatic ssize_t sys_t_policy_do_len_show(struct config_item *item,
1448c2ecf20Sopenharmony_ci				      char *page)
1458c2ecf20Sopenharmony_ci{
1468c2ecf20Sopenharmony_ci	struct sys_t_policy_node *pn = to_pdrv_policy_node(item);
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci	return sprintf(page, "%d\n", pn->do_len);
1498c2ecf20Sopenharmony_ci}
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_cistatic ssize_t
1528c2ecf20Sopenharmony_cisys_t_policy_do_len_store(struct config_item *item, const char *page,
1538c2ecf20Sopenharmony_ci			size_t count)
1548c2ecf20Sopenharmony_ci{
1558c2ecf20Sopenharmony_ci	struct mutex *mutexp = &item->ci_group->cg_subsys->su_mutex;
1568c2ecf20Sopenharmony_ci	struct sys_t_policy_node *pn = to_pdrv_policy_node(item);
1578c2ecf20Sopenharmony_ci	int ret;
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci	mutex_lock(mutexp);
1608c2ecf20Sopenharmony_ci	ret = kstrtobool(page, &pn->do_len);
1618c2ecf20Sopenharmony_ci	mutex_unlock(mutexp);
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci	return ret ? ret : count;
1648c2ecf20Sopenharmony_ci}
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ciCONFIGFS_ATTR(sys_t_policy_, do_len);
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_cistatic ssize_t sys_t_policy_ts_interval_show(struct config_item *item,
1698c2ecf20Sopenharmony_ci					     char *page)
1708c2ecf20Sopenharmony_ci{
1718c2ecf20Sopenharmony_ci	struct sys_t_policy_node *pn = to_pdrv_policy_node(item);
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci	return sprintf(page, "%u\n", jiffies_to_msecs(pn->ts_interval));
1748c2ecf20Sopenharmony_ci}
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_cistatic ssize_t
1778c2ecf20Sopenharmony_cisys_t_policy_ts_interval_store(struct config_item *item, const char *page,
1788c2ecf20Sopenharmony_ci			       size_t count)
1798c2ecf20Sopenharmony_ci{
1808c2ecf20Sopenharmony_ci	struct mutex *mutexp = &item->ci_group->cg_subsys->su_mutex;
1818c2ecf20Sopenharmony_ci	struct sys_t_policy_node *pn = to_pdrv_policy_node(item);
1828c2ecf20Sopenharmony_ci	unsigned int ms;
1838c2ecf20Sopenharmony_ci	int ret;
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci	mutex_lock(mutexp);
1868c2ecf20Sopenharmony_ci	ret = kstrtouint(page, 10, &ms);
1878c2ecf20Sopenharmony_ci	mutex_unlock(mutexp);
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci	if (!ret) {
1908c2ecf20Sopenharmony_ci		pn->ts_interval = msecs_to_jiffies(ms);
1918c2ecf20Sopenharmony_ci		return count;
1928c2ecf20Sopenharmony_ci	}
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci	return ret;
1958c2ecf20Sopenharmony_ci}
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ciCONFIGFS_ATTR(sys_t_policy_, ts_interval);
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_cistatic ssize_t sys_t_policy_clocksync_interval_show(struct config_item *item,
2008c2ecf20Sopenharmony_ci						    char *page)
2018c2ecf20Sopenharmony_ci{
2028c2ecf20Sopenharmony_ci	struct sys_t_policy_node *pn = to_pdrv_policy_node(item);
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci	return sprintf(page, "%u\n", jiffies_to_msecs(pn->clocksync_interval));
2058c2ecf20Sopenharmony_ci}
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_cistatic ssize_t
2088c2ecf20Sopenharmony_cisys_t_policy_clocksync_interval_store(struct config_item *item,
2098c2ecf20Sopenharmony_ci				      const char *page, size_t count)
2108c2ecf20Sopenharmony_ci{
2118c2ecf20Sopenharmony_ci	struct mutex *mutexp = &item->ci_group->cg_subsys->su_mutex;
2128c2ecf20Sopenharmony_ci	struct sys_t_policy_node *pn = to_pdrv_policy_node(item);
2138c2ecf20Sopenharmony_ci	unsigned int ms;
2148c2ecf20Sopenharmony_ci	int ret;
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ci	mutex_lock(mutexp);
2178c2ecf20Sopenharmony_ci	ret = kstrtouint(page, 10, &ms);
2188c2ecf20Sopenharmony_ci	mutex_unlock(mutexp);
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci	if (!ret) {
2218c2ecf20Sopenharmony_ci		pn->clocksync_interval = msecs_to_jiffies(ms);
2228c2ecf20Sopenharmony_ci		return count;
2238c2ecf20Sopenharmony_ci	}
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci	return ret;
2268c2ecf20Sopenharmony_ci}
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ciCONFIGFS_ATTR(sys_t_policy_, clocksync_interval);
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_cistatic struct configfs_attribute *sys_t_policy_attrs[] = {
2318c2ecf20Sopenharmony_ci	&sys_t_policy_attr_uuid,
2328c2ecf20Sopenharmony_ci	&sys_t_policy_attr_do_len,
2338c2ecf20Sopenharmony_ci	&sys_t_policy_attr_ts_interval,
2348c2ecf20Sopenharmony_ci	&sys_t_policy_attr_clocksync_interval,
2358c2ecf20Sopenharmony_ci	NULL,
2368c2ecf20Sopenharmony_ci};
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_cistatic inline bool sys_t_need_ts(struct sys_t_output *op)
2398c2ecf20Sopenharmony_ci{
2408c2ecf20Sopenharmony_ci	if (op->node.ts_interval &&
2418c2ecf20Sopenharmony_ci	    time_after(jiffies, op->ts_jiffies + op->node.ts_interval)) {
2428c2ecf20Sopenharmony_ci		op->ts_jiffies = jiffies;
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci		return true;
2458c2ecf20Sopenharmony_ci	}
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci	return false;
2488c2ecf20Sopenharmony_ci}
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_cistatic bool sys_t_need_clock_sync(struct sys_t_output *op)
2518c2ecf20Sopenharmony_ci{
2528c2ecf20Sopenharmony_ci	if (op->node.clocksync_interval &&
2538c2ecf20Sopenharmony_ci	    time_after(jiffies,
2548c2ecf20Sopenharmony_ci		       op->clocksync_jiffies + op->node.clocksync_interval)) {
2558c2ecf20Sopenharmony_ci		op->clocksync_jiffies = jiffies;
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci		return true;
2588c2ecf20Sopenharmony_ci	}
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_ci	return false;
2618c2ecf20Sopenharmony_ci}
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_cistatic ssize_t
2648c2ecf20Sopenharmony_cisys_t_clock_sync(struct stm_data *data, unsigned int m, unsigned int c)
2658c2ecf20Sopenharmony_ci{
2668c2ecf20Sopenharmony_ci	u32 header = CLOCK_SYNC_HEADER;
2678c2ecf20Sopenharmony_ci	const unsigned char nil = 0;
2688c2ecf20Sopenharmony_ci	u64 payload[2]; /* Clock value and frequency */
2698c2ecf20Sopenharmony_ci	ssize_t sz;
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_ci	sz = data->packet(data, m, c, STP_PACKET_DATA, STP_PACKET_TIMESTAMPED,
2728c2ecf20Sopenharmony_ci			  4, (u8 *)&header);
2738c2ecf20Sopenharmony_ci	if (sz <= 0)
2748c2ecf20Sopenharmony_ci		return sz;
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_ci	payload[0] = ktime_get_real_ns();
2778c2ecf20Sopenharmony_ci	payload[1] = NSEC_PER_SEC;
2788c2ecf20Sopenharmony_ci	sz = stm_data_write(data, m, c, false, &payload, sizeof(payload));
2798c2ecf20Sopenharmony_ci	if (sz <= 0)
2808c2ecf20Sopenharmony_ci		return sz;
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci	data->packet(data, m, c, STP_PACKET_FLAG, 0, 0, &nil);
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_ci	return sizeof(header) + sizeof(payload);
2858c2ecf20Sopenharmony_ci}
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_cistatic ssize_t sys_t_write(struct stm_data *data, struct stm_output *output,
2888c2ecf20Sopenharmony_ci			   unsigned int chan, const char *buf, size_t count)
2898c2ecf20Sopenharmony_ci{
2908c2ecf20Sopenharmony_ci	struct sys_t_output *op = output->pdrv_private;
2918c2ecf20Sopenharmony_ci	unsigned int c = output->channel + chan;
2928c2ecf20Sopenharmony_ci	unsigned int m = output->master;
2938c2ecf20Sopenharmony_ci	const unsigned char nil = 0;
2948c2ecf20Sopenharmony_ci	u32 header = DATA_HEADER;
2958c2ecf20Sopenharmony_ci	ssize_t sz;
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci	/* We require an existing policy node to proceed */
2988c2ecf20Sopenharmony_ci	if (!op)
2998c2ecf20Sopenharmony_ci		return -EINVAL;
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci	if (sys_t_need_clock_sync(op)) {
3028c2ecf20Sopenharmony_ci		sz = sys_t_clock_sync(data, m, c);
3038c2ecf20Sopenharmony_ci		if (sz <= 0)
3048c2ecf20Sopenharmony_ci			return sz;
3058c2ecf20Sopenharmony_ci	}
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci	if (op->node.do_len)
3088c2ecf20Sopenharmony_ci		header |= MIPI_SYST_OPT_LEN;
3098c2ecf20Sopenharmony_ci	if (sys_t_need_ts(op))
3108c2ecf20Sopenharmony_ci		header |= MIPI_SYST_OPT_TS;
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci	/*
3138c2ecf20Sopenharmony_ci	 * STP framing rules for SyS-T frames:
3148c2ecf20Sopenharmony_ci	 *   * the first packet of the SyS-T frame is timestamped;
3158c2ecf20Sopenharmony_ci	 *   * the last packet is a FLAG.
3168c2ecf20Sopenharmony_ci	 */
3178c2ecf20Sopenharmony_ci	/* Message layout: HEADER / GUID / [LENGTH /][TIMESTAMP /] DATA */
3188c2ecf20Sopenharmony_ci	/* HEADER */
3198c2ecf20Sopenharmony_ci	sz = data->packet(data, m, c, STP_PACKET_DATA, STP_PACKET_TIMESTAMPED,
3208c2ecf20Sopenharmony_ci			  4, (u8 *)&header);
3218c2ecf20Sopenharmony_ci	if (sz <= 0)
3228c2ecf20Sopenharmony_ci		return sz;
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_ci	/* GUID */
3258c2ecf20Sopenharmony_ci	sz = stm_data_write(data, m, c, false, op->node.uuid.b, UUID_SIZE);
3268c2ecf20Sopenharmony_ci	if (sz <= 0)
3278c2ecf20Sopenharmony_ci		return sz;
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_ci	/* [LENGTH] */
3308c2ecf20Sopenharmony_ci	if (op->node.do_len) {
3318c2ecf20Sopenharmony_ci		u16 length = count;
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ci		sz = data->packet(data, m, c, STP_PACKET_DATA, 0, 2,
3348c2ecf20Sopenharmony_ci				  (u8 *)&length);
3358c2ecf20Sopenharmony_ci		if (sz <= 0)
3368c2ecf20Sopenharmony_ci			return sz;
3378c2ecf20Sopenharmony_ci	}
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci	/* [TIMESTAMP] */
3408c2ecf20Sopenharmony_ci	if (header & MIPI_SYST_OPT_TS) {
3418c2ecf20Sopenharmony_ci		u64 ts = ktime_get_real_ns();
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_ci		sz = stm_data_write(data, m, c, false, &ts, sizeof(ts));
3448c2ecf20Sopenharmony_ci		if (sz <= 0)
3458c2ecf20Sopenharmony_ci			return sz;
3468c2ecf20Sopenharmony_ci	}
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ci	/* DATA */
3498c2ecf20Sopenharmony_ci	sz = stm_data_write(data, m, c, false, buf, count);
3508c2ecf20Sopenharmony_ci	if (sz > 0)
3518c2ecf20Sopenharmony_ci		data->packet(data, m, c, STP_PACKET_FLAG, 0, 0, &nil);
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_ci	return sz;
3548c2ecf20Sopenharmony_ci}
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_cistatic const struct stm_protocol_driver sys_t_pdrv = {
3578c2ecf20Sopenharmony_ci	.owner			= THIS_MODULE,
3588c2ecf20Sopenharmony_ci	.name			= "p_sys-t",
3598c2ecf20Sopenharmony_ci	.priv_sz		= sizeof(struct sys_t_policy_node),
3608c2ecf20Sopenharmony_ci	.write			= sys_t_write,
3618c2ecf20Sopenharmony_ci	.policy_attr		= sys_t_policy_attrs,
3628c2ecf20Sopenharmony_ci	.policy_node_init	= sys_t_policy_node_init,
3638c2ecf20Sopenharmony_ci	.output_open		= sys_t_output_open,
3648c2ecf20Sopenharmony_ci	.output_close		= sys_t_output_close,
3658c2ecf20Sopenharmony_ci};
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_cistatic int sys_t_stm_init(void)
3688c2ecf20Sopenharmony_ci{
3698c2ecf20Sopenharmony_ci	return stm_register_protocol(&sys_t_pdrv);
3708c2ecf20Sopenharmony_ci}
3718c2ecf20Sopenharmony_ci
3728c2ecf20Sopenharmony_cistatic void sys_t_stm_exit(void)
3738c2ecf20Sopenharmony_ci{
3748c2ecf20Sopenharmony_ci	stm_unregister_protocol(&sys_t_pdrv);
3758c2ecf20Sopenharmony_ci}
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_cimodule_init(sys_t_stm_init);
3788c2ecf20Sopenharmony_cimodule_exit(sys_t_stm_exit);
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2");
3818c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("MIPI SyS-T STM framing protocol driver");
3828c2ecf20Sopenharmony_ciMODULE_AUTHOR("Alexander Shishkin <alexander.shishkin@linux.intel.com>");
383