xref: /openbmc/linux/sound/soc/qcom/qdsp6/q6apm.c (revision ecfb9f40)
1 // SPDX-License-Identifier: GPL-2.0
2 // Copyright (c) 2020, Linaro Limited
3 
4 #include <dt-bindings/soc/qcom,gpr.h>
5 #include <linux/delay.h>
6 #include <linux/jiffies.h>
7 #include <linux/kernel.h>
8 #include <linux/module.h>
9 #include <linux/of.h>
10 #include <linux/of_platform.h>
11 #include <linux/sched.h>
12 #include <linux/slab.h>
13 #include <linux/soc/qcom/apr.h>
14 #include <linux/wait.h>
15 #include <sound/soc.h>
16 #include <sound/soc-dapm.h>
17 #include <sound/pcm.h>
18 #include "audioreach.h"
19 #include "q6apm.h"
20 
21 /* Graph Management */
22 struct apm_graph_mgmt_cmd {
23 	struct apm_module_param_data param_data;
24 	uint32_t num_sub_graphs;
25 	uint32_t sub_graph_id_list[];
26 } __packed;
27 
28 #define APM_GRAPH_MGMT_PSIZE(p, n) ALIGN(struct_size(p, sub_graph_id_list, n), 8)
29 
30 int q6apm_send_cmd_sync(struct q6apm *apm, struct gpr_pkt *pkt, uint32_t rsp_opcode)
31 {
32 	gpr_device_t *gdev = apm->gdev;
33 
34 	return audioreach_send_cmd_sync(&gdev->dev, gdev, &apm->result, &apm->lock,
35 					NULL, &apm->wait, pkt, rsp_opcode);
36 }
37 
38 static struct audioreach_graph *q6apm_get_audioreach_graph(struct q6apm *apm, uint32_t graph_id)
39 {
40 	struct audioreach_graph_info *info;
41 	struct audioreach_graph *graph;
42 	int id;
43 
44 	mutex_lock(&apm->lock);
45 	graph = idr_find(&apm->graph_idr, graph_id);
46 	mutex_unlock(&apm->lock);
47 
48 	if (graph) {
49 		kref_get(&graph->refcount);
50 		return graph;
51 	}
52 
53 	info = idr_find(&apm->graph_info_idr, graph_id);
54 
55 	if (!info)
56 		return ERR_PTR(-ENODEV);
57 
58 	graph = kzalloc(sizeof(*graph), GFP_KERNEL);
59 	if (!graph)
60 		return ERR_PTR(-ENOMEM);
61 
62 	graph->apm = apm;
63 	graph->info = info;
64 	graph->id = graph_id;
65 
66 	graph->graph = audioreach_alloc_graph_pkt(apm, info);
67 	if (IS_ERR(graph->graph)) {
68 		void *err = graph->graph;
69 
70 		kfree(graph);
71 		return ERR_CAST(err);
72 	}
73 
74 	mutex_lock(&apm->lock);
75 	id = idr_alloc(&apm->graph_idr, graph, graph_id, graph_id + 1, GFP_KERNEL);
76 	if (id < 0) {
77 		dev_err(apm->dev, "Unable to allocate graph id (%d)\n", graph_id);
78 		kfree(graph->graph);
79 		kfree(graph);
80 		mutex_unlock(&apm->lock);
81 		return ERR_PTR(id);
82 	}
83 	mutex_unlock(&apm->lock);
84 
85 	kref_init(&graph->refcount);
86 
87 	q6apm_send_cmd_sync(apm, graph->graph, 0);
88 
89 	return graph;
90 }
91 
92 static int audioreach_graph_mgmt_cmd(struct audioreach_graph *graph, uint32_t opcode)
93 {
94 	struct audioreach_graph_info *info = graph->info;
95 	int num_sub_graphs = info->num_sub_graphs;
96 	struct apm_module_param_data *param_data;
97 	struct apm_graph_mgmt_cmd *mgmt_cmd;
98 	struct audioreach_sub_graph *sg;
99 	struct q6apm *apm = graph->apm;
100 	int i = 0, rc, payload_size;
101 	struct gpr_pkt *pkt;
102 
103 	payload_size = APM_GRAPH_MGMT_PSIZE(mgmt_cmd, num_sub_graphs);
104 
105 	pkt = audioreach_alloc_apm_cmd_pkt(payload_size, opcode, 0);
106 	if (IS_ERR(pkt))
107 		return PTR_ERR(pkt);
108 
109 	mgmt_cmd = (void *)pkt + GPR_HDR_SIZE + APM_CMD_HDR_SIZE;
110 
111 	mgmt_cmd->num_sub_graphs = num_sub_graphs;
112 
113 	param_data = &mgmt_cmd->param_data;
114 	param_data->module_instance_id = APM_MODULE_INSTANCE_ID;
115 	param_data->param_id = APM_PARAM_ID_SUB_GRAPH_LIST;
116 	param_data->param_size = payload_size - APM_MODULE_PARAM_DATA_SIZE;
117 
118 	list_for_each_entry(sg, &info->sg_list, node)
119 		mgmt_cmd->sub_graph_id_list[i++] = sg->sub_graph_id;
120 
121 	rc = q6apm_send_cmd_sync(apm, pkt, 0);
122 
123 	kfree(pkt);
124 
125 	return rc;
126 }
127 
128 static void q6apm_put_audioreach_graph(struct kref *ref)
129 {
130 	struct audioreach_graph *graph;
131 	struct q6apm *apm;
132 
133 	graph = container_of(ref, struct audioreach_graph, refcount);
134 	apm = graph->apm;
135 
136 	audioreach_graph_mgmt_cmd(graph, APM_CMD_GRAPH_CLOSE);
137 
138 	mutex_lock(&apm->lock);
139 	graph = idr_remove(&apm->graph_idr, graph->id);
140 	mutex_unlock(&apm->lock);
141 
142 	kfree(graph->graph);
143 	kfree(graph);
144 }
145 
146 static int q6apm_get_apm_state(struct q6apm *apm)
147 {
148 	struct gpr_pkt *pkt;
149 
150 	pkt = audioreach_alloc_apm_cmd_pkt(0, APM_CMD_GET_SPF_STATE, 0);
151 	if (IS_ERR(pkt))
152 		return PTR_ERR(pkt);
153 
154 	q6apm_send_cmd_sync(apm, pkt, APM_CMD_RSP_GET_SPF_STATE);
155 
156 	kfree(pkt);
157 
158 	return apm->state;
159 }
160 
161 static struct audioreach_module *__q6apm_find_module_by_mid(struct q6apm *apm,
162 						    struct audioreach_graph_info *info,
163 						    uint32_t mid)
164 {
165 	struct audioreach_container *container;
166 	struct audioreach_sub_graph *sgs;
167 	struct audioreach_module *module;
168 
169 	list_for_each_entry(sgs, &info->sg_list, node) {
170 		list_for_each_entry(container, &sgs->container_list, node) {
171 			list_for_each_entry(module, &container->modules_list, node) {
172 				if (mid == module->module_id)
173 					return module;
174 			}
175 		}
176 	}
177 
178 	return NULL;
179 }
180 
181 int q6apm_graph_media_format_shmem(struct q6apm_graph *graph,
182 				   struct audioreach_module_config *cfg)
183 {
184 	struct audioreach_module *module;
185 
186 	if (cfg->direction == SNDRV_PCM_STREAM_CAPTURE)
187 		module = q6apm_find_module_by_mid(graph, MODULE_ID_RD_SHARED_MEM_EP);
188 	else
189 		module = q6apm_find_module_by_mid(graph, MODULE_ID_WR_SHARED_MEM_EP);
190 
191 	if (!module)
192 		return -ENODEV;
193 
194 	audioreach_set_media_format(graph, module, cfg);
195 
196 	return 0;
197 
198 }
199 EXPORT_SYMBOL_GPL(q6apm_graph_media_format_shmem);
200 
201 int q6apm_map_memory_regions(struct q6apm_graph *graph, unsigned int dir, phys_addr_t phys,
202 			     size_t period_sz, unsigned int periods)
203 {
204 	struct audioreach_graph_data *data;
205 	struct audio_buffer *buf;
206 	int cnt;
207 	int rc;
208 
209 	if (dir == SNDRV_PCM_STREAM_PLAYBACK)
210 		data = &graph->rx_data;
211 	else
212 		data = &graph->tx_data;
213 
214 	mutex_lock(&graph->lock);
215 
216 	if (data->buf) {
217 		mutex_unlock(&graph->lock);
218 		return 0;
219 	}
220 
221 	buf = kzalloc(((sizeof(struct audio_buffer)) * periods), GFP_KERNEL);
222 	if (!buf) {
223 		mutex_unlock(&graph->lock);
224 		return -ENOMEM;
225 	}
226 
227 	if (dir == SNDRV_PCM_STREAM_PLAYBACK)
228 		data = &graph->rx_data;
229 	else
230 		data = &graph->tx_data;
231 
232 	data->buf = buf;
233 
234 	buf[0].phys = phys;
235 	buf[0].size = period_sz;
236 
237 	for (cnt = 1; cnt < periods; cnt++) {
238 		if (period_sz > 0) {
239 			buf[cnt].phys = buf[0].phys + (cnt * period_sz);
240 			buf[cnt].size = period_sz;
241 		}
242 	}
243 	data->num_periods = periods;
244 
245 	mutex_unlock(&graph->lock);
246 
247 	rc = audioreach_map_memory_regions(graph, dir, period_sz, periods, 1);
248 	if (rc < 0) {
249 		dev_err(graph->dev, "Memory_map_regions failed\n");
250 		audioreach_graph_free_buf(graph);
251 	}
252 
253 	return rc;
254 }
255 EXPORT_SYMBOL_GPL(q6apm_map_memory_regions);
256 
257 int q6apm_unmap_memory_regions(struct q6apm_graph *graph, unsigned int dir)
258 {
259 	struct apm_cmd_shared_mem_unmap_regions *cmd;
260 	struct audioreach_graph_data *data;
261 	struct gpr_pkt *pkt;
262 	int rc;
263 
264 	if (dir == SNDRV_PCM_STREAM_PLAYBACK)
265 		data = &graph->rx_data;
266 	else
267 		data = &graph->tx_data;
268 
269 	if (!data->mem_map_handle)
270 		return 0;
271 
272 	pkt = audioreach_alloc_apm_pkt(sizeof(*cmd), APM_CMD_SHARED_MEM_UNMAP_REGIONS, dir,
273 				     graph->port->id);
274 	if (IS_ERR(pkt))
275 		return PTR_ERR(pkt);
276 
277 	cmd = (void *)pkt + GPR_HDR_SIZE;
278 	cmd->mem_map_handle = data->mem_map_handle;
279 
280 	rc = audioreach_graph_send_cmd_sync(graph, pkt, APM_CMD_SHARED_MEM_UNMAP_REGIONS);
281 	kfree(pkt);
282 
283 	audioreach_graph_free_buf(graph);
284 
285 	return rc;
286 }
287 EXPORT_SYMBOL_GPL(q6apm_unmap_memory_regions);
288 
289 int q6apm_graph_media_format_pcm(struct q6apm_graph *graph, struct audioreach_module_config *cfg)
290 {
291 	struct audioreach_graph_info *info = graph->info;
292 	struct audioreach_sub_graph *sgs;
293 	struct audioreach_container *container;
294 	struct audioreach_module *module;
295 
296 	list_for_each_entry(sgs, &info->sg_list, node) {
297 		list_for_each_entry(container, &sgs->container_list, node) {
298 			list_for_each_entry(module, &container->modules_list, node) {
299 				if ((module->module_id == MODULE_ID_WR_SHARED_MEM_EP) ||
300 					(module->module_id == MODULE_ID_RD_SHARED_MEM_EP))
301 					continue;
302 
303 				audioreach_set_media_format(graph, module, cfg);
304 			}
305 		}
306 	}
307 
308 	return 0;
309 
310 }
311 EXPORT_SYMBOL_GPL(q6apm_graph_media_format_pcm);
312 
313 static int q6apm_graph_get_tx_shmem_module_iid(struct q6apm_graph *graph)
314 {
315 	struct audioreach_module *module;
316 
317 	module = q6apm_find_module_by_mid(graph, MODULE_ID_RD_SHARED_MEM_EP);
318 	if (!module)
319 		return -ENODEV;
320 
321 	return module->instance_id;
322 
323 }
324 
325 int q6apm_graph_get_rx_shmem_module_iid(struct q6apm_graph *graph)
326 {
327 	struct audioreach_module *module;
328 
329 	module = q6apm_find_module_by_mid(graph, MODULE_ID_WR_SHARED_MEM_EP);
330 	if (!module)
331 		return -ENODEV;
332 
333 	return module->instance_id;
334 
335 }
336 EXPORT_SYMBOL_GPL(q6apm_graph_get_rx_shmem_module_iid);
337 
338 int q6apm_write_async(struct q6apm_graph *graph, uint32_t len, uint32_t msw_ts,
339 		      uint32_t lsw_ts, uint32_t wflags)
340 {
341 	struct apm_data_cmd_wr_sh_mem_ep_data_buffer_v2 *write_buffer;
342 	struct audio_buffer *ab;
343 	struct gpr_pkt *pkt;
344 	int rc, iid;
345 
346 	iid = q6apm_graph_get_rx_shmem_module_iid(graph);
347 	pkt = audioreach_alloc_pkt(sizeof(*write_buffer), DATA_CMD_WR_SH_MEM_EP_DATA_BUFFER_V2,
348 				   graph->rx_data.dsp_buf | (len << APM_WRITE_TOKEN_LEN_SHIFT),
349 				   graph->port->id, iid);
350 	if (IS_ERR(pkt))
351 		return PTR_ERR(pkt);
352 
353 	write_buffer = (void *)pkt + GPR_HDR_SIZE;
354 
355 	mutex_lock(&graph->lock);
356 	ab = &graph->rx_data.buf[graph->rx_data.dsp_buf];
357 
358 	write_buffer->buf_addr_lsw = lower_32_bits(ab->phys);
359 	write_buffer->buf_addr_msw = upper_32_bits(ab->phys);
360 	write_buffer->buf_size = len;
361 	write_buffer->timestamp_lsw = lsw_ts;
362 	write_buffer->timestamp_msw = msw_ts;
363 	write_buffer->mem_map_handle = graph->rx_data.mem_map_handle;
364 	write_buffer->flags = wflags;
365 
366 	graph->rx_data.dsp_buf++;
367 
368 	if (graph->rx_data.dsp_buf >= graph->rx_data.num_periods)
369 		graph->rx_data.dsp_buf = 0;
370 
371 	mutex_unlock(&graph->lock);
372 
373 	rc = gpr_send_port_pkt(graph->port, pkt);
374 
375 	kfree(pkt);
376 
377 	return rc;
378 }
379 EXPORT_SYMBOL_GPL(q6apm_write_async);
380 
381 int q6apm_read(struct q6apm_graph *graph)
382 {
383 	struct data_cmd_rd_sh_mem_ep_data_buffer_v2 *read_buffer;
384 	struct audioreach_graph_data *port;
385 	struct audio_buffer *ab;
386 	struct gpr_pkt *pkt;
387 	int rc, iid;
388 
389 	iid = q6apm_graph_get_tx_shmem_module_iid(graph);
390 	pkt = audioreach_alloc_pkt(sizeof(*read_buffer), DATA_CMD_RD_SH_MEM_EP_DATA_BUFFER_V2,
391 				   graph->tx_data.dsp_buf, graph->port->id, iid);
392 	if (IS_ERR(pkt))
393 		return PTR_ERR(pkt);
394 
395 	read_buffer = (void *)pkt + GPR_HDR_SIZE;
396 
397 	mutex_lock(&graph->lock);
398 	port = &graph->tx_data;
399 	ab = &port->buf[port->dsp_buf];
400 
401 	read_buffer->buf_addr_lsw = lower_32_bits(ab->phys);
402 	read_buffer->buf_addr_msw = upper_32_bits(ab->phys);
403 	read_buffer->mem_map_handle = port->mem_map_handle;
404 	read_buffer->buf_size = ab->size;
405 
406 	port->dsp_buf++;
407 
408 	if (port->dsp_buf >= port->num_periods)
409 		port->dsp_buf = 0;
410 
411 	mutex_unlock(&graph->lock);
412 
413 	rc = gpr_send_port_pkt(graph->port, pkt);
414 	kfree(pkt);
415 
416 	return rc;
417 }
418 EXPORT_SYMBOL_GPL(q6apm_read);
419 
420 static int graph_callback(struct gpr_resp_pkt *data, void *priv, int op)
421 {
422 	struct data_cmd_rsp_rd_sh_mem_ep_data_buffer_done_v2 *rd_done;
423 	struct data_cmd_rsp_wr_sh_mem_ep_data_buffer_done_v2 *done;
424 	struct apm_cmd_rsp_shared_mem_map_regions *rsp;
425 	struct gpr_ibasic_rsp_result_t *result;
426 	struct q6apm_graph *graph = priv;
427 	struct gpr_hdr *hdr = &data->hdr;
428 	struct device *dev = graph->dev;
429 	uint32_t client_event;
430 	phys_addr_t phys;
431 	int token;
432 
433 	result = data->payload;
434 
435 	switch (hdr->opcode) {
436 	case DATA_CMD_RSP_WR_SH_MEM_EP_DATA_BUFFER_DONE_V2:
437 		client_event = APM_CLIENT_EVENT_DATA_WRITE_DONE;
438 		mutex_lock(&graph->lock);
439 		token = hdr->token & APM_WRITE_TOKEN_MASK;
440 
441 		done = data->payload;
442 		phys = graph->rx_data.buf[token].phys;
443 		mutex_unlock(&graph->lock);
444 
445 		if (lower_32_bits(phys) == done->buf_addr_lsw &&
446 		    upper_32_bits(phys) == done->buf_addr_msw) {
447 			graph->result.opcode = hdr->opcode;
448 			graph->result.status = done->status;
449 			if (graph->cb)
450 				graph->cb(client_event, hdr->token, data->payload, graph->priv);
451 		} else {
452 			dev_err(dev, "WR BUFF Unexpected addr %08x-%08x\n", done->buf_addr_lsw,
453 				done->buf_addr_msw);
454 		}
455 
456 		break;
457 	case APM_CMD_RSP_SHARED_MEM_MAP_REGIONS:
458 		graph->result.opcode = hdr->opcode;
459 		graph->result.status = 0;
460 		rsp = data->payload;
461 
462 		if (hdr->token == SNDRV_PCM_STREAM_PLAYBACK)
463 			graph->rx_data.mem_map_handle = rsp->mem_map_handle;
464 		else
465 			graph->tx_data.mem_map_handle = rsp->mem_map_handle;
466 
467 		wake_up(&graph->cmd_wait);
468 		break;
469 	case DATA_CMD_RSP_RD_SH_MEM_EP_DATA_BUFFER_V2:
470 		client_event = APM_CLIENT_EVENT_DATA_READ_DONE;
471 		mutex_lock(&graph->lock);
472 		rd_done = data->payload;
473 		phys = graph->tx_data.buf[hdr->token].phys;
474 		mutex_unlock(&graph->lock);
475 
476 		if (upper_32_bits(phys) == rd_done->buf_addr_msw &&
477 		    lower_32_bits(phys) == rd_done->buf_addr_lsw) {
478 			graph->result.opcode = hdr->opcode;
479 			graph->result.status = rd_done->status;
480 			if (graph->cb)
481 				graph->cb(client_event, hdr->token, data->payload, graph->priv);
482 		} else {
483 			dev_err(dev, "RD BUFF Unexpected addr %08x-%08x\n", rd_done->buf_addr_lsw,
484 				rd_done->buf_addr_msw);
485 		}
486 		break;
487 	case DATA_CMD_WR_SH_MEM_EP_EOS_RENDERED:
488 		break;
489 	case GPR_BASIC_RSP_RESULT:
490 		switch (result->opcode) {
491 		case APM_CMD_SHARED_MEM_UNMAP_REGIONS:
492 			graph->result.opcode = result->opcode;
493 			graph->result.status = 0;
494 			if (hdr->token == SNDRV_PCM_STREAM_PLAYBACK)
495 				graph->rx_data.mem_map_handle = 0;
496 			else
497 				graph->tx_data.mem_map_handle = 0;
498 
499 			wake_up(&graph->cmd_wait);
500 			break;
501 		case APM_CMD_SHARED_MEM_MAP_REGIONS:
502 		case DATA_CMD_WR_SH_MEM_EP_MEDIA_FORMAT:
503 		case APM_CMD_SET_CFG:
504 			graph->result.opcode = result->opcode;
505 			graph->result.status = result->status;
506 			if (result->status)
507 				dev_err(dev, "Error (%d) Processing 0x%08x cmd\n",
508 					result->status, result->opcode);
509 			wake_up(&graph->cmd_wait);
510 			break;
511 		default:
512 			break;
513 		}
514 		break;
515 	default:
516 		break;
517 	}
518 	return 0;
519 }
520 
521 struct q6apm_graph *q6apm_graph_open(struct device *dev, q6apm_cb cb,
522 				     void *priv, int graph_id)
523 {
524 	struct q6apm *apm = dev_get_drvdata(dev->parent);
525 	struct audioreach_graph *ar_graph;
526 	struct q6apm_graph *graph;
527 	int ret;
528 
529 	ar_graph = q6apm_get_audioreach_graph(apm, graph_id);
530 	if (IS_ERR(ar_graph)) {
531 		dev_err(dev, "No graph found with id %d\n", graph_id);
532 		return ERR_CAST(ar_graph);
533 	}
534 
535 	graph = kzalloc(sizeof(*graph), GFP_KERNEL);
536 	if (!graph) {
537 		ret = -ENOMEM;
538 		goto put_ar_graph;
539 	}
540 
541 	graph->apm = apm;
542 	graph->priv = priv;
543 	graph->cb = cb;
544 	graph->info = ar_graph->info;
545 	graph->ar_graph = ar_graph;
546 	graph->id = ar_graph->id;
547 	graph->dev = dev;
548 
549 	mutex_init(&graph->lock);
550 	init_waitqueue_head(&graph->cmd_wait);
551 
552 	graph->port = gpr_alloc_port(apm->gdev, dev, graph_callback, graph);
553 	if (IS_ERR(graph->port)) {
554 		ret = PTR_ERR(graph->port);
555 		goto free_graph;
556 	}
557 
558 	return graph;
559 
560 free_graph:
561 	kfree(graph);
562 put_ar_graph:
563 	kref_put(&ar_graph->refcount, q6apm_put_audioreach_graph);
564 	return ERR_PTR(ret);
565 }
566 EXPORT_SYMBOL_GPL(q6apm_graph_open);
567 
568 int q6apm_graph_close(struct q6apm_graph *graph)
569 {
570 	struct audioreach_graph *ar_graph = graph->ar_graph;
571 
572 	gpr_free_port(graph->port);
573 	kref_put(&ar_graph->refcount, q6apm_put_audioreach_graph);
574 	kfree(graph);
575 
576 	return 0;
577 }
578 EXPORT_SYMBOL_GPL(q6apm_graph_close);
579 
580 int q6apm_graph_prepare(struct q6apm_graph *graph)
581 {
582 	return audioreach_graph_mgmt_cmd(graph->ar_graph, APM_CMD_GRAPH_PREPARE);
583 }
584 EXPORT_SYMBOL_GPL(q6apm_graph_prepare);
585 
586 int q6apm_graph_start(struct q6apm_graph *graph)
587 {
588 	struct audioreach_graph *ar_graph = graph->ar_graph;
589 	int ret = 0;
590 
591 	if (ar_graph->start_count == 0)
592 		ret = audioreach_graph_mgmt_cmd(ar_graph, APM_CMD_GRAPH_START);
593 
594 	ar_graph->start_count++;
595 
596 	return ret;
597 }
598 EXPORT_SYMBOL_GPL(q6apm_graph_start);
599 
600 int q6apm_graph_stop(struct q6apm_graph *graph)
601 {
602 	struct audioreach_graph *ar_graph = graph->ar_graph;
603 
604 	if (--ar_graph->start_count > 0)
605 		return 0;
606 
607 	return audioreach_graph_mgmt_cmd(ar_graph, APM_CMD_GRAPH_STOP);
608 }
609 EXPORT_SYMBOL_GPL(q6apm_graph_stop);
610 
611 int q6apm_graph_flush(struct q6apm_graph *graph)
612 {
613 	return audioreach_graph_mgmt_cmd(graph->ar_graph, APM_CMD_GRAPH_FLUSH);
614 }
615 EXPORT_SYMBOL_GPL(q6apm_graph_flush);
616 
617 static int q6apm_audio_probe(struct snd_soc_component *component)
618 {
619 	return audioreach_tplg_init(component);
620 }
621 
622 static void q6apm_audio_remove(struct snd_soc_component *component)
623 {
624 	/* remove topology */
625 	snd_soc_tplg_component_remove(component);
626 }
627 
628 #define APM_AUDIO_DRV_NAME "q6apm-audio"
629 
630 static const struct snd_soc_component_driver q6apm_audio_component = {
631 	.name		= APM_AUDIO_DRV_NAME,
632 	.probe		= q6apm_audio_probe,
633 	.remove		= q6apm_audio_remove,
634 };
635 
636 static int apm_probe(gpr_device_t *gdev)
637 {
638 	struct device *dev = &gdev->dev;
639 	struct q6apm *apm;
640 	int ret;
641 
642 	apm = devm_kzalloc(dev, sizeof(*apm), GFP_KERNEL);
643 	if (!apm)
644 		return -ENOMEM;
645 
646 	dev_set_drvdata(dev, apm);
647 
648 	mutex_init(&apm->lock);
649 	apm->dev = dev;
650 	apm->gdev = gdev;
651 	init_waitqueue_head(&apm->wait);
652 
653 	INIT_LIST_HEAD(&apm->widget_list);
654 	idr_init(&apm->graph_idr);
655 	idr_init(&apm->graph_info_idr);
656 	idr_init(&apm->sub_graphs_idr);
657 	idr_init(&apm->containers_idr);
658 
659 	idr_init(&apm->modules_idr);
660 
661 	q6apm_get_apm_state(apm);
662 
663 	ret = devm_snd_soc_register_component(dev, &q6apm_audio_component, NULL, 0);
664 	if (ret < 0) {
665 		dev_err(dev, "failed to get register q6apm: %d\n", ret);
666 		return ret;
667 	}
668 
669 	return of_platform_populate(dev->of_node, NULL, NULL, dev);
670 }
671 
672 struct audioreach_module *q6apm_find_module_by_mid(struct q6apm_graph *graph, uint32_t mid)
673 {
674 	struct audioreach_graph_info *info = graph->info;
675 	struct q6apm *apm = graph->apm;
676 
677 	return __q6apm_find_module_by_mid(apm, info, mid);
678 
679 }
680 
681 static int apm_callback(struct gpr_resp_pkt *data, void *priv, int op)
682 {
683 	gpr_device_t *gdev = priv;
684 	struct q6apm *apm = dev_get_drvdata(&gdev->dev);
685 	struct device *dev = &gdev->dev;
686 	struct gpr_ibasic_rsp_result_t *result;
687 	struct gpr_hdr *hdr = &data->hdr;
688 
689 	result = data->payload;
690 
691 	switch (hdr->opcode) {
692 	case APM_CMD_RSP_GET_SPF_STATE:
693 		apm->result.opcode = hdr->opcode;
694 		apm->result.status = 0;
695 		/* First word of result it state */
696 		apm->state = result->opcode;
697 		wake_up(&apm->wait);
698 		break;
699 	case GPR_BASIC_RSP_RESULT:
700 		switch (result->opcode) {
701 		case APM_CMD_GRAPH_START:
702 		case APM_CMD_GRAPH_OPEN:
703 		case APM_CMD_GRAPH_PREPARE:
704 		case APM_CMD_GRAPH_CLOSE:
705 		case APM_CMD_GRAPH_FLUSH:
706 		case APM_CMD_GRAPH_STOP:
707 		case APM_CMD_SET_CFG:
708 			apm->result.opcode = result->opcode;
709 			apm->result.status = result->status;
710 			if (result->status)
711 				dev_err(dev, "Error (%d) Processing 0x%08x cmd\n", result->status,
712 					result->opcode);
713 			wake_up(&apm->wait);
714 			break;
715 		default:
716 			break;
717 		}
718 		break;
719 	default:
720 		break;
721 	}
722 
723 	return 0;
724 }
725 
726 #ifdef CONFIG_OF
727 static const struct of_device_id apm_device_id[]  = {
728 	{ .compatible = "qcom,q6apm" },
729 	{},
730 };
731 MODULE_DEVICE_TABLE(of, apm_device_id);
732 #endif
733 
734 static gpr_driver_t apm_driver = {
735 	.probe = apm_probe,
736 	.gpr_callback = apm_callback,
737 	.driver = {
738 		.name = "qcom-apm",
739 		.of_match_table = of_match_ptr(apm_device_id),
740 	},
741 };
742 
743 module_gpr_driver(apm_driver);
744 MODULE_DESCRIPTION("Audio Process Manager");
745 MODULE_LICENSE("GPL");
746