编辑
2025-01-20
工作知识
0
请注意,本文编写于 137 天前,最后修改于 137 天前,其中某些信息可能已经过时。

目录

一、代码目录
二、代码解析
2.1 rk3568dailinux_driver.c
2.2 rk3568daiadapter.c
2.3 rk3568daiops.c
三、总结

对于声卡的dai部分,因为i2s是rk3568侧的通讯总线,所以我们对于i2s的控制器这侧也需要配置正确,这样rk3568的i2s发送音频数据的时候,es8388能够正常的接收,所以有必要介绍一下rk侧的i2s的驱动,也就是dai驱动

一、代码目录

对于i2s的驱动,代码路径如下:

device/board/hihope/rk3568/audio_drivers/dai/

相应文件如下:

rk3568_dai_adapter.c rk3568_dai_linux_driver.c rk3568_dai_ops.c

二、代码解析

2.1 rk3568_dai_linux_driver.c

此驱动主要注册platfrom设备,读取dts的配置,设置时钟和分频,大致如下

static struct platform_driver rockchip_i2s_tdm_driver = { .probe = rockchip_i2s_tdm_probe, .remove = rockchip_i2s_tdm_remove, .driver = { .name = DRV_NAME, .of_match_table = of_match_ptr(rockchip_i2s_tdm_match), .pm = NULL, }, }; module_platform_driver(rockchip_i2s_tdm_driver); static int rockchip_i2s_tdm_probe(struct platform_device *pdev) { struct device_node *node = pdev->dev.of_node; const struct of_device_id *of_id; struct rk3568_i2s_tdm_dev *i2s_tdm; struct resource *res; struct device *temp_i2s_dev; ...... i2s_tdm->bclk_fs = 64; // default-freq div factor is 64 if (!of_property_read_u32(node, "rockchip,bclk-fs", &val)) { if ((val >= 32) && (val % 2 == 0)) // min-freq div factor is 32, and it is an integer multiple of 2 i2s_tdm->bclk_fs = val; } ...... i2s_tdm->mclk_tx = devm_clk_get(&pdev->dev, "mclk_tx"); if (IS_ERR(i2s_tdm->mclk_tx)) { return PTR_ERR(i2s_tdm->mclk_tx); } i2s_tdm->mclk_rx = devm_clk_get(&pdev->dev, "mclk_rx"); if (IS_ERR(i2s_tdm->mclk_rx)) { return PTR_ERR(i2s_tdm->mclk_rx); } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); i2s_tdm->regmap = devm_regmap_init_mmio(&pdev->dev, devm_ioremap_resource(&pdev->dev, res), &rockchip_i2s_tdm_regmap_config); if (IS_ERR(i2s_tdm->regmap)) { return PTR_ERR(i2s_tdm->regmap); } ...... }

2.2 rk3568_dai_adapter.c

这份驱动是hdf的驱动程序,它通过HDF_INIT(g_daiDriverEntry);来注册一个hdf的驱动

/* HdfDriverEntry definitions */ struct HdfDriverEntry g_daiDriverEntry = { .moduleVersion = 1, .moduleName = "DAI_RK3568", .Bind = DaiDriverBind, .Init = DaiDriverInit, .Release = DaiDriverRelease, }; HDF_INIT(g_daiDriverEntry);

对于Bind回调,绑定服务,对于Init,用作注册dai,如下

daiData = (struct DaiData *)OsalMemCalloc(sizeof(*daiData)); if (daiData == NULL) { AUDIO_DEVICE_LOG_ERR("malloc DaiData fail!"); return HDF_FAILURE; } daiData->Read = Rk3568DeviceReadReg, daiData->Write = Rk3568DeviceWriteReg, daiData->DaiInit = Rk3568DaiDeviceInit, daiData->ops = &g_daiDeviceOps, daiData->daiInitFlag = false; OsalMutexInit(&daiData->mutex); daiHost->priv = daiData; if (DaiGetConfigInfo(device, daiData) != HDF_SUCCESS) { AUDIO_DEVICE_LOG_ERR("get dai data fail."); OsalMemFree(daiData); return HDF_FAILURE; } if (DaiGetServiceName(device, daiData) != HDF_SUCCESS) { AUDIO_DEVICE_LOG_ERR("get service name fail."); OsalMemFree(daiData); return HDF_FAILURE; } ret = AudioSocRegisterDai(device, (void *)daiData);

所以这里涉及一个dai的结构体,用于触发startup和hwparams以及trigger时的i2s的寄存器设置,如下:

struct AudioDaiOps g_daiDeviceOps = { .Startup = Rk3568DaiStartup, .HwParams = Rk3568DaiHwParams, .Trigger = Rk3568NormalTrigger, };

2.3 rk3568_dai_ops.c

对于startup回调,这里i2s不需要做任何事情

对于hwparams回调,这里需要根据实际的参数,设置i2s的寄存器,时钟,如下:

int32_t Rk3568DaiHwParams(const struct AudioCard *card, const struct AudioPcmHwParams *param) { int ret; uint32_t bitWidth; struct DaiDevice *dai = NULL; struct DaiData *data = DaiDataFromCard(card); struct platform_device *platformdev = NULL; struct rk3568_i2s_tdm_dev *i2sTdm = NULL; if (card == NULL || card->rtd == NULL || param == NULL || param->cardServiceName == NULL) { AUDIO_DEVICE_LOG_ERR("input para is NULL."); return HDF_ERR_INVALID_PARAM; } if (data == NULL) { AUDIO_DEVICE_LOG_ERR("data is nullptr."); return HDF_FAILURE; } dai = card->rtd->cpuDai; platformdev = GetPlatformDev(dai); if (platformdev == NULL) { AUDIO_DEVICE_LOG_ERR("platformdev is NULL."); return HDF_FAILURE; } data->pcmInfo.channels = param->channels; AUDIO_DEVICE_LOG_DEBUG("channels count : %d .", param->channels); if (AudioFormatToBitWidth(param->format, &bitWidth) != HDF_SUCCESS) { AUDIO_DEVICE_LOG_ERR("AudioFormatToBitWidth error"); return HDF_FAILURE; } data->pcmInfo.bitWidth = bitWidth; data->pcmInfo.rate = param->rate; data->pcmInfo.streamType = param->streamType; i2sTdm = dev_get_drvdata(&platformdev->dev); if (i2sTdm == NULL) { AUDIO_DEVICE_LOG_ERR("i2sTdm is null"); return HDF_FAILURE; } ret = RK3568I2sTdmSetSysClk(i2sTdm, param); if (ret != HDF_SUCCESS) { AUDIO_DEVICE_LOG_ERR("RK3568I2sTdmSetSysClk error"); return HDF_FAILURE; } ret = RK3568I2sTdmSetMclk(i2sTdm, param); if (ret != HDF_SUCCESS) { AUDIO_DEVICE_LOG_ERR("RK3568I2sTdmSetMclk error"); return HDF_FAILURE; } AUDIO_DEVICE_LOG_DEBUG("success"); return HDF_SUCCESS; }

对于trigger回调,判断是否是stop/pause,start/resume,来控制i2s的寄存器,如下

static int32_t Rk3568TxAndRxSetReg(struct rk3568_i2s_tdm_dev *i2sTdm, enum AudioStreamType streamType, int on) { int ret; if (i2sTdm == NULL || i2sTdm->regmap == NULL) { AUDIO_DEVICE_LOG_ERR("i2sTdm is null"); return HDF_FAILURE; } if (on) { // when start/resume ret = Rk3568TxAndRxStart(i2sTdm, streamType); if (ret != HDF_SUCCESS) { AUDIO_DEVICE_LOG_ERR("Rk3568TxAndRxStart is failed"); return HDF_FAILURE; } } else { // when stop/pause ret = Rk3568TxAndRxStop(i2sTdm, streamType); if (ret != HDF_SUCCESS) { AUDIO_DEVICE_LOG_ERR("Rk3568TxAndRxStop is failed"); return HDF_FAILURE; } } AUDIO_DEVICE_LOG_DEBUG("success"); return HDF_SUCCESS; }

三、总结

至此,rk3568的i2s的hdf驱动解析完成,我们可以知道,对于i2s,我们应该在合适的时候对其设置rk3568这侧的寄存器,让其按照指定的方式和codec进行通讯,所以需要这么一个hdf driver。