1. 程式人生 > >openwrt pcm driver on mt7620 or rt5350

openwrt pcm driver on mt7620 or rt5350

檢視datasheet可以知道,mt7620和rt5350有相通的Audio元件
從openwrt14.07的kernel原始碼中,我們可以找到mt7620 i2s的驅動
我們的pcm驅動,可以基於i2s驅動進行改動。pcm驅動已傳至github,相關程式碼可以看這裡
主要改動了以下幾點:

1.暫存器相關

參考datasheet,定義PCM相關的暫存器,把i2s驅動裡對應的暫存器操作換成對PCM部分暫存器的操作

#define PCM_GLB_CFG 0x00
#define PCM_GLB_CFG_EN BIT(31)
#define PCM_GLB_CFG_DMA_EN BIT(30)
#define
PCM_GLB_CFG_CH0_TX_EN BIT(8)
#define PCM_GLB_CFG_CH0_RX_EN BIT(0) #define PCM_GLB_CFG_RFF_THRES 20 #define PCM_GLB_CFG_TFF_THRES 16 #define PCM_GLB_CFG_DFT_THRES (4 << PCM_GLB_CFG_RFF_THRES) | \ (4 << PCM_GLB_CFG_TFF_THRES) #define PCM_PCM_CFG 0x04 #define PCM_PCM_CFG_CLKOUT_EN BIT(30)
#define PCM_PCM_CFG_EXT_FSYNC BIT(27) #define PCM_PCM_CFG_LONG_FSYNC BIT(26) #define PCM_PCM_CFG_FSYNC_POL BIT(25) #define PCM_INT_STATUS 0x08 #define PCM_INT_EN 0x0C #define PCM_FF_STATUS 0x10 #define PCM_CH0_CFG 0x20 #define PCM_CH1_CFG 0x24 #define PCM_FSYNC_CFG 0x30 #define PCM_CH_CFG2 0x34 #define PCM_DIVCOMP_CFG 0x50
#define PCM_DIVCOMP_CFG_CLK_EN BIT(31) #define PCM_DIVINT_CFG 0x54 #define PCM_DIGDELAY_CFG 0x60 #define PCM_CH0_FIFO 0x80 #define PCM_CH1_FIFO 0x84

2.PCM Config相關

參考RT5350 Preliminary Datasheet.pdf第3.12.3節
Peripheral Channel Connection部分可知,
PCM Channel0 對應的GDMA Slot為4(RX)、6(TX),
在配置dma channel的時候做對應的改動即可

static void rt5350_init_pcm_config(struct rt5350_pcm *pcm)
{
    struct snd_dmaengine_dai_dma_data *dma_data;

    /* Playback */
    dma_data = &pcm->playback_dma_data;
    dma_data->maxburst = 16;
    dma_data->slave_id = 6;
    dma_data->addr = pcm->phys_base + PCM_CH0_FIFO; //only use channel 0

    /* Capture */
    dma_data = &pcm->capture_dma_data;
    dma_data->maxburst = 16;
    dma_data->slave_id = 4;
    dma_data->addr = pcm->phys_base + PCM_CH0_FIFO;
}

3.PCM時序相關

以rt5350做pcm slave,sim800模組做master為例
sim800模組的pcm引數如下:

a) PCM clock 為256kHz

b) PCM sync 為 short sync,極性為高有效

於是參考datasheet對PCM_CFG暫存器的描述,可以得到下面改動

rt5350_pcm_dai_probe
    ///////////// pcm general config
    cfg = rt5350_pcm_read(pcm, PCM_FSYNC_CFG);
    cfg &= ~PCM_PCM_CFG_LONG_FSYNC; //short sync mode
    cfg |= PCM_PCM_CFG_FSYNC_POL; // sync high active

    //slot mode, pcm clock = 256KHz
    cfg &= ~(0x07);
    cfg = 0; // 4 slots

    rt5350_pcm_write(pcm, PCM_PCM_CFG, cfg);

    ///////////// pcm sync config
    cfg = rt5350_pcm_read(pcm, PCM_FSYNC_CFG);
    // pol, etc.

    rt5350_pcm_write(pcm, PCM_FSYNC_CFG, cfg);

    //When using the external clock, the frequency clock
    //should be equal to the PCM_clock out. Otherwise, the
    //PCM_CLKin should be 8.192 MHz.
    rt5350_pcm_write(pcm, PCM_DIVINT_CFG, i2sMaster_inclk_int[PCMCLOCK_OUT]);
    rt5350_pcm_write(pcm, PCM_DIVCOMP_CFG, i2sMaster_inclk_comp[PCMCLOCK_OUT] | PCM_DIVCOMP_CFG_CLK_EN);
----------------------------
rt5350_pcm_set_fmt
    cfg = rt5350_pcm_read(pcm, PCM_PCM_CFG);

    switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
    case SND_SOC_DAIFMT_CBS_CFS:
        cfg &= ~PCM_PCM_CFG_CLKOUT_EN; // pcm clock from external
        cfg |= PCM_PCM_CFG_EXT_FSYNC; // pcm sync from external
        break;
    case SND_SOC_DAIFMT_CBM_CFM:
        cfg |= PCM_PCM_CFG_CLKOUT_EN; // pcm clock from internal
        cfg &= ~PCM_PCM_CFG_EXT_FSYNC; // pcm sync from internal
        break;
    case SND_SOC_DAIFMT_CBM_CFS:
    default:
        return -EINVAL;
    }

    rt5350_pcm_write(pcm, PCM_PCM_CFG, cfg);

4.管腳定義

因為rt5350/mt7620上PCM是複用腳,所以需要配置成PCM功能,
這部分通過修改dts檔案即可,
另外,PCM驅動裝置節點的宣告,codec machine層、codec層驅動裝置節點的宣告
也都是在dts檔案裡完成,
具體如下

rt5350.dtsi

        pcm: [email protected]2000 {
            compatible = "ralink,rt5350-pcm";
            reg = <0x2000 0x800>;

            resets = <&rstctrl 11>;
            reset-names = "pcm";

            interrupt-parent = <&intc>;
            interrupts = <4>;

            dmas = <&gdma 4>,
                <&gdma 5>;
            dma-names = "tx", "rx";

            status = "disabled";
        };

SXX.dts

    //使能pcm驅動
    [email protected]10000000 {
        [email protected]2000 {
            status = "okay";
        };
    }

    //管腳功能初始化
    pinctrl {
        state_default: pinctrl0 {
            gpio {
                ralink,group = "i2c", "jtag";
                ralink,function = "gpio";
            };
            uartf {
                ralink,group = "uartf";
                ralink,function = "pcm uartf";
            };
        };
    };

    //宣告codec裝置節點
    codec: sxx-pcm-codec {
        compatible = "ralink,sxx-pcm-codec";
    };

    //宣告codec machine層裝置節點
    sound: sxx-pcm-machine {
        compatible = "ralink,sxx-pcm-machine";
        model = "sxx-pcm-machine";
        cpu-dai = <&pcm>;
        codec-dai = <&codec>;
    };