1cc52688aSLars-Peter Clausen /* 2cc52688aSLars-Peter Clausen * ADAV80X Audio Codec driver supporting ADAV801, ADAV803 3cc52688aSLars-Peter Clausen * 4cc52688aSLars-Peter Clausen * Copyright 2011 Analog Devices Inc. 5cc52688aSLars-Peter Clausen * Author: Yi Li <yi.li@analog.com> 6cc52688aSLars-Peter Clausen * Author: Lars-Peter Clausen <lars@metafoo.de> 7cc52688aSLars-Peter Clausen * 8cc52688aSLars-Peter Clausen * Licensed under the GPL-2 or later. 9cc52688aSLars-Peter Clausen */ 10cc52688aSLars-Peter Clausen 11cc52688aSLars-Peter Clausen #include <linux/module.h> 12cc52688aSLars-Peter Clausen #include <linux/kernel.h> 130c2d6964SLars-Peter Clausen #include <linux/regmap.h> 14cc52688aSLars-Peter Clausen #include <linux/slab.h> 150c2d6964SLars-Peter Clausen 16cc52688aSLars-Peter Clausen #include <sound/pcm.h> 17cc52688aSLars-Peter Clausen #include <sound/pcm_params.h> 18cc52688aSLars-Peter Clausen #include <sound/soc.h> 190c2d6964SLars-Peter Clausen #include <sound/tlv.h> 20cc52688aSLars-Peter Clausen 21cc52688aSLars-Peter Clausen #include "adav80x.h" 22cc52688aSLars-Peter Clausen 23cc52688aSLars-Peter Clausen #define ADAV80X_PLAYBACK_CTRL 0x04 24cc52688aSLars-Peter Clausen #define ADAV80X_AUX_IN_CTRL 0x05 25cc52688aSLars-Peter Clausen #define ADAV80X_REC_CTRL 0x06 26cc52688aSLars-Peter Clausen #define ADAV80X_AUX_OUT_CTRL 0x07 27cc52688aSLars-Peter Clausen #define ADAV80X_DPATH_CTRL1 0x62 28cc52688aSLars-Peter Clausen #define ADAV80X_DPATH_CTRL2 0x63 29cc52688aSLars-Peter Clausen #define ADAV80X_DAC_CTRL1 0x64 30cc52688aSLars-Peter Clausen #define ADAV80X_DAC_CTRL2 0x65 31cc52688aSLars-Peter Clausen #define ADAV80X_DAC_CTRL3 0x66 32cc52688aSLars-Peter Clausen #define ADAV80X_DAC_L_VOL 0x68 33cc52688aSLars-Peter Clausen #define ADAV80X_DAC_R_VOL 0x69 34cc52688aSLars-Peter Clausen #define ADAV80X_PGA_L_VOL 0x6c 35cc52688aSLars-Peter Clausen #define ADAV80X_PGA_R_VOL 0x6d 36cc52688aSLars-Peter Clausen #define ADAV80X_ADC_CTRL1 0x6e 37cc52688aSLars-Peter Clausen #define ADAV80X_ADC_CTRL2 0x6f 38cc52688aSLars-Peter Clausen #define ADAV80X_ADC_L_VOL 0x70 39cc52688aSLars-Peter Clausen #define ADAV80X_ADC_R_VOL 0x71 40cc52688aSLars-Peter Clausen #define ADAV80X_PLL_CTRL1 0x74 41cc52688aSLars-Peter Clausen #define ADAV80X_PLL_CTRL2 0x75 42cc52688aSLars-Peter Clausen #define ADAV80X_ICLK_CTRL1 0x76 43cc52688aSLars-Peter Clausen #define ADAV80X_ICLK_CTRL2 0x77 44cc52688aSLars-Peter Clausen #define ADAV80X_PLL_CLK_SRC 0x78 45cc52688aSLars-Peter Clausen #define ADAV80X_PLL_OUTE 0x7a 46cc52688aSLars-Peter Clausen 47cc52688aSLars-Peter Clausen #define ADAV80X_PLL_CLK_SRC_PLL_XIN(pll) 0x00 48cc52688aSLars-Peter Clausen #define ADAV80X_PLL_CLK_SRC_PLL_MCLKI(pll) (0x40 << (pll)) 49cc52688aSLars-Peter Clausen #define ADAV80X_PLL_CLK_SRC_PLL_MASK(pll) (0x40 << (pll)) 50cc52688aSLars-Peter Clausen 51cc52688aSLars-Peter Clausen #define ADAV80X_ICLK_CTRL1_DAC_SRC(src) ((src) << 5) 52cc52688aSLars-Peter Clausen #define ADAV80X_ICLK_CTRL1_ADC_SRC(src) ((src) << 2) 53cc52688aSLars-Peter Clausen #define ADAV80X_ICLK_CTRL1_ICLK2_SRC(src) (src) 54cc52688aSLars-Peter Clausen #define ADAV80X_ICLK_CTRL2_ICLK1_SRC(src) ((src) << 3) 55cc52688aSLars-Peter Clausen 56cc52688aSLars-Peter Clausen #define ADAV80X_PLL_CTRL1_PLLDIV 0x10 57cc52688aSLars-Peter Clausen #define ADAV80X_PLL_CTRL1_PLLPD(pll) (0x04 << (pll)) 58cc52688aSLars-Peter Clausen #define ADAV80X_PLL_CTRL1_XTLPD 0x02 59cc52688aSLars-Peter Clausen 60cc52688aSLars-Peter Clausen #define ADAV80X_PLL_CTRL2_FIELD(pll, x) ((x) << ((pll) * 4)) 61cc52688aSLars-Peter Clausen 62cc52688aSLars-Peter Clausen #define ADAV80X_PLL_CTRL2_FS_48(pll) ADAV80X_PLL_CTRL2_FIELD((pll), 0x00) 63cc52688aSLars-Peter Clausen #define ADAV80X_PLL_CTRL2_FS_32(pll) ADAV80X_PLL_CTRL2_FIELD((pll), 0x08) 64cc52688aSLars-Peter Clausen #define ADAV80X_PLL_CTRL2_FS_44(pll) ADAV80X_PLL_CTRL2_FIELD((pll), 0x0c) 65cc52688aSLars-Peter Clausen 66cc52688aSLars-Peter Clausen #define ADAV80X_PLL_CTRL2_SEL(pll) ADAV80X_PLL_CTRL2_FIELD((pll), 0x02) 67cc52688aSLars-Peter Clausen #define ADAV80X_PLL_CTRL2_DOUB(pll) ADAV80X_PLL_CTRL2_FIELD((pll), 0x01) 68cc52688aSLars-Peter Clausen #define ADAV80X_PLL_CTRL2_PLL_MASK(pll) ADAV80X_PLL_CTRL2_FIELD((pll), 0x0f) 69cc52688aSLars-Peter Clausen 70cc52688aSLars-Peter Clausen #define ADAV80X_ADC_CTRL1_MODULATOR_MASK 0x80 71cc52688aSLars-Peter Clausen #define ADAV80X_ADC_CTRL1_MODULATOR_128FS 0x00 72cc52688aSLars-Peter Clausen #define ADAV80X_ADC_CTRL1_MODULATOR_64FS 0x80 73cc52688aSLars-Peter Clausen 74cc52688aSLars-Peter Clausen #define ADAV80X_DAC_CTRL1_PD 0x80 75cc52688aSLars-Peter Clausen 76cc52688aSLars-Peter Clausen #define ADAV80X_DAC_CTRL2_DIV1 0x00 77cc52688aSLars-Peter Clausen #define ADAV80X_DAC_CTRL2_DIV1_5 0x10 78cc52688aSLars-Peter Clausen #define ADAV80X_DAC_CTRL2_DIV2 0x20 79cc52688aSLars-Peter Clausen #define ADAV80X_DAC_CTRL2_DIV3 0x30 80cc52688aSLars-Peter Clausen #define ADAV80X_DAC_CTRL2_DIV_MASK 0x30 81cc52688aSLars-Peter Clausen 82cc52688aSLars-Peter Clausen #define ADAV80X_DAC_CTRL2_INTERPOL_256FS 0x00 83cc52688aSLars-Peter Clausen #define ADAV80X_DAC_CTRL2_INTERPOL_128FS 0x40 84cc52688aSLars-Peter Clausen #define ADAV80X_DAC_CTRL2_INTERPOL_64FS 0x80 85cc52688aSLars-Peter Clausen #define ADAV80X_DAC_CTRL2_INTERPOL_MASK 0xc0 86cc52688aSLars-Peter Clausen 87cc52688aSLars-Peter Clausen #define ADAV80X_DAC_CTRL2_DEEMPH_NONE 0x00 88cc52688aSLars-Peter Clausen #define ADAV80X_DAC_CTRL2_DEEMPH_44 0x01 89cc52688aSLars-Peter Clausen #define ADAV80X_DAC_CTRL2_DEEMPH_32 0x02 90cc52688aSLars-Peter Clausen #define ADAV80X_DAC_CTRL2_DEEMPH_48 0x03 91cc52688aSLars-Peter Clausen #define ADAV80X_DAC_CTRL2_DEEMPH_MASK 0x01 92cc52688aSLars-Peter Clausen 93cc52688aSLars-Peter Clausen #define ADAV80X_CAPTURE_MODE_MASTER 0x20 94cc52688aSLars-Peter Clausen #define ADAV80X_CAPTURE_WORD_LEN24 0x00 95cc52688aSLars-Peter Clausen #define ADAV80X_CAPTURE_WORD_LEN20 0x04 96cc52688aSLars-Peter Clausen #define ADAV80X_CAPTRUE_WORD_LEN18 0x08 97cc52688aSLars-Peter Clausen #define ADAV80X_CAPTURE_WORD_LEN16 0x0c 98cc52688aSLars-Peter Clausen #define ADAV80X_CAPTURE_WORD_LEN_MASK 0x0c 99cc52688aSLars-Peter Clausen 100cc52688aSLars-Peter Clausen #define ADAV80X_CAPTURE_MODE_LEFT_J 0x00 101cc52688aSLars-Peter Clausen #define ADAV80X_CAPTURE_MODE_I2S 0x01 102cc52688aSLars-Peter Clausen #define ADAV80X_CAPTURE_MODE_RIGHT_J 0x03 103cc52688aSLars-Peter Clausen #define ADAV80X_CAPTURE_MODE_MASK 0x03 104cc52688aSLars-Peter Clausen 105cc52688aSLars-Peter Clausen #define ADAV80X_PLAYBACK_MODE_MASTER 0x10 106cc52688aSLars-Peter Clausen #define ADAV80X_PLAYBACK_MODE_LEFT_J 0x00 107cc52688aSLars-Peter Clausen #define ADAV80X_PLAYBACK_MODE_I2S 0x01 108cc52688aSLars-Peter Clausen #define ADAV80X_PLAYBACK_MODE_RIGHT_J_24 0x04 109cc52688aSLars-Peter Clausen #define ADAV80X_PLAYBACK_MODE_RIGHT_J_20 0x05 110cc52688aSLars-Peter Clausen #define ADAV80X_PLAYBACK_MODE_RIGHT_J_18 0x06 111cc52688aSLars-Peter Clausen #define ADAV80X_PLAYBACK_MODE_RIGHT_J_16 0x07 112cc52688aSLars-Peter Clausen #define ADAV80X_PLAYBACK_MODE_MASK 0x07 113cc52688aSLars-Peter Clausen 114cc52688aSLars-Peter Clausen #define ADAV80X_PLL_OUTE_SYSCLKPD(x) BIT(2 - (x)) 115cc52688aSLars-Peter Clausen 1162560b3d1SLars-Peter Clausen static struct reg_default adav80x_reg_defaults[] = { 1172560b3d1SLars-Peter Clausen { ADAV80X_PLAYBACK_CTRL, 0x01 }, 1182560b3d1SLars-Peter Clausen { ADAV80X_AUX_IN_CTRL, 0x01 }, 1192560b3d1SLars-Peter Clausen { ADAV80X_REC_CTRL, 0x02 }, 1202560b3d1SLars-Peter Clausen { ADAV80X_AUX_OUT_CTRL, 0x01 }, 1212560b3d1SLars-Peter Clausen { ADAV80X_DPATH_CTRL1, 0xc0 }, 1222560b3d1SLars-Peter Clausen { ADAV80X_DPATH_CTRL2, 0x11 }, 1232560b3d1SLars-Peter Clausen { ADAV80X_DAC_CTRL1, 0x00 }, 1242560b3d1SLars-Peter Clausen { ADAV80X_DAC_CTRL2, 0x00 }, 1252560b3d1SLars-Peter Clausen { ADAV80X_DAC_CTRL3, 0x00 }, 1262560b3d1SLars-Peter Clausen { ADAV80X_DAC_L_VOL, 0xff }, 1272560b3d1SLars-Peter Clausen { ADAV80X_DAC_R_VOL, 0xff }, 1282560b3d1SLars-Peter Clausen { ADAV80X_PGA_L_VOL, 0x00 }, 1292560b3d1SLars-Peter Clausen { ADAV80X_PGA_R_VOL, 0x00 }, 1302560b3d1SLars-Peter Clausen { ADAV80X_ADC_CTRL1, 0x00 }, 1312560b3d1SLars-Peter Clausen { ADAV80X_ADC_CTRL2, 0x00 }, 1322560b3d1SLars-Peter Clausen { ADAV80X_ADC_L_VOL, 0xff }, 1332560b3d1SLars-Peter Clausen { ADAV80X_ADC_R_VOL, 0xff }, 1342560b3d1SLars-Peter Clausen { ADAV80X_PLL_CTRL1, 0x00 }, 1352560b3d1SLars-Peter Clausen { ADAV80X_PLL_CTRL2, 0x00 }, 1362560b3d1SLars-Peter Clausen { ADAV80X_ICLK_CTRL1, 0x00 }, 1372560b3d1SLars-Peter Clausen { ADAV80X_ICLK_CTRL2, 0x00 }, 1382560b3d1SLars-Peter Clausen { ADAV80X_PLL_CLK_SRC, 0x00 }, 1392560b3d1SLars-Peter Clausen { ADAV80X_PLL_OUTE, 0x00 }, 140cc52688aSLars-Peter Clausen }; 141cc52688aSLars-Peter Clausen 142cc52688aSLars-Peter Clausen struct adav80x { 1432560b3d1SLars-Peter Clausen struct regmap *regmap; 144cc52688aSLars-Peter Clausen 145cc52688aSLars-Peter Clausen enum adav80x_clk_src clk_src; 146cc52688aSLars-Peter Clausen unsigned int sysclk; 147cc52688aSLars-Peter Clausen enum adav80x_pll_src pll_src; 148cc52688aSLars-Peter Clausen 149cc52688aSLars-Peter Clausen unsigned int dai_fmt[2]; 150cc52688aSLars-Peter Clausen unsigned int rate; 151cc52688aSLars-Peter Clausen bool deemph; 152cc52688aSLars-Peter Clausen bool sysclk_pd[3]; 153cc52688aSLars-Peter Clausen }; 154cc52688aSLars-Peter Clausen 155cc52688aSLars-Peter Clausen static const char *adav80x_mux_text[] = { 156cc52688aSLars-Peter Clausen "ADC", 157cc52688aSLars-Peter Clausen "Playback", 158cc52688aSLars-Peter Clausen "Aux Playback", 159cc52688aSLars-Peter Clausen }; 160cc52688aSLars-Peter Clausen 161cc52688aSLars-Peter Clausen static const unsigned int adav80x_mux_values[] = { 162cc52688aSLars-Peter Clausen 0, 2, 3, 163cc52688aSLars-Peter Clausen }; 164cc52688aSLars-Peter Clausen 165cc52688aSLars-Peter Clausen #define ADAV80X_MUX_ENUM_DECL(name, reg, shift) \ 166cc52688aSLars-Peter Clausen SOC_VALUE_ENUM_DOUBLE_DECL(name, reg, shift, 7, \ 167cc52688aSLars-Peter Clausen ARRAY_SIZE(adav80x_mux_text), adav80x_mux_text, \ 168cc52688aSLars-Peter Clausen adav80x_mux_values) 169cc52688aSLars-Peter Clausen 170cc52688aSLars-Peter Clausen static ADAV80X_MUX_ENUM_DECL(adav80x_aux_capture_enum, ADAV80X_DPATH_CTRL1, 0); 171cc52688aSLars-Peter Clausen static ADAV80X_MUX_ENUM_DECL(adav80x_capture_enum, ADAV80X_DPATH_CTRL1, 3); 172cc52688aSLars-Peter Clausen static ADAV80X_MUX_ENUM_DECL(adav80x_dac_enum, ADAV80X_DPATH_CTRL2, 3); 173cc52688aSLars-Peter Clausen 174cc52688aSLars-Peter Clausen static const struct snd_kcontrol_new adav80x_aux_capture_mux_ctrl = 17548fa3636SLars-Peter Clausen SOC_DAPM_ENUM("Route", adav80x_aux_capture_enum); 176cc52688aSLars-Peter Clausen static const struct snd_kcontrol_new adav80x_capture_mux_ctrl = 17748fa3636SLars-Peter Clausen SOC_DAPM_ENUM("Route", adav80x_capture_enum); 178cc52688aSLars-Peter Clausen static const struct snd_kcontrol_new adav80x_dac_mux_ctrl = 17948fa3636SLars-Peter Clausen SOC_DAPM_ENUM("Route", adav80x_dac_enum); 180cc52688aSLars-Peter Clausen 181cc52688aSLars-Peter Clausen #define ADAV80X_MUX(name, ctrl) \ 18248fa3636SLars-Peter Clausen SND_SOC_DAPM_MUX(name, SND_SOC_NOPM, 0, 0, ctrl) 183cc52688aSLars-Peter Clausen 184cc52688aSLars-Peter Clausen static const struct snd_soc_dapm_widget adav80x_dapm_widgets[] = { 185cc52688aSLars-Peter Clausen SND_SOC_DAPM_DAC("DAC", NULL, ADAV80X_DAC_CTRL1, 7, 1), 186cc52688aSLars-Peter Clausen SND_SOC_DAPM_ADC("ADC", NULL, ADAV80X_ADC_CTRL1, 5, 1), 187cc52688aSLars-Peter Clausen 188cc52688aSLars-Peter Clausen SND_SOC_DAPM_PGA("Right PGA", ADAV80X_ADC_CTRL1, 0, 1, NULL, 0), 189cc52688aSLars-Peter Clausen SND_SOC_DAPM_PGA("Left PGA", ADAV80X_ADC_CTRL1, 1, 1, NULL, 0), 190cc52688aSLars-Peter Clausen 191cc52688aSLars-Peter Clausen SND_SOC_DAPM_AIF_OUT("AIFOUT", "HiFi Capture", 0, SND_SOC_NOPM, 0, 0), 192cc52688aSLars-Peter Clausen SND_SOC_DAPM_AIF_IN("AIFIN", "HiFi Playback", 0, SND_SOC_NOPM, 0, 0), 193cc52688aSLars-Peter Clausen 194cc52688aSLars-Peter Clausen SND_SOC_DAPM_AIF_OUT("AIFAUXOUT", "Aux Capture", 0, SND_SOC_NOPM, 0, 0), 195cc52688aSLars-Peter Clausen SND_SOC_DAPM_AIF_IN("AIFAUXIN", "Aux Playback", 0, SND_SOC_NOPM, 0, 0), 196cc52688aSLars-Peter Clausen 197cc52688aSLars-Peter Clausen ADAV80X_MUX("Aux Capture Select", &adav80x_aux_capture_mux_ctrl), 198cc52688aSLars-Peter Clausen ADAV80X_MUX("Capture Select", &adav80x_capture_mux_ctrl), 199cc52688aSLars-Peter Clausen ADAV80X_MUX("DAC Select", &adav80x_dac_mux_ctrl), 200cc52688aSLars-Peter Clausen 201cc52688aSLars-Peter Clausen SND_SOC_DAPM_INPUT("VINR"), 202cc52688aSLars-Peter Clausen SND_SOC_DAPM_INPUT("VINL"), 203cc52688aSLars-Peter Clausen SND_SOC_DAPM_OUTPUT("VOUTR"), 204cc52688aSLars-Peter Clausen SND_SOC_DAPM_OUTPUT("VOUTL"), 205cc52688aSLars-Peter Clausen 206cc52688aSLars-Peter Clausen SND_SOC_DAPM_SUPPLY("SYSCLK", SND_SOC_NOPM, 0, 0, NULL, 0), 207cc52688aSLars-Peter Clausen SND_SOC_DAPM_SUPPLY("PLL1", ADAV80X_PLL_CTRL1, 2, 1, NULL, 0), 208cc52688aSLars-Peter Clausen SND_SOC_DAPM_SUPPLY("PLL2", ADAV80X_PLL_CTRL1, 3, 1, NULL, 0), 209cc52688aSLars-Peter Clausen SND_SOC_DAPM_SUPPLY("OSC", ADAV80X_PLL_CTRL1, 1, 1, NULL, 0), 210cc52688aSLars-Peter Clausen }; 211cc52688aSLars-Peter Clausen 212cc52688aSLars-Peter Clausen static int adav80x_dapm_sysclk_check(struct snd_soc_dapm_widget *source, 213cc52688aSLars-Peter Clausen struct snd_soc_dapm_widget *sink) 214cc52688aSLars-Peter Clausen { 2156fdaac1cSLars-Peter Clausen struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm); 216cc52688aSLars-Peter Clausen struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); 217cc52688aSLars-Peter Clausen const char *clk; 218cc52688aSLars-Peter Clausen 219cc52688aSLars-Peter Clausen switch (adav80x->clk_src) { 220cc52688aSLars-Peter Clausen case ADAV80X_CLK_PLL1: 221cc52688aSLars-Peter Clausen clk = "PLL1"; 222cc52688aSLars-Peter Clausen break; 223cc52688aSLars-Peter Clausen case ADAV80X_CLK_PLL2: 224cc52688aSLars-Peter Clausen clk = "PLL2"; 225cc52688aSLars-Peter Clausen break; 226cc52688aSLars-Peter Clausen case ADAV80X_CLK_XTAL: 227cc52688aSLars-Peter Clausen clk = "OSC"; 228cc52688aSLars-Peter Clausen break; 229cc52688aSLars-Peter Clausen default: 230cc52688aSLars-Peter Clausen return 0; 231cc52688aSLars-Peter Clausen } 232cc52688aSLars-Peter Clausen 233cc52688aSLars-Peter Clausen return strcmp(source->name, clk) == 0; 234cc52688aSLars-Peter Clausen } 235cc52688aSLars-Peter Clausen 236cc52688aSLars-Peter Clausen static int adav80x_dapm_pll_check(struct snd_soc_dapm_widget *source, 237cc52688aSLars-Peter Clausen struct snd_soc_dapm_widget *sink) 238cc52688aSLars-Peter Clausen { 2396fdaac1cSLars-Peter Clausen struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm); 240cc52688aSLars-Peter Clausen struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); 241cc52688aSLars-Peter Clausen 242cc52688aSLars-Peter Clausen return adav80x->pll_src == ADAV80X_PLL_SRC_XTAL; 243cc52688aSLars-Peter Clausen } 244cc52688aSLars-Peter Clausen 245cc52688aSLars-Peter Clausen 246cc52688aSLars-Peter Clausen static const struct snd_soc_dapm_route adav80x_dapm_routes[] = { 247cc52688aSLars-Peter Clausen { "DAC Select", "ADC", "ADC" }, 248cc52688aSLars-Peter Clausen { "DAC Select", "Playback", "AIFIN" }, 249cc52688aSLars-Peter Clausen { "DAC Select", "Aux Playback", "AIFAUXIN" }, 250cc52688aSLars-Peter Clausen { "DAC", NULL, "DAC Select" }, 251cc52688aSLars-Peter Clausen 252cc52688aSLars-Peter Clausen { "Capture Select", "ADC", "ADC" }, 253cc52688aSLars-Peter Clausen { "Capture Select", "Playback", "AIFIN" }, 254cc52688aSLars-Peter Clausen { "Capture Select", "Aux Playback", "AIFAUXIN" }, 255cc52688aSLars-Peter Clausen { "AIFOUT", NULL, "Capture Select" }, 256cc52688aSLars-Peter Clausen 257cc52688aSLars-Peter Clausen { "Aux Capture Select", "ADC", "ADC" }, 258cc52688aSLars-Peter Clausen { "Aux Capture Select", "Playback", "AIFIN" }, 259cc52688aSLars-Peter Clausen { "Aux Capture Select", "Aux Playback", "AIFAUXIN" }, 260cc52688aSLars-Peter Clausen { "AIFAUXOUT", NULL, "Aux Capture Select" }, 261cc52688aSLars-Peter Clausen 262cc52688aSLars-Peter Clausen { "VOUTR", NULL, "DAC" }, 263cc52688aSLars-Peter Clausen { "VOUTL", NULL, "DAC" }, 264cc52688aSLars-Peter Clausen 265cc52688aSLars-Peter Clausen { "Left PGA", NULL, "VINL" }, 266cc52688aSLars-Peter Clausen { "Right PGA", NULL, "VINR" }, 267cc52688aSLars-Peter Clausen { "ADC", NULL, "Left PGA" }, 268cc52688aSLars-Peter Clausen { "ADC", NULL, "Right PGA" }, 269cc52688aSLars-Peter Clausen 270cc52688aSLars-Peter Clausen { "SYSCLK", NULL, "PLL1", adav80x_dapm_sysclk_check }, 271cc52688aSLars-Peter Clausen { "SYSCLK", NULL, "PLL2", adav80x_dapm_sysclk_check }, 272cc52688aSLars-Peter Clausen { "SYSCLK", NULL, "OSC", adav80x_dapm_sysclk_check }, 273cc52688aSLars-Peter Clausen { "PLL1", NULL, "OSC", adav80x_dapm_pll_check }, 274cc52688aSLars-Peter Clausen { "PLL2", NULL, "OSC", adav80x_dapm_pll_check }, 275cc52688aSLars-Peter Clausen 276cc52688aSLars-Peter Clausen { "ADC", NULL, "SYSCLK" }, 277cc52688aSLars-Peter Clausen { "DAC", NULL, "SYSCLK" }, 278cc52688aSLars-Peter Clausen { "AIFOUT", NULL, "SYSCLK" }, 279cc52688aSLars-Peter Clausen { "AIFAUXOUT", NULL, "SYSCLK" }, 280cc52688aSLars-Peter Clausen { "AIFIN", NULL, "SYSCLK" }, 281cc52688aSLars-Peter Clausen { "AIFAUXIN", NULL, "SYSCLK" }, 282cc52688aSLars-Peter Clausen }; 283cc52688aSLars-Peter Clausen 284cc52688aSLars-Peter Clausen static int adav80x_set_deemph(struct snd_soc_codec *codec) 285cc52688aSLars-Peter Clausen { 286cc52688aSLars-Peter Clausen struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); 287cc52688aSLars-Peter Clausen unsigned int val; 288cc52688aSLars-Peter Clausen 289cc52688aSLars-Peter Clausen if (adav80x->deemph) { 290cc52688aSLars-Peter Clausen switch (adav80x->rate) { 291cc52688aSLars-Peter Clausen case 32000: 292cc52688aSLars-Peter Clausen val = ADAV80X_DAC_CTRL2_DEEMPH_32; 293cc52688aSLars-Peter Clausen break; 294cc52688aSLars-Peter Clausen case 44100: 295cc52688aSLars-Peter Clausen val = ADAV80X_DAC_CTRL2_DEEMPH_44; 296cc52688aSLars-Peter Clausen break; 297cc52688aSLars-Peter Clausen case 48000: 298cc52688aSLars-Peter Clausen case 64000: 299cc52688aSLars-Peter Clausen case 88200: 300cc52688aSLars-Peter Clausen case 96000: 301cc52688aSLars-Peter Clausen val = ADAV80X_DAC_CTRL2_DEEMPH_48; 302cc52688aSLars-Peter Clausen break; 303cc52688aSLars-Peter Clausen default: 304cc52688aSLars-Peter Clausen val = ADAV80X_DAC_CTRL2_DEEMPH_NONE; 305cc52688aSLars-Peter Clausen break; 306cc52688aSLars-Peter Clausen } 307cc52688aSLars-Peter Clausen } else { 308cc52688aSLars-Peter Clausen val = ADAV80X_DAC_CTRL2_DEEMPH_NONE; 309cc52688aSLars-Peter Clausen } 310cc52688aSLars-Peter Clausen 3112560b3d1SLars-Peter Clausen return regmap_update_bits(adav80x->regmap, ADAV80X_DAC_CTRL2, 312cc52688aSLars-Peter Clausen ADAV80X_DAC_CTRL2_DEEMPH_MASK, val); 313cc52688aSLars-Peter Clausen } 314cc52688aSLars-Peter Clausen 315cc52688aSLars-Peter Clausen static int adav80x_put_deemph(struct snd_kcontrol *kcontrol, 316cc52688aSLars-Peter Clausen struct snd_ctl_elem_value *ucontrol) 317cc52688aSLars-Peter Clausen { 318ea53bf77SLars-Peter Clausen struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); 319cc52688aSLars-Peter Clausen struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); 3202bf4c1d4STakashi Iwai unsigned int deemph = ucontrol->value.integer.value[0]; 321cc52688aSLars-Peter Clausen 322cc52688aSLars-Peter Clausen if (deemph > 1) 323cc52688aSLars-Peter Clausen return -EINVAL; 324cc52688aSLars-Peter Clausen 325cc52688aSLars-Peter Clausen adav80x->deemph = deemph; 326cc52688aSLars-Peter Clausen 327cc52688aSLars-Peter Clausen return adav80x_set_deemph(codec); 328cc52688aSLars-Peter Clausen } 329cc52688aSLars-Peter Clausen 330cc52688aSLars-Peter Clausen static int adav80x_get_deemph(struct snd_kcontrol *kcontrol, 331cc52688aSLars-Peter Clausen struct snd_ctl_elem_value *ucontrol) 332cc52688aSLars-Peter Clausen { 333ea53bf77SLars-Peter Clausen struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); 334cc52688aSLars-Peter Clausen struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); 335cc52688aSLars-Peter Clausen 3362bf4c1d4STakashi Iwai ucontrol->value.integer.value[0] = adav80x->deemph; 337cc52688aSLars-Peter Clausen return 0; 338cc52688aSLars-Peter Clausen }; 339cc52688aSLars-Peter Clausen 340cc52688aSLars-Peter Clausen static const DECLARE_TLV_DB_SCALE(adav80x_inpga_tlv, 0, 50, 0); 341cc52688aSLars-Peter Clausen static const DECLARE_TLV_DB_MINMAX(adav80x_digital_tlv, -9563, 0); 342cc52688aSLars-Peter Clausen 343cc52688aSLars-Peter Clausen static const struct snd_kcontrol_new adav80x_controls[] = { 344cc52688aSLars-Peter Clausen SOC_DOUBLE_R_TLV("Master Playback Volume", ADAV80X_DAC_L_VOL, 345cc52688aSLars-Peter Clausen ADAV80X_DAC_R_VOL, 0, 0xff, 0, adav80x_digital_tlv), 346cc52688aSLars-Peter Clausen SOC_DOUBLE_R_TLV("Master Capture Volume", ADAV80X_ADC_L_VOL, 347cc52688aSLars-Peter Clausen ADAV80X_ADC_R_VOL, 0, 0xff, 0, adav80x_digital_tlv), 348cc52688aSLars-Peter Clausen 349cc52688aSLars-Peter Clausen SOC_DOUBLE_R_TLV("PGA Capture Volume", ADAV80X_PGA_L_VOL, 350cc52688aSLars-Peter Clausen ADAV80X_PGA_R_VOL, 0, 0x30, 0, adav80x_inpga_tlv), 351cc52688aSLars-Peter Clausen 352cc52688aSLars-Peter Clausen SOC_DOUBLE("Master Playback Switch", ADAV80X_DAC_CTRL1, 0, 1, 1, 0), 353cc52688aSLars-Peter Clausen SOC_DOUBLE("Master Capture Switch", ADAV80X_ADC_CTRL1, 2, 3, 1, 1), 354cc52688aSLars-Peter Clausen 355cc52688aSLars-Peter Clausen SOC_SINGLE("ADC High Pass Filter Switch", ADAV80X_ADC_CTRL1, 6, 1, 0), 356cc52688aSLars-Peter Clausen 357cc52688aSLars-Peter Clausen SOC_SINGLE_BOOL_EXT("Playback De-emphasis Switch", 0, 358cc52688aSLars-Peter Clausen adav80x_get_deemph, adav80x_put_deemph), 359cc52688aSLars-Peter Clausen }; 360cc52688aSLars-Peter Clausen 361cc52688aSLars-Peter Clausen static unsigned int adav80x_port_ctrl_regs[2][2] = { 362cc52688aSLars-Peter Clausen { ADAV80X_REC_CTRL, ADAV80X_PLAYBACK_CTRL, }, 363cc52688aSLars-Peter Clausen { ADAV80X_AUX_OUT_CTRL, ADAV80X_AUX_IN_CTRL }, 364cc52688aSLars-Peter Clausen }; 365cc52688aSLars-Peter Clausen 366cc52688aSLars-Peter Clausen static int adav80x_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) 367cc52688aSLars-Peter Clausen { 368cc52688aSLars-Peter Clausen struct snd_soc_codec *codec = dai->codec; 369cc52688aSLars-Peter Clausen struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); 370cc52688aSLars-Peter Clausen unsigned int capture = 0x00; 371cc52688aSLars-Peter Clausen unsigned int playback = 0x00; 372cc52688aSLars-Peter Clausen 373cc52688aSLars-Peter Clausen switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { 374cc52688aSLars-Peter Clausen case SND_SOC_DAIFMT_CBM_CFM: 375cc52688aSLars-Peter Clausen capture |= ADAV80X_CAPTURE_MODE_MASTER; 376cc52688aSLars-Peter Clausen playback |= ADAV80X_PLAYBACK_MODE_MASTER; 377cc52688aSLars-Peter Clausen case SND_SOC_DAIFMT_CBS_CFS: 378cc52688aSLars-Peter Clausen break; 379cc52688aSLars-Peter Clausen default: 380cc52688aSLars-Peter Clausen return -EINVAL; 381cc52688aSLars-Peter Clausen } 382cc52688aSLars-Peter Clausen 383cc52688aSLars-Peter Clausen switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 384cc52688aSLars-Peter Clausen case SND_SOC_DAIFMT_I2S: 385cc52688aSLars-Peter Clausen capture |= ADAV80X_CAPTURE_MODE_I2S; 386cc52688aSLars-Peter Clausen playback |= ADAV80X_PLAYBACK_MODE_I2S; 387cc52688aSLars-Peter Clausen break; 388cc52688aSLars-Peter Clausen case SND_SOC_DAIFMT_LEFT_J: 389cc52688aSLars-Peter Clausen capture |= ADAV80X_CAPTURE_MODE_LEFT_J; 390cc52688aSLars-Peter Clausen playback |= ADAV80X_PLAYBACK_MODE_LEFT_J; 391cc52688aSLars-Peter Clausen break; 392cc52688aSLars-Peter Clausen case SND_SOC_DAIFMT_RIGHT_J: 393cc52688aSLars-Peter Clausen capture |= ADAV80X_CAPTURE_MODE_RIGHT_J; 394cc52688aSLars-Peter Clausen playback |= ADAV80X_PLAYBACK_MODE_RIGHT_J_24; 395cc52688aSLars-Peter Clausen break; 396cc52688aSLars-Peter Clausen default: 397cc52688aSLars-Peter Clausen return -EINVAL; 398cc52688aSLars-Peter Clausen } 399cc52688aSLars-Peter Clausen 400cc52688aSLars-Peter Clausen switch (fmt & SND_SOC_DAIFMT_INV_MASK) { 401cc52688aSLars-Peter Clausen case SND_SOC_DAIFMT_NB_NF: 402cc52688aSLars-Peter Clausen break; 403cc52688aSLars-Peter Clausen default: 404cc52688aSLars-Peter Clausen return -EINVAL; 405cc52688aSLars-Peter Clausen } 406cc52688aSLars-Peter Clausen 4072560b3d1SLars-Peter Clausen regmap_update_bits(adav80x->regmap, adav80x_port_ctrl_regs[dai->id][0], 408cc52688aSLars-Peter Clausen ADAV80X_CAPTURE_MODE_MASK | ADAV80X_CAPTURE_MODE_MASTER, 409cc52688aSLars-Peter Clausen capture); 4102560b3d1SLars-Peter Clausen regmap_write(adav80x->regmap, adav80x_port_ctrl_regs[dai->id][1], 4112560b3d1SLars-Peter Clausen playback); 412cc52688aSLars-Peter Clausen 413cc52688aSLars-Peter Clausen adav80x->dai_fmt[dai->id] = fmt & SND_SOC_DAIFMT_FORMAT_MASK; 414cc52688aSLars-Peter Clausen 415cc52688aSLars-Peter Clausen return 0; 416cc52688aSLars-Peter Clausen } 417cc52688aSLars-Peter Clausen 418cc52688aSLars-Peter Clausen static int adav80x_set_adc_clock(struct snd_soc_codec *codec, 419cc52688aSLars-Peter Clausen unsigned int sample_rate) 420cc52688aSLars-Peter Clausen { 4212560b3d1SLars-Peter Clausen struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); 422cc52688aSLars-Peter Clausen unsigned int val; 423cc52688aSLars-Peter Clausen 424cc52688aSLars-Peter Clausen if (sample_rate <= 48000) 425cc52688aSLars-Peter Clausen val = ADAV80X_ADC_CTRL1_MODULATOR_128FS; 426cc52688aSLars-Peter Clausen else 427cc52688aSLars-Peter Clausen val = ADAV80X_ADC_CTRL1_MODULATOR_64FS; 428cc52688aSLars-Peter Clausen 4292560b3d1SLars-Peter Clausen regmap_update_bits(adav80x->regmap, ADAV80X_ADC_CTRL1, 430cc52688aSLars-Peter Clausen ADAV80X_ADC_CTRL1_MODULATOR_MASK, val); 431cc52688aSLars-Peter Clausen 432cc52688aSLars-Peter Clausen return 0; 433cc52688aSLars-Peter Clausen } 434cc52688aSLars-Peter Clausen 435cc52688aSLars-Peter Clausen static int adav80x_set_dac_clock(struct snd_soc_codec *codec, 436cc52688aSLars-Peter Clausen unsigned int sample_rate) 437cc52688aSLars-Peter Clausen { 4382560b3d1SLars-Peter Clausen struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); 439cc52688aSLars-Peter Clausen unsigned int val; 440cc52688aSLars-Peter Clausen 441cc52688aSLars-Peter Clausen if (sample_rate <= 48000) 442cc52688aSLars-Peter Clausen val = ADAV80X_DAC_CTRL2_DIV1 | ADAV80X_DAC_CTRL2_INTERPOL_256FS; 443cc52688aSLars-Peter Clausen else 444cc52688aSLars-Peter Clausen val = ADAV80X_DAC_CTRL2_DIV2 | ADAV80X_DAC_CTRL2_INTERPOL_128FS; 445cc52688aSLars-Peter Clausen 4462560b3d1SLars-Peter Clausen regmap_update_bits(adav80x->regmap, ADAV80X_DAC_CTRL2, 447cc52688aSLars-Peter Clausen ADAV80X_DAC_CTRL2_DIV_MASK | ADAV80X_DAC_CTRL2_INTERPOL_MASK, 448cc52688aSLars-Peter Clausen val); 449cc52688aSLars-Peter Clausen 450cc52688aSLars-Peter Clausen return 0; 451cc52688aSLars-Peter Clausen } 452cc52688aSLars-Peter Clausen 453cc52688aSLars-Peter Clausen static int adav80x_set_capture_pcm_format(struct snd_soc_codec *codec, 454cf7d8b27SMark Brown struct snd_soc_dai *dai, struct snd_pcm_hw_params *params) 455cc52688aSLars-Peter Clausen { 4562560b3d1SLars-Peter Clausen struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); 457cc52688aSLars-Peter Clausen unsigned int val; 458cc52688aSLars-Peter Clausen 459cf7d8b27SMark Brown switch (params_width(params)) { 460cf7d8b27SMark Brown case 16: 461cc52688aSLars-Peter Clausen val = ADAV80X_CAPTURE_WORD_LEN16; 462cc52688aSLars-Peter Clausen break; 463cf7d8b27SMark Brown case 18: 464cc52688aSLars-Peter Clausen val = ADAV80X_CAPTRUE_WORD_LEN18; 465cc52688aSLars-Peter Clausen break; 466cf7d8b27SMark Brown case 20: 467cc52688aSLars-Peter Clausen val = ADAV80X_CAPTURE_WORD_LEN20; 468cc52688aSLars-Peter Clausen break; 469cf7d8b27SMark Brown case 24: 470cc52688aSLars-Peter Clausen val = ADAV80X_CAPTURE_WORD_LEN24; 471cc52688aSLars-Peter Clausen break; 472cc52688aSLars-Peter Clausen default: 473ca1004baSMark Brown return -EINVAL; 474cc52688aSLars-Peter Clausen } 475cc52688aSLars-Peter Clausen 4762560b3d1SLars-Peter Clausen regmap_update_bits(adav80x->regmap, adav80x_port_ctrl_regs[dai->id][0], 477cc52688aSLars-Peter Clausen ADAV80X_CAPTURE_WORD_LEN_MASK, val); 478cc52688aSLars-Peter Clausen 479cc52688aSLars-Peter Clausen return 0; 480cc52688aSLars-Peter Clausen } 481cc52688aSLars-Peter Clausen 482cc52688aSLars-Peter Clausen static int adav80x_set_playback_pcm_format(struct snd_soc_codec *codec, 483cf7d8b27SMark Brown struct snd_soc_dai *dai, struct snd_pcm_hw_params *params) 484cc52688aSLars-Peter Clausen { 485cc52688aSLars-Peter Clausen struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); 486cc52688aSLars-Peter Clausen unsigned int val; 487cc52688aSLars-Peter Clausen 488cc52688aSLars-Peter Clausen if (adav80x->dai_fmt[dai->id] != SND_SOC_DAIFMT_RIGHT_J) 489cc52688aSLars-Peter Clausen return 0; 490cc52688aSLars-Peter Clausen 491cf7d8b27SMark Brown switch (params_width(params)) { 492cf7d8b27SMark Brown case 16: 493cc52688aSLars-Peter Clausen val = ADAV80X_PLAYBACK_MODE_RIGHT_J_16; 494cc52688aSLars-Peter Clausen break; 495cf7d8b27SMark Brown case 18: 496cc52688aSLars-Peter Clausen val = ADAV80X_PLAYBACK_MODE_RIGHT_J_18; 497cc52688aSLars-Peter Clausen break; 498cf7d8b27SMark Brown case 20: 499cc52688aSLars-Peter Clausen val = ADAV80X_PLAYBACK_MODE_RIGHT_J_20; 500cc52688aSLars-Peter Clausen break; 501cf7d8b27SMark Brown case 24: 502cc52688aSLars-Peter Clausen val = ADAV80X_PLAYBACK_MODE_RIGHT_J_24; 503cc52688aSLars-Peter Clausen break; 504cc52688aSLars-Peter Clausen default: 505ca1004baSMark Brown return -EINVAL; 506cc52688aSLars-Peter Clausen } 507cc52688aSLars-Peter Clausen 5082560b3d1SLars-Peter Clausen regmap_update_bits(adav80x->regmap, adav80x_port_ctrl_regs[dai->id][1], 509cc52688aSLars-Peter Clausen ADAV80X_PLAYBACK_MODE_MASK, val); 510cc52688aSLars-Peter Clausen 511cc52688aSLars-Peter Clausen return 0; 512cc52688aSLars-Peter Clausen } 513cc52688aSLars-Peter Clausen 514cc52688aSLars-Peter Clausen static int adav80x_hw_params(struct snd_pcm_substream *substream, 515cc52688aSLars-Peter Clausen struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) 516cc52688aSLars-Peter Clausen { 517cc52688aSLars-Peter Clausen struct snd_soc_codec *codec = dai->codec; 518cc52688aSLars-Peter Clausen struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); 519cc52688aSLars-Peter Clausen unsigned int rate = params_rate(params); 520cc52688aSLars-Peter Clausen 521cc52688aSLars-Peter Clausen if (rate * 256 != adav80x->sysclk) 522cc52688aSLars-Peter Clausen return -EINVAL; 523cc52688aSLars-Peter Clausen 524cc52688aSLars-Peter Clausen if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 525cf7d8b27SMark Brown adav80x_set_playback_pcm_format(codec, dai, params); 526cc52688aSLars-Peter Clausen adav80x_set_dac_clock(codec, rate); 527cc52688aSLars-Peter Clausen } else { 528cf7d8b27SMark Brown adav80x_set_capture_pcm_format(codec, dai, params); 529cc52688aSLars-Peter Clausen adav80x_set_adc_clock(codec, rate); 530cc52688aSLars-Peter Clausen } 531cc52688aSLars-Peter Clausen adav80x->rate = rate; 532cc52688aSLars-Peter Clausen adav80x_set_deemph(codec); 533cc52688aSLars-Peter Clausen 534cc52688aSLars-Peter Clausen return 0; 535cc52688aSLars-Peter Clausen } 536cc52688aSLars-Peter Clausen 537cc52688aSLars-Peter Clausen static int adav80x_set_sysclk(struct snd_soc_codec *codec, 538da1c6ea6SMark Brown int clk_id, int source, 539da1c6ea6SMark Brown unsigned int freq, int dir) 540cc52688aSLars-Peter Clausen { 541cc52688aSLars-Peter Clausen struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); 5421bf1b8cfSCharles Keepax struct snd_soc_dapm_context *dapm = &codec->dapm; 543cc52688aSLars-Peter Clausen 544cc52688aSLars-Peter Clausen if (dir == SND_SOC_CLOCK_IN) { 545cc52688aSLars-Peter Clausen switch (clk_id) { 546cc52688aSLars-Peter Clausen case ADAV80X_CLK_XIN: 547cc52688aSLars-Peter Clausen case ADAV80X_CLK_XTAL: 548cc52688aSLars-Peter Clausen case ADAV80X_CLK_MCLKI: 549cc52688aSLars-Peter Clausen case ADAV80X_CLK_PLL1: 550cc52688aSLars-Peter Clausen case ADAV80X_CLK_PLL2: 551cc52688aSLars-Peter Clausen break; 552cc52688aSLars-Peter Clausen default: 553cc52688aSLars-Peter Clausen return -EINVAL; 554cc52688aSLars-Peter Clausen } 555cc52688aSLars-Peter Clausen 556cc52688aSLars-Peter Clausen adav80x->sysclk = freq; 557cc52688aSLars-Peter Clausen 558cc52688aSLars-Peter Clausen if (adav80x->clk_src != clk_id) { 559cc52688aSLars-Peter Clausen unsigned int iclk_ctrl1, iclk_ctrl2; 560cc52688aSLars-Peter Clausen 561cc52688aSLars-Peter Clausen adav80x->clk_src = clk_id; 562cc52688aSLars-Peter Clausen if (clk_id == ADAV80X_CLK_XTAL) 563cc52688aSLars-Peter Clausen clk_id = ADAV80X_CLK_XIN; 564cc52688aSLars-Peter Clausen 565cc52688aSLars-Peter Clausen iclk_ctrl1 = ADAV80X_ICLK_CTRL1_DAC_SRC(clk_id) | 566cc52688aSLars-Peter Clausen ADAV80X_ICLK_CTRL1_ADC_SRC(clk_id) | 567cc52688aSLars-Peter Clausen ADAV80X_ICLK_CTRL1_ICLK2_SRC(clk_id); 568cc52688aSLars-Peter Clausen iclk_ctrl2 = ADAV80X_ICLK_CTRL2_ICLK1_SRC(clk_id); 569cc52688aSLars-Peter Clausen 5702560b3d1SLars-Peter Clausen regmap_write(adav80x->regmap, ADAV80X_ICLK_CTRL1, 5712560b3d1SLars-Peter Clausen iclk_ctrl1); 5722560b3d1SLars-Peter Clausen regmap_write(adav80x->regmap, ADAV80X_ICLK_CTRL2, 5732560b3d1SLars-Peter Clausen iclk_ctrl2); 574cc52688aSLars-Peter Clausen 5751bf1b8cfSCharles Keepax snd_soc_dapm_sync(dapm); 576cc52688aSLars-Peter Clausen } 577cc52688aSLars-Peter Clausen } else { 578cc52688aSLars-Peter Clausen unsigned int mask; 579cc52688aSLars-Peter Clausen 580cc52688aSLars-Peter Clausen switch (clk_id) { 581cc52688aSLars-Peter Clausen case ADAV80X_CLK_SYSCLK1: 582cc52688aSLars-Peter Clausen case ADAV80X_CLK_SYSCLK2: 583cc52688aSLars-Peter Clausen case ADAV80X_CLK_SYSCLK3: 584cc52688aSLars-Peter Clausen break; 585cc52688aSLars-Peter Clausen default: 586cc52688aSLars-Peter Clausen return -EINVAL; 587cc52688aSLars-Peter Clausen } 588cc52688aSLars-Peter Clausen 589cc52688aSLars-Peter Clausen clk_id -= ADAV80X_CLK_SYSCLK1; 590cc52688aSLars-Peter Clausen mask = ADAV80X_PLL_OUTE_SYSCLKPD(clk_id); 591cc52688aSLars-Peter Clausen 592cc52688aSLars-Peter Clausen if (freq == 0) { 5932560b3d1SLars-Peter Clausen regmap_update_bits(adav80x->regmap, ADAV80X_PLL_OUTE, 5942560b3d1SLars-Peter Clausen mask, mask); 595cc52688aSLars-Peter Clausen adav80x->sysclk_pd[clk_id] = true; 596cc52688aSLars-Peter Clausen } else { 5972560b3d1SLars-Peter Clausen regmap_update_bits(adav80x->regmap, ADAV80X_PLL_OUTE, 5982560b3d1SLars-Peter Clausen mask, 0); 599cc52688aSLars-Peter Clausen adav80x->sysclk_pd[clk_id] = false; 600cc52688aSLars-Peter Clausen } 601cc52688aSLars-Peter Clausen 6021bf1b8cfSCharles Keepax snd_soc_dapm_mutex_lock(dapm); 6031bf1b8cfSCharles Keepax 604cc52688aSLars-Peter Clausen if (adav80x->sysclk_pd[0]) 6051bf1b8cfSCharles Keepax snd_soc_dapm_disable_pin_unlocked(dapm, "PLL1"); 606cc52688aSLars-Peter Clausen else 6071bf1b8cfSCharles Keepax snd_soc_dapm_force_enable_pin_unlocked(dapm, "PLL1"); 608cc52688aSLars-Peter Clausen 609cc52688aSLars-Peter Clausen if (adav80x->sysclk_pd[1] || adav80x->sysclk_pd[2]) 6101bf1b8cfSCharles Keepax snd_soc_dapm_disable_pin_unlocked(dapm, "PLL2"); 611cc52688aSLars-Peter Clausen else 6121bf1b8cfSCharles Keepax snd_soc_dapm_force_enable_pin_unlocked(dapm, "PLL2"); 613cc52688aSLars-Peter Clausen 6141bf1b8cfSCharles Keepax snd_soc_dapm_sync_unlocked(dapm); 6151bf1b8cfSCharles Keepax 6161bf1b8cfSCharles Keepax snd_soc_dapm_mutex_unlock(dapm); 617cc52688aSLars-Peter Clausen } 618cc52688aSLars-Peter Clausen 619cc52688aSLars-Peter Clausen return 0; 620cc52688aSLars-Peter Clausen } 621cc52688aSLars-Peter Clausen 622cc52688aSLars-Peter Clausen static int adav80x_set_pll(struct snd_soc_codec *codec, int pll_id, 623cc52688aSLars-Peter Clausen int source, unsigned int freq_in, unsigned int freq_out) 624cc52688aSLars-Peter Clausen { 625cc52688aSLars-Peter Clausen struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); 626cc52688aSLars-Peter Clausen unsigned int pll_ctrl1 = 0; 627cc52688aSLars-Peter Clausen unsigned int pll_ctrl2 = 0; 628cc52688aSLars-Peter Clausen unsigned int pll_src; 629cc52688aSLars-Peter Clausen 630cc52688aSLars-Peter Clausen switch (source) { 631cc52688aSLars-Peter Clausen case ADAV80X_PLL_SRC_XTAL: 632cc52688aSLars-Peter Clausen case ADAV80X_PLL_SRC_XIN: 633cc52688aSLars-Peter Clausen case ADAV80X_PLL_SRC_MCLKI: 634cc52688aSLars-Peter Clausen break; 635cc52688aSLars-Peter Clausen default: 636cc52688aSLars-Peter Clausen return -EINVAL; 637cc52688aSLars-Peter Clausen } 638cc52688aSLars-Peter Clausen 639cc52688aSLars-Peter Clausen if (!freq_out) 640cc52688aSLars-Peter Clausen return 0; 641cc52688aSLars-Peter Clausen 642cc52688aSLars-Peter Clausen switch (freq_in) { 643cc52688aSLars-Peter Clausen case 27000000: 644cc52688aSLars-Peter Clausen break; 645cc52688aSLars-Peter Clausen case 54000000: 646cc52688aSLars-Peter Clausen if (source == ADAV80X_PLL_SRC_XIN) { 647cc52688aSLars-Peter Clausen pll_ctrl1 |= ADAV80X_PLL_CTRL1_PLLDIV; 648cc52688aSLars-Peter Clausen break; 649cc52688aSLars-Peter Clausen } 650cc52688aSLars-Peter Clausen default: 651cc52688aSLars-Peter Clausen return -EINVAL; 652cc52688aSLars-Peter Clausen } 653cc52688aSLars-Peter Clausen 654cc52688aSLars-Peter Clausen if (freq_out > 12288000) { 655cc52688aSLars-Peter Clausen pll_ctrl2 |= ADAV80X_PLL_CTRL2_DOUB(pll_id); 656cc52688aSLars-Peter Clausen freq_out /= 2; 657cc52688aSLars-Peter Clausen } 658cc52688aSLars-Peter Clausen 659cc52688aSLars-Peter Clausen /* freq_out = sample_rate * 256 */ 660cc52688aSLars-Peter Clausen switch (freq_out) { 661cc52688aSLars-Peter Clausen case 8192000: 662cc52688aSLars-Peter Clausen pll_ctrl2 |= ADAV80X_PLL_CTRL2_FS_32(pll_id); 663cc52688aSLars-Peter Clausen break; 664cc52688aSLars-Peter Clausen case 11289600: 665cc52688aSLars-Peter Clausen pll_ctrl2 |= ADAV80X_PLL_CTRL2_FS_44(pll_id); 666cc52688aSLars-Peter Clausen break; 667cc52688aSLars-Peter Clausen case 12288000: 668cc52688aSLars-Peter Clausen pll_ctrl2 |= ADAV80X_PLL_CTRL2_FS_48(pll_id); 669cc52688aSLars-Peter Clausen break; 670cc52688aSLars-Peter Clausen default: 671cc52688aSLars-Peter Clausen return -EINVAL; 672cc52688aSLars-Peter Clausen } 673cc52688aSLars-Peter Clausen 6742560b3d1SLars-Peter Clausen regmap_update_bits(adav80x->regmap, ADAV80X_PLL_CTRL1, 6752560b3d1SLars-Peter Clausen ADAV80X_PLL_CTRL1_PLLDIV, pll_ctrl1); 6762560b3d1SLars-Peter Clausen regmap_update_bits(adav80x->regmap, ADAV80X_PLL_CTRL2, 677cc52688aSLars-Peter Clausen ADAV80X_PLL_CTRL2_PLL_MASK(pll_id), pll_ctrl2); 678cc52688aSLars-Peter Clausen 679cc52688aSLars-Peter Clausen if (source != adav80x->pll_src) { 680cc52688aSLars-Peter Clausen if (source == ADAV80X_PLL_SRC_MCLKI) 681cc52688aSLars-Peter Clausen pll_src = ADAV80X_PLL_CLK_SRC_PLL_MCLKI(pll_id); 682cc52688aSLars-Peter Clausen else 683cc52688aSLars-Peter Clausen pll_src = ADAV80X_PLL_CLK_SRC_PLL_XIN(pll_id); 684cc52688aSLars-Peter Clausen 6852560b3d1SLars-Peter Clausen regmap_update_bits(adav80x->regmap, ADAV80X_PLL_CLK_SRC, 686cc52688aSLars-Peter Clausen ADAV80X_PLL_CLK_SRC_PLL_MASK(pll_id), pll_src); 687cc52688aSLars-Peter Clausen 688cc52688aSLars-Peter Clausen adav80x->pll_src = source; 689cc52688aSLars-Peter Clausen 690cc52688aSLars-Peter Clausen snd_soc_dapm_sync(&codec->dapm); 691cc52688aSLars-Peter Clausen } 692cc52688aSLars-Peter Clausen 693cc52688aSLars-Peter Clausen return 0; 694cc52688aSLars-Peter Clausen } 695cc52688aSLars-Peter Clausen 696cc52688aSLars-Peter Clausen static int adav80x_set_bias_level(struct snd_soc_codec *codec, 697cc52688aSLars-Peter Clausen enum snd_soc_bias_level level) 698cc52688aSLars-Peter Clausen { 6992560b3d1SLars-Peter Clausen struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); 700cc52688aSLars-Peter Clausen unsigned int mask = ADAV80X_DAC_CTRL1_PD; 701cc52688aSLars-Peter Clausen 702cc52688aSLars-Peter Clausen switch (level) { 703cc52688aSLars-Peter Clausen case SND_SOC_BIAS_ON: 704cc52688aSLars-Peter Clausen break; 705cc52688aSLars-Peter Clausen case SND_SOC_BIAS_PREPARE: 706cc52688aSLars-Peter Clausen break; 707cc52688aSLars-Peter Clausen case SND_SOC_BIAS_STANDBY: 7082560b3d1SLars-Peter Clausen regmap_update_bits(adav80x->regmap, ADAV80X_DAC_CTRL1, mask, 7092560b3d1SLars-Peter Clausen 0x00); 710cc52688aSLars-Peter Clausen break; 711cc52688aSLars-Peter Clausen case SND_SOC_BIAS_OFF: 7122560b3d1SLars-Peter Clausen regmap_update_bits(adav80x->regmap, ADAV80X_DAC_CTRL1, mask, 7132560b3d1SLars-Peter Clausen mask); 714cc52688aSLars-Peter Clausen break; 715cc52688aSLars-Peter Clausen } 716cc52688aSLars-Peter Clausen 717cc52688aSLars-Peter Clausen codec->dapm.bias_level = level; 718cc52688aSLars-Peter Clausen return 0; 719cc52688aSLars-Peter Clausen } 720cc52688aSLars-Peter Clausen 721cc52688aSLars-Peter Clausen /* Enforce the same sample rate on all audio interfaces */ 722cc52688aSLars-Peter Clausen static int adav80x_dai_startup(struct snd_pcm_substream *substream, 723cc52688aSLars-Peter Clausen struct snd_soc_dai *dai) 724cc52688aSLars-Peter Clausen { 725cc52688aSLars-Peter Clausen struct snd_soc_codec *codec = dai->codec; 726cc52688aSLars-Peter Clausen struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); 727cc52688aSLars-Peter Clausen 7285c898e74SLars-Peter Clausen if (!snd_soc_codec_is_active(codec) || !adav80x->rate) 729cc52688aSLars-Peter Clausen return 0; 730cc52688aSLars-Peter Clausen 731cc52688aSLars-Peter Clausen return snd_pcm_hw_constraint_minmax(substream->runtime, 732cc52688aSLars-Peter Clausen SNDRV_PCM_HW_PARAM_RATE, adav80x->rate, adav80x->rate); 733cc52688aSLars-Peter Clausen } 734cc52688aSLars-Peter Clausen 735cc52688aSLars-Peter Clausen static void adav80x_dai_shutdown(struct snd_pcm_substream *substream, 736cc52688aSLars-Peter Clausen struct snd_soc_dai *dai) 737cc52688aSLars-Peter Clausen { 738cc52688aSLars-Peter Clausen struct snd_soc_codec *codec = dai->codec; 739cc52688aSLars-Peter Clausen struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); 740cc52688aSLars-Peter Clausen 7415c898e74SLars-Peter Clausen if (!snd_soc_codec_is_active(codec)) 742cc52688aSLars-Peter Clausen adav80x->rate = 0; 743cc52688aSLars-Peter Clausen } 744cc52688aSLars-Peter Clausen 745890754a8SLars-Peter Clausen static const struct snd_soc_dai_ops adav80x_dai_ops = { 746cc52688aSLars-Peter Clausen .set_fmt = adav80x_set_dai_fmt, 747cc52688aSLars-Peter Clausen .hw_params = adav80x_hw_params, 748cc52688aSLars-Peter Clausen .startup = adav80x_dai_startup, 749cc52688aSLars-Peter Clausen .shutdown = adav80x_dai_shutdown, 750cc52688aSLars-Peter Clausen }; 751cc52688aSLars-Peter Clausen 752cc52688aSLars-Peter Clausen #define ADAV80X_PLAYBACK_RATES (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ 753cc52688aSLars-Peter Clausen SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_64000 | SNDRV_PCM_RATE_88200 | \ 754cc52688aSLars-Peter Clausen SNDRV_PCM_RATE_96000) 755cc52688aSLars-Peter Clausen 756cc52688aSLars-Peter Clausen #define ADAV80X_CAPTURE_RATES (SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000) 757cc52688aSLars-Peter Clausen 758cc52688aSLars-Peter Clausen #define ADAV80X_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S18_3LE | \ 759cc52688aSLars-Peter Clausen SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE) 760cc52688aSLars-Peter Clausen 761cc52688aSLars-Peter Clausen static struct snd_soc_dai_driver adav80x_dais[] = { 762cc52688aSLars-Peter Clausen { 763cc52688aSLars-Peter Clausen .name = "adav80x-hifi", 764cc52688aSLars-Peter Clausen .id = 0, 765cc52688aSLars-Peter Clausen .playback = { 766cc52688aSLars-Peter Clausen .stream_name = "HiFi Playback", 767cc52688aSLars-Peter Clausen .channels_min = 2, 768cc52688aSLars-Peter Clausen .channels_max = 2, 769cc52688aSLars-Peter Clausen .rates = ADAV80X_PLAYBACK_RATES, 770cc52688aSLars-Peter Clausen .formats = ADAV80X_FORMATS, 771cc52688aSLars-Peter Clausen }, 772cc52688aSLars-Peter Clausen .capture = { 773cc52688aSLars-Peter Clausen .stream_name = "HiFi Capture", 774cc52688aSLars-Peter Clausen .channels_min = 2, 775cc52688aSLars-Peter Clausen .channels_max = 2, 776cc52688aSLars-Peter Clausen .rates = ADAV80X_CAPTURE_RATES, 777cc52688aSLars-Peter Clausen .formats = ADAV80X_FORMATS, 778cc52688aSLars-Peter Clausen }, 779cc52688aSLars-Peter Clausen .ops = &adav80x_dai_ops, 780cc52688aSLars-Peter Clausen }, 781cc52688aSLars-Peter Clausen { 782cc52688aSLars-Peter Clausen .name = "adav80x-aux", 783cc52688aSLars-Peter Clausen .id = 1, 784cc52688aSLars-Peter Clausen .playback = { 785cc52688aSLars-Peter Clausen .stream_name = "Aux Playback", 786cc52688aSLars-Peter Clausen .channels_min = 2, 787cc52688aSLars-Peter Clausen .channels_max = 2, 788cc52688aSLars-Peter Clausen .rates = ADAV80X_PLAYBACK_RATES, 789cc52688aSLars-Peter Clausen .formats = ADAV80X_FORMATS, 790cc52688aSLars-Peter Clausen }, 791cc52688aSLars-Peter Clausen .capture = { 792cc52688aSLars-Peter Clausen .stream_name = "Aux Capture", 793cc52688aSLars-Peter Clausen .channels_min = 2, 794cc52688aSLars-Peter Clausen .channels_max = 2, 795cc52688aSLars-Peter Clausen .rates = ADAV80X_CAPTURE_RATES, 796cc52688aSLars-Peter Clausen .formats = ADAV80X_FORMATS, 797cc52688aSLars-Peter Clausen }, 798cc52688aSLars-Peter Clausen .ops = &adav80x_dai_ops, 799cc52688aSLars-Peter Clausen }, 800cc52688aSLars-Peter Clausen }; 801cc52688aSLars-Peter Clausen 802cc52688aSLars-Peter Clausen static int adav80x_probe(struct snd_soc_codec *codec) 803cc52688aSLars-Peter Clausen { 804cc52688aSLars-Peter Clausen struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); 805cc52688aSLars-Peter Clausen 806cc52688aSLars-Peter Clausen /* Force PLLs on for SYSCLK output */ 807cc52688aSLars-Peter Clausen snd_soc_dapm_force_enable_pin(&codec->dapm, "PLL1"); 808cc52688aSLars-Peter Clausen snd_soc_dapm_force_enable_pin(&codec->dapm, "PLL2"); 809cc52688aSLars-Peter Clausen 810cc52688aSLars-Peter Clausen /* Power down S/PDIF receiver, since it is currently not supported */ 8112560b3d1SLars-Peter Clausen regmap_write(adav80x->regmap, ADAV80X_PLL_OUTE, 0x20); 812cc52688aSLars-Peter Clausen /* Disable DAC zero flag */ 8132560b3d1SLars-Peter Clausen regmap_write(adav80x->regmap, ADAV80X_DAC_CTRL3, 0x6); 814cc52688aSLars-Peter Clausen 815cd5d3a15SLars-Peter Clausen return 0; 816cc52688aSLars-Peter Clausen } 817cc52688aSLars-Peter Clausen 818cc52688aSLars-Peter Clausen static int adav80x_resume(struct snd_soc_codec *codec) 819cc52688aSLars-Peter Clausen { 8202560b3d1SLars-Peter Clausen struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); 8212560b3d1SLars-Peter Clausen 8222560b3d1SLars-Peter Clausen regcache_sync(adav80x->regmap); 823cc52688aSLars-Peter Clausen 824cc52688aSLars-Peter Clausen return 0; 825cc52688aSLars-Peter Clausen } 826cc52688aSLars-Peter Clausen 827cc52688aSLars-Peter Clausen static struct snd_soc_codec_driver adav80x_codec_driver = { 828cc52688aSLars-Peter Clausen .probe = adav80x_probe, 829cc52688aSLars-Peter Clausen .resume = adav80x_resume, 830cc52688aSLars-Peter Clausen .set_bias_level = adav80x_set_bias_level, 831cd5d3a15SLars-Peter Clausen .suspend_bias_off = true, 832cc52688aSLars-Peter Clausen 833cc52688aSLars-Peter Clausen .set_pll = adav80x_set_pll, 834cc52688aSLars-Peter Clausen .set_sysclk = adav80x_set_sysclk, 835cc52688aSLars-Peter Clausen 836cc52688aSLars-Peter Clausen .controls = adav80x_controls, 837cc52688aSLars-Peter Clausen .num_controls = ARRAY_SIZE(adav80x_controls), 838cc52688aSLars-Peter Clausen .dapm_widgets = adav80x_dapm_widgets, 839cc52688aSLars-Peter Clausen .num_dapm_widgets = ARRAY_SIZE(adav80x_dapm_widgets), 840cc52688aSLars-Peter Clausen .dapm_routes = adav80x_dapm_routes, 841cc52688aSLars-Peter Clausen .num_dapm_routes = ARRAY_SIZE(adav80x_dapm_routes), 842cc52688aSLars-Peter Clausen }; 843cc52688aSLars-Peter Clausen 8440c2d6964SLars-Peter Clausen int adav80x_bus_probe(struct device *dev, struct regmap *regmap) 845cc52688aSLars-Peter Clausen { 846cc52688aSLars-Peter Clausen struct adav80x *adav80x; 847cc52688aSLars-Peter Clausen 8482560b3d1SLars-Peter Clausen if (IS_ERR(regmap)) 8492560b3d1SLars-Peter Clausen return PTR_ERR(regmap); 8502560b3d1SLars-Peter Clausen 851f96a5d3fSLars-Peter Clausen adav80x = devm_kzalloc(dev, sizeof(*adav80x), GFP_KERNEL); 852cc52688aSLars-Peter Clausen if (!adav80x) 853cc52688aSLars-Peter Clausen return -ENOMEM; 854cc52688aSLars-Peter Clausen 855cc52688aSLars-Peter Clausen dev_set_drvdata(dev, adav80x); 8562560b3d1SLars-Peter Clausen adav80x->regmap = regmap; 857cc52688aSLars-Peter Clausen 858f96a5d3fSLars-Peter Clausen return snd_soc_register_codec(dev, &adav80x_codec_driver, 859cc52688aSLars-Peter Clausen adav80x_dais, ARRAY_SIZE(adav80x_dais)); 860cc52688aSLars-Peter Clausen } 8610c2d6964SLars-Peter Clausen EXPORT_SYMBOL_GPL(adav80x_bus_probe); 862cc52688aSLars-Peter Clausen 8630c2d6964SLars-Peter Clausen const struct regmap_config adav80x_regmap_config = { 8642560b3d1SLars-Peter Clausen .val_bits = 8, 8652560b3d1SLars-Peter Clausen .pad_bits = 1, 8662560b3d1SLars-Peter Clausen .reg_bits = 7, 8672560b3d1SLars-Peter Clausen .read_flag_mask = 0x01, 8682560b3d1SLars-Peter Clausen 8692560b3d1SLars-Peter Clausen .max_register = ADAV80X_PLL_OUTE, 8702560b3d1SLars-Peter Clausen 8712560b3d1SLars-Peter Clausen .cache_type = REGCACHE_RBTREE, 8722560b3d1SLars-Peter Clausen .reg_defaults = adav80x_reg_defaults, 8732560b3d1SLars-Peter Clausen .num_reg_defaults = ARRAY_SIZE(adav80x_reg_defaults), 8742560b3d1SLars-Peter Clausen }; 8750c2d6964SLars-Peter Clausen EXPORT_SYMBOL_GPL(adav80x_regmap_config); 876cc52688aSLars-Peter Clausen 877cc52688aSLars-Peter Clausen MODULE_DESCRIPTION("ASoC ADAV80x driver"); 878cc52688aSLars-Peter Clausen MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); 879cc52688aSLars-Peter Clausen MODULE_AUTHOR("Yi Li <yi.li@analog.com>>"); 880cc52688aSLars-Peter Clausen MODULE_LICENSE("GPL"); 881