1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 2f2644a2cSMark Brown /* 3f2644a2cSMark Brown * wm8960.c -- WM8960 ALSA SoC Audio driver 4f2644a2cSMark Brown * 5656baaebSMark Brown * Copyright 2007-11 Wolfson Microelectronics, plc 6656baaebSMark Brown * 7f2644a2cSMark Brown * Author: Liam Girdwood 8f2644a2cSMark Brown */ 9f2644a2cSMark Brown 10f2644a2cSMark Brown #include <linux/module.h> 11f2644a2cSMark Brown #include <linux/moduleparam.h> 12f2644a2cSMark Brown #include <linux/init.h> 13f2644a2cSMark Brown #include <linux/delay.h> 14f2644a2cSMark Brown #include <linux/pm.h> 1575aa8868SZidan Wang #include <linux/clk.h> 16f2644a2cSMark Brown #include <linux/i2c.h> 177e0bdbaeSNicola Lunghi #include <linux/acpi.h> 185a0e3ad6STejun Heo #include <linux/slab.h> 19f2644a2cSMark Brown #include <sound/core.h> 20f2644a2cSMark Brown #include <sound/pcm.h> 21f2644a2cSMark Brown #include <sound/pcm_params.h> 22f2644a2cSMark Brown #include <sound/soc.h> 23f2644a2cSMark Brown #include <sound/initval.h> 24f2644a2cSMark Brown #include <sound/tlv.h> 25b6877a47SMark Brown #include <sound/wm8960.h> 26f2644a2cSMark Brown 27f2644a2cSMark Brown #include "wm8960.h" 28f2644a2cSMark Brown 29f2644a2cSMark Brown /* R25 - Power 1 */ 30913d7b4cSMark Brown #define WM8960_VMID_MASK 0x180 31f2644a2cSMark Brown #define WM8960_VREF 0x40 32f2644a2cSMark Brown 33913d7b4cSMark Brown /* R26 - Power 2 */ 34913d7b4cSMark Brown #define WM8960_PWR2_LOUT1 0x40 35913d7b4cSMark Brown #define WM8960_PWR2_ROUT1 0x20 36913d7b4cSMark Brown #define WM8960_PWR2_OUT3 0x02 37913d7b4cSMark Brown 38f2644a2cSMark Brown /* R28 - Anti-pop 1 */ 39f2644a2cSMark Brown #define WM8960_POBCTRL 0x80 40f2644a2cSMark Brown #define WM8960_BUFDCOPEN 0x10 41f2644a2cSMark Brown #define WM8960_BUFIOEN 0x08 42f2644a2cSMark Brown #define WM8960_SOFT_ST 0x04 43f2644a2cSMark Brown #define WM8960_HPSTBY 0x01 44f2644a2cSMark Brown 45f2644a2cSMark Brown /* R29 - Anti-pop 2 */ 46f2644a2cSMark Brown #define WM8960_DISOP 0x40 47913d7b4cSMark Brown #define WM8960_DRES_MASK 0x30 48f2644a2cSMark Brown 493c7a4c24SViorel Suman #define WM8960_DSCH_TOUT 600 /* discharge timeout, ms */ 503c7a4c24SViorel Suman 513176bf2dSZidan Wang static bool is_pll_freq_available(unsigned int source, unsigned int target); 52e075fc17SKuninori Morimoto static int wm8960_set_pll(struct snd_soc_component *component, 533176bf2dSZidan Wang unsigned int freq_in, unsigned int freq_out); 54f2644a2cSMark Brown /* 55f2644a2cSMark Brown * wm8960 register cache 56f2644a2cSMark Brown * We can't read the WM8960 register space when we are 57f2644a2cSMark Brown * using 2 wire for device control, so we cache them instead. 58f2644a2cSMark Brown */ 590ebe36c6SMark Brown static const struct reg_default wm8960_reg_defaults[] = { 60b3df026eSMark Brown { 0x0, 0x00a7 }, 61b3df026eSMark Brown { 0x1, 0x00a7 }, 620ebe36c6SMark Brown { 0x2, 0x0000 }, 630ebe36c6SMark Brown { 0x3, 0x0000 }, 640ebe36c6SMark Brown { 0x4, 0x0000 }, 650ebe36c6SMark Brown { 0x5, 0x0008 }, 660ebe36c6SMark Brown { 0x6, 0x0000 }, 670ebe36c6SMark Brown { 0x7, 0x000a }, 680ebe36c6SMark Brown { 0x8, 0x01c0 }, 690ebe36c6SMark Brown { 0x9, 0x0000 }, 700ebe36c6SMark Brown { 0xa, 0x00ff }, 710ebe36c6SMark Brown { 0xb, 0x00ff }, 720ebe36c6SMark Brown 730ebe36c6SMark Brown { 0x10, 0x0000 }, 740ebe36c6SMark Brown { 0x11, 0x007b }, 750ebe36c6SMark Brown { 0x12, 0x0100 }, 760ebe36c6SMark Brown { 0x13, 0x0032 }, 770ebe36c6SMark Brown { 0x14, 0x0000 }, 780ebe36c6SMark Brown { 0x15, 0x00c3 }, 790ebe36c6SMark Brown { 0x16, 0x00c3 }, 800ebe36c6SMark Brown { 0x17, 0x01c0 }, 810ebe36c6SMark Brown { 0x18, 0x0000 }, 820ebe36c6SMark Brown { 0x19, 0x0000 }, 830ebe36c6SMark Brown { 0x1a, 0x0000 }, 840ebe36c6SMark Brown { 0x1b, 0x0000 }, 850ebe36c6SMark Brown { 0x1c, 0x0000 }, 860ebe36c6SMark Brown { 0x1d, 0x0000 }, 870ebe36c6SMark Brown 880ebe36c6SMark Brown { 0x20, 0x0100 }, 890ebe36c6SMark Brown { 0x21, 0x0100 }, 900ebe36c6SMark Brown { 0x22, 0x0050 }, 910ebe36c6SMark Brown 920ebe36c6SMark Brown { 0x25, 0x0050 }, 930ebe36c6SMark Brown { 0x26, 0x0000 }, 940ebe36c6SMark Brown { 0x27, 0x0000 }, 950ebe36c6SMark Brown { 0x28, 0x0000 }, 960ebe36c6SMark Brown { 0x29, 0x0000 }, 970ebe36c6SMark Brown { 0x2a, 0x0040 }, 980ebe36c6SMark Brown { 0x2b, 0x0000 }, 990ebe36c6SMark Brown { 0x2c, 0x0000 }, 1000ebe36c6SMark Brown { 0x2d, 0x0050 }, 1010ebe36c6SMark Brown { 0x2e, 0x0050 }, 1020ebe36c6SMark Brown { 0x2f, 0x0000 }, 1030ebe36c6SMark Brown { 0x30, 0x0002 }, 1040ebe36c6SMark Brown { 0x31, 0x0037 }, 1050ebe36c6SMark Brown 1060ebe36c6SMark Brown { 0x33, 0x0080 }, 1070ebe36c6SMark Brown { 0x34, 0x0008 }, 1080ebe36c6SMark Brown { 0x35, 0x0031 }, 1090ebe36c6SMark Brown { 0x36, 0x0026 }, 1100ebe36c6SMark Brown { 0x37, 0x00e9 }, 111f2644a2cSMark Brown }; 112f2644a2cSMark Brown 1130ebe36c6SMark Brown static bool wm8960_volatile(struct device *dev, unsigned int reg) 1140ebe36c6SMark Brown { 1150ebe36c6SMark Brown switch (reg) { 1160ebe36c6SMark Brown case WM8960_RESET: 1170ebe36c6SMark Brown return true; 1180ebe36c6SMark Brown default: 1190ebe36c6SMark Brown return false; 1200ebe36c6SMark Brown } 1210ebe36c6SMark Brown } 1220ebe36c6SMark Brown 123f2644a2cSMark Brown struct wm8960_priv { 12475aa8868SZidan Wang struct clk *mclk; 1250ebe36c6SMark Brown struct regmap *regmap; 126e075fc17SKuninori Morimoto int (*set_bias_level)(struct snd_soc_component *, 127f0fba2adSLiam Girdwood enum snd_soc_bias_level level); 128913d7b4cSMark Brown struct snd_soc_dapm_widget *lout1; 129913d7b4cSMark Brown struct snd_soc_dapm_widget *rout1; 130913d7b4cSMark Brown struct snd_soc_dapm_widget *out3; 131afd6d36aSMark Brown bool deemph; 1323176bf2dSZidan Wang int lrclk; 1330e50b51aSZidan Wang int bclk; 1340e50b51aSZidan Wang int sysclk; 1353176bf2dSZidan Wang int clk_id; 1363176bf2dSZidan Wang int freq_in; 1373176bf2dSZidan Wang bool is_stream_in_use[2]; 138e2280c90SZidan Wang struct wm8960_data pdata; 1393c7a4c24SViorel Suman ktime_t dsch_start; 140f2644a2cSMark Brown }; 141f2644a2cSMark Brown 1423ad5e861SZidan Wang #define wm8960_reset(c) regmap_write(c, WM8960_RESET, 0) 143f2644a2cSMark Brown 144f2644a2cSMark Brown /* enumerated controls */ 145f2644a2cSMark Brown static const char *wm8960_polarity[] = {"No Inversion", "Left Inverted", 146f2644a2cSMark Brown "Right Inverted", "Stereo Inversion"}; 147f2644a2cSMark Brown static const char *wm8960_3d_upper_cutoff[] = {"High", "Low"}; 148f2644a2cSMark Brown static const char *wm8960_3d_lower_cutoff[] = {"Low", "High"}; 149f2644a2cSMark Brown static const char *wm8960_alcfunc[] = {"Off", "Right", "Left", "Stereo"}; 150f2644a2cSMark Brown static const char *wm8960_alcmode[] = {"ALC", "Limiter"}; 1514a5893cfSZidan Wang static const char *wm8960_adc_data_output_sel[] = { 1524a5893cfSZidan Wang "Left Data = Left ADC; Right Data = Right ADC", 1534a5893cfSZidan Wang "Left Data = Left ADC; Right Data = Left ADC", 1544a5893cfSZidan Wang "Left Data = Right ADC; Right Data = Right ADC", 1554a5893cfSZidan Wang "Left Data = Right ADC; Right Data = Left ADC", 1564a5893cfSZidan Wang }; 157defbf708SZidan Wang static const char *wm8960_dmonomix[] = {"Stereo", "Mono"}; 158f2644a2cSMark Brown 159f2644a2cSMark Brown static const struct soc_enum wm8960_enum[] = { 160f2644a2cSMark Brown SOC_ENUM_SINGLE(WM8960_DACCTL1, 5, 4, wm8960_polarity), 161f2644a2cSMark Brown SOC_ENUM_SINGLE(WM8960_DACCTL2, 5, 4, wm8960_polarity), 162f2644a2cSMark Brown SOC_ENUM_SINGLE(WM8960_3D, 6, 2, wm8960_3d_upper_cutoff), 163f2644a2cSMark Brown SOC_ENUM_SINGLE(WM8960_3D, 5, 2, wm8960_3d_lower_cutoff), 164f2644a2cSMark Brown SOC_ENUM_SINGLE(WM8960_ALC1, 7, 4, wm8960_alcfunc), 165f2644a2cSMark Brown SOC_ENUM_SINGLE(WM8960_ALC3, 8, 2, wm8960_alcmode), 1664a5893cfSZidan Wang SOC_ENUM_SINGLE(WM8960_ADDCTL1, 2, 4, wm8960_adc_data_output_sel), 167defbf708SZidan Wang SOC_ENUM_SINGLE(WM8960_ADDCTL1, 4, 2, wm8960_dmonomix), 168f2644a2cSMark Brown }; 169f2644a2cSMark Brown 170afd6d36aSMark Brown static const int deemph_settings[] = { 0, 32000, 44100, 48000 }; 171afd6d36aSMark Brown 172e075fc17SKuninori Morimoto static int wm8960_set_deemph(struct snd_soc_component *component) 173afd6d36aSMark Brown { 174e075fc17SKuninori Morimoto struct wm8960_priv *wm8960 = snd_soc_component_get_drvdata(component); 175afd6d36aSMark Brown int val, i, best; 176afd6d36aSMark Brown 177afd6d36aSMark Brown /* If we're using deemphasis select the nearest available sample 178afd6d36aSMark Brown * rate. 179afd6d36aSMark Brown */ 180afd6d36aSMark Brown if (wm8960->deemph) { 181afd6d36aSMark Brown best = 1; 182afd6d36aSMark Brown for (i = 2; i < ARRAY_SIZE(deemph_settings); i++) { 1833176bf2dSZidan Wang if (abs(deemph_settings[i] - wm8960->lrclk) < 1843176bf2dSZidan Wang abs(deemph_settings[best] - wm8960->lrclk)) 185afd6d36aSMark Brown best = i; 186afd6d36aSMark Brown } 187afd6d36aSMark Brown 188afd6d36aSMark Brown val = best << 1; 189afd6d36aSMark Brown } else { 190afd6d36aSMark Brown val = 0; 191afd6d36aSMark Brown } 192afd6d36aSMark Brown 193e075fc17SKuninori Morimoto dev_dbg(component->dev, "Set deemphasis %d\n", val); 194afd6d36aSMark Brown 195e075fc17SKuninori Morimoto return snd_soc_component_update_bits(component, WM8960_DACCTL1, 196afd6d36aSMark Brown 0x6, val); 197afd6d36aSMark Brown } 198afd6d36aSMark Brown 199afd6d36aSMark Brown static int wm8960_get_deemph(struct snd_kcontrol *kcontrol, 200afd6d36aSMark Brown struct snd_ctl_elem_value *ucontrol) 201afd6d36aSMark Brown { 202e075fc17SKuninori Morimoto struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); 203e075fc17SKuninori Morimoto struct wm8960_priv *wm8960 = snd_soc_component_get_drvdata(component); 204afd6d36aSMark Brown 205b4a18c8bSTakashi Iwai ucontrol->value.integer.value[0] = wm8960->deemph; 2063f343f85SDmitry Artamonow return 0; 207afd6d36aSMark Brown } 208afd6d36aSMark Brown 209afd6d36aSMark Brown static int wm8960_put_deemph(struct snd_kcontrol *kcontrol, 210afd6d36aSMark Brown struct snd_ctl_elem_value *ucontrol) 211afd6d36aSMark Brown { 212e075fc17SKuninori Morimoto struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); 213e075fc17SKuninori Morimoto struct wm8960_priv *wm8960 = snd_soc_component_get_drvdata(component); 214c1fe81f2SDan Carpenter unsigned int deemph = ucontrol->value.integer.value[0]; 215afd6d36aSMark Brown 216afd6d36aSMark Brown if (deemph > 1) 217afd6d36aSMark Brown return -EINVAL; 218afd6d36aSMark Brown 219afd6d36aSMark Brown wm8960->deemph = deemph; 220afd6d36aSMark Brown 221e075fc17SKuninori Morimoto return wm8960_set_deemph(component); 222afd6d36aSMark Brown } 223afd6d36aSMark Brown 2243758ff5fSZidan Wang static const DECLARE_TLV_DB_SCALE(adc_tlv, -9750, 50, 1); 2257e90f9b2SZidan Wang static const DECLARE_TLV_DB_SCALE(inpga_tlv, -1725, 75, 0); 2263758ff5fSZidan Wang static const DECLARE_TLV_DB_SCALE(dac_tlv, -12750, 50, 1); 227f2644a2cSMark Brown static const DECLARE_TLV_DB_SCALE(bypass_tlv, -2100, 300, 0); 228f2644a2cSMark Brown static const DECLARE_TLV_DB_SCALE(out_tlv, -12100, 100, 1); 2297e90f9b2SZidan Wang static const DECLARE_TLV_DB_SCALE(lineinboost_tlv, -1500, 300, 1); 230b269cebfSTakashi Sakamoto static const SNDRV_CTL_TLVD_DECLARE_DB_RANGE(micboost_tlv, 2317e90f9b2SZidan Wang 0, 1, TLV_DB_SCALE_ITEM(0, 1300, 0), 2327e90f9b2SZidan Wang 2, 3, TLV_DB_SCALE_ITEM(2000, 900, 0), 233b269cebfSTakashi Sakamoto ); 234f2644a2cSMark Brown 235f2644a2cSMark Brown static const struct snd_kcontrol_new wm8960_snd_controls[] = { 236f2644a2cSMark Brown SOC_DOUBLE_R_TLV("Capture Volume", WM8960_LINVOL, WM8960_RINVOL, 2377e90f9b2SZidan Wang 0, 63, 0, inpga_tlv), 238f2644a2cSMark Brown SOC_DOUBLE_R("Capture Volume ZC Switch", WM8960_LINVOL, WM8960_RINVOL, 239f2644a2cSMark Brown 6, 1, 0), 240f2644a2cSMark Brown SOC_DOUBLE_R("Capture Switch", WM8960_LINVOL, WM8960_RINVOL, 24141a59caeSJongHo Kim 7, 1, 1), 242f2644a2cSMark Brown 24321eb2693SMark Brown SOC_SINGLE_TLV("Left Input Boost Mixer LINPUT3 Volume", 24495826a37SStuart Henderson WM8960_INBMIX1, 4, 7, 0, lineinboost_tlv), 24521eb2693SMark Brown SOC_SINGLE_TLV("Left Input Boost Mixer LINPUT2 Volume", 24695826a37SStuart Henderson WM8960_INBMIX1, 1, 7, 0, lineinboost_tlv), 24795826a37SStuart Henderson SOC_SINGLE_TLV("Right Input Boost Mixer RINPUT3 Volume", 24895826a37SStuart Henderson WM8960_INBMIX2, 4, 7, 0, lineinboost_tlv), 24995826a37SStuart Henderson SOC_SINGLE_TLV("Right Input Boost Mixer RINPUT2 Volume", 2507e90f9b2SZidan Wang WM8960_INBMIX2, 1, 7, 0, lineinboost_tlv), 2517e90f9b2SZidan Wang SOC_SINGLE_TLV("Right Input Boost Mixer RINPUT1 Volume", 2528524bb0cSZidan Wang WM8960_RINPATH, 4, 3, 0, micboost_tlv), 2537e90f9b2SZidan Wang SOC_SINGLE_TLV("Left Input Boost Mixer LINPUT1 Volume", 2548524bb0cSZidan Wang WM8960_LINPATH, 4, 3, 0, micboost_tlv), 25521eb2693SMark Brown 256f2644a2cSMark Brown SOC_DOUBLE_R_TLV("Playback Volume", WM8960_LDAC, WM8960_RDAC, 257f2644a2cSMark Brown 0, 255, 0, dac_tlv), 258f2644a2cSMark Brown 259f2644a2cSMark Brown SOC_DOUBLE_R_TLV("Headphone Playback Volume", WM8960_LOUT1, WM8960_ROUT1, 260f2644a2cSMark Brown 0, 127, 0, out_tlv), 261f2644a2cSMark Brown SOC_DOUBLE_R("Headphone Playback ZC Switch", WM8960_LOUT1, WM8960_ROUT1, 262f2644a2cSMark Brown 7, 1, 0), 263f2644a2cSMark Brown 264f2644a2cSMark Brown SOC_DOUBLE_R_TLV("Speaker Playback Volume", WM8960_LOUT2, WM8960_ROUT2, 265f2644a2cSMark Brown 0, 127, 0, out_tlv), 266f2644a2cSMark Brown SOC_DOUBLE_R("Speaker Playback ZC Switch", WM8960_LOUT2, WM8960_ROUT2, 267f2644a2cSMark Brown 7, 1, 0), 268f2644a2cSMark Brown SOC_SINGLE("Speaker DC Volume", WM8960_CLASSD3, 3, 5, 0), 269f2644a2cSMark Brown SOC_SINGLE("Speaker AC Volume", WM8960_CLASSD3, 0, 5, 0), 270f2644a2cSMark Brown 271f2644a2cSMark Brown SOC_SINGLE("PCM Playback -6dB Switch", WM8960_DACCTL1, 7, 1, 0), 2724faaa8d9SMark Brown SOC_ENUM("ADC Polarity", wm8960_enum[0]), 273f2644a2cSMark Brown SOC_SINGLE("ADC High Pass Filter Switch", WM8960_DACCTL1, 0, 1, 0), 274f2644a2cSMark Brown 275a077e81eSZidan Wang SOC_ENUM("DAC Polarity", wm8960_enum[1]), 276afd6d36aSMark Brown SOC_SINGLE_BOOL_EXT("DAC Deemphasis Switch", 0, 277afd6d36aSMark Brown wm8960_get_deemph, wm8960_put_deemph), 278f2644a2cSMark Brown 2794faaa8d9SMark Brown SOC_ENUM("3D Filter Upper Cut-Off", wm8960_enum[2]), 2804faaa8d9SMark Brown SOC_ENUM("3D Filter Lower Cut-Off", wm8960_enum[3]), 281f2644a2cSMark Brown SOC_SINGLE("3D Volume", WM8960_3D, 1, 15, 0), 282f2644a2cSMark Brown SOC_SINGLE("3D Switch", WM8960_3D, 0, 1, 0), 283f2644a2cSMark Brown 2844faaa8d9SMark Brown SOC_ENUM("ALC Function", wm8960_enum[4]), 285f2644a2cSMark Brown SOC_SINGLE("ALC Max Gain", WM8960_ALC1, 4, 7, 0), 286f2644a2cSMark Brown SOC_SINGLE("ALC Target", WM8960_ALC1, 0, 15, 1), 287f2644a2cSMark Brown SOC_SINGLE("ALC Min Gain", WM8960_ALC2, 4, 7, 0), 288f2644a2cSMark Brown SOC_SINGLE("ALC Hold Time", WM8960_ALC2, 0, 15, 0), 2894faaa8d9SMark Brown SOC_ENUM("ALC Mode", wm8960_enum[5]), 290f2644a2cSMark Brown SOC_SINGLE("ALC Decay", WM8960_ALC3, 4, 15, 0), 291f2644a2cSMark Brown SOC_SINGLE("ALC Attack", WM8960_ALC3, 0, 15, 0), 292f2644a2cSMark Brown 293f2644a2cSMark Brown SOC_SINGLE("Noise Gate Threshold", WM8960_NOISEG, 3, 31, 0), 294f2644a2cSMark Brown SOC_SINGLE("Noise Gate Switch", WM8960_NOISEG, 0, 1, 0), 295f2644a2cSMark Brown 296c324aac0SMa Haijun SOC_DOUBLE_R_TLV("ADC PCM Capture Volume", WM8960_LADC, WM8960_RADC, 297c324aac0SMa Haijun 0, 255, 0, adc_tlv), 298f2644a2cSMark Brown 299f2644a2cSMark Brown SOC_SINGLE_TLV("Left Output Mixer Boost Bypass Volume", 300f2644a2cSMark Brown WM8960_BYPASS1, 4, 7, 1, bypass_tlv), 301f2644a2cSMark Brown SOC_SINGLE_TLV("Left Output Mixer LINPUT3 Volume", 302f2644a2cSMark Brown WM8960_LOUTMIX, 4, 7, 1, bypass_tlv), 303f2644a2cSMark Brown SOC_SINGLE_TLV("Right Output Mixer Boost Bypass Volume", 304f2644a2cSMark Brown WM8960_BYPASS2, 4, 7, 1, bypass_tlv), 305f2644a2cSMark Brown SOC_SINGLE_TLV("Right Output Mixer RINPUT3 Volume", 306f2644a2cSMark Brown WM8960_ROUTMIX, 4, 7, 1, bypass_tlv), 3074a5893cfSZidan Wang 3084a5893cfSZidan Wang SOC_ENUM("ADC Data Output Select", wm8960_enum[6]), 309defbf708SZidan Wang SOC_ENUM("DAC Mono Mix", wm8960_enum[7]), 310f2644a2cSMark Brown }; 311f2644a2cSMark Brown 312f2644a2cSMark Brown static const struct snd_kcontrol_new wm8960_lin_boost[] = { 313f2644a2cSMark Brown SOC_DAPM_SINGLE("LINPUT2 Switch", WM8960_LINPATH, 6, 1, 0), 314f2644a2cSMark Brown SOC_DAPM_SINGLE("LINPUT3 Switch", WM8960_LINPATH, 7, 1, 0), 315f2644a2cSMark Brown SOC_DAPM_SINGLE("LINPUT1 Switch", WM8960_LINPATH, 8, 1, 0), 316f2644a2cSMark Brown }; 317f2644a2cSMark Brown 318f2644a2cSMark Brown static const struct snd_kcontrol_new wm8960_lin[] = { 319f2644a2cSMark Brown SOC_DAPM_SINGLE("Boost Switch", WM8960_LINPATH, 3, 1, 0), 320f2644a2cSMark Brown }; 321f2644a2cSMark Brown 322f2644a2cSMark Brown static const struct snd_kcontrol_new wm8960_rin_boost[] = { 323f2644a2cSMark Brown SOC_DAPM_SINGLE("RINPUT2 Switch", WM8960_RINPATH, 6, 1, 0), 324f2644a2cSMark Brown SOC_DAPM_SINGLE("RINPUT3 Switch", WM8960_RINPATH, 7, 1, 0), 325f2644a2cSMark Brown SOC_DAPM_SINGLE("RINPUT1 Switch", WM8960_RINPATH, 8, 1, 0), 326f2644a2cSMark Brown }; 327f2644a2cSMark Brown 328f2644a2cSMark Brown static const struct snd_kcontrol_new wm8960_rin[] = { 329f2644a2cSMark Brown SOC_DAPM_SINGLE("Boost Switch", WM8960_RINPATH, 3, 1, 0), 330f2644a2cSMark Brown }; 331f2644a2cSMark Brown 332f2644a2cSMark Brown static const struct snd_kcontrol_new wm8960_loutput_mixer[] = { 333f2644a2cSMark Brown SOC_DAPM_SINGLE("PCM Playback Switch", WM8960_LOUTMIX, 8, 1, 0), 334f2644a2cSMark Brown SOC_DAPM_SINGLE("LINPUT3 Switch", WM8960_LOUTMIX, 7, 1, 0), 335f2644a2cSMark Brown SOC_DAPM_SINGLE("Boost Bypass Switch", WM8960_BYPASS1, 7, 1, 0), 336f2644a2cSMark Brown }; 337f2644a2cSMark Brown 338f2644a2cSMark Brown static const struct snd_kcontrol_new wm8960_routput_mixer[] = { 339f2644a2cSMark Brown SOC_DAPM_SINGLE("PCM Playback Switch", WM8960_ROUTMIX, 8, 1, 0), 340f2644a2cSMark Brown SOC_DAPM_SINGLE("RINPUT3 Switch", WM8960_ROUTMIX, 7, 1, 0), 341f2644a2cSMark Brown SOC_DAPM_SINGLE("Boost Bypass Switch", WM8960_BYPASS2, 7, 1, 0), 342f2644a2cSMark Brown }; 343f2644a2cSMark Brown 344f2644a2cSMark Brown static const struct snd_kcontrol_new wm8960_mono_out[] = { 345f2644a2cSMark Brown SOC_DAPM_SINGLE("Left Switch", WM8960_MONOMIX1, 7, 1, 0), 346f2644a2cSMark Brown SOC_DAPM_SINGLE("Right Switch", WM8960_MONOMIX2, 7, 1, 0), 347f2644a2cSMark Brown }; 348f2644a2cSMark Brown 349f2644a2cSMark Brown static const struct snd_soc_dapm_widget wm8960_dapm_widgets[] = { 350f2644a2cSMark Brown SND_SOC_DAPM_INPUT("LINPUT1"), 351f2644a2cSMark Brown SND_SOC_DAPM_INPUT("RINPUT1"), 352f2644a2cSMark Brown SND_SOC_DAPM_INPUT("LINPUT2"), 353f2644a2cSMark Brown SND_SOC_DAPM_INPUT("RINPUT2"), 354f2644a2cSMark Brown SND_SOC_DAPM_INPUT("LINPUT3"), 355f2644a2cSMark Brown SND_SOC_DAPM_INPUT("RINPUT3"), 356f2644a2cSMark Brown 357187774cbSMark Brown SND_SOC_DAPM_SUPPLY("MICB", WM8960_POWER1, 1, 0, NULL, 0), 358f2644a2cSMark Brown 359f2644a2cSMark Brown SND_SOC_DAPM_MIXER("Left Boost Mixer", WM8960_POWER1, 5, 0, 360f2644a2cSMark Brown wm8960_lin_boost, ARRAY_SIZE(wm8960_lin_boost)), 361f2644a2cSMark Brown SND_SOC_DAPM_MIXER("Right Boost Mixer", WM8960_POWER1, 4, 0, 362f2644a2cSMark Brown wm8960_rin_boost, ARRAY_SIZE(wm8960_rin_boost)), 363f2644a2cSMark Brown 364f2644a2cSMark Brown SND_SOC_DAPM_MIXER("Left Input Mixer", WM8960_POWER3, 5, 0, 365f2644a2cSMark Brown wm8960_lin, ARRAY_SIZE(wm8960_lin)), 366f2644a2cSMark Brown SND_SOC_DAPM_MIXER("Right Input Mixer", WM8960_POWER3, 4, 0, 367f2644a2cSMark Brown wm8960_rin, ARRAY_SIZE(wm8960_rin)), 368f2644a2cSMark Brown 36944426de4SMark Brown SND_SOC_DAPM_ADC("Left ADC", "Capture", WM8960_POWER1, 3, 0), 37044426de4SMark Brown SND_SOC_DAPM_ADC("Right ADC", "Capture", WM8960_POWER1, 2, 0), 371f2644a2cSMark Brown 372f2644a2cSMark Brown SND_SOC_DAPM_DAC("Left DAC", "Playback", WM8960_POWER2, 8, 0), 373f2644a2cSMark Brown SND_SOC_DAPM_DAC("Right DAC", "Playback", WM8960_POWER2, 7, 0), 374f2644a2cSMark Brown 375f2644a2cSMark Brown SND_SOC_DAPM_MIXER("Left Output Mixer", WM8960_POWER3, 3, 0, 376f2644a2cSMark Brown &wm8960_loutput_mixer[0], 377f2644a2cSMark Brown ARRAY_SIZE(wm8960_loutput_mixer)), 378f2644a2cSMark Brown SND_SOC_DAPM_MIXER("Right Output Mixer", WM8960_POWER3, 2, 0, 379f2644a2cSMark Brown &wm8960_routput_mixer[0], 380f2644a2cSMark Brown ARRAY_SIZE(wm8960_routput_mixer)), 381f2644a2cSMark Brown 382f2644a2cSMark Brown SND_SOC_DAPM_PGA("LOUT1 PGA", WM8960_POWER2, 6, 0, NULL, 0), 383f2644a2cSMark Brown SND_SOC_DAPM_PGA("ROUT1 PGA", WM8960_POWER2, 5, 0, NULL, 0), 384f2644a2cSMark Brown 385f2644a2cSMark Brown SND_SOC_DAPM_PGA("Left Speaker PGA", WM8960_POWER2, 4, 0, NULL, 0), 386f2644a2cSMark Brown SND_SOC_DAPM_PGA("Right Speaker PGA", WM8960_POWER2, 3, 0, NULL, 0), 387f2644a2cSMark Brown 388f2644a2cSMark Brown SND_SOC_DAPM_PGA("Right Speaker Output", WM8960_CLASSD1, 7, 0, NULL, 0), 389f2644a2cSMark Brown SND_SOC_DAPM_PGA("Left Speaker Output", WM8960_CLASSD1, 6, 0, NULL, 0), 390f2644a2cSMark Brown 391f2644a2cSMark Brown SND_SOC_DAPM_OUTPUT("SPK_LP"), 392f2644a2cSMark Brown SND_SOC_DAPM_OUTPUT("SPK_LN"), 393f2644a2cSMark Brown SND_SOC_DAPM_OUTPUT("HP_L"), 394f2644a2cSMark Brown SND_SOC_DAPM_OUTPUT("HP_R"), 395f2644a2cSMark Brown SND_SOC_DAPM_OUTPUT("SPK_RP"), 396f2644a2cSMark Brown SND_SOC_DAPM_OUTPUT("SPK_RN"), 397f2644a2cSMark Brown SND_SOC_DAPM_OUTPUT("OUT3"), 398f2644a2cSMark Brown }; 399f2644a2cSMark Brown 400913d7b4cSMark Brown static const struct snd_soc_dapm_widget wm8960_dapm_widgets_out3[] = { 401913d7b4cSMark Brown SND_SOC_DAPM_MIXER("Mono Output Mixer", WM8960_POWER2, 1, 0, 402913d7b4cSMark Brown &wm8960_mono_out[0], 403913d7b4cSMark Brown ARRAY_SIZE(wm8960_mono_out)), 404913d7b4cSMark Brown }; 405913d7b4cSMark Brown 406913d7b4cSMark Brown /* Represent OUT3 as a PGA so that it gets turned on with LOUT1/ROUT1 */ 407913d7b4cSMark Brown static const struct snd_soc_dapm_widget wm8960_dapm_widgets_capless[] = { 408913d7b4cSMark Brown SND_SOC_DAPM_PGA("OUT3 VMID", WM8960_POWER2, 1, 0, NULL, 0), 409913d7b4cSMark Brown }; 410913d7b4cSMark Brown 411f2644a2cSMark Brown static const struct snd_soc_dapm_route audio_paths[] = { 412f2644a2cSMark Brown { "Left Boost Mixer", "LINPUT1 Switch", "LINPUT1" }, 413f2644a2cSMark Brown { "Left Boost Mixer", "LINPUT2 Switch", "LINPUT2" }, 414f2644a2cSMark Brown { "Left Boost Mixer", "LINPUT3 Switch", "LINPUT3" }, 415f2644a2cSMark Brown 4162d4a3260SZidan Wang { "Left Input Mixer", "Boost Switch", "Left Boost Mixer" }, 4172d4a3260SZidan Wang { "Left Input Mixer", "Boost Switch", "LINPUT1" }, /* Really Boost Switch */ 418f2644a2cSMark Brown { "Left Input Mixer", NULL, "LINPUT2" }, 419f2644a2cSMark Brown { "Left Input Mixer", NULL, "LINPUT3" }, 420f2644a2cSMark Brown 421f2644a2cSMark Brown { "Right Boost Mixer", "RINPUT1 Switch", "RINPUT1" }, 422f2644a2cSMark Brown { "Right Boost Mixer", "RINPUT2 Switch", "RINPUT2" }, 423f2644a2cSMark Brown { "Right Boost Mixer", "RINPUT3 Switch", "RINPUT3" }, 424f2644a2cSMark Brown 4252d4a3260SZidan Wang { "Right Input Mixer", "Boost Switch", "Right Boost Mixer" }, 4262d4a3260SZidan Wang { "Right Input Mixer", "Boost Switch", "RINPUT1" }, /* Really Boost Switch */ 427f2644a2cSMark Brown { "Right Input Mixer", NULL, "RINPUT2" }, 42885e36a1fSZidan Wang { "Right Input Mixer", NULL, "RINPUT3" }, 429f2644a2cSMark Brown 430f2644a2cSMark Brown { "Left ADC", NULL, "Left Input Mixer" }, 431f2644a2cSMark Brown { "Right ADC", NULL, "Right Input Mixer" }, 432f2644a2cSMark Brown 433f2644a2cSMark Brown { "Left Output Mixer", "LINPUT3 Switch", "LINPUT3" }, 434f2644a2cSMark Brown { "Left Output Mixer", "Boost Bypass Switch", "Left Boost Mixer" }, 435f2644a2cSMark Brown { "Left Output Mixer", "PCM Playback Switch", "Left DAC" }, 436f2644a2cSMark Brown 437f2644a2cSMark Brown { "Right Output Mixer", "RINPUT3 Switch", "RINPUT3" }, 438f2644a2cSMark Brown { "Right Output Mixer", "Boost Bypass Switch", "Right Boost Mixer" }, 439f2644a2cSMark Brown { "Right Output Mixer", "PCM Playback Switch", "Right DAC" }, 440f2644a2cSMark Brown 441f2644a2cSMark Brown { "LOUT1 PGA", NULL, "Left Output Mixer" }, 442f2644a2cSMark Brown { "ROUT1 PGA", NULL, "Right Output Mixer" }, 443f2644a2cSMark Brown 444f2644a2cSMark Brown { "HP_L", NULL, "LOUT1 PGA" }, 445f2644a2cSMark Brown { "HP_R", NULL, "ROUT1 PGA" }, 446f2644a2cSMark Brown 447f2644a2cSMark Brown { "Left Speaker PGA", NULL, "Left Output Mixer" }, 448f2644a2cSMark Brown { "Right Speaker PGA", NULL, "Right Output Mixer" }, 449f2644a2cSMark Brown 450f2644a2cSMark Brown { "Left Speaker Output", NULL, "Left Speaker PGA" }, 451f2644a2cSMark Brown { "Right Speaker Output", NULL, "Right Speaker PGA" }, 452f2644a2cSMark Brown 453f2644a2cSMark Brown { "SPK_LN", NULL, "Left Speaker Output" }, 454f2644a2cSMark Brown { "SPK_LP", NULL, "Left Speaker Output" }, 455f2644a2cSMark Brown { "SPK_RN", NULL, "Right Speaker Output" }, 456f2644a2cSMark Brown { "SPK_RP", NULL, "Right Speaker Output" }, 457913d7b4cSMark Brown }; 458913d7b4cSMark Brown 459913d7b4cSMark Brown static const struct snd_soc_dapm_route audio_paths_out3[] = { 460913d7b4cSMark Brown { "Mono Output Mixer", "Left Switch", "Left Output Mixer" }, 461913d7b4cSMark Brown { "Mono Output Mixer", "Right Switch", "Right Output Mixer" }, 462f2644a2cSMark Brown 463f2644a2cSMark Brown { "OUT3", NULL, "Mono Output Mixer", } 464f2644a2cSMark Brown }; 465f2644a2cSMark Brown 466913d7b4cSMark Brown static const struct snd_soc_dapm_route audio_paths_capless[] = { 467913d7b4cSMark Brown { "HP_L", NULL, "OUT3 VMID" }, 468913d7b4cSMark Brown { "HP_R", NULL, "OUT3 VMID" }, 469913d7b4cSMark Brown 470913d7b4cSMark Brown { "OUT3 VMID", NULL, "Left Output Mixer" }, 471913d7b4cSMark Brown { "OUT3 VMID", NULL, "Right Output Mixer" }, 472913d7b4cSMark Brown }; 473913d7b4cSMark Brown 474e075fc17SKuninori Morimoto static int wm8960_add_widgets(struct snd_soc_component *component) 475f2644a2cSMark Brown { 476e075fc17SKuninori Morimoto struct wm8960_priv *wm8960 = snd_soc_component_get_drvdata(component); 477e2280c90SZidan Wang struct wm8960_data *pdata = &wm8960->pdata; 478e075fc17SKuninori Morimoto struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); 479913d7b4cSMark Brown struct snd_soc_dapm_widget *w; 480913d7b4cSMark Brown 481ce6120ccSLiam Girdwood snd_soc_dapm_new_controls(dapm, wm8960_dapm_widgets, 482f2644a2cSMark Brown ARRAY_SIZE(wm8960_dapm_widgets)); 483f2644a2cSMark Brown 484ce6120ccSLiam Girdwood snd_soc_dapm_add_routes(dapm, audio_paths, ARRAY_SIZE(audio_paths)); 485f2644a2cSMark Brown 486913d7b4cSMark Brown /* In capless mode OUT3 is used to provide VMID for the 487913d7b4cSMark Brown * headphone outputs, otherwise it is used as a mono mixer. 488913d7b4cSMark Brown */ 489913d7b4cSMark Brown if (pdata && pdata->capless) { 490ce6120ccSLiam Girdwood snd_soc_dapm_new_controls(dapm, wm8960_dapm_widgets_capless, 491913d7b4cSMark Brown ARRAY_SIZE(wm8960_dapm_widgets_capless)); 492913d7b4cSMark Brown 493ce6120ccSLiam Girdwood snd_soc_dapm_add_routes(dapm, audio_paths_capless, 494913d7b4cSMark Brown ARRAY_SIZE(audio_paths_capless)); 495913d7b4cSMark Brown } else { 496ce6120ccSLiam Girdwood snd_soc_dapm_new_controls(dapm, wm8960_dapm_widgets_out3, 497913d7b4cSMark Brown ARRAY_SIZE(wm8960_dapm_widgets_out3)); 498913d7b4cSMark Brown 499ce6120ccSLiam Girdwood snd_soc_dapm_add_routes(dapm, audio_paths_out3, 500913d7b4cSMark Brown ARRAY_SIZE(audio_paths_out3)); 501913d7b4cSMark Brown } 502913d7b4cSMark Brown 503913d7b4cSMark Brown /* We need to power up the headphone output stage out of 504913d7b4cSMark Brown * sequence for capless mode. To save scanning the widget 505913d7b4cSMark Brown * list each time to find the desired power state do so now 506913d7b4cSMark Brown * and save the result. 507913d7b4cSMark Brown */ 508e075fc17SKuninori Morimoto list_for_each_entry(w, &component->card->widgets, list) { 50993f32f53SLars-Peter Clausen if (w->dapm != dapm) 51097c866deSJarkko Nikula continue; 511913d7b4cSMark Brown if (strcmp(w->name, "LOUT1 PGA") == 0) 512913d7b4cSMark Brown wm8960->lout1 = w; 513913d7b4cSMark Brown if (strcmp(w->name, "ROUT1 PGA") == 0) 514913d7b4cSMark Brown wm8960->rout1 = w; 515913d7b4cSMark Brown if (strcmp(w->name, "OUT3 VMID") == 0) 516913d7b4cSMark Brown wm8960->out3 = w; 517913d7b4cSMark Brown } 518913d7b4cSMark Brown 519f2644a2cSMark Brown return 0; 520f2644a2cSMark Brown } 521f2644a2cSMark Brown 522f2644a2cSMark Brown static int wm8960_set_dai_fmt(struct snd_soc_dai *codec_dai, 523f2644a2cSMark Brown unsigned int fmt) 524f2644a2cSMark Brown { 525e075fc17SKuninori Morimoto struct snd_soc_component *component = codec_dai->component; 526f2644a2cSMark Brown u16 iface = 0; 527f2644a2cSMark Brown 528f2644a2cSMark Brown /* set master/slave audio interface */ 529f2644a2cSMark Brown switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { 530f2644a2cSMark Brown case SND_SOC_DAIFMT_CBM_CFM: 531f2644a2cSMark Brown iface |= 0x0040; 532f2644a2cSMark Brown break; 533f2644a2cSMark Brown case SND_SOC_DAIFMT_CBS_CFS: 534f2644a2cSMark Brown break; 535f2644a2cSMark Brown default: 536f2644a2cSMark Brown return -EINVAL; 537f2644a2cSMark Brown } 538f2644a2cSMark Brown 539f2644a2cSMark Brown /* interface format */ 540f2644a2cSMark Brown switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 541f2644a2cSMark Brown case SND_SOC_DAIFMT_I2S: 542f2644a2cSMark Brown iface |= 0x0002; 543f2644a2cSMark Brown break; 544f2644a2cSMark Brown case SND_SOC_DAIFMT_RIGHT_J: 545f2644a2cSMark Brown break; 546f2644a2cSMark Brown case SND_SOC_DAIFMT_LEFT_J: 547f2644a2cSMark Brown iface |= 0x0001; 548f2644a2cSMark Brown break; 549f2644a2cSMark Brown case SND_SOC_DAIFMT_DSP_A: 550f2644a2cSMark Brown iface |= 0x0003; 551f2644a2cSMark Brown break; 552f2644a2cSMark Brown case SND_SOC_DAIFMT_DSP_B: 553f2644a2cSMark Brown iface |= 0x0013; 554f2644a2cSMark Brown break; 555f2644a2cSMark Brown default: 556f2644a2cSMark Brown return -EINVAL; 557f2644a2cSMark Brown } 558f2644a2cSMark Brown 559f2644a2cSMark Brown /* clock inversion */ 560f2644a2cSMark Brown switch (fmt & SND_SOC_DAIFMT_INV_MASK) { 561f2644a2cSMark Brown case SND_SOC_DAIFMT_NB_NF: 562f2644a2cSMark Brown break; 563f2644a2cSMark Brown case SND_SOC_DAIFMT_IB_IF: 564f2644a2cSMark Brown iface |= 0x0090; 565f2644a2cSMark Brown break; 566f2644a2cSMark Brown case SND_SOC_DAIFMT_IB_NF: 567f2644a2cSMark Brown iface |= 0x0080; 568f2644a2cSMark Brown break; 569f2644a2cSMark Brown case SND_SOC_DAIFMT_NB_IF: 570f2644a2cSMark Brown iface |= 0x0010; 571f2644a2cSMark Brown break; 572f2644a2cSMark Brown default: 573f2644a2cSMark Brown return -EINVAL; 574f2644a2cSMark Brown } 575f2644a2cSMark Brown 576f2644a2cSMark Brown /* set iface */ 577e075fc17SKuninori Morimoto snd_soc_component_write(component, WM8960_IFACE1, iface); 578f2644a2cSMark Brown return 0; 579f2644a2cSMark Brown } 580f2644a2cSMark Brown 581db059c0fSMark Brown static struct { 582db059c0fSMark Brown int rate; 583db059c0fSMark Brown unsigned int val; 584db059c0fSMark Brown } alc_rates[] = { 585db059c0fSMark Brown { 48000, 0 }, 586db059c0fSMark Brown { 44100, 0 }, 587db059c0fSMark Brown { 32000, 1 }, 588db059c0fSMark Brown { 22050, 2 }, 589db059c0fSMark Brown { 24000, 2 }, 590db059c0fSMark Brown { 16000, 3 }, 59122ee76daSZidan Wang { 11025, 4 }, 592db059c0fSMark Brown { 12000, 4 }, 593db059c0fSMark Brown { 8000, 5 }, 594db059c0fSMark Brown }; 595db059c0fSMark Brown 5963176bf2dSZidan Wang /* -1 for reserved value */ 5973176bf2dSZidan Wang static const int sysclk_divs[] = { 1, -1, 2, -1 }; 5983176bf2dSZidan Wang 5990e50b51aSZidan Wang /* Multiply 256 for internal 256 div */ 6000e50b51aSZidan Wang static const int dac_divs[] = { 256, 384, 512, 768, 1024, 1408, 1536 }; 6010e50b51aSZidan Wang 6020e50b51aSZidan Wang /* Multiply 10 to eliminate decimials */ 6030e50b51aSZidan Wang static const int bclk_divs[] = { 6040e50b51aSZidan Wang 10, 15, 20, 30, 40, 55, 60, 80, 110, 6050e50b51aSZidan Wang 120, 160, 220, 240, 320, 320, 320 6060e50b51aSZidan Wang }; 6070e50b51aSZidan Wang 6083ddc9721SDaniel Baluta /** 6093ddc9721SDaniel Baluta * wm8960_configure_sysclk - checks if there is a sysclk frequency available 6103ddc9721SDaniel Baluta * The sysclk must be chosen such that: 6113ddc9721SDaniel Baluta * - sysclk = MCLK / sysclk_divs 6123ddc9721SDaniel Baluta * - lrclk = sysclk / dac_divs 6133ddc9721SDaniel Baluta * - 10 * bclk = sysclk / bclk_divs 6143ddc9721SDaniel Baluta * 615419eac3cSPierre-Louis Bossart * @wm8960: codec private data 6163ddc9721SDaniel Baluta * @mclk: MCLK used to derive sysclk 6173ddc9721SDaniel Baluta * @sysclk_idx: sysclk_divs index for found sysclk 6183ddc9721SDaniel Baluta * @dac_idx: dac_divs index for found lrclk 6193ddc9721SDaniel Baluta * @bclk_idx: bclk_divs index for found bclk 6203ddc9721SDaniel Baluta * 6213ddc9721SDaniel Baluta * Returns: 6223ddc9721SDaniel Baluta * -1, in case no sysclk frequency available found 6233c01b9eeSDaniel Baluta * >=0, in case we could derive bclk and lrclk from sysclk using 6243c01b9eeSDaniel Baluta * (@sysclk_idx, @dac_idx, @bclk_idx) dividers 6253ddc9721SDaniel Baluta */ 6263ddc9721SDaniel Baluta static 6273ddc9721SDaniel Baluta int wm8960_configure_sysclk(struct wm8960_priv *wm8960, int mclk, 6283ddc9721SDaniel Baluta int *sysclk_idx, int *dac_idx, int *bclk_idx) 6293ddc9721SDaniel Baluta { 6303ddc9721SDaniel Baluta int sysclk, bclk, lrclk; 6313ddc9721SDaniel Baluta int i, j, k; 63299067c07SShengjiu Wang int diff; 6333c01b9eeSDaniel Baluta 6343c01b9eeSDaniel Baluta /* marker for no match */ 6353c01b9eeSDaniel Baluta *bclk_idx = -1; 6363ddc9721SDaniel Baluta 6373ddc9721SDaniel Baluta bclk = wm8960->bclk; 6383ddc9721SDaniel Baluta lrclk = wm8960->lrclk; 6393ddc9721SDaniel Baluta 6403ddc9721SDaniel Baluta /* check if the sysclk frequency is available. */ 6413ddc9721SDaniel Baluta for (i = 0; i < ARRAY_SIZE(sysclk_divs); ++i) { 6423ddc9721SDaniel Baluta if (sysclk_divs[i] == -1) 6433ddc9721SDaniel Baluta continue; 6443ddc9721SDaniel Baluta sysclk = mclk / sysclk_divs[i]; 6453ddc9721SDaniel Baluta for (j = 0; j < ARRAY_SIZE(dac_divs); ++j) { 6463ddc9721SDaniel Baluta if (sysclk != dac_divs[j] * lrclk) 6473ddc9721SDaniel Baluta continue; 6483ddc9721SDaniel Baluta for (k = 0; k < ARRAY_SIZE(bclk_divs); ++k) { 6493ddc9721SDaniel Baluta diff = sysclk - bclk * bclk_divs[k] / 10; 6503ddc9721SDaniel Baluta if (diff == 0) { 6513ddc9721SDaniel Baluta *sysclk_idx = i; 6523ddc9721SDaniel Baluta *dac_idx = j; 6533ddc9721SDaniel Baluta *bclk_idx = k; 6543ddc9721SDaniel Baluta break; 6553ddc9721SDaniel Baluta } 6563ddc9721SDaniel Baluta } 6573ddc9721SDaniel Baluta if (k != ARRAY_SIZE(bclk_divs)) 6583ddc9721SDaniel Baluta break; 6593ddc9721SDaniel Baluta } 6603ddc9721SDaniel Baluta if (j != ARRAY_SIZE(dac_divs)) 6613ddc9721SDaniel Baluta break; 6623ddc9721SDaniel Baluta } 6633c01b9eeSDaniel Baluta return *bclk_idx; 6643ddc9721SDaniel Baluta } 6653ddc9721SDaniel Baluta 66684fdc00dSDaniel Baluta /** 66784fdc00dSDaniel Baluta * wm8960_configure_pll - checks if there is a PLL out frequency available 66884fdc00dSDaniel Baluta * The PLL out frequency must be chosen such that: 66984fdc00dSDaniel Baluta * - sysclk = lrclk * dac_divs 67084fdc00dSDaniel Baluta * - freq_out = sysclk * sysclk_divs 67184fdc00dSDaniel Baluta * - 10 * sysclk = bclk * bclk_divs 67284fdc00dSDaniel Baluta * 67382bab889SDaniel Baluta * If we cannot find an exact match for (sysclk, lrclk, bclk) 67482bab889SDaniel Baluta * triplet, we relax the bclk such that bclk is chosen as the 67582bab889SDaniel Baluta * closest available frequency greater than expected bclk. 67682bab889SDaniel Baluta * 677e075fc17SKuninori Morimoto * @component: component structure 67884fdc00dSDaniel Baluta * @freq_in: input frequency used to derive freq out via PLL 67984fdc00dSDaniel Baluta * @sysclk_idx: sysclk_divs index for found sysclk 68084fdc00dSDaniel Baluta * @dac_idx: dac_divs index for found lrclk 68184fdc00dSDaniel Baluta * @bclk_idx: bclk_divs index for found bclk 68284fdc00dSDaniel Baluta * 68384fdc00dSDaniel Baluta * Returns: 68466772edaSDaniel Baluta * < 0, in case no PLL frequency out available was found 68584fdc00dSDaniel Baluta * >=0, in case we could derive bclk, lrclk, sysclk from PLL out using 68684fdc00dSDaniel Baluta * (@sysclk_idx, @dac_idx, @bclk_idx) dividers 68784fdc00dSDaniel Baluta */ 68884fdc00dSDaniel Baluta static 689e075fc17SKuninori Morimoto int wm8960_configure_pll(struct snd_soc_component *component, int freq_in, 69084fdc00dSDaniel Baluta int *sysclk_idx, int *dac_idx, int *bclk_idx) 69184fdc00dSDaniel Baluta { 692e075fc17SKuninori Morimoto struct wm8960_priv *wm8960 = snd_soc_component_get_drvdata(component); 69384fdc00dSDaniel Baluta int sysclk, bclk, lrclk, freq_out; 69482bab889SDaniel Baluta int diff, closest, best_freq_out; 69584fdc00dSDaniel Baluta int i, j, k; 69684fdc00dSDaniel Baluta 69784fdc00dSDaniel Baluta bclk = wm8960->bclk; 69884fdc00dSDaniel Baluta lrclk = wm8960->lrclk; 69982bab889SDaniel Baluta closest = freq_in; 70084fdc00dSDaniel Baluta 70182bab889SDaniel Baluta best_freq_out = -EINVAL; 70266772edaSDaniel Baluta *sysclk_idx = *dac_idx = *bclk_idx = -1; 70384fdc00dSDaniel Baluta 70416b82e75SShengjiu Wang /* 70516b82e75SShengjiu Wang * From Datasheet, the PLL performs best when f2 is between 70616b82e75SShengjiu Wang * 90MHz and 100MHz, the desired sysclk output is 11.2896MHz 70716b82e75SShengjiu Wang * or 12.288MHz, then sysclkdiv = 2 is the best choice. 70816b82e75SShengjiu Wang * So search sysclk_divs from 2 to 1 other than from 1 to 2. 70916b82e75SShengjiu Wang */ 71016b82e75SShengjiu Wang for (i = ARRAY_SIZE(sysclk_divs) - 1; i >= 0; --i) { 71184fdc00dSDaniel Baluta if (sysclk_divs[i] == -1) 71284fdc00dSDaniel Baluta continue; 71384fdc00dSDaniel Baluta for (j = 0; j < ARRAY_SIZE(dac_divs); ++j) { 71484fdc00dSDaniel Baluta sysclk = lrclk * dac_divs[j]; 71584fdc00dSDaniel Baluta freq_out = sysclk * sysclk_divs[i]; 71684fdc00dSDaniel Baluta 71784fdc00dSDaniel Baluta for (k = 0; k < ARRAY_SIZE(bclk_divs); ++k) { 71884fdc00dSDaniel Baluta if (!is_pll_freq_available(freq_in, freq_out)) 71984fdc00dSDaniel Baluta continue; 72084fdc00dSDaniel Baluta 72184fdc00dSDaniel Baluta diff = sysclk - bclk * bclk_divs[k] / 10; 72284fdc00dSDaniel Baluta if (diff == 0) { 72384fdc00dSDaniel Baluta *sysclk_idx = i; 72484fdc00dSDaniel Baluta *dac_idx = j; 72584fdc00dSDaniel Baluta *bclk_idx = k; 72666772edaSDaniel Baluta return freq_out; 72784fdc00dSDaniel Baluta } 72882bab889SDaniel Baluta if (diff > 0 && closest > diff) { 72982bab889SDaniel Baluta *sysclk_idx = i; 73082bab889SDaniel Baluta *dac_idx = j; 73182bab889SDaniel Baluta *bclk_idx = k; 73282bab889SDaniel Baluta closest = diff; 73382bab889SDaniel Baluta best_freq_out = freq_out; 73484fdc00dSDaniel Baluta } 73584fdc00dSDaniel Baluta } 73684fdc00dSDaniel Baluta } 73782bab889SDaniel Baluta } 73882bab889SDaniel Baluta 73982bab889SDaniel Baluta return best_freq_out; 74084fdc00dSDaniel Baluta } 741e075fc17SKuninori Morimoto static int wm8960_configure_clocking(struct snd_soc_component *component) 7420e50b51aSZidan Wang { 743e075fc17SKuninori Morimoto struct wm8960_priv *wm8960 = snd_soc_component_get_drvdata(component); 74484fdc00dSDaniel Baluta int freq_out, freq_in; 7456d75dfc3SKuninori Morimoto u16 iface1 = snd_soc_component_read(component, WM8960_IFACE1); 7463176bf2dSZidan Wang int i, j, k; 7473ddc9721SDaniel Baluta int ret; 7480e50b51aSZidan Wang 7496b9b546dSShengjiu Wang /* 7506b9b546dSShengjiu Wang * For Slave mode clocking should still be configured, 7516b9b546dSShengjiu Wang * so this if statement should be removed, but some platform 7526b9b546dSShengjiu Wang * may not work if the sysclk is not configured, to avoid such 7536b9b546dSShengjiu Wang * compatible issue, just add '!wm8960->sysclk' condition in 7546b9b546dSShengjiu Wang * this if statement. 7556b9b546dSShengjiu Wang */ 7566b9b546dSShengjiu Wang if (!(iface1 & (1 << 6)) && !wm8960->sysclk) { 7576b9b546dSShengjiu Wang dev_warn(component->dev, 7586b9b546dSShengjiu Wang "slave mode, but proceeding with no clock configuration\n"); 7593176bf2dSZidan Wang return 0; 7600e50b51aSZidan Wang } 7610e50b51aSZidan Wang 7623176bf2dSZidan Wang if (wm8960->clk_id != WM8960_SYSCLK_MCLK && !wm8960->freq_in) { 763e075fc17SKuninori Morimoto dev_err(component->dev, "No MCLK configured\n"); 7643176bf2dSZidan Wang return -EINVAL; 7650e50b51aSZidan Wang } 7660e50b51aSZidan Wang 7673176bf2dSZidan Wang freq_in = wm8960->freq_in; 7680e50b51aSZidan Wang /* 7693176bf2dSZidan Wang * If it's sysclk auto mode, check if the MCLK can provide sysclk or 7703176bf2dSZidan Wang * not. If MCLK can provide sysclk, using MCLK to provide sysclk 7713176bf2dSZidan Wang * directly. Otherwise, auto select a available pll out frequency 7723176bf2dSZidan Wang * and set PLL. 7730e50b51aSZidan Wang */ 7743176bf2dSZidan Wang if (wm8960->clk_id == WM8960_SYSCLK_AUTO) { 7753176bf2dSZidan Wang /* disable the PLL and using MCLK to provide sysclk */ 776e075fc17SKuninori Morimoto wm8960_set_pll(component, 0, 0); 7773176bf2dSZidan Wang freq_out = freq_in; 7783176bf2dSZidan Wang } else if (wm8960->sysclk) { 7793176bf2dSZidan Wang freq_out = wm8960->sysclk; 7803176bf2dSZidan Wang } else { 781e075fc17SKuninori Morimoto dev_err(component->dev, "No SYSCLK configured\n"); 7823176bf2dSZidan Wang return -EINVAL; 7833176bf2dSZidan Wang } 7843176bf2dSZidan Wang 7856bb74514SStuart Henderson if (wm8960->clk_id != WM8960_SYSCLK_PLL) { 7863ddc9721SDaniel Baluta ret = wm8960_configure_sysclk(wm8960, freq_out, &i, &j, &k); 7873c01b9eeSDaniel Baluta if (ret >= 0) { 7883176bf2dSZidan Wang goto configure_clock; 7893176bf2dSZidan Wang } else if (wm8960->clk_id != WM8960_SYSCLK_AUTO) { 790e075fc17SKuninori Morimoto dev_err(component->dev, "failed to configure clock\n"); 7913176bf2dSZidan Wang return -EINVAL; 7923176bf2dSZidan Wang } 7936bb74514SStuart Henderson } 7943176bf2dSZidan Wang 795e075fc17SKuninori Morimoto freq_out = wm8960_configure_pll(component, freq_in, &i, &j, &k); 79666772edaSDaniel Baluta if (freq_out < 0) { 797e075fc17SKuninori Morimoto dev_err(component->dev, "failed to configure clock via PLL\n"); 79866772edaSDaniel Baluta return freq_out; 7993176bf2dSZidan Wang } 800e075fc17SKuninori Morimoto wm8960_set_pll(component, freq_in, freq_out); 8013176bf2dSZidan Wang 8023176bf2dSZidan Wang configure_clock: 8033176bf2dSZidan Wang /* configure sysclk clock */ 804e075fc17SKuninori Morimoto snd_soc_component_update_bits(component, WM8960_CLOCK1, 3 << 1, i << 1); 8053176bf2dSZidan Wang 8063176bf2dSZidan Wang /* configure frame clock */ 807e075fc17SKuninori Morimoto snd_soc_component_update_bits(component, WM8960_CLOCK1, 0x7 << 3, j << 3); 808e075fc17SKuninori Morimoto snd_soc_component_update_bits(component, WM8960_CLOCK1, 0x7 << 6, j << 6); 8090e50b51aSZidan Wang 8100e50b51aSZidan Wang /* configure bit clock */ 811e075fc17SKuninori Morimoto snd_soc_component_update_bits(component, WM8960_CLOCK2, 0xf, k); 8123176bf2dSZidan Wang 8133176bf2dSZidan Wang return 0; 8140e50b51aSZidan Wang } 8150e50b51aSZidan Wang 816f2644a2cSMark Brown static int wm8960_hw_params(struct snd_pcm_substream *substream, 817f2644a2cSMark Brown struct snd_pcm_hw_params *params, 818f2644a2cSMark Brown struct snd_soc_dai *dai) 819f2644a2cSMark Brown { 820e075fc17SKuninori Morimoto struct snd_soc_component *component = dai->component; 821e075fc17SKuninori Morimoto struct wm8960_priv *wm8960 = snd_soc_component_get_drvdata(component); 8226d75dfc3SKuninori Morimoto u16 iface = snd_soc_component_read(component, WM8960_IFACE1) & 0xfff3; 8230e50b51aSZidan Wang bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; 824db059c0fSMark Brown int i; 825f2644a2cSMark Brown 8260e50b51aSZidan Wang wm8960->bclk = snd_soc_params_to_bclk(params); 8270e50b51aSZidan Wang if (params_channels(params) == 1) 8280e50b51aSZidan Wang wm8960->bclk *= 2; 8290e50b51aSZidan Wang 830f2644a2cSMark Brown /* bit size */ 83139e9cc46SMark Brown switch (params_width(params)) { 83239e9cc46SMark Brown case 16: 833f2644a2cSMark Brown break; 83439e9cc46SMark Brown case 20: 835f2644a2cSMark Brown iface |= 0x0004; 836f2644a2cSMark Brown break; 83739e9cc46SMark Brown case 24: 838f2644a2cSMark Brown iface |= 0x0008; 839f2644a2cSMark Brown break; 8407a8c7867SZidan Wang case 32: 8417a8c7867SZidan Wang /* right justify mode does not support 32 word length */ 8427a8c7867SZidan Wang if ((iface & 0x3) != 0) { 8437a8c7867SZidan Wang iface |= 0x000c; 8447a8c7867SZidan Wang break; 8457a8c7867SZidan Wang } 8463e146b55SGustavo A. R. Silva fallthrough; 8474c2474c0STimur Tabi default: 848e075fc17SKuninori Morimoto dev_err(component->dev, "unsupported width %d\n", 84939e9cc46SMark Brown params_width(params)); 8504c2474c0STimur Tabi return -EINVAL; 851f2644a2cSMark Brown } 852f2644a2cSMark Brown 8533176bf2dSZidan Wang wm8960->lrclk = params_rate(params); 854afd6d36aSMark Brown /* Update filters for the new rate */ 8553176bf2dSZidan Wang if (tx) { 856e075fc17SKuninori Morimoto wm8960_set_deemph(component); 857db059c0fSMark Brown } else { 858db059c0fSMark Brown for (i = 0; i < ARRAY_SIZE(alc_rates); i++) 859db059c0fSMark Brown if (alc_rates[i].rate == params_rate(params)) 860e075fc17SKuninori Morimoto snd_soc_component_update_bits(component, 861db059c0fSMark Brown WM8960_ADDCTL3, 0x7, 862db059c0fSMark Brown alc_rates[i].val); 863afd6d36aSMark Brown } 864afd6d36aSMark Brown 865f2644a2cSMark Brown /* set iface */ 866e075fc17SKuninori Morimoto snd_soc_component_write(component, WM8960_IFACE1, iface); 8670e50b51aSZidan Wang 8683176bf2dSZidan Wang wm8960->is_stream_in_use[tx] = true; 8693176bf2dSZidan Wang 8701e060a45SShengjiu Wang if (!wm8960->is_stream_in_use[!tx]) 871e075fc17SKuninori Morimoto return wm8960_configure_clocking(component); 8723176bf2dSZidan Wang 8733176bf2dSZidan Wang return 0; 8743176bf2dSZidan Wang } 8753176bf2dSZidan Wang 8763176bf2dSZidan Wang static int wm8960_hw_free(struct snd_pcm_substream *substream, 8773176bf2dSZidan Wang struct snd_soc_dai *dai) 8783176bf2dSZidan Wang { 879e075fc17SKuninori Morimoto struct snd_soc_component *component = dai->component; 880e075fc17SKuninori Morimoto struct wm8960_priv *wm8960 = snd_soc_component_get_drvdata(component); 8813176bf2dSZidan Wang bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; 8823176bf2dSZidan Wang 8833176bf2dSZidan Wang wm8960->is_stream_in_use[tx] = false; 8840e50b51aSZidan Wang 885f2644a2cSMark Brown return 0; 886f2644a2cSMark Brown } 887f2644a2cSMark Brown 88826d3c16eSKuninori Morimoto static int wm8960_mute(struct snd_soc_dai *dai, int mute, int direction) 889f2644a2cSMark Brown { 890e075fc17SKuninori Morimoto struct snd_soc_component *component = dai->component; 891f2644a2cSMark Brown 892f2644a2cSMark Brown if (mute) 893e075fc17SKuninori Morimoto snd_soc_component_update_bits(component, WM8960_DACCTL1, 0x8, 0x8); 894f2644a2cSMark Brown else 895e075fc17SKuninori Morimoto snd_soc_component_update_bits(component, WM8960_DACCTL1, 0x8, 0); 896f2644a2cSMark Brown return 0; 897f2644a2cSMark Brown } 898f2644a2cSMark Brown 899e075fc17SKuninori Morimoto static int wm8960_set_bias_level_out3(struct snd_soc_component *component, 900f2644a2cSMark Brown enum snd_soc_bias_level level) 901f2644a2cSMark Brown { 902e075fc17SKuninori Morimoto struct wm8960_priv *wm8960 = snd_soc_component_get_drvdata(component); 9036d75dfc3SKuninori Morimoto u16 pm2 = snd_soc_component_read(component, WM8960_POWER2); 90475aa8868SZidan Wang int ret; 9053c7a4c24SViorel Suman ktime_t tout; 9060ebe36c6SMark Brown 907f2644a2cSMark Brown switch (level) { 908f2644a2cSMark Brown case SND_SOC_BIAS_ON: 909f2644a2cSMark Brown break; 910f2644a2cSMark Brown 911f2644a2cSMark Brown case SND_SOC_BIAS_PREPARE: 912e075fc17SKuninori Morimoto switch (snd_soc_component_get_bias_level(component)) { 91375aa8868SZidan Wang case SND_SOC_BIAS_STANDBY: 91475aa8868SZidan Wang if (!IS_ERR(wm8960->mclk)) { 91575aa8868SZidan Wang ret = clk_prepare_enable(wm8960->mclk); 91675aa8868SZidan Wang if (ret) { 917e075fc17SKuninori Morimoto dev_err(component->dev, 91875aa8868SZidan Wang "Failed to enable MCLK: %d\n", 91975aa8868SZidan Wang ret); 92075aa8868SZidan Wang return ret; 92175aa8868SZidan Wang } 92275aa8868SZidan Wang } 92375aa8868SZidan Wang 924e075fc17SKuninori Morimoto ret = wm8960_configure_clocking(component); 9253176bf2dSZidan Wang if (ret) 9263176bf2dSZidan Wang return ret; 9273176bf2dSZidan Wang 928f2644a2cSMark Brown /* Set VMID to 2x50k */ 929e075fc17SKuninori Morimoto snd_soc_component_update_bits(component, WM8960_POWER1, 0x180, 0x80); 930f2644a2cSMark Brown break; 931f2644a2cSMark Brown 93275aa8868SZidan Wang case SND_SOC_BIAS_ON: 9333176bf2dSZidan Wang /* 9343176bf2dSZidan Wang * If it's sysclk auto mode, and the pll is enabled, 9353176bf2dSZidan Wang * disable the pll 9363176bf2dSZidan Wang */ 9373176bf2dSZidan Wang if (wm8960->clk_id == WM8960_SYSCLK_AUTO && (pm2 & 0x1)) 938e075fc17SKuninori Morimoto wm8960_set_pll(component, 0, 0); 9393176bf2dSZidan Wang 94075aa8868SZidan Wang if (!IS_ERR(wm8960->mclk)) 94175aa8868SZidan Wang clk_disable_unprepare(wm8960->mclk); 94275aa8868SZidan Wang break; 94375aa8868SZidan Wang 94475aa8868SZidan Wang default: 94575aa8868SZidan Wang break; 94675aa8868SZidan Wang } 94775aa8868SZidan Wang 94875aa8868SZidan Wang break; 94975aa8868SZidan Wang 950f2644a2cSMark Brown case SND_SOC_BIAS_STANDBY: 951e075fc17SKuninori Morimoto if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) { 9523c7a4c24SViorel Suman /* ensure discharge is complete */ 9533c7a4c24SViorel Suman tout = WM8960_DSCH_TOUT - ktime_ms_delta(ktime_get(), wm8960->dsch_start); 9543c7a4c24SViorel Suman if (tout > 0) 9553c7a4c24SViorel Suman msleep(tout); 9563c7a4c24SViorel Suman 9570ebe36c6SMark Brown regcache_sync(wm8960->regmap); 958bc45df2dSAxel Lin 959f2644a2cSMark Brown /* Enable anti-pop features */ 960e075fc17SKuninori Morimoto snd_soc_component_write(component, WM8960_APOP1, 961f2644a2cSMark Brown WM8960_POBCTRL | WM8960_SOFT_ST | 962f2644a2cSMark Brown WM8960_BUFDCOPEN | WM8960_BUFIOEN); 963f2644a2cSMark Brown 964f2644a2cSMark Brown /* Enable & ramp VMID at 2x50k */ 965e075fc17SKuninori Morimoto snd_soc_component_update_bits(component, WM8960_POWER1, 0x80, 0x80); 966f2644a2cSMark Brown msleep(100); 967f2644a2cSMark Brown 968f2644a2cSMark Brown /* Enable VREF */ 969e075fc17SKuninori Morimoto snd_soc_component_update_bits(component, WM8960_POWER1, WM8960_VREF, 97016b24881SAxel Lin WM8960_VREF); 971f2644a2cSMark Brown 972f2644a2cSMark Brown /* Disable anti-pop features */ 973e075fc17SKuninori Morimoto snd_soc_component_write(component, WM8960_APOP1, WM8960_BUFIOEN); 974f2644a2cSMark Brown } 975f2644a2cSMark Brown 976f2644a2cSMark Brown /* Set VMID to 2x250k */ 977e075fc17SKuninori Morimoto snd_soc_component_update_bits(component, WM8960_POWER1, 0x180, 0x100); 978f2644a2cSMark Brown break; 979f2644a2cSMark Brown 980f2644a2cSMark Brown case SND_SOC_BIAS_OFF: 981f2644a2cSMark Brown /* Enable anti-pop features */ 982e075fc17SKuninori Morimoto snd_soc_component_write(component, WM8960_APOP1, 983f2644a2cSMark Brown WM8960_POBCTRL | WM8960_SOFT_ST | 984f2644a2cSMark Brown WM8960_BUFDCOPEN | WM8960_BUFIOEN); 985f2644a2cSMark Brown 9863c7a4c24SViorel Suman /* Disable VMID and VREF, mark discharge */ 987e075fc17SKuninori Morimoto snd_soc_component_write(component, WM8960_POWER1, 0); 9883c7a4c24SViorel Suman wm8960->dsch_start = ktime_get(); 989913d7b4cSMark Brown break; 990913d7b4cSMark Brown } 991f2644a2cSMark Brown 992913d7b4cSMark Brown return 0; 993913d7b4cSMark Brown } 994913d7b4cSMark Brown 995e075fc17SKuninori Morimoto static int wm8960_set_bias_level_capless(struct snd_soc_component *component, 996913d7b4cSMark Brown enum snd_soc_bias_level level) 997913d7b4cSMark Brown { 998e075fc17SKuninori Morimoto struct wm8960_priv *wm8960 = snd_soc_component_get_drvdata(component); 9996d75dfc3SKuninori Morimoto u16 pm2 = snd_soc_component_read(component, WM8960_POWER2); 100075aa8868SZidan Wang int reg, ret; 1001913d7b4cSMark Brown 1002913d7b4cSMark Brown switch (level) { 1003913d7b4cSMark Brown case SND_SOC_BIAS_ON: 1004913d7b4cSMark Brown break; 1005913d7b4cSMark Brown 1006913d7b4cSMark Brown case SND_SOC_BIAS_PREPARE: 1007e075fc17SKuninori Morimoto switch (snd_soc_component_get_bias_level(component)) { 1008913d7b4cSMark Brown case SND_SOC_BIAS_STANDBY: 1009913d7b4cSMark Brown /* Enable anti pop mode */ 1010e075fc17SKuninori Morimoto snd_soc_component_update_bits(component, WM8960_APOP1, 1011913d7b4cSMark Brown WM8960_POBCTRL | WM8960_SOFT_ST | 1012913d7b4cSMark Brown WM8960_BUFDCOPEN, 1013913d7b4cSMark Brown WM8960_POBCTRL | WM8960_SOFT_ST | 1014913d7b4cSMark Brown WM8960_BUFDCOPEN); 1015913d7b4cSMark Brown 1016913d7b4cSMark Brown /* Enable LOUT1, ROUT1 and OUT3 if they're enabled */ 1017913d7b4cSMark Brown reg = 0; 1018913d7b4cSMark Brown if (wm8960->lout1 && wm8960->lout1->power) 1019913d7b4cSMark Brown reg |= WM8960_PWR2_LOUT1; 1020913d7b4cSMark Brown if (wm8960->rout1 && wm8960->rout1->power) 1021913d7b4cSMark Brown reg |= WM8960_PWR2_ROUT1; 1022913d7b4cSMark Brown if (wm8960->out3 && wm8960->out3->power) 1023913d7b4cSMark Brown reg |= WM8960_PWR2_OUT3; 1024e075fc17SKuninori Morimoto snd_soc_component_update_bits(component, WM8960_POWER2, 1025913d7b4cSMark Brown WM8960_PWR2_LOUT1 | 1026913d7b4cSMark Brown WM8960_PWR2_ROUT1 | 1027913d7b4cSMark Brown WM8960_PWR2_OUT3, reg); 1028913d7b4cSMark Brown 1029913d7b4cSMark Brown /* Enable VMID at 2*50k */ 1030e075fc17SKuninori Morimoto snd_soc_component_update_bits(component, WM8960_POWER1, 1031913d7b4cSMark Brown WM8960_VMID_MASK, 0x80); 1032913d7b4cSMark Brown 1033913d7b4cSMark Brown /* Ramp */ 1034913d7b4cSMark Brown msleep(100); 1035913d7b4cSMark Brown 1036913d7b4cSMark Brown /* Enable VREF */ 1037e075fc17SKuninori Morimoto snd_soc_component_update_bits(component, WM8960_POWER1, 1038913d7b4cSMark Brown WM8960_VREF, WM8960_VREF); 1039913d7b4cSMark Brown 1040913d7b4cSMark Brown msleep(100); 104175aa8868SZidan Wang 104275aa8868SZidan Wang if (!IS_ERR(wm8960->mclk)) { 104375aa8868SZidan Wang ret = clk_prepare_enable(wm8960->mclk); 104475aa8868SZidan Wang if (ret) { 1045e075fc17SKuninori Morimoto dev_err(component->dev, 104675aa8868SZidan Wang "Failed to enable MCLK: %d\n", 104775aa8868SZidan Wang ret); 104875aa8868SZidan Wang return ret; 104975aa8868SZidan Wang } 105075aa8868SZidan Wang } 10513176bf2dSZidan Wang 1052e075fc17SKuninori Morimoto ret = wm8960_configure_clocking(component); 10533176bf2dSZidan Wang if (ret) 10543176bf2dSZidan Wang return ret; 10553176bf2dSZidan Wang 1056913d7b4cSMark Brown break; 1057913d7b4cSMark Brown 1058913d7b4cSMark Brown case SND_SOC_BIAS_ON: 10593176bf2dSZidan Wang /* 10603176bf2dSZidan Wang * If it's sysclk auto mode, and the pll is enabled, 10613176bf2dSZidan Wang * disable the pll 10623176bf2dSZidan Wang */ 10633176bf2dSZidan Wang if (wm8960->clk_id == WM8960_SYSCLK_AUTO && (pm2 & 0x1)) 1064e075fc17SKuninori Morimoto wm8960_set_pll(component, 0, 0); 10653176bf2dSZidan Wang 106675aa8868SZidan Wang if (!IS_ERR(wm8960->mclk)) 106775aa8868SZidan Wang clk_disable_unprepare(wm8960->mclk); 106875aa8868SZidan Wang 1069913d7b4cSMark Brown /* Enable anti-pop mode */ 1070e075fc17SKuninori Morimoto snd_soc_component_update_bits(component, WM8960_APOP1, 1071913d7b4cSMark Brown WM8960_POBCTRL | WM8960_SOFT_ST | 1072913d7b4cSMark Brown WM8960_BUFDCOPEN, 1073913d7b4cSMark Brown WM8960_POBCTRL | WM8960_SOFT_ST | 1074913d7b4cSMark Brown WM8960_BUFDCOPEN); 1075913d7b4cSMark Brown 1076913d7b4cSMark Brown /* Disable VMID and VREF */ 1077e075fc17SKuninori Morimoto snd_soc_component_update_bits(component, WM8960_POWER1, 1078913d7b4cSMark Brown WM8960_VREF | WM8960_VMID_MASK, 0); 1079913d7b4cSMark Brown break; 1080913d7b4cSMark Brown 1081bc45df2dSAxel Lin case SND_SOC_BIAS_OFF: 10820ebe36c6SMark Brown regcache_sync(wm8960->regmap); 1083bc45df2dSAxel Lin break; 1084913d7b4cSMark Brown default: 1085913d7b4cSMark Brown break; 1086913d7b4cSMark Brown } 1087913d7b4cSMark Brown break; 1088913d7b4cSMark Brown 1089913d7b4cSMark Brown case SND_SOC_BIAS_STANDBY: 1090e075fc17SKuninori Morimoto switch (snd_soc_component_get_bias_level(component)) { 1091913d7b4cSMark Brown case SND_SOC_BIAS_PREPARE: 1092913d7b4cSMark Brown /* Disable HP discharge */ 1093e075fc17SKuninori Morimoto snd_soc_component_update_bits(component, WM8960_APOP2, 1094913d7b4cSMark Brown WM8960_DISOP | WM8960_DRES_MASK, 1095913d7b4cSMark Brown 0); 1096913d7b4cSMark Brown 1097913d7b4cSMark Brown /* Disable anti-pop features */ 1098e075fc17SKuninori Morimoto snd_soc_component_update_bits(component, WM8960_APOP1, 1099913d7b4cSMark Brown WM8960_POBCTRL | WM8960_SOFT_ST | 1100913d7b4cSMark Brown WM8960_BUFDCOPEN, 1101913d7b4cSMark Brown WM8960_POBCTRL | WM8960_SOFT_ST | 1102913d7b4cSMark Brown WM8960_BUFDCOPEN); 1103913d7b4cSMark Brown break; 1104913d7b4cSMark Brown 1105913d7b4cSMark Brown default: 1106913d7b4cSMark Brown break; 1107913d7b4cSMark Brown } 1108913d7b4cSMark Brown break; 1109913d7b4cSMark Brown 1110913d7b4cSMark Brown case SND_SOC_BIAS_OFF: 1111f2644a2cSMark Brown break; 1112f2644a2cSMark Brown } 1113f2644a2cSMark Brown 1114f2644a2cSMark Brown return 0; 1115f2644a2cSMark Brown } 1116f2644a2cSMark Brown 1117f2644a2cSMark Brown /* PLL divisors */ 1118f2644a2cSMark Brown struct _pll_div { 1119f2644a2cSMark Brown u32 pre_div:1; 1120f2644a2cSMark Brown u32 n:4; 1121f2644a2cSMark Brown u32 k:24; 1122f2644a2cSMark Brown }; 1123f2644a2cSMark Brown 11243176bf2dSZidan Wang static bool is_pll_freq_available(unsigned int source, unsigned int target) 11253176bf2dSZidan Wang { 11263176bf2dSZidan Wang unsigned int Ndiv; 11273176bf2dSZidan Wang 11283176bf2dSZidan Wang if (source == 0 || target == 0) 11293176bf2dSZidan Wang return false; 11303176bf2dSZidan Wang 11313176bf2dSZidan Wang /* Scale up target to PLL operating frequency */ 11323176bf2dSZidan Wang target *= 4; 11333176bf2dSZidan Wang Ndiv = target / source; 11343176bf2dSZidan Wang 11353176bf2dSZidan Wang if (Ndiv < 6) { 11363176bf2dSZidan Wang source >>= 1; 11373176bf2dSZidan Wang Ndiv = target / source; 11383176bf2dSZidan Wang } 11393176bf2dSZidan Wang 11403176bf2dSZidan Wang if ((Ndiv < 6) || (Ndiv > 12)) 11413176bf2dSZidan Wang return false; 11423176bf2dSZidan Wang 11433176bf2dSZidan Wang return true; 11443176bf2dSZidan Wang } 11453176bf2dSZidan Wang 1146f2644a2cSMark Brown /* The size in bits of the pll divide multiplied by 10 1147f2644a2cSMark Brown * to allow rounding later */ 1148f2644a2cSMark Brown #define FIXED_PLL_SIZE ((1 << 24) * 10) 1149f2644a2cSMark Brown 1150f2644a2cSMark Brown static int pll_factors(unsigned int source, unsigned int target, 1151f2644a2cSMark Brown struct _pll_div *pll_div) 1152f2644a2cSMark Brown { 1153f2644a2cSMark Brown unsigned long long Kpart; 1154f2644a2cSMark Brown unsigned int K, Ndiv, Nmod; 1155f2644a2cSMark Brown 1156f2644a2cSMark Brown pr_debug("WM8960 PLL: setting %dHz->%dHz\n", source, target); 1157f2644a2cSMark Brown 1158f2644a2cSMark Brown /* Scale up target to PLL operating frequency */ 1159f2644a2cSMark Brown target *= 4; 1160f2644a2cSMark Brown 1161f2644a2cSMark Brown Ndiv = target / source; 1162f2644a2cSMark Brown if (Ndiv < 6) { 1163f2644a2cSMark Brown source >>= 1; 1164f2644a2cSMark Brown pll_div->pre_div = 1; 1165f2644a2cSMark Brown Ndiv = target / source; 1166f2644a2cSMark Brown } else 1167f2644a2cSMark Brown pll_div->pre_div = 0; 1168f2644a2cSMark Brown 1169f2644a2cSMark Brown if ((Ndiv < 6) || (Ndiv > 12)) { 1170f2644a2cSMark Brown pr_err("WM8960 PLL: Unsupported N=%d\n", Ndiv); 1171f2644a2cSMark Brown return -EINVAL; 1172f2644a2cSMark Brown } 1173f2644a2cSMark Brown 1174f2644a2cSMark Brown pll_div->n = Ndiv; 1175f2644a2cSMark Brown Nmod = target % source; 1176f2644a2cSMark Brown Kpart = FIXED_PLL_SIZE * (long long)Nmod; 1177f2644a2cSMark Brown 1178f2644a2cSMark Brown do_div(Kpart, source); 1179f2644a2cSMark Brown 1180f2644a2cSMark Brown K = Kpart & 0xFFFFFFFF; 1181f2644a2cSMark Brown 1182f2644a2cSMark Brown /* Check if we need to round */ 1183f2644a2cSMark Brown if ((K % 10) >= 5) 1184f2644a2cSMark Brown K += 5; 1185f2644a2cSMark Brown 1186f2644a2cSMark Brown /* Move down to proper range now rounding is done */ 1187f2644a2cSMark Brown K /= 10; 1188f2644a2cSMark Brown 1189f2644a2cSMark Brown pll_div->k = K; 1190f2644a2cSMark Brown 1191f2644a2cSMark Brown pr_debug("WM8960 PLL: N=%x K=%x pre_div=%d\n", 1192f2644a2cSMark Brown pll_div->n, pll_div->k, pll_div->pre_div); 1193f2644a2cSMark Brown 1194f2644a2cSMark Brown return 0; 1195f2644a2cSMark Brown } 1196f2644a2cSMark Brown 1197e075fc17SKuninori Morimoto static int wm8960_set_pll(struct snd_soc_component *component, 11983176bf2dSZidan Wang unsigned int freq_in, unsigned int freq_out) 1199f2644a2cSMark Brown { 1200f2644a2cSMark Brown u16 reg; 1201f2644a2cSMark Brown static struct _pll_div pll_div; 1202f2644a2cSMark Brown int ret; 1203f2644a2cSMark Brown 1204f2644a2cSMark Brown if (freq_in && freq_out) { 1205f2644a2cSMark Brown ret = pll_factors(freq_in, freq_out, &pll_div); 1206f2644a2cSMark Brown if (ret != 0) 1207f2644a2cSMark Brown return ret; 1208f2644a2cSMark Brown } 1209f2644a2cSMark Brown 1210f2644a2cSMark Brown /* Disable the PLL: even if we are changing the frequency the 1211f2644a2cSMark Brown * PLL needs to be disabled while we do so. */ 1212e075fc17SKuninori Morimoto snd_soc_component_update_bits(component, WM8960_CLOCK1, 0x1, 0); 1213e075fc17SKuninori Morimoto snd_soc_component_update_bits(component, WM8960_POWER2, 0x1, 0); 1214f2644a2cSMark Brown 1215f2644a2cSMark Brown if (!freq_in || !freq_out) 1216f2644a2cSMark Brown return 0; 1217f2644a2cSMark Brown 12186d75dfc3SKuninori Morimoto reg = snd_soc_component_read(component, WM8960_PLL1) & ~0x3f; 1219f2644a2cSMark Brown reg |= pll_div.pre_div << 4; 1220f2644a2cSMark Brown reg |= pll_div.n; 1221f2644a2cSMark Brown 1222f2644a2cSMark Brown if (pll_div.k) { 1223f2644a2cSMark Brown reg |= 0x20; 1224f2644a2cSMark Brown 1225e075fc17SKuninori Morimoto snd_soc_component_write(component, WM8960_PLL2, (pll_div.k >> 16) & 0xff); 1226e075fc17SKuninori Morimoto snd_soc_component_write(component, WM8960_PLL3, (pll_div.k >> 8) & 0xff); 1227e075fc17SKuninori Morimoto snd_soc_component_write(component, WM8960_PLL4, pll_div.k & 0xff); 1228f2644a2cSMark Brown } 1229e075fc17SKuninori Morimoto snd_soc_component_write(component, WM8960_PLL1, reg); 1230f2644a2cSMark Brown 1231f2644a2cSMark Brown /* Turn it on */ 1232e075fc17SKuninori Morimoto snd_soc_component_update_bits(component, WM8960_POWER2, 0x1, 0x1); 1233f2644a2cSMark Brown msleep(250); 1234e075fc17SKuninori Morimoto snd_soc_component_update_bits(component, WM8960_CLOCK1, 0x1, 0x1); 1235f2644a2cSMark Brown 1236f2644a2cSMark Brown return 0; 1237f2644a2cSMark Brown } 1238f2644a2cSMark Brown 12393176bf2dSZidan Wang static int wm8960_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, 12403176bf2dSZidan Wang int source, unsigned int freq_in, unsigned int freq_out) 12413176bf2dSZidan Wang { 1242e075fc17SKuninori Morimoto struct snd_soc_component *component = codec_dai->component; 1243e075fc17SKuninori Morimoto struct wm8960_priv *wm8960 = snd_soc_component_get_drvdata(component); 12443176bf2dSZidan Wang 12453176bf2dSZidan Wang wm8960->freq_in = freq_in; 12463176bf2dSZidan Wang 12473176bf2dSZidan Wang if (pll_id == WM8960_SYSCLK_AUTO) 12483176bf2dSZidan Wang return 0; 12493176bf2dSZidan Wang 1250e075fc17SKuninori Morimoto return wm8960_set_pll(component, freq_in, freq_out); 12513176bf2dSZidan Wang } 12523176bf2dSZidan Wang 1253f2644a2cSMark Brown static int wm8960_set_dai_clkdiv(struct snd_soc_dai *codec_dai, 1254f2644a2cSMark Brown int div_id, int div) 1255f2644a2cSMark Brown { 1256e075fc17SKuninori Morimoto struct snd_soc_component *component = codec_dai->component; 1257f2644a2cSMark Brown u16 reg; 1258f2644a2cSMark Brown 1259f2644a2cSMark Brown switch (div_id) { 1260f2644a2cSMark Brown case WM8960_SYSCLKDIV: 12616d75dfc3SKuninori Morimoto reg = snd_soc_component_read(component, WM8960_CLOCK1) & 0x1f9; 1262e075fc17SKuninori Morimoto snd_soc_component_write(component, WM8960_CLOCK1, reg | div); 1263f2644a2cSMark Brown break; 1264f2644a2cSMark Brown case WM8960_DACDIV: 12656d75dfc3SKuninori Morimoto reg = snd_soc_component_read(component, WM8960_CLOCK1) & 0x1c7; 1266e075fc17SKuninori Morimoto snd_soc_component_write(component, WM8960_CLOCK1, reg | div); 1267f2644a2cSMark Brown break; 1268f2644a2cSMark Brown case WM8960_OPCLKDIV: 12696d75dfc3SKuninori Morimoto reg = snd_soc_component_read(component, WM8960_PLL1) & 0x03f; 1270e075fc17SKuninori Morimoto snd_soc_component_write(component, WM8960_PLL1, reg | div); 1271f2644a2cSMark Brown break; 1272f2644a2cSMark Brown case WM8960_DCLKDIV: 12736d75dfc3SKuninori Morimoto reg = snd_soc_component_read(component, WM8960_CLOCK2) & 0x03f; 1274e075fc17SKuninori Morimoto snd_soc_component_write(component, WM8960_CLOCK2, reg | div); 1275f2644a2cSMark Brown break; 1276f2644a2cSMark Brown case WM8960_TOCLKSEL: 12776d75dfc3SKuninori Morimoto reg = snd_soc_component_read(component, WM8960_ADDCTL1) & 0x1fd; 1278e075fc17SKuninori Morimoto snd_soc_component_write(component, WM8960_ADDCTL1, reg | div); 1279f2644a2cSMark Brown break; 1280f2644a2cSMark Brown default: 1281f2644a2cSMark Brown return -EINVAL; 1282f2644a2cSMark Brown } 1283f2644a2cSMark Brown 1284f2644a2cSMark Brown return 0; 1285f2644a2cSMark Brown } 1286f2644a2cSMark Brown 1287e075fc17SKuninori Morimoto static int wm8960_set_bias_level(struct snd_soc_component *component, 1288f0fba2adSLiam Girdwood enum snd_soc_bias_level level) 1289f0fba2adSLiam Girdwood { 1290e075fc17SKuninori Morimoto struct wm8960_priv *wm8960 = snd_soc_component_get_drvdata(component); 1291f0fba2adSLiam Girdwood 1292e075fc17SKuninori Morimoto return wm8960->set_bias_level(component, level); 1293f0fba2adSLiam Girdwood } 1294f0fba2adSLiam Girdwood 12950e50b51aSZidan Wang static int wm8960_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id, 12960e50b51aSZidan Wang unsigned int freq, int dir) 12970e50b51aSZidan Wang { 1298e075fc17SKuninori Morimoto struct snd_soc_component *component = dai->component; 1299e075fc17SKuninori Morimoto struct wm8960_priv *wm8960 = snd_soc_component_get_drvdata(component); 13000e50b51aSZidan Wang 13010e50b51aSZidan Wang switch (clk_id) { 13020e50b51aSZidan Wang case WM8960_SYSCLK_MCLK: 1303e075fc17SKuninori Morimoto snd_soc_component_update_bits(component, WM8960_CLOCK1, 13040e50b51aSZidan Wang 0x1, WM8960_SYSCLK_MCLK); 13050e50b51aSZidan Wang break; 13060e50b51aSZidan Wang case WM8960_SYSCLK_PLL: 1307e075fc17SKuninori Morimoto snd_soc_component_update_bits(component, WM8960_CLOCK1, 13080e50b51aSZidan Wang 0x1, WM8960_SYSCLK_PLL); 13090e50b51aSZidan Wang break; 13103176bf2dSZidan Wang case WM8960_SYSCLK_AUTO: 13113176bf2dSZidan Wang break; 13120e50b51aSZidan Wang default: 13130e50b51aSZidan Wang return -EINVAL; 13140e50b51aSZidan Wang } 13150e50b51aSZidan Wang 13160e50b51aSZidan Wang wm8960->sysclk = freq; 13173176bf2dSZidan Wang wm8960->clk_id = clk_id; 13180e50b51aSZidan Wang 13190e50b51aSZidan Wang return 0; 13200e50b51aSZidan Wang } 13210e50b51aSZidan Wang 1322f2644a2cSMark Brown #define WM8960_RATES SNDRV_PCM_RATE_8000_48000 1323f2644a2cSMark Brown 1324f2644a2cSMark Brown #define WM8960_FORMATS \ 1325f2644a2cSMark Brown (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ 13267a8c7867SZidan Wang SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) 1327f2644a2cSMark Brown 132885e7652dSLars-Peter Clausen static const struct snd_soc_dai_ops wm8960_dai_ops = { 1329f2644a2cSMark Brown .hw_params = wm8960_hw_params, 13303176bf2dSZidan Wang .hw_free = wm8960_hw_free, 133126d3c16eSKuninori Morimoto .mute_stream = wm8960_mute, 1332f2644a2cSMark Brown .set_fmt = wm8960_set_dai_fmt, 1333f2644a2cSMark Brown .set_clkdiv = wm8960_set_dai_clkdiv, 1334f2644a2cSMark Brown .set_pll = wm8960_set_dai_pll, 13350e50b51aSZidan Wang .set_sysclk = wm8960_set_dai_sysclk, 133626d3c16eSKuninori Morimoto .no_capture_mute = 1, 1337f2644a2cSMark Brown }; 1338f2644a2cSMark Brown 1339f0fba2adSLiam Girdwood static struct snd_soc_dai_driver wm8960_dai = { 1340f0fba2adSLiam Girdwood .name = "wm8960-hifi", 1341f2644a2cSMark Brown .playback = { 1342f2644a2cSMark Brown .stream_name = "Playback", 1343f2644a2cSMark Brown .channels_min = 1, 1344f2644a2cSMark Brown .channels_max = 2, 1345f2644a2cSMark Brown .rates = WM8960_RATES, 1346f2644a2cSMark Brown .formats = WM8960_FORMATS,}, 1347f2644a2cSMark Brown .capture = { 1348f2644a2cSMark Brown .stream_name = "Capture", 1349f2644a2cSMark Brown .channels_min = 1, 1350f2644a2cSMark Brown .channels_max = 2, 1351f2644a2cSMark Brown .rates = WM8960_RATES, 1352f2644a2cSMark Brown .formats = WM8960_FORMATS,}, 1353f2644a2cSMark Brown .ops = &wm8960_dai_ops, 135407695752SKuninori Morimoto .symmetric_rate = 1, 1355f2644a2cSMark Brown }; 1356f2644a2cSMark Brown 1357e075fc17SKuninori Morimoto static int wm8960_probe(struct snd_soc_component *component) 1358f2644a2cSMark Brown { 1359e075fc17SKuninori Morimoto struct wm8960_priv *wm8960 = snd_soc_component_get_drvdata(component); 1360e2280c90SZidan Wang struct wm8960_data *pdata = &wm8960->pdata; 1361f2644a2cSMark Brown 1362913d7b4cSMark Brown if (pdata->capless) 1363f0fba2adSLiam Girdwood wm8960->set_bias_level = wm8960_set_bias_level_capless; 1364e2280c90SZidan Wang else 1365e2280c90SZidan Wang wm8960->set_bias_level = wm8960_set_bias_level_out3; 1366f2644a2cSMark Brown 1367e075fc17SKuninori Morimoto snd_soc_add_component_controls(component, wm8960_snd_controls, 1368f0fba2adSLiam Girdwood ARRAY_SIZE(wm8960_snd_controls)); 1369e075fc17SKuninori Morimoto wm8960_add_widgets(component); 1370f2644a2cSMark Brown 1371f2644a2cSMark Brown return 0; 1372f2644a2cSMark Brown } 1373f2644a2cSMark Brown 1374e075fc17SKuninori Morimoto static const struct snd_soc_component_driver soc_component_dev_wm8960 = { 1375f0fba2adSLiam Girdwood .probe = wm8960_probe, 1376f0fba2adSLiam Girdwood .set_bias_level = wm8960_set_bias_level, 1377e075fc17SKuninori Morimoto .suspend_bias_off = 1, 1378e075fc17SKuninori Morimoto .idle_bias_on = 1, 1379e075fc17SKuninori Morimoto .use_pmdown_time = 1, 1380e075fc17SKuninori Morimoto .endianness = 1, 13810ebe36c6SMark Brown }; 13820ebe36c6SMark Brown 13830ebe36c6SMark Brown static const struct regmap_config wm8960_regmap = { 13840ebe36c6SMark Brown .reg_bits = 7, 13850ebe36c6SMark Brown .val_bits = 9, 13860ebe36c6SMark Brown .max_register = WM8960_PLL4, 13870ebe36c6SMark Brown 13880ebe36c6SMark Brown .reg_defaults = wm8960_reg_defaults, 13890ebe36c6SMark Brown .num_reg_defaults = ARRAY_SIZE(wm8960_reg_defaults), 13900ebe36c6SMark Brown .cache_type = REGCACHE_RBTREE, 13910ebe36c6SMark Brown 13920ebe36c6SMark Brown .volatile_reg = wm8960_volatile, 1393f0fba2adSLiam Girdwood }; 1394f0fba2adSLiam Girdwood 1395e2280c90SZidan Wang static void wm8960_set_pdata_from_of(struct i2c_client *i2c, 1396e2280c90SZidan Wang struct wm8960_data *pdata) 1397e2280c90SZidan Wang { 1398e2280c90SZidan Wang const struct device_node *np = i2c->dev.of_node; 1399e2280c90SZidan Wang 1400e2280c90SZidan Wang if (of_property_read_bool(np, "wlf,capless")) 1401e2280c90SZidan Wang pdata->capless = true; 1402e2280c90SZidan Wang 1403e2280c90SZidan Wang if (of_property_read_bool(np, "wlf,shared-lrclk")) 1404e2280c90SZidan Wang pdata->shared_lrclk = true; 1405c9015a17SShengjiu Wang 1406c9015a17SShengjiu Wang of_property_read_u32_array(np, "wlf,gpio-cfg", pdata->gpio_cfg, 1407c9015a17SShengjiu Wang ARRAY_SIZE(pdata->gpio_cfg)); 1408c9015a17SShengjiu Wang 1409c9015a17SShengjiu Wang of_property_read_u32_array(np, "wlf,hp-cfg", pdata->hp_cfg, 1410c9015a17SShengjiu Wang ARRAY_SIZE(pdata->hp_cfg)); 1411e2280c90SZidan Wang } 1412e2280c90SZidan Wang 141397b0b6e3SStephen Kitt static int wm8960_i2c_probe(struct i2c_client *i2c) 1414f2644a2cSMark Brown { 141537061631SMark Brown struct wm8960_data *pdata = dev_get_platdata(&i2c->dev); 1416f2644a2cSMark Brown struct wm8960_priv *wm8960; 1417f0fba2adSLiam Girdwood int ret; 1418f2644a2cSMark Brown 1419b9791c01SMark Brown wm8960 = devm_kzalloc(&i2c->dev, sizeof(struct wm8960_priv), 1420b9791c01SMark Brown GFP_KERNEL); 1421f2644a2cSMark Brown if (wm8960 == NULL) 1422f2644a2cSMark Brown return -ENOMEM; 1423f2644a2cSMark Brown 142475aa8868SZidan Wang wm8960->mclk = devm_clk_get(&i2c->dev, "mclk"); 142575aa8868SZidan Wang if (IS_ERR(wm8960->mclk)) { 142675aa8868SZidan Wang if (PTR_ERR(wm8960->mclk) == -EPROBE_DEFER) 142775aa8868SZidan Wang return -EPROBE_DEFER; 142875aa8868SZidan Wang } 142975aa8868SZidan Wang 1430c5e6f5faSSachin Kamat wm8960->regmap = devm_regmap_init_i2c(i2c, &wm8960_regmap); 14310ebe36c6SMark Brown if (IS_ERR(wm8960->regmap)) 14320ebe36c6SMark Brown return PTR_ERR(wm8960->regmap); 14330ebe36c6SMark Brown 1434e2280c90SZidan Wang if (pdata) 1435e2280c90SZidan Wang memcpy(&wm8960->pdata, pdata, sizeof(struct wm8960_data)); 1436e2280c90SZidan Wang else if (i2c->dev.of_node) 1437e2280c90SZidan Wang wm8960_set_pdata_from_of(i2c, &wm8960->pdata); 1438e2280c90SZidan Wang 14393ad5e861SZidan Wang ret = wm8960_reset(wm8960->regmap); 14403ad5e861SZidan Wang if (ret != 0) { 14413ad5e861SZidan Wang dev_err(&i2c->dev, "Failed to issue reset\n"); 14423ad5e861SZidan Wang return ret; 14433ad5e861SZidan Wang } 14443ad5e861SZidan Wang 14453ad5e861SZidan Wang if (wm8960->pdata.shared_lrclk) { 144637061631SMark Brown ret = regmap_update_bits(wm8960->regmap, WM8960_ADDCTL2, 144737061631SMark Brown 0x4, 0x4); 144837061631SMark Brown if (ret != 0) { 144937061631SMark Brown dev_err(&i2c->dev, "Failed to enable LRCM: %d\n", 145037061631SMark Brown ret); 145137061631SMark Brown return ret; 145237061631SMark Brown } 145337061631SMark Brown } 145437061631SMark Brown 14553ad5e861SZidan Wang /* Latch the update bits */ 14563ad5e861SZidan Wang regmap_update_bits(wm8960->regmap, WM8960_LINVOL, 0x100, 0x100); 14573ad5e861SZidan Wang regmap_update_bits(wm8960->regmap, WM8960_RINVOL, 0x100, 0x100); 14583ad5e861SZidan Wang regmap_update_bits(wm8960->regmap, WM8960_LADC, 0x100, 0x100); 14593ad5e861SZidan Wang regmap_update_bits(wm8960->regmap, WM8960_RADC, 0x100, 0x100); 14603ad5e861SZidan Wang regmap_update_bits(wm8960->regmap, WM8960_LDAC, 0x100, 0x100); 14613ad5e861SZidan Wang regmap_update_bits(wm8960->regmap, WM8960_RDAC, 0x100, 0x100); 14623ad5e861SZidan Wang regmap_update_bits(wm8960->regmap, WM8960_LOUT1, 0x100, 0x100); 14633ad5e861SZidan Wang regmap_update_bits(wm8960->regmap, WM8960_ROUT1, 0x100, 0x100); 14643ad5e861SZidan Wang regmap_update_bits(wm8960->regmap, WM8960_LOUT2, 0x100, 0x100); 14653ad5e861SZidan Wang regmap_update_bits(wm8960->regmap, WM8960_ROUT2, 0x100, 0x100); 14663ad5e861SZidan Wang 1467c9015a17SShengjiu Wang /* ADCLRC pin configured as GPIO. */ 1468c9015a17SShengjiu Wang regmap_update_bits(wm8960->regmap, WM8960_IFACE2, 1 << 6, 1469c9015a17SShengjiu Wang wm8960->pdata.gpio_cfg[0] << 6); 1470c9015a17SShengjiu Wang regmap_update_bits(wm8960->regmap, WM8960_ADDCTL4, 0xF << 4, 1471c9015a17SShengjiu Wang wm8960->pdata.gpio_cfg[1] << 4); 1472c9015a17SShengjiu Wang 1473c9015a17SShengjiu Wang /* Enable headphone jack detect */ 1474c9015a17SShengjiu Wang regmap_update_bits(wm8960->regmap, WM8960_ADDCTL4, 3 << 2, 1475c9015a17SShengjiu Wang wm8960->pdata.hp_cfg[0] << 2); 1476c9015a17SShengjiu Wang regmap_update_bits(wm8960->regmap, WM8960_ADDCTL2, 3 << 5, 1477c9015a17SShengjiu Wang wm8960->pdata.hp_cfg[1] << 5); 1478c9015a17SShengjiu Wang regmap_update_bits(wm8960->regmap, WM8960_ADDCTL1, 3, 1479c9015a17SShengjiu Wang wm8960->pdata.hp_cfg[2]); 1480c9015a17SShengjiu Wang 1481f2644a2cSMark Brown i2c_set_clientdata(i2c, wm8960); 1482f2644a2cSMark Brown 1483e075fc17SKuninori Morimoto ret = devm_snd_soc_register_component(&i2c->dev, 1484e075fc17SKuninori Morimoto &soc_component_dev_wm8960, &wm8960_dai, 1); 1485b9791c01SMark Brown 1486f0fba2adSLiam Girdwood return ret; 1487f2644a2cSMark Brown } 1488f2644a2cSMark Brown 1489ed5c2f5fSUwe Kleine-König static void wm8960_i2c_remove(struct i2c_client *client) 1490ed5c2f5fSUwe Kleine-König {} 1491f2644a2cSMark Brown 1492f2644a2cSMark Brown static const struct i2c_device_id wm8960_i2c_id[] = { 1493f2644a2cSMark Brown { "wm8960", 0 }, 1494f2644a2cSMark Brown { } 1495f2644a2cSMark Brown }; 1496f2644a2cSMark Brown MODULE_DEVICE_TABLE(i2c, wm8960_i2c_id); 1497f2644a2cSMark Brown 14987e0bdbaeSNicola Lunghi #if defined(CONFIG_OF) 1499e2280c90SZidan Wang static const struct of_device_id wm8960_of_match[] = { 1500e2280c90SZidan Wang { .compatible = "wlf,wm8960", }, 1501e2280c90SZidan Wang { } 1502e2280c90SZidan Wang }; 1503e2280c90SZidan Wang MODULE_DEVICE_TABLE(of, wm8960_of_match); 15047e0bdbaeSNicola Lunghi #endif 15057e0bdbaeSNicola Lunghi 15067e0bdbaeSNicola Lunghi #if defined(CONFIG_ACPI) 15077e0bdbaeSNicola Lunghi static const struct acpi_device_id wm8960_acpi_match[] = { 15087e0bdbaeSNicola Lunghi { "1AEC8960", 0 }, /* Wolfson PCI ID + part ID */ 15097e0bdbaeSNicola Lunghi { "10138960", 0 }, /* Cirrus Logic PCI ID + part ID */ 15107e0bdbaeSNicola Lunghi { }, 15117e0bdbaeSNicola Lunghi }; 15127e0bdbaeSNicola Lunghi MODULE_DEVICE_TABLE(acpi, wm8960_acpi_match); 15137e0bdbaeSNicola Lunghi #endif 1514e2280c90SZidan Wang 1515f2644a2cSMark Brown static struct i2c_driver wm8960_i2c_driver = { 1516f2644a2cSMark Brown .driver = { 1517091edccfSMark Brown .name = "wm8960", 15187e0bdbaeSNicola Lunghi .of_match_table = of_match_ptr(wm8960_of_match), 15197e0bdbaeSNicola Lunghi .acpi_match_table = ACPI_PTR(wm8960_acpi_match), 1520f2644a2cSMark Brown }, 1521*9abcd240SUwe Kleine-König .probe = wm8960_i2c_probe, 15227a79e94eSBill Pemberton .remove = wm8960_i2c_remove, 1523f2644a2cSMark Brown .id_table = wm8960_i2c_id, 1524f2644a2cSMark Brown }; 1525f2644a2cSMark Brown 15263c010e60SSachin Kamat module_i2c_driver(wm8960_i2c_driver); 1527f2644a2cSMark Brown 1528f2644a2cSMark Brown MODULE_DESCRIPTION("ASoC WM8960 driver"); 1529f2644a2cSMark Brown MODULE_AUTHOR("Liam Girdwood"); 1530f2644a2cSMark Brown MODULE_LICENSE("GPL"); 1531