blob: 545590fa3735a312e0253ff84ae9a6f848f36f81 [file] [log] [blame]
Meng Wang43bbb872018-12-10 12:32:05 +08001// SPDX-License-Identifier: GPL-2.0-only
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302/*
3 * Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304 */
5
6#include <linux/init.h>
7#include <linux/module.h>
8#include <linux/of.h>
9#include <linux/bitops.h>
10#include <linux/slimbus/slimbus.h>
11#include <sound/soc.h>
12#include <sound/pcm.h>
13#include <sound/pcm_params.h>
Laxminath Kasam605b42f2017-08-01 22:02:15 +053014#include "msm-slim-dma.h"
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053015
16#define SLIM_DEV_NAME "msm-dai-slim"
17
18#define SLIM_DAI_RATES (SNDRV_PCM_RATE_48000 | \
19 SNDRV_PCM_RATE_8000 | \
20 SNDRV_PCM_RATE_16000 | \
21 SNDRV_PCM_RATE_96000 | \
22 SNDRV_PCM_RATE_192000 | \
23 SNDRV_PCM_RATE_384000)
24
25#define SLIM_DAI_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
26 SNDRV_PCM_FMTBIT_S24_LE | \
27 SNDRV_PCM_FMTBIT_S32_LE)
28
29#define DAI_STATE_INITIALIZED (0x01 << 0)
30#define DAI_STATE_PREPARED (0x01 << 1)
31#define DAI_STATE_RUNNING (0x01 << 2)
32
33#define SET_DAI_STATE(status, state) \
34 (status |= state)
35
36#define CLR_DAI_STATE(status, state) \
37 (status = status & (~state))
38
39enum {
40 MSM_DAI_SLIM0 = 0,
41 NUM_SLIM_DAIS,
42};
43
44struct msm_slim_dai_data {
45 unsigned int dai_id;
46 u16 *chan_h;
47 u16 *sh_ch;
48 u16 grph;
49 u32 rate;
50 u16 bits;
51 u16 ch_cnt;
52 u8 status;
53 struct snd_soc_dai_driver *dai_drv;
54 struct msm_slim_dma_data dma_data;
55 struct slim_port_cfg port_cfg;
56};
57
58struct msm_dai_slim_drv_data {
59 struct slim_device *sdev;
60 u16 num_dais;
61 struct msm_slim_dai_data slim_dai_data[NUM_SLIM_DAIS];
62};
63
64struct msm_slim_dai_data *msm_slim_get_dai_data(
65 struct msm_dai_slim_drv_data *drv_data,
66 struct snd_soc_dai *dai)
67{
68 struct msm_slim_dai_data *dai_data_t;
69 int i;
70
71 for (i = 0; i < drv_data->num_dais; i++) {
72 dai_data_t = &drv_data->slim_dai_data[i];
73 if (dai_data_t->dai_id == dai->id)
74 return dai_data_t;
75 }
76
77 dev_err(dai->dev,
78 "%s: no dai data found for dai_id %d\n",
79 __func__, dai->id);
80 return NULL;
81}
82
83static int msm_dai_slim_ch_ctl(struct msm_slim_dma_data *dma_data,
84 struct snd_soc_dai *dai, bool enable)
85{
86 struct slim_device *sdev;
87 struct msm_dai_slim_drv_data *drv_data;
88 struct msm_slim_dai_data *dai_data;
89 int rc, rc1, i;
90
91 if (!dma_data || !dma_data->sdev) {
92 pr_err("%s: Invalid %s\n", __func__,
93 (!dma_data) ? "dma_data" : "slim_device");
94 return -EINVAL;
95 }
96
97 sdev = dma_data->sdev;
98 drv_data = dev_get_drvdata(&sdev->dev);
99 dai_data = msm_slim_get_dai_data(drv_data, dai);
100
101 if (!dai_data) {
102 dev_err(dai->dev,
103 "%s: Invalid dai_data for dai_id %d\n",
104 __func__, dai->id);
105 return -EINVAL;
106 }
107
108 dev_dbg(&sdev->dev,
109 "%s: enable = %s, rate = %u\n", __func__,
110 enable ? "true" : "false",
111 dai_data->rate);
112
113 if (enable) {
114 if (!(dai_data->status & DAI_STATE_PREPARED)) {
115 dev_err(&sdev->dev,
116 "%s: dai id (%d) has invalid state 0x%x\n",
117 __func__, dai->id, dai_data->status);
118 return -EINVAL;
119 }
120
121 rc = slim_alloc_mgrports(sdev,
122 SLIM_REQ_DEFAULT, dai_data->ch_cnt,
123 &(dma_data->ph),
124 sizeof(dma_data->ph));
125 if (rc < 0) {
126 dev_err(&sdev->dev,
127 "%s:alloc mgrport failed rc %d\n",
128 __func__, rc);
129 goto done;
130 }
131
132 rc = slim_config_mgrports(sdev, &(dma_data->ph),
133 dai_data->ch_cnt,
134 &(dai_data->port_cfg));
135 if (rc < 0) {
136 dev_err(&sdev->dev,
137 "%s: config mgrport failed rc %d\n",
138 __func__, rc);
139 goto err_done;
140 }
141
142 for (i = 0; i < dai_data->ch_cnt; i++) {
143 rc = slim_connect_sink(sdev,
144 &dma_data->ph, 1,
145 dai_data->chan_h[i]);
146 if (rc < 0) {
147 dev_err(&sdev->dev,
148 "%s: slim_connect_sink failed, ch = %d, err = %d\n",
149 __func__, i, rc);
150 goto err_done;
151 }
152 }
153
154 rc = slim_control_ch(sdev,
155 dai_data->grph,
156 SLIM_CH_ACTIVATE, true);
157 if (rc < 0) {
158 dev_err(&sdev->dev,
159 "%s: slim activate ch failed, err = %d\n",
160 __func__, rc);
161 goto err_done;
162 }
163 /* Mark dai status as running */
164 SET_DAI_STATE(dai_data->status, DAI_STATE_RUNNING);
165 } else {
166 if (!(dai_data->status & DAI_STATE_RUNNING)) {
167 dev_err(&sdev->dev,
168 "%s: dai id (%d) has invalid state 0x%x\n",
169 __func__, dai->id, dai_data->status);
170 return -EINVAL;
171 }
172
173 rc = slim_control_ch(sdev,
174 dai_data->grph,
175 SLIM_CH_REMOVE, true);
176 if (rc < 0) {
177 dev_err(&sdev->dev,
178 "%s: slim activate ch failed, err = %d\n",
179 __func__, rc);
180 goto done;
181 }
182
183 rc = slim_dealloc_mgrports(sdev,
184 &dma_data->ph, 1);
185 if (rc < 0) {
186 dev_err(&sdev->dev,
187 "%s: dealloc mgrport failed, err = %d\n",
188 __func__, rc);
189 goto done;
190 }
191 /* clear running state for dai*/
192 CLR_DAI_STATE(dai_data->status, DAI_STATE_RUNNING);
193 }
194
195 return rc;
196
197err_done:
198 rc1 = slim_dealloc_mgrports(sdev,
199 &dma_data->ph, 1);
200 if (rc1 < 0)
201 dev_err(&sdev->dev,
202 "%s: dealloc mgrport failed, err = %d\n",
203 __func__, rc1);
204done:
205 return rc;
206}
207
208static int msm_dai_slim_hw_params(
209 struct snd_pcm_substream *substream,
210 struct snd_pcm_hw_params *params,
211 struct snd_soc_dai *dai)
212{
213 struct msm_dai_slim_drv_data *drv_data = dev_get_drvdata(dai->dev);
214 struct msm_slim_dai_data *dai_data;
215 int rc = 0;
216
217 dai_data = msm_slim_get_dai_data(drv_data, dai);
218 if (!dai_data) {
219 dev_err(dai->dev,
220 "%s: Invalid dai_data for dai_id %d\n",
221 __func__, dai->id);
222 rc = -EINVAL;
223 goto done;
224 }
225
226 if (!dai_data->ch_cnt || dai_data->ch_cnt != params_channels(params)) {
227 dev_err(dai->dev, "%s: invalid ch_cnt %d %d\n",
228 __func__, dai_data->ch_cnt, params_channels(params));
229 rc = -EINVAL;
230 goto done;
231 }
232
233 dai_data->rate = params_rate(params);
234 dai_data->port_cfg.port_opts = SLIM_OPT_NONE;
235 if (dai_data->rate >= SNDRV_PCM_RATE_48000)
236 dai_data->port_cfg.watermark = 16;
237 else
238 dai_data->port_cfg.watermark = 8;
239
240 switch (params_format(params)) {
241 case SNDRV_PCM_FORMAT_S16_LE:
242 dai_data->bits = 16;
243 break;
244 case SNDRV_PCM_FORMAT_S24_LE:
245 dai_data->bits = 24;
246 break;
247 case SNDRV_PCM_FORMAT_S32_LE:
248 dai_data->bits = 32;
249 break;
250 default:
251 dev_err(dai->dev, "%s: invalid format %d\n", __func__,
252 params_format(params));
253 rc = -EINVAL;
254 goto done;
255 }
256
257 dev_dbg(dai->dev, "%s: ch_cnt=%u rate=%u, bit_width = %u\n",
258 __func__, dai_data->ch_cnt, dai_data->rate,
259 dai_data->bits);
260done:
261 return rc;
262}
263
264static int msm_dai_slim_set_channel_map(struct snd_soc_dai *dai,
265 unsigned int tx_num, unsigned int *tx_slot,
266 unsigned int rx_num, unsigned int *rx_slot)
267{
268 struct msm_dai_slim_drv_data *drv_data = dev_get_drvdata(dai->dev);
269 struct msm_slim_dai_data *dai_data;
270 struct snd_soc_dai_driver *dai_drv;
271 u8 i = 0;
272
273 dev_dbg(dai->dev,
274 "%s: tx_num=%u, rx_num=%u\n",
275 __func__, tx_num, rx_num);
276
277 dai_data = msm_slim_get_dai_data(drv_data, dai);
278 if (!dai_data) {
279 dev_err(dai->dev,
280 "%s: Invalid dai_data for dai_id %d\n",
281 __func__, dai->id);
282 return -EINVAL;
283 }
284
285 dai_drv = dai_data->dai_drv;
286
287 if (tx_num > dai_drv->capture.channels_max) {
288 dev_err(dai->dev, "%s: tx_num %u max out master port cnt\n",
289 __func__, tx_num);
290 return -EINVAL;
291 }
292
293 for (i = 0; i < tx_num; i++)
294 dai_data->sh_ch[i] = tx_slot[i];
295
296 dai_data->ch_cnt = tx_num;
297 return 0;
298}
299
300static int msm_dai_slim_prepare(struct snd_pcm_substream *substream,
301 struct snd_soc_dai *dai)
302{
303 struct msm_dai_slim_drv_data *drv_data = dev_get_drvdata(dai->dev);
304 struct msm_slim_dma_data *dma_data;
305 struct msm_slim_dai_data *dai_data = NULL;
306 struct slim_ch prop;
307 int rc;
308 u8 i, j;
309
310 dai_data = msm_slim_get_dai_data(drv_data, dai);
311 if (!dai_data) {
312 dev_err(dai->dev,
313 "%s: Invalid dai_data for dai %d\n",
314 __func__, dai->id);
315 return -EINVAL;
316 }
317
318 if (!(dai_data->status & DAI_STATE_INITIALIZED)) {
319 dev_err(dai->dev,
320 "%s: dai id (%d) has invalid state 0x%x\n",
321 __func__, dai->id, dai_data->status);
322 return -EINVAL;
323 }
324
325 if (dai_data->status & DAI_STATE_PREPARED) {
326 dev_dbg(dai->dev,
327 "%s: dai id (%d) has already prepared.\n",
328 __func__, dai->id);
329 return 0;
330 }
331
332 dma_data = &dai_data->dma_data;
333 snd_soc_dai_set_dma_data(dai, substream, dma_data);
334
335 for (i = 0; i < dai_data->ch_cnt; i++) {
336 rc = slim_query_ch(drv_data->sdev, dai_data->sh_ch[i],
337 &dai_data->chan_h[i]);
338 if (rc) {
339 dev_err(dai->dev, "%s:query chan handle failed rc %d\n",
340 __func__, rc);
341 goto error_chan_query;
342 }
343 }
344
345 prop.prot = SLIM_AUTO_ISO;
346 prop.baser = SLIM_RATE_4000HZ;
347 prop.dataf = SLIM_CH_DATAF_NOT_DEFINED;
348 prop.auxf = SLIM_CH_AUXF_NOT_APPLICABLE;
349 prop.ratem = (dai_data->rate/4000);
350 prop.sampleszbits = dai_data->bits;
351
352 rc = slim_define_ch(drv_data->sdev, &prop, dai_data->chan_h,
353 dai_data->ch_cnt, true, &dai_data->grph);
354
355 if (rc) {
356 dev_err(dai->dev, "%s:define chan failed rc %d\n",
357 __func__, rc);
358 goto error_define_chan;
359 }
360
361 /* Mark stream status as prepared */
362 SET_DAI_STATE(dai_data->status, DAI_STATE_PREPARED);
363
364 return rc;
365
366error_define_chan:
367error_chan_query:
368 for (j = 0; j < i; j++)
369 slim_dealloc_ch(drv_data->sdev, dai_data->chan_h[j]);
370 return rc;
371}
372
373static void msm_dai_slim_shutdown(struct snd_pcm_substream *stream,
374 struct snd_soc_dai *dai)
375{
376 struct msm_dai_slim_drv_data *drv_data = dev_get_drvdata(dai->dev);
377 struct msm_slim_dma_data *dma_data = NULL;
378 struct msm_slim_dai_data *dai_data;
379 int i, rc = 0;
380
381 dai_data = msm_slim_get_dai_data(drv_data, dai);
382 dma_data = snd_soc_dai_get_dma_data(dai, stream);
383 if (!dma_data || !dai_data) {
384 dev_err(dai->dev,
385 "%s: Invalid %s\n", __func__,
386 (!dma_data) ? "dma_data" : "dai_data");
387 return;
388 }
389
390 if ((!(dai_data->status & DAI_STATE_PREPARED)) ||
391 dai_data->status & DAI_STATE_RUNNING) {
392 dev_err(dai->dev,
393 "%s: dai id (%d) has invalid state 0x%x\n",
394 __func__, dai->id, dai_data->status);
395 return;
396 }
397
398 for (i = 0; i < dai_data->ch_cnt; i++) {
399 rc = slim_dealloc_ch(drv_data->sdev, dai_data->chan_h[i]);
400 if (rc) {
401 dev_err(dai->dev,
402 "%s: dealloc_ch failed, err = %d\n",
403 __func__, rc);
404 }
405 }
406
407 snd_soc_dai_set_dma_data(dai, stream, NULL);
408 /* clear prepared state for the dai */
409 CLR_DAI_STATE(dai_data->status, DAI_STATE_PREPARED);
410}
411
412static const struct snd_soc_component_driver msm_dai_slim_component = {
413 .name = "msm-dai-slim-cmpnt",
414};
415
416static struct snd_soc_dai_ops msm_dai_slim_ops = {
417 .prepare = msm_dai_slim_prepare,
418 .hw_params = msm_dai_slim_hw_params,
419 .shutdown = msm_dai_slim_shutdown,
420 .set_channel_map = msm_dai_slim_set_channel_map,
421};
422
423static struct snd_soc_dai_driver msm_slim_dais[] = {
424 {
425 /*
426 * The first dai name should be same as device name
427 * to support registering single and multile dais.
428 */
429 .name = SLIM_DEV_NAME,
430 .id = MSM_DAI_SLIM0,
431 .capture = {
432 .rates = SLIM_DAI_RATES,
433 .formats = SLIM_DAI_FORMATS,
434 .channels_min = 1,
435 /*
436 * max channels allowed is
437 * dependent on platform and
438 * will be updated before this
439 * dai driver is registered.
440 */
441 .channels_max = 1,
442 .rate_min = 8000,
443 .rate_max = 384000,
444 .stream_name = "SLIM_DAI0 Capture",
445 },
446 .ops = &msm_dai_slim_ops,
447 },
448 /*
449 * If multiple dais are needed,
450 * add dais here and update the
451 * dai_id enum.
452 */
453};
454
455static void msm_dai_slim_remove_dai_data(
456 struct device *dev,
457 struct msm_dai_slim_drv_data *drv_data)
458{
459 int i;
460 struct msm_slim_dai_data *dai_data_t;
461
462 for (i = 0; i < drv_data->num_dais; i++) {
463 dai_data_t = &drv_data->slim_dai_data[i];
464
465 kfree(dai_data_t->chan_h);
466 dai_data_t->chan_h = NULL;
467 kfree(dai_data_t->sh_ch);
468 dai_data_t->sh_ch = NULL;
469 }
470}
471
472static int msm_dai_slim_populate_dai_data(struct device *dev,
473 struct msm_dai_slim_drv_data *drv_data)
474{
475 struct snd_soc_dai_driver *dai_drv;
476 struct msm_slim_dai_data *dai_data_t;
477 u8 num_ch;
478 int i, j, rc;
479
480 for (i = 0; i < drv_data->num_dais; i++) {
481 num_ch = 0;
482 dai_drv = &msm_slim_dais[i];
483 num_ch += dai_drv->capture.channels_max;
484 num_ch += dai_drv->playback.channels_max;
485
486 dai_data_t = &drv_data->slim_dai_data[i];
487 dai_data_t->dai_drv = dai_drv;
488 dai_data_t->dai_id = dai_drv->id;
489 dai_data_t->dma_data.sdev = drv_data->sdev;
490 dai_data_t->dma_data.dai_channel_ctl =
491 msm_dai_slim_ch_ctl;
492 SET_DAI_STATE(dai_data_t->status,
493 DAI_STATE_INITIALIZED);
494
495 dai_data_t->chan_h = devm_kzalloc(dev,
496 sizeof(u16) * num_ch,
497 GFP_KERNEL);
498 if (!dai_data_t->chan_h) {
499 dev_err(dev,
500 "%s: DAI ID %d, Failed to alloc channel handles\n",
501 __func__, i);
502 rc = -ENOMEM;
503 goto err_mem_alloc;
504 }
505
506 dai_data_t->sh_ch = devm_kzalloc(dev,
507 sizeof(u16) * num_ch,
508 GFP_KERNEL);
509 if (!dai_data_t->sh_ch) {
510 dev_err(dev,
511 "%s: DAI ID %d, Failed to alloc sh_ch\n",
512 __func__, i);
513 rc = -ENOMEM;
514 goto err_mem_alloc;
515 }
516 }
517 return 0;
518
519err_mem_alloc:
520 for (j = 0; j < i; j++) {
521 dai_data_t = &drv_data->slim_dai_data[i];
522
523 devm_kfree(dev, dai_data_t->chan_h);
524 dai_data_t->chan_h = NULL;
525
526 devm_kfree(dev, dai_data_t->sh_ch);
527 dai_data_t->sh_ch = NULL;
528 }
529 return rc;
530}
531
532static int msm_dai_slim_dev_probe(struct slim_device *sdev)
533{
534 int rc, i;
535 u8 max_channels;
536 u32 apps_ch_pipes;
537 struct msm_dai_slim_drv_data *drv_data;
538 struct device *dev = &sdev->dev;
539 struct snd_soc_dai_driver *dai_drv;
540
541 if (!dev->of_node ||
542 !dev->of_node->parent) {
543 dev_err(dev,
544 "%s: Invalid %s\n", __func__,
545 (!dev->of_node) ? "of_node" : "parent_of_node");
546 return -EINVAL;
547 }
548
549 rc = of_property_read_u32(dev->of_node->parent,
550 "qcom,apps-ch-pipes",
551 &apps_ch_pipes);
552 if (rc) {
553 dev_err(dev,
554 "%s: Failed to lookup property %s in node %s, err = %d\n",
555 __func__, "qcom,apps-ch-pipes",
556 dev->of_node->parent->full_name, rc);
557 goto err_ret;
558 }
559
560 max_channels = hweight_long(apps_ch_pipes);
561 if (max_channels <= 0) {
562 dev_err(dev,
563 "%s: Invalid apps owned ports %d\n",
564 __func__, max_channels);
565 goto err_ret;
566 }
567
568 dev_dbg(dev, "%s: max channels = %u\n",
569 __func__, max_channels);
570
571 for (i = 0; i < ARRAY_SIZE(msm_slim_dais); i++) {
572 dai_drv = &msm_slim_dais[i];
573 dai_drv->capture.channels_max = max_channels;
574 dai_drv->playback.channels_max = max_channels;
575 }
576
577 drv_data = devm_kzalloc(dev, sizeof(*drv_data),
578 GFP_KERNEL);
579 if (!drv_data) {
580 rc = -ENOMEM;
581 goto err_ret;
582 }
583
584 drv_data->sdev = sdev;
585 drv_data->num_dais = NUM_SLIM_DAIS;
586
587 rc = msm_dai_slim_populate_dai_data(dev, drv_data);
588 if (rc) {
589 dev_err(dev,
590 "%s: failed to setup dai_data, err = %d\n",
591 __func__, rc);
592 goto err_populate_dai;
593 }
594
595 rc = snd_soc_register_component(&sdev->dev, &msm_dai_slim_component,
596 msm_slim_dais, NUM_SLIM_DAIS);
597 if (rc < 0) {
598 dev_err(dev, "%s: failed to register DAI, err = %d\n",
599 __func__, rc);
600 goto err_reg_comp;
601 }
602
603 dev_set_drvdata(dev, drv_data);
604 return rc;
605
606err_reg_comp:
607 msm_dai_slim_remove_dai_data(dev, drv_data);
608
609err_populate_dai:
610 devm_kfree(dev, drv_data);
611
612err_ret:
613 return rc;
614}
615
616static int msm_dai_slim_dev_remove(struct slim_device *sdev)
617{
618 snd_soc_unregister_component(&sdev->dev);
619 return 0;
620}
621
622static const struct slim_device_id msm_dai_slim_dt_match[] = {
623 {SLIM_DEV_NAME, 0 },
624 {}
625};
626
627static struct slim_driver msm_dai_slim_driver = {
628 .driver = {
629 .name = SLIM_DEV_NAME,
630 .owner = THIS_MODULE,
631 },
632 .probe = msm_dai_slim_dev_probe,
633 .remove = msm_dai_slim_dev_remove,
634 .id_table = msm_dai_slim_dt_match,
635};
636
Laxminath Kasam8b1366a2017-10-05 01:44:16 +0530637int __init msm_dai_slim_init(void)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530638{
639 int rc;
640
641 rc = slim_driver_register(&msm_dai_slim_driver);
642 if (rc)
643 pr_err("%s: failed to register with slimbus driver rc = %d",
644 __func__, rc);
645 return rc;
646}
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530647
Asish Bhattacharya5faacb32017-12-04 17:23:15 +0530648void msm_dai_slim_exit(void)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530649{
Laxminath Kasam8b1366a2017-10-05 01:44:16 +0530650 slim_driver_unregister(&msm_dai_slim_driver);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530651}
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530652
653/* Module information */
654MODULE_DESCRIPTION("Slimbus apps-owned channel handling driver");
655MODULE_LICENSE("GPL v2");