1 /*
2 * Copyright (c) 2022 Unionman Technology Co., Ltd.
3 *
4 * HDF is dual licensed: you can use it either under the terms of
5 * the GPL, or the BSD license, at your option.
6 * See the LICENSE file in the root of this repository for complete details.
7 */
8
9 #include "audio_host.h"
10 #include "audio_control.h"
11 #include "audio_dai_if.h"
12 #include "audio_dai_base.h"
13 #include "audio_driver_log.h"
14 #include "osal_io.h"
15 #include "audio_stream_dispatch.h"
16
17 #include "axg_snd_card.h"
18 #include "a311d_dai_ops.h"
19
20 #define HDF_LOG_TAG a311d_dai_ops
21
22 static struct axg_fifo *g_fifoDev[2];
23 static struct axg_tdm_iface *g_ifaceDev;
24
A311DDeviceInit(struct AudioCard * audioCard,const struct DaiDevice * dai)25 int32_t A311DDeviceInit(struct AudioCard *audioCard, const struct DaiDevice *dai)
26 {
27 int ret;
28 struct DaiData *data;
29
30 AUDIO_DRIVER_LOG_DEBUG("");
31 if (dai == NULL || dai->device == NULL || dai->devDaiName == NULL) {
32 AUDIO_DRIVER_LOG_ERR("input para is NULL.");
33 return HDF_ERR_INVALID_PARAM;
34 }
35 if (dai == NULL || dai->devData == NULL) {
36 AUDIO_DRIVER_LOG_ERR("dai host is NULL.");
37 return HDF_FAILURE;
38 }
39 data = dai->devData;
40 if (DaiSetConfigInfoOfControls(data) != HDF_SUCCESS) {
41 AUDIO_DRIVER_LOG_ERR("set config info fail.");
42 return HDF_FAILURE;
43 }
44
45 AUDIO_DRIVER_LOG_DEBUG("numControls:%d", data->numControls);
46
47 ret = AudioAddControls(audioCard, data->controls, data->numControls);
48 if (ret != HDF_SUCCESS) {
49 AUDIO_DRIVER_LOG_ERR("add controls failed.", data->numControls);
50 return HDF_FAILURE;
51 }
52
53 if (data->daiInitFlag == true) {
54 AUDIO_DRIVER_LOG_INFO("dai already inited.");
55 return HDF_SUCCESS;
56 }
57
58 if (meson_axg_snd_card_init()) {
59 AUDIO_DRIVER_LOG_ERR("axg_snd_card_init() failed.");
60 return HDF_FAILURE;
61 }
62
63 g_fifoDev[AUDIO_CAPTURE_STREAM] = meson_axg_default_fifo_get(1);
64 g_fifoDev[AUDIO_RENDER_STREAM] = meson_axg_default_fifo_get(0);
65
66 if (!g_fifoDev[AUDIO_CAPTURE_STREAM] || !g_fifoDev[AUDIO_RENDER_STREAM]) {
67 AUDIO_DRIVER_LOG_ERR("meson_axg_fifo_get() failed.");
68 return HDF_FAILURE;
69 }
70
71 g_ifaceDev = meson_axg_default_tdm_iface_get();
72 if (!g_ifaceDev) {
73 AUDIO_DRIVER_LOG_ERR("meson_axg_tdm_iface_get() failed.");
74 return HDF_FAILURE;
75 }
76
77 data->daiInitFlag = true;
78
79 AUDIO_DRIVER_LOG_INFO("success");
80
81 return HDF_SUCCESS;
82 }
83
A311DDeviceReadReg(const struct DaiDevice * dai,uint32_t reg,uint32_t * value)84 int32_t A311DDeviceReadReg(const struct DaiDevice *dai, uint32_t reg, uint32_t *value)
85 {
86 AUDIO_DRIVER_LOG_DEBUG("");
87 return HDF_SUCCESS;
88 }
89
A311DDeviceWriteReg(const struct DaiDevice * dai,uint32_t reg,uint32_t value)90 int32_t A311DDeviceWriteReg(const struct DaiDevice *dai, uint32_t reg, uint32_t value)
91 {
92 AUDIO_DRIVER_LOG_DEBUG("");
93 return HDF_SUCCESS;
94 }
95
A311DDaiTrigger(const struct AudioCard * card,int cmd,const struct DaiDevice * device)96 int32_t A311DDaiTrigger(const struct AudioCard *card, int cmd, const struct DaiDevice *device)
97 {
98 int32_t ret = HDF_FAILURE;
99
100 AUDIO_DRIVER_LOG_DEBUG("cmd -> %d", cmd);
101
102 switch (cmd) {
103 case AUDIO_DRV_PCM_IOCTL_RENDER_START:
104 case AUDIO_DRV_PCM_IOCTL_RENDER_RESUME:
105 ret = meson_axg_tdm_iface_prepare(g_ifaceDev, AXG_TDM_IFACE_STREAM_PLAYBACK);
106 ret |= meson_axg_tdm_iface_start(g_ifaceDev, AXG_TDM_IFACE_STREAM_PLAYBACK);
107 break;
108 case AUDIO_DRV_PCM_IOCTL_RENDER_STOP:
109 case AUDIO_DRV_PCM_IOCTL_RENDER_PAUSE:
110 ret = meson_axg_tdm_iface_unprepare(g_ifaceDev, AXG_TDM_IFACE_STREAM_PLAYBACK);
111 ret |= meson_axg_tdm_iface_stop(g_ifaceDev, AXG_TDM_IFACE_STREAM_PLAYBACK);
112 break;
113 case AUDIO_DRV_PCM_IOCTL_CAPTURE_START:
114 case AUDIO_DRV_PCM_IOCTL_CAPTURE_RESUME:
115 ret = meson_axg_tdm_iface_prepare(g_ifaceDev, AXG_TDM_IFACE_STREAM_CAPTURE);
116 ret |= meson_axg_tdm_iface_start(g_ifaceDev, AXG_TDM_IFACE_STREAM_CAPTURE);
117 break;
118 case AUDIO_DRV_PCM_IOCTL_CAPTURE_STOP:
119 case AUDIO_DRV_PCM_IOCTL_CAPTURE_PAUSE:
120 ret = meson_axg_tdm_iface_unprepare(g_ifaceDev, AXG_TDM_IFACE_STREAM_CAPTURE);
121 ret |= meson_axg_tdm_iface_stop(g_ifaceDev, AXG_TDM_IFACE_STREAM_CAPTURE);
122 break;
123 default:
124 AUDIO_DRIVER_LOG_ERR("invalid cmd");
125 break;
126 }
127
128 AUDIO_DRIVER_LOG_DEBUG(" cmd -> %d, ret -> %d", cmd, ret);
129
130 return ret;
131 }
132
A311DDaiStartup(const struct AudioCard * card,const struct DaiDevice * device)133 int32_t A311DDaiStartup(const struct AudioCard *card, const struct DaiDevice *device)
134 {
135 AUDIO_DRIVER_LOG_DEBUG("");
136
137 (void)card;
138 (void)device;
139
140 return HDF_SUCCESS;
141 }
142
FormatToBitWidth(enum AudioFormat format,uint32_t * bitWidth,uint32_t * phyBitWidth)143 static int32_t FormatToBitWidth(enum AudioFormat format, uint32_t *bitWidth, uint32_t *phyBitWidth)
144 {
145 switch (format) {
146 case AUDIO_FORMAT_TYPE_PCM_32_BIT:
147 *bitWidth = BIT_WIDTH32;
148 *phyBitWidth = BIT_WIDTH32;
149 break;
150 case AUDIO_FORMAT_TYPE_PCM_24_BIT:
151 *bitWidth = BIT_WIDTH24;
152 *phyBitWidth = BIT_WIDTH32;
153 break;
154 case AUDIO_FORMAT_TYPE_PCM_16_BIT:
155 *bitWidth = BIT_WIDTH16;
156 *phyBitWidth = BIT_WIDTH16;
157 break;
158 case AUDIO_FORMAT_TYPE_PCM_8_BIT:
159 *bitWidth = BIT_WIDTH8;
160 *phyBitWidth = BIT_WIDTH8;
161 break;
162 default:
163 return -1;
164 }
165
166 return 0;
167 }
168
A311DDaiHwParams(const struct AudioCard * card,const struct AudioPcmHwParams * param)169 int32_t A311DDaiHwParams(const struct AudioCard *card, const struct AudioPcmHwParams *param)
170 {
171 int32_t ret;
172 uint32_t bitWidth, phyBitWidth;
173 enum axg_tdm_iface_stream tdmStreamType;
174 struct axg_pcm_hw_params hwParam = {0};
175 struct axg_fifo *fifo;
176
177 if (card == NULL || card->rtd == NULL || card->rtd->cpuDai == NULL ||
178 param == NULL || param->cardServiceName == NULL) {
179 AUDIO_DRIVER_LOG_ERR("input para is nullptr.");
180 return HDF_FAILURE;
181 }
182
183 AUDIO_DRIVER_LOG_DEBUG("streamType: %d", param->streamType);
184
185 if (FormatToBitWidth(param->format, &bitWidth, &phyBitWidth)) {
186 AUDIO_DRIVER_LOG_ERR("FormatToBitWidth() failed.");
187 return HDF_FAILURE;
188 }
189
190 struct DaiData *data = DaiDataFromCard(card);
191
192 tdmStreamType = (param->streamType == AUDIO_RENDER_STREAM) ?
193 AXG_TDM_IFACE_STREAM_PLAYBACK : AXG_TDM_IFACE_STREAM_CAPTURE;
194 fifo = g_fifoDev[param->streamType];
195
196 hwParam.bit_width = bitWidth;
197 hwParam.channels = param->channels;
198 hwParam.physical_width = phyBitWidth;
199 hwParam.rate = param->rate;
200
201 ret = meson_axg_fifo_pcm_close(fifo);
202 ret |= meson_axg_fifo_pcm_open(fifo);
203 if (ret) {
204 AUDIO_DRIVER_LOG_ERR("meson_axg_fifo_pcm_open() failed.");
205 return HDF_FAILURE;
206 }
207
208 if (meson_axg_fifo_dai_hw_params(fifo, hwParam.bit_width,
209 hwParam.physical_width)) {
210 AUDIO_DRIVER_LOG_ERR("meson_axg_fifo_dai_hw_params() failed.");
211 return HDF_FAILURE;
212 }
213
214 if (meson_axg_tdm_iface_hw_params(g_ifaceDev, tdmStreamType, &hwParam)) {
215 AUDIO_DRIVER_LOG_ERR("meson_axg_tdm_iface_hw_params() failed.");
216 return HDF_FAILURE;
217 }
218
219 data->pcmInfo.channels = param->channels;
220 data->pcmInfo.bitWidth = bitWidth;
221 data->pcmInfo.rate = param->rate;
222 data->pcmInfo.streamType = param->streamType;
223
224 AUDIO_DRIVER_LOG_DEBUG("success");
225 return HDF_SUCCESS;
226 }
227