Liam Girdwood | eb1a6af | 2006-10-06 18:34:51 +0200 | [diff] [blame] | 1 | ASoC Codec Driver |
| 2 | ================= |
| 3 | |
| 4 | The codec driver is generic and hardware independent code that configures the |
| 5 | codec to provide audio capture and playback. It should contain no code that is |
| 6 | specific to the target platform or machine. All platform and machine specific |
| 7 | code should be added to the platform and machine drivers respectively. |
| 8 | |
Liam Girdwood | 10b9852 | 2007-02-08 17:06:09 +0100 | [diff] [blame] | 9 | Each codec driver *must* provide the following features:- |
Liam Girdwood | eb1a6af | 2006-10-06 18:34:51 +0200 | [diff] [blame] | 10 | |
Liam Girdwood | 10b9852 | 2007-02-08 17:06:09 +0100 | [diff] [blame] | 11 | 1) Codec DAI and PCM configuration |
Mark Brown | 7c4dbbd | 2008-01-23 08:41:46 +0100 | [diff] [blame] | 12 | 2) Codec control IO - using I2C, 3 Wire(SPI) or both APIs |
Liam Girdwood | 10b9852 | 2007-02-08 17:06:09 +0100 | [diff] [blame] | 13 | 3) Mixers and audio controls |
| 14 | 4) Codec audio operations |
Liam Girdwood | eb1a6af | 2006-10-06 18:34:51 +0200 | [diff] [blame] | 15 | |
| 16 | Optionally, codec drivers can also provide:- |
| 17 | |
Liam Girdwood | 10b9852 | 2007-02-08 17:06:09 +0100 | [diff] [blame] | 18 | 5) DAPM description. |
| 19 | 6) DAPM event handler. |
| 20 | 7) DAC Digital mute control. |
Liam Girdwood | eb1a6af | 2006-10-06 18:34:51 +0200 | [diff] [blame] | 21 | |
Mark Brown | 7c4dbbd | 2008-01-23 08:41:46 +0100 | [diff] [blame] | 22 | Its probably best to use this guide in conjunction with the existing codec |
Liam Girdwood | eb1a6af | 2006-10-06 18:34:51 +0200 | [diff] [blame] | 23 | driver code in sound/soc/codecs/ |
| 24 | |
| 25 | ASoC Codec driver breakdown |
| 26 | =========================== |
| 27 | |
Liam Girdwood | 10b9852 | 2007-02-08 17:06:09 +0100 | [diff] [blame] | 28 | 1 - Codec DAI and PCM configuration |
| 29 | ----------------------------------- |
Seungwhan Youn | 379c4bf | 2011-01-13 11:08:21 +0900 | [diff] [blame] | 30 | Each codec driver must have a struct snd_soc_dai_driver to define its DAI and |
Mark Brown | 7c4dbbd | 2008-01-23 08:41:46 +0100 | [diff] [blame] | 31 | PCM capabilities and operations. This struct is exported so that it can be |
Liam Girdwood | 10b9852 | 2007-02-08 17:06:09 +0100 | [diff] [blame] | 32 | registered with the core by your machine driver. |
Liam Girdwood | eb1a6af | 2006-10-06 18:34:51 +0200 | [diff] [blame] | 33 | |
| 34 | e.g. |
| 35 | |
Seungwhan Youn | 379c4bf | 2011-01-13 11:08:21 +0900 | [diff] [blame] | 36 | static struct snd_soc_dai_ops wm8731_dai_ops = { |
| 37 | .prepare = wm8731_pcm_prepare, |
| 38 | .hw_params = wm8731_hw_params, |
| 39 | .shutdown = wm8731_shutdown, |
| 40 | .digital_mute = wm8731_mute, |
| 41 | .set_sysclk = wm8731_set_dai_sysclk, |
| 42 | .set_fmt = wm8731_set_dai_fmt, |
| 43 | }; |
| 44 | |
| 45 | struct snd_soc_dai_driver wm8731_dai = { |
| 46 | .name = "wm8731-hifi", |
Liam Girdwood | eb1a6af | 2006-10-06 18:34:51 +0200 | [diff] [blame] | 47 | .playback = { |
| 48 | .stream_name = "Playback", |
| 49 | .channels_min = 1, |
| 50 | .channels_max = 2, |
Liam Girdwood | 10b9852 | 2007-02-08 17:06:09 +0100 | [diff] [blame] | 51 | .rates = WM8731_RATES, |
| 52 | .formats = WM8731_FORMATS,}, |
Liam Girdwood | eb1a6af | 2006-10-06 18:34:51 +0200 | [diff] [blame] | 53 | .capture = { |
| 54 | .stream_name = "Capture", |
| 55 | .channels_min = 1, |
| 56 | .channels_max = 2, |
Liam Girdwood | 10b9852 | 2007-02-08 17:06:09 +0100 | [diff] [blame] | 57 | .rates = WM8731_RATES, |
| 58 | .formats = WM8731_FORMATS,}, |
Seungwhan Youn | 379c4bf | 2011-01-13 11:08:21 +0900 | [diff] [blame] | 59 | .ops = &wm8731_dai_ops, |
| 60 | .symmetric_rates = 1, |
Liam Girdwood | eb1a6af | 2006-10-06 18:34:51 +0200 | [diff] [blame] | 61 | }; |
| 62 | |
| 63 | |
Liam Girdwood | 10b9852 | 2007-02-08 17:06:09 +0100 | [diff] [blame] | 64 | 2 - Codec control IO |
Liam Girdwood | eb1a6af | 2006-10-06 18:34:51 +0200 | [diff] [blame] | 65 | -------------------- |
Mark Brown | 7c4dbbd | 2008-01-23 08:41:46 +0100 | [diff] [blame] | 66 | The codec can usually be controlled via an I2C or SPI style interface |
| 67 | (AC97 combines control with data in the DAI). The codec drivers provide |
| 68 | functions to read and write the codec registers along with supplying a |
| 69 | register cache:- |
Liam Girdwood | eb1a6af | 2006-10-06 18:34:51 +0200 | [diff] [blame] | 70 | |
| 71 | /* IO control data and register cache */ |
Mark Brown | 7c4dbbd | 2008-01-23 08:41:46 +0100 | [diff] [blame] | 72 | void *control_data; /* codec control (i2c/3wire) data */ |
| 73 | void *reg_cache; |
Liam Girdwood | eb1a6af | 2006-10-06 18:34:51 +0200 | [diff] [blame] | 74 | |
Mark Brown | 7c4dbbd | 2008-01-23 08:41:46 +0100 | [diff] [blame] | 75 | Codec read/write should do any data formatting and call the hardware |
| 76 | read write below to perform the IO. These functions are called by the |
| 77 | core and ALSA when performing DAPM or changing the mixer:- |
Liam Girdwood | eb1a6af | 2006-10-06 18:34:51 +0200 | [diff] [blame] | 78 | |
| 79 | unsigned int (*read)(struct snd_soc_codec *, unsigned int); |
| 80 | int (*write)(struct snd_soc_codec *, unsigned int, unsigned int); |
| 81 | |
| 82 | Codec hardware IO functions - usually points to either the I2C, SPI or AC97 |
| 83 | read/write:- |
| 84 | |
| 85 | hw_write_t hw_write; |
| 86 | hw_read_t hw_read; |
| 87 | |
| 88 | |
Liam Girdwood | 10b9852 | 2007-02-08 17:06:09 +0100 | [diff] [blame] | 89 | 3 - Mixers and audio controls |
Liam Girdwood | eb1a6af | 2006-10-06 18:34:51 +0200 | [diff] [blame] | 90 | ----------------------------- |
| 91 | All the codec mixers and audio controls can be defined using the convenience |
| 92 | macros defined in soc.h. |
| 93 | |
| 94 | #define SOC_SINGLE(xname, reg, shift, mask, invert) |
| 95 | |
| 96 | Defines a single control as follows:- |
| 97 | |
| 98 | xname = Control name e.g. "Playback Volume" |
| 99 | reg = codec register |
| 100 | shift = control bit(s) offset in register |
| 101 | mask = control bit size(s) e.g. mask of 7 = 3 bits |
| 102 | invert = the control is inverted |
| 103 | |
| 104 | Other macros include:- |
| 105 | |
| 106 | #define SOC_DOUBLE(xname, reg, shift_left, shift_right, mask, invert) |
| 107 | |
| 108 | A stereo control |
| 109 | |
| 110 | #define SOC_DOUBLE_R(xname, reg_left, reg_right, shift, mask, invert) |
| 111 | |
| 112 | A stereo control spanning 2 registers |
| 113 | |
| 114 | #define SOC_ENUM_SINGLE(xreg, xshift, xmask, xtexts) |
| 115 | |
| 116 | Defines an single enumerated control as follows:- |
| 117 | |
| 118 | xreg = register |
| 119 | xshift = control bit(s) offset in register |
| 120 | xmask = control bit(s) size |
| 121 | xtexts = pointer to array of strings that describe each setting |
| 122 | |
| 123 | #define SOC_ENUM_DOUBLE(xreg, xshift_l, xshift_r, xmask, xtexts) |
| 124 | |
| 125 | Defines a stereo enumerated control |
| 126 | |
| 127 | |
Liam Girdwood | 10b9852 | 2007-02-08 17:06:09 +0100 | [diff] [blame] | 128 | 4 - Codec Audio Operations |
Liam Girdwood | eb1a6af | 2006-10-06 18:34:51 +0200 | [diff] [blame] | 129 | -------------------------- |
Mark Brown | 7c4dbbd | 2008-01-23 08:41:46 +0100 | [diff] [blame] | 130 | The codec driver also supports the following ALSA operations:- |
Liam Girdwood | eb1a6af | 2006-10-06 18:34:51 +0200 | [diff] [blame] | 131 | |
| 132 | /* SoC audio ops */ |
| 133 | struct snd_soc_ops { |
Takashi Iwai | 5b78efd | 2006-11-24 16:12:50 +0100 | [diff] [blame] | 134 | int (*startup)(struct snd_pcm_substream *); |
| 135 | void (*shutdown)(struct snd_pcm_substream *); |
| 136 | int (*hw_params)(struct snd_pcm_substream *, struct snd_pcm_hw_params *); |
| 137 | int (*hw_free)(struct snd_pcm_substream *); |
| 138 | int (*prepare)(struct snd_pcm_substream *); |
Liam Girdwood | eb1a6af | 2006-10-06 18:34:51 +0200 | [diff] [blame] | 139 | }; |
| 140 | |
Mark Brown | 7c4dbbd | 2008-01-23 08:41:46 +0100 | [diff] [blame] | 141 | Please refer to the ALSA driver PCM documentation for details. |
Justin P. Mattock | 0ea6e61 | 2010-07-23 20:51:24 -0700 | [diff] [blame] | 142 | http://www.alsa-project.org/~iwai/writing-an-alsa-driver/ |
Liam Girdwood | eb1a6af | 2006-10-06 18:34:51 +0200 | [diff] [blame] | 143 | |
| 144 | |
Liam Girdwood | 10b9852 | 2007-02-08 17:06:09 +0100 | [diff] [blame] | 145 | 5 - DAPM description. |
Liam Girdwood | eb1a6af | 2006-10-06 18:34:51 +0200 | [diff] [blame] | 146 | --------------------- |
Mark Brown | 7c4dbbd | 2008-01-23 08:41:46 +0100 | [diff] [blame] | 147 | The Dynamic Audio Power Management description describes the codec power |
| 148 | components and their relationships and registers to the ASoC core. |
| 149 | Please read dapm.txt for details of building the description. |
Liam Girdwood | eb1a6af | 2006-10-06 18:34:51 +0200 | [diff] [blame] | 150 | |
| 151 | Please also see the examples in other codec drivers. |
| 152 | |
| 153 | |
Liam Girdwood | 10b9852 | 2007-02-08 17:06:09 +0100 | [diff] [blame] | 154 | 6 - DAPM event handler |
Liam Girdwood | eb1a6af | 2006-10-06 18:34:51 +0200 | [diff] [blame] | 155 | ---------------------- |
| 156 | This function is a callback that handles codec domain PM calls and system |
Mark Brown | 7c4dbbd | 2008-01-23 08:41:46 +0100 | [diff] [blame] | 157 | domain PM calls (e.g. suspend and resume). It is used to put the codec |
| 158 | to sleep when not in use. |
Liam Girdwood | eb1a6af | 2006-10-06 18:34:51 +0200 | [diff] [blame] | 159 | |
| 160 | Power states:- |
| 161 | |
| 162 | SNDRV_CTL_POWER_D0: /* full On */ |
| 163 | /* vref/mid, clk and osc on, active */ |
| 164 | |
| 165 | SNDRV_CTL_POWER_D1: /* partial On */ |
| 166 | SNDRV_CTL_POWER_D2: /* partial On */ |
| 167 | |
| 168 | SNDRV_CTL_POWER_D3hot: /* Off, with power */ |
| 169 | /* everything off except vref/vmid, inactive */ |
| 170 | |
| 171 | SNDRV_CTL_POWER_D3cold: /* Everything Off, without power */ |
| 172 | |
| 173 | |
Mark Brown | 7c4dbbd | 2008-01-23 08:41:46 +0100 | [diff] [blame] | 174 | 7 - Codec DAC digital mute control |
| 175 | ---------------------------------- |
| 176 | Most codecs have a digital mute before the DACs that can be used to |
| 177 | minimise any system noise. The mute stops any digital data from |
| 178 | entering the DAC. |
Liam Girdwood | eb1a6af | 2006-10-06 18:34:51 +0200 | [diff] [blame] | 179 | |
Mark Brown | 7c4dbbd | 2008-01-23 08:41:46 +0100 | [diff] [blame] | 180 | A callback can be created that is called by the core for each codec DAI |
| 181 | when the mute is applied or freed. |
Liam Girdwood | eb1a6af | 2006-10-06 18:34:51 +0200 | [diff] [blame] | 182 | |
| 183 | i.e. |
| 184 | |
Seungwhan Youn | 379c4bf | 2011-01-13 11:08:21 +0900 | [diff] [blame] | 185 | static int wm8974_mute(struct snd_soc_dai *dai, int mute) |
Liam Girdwood | eb1a6af | 2006-10-06 18:34:51 +0200 | [diff] [blame] | 186 | { |
Seungwhan Youn | 379c4bf | 2011-01-13 11:08:21 +0900 | [diff] [blame] | 187 | struct snd_soc_codec *codec = dai->codec; |
| 188 | u16 mute_reg = snd_soc_read(codec, WM8974_DAC) & 0xffbf; |
| 189 | |
| 190 | if (mute) |
| 191 | snd_soc_write(codec, WM8974_DAC, mute_reg | 0x40); |
Liam Girdwood | eb1a6af | 2006-10-06 18:34:51 +0200 | [diff] [blame] | 192 | else |
Seungwhan Youn | 379c4bf | 2011-01-13 11:08:21 +0900 | [diff] [blame] | 193 | snd_soc_write(codec, WM8974_DAC, mute_reg); |
Liam Girdwood | eb1a6af | 2006-10-06 18:34:51 +0200 | [diff] [blame] | 194 | return 0; |
| 195 | } |