]>
Commit | Line | Data |
---|---|---|
d2912cb1 | 1 | // SPDX-License-Identifier: GPL-2.0-only |
01a0c113 OL |
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 | * License terms: | |
01a0c113 OL |
10 | */ |
11 | ||
12 | #include <asm/page.h> | |
13 | ||
14 | #include <linux/module.h> | |
15 | #include <linux/dma-mapping.h> | |
16 | #include <linux/dmaengine.h> | |
17 | #include <linux/slab.h> | |
865fab60 | 18 | #include <linux/platform_data/dma-ste-dma40.h> |
01a0c113 OL |
19 | |
20 | #include <sound/pcm.h> | |
21 | #include <sound/pcm_params.h> | |
22 | #include <sound/soc.h> | |
23 | #include <sound/dmaengine_pcm.h> | |
24 | ||
25 | #include "ux500_msp_i2s.h" | |
26 | #include "ux500_pcm.h" | |
27 | ||
69b6f196 LPC |
28 | #define UX500_PLATFORM_PERIODS_BYTES_MIN 128 |
29 | #define UX500_PLATFORM_PERIODS_BYTES_MAX (64 * PAGE_SIZE) | |
30 | #define UX500_PLATFORM_PERIODS_MIN 2 | |
31 | #define UX500_PLATFORM_PERIODS_MAX 48 | |
32 | #define UX500_PLATFORM_BUFFER_BYTES_MAX (2048 * PAGE_SIZE) | |
01a0c113 | 33 | |
22f38f79 | 34 | static const struct snd_pcm_hardware ux500_pcm_hw = { |
01a0c113 OL |
35 | .info = SNDRV_PCM_INFO_INTERLEAVED | |
36 | SNDRV_PCM_INFO_MMAP | | |
37 | SNDRV_PCM_INFO_RESUME | | |
38 | SNDRV_PCM_INFO_PAUSE, | |
01a0c113 OL |
39 | .buffer_bytes_max = UX500_PLATFORM_BUFFER_BYTES_MAX, |
40 | .period_bytes_min = UX500_PLATFORM_PERIODS_BYTES_MIN, | |
41 | .period_bytes_max = UX500_PLATFORM_PERIODS_BYTES_MAX, | |
42 | .periods_min = UX500_PLATFORM_PERIODS_MIN, | |
43 | .periods_max = UX500_PLATFORM_PERIODS_MAX, | |
44 | }; | |
45 | ||
22f38f79 LPC |
46 | static struct dma_chan *ux500_pcm_request_chan(struct snd_soc_pcm_runtime *rtd, |
47 | struct snd_pcm_substream *substream) | |
01a0c113 | 48 | { |
01a0c113 | 49 | struct snd_soc_dai *dai = rtd->cpu_dai; |
01a0c113 OL |
50 | u16 per_data_width, mem_data_width; |
51 | struct stedma40_chan_cfg *dma_cfg; | |
22f38f79 | 52 | struct ux500_msp_dma_params *dma_params; |
01a0c113 | 53 | |
22f38f79 LPC |
54 | dma_params = snd_soc_dai_get_dma_data(dai, substream); |
55 | dma_cfg = dma_params->dma_cfg; | |
01a0c113 | 56 | |
43f2e1a3 | 57 | mem_data_width = DMA_SLAVE_BUSWIDTH_2_BYTES; |
01a0c113 | 58 | |
01a0c113 OL |
59 | switch (dma_params->data_size) { |
60 | case 32: | |
43f2e1a3 | 61 | per_data_width = DMA_SLAVE_BUSWIDTH_4_BYTES; |
01a0c113 OL |
62 | break; |
63 | case 16: | |
43f2e1a3 | 64 | per_data_width = DMA_SLAVE_BUSWIDTH_2_BYTES; |
01a0c113 OL |
65 | break; |
66 | case 8: | |
43f2e1a3 | 67 | per_data_width = DMA_SLAVE_BUSWIDTH_1_BYTE; |
01a0c113 OL |
68 | break; |
69 | default: | |
43f2e1a3 | 70 | per_data_width = DMA_SLAVE_BUSWIDTH_4_BYTES; |
01a0c113 OL |
71 | } |
72 | ||
01a0c113 OL |
73 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { |
74 | dma_cfg->src_info.data_width = mem_data_width; | |
75 | dma_cfg->dst_info.data_width = per_data_width; | |
76 | } else { | |
77 | dma_cfg->src_info.data_width = per_data_width; | |
78 | dma_cfg->dst_info.data_width = mem_data_width; | |
79 | } | |
80 | ||
22f38f79 | 81 | return snd_dmaengine_pcm_request_channel(stedma40_filter, dma_cfg); |
01a0c113 OL |
82 | } |
83 | ||
eef6473f FB |
84 | static int ux500_pcm_prepare_slave_config(struct snd_pcm_substream *substream, |
85 | struct snd_pcm_hw_params *params, | |
86 | struct dma_slave_config *slave_config) | |
87 | { | |
88 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | |
f6c37752 LJ |
89 | struct msp_i2s_platform_data *pdata = rtd->cpu_dai->dev->platform_data; |
90 | struct snd_dmaengine_dai_dma_data *snd_dma_params; | |
91 | struct ux500_msp_dma_params *ste_dma_params; | |
92 | dma_addr_t dma_addr; | |
eef6473f FB |
93 | int ret; |
94 | ||
f6c37752 LJ |
95 | if (pdata) { |
96 | ste_dma_params = | |
97 | snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); | |
98 | dma_addr = ste_dma_params->tx_rx_addr; | |
99 | } else { | |
100 | snd_dma_params = | |
101 | snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); | |
102 | dma_addr = snd_dma_params->addr; | |
103 | } | |
eef6473f FB |
104 | |
105 | ret = snd_hwparams_to_dma_slave_config(substream, params, slave_config); | |
106 | if (ret) | |
107 | return ret; | |
108 | ||
109 | slave_config->dst_maxburst = 4; | |
eef6473f | 110 | slave_config->src_maxburst = 4; |
609a3050 LJ |
111 | |
112 | slave_config->src_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; | |
113 | slave_config->dst_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; | |
eef6473f FB |
114 | |
115 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | |
f6c37752 | 116 | slave_config->dst_addr = dma_addr; |
eef6473f | 117 | else |
f6c37752 | 118 | slave_config->src_addr = dma_addr; |
eef6473f FB |
119 | |
120 | return 0; | |
121 | } | |
122 | ||
22f38f79 LPC |
123 | static const struct snd_dmaengine_pcm_config ux500_dmaengine_pcm_config = { |
124 | .pcm_hardware = &ux500_pcm_hw, | |
125 | .compat_request_channel = ux500_pcm_request_chan, | |
126 | .prealloc_buffer_size = 128 * 1024, | |
eef6473f | 127 | .prepare_slave_config = ux500_pcm_prepare_slave_config, |
01a0c113 OL |
128 | }; |
129 | ||
86a3fdfc LJ |
130 | static const struct snd_dmaengine_pcm_config ux500_dmaengine_of_pcm_config = { |
131 | .compat_request_channel = ux500_pcm_request_chan, | |
132 | .prepare_slave_config = ux500_pcm_prepare_slave_config, | |
133 | }; | |
134 | ||
da794876 | 135 | int ux500_pcm_register_platform(struct platform_device *pdev) |
01a0c113 | 136 | { |
86a3fdfc LJ |
137 | const struct snd_dmaengine_pcm_config *pcm_config; |
138 | struct device_node *np = pdev->dev.of_node; | |
01a0c113 OL |
139 | int ret; |
140 | ||
86a3fdfc LJ |
141 | if (np) |
142 | pcm_config = &ux500_dmaengine_of_pcm_config; | |
143 | else | |
144 | pcm_config = &ux500_dmaengine_pcm_config; | |
145 | ||
146 | ret = snd_dmaengine_pcm_register(&pdev->dev, pcm_config, | |
86a3fdfc | 147 | SND_DMAENGINE_PCM_FLAG_COMPAT); |
01a0c113 OL |
148 | if (ret < 0) { |
149 | dev_err(&pdev->dev, | |
150 | "%s: ERROR: Failed to register platform '%s' (%d)!\n", | |
151 | __func__, pdev->name, ret); | |
152 | return ret; | |
153 | } | |
154 | ||
155 | return 0; | |
156 | } | |
1428c20f | 157 | EXPORT_SYMBOL_GPL(ux500_pcm_register_platform); |
01a0c113 | 158 | |
da794876 | 159 | int ux500_pcm_unregister_platform(struct platform_device *pdev) |
01a0c113 | 160 | { |
22f38f79 | 161 | snd_dmaengine_pcm_unregister(&pdev->dev); |
01a0c113 OL |
162 | return 0; |
163 | } | |
1428c20f | 164 | EXPORT_SYMBOL_GPL(ux500_pcm_unregister_platform); |
1783c9d7 AB |
165 | |
166 | MODULE_AUTHOR("Ola Lilja"); | |
167 | MODULE_AUTHOR("Roger Nilsson"); | |
168 | MODULE_DESCRIPTION("ASoC UX500 driver"); | |
169 | MODULE_LICENSE("GPL v2"); |