1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
20e0e16a8SMark Brown /*
30e0e16a8SMark Brown * wm8900.c -- WM8900 ALSA Soc Audio driver
40e0e16a8SMark Brown *
50e0e16a8SMark Brown * Copyright 2007, 2008 Wolfson Microelectronics PLC.
60e0e16a8SMark Brown *
70e0e16a8SMark Brown * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
80e0e16a8SMark Brown *
90e0e16a8SMark Brown * TODO:
100e0e16a8SMark Brown * - Tristating.
110e0e16a8SMark Brown * - TDM.
120e0e16a8SMark Brown * - Jack detect.
130e0e16a8SMark Brown * - FLL source configuration, currently only MCLK is supported.
140e0e16a8SMark Brown */
150e0e16a8SMark Brown
160e0e16a8SMark Brown #include <linux/module.h>
170e0e16a8SMark Brown #include <linux/moduleparam.h>
180e0e16a8SMark Brown #include <linux/kernel.h>
190e0e16a8SMark Brown #include <linux/init.h>
200e0e16a8SMark Brown #include <linux/delay.h>
210e0e16a8SMark Brown #include <linux/pm.h>
220e0e16a8SMark Brown #include <linux/i2c.h>
2349992624SMark Brown #include <linux/regmap.h>
24f0fba2adSLiam Girdwood #include <linux/spi/spi.h>
255a0e3ad6STejun Heo #include <linux/slab.h>
260e0e16a8SMark Brown #include <sound/core.h>
270e0e16a8SMark Brown #include <sound/pcm.h>
280e0e16a8SMark Brown #include <sound/pcm_params.h>
290e0e16a8SMark Brown #include <sound/soc.h>
300e0e16a8SMark Brown #include <sound/initval.h>
310e0e16a8SMark Brown #include <sound/tlv.h>
320e0e16a8SMark Brown
330e0e16a8SMark Brown #include "wm8900.h"
340e0e16a8SMark Brown
350e0e16a8SMark Brown /* WM8900 register space */
360e0e16a8SMark Brown #define WM8900_REG_RESET 0x0
370e0e16a8SMark Brown #define WM8900_REG_ID 0x0
380e0e16a8SMark Brown #define WM8900_REG_POWER1 0x1
390e0e16a8SMark Brown #define WM8900_REG_POWER2 0x2
400e0e16a8SMark Brown #define WM8900_REG_POWER3 0x3
410e0e16a8SMark Brown #define WM8900_REG_AUDIO1 0x4
420e0e16a8SMark Brown #define WM8900_REG_AUDIO2 0x5
430e0e16a8SMark Brown #define WM8900_REG_CLOCKING1 0x6
440e0e16a8SMark Brown #define WM8900_REG_CLOCKING2 0x7
450e0e16a8SMark Brown #define WM8900_REG_AUDIO3 0x8
460e0e16a8SMark Brown #define WM8900_REG_AUDIO4 0x9
470e0e16a8SMark Brown #define WM8900_REG_DACCTRL 0xa
480e0e16a8SMark Brown #define WM8900_REG_LDAC_DV 0xb
490e0e16a8SMark Brown #define WM8900_REG_RDAC_DV 0xc
500e0e16a8SMark Brown #define WM8900_REG_SIDETONE 0xd
510e0e16a8SMark Brown #define WM8900_REG_ADCCTRL 0xe
520e0e16a8SMark Brown #define WM8900_REG_LADC_DV 0xf
530e0e16a8SMark Brown #define WM8900_REG_RADC_DV 0x10
540e0e16a8SMark Brown #define WM8900_REG_GPIO 0x12
550e0e16a8SMark Brown #define WM8900_REG_INCTL 0x15
560e0e16a8SMark Brown #define WM8900_REG_LINVOL 0x16
570e0e16a8SMark Brown #define WM8900_REG_RINVOL 0x17
580e0e16a8SMark Brown #define WM8900_REG_INBOOSTMIX1 0x18
590e0e16a8SMark Brown #define WM8900_REG_INBOOSTMIX2 0x19
600e0e16a8SMark Brown #define WM8900_REG_ADCPATH 0x1a
610e0e16a8SMark Brown #define WM8900_REG_AUXBOOST 0x1b
620e0e16a8SMark Brown #define WM8900_REG_ADDCTL 0x1e
630e0e16a8SMark Brown #define WM8900_REG_FLLCTL1 0x24
640e0e16a8SMark Brown #define WM8900_REG_FLLCTL2 0x25
650e0e16a8SMark Brown #define WM8900_REG_FLLCTL3 0x26
660e0e16a8SMark Brown #define WM8900_REG_FLLCTL4 0x27
670e0e16a8SMark Brown #define WM8900_REG_FLLCTL5 0x28
680e0e16a8SMark Brown #define WM8900_REG_FLLCTL6 0x29
690e0e16a8SMark Brown #define WM8900_REG_LOUTMIXCTL1 0x2c
700e0e16a8SMark Brown #define WM8900_REG_ROUTMIXCTL1 0x2d
710e0e16a8SMark Brown #define WM8900_REG_BYPASS1 0x2e
720e0e16a8SMark Brown #define WM8900_REG_BYPASS2 0x2f
730e0e16a8SMark Brown #define WM8900_REG_AUXOUT_CTL 0x30
740e0e16a8SMark Brown #define WM8900_REG_LOUT1CTL 0x33
750e0e16a8SMark Brown #define WM8900_REG_ROUT1CTL 0x34
760e0e16a8SMark Brown #define WM8900_REG_LOUT2CTL 0x35
770e0e16a8SMark Brown #define WM8900_REG_ROUT2CTL 0x36
780e0e16a8SMark Brown #define WM8900_REG_HPCTL1 0x3a
790e0e16a8SMark Brown #define WM8900_REG_OUTBIASCTL 0x73
800e0e16a8SMark Brown
810e0e16a8SMark Brown #define WM8900_MAXREG 0x80
820e0e16a8SMark Brown
830e0e16a8SMark Brown #define WM8900_REG_ADDCTL_OUT1_DIS 0x80
840e0e16a8SMark Brown #define WM8900_REG_ADDCTL_OUT2_DIS 0x40
850e0e16a8SMark Brown #define WM8900_REG_ADDCTL_VMID_DIS 0x20
860e0e16a8SMark Brown #define WM8900_REG_ADDCTL_BIAS_SRC 0x10
870e0e16a8SMark Brown #define WM8900_REG_ADDCTL_VMID_SOFTST 0x04
880e0e16a8SMark Brown #define WM8900_REG_ADDCTL_TEMP_SD 0x02
890e0e16a8SMark Brown
900e0e16a8SMark Brown #define WM8900_REG_GPIO_TEMP_ENA 0x2
910e0e16a8SMark Brown
920e0e16a8SMark Brown #define WM8900_REG_POWER1_STARTUP_BIAS_ENA 0x0100
930e0e16a8SMark Brown #define WM8900_REG_POWER1_BIAS_ENA 0x0008
940e0e16a8SMark Brown #define WM8900_REG_POWER1_VMID_BUF_ENA 0x0004
950e0e16a8SMark Brown #define WM8900_REG_POWER1_FLL_ENA 0x0040
960e0e16a8SMark Brown
970e0e16a8SMark Brown #define WM8900_REG_POWER2_SYSCLK_ENA 0x8000
980e0e16a8SMark Brown #define WM8900_REG_POWER2_ADCL_ENA 0x0002
990e0e16a8SMark Brown #define WM8900_REG_POWER2_ADCR_ENA 0x0001
1000e0e16a8SMark Brown
1010e0e16a8SMark Brown #define WM8900_REG_POWER3_DACL_ENA 0x0002
1020e0e16a8SMark Brown #define WM8900_REG_POWER3_DACR_ENA 0x0001
1030e0e16a8SMark Brown
1040e0e16a8SMark Brown #define WM8900_REG_AUDIO1_AIF_FMT_MASK 0x0018
1050e0e16a8SMark Brown #define WM8900_REG_AUDIO1_LRCLK_INV 0x0080
1060e0e16a8SMark Brown #define WM8900_REG_AUDIO1_BCLK_INV 0x0100
1070e0e16a8SMark Brown
1080e0e16a8SMark Brown #define WM8900_REG_CLOCKING1_BCLK_DIR 0x1
1090e0e16a8SMark Brown #define WM8900_REG_CLOCKING1_MCLK_SRC 0x100
110de5035b1SAxel Lin #define WM8900_REG_CLOCKING1_BCLK_MASK 0x01e
111de5035b1SAxel Lin #define WM8900_REG_CLOCKING1_OPCLK_MASK 0x7000
1120e0e16a8SMark Brown
1130e0e16a8SMark Brown #define WM8900_REG_CLOCKING2_ADC_CLKDIV 0xe0
1140e0e16a8SMark Brown #define WM8900_REG_CLOCKING2_DAC_CLKDIV 0x1c
1150e0e16a8SMark Brown
1160e0e16a8SMark Brown #define WM8900_REG_DACCTRL_MUTE 0x004
11721002e20SMark Brown #define WM8900_REG_DACCTRL_DAC_SB_FILT 0x100
1180e0e16a8SMark Brown #define WM8900_REG_DACCTRL_AIF_LRCLKRATE 0x400
1190e0e16a8SMark Brown
1200e0e16a8SMark Brown #define WM8900_REG_AUDIO3_ADCLRC_DIR 0x0800
1210e0e16a8SMark Brown
1220e0e16a8SMark Brown #define WM8900_REG_AUDIO4_DACLRC_DIR 0x0800
1230e0e16a8SMark Brown
1240e0e16a8SMark Brown #define WM8900_REG_FLLCTL1_OSC_ENA 0x100
1250e0e16a8SMark Brown
1260e0e16a8SMark Brown #define WM8900_REG_FLLCTL6_FLL_SLOW_LOCK_REF 0x100
1270e0e16a8SMark Brown
1280e0e16a8SMark Brown #define WM8900_REG_HPCTL1_HP_IPSTAGE_ENA 0x80
1290e0e16a8SMark Brown #define WM8900_REG_HPCTL1_HP_OPSTAGE_ENA 0x40
1300e0e16a8SMark Brown #define WM8900_REG_HPCTL1_HP_CLAMP_IP 0x20
1310e0e16a8SMark Brown #define WM8900_REG_HPCTL1_HP_CLAMP_OP 0x10
1320e0e16a8SMark Brown #define WM8900_REG_HPCTL1_HP_SHORT 0x08
1330e0e16a8SMark Brown #define WM8900_REG_HPCTL1_HP_SHORT2 0x04
1340e0e16a8SMark Brown
135de5035b1SAxel Lin #define WM8900_LRC_MASK 0x03ff
1360e0e16a8SMark Brown
1370e0e16a8SMark Brown struct wm8900_priv {
13849992624SMark Brown struct regmap *regmap;
13978e19a39SMark Brown
1400e0e16a8SMark Brown u32 fll_in; /* FLL input frequency */
1410e0e16a8SMark Brown u32 fll_out; /* FLL output frequency */
1420e0e16a8SMark Brown };
1430e0e16a8SMark Brown
1440e0e16a8SMark Brown /*
1450e0e16a8SMark Brown * wm8900 register cache. We can't read the entire register space and we
1460e0e16a8SMark Brown * have slow control buses so we cache the registers.
1470e0e16a8SMark Brown */
14849992624SMark Brown static const struct reg_default wm8900_reg_defaults[] = {
14949992624SMark Brown { 1, 0x0000 },
15049992624SMark Brown { 2, 0xc000 },
15149992624SMark Brown { 3, 0x0000 },
15249992624SMark Brown { 4, 0x4050 },
15349992624SMark Brown { 5, 0x4000 },
15449992624SMark Brown { 6, 0x0008 },
15549992624SMark Brown { 7, 0x0000 },
15649992624SMark Brown { 8, 0x0040 },
15749992624SMark Brown { 9, 0x0040 },
15849992624SMark Brown { 10, 0x1004 },
15949992624SMark Brown { 11, 0x00c0 },
16049992624SMark Brown { 12, 0x00c0 },
16149992624SMark Brown { 13, 0x0000 },
16249992624SMark Brown { 14, 0x0100 },
16349992624SMark Brown { 15, 0x00c0 },
16449992624SMark Brown { 16, 0x00c0 },
16549992624SMark Brown { 17, 0x0000 },
16649992624SMark Brown { 18, 0xb001 },
16749992624SMark Brown { 19, 0x0000 },
16849992624SMark Brown { 20, 0x0000 },
16949992624SMark Brown { 21, 0x0044 },
17049992624SMark Brown { 22, 0x004c },
17149992624SMark Brown { 23, 0x004c },
17249992624SMark Brown { 24, 0x0044 },
17349992624SMark Brown { 25, 0x0044 },
17449992624SMark Brown { 26, 0x0000 },
17549992624SMark Brown { 27, 0x0044 },
17649992624SMark Brown { 28, 0x0000 },
17749992624SMark Brown { 29, 0x0000 },
17849992624SMark Brown { 30, 0x0002 },
17949992624SMark Brown { 31, 0x0000 },
18049992624SMark Brown { 32, 0x0000 },
18149992624SMark Brown { 33, 0x0000 },
18249992624SMark Brown { 34, 0x0000 },
18349992624SMark Brown { 35, 0x0000 },
18449992624SMark Brown { 36, 0x0008 },
18549992624SMark Brown { 37, 0x0000 },
18649992624SMark Brown { 38, 0x0000 },
18749992624SMark Brown { 39, 0x0008 },
18849992624SMark Brown { 40, 0x0097 },
18949992624SMark Brown { 41, 0x0100 },
19049992624SMark Brown { 42, 0x0000 },
19149992624SMark Brown { 43, 0x0000 },
19249992624SMark Brown { 44, 0x0050 },
19349992624SMark Brown { 45, 0x0050 },
19449992624SMark Brown { 46, 0x0055 },
19549992624SMark Brown { 47, 0x0055 },
19649992624SMark Brown { 48, 0x0055 },
19749992624SMark Brown { 49, 0x0000 },
19849992624SMark Brown { 50, 0x0000 },
19949992624SMark Brown { 51, 0x0079 },
20049992624SMark Brown { 52, 0x0079 },
20149992624SMark Brown { 53, 0x0079 },
20249992624SMark Brown { 54, 0x0079 },
20349992624SMark Brown { 55, 0x0000 },
2040e0e16a8SMark Brown };
2050e0e16a8SMark Brown
wm8900_volatile_register(struct device * dev,unsigned int reg)20649992624SMark Brown static bool wm8900_volatile_register(struct device *dev, unsigned int reg)
2070e0e16a8SMark Brown {
2080e0e16a8SMark Brown switch (reg) {
2090e0e16a8SMark Brown case WM8900_REG_ID:
21049992624SMark Brown return true;
2110e0e16a8SMark Brown default:
21249992624SMark Brown return false;
2130e0e16a8SMark Brown }
2140e0e16a8SMark Brown }
2150e0e16a8SMark Brown
wm8900_reset(struct snd_soc_component * component)216825a52aaSKuninori Morimoto static void wm8900_reset(struct snd_soc_component *component)
2170e0e16a8SMark Brown {
218825a52aaSKuninori Morimoto snd_soc_component_write(component, WM8900_REG_RESET, 0);
2190e0e16a8SMark Brown }
2200e0e16a8SMark Brown
wm8900_hp_event(struct snd_soc_dapm_widget * w,struct snd_kcontrol * kcontrol,int event)2210e0e16a8SMark Brown static int wm8900_hp_event(struct snd_soc_dapm_widget *w,
2220e0e16a8SMark Brown struct snd_kcontrol *kcontrol, int event)
2230e0e16a8SMark Brown {
224825a52aaSKuninori Morimoto struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
2256d75dfc3SKuninori Morimoto u16 hpctl1 = snd_soc_component_read(component, WM8900_REG_HPCTL1);
2260e0e16a8SMark Brown
2270e0e16a8SMark Brown switch (event) {
2280e0e16a8SMark Brown case SND_SOC_DAPM_PRE_PMU:
2290e0e16a8SMark Brown /* Clamp headphone outputs */
2300e0e16a8SMark Brown hpctl1 = WM8900_REG_HPCTL1_HP_CLAMP_IP |
2310e0e16a8SMark Brown WM8900_REG_HPCTL1_HP_CLAMP_OP;
232825a52aaSKuninori Morimoto snd_soc_component_write(component, WM8900_REG_HPCTL1, hpctl1);
2330e0e16a8SMark Brown break;
2340e0e16a8SMark Brown
2350e0e16a8SMark Brown case SND_SOC_DAPM_POST_PMU:
2360e0e16a8SMark Brown /* Enable the input stage */
2370e0e16a8SMark Brown hpctl1 &= ~WM8900_REG_HPCTL1_HP_CLAMP_IP;
2380e0e16a8SMark Brown hpctl1 |= WM8900_REG_HPCTL1_HP_SHORT |
2390e0e16a8SMark Brown WM8900_REG_HPCTL1_HP_SHORT2 |
2400e0e16a8SMark Brown WM8900_REG_HPCTL1_HP_IPSTAGE_ENA;
241825a52aaSKuninori Morimoto snd_soc_component_write(component, WM8900_REG_HPCTL1, hpctl1);
2420e0e16a8SMark Brown
2430e0e16a8SMark Brown msleep(400);
2440e0e16a8SMark Brown
2450e0e16a8SMark Brown /* Enable the output stage */
2460e0e16a8SMark Brown hpctl1 &= ~WM8900_REG_HPCTL1_HP_CLAMP_OP;
2470e0e16a8SMark Brown hpctl1 |= WM8900_REG_HPCTL1_HP_OPSTAGE_ENA;
248825a52aaSKuninori Morimoto snd_soc_component_write(component, WM8900_REG_HPCTL1, hpctl1);
2490e0e16a8SMark Brown
2500e0e16a8SMark Brown /* Remove the shorts */
2510e0e16a8SMark Brown hpctl1 &= ~WM8900_REG_HPCTL1_HP_SHORT2;
252825a52aaSKuninori Morimoto snd_soc_component_write(component, WM8900_REG_HPCTL1, hpctl1);
2530e0e16a8SMark Brown hpctl1 &= ~WM8900_REG_HPCTL1_HP_SHORT;
254825a52aaSKuninori Morimoto snd_soc_component_write(component, WM8900_REG_HPCTL1, hpctl1);
2550e0e16a8SMark Brown break;
2560e0e16a8SMark Brown
2570e0e16a8SMark Brown case SND_SOC_DAPM_PRE_PMD:
2580e0e16a8SMark Brown /* Short the output */
2590e0e16a8SMark Brown hpctl1 |= WM8900_REG_HPCTL1_HP_SHORT;
260825a52aaSKuninori Morimoto snd_soc_component_write(component, WM8900_REG_HPCTL1, hpctl1);
2610e0e16a8SMark Brown
2620e0e16a8SMark Brown /* Disable the output stage */
2630e0e16a8SMark Brown hpctl1 &= ~WM8900_REG_HPCTL1_HP_OPSTAGE_ENA;
264825a52aaSKuninori Morimoto snd_soc_component_write(component, WM8900_REG_HPCTL1, hpctl1);
2650e0e16a8SMark Brown
2660e0e16a8SMark Brown /* Clamp the outputs and power down input */
2670e0e16a8SMark Brown hpctl1 |= WM8900_REG_HPCTL1_HP_CLAMP_IP |
2680e0e16a8SMark Brown WM8900_REG_HPCTL1_HP_CLAMP_OP;
2690e0e16a8SMark Brown hpctl1 &= ~WM8900_REG_HPCTL1_HP_IPSTAGE_ENA;
270825a52aaSKuninori Morimoto snd_soc_component_write(component, WM8900_REG_HPCTL1, hpctl1);
2710e0e16a8SMark Brown break;
2720e0e16a8SMark Brown
2730e0e16a8SMark Brown case SND_SOC_DAPM_POST_PMD:
2740e0e16a8SMark Brown /* Disable everything */
275825a52aaSKuninori Morimoto snd_soc_component_write(component, WM8900_REG_HPCTL1, 0);
2760e0e16a8SMark Brown break;
2770e0e16a8SMark Brown
2780e0e16a8SMark Brown default:
279d9dea396STakashi Iwai WARN(1, "Invalid event %d\n", event);
280d9dea396STakashi Iwai break;
2810e0e16a8SMark Brown }
2820e0e16a8SMark Brown
2830e0e16a8SMark Brown return 0;
2840e0e16a8SMark Brown }
2850e0e16a8SMark Brown
2860e0e16a8SMark Brown static const DECLARE_TLV_DB_SCALE(out_pga_tlv, -5700, 100, 0);
2870e0e16a8SMark Brown
2880e0e16a8SMark Brown static const DECLARE_TLV_DB_SCALE(out_mix_tlv, -1500, 300, 0);
2890e0e16a8SMark Brown
2900e0e16a8SMark Brown static const DECLARE_TLV_DB_SCALE(in_boost_tlv, -1200, 600, 0);
2910e0e16a8SMark Brown
2920e0e16a8SMark Brown static const DECLARE_TLV_DB_SCALE(in_pga_tlv, -1200, 100, 0);
2930e0e16a8SMark Brown
2940e0e16a8SMark Brown static const DECLARE_TLV_DB_SCALE(dac_boost_tlv, 0, 600, 0);
2950e0e16a8SMark Brown
2960e0e16a8SMark Brown static const DECLARE_TLV_DB_SCALE(dac_tlv, -7200, 75, 1);
2970e0e16a8SMark Brown
2980e0e16a8SMark Brown static const DECLARE_TLV_DB_SCALE(adc_svol_tlv, -3600, 300, 0);
2990e0e16a8SMark Brown
3000e0e16a8SMark Brown static const DECLARE_TLV_DB_SCALE(adc_tlv, -7200, 75, 1);
3010e0e16a8SMark Brown
3020e0e16a8SMark Brown static const char *mic_bias_level_txt[] = { "0.9*AVDD", "0.65*AVDD" };
3030e0e16a8SMark Brown
3049d166314STakashi Iwai static SOC_ENUM_SINGLE_DECL(mic_bias_level,
3059d166314STakashi Iwai WM8900_REG_INCTL, 8, mic_bias_level_txt);
3060e0e16a8SMark Brown
3070e0e16a8SMark Brown static const char *dac_mute_rate_txt[] = { "Fast", "Slow" };
3080e0e16a8SMark Brown
3099d166314STakashi Iwai static SOC_ENUM_SINGLE_DECL(dac_mute_rate,
3109d166314STakashi Iwai WM8900_REG_DACCTRL, 7, dac_mute_rate_txt);
3110e0e16a8SMark Brown
3120e0e16a8SMark Brown static const char *dac_deemphasis_txt[] = {
3130e0e16a8SMark Brown "Disabled", "32kHz", "44.1kHz", "48kHz"
3140e0e16a8SMark Brown };
3150e0e16a8SMark Brown
3169d166314STakashi Iwai static SOC_ENUM_SINGLE_DECL(dac_deemphasis,
3179d166314STakashi Iwai WM8900_REG_DACCTRL, 4, dac_deemphasis_txt);
3180e0e16a8SMark Brown
3190e0e16a8SMark Brown static const char *adc_hpf_cut_txt[] = {
3200e0e16a8SMark Brown "Hi-fi mode", "Voice mode 1", "Voice mode 2", "Voice mode 3"
3210e0e16a8SMark Brown };
3220e0e16a8SMark Brown
3239d166314STakashi Iwai static SOC_ENUM_SINGLE_DECL(adc_hpf_cut,
3249d166314STakashi Iwai WM8900_REG_ADCCTRL, 5, adc_hpf_cut_txt);
3250e0e16a8SMark Brown
3260e0e16a8SMark Brown static const char *lr_txt[] = {
3270e0e16a8SMark Brown "Left", "Right"
3280e0e16a8SMark Brown };
3290e0e16a8SMark Brown
3309d166314STakashi Iwai static SOC_ENUM_SINGLE_DECL(aifl_src,
3319d166314STakashi Iwai WM8900_REG_AUDIO1, 15, lr_txt);
3320e0e16a8SMark Brown
3339d166314STakashi Iwai static SOC_ENUM_SINGLE_DECL(aifr_src,
3349d166314STakashi Iwai WM8900_REG_AUDIO1, 14, lr_txt);
3350e0e16a8SMark Brown
3369d166314STakashi Iwai static SOC_ENUM_SINGLE_DECL(dacl_src,
3379d166314STakashi Iwai WM8900_REG_AUDIO2, 15, lr_txt);
3380e0e16a8SMark Brown
3399d166314STakashi Iwai static SOC_ENUM_SINGLE_DECL(dacr_src,
3409d166314STakashi Iwai WM8900_REG_AUDIO2, 14, lr_txt);
3410e0e16a8SMark Brown
3420e0e16a8SMark Brown static const char *sidetone_txt[] = {
3430e0e16a8SMark Brown "Disabled", "Left ADC", "Right ADC"
3440e0e16a8SMark Brown };
3450e0e16a8SMark Brown
3469d166314STakashi Iwai static SOC_ENUM_SINGLE_DECL(dacl_sidetone,
3479d166314STakashi Iwai WM8900_REG_SIDETONE, 2, sidetone_txt);
3480e0e16a8SMark Brown
3499d166314STakashi Iwai static SOC_ENUM_SINGLE_DECL(dacr_sidetone,
3509d166314STakashi Iwai WM8900_REG_SIDETONE, 0, sidetone_txt);
3510e0e16a8SMark Brown
3520e0e16a8SMark Brown static const struct snd_kcontrol_new wm8900_snd_controls[] = {
3530e0e16a8SMark Brown SOC_ENUM("Mic Bias Level", mic_bias_level),
3540e0e16a8SMark Brown
3550e0e16a8SMark Brown SOC_SINGLE_TLV("Left Input PGA Volume", WM8900_REG_LINVOL, 0, 31, 0,
3560e0e16a8SMark Brown in_pga_tlv),
3570e0e16a8SMark Brown SOC_SINGLE("Left Input PGA Switch", WM8900_REG_LINVOL, 6, 1, 1),
3580e0e16a8SMark Brown SOC_SINGLE("Left Input PGA ZC Switch", WM8900_REG_LINVOL, 7, 1, 0),
3590e0e16a8SMark Brown
3600e0e16a8SMark Brown SOC_SINGLE_TLV("Right Input PGA Volume", WM8900_REG_RINVOL, 0, 31, 0,
3610e0e16a8SMark Brown in_pga_tlv),
3620e0e16a8SMark Brown SOC_SINGLE("Right Input PGA Switch", WM8900_REG_RINVOL, 6, 1, 1),
3630e0e16a8SMark Brown SOC_SINGLE("Right Input PGA ZC Switch", WM8900_REG_RINVOL, 7, 1, 0),
3640e0e16a8SMark Brown
3650e0e16a8SMark Brown SOC_SINGLE("DAC Soft Mute Switch", WM8900_REG_DACCTRL, 6, 1, 1),
3660e0e16a8SMark Brown SOC_ENUM("DAC Mute Rate", dac_mute_rate),
3670e0e16a8SMark Brown SOC_SINGLE("DAC Mono Switch", WM8900_REG_DACCTRL, 9, 1, 0),
3680e0e16a8SMark Brown SOC_ENUM("DAC Deemphasis", dac_deemphasis),
3690e0e16a8SMark Brown SOC_SINGLE("DAC Sigma-Delta Modulator Clock Switch", WM8900_REG_DACCTRL,
3700e0e16a8SMark Brown 12, 1, 0),
3710e0e16a8SMark Brown
3720e0e16a8SMark Brown SOC_SINGLE("ADC HPF Switch", WM8900_REG_ADCCTRL, 8, 1, 0),
3730e0e16a8SMark Brown SOC_ENUM("ADC HPF Cut-Off", adc_hpf_cut),
3740e0e16a8SMark Brown SOC_DOUBLE("ADC Invert Switch", WM8900_REG_ADCCTRL, 1, 0, 1, 0),
3750e0e16a8SMark Brown SOC_SINGLE_TLV("Left ADC Sidetone Volume", WM8900_REG_SIDETONE, 9, 12, 0,
3760e0e16a8SMark Brown adc_svol_tlv),
3770e0e16a8SMark Brown SOC_SINGLE_TLV("Right ADC Sidetone Volume", WM8900_REG_SIDETONE, 5, 12, 0,
3780e0e16a8SMark Brown adc_svol_tlv),
3790e0e16a8SMark Brown SOC_ENUM("Left Digital Audio Source", aifl_src),
3800e0e16a8SMark Brown SOC_ENUM("Right Digital Audio Source", aifr_src),
3810e0e16a8SMark Brown
3820e0e16a8SMark Brown SOC_SINGLE_TLV("DAC Input Boost Volume", WM8900_REG_AUDIO2, 10, 4, 0,
3830e0e16a8SMark Brown dac_boost_tlv),
3840e0e16a8SMark Brown SOC_ENUM("Left DAC Source", dacl_src),
3850e0e16a8SMark Brown SOC_ENUM("Right DAC Source", dacr_src),
3860e0e16a8SMark Brown SOC_ENUM("Left DAC Sidetone", dacl_sidetone),
3870e0e16a8SMark Brown SOC_ENUM("Right DAC Sidetone", dacr_sidetone),
3880e0e16a8SMark Brown SOC_DOUBLE("DAC Invert Switch", WM8900_REG_DACCTRL, 1, 0, 1, 0),
3890e0e16a8SMark Brown
3900e0e16a8SMark Brown SOC_DOUBLE_R_TLV("Digital Playback Volume",
3910e0e16a8SMark Brown WM8900_REG_LDAC_DV, WM8900_REG_RDAC_DV,
3920e0e16a8SMark Brown 1, 96, 0, dac_tlv),
3930e0e16a8SMark Brown SOC_DOUBLE_R_TLV("Digital Capture Volume",
3940e0e16a8SMark Brown WM8900_REG_LADC_DV, WM8900_REG_RADC_DV, 1, 119, 0, adc_tlv),
3950e0e16a8SMark Brown
3960e0e16a8SMark Brown SOC_SINGLE_TLV("LINPUT3 Bypass Volume", WM8900_REG_LOUTMIXCTL1, 4, 7, 0,
3970e0e16a8SMark Brown out_mix_tlv),
3980e0e16a8SMark Brown SOC_SINGLE_TLV("RINPUT3 Bypass Volume", WM8900_REG_ROUTMIXCTL1, 4, 7, 0,
3990e0e16a8SMark Brown out_mix_tlv),
4000e0e16a8SMark Brown SOC_SINGLE_TLV("Left AUX Bypass Volume", WM8900_REG_AUXOUT_CTL, 4, 7, 0,
4010e0e16a8SMark Brown out_mix_tlv),
4020e0e16a8SMark Brown SOC_SINGLE_TLV("Right AUX Bypass Volume", WM8900_REG_AUXOUT_CTL, 0, 7, 0,
4030e0e16a8SMark Brown out_mix_tlv),
4040e0e16a8SMark Brown
4050e0e16a8SMark Brown SOC_SINGLE_TLV("LeftIn to RightOut Mixer Volume", WM8900_REG_BYPASS1, 0, 7, 0,
4060e0e16a8SMark Brown out_mix_tlv),
4070e0e16a8SMark Brown SOC_SINGLE_TLV("LeftIn to LeftOut Mixer Volume", WM8900_REG_BYPASS1, 4, 7, 0,
4080e0e16a8SMark Brown out_mix_tlv),
4090e0e16a8SMark Brown SOC_SINGLE_TLV("RightIn to LeftOut Mixer Volume", WM8900_REG_BYPASS2, 0, 7, 0,
4100e0e16a8SMark Brown out_mix_tlv),
4110e0e16a8SMark Brown SOC_SINGLE_TLV("RightIn to RightOut Mixer Volume", WM8900_REG_BYPASS2, 4, 7, 0,
4120e0e16a8SMark Brown out_mix_tlv),
4130e0e16a8SMark Brown
4140e0e16a8SMark Brown SOC_SINGLE_TLV("IN2L Boost Volume", WM8900_REG_INBOOSTMIX1, 0, 3, 0,
4150e0e16a8SMark Brown in_boost_tlv),
4160e0e16a8SMark Brown SOC_SINGLE_TLV("IN3L Boost Volume", WM8900_REG_INBOOSTMIX1, 4, 3, 0,
4170e0e16a8SMark Brown in_boost_tlv),
4180e0e16a8SMark Brown SOC_SINGLE_TLV("IN2R Boost Volume", WM8900_REG_INBOOSTMIX2, 0, 3, 0,
4190e0e16a8SMark Brown in_boost_tlv),
4200e0e16a8SMark Brown SOC_SINGLE_TLV("IN3R Boost Volume", WM8900_REG_INBOOSTMIX2, 4, 3, 0,
4210e0e16a8SMark Brown in_boost_tlv),
4220e0e16a8SMark Brown SOC_SINGLE_TLV("Left AUX Boost Volume", WM8900_REG_AUXBOOST, 4, 3, 0,
4230e0e16a8SMark Brown in_boost_tlv),
4240e0e16a8SMark Brown SOC_SINGLE_TLV("Right AUX Boost Volume", WM8900_REG_AUXBOOST, 0, 3, 0,
4250e0e16a8SMark Brown in_boost_tlv),
4260e0e16a8SMark Brown
4270e0e16a8SMark Brown SOC_DOUBLE_R_TLV("LINEOUT1 Volume", WM8900_REG_LOUT1CTL, WM8900_REG_ROUT1CTL,
4280e0e16a8SMark Brown 0, 63, 0, out_pga_tlv),
4290e0e16a8SMark Brown SOC_DOUBLE_R("LINEOUT1 Switch", WM8900_REG_LOUT1CTL, WM8900_REG_ROUT1CTL,
4300e0e16a8SMark Brown 6, 1, 1),
4310e0e16a8SMark Brown SOC_DOUBLE_R("LINEOUT1 ZC Switch", WM8900_REG_LOUT1CTL, WM8900_REG_ROUT1CTL,
4320e0e16a8SMark Brown 7, 1, 0),
4330e0e16a8SMark Brown
4340e0e16a8SMark Brown SOC_DOUBLE_R_TLV("LINEOUT2 Volume",
4350e0e16a8SMark Brown WM8900_REG_LOUT2CTL, WM8900_REG_ROUT2CTL,
4360e0e16a8SMark Brown 0, 63, 0, out_pga_tlv),
4370e0e16a8SMark Brown SOC_DOUBLE_R("LINEOUT2 Switch",
4380e0e16a8SMark Brown WM8900_REG_LOUT2CTL, WM8900_REG_ROUT2CTL, 6, 1, 1),
4390e0e16a8SMark Brown SOC_DOUBLE_R("LINEOUT2 ZC Switch",
4400e0e16a8SMark Brown WM8900_REG_LOUT2CTL, WM8900_REG_ROUT2CTL, 7, 1, 0),
4410e0e16a8SMark Brown SOC_SINGLE("LINEOUT2 LP -12dB", WM8900_REG_LOUTMIXCTL1,
4420e0e16a8SMark Brown 0, 1, 1),
4430e0e16a8SMark Brown
4440e0e16a8SMark Brown };
4450e0e16a8SMark Brown
4460e0e16a8SMark Brown static const struct snd_kcontrol_new wm8900_loutmix_controls[] = {
4470e0e16a8SMark Brown SOC_DAPM_SINGLE("LINPUT3 Bypass Switch", WM8900_REG_LOUTMIXCTL1, 7, 1, 0),
4480e0e16a8SMark Brown SOC_DAPM_SINGLE("AUX Bypass Switch", WM8900_REG_AUXOUT_CTL, 7, 1, 0),
4490e0e16a8SMark Brown SOC_DAPM_SINGLE("Left Input Mixer Switch", WM8900_REG_BYPASS1, 7, 1, 0),
4500e0e16a8SMark Brown SOC_DAPM_SINGLE("Right Input Mixer Switch", WM8900_REG_BYPASS2, 3, 1, 0),
4510e0e16a8SMark Brown SOC_DAPM_SINGLE("DACL Switch", WM8900_REG_LOUTMIXCTL1, 8, 1, 0),
4520e0e16a8SMark Brown };
4530e0e16a8SMark Brown
4540e0e16a8SMark Brown static const struct snd_kcontrol_new wm8900_routmix_controls[] = {
4550e0e16a8SMark Brown SOC_DAPM_SINGLE("RINPUT3 Bypass Switch", WM8900_REG_ROUTMIXCTL1, 7, 1, 0),
4560e0e16a8SMark Brown SOC_DAPM_SINGLE("AUX Bypass Switch", WM8900_REG_AUXOUT_CTL, 3, 1, 0),
4570e0e16a8SMark Brown SOC_DAPM_SINGLE("Left Input Mixer Switch", WM8900_REG_BYPASS1, 3, 1, 0),
4580e0e16a8SMark Brown SOC_DAPM_SINGLE("Right Input Mixer Switch", WM8900_REG_BYPASS2, 7, 1, 0),
4590e0e16a8SMark Brown SOC_DAPM_SINGLE("DACR Switch", WM8900_REG_ROUTMIXCTL1, 8, 1, 0),
4600e0e16a8SMark Brown };
4610e0e16a8SMark Brown
4620e0e16a8SMark Brown static const struct snd_kcontrol_new wm8900_linmix_controls[] = {
4630e0e16a8SMark Brown SOC_DAPM_SINGLE("LINPUT2 Switch", WM8900_REG_INBOOSTMIX1, 2, 1, 1),
4640e0e16a8SMark Brown SOC_DAPM_SINGLE("LINPUT3 Switch", WM8900_REG_INBOOSTMIX1, 6, 1, 1),
4650e0e16a8SMark Brown SOC_DAPM_SINGLE("AUX Switch", WM8900_REG_AUXBOOST, 6, 1, 1),
4660e0e16a8SMark Brown SOC_DAPM_SINGLE("Input PGA Switch", WM8900_REG_ADCPATH, 6, 1, 0),
4670e0e16a8SMark Brown };
4680e0e16a8SMark Brown
4690e0e16a8SMark Brown static const struct snd_kcontrol_new wm8900_rinmix_controls[] = {
4700e0e16a8SMark Brown SOC_DAPM_SINGLE("RINPUT2 Switch", WM8900_REG_INBOOSTMIX2, 2, 1, 1),
4710e0e16a8SMark Brown SOC_DAPM_SINGLE("RINPUT3 Switch", WM8900_REG_INBOOSTMIX2, 6, 1, 1),
4720e0e16a8SMark Brown SOC_DAPM_SINGLE("AUX Switch", WM8900_REG_AUXBOOST, 2, 1, 1),
4730e0e16a8SMark Brown SOC_DAPM_SINGLE("Input PGA Switch", WM8900_REG_ADCPATH, 2, 1, 0),
4740e0e16a8SMark Brown };
4750e0e16a8SMark Brown
4760e0e16a8SMark Brown static const struct snd_kcontrol_new wm8900_linpga_controls[] = {
4770e0e16a8SMark Brown SOC_DAPM_SINGLE("LINPUT1 Switch", WM8900_REG_INCTL, 6, 1, 0),
4780e0e16a8SMark Brown SOC_DAPM_SINGLE("LINPUT2 Switch", WM8900_REG_INCTL, 5, 1, 0),
4790e0e16a8SMark Brown SOC_DAPM_SINGLE("LINPUT3 Switch", WM8900_REG_INCTL, 4, 1, 0),
4800e0e16a8SMark Brown };
4810e0e16a8SMark Brown
4820e0e16a8SMark Brown static const struct snd_kcontrol_new wm8900_rinpga_controls[] = {
4830e0e16a8SMark Brown SOC_DAPM_SINGLE("RINPUT1 Switch", WM8900_REG_INCTL, 2, 1, 0),
4840e0e16a8SMark Brown SOC_DAPM_SINGLE("RINPUT2 Switch", WM8900_REG_INCTL, 1, 1, 0),
4850e0e16a8SMark Brown SOC_DAPM_SINGLE("RINPUT3 Switch", WM8900_REG_INCTL, 0, 1, 0),
4860e0e16a8SMark Brown };
4870e0e16a8SMark Brown
4887e94ca47SMark Brown static const char *wm8900_lp_mux[] = { "Disabled", "Enabled" };
4890e0e16a8SMark Brown
4909d166314STakashi Iwai static SOC_ENUM_SINGLE_DECL(wm8900_lineout2_lp_mux,
4919d166314STakashi Iwai WM8900_REG_LOUTMIXCTL1, 1, wm8900_lp_mux);
4920e0e16a8SMark Brown
4930e0e16a8SMark Brown static const struct snd_kcontrol_new wm8900_lineout2_lp =
4940e0e16a8SMark Brown SOC_DAPM_ENUM("Route", wm8900_lineout2_lp_mux);
4950e0e16a8SMark Brown
4960e0e16a8SMark Brown static const struct snd_soc_dapm_widget wm8900_dapm_widgets[] = {
4970e0e16a8SMark Brown
4980e0e16a8SMark Brown /* Externally visible pins */
4990e0e16a8SMark Brown SND_SOC_DAPM_OUTPUT("LINEOUT1L"),
5000e0e16a8SMark Brown SND_SOC_DAPM_OUTPUT("LINEOUT1R"),
5010e0e16a8SMark Brown SND_SOC_DAPM_OUTPUT("LINEOUT2L"),
5020e0e16a8SMark Brown SND_SOC_DAPM_OUTPUT("LINEOUT2R"),
5030e0e16a8SMark Brown SND_SOC_DAPM_OUTPUT("HP_L"),
5040e0e16a8SMark Brown SND_SOC_DAPM_OUTPUT("HP_R"),
5050e0e16a8SMark Brown
5060e0e16a8SMark Brown SND_SOC_DAPM_INPUT("RINPUT1"),
5070e0e16a8SMark Brown SND_SOC_DAPM_INPUT("LINPUT1"),
5080e0e16a8SMark Brown SND_SOC_DAPM_INPUT("RINPUT2"),
5090e0e16a8SMark Brown SND_SOC_DAPM_INPUT("LINPUT2"),
5100e0e16a8SMark Brown SND_SOC_DAPM_INPUT("RINPUT3"),
5110e0e16a8SMark Brown SND_SOC_DAPM_INPUT("LINPUT3"),
5120e0e16a8SMark Brown SND_SOC_DAPM_INPUT("AUX"),
5130e0e16a8SMark Brown
5140e0e16a8SMark Brown SND_SOC_DAPM_VMID("VMID"),
5150e0e16a8SMark Brown
5160e0e16a8SMark Brown /* Input */
5170e0e16a8SMark Brown SND_SOC_DAPM_MIXER("Left Input PGA", WM8900_REG_POWER2, 3, 0,
5180e0e16a8SMark Brown wm8900_linpga_controls,
5190e0e16a8SMark Brown ARRAY_SIZE(wm8900_linpga_controls)),
5200e0e16a8SMark Brown SND_SOC_DAPM_MIXER("Right Input PGA", WM8900_REG_POWER2, 2, 0,
5210e0e16a8SMark Brown wm8900_rinpga_controls,
5220e0e16a8SMark Brown ARRAY_SIZE(wm8900_rinpga_controls)),
5230e0e16a8SMark Brown
5240e0e16a8SMark Brown SND_SOC_DAPM_MIXER("Left Input Mixer", WM8900_REG_POWER2, 5, 0,
5250e0e16a8SMark Brown wm8900_linmix_controls,
5260e0e16a8SMark Brown ARRAY_SIZE(wm8900_linmix_controls)),
5270e0e16a8SMark Brown SND_SOC_DAPM_MIXER("Right Input Mixer", WM8900_REG_POWER2, 4, 0,
5280e0e16a8SMark Brown wm8900_rinmix_controls,
5290e0e16a8SMark Brown ARRAY_SIZE(wm8900_rinmix_controls)),
5300e0e16a8SMark Brown
5318a709d92SMark Brown SND_SOC_DAPM_SUPPLY("Mic Bias", WM8900_REG_POWER1, 4, 0, NULL, 0),
5320e0e16a8SMark Brown
5330e0e16a8SMark Brown SND_SOC_DAPM_ADC("ADCL", "Left HiFi Capture", WM8900_REG_POWER2, 1, 0),
5340e0e16a8SMark Brown SND_SOC_DAPM_ADC("ADCR", "Right HiFi Capture", WM8900_REG_POWER2, 0, 0),
5350e0e16a8SMark Brown
5360e0e16a8SMark Brown /* Output */
5370e0e16a8SMark Brown SND_SOC_DAPM_DAC("DACL", "Left HiFi Playback", WM8900_REG_POWER3, 1, 0),
5380e0e16a8SMark Brown SND_SOC_DAPM_DAC("DACR", "Right HiFi Playback", WM8900_REG_POWER3, 0, 0),
5390e0e16a8SMark Brown
5400e0e16a8SMark Brown SND_SOC_DAPM_PGA_E("Headphone Amplifier", WM8900_REG_POWER3, 7, 0, NULL, 0,
5410e0e16a8SMark Brown wm8900_hp_event,
5420e0e16a8SMark Brown SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
5430e0e16a8SMark Brown SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
5440e0e16a8SMark Brown
5450e0e16a8SMark Brown SND_SOC_DAPM_PGA("LINEOUT1L PGA", WM8900_REG_POWER2, 8, 0, NULL, 0),
5460e0e16a8SMark Brown SND_SOC_DAPM_PGA("LINEOUT1R PGA", WM8900_REG_POWER2, 7, 0, NULL, 0),
5470e0e16a8SMark Brown
5480e0e16a8SMark Brown SND_SOC_DAPM_MUX("LINEOUT2 LP", SND_SOC_NOPM, 0, 0, &wm8900_lineout2_lp),
5490e0e16a8SMark Brown SND_SOC_DAPM_PGA("LINEOUT2L PGA", WM8900_REG_POWER3, 6, 0, NULL, 0),
5500e0e16a8SMark Brown SND_SOC_DAPM_PGA("LINEOUT2R PGA", WM8900_REG_POWER3, 5, 0, NULL, 0),
5510e0e16a8SMark Brown
5520e0e16a8SMark Brown SND_SOC_DAPM_MIXER("Left Output Mixer", WM8900_REG_POWER3, 3, 0,
5530e0e16a8SMark Brown wm8900_loutmix_controls,
5540e0e16a8SMark Brown ARRAY_SIZE(wm8900_loutmix_controls)),
5550e0e16a8SMark Brown SND_SOC_DAPM_MIXER("Right Output Mixer", WM8900_REG_POWER3, 2, 0,
5560e0e16a8SMark Brown wm8900_routmix_controls,
5570e0e16a8SMark Brown ARRAY_SIZE(wm8900_routmix_controls)),
5580e0e16a8SMark Brown };
5590e0e16a8SMark Brown
5600e0e16a8SMark Brown /* Target, Path, Source */
56146ce904fSMark Brown static const struct snd_soc_dapm_route wm8900_dapm_routes[] = {
5620e0e16a8SMark Brown /* Inputs */
5630e0e16a8SMark Brown {"Left Input PGA", "LINPUT1 Switch", "LINPUT1"},
5640e0e16a8SMark Brown {"Left Input PGA", "LINPUT2 Switch", "LINPUT2"},
5650e0e16a8SMark Brown {"Left Input PGA", "LINPUT3 Switch", "LINPUT3"},
5660e0e16a8SMark Brown
5670e0e16a8SMark Brown {"Right Input PGA", "RINPUT1 Switch", "RINPUT1"},
5680e0e16a8SMark Brown {"Right Input PGA", "RINPUT2 Switch", "RINPUT2"},
5690e0e16a8SMark Brown {"Right Input PGA", "RINPUT3 Switch", "RINPUT3"},
5700e0e16a8SMark Brown
5710e0e16a8SMark Brown {"Left Input Mixer", "LINPUT2 Switch", "LINPUT2"},
5720e0e16a8SMark Brown {"Left Input Mixer", "LINPUT3 Switch", "LINPUT3"},
5730e0e16a8SMark Brown {"Left Input Mixer", "AUX Switch", "AUX"},
5740e0e16a8SMark Brown {"Left Input Mixer", "Input PGA Switch", "Left Input PGA"},
5750e0e16a8SMark Brown
5760e0e16a8SMark Brown {"Right Input Mixer", "RINPUT2 Switch", "RINPUT2"},
5770e0e16a8SMark Brown {"Right Input Mixer", "RINPUT3 Switch", "RINPUT3"},
5780e0e16a8SMark Brown {"Right Input Mixer", "AUX Switch", "AUX"},
5790e0e16a8SMark Brown {"Right Input Mixer", "Input PGA Switch", "Right Input PGA"},
5800e0e16a8SMark Brown
5810e0e16a8SMark Brown {"ADCL", NULL, "Left Input Mixer"},
5820e0e16a8SMark Brown {"ADCR", NULL, "Right Input Mixer"},
5830e0e16a8SMark Brown
5840e0e16a8SMark Brown /* Outputs */
5850e0e16a8SMark Brown {"LINEOUT1L", NULL, "LINEOUT1L PGA"},
5860e0e16a8SMark Brown {"LINEOUT1L PGA", NULL, "Left Output Mixer"},
5870e0e16a8SMark Brown {"LINEOUT1R", NULL, "LINEOUT1R PGA"},
5880e0e16a8SMark Brown {"LINEOUT1R PGA", NULL, "Right Output Mixer"},
5890e0e16a8SMark Brown
5900e0e16a8SMark Brown {"LINEOUT2L PGA", NULL, "Left Output Mixer"},
5910e0e16a8SMark Brown {"LINEOUT2 LP", "Disabled", "LINEOUT2L PGA"},
5920e0e16a8SMark Brown {"LINEOUT2 LP", "Enabled", "Left Output Mixer"},
5930e0e16a8SMark Brown {"LINEOUT2L", NULL, "LINEOUT2 LP"},
5940e0e16a8SMark Brown
5950e0e16a8SMark Brown {"LINEOUT2R PGA", NULL, "Right Output Mixer"},
5960e0e16a8SMark Brown {"LINEOUT2 LP", "Disabled", "LINEOUT2R PGA"},
5970e0e16a8SMark Brown {"LINEOUT2 LP", "Enabled", "Right Output Mixer"},
5980e0e16a8SMark Brown {"LINEOUT2R", NULL, "LINEOUT2 LP"},
5990e0e16a8SMark Brown
6000e0e16a8SMark Brown {"Left Output Mixer", "LINPUT3 Bypass Switch", "LINPUT3"},
6010e0e16a8SMark Brown {"Left Output Mixer", "AUX Bypass Switch", "AUX"},
6020e0e16a8SMark Brown {"Left Output Mixer", "Left Input Mixer Switch", "Left Input Mixer"},
6030e0e16a8SMark Brown {"Left Output Mixer", "Right Input Mixer Switch", "Right Input Mixer"},
6040e0e16a8SMark Brown {"Left Output Mixer", "DACL Switch", "DACL"},
6050e0e16a8SMark Brown
6060e0e16a8SMark Brown {"Right Output Mixer", "RINPUT3 Bypass Switch", "RINPUT3"},
6070e0e16a8SMark Brown {"Right Output Mixer", "AUX Bypass Switch", "AUX"},
6080e0e16a8SMark Brown {"Right Output Mixer", "Left Input Mixer Switch", "Left Input Mixer"},
6090e0e16a8SMark Brown {"Right Output Mixer", "Right Input Mixer Switch", "Right Input Mixer"},
6100e0e16a8SMark Brown {"Right Output Mixer", "DACR Switch", "DACR"},
6110e0e16a8SMark Brown
6120e0e16a8SMark Brown /* Note that the headphone output stage needs to be connected
6130e0e16a8SMark Brown * externally to LINEOUT2 via DC blocking capacitors. Other
6140e0e16a8SMark Brown * configurations are not supported.
6150e0e16a8SMark Brown *
6160e0e16a8SMark Brown * Note also that left and right headphone paths are treated as a
6170e0e16a8SMark Brown * mono path.
6180e0e16a8SMark Brown */
6190e0e16a8SMark Brown {"Headphone Amplifier", NULL, "LINEOUT2 LP"},
6200e0e16a8SMark Brown {"Headphone Amplifier", NULL, "LINEOUT2 LP"},
6210e0e16a8SMark Brown {"HP_L", NULL, "Headphone Amplifier"},
6220e0e16a8SMark Brown {"HP_R", NULL, "Headphone Amplifier"},
6230e0e16a8SMark Brown };
6240e0e16a8SMark Brown
wm8900_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params,struct snd_soc_dai * dai)6250e0e16a8SMark Brown static int wm8900_hw_params(struct snd_pcm_substream *substream,
626dee89c4dSMark Brown struct snd_pcm_hw_params *params,
627dee89c4dSMark Brown struct snd_soc_dai *dai)
6280e0e16a8SMark Brown {
629825a52aaSKuninori Morimoto struct snd_soc_component *component = dai->component;
6300e0e16a8SMark Brown u16 reg;
6310e0e16a8SMark Brown
6326d75dfc3SKuninori Morimoto reg = snd_soc_component_read(component, WM8900_REG_AUDIO1) & ~0x60;
6330e0e16a8SMark Brown
6340cd44891SMark Brown switch (params_width(params)) {
6350cd44891SMark Brown case 16:
6360e0e16a8SMark Brown break;
6370cd44891SMark Brown case 20:
6380e0e16a8SMark Brown reg |= 0x20;
6390e0e16a8SMark Brown break;
6400cd44891SMark Brown case 24:
6410e0e16a8SMark Brown reg |= 0x40;
6420e0e16a8SMark Brown break;
6430cd44891SMark Brown case 32:
6440e0e16a8SMark Brown reg |= 0x60;
6450e0e16a8SMark Brown break;
6460e0e16a8SMark Brown default:
6470e0e16a8SMark Brown return -EINVAL;
6480e0e16a8SMark Brown }
6490e0e16a8SMark Brown
650825a52aaSKuninori Morimoto snd_soc_component_write(component, WM8900_REG_AUDIO1, reg);
6510e0e16a8SMark Brown
65221002e20SMark Brown if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
6536d75dfc3SKuninori Morimoto reg = snd_soc_component_read(component, WM8900_REG_DACCTRL);
65421002e20SMark Brown
65521002e20SMark Brown if (params_rate(params) <= 24000)
65621002e20SMark Brown reg |= WM8900_REG_DACCTRL_DAC_SB_FILT;
65721002e20SMark Brown else
65821002e20SMark Brown reg &= ~WM8900_REG_DACCTRL_DAC_SB_FILT;
65921002e20SMark Brown
660825a52aaSKuninori Morimoto snd_soc_component_write(component, WM8900_REG_DACCTRL, reg);
66121002e20SMark Brown }
66221002e20SMark Brown
6630e0e16a8SMark Brown return 0;
6640e0e16a8SMark Brown }
6650e0e16a8SMark Brown
6660e0e16a8SMark Brown /* FLL divisors */
6670e0e16a8SMark Brown struct _fll_div {
6680e0e16a8SMark Brown u16 fll_ratio;
6690e0e16a8SMark Brown u16 fllclk_div;
6700e0e16a8SMark Brown u16 fll_slow_lock_ref;
6710e0e16a8SMark Brown u16 n;
6720e0e16a8SMark Brown u16 k;
6730e0e16a8SMark Brown };
6740e0e16a8SMark Brown
6750e0e16a8SMark Brown /* The size in bits of the FLL divide multiplied by 10
6760e0e16a8SMark Brown * to allow rounding later */
6770e0e16a8SMark Brown #define FIXED_FLL_SIZE ((1 << 16) * 10)
6780e0e16a8SMark Brown
fll_factors(struct _fll_div * fll_div,unsigned int Fref,unsigned int Fout)6790e0e16a8SMark Brown static int fll_factors(struct _fll_div *fll_div, unsigned int Fref,
6800e0e16a8SMark Brown unsigned int Fout)
6810e0e16a8SMark Brown {
6820e0e16a8SMark Brown u64 Kpart;
6830e0e16a8SMark Brown unsigned int K, Ndiv, Nmod, target;
6840e0e16a8SMark Brown unsigned int div;
6850e0e16a8SMark Brown
686246e884bSTakashi Iwai if (WARN_ON(!Fout))
687246e884bSTakashi Iwai return -EINVAL;
6880e0e16a8SMark Brown
6890e0e16a8SMark Brown /* The FLL must run at 90-100MHz which is then scaled down to
6900e0e16a8SMark Brown * the output value by FLLCLK_DIV. */
6910e0e16a8SMark Brown target = Fout;
6920e0e16a8SMark Brown div = 1;
6930e0e16a8SMark Brown while (target < 90000000) {
6940e0e16a8SMark Brown div *= 2;
6950e0e16a8SMark Brown target *= 2;
6960e0e16a8SMark Brown }
6970e0e16a8SMark Brown
6980e0e16a8SMark Brown if (target > 100000000)
699449bd54dSRoel Kluin printk(KERN_WARNING "wm8900: FLL rate %u out of range, Fref=%u"
700449bd54dSRoel Kluin " Fout=%u\n", target, Fref, Fout);
7010e0e16a8SMark Brown if (div > 32) {
7020e0e16a8SMark Brown printk(KERN_ERR "wm8900: Invalid FLL division rate %u, "
703449bd54dSRoel Kluin "Fref=%u, Fout=%u, target=%u\n",
7040e0e16a8SMark Brown div, Fref, Fout, target);
7050e0e16a8SMark Brown return -EINVAL;
7060e0e16a8SMark Brown }
7070e0e16a8SMark Brown
7080e0e16a8SMark Brown fll_div->fllclk_div = div >> 2;
7090e0e16a8SMark Brown
7100e0e16a8SMark Brown if (Fref < 48000)
7110e0e16a8SMark Brown fll_div->fll_slow_lock_ref = 1;
7120e0e16a8SMark Brown else
7130e0e16a8SMark Brown fll_div->fll_slow_lock_ref = 0;
7140e0e16a8SMark Brown
7150e0e16a8SMark Brown Ndiv = target / Fref;
7160e0e16a8SMark Brown
7170e0e16a8SMark Brown if (Fref < 1000000)
7180e0e16a8SMark Brown fll_div->fll_ratio = 8;
7190e0e16a8SMark Brown else
7200e0e16a8SMark Brown fll_div->fll_ratio = 1;
7210e0e16a8SMark Brown
7220e0e16a8SMark Brown fll_div->n = Ndiv / fll_div->fll_ratio;
7230e0e16a8SMark Brown Nmod = (target / fll_div->fll_ratio) % Fref;
7240e0e16a8SMark Brown
7250e0e16a8SMark Brown /* Calculate fractional part - scale up so we can round. */
7260e0e16a8SMark Brown Kpart = FIXED_FLL_SIZE * (long long)Nmod;
7270e0e16a8SMark Brown
7280e0e16a8SMark Brown do_div(Kpart, Fref);
7290e0e16a8SMark Brown
7300e0e16a8SMark Brown K = Kpart & 0xFFFFFFFF;
7310e0e16a8SMark Brown
7320e0e16a8SMark Brown if ((K % 10) >= 5)
7330e0e16a8SMark Brown K += 5;
7340e0e16a8SMark Brown
7350e0e16a8SMark Brown /* Move down to proper range now rounding is done */
7360e0e16a8SMark Brown fll_div->k = K / 10;
7370e0e16a8SMark Brown
738246e884bSTakashi Iwai if (WARN_ON(target != Fout * (fll_div->fllclk_div << 2)) ||
739246e884bSTakashi Iwai WARN_ON(!K && target != Fref * fll_div->fll_ratio * fll_div->n))
740246e884bSTakashi Iwai return -EINVAL;
7410e0e16a8SMark Brown
7420e0e16a8SMark Brown return 0;
7430e0e16a8SMark Brown }
7440e0e16a8SMark Brown
wm8900_set_fll(struct snd_soc_component * component,int fll_id,unsigned int freq_in,unsigned int freq_out)745825a52aaSKuninori Morimoto static int wm8900_set_fll(struct snd_soc_component *component,
7460e0e16a8SMark Brown int fll_id, unsigned int freq_in, unsigned int freq_out)
7470e0e16a8SMark Brown {
748825a52aaSKuninori Morimoto struct wm8900_priv *wm8900 = snd_soc_component_get_drvdata(component);
7490e0e16a8SMark Brown struct _fll_div fll_div;
7500e0e16a8SMark Brown
7510e0e16a8SMark Brown if (wm8900->fll_in == freq_in && wm8900->fll_out == freq_out)
7520e0e16a8SMark Brown return 0;
7530e0e16a8SMark Brown
7540e0e16a8SMark Brown /* The digital side should be disabled during any change. */
755825a52aaSKuninori Morimoto snd_soc_component_update_bits(component, WM8900_REG_POWER1,
75629c6a01dSAxel Lin WM8900_REG_POWER1_FLL_ENA, 0);
7570e0e16a8SMark Brown
7580e0e16a8SMark Brown /* Disable the FLL? */
7590e0e16a8SMark Brown if (!freq_in || !freq_out) {
760825a52aaSKuninori Morimoto snd_soc_component_update_bits(component, WM8900_REG_CLOCKING1,
76129c6a01dSAxel Lin WM8900_REG_CLOCKING1_MCLK_SRC, 0);
762825a52aaSKuninori Morimoto snd_soc_component_update_bits(component, WM8900_REG_FLLCTL1,
76329c6a01dSAxel Lin WM8900_REG_FLLCTL1_OSC_ENA, 0);
7640e0e16a8SMark Brown wm8900->fll_in = freq_in;
7650e0e16a8SMark Brown wm8900->fll_out = freq_out;
7660e0e16a8SMark Brown
7670e0e16a8SMark Brown return 0;
7680e0e16a8SMark Brown }
7690e0e16a8SMark Brown
7700e0e16a8SMark Brown if (fll_factors(&fll_div, freq_in, freq_out) != 0)
7710e0e16a8SMark Brown goto reenable;
7720e0e16a8SMark Brown
7730e0e16a8SMark Brown wm8900->fll_in = freq_in;
7740e0e16a8SMark Brown wm8900->fll_out = freq_out;
7750e0e16a8SMark Brown
7760e0e16a8SMark Brown /* The osclilator *MUST* be enabled before we enable the
7770e0e16a8SMark Brown * digital circuit. */
778825a52aaSKuninori Morimoto snd_soc_component_write(component, WM8900_REG_FLLCTL1,
7790e0e16a8SMark Brown fll_div.fll_ratio | WM8900_REG_FLLCTL1_OSC_ENA);
7800e0e16a8SMark Brown
781825a52aaSKuninori Morimoto snd_soc_component_write(component, WM8900_REG_FLLCTL4, fll_div.n >> 5);
782825a52aaSKuninori Morimoto snd_soc_component_write(component, WM8900_REG_FLLCTL5,
7830e0e16a8SMark Brown (fll_div.fllclk_div << 6) | (fll_div.n & 0x1f));
7840e0e16a8SMark Brown
7850e0e16a8SMark Brown if (fll_div.k) {
786825a52aaSKuninori Morimoto snd_soc_component_write(component, WM8900_REG_FLLCTL2,
7870e0e16a8SMark Brown (fll_div.k >> 8) | 0x100);
788825a52aaSKuninori Morimoto snd_soc_component_write(component, WM8900_REG_FLLCTL3, fll_div.k & 0xff);
7890e0e16a8SMark Brown } else
790825a52aaSKuninori Morimoto snd_soc_component_write(component, WM8900_REG_FLLCTL2, 0);
7910e0e16a8SMark Brown
7920e0e16a8SMark Brown if (fll_div.fll_slow_lock_ref)
793825a52aaSKuninori Morimoto snd_soc_component_write(component, WM8900_REG_FLLCTL6,
7940e0e16a8SMark Brown WM8900_REG_FLLCTL6_FLL_SLOW_LOCK_REF);
7950e0e16a8SMark Brown else
796825a52aaSKuninori Morimoto snd_soc_component_write(component, WM8900_REG_FLLCTL6, 0);
7970e0e16a8SMark Brown
798825a52aaSKuninori Morimoto snd_soc_component_update_bits(component, WM8900_REG_POWER1,
79929c6a01dSAxel Lin WM8900_REG_POWER1_FLL_ENA,
80029c6a01dSAxel Lin WM8900_REG_POWER1_FLL_ENA);
8010e0e16a8SMark Brown
8020e0e16a8SMark Brown reenable:
803825a52aaSKuninori Morimoto snd_soc_component_update_bits(component, WM8900_REG_CLOCKING1,
80429c6a01dSAxel Lin WM8900_REG_CLOCKING1_MCLK_SRC,
80529c6a01dSAxel Lin WM8900_REG_CLOCKING1_MCLK_SRC);
8060e0e16a8SMark Brown return 0;
8070e0e16a8SMark Brown }
8080e0e16a8SMark Brown
wm8900_set_dai_pll(struct snd_soc_dai * codec_dai,int pll_id,int source,unsigned int freq_in,unsigned int freq_out)80985488037SMark Brown static int wm8900_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
81085488037SMark Brown int source, unsigned int freq_in, unsigned int freq_out)
8110e0e16a8SMark Brown {
812825a52aaSKuninori Morimoto return wm8900_set_fll(codec_dai->component, pll_id, freq_in, freq_out);
8130e0e16a8SMark Brown }
8140e0e16a8SMark Brown
wm8900_set_dai_clkdiv(struct snd_soc_dai * codec_dai,int div_id,int div)8150e0e16a8SMark Brown static int wm8900_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
8160e0e16a8SMark Brown int div_id, int div)
8170e0e16a8SMark Brown {
818825a52aaSKuninori Morimoto struct snd_soc_component *component = codec_dai->component;
8190e0e16a8SMark Brown
8200e0e16a8SMark Brown switch (div_id) {
8210e0e16a8SMark Brown case WM8900_BCLK_DIV:
822825a52aaSKuninori Morimoto snd_soc_component_update_bits(component, WM8900_REG_CLOCKING1,
82329c6a01dSAxel Lin WM8900_REG_CLOCKING1_BCLK_MASK, div);
8240e0e16a8SMark Brown break;
8250e0e16a8SMark Brown case WM8900_OPCLK_DIV:
826825a52aaSKuninori Morimoto snd_soc_component_update_bits(component, WM8900_REG_CLOCKING1,
82729c6a01dSAxel Lin WM8900_REG_CLOCKING1_OPCLK_MASK, div);
8280e0e16a8SMark Brown break;
8290e0e16a8SMark Brown case WM8900_DAC_LRCLK:
830825a52aaSKuninori Morimoto snd_soc_component_update_bits(component, WM8900_REG_AUDIO4,
83129c6a01dSAxel Lin WM8900_LRC_MASK, div);
8320e0e16a8SMark Brown break;
8330e0e16a8SMark Brown case WM8900_ADC_LRCLK:
834825a52aaSKuninori Morimoto snd_soc_component_update_bits(component, WM8900_REG_AUDIO3,
83529c6a01dSAxel Lin WM8900_LRC_MASK, div);
8360e0e16a8SMark Brown break;
8370e0e16a8SMark Brown case WM8900_DAC_CLKDIV:
838825a52aaSKuninori Morimoto snd_soc_component_update_bits(component, WM8900_REG_CLOCKING2,
83929c6a01dSAxel Lin WM8900_REG_CLOCKING2_DAC_CLKDIV, div);
8400e0e16a8SMark Brown break;
8410e0e16a8SMark Brown case WM8900_ADC_CLKDIV:
842825a52aaSKuninori Morimoto snd_soc_component_update_bits(component, WM8900_REG_CLOCKING2,
84329c6a01dSAxel Lin WM8900_REG_CLOCKING2_ADC_CLKDIV, div);
8440e0e16a8SMark Brown break;
8450e0e16a8SMark Brown case WM8900_LRCLK_MODE:
846825a52aaSKuninori Morimoto snd_soc_component_update_bits(component, WM8900_REG_DACCTRL,
84729c6a01dSAxel Lin WM8900_REG_DACCTRL_AIF_LRCLKRATE, div);
8480e0e16a8SMark Brown break;
8490e0e16a8SMark Brown default:
8500e0e16a8SMark Brown return -EINVAL;
8510e0e16a8SMark Brown }
8520e0e16a8SMark Brown
8530e0e16a8SMark Brown return 0;
8540e0e16a8SMark Brown }
8550e0e16a8SMark Brown
8560e0e16a8SMark Brown
wm8900_set_dai_fmt(struct snd_soc_dai * codec_dai,unsigned int fmt)8570e0e16a8SMark Brown static int wm8900_set_dai_fmt(struct snd_soc_dai *codec_dai,
8580e0e16a8SMark Brown unsigned int fmt)
8590e0e16a8SMark Brown {
860825a52aaSKuninori Morimoto struct snd_soc_component *component = codec_dai->component;
8610e0e16a8SMark Brown unsigned int clocking1, aif1, aif3, aif4;
8620e0e16a8SMark Brown
8636d75dfc3SKuninori Morimoto clocking1 = snd_soc_component_read(component, WM8900_REG_CLOCKING1);
8646d75dfc3SKuninori Morimoto aif1 = snd_soc_component_read(component, WM8900_REG_AUDIO1);
8656d75dfc3SKuninori Morimoto aif3 = snd_soc_component_read(component, WM8900_REG_AUDIO3);
8666d75dfc3SKuninori Morimoto aif4 = snd_soc_component_read(component, WM8900_REG_AUDIO4);
8670e0e16a8SMark Brown
8680e0e16a8SMark Brown /* set master/slave audio interface */
8690e0e16a8SMark Brown switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
8700e0e16a8SMark Brown case SND_SOC_DAIFMT_CBS_CFS:
8710e0e16a8SMark Brown clocking1 &= ~WM8900_REG_CLOCKING1_BCLK_DIR;
8720e0e16a8SMark Brown aif3 &= ~WM8900_REG_AUDIO3_ADCLRC_DIR;
8730e0e16a8SMark Brown aif4 &= ~WM8900_REG_AUDIO4_DACLRC_DIR;
8740e0e16a8SMark Brown break;
8750e0e16a8SMark Brown case SND_SOC_DAIFMT_CBS_CFM:
8760e0e16a8SMark Brown clocking1 &= ~WM8900_REG_CLOCKING1_BCLK_DIR;
8770e0e16a8SMark Brown aif3 |= WM8900_REG_AUDIO3_ADCLRC_DIR;
8780e0e16a8SMark Brown aif4 |= WM8900_REG_AUDIO4_DACLRC_DIR;
8790e0e16a8SMark Brown break;
8800e0e16a8SMark Brown case SND_SOC_DAIFMT_CBM_CFM:
8810e0e16a8SMark Brown clocking1 |= WM8900_REG_CLOCKING1_BCLK_DIR;
8820e0e16a8SMark Brown aif3 |= WM8900_REG_AUDIO3_ADCLRC_DIR;
8830e0e16a8SMark Brown aif4 |= WM8900_REG_AUDIO4_DACLRC_DIR;
8840e0e16a8SMark Brown break;
8850e0e16a8SMark Brown case SND_SOC_DAIFMT_CBM_CFS:
8860e0e16a8SMark Brown clocking1 |= WM8900_REG_CLOCKING1_BCLK_DIR;
8870e0e16a8SMark Brown aif3 &= ~WM8900_REG_AUDIO3_ADCLRC_DIR;
8880e0e16a8SMark Brown aif4 &= ~WM8900_REG_AUDIO4_DACLRC_DIR;
8890e0e16a8SMark Brown break;
8900e0e16a8SMark Brown default:
8910e0e16a8SMark Brown return -EINVAL;
8920e0e16a8SMark Brown }
8930e0e16a8SMark Brown
8940e0e16a8SMark Brown switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
8950e0e16a8SMark Brown case SND_SOC_DAIFMT_DSP_A:
8960e0e16a8SMark Brown aif1 |= WM8900_REG_AUDIO1_AIF_FMT_MASK;
8970e0e16a8SMark Brown aif1 &= ~WM8900_REG_AUDIO1_LRCLK_INV;
8980e0e16a8SMark Brown break;
8990e0e16a8SMark Brown case SND_SOC_DAIFMT_DSP_B:
9000e0e16a8SMark Brown aif1 |= WM8900_REG_AUDIO1_AIF_FMT_MASK;
9010e0e16a8SMark Brown aif1 |= WM8900_REG_AUDIO1_LRCLK_INV;
9020e0e16a8SMark Brown break;
9030e0e16a8SMark Brown case SND_SOC_DAIFMT_I2S:
9040e0e16a8SMark Brown aif1 &= ~WM8900_REG_AUDIO1_AIF_FMT_MASK;
9050e0e16a8SMark Brown aif1 |= 0x10;
9060e0e16a8SMark Brown break;
9070e0e16a8SMark Brown case SND_SOC_DAIFMT_RIGHT_J:
9080e0e16a8SMark Brown aif1 &= ~WM8900_REG_AUDIO1_AIF_FMT_MASK;
9090e0e16a8SMark Brown break;
9100e0e16a8SMark Brown case SND_SOC_DAIFMT_LEFT_J:
9110e0e16a8SMark Brown aif1 &= ~WM8900_REG_AUDIO1_AIF_FMT_MASK;
9120e0e16a8SMark Brown aif1 |= 0x8;
9130e0e16a8SMark Brown break;
9140e0e16a8SMark Brown default:
9150e0e16a8SMark Brown return -EINVAL;
9160e0e16a8SMark Brown }
9170e0e16a8SMark Brown
9180e0e16a8SMark Brown /* Clock inversion */
9190e0e16a8SMark Brown switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
9200e0e16a8SMark Brown case SND_SOC_DAIFMT_DSP_A:
9210e0e16a8SMark Brown case SND_SOC_DAIFMT_DSP_B:
9220e0e16a8SMark Brown /* frame inversion not valid for DSP modes */
9230e0e16a8SMark Brown switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
9240e0e16a8SMark Brown case SND_SOC_DAIFMT_NB_NF:
9250e0e16a8SMark Brown aif1 &= ~WM8900_REG_AUDIO1_BCLK_INV;
9260e0e16a8SMark Brown break;
9270e0e16a8SMark Brown case SND_SOC_DAIFMT_IB_NF:
9280e0e16a8SMark Brown aif1 |= WM8900_REG_AUDIO1_BCLK_INV;
9290e0e16a8SMark Brown break;
9300e0e16a8SMark Brown default:
9310e0e16a8SMark Brown return -EINVAL;
9320e0e16a8SMark Brown }
9330e0e16a8SMark Brown break;
9340e0e16a8SMark Brown case SND_SOC_DAIFMT_I2S:
9350e0e16a8SMark Brown case SND_SOC_DAIFMT_RIGHT_J:
9360e0e16a8SMark Brown case SND_SOC_DAIFMT_LEFT_J:
9370e0e16a8SMark Brown switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
9380e0e16a8SMark Brown case SND_SOC_DAIFMT_NB_NF:
9390e0e16a8SMark Brown aif1 &= ~WM8900_REG_AUDIO1_BCLK_INV;
9400e0e16a8SMark Brown aif1 &= ~WM8900_REG_AUDIO1_LRCLK_INV;
9410e0e16a8SMark Brown break;
9420e0e16a8SMark Brown case SND_SOC_DAIFMT_IB_IF:
9430e0e16a8SMark Brown aif1 |= WM8900_REG_AUDIO1_BCLK_INV;
9440e0e16a8SMark Brown aif1 |= WM8900_REG_AUDIO1_LRCLK_INV;
9450e0e16a8SMark Brown break;
9460e0e16a8SMark Brown case SND_SOC_DAIFMT_IB_NF:
9470e0e16a8SMark Brown aif1 |= WM8900_REG_AUDIO1_BCLK_INV;
9480e0e16a8SMark Brown aif1 &= ~WM8900_REG_AUDIO1_LRCLK_INV;
9490e0e16a8SMark Brown break;
9500e0e16a8SMark Brown case SND_SOC_DAIFMT_NB_IF:
9510e0e16a8SMark Brown aif1 &= ~WM8900_REG_AUDIO1_BCLK_INV;
9520e0e16a8SMark Brown aif1 |= WM8900_REG_AUDIO1_LRCLK_INV;
9530e0e16a8SMark Brown break;
9540e0e16a8SMark Brown default:
9550e0e16a8SMark Brown return -EINVAL;
9560e0e16a8SMark Brown }
9570e0e16a8SMark Brown break;
9580e0e16a8SMark Brown default:
9590e0e16a8SMark Brown return -EINVAL;
9600e0e16a8SMark Brown }
9610e0e16a8SMark Brown
962825a52aaSKuninori Morimoto snd_soc_component_write(component, WM8900_REG_CLOCKING1, clocking1);
963825a52aaSKuninori Morimoto snd_soc_component_write(component, WM8900_REG_AUDIO1, aif1);
964825a52aaSKuninori Morimoto snd_soc_component_write(component, WM8900_REG_AUDIO3, aif3);
965825a52aaSKuninori Morimoto snd_soc_component_write(component, WM8900_REG_AUDIO4, aif4);
9660e0e16a8SMark Brown
9670e0e16a8SMark Brown return 0;
9680e0e16a8SMark Brown }
9690e0e16a8SMark Brown
wm8900_mute(struct snd_soc_dai * codec_dai,int mute,int direction)97026d3c16eSKuninori Morimoto static int wm8900_mute(struct snd_soc_dai *codec_dai, int mute, int direction)
9710e0e16a8SMark Brown {
972825a52aaSKuninori Morimoto struct snd_soc_component *component = codec_dai->component;
9730e0e16a8SMark Brown u16 reg;
9740e0e16a8SMark Brown
9756d75dfc3SKuninori Morimoto reg = snd_soc_component_read(component, WM8900_REG_DACCTRL);
9760e0e16a8SMark Brown
9770e0e16a8SMark Brown if (mute)
9780e0e16a8SMark Brown reg |= WM8900_REG_DACCTRL_MUTE;
9790e0e16a8SMark Brown else
9800e0e16a8SMark Brown reg &= ~WM8900_REG_DACCTRL_MUTE;
9810e0e16a8SMark Brown
982825a52aaSKuninori Morimoto snd_soc_component_write(component, WM8900_REG_DACCTRL, reg);
9830e0e16a8SMark Brown
9840e0e16a8SMark Brown return 0;
9850e0e16a8SMark Brown }
9860e0e16a8SMark Brown
9870e0e16a8SMark Brown #define WM8900_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
9880e0e16a8SMark Brown SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\
9890e0e16a8SMark Brown SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000)
9900e0e16a8SMark Brown
9910e0e16a8SMark Brown #define WM8900_PCM_FORMATS \
992e712bfcaSMaciej S. Szmigiero (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
993e712bfcaSMaciej S. Szmigiero SNDRV_PCM_FMTBIT_S24_LE)
9940e0e16a8SMark Brown
99585e7652dSLars-Peter Clausen static const struct snd_soc_dai_ops wm8900_dai_ops = {
9966335d055SEric Miao .hw_params = wm8900_hw_params,
9976335d055SEric Miao .set_clkdiv = wm8900_set_dai_clkdiv,
9986335d055SEric Miao .set_pll = wm8900_set_dai_pll,
9996335d055SEric Miao .set_fmt = wm8900_set_dai_fmt,
100026d3c16eSKuninori Morimoto .mute_stream = wm8900_mute,
100126d3c16eSKuninori Morimoto .no_capture_mute = 1,
10026335d055SEric Miao };
10036335d055SEric Miao
1004f0fba2adSLiam Girdwood static struct snd_soc_dai_driver wm8900_dai = {
1005f0fba2adSLiam Girdwood .name = "wm8900-hifi",
10060e0e16a8SMark Brown .playback = {
10070e0e16a8SMark Brown .stream_name = "HiFi Playback",
10080e0e16a8SMark Brown .channels_min = 1,
10090e0e16a8SMark Brown .channels_max = 2,
10100e0e16a8SMark Brown .rates = WM8900_RATES,
10110e0e16a8SMark Brown .formats = WM8900_PCM_FORMATS,
10120e0e16a8SMark Brown },
10130e0e16a8SMark Brown .capture = {
10140e0e16a8SMark Brown .stream_name = "HiFi Capture",
10150e0e16a8SMark Brown .channels_min = 1,
10160e0e16a8SMark Brown .channels_max = 2,
10170e0e16a8SMark Brown .rates = WM8900_RATES,
10180e0e16a8SMark Brown .formats = WM8900_PCM_FORMATS,
10190e0e16a8SMark Brown },
10206335d055SEric Miao .ops = &wm8900_dai_ops,
10210e0e16a8SMark Brown };
10220e0e16a8SMark Brown
wm8900_set_bias_level(struct snd_soc_component * component,enum snd_soc_bias_level level)1023825a52aaSKuninori Morimoto static int wm8900_set_bias_level(struct snd_soc_component *component,
10240e0e16a8SMark Brown enum snd_soc_bias_level level)
10250e0e16a8SMark Brown {
10260e0e16a8SMark Brown u16 reg;
10270e0e16a8SMark Brown
10280e0e16a8SMark Brown switch (level) {
10290e0e16a8SMark Brown case SND_SOC_BIAS_ON:
10300e0e16a8SMark Brown /* Enable thermal shutdown */
1031825a52aaSKuninori Morimoto snd_soc_component_update_bits(component, WM8900_REG_GPIO,
103229c6a01dSAxel Lin WM8900_REG_GPIO_TEMP_ENA,
103329c6a01dSAxel Lin WM8900_REG_GPIO_TEMP_ENA);
1034825a52aaSKuninori Morimoto snd_soc_component_update_bits(component, WM8900_REG_ADDCTL,
103529c6a01dSAxel Lin WM8900_REG_ADDCTL_TEMP_SD,
103629c6a01dSAxel Lin WM8900_REG_ADDCTL_TEMP_SD);
10370e0e16a8SMark Brown break;
10380e0e16a8SMark Brown
10390e0e16a8SMark Brown case SND_SOC_BIAS_PREPARE:
10400e0e16a8SMark Brown break;
10410e0e16a8SMark Brown
10420e0e16a8SMark Brown case SND_SOC_BIAS_STANDBY:
10430e0e16a8SMark Brown /* Charge capacitors if initial power up */
1044825a52aaSKuninori Morimoto if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
10450e0e16a8SMark Brown /* STARTUP_BIAS_ENA on */
1046825a52aaSKuninori Morimoto snd_soc_component_write(component, WM8900_REG_POWER1,
10470e0e16a8SMark Brown WM8900_REG_POWER1_STARTUP_BIAS_ENA);
10480e0e16a8SMark Brown
10490e0e16a8SMark Brown /* Startup bias mode */
1050825a52aaSKuninori Morimoto snd_soc_component_write(component, WM8900_REG_ADDCTL,
10510e0e16a8SMark Brown WM8900_REG_ADDCTL_BIAS_SRC |
10520e0e16a8SMark Brown WM8900_REG_ADDCTL_VMID_SOFTST);
10530e0e16a8SMark Brown
10540e0e16a8SMark Brown /* VMID 2x50k */
1055825a52aaSKuninori Morimoto snd_soc_component_write(component, WM8900_REG_POWER1,
10560e0e16a8SMark Brown WM8900_REG_POWER1_STARTUP_BIAS_ENA | 0x1);
10570e0e16a8SMark Brown
10580e0e16a8SMark Brown /* Allow capacitors to charge */
10590e0e16a8SMark Brown schedule_timeout_interruptible(msecs_to_jiffies(400));
10600e0e16a8SMark Brown
10610e0e16a8SMark Brown /* Enable bias */
1062825a52aaSKuninori Morimoto snd_soc_component_write(component, WM8900_REG_POWER1,
10630e0e16a8SMark Brown WM8900_REG_POWER1_STARTUP_BIAS_ENA |
10640e0e16a8SMark Brown WM8900_REG_POWER1_BIAS_ENA | 0x1);
10650e0e16a8SMark Brown
1066825a52aaSKuninori Morimoto snd_soc_component_write(component, WM8900_REG_ADDCTL, 0);
10670e0e16a8SMark Brown
1068825a52aaSKuninori Morimoto snd_soc_component_write(component, WM8900_REG_POWER1,
10690e0e16a8SMark Brown WM8900_REG_POWER1_BIAS_ENA | 0x1);
10700e0e16a8SMark Brown }
10710e0e16a8SMark Brown
10726d75dfc3SKuninori Morimoto reg = snd_soc_component_read(component, WM8900_REG_POWER1);
1073825a52aaSKuninori Morimoto snd_soc_component_write(component, WM8900_REG_POWER1,
10740e0e16a8SMark Brown (reg & WM8900_REG_POWER1_FLL_ENA) |
10750e0e16a8SMark Brown WM8900_REG_POWER1_BIAS_ENA | 0x1);
1076825a52aaSKuninori Morimoto snd_soc_component_write(component, WM8900_REG_POWER2,
10770e0e16a8SMark Brown WM8900_REG_POWER2_SYSCLK_ENA);
1078825a52aaSKuninori Morimoto snd_soc_component_write(component, WM8900_REG_POWER3, 0);
10790e0e16a8SMark Brown break;
10800e0e16a8SMark Brown
10810e0e16a8SMark Brown case SND_SOC_BIAS_OFF:
10820e0e16a8SMark Brown /* Startup bias enable */
10836d75dfc3SKuninori Morimoto reg = snd_soc_component_read(component, WM8900_REG_POWER1);
1084825a52aaSKuninori Morimoto snd_soc_component_write(component, WM8900_REG_POWER1,
10850e0e16a8SMark Brown reg & WM8900_REG_POWER1_STARTUP_BIAS_ENA);
1086825a52aaSKuninori Morimoto snd_soc_component_write(component, WM8900_REG_ADDCTL,
10870e0e16a8SMark Brown WM8900_REG_ADDCTL_BIAS_SRC |
10880e0e16a8SMark Brown WM8900_REG_ADDCTL_VMID_SOFTST);
10890e0e16a8SMark Brown
10900e0e16a8SMark Brown /* Discharge caps */
1091825a52aaSKuninori Morimoto snd_soc_component_write(component, WM8900_REG_POWER1,
10920e0e16a8SMark Brown WM8900_REG_POWER1_STARTUP_BIAS_ENA);
10930e0e16a8SMark Brown schedule_timeout_interruptible(msecs_to_jiffies(500));
10940e0e16a8SMark Brown
10950e0e16a8SMark Brown /* Remove clamp */
1096825a52aaSKuninori Morimoto snd_soc_component_write(component, WM8900_REG_HPCTL1, 0);
10970e0e16a8SMark Brown
10980e0e16a8SMark Brown /* Power down */
1099825a52aaSKuninori Morimoto snd_soc_component_write(component, WM8900_REG_ADDCTL, 0);
1100825a52aaSKuninori Morimoto snd_soc_component_write(component, WM8900_REG_POWER1, 0);
1101825a52aaSKuninori Morimoto snd_soc_component_write(component, WM8900_REG_POWER2, 0);
1102825a52aaSKuninori Morimoto snd_soc_component_write(component, WM8900_REG_POWER3, 0);
11030e0e16a8SMark Brown
11040e0e16a8SMark Brown /* Need to let things settle before stopping the clock
11050e0e16a8SMark Brown * to ensure that restart works, see "Stopping the
11060e0e16a8SMark Brown * master clock" in the datasheet. */
11070e0e16a8SMark Brown schedule_timeout_interruptible(msecs_to_jiffies(1));
1108825a52aaSKuninori Morimoto snd_soc_component_write(component, WM8900_REG_POWER2,
11090e0e16a8SMark Brown WM8900_REG_POWER2_SYSCLK_ENA);
11100e0e16a8SMark Brown break;
11110e0e16a8SMark Brown }
11120e0e16a8SMark Brown return 0;
11130e0e16a8SMark Brown }
11140e0e16a8SMark Brown
wm8900_suspend(struct snd_soc_component * component)1115825a52aaSKuninori Morimoto static int wm8900_suspend(struct snd_soc_component *component)
11160e0e16a8SMark Brown {
1117825a52aaSKuninori Morimoto struct wm8900_priv *wm8900 = snd_soc_component_get_drvdata(component);
11180e0e16a8SMark Brown int fll_out = wm8900->fll_out;
11190e0e16a8SMark Brown int fll_in = wm8900->fll_in;
11200e0e16a8SMark Brown int ret;
11210e0e16a8SMark Brown
11220e0e16a8SMark Brown /* Stop the FLL in an orderly fashion */
1123825a52aaSKuninori Morimoto ret = wm8900_set_fll(component, 0, 0, 0);
11240e0e16a8SMark Brown if (ret != 0) {
1125825a52aaSKuninori Morimoto dev_err(component->dev, "Failed to stop FLL\n");
11260e0e16a8SMark Brown return ret;
11270e0e16a8SMark Brown }
11280e0e16a8SMark Brown
11290e0e16a8SMark Brown wm8900->fll_out = fll_out;
11300e0e16a8SMark Brown wm8900->fll_in = fll_in;
11310e0e16a8SMark Brown
1132825a52aaSKuninori Morimoto snd_soc_component_force_bias_level(component, SND_SOC_BIAS_OFF);
11330e0e16a8SMark Brown
11340e0e16a8SMark Brown return 0;
11350e0e16a8SMark Brown }
11360e0e16a8SMark Brown
wm8900_resume(struct snd_soc_component * component)1137825a52aaSKuninori Morimoto static int wm8900_resume(struct snd_soc_component *component)
11380e0e16a8SMark Brown {
1139825a52aaSKuninori Morimoto struct wm8900_priv *wm8900 = snd_soc_component_get_drvdata(component);
114049992624SMark Brown int ret;
11410e0e16a8SMark Brown
1142825a52aaSKuninori Morimoto wm8900_reset(component);
114349992624SMark Brown
114449992624SMark Brown ret = regcache_sync(wm8900->regmap);
114549992624SMark Brown if (ret != 0) {
1146825a52aaSKuninori Morimoto dev_err(component->dev, "Failed to restore cache: %d\n", ret);
114749992624SMark Brown return ret;
114849992624SMark Brown }
114949992624SMark Brown
1150825a52aaSKuninori Morimoto snd_soc_component_force_bias_level(component, SND_SOC_BIAS_STANDBY);
11510e0e16a8SMark Brown
11520e0e16a8SMark Brown /* Restart the FLL? */
11530e0e16a8SMark Brown if (wm8900->fll_out) {
11540e0e16a8SMark Brown int fll_out = wm8900->fll_out;
11550e0e16a8SMark Brown int fll_in = wm8900->fll_in;
11560e0e16a8SMark Brown
11570e0e16a8SMark Brown wm8900->fll_in = 0;
11580e0e16a8SMark Brown wm8900->fll_out = 0;
11590e0e16a8SMark Brown
1160825a52aaSKuninori Morimoto ret = wm8900_set_fll(component, 0, fll_in, fll_out);
11610e0e16a8SMark Brown if (ret != 0) {
1162825a52aaSKuninori Morimoto dev_err(component->dev, "Failed to restart FLL\n");
11630e0e16a8SMark Brown return ret;
11640e0e16a8SMark Brown }
11650e0e16a8SMark Brown }
11660e0e16a8SMark Brown
11670e0e16a8SMark Brown return 0;
11680e0e16a8SMark Brown }
11690e0e16a8SMark Brown
wm8900_probe(struct snd_soc_component * component)1170825a52aaSKuninori Morimoto static int wm8900_probe(struct snd_soc_component *component)
11710e0e16a8SMark Brown {
11725d6be5aaSXiubo Li int reg;
11738d50e447SMark Brown
11746d75dfc3SKuninori Morimoto reg = snd_soc_component_read(component, WM8900_REG_ID);
11750e0e16a8SMark Brown if (reg != 0x8900) {
1176825a52aaSKuninori Morimoto dev_err(component->dev, "Device is not a WM8900 - ID %x\n", reg);
1177f0fba2adSLiam Girdwood return -ENODEV;
11780e0e16a8SMark Brown }
11790e0e16a8SMark Brown
1180825a52aaSKuninori Morimoto wm8900_reset(component);
11810e0e16a8SMark Brown
118278e19a39SMark Brown /* Turn the chip on */
1183825a52aaSKuninori Morimoto snd_soc_component_force_bias_level(component, SND_SOC_BIAS_STANDBY);
118478e19a39SMark Brown
11850e0e16a8SMark Brown /* Latch the volume update bits */
1186825a52aaSKuninori Morimoto snd_soc_component_update_bits(component, WM8900_REG_LINVOL, 0x100, 0x100);
1187825a52aaSKuninori Morimoto snd_soc_component_update_bits(component, WM8900_REG_RINVOL, 0x100, 0x100);
1188825a52aaSKuninori Morimoto snd_soc_component_update_bits(component, WM8900_REG_LOUT1CTL, 0x100, 0x100);
1189825a52aaSKuninori Morimoto snd_soc_component_update_bits(component, WM8900_REG_ROUT1CTL, 0x100, 0x100);
1190825a52aaSKuninori Morimoto snd_soc_component_update_bits(component, WM8900_REG_LOUT2CTL, 0x100, 0x100);
1191825a52aaSKuninori Morimoto snd_soc_component_update_bits(component, WM8900_REG_ROUT2CTL, 0x100, 0x100);
1192825a52aaSKuninori Morimoto snd_soc_component_update_bits(component, WM8900_REG_LDAC_DV, 0x100, 0x100);
1193825a52aaSKuninori Morimoto snd_soc_component_update_bits(component, WM8900_REG_RDAC_DV, 0x100, 0x100);
1194825a52aaSKuninori Morimoto snd_soc_component_update_bits(component, WM8900_REG_LADC_DV, 0x100, 0x100);
1195825a52aaSKuninori Morimoto snd_soc_component_update_bits(component, WM8900_REG_RADC_DV, 0x100, 0x100);
11960e0e16a8SMark Brown
11970e0e16a8SMark Brown /* Set the DAC and mixer output bias */
1198825a52aaSKuninori Morimoto snd_soc_component_write(component, WM8900_REG_OUTBIASCTL, 0x81);
11990e0e16a8SMark Brown
1200f0fba2adSLiam Girdwood return 0;
120178e19a39SMark Brown }
120278e19a39SMark Brown
1203825a52aaSKuninori Morimoto static const struct snd_soc_component_driver soc_component_dev_wm8900 = {
1204f0fba2adSLiam Girdwood .probe = wm8900_probe,
1205f0fba2adSLiam Girdwood .suspend = wm8900_suspend,
1206f0fba2adSLiam Girdwood .resume = wm8900_resume,
1207f0fba2adSLiam Girdwood .set_bias_level = wm8900_set_bias_level,
120846ce904fSMark Brown .controls = wm8900_snd_controls,
120946ce904fSMark Brown .num_controls = ARRAY_SIZE(wm8900_snd_controls),
121046ce904fSMark Brown .dapm_widgets = wm8900_dapm_widgets,
121146ce904fSMark Brown .num_dapm_widgets = ARRAY_SIZE(wm8900_dapm_widgets),
121246ce904fSMark Brown .dapm_routes = wm8900_dapm_routes,
121346ce904fSMark Brown .num_dapm_routes = ARRAY_SIZE(wm8900_dapm_routes),
1214825a52aaSKuninori Morimoto .idle_bias_on = 1,
1215825a52aaSKuninori Morimoto .use_pmdown_time = 1,
1216825a52aaSKuninori Morimoto .endianness = 1,
1217f0fba2adSLiam Girdwood };
121878e19a39SMark Brown
121949992624SMark Brown static const struct regmap_config wm8900_regmap = {
122049992624SMark Brown .reg_bits = 8,
122149992624SMark Brown .val_bits = 16,
122249992624SMark Brown .max_register = WM8900_MAXREG,
122349992624SMark Brown
122449992624SMark Brown .reg_defaults = wm8900_reg_defaults,
122549992624SMark Brown .num_reg_defaults = ARRAY_SIZE(wm8900_reg_defaults),
1226*2c609c6bSMark Brown .cache_type = REGCACHE_MAPLE,
122749992624SMark Brown
122849992624SMark Brown .volatile_reg = wm8900_volatile_register,
122949992624SMark Brown };
123049992624SMark Brown
1231f0fba2adSLiam Girdwood #if defined(CONFIG_SPI_MASTER)
wm8900_spi_probe(struct spi_device * spi)12327a79e94eSBill Pemberton static int wm8900_spi_probe(struct spi_device *spi)
1233f0fba2adSLiam Girdwood {
1234f0fba2adSLiam Girdwood struct wm8900_priv *wm8900;
1235f0fba2adSLiam Girdwood int ret;
1236f0fba2adSLiam Girdwood
12376a58870dSMark Brown wm8900 = devm_kzalloc(&spi->dev, sizeof(struct wm8900_priv),
12386a58870dSMark Brown GFP_KERNEL);
1239f0fba2adSLiam Girdwood if (wm8900 == NULL)
1240f0fba2adSLiam Girdwood return -ENOMEM;
1241f0fba2adSLiam Girdwood
124249992624SMark Brown wm8900->regmap = devm_regmap_init_spi(spi, &wm8900_regmap);
124349992624SMark Brown if (IS_ERR(wm8900->regmap))
124449992624SMark Brown return PTR_ERR(wm8900->regmap);
124549992624SMark Brown
1246f0fba2adSLiam Girdwood spi_set_drvdata(spi, wm8900);
1247f0fba2adSLiam Girdwood
1248825a52aaSKuninori Morimoto ret = devm_snd_soc_register_component(&spi->dev,
1249825a52aaSKuninori Morimoto &soc_component_dev_wm8900, &wm8900_dai, 1);
12506a58870dSMark Brown
1251f0fba2adSLiam Girdwood return ret;
1252f0fba2adSLiam Girdwood }
1253f0fba2adSLiam Girdwood
1254f0fba2adSLiam Girdwood static struct spi_driver wm8900_spi_driver = {
1255f0fba2adSLiam Girdwood .driver = {
1256091edccfSMark Brown .name = "wm8900",
1257f0fba2adSLiam Girdwood },
1258f0fba2adSLiam Girdwood .probe = wm8900_spi_probe,
1259f0fba2adSLiam Girdwood };
1260f0fba2adSLiam Girdwood #endif /* CONFIG_SPI_MASTER */
1261f0fba2adSLiam Girdwood
1262f25cf349SFabio Estevam #if IS_ENABLED(CONFIG_I2C)
wm8900_i2c_probe(struct i2c_client * i2c)126397b0b6e3SStephen Kitt static int wm8900_i2c_probe(struct i2c_client *i2c)
1264f0fba2adSLiam Girdwood {
1265f0fba2adSLiam Girdwood struct wm8900_priv *wm8900;
1266f0fba2adSLiam Girdwood int ret;
1267f0fba2adSLiam Girdwood
12686a58870dSMark Brown wm8900 = devm_kzalloc(&i2c->dev, sizeof(struct wm8900_priv),
12696a58870dSMark Brown GFP_KERNEL);
1270f0fba2adSLiam Girdwood if (wm8900 == NULL)
1271f0fba2adSLiam Girdwood return -ENOMEM;
1272f0fba2adSLiam Girdwood
127349992624SMark Brown wm8900->regmap = devm_regmap_init_i2c(i2c, &wm8900_regmap);
127449992624SMark Brown if (IS_ERR(wm8900->regmap))
127549992624SMark Brown return PTR_ERR(wm8900->regmap);
127649992624SMark Brown
1277f0fba2adSLiam Girdwood i2c_set_clientdata(i2c, wm8900);
1278f0fba2adSLiam Girdwood
1279825a52aaSKuninori Morimoto ret = devm_snd_soc_register_component(&i2c->dev,
1280825a52aaSKuninori Morimoto &soc_component_dev_wm8900, &wm8900_dai, 1);
12816a58870dSMark Brown
128278e19a39SMark Brown return ret;
12830e0e16a8SMark Brown }
12840e0e16a8SMark Brown
wm8900_i2c_remove(struct i2c_client * client)1285ed5c2f5fSUwe Kleine-König static void wm8900_i2c_remove(struct i2c_client *client)
1286ed5c2f5fSUwe Kleine-König {}
12870e0e16a8SMark Brown
12888ae6a552SJean Delvare static const struct i2c_device_id wm8900_i2c_id[] = {
12898ae6a552SJean Delvare { "wm8900", 0 },
12908ae6a552SJean Delvare { }
12918ae6a552SJean Delvare };
12928ae6a552SJean Delvare MODULE_DEVICE_TABLE(i2c, wm8900_i2c_id);
12930e0e16a8SMark Brown
12940e0e16a8SMark Brown static struct i2c_driver wm8900_i2c_driver = {
12950e0e16a8SMark Brown .driver = {
1296091edccfSMark Brown .name = "wm8900",
12970e0e16a8SMark Brown },
12989abcd240SUwe Kleine-König .probe = wm8900_i2c_probe,
12997a79e94eSBill Pemberton .remove = wm8900_i2c_remove,
13008ae6a552SJean Delvare .id_table = wm8900_i2c_id,
13010e0e16a8SMark Brown };
1302f0fba2adSLiam Girdwood #endif
13030e0e16a8SMark Brown
wm8900_modinit(void)1304c9b3a40fSTakashi Iwai static int __init wm8900_modinit(void)
130564089b84SMark Brown {
1306f0fba2adSLiam Girdwood int ret = 0;
1307f25cf349SFabio Estevam #if IS_ENABLED(CONFIG_I2C)
1308f0fba2adSLiam Girdwood ret = i2c_add_driver(&wm8900_i2c_driver);
1309f0fba2adSLiam Girdwood if (ret != 0) {
1310f0fba2adSLiam Girdwood printk(KERN_ERR "Failed to register wm8900 I2C driver: %d\n",
1311f0fba2adSLiam Girdwood ret);
1312f0fba2adSLiam Girdwood }
1313f0fba2adSLiam Girdwood #endif
1314f0fba2adSLiam Girdwood #if defined(CONFIG_SPI_MASTER)
1315f0fba2adSLiam Girdwood ret = spi_register_driver(&wm8900_spi_driver);
1316f0fba2adSLiam Girdwood if (ret != 0) {
1317f0fba2adSLiam Girdwood printk(KERN_ERR "Failed to register wm8900 SPI driver: %d\n",
1318f0fba2adSLiam Girdwood ret);
1319f0fba2adSLiam Girdwood }
1320f0fba2adSLiam Girdwood #endif
1321f0fba2adSLiam Girdwood return ret;
132264089b84SMark Brown }
132364089b84SMark Brown module_init(wm8900_modinit);
132464089b84SMark Brown
wm8900_exit(void)132564089b84SMark Brown static void __exit wm8900_exit(void)
132664089b84SMark Brown {
1327f25cf349SFabio Estevam #if IS_ENABLED(CONFIG_I2C)
1328f0752331SMark Brown i2c_del_driver(&wm8900_i2c_driver);
1329f0fba2adSLiam Girdwood #endif
1330f0fba2adSLiam Girdwood #if defined(CONFIG_SPI_MASTER)
1331f0fba2adSLiam Girdwood spi_unregister_driver(&wm8900_spi_driver);
1332f0fba2adSLiam Girdwood #endif
133364089b84SMark Brown }
133464089b84SMark Brown module_exit(wm8900_exit);
133564089b84SMark Brown
13360e0e16a8SMark Brown MODULE_DESCRIPTION("ASoC WM8900 driver");
13370e0e16a8SMark Brown MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfonmicro.com>");
13380e0e16a8SMark Brown MODULE_LICENSE("GPL");
1339