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