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

Commit 1c275c41 authored by Bhaumik Bhatt's avatar Bhaumik Bhatt
Browse files

mhi: core: enable doorbell method for time synchronization



Some devices support doorbell method to collect time
synchronization information. Add support from host for the
updated way of handling initialization and advertising
support.

Change-Id: I5bc82b946fd64927a2a88babc8d383e5fa664cf6
Signed-off-by: default avatarBhaumik Bhatt <bbhatt@codeaurora.org>
parent 195cc24a
Loading
Loading
Loading
Loading
+96 −73
Original line number Diff line number Diff line
@@ -96,6 +96,57 @@ const char *to_mhi_pm_state_str(enum MHI_PM_STATE state)
	return mhi_pm_state_str[index];
}

static ssize_t time_show(struct device *dev,
			 struct device_attribute *attr,
			 char *buf)
{
	struct mhi_device *mhi_dev = to_mhi_device(dev);
	struct mhi_controller *mhi_cntrl = mhi_dev->mhi_cntrl;
	u64 t_host, t_device;
	int ret;

	ret = mhi_get_remote_time_sync(mhi_dev, &t_host, &t_device);
	if (ret) {
		MHI_ERR("Failed to obtain time, ret:%d\n", ret);
		return ret;
	}

	return scnprintf(buf, PAGE_SIZE, "local: %llu remote: %llu (ticks)\n",
			 t_host, t_device);
}
static DEVICE_ATTR_RO(time);

static ssize_t time_us_show(struct device *dev,
			    struct device_attribute *attr,
			    char *buf)
{
	struct mhi_device *mhi_dev = to_mhi_device(dev);
	struct mhi_controller *mhi_cntrl = mhi_dev->mhi_cntrl;
	u64 t_host, t_device;
	int ret;

	ret = mhi_get_remote_time_sync(mhi_dev, &t_host, &t_device);
	if (ret) {
		MHI_ERR("Failed to obtain time, ret:%d\n", ret);
		return ret;
	}

	return scnprintf(buf, PAGE_SIZE, "local: %llu remote: %llu (us)\n",
			 LOCAL_TICKS_TO_US(t_host),
			 REMOTE_TICKS_TO_US(t_device));
}
static DEVICE_ATTR_RO(time_us);

static struct attribute *mhi_tsync_attrs[] = {
	&dev_attr_time.attr,
	&dev_attr_time_us.attr,
	NULL,
};

static const struct attribute_group mhi_tsync_group = {
	.attrs = mhi_tsync_attrs,
};

static ssize_t log_level_show(struct device *dev,
			      struct device_attribute *attr,
			      char *buf)
@@ -197,15 +248,36 @@ static const struct attribute_group mhi_sysfs_group = {
	.attrs = mhi_sysfs_attrs,
};

int mhi_create_sysfs(struct mhi_controller *mhi_cntrl)
void mhi_create_sysfs(struct mhi_controller *mhi_cntrl)
{
	return sysfs_create_group(&mhi_cntrl->mhi_dev->dev.kobj,
				  &mhi_sysfs_group);
	sysfs_create_group(&mhi_cntrl->mhi_dev->dev.kobj, &mhi_sysfs_group);
	if (mhi_cntrl->mhi_tsync)
		sysfs_create_group(&mhi_cntrl->mhi_dev->dev.kobj,
				   &mhi_tsync_group);
}

void mhi_destroy_sysfs(struct mhi_controller *mhi_cntrl)
{
	struct mhi_device *mhi_dev = mhi_cntrl->mhi_dev;
	struct mhi_timesync *mhi_tsync = mhi_cntrl->mhi_tsync;
	struct tsync_node *tsync, *tmp;

	if (mhi_tsync) {
		mutex_lock(&mhi_cntrl->tsync_mutex);
		sysfs_remove_group(&mhi_cntrl->mhi_dev->dev.kobj,
				   &mhi_tsync_group);

		spin_lock(&mhi_tsync->lock);
		list_for_each_entry_safe(tsync, tmp, &mhi_tsync->head, node) {
			list_del(&tsync->node);
			kfree(tsync);
		}
		spin_unlock(&mhi_tsync->lock);

		kfree(mhi_cntrl->mhi_tsync);
		mhi_cntrl->mhi_tsync = NULL;
		mutex_unlock(&mhi_cntrl->tsync_mutex);
	}

	sysfs_remove_group(&mhi_dev->dev.kobj, &mhi_sysfs_group);

@@ -569,42 +641,32 @@ static int mhi_get_er_index(struct mhi_controller *mhi_cntrl,
	return -ENOENT;
}

int mhi_init_timesync(struct mhi_controller *mhi_cntrl)
static int mhi_init_timesync(struct mhi_controller *mhi_cntrl)
{
	struct mhi_timesync *mhi_tsync;
	u32 time_offset, db_offset;
	int ret;

	read_lock_bh(&mhi_cntrl->pm_lock);
	u32 time_offset, time_cfg_offset;
	int ret, er_index;

	if (!MHI_REG_ACCESS_VALID(mhi_cntrl->pm_state)) {
		ret = -EIO;
		goto exit_timesync;
	}
	if (!mhi_cntrl->time_get || !mhi_cntrl->lpm_disable ||
	     !mhi_cntrl->lpm_enable)
		return -EINVAL;

	ret = mhi_get_capability_offset(mhi_cntrl, TIMESYNC_CAP_ID,
					&time_offset);
	if (ret) {
		MHI_LOG("No timesync capability found\n");
		goto exit_timesync;
		return ret;
	}

	read_unlock_bh(&mhi_cntrl->pm_lock);

	if (!mhi_cntrl->time_get || !mhi_cntrl->lpm_disable ||
	     !mhi_cntrl->lpm_enable)
		return -EINVAL;

	mhi_cntrl->local_timer_freq = arch_timer_get_cntfrq();

	/* register method supported */
	mhi_tsync = kzalloc(sizeof(*mhi_tsync), GFP_KERNEL);
	/* register method is supported */
	mhi_tsync = kzalloc(sizeof(*mhi_tsync), GFP_ATOMIC);
	if (!mhi_tsync)
		return -ENOMEM;

	spin_lock_init(&mhi_tsync->lock);
	INIT_LIST_HEAD(&mhi_tsync->head);
	init_completion(&mhi_tsync->completion);

	/* save time_offset for obtaining time */
	MHI_LOG("TIME OFFS:0x%x\n", time_offset);
@@ -613,61 +675,20 @@ int mhi_init_timesync(struct mhi_controller *mhi_cntrl)

	mhi_cntrl->mhi_tsync = mhi_tsync;

	ret = mhi_create_timesync_sysfs(mhi_cntrl);
	if (unlikely(ret)) {
		/* kernel method still work */
		MHI_ERR("Failed to create timesync sysfs nodes\n");
	}

	read_lock_bh(&mhi_cntrl->pm_lock);

	if (!MHI_REG_ACCESS_VALID(mhi_cntrl->pm_state)) {
		ret = -EIO;
		goto exit_timesync;
	}

	/* get DB offset if supported, else return */
	ret = mhi_read_reg(mhi_cntrl, mhi_cntrl->regs,
			   time_offset + TIMESYNC_DB_OFFSET, &db_offset);
	if (ret || !db_offset) {
		ret = 0;
		goto exit_timesync;
	}

	MHI_LOG("TIMESYNC_DB OFFS:0x%x\n", db_offset);
	mhi_tsync->db = mhi_cntrl->regs + db_offset;

	read_unlock_bh(&mhi_cntrl->pm_lock);

	/* get time-sync event ring configuration */
	ret = mhi_get_er_index(mhi_cntrl, MHI_ER_TSYNC_ELEMENT_TYPE);
	if (ret < 0) {
	/* get timesync event ring configuration */
	er_index = mhi_get_er_index(mhi_cntrl, MHI_ER_TSYNC_ELEMENT_TYPE);
	if (er_index < 0) {
		MHI_LOG("Could not find timesync event ring\n");
		return ret;
	}

	mhi_tsync->er_index = ret;

	ret = mhi_send_cmd(mhi_cntrl, NULL, MHI_CMD_TIMSYNC_CFG);
	if (ret) {
		MHI_ERR("Failed to send time sync cfg cmd\n");
		return ret;
		return er_index;
	}

	ret = wait_for_completion_timeout(&mhi_tsync->completion,
			msecs_to_jiffies(mhi_cntrl->timeout_ms));
	time_cfg_offset = time_offset + TIMESYNC_CFG_OFFSET;

	if (!ret || mhi_tsync->ccs != MHI_EV_CC_SUCCESS) {
		MHI_ERR("Failed to get time cfg cmd completion\n");
		return -EIO;
	}
	/* advertise host support */
	mhi_cntrl->write_reg(mhi_cntrl, mhi_cntrl->regs, time_cfg_offset,
			     MHI_TIMESYNC_DB_SETUP(er_index));

	return 0;

exit_timesync:
	read_unlock_bh(&mhi_cntrl->pm_lock);

	return ret;
}

int mhi_init_sfr(struct mhi_controller *mhi_cntrl)
@@ -832,7 +853,8 @@ int mhi_init_mmio(struct mhi_controller *mhi_cntrl)
	mhi_cntrl->write_reg(mhi_cntrl, mhi_cntrl->wake_db, 0, 0);
	mhi_cntrl->wake_set = false;

	/* setup bw scale db */
	/* setup special purpose doorbells (timesync, bw scale) */
	mhi_cntrl->tsync_db = base + val + (8 * MHI_TIMESYNC_CHAN_DB);
	mhi_cntrl->bw_scale_db = base + val + (8 * MHI_BW_SCALE_CHAN_DB);

	/* setup channel db addresses */
@@ -865,8 +887,9 @@ int mhi_init_mmio(struct mhi_controller *mhi_cntrl)
				    reg_info[i].mask, reg_info[i].shift,
				    reg_info[i].val);

	/* setup bandwidth scaling features */
	/* setup special purpose features such as timesync or bw scaling */
	mhi_init_bw_scale(mhi_cntrl);
	mhi_init_timesync(mhi_cntrl);

	return 0;
}
+16 −23
Original line number Diff line number Diff line
@@ -141,14 +141,14 @@ extern struct bus_type mhi_bus_type;
#define CAP_NEXT_CAP_SHIFT (12)

/* MHI Timesync offsets */
#define TIMESYNC_CFG_OFFSET (0x00)
#define TIMESYNC_CFG_CAPID_MASK (CAP_CAPID_MASK)
#define TIMESYNC_CFG_CAPID_SHIFT (CAP_CAPID_SHIFT)
#define TIMESYNC_CFG_NEXT_OFF_MASK (CAP_NEXT_CAP_MASK)
#define TIMESYNC_CFG_NEXT_OFF_SHIFT (CAP_NEXT_CAP_SHIFT)
#define TIMESYNC_CFG_NUMCMD_MASK (0xFF)
#define TIMESYNC_CFG_NUMCMD_SHIFT (0)
#define TIMESYNC_DB_OFFSET (0x4)
#define TIMESYNC_CFG_OFFSET (0x04)
#define TIMESYNC_CFG_ENABLED_MASK (0x80000000)
#define TIMESYNC_CFG_ENABLED_SHIFT (31)
#define TIMESYNC_CFG_CHAN_DB_ID_MASK (0x0000FF00)
#define TIMESYNC_CFG_CHAN_DB_ID_SHIFT (8)
#define TIMESYNC_CFG_ER_ID_MASK (0x000000FF)
#define TIMESYNC_CFG_ER_ID_SHIFT (0)

#define TIMESYNC_TIME_LOW_OFFSET (0x8)
#define TIMESYNC_TIME_HIGH_OFFSET (0xC)

@@ -325,12 +325,6 @@ enum mhi_cmd_type {
#define MHI_TRE_CMD_START_DWORD1(chid) ((chid << 24) | \
					(MHI_CMD_TYPE_START << 16))

/* time sync cfg command */
#define MHI_TRE_CMD_TSYNC_CFG_PTR (0)
#define MHI_TRE_CMD_TSYNC_CFG_DWORD0 (0)
#define MHI_TRE_CMD_TSYNC_CFG_DWORD1(er) ((MHI_CMD_TYPE_TSYNC << 16) | \
					  (er << 24))

/* subsystem failure reason cfg command */
#define MHI_TRE_CMD_SFR_CFG_PTR(ptr) (ptr)
#define MHI_TRE_CMD_SFR_CFG_DWORD0(len) (len)
@@ -351,6 +345,7 @@ enum mhi_cmd_type {
#define MHI_TRE_GET_EV_STATE(tre) (((tre)->dword[0] >> 24) & 0xFF)
#define MHI_TRE_GET_EV_EXECENV(tre) (((tre)->dword[0] >> 24) & 0xFF)
#define MHI_TRE_GET_EV_TSYNC_SEQ(tre) ((tre)->dword[0])
#define MHI_TRE_GET_EV_TSYNC_UNIT(tre) (((tre)->dword[1] >> 24) & 0xFF)
#define MHI_TRE_GET_EV_TIME(tre) ((tre)->ptr)
#define MHI_TRE_GET_EV_COOKIE(tre) lower_32_bits((tre)->ptr)
#define MHI_TRE_GET_EV_VEID(tre) (((tre)->dword[0] >> 16) & 0xFF)
@@ -375,7 +370,6 @@ enum MHI_CMD {
	MHI_CMD_RESET_CHAN,
	MHI_CMD_START_CHAN,
	MHI_CMD_STOP_CHAN,
	MHI_CMD_TIMSYNC_CFG,
	MHI_CMD_SFR_CFG,
};

@@ -530,10 +524,16 @@ enum MHI_XFER_TYPE {
#define NR_OF_CMD_RINGS (1)
#define CMD_EL_PER_RING (128)
#define PRIMARY_CMD_RING (0)
#define MHI_TIMESYNC_CHAN_DB (125)
#define MHI_BW_SCALE_CHAN_DB (126)
#define MHI_DEV_WAKE_DB (127)
#define MHI_MAX_MTU (0xffff)

#define MHI_TIMESYNC_DB_SETUP(er_index) ((MHI_TIMESYNC_CHAN_DB << \
	TIMESYNC_CFG_CHAN_DB_ID_SHIFT) & TIMESYNC_CFG_CHAN_DB_ID_MASK | \
	(1 << TIMESYNC_CFG_ENABLED_SHIFT) & TIMESYNC_CFG_ENABLED_MASK | \
	((er_index) << TIMESYNC_CFG_ER_ID_SHIFT) & TIMESYNC_CFG_ER_ID_MASK)

#define MHI_BW_SCALE_SETUP(er_index) ((MHI_BW_SCALE_CHAN_DB << \
	BW_SCALE_CFG_CHAN_DB_ID_SHIFT) & BW_SCALE_CFG_CHAN_DB_ID_MASK | \
	(1 << BW_SCALE_CFG_ENABLED_SHIFT) & BW_SCALE_CFG_ENABLED_MASK | \
@@ -722,11 +722,7 @@ struct tsync_node {
};

struct mhi_timesync {
	u32 er_index;
	void __iomem *db;
	void __iomem *time_reg;
	enum MHI_EV_CCS ccs;
	struct completion completion;
	spinlock_t lock; /* list protection */
	struct list_head head;
};
@@ -837,11 +833,8 @@ void mhi_ring_chan_db(struct mhi_controller *mhi_cntrl,
int mhi_get_capability_offset(struct mhi_controller *mhi_cntrl, u32 capability,
			      u32 *offset);
void *mhi_to_virtual(struct mhi_ring *ring, dma_addr_t addr);
int mhi_init_timesync(struct mhi_controller *mhi_cntrl);
int mhi_init_sfr(struct mhi_controller *mhi_cntrl);
int mhi_create_timesync_sysfs(struct mhi_controller *mhi_cntrl);
void mhi_destroy_timesync(struct mhi_controller *mhi_cntrl);
int mhi_create_sysfs(struct mhi_controller *mhi_cntrl);
void mhi_create_sysfs(struct mhi_controller *mhi_cntrl);
void mhi_destroy_sysfs(struct mhi_controller *mhi_cntrl);
int mhi_early_notify_device(struct device *dev, void *data);
void mhi_write_reg_offload(struct mhi_controller *mhi_cntrl,
+29 −34
Original line number Diff line number Diff line
@@ -1170,7 +1170,6 @@ static void mhi_process_cmd_completion(struct mhi_controller *mhi_cntrl,
	struct mhi_ring *mhi_ring = &cmd_ring->ring;
	struct mhi_tre *cmd_pkt;
	struct mhi_chan *mhi_chan;
	struct mhi_timesync *mhi_tsync;
	struct mhi_sfr_info *sfr_info;
	enum mhi_cmd_type type;
	u32 chan;
@@ -1183,11 +1182,6 @@ static void mhi_process_cmd_completion(struct mhi_controller *mhi_cntrl,
	type = MHI_TRE_GET_CMD_TYPE(cmd_pkt);

	switch (type) {
	case MHI_CMD_TYPE_TSYNC:
		mhi_tsync = mhi_cntrl->mhi_tsync;
		mhi_tsync->ccs = MHI_TRE_GET_EV_CODE(tre);
		complete(&mhi_tsync->completion);
		break;
	case MHI_CMD_TYPE_SFR_CFG:
		sfr_info = mhi_cntrl->mhi_sfr;
		sfr_info->ccs = MHI_TRE_GET_EV_CODE(tre);
@@ -1412,7 +1406,7 @@ int mhi_process_tsync_event_ring(struct mhi_controller *mhi_cntrl,
		&mhi_cntrl->mhi_ctxt->er_ctxt[mhi_event->er_index];
	struct mhi_timesync *mhi_tsync = mhi_cntrl->mhi_tsync;
	int count = 0;
	u32 sequence;
	u32 sequence, unit;
	u64 remote_time;

	if (unlikely(MHI_EVENT_ACCESS_INVALID(mhi_cntrl->pm_state))) {
@@ -1435,19 +1429,20 @@ int mhi_process_tsync_event_ring(struct mhi_controller *mhi_cntrl,
		MHI_ASSERT(type != MHI_PKT_TYPE_TSYNC_EVENT, "!TSYNC event");

		sequence = MHI_TRE_GET_EV_TSYNC_SEQ(local_rp);
		unit = MHI_TRE_GET_EV_TSYNC_UNIT(local_rp);
		remote_time = MHI_TRE_GET_EV_TIME(local_rp);

		do {
			spin_lock_irq(&mhi_tsync->lock);
			spin_lock(&mhi_tsync->lock);
			tsync_node = list_first_entry_or_null(&mhi_tsync->head,
						      struct tsync_node, node);
			MHI_ASSERT(!tsync_node, "Unexpected Event");

			if (unlikely(!tsync_node))
			if (!tsync_node) {
				spin_unlock(&mhi_tsync->lock);
				break;
			}

			list_del(&tsync_node->node);
			spin_unlock_irq(&mhi_tsync->lock);
			spin_unlock(&mhi_tsync->lock);

			/*
			 * device may not able to process all time sync commands
@@ -1781,12 +1776,6 @@ int mhi_send_cmd(struct mhi_controller *mhi_cntrl,
		cmd_tre->dword[0] = MHI_TRE_CMD_STOP_DWORD0;
		cmd_tre->dword[1] = MHI_TRE_CMD_STOP_DWORD1(chan);
		break;
	case MHI_CMD_TIMSYNC_CFG:
		cmd_tre->ptr = MHI_TRE_CMD_TSYNC_CFG_PTR;
		cmd_tre->dword[0] = MHI_TRE_CMD_TSYNC_CFG_DWORD0;
		cmd_tre->dword[1] = MHI_TRE_CMD_TSYNC_CFG_DWORD1
			(mhi_cntrl->mhi_tsync->er_index);
		break;
	case MHI_CMD_SFR_CFG:
		sfr_info = mhi_cntrl->mhi_sfr;
		cmd_tre->ptr = MHI_TRE_CMD_SFR_CFG_PTR
@@ -2552,13 +2541,23 @@ int mhi_get_remote_time(struct mhi_device *mhi_dev,
	mutex_lock(&mhi_cntrl->tsync_mutex);
	if (!mhi_tsync) {
		ret = -EIO;
		goto err_unlock;
		goto error_unlock;
	}

	/* tsync db can only be rung in M0 state */
	ret = __mhi_device_get_sync(mhi_cntrl);
	if (ret)
		goto err_unlock;
		goto error_unlock;

	read_lock_bh(&mhi_cntrl->pm_lock);
	if (unlikely(MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state))) {
		MHI_ERR("MHI is not in active state, pm_state:%s\n",
			to_mhi_pm_state_str(mhi_cntrl->pm_state));
		ret = -EIO;
		read_unlock_bh(&mhi_cntrl->pm_lock);
		goto error_no_mem;
	}
	read_unlock_bh(&mhi_cntrl->pm_lock);

	/*
	 * technically we can use GFP_KERNEL, but wants to avoid
@@ -2575,19 +2574,16 @@ int mhi_get_remote_time(struct mhi_device *mhi_dev,
	tsync_node->mhi_dev = mhi_dev;

	/* disable link level low power modes */
	mhi_cntrl->lpm_disable(mhi_cntrl, mhi_cntrl->priv_data);

	read_lock_bh(&mhi_cntrl->pm_lock);
	if (unlikely(MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state))) {
		MHI_ERR("MHI is not in active state, pm_state:%s\n",
			to_mhi_pm_state_str(mhi_cntrl->pm_state));
		ret = -EIO;
	ret = mhi_cntrl->lpm_disable(mhi_cntrl, mhi_cntrl->priv_data);
	if (ret) {
		MHI_ERR("LPM disable request failed for %s!\n",
			mhi_dev->chan_name);
		goto error_invalid_state;
	}

	spin_lock_irq(&mhi_tsync->lock);
	spin_lock(&mhi_tsync->lock);
	list_add_tail(&tsync_node->node, &mhi_tsync->head);
	spin_unlock_irq(&mhi_tsync->lock);
	spin_unlock(&mhi_tsync->lock);

	/*
	 * time critical code, delay between these two steps should be
@@ -2598,26 +2594,25 @@ int mhi_get_remote_time(struct mhi_device *mhi_dev,

	tsync_node->local_time =
		mhi_cntrl->time_get(mhi_cntrl, mhi_cntrl->priv_data);
	writel_relaxed_no_log(tsync_node->sequence, mhi_tsync->db);
	writel_relaxed_no_log(tsync_node->sequence, mhi_cntrl->tsync_db);
	/* write must go thru immediately */
	wmb();

	local_irq_enable();
	preempt_enable();

	mhi_cntrl->lpm_enable(mhi_cntrl, mhi_cntrl->priv_data);

	ret = 0;

error_invalid_state:
	if (ret)
		kfree(tsync_node);
	read_unlock_bh(&mhi_cntrl->pm_lock);
	mhi_cntrl->lpm_enable(mhi_cntrl, mhi_cntrl->priv_data);

error_no_mem:
	read_lock_bh(&mhi_cntrl->pm_lock);
	mhi_cntrl->wake_put(mhi_cntrl, false);
	read_unlock_bh(&mhi_cntrl->pm_lock);
err_unlock:
error_unlock:
	mutex_unlock(&mhi_cntrl->tsync_mutex);
	return ret;
}
+1 −5
Original line number Diff line number Diff line
@@ -520,9 +520,8 @@ static int mhi_pm_mission_mode_transition(struct mhi_controller *mhi_cntrl)

	read_unlock_bh(&mhi_cntrl->pm_lock);

	/* setup support for additional features (SFR, timesync, etc.) */
	/* setup support for additional features */
	mhi_init_sfr(mhi_cntrl);
	mhi_init_timesync(mhi_cntrl);

	if (MHI_REG_ACCESS_VALID(mhi_cntrl->pm_state))
		mhi_timesync_log(mhi_cntrl);
@@ -657,9 +656,6 @@ static void mhi_pm_disable_transition(struct mhi_controller *mhi_cntrl,
		sfr_info->buf_addr = NULL;
	}

	/* remove support for time sync */
	mhi_destroy_timesync(mhi_cntrl);

	mutex_lock(&mhi_cntrl->pm_mutex);

	MHI_ASSERT(atomic_read(&mhi_cntrl->dev_wake), "dev_wake != 0");
+18 −0
Original line number Diff line number Diff line
@@ -263,6 +263,7 @@ struct mhi_controller {
	void __iomem *bhi;
	void __iomem *bhie;
	void __iomem *wake_db;
	void __iomem *tsync_db;
	void __iomem *bw_scale_db;

	/* device topology */
@@ -775,6 +776,23 @@ int mhi_force_rddm_mode(struct mhi_controller *mhi_cntrl);
 */
void mhi_dump_sfr(struct mhi_controller *mhi_cntrl);

/**
 * mhi_get_remote_time - Get external modem time relative to host time
 * Trigger event to capture modem time, also capture host time so client
 * can do a relative drift comparision.
 * Recommended only tsync device calls this method and do not call this
 * from atomic context
 * @mhi_dev: Device associated with the channels
 * @sequence:unique sequence id track event
 * @cb_func: callback function to call back
 */
int mhi_get_remote_time(struct mhi_device *mhi_dev,
			u32 sequence,
			void (*cb_func)(struct mhi_device *mhi_dev,
					u32 sequence,
					u64 local_time,
					u64 remote_time));

/**
 * mhi_get_remote_time_sync - Get external soc time relative to local soc time
 * using MMIO method.