1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Copyright (C) ST-Ericsson SA 2012 |
4 | * |
5 | * Author: Ola Lilja <ola.o.lilja@stericsson.com>, |
6 | * Roger Nilsson <roger.xr.nilsson@stericsson.com> |
7 | * for ST-Ericsson. |
8 | */ |
9 | |
10 | #include <asm/page.h> |
11 | |
12 | #include <linux/module.h> |
13 | #include <linux/dma-mapping.h> |
14 | #include <linux/dmaengine.h> |
15 | #include <linux/slab.h> |
16 | |
17 | #include <sound/pcm.h> |
18 | #include <sound/pcm_params.h> |
19 | #include <sound/soc.h> |
20 | #include <sound/dmaengine_pcm.h> |
21 | |
22 | #include "ux500_msp_i2s.h" |
23 | #include "ux500_pcm.h" |
24 | |
25 | #define UX500_PLATFORM_PERIODS_BYTES_MIN 128 |
26 | #define UX500_PLATFORM_PERIODS_BYTES_MAX (64 * PAGE_SIZE) |
27 | #define UX500_PLATFORM_PERIODS_MIN 2 |
28 | #define UX500_PLATFORM_PERIODS_MAX 48 |
29 | #define UX500_PLATFORM_BUFFER_BYTES_MAX (2048 * PAGE_SIZE) |
30 | |
31 | static int ux500_pcm_prepare_slave_config(struct snd_pcm_substream *substream, |
32 | struct snd_pcm_hw_params *params, |
33 | struct dma_slave_config *slave_config) |
34 | { |
35 | struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); |
36 | struct snd_dmaengine_dai_dma_data *snd_dma_params; |
37 | dma_addr_t dma_addr; |
38 | int ret; |
39 | |
40 | snd_dma_params = snd_soc_dai_get_dma_data(snd_soc_rtd_to_cpu(rtd, 0), substream); |
41 | dma_addr = snd_dma_params->addr; |
42 | |
43 | ret = snd_hwparams_to_dma_slave_config(substream, params, slave_config); |
44 | if (ret) |
45 | return ret; |
46 | |
47 | slave_config->dst_maxburst = 4; |
48 | slave_config->src_maxburst = 4; |
49 | |
50 | slave_config->src_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; |
51 | slave_config->dst_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; |
52 | |
53 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
54 | slave_config->dst_addr = dma_addr; |
55 | else |
56 | slave_config->src_addr = dma_addr; |
57 | |
58 | return 0; |
59 | } |
60 | |
61 | static const struct snd_dmaengine_pcm_config ux500_dmaengine_of_pcm_config = { |
62 | .prepare_slave_config = ux500_pcm_prepare_slave_config, |
63 | }; |
64 | |
65 | int ux500_pcm_register_platform(struct platform_device *pdev) |
66 | { |
67 | int ret; |
68 | |
69 | ret = snd_dmaengine_pcm_register(dev: &pdev->dev, |
70 | config: &ux500_dmaengine_of_pcm_config, flags: 0); |
71 | if (ret < 0) { |
72 | dev_err(&pdev->dev, |
73 | "%s: ERROR: Failed to register platform '%s' (%d)!\n" , |
74 | __func__, pdev->name, ret); |
75 | return ret; |
76 | } |
77 | |
78 | return 0; |
79 | } |
80 | EXPORT_SYMBOL_GPL(ux500_pcm_register_platform); |
81 | |
82 | int ux500_pcm_unregister_platform(struct platform_device *pdev) |
83 | { |
84 | snd_dmaengine_pcm_unregister(dev: &pdev->dev); |
85 | return 0; |
86 | } |
87 | EXPORT_SYMBOL_GPL(ux500_pcm_unregister_platform); |
88 | |
89 | MODULE_AUTHOR("Ola Lilja" ); |
90 | MODULE_AUTHOR("Roger Nilsson" ); |
91 | MODULE_DESCRIPTION("ASoC UX500 driver" ); |
92 | MODULE_LICENSE("GPL v2" ); |
93 | |