162306a36Sopenharmony_ci======================= 262306a36Sopenharmony_ciASoC Codec Class Driver 362306a36Sopenharmony_ci======================= 462306a36Sopenharmony_ci 562306a36Sopenharmony_ciThe codec class driver is generic and hardware independent code that configures 662306a36Sopenharmony_cithe codec, FM, MODEM, BT or external DSP to provide audio capture and playback. 762306a36Sopenharmony_ciIt should contain no code that is specific to the target platform or machine. 862306a36Sopenharmony_ciAll platform and machine specific code should be added to the platform and 962306a36Sopenharmony_cimachine drivers respectively. 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ciEach codec class driver *must* provide the following features:- 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci1. Codec DAI and PCM configuration 1462306a36Sopenharmony_ci2. Codec control IO - using RegMap API 1562306a36Sopenharmony_ci3. Mixers and audio controls 1662306a36Sopenharmony_ci4. Codec audio operations 1762306a36Sopenharmony_ci5. DAPM description. 1862306a36Sopenharmony_ci6. DAPM event handler. 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ciOptionally, codec drivers can also provide:- 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci7. DAC Digital mute control. 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ciIts probably best to use this guide in conjunction with the existing codec 2562306a36Sopenharmony_cidriver code in sound/soc/codecs/ 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ciASoC Codec driver breakdown 2862306a36Sopenharmony_ci=========================== 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ciCodec DAI and PCM configuration 3162306a36Sopenharmony_ci------------------------------- 3262306a36Sopenharmony_ciEach codec driver must have a struct snd_soc_dai_driver to define its DAI and 3362306a36Sopenharmony_ciPCM capabilities and operations. This struct is exported so that it can be 3462306a36Sopenharmony_ciregistered with the core by your machine driver. 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_cie.g. 3762306a36Sopenharmony_ci:: 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci static struct snd_soc_dai_ops wm8731_dai_ops = { 4062306a36Sopenharmony_ci .prepare = wm8731_pcm_prepare, 4162306a36Sopenharmony_ci .hw_params = wm8731_hw_params, 4262306a36Sopenharmony_ci .shutdown = wm8731_shutdown, 4362306a36Sopenharmony_ci .mute_stream = wm8731_mute, 4462306a36Sopenharmony_ci .set_sysclk = wm8731_set_dai_sysclk, 4562306a36Sopenharmony_ci .set_fmt = wm8731_set_dai_fmt, 4662306a36Sopenharmony_ci }; 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci struct snd_soc_dai_driver wm8731_dai = { 4962306a36Sopenharmony_ci .name = "wm8731-hifi", 5062306a36Sopenharmony_ci .playback = { 5162306a36Sopenharmony_ci .stream_name = "Playback", 5262306a36Sopenharmony_ci .channels_min = 1, 5362306a36Sopenharmony_ci .channels_max = 2, 5462306a36Sopenharmony_ci .rates = WM8731_RATES, 5562306a36Sopenharmony_ci .formats = WM8731_FORMATS,}, 5662306a36Sopenharmony_ci .capture = { 5762306a36Sopenharmony_ci .stream_name = "Capture", 5862306a36Sopenharmony_ci .channels_min = 1, 5962306a36Sopenharmony_ci .channels_max = 2, 6062306a36Sopenharmony_ci .rates = WM8731_RATES, 6162306a36Sopenharmony_ci .formats = WM8731_FORMATS,}, 6262306a36Sopenharmony_ci .ops = &wm8731_dai_ops, 6362306a36Sopenharmony_ci .symmetric_rate = 1, 6462306a36Sopenharmony_ci }; 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ciCodec control IO 6862306a36Sopenharmony_ci---------------- 6962306a36Sopenharmony_ciThe codec can usually be controlled via an I2C or SPI style interface 7062306a36Sopenharmony_ci(AC97 combines control with data in the DAI). The codec driver should use the 7162306a36Sopenharmony_ciRegmap API for all codec IO. Please see include/linux/regmap.h and existing 7262306a36Sopenharmony_cicodec drivers for example regmap usage. 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ciMixers and audio controls 7662306a36Sopenharmony_ci------------------------- 7762306a36Sopenharmony_ciAll the codec mixers and audio controls can be defined using the convenience 7862306a36Sopenharmony_cimacros defined in soc.h. 7962306a36Sopenharmony_ci:: 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci #define SOC_SINGLE(xname, reg, shift, mask, invert) 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ciDefines a single control as follows:- 8462306a36Sopenharmony_ci:: 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci xname = Control name e.g. "Playback Volume" 8762306a36Sopenharmony_ci reg = codec register 8862306a36Sopenharmony_ci shift = control bit(s) offset in register 8962306a36Sopenharmony_ci mask = control bit size(s) e.g. mask of 7 = 3 bits 9062306a36Sopenharmony_ci invert = the control is inverted 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ciOther macros include:- 9362306a36Sopenharmony_ci:: 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci #define SOC_DOUBLE(xname, reg, shift_left, shift_right, mask, invert) 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ciA stereo control 9862306a36Sopenharmony_ci:: 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci #define SOC_DOUBLE_R(xname, reg_left, reg_right, shift, mask, invert) 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ciA stereo control spanning 2 registers 10362306a36Sopenharmony_ci:: 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci #define SOC_ENUM_SINGLE(xreg, xshift, xmask, xtexts) 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ciDefines an single enumerated control as follows:- 10862306a36Sopenharmony_ci:: 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci xreg = register 11162306a36Sopenharmony_ci xshift = control bit(s) offset in register 11262306a36Sopenharmony_ci xmask = control bit(s) size 11362306a36Sopenharmony_ci xtexts = pointer to array of strings that describe each setting 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci #define SOC_ENUM_DOUBLE(xreg, xshift_l, xshift_r, xmask, xtexts) 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ciDefines a stereo enumerated control 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ciCodec Audio Operations 12162306a36Sopenharmony_ci---------------------- 12262306a36Sopenharmony_ciThe codec driver also supports the following ALSA PCM operations:- 12362306a36Sopenharmony_ci:: 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci /* SoC audio ops */ 12662306a36Sopenharmony_ci struct snd_soc_ops { 12762306a36Sopenharmony_ci int (*startup)(struct snd_pcm_substream *); 12862306a36Sopenharmony_ci void (*shutdown)(struct snd_pcm_substream *); 12962306a36Sopenharmony_ci int (*hw_params)(struct snd_pcm_substream *, struct snd_pcm_hw_params *); 13062306a36Sopenharmony_ci int (*hw_free)(struct snd_pcm_substream *); 13162306a36Sopenharmony_ci int (*prepare)(struct snd_pcm_substream *); 13262306a36Sopenharmony_ci }; 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ciPlease refer to the ALSA driver PCM documentation for details. 13562306a36Sopenharmony_cihttps://www.kernel.org/doc/html/latest/sound/kernel-api/writing-an-alsa-driver.html 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ciDAPM description 13962306a36Sopenharmony_ci---------------- 14062306a36Sopenharmony_ciThe Dynamic Audio Power Management description describes the codec power 14162306a36Sopenharmony_cicomponents and their relationships and registers to the ASoC core. 14262306a36Sopenharmony_ciPlease read dapm.rst for details of building the description. 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ciPlease also see the examples in other codec drivers. 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ciDAPM event handler 14862306a36Sopenharmony_ci------------------ 14962306a36Sopenharmony_ciThis function is a callback that handles codec domain PM calls and system 15062306a36Sopenharmony_cidomain PM calls (e.g. suspend and resume). It is used to put the codec 15162306a36Sopenharmony_cito sleep when not in use. 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ciPower states:- 15462306a36Sopenharmony_ci:: 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci SNDRV_CTL_POWER_D0: /* full On */ 15762306a36Sopenharmony_ci /* vref/mid, clk and osc on, active */ 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci SNDRV_CTL_POWER_D1: /* partial On */ 16062306a36Sopenharmony_ci SNDRV_CTL_POWER_D2: /* partial On */ 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci SNDRV_CTL_POWER_D3hot: /* Off, with power */ 16362306a36Sopenharmony_ci /* everything off except vref/vmid, inactive */ 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci SNDRV_CTL_POWER_D3cold: /* Everything Off, without power */ 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ciCodec DAC digital mute control 16962306a36Sopenharmony_ci------------------------------ 17062306a36Sopenharmony_ciMost codecs have a digital mute before the DACs that can be used to 17162306a36Sopenharmony_ciminimise any system noise. The mute stops any digital data from 17262306a36Sopenharmony_cientering the DAC. 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ciA callback can be created that is called by the core for each codec DAI 17562306a36Sopenharmony_ciwhen the mute is applied or freed. 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_cii.e. 17862306a36Sopenharmony_ci:: 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci static int wm8974_mute(struct snd_soc_dai *dai, int mute, int direction) 18162306a36Sopenharmony_ci { 18262306a36Sopenharmony_ci struct snd_soc_component *component = dai->component; 18362306a36Sopenharmony_ci u16 mute_reg = snd_soc_component_read(component, WM8974_DAC) & 0xffbf; 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci if (mute) 18662306a36Sopenharmony_ci snd_soc_component_write(component, WM8974_DAC, mute_reg | 0x40); 18762306a36Sopenharmony_ci else 18862306a36Sopenharmony_ci snd_soc_component_write(component, WM8974_DAC, mute_reg); 18962306a36Sopenharmony_ci return 0; 19062306a36Sopenharmony_ci } 191