• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021–2022 Beijing OSWare Technology Co., Ltd
3  * This file contains confidential and proprietary information of
4  * OSWare Technology Co., Ltd
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18 
19 #include <sound/soc.h>
20 #include <sound/jack.h>
21 #include <sound/control.h>
22 #include <sound/pcm_params.h>
23 #include <sound/soc-dapm.h>
24 #include <linux/clk.h>
25 #include <linux/clk/clk-conf.h>
26 #include <linux/module.h>
27 #include <linux/of_platform.h>
28 #include <linux/i2c.h>
29 #include <linux/of_gpio.h>
30 #include <linux/slab.h>
31 #include <linux/gpio.h>
32 #include <linux/pinctrl/consumer.h>
33 #include <linux/mfd/syscon.h>
34 
35 #include "imx8mm_common.h"
36 #include "audio_core.h"
37 #include "audio_driver_log.h"
38 #include "osal_io.h"
39 #include "audio_dai_base.h"
40 #include "audio_platform_base.h"
41 #include "imx8mm_platform_ops.h"
42 #include "dma_driver.h"
43 
44 #define HDF_LOG_TAG imx8mm_dai_adapter
45 
46 #define DAI_FIND_NEXT 0
47 #define DAI_FIND_SUCCESS 2
48 
49 #define    AUDIO_DRV_PCM_IOCTL_RENDER_START   5
50 #define    AUDIO_DRV_PCM_IOCTL_RENDER_STOP    6
51 #define    AUDIO_DRV_PCM_IOCTL_CAPTURE_START  7
52 #define    AUDIO_DRV_PCM_IOCTL_CAPTURE_STOP   8
53 #define    AUDIO_DRV_PCM_IOCTL_RENDER_PAUSE   9
54 #define    AUDIO_DRV_PCM_IOCTL_CAPTURE_PAUSE  10
55 #define    AUDIO_DRV_PCM_IOCTL_RENDER_RESUME  11
56 #define    AUDIO_DRV_PCM_IOCTL_CAPTURE_RESUME 12
57 
58 #define TRIGGER_TX                     (0)
59 #define TRIGGER_RX                     (1)
60 #define TRIGGER_START                  (0)
61 #define TRIGGER_STOP                   (1)
62 
63 struct PrivDaiData {
64     struct platform_device *pdev;
65     const char *dai_dev_name;
66     struct clk *mclk;
67     struct regmap *gpr;
68 };
69 
70 extern int32_t DaiHwParams(const struct AudioCard *card, const struct AudioPcmHwParams *param);
71 extern int32_t DaiTrigger(const struct AudioCard *card, int cmd, const struct DaiDevice *device);
72 extern int32_t DaiDeviceInit(struct AudioCard *audioCard, const struct DaiDevice *dai);
73 extern int32_t SaiTrigger(const struct DaiData *pd, int cmd, int isTx);
74 extern int32_t SaiRuntimeSuspend(const struct DaiData *daiData);
75 extern int32_t SaiHwFree(const struct DaiData *pd, int isTx);
76 
77 struct AudioDaiOps g_dai_device_ops = {
78     .HwParams = DaiHwParams,
79     .Trigger = DaiTrigger,
80 };
81 
82 struct DaiData g_dai_data = {
83     .DaiInit = DaiDeviceInit,
84     .ops = &g_dai_device_ops,
85 };
86 
87 
DaiDriverBind(struct HdfDeviceObject * device)88 static int32_t DaiDriverBind(struct HdfDeviceObject *device)
89 {
90     struct DaiHost *daiHost = NULL;
91     AUDIO_DRIVER_LOG_DEBUG("entry!");
92 
93     if (device == NULL) {
94         AUDIO_DRIVER_LOG_ERR("input para is NULL.");
95         return HDF_FAILURE;
96     }
97 
98     daiHost = (struct DaiHost *)OsalMemCalloc(sizeof(*daiHost));
99     if (daiHost == NULL) {
100         AUDIO_DRIVER_LOG_ERR("malloc host fail!");
101         return HDF_FAILURE;
102     }
103 
104     daiHost->device = device;
105     g_dai_data.daiInitFlag = false;
106     device->service = &daiHost->service;
107 
108     AUDIO_DRIVER_LOG_ERR("success!");
109     return HDF_SUCCESS;
110 }
111 
DaiDeviceInit(struct AudioCard * audioCard,const struct DaiDevice * dai)112 int32_t DaiDeviceInit(struct AudioCard *audioCard, const struct DaiDevice *dai)
113 {
114     struct DaiHost *daiHost = NULL;
115 
116     if (dai == NULL || dai->device == NULL || dai->devDaiName == NULL) {
117         AUDIO_DRIVER_LOG_ERR("dai is nullptr.");
118         return HDF_FAILURE;
119     }
120 
121     AUDIO_DRIVER_LOG_ERR("cpu dai device name: %s\n", dai->devDaiName);
122     (void)audioCard;
123 
124     daiHost = (struct DaiHost *)dai->device->service;
125     if (daiHost == NULL) {
126         AUDIO_DRIVER_LOG_ERR("dai host is NULL.");
127         return HDF_FAILURE;
128     }
129 
130     if (g_dai_data.daiInitFlag == true) {
131         AUDIO_DRIVER_LOG_DEBUG("dai init complete!");
132         return HDF_SUCCESS;
133     }
134 
135     g_dai_data.daiInitFlag = true;
136 
137     return HDF_SUCCESS;
138 }
139 
CheckSampleRate(unsigned int sampleRates)140 static int32_t CheckSampleRate(unsigned int sampleRates)
141 {
142     bool checkSampleRate = (sampleRates == AUDIO_SAMPLE_RATE_8000 ||
143                            sampleRates == AUDIO_SAMPLE_RATE_12000 ||
144                            sampleRates == AUDIO_SAMPLE_RATE_11025 ||
145                            sampleRates == AUDIO_SAMPLE_RATE_16000 ||
146                            sampleRates == AUDIO_SAMPLE_RATE_22050 ||
147                            sampleRates == AUDIO_SAMPLE_RATE_24000 ||
148                            sampleRates == AUDIO_SAMPLE_RATE_32000 ||
149                            sampleRates == AUDIO_SAMPLE_RATE_44100 ||
150                            sampleRates == AUDIO_SAMPLE_RATE_48000 ||
151                            sampleRates == AUDIO_SAMPLE_RATE_64000 ||
152                            sampleRates == AUDIO_SAMPLE_RATE_96000);
153     if (checkSampleRate) {
154         return HDF_SUCCESS;
155     } else {
156         AUDIO_DRIVER_LOG_ERR("FramatToSampleRate fail: Invalid sampling rate: %d.", sampleRates);
157         return HDF_ERR_NOT_SUPPORT;
158     }
159 }
160 
DaiHwParams(const struct AudioCard * card,const struct AudioPcmHwParams * param)161 int32_t DaiHwParams(const struct AudioCard *card, const struct AudioPcmHwParams *param)
162 {
163     struct DaiHost *daiHost = NULL;
164     struct PrivDaiData *pdd = NULL;
165     int ret = 0;
166 
167     AUDIO_DRIVER_LOG_DEBUG("entry.");
168 
169     if (card == NULL || card->rtd == NULL || card->rtd->platform == NULL ||
170         param == NULL || param->cardServiceName == NULL) {
171         AUDIO_DRIVER_LOG_ERR("input para is nullptr.");
172         return HDF_FAILURE;
173     }
174 
175     ret = CheckSampleRate(param->rate);
176     if (ret != HDF_SUCCESS) {
177         AUDIO_DRIVER_LOG_ERR("CheckSampleRate:  fail.");
178         return HDF_ERR_NOT_SUPPORT;
179     }
180 
181     daiHost = (struct DaiHost *)card->rtd->cpuDai->device->service;
182     if (daiHost == NULL) {
183         AUDIO_DRIVER_LOG_ERR("platformHost is nullptr.");
184         return HDF_FAILURE;
185     }
186 
187     pdd = (struct PrivDaiData *)daiHost->priv;
188     if (pdd == NULL) {
189         AUDIO_DRIVER_LOG_ERR("daiHost is null");
190         return HDF_FAILURE;
191     }
192 
193     if (pdd->mclk) {
194         AUDIO_DRIVER_LOG_ERR("enable mclk");
195     } else {
196         AUDIO_DRIVER_LOG_ERR("daihost mclk nullptr");
197         return HDF_FAILURE;
198     }
199 
200     if (ret) {
201         AUDIO_DRIVER_LOG_ERR("mclk enable failed");
202         return HDF_FAILURE;
203     }
204 
205     struct DaiData *data = DaiDataFromCard(card);
206     if (data == NULL) {
207         AUDIO_DRIVER_LOG_ERR("platformHost is nullptr.");
208         return HDF_FAILURE;
209     }
210 
211     data->pcmInfo.channels = param->channels;
212     data->pcmInfo.rate = param->rate;
213     data->pcmInfo.streamType = param->streamType;
214 
215     return HDF_SUCCESS;
216 }
217 
DaiTriggerDMAInit(struct PlatformData * pData)218 static int DaiTriggerDMAInit(struct PlatformData *pData)
219 {
220     int32_t ret = 0;
221 
222     if (pData == NULL) {
223         return HDF_FAILURE;
224     }
225 
226     if (pData->renderBufInfo.virtAddr == NULL) {
227         ret = DMAInitTxBuff(pData);
228         if (ret != HDF_SUCCESS) {
229             AUDIO_DRIVER_LOG_ERR("DMAAoInit: fail");
230             return HDF_FAILURE;
231         }
232         ret = DMAConfigTxBuff(pData);
233         if (ret != HDF_SUCCESS) {
234             AUDIO_DRIVER_LOG_ERR("DMAAoInit: fail");
235             return HDF_FAILURE;
236         }
237     }
238 
239     return ret;
240 }
241 
242 
243 extern int32_t g_dmaRequestChannel;
DaiTrigger(const struct AudioCard * card,int cmd,const struct DaiDevice * device)244 int32_t DaiTrigger(const struct AudioCard *card, int cmd, const struct DaiDevice *device)
245 {
246     struct DaiData *data = device->devData;
247     bool tx = data->pcmInfo.streamType == AUDIO_CAPTURE_STREAM;
248     int32_t ret = 0;
249     struct PlatformData *pData = PlatformDataFromCard(card);
250 
251     switch (cmd) {
252         case AUDIO_DRV_PCM_IOCTL_RENDER_START:
253         case AUDIO_DRV_PCM_IOCTL_CAPTURE_START:
254         case AUDIO_DRV_PCM_IOCTL_RENDER_RESUME:
255         case AUDIO_DRV_PCM_IOCTL_CAPTURE_RESUME:
256             if (g_dmaRequestChannel == 0) {
257                 Imx8mmDmaRequestChannel(pData, data->pcmInfo.streamType);
258 
259                 DaiTriggerDMAInit(pData);
260 
261                 ret = DMAEnableTx(pData);
262                 if (ret != HDF_SUCCESS) {
263                     AUDIO_DRIVER_LOG_ERR("DMAEnableTx failed");
264                     return HDF_FAILURE;
265                 }
266             }
267 
268             g_dmaRequestChannel = 0;
269             ret = SaiTrigger(data, TRIGGER_START, tx);
270             if (ret != HDF_SUCCESS) {
271                 AUDIO_DRIVER_LOG_ERR("SaiTrigger failed");
272                 return HDF_FAILURE;
273             }
274             break;
275         case AUDIO_DRV_PCM_IOCTL_RENDER_STOP:
276         case AUDIO_DRV_PCM_IOCTL_CAPTURE_STOP:
277         case AUDIO_DRV_PCM_IOCTL_RENDER_PAUSE:
278         case AUDIO_DRV_PCM_IOCTL_CAPTURE_PAUSE:
279             ret = SaiTrigger(data, TRIGGER_STOP, tx);
280             if (ret != HDF_SUCCESS) {
281                 AUDIO_DRIVER_LOG_ERR("SaiTrigger failed");
282                 return HDF_FAILURE;
283             }
284 
285             ret = SaiRuntimeSuspend(data);
286             if (ret != HDF_SUCCESS) {
287                 AUDIO_DRIVER_LOG_ERR("runtime suspend failed");
288                 return HDF_FAILURE;
289             }
290             break;
291         default:
292             break;
293     }
294     return HDF_SUCCESS;
295 }
296 
DaiGetInfoFromHcs(struct PrivDaiData * p_data,const struct DeviceResourceNode * node)297 static int32_t DaiGetInfoFromHcs(struct PrivDaiData *p_data, const struct DeviceResourceNode *node)
298 {
299     struct DeviceResourceIface *iface = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE);
300     if (p_data == NULL || node == NULL || iface == NULL || iface->GetString == NULL) {
301         AUDIO_DRIVER_LOG_ERR("%s: face is invalid", __func__);
302         return HDF_FAILURE;
303     }
304 
305     if (iface->GetString(node, "dai_dev_name", &p_data->dai_dev_name, NULL) != HDF_SUCCESS) {
306         AUDIO_DRIVER_LOG_ERR("%s: read dai name fail", __func__);
307         return HDF_FAILURE;
308     }
309 
310     AUDIO_DRIVER_LOG_ERR("%s: dai_name = %s", __func__, p_data->dai_dev_name);
311 
312     return HDF_SUCCESS;
313 }
314 
DaiFindDeviceFromBus(struct device * dev,void * para)315 static int32_t DaiFindDeviceFromBus(struct device *dev, void *para)
316 {
317     struct platform_device *pdev = NULL;
318     struct PrivDaiData *pdd = (struct PrivDaiData*)para;
319 
320     if (dev == NULL || para == NULL) {
321         AUDIO_DRIVER_LOG_ERR("invalid param.\n");
322         return HDF_ERR_INVALID_PARAM;
323     }
324 
325     pdev = to_platform_device(dev);
326     if (pdev->name == NULL) {
327         AUDIO_DRIVER_LOG_ERR("pdev name NULL\n");
328         return HDF_ERR_INVALID_PARAM;
329     }
330 
331     if (!strstr(pdev->name, pdd->dai_dev_name)) {
332         return DAI_FIND_NEXT;
333     }
334 
335     pdd->pdev = pdev;
336 
337     return DAI_FIND_SUCCESS;
338 }
339 
340 #define MCLK_BITS (4)
341 #define MCLK_BITS_OFFSET  (20)
DaiInit(struct DaiHost * daiHost,struct HdfDeviceObject * device)342 static int32_t DaiInit(struct DaiHost * daiHost, struct HdfDeviceObject *device)
343 {
344     int ret = 0;
345     struct PrivDaiData *pdd;
346     struct device_node *codec_np = NULL, *gpr_np;
347     struct i2c_client *codec_dev;
348 
349     if (device->property == NULL || daiHost == NULL) {
350         return HDF_FAILURE;
351     }
352 
353     pdd = (struct PrivDaiData *)OsalMemCalloc(sizeof(struct PrivDaiData));
354     if (pdd == NULL) {
355         return HDF_ERR_MALLOC_FAIL;
356     }
357 
358     ret = DaiGetInfoFromHcs(pdd, device->property);
359     if (ret != HDF_SUCCESS) {
360         return HDF_FAILURE;
361     }
362 
363     daiHost->priv = pdd;
364 
365     ret = bus_for_each_dev(&platform_bus_type, NULL, (void*)pdd, DaiFindDeviceFromBus);
366     if (ret != DAI_FIND_SUCCESS) {
367         return HDF_FAILURE;
368     }
369 
370     ret = of_clk_set_defaults(pdd->pdev->dev.of_node, false);
371     if (ret < 0) {
372         return HDF_FAILURE;
373     }
374 
375     codec_np = of_parse_phandle(pdd->pdev->dev.of_node, "audio-codec", 0);
376     if (!codec_np) {
377         return HDF_FAILURE;
378     }
379 
380     codec_dev = of_find_i2c_device_by_node(codec_np);
381     if (!codec_dev) {
382         of_node_put(codec_np);
383         return HDF_FAILURE;
384     }
385 
386     pdd->mclk = devm_clk_get(&codec_dev->dev, "mclk");
387     if (IS_ERR(pdd->mclk)) {
388         of_node_put(codec_np);
389         return HDF_FAILURE;
390     }
391 
392     gpr_np = of_parse_phandle(pdd->pdev->dev.of_node, "gpr", 0);
393     if (gpr_np) {
394         pdd->gpr = syscon_node_to_regmap(gpr_np);
395         if (IS_ERR(pdd->gpr)) {
396             if (codec_np) {
397                 of_node_put(codec_np);
398             }
399 
400             return HDF_FAILURE;
401         }
402 
403         /* set SAI2_MCLK_DIR to enable codec MCLK for imx7d */
404         regmap_update_bits(pdd->gpr, MCLK_BITS, 1 << MCLK_BITS_OFFSET, 1 << MCLK_BITS_OFFSET);
405     }
406 
407     return HDF_SUCCESS;
408 }
409 
DaiGetServiceName(const struct HdfDeviceObject * device)410 static int32_t DaiGetServiceName(const struct HdfDeviceObject *device)
411 {
412     const struct DeviceResourceNode *node = NULL;
413     struct DeviceResourceIface *drsOps = NULL;
414     int32_t ret;
415 
416     if (device == NULL) {
417         AUDIO_DRIVER_LOG_ERR("input para is nullptr.");
418         return HDF_FAILURE;
419     }
420 
421     node = device->property;
422     if (node == NULL) {
423         AUDIO_DRIVER_LOG_ERR("drs node is nullptr.");
424         return HDF_FAILURE;
425     }
426     drsOps = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE);
427     if (drsOps == NULL || drsOps->GetString == NULL) {
428         AUDIO_DRIVER_LOG_ERR("invalid drs ops fail!");
429         return HDF_FAILURE;
430     }
431 
432     ret = drsOps->GetString(node, "serviceName", &g_dai_data.drvDaiName, 0);
433     if (ret != HDF_SUCCESS) {
434         AUDIO_DRIVER_LOG_ERR("read serviceName fail!");
435         return ret;
436     }
437 
438     return HDF_SUCCESS;
439 }
440 
DaiDriverInit(struct HdfDeviceObject * device)441 static int32_t DaiDriverInit(struct HdfDeviceObject *device)
442 {
443     int32_t ret;
444     struct DaiHost *daiHost = NULL;
445     AUDIO_DRIVER_LOG_DEBUG("entry.\n");
446 
447     if (device == NULL) {
448         AUDIO_DRIVER_LOG_ERR("device is nullptr.");
449         return HDF_ERR_INVALID_OBJECT;
450     }
451 
452     ret = DaiGetServiceName(device);
453     if (ret !=  HDF_SUCCESS) {
454         AUDIO_DRIVER_LOG_ERR("get service name fail.");
455         return ret;
456     }
457 
458     ret = AudioSocRegisterDai(device, (void *)&g_dai_data);
459     if (ret !=  HDF_SUCCESS) {
460         AUDIO_DRIVER_LOG_ERR("register dai fail.");
461         return ret;
462     }
463 
464     daiHost = (struct DaiHost *)device->service;
465 
466     ret = DaiInit(daiHost, device);
467     if (ret != HDF_SUCCESS) {
468         AUDIO_DRIVER_LOG_ERR("Dai init fail.");
469         return ret;
470     }
471 
472     AUDIO_DRIVER_LOG_DEBUG("success.\n");
473     return HDF_SUCCESS;
474 }
475 
476 struct HdfDriverEntry g_dai_driver_entry = {
477     .moduleVersion = 1,
478     .moduleName = "DAI_IMX8",
479     .Bind = DaiDriverBind,
480     .Init = DaiDriverInit,
481     .Release = NULL,
482 };
483 HDF_INIT(g_dai_driver_entry);
484