1d69d5e83SAlexander Shishkin // SPDX-License-Identifier: GPL-2.0 2d69d5e83SAlexander Shishkin /* 3d69d5e83SAlexander Shishkin * MIPI SyS-T framing protocol for STM devices. 4d69d5e83SAlexander Shishkin * Copyright (c) 2018, Intel Corporation. 5d69d5e83SAlexander Shishkin */ 6d69d5e83SAlexander Shishkin 7d69d5e83SAlexander Shishkin #include <linux/configfs.h> 8d69d5e83SAlexander Shishkin #include <linux/module.h> 9d69d5e83SAlexander Shishkin #include <linux/device.h> 10d69d5e83SAlexander Shishkin #include <linux/slab.h> 11d69d5e83SAlexander Shishkin #include <linux/uuid.h> 12d69d5e83SAlexander Shishkin #include <linux/stm.h> 13d69d5e83SAlexander Shishkin #include "stm.h" 14d69d5e83SAlexander Shishkin 15d69d5e83SAlexander Shishkin enum sys_t_message_type { 16d69d5e83SAlexander Shishkin MIPI_SYST_TYPE_BUILD = 0, 17d69d5e83SAlexander Shishkin MIPI_SYST_TYPE_SHORT32, 18d69d5e83SAlexander Shishkin MIPI_SYST_TYPE_STRING, 19d69d5e83SAlexander Shishkin MIPI_SYST_TYPE_CATALOG, 20d69d5e83SAlexander Shishkin MIPI_SYST_TYPE_RAW = 6, 21d69d5e83SAlexander Shishkin MIPI_SYST_TYPE_SHORT64, 22d69d5e83SAlexander Shishkin MIPI_SYST_TYPE_CLOCK, 23d69d5e83SAlexander Shishkin }; 24d69d5e83SAlexander Shishkin 25d69d5e83SAlexander Shishkin enum sys_t_message_severity { 26d69d5e83SAlexander Shishkin MIPI_SYST_SEVERITY_MAX = 0, 27d69d5e83SAlexander Shishkin MIPI_SYST_SEVERITY_FATAL, 28d69d5e83SAlexander Shishkin MIPI_SYST_SEVERITY_ERROR, 29d69d5e83SAlexander Shishkin MIPI_SYST_SEVERITY_WARNING, 30d69d5e83SAlexander Shishkin MIPI_SYST_SEVERITY_INFO, 31d69d5e83SAlexander Shishkin MIPI_SYST_SEVERITY_USER1, 32d69d5e83SAlexander Shishkin MIPI_SYST_SEVERITY_USER2, 33d69d5e83SAlexander Shishkin MIPI_SYST_SEVERITY_DEBUG, 34d69d5e83SAlexander Shishkin }; 35d69d5e83SAlexander Shishkin 36d69d5e83SAlexander Shishkin enum sys_t_message_build_subtype { 37d69d5e83SAlexander Shishkin MIPI_SYST_BUILD_ID_COMPACT32 = 0, 38d69d5e83SAlexander Shishkin MIPI_SYST_BUILD_ID_COMPACT64, 39d69d5e83SAlexander Shishkin MIPI_SYST_BUILD_ID_LONG, 40d69d5e83SAlexander Shishkin }; 41d69d5e83SAlexander Shishkin 42d69d5e83SAlexander Shishkin enum sys_t_message_clock_subtype { 43d69d5e83SAlexander Shishkin MIPI_SYST_CLOCK_TRANSPORT_SYNC = 1, 44d69d5e83SAlexander Shishkin }; 45d69d5e83SAlexander Shishkin 46d69d5e83SAlexander Shishkin enum sys_t_message_string_subtype { 47d69d5e83SAlexander Shishkin MIPI_SYST_STRING_GENERIC = 1, 48d69d5e83SAlexander Shishkin MIPI_SYST_STRING_FUNCTIONENTER, 49d69d5e83SAlexander Shishkin MIPI_SYST_STRING_FUNCTIONEXIT, 50d69d5e83SAlexander Shishkin MIPI_SYST_STRING_INVALIDPARAM = 5, 51d69d5e83SAlexander Shishkin MIPI_SYST_STRING_ASSERT = 7, 52d69d5e83SAlexander Shishkin MIPI_SYST_STRING_PRINTF_32 = 11, 53d69d5e83SAlexander Shishkin MIPI_SYST_STRING_PRINTF_64 = 12, 54d69d5e83SAlexander Shishkin }; 55d69d5e83SAlexander Shishkin 56d69d5e83SAlexander Shishkin #define MIPI_SYST_TYPE(t) ((u32)(MIPI_SYST_TYPE_ ## t)) 57d69d5e83SAlexander Shishkin #define MIPI_SYST_SEVERITY(s) ((u32)(MIPI_SYST_SEVERITY_ ## s) << 4) 58d69d5e83SAlexander Shishkin #define MIPI_SYST_OPT_LOC BIT(8) 59d69d5e83SAlexander Shishkin #define MIPI_SYST_OPT_LEN BIT(9) 60d69d5e83SAlexander Shishkin #define MIPI_SYST_OPT_CHK BIT(10) 61d69d5e83SAlexander Shishkin #define MIPI_SYST_OPT_TS BIT(11) 62d69d5e83SAlexander Shishkin #define MIPI_SYST_UNIT(u) ((u32)(u) << 12) 63d69d5e83SAlexander Shishkin #define MIPI_SYST_ORIGIN(o) ((u32)(o) << 16) 64d69d5e83SAlexander Shishkin #define MIPI_SYST_OPT_GUID BIT(23) 65d69d5e83SAlexander Shishkin #define MIPI_SYST_SUBTYPE(s) ((u32)(MIPI_SYST_ ## s) << 24) 66d69d5e83SAlexander Shishkin #define MIPI_SYST_UNITLARGE(u) (MIPI_SYST_UNIT(u & 0xf) | \ 67d69d5e83SAlexander Shishkin MIPI_SYST_ORIGIN(u >> 4)) 68d69d5e83SAlexander Shishkin #define MIPI_SYST_TYPES(t, s) (MIPI_SYST_TYPE(t) | \ 69d69d5e83SAlexander Shishkin MIPI_SYST_SUBTYPE(t ## _ ## s)) 70d69d5e83SAlexander Shishkin 71d69d5e83SAlexander Shishkin #define DATA_HEADER (MIPI_SYST_TYPES(STRING, GENERIC) | \ 72d69d5e83SAlexander Shishkin MIPI_SYST_SEVERITY(INFO) | \ 73d69d5e83SAlexander Shishkin MIPI_SYST_OPT_GUID) 74d69d5e83SAlexander Shishkin 75*39f10239SAlexander Shishkin #define CLOCK_SYNC_HEADER (MIPI_SYST_TYPES(CLOCK, TRANSPORT_SYNC) | \ 76*39f10239SAlexander Shishkin MIPI_SYST_SEVERITY(MAX)) 77*39f10239SAlexander Shishkin 78d69d5e83SAlexander Shishkin struct sys_t_policy_node { 79d69d5e83SAlexander Shishkin uuid_t uuid; 80d69d5e83SAlexander Shishkin bool do_len; 81d69d5e83SAlexander Shishkin unsigned long ts_interval; 82*39f10239SAlexander Shishkin unsigned long clocksync_interval; 83d69d5e83SAlexander Shishkin }; 84d69d5e83SAlexander Shishkin 85d69d5e83SAlexander Shishkin struct sys_t_output { 86d69d5e83SAlexander Shishkin struct sys_t_policy_node node; 87d69d5e83SAlexander Shishkin unsigned long ts_jiffies; 88*39f10239SAlexander Shishkin unsigned long clocksync_jiffies; 89d69d5e83SAlexander Shishkin }; 90d69d5e83SAlexander Shishkin 91d69d5e83SAlexander Shishkin static void sys_t_policy_node_init(void *priv) 92d69d5e83SAlexander Shishkin { 93d69d5e83SAlexander Shishkin struct sys_t_policy_node *pn = priv; 94d69d5e83SAlexander Shishkin 95d69d5e83SAlexander Shishkin generate_random_uuid(pn->uuid.b); 96d69d5e83SAlexander Shishkin } 97d69d5e83SAlexander Shishkin 98d69d5e83SAlexander Shishkin static int sys_t_output_open(void *priv, struct stm_output *output) 99d69d5e83SAlexander Shishkin { 100d69d5e83SAlexander Shishkin struct sys_t_policy_node *pn = priv; 101d69d5e83SAlexander Shishkin struct sys_t_output *opriv; 102d69d5e83SAlexander Shishkin 103d69d5e83SAlexander Shishkin opriv = kzalloc(sizeof(*opriv), GFP_ATOMIC); 104d69d5e83SAlexander Shishkin if (!opriv) 105d69d5e83SAlexander Shishkin return -ENOMEM; 106d69d5e83SAlexander Shishkin 107d69d5e83SAlexander Shishkin memcpy(&opriv->node, pn, sizeof(opriv->node)); 108d69d5e83SAlexander Shishkin output->pdrv_private = opriv; 109d69d5e83SAlexander Shishkin 110d69d5e83SAlexander Shishkin return 0; 111d69d5e83SAlexander Shishkin } 112d69d5e83SAlexander Shishkin 113d69d5e83SAlexander Shishkin static void sys_t_output_close(struct stm_output *output) 114d69d5e83SAlexander Shishkin { 115d69d5e83SAlexander Shishkin kfree(output->pdrv_private); 116d69d5e83SAlexander Shishkin } 117d69d5e83SAlexander Shishkin 118d69d5e83SAlexander Shishkin static ssize_t sys_t_policy_uuid_show(struct config_item *item, 119d69d5e83SAlexander Shishkin char *page) 120d69d5e83SAlexander Shishkin { 121d69d5e83SAlexander Shishkin struct sys_t_policy_node *pn = to_pdrv_policy_node(item); 122d69d5e83SAlexander Shishkin 123d69d5e83SAlexander Shishkin return sprintf(page, "%pU\n", &pn->uuid); 124d69d5e83SAlexander Shishkin } 125d69d5e83SAlexander Shishkin 126d69d5e83SAlexander Shishkin static ssize_t 127d69d5e83SAlexander Shishkin sys_t_policy_uuid_store(struct config_item *item, const char *page, 128d69d5e83SAlexander Shishkin size_t count) 129d69d5e83SAlexander Shishkin { 130d69d5e83SAlexander Shishkin struct mutex *mutexp = &item->ci_group->cg_subsys->su_mutex; 131d69d5e83SAlexander Shishkin struct sys_t_policy_node *pn = to_pdrv_policy_node(item); 132d69d5e83SAlexander Shishkin int ret; 133d69d5e83SAlexander Shishkin 134d69d5e83SAlexander Shishkin mutex_lock(mutexp); 135d69d5e83SAlexander Shishkin ret = uuid_parse(page, &pn->uuid); 136d69d5e83SAlexander Shishkin mutex_unlock(mutexp); 137d69d5e83SAlexander Shishkin 138d69d5e83SAlexander Shishkin return ret < 0 ? ret : count; 139d69d5e83SAlexander Shishkin } 140d69d5e83SAlexander Shishkin 141d69d5e83SAlexander Shishkin CONFIGFS_ATTR(sys_t_policy_, uuid); 142d69d5e83SAlexander Shishkin 143d69d5e83SAlexander Shishkin static ssize_t sys_t_policy_do_len_show(struct config_item *item, 144d69d5e83SAlexander Shishkin char *page) 145d69d5e83SAlexander Shishkin { 146d69d5e83SAlexander Shishkin struct sys_t_policy_node *pn = to_pdrv_policy_node(item); 147d69d5e83SAlexander Shishkin 148d69d5e83SAlexander Shishkin return sprintf(page, "%d\n", pn->do_len); 149d69d5e83SAlexander Shishkin } 150d69d5e83SAlexander Shishkin 151d69d5e83SAlexander Shishkin static ssize_t 152d69d5e83SAlexander Shishkin sys_t_policy_do_len_store(struct config_item *item, const char *page, 153d69d5e83SAlexander Shishkin size_t count) 154d69d5e83SAlexander Shishkin { 155d69d5e83SAlexander Shishkin struct mutex *mutexp = &item->ci_group->cg_subsys->su_mutex; 156d69d5e83SAlexander Shishkin struct sys_t_policy_node *pn = to_pdrv_policy_node(item); 157d69d5e83SAlexander Shishkin int ret; 158d69d5e83SAlexander Shishkin 159d69d5e83SAlexander Shishkin mutex_lock(mutexp); 160d69d5e83SAlexander Shishkin ret = kstrtobool(page, &pn->do_len); 161d69d5e83SAlexander Shishkin mutex_unlock(mutexp); 162d69d5e83SAlexander Shishkin 163d69d5e83SAlexander Shishkin return ret ? ret : count; 164d69d5e83SAlexander Shishkin } 165d69d5e83SAlexander Shishkin 166d69d5e83SAlexander Shishkin CONFIGFS_ATTR(sys_t_policy_, do_len); 167d69d5e83SAlexander Shishkin 168d69d5e83SAlexander Shishkin static ssize_t sys_t_policy_ts_interval_show(struct config_item *item, 169d69d5e83SAlexander Shishkin char *page) 170d69d5e83SAlexander Shishkin { 171d69d5e83SAlexander Shishkin struct sys_t_policy_node *pn = to_pdrv_policy_node(item); 172d69d5e83SAlexander Shishkin 173d69d5e83SAlexander Shishkin return sprintf(page, "%u\n", jiffies_to_msecs(pn->ts_interval)); 174d69d5e83SAlexander Shishkin } 175d69d5e83SAlexander Shishkin 176d69d5e83SAlexander Shishkin static ssize_t 177d69d5e83SAlexander Shishkin sys_t_policy_ts_interval_store(struct config_item *item, const char *page, 178d69d5e83SAlexander Shishkin size_t count) 179d69d5e83SAlexander Shishkin { 180d69d5e83SAlexander Shishkin struct mutex *mutexp = &item->ci_group->cg_subsys->su_mutex; 181d69d5e83SAlexander Shishkin struct sys_t_policy_node *pn = to_pdrv_policy_node(item); 182d69d5e83SAlexander Shishkin unsigned int ms; 183d69d5e83SAlexander Shishkin int ret; 184d69d5e83SAlexander Shishkin 185d69d5e83SAlexander Shishkin mutex_lock(mutexp); 186d69d5e83SAlexander Shishkin ret = kstrtouint(page, 10, &ms); 187d69d5e83SAlexander Shishkin mutex_unlock(mutexp); 188d69d5e83SAlexander Shishkin 189d69d5e83SAlexander Shishkin if (!ret) { 190d69d5e83SAlexander Shishkin pn->ts_interval = msecs_to_jiffies(ms); 191d69d5e83SAlexander Shishkin return count; 192d69d5e83SAlexander Shishkin } 193d69d5e83SAlexander Shishkin 194d69d5e83SAlexander Shishkin return ret; 195d69d5e83SAlexander Shishkin } 196d69d5e83SAlexander Shishkin 197d69d5e83SAlexander Shishkin CONFIGFS_ATTR(sys_t_policy_, ts_interval); 198d69d5e83SAlexander Shishkin 199*39f10239SAlexander Shishkin static ssize_t sys_t_policy_clocksync_interval_show(struct config_item *item, 200*39f10239SAlexander Shishkin char *page) 201*39f10239SAlexander Shishkin { 202*39f10239SAlexander Shishkin struct sys_t_policy_node *pn = to_pdrv_policy_node(item); 203*39f10239SAlexander Shishkin 204*39f10239SAlexander Shishkin return sprintf(page, "%u\n", jiffies_to_msecs(pn->clocksync_interval)); 205*39f10239SAlexander Shishkin } 206*39f10239SAlexander Shishkin 207*39f10239SAlexander Shishkin static ssize_t 208*39f10239SAlexander Shishkin sys_t_policy_clocksync_interval_store(struct config_item *item, 209*39f10239SAlexander Shishkin const char *page, size_t count) 210*39f10239SAlexander Shishkin { 211*39f10239SAlexander Shishkin struct mutex *mutexp = &item->ci_group->cg_subsys->su_mutex; 212*39f10239SAlexander Shishkin struct sys_t_policy_node *pn = to_pdrv_policy_node(item); 213*39f10239SAlexander Shishkin unsigned int ms; 214*39f10239SAlexander Shishkin int ret; 215*39f10239SAlexander Shishkin 216*39f10239SAlexander Shishkin mutex_lock(mutexp); 217*39f10239SAlexander Shishkin ret = kstrtouint(page, 10, &ms); 218*39f10239SAlexander Shishkin mutex_unlock(mutexp); 219*39f10239SAlexander Shishkin 220*39f10239SAlexander Shishkin if (!ret) { 221*39f10239SAlexander Shishkin pn->clocksync_interval = msecs_to_jiffies(ms); 222*39f10239SAlexander Shishkin return count; 223*39f10239SAlexander Shishkin } 224*39f10239SAlexander Shishkin 225*39f10239SAlexander Shishkin return ret; 226*39f10239SAlexander Shishkin } 227*39f10239SAlexander Shishkin 228*39f10239SAlexander Shishkin CONFIGFS_ATTR(sys_t_policy_, clocksync_interval); 229*39f10239SAlexander Shishkin 230d69d5e83SAlexander Shishkin static struct configfs_attribute *sys_t_policy_attrs[] = { 231d69d5e83SAlexander Shishkin &sys_t_policy_attr_uuid, 232d69d5e83SAlexander Shishkin &sys_t_policy_attr_do_len, 233d69d5e83SAlexander Shishkin &sys_t_policy_attr_ts_interval, 234*39f10239SAlexander Shishkin &sys_t_policy_attr_clocksync_interval, 235d69d5e83SAlexander Shishkin NULL, 236d69d5e83SAlexander Shishkin }; 237d69d5e83SAlexander Shishkin 238d69d5e83SAlexander Shishkin static inline bool sys_t_need_ts(struct sys_t_output *op) 239d69d5e83SAlexander Shishkin { 240d69d5e83SAlexander Shishkin if (op->node.ts_interval && 241d69d5e83SAlexander Shishkin time_after(op->ts_jiffies + op->node.ts_interval, jiffies)) { 242d69d5e83SAlexander Shishkin op->ts_jiffies = jiffies; 243d69d5e83SAlexander Shishkin 244d69d5e83SAlexander Shishkin return true; 245d69d5e83SAlexander Shishkin } 246d69d5e83SAlexander Shishkin 247d69d5e83SAlexander Shishkin return false; 248d69d5e83SAlexander Shishkin } 249d69d5e83SAlexander Shishkin 250*39f10239SAlexander Shishkin static bool sys_t_need_clock_sync(struct sys_t_output *op) 251*39f10239SAlexander Shishkin { 252*39f10239SAlexander Shishkin if (op->node.clocksync_interval && 253*39f10239SAlexander Shishkin time_after(op->clocksync_jiffies + op->node.clocksync_interval, 254*39f10239SAlexander Shishkin jiffies)) { 255*39f10239SAlexander Shishkin op->clocksync_jiffies = jiffies; 256*39f10239SAlexander Shishkin 257*39f10239SAlexander Shishkin return true; 258*39f10239SAlexander Shishkin } 259*39f10239SAlexander Shishkin 260*39f10239SAlexander Shishkin return false; 261*39f10239SAlexander Shishkin } 262*39f10239SAlexander Shishkin 263*39f10239SAlexander Shishkin static ssize_t 264*39f10239SAlexander Shishkin sys_t_clock_sync(struct stm_data *data, unsigned int m, unsigned int c) 265*39f10239SAlexander Shishkin { 266*39f10239SAlexander Shishkin u32 header = CLOCK_SYNC_HEADER; 267*39f10239SAlexander Shishkin const unsigned char nil = 0; 268*39f10239SAlexander Shishkin u64 payload[2]; /* Clock value and frequency */ 269*39f10239SAlexander Shishkin ssize_t sz; 270*39f10239SAlexander Shishkin 271*39f10239SAlexander Shishkin sz = data->packet(data, m, c, STP_PACKET_DATA, STP_PACKET_TIMESTAMPED, 272*39f10239SAlexander Shishkin 4, (u8 *)&header); 273*39f10239SAlexander Shishkin if (sz <= 0) 274*39f10239SAlexander Shishkin return sz; 275*39f10239SAlexander Shishkin 276*39f10239SAlexander Shishkin payload[0] = ktime_get_real_ns(); 277*39f10239SAlexander Shishkin payload[1] = NSEC_PER_SEC; 278*39f10239SAlexander Shishkin sz = stm_data_write(data, m, c, false, &payload, sizeof(payload)); 279*39f10239SAlexander Shishkin if (sz <= 0) 280*39f10239SAlexander Shishkin return sz; 281*39f10239SAlexander Shishkin 282*39f10239SAlexander Shishkin data->packet(data, m, c, STP_PACKET_FLAG, 0, 0, &nil); 283*39f10239SAlexander Shishkin 284*39f10239SAlexander Shishkin return sizeof(header) + sizeof(payload); 285*39f10239SAlexander Shishkin } 286*39f10239SAlexander Shishkin 287d69d5e83SAlexander Shishkin static ssize_t sys_t_write(struct stm_data *data, struct stm_output *output, 288d69d5e83SAlexander Shishkin unsigned int chan, const char *buf, size_t count) 289d69d5e83SAlexander Shishkin { 290d69d5e83SAlexander Shishkin struct sys_t_output *op = output->pdrv_private; 291d69d5e83SAlexander Shishkin unsigned int c = output->channel + chan; 292d69d5e83SAlexander Shishkin unsigned int m = output->master; 293d69d5e83SAlexander Shishkin const unsigned char nil = 0; 294d69d5e83SAlexander Shishkin u32 header = DATA_HEADER; 295d69d5e83SAlexander Shishkin ssize_t sz; 296d69d5e83SAlexander Shishkin 297d69d5e83SAlexander Shishkin /* We require an existing policy node to proceed */ 298d69d5e83SAlexander Shishkin if (!op) 299d69d5e83SAlexander Shishkin return -EINVAL; 300d69d5e83SAlexander Shishkin 301*39f10239SAlexander Shishkin if (sys_t_need_clock_sync(op)) { 302*39f10239SAlexander Shishkin sz = sys_t_clock_sync(data, m, c); 303*39f10239SAlexander Shishkin if (sz <= 0) 304*39f10239SAlexander Shishkin return sz; 305*39f10239SAlexander Shishkin } 306*39f10239SAlexander Shishkin 307d69d5e83SAlexander Shishkin if (op->node.do_len) 308d69d5e83SAlexander Shishkin header |= MIPI_SYST_OPT_LEN; 309d69d5e83SAlexander Shishkin if (sys_t_need_ts(op)) 310d69d5e83SAlexander Shishkin header |= MIPI_SYST_OPT_TS; 311d69d5e83SAlexander Shishkin 312d69d5e83SAlexander Shishkin /* 313d69d5e83SAlexander Shishkin * STP framing rules for SyS-T frames: 314d69d5e83SAlexander Shishkin * * the first packet of the SyS-T frame is timestamped; 315d69d5e83SAlexander Shishkin * * the last packet is a FLAG. 316d69d5e83SAlexander Shishkin */ 317d69d5e83SAlexander Shishkin /* Message layout: HEADER / GUID / [LENGTH /][TIMESTAMP /] DATA */ 318d69d5e83SAlexander Shishkin /* HEADER */ 319d69d5e83SAlexander Shishkin sz = data->packet(data, m, c, STP_PACKET_DATA, STP_PACKET_TIMESTAMPED, 320d69d5e83SAlexander Shishkin 4, (u8 *)&header); 321d69d5e83SAlexander Shishkin if (sz <= 0) 322d69d5e83SAlexander Shishkin return sz; 323d69d5e83SAlexander Shishkin 324d69d5e83SAlexander Shishkin /* GUID */ 325d69d5e83SAlexander Shishkin sz = stm_data_write(data, m, c, false, op->node.uuid.b, UUID_SIZE); 326d69d5e83SAlexander Shishkin if (sz <= 0) 327d69d5e83SAlexander Shishkin return sz; 328d69d5e83SAlexander Shishkin 329d69d5e83SAlexander Shishkin /* [LENGTH] */ 330d69d5e83SAlexander Shishkin if (op->node.do_len) { 331d69d5e83SAlexander Shishkin u16 length = count; 332d69d5e83SAlexander Shishkin 333d69d5e83SAlexander Shishkin sz = data->packet(data, m, c, STP_PACKET_DATA, 0, 2, 334d69d5e83SAlexander Shishkin (u8 *)&length); 335d69d5e83SAlexander Shishkin if (sz <= 0) 336d69d5e83SAlexander Shishkin return sz; 337d69d5e83SAlexander Shishkin } 338d69d5e83SAlexander Shishkin 339d69d5e83SAlexander Shishkin /* [TIMESTAMP] */ 340d69d5e83SAlexander Shishkin if (header & MIPI_SYST_OPT_TS) { 341d69d5e83SAlexander Shishkin u64 ts = ktime_get_real_ns(); 342d69d5e83SAlexander Shishkin 343d69d5e83SAlexander Shishkin sz = stm_data_write(data, m, c, false, &ts, sizeof(ts)); 344d69d5e83SAlexander Shishkin if (sz <= 0) 345d69d5e83SAlexander Shishkin return sz; 346d69d5e83SAlexander Shishkin } 347d69d5e83SAlexander Shishkin 348d69d5e83SAlexander Shishkin /* DATA */ 349d69d5e83SAlexander Shishkin sz = stm_data_write(data, m, c, false, buf, count); 350d69d5e83SAlexander Shishkin if (sz > 0) 351d69d5e83SAlexander Shishkin data->packet(data, m, c, STP_PACKET_FLAG, 0, 0, &nil); 352d69d5e83SAlexander Shishkin 353d69d5e83SAlexander Shishkin return sz; 354d69d5e83SAlexander Shishkin } 355d69d5e83SAlexander Shishkin 356d69d5e83SAlexander Shishkin static const struct stm_protocol_driver sys_t_pdrv = { 357d69d5e83SAlexander Shishkin .owner = THIS_MODULE, 358d69d5e83SAlexander Shishkin .name = "p_sys-t", 359d69d5e83SAlexander Shishkin .priv_sz = sizeof(struct sys_t_policy_node), 360d69d5e83SAlexander Shishkin .write = sys_t_write, 361d69d5e83SAlexander Shishkin .policy_attr = sys_t_policy_attrs, 362d69d5e83SAlexander Shishkin .policy_node_init = sys_t_policy_node_init, 363d69d5e83SAlexander Shishkin .output_open = sys_t_output_open, 364d69d5e83SAlexander Shishkin .output_close = sys_t_output_close, 365d69d5e83SAlexander Shishkin }; 366d69d5e83SAlexander Shishkin 367d69d5e83SAlexander Shishkin static int sys_t_stm_init(void) 368d69d5e83SAlexander Shishkin { 369d69d5e83SAlexander Shishkin return stm_register_protocol(&sys_t_pdrv); 370d69d5e83SAlexander Shishkin } 371d69d5e83SAlexander Shishkin 372d69d5e83SAlexander Shishkin static void sys_t_stm_exit(void) 373d69d5e83SAlexander Shishkin { 374d69d5e83SAlexander Shishkin stm_unregister_protocol(&sys_t_pdrv); 375d69d5e83SAlexander Shishkin } 376d69d5e83SAlexander Shishkin 377d69d5e83SAlexander Shishkin module_init(sys_t_stm_init); 378d69d5e83SAlexander Shishkin module_exit(sys_t_stm_exit); 379d69d5e83SAlexander Shishkin 380d69d5e83SAlexander Shishkin MODULE_LICENSE("GPL v2"); 381d69d5e83SAlexander Shishkin MODULE_DESCRIPTION("MIPI SyS-T STM framing protocol driver"); 382d69d5e83SAlexander Shishkin MODULE_AUTHOR("Alexander Shishkin <alexander.shishkin@linux.intel.com>"); 383