1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
26d4baf08SMark Brown /*
36d4baf08SMark Brown * wm5100.c -- WM5100 ALSA SoC Audio driver
46d4baf08SMark Brown *
5656baaebSMark Brown * Copyright 2011-2 Wolfson Microelectronics plc
66d4baf08SMark Brown *
76d4baf08SMark Brown * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
86d4baf08SMark Brown */
96d4baf08SMark Brown
106d4baf08SMark Brown #include <linux/module.h>
116d4baf08SMark Brown #include <linux/moduleparam.h>
126d4baf08SMark Brown #include <linux/init.h>
136d4baf08SMark Brown #include <linux/delay.h>
140cf0f174SSachin Kamat #include <linux/export.h>
156d4baf08SMark Brown #include <linux/pm.h>
166d4baf08SMark Brown #include <linux/gcd.h>
17db1d1270SLinus Walleij #include <linux/gpio/driver.h>
186d4baf08SMark Brown #include <linux/gpio.h>
196d4baf08SMark Brown #include <linux/i2c.h>
2062c1c401SMark Brown #include <linux/pm_runtime.h>
216d4baf08SMark Brown #include <linux/regulator/consumer.h>
226d4baf08SMark Brown #include <linux/regulator/fixed.h>
236d4baf08SMark Brown #include <linux/slab.h>
246d4baf08SMark Brown #include <sound/core.h>
256d4baf08SMark Brown #include <sound/pcm.h>
266d4baf08SMark Brown #include <sound/pcm_params.h>
276d4baf08SMark Brown #include <sound/soc.h>
28ba896edeSMark Brown #include <sound/jack.h>
296d4baf08SMark Brown #include <sound/initval.h>
306d4baf08SMark Brown #include <sound/tlv.h>
316d4baf08SMark Brown #include <sound/wm5100.h>
326d4baf08SMark Brown
336d4baf08SMark Brown #include "wm5100.h"
346d4baf08SMark Brown
356d4baf08SMark Brown #define WM5100_NUM_CORE_SUPPLIES 2
366d4baf08SMark Brown static const char *wm5100_core_supply_names[WM5100_NUM_CORE_SUPPLIES] = {
376d4baf08SMark Brown "DBVDD1",
386d4baf08SMark Brown "LDOVDD", /* If DCVDD is supplied externally specify as LDOVDD */
396d4baf08SMark Brown };
406d4baf08SMark Brown
416d4baf08SMark Brown #define WM5100_AIFS 3
426d4baf08SMark Brown #define WM5100_SYNC_SRS 3
436d4baf08SMark Brown
446d4baf08SMark Brown struct wm5100_fll {
456d4baf08SMark Brown int fref;
466d4baf08SMark Brown int fout;
476d4baf08SMark Brown int src;
486d4baf08SMark Brown struct completion lock;
496d4baf08SMark Brown };
506d4baf08SMark Brown
516d4baf08SMark Brown /* codec private data */
526d4baf08SMark Brown struct wm5100_priv {
5346c1a877SMark Brown struct device *dev;
54bd132ec5SMark Brown struct regmap *regmap;
5561195838SKuninori Morimoto struct snd_soc_component *component;
566d4baf08SMark Brown
576d4baf08SMark Brown struct regulator_bulk_data core_supplies[WM5100_NUM_CORE_SUPPLIES];
586d4baf08SMark Brown
596d4baf08SMark Brown int rev;
606d4baf08SMark Brown
616d4baf08SMark Brown int sysclk;
626d4baf08SMark Brown int asyncclk;
636d4baf08SMark Brown
646d4baf08SMark Brown bool aif_async[WM5100_AIFS];
656d4baf08SMark Brown bool aif_symmetric[WM5100_AIFS];
666d4baf08SMark Brown int sr_ref[WM5100_SYNC_SRS];
676d4baf08SMark Brown
686d4baf08SMark Brown bool out_ena[2];
696d4baf08SMark Brown
70ba896edeSMark Brown struct snd_soc_jack *jack;
71ba896edeSMark Brown bool jack_detecting;
72ba896edeSMark Brown bool jack_mic;
73ba896edeSMark Brown int jack_mode;
742633f736SMark Brown int jack_flips;
75ba896edeSMark Brown
766d4baf08SMark Brown struct wm5100_fll fll[2];
776d4baf08SMark Brown
786d4baf08SMark Brown struct wm5100_pdata pdata;
796d4baf08SMark Brown
806d4baf08SMark Brown #ifdef CONFIG_GPIOLIB
816d4baf08SMark Brown struct gpio_chip gpio_chip;
826d4baf08SMark Brown #endif
836d4baf08SMark Brown };
846d4baf08SMark Brown
856d4baf08SMark Brown static int wm5100_sr_code[] = {
866d4baf08SMark Brown 0,
876d4baf08SMark Brown 12000,
886d4baf08SMark Brown 24000,
896d4baf08SMark Brown 48000,
906d4baf08SMark Brown 96000,
916d4baf08SMark Brown 192000,
926d4baf08SMark Brown 384000,
936d4baf08SMark Brown 768000,
946d4baf08SMark Brown 0,
956d4baf08SMark Brown 11025,
966d4baf08SMark Brown 22050,
976d4baf08SMark Brown 44100,
986d4baf08SMark Brown 88200,
996d4baf08SMark Brown 176400,
1006d4baf08SMark Brown 352800,
1016d4baf08SMark Brown 705600,
1026d4baf08SMark Brown 4000,
1036d4baf08SMark Brown 8000,
1046d4baf08SMark Brown 16000,
1056d4baf08SMark Brown 32000,
1066d4baf08SMark Brown 64000,
1076d4baf08SMark Brown 128000,
1086d4baf08SMark Brown 256000,
1096d4baf08SMark Brown 512000,
1106d4baf08SMark Brown };
1116d4baf08SMark Brown
1126d4baf08SMark Brown static int wm5100_sr_regs[WM5100_SYNC_SRS] = {
1136d4baf08SMark Brown WM5100_CLOCKING_4,
1146d4baf08SMark Brown WM5100_CLOCKING_5,
1156d4baf08SMark Brown WM5100_CLOCKING_6,
1166d4baf08SMark Brown };
1176d4baf08SMark Brown
wm5100_alloc_sr(struct snd_soc_component * component,int rate)11861195838SKuninori Morimoto static int wm5100_alloc_sr(struct snd_soc_component *component, int rate)
1196d4baf08SMark Brown {
12061195838SKuninori Morimoto struct wm5100_priv *wm5100 = snd_soc_component_get_drvdata(component);
1216d4baf08SMark Brown int sr_code, sr_free, i;
1226d4baf08SMark Brown
1236d4baf08SMark Brown for (i = 0; i < ARRAY_SIZE(wm5100_sr_code); i++)
1246d4baf08SMark Brown if (wm5100_sr_code[i] == rate)
1256d4baf08SMark Brown break;
1266d4baf08SMark Brown if (i == ARRAY_SIZE(wm5100_sr_code)) {
12761195838SKuninori Morimoto dev_err(component->dev, "Unsupported sample rate: %dHz\n", rate);
1286d4baf08SMark Brown return -EINVAL;
1296d4baf08SMark Brown }
1306d4baf08SMark Brown sr_code = i;
1316d4baf08SMark Brown
1326d4baf08SMark Brown if ((wm5100->sysclk % rate) == 0) {
1336d4baf08SMark Brown /* Is this rate already in use? */
1346d4baf08SMark Brown sr_free = -1;
1356d4baf08SMark Brown for (i = 0; i < ARRAY_SIZE(wm5100_sr_regs); i++) {
1366d4baf08SMark Brown if (!wm5100->sr_ref[i] && sr_free == -1) {
1376d4baf08SMark Brown sr_free = i;
1386d4baf08SMark Brown continue;
1396d4baf08SMark Brown }
1406d75dfc3SKuninori Morimoto if ((snd_soc_component_read(component, wm5100_sr_regs[i]) &
1416d4baf08SMark Brown WM5100_SAMPLE_RATE_1_MASK) == sr_code)
1426d4baf08SMark Brown break;
1436d4baf08SMark Brown }
1446d4baf08SMark Brown
1456d4baf08SMark Brown if (i < ARRAY_SIZE(wm5100_sr_regs)) {
1466d4baf08SMark Brown wm5100->sr_ref[i]++;
14761195838SKuninori Morimoto dev_dbg(component->dev, "SR %dHz, slot %d, ref %d\n",
1486d4baf08SMark Brown rate, i, wm5100->sr_ref[i]);
1496d4baf08SMark Brown return i;
1506d4baf08SMark Brown }
1516d4baf08SMark Brown
1526d4baf08SMark Brown if (sr_free == -1) {
15361195838SKuninori Morimoto dev_err(component->dev, "All SR slots already in use\n");
1546d4baf08SMark Brown return -EBUSY;
1556d4baf08SMark Brown }
1566d4baf08SMark Brown
15761195838SKuninori Morimoto dev_dbg(component->dev, "Allocating SR slot %d for %dHz\n",
1586d4baf08SMark Brown sr_free, rate);
1596d4baf08SMark Brown wm5100->sr_ref[sr_free]++;
16061195838SKuninori Morimoto snd_soc_component_update_bits(component, wm5100_sr_regs[sr_free],
1616d4baf08SMark Brown WM5100_SAMPLE_RATE_1_MASK,
1626d4baf08SMark Brown sr_code);
1636d4baf08SMark Brown
1646d4baf08SMark Brown return sr_free;
1656d4baf08SMark Brown
1666d4baf08SMark Brown } else {
16761195838SKuninori Morimoto dev_err(component->dev,
1686d4baf08SMark Brown "SR %dHz incompatible with %dHz SYSCLK and %dHz ASYNCCLK\n",
1696d4baf08SMark Brown rate, wm5100->sysclk, wm5100->asyncclk);
1706d4baf08SMark Brown return -EINVAL;
1716d4baf08SMark Brown }
1726d4baf08SMark Brown }
1736d4baf08SMark Brown
wm5100_free_sr(struct snd_soc_component * component,int rate)17461195838SKuninori Morimoto static void wm5100_free_sr(struct snd_soc_component *component, int rate)
1756d4baf08SMark Brown {
17661195838SKuninori Morimoto struct wm5100_priv *wm5100 = snd_soc_component_get_drvdata(component);
1776d4baf08SMark Brown int i, sr_code;
1786d4baf08SMark Brown
1796d4baf08SMark Brown for (i = 0; i < ARRAY_SIZE(wm5100_sr_code); i++)
1806d4baf08SMark Brown if (wm5100_sr_code[i] == rate)
1816d4baf08SMark Brown break;
1826d4baf08SMark Brown if (i == ARRAY_SIZE(wm5100_sr_code)) {
18361195838SKuninori Morimoto dev_err(component->dev, "Unsupported sample rate: %dHz\n", rate);
1846d4baf08SMark Brown return;
1856d4baf08SMark Brown }
1866d4baf08SMark Brown sr_code = wm5100_sr_code[i];
1876d4baf08SMark Brown
1886d4baf08SMark Brown for (i = 0; i < ARRAY_SIZE(wm5100_sr_regs); i++) {
1896d4baf08SMark Brown if (!wm5100->sr_ref[i])
1906d4baf08SMark Brown continue;
1916d4baf08SMark Brown
1926d75dfc3SKuninori Morimoto if ((snd_soc_component_read(component, wm5100_sr_regs[i]) &
1936d4baf08SMark Brown WM5100_SAMPLE_RATE_1_MASK) == sr_code)
1946d4baf08SMark Brown break;
1956d4baf08SMark Brown }
1966d4baf08SMark Brown if (i < ARRAY_SIZE(wm5100_sr_regs)) {
1976d4baf08SMark Brown wm5100->sr_ref[i]--;
19861195838SKuninori Morimoto dev_dbg(component->dev, "Dereference SR %dHz, count now %d\n",
1996d4baf08SMark Brown rate, wm5100->sr_ref[i]);
2006d4baf08SMark Brown } else {
20161195838SKuninori Morimoto dev_warn(component->dev, "Freeing unreferenced sample rate %dHz\n",
2026d4baf08SMark Brown rate);
2036d4baf08SMark Brown }
2046d4baf08SMark Brown }
2056d4baf08SMark Brown
wm5100_reset(struct wm5100_priv * wm5100)206588ac5e0SMark Brown static int wm5100_reset(struct wm5100_priv *wm5100)
2076d4baf08SMark Brown {
2086d4baf08SMark Brown if (wm5100->pdata.reset) {
2096d4baf08SMark Brown gpio_set_value_cansleep(wm5100->pdata.reset, 0);
2106d4baf08SMark Brown gpio_set_value_cansleep(wm5100->pdata.reset, 1);
2116d4baf08SMark Brown
2126d4baf08SMark Brown return 0;
2136d4baf08SMark Brown } else {
214588ac5e0SMark Brown return regmap_write(wm5100->regmap, WM5100_SOFTWARE_RESET, 0);
2156d4baf08SMark Brown }
2166d4baf08SMark Brown }
2176d4baf08SMark Brown
2186d4baf08SMark Brown static DECLARE_TLV_DB_SCALE(in_tlv, -6300, 100, 0);
2196d4baf08SMark Brown static DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0);
2206d4baf08SMark Brown static DECLARE_TLV_DB_SCALE(mixer_tlv, -3200, 100, 0);
2216d4baf08SMark Brown static DECLARE_TLV_DB_SCALE(out_tlv, -6400, 100, 0);
2226d4baf08SMark Brown static DECLARE_TLV_DB_SCALE(digital_tlv, -6400, 50, 0);
2236d4baf08SMark Brown
2246d4baf08SMark Brown static const char *wm5100_mixer_texts[] = {
2256d4baf08SMark Brown "None",
2266d4baf08SMark Brown "Tone Generator 1",
2276d4baf08SMark Brown "Tone Generator 2",
2286d4baf08SMark Brown "AEC loopback",
2296d4baf08SMark Brown "IN1L",
2306d4baf08SMark Brown "IN1R",
2316d4baf08SMark Brown "IN2L",
2326d4baf08SMark Brown "IN2R",
2336d4baf08SMark Brown "IN3L",
2346d4baf08SMark Brown "IN3R",
2356d4baf08SMark Brown "IN4L",
2366d4baf08SMark Brown "IN4R",
2376d4baf08SMark Brown "AIF1RX1",
2386d4baf08SMark Brown "AIF1RX2",
2396d4baf08SMark Brown "AIF1RX3",
2406d4baf08SMark Brown "AIF1RX4",
2416d4baf08SMark Brown "AIF1RX5",
2426d4baf08SMark Brown "AIF1RX6",
2436d4baf08SMark Brown "AIF1RX7",
2446d4baf08SMark Brown "AIF1RX8",
2456d4baf08SMark Brown "AIF2RX1",
2466d4baf08SMark Brown "AIF2RX2",
2476d4baf08SMark Brown "AIF3RX1",
2486d4baf08SMark Brown "AIF3RX2",
2496d4baf08SMark Brown "EQ1",
2506d4baf08SMark Brown "EQ2",
2516d4baf08SMark Brown "EQ3",
2526d4baf08SMark Brown "EQ4",
2536d4baf08SMark Brown "DRC1L",
2546d4baf08SMark Brown "DRC1R",
2556d4baf08SMark Brown "LHPF1",
2566d4baf08SMark Brown "LHPF2",
2576d4baf08SMark Brown "LHPF3",
2586d4baf08SMark Brown "LHPF4",
2596d4baf08SMark Brown "DSP1.1",
2606d4baf08SMark Brown "DSP1.2",
2616d4baf08SMark Brown "DSP1.3",
2626d4baf08SMark Brown "DSP1.4",
2636d4baf08SMark Brown "DSP1.5",
2646d4baf08SMark Brown "DSP1.6",
2656d4baf08SMark Brown "DSP2.1",
2666d4baf08SMark Brown "DSP2.2",
2676d4baf08SMark Brown "DSP2.3",
2686d4baf08SMark Brown "DSP2.4",
2696d4baf08SMark Brown "DSP2.5",
2706d4baf08SMark Brown "DSP2.6",
2716d4baf08SMark Brown "DSP3.1",
2726d4baf08SMark Brown "DSP3.2",
2736d4baf08SMark Brown "DSP3.3",
2746d4baf08SMark Brown "DSP3.4",
2756d4baf08SMark Brown "DSP3.5",
2766d4baf08SMark Brown "DSP3.6",
2776d4baf08SMark Brown "ASRC1L",
2786d4baf08SMark Brown "ASRC1R",
2796d4baf08SMark Brown "ASRC2L",
2806d4baf08SMark Brown "ASRC2R",
2816d4baf08SMark Brown "ISRC1INT1",
2826d4baf08SMark Brown "ISRC1INT2",
2836d4baf08SMark Brown "ISRC1INT3",
2846d4baf08SMark Brown "ISRC1INT4",
2856d4baf08SMark Brown "ISRC2INT1",
2866d4baf08SMark Brown "ISRC2INT2",
2876d4baf08SMark Brown "ISRC2INT3",
2886d4baf08SMark Brown "ISRC2INT4",
2896d4baf08SMark Brown "ISRC1DEC1",
2906d4baf08SMark Brown "ISRC1DEC2",
2916d4baf08SMark Brown "ISRC1DEC3",
2926d4baf08SMark Brown "ISRC1DEC4",
2936d4baf08SMark Brown "ISRC2DEC1",
2946d4baf08SMark Brown "ISRC2DEC2",
2956d4baf08SMark Brown "ISRC2DEC3",
2966d4baf08SMark Brown "ISRC2DEC4",
2976d4baf08SMark Brown };
2986d4baf08SMark Brown
2996d4baf08SMark Brown static int wm5100_mixer_values[] = {
3006d4baf08SMark Brown 0x00,
3016d4baf08SMark Brown 0x04, /* Tone */
3026d4baf08SMark Brown 0x05,
3036d4baf08SMark Brown 0x08, /* AEC */
3046d4baf08SMark Brown 0x10, /* Input */
3056d4baf08SMark Brown 0x11,
3066d4baf08SMark Brown 0x12,
3076d4baf08SMark Brown 0x13,
3086d4baf08SMark Brown 0x14,
3096d4baf08SMark Brown 0x15,
3106d4baf08SMark Brown 0x16,
3116d4baf08SMark Brown 0x17,
3126d4baf08SMark Brown 0x20, /* AIF */
3136d4baf08SMark Brown 0x21,
3146d4baf08SMark Brown 0x22,
3156d4baf08SMark Brown 0x23,
3166d4baf08SMark Brown 0x24,
3176d4baf08SMark Brown 0x25,
3186d4baf08SMark Brown 0x26,
3196d4baf08SMark Brown 0x27,
3206d4baf08SMark Brown 0x28,
3216d4baf08SMark Brown 0x29,
3226d4baf08SMark Brown 0x30, /* AIF3 - check */
3236d4baf08SMark Brown 0x31,
3246d4baf08SMark Brown 0x50, /* EQ */
3256d4baf08SMark Brown 0x51,
3266d4baf08SMark Brown 0x52,
3276d4baf08SMark Brown 0x53,
3286d4baf08SMark Brown 0x54,
3296d4baf08SMark Brown 0x58, /* DRC */
3306d4baf08SMark Brown 0x59,
3316d4baf08SMark Brown 0x60, /* LHPF1 */
3326d4baf08SMark Brown 0x61, /* LHPF2 */
3336d4baf08SMark Brown 0x62, /* LHPF3 */
3346d4baf08SMark Brown 0x63, /* LHPF4 */
3356d4baf08SMark Brown 0x68, /* DSP1 */
3366d4baf08SMark Brown 0x69,
3376d4baf08SMark Brown 0x6a,
3386d4baf08SMark Brown 0x6b,
3396d4baf08SMark Brown 0x6c,
3406d4baf08SMark Brown 0x6d,
3416d4baf08SMark Brown 0x70, /* DSP2 */
3426d4baf08SMark Brown 0x71,
3436d4baf08SMark Brown 0x72,
3446d4baf08SMark Brown 0x73,
3456d4baf08SMark Brown 0x74,
3466d4baf08SMark Brown 0x75,
3476d4baf08SMark Brown 0x78, /* DSP3 */
3486d4baf08SMark Brown 0x79,
3496d4baf08SMark Brown 0x7a,
3506d4baf08SMark Brown 0x7b,
3516d4baf08SMark Brown 0x7c,
3526d4baf08SMark Brown 0x7d,
3536d4baf08SMark Brown 0x90, /* ASRC1 */
3546d4baf08SMark Brown 0x91,
3556d4baf08SMark Brown 0x92, /* ASRC2 */
3566d4baf08SMark Brown 0x93,
3576d4baf08SMark Brown 0xa0, /* ISRC1DEC1 */
3586d4baf08SMark Brown 0xa1,
3596d4baf08SMark Brown 0xa2,
3606d4baf08SMark Brown 0xa3,
3616d4baf08SMark Brown 0xa4, /* ISRC1INT1 */
3626d4baf08SMark Brown 0xa5,
3636d4baf08SMark Brown 0xa6,
3646d4baf08SMark Brown 0xa7,
3656d4baf08SMark Brown 0xa8, /* ISRC2DEC1 */
3666d4baf08SMark Brown 0xa9,
3676d4baf08SMark Brown 0xaa,
3686d4baf08SMark Brown 0xab,
3696d4baf08SMark Brown 0xac, /* ISRC2INT1 */
3706d4baf08SMark Brown 0xad,
3716d4baf08SMark Brown 0xae,
3726d4baf08SMark Brown 0xaf,
3736d4baf08SMark Brown };
3746d4baf08SMark Brown
3756d4baf08SMark Brown #define WM5100_MIXER_CONTROLS(name, base) \
3766d4baf08SMark Brown SOC_SINGLE_TLV(name " Input 1 Volume", base + 1 , \
3776d4baf08SMark Brown WM5100_MIXER_VOL_SHIFT, 80, 0, mixer_tlv), \
3786d4baf08SMark Brown SOC_SINGLE_TLV(name " Input 2 Volume", base + 3 , \
3796d4baf08SMark Brown WM5100_MIXER_VOL_SHIFT, 80, 0, mixer_tlv), \
3806d4baf08SMark Brown SOC_SINGLE_TLV(name " Input 3 Volume", base + 5 , \
3816d4baf08SMark Brown WM5100_MIXER_VOL_SHIFT, 80, 0, mixer_tlv), \
3826d4baf08SMark Brown SOC_SINGLE_TLV(name " Input 4 Volume", base + 7 , \
3836d4baf08SMark Brown WM5100_MIXER_VOL_SHIFT, 80, 0, mixer_tlv)
3846d4baf08SMark Brown
3856d4baf08SMark Brown #define WM5100_MUX_ENUM_DECL(name, reg) \
3866d4baf08SMark Brown SOC_VALUE_ENUM_SINGLE_DECL(name, reg, 0, 0xff, \
3876d4baf08SMark Brown wm5100_mixer_texts, wm5100_mixer_values)
3886d4baf08SMark Brown
3896d4baf08SMark Brown #define WM5100_MUX_CTL_DECL(name) \
3906d4baf08SMark Brown const struct snd_kcontrol_new name##_mux = \
391cda88669SLars-Peter Clausen SOC_DAPM_ENUM("Route", name##_enum)
3926d4baf08SMark Brown
3936d4baf08SMark Brown #define WM5100_MIXER_ENUMS(name, base_reg) \
3946d4baf08SMark Brown static WM5100_MUX_ENUM_DECL(name##_in1_enum, base_reg); \
3956d4baf08SMark Brown static WM5100_MUX_ENUM_DECL(name##_in2_enum, base_reg + 2); \
3966d4baf08SMark Brown static WM5100_MUX_ENUM_DECL(name##_in3_enum, base_reg + 4); \
3976d4baf08SMark Brown static WM5100_MUX_ENUM_DECL(name##_in4_enum, base_reg + 6); \
3986d4baf08SMark Brown static WM5100_MUX_CTL_DECL(name##_in1); \
3996d4baf08SMark Brown static WM5100_MUX_CTL_DECL(name##_in2); \
4006d4baf08SMark Brown static WM5100_MUX_CTL_DECL(name##_in3); \
4016d4baf08SMark Brown static WM5100_MUX_CTL_DECL(name##_in4)
4026d4baf08SMark Brown
4036d4baf08SMark Brown WM5100_MIXER_ENUMS(HPOUT1L, WM5100_OUT1LMIX_INPUT_1_SOURCE);
4046d4baf08SMark Brown WM5100_MIXER_ENUMS(HPOUT1R, WM5100_OUT1RMIX_INPUT_1_SOURCE);
4056d4baf08SMark Brown WM5100_MIXER_ENUMS(HPOUT2L, WM5100_OUT2LMIX_INPUT_1_SOURCE);
4066d4baf08SMark Brown WM5100_MIXER_ENUMS(HPOUT2R, WM5100_OUT2RMIX_INPUT_1_SOURCE);
4076d4baf08SMark Brown WM5100_MIXER_ENUMS(HPOUT3L, WM5100_OUT3LMIX_INPUT_1_SOURCE);
4086d4baf08SMark Brown WM5100_MIXER_ENUMS(HPOUT3R, WM5100_OUT3RMIX_INPUT_1_SOURCE);
4096d4baf08SMark Brown
4106d4baf08SMark Brown WM5100_MIXER_ENUMS(SPKOUTL, WM5100_OUT4LMIX_INPUT_1_SOURCE);
4116d4baf08SMark Brown WM5100_MIXER_ENUMS(SPKOUTR, WM5100_OUT4RMIX_INPUT_1_SOURCE);
4126d4baf08SMark Brown WM5100_MIXER_ENUMS(SPKDAT1L, WM5100_OUT5LMIX_INPUT_1_SOURCE);
4136d4baf08SMark Brown WM5100_MIXER_ENUMS(SPKDAT1R, WM5100_OUT5RMIX_INPUT_1_SOURCE);
4146d4baf08SMark Brown WM5100_MIXER_ENUMS(SPKDAT2L, WM5100_OUT6LMIX_INPUT_1_SOURCE);
4156d4baf08SMark Brown WM5100_MIXER_ENUMS(SPKDAT2R, WM5100_OUT6RMIX_INPUT_1_SOURCE);
4166d4baf08SMark Brown
4176d4baf08SMark Brown WM5100_MIXER_ENUMS(PWM1, WM5100_PWM1MIX_INPUT_1_SOURCE);
4186d4baf08SMark Brown WM5100_MIXER_ENUMS(PWM2, WM5100_PWM1MIX_INPUT_1_SOURCE);
4196d4baf08SMark Brown
4206d4baf08SMark Brown WM5100_MIXER_ENUMS(AIF1TX1, WM5100_AIF1TX1MIX_INPUT_1_SOURCE);
4216d4baf08SMark Brown WM5100_MIXER_ENUMS(AIF1TX2, WM5100_AIF1TX2MIX_INPUT_1_SOURCE);
4226d4baf08SMark Brown WM5100_MIXER_ENUMS(AIF1TX3, WM5100_AIF1TX3MIX_INPUT_1_SOURCE);
4236d4baf08SMark Brown WM5100_MIXER_ENUMS(AIF1TX4, WM5100_AIF1TX4MIX_INPUT_1_SOURCE);
4246d4baf08SMark Brown WM5100_MIXER_ENUMS(AIF1TX5, WM5100_AIF1TX5MIX_INPUT_1_SOURCE);
4256d4baf08SMark Brown WM5100_MIXER_ENUMS(AIF1TX6, WM5100_AIF1TX6MIX_INPUT_1_SOURCE);
4266d4baf08SMark Brown WM5100_MIXER_ENUMS(AIF1TX7, WM5100_AIF1TX7MIX_INPUT_1_SOURCE);
4276d4baf08SMark Brown WM5100_MIXER_ENUMS(AIF1TX8, WM5100_AIF1TX8MIX_INPUT_1_SOURCE);
4286d4baf08SMark Brown
4296d4baf08SMark Brown WM5100_MIXER_ENUMS(AIF2TX1, WM5100_AIF2TX1MIX_INPUT_1_SOURCE);
4306d4baf08SMark Brown WM5100_MIXER_ENUMS(AIF2TX2, WM5100_AIF2TX2MIX_INPUT_1_SOURCE);
4316d4baf08SMark Brown
4326d4baf08SMark Brown WM5100_MIXER_ENUMS(AIF3TX1, WM5100_AIF1TX1MIX_INPUT_1_SOURCE);
4336d4baf08SMark Brown WM5100_MIXER_ENUMS(AIF3TX2, WM5100_AIF1TX2MIX_INPUT_1_SOURCE);
4346d4baf08SMark Brown
4356d4baf08SMark Brown WM5100_MIXER_ENUMS(EQ1, WM5100_EQ1MIX_INPUT_1_SOURCE);
4366d4baf08SMark Brown WM5100_MIXER_ENUMS(EQ2, WM5100_EQ2MIX_INPUT_1_SOURCE);
4376d4baf08SMark Brown WM5100_MIXER_ENUMS(EQ3, WM5100_EQ3MIX_INPUT_1_SOURCE);
4386d4baf08SMark Brown WM5100_MIXER_ENUMS(EQ4, WM5100_EQ4MIX_INPUT_1_SOURCE);
4396d4baf08SMark Brown
4406d4baf08SMark Brown WM5100_MIXER_ENUMS(DRC1L, WM5100_DRC1LMIX_INPUT_1_SOURCE);
4416d4baf08SMark Brown WM5100_MIXER_ENUMS(DRC1R, WM5100_DRC1RMIX_INPUT_1_SOURCE);
4426d4baf08SMark Brown
4436d4baf08SMark Brown WM5100_MIXER_ENUMS(LHPF1, WM5100_HPLP1MIX_INPUT_1_SOURCE);
4446d4baf08SMark Brown WM5100_MIXER_ENUMS(LHPF2, WM5100_HPLP2MIX_INPUT_1_SOURCE);
4456d4baf08SMark Brown WM5100_MIXER_ENUMS(LHPF3, WM5100_HPLP3MIX_INPUT_1_SOURCE);
4466d4baf08SMark Brown WM5100_MIXER_ENUMS(LHPF4, WM5100_HPLP4MIX_INPUT_1_SOURCE);
4476d4baf08SMark Brown
4486d4baf08SMark Brown #define WM5100_MUX(name, ctrl) \
449cda88669SLars-Peter Clausen SND_SOC_DAPM_MUX(name, SND_SOC_NOPM, 0, 0, ctrl)
4506d4baf08SMark Brown
4516d4baf08SMark Brown #define WM5100_MIXER_WIDGETS(name, name_str) \
4526d4baf08SMark Brown WM5100_MUX(name_str " Input 1", &name##_in1_mux), \
4536d4baf08SMark Brown WM5100_MUX(name_str " Input 2", &name##_in2_mux), \
4546d4baf08SMark Brown WM5100_MUX(name_str " Input 3", &name##_in3_mux), \
4556d4baf08SMark Brown WM5100_MUX(name_str " Input 4", &name##_in4_mux), \
4566d4baf08SMark Brown SND_SOC_DAPM_MIXER(name_str " Mixer", SND_SOC_NOPM, 0, 0, NULL, 0)
4576d4baf08SMark Brown
4586d4baf08SMark Brown #define WM5100_MIXER_INPUT_ROUTES(name) \
4596d4baf08SMark Brown { name, "Tone Generator 1", "Tone Generator 1" }, \
4606d4baf08SMark Brown { name, "Tone Generator 2", "Tone Generator 2" }, \
4616d4baf08SMark Brown { name, "IN1L", "IN1L PGA" }, \
4626d4baf08SMark Brown { name, "IN1R", "IN1R PGA" }, \
4636d4baf08SMark Brown { name, "IN2L", "IN2L PGA" }, \
4646d4baf08SMark Brown { name, "IN2R", "IN2R PGA" }, \
4656d4baf08SMark Brown { name, "IN3L", "IN3L PGA" }, \
4666d4baf08SMark Brown { name, "IN3R", "IN3R PGA" }, \
4676d4baf08SMark Brown { name, "IN4L", "IN4L PGA" }, \
4686d4baf08SMark Brown { name, "IN4R", "IN4R PGA" }, \
4696d4baf08SMark Brown { name, "AIF1RX1", "AIF1RX1" }, \
4706d4baf08SMark Brown { name, "AIF1RX2", "AIF1RX2" }, \
4716d4baf08SMark Brown { name, "AIF1RX3", "AIF1RX3" }, \
4726d4baf08SMark Brown { name, "AIF1RX4", "AIF1RX4" }, \
4736d4baf08SMark Brown { name, "AIF1RX5", "AIF1RX5" }, \
4746d4baf08SMark Brown { name, "AIF1RX6", "AIF1RX6" }, \
4756d4baf08SMark Brown { name, "AIF1RX7", "AIF1RX7" }, \
4766d4baf08SMark Brown { name, "AIF1RX8", "AIF1RX8" }, \
4776d4baf08SMark Brown { name, "AIF2RX1", "AIF2RX1" }, \
4786d4baf08SMark Brown { name, "AIF2RX2", "AIF2RX2" }, \
4796d4baf08SMark Brown { name, "AIF3RX1", "AIF3RX1" }, \
4806d4baf08SMark Brown { name, "AIF3RX2", "AIF3RX2" }, \
4816d4baf08SMark Brown { name, "EQ1", "EQ1" }, \
4826d4baf08SMark Brown { name, "EQ2", "EQ2" }, \
4836d4baf08SMark Brown { name, "EQ3", "EQ3" }, \
4846d4baf08SMark Brown { name, "EQ4", "EQ4" }, \
4856d4baf08SMark Brown { name, "DRC1L", "DRC1L" }, \
4866d4baf08SMark Brown { name, "DRC1R", "DRC1R" }, \
4876d4baf08SMark Brown { name, "LHPF1", "LHPF1" }, \
4886d4baf08SMark Brown { name, "LHPF2", "LHPF2" }, \
4896d4baf08SMark Brown { name, "LHPF3", "LHPF3" }, \
4906d4baf08SMark Brown { name, "LHPF4", "LHPF4" }
4916d4baf08SMark Brown
4926d4baf08SMark Brown #define WM5100_MIXER_ROUTES(widget, name) \
4936d4baf08SMark Brown { widget, NULL, name " Mixer" }, \
4946d4baf08SMark Brown { name " Mixer", NULL, name " Input 1" }, \
4956d4baf08SMark Brown { name " Mixer", NULL, name " Input 2" }, \
4966d4baf08SMark Brown { name " Mixer", NULL, name " Input 3" }, \
4976d4baf08SMark Brown { name " Mixer", NULL, name " Input 4" }, \
4986d4baf08SMark Brown WM5100_MIXER_INPUT_ROUTES(name " Input 1"), \
4996d4baf08SMark Brown WM5100_MIXER_INPUT_ROUTES(name " Input 2"), \
5006d4baf08SMark Brown WM5100_MIXER_INPUT_ROUTES(name " Input 3"), \
5016d4baf08SMark Brown WM5100_MIXER_INPUT_ROUTES(name " Input 4")
5026d4baf08SMark Brown
5036d4baf08SMark Brown static const char *wm5100_lhpf_mode_text[] = {
5046d4baf08SMark Brown "Low-pass", "High-pass"
5056d4baf08SMark Brown };
5066d4baf08SMark Brown
5070224ba6aSTakashi Iwai static SOC_ENUM_SINGLE_DECL(wm5100_lhpf1_mode,
5080224ba6aSTakashi Iwai WM5100_HPLPF1_1, WM5100_LHPF1_MODE_SHIFT,
5096d4baf08SMark Brown wm5100_lhpf_mode_text);
5106d4baf08SMark Brown
5110224ba6aSTakashi Iwai static SOC_ENUM_SINGLE_DECL(wm5100_lhpf2_mode,
5120224ba6aSTakashi Iwai WM5100_HPLPF2_1, WM5100_LHPF2_MODE_SHIFT,
5136d4baf08SMark Brown wm5100_lhpf_mode_text);
5146d4baf08SMark Brown
5150224ba6aSTakashi Iwai static SOC_ENUM_SINGLE_DECL(wm5100_lhpf3_mode,
5160224ba6aSTakashi Iwai WM5100_HPLPF3_1, WM5100_LHPF3_MODE_SHIFT,
5176d4baf08SMark Brown wm5100_lhpf_mode_text);
5186d4baf08SMark Brown
5190224ba6aSTakashi Iwai static SOC_ENUM_SINGLE_DECL(wm5100_lhpf4_mode,
5200224ba6aSTakashi Iwai WM5100_HPLPF4_1, WM5100_LHPF4_MODE_SHIFT,
5216d4baf08SMark Brown wm5100_lhpf_mode_text);
5226d4baf08SMark Brown
5236d4baf08SMark Brown static const struct snd_kcontrol_new wm5100_snd_controls[] = {
5246d4baf08SMark Brown SOC_SINGLE("IN1 High Performance Switch", WM5100_IN1L_CONTROL,
5256d4baf08SMark Brown WM5100_IN1_OSR_SHIFT, 1, 0),
5266d4baf08SMark Brown SOC_SINGLE("IN2 High Performance Switch", WM5100_IN2L_CONTROL,
5276d4baf08SMark Brown WM5100_IN2_OSR_SHIFT, 1, 0),
5286d4baf08SMark Brown SOC_SINGLE("IN3 High Performance Switch", WM5100_IN3L_CONTROL,
5296d4baf08SMark Brown WM5100_IN3_OSR_SHIFT, 1, 0),
5306d4baf08SMark Brown SOC_SINGLE("IN4 High Performance Switch", WM5100_IN4L_CONTROL,
5316d4baf08SMark Brown WM5100_IN4_OSR_SHIFT, 1, 0),
5326d4baf08SMark Brown
5336d4baf08SMark Brown /* Only applicable for analogue inputs */
5346d4baf08SMark Brown SOC_DOUBLE_R_TLV("IN1 Volume", WM5100_IN1L_CONTROL, WM5100_IN1R_CONTROL,
5356d4baf08SMark Brown WM5100_IN1L_PGA_VOL_SHIFT, 94, 0, in_tlv),
5366d4baf08SMark Brown SOC_DOUBLE_R_TLV("IN2 Volume", WM5100_IN2L_CONTROL, WM5100_IN2R_CONTROL,
5376d4baf08SMark Brown WM5100_IN2L_PGA_VOL_SHIFT, 94, 0, in_tlv),
5386d4baf08SMark Brown SOC_DOUBLE_R_TLV("IN3 Volume", WM5100_IN3L_CONTROL, WM5100_IN3R_CONTROL,
5396d4baf08SMark Brown WM5100_IN3L_PGA_VOL_SHIFT, 94, 0, in_tlv),
5406d4baf08SMark Brown SOC_DOUBLE_R_TLV("IN4 Volume", WM5100_IN4L_CONTROL, WM5100_IN4R_CONTROL,
5416d4baf08SMark Brown WM5100_IN4L_PGA_VOL_SHIFT, 94, 0, in_tlv),
5426d4baf08SMark Brown
5436d4baf08SMark Brown SOC_DOUBLE_R_TLV("IN1 Digital Volume", WM5100_ADC_DIGITAL_VOLUME_1L,
5446d4baf08SMark Brown WM5100_ADC_DIGITAL_VOLUME_1R, WM5100_IN1L_VOL_SHIFT, 191,
5456d4baf08SMark Brown 0, digital_tlv),
5466d4baf08SMark Brown SOC_DOUBLE_R_TLV("IN2 Digital Volume", WM5100_ADC_DIGITAL_VOLUME_2L,
5476d4baf08SMark Brown WM5100_ADC_DIGITAL_VOLUME_2R, WM5100_IN2L_VOL_SHIFT, 191,
5486d4baf08SMark Brown 0, digital_tlv),
5496d4baf08SMark Brown SOC_DOUBLE_R_TLV("IN3 Digital Volume", WM5100_ADC_DIGITAL_VOLUME_3L,
5506d4baf08SMark Brown WM5100_ADC_DIGITAL_VOLUME_3R, WM5100_IN3L_VOL_SHIFT, 191,
5516d4baf08SMark Brown 0, digital_tlv),
5526d4baf08SMark Brown SOC_DOUBLE_R_TLV("IN4 Digital Volume", WM5100_ADC_DIGITAL_VOLUME_4L,
5536d4baf08SMark Brown WM5100_ADC_DIGITAL_VOLUME_4R, WM5100_IN4L_VOL_SHIFT, 191,
5546d4baf08SMark Brown 0, digital_tlv),
5556d4baf08SMark Brown
5566d4baf08SMark Brown SOC_DOUBLE_R("IN1 Switch", WM5100_ADC_DIGITAL_VOLUME_1L,
5576d4baf08SMark Brown WM5100_ADC_DIGITAL_VOLUME_1R, WM5100_IN1L_MUTE_SHIFT, 1, 1),
5586d4baf08SMark Brown SOC_DOUBLE_R("IN2 Switch", WM5100_ADC_DIGITAL_VOLUME_2L,
5596d4baf08SMark Brown WM5100_ADC_DIGITAL_VOLUME_2R, WM5100_IN2L_MUTE_SHIFT, 1, 1),
5606d4baf08SMark Brown SOC_DOUBLE_R("IN3 Switch", WM5100_ADC_DIGITAL_VOLUME_3L,
5616d4baf08SMark Brown WM5100_ADC_DIGITAL_VOLUME_3R, WM5100_IN3L_MUTE_SHIFT, 1, 1),
5626d4baf08SMark Brown SOC_DOUBLE_R("IN4 Switch", WM5100_ADC_DIGITAL_VOLUME_4L,
5636d4baf08SMark Brown WM5100_ADC_DIGITAL_VOLUME_4R, WM5100_IN4L_MUTE_SHIFT, 1, 1),
5646d4baf08SMark Brown
56520fc4863SMark Brown SND_SOC_BYTES_MASK("EQ1 Coefficients", WM5100_EQ1_1, 20, WM5100_EQ1_ENA),
56620fc4863SMark Brown SND_SOC_BYTES_MASK("EQ2 Coefficients", WM5100_EQ2_1, 20, WM5100_EQ2_ENA),
56720fc4863SMark Brown SND_SOC_BYTES_MASK("EQ3 Coefficients", WM5100_EQ3_1, 20, WM5100_EQ3_ENA),
56820fc4863SMark Brown SND_SOC_BYTES_MASK("EQ4 Coefficients", WM5100_EQ4_1, 20, WM5100_EQ4_ENA),
56920fc4863SMark Brown
57020fc4863SMark Brown SND_SOC_BYTES_MASK("DRC Coefficients", WM5100_DRC1_CTRL1, 5,
57120fc4863SMark Brown WM5100_DRCL_ENA | WM5100_DRCR_ENA),
57220fc4863SMark Brown
57357b70db2SColin Ian King SND_SOC_BYTES("LHPF1 Coefficients", WM5100_HPLPF1_2, 1),
57457b70db2SColin Ian King SND_SOC_BYTES("LHPF2 Coefficients", WM5100_HPLPF2_2, 1),
57557b70db2SColin Ian King SND_SOC_BYTES("LHPF3 Coefficients", WM5100_HPLPF3_2, 1),
57657b70db2SColin Ian King SND_SOC_BYTES("LHPF4 Coefficients", WM5100_HPLPF4_2, 1),
57720fc4863SMark Brown
5786d4baf08SMark Brown SOC_SINGLE("HPOUT1 High Performance Switch", WM5100_OUT_VOLUME_1L,
5796d4baf08SMark Brown WM5100_OUT1_OSR_SHIFT, 1, 0),
5806d4baf08SMark Brown SOC_SINGLE("HPOUT2 High Performance Switch", WM5100_OUT_VOLUME_2L,
5816d4baf08SMark Brown WM5100_OUT2_OSR_SHIFT, 1, 0),
5826d4baf08SMark Brown SOC_SINGLE("HPOUT3 High Performance Switch", WM5100_OUT_VOLUME_3L,
5836d4baf08SMark Brown WM5100_OUT3_OSR_SHIFT, 1, 0),
5846d4baf08SMark Brown SOC_SINGLE("SPKOUT High Performance Switch", WM5100_OUT_VOLUME_4L,
5856d4baf08SMark Brown WM5100_OUT4_OSR_SHIFT, 1, 0),
5866d4baf08SMark Brown SOC_SINGLE("SPKDAT1 High Performance Switch", WM5100_DAC_VOLUME_LIMIT_5L,
5876d4baf08SMark Brown WM5100_OUT5_OSR_SHIFT, 1, 0),
5886d4baf08SMark Brown SOC_SINGLE("SPKDAT2 High Performance Switch", WM5100_DAC_VOLUME_LIMIT_6L,
5896d4baf08SMark Brown WM5100_OUT6_OSR_SHIFT, 1, 0),
5906d4baf08SMark Brown
5916d4baf08SMark Brown SOC_DOUBLE_R_TLV("HPOUT1 Digital Volume", WM5100_DAC_DIGITAL_VOLUME_1L,
5926d4baf08SMark Brown WM5100_DAC_DIGITAL_VOLUME_1R, WM5100_OUT1L_VOL_SHIFT, 159, 0,
5936d4baf08SMark Brown digital_tlv),
5946d4baf08SMark Brown SOC_DOUBLE_R_TLV("HPOUT2 Digital Volume", WM5100_DAC_DIGITAL_VOLUME_2L,
5956d4baf08SMark Brown WM5100_DAC_DIGITAL_VOLUME_2R, WM5100_OUT2L_VOL_SHIFT, 159, 0,
5966d4baf08SMark Brown digital_tlv),
5976d4baf08SMark Brown SOC_DOUBLE_R_TLV("HPOUT3 Digital Volume", WM5100_DAC_DIGITAL_VOLUME_3L,
5986d4baf08SMark Brown WM5100_DAC_DIGITAL_VOLUME_3R, WM5100_OUT3L_VOL_SHIFT, 159, 0,
5996d4baf08SMark Brown digital_tlv),
6006d4baf08SMark Brown SOC_DOUBLE_R_TLV("SPKOUT Digital Volume", WM5100_DAC_DIGITAL_VOLUME_4L,
6016d4baf08SMark Brown WM5100_DAC_DIGITAL_VOLUME_4R, WM5100_OUT4L_VOL_SHIFT, 159, 0,
6026d4baf08SMark Brown digital_tlv),
6036d4baf08SMark Brown SOC_DOUBLE_R_TLV("SPKDAT1 Digital Volume", WM5100_DAC_DIGITAL_VOLUME_5L,
6046d4baf08SMark Brown WM5100_DAC_DIGITAL_VOLUME_5R, WM5100_OUT5L_VOL_SHIFT, 159, 0,
6056d4baf08SMark Brown digital_tlv),
6066d4baf08SMark Brown SOC_DOUBLE_R_TLV("SPKDAT2 Digital Volume", WM5100_DAC_DIGITAL_VOLUME_6L,
6076d4baf08SMark Brown WM5100_DAC_DIGITAL_VOLUME_6R, WM5100_OUT6L_VOL_SHIFT, 159, 0,
6086d4baf08SMark Brown digital_tlv),
6096d4baf08SMark Brown
6106d4baf08SMark Brown SOC_DOUBLE_R("HPOUT1 Digital Switch", WM5100_DAC_DIGITAL_VOLUME_1L,
6116d4baf08SMark Brown WM5100_DAC_DIGITAL_VOLUME_1R, WM5100_OUT1L_MUTE_SHIFT, 1, 1),
6126d4baf08SMark Brown SOC_DOUBLE_R("HPOUT2 Digital Switch", WM5100_DAC_DIGITAL_VOLUME_2L,
6136d4baf08SMark Brown WM5100_DAC_DIGITAL_VOLUME_2R, WM5100_OUT2L_MUTE_SHIFT, 1, 1),
6146d4baf08SMark Brown SOC_DOUBLE_R("HPOUT3 Digital Switch", WM5100_DAC_DIGITAL_VOLUME_3L,
6156d4baf08SMark Brown WM5100_DAC_DIGITAL_VOLUME_3R, WM5100_OUT3L_MUTE_SHIFT, 1, 1),
6166d4baf08SMark Brown SOC_DOUBLE_R("SPKOUT Digital Switch", WM5100_DAC_DIGITAL_VOLUME_4L,
6176d4baf08SMark Brown WM5100_DAC_DIGITAL_VOLUME_4R, WM5100_OUT4L_MUTE_SHIFT, 1, 1),
6186d4baf08SMark Brown SOC_DOUBLE_R("SPKDAT1 Digital Switch", WM5100_DAC_DIGITAL_VOLUME_5L,
6196d4baf08SMark Brown WM5100_DAC_DIGITAL_VOLUME_5R, WM5100_OUT5L_MUTE_SHIFT, 1, 1),
6206d4baf08SMark Brown SOC_DOUBLE_R("SPKDAT2 Digital Switch", WM5100_DAC_DIGITAL_VOLUME_6L,
6216d4baf08SMark Brown WM5100_DAC_DIGITAL_VOLUME_6R, WM5100_OUT6L_MUTE_SHIFT, 1, 1),
6226d4baf08SMark Brown
6236d4baf08SMark Brown /* FIXME: Only valid from -12dB to 0dB (52-64) */
6246d4baf08SMark Brown SOC_DOUBLE_R_TLV("HPOUT1 Volume", WM5100_OUT_VOLUME_1L, WM5100_OUT_VOLUME_1R,
6256d4baf08SMark Brown WM5100_OUT1L_PGA_VOL_SHIFT, 64, 0, out_tlv),
6266d4baf08SMark Brown SOC_DOUBLE_R_TLV("HPOUT2 Volume", WM5100_OUT_VOLUME_2L, WM5100_OUT_VOLUME_2R,
6276d4baf08SMark Brown WM5100_OUT2L_PGA_VOL_SHIFT, 64, 0, out_tlv),
6286d4baf08SMark Brown SOC_DOUBLE_R_TLV("HPOUT3 Volume", WM5100_OUT_VOLUME_3L, WM5100_OUT_VOLUME_3R,
6296d4baf08SMark Brown WM5100_OUT2L_PGA_VOL_SHIFT, 64, 0, out_tlv),
6306d4baf08SMark Brown
6316d4baf08SMark Brown SOC_DOUBLE("SPKDAT1 Switch", WM5100_PDM_SPK1_CTRL_1, WM5100_SPK1L_MUTE_SHIFT,
6326d4baf08SMark Brown WM5100_SPK1R_MUTE_SHIFT, 1, 1),
6336d4baf08SMark Brown SOC_DOUBLE("SPKDAT2 Switch", WM5100_PDM_SPK2_CTRL_1, WM5100_SPK2L_MUTE_SHIFT,
6346d4baf08SMark Brown WM5100_SPK2R_MUTE_SHIFT, 1, 1),
6356d4baf08SMark Brown
6366d4baf08SMark Brown SOC_SINGLE_TLV("EQ1 Band 1 Volume", WM5100_EQ1_1, WM5100_EQ1_B1_GAIN_SHIFT,
6376d4baf08SMark Brown 24, 0, eq_tlv),
6386d4baf08SMark Brown SOC_SINGLE_TLV("EQ1 Band 2 Volume", WM5100_EQ1_1, WM5100_EQ1_B2_GAIN_SHIFT,
6396d4baf08SMark Brown 24, 0, eq_tlv),
6406d4baf08SMark Brown SOC_SINGLE_TLV("EQ1 Band 3 Volume", WM5100_EQ1_1, WM5100_EQ1_B3_GAIN_SHIFT,
6416d4baf08SMark Brown 24, 0, eq_tlv),
6426d4baf08SMark Brown SOC_SINGLE_TLV("EQ1 Band 4 Volume", WM5100_EQ1_2, WM5100_EQ1_B4_GAIN_SHIFT,
6436d4baf08SMark Brown 24, 0, eq_tlv),
6446d4baf08SMark Brown SOC_SINGLE_TLV("EQ1 Band 5 Volume", WM5100_EQ1_2, WM5100_EQ1_B5_GAIN_SHIFT,
6456d4baf08SMark Brown 24, 0, eq_tlv),
6466d4baf08SMark Brown
6476d4baf08SMark Brown SOC_SINGLE_TLV("EQ2 Band 1 Volume", WM5100_EQ2_1, WM5100_EQ2_B1_GAIN_SHIFT,
6486d4baf08SMark Brown 24, 0, eq_tlv),
6496d4baf08SMark Brown SOC_SINGLE_TLV("EQ2 Band 2 Volume", WM5100_EQ2_1, WM5100_EQ2_B2_GAIN_SHIFT,
6506d4baf08SMark Brown 24, 0, eq_tlv),
6516d4baf08SMark Brown SOC_SINGLE_TLV("EQ2 Band 3 Volume", WM5100_EQ2_1, WM5100_EQ2_B3_GAIN_SHIFT,
6526d4baf08SMark Brown 24, 0, eq_tlv),
6536d4baf08SMark Brown SOC_SINGLE_TLV("EQ2 Band 4 Volume", WM5100_EQ2_2, WM5100_EQ2_B4_GAIN_SHIFT,
6546d4baf08SMark Brown 24, 0, eq_tlv),
6556d4baf08SMark Brown SOC_SINGLE_TLV("EQ2 Band 5 Volume", WM5100_EQ2_2, WM5100_EQ2_B5_GAIN_SHIFT,
6566d4baf08SMark Brown 24, 0, eq_tlv),
6576d4baf08SMark Brown
6586d4baf08SMark Brown SOC_SINGLE_TLV("EQ3 Band 1 Volume", WM5100_EQ1_1, WM5100_EQ3_B1_GAIN_SHIFT,
6596d4baf08SMark Brown 24, 0, eq_tlv),
6606d4baf08SMark Brown SOC_SINGLE_TLV("EQ3 Band 2 Volume", WM5100_EQ3_1, WM5100_EQ3_B2_GAIN_SHIFT,
6616d4baf08SMark Brown 24, 0, eq_tlv),
6626d4baf08SMark Brown SOC_SINGLE_TLV("EQ3 Band 3 Volume", WM5100_EQ3_1, WM5100_EQ3_B3_GAIN_SHIFT,
6636d4baf08SMark Brown 24, 0, eq_tlv),
6646d4baf08SMark Brown SOC_SINGLE_TLV("EQ3 Band 4 Volume", WM5100_EQ3_2, WM5100_EQ3_B4_GAIN_SHIFT,
6656d4baf08SMark Brown 24, 0, eq_tlv),
6666d4baf08SMark Brown SOC_SINGLE_TLV("EQ3 Band 5 Volume", WM5100_EQ3_2, WM5100_EQ3_B5_GAIN_SHIFT,
6676d4baf08SMark Brown 24, 0, eq_tlv),
6686d4baf08SMark Brown
6696d4baf08SMark Brown SOC_SINGLE_TLV("EQ4 Band 1 Volume", WM5100_EQ4_1, WM5100_EQ4_B1_GAIN_SHIFT,
6706d4baf08SMark Brown 24, 0, eq_tlv),
6716d4baf08SMark Brown SOC_SINGLE_TLV("EQ4 Band 2 Volume", WM5100_EQ4_1, WM5100_EQ4_B2_GAIN_SHIFT,
6726d4baf08SMark Brown 24, 0, eq_tlv),
6736d4baf08SMark Brown SOC_SINGLE_TLV("EQ4 Band 3 Volume", WM5100_EQ4_1, WM5100_EQ4_B3_GAIN_SHIFT,
6746d4baf08SMark Brown 24, 0, eq_tlv),
6756d4baf08SMark Brown SOC_SINGLE_TLV("EQ4 Band 4 Volume", WM5100_EQ4_2, WM5100_EQ4_B4_GAIN_SHIFT,
6766d4baf08SMark Brown 24, 0, eq_tlv),
6776d4baf08SMark Brown SOC_SINGLE_TLV("EQ4 Band 5 Volume", WM5100_EQ4_2, WM5100_EQ4_B5_GAIN_SHIFT,
6786d4baf08SMark Brown 24, 0, eq_tlv),
6796d4baf08SMark Brown
6806d4baf08SMark Brown SOC_ENUM("LHPF1 Mode", wm5100_lhpf1_mode),
6816d4baf08SMark Brown SOC_ENUM("LHPF2 Mode", wm5100_lhpf2_mode),
6826d4baf08SMark Brown SOC_ENUM("LHPF3 Mode", wm5100_lhpf3_mode),
6836d4baf08SMark Brown SOC_ENUM("LHPF4 Mode", wm5100_lhpf4_mode),
6846d4baf08SMark Brown
6856d4baf08SMark Brown WM5100_MIXER_CONTROLS("HPOUT1L", WM5100_OUT1LMIX_INPUT_1_SOURCE),
6866d4baf08SMark Brown WM5100_MIXER_CONTROLS("HPOUT1R", WM5100_OUT1RMIX_INPUT_1_SOURCE),
6876d4baf08SMark Brown WM5100_MIXER_CONTROLS("HPOUT2L", WM5100_OUT2LMIX_INPUT_1_SOURCE),
6886d4baf08SMark Brown WM5100_MIXER_CONTROLS("HPOUT2R", WM5100_OUT2RMIX_INPUT_1_SOURCE),
6896d4baf08SMark Brown WM5100_MIXER_CONTROLS("HPOUT3L", WM5100_OUT3LMIX_INPUT_1_SOURCE),
6906d4baf08SMark Brown WM5100_MIXER_CONTROLS("HPOUT3R", WM5100_OUT3RMIX_INPUT_1_SOURCE),
6916d4baf08SMark Brown
6926d4baf08SMark Brown WM5100_MIXER_CONTROLS("SPKOUTL", WM5100_OUT4LMIX_INPUT_1_SOURCE),
6936d4baf08SMark Brown WM5100_MIXER_CONTROLS("SPKOUTR", WM5100_OUT4RMIX_INPUT_1_SOURCE),
6946d4baf08SMark Brown WM5100_MIXER_CONTROLS("SPKDAT1L", WM5100_OUT5LMIX_INPUT_1_SOURCE),
6956d4baf08SMark Brown WM5100_MIXER_CONTROLS("SPKDAT1R", WM5100_OUT5RMIX_INPUT_1_SOURCE),
6966d4baf08SMark Brown WM5100_MIXER_CONTROLS("SPKDAT2L", WM5100_OUT6LMIX_INPUT_1_SOURCE),
6976d4baf08SMark Brown WM5100_MIXER_CONTROLS("SPKDAT2R", WM5100_OUT6RMIX_INPUT_1_SOURCE),
6986d4baf08SMark Brown
6996d4baf08SMark Brown WM5100_MIXER_CONTROLS("PWM1", WM5100_PWM1MIX_INPUT_1_SOURCE),
7006d4baf08SMark Brown WM5100_MIXER_CONTROLS("PWM2", WM5100_PWM2MIX_INPUT_1_SOURCE),
7016d4baf08SMark Brown
7026d4baf08SMark Brown WM5100_MIXER_CONTROLS("AIF1TX1", WM5100_AIF1TX1MIX_INPUT_1_SOURCE),
7036d4baf08SMark Brown WM5100_MIXER_CONTROLS("AIF1TX2", WM5100_AIF1TX2MIX_INPUT_1_SOURCE),
7046d4baf08SMark Brown WM5100_MIXER_CONTROLS("AIF1TX3", WM5100_AIF1TX3MIX_INPUT_1_SOURCE),
7056d4baf08SMark Brown WM5100_MIXER_CONTROLS("AIF1TX4", WM5100_AIF1TX4MIX_INPUT_1_SOURCE),
7066d4baf08SMark Brown WM5100_MIXER_CONTROLS("AIF1TX5", WM5100_AIF1TX5MIX_INPUT_1_SOURCE),
7076d4baf08SMark Brown WM5100_MIXER_CONTROLS("AIF1TX6", WM5100_AIF1TX6MIX_INPUT_1_SOURCE),
7086d4baf08SMark Brown WM5100_MIXER_CONTROLS("AIF1TX7", WM5100_AIF1TX7MIX_INPUT_1_SOURCE),
7096d4baf08SMark Brown WM5100_MIXER_CONTROLS("AIF1TX8", WM5100_AIF1TX8MIX_INPUT_1_SOURCE),
7106d4baf08SMark Brown
7116d4baf08SMark Brown WM5100_MIXER_CONTROLS("AIF2TX1", WM5100_AIF2TX1MIX_INPUT_1_SOURCE),
7126d4baf08SMark Brown WM5100_MIXER_CONTROLS("AIF2TX2", WM5100_AIF2TX2MIX_INPUT_1_SOURCE),
7136d4baf08SMark Brown
7146d4baf08SMark Brown WM5100_MIXER_CONTROLS("AIF3TX1", WM5100_AIF3TX1MIX_INPUT_1_SOURCE),
7156d4baf08SMark Brown WM5100_MIXER_CONTROLS("AIF3TX2", WM5100_AIF3TX2MIX_INPUT_1_SOURCE),
7166d4baf08SMark Brown
7176d4baf08SMark Brown WM5100_MIXER_CONTROLS("EQ1", WM5100_EQ1MIX_INPUT_1_SOURCE),
7186d4baf08SMark Brown WM5100_MIXER_CONTROLS("EQ2", WM5100_EQ2MIX_INPUT_1_SOURCE),
7196d4baf08SMark Brown WM5100_MIXER_CONTROLS("EQ3", WM5100_EQ3MIX_INPUT_1_SOURCE),
7206d4baf08SMark Brown WM5100_MIXER_CONTROLS("EQ4", WM5100_EQ4MIX_INPUT_1_SOURCE),
7216d4baf08SMark Brown
7226d4baf08SMark Brown WM5100_MIXER_CONTROLS("DRC1L", WM5100_DRC1LMIX_INPUT_1_SOURCE),
7236d4baf08SMark Brown WM5100_MIXER_CONTROLS("DRC1R", WM5100_DRC1RMIX_INPUT_1_SOURCE),
724cdaaf301SMark Brown SND_SOC_BYTES_MASK("DRC", WM5100_DRC1_CTRL1, 5,
725cdaaf301SMark Brown WM5100_DRCL_ENA | WM5100_DRCR_ENA),
7266d4baf08SMark Brown
7276d4baf08SMark Brown WM5100_MIXER_CONTROLS("LHPF1", WM5100_HPLP1MIX_INPUT_1_SOURCE),
7286d4baf08SMark Brown WM5100_MIXER_CONTROLS("LHPF2", WM5100_HPLP2MIX_INPUT_1_SOURCE),
7296d4baf08SMark Brown WM5100_MIXER_CONTROLS("LHPF3", WM5100_HPLP3MIX_INPUT_1_SOURCE),
7306d4baf08SMark Brown WM5100_MIXER_CONTROLS("LHPF4", WM5100_HPLP4MIX_INPUT_1_SOURCE),
7316d4baf08SMark Brown };
7326d4baf08SMark Brown
wm5100_seq_notifier(struct snd_soc_component * component,enum snd_soc_dapm_type event,int subseq)73361195838SKuninori Morimoto static void wm5100_seq_notifier(struct snd_soc_component *component,
7346d4baf08SMark Brown enum snd_soc_dapm_type event, int subseq)
7356d4baf08SMark Brown {
73661195838SKuninori Morimoto struct wm5100_priv *wm5100 = snd_soc_component_get_drvdata(component);
7376d4baf08SMark Brown u16 val, expect, i;
7386d4baf08SMark Brown
7396d4baf08SMark Brown /* Wait for the outputs to flag themselves as enabled */
7406d4baf08SMark Brown if (wm5100->out_ena[0]) {
7416d75dfc3SKuninori Morimoto expect = snd_soc_component_read(component, WM5100_CHANNEL_ENABLES_1);
7426d4baf08SMark Brown for (i = 0; i < 200; i++) {
7436d75dfc3SKuninori Morimoto val = snd_soc_component_read(component, WM5100_OUTPUT_STATUS_1);
7446d4baf08SMark Brown if (val == expect) {
7456d4baf08SMark Brown wm5100->out_ena[0] = false;
7466d4baf08SMark Brown break;
7476d4baf08SMark Brown }
7486d4baf08SMark Brown }
7496d4baf08SMark Brown if (i == 200) {
75061195838SKuninori Morimoto dev_err(component->dev, "Timeout waiting for OUTPUT1 %x\n",
7516d4baf08SMark Brown expect);
7526d4baf08SMark Brown }
7536d4baf08SMark Brown }
7546d4baf08SMark Brown
7556d4baf08SMark Brown if (wm5100->out_ena[1]) {
7566d75dfc3SKuninori Morimoto expect = snd_soc_component_read(component, WM5100_OUTPUT_ENABLES_2);
7576d4baf08SMark Brown for (i = 0; i < 200; i++) {
7586d75dfc3SKuninori Morimoto val = snd_soc_component_read(component, WM5100_OUTPUT_STATUS_2);
7596d4baf08SMark Brown if (val == expect) {
7606d4baf08SMark Brown wm5100->out_ena[1] = false;
7616d4baf08SMark Brown break;
7626d4baf08SMark Brown }
7636d4baf08SMark Brown }
7646d4baf08SMark Brown if (i == 200) {
76561195838SKuninori Morimoto dev_err(component->dev, "Timeout waiting for OUTPUT2 %x\n",
7666d4baf08SMark Brown expect);
7676d4baf08SMark Brown }
7686d4baf08SMark Brown }
7696d4baf08SMark Brown }
7706d4baf08SMark Brown
wm5100_out_ev(struct snd_soc_dapm_widget * w,struct snd_kcontrol * kcontrol,int event)7716d4baf08SMark Brown static int wm5100_out_ev(struct snd_soc_dapm_widget *w,
7726d4baf08SMark Brown struct snd_kcontrol *kcontrol,
7736d4baf08SMark Brown int event)
7746d4baf08SMark Brown {
77561195838SKuninori Morimoto struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
77661195838SKuninori Morimoto struct wm5100_priv *wm5100 = snd_soc_component_get_drvdata(component);
7776d4baf08SMark Brown
7786d4baf08SMark Brown switch (w->reg) {
7796d4baf08SMark Brown case WM5100_CHANNEL_ENABLES_1:
7806d4baf08SMark Brown wm5100->out_ena[0] = true;
7816d4baf08SMark Brown break;
7826d4baf08SMark Brown case WM5100_OUTPUT_ENABLES_2:
7836d4baf08SMark Brown wm5100->out_ena[0] = true;
7846d4baf08SMark Brown break;
7856d4baf08SMark Brown default:
7866d4baf08SMark Brown break;
7876d4baf08SMark Brown }
7886d4baf08SMark Brown
7896d4baf08SMark Brown return 0;
7906d4baf08SMark Brown }
7916d4baf08SMark Brown
wm5100_log_status3(struct wm5100_priv * wm5100,int val)79246c1a877SMark Brown static void wm5100_log_status3(struct wm5100_priv *wm5100, int val)
7936d4baf08SMark Brown {
7946d4baf08SMark Brown if (val & WM5100_SPK_SHUTDOWN_WARN_EINT)
79546c1a877SMark Brown dev_crit(wm5100->dev, "Speaker shutdown warning\n");
7966d4baf08SMark Brown if (val & WM5100_SPK_SHUTDOWN_EINT)
79746c1a877SMark Brown dev_crit(wm5100->dev, "Speaker shutdown\n");
7986d4baf08SMark Brown if (val & WM5100_CLKGEN_ERR_EINT)
79946c1a877SMark Brown dev_crit(wm5100->dev, "SYSCLK underclocked\n");
8006d4baf08SMark Brown if (val & WM5100_CLKGEN_ERR_ASYNC_EINT)
80146c1a877SMark Brown dev_crit(wm5100->dev, "ASYNCCLK underclocked\n");
8026d4baf08SMark Brown }
8036d4baf08SMark Brown
wm5100_log_status4(struct wm5100_priv * wm5100,int val)80446c1a877SMark Brown static void wm5100_log_status4(struct wm5100_priv *wm5100, int val)
8056d4baf08SMark Brown {
8066d4baf08SMark Brown if (val & WM5100_AIF3_ERR_EINT)
80746c1a877SMark Brown dev_err(wm5100->dev, "AIF3 configuration error\n");
8086d4baf08SMark Brown if (val & WM5100_AIF2_ERR_EINT)
80946c1a877SMark Brown dev_err(wm5100->dev, "AIF2 configuration error\n");
8106d4baf08SMark Brown if (val & WM5100_AIF1_ERR_EINT)
81146c1a877SMark Brown dev_err(wm5100->dev, "AIF1 configuration error\n");
8126d4baf08SMark Brown if (val & WM5100_CTRLIF_ERR_EINT)
81346c1a877SMark Brown dev_err(wm5100->dev, "Control interface error\n");
8146d4baf08SMark Brown if (val & WM5100_ISRC2_UNDERCLOCKED_EINT)
81546c1a877SMark Brown dev_err(wm5100->dev, "ISRC2 underclocked\n");
8166d4baf08SMark Brown if (val & WM5100_ISRC1_UNDERCLOCKED_EINT)
81746c1a877SMark Brown dev_err(wm5100->dev, "ISRC1 underclocked\n");
8186d4baf08SMark Brown if (val & WM5100_FX_UNDERCLOCKED_EINT)
81946c1a877SMark Brown dev_err(wm5100->dev, "FX underclocked\n");
8206d4baf08SMark Brown if (val & WM5100_AIF3_UNDERCLOCKED_EINT)
82146c1a877SMark Brown dev_err(wm5100->dev, "AIF3 underclocked\n");
8226d4baf08SMark Brown if (val & WM5100_AIF2_UNDERCLOCKED_EINT)
82346c1a877SMark Brown dev_err(wm5100->dev, "AIF2 underclocked\n");
8246d4baf08SMark Brown if (val & WM5100_AIF1_UNDERCLOCKED_EINT)
82546c1a877SMark Brown dev_err(wm5100->dev, "AIF1 underclocked\n");
8266d4baf08SMark Brown if (val & WM5100_ASRC_UNDERCLOCKED_EINT)
82746c1a877SMark Brown dev_err(wm5100->dev, "ASRC underclocked\n");
8286d4baf08SMark Brown if (val & WM5100_DAC_UNDERCLOCKED_EINT)
82946c1a877SMark Brown dev_err(wm5100->dev, "DAC underclocked\n");
8306d4baf08SMark Brown if (val & WM5100_ADC_UNDERCLOCKED_EINT)
83146c1a877SMark Brown dev_err(wm5100->dev, "ADC underclocked\n");
8326d4baf08SMark Brown if (val & WM5100_MIXER_UNDERCLOCKED_EINT)
83346c1a877SMark Brown dev_err(wm5100->dev, "Mixer underclocked\n");
8346d4baf08SMark Brown }
8356d4baf08SMark Brown
wm5100_post_ev(struct snd_soc_dapm_widget * w,struct snd_kcontrol * kcontrol,int event)8366d4baf08SMark Brown static int wm5100_post_ev(struct snd_soc_dapm_widget *w,
8376d4baf08SMark Brown struct snd_kcontrol *kcontrol,
8386d4baf08SMark Brown int event)
8396d4baf08SMark Brown {
84061195838SKuninori Morimoto struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
84161195838SKuninori Morimoto struct wm5100_priv *wm5100 = snd_soc_component_get_drvdata(component);
8426d4baf08SMark Brown int ret;
8436d4baf08SMark Brown
8446d75dfc3SKuninori Morimoto ret = snd_soc_component_read(component, WM5100_INTERRUPT_RAW_STATUS_3);
8456d4baf08SMark Brown ret &= WM5100_SPK_SHUTDOWN_WARN_STS |
8466d4baf08SMark Brown WM5100_SPK_SHUTDOWN_STS | WM5100_CLKGEN_ERR_STS |
8476d4baf08SMark Brown WM5100_CLKGEN_ERR_ASYNC_STS;
84846c1a877SMark Brown wm5100_log_status3(wm5100, ret);
8496d4baf08SMark Brown
8506d75dfc3SKuninori Morimoto ret = snd_soc_component_read(component, WM5100_INTERRUPT_RAW_STATUS_4);
85146c1a877SMark Brown wm5100_log_status4(wm5100, ret);
8526d4baf08SMark Brown
8536d4baf08SMark Brown return 0;
8546d4baf08SMark Brown }
8556d4baf08SMark Brown
8566d4baf08SMark Brown static const struct snd_soc_dapm_widget wm5100_dapm_widgets[] = {
8576d4baf08SMark Brown SND_SOC_DAPM_SUPPLY("SYSCLK", WM5100_CLOCKING_3, WM5100_SYSCLK_ENA_SHIFT, 0,
8586d4baf08SMark Brown NULL, 0),
8596d4baf08SMark Brown SND_SOC_DAPM_SUPPLY("ASYNCCLK", WM5100_CLOCKING_6, WM5100_ASYNC_CLK_ENA_SHIFT,
8606d4baf08SMark Brown 0, NULL, 0),
8616d4baf08SMark Brown
862822b4b8dSMark Brown SND_SOC_DAPM_REGULATOR_SUPPLY("CPVDD", 20, 0),
863822b4b8dSMark Brown SND_SOC_DAPM_REGULATOR_SUPPLY("DBVDD2", 0, 0),
864822b4b8dSMark Brown SND_SOC_DAPM_REGULATOR_SUPPLY("DBVDD3", 0, 0),
8651cf73356SMark Brown
8666d4baf08SMark Brown SND_SOC_DAPM_SUPPLY("CP1", WM5100_HP_CHARGE_PUMP_1, WM5100_CP1_ENA_SHIFT, 0,
8671cf73356SMark Brown NULL, 0),
8686d4baf08SMark Brown SND_SOC_DAPM_SUPPLY("CP2", WM5100_MIC_CHARGE_PUMP_1, WM5100_CP2_ENA_SHIFT, 0,
8696d4baf08SMark Brown NULL, 0),
8706d4baf08SMark Brown SND_SOC_DAPM_SUPPLY("CP2 Active", WM5100_MIC_CHARGE_PUMP_1,
8711cf73356SMark Brown WM5100_CP2_BYPASS_SHIFT, 1, NULL, 0),
8726d4baf08SMark Brown
8736d4baf08SMark Brown SND_SOC_DAPM_SUPPLY("MICBIAS1", WM5100_MIC_BIAS_CTRL_1, WM5100_MICB1_ENA_SHIFT,
8746d4baf08SMark Brown 0, NULL, 0),
8756d4baf08SMark Brown SND_SOC_DAPM_SUPPLY("MICBIAS2", WM5100_MIC_BIAS_CTRL_2, WM5100_MICB2_ENA_SHIFT,
8766d4baf08SMark Brown 0, NULL, 0),
8776d4baf08SMark Brown SND_SOC_DAPM_SUPPLY("MICBIAS3", WM5100_MIC_BIAS_CTRL_3, WM5100_MICB3_ENA_SHIFT,
8786d4baf08SMark Brown 0, NULL, 0),
8796d4baf08SMark Brown
8806d4baf08SMark Brown SND_SOC_DAPM_INPUT("IN1L"),
8816d4baf08SMark Brown SND_SOC_DAPM_INPUT("IN1R"),
8826d4baf08SMark Brown SND_SOC_DAPM_INPUT("IN2L"),
8836d4baf08SMark Brown SND_SOC_DAPM_INPUT("IN2R"),
8846d4baf08SMark Brown SND_SOC_DAPM_INPUT("IN3L"),
8856d4baf08SMark Brown SND_SOC_DAPM_INPUT("IN3R"),
8866d4baf08SMark Brown SND_SOC_DAPM_INPUT("IN4L"),
8876d4baf08SMark Brown SND_SOC_DAPM_INPUT("IN4R"),
888dea8e237SMark Brown SND_SOC_DAPM_SIGGEN("TONE"),
8896d4baf08SMark Brown
8906d4baf08SMark Brown SND_SOC_DAPM_PGA_E("IN1L PGA", WM5100_INPUT_ENABLES, WM5100_IN1L_ENA_SHIFT, 0,
8916d4baf08SMark Brown NULL, 0, wm5100_out_ev, SND_SOC_DAPM_POST_PMU),
8926d4baf08SMark Brown SND_SOC_DAPM_PGA_E("IN1R PGA", WM5100_INPUT_ENABLES, WM5100_IN1R_ENA_SHIFT, 0,
8936d4baf08SMark Brown NULL, 0, wm5100_out_ev, SND_SOC_DAPM_POST_PMU),
8946d4baf08SMark Brown SND_SOC_DAPM_PGA_E("IN2L PGA", WM5100_INPUT_ENABLES, WM5100_IN2L_ENA_SHIFT, 0,
8956d4baf08SMark Brown NULL, 0, wm5100_out_ev, SND_SOC_DAPM_POST_PMU),
8966d4baf08SMark Brown SND_SOC_DAPM_PGA_E("IN2R PGA", WM5100_INPUT_ENABLES, WM5100_IN2R_ENA_SHIFT, 0,
8976d4baf08SMark Brown NULL, 0, wm5100_out_ev, SND_SOC_DAPM_POST_PMU),
8986d4baf08SMark Brown SND_SOC_DAPM_PGA_E("IN3L PGA", WM5100_INPUT_ENABLES, WM5100_IN3L_ENA_SHIFT, 0,
8996d4baf08SMark Brown NULL, 0, wm5100_out_ev, SND_SOC_DAPM_POST_PMU),
9006d4baf08SMark Brown SND_SOC_DAPM_PGA_E("IN3R PGA", WM5100_INPUT_ENABLES, WM5100_IN3R_ENA_SHIFT, 0,
9016d4baf08SMark Brown NULL, 0, wm5100_out_ev, SND_SOC_DAPM_POST_PMU),
9026d4baf08SMark Brown SND_SOC_DAPM_PGA_E("IN4L PGA", WM5100_INPUT_ENABLES, WM5100_IN4L_ENA_SHIFT, 0,
9036d4baf08SMark Brown NULL, 0, wm5100_out_ev, SND_SOC_DAPM_POST_PMU),
9046d4baf08SMark Brown SND_SOC_DAPM_PGA_E("IN4R PGA", WM5100_INPUT_ENABLES, WM5100_IN4R_ENA_SHIFT, 0,
9056d4baf08SMark Brown NULL, 0, wm5100_out_ev, SND_SOC_DAPM_POST_PMU),
9066d4baf08SMark Brown
9076d4baf08SMark Brown SND_SOC_DAPM_PGA("Tone Generator 1", WM5100_TONE_GENERATOR_1,
9086d4baf08SMark Brown WM5100_TONE1_ENA_SHIFT, 0, NULL, 0),
9096d4baf08SMark Brown SND_SOC_DAPM_PGA("Tone Generator 2", WM5100_TONE_GENERATOR_1,
9106d4baf08SMark Brown WM5100_TONE2_ENA_SHIFT, 0, NULL, 0),
9116d4baf08SMark Brown
9126d4baf08SMark Brown SND_SOC_DAPM_AIF_IN("AIF1RX1", "AIF1 Playback", 0,
9136d4baf08SMark Brown WM5100_AUDIO_IF_1_27, WM5100_AIF1RX1_ENA_SHIFT, 0),
9146d4baf08SMark Brown SND_SOC_DAPM_AIF_IN("AIF1RX2", "AIF1 Playback", 1,
9156d4baf08SMark Brown WM5100_AUDIO_IF_1_27, WM5100_AIF1RX2_ENA_SHIFT, 0),
9166d4baf08SMark Brown SND_SOC_DAPM_AIF_IN("AIF1RX3", "AIF1 Playback", 2,
9176d4baf08SMark Brown WM5100_AUDIO_IF_1_27, WM5100_AIF1RX3_ENA_SHIFT, 0),
9186d4baf08SMark Brown SND_SOC_DAPM_AIF_IN("AIF1RX4", "AIF1 Playback", 3,
9196d4baf08SMark Brown WM5100_AUDIO_IF_1_27, WM5100_AIF1RX4_ENA_SHIFT, 0),
9206d4baf08SMark Brown SND_SOC_DAPM_AIF_IN("AIF1RX5", "AIF1 Playback", 4,
9216d4baf08SMark Brown WM5100_AUDIO_IF_1_27, WM5100_AIF1RX5_ENA_SHIFT, 0),
9226d4baf08SMark Brown SND_SOC_DAPM_AIF_IN("AIF1RX6", "AIF1 Playback", 5,
9236d4baf08SMark Brown WM5100_AUDIO_IF_1_27, WM5100_AIF1RX6_ENA_SHIFT, 0),
9246d4baf08SMark Brown SND_SOC_DAPM_AIF_IN("AIF1RX7", "AIF1 Playback", 6,
9256d4baf08SMark Brown WM5100_AUDIO_IF_1_27, WM5100_AIF1RX7_ENA_SHIFT, 0),
9266d4baf08SMark Brown SND_SOC_DAPM_AIF_IN("AIF1RX8", "AIF1 Playback", 7,
9276d4baf08SMark Brown WM5100_AUDIO_IF_1_27, WM5100_AIF1RX8_ENA_SHIFT, 0),
9286d4baf08SMark Brown
9296d4baf08SMark Brown SND_SOC_DAPM_AIF_IN("AIF2RX1", "AIF2 Playback", 0,
9306d4baf08SMark Brown WM5100_AUDIO_IF_2_27, WM5100_AIF2RX1_ENA_SHIFT, 0),
9316d4baf08SMark Brown SND_SOC_DAPM_AIF_IN("AIF2RX2", "AIF2 Playback", 1,
9326d4baf08SMark Brown WM5100_AUDIO_IF_2_27, WM5100_AIF2RX2_ENA_SHIFT, 0),
9336d4baf08SMark Brown
9346d4baf08SMark Brown SND_SOC_DAPM_AIF_IN("AIF3RX1", "AIF3 Playback", 0,
9356d4baf08SMark Brown WM5100_AUDIO_IF_3_27, WM5100_AIF3RX1_ENA_SHIFT, 0),
9366d4baf08SMark Brown SND_SOC_DAPM_AIF_IN("AIF3RX2", "AIF3 Playback", 1,
9376d4baf08SMark Brown WM5100_AUDIO_IF_3_27, WM5100_AIF3RX2_ENA_SHIFT, 0),
9386d4baf08SMark Brown
9396d4baf08SMark Brown SND_SOC_DAPM_AIF_OUT("AIF1TX1", "AIF1 Capture", 0,
9406d4baf08SMark Brown WM5100_AUDIO_IF_1_26, WM5100_AIF1TX1_ENA_SHIFT, 0),
9416d4baf08SMark Brown SND_SOC_DAPM_AIF_OUT("AIF1TX2", "AIF1 Capture", 1,
9426d4baf08SMark Brown WM5100_AUDIO_IF_1_26, WM5100_AIF1TX2_ENA_SHIFT, 0),
9436d4baf08SMark Brown SND_SOC_DAPM_AIF_OUT("AIF1TX3", "AIF1 Capture", 2,
9446d4baf08SMark Brown WM5100_AUDIO_IF_1_26, WM5100_AIF1TX3_ENA_SHIFT, 0),
9456d4baf08SMark Brown SND_SOC_DAPM_AIF_OUT("AIF1TX4", "AIF1 Capture", 3,
9466d4baf08SMark Brown WM5100_AUDIO_IF_1_26, WM5100_AIF1TX4_ENA_SHIFT, 0),
9476d4baf08SMark Brown SND_SOC_DAPM_AIF_OUT("AIF1TX5", "AIF1 Capture", 4,
9486d4baf08SMark Brown WM5100_AUDIO_IF_1_26, WM5100_AIF1TX5_ENA_SHIFT, 0),
9496d4baf08SMark Brown SND_SOC_DAPM_AIF_OUT("AIF1TX6", "AIF1 Capture", 5,
9506d4baf08SMark Brown WM5100_AUDIO_IF_1_26, WM5100_AIF1TX6_ENA_SHIFT, 0),
9516d4baf08SMark Brown SND_SOC_DAPM_AIF_OUT("AIF1TX7", "AIF1 Capture", 6,
9526d4baf08SMark Brown WM5100_AUDIO_IF_1_26, WM5100_AIF1TX7_ENA_SHIFT, 0),
9536d4baf08SMark Brown SND_SOC_DAPM_AIF_OUT("AIF1TX8", "AIF1 Capture", 7,
9546d4baf08SMark Brown WM5100_AUDIO_IF_1_26, WM5100_AIF1TX8_ENA_SHIFT, 0),
9556d4baf08SMark Brown
9566d4baf08SMark Brown SND_SOC_DAPM_AIF_OUT("AIF2TX1", "AIF2 Capture", 0,
9576d4baf08SMark Brown WM5100_AUDIO_IF_2_26, WM5100_AIF2TX1_ENA_SHIFT, 0),
9586d4baf08SMark Brown SND_SOC_DAPM_AIF_OUT("AIF2TX2", "AIF2 Capture", 1,
9596d4baf08SMark Brown WM5100_AUDIO_IF_2_26, WM5100_AIF2TX2_ENA_SHIFT, 0),
9606d4baf08SMark Brown
9616d4baf08SMark Brown SND_SOC_DAPM_AIF_OUT("AIF3TX1", "AIF3 Capture", 0,
9626d4baf08SMark Brown WM5100_AUDIO_IF_3_26, WM5100_AIF3TX1_ENA_SHIFT, 0),
9636d4baf08SMark Brown SND_SOC_DAPM_AIF_OUT("AIF3TX2", "AIF3 Capture", 1,
9646d4baf08SMark Brown WM5100_AUDIO_IF_3_26, WM5100_AIF3TX2_ENA_SHIFT, 0),
9656d4baf08SMark Brown
9666d4baf08SMark Brown SND_SOC_DAPM_PGA_E("OUT6L", WM5100_OUTPUT_ENABLES_2, WM5100_OUT6L_ENA_SHIFT, 0,
9676d4baf08SMark Brown NULL, 0, wm5100_out_ev, SND_SOC_DAPM_POST_PMU),
9686d4baf08SMark Brown SND_SOC_DAPM_PGA_E("OUT6R", WM5100_OUTPUT_ENABLES_2, WM5100_OUT6R_ENA_SHIFT, 0,
9696d4baf08SMark Brown NULL, 0, wm5100_out_ev, SND_SOC_DAPM_POST_PMU),
9706d4baf08SMark Brown SND_SOC_DAPM_PGA_E("OUT5L", WM5100_OUTPUT_ENABLES_2, WM5100_OUT5L_ENA_SHIFT, 0,
9716d4baf08SMark Brown NULL, 0, wm5100_out_ev, SND_SOC_DAPM_POST_PMU),
9726d4baf08SMark Brown SND_SOC_DAPM_PGA_E("OUT5R", WM5100_OUTPUT_ENABLES_2, WM5100_OUT5R_ENA_SHIFT, 0,
9736d4baf08SMark Brown NULL, 0, wm5100_out_ev, SND_SOC_DAPM_POST_PMU),
9746d4baf08SMark Brown SND_SOC_DAPM_PGA_E("OUT4L", WM5100_OUTPUT_ENABLES_2, WM5100_OUT4L_ENA_SHIFT, 0,
9756d4baf08SMark Brown NULL, 0, wm5100_out_ev, SND_SOC_DAPM_POST_PMU),
9766d4baf08SMark Brown SND_SOC_DAPM_PGA_E("OUT4R", WM5100_OUTPUT_ENABLES_2, WM5100_OUT4R_ENA_SHIFT, 0,
9776d4baf08SMark Brown NULL, 0, wm5100_out_ev, SND_SOC_DAPM_POST_PMU),
9786d4baf08SMark Brown SND_SOC_DAPM_PGA_E("OUT3L", WM5100_CHANNEL_ENABLES_1, WM5100_HP3L_ENA_SHIFT, 0,
9796d4baf08SMark Brown NULL, 0, wm5100_out_ev, SND_SOC_DAPM_POST_PMU),
9806d4baf08SMark Brown SND_SOC_DAPM_PGA_E("OUT3R", WM5100_CHANNEL_ENABLES_1, WM5100_HP3R_ENA_SHIFT, 0,
9816d4baf08SMark Brown NULL, 0, wm5100_out_ev, SND_SOC_DAPM_POST_PMU),
9826d4baf08SMark Brown SND_SOC_DAPM_PGA_E("OUT2L", WM5100_CHANNEL_ENABLES_1, WM5100_HP2L_ENA_SHIFT, 0,
9836d4baf08SMark Brown NULL, 0, wm5100_out_ev, SND_SOC_DAPM_POST_PMU),
9846d4baf08SMark Brown SND_SOC_DAPM_PGA_E("OUT2R", WM5100_CHANNEL_ENABLES_1, WM5100_HP2R_ENA_SHIFT, 0,
9856d4baf08SMark Brown NULL, 0, wm5100_out_ev, SND_SOC_DAPM_POST_PMU),
9866d4baf08SMark Brown SND_SOC_DAPM_PGA_E("OUT1L", WM5100_CHANNEL_ENABLES_1, WM5100_HP1L_ENA_SHIFT, 0,
9876d4baf08SMark Brown NULL, 0, wm5100_out_ev, SND_SOC_DAPM_POST_PMU),
9886d4baf08SMark Brown SND_SOC_DAPM_PGA_E("OUT1R", WM5100_CHANNEL_ENABLES_1, WM5100_HP1R_ENA_SHIFT, 0,
9896d4baf08SMark Brown NULL, 0, wm5100_out_ev, SND_SOC_DAPM_POST_PMU),
9906d4baf08SMark Brown SND_SOC_DAPM_PGA_E("PWM1 Driver", WM5100_PWM_DRIVE_1, WM5100_PWM1_ENA_SHIFT, 0,
9916d4baf08SMark Brown NULL, 0, wm5100_out_ev, SND_SOC_DAPM_POST_PMU),
9926d4baf08SMark Brown SND_SOC_DAPM_PGA_E("PWM2 Driver", WM5100_PWM_DRIVE_1, WM5100_PWM2_ENA_SHIFT, 0,
9936d4baf08SMark Brown NULL, 0, wm5100_out_ev, SND_SOC_DAPM_POST_PMU),
9946d4baf08SMark Brown
9956d4baf08SMark Brown SND_SOC_DAPM_PGA("EQ1", WM5100_EQ1_1, WM5100_EQ1_ENA_SHIFT, 0, NULL, 0),
9966d4baf08SMark Brown SND_SOC_DAPM_PGA("EQ2", WM5100_EQ2_1, WM5100_EQ2_ENA_SHIFT, 0, NULL, 0),
9976d4baf08SMark Brown SND_SOC_DAPM_PGA("EQ3", WM5100_EQ3_1, WM5100_EQ3_ENA_SHIFT, 0, NULL, 0),
9986d4baf08SMark Brown SND_SOC_DAPM_PGA("EQ4", WM5100_EQ4_1, WM5100_EQ4_ENA_SHIFT, 0, NULL, 0),
9996d4baf08SMark Brown
10006d4baf08SMark Brown SND_SOC_DAPM_PGA("DRC1L", WM5100_DRC1_CTRL1, WM5100_DRCL_ENA_SHIFT, 0,
10016d4baf08SMark Brown NULL, 0),
10026d4baf08SMark Brown SND_SOC_DAPM_PGA("DRC1R", WM5100_DRC1_CTRL1, WM5100_DRCR_ENA_SHIFT, 0,
10036d4baf08SMark Brown NULL, 0),
10046d4baf08SMark Brown
10056d4baf08SMark Brown SND_SOC_DAPM_PGA("LHPF1", WM5100_HPLPF1_1, WM5100_LHPF1_ENA_SHIFT, 0,
10066d4baf08SMark Brown NULL, 0),
10076d4baf08SMark Brown SND_SOC_DAPM_PGA("LHPF2", WM5100_HPLPF2_1, WM5100_LHPF2_ENA_SHIFT, 0,
10086d4baf08SMark Brown NULL, 0),
10096d4baf08SMark Brown SND_SOC_DAPM_PGA("LHPF3", WM5100_HPLPF3_1, WM5100_LHPF3_ENA_SHIFT, 0,
10106d4baf08SMark Brown NULL, 0),
10116d4baf08SMark Brown SND_SOC_DAPM_PGA("LHPF4", WM5100_HPLPF4_1, WM5100_LHPF4_ENA_SHIFT, 0,
10126d4baf08SMark Brown NULL, 0),
10136d4baf08SMark Brown
10146d4baf08SMark Brown WM5100_MIXER_WIDGETS(EQ1, "EQ1"),
10156d4baf08SMark Brown WM5100_MIXER_WIDGETS(EQ2, "EQ2"),
10166d4baf08SMark Brown WM5100_MIXER_WIDGETS(EQ3, "EQ3"),
10176d4baf08SMark Brown WM5100_MIXER_WIDGETS(EQ4, "EQ4"),
10186d4baf08SMark Brown
10196d4baf08SMark Brown WM5100_MIXER_WIDGETS(DRC1L, "DRC1L"),
10206d4baf08SMark Brown WM5100_MIXER_WIDGETS(DRC1R, "DRC1R"),
10216d4baf08SMark Brown
10226d4baf08SMark Brown WM5100_MIXER_WIDGETS(LHPF1, "LHPF1"),
10236d4baf08SMark Brown WM5100_MIXER_WIDGETS(LHPF2, "LHPF2"),
10246d4baf08SMark Brown WM5100_MIXER_WIDGETS(LHPF3, "LHPF3"),
10256d4baf08SMark Brown WM5100_MIXER_WIDGETS(LHPF4, "LHPF4"),
10266d4baf08SMark Brown
10276d4baf08SMark Brown WM5100_MIXER_WIDGETS(AIF1TX1, "AIF1TX1"),
10286d4baf08SMark Brown WM5100_MIXER_WIDGETS(AIF1TX2, "AIF1TX2"),
10296d4baf08SMark Brown WM5100_MIXER_WIDGETS(AIF1TX3, "AIF1TX3"),
10306d4baf08SMark Brown WM5100_MIXER_WIDGETS(AIF1TX4, "AIF1TX4"),
10316d4baf08SMark Brown WM5100_MIXER_WIDGETS(AIF1TX5, "AIF1TX5"),
10326d4baf08SMark Brown WM5100_MIXER_WIDGETS(AIF1TX6, "AIF1TX6"),
10336d4baf08SMark Brown WM5100_MIXER_WIDGETS(AIF1TX7, "AIF1TX7"),
10346d4baf08SMark Brown WM5100_MIXER_WIDGETS(AIF1TX8, "AIF1TX8"),
10356d4baf08SMark Brown
10366d4baf08SMark Brown WM5100_MIXER_WIDGETS(AIF2TX1, "AIF2TX1"),
10376d4baf08SMark Brown WM5100_MIXER_WIDGETS(AIF2TX2, "AIF2TX2"),
10386d4baf08SMark Brown
10396d4baf08SMark Brown WM5100_MIXER_WIDGETS(AIF3TX1, "AIF3TX1"),
10406d4baf08SMark Brown WM5100_MIXER_WIDGETS(AIF3TX2, "AIF3TX2"),
10416d4baf08SMark Brown
10426d4baf08SMark Brown WM5100_MIXER_WIDGETS(HPOUT1L, "HPOUT1L"),
10436d4baf08SMark Brown WM5100_MIXER_WIDGETS(HPOUT1R, "HPOUT1R"),
10446d4baf08SMark Brown WM5100_MIXER_WIDGETS(HPOUT2L, "HPOUT2L"),
10456d4baf08SMark Brown WM5100_MIXER_WIDGETS(HPOUT2R, "HPOUT2R"),
10466d4baf08SMark Brown WM5100_MIXER_WIDGETS(HPOUT3L, "HPOUT3L"),
10476d4baf08SMark Brown WM5100_MIXER_WIDGETS(HPOUT3R, "HPOUT3R"),
10486d4baf08SMark Brown
10496d4baf08SMark Brown WM5100_MIXER_WIDGETS(SPKOUTL, "SPKOUTL"),
10506d4baf08SMark Brown WM5100_MIXER_WIDGETS(SPKOUTR, "SPKOUTR"),
10516d4baf08SMark Brown WM5100_MIXER_WIDGETS(SPKDAT1L, "SPKDAT1L"),
10526d4baf08SMark Brown WM5100_MIXER_WIDGETS(SPKDAT1R, "SPKDAT1R"),
10536d4baf08SMark Brown WM5100_MIXER_WIDGETS(SPKDAT2L, "SPKDAT2L"),
10546d4baf08SMark Brown WM5100_MIXER_WIDGETS(SPKDAT2R, "SPKDAT2R"),
10556d4baf08SMark Brown
10566d4baf08SMark Brown WM5100_MIXER_WIDGETS(PWM1, "PWM1"),
10576d4baf08SMark Brown WM5100_MIXER_WIDGETS(PWM2, "PWM2"),
10586d4baf08SMark Brown
10596d4baf08SMark Brown SND_SOC_DAPM_OUTPUT("HPOUT1L"),
10606d4baf08SMark Brown SND_SOC_DAPM_OUTPUT("HPOUT1R"),
10616d4baf08SMark Brown SND_SOC_DAPM_OUTPUT("HPOUT2L"),
10626d4baf08SMark Brown SND_SOC_DAPM_OUTPUT("HPOUT2R"),
10636d4baf08SMark Brown SND_SOC_DAPM_OUTPUT("HPOUT3L"),
10646d4baf08SMark Brown SND_SOC_DAPM_OUTPUT("HPOUT3R"),
10656d4baf08SMark Brown SND_SOC_DAPM_OUTPUT("SPKOUTL"),
10666d4baf08SMark Brown SND_SOC_DAPM_OUTPUT("SPKOUTR"),
10676d4baf08SMark Brown SND_SOC_DAPM_OUTPUT("SPKDAT1"),
10686d4baf08SMark Brown SND_SOC_DAPM_OUTPUT("SPKDAT2"),
10696d4baf08SMark Brown SND_SOC_DAPM_OUTPUT("PWM1"),
10706d4baf08SMark Brown SND_SOC_DAPM_OUTPUT("PWM2"),
10716d4baf08SMark Brown };
10726d4baf08SMark Brown
10736d4baf08SMark Brown /* We register a _POST event if we don't have IRQ support so we can
10746d4baf08SMark Brown * look at the error status from the CODEC - if we've got the IRQ
10756d4baf08SMark Brown * hooked up then we will get prompted to look by an interrupt.
10766d4baf08SMark Brown */
10776d4baf08SMark Brown static const struct snd_soc_dapm_widget wm5100_dapm_widgets_noirq[] = {
10786d4baf08SMark Brown SND_SOC_DAPM_POST("Post", wm5100_post_ev),
10796d4baf08SMark Brown };
10806d4baf08SMark Brown
10816d4baf08SMark Brown static const struct snd_soc_dapm_route wm5100_dapm_routes[] = {
10821cf73356SMark Brown { "CP1", NULL, "CPVDD" },
10831cf73356SMark Brown { "CP2 Active", NULL, "CPVDD" },
10841cf73356SMark Brown
10856d4baf08SMark Brown { "IN1L", NULL, "SYSCLK" },
10866d4baf08SMark Brown { "IN1R", NULL, "SYSCLK" },
10876d4baf08SMark Brown { "IN2L", NULL, "SYSCLK" },
10886d4baf08SMark Brown { "IN2R", NULL, "SYSCLK" },
10896d4baf08SMark Brown { "IN3L", NULL, "SYSCLK" },
10906d4baf08SMark Brown { "IN3R", NULL, "SYSCLK" },
10916d4baf08SMark Brown { "IN4L", NULL, "SYSCLK" },
10926d4baf08SMark Brown { "IN4R", NULL, "SYSCLK" },
10936d4baf08SMark Brown
10946d4baf08SMark Brown { "OUT1L", NULL, "SYSCLK" },
10956d4baf08SMark Brown { "OUT1R", NULL, "SYSCLK" },
10966d4baf08SMark Brown { "OUT2L", NULL, "SYSCLK" },
10976d4baf08SMark Brown { "OUT2R", NULL, "SYSCLK" },
10986d4baf08SMark Brown { "OUT3L", NULL, "SYSCLK" },
10996d4baf08SMark Brown { "OUT3R", NULL, "SYSCLK" },
11006d4baf08SMark Brown { "OUT4L", NULL, "SYSCLK" },
11016d4baf08SMark Brown { "OUT4R", NULL, "SYSCLK" },
11026d4baf08SMark Brown { "OUT5L", NULL, "SYSCLK" },
11036d4baf08SMark Brown { "OUT5R", NULL, "SYSCLK" },
11046d4baf08SMark Brown { "OUT6L", NULL, "SYSCLK" },
11056d4baf08SMark Brown { "OUT6R", NULL, "SYSCLK" },
11066d4baf08SMark Brown
11076d4baf08SMark Brown { "AIF1RX1", NULL, "SYSCLK" },
11086d4baf08SMark Brown { "AIF1RX2", NULL, "SYSCLK" },
11096d4baf08SMark Brown { "AIF1RX3", NULL, "SYSCLK" },
11106d4baf08SMark Brown { "AIF1RX4", NULL, "SYSCLK" },
11116d4baf08SMark Brown { "AIF1RX5", NULL, "SYSCLK" },
11126d4baf08SMark Brown { "AIF1RX6", NULL, "SYSCLK" },
11136d4baf08SMark Brown { "AIF1RX7", NULL, "SYSCLK" },
11146d4baf08SMark Brown { "AIF1RX8", NULL, "SYSCLK" },
11156d4baf08SMark Brown
11166d4baf08SMark Brown { "AIF2RX1", NULL, "SYSCLK" },
11177aefb086SMark Brown { "AIF2RX1", NULL, "DBVDD2" },
11186d4baf08SMark Brown { "AIF2RX2", NULL, "SYSCLK" },
11197aefb086SMark Brown { "AIF2RX2", NULL, "DBVDD2" },
11206d4baf08SMark Brown
11216d4baf08SMark Brown { "AIF3RX1", NULL, "SYSCLK" },
11227aefb086SMark Brown { "AIF3RX1", NULL, "DBVDD3" },
11236d4baf08SMark Brown { "AIF3RX2", NULL, "SYSCLK" },
11247aefb086SMark Brown { "AIF3RX2", NULL, "DBVDD3" },
11256d4baf08SMark Brown
11266d4baf08SMark Brown { "AIF1TX1", NULL, "SYSCLK" },
11276d4baf08SMark Brown { "AIF1TX2", NULL, "SYSCLK" },
11286d4baf08SMark Brown { "AIF1TX3", NULL, "SYSCLK" },
11296d4baf08SMark Brown { "AIF1TX4", NULL, "SYSCLK" },
11306d4baf08SMark Brown { "AIF1TX5", NULL, "SYSCLK" },
11316d4baf08SMark Brown { "AIF1TX6", NULL, "SYSCLK" },
11326d4baf08SMark Brown { "AIF1TX7", NULL, "SYSCLK" },
11336d4baf08SMark Brown { "AIF1TX8", NULL, "SYSCLK" },
11346d4baf08SMark Brown
11356d4baf08SMark Brown { "AIF2TX1", NULL, "SYSCLK" },
11367aefb086SMark Brown { "AIF2TX1", NULL, "DBVDD2" },
11376d4baf08SMark Brown { "AIF2TX2", NULL, "SYSCLK" },
11387aefb086SMark Brown { "AIF2TX2", NULL, "DBVDD2" },
11396d4baf08SMark Brown
11406d4baf08SMark Brown { "AIF3TX1", NULL, "SYSCLK" },
11417aefb086SMark Brown { "AIF3TX1", NULL, "DBVDD3" },
11426d4baf08SMark Brown { "AIF3TX2", NULL, "SYSCLK" },
11437aefb086SMark Brown { "AIF3TX2", NULL, "DBVDD3" },
11446d4baf08SMark Brown
11456d4baf08SMark Brown { "MICBIAS1", NULL, "CP2" },
11466d4baf08SMark Brown { "MICBIAS2", NULL, "CP2" },
11476d4baf08SMark Brown { "MICBIAS3", NULL, "CP2" },
11486d4baf08SMark Brown
11496d4baf08SMark Brown { "IN1L PGA", NULL, "CP2" },
11506d4baf08SMark Brown { "IN1R PGA", NULL, "CP2" },
11516d4baf08SMark Brown { "IN2L PGA", NULL, "CP2" },
11526d4baf08SMark Brown { "IN2R PGA", NULL, "CP2" },
11536d4baf08SMark Brown { "IN3L PGA", NULL, "CP2" },
11546d4baf08SMark Brown { "IN3R PGA", NULL, "CP2" },
11556d4baf08SMark Brown { "IN4L PGA", NULL, "CP2" },
11566d4baf08SMark Brown { "IN4R PGA", NULL, "CP2" },
11576d4baf08SMark Brown
11586d4baf08SMark Brown { "IN1L PGA", NULL, "CP2 Active" },
11596d4baf08SMark Brown { "IN1R PGA", NULL, "CP2 Active" },
11606d4baf08SMark Brown { "IN2L PGA", NULL, "CP2 Active" },
11616d4baf08SMark Brown { "IN2R PGA", NULL, "CP2 Active" },
11626d4baf08SMark Brown { "IN3L PGA", NULL, "CP2 Active" },
11636d4baf08SMark Brown { "IN3R PGA", NULL, "CP2 Active" },
11646d4baf08SMark Brown { "IN4L PGA", NULL, "CP2 Active" },
11656d4baf08SMark Brown { "IN4R PGA", NULL, "CP2 Active" },
11666d4baf08SMark Brown
11676d4baf08SMark Brown { "OUT1L", NULL, "CP1" },
11686d4baf08SMark Brown { "OUT1R", NULL, "CP1" },
11696d4baf08SMark Brown { "OUT2L", NULL, "CP1" },
11706d4baf08SMark Brown { "OUT2R", NULL, "CP1" },
11716d4baf08SMark Brown { "OUT3L", NULL, "CP1" },
11726d4baf08SMark Brown { "OUT3R", NULL, "CP1" },
11736d4baf08SMark Brown
11746d4baf08SMark Brown { "Tone Generator 1", NULL, "TONE" },
11756d4baf08SMark Brown { "Tone Generator 2", NULL, "TONE" },
11766d4baf08SMark Brown
11776d4baf08SMark Brown { "IN1L PGA", NULL, "IN1L" },
11786d4baf08SMark Brown { "IN1R PGA", NULL, "IN1R" },
11796d4baf08SMark Brown { "IN2L PGA", NULL, "IN2L" },
11806d4baf08SMark Brown { "IN2R PGA", NULL, "IN2R" },
11816d4baf08SMark Brown { "IN3L PGA", NULL, "IN3L" },
11826d4baf08SMark Brown { "IN3R PGA", NULL, "IN3R" },
11836d4baf08SMark Brown { "IN4L PGA", NULL, "IN4L" },
11846d4baf08SMark Brown { "IN4R PGA", NULL, "IN4R" },
11856d4baf08SMark Brown
11866d4baf08SMark Brown WM5100_MIXER_ROUTES("OUT1L", "HPOUT1L"),
11876d4baf08SMark Brown WM5100_MIXER_ROUTES("OUT1R", "HPOUT1R"),
11886d4baf08SMark Brown WM5100_MIXER_ROUTES("OUT2L", "HPOUT2L"),
11896d4baf08SMark Brown WM5100_MIXER_ROUTES("OUT2R", "HPOUT2R"),
11906d4baf08SMark Brown WM5100_MIXER_ROUTES("OUT3L", "HPOUT3L"),
11916d4baf08SMark Brown WM5100_MIXER_ROUTES("OUT3R", "HPOUT3R"),
11926d4baf08SMark Brown
11936d4baf08SMark Brown WM5100_MIXER_ROUTES("OUT4L", "SPKOUTL"),
11946d4baf08SMark Brown WM5100_MIXER_ROUTES("OUT4R", "SPKOUTR"),
11956d4baf08SMark Brown WM5100_MIXER_ROUTES("OUT5L", "SPKDAT1L"),
11966d4baf08SMark Brown WM5100_MIXER_ROUTES("OUT5R", "SPKDAT1R"),
11976d4baf08SMark Brown WM5100_MIXER_ROUTES("OUT6L", "SPKDAT2L"),
11986d4baf08SMark Brown WM5100_MIXER_ROUTES("OUT6R", "SPKDAT2R"),
11996d4baf08SMark Brown
12006d4baf08SMark Brown WM5100_MIXER_ROUTES("PWM1 Driver", "PWM1"),
12016d4baf08SMark Brown WM5100_MIXER_ROUTES("PWM2 Driver", "PWM2"),
12026d4baf08SMark Brown
12036d4baf08SMark Brown WM5100_MIXER_ROUTES("AIF1TX1", "AIF1TX1"),
12046d4baf08SMark Brown WM5100_MIXER_ROUTES("AIF1TX2", "AIF1TX2"),
12056d4baf08SMark Brown WM5100_MIXER_ROUTES("AIF1TX3", "AIF1TX3"),
12066d4baf08SMark Brown WM5100_MIXER_ROUTES("AIF1TX4", "AIF1TX4"),
12076d4baf08SMark Brown WM5100_MIXER_ROUTES("AIF1TX5", "AIF1TX5"),
12086d4baf08SMark Brown WM5100_MIXER_ROUTES("AIF1TX6", "AIF1TX6"),
12096d4baf08SMark Brown WM5100_MIXER_ROUTES("AIF1TX7", "AIF1TX7"),
12106d4baf08SMark Brown WM5100_MIXER_ROUTES("AIF1TX8", "AIF1TX8"),
12116d4baf08SMark Brown
12126d4baf08SMark Brown WM5100_MIXER_ROUTES("AIF2TX1", "AIF2TX1"),
12136d4baf08SMark Brown WM5100_MIXER_ROUTES("AIF2TX2", "AIF2TX2"),
12146d4baf08SMark Brown
12156d4baf08SMark Brown WM5100_MIXER_ROUTES("AIF3TX1", "AIF3TX1"),
12166d4baf08SMark Brown WM5100_MIXER_ROUTES("AIF3TX2", "AIF3TX2"),
12176d4baf08SMark Brown
12186d4baf08SMark Brown WM5100_MIXER_ROUTES("EQ1", "EQ1"),
12196d4baf08SMark Brown WM5100_MIXER_ROUTES("EQ2", "EQ2"),
12206d4baf08SMark Brown WM5100_MIXER_ROUTES("EQ3", "EQ3"),
12216d4baf08SMark Brown WM5100_MIXER_ROUTES("EQ4", "EQ4"),
12226d4baf08SMark Brown
12236d4baf08SMark Brown WM5100_MIXER_ROUTES("DRC1L", "DRC1L"),
12246d4baf08SMark Brown WM5100_MIXER_ROUTES("DRC1R", "DRC1R"),
12256d4baf08SMark Brown
12266d4baf08SMark Brown WM5100_MIXER_ROUTES("LHPF1", "LHPF1"),
12276d4baf08SMark Brown WM5100_MIXER_ROUTES("LHPF2", "LHPF2"),
12286d4baf08SMark Brown WM5100_MIXER_ROUTES("LHPF3", "LHPF3"),
12296d4baf08SMark Brown WM5100_MIXER_ROUTES("LHPF4", "LHPF4"),
12306d4baf08SMark Brown
12316d4baf08SMark Brown { "HPOUT1L", NULL, "OUT1L" },
12326d4baf08SMark Brown { "HPOUT1R", NULL, "OUT1R" },
12336d4baf08SMark Brown { "HPOUT2L", NULL, "OUT2L" },
12346d4baf08SMark Brown { "HPOUT2R", NULL, "OUT2R" },
12356d4baf08SMark Brown { "HPOUT3L", NULL, "OUT3L" },
12366d4baf08SMark Brown { "HPOUT3R", NULL, "OUT3R" },
12376d4baf08SMark Brown { "SPKOUTL", NULL, "OUT4L" },
12386d4baf08SMark Brown { "SPKOUTR", NULL, "OUT4R" },
12396d4baf08SMark Brown { "SPKDAT1", NULL, "OUT5L" },
12406d4baf08SMark Brown { "SPKDAT1", NULL, "OUT5R" },
12416d4baf08SMark Brown { "SPKDAT2", NULL, "OUT6L" },
12426d4baf08SMark Brown { "SPKDAT2", NULL, "OUT6R" },
12436d4baf08SMark Brown { "PWM1", NULL, "PWM1 Driver" },
12446d4baf08SMark Brown { "PWM2", NULL, "PWM2 Driver" },
12456d4baf08SMark Brown };
12466d4baf08SMark Brown
12478019ff6cSNariman Poushin static const struct reg_sequence wm5100_reva_patches[] = {
12486d4baf08SMark Brown { WM5100_AUDIO_IF_1_10, 0 },
12496d4baf08SMark Brown { WM5100_AUDIO_IF_1_11, 1 },
12506d4baf08SMark Brown { WM5100_AUDIO_IF_1_12, 2 },
12516d4baf08SMark Brown { WM5100_AUDIO_IF_1_13, 3 },
12526d4baf08SMark Brown { WM5100_AUDIO_IF_1_14, 4 },
12536d4baf08SMark Brown { WM5100_AUDIO_IF_1_15, 5 },
12546d4baf08SMark Brown { WM5100_AUDIO_IF_1_16, 6 },
12556d4baf08SMark Brown { WM5100_AUDIO_IF_1_17, 7 },
12566d4baf08SMark Brown
12576d4baf08SMark Brown { WM5100_AUDIO_IF_1_18, 0 },
12586d4baf08SMark Brown { WM5100_AUDIO_IF_1_19, 1 },
12596d4baf08SMark Brown { WM5100_AUDIO_IF_1_20, 2 },
12606d4baf08SMark Brown { WM5100_AUDIO_IF_1_21, 3 },
12616d4baf08SMark Brown { WM5100_AUDIO_IF_1_22, 4 },
12626d4baf08SMark Brown { WM5100_AUDIO_IF_1_23, 5 },
12636d4baf08SMark Brown { WM5100_AUDIO_IF_1_24, 6 },
12646d4baf08SMark Brown { WM5100_AUDIO_IF_1_25, 7 },
12656d4baf08SMark Brown
12666d4baf08SMark Brown { WM5100_AUDIO_IF_2_10, 0 },
12676d4baf08SMark Brown { WM5100_AUDIO_IF_2_11, 1 },
12686d4baf08SMark Brown
12696d4baf08SMark Brown { WM5100_AUDIO_IF_2_18, 0 },
12706d4baf08SMark Brown { WM5100_AUDIO_IF_2_19, 1 },
12716d4baf08SMark Brown
12726d4baf08SMark Brown { WM5100_AUDIO_IF_3_10, 0 },
12736d4baf08SMark Brown { WM5100_AUDIO_IF_3_11, 1 },
12746d4baf08SMark Brown
12756d4baf08SMark Brown { WM5100_AUDIO_IF_3_18, 0 },
12766d4baf08SMark Brown { WM5100_AUDIO_IF_3_19, 1 },
12776d4baf08SMark Brown };
12786d4baf08SMark Brown
wm5100_set_fmt(struct snd_soc_dai * dai,unsigned int fmt)12796d4baf08SMark Brown static int wm5100_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
12806d4baf08SMark Brown {
128161195838SKuninori Morimoto struct snd_soc_component *component = dai->component;
12826d4baf08SMark Brown int lrclk, bclk, mask, base;
12836d4baf08SMark Brown
12849b523124SMark Brown base = dai->driver->base;
12856d4baf08SMark Brown
12866d4baf08SMark Brown lrclk = 0;
12876d4baf08SMark Brown bclk = 0;
12886d4baf08SMark Brown
12896d4baf08SMark Brown switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
12906d4baf08SMark Brown case SND_SOC_DAIFMT_DSP_A:
12916d4baf08SMark Brown mask = 0;
12926d4baf08SMark Brown break;
12936d4baf08SMark Brown case SND_SOC_DAIFMT_I2S:
12946d4baf08SMark Brown mask = 2;
12956d4baf08SMark Brown break;
12966d4baf08SMark Brown default:
129761195838SKuninori Morimoto dev_err(component->dev, "Unsupported DAI format %d\n",
12986d4baf08SMark Brown fmt & SND_SOC_DAIFMT_FORMAT_MASK);
12996d4baf08SMark Brown return -EINVAL;
13006d4baf08SMark Brown }
13016d4baf08SMark Brown
13026d4baf08SMark Brown switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
13036d4baf08SMark Brown case SND_SOC_DAIFMT_CBS_CFS:
13046d4baf08SMark Brown break;
13056d4baf08SMark Brown case SND_SOC_DAIFMT_CBS_CFM:
13066d4baf08SMark Brown lrclk |= WM5100_AIF1TX_LRCLK_MSTR;
13076d4baf08SMark Brown break;
13086d4baf08SMark Brown case SND_SOC_DAIFMT_CBM_CFS:
13096d4baf08SMark Brown bclk |= WM5100_AIF1_BCLK_MSTR;
13106d4baf08SMark Brown break;
13116d4baf08SMark Brown case SND_SOC_DAIFMT_CBM_CFM:
13126d4baf08SMark Brown lrclk |= WM5100_AIF1TX_LRCLK_MSTR;
13136d4baf08SMark Brown bclk |= WM5100_AIF1_BCLK_MSTR;
13146d4baf08SMark Brown break;
13156d4baf08SMark Brown default:
131661195838SKuninori Morimoto dev_err(component->dev, "Unsupported master mode %d\n",
13176d4baf08SMark Brown fmt & SND_SOC_DAIFMT_MASTER_MASK);
13186d4baf08SMark Brown return -EINVAL;
13196d4baf08SMark Brown }
13206d4baf08SMark Brown
13216d4baf08SMark Brown switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
13226d4baf08SMark Brown case SND_SOC_DAIFMT_NB_NF:
13236d4baf08SMark Brown break;
13246d4baf08SMark Brown case SND_SOC_DAIFMT_IB_IF:
13256d4baf08SMark Brown bclk |= WM5100_AIF1_BCLK_INV;
13266d4baf08SMark Brown lrclk |= WM5100_AIF1TX_LRCLK_INV;
13276d4baf08SMark Brown break;
13286d4baf08SMark Brown case SND_SOC_DAIFMT_IB_NF:
13296d4baf08SMark Brown bclk |= WM5100_AIF1_BCLK_INV;
13306d4baf08SMark Brown break;
13316d4baf08SMark Brown case SND_SOC_DAIFMT_NB_IF:
13326d4baf08SMark Brown lrclk |= WM5100_AIF1TX_LRCLK_INV;
13336d4baf08SMark Brown break;
13346d4baf08SMark Brown default:
13356d4baf08SMark Brown return -EINVAL;
13366d4baf08SMark Brown }
13376d4baf08SMark Brown
133861195838SKuninori Morimoto snd_soc_component_update_bits(component, base + 1, WM5100_AIF1_BCLK_MSTR |
13396d4baf08SMark Brown WM5100_AIF1_BCLK_INV, bclk);
134061195838SKuninori Morimoto snd_soc_component_update_bits(component, base + 2, WM5100_AIF1TX_LRCLK_MSTR |
13416d4baf08SMark Brown WM5100_AIF1TX_LRCLK_INV, lrclk);
134261195838SKuninori Morimoto snd_soc_component_update_bits(component, base + 3, WM5100_AIF1TX_LRCLK_MSTR |
13436d4baf08SMark Brown WM5100_AIF1TX_LRCLK_INV, lrclk);
134461195838SKuninori Morimoto snd_soc_component_update_bits(component, base + 5, WM5100_AIF1_FMT_MASK, mask);
13456d4baf08SMark Brown
13466d4baf08SMark Brown return 0;
13476d4baf08SMark Brown }
13486d4baf08SMark Brown
13496d4baf08SMark Brown #define WM5100_NUM_BCLK_RATES 19
13506d4baf08SMark Brown
13516d4baf08SMark Brown static int wm5100_bclk_rates_dat[WM5100_NUM_BCLK_RATES] = {
13526d4baf08SMark Brown 32000,
13536d4baf08SMark Brown 48000,
13546d4baf08SMark Brown 64000,
13556d4baf08SMark Brown 96000,
13566d4baf08SMark Brown 128000,
13576d4baf08SMark Brown 192000,
1358d73ec75cSMark Brown 256000,
13596d4baf08SMark Brown 384000,
13606d4baf08SMark Brown 512000,
13616d4baf08SMark Brown 768000,
13626d4baf08SMark Brown 1024000,
13636d4baf08SMark Brown 1536000,
13646d4baf08SMark Brown 2048000,
13656d4baf08SMark Brown 3072000,
13666d4baf08SMark Brown 4096000,
13676d4baf08SMark Brown 6144000,
13686d4baf08SMark Brown 8192000,
13696d4baf08SMark Brown 12288000,
13706d4baf08SMark Brown 24576000,
13716d4baf08SMark Brown };
13726d4baf08SMark Brown
13736d4baf08SMark Brown static int wm5100_bclk_rates_cd[WM5100_NUM_BCLK_RATES] = {
13746d4baf08SMark Brown 29400,
13756d4baf08SMark Brown 44100,
13766d4baf08SMark Brown 58800,
13776d4baf08SMark Brown 88200,
13786d4baf08SMark Brown 117600,
13796d4baf08SMark Brown 176400,
13806d4baf08SMark Brown 235200,
13816d4baf08SMark Brown 352800,
13826d4baf08SMark Brown 470400,
13836d4baf08SMark Brown 705600,
13846d4baf08SMark Brown 940800,
13856d4baf08SMark Brown 1411200,
13866d4baf08SMark Brown 1881600,
13876d4baf08SMark Brown 2882400,
13886d4baf08SMark Brown 3763200,
13896d4baf08SMark Brown 5644800,
13906d4baf08SMark Brown 7526400,
13916d4baf08SMark Brown 11289600,
13926d4baf08SMark Brown 22579600,
13936d4baf08SMark Brown };
13946d4baf08SMark Brown
wm5100_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params,struct snd_soc_dai * dai)13956d4baf08SMark Brown static int wm5100_hw_params(struct snd_pcm_substream *substream,
13966d4baf08SMark Brown struct snd_pcm_hw_params *params,
13976d4baf08SMark Brown struct snd_soc_dai *dai)
13986d4baf08SMark Brown {
139961195838SKuninori Morimoto struct snd_soc_component *component = dai->component;
140061195838SKuninori Morimoto struct wm5100_priv *wm5100 = snd_soc_component_get_drvdata(component);
14016d4baf08SMark Brown bool async = wm5100->aif_async[dai->id];
14026d4baf08SMark Brown int i, base, bclk, aif_rate, lrclk, wl, fl, sr;
14036d4baf08SMark Brown int *bclk_rates;
14046d4baf08SMark Brown
14059b523124SMark Brown base = dai->driver->base;
14066d4baf08SMark Brown
14076d4baf08SMark Brown /* Data sizes if not using TDM */
14080a3dcb50SAxel Lin wl = params_width(params);
14096d4baf08SMark Brown if (wl < 0)
14106d4baf08SMark Brown return wl;
14116d4baf08SMark Brown fl = snd_soc_params_to_frame_size(params);
14126d4baf08SMark Brown if (fl < 0)
14136d4baf08SMark Brown return fl;
14146d4baf08SMark Brown
141561195838SKuninori Morimoto dev_dbg(component->dev, "Word length %d bits, frame length %d bits\n",
14166d4baf08SMark Brown wl, fl);
14176d4baf08SMark Brown
14186d4baf08SMark Brown /* Target BCLK rate */
14196d4baf08SMark Brown bclk = snd_soc_params_to_bclk(params);
14206d4baf08SMark Brown if (bclk < 0)
14216d4baf08SMark Brown return bclk;
14226d4baf08SMark Brown
14236d4baf08SMark Brown /* Root for BCLK depends on SYS/ASYNCCLK */
14246d4baf08SMark Brown if (!async) {
14256d4baf08SMark Brown aif_rate = wm5100->sysclk;
142661195838SKuninori Morimoto sr = wm5100_alloc_sr(component, params_rate(params));
14276d4baf08SMark Brown if (sr < 0)
14286d4baf08SMark Brown return sr;
14296d4baf08SMark Brown } else {
14306d4baf08SMark Brown /* If we're in ASYNCCLK set the ASYNC sample rate */
14316d4baf08SMark Brown aif_rate = wm5100->asyncclk;
14326d4baf08SMark Brown sr = 3;
14336d4baf08SMark Brown
14346d4baf08SMark Brown for (i = 0; i < ARRAY_SIZE(wm5100_sr_code); i++)
14356d4baf08SMark Brown if (params_rate(params) == wm5100_sr_code[i])
14366d4baf08SMark Brown break;
14376d4baf08SMark Brown if (i == ARRAY_SIZE(wm5100_sr_code)) {
143861195838SKuninori Morimoto dev_err(component->dev, "Invalid rate %dHzn",
14396d4baf08SMark Brown params_rate(params));
14406d4baf08SMark Brown return -EINVAL;
14416d4baf08SMark Brown }
14426d4baf08SMark Brown
14436d4baf08SMark Brown /* TODO: We should really check for symmetry */
144461195838SKuninori Morimoto snd_soc_component_update_bits(component, WM5100_CLOCKING_8,
14456d4baf08SMark Brown WM5100_ASYNC_SAMPLE_RATE_MASK, i);
14466d4baf08SMark Brown }
14476d4baf08SMark Brown
14486d4baf08SMark Brown if (!aif_rate) {
144961195838SKuninori Morimoto dev_err(component->dev, "%s has no rate set\n",
14506d4baf08SMark Brown async ? "ASYNCCLK" : "SYSCLK");
14516d4baf08SMark Brown return -EINVAL;
14526d4baf08SMark Brown }
14536d4baf08SMark Brown
145461195838SKuninori Morimoto dev_dbg(component->dev, "Target BCLK is %dHz, using %dHz %s\n",
14556d4baf08SMark Brown bclk, aif_rate, async ? "ASYNCCLK" : "SYSCLK");
14566d4baf08SMark Brown
14576d4baf08SMark Brown if (aif_rate % 4000)
14586d4baf08SMark Brown bclk_rates = wm5100_bclk_rates_cd;
14596d4baf08SMark Brown else
14606d4baf08SMark Brown bclk_rates = wm5100_bclk_rates_dat;
14616d4baf08SMark Brown
14626d4baf08SMark Brown for (i = 0; i < WM5100_NUM_BCLK_RATES; i++)
14636d4baf08SMark Brown if (bclk_rates[i] >= bclk && (bclk_rates[i] % bclk == 0))
14646d4baf08SMark Brown break;
14656d4baf08SMark Brown if (i == WM5100_NUM_BCLK_RATES) {
146661195838SKuninori Morimoto dev_err(component->dev,
14676d4baf08SMark Brown "No valid BCLK for %dHz found from %dHz %s\n",
14686d4baf08SMark Brown bclk, aif_rate, async ? "ASYNCCLK" : "SYSCLK");
14696d4baf08SMark Brown return -EINVAL;
14706d4baf08SMark Brown }
14716d4baf08SMark Brown
14726d4baf08SMark Brown bclk = i;
147361195838SKuninori Morimoto dev_dbg(component->dev, "Setting %dHz BCLK\n", bclk_rates[bclk]);
147461195838SKuninori Morimoto snd_soc_component_update_bits(component, base + 1, WM5100_AIF1_BCLK_FREQ_MASK, bclk);
14756d4baf08SMark Brown
14766d4baf08SMark Brown lrclk = bclk_rates[bclk] / params_rate(params);
147761195838SKuninori Morimoto dev_dbg(component->dev, "Setting %dHz LRCLK\n", bclk_rates[bclk] / lrclk);
14786d4baf08SMark Brown if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ||
14796d4baf08SMark Brown wm5100->aif_symmetric[dai->id])
148061195838SKuninori Morimoto snd_soc_component_update_bits(component, base + 7,
14816d4baf08SMark Brown WM5100_AIF1RX_BCPF_MASK, lrclk);
14826d4baf08SMark Brown else
148361195838SKuninori Morimoto snd_soc_component_update_bits(component, base + 6,
14846d4baf08SMark Brown WM5100_AIF1TX_BCPF_MASK, lrclk);
14856d4baf08SMark Brown
14866d4baf08SMark Brown i = (wl << WM5100_AIF1TX_WL_SHIFT) | fl;
14876d4baf08SMark Brown if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
148861195838SKuninori Morimoto snd_soc_component_update_bits(component, base + 9,
14896d4baf08SMark Brown WM5100_AIF1RX_WL_MASK |
14906d4baf08SMark Brown WM5100_AIF1RX_SLOT_LEN_MASK, i);
14916d4baf08SMark Brown else
149261195838SKuninori Morimoto snd_soc_component_update_bits(component, base + 8,
14936d4baf08SMark Brown WM5100_AIF1TX_WL_MASK |
14946d4baf08SMark Brown WM5100_AIF1TX_SLOT_LEN_MASK, i);
14956d4baf08SMark Brown
149661195838SKuninori Morimoto snd_soc_component_update_bits(component, base + 4, WM5100_AIF1_RATE_MASK, sr);
14976d4baf08SMark Brown
14986d4baf08SMark Brown return 0;
14996d4baf08SMark Brown }
15006d4baf08SMark Brown
150185e7652dSLars-Peter Clausen static const struct snd_soc_dai_ops wm5100_dai_ops = {
15026d4baf08SMark Brown .set_fmt = wm5100_set_fmt,
15036d4baf08SMark Brown .hw_params = wm5100_hw_params,
15046d4baf08SMark Brown };
15056d4baf08SMark Brown
wm5100_set_sysclk(struct snd_soc_component * component,int clk_id,int source,unsigned int freq,int dir)150661195838SKuninori Morimoto static int wm5100_set_sysclk(struct snd_soc_component *component, int clk_id,
15076d4baf08SMark Brown int source, unsigned int freq, int dir)
15086d4baf08SMark Brown {
150961195838SKuninori Morimoto struct wm5100_priv *wm5100 = snd_soc_component_get_drvdata(component);
15106d4baf08SMark Brown int *rate_store;
15116d4baf08SMark Brown int fval, audio_rate, ret, reg;
15126d4baf08SMark Brown
15136d4baf08SMark Brown switch (clk_id) {
15146d4baf08SMark Brown case WM5100_CLK_SYSCLK:
15156d4baf08SMark Brown reg = WM5100_CLOCKING_3;
15166d4baf08SMark Brown rate_store = &wm5100->sysclk;
15176d4baf08SMark Brown break;
15186d4baf08SMark Brown case WM5100_CLK_ASYNCCLK:
15196d4baf08SMark Brown reg = WM5100_CLOCKING_7;
15206d4baf08SMark Brown rate_store = &wm5100->asyncclk;
15216d4baf08SMark Brown break;
15226d4baf08SMark Brown case WM5100_CLK_32KHZ:
15236d4baf08SMark Brown /* The 32kHz clock is slightly different to the others */
15246d4baf08SMark Brown switch (source) {
15256d4baf08SMark Brown case WM5100_CLKSRC_MCLK1:
15266d4baf08SMark Brown case WM5100_CLKSRC_MCLK2:
15276d4baf08SMark Brown case WM5100_CLKSRC_SYSCLK:
152861195838SKuninori Morimoto snd_soc_component_update_bits(component, WM5100_CLOCKING_1,
15296d4baf08SMark Brown WM5100_CLK_32K_SRC_MASK,
15306d4baf08SMark Brown source);
15316d4baf08SMark Brown break;
15326d4baf08SMark Brown default:
15336d4baf08SMark Brown return -EINVAL;
15346d4baf08SMark Brown }
15356d4baf08SMark Brown return 0;
15366d4baf08SMark Brown
15376d4baf08SMark Brown case WM5100_CLK_AIF1:
15386d4baf08SMark Brown case WM5100_CLK_AIF2:
15396d4baf08SMark Brown case WM5100_CLK_AIF3:
15406d4baf08SMark Brown /* Not real clocks, record which clock domain they're in */
15416d4baf08SMark Brown switch (source) {
15426d4baf08SMark Brown case WM5100_CLKSRC_SYSCLK:
15436d4baf08SMark Brown wm5100->aif_async[clk_id - 1] = false;
15446d4baf08SMark Brown break;
15456d4baf08SMark Brown case WM5100_CLKSRC_ASYNCCLK:
15466d4baf08SMark Brown wm5100->aif_async[clk_id - 1] = true;
15476d4baf08SMark Brown break;
15486d4baf08SMark Brown default:
154961195838SKuninori Morimoto dev_err(component->dev, "Invalid source %d\n", source);
15506d4baf08SMark Brown return -EINVAL;
15516d4baf08SMark Brown }
15526d4baf08SMark Brown return 0;
15536d4baf08SMark Brown
15546d4baf08SMark Brown case WM5100_CLK_OPCLK:
15556d4baf08SMark Brown switch (freq) {
15566d4baf08SMark Brown case 5644800:
15576d4baf08SMark Brown case 6144000:
155861195838SKuninori Morimoto snd_soc_component_update_bits(component, WM5100_MISC_GPIO_1,
15596d4baf08SMark Brown WM5100_OPCLK_SEL_MASK, 0);
15606d4baf08SMark Brown break;
15616d4baf08SMark Brown case 11289600:
15626d4baf08SMark Brown case 12288000:
156361195838SKuninori Morimoto snd_soc_component_update_bits(component, WM5100_MISC_GPIO_1,
15646d4baf08SMark Brown WM5100_OPCLK_SEL_MASK, 0);
15656d4baf08SMark Brown break;
15666d4baf08SMark Brown case 22579200:
15676d4baf08SMark Brown case 24576000:
156861195838SKuninori Morimoto snd_soc_component_update_bits(component, WM5100_MISC_GPIO_1,
15696d4baf08SMark Brown WM5100_OPCLK_SEL_MASK, 0);
15706d4baf08SMark Brown break;
15716d4baf08SMark Brown default:
157261195838SKuninori Morimoto dev_err(component->dev, "Unsupported OPCLK %dHz\n",
15736d4baf08SMark Brown freq);
15746d4baf08SMark Brown return -EINVAL;
15756d4baf08SMark Brown }
15766d4baf08SMark Brown return 0;
15776d4baf08SMark Brown
15786d4baf08SMark Brown default:
157961195838SKuninori Morimoto dev_err(component->dev, "Unknown clock %d\n", clk_id);
15806d4baf08SMark Brown return -EINVAL;
15816d4baf08SMark Brown }
15826d4baf08SMark Brown
15836d4baf08SMark Brown switch (source) {
15846d4baf08SMark Brown case WM5100_CLKSRC_SYSCLK:
15856d4baf08SMark Brown case WM5100_CLKSRC_ASYNCCLK:
158661195838SKuninori Morimoto dev_err(component->dev, "Invalid source %d\n", source);
15876d4baf08SMark Brown return -EINVAL;
15886d4baf08SMark Brown }
15896d4baf08SMark Brown
15906d4baf08SMark Brown switch (freq) {
15916d4baf08SMark Brown case 5644800:
15926d4baf08SMark Brown case 6144000:
15936d4baf08SMark Brown fval = 0;
15946d4baf08SMark Brown break;
15956d4baf08SMark Brown case 11289600:
15966d4baf08SMark Brown case 12288000:
15976d4baf08SMark Brown fval = 1;
15986d4baf08SMark Brown break;
15996d4baf08SMark Brown case 22579200:
160011c2b5f2SMark Brown case 24576000:
16016d4baf08SMark Brown fval = 2;
16026d4baf08SMark Brown break;
16036d4baf08SMark Brown default:
160461195838SKuninori Morimoto dev_err(component->dev, "Invalid clock rate: %d\n", freq);
16056d4baf08SMark Brown return -EINVAL;
16066d4baf08SMark Brown }
16076d4baf08SMark Brown
16086d4baf08SMark Brown switch (freq) {
16096d4baf08SMark Brown case 5644800:
16106d4baf08SMark Brown case 11289600:
16116d4baf08SMark Brown case 22579200:
16126d4baf08SMark Brown audio_rate = 44100;
16136d4baf08SMark Brown break;
16146d4baf08SMark Brown
16156d4baf08SMark Brown case 6144000:
16166d4baf08SMark Brown case 12288000:
161711c2b5f2SMark Brown case 24576000:
16186d4baf08SMark Brown audio_rate = 48000;
16196d4baf08SMark Brown break;
16206d4baf08SMark Brown
16216d4baf08SMark Brown default:
16226d4baf08SMark Brown BUG();
16236d4baf08SMark Brown audio_rate = 0;
16246d4baf08SMark Brown break;
16256d4baf08SMark Brown }
16266d4baf08SMark Brown
16276d4baf08SMark Brown /* TODO: Check if MCLKs are in use and enable/disable pulls to
16286d4baf08SMark Brown * match.
16296d4baf08SMark Brown */
16306d4baf08SMark Brown
163161195838SKuninori Morimoto snd_soc_component_update_bits(component, reg, WM5100_SYSCLK_FREQ_MASK |
16326d4baf08SMark Brown WM5100_SYSCLK_SRC_MASK,
16336d4baf08SMark Brown fval << WM5100_SYSCLK_FREQ_SHIFT | source);
16346d4baf08SMark Brown
16356d4baf08SMark Brown /* If this is SYSCLK then configure the clock rate for the
16366d4baf08SMark Brown * internal audio functions to the natural sample rate for
16376d4baf08SMark Brown * this clock rate.
16386d4baf08SMark Brown */
16396d4baf08SMark Brown if (clk_id == WM5100_CLK_SYSCLK) {
164061195838SKuninori Morimoto dev_dbg(component->dev, "Setting primary audio rate to %dHz",
16416d4baf08SMark Brown audio_rate);
16426d4baf08SMark Brown if (0 && *rate_store)
164361195838SKuninori Morimoto wm5100_free_sr(component, audio_rate);
164461195838SKuninori Morimoto ret = wm5100_alloc_sr(component, audio_rate);
16456d4baf08SMark Brown if (ret != 0)
164661195838SKuninori Morimoto dev_warn(component->dev, "Primary audio slot is %d\n",
16476d4baf08SMark Brown ret);
16486d4baf08SMark Brown }
16496d4baf08SMark Brown
16506d4baf08SMark Brown *rate_store = freq;
16516d4baf08SMark Brown
16526d4baf08SMark Brown return 0;
16536d4baf08SMark Brown }
16546d4baf08SMark Brown
16556d4baf08SMark Brown struct _fll_div {
16566d4baf08SMark Brown u16 fll_fratio;
16576d4baf08SMark Brown u16 fll_outdiv;
16586d4baf08SMark Brown u16 fll_refclk_div;
16596d4baf08SMark Brown u16 n;
16606d4baf08SMark Brown u16 theta;
16616d4baf08SMark Brown u16 lambda;
16626d4baf08SMark Brown };
16636d4baf08SMark Brown
16646d4baf08SMark Brown static struct {
16656d4baf08SMark Brown unsigned int min;
16666d4baf08SMark Brown unsigned int max;
16676d4baf08SMark Brown u16 fll_fratio;
16686d4baf08SMark Brown int ratio;
16696d4baf08SMark Brown } fll_fratios[] = {
16706d4baf08SMark Brown { 0, 64000, 4, 16 },
16716d4baf08SMark Brown { 64000, 128000, 3, 8 },
16726d4baf08SMark Brown { 128000, 256000, 2, 4 },
16736d4baf08SMark Brown { 256000, 1000000, 1, 2 },
16746d4baf08SMark Brown { 1000000, 13500000, 0, 1 },
16756d4baf08SMark Brown };
16766d4baf08SMark Brown
fll_factors(struct _fll_div * fll_div,unsigned int Fref,unsigned int Fout)16776d4baf08SMark Brown static int fll_factors(struct _fll_div *fll_div, unsigned int Fref,
16786d4baf08SMark Brown unsigned int Fout)
16796d4baf08SMark Brown {
16806d4baf08SMark Brown unsigned int target;
16816d4baf08SMark Brown unsigned int div;
16826d4baf08SMark Brown unsigned int fratio, gcd_fll;
16836d4baf08SMark Brown int i;
16846d4baf08SMark Brown
16856d4baf08SMark Brown /* Fref must be <=13.5MHz */
16866d4baf08SMark Brown div = 1;
16876d4baf08SMark Brown fll_div->fll_refclk_div = 0;
16886d4baf08SMark Brown while ((Fref / div) > 13500000) {
16896d4baf08SMark Brown div *= 2;
16906d4baf08SMark Brown fll_div->fll_refclk_div++;
16916d4baf08SMark Brown
16926d4baf08SMark Brown if (div > 8) {
16936d4baf08SMark Brown pr_err("Can't scale %dMHz input down to <=13.5MHz\n",
16946d4baf08SMark Brown Fref);
16956d4baf08SMark Brown return -EINVAL;
16966d4baf08SMark Brown }
16976d4baf08SMark Brown }
16986d4baf08SMark Brown
16996d4baf08SMark Brown pr_debug("FLL Fref=%u Fout=%u\n", Fref, Fout);
17006d4baf08SMark Brown
17016d4baf08SMark Brown /* Apply the division for our remaining calculations */
17026d4baf08SMark Brown Fref /= div;
17036d4baf08SMark Brown
17046d4baf08SMark Brown /* Fvco should be 90-100MHz; don't check the upper bound */
17056d4baf08SMark Brown div = 2;
17066d4baf08SMark Brown while (Fout * div < 90000000) {
17076d4baf08SMark Brown div++;
17086d4baf08SMark Brown if (div > 64) {
17096d4baf08SMark Brown pr_err("Unable to find FLL_OUTDIV for Fout=%uHz\n",
17106d4baf08SMark Brown Fout);
17116d4baf08SMark Brown return -EINVAL;
17126d4baf08SMark Brown }
17136d4baf08SMark Brown }
17146d4baf08SMark Brown target = Fout * div;
17156d4baf08SMark Brown fll_div->fll_outdiv = div - 1;
17166d4baf08SMark Brown
17176d4baf08SMark Brown pr_debug("FLL Fvco=%dHz\n", target);
17186d4baf08SMark Brown
17196d4baf08SMark Brown /* Find an appropraite FLL_FRATIO and factor it out of the target */
17206d4baf08SMark Brown for (i = 0; i < ARRAY_SIZE(fll_fratios); i++) {
17216d4baf08SMark Brown if (fll_fratios[i].min <= Fref && Fref <= fll_fratios[i].max) {
17226d4baf08SMark Brown fll_div->fll_fratio = fll_fratios[i].fll_fratio;
17236d4baf08SMark Brown fratio = fll_fratios[i].ratio;
17246d4baf08SMark Brown break;
17256d4baf08SMark Brown }
17266d4baf08SMark Brown }
17276d4baf08SMark Brown if (i == ARRAY_SIZE(fll_fratios)) {
17286d4baf08SMark Brown pr_err("Unable to find FLL_FRATIO for Fref=%uHz\n", Fref);
17296d4baf08SMark Brown return -EINVAL;
17306d4baf08SMark Brown }
17316d4baf08SMark Brown
17326d4baf08SMark Brown fll_div->n = target / (fratio * Fref);
17336d4baf08SMark Brown
17346d4baf08SMark Brown if (target % Fref == 0) {
17356d4baf08SMark Brown fll_div->theta = 0;
17366d4baf08SMark Brown fll_div->lambda = 0;
17376d4baf08SMark Brown } else {
17386d4baf08SMark Brown gcd_fll = gcd(target, fratio * Fref);
17396d4baf08SMark Brown
17406d4baf08SMark Brown fll_div->theta = (target - (fll_div->n * fratio * Fref))
17416d4baf08SMark Brown / gcd_fll;
17426d4baf08SMark Brown fll_div->lambda = (fratio * Fref) / gcd_fll;
17436d4baf08SMark Brown }
17446d4baf08SMark Brown
17456d4baf08SMark Brown pr_debug("FLL N=%x THETA=%x LAMBDA=%x\n",
17466d4baf08SMark Brown fll_div->n, fll_div->theta, fll_div->lambda);
17476d4baf08SMark Brown pr_debug("FLL_FRATIO=%x(%d) FLL_OUTDIV=%x FLL_REFCLK_DIV=%x\n",
17486d4baf08SMark Brown fll_div->fll_fratio, fratio, fll_div->fll_outdiv,
17496d4baf08SMark Brown fll_div->fll_refclk_div);
17506d4baf08SMark Brown
17516d4baf08SMark Brown return 0;
17526d4baf08SMark Brown }
17536d4baf08SMark Brown
wm5100_set_fll(struct snd_soc_component * component,int fll_id,int source,unsigned int Fref,unsigned int Fout)175461195838SKuninori Morimoto static int wm5100_set_fll(struct snd_soc_component *component, int fll_id, int source,
17556d4baf08SMark Brown unsigned int Fref, unsigned int Fout)
17566d4baf08SMark Brown {
175761195838SKuninori Morimoto struct i2c_client *i2c = to_i2c_client(component->dev);
175861195838SKuninori Morimoto struct wm5100_priv *wm5100 = snd_soc_component_get_drvdata(component);
17596d4baf08SMark Brown struct _fll_div factors;
17606d4baf08SMark Brown struct wm5100_fll *fll;
17616d4baf08SMark Brown int ret, base, lock, i, timeout;
1762905a8086SNicholas Mc Guire unsigned long time_left;
17636d4baf08SMark Brown
17646d4baf08SMark Brown switch (fll_id) {
17656d4baf08SMark Brown case WM5100_FLL1:
17666d4baf08SMark Brown fll = &wm5100->fll[0];
17676d4baf08SMark Brown base = WM5100_FLL1_CONTROL_1 - 1;
17686d4baf08SMark Brown lock = WM5100_FLL1_LOCK_STS;
17696d4baf08SMark Brown break;
17706d4baf08SMark Brown case WM5100_FLL2:
17716d4baf08SMark Brown fll = &wm5100->fll[1];
17726d4baf08SMark Brown base = WM5100_FLL2_CONTROL_2 - 1;
17736d4baf08SMark Brown lock = WM5100_FLL2_LOCK_STS;
17746d4baf08SMark Brown break;
17756d4baf08SMark Brown default:
177661195838SKuninori Morimoto dev_err(component->dev, "Unknown FLL %d\n",fll_id);
17776d4baf08SMark Brown return -EINVAL;
17786d4baf08SMark Brown }
17796d4baf08SMark Brown
17806d4baf08SMark Brown if (!Fout) {
178161195838SKuninori Morimoto dev_dbg(component->dev, "FLL%d disabled", fll_id);
178262c1c401SMark Brown if (fll->fout)
178361195838SKuninori Morimoto pm_runtime_put(component->dev);
17846d4baf08SMark Brown fll->fout = 0;
178561195838SKuninori Morimoto snd_soc_component_update_bits(component, base + 1, WM5100_FLL1_ENA, 0);
17866d4baf08SMark Brown return 0;
17876d4baf08SMark Brown }
17886d4baf08SMark Brown
17896d4baf08SMark Brown switch (source) {
17906d4baf08SMark Brown case WM5100_FLL_SRC_MCLK1:
17916d4baf08SMark Brown case WM5100_FLL_SRC_MCLK2:
17926d4baf08SMark Brown case WM5100_FLL_SRC_FLL1:
17936d4baf08SMark Brown case WM5100_FLL_SRC_FLL2:
17946d4baf08SMark Brown case WM5100_FLL_SRC_AIF1BCLK:
17956d4baf08SMark Brown case WM5100_FLL_SRC_AIF2BCLK:
17966d4baf08SMark Brown case WM5100_FLL_SRC_AIF3BCLK:
17976d4baf08SMark Brown break;
17986d4baf08SMark Brown default:
179961195838SKuninori Morimoto dev_err(component->dev, "Invalid FLL source %d\n", source);
18006d4baf08SMark Brown return -EINVAL;
18016d4baf08SMark Brown }
18026d4baf08SMark Brown
18036d4baf08SMark Brown ret = fll_factors(&factors, Fref, Fout);
18046d4baf08SMark Brown if (ret < 0)
18056d4baf08SMark Brown return ret;
18066d4baf08SMark Brown
18076d4baf08SMark Brown /* Disable the FLL while we reconfigure */
180861195838SKuninori Morimoto snd_soc_component_update_bits(component, base + 1, WM5100_FLL1_ENA, 0);
18096d4baf08SMark Brown
181061195838SKuninori Morimoto snd_soc_component_update_bits(component, base + 2,
18116d4baf08SMark Brown WM5100_FLL1_OUTDIV_MASK | WM5100_FLL1_FRATIO_MASK,
18126d4baf08SMark Brown (factors.fll_outdiv << WM5100_FLL1_OUTDIV_SHIFT) |
18136d4baf08SMark Brown factors.fll_fratio);
181461195838SKuninori Morimoto snd_soc_component_update_bits(component, base + 3, WM5100_FLL1_THETA_MASK,
18156d4baf08SMark Brown factors.theta);
181661195838SKuninori Morimoto snd_soc_component_update_bits(component, base + 5, WM5100_FLL1_N_MASK, factors.n);
181761195838SKuninori Morimoto snd_soc_component_update_bits(component, base + 6,
18186d4baf08SMark Brown WM5100_FLL1_REFCLK_DIV_MASK |
18196d4baf08SMark Brown WM5100_FLL1_REFCLK_SRC_MASK,
18206d4baf08SMark Brown (factors.fll_refclk_div
18216d4baf08SMark Brown << WM5100_FLL1_REFCLK_DIV_SHIFT) | source);
182261195838SKuninori Morimoto snd_soc_component_update_bits(component, base + 7, WM5100_FLL1_LAMBDA_MASK,
18236d4baf08SMark Brown factors.lambda);
18246d4baf08SMark Brown
18256d4baf08SMark Brown /* Clear any pending completions */
18266d4baf08SMark Brown try_wait_for_completion(&fll->lock);
18276d4baf08SMark Brown
182861195838SKuninori Morimoto pm_runtime_get_sync(component->dev);
182962c1c401SMark Brown
183061195838SKuninori Morimoto snd_soc_component_update_bits(component, base + 1, WM5100_FLL1_ENA, WM5100_FLL1_ENA);
18316d4baf08SMark Brown
18326d4baf08SMark Brown if (i2c->irq)
18336d4baf08SMark Brown timeout = 2;
18346d4baf08SMark Brown else
18356d4baf08SMark Brown timeout = 50;
18366d4baf08SMark Brown
183761195838SKuninori Morimoto snd_soc_component_update_bits(component, WM5100_CLOCKING_3, WM5100_SYSCLK_ENA,
1838bd132ec5SMark Brown WM5100_SYSCLK_ENA);
1839bd132ec5SMark Brown
18406d4baf08SMark Brown /* Poll for the lock; will use interrupt when we can test */
18416d4baf08SMark Brown for (i = 0; i < timeout; i++) {
18426d4baf08SMark Brown if (i2c->irq) {
1843905a8086SNicholas Mc Guire time_left = wait_for_completion_timeout(&fll->lock,
18446d4baf08SMark Brown msecs_to_jiffies(25));
1845905a8086SNicholas Mc Guire if (time_left > 0)
18466d4baf08SMark Brown break;
18476d4baf08SMark Brown } else {
18486d4baf08SMark Brown msleep(1);
18496d4baf08SMark Brown }
18506d4baf08SMark Brown
18516d75dfc3SKuninori Morimoto ret = snd_soc_component_read(component,
18526d4baf08SMark Brown WM5100_INTERRUPT_RAW_STATUS_3);
18536d4baf08SMark Brown if (ret < 0) {
185461195838SKuninori Morimoto dev_err(component->dev,
18556d4baf08SMark Brown "Failed to read FLL status: %d\n",
18566d4baf08SMark Brown ret);
18576d4baf08SMark Brown continue;
18586d4baf08SMark Brown }
18596d4baf08SMark Brown if (ret & lock)
18606d4baf08SMark Brown break;
18616d4baf08SMark Brown }
18626d4baf08SMark Brown if (i == timeout) {
186361195838SKuninori Morimoto dev_err(component->dev, "FLL%d lock timed out\n", fll_id);
186461195838SKuninori Morimoto pm_runtime_put(component->dev);
18656d4baf08SMark Brown return -ETIMEDOUT;
18666d4baf08SMark Brown }
18676d4baf08SMark Brown
18686d4baf08SMark Brown fll->src = source;
18696d4baf08SMark Brown fll->fref = Fref;
18706d4baf08SMark Brown fll->fout = Fout;
18716d4baf08SMark Brown
187261195838SKuninori Morimoto dev_dbg(component->dev, "FLL%d running %dHz->%dHz\n", fll_id,
18736d4baf08SMark Brown Fref, Fout);
18746d4baf08SMark Brown
18756d4baf08SMark Brown return 0;
18766d4baf08SMark Brown }
18776d4baf08SMark Brown
18786d4baf08SMark Brown /* Actually go much higher */
18796d4baf08SMark Brown #define WM5100_RATES SNDRV_PCM_RATE_8000_192000
18806d4baf08SMark Brown
18816d4baf08SMark Brown #define WM5100_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
18826d4baf08SMark Brown SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
18836d4baf08SMark Brown
18846d4baf08SMark Brown static struct snd_soc_dai_driver wm5100_dai[] = {
18856d4baf08SMark Brown {
18866d4baf08SMark Brown .name = "wm5100-aif1",
18879b523124SMark Brown .base = WM5100_AUDIO_IF_1_1 - 1,
18886d4baf08SMark Brown .playback = {
18896d4baf08SMark Brown .stream_name = "AIF1 Playback",
18906d4baf08SMark Brown .channels_min = 2,
18916d4baf08SMark Brown .channels_max = 2,
18926d4baf08SMark Brown .rates = WM5100_RATES,
18936d4baf08SMark Brown .formats = WM5100_FORMATS,
18946d4baf08SMark Brown },
18956d4baf08SMark Brown .capture = {
18966d4baf08SMark Brown .stream_name = "AIF1 Capture",
18976d4baf08SMark Brown .channels_min = 2,
18986d4baf08SMark Brown .channels_max = 2,
18996d4baf08SMark Brown .rates = WM5100_RATES,
19006d4baf08SMark Brown .formats = WM5100_FORMATS,
19016d4baf08SMark Brown },
19026d4baf08SMark Brown .ops = &wm5100_dai_ops,
19036d4baf08SMark Brown },
19046d4baf08SMark Brown {
19056d4baf08SMark Brown .name = "wm5100-aif2",
19066d4baf08SMark Brown .id = 1,
19079b523124SMark Brown .base = WM5100_AUDIO_IF_2_1 - 1,
19086d4baf08SMark Brown .playback = {
19096d4baf08SMark Brown .stream_name = "AIF2 Playback",
19106d4baf08SMark Brown .channels_min = 2,
19116d4baf08SMark Brown .channels_max = 2,
19126d4baf08SMark Brown .rates = WM5100_RATES,
19136d4baf08SMark Brown .formats = WM5100_FORMATS,
19146d4baf08SMark Brown },
19156d4baf08SMark Brown .capture = {
19166d4baf08SMark Brown .stream_name = "AIF2 Capture",
19176d4baf08SMark Brown .channels_min = 2,
19186d4baf08SMark Brown .channels_max = 2,
19196d4baf08SMark Brown .rates = WM5100_RATES,
19206d4baf08SMark Brown .formats = WM5100_FORMATS,
19216d4baf08SMark Brown },
19226d4baf08SMark Brown .ops = &wm5100_dai_ops,
19236d4baf08SMark Brown },
19246d4baf08SMark Brown {
19256d4baf08SMark Brown .name = "wm5100-aif3",
19266d4baf08SMark Brown .id = 2,
19279b523124SMark Brown .base = WM5100_AUDIO_IF_3_1 - 1,
19286d4baf08SMark Brown .playback = {
19296d4baf08SMark Brown .stream_name = "AIF3 Playback",
19306d4baf08SMark Brown .channels_min = 2,
19316d4baf08SMark Brown .channels_max = 2,
19326d4baf08SMark Brown .rates = WM5100_RATES,
19336d4baf08SMark Brown .formats = WM5100_FORMATS,
19346d4baf08SMark Brown },
19356d4baf08SMark Brown .capture = {
19366d4baf08SMark Brown .stream_name = "AIF3 Capture",
19376d4baf08SMark Brown .channels_min = 2,
19386d4baf08SMark Brown .channels_max = 2,
19396d4baf08SMark Brown .rates = WM5100_RATES,
19406d4baf08SMark Brown .formats = WM5100_FORMATS,
19416d4baf08SMark Brown },
19426d4baf08SMark Brown .ops = &wm5100_dai_ops,
19436d4baf08SMark Brown },
19446d4baf08SMark Brown };
19456d4baf08SMark Brown
19466d4baf08SMark Brown static int wm5100_dig_vu[] = {
19476d4baf08SMark Brown WM5100_ADC_DIGITAL_VOLUME_1L,
19486d4baf08SMark Brown WM5100_ADC_DIGITAL_VOLUME_1R,
19496d4baf08SMark Brown WM5100_ADC_DIGITAL_VOLUME_2L,
19506d4baf08SMark Brown WM5100_ADC_DIGITAL_VOLUME_2R,
19516d4baf08SMark Brown WM5100_ADC_DIGITAL_VOLUME_3L,
19526d4baf08SMark Brown WM5100_ADC_DIGITAL_VOLUME_3R,
19536d4baf08SMark Brown WM5100_ADC_DIGITAL_VOLUME_4L,
19546d4baf08SMark Brown WM5100_ADC_DIGITAL_VOLUME_4R,
19556d4baf08SMark Brown
19566d4baf08SMark Brown WM5100_DAC_DIGITAL_VOLUME_1L,
19576d4baf08SMark Brown WM5100_DAC_DIGITAL_VOLUME_1R,
19586d4baf08SMark Brown WM5100_DAC_DIGITAL_VOLUME_2L,
19596d4baf08SMark Brown WM5100_DAC_DIGITAL_VOLUME_2R,
19606d4baf08SMark Brown WM5100_DAC_DIGITAL_VOLUME_3L,
19616d4baf08SMark Brown WM5100_DAC_DIGITAL_VOLUME_3R,
19626d4baf08SMark Brown WM5100_DAC_DIGITAL_VOLUME_4L,
19636d4baf08SMark Brown WM5100_DAC_DIGITAL_VOLUME_4R,
19646d4baf08SMark Brown WM5100_DAC_DIGITAL_VOLUME_5L,
19656d4baf08SMark Brown WM5100_DAC_DIGITAL_VOLUME_5R,
19666d4baf08SMark Brown WM5100_DAC_DIGITAL_VOLUME_6L,
19676d4baf08SMark Brown WM5100_DAC_DIGITAL_VOLUME_6R,
19686d4baf08SMark Brown };
19696d4baf08SMark Brown
wm5100_set_detect_mode(struct wm5100_priv * wm5100,int the_mode)197046c1a877SMark Brown static void wm5100_set_detect_mode(struct wm5100_priv *wm5100, int the_mode)
1971ba896edeSMark Brown {
1972ba896edeSMark Brown struct wm5100_jack_mode *mode = &wm5100->pdata.jack_modes[the_mode];
1973ba896edeSMark Brown
197495ff71e9STakashi Iwai if (WARN_ON(the_mode >= ARRAY_SIZE(wm5100->pdata.jack_modes)))
197595ff71e9STakashi Iwai return;
1976ba896edeSMark Brown
1977ba896edeSMark Brown gpio_set_value_cansleep(wm5100->pdata.hp_pol, mode->hp_pol);
197846c1a877SMark Brown regmap_update_bits(wm5100->regmap, WM5100_ACCESSORY_DETECT_MODE_1,
1979ba896edeSMark Brown WM5100_ACCDET_BIAS_SRC_MASK |
1980ba896edeSMark Brown WM5100_ACCDET_SRC,
1981ba896edeSMark Brown (mode->bias << WM5100_ACCDET_BIAS_SRC_SHIFT) |
1982ba896edeSMark Brown mode->micd_src << WM5100_ACCDET_SRC_SHIFT);
198346c1a877SMark Brown regmap_update_bits(wm5100->regmap, WM5100_MISC_CONTROL,
19841cba77c1SMark Brown WM5100_HPCOM_SRC,
19851cba77c1SMark Brown mode->micd_src << WM5100_HPCOM_SRC_SHIFT);
1986ba896edeSMark Brown
1987ba896edeSMark Brown wm5100->jack_mode = the_mode;
1988ba896edeSMark Brown
198946c1a877SMark Brown dev_dbg(wm5100->dev, "Set microphone polarity to %d\n",
1990ba896edeSMark Brown wm5100->jack_mode);
1991ba896edeSMark Brown }
1992ba896edeSMark Brown
wm5100_report_headphone(struct wm5100_priv * wm5100)19932633f736SMark Brown static void wm5100_report_headphone(struct wm5100_priv *wm5100)
19942633f736SMark Brown {
19952633f736SMark Brown dev_dbg(wm5100->dev, "Headphone detected\n");
19962633f736SMark Brown wm5100->jack_detecting = false;
19972633f736SMark Brown snd_soc_jack_report(wm5100->jack, SND_JACK_HEADPHONE,
19982633f736SMark Brown SND_JACK_HEADPHONE);
19992633f736SMark Brown
20002633f736SMark Brown /* Increase the detection rate a bit for responsiveness. */
20012633f736SMark Brown regmap_update_bits(wm5100->regmap, WM5100_MIC_DETECT_1,
20022633f736SMark Brown WM5100_ACCDET_RATE_MASK,
20032633f736SMark Brown 7 << WM5100_ACCDET_RATE_SHIFT);
20042633f736SMark Brown }
20052633f736SMark Brown
wm5100_micd_irq(struct wm5100_priv * wm5100)200646c1a877SMark Brown static void wm5100_micd_irq(struct wm5100_priv *wm5100)
2007ba896edeSMark Brown {
200846c1a877SMark Brown unsigned int val;
200946c1a877SMark Brown int ret;
2010ba896edeSMark Brown
201146c1a877SMark Brown ret = regmap_read(wm5100->regmap, WM5100_MIC_DETECT_3, &val);
201246c1a877SMark Brown if (ret != 0) {
2013fd9f069dSColin Ian King dev_err(wm5100->dev, "Failed to read microphone status: %d\n",
201446c1a877SMark Brown ret);
201546c1a877SMark Brown return;
201646c1a877SMark Brown }
2017ba896edeSMark Brown
201846c1a877SMark Brown dev_dbg(wm5100->dev, "Microphone event: %x\n", val);
2019ba896edeSMark Brown
2020ba896edeSMark Brown if (!(val & WM5100_ACCDET_VALID)) {
202146c1a877SMark Brown dev_warn(wm5100->dev, "Microphone detection state invalid\n");
2022ba896edeSMark Brown return;
2023ba896edeSMark Brown }
2024ba896edeSMark Brown
2025ba896edeSMark Brown /* No accessory, reset everything and report removal */
2026ba896edeSMark Brown if (!(val & WM5100_ACCDET_STS)) {
202746c1a877SMark Brown dev_dbg(wm5100->dev, "Jack removal detected\n");
2028ba896edeSMark Brown wm5100->jack_mic = false;
2029ba896edeSMark Brown wm5100->jack_detecting = true;
20302633f736SMark Brown wm5100->jack_flips = 0;
2031ba896edeSMark Brown snd_soc_jack_report(wm5100->jack, 0,
2032ba896edeSMark Brown SND_JACK_LINEOUT | SND_JACK_HEADSET |
2033ba896edeSMark Brown SND_JACK_BTN_0);
2034ba896edeSMark Brown
203546c1a877SMark Brown regmap_update_bits(wm5100->regmap, WM5100_MIC_DETECT_1,
2036ba896edeSMark Brown WM5100_ACCDET_RATE_MASK,
2037ba896edeSMark Brown WM5100_ACCDET_RATE_MASK);
2038ba896edeSMark Brown return;
2039ba896edeSMark Brown }
2040ba896edeSMark Brown
2041ba896edeSMark Brown /* If the measurement is very high we've got a microphone,
2042ba896edeSMark Brown * either we just detected one or if we already reported then
2043ba896edeSMark Brown * we've got a button release event.
2044ba896edeSMark Brown */
2045ba896edeSMark Brown if (val & 0x400) {
2046ba896edeSMark Brown if (wm5100->jack_detecting) {
204746c1a877SMark Brown dev_dbg(wm5100->dev, "Microphone detected\n");
2048ba896edeSMark Brown wm5100->jack_mic = true;
20499fb83526SMark Brown wm5100->jack_detecting = false;
2050ba896edeSMark Brown snd_soc_jack_report(wm5100->jack,
2051ba896edeSMark Brown SND_JACK_HEADSET,
2052ba896edeSMark Brown SND_JACK_HEADSET | SND_JACK_BTN_0);
2053ba896edeSMark Brown
2054ba896edeSMark Brown /* Increase poll rate to give better responsiveness
2055ba896edeSMark Brown * for buttons */
205646c1a877SMark Brown regmap_update_bits(wm5100->regmap, WM5100_MIC_DETECT_1,
2057ba896edeSMark Brown WM5100_ACCDET_RATE_MASK,
2058ba896edeSMark Brown 5 << WM5100_ACCDET_RATE_SHIFT);
2059ba896edeSMark Brown } else {
206046c1a877SMark Brown dev_dbg(wm5100->dev, "Mic button up\n");
2061ba896edeSMark Brown snd_soc_jack_report(wm5100->jack, 0, SND_JACK_BTN_0);
2062ba896edeSMark Brown }
2063ba896edeSMark Brown
2064ba896edeSMark Brown return;
2065ba896edeSMark Brown }
2066ba896edeSMark Brown
2067ba896edeSMark Brown /* If we detected a lower impedence during initial startup
2068ba896edeSMark Brown * then we probably have the wrong polarity, flip it. Don't
2069ba896edeSMark Brown * do this for the lowest impedences to speed up detection of
20702633f736SMark Brown * plain headphones and give up if neither polarity looks
20712633f736SMark Brown * sensible.
2072ba896edeSMark Brown */
2073ba896edeSMark Brown if (wm5100->jack_detecting && (val & 0x3f8)) {
20742633f736SMark Brown wm5100->jack_flips++;
20752633f736SMark Brown
20762633f736SMark Brown if (wm5100->jack_flips > 1)
20772633f736SMark Brown wm5100_report_headphone(wm5100);
20782633f736SMark Brown else
207946c1a877SMark Brown wm5100_set_detect_mode(wm5100, !wm5100->jack_mode);
2080ba896edeSMark Brown
2081ba896edeSMark Brown return;
2082ba896edeSMark Brown }
2083ba896edeSMark Brown
2084ba896edeSMark Brown /* Don't distinguish between buttons, just report any low
2085ba896edeSMark Brown * impedence as BTN_0.
2086ba896edeSMark Brown */
2087ba896edeSMark Brown if (val & 0x3fc) {
2088ba896edeSMark Brown if (wm5100->jack_mic) {
208946c1a877SMark Brown dev_dbg(wm5100->dev, "Mic button detected\n");
2090ba896edeSMark Brown snd_soc_jack_report(wm5100->jack, SND_JACK_BTN_0,
2091ba896edeSMark Brown SND_JACK_BTN_0);
2092ba896edeSMark Brown } else if (wm5100->jack_detecting) {
20932633f736SMark Brown wm5100_report_headphone(wm5100);
2094ba896edeSMark Brown }
2095ba896edeSMark Brown }
2096ba896edeSMark Brown }
2097ba896edeSMark Brown
wm5100_detect(struct snd_soc_component * component,struct snd_soc_jack * jack)209861195838SKuninori Morimoto int wm5100_detect(struct snd_soc_component *component, struct snd_soc_jack *jack)
2099ba896edeSMark Brown {
210061195838SKuninori Morimoto struct wm5100_priv *wm5100 = snd_soc_component_get_drvdata(component);
210161195838SKuninori Morimoto struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
2102ba896edeSMark Brown
2103ba896edeSMark Brown if (jack) {
2104ba896edeSMark Brown wm5100->jack = jack;
2105ba896edeSMark Brown wm5100->jack_detecting = true;
21062633f736SMark Brown wm5100->jack_flips = 0;
2107ba896edeSMark Brown
210846c1a877SMark Brown wm5100_set_detect_mode(wm5100, 0);
2109ba896edeSMark Brown
2110ba896edeSMark Brown /* Slowest detection rate, gives debounce for initial
2111ba896edeSMark Brown * detection */
211261195838SKuninori Morimoto snd_soc_component_update_bits(component, WM5100_MIC_DETECT_1,
2113ba896edeSMark Brown WM5100_ACCDET_BIAS_STARTTIME_MASK |
2114ba896edeSMark Brown WM5100_ACCDET_RATE_MASK,
2115ba896edeSMark Brown (7 << WM5100_ACCDET_BIAS_STARTTIME_SHIFT) |
2116ba896edeSMark Brown WM5100_ACCDET_RATE_MASK);
2117ba896edeSMark Brown
2118ba896edeSMark Brown /* We need the charge pump to power MICBIAS */
2119e951f267SCharles Keepax snd_soc_dapm_mutex_lock(dapm);
2120e951f267SCharles Keepax
2121e951f267SCharles Keepax snd_soc_dapm_force_enable_pin_unlocked(dapm, "CP2");
2122e951f267SCharles Keepax snd_soc_dapm_force_enable_pin_unlocked(dapm, "SYSCLK");
2123e951f267SCharles Keepax
2124e951f267SCharles Keepax snd_soc_dapm_sync_unlocked(dapm);
2125e951f267SCharles Keepax
2126e951f267SCharles Keepax snd_soc_dapm_mutex_unlock(dapm);
2127ba896edeSMark Brown
2128ba896edeSMark Brown /* We start off just enabling microphone detection - even a
2129ba896edeSMark Brown * plain headphone will trigger detection.
2130ba896edeSMark Brown */
213161195838SKuninori Morimoto snd_soc_component_update_bits(component, WM5100_MIC_DETECT_1,
2132ba896edeSMark Brown WM5100_ACCDET_ENA, WM5100_ACCDET_ENA);
2133ba896edeSMark Brown
213461195838SKuninori Morimoto snd_soc_component_update_bits(component, WM5100_INTERRUPT_STATUS_3_MASK,
2135ba896edeSMark Brown WM5100_IM_ACCDET_EINT, 0);
2136ba896edeSMark Brown } else {
213761195838SKuninori Morimoto snd_soc_component_update_bits(component, WM5100_INTERRUPT_STATUS_3_MASK,
2138ba896edeSMark Brown WM5100_IM_HPDET_EINT |
2139ba896edeSMark Brown WM5100_IM_ACCDET_EINT,
2140ba896edeSMark Brown WM5100_IM_HPDET_EINT |
2141ba896edeSMark Brown WM5100_IM_ACCDET_EINT);
214261195838SKuninori Morimoto snd_soc_component_update_bits(component, WM5100_MIC_DETECT_1,
2143ba896edeSMark Brown WM5100_ACCDET_ENA, 0);
2144ba896edeSMark Brown wm5100->jack = NULL;
2145ba896edeSMark Brown }
2146ba896edeSMark Brown
2147ba896edeSMark Brown return 0;
2148ba896edeSMark Brown }
21490cf0f174SSachin Kamat EXPORT_SYMBOL_GPL(wm5100_detect);
2150ba896edeSMark Brown
wm5100_irq(int irq,void * data)21516d4baf08SMark Brown static irqreturn_t wm5100_irq(int irq, void *data)
21526d4baf08SMark Brown {
215346c1a877SMark Brown struct wm5100_priv *wm5100 = data;
21546d4baf08SMark Brown irqreturn_t status = IRQ_NONE;
215546c1a877SMark Brown unsigned int irq_val, mask_val;
215646c1a877SMark Brown int ret;
21576d4baf08SMark Brown
215846c1a877SMark Brown ret = regmap_read(wm5100->regmap, WM5100_INTERRUPT_STATUS_3, &irq_val);
215946c1a877SMark Brown if (ret < 0) {
216046c1a877SMark Brown dev_err(wm5100->dev, "Failed to read IRQ status 3: %d\n",
216146c1a877SMark Brown ret);
21626d4baf08SMark Brown irq_val = 0;
21636d4baf08SMark Brown }
21646d4baf08SMark Brown
216546c1a877SMark Brown ret = regmap_read(wm5100->regmap, WM5100_INTERRUPT_STATUS_3_MASK,
216646c1a877SMark Brown &mask_val);
216746c1a877SMark Brown if (ret < 0) {
216846c1a877SMark Brown dev_err(wm5100->dev, "Failed to read IRQ mask 3: %d\n",
216946c1a877SMark Brown ret);
217046c1a877SMark Brown mask_val = 0xffff;
217146c1a877SMark Brown }
217246c1a877SMark Brown
217346c1a877SMark Brown irq_val &= ~mask_val;
217446c1a877SMark Brown
217546c1a877SMark Brown regmap_write(wm5100->regmap, WM5100_INTERRUPT_STATUS_3, irq_val);
21766d4baf08SMark Brown
21776d4baf08SMark Brown if (irq_val)
21786d4baf08SMark Brown status = IRQ_HANDLED;
21796d4baf08SMark Brown
218046c1a877SMark Brown wm5100_log_status3(wm5100, irq_val);
21816d4baf08SMark Brown
21826d4baf08SMark Brown if (irq_val & WM5100_FLL1_LOCK_EINT) {
218346c1a877SMark Brown dev_dbg(wm5100->dev, "FLL1 locked\n");
21846d4baf08SMark Brown complete(&wm5100->fll[0].lock);
21856d4baf08SMark Brown }
21866d4baf08SMark Brown if (irq_val & WM5100_FLL2_LOCK_EINT) {
218746c1a877SMark Brown dev_dbg(wm5100->dev, "FLL2 locked\n");
21886d4baf08SMark Brown complete(&wm5100->fll[1].lock);
21896d4baf08SMark Brown }
21906d4baf08SMark Brown
2191ba896edeSMark Brown if (irq_val & WM5100_ACCDET_EINT)
219246c1a877SMark Brown wm5100_micd_irq(wm5100);
2193ba896edeSMark Brown
219446c1a877SMark Brown ret = regmap_read(wm5100->regmap, WM5100_INTERRUPT_STATUS_4, &irq_val);
219546c1a877SMark Brown if (ret < 0) {
219646c1a877SMark Brown dev_err(wm5100->dev, "Failed to read IRQ status 4: %d\n",
219746c1a877SMark Brown ret);
21986d4baf08SMark Brown irq_val = 0;
21996d4baf08SMark Brown }
220046c1a877SMark Brown
220146c1a877SMark Brown ret = regmap_read(wm5100->regmap, WM5100_INTERRUPT_STATUS_4_MASK,
220246c1a877SMark Brown &mask_val);
220346c1a877SMark Brown if (ret < 0) {
220446c1a877SMark Brown dev_err(wm5100->dev, "Failed to read IRQ mask 4: %d\n",
220546c1a877SMark Brown ret);
220646c1a877SMark Brown mask_val = 0xffff;
220746c1a877SMark Brown }
220846c1a877SMark Brown
220946c1a877SMark Brown irq_val &= ~mask_val;
22106d4baf08SMark Brown
22116d4baf08SMark Brown if (irq_val)
22126d4baf08SMark Brown status = IRQ_HANDLED;
22136d4baf08SMark Brown
221446c1a877SMark Brown regmap_write(wm5100->regmap, WM5100_INTERRUPT_STATUS_4, irq_val);
22156d4baf08SMark Brown
221646c1a877SMark Brown wm5100_log_status4(wm5100, irq_val);
22176d4baf08SMark Brown
22186d4baf08SMark Brown return status;
22196d4baf08SMark Brown }
22206d4baf08SMark Brown
wm5100_edge_irq(int irq,void * data)22216d4baf08SMark Brown static irqreturn_t wm5100_edge_irq(int irq, void *data)
22226d4baf08SMark Brown {
22236d4baf08SMark Brown irqreturn_t ret = IRQ_NONE;
22246d4baf08SMark Brown irqreturn_t val;
22256d4baf08SMark Brown
22266d4baf08SMark Brown do {
22276d4baf08SMark Brown val = wm5100_irq(irq, data);
22286d4baf08SMark Brown if (val != IRQ_NONE)
22296d4baf08SMark Brown ret = val;
22306d4baf08SMark Brown } while (val != IRQ_NONE);
22316d4baf08SMark Brown
22326d4baf08SMark Brown return ret;
22336d4baf08SMark Brown }
22346d4baf08SMark Brown
22356d4baf08SMark Brown #ifdef CONFIG_GPIOLIB
wm5100_gpio_set(struct gpio_chip * chip,unsigned offset,int value)22366d4baf08SMark Brown static void wm5100_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
22376d4baf08SMark Brown {
2238db1d1270SLinus Walleij struct wm5100_priv *wm5100 = gpiochip_get_data(chip);
22396d4baf08SMark Brown
22409db16e4cSMark Brown regmap_update_bits(wm5100->regmap, WM5100_GPIO_CTRL_1 + offset,
22416d4baf08SMark Brown WM5100_GP1_LVL, !!value << WM5100_GP1_LVL_SHIFT);
22426d4baf08SMark Brown }
22436d4baf08SMark Brown
wm5100_gpio_direction_out(struct gpio_chip * chip,unsigned offset,int value)22446d4baf08SMark Brown static int wm5100_gpio_direction_out(struct gpio_chip *chip,
22456d4baf08SMark Brown unsigned offset, int value)
22466d4baf08SMark Brown {
2247db1d1270SLinus Walleij struct wm5100_priv *wm5100 = gpiochip_get_data(chip);
224864964e82SMark Brown int val, ret;
22496d4baf08SMark Brown
22506d4baf08SMark Brown val = (1 << WM5100_GP1_FN_SHIFT) | (!!value << WM5100_GP1_LVL_SHIFT);
22516d4baf08SMark Brown
22529db16e4cSMark Brown ret = regmap_update_bits(wm5100->regmap, WM5100_GPIO_CTRL_1 + offset,
22536d4baf08SMark Brown WM5100_GP1_FN_MASK | WM5100_GP1_DIR |
22546d4baf08SMark Brown WM5100_GP1_LVL, val);
225564964e82SMark Brown if (ret < 0)
225664964e82SMark Brown return ret;
225764964e82SMark Brown else
225864964e82SMark Brown return 0;
22596d4baf08SMark Brown }
22606d4baf08SMark Brown
wm5100_gpio_get(struct gpio_chip * chip,unsigned offset)22616d4baf08SMark Brown static int wm5100_gpio_get(struct gpio_chip *chip, unsigned offset)
22626d4baf08SMark Brown {
2263db1d1270SLinus Walleij struct wm5100_priv *wm5100 = gpiochip_get_data(chip);
22649db16e4cSMark Brown unsigned int reg;
22656d4baf08SMark Brown int ret;
22666d4baf08SMark Brown
22679db16e4cSMark Brown ret = regmap_read(wm5100->regmap, WM5100_GPIO_CTRL_1 + offset, ®);
22686d4baf08SMark Brown if (ret < 0)
22696d4baf08SMark Brown return ret;
22706d4baf08SMark Brown
22719db16e4cSMark Brown return (reg & WM5100_GP1_LVL) != 0;
22726d4baf08SMark Brown }
22736d4baf08SMark Brown
wm5100_gpio_direction_in(struct gpio_chip * chip,unsigned offset)22746d4baf08SMark Brown static int wm5100_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
22756d4baf08SMark Brown {
2276db1d1270SLinus Walleij struct wm5100_priv *wm5100 = gpiochip_get_data(chip);
22776d4baf08SMark Brown
22789db16e4cSMark Brown return regmap_update_bits(wm5100->regmap, WM5100_GPIO_CTRL_1 + offset,
22796d4baf08SMark Brown WM5100_GP1_FN_MASK | WM5100_GP1_DIR,
22806d4baf08SMark Brown (1 << WM5100_GP1_FN_SHIFT) |
22816d4baf08SMark Brown (1 << WM5100_GP1_DIR_SHIFT));
22826d4baf08SMark Brown }
22836d4baf08SMark Brown
2284c59b24f8SJulia Lawall static const struct gpio_chip wm5100_template_chip = {
22856d4baf08SMark Brown .label = "wm5100",
22866d4baf08SMark Brown .owner = THIS_MODULE,
22876d4baf08SMark Brown .direction_output = wm5100_gpio_direction_out,
22886d4baf08SMark Brown .set = wm5100_gpio_set,
22896d4baf08SMark Brown .direction_input = wm5100_gpio_direction_in,
22906d4baf08SMark Brown .get = wm5100_gpio_get,
22916d4baf08SMark Brown .can_sleep = 1,
22926d4baf08SMark Brown };
22936d4baf08SMark Brown
wm5100_init_gpio(struct i2c_client * i2c)22949db16e4cSMark Brown static void wm5100_init_gpio(struct i2c_client *i2c)
22956d4baf08SMark Brown {
22969db16e4cSMark Brown struct wm5100_priv *wm5100 = i2c_get_clientdata(i2c);
22976d4baf08SMark Brown int ret;
22986d4baf08SMark Brown
22996d4baf08SMark Brown wm5100->gpio_chip = wm5100_template_chip;
23006d4baf08SMark Brown wm5100->gpio_chip.ngpio = 6;
230158383c78SLinus Walleij wm5100->gpio_chip.parent = &i2c->dev;
23026d4baf08SMark Brown
23036d4baf08SMark Brown if (wm5100->pdata.gpio_base)
23046d4baf08SMark Brown wm5100->gpio_chip.base = wm5100->pdata.gpio_base;
23056d4baf08SMark Brown else
23066d4baf08SMark Brown wm5100->gpio_chip.base = -1;
23076d4baf08SMark Brown
2308db1d1270SLinus Walleij ret = gpiochip_add_data(&wm5100->gpio_chip, wm5100);
23096d4baf08SMark Brown if (ret != 0)
23109db16e4cSMark Brown dev_err(&i2c->dev, "Failed to add GPIOs: %d\n", ret);
23116d4baf08SMark Brown }
23126d4baf08SMark Brown
wm5100_free_gpio(struct i2c_client * i2c)23139db16e4cSMark Brown static void wm5100_free_gpio(struct i2c_client *i2c)
23146d4baf08SMark Brown {
23159db16e4cSMark Brown struct wm5100_priv *wm5100 = i2c_get_clientdata(i2c);
23166d4baf08SMark Brown
231788d5e520Sabdoulaye berthe gpiochip_remove(&wm5100->gpio_chip);
23186d4baf08SMark Brown }
23196d4baf08SMark Brown #else
wm5100_init_gpio(struct i2c_client * i2c)23209db16e4cSMark Brown static void wm5100_init_gpio(struct i2c_client *i2c)
23216d4baf08SMark Brown {
23226d4baf08SMark Brown }
23236d4baf08SMark Brown
wm5100_free_gpio(struct i2c_client * i2c)23249db16e4cSMark Brown static void wm5100_free_gpio(struct i2c_client *i2c)
23256d4baf08SMark Brown {
23266d4baf08SMark Brown }
23276d4baf08SMark Brown #endif
23286d4baf08SMark Brown
wm5100_probe(struct snd_soc_component * component)232961195838SKuninori Morimoto static int wm5100_probe(struct snd_soc_component *component)
23306d4baf08SMark Brown {
233161195838SKuninori Morimoto struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
233261195838SKuninori Morimoto struct i2c_client *i2c = to_i2c_client(component->dev);
233361195838SKuninori Morimoto struct wm5100_priv *wm5100 = snd_soc_component_get_drvdata(component);
233409452f23SMark Brown int ret, i;
23356d4baf08SMark Brown
233661195838SKuninori Morimoto wm5100->component = component;
23376d4baf08SMark Brown
23386d4baf08SMark Brown for (i = 0; i < ARRAY_SIZE(wm5100_dig_vu); i++)
233961195838SKuninori Morimoto snd_soc_component_update_bits(component, wm5100_dig_vu[i], WM5100_OUT_VU,
23406d4baf08SMark Brown WM5100_OUT_VU);
23416d4baf08SMark Brown
23426d4baf08SMark Brown /* Don't debounce interrupts to support use of SYSCLK only */
234361195838SKuninori Morimoto snd_soc_component_write(component, WM5100_IRQ_DEBOUNCE_1, 0);
234461195838SKuninori Morimoto snd_soc_component_write(component, WM5100_IRQ_DEBOUNCE_2, 0);
23456d4baf08SMark Brown
23466d4baf08SMark Brown /* TODO: check if we're symmetric */
23476d4baf08SMark Brown
234809452f23SMark Brown if (i2c->irq)
2349002d1c4eSLars-Peter Clausen snd_soc_dapm_new_controls(dapm, wm5100_dapm_widgets_noirq,
23506d4baf08SMark Brown ARRAY_SIZE(wm5100_dapm_widgets_noirq));
23516d4baf08SMark Brown
23526d4baf08SMark Brown if (wm5100->pdata.hp_pol) {
23536d4baf08SMark Brown ret = gpio_request_one(wm5100->pdata.hp_pol,
23546d4baf08SMark Brown GPIOF_OUT_INIT_HIGH, "WM5100 HP_POL");
23556d4baf08SMark Brown if (ret < 0) {
23566d4baf08SMark Brown dev_err(&i2c->dev, "Failed to request HP_POL %d: %d\n",
23576d4baf08SMark Brown wm5100->pdata.hp_pol, ret);
23586d4baf08SMark Brown goto err_gpio;
23596d4baf08SMark Brown }
23606d4baf08SMark Brown }
23616d4baf08SMark Brown
23626d4baf08SMark Brown return 0;
23636d4baf08SMark Brown
23646d4baf08SMark Brown err_gpio:
23656d4baf08SMark Brown
23666d4baf08SMark Brown return ret;
23676d4baf08SMark Brown }
23686d4baf08SMark Brown
wm5100_remove(struct snd_soc_component * component)236961195838SKuninori Morimoto static void wm5100_remove(struct snd_soc_component *component)
23706d4baf08SMark Brown {
237161195838SKuninori Morimoto struct wm5100_priv *wm5100 = snd_soc_component_get_drvdata(component);
23726d4baf08SMark Brown
23736d4baf08SMark Brown if (wm5100->pdata.hp_pol) {
23746d4baf08SMark Brown gpio_free(wm5100->pdata.hp_pol);
23756d4baf08SMark Brown }
23766d4baf08SMark Brown }
23776d4baf08SMark Brown
237861195838SKuninori Morimoto static const struct snd_soc_component_driver soc_component_dev_wm5100 = {
23796d4baf08SMark Brown .probe = wm5100_probe,
23806d4baf08SMark Brown .remove = wm5100_remove,
23816d4baf08SMark Brown .set_sysclk = wm5100_set_sysclk,
23826d4baf08SMark Brown .set_pll = wm5100_set_fll,
23836d4baf08SMark Brown .seq_notifier = wm5100_seq_notifier,
23846d4baf08SMark Brown .controls = wm5100_snd_controls,
23856d4baf08SMark Brown .num_controls = ARRAY_SIZE(wm5100_snd_controls),
23866d4baf08SMark Brown .dapm_widgets = wm5100_dapm_widgets,
23876d4baf08SMark Brown .num_dapm_widgets = ARRAY_SIZE(wm5100_dapm_widgets),
23886d4baf08SMark Brown .dapm_routes = wm5100_dapm_routes,
23896d4baf08SMark Brown .num_dapm_routes = ARRAY_SIZE(wm5100_dapm_routes),
239061195838SKuninori Morimoto .use_pmdown_time = 1,
239161195838SKuninori Morimoto .endianness = 1,
2392bd132ec5SMark Brown };
23936d4baf08SMark Brown
2394bd132ec5SMark Brown static const struct regmap_config wm5100_regmap = {
2395bd132ec5SMark Brown .reg_bits = 16,
2396bd132ec5SMark Brown .val_bits = 16,
23976d4baf08SMark Brown
2398bd132ec5SMark Brown .max_register = WM5100_MAX_REGISTER,
2399bd132ec5SMark Brown .reg_defaults = wm5100_reg_defaults,
2400bd132ec5SMark Brown .num_reg_defaults = ARRAY_SIZE(wm5100_reg_defaults),
2401bd132ec5SMark Brown .volatile_reg = wm5100_volatile_register,
2402bd132ec5SMark Brown .readable_reg = wm5100_readable_register,
2403*4f2e3688SMark Brown .cache_type = REGCACHE_MAPLE,
24046d4baf08SMark Brown };
24056d4baf08SMark Brown
2406a188fcbaSMark Brown static const unsigned int wm5100_mic_ctrl_reg[] = {
2407a188fcbaSMark Brown WM5100_IN1L_CONTROL,
2408a188fcbaSMark Brown WM5100_IN2L_CONTROL,
2409a188fcbaSMark Brown WM5100_IN3L_CONTROL,
2410a188fcbaSMark Brown WM5100_IN4L_CONTROL,
2411a188fcbaSMark Brown };
2412a188fcbaSMark Brown
wm5100_i2c_probe(struct i2c_client * i2c)241397b0b6e3SStephen Kitt static int wm5100_i2c_probe(struct i2c_client *i2c)
24146d4baf08SMark Brown {
24156d4baf08SMark Brown struct wm5100_pdata *pdata = dev_get_platdata(&i2c->dev);
24166d4baf08SMark Brown struct wm5100_priv *wm5100;
2417588ac5e0SMark Brown unsigned int reg;
241809452f23SMark Brown int ret, i, irq_flags;
24196d4baf08SMark Brown
2420a81b82c0SMark Brown wm5100 = devm_kzalloc(&i2c->dev, sizeof(struct wm5100_priv),
2421a81b82c0SMark Brown GFP_KERNEL);
24226d4baf08SMark Brown if (wm5100 == NULL)
24236d4baf08SMark Brown return -ENOMEM;
24246d4baf08SMark Brown
242546c1a877SMark Brown wm5100->dev = &i2c->dev;
242646c1a877SMark Brown
242777caabaaSMark Brown wm5100->regmap = devm_regmap_init_i2c(i2c, &wm5100_regmap);
2428bd132ec5SMark Brown if (IS_ERR(wm5100->regmap)) {
2429bd132ec5SMark Brown ret = PTR_ERR(wm5100->regmap);
2430bd132ec5SMark Brown dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
2431bd132ec5SMark Brown ret);
2432a81b82c0SMark Brown goto err;
2433bd132ec5SMark Brown }
2434bd132ec5SMark Brown
24356d4baf08SMark Brown for (i = 0; i < ARRAY_SIZE(wm5100->fll); i++)
24366d4baf08SMark Brown init_completion(&wm5100->fll[i].lock);
24376d4baf08SMark Brown
24386d4baf08SMark Brown if (pdata)
24396d4baf08SMark Brown wm5100->pdata = *pdata;
24406d4baf08SMark Brown
24416d4baf08SMark Brown i2c_set_clientdata(i2c, wm5100);
24426d4baf08SMark Brown
2443588ac5e0SMark Brown for (i = 0; i < ARRAY_SIZE(wm5100->core_supplies); i++)
2444588ac5e0SMark Brown wm5100->core_supplies[i].supply = wm5100_core_supply_names[i];
2445588ac5e0SMark Brown
244617e3e57bSMark Brown ret = devm_regulator_bulk_get(&i2c->dev,
244717e3e57bSMark Brown ARRAY_SIZE(wm5100->core_supplies),
2448588ac5e0SMark Brown wm5100->core_supplies);
2449588ac5e0SMark Brown if (ret != 0) {
2450588ac5e0SMark Brown dev_err(&i2c->dev, "Failed to request core supplies: %d\n",
2451588ac5e0SMark Brown ret);
245277caabaaSMark Brown goto err;
2453588ac5e0SMark Brown }
2454588ac5e0SMark Brown
2455588ac5e0SMark Brown ret = regulator_bulk_enable(ARRAY_SIZE(wm5100->core_supplies),
2456588ac5e0SMark Brown wm5100->core_supplies);
2457588ac5e0SMark Brown if (ret != 0) {
2458588ac5e0SMark Brown dev_err(&i2c->dev, "Failed to enable core supplies: %d\n",
2459588ac5e0SMark Brown ret);
246077caabaaSMark Brown goto err;
2461588ac5e0SMark Brown }
2462588ac5e0SMark Brown
2463588ac5e0SMark Brown if (wm5100->pdata.ldo_ena) {
2464588ac5e0SMark Brown ret = gpio_request_one(wm5100->pdata.ldo_ena,
2465588ac5e0SMark Brown GPIOF_OUT_INIT_HIGH, "WM5100 LDOENA");
2466588ac5e0SMark Brown if (ret < 0) {
2467588ac5e0SMark Brown dev_err(&i2c->dev, "Failed to request LDOENA %d: %d\n",
2468588ac5e0SMark Brown wm5100->pdata.ldo_ena, ret);
2469588ac5e0SMark Brown goto err_enable;
2470588ac5e0SMark Brown }
2471588ac5e0SMark Brown msleep(2);
2472588ac5e0SMark Brown }
2473588ac5e0SMark Brown
2474588ac5e0SMark Brown if (wm5100->pdata.reset) {
2475588ac5e0SMark Brown ret = gpio_request_one(wm5100->pdata.reset,
2476588ac5e0SMark Brown GPIOF_OUT_INIT_HIGH, "WM5100 /RESET");
2477588ac5e0SMark Brown if (ret < 0) {
2478588ac5e0SMark Brown dev_err(&i2c->dev, "Failed to request /RESET %d: %d\n",
2479588ac5e0SMark Brown wm5100->pdata.reset, ret);
2480588ac5e0SMark Brown goto err_ldo;
2481588ac5e0SMark Brown }
2482588ac5e0SMark Brown }
2483588ac5e0SMark Brown
2484588ac5e0SMark Brown ret = regmap_read(wm5100->regmap, WM5100_SOFTWARE_RESET, ®);
2485588ac5e0SMark Brown if (ret < 0) {
24860132615dSMark Brown dev_err(&i2c->dev, "Failed to read ID register: %d\n", ret);
2487588ac5e0SMark Brown goto err_reset;
2488588ac5e0SMark Brown }
2489588ac5e0SMark Brown switch (reg) {
2490588ac5e0SMark Brown case 0x8997:
2491588ac5e0SMark Brown case 0x5100:
2492588ac5e0SMark Brown break;
2493588ac5e0SMark Brown
2494588ac5e0SMark Brown default:
2495588ac5e0SMark Brown dev_err(&i2c->dev, "Device is not a WM5100, ID is %x\n", reg);
2496588ac5e0SMark Brown ret = -EINVAL;
2497588ac5e0SMark Brown goto err_reset;
2498588ac5e0SMark Brown }
2499588ac5e0SMark Brown
2500588ac5e0SMark Brown ret = regmap_read(wm5100->regmap, WM5100_DEVICE_REVISION, ®);
2501588ac5e0SMark Brown if (ret < 0) {
2502588ac5e0SMark Brown dev_err(&i2c->dev, "Failed to read revision register\n");
2503588ac5e0SMark Brown goto err_reset;
2504588ac5e0SMark Brown }
2505588ac5e0SMark Brown wm5100->rev = reg & WM5100_DEVICE_REVISION_MASK;
2506588ac5e0SMark Brown
2507588ac5e0SMark Brown dev_info(&i2c->dev, "revision %c\n", wm5100->rev + 'A');
2508588ac5e0SMark Brown
2509588ac5e0SMark Brown ret = wm5100_reset(wm5100);
2510588ac5e0SMark Brown if (ret < 0) {
2511588ac5e0SMark Brown dev_err(&i2c->dev, "Failed to issue reset\n");
2512588ac5e0SMark Brown goto err_reset;
2513588ac5e0SMark Brown }
2514588ac5e0SMark Brown
251515b52f10SMark Brown switch (wm5100->rev) {
251615b52f10SMark Brown case 0:
251715b52f10SMark Brown ret = regmap_register_patch(wm5100->regmap,
251815b52f10SMark Brown wm5100_reva_patches,
251915b52f10SMark Brown ARRAY_SIZE(wm5100_reva_patches));
252015b52f10SMark Brown if (ret != 0) {
252115b52f10SMark Brown dev_err(&i2c->dev, "Failed to register patches: %d\n",
252215b52f10SMark Brown ret);
252315b52f10SMark Brown goto err_reset;
252415b52f10SMark Brown }
252515b52f10SMark Brown break;
252615b52f10SMark Brown default:
252715b52f10SMark Brown break;
252815b52f10SMark Brown }
252915b52f10SMark Brown
253015b52f10SMark Brown
25319db16e4cSMark Brown wm5100_init_gpio(i2c);
25329db16e4cSMark Brown
2533d9b5e9c6SMark Brown for (i = 0; i < ARRAY_SIZE(wm5100->pdata.gpio_defaults); i++) {
2534d9b5e9c6SMark Brown if (!wm5100->pdata.gpio_defaults[i])
2535d9b5e9c6SMark Brown continue;
2536d9b5e9c6SMark Brown
2537d9b5e9c6SMark Brown regmap_write(wm5100->regmap, WM5100_GPIO_CTRL_1 + i,
2538d9b5e9c6SMark Brown wm5100->pdata.gpio_defaults[i]);
2539d9b5e9c6SMark Brown }
2540d9b5e9c6SMark Brown
2541d9b5e9c6SMark Brown for (i = 0; i < ARRAY_SIZE(wm5100->pdata.in_mode); i++) {
2542a188fcbaSMark Brown regmap_update_bits(wm5100->regmap, wm5100_mic_ctrl_reg[i],
2543d9b5e9c6SMark Brown WM5100_IN1_MODE_MASK |
2544d9b5e9c6SMark Brown WM5100_IN1_DMIC_SUP_MASK,
2545d9b5e9c6SMark Brown (wm5100->pdata.in_mode[i] <<
2546d9b5e9c6SMark Brown WM5100_IN1_MODE_SHIFT) |
2547d9b5e9c6SMark Brown (wm5100->pdata.dmic_sup[i] <<
2548d9b5e9c6SMark Brown WM5100_IN1_DMIC_SUP_SHIFT));
2549d9b5e9c6SMark Brown }
2550d9b5e9c6SMark Brown
255109452f23SMark Brown if (i2c->irq) {
255209452f23SMark Brown if (wm5100->pdata.irq_flags)
255309452f23SMark Brown irq_flags = wm5100->pdata.irq_flags;
255409452f23SMark Brown else
255509452f23SMark Brown irq_flags = IRQF_TRIGGER_LOW;
255609452f23SMark Brown
255709452f23SMark Brown irq_flags |= IRQF_ONESHOT;
255809452f23SMark Brown
255909452f23SMark Brown if (irq_flags & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING))
256009452f23SMark Brown ret = request_threaded_irq(i2c->irq, NULL,
2561efc04ca2SAxel Lin wm5100_edge_irq, irq_flags,
256209452f23SMark Brown "wm5100", wm5100);
256309452f23SMark Brown else
256409452f23SMark Brown ret = request_threaded_irq(i2c->irq, NULL, wm5100_irq,
2565efc04ca2SAxel Lin irq_flags, "wm5100",
256609452f23SMark Brown wm5100);
256709452f23SMark Brown
256809452f23SMark Brown if (ret != 0) {
256909452f23SMark Brown dev_err(&i2c->dev, "Failed to request IRQ %d: %d\n",
257009452f23SMark Brown i2c->irq, ret);
257109452f23SMark Brown } else {
257209452f23SMark Brown /* Enable default interrupts */
257309452f23SMark Brown regmap_update_bits(wm5100->regmap,
257409452f23SMark Brown WM5100_INTERRUPT_STATUS_3_MASK,
257509452f23SMark Brown WM5100_IM_SPK_SHUTDOWN_WARN_EINT |
257609452f23SMark Brown WM5100_IM_SPK_SHUTDOWN_EINT |
257709452f23SMark Brown WM5100_IM_ASRC2_LOCK_EINT |
257809452f23SMark Brown WM5100_IM_ASRC1_LOCK_EINT |
257909452f23SMark Brown WM5100_IM_FLL2_LOCK_EINT |
258009452f23SMark Brown WM5100_IM_FLL1_LOCK_EINT |
258109452f23SMark Brown WM5100_CLKGEN_ERR_EINT |
258209452f23SMark Brown WM5100_CLKGEN_ERR_ASYNC_EINT, 0);
258309452f23SMark Brown
258409452f23SMark Brown regmap_update_bits(wm5100->regmap,
258509452f23SMark Brown WM5100_INTERRUPT_STATUS_4_MASK,
258609452f23SMark Brown WM5100_AIF3_ERR_EINT |
258709452f23SMark Brown WM5100_AIF2_ERR_EINT |
258809452f23SMark Brown WM5100_AIF1_ERR_EINT |
258909452f23SMark Brown WM5100_CTRLIF_ERR_EINT |
259009452f23SMark Brown WM5100_ISRC2_UNDERCLOCKED_EINT |
259109452f23SMark Brown WM5100_ISRC1_UNDERCLOCKED_EINT |
259209452f23SMark Brown WM5100_FX_UNDERCLOCKED_EINT |
259309452f23SMark Brown WM5100_AIF3_UNDERCLOCKED_EINT |
259409452f23SMark Brown WM5100_AIF2_UNDERCLOCKED_EINT |
259509452f23SMark Brown WM5100_AIF1_UNDERCLOCKED_EINT |
259609452f23SMark Brown WM5100_ASRC_UNDERCLOCKED_EINT |
259709452f23SMark Brown WM5100_DAC_UNDERCLOCKED_EINT |
259809452f23SMark Brown WM5100_ADC_UNDERCLOCKED_EINT |
259909452f23SMark Brown WM5100_MIXER_UNDERCLOCKED_EINT, 0);
260009452f23SMark Brown }
260109452f23SMark Brown }
260209452f23SMark Brown
260362c1c401SMark Brown pm_runtime_set_active(&i2c->dev);
260462c1c401SMark Brown pm_runtime_enable(&i2c->dev);
260562c1c401SMark Brown pm_request_idle(&i2c->dev);
260662c1c401SMark Brown
260761195838SKuninori Morimoto ret = devm_snd_soc_register_component(&i2c->dev,
260861195838SKuninori Morimoto &soc_component_dev_wm5100, wm5100_dai,
26096d4baf08SMark Brown ARRAY_SIZE(wm5100_dai));
26106d4baf08SMark Brown if (ret < 0) {
26116d4baf08SMark Brown dev_err(&i2c->dev, "Failed to register WM5100: %d\n", ret);
2612588ac5e0SMark Brown goto err_reset;
26136d4baf08SMark Brown }
26146d4baf08SMark Brown
26156d4baf08SMark Brown return ret;
2616bd132ec5SMark Brown
2617588ac5e0SMark Brown err_reset:
2618b1176bbbSChuhong Yuan pm_runtime_disable(&i2c->dev);
261909452f23SMark Brown if (i2c->irq)
262009452f23SMark Brown free_irq(i2c->irq, wm5100);
26219db16e4cSMark Brown wm5100_free_gpio(i2c);
2622588ac5e0SMark Brown if (wm5100->pdata.reset) {
26232688738eSMark Brown gpio_set_value_cansleep(wm5100->pdata.reset, 0);
2624588ac5e0SMark Brown gpio_free(wm5100->pdata.reset);
2625588ac5e0SMark Brown }
2626588ac5e0SMark Brown err_ldo:
2627588ac5e0SMark Brown if (wm5100->pdata.ldo_ena) {
2628588ac5e0SMark Brown gpio_set_value_cansleep(wm5100->pdata.ldo_ena, 0);
2629588ac5e0SMark Brown gpio_free(wm5100->pdata.ldo_ena);
2630588ac5e0SMark Brown }
2631588ac5e0SMark Brown err_enable:
2632588ac5e0SMark Brown regulator_bulk_disable(ARRAY_SIZE(wm5100->core_supplies),
2633588ac5e0SMark Brown wm5100->core_supplies);
2634a81b82c0SMark Brown err:
2635bd132ec5SMark Brown return ret;
26366d4baf08SMark Brown }
26376d4baf08SMark Brown
wm5100_i2c_remove(struct i2c_client * i2c)2638ed5c2f5fSUwe Kleine-König static void wm5100_i2c_remove(struct i2c_client *i2c)
26396d4baf08SMark Brown {
264009452f23SMark Brown struct wm5100_priv *wm5100 = i2c_get_clientdata(i2c);
2641bd132ec5SMark Brown
2642b1176bbbSChuhong Yuan pm_runtime_disable(&i2c->dev);
264309452f23SMark Brown if (i2c->irq)
264409452f23SMark Brown free_irq(i2c->irq, wm5100);
264509452f23SMark Brown wm5100_free_gpio(i2c);
2646588ac5e0SMark Brown if (wm5100->pdata.reset) {
26472688738eSMark Brown gpio_set_value_cansleep(wm5100->pdata.reset, 0);
2648588ac5e0SMark Brown gpio_free(wm5100->pdata.reset);
2649588ac5e0SMark Brown }
2650588ac5e0SMark Brown if (wm5100->pdata.ldo_ena) {
2651588ac5e0SMark Brown gpio_set_value_cansleep(wm5100->pdata.ldo_ena, 0);
2652588ac5e0SMark Brown gpio_free(wm5100->pdata.ldo_ena);
2653588ac5e0SMark Brown }
26546d4baf08SMark Brown }
26556d4baf08SMark Brown
2656641d334bSRafael J. Wysocki #ifdef CONFIG_PM
wm5100_runtime_suspend(struct device * dev)265762c1c401SMark Brown static int wm5100_runtime_suspend(struct device *dev)
265862c1c401SMark Brown {
265962c1c401SMark Brown struct wm5100_priv *wm5100 = dev_get_drvdata(dev);
266062c1c401SMark Brown
266162c1c401SMark Brown regcache_cache_only(wm5100->regmap, true);
266262c1c401SMark Brown regcache_mark_dirty(wm5100->regmap);
266362c1c401SMark Brown if (wm5100->pdata.ldo_ena)
266462c1c401SMark Brown gpio_set_value_cansleep(wm5100->pdata.ldo_ena, 0);
266562c1c401SMark Brown regulator_bulk_disable(ARRAY_SIZE(wm5100->core_supplies),
266662c1c401SMark Brown wm5100->core_supplies);
266762c1c401SMark Brown
266862c1c401SMark Brown return 0;
266962c1c401SMark Brown }
267062c1c401SMark Brown
wm5100_runtime_resume(struct device * dev)267162c1c401SMark Brown static int wm5100_runtime_resume(struct device *dev)
267262c1c401SMark Brown {
267362c1c401SMark Brown struct wm5100_priv *wm5100 = dev_get_drvdata(dev);
267462c1c401SMark Brown int ret;
267562c1c401SMark Brown
267662c1c401SMark Brown ret = regulator_bulk_enable(ARRAY_SIZE(wm5100->core_supplies),
267762c1c401SMark Brown wm5100->core_supplies);
267862c1c401SMark Brown if (ret != 0) {
267962c1c401SMark Brown dev_err(dev, "Failed to enable supplies: %d\n",
268062c1c401SMark Brown ret);
268162c1c401SMark Brown return ret;
268262c1c401SMark Brown }
268362c1c401SMark Brown
268462c1c401SMark Brown if (wm5100->pdata.ldo_ena) {
268562c1c401SMark Brown gpio_set_value_cansleep(wm5100->pdata.ldo_ena, 1);
268662c1c401SMark Brown msleep(2);
268762c1c401SMark Brown }
268862c1c401SMark Brown
268962c1c401SMark Brown regcache_cache_only(wm5100->regmap, false);
269062c1c401SMark Brown regcache_sync(wm5100->regmap);
269162c1c401SMark Brown
269262c1c401SMark Brown return 0;
269362c1c401SMark Brown }
269462c1c401SMark Brown #endif
269562c1c401SMark Brown
269642d1b8ceSAxel Lin static const struct dev_pm_ops wm5100_pm = {
269762c1c401SMark Brown SET_RUNTIME_PM_OPS(wm5100_runtime_suspend, wm5100_runtime_resume,
269862c1c401SMark Brown NULL)
269962c1c401SMark Brown };
270062c1c401SMark Brown
27016d4baf08SMark Brown static const struct i2c_device_id wm5100_i2c_id[] = {
27026d4baf08SMark Brown { "wm5100", 0 },
27036d4baf08SMark Brown { }
27046d4baf08SMark Brown };
27056d4baf08SMark Brown MODULE_DEVICE_TABLE(i2c, wm5100_i2c_id);
27066d4baf08SMark Brown
27076d4baf08SMark Brown static struct i2c_driver wm5100_i2c_driver = {
27086d4baf08SMark Brown .driver = {
27096d4baf08SMark Brown .name = "wm5100",
271062c1c401SMark Brown .pm = &wm5100_pm,
27116d4baf08SMark Brown },
27129abcd240SUwe Kleine-König .probe = wm5100_i2c_probe,
27137a79e94eSBill Pemberton .remove = wm5100_i2c_remove,
27146d4baf08SMark Brown .id_table = wm5100_i2c_id,
27156d4baf08SMark Brown };
27166d4baf08SMark Brown
2717d5644076SMark Brown module_i2c_driver(wm5100_i2c_driver);
27186d4baf08SMark Brown
27196d4baf08SMark Brown MODULE_DESCRIPTION("ASoC WM5100 driver");
27206d4baf08SMark Brown MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
27216d4baf08SMark Brown MODULE_LICENSE("GPL");
2722