diff --git a/imx8mm/drivers/audio/codec/src/wm8904.c b/imx8mm/drivers/audio/codec/src/wm8904.c index 5147d77..f9dd444 100644 --- a/imx8mm/drivers/audio/codec/src/wm8904.c +++ b/imx8mm/drivers/audio/codec/src/wm8904.c @@ -722,33 +722,8 @@ struct AudioPcmHwParams g_PcmParams = {0}; #define FORMAT_HW (16385) #define RATE_MULTIPLE (10) #define LOW_SAMPLE_RATES (24000) -int Wm8904DaiHwParamsSet(const struct AudioCard *card, const struct AudioPcmHwParams *param) +int WM8904GetAif1(int width, unsigned int *aif1) { - int fs = 0, width = 0, channel = 0, slots = 0, dir = 0; - int ret = 0, i = 0, best = 0, best_val = 0, cur_val = 0, errno = 0; - unsigned int aif1 = 0, aif2 = 0, aif3 = 0, clock1 = 0, dac_digital1 = 0; - - errno = memcpy_s(&g_PcmParams, sizeof(struct AudioPcmHwParams), param, sizeof(struct AudioPcmHwParams)); - if (errno != 0) { - WM8904_CODEC_LOG_ERR("Memcpy pcm parameters failed!"); - } - - fs = param->rate; - Frame_To_Bit_Width(param->format, &width); - channel = param->channels; - slots = 1; - - dir = param->streamType == AUDIO_RENDER_STREAM ? 1 : 0; - - WM8904_Set_Fmt(FORMAT_HW); - msleep(SLEEP_TIME_10); - WM8904_Set_Sysclk(1, 0); - msleep(SLEEP_TIME_10); - - /* What BCLK do we need? */ - gpwm8904->fs = fs; - gpwm8904->bclk = fs * width * channel * slots; - switch (width) { case BIT_WIDTH_16: break; @@ -764,14 +739,13 @@ int Wm8904DaiHwParamsSet(const struct AudioCard *card, const struct AudioPcmHwPa default: return -EINVAL; } + return HDF_SUCCESS; +} - ret = WM8904_Configure_Clocking(); - if (ret != 0) { - return ret; - } - +void WM8904HwParamsGetClkRate(unsigned int *dac_digital1, unsigned int *aif2, unsigned int *aif3, unsigned int *clock1) +{ + int ret = 0, i = 0, best = 0, best_val = 0, cur_val = 0; /* Select nearest CLK_SYS_RATE */ - best = 0; best_val = abs((gpwm8904->sysclk_rate / clk_sys_rates[0].ratio) - gpwm8904->fs); for (i = 1; i < ARRAY_SIZE(clk_sys_rates); i++) { cur_val = abs((gpwm8904->sysclk_rate / clk_sys_rates[i].ratio) - gpwm8904->fs); @@ -780,7 +754,7 @@ int Wm8904DaiHwParamsSet(const struct AudioCard *card, const struct AudioPcmHwPa best_val = cur_val; } } - clock1 |= (clk_sys_rates[best].clk_sys_rate << WM8904_CLK_SYS_RATE_SHIFT); + *clock1 |= (clk_sys_rates[best].clk_sys_rate << WM8904_CLK_SYS_RATE_SHIFT); /* SAMPLE_RATE */ best = 0; @@ -793,12 +767,12 @@ int Wm8904DaiHwParamsSet(const struct AudioCard *card, const struct AudioPcmHwPa best_val = cur_val; } } - WM8904_CODEC_LOG_DEBUG("Selected SAMPLE_RATE of %dHz", sample_rates[best].rate); - clock1 |= (sample_rates[best].sample_rate << WM8904_SAMPLE_RATE_SHIFT); + WM8904_CODEC_LOG_DEBUG("Selected SAMPLE_RATE of %dHz", sample_rates[best].rate); + *clock1 |= (sample_rates[best].sample_rate << WM8904_SAMPLE_RATE_SHIFT); /* Enable sloping stopband filter for low sample rates */ if (gpwm8904->fs <= LOW_SAMPLE_RATES) { - dac_digital1 |= WM8904_DAC_SB_FILT; + *dac_digital1 |= WM8904_DAC_SB_FILT; } /* BCLK_DIV */ @@ -815,17 +789,51 @@ int Wm8904DaiHwParamsSet(const struct AudioCard *card, const struct AudioPcmHwPa } } gpwm8904->bclk = (gpwm8904->sysclk_rate * RATE_MULTIPLE) / bclk_divs[best].div; + *aif2 |= bclk_divs[best].bclk_div; + *aif3 |= gpwm8904->bclk / gpwm8904->fs; +} - aif2 |= bclk_divs[best].bclk_div; - aif3 |= gpwm8904->bclk / gpwm8904->fs; +int Wm8904DaiHwParamsSet(const struct AudioCard *card, const struct AudioPcmHwParams *param) +{ + int fs = 0, width = 0, channel = 0, slots = 1, dir = 0, ret = 0, errno = 0; + unsigned int aif1 = 0, aif2 = 0, aif3 = 0, clock1 = 0, dac_digital1 = 0; + + errno = memcpy_s(&g_PcmParams, sizeof(struct AudioPcmHwParams), param, sizeof(struct AudioPcmHwParams)); + if (errno != 0) { + WM8904_CODEC_LOG_ERR("Memcpy pcm parameters failed!"); + } + + fs = param->rate; + channel = param->channels; + dir = param->streamType == AUDIO_RENDER_STREAM ? 1 : 0; + Frame_To_Bit_Width(param->format, &width); + + WM8904_Set_Fmt(FORMAT_HW); + msleep(SLEEP_TIME_10); + WM8904_Set_Sysclk(1, 0); + msleep(SLEEP_TIME_10); + + /* What BCLK do we need? */ + gpwm8904->fs = fs; + gpwm8904->bclk = fs * width * channel * slots; + + ret = WM8904GetAif1(&aif1); + if (ret != 0) { + return ret; + } + + ret = WM8904_Configure_Clocking(); + if (ret != 0) { + return ret; + } + WM8904HwParamsGetClkRate(&dac_digital1, &aif2, &aif3, &clock1); /* Apply the settings */ WM8904RegUpdateBits(g_wm8904_i2c_handle, WM8904_DAC_DIGITAL_1, WM8904_DAC_SB_FILT, dac_digital1, BYTE_NUM); WM8904RegUpdateBits(g_wm8904_i2c_handle, WM8904_AUDIO_INTERFACE_1, WM8904_AIF_WL_MASK, aif1, BYTE_NUM); WM8904RegUpdateBits(g_wm8904_i2c_handle, WM8904_AUDIO_INTERFACE_2, WM8904_BCLK_DIV_MASK, aif2, BYTE_NUM); WM8904RegUpdateBits(g_wm8904_i2c_handle, WM8904_AUDIO_INTERFACE_3, WM8904_LRCLK_RATE_MASK, aif3, BYTE_NUM); - WM8904RegUpdateBits(g_wm8904_i2c_handle, WM8904_CLOCK_RATES_1, - WM8904_SAMPLE_RATE_MASK | WM8904_CLK_SYS_RATE_MASK, clock1, BYTE_NUM); + WM8904RegUpdateBits(g_wm8904_i2c_handle, WM8904_CLOCK_RATES_1, WM8904_SAMPLE_RATE_MASK | WM8904_CLK_SYS_RATE_MASK, clock1, BYTE_NUM); /* Update filters for the new settings */ WM8904_Set_Retune_Mobile(); diff --git a/imx8mm/drivers/audio/soc/src/sai_driver.c b/imx8mm/drivers/audio/soc/src/sai_driver.c index dc06410..1dd38e0 100644 --- a/imx8mm/drivers/audio/soc/src/sai_driver.c +++ b/imx8mm/drivers/audio/soc/src/sai_driver.c @@ -68,38 +68,11 @@ static struct fsl_sai *GetDrvSai(const struct PlatformData *pd) return NULL; } -int32_t SaiPrintAllRegister() +int32_t SaiPrintTFRegister() { struct fsl_sai *sai = g_sai; u32 read_val = 0; - regmap_read(sai->regmap, FSL_SAI_TCSR(BYTE_NUM), &read_val); - AUDIO_DRIVER_LOG_ERR("FSL_SAI_TCSR %08x", read_val); - regmap_read(sai->regmap, FSL_SAI_TCR1(BYTE_NUM), &read_val); - AUDIO_DRIVER_LOG_ERR("FSL_SAI_TCR1 %08x", read_val); - regmap_read(sai->regmap, FSL_SAI_TCR2(BYTE_NUM), &read_val); - AUDIO_DRIVER_LOG_ERR("FSL_SAI_TCR2 %08x", read_val); - regmap_read(sai->regmap, FSL_SAI_TCR3(BYTE_NUM), &read_val); - AUDIO_DRIVER_LOG_ERR("FSL_SAI_TCR3 %08x", read_val); - regmap_read(sai->regmap, FSL_SAI_TCR4(BYTE_NUM), &read_val); - AUDIO_DRIVER_LOG_ERR("FSL_SAI_TCR4 %08x", read_val); - regmap_read(sai->regmap, FSL_SAI_TCR5(BYTE_NUM), &read_val); - AUDIO_DRIVER_LOG_ERR("FSL_SAI_TCR5 %08x", read_val); - regmap_read(sai->regmap, FSL_SAI_TDR0, &read_val); - AUDIO_DRIVER_LOG_ERR("FSL_SAI_TDR0 %08x", read_val); - regmap_read(sai->regmap, FSL_SAI_TDR1, &read_val); - AUDIO_DRIVER_LOG_ERR("FSL_SAI_TDR1 %08x", read_val); - regmap_read(sai->regmap, FSL_SAI_TDR2, &read_val); - AUDIO_DRIVER_LOG_ERR("FSL_SAI_TDR2 %08x", read_val); - regmap_read(sai->regmap, FSL_SAI_TDR3, &read_val); - AUDIO_DRIVER_LOG_ERR("FSL_SAI_TDR3 %08x", read_val); - regmap_read(sai->regmap, FSL_SAI_TDR4, &read_val); - AUDIO_DRIVER_LOG_ERR("FSL_SAI_TDR4 %08x", read_val); - regmap_read(sai->regmap, FSL_SAI_TDR5, &read_val); - AUDIO_DRIVER_LOG_ERR("FSL_SAI_TDR5 %08x", read_val); - regmap_read(sai->regmap, FSL_SAI_TDR6, &read_val); - AUDIO_DRIVER_LOG_ERR("FSL_SAI_TDR6 %08x", read_val); - regmap_read(sai->regmap, FSL_SAI_TDR7, &read_val); - AUDIO_DRIVER_LOG_ERR("FSL_SAI_TDR7 %08x", read_val); + regmap_read(sai->regmap, FSL_SAI_TFR0, &read_val); AUDIO_DRIVER_LOG_ERR("FSL_SAI_TFR0 %08x", read_val); regmap_read(sai->regmap, FSL_SAI_TFR1, &read_val); @@ -116,6 +89,55 @@ int32_t SaiPrintAllRegister() AUDIO_DRIVER_LOG_ERR("FSL_SAI_TFR6 %08x", read_val); regmap_read(sai->regmap, FSL_SAI_TFR7, &read_val); AUDIO_DRIVER_LOG_ERR("FSL_SAI_TFR7 %08x", read_val); + + return 0; +} + +int32_t SaiPrintTDRegister() +{ + struct fsl_sai *sai = g_sai; + u32 read_val = 0; + + regmap_read(sai->regmap, FSL_SAI_TDR0, &read_val); + AUDIO_DRIVER_LOG_ERR("FSL_SAI_TDR0 %08x", read_val); + regmap_read(sai->regmap, FSL_SAI_TDR1, &read_val); + AUDIO_DRIVER_LOG_ERR("FSL_SAI_TDR1 %08x", read_val); + regmap_read(sai->regmap, FSL_SAI_TDR2, &read_val); + AUDIO_DRIVER_LOG_ERR("FSL_SAI_TDR2 %08x", read_val); + regmap_read(sai->regmap, FSL_SAI_TDR3, &read_val); + AUDIO_DRIVER_LOG_ERR("FSL_SAI_TDR3 %08x", read_val); + regmap_read(sai->regmap, FSL_SAI_TDR4, &read_val); + AUDIO_DRIVER_LOG_ERR("FSL_SAI_TDR4 %08x", read_val); + regmap_read(sai->regmap, FSL_SAI_TDR5, &read_val); + AUDIO_DRIVER_LOG_ERR("FSL_SAI_TDR5 %08x", read_val); + regmap_read(sai->regmap, FSL_SAI_TDR6, &read_val); + AUDIO_DRIVER_LOG_ERR("FSL_SAI_TDR6 %08x", read_val); + regmap_read(sai->regmap, FSL_SAI_TDR7, &read_val); + AUDIO_DRIVER_LOG_ERR("FSL_SAI_TDR7 %08x", read_val); + + return 0; +} + +int32_t SaiPrintAllRegister() +{ + struct fsl_sai *sai = g_sai; + u32 read_val = 0; + regmap_read(sai->regmap, FSL_SAI_TCSR(BYTE_NUM), &read_val); + AUDIO_DRIVER_LOG_ERR("FSL_SAI_TCSR %08x", read_val); + regmap_read(sai->regmap, FSL_SAI_TCR1(BYTE_NUM), &read_val); + AUDIO_DRIVER_LOG_ERR("FSL_SAI_TCR1 %08x", read_val); + regmap_read(sai->regmap, FSL_SAI_TCR2(BYTE_NUM), &read_val); + AUDIO_DRIVER_LOG_ERR("FSL_SAI_TCR2 %08x", read_val); + regmap_read(sai->regmap, FSL_SAI_TCR3(BYTE_NUM), &read_val); + AUDIO_DRIVER_LOG_ERR("FSL_SAI_TCR3 %08x", read_val); + regmap_read(sai->regmap, FSL_SAI_TCR4(BYTE_NUM), &read_val); + AUDIO_DRIVER_LOG_ERR("FSL_SAI_TCR4 %08x", read_val); + regmap_read(sai->regmap, FSL_SAI_TCR5(BYTE_NUM), &read_val); + AUDIO_DRIVER_LOG_ERR("FSL_SAI_TCR5 %08x", read_val); + + SaiPrintTDRegister(); + SaiPrintTFRegister(); + regmap_read(sai->regmap, FSL_SAI_TMR, &read_val); AUDIO_DRIVER_LOG_ERR("FSL_SAI_TMR %08x", read_val); regmap_read(sai->regmap, FSL_SAI_TTCTL, &read_val); @@ -132,6 +154,43 @@ int32_t SaiPrintAllRegister() return 0; } +static bool fsl_sai_rx_irq(int irq, void *devid) +{ + u32 flags = 0, xcsr = 0, mask = 0; + bool irq_none = true; + struct PrivPlatformData *ppd = (struct PrivPlatformData *)devid; + struct fsl_sai *sai = (struct fsl_sai *)&(ppd->sai); + unsigned char offset = sai->reg_offset; + + regmap_read(sai->regmap, FSL_SAI_RCSR(offset), &xcsr); + flags = xcsr & mask; + + if (flags) { + irq_none = false; + } else { + if (irq_none) { + return IRQ_NONE; + } else { + return IRQ_HANDLED; + } + } + + if (flags & FSL_SAI_CSR_FEF) { + AUDIO_DRIVER_LOG_ERR("isr: Receive overflow detected\n"); + /* FIFO reset for safety */ + xcsr |= FSL_SAI_CSR_FR; + } + + flags &= FSL_SAI_CSR_xF_W_MASK; + xcsr &= ~FSL_SAI_CSR_xF_MASK; + + if (flags) { + regmap_write(sai->regmap, FSL_SAI_RCSR(offset), flags | xcsr); + } + + return irq_none; +} + static irqreturn_t fsl_sai_isr(int irq, void *devid) { struct PrivPlatformData *ppd = (struct PrivPlatformData *)devid; @@ -164,28 +223,12 @@ static irqreturn_t fsl_sai_isr(int irq, void *devid) } } - if (flags & FSL_SAI_CSR_WSF) { - AUDIO_DRIVER_LOG_ERR("isr: Start of Rx word detected\n"); - } - - if (flags & FSL_SAI_CSR_SEF) { - AUDIO_DRIVER_LOG_ERR("isr: Rx Frame sync error detected\n"); - } - if (flags & FSL_SAI_CSR_FEF) { AUDIO_DRIVER_LOG_ERR("isr: Receive overflow detected\n"); /* FIFO reset for safety */ xcsr |= FSL_SAI_CSR_FR; } - if (flags & FSL_SAI_CSR_FWF) { - AUDIO_DRIVER_LOG_ERR("isr: Enabled receive FIFO is full\n"); - } - - if (flags & FSL_SAI_CSR_FRF) { - AUDIO_DRIVER_LOG_ERR("isr: Receive FIFO watermark has been reached\n"); - } - flags &= FSL_SAI_CSR_xF_W_MASK; xcsr &= ~FSL_SAI_CSR_xF_MASK; @@ -200,28 +243,12 @@ static irqreturn_t fsl_sai_isr(int irq, void *devid) } } - if (flags & FSL_SAI_CSR_WSF) { - AUDIO_DRIVER_LOG_ERR("isr: Start of Tx word detected\n"); - } - - if (flags & FSL_SAI_CSR_SEF) { - AUDIO_DRIVER_LOG_ERR("isr: Tx Frame sync error detected\n"); - } - if (flags & FSL_SAI_CSR_FEF) { AUDIO_DRIVER_LOG_ERR("isr: Transmit underrun detected\n"); /* FIFO reset for safety */ xcsr |= FSL_SAI_CSR_FR; } - if (flags & FSL_SAI_CSR_FWF) { - AUDIO_DRIVER_LOG_ERR("isr: Enabled transmit FIFO is empty\n"); - } - - if (flags & FSL_SAI_CSR_FRF) { - AUDIO_DRIVER_LOG_ERR("isr: Transmit FIFO watermark has been reached\n"); - } - flags &= FSL_SAI_CSR_xF_W_MASK; xcsr &= ~FSL_SAI_CSR_xF_MASK; @@ -230,47 +257,7 @@ static irqreturn_t fsl_sai_isr(int irq, void *devid) } /* Rx IRQ */ - regmap_read(sai->regmap, FSL_SAI_RCSR(offset), &xcsr); - flags = xcsr & mask; - - if (flags) { - irq_none = false; - } else { - if (irq_none) { - return IRQ_NONE; - } else { - return IRQ_HANDLED; - } - } - - if (flags & FSL_SAI_CSR_WSF) { - AUDIO_DRIVER_LOG_ERR("isr: Start of Rx word detected\n"); - } - - if (flags & FSL_SAI_CSR_SEF) { - AUDIO_DRIVER_LOG_ERR("isr: Rx Frame sync error detected\n"); - } - - if (flags & FSL_SAI_CSR_FEF) { - AUDIO_DRIVER_LOG_ERR("isr: Receive overflow detected\n"); - /* FIFO reset for safety */ - xcsr |= FSL_SAI_CSR_FR; - } - - if (flags & FSL_SAI_CSR_FWF) { - AUDIO_DRIVER_LOG_ERR("isr: Enabled receive FIFO is full\n"); - } - - if (flags & FSL_SAI_CSR_FRF) { - AUDIO_DRIVER_LOG_ERR("isr: Receive FIFO watermark has been reached\n"); - } - - flags &= FSL_SAI_CSR_xF_W_MASK; - xcsr &= ~FSL_SAI_CSR_xF_MASK; - - if (flags) { - regmap_write(sai->regmap, FSL_SAI_RCSR(offset), flags | xcsr); - } + irq_none = fsl_sai_rx_irq(irq, devid); if (irq_none) { return IRQ_NONE; @@ -304,6 +291,61 @@ static struct reg_default fsl_sai_v3_reg_defaults[] = { {FSL_SAI_MDIV, 0}, }; +static bool fsl_sai_readable_tfr_reg(unsigned int reg) +{ + bool ret = false; + switch (reg) { + case FSL_SAI_TFR0: fallthrough; + case FSL_SAI_TFR1: fallthrough; + case FSL_SAI_TFR2: fallthrough; + case FSL_SAI_TFR3: fallthrough; + case FSL_SAI_TFR4: fallthrough; + case FSL_SAI_TFR5: fallthrough; + case FSL_SAI_TFR6: fallthrough; + case FSL_SAI_TFR7: + ret = true; + break; + + default: + ret = false; + break; + } + + return ret; +} + +static bool fsl_sai_readable_rxr_reg(unsigned int reg) +{ + bool ret = false; + switch (reg) { + case FSL_SAI_RDR0: fallthrough; + case FSL_SAI_RDR1: fallthrough; + case FSL_SAI_RDR2: fallthrough; + case FSL_SAI_RDR3: fallthrough; + case FSL_SAI_RDR4: fallthrough; + case FSL_SAI_RDR5: fallthrough; + case FSL_SAI_RDR6: fallthrough; + case FSL_SAI_RDR7: fallthrough; + case FSL_SAI_RFR0: fallthrough; + case FSL_SAI_RFR1: fallthrough; + case FSL_SAI_RFR2: fallthrough; + case FSL_SAI_RFR3: fallthrough; + case FSL_SAI_RFR4: fallthrough; + case FSL_SAI_RFR5: fallthrough; + case FSL_SAI_RFR6: fallthrough; + case FSL_SAI_RFR7: fallthrough; + case FSL_SAI_RMR: + ret = true; + break; + + default: + ret = false; + break; + } + + return ret; +} + static bool fsl_sai_readable_reg(struct device *dev, unsigned int reg) { struct fsl_sai *sai = dev_get_drvdata(dev); @@ -317,44 +359,27 @@ static bool fsl_sai_readable_reg(struct device *dev, unsigned int reg) return true; } + if (fsl_sai_readable_tfr_reg(reg) == true) { + return true; + } + + if (fsl_sai_readable_rxr_reg(reg) == true) { + return true; + } + switch (reg) { - case FSL_SAI_TFR0: - case FSL_SAI_TFR1: - case FSL_SAI_TFR2: - case FSL_SAI_TFR3: - case FSL_SAI_TFR4: - case FSL_SAI_TFR5: - case FSL_SAI_TFR6: - case FSL_SAI_TFR7: - case FSL_SAI_TMR: - case FSL_SAI_RDR0: - case FSL_SAI_RDR1: - case FSL_SAI_RDR2: - case FSL_SAI_RDR3: - case FSL_SAI_RDR4: - case FSL_SAI_RDR5: - case FSL_SAI_RDR6: - case FSL_SAI_RDR7: - case FSL_SAI_RFR0: - case FSL_SAI_RFR1: - case FSL_SAI_RFR2: - case FSL_SAI_RFR3: - case FSL_SAI_RFR4: - case FSL_SAI_RFR5: - case FSL_SAI_RFR6: - case FSL_SAI_RFR7: - case FSL_SAI_RMR: - case FSL_SAI_MCTL: - case FSL_SAI_MDIV: - case FSL_SAI_VERID: - case FSL_SAI_PARAM: - case FSL_SAI_TTCTN: - case FSL_SAI_RTCTN: - case FSL_SAI_TTCTL: - case FSL_SAI_TBCTN: - case FSL_SAI_TTCAP: - case FSL_SAI_RTCTL: - case FSL_SAI_RBCTN: + case FSL_SAI_TMR: fallthrough; + case FSL_SAI_MCTL: fallthrough; + case FSL_SAI_MDIV: fallthrough; + case FSL_SAI_VERID: fallthrough; + case FSL_SAI_PARAM: fallthrough; + case FSL_SAI_TTCTN: fallthrough; + case FSL_SAI_RTCTN: fallthrough; + case FSL_SAI_TTCTL: fallthrough; + case FSL_SAI_TBCTN: fallthrough; + case FSL_SAI_TTCAP: fallthrough; + case FSL_SAI_RTCTL: fallthrough; + case FSL_SAI_RBCTN: fallthrough; case FSL_SAI_RTCAP: return true; default: @@ -667,71 +692,47 @@ static int fsl_sai_set_bclk(struct fsl_sai *sai, bool tx, u32 freq) return 0; } - -int32_t SaiSetHwParams(const struct PlatformData *pd, const enum AudioStreamType streamType) +struct fsl_hwParams_register { - struct fsl_sai *sai = GetDrvSai(pd); - unsigned char offset = sai->reg_offset; - u32 channels = 0; - u32 rate = 0; - u32 word_width = 0; - bool tx = streamType == AUDIO_RENDER_STREAM; + u32 cr3; + u32 cr4; + u32 cr5; + u32 mr; +}; + +int32_t SaiGetHwParams(const struct PlatformData *pd, const enum AudioStreamType streamType, u32 *channels, u32 *rate, u32 *word_width) +{ + int32_t ret = 0; if (streamType == AUDIO_RENDER_STREAM) { - channels = pd->renderPcmInfo.channels; - rate = pd->renderPcmInfo.rate; - word_width = pd->renderPcmInfo.bitWidth; + *channels = pd->renderPcmInfo.channels; + *rate = pd->renderPcmInfo.rate; + *word_width = pd->renderPcmInfo.bitWidth; } else if (streamType == AUDIO_CAPTURE_STREAM) { - channels = pd->capturePcmInfo.channels; - rate = pd->capturePcmInfo.rate; - word_width = pd->capturePcmInfo.bitWidth; + *channels = pd->capturePcmInfo.channels; + *rate = pd->capturePcmInfo.rate; + *word_width = pd->capturePcmInfo.bitWidth; } else { AUDIO_DRIVER_LOG_ERR("streamType is invaild "); return HDF_FAILURE; } + return ret; +} - u32 val_cr4 = 0, val_cr5 = 0; - u32 slots = (channels == 1) ? 2 : channels; - u32 slot_width = word_width; - u32 pins = 0, bclk = 0; - int32_t ret = 0, i = 0, trce_mask = 0, dl_cfg_cnt, dl_cfg_idx = 0; - struct fsl_sai_dl_cfg *dl_cfg = NULL; +int32_t SaiSetHwParamsPin(struct fsl_sai *sai, u32 channels, u32 *pins, u32 *slots) +{ + int32_t ret = 0; if (sai->slots) { - slots = sai->slots; + *slots = sai->slots; } - pins = DIV_ROUND_UP(channels, slots); - sai->is_dsd = false; - dl_cfg = sai->pcm_dl_cfg; - dl_cfg_cnt = sai->pcm_dl_cfg_cnt; - for (i = 0; i < dl_cfg_cnt; i++) { - if (dl_cfg[i].pins == pins) { - dl_cfg_idx = i; - break; - } - } - - if (dl_cfg_idx >= dl_cfg_cnt) { - AUDIO_DRIVER_LOG_ERR("fsl,dataline%s invalid or not provided.", - sai->is_dsd ? ",dsd" : ""); - return HDF_FAILURE; - } - - if (sai->slot_width) { - slot_width = sai->slot_width; - } - - AUDIO_DRIVER_LOG_ERR("rate = %d, slots = %d, slot_width = %d", rate, slots, slot_width); - - bclk = rate*(sai->bitclk_ratio ? sai->bitclk_ratio : slots * slot_width); + *pins = DIV_ROUND_UP(channels, *slots); if (!IS_ERR_OR_NULL(sai->pinctrl)) { - AUDIO_DRIVER_LOG_ERR("pin cntrl"); sai->pins_state = pinctrl_lookup_state(sai->pinctrl, "default"); if (!IS_ERR_OR_NULL(sai->pins_state)) { - AUDIO_DRIVER_LOG_ERR("pin cntrl"); ret = pinctrl_select_state(sai->pinctrl, sai->pins_state); if (ret) { AUDIO_DRIVER_LOG_ERR("failed to set proper pins state"); @@ -739,7 +740,12 @@ int32_t SaiSetHwParams(const struct PlatformData *pd, const enum AudioStreamType } } } + return ret; +} +int32_t SaiSetHwParamsClk(struct fsl_sai *sai, bool tx, u32 bclk, const enum AudioStreamType streamType) +{ + int32_t ret = 0; if (!sai->slave_mode[tx]) { ret = fsl_sai_set_bclk(sai, tx, bclk); if (ret) { @@ -757,10 +763,12 @@ int32_t SaiSetHwParams(const struct PlatformData *pd, const enum AudioStreamType sai->mclk_streams |= BIT(streamType); } } + return ret; +} - if (!sai->is_dsp_mode) { - val_cr4 |= FSL_SAI_CR4_SYWD(slot_width); - } +u32 SaiGetHwParamsCR5(struct fsl_sai *sai, u32 slot_width, u32 word_width) +{ + u32 val_cr5; val_cr5 |= FSL_SAI_CR5_WNW(slot_width); val_cr5 |= FSL_SAI_CR5_W0W(slot_width); @@ -771,42 +779,75 @@ int32_t SaiSetHwParams(const struct PlatformData *pd, const enum AudioStreamType val_cr5 |= FSL_SAI_CR5_FBT(word_width - 1); } + return val_cr5; +} + +u32 SaiGetHwParamsCR4(struct fsl_sai *sai, u32 slot_width, u32 slots) +{ + u32 val_cr4 = 0; + + if (!sai->is_dsp_mode) { + val_cr4 |= FSL_SAI_CR4_SYWD(slot_width); + } val_cr4 |= FSL_SAI_CR4_FRSZ(slots); /* Output Mode - data pins transmit 0 when slots are masked * or channels are disabled */ val_cr4 |= FSL_SAI_CR4_CHMOD; + return val_cr4; +} - /* - * For SAI master mode, when Tx(Rx) sync with Rx(Tx) clock, Rx(Tx) will - * generate bclk and frame clock for Tx(Rx), we should set RCR4(TCR4), - * RCR5(TCR5) and RMR(TMR) for playback(capture), or there will be sync - * error. - */ +u32 SaiGetdlMask(struct fsl_sai *sai, bool tx, u32 pins) +{ + int32_t i = 0, dl_cfg_cnt, dl_cfg_idx = 0; + struct fsl_sai_dl_cfg *dl_cfg = NULL; + + + sai->is_dsd = false; + dl_cfg = sai->pcm_dl_cfg; + dl_cfg_cnt = sai->pcm_dl_cfg_cnt; + for (i = 0; i < dl_cfg_cnt; i++) { + if (dl_cfg[i].pins == pins) { + dl_cfg_idx = i; + break; + } + } + + if (dl_cfg_idx >= dl_cfg_cnt) { + AUDIO_DRIVER_LOG_ERR("fsl,dataline%s invalid or not provided.", sai->is_dsd ? ",dsd" : ""); + return HDF_FAILURE; + } + + return dl_cfg[dl_cfg_idx].mask[tx]; +} + +SaiSetHwParamsRegister(struct fsl_sai *sai, bool tx, struct fsl_hwParams_register *val, unsigned int dl_mask) +{ + unsigned char offset = sai->reg_offset; if (!sai->slave_mode[tx]) { if (!sai->synchronous[TX] && sai->synchronous[RX] && !tx) { regmap_update_bits(sai->regmap, FSL_SAI_TCR4(offset), FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK | FSL_SAI_CR4_CHMOD_MASK, - val_cr4); + val->cr4); regmap_update_bits(sai->regmap, FSL_SAI_TCR5(offset), FSL_SAI_CR5_WNW_MASK | FSL_SAI_CR5_W0W_MASK | - FSL_SAI_CR5_FBT_MASK, val_cr5); + FSL_SAI_CR5_FBT_MASK, val->cr5); } else if (!sai->synchronous[RX] && sai->synchronous[TX] && tx) { regmap_update_bits(sai->regmap, FSL_SAI_RCR4(offset), FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK | FSL_SAI_CR4_CHMOD_MASK, - val_cr4); + val->cr4); regmap_update_bits(sai->regmap, FSL_SAI_RCR5(offset), FSL_SAI_CR5_WNW_MASK | FSL_SAI_CR5_W0W_MASK | - FSL_SAI_CR5_FBT_MASK, val_cr5); + FSL_SAI_CR5_FBT_MASK, val->cr5); } } if (sai->dataline != 0x1) { - if (dl_cfg[dl_cfg_idx].mask[tx] <= 1 || sai->is_multi_lane) { + if (dl_mask <= 1 || sai->is_multi_lane) { regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx, offset), FSL_SAI_CR4_FCOMB_MASK, 0); } else { @@ -815,38 +856,75 @@ int32_t SaiSetHwParams(const struct PlatformData *pd, const enum AudioStreamType } } - if (__sw_hweight8(dl_cfg[dl_cfg_idx].mask[tx] & 0xFF) < pins) { - AUDIO_DRIVER_LOG_ERR("channel not supported"); - return -EINVAL; - } - - /* find a proper tcre setting */ - for (i = 0; i < BYTE_NUM; i++) { - trce_mask = (1 << (i + 1)) - 1; - if (__sw_hweight8(dl_cfg[dl_cfg_idx].mask[tx] & trce_mask) == pins) { - break; - } - } - regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx, offset), FSL_SAI_CR3_TRCE_MASK, - FSL_SAI_CR3_TRCE((dl_cfg[dl_cfg_idx].mask[tx] & trce_mask))); + FSL_SAI_CR3_TRCE(val->cr3)); regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx, offset), FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK | FSL_SAI_CR4_CHMOD_MASK, - val_cr4); + val->cr4); regmap_update_bits(sai->regmap, FSL_SAI_xCR5(tx, offset), FSL_SAI_CR5_WNW_MASK | FSL_SAI_CR5_W0W_MASK | - FSL_SAI_CR5_FBT_MASK, val_cr5); + FSL_SAI_CR5_FBT_MASK, val->cr5); - regmap_write(sai->regmap, FSL_SAI_xMR(tx), - ~0UL - ((1 << min(channels, slots)) - 1)); + regmap_write(sai->regmap, FSL_SAI_xMR(tx), val->mr); return HDF_SUCCESS; } +int32_t SaiSetHwParams(const struct PlatformData *pd, const enum AudioStreamType streamType) +{ + struct fsl_sai *sai = GetDrvSai(pd); + u32 channels = 0, rate = 0, word_width = 0, pins = 0, bclk = 0, slot_width = word_width, slots = (channels == 1) ? 2 : channels; + bool tx = streamType == AUDIO_RENDER_STREAM; + struct fsl_hwParams_register val; + int32_t trce_mask = 0, ret = 0; + unsigned int dl_mask, i; + + ret = SaiGetHwParams(sai, &channels, &rate, &word_width); + if (ret != HDF_SUCCESS) { + ADM_LOG_ERR("SaiGetHwParams fail ret=%d", ret); + return ret; + } + + ret = SaiSetHwParamsPin(sai, channels, &pins, &slots); + if (ret != HDF_SUCCESS) { + ADM_LOG_ERR("SaiSetHwParamsPin fail ret=%d", ret); + return ret; + } + + if (sai->slot_width) { + slot_width = sai->slot_width; + } + bclk = rate*(sai->bitclk_ratio ? sai->bitclk_ratio : slots * slot_width); + ret = SaiSetHwParamsClk(sai, tx, bclk, streamType); + if (ret != HDF_SUCCESS) { + ADM_LOG_ERR("SaiSetHwParamsClk fail ret=%d", ret); + return ret; + } + + val.cr5 = SaiGetHwParamsCR5(sai, slot_width, word_width); + val.cr4 = SaiGetHwParamsCR4(sai, slot_width, slots); + dl_mask = SaiGetdlMask(sai, tx, pins); + if (__sw_hweight8(dl_mask & 0xFF) < pins) { + AUDIO_DRIVER_LOG_ERR("channel not supported"); + return -EINVAL; + } + for (i = 0; i < BYTE_NUM; i++) { + trce_mask = (1 << (i + 1)) - 1; + if (__sw_hweight8(dl_mask & trce_mask) == pins) { + break; + } + } + val.cr3 = dl_mask & trce_mask; + val.mr = ~0UL - ((1 << min(channels, slots)) - 1); + + SaiSetHwParamsRegister(sai, &val, dl_mask); + return HDF_SUCCESS; +} + int32_t SaiSetDaiTdmSlot(const struct PlatformData *pd, int32_t tx_mask, int32_t rx_mask, int32_t slots, int32_t slot_width) { @@ -980,17 +1058,95 @@ int32_t SaiSetSysclk(const struct PlatformData *pd, int clk_id, unsigned int fre return HDF_SUCCESS; } +static int32_t HandleDaiMode(unsigned int fmt, int32_t *val_cr2, int32_t *val_cr4, struct fsl_sai **sai) +{ + /* DAI mode */ + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + /* + * Frame low, 1clk before data, one word length for frame sync, + * frame sync starts one serial clock cycle earlier, + * that is, together with the last bit of the previous + * data word. + */ + *val_cr2 |= FSL_SAI_CR2_BCP; + *val_cr4 |= FSL_SAI_CR4_FSE | FSL_SAI_CR4_FSP; + break; + case SND_SOC_DAIFMT_LEFT_J: + /* + * Frame high, one word length for frame sync, + * frame sync asserts with the first bit of the frame. + */ + *val_cr2 |= FSL_SAI_CR2_BCP; + break; + case SND_SOC_DAIFMT_DSP_A: + /* + * Frame high, 1clk before data, one bit for frame sync, + * frame sync starts one serial clock cycle earlier, + * that is, together with the last bit of the previous + * data word. + */ + *val_cr2 |= FSL_SAI_CR2_BCP; + *val_cr4 |= FSL_SAI_CR4_FSE; + (*sai)->is_dsp_mode = true; + break; + case SND_SOC_DAIFMT_DSP_B: + /* + * Frame high, one bit for frame sync, + * frame sync asserts with the first bit of the frame. + */ + *val_cr2 |= FSL_SAI_CR2_BCP; + (*sai)->is_dsp_mode = true; + break; + case SND_SOC_DAIFMT_PDM: + *val_cr2 |= FSL_SAI_CR2_BCP; + *val_cr4 &= ~FSL_SAI_CR4_MF; + (*sai)->is_dsp_mode = true; + break; + case SND_SOC_DAIFMT_RIGHT_J: + /* To be done */ + default: + return -EINVAL; + } + return 0; +} + +static int32_t HandleDaiCLK(unsigned int fmt, int32_t *val_cr2, int32_t *val_cr4) +{ + /* DAI clock inversion */ + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_IB_IF: + /* Invert both clocks */ + *val_cr2 ^= FSL_SAI_CR2_BCP; + *val_cr4 ^= FSL_SAI_CR4_FSP; + break; + case SND_SOC_DAIFMT_IB_NF: + /* Invert bit clock */ + *val_cr2 ^= FSL_SAI_CR2_BCP; + break; + case SND_SOC_DAIFMT_NB_IF: + /* Invert frame clock */ + *val_cr4 ^= FSL_SAI_CR4_FSP; + break; + case SND_SOC_DAIFMT_NB_NF: + /* Nothing to do for both normal cases */ + break; + default: + return -EINVAL; + } + + return 0; +} + static int32_t SaiSetDaiFmtTr(struct PrivPlatformData *ppd, unsigned int fmt, int fsl_dir) { struct fsl_sai *sai = NULL; unsigned char offset = 0; - int32_t val_cr2 = 0; - int32_t val_cr4 = 0; + int32_t val_cr2 = 0, val_cr4 = 0; bool tx = fsl_dir == FSL_FMT_TRANSMITTER; uint32_t read_val; if (ppd == NULL) { - AUDIO_DRIVER_LOG_ERR("pdd is null"); return HDF_FAILURE; } @@ -1002,78 +1158,15 @@ static int32_t SaiSetDaiFmtTr(struct PrivPlatformData *ppd, unsigned int fmt, in } sai->is_dsp_mode = false; - - /* DAI mode */ - switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { - case SND_SOC_DAIFMT_I2S: - /* - * Frame low, 1clk before data, one word length for frame sync, - * frame sync starts one serial clock cycle earlier, - * that is, together with the last bit of the previous - * data word. - */ - val_cr2 |= FSL_SAI_CR2_BCP; - val_cr4 |= FSL_SAI_CR4_FSE | FSL_SAI_CR4_FSP; - break; - case SND_SOC_DAIFMT_LEFT_J: - /* - * Frame high, one word length for frame sync, - * frame sync asserts with the first bit of the frame. - */ - val_cr2 |= FSL_SAI_CR2_BCP; - break; - case SND_SOC_DAIFMT_DSP_A: - /* - * Frame high, 1clk before data, one bit for frame sync, - * frame sync starts one serial clock cycle earlier, - * that is, together with the last bit of the previous - * data word. - */ - val_cr2 |= FSL_SAI_CR2_BCP; - val_cr4 |= FSL_SAI_CR4_FSE; - sai->is_dsp_mode = true; - break; - case SND_SOC_DAIFMT_DSP_B: - /* - * Frame high, one bit for frame sync, - * frame sync asserts with the first bit of the frame. - */ - val_cr2 |= FSL_SAI_CR2_BCP; - sai->is_dsp_mode = true; - break; - case SND_SOC_DAIFMT_PDM: - val_cr2 |= FSL_SAI_CR2_BCP; - val_cr4 &= ~FSL_SAI_CR4_MF; - sai->is_dsp_mode = true; - break; - case SND_SOC_DAIFMT_RIGHT_J: - /* To be done */ - default: - return -EINVAL; + if (HandleDaiMode(fmt, &val_cr2, &val_cr4, &sai) < 0) { + return -EINVAL; } - /* DAI clock inversion */ - switch (fmt & SND_SOC_DAIFMT_INV_MASK) { - case SND_SOC_DAIFMT_IB_IF: - /* Invert both clocks */ - val_cr2 ^= FSL_SAI_CR2_BCP; - val_cr4 ^= FSL_SAI_CR4_FSP; - break; - case SND_SOC_DAIFMT_IB_NF: - /* Invert bit clock */ - val_cr2 ^= FSL_SAI_CR2_BCP; - break; - case SND_SOC_DAIFMT_NB_IF: - /* Invert frame clock */ - val_cr4 ^= FSL_SAI_CR4_FSP; - break; - case SND_SOC_DAIFMT_NB_NF: - /* Nothing to do for both normal cases */ - break; - default: - return -EINVAL; + if (HandleDaiCLK(fmt, &val_cr2, &val_cr4) < 0) { + return -EINVAL; } + sai->slave_mode[tx] = false; /* DAI clock master masks */ @@ -1097,10 +1190,7 @@ static int32_t SaiSetDaiFmtTr(struct PrivPlatformData *ppd, unsigned int fmt, in } regmap_read(sai->regmap, FSL_SAI_xCR2(tx, offset), &read_val); - AUDIO_DRIVER_LOG_ERR("FSL_SAI_xCR2 %08x", read_val); - regmap_read(sai->regmap, FSL_SAI_xCR4(tx, offset), &read_val); - AUDIO_DRIVER_LOG_ERR("FSL_SAI_xCR4 %08x", read_val); regmap_update_bits(sai->regmap, FSL_SAI_xCR2(tx, offset), FSL_SAI_CR2_BCP | FSL_SAI_CR2_BCD_MSTR, val_cr2); @@ -1109,10 +1199,7 @@ static int32_t SaiSetDaiFmtTr(struct PrivPlatformData *ppd, unsigned int fmt, in FSL_SAI_CR4_FSP | FSL_SAI_CR4_FSD_MSTR, val_cr4); regmap_read(sai->regmap, FSL_SAI_xCR2(tx, offset), &read_val); - AUDIO_DRIVER_LOG_ERR("FSL_SAI_xCR2 %08x", read_val); - regmap_read(sai->regmap, FSL_SAI_xCR4(tx, offset), &read_val); - AUDIO_DRIVER_LOG_ERR("FSL_SAI_xCR4 %08x", read_val); return HDF_SUCCESS; } @@ -1158,45 +1245,17 @@ int32_t SaiHwFree(const struct DaiData *pd, int isTx) #define NUM_128 (128) #define DELAY_10 (10) -int32_t SaiDriverInit(struct PlatformData *pd) +int32_t SaiDriverInitClk(struct PrivPlatformData *ppd, void __iomem *base) { - struct PrivPlatformData *ppd = (struct PrivPlatformData *)pd->dmaPrv; - struct device_node *np = NULL; - struct resource *res = NULL; - struct fsl_sai *sai = NULL; - void __iomem *base = NULL; - char tmp[8]; - int irq = 0, ret = 0, i = 0; + int ret = 0, i = 0;; + struct fsl_sai *sai = &ppd->sai; unsigned long clk_rate = 0; - int ret = 0; + char tmp[8]; - sai = &ppd->sai; - g_sai = sai; - - np = ppd->pdev->dev.of_node; - - ret = of_clk_set_defaults(np, false); - if (ret < 0) { - AUDIO_DRIVER_LOG_ERR("sai driver init clk set default failed"); - return HDF_FAILURE; - } - - sai->is_lsb_first = of_property_read_bool(np, "lsb-first"); - - res = platform_get_resource(ppd->pdev, IORESOURCE_MEM, 0); - base = devm_ioremap_resource(&ppd->pdev->dev, res); - if (IS_ERR(base)) { - return PTR_ERR(base); - } - - sai->reg_offset = FSL_REG_OFFSET; - - sai->regmap = devm_regmap_init_mmio_clk(&ppd->pdev->dev, "bus", base, - &fsl_sai_regmap_config); + sai->regmap = devm_regmap_init_mmio_clk(&ppd->pdev->dev, "bus", base, &fsl_sai_regmap_config); if (IS_ERR(sai->regmap) && PTR_ERR(sai->regmap) != -EPROBE_DEFER) { - sai->regmap = devm_regmap_init_mmio_clk(&ppd->pdev->dev, - "sai", base, &fsl_sai_regmap_config); + sai->regmap = devm_regmap_init_mmio_clk(&ppd->pdev->dev, "sai", base, &fsl_sai_regmap_config); } if (IS_ERR(sai->regmap)) { AUDIO_DRIVER_LOG_ERR("regmap init failed\n"); @@ -1220,12 +1279,10 @@ int32_t SaiDriverInit(struct PlatformData *pd) } sai->mclk_clk[i] = devm_clk_get(&ppd->pdev->dev, tmp); if (IS_ERR(sai->mclk_clk[i])) { - AUDIO_DRIVER_LOG_ERR("failed to get mclk%d clock: %ld\n", - i, PTR_ERR(sai->mclk_clk[i])); + AUDIO_DRIVER_LOG_ERR("failed to get mclk%d clock: %ld\n", i, PTR_ERR(sai->mclk_clk[i])); sai->mclk_clk[i] = NULL; } clk_rate = clk_get_rate(sai->mclk_clk[i]); - AUDIO_DRIVER_LOG_ERR("mclk %d rate %d", i, clk_rate); } sai->pll8k_clk = devm_clk_get(&ppd->pdev->dev, "pll8k"); @@ -1237,10 +1294,13 @@ int32_t SaiDriverInit(struct PlatformData *pd) if (IS_ERR(sai->pll11k_clk)) { sai->pll11k_clk = NULL; } + return ret; +} - sai->reg_offset = FSL_REG_OFFSET; - sai->dataline = 0xFF; - sai->fifo_depth = NUM_128; +int32_t SaiDriverInitDataline(struct PrivPlatformData *ppd) +{ + int ret = 0; + struct fsl_sai *sai = &ppd->sai; ret = fsl_sai_read_dlcfg(ppd->pdev, "fsl,dataline", &sai->pcm_dl_cfg, sai->dataline); @@ -1258,6 +1318,14 @@ int32_t SaiDriverInit(struct PlatformData *pd) sai->dsd_dl_cfg_cnt = ret; + return ret; +} + +int32_t SaiDriverInitIrq(struct PrivPlatformData *ppd, struct device_node *np) +{ + int irq = 0, ret = 0; + struct fsl_sai *sai = &ppd->sai; + irq = platform_get_irq(ppd->pdev, 0); if (irq < 0) { AUDIO_DRIVER_LOG_ERR("failed to get irq"); @@ -1291,6 +1359,14 @@ int32_t SaiDriverInit(struct PlatformData *pd) sai->synchronous[TX] = false; } + return ret; +} + +int32_t SaiDriverInitDma(struct PrivPlatformData *ppd, struct device_node *np) +{ + int ret = 0; + struct fsl_sai *sai = &ppd->sai; + platform_set_drvdata(ppd->pdev, sai); ret = fsl_sai_check_ver(sai, &ppd->pdev->dev); if (ret < 0) { @@ -1313,136 +1389,183 @@ int32_t SaiDriverInit(struct PlatformData *pd) pm_runtime_enable(&ppd->pdev->dev); - AUDIO_DRIVER_LOG_ERR("success probe in sai driver"); + return ret; +} +int32_t SaiDriverInit(struct PlatformData *pd) +{ + struct PrivPlatformData *ppd = (struct PrivPlatformData *)pd->dmaPrv; + struct device_node *np = ppd->pdev->dev.of_node; + struct resource *res = NULL; + struct fsl_sai *sai = &ppd->sai; + void __iomem *base = NULL; + int ret = 0; + g_sai = sai; + + ret = of_clk_set_defaults(np, false); + if (ret < 0) { + AUDIO_DRIVER_LOG_ERR("sai driver init clk set default failed"); + return HDF_FAILURE; + } + + sai->is_lsb_first = of_property_read_bool(np, "lsb-first"); + res = platform_get_resource(ppd->pdev, IORESOURCE_MEM, 0); + base = devm_ioremap_resource(&ppd->pdev->dev, res); + if (IS_ERR(base)) { + return PTR_ERR(base); + } + + sai->reg_offset = FSL_REG_OFFSET; + ret = SaiDriverInitClk(ppd, base); + if (ret != HDF_SUCCESS) { + ADM_LOG_ERR("SaiDriverInitClk fail ret=%d", ret); + return ret; + } + sai->dataline = 0xFF; + sai->fifo_depth = NUM_128; + ret = SaiDriverInitDataline(ppd); + if (ret != HDF_SUCCESS) { + ADM_LOG_ERR("SaiDriverInitDataline fail ret=%d", ret); + return ret; + } + ret = SaiDriverInitIrq(ppd, np); + if (ret != HDF_SUCCESS) { + ADM_LOG_ERR("SaiDriverInitIrq fail ret=%d", ret); + return ret; + } + ret = SaiDriverInitDma(ppd, np); + if (ret != HDF_SUCCESS) { + ADM_LOG_ERR("SaiDriverInitDma fail ret=%d", ret); + return ret; + } + AUDIO_DRIVER_LOG_ERR("success probe in sai driver"); return HDF_SUCCESS; } +void SaiTriggerStart(struct fsl_sai *sai, bool tx, u8 channels, u32 dl_mask, u32 pins) +{ + unsigned char offset = sai->reg_offset; + int i = 0, j = 0, k = 0; + /* + * Asynchronous mode: Clear SYNC for both Tx and Rx. + * Rx sync with Tx clocks: Clear SYNC for Tx, set it for Rx. + * Tx sync with Rx clocks: Clear SYNC for Rx, set it for Tx. + */ + regmap_update_bits(sai->regmap, FSL_SAI_TCR2(offset), FSL_SAI_CR2_SYNC, + sai->synchronous[TX] ? FSL_SAI_CR2_SYNC : 0); + regmap_update_bits(sai->regmap, FSL_SAI_RCR2(offset), FSL_SAI_CR2_SYNC, + sai->synchronous[RX] ? FSL_SAI_CR2_SYNC : 0); + + while (tx && i < channels) { + if (dl_mask & (1 << j)) { + regmap_write(sai->regmap, FSL_SAI_TDR0 + j * 0x4, 0x0); + i++; + k++; + } + j++; + + if ((pins != 0) && (k % pins) == 0) { + j = 0; + } + } + + regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx, offset), + FSL_SAI_CSR_FRDE, FSL_SAI_CSR_FRDE); + + regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx, offset), + FSL_SAI_CSR_TERE, FSL_SAI_CSR_TERE); + regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx, offset), + FSL_SAI_CSR_SE, FSL_SAI_CSR_SE); + if (!sai->synchronous[TX] && sai->synchronous[RX] && !tx) { + regmap_update_bits(sai->regmap, FSL_SAI_xCSR((!tx), offset), + FSL_SAI_CSR_TERE, FSL_SAI_CSR_TERE); + } else if (!sai->synchronous[RX] && sai->synchronous[TX] && tx) { + regmap_update_bits(sai->regmap, FSL_SAI_xCSR((!tx), offset), + FSL_SAI_CSR_TERE, FSL_SAI_CSR_TERE); + } + + regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx, offset), + FSL_SAI_CSR_xIE_MASK, FSL_SAI_FLAGS); +} +void SaiTriggerStop(struct fsl_sai *sai, bool tx) +{ + unsigned char offset = sai->reg_offset; + u32 xcsr = 0, count = 100; + + regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx, offset), + FSL_SAI_CSR_FRDE, 0); + regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx, offset), + FSL_SAI_CSR_xIE_MASK, 0); + + /* Check if the opposite FRDE is also disabled */ + regmap_read(sai->regmap, FSL_SAI_xCSR(!tx, offset), &xcsr); + if (!(xcsr & FSL_SAI_CSR_FRDE)) { + /* Disable both directions and reset their FIFOs */ + regmap_update_bits(sai->regmap, FSL_SAI_TCSR(offset), + FSL_SAI_CSR_TERE, 0); + regmap_update_bits(sai->regmap, FSL_SAI_RCSR(offset), + FSL_SAI_CSR_TERE, 0); + + /* TERE will remain set till the end of current frame */ + do { + udelay(DELAY_10); + regmap_read(sai->regmap, FSL_SAI_xCSR(tx, offset), &xcsr); + } while (((--count) && (xcsr)) & (FSL_SAI_CSR_TERE)); + + regmap_update_bits(sai->regmap, FSL_SAI_TCSR(offset), + FSL_SAI_CSR_FR, FSL_SAI_CSR_FR); + regmap_update_bits(sai->regmap, FSL_SAI_RCSR(offset), + FSL_SAI_CSR_FR, FSL_SAI_CSR_FR); + + /* + * For sai master mode, after several open/close sai, + * there will be no frame clock, and can't recover + * anymore. Add software reset to fix this issue. + * This is a hardware bug, and will be fix in the + * next sai version. + */ + if (!sai->slave_mode[tx]) { + /* Software Reset for both Tx and Rx */ + regmap_write(sai->regmap, + FSL_SAI_TCSR(offset), FSL_SAI_CSR_SR); + regmap_write(sai->regmap, + FSL_SAI_RCSR(offset), FSL_SAI_CSR_SR); + /* Clear SR bit to finish the reset */ + regmap_write(sai->regmap, FSL_SAI_TCSR(offset), 0); + regmap_write(sai->regmap, FSL_SAI_RCSR(offset), 0); + } + } +} + int32_t SaiTrigger(const struct DaiData *pd, int cmd, int isTx) { struct fsl_sai *sai = g_sai; - unsigned char offset = sai->reg_offset; - u8 channels = 0; bool tx = isTx == TRIGGER_TX; + u8 channels = 0; + u32 slots = (channels == 1) ? 2 : channels; + u32 pins = 0; + u32 dl_mask = 0; + if (isTx == TRIGGER_TX) { channels = pd->pcmInfo.channels; } else if (isTx == TRIGGER_RX) { channels = pd->pcmInfo.channels; } - u32 slots = (channels == 1) ? 2 : channels; - u32 xcsr = 0, count = 100; - u32 pins = 0; - int i = 0, j = 0, k = 0, dl_cfg_cnt = 0, dl_cfg_idx = 0; - struct fsl_sai_dl_cfg *dl_cfg; - if (sai->slots) { slots = sai->slots; } pins = DIV_ROUND_UP(channels, slots); - sai->is_dsd = false; + dl_mask = SaiGetdlMask(sai, tx, pins); - dl_cfg = sai->pcm_dl_cfg; - dl_cfg_cnt = sai->pcm_dl_cfg_cnt; - - for (i = 0; i < dl_cfg_cnt; i++) { - if (dl_cfg[i].pins == pins) { - dl_cfg_idx = i; - break; - } - } - - i = 0; if (cmd == TRIGGER_START) { - /* - * Asynchronous mode: Clear SYNC for both Tx and Rx. - * Rx sync with Tx clocks: Clear SYNC for Tx, set it for Rx. - * Tx sync with Rx clocks: Clear SYNC for Rx, set it for Tx. - */ - regmap_update_bits(sai->regmap, FSL_SAI_TCR2(offset), FSL_SAI_CR2_SYNC, - sai->synchronous[TX] ? FSL_SAI_CR2_SYNC : 0); - regmap_update_bits(sai->regmap, FSL_SAI_RCR2(offset), FSL_SAI_CR2_SYNC, - sai->synchronous[RX] ? FSL_SAI_CR2_SYNC : 0); - - while (tx && i < channels) { - if (dl_cfg[dl_cfg_idx].mask[tx] & (1 << j)) { - regmap_write(sai->regmap, FSL_SAI_TDR0 + j * 0x4, 0x0); - i++; - k++; - } - j++; - - if ((pins != 0) && (k % pins) == 0) { - j = 0; - } - } - - regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx, offset), - FSL_SAI_CSR_FRDE, FSL_SAI_CSR_FRDE); - - regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx, offset), - FSL_SAI_CSR_TERE, FSL_SAI_CSR_TERE); - regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx, offset), - FSL_SAI_CSR_SE, FSL_SAI_CSR_SE); - if (!sai->synchronous[TX] && sai->synchronous[RX] && !tx) { - regmap_update_bits(sai->regmap, FSL_SAI_xCSR((!tx), offset), - FSL_SAI_CSR_TERE, FSL_SAI_CSR_TERE); - } else if (!sai->synchronous[RX] && sai->synchronous[TX] && tx) { - regmap_update_bits(sai->regmap, FSL_SAI_xCSR((!tx), offset), - FSL_SAI_CSR_TERE, FSL_SAI_CSR_TERE); - } - - regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx, offset), - FSL_SAI_CSR_xIE_MASK, FSL_SAI_FLAGS); + SaiTriggerStart(sai, tx, channels, dl_mask); } else { - regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx, offset), - FSL_SAI_CSR_FRDE, 0); - regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx, offset), - FSL_SAI_CSR_xIE_MASK, 0); - - /* Check if the opposite FRDE is also disabled */ - regmap_read(sai->regmap, FSL_SAI_xCSR(!tx, offset), &xcsr); - if (!(xcsr & FSL_SAI_CSR_FRDE)) { - /* Disable both directions and reset their FIFOs */ - regmap_update_bits(sai->regmap, FSL_SAI_TCSR(offset), - FSL_SAI_CSR_TERE, 0); - regmap_update_bits(sai->regmap, FSL_SAI_RCSR(offset), - FSL_SAI_CSR_TERE, 0); - - /* TERE will remain set till the end of current frame */ - do { - udelay(DELAY_10); - regmap_read(sai->regmap, FSL_SAI_xCSR(tx, offset), &xcsr); - } while (((--count) && (xcsr)) & (FSL_SAI_CSR_TERE)); - - regmap_update_bits(sai->regmap, FSL_SAI_TCSR(offset), - FSL_SAI_CSR_FR, FSL_SAI_CSR_FR); - regmap_update_bits(sai->regmap, FSL_SAI_RCSR(offset), - FSL_SAI_CSR_FR, FSL_SAI_CSR_FR); - - /* - * For sai master mode, after several open/close sai, - * there will be no frame clock, and can't recover - * anymore. Add software reset to fix this issue. - * This is a hardware bug, and will be fix in the - * next sai version. - */ - if (!sai->slave_mode[tx]) { - /* Software Reset for both Tx and Rx */ - regmap_write(sai->regmap, - FSL_SAI_TCSR(offset), FSL_SAI_CSR_SR); - regmap_write(sai->regmap, - FSL_SAI_RCSR(offset), FSL_SAI_CSR_SR); - /* Clear SR bit to finish the reset */ - regmap_write(sai->regmap, FSL_SAI_TCSR(offset), 0); - regmap_write(sai->regmap, FSL_SAI_RCSR(offset), 0); - } - } + SaiTriggerStop(sai, tx); } SaiPrintAllRegister(); - return HDF_SUCCESS; } diff --git a/imx8mm/drivers/wifi/ap6212/hdfadapter/hdf_mac80211.c b/imx8mm/drivers/wifi/ap6212/hdfadapter/hdf_mac80211.c index 0224abe..d924b8a 100644 --- a/imx8mm/drivers/wifi/ap6212/hdfadapter/hdf_mac80211.c +++ b/imx8mm/drivers/wifi/ap6212/hdfadapter/hdf_mac80211.c @@ -713,27 +713,13 @@ int32_t WalDisconnect(NetDevice *netDev, uint16_t reasonCode) return retVal; } -struct cfg80211_scan_request g_request; -int32_t WalStartScan(NetDevice *netDev, struct WlanScanRequest *scanParam) +int32_t WalBuildChannelInfo(struct wiphy* wiphy, struct WlanScanRequest *scanParam, + struct cfg80211_scan_request **request) { int32_t loop; int32_t count = 0; - int32_t retVal = 0; - enum Ieee80211Band band = IEEE80211_BAND_2GHZ; struct ieee80211_channel *chan = NULL; - struct wiphy* wiphy = wrap_get_wiphy(); - - struct cfg80211_scan_request *request = &g_request; - - if (request == NULL) { - HDF_LOGE("%s: calloc request null!\n", __func__); - return HDF_FAILURE; - } - - // basic info - request->wiphy = wiphy; - request->wdev = GET_NET_DEV_CFG80211_WIRELESS(netDev); - request->n_ssids = scanParam->ssidCount; + enum Ieee80211Band band = IEEE80211_BAND_2GHZ; // channel info if ((scanParam->freqs == NULL) || (scanParam->freqsCount == 0)) { @@ -747,17 +733,16 @@ int32_t WalStartScan(NetDevice *netDev, struct WlanScanRequest *scanParam) if ((chan->flags & WIFI_CHAN_DISABLED) != 0) { continue; } - request->channels[count++] = chan; + (*request)->channels[count++] = chan; } } else { for (loop = 0; loop < scanParam->freqsCount; loop++) { chan = GetChannelByFreq(wiphy, (uint16_t)(scanParam->freqs[loop])); if (chan == NULL) { - HDF_LOGE("%s: freq not found!freq=%d!\n", __func__, scanParam->freqs[loop]); continue; } - request->channels[count++] = chan; + (*request)->channels[count++] = chan; } } @@ -765,11 +750,14 @@ int32_t WalStartScan(NetDevice *netDev, struct WlanScanRequest *scanParam) HDF_LOGE("%s: invalid freq info!\n", __func__); return HDF_FAILURE; } - request->n_channels = count; + (*request)->n_channels = count; - // ssid info - count = 0; - loop = 0; + return HDF_SUCCESS; +} + +int32_t WalBuildSSidInfo(struct WlanScanRequest *scanParam, struct cfg80211_scan_request **request) +{ + int32_t loop, count = 0, retVal = 0; if (scanParam->ssidCount > WPAS_MAX_SCAN_SSIDS) { HDF_LOGE("%s:unexpected numSsids!numSsids=%u", __func__, scanParam->ssidCount); return HDF_FAILURE; @@ -780,7 +768,7 @@ int32_t WalStartScan(NetDevice *netDev, struct WlanScanRequest *scanParam) return HDF_SUCCESS; } - request->ssids = (struct cfg80211_ssid *)OsalMemCalloc(scanParam->ssidCount * sizeof(struct cfg80211_ssid)); + (*request)->ssids = (struct cfg80211_ssid *)OsalMemCalloc(scanParam->ssidCount * sizeof(struct cfg80211_ssid)); if (request->ssids == NULL) { HDF_LOGE("%s: calloc request->ssids null", __func__); return HDF_FAILURE; @@ -795,25 +783,53 @@ int32_t WalStartScan(NetDevice *netDev, struct WlanScanRequest *scanParam) continue; } - request->ssids[count].ssid_len = scanParam->ssids[loop].ssidLen; - if (memcpy_s(request->ssids[count].ssid, OAL_IEEE80211_MAX_SSID_LEN, scanParam->ssids[loop].ssid, + (*request)->ssids[count].ssid_len = scanParam->ssids[loop].ssidLen; + if (memcpy_s((*request)->ssids[count].ssid, OAL_IEEE80211_MAX_SSID_LEN, scanParam->ssids[loop].ssid, scanParam->ssids[loop].ssidLen) != 0) { continue; } count++; } - request->n_ssids = count; + (*request)->n_ssids = count; + + return HDF_SUCCESS; +} + +struct cfg80211_scan_request g_request; +int32_t WalStartScan(NetDevice *netDev, struct WlanScanRequest *scanParam) +{ + int32_t loop, count = 0, retVal = 0; + enum Ieee80211Band band = IEEE80211_BAND_2GHZ; + struct ieee80211_channel *chan = NULL; + struct wiphy* wiphy = wrap_get_wiphy(); + struct cfg80211_scan_request *request = &g_request; + + if (request == NULL) { + return HDF_FAILURE; + } + + // basic info + request->wiphy = wiphy; + request->wdev = GET_NET_DEV_CFG80211_WIRELESS(netDev); + request->n_ssids = scanParam->ssidCount; + + if (WalBuildChannelInfo(wiphy, scanParam, &request) == HDF_FAILURE) { + return HDF_FAILURE; + } + + // ssid info + if (WalBuildSSidInfo(scanParam, &request) == HDF_FAILURE) { + return HDF_FAILURE; + } // User Ie Info if (scanParam->extraIEsLen > 512) { - HDF_LOGE("%s:unexpected extra len!extraIesLen=%d", __func__, scanParam->extraIEsLen); return HDF_FAILURE; } if ((scanParam->extraIEs != NULL) && (scanParam->extraIEsLen != 0)) { request->ie = (uint8_t *)OsalMemCalloc(scanParam->extraIEsLen); if (request->ie == NULL) { - HDF_LOGE("%s: calloc request->ie null", __func__); if (request->ie != NULL) { OsalMemFree((void*)request->ie); request->ie = NULL; @@ -827,7 +843,6 @@ int32_t WalStartScan(NetDevice *netDev, struct WlanScanRequest *scanParam) retVal = (int32_t)wl_cfg80211_ops.scan(wiphy, request); if (retVal < 0) { - HDF_LOGE("%s: scan Failed!", __func__); if (request != NULL) { if ((request)->ie != NULL) { OsalMemFree((void*)(request->ie)); @@ -840,8 +855,6 @@ int32_t WalStartScan(NetDevice *netDev, struct WlanScanRequest *scanParam) OsalMemFree(request); request = NULL; } - } else { - HDF_LOGE("%s: scan OK!", __func__); } return retVal;