|  | // SPDX-License-Identifier: GPL-2.0-only | 
|  | /* | 
|  | * Analog Devices ADAU1372 Audio Codec driver | 
|  | * | 
|  | * Copyright 2016 Analog Devices Inc. | 
|  | * Author: Lars-Peter Clausen <lars@metafoo.de> | 
|  | */ | 
|  |  | 
|  | #include <linux/clk.h> | 
|  | #include <linux/delay.h> | 
|  | #include <linux/gcd.h> | 
|  | #include <linux/gpio/consumer.h> | 
|  | #include <linux/init.h> | 
|  | #include <linux/module.h> | 
|  | #include <linux/pm.h> | 
|  | #include <linux/slab.h> | 
|  |  | 
|  | #include <sound/core.h> | 
|  | #include <sound/pcm.h> | 
|  | #include <sound/pcm_params.h> | 
|  | #include <sound/tlv.h> | 
|  | #include <sound/soc.h> | 
|  |  | 
|  | #include "adau1372.h" | 
|  | #include "adau-utils.h" | 
|  |  | 
|  | struct adau1372 { | 
|  | struct clk *clk; | 
|  | struct regmap *regmap; | 
|  | void (*switch_mode)(struct device *dev); | 
|  | bool use_pll; | 
|  | bool enabled; | 
|  | bool master; | 
|  |  | 
|  | struct snd_pcm_hw_constraint_list rate_constraints; | 
|  | unsigned int slot_width; | 
|  |  | 
|  | struct clk *mclk; | 
|  | struct gpio_desc *pd_gpio; | 
|  | struct device *dev; | 
|  | }; | 
|  |  | 
|  | #define ADAU1372_REG_CLK_CTRL		0x00 | 
|  | #define ADAU1372_REG_PLL(x)		(0x01 + (x)) | 
|  | #define ADAU1372_REG_DAC_SOURCE		0x11 | 
|  | #define ADAU1372_REG_SOUT_SOURCE_0_1	0x13 | 
|  | #define ADAU1372_REG_SOUT_SOURCE_2_3	0x14 | 
|  | #define ADAU1372_REG_SOUT_SOURCE_4_5	0x15 | 
|  | #define ADAU1372_REG_SOUT_SOURCE_6_7	0x16 | 
|  | #define ADAU1372_REG_ADC_SDATA_CH	0x17 | 
|  | #define ADAU1372_REG_ASRCO_SOURCE_0_1	0x18 | 
|  | #define ADAU1372_REG_ASRCO_SOURCE_2_3	0x19 | 
|  | #define ADAU1372_REG_ASRC_MODE		0x1a | 
|  | #define ADAU1372_REG_ADC_CTRL0		0x1b | 
|  | #define ADAU1372_REG_ADC_CTRL1		0x1c | 
|  | #define ADAU1372_REG_ADC_CTRL2		0x1d | 
|  | #define ADAU1372_REG_ADC_CTRL3		0x1e | 
|  | #define ADAU1372_REG_ADC_VOL(x)		(0x1f + (x)) | 
|  | #define ADAU1372_REG_PGA_CTRL(x)	(0x23 + (x)) | 
|  | #define ADAU1372_REG_PGA_BOOST		0x28 | 
|  | #define ADAU1372_REG_MICBIAS		0x2d | 
|  | #define ADAU1372_REG_DAC_CTRL		0x2e | 
|  | #define ADAU1372_REG_DAC_VOL(x)		(0x2f + (x)) | 
|  | #define ADAU1372_REG_OP_STAGE_MUTE	0x31 | 
|  | #define ADAU1372_REG_SAI0		0x32 | 
|  | #define ADAU1372_REG_SAI1		0x33 | 
|  | #define ADAU1372_REG_SOUT_CTRL		0x34 | 
|  | #define ADAU1372_REG_MODE_MP(x)		(0x38 + (x)) | 
|  | #define ADAU1372_REG_OP_STAGE_CTRL	0x43 | 
|  | #define ADAU1372_REG_DECIM_PWR		0x44 | 
|  | #define ADAU1372_REG_INTERP_PWR		0x45 | 
|  | #define ADAU1372_REG_BIAS_CTRL0		0x46 | 
|  | #define ADAU1372_REG_BIAS_CTRL1		0x47 | 
|  |  | 
|  | #define ADAU1372_CLK_CTRL_PLL_EN	BIT(7) | 
|  | #define ADAU1372_CLK_CTRL_XTAL_DIS	BIT(4) | 
|  | #define ADAU1372_CLK_CTRL_CLKSRC	BIT(3) | 
|  | #define ADAU1372_CLK_CTRL_CC_MDIV	BIT(1) | 
|  | #define ADAU1372_CLK_CTRL_MCLK_EN	BIT(0) | 
|  |  | 
|  | #define ADAU1372_SAI0_DELAY1		(0x0 << 6) | 
|  | #define ADAU1372_SAI0_DELAY0		(0x1 << 6) | 
|  | #define ADAU1372_SAI0_DELAY_MASK	(0x3 << 6) | 
|  | #define ADAU1372_SAI0_SAI_I2S		(0x0 << 4) | 
|  | #define ADAU1372_SAI0_SAI_TDM2		(0x1 << 4) | 
|  | #define ADAU1372_SAI0_SAI_TDM4		(0x2 << 4) | 
|  | #define ADAU1372_SAI0_SAI_TDM8		(0x3 << 4) | 
|  | #define ADAU1372_SAI0_SAI_MASK		(0x3 << 4) | 
|  | #define ADAU1372_SAI0_FS_48		0x0 | 
|  | #define ADAU1372_SAI0_FS_8		0x1 | 
|  | #define ADAU1372_SAI0_FS_12		0x2 | 
|  | #define ADAU1372_SAI0_FS_16		0x3 | 
|  | #define ADAU1372_SAI0_FS_24		0x4 | 
|  | #define ADAU1372_SAI0_FS_32		0x5 | 
|  | #define ADAU1372_SAI0_FS_96		0x6 | 
|  | #define ADAU1372_SAI0_FS_192		0x7 | 
|  | #define ADAU1372_SAI0_FS_MASK		0xf | 
|  |  | 
|  | #define ADAU1372_SAI1_TDM_TS		BIT(7) | 
|  | #define ADAU1372_SAI1_BCLK_TDMC		BIT(6) | 
|  | #define ADAU1372_SAI1_LR_MODE		BIT(5) | 
|  | #define ADAU1372_SAI1_LR_POL		BIT(4) | 
|  | #define ADAU1372_SAI1_BCLKRATE		BIT(2) | 
|  | #define ADAU1372_SAI1_BCLKEDGE		BIT(1) | 
|  | #define ADAU1372_SAI1_MS		BIT(0) | 
|  |  | 
|  | static const unsigned int adau1372_rates[] = { | 
|  | [ADAU1372_SAI0_FS_8] = 8000, | 
|  | [ADAU1372_SAI0_FS_12] = 12000, | 
|  | [ADAU1372_SAI0_FS_16] = 16000, | 
|  | [ADAU1372_SAI0_FS_24] = 24000, | 
|  | [ADAU1372_SAI0_FS_32] = 32000, | 
|  | [ADAU1372_SAI0_FS_48] = 48000, | 
|  | [ADAU1372_SAI0_FS_96] = 96000, | 
|  | [ADAU1372_SAI0_FS_192] = 192000, | 
|  | }; | 
|  |  | 
|  | /* 8k, 12k, 24k, 48k */ | 
|  | #define ADAU1372_RATE_MASK_TDM8 0x17 | 
|  | /* + 16k, 96k */ | 
|  | #define ADAU1372_RATE_MASK_TDM4_MASTER (ADAU1372_RATE_MASK_TDM8 | 0x48 | 0x20) | 
|  | /* +32k */ | 
|  | #define ADAU1372_RATE_MASK_TDM4 (ADAU1372_RATE_MASK_TDM4_MASTER | 0x20) | 
|  | /* + 192k */ | 
|  | #define ADAU1372_RATE_MASK_TDM2 (ADAU1372_RATE_MASK_TDM4 | 0x80) | 
|  |  | 
|  | static const DECLARE_TLV_DB_MINMAX(adau1372_digital_tlv, -9563, 0); | 
|  | static const DECLARE_TLV_DB_SCALE(adau1372_pga_tlv, -1200, 75, 0); | 
|  | static const DECLARE_TLV_DB_SCALE(adau1372_pga_boost_tlv, 0, 1000, 0); | 
|  |  | 
|  | static const char * const adau1372_bias_text[] = { | 
|  | "Normal operation", "Extreme power saving", "Enhanced performance", | 
|  | "Power saving", | 
|  | }; | 
|  |  | 
|  | static const unsigned int adau1372_bias_adc_values[] = { | 
|  | 0, 2, 3, | 
|  | }; | 
|  |  | 
|  | static const char * const adau1372_bias_adc_text[] = { | 
|  | "Normal operation", "Enhanced performance", "Power saving", | 
|  | }; | 
|  |  | 
|  | static const char * const adau1372_bias_dac_text[] = { | 
|  | "Normal operation", "Power saving", "Superior performance", | 
|  | "Enhanced performance", | 
|  | }; | 
|  |  | 
|  | static SOC_ENUM_SINGLE_DECL(adau1372_bias_hp_enum, | 
|  | ADAU1372_REG_BIAS_CTRL0, 6, adau1372_bias_text); | 
|  | static SOC_ENUM_SINGLE_DECL(adau1372_bias_afe0_1_enum, | 
|  | ADAU1372_REG_BIAS_CTRL0, 4, adau1372_bias_text); | 
|  | static SOC_VALUE_ENUM_SINGLE_DECL(adau1372_bias_adc2_3_enum, | 
|  | ADAU1372_REG_BIAS_CTRL0, 2, 0x3, adau1372_bias_adc_text, | 
|  | adau1372_bias_adc_values); | 
|  | static SOC_VALUE_ENUM_SINGLE_DECL(adau1372_bias_adc0_1_enum, | 
|  | ADAU1372_REG_BIAS_CTRL0, 0, 0x3, adau1372_bias_adc_text, | 
|  | adau1372_bias_adc_values); | 
|  | static SOC_ENUM_SINGLE_DECL(adau1372_bias_afe2_3_enum, | 
|  | ADAU1372_REG_BIAS_CTRL1, 4, adau1372_bias_text); | 
|  | static SOC_ENUM_SINGLE_DECL(adau1372_bias_mic_enum, | 
|  | ADAU1372_REG_BIAS_CTRL1, 2, adau1372_bias_text); | 
|  | static SOC_ENUM_SINGLE_DECL(adau1372_bias_dac_enum, | 
|  | ADAU1372_REG_BIAS_CTRL1, 0, adau1372_bias_dac_text); | 
|  |  | 
|  | static const char * const adau1372_hpf_text[] = { | 
|  | "Off", | 
|  | "1 Hz", | 
|  | "4 Hz", | 
|  | "8 Hz", | 
|  | }; | 
|  |  | 
|  | static SOC_ENUM_SINGLE_DECL(adau1372_hpf0_1_enum, ADAU1372_REG_ADC_CTRL2, 5, | 
|  | adau1372_hpf_text); | 
|  | static SOC_ENUM_SINGLE_DECL(adau1372_hpf2_3_enum, ADAU1372_REG_ADC_CTRL3, 5, | 
|  | adau1372_hpf_text); | 
|  | static const struct snd_kcontrol_new adau1372_controls[] = { | 
|  | SOC_SINGLE_TLV("ADC 0 Capture Volume", ADAU1372_REG_ADC_VOL(0), | 
|  | 0, 0xff, 1, adau1372_digital_tlv), | 
|  | SOC_SINGLE_TLV("ADC 1 Capture Volume", ADAU1372_REG_ADC_VOL(1), | 
|  | 0, 0xff, 1, adau1372_digital_tlv), | 
|  | SOC_SINGLE_TLV("ADC 2 Capture Volume", ADAU1372_REG_ADC_VOL(2), | 
|  | 0, 0xff, 1, adau1372_digital_tlv), | 
|  | SOC_SINGLE_TLV("ADC 3 Capture Volume", ADAU1372_REG_ADC_VOL(3), | 
|  | 0, 0xff, 1, adau1372_digital_tlv), | 
|  | SOC_SINGLE("ADC 0 Capture Switch", ADAU1372_REG_ADC_CTRL0, 3, 1, 1), | 
|  | SOC_SINGLE("ADC 1 Capture Switch", ADAU1372_REG_ADC_CTRL0, 4, 1, 1), | 
|  | SOC_SINGLE("ADC 2 Capture Switch", ADAU1372_REG_ADC_CTRL1, 3, 1, 1), | 
|  | SOC_SINGLE("ADC 3 Capture Switch", ADAU1372_REG_ADC_CTRL1, 4, 1, 1), | 
|  |  | 
|  | SOC_ENUM("ADC 0+1 High-Pass-Filter", adau1372_hpf0_1_enum), | 
|  | SOC_ENUM("ADC 2+3 High-Pass-Filter", adau1372_hpf2_3_enum), | 
|  |  | 
|  | SOC_SINGLE_TLV("PGA 0 Capture Volume", ADAU1372_REG_PGA_CTRL(0), | 
|  | 0, 0x3f, 0, adau1372_pga_tlv), | 
|  | SOC_SINGLE_TLV("PGA 1 Capture Volume", ADAU1372_REG_PGA_CTRL(1), | 
|  | 0, 0x3f, 0, adau1372_pga_tlv), | 
|  | SOC_SINGLE_TLV("PGA 2 Capture Volume", ADAU1372_REG_PGA_CTRL(2), | 
|  | 0, 0x3f, 0, adau1372_pga_tlv), | 
|  | SOC_SINGLE_TLV("PGA 3 Capture Volume", ADAU1372_REG_PGA_CTRL(3), | 
|  | 0, 0x3f, 0, adau1372_pga_tlv), | 
|  | SOC_SINGLE_TLV("PGA 0 Boost Capture Volume", ADAU1372_REG_PGA_BOOST, | 
|  | 0, 1, 0, adau1372_pga_boost_tlv), | 
|  | SOC_SINGLE_TLV("PGA 1 Boost Capture Volume", ADAU1372_REG_PGA_BOOST, | 
|  | 1, 1, 0, adau1372_pga_boost_tlv), | 
|  | SOC_SINGLE_TLV("PGA 2 Boost Capture Volume", ADAU1372_REG_PGA_BOOST, | 
|  | 2, 1, 0, adau1372_pga_boost_tlv), | 
|  | SOC_SINGLE_TLV("PGA 3 Boost Capture Volume", ADAU1372_REG_PGA_BOOST, | 
|  | 3, 1, 0, adau1372_pga_boost_tlv), | 
|  | SOC_SINGLE("PGA 0 Capture Switch", ADAU1372_REG_PGA_CTRL(0), 7, 1, 1), | 
|  | SOC_SINGLE("PGA 1 Capture Switch", ADAU1372_REG_PGA_CTRL(1), 7, 1, 1), | 
|  | SOC_SINGLE("PGA 2 Capture Switch", ADAU1372_REG_PGA_CTRL(2), 7, 1, 1), | 
|  | SOC_SINGLE("PGA 3 Capture Switch", ADAU1372_REG_PGA_CTRL(3), 7, 1, 1), | 
|  |  | 
|  | SOC_SINGLE_TLV("DAC 0 Playback Volume", ADAU1372_REG_DAC_VOL(0), | 
|  | 0, 0xff, 1, adau1372_digital_tlv), | 
|  | SOC_SINGLE_TLV("DAC 1 Playback Volume", ADAU1372_REG_DAC_VOL(1), | 
|  | 0, 0xff, 1, adau1372_digital_tlv), | 
|  | SOC_SINGLE("DAC 0 Playback Switch", ADAU1372_REG_DAC_CTRL, 3, 1, 1), | 
|  | SOC_SINGLE("DAC 1 Playback Switch", ADAU1372_REG_DAC_CTRL, 4, 1, 1), | 
|  |  | 
|  | SOC_ENUM("Headphone Bias", adau1372_bias_hp_enum), | 
|  | SOC_ENUM("Microphone Bias", adau1372_bias_mic_enum), | 
|  | SOC_ENUM("AFE 0+1 Bias", adau1372_bias_afe0_1_enum), | 
|  | SOC_ENUM("AFE 2+3 Bias", adau1372_bias_afe2_3_enum), | 
|  | SOC_ENUM("ADC 0+1 Bias", adau1372_bias_adc0_1_enum), | 
|  | SOC_ENUM("ADC 2+3 Bias", adau1372_bias_adc2_3_enum), | 
|  | SOC_ENUM("DAC 0+1 Bias", adau1372_bias_dac_enum), | 
|  | }; | 
|  |  | 
|  | static const char * const adau1372_decimator_mux_text[] = { | 
|  | "ADC", | 
|  | "DMIC", | 
|  | }; | 
|  |  | 
|  | static SOC_ENUM_SINGLE_DECL(adau1372_decimator0_1_mux_enum, ADAU1372_REG_ADC_CTRL2, | 
|  | 2, adau1372_decimator_mux_text); | 
|  |  | 
|  | static const struct snd_kcontrol_new adau1372_decimator0_1_mux_control = | 
|  | SOC_DAPM_ENUM("Decimator 0+1 Capture Mux", adau1372_decimator0_1_mux_enum); | 
|  |  | 
|  | static SOC_ENUM_SINGLE_DECL(adau1372_decimator2_3_mux_enum, ADAU1372_REG_ADC_CTRL3, | 
|  | 2, adau1372_decimator_mux_text); | 
|  |  | 
|  | static const struct snd_kcontrol_new adau1372_decimator2_3_mux_control = | 
|  | SOC_DAPM_ENUM("Decimator 2+3 Capture Mux", adau1372_decimator2_3_mux_enum); | 
|  |  | 
|  | static const unsigned int adau1372_asrco_mux_values[] = { | 
|  | 4, 5, 6, 7, | 
|  | }; | 
|  |  | 
|  | static const char * const adau1372_asrco_mux_text[] = { | 
|  | "Decimator0", | 
|  | "Decimator1", | 
|  | "Decimator2", | 
|  | "Decimator3", | 
|  | }; | 
|  |  | 
|  | static SOC_VALUE_ENUM_SINGLE_DECL(adau1372_asrco0_mux_enum, ADAU1372_REG_ASRCO_SOURCE_0_1, | 
|  | 0, 0xf, adau1372_asrco_mux_text, adau1372_asrco_mux_values); | 
|  | static SOC_VALUE_ENUM_SINGLE_DECL(adau1372_asrco1_mux_enum, ADAU1372_REG_ASRCO_SOURCE_0_1, | 
|  | 4, 0xf, adau1372_asrco_mux_text, adau1372_asrco_mux_values); | 
|  | static SOC_VALUE_ENUM_SINGLE_DECL(adau1372_asrco2_mux_enum, ADAU1372_REG_ASRCO_SOURCE_2_3, | 
|  | 0, 0xf, adau1372_asrco_mux_text, adau1372_asrco_mux_values); | 
|  | static SOC_VALUE_ENUM_SINGLE_DECL(adau1372_asrco3_mux_enum, ADAU1372_REG_ASRCO_SOURCE_2_3, | 
|  | 4, 0xf, adau1372_asrco_mux_text, adau1372_asrco_mux_values); | 
|  |  | 
|  | static const struct snd_kcontrol_new adau1372_asrco0_mux_control = | 
|  | SOC_DAPM_ENUM("Output ASRC0 Capture Mux", adau1372_asrco0_mux_enum); | 
|  | static const struct snd_kcontrol_new adau1372_asrco1_mux_control = | 
|  | SOC_DAPM_ENUM("Output ASRC1 Capture Mux", adau1372_asrco1_mux_enum); | 
|  | static const struct snd_kcontrol_new adau1372_asrco2_mux_control = | 
|  | SOC_DAPM_ENUM("Output ASRC2 Capture Mux", adau1372_asrco2_mux_enum); | 
|  | static const struct snd_kcontrol_new adau1372_asrco3_mux_control = | 
|  | SOC_DAPM_ENUM("Output ASRC3 Capture Mux", adau1372_asrco3_mux_enum); | 
|  |  | 
|  | static const unsigned int adau1372_sout_mux_values[] = { | 
|  | 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 | 
|  | }; | 
|  |  | 
|  | static const char * const adau1372_sout_mux_text[] = { | 
|  | "Output ASRC0", | 
|  | "Output ASRC1", | 
|  | "Output ASRC2", | 
|  | "Output ASRC3", | 
|  | "Serial Input 0", | 
|  | "Serial Input 1", | 
|  | "Serial Input 2", | 
|  | "Serial Input 3", | 
|  | "Serial Input 4", | 
|  | "Serial Input 5", | 
|  | "Serial Input 6", | 
|  | "Serial Input 7", | 
|  | }; | 
|  |  | 
|  | static SOC_VALUE_ENUM_SINGLE_DECL(adau1372_sout0_mux_enum, ADAU1372_REG_SOUT_SOURCE_0_1, | 
|  | 0, 0xf, adau1372_sout_mux_text, adau1372_sout_mux_values); | 
|  | static SOC_VALUE_ENUM_SINGLE_DECL(adau1372_sout1_mux_enum, ADAU1372_REG_SOUT_SOURCE_0_1, | 
|  | 4, 0xf, adau1372_sout_mux_text, adau1372_sout_mux_values); | 
|  | static SOC_VALUE_ENUM_SINGLE_DECL(adau1372_sout2_mux_enum, ADAU1372_REG_SOUT_SOURCE_2_3, | 
|  | 0, 0xf, adau1372_sout_mux_text, adau1372_sout_mux_values); | 
|  | static SOC_VALUE_ENUM_SINGLE_DECL(adau1372_sout3_mux_enum, ADAU1372_REG_SOUT_SOURCE_2_3, | 
|  | 4, 0xf, adau1372_sout_mux_text, adau1372_sout_mux_values); | 
|  | static SOC_VALUE_ENUM_SINGLE_DECL(adau1372_sout4_mux_enum, ADAU1372_REG_SOUT_SOURCE_4_5, | 
|  | 0, 0xf, adau1372_sout_mux_text, adau1372_sout_mux_values); | 
|  | static SOC_VALUE_ENUM_SINGLE_DECL(adau1372_sout5_mux_enum, ADAU1372_REG_SOUT_SOURCE_4_5, | 
|  | 4, 0xf, adau1372_sout_mux_text, adau1372_sout_mux_values); | 
|  | static SOC_VALUE_ENUM_SINGLE_DECL(adau1372_sout6_mux_enum, ADAU1372_REG_SOUT_SOURCE_6_7, | 
|  | 0, 0xf, adau1372_sout_mux_text, adau1372_sout_mux_values); | 
|  | static SOC_VALUE_ENUM_SINGLE_DECL(adau1372_sout7_mux_enum, ADAU1372_REG_SOUT_SOURCE_6_7, | 
|  | 4, 0xf, adau1372_sout_mux_text, adau1372_sout_mux_values); | 
|  |  | 
|  | static const struct snd_kcontrol_new adau1372_sout0_mux_control = | 
|  | SOC_DAPM_ENUM("Serial Output 0 Capture Mux", adau1372_sout0_mux_enum); | 
|  | static const struct snd_kcontrol_new adau1372_sout1_mux_control = | 
|  | SOC_DAPM_ENUM("Serial Output 1 Capture Mux", adau1372_sout1_mux_enum); | 
|  | static const struct snd_kcontrol_new adau1372_sout2_mux_control = | 
|  | SOC_DAPM_ENUM("Serial Output 2 Capture Mux", adau1372_sout2_mux_enum); | 
|  | static const struct snd_kcontrol_new adau1372_sout3_mux_control = | 
|  | SOC_DAPM_ENUM("Serial Output 3 Capture Mux", adau1372_sout3_mux_enum); | 
|  | static const struct snd_kcontrol_new adau1372_sout4_mux_control = | 
|  | SOC_DAPM_ENUM("Serial Output 4 Capture Mux", adau1372_sout4_mux_enum); | 
|  | static const struct snd_kcontrol_new adau1372_sout5_mux_control = | 
|  | SOC_DAPM_ENUM("Serial Output 5 Capture Mux", adau1372_sout5_mux_enum); | 
|  | static const struct snd_kcontrol_new adau1372_sout6_mux_control = | 
|  | SOC_DAPM_ENUM("Serial Output 6 Capture Mux", adau1372_sout6_mux_enum); | 
|  | static const struct snd_kcontrol_new adau1372_sout7_mux_control = | 
|  | SOC_DAPM_ENUM("Serial Output 7 Capture Mux", adau1372_sout7_mux_enum); | 
|  |  | 
|  | static const char * const adau1372_asrci_mux_text[] = { | 
|  | "Serial Input 0+1", | 
|  | "Serial Input 2+3", | 
|  | "Serial Input 4+5", | 
|  | "Serial Input 6+7", | 
|  | }; | 
|  |  | 
|  | static SOC_ENUM_SINGLE_DECL(adau1372_asrci_mux_enum, | 
|  | ADAU1372_REG_ASRC_MODE, 2, adau1372_asrci_mux_text); | 
|  |  | 
|  | static const struct snd_kcontrol_new adau1372_asrci_mux_control = | 
|  | SOC_DAPM_ENUM("Input ASRC Playback Mux", adau1372_asrci_mux_enum); | 
|  |  | 
|  | static const unsigned int adau1372_dac_mux_values[] = { | 
|  | 12, 13 | 
|  | }; | 
|  |  | 
|  | static const char * const adau1372_dac_mux_text[] = { | 
|  | "Input ASRC0", | 
|  | "Input ASRC1", | 
|  | }; | 
|  |  | 
|  | static SOC_VALUE_ENUM_SINGLE_DECL(adau1372_dac0_mux_enum, ADAU1372_REG_DAC_SOURCE, | 
|  | 0, 0xf, adau1372_dac_mux_text, adau1372_dac_mux_values); | 
|  | static SOC_VALUE_ENUM_SINGLE_DECL(adau1372_dac1_mux_enum, ADAU1372_REG_DAC_SOURCE, | 
|  | 4, 0xf, adau1372_dac_mux_text, adau1372_dac_mux_values); | 
|  |  | 
|  | static const struct snd_kcontrol_new adau1372_dac0_mux_control = | 
|  | SOC_DAPM_ENUM("DAC 0 Playback Mux", adau1372_dac0_mux_enum); | 
|  | static const struct snd_kcontrol_new adau1372_dac1_mux_control = | 
|  | SOC_DAPM_ENUM("DAC 1 Playback Mux", adau1372_dac1_mux_enum); | 
|  |  | 
|  | static const struct snd_soc_dapm_widget adau1372_dapm_widgets[] = { | 
|  | SND_SOC_DAPM_INPUT("AIN0"), | 
|  | SND_SOC_DAPM_INPUT("AIN1"), | 
|  | SND_SOC_DAPM_INPUT("AIN2"), | 
|  | SND_SOC_DAPM_INPUT("AIN3"), | 
|  | SND_SOC_DAPM_INPUT("DMIC0_1"), | 
|  | SND_SOC_DAPM_INPUT("DMIC2_3"), | 
|  |  | 
|  | SND_SOC_DAPM_SUPPLY("MICBIAS0", ADAU1372_REG_MICBIAS, 4, 0, NULL, 0), | 
|  | SND_SOC_DAPM_SUPPLY("MICBIAS1", ADAU1372_REG_MICBIAS, 5, 0, NULL, 0), | 
|  |  | 
|  | SND_SOC_DAPM_PGA("PGA0", ADAU1372_REG_PGA_CTRL(0), 6, 0, NULL, 0), | 
|  | SND_SOC_DAPM_PGA("PGA1", ADAU1372_REG_PGA_CTRL(1), 6, 0, NULL, 0), | 
|  | SND_SOC_DAPM_PGA("PGA2", ADAU1372_REG_PGA_CTRL(2), 6, 0, NULL, 0), | 
|  | SND_SOC_DAPM_PGA("PGA3", ADAU1372_REG_PGA_CTRL(3), 6, 0, NULL, 0), | 
|  | SND_SOC_DAPM_ADC("ADC0", NULL, ADAU1372_REG_ADC_CTRL2, 0, 0), | 
|  | SND_SOC_DAPM_ADC("ADC1", NULL, ADAU1372_REG_ADC_CTRL2, 1, 0), | 
|  | SND_SOC_DAPM_ADC("ADC2", NULL, ADAU1372_REG_ADC_CTRL3, 0, 0), | 
|  | SND_SOC_DAPM_ADC("ADC3", NULL, ADAU1372_REG_ADC_CTRL3, 1, 0), | 
|  |  | 
|  | SND_SOC_DAPM_SUPPLY("ADC0 Filter", ADAU1372_REG_DECIM_PWR, 0, 0, NULL, 0), | 
|  | SND_SOC_DAPM_SUPPLY("ADC1 Filter", ADAU1372_REG_DECIM_PWR, 1, 0, NULL, 0), | 
|  | SND_SOC_DAPM_SUPPLY("ADC2 Filter", ADAU1372_REG_DECIM_PWR, 2, 0, NULL, 0), | 
|  | SND_SOC_DAPM_SUPPLY("ADC3 Filter", ADAU1372_REG_DECIM_PWR, 3, 0, NULL, 0), | 
|  | SND_SOC_DAPM_SUPPLY("Output ASRC0 Decimator", ADAU1372_REG_DECIM_PWR, 4, 0, NULL, 0), | 
|  | SND_SOC_DAPM_SUPPLY("Output ASRC1 Decimator", ADAU1372_REG_DECIM_PWR, 5, 0, NULL, 0), | 
|  | SND_SOC_DAPM_SUPPLY("Output ASRC2 Decimator", ADAU1372_REG_DECIM_PWR, 6, 0, NULL, 0), | 
|  | SND_SOC_DAPM_SUPPLY("Output ASRC3 Decimator", ADAU1372_REG_DECIM_PWR, 7, 0, NULL, 0), | 
|  |  | 
|  | SND_SOC_DAPM_MUX("Decimator0 Mux", SND_SOC_NOPM, 0, 0, &adau1372_decimator0_1_mux_control), | 
|  | SND_SOC_DAPM_MUX("Decimator1 Mux", SND_SOC_NOPM, 0, 0, &adau1372_decimator0_1_mux_control), | 
|  | SND_SOC_DAPM_MUX("Decimator2 Mux", SND_SOC_NOPM, 0, 0, &adau1372_decimator2_3_mux_control), | 
|  | SND_SOC_DAPM_MUX("Decimator3 Mux", SND_SOC_NOPM, 0, 0, &adau1372_decimator2_3_mux_control), | 
|  |  | 
|  | SND_SOC_DAPM_MUX("Output ASRC0 Mux", SND_SOC_NOPM, 0, 0, &adau1372_asrco0_mux_control), | 
|  | SND_SOC_DAPM_MUX("Output ASRC1 Mux", SND_SOC_NOPM, 0, 0, &adau1372_asrco1_mux_control), | 
|  | SND_SOC_DAPM_MUX("Output ASRC2 Mux", SND_SOC_NOPM, 0, 0, &adau1372_asrco2_mux_control), | 
|  | SND_SOC_DAPM_MUX("Output ASRC3 Mux", SND_SOC_NOPM, 0, 0, &adau1372_asrco3_mux_control), | 
|  | SND_SOC_DAPM_MUX("Serial Output 0 Capture Mux", SND_SOC_NOPM, 0, 0, | 
|  | &adau1372_sout0_mux_control), | 
|  | SND_SOC_DAPM_MUX("Serial Output 1 Capture Mux", SND_SOC_NOPM, 0, 0, | 
|  | &adau1372_sout1_mux_control), | 
|  | SND_SOC_DAPM_MUX("Serial Output 2 Capture Mux", SND_SOC_NOPM, 0, 0, | 
|  | &adau1372_sout2_mux_control), | 
|  | SND_SOC_DAPM_MUX("Serial Output 3 Capture Mux", SND_SOC_NOPM, 0, 0, | 
|  | &adau1372_sout3_mux_control), | 
|  | SND_SOC_DAPM_MUX("Serial Output 4 Capture Mux", SND_SOC_NOPM, 0, 0, | 
|  | &adau1372_sout4_mux_control), | 
|  | SND_SOC_DAPM_MUX("Serial Output 5 Capture Mux", SND_SOC_NOPM, 0, 0, | 
|  | &adau1372_sout5_mux_control), | 
|  | SND_SOC_DAPM_MUX("Serial Output 6 Capture Mux", SND_SOC_NOPM, 0, 0, | 
|  | &adau1372_sout6_mux_control), | 
|  | SND_SOC_DAPM_MUX("Serial Output 7 Capture Mux", SND_SOC_NOPM, 0, 0, | 
|  | &adau1372_sout7_mux_control), | 
|  |  | 
|  | SND_SOC_DAPM_AIF_IN("Serial Input 0", NULL, 0, SND_SOC_NOPM, 0, 0), | 
|  | SND_SOC_DAPM_AIF_IN("Serial Input 1", NULL, 1, SND_SOC_NOPM, 0, 0), | 
|  | SND_SOC_DAPM_AIF_IN("Serial Input 2", NULL, 2, SND_SOC_NOPM, 0, 0), | 
|  | SND_SOC_DAPM_AIF_IN("Serial Input 3", NULL, 3, SND_SOC_NOPM, 0, 0), | 
|  | SND_SOC_DAPM_AIF_IN("Serial Input 4", NULL, 4, SND_SOC_NOPM, 0, 0), | 
|  | SND_SOC_DAPM_AIF_IN("Serial Input 5", NULL, 5, SND_SOC_NOPM, 0, 0), | 
|  | SND_SOC_DAPM_AIF_IN("Serial Input 6", NULL, 6, SND_SOC_NOPM, 0, 0), | 
|  | SND_SOC_DAPM_AIF_IN("Serial Input 7", NULL, 7, SND_SOC_NOPM, 0, 0), | 
|  |  | 
|  | SND_SOC_DAPM_AIF_OUT("Serial Output 0", NULL, 0, SND_SOC_NOPM, 0, 0), | 
|  | SND_SOC_DAPM_AIF_OUT("Serial Output 1", NULL, 1, SND_SOC_NOPM, 0, 0), | 
|  | SND_SOC_DAPM_AIF_OUT("Serial Output 2", NULL, 2, SND_SOC_NOPM, 0, 0), | 
|  | SND_SOC_DAPM_AIF_OUT("Serial Output 3", NULL, 3, SND_SOC_NOPM, 0, 0), | 
|  | SND_SOC_DAPM_AIF_OUT("Serial Output 4", NULL, 4, SND_SOC_NOPM, 0, 0), | 
|  | SND_SOC_DAPM_AIF_OUT("Serial Output 5", NULL, 5, SND_SOC_NOPM, 0, 0), | 
|  | SND_SOC_DAPM_AIF_OUT("Serial Output 6", NULL, 6, SND_SOC_NOPM, 0, 0), | 
|  | SND_SOC_DAPM_AIF_OUT("Serial Output 7", NULL, 7, SND_SOC_NOPM, 0, 0), | 
|  |  | 
|  | SND_SOC_DAPM_SUPPLY("Output ASRC Supply", ADAU1372_REG_ASRC_MODE, 1, 0, NULL, 0), | 
|  | SND_SOC_DAPM_SUPPLY("Input ASRC Supply", ADAU1372_REG_ASRC_MODE, 0, 0, NULL, 0), | 
|  |  | 
|  | SND_SOC_DAPM_SUPPLY("DAC1 Modulator", ADAU1372_REG_INTERP_PWR, 3, 0, NULL, 0), | 
|  | SND_SOC_DAPM_SUPPLY("DAC0 Modulator", ADAU1372_REG_INTERP_PWR, 2, 0, NULL, 0), | 
|  | SND_SOC_DAPM_SUPPLY("Input ASRC1 Interpolator", ADAU1372_REG_INTERP_PWR, 1, 0, NULL, 0), | 
|  | SND_SOC_DAPM_SUPPLY("Input ASRC0 Interpolator", ADAU1372_REG_INTERP_PWR, 0, 0, NULL, 0), | 
|  |  | 
|  | SND_SOC_DAPM_MUX("Input ASRC0 Mux", SND_SOC_NOPM, 0, 0, &adau1372_asrci_mux_control), | 
|  | SND_SOC_DAPM_MUX("Input ASRC1 Mux", SND_SOC_NOPM, 0, 0, &adau1372_asrci_mux_control), | 
|  |  | 
|  | SND_SOC_DAPM_MUX("DAC 0 Mux", SND_SOC_NOPM, 0, 0, &adau1372_dac0_mux_control), | 
|  | SND_SOC_DAPM_MUX("DAC 1 Mux", SND_SOC_NOPM, 0, 0, &adau1372_dac1_mux_control), | 
|  |  | 
|  | SND_SOC_DAPM_DAC("DAC0", NULL, ADAU1372_REG_DAC_CTRL, 0, 0), | 
|  | SND_SOC_DAPM_DAC("DAC1", NULL, ADAU1372_REG_DAC_CTRL, 1, 0), | 
|  |  | 
|  | SND_SOC_DAPM_OUT_DRV("OP_STAGE_LP", ADAU1372_REG_OP_STAGE_CTRL, 0, 1, NULL, 0), | 
|  | SND_SOC_DAPM_OUT_DRV("OP_STAGE_LN", ADAU1372_REG_OP_STAGE_CTRL, 1, 1, NULL, 0), | 
|  | SND_SOC_DAPM_OUT_DRV("OP_STAGE_RP", ADAU1372_REG_OP_STAGE_CTRL, 2, 1, NULL, 0), | 
|  | SND_SOC_DAPM_OUT_DRV("OP_STAGE_RN", ADAU1372_REG_OP_STAGE_CTRL, 3, 1, NULL, 0), | 
|  |  | 
|  | SND_SOC_DAPM_OUTPUT("HPOUTL"), | 
|  | SND_SOC_DAPM_OUTPUT("HPOUTR"), | 
|  | }; | 
|  |  | 
|  | #define ADAU1372_SOUT_ROUTES(x) \ | 
|  | { "Serial Output " #x " Capture Mux", "Output ASRC0", "Output ASRC0 Mux" }, \ | 
|  | { "Serial Output " #x " Capture Mux", "Output ASRC1", "Output ASRC1 Mux" }, \ | 
|  | { "Serial Output " #x " Capture Mux", "Output ASRC2", "Output ASRC2 Mux" }, \ | 
|  | { "Serial Output " #x " Capture Mux", "Output ASRC3", "Output ASRC3 Mux" }, \ | 
|  | { "Serial Output " #x " Capture Mux", "Serial Input 0", "Serial Input 0" }, \ | 
|  | { "Serial Output " #x " Capture Mux", "Serial Input 1", "Serial Input 1" }, \ | 
|  | { "Serial Output " #x " Capture Mux", "Serial Input 2", "Serial Input 2" }, \ | 
|  | { "Serial Output " #x " Capture Mux", "Serial Input 3", "Serial Input 3" }, \ | 
|  | { "Serial Output " #x " Capture Mux", "Serial Input 4", "Serial Input 4" }, \ | 
|  | { "Serial Output " #x " Capture Mux", "Serial Input 5", "Serial Input 5" }, \ | 
|  | { "Serial Output " #x " Capture Mux", "Serial Input 6", "Serial Input 6" }, \ | 
|  | { "Serial Output " #x " Capture Mux", "Serial Input 7", "Serial Input 7" }, \ | 
|  | { "Serial Output " #x, NULL, "Serial Output " #x " Capture Mux" }, \ | 
|  | { "Capture", NULL, "Serial Output " #x } | 
|  |  | 
|  | #define ADAU1372_ASRCO_ROUTES(x) \ | 
|  | { "Output ASRC" #x " Mux", "Decimator0", "Decimator0 Mux" }, \ | 
|  | { "Output ASRC" #x " Mux", "Decimator1", "Decimator1 Mux" }, \ | 
|  | { "Output ASRC" #x " Mux", "Decimator2", "Decimator2 Mux" }, \ | 
|  | { "Output ASRC" #x " Mux", "Decimator3", "Decimator3 Mux" } | 
|  |  | 
|  | static const struct snd_soc_dapm_route adau1372_dapm_routes[] = { | 
|  | { "PGA0", NULL, "AIN0" }, | 
|  | { "PGA1", NULL, "AIN1" }, | 
|  | { "PGA2", NULL, "AIN2" }, | 
|  | { "PGA3", NULL, "AIN3" }, | 
|  |  | 
|  | { "ADC0", NULL, "PGA0" }, | 
|  | { "ADC1", NULL, "PGA1" }, | 
|  | { "ADC2", NULL, "PGA2" }, | 
|  | { "ADC3", NULL, "PGA3" }, | 
|  |  | 
|  | { "Decimator0 Mux", "ADC", "ADC0" }, | 
|  | { "Decimator1 Mux", "ADC", "ADC1" }, | 
|  | { "Decimator2 Mux", "ADC", "ADC2" }, | 
|  | { "Decimator3 Mux", "ADC", "ADC3" }, | 
|  |  | 
|  | { "Decimator0 Mux", "DMIC", "DMIC0_1" }, | 
|  | { "Decimator1 Mux", "DMIC", "DMIC0_1" }, | 
|  | { "Decimator2 Mux", "DMIC", "DMIC2_3" }, | 
|  | { "Decimator3 Mux", "DMIC", "DMIC2_3" }, | 
|  |  | 
|  | { "Decimator0 Mux", NULL, "ADC0 Filter" }, | 
|  | { "Decimator1 Mux", NULL, "ADC1 Filter" }, | 
|  | { "Decimator2 Mux", NULL, "ADC2 Filter" }, | 
|  | { "Decimator3 Mux", NULL, "ADC3 Filter" }, | 
|  |  | 
|  | { "Output ASRC0 Mux", NULL, "Output ASRC Supply" }, | 
|  | { "Output ASRC1 Mux", NULL, "Output ASRC Supply" }, | 
|  | { "Output ASRC2 Mux", NULL, "Output ASRC Supply" }, | 
|  | { "Output ASRC3 Mux", NULL, "Output ASRC Supply" }, | 
|  | { "Output ASRC0 Mux", NULL, "Output ASRC0 Decimator" }, | 
|  | { "Output ASRC1 Mux", NULL, "Output ASRC1 Decimator" }, | 
|  | { "Output ASRC2 Mux", NULL, "Output ASRC2 Decimator" }, | 
|  | { "Output ASRC3 Mux", NULL, "Output ASRC3 Decimator" }, | 
|  |  | 
|  | ADAU1372_ASRCO_ROUTES(0), | 
|  | ADAU1372_ASRCO_ROUTES(1), | 
|  | ADAU1372_ASRCO_ROUTES(2), | 
|  | ADAU1372_ASRCO_ROUTES(3), | 
|  |  | 
|  | ADAU1372_SOUT_ROUTES(0), | 
|  | ADAU1372_SOUT_ROUTES(1), | 
|  | ADAU1372_SOUT_ROUTES(2), | 
|  | ADAU1372_SOUT_ROUTES(3), | 
|  | ADAU1372_SOUT_ROUTES(4), | 
|  | ADAU1372_SOUT_ROUTES(5), | 
|  | ADAU1372_SOUT_ROUTES(6), | 
|  | ADAU1372_SOUT_ROUTES(7), | 
|  |  | 
|  | { "Serial Input 0", NULL, "Playback" }, | 
|  | { "Serial Input 1", NULL, "Playback" }, | 
|  | { "Serial Input 2", NULL, "Playback" }, | 
|  | { "Serial Input 3", NULL, "Playback" }, | 
|  | { "Serial Input 4", NULL, "Playback" }, | 
|  | { "Serial Input 5", NULL, "Playback" }, | 
|  | { "Serial Input 6", NULL, "Playback" }, | 
|  | { "Serial Input 7", NULL, "Playback" }, | 
|  |  | 
|  | { "Input ASRC0 Mux", "Serial Input 0+1", "Serial Input 0" }, | 
|  | { "Input ASRC1 Mux", "Serial Input 0+1", "Serial Input 1" }, | 
|  | { "Input ASRC0 Mux", "Serial Input 2+3", "Serial Input 2" }, | 
|  | { "Input ASRC1 Mux", "Serial Input 2+3", "Serial Input 3" }, | 
|  | { "Input ASRC0 Mux", "Serial Input 4+5", "Serial Input 4" }, | 
|  | { "Input ASRC1 Mux", "Serial Input 4+5", "Serial Input 5" }, | 
|  | { "Input ASRC0 Mux", "Serial Input 6+7", "Serial Input 6" }, | 
|  | { "Input ASRC1 Mux", "Serial Input 6+7", "Serial Input 7" }, | 
|  | { "Input ASRC0 Mux", NULL, "Input ASRC Supply" }, | 
|  | { "Input ASRC1 Mux", NULL, "Input ASRC Supply" }, | 
|  | { "Input ASRC0 Mux", NULL, "Input ASRC0 Interpolator" }, | 
|  | { "Input ASRC1 Mux", NULL, "Input ASRC1 Interpolator" }, | 
|  |  | 
|  | { "DAC 0 Mux", "Input ASRC0", "Input ASRC0 Mux" }, | 
|  | { "DAC 0 Mux", "Input ASRC1", "Input ASRC1 Mux" }, | 
|  | { "DAC 1 Mux", "Input ASRC0", "Input ASRC0 Mux" }, | 
|  | { "DAC 1 Mux", "Input ASRC1", "Input ASRC1 Mux" }, | 
|  |  | 
|  | { "DAC0", NULL, "DAC 0 Mux" }, | 
|  | { "DAC1", NULL, "DAC 1 Mux" }, | 
|  | { "DAC0", NULL, "DAC0 Modulator" }, | 
|  | { "DAC1", NULL, "DAC1 Modulator" }, | 
|  |  | 
|  | { "OP_STAGE_LP", NULL, "DAC0" }, | 
|  | { "OP_STAGE_LN", NULL, "DAC0" }, | 
|  | { "OP_STAGE_RP", NULL, "DAC1" }, | 
|  | { "OP_STAGE_RN", NULL, "DAC1" }, | 
|  |  | 
|  | { "HPOUTL", NULL, "OP_STAGE_LP" }, | 
|  | { "HPOUTL", NULL, "OP_STAGE_LN" }, | 
|  | { "HPOUTR", NULL, "OP_STAGE_RP" }, | 
|  | { "HPOUTR", NULL, "OP_STAGE_RN" }, | 
|  | }; | 
|  |  | 
|  | static int adau1372_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) | 
|  | { | 
|  | struct adau1372 *adau1372 = snd_soc_dai_get_drvdata(dai); | 
|  | unsigned int sai0 = 0, sai1 = 0; | 
|  | bool invert_lrclk = false; | 
|  |  | 
|  | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | 
|  | case SND_SOC_DAIFMT_CBM_CFM: | 
|  | adau1372->master = true; | 
|  | sai1 |= ADAU1372_SAI1_MS; | 
|  | break; | 
|  | case SND_SOC_DAIFMT_CBS_CFS: | 
|  | adau1372->master = false; | 
|  | break; | 
|  | default: | 
|  | return -EINVAL; | 
|  | } | 
|  |  | 
|  | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { | 
|  | case SND_SOC_DAIFMT_NB_NF: | 
|  | invert_lrclk = false; | 
|  | break; | 
|  | case SND_SOC_DAIFMT_NB_IF: | 
|  | invert_lrclk = true; | 
|  | break; | 
|  | case SND_SOC_DAIFMT_IB_NF: | 
|  | invert_lrclk = false; | 
|  | sai1 |= ADAU1372_SAI1_BCLKEDGE; | 
|  | break; | 
|  | case SND_SOC_DAIFMT_IB_IF: | 
|  | invert_lrclk = true; | 
|  | sai1 |= ADAU1372_SAI1_BCLKEDGE; | 
|  | break; | 
|  | } | 
|  |  | 
|  | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | 
|  | case SND_SOC_DAIFMT_I2S: | 
|  | sai0 |= ADAU1372_SAI0_DELAY1; | 
|  | break; | 
|  | case SND_SOC_DAIFMT_LEFT_J: | 
|  | sai0 |= ADAU1372_SAI0_DELAY0; | 
|  | invert_lrclk = !invert_lrclk; | 
|  | break; | 
|  | case SND_SOC_DAIFMT_DSP_A: | 
|  | sai0 |= ADAU1372_SAI0_DELAY1; | 
|  | sai1 |= ADAU1372_SAI1_LR_MODE; | 
|  | break; | 
|  | case SND_SOC_DAIFMT_DSP_B: | 
|  | sai0 |= ADAU1372_SAI0_DELAY0; | 
|  | sai1 |= ADAU1372_SAI1_LR_MODE; | 
|  | break; | 
|  | } | 
|  |  | 
|  | if (invert_lrclk) | 
|  | sai1 |= ADAU1372_SAI1_LR_POL; | 
|  |  | 
|  | regmap_update_bits(adau1372->regmap, ADAU1372_REG_SAI0, ADAU1372_SAI0_DELAY_MASK, sai0); | 
|  | regmap_update_bits(adau1372->regmap, ADAU1372_REG_SAI1, | 
|  | ADAU1372_SAI1_MS | ADAU1372_SAI1_BCLKEDGE | | 
|  | ADAU1372_SAI1_LR_MODE | ADAU1372_SAI1_LR_POL, sai1); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static int adau1372_hw_params(struct snd_pcm_substream *substream, | 
|  | struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) | 
|  | { | 
|  | struct adau1372 *adau1372 = snd_soc_dai_get_drvdata(dai); | 
|  | unsigned int rate = params_rate(params); | 
|  | unsigned int slot_width; | 
|  | unsigned int sai0, sai1; | 
|  | unsigned int i; | 
|  |  | 
|  | for (i = 0; i < ARRAY_SIZE(adau1372_rates); i++) { | 
|  | if (rate == adau1372_rates[i]) | 
|  | break; | 
|  | } | 
|  |  | 
|  | if (i == ARRAY_SIZE(adau1372_rates)) | 
|  | return -EINVAL; | 
|  |  | 
|  | sai0 = i; | 
|  |  | 
|  | slot_width = adau1372->slot_width; | 
|  | if (slot_width == 0) | 
|  | slot_width = params_width(params); | 
|  |  | 
|  | switch (slot_width) { | 
|  | case 16: | 
|  | sai1 = ADAU1372_SAI1_BCLKRATE; | 
|  | break; | 
|  | case 32: | 
|  | sai1 = 0; | 
|  | break; | 
|  | default: | 
|  | return -EINVAL; | 
|  | } | 
|  |  | 
|  | regmap_update_bits(adau1372->regmap, ADAU1372_REG_SAI0, ADAU1372_SAI0_FS_MASK, sai0); | 
|  | regmap_update_bits(adau1372->regmap, ADAU1372_REG_SAI1, ADAU1372_SAI1_BCLKRATE, sai1); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static int adau1372_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, | 
|  | unsigned int rx_mask, int slots, int width) | 
|  | { | 
|  | struct adau1372 *adau1372 = snd_soc_dai_get_drvdata(dai); | 
|  | unsigned int sai0, sai1; | 
|  |  | 
|  | /* I2S mode */ | 
|  | if (slots == 0) { | 
|  | /* The other settings dont matter in I2S mode */ | 
|  | regmap_update_bits(adau1372->regmap, ADAU1372_REG_SAI0, | 
|  | ADAU1372_SAI0_SAI_MASK, ADAU1372_SAI0_SAI_I2S); | 
|  | adau1372->rate_constraints.mask = ADAU1372_RATE_MASK_TDM2; | 
|  | adau1372->slot_width = 0; | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* We have 8 channels anything outside that is not supported */ | 
|  | if ((tx_mask & ~0xff) != 0 || (rx_mask & ~0xff) != 0) | 
|  | return -EINVAL; | 
|  |  | 
|  | switch (width) { | 
|  | case 16: | 
|  | sai1 = ADAU1372_SAI1_BCLK_TDMC; | 
|  | break; | 
|  | case 32: | 
|  | sai1 = 0; | 
|  | break; | 
|  | default: | 
|  | return -EINVAL; | 
|  | } | 
|  |  | 
|  | switch (slots) { | 
|  | case 2: | 
|  | sai0 = ADAU1372_SAI0_SAI_TDM2; | 
|  | adau1372->rate_constraints.mask = ADAU1372_RATE_MASK_TDM2; | 
|  | break; | 
|  | case 4: | 
|  | sai0 = ADAU1372_SAI0_SAI_TDM4; | 
|  | if (adau1372->master) | 
|  | adau1372->rate_constraints.mask = ADAU1372_RATE_MASK_TDM4_MASTER; | 
|  | else | 
|  | adau1372->rate_constraints.mask = ADAU1372_RATE_MASK_TDM4; | 
|  | break; | 
|  | case 8: | 
|  | sai0 = ADAU1372_SAI0_SAI_TDM8; | 
|  | adau1372->rate_constraints.mask = ADAU1372_RATE_MASK_TDM8; | 
|  | break; | 
|  | default: | 
|  | return -EINVAL; | 
|  | } | 
|  |  | 
|  | adau1372->slot_width = width; | 
|  |  | 
|  | regmap_update_bits(adau1372->regmap, ADAU1372_REG_SAI0, ADAU1372_SAI0_SAI_MASK, sai0); | 
|  | regmap_update_bits(adau1372->regmap, ADAU1372_REG_SAI1, ADAU1372_SAI1_BCLK_TDMC, sai1); | 
|  |  | 
|  | /* Mask is inverted in hardware */ | 
|  | regmap_write(adau1372->regmap, ADAU1372_REG_SOUT_CTRL, ~tx_mask); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static int adau1372_set_tristate(struct snd_soc_dai *dai, int tristate) | 
|  | { | 
|  | struct adau1372 *adau1372 = snd_soc_dai_get_drvdata(dai); | 
|  | unsigned int sai1; | 
|  |  | 
|  | if (tristate) | 
|  | sai1 = ADAU1372_SAI1_TDM_TS; | 
|  | else | 
|  | sai1 = 0; | 
|  |  | 
|  | return regmap_update_bits(adau1372->regmap, ADAU1372_REG_SAI1, ADAU1372_SAI1_TDM_TS, sai1); | 
|  | } | 
|  |  | 
|  | static int adau1372_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) | 
|  | { | 
|  | struct adau1372 *adau1372 = snd_soc_dai_get_drvdata(dai); | 
|  |  | 
|  | snd_pcm_hw_constraint_list(substream->runtime, 0, SNDRV_PCM_HW_PARAM_RATE, | 
|  | &adau1372->rate_constraints); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static void adau1372_enable_pll(struct adau1372 *adau1372) | 
|  | { | 
|  | unsigned int val, timeout = 0; | 
|  | int ret; | 
|  |  | 
|  | regmap_update_bits(adau1372->regmap, ADAU1372_REG_CLK_CTRL, | 
|  | ADAU1372_CLK_CTRL_PLL_EN, ADAU1372_CLK_CTRL_PLL_EN); | 
|  | do { | 
|  | /* Takes about 1ms to lock */ | 
|  | usleep_range(1000, 2000); | 
|  | ret = regmap_read(adau1372->regmap, ADAU1372_REG_PLL(5), &val); | 
|  | if (ret) | 
|  | break; | 
|  | timeout++; | 
|  | } while (!(val & 1) && timeout < 3); | 
|  |  | 
|  | if (ret < 0 || !(val & 1)) | 
|  | dev_err(adau1372->dev, "Failed to lock PLL\n"); | 
|  | } | 
|  |  | 
|  | static void adau1372_set_power(struct adau1372 *adau1372, bool enable) | 
|  | { | 
|  | if (adau1372->enabled == enable) | 
|  | return; | 
|  |  | 
|  | if (enable) { | 
|  | unsigned int clk_ctrl = ADAU1372_CLK_CTRL_MCLK_EN; | 
|  |  | 
|  | clk_prepare_enable(adau1372->mclk); | 
|  | if (adau1372->pd_gpio) | 
|  | gpiod_set_value(adau1372->pd_gpio, 0); | 
|  |  | 
|  | if (adau1372->switch_mode) | 
|  | adau1372->switch_mode(adau1372->dev); | 
|  |  | 
|  | regcache_cache_only(adau1372->regmap, false); | 
|  |  | 
|  | /* | 
|  | * Clocks needs to be enabled before any other register can be | 
|  | * accessed. | 
|  | */ | 
|  | if (adau1372->use_pll) { | 
|  | adau1372_enable_pll(adau1372); | 
|  | clk_ctrl |= ADAU1372_CLK_CTRL_CLKSRC; | 
|  | } | 
|  |  | 
|  | regmap_update_bits(adau1372->regmap, ADAU1372_REG_CLK_CTRL, | 
|  | ADAU1372_CLK_CTRL_MCLK_EN | ADAU1372_CLK_CTRL_CLKSRC, clk_ctrl); | 
|  | regcache_sync(adau1372->regmap); | 
|  | } else { | 
|  | if (adau1372->pd_gpio) { | 
|  | /* | 
|  | * This will turn everything off and reset the register | 
|  | * map. No need to do any register writes to manually | 
|  | * turn things off. | 
|  | */ | 
|  | gpiod_set_value(adau1372->pd_gpio, 1); | 
|  | regcache_mark_dirty(adau1372->regmap); | 
|  | } else { | 
|  | regmap_update_bits(adau1372->regmap, ADAU1372_REG_CLK_CTRL, | 
|  | ADAU1372_CLK_CTRL_MCLK_EN | ADAU1372_CLK_CTRL_PLL_EN, 0); | 
|  | } | 
|  | clk_disable_unprepare(adau1372->mclk); | 
|  | regcache_cache_only(adau1372->regmap, true); | 
|  | } | 
|  |  | 
|  | adau1372->enabled = enable; | 
|  | } | 
|  |  | 
|  | static int adau1372_set_bias_level(struct snd_soc_component *component, | 
|  | enum snd_soc_bias_level level) | 
|  | { | 
|  | struct adau1372 *adau1372 = snd_soc_component_get_drvdata(component); | 
|  |  | 
|  | switch (level) { | 
|  | case SND_SOC_BIAS_ON: | 
|  | break; | 
|  | case SND_SOC_BIAS_PREPARE: | 
|  | break; | 
|  | case SND_SOC_BIAS_STANDBY: | 
|  | adau1372_set_power(adau1372, true); | 
|  | break; | 
|  | case SND_SOC_BIAS_OFF: | 
|  | adau1372_set_power(adau1372, false); | 
|  | break; | 
|  | } | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static const struct snd_soc_component_driver adau1372_driver = { | 
|  | .set_bias_level = adau1372_set_bias_level, | 
|  | .controls = adau1372_controls, | 
|  | .num_controls = ARRAY_SIZE(adau1372_controls), | 
|  | .dapm_widgets = adau1372_dapm_widgets, | 
|  | .num_dapm_widgets = ARRAY_SIZE(adau1372_dapm_widgets), | 
|  | .dapm_routes = adau1372_dapm_routes, | 
|  | .num_dapm_routes = ARRAY_SIZE(adau1372_dapm_routes), | 
|  | }; | 
|  |  | 
|  | static const struct snd_soc_dai_ops adau1372_dai_ops = { | 
|  | .set_fmt = adau1372_set_dai_fmt, | 
|  | .set_tdm_slot = adau1372_set_tdm_slot, | 
|  | .set_tristate = adau1372_set_tristate, | 
|  | .hw_params = adau1372_hw_params, | 
|  | .startup = adau1372_startup, | 
|  | }; | 
|  |  | 
|  | #define ADAU1372_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |	SNDRV_PCM_FMTBIT_S32_LE) | 
|  |  | 
|  | static struct snd_soc_dai_driver adau1372_dai_driver = { | 
|  | .name = "adau1372", | 
|  | .playback = { | 
|  | .stream_name = "Playback", | 
|  | .channels_min = 2, | 
|  | .channels_max = 8, | 
|  | .rates = SNDRV_PCM_RATE_KNOT, | 
|  | .formats = ADAU1372_FORMATS, | 
|  | .sig_bits = 24, | 
|  | }, | 
|  | .capture = { | 
|  | .stream_name = "Capture", | 
|  | .channels_min = 2, | 
|  | .channels_max = 8, | 
|  | .rates = SNDRV_PCM_RATE_KNOT, | 
|  | .formats = ADAU1372_FORMATS, | 
|  | .sig_bits = 24, | 
|  | }, | 
|  | .ops = &adau1372_dai_ops, | 
|  | .symmetric_rate = 1, | 
|  | }; | 
|  |  | 
|  | static int adau1372_setup_pll(struct adau1372 *adau1372, unsigned int rate) | 
|  | { | 
|  | u8 regs[5]; | 
|  | unsigned int i; | 
|  | int ret; | 
|  |  | 
|  | ret = adau_calc_pll_cfg(rate, 49152000, regs); | 
|  | if (ret < 0) | 
|  | return ret; | 
|  |  | 
|  | for (i = 0; i < ARRAY_SIZE(regs); i++) | 
|  | regmap_write(adau1372->regmap, ADAU1372_REG_PLL(i), regs[i]); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | int adau1372_probe(struct device *dev, struct regmap *regmap, | 
|  | void (*switch_mode)(struct device *dev)) | 
|  | { | 
|  | struct adau1372 *adau1372; | 
|  | unsigned int clk_ctrl; | 
|  | unsigned long rate; | 
|  | int ret; | 
|  |  | 
|  | if (IS_ERR(regmap)) | 
|  | return PTR_ERR(regmap); | 
|  |  | 
|  | adau1372 = devm_kzalloc(dev, sizeof(*adau1372), GFP_KERNEL); | 
|  | if (!adau1372) | 
|  | return -ENOMEM; | 
|  |  | 
|  | adau1372->clk = devm_clk_get(dev, "mclk"); | 
|  | if (IS_ERR(adau1372->clk)) | 
|  | return PTR_ERR(adau1372->clk); | 
|  |  | 
|  | adau1372->pd_gpio = devm_gpiod_get_optional(dev, "powerdown", GPIOD_OUT_HIGH); | 
|  | if (IS_ERR(adau1372->pd_gpio)) | 
|  | return PTR_ERR(adau1372->pd_gpio); | 
|  |  | 
|  | adau1372->regmap = regmap; | 
|  | adau1372->switch_mode = switch_mode; | 
|  | adau1372->dev = dev; | 
|  | adau1372->rate_constraints.list = adau1372_rates; | 
|  | adau1372->rate_constraints.count = ARRAY_SIZE(adau1372_rates); | 
|  | adau1372->rate_constraints.mask = ADAU1372_RATE_MASK_TDM2; | 
|  |  | 
|  | dev_set_drvdata(dev, adau1372); | 
|  |  | 
|  | /* | 
|  | * The datasheet says that the internal MCLK always needs to run at | 
|  | * 12.288MHz. Automatically choose a valid configuration from the | 
|  | * external clock. | 
|  | */ | 
|  | rate = clk_get_rate(adau1372->clk); | 
|  |  | 
|  | switch (rate) { | 
|  | case 12288000: | 
|  | clk_ctrl = ADAU1372_CLK_CTRL_CC_MDIV; | 
|  | break; | 
|  | case 24576000: | 
|  | clk_ctrl = 0; | 
|  | break; | 
|  | default: | 
|  | clk_ctrl = 0; | 
|  | ret = adau1372_setup_pll(adau1372, rate); | 
|  | if (ret < 0) | 
|  | return ret; | 
|  | adau1372->use_pll = true; | 
|  | break; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * Most of the registers are inaccessible unless the internal clock is | 
|  | * enabled. | 
|  | */ | 
|  | regcache_cache_only(regmap, true); | 
|  |  | 
|  | regmap_update_bits(regmap, ADAU1372_REG_CLK_CTRL, ADAU1372_CLK_CTRL_CC_MDIV, clk_ctrl); | 
|  |  | 
|  | /* | 
|  | * No pinctrl support yet, put the multi-purpose pins in the most | 
|  | * sensible mode for general purpose CODEC operation. | 
|  | */ | 
|  | regmap_write(regmap, ADAU1372_REG_MODE_MP(1), 0x00); /* SDATA OUT */ | 
|  | regmap_write(regmap, ADAU1372_REG_MODE_MP(6), 0x12); /* CLOCKOUT */ | 
|  |  | 
|  | regmap_write(regmap, ADAU1372_REG_OP_STAGE_MUTE, 0x0); | 
|  |  | 
|  | regmap_write(regmap, 0x7, 0x01); /* CLOCK OUT */ | 
|  |  | 
|  | return  devm_snd_soc_register_component(dev, &adau1372_driver, &adau1372_dai_driver, 1); | 
|  | } | 
|  | EXPORT_SYMBOL(adau1372_probe); | 
|  |  | 
|  | static const struct reg_default adau1372_reg_defaults[] = { | 
|  | { ADAU1372_REG_CLK_CTRL,		0x00 }, | 
|  | { ADAU1372_REG_PLL(0),			0x00 }, | 
|  | { ADAU1372_REG_PLL(1),			0x00 }, | 
|  | { ADAU1372_REG_PLL(2),			0x00 }, | 
|  | { ADAU1372_REG_PLL(3),			0x00 }, | 
|  | { ADAU1372_REG_PLL(4),			0x00 }, | 
|  | { ADAU1372_REG_PLL(5),			0x00 }, | 
|  | { ADAU1372_REG_DAC_SOURCE,		0x10 }, | 
|  | { ADAU1372_REG_SOUT_SOURCE_0_1,		0x54 }, | 
|  | { ADAU1372_REG_SOUT_SOURCE_2_3,		0x76 }, | 
|  | { ADAU1372_REG_SOUT_SOURCE_4_5,		0x54 }, | 
|  | { ADAU1372_REG_SOUT_SOURCE_6_7,		0x76 }, | 
|  | { ADAU1372_REG_ADC_SDATA_CH,		0x04 }, | 
|  | { ADAU1372_REG_ASRCO_SOURCE_0_1,	0x10 }, | 
|  | { ADAU1372_REG_ASRCO_SOURCE_2_3,	0x32 }, | 
|  | { ADAU1372_REG_ASRC_MODE,		0x00 }, | 
|  | { ADAU1372_REG_ADC_CTRL0,		0x19 }, | 
|  | { ADAU1372_REG_ADC_CTRL1,		0x19 }, | 
|  | { ADAU1372_REG_ADC_CTRL2,		0x00 }, | 
|  | { ADAU1372_REG_ADC_CTRL3,		0x00 }, | 
|  | { ADAU1372_REG_ADC_VOL(0),		0x00 }, | 
|  | { ADAU1372_REG_ADC_VOL(1),		0x00 }, | 
|  | { ADAU1372_REG_ADC_VOL(2),		0x00 }, | 
|  | { ADAU1372_REG_ADC_VOL(3),		0x00 }, | 
|  | { ADAU1372_REG_PGA_CTRL(0),		0x40 }, | 
|  | { ADAU1372_REG_PGA_CTRL(1),		0x40 }, | 
|  | { ADAU1372_REG_PGA_CTRL(2),		0x40 }, | 
|  | { ADAU1372_REG_PGA_CTRL(3),		0x40 }, | 
|  | { ADAU1372_REG_PGA_BOOST,		0x00 }, | 
|  | { ADAU1372_REG_MICBIAS,			0x00 }, | 
|  | { ADAU1372_REG_DAC_CTRL,		0x18 }, | 
|  | { ADAU1372_REG_DAC_VOL(0),		0x00 }, | 
|  | { ADAU1372_REG_DAC_VOL(1),		0x00 }, | 
|  | { ADAU1372_REG_OP_STAGE_MUTE,		0x0f }, | 
|  | { ADAU1372_REG_SAI0,			0x00 }, | 
|  | { ADAU1372_REG_SAI1,			0x00 }, | 
|  | { ADAU1372_REG_SOUT_CTRL,		0x00 }, | 
|  | { ADAU1372_REG_MODE_MP(0),		0x00 }, | 
|  | { ADAU1372_REG_MODE_MP(1),		0x10 }, | 
|  | { ADAU1372_REG_MODE_MP(4),		0x00 }, | 
|  | { ADAU1372_REG_MODE_MP(5),		0x00 }, | 
|  | { ADAU1372_REG_MODE_MP(6),		0x11 }, | 
|  | { ADAU1372_REG_OP_STAGE_CTRL,		0x0f }, | 
|  | { ADAU1372_REG_DECIM_PWR,		0x00 }, | 
|  | { ADAU1372_REG_INTERP_PWR,		0x00 }, | 
|  | { ADAU1372_REG_BIAS_CTRL0,		0x00 }, | 
|  | { ADAU1372_REG_BIAS_CTRL1,		0x00 }, | 
|  | }; | 
|  |  | 
|  | static bool adau1372_volatile_register(struct device *dev, unsigned int reg) | 
|  | { | 
|  | if (reg == ADAU1372_REG_PLL(5)) | 
|  | return true; | 
|  |  | 
|  | return false; | 
|  | } | 
|  |  | 
|  | const struct regmap_config adau1372_regmap_config = { | 
|  | .val_bits = 8, | 
|  | .reg_bits = 16, | 
|  | .max_register = 0x4d, | 
|  |  | 
|  | .reg_defaults = adau1372_reg_defaults, | 
|  | .num_reg_defaults = ARRAY_SIZE(adau1372_reg_defaults), | 
|  | .volatile_reg = adau1372_volatile_register, | 
|  | .cache_type = REGCACHE_RBTREE, | 
|  | }; | 
|  | EXPORT_SYMBOL_GPL(adau1372_regmap_config); | 
|  |  | 
|  | MODULE_DESCRIPTION("ASoC ADAU1372 CODEC driver"); | 
|  | MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); | 
|  | MODULE_LICENSE("GPL v2"); |