int32_t I2S_Output()

in IndustrialDeviceController/Software/MT3620_IDC_RTApp/lib/I2S.c [191:306]


int32_t I2S_Output(
    I2S *handle, I2S_Format format, unsigned channels, unsigned bits, unsigned rate,
    bool (*callback)(void *data, uintptr_t size))
{
    if (!handle) {
        return ERROR_PARAMETER;
    }
    if (!handle->open) {
        return ERROR_HANDLE_CLOSED;
    }
    unsigned id = handle->id;

    bool            enable = (format != I2S_FORMAT_NONE);
    bool            tdm    = false;
    mt3620_i2s_sr_t sr     = MT3620_I2S_SR_48K;
    if (enable) {
        if (channels == 0) {
            return ERROR_PARAMETER;
        }

        switch (format) {
        case I2S_FORMAT_I2S:
            if (channels > 2) {
                return ERROR_PARAMETER;
            }
            break;

        case I2S_FORMAT_TDM:
            if ((channels > 4) || (channels % 2)) {
                return ERROR_UNSUPPORTED;
            }
            tdm = true;
            break;

        default:
            return ERROR_PARAMETER;
        }

        if (bits != 16) {
            return ERROR_UNSUPPORTED;
        }

        sr = I2S_SampleRate(rate);
        if (sr >= MT3620_I2S_SR_COUNT) {
            return ERROR_UNSUPPORTED;
        }
    }

    mt3620_i2s_global_control_t global_control = { .mask = mt3620_i2s[id]->global_control };
    if (enable) {
        global_control.dl_mono           = (channels == 1);
        global_control.dl_mono_dup       = (channels == 1);
        global_control.i2s_out_clk_en    = true;
        global_control.dl_empty_value_en = true;
        global_control.clk_sel_out       = MT3620_I2S_CLK_SEL_EXTERNAL;
        mt3620_i2s[id]->global_control = global_control.mask;
    }

    mt3620_i2s_dl_control_t dl_control = { .mask = mt3620_i2s[id]->dl_control };
    dl_control.en = enable;
    if (enable) {
        dl_control.wlen        = MT3620_I2S_WLEN_16BIT;
        dl_control.src         = MT3620_I2S_SRC_SLAVE;
        dl_control.fmt         = (tdm ? MT3620_I2S_FMT_TDM : MT3620_I2S_FMT_I2S);
        dl_control.wsinv       = tdm;
        dl_control.dlfifo_2deq = (tdm && (channels == 4));
        dl_control.sr          = sr;
        dl_control.bit_per_s   = (tdm && (channels == 4) ? 1 : 0);
        dl_control.ws_rsync    = true; // Functional Spec recommends this be on.
        dl_control.msb_offset  = 0;
        dl_control.ch_per_s    = (tdm && (channels == 4) ? 1 : 0);
    }
    mt3620_i2s[id]->dl_control = dl_control.mask;

    if (enable) {
        // Enable DMA.
        mt3620_dma_global->ch_en_set = (1U << MT3620_I2S_DMA_TX(id));
        MT3620_DMA_FIELD_WRITE(MT3620_I2S_DMA_TX(id), start, str, false);
        mt3620_dma_con_t dma_con_tx = { .mask = mt3620_dma[MT3620_I2S_DMA_TX(id)].con };
        dma_con_tx.dir   = 0;
        dma_con_tx.iten  = true;
        dma_con_tx.dreq  = true;
        dma_con_tx.size  = (channels == 1 ? 1 : 2);
        mt3620_dma[MT3620_I2S_DMA_TX(id)].con     = dma_con_tx.mask;
        mt3620_dma[MT3620_I2S_DMA_TX(id)].fixaddr = (void *)mt3620_i2s_fifo[id];
        mt3620_dma[MT3620_I2S_DMA_TX(id)].pgmaddr = (void *)I2S_Buffer[id][0];
        mt3620_dma[MT3620_I2S_DMA_TX(id)].swptr   = 0;
        mt3620_dma[MT3620_I2S_DMA_TX(id)].ffsize  = (I2S_BUFFER_SIZE >> dma_con_tx.size);
        mt3620_dma[MT3620_I2S_DMA_TX(id)].count   = (mt3620_dma[MT3620_I2S_DMA_TX(id)].ffsize / 4);
    } else {
        MT3620_DMA_FIELD_WRITE(MT3620_I2S_DMA_TX(id), start, str, false);
        mt3620_dma_global->ch_en_clr = (1U << MT3620_I2S_DMA_TX(id));
    }

    // Enable DMA handshakes for master mode.
    mt3620_i2s_dma_if_control_t dma_if_control = { .mask = mt3620_i2s[id]->dma_if_control };
    dma_if_control.dl_dmareq_mi_num = (enable ? 1 : 0);
    dma_if_control.dl_ahb_early_en  = enable;
    dma_if_control.dl_dma_mode_sel  = enable;
    mt3620_i2s[id]->dma_if_control = dma_if_control.mask;

    // Enable I2S.
    global_control.en = (enable || handle->in.enable);
    global_control.dlfifo_en = enable;
    mt3620_i2s[id]->global_control = global_control.mask;

    handle->out.enable   = enable;
    handle->out.channels = channels;
    handle->out.callback = callback;

    if (enable) {
        MT3620_DMA_FIELD_WRITE(MT3620_I2S_DMA_TX(id), start, str, true);
    }

    return ERROR_NONE;
}