ASoC 編解碼器類驅動

編解碼器類驅動是通用的、與硬體無關的程式碼,用於配置編解碼器、FM、MODEM、BT 或外部 DSP,以提供音訊捕獲和播放。它不應包含任何特定於目標平臺或機器的程式碼。所有平臺和機器特定的程式碼都應分別新增到平臺和機器驅動程式中。

每個編解碼器類驅動必須提供以下功能:-

  1. 編解碼器 DAI 和 PCM 配置

  2. 編解碼器控制 IO - 使用 RegMap API

  3. 混音器和音訊控制

  4. 編解碼器音訊操作

  5. DAPM 描述。

  6. DAPM 事件處理程式。

可選地,編解碼器驅動程式還可以提供:-

  1. DAC 數字靜音控制。

最好將本指南與 sound/soc/codecs/ 中現有的編解碼器驅動程式程式碼結合使用。

ASoC 編解碼器驅動程式分解

編解碼器 DAI 和 PCM 配置

每個編解碼器驅動程式都必須有一個 struct snd_soc_dai_driver 來定義其 DAI 和 PCM 功能和操作。該結構已匯出,因此您的機器驅動程式可以向核心註冊它。

例如:

static struct snd_soc_dai_ops wm8731_dai_ops = {
      .prepare        = wm8731_pcm_prepare,
      .hw_params      = wm8731_hw_params,
      .shutdown       = wm8731_shutdown,
      .mute_stream    = wm8731_mute,
      .set_sysclk     = wm8731_set_dai_sysclk,
      .set_fmt        = wm8731_set_dai_fmt,
};

struct snd_soc_dai_driver wm8731_dai = {
      .name = "wm8731-hifi",
      .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,
      .symmetric_rate = 1,
};

編解碼器控制 IO

編解碼器通常可以透過 I2C 或 SPI 樣式的介面來控制(AC97 將控制與 DAI 中的資料結合在一起)。 編解碼器驅動程式應使用 Regmap API 進行所有編解碼器 IO。 請參閱 include/linux/regmap.h 和現有的編解碼器驅動程式,以瞭解 regmap 的用法示例。

混音器和音訊控制

可以使用 soc.h 中定義的便利宏來定義所有編解碼器混音器和音訊控制。

#define SOC_SINGLE(xname, reg, shift, mask, invert)

按如下方式定義單個控制元件:-

xname = Control name e.g. "Playback Volume"
reg = codec register
shift = control bit(s) offset in register
mask = control bit size(s) e.g. mask of 7 = 3 bits
invert = the control is inverted

其他宏包括:-

#define SOC_DOUBLE(xname, reg, shift_left, shift_right, mask, invert)

一個立體聲控制

#define SOC_DOUBLE_R(xname, reg_left, reg_right, shift, mask, invert)

跨越 2 個暫存器的立體聲控制

#define SOC_ENUM_SINGLE(xreg, xshift, xmask, xtexts)

按如下方式定義單個列舉控制:-

xreg = register
xshift = control bit(s) offset in register
xmask = control bit(s) size
xtexts = pointer to array of strings that describe each setting

#define SOC_ENUM_DOUBLE(xreg, xshift_l, xshift_r, xmask, xtexts)

定義一個立體聲列舉控制

編解碼器音訊操作

編解碼器驅動程式還支援以下 ALSA PCM 操作:-

/* 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 *);
};

有關詳細資訊,請參閱 ALSA 驅動程式 PCM 文件。 https://kernel.linux.club.tw/doc/html/latest/sound/kernel-api/writing-an-alsa-driver.html

DAPM 描述

動態音訊電源管理描述描述了編解碼器電源元件及其與 ASoC 核心的關係和暫存器。 請閱讀 行動式裝置的動態音訊電源管理,以瞭解有關構建描述的詳細資訊。

另請參閱其他編解碼器驅動程式中的示例。

DAPM 事件處理程式

此函式是一個回撥,用於處理編解碼器域 PM 呼叫和系統域 PM 呼叫(例如,掛起和恢復)。 它用於在不使用時使編解碼器進入睡眠狀態。

電源狀態:-

SNDRV_CTL_POWER_D0: /* full On */
/* vref/mid, clk and osc on, active */

SNDRV_CTL_POWER_D1: /* partial On */
SNDRV_CTL_POWER_D2: /* partial On */

SNDRV_CTL_POWER_D3hot: /* Off, with power */
/* everything off except vref/vmid, inactive */

SNDRV_CTL_POWER_D3cold: /* Everything Off, without power */

編解碼器 DAC 數字靜音控制

大多數編解碼器在 DAC 之前都有一個數字靜音功能,可用於最大限度地減少任何系統噪聲。 靜音會阻止任何數字資料進入 DAC。

可以建立一個回撥,當應用或釋放靜音時,核心會為每個編解碼器 DAI 呼叫該回調。

即:

static int wm8974_mute(struct snd_soc_dai *dai, int mute, int direction)
{
      struct snd_soc_component *component = dai->component;
      u16 mute_reg = snd_soc_component_read(component, WM8974_DAC) & 0xffbf;

      if (mute)
              snd_soc_component_write(component, WM8974_DAC, mute_reg | 0x40);
      else
              snd_soc_component_write(component, WM8974_DAC, mute_reg);
      return 0;
}