diff options
| author | Ian Lartey <ian@opensource.wolfsonmicro.com> | 2010-07-30 19:32:11 -0400 |
|---|---|---|
| committer | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2010-08-03 02:38:15 -0400 |
| commit | 992bee401c06872175056bc5567cb3ebab098cb5 (patch) | |
| tree | 14e3087d84a8e64e583d1387a1cf50206be4bb0b | |
| parent | 988b0dc1547f9f6a7c8cae472cad0a55df31818c (diff) | |
ASoC: Initial WM8741 CODEC driver
The WM8741 is a very high performance stereo DAC designed for audio
applications such as professional recording systems, A/V receivers and
high specification CD, DVD and home theatre systems. The device supports
PCM data input word lengths from 16 to 32-bits and sampling rates up to
192kHz. The WM8741 also supports DSD bit-stream data format, in both
direct DSD and PCM-converted DSD modes.
TODO: Expand wm8741_set_dai_sysclk and rate_constraint members to
allow for all supported sample rate / Master Clock frequency combinations.
Fully enable control of supplies.
Signed-off-by: Ian Lartey <ian@opensource.wolfsonmicro.com>
Acked-by: Liam Girdwood <lrg@slimlogic.co.uk>
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
| -rw-r--r-- | sound/soc/codecs/Kconfig | 4 | ||||
| -rw-r--r-- | sound/soc/codecs/Makefile | 2 | ||||
| -rw-r--r-- | sound/soc/codecs/wm8741.c | 579 | ||||
| -rw-r--r-- | sound/soc/codecs/wm8741.h | 214 |
4 files changed, 799 insertions, 0 deletions
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 55bc2beffb3a..83f5c67d3c41 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig | |||
| @@ -50,6 +50,7 @@ config SND_SOC_ALL_CODECS | |||
| 50 | select SND_SOC_WM8727 | 50 | select SND_SOC_WM8727 |
| 51 | select SND_SOC_WM8728 if SND_SOC_I2C_AND_SPI | 51 | select SND_SOC_WM8728 if SND_SOC_I2C_AND_SPI |
| 52 | select SND_SOC_WM8731 if SND_SOC_I2C_AND_SPI | 52 | select SND_SOC_WM8731 if SND_SOC_I2C_AND_SPI |
| 53 | select SND_SOC_WM8741 if SND_SOC_I2C_AND_SPI | ||
| 53 | select SND_SOC_WM8750 if SND_SOC_I2C_AND_SPI | 54 | select SND_SOC_WM8750 if SND_SOC_I2C_AND_SPI |
| 54 | select SND_SOC_WM8753 if SND_SOC_I2C_AND_SPI | 55 | select SND_SOC_WM8753 if SND_SOC_I2C_AND_SPI |
| 55 | select SND_SOC_WM8776 if SND_SOC_I2C_AND_SPI | 56 | select SND_SOC_WM8776 if SND_SOC_I2C_AND_SPI |
| @@ -214,6 +215,9 @@ config SND_SOC_WM8728 | |||
| 214 | config SND_SOC_WM8731 | 215 | config SND_SOC_WM8731 |
| 215 | tristate | 216 | tristate |
| 216 | 217 | ||
| 218 | config SND_SOC_WM8741 | ||
| 219 | tristate | ||
| 220 | |||
| 217 | config SND_SOC_WM8750 | 221 | config SND_SOC_WM8750 |
| 218 | tristate | 222 | tristate |
| 219 | 223 | ||
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index d8d9eebf78b5..53524095759c 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile | |||
| @@ -35,6 +35,7 @@ snd-soc-wm8711-objs := wm8711.o | |||
| 35 | snd-soc-wm8727-objs := wm8727.o | 35 | snd-soc-wm8727-objs := wm8727.o |
| 36 | snd-soc-wm8728-objs := wm8728.o | 36 | snd-soc-wm8728-objs := wm8728.o |
| 37 | snd-soc-wm8731-objs := wm8731.o | 37 | snd-soc-wm8731-objs := wm8731.o |
| 38 | snd-soc-wm8741-objs := wm8741.o | ||
| 38 | snd-soc-wm8750-objs := wm8750.o | 39 | snd-soc-wm8750-objs := wm8750.o |
| 39 | snd-soc-wm8753-objs := wm8753.o | 40 | snd-soc-wm8753-objs := wm8753.o |
| 40 | snd-soc-wm8776-objs := wm8776.o | 41 | snd-soc-wm8776-objs := wm8776.o |
| @@ -103,6 +104,7 @@ obj-$(CONFIG_SND_SOC_WM8711) += snd-soc-wm8711.o | |||
| 103 | obj-$(CONFIG_SND_SOC_WM8727) += snd-soc-wm8727.o | 104 | obj-$(CONFIG_SND_SOC_WM8727) += snd-soc-wm8727.o |
| 104 | obj-$(CONFIG_SND_SOC_WM8728) += snd-soc-wm8728.o | 105 | obj-$(CONFIG_SND_SOC_WM8728) += snd-soc-wm8728.o |
| 105 | obj-$(CONFIG_SND_SOC_WM8731) += snd-soc-wm8731.o | 106 | obj-$(CONFIG_SND_SOC_WM8731) += snd-soc-wm8731.o |
| 107 | obj-$(CONFIG_SND_SOC_WM8741) += snd-soc-wm8741.o | ||
| 106 | obj-$(CONFIG_SND_SOC_WM8750) += snd-soc-wm8750.o | 108 | obj-$(CONFIG_SND_SOC_WM8750) += snd-soc-wm8750.o |
| 107 | obj-$(CONFIG_SND_SOC_WM8753) += snd-soc-wm8753.o | 109 | obj-$(CONFIG_SND_SOC_WM8753) += snd-soc-wm8753.o |
| 108 | obj-$(CONFIG_SND_SOC_WM8776) += snd-soc-wm8776.o | 110 | obj-$(CONFIG_SND_SOC_WM8776) += snd-soc-wm8776.o |
diff --git a/sound/soc/codecs/wm8741.c b/sound/soc/codecs/wm8741.c new file mode 100644 index 000000000000..b9ea8904ad4b --- /dev/null +++ b/sound/soc/codecs/wm8741.c | |||
| @@ -0,0 +1,579 @@ | |||
| 1 | /* | ||
| 2 | * wm8741.c -- WM8741 ALSA SoC Audio driver | ||
| 3 | * | ||
| 4 | * Copyright 2010 Wolfson Microelectronics plc | ||
| 5 | * | ||
| 6 | * Author: Ian Lartey <ian@opensource.wolfsonmicro.com> | ||
| 7 | * | ||
| 8 | * | ||
| 9 | * This program is free software; you can redistribute it and/or modify | ||
| 10 | * it under the terms of the GNU General Public License version 2 as | ||
| 11 | * published by the Free Software Foundation. | ||
| 12 | */ | ||
| 13 | |||
| 14 | #include <linux/module.h> | ||
| 15 | #include <linux/moduleparam.h> | ||
| 16 | #include <linux/init.h> | ||
| 17 | #include <linux/delay.h> | ||
| 18 | #include <linux/pm.h> | ||
| 19 | #include <linux/i2c.h> | ||
| 20 | #include <linux/platform_device.h> | ||
| 21 | #include <linux/regulator/consumer.h> | ||
| 22 | #include <linux/slab.h> | ||
| 23 | #include <sound/core.h> | ||
| 24 | #include <sound/pcm.h> | ||
| 25 | #include <sound/pcm_params.h> | ||
| 26 | #include <sound/soc.h> | ||
| 27 | #include <sound/soc-dapm.h> | ||
| 28 | #include <sound/initval.h> | ||
| 29 | #include <sound/tlv.h> | ||
| 30 | |||
| 31 | #include "wm8741.h" | ||
| 32 | |||
| 33 | static struct snd_soc_codec *wm8741_codec; | ||
| 34 | struct snd_soc_codec_device soc_codec_dev_wm8741; | ||
| 35 | |||
| 36 | #define WM8741_NUM_SUPPLIES 2 | ||
| 37 | static const char *wm8741_supply_names[WM8741_NUM_SUPPLIES] = { | ||
| 38 | "AVDD", | ||
| 39 | "DVDD", | ||
| 40 | }; | ||
| 41 | |||
| 42 | #define WM8741_NUM_RATES 4 | ||
| 43 | |||
| 44 | /* codec private data */ | ||
| 45 | struct wm8741_priv { | ||
| 46 | struct snd_soc_codec codec; | ||
| 47 | u16 reg_cache[WM8741_REGISTER_COUNT]; | ||
| 48 | struct regulator_bulk_data supplies[WM8741_NUM_SUPPLIES]; | ||
| 49 | unsigned int sysclk; | ||
| 50 | unsigned int rate_constraint_list[WM8741_NUM_RATES]; | ||
| 51 | struct snd_pcm_hw_constraint_list rate_constraint; | ||
| 52 | }; | ||
| 53 | |||
| 54 | static const u16 wm8741_reg_defaults[WM8741_REGISTER_COUNT] = { | ||
| 55 | 0x0000, /* R0 - DACLLSB Attenuation */ | ||
| 56 | 0x0000, /* R1 - DACLMSB Attenuation */ | ||
| 57 | 0x0000, /* R2 - DACRLSB Attenuation */ | ||
| 58 | 0x0000, /* R3 - DACRMSB Attenuation */ | ||
| 59 | 0x0000, /* R4 - Volume Control */ | ||
| 60 | 0x000A, /* R5 - Format Control */ | ||
| 61 | 0x0000, /* R6 - Filter Control */ | ||
| 62 | 0x0000, /* R7 - Mode Control 1 */ | ||
| 63 | 0x0002, /* R8 - Mode Control 2 */ | ||
| 64 | 0x0000, /* R9 - Reset */ | ||
| 65 | 0x0002, /* R32 - ADDITONAL_CONTROL_1 */ | ||
| 66 | }; | ||
| 67 | |||
| 68 | |||
| 69 | static int wm8741_reset(struct snd_soc_codec *codec) | ||
| 70 | { | ||
| 71 | return snd_soc_write(codec, WM8741_RESET, 0); | ||
| 72 | } | ||
| 73 | |||
| 74 | static const DECLARE_TLV_DB_SCALE(dac_tlv_fine, -12700, 13, 0); | ||
| 75 | static const DECLARE_TLV_DB_SCALE(dac_tlv, -12700, 400, 0); | ||
| 76 | |||
| 77 | static const struct snd_kcontrol_new wm8741_snd_controls[] = { | ||
| 78 | SOC_DOUBLE_R_TLV("Fine Playback Volume", WM8741_DACLLSB_ATTENUATION, | ||
| 79 | WM8741_DACRLSB_ATTENUATION, 1, 255, 1, dac_tlv_fine), | ||
| 80 | SOC_DOUBLE_R_TLV("Playback Volume", WM8741_DACLMSB_ATTENUATION, | ||
| 81 | WM8741_DACRMSB_ATTENUATION, 0, 511, 1, dac_tlv), | ||
| 82 | }; | ||
| 83 | |||
| 84 | static const struct snd_soc_dapm_widget wm8741_dapm_widgets[] = { | ||
| 85 | SND_SOC_DAPM_DAC("DACL", "Playback", SND_SOC_NOPM, 0, 0), | ||
| 86 | SND_SOC_DAPM_DAC("DACR", "Playback", SND_SOC_NOPM, 0, 0), | ||
| 87 | SND_SOC_DAPM_OUTPUT("VOUTLP"), | ||
| 88 | SND_SOC_DAPM_OUTPUT("VOUTLN"), | ||
| 89 | SND_SOC_DAPM_OUTPUT("VOUTRP"), | ||
| 90 | SND_SOC_DAPM_OUTPUT("VOUTRN"), | ||
| 91 | }; | ||
| 92 | |||
| 93 | static const struct snd_soc_dapm_route intercon[] = { | ||
| 94 | { "VOUTLP", NULL, "DACL" }, | ||
| 95 | { "VOUTLN", NULL, "DACL" }, | ||
| 96 | { "VOUTRP", NULL, "DACR" }, | ||
| 97 | { "VOUTRN", NULL, "DACR" }, | ||
| 98 | }; | ||
| 99 | |||
| 100 | static int wm8741_add_widgets(struct snd_soc_codec *codec) | ||
| 101 | { | ||
| 102 | snd_soc_dapm_new_controls(codec, wm8741_dapm_widgets, | ||
| 103 | ARRAY_SIZE(wm8741_dapm_widgets)); | ||
| 104 | |||
| 105 | snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon)); | ||
| 106 | |||
| 107 | return 0; | ||
| 108 | } | ||
| 109 | |||
| 110 | static struct { | ||
| 111 | int value; | ||
| 112 | int ratio; | ||
| 113 | } lrclk_ratios[WM8741_NUM_RATES] = { | ||
| 114 | { 1, 256 }, | ||
| 115 | { 2, 384 }, | ||
| 116 | { 3, 512 }, | ||
| 117 | { 4, 768 }, | ||
| 118 | }; | ||
| 119 | |||
| 120 | |||
| 121 | static int wm8741_startup(struct snd_pcm_substream *substream, | ||
| 122 | struct snd_soc_dai *dai) | ||
| 123 | { | ||
| 124 | struct snd_soc_codec *codec = dai->codec; | ||
| 125 | struct wm8741_priv *wm8741 = snd_soc_codec_get_drvdata(codec); | ||
| 126 | |||
| 127 | /* The set of sample rates that can be supported depends on the | ||
| 128 | * MCLK supplied to the CODEC - enforce this. | ||
| 129 | */ | ||
| 130 | if (!wm8741->sysclk) { | ||
| 131 | dev_err(codec->dev, | ||
| 132 | "No MCLK configured, call set_sysclk() on init\n"); | ||
| 133 | return -EINVAL; | ||
| 134 | } | ||
| 135 | |||
| 136 | snd_pcm_hw_constraint_list(substream->runtime, 0, | ||
| 137 | SNDRV_PCM_HW_PARAM_RATE, | ||
| 138 | &wm8741->rate_constraint); | ||
| 139 | |||
| 140 | return 0; | ||
| 141 | } | ||
| 142 | |||
| 143 | static int wm8741_hw_params(struct snd_pcm_substream *substream, | ||
| 144 | struct snd_pcm_hw_params *params, | ||
| 145 | struct snd_soc_dai *dai) | ||
| 146 | { | ||
| 147 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
| 148 | struct snd_soc_device *socdev = rtd->socdev; | ||
| 149 | struct snd_soc_codec *codec = socdev->card->codec; | ||
| 150 | struct wm8741_priv *wm8741 = snd_soc_codec_get_drvdata(codec); | ||
| 151 | u16 iface = snd_soc_read(codec, WM8741_FORMAT_CONTROL) & 0x1FC; | ||
| 152 | int i; | ||
| 153 | |||
| 154 | /* Find a supported LRCLK ratio */ | ||
| 155 | for (i = 0; i < ARRAY_SIZE(lrclk_ratios); i++) { | ||
| 156 | if (wm8741->sysclk / params_rate(params) == | ||
| 157 | lrclk_ratios[i].ratio) | ||
| 158 | break; | ||
| 159 | } | ||
| 160 | |||
| 161 | /* Should never happen, should be handled by constraints */ | ||
| 162 | if (i == ARRAY_SIZE(lrclk_ratios)) { | ||
| 163 | dev_err(codec->dev, "MCLK/fs ratio %d unsupported\n", | ||
| 164 | wm8741->sysclk / params_rate(params)); | ||
| 165 | return -EINVAL; | ||
| 166 | } | ||
| 167 | |||
| 168 | /* bit size */ | ||
| 169 | switch (params_format(params)) { | ||
| 170 | case SNDRV_PCM_FORMAT_S16_LE: | ||
| 171 | break; | ||
| 172 | case SNDRV_PCM_FORMAT_S20_3LE: | ||
| 173 | iface |= 0x0001; | ||
| 174 | break; | ||
| 175 | case SNDRV_PCM_FORMAT_S24_LE: | ||
| 176 | iface |= 0x0002; | ||
| 177 | break; | ||
| 178 | case SNDRV_PCM_FORMAT_S32_LE: | ||
| 179 | iface |= 0x0003; | ||
| 180 | break; | ||
| 181 | default: | ||
| 182 | dev_dbg(codec->dev, "wm8741_hw_params: Unsupported bit size param = %d", | ||
| 183 | params_format(params)); | ||
| 184 | return -EINVAL; | ||
| 185 | } | ||
| 186 | |||
| 187 | dev_dbg(codec->dev, "wm8741_hw_params: bit size param = %d", | ||
| 188 | params_format(params)); | ||
| 189 | |||
| 190 | snd_soc_write(codec, WM8741_FORMAT_CONTROL, iface); | ||
| 191 | return 0; | ||
| 192 | } | ||
| 193 | |||
| 194 | static int wm8741_set_dai_sysclk(struct snd_soc_dai *codec_dai, | ||
| 195 | int clk_id, unsigned int freq, int dir) | ||
| 196 | { | ||
| 197 | struct snd_soc_codec *codec = codec_dai->codec; | ||
| 198 | struct wm8741_priv *wm8741 = snd_soc_codec_get_drvdata(codec); | ||
| 199 | unsigned int val; | ||
| 200 | int i; | ||
| 201 | |||
| 202 | dev_dbg(codec->dev, "wm8741_set_dai_sysclk info: freq=%dHz\n", freq); | ||
| 203 | |||
| 204 | wm8741->sysclk = freq; | ||
| 205 | |||
| 206 | wm8741->rate_constraint.count = 0; | ||
| 207 | |||
| 208 | for (i = 0; i < ARRAY_SIZE(lrclk_ratios); i++) { | ||
| 209 | dev_dbg(codec->dev, "index = %d, ratio = %d, freq = %d", | ||
| 210 | i, lrclk_ratios[i].ratio, freq); | ||
| 211 | |||
| 212 | val = freq / lrclk_ratios[i].ratio; | ||
| 213 | /* Check that it's a standard rate since core can't | ||
| 214 | * cope with others and having the odd rates confuses | ||
| 215 | * constraint matching. | ||
| 216 | */ | ||
| 217 | switch (val) { | ||
| 218 | case 32000: | ||
| 219 | case 44100: | ||
| 220 | case 48000: | ||
| 221 | case 64000: | ||
| 222 | case 88200: | ||
| 223 | case 96000: | ||
| 224 | dev_dbg(codec->dev, "Supported sample rate: %dHz\n", | ||
| 225 | val); | ||
| 226 | wm8741->rate_constraint_list[i] = val; | ||
| 227 | wm8741->rate_constraint.count++; | ||
| 228 | break; | ||
| 229 | default: | ||
| 230 | dev_dbg(codec->dev, "Skipping sample rate: %dHz\n", | ||
| 231 | val); | ||
| 232 | } | ||
| 233 | } | ||
| 234 | |||
| 235 | /* Need at least one supported rate... */ | ||
| 236 | if (wm8741->rate_constraint.count == 0) | ||
| 237 | return -EINVAL; | ||
| 238 | |||
| 239 | return 0; | ||
| 240 | } | ||
| 241 | |||
| 242 | static int wm8741_set_dai_fmt(struct snd_soc_dai *codec_dai, | ||
| 243 | unsigned int fmt) | ||
| 244 | { | ||
| 245 | struct snd_soc_codec *codec = codec_dai->codec; | ||
| 246 | u16 iface = snd_soc_read(codec, WM8741_FORMAT_CONTROL) & 0x1C3; | ||
| 247 | |||
| 248 | /* check master/slave audio interface */ | ||
| 249 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
| 250 | case SND_SOC_DAIFMT_CBS_CFS: | ||
| 251 | break; | ||
| 252 | default: | ||
| 253 | return -EINVAL; | ||
| 254 | } | ||
| 255 | |||
| 256 | /* interface format */ | ||
| 257 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
| 258 | case SND_SOC_DAIFMT_I2S: | ||
| 259 | iface |= 0x0008; | ||
| 260 | break; | ||
| 261 | case SND_SOC_DAIFMT_RIGHT_J: | ||
| 262 | break; | ||
| 263 | case SND_SOC_DAIFMT_LEFT_J: | ||
| 264 | iface |= 0x0004; | ||
| 265 | break; | ||
| 266 | case SND_SOC_DAIFMT_DSP_A: | ||
| 267 | iface |= 0x0003; | ||
| 268 | break; | ||
| 269 | case SND_SOC_DAIFMT_DSP_B: | ||
| 270 | iface |= 0x0013; | ||
| 271 | break; | ||
| 272 | default: | ||
| 273 | return -EINVAL; | ||
| 274 | } | ||
| 275 | |||
| 276 | /* clock inversion */ | ||
| 277 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { | ||
| 278 | case SND_SOC_DAIFMT_NB_NF: | ||
| 279 | break; | ||
| 280 | case SND_SOC_DAIFMT_IB_IF: | ||
| 281 | iface |= 0x0010; | ||
| 282 | break; | ||
| 283 | case SND_SOC_DAIFMT_IB_NF: | ||
| 284 | iface |= 0x0020; | ||
| 285 | break; | ||
| 286 | case SND_SOC_DAIFMT_NB_IF: | ||
| 287 | iface |= 0x0030; | ||
| 288 | break; | ||
| 289 | default: | ||
| 290 | return -EINVAL; | ||
| 291 | } | ||
| 292 | |||
| 293 | |||
| 294 | dev_dbg(codec->dev, "wm8741_set_dai_fmt: Format=%x, Clock Inv=%x\n", | ||
| 295 | fmt & SND_SOC_DAIFMT_FORMAT_MASK, | ||
| 296 | ((fmt & SND_SOC_DAIFMT_INV_MASK))); | ||
| 297 | |||
| 298 | snd_soc_write(codec, WM8741_FORMAT_CONTROL, iface); | ||
| 299 | return 0; | ||
| 300 | } | ||
| 301 | |||
| 302 | #define WM8741_RATES (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ | ||
| 303 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | \ | ||
| 304 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | \ | ||
| 305 | SNDRV_PCM_RATE_192000) | ||
| 306 | |||
| 307 | #define WM8741_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ | ||
| 308 | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) | ||
| 309 | |||
| 310 | static struct snd_soc_dai_ops wm8741_dai_ops = { | ||
| 311 | .startup = wm8741_startup, | ||
| 312 | .hw_params = wm8741_hw_params, | ||
| 313 | .set_sysclk = wm8741_set_dai_sysclk, | ||
| 314 | .set_fmt = wm8741_set_dai_fmt, | ||
| 315 | }; | ||
| 316 | |||
| 317 | struct snd_soc_dai wm8741_dai = { | ||
| 318 | .name = "WM8741", | ||
| 319 | .playback = { | ||
| 320 | .stream_name = "Playback", | ||
| 321 | .channels_min = 2, /* Mono modes not yet supported */ | ||
| 322 | .channels_max = 2, | ||
| 323 | .rates = WM8741_RATES, | ||
| 324 | .formats = WM8741_FORMATS, | ||
| 325 | }, | ||
| 326 | .ops = &wm8741_dai_ops, | ||
| 327 | }; | ||
| 328 | EXPORT_SYMBOL_GPL(wm8741_dai); | ||
| 329 | |||
| 330 | #ifdef CONFIG_PM | ||
| 331 | static int wm8741_resume(struct platform_device *pdev) | ||
| 332 | { | ||
| 333 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
| 334 | struct snd_soc_codec *codec = socdev->card->codec; | ||
| 335 | u16 *cache = codec->reg_cache; | ||
| 336 | int i; | ||
| 337 | |||
| 338 | /* RESTORE REG Cache */ | ||
| 339 | for (i = 0; i < WM8741_REGISTER_COUNT; i++) { | ||
| 340 | if (cache[i] == wm8741_reg_defaults[i] || WM8741_RESET == i) | ||
| 341 | continue; | ||
| 342 | snd_soc_write(codec, i, cache[i]); | ||
| 343 | } | ||
| 344 | return 0; | ||
| 345 | } | ||
| 346 | #else | ||
| 347 | #define wm8741_suspend NULL | ||
| 348 | #define wm8741_resume NULL | ||
| 349 | #endif | ||
| 350 | |||
| 351 | static int wm8741_probe(struct platform_device *pdev) | ||
| 352 | { | ||
| 353 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
| 354 | struct snd_soc_codec *codec; | ||
| 355 | int ret = 0; | ||
| 356 | |||
| 357 | if (wm8741_codec == NULL) { | ||
| 358 | dev_err(&pdev->dev, "Codec device not registered\n"); | ||
| 359 | return -ENODEV; | ||
| 360 | } | ||
| 361 | |||
| 362 | socdev->card->codec = wm8741_codec; | ||
| 363 | codec = wm8741_codec; | ||
| 364 | |||
| 365 | /* register pcms */ | ||
| 366 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | ||
| 367 | if (ret < 0) { | ||
| 368 | dev_err(codec->dev, "failed to create pcms: %d\n", ret); | ||
| 369 | goto pcm_err; | ||
| 370 | } | ||
| 371 | |||
| 372 | snd_soc_add_controls(codec, wm8741_snd_controls, | ||
| 373 | ARRAY_SIZE(wm8741_snd_controls)); | ||
| 374 | wm8741_add_widgets(codec); | ||
| 375 | |||
| 376 | return ret; | ||
| 377 | |||
| 378 | pcm_err: | ||
| 379 | return ret; | ||
| 380 | } | ||
| 381 | |||
| 382 | static int wm8741_remove(struct platform_device *pdev) | ||
| 383 | { | ||
| 384 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
| 385 | |||
| 386 | snd_soc_free_pcms(socdev); | ||
| 387 | snd_soc_dapm_free(socdev); | ||
| 388 | |||
| 389 | return 0; | ||
| 390 | } | ||
| 391 | |||
| 392 | struct snd_soc_codec_device soc_codec_dev_wm8741 = { | ||
| 393 | .probe = wm8741_probe, | ||
| 394 | .remove = wm8741_remove, | ||
| 395 | .resume = wm8741_resume, | ||
| 396 | }; | ||
| 397 | EXPORT_SYMBOL_GPL(soc_codec_dev_wm8741); | ||
| 398 | |||
| 399 | static int wm8741_register(struct wm8741_priv *wm8741, | ||
| 400 | enum snd_soc_control_type control) | ||
| 401 | { | ||
| 402 | int ret; | ||
| 403 | struct snd_soc_codec *codec = &wm8741->codec; | ||
| 404 | int i; | ||
| 405 | |||
| 406 | if (wm8741_codec) { | ||
| 407 | dev_err(codec->dev, "Another WM8741 is registered\n"); | ||
| 408 | return -EINVAL; | ||
| 409 | } | ||
| 410 | |||
| 411 | mutex_init(&codec->mutex); | ||
| 412 | INIT_LIST_HEAD(&codec->dapm_widgets); | ||
| 413 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
| 414 | |||
| 415 | snd_soc_codec_set_drvdata(codec, wm8741); | ||
| 416 | codec->name = "WM8741"; | ||
| 417 | codec->owner = THIS_MODULE; | ||
| 418 | codec->bias_level = SND_SOC_BIAS_OFF; | ||
| 419 | codec->set_bias_level = NULL; | ||
| 420 | codec->dai = &wm8741_dai; | ||
| 421 | codec->num_dai = 1; | ||
| 422 | codec->reg_cache_size = WM8741_REGISTER_COUNT; | ||
| 423 | codec->reg_cache = &wm8741->reg_cache; | ||
| 424 | |||
| 425 | wm8741->rate_constraint.list = &wm8741->rate_constraint_list[0]; | ||
| 426 | wm8741->rate_constraint.count = | ||
| 427 | ARRAY_SIZE(wm8741->rate_constraint_list); | ||
| 428 | |||
| 429 | memcpy(codec->reg_cache, wm8741_reg_defaults, | ||
| 430 | sizeof(wm8741->reg_cache)); | ||
| 431 | |||
| 432 | ret = snd_soc_codec_set_cache_io(codec, 7, 9, control); | ||
| 433 | if (ret != 0) { | ||
| 434 | dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); | ||
| 435 | goto err; | ||
| 436 | } | ||
| 437 | |||
| 438 | for (i = 0; i < ARRAY_SIZE(wm8741->supplies); i++) | ||
| 439 | wm8741->supplies[i].supply = wm8741_supply_names[i]; | ||
| 440 | |||
| 441 | ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8741->supplies), | ||
| 442 | wm8741->supplies); | ||
| 443 | if (ret != 0) { | ||
| 444 | dev_err(codec->dev, "Failed to request supplies: %d\n", ret); | ||
| 445 | goto err; | ||
| 446 | } | ||
| 447 | |||
| 448 | ret = regulator_bulk_enable(ARRAY_SIZE(wm8741->supplies), | ||
| 449 | wm8741->supplies); | ||
| 450 | if (ret != 0) { | ||
| 451 | dev_err(codec->dev, "Failed to enable supplies: %d\n", ret); | ||
| 452 | goto err_get; | ||
| 453 | } | ||
| 454 | |||
| 455 | ret = wm8741_reset(codec); | ||
| 456 | if (ret < 0) { | ||
| 457 | dev_err(codec->dev, "Failed to issue reset\n"); | ||
| 458 | goto err_enable; | ||
| 459 | } | ||
| 460 | |||
| 461 | wm8741_dai.dev = codec->dev; | ||
| 462 | |||
| 463 | /* Change some default settings - latch VU */ | ||
| 464 | wm8741->reg_cache[WM8741_DACLLSB_ATTENUATION] |= WM8741_UPDATELL; | ||
| 465 | wm8741->reg_cache[WM8741_DACLMSB_ATTENUATION] |= WM8741_UPDATELM; | ||
| 466 | wm8741->reg_cache[WM8741_DACRLSB_ATTENUATION] |= WM8741_UPDATERL; | ||
| 467 | wm8741->reg_cache[WM8741_DACRLSB_ATTENUATION] |= WM8741_UPDATERM; | ||
| 468 | |||
| 469 | wm8741_codec = codec; | ||
| 470 | |||
| 471 | ret = snd_soc_register_codec(codec); | ||
| 472 | if (ret != 0) { | ||
| 473 | dev_err(codec->dev, "Failed to register codec: %d\n", ret); | ||
| 474 | return ret; | ||
| 475 | } | ||
| 476 | |||
| 477 | ret = snd_soc_register_dai(&wm8741_dai); | ||
| 478 | if (ret != 0) { | ||
| 479 | dev_err(codec->dev, "Failed to register DAI: %d\n", ret); | ||
| 480 | snd_soc_unregister_codec(codec); | ||
| 481 | return ret; | ||
| 482 | } | ||
| 483 | |||
| 484 | dev_dbg(codec->dev, "Successful registration\n"); | ||
| 485 | return 0; | ||
| 486 | |||
| 487 | err_enable: | ||
| 488 | regulator_bulk_disable(ARRAY_SIZE(wm8741->supplies), wm8741->supplies); | ||
| 489 | |||
| 490 | err_get: | ||
| 491 | regulator_bulk_free(ARRAY_SIZE(wm8741->supplies), wm8741->supplies); | ||
| 492 | |||
| 493 | err: | ||
| 494 | kfree(wm8741); | ||
| 495 | return ret; | ||
| 496 | } | ||
| 497 | |||
| 498 | static void wm8741_unregister(struct wm8741_priv *wm8741) | ||
| 499 | { | ||
| 500 | regulator_bulk_free(ARRAY_SIZE(wm8741->supplies), wm8741->supplies); | ||
| 501 | |||
| 502 | snd_soc_unregister_dai(&wm8741_dai); | ||
| 503 | snd_soc_unregister_codec(&wm8741->codec); | ||
| 504 | kfree(wm8741); | ||
| 505 | wm8741_codec = NULL; | ||
| 506 | } | ||
| 507 | |||
| 508 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
| 509 | static __devinit int wm8741_i2c_probe(struct i2c_client *i2c, | ||
| 510 | const struct i2c_device_id *id) | ||
| 511 | { | ||
| 512 | struct wm8741_priv *wm8741; | ||
| 513 | struct snd_soc_codec *codec; | ||
| 514 | |||
| 515 | wm8741 = kzalloc(sizeof(struct wm8741_priv), GFP_KERNEL); | ||
| 516 | if (wm8741 == NULL) | ||
| 517 | return -ENOMEM; | ||
| 518 | |||
| 519 | codec = &wm8741->codec; | ||
| 520 | codec->hw_write = (hw_write_t)i2c_master_send; | ||
| 521 | |||
| 522 | i2c_set_clientdata(i2c, wm8741); | ||
| 523 | codec->control_data = i2c; | ||
| 524 | |||
| 525 | codec->dev = &i2c->dev; | ||
| 526 | |||
| 527 | return wm8741_register(wm8741, SND_SOC_I2C); | ||
| 528 | } | ||
| 529 | |||
| 530 | static __devexit int wm8741_i2c_remove(struct i2c_client *client) | ||
| 531 | { | ||
| 532 | struct wm8741_priv *wm8741 = i2c_get_clientdata(client); | ||
| 533 | wm8741_unregister(wm8741); | ||
| 534 | return 0; | ||
| 535 | } | ||
| 536 | |||
| 537 | static const struct i2c_device_id wm8741_i2c_id[] = { | ||
| 538 | { "wm8741", 0 }, | ||
| 539 | { } | ||
| 540 | }; | ||
| 541 | MODULE_DEVICE_TABLE(i2c, wm8741_i2c_id); | ||
| 542 | |||
| 543 | |||
| 544 | static struct i2c_driver wm8741_i2c_driver = { | ||
| 545 | .driver = { | ||
| 546 | .name = "WM8741", | ||
| 547 | .owner = THIS_MODULE, | ||
| 548 | }, | ||
| 549 | .probe = wm8741_i2c_probe, | ||
| 550 | .remove = __devexit_p(wm8741_i2c_remove), | ||
| 551 | .id_table = wm8741_i2c_id, | ||
| 552 | }; | ||
| 553 | #endif | ||
| 554 | |||
| 555 | static int __init wm8741_modinit(void) | ||
| 556 | { | ||
| 557 | int ret; | ||
| 558 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
| 559 | ret = i2c_add_driver(&wm8741_i2c_driver); | ||
| 560 | if (ret != 0) { | ||
| 561 | printk(KERN_ERR "Failed to register WM8741 I2C driver: %d\n", | ||
| 562 | ret); | ||
| 563 | } | ||
| 564 | #endif | ||
| 565 | return 0; | ||
| 566 | } | ||
| 567 | module_init(wm8741_modinit); | ||
| 568 | |||
| 569 | static void __exit wm8741_exit(void) | ||
| 570 | { | ||
| 571 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
| 572 | i2c_del_driver(&wm8741_i2c_driver); | ||
| 573 | #endif | ||
| 574 | } | ||
| 575 | module_exit(wm8741_exit); | ||
| 576 | |||
| 577 | MODULE_DESCRIPTION("ASoC WM8741 driver"); | ||
| 578 | MODULE_AUTHOR("Ian Lartey <ian@opensource.wolfsonmicro.com>"); | ||
| 579 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/wm8741.h b/sound/soc/codecs/wm8741.h new file mode 100644 index 000000000000..fdef6ecd1f6f --- /dev/null +++ b/sound/soc/codecs/wm8741.h | |||
| @@ -0,0 +1,214 @@ | |||
| 1 | /* | ||
| 2 | * wm8741.h -- WM8423 ASoC driver | ||
| 3 | * | ||
| 4 | * Copyright 2010 Wolfson Microelectronics, plc | ||
| 5 | * | ||
| 6 | * Author: Ian Lartey <ian@opensource.wolfsonmicro.com> | ||
| 7 | * | ||
| 8 | * Based on wm8753.h | ||
| 9 | * | ||
| 10 | * This program is free software; you can redistribute it and/or modify | ||
| 11 | * it under the terms of the GNU General Public License version 2 as | ||
| 12 | * published by the Free Software Foundation. | ||
| 13 | */ | ||
| 14 | |||
| 15 | #ifndef _WM8741_H | ||
| 16 | #define _WM8741_H | ||
| 17 | |||
| 18 | /* | ||
| 19 | * Register values. | ||
| 20 | */ | ||
| 21 | #define WM8741_DACLLSB_ATTENUATION 0x00 | ||
| 22 | #define WM8741_DACLMSB_ATTENUATION 0x01 | ||
| 23 | #define WM8741_DACRLSB_ATTENUATION 0x02 | ||
| 24 | #define WM8741_DACRMSB_ATTENUATION 0x03 | ||
| 25 | #define WM8741_VOLUME_CONTROL 0x04 | ||
| 26 | #define WM8741_FORMAT_CONTROL 0x05 | ||
| 27 | #define WM8741_FILTER_CONTROL 0x06 | ||
| 28 | #define WM8741_MODE_CONTROL_1 0x07 | ||
| 29 | #define WM8741_MODE_CONTROL_2 0x08 | ||
| 30 | #define WM8741_RESET 0x09 | ||
| 31 | #define WM8741_ADDITIONAL_CONTROL_1 0x20 | ||
| 32 | |||
| 33 | #define WM8741_REGISTER_COUNT 11 | ||
| 34 | #define WM8741_MAX_REGISTER 0x20 | ||
| 35 | |||
| 36 | /* | ||
| 37 | * Field Definitions. | ||
| 38 | */ | ||
| 39 | |||
| 40 | /* | ||
| 41 | * R0 (0x00) - DACLLSB_ATTENUATION | ||
| 42 | */ | ||
| 43 | #define WM8741_UPDATELL 0x0020 /* UPDATELL */ | ||
| 44 | #define WM8741_UPDATELL_MASK 0x0020 /* UPDATELL */ | ||
| 45 | #define WM8741_UPDATELL_SHIFT 5 /* UPDATELL */ | ||
| 46 | #define WM8741_UPDATELL_WIDTH 1 /* UPDATELL */ | ||
| 47 | #define WM8741_LAT_4_0_MASK 0x001F /* LAT[4:0] - [4:0] */ | ||
| 48 | #define WM8741_LAT_4_0_SHIFT 0 /* LAT[4:0] - [4:0] */ | ||
| 49 | #define WM8741_LAT_4_0_WIDTH 5 /* LAT[4:0] - [4:0] */ | ||
| 50 | |||
| 51 | /* | ||
| 52 | * R1 (0x01) - DACLMSB_ATTENUATION | ||
| 53 | */ | ||
| 54 | #define WM8741_UPDATELM 0x0020 /* UPDATELM */ | ||
| 55 | #define WM8741_UPDATELM_MASK 0x0020 /* UPDATELM */ | ||
| 56 | #define WM8741_UPDATELM_SHIFT 5 /* UPDATELM */ | ||
| 57 | #define WM8741_UPDATELM_WIDTH 1 /* UPDATELM */ | ||
| 58 | #define WM8741_LAT_9_5_0_MASK 0x001F /* LAT[9:5] - [4:0] */ | ||
| 59 | #define WM8741_LAT_9_5_0_SHIFT 0 /* LAT[9:5] - [4:0] */ | ||
| 60 | #define WM8741_LAT_9_5_0_WIDTH 5 /* LAT[9:5] - [4:0] */ | ||
| 61 | |||
| 62 | /* | ||
| 63 | * R2 (0x02) - DACRLSB_ATTENUATION | ||
| 64 | */ | ||
| 65 | #define WM8741_UPDATERL 0x0020 /* UPDATERL */ | ||
| 66 | #define WM8741_UPDATERL_MASK 0x0020 /* UPDATERL */ | ||
| 67 | #define WM8741_UPDATERL_SHIFT 5 /* UPDATERL */ | ||
| 68 | #define WM8741_UPDATERL_WIDTH 1 /* UPDATERL */ | ||
| 69 | #define WM8741_RAT_4_0_MASK 0x001F /* RAT[4:0] - [4:0] */ | ||
| 70 | #define WM8741_RAT_4_0_SHIFT 0 /* RAT[4:0] - [4:0] */ | ||
| 71 | #define WM8741_RAT_4_0_WIDTH 5 /* RAT[4:0] - [4:0] */ | ||
| 72 | |||
| 73 | /* | ||
| 74 | * R3 (0x03) - DACRMSB_ATTENUATION | ||
| 75 | */ | ||
| 76 | #define WM8741_UPDATERM 0x0020 /* UPDATERM */ | ||
| 77 | #define WM8741_UPDATERM_MASK 0x0020 /* UPDATERM */ | ||
| 78 | #define WM8741_UPDATERM_SHIFT 5 /* UPDATERM */ | ||
| 79 | #define WM8741_UPDATERM_WIDTH 1 /* UPDATERM */ | ||
| 80 | #define WM8741_RAT_9_5_0_MASK 0x001F /* RAT[9:5] - [4:0] */ | ||
| 81 | #define WM8741_RAT_9_5_0_SHIFT 0 /* RAT[9:5] - [4:0] */ | ||
| 82 | #define WM8741_RAT_9_5_0_WIDTH 5 /* RAT[9:5] - [4:0] */ | ||
| 83 | |||
| 84 | /* | ||
| 85 | * R4 (0x04) - VOLUME_CONTROL | ||
| 86 | */ | ||
| 87 | #define WM8741_AMUTE 0x0080 /* AMUTE */ | ||
| 88 | #define WM8741_AMUTE_MASK 0x0080 /* AMUTE */ | ||
| 89 | #define WM8741_AMUTE_SHIFT 7 /* AMUTE */ | ||
| 90 | #define WM8741_AMUTE_WIDTH 1 /* AMUTE */ | ||
| 91 | #define WM8741_ZFLAG_MASK 0x0060 /* ZFLAG - [6:5] */ | ||
| 92 | #define WM8741_ZFLAG_SHIFT 5 /* ZFLAG - [6:5] */ | ||
| 93 | #define WM8741_ZFLAG_WIDTH 2 /* ZFLAG - [6:5] */ | ||
| 94 | #define WM8741_IZD 0x0010 /* IZD */ | ||
| 95 | #define WM8741_IZD_MASK 0x0010 /* IZD */ | ||
| 96 | #define WM8741_IZD_SHIFT 4 /* IZD */ | ||
| 97 | #define WM8741_IZD_WIDTH 1 /* IZD */ | ||
| 98 | #define WM8741_SOFT 0x0008 /* SOFT MUTE */ | ||
| 99 | #define WM8741_SOFT_MASK 0x0008 /* SOFT MUTE */ | ||
| 100 | #define WM8741_SOFT_SHIFT 3 /* SOFT MUTE */ | ||
| 101 | #define WM8741_SOFT_WIDTH 1 /* SOFT MUTE */ | ||
| 102 | #define WM8741_ATC 0x0004 /* ATC */ | ||
| 103 | #define WM8741_ATC_MASK 0x0004 /* ATC */ | ||
| 104 | #define WM8741_ATC_SHIFT 2 /* ATC */ | ||
| 105 | #define WM8741_ATC_WIDTH 1 /* ATC */ | ||
| 106 | #define WM8741_ATT2DB 0x0002 /* ATT2DB */ | ||
| 107 | #define WM8741_ATT2DB_MASK 0x0002 /* ATT2DB */ | ||
| 108 | #define WM8741_ATT2DB_SHIFT 1 /* ATT2DB */ | ||
| 109 | #define WM8741_ATT2DB_WIDTH 1 /* ATT2DB */ | ||
| 110 | #define WM8741_VOL_RAMP 0x0001 /* VOL_RAMP */ | ||
| 111 | #define WM8741_VOL_RAMP_MASK 0x0001 /* VOL_RAMP */ | ||
| 112 | #define WM8741_VOL_RAMP_SHIFT 0 /* VOL_RAMP */ | ||
| 113 | #define WM8741_VOL_RAMP_WIDTH 1 /* VOL_RAMP */ | ||
| 114 | |||
| 115 | /* | ||
| 116 | * R5 (0x05) - FORMAT_CONTROL | ||
| 117 | */ | ||
| 118 | #define WM8741_PWDN 0x0080 /* PWDN */ | ||
| 119 | #define WM8741_PWDN_MASK 0x0080 /* PWDN */ | ||
| 120 | #define WM8741_PWDN_SHIFT 7 /* PWDN */ | ||
| 121 | #define WM8741_PWDN_WIDTH 1 /* PWDN */ | ||
| 122 | #define WM8741_REV 0x0040 /* REV */ | ||
| 123 | #define WM8741_REV_MASK 0x0040 /* REV */ | ||
| 124 | #define WM8741_REV_SHIFT 6 /* REV */ | ||
| 125 | #define WM8741_REV_WIDTH 1 /* REV */ | ||
| 126 | #define WM8741_BCP 0x0020 /* BCP */ | ||
| 127 | #define WM8741_BCP_MASK 0x0020 /* BCP */ | ||
| 128 | #define WM8741_BCP_SHIFT 5 /* BCP */ | ||
| 129 | #define WM8741_BCP_WIDTH 1 /* BCP */ | ||
| 130 | #define WM8741_LRP 0x0010 /* LRP */ | ||
| 131 | #define WM8741_LRP_MASK 0x0010 /* LRP */ | ||
| 132 | #define WM8741_LRP_SHIFT 4 /* LRP */ | ||
| 133 | #define WM8741_LRP_WIDTH 1 /* LRP */ | ||
| 134 | #define WM8741_FMT_MASK 0x000C /* FMT - [3:2] */ | ||
| 135 | #define WM8741_FMT_SHIFT 2 /* FMT - [3:2] */ | ||
| 136 | #define WM8741_FMT_WIDTH 2 /* FMT - [3:2] */ | ||
| 137 | #define WM8741_IWL_MASK 0x0003 /* IWL - [1:0] */ | ||
| 138 | #define WM8741_IWL_SHIFT 0 /* IWL - [1:0] */ | ||
| 139 | #define WM8741_IWL_WIDTH 2 /* IWL - [1:0] */ | ||
| 140 | |||
| 141 | /* | ||
| 142 | * R6 (0x06) - FILTER_CONTROL | ||
| 143 | */ | ||
| 144 | #define WM8741_ZFLAG_HI 0x0080 /* ZFLAG_HI */ | ||
| 145 | #define WM8741_ZFLAG_HI_MASK 0x0080 /* ZFLAG_HI */ | ||
| 146 | #define WM8741_ZFLAG_HI_SHIFT 7 /* ZFLAG_HI */ | ||
| 147 | #define WM8741_ZFLAG_HI_WIDTH 1 /* ZFLAG_HI */ | ||
| 148 | #define WM8741_DEEMPH_MASK 0x0060 /* DEEMPH - [6:5] */ | ||
| 149 | #define WM8741_DEEMPH_SHIFT 5 /* DEEMPH - [6:5] */ | ||
| 150 | #define WM8741_DEEMPH_WIDTH 2 /* DEEMPH - [6:5] */ | ||
| 151 | #define WM8741_DSDFILT_MASK 0x0018 /* DSDFILT - [4:3] */ | ||
| 152 | #define WM8741_DSDFILT_SHIFT 3 /* DSDFILT - [4:3] */ | ||
| 153 | #define WM8741_DSDFILT_WIDTH 2 /* DSDFILT - [4:3] */ | ||
| 154 | #define WM8741_FIRSEL_MASK 0x0007 /* FIRSEL - [2:0] */ | ||
| 155 | #define WM8741_FIRSEL_SHIFT 0 /* FIRSEL - [2:0] */ | ||
| 156 | #define WM8741_FIRSEL_WIDTH 3 /* FIRSEL - [2:0] */ | ||
| 157 | |||
| 158 | /* | ||
| 159 | * R7 (0x07) - MODE_CONTROL_1 | ||
| 160 | */ | ||
| 161 | #define WM8741_MODE8X 0x0080 /* MODE8X */ | ||
| 162 | #define WM8741_MODE8X_MASK 0x0080 /* MODE8X */ | ||
| 163 | #define WM8741_MODE8X_SHIFT 7 /* MODE8X */ | ||
| 164 | #define WM8741_MODE8X_WIDTH 1 /* MODE8X */ | ||
| 165 | #define WM8741_OSR_MASK 0x0060 /* OSR - [6:5] */ | ||
| 166 | #define WM8741_OSR_SHIFT 5 /* OSR - [6:5] */ | ||
| 167 | #define WM8741_OSR_WIDTH 2 /* OSR - [6:5] */ | ||
| 168 | #define WM8741_SR_MASK 0x001C /* SR - [4:2] */ | ||
| 169 | #define WM8741_SR_SHIFT 2 /* SR - [4:2] */ | ||
| 170 | #define WM8741_SR_WIDTH 3 /* SR - [4:2] */ | ||
| 171 | #define WM8741_MODESEL_MASK 0x0003 /* MODESEL - [1:0] */ | ||
| 172 | #define WM8741_MODESEL_SHIFT 0 /* MODESEL - [1:0] */ | ||
| 173 | #define WM8741_MODESEL_WIDTH 2 /* MODESEL - [1:0] */ | ||
| 174 | |||
| 175 | /* | ||
| 176 | * R8 (0x08) - MODE_CONTROL_2 | ||
| 177 | */ | ||
| 178 | #define WM8741_DSD_GAIN 0x0040 /* DSD_GAIN */ | ||
| 179 | #define WM8741_DSD_GAIN_MASK 0x0040 /* DSD_GAIN */ | ||
| 180 | #define WM8741_DSD_GAIN_SHIFT 6 /* DSD_GAIN */ | ||
| 181 | #define WM8741_DSD_GAIN_WIDTH 1 /* DSD_GAIN */ | ||
| 182 | #define WM8741_SDOUT 0x0020 /* SDOUT */ | ||
| 183 | #define WM8741_SDOUT_MASK 0x0020 /* SDOUT */ | ||
| 184 | #define WM8741_SDOUT_SHIFT 5 /* SDOUT */ | ||
| 185 | #define WM8741_SDOUT_WIDTH 1 /* SDOUT */ | ||
| 186 | #define WM8741_DOUT 0x0010 /* DOUT */ | ||
| 187 | #define WM8741_DOUT_MASK 0x0010 /* DOUT */ | ||
| 188 | #define WM8741_DOUT_SHIFT 4 /* DOUT */ | ||
| 189 | #define WM8741_DOUT_WIDTH 1 /* DOUT */ | ||
| 190 | #define WM8741_DIFF_MASK 0x000C /* DIFF - [3:2] */ | ||
| 191 | #define WM8741_DIFF_SHIFT 2 /* DIFF - [3:2] */ | ||
| 192 | #define WM8741_DIFF_WIDTH 2 /* DIFF - [3:2] */ | ||
| 193 | #define WM8741_DITHER_MASK 0x0003 /* DITHER - [1:0] */ | ||
| 194 | #define WM8741_DITHER_SHIFT 0 /* DITHER - [1:0] */ | ||
| 195 | #define WM8741_DITHER_WIDTH 2 /* DITHER - [1:0] */ | ||
| 196 | |||
| 197 | /* | ||
| 198 | * R32 (0x20) - ADDITONAL_CONTROL_1 | ||
| 199 | */ | ||
| 200 | #define WM8741_DSD_LEVEL 0x0002 /* DSD_LEVEL */ | ||
| 201 | #define WM8741_DSD_LEVEL_MASK 0x0002 /* DSD_LEVEL */ | ||
| 202 | #define WM8741_DSD_LEVEL_SHIFT 1 /* DSD_LEVEL */ | ||
| 203 | #define WM8741_DSD_LEVEL_WIDTH 1 /* DSD_LEVEL */ | ||
| 204 | #define WM8741_DSD_NO_NOTCH 0x0001 /* DSD_NO_NOTCH */ | ||
| 205 | #define WM8741_DSD_NO_NOTCH_MASK 0x0001 /* DSD_NO_NOTCH */ | ||
| 206 | #define WM8741_DSD_NO_NOTCH_SHIFT 0 /* DSD_NO_NOTCH */ | ||
| 207 | #define WM8741_DSD_NO_NOTCH_WIDTH 1 /* DSD_NO_NOTCH */ | ||
| 208 | |||
| 209 | #define WM8741_SYSCLK 0 | ||
| 210 | |||
| 211 | extern struct snd_soc_dai wm8741_dai; | ||
| 212 | extern struct snd_soc_codec_device soc_codec_dev_wm8741; | ||
| 213 | |||
| 214 | #endif | ||
