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