xref: /openbmc/linux/drivers/remoteproc/qcom_q6v5.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
13b415c8fSBjorn Andersson // SPDX-License-Identifier: GPL-2.0
23b415c8fSBjorn Andersson /*
33b415c8fSBjorn Andersson  * Qualcomm Peripheral Image Loader for Q6V5
43b415c8fSBjorn Andersson  *
53b415c8fSBjorn Andersson  * Copyright (C) 2016-2018 Linaro Ltd.
63b415c8fSBjorn Andersson  * Copyright (C) 2014 Sony Mobile Communications AB
73b415c8fSBjorn Andersson  * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
83b415c8fSBjorn Andersson  */
93b415c8fSBjorn Andersson #include <linux/kernel.h>
103b415c8fSBjorn Andersson #include <linux/platform_device.h>
118d9be5c6SBjorn Andersson #include <linux/interconnect.h>
123b415c8fSBjorn Andersson #include <linux/interrupt.h>
13ded79d06SArnd Bergmann #include <linux/module.h>
14eee412e9SRandy Dunlap #include <linux/soc/qcom/qcom_aoss.h>
153b415c8fSBjorn Andersson #include <linux/soc/qcom/smem.h>
163b415c8fSBjorn Andersson #include <linux/soc/qcom/smem_state.h>
173b415c8fSBjorn Andersson #include <linux/remoteproc.h>
18ed5da808SBjorn Andersson #include "qcom_common.h"
193b415c8fSBjorn Andersson #include "qcom_q6v5.h"
203b415c8fSBjorn Andersson 
21c1fe10d2SSibi Sankar #define Q6V5_LOAD_STATE_MSG_LEN	64
22e9142f5cSBjorn Andersson #define Q6V5_PANIC_DELAY_MS	200
23e9142f5cSBjorn Andersson 
q6v5_load_state_toggle(struct qcom_q6v5 * q6v5,bool enable)24c1fe10d2SSibi Sankar static int q6v5_load_state_toggle(struct qcom_q6v5 *q6v5, bool enable)
25c1fe10d2SSibi Sankar {
26c1fe10d2SSibi Sankar 	int ret;
27c1fe10d2SSibi Sankar 
28c1fe10d2SSibi Sankar 	if (!q6v5->qmp)
29c1fe10d2SSibi Sankar 		return 0;
30c1fe10d2SSibi Sankar 
31*b4f63bbfSBjorn Andersson 	ret = qmp_send(q6v5->qmp, "{class: image, res: load_state, name: %s, val: %s}",
32c1fe10d2SSibi Sankar 		       q6v5->load_state, enable ? "on" : "off");
33c1fe10d2SSibi Sankar 	if (ret)
34c1fe10d2SSibi Sankar 		dev_err(q6v5->dev, "failed to toggle load state\n");
35c1fe10d2SSibi Sankar 
36c1fe10d2SSibi Sankar 	return ret;
37c1fe10d2SSibi Sankar }
38c1fe10d2SSibi Sankar 
393b415c8fSBjorn Andersson /**
403b415c8fSBjorn Andersson  * qcom_q6v5_prepare() - reinitialize the qcom_q6v5 context before start
413b415c8fSBjorn Andersson  * @q6v5:	reference to qcom_q6v5 context to be reinitialized
423b415c8fSBjorn Andersson  *
433b415c8fSBjorn Andersson  * Return: 0 on success, negative errno on failure
443b415c8fSBjorn Andersson  */
qcom_q6v5_prepare(struct qcom_q6v5 * q6v5)453b415c8fSBjorn Andersson int qcom_q6v5_prepare(struct qcom_q6v5 *q6v5)
463b415c8fSBjorn Andersson {
47c1fe10d2SSibi Sankar 	int ret;
48c1fe10d2SSibi Sankar 
498d9be5c6SBjorn Andersson 	ret = icc_set_bw(q6v5->path, 0, UINT_MAX);
508d9be5c6SBjorn Andersson 	if (ret < 0) {
518d9be5c6SBjorn Andersson 		dev_err(q6v5->dev, "failed to set bandwidth request\n");
52c1fe10d2SSibi Sankar 		return ret;
538d9be5c6SBjorn Andersson 	}
548d9be5c6SBjorn Andersson 
558d9be5c6SBjorn Andersson 	ret = q6v5_load_state_toggle(q6v5, true);
568d9be5c6SBjorn Andersson 	if (ret) {
578d9be5c6SBjorn Andersson 		icc_set_bw(q6v5->path, 0, 0);
588d9be5c6SBjorn Andersson 		return ret;
598d9be5c6SBjorn Andersson 	}
60c1fe10d2SSibi Sankar 
613b415c8fSBjorn Andersson 	reinit_completion(&q6v5->start_done);
623b415c8fSBjorn Andersson 	reinit_completion(&q6v5->stop_done);
633b415c8fSBjorn Andersson 
643b415c8fSBjorn Andersson 	q6v5->running = true;
653b415c8fSBjorn Andersson 	q6v5->handover_issued = false;
663b415c8fSBjorn Andersson 
673b415c8fSBjorn Andersson 	enable_irq(q6v5->handover_irq);
683b415c8fSBjorn Andersson 
693b415c8fSBjorn Andersson 	return 0;
703b415c8fSBjorn Andersson }
71ded79d06SArnd Bergmann EXPORT_SYMBOL_GPL(qcom_q6v5_prepare);
723b415c8fSBjorn Andersson 
733b415c8fSBjorn Andersson /**
743b415c8fSBjorn Andersson  * qcom_q6v5_unprepare() - unprepare the qcom_q6v5 context after stop
753b415c8fSBjorn Andersson  * @q6v5:	reference to qcom_q6v5 context to be unprepared
763b415c8fSBjorn Andersson  *
773b415c8fSBjorn Andersson  * Return: 0 on success, 1 if handover hasn't yet been called
783b415c8fSBjorn Andersson  */
qcom_q6v5_unprepare(struct qcom_q6v5 * q6v5)793b415c8fSBjorn Andersson int qcom_q6v5_unprepare(struct qcom_q6v5 *q6v5)
803b415c8fSBjorn Andersson {
813b415c8fSBjorn Andersson 	disable_irq(q6v5->handover_irq);
82c1fe10d2SSibi Sankar 	q6v5_load_state_toggle(q6v5, false);
833b415c8fSBjorn Andersson 
848d9be5c6SBjorn Andersson 	/* Disable interconnect vote, in case handover never happened */
858d9be5c6SBjorn Andersson 	icc_set_bw(q6v5->path, 0, 0);
868d9be5c6SBjorn Andersson 
873b415c8fSBjorn Andersson 	return !q6v5->handover_issued;
883b415c8fSBjorn Andersson }
89ded79d06SArnd Bergmann EXPORT_SYMBOL_GPL(qcom_q6v5_unprepare);
903b415c8fSBjorn Andersson 
q6v5_wdog_interrupt(int irq,void * data)913b415c8fSBjorn Andersson static irqreturn_t q6v5_wdog_interrupt(int irq, void *data)
923b415c8fSBjorn Andersson {
933b415c8fSBjorn Andersson 	struct qcom_q6v5 *q6v5 = data;
943b415c8fSBjorn Andersson 	size_t len;
953b415c8fSBjorn Andersson 	char *msg;
963b415c8fSBjorn Andersson 
973b415c8fSBjorn Andersson 	/* Sometimes the stop triggers a watchdog rather than a stop-ack */
983b415c8fSBjorn Andersson 	if (!q6v5->running) {
993b415c8fSBjorn Andersson 		complete(&q6v5->stop_done);
1003b415c8fSBjorn Andersson 		return IRQ_HANDLED;
1013b415c8fSBjorn Andersson 	}
1023b415c8fSBjorn Andersson 
1033b415c8fSBjorn Andersson 	msg = qcom_smem_get(QCOM_SMEM_HOST_ANY, q6v5->crash_reason, &len);
1043b415c8fSBjorn Andersson 	if (!IS_ERR(msg) && len > 0 && msg[0])
1053b415c8fSBjorn Andersson 		dev_err(q6v5->dev, "watchdog received: %s\n", msg);
1063b415c8fSBjorn Andersson 	else
1073b415c8fSBjorn Andersson 		dev_err(q6v5->dev, "watchdog without message\n");
1083b415c8fSBjorn Andersson 
1090ad7e3edSSiddharth Gupta 	q6v5->running = false;
1103b415c8fSBjorn Andersson 	rproc_report_crash(q6v5->rproc, RPROC_WATCHDOG);
1113b415c8fSBjorn Andersson 
1123b415c8fSBjorn Andersson 	return IRQ_HANDLED;
1133b415c8fSBjorn Andersson }
1143b415c8fSBjorn Andersson 
q6v5_fatal_interrupt(int irq,void * data)1153b415c8fSBjorn Andersson static irqreturn_t q6v5_fatal_interrupt(int irq, void *data)
1163b415c8fSBjorn Andersson {
1173b415c8fSBjorn Andersson 	struct qcom_q6v5 *q6v5 = data;
1183b415c8fSBjorn Andersson 	size_t len;
1193b415c8fSBjorn Andersson 	char *msg;
1203b415c8fSBjorn Andersson 
1210ad7e3edSSiddharth Gupta 	if (!q6v5->running)
1220ad7e3edSSiddharth Gupta 		return IRQ_HANDLED;
1230ad7e3edSSiddharth Gupta 
1243b415c8fSBjorn Andersson 	msg = qcom_smem_get(QCOM_SMEM_HOST_ANY, q6v5->crash_reason, &len);
1253b415c8fSBjorn Andersson 	if (!IS_ERR(msg) && len > 0 && msg[0])
1263b415c8fSBjorn Andersson 		dev_err(q6v5->dev, "fatal error received: %s\n", msg);
1273b415c8fSBjorn Andersson 	else
1283b415c8fSBjorn Andersson 		dev_err(q6v5->dev, "fatal error without message\n");
1293b415c8fSBjorn Andersson 
130d3ae96c0SSibi Sankar 	q6v5->running = false;
1313b415c8fSBjorn Andersson 	rproc_report_crash(q6v5->rproc, RPROC_FATAL_ERROR);
1323b415c8fSBjorn Andersson 
1333b415c8fSBjorn Andersson 	return IRQ_HANDLED;
1343b415c8fSBjorn Andersson }
1353b415c8fSBjorn Andersson 
q6v5_ready_interrupt(int irq,void * data)1363b415c8fSBjorn Andersson static irqreturn_t q6v5_ready_interrupt(int irq, void *data)
1373b415c8fSBjorn Andersson {
1383b415c8fSBjorn Andersson 	struct qcom_q6v5 *q6v5 = data;
1393b415c8fSBjorn Andersson 
1403b415c8fSBjorn Andersson 	complete(&q6v5->start_done);
1413b415c8fSBjorn Andersson 
1423b415c8fSBjorn Andersson 	return IRQ_HANDLED;
1433b415c8fSBjorn Andersson }
1443b415c8fSBjorn Andersson 
1453b415c8fSBjorn Andersson /**
1463b415c8fSBjorn Andersson  * qcom_q6v5_wait_for_start() - wait for remote processor start signal
1473b415c8fSBjorn Andersson  * @q6v5:	reference to qcom_q6v5 context
1483b415c8fSBjorn Andersson  * @timeout:	timeout to wait for the event, in jiffies
1493b415c8fSBjorn Andersson  *
1503b415c8fSBjorn Andersson  * qcom_q6v5_unprepare() should not be called when this function fails.
1513b415c8fSBjorn Andersson  *
1523b415c8fSBjorn Andersson  * Return: 0 on success, -ETIMEDOUT on timeout
1533b415c8fSBjorn Andersson  */
qcom_q6v5_wait_for_start(struct qcom_q6v5 * q6v5,int timeout)1543b415c8fSBjorn Andersson int qcom_q6v5_wait_for_start(struct qcom_q6v5 *q6v5, int timeout)
1553b415c8fSBjorn Andersson {
1563b415c8fSBjorn Andersson 	int ret;
1573b415c8fSBjorn Andersson 
1583b415c8fSBjorn Andersson 	ret = wait_for_completion_timeout(&q6v5->start_done, timeout);
1593b415c8fSBjorn Andersson 	if (!ret)
1603b415c8fSBjorn Andersson 		disable_irq(q6v5->handover_irq);
1613b415c8fSBjorn Andersson 
1623b415c8fSBjorn Andersson 	return !ret ? -ETIMEDOUT : 0;
1633b415c8fSBjorn Andersson }
164ded79d06SArnd Bergmann EXPORT_SYMBOL_GPL(qcom_q6v5_wait_for_start);
1653b415c8fSBjorn Andersson 
q6v5_handover_interrupt(int irq,void * data)1663b415c8fSBjorn Andersson static irqreturn_t q6v5_handover_interrupt(int irq, void *data)
1673b415c8fSBjorn Andersson {
1683b415c8fSBjorn Andersson 	struct qcom_q6v5 *q6v5 = data;
1693b415c8fSBjorn Andersson 
1703b415c8fSBjorn Andersson 	if (q6v5->handover)
1713b415c8fSBjorn Andersson 		q6v5->handover(q6v5);
1723b415c8fSBjorn Andersson 
1738d9be5c6SBjorn Andersson 	icc_set_bw(q6v5->path, 0, 0);
1748d9be5c6SBjorn Andersson 
1753b415c8fSBjorn Andersson 	q6v5->handover_issued = true;
1763b415c8fSBjorn Andersson 
1773b415c8fSBjorn Andersson 	return IRQ_HANDLED;
1783b415c8fSBjorn Andersson }
1793b415c8fSBjorn Andersson 
q6v5_stop_interrupt(int irq,void * data)1803b415c8fSBjorn Andersson static irqreturn_t q6v5_stop_interrupt(int irq, void *data)
1813b415c8fSBjorn Andersson {
1823b415c8fSBjorn Andersson 	struct qcom_q6v5 *q6v5 = data;
1833b415c8fSBjorn Andersson 
1843b415c8fSBjorn Andersson 	complete(&q6v5->stop_done);
1853b415c8fSBjorn Andersson 
1863b415c8fSBjorn Andersson 	return IRQ_HANDLED;
1873b415c8fSBjorn Andersson }
1883b415c8fSBjorn Andersson 
1893b415c8fSBjorn Andersson /**
1903b415c8fSBjorn Andersson  * qcom_q6v5_request_stop() - request the remote processor to stop
1913b415c8fSBjorn Andersson  * @q6v5:	reference to qcom_q6v5 context
192ed5da808SBjorn Andersson  * @sysmon:	reference to the remote's sysmon instance, or NULL
1933b415c8fSBjorn Andersson  *
1943b415c8fSBjorn Andersson  * Return: 0 on success, negative errno on failure
1953b415c8fSBjorn Andersson  */
qcom_q6v5_request_stop(struct qcom_q6v5 * q6v5,struct qcom_sysmon * sysmon)196ed5da808SBjorn Andersson int qcom_q6v5_request_stop(struct qcom_q6v5 *q6v5, struct qcom_sysmon *sysmon)
1973b415c8fSBjorn Andersson {
1983b415c8fSBjorn Andersson 	int ret;
1993b415c8fSBjorn Andersson 
2005b7be880SSibi Sankar 	q6v5->running = false;
2015b7be880SSibi Sankar 
2023cc889ebSGokul krishna Krishnakumar 	/* Don't perform SMP2P dance if remote isn't running */
2033cc889ebSGokul krishna Krishnakumar 	if (q6v5->rproc->state != RPROC_RUNNING || qcom_sysmon_shutdown_acked(sysmon))
204ed5da808SBjorn Andersson 		return 0;
205ed5da808SBjorn Andersson 
2063b415c8fSBjorn Andersson 	qcom_smem_state_update_bits(q6v5->state,
2073b415c8fSBjorn Andersson 				    BIT(q6v5->stop_bit), BIT(q6v5->stop_bit));
2083b415c8fSBjorn Andersson 
2093b415c8fSBjorn Andersson 	ret = wait_for_completion_timeout(&q6v5->stop_done, 5 * HZ);
2103b415c8fSBjorn Andersson 
2113b415c8fSBjorn Andersson 	qcom_smem_state_update_bits(q6v5->state, BIT(q6v5->stop_bit), 0);
2123b415c8fSBjorn Andersson 
2133b415c8fSBjorn Andersson 	return ret == 0 ? -ETIMEDOUT : 0;
2143b415c8fSBjorn Andersson }
215ded79d06SArnd Bergmann EXPORT_SYMBOL_GPL(qcom_q6v5_request_stop);
2163b415c8fSBjorn Andersson 
2173b415c8fSBjorn Andersson /**
218e9142f5cSBjorn Andersson  * qcom_q6v5_panic() - panic handler to invoke a stop on the remote
219e9142f5cSBjorn Andersson  * @q6v5:	reference to qcom_q6v5 context
220e9142f5cSBjorn Andersson  *
221e9142f5cSBjorn Andersson  * Set the stop bit and sleep in order to allow the remote processor to flush
222e9142f5cSBjorn Andersson  * its caches etc for post mortem debugging.
223e9142f5cSBjorn Andersson  *
224e9142f5cSBjorn Andersson  * Return: 200ms
225e9142f5cSBjorn Andersson  */
qcom_q6v5_panic(struct qcom_q6v5 * q6v5)226e9142f5cSBjorn Andersson unsigned long qcom_q6v5_panic(struct qcom_q6v5 *q6v5)
227e9142f5cSBjorn Andersson {
228e9142f5cSBjorn Andersson 	qcom_smem_state_update_bits(q6v5->state,
229e9142f5cSBjorn Andersson 				    BIT(q6v5->stop_bit), BIT(q6v5->stop_bit));
230e9142f5cSBjorn Andersson 
231e9142f5cSBjorn Andersson 	return Q6V5_PANIC_DELAY_MS;
232e9142f5cSBjorn Andersson }
233e9142f5cSBjorn Andersson EXPORT_SYMBOL_GPL(qcom_q6v5_panic);
234e9142f5cSBjorn Andersson 
235e9142f5cSBjorn Andersson /**
2363b415c8fSBjorn Andersson  * qcom_q6v5_init() - initializer of the q6v5 common struct
2373b415c8fSBjorn Andersson  * @q6v5:	handle to be initialized
2383b415c8fSBjorn Andersson  * @pdev:	platform_device reference for acquiring resources
2393b415c8fSBjorn Andersson  * @rproc:	associated remoteproc instance
2403b415c8fSBjorn Andersson  * @crash_reason: SMEM id for crash reason string, or 0 if none
241c1fe10d2SSibi Sankar  * @load_state: load state resource string
2423b415c8fSBjorn Andersson  * @handover:	function to be called when proxy resources should be released
2433b415c8fSBjorn Andersson  *
2443b415c8fSBjorn Andersson  * Return: 0 on success, negative errno on failure
2453b415c8fSBjorn Andersson  */
qcom_q6v5_init(struct qcom_q6v5 * q6v5,struct platform_device * pdev,struct rproc * rproc,int crash_reason,const char * load_state,void (* handover)(struct qcom_q6v5 * q6v5))2463b415c8fSBjorn Andersson int qcom_q6v5_init(struct qcom_q6v5 *q6v5, struct platform_device *pdev,
247c1fe10d2SSibi Sankar 		   struct rproc *rproc, int crash_reason, const char *load_state,
2483b415c8fSBjorn Andersson 		   void (*handover)(struct qcom_q6v5 *q6v5))
2493b415c8fSBjorn Andersson {
2503b415c8fSBjorn Andersson 	int ret;
2513b415c8fSBjorn Andersson 
2523b415c8fSBjorn Andersson 	q6v5->rproc = rproc;
2533b415c8fSBjorn Andersson 	q6v5->dev = &pdev->dev;
2543b415c8fSBjorn Andersson 	q6v5->crash_reason = crash_reason;
2553b415c8fSBjorn Andersson 	q6v5->handover = handover;
2563b415c8fSBjorn Andersson 
2573b415c8fSBjorn Andersson 	init_completion(&q6v5->start_done);
2583b415c8fSBjorn Andersson 	init_completion(&q6v5->stop_done);
2593b415c8fSBjorn Andersson 
2603b415c8fSBjorn Andersson 	q6v5->wdog_irq = platform_get_irq_byname(pdev, "wdog");
261d446609dSStephen Boyd 	if (q6v5->wdog_irq < 0)
2621e2517d1SBrian Norris 		return q6v5->wdog_irq;
2631e2517d1SBrian Norris 
2643b415c8fSBjorn Andersson 	ret = devm_request_threaded_irq(&pdev->dev, q6v5->wdog_irq,
2653b415c8fSBjorn Andersson 					NULL, q6v5_wdog_interrupt,
2663b415c8fSBjorn Andersson 					IRQF_TRIGGER_RISING | IRQF_ONESHOT,
2673b415c8fSBjorn Andersson 					"q6v5 wdog", q6v5);
2683b415c8fSBjorn Andersson 	if (ret) {
2693b415c8fSBjorn Andersson 		dev_err(&pdev->dev, "failed to acquire wdog IRQ\n");
2703b415c8fSBjorn Andersson 		return ret;
2713b415c8fSBjorn Andersson 	}
2723b415c8fSBjorn Andersson 
2733b415c8fSBjorn Andersson 	q6v5->fatal_irq = platform_get_irq_byname(pdev, "fatal");
274d446609dSStephen Boyd 	if (q6v5->fatal_irq < 0)
2751e2517d1SBrian Norris 		return q6v5->fatal_irq;
276d5269c45SBjorn Andersson 
2773b415c8fSBjorn Andersson 	ret = devm_request_threaded_irq(&pdev->dev, q6v5->fatal_irq,
2783b415c8fSBjorn Andersson 					NULL, q6v5_fatal_interrupt,
2793b415c8fSBjorn Andersson 					IRQF_TRIGGER_RISING | IRQF_ONESHOT,
2803b415c8fSBjorn Andersson 					"q6v5 fatal", q6v5);
2813b415c8fSBjorn Andersson 	if (ret) {
2823b415c8fSBjorn Andersson 		dev_err(&pdev->dev, "failed to acquire fatal IRQ\n");
2833b415c8fSBjorn Andersson 		return ret;
2843b415c8fSBjorn Andersson 	}
2853b415c8fSBjorn Andersson 
2863b415c8fSBjorn Andersson 	q6v5->ready_irq = platform_get_irq_byname(pdev, "ready");
287d446609dSStephen Boyd 	if (q6v5->ready_irq < 0)
2881e2517d1SBrian Norris 		return q6v5->ready_irq;
289d5269c45SBjorn Andersson 
2903b415c8fSBjorn Andersson 	ret = devm_request_threaded_irq(&pdev->dev, q6v5->ready_irq,
2913b415c8fSBjorn Andersson 					NULL, q6v5_ready_interrupt,
2923b415c8fSBjorn Andersson 					IRQF_TRIGGER_RISING | IRQF_ONESHOT,
2933b415c8fSBjorn Andersson 					"q6v5 ready", q6v5);
2943b415c8fSBjorn Andersson 	if (ret) {
2953b415c8fSBjorn Andersson 		dev_err(&pdev->dev, "failed to acquire ready IRQ\n");
2963b415c8fSBjorn Andersson 		return ret;
2973b415c8fSBjorn Andersson 	}
2983b415c8fSBjorn Andersson 
2993b415c8fSBjorn Andersson 	q6v5->handover_irq = platform_get_irq_byname(pdev, "handover");
300d446609dSStephen Boyd 	if (q6v5->handover_irq < 0)
3011e2517d1SBrian Norris 		return q6v5->handover_irq;
302d5269c45SBjorn Andersson 
3033b415c8fSBjorn Andersson 	ret = devm_request_threaded_irq(&pdev->dev, q6v5->handover_irq,
3043b415c8fSBjorn Andersson 					NULL, q6v5_handover_interrupt,
3053b415c8fSBjorn Andersson 					IRQF_TRIGGER_RISING | IRQF_ONESHOT,
3063b415c8fSBjorn Andersson 					"q6v5 handover", q6v5);
3073b415c8fSBjorn Andersson 	if (ret) {
3083b415c8fSBjorn Andersson 		dev_err(&pdev->dev, "failed to acquire handover IRQ\n");
3093b415c8fSBjorn Andersson 		return ret;
3103b415c8fSBjorn Andersson 	}
3113b415c8fSBjorn Andersson 	disable_irq(q6v5->handover_irq);
3123b415c8fSBjorn Andersson 
3133b415c8fSBjorn Andersson 	q6v5->stop_irq = platform_get_irq_byname(pdev, "stop-ack");
314d446609dSStephen Boyd 	if (q6v5->stop_irq < 0)
3151e2517d1SBrian Norris 		return q6v5->stop_irq;
316d5269c45SBjorn Andersson 
3173b415c8fSBjorn Andersson 	ret = devm_request_threaded_irq(&pdev->dev, q6v5->stop_irq,
3183b415c8fSBjorn Andersson 					NULL, q6v5_stop_interrupt,
3193b415c8fSBjorn Andersson 					IRQF_TRIGGER_RISING | IRQF_ONESHOT,
3203b415c8fSBjorn Andersson 					"q6v5 stop", q6v5);
3213b415c8fSBjorn Andersson 	if (ret) {
3223b415c8fSBjorn Andersson 		dev_err(&pdev->dev, "failed to acquire stop-ack IRQ\n");
3233b415c8fSBjorn Andersson 		return ret;
3243b415c8fSBjorn Andersson 	}
3253b415c8fSBjorn Andersson 
326632f1ca3SStephan Gerhold 	q6v5->state = devm_qcom_smem_state_get(&pdev->dev, "stop", &q6v5->stop_bit);
3273b415c8fSBjorn Andersson 	if (IS_ERR(q6v5->state)) {
3283b415c8fSBjorn Andersson 		dev_err(&pdev->dev, "failed to acquire stop state\n");
3293b415c8fSBjorn Andersson 		return PTR_ERR(q6v5->state);
3303b415c8fSBjorn Andersson 	}
3313b415c8fSBjorn Andersson 
332c1fe10d2SSibi Sankar 	q6v5->load_state = devm_kstrdup_const(&pdev->dev, load_state, GFP_KERNEL);
333c1fe10d2SSibi Sankar 	q6v5->qmp = qmp_get(&pdev->dev);
334c1fe10d2SSibi Sankar 	if (IS_ERR(q6v5->qmp)) {
335c1fe10d2SSibi Sankar 		if (PTR_ERR(q6v5->qmp) != -ENODEV)
336c1fe10d2SSibi Sankar 			return dev_err_probe(&pdev->dev, PTR_ERR(q6v5->qmp),
337c1fe10d2SSibi Sankar 					     "failed to acquire load state\n");
338c1fe10d2SSibi Sankar 		q6v5->qmp = NULL;
339c1fe10d2SSibi Sankar 	} else if (!q6v5->load_state) {
340c1fe10d2SSibi Sankar 		if (!load_state)
341c1fe10d2SSibi Sankar 			dev_err(&pdev->dev, "load state resource string empty\n");
342c1fe10d2SSibi Sankar 
343c1fe10d2SSibi Sankar 		qmp_put(q6v5->qmp);
344c1fe10d2SSibi Sankar 		return load_state ? -ENOMEM : -EINVAL;
345c1fe10d2SSibi Sankar 	}
346c1fe10d2SSibi Sankar 
3478d9be5c6SBjorn Andersson 	q6v5->path = devm_of_icc_get(&pdev->dev, NULL);
3488d9be5c6SBjorn Andersson 	if (IS_ERR(q6v5->path))
3498d9be5c6SBjorn Andersson 		return dev_err_probe(&pdev->dev, PTR_ERR(q6v5->path),
3508d9be5c6SBjorn Andersson 				     "failed to acquire interconnect path\n");
3518d9be5c6SBjorn Andersson 
3523b415c8fSBjorn Andersson 	return 0;
3533b415c8fSBjorn Andersson }
354ded79d06SArnd Bergmann EXPORT_SYMBOL_GPL(qcom_q6v5_init);
355ded79d06SArnd Bergmann 
356c1fe10d2SSibi Sankar /**
357c1fe10d2SSibi Sankar  * qcom_q6v5_deinit() - deinitialize the q6v5 common struct
358c1fe10d2SSibi Sankar  * @q6v5:	reference to qcom_q6v5 context to be deinitialized
359c1fe10d2SSibi Sankar  */
qcom_q6v5_deinit(struct qcom_q6v5 * q6v5)360c1fe10d2SSibi Sankar void qcom_q6v5_deinit(struct qcom_q6v5 *q6v5)
361c1fe10d2SSibi Sankar {
362c1fe10d2SSibi Sankar 	qmp_put(q6v5->qmp);
363c1fe10d2SSibi Sankar }
364c1fe10d2SSibi Sankar EXPORT_SYMBOL_GPL(qcom_q6v5_deinit);
365c1fe10d2SSibi Sankar 
366ded79d06SArnd Bergmann MODULE_LICENSE("GPL v2");
367ded79d06SArnd Bergmann MODULE_DESCRIPTION("Qualcomm Peripheral Image Loader for Q6V5");
368