Commit 6d4baf08 authored by Mark Brown's avatar Mark Brown

ASoC: Add WM5100 driver

The WM5100 is a highly integrated low power audio subsystem with advanced
digital signal processing capabilities including effects, speech clarity
enhancement and active noise cancellation.  This initial driver provides
support for basic audio paths, further patches will provide more
complete functionality.
Signed-off-by: default avatarMark Brown <broonie@opensource.wolfsonmicro.com>
Acked-by: default avatarLiam Girdwood <lrg@ti.com>
parent f648de83
/*
* linux/sound/wm5100.h -- Platform data for WM5100
*
* Copyright 2011 Wolfson Microelectronics. PLC.
*
* 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.
*/
#ifndef __LINUX_SND_WM5100_H
#define __LINUX_SND_WM5100_H
enum wm5100_in_mode {
WM5100_IN_SE = 0,
WM5100_IN_DIFF = 1,
WM5100_IN_DMIC = 2,
};
enum wm5100_dmic_sup {
WM5100_DMIC_SUP_MICVDD = 0,
WM5100_DMIC_SUP_MICBIAS1 = 1,
WM5100_DMIC_SUP_MICBIAS2 = 2,
WM5100_DMIC_SUP_MICBIAS3 = 3,
};
enum wm5100_micdet_bias {
WM5100_MICDET_MICBIAS1 = 0,
WM5100_MICDET_MICBIAS2 = 1,
WM5100_MICDET_MICBIAS3 = 2,
};
struct wm5100_jack_mode {
enum wm5100_micdet_bias bias;
int hp_pol;
int micd_src;
};
#define WM5100_GPIO_SET 0x10000
struct wm5100_pdata {
int reset; /** GPIO controlling /RESET, if any */
int ldo_ena; /** GPIO controlling LODENA, if any */
int hp_pol; /** GPIO controlling headset polarity, if any */
int irq_flags;
int gpio_base;
struct wm5100_jack_mode jack_modes[2];
/* Input pin mode selection */
enum wm5100_in_mode in_mode[4];
/* DMIC supply selection */
enum wm5100_dmic_sup dmic_sup[4];
int gpio_defaults[6];
};
#endif
...@@ -59,6 +59,7 @@ config SND_SOC_ALL_CODECS ...@@ -59,6 +59,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_WL1273 if MFD_WL1273_CORE select SND_SOC_WL1273 if MFD_WL1273_CORE
select SND_SOC_WM1250_EV1 if I2C select SND_SOC_WM1250_EV1 if I2C
select SND_SOC_WM2000 if I2C select SND_SOC_WM2000 if I2C
select SND_SOC_WM5100 if I2C
select SND_SOC_WM8350 if MFD_WM8350 select SND_SOC_WM8350 if MFD_WM8350
select SND_SOC_WM8400 if MFD_WM8400 select SND_SOC_WM8400 if MFD_WM8400
select SND_SOC_WM8510 if SND_SOC_I2C_AND_SPI select SND_SOC_WM8510 if SND_SOC_I2C_AND_SPI
...@@ -273,6 +274,9 @@ config SND_SOC_WL1273 ...@@ -273,6 +274,9 @@ config SND_SOC_WL1273
config SND_SOC_WM1250_EV1 config SND_SOC_WM1250_EV1
tristate tristate
config SND_SOC_WM5100
tristate
config SND_SOC_WM8350 config SND_SOC_WM8350
tristate tristate
......
...@@ -44,6 +44,7 @@ snd-soc-uda134x-objs := uda134x.o ...@@ -44,6 +44,7 @@ snd-soc-uda134x-objs := uda134x.o
snd-soc-uda1380-objs := uda1380.o snd-soc-uda1380-objs := uda1380.o
snd-soc-wl1273-objs := wl1273.o snd-soc-wl1273-objs := wl1273.o
snd-soc-wm1250-ev1-objs := wm1250-ev1.o snd-soc-wm1250-ev1-objs := wm1250-ev1.o
snd-soc-wm5100-objs := wm5100.o wm5100-tables.o
snd-soc-wm8350-objs := wm8350.o snd-soc-wm8350-objs := wm8350.o
snd-soc-wm8400-objs := wm8400.o snd-soc-wm8400-objs := wm8400.o
snd-soc-wm8510-objs := wm8510.o snd-soc-wm8510-objs := wm8510.o
...@@ -142,6 +143,7 @@ obj-$(CONFIG_SND_SOC_UDA134X) += snd-soc-uda134x.o ...@@ -142,6 +143,7 @@ obj-$(CONFIG_SND_SOC_UDA134X) += snd-soc-uda134x.o
obj-$(CONFIG_SND_SOC_UDA1380) += snd-soc-uda1380.o obj-$(CONFIG_SND_SOC_UDA1380) += snd-soc-uda1380.o
obj-$(CONFIG_SND_SOC_WL1273) += snd-soc-wl1273.o obj-$(CONFIG_SND_SOC_WL1273) += snd-soc-wl1273.o
obj-$(CONFIG_SND_SOC_WM1250_EV1) += snd-soc-wm1250-ev1.o obj-$(CONFIG_SND_SOC_WM1250_EV1) += snd-soc-wm1250-ev1.o
obj-$(CONFIG_SND_SOC_WM5100) += snd-soc-wm5100.o
obj-$(CONFIG_SND_SOC_WM8350) += snd-soc-wm8350.o obj-$(CONFIG_SND_SOC_WM8350) += snd-soc-wm8350.o
obj-$(CONFIG_SND_SOC_WM8400) += snd-soc-wm8400.o obj-$(CONFIG_SND_SOC_WM8400) += snd-soc-wm8400.o
obj-$(CONFIG_SND_SOC_WM8510) += snd-soc-wm8510.o obj-$(CONFIG_SND_SOC_WM8510) += snd-soc-wm8510.o
......
/*
* wm5100-tables.c -- WM5100 ALSA SoC Audio driver data
*
* Copyright 2011 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 "wm5100.h"
int wm5100_volatile_register(struct snd_soc_codec *codec, unsigned int reg)
{
switch (reg) {
case WM5100_SOFTWARE_RESET:
case WM5100_DEVICE_REVISION:
case WM5100_FX_CTRL:
case WM5100_INTERRUPT_STATUS_1:
case WM5100_INTERRUPT_STATUS_2:
case WM5100_INTERRUPT_STATUS_3:
case WM5100_INTERRUPT_STATUS_4:
case WM5100_INTERRUPT_RAW_STATUS_2:
case WM5100_INTERRUPT_RAW_STATUS_3:
case WM5100_INTERRUPT_RAW_STATUS_4:
case WM5100_OUTPUT_STATUS_1:
case WM5100_OUTPUT_STATUS_2:
case WM5100_INPUT_ENABLES_STATUS:
case WM5100_MIC_DETECT_3:
return 1;
default:
return 0;
}
}
int wm5100_readable_register(struct snd_soc_codec *codec, unsigned int reg)
{
switch (reg) {
case WM5100_SOFTWARE_RESET:
case WM5100_DEVICE_REVISION:
case WM5100_CTRL_IF_1:
case WM5100_TONE_GENERATOR_1:
case WM5100_PWM_DRIVE_1:
case WM5100_PWM_DRIVE_2:
case WM5100_PWM_DRIVE_3:
case WM5100_CLOCKING_1:
case WM5100_CLOCKING_3:
case WM5100_CLOCKING_4:
case WM5100_CLOCKING_5:
case WM5100_CLOCKING_6:
case WM5100_CLOCKING_7:
case WM5100_CLOCKING_8:
case WM5100_ASRC_ENABLE:
case WM5100_ASRC_STATUS:
case WM5100_ASRC_RATE1:
case WM5100_ISRC_1_CTRL_1:
case WM5100_ISRC_1_CTRL_2:
case WM5100_ISRC_2_CTRL1:
case WM5100_ISRC_2_CTRL_2:
case WM5100_FLL1_CONTROL_1:
case WM5100_FLL1_CONTROL_2:
case WM5100_FLL1_CONTROL_3:
case WM5100_FLL1_CONTROL_5:
case WM5100_FLL1_CONTROL_6:
case WM5100_FLL1_EFS_1:
case WM5100_FLL2_CONTROL_1:
case WM5100_FLL2_CONTROL_2:
case WM5100_FLL2_CONTROL_3:
case WM5100_FLL2_CONTROL_5:
case WM5100_FLL2_CONTROL_6:
case WM5100_FLL2_EFS_1:
case WM5100_MIC_CHARGE_PUMP_1:
case WM5100_MIC_CHARGE_PUMP_2:
case WM5100_HP_CHARGE_PUMP_1:
case WM5100_LDO1_CONTROL:
case WM5100_MIC_BIAS_CTRL_1:
case WM5100_MIC_BIAS_CTRL_2:
case WM5100_MIC_BIAS_CTRL_3:
case WM5100_ACCESSORY_DETECT_MODE_1:
case WM5100_HEADPHONE_DETECT_1:
case WM5100_HEADPHONE_DETECT_2:
case WM5100_MIC_DETECT_1:
case WM5100_MIC_DETECT_2:
case WM5100_MIC_DETECT_3:
case WM5100_INPUT_ENABLES:
case WM5100_INPUT_ENABLES_STATUS:
case WM5100_IN1L_CONTROL:
case WM5100_IN1R_CONTROL:
case WM5100_IN2L_CONTROL:
case WM5100_IN2R_CONTROL:
case WM5100_IN3L_CONTROL:
case WM5100_IN3R_CONTROL:
case WM5100_IN4L_CONTROL:
case WM5100_IN4R_CONTROL:
case WM5100_RXANC_SRC:
case WM5100_INPUT_VOLUME_RAMP:
case WM5100_ADC_DIGITAL_VOLUME_1L:
case WM5100_ADC_DIGITAL_VOLUME_1R:
case WM5100_ADC_DIGITAL_VOLUME_2L:
case WM5100_ADC_DIGITAL_VOLUME_2R:
case WM5100_ADC_DIGITAL_VOLUME_3L:
case WM5100_ADC_DIGITAL_VOLUME_3R:
case WM5100_ADC_DIGITAL_VOLUME_4L:
case WM5100_ADC_DIGITAL_VOLUME_4R:
case WM5100_OUTPUT_ENABLES_2:
case WM5100_OUTPUT_STATUS_1:
case WM5100_OUTPUT_STATUS_2:
case WM5100_CHANNEL_ENABLES_1:
case WM5100_OUT_VOLUME_1L:
case WM5100_OUT_VOLUME_1R:
case WM5100_DAC_VOLUME_LIMIT_1L:
case WM5100_DAC_VOLUME_LIMIT_1R:
case WM5100_OUT_VOLUME_2L:
case WM5100_OUT_VOLUME_2R:
case WM5100_DAC_VOLUME_LIMIT_2L:
case WM5100_DAC_VOLUME_LIMIT_2R:
case WM5100_OUT_VOLUME_3L:
case WM5100_OUT_VOLUME_3R:
case WM5100_DAC_VOLUME_LIMIT_3L:
case WM5100_DAC_VOLUME_LIMIT_3R:
case WM5100_OUT_VOLUME_4L:
case WM5100_OUT_VOLUME_4R:
case WM5100_DAC_VOLUME_LIMIT_5L:
case WM5100_DAC_VOLUME_LIMIT_5R:
case WM5100_DAC_VOLUME_LIMIT_6L:
case WM5100_DAC_VOLUME_LIMIT_6R:
case WM5100_DAC_AEC_CONTROL_1:
case WM5100_OUTPUT_VOLUME_RAMP:
case WM5100_DAC_DIGITAL_VOLUME_1L:
case WM5100_DAC_DIGITAL_VOLUME_1R:
case WM5100_DAC_DIGITAL_VOLUME_2L:
case WM5100_DAC_DIGITAL_VOLUME_2R:
case WM5100_DAC_DIGITAL_VOLUME_3L:
case WM5100_DAC_DIGITAL_VOLUME_3R:
case WM5100_DAC_DIGITAL_VOLUME_4L:
case WM5100_DAC_DIGITAL_VOLUME_4R:
case WM5100_DAC_DIGITAL_VOLUME_5L:
case WM5100_DAC_DIGITAL_VOLUME_5R:
case WM5100_DAC_DIGITAL_VOLUME_6L:
case WM5100_DAC_DIGITAL_VOLUME_6R:
case WM5100_PDM_SPK1_CTRL_1:
case WM5100_PDM_SPK1_CTRL_2:
case WM5100_PDM_SPK2_CTRL_1:
case WM5100_PDM_SPK2_CTRL_2:
case WM5100_AUDIO_IF_1_1:
case WM5100_AUDIO_IF_1_2:
case WM5100_AUDIO_IF_1_3:
case WM5100_AUDIO_IF_1_4:
case WM5100_AUDIO_IF_1_5:
case WM5100_AUDIO_IF_1_6:
case WM5100_AUDIO_IF_1_7:
case WM5100_AUDIO_IF_1_8:
case WM5100_AUDIO_IF_1_9:
case WM5100_AUDIO_IF_1_10:
case WM5100_AUDIO_IF_1_11:
case WM5100_AUDIO_IF_1_12:
case WM5100_AUDIO_IF_1_13:
case WM5100_AUDIO_IF_1_14:
case WM5100_AUDIO_IF_1_15:
case WM5100_AUDIO_IF_1_16:
case WM5100_AUDIO_IF_1_17:
case WM5100_AUDIO_IF_1_18:
case WM5100_AUDIO_IF_1_19:
case WM5100_AUDIO_IF_1_20:
case WM5100_AUDIO_IF_1_21:
case WM5100_AUDIO_IF_1_22:
case WM5100_AUDIO_IF_1_23:
case WM5100_AUDIO_IF_1_24:
case WM5100_AUDIO_IF_1_25:
case WM5100_AUDIO_IF_1_26:
case WM5100_AUDIO_IF_1_27:
case WM5100_AUDIO_IF_2_1:
case WM5100_AUDIO_IF_2_2:
case WM5100_AUDIO_IF_2_3:
case WM5100_AUDIO_IF_2_4:
case WM5100_AUDIO_IF_2_5:
case WM5100_AUDIO_IF_2_6:
case WM5100_AUDIO_IF_2_7:
case WM5100_AUDIO_IF_2_8:
case WM5100_AUDIO_IF_2_9:
case WM5100_AUDIO_IF_2_10:
case WM5100_AUDIO_IF_2_11:
case WM5100_AUDIO_IF_2_18:
case WM5100_AUDIO_IF_2_19:
case WM5100_AUDIO_IF_2_26:
case WM5100_AUDIO_IF_2_27:
case WM5100_AUDIO_IF_3_1:
case WM5100_AUDIO_IF_3_2:
case WM5100_AUDIO_IF_3_3:
case WM5100_AUDIO_IF_3_4:
case WM5100_AUDIO_IF_3_5:
case WM5100_AUDIO_IF_3_6:
case WM5100_AUDIO_IF_3_7:
case WM5100_AUDIO_IF_3_8:
case WM5100_AUDIO_IF_3_9:
case WM5100_AUDIO_IF_3_10:
case WM5100_AUDIO_IF_3_11:
case WM5100_AUDIO_IF_3_18:
case WM5100_AUDIO_IF_3_19:
case WM5100_AUDIO_IF_3_26:
case WM5100_AUDIO_IF_3_27:
case WM5100_PWM1MIX_INPUT_1_SOURCE:
case WM5100_PWM1MIX_INPUT_1_VOLUME:
case WM5100_PWM1MIX_INPUT_2_SOURCE:
case WM5100_PWM1MIX_INPUT_2_VOLUME:
case WM5100_PWM1MIX_INPUT_3_SOURCE:
case WM5100_PWM1MIX_INPUT_3_VOLUME:
case WM5100_PWM1MIX_INPUT_4_SOURCE:
case WM5100_PWM1MIX_INPUT_4_VOLUME:
case WM5100_PWM2MIX_INPUT_1_SOURCE:
case WM5100_PWM2MIX_INPUT_1_VOLUME:
case WM5100_PWM2MIX_INPUT_2_SOURCE:
case WM5100_PWM2MIX_INPUT_2_VOLUME:
case WM5100_PWM2MIX_INPUT_3_SOURCE:
case WM5100_PWM2MIX_INPUT_3_VOLUME:
case WM5100_PWM2MIX_INPUT_4_SOURCE:
case WM5100_PWM2MIX_INPUT_4_VOLUME:
case WM5100_OUT1LMIX_INPUT_1_SOURCE:
case WM5100_OUT1LMIX_INPUT_1_VOLUME:
case WM5100_OUT1LMIX_INPUT_2_SOURCE:
case WM5100_OUT1LMIX_INPUT_2_VOLUME:
case WM5100_OUT1LMIX_INPUT_3_SOURCE:
case WM5100_OUT1LMIX_INPUT_3_VOLUME:
case WM5100_OUT1LMIX_INPUT_4_SOURCE:
case WM5100_OUT1LMIX_INPUT_4_VOLUME:
case WM5100_OUT1RMIX_INPUT_1_SOURCE:
case WM5100_OUT1RMIX_INPUT_1_VOLUME:
case WM5100_OUT1RMIX_INPUT_2_SOURCE:
case WM5100_OUT1RMIX_INPUT_2_VOLUME:
case WM5100_OUT1RMIX_INPUT_3_SOURCE:
case WM5100_OUT1RMIX_INPUT_3_VOLUME:
case WM5100_OUT1RMIX_INPUT_4_SOURCE:
case WM5100_OUT1RMIX_INPUT_4_VOLUME:
case WM5100_OUT2LMIX_INPUT_1_SOURCE:
case WM5100_OUT2LMIX_INPUT_1_VOLUME:
case WM5100_OUT2LMIX_INPUT_2_SOURCE:
case WM5100_OUT2LMIX_INPUT_2_VOLUME:
case WM5100_OUT2LMIX_INPUT_3_SOURCE:
case WM5100_OUT2LMIX_INPUT_3_VOLUME:
case WM5100_OUT2LMIX_INPUT_4_SOURCE:
case WM5100_OUT2LMIX_INPUT_4_VOLUME:
case WM5100_OUT2RMIX_INPUT_1_SOURCE:
case WM5100_OUT2RMIX_INPUT_1_VOLUME:
case WM5100_OUT2RMIX_INPUT_2_SOURCE:
case WM5100_OUT2RMIX_INPUT_2_VOLUME:
case WM5100_OUT2RMIX_INPUT_3_SOURCE:
case WM5100_OUT2RMIX_INPUT_3_VOLUME:
case WM5100_OUT2RMIX_INPUT_4_SOURCE:
case WM5100_OUT2RMIX_INPUT_4_VOLUME:
case WM5100_OUT3LMIX_INPUT_1_SOURCE:
case WM5100_OUT3LMIX_INPUT_1_VOLUME:
case WM5100_OUT3LMIX_INPUT_2_SOURCE:
case WM5100_OUT3LMIX_INPUT_2_VOLUME:
case WM5100_OUT3LMIX_INPUT_3_SOURCE:
case WM5100_OUT3LMIX_INPUT_3_VOLUME:
case WM5100_OUT3LMIX_INPUT_4_SOURCE:
case WM5100_OUT3LMIX_INPUT_4_VOLUME:
case WM5100_OUT3RMIX_INPUT_1_SOURCE:
case WM5100_OUT3RMIX_INPUT_1_VOLUME:
case WM5100_OUT3RMIX_INPUT_2_SOURCE:
case WM5100_OUT3RMIX_INPUT_2_VOLUME:
case WM5100_OUT3RMIX_INPUT_3_SOURCE:
case WM5100_OUT3RMIX_INPUT_3_VOLUME:
case WM5100_OUT3RMIX_INPUT_4_SOURCE:
case WM5100_OUT3RMIX_INPUT_4_VOLUME:
case WM5100_OUT4LMIX_INPUT_1_SOURCE:
case WM5100_OUT4LMIX_INPUT_1_VOLUME:
case WM5100_OUT4LMIX_INPUT_2_SOURCE:
case WM5100_OUT4LMIX_INPUT_2_VOLUME:
case WM5100_OUT4LMIX_INPUT_3_SOURCE:
case WM5100_OUT4LMIX_INPUT_3_VOLUME:
case WM5100_OUT4LMIX_INPUT_4_SOURCE:
case WM5100_OUT4LMIX_INPUT_4_VOLUME:
case WM5100_OUT4RMIX_INPUT_1_SOURCE:
case WM5100_OUT4RMIX_INPUT_1_VOLUME:
case WM5100_OUT4RMIX_INPUT_2_SOURCE:
case WM5100_OUT4RMIX_INPUT_2_VOLUME:
case WM5100_OUT4RMIX_INPUT_3_SOURCE:
case WM5100_OUT4RMIX_INPUT_3_VOLUME:
case WM5100_OUT4RMIX_INPUT_4_SOURCE:
case WM5100_OUT4RMIX_INPUT_4_VOLUME:
case WM5100_OUT5LMIX_INPUT_1_SOURCE:
case WM5100_OUT5LMIX_INPUT_1_VOLUME:
case WM5100_OUT5LMIX_INPUT_2_SOURCE:
case WM5100_OUT5LMIX_INPUT_2_VOLUME:
case WM5100_OUT5LMIX_INPUT_3_SOURCE:
case WM5100_OUT5LMIX_INPUT_3_VOLUME:
case WM5100_OUT5LMIX_INPUT_4_SOURCE:
case WM5100_OUT5LMIX_INPUT_4_VOLUME:
case WM5100_OUT5RMIX_INPUT_1_SOURCE:
case WM5100_OUT5RMIX_INPUT_1_VOLUME:
case WM5100_OUT5RMIX_INPUT_2_SOURCE:
case WM5100_OUT5RMIX_INPUT_2_VOLUME:
case WM5100_OUT5RMIX_INPUT_3_SOURCE:
case WM5100_OUT5RMIX_INPUT_3_VOLUME:
case WM5100_OUT5RMIX_INPUT_4_SOURCE:
case WM5100_OUT5RMIX_INPUT_4_VOLUME:
case WM5100_OUT6LMIX_INPUT_1_SOURCE:
case WM5100_OUT6LMIX_INPUT_1_VOLUME:
case WM5100_OUT6LMIX_INPUT_2_SOURCE:
case WM5100_OUT6LMIX_INPUT_2_VOLUME:
case WM5100_OUT6LMIX_INPUT_3_SOURCE:
case WM5100_OUT6LMIX_INPUT_3_VOLUME:
case WM5100_OUT6LMIX_INPUT_4_SOURCE:
case WM5100_OUT6LMIX_INPUT_4_VOLUME:
case WM5100_OUT6RMIX_INPUT_1_SOURCE:
case WM5100_OUT6RMIX_INPUT_1_VOLUME:
case WM5100_OUT6RMIX_INPUT_2_SOURCE:
case WM5100_OUT6RMIX_INPUT_2_VOLUME:
case WM5100_OUT6RMIX_INPUT_3_SOURCE:
case WM5100_OUT6RMIX_INPUT_3_VOLUME:
case WM5100_OUT6RMIX_INPUT_4_SOURCE:
case WM5100_OUT6RMIX_INPUT_4_VOLUME:
case WM5100_AIF1TX1MIX_INPUT_1_SOURCE:
case WM5100_AIF1TX1MIX_INPUT_1_VOLUME:
case WM5100_AIF1TX1MIX_INPUT_2_SOURCE:
case WM5100_AIF1TX1MIX_INPUT_2_VOLUME:
case WM5100_AIF1TX1MIX_INPUT_3_SOURCE:
case WM5100_AIF1TX1MIX_INPUT_3_VOLUME:
case WM5100_AIF1TX1MIX_INPUT_4_SOURCE:
case WM5100_AIF1TX1MIX_INPUT_4_VOLUME:
case WM5100_AIF1TX2MIX_INPUT_1_SOURCE:
case WM5100_AIF1TX2MIX_INPUT_1_VOLUME:
case WM5100_AIF1TX2MIX_INPUT_2_SOURCE:
case WM5100_AIF1TX2MIX_INPUT_2_VOLUME:
case WM5100_AIF1TX2MIX_INPUT_3_SOURCE:
case WM5100_AIF1TX2MIX_INPUT_3_VOLUME:
case WM5100_AIF1TX2MIX_INPUT_4_SOURCE:
case WM5100_AIF1TX2MIX_INPUT_4_VOLUME:
case WM5100_AIF1TX3MIX_INPUT_1_SOURCE:
case WM5100_AIF1TX3MIX_INPUT_1_VOLUME:
case WM5100_AIF1TX3MIX_INPUT_2_SOURCE:
case WM5100_AIF1TX3MIX_INPUT_2_VOLUME:
case WM5100_AIF1TX3MIX_INPUT_3_SOURCE:
case WM5100_AIF1TX3MIX_INPUT_3_VOLUME:
case WM5100_AIF1TX3MIX_INPUT_4_SOURCE:
case WM5100_AIF1TX3MIX_INPUT_4_VOLUME:
case WM5100_AIF1TX4MIX_INPUT_1_SOURCE:
case WM5100_AIF1TX4MIX_INPUT_1_VOLUME:
case WM5100_AIF1TX4MIX_INPUT_2_SOURCE:
case WM5100_AIF1TX4MIX_INPUT_2_VOLUME:
case WM5100_AIF1TX4MIX_INPUT_3_SOURCE:
case WM5100_AIF1TX4MIX_INPUT_3_VOLUME:
case WM5100_AIF1TX4MIX_INPUT_4_SOURCE:
case WM5100_AIF1TX4MIX_INPUT_4_VOLUME:
case WM5100_AIF1TX5MIX_INPUT_1_SOURCE:
case WM5100_AIF1TX5MIX_INPUT_1_VOLUME:
case WM5100_AIF1TX5MIX_INPUT_2_SOURCE:
case WM5100_AIF1TX5MIX_INPUT_2_VOLUME:
case WM5100_AIF1TX5MIX_INPUT_3_SOURCE:
case WM5100_AIF1TX5MIX_INPUT_3_VOLUME:
case WM5100_AIF1TX5MIX_INPUT_4_SOURCE:
case WM5100_AIF1TX5MIX_INPUT_4_VOLUME:
case WM5100_AIF1TX6MIX_INPUT_1_SOURCE:
case WM5100_AIF1TX6MIX_INPUT_1_VOLUME:
case WM5100_AIF1TX6MIX_INPUT_2_SOURCE:
case WM5100_AIF1TX6MIX_INPUT_2_VOLUME:
case WM5100_AIF1TX6MIX_INPUT_3_SOURCE:
case WM5100_AIF1TX6MIX_INPUT_3_VOLUME:
case WM5100_AIF1TX6MIX_INPUT_4_SOURCE:
case WM5100_AIF1TX6MIX_INPUT_4_VOLUME:
case WM5100_AIF1TX7MIX_INPUT_1_SOURCE:
case WM5100_AIF1TX7MIX_INPUT_1_VOLUME:
case WM5100_AIF1TX7MIX_INPUT_2_SOURCE:
case WM5100_AIF1TX7MIX_INPUT_2_VOLUME:
case WM5100_AIF1TX7MIX_INPUT_3_SOURCE:
case WM5100_AIF1TX7MIX_INPUT_3_VOLUME:
case WM5100_AIF1TX7MIX_INPUT_4_SOURCE:
case WM5100_AIF1TX7MIX_INPUT_4_VOLUME:
case WM5100_AIF1TX8MIX_INPUT_1_SOURCE:
case WM5100_AIF1TX8MIX_INPUT_1_VOLUME:
case WM5100_AIF1TX8MIX_INPUT_2_SOURCE:
case WM5100_AIF1TX8MIX_INPUT_2_VOLUME:
case WM5100_AIF1TX8MIX_INPUT_3_SOURCE:
case WM5100_AIF1TX8MIX_INPUT_3_VOLUME:
case WM5100_AIF1TX8MIX_INPUT_4_SOURCE:
case WM5100_AIF1TX8MIX_INPUT_4_VOLUME:
case WM5100_AIF2TX1MIX_INPUT_1_SOURCE:
case WM5100_AIF2TX1MIX_INPUT_1_VOLUME:
case WM5100_AIF2TX1MIX_INPUT_2_SOURCE:
case WM5100_AIF2TX1MIX_INPUT_2_VOLUME:
case WM5100_AIF2TX1MIX_INPUT_3_SOURCE:
case WM5100_AIF2TX1MIX_INPUT_3_VOLUME:
case WM5100_AIF2TX1MIX_INPUT_4_SOURCE:
case WM5100_AIF2TX1MIX_INPUT_4_VOLUME:
case WM5100_AIF2TX2MIX_INPUT_1_SOURCE:
case WM5100_AIF2TX2MIX_INPUT_1_VOLUME:
case WM5100_AIF2TX2MIX_INPUT_2_SOURCE:
case WM5100_AIF2TX2MIX_INPUT_2_VOLUME:
case WM5100_AIF2TX2MIX_INPUT_3_SOURCE:
case WM5100_AIF2TX2MIX_INPUT_3_VOLUME:
case WM5100_AIF2TX2MIX_INPUT_4_SOURCE:
case WM5100_AIF2TX2MIX_INPUT_4_VOLUME:
case WM5100_AIF3TX1MIX_INPUT_1_SOURCE:
case WM5100_AIF3TX1MIX_INPUT_1_VOLUME:
case WM5100_AIF3TX1MIX_INPUT_2_SOURCE:
case WM5100_AIF3TX1MIX_INPUT_2_VOLUME:
case WM5100_AIF3TX1MIX_INPUT_3_SOURCE:
case WM5100_AIF3TX1MIX_INPUT_3_VOLUME:
case WM5100_AIF3TX1MIX_INPUT_4_SOURCE:
case WM5100_AIF3TX1MIX_INPUT_4_VOLUME:
case WM5100_AIF3TX2MIX_INPUT_1_SOURCE:
case WM5100_AIF3TX2MIX_INPUT_1_VOLUME:
case WM5100_AIF3TX2MIX_INPUT_2_SOURCE:
case WM5100_AIF3TX2MIX_INPUT_2_VOLUME:
case WM5100_AIF3TX2MIX_INPUT_3_SOURCE:
case WM5100_AIF3TX2MIX_INPUT_3_VOLUME:
case WM5100_AIF3TX2MIX_INPUT_4_SOURCE:
case WM5100_AIF3TX2MIX_INPUT_4_VOLUME:
case WM5100_EQ1MIX_INPUT_1_SOURCE:
case WM5100_EQ1MIX_INPUT_1_VOLUME:
case WM5100_EQ1MIX_INPUT_2_SOURCE:
case WM5100_EQ1MIX_INPUT_2_VOLUME:
case WM5100_EQ1MIX_INPUT_3_SOURCE:
case WM5100_EQ1MIX_INPUT_3_VOLUME:
case WM5100_EQ1MIX_INPUT_4_SOURCE:
case WM5100_EQ1MIX_INPUT_4_VOLUME:
case WM5100_EQ2MIX_INPUT_1_SOURCE:
case WM5100_EQ2MIX_INPUT_1_VOLUME:
case WM5100_EQ2MIX_INPUT_2_SOURCE:
case WM5100_EQ2MIX_INPUT_2_VOLUME:
case WM5100_EQ2MIX_INPUT_3_SOURCE:
case WM5100_EQ2MIX_INPUT_3_VOLUME:
case WM5100_EQ2MIX_INPUT_4_SOURCE:
case WM5100_EQ2MIX_INPUT_4_VOLUME:
case WM5100_EQ3MIX_INPUT_1_SOURCE:
case WM5100_EQ3MIX_INPUT_1_VOLUME:
case WM5100_EQ3MIX_INPUT_2_SOURCE:
case WM5100_EQ3MIX_INPUT_2_VOLUME:
case WM5100_EQ3MIX_INPUT_3_SOURCE:
case WM5100_EQ3MIX_INPUT_3_VOLUME:
case WM5100_EQ3MIX_INPUT_4_SOURCE:
case WM5100_EQ3MIX_INPUT_4_VOLUME:
case WM5100_EQ4MIX_INPUT_1_SOURCE:
case WM5100_EQ4MIX_INPUT_1_VOLUME:
case WM5100_EQ4MIX_INPUT_2_SOURCE:
case WM5100_EQ4MIX_INPUT_2_VOLUME:
case WM5100_EQ4MIX_INPUT_3_SOURCE:
case WM5100_EQ4MIX_INPUT_3_VOLUME:
case WM5100_EQ4MIX_INPUT_4_SOURCE:
case WM5100_EQ4MIX_INPUT_4_VOLUME:
case WM5100_DRC1LMIX_INPUT_1_SOURCE:
case WM5100_DRC1LMIX_INPUT_1_VOLUME:
case WM5100_DRC1LMIX_INPUT_2_SOURCE:
case WM5100_DRC1LMIX_INPUT_2_VOLUME:
case WM5100_DRC1LMIX_INPUT_3_SOURCE:
case WM5100_DRC1LMIX_INPUT_3_VOLUME:
case WM5100_DRC1LMIX_INPUT_4_SOURCE:
case WM5100_DRC1LMIX_INPUT_4_VOLUME:
case WM5100_DRC1RMIX_INPUT_1_SOURCE:
case WM5100_DRC1RMIX_INPUT_1_VOLUME:
case WM5100_DRC1RMIX_INPUT_2_SOURCE:
case WM5100_DRC1RMIX_INPUT_2_VOLUME:
case WM5100_DRC1RMIX_INPUT_3_SOURCE:
case WM5100_DRC1RMIX_INPUT_3_VOLUME:
case WM5100_DRC1RMIX_INPUT_4_SOURCE:
case WM5100_DRC1RMIX_INPUT_4_VOLUME:
case WM5100_HPLP1MIX_INPUT_1_SOURCE:
case WM5100_HPLP1MIX_INPUT_1_VOLUME:
case WM5100_HPLP1MIX_INPUT_2_SOURCE:
case WM5100_HPLP1MIX_INPUT_2_VOLUME:
case WM5100_HPLP1MIX_INPUT_3_SOURCE:
case WM5100_HPLP1MIX_INPUT_3_VOLUME:
case WM5100_HPLP1MIX_INPUT_4_SOURCE:
case WM5100_HPLP1MIX_INPUT_4_VOLUME:
case WM5100_HPLP2MIX_INPUT_1_SOURCE:
case WM5100_HPLP2MIX_INPUT_1_VOLUME:
case WM5100_HPLP2MIX_INPUT_2_SOURCE:
case WM5100_HPLP2MIX_INPUT_2_VOLUME:
case WM5100_HPLP2MIX_INPUT_3_SOURCE:
case WM5100_HPLP2MIX_INPUT_3_VOLUME:
case WM5100_HPLP2MIX_INPUT_4_SOURCE:
case WM5100_HPLP2MIX_INPUT_4_VOLUME:
case WM5100_HPLP3MIX_INPUT_1_SOURCE:
case WM5100_HPLP3MIX_INPUT_1_VOLUME:
case WM5100_HPLP3MIX_INPUT_2_SOURCE:
case WM5100_HPLP3MIX_INPUT_2_VOLUME:
case WM5100_HPLP3MIX_INPUT_3_SOURCE:
case WM5100_HPLP3MIX_INPUT_3_VOLUME:
case WM5100_HPLP3MIX_INPUT_4_SOURCE:
case WM5100_HPLP3MIX_INPUT_4_VOLUME:
case WM5100_HPLP4MIX_INPUT_1_SOURCE:
case WM5100_HPLP4MIX_INPUT_1_VOLUME:
case WM5100_HPLP4MIX_INPUT_2_SOURCE:
case WM5100_HPLP4MIX_INPUT_2_VOLUME:
case WM5100_HPLP4MIX_INPUT_3_SOURCE:
case WM5100_HPLP4MIX_INPUT_3_VOLUME:
case WM5100_HPLP4MIX_INPUT_4_SOURCE:
case WM5100_HPLP4MIX_INPUT_4_VOLUME:
case WM5100_DSP1LMIX_INPUT_1_SOURCE:
case WM5100_DSP1LMIX_INPUT_1_VOLUME:
case WM5100_DSP1LMIX_INPUT_2_SOURCE:
case WM5100_DSP1LMIX_INPUT_2_VOLUME:
case WM5100_DSP1LMIX_INPUT_3_SOURCE:
case WM5100_DSP1LMIX_INPUT_3_VOLUME:
case WM5100_DSP1LMIX_INPUT_4_SOURCE:
case WM5100_DSP1LMIX_INPUT_4_VOLUME:
case WM5100_DSP1RMIX_INPUT_1_SOURCE:
case WM5100_DSP1RMIX_INPUT_1_VOLUME:
case WM5100_DSP1RMIX_INPUT_2_SOURCE:
case WM5100_DSP1RMIX_INPUT_2_VOLUME:
case WM5100_DSP1RMIX_INPUT_3_SOURCE:
case WM5100_DSP1RMIX_INPUT_3_VOLUME:
case WM5100_DSP1RMIX_INPUT_4_SOURCE:
case WM5100_DSP1RMIX_INPUT_4_VOLUME:
case WM5100_DSP1AUX1MIX_INPUT_1_SOURCE:
case WM5100_DSP1AUX2MIX_INPUT_1_SOURCE:
case WM5100_DSP1AUX3MIX_INPUT_1_SOURCE:
case WM5100_DSP1AUX4MIX_INPUT_1_SOURCE:
case WM5100_DSP1AUX5MIX_INPUT_1_SOURCE:
case WM5100_DSP1AUX6MIX_INPUT_1_SOURCE:
case WM5100_DSP2LMIX_INPUT_1_SOURCE:
case WM5100_DSP2LMIX_INPUT_1_VOLUME:
case WM5100_DSP2LMIX_INPUT_2_SOURCE:
case WM5100_DSP2LMIX_INPUT_2_VOLUME:
case WM5100_DSP2LMIX_INPUT_3_SOURCE:
case WM5100_DSP2LMIX_INPUT_3_VOLUME:
case WM5100_DSP2LMIX_INPUT_4_SOURCE:
case WM5100_DSP2LMIX_INPUT_4_VOLUME:
case WM5100_DSP2RMIX_INPUT_1_SOURCE:
case WM5100_DSP2RMIX_INPUT_1_VOLUME:
case WM5100_DSP2RMIX_INPUT_2_SOURCE:
case WM5100_DSP2RMIX_INPUT_2_VOLUME:
case WM5100_DSP2RMIX_INPUT_3_SOURCE:
case WM5100_DSP2RMIX_INPUT_3_VOLUME:
case WM5100_DSP2RMIX_INPUT_4_SOURCE:
case WM5100_DSP2RMIX_INPUT_4_VOLUME:
case WM5100_DSP2AUX1MIX_INPUT_1_SOURCE:
case WM5100_DSP2AUX2MIX_INPUT_1_SOURCE:
case WM5100_DSP2AUX3MIX_INPUT_1_SOURCE:
case WM5100_DSP2AUX4MIX_INPUT_1_SOURCE:
case WM5100_DSP2AUX5MIX_INPUT_1_SOURCE:
case WM5100_DSP2AUX6MIX_INPUT_1_SOURCE:
case WM5100_DSP3LMIX_INPUT_1_SOURCE:
case WM5100_DSP3LMIX_INPUT_1_VOLUME:
case WM5100_DSP3LMIX_INPUT_2_SOURCE:
case WM5100_DSP3LMIX_INPUT_2_VOLUME:
case WM5100_DSP3LMIX_INPUT_3_SOURCE:
case WM5100_DSP3LMIX_INPUT_3_VOLUME:
case WM5100_DSP3LMIX_INPUT_4_SOURCE:
case WM5100_DSP3LMIX_INPUT_4_VOLUME:
case WM5100_DSP3RMIX_INPUT_1_SOURCE:
case WM5100_DSP3RMIX_INPUT_1_VOLUME:
case WM5100_DSP3RMIX_INPUT_2_SOURCE:
case WM5100_DSP3RMIX_INPUT_2_VOLUME:
case WM5100_DSP3RMIX_INPUT_3_SOURCE:
case WM5100_DSP3RMIX_INPUT_3_VOLUME:
case WM5100_DSP3RMIX_INPUT_4_SOURCE:
case WM5100_DSP3RMIX_INPUT_4_VOLUME:
case WM5100_DSP3AUX1MIX_INPUT_1_SOURCE:
case WM5100_DSP3AUX2MIX_INPUT_1_SOURCE:
case WM5100_DSP3AUX3MIX_INPUT_1_SOURCE:
case WM5100_DSP3AUX4MIX_INPUT_1_SOURCE:
case WM5100_DSP3AUX5MIX_INPUT_1_SOURCE:
case WM5100_DSP3AUX6MIX_INPUT_1_SOURCE:
case WM5100_ASRC1LMIX_INPUT_1_SOURCE:
case WM5100_ASRC1RMIX_INPUT_1_SOURCE:
case WM5100_ASRC2LMIX_INPUT_1_SOURCE:
case WM5100_ASRC2RMIX_INPUT_1_SOURCE:
case WM5100_ISRC1DEC1MIX_INPUT_1_SOURCE:
case WM5100_ISRC1DEC2MIX_INPUT_1_SOURCE:
case WM5100_ISRC1DEC3MIX_INPUT_1_SOURCE:
case WM5100_ISRC1DEC4MIX_INPUT_1_SOURCE:
case WM5100_ISRC1INT1MIX_INPUT_1_SOURCE:
case WM5100_ISRC1INT2MIX_INPUT_1_SOURCE:
case WM5100_ISRC1INT3MIX_INPUT_1_SOURCE:
case WM5100_ISRC1INT4MIX_INPUT_1_SOURCE:
case WM5100_ISRC2DEC1MIX_INPUT_1_SOURCE:
case WM5100_ISRC2DEC2MIX_INPUT_1_SOURCE:
case WM5100_ISRC2DEC3MIX_INPUT_1_SOURCE:
case WM5100_ISRC2DEC4MIX_INPUT_1_SOURCE:
case WM5100_ISRC2INT1MIX_INPUT_1_SOURCE:
case WM5100_ISRC2INT2MIX_INPUT_1_SOURCE:
case WM5100_ISRC2INT3MIX_INPUT_1_SOURCE:
case WM5100_ISRC2INT4MIX_INPUT_1_SOURCE:
case WM5100_GPIO_CTRL_1:
case WM5100_GPIO_CTRL_2:
case WM5100_GPIO_CTRL_3:
case WM5100_GPIO_CTRL_4:
case WM5100_GPIO_CTRL_5:
case WM5100_GPIO_CTRL_6:
case WM5100_MISC_PAD_CTRL_1:
case WM5100_MISC_PAD_CTRL_2:
case WM5100_MISC_PAD_CTRL_3:
case WM5100_MISC_PAD_CTRL_4:
case WM5100_MISC_PAD_CTRL_5:
case WM5100_MISC_GPIO_1:
case WM5100_INTERRUPT_STATUS_1:
case WM5100_INTERRUPT_STATUS_2:
case WM5100_INTERRUPT_STATUS_3:
case WM5100_INTERRUPT_STATUS_4:
case WM5100_INTERRUPT_RAW_STATUS_2:
case WM5100_INTERRUPT_RAW_STATUS_3:
case WM5100_INTERRUPT_RAW_STATUS_4:
case WM5100_INTERRUPT_STATUS_1_MASK:
case WM5100_INTERRUPT_STATUS_2_MASK:
case WM5100_INTERRUPT_STATUS_3_MASK:
case WM5100_INTERRUPT_STATUS_4_MASK:
case WM5100_INTERRUPT_CONTROL:
case WM5100_IRQ_DEBOUNCE_1:
case WM5100_IRQ_DEBOUNCE_2:
case WM5100_FX_CTRL:
case WM5100_EQ1_1:
case WM5100_EQ1_2:
case WM5100_EQ1_3:
case WM5100_EQ1_4:
case WM5100_EQ1_5:
case WM5100_EQ1_6:
case WM5100_EQ1_7:
case WM5100_EQ1_8:
case WM5100_EQ1_9:
case WM5100_EQ1_10:
case WM5100_EQ1_11:
case WM5100_EQ1_12:
case WM5100_EQ1_13:
case WM5100_EQ1_14:
case WM5100_EQ1_15:
case WM5100_EQ1_16:
case WM5100_EQ1_17:
case WM5100_EQ1_18:
case WM5100_EQ1_19:
case WM5100_EQ1_20:
case WM5100_EQ2_1:
case WM5100_EQ2_2:
case WM5100_EQ2_3:
case WM5100_EQ2_4:
case WM5100_EQ2_5:
case WM5100_EQ2_6:
case WM5100_EQ2_7:
case WM5100_EQ2_8:
case WM5100_EQ2_9:
case WM5100_EQ2_10:
case WM5100_EQ2_11:
case WM5100_EQ2_12:
case WM5100_EQ2_13:
case WM5100_EQ2_14:
case WM5100_EQ2_15:
case WM5100_EQ2_16:
case WM5100_EQ2_17:
case WM5100_EQ2_18:
case WM5100_EQ2_19:
case WM5100_EQ2_20:
case WM5100_EQ3_1:
case WM5100_EQ3_2:
case WM5100_EQ3_3:
case WM5100_EQ3_4:
case WM5100_EQ3_5:
case WM5100_EQ3_6:
case WM5100_EQ3_7:
case WM5100_EQ3_8:
case WM5100_EQ3_9:
case WM5100_EQ3_10:
case WM5100_EQ3_11:
case WM5100_EQ3_12:
case WM5100_EQ3_13:
case WM5100_EQ3_14:
case WM5100_EQ3_15:
case WM5100_EQ3_16:
case WM5100_EQ3_17:
case WM5100_EQ3_18:
case WM5100_EQ3_19:
case WM5100_EQ3_20:
case WM5100_EQ4_1:
case WM5100_EQ4_2:
case WM5100_EQ4_3:
case WM5100_EQ4_4:
case WM5100_EQ4_5:
case WM5100_EQ4_6:
case WM5100_EQ4_7:
case WM5100_EQ4_8:
case WM5100_EQ4_9:
case WM5100_EQ4_10:
case WM5100_EQ4_11:
case WM5100_EQ4_12:
case WM5100_EQ4_13:
case WM5100_EQ4_14:
case WM5100_EQ4_15:
case WM5100_EQ4_16:
case WM5100_EQ4_17:
case WM5100_EQ4_18:
case WM5100_EQ4_19:
case WM5100_EQ4_20:
case WM5100_DRC1_CTRL1:
case WM5100_DRC1_CTRL2:
case WM5100_DRC1_CTRL3:
case WM5100_DRC1_CTRL4:
case WM5100_DRC1_CTRL5:
case WM5100_HPLPF1_1:
case WM5100_HPLPF1_2:
case WM5100_HPLPF2_1:
case WM5100_HPLPF2_2:
case WM5100_HPLPF3_1:
case WM5100_HPLPF3_2:
case WM5100_HPLPF4_1:
case WM5100_HPLPF4_2:
case WM5100_DSP1_DM_0:
case WM5100_DSP1_DM_1:
case WM5100_DSP1_DM_2:
case WM5100_DSP1_DM_3:
case WM5100_DSP1_DM_508:
case WM5100_DSP1_DM_509:
case WM5100_DSP1_DM_510:
case WM5100_DSP1_DM_511:
case WM5100_DSP1_PM_0:
case WM5100_DSP1_PM_1:
case WM5100_DSP1_PM_2:
case WM5100_DSP1_PM_3:
case WM5100_DSP1_PM_4:
case WM5100_DSP1_PM_5:
case WM5100_DSP1_PM_1530:
case WM5100_DSP1_PM_1531:
case WM5100_DSP1_PM_1532:
case WM5100_DSP1_PM_1533:
case WM5100_DSP1_PM_1534:
case WM5100_DSP1_PM_1535:
case WM5100_DSP1_ZM_0:
case WM5100_DSP1_ZM_1:
case WM5100_DSP1_ZM_2:
case WM5100_DSP1_ZM_3:
case WM5100_DSP1_ZM_2044:
case WM5100_DSP1_ZM_2045:
case WM5100_DSP1_ZM_2046:
case WM5100_DSP1_ZM_2047:
case WM5100_DSP2_DM_0:
case WM5100_DSP2_DM_1:
case WM5100_DSP2_DM_2:
case WM5100_DSP2_DM_3:
case WM5100_DSP2_DM_508:
case WM5100_DSP2_DM_509:
case WM5100_DSP2_DM_510:
case WM5100_DSP2_DM_511:
case WM5100_DSP2_PM_0:
case WM5100_DSP2_PM_1:
case WM5100_DSP2_PM_2:
case WM5100_DSP2_PM_3:
case WM5100_DSP2_PM_4:
case WM5100_DSP2_PM_5:
case WM5100_DSP2_PM_1530:
case WM5100_DSP2_PM_1531:
case WM5100_DSP2_PM_1532:
case WM5100_DSP2_PM_1533:
case WM5100_DSP2_PM_1534:
case WM5100_DSP2_PM_1535:
case WM5100_DSP2_ZM_0:
case WM5100_DSP2_ZM_1:
case WM5100_DSP2_ZM_2:
case WM5100_DSP2_ZM_3:
case WM5100_DSP2_ZM_2044:
case WM5100_DSP2_ZM_2045:
case WM5100_DSP2_ZM_2046:
case WM5100_DSP2_ZM_2047:
case WM5100_DSP3_DM_0:
case WM5100_DSP3_DM_1:
case WM5100_DSP3_DM_2:
case WM5100_DSP3_DM_3:
case WM5100_DSP3_DM_508:
case WM5100_DSP3_DM_509:
case WM5100_DSP3_DM_510:
case WM5100_DSP3_DM_511:
case WM5100_DSP3_PM_0:
case WM5100_DSP3_PM_1:
case WM5100_DSP3_PM_2:
case WM5100_DSP3_PM_3:
case WM5100_DSP3_PM_4:
case WM5100_DSP3_PM_5:
case WM5100_DSP3_PM_1530:
case WM5100_DSP3_PM_1531:
case WM5100_DSP3_PM_1532:
case WM5100_DSP3_PM_1533:
case WM5100_DSP3_PM_1534:
case WM5100_DSP3_PM_1535:
case WM5100_DSP3_ZM_0:
case WM5100_DSP3_ZM_1:
case WM5100_DSP3_ZM_2:
case WM5100_DSP3_ZM_3:
case WM5100_DSP3_ZM_2044:
case WM5100_DSP3_ZM_2045:
case WM5100_DSP3_ZM_2046:
case WM5100_DSP3_ZM_2047:
return 1;
default:
return 0;
}
}
u16 wm5100_reg_defaults[WM5100_MAX_REGISTER + 1] = {
[0x0000] = 0x0000, /* R0 - software reset */
[0x0001] = 0x0000, /* R1 - Device Revision */
[0x0010] = 0x0801, /* R16 - Ctrl IF 1 */
[0x0020] = 0x0000, /* R32 - Tone Generator 1 */
[0x0030] = 0x0000, /* R48 - PWM Drive 1 */
[0x0031] = 0x0100, /* R49 - PWM Drive 2 */
[0x0032] = 0x0100, /* R50 - PWM Drive 3 */
[0x0101] = 0x0000, /* R257 - Clocking 3 */
[0x0102] = 0x0011, /* R258 - Clocking 4 */
[0x0103] = 0x0011, /* R259 - Clocking 5 */
[0x0104] = 0x0011, /* R260 - Clocking 6 */
[0x0107] = 0x0000, /* R263 - Clocking 7 */
[0x0108] = 0x0000, /* R264 - Clocking 8 */
[0x0120] = 0x0000, /* R288 - ASRC_ENABLE */
[0x0121] = 0x0000, /* R289 - ASRC_STATUS */
[0x0122] = 0x0000, /* R290 - ASRC_RATE1 */
[0x0141] = 0x8000, /* R321 - ISRC 1 CTRL 1 */
[0x0142] = 0x0000, /* R322 - ISRC 1 CTRL 2 */
[0x0143] = 0x8000, /* R323 - ISRC 2 CTRL1 */
[0x0144] = 0x0000, /* R324 - ISRC 2 CTRL 2 */
[0x0182] = 0x0000, /* R386 - FLL1 Control 1 */
[0x0183] = 0x0000, /* R387 - FLL1 Control 2 */
[0x0184] = 0x0000, /* R388 - FLL1 Control 3 */
[0x0186] = 0x0177, /* R390 - FLL1 Control 5 */
[0x0187] = 0x0001, /* R391 - FLL1 Control 6 */
[0x0188] = 0x0000, /* R392 - FLL1 EFS 1 */
[0x01A2] = 0x0000, /* R418 - FLL2 Control 1 */
[0x01A3] = 0x0000, /* R419 - FLL2 Control 2 */
[0x01A4] = 0x0000, /* R420 - FLL2 Control 3 */
[0x01A6] = 0x0177, /* R422 - FLL2 Control 5 */
[0x01A7] = 0x0001, /* R423 - FLL2 Control 6 */
[0x01A8] = 0x0000, /* R424 - FLL2 EFS 1 */
[0x0200] = 0x0020, /* R512 - Mic Charge Pump 1 */
[0x0201] = 0xB084, /* R513 - Mic Charge Pump 2 */
[0x0202] = 0xBBDE, /* R514 - HP Charge Pump 1 */
[0x0211] = 0x20D4, /* R529 - LDO1 Control */
[0x0215] = 0x0062, /* R533 - Mic Bias Ctrl 1 */
[0x0216] = 0x0062, /* R534 - Mic Bias Ctrl 2 */
[0x0217] = 0x0062, /* R535 - Mic Bias Ctrl 3 */
[0x0280] = 0x0004, /* R640 - Accessory Detect Mode 1 */
[0x0288] = 0x0020, /* R648 - Headphone Detect 1 */
[0x0289] = 0x0000, /* R649 - Headphone Detect 2 */
[0x0290] = 0x1100, /* R656 - Mic Detect 1 */
[0x0291] = 0x009F, /* R657 - Mic Detect 2 */
[0x0292] = 0x0000, /* R658 - Mic Detect 3 */
[0x0301] = 0x0000, /* R769 - Input Enables */
[0x0302] = 0x0000, /* R770 - Input Enables Status */
[0x0310] = 0x2280, /* R784 - Status */
[0x0311] = 0x0080, /* R785 - IN1R Control */
[0x0312] = 0x2280, /* R786 - IN2L Control */
[0x0313] = 0x0080, /* R787 - IN2R Control */
[0x0314] = 0x2280, /* R788 - IN3L Control */
[0x0315] = 0x0080, /* R789 - IN3R Control */
[0x0316] = 0x2280, /* R790 - IN4L Control */
[0x0317] = 0x0080, /* R791 - IN4R Control */
[0x0318] = 0x0000, /* R792 - RXANC_SRC */
[0x0319] = 0x0022, /* R793 - Input Volume Ramp */
[0x0320] = 0x0180, /* R800 - ADC Digital Volume 1L */
[0x0321] = 0x0180, /* R801 - ADC Digital Volume 1R */
[0x0322] = 0x0180, /* R802 - ADC Digital Volume 2L */
[0x0323] = 0x0180, /* R803 - ADC Digital Volume 2R */
[0x0324] = 0x0180, /* R804 - ADC Digital Volume 3L */
[0x0325] = 0x0180, /* R805 - ADC Digital Volume 3R */
[0x0326] = 0x0180, /* R806 - ADC Digital Volume 4L */
[0x0327] = 0x0180, /* R807 - ADC Digital Volume 4R */
[0x0401] = 0x0000, /* R1025 - Output Enables 2 */
[0x0402] = 0x0000, /* R1026 - Output Status 1 */
[0x0403] = 0x0000, /* R1027 - Output Status 2 */
[0x0408] = 0x0000, /* R1032 - Channel Enables 1 */
[0x0410] = 0x0080, /* R1040 - Out Volume 1L */
[0x0411] = 0x0080, /* R1041 - Out Volume 1R */
[0x0412] = 0x0080, /* R1042 - DAC Volume Limit 1L */
[0x0413] = 0x0080, /* R1043 - DAC Volume Limit 1R */
[0x0414] = 0x0080, /* R1044 - Out Volume 2L */
[0x0415] = 0x0080, /* R1045 - Out Volume 2R */
[0x0416] = 0x0080, /* R1046 - DAC Volume Limit 2L */
[0x0417] = 0x0080, /* R1047 - DAC Volume Limit 2R */
[0x0418] = 0x0080, /* R1048 - Out Volume 3L */
[0x0419] = 0x0080, /* R1049 - Out Volume 3R */
[0x041A] = 0x0080, /* R1050 - DAC Volume Limit 3L */
[0x041B] = 0x0080, /* R1051 - DAC Volume Limit 3R */
[0x041C] = 0x0080, /* R1052 - Out Volume 4L */
[0x041D] = 0x0080, /* R1053 - Out Volume 4R */
[0x041E] = 0x0080, /* R1054 - DAC Volume Limit 5L */
[0x041F] = 0x0080, /* R1055 - DAC Volume Limit 5R */
[0x0420] = 0x0080, /* R1056 - DAC Volume Limit 6L */
[0x0421] = 0x0080, /* R1057 - DAC Volume Limit 6R */
[0x0440] = 0x0000, /* R1088 - DAC AEC Control 1 */
[0x0441] = 0x0022, /* R1089 - Output Volume Ramp */
[0x0480] = 0x0180, /* R1152 - DAC Digital Volume 1L */
[0x0481] = 0x0180, /* R1153 - DAC Digital Volume 1R */
[0x0482] = 0x0180, /* R1154 - DAC Digital Volume 2L */
[0x0483] = 0x0180, /* R1155 - DAC Digital Volume 2R */
[0x0484] = 0x0180, /* R1156 - DAC Digital Volume 3L */
[0x0485] = 0x0180, /* R1157 - DAC Digital Volume 3R */
[0x0486] = 0x0180, /* R1158 - DAC Digital Volume 4L */
[0x0487] = 0x0180, /* R1159 - DAC Digital Volume 4R */
[0x0488] = 0x0180, /* R1160 - DAC Digital Volume 5L */
[0x0489] = 0x0180, /* R1161 - DAC Digital Volume 5R */
[0x048A] = 0x0180, /* R1162 - DAC Digital Volume 6L */
[0x048B] = 0x0180, /* R1163 - DAC Digital Volume 6R */
[0x04C0] = 0x0069, /* R1216 - PDM SPK1 CTRL 1 */
[0x04C1] = 0x0000, /* R1217 - PDM SPK1 CTRL 2 */
[0x04C2] = 0x0069, /* R1218 - PDM SPK2 CTRL 1 */
[0x04C3] = 0x0000, /* R1219 - PDM SPK2 CTRL 2 */
[0x0500] = 0x000C, /* R1280 - Audio IF 1_1 */
[0x0501] = 0x0008, /* R1281 - Audio IF 1_2 */
[0x0502] = 0x0000, /* R1282 - Audio IF 1_3 */
[0x0503] = 0x0000, /* R1283 - Audio IF 1_4 */
[0x0504] = 0x0000, /* R1284 - Audio IF 1_5 */
[0x0505] = 0x0300, /* R1285 - Audio IF 1_6 */
[0x0506] = 0x0300, /* R1286 - Audio IF 1_7 */
[0x0507] = 0x1820, /* R1287 - Audio IF 1_8 */
[0x0508] = 0x1820, /* R1288 - Audio IF 1_9 */
[0x0509] = 0x0000, /* R1289 - Audio IF 1_10 */
[0x050A] = 0x0001, /* R1290 - Audio IF 1_11 */
[0x050B] = 0x0002, /* R1291 - Audio IF 1_12 */
[0x050C] = 0x0003, /* R1292 - Audio IF 1_13 */
[0x050D] = 0x0004, /* R1293 - Audio IF 1_14 */
[0x050E] = 0x0005, /* R1294 - Audio IF 1_15 */
[0x050F] = 0x0006, /* R1295 - Audio IF 1_16 */
[0x0510] = 0x0007, /* R1296 - Audio IF 1_17 */
[0x0511] = 0x0000, /* R1297 - Audio IF 1_18 */
[0x0512] = 0x0001, /* R1298 - Audio IF 1_19 */
[0x0513] = 0x0002, /* R1299 - Audio IF 1_20 */
[0x0514] = 0x0003, /* R1300 - Audio IF 1_21 */
[0x0515] = 0x0004, /* R1301 - Audio IF 1_22 */
[0x0516] = 0x0005, /* R1302 - Audio IF 1_23 */
[0x0517] = 0x0006, /* R1303 - Audio IF 1_24 */
[0x0518] = 0x0007, /* R1304 - Audio IF 1_25 */
[0x0519] = 0x0000, /* R1305 - Audio IF 1_26 */
[0x051A] = 0x0000, /* R1306 - Audio IF 1_27 */
[0x0540] = 0x000C, /* R1344 - Audio IF 2_1 */
[0x0541] = 0x0008, /* R1345 - Audio IF 2_2 */
[0x0542] = 0x0000, /* R1346 - Audio IF 2_3 */
[0x0543] = 0x0000, /* R1347 - Audio IF 2_4 */
[0x0544] = 0x0000, /* R1348 - Audio IF 2_5 */
[0x0545] = 0x0300, /* R1349 - Audio IF 2_6 */
[0x0546] = 0x0300, /* R1350 - Audio IF 2_7 */
[0x0547] = 0x1820, /* R1351 - Audio IF 2_8 */
[0x0548] = 0x1820, /* R1352 - Audio IF 2_9 */
[0x0549] = 0x0000, /* R1353 - Audio IF 2_10 */
[0x054A] = 0x0001, /* R1354 - Audio IF 2_11 */
[0x0551] = 0x0000, /* R1361 - Audio IF 2_18 */
[0x0552] = 0x0001, /* R1362 - Audio IF 2_19 */
[0x0559] = 0x0000, /* R1369 - Audio IF 2_26 */
[0x055A] = 0x0000, /* R1370 - Audio IF 2_27 */
[0x0580] = 0x000C, /* R1408 - Audio IF 3_1 */
[0x0581] = 0x0008, /* R1409 - Audio IF 3_2 */
[0x0582] = 0x0000, /* R1410 - Audio IF 3_3 */
[0x0583] = 0x0000, /* R1411 - Audio IF 3_4 */
[0x0584] = 0x0000, /* R1412 - Audio IF 3_5 */
[0x0585] = 0x0300, /* R1413 - Audio IF 3_6 */
[0x0586] = 0x0300, /* R1414 - Audio IF 3_7 */
[0x0587] = 0x1820, /* R1415 - Audio IF 3_8 */
[0x0588] = 0x1820, /* R1416 - Audio IF 3_9 */
[0x0589] = 0x0000, /* R1417 - Audio IF 3_10 */
[0x058A] = 0x0001, /* R1418 - Audio IF 3_11 */
[0x0591] = 0x0000, /* R1425 - Audio IF 3_18 */
[0x0592] = 0x0001, /* R1426 - Audio IF 3_19 */
[0x0599] = 0x0000, /* R1433 - Audio IF 3_26 */
[0x059A] = 0x0000, /* R1434 - Audio IF 3_27 */
[0x0640] = 0x0000, /* R1600 - PWM1MIX Input 1 Source */
[0x0641] = 0x0080, /* R1601 - PWM1MIX Input 1 Volume */
[0x0642] = 0x0000, /* R1602 - PWM1MIX Input 2 Source */
[0x0643] = 0x0080, /* R1603 - PWM1MIX Input 2 Volume */
[0x0644] = 0x0000, /* R1604 - PWM1MIX Input 3 Source */
[0x0645] = 0x0080, /* R1605 - PWM1MIX Input 3 Volume */
[0x0646] = 0x0000, /* R1606 - PWM1MIX Input 4 Source */
[0x0647] = 0x0080, /* R1607 - PWM1MIX Input 4 Volume */
[0x0648] = 0x0000, /* R1608 - PWM2MIX Input 1 Source */
[0x0649] = 0x0080, /* R1609 - PWM2MIX Input 1 Volume */
[0x064A] = 0x0000, /* R1610 - PWM2MIX Input 2 Source */
[0x064B] = 0x0080, /* R1611 - PWM2MIX Input 2 Volume */
[0x064C] = 0x0000, /* R1612 - PWM2MIX Input 3 Source */
[0x064D] = 0x0080, /* R1613 - PWM2MIX Input 3 Volume */
[0x064E] = 0x0000, /* R1614 - PWM2MIX Input 4 Source */
[0x064F] = 0x0080, /* R1615 - PWM2MIX Input 4 Volume */
[0x0680] = 0x0000, /* R1664 - OUT1LMIX Input 1 Source */
[0x0681] = 0x0080, /* R1665 - OUT1LMIX Input 1 Volume */
[0x0682] = 0x0000, /* R1666 - OUT1LMIX Input 2 Source */
[0x0683] = 0x0080, /* R1667 - OUT1LMIX Input 2 Volume */
[0x0684] = 0x0000, /* R1668 - OUT1LMIX Input 3 Source */
[0x0685] = 0x0080, /* R1669 - OUT1LMIX Input 3 Volume */
[0x0686] = 0x0000, /* R1670 - OUT1LMIX Input 4 Source */
[0x0687] = 0x0080, /* R1671 - OUT1LMIX Input 4 Volume */
[0x0688] = 0x0000, /* R1672 - OUT1RMIX Input 1 Source */
[0x0689] = 0x0080, /* R1673 - OUT1RMIX Input 1 Volume */
[0x068A] = 0x0000, /* R1674 - OUT1RMIX Input 2 Source */
[0x068B] = 0x0080, /* R1675 - OUT1RMIX Input 2 Volume */
[0x068C] = 0x0000, /* R1676 - OUT1RMIX Input 3 Source */
[0x068D] = 0x0080, /* R1677 - OUT1RMIX Input 3 Volume */
[0x068E] = 0x0000, /* R1678 - OUT1RMIX Input 4 Source */
[0x068F] = 0x0080, /* R1679 - OUT1RMIX Input 4 Volume */
[0x0690] = 0x0000, /* R1680 - OUT2LMIX Input 1 Source */
[0x0691] = 0x0080, /* R1681 - OUT2LMIX Input 1 Volume */
[0x0692] = 0x0000, /* R1682 - OUT2LMIX Input 2 Source */
[0x0693] = 0x0080, /* R1683 - OUT2LMIX Input 2 Volume */
[0x0694] = 0x0000, /* R1684 - OUT2LMIX Input 3 Source */
[0x0695] = 0x0080, /* R1685 - OUT2LMIX Input 3 Volume */
[0x0696] = 0x0000, /* R1686 - OUT2LMIX Input 4 Source */
[0x0697] = 0x0080, /* R1687 - OUT2LMIX Input 4 Volume */
[0x0698] = 0x0000, /* R1688 - OUT2RMIX Input 1 Source */
[0x0699] = 0x0080, /* R1689 - OUT2RMIX Input 1 Volume */
[0x069A] = 0x0000, /* R1690 - OUT2RMIX Input 2 Source */
[0x069B] = 0x0080, /* R1691 - OUT2RMIX Input 2 Volume */
[0x069C] = 0x0000, /* R1692 - OUT2RMIX Input 3 Source */
[0x069D] = 0x0080, /* R1693 - OUT2RMIX Input 3 Volume */
[0x069E] = 0x0000, /* R1694 - OUT2RMIX Input 4 Source */
[0x069F] = 0x0080, /* R1695 - OUT2RMIX Input 4 Volume */
[0x06A0] = 0x0000, /* R1696 - OUT3LMIX Input 1 Source */
[0x06A1] = 0x0080, /* R1697 - OUT3LMIX Input 1 Volume */
[0x06A2] = 0x0000, /* R1698 - OUT3LMIX Input 2 Source */
[0x06A3] = 0x0080, /* R1699 - OUT3LMIX Input 2 Volume */
[0x06A4] = 0x0000, /* R1700 - OUT3LMIX Input 3 Source */
[0x06A5] = 0x0080, /* R1701 - OUT3LMIX Input 3 Volume */
[0x06A6] = 0x0000, /* R1702 - OUT3LMIX Input 4 Source */
[0x06A7] = 0x0080, /* R1703 - OUT3LMIX Input 4 Volume */
[0x06A8] = 0x0000, /* R1704 - OUT3RMIX Input 1 Source */
[0x06A9] = 0x0080, /* R1705 - OUT3RMIX Input 1 Volume */
[0x06AA] = 0x0000, /* R1706 - OUT3RMIX Input 2 Source */
[0x06AB] = 0x0080, /* R1707 - OUT3RMIX Input 2 Volume */
[0x06AC] = 0x0000, /* R1708 - OUT3RMIX Input 3 Source */
[0x06AD] = 0x0080, /* R1709 - OUT3RMIX Input 3 Volume */
[0x06AE] = 0x0000, /* R1710 - OUT3RMIX Input 4 Source */
[0x06AF] = 0x0080, /* R1711 - OUT3RMIX Input 4 Volume */
[0x06B0] = 0x0000, /* R1712 - OUT4LMIX Input 1 Source */
[0x06B1] = 0x0080, /* R1713 - OUT4LMIX Input 1 Volume */
[0x06B2] = 0x0000, /* R1714 - OUT4LMIX Input 2 Source */
[0x06B3] = 0x0080, /* R1715 - OUT4LMIX Input 2 Volume */
[0x06B4] = 0x0000, /* R1716 - OUT4LMIX Input 3 Source */
[0x06B5] = 0x0080, /* R1717 - OUT4LMIX Input 3 Volume */
[0x06B6] = 0x0000, /* R1718 - OUT4LMIX Input 4 Source */
[0x06B7] = 0x0080, /* R1719 - OUT4LMIX Input 4 Volume */
[0x06B8] = 0x0000, /* R1720 - OUT4RMIX Input 1 Source */
[0x06B9] = 0x0080, /* R1721 - OUT4RMIX Input 1 Volume */
[0x06BA] = 0x0000, /* R1722 - OUT4RMIX Input 2 Source */
[0x06BB] = 0x0080, /* R1723 - OUT4RMIX Input 2 Volume */
[0x06BC] = 0x0000, /* R1724 - OUT4RMIX Input 3 Source */
[0x06BD] = 0x0080, /* R1725 - OUT4RMIX Input 3 Volume */
[0x06BE] = 0x0000, /* R1726 - OUT4RMIX Input 4 Source */
[0x06BF] = 0x0080, /* R1727 - OUT4RMIX Input 4 Volume */
[0x06C0] = 0x0000, /* R1728 - OUT5LMIX Input 1 Source */
[0x06C1] = 0x0080, /* R1729 - OUT5LMIX Input 1 Volume */
[0x06C2] = 0x0000, /* R1730 - OUT5LMIX Input 2 Source */
[0x06C3] = 0x0080, /* R1731 - OUT5LMIX Input 2 Volume */
[0x06C4] = 0x0000, /* R1732 - OUT5LMIX Input 3 Source */
[0x06C5] = 0x0080, /* R1733 - OUT5LMIX Input 3 Volume */
[0x06C6] = 0x0000, /* R1734 - OUT5LMIX Input 4 Source */
[0x06C7] = 0x0080, /* R1735 - OUT5LMIX Input 4 Volume */
[0x06C8] = 0x0000, /* R1736 - OUT5RMIX Input 1 Source */
[0x06C9] = 0x0080, /* R1737 - OUT5RMIX Input 1 Volume */
[0x06CA] = 0x0000, /* R1738 - OUT5RMIX Input 2 Source */
[0x06CB] = 0x0080, /* R1739 - OUT5RMIX Input 2 Volume */
[0x06CC] = 0x0000, /* R1740 - OUT5RMIX Input 3 Source */
[0x06CD] = 0x0080, /* R1741 - OUT5RMIX Input 3 Volume */
[0x06CE] = 0x0000, /* R1742 - OUT5RMIX Input 4 Source */
[0x06CF] = 0x0080, /* R1743 - OUT5RMIX Input 4 Volume */
[0x06D0] = 0x0000, /* R1744 - OUT6LMIX Input 1 Source */
[0x06D1] = 0x0080, /* R1745 - OUT6LMIX Input 1 Volume */
[0x06D2] = 0x0000, /* R1746 - OUT6LMIX Input 2 Source */
[0x06D3] = 0x0080, /* R1747 - OUT6LMIX Input 2 Volume */
[0x06D4] = 0x0000, /* R1748 - OUT6LMIX Input 3 Source */
[0x06D5] = 0x0080, /* R1749 - OUT6LMIX Input 3 Volume */
[0x06D6] = 0x0000, /* R1750 - OUT6LMIX Input 4 Source */
[0x06D7] = 0x0080, /* R1751 - OUT6LMIX Input 4 Volume */
[0x06D8] = 0x0000, /* R1752 - OUT6RMIX Input 1 Source */
[0x06D9] = 0x0080, /* R1753 - OUT6RMIX Input 1 Volume */
[0x06DA] = 0x0000, /* R1754 - OUT6RMIX Input 2 Source */
[0x06DB] = 0x0080, /* R1755 - OUT6RMIX Input 2 Volume */
[0x06DC] = 0x0000, /* R1756 - OUT6RMIX Input 3 Source */
[0x06DD] = 0x0080, /* R1757 - OUT6RMIX Input 3 Volume */
[0x06DE] = 0x0000, /* R1758 - OUT6RMIX Input 4 Source */
[0x06DF] = 0x0080, /* R1759 - OUT6RMIX Input 4 Volume */
[0x0700] = 0x0000, /* R1792 - AIF1TX1MIX Input 1 Source */
[0x0701] = 0x0080, /* R1793 - AIF1TX1MIX Input 1 Volume */
[0x0702] = 0x0000, /* R1794 - AIF1TX1MIX Input 2 Source */
[0x0703] = 0x0080, /* R1795 - AIF1TX1MIX Input 2 Volume */
[0x0704] = 0x0000, /* R1796 - AIF1TX1MIX Input 3 Source */
[0x0705] = 0x0080, /* R1797 - AIF1TX1MIX Input 3 Volume */
[0x0706] = 0x0000, /* R1798 - AIF1TX1MIX Input 4 Source */
[0x0707] = 0x0080, /* R1799 - AIF1TX1MIX Input 4 Volume */
[0x0708] = 0x0000, /* R1800 - AIF1TX2MIX Input 1 Source */
[0x0709] = 0x0080, /* R1801 - AIF1TX2MIX Input 1 Volume */
[0x070A] = 0x0000, /* R1802 - AIF1TX2MIX Input 2 Source */
[0x070B] = 0x0080, /* R1803 - AIF1TX2MIX Input 2 Volume */
[0x070C] = 0x0000, /* R1804 - AIF1TX2MIX Input 3 Source */
[0x070D] = 0x0080, /* R1805 - AIF1TX2MIX Input 3 Volume */
[0x070E] = 0x0000, /* R1806 - AIF1TX2MIX Input 4 Source */
[0x070F] = 0x0080, /* R1807 - AIF1TX2MIX Input 4 Volume */
[0x0710] = 0x0000, /* R1808 - AIF1TX3MIX Input 1 Source */
[0x0711] = 0x0080, /* R1809 - AIF1TX3MIX Input 1 Volume */
[0x0712] = 0x0000, /* R1810 - AIF1TX3MIX Input 2 Source */
[0x0713] = 0x0080, /* R1811 - AIF1TX3MIX Input 2 Volume */
[0x0714] = 0x0000, /* R1812 - AIF1TX3MIX Input 3 Source */
[0x0715] = 0x0080, /* R1813 - AIF1TX3MIX Input 3 Volume */
[0x0716] = 0x0000, /* R1814 - AIF1TX3MIX Input 4 Source */
[0x0717] = 0x0080, /* R1815 - AIF1TX3MIX Input 4 Volume */
[0x0718] = 0x0000, /* R1816 - AIF1TX4MIX Input 1 Source */
[0x0719] = 0x0080, /* R1817 - AIF1TX4MIX Input 1 Volume */
[0x071A] = 0x0000, /* R1818 - AIF1TX4MIX Input 2 Source */
[0x071B] = 0x0080, /* R1819 - AIF1TX4MIX Input 2 Volume */
[0x071C] = 0x0000, /* R1820 - AIF1TX4MIX Input 3 Source */
[0x071D] = 0x0080, /* R1821 - AIF1TX4MIX Input 3 Volume */
[0x071E] = 0x0000, /* R1822 - AIF1TX4MIX Input 4 Source */
[0x071F] = 0x0080, /* R1823 - AIF1TX4MIX Input 4 Volume */
[0x0720] = 0x0000, /* R1824 - AIF1TX5MIX Input 1 Source */
[0x0721] = 0x0080, /* R1825 - AIF1TX5MIX Input 1 Volume */
[0x0722] = 0x0000, /* R1826 - AIF1TX5MIX Input 2 Source */
[0x0723] = 0x0080, /* R1827 - AIF1TX5MIX Input 2 Volume */
[0x0724] = 0x0000, /* R1828 - AIF1TX5MIX Input 3 Source */
[0x0725] = 0x0080, /* R1829 - AIF1TX5MIX Input 3 Volume */
[0x0726] = 0x0000, /* R1830 - AIF1TX5MIX Input 4 Source */
[0x0727] = 0x0080, /* R1831 - AIF1TX5MIX Input 4 Volume */
[0x0728] = 0x0000, /* R1832 - AIF1TX6MIX Input 1 Source */
[0x0729] = 0x0080, /* R1833 - AIF1TX6MIX Input 1 Volume */
[0x072A] = 0x0000, /* R1834 - AIF1TX6MIX Input 2 Source */
[0x072B] = 0x0080, /* R1835 - AIF1TX6MIX Input 2 Volume */
[0x072C] = 0x0000, /* R1836 - AIF1TX6MIX Input 3 Source */
[0x072D] = 0x0080, /* R1837 - AIF1TX6MIX Input 3 Volume */
[0x072E] = 0x0000, /* R1838 - AIF1TX6MIX Input 4 Source */
[0x072F] = 0x0080, /* R1839 - AIF1TX6MIX Input 4 Volume */
[0x0730] = 0x0000, /* R1840 - AIF1TX7MIX Input 1 Source */
[0x0731] = 0x0080, /* R1841 - AIF1TX7MIX Input 1 Volume */
[0x0732] = 0x0000, /* R1842 - AIF1TX7MIX Input 2 Source */
[0x0733] = 0x0080, /* R1843 - AIF1TX7MIX Input 2 Volume */
[0x0734] = 0x0000, /* R1844 - AIF1TX7MIX Input 3 Source */
[0x0735] = 0x0080, /* R1845 - AIF1TX7MIX Input 3 Volume */
[0x0736] = 0x0000, /* R1846 - AIF1TX7MIX Input 4 Source */
[0x0737] = 0x0080, /* R1847 - AIF1TX7MIX Input 4 Volume */
[0x0738] = 0x0000, /* R1848 - AIF1TX8MIX Input 1 Source */
[0x0739] = 0x0080, /* R1849 - AIF1TX8MIX Input 1 Volume */
[0x073A] = 0x0000, /* R1850 - AIF1TX8MIX Input 2 Source */
[0x073B] = 0x0080, /* R1851 - AIF1TX8MIX Input 2 Volume */
[0x073C] = 0x0000, /* R1852 - AIF1TX8MIX Input 3 Source */
[0x073D] = 0x0080, /* R1853 - AIF1TX8MIX Input 3 Volume */
[0x073E] = 0x0000, /* R1854 - AIF1TX8MIX Input 4 Source */
[0x073F] = 0x0080, /* R1855 - AIF1TX8MIX Input 4 Volume */
[0x0740] = 0x0000, /* R1856 - AIF2TX1MIX Input 1 Source */
[0x0741] = 0x0080, /* R1857 - AIF2TX1MIX Input 1 Volume */
[0x0742] = 0x0000, /* R1858 - AIF2TX1MIX Input 2 Source */
[0x0743] = 0x0080, /* R1859 - AIF2TX1MIX Input 2 Volume */
[0x0744] = 0x0000, /* R1860 - AIF2TX1MIX Input 3 Source */
[0x0745] = 0x0080, /* R1861 - AIF2TX1MIX Input 3 Volume */
[0x0746] = 0x0000, /* R1862 - AIF2TX1MIX Input 4 Source */
[0x0747] = 0x0080, /* R1863 - AIF2TX1MIX Input 4 Volume */
[0x0748] = 0x0000, /* R1864 - AIF2TX2MIX Input 1 Source */
[0x0749] = 0x0080, /* R1865 - AIF2TX2MIX Input 1 Volume */
[0x074A] = 0x0000, /* R1866 - AIF2TX2MIX Input 2 Source */
[0x074B] = 0x0080, /* R1867 - AIF2TX2MIX Input 2 Volume */
[0x074C] = 0x0000, /* R1868 - AIF2TX2MIX Input 3 Source */
[0x074D] = 0x0080, /* R1869 - AIF2TX2MIX Input 3 Volume */
[0x074E] = 0x0000, /* R1870 - AIF2TX2MIX Input 4 Source */
[0x074F] = 0x0080, /* R1871 - AIF2TX2MIX Input 4 Volume */
[0x0780] = 0x0000, /* R1920 - AIF3TX1MIX Input 1 Source */
[0x0781] = 0x0080, /* R1921 - AIF3TX1MIX Input 1 Volume */
[0x0782] = 0x0000, /* R1922 - AIF3TX1MIX Input 2 Source */
[0x0783] = 0x0080, /* R1923 - AIF3TX1MIX Input 2 Volume */
[0x0784] = 0x0000, /* R1924 - AIF3TX1MIX Input 3 Source */
[0x0785] = 0x0080, /* R1925 - AIF3TX1MIX Input 3 Volume */
[0x0786] = 0x0000, /* R1926 - AIF3TX1MIX Input 4 Source */
[0x0787] = 0x0080, /* R1927 - AIF3TX1MIX Input 4 Volume */
[0x0788] = 0x0000, /* R1928 - AIF3TX2MIX Input 1 Source */
[0x0789] = 0x0080, /* R1929 - AIF3TX2MIX Input 1 Volume */
[0x078A] = 0x0000, /* R1930 - AIF3TX2MIX Input 2 Source */
[0x078B] = 0x0080, /* R1931 - AIF3TX2MIX Input 2 Volume */
[0x078C] = 0x0000, /* R1932 - AIF3TX2MIX Input 3 Source */
[0x078D] = 0x0080, /* R1933 - AIF3TX2MIX Input 3 Volume */
[0x078E] = 0x0000, /* R1934 - AIF3TX2MIX Input 4 Source */
[0x078F] = 0x0080, /* R1935 - AIF3TX2MIX Input 4 Volume */
[0x0880] = 0x0000, /* R2176 - EQ1MIX Input 1 Source */
[0x0881] = 0x0080, /* R2177 - EQ1MIX Input 1 Volume */
[0x0882] = 0x0000, /* R2178 - EQ1MIX Input 2 Source */
[0x0883] = 0x0080, /* R2179 - EQ1MIX Input 2 Volume */
[0x0884] = 0x0000, /* R2180 - EQ1MIX Input 3 Source */
[0x0885] = 0x0080, /* R2181 - EQ1MIX Input 3 Volume */
[0x0886] = 0x0000, /* R2182 - EQ1MIX Input 4 Source */
[0x0887] = 0x0080, /* R2183 - EQ1MIX Input 4 Volume */
[0x0888] = 0x0000, /* R2184 - EQ2MIX Input 1 Source */
[0x0889] = 0x0080, /* R2185 - EQ2MIX Input 1 Volume */
[0x088A] = 0x0000, /* R2186 - EQ2MIX Input 2 Source */
[0x088B] = 0x0080, /* R2187 - EQ2MIX Input 2 Volume */
[0x088C] = 0x0000, /* R2188 - EQ2MIX Input 3 Source */
[0x088D] = 0x0080, /* R2189 - EQ2MIX Input 3 Volume */
[0x088E] = 0x0000, /* R2190 - EQ2MIX Input 4 Source */
[0x088F] = 0x0080, /* R2191 - EQ2MIX Input 4 Volume */
[0x0890] = 0x0000, /* R2192 - EQ3MIX Input 1 Source */
[0x0891] = 0x0080, /* R2193 - EQ3MIX Input 1 Volume */
[0x0892] = 0x0000, /* R2194 - EQ3MIX Input 2 Source */
[0x0893] = 0x0080, /* R2195 - EQ3MIX Input 2 Volume */
[0x0894] = 0x0000, /* R2196 - EQ3MIX Input 3 Source */
[0x0895] = 0x0080, /* R2197 - EQ3MIX Input 3 Volume */
[0x0896] = 0x0000, /* R2198 - EQ3MIX Input 4 Source */
[0x0897] = 0x0080, /* R2199 - EQ3MIX Input 4 Volume */
[0x0898] = 0x0000, /* R2200 - EQ4MIX Input 1 Source */
[0x0899] = 0x0080, /* R2201 - EQ4MIX Input 1 Volume */
[0x089A] = 0x0000, /* R2202 - EQ4MIX Input 2 Source */
[0x089B] = 0x0080, /* R2203 - EQ4MIX Input 2 Volume */
[0x089C] = 0x0000, /* R2204 - EQ4MIX Input 3 Source */
[0x089D] = 0x0080, /* R2205 - EQ4MIX Input 3 Volume */
[0x089E] = 0x0000, /* R2206 - EQ4MIX Input 4 Source */
[0x089F] = 0x0080, /* R2207 - EQ4MIX Input 4 Volume */
[0x08C0] = 0x0000, /* R2240 - DRC1LMIX Input 1 Source */
[0x08C1] = 0x0080, /* R2241 - DRC1LMIX Input 1 Volume */
[0x08C2] = 0x0000, /* R2242 - DRC1LMIX Input 2 Source */
[0x08C3] = 0x0080, /* R2243 - DRC1LMIX Input 2 Volume */
[0x08C4] = 0x0000, /* R2244 - DRC1LMIX Input 3 Source */
[0x08C5] = 0x0080, /* R2245 - DRC1LMIX Input 3 Volume */
[0x08C6] = 0x0000, /* R2246 - DRC1LMIX Input 4 Source */
[0x08C7] = 0x0080, /* R2247 - DRC1LMIX Input 4 Volume */
[0x08C8] = 0x0000, /* R2248 - DRC1RMIX Input 1 Source */
[0x08C9] = 0x0080, /* R2249 - DRC1RMIX Input 1 Volume */
[0x08CA] = 0x0000, /* R2250 - DRC1RMIX Input 2 Source */
[0x08CB] = 0x0080, /* R2251 - DRC1RMIX Input 2 Volume */
[0x08CC] = 0x0000, /* R2252 - DRC1RMIX Input 3 Source */
[0x08CD] = 0x0080, /* R2253 - DRC1RMIX Input 3 Volume */
[0x08CE] = 0x0000, /* R2254 - DRC1RMIX Input 4 Source */
[0x08CF] = 0x0080, /* R2255 - DRC1RMIX Input 4 Volume */
[0x0900] = 0x0000, /* R2304 - HPLP1MIX Input 1 Source */
[0x0901] = 0x0080, /* R2305 - HPLP1MIX Input 1 Volume */
[0x0902] = 0x0000, /* R2306 - HPLP1MIX Input 2 Source */
[0x0903] = 0x0080, /* R2307 - HPLP1MIX Input 2 Volume */
[0x0904] = 0x0000, /* R2308 - HPLP1MIX Input 3 Source */
[0x0905] = 0x0080, /* R2309 - HPLP1MIX Input 3 Volume */
[0x0906] = 0x0000, /* R2310 - HPLP1MIX Input 4 Source */
[0x0907] = 0x0080, /* R2311 - HPLP1MIX Input 4 Volume */
[0x0908] = 0x0000, /* R2312 - HPLP2MIX Input 1 Source */
[0x0909] = 0x0080, /* R2313 - HPLP2MIX Input 1 Volume */
[0x090A] = 0x0000, /* R2314 - HPLP2MIX Input 2 Source */
[0x090B] = 0x0080, /* R2315 - HPLP2MIX Input 2 Volume */
[0x090C] = 0x0000, /* R2316 - HPLP2MIX Input 3 Source */
[0x090D] = 0x0080, /* R2317 - HPLP2MIX Input 3 Volume */
[0x090E] = 0x0000, /* R2318 - HPLP2MIX Input 4 Source */
[0x090F] = 0x0080, /* R2319 - HPLP2MIX Input 4 Volume */
[0x0910] = 0x0000, /* R2320 - HPLP3MIX Input 1 Source */
[0x0911] = 0x0080, /* R2321 - HPLP3MIX Input 1 Volume */
[0x0912] = 0x0000, /* R2322 - HPLP3MIX Input 2 Source */
[0x0913] = 0x0080, /* R2323 - HPLP3MIX Input 2 Volume */
[0x0914] = 0x0000, /* R2324 - HPLP3MIX Input 3 Source */
[0x0915] = 0x0080, /* R2325 - HPLP3MIX Input 3 Volume */
[0x0916] = 0x0000, /* R2326 - HPLP3MIX Input 4 Source */
[0x0917] = 0x0080, /* R2327 - HPLP3MIX Input 4 Volume */
[0x0918] = 0x0000, /* R2328 - HPLP4MIX Input 1 Source */
[0x0919] = 0x0080, /* R2329 - HPLP4MIX Input 1 Volume */
[0x091A] = 0x0000, /* R2330 - HPLP4MIX Input 2 Source */
[0x091B] = 0x0080, /* R2331 - HPLP4MIX Input 2 Volume */
[0x091C] = 0x0000, /* R2332 - HPLP4MIX Input 3 Source */
[0x091D] = 0x0080, /* R2333 - HPLP4MIX Input 3 Volume */
[0x091E] = 0x0000, /* R2334 - HPLP4MIX Input 4 Source */
[0x091F] = 0x0080, /* R2335 - HPLP4MIX Input 4 Volume */
[0x0940] = 0x0000, /* R2368 - DSP1LMIX Input 1 Source */
[0x0941] = 0x0080, /* R2369 - DSP1LMIX Input 1 Volume */
[0x0942] = 0x0000, /* R2370 - DSP1LMIX Input 2 Source */
[0x0943] = 0x0080, /* R2371 - DSP1LMIX Input 2 Volume */
[0x0944] = 0x0000, /* R2372 - DSP1LMIX Input 3 Source */
[0x0945] = 0x0080, /* R2373 - DSP1LMIX Input 3 Volume */
[0x0946] = 0x0000, /* R2374 - DSP1LMIX Input 4 Source */
[0x0947] = 0x0080, /* R2375 - DSP1LMIX Input 4 Volume */
[0x0948] = 0x0000, /* R2376 - DSP1RMIX Input 1 Source */
[0x0949] = 0x0080, /* R2377 - DSP1RMIX Input 1 Volume */
[0x094A] = 0x0000, /* R2378 - DSP1RMIX Input 2 Source */
[0x094B] = 0x0080, /* R2379 - DSP1RMIX Input 2 Volume */
[0x094C] = 0x0000, /* R2380 - DSP1RMIX Input 3 Source */
[0x094D] = 0x0080, /* R2381 - DSP1RMIX Input 3 Volume */
[0x094E] = 0x0000, /* R2382 - DSP1RMIX Input 4 Source */
[0x094F] = 0x0080, /* R2383 - DSP1RMIX Input 4 Volume */
[0x0950] = 0x0000, /* R2384 - DSP1AUX1MIX Input 1 Source */
[0x0958] = 0x0000, /* R2392 - DSP1AUX2MIX Input 1 Source */
[0x0960] = 0x0000, /* R2400 - DSP1AUX3MIX Input 1 Source */
[0x0968] = 0x0000, /* R2408 - DSP1AUX4MIX Input 1 Source */
[0x0970] = 0x0000, /* R2416 - DSP1AUX5MIX Input 1 Source */
[0x0978] = 0x0000, /* R2424 - DSP1AUX6MIX Input 1 Source */
[0x0980] = 0x0000, /* R2432 - DSP2LMIX Input 1 Source */
[0x0981] = 0x0080, /* R2433 - DSP2LMIX Input 1 Volume */
[0x0982] = 0x0000, /* R2434 - DSP2LMIX Input 2 Source */
[0x0983] = 0x0080, /* R2435 - DSP2LMIX Input 2 Volume */
[0x0984] = 0x0000, /* R2436 - DSP2LMIX Input 3 Source */
[0x0985] = 0x0080, /* R2437 - DSP2LMIX Input 3 Volume */
[0x0986] = 0x0000, /* R2438 - DSP2LMIX Input 4 Source */
[0x0987] = 0x0080, /* R2439 - DSP2LMIX Input 4 Volume */
[0x0988] = 0x0000, /* R2440 - DSP2RMIX Input 1 Source */
[0x0989] = 0x0080, /* R2441 - DSP2RMIX Input 1 Volume */
[0x098A] = 0x0000, /* R2442 - DSP2RMIX Input 2 Source */
[0x098B] = 0x0080, /* R2443 - DSP2RMIX Input 2 Volume */
[0x098C] = 0x0000, /* R2444 - DSP2RMIX Input 3 Source */
[0x098D] = 0x0080, /* R2445 - DSP2RMIX Input 3 Volume */
[0x098E] = 0x0000, /* R2446 - DSP2RMIX Input 4 Source */
[0x098F] = 0x0080, /* R2447 - DSP2RMIX Input 4 Volume */
[0x0990] = 0x0000, /* R2448 - DSP2AUX1MIX Input 1 Source */
[0x0998] = 0x0000, /* R2456 - DSP2AUX2MIX Input 1 Source */
[0x09A0] = 0x0000, /* R2464 - DSP2AUX3MIX Input 1 Source */
[0x09A8] = 0x0000, /* R2472 - DSP2AUX4MIX Input 1 Source */
[0x09B0] = 0x0000, /* R2480 - DSP2AUX5MIX Input 1 Source */
[0x09B8] = 0x0000, /* R2488 - DSP2AUX6MIX Input 1 Source */
[0x09C0] = 0x0000, /* R2496 - DSP3LMIX Input 1 Source */
[0x09C1] = 0x0080, /* R2497 - DSP3LMIX Input 1 Volume */
[0x09C2] = 0x0000, /* R2498 - DSP3LMIX Input 2 Source */
[0x09C3] = 0x0080, /* R2499 - DSP3LMIX Input 2 Volume */
[0x09C4] = 0x0000, /* R2500 - DSP3LMIX Input 3 Source */
[0x09C5] = 0x0080, /* R2501 - DSP3LMIX Input 3 Volume */
[0x09C6] = 0x0000, /* R2502 - DSP3LMIX Input 4 Source */
[0x09C7] = 0x0080, /* R2503 - DSP3LMIX Input 4 Volume */
[0x09C8] = 0x0000, /* R2504 - DSP3RMIX Input 1 Source */
[0x09C9] = 0x0080, /* R2505 - DSP3RMIX Input 1 Volume */
[0x09CA] = 0x0000, /* R2506 - DSP3RMIX Input 2 Source */
[0x09CB] = 0x0080, /* R2507 - DSP3RMIX Input 2 Volume */
[0x09CC] = 0x0000, /* R2508 - DSP3RMIX Input 3 Source */
[0x09CD] = 0x0080, /* R2509 - DSP3RMIX Input 3 Volume */
[0x09CE] = 0x0000, /* R2510 - DSP3RMIX Input 4 Source */
[0x09CF] = 0x0080, /* R2511 - DSP3RMIX Input 4 Volume */
[0x09D0] = 0x0000, /* R2512 - DSP3AUX1MIX Input 1 Source */
[0x09D8] = 0x0000, /* R2520 - DSP3AUX2MIX Input 1 Source */
[0x09E0] = 0x0000, /* R2528 - DSP3AUX3MIX Input 1 Source */
[0x09E8] = 0x0000, /* R2536 - DSP3AUX4MIX Input 1 Source */
[0x09F0] = 0x0000, /* R2544 - DSP3AUX5MIX Input 1 Source */
[0x09F8] = 0x0000, /* R2552 - DSP3AUX6MIX Input 1 Source */
[0x0A80] = 0x0000, /* R2688 - ASRC1LMIX Input 1 Source */
[0x0A88] = 0x0000, /* R2696 - ASRC1RMIX Input 1 Source */
[0x0A90] = 0x0000, /* R2704 - ASRC2LMIX Input 1 Source */
[0x0A98] = 0x0000, /* R2712 - ASRC2RMIX Input 1 Source */
[0x0B00] = 0x0000, /* R2816 - ISRC1DEC1MIX Input 1 Source */
[0x0B08] = 0x0000, /* R2824 - ISRC1DEC2MIX Input 1 Source */
[0x0B10] = 0x0000, /* R2832 - ISRC1DEC3MIX Input 1 Source */
[0x0B18] = 0x0000, /* R2840 - ISRC1DEC4MIX Input 1 Source */
[0x0B20] = 0x0000, /* R2848 - ISRC1INT1MIX Input 1 Source */
[0x0B28] = 0x0000, /* R2856 - ISRC1INT2MIX Input 1 Source */
[0x0B30] = 0x0000, /* R2864 - ISRC1INT3MIX Input 1 Source */
[0x0B38] = 0x0000, /* R2872 - ISRC1INT4MIX Input 1 Source */
[0x0B40] = 0x0000, /* R2880 - ISRC2DEC1MIX Input 1 Source */
[0x0B48] = 0x0000, /* R2888 - ISRC2DEC2MIX Input 1 Source */
[0x0B50] = 0x0000, /* R2896 - ISRC2DEC3MIX Input 1 Source */
[0x0B58] = 0x0000, /* R2904 - ISRC2DEC4MIX Input 1 Source */
[0x0B60] = 0x0000, /* R2912 - ISRC2INT1MIX Input 1 Source */
[0x0B68] = 0x0000, /* R2920 - ISRC2INT2MIX Input 1 Source */
[0x0B70] = 0x0000, /* R2928 - ISRC2INT3MIX Input 1 Source */
[0x0B78] = 0x0000, /* R2936 - ISRC2INT4MIX Input 1 Source */
[0x0C00] = 0xA001, /* R3072 - GPIO CTRL 1 */
[0x0C01] = 0xA001, /* R3073 - GPIO CTRL 2 */
[0x0C02] = 0xA001, /* R3074 - GPIO CTRL 3 */
[0x0C03] = 0xA001, /* R3075 - GPIO CTRL 4 */
[0x0C04] = 0xA001, /* R3076 - GPIO CTRL 5 */
[0x0C05] = 0xA001, /* R3077 - GPIO CTRL 6 */
[0x0C23] = 0x4003, /* R3107 - Misc Pad Ctrl 1 */
[0x0C24] = 0x0000, /* R3108 - Misc Pad Ctrl 2 */
[0x0C25] = 0x0000, /* R3109 - Misc Pad Ctrl 3 */
[0x0C26] = 0x0000, /* R3110 - Misc Pad Ctrl 4 */
[0x0C27] = 0x0000, /* R3111 - Misc Pad Ctrl 5 */
[0x0C28] = 0x0000, /* R3112 - Misc GPIO 1 */
[0x0D00] = 0x0000, /* R3328 - Interrupt Status 1 */
[0x0D01] = 0x0000, /* R3329 - Interrupt Status 2 */
[0x0D02] = 0x0000, /* R3330 - Interrupt Status 3 */
[0x0D03] = 0x0000, /* R3331 - Interrupt Status 4 */
[0x0D04] = 0x0000, /* R3332 - Interrupt Raw Status 2 */
[0x0D05] = 0x0000, /* R3333 - Interrupt Raw Status 3 */
[0x0D06] = 0x0000, /* R3334 - Interrupt Raw Status 4 */
[0x0D07] = 0xFFFF, /* R3335 - Interrupt Status 1 Mask */
[0x0D08] = 0xFFFF, /* R3336 - Interrupt Status 2 Mask */
[0x0D09] = 0xFFFF, /* R3337 - Interrupt Status 3 Mask */
[0x0D0A] = 0xFFFF, /* R3338 - Interrupt Status 4 Mask */
[0x0D1F] = 0x0000, /* R3359 - Interrupt Control */
[0x0D20] = 0xFFFF, /* R3360 - IRQ Debounce 1 */
[0x0D21] = 0xFFFF, /* R3361 - IRQ Debounce 2 */
[0x0E00] = 0x0000, /* R3584 - FX_Ctrl */
[0x0E10] = 0x6318, /* R3600 - EQ1_1 */
[0x0E11] = 0x6300, /* R3601 - EQ1_2 */
[0x0E12] = 0x0FC8, /* R3602 - EQ1_3 */
[0x0E13] = 0x03FE, /* R3603 - EQ1_4 */
[0x0E14] = 0x00E0, /* R3604 - EQ1_5 */
[0x0E15] = 0x1EC4, /* R3605 - EQ1_6 */
[0x0E16] = 0xF136, /* R3606 - EQ1_7 */
[0x0E17] = 0x0409, /* R3607 - EQ1_8 */
[0x0E18] = 0x04CC, /* R3608 - EQ1_9 */
[0x0E19] = 0x1C9B, /* R3609 - EQ1_10 */
[0x0E1A] = 0xF337, /* R3610 - EQ1_11 */
[0x0E1B] = 0x040B, /* R3611 - EQ1_12 */
[0x0E1C] = 0x0CBB, /* R3612 - EQ1_13 */
[0x0E1D] = 0x16F8, /* R3613 - EQ1_14 */
[0x0E1E] = 0xF7D9, /* R3614 - EQ1_15 */
[0x0E1F] = 0x040A, /* R3615 - EQ1_16 */
[0x0E20] = 0x1F14, /* R3616 - EQ1_17 */
[0x0E21] = 0x058C, /* R3617 - EQ1_18 */
[0x0E22] = 0x0563, /* R3618 - EQ1_19 */
[0x0E23] = 0x4000, /* R3619 - EQ1_20 */
[0x0E26] = 0x6318, /* R3622 - EQ2_1 */
[0x0E27] = 0x6300, /* R3623 - EQ2_2 */
[0x0E28] = 0x0FC8, /* R3624 - EQ2_3 */
[0x0E29] = 0x03FE, /* R3625 - EQ2_4 */
[0x0E2A] = 0x00E0, /* R3626 - EQ2_5 */
[0x0E2B] = 0x1EC4, /* R3627 - EQ2_6 */
[0x0E2C] = 0xF136, /* R3628 - EQ2_7 */
[0x0E2D] = 0x0409, /* R3629 - EQ2_8 */
[0x0E2E] = 0x04CC, /* R3630 - EQ2_9 */
[0x0E2F] = 0x1C9B, /* R3631 - EQ2_10 */
[0x0E30] = 0xF337, /* R3632 - EQ2_11 */
[0x0E31] = 0x040B, /* R3633 - EQ2_12 */
[0x0E32] = 0x0CBB, /* R3634 - EQ2_13 */
[0x0E33] = 0x16F8, /* R3635 - EQ2_14 */
[0x0E34] = 0xF7D9, /* R3636 - EQ2_15 */
[0x0E35] = 0x040A, /* R3637 - EQ2_16 */
[0x0E36] = 0x1F14, /* R3638 - EQ2_17 */
[0x0E37] = 0x058C, /* R3639 - EQ2_18 */
[0x0E38] = 0x0563, /* R3640 - EQ2_19 */
[0x0E39] = 0x4000, /* R3641 - EQ2_20 */
[0x0E3C] = 0x6318, /* R3644 - EQ3_1 */
[0x0E3D] = 0x6300, /* R3645 - EQ3_2 */
[0x0E3E] = 0x0FC8, /* R3646 - EQ3_3 */
[0x0E3F] = 0x03FE, /* R3647 - EQ3_4 */
[0x0E40] = 0x00E0, /* R3648 - EQ3_5 */
[0x0E41] = 0x1EC4, /* R3649 - EQ3_6 */
[0x0E42] = 0xF136, /* R3650 - EQ3_7 */
[0x0E43] = 0x0409, /* R3651 - EQ3_8 */
[0x0E44] = 0x04CC, /* R3652 - EQ3_9 */
[0x0E45] = 0x1C9B, /* R3653 - EQ3_10 */
[0x0E46] = 0xF337, /* R3654 - EQ3_11 */
[0x0E47] = 0x040B, /* R3655 - EQ3_12 */
[0x0E48] = 0x0CBB, /* R3656 - EQ3_13 */
[0x0E49] = 0x16F8, /* R3657 - EQ3_14 */
[0x0E4A] = 0xF7D9, /* R3658 - EQ3_15 */
[0x0E4B] = 0x040A, /* R3659 - EQ3_16 */
[0x0E4C] = 0x1F14, /* R3660 - EQ3_17 */
[0x0E4D] = 0x058C, /* R3661 - EQ3_18 */
[0x0E4E] = 0x0563, /* R3662 - EQ3_19 */
[0x0E4F] = 0x4000, /* R3663 - EQ3_20 */
[0x0E52] = 0x6318, /* R3666 - EQ4_1 */
[0x0E53] = 0x6300, /* R3667 - EQ4_2 */
[0x0E54] = 0x0FC8, /* R3668 - EQ4_3 */
[0x0E55] = 0x03FE, /* R3669 - EQ4_4 */
[0x0E56] = 0x00E0, /* R3670 - EQ4_5 */
[0x0E57] = 0x1EC4, /* R3671 - EQ4_6 */
[0x0E58] = 0xF136, /* R3672 - EQ4_7 */
[0x0E59] = 0x0409, /* R3673 - EQ4_8 */
[0x0E5A] = 0x04CC, /* R3674 - EQ4_9 */
[0x0E5B] = 0x1C9B, /* R3675 - EQ4_10 */
[0x0E5C] = 0xF337, /* R3676 - EQ4_11 */
[0x0E5D] = 0x040B, /* R3677 - EQ4_12 */
[0x0E5E] = 0x0CBB, /* R3678 - EQ4_13 */
[0x0E5F] = 0x16F8, /* R3679 - EQ4_14 */
[0x0E60] = 0xF7D9, /* R3680 - EQ4_15 */
[0x0E61] = 0x040A, /* R3681 - EQ4_16 */
[0x0E62] = 0x1F14, /* R3682 - EQ4_17 */
[0x0E63] = 0x058C, /* R3683 - EQ4_18 */
[0x0E64] = 0x0563, /* R3684 - EQ4_19 */
[0x0E65] = 0x4000, /* R3685 - EQ4_20 */
[0x0E80] = 0x0018, /* R3712 - DRC1 ctrl1 */
[0x0E81] = 0x0933, /* R3713 - DRC1 ctrl2 */
[0x0E82] = 0x0018, /* R3714 - DRC1 ctrl3 */
[0x0E83] = 0x0000, /* R3715 - DRC1 ctrl4 */
[0x0E84] = 0x0000, /* R3716 - DRC1 ctrl5 */
[0x0EC0] = 0x0000, /* R3776 - HPLPF1_1 */
[0x0EC1] = 0x0000, /* R3777 - HPLPF1_2 */
[0x0EC4] = 0x0000, /* R3780 - HPLPF2_1 */
[0x0EC5] = 0x0000, /* R3781 - HPLPF2_2 */
[0x0EC8] = 0x0000, /* R3784 - HPLPF3_1 */
[0x0EC9] = 0x0000, /* R3785 - HPLPF3_2 */
[0x0ECC] = 0x0000, /* R3788 - HPLPF4_1 */
[0x0ECD] = 0x0000, /* R3789 - HPLPF4_2 */
[0x4000] = 0x0000, /* R16384 - DSP1 DM 0 */
[0x4001] = 0x0000, /* R16385 - DSP1 DM 1 */
[0x4002] = 0x0000, /* R16386 - DSP1 DM 2 */
[0x4003] = 0x0000, /* R16387 - DSP1 DM 3 */
[0x41FC] = 0x0000, /* R16892 - DSP1 DM 508 */
[0x41FD] = 0x0000, /* R16893 - DSP1 DM 509 */
[0x41FE] = 0x0000, /* R16894 - DSP1 DM 510 */
[0x41FF] = 0x0000, /* R16895 - DSP1 DM 511 */
[0x4800] = 0x0000, /* R18432 - DSP1 PM 0 */
[0x4801] = 0x0000, /* R18433 - DSP1 PM 1 */
[0x4802] = 0x0000, /* R18434 - DSP1 PM 2 */
[0x4803] = 0x0000, /* R18435 - DSP1 PM 3 */
[0x4804] = 0x0000, /* R18436 - DSP1 PM 4 */
[0x4805] = 0x0000, /* R18437 - DSP1 PM 5 */
[0x4DFA] = 0x0000, /* R19962 - DSP1 PM 1530 */
[0x4DFB] = 0x0000, /* R19963 - DSP1 PM 1531 */
[0x4DFC] = 0x0000, /* R19964 - DSP1 PM 1532 */
[0x4DFD] = 0x0000, /* R19965 - DSP1 PM 1533 */
[0x4DFE] = 0x0000, /* R19966 - DSP1 PM 1534 */
[0x4DFF] = 0x0000, /* R19967 - DSP1 PM 1535 */
[0x5000] = 0x0000, /* R20480 - DSP1 ZM 0 */
[0x5001] = 0x0000, /* R20481 - DSP1 ZM 1 */
[0x5002] = 0x0000, /* R20482 - DSP1 ZM 2 */
[0x5003] = 0x0000, /* R20483 - DSP1 ZM 3 */
[0x57FC] = 0x0000, /* R22524 - DSP1 ZM 2044 */
[0x57FD] = 0x0000, /* R22525 - DSP1 ZM 2045 */
[0x57FE] = 0x0000, /* R22526 - DSP1 ZM 2046 */
[0x57FF] = 0x0000, /* R22527 - DSP1 ZM 2047 */
[0x6000] = 0x0000, /* R24576 - DSP2 DM 0 */
[0x6001] = 0x0000, /* R24577 - DSP2 DM 1 */
[0x6002] = 0x0000, /* R24578 - DSP2 DM 2 */
[0x6003] = 0x0000, /* R24579 - DSP2 DM 3 */
[0x61FC] = 0x0000, /* R25084 - DSP2 DM 508 */
[0x61FD] = 0x0000, /* R25085 - DSP2 DM 509 */
[0x61FE] = 0x0000, /* R25086 - DSP2 DM 510 */
[0x61FF] = 0x0000, /* R25087 - DSP2 DM 511 */
[0x6800] = 0x0000, /* R26624 - DSP2 PM 0 */
[0x6801] = 0x0000, /* R26625 - DSP2 PM 1 */
[0x6802] = 0x0000, /* R26626 - DSP2 PM 2 */
[0x6803] = 0x0000, /* R26627 - DSP2 PM 3 */
[0x6804] = 0x0000, /* R26628 - DSP2 PM 4 */
[0x6805] = 0x0000, /* R26629 - DSP2 PM 5 */
[0x6DFA] = 0x0000, /* R28154 - DSP2 PM 1530 */
[0x6DFB] = 0x0000, /* R28155 - DSP2 PM 1531 */
[0x6DFC] = 0x0000, /* R28156 - DSP2 PM 1532 */
[0x6DFD] = 0x0000, /* R28157 - DSP2 PM 1533 */
[0x6DFE] = 0x0000, /* R28158 - DSP2 PM 1534 */
[0x6DFF] = 0x0000, /* R28159 - DSP2 PM 1535 */
[0x7000] = 0x0000, /* R28672 - DSP2 ZM 0 */
[0x7001] = 0x0000, /* R28673 - DSP2 ZM 1 */
[0x7002] = 0x0000, /* R28674 - DSP2 ZM 2 */
[0x7003] = 0x0000, /* R28675 - DSP2 ZM 3 */
[0x77FC] = 0x0000, /* R30716 - DSP2 ZM 2044 */
[0x77FD] = 0x0000, /* R30717 - DSP2 ZM 2045 */
[0x77FE] = 0x0000, /* R30718 - DSP2 ZM 2046 */
[0x77FF] = 0x0000, /* R30719 - DSP2 ZM 2047 */
[0x8000] = 0x0000, /* R32768 - DSP3 DM 0 */
[0x8001] = 0x0000, /* R32769 - DSP3 DM 1 */
[0x8002] = 0x0000, /* R32770 - DSP3 DM 2 */
[0x8003] = 0x0000, /* R32771 - DSP3 DM 3 */
[0x81FC] = 0x0000, /* R33276 - DSP3 DM 508 */
[0x81FD] = 0x0000, /* R33277 - DSP3 DM 509 */
[0x81FE] = 0x0000, /* R33278 - DSP3 DM 510 */
[0x81FF] = 0x0000, /* R33279 - DSP3 DM 511 */
[0x8800] = 0x0000, /* R34816 - DSP3 PM 0 */
[0x8801] = 0x0000, /* R34817 - DSP3 PM 1 */
[0x8802] = 0x0000, /* R34818 - DSP3 PM 2 */
[0x8803] = 0x0000, /* R34819 - DSP3 PM 3 */
[0x8804] = 0x0000, /* R34820 - DSP3 PM 4 */
[0x8805] = 0x0000, /* R34821 - DSP3 PM 5 */
[0x8DFA] = 0x0000, /* R36346 - DSP3 PM 1530 */
[0x8DFB] = 0x0000, /* R36347 - DSP3 PM 1531 */
[0x8DFC] = 0x0000, /* R36348 - DSP3 PM 1532 */
[0x8DFD] = 0x0000, /* R36349 - DSP3 PM 1533 */
[0x8DFE] = 0x0000, /* R36350 - DSP3 PM 1534 */
[0x8DFF] = 0x0000, /* R36351 - DSP3 PM 1535 */
[0x9000] = 0x0000, /* R36864 - DSP3 ZM 0 */
[0x9001] = 0x0000, /* R36865 - DSP3 ZM 1 */
[0x9002] = 0x0000, /* R36866 - DSP3 ZM 2 */
[0x9003] = 0x0000, /* R36867 - DSP3 ZM 3 */
[0x97FC] = 0x0000, /* R38908 - DSP3 ZM 2044 */
[0x97FD] = 0x0000, /* R38909 - DSP3 ZM 2045 */
[0x97FE] = 0x0000, /* R38910 - DSP3 ZM 2046 */
[0x97FF] = 0x0000 /* R38911 - DSP3 ZM 2047 */
};
/*
* wm5100.c -- WM5100 ALSA SoC Audio driver
*
* Copyright 2011 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/gcd.h>
#include <linux/gpio.h>
#include <linux/i2c.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
#include <linux/regulator/fixed.h>
#include <linux/slab.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/initval.h>
#include <sound/tlv.h>
#include <sound/wm5100.h>
#include "wm5100.h"
#define WM5100_NUM_CORE_SUPPLIES 2
static const char *wm5100_core_supply_names[WM5100_NUM_CORE_SUPPLIES] = {
"DBVDD1",
"LDOVDD", /* If DCVDD is supplied externally specify as LDOVDD */
};
#define WM5100_AIFS 3
#define WM5100_SYNC_SRS 3
struct wm5100_fll {
int fref;
int fout;
int src;
struct completion lock;
};
/* codec private data */
struct wm5100_priv {
struct snd_soc_codec *codec;
struct regulator_bulk_data core_supplies[WM5100_NUM_CORE_SUPPLIES];
struct regulator *cpvdd;
int rev;
int sysclk;
int asyncclk;
bool aif_async[WM5100_AIFS];
bool aif_symmetric[WM5100_AIFS];
int sr_ref[WM5100_SYNC_SRS];
bool out_ena[2];
struct wm5100_fll fll[2];
struct wm5100_pdata pdata;
#ifdef CONFIG_GPIOLIB
struct gpio_chip gpio_chip;
#endif
};
static int wm5100_sr_code[] = {
0,
12000,
24000,
48000,
96000,
192000,
384000,
768000,
0,
11025,
22050,
44100,
88200,
176400,
352800,
705600,
4000,
8000,
16000,
32000,
64000,
128000,
256000,
512000,
};
static int wm5100_sr_regs[WM5100_SYNC_SRS] = {
WM5100_CLOCKING_4,
WM5100_CLOCKING_5,
WM5100_CLOCKING_6,
};
static int wm5100_alloc_sr(struct snd_soc_codec *codec, int rate)
{
struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(codec);
int sr_code, sr_free, i;
for (i = 0; i < ARRAY_SIZE(wm5100_sr_code); i++)
if (wm5100_sr_code[i] == rate)
break;
if (i == ARRAY_SIZE(wm5100_sr_code)) {
dev_err(codec->dev, "Unsupported sample rate: %dHz\n", rate);
return -EINVAL;
}
sr_code = i;
if ((wm5100->sysclk % rate) == 0) {
/* Is this rate already in use? */
sr_free = -1;
for (i = 0; i < ARRAY_SIZE(wm5100_sr_regs); i++) {
if (!wm5100->sr_ref[i] && sr_free == -1) {
sr_free = i;
continue;
}
if ((snd_soc_read(codec, wm5100_sr_regs[i]) &
WM5100_SAMPLE_RATE_1_MASK) == sr_code)
break;
}
if (i < ARRAY_SIZE(wm5100_sr_regs)) {
wm5100->sr_ref[i]++;
dev_dbg(codec->dev, "SR %dHz, slot %d, ref %d\n",
rate, i, wm5100->sr_ref[i]);
return i;
}
if (sr_free == -1) {
dev_err(codec->dev, "All SR slots already in use\n");
return -EBUSY;
}
dev_dbg(codec->dev, "Allocating SR slot %d for %dHz\n",
sr_free, rate);
wm5100->sr_ref[sr_free]++;
snd_soc_update_bits(codec, wm5100_sr_regs[sr_free],
WM5100_SAMPLE_RATE_1_MASK,
sr_code);
return sr_free;
} else {
dev_err(codec->dev,
"SR %dHz incompatible with %dHz SYSCLK and %dHz ASYNCCLK\n",
rate, wm5100->sysclk, wm5100->asyncclk);
return -EINVAL;
}
}
static void wm5100_free_sr(struct snd_soc_codec *codec, int rate)
{
struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(codec);
int i, sr_code;
for (i = 0; i < ARRAY_SIZE(wm5100_sr_code); i++)
if (wm5100_sr_code[i] == rate)
break;
if (i == ARRAY_SIZE(wm5100_sr_code)) {
dev_err(codec->dev, "Unsupported sample rate: %dHz\n", rate);
return;
}
sr_code = wm5100_sr_code[i];
for (i = 0; i < ARRAY_SIZE(wm5100_sr_regs); i++) {
if (!wm5100->sr_ref[i])
continue;
if ((snd_soc_read(codec, wm5100_sr_regs[i]) &
WM5100_SAMPLE_RATE_1_MASK) == sr_code)
break;
}
if (i < ARRAY_SIZE(wm5100_sr_regs)) {
wm5100->sr_ref[i]--;
dev_dbg(codec->dev, "Dereference SR %dHz, count now %d\n",
rate, wm5100->sr_ref[i]);
} else {
dev_warn(codec->dev, "Freeing unreferenced sample rate %dHz\n",
rate);
}
}
static int wm5100_reset(struct snd_soc_codec *codec)
{
struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(codec);
if (wm5100->pdata.reset) {
gpio_set_value_cansleep(wm5100->pdata.reset, 0);
gpio_set_value_cansleep(wm5100->pdata.reset, 1);
return 0;
} else {
return snd_soc_write(codec, WM5100_SOFTWARE_RESET, 0);
}
}
static DECLARE_TLV_DB_SCALE(in_tlv, -6300, 100, 0);
static DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0);
static DECLARE_TLV_DB_SCALE(mixer_tlv, -3200, 100, 0);
static DECLARE_TLV_DB_SCALE(out_tlv, -6400, 100, 0);
static DECLARE_TLV_DB_SCALE(digital_tlv, -6400, 50, 0);
static const char *wm5100_mixer_texts[] = {
"None",
"Tone Generator 1",
"Tone Generator 2",
"AEC loopback",
"IN1L",
"IN1R",
"IN2L",
"IN2R",
"IN3L",
"IN3R",
"IN4L",
"IN4R",
"AIF1RX1",
"AIF1RX2",
"AIF1RX3",
"AIF1RX4",
"AIF1RX5",
"AIF1RX6",
"AIF1RX7",
"AIF1RX8",
"AIF2RX1",
"AIF2RX2",
"AIF3RX1",
"AIF3RX2",
"EQ1",
"EQ2",
"EQ3",
"EQ4",
"DRC1L",
"DRC1R",
"LHPF1",
"LHPF2",
"LHPF3",
"LHPF4",
"DSP1.1",
"DSP1.2",
"DSP1.3",
"DSP1.4",
"DSP1.5",
"DSP1.6",
"DSP2.1",
"DSP2.2",
"DSP2.3",
"DSP2.4",
"DSP2.5",
"DSP2.6",
"DSP3.1",
"DSP3.2",
"DSP3.3",
"DSP3.4",
"DSP3.5",
"DSP3.6",
"ASRC1L",
"ASRC1R",
"ASRC2L",
"ASRC2R",
"ISRC1INT1",
"ISRC1INT2",
"ISRC1INT3",
"ISRC1INT4",
"ISRC2INT1",
"ISRC2INT2",
"ISRC2INT3",
"ISRC2INT4",
"ISRC1DEC1",
"ISRC1DEC2",
"ISRC1DEC3",
"ISRC1DEC4",
"ISRC2DEC1",
"ISRC2DEC2",
"ISRC2DEC3",
"ISRC2DEC4",
};
static int wm5100_mixer_values[] = {
0x00,
0x04, /* Tone */
0x05,
0x08, /* AEC */
0x10, /* Input */
0x11,
0x12,
0x13,
0x14,
0x15,
0x16,
0x17,
0x20, /* AIF */
0x21,
0x22,
0x23,
0x24,
0x25,
0x26,
0x27,
0x28,
0x29,
0x30, /* AIF3 - check */
0x31,
0x50, /* EQ */
0x51,
0x52,
0x53,
0x54,
0x58, /* DRC */
0x59,
0x60, /* LHPF1 */
0x61, /* LHPF2 */
0x62, /* LHPF3 */
0x63, /* LHPF4 */
0x68, /* DSP1 */
0x69,
0x6a,
0x6b,
0x6c,
0x6d,
0x70, /* DSP2 */
0x71,
0x72,
0x73,
0x74,
0x75,
0x78, /* DSP3 */
0x79,
0x7a,
0x7b,
0x7c,
0x7d,
0x90, /* ASRC1 */
0x91,
0x92, /* ASRC2 */
0x93,
0xa0, /* ISRC1DEC1 */
0xa1,
0xa2,
0xa3,
0xa4, /* ISRC1INT1 */
0xa5,
0xa6,
0xa7,
0xa8, /* ISRC2DEC1 */
0xa9,
0xaa,
0xab,
0xac, /* ISRC2INT1 */
0xad,
0xae,
0xaf,
};
#define WM5100_MIXER_CONTROLS(name, base) \
SOC_SINGLE_TLV(name " Input 1 Volume", base + 1 , \
WM5100_MIXER_VOL_SHIFT, 80, 0, mixer_tlv), \
SOC_SINGLE_TLV(name " Input 2 Volume", base + 3 , \
WM5100_MIXER_VOL_SHIFT, 80, 0, mixer_tlv), \
SOC_SINGLE_TLV(name " Input 3 Volume", base + 5 , \
WM5100_MIXER_VOL_SHIFT, 80, 0, mixer_tlv), \
SOC_SINGLE_TLV(name " Input 4 Volume", base + 7 , \
WM5100_MIXER_VOL_SHIFT, 80, 0, mixer_tlv)
#define WM5100_MUX_ENUM_DECL(name, reg) \
SOC_VALUE_ENUM_SINGLE_DECL(name, reg, 0, 0xff, \
wm5100_mixer_texts, wm5100_mixer_values)
#define WM5100_MUX_CTL_DECL(name) \
const struct snd_kcontrol_new name##_mux = \
SOC_DAPM_VALUE_ENUM("Route", name##_enum)
#define WM5100_MIXER_ENUMS(name, base_reg) \
static WM5100_MUX_ENUM_DECL(name##_in1_enum, base_reg); \
static WM5100_MUX_ENUM_DECL(name##_in2_enum, base_reg + 2); \
static WM5100_MUX_ENUM_DECL(name##_in3_enum, base_reg + 4); \
static WM5100_MUX_ENUM_DECL(name##_in4_enum, base_reg + 6); \
static WM5100_MUX_CTL_DECL(name##_in1); \
static WM5100_MUX_CTL_DECL(name##_in2); \
static WM5100_MUX_CTL_DECL(name##_in3); \
static WM5100_MUX_CTL_DECL(name##_in4)
WM5100_MIXER_ENUMS(HPOUT1L, WM5100_OUT1LMIX_INPUT_1_SOURCE);
WM5100_MIXER_ENUMS(HPOUT1R, WM5100_OUT1RMIX_INPUT_1_SOURCE);
WM5100_MIXER_ENUMS(HPOUT2L, WM5100_OUT2LMIX_INPUT_1_SOURCE);
WM5100_MIXER_ENUMS(HPOUT2R, WM5100_OUT2RMIX_INPUT_1_SOURCE);
WM5100_MIXER_ENUMS(HPOUT3L, WM5100_OUT3LMIX_INPUT_1_SOURCE);
WM5100_MIXER_ENUMS(HPOUT3R, WM5100_OUT3RMIX_INPUT_1_SOURCE);
WM5100_MIXER_ENUMS(SPKOUTL, WM5100_OUT4LMIX_INPUT_1_SOURCE);
WM5100_MIXER_ENUMS(SPKOUTR, WM5100_OUT4RMIX_INPUT_1_SOURCE);
WM5100_MIXER_ENUMS(SPKDAT1L, WM5100_OUT5LMIX_INPUT_1_SOURCE);
WM5100_MIXER_ENUMS(SPKDAT1R, WM5100_OUT5RMIX_INPUT_1_SOURCE);
WM5100_MIXER_ENUMS(SPKDAT2L, WM5100_OUT6LMIX_INPUT_1_SOURCE);
WM5100_MIXER_ENUMS(SPKDAT2R, WM5100_OUT6RMIX_INPUT_1_SOURCE);
WM5100_MIXER_ENUMS(PWM1, WM5100_PWM1MIX_INPUT_1_SOURCE);
WM5100_MIXER_ENUMS(PWM2, WM5100_PWM1MIX_INPUT_1_SOURCE);
WM5100_MIXER_ENUMS(AIF1TX1, WM5100_AIF1TX1MIX_INPUT_1_SOURCE);
WM5100_MIXER_ENUMS(AIF1TX2, WM5100_AIF1TX2MIX_INPUT_1_SOURCE);
WM5100_MIXER_ENUMS(AIF1TX3, WM5100_AIF1TX3MIX_INPUT_1_SOURCE);
WM5100_MIXER_ENUMS(AIF1TX4, WM5100_AIF1TX4MIX_INPUT_1_SOURCE);
WM5100_MIXER_ENUMS(AIF1TX5, WM5100_AIF1TX5MIX_INPUT_1_SOURCE);
WM5100_MIXER_ENUMS(AIF1TX6, WM5100_AIF1TX6MIX_INPUT_1_SOURCE);
WM5100_MIXER_ENUMS(AIF1TX7, WM5100_AIF1TX7MIX_INPUT_1_SOURCE);
WM5100_MIXER_ENUMS(AIF1TX8, WM5100_AIF1TX8MIX_INPUT_1_SOURCE);
WM5100_MIXER_ENUMS(AIF2TX1, WM5100_AIF2TX1MIX_INPUT_1_SOURCE);
WM5100_MIXER_ENUMS(AIF2TX2, WM5100_AIF2TX2MIX_INPUT_1_SOURCE);
WM5100_MIXER_ENUMS(AIF3TX1, WM5100_AIF1TX1MIX_INPUT_1_SOURCE);
WM5100_MIXER_ENUMS(AIF3TX2, WM5100_AIF1TX2MIX_INPUT_1_SOURCE);
WM5100_MIXER_ENUMS(EQ1, WM5100_EQ1MIX_INPUT_1_SOURCE);
WM5100_MIXER_ENUMS(EQ2, WM5100_EQ2MIX_INPUT_1_SOURCE);
WM5100_MIXER_ENUMS(EQ3, WM5100_EQ3MIX_INPUT_1_SOURCE);
WM5100_MIXER_ENUMS(EQ4, WM5100_EQ4MIX_INPUT_1_SOURCE);
WM5100_MIXER_ENUMS(DRC1L, WM5100_DRC1LMIX_INPUT_1_SOURCE);
WM5100_MIXER_ENUMS(DRC1R, WM5100_DRC1RMIX_INPUT_1_SOURCE);
WM5100_MIXER_ENUMS(LHPF1, WM5100_HPLP1MIX_INPUT_1_SOURCE);
WM5100_MIXER_ENUMS(LHPF2, WM5100_HPLP2MIX_INPUT_1_SOURCE);
WM5100_MIXER_ENUMS(LHPF3, WM5100_HPLP3MIX_INPUT_1_SOURCE);
WM5100_MIXER_ENUMS(LHPF4, WM5100_HPLP4MIX_INPUT_1_SOURCE);
#define WM5100_MUX(name, ctrl) \
SND_SOC_DAPM_VALUE_MUX(name, SND_SOC_NOPM, 0, 0, ctrl)
#define WM5100_MIXER_WIDGETS(name, name_str) \
WM5100_MUX(name_str " Input 1", &name##_in1_mux), \
WM5100_MUX(name_str " Input 2", &name##_in2_mux), \
WM5100_MUX(name_str " Input 3", &name##_in3_mux), \
WM5100_MUX(name_str " Input 4", &name##_in4_mux), \
SND_SOC_DAPM_MIXER(name_str " Mixer", SND_SOC_NOPM, 0, 0, NULL, 0)
#define WM5100_MIXER_INPUT_ROUTES(name) \
{ name, "Tone Generator 1", "Tone Generator 1" }, \
{ name, "Tone Generator 2", "Tone Generator 2" }, \
{ name, "IN1L", "IN1L PGA" }, \
{ name, "IN1R", "IN1R PGA" }, \
{ name, "IN2L", "IN2L PGA" }, \
{ name, "IN2R", "IN2R PGA" }, \
{ name, "IN3L", "IN3L PGA" }, \
{ name, "IN3R", "IN3R PGA" }, \
{ name, "IN4L", "IN4L PGA" }, \
{ name, "IN4R", "IN4R PGA" }, \
{ name, "AIF1RX1", "AIF1RX1" }, \
{ name, "AIF1RX2", "AIF1RX2" }, \
{ name, "AIF1RX3", "AIF1RX3" }, \
{ name, "AIF1RX4", "AIF1RX4" }, \
{ name, "AIF1RX5", "AIF1RX5" }, \
{ name, "AIF1RX6", "AIF1RX6" }, \
{ name, "AIF1RX7", "AIF1RX7" }, \
{ name, "AIF1RX8", "AIF1RX8" }, \
{ name, "AIF2RX1", "AIF2RX1" }, \
{ name, "AIF2RX2", "AIF2RX2" }, \
{ name, "AIF3RX1", "AIF3RX1" }, \
{ name, "AIF3RX2", "AIF3RX2" }, \
{ name, "EQ1", "EQ1" }, \
{ name, "EQ2", "EQ2" }, \
{ name, "EQ3", "EQ3" }, \
{ name, "EQ4", "EQ4" }, \
{ name, "DRC1L", "DRC1L" }, \
{ name, "DRC1R", "DRC1R" }, \
{ name, "LHPF1", "LHPF1" }, \
{ name, "LHPF2", "LHPF2" }, \
{ name, "LHPF3", "LHPF3" }, \
{ name, "LHPF4", "LHPF4" }
#define WM5100_MIXER_ROUTES(widget, name) \
{ widget, NULL, name " Mixer" }, \
{ name " Mixer", NULL, name " Input 1" }, \
{ name " Mixer", NULL, name " Input 2" }, \
{ name " Mixer", NULL, name " Input 3" }, \
{ name " Mixer", NULL, name " Input 4" }, \
WM5100_MIXER_INPUT_ROUTES(name " Input 1"), \
WM5100_MIXER_INPUT_ROUTES(name " Input 2"), \
WM5100_MIXER_INPUT_ROUTES(name " Input 3"), \
WM5100_MIXER_INPUT_ROUTES(name " Input 4")
static const char *wm5100_lhpf_mode_text[] = {
"Low-pass", "High-pass"
};
static const struct soc_enum wm5100_lhpf1_mode =
SOC_ENUM_SINGLE(WM5100_HPLPF1_1, WM5100_LHPF1_MODE_SHIFT, 2,
wm5100_lhpf_mode_text);
static const struct soc_enum wm5100_lhpf2_mode =
SOC_ENUM_SINGLE(WM5100_HPLPF2_1, WM5100_LHPF2_MODE_SHIFT, 2,
wm5100_lhpf_mode_text);
static const struct soc_enum wm5100_lhpf3_mode =
SOC_ENUM_SINGLE(WM5100_HPLPF3_1, WM5100_LHPF3_MODE_SHIFT, 2,
wm5100_lhpf_mode_text);
static const struct soc_enum wm5100_lhpf4_mode =
SOC_ENUM_SINGLE(WM5100_HPLPF4_1, WM5100_LHPF4_MODE_SHIFT, 2,
wm5100_lhpf_mode_text);
static const struct snd_kcontrol_new wm5100_snd_controls[] = {
SOC_SINGLE("IN1 High Performance Switch", WM5100_IN1L_CONTROL,
WM5100_IN1_OSR_SHIFT, 1, 0),
SOC_SINGLE("IN2 High Performance Switch", WM5100_IN2L_CONTROL,
WM5100_IN2_OSR_SHIFT, 1, 0),
SOC_SINGLE("IN3 High Performance Switch", WM5100_IN3L_CONTROL,
WM5100_IN3_OSR_SHIFT, 1, 0),
SOC_SINGLE("IN4 High Performance Switch", WM5100_IN4L_CONTROL,
WM5100_IN4_OSR_SHIFT, 1, 0),
/* Only applicable for analogue inputs */
SOC_DOUBLE_R_TLV("IN1 Volume", WM5100_IN1L_CONTROL, WM5100_IN1R_CONTROL,
WM5100_IN1L_PGA_VOL_SHIFT, 94, 0, in_tlv),
SOC_DOUBLE_R_TLV("IN2 Volume", WM5100_IN2L_CONTROL, WM5100_IN2R_CONTROL,
WM5100_IN2L_PGA_VOL_SHIFT, 94, 0, in_tlv),
SOC_DOUBLE_R_TLV("IN3 Volume", WM5100_IN3L_CONTROL, WM5100_IN3R_CONTROL,
WM5100_IN3L_PGA_VOL_SHIFT, 94, 0, in_tlv),
SOC_DOUBLE_R_TLV("IN4 Volume", WM5100_IN4L_CONTROL, WM5100_IN4R_CONTROL,
WM5100_IN4L_PGA_VOL_SHIFT, 94, 0, in_tlv),
SOC_DOUBLE_R_TLV("IN1 Digital Volume", WM5100_ADC_DIGITAL_VOLUME_1L,
WM5100_ADC_DIGITAL_VOLUME_1R, WM5100_IN1L_VOL_SHIFT, 191,
0, digital_tlv),
SOC_DOUBLE_R_TLV("IN2 Digital Volume", WM5100_ADC_DIGITAL_VOLUME_2L,
WM5100_ADC_DIGITAL_VOLUME_2R, WM5100_IN2L_VOL_SHIFT, 191,
0, digital_tlv),
SOC_DOUBLE_R_TLV("IN3 Digital Volume", WM5100_ADC_DIGITAL_VOLUME_3L,
WM5100_ADC_DIGITAL_VOLUME_3R, WM5100_IN3L_VOL_SHIFT, 191,
0, digital_tlv),
SOC_DOUBLE_R_TLV("IN4 Digital Volume", WM5100_ADC_DIGITAL_VOLUME_4L,
WM5100_ADC_DIGITAL_VOLUME_4R, WM5100_IN4L_VOL_SHIFT, 191,
0, digital_tlv),
SOC_DOUBLE_R("IN1 Switch", WM5100_ADC_DIGITAL_VOLUME_1L,
WM5100_ADC_DIGITAL_VOLUME_1R, WM5100_IN1L_MUTE_SHIFT, 1, 1),
SOC_DOUBLE_R("IN2 Switch", WM5100_ADC_DIGITAL_VOLUME_2L,
WM5100_ADC_DIGITAL_VOLUME_2R, WM5100_IN2L_MUTE_SHIFT, 1, 1),
SOC_DOUBLE_R("IN3 Switch", WM5100_ADC_DIGITAL_VOLUME_3L,
WM5100_ADC_DIGITAL_VOLUME_3R, WM5100_IN3L_MUTE_SHIFT, 1, 1),
SOC_DOUBLE_R("IN4 Switch", WM5100_ADC_DIGITAL_VOLUME_4L,
WM5100_ADC_DIGITAL_VOLUME_4R, WM5100_IN4L_MUTE_SHIFT, 1, 1),
SOC_SINGLE("HPOUT1 High Performance Switch", WM5100_OUT_VOLUME_1L,
WM5100_OUT1_OSR_SHIFT, 1, 0),
SOC_SINGLE("HPOUT2 High Performance Switch", WM5100_OUT_VOLUME_2L,
WM5100_OUT2_OSR_SHIFT, 1, 0),
SOC_SINGLE("HPOUT3 High Performance Switch", WM5100_OUT_VOLUME_3L,
WM5100_OUT3_OSR_SHIFT, 1, 0),
SOC_SINGLE("SPKOUT High Performance Switch", WM5100_OUT_VOLUME_4L,
WM5100_OUT4_OSR_SHIFT, 1, 0),
SOC_SINGLE("SPKDAT1 High Performance Switch", WM5100_DAC_VOLUME_LIMIT_5L,
WM5100_OUT5_OSR_SHIFT, 1, 0),
SOC_SINGLE("SPKDAT2 High Performance Switch", WM5100_DAC_VOLUME_LIMIT_6L,
WM5100_OUT6_OSR_SHIFT, 1, 0),
SOC_DOUBLE_R_TLV("HPOUT1 Digital Volume", WM5100_DAC_DIGITAL_VOLUME_1L,
WM5100_DAC_DIGITAL_VOLUME_1R, WM5100_OUT1L_VOL_SHIFT, 159, 0,
digital_tlv),
SOC_DOUBLE_R_TLV("HPOUT2 Digital Volume", WM5100_DAC_DIGITAL_VOLUME_2L,
WM5100_DAC_DIGITAL_VOLUME_2R, WM5100_OUT2L_VOL_SHIFT, 159, 0,
digital_tlv),
SOC_DOUBLE_R_TLV("HPOUT3 Digital Volume", WM5100_DAC_DIGITAL_VOLUME_3L,
WM5100_DAC_DIGITAL_VOLUME_3R, WM5100_OUT3L_VOL_SHIFT, 159, 0,
digital_tlv),
SOC_DOUBLE_R_TLV("SPKOUT Digital Volume", WM5100_DAC_DIGITAL_VOLUME_4L,
WM5100_DAC_DIGITAL_VOLUME_4R, WM5100_OUT4L_VOL_SHIFT, 159, 0,
digital_tlv),
SOC_DOUBLE_R_TLV("SPKDAT1 Digital Volume", WM5100_DAC_DIGITAL_VOLUME_5L,
WM5100_DAC_DIGITAL_VOLUME_5R, WM5100_OUT5L_VOL_SHIFT, 159, 0,
digital_tlv),
SOC_DOUBLE_R_TLV("SPKDAT2 Digital Volume", WM5100_DAC_DIGITAL_VOLUME_6L,
WM5100_DAC_DIGITAL_VOLUME_6R, WM5100_OUT6L_VOL_SHIFT, 159, 0,
digital_tlv),
SOC_DOUBLE_R("HPOUT1 Digital Switch", WM5100_DAC_DIGITAL_VOLUME_1L,
WM5100_DAC_DIGITAL_VOLUME_1R, WM5100_OUT1L_MUTE_SHIFT, 1, 1),
SOC_DOUBLE_R("HPOUT2 Digital Switch", WM5100_DAC_DIGITAL_VOLUME_2L,
WM5100_DAC_DIGITAL_VOLUME_2R, WM5100_OUT2L_MUTE_SHIFT, 1, 1),
SOC_DOUBLE_R("HPOUT3 Digital Switch", WM5100_DAC_DIGITAL_VOLUME_3L,
WM5100_DAC_DIGITAL_VOLUME_3R, WM5100_OUT3L_MUTE_SHIFT, 1, 1),
SOC_DOUBLE_R("SPKOUT Digital Switch", WM5100_DAC_DIGITAL_VOLUME_4L,
WM5100_DAC_DIGITAL_VOLUME_4R, WM5100_OUT4L_MUTE_SHIFT, 1, 1),
SOC_DOUBLE_R("SPKDAT1 Digital Switch", WM5100_DAC_DIGITAL_VOLUME_5L,
WM5100_DAC_DIGITAL_VOLUME_5R, WM5100_OUT5L_MUTE_SHIFT, 1, 1),
SOC_DOUBLE_R("SPKDAT2 Digital Switch", WM5100_DAC_DIGITAL_VOLUME_6L,
WM5100_DAC_DIGITAL_VOLUME_6R, WM5100_OUT6L_MUTE_SHIFT, 1, 1),
/* FIXME: Only valid from -12dB to 0dB (52-64) */
SOC_DOUBLE_R_TLV("HPOUT1 Volume", WM5100_OUT_VOLUME_1L, WM5100_OUT_VOLUME_1R,
WM5100_OUT1L_PGA_VOL_SHIFT, 64, 0, out_tlv),
SOC_DOUBLE_R_TLV("HPOUT2 Volume", WM5100_OUT_VOLUME_2L, WM5100_OUT_VOLUME_2R,
WM5100_OUT2L_PGA_VOL_SHIFT, 64, 0, out_tlv),
SOC_DOUBLE_R_TLV("HPOUT3 Volume", WM5100_OUT_VOLUME_3L, WM5100_OUT_VOLUME_3R,
WM5100_OUT2L_PGA_VOL_SHIFT, 64, 0, out_tlv),
SOC_DOUBLE("SPKDAT1 Switch", WM5100_PDM_SPK1_CTRL_1, WM5100_SPK1L_MUTE_SHIFT,
WM5100_SPK1R_MUTE_SHIFT, 1, 1),
SOC_DOUBLE("SPKDAT2 Switch", WM5100_PDM_SPK2_CTRL_1, WM5100_SPK2L_MUTE_SHIFT,
WM5100_SPK2R_MUTE_SHIFT, 1, 1),
SOC_SINGLE_TLV("EQ1 Band 1 Volume", WM5100_EQ1_1, WM5100_EQ1_B1_GAIN_SHIFT,
24, 0, eq_tlv),
SOC_SINGLE_TLV("EQ1 Band 2 Volume", WM5100_EQ1_1, WM5100_EQ1_B2_GAIN_SHIFT,
24, 0, eq_tlv),
SOC_SINGLE_TLV("EQ1 Band 3 Volume", WM5100_EQ1_1, WM5100_EQ1_B3_GAIN_SHIFT,
24, 0, eq_tlv),
SOC_SINGLE_TLV("EQ1 Band 4 Volume", WM5100_EQ1_2, WM5100_EQ1_B4_GAIN_SHIFT,
24, 0, eq_tlv),
SOC_SINGLE_TLV("EQ1 Band 5 Volume", WM5100_EQ1_2, WM5100_EQ1_B5_GAIN_SHIFT,
24, 0, eq_tlv),
SOC_SINGLE_TLV("EQ2 Band 1 Volume", WM5100_EQ2_1, WM5100_EQ2_B1_GAIN_SHIFT,
24, 0, eq_tlv),
SOC_SINGLE_TLV("EQ2 Band 2 Volume", WM5100_EQ2_1, WM5100_EQ2_B2_GAIN_SHIFT,
24, 0, eq_tlv),
SOC_SINGLE_TLV("EQ2 Band 3 Volume", WM5100_EQ2_1, WM5100_EQ2_B3_GAIN_SHIFT,
24, 0, eq_tlv),
SOC_SINGLE_TLV("EQ2 Band 4 Volume", WM5100_EQ2_2, WM5100_EQ2_B4_GAIN_SHIFT,
24, 0, eq_tlv),
SOC_SINGLE_TLV("EQ2 Band 5 Volume", WM5100_EQ2_2, WM5100_EQ2_B5_GAIN_SHIFT,
24, 0, eq_tlv),
SOC_SINGLE_TLV("EQ3 Band 1 Volume", WM5100_EQ1_1, WM5100_EQ3_B1_GAIN_SHIFT,
24, 0, eq_tlv),
SOC_SINGLE_TLV("EQ3 Band 2 Volume", WM5100_EQ3_1, WM5100_EQ3_B2_GAIN_SHIFT,
24, 0, eq_tlv),
SOC_SINGLE_TLV("EQ3 Band 3 Volume", WM5100_EQ3_1, WM5100_EQ3_B3_GAIN_SHIFT,
24, 0, eq_tlv),
SOC_SINGLE_TLV("EQ3 Band 4 Volume", WM5100_EQ3_2, WM5100_EQ3_B4_GAIN_SHIFT,
24, 0, eq_tlv),
SOC_SINGLE_TLV("EQ3 Band 5 Volume", WM5100_EQ3_2, WM5100_EQ3_B5_GAIN_SHIFT,
24, 0, eq_tlv),
SOC_SINGLE_TLV("EQ4 Band 1 Volume", WM5100_EQ4_1, WM5100_EQ4_B1_GAIN_SHIFT,
24, 0, eq_tlv),
SOC_SINGLE_TLV("EQ4 Band 2 Volume", WM5100_EQ4_1, WM5100_EQ4_B2_GAIN_SHIFT,
24, 0, eq_tlv),
SOC_SINGLE_TLV("EQ4 Band 3 Volume", WM5100_EQ4_1, WM5100_EQ4_B3_GAIN_SHIFT,
24, 0, eq_tlv),
SOC_SINGLE_TLV("EQ4 Band 4 Volume", WM5100_EQ4_2, WM5100_EQ4_B4_GAIN_SHIFT,
24, 0, eq_tlv),
SOC_SINGLE_TLV("EQ4 Band 5 Volume", WM5100_EQ4_2, WM5100_EQ4_B5_GAIN_SHIFT,
24, 0, eq_tlv),
SOC_ENUM("LHPF1 Mode", wm5100_lhpf1_mode),
SOC_ENUM("LHPF2 Mode", wm5100_lhpf2_mode),
SOC_ENUM("LHPF3 Mode", wm5100_lhpf3_mode),
SOC_ENUM("LHPF4 Mode", wm5100_lhpf4_mode),
WM5100_MIXER_CONTROLS("HPOUT1L", WM5100_OUT1LMIX_INPUT_1_SOURCE),
WM5100_MIXER_CONTROLS("HPOUT1R", WM5100_OUT1RMIX_INPUT_1_SOURCE),
WM5100_MIXER_CONTROLS("HPOUT2L", WM5100_OUT2LMIX_INPUT_1_SOURCE),
WM5100_MIXER_CONTROLS("HPOUT2R", WM5100_OUT2RMIX_INPUT_1_SOURCE),
WM5100_MIXER_CONTROLS("HPOUT3L", WM5100_OUT3LMIX_INPUT_1_SOURCE),
WM5100_MIXER_CONTROLS("HPOUT3R", WM5100_OUT3RMIX_INPUT_1_SOURCE),
WM5100_MIXER_CONTROLS("SPKOUTL", WM5100_OUT4LMIX_INPUT_1_SOURCE),
WM5100_MIXER_CONTROLS("SPKOUTR", WM5100_OUT4RMIX_INPUT_1_SOURCE),
WM5100_MIXER_CONTROLS("SPKDAT1L", WM5100_OUT5LMIX_INPUT_1_SOURCE),
WM5100_MIXER_CONTROLS("SPKDAT1R", WM5100_OUT5RMIX_INPUT_1_SOURCE),
WM5100_MIXER_CONTROLS("SPKDAT2L", WM5100_OUT6LMIX_INPUT_1_SOURCE),
WM5100_MIXER_CONTROLS("SPKDAT2R", WM5100_OUT6RMIX_INPUT_1_SOURCE),
WM5100_MIXER_CONTROLS("PWM1", WM5100_PWM1MIX_INPUT_1_SOURCE),
WM5100_MIXER_CONTROLS("PWM2", WM5100_PWM2MIX_INPUT_1_SOURCE),
WM5100_MIXER_CONTROLS("AIF1TX1", WM5100_AIF1TX1MIX_INPUT_1_SOURCE),
WM5100_MIXER_CONTROLS("AIF1TX2", WM5100_AIF1TX2MIX_INPUT_1_SOURCE),
WM5100_MIXER_CONTROLS("AIF1TX3", WM5100_AIF1TX3MIX_INPUT_1_SOURCE),
WM5100_MIXER_CONTROLS("AIF1TX4", WM5100_AIF1TX4MIX_INPUT_1_SOURCE),
WM5100_MIXER_CONTROLS("AIF1TX5", WM5100_AIF1TX5MIX_INPUT_1_SOURCE),
WM5100_MIXER_CONTROLS("AIF1TX6", WM5100_AIF1TX6MIX_INPUT_1_SOURCE),
WM5100_MIXER_CONTROLS("AIF1TX7", WM5100_AIF1TX7MIX_INPUT_1_SOURCE),
WM5100_MIXER_CONTROLS("AIF1TX8", WM5100_AIF1TX8MIX_INPUT_1_SOURCE),
WM5100_MIXER_CONTROLS("AIF2TX1", WM5100_AIF2TX1MIX_INPUT_1_SOURCE),
WM5100_MIXER_CONTROLS("AIF2TX2", WM5100_AIF2TX2MIX_INPUT_1_SOURCE),
WM5100_MIXER_CONTROLS("AIF3TX1", WM5100_AIF3TX1MIX_INPUT_1_SOURCE),
WM5100_MIXER_CONTROLS("AIF3TX2", WM5100_AIF3TX2MIX_INPUT_1_SOURCE),
WM5100_MIXER_CONTROLS("EQ1", WM5100_EQ1MIX_INPUT_1_SOURCE),
WM5100_MIXER_CONTROLS("EQ2", WM5100_EQ2MIX_INPUT_1_SOURCE),
WM5100_MIXER_CONTROLS("EQ3", WM5100_EQ3MIX_INPUT_1_SOURCE),
WM5100_MIXER_CONTROLS("EQ4", WM5100_EQ4MIX_INPUT_1_SOURCE),
WM5100_MIXER_CONTROLS("DRC1L", WM5100_DRC1LMIX_INPUT_1_SOURCE),
WM5100_MIXER_CONTROLS("DRC1R", WM5100_DRC1RMIX_INPUT_1_SOURCE),
WM5100_MIXER_CONTROLS("LHPF1", WM5100_HPLP1MIX_INPUT_1_SOURCE),
WM5100_MIXER_CONTROLS("LHPF2", WM5100_HPLP2MIX_INPUT_1_SOURCE),
WM5100_MIXER_CONTROLS("LHPF3", WM5100_HPLP3MIX_INPUT_1_SOURCE),
WM5100_MIXER_CONTROLS("LHPF4", WM5100_HPLP4MIX_INPUT_1_SOURCE),
};
static void wm5100_seq_notifier(struct snd_soc_dapm_context *dapm,
enum snd_soc_dapm_type event, int subseq)
{
struct snd_soc_codec *codec = container_of(dapm,
struct snd_soc_codec, dapm);
struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(codec);
u16 val, expect, i;
/* Wait for the outputs to flag themselves as enabled */
if (wm5100->out_ena[0]) {
expect = snd_soc_read(codec, WM5100_CHANNEL_ENABLES_1);
for (i = 0; i < 200; i++) {
val = snd_soc_read(codec, WM5100_OUTPUT_STATUS_1);
if (val == expect) {
wm5100->out_ena[0] = false;
break;
}
}
if (i == 200) {
dev_err(codec->dev, "Timeout waiting for OUTPUT1 %x\n",
expect);
}
}
if (wm5100->out_ena[1]) {
expect = snd_soc_read(codec, WM5100_OUTPUT_ENABLES_2);
for (i = 0; i < 200; i++) {
val = snd_soc_read(codec, WM5100_OUTPUT_STATUS_2);
if (val == expect) {
wm5100->out_ena[1] = false;
break;
}
}
if (i == 200) {
dev_err(codec->dev, "Timeout waiting for OUTPUT2 %x\n",
expect);
}
}
}
static int wm5100_out_ev(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol,
int event)
{
struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(w->codec);
switch (w->reg) {
case WM5100_CHANNEL_ENABLES_1:
wm5100->out_ena[0] = true;
break;
case WM5100_OUTPUT_ENABLES_2:
wm5100->out_ena[0] = true;
break;
default:
break;
}
return 0;
}
static int wm5100_cp_ev(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol,
int event)
{
struct snd_soc_codec *codec = w->codec;
struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(codec);
int ret;
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
ret = regulator_enable(wm5100->cpvdd);
if (ret != 0) {
dev_err(codec->dev, "Failed to enable CPVDD: %d\n",
ret);
return ret;
}
return ret;
case SND_SOC_DAPM_POST_PMD:
ret = regulator_disable_deferred(wm5100->cpvdd, 20);
if (ret != 0) {
dev_err(codec->dev, "Failed to disable CPVDD: %d\n",
ret);
return ret;
}
return ret;
default:
BUG();
return 0;
}
}
static void wm5100_log_status3(struct snd_soc_codec *codec, int val)
{
if (val & WM5100_SPK_SHUTDOWN_WARN_EINT)
dev_crit(codec->dev, "Speaker shutdown warning\n");
if (val & WM5100_SPK_SHUTDOWN_EINT)
dev_crit(codec->dev, "Speaker shutdown\n");
if (val & WM5100_CLKGEN_ERR_EINT)
dev_crit(codec->dev, "SYSCLK underclocked\n");
if (val & WM5100_CLKGEN_ERR_ASYNC_EINT)
dev_crit(codec->dev, "ASYNCCLK underclocked\n");
}
static void wm5100_log_status4(struct snd_soc_codec *codec, int val)
{
if (val & WM5100_AIF3_ERR_EINT)
dev_err(codec->dev, "AIF3 configuration error\n");
if (val & WM5100_AIF2_ERR_EINT)
dev_err(codec->dev, "AIF2 configuration error\n");
if (val & WM5100_AIF1_ERR_EINT)
dev_err(codec->dev, "AIF1 configuration error\n");
if (val & WM5100_CTRLIF_ERR_EINT)
dev_err(codec->dev, "Control interface error\n");
if (val & WM5100_ISRC2_UNDERCLOCKED_EINT)
dev_err(codec->dev, "ISRC2 underclocked\n");
if (val & WM5100_ISRC1_UNDERCLOCKED_EINT)
dev_err(codec->dev, "ISRC1 underclocked\n");
if (val & WM5100_FX_UNDERCLOCKED_EINT)
dev_err(codec->dev, "FX underclocked\n");
if (val & WM5100_AIF3_UNDERCLOCKED_EINT)
dev_err(codec->dev, "AIF3 underclocked\n");
if (val & WM5100_AIF2_UNDERCLOCKED_EINT)
dev_err(codec->dev, "AIF2 underclocked\n");
if (val & WM5100_AIF1_UNDERCLOCKED_EINT)
dev_err(codec->dev, "AIF1 underclocked\n");
if (val & WM5100_ASRC_UNDERCLOCKED_EINT)
dev_err(codec->dev, "ASRC underclocked\n");
if (val & WM5100_DAC_UNDERCLOCKED_EINT)
dev_err(codec->dev, "DAC underclocked\n");
if (val & WM5100_ADC_UNDERCLOCKED_EINT)
dev_err(codec->dev, "ADC underclocked\n");
if (val & WM5100_MIXER_UNDERCLOCKED_EINT)
dev_err(codec->dev, "Mixer underclocked\n");
}
static int wm5100_post_ev(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol,
int event)
{
struct snd_soc_codec *codec = w->codec;
int ret;
ret = snd_soc_read(codec, WM5100_INTERRUPT_RAW_STATUS_3);
ret &= WM5100_SPK_SHUTDOWN_WARN_STS |
WM5100_SPK_SHUTDOWN_STS | WM5100_CLKGEN_ERR_STS |
WM5100_CLKGEN_ERR_ASYNC_STS;
wm5100_log_status3(codec, ret);
ret = snd_soc_read(codec, WM5100_INTERRUPT_RAW_STATUS_4);
wm5100_log_status4(codec, ret);
return 0;
}
static const struct snd_soc_dapm_widget wm5100_dapm_widgets[] = {
SND_SOC_DAPM_SUPPLY("SYSCLK", WM5100_CLOCKING_3, WM5100_SYSCLK_ENA_SHIFT, 0,
NULL, 0),
SND_SOC_DAPM_SUPPLY("ASYNCCLK", WM5100_CLOCKING_6, WM5100_ASYNC_CLK_ENA_SHIFT,
0, NULL, 0),
SND_SOC_DAPM_SUPPLY("CP1", WM5100_HP_CHARGE_PUMP_1, WM5100_CP1_ENA_SHIFT, 0,
wm5100_cp_ev,
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_SUPPLY("CP2", WM5100_MIC_CHARGE_PUMP_1, WM5100_CP2_ENA_SHIFT, 0,
NULL, 0),
SND_SOC_DAPM_SUPPLY("CP2 Active", WM5100_MIC_CHARGE_PUMP_1,
WM5100_CP2_BYPASS_SHIFT, 1, wm5100_cp_ev,
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_SUPPLY("MICBIAS1", WM5100_MIC_BIAS_CTRL_1, WM5100_MICB1_ENA_SHIFT,
0, NULL, 0),
SND_SOC_DAPM_SUPPLY("MICBIAS2", WM5100_MIC_BIAS_CTRL_2, WM5100_MICB2_ENA_SHIFT,
0, NULL, 0),
SND_SOC_DAPM_SUPPLY("MICBIAS3", WM5100_MIC_BIAS_CTRL_3, WM5100_MICB3_ENA_SHIFT,
0, NULL, 0),
SND_SOC_DAPM_INPUT("IN1L"),
SND_SOC_DAPM_INPUT("IN1R"),
SND_SOC_DAPM_INPUT("IN2L"),
SND_SOC_DAPM_INPUT("IN2R"),
SND_SOC_DAPM_INPUT("IN3L"),
SND_SOC_DAPM_INPUT("IN3R"),
SND_SOC_DAPM_INPUT("IN4L"),
SND_SOC_DAPM_INPUT("IN4R"),
SND_SOC_DAPM_INPUT("TONE"),
SND_SOC_DAPM_PGA_E("IN1L PGA", WM5100_INPUT_ENABLES, WM5100_IN1L_ENA_SHIFT, 0,
NULL, 0, wm5100_out_ev, SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_PGA_E("IN1R PGA", WM5100_INPUT_ENABLES, WM5100_IN1R_ENA_SHIFT, 0,
NULL, 0, wm5100_out_ev, SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_PGA_E("IN2L PGA", WM5100_INPUT_ENABLES, WM5100_IN2L_ENA_SHIFT, 0,
NULL, 0, wm5100_out_ev, SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_PGA_E("IN2R PGA", WM5100_INPUT_ENABLES, WM5100_IN2R_ENA_SHIFT, 0,
NULL, 0, wm5100_out_ev, SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_PGA_E("IN3L PGA", WM5100_INPUT_ENABLES, WM5100_IN3L_ENA_SHIFT, 0,
NULL, 0, wm5100_out_ev, SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_PGA_E("IN3R PGA", WM5100_INPUT_ENABLES, WM5100_IN3R_ENA_SHIFT, 0,
NULL, 0, wm5100_out_ev, SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_PGA_E("IN4L PGA", WM5100_INPUT_ENABLES, WM5100_IN4L_ENA_SHIFT, 0,
NULL, 0, wm5100_out_ev, SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_PGA_E("IN4R PGA", WM5100_INPUT_ENABLES, WM5100_IN4R_ENA_SHIFT, 0,
NULL, 0, wm5100_out_ev, SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_PGA("Tone Generator 1", WM5100_TONE_GENERATOR_1,
WM5100_TONE1_ENA_SHIFT, 0, NULL, 0),
SND_SOC_DAPM_PGA("Tone Generator 2", WM5100_TONE_GENERATOR_1,
WM5100_TONE2_ENA_SHIFT, 0, NULL, 0),
SND_SOC_DAPM_AIF_IN("AIF1RX1", "AIF1 Playback", 0,
WM5100_AUDIO_IF_1_27, WM5100_AIF1RX1_ENA_SHIFT, 0),
SND_SOC_DAPM_AIF_IN("AIF1RX2", "AIF1 Playback", 1,
WM5100_AUDIO_IF_1_27, WM5100_AIF1RX2_ENA_SHIFT, 0),
SND_SOC_DAPM_AIF_IN("AIF1RX3", "AIF1 Playback", 2,
WM5100_AUDIO_IF_1_27, WM5100_AIF1RX3_ENA_SHIFT, 0),
SND_SOC_DAPM_AIF_IN("AIF1RX4", "AIF1 Playback", 3,
WM5100_AUDIO_IF_1_27, WM5100_AIF1RX4_ENA_SHIFT, 0),
SND_SOC_DAPM_AIF_IN("AIF1RX5", "AIF1 Playback", 4,
WM5100_AUDIO_IF_1_27, WM5100_AIF1RX5_ENA_SHIFT, 0),
SND_SOC_DAPM_AIF_IN("AIF1RX6", "AIF1 Playback", 5,
WM5100_AUDIO_IF_1_27, WM5100_AIF1RX6_ENA_SHIFT, 0),
SND_SOC_DAPM_AIF_IN("AIF1RX7", "AIF1 Playback", 6,
WM5100_AUDIO_IF_1_27, WM5100_AIF1RX7_ENA_SHIFT, 0),
SND_SOC_DAPM_AIF_IN("AIF1RX8", "AIF1 Playback", 7,
WM5100_AUDIO_IF_1_27, WM5100_AIF1RX8_ENA_SHIFT, 0),
SND_SOC_DAPM_AIF_IN("AIF2RX1", "AIF2 Playback", 0,
WM5100_AUDIO_IF_2_27, WM5100_AIF2RX1_ENA_SHIFT, 0),
SND_SOC_DAPM_AIF_IN("AIF2RX2", "AIF2 Playback", 1,
WM5100_AUDIO_IF_2_27, WM5100_AIF2RX2_ENA_SHIFT, 0),
SND_SOC_DAPM_AIF_IN("AIF3RX1", "AIF3 Playback", 0,
WM5100_AUDIO_IF_3_27, WM5100_AIF3RX1_ENA_SHIFT, 0),
SND_SOC_DAPM_AIF_IN("AIF3RX2", "AIF3 Playback", 1,
WM5100_AUDIO_IF_3_27, WM5100_AIF3RX2_ENA_SHIFT, 0),
SND_SOC_DAPM_AIF_OUT("AIF1TX1", "AIF1 Capture", 0,
WM5100_AUDIO_IF_1_26, WM5100_AIF1TX1_ENA_SHIFT, 0),
SND_SOC_DAPM_AIF_OUT("AIF1TX2", "AIF1 Capture", 1,
WM5100_AUDIO_IF_1_26, WM5100_AIF1TX2_ENA_SHIFT, 0),
SND_SOC_DAPM_AIF_OUT("AIF1TX3", "AIF1 Capture", 2,
WM5100_AUDIO_IF_1_26, WM5100_AIF1TX3_ENA_SHIFT, 0),
SND_SOC_DAPM_AIF_OUT("AIF1TX4", "AIF1 Capture", 3,
WM5100_AUDIO_IF_1_26, WM5100_AIF1TX4_ENA_SHIFT, 0),
SND_SOC_DAPM_AIF_OUT("AIF1TX5", "AIF1 Capture", 4,
WM5100_AUDIO_IF_1_26, WM5100_AIF1TX5_ENA_SHIFT, 0),
SND_SOC_DAPM_AIF_OUT("AIF1TX6", "AIF1 Capture", 5,
WM5100_AUDIO_IF_1_26, WM5100_AIF1TX6_ENA_SHIFT, 0),
SND_SOC_DAPM_AIF_OUT("AIF1TX7", "AIF1 Capture", 6,
WM5100_AUDIO_IF_1_26, WM5100_AIF1TX7_ENA_SHIFT, 0),
SND_SOC_DAPM_AIF_OUT("AIF1TX8", "AIF1 Capture", 7,
WM5100_AUDIO_IF_1_26, WM5100_AIF1TX8_ENA_SHIFT, 0),
SND_SOC_DAPM_AIF_OUT("AIF2TX1", "AIF2 Capture", 0,
WM5100_AUDIO_IF_2_26, WM5100_AIF2TX1_ENA_SHIFT, 0),
SND_SOC_DAPM_AIF_OUT("AIF2TX2", "AIF2 Capture", 1,
WM5100_AUDIO_IF_2_26, WM5100_AIF2TX2_ENA_SHIFT, 0),
SND_SOC_DAPM_AIF_OUT("AIF3TX1", "AIF3 Capture", 0,
WM5100_AUDIO_IF_3_26, WM5100_AIF3TX1_ENA_SHIFT, 0),
SND_SOC_DAPM_AIF_OUT("AIF3TX2", "AIF3 Capture", 1,
WM5100_AUDIO_IF_3_26, WM5100_AIF3TX2_ENA_SHIFT, 0),
SND_SOC_DAPM_PGA_E("OUT6L", WM5100_OUTPUT_ENABLES_2, WM5100_OUT6L_ENA_SHIFT, 0,
NULL, 0, wm5100_out_ev, SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_PGA_E("OUT6R", WM5100_OUTPUT_ENABLES_2, WM5100_OUT6R_ENA_SHIFT, 0,
NULL, 0, wm5100_out_ev, SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_PGA_E("OUT5L", WM5100_OUTPUT_ENABLES_2, WM5100_OUT5L_ENA_SHIFT, 0,
NULL, 0, wm5100_out_ev, SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_PGA_E("OUT5R", WM5100_OUTPUT_ENABLES_2, WM5100_OUT5R_ENA_SHIFT, 0,
NULL, 0, wm5100_out_ev, SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_PGA_E("OUT4L", WM5100_OUTPUT_ENABLES_2, WM5100_OUT4L_ENA_SHIFT, 0,
NULL, 0, wm5100_out_ev, SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_PGA_E("OUT4R", WM5100_OUTPUT_ENABLES_2, WM5100_OUT4R_ENA_SHIFT, 0,
NULL, 0, wm5100_out_ev, SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_PGA_E("OUT3L", WM5100_CHANNEL_ENABLES_1, WM5100_HP3L_ENA_SHIFT, 0,
NULL, 0, wm5100_out_ev, SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_PGA_E("OUT3R", WM5100_CHANNEL_ENABLES_1, WM5100_HP3R_ENA_SHIFT, 0,
NULL, 0, wm5100_out_ev, SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_PGA_E("OUT2L", WM5100_CHANNEL_ENABLES_1, WM5100_HP2L_ENA_SHIFT, 0,
NULL, 0, wm5100_out_ev, SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_PGA_E("OUT2R", WM5100_CHANNEL_ENABLES_1, WM5100_HP2R_ENA_SHIFT, 0,
NULL, 0, wm5100_out_ev, SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_PGA_E("OUT1L", WM5100_CHANNEL_ENABLES_1, WM5100_HP1L_ENA_SHIFT, 0,
NULL, 0, wm5100_out_ev, SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_PGA_E("OUT1R", WM5100_CHANNEL_ENABLES_1, WM5100_HP1R_ENA_SHIFT, 0,
NULL, 0, wm5100_out_ev, SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_PGA_E("PWM1 Driver", WM5100_PWM_DRIVE_1, WM5100_PWM1_ENA_SHIFT, 0,
NULL, 0, wm5100_out_ev, SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_PGA_E("PWM2 Driver", WM5100_PWM_DRIVE_1, WM5100_PWM2_ENA_SHIFT, 0,
NULL, 0, wm5100_out_ev, SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_PGA("EQ1", WM5100_EQ1_1, WM5100_EQ1_ENA_SHIFT, 0, NULL, 0),
SND_SOC_DAPM_PGA("EQ2", WM5100_EQ2_1, WM5100_EQ2_ENA_SHIFT, 0, NULL, 0),
SND_SOC_DAPM_PGA("EQ3", WM5100_EQ3_1, WM5100_EQ3_ENA_SHIFT, 0, NULL, 0),
SND_SOC_DAPM_PGA("EQ4", WM5100_EQ4_1, WM5100_EQ4_ENA_SHIFT, 0, NULL, 0),
SND_SOC_DAPM_PGA("DRC1L", WM5100_DRC1_CTRL1, WM5100_DRCL_ENA_SHIFT, 0,
NULL, 0),
SND_SOC_DAPM_PGA("DRC1R", WM5100_DRC1_CTRL1, WM5100_DRCR_ENA_SHIFT, 0,
NULL, 0),
SND_SOC_DAPM_PGA("LHPF1", WM5100_HPLPF1_1, WM5100_LHPF1_ENA_SHIFT, 0,
NULL, 0),
SND_SOC_DAPM_PGA("LHPF2", WM5100_HPLPF2_1, WM5100_LHPF2_ENA_SHIFT, 0,
NULL, 0),
SND_SOC_DAPM_PGA("LHPF3", WM5100_HPLPF3_1, WM5100_LHPF3_ENA_SHIFT, 0,
NULL, 0),
SND_SOC_DAPM_PGA("LHPF4", WM5100_HPLPF4_1, WM5100_LHPF4_ENA_SHIFT, 0,
NULL, 0),
WM5100_MIXER_WIDGETS(EQ1, "EQ1"),
WM5100_MIXER_WIDGETS(EQ2, "EQ2"),
WM5100_MIXER_WIDGETS(EQ3, "EQ3"),
WM5100_MIXER_WIDGETS(EQ4, "EQ4"),
WM5100_MIXER_WIDGETS(DRC1L, "DRC1L"),
WM5100_MIXER_WIDGETS(DRC1R, "DRC1R"),
WM5100_MIXER_WIDGETS(LHPF1, "LHPF1"),
WM5100_MIXER_WIDGETS(LHPF2, "LHPF2"),
WM5100_MIXER_WIDGETS(LHPF3, "LHPF3"),
WM5100_MIXER_WIDGETS(LHPF4, "LHPF4"),
WM5100_MIXER_WIDGETS(AIF1TX1, "AIF1TX1"),
WM5100_MIXER_WIDGETS(AIF1TX2, "AIF1TX2"),
WM5100_MIXER_WIDGETS(AIF1TX3, "AIF1TX3"),
WM5100_MIXER_WIDGETS(AIF1TX4, "AIF1TX4"),
WM5100_MIXER_WIDGETS(AIF1TX5, "AIF1TX5"),
WM5100_MIXER_WIDGETS(AIF1TX6, "AIF1TX6"),
WM5100_MIXER_WIDGETS(AIF1TX7, "AIF1TX7"),
WM5100_MIXER_WIDGETS(AIF1TX8, "AIF1TX8"),
WM5100_MIXER_WIDGETS(AIF2TX1, "AIF2TX1"),
WM5100_MIXER_WIDGETS(AIF2TX2, "AIF2TX2"),
WM5100_MIXER_WIDGETS(AIF3TX1, "AIF3TX1"),
WM5100_MIXER_WIDGETS(AIF3TX2, "AIF3TX2"),
WM5100_MIXER_WIDGETS(HPOUT1L, "HPOUT1L"),
WM5100_MIXER_WIDGETS(HPOUT1R, "HPOUT1R"),
WM5100_MIXER_WIDGETS(HPOUT2L, "HPOUT2L"),
WM5100_MIXER_WIDGETS(HPOUT2R, "HPOUT2R"),
WM5100_MIXER_WIDGETS(HPOUT3L, "HPOUT3L"),
WM5100_MIXER_WIDGETS(HPOUT3R, "HPOUT3R"),
WM5100_MIXER_WIDGETS(SPKOUTL, "SPKOUTL"),
WM5100_MIXER_WIDGETS(SPKOUTR, "SPKOUTR"),
WM5100_MIXER_WIDGETS(SPKDAT1L, "SPKDAT1L"),
WM5100_MIXER_WIDGETS(SPKDAT1R, "SPKDAT1R"),
WM5100_MIXER_WIDGETS(SPKDAT2L, "SPKDAT2L"),
WM5100_MIXER_WIDGETS(SPKDAT2R, "SPKDAT2R"),
WM5100_MIXER_WIDGETS(PWM1, "PWM1"),
WM5100_MIXER_WIDGETS(PWM2, "PWM2"),
SND_SOC_DAPM_OUTPUT("HPOUT1L"),
SND_SOC_DAPM_OUTPUT("HPOUT1R"),
SND_SOC_DAPM_OUTPUT("HPOUT2L"),
SND_SOC_DAPM_OUTPUT("HPOUT2R"),
SND_SOC_DAPM_OUTPUT("HPOUT3L"),
SND_SOC_DAPM_OUTPUT("HPOUT3R"),
SND_SOC_DAPM_OUTPUT("SPKOUTL"),
SND_SOC_DAPM_OUTPUT("SPKOUTR"),
SND_SOC_DAPM_OUTPUT("SPKDAT1"),
SND_SOC_DAPM_OUTPUT("SPKDAT2"),
SND_SOC_DAPM_OUTPUT("PWM1"),
SND_SOC_DAPM_OUTPUT("PWM2"),
};
/* We register a _POST event if we don't have IRQ support so we can
* look at the error status from the CODEC - if we've got the IRQ
* hooked up then we will get prompted to look by an interrupt.
*/
static const struct snd_soc_dapm_widget wm5100_dapm_widgets_noirq[] = {
SND_SOC_DAPM_POST("Post", wm5100_post_ev),
};
static const struct snd_soc_dapm_route wm5100_dapm_routes[] = {
{ "IN1L", NULL, "SYSCLK" },
{ "IN1R", NULL, "SYSCLK" },
{ "IN2L", NULL, "SYSCLK" },
{ "IN2R", NULL, "SYSCLK" },
{ "IN3L", NULL, "SYSCLK" },
{ "IN3R", NULL, "SYSCLK" },
{ "IN4L", NULL, "SYSCLK" },
{ "IN4R", NULL, "SYSCLK" },
{ "OUT1L", NULL, "SYSCLK" },
{ "OUT1R", NULL, "SYSCLK" },
{ "OUT2L", NULL, "SYSCLK" },
{ "OUT2R", NULL, "SYSCLK" },
{ "OUT3L", NULL, "SYSCLK" },
{ "OUT3R", NULL, "SYSCLK" },
{ "OUT4L", NULL, "SYSCLK" },
{ "OUT4R", NULL, "SYSCLK" },
{ "OUT5L", NULL, "SYSCLK" },
{ "OUT5R", NULL, "SYSCLK" },
{ "OUT6L", NULL, "SYSCLK" },
{ "OUT6R", NULL, "SYSCLK" },
{ "AIF1RX1", NULL, "SYSCLK" },
{ "AIF1RX2", NULL, "SYSCLK" },
{ "AIF1RX3", NULL, "SYSCLK" },
{ "AIF1RX4", NULL, "SYSCLK" },
{ "AIF1RX5", NULL, "SYSCLK" },
{ "AIF1RX6", NULL, "SYSCLK" },
{ "AIF1RX7", NULL, "SYSCLK" },
{ "AIF1RX8", NULL, "SYSCLK" },
{ "AIF2RX1", NULL, "SYSCLK" },
{ "AIF2RX2", NULL, "SYSCLK" },
{ "AIF3RX1", NULL, "SYSCLK" },
{ "AIF3RX2", NULL, "SYSCLK" },
{ "AIF1TX1", NULL, "SYSCLK" },
{ "AIF1TX2", NULL, "SYSCLK" },
{ "AIF1TX3", NULL, "SYSCLK" },
{ "AIF1TX4", NULL, "SYSCLK" },
{ "AIF1TX5", NULL, "SYSCLK" },
{ "AIF1TX6", NULL, "SYSCLK" },
{ "AIF1TX7", NULL, "SYSCLK" },
{ "AIF1TX8", NULL, "SYSCLK" },
{ "AIF2TX1", NULL, "SYSCLK" },
{ "AIF2TX2", NULL, "SYSCLK" },
{ "AIF3TX1", NULL, "SYSCLK" },
{ "AIF3TX2", NULL, "SYSCLK" },
{ "MICBIAS1", NULL, "CP2" },
{ "MICBIAS2", NULL, "CP2" },
{ "MICBIAS3", NULL, "CP2" },
{ "IN1L PGA", NULL, "CP2" },
{ "IN1R PGA", NULL, "CP2" },
{ "IN2L PGA", NULL, "CP2" },
{ "IN2R PGA", NULL, "CP2" },
{ "IN3L PGA", NULL, "CP2" },
{ "IN3R PGA", NULL, "CP2" },
{ "IN4L PGA", NULL, "CP2" },
{ "IN4R PGA", NULL, "CP2" },
{ "IN1L PGA", NULL, "CP2 Active" },
{ "IN1R PGA", NULL, "CP2 Active" },
{ "IN2L PGA", NULL, "CP2 Active" },
{ "IN2R PGA", NULL, "CP2 Active" },
{ "IN3L PGA", NULL, "CP2 Active" },
{ "IN3R PGA", NULL, "CP2 Active" },
{ "IN4L PGA", NULL, "CP2 Active" },
{ "IN4R PGA", NULL, "CP2 Active" },
{ "OUT1L", NULL, "CP1" },
{ "OUT1R", NULL, "CP1" },
{ "OUT2L", NULL, "CP1" },
{ "OUT2R", NULL, "CP1" },
{ "OUT3L", NULL, "CP1" },
{ "OUT3R", NULL, "CP1" },
{ "Tone Generator 1", NULL, "TONE" },
{ "Tone Generator 2", NULL, "TONE" },
{ "IN1L PGA", NULL, "IN1L" },
{ "IN1R PGA", NULL, "IN1R" },
{ "IN2L PGA", NULL, "IN2L" },
{ "IN2R PGA", NULL, "IN2R" },
{ "IN3L PGA", NULL, "IN3L" },
{ "IN3R PGA", NULL, "IN3R" },
{ "IN4L PGA", NULL, "IN4L" },
{ "IN4R PGA", NULL, "IN4R" },
WM5100_MIXER_ROUTES("OUT1L", "HPOUT1L"),
WM5100_MIXER_ROUTES("OUT1R", "HPOUT1R"),
WM5100_MIXER_ROUTES("OUT2L", "HPOUT2L"),
WM5100_MIXER_ROUTES("OUT2R", "HPOUT2R"),
WM5100_MIXER_ROUTES("OUT3L", "HPOUT3L"),
WM5100_MIXER_ROUTES("OUT3R", "HPOUT3R"),
WM5100_MIXER_ROUTES("OUT4L", "SPKOUTL"),
WM5100_MIXER_ROUTES("OUT4R", "SPKOUTR"),
WM5100_MIXER_ROUTES("OUT5L", "SPKDAT1L"),
WM5100_MIXER_ROUTES("OUT5R", "SPKDAT1R"),
WM5100_MIXER_ROUTES("OUT6L", "SPKDAT2L"),
WM5100_MIXER_ROUTES("OUT6R", "SPKDAT2R"),
WM5100_MIXER_ROUTES("PWM1 Driver", "PWM1"),
WM5100_MIXER_ROUTES("PWM2 Driver", "PWM2"),
WM5100_MIXER_ROUTES("AIF1TX1", "AIF1TX1"),
WM5100_MIXER_ROUTES("AIF1TX2", "AIF1TX2"),
WM5100_MIXER_ROUTES("AIF1TX3", "AIF1TX3"),
WM5100_MIXER_ROUTES("AIF1TX4", "AIF1TX4"),
WM5100_MIXER_ROUTES("AIF1TX5", "AIF1TX5"),
WM5100_MIXER_ROUTES("AIF1TX6", "AIF1TX6"),
WM5100_MIXER_ROUTES("AIF1TX7", "AIF1TX7"),
WM5100_MIXER_ROUTES("AIF1TX8", "AIF1TX8"),
WM5100_MIXER_ROUTES("AIF2TX1", "AIF2TX1"),
WM5100_MIXER_ROUTES("AIF2TX2", "AIF2TX2"),
WM5100_MIXER_ROUTES("AIF3TX1", "AIF3TX1"),
WM5100_MIXER_ROUTES("AIF3TX2", "AIF3TX2"),
WM5100_MIXER_ROUTES("EQ1", "EQ1"),
WM5100_MIXER_ROUTES("EQ2", "EQ2"),
WM5100_MIXER_ROUTES("EQ3", "EQ3"),
WM5100_MIXER_ROUTES("EQ4", "EQ4"),
WM5100_MIXER_ROUTES("DRC1L", "DRC1L"),
WM5100_MIXER_ROUTES("DRC1R", "DRC1R"),
WM5100_MIXER_ROUTES("LHPF1", "LHPF1"),
WM5100_MIXER_ROUTES("LHPF2", "LHPF2"),
WM5100_MIXER_ROUTES("LHPF3", "LHPF3"),
WM5100_MIXER_ROUTES("LHPF4", "LHPF4"),
{ "HPOUT1L", NULL, "OUT1L" },
{ "HPOUT1R", NULL, "OUT1R" },
{ "HPOUT2L", NULL, "OUT2L" },
{ "HPOUT2R", NULL, "OUT2R" },
{ "HPOUT3L", NULL, "OUT3L" },
{ "HPOUT3R", NULL, "OUT3R" },
{ "SPKOUTL", NULL, "OUT4L" },
{ "SPKOUTR", NULL, "OUT4R" },
{ "SPKDAT1", NULL, "OUT5L" },
{ "SPKDAT1", NULL, "OUT5R" },
{ "SPKDAT2", NULL, "OUT6L" },
{ "SPKDAT2", NULL, "OUT6R" },
{ "PWM1", NULL, "PWM1 Driver" },
{ "PWM2", NULL, "PWM2 Driver" },
};
static struct {
int reg;
int val;
} wm5100_reva_patches[] = {
{ WM5100_AUDIO_IF_1_10, 0 },
{ WM5100_AUDIO_IF_1_11, 1 },
{ WM5100_AUDIO_IF_1_12, 2 },
{ WM5100_AUDIO_IF_1_13, 3 },
{ WM5100_AUDIO_IF_1_14, 4 },
{ WM5100_AUDIO_IF_1_15, 5 },
{ WM5100_AUDIO_IF_1_16, 6 },
{ WM5100_AUDIO_IF_1_17, 7 },
{ WM5100_AUDIO_IF_1_18, 0 },
{ WM5100_AUDIO_IF_1_19, 1 },
{ WM5100_AUDIO_IF_1_20, 2 },
{ WM5100_AUDIO_IF_1_21, 3 },
{ WM5100_AUDIO_IF_1_22, 4 },
{ WM5100_AUDIO_IF_1_23, 5 },
{ WM5100_AUDIO_IF_1_24, 6 },
{ WM5100_AUDIO_IF_1_25, 7 },
{ WM5100_AUDIO_IF_2_10, 0 },
{ WM5100_AUDIO_IF_2_11, 1 },
{ WM5100_AUDIO_IF_2_18, 0 },
{ WM5100_AUDIO_IF_2_19, 1 },
{ WM5100_AUDIO_IF_3_10, 0 },
{ WM5100_AUDIO_IF_3_11, 1 },
{ WM5100_AUDIO_IF_3_18, 0 },
{ WM5100_AUDIO_IF_3_19, 1 },
};
static int wm5100_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level)
{
struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(codec);
int ret, i;
switch (level) {
case SND_SOC_BIAS_ON:
break;
case SND_SOC_BIAS_PREPARE:
break;
case SND_SOC_BIAS_STANDBY:
if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
ret = regulator_bulk_enable(ARRAY_SIZE(wm5100->core_supplies),
wm5100->core_supplies);
if (ret != 0) {
dev_err(codec->dev,
"Failed to enable supplies: %d\n",
ret);
return ret;
}
if (wm5100->pdata.ldo_ena) {
gpio_set_value_cansleep(wm5100->pdata.ldo_ena,
1);
msleep(2);
}
codec->cache_only = false;
switch (wm5100->rev) {
case 0:
snd_soc_write(codec, 0x11, 0x3);
snd_soc_write(codec, 0x203, 0xc);
snd_soc_write(codec, 0x206, 0);
snd_soc_write(codec, 0x207, 0xf0);
snd_soc_write(codec, 0x208, 0x3c);
snd_soc_write(codec, 0x209, 0);
snd_soc_write(codec, 0x211, 0x20d8);
snd_soc_write(codec, 0x11, 0);
for (i = 0;
i < ARRAY_SIZE(wm5100_reva_patches);
i++)
snd_soc_write(codec,
wm5100_reva_patches[i].reg,
wm5100_reva_patches[i].val);
break;
default:
break;
}
snd_soc_cache_sync(codec);
}
break;
case SND_SOC_BIAS_OFF:
if (wm5100->pdata.ldo_ena)
gpio_set_value_cansleep(wm5100->pdata.ldo_ena, 0);
regulator_bulk_disable(ARRAY_SIZE(wm5100->core_supplies),
wm5100->core_supplies);
break;
}
codec->dapm.bias_level = level;
return 0;
}
static int wm5100_dai_to_base(struct snd_soc_dai *dai)
{
switch (dai->id) {
case 0:
return WM5100_AUDIO_IF_1_1 - 1;
case 1:
return WM5100_AUDIO_IF_2_1 - 1;
case 2:
return WM5100_AUDIO_IF_3_1 - 1;
default:
BUG();
return -EINVAL;
}
}
static int wm5100_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
{
struct snd_soc_codec *codec = dai->codec;
int lrclk, bclk, mask, base;
base = wm5100_dai_to_base(dai);
if (base < 0)
return base;
lrclk = 0;
bclk = 0;
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_DSP_A:
mask = 0;
break;
case SND_SOC_DAIFMT_DSP_B:
mask = 1;
break;
case SND_SOC_DAIFMT_I2S:
mask = 2;
break;
case SND_SOC_DAIFMT_LEFT_J:
mask = 3;
break;
default:
dev_err(codec->dev, "Unsupported DAI format %d\n",
fmt & SND_SOC_DAIFMT_FORMAT_MASK);
return -EINVAL;
}
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
case SND_SOC_DAIFMT_CBS_CFS:
break;
case SND_SOC_DAIFMT_CBS_CFM:
lrclk |= WM5100_AIF1TX_LRCLK_MSTR;
break;
case SND_SOC_DAIFMT_CBM_CFS:
bclk |= WM5100_AIF1_BCLK_MSTR;
break;
case SND_SOC_DAIFMT_CBM_CFM:
lrclk |= WM5100_AIF1TX_LRCLK_MSTR;
bclk |= WM5100_AIF1_BCLK_MSTR;
break;
default:
dev_err(codec->dev, "Unsupported master mode %d\n",
fmt & SND_SOC_DAIFMT_MASTER_MASK);
return -EINVAL;
}
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
case SND_SOC_DAIFMT_NB_NF:
break;
case SND_SOC_DAIFMT_IB_IF:
bclk |= WM5100_AIF1_BCLK_INV;
lrclk |= WM5100_AIF1TX_LRCLK_INV;
break;
case SND_SOC_DAIFMT_IB_NF:
bclk |= WM5100_AIF1_BCLK_INV;
break;
case SND_SOC_DAIFMT_NB_IF:
lrclk |= WM5100_AIF1TX_LRCLK_INV;
break;
default:
return -EINVAL;
}
snd_soc_update_bits(codec, base + 1, WM5100_AIF1_BCLK_MSTR |
WM5100_AIF1_BCLK_INV, bclk);
snd_soc_update_bits(codec, base + 2, WM5100_AIF1TX_LRCLK_MSTR |
WM5100_AIF1TX_LRCLK_INV, lrclk);
snd_soc_update_bits(codec, base + 3, WM5100_AIF1TX_LRCLK_MSTR |
WM5100_AIF1TX_LRCLK_INV, lrclk);
snd_soc_update_bits(codec, base + 5, WM5100_AIF1_FMT_MASK, mask);
return 0;
}
#define WM5100_NUM_BCLK_RATES 19
static int wm5100_bclk_rates_dat[WM5100_NUM_BCLK_RATES] = {
32000,
48000,
64000,
96000,
128000,
192000,
384000,
512000,
768000,
1024000,
1536000,
2048000,
3072000,
4096000,
6144000,
8192000,
12288000,
24576000,
};
static int wm5100_bclk_rates_cd[WM5100_NUM_BCLK_RATES] = {
29400,
44100,
58800,
88200,
117600,
176400,
235200,
352800,
470400,
705600,
940800,
1411200,
1881600,
2882400,
3763200,
5644800,
7526400,
11289600,
22579600,
};
static int wm5100_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
struct snd_soc_codec *codec = dai->codec;
struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(codec);
bool async = wm5100->aif_async[dai->id];
int i, base, bclk, aif_rate, lrclk, wl, fl, sr;
int *bclk_rates;
base = wm5100_dai_to_base(dai);
if (base < 0)
return base;
/* Data sizes if not using TDM */
wl = snd_pcm_format_width(params_format(params));
if (wl < 0)
return wl;
fl = snd_soc_params_to_frame_size(params);
if (fl < 0)
return fl;
dev_dbg(codec->dev, "Word length %d bits, frame length %d bits\n",
wl, fl);
/* Target BCLK rate */
bclk = snd_soc_params_to_bclk(params);
if (bclk < 0)
return bclk;
/* Root for BCLK depends on SYS/ASYNCCLK */
if (!async) {
aif_rate = wm5100->sysclk;
sr = wm5100_alloc_sr(codec, params_rate(params));
if (sr < 0)
return sr;
} else {
/* If we're in ASYNCCLK set the ASYNC sample rate */
aif_rate = wm5100->asyncclk;
sr = 3;
for (i = 0; i < ARRAY_SIZE(wm5100_sr_code); i++)
if (params_rate(params) == wm5100_sr_code[i])
break;
if (i == ARRAY_SIZE(wm5100_sr_code)) {
dev_err(codec->dev, "Invalid rate %dHzn",
params_rate(params));
return -EINVAL;
}
/* TODO: We should really check for symmetry */
snd_soc_update_bits(codec, WM5100_CLOCKING_8,
WM5100_ASYNC_SAMPLE_RATE_MASK, i);
}
if (!aif_rate) {
dev_err(codec->dev, "%s has no rate set\n",
async ? "ASYNCCLK" : "SYSCLK");
return -EINVAL;
}
dev_dbg(codec->dev, "Target BCLK is %dHz, using %dHz %s\n",
bclk, aif_rate, async ? "ASYNCCLK" : "SYSCLK");
if (aif_rate % 4000)
bclk_rates = wm5100_bclk_rates_cd;
else
bclk_rates = wm5100_bclk_rates_dat;
for (i = 0; i < WM5100_NUM_BCLK_RATES; i++)
if (bclk_rates[i] >= bclk && (bclk_rates[i] % bclk == 0))
break;
if (i == WM5100_NUM_BCLK_RATES) {
dev_err(codec->dev,
"No valid BCLK for %dHz found from %dHz %s\n",
bclk, aif_rate, async ? "ASYNCCLK" : "SYSCLK");
return -EINVAL;
}
bclk = i;
dev_dbg(codec->dev, "Setting %dHz BCLK\n", bclk_rates[bclk]);
snd_soc_update_bits(codec, base + 1, WM5100_AIF1_BCLK_FREQ_MASK, bclk);
lrclk = bclk_rates[bclk] / params_rate(params);
dev_dbg(codec->dev, "Setting %dHz LRCLK\n", bclk_rates[bclk] / lrclk);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ||
wm5100->aif_symmetric[dai->id])
snd_soc_update_bits(codec, base + 7,
WM5100_AIF1RX_BCPF_MASK, lrclk);
else
snd_soc_update_bits(codec, base + 6,
WM5100_AIF1TX_BCPF_MASK, lrclk);
i = (wl << WM5100_AIF1TX_WL_SHIFT) | fl;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
snd_soc_update_bits(codec, base + 9,
WM5100_AIF1RX_WL_MASK |
WM5100_AIF1RX_SLOT_LEN_MASK, i);
else
snd_soc_update_bits(codec, base + 8,
WM5100_AIF1TX_WL_MASK |
WM5100_AIF1TX_SLOT_LEN_MASK, i);
snd_soc_update_bits(codec, base + 4, WM5100_AIF1_RATE_MASK, sr);
return 0;
}
static struct snd_soc_dai_ops wm5100_dai_ops = {
.set_fmt = wm5100_set_fmt,
.hw_params = wm5100_hw_params,
};
static int wm5100_set_sysclk(struct snd_soc_codec *codec, int clk_id,
int source, unsigned int freq, int dir)
{
struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(codec);
int *rate_store;
int fval, audio_rate, ret, reg;
switch (clk_id) {
case WM5100_CLK_SYSCLK:
reg = WM5100_CLOCKING_3;
rate_store = &wm5100->sysclk;
break;
case WM5100_CLK_ASYNCCLK:
reg = WM5100_CLOCKING_7;
rate_store = &wm5100->asyncclk;
break;
case WM5100_CLK_32KHZ:
/* The 32kHz clock is slightly different to the others */
switch (source) {
case WM5100_CLKSRC_MCLK1:
case WM5100_CLKSRC_MCLK2:
case WM5100_CLKSRC_SYSCLK:
snd_soc_update_bits(codec, WM5100_CLOCKING_1,
WM5100_CLK_32K_SRC_MASK,
source);
break;
default:
return -EINVAL;
}
return 0;
case WM5100_CLK_AIF1:
case WM5100_CLK_AIF2:
case WM5100_CLK_AIF3:
/* Not real clocks, record which clock domain they're in */
switch (source) {
case WM5100_CLKSRC_SYSCLK:
wm5100->aif_async[clk_id - 1] = false;
break;
case WM5100_CLKSRC_ASYNCCLK:
wm5100->aif_async[clk_id - 1] = true;
break;
default:
dev_err(codec->dev, "Invalid source %d\n", source);
return -EINVAL;
}
return 0;
case WM5100_CLK_OPCLK:
switch (freq) {
case 5644800:
case 6144000:
snd_soc_update_bits(codec, WM5100_MISC_GPIO_1,
WM5100_OPCLK_SEL_MASK, 0);
break;
case 11289600:
case 12288000:
snd_soc_update_bits(codec, WM5100_MISC_GPIO_1,
WM5100_OPCLK_SEL_MASK, 0);
break;
case 22579200:
case 24576000:
snd_soc_update_bits(codec, WM5100_MISC_GPIO_1,
WM5100_OPCLK_SEL_MASK, 0);
break;
default:
dev_err(codec->dev, "Unsupported OPCLK %dHz\n",
freq);
return -EINVAL;
}
return 0;
default:
dev_err(codec->dev, "Unknown clock %d\n", clk_id);
return -EINVAL;
}
switch (source) {
case WM5100_CLKSRC_SYSCLK:
case WM5100_CLKSRC_ASYNCCLK:
dev_err(codec->dev, "Invalid source %d\n", source);
return -EINVAL;
}
switch (freq) {
case 5644800:
case 6144000:
fval = 0;
break;
case 11289600:
case 12288000:
fval = 1;
break;
case 22579200:
case 2457600:
fval = 2;
break;
default:
dev_err(codec->dev, "Invalid clock rate: %d\n", freq);
return -EINVAL;
}
switch (freq) {
case 5644800:
case 11289600:
case 22579200:
audio_rate = 44100;
break;
case 6144000:
case 12288000:
case 2457600:
audio_rate = 48000;
break;
default:
BUG();
audio_rate = 0;
break;
}
/* TODO: Check if MCLKs are in use and enable/disable pulls to
* match.
*/
snd_soc_update_bits(codec, reg, WM5100_SYSCLK_FREQ_MASK |
WM5100_SYSCLK_SRC_MASK,
fval << WM5100_SYSCLK_FREQ_SHIFT | source);
/* If this is SYSCLK then configure the clock rate for the
* internal audio functions to the natural sample rate for
* this clock rate.
*/
if (clk_id == WM5100_CLK_SYSCLK) {
dev_dbg(codec->dev, "Setting primary audio rate to %dHz",
audio_rate);
if (0 && *rate_store)
wm5100_free_sr(codec, audio_rate);
ret = wm5100_alloc_sr(codec, audio_rate);
if (ret != 0)
dev_warn(codec->dev, "Primary audio slot is %d\n",
ret);
}
*rate_store = freq;
return 0;
}
struct _fll_div {
u16 fll_fratio;
u16 fll_outdiv;
u16 fll_refclk_div;
u16 n;
u16 theta;
u16 lambda;
};
static struct {
unsigned int min;
unsigned int max;
u16 fll_fratio;
int ratio;
} fll_fratios[] = {
{ 0, 64000, 4, 16 },
{ 64000, 128000, 3, 8 },
{ 128000, 256000, 2, 4 },
{ 256000, 1000000, 1, 2 },
{ 1000000, 13500000, 0, 1 },
};
static int fll_factors(struct _fll_div *fll_div, unsigned int Fref,
unsigned int Fout)
{
unsigned int target;
unsigned int div;
unsigned int fratio, gcd_fll;
int i;
/* Fref must be <=13.5MHz */
div = 1;
fll_div->fll_refclk_div = 0;
while ((Fref / div) > 13500000) {
div *= 2;
fll_div->fll_refclk_div++;
if (div > 8) {
pr_err("Can't scale %dMHz input down to <=13.5MHz\n",
Fref);
return -EINVAL;
}
}
pr_debug("FLL Fref=%u Fout=%u\n", Fref, Fout);
/* Apply the division for our remaining calculations */
Fref /= div;
/* Fvco should be 90-100MHz; don't check the upper bound */
div = 2;
while (Fout * div < 90000000) {
div++;
if (div > 64) {
pr_err("Unable to find FLL_OUTDIV for Fout=%uHz\n",
Fout);
return -EINVAL;
}
}
target = Fout * div;
fll_div->fll_outdiv = div - 1;
pr_debug("FLL Fvco=%dHz\n", target);
/* Find an appropraite FLL_FRATIO and factor it out of the target */
for (i = 0; i < ARRAY_SIZE(fll_fratios); i++) {
if (fll_fratios[i].min <= Fref && Fref <= fll_fratios[i].max) {
fll_div->fll_fratio = fll_fratios[i].fll_fratio;
fratio = fll_fratios[i].ratio;
break;
}
}
if (i == ARRAY_SIZE(fll_fratios)) {
pr_err("Unable to find FLL_FRATIO for Fref=%uHz\n", Fref);
return -EINVAL;
}
fll_div->n = target / (fratio * Fref);
if (target % Fref == 0) {
fll_div->theta = 0;
fll_div->lambda = 0;
} else {
gcd_fll = gcd(target, fratio * Fref);
fll_div->theta = (target - (fll_div->n * fratio * Fref))
/ gcd_fll;
fll_div->lambda = (fratio * Fref) / gcd_fll;
}
pr_debug("FLL N=%x THETA=%x LAMBDA=%x\n",
fll_div->n, fll_div->theta, fll_div->lambda);
pr_debug("FLL_FRATIO=%x(%d) FLL_OUTDIV=%x FLL_REFCLK_DIV=%x\n",
fll_div->fll_fratio, fratio, fll_div->fll_outdiv,
fll_div->fll_refclk_div);
return 0;
}
static int wm5100_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
unsigned int Fref, unsigned int Fout)
{
struct i2c_client *i2c = to_i2c_client(codec->dev);
struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(codec);
struct _fll_div factors;
struct wm5100_fll *fll;
int ret, base, lock, i, timeout;
switch (fll_id) {
case WM5100_FLL1:
fll = &wm5100->fll[0];
base = WM5100_FLL1_CONTROL_1 - 1;
lock = WM5100_FLL1_LOCK_STS;
break;
case WM5100_FLL2:
fll = &wm5100->fll[1];
base = WM5100_FLL2_CONTROL_2 - 1;
lock = WM5100_FLL2_LOCK_STS;
break;
default:
dev_err(codec->dev, "Unknown FLL %d\n",fll_id);
return -EINVAL;
}
if (!Fout) {
dev_dbg(codec->dev, "FLL%d disabled", fll_id);
fll->fout = 0;
snd_soc_update_bits(codec, base + 1, WM5100_FLL1_ENA, 0);
return 0;
}
switch (source) {
case WM5100_FLL_SRC_MCLK1:
case WM5100_FLL_SRC_MCLK2:
case WM5100_FLL_SRC_FLL1:
case WM5100_FLL_SRC_FLL2:
case WM5100_FLL_SRC_AIF1BCLK:
case WM5100_FLL_SRC_AIF2BCLK:
case WM5100_FLL_SRC_AIF3BCLK:
break;
default:
dev_err(codec->dev, "Invalid FLL source %d\n", source);
return -EINVAL;
}
ret = fll_factors(&factors, Fref, Fout);
if (ret < 0)
return ret;
/* Disable the FLL while we reconfigure */
snd_soc_update_bits(codec, base + 1, WM5100_FLL1_ENA, 0);
snd_soc_update_bits(codec, base + 2,
WM5100_FLL1_OUTDIV_MASK | WM5100_FLL1_FRATIO_MASK,
(factors.fll_outdiv << WM5100_FLL1_OUTDIV_SHIFT) |
factors.fll_fratio);
snd_soc_update_bits(codec, base + 3, WM5100_FLL1_THETA_MASK,
factors.theta);
snd_soc_update_bits(codec, base + 5, WM5100_FLL1_N_MASK, factors.n);
snd_soc_update_bits(codec, base + 6,
WM5100_FLL1_REFCLK_DIV_MASK |
WM5100_FLL1_REFCLK_SRC_MASK,
(factors.fll_refclk_div
<< WM5100_FLL1_REFCLK_DIV_SHIFT) | source);
snd_soc_update_bits(codec, base + 7, WM5100_FLL1_LAMBDA_MASK,
factors.lambda);
/* Clear any pending completions */
try_wait_for_completion(&fll->lock);
snd_soc_update_bits(codec, base + 1, WM5100_FLL1_ENA, WM5100_FLL1_ENA);
if (i2c->irq)
timeout = 2;
else
timeout = 50;
/* Poll for the lock; will use interrupt when we can test */
for (i = 0; i < timeout; i++) {
if (i2c->irq) {
ret = wait_for_completion_timeout(&fll->lock,
msecs_to_jiffies(25));
if (ret > 0)
break;
} else {
msleep(1);
}
ret = snd_soc_read(codec,
WM5100_INTERRUPT_RAW_STATUS_3);
if (ret < 0) {
dev_err(codec->dev,
"Failed to read FLL status: %d\n",
ret);
continue;
}
if (ret & lock)
break;
}
if (i == timeout) {
dev_err(codec->dev, "FLL%d lock timed out\n", fll_id);
return -ETIMEDOUT;
}
fll->src = source;
fll->fref = Fref;
fll->fout = Fout;
dev_dbg(codec->dev, "FLL%d running %dHz->%dHz\n", fll_id,
Fref, Fout);
return 0;
}
/* Actually go much higher */
#define WM5100_RATES SNDRV_PCM_RATE_8000_192000
#define WM5100_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
static struct snd_soc_dai_driver wm5100_dai[] = {
{
.name = "wm5100-aif1",
.playback = {
.stream_name = "AIF1 Playback",
.channels_min = 2,
.channels_max = 2,
.rates = WM5100_RATES,
.formats = WM5100_FORMATS,
},
.capture = {
.stream_name = "AIF1 Capture",
.channels_min = 2,
.channels_max = 2,
.rates = WM5100_RATES,
.formats = WM5100_FORMATS,
},
.ops = &wm5100_dai_ops,
},
{
.name = "wm5100-aif2",
.id = 1,
.playback = {
.stream_name = "AIF2 Playback",
.channels_min = 2,
.channels_max = 2,
.rates = WM5100_RATES,
.formats = WM5100_FORMATS,
},
.capture = {
.stream_name = "AIF2 Capture",
.channels_min = 2,
.channels_max = 2,
.rates = WM5100_RATES,
.formats = WM5100_FORMATS,
},
.ops = &wm5100_dai_ops,
},
{
.name = "wm5100-aif3",
.id = 2,
.playback = {
.stream_name = "AIF3 Playback",
.channels_min = 2,
.channels_max = 2,
.rates = WM5100_RATES,
.formats = WM5100_FORMATS,
},
.capture = {
.stream_name = "AIF3 Capture",
.channels_min = 2,
.channels_max = 2,
.rates = WM5100_RATES,
.formats = WM5100_FORMATS,
},
.ops = &wm5100_dai_ops,
},
};
static int wm5100_dig_vu[] = {
WM5100_ADC_DIGITAL_VOLUME_1L,
WM5100_ADC_DIGITAL_VOLUME_1R,
WM5100_ADC_DIGITAL_VOLUME_2L,
WM5100_ADC_DIGITAL_VOLUME_2R,
WM5100_ADC_DIGITAL_VOLUME_3L,
WM5100_ADC_DIGITAL_VOLUME_3R,
WM5100_ADC_DIGITAL_VOLUME_4L,
WM5100_ADC_DIGITAL_VOLUME_4R,
WM5100_DAC_DIGITAL_VOLUME_1L,
WM5100_DAC_DIGITAL_VOLUME_1R,
WM5100_DAC_DIGITAL_VOLUME_2L,
WM5100_DAC_DIGITAL_VOLUME_2R,
WM5100_DAC_DIGITAL_VOLUME_3L,
WM5100_DAC_DIGITAL_VOLUME_3R,
WM5100_DAC_DIGITAL_VOLUME_4L,
WM5100_DAC_DIGITAL_VOLUME_4R,
WM5100_DAC_DIGITAL_VOLUME_5L,
WM5100_DAC_DIGITAL_VOLUME_5R,
WM5100_DAC_DIGITAL_VOLUME_6L,
WM5100_DAC_DIGITAL_VOLUME_6R,
};
static irqreturn_t wm5100_irq(int irq, void *data)
{
struct snd_soc_codec *codec = data;
struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(codec);
irqreturn_t status = IRQ_NONE;
int irq_val;
irq_val = snd_soc_read(codec, WM5100_INTERRUPT_STATUS_3);
if (irq_val < 0) {
dev_err(codec->dev, "Failed to read IRQ status 3: %d\n",
irq_val);
irq_val = 0;
}
irq_val &= ~snd_soc_read(codec, WM5100_INTERRUPT_STATUS_3_MASK);
snd_soc_write(codec, WM5100_INTERRUPT_STATUS_3, irq_val);
if (irq_val)
status = IRQ_HANDLED;
wm5100_log_status3(codec, irq_val);
if (irq_val & WM5100_FLL1_LOCK_EINT) {
dev_dbg(codec->dev, "FLL1 locked\n");
complete(&wm5100->fll[0].lock);
}
if (irq_val & WM5100_FLL2_LOCK_EINT) {
dev_dbg(codec->dev, "FLL2 locked\n");
complete(&wm5100->fll[1].lock);
}
irq_val = snd_soc_read(codec, WM5100_INTERRUPT_STATUS_4);
if (irq_val < 0) {
dev_err(codec->dev, "Failed to read IRQ status 4: %d\n",
irq_val);
irq_val = 0;
}
irq_val &= ~snd_soc_read(codec, WM5100_INTERRUPT_STATUS_4_MASK);
if (irq_val)
status = IRQ_HANDLED;
snd_soc_write(codec, WM5100_INTERRUPT_STATUS_4, irq_val);
wm5100_log_status4(codec, irq_val);
return status;
}
static irqreturn_t wm5100_edge_irq(int irq, void *data)
{
irqreturn_t ret = IRQ_NONE;
irqreturn_t val;
do {
val = wm5100_irq(irq, data);
if (val != IRQ_NONE)
ret = val;
} while (val != IRQ_NONE);
return ret;
}
#ifdef CONFIG_GPIOLIB
static inline struct wm5100_priv *gpio_to_wm5100(struct gpio_chip *chip)
{
return container_of(chip, struct wm5100_priv, gpio_chip);
}
static void wm5100_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
{
struct wm5100_priv *wm5100 = gpio_to_wm5100(chip);
struct snd_soc_codec *codec = wm5100->codec;
snd_soc_update_bits(codec, WM5100_GPIO_CTRL_1 + offset,
WM5100_GP1_LVL, !!value << WM5100_GP1_LVL_SHIFT);
}
static int wm5100_gpio_direction_out(struct gpio_chip *chip,
unsigned offset, int value)
{
struct wm5100_priv *wm5100 = gpio_to_wm5100(chip);
struct snd_soc_codec *codec = wm5100->codec;
int val;
val = (1 << WM5100_GP1_FN_SHIFT) | (!!value << WM5100_GP1_LVL_SHIFT);
return snd_soc_update_bits(codec, WM5100_GPIO_CTRL_1 + offset,
WM5100_GP1_FN_MASK | WM5100_GP1_DIR |
WM5100_GP1_LVL, val);
}
static int wm5100_gpio_get(struct gpio_chip *chip, unsigned offset)
{
struct wm5100_priv *wm5100 = gpio_to_wm5100(chip);
struct snd_soc_codec *codec = wm5100->codec;
int ret;
ret = snd_soc_read(codec, WM5100_GPIO_CTRL_1 + offset);
if (ret < 0)
return ret;
return (ret & WM5100_GP1_LVL) != 0;
}
static int wm5100_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
{
struct wm5100_priv *wm5100 = gpio_to_wm5100(chip);
struct snd_soc_codec *codec = wm5100->codec;
return snd_soc_update_bits(codec, WM5100_GPIO_CTRL_1 + offset,
WM5100_GP1_FN_MASK | WM5100_GP1_DIR,
(1 << WM5100_GP1_FN_SHIFT) |
(1 << WM5100_GP1_DIR_SHIFT));
}
static struct gpio_chip wm5100_template_chip = {
.label = "wm5100",
.owner = THIS_MODULE,
.direction_output = wm5100_gpio_direction_out,
.set = wm5100_gpio_set,
.direction_input = wm5100_gpio_direction_in,
.get = wm5100_gpio_get,
.can_sleep = 1,
};
static void wm5100_init_gpio(struct snd_soc_codec *codec)
{
struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(codec);
int ret;
wm5100->gpio_chip = wm5100_template_chip;
wm5100->gpio_chip.ngpio = 6;
wm5100->gpio_chip.dev = codec->dev;
if (wm5100->pdata.gpio_base)
wm5100->gpio_chip.base = wm5100->pdata.gpio_base;
else
wm5100->gpio_chip.base = -1;
ret = gpiochip_add(&wm5100->gpio_chip);
if (ret != 0)
dev_err(codec->dev, "Failed to add GPIOs: %d\n", ret);
}
static void wm5100_free_gpio(struct snd_soc_codec *codec)
{
struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(codec);
int ret;
ret = gpiochip_remove(&wm5100->gpio_chip);
if (ret != 0)
dev_err(codec->dev, "Failed to remove GPIOs: %d\n", ret);
}
#else
static void wm5100_init_gpio(struct snd_soc_codec *codec)
{
}
static void wm5100_free_gpio(struct snd_soc_codec *codec)
{
}
#endif
static int wm5100_probe(struct snd_soc_codec *codec)
{
struct i2c_client *i2c = to_i2c_client(codec->dev);
struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(codec);
int ret, i, irq_flags;
wm5100->codec = codec;
codec->dapm.bias_level = SND_SOC_BIAS_OFF;
ret = snd_soc_codec_set_cache_io(codec, 16, 16, SND_SOC_I2C);
if (ret != 0) {
dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
return ret;
}
for (i = 0; i < ARRAY_SIZE(wm5100->core_supplies); i++)
wm5100->core_supplies[i].supply = wm5100_core_supply_names[i];
ret = regulator_bulk_get(&i2c->dev, ARRAY_SIZE(wm5100->core_supplies),
wm5100->core_supplies);
if (ret != 0) {
dev_err(codec->dev, "Failed to request core supplies: %d\n",
ret);
return ret;
}
wm5100->cpvdd = regulator_get(&i2c->dev, "CPVDD");
if (IS_ERR(wm5100->cpvdd)) {
ret = PTR_ERR(wm5100->cpvdd);
dev_err(&i2c->dev, "Failed to get CPVDD: %d\n", ret);
goto err_core;
}
ret = regulator_bulk_enable(ARRAY_SIZE(wm5100->core_supplies),
wm5100->core_supplies);
if (ret != 0) {
dev_err(codec->dev, "Failed to enable core supplies: %d\n",
ret);
goto err_cpvdd;
}
if (wm5100->pdata.ldo_ena) {
ret = gpio_request_one(wm5100->pdata.ldo_ena,
GPIOF_OUT_INIT_HIGH, "WM5100 LDOENA");
if (ret < 0) {
dev_err(&i2c->dev, "Failed to request LDOENA %d: %d\n",
wm5100->pdata.ldo_ena, ret);
goto err_enable;
}
msleep(2);
}
if (wm5100->pdata.reset) {
ret = gpio_request_one(wm5100->pdata.reset,
GPIOF_OUT_INIT_HIGH, "WM5100 /RESET");
if (ret < 0) {
dev_err(&i2c->dev, "Failed to request /RESET %d: %d\n",
wm5100->pdata.reset, ret);
goto err_ldo;
}
}
ret = snd_soc_read(codec, WM5100_SOFTWARE_RESET);
if (ret < 0) {
dev_err(codec->dev, "Failed to read ID register\n");
goto err_reset;
}
switch (ret) {
case 0x8997:
case 0x5100:
break;
default:
dev_err(codec->dev, "Device is not a WM5100, ID is %x\n", ret);
ret = -EINVAL;
goto err_reset;
}
ret = snd_soc_read(codec, WM5100_DEVICE_REVISION);
if (ret < 0) {
dev_err(codec->dev, "Failed to read revision register\n");
goto err_reset;
}
wm5100->rev = ret & WM5100_DEVICE_REVISION_MASK;
dev_info(codec->dev, "revision %c\n", wm5100->rev + 'A');
ret = wm5100_reset(codec);
if (ret < 0) {
dev_err(codec->dev, "Failed to issue reset\n");
goto err_reset;
}
codec->cache_only = true;
wm5100_init_gpio(codec);
for (i = 0; i < ARRAY_SIZE(wm5100_dig_vu); i++)
snd_soc_update_bits(codec, wm5100_dig_vu[i], WM5100_OUT_VU,
WM5100_OUT_VU);
for (i = 0; i < ARRAY_SIZE(wm5100->pdata.in_mode); i++) {
snd_soc_update_bits(codec, WM5100_IN1L_CONTROL,
WM5100_IN1_MODE_MASK |
WM5100_IN1_DMIC_SUP_MASK,
(wm5100->pdata.in_mode[i] <<
WM5100_IN1_MODE_SHIFT) |
(wm5100->pdata.dmic_sup[i] <<
WM5100_IN1_DMIC_SUP_SHIFT));
}
for (i = 0; i < ARRAY_SIZE(wm5100->pdata.gpio_defaults); i++) {
if (!wm5100->pdata.gpio_defaults[i])
continue;
snd_soc_write(codec, WM5100_GPIO_CTRL_1 + i,
wm5100->pdata.gpio_defaults[i]);
}
/* Don't debounce interrupts to support use of SYSCLK only */
snd_soc_write(codec, WM5100_IRQ_DEBOUNCE_1, 0);
snd_soc_write(codec, WM5100_IRQ_DEBOUNCE_2, 0);
/* TODO: check if we're symmetric */
if (i2c->irq) {
if (wm5100->pdata.irq_flags)
irq_flags = wm5100->pdata.irq_flags;
else
irq_flags = IRQF_TRIGGER_LOW;
irq_flags |= IRQF_ONESHOT;
if (irq_flags & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING))
ret = request_threaded_irq(i2c->irq, NULL,
wm5100_edge_irq,
irq_flags, "wm5100", codec);
else
ret = request_threaded_irq(i2c->irq, NULL, wm5100_irq,
irq_flags, "wm5100", codec);
if (ret != 0) {
dev_err(codec->dev, "Failed to request IRQ %d: %d\n",
i2c->irq, ret);
} else {
/* Enable default interrupts */
snd_soc_update_bits(codec,
WM5100_INTERRUPT_STATUS_3_MASK,
WM5100_IM_SPK_SHUTDOWN_WARN_EINT |
WM5100_IM_SPK_SHUTDOWN_EINT |
WM5100_IM_ASRC2_LOCK_EINT |
WM5100_IM_ASRC1_LOCK_EINT |
WM5100_IM_FLL2_LOCK_EINT |
WM5100_IM_FLL1_LOCK_EINT |
WM5100_CLKGEN_ERR_EINT |
WM5100_CLKGEN_ERR_ASYNC_EINT, 0);
snd_soc_update_bits(codec,
WM5100_INTERRUPT_STATUS_4_MASK,
WM5100_AIF3_ERR_EINT |
WM5100_AIF2_ERR_EINT |
WM5100_AIF1_ERR_EINT |
WM5100_CTRLIF_ERR_EINT |
WM5100_ISRC2_UNDERCLOCKED_EINT |
WM5100_ISRC1_UNDERCLOCKED_EINT |
WM5100_FX_UNDERCLOCKED_EINT |
WM5100_AIF3_UNDERCLOCKED_EINT |
WM5100_AIF2_UNDERCLOCKED_EINT |
WM5100_AIF1_UNDERCLOCKED_EINT |
WM5100_ASRC_UNDERCLOCKED_EINT |
WM5100_DAC_UNDERCLOCKED_EINT |
WM5100_ADC_UNDERCLOCKED_EINT |
WM5100_MIXER_UNDERCLOCKED_EINT, 0);
}
} else {
snd_soc_dapm_new_controls(&codec->dapm,
wm5100_dapm_widgets_noirq,
ARRAY_SIZE(wm5100_dapm_widgets_noirq));
}
if (wm5100->pdata.hp_pol) {
ret = gpio_request_one(wm5100->pdata.hp_pol,
GPIOF_OUT_INIT_HIGH, "WM5100 HP_POL");
if (ret < 0) {
dev_err(&i2c->dev, "Failed to request HP_POL %d: %d\n",
wm5100->pdata.hp_pol, ret);
goto err_gpio;
}
}
/* We'll get woken up again when the system has something useful
* for us to do.
*/
if (wm5100->pdata.ldo_ena)
gpio_set_value_cansleep(wm5100->pdata.ldo_ena, 0);
regulator_bulk_disable(ARRAY_SIZE(wm5100->core_supplies),
wm5100->core_supplies);
return 0;
err_gpio:
wm5100_free_gpio(codec);
err_reset:
if (wm5100->pdata.reset) {
gpio_set_value_cansleep(wm5100->pdata.reset, 1);
gpio_free(wm5100->pdata.reset);
}
err_ldo:
if (wm5100->pdata.ldo_ena) {
gpio_set_value_cansleep(wm5100->pdata.ldo_ena, 0);
gpio_free(wm5100->pdata.ldo_ena);
}
err_enable:
regulator_bulk_disable(ARRAY_SIZE(wm5100->core_supplies),
wm5100->core_supplies);
err_cpvdd:
regulator_put(wm5100->cpvdd);
err_core:
regulator_bulk_free(ARRAY_SIZE(wm5100->core_supplies),
wm5100->core_supplies);
return ret;
}
static int wm5100_remove(struct snd_soc_codec *codec)
{
struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(codec);
wm5100_set_bias_level(codec, SND_SOC_BIAS_OFF);
if (wm5100->pdata.hp_pol) {
gpio_free(wm5100->pdata.hp_pol);
}
wm5100_free_gpio(codec);
if (wm5100->pdata.reset) {
gpio_set_value_cansleep(wm5100->pdata.reset, 1);
gpio_free(wm5100->pdata.reset);
}
if (wm5100->pdata.ldo_ena) {
gpio_set_value_cansleep(wm5100->pdata.ldo_ena, 0);
gpio_free(wm5100->pdata.ldo_ena);
}
regulator_put(wm5100->cpvdd);
regulator_bulk_free(ARRAY_SIZE(wm5100->core_supplies),
wm5100->core_supplies);
return 0;
}
static struct snd_soc_codec_driver soc_codec_dev_wm5100 = {
.probe = wm5100_probe,
.remove = wm5100_remove,
.set_sysclk = wm5100_set_sysclk,
.set_pll = wm5100_set_fll,
.set_bias_level = wm5100_set_bias_level,
.idle_bias_off = 1,
.seq_notifier = wm5100_seq_notifier,
.controls = wm5100_snd_controls,
.num_controls = ARRAY_SIZE(wm5100_snd_controls),
.dapm_widgets = wm5100_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(wm5100_dapm_widgets),
.dapm_routes = wm5100_dapm_routes,
.num_dapm_routes = ARRAY_SIZE(wm5100_dapm_routes),
.reg_cache_size = ARRAY_SIZE(wm5100_reg_defaults),
.reg_word_size = sizeof(u16),
.compress_type = SND_SOC_RBTREE_COMPRESSION,
.reg_cache_default = wm5100_reg_defaults,
.volatile_register = wm5100_volatile_register,
.readable_register = wm5100_readable_register,
};
static __devinit int wm5100_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct wm5100_pdata *pdata = dev_get_platdata(&i2c->dev);
struct wm5100_priv *wm5100;
int ret, i;
wm5100 = kzalloc(sizeof(struct wm5100_priv), GFP_KERNEL);
if (wm5100 == NULL)
return -ENOMEM;
for (i = 0; i < ARRAY_SIZE(wm5100->fll); i++)
init_completion(&wm5100->fll[i].lock);
if (pdata)
wm5100->pdata = *pdata;
i2c_set_clientdata(i2c, wm5100);
ret = snd_soc_register_codec(&i2c->dev,
&soc_codec_dev_wm5100, wm5100_dai,
ARRAY_SIZE(wm5100_dai));
if (ret < 0) {
dev_err(&i2c->dev, "Failed to register WM5100: %d\n", ret);
kfree(wm5100);
}
return ret;
}
static __devexit int wm5100_i2c_remove(struct i2c_client *client)
{
snd_soc_unregister_codec(&client->dev);
kfree(i2c_get_clientdata(client));
return 0;
}
static const struct i2c_device_id wm5100_i2c_id[] = {
{ "wm5100", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, wm5100_i2c_id);
static struct i2c_driver wm5100_i2c_driver = {
.driver = {
.name = "wm5100",
.owner = THIS_MODULE,
},
.probe = wm5100_i2c_probe,
.remove = __devexit_p(wm5100_i2c_remove),
.id_table = wm5100_i2c_id,
};
static int __init wm5100_modinit(void)
{
return i2c_add_driver(&wm5100_i2c_driver);
}
module_init(wm5100_modinit);
static void __exit wm5100_exit(void)
{
i2c_del_driver(&wm5100_i2c_driver);
}
module_exit(wm5100_exit);
MODULE_DESCRIPTION("ASoC WM5100 driver");
MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
MODULE_LICENSE("GPL");
This source diff could not be displayed because it is too large. You can view the blob instead.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment