162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Qualcomm Peripheral Image Loader for Q6V5
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2016-2018 Linaro Ltd.
662306a36Sopenharmony_ci * Copyright (C) 2014 Sony Mobile Communications AB
762306a36Sopenharmony_ci * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci#include <linux/kernel.h>
1062306a36Sopenharmony_ci#include <linux/platform_device.h>
1162306a36Sopenharmony_ci#include <linux/interconnect.h>
1262306a36Sopenharmony_ci#include <linux/interrupt.h>
1362306a36Sopenharmony_ci#include <linux/module.h>
1462306a36Sopenharmony_ci#include <linux/soc/qcom/qcom_aoss.h>
1562306a36Sopenharmony_ci#include <linux/soc/qcom/smem.h>
1662306a36Sopenharmony_ci#include <linux/soc/qcom/smem_state.h>
1762306a36Sopenharmony_ci#include <linux/remoteproc.h>
1862306a36Sopenharmony_ci#include "qcom_common.h"
1962306a36Sopenharmony_ci#include "qcom_q6v5.h"
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci#define Q6V5_LOAD_STATE_MSG_LEN	64
2262306a36Sopenharmony_ci#define Q6V5_PANIC_DELAY_MS	200
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_cistatic int q6v5_load_state_toggle(struct qcom_q6v5 *q6v5, bool enable)
2562306a36Sopenharmony_ci{
2662306a36Sopenharmony_ci	int ret;
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci	if (!q6v5->qmp)
2962306a36Sopenharmony_ci		return 0;
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci	ret = qmp_send(q6v5->qmp, "{class: image, res: load_state, name: %s, val: %s}",
3262306a36Sopenharmony_ci		       q6v5->load_state, enable ? "on" : "off");
3362306a36Sopenharmony_ci	if (ret)
3462306a36Sopenharmony_ci		dev_err(q6v5->dev, "failed to toggle load state\n");
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci	return ret;
3762306a36Sopenharmony_ci}
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci/**
4062306a36Sopenharmony_ci * qcom_q6v5_prepare() - reinitialize the qcom_q6v5 context before start
4162306a36Sopenharmony_ci * @q6v5:	reference to qcom_q6v5 context to be reinitialized
4262306a36Sopenharmony_ci *
4362306a36Sopenharmony_ci * Return: 0 on success, negative errno on failure
4462306a36Sopenharmony_ci */
4562306a36Sopenharmony_ciint qcom_q6v5_prepare(struct qcom_q6v5 *q6v5)
4662306a36Sopenharmony_ci{
4762306a36Sopenharmony_ci	int ret;
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci	ret = icc_set_bw(q6v5->path, 0, UINT_MAX);
5062306a36Sopenharmony_ci	if (ret < 0) {
5162306a36Sopenharmony_ci		dev_err(q6v5->dev, "failed to set bandwidth request\n");
5262306a36Sopenharmony_ci		return ret;
5362306a36Sopenharmony_ci	}
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci	ret = q6v5_load_state_toggle(q6v5, true);
5662306a36Sopenharmony_ci	if (ret) {
5762306a36Sopenharmony_ci		icc_set_bw(q6v5->path, 0, 0);
5862306a36Sopenharmony_ci		return ret;
5962306a36Sopenharmony_ci	}
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci	reinit_completion(&q6v5->start_done);
6262306a36Sopenharmony_ci	reinit_completion(&q6v5->stop_done);
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci	q6v5->running = true;
6562306a36Sopenharmony_ci	q6v5->handover_issued = false;
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci	enable_irq(q6v5->handover_irq);
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci	return 0;
7062306a36Sopenharmony_ci}
7162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(qcom_q6v5_prepare);
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci/**
7462306a36Sopenharmony_ci * qcom_q6v5_unprepare() - unprepare the qcom_q6v5 context after stop
7562306a36Sopenharmony_ci * @q6v5:	reference to qcom_q6v5 context to be unprepared
7662306a36Sopenharmony_ci *
7762306a36Sopenharmony_ci * Return: 0 on success, 1 if handover hasn't yet been called
7862306a36Sopenharmony_ci */
7962306a36Sopenharmony_ciint qcom_q6v5_unprepare(struct qcom_q6v5 *q6v5)
8062306a36Sopenharmony_ci{
8162306a36Sopenharmony_ci	disable_irq(q6v5->handover_irq);
8262306a36Sopenharmony_ci	q6v5_load_state_toggle(q6v5, false);
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci	/* Disable interconnect vote, in case handover never happened */
8562306a36Sopenharmony_ci	icc_set_bw(q6v5->path, 0, 0);
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci	return !q6v5->handover_issued;
8862306a36Sopenharmony_ci}
8962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(qcom_q6v5_unprepare);
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_cistatic irqreturn_t q6v5_wdog_interrupt(int irq, void *data)
9262306a36Sopenharmony_ci{
9362306a36Sopenharmony_ci	struct qcom_q6v5 *q6v5 = data;
9462306a36Sopenharmony_ci	size_t len;
9562306a36Sopenharmony_ci	char *msg;
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci	/* Sometimes the stop triggers a watchdog rather than a stop-ack */
9862306a36Sopenharmony_ci	if (!q6v5->running) {
9962306a36Sopenharmony_ci		complete(&q6v5->stop_done);
10062306a36Sopenharmony_ci		return IRQ_HANDLED;
10162306a36Sopenharmony_ci	}
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci	msg = qcom_smem_get(QCOM_SMEM_HOST_ANY, q6v5->crash_reason, &len);
10462306a36Sopenharmony_ci	if (!IS_ERR(msg) && len > 0 && msg[0])
10562306a36Sopenharmony_ci		dev_err(q6v5->dev, "watchdog received: %s\n", msg);
10662306a36Sopenharmony_ci	else
10762306a36Sopenharmony_ci		dev_err(q6v5->dev, "watchdog without message\n");
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	q6v5->running = false;
11062306a36Sopenharmony_ci	rproc_report_crash(q6v5->rproc, RPROC_WATCHDOG);
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci	return IRQ_HANDLED;
11362306a36Sopenharmony_ci}
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_cistatic irqreturn_t q6v5_fatal_interrupt(int irq, void *data)
11662306a36Sopenharmony_ci{
11762306a36Sopenharmony_ci	struct qcom_q6v5 *q6v5 = data;
11862306a36Sopenharmony_ci	size_t len;
11962306a36Sopenharmony_ci	char *msg;
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci	if (!q6v5->running)
12262306a36Sopenharmony_ci		return IRQ_HANDLED;
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci	msg = qcom_smem_get(QCOM_SMEM_HOST_ANY, q6v5->crash_reason, &len);
12562306a36Sopenharmony_ci	if (!IS_ERR(msg) && len > 0 && msg[0])
12662306a36Sopenharmony_ci		dev_err(q6v5->dev, "fatal error received: %s\n", msg);
12762306a36Sopenharmony_ci	else
12862306a36Sopenharmony_ci		dev_err(q6v5->dev, "fatal error without message\n");
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci	q6v5->running = false;
13162306a36Sopenharmony_ci	rproc_report_crash(q6v5->rproc, RPROC_FATAL_ERROR);
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci	return IRQ_HANDLED;
13462306a36Sopenharmony_ci}
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_cistatic irqreturn_t q6v5_ready_interrupt(int irq, void *data)
13762306a36Sopenharmony_ci{
13862306a36Sopenharmony_ci	struct qcom_q6v5 *q6v5 = data;
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci	complete(&q6v5->start_done);
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci	return IRQ_HANDLED;
14362306a36Sopenharmony_ci}
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci/**
14662306a36Sopenharmony_ci * qcom_q6v5_wait_for_start() - wait for remote processor start signal
14762306a36Sopenharmony_ci * @q6v5:	reference to qcom_q6v5 context
14862306a36Sopenharmony_ci * @timeout:	timeout to wait for the event, in jiffies
14962306a36Sopenharmony_ci *
15062306a36Sopenharmony_ci * qcom_q6v5_unprepare() should not be called when this function fails.
15162306a36Sopenharmony_ci *
15262306a36Sopenharmony_ci * Return: 0 on success, -ETIMEDOUT on timeout
15362306a36Sopenharmony_ci */
15462306a36Sopenharmony_ciint qcom_q6v5_wait_for_start(struct qcom_q6v5 *q6v5, int timeout)
15562306a36Sopenharmony_ci{
15662306a36Sopenharmony_ci	int ret;
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci	ret = wait_for_completion_timeout(&q6v5->start_done, timeout);
15962306a36Sopenharmony_ci	if (!ret)
16062306a36Sopenharmony_ci		disable_irq(q6v5->handover_irq);
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	return !ret ? -ETIMEDOUT : 0;
16362306a36Sopenharmony_ci}
16462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(qcom_q6v5_wait_for_start);
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_cistatic irqreturn_t q6v5_handover_interrupt(int irq, void *data)
16762306a36Sopenharmony_ci{
16862306a36Sopenharmony_ci	struct qcom_q6v5 *q6v5 = data;
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci	if (q6v5->handover)
17162306a36Sopenharmony_ci		q6v5->handover(q6v5);
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	icc_set_bw(q6v5->path, 0, 0);
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	q6v5->handover_issued = true;
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci	return IRQ_HANDLED;
17862306a36Sopenharmony_ci}
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_cistatic irqreturn_t q6v5_stop_interrupt(int irq, void *data)
18162306a36Sopenharmony_ci{
18262306a36Sopenharmony_ci	struct qcom_q6v5 *q6v5 = data;
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	complete(&q6v5->stop_done);
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci	return IRQ_HANDLED;
18762306a36Sopenharmony_ci}
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci/**
19062306a36Sopenharmony_ci * qcom_q6v5_request_stop() - request the remote processor to stop
19162306a36Sopenharmony_ci * @q6v5:	reference to qcom_q6v5 context
19262306a36Sopenharmony_ci * @sysmon:	reference to the remote's sysmon instance, or NULL
19362306a36Sopenharmony_ci *
19462306a36Sopenharmony_ci * Return: 0 on success, negative errno on failure
19562306a36Sopenharmony_ci */
19662306a36Sopenharmony_ciint qcom_q6v5_request_stop(struct qcom_q6v5 *q6v5, struct qcom_sysmon *sysmon)
19762306a36Sopenharmony_ci{
19862306a36Sopenharmony_ci	int ret;
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci	q6v5->running = false;
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci	/* Don't perform SMP2P dance if remote isn't running */
20362306a36Sopenharmony_ci	if (q6v5->rproc->state != RPROC_RUNNING || qcom_sysmon_shutdown_acked(sysmon))
20462306a36Sopenharmony_ci		return 0;
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	qcom_smem_state_update_bits(q6v5->state,
20762306a36Sopenharmony_ci				    BIT(q6v5->stop_bit), BIT(q6v5->stop_bit));
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci	ret = wait_for_completion_timeout(&q6v5->stop_done, 5 * HZ);
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci	qcom_smem_state_update_bits(q6v5->state, BIT(q6v5->stop_bit), 0);
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci	return ret == 0 ? -ETIMEDOUT : 0;
21462306a36Sopenharmony_ci}
21562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(qcom_q6v5_request_stop);
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci/**
21862306a36Sopenharmony_ci * qcom_q6v5_panic() - panic handler to invoke a stop on the remote
21962306a36Sopenharmony_ci * @q6v5:	reference to qcom_q6v5 context
22062306a36Sopenharmony_ci *
22162306a36Sopenharmony_ci * Set the stop bit and sleep in order to allow the remote processor to flush
22262306a36Sopenharmony_ci * its caches etc for post mortem debugging.
22362306a36Sopenharmony_ci *
22462306a36Sopenharmony_ci * Return: 200ms
22562306a36Sopenharmony_ci */
22662306a36Sopenharmony_ciunsigned long qcom_q6v5_panic(struct qcom_q6v5 *q6v5)
22762306a36Sopenharmony_ci{
22862306a36Sopenharmony_ci	qcom_smem_state_update_bits(q6v5->state,
22962306a36Sopenharmony_ci				    BIT(q6v5->stop_bit), BIT(q6v5->stop_bit));
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci	return Q6V5_PANIC_DELAY_MS;
23262306a36Sopenharmony_ci}
23362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(qcom_q6v5_panic);
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci/**
23662306a36Sopenharmony_ci * qcom_q6v5_init() - initializer of the q6v5 common struct
23762306a36Sopenharmony_ci * @q6v5:	handle to be initialized
23862306a36Sopenharmony_ci * @pdev:	platform_device reference for acquiring resources
23962306a36Sopenharmony_ci * @rproc:	associated remoteproc instance
24062306a36Sopenharmony_ci * @crash_reason: SMEM id for crash reason string, or 0 if none
24162306a36Sopenharmony_ci * @load_state: load state resource string
24262306a36Sopenharmony_ci * @handover:	function to be called when proxy resources should be released
24362306a36Sopenharmony_ci *
24462306a36Sopenharmony_ci * Return: 0 on success, negative errno on failure
24562306a36Sopenharmony_ci */
24662306a36Sopenharmony_ciint qcom_q6v5_init(struct qcom_q6v5 *q6v5, struct platform_device *pdev,
24762306a36Sopenharmony_ci		   struct rproc *rproc, int crash_reason, const char *load_state,
24862306a36Sopenharmony_ci		   void (*handover)(struct qcom_q6v5 *q6v5))
24962306a36Sopenharmony_ci{
25062306a36Sopenharmony_ci	int ret;
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci	q6v5->rproc = rproc;
25362306a36Sopenharmony_ci	q6v5->dev = &pdev->dev;
25462306a36Sopenharmony_ci	q6v5->crash_reason = crash_reason;
25562306a36Sopenharmony_ci	q6v5->handover = handover;
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci	init_completion(&q6v5->start_done);
25862306a36Sopenharmony_ci	init_completion(&q6v5->stop_done);
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci	q6v5->wdog_irq = platform_get_irq_byname(pdev, "wdog");
26162306a36Sopenharmony_ci	if (q6v5->wdog_irq < 0)
26262306a36Sopenharmony_ci		return q6v5->wdog_irq;
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci	ret = devm_request_threaded_irq(&pdev->dev, q6v5->wdog_irq,
26562306a36Sopenharmony_ci					NULL, q6v5_wdog_interrupt,
26662306a36Sopenharmony_ci					IRQF_TRIGGER_RISING | IRQF_ONESHOT,
26762306a36Sopenharmony_ci					"q6v5 wdog", q6v5);
26862306a36Sopenharmony_ci	if (ret) {
26962306a36Sopenharmony_ci		dev_err(&pdev->dev, "failed to acquire wdog IRQ\n");
27062306a36Sopenharmony_ci		return ret;
27162306a36Sopenharmony_ci	}
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci	q6v5->fatal_irq = platform_get_irq_byname(pdev, "fatal");
27462306a36Sopenharmony_ci	if (q6v5->fatal_irq < 0)
27562306a36Sopenharmony_ci		return q6v5->fatal_irq;
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci	ret = devm_request_threaded_irq(&pdev->dev, q6v5->fatal_irq,
27862306a36Sopenharmony_ci					NULL, q6v5_fatal_interrupt,
27962306a36Sopenharmony_ci					IRQF_TRIGGER_RISING | IRQF_ONESHOT,
28062306a36Sopenharmony_ci					"q6v5 fatal", q6v5);
28162306a36Sopenharmony_ci	if (ret) {
28262306a36Sopenharmony_ci		dev_err(&pdev->dev, "failed to acquire fatal IRQ\n");
28362306a36Sopenharmony_ci		return ret;
28462306a36Sopenharmony_ci	}
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci	q6v5->ready_irq = platform_get_irq_byname(pdev, "ready");
28762306a36Sopenharmony_ci	if (q6v5->ready_irq < 0)
28862306a36Sopenharmony_ci		return q6v5->ready_irq;
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci	ret = devm_request_threaded_irq(&pdev->dev, q6v5->ready_irq,
29162306a36Sopenharmony_ci					NULL, q6v5_ready_interrupt,
29262306a36Sopenharmony_ci					IRQF_TRIGGER_RISING | IRQF_ONESHOT,
29362306a36Sopenharmony_ci					"q6v5 ready", q6v5);
29462306a36Sopenharmony_ci	if (ret) {
29562306a36Sopenharmony_ci		dev_err(&pdev->dev, "failed to acquire ready IRQ\n");
29662306a36Sopenharmony_ci		return ret;
29762306a36Sopenharmony_ci	}
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci	q6v5->handover_irq = platform_get_irq_byname(pdev, "handover");
30062306a36Sopenharmony_ci	if (q6v5->handover_irq < 0)
30162306a36Sopenharmony_ci		return q6v5->handover_irq;
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci	ret = devm_request_threaded_irq(&pdev->dev, q6v5->handover_irq,
30462306a36Sopenharmony_ci					NULL, q6v5_handover_interrupt,
30562306a36Sopenharmony_ci					IRQF_TRIGGER_RISING | IRQF_ONESHOT,
30662306a36Sopenharmony_ci					"q6v5 handover", q6v5);
30762306a36Sopenharmony_ci	if (ret) {
30862306a36Sopenharmony_ci		dev_err(&pdev->dev, "failed to acquire handover IRQ\n");
30962306a36Sopenharmony_ci		return ret;
31062306a36Sopenharmony_ci	}
31162306a36Sopenharmony_ci	disable_irq(q6v5->handover_irq);
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci	q6v5->stop_irq = platform_get_irq_byname(pdev, "stop-ack");
31462306a36Sopenharmony_ci	if (q6v5->stop_irq < 0)
31562306a36Sopenharmony_ci		return q6v5->stop_irq;
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci	ret = devm_request_threaded_irq(&pdev->dev, q6v5->stop_irq,
31862306a36Sopenharmony_ci					NULL, q6v5_stop_interrupt,
31962306a36Sopenharmony_ci					IRQF_TRIGGER_RISING | IRQF_ONESHOT,
32062306a36Sopenharmony_ci					"q6v5 stop", q6v5);
32162306a36Sopenharmony_ci	if (ret) {
32262306a36Sopenharmony_ci		dev_err(&pdev->dev, "failed to acquire stop-ack IRQ\n");
32362306a36Sopenharmony_ci		return ret;
32462306a36Sopenharmony_ci	}
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci	q6v5->state = devm_qcom_smem_state_get(&pdev->dev, "stop", &q6v5->stop_bit);
32762306a36Sopenharmony_ci	if (IS_ERR(q6v5->state)) {
32862306a36Sopenharmony_ci		dev_err(&pdev->dev, "failed to acquire stop state\n");
32962306a36Sopenharmony_ci		return PTR_ERR(q6v5->state);
33062306a36Sopenharmony_ci	}
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	q6v5->load_state = devm_kstrdup_const(&pdev->dev, load_state, GFP_KERNEL);
33362306a36Sopenharmony_ci	q6v5->qmp = qmp_get(&pdev->dev);
33462306a36Sopenharmony_ci	if (IS_ERR(q6v5->qmp)) {
33562306a36Sopenharmony_ci		if (PTR_ERR(q6v5->qmp) != -ENODEV)
33662306a36Sopenharmony_ci			return dev_err_probe(&pdev->dev, PTR_ERR(q6v5->qmp),
33762306a36Sopenharmony_ci					     "failed to acquire load state\n");
33862306a36Sopenharmony_ci		q6v5->qmp = NULL;
33962306a36Sopenharmony_ci	} else if (!q6v5->load_state) {
34062306a36Sopenharmony_ci		if (!load_state)
34162306a36Sopenharmony_ci			dev_err(&pdev->dev, "load state resource string empty\n");
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci		qmp_put(q6v5->qmp);
34462306a36Sopenharmony_ci		return load_state ? -ENOMEM : -EINVAL;
34562306a36Sopenharmony_ci	}
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci	q6v5->path = devm_of_icc_get(&pdev->dev, NULL);
34862306a36Sopenharmony_ci	if (IS_ERR(q6v5->path))
34962306a36Sopenharmony_ci		return dev_err_probe(&pdev->dev, PTR_ERR(q6v5->path),
35062306a36Sopenharmony_ci				     "failed to acquire interconnect path\n");
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ci	return 0;
35362306a36Sopenharmony_ci}
35462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(qcom_q6v5_init);
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci/**
35762306a36Sopenharmony_ci * qcom_q6v5_deinit() - deinitialize the q6v5 common struct
35862306a36Sopenharmony_ci * @q6v5:	reference to qcom_q6v5 context to be deinitialized
35962306a36Sopenharmony_ci */
36062306a36Sopenharmony_civoid qcom_q6v5_deinit(struct qcom_q6v5 *q6v5)
36162306a36Sopenharmony_ci{
36262306a36Sopenharmony_ci	qmp_put(q6v5->qmp);
36362306a36Sopenharmony_ci}
36462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(qcom_q6v5_deinit);
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
36762306a36Sopenharmony_ciMODULE_DESCRIPTION("Qualcomm Peripheral Image Loader for Q6V5");
368