1 /*
2 * Copyright (c) 2019-2025 Allwinner Technology Co., Ltd. ALL rights reserved.
3 *
4 * Allwinner is a trademark of Allwinner Technology Co.,Ltd., registered in
5 * the the people's Republic of China and other countries.
6 * All Allwinner Technology Co.,Ltd. trademarks are used with permission.
7 *
8 * DISCLAIMER
9 * THIRD PARTY LICENCES MAY BE REQUIRED TO IMPLEMENT THE SOLUTION/PRODUCT.
10 * IF YOU NEED TO INTEGRATE THIRD PARTY’S TECHNOLOGY (SONY, DTS, DOLBY, AVS OR MPEGLA, ETC.)
11 * IN ALLWINNERS’SDK OR PRODUCTS, YOU SHALL BE SOLELY RESPONSIBLE TO OBTAIN
12 * ALL APPROPRIATELY REQUIRED THIRD PARTY LICENCES.
13 * ALLWINNER SHALL HAVE NO WARRANTY, INDEMNITY OR OTHER OBLIGATIONS WITH RESPECT TO MATTERS
14 * COVERED UNDER ANY REQUIRED THIRD PARTY LICENSE.
15 * YOU ARE SOLELY RESPONSIBLE FOR YOUR USAGE OF THIRD PARTY’S TECHNOLOGY.
16 *
17 *
18 * THIS SOFTWARE IS PROVIDED BY ALLWINNER"AS IS" AND TO THE MAXIMUM EXTENT
19 * PERMITTED BY LAW, ALLWINNER EXPRESSLY DISCLAIMS ALL WARRANTIES OF ANY KIND,
20 * WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING WITHOUT LIMITATION REGARDING
21 * THE TITLE, NON-INFRINGEMENT, ACCURACY, CONDITION, COMPLETENESS, PERFORMANCE
22 * OR MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
23 * IN NO EVENT SHALL ALLWINNER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26 * LOSS OF USE, DATA, OR PROFITS, OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
28 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
30 * OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32 #include <stdio.h>
33 #include <string.h>
34 #include <hal_dma.h>
35 #include <sound/snd_core.h>
36 #include <sound/snd_pcm.h>
37 /* #include <sound/sunxi-codec.h> */
38 #include "../codecs/sunxi-codec.h"
39 #include "sunxi-pcm.h"
40
41 struct sunxi_cpudai_info {
42 struct sunxi_dma_params playback_dma_param;
43 struct sunxi_dma_params capture_dma_param;
44 };
45
sunxi_cpudai_platform_probe(struct snd_platform * platform)46 static int sunxi_cpudai_platform_probe(struct snd_platform *platform)
47 {
48 struct sunxi_cpudai_info *info = NULL;
49
50 snd_print("\n");
51 if (!platform->cpu_dai)
52 return -1;
53
54 info = snd_malloc(sizeof(struct sunxi_cpudai_info));
55 if (!info) {
56 snd_err("no memory\n");
57 return -ENOMEM;
58 }
59 platform->private_data = (void *)info;
60 /* dma para */
61 info->playback_dma_param.dma_addr = (dma_addr_t)(SUNXI_CODEC_BASE_ADDR + SUNXI_DAC_TXDATA);
62 info->playback_dma_param.dma_drq_type_num = DRQDST_AUDIO_CODEC;
63 info->playback_dma_param.dst_maxburst = 4;
64 info->playback_dma_param.src_maxburst = 4;
65
66 info->capture_dma_param.dma_addr = (dma_addr_t)(SUNXI_CODEC_BASE_ADDR + SUNXI_ADC_RXDATA);
67 info->capture_dma_param.dma_drq_type_num = DRQSRC_AUDIO_CODEC;
68 info->capture_dma_param.dst_maxburst = 4;
69 info->capture_dma_param.src_maxburst = 4;
70
71 platform->cpu_dai->component = platform;
72
73 return 0;
74 }
75
sunxi_cpudai_platform_remove(struct snd_platform * platform)76 static int sunxi_cpudai_platform_remove(struct snd_platform *platform)
77 {
78 struct sunxi_cpudai_info *info = NULL;
79
80 snd_print("\n");
81 info = platform->private_data;
82 snd_free(info);
83 platform->private_data = NULL;
84 return 0;
85 }
86
sunxi_cpudai_startup(struct snd_pcm_substream * substream,struct snd_dai * dai)87 static int sunxi_cpudai_startup(struct snd_pcm_substream *substream,
88 struct snd_dai *dai)
89 {
90 struct snd_platform *platform = snd_soc_dai_get_component(dai);
91 struct sunxi_cpudai_info *info = platform->private_data;
92
93 snd_print("\n");
94 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
95 dai->playback_dma_data = &info->playback_dma_param;
96 else
97 dai->capture_dma_data = &info->capture_dma_param;
98
99 return 0;
100 }
101 #if 0
102 static int sunxi_cpudai_probe(struct snd_dai *dai)
103 {
104 dai->playback_dma_data = 0;
105 dai->capture_dma_data = 0;
106 }
107 #endif
108
109 static struct snd_dai_ops sunxi_cpudai_dai_ops = {
110 .startup = sunxi_cpudai_startup,
111 };
112
113 static struct snd_dai sunxi_cpudai = {
114 .id = 1,
115 .name = "audiocodec-cpudai",
116 /*.probe = sunxi_cpudai_probe,*/
117 .playback = {
118 .stream_name = "Playback",
119 .channels_min = 1,
120 .channels_max = 2,
121 .rates = SNDRV_PCM_RATE_8000_192000
122 | SNDRV_PCM_RATE_KNOT,
123 .formats = SNDRV_PCM_FMTBIT_S16_LE
124 | SNDRV_PCM_FMTBIT_S24_LE
125 | SNDRV_PCM_FMTBIT_S32_LE,
126 .rate_min = 8000,
127 .rate_max = 192000,
128 },
129 .capture = {
130 .stream_name = "Capture",
131 .channels_min = 1,
132 .channels_max = 4,
133 .rates = SNDRV_PCM_RATE_8000_48000
134 | SNDRV_PCM_RATE_KNOT,
135 .formats = SNDRV_PCM_FMTBIT_S16_LE
136 | SNDRV_PCM_FMTBIT_S24_LE,
137 .rate_min = 8000,
138 .rate_max = 48000,
139 },
140 .ops = &sunxi_cpudai_dai_ops,
141 };
142
143 #if 0
144 struct snd_platform gAudioCodecPlatform = {
145 .name = "audiocodec-cpudai",
146 .ops = &sunxi_pcm_ops,
147 .pcm_new = sunxi_pcm_new,
148 .pcm_free = sunxi_pcm_free,
149 .cpu_dai = &sunxi_cpudai,
150 .private_data = NULL,
151 };
152 #endif
153
snd_platform_cpudai_register(struct snd_platform * platform,int arg)154 int snd_platform_cpudai_register(struct snd_platform *platform, int arg)
155 {
156 int ret = 0;
157
158 platform->name = strdup("audiocodec-platform");
159 platform->ops = &sunxi_pcm_ops;
160 platform->pcm_new = sunxi_pcm_new;
161 platform->pcm_free = sunxi_pcm_free;
162 platform->cpu_dai = snd_malloc(sizeof(struct snd_dai));
163 if (!platform->cpu_dai) {
164 snd_err("cpu_dai malloc failed.\n");
165 ret = -ENOMEM;
166 goto err_cpu_dai_malloc;
167 }
168 memcpy(platform->cpu_dai, &sunxi_cpudai, sizeof(struct snd_dai));
169
170 platform->probe = sunxi_cpudai_platform_probe;
171 platform->remove = sunxi_cpudai_platform_remove;
172
173 return 0;
174
175 err_cpu_dai_malloc:
176 snd_free(platform->name);
177 return ret;
178 }
179