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