diff options
| -rw-r--r-- | include/sound/wm8904.h | 57 | ||||
| -rw-r--r-- | sound/soc/codecs/Kconfig | 4 | ||||
| -rw-r--r-- | sound/soc/codecs/Makefile | 2 | ||||
| -rw-r--r-- | sound/soc/codecs/wm8904.c | 2538 | ||||
| -rw-r--r-- | sound/soc/codecs/wm8904.h | 1681 |
5 files changed, 4282 insertions, 0 deletions
diff --git a/include/sound/wm8904.h b/include/sound/wm8904.h new file mode 100644 index 000000000000..d66575a601be --- /dev/null +++ b/include/sound/wm8904.h @@ -0,0 +1,57 @@ +/* + * Platform data for WM8904 + * + * Copyright 2009 Wolfson Microelectronics PLC. + * + * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#ifndef __MFD_WM8994_PDATA_H__ +#define __MFD_WM8994_PDATA_H__ + +#define WM8904_DRC_REGS 4 +#define WM8904_EQ_REGS 25 + +/** + * DRC configurations are specified with a label and a set of register + * values to write (the enable bits will be ignored). At runtime an + * enumerated control will be presented for each DRC block allowing + * the user to choose the configration to use. + * + * Configurations may be generated by hand or by using the DRC control + * panel provided by the WISCE - see http://www.wolfsonmicro.com/wisce/ + * for details. + */ +struct wm8904_drc_cfg { + const char *name; + u16 regs[WM8904_DRC_REGS]; +}; + +/** + * ReTune Mobile configurations are specified with a label, sample + * rate and set of values to write (the enable bits will be ignored). + * + * Configurations are expected to be generated using the ReTune Mobile + * control panel in WISCE - see http://www.wolfsonmicro.com/wisce/ + */ +struct wm8904_retune_mobile_cfg { + const char *name; + unsigned int rate; + u16 regs[WM8904_EQ_REGS]; +}; + +struct wm8904_pdata { + int num_drc_cfgs; + struct wm8904_drc_cfg *drc_cfgs; + + int num_retune_mobile_cfgs; + struct wm8904_retune_mobile_cfg *retune_mobile_cfgs; +}; + +#endif diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 52b005f8fed4..011d3ab7e64a 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -49,6 +49,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_WM8776 if SND_SOC_I2C_AND_SPI select SND_SOC_WM8900 if I2C select SND_SOC_WM8903 if I2C + select SND_SOC_WM8904 if I2C select SND_SOC_WM8940 if I2C select SND_SOC_WM8960 if I2C select SND_SOC_WM8961 if I2C @@ -203,6 +204,9 @@ config SND_SOC_WM8900 config SND_SOC_WM8903 tristate +config SND_SOC_WM8904 + tristate + config SND_SOC_WM8940 tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index dbaecb133ac7..0471d9044205 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -36,6 +36,7 @@ snd-soc-wm8753-objs := wm8753.o snd-soc-wm8776-objs := wm8776.o snd-soc-wm8900-objs := wm8900.o snd-soc-wm8903-objs := wm8903.o +snd-soc-wm8904-objs := wm8904.o snd-soc-wm8940-objs := wm8940.o snd-soc-wm8960-objs := wm8960.o snd-soc-wm8961-objs := wm8961.o @@ -92,6 +93,7 @@ obj-$(CONFIG_SND_SOC_WM8753) += snd-soc-wm8753.o obj-$(CONFIG_SND_SOC_WM8776) += snd-soc-wm8776.o obj-$(CONFIG_SND_SOC_WM8900) += snd-soc-wm8900.o obj-$(CONFIG_SND_SOC_WM8903) += snd-soc-wm8903.o +obj-$(CONFIG_SND_SOC_WM8904) += snd-soc-wm8904.o obj-$(CONFIG_SND_SOC_WM8971) += snd-soc-wm8971.o obj-$(CONFIG_SND_SOC_WM8974) += snd-soc-wm8974.o obj-$(CONFIG_SND_SOC_WM8940) += snd-soc-wm8940.o diff --git a/sound/soc/codecs/wm8904.c b/sound/soc/codecs/wm8904.c new file mode 100644 index 000000000000..8310e5d14b83 --- /dev/null +++ b/sound/soc/codecs/wm8904.c @@ -0,0 +1,2538 @@ +/* + * wm8904.c -- WM8904 ALSA SoC Audio driver + * + * Copyright 2009 Wolfson Microelectronics plc + * + * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/pm.h> +#include <linux/i2c.h> +#include <linux/platform_device.h> +#include <linux/regulator/consumer.h> +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include <sound/soc-dapm.h> +#include <sound/initval.h> +#include <sound/tlv.h> +#include <sound/wm8904.h> + +#include "wm8904.h" + +static struct snd_soc_codec *wm8904_codec; +struct snd_soc_codec_device soc_codec_dev_wm8904; + +#define WM8904_NUM_DCS_CHANNELS 4 + +#define WM8904_NUM_SUPPLIES 5 +static const char *wm8904_supply_names[WM8904_NUM_SUPPLIES] = { + "DCVDD", + "DBVDD", + "AVDD", + "CPVDD", + "MICVDD", +}; + +/* codec private data */ +struct wm8904_priv { + struct snd_soc_codec codec; + u16 reg_cache[WM8904_MAX_REGISTER + 1]; + + struct regulator_bulk_data supplies[WM8904_NUM_SUPPLIES]; + + struct wm8904_pdata *pdata; + + int deemph; + + /* Platform provided DRC configuration */ + const char **drc_texts; + int drc_cfg; + struct soc_enum drc_enum; + + /* Platform provided ReTune mobile configuration */ + int num_retune_mobile_texts; + const char **retune_mobile_texts; + int retune_mobile_cfg; + struct soc_enum retune_mobile_enum; + + /* FLL setup */ + int fll_src; + int fll_fref; + int fll_fout; + + /* Clocking configuration */ + unsigned int mclk_rate; + int sysclk_src; + unsigned int sysclk_rate; + + int tdm_width; + int tdm_slots; + int bclk; + int fs; + + /* DC servo configuration - cached offset values */ + int dcs_state[WM8904_NUM_DCS_CHANNELS]; +}; + +static const u16 wm8904_reg[WM8904_MAX_REGISTER + 1] = { + 0x8904, /* R0 - SW Reset and ID */ + 0x0000, /* R1 - Revision */ + 0x0000, /* R2 */ + 0x0000, /* R3 */ + 0x0018, /* R4 - Bias Control 0 */ + 0x0000, /* R5 - VMID Control 0 */ + 0x0000, /* R6 - Mic Bias Control 0 */ + 0x0000, /* R7 - Mic Bias Control 1 */ + 0x0001, /* R8 - Analogue DAC 0 */ + 0x9696, /* R9 - mic Filter Control */ + 0x0001, /* R10 - Analogue ADC 0 */ + 0x0000, /* R11 */ + 0x0000, /* R12 - Power Management 0 */ + 0x0000, /* R13 */ + 0x0000, /* R14 - Power Management 2 */ + 0x0000, /* R15 - Power Management 3 */ + 0x0000, /* R16 */ + 0x0000, /* R17 */ + 0x0000, /* R18 - Power Management 6 */ + 0x0000, /* R19 */ + 0x945E, /* R20 - Clock Rates 0 */ + 0x0C05, /* R21 - Clock Rates 1 */ + 0x0006, /* R22 - Clock Rates 2 */ + 0x0000, /* R23 */ + 0x0050, /* R24 - Audio Interface 0 */ + 0x000A, /* R25 - Audio Interface 1 */ + 0x00E4, /* R26 - Audio Interface 2 */ + 0x0040, /* R27 - Audio Interface 3 */ + 0x0000, /* R28 */ + 0x0000, /* R29 */ + 0x00C0, /* R30 - DAC Digital Volume Left */ + 0x00C0, /* R31 - DAC Digital Volume Right */ + 0x0000, /* R32 - DAC Digital 0 */ + 0x0008, /* R33 - DAC Digital 1 */ + 0x0000, /* R34 */ + 0x0000, /* R35 */ + 0x00C0, /* R36 - ADC Digital Volume Left */ + 0x00C0, /* R37 - ADC Digital Volume Right */ + 0x0010, /* R38 - ADC Digital 0 */ + 0x0000, /* R39 - Digital Microphone 0 */ + 0x01AF, /* R40 - DRC 0 */ + 0x3248, /* R41 - DRC 1 */ + 0x0000, /* R42 - DRC 2 */ + 0x0000, /* R43 - DRC 3 */ + 0x0085, /* R44 - Analogue Left Input 0 */ + 0x0085, /* R45 - Analogue Right Input 0 */ + 0x0044, /* R46 - Analogue Left Input 1 */ + 0x0044, /* R47 - Analogue Right Input 1 */ + 0x0000, /* R48 */ + 0x0000, /* R49 */ + 0x0000, /* R50 */ + 0x0000, /* R51 */ + 0x0000, /* R52 */ + 0x0000, /* R53 */ + 0x0000, /* R54 */ + 0x0000, /* R55 */ + 0x0000, /* R56 */ + 0x002D, /* R57 - Analogue OUT1 Left */ + 0x002D, /* R58 - Analogue OUT1 Right */ + 0x0039, /* R59 - Analogue OUT2 Left */ + 0x0039, /* R60 - Analogue OUT2 Right */ + 0x0000, /* R61 - Analogue OUT12 ZC */ + 0x0000, /* R62 */ + 0x0000, /* R63 */ + 0x0000, /* R64 */ + 0x0000, /* R65 */ + 0x0000, /* R66 */ + 0x0000, /* R67 - DC Servo 0 */ + 0x0000, /* R68 - DC Servo 1 */ + 0xAAAA, /* R69 - DC Servo 2 */ + 0x0000, /* R70 */ + 0xAAAA, /* R71 - DC Servo 4 */ + 0xAAAA, /* R72 - DC Servo 5 */ + 0x0000, /* R73 - DC Servo 6 */ + 0x0000, /* R74 - DC Servo 7 */ + 0x0000, /* R75 - DC Servo 8 */ + 0x0000, /* R76 - DC Servo 9 */ + 0x0000, /* R77 - DC Servo Readback 0 */ + 0x0000, /* R78 */ + 0x0000, /* R79 */ + 0x0000, /* R80 */ + 0x0000, /* R81 */ + 0x0000, /* R82 */ + 0x0000, /* R83 */ + 0x0000, /* R84 */ + 0x0000, /* R85 */ + 0x0000, /* R86 */ + 0x0000, /* R87 */ + 0x0000, /* R88 */ + 0x0000, /* R89 */ + 0x0000, /* R90 - Analogue HP 0 */ + 0x0000, /* R91 */ + 0x0000, /* R92 */ + 0x0000, /* R93 */ + 0x0000, /* R94 - Analogue Lineout 0 */ + 0x0000, /* R95 */ + 0x0000, /* R96 */ + 0x0000, /* R97 */ + 0x0000, /* R98 - Charge Pump 0 */ + 0x0000, /* R99 */ + 0x0000, /* R100 */ + 0x0000, /* R101 */ + 0x0000, /* R102 */ + 0x0000, /* R103 */ + 0x0004, /* R104 - Class W 0 */ + 0x0000, /* R105 */ + 0x0000, /* R106 */ + 0x0000, /* R107 */ + 0x0000, /* R108 - Write Sequencer 0 */ + 0x0000, /* R109 - Write Sequencer 1 */ + 0x0000, /* R110 - Write Sequencer 2 */ + 0x0000, /* R111 - Write Sequencer 3 */ + 0x0000, /* R112 - Write Sequencer 4 */ + 0x0000, /* R113 */ + 0x0000, /* R114 */ + 0x0000, /* R115 */ + 0x0000, /* R116 - FLL Control 1 */ + 0x0007, /* R117 - FLL Control 2 */ + 0x0000, /* R118 - FLL Control 3 */ + 0x2EE0, /* R119 - FLL Control 4 */ + 0x0004, /* R120 - FLL Control 5 */ + 0x0014, /* R121 - GPIO Control 1 */ + 0x0010, /* R122 - GPIO Control 2 */ + 0x0010, /* R123 - GPIO Control 3 */ + 0x0000, /* R124 - GPIO Control 4 */ + 0x0000, /* R125 */ + 0x0000, /* R126 - Digital Pulls */ + 0x0000, /* R127 - Interrupt Status */ + 0xFFFF, /* R128 - Interrupt Status Mask */ + 0x0000, /* R129 - Interrupt Polarity */ + 0x0000, /* R130 - Interrupt Debounce */ + 0x0000, /* R131 */ + 0x0000, /* R132 */ + 0x0000, /* R133 */ + 0x0000, /* R134 - EQ1 */ + 0x000C, /* R135 - EQ2 */ + 0x000C, /* R136 - EQ3 */ + 0x000C, /* R137 - EQ4 */ + 0x000C, /* R138 - EQ5 */ + 0x000C, /* R139 - EQ6 */ + 0x0FCA, /* R140 - EQ7 */ + 0x0400, /* R141 - EQ8 */ + 0x00D8, /* R142 - EQ9 */ + 0x1EB5, /* R143 - EQ10 */ + 0xF145, /* R144 - EQ11 */ + 0x0B75, /* R145 - EQ12 */ + 0x01C5, /* R146 - EQ13 */ + 0x1C58, /* R147 - EQ14 */ + 0xF373, /* R148 - EQ15 */ + 0x0A54, /* R149 - EQ16 */ + 0x0558, /* R150 - EQ17 */ + 0x168E, /* R151 - EQ18 */ + 0xF829, /* R152 - EQ19 */ + 0x07AD, /* R153 - EQ20 */ + 0x1103, /* R154 - EQ21 */ + 0x0564, /* R155 - EQ22 */ + 0x0559, /* R156 - EQ23 */ + 0x4000, /* R157 - EQ24 */ + 0x0000, /* R158 */ + 0x0000, /* R159 */ + 0x0000, /* R160 */ + 0x0000, /* R161 - Control Interface Test 1 */ + 0x0000, /* R162 */ + 0x0000, /* R163 */ + 0x0000, /* R164 */ + 0x0000, /* R165 */ + 0x0000, /* R166 */ + 0x0000, /* R167 */ + 0x0000, /* R168 */ + 0x0000, /* R169 */ + 0x0000, /* R170 */ + 0x0000, /* R171 */ + 0x0000, /* R172 */ + 0x0000, /* R173 */ + 0x0000, /* R174 */ + 0x0000, /* R175 */ + 0x0000, /* R176 */ + 0x0000, /* R177 */ + 0x0000, /* R178 */ + 0x0000, /* R179 */ + 0x0000, /* R180 */ + 0x0000, /* R181 */ + 0x0000, /* R182 */ + 0x0000, /* R183 */ + 0x0000, /* R184 */ + 0x0000, /* R185 */ + 0x0000, /* R186 */ + 0x0000, /* R187 */ + 0x0000, /* R188 */ + 0x0000, /* R189 */ + 0x0000, /* R190 */ + 0x0000, /* R191 */ + 0x0000, /* R192 */ + 0x0000, /* R193 */ + 0x0000, /* R194 */ + 0x0000, /* R195 */ + 0x0000, /* R196 */ + 0x0000, /* R197 */ + 0x0000, /* R198 */ + 0x0000, /* R199 */ + 0x0000, /* R200 */ + 0x0000, /* R201 */ + 0x0000, /* R202 */ + 0x0000, /* R203 */ + 0x0000, /* R204 - Analogue Output Bias 0 */ + 0x0000, /* R205 */ + 0x0000, /* R206 */ + 0x0000, /* R207 */ + 0x0000, /* R208 */ + 0x0000, /* R209 */ + 0x0000, /* R210 */ + 0x0000, /* R211 */ + 0x0000, /* R212 */ + 0x0000, /* R213 */ + 0x0000, /* R214 */ + 0x0000, /* R215 */ + 0x0000, /* R216 */ + 0x0000, /* R217 */ + 0x0000, /* R218 */ + 0x0000, /* R219 */ + 0x0000, /* R220 */ + 0x0000, /* R221 */ + 0x0000, /* R222 */ + 0x0000, /* R223 */ + 0x0000, /* R224 */ + 0x0000, /* R225 */ + 0x0000, /* R226 */ + 0x0000, /* R227 */ + 0x0000, /* R228 */ + 0x0000, /* R229 */ + 0x0000, /* R230 */ + 0x0000, /* R231 */ + 0x0000, /* R232 */ + 0x0000, /* R233 */ + 0x0000, /* R234 */ + 0x0000, /* R235 */ + 0x0000, /* R236 */ + 0x0000, /* R237 */ + 0x0000, /* R238 */ + 0x0000, /* R239 */ + 0x0000, /* R240 */ + 0x0000, /* R241 */ + 0x0000, /* R242 */ + 0x0000, /* R243 */ + 0x0000, /* R244 */ + 0x0000, /* R245 */ + 0x0000, /* R246 */ + 0x0000, /* R247 - FLL NCO Test 0 */ + 0x0019, /* R248 - FLL NCO Test 1 */ +}; + +static struct { + int readable; + int writable; + int vol; +} wm8904_access[] = { + { 0xFFFF, 0xFFFF, 1 }, /* R0 - SW Reset and ID */ + { 0x0000, 0x0000, 0 }, /* R1 - Revision */ + { 0x0000, 0x0000, 0 }, /* R2 */ + { 0x0000, 0x0000, 0 }, /* R3 */ + { 0x001F, 0x001F, 0 }, /* R4 - Bias Control 0 */ + { 0x0047, 0x0047, 0 }, /* R5 - VMID Control 0 */ + { 0x007F, 0x007F, 0 }, /* R6 - Mic Bias Control 0 */ + { 0xC007, 0xC007, 0 }, /* R7 - Mic Bias Control 1 */ + { 0x001E, 0x001E, 0 }, /* R8 - Analogue DAC 0 */ + { 0xFFFF, 0xFFFF, 0 }, /* R9 - mic Filter Control */ + { 0x0001, 0x0001, 0 }, /* R10 - Analogue ADC 0 */ + { 0x0000, 0x0000, 0 }, /* R11 */ + { 0x0003, 0x0003, 0 }, /* R12 - Power Management 0 */ + { 0x0000, 0x0000, 0 }, /* R13 */ + { 0x0003, 0x0003, 0 }, /* R14 - Power Management 2 */ + { 0x0003, 0x0003, 0 }, /* R15 - Power Management 3 */ + { 0x0000, 0x0000, 0 }, /* R16 */ + { 0x0000, 0x0000, 0 }, /* R17 */ + { 0x000F, 0x000F, 0 }, /* R18 - Power Management 6 */ + { 0x0000, 0x0000, 0 }, /* R19 */ + { 0x7001, 0x7001, 0 }, /* R20 - Clock Rates 0 */ + { 0x3C07, 0x3C07, 0 }, /* R21 - Clock Rates 1 */ + { 0xD00F, 0xD00F, 0 }, /* R22 - Clock Rates 2 */ + { 0x0000, 0x0000, 0 }, /* R23 */ + { 0x1FFF, 0x1FFF, 0 }, /* R24 - Audio Interface 0 */ + { 0x3DDF, 0x3DDF, 0 }, /* R25 - Audio Interface 1 */ + { 0x0F1F, 0x0F1F, 0 }, /* R26 - Audio Interface 2 */ + { 0x0FFF, 0x0FFF, 0 }, /* R27 - Audio Interface 3 */ + { 0x0000, 0x0000, 0 }, /* R28 */ + { 0x0000, 0x0000, 0 }, /* R29 */ + { 0x00FF, 0x01FF, 0 }, /* R30 - DAC Digital Volume Left */ + { 0x00FF, 0x01FF, 0 }, /* R31 - DAC Digital Volume Right */ + { 0x0FFF, 0x0FFF, 0 }, /* R32 - DAC Digital 0 */ + { 0x1E4E, 0x1E4E, 0 }, /* R33 - DAC Digital 1 */ + { 0x0000, 0x0000, 0 }, /* R34 */ + { 0x0000, 0x0000, 0 }, /* R35 */ + { 0x00FF, 0x01FF, 0 }, /* R36 - ADC Digital Volume Left */ + { 0x00FF, 0x01FF, 0 }, /* R37 - ADC Digital Volume Right */ + { 0x0073, 0x0073, 0 }, /* R38 - ADC Digital 0 */ + { 0x1800, 0x1800, 0 }, /* R39 - Digital Microphone 0 */ + { 0xDFEF, 0xDFEF, 0 }, /* R40 - DRC 0 */ + { 0xFFFF, 0xFFFF, 0 }, /* R41 - DRC 1 */ + { 0x003F, 0x003F, 0 }, /* R42 - DRC 2 */ + { 0x07FF, 0x07FF, 0 }, /* R43 - DRC 3 */ + { 0x009F, 0x009F, 0 }, /* R44 - Analogue Left Input 0 */ + { 0x009F, 0x009F, 0 }, /* R45 - Analogue Right Input 0 */ + { 0x007F, 0x007F, 0 }, /* R46 - Analogue Left Input 1 */ + { 0x007F, 0x007F, 0 }, /* R47 - Analogue Right Input 1 */ + { 0x0000, 0x0000, 0 }, /* R48 */ + { 0x0000, 0x0000, 0 }, /* R49 */ + { 0x0000, 0x0000, 0 }, /* R50 */ + { 0x0000, 0x0000, 0 }, /* R51 */ + { 0x0000, 0x0000, 0 }, /* R52 */ + { 0x0000, 0x0000, 0 }, /* R53 */ + { 0x0000, 0x0000, 0 }, /* R54 */ + { 0x0000, 0x0000, 0 }, /* R55 */ + { 0x0000, 0x0000, 0 }, /* R56 */ + { 0x017F, 0x01FF, 0 }, /* R57 - Analogue OUT1 Left */ + { 0x017F, 0x01FF, 0 }, /* R58 - Analogue OUT1 Right */ + { 0x017F, 0x01FF, 0 }, /* R59 - Analogue OUT2 Left */ + { 0x017F, 0x01FF, 0 }, /* R60 - Analogue OUT2 Right */ + { 0x000F, 0x000F, 0 }, /* R61 - Analogue OUT12 ZC */ + { 0x0000, 0x0000, 0 }, /* R62 */ + { 0x0000, 0x0000, 0 }, /* R63 */ + { 0x0000, 0x0000, 0 }, /* R64 */ + { 0x0000, 0x0000, 0 }, /* R65 */ + { 0x0000, 0x0000, 0 }, /* R66 */ + { 0x000F, 0x000F, 0 }, /* R67 - DC Servo 0 */ + { 0xFFFF, 0xFFFF, 1 }, /* R68 - DC Servo 1 */ + { 0x0F0F, 0x0F0F, 0 }, /* R69 - DC Servo 2 */ + { 0x0000, 0x0000, 0 }, /* R70 */ + { 0x007F, 0x007F, 0 }, /* R71 - DC Servo 4 */ + { 0x007F, 0x007F, 0 }, /* R72 - DC Servo 5 */ + { 0x00FF, 0x00FF, 1 }, /* R73 - DC Servo 6 */ + { 0x00FF, 0x00FF, 1 }, /* R74 - DC Servo 7 */ + { 0x00FF, 0x00FF, 1 }, /* R75 - DC Servo 8 */ + { 0x00FF, 0x00FF, 1 }, /* R76 - DC Servo 9 */ + { 0x0FFF, 0x0000, 1 }, /* R77 - DC Servo Readback 0 */ + { 0x0000, 0x0000, 0 }, /* R78 */ + { 0x0000, 0x0000, 0 }, /* R79 */ + { 0x0000, 0x0000, 0 }, /* R80 */ + { 0x0000, 0x0000, 0 }, /* R81 */ + { 0x0000, 0x0000, 0 }, /* R82 */ + { 0x0000, 0x0000, 0 }, /* R83 */ + { 0x0000, 0x0000, 0 }, /* R84 */ + { 0x0000, 0x0000, 0 }, /* R85 */ + { 0x0000, 0x0000, 0 }, /* R86 */ + { 0x0000, 0x0000, 0 }, /* R87 */ + { 0x0000, 0x0000, 0 }, /* R88 */ + { 0x0000, 0x0000, 0 }, /* R89 */ + { 0x00FF, 0x00FF, 0 }, /* R90 - Analogue HP 0 */ + { 0x0000, 0x0000, 0 }, /* R91 */ + { 0x0000, 0x0000, 0 }, /* R92 */ + { 0x0000, 0x0000, 0 }, /* R93 */ + { 0x00FF, 0x00FF, 0 }, /* R94 - Analogue Lineout 0 */ + { 0x0000, 0x0000, 0 }, /* R95 */ + { 0x0000, 0x0000, 0 }, /* R96 */ + { 0x0000, 0x0000, 0 }, /* R97 */ + { 0x0001, 0x0001, 0 }, /* R98 - Charge Pump 0 */ + { 0x0000, 0x0000, 0 }, /* R99 */ + { 0x0000, 0x0000, 0 }, /* R100 */ + { 0x0000, 0x0000, 0 }, /* R101 */ + { 0x0000, 0x0000, 0 }, /* R102 */ + { 0x0000, 0x0000, 0 }, /* R103 */ + { 0x0001, 0x0001, 0 }, /* R104 - Class W 0 */ + { 0x0000, 0x0000, 0 }, /* R105 */ + { 0x0000, 0x0000, 0 }, /* R106 */ + { 0x0000, 0x0000, 0 }, /* R107 */ + { 0x011F, 0x011F, 0 }, /* R108 - Write Sequencer 0 */ + { 0x7FFF, 0x7FFF, 0 }, /* R109 - Write Sequencer 1 */ + { 0x4FFF, 0x4FFF, 0 }, /* R110 - Write Sequencer 2 */ + { 0x003F, 0x033F, 0 }, /* R111 - Write Sequencer 3 */ + { 0x03F1, 0x0000, 0 }, /* R112 - Write Sequencer 4 */ + { 0x0000, 0x0000, 0 }, /* R113 */ + { 0x0000, 0x0000, 0 }, /* R114 */ + { 0x0000, 0x0000, 0 }, /* R115 */ + { 0x0007, 0x0007, 0 }, /* R116 - FLL Control 1 */ + { 0x3F77, 0x3F77, 0 }, /* R117 - FLL Control 2 */ + { 0xFFFF, 0xFFFF, 0 }, /* R118 - FLL Control 3 */ + { 0x7FEF, 0x7FEF, 0 }, /* R119 - FLL Control 4 */ + { 0x001B, 0x001B, 0 }, /* R120 - FLL Control 5 */ + { 0x003F, 0x003F, 0 }, /* R121 - GPIO Control 1 */ + { 0x003F, 0x003F, 0 }, /* R122 - GPIO Control 2 */ + { 0x003F, 0x003F, 0 }, /* R123 - GPIO Control 3 */ + { 0x038F, 0x038F, 0 }, /* R124 - GPIO Control 4 */ + { 0x0000, 0x0000, 0 }, /* R125 */ + { 0x00FF, 0x00FF, 0 }, /* R126 - Digital Pulls */ + { 0x07FF, 0x03FF, 1 }, /* R127 - Interrupt Status */ + { 0x03FF, 0x03FF, 0 }, /* R128 - Interrupt Status Mask */ + { 0x03FF, 0x03FF, 0 }, /* R129 - Interrupt Polarity */ + { 0x03FF, 0x03FF, 0 }, /* R130 - Interrupt Debounce */ + { 0x0000, 0x0000, 0 }, /* R131 */ + { 0x0000, 0x0000, 0 }, /* R132 */ + { 0x0000, 0x0000, 0 }, /* R133 */ + { 0x0001, 0x0001, 0 }, /* R134 - EQ1 */ + { 0x001F, 0x001F, 0 }, /* R135 - EQ2 */ + { 0x001F, 0x001F, 0 }, /* R136 - EQ3 */ + { 0x001F, 0x001F, 0 }, /* R137 - EQ4 */ + { 0x001F, 0x001F, 0 }, /* R138 - EQ5 */ + { 0x001F, 0x001F, 0 }, /* R139 - EQ6 */ + { 0xFFFF, 0xFFFF, 0 }, /* R140 - EQ7 */ + { 0xFFFF, 0xFFFF, 0 }, /* R141 - EQ8 */ + { 0xFFFF, 0xFFFF, 0 }, /* R142 - EQ9 */ + { 0xFFFF, 0xFFFF, 0 }, /* R143 - EQ10 */ + { 0xFFFF, 0xFFFF, 0 }, /* R144 - EQ11 */ + { 0xFFFF, 0xFFFF, 0 }, /* R145 - EQ12 */ + { 0xFFFF, 0xFFFF, 0 }, /* R146 - EQ13 */ + { 0xFFFF, 0xFFFF, 0 }, /* R147 - EQ14 */ + { 0xFFFF, 0xFFFF, 0 }, /* R148 - EQ15 */ + { 0xFFFF, 0xFFFF, 0 }, /* R149 - EQ16 */ + { 0xFFFF, 0xFFFF, 0 }, /* R150 - EQ17 */ + { 0xFFFF, 0xFFFF, 0 }, /* R151wm8523_dai - EQ18 */ + { 0xFFFF, 0xFFFF, 0 }, /* R152 - EQ19 */ + { 0xFFFF, 0xFFFF, 0 }, /* R153 - EQ20 */ + { 0xFFFF, 0xFFFF, 0 }, /* R154 - EQ21 */ + { 0xFFFF, 0xFFFF, 0 }, /* R155 - EQ22 */ + { 0xFFFF, 0xFFFF, 0 }, /* R156 - EQ23 */ + { 0xFFFF, 0xFFFF, 0 }, /* R157 - EQ24 */ + { 0x0000, 0x0000, 0 }, /* R158 */ + { 0x0000, 0x0000, 0 }, /* R159 */ + { 0x0000, 0x0000, 0 }, /* R160 */ + { 0x0002, 0x0002, 0 }, /* R161 - Control Interface Test 1 */ + { 0x0000, 0x0000, 0 }, /* R162 */ + { 0x0000, 0x0000, 0 }, /* R163 */ + { 0x0000, 0x0000, 0 }, /* R164 */ + { 0x0000, 0x0000, 0 }, /* R165 */ + { 0x0000, 0x0000, 0 }, /* R166 */ + { 0x0000, 0x0000, 0 }, /* R167 */ + { 0x0000, 0x0000, 0 }, /* R168 */ + { 0x0000, 0x0000, 0 }, /* R169 */ + { 0x0000, 0x0000, 0 }, /* R170 */ + { 0x0000, 0x0000, 0 }, /* R171 */ + { 0x0000, 0x0000, 0 }, /* R172 */ + { 0x0000, 0x0000, 0 }, /* R173 */ + { 0x0000, 0x0000, 0 }, /* R174 */ + { 0x0000, 0x0000, 0 }, /* R175 */ + { 0x0000, 0x0000, 0 }, /* R176 */ + { 0x0000, 0x0000, 0 }, /* R177 */ + { 0x0000, 0x0000, 0 }, /* R178 */ + { 0x0000, 0x0000, 0 }, /* R179 */ + { 0x0000, 0x0000, 0 }, /* R180 */ + { 0x0000, 0x0000, 0 }, /* R181 */ + { 0x0000, 0x0000, 0 }, /* R182 */ + { 0x0000, 0x0000, 0 }, /* R183 */ + { 0x0000, 0x0000, 0 }, /* R184 */ + { 0x0000, 0x0000, 0 }, /* R185 */ + { 0x0000, 0x0000, 0 }, /* R186 */ + { 0x0000, 0x0000, 0 }, /* R187 */ + { 0x0000, 0x0000, 0 }, /* R188 */ + { 0x0000, 0x0000, 0 }, /* R189 */ + { 0x0000, 0x0000, 0 }, /* R190 */ + { 0x0000, 0x0000, 0 }, /* R191 */ + { 0x0000, 0x0000, 0 }, /* R192 */ + { 0x0000, 0x0000, 0 }, /* R193 */ + { 0x0000, 0x0000, 0 }, /* R194 */ + { 0x0000, 0x0000, 0 }, /* R195 */ + { 0x0000, 0x0000, 0 }, /* R196 */ + { 0x0000, 0x0000, 0 }, /* R197 */ + { 0x0000, 0x0000, 0 }, /* R198 */ + { 0x0000, 0x0000, 0 }, /* R199 */ + { 0x0000, 0x0000, 0 }, /* R200 */ + { 0x0000, 0x0000, 0 }, /* R201 */ + { 0x0000, 0x0000, 0 }, /* R202 */ + { 0x0000, 0x0000, 0 }, /* R203 */ + { 0x0070, 0x0070, 0 }, /* R204 - Analogue Output Bias 0 */ + { 0x0000, 0x0000, 0 }, /* R205 */ + { 0x0000, 0x0000, 0 }, /* R206 */ + { 0x0000, 0x0000, 0 }, /* R207 */ + { 0x0000, 0x0000, 0 }, /* R208 */ + { 0x0000, 0x0000, 0 }, /* R209 */ + { 0x0000, 0x0000, 0 }, /* R210 */ + { 0x0000, 0x0000, 0 }, /* R211 */ + { 0x0000, 0x0000, 0 }, /* R212 */ + { 0x0000, 0x0000, 0 }, /* R213 */ + { 0x0000, 0x0000, 0 }, /* R214 */ + { 0x0000, 0x0000, 0 }, /* R215 */ + { 0x0000, 0x0000, 0 }, /* R216 */ + { 0x0000, 0x0000, 0 }, /* R217 */ + { 0x0000, 0x0000, 0 }, /* R218 */ + { 0x0000, 0x0000, 0 }, /* R219 */ + { 0x0000, 0x0000, 0 }, /* R220 */ + { 0x0000, 0x0000, 0 }, /* R221 */ + { 0x0000, 0x0000, 0 }, /* R222 */ + { 0x0000, 0x0000, 0 }, /* R223 */ + { 0x0000, 0x0000, 0 }, /* R224 */ + { 0x0000, 0x0000, 0 }, /* R225 */ + { 0x0000, 0x0000, 0 }, /* R226 */ + { 0x0000, 0x0000, 0 }, /* R227 */ + { 0x0000, 0x0000, 0 }, /* R228 */ + { 0x0000, 0x0000, 0 }, /* R229 */ + { 0x0000, 0x0000, 0 }, /* R230 */ + { 0x0000, 0x0000, 0 }, /* R231 */ + { 0x0000, 0x0000, 0 }, /* R232 */ + { 0x0000, 0x0000, 0 }, /* R233 */ + { 0x0000, 0x0000, 0 }, /* R234 */ + { 0x0000, 0x0000, 0 }, /* R235 */ + { 0x0000, 0x0000, 0 }, /* R236 */ + { 0x0000, 0x0000, 0 }, /* R237 */ + { 0x0000, 0x0000, 0 }, /* R238 */ + { 0x0000, 0x0000, 0 }, /* R239 */ + { 0x0000, 0x0000, 0 }, /* R240 */ + { 0x0000, 0x0000, 0 }, /* R241 */ + { 0x0000, 0x0000, 0 }, /* R242 */ + { 0x0000, 0x0000, 0 }, /* R243 */ + { 0x0000, 0x0000, 0 }, /* R244 */ + { 0x0000, 0x0000, 0 }, /* R245 */ + { 0x0000, 0x0000, 0 }, /* R246 */ + { 0x0001, 0x0001, 0 }, /* R247 - FLL NCO Test 0 */ + { 0x003F, 0x003F, 0 }, /* R248 - FLL NCO Test 1 */ +}; + +static int wm8904_volatile_register(unsigned int reg) +{ + return wm8904_access[reg].vol; +} + +static int wm8904_reset(struct snd_soc_codec *codec) +{ + return snd_soc_write(codec, WM8904_SW_RESET_AND_ID, 0); +} + +static int wm8904_configure_clocking(struct snd_soc_codec *codec) +{ + struct wm8904_priv *wm8904 = codec->private_data; + unsigned int clock0, clock2, rate; + + /* Gate the clock while we're updating to avoid misclocking */ + clock2 = snd_soc_read(codec, WM8904_CLOCK_RATES_2); + snd_soc_update_bits(codec, WM8904_CLOCK_RATES_2, + WM8904_SYSCLK_SRC, 0); + + /* This should be done on init() for bypass paths */ + switch (wm8904->sysclk_src) { + case WM8904_CLK_MCLK: + dev_dbg(codec->dev, "Using %dHz MCLK\n", wm8904->mclk_rate); + + clock2 &= ~WM8904_SYSCLK_SRC; + rate = wm8904->mclk_rate; + + /* Ensure the FLL is stopped */ + snd_soc_update_bits(codec, WM8904_FLL_CONTROL_1, + WM8904_FLL_OSC_ENA | WM8904_FLL_ENA, 0); + break; + + case WM8904_CLK_FLL: + dev_dbg(codec->dev, "Using %dHz FLL clock\n", + wm8904->fll_fout); + + clock2 |= WM8904_SYSCLK_SRC; + rate = wm8904->fll_fout; + break; + + default: + dev_err(codec->dev, "System clock not configured\n"); + return -EINVAL; + } + + /* SYSCLK shouldn't be over 13.5MHz */ + if (rate > 13500000) { + clock0 = WM8904_MCLK_DIV; + wm8904->sysclk_rate = rate / 2; + } else { + clock0 = 0; + wm8904->sysclk_rate = rate; + } + + snd_soc_update_bits(codec, WM8904_CLOCK_RATES_0, WM8904_MCLK_DIV, + clock0); + + snd_soc_update_bits(codec, WM8904_CLOCK_RATES_2, + WM8904_CLK_SYS_ENA | WM8904_SYSCLK_SRC, clock2); + + dev_dbg(codec->dev, "CLK_SYS is %dHz\n", wm8904->sysclk_rate); + + return 0; +} + +static void wm8904_set_drc(struct snd_soc_codec *codec) +{ + struct wm8904_priv *wm8904 = codec->private_data; + struct wm8904_pdata *pdata = wm8904->pdata; + int save, i; + + /* Save any enables; the configuration should clear them. */ + save = snd_soc_read(codec, WM8904_DRC_0); + + for (i = 0; i < WM8904_DRC_REGS; i++) + snd_soc_update_bits(codec, WM8904_DRC_0 + i, 0xffff, + pdata->drc_cfgs[wm8904->drc_cfg].regs[i]); + + /* Reenable the DRC */ + snd_soc_update_bits(codec, WM8904_DRC_0, + WM8904_DRC_ENA | WM8904_DRC_DAC_PATH, save); +} + +static int wm8904_put_drc_enum(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct wm8904_priv *wm8904 = codec->private_data; + struct wm8904_pdata *pdata = wm8904->pdata; + int value = ucontrol->value.integer.value[0]; + + if (value >= pdata->num_drc_cfgs) + return -EINVAL; + + wm8904->drc_cfg = value; + + wm8904_set_drc(codec); + + return 0; +} + +static int wm8904_get_drc_enum(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct wm8904_priv *wm8904 = codec->private_data; + + ucontrol->value.enumerated.item[0] = wm8904->drc_cfg; + + return 0; +} + +static void wm8904_set_retune_mobile(struct snd_soc_codec *codec) +{ + struct wm8904_priv *wm8904 = codec->private_data; + struct wm8904_pdata *pdata = wm8904->pdata; + int best, best_val, save, i, cfg; + + if (!pdata || !wm8904->num_retune_mobile_texts) + return; + + /* Find the version of the currently selected configuration + * with the nearest sample rate. */ + cfg = wm8904->retune_mobile_cfg; + best = 0; + best_val = INT_MAX; + for (i = 0; i < pdata->num_retune_mobile_cfgs; i++) { + if (strcmp(pdata->retune_mobile_cfgs[i].name, + wm8904->retune_mobile_texts[cfg]) == 0 && + abs(pdata->retune_mobile_cfgs[i].rate + - wm8904->fs) < best_val) { + best = i; + best_val = abs(pdata->retune_mobile_cfgs[i].rate + - wm8904->fs); + } + } + + dev_dbg(codec->dev, "ReTune Mobile %s/%dHz for %dHz sample rate\n", + pdata->retune_mobile_cfgs[best].name, + pdata->retune_mobile_cfgs[best].rate, + wm8904->fs); + + /* The EQ will be disabled while reconfiguring it, remember the + * current configuration. + */ + save = snd_soc_read(codec, WM8904_EQ1); + + for (i = 0; i < WM8904_EQ_REGS; i++) + snd_soc_update_bits(codec, WM8904_EQ1 + i, 0xffff, + pdata->retune_mobile_cfgs[best].regs[i]); + + snd_soc_update_bits(codec, WM8904_EQ1, WM8904_EQ_ENA, save); +} + +static int wm8904_put_retune_mobile_enum(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct wm8904_priv *wm8904 = codec->private_data; + struct wm8904_pdata *pdata = wm8904->pdata; + int value = ucontrol->value.integer.value[0]; + + if (value >= pdata->num_retune_mobile_cfgs) + return -EINVAL; + + wm8904->retune_mobile_cfg = value; + + wm8904_set_retune_mobile(codec); + + return 0; +} + +static int wm8904_get_retune_mobile_enum(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct wm8904_priv *wm8904 = codec->private_data; + + ucontrol->value.enumerated.item[0] = wm8904->retune_mobile_cfg; + + return 0; +} + +static int deemph_settings[] = { 0, 32000, 44100, 48000 }; + +static int wm8904_set_deemph(struct snd_soc_codec *codec) +{ + struct wm8904_priv *wm8904 = codec->private_data; + int val, i, best; + + /* If we're using deemphasis select the nearest available sample + * rate. + */ + if (wm8904->deemph) { + best = 1; + for (i = 2; i < ARRAY_SIZE(deemph_settings); i++) { + if (abs(deemph_settings[i] - wm8904->fs) < + abs(deemph_settings[best] - wm8904->fs)) + best = i; + } + + val = best << WM8904_DEEMPH_SHIFT; + } else { + val = 0; + } + + dev_dbg(codec->dev, "Set deemphasis %d\n", val); + + return snd_soc_update_bits(codec, WM8904_DAC_DIGITAL_1, + WM8904_DEEMPH_MASK, val); +} + +static int wm8904_get_deemph(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct wm8904_priv *wm8904 = codec->private_data; + + return wm8904->deemph; +} + +static int wm8904_put_deemph(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct wm8904_priv *wm8904 = codec->private_data; + int deemph = ucontrol->value.enumerated.item[0]; + + if (deemph > 1) + return -EINVAL; + + wm8904->deemph = deemph; + + return wm8904_set_deemph(codec); +} + +static const DECLARE_TLV_DB_SCALE(dac_boost_tlv, 0, 600, 0); +static const DECLARE_TLV_DB_SCALE(digital_tlv, -7200, 75, 1); +static const DECLARE_TLV_DB_SCALE(out_tlv, -5700, 100, 0); +static const DECLARE_TLV_DB_SCALE(sidetone_tlv, -3600, 300, 0); +static const DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0); + +static const char *input_mode_text[] = { + "Single-Ended", "Differential Line", "Differential Mic" +}; + +static const struct soc_enum lin_mode = + SOC_ENUM_SINGLE(WM8904_ANALOGUE_LEFT_INPUT_1, 0, 3, input_mode_text); + +static const struct soc_enum rin_mode = + SOC_ENUM_SINGLE(WM8904_ANALOGUE_RIGHT_INPUT_1, 0, 3, input_mode_text); + +static const char *hpf_mode_text[] = { + "Hi-fi", "Voice 1", "Voice 2", "Voice 3" +}; + +static const struct soc_enum hpf_mode = + SOC_ENUM_SINGLE(WM8904_ADC_DIGITAL_0, 5, 4, hpf_mode_text); + +static const struct snd_kcontrol_new wm8904_adc_snd_controls[] = { +SOC_DOUBLE_R_TLV("Digital Capture Volume", WM8904_ADC_DIGITAL_VOLUME_LEFT, + WM8904_ADC_DIGITAL_VOLUME_RIGHT, 1, 119, 0, digital_tlv), + +SOC_ENUM("Left Caputure Mode", lin_mode), +SOC_ENUM("Right Capture Mode", rin_mode), + +/* No TLV since it depends on mode */ +SOC_DOUBLE_R("Capture Volume", WM8904_ANALOGUE_LEFT_INPUT_0, + WM8904_ANALOGUE_RIGHT_INPUT_0, 0, 31, 0), +SOC_DOUBLE_R("Capture Switch", WM8904_ANALOGUE_LEFT_INPUT_0, + WM8904_ANALOGUE_RIGHT_INPUT_0, 7, 1, 0), + +SOC_SINGLE("High Pass Filter Switch", WM8904_ADC_DIGITAL_0, 4, 1, 0), +SOC_ENUM("High Pass Filter Mode", hpf_mode), + +SOC_SINGLE("ADC 128x OSR Switch", WM8904_ANALOGUE_ADC_0, 0, 1, 0), +}; + +static const char *drc_path_text[] = { + "ADC", "DAC" +}; + +static const struct soc_enum drc_path = + SOC_ENUM_SINGLE(WM8904_DRC_0, 14, 2, drc_path_text); + +static const struct snd_kcontrol_new wm8904_dac_snd_controls[] = { +SOC_SINGLE_TLV("Digital Playback Boost Volume", + WM8904_AUDIO_INTERFACE_0, 9, 3, 0, dac_boost_tlv), +SOC_DOUBLE_R_TLV("Digital Playback Volume", WM8904_DAC_DIGITAL_VOLUME_LEFT, + WM8904_DAC_DIGITAL_VOLUME_RIGHT, 1, 96, 0, digital_tlv), + +SOC_DOUBLE_R_TLV("Headphone Volume", WM8904_ANALOGUE_OUT1_LEFT, + WM8904_ANALOGUE_OUT1_RIGHT, 0, 63, 0, out_tlv), +SOC_DOUBLE_R("Headphone Switch", WM8904_ANALOGUE_OUT1_LEFT, + WM8904_ANALOGUE_OUT1_RIGHT, 8, 1, 1), +SOC_DOUBLE_R("Headphone ZC Switch", WM8904_ANALOGUE_OUT1_LEFT, + WM8904_ANALOGUE_OUT1_RIGHT, 6, 1, 0), + +SOC_DOUBLE_R_TLV("Line Output Volume", WM8904_ANALOGUE_OUT2_LEFT, + WM8904_ANALOGUE_OUT2_RIGHT, 0, 63, 0, out_tlv), +SOC_DOUBLE_R("Line Output Switch", WM8904_ANALOGUE_OUT2_LEFT, + WM8904_ANALOGUE_OUT2_RIGHT, 8, 1, 1), +SOC_DOUBLE_R("Line Output ZC Switch", WM8904_ANALOGUE_OUT2_LEFT, + WM8904_ANALOGUE_OUT2_RIGHT, 6, 1, 0), + +SOC_SINGLE("EQ Switch", WM8904_EQ1, 0, 1, 0), +SOC_SINGLE("DRC Switch", WM8904_DRC_0, 15, 1, 0), +SOC_ENUM("DRC Path", drc_path), +SOC_SINGLE("DAC OSRx2 Switch", WM8904_DAC_DIGITAL_1, 6, 1, 0), +SOC_SINGLE_BOOL_EXT("DAC Deemphasis Switch", 0, + wm8904_get_deemph, wm8904_put_deemph), +}; + +static const struct snd_kcontrol_new wm8904_snd_controls[] = { +SOC_DOUBLE_TLV("Digital Sidetone Volume", WM8904_DAC_DIGITAL_0, 4, 8, 15, 0, + sidetone_tlv), +}; + +static const struct snd_kcontrol_new wm8904_eq_controls[] = { +SOC_SINGLE_TLV("EQ1 Volume", WM8904_EQ2, 0, 24, 0, eq_tlv), +SOC_SINGLE_TLV("EQ2 Volume", WM8904_EQ3, 0, 24, 0, eq_tlv), +SOC_SINGLE_TLV("EQ3 Volume", WM8904_EQ4, 0, 24, 0, eq_tlv), +SOC_SINGLE_TLV("EQ4 Volume", WM8904_EQ5, 0, 24, 0, eq_tlv), +SOC_SINGLE_TLV("EQ5 Volume", WM8904_EQ6, 0, 24, 0, eq_tlv), +}; + +static int cp_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + BUG_ON(event != SND_SOC_DAPM_POST_PMU); + + /* Maximum startup time */ + udelay(500); + + return 0; +} + +static int sysclk_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = w->codec; < |
