原文:http://lxr.linux.no/#linux+v2.6.32/Documentation/sound/alsa/soc/

Embedded linux 裡的audio通常是由ASoC (Alsa System on Chip)這個subsystem實作,此subsystem由Wolfson提出,用來針對portable embedded system的聲音支援。

ASoC subsystem對embedded SoC及可攜式的auido codec提供較好alsa支援。在ASoC subsystem之前,在kernel也有SoC audio的支援,但有一些限制:
1. codec driver跟SoC CPU有相依性,因此不同的cpu就需要不同的driver
2. 對於audio event (如插入headphone/mic)並沒有標準的通知方法。
3. power management的支援較差

ASoC的設計

ASoC就是要解決上述限制,其特色如下:
1. codec independence:不同platform可用同一隻codec driver
2. 在codec/CPU之間的簡易I2S/PCM/AC97介面
3. DAPM (Dynamic Audio Power Management)
4. 減少pop和click (audio component在power up/down時的副作用,就是雜音啦)
5. 對音效卡特定的控制,如控制放大器的音量。Machine透過I2C控制codec。

因此,在設計上,將audio system分成3個部分:


Codec driver

與平台無關,並包括audio controls, audio interface capabilities, codec DAPM definition and codec IO functions。codec driver是通用且硬體無關,讓codec可提供audio playback和capture。與硬體相關的程式硬應寫在machine/platform driver。
code driver必須提供以下特色:

Codec DAI and PCM configuration

playback和capture的結構如下:

struct snd_soc_dai wm8731_dai = {snd_soc_platfor

    .name = "WM8731",
    .playback = {
        .stream_name = "Playback",
        .channels_min = 1,
        .channels_max = 2,
        .rates = WM8731_RATES,
        .formats = WM8731_FORMATS,},
    .capture = {
        .stream_name = "Capture",
        .channels_min = 1,
        .channels_max = 2,
        .rates = WM8731_RATES,
        .formats = WM8731_FORMATS,},
    .ops = &wm8731_dai_ops,
};

PCM的instance由playback和capture組成。platform driver會對每個DAI註冊一個這樣的ops,主要是clocking (set_sysclk, set_pll, set_clkdiv), format configuration (set_fmt, set_tdm_slot, set_tristate) 和alsa operation (startup/suhutdown, hw_params, hw_free, prepare, trigger),這些都是在codec driver實作。

 

Codec control IO - using I2C, 3 Wire(SPI) or both APIs

通常是由I2C或是SPI來設定register的值,因提要提供read/write這兩個function:

static unsigned int rt5626_read(struct snd_soc_codec *codec, unsigned int reg)

static int rt5626_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int value)


。Mixers and audio controls

這是對output mixer register的read/write:

static struct soc_enum rt5626_enum[] = {
SOC_ENUM_SINGLE(RT5626_OUTPUT_MIXER_CTRL, 13, 2, rt5626_spk_out_sel),                /*0*/
SOC_ENUM_SINGLE(RT5626_OUTPUT_MIXER_CTRL, 14, 4,rt5626_spk_l_source_sel),            /*1*/
SOC_ENUM_SINGLE(RT5626_OUTPUT_MIXER_CTRL, 10, 3, rt5626_spk_source_sel),            /*2*/
SOC_ENUM_SINGLE(RT5626_OUTPUT_MIXER_CTRL, 9, 2, rt5626_hpl_source_sel),              /*3*/
SOC_ENUM_SINGLE(RT5626_OUTPUT_MIXER_CTRL, 8, 2, rt5626_hpr_source_sel),             /*4*/
SOC_ENUM_SINGLE(RT5626_GP_CONTROL, 9, 6, rt5626_classd_ratio_sel),                           /*5*/
SOC_ENUM_SINGLE(RT5626_OUTPUT_MIXER_CTRL, 1, 2, rt5626_direct_out_sel),                  /*6*/
SOC_ENUM_SINGLE(VIRTUAL_REG_FOR_MISC_FUNC, 4, 9, rt5626_eq_sel),                                  /*7*/
};

SOC_ENUM_SINGLE這類的Macro定義在soc.h。
RT5626_OUTPUT_MIXER_CTRL就是output mixer register的offset

#define RT5626_OUTPUT_MIXER_CTRL (0x1C)

相關的register資訊則要從spec得知

Codec audio operations

這就是第一項提到的startup/suhutdown, hw_params, hw_free, prepare, trigger這些實作

以下為optional:

DAPM description
DAPM event handler.

DAPM就是power manager相關,應該是clock相關的設定


DAC Digital mute control.

這個mute function是用來最小化noise,因為DAC沒有任何的input data (mute line out/headphone out)。

 

Platform driver

分成兩部分: DMA engine和audio interface driver (e.g. I2S, AC97, PCM)。主要是audio DMA以及SoC DAI的設定和控制。platform driver是跟cpu相關的code,而與板子無關。

Audio DMA的部分為alsa operation:

/* SoC audio ops */
struct snd_soc_ops {
    int (*startup)(struct snd_pcm_substream *);
    void (*shutdown)(struct snd_pcm_substream *);
    int (*hw_params)(struct snd_pcm_substream *, struct snd_pcm_hw_params *);
    int (*hw_free)(struct snd_pcm_substream *);
    int (*prepare)(struct snd_pcm_substream *);
    int (*trigger)(struct snd_pcm_substream *, int);
};

這個地方的function跟codec的 alsa operation是一樣的,都是設定 clocking和formatting 等,看起來是時間點不一樣。codec是userspace透過alsa-lib下來的。

下面是DMA的功能,不過在wm8580的platform driver並沒有看到相關實作。

/* SoC platform interface */
struct snd_soc_platform {
    char *name;
    struct list_head list;

    int (*probe)(struct platform_device *pdev);
    int (*remove)(struct platform_device *pdev);
    int (*suspend)(struct snd_soc_dai *dai);
    int (*resume)(struct snd_soc_dai *dai);

    /* pcm creation and destruction */
    int (*pcm_new)(struct snd_card *, struct snd_soc_dai *,
        struct snd_pcm *);
    void (*pcm_free)(struct snd_pcm *);

    /* platform stream ops */
    struct snd_pcm_ops *pcm_ops;
};

DAI driver 還是有clocking. formatting的設定。

Machine driver

machine specific control以及audio event。是platform driver和codec driver的介面。machine driver包括與codec和platform相關的code,並將audio subsystem向kernel註冊為platform device。其主要是對CPU的驅動,並調用codec driver和platform driver

snd_soc_card的結構,這在向platform註冊為platform device時會用到 (platform_device_alloc("soc-audio", 0);)

/* SoC card */
struct snd_soc_card {
    char *name;
    struct device *dev;

    struct list_head list;

    int instantiated;

    int lp_mode; /* if this card is operating in LowPower mode, where SUSPEND/RESUME doesn't matter */

    int (*probe)(struct platform_device *pdev);
    int (*remove)(struct platform_device *pdev);

    /* the pre and post PM functions are used to do any PM work before and
     * after the codec and DAI's do any PM work. */
    int (*suspend_pre)(struct platform_device *pdev, pm_message_t state);
    int (*suspend_post)(struct platform_device *pdev, pm_message_t state);
    int (*resume_pre)(struct platform_device *pdev);
    int (*resume_post)(struct platform_device *pdev);

    /* callbacks */
    int (*set_bias_level)(struct snd_soc_card *,
                  enum snd_soc_bias_level level);

    /* CPU <--> Codec DAI links  */
    struct snd_soc_dai_link *dai_link;
    int num_links;

    struct snd_soc_device *socdev;

    struct snd_soc_codec *codec;

    struct snd_soc_platform *platform;
    struct delayed_work delayed_work;
    struct work_struct deferred_resume_work;
};

 

machine driver的 DAI configuration將 codec (屬於codec driver)和cpu DAI (屬於platform driver) glue起來

static struct snd_soc_card smdkc100 = {
    .name = "smdkc100",
    .lp_mode = 0,
    .platform = &s3c_pcm_pdat.pcm_pltfm,
    .dai_link = smdkc100_dai,
    .num_links = ARRAY_SIZE(smdkc100_dai),
}; 

Machine Audio Subsystem

最後soc device將machine, platform, codec glue起來

在codec driver 指定i2c_address

//need check A1 pin(16pin),high is 0x1b,low is 0x1a
static struct rt5626_setup_data smdkc100_rt5626_setup = {
    .i2c_address = 0x1b,
};

再來是snd_soc_device

static struct snd_soc_device smdkc100_snd_devdata = {
    .card = &smdkc100,
    .codec_dev = &soc_codec_dev_rt5626,
    .codec_data = &smdkc100_rt5626_setup,

};

 

輔助資訊

DAI
即digital/audio interface。ASoC支援AC97,PCM及I2S。


AC97

intel提出的標準,全名為Audio Codec '97。這個audio codec指的是anolog/digital訊號的編碼/解碼轉換,因此是由ADC/DAC所組合而成。而一般的codec指的是digital格式的轉換,如mp3, mpeg4, H.264。

On-borad的audio由兩部份組成: DC '97 (AC '97 digital controller,built-in在南橋)和 AC '97 audio codec (處理anolog的部份,此做法降低了電磁干擾,是重要特色)。各vendor的DC特色和實作都不同,基本功能為透過AC-link控制audio codec。AC-link連接DC '97和AC '97 codec。有5條線,包括reset,SDATA_out,SDATA_IN (bidirectional),BCLK及FRAME,是pc的sound card常見的介面,現在的portable device也很常見。BCLK由codec driven(通常為12.288MHZ),而frame則由SoC controller driven。每個AC97 frame長度為21us,且分為13個slot。每個12.288MHz的stream被初成48K/256bit的frame (12.288M=48K*256),除第一個slot為16bit外,其餘為12個20bit的data slot。

Note: AC '97並不是音效卡的型號,而是音效卡的標準。

I2S
有4(3)條線,用於HiFi,STB及portable device。Tx/Rx用於audio transmission,BCLK及LRCK用來做sync。I2S較有彈性,controller和 codec都可 drive BCLK及LRCK。BCLK通常相依於sample rate及master system clock (sysclk)。LRCK就是sample rate。I2S的3條線 (serial bus):

1. 2個TDM data channel: 每個channel都佔固定的有效時間,時間到了channel互換。

2. word select: 指明用哪個channel, 有點類似CS (chip select)

3. clock line (SCK): typical為2.8MHz,最高可為3.125MHz

三線與四線的差別在於單雙向,三線只有輸出,四線可以雙相,可接ADC (for mic)。

PCM

PCM也是4條線,類似I2S。這4條為BCLK,SYNC (這兩條用做sync),Tx和Rx (這兩條傳audio data)。BCLK跟sample rate有關,而SYNC就是sample rate 。

2010/01/21

LPCM (Linear PCM)顧名思義就是連續性的採樣再轉成數位訊號,且不經過壓縮,而達到原音重現的效果。LPCM為DVD player的一種標準(CD為16bit/44.1K),一般機種只能(16bit/48K),高規的可達24bit/96K。而AC3, MPEG1 and MPEG2則屬於Non-linear PCM。

 

Clock

MCLK

master clock,用來驅動audio subsystem,其source可由crystal (fix rate),PLL或是CPU clock。主要用來對audio playback / capture產生sample rate。

 

FRAME

FRAME clock用來告知每個audio frame的開始,也就是下述的LRCK (sample rate)。clock間的關係如下:

BCLK = MCLK/x

            = LRCKx32/64

此關係與codec及cpu有關。在省電考量,會儘量拉低BCLK。

CDCLK (SYSCLK)由cpu產生,可當作codec的MCLK,此時為output。也可以codec產生,當input,一樣做為I2S的MCLK。CDCLK應為sample rate的256/384/512倍。以44.1K為例,SYSCLK一般是384倍,所以是16.9344MHz

 

Reference

集成声卡基础知识(AC '97)

arrow
arrow
    全站熱搜

    kezeodsnx 發表在 痞客邦 留言(1) 人氣()