1b73e93e1SSrinivas Kandagatla // SPDX-License-Identifier: GPL-2.0
2b73e93e1SSrinivas Kandagatla // Copyright (c) 2011-2017, The Linux Foundation. All rights reserved.
3b73e93e1SSrinivas Kandagatla // Copyright (c) 2018, Linaro Limited
4b73e93e1SSrinivas Kandagatla
5b73e93e1SSrinivas Kandagatla #include <linux/slab.h>
6b73e93e1SSrinivas Kandagatla #include <linux/wait.h>
7b73e93e1SSrinivas Kandagatla #include <linux/kernel.h>
8b73e93e1SSrinivas Kandagatla #include <linux/module.h>
9b73e93e1SSrinivas Kandagatla #include <linux/sched.h>
10b73e93e1SSrinivas Kandagatla #include <linux/of.h>
11b73e93e1SSrinivas Kandagatla #include <linux/of_platform.h>
12b73e93e1SSrinivas Kandagatla #include <linux/jiffies.h>
13b73e93e1SSrinivas Kandagatla #include <linux/soc/qcom/apr.h>
14b73e93e1SSrinivas Kandagatla #include "q6core.h"
15b73e93e1SSrinivas Kandagatla #include "q6dsp-errno.h"
16b73e93e1SSrinivas Kandagatla
17b73e93e1SSrinivas Kandagatla #define ADSP_STATE_READY_TIMEOUT_MS 3000
18b73e93e1SSrinivas Kandagatla #define Q6_READY_TIMEOUT_MS 100
19b73e93e1SSrinivas Kandagatla #define AVCS_CMD_ADSP_EVENT_GET_STATE 0x0001290C
20b73e93e1SSrinivas Kandagatla #define AVCS_CMDRSP_ADSP_EVENT_GET_STATE 0x0001290D
21b73e93e1SSrinivas Kandagatla #define AVCS_GET_VERSIONS 0x00012905
22b73e93e1SSrinivas Kandagatla #define AVCS_GET_VERSIONS_RSP 0x00012906
23b73e93e1SSrinivas Kandagatla #define AVCS_CMD_GET_FWK_VERSION 0x001292c
24b73e93e1SSrinivas Kandagatla #define AVCS_CMDRSP_GET_FWK_VERSION 0x001292d
25b73e93e1SSrinivas Kandagatla
26b73e93e1SSrinivas Kandagatla struct avcs_svc_info {
27b73e93e1SSrinivas Kandagatla uint32_t service_id;
28b73e93e1SSrinivas Kandagatla uint32_t version;
29b73e93e1SSrinivas Kandagatla } __packed;
30b73e93e1SSrinivas Kandagatla
31b73e93e1SSrinivas Kandagatla struct avcs_cmdrsp_get_version {
32b73e93e1SSrinivas Kandagatla uint32_t build_id;
33b73e93e1SSrinivas Kandagatla uint32_t num_services;
34b73e93e1SSrinivas Kandagatla struct avcs_svc_info svc_api_info[];
35b73e93e1SSrinivas Kandagatla } __packed;
36b73e93e1SSrinivas Kandagatla
37b73e93e1SSrinivas Kandagatla /* for ADSP2.8 and above */
38b73e93e1SSrinivas Kandagatla struct avcs_svc_api_info {
39b73e93e1SSrinivas Kandagatla uint32_t service_id;
40b73e93e1SSrinivas Kandagatla uint32_t api_version;
41b73e93e1SSrinivas Kandagatla uint32_t api_branch_version;
42b73e93e1SSrinivas Kandagatla } __packed;
43b73e93e1SSrinivas Kandagatla
44b73e93e1SSrinivas Kandagatla struct avcs_cmdrsp_get_fwk_version {
45b73e93e1SSrinivas Kandagatla uint32_t build_major_version;
46b73e93e1SSrinivas Kandagatla uint32_t build_minor_version;
47b73e93e1SSrinivas Kandagatla uint32_t build_branch_version;
48b73e93e1SSrinivas Kandagatla uint32_t build_subbranch_version;
49b73e93e1SSrinivas Kandagatla uint32_t num_services;
50b73e93e1SSrinivas Kandagatla struct avcs_svc_api_info svc_api_info[];
51b73e93e1SSrinivas Kandagatla } __packed;
52b73e93e1SSrinivas Kandagatla
53b73e93e1SSrinivas Kandagatla struct q6core {
54b73e93e1SSrinivas Kandagatla struct apr_device *adev;
55b73e93e1SSrinivas Kandagatla wait_queue_head_t wait;
56b73e93e1SSrinivas Kandagatla uint32_t avcs_state;
57b73e93e1SSrinivas Kandagatla struct mutex lock;
58b73e93e1SSrinivas Kandagatla bool resp_received;
59b73e93e1SSrinivas Kandagatla uint32_t num_services;
60b73e93e1SSrinivas Kandagatla struct avcs_cmdrsp_get_fwk_version *fwk_version;
61b73e93e1SSrinivas Kandagatla struct avcs_cmdrsp_get_version *svc_version;
62b73e93e1SSrinivas Kandagatla bool fwk_version_supported;
63b73e93e1SSrinivas Kandagatla bool get_state_supported;
64b73e93e1SSrinivas Kandagatla bool get_version_supported;
65b73e93e1SSrinivas Kandagatla bool is_version_requested;
66b73e93e1SSrinivas Kandagatla };
67b73e93e1SSrinivas Kandagatla
68b73e93e1SSrinivas Kandagatla static struct q6core *g_core;
69b73e93e1SSrinivas Kandagatla
q6core_callback(struct apr_device * adev,struct apr_resp_pkt * data)70b73e93e1SSrinivas Kandagatla static int q6core_callback(struct apr_device *adev, struct apr_resp_pkt *data)
71b73e93e1SSrinivas Kandagatla {
72b73e93e1SSrinivas Kandagatla struct q6core *core = dev_get_drvdata(&adev->dev);
73b73e93e1SSrinivas Kandagatla struct aprv2_ibasic_rsp_result_t *result;
74b73e93e1SSrinivas Kandagatla struct apr_hdr *hdr = &data->hdr;
75b73e93e1SSrinivas Kandagatla
76b73e93e1SSrinivas Kandagatla result = data->payload;
77b73e93e1SSrinivas Kandagatla switch (hdr->opcode) {
78b73e93e1SSrinivas Kandagatla case APR_BASIC_RSP_RESULT:{
79b73e93e1SSrinivas Kandagatla result = data->payload;
80b73e93e1SSrinivas Kandagatla switch (result->opcode) {
81b73e93e1SSrinivas Kandagatla case AVCS_GET_VERSIONS:
82b73e93e1SSrinivas Kandagatla if (result->status == ADSP_EUNSUPPORTED)
83b73e93e1SSrinivas Kandagatla core->get_version_supported = false;
84b73e93e1SSrinivas Kandagatla core->resp_received = true;
85b73e93e1SSrinivas Kandagatla break;
86b73e93e1SSrinivas Kandagatla case AVCS_CMD_GET_FWK_VERSION:
87b73e93e1SSrinivas Kandagatla if (result->status == ADSP_EUNSUPPORTED)
88b73e93e1SSrinivas Kandagatla core->fwk_version_supported = false;
89b73e93e1SSrinivas Kandagatla core->resp_received = true;
90b73e93e1SSrinivas Kandagatla break;
91b73e93e1SSrinivas Kandagatla case AVCS_CMD_ADSP_EVENT_GET_STATE:
92b73e93e1SSrinivas Kandagatla if (result->status == ADSP_EUNSUPPORTED)
93b73e93e1SSrinivas Kandagatla core->get_state_supported = false;
94b73e93e1SSrinivas Kandagatla core->resp_received = true;
95b73e93e1SSrinivas Kandagatla break;
96b73e93e1SSrinivas Kandagatla }
97b73e93e1SSrinivas Kandagatla break;
98b73e93e1SSrinivas Kandagatla }
99b73e93e1SSrinivas Kandagatla case AVCS_CMDRSP_GET_FWK_VERSION: {
100b73e93e1SSrinivas Kandagatla struct avcs_cmdrsp_get_fwk_version *fwk;
101b73e93e1SSrinivas Kandagatla
102b73e93e1SSrinivas Kandagatla fwk = data->payload;
103b73e93e1SSrinivas Kandagatla
104e718a3ebSGustavo A. R. Silva core->fwk_version = kmemdup(data->payload,
105e718a3ebSGustavo A. R. Silva struct_size(fwk, svc_api_info,
106e718a3ebSGustavo A. R. Silva fwk->num_services),
107e718a3ebSGustavo A. R. Silva GFP_ATOMIC);
108b73e93e1SSrinivas Kandagatla if (!core->fwk_version)
109b73e93e1SSrinivas Kandagatla return -ENOMEM;
110b73e93e1SSrinivas Kandagatla
111b73e93e1SSrinivas Kandagatla core->fwk_version_supported = true;
112b73e93e1SSrinivas Kandagatla core->resp_received = true;
113b73e93e1SSrinivas Kandagatla
114b73e93e1SSrinivas Kandagatla break;
115b73e93e1SSrinivas Kandagatla }
116b73e93e1SSrinivas Kandagatla case AVCS_GET_VERSIONS_RSP: {
117b73e93e1SSrinivas Kandagatla struct avcs_cmdrsp_get_version *v;
118b73e93e1SSrinivas Kandagatla
119b73e93e1SSrinivas Kandagatla v = data->payload;
120b73e93e1SSrinivas Kandagatla
121e718a3ebSGustavo A. R. Silva core->svc_version = kmemdup(data->payload,
122e718a3ebSGustavo A. R. Silva struct_size(v, svc_api_info,
123e718a3ebSGustavo A. R. Silva v->num_services),
124e718a3ebSGustavo A. R. Silva GFP_ATOMIC);
125b73e93e1SSrinivas Kandagatla if (!core->svc_version)
126b73e93e1SSrinivas Kandagatla return -ENOMEM;
127b73e93e1SSrinivas Kandagatla
128b73e93e1SSrinivas Kandagatla core->get_version_supported = true;
129b73e93e1SSrinivas Kandagatla core->resp_received = true;
130b73e93e1SSrinivas Kandagatla
131b73e93e1SSrinivas Kandagatla break;
132b73e93e1SSrinivas Kandagatla }
133b73e93e1SSrinivas Kandagatla case AVCS_CMDRSP_ADSP_EVENT_GET_STATE:
134b73e93e1SSrinivas Kandagatla core->get_state_supported = true;
135b73e93e1SSrinivas Kandagatla core->avcs_state = result->opcode;
136b73e93e1SSrinivas Kandagatla
137b73e93e1SSrinivas Kandagatla core->resp_received = true;
138b73e93e1SSrinivas Kandagatla break;
139b73e93e1SSrinivas Kandagatla default:
140b73e93e1SSrinivas Kandagatla dev_err(&adev->dev, "Message id from adsp core svc: 0x%x\n",
141b73e93e1SSrinivas Kandagatla hdr->opcode);
142b73e93e1SSrinivas Kandagatla break;
143b73e93e1SSrinivas Kandagatla }
144b73e93e1SSrinivas Kandagatla
145b73e93e1SSrinivas Kandagatla if (core->resp_received)
146b73e93e1SSrinivas Kandagatla wake_up(&core->wait);
147b73e93e1SSrinivas Kandagatla
148b73e93e1SSrinivas Kandagatla return 0;
149b73e93e1SSrinivas Kandagatla }
150b73e93e1SSrinivas Kandagatla
q6core_get_fwk_versions(struct q6core * core)151b73e93e1SSrinivas Kandagatla static int q6core_get_fwk_versions(struct q6core *core)
152b73e93e1SSrinivas Kandagatla {
153b73e93e1SSrinivas Kandagatla struct apr_device *adev = core->adev;
154b73e93e1SSrinivas Kandagatla struct apr_pkt pkt;
155b73e93e1SSrinivas Kandagatla int rc;
156b73e93e1SSrinivas Kandagatla
157b73e93e1SSrinivas Kandagatla pkt.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
158b73e93e1SSrinivas Kandagatla APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
159b73e93e1SSrinivas Kandagatla pkt.hdr.pkt_size = APR_HDR_SIZE;
160b73e93e1SSrinivas Kandagatla pkt.hdr.opcode = AVCS_CMD_GET_FWK_VERSION;
161b73e93e1SSrinivas Kandagatla
162b73e93e1SSrinivas Kandagatla rc = apr_send_pkt(adev, &pkt);
163b73e93e1SSrinivas Kandagatla if (rc < 0)
164b73e93e1SSrinivas Kandagatla return rc;
165b73e93e1SSrinivas Kandagatla
166b73e93e1SSrinivas Kandagatla rc = wait_event_timeout(core->wait, (core->resp_received),
167b73e93e1SSrinivas Kandagatla msecs_to_jiffies(Q6_READY_TIMEOUT_MS));
168b73e93e1SSrinivas Kandagatla if (rc > 0 && core->resp_received) {
169b73e93e1SSrinivas Kandagatla core->resp_received = false;
170b73e93e1SSrinivas Kandagatla
171b73e93e1SSrinivas Kandagatla if (!core->fwk_version_supported)
172b73e93e1SSrinivas Kandagatla return -ENOTSUPP;
173b73e93e1SSrinivas Kandagatla else
174b73e93e1SSrinivas Kandagatla return 0;
175b73e93e1SSrinivas Kandagatla }
176b73e93e1SSrinivas Kandagatla
177b73e93e1SSrinivas Kandagatla
178b73e93e1SSrinivas Kandagatla return rc;
179b73e93e1SSrinivas Kandagatla }
180b73e93e1SSrinivas Kandagatla
q6core_get_svc_versions(struct q6core * core)181b73e93e1SSrinivas Kandagatla static int q6core_get_svc_versions(struct q6core *core)
182b73e93e1SSrinivas Kandagatla {
183b73e93e1SSrinivas Kandagatla struct apr_device *adev = core->adev;
184b73e93e1SSrinivas Kandagatla struct apr_pkt pkt;
185b73e93e1SSrinivas Kandagatla int rc;
186b73e93e1SSrinivas Kandagatla
187b73e93e1SSrinivas Kandagatla pkt.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
188b73e93e1SSrinivas Kandagatla APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
189b73e93e1SSrinivas Kandagatla pkt.hdr.pkt_size = APR_HDR_SIZE;
190b73e93e1SSrinivas Kandagatla pkt.hdr.opcode = AVCS_GET_VERSIONS;
191b73e93e1SSrinivas Kandagatla
192b73e93e1SSrinivas Kandagatla rc = apr_send_pkt(adev, &pkt);
193b73e93e1SSrinivas Kandagatla if (rc < 0)
194b73e93e1SSrinivas Kandagatla return rc;
195b73e93e1SSrinivas Kandagatla
196b73e93e1SSrinivas Kandagatla rc = wait_event_timeout(core->wait, (core->resp_received),
197b73e93e1SSrinivas Kandagatla msecs_to_jiffies(Q6_READY_TIMEOUT_MS));
198b73e93e1SSrinivas Kandagatla if (rc > 0 && core->resp_received) {
199b73e93e1SSrinivas Kandagatla core->resp_received = false;
200b73e93e1SSrinivas Kandagatla return 0;
201b73e93e1SSrinivas Kandagatla }
202b73e93e1SSrinivas Kandagatla
203b73e93e1SSrinivas Kandagatla return rc;
204b73e93e1SSrinivas Kandagatla }
205b73e93e1SSrinivas Kandagatla
__q6core_is_adsp_ready(struct q6core * core)206b73e93e1SSrinivas Kandagatla static bool __q6core_is_adsp_ready(struct q6core *core)
207b73e93e1SSrinivas Kandagatla {
208b73e93e1SSrinivas Kandagatla struct apr_device *adev = core->adev;
209b73e93e1SSrinivas Kandagatla struct apr_pkt pkt;
210b73e93e1SSrinivas Kandagatla int rc;
211b73e93e1SSrinivas Kandagatla
212b73e93e1SSrinivas Kandagatla core->get_state_supported = false;
213b73e93e1SSrinivas Kandagatla
214b73e93e1SSrinivas Kandagatla pkt.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
215b73e93e1SSrinivas Kandagatla APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
216b73e93e1SSrinivas Kandagatla pkt.hdr.pkt_size = APR_HDR_SIZE;
217b73e93e1SSrinivas Kandagatla pkt.hdr.opcode = AVCS_CMD_ADSP_EVENT_GET_STATE;
218b73e93e1SSrinivas Kandagatla
219b73e93e1SSrinivas Kandagatla rc = apr_send_pkt(adev, &pkt);
220b73e93e1SSrinivas Kandagatla if (rc < 0)
221b73e93e1SSrinivas Kandagatla return false;
222b73e93e1SSrinivas Kandagatla
223b73e93e1SSrinivas Kandagatla rc = wait_event_timeout(core->wait, (core->resp_received),
224b73e93e1SSrinivas Kandagatla msecs_to_jiffies(Q6_READY_TIMEOUT_MS));
225b73e93e1SSrinivas Kandagatla if (rc > 0 && core->resp_received) {
226b73e93e1SSrinivas Kandagatla core->resp_received = false;
227b73e93e1SSrinivas Kandagatla
228b73e93e1SSrinivas Kandagatla if (core->avcs_state)
229b73e93e1SSrinivas Kandagatla return true;
230b73e93e1SSrinivas Kandagatla }
231b73e93e1SSrinivas Kandagatla
232b73e93e1SSrinivas Kandagatla /* assume that the adsp is up if we not support this command */
233b73e93e1SSrinivas Kandagatla if (!core->get_state_supported)
234b73e93e1SSrinivas Kandagatla return true;
235b73e93e1SSrinivas Kandagatla
236b73e93e1SSrinivas Kandagatla return false;
237b73e93e1SSrinivas Kandagatla }
238b73e93e1SSrinivas Kandagatla
239b73e93e1SSrinivas Kandagatla /**
240b73e93e1SSrinivas Kandagatla * q6core_get_svc_api_info() - Get version number of a service.
241b73e93e1SSrinivas Kandagatla *
242b73e93e1SSrinivas Kandagatla * @svc_id: service id of the service.
243b73e93e1SSrinivas Kandagatla * @ainfo: Valid struct pointer to fill svc api information.
244b73e93e1SSrinivas Kandagatla *
245b73e93e1SSrinivas Kandagatla * Return: zero on success and error code on failure or unsupported
246b73e93e1SSrinivas Kandagatla */
q6core_get_svc_api_info(int svc_id,struct q6core_svc_api_info * ainfo)247b73e93e1SSrinivas Kandagatla int q6core_get_svc_api_info(int svc_id, struct q6core_svc_api_info *ainfo)
248b73e93e1SSrinivas Kandagatla {
249b73e93e1SSrinivas Kandagatla int i;
250b73e93e1SSrinivas Kandagatla int ret = -ENOTSUPP;
251b73e93e1SSrinivas Kandagatla
252b73e93e1SSrinivas Kandagatla if (!g_core || !ainfo)
253b73e93e1SSrinivas Kandagatla return 0;
254b73e93e1SSrinivas Kandagatla
255b73e93e1SSrinivas Kandagatla mutex_lock(&g_core->lock);
256b73e93e1SSrinivas Kandagatla if (!g_core->is_version_requested) {
257b73e93e1SSrinivas Kandagatla if (q6core_get_fwk_versions(g_core) == -ENOTSUPP)
258b73e93e1SSrinivas Kandagatla q6core_get_svc_versions(g_core);
259b73e93e1SSrinivas Kandagatla g_core->is_version_requested = true;
260b73e93e1SSrinivas Kandagatla }
261b73e93e1SSrinivas Kandagatla
262b73e93e1SSrinivas Kandagatla if (g_core->fwk_version_supported) {
263b73e93e1SSrinivas Kandagatla for (i = 0; i < g_core->fwk_version->num_services; i++) {
264b73e93e1SSrinivas Kandagatla struct avcs_svc_api_info *info;
265b73e93e1SSrinivas Kandagatla
266b73e93e1SSrinivas Kandagatla info = &g_core->fwk_version->svc_api_info[i];
267b73e93e1SSrinivas Kandagatla if (svc_id != info->service_id)
268b73e93e1SSrinivas Kandagatla continue;
269b73e93e1SSrinivas Kandagatla
270b73e93e1SSrinivas Kandagatla ainfo->api_version = info->api_version;
271b73e93e1SSrinivas Kandagatla ainfo->api_branch_version = info->api_branch_version;
272b73e93e1SSrinivas Kandagatla ret = 0;
273b73e93e1SSrinivas Kandagatla break;
274b73e93e1SSrinivas Kandagatla }
275b73e93e1SSrinivas Kandagatla } else if (g_core->get_version_supported) {
276b73e93e1SSrinivas Kandagatla for (i = 0; i < g_core->svc_version->num_services; i++) {
277b73e93e1SSrinivas Kandagatla struct avcs_svc_info *info;
278b73e93e1SSrinivas Kandagatla
279b73e93e1SSrinivas Kandagatla info = &g_core->svc_version->svc_api_info[i];
280b73e93e1SSrinivas Kandagatla if (svc_id != info->service_id)
281b73e93e1SSrinivas Kandagatla continue;
282b73e93e1SSrinivas Kandagatla
283b73e93e1SSrinivas Kandagatla ainfo->api_version = info->version;
284b73e93e1SSrinivas Kandagatla ainfo->api_branch_version = 0;
285b73e93e1SSrinivas Kandagatla ret = 0;
286b73e93e1SSrinivas Kandagatla break;
287b73e93e1SSrinivas Kandagatla }
288b73e93e1SSrinivas Kandagatla }
289b73e93e1SSrinivas Kandagatla
290b73e93e1SSrinivas Kandagatla mutex_unlock(&g_core->lock);
291b73e93e1SSrinivas Kandagatla
292b73e93e1SSrinivas Kandagatla return ret;
293b73e93e1SSrinivas Kandagatla }
294b73e93e1SSrinivas Kandagatla EXPORT_SYMBOL_GPL(q6core_get_svc_api_info);
295b73e93e1SSrinivas Kandagatla
296b73e93e1SSrinivas Kandagatla /**
297b73e93e1SSrinivas Kandagatla * q6core_is_adsp_ready() - Get status of adsp
298b73e93e1SSrinivas Kandagatla *
299b73e93e1SSrinivas Kandagatla * Return: Will be an true if adsp is ready and false if not.
300b73e93e1SSrinivas Kandagatla */
q6core_is_adsp_ready(void)301b73e93e1SSrinivas Kandagatla bool q6core_is_adsp_ready(void)
302b73e93e1SSrinivas Kandagatla {
303b73e93e1SSrinivas Kandagatla unsigned long timeout;
304b73e93e1SSrinivas Kandagatla bool ret = false;
305b73e93e1SSrinivas Kandagatla
306b73e93e1SSrinivas Kandagatla if (!g_core)
307b73e93e1SSrinivas Kandagatla return false;
308b73e93e1SSrinivas Kandagatla
309b73e93e1SSrinivas Kandagatla mutex_lock(&g_core->lock);
310b73e93e1SSrinivas Kandagatla timeout = jiffies + msecs_to_jiffies(ADSP_STATE_READY_TIMEOUT_MS);
311b73e93e1SSrinivas Kandagatla for (;;) {
312b73e93e1SSrinivas Kandagatla if (__q6core_is_adsp_ready(g_core)) {
313b73e93e1SSrinivas Kandagatla ret = true;
314b73e93e1SSrinivas Kandagatla break;
315b73e93e1SSrinivas Kandagatla }
316b73e93e1SSrinivas Kandagatla
317b73e93e1SSrinivas Kandagatla if (!time_after(timeout, jiffies)) {
318b73e93e1SSrinivas Kandagatla ret = false;
319b73e93e1SSrinivas Kandagatla break;
320b73e93e1SSrinivas Kandagatla }
321b73e93e1SSrinivas Kandagatla }
322b73e93e1SSrinivas Kandagatla
323b73e93e1SSrinivas Kandagatla mutex_unlock(&g_core->lock);
324b73e93e1SSrinivas Kandagatla return ret;
325b73e93e1SSrinivas Kandagatla }
326b73e93e1SSrinivas Kandagatla EXPORT_SYMBOL_GPL(q6core_is_adsp_ready);
327b73e93e1SSrinivas Kandagatla
q6core_probe(struct apr_device * adev)328b73e93e1SSrinivas Kandagatla static int q6core_probe(struct apr_device *adev)
329b73e93e1SSrinivas Kandagatla {
330b73e93e1SSrinivas Kandagatla g_core = kzalloc(sizeof(*g_core), GFP_KERNEL);
331b73e93e1SSrinivas Kandagatla if (!g_core)
332b73e93e1SSrinivas Kandagatla return -ENOMEM;
333b73e93e1SSrinivas Kandagatla
334b73e93e1SSrinivas Kandagatla dev_set_drvdata(&adev->dev, g_core);
335b73e93e1SSrinivas Kandagatla
336b73e93e1SSrinivas Kandagatla mutex_init(&g_core->lock);
337b73e93e1SSrinivas Kandagatla g_core->adev = adev;
338b73e93e1SSrinivas Kandagatla init_waitqueue_head(&g_core->wait);
339b73e93e1SSrinivas Kandagatla return 0;
340b73e93e1SSrinivas Kandagatla }
341b73e93e1SSrinivas Kandagatla
q6core_exit(struct apr_device * adev)342*33ae3d09SDawei Li static void q6core_exit(struct apr_device *adev)
343b73e93e1SSrinivas Kandagatla {
344b73e93e1SSrinivas Kandagatla struct q6core *core = dev_get_drvdata(&adev->dev);
345b73e93e1SSrinivas Kandagatla
346b73e93e1SSrinivas Kandagatla if (core->fwk_version_supported)
347b73e93e1SSrinivas Kandagatla kfree(core->fwk_version);
348b73e93e1SSrinivas Kandagatla if (core->get_version_supported)
349b73e93e1SSrinivas Kandagatla kfree(core->svc_version);
350b73e93e1SSrinivas Kandagatla
351b73e93e1SSrinivas Kandagatla g_core = NULL;
352b73e93e1SSrinivas Kandagatla kfree(core);
353b73e93e1SSrinivas Kandagatla }
354b73e93e1SSrinivas Kandagatla
355156d0273SSrinivas Kandagatla #ifdef CONFIG_OF
356b73e93e1SSrinivas Kandagatla static const struct of_device_id q6core_device_id[] = {
357b73e93e1SSrinivas Kandagatla { .compatible = "qcom,q6core" },
358b73e93e1SSrinivas Kandagatla {},
359b73e93e1SSrinivas Kandagatla };
360b73e93e1SSrinivas Kandagatla MODULE_DEVICE_TABLE(of, q6core_device_id);
361156d0273SSrinivas Kandagatla #endif
362b73e93e1SSrinivas Kandagatla
363b73e93e1SSrinivas Kandagatla static struct apr_driver qcom_q6core_driver = {
364b73e93e1SSrinivas Kandagatla .probe = q6core_probe,
365b73e93e1SSrinivas Kandagatla .remove = q6core_exit,
366b73e93e1SSrinivas Kandagatla .callback = q6core_callback,
367b73e93e1SSrinivas Kandagatla .driver = {
368b73e93e1SSrinivas Kandagatla .name = "qcom-q6core",
369b73e93e1SSrinivas Kandagatla .of_match_table = of_match_ptr(q6core_device_id),
370b73e93e1SSrinivas Kandagatla },
371b73e93e1SSrinivas Kandagatla };
372b73e93e1SSrinivas Kandagatla
373b73e93e1SSrinivas Kandagatla module_apr_driver(qcom_q6core_driver);
374b73e93e1SSrinivas Kandagatla MODULE_DESCRIPTION("q6 core");
375b73e93e1SSrinivas Kandagatla MODULE_LICENSE("GPL v2");
376