xref: /linux/sound/soc/codecs/max98388.c (revision 33e02dc69afbd8f1b85a51d74d72f139ba4ca623)
16a8e1d46SRyan Lee // SPDX-License-Identifier: GPL-2.0
26a8e1d46SRyan Lee // Copyright (c) 2022, Analog Devices Inc.
36a8e1d46SRyan Lee 
46a8e1d46SRyan Lee #include <linux/acpi.h>
56a8e1d46SRyan Lee #include <linux/delay.h>
6832beb64SLinus Walleij #include <linux/gpio/consumer.h>
76a8e1d46SRyan Lee #include <linux/i2c.h>
86a8e1d46SRyan Lee #include <linux/module.h>
96a8e1d46SRyan Lee #include <linux/mod_devicetable.h>
106a8e1d46SRyan Lee #include <linux/of.h>
116a8e1d46SRyan Lee #include <linux/pm_runtime.h>
126a8e1d46SRyan Lee #include <linux/regmap.h>
136a8e1d46SRyan Lee #include <linux/slab.h>
146a8e1d46SRyan Lee #include <linux/cdev.h>
156a8e1d46SRyan Lee #include <sound/pcm.h>
166a8e1d46SRyan Lee #include <sound/pcm_params.h>
176a8e1d46SRyan Lee #include <sound/soc.h>
186a8e1d46SRyan Lee #include <sound/tlv.h>
196a8e1d46SRyan Lee #include "max98388.h"
206a8e1d46SRyan Lee 
216a8e1d46SRyan Lee static struct reg_default max98388_reg[] = {
226a8e1d46SRyan Lee 	{MAX98388_R2000_SW_RESET, 0x00},
236a8e1d46SRyan Lee 	{MAX98388_R2001_INT_RAW1, 0x00},
246a8e1d46SRyan Lee 	{MAX98388_R2002_INT_RAW2, 0x00},
256a8e1d46SRyan Lee 	{MAX98388_R2004_INT_STATE1, 0x00},
266a8e1d46SRyan Lee 	{MAX98388_R2005_INT_STATE2, 0x00},
276a8e1d46SRyan Lee 	{MAX98388_R2020_THERM_WARN_THRESH, 0x0A},
286a8e1d46SRyan Lee 	{MAX98388_R2031_SPK_MON_THRESH, 0x58},
296a8e1d46SRyan Lee 	{MAX98388_R2032_SPK_MON_LD_SEL, 0x08},
306a8e1d46SRyan Lee 	{MAX98388_R2033_SPK_MON_DURATION, 0x02},
316a8e1d46SRyan Lee 	{MAX98388_R2037_ERR_MON_CTRL, 0x01},
326a8e1d46SRyan Lee 	{MAX98388_R2040_PCM_MODE_CFG, 0xC0},
336a8e1d46SRyan Lee 	{MAX98388_R2041_PCM_CLK_SETUP, 0x04},
346a8e1d46SRyan Lee 	{MAX98388_R2042_PCM_SR_SETUP, 0x88},
356a8e1d46SRyan Lee 	{MAX98388_R2044_PCM_TX_CTRL1, 0x00},
366a8e1d46SRyan Lee 	{MAX98388_R2045_PCM_TX_CTRL2, 0x00},
376a8e1d46SRyan Lee 	{MAX98388_R2050_PCM_TX_HIZ_CTRL1, 0xFF},
386a8e1d46SRyan Lee 	{MAX98388_R2051_PCM_TX_HIZ_CTRL2, 0xFF},
396a8e1d46SRyan Lee 	{MAX98388_R2052_PCM_TX_HIZ_CTRL3, 0xFF},
406a8e1d46SRyan Lee 	{MAX98388_R2053_PCM_TX_HIZ_CTRL4, 0xFF},
416a8e1d46SRyan Lee 	{MAX98388_R2054_PCM_TX_HIZ_CTRL5, 0xFF},
426a8e1d46SRyan Lee 	{MAX98388_R2055_PCM_TX_HIZ_CTRL6, 0xFF},
436a8e1d46SRyan Lee 	{MAX98388_R2056_PCM_TX_HIZ_CTRL7, 0xFF},
446a8e1d46SRyan Lee 	{MAX98388_R2057_PCM_TX_HIZ_CTRL8, 0xFF},
456a8e1d46SRyan Lee 	{MAX98388_R2058_PCM_RX_SRC1, 0x00},
466a8e1d46SRyan Lee 	{MAX98388_R2059_PCM_RX_SRC2, 0x01},
476a8e1d46SRyan Lee 	{MAX98388_R205C_PCM_TX_DRIVE_STRENGTH, 0x00},
486a8e1d46SRyan Lee 	{MAX98388_R205D_PCM_TX_SRC_EN, 0x00},
496a8e1d46SRyan Lee 	{MAX98388_R205E_PCM_RX_EN, 0x00},
506a8e1d46SRyan Lee 	{MAX98388_R205F_PCM_TX_EN, 0x00},
516a8e1d46SRyan Lee 	{MAX98388_R2090_SPK_CH_VOL_CTRL, 0x00},
526a8e1d46SRyan Lee 	{MAX98388_R2091_SPK_CH_CFG, 0x02},
536a8e1d46SRyan Lee 	{MAX98388_R2092_SPK_AMP_OUT_CFG, 0x03},
546a8e1d46SRyan Lee 	{MAX98388_R2093_SPK_AMP_SSM_CFG, 0x01},
556a8e1d46SRyan Lee 	{MAX98388_R2094_SPK_AMP_ER_CTRL, 0x00},
566a8e1d46SRyan Lee 	{MAX98388_R209E_SPK_CH_PINK_NOISE_EN, 0x00},
576a8e1d46SRyan Lee 	{MAX98388_R209F_SPK_CH_AMP_EN, 0x00},
586a8e1d46SRyan Lee 	{MAX98388_R20A0_IV_DATA_DSP_CTRL, 0x10},
596a8e1d46SRyan Lee 	{MAX98388_R20A7_IV_DATA_EN, 0x00},
606a8e1d46SRyan Lee 	{MAX98388_R20E0_BP_ALC_THRESH, 0x04},
616a8e1d46SRyan Lee 	{MAX98388_R20E1_BP_ALC_RATES, 0x20},
626a8e1d46SRyan Lee 	{MAX98388_R20E2_BP_ALC_ATTEN, 0x06},
636a8e1d46SRyan Lee 	{MAX98388_R20E3_BP_ALC_REL, 0x02},
646a8e1d46SRyan Lee 	{MAX98388_R20E4_BP_ALC_MUTE, 0x33},
656a8e1d46SRyan Lee 	{MAX98388_R20EE_BP_INF_HOLD_REL, 0x00},
666a8e1d46SRyan Lee 	{MAX98388_R20EF_BP_ALC_EN, 0x00},
676a8e1d46SRyan Lee 	{MAX98388_R210E_AUTO_RESTART, 0x00},
686a8e1d46SRyan Lee 	{MAX98388_R210F_GLOBAL_EN, 0x00},
696a8e1d46SRyan Lee 	{MAX98388_R22FF_REV_ID, 0x00},
706a8e1d46SRyan Lee };
716a8e1d46SRyan Lee 
max98388_dac_event(struct snd_soc_dapm_widget * w,struct snd_kcontrol * kcontrol,int event)726a8e1d46SRyan Lee static int max98388_dac_event(struct snd_soc_dapm_widget *w,
736a8e1d46SRyan Lee 			      struct snd_kcontrol *kcontrol, int event)
746a8e1d46SRyan Lee {
756a8e1d46SRyan Lee 	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
766a8e1d46SRyan Lee 	struct max98388_priv *max98388 = snd_soc_component_get_drvdata(component);
776a8e1d46SRyan Lee 
786a8e1d46SRyan Lee 	switch (event) {
796a8e1d46SRyan Lee 	case SND_SOC_DAPM_POST_PMU:
806a8e1d46SRyan Lee 		regmap_write(max98388->regmap,
816a8e1d46SRyan Lee 			     MAX98388_R210F_GLOBAL_EN, 1);
826a8e1d46SRyan Lee 		usleep_range(30000, 31000);
836a8e1d46SRyan Lee 		break;
846a8e1d46SRyan Lee 	case SND_SOC_DAPM_PRE_PMD:
856a8e1d46SRyan Lee 		regmap_write(max98388->regmap,
866a8e1d46SRyan Lee 			     MAX98388_R210F_GLOBAL_EN, 0);
876a8e1d46SRyan Lee 		usleep_range(30000, 31000);
886a8e1d46SRyan Lee 		max98388->tdm_mode = false;
896a8e1d46SRyan Lee 		break;
906a8e1d46SRyan Lee 	default:
916a8e1d46SRyan Lee 		return 0;
926a8e1d46SRyan Lee 	}
936a8e1d46SRyan Lee 	return 0;
946a8e1d46SRyan Lee }
956a8e1d46SRyan Lee 
966a8e1d46SRyan Lee static const char * const max98388_monomix_switch_text[] = {
976a8e1d46SRyan Lee 	"Left", "Right", "LeftRight"};
986a8e1d46SRyan Lee 
996a8e1d46SRyan Lee static const struct soc_enum dai_sel_enum =
1006a8e1d46SRyan Lee 	SOC_ENUM_SINGLE(MAX98388_R2058_PCM_RX_SRC1,
1016a8e1d46SRyan Lee 			MAX98388_PCM_TO_SPK_MONOMIX_CFG_SHIFT,
1026a8e1d46SRyan Lee 			3, max98388_monomix_switch_text);
1036a8e1d46SRyan Lee 
1046a8e1d46SRyan Lee static const struct snd_kcontrol_new max98388_dai_controls =
1056a8e1d46SRyan Lee 	SOC_DAPM_ENUM("DAI Sel", dai_sel_enum);
1066a8e1d46SRyan Lee 
1076a8e1d46SRyan Lee static const struct snd_kcontrol_new max98388_vi_control =
1086a8e1d46SRyan Lee 	SOC_DAPM_SINGLE("Switch", MAX98388_R205F_PCM_TX_EN, 0, 1, 0);
1096a8e1d46SRyan Lee 
1106a8e1d46SRyan Lee static const struct snd_soc_dapm_widget max98388_dapm_widgets[] = {
1116a8e1d46SRyan Lee 	SND_SOC_DAPM_DAC_E("Amp Enable", "HiFi Playback",
1126a8e1d46SRyan Lee 			   MAX98388_R205E_PCM_RX_EN, 0, 0, max98388_dac_event,
1136a8e1d46SRyan Lee 			   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
1146a8e1d46SRyan Lee 	SND_SOC_DAPM_MUX("DAI Sel Mux", SND_SOC_NOPM, 0, 0,
1156a8e1d46SRyan Lee 			 &max98388_dai_controls),
1166a8e1d46SRyan Lee 	SND_SOC_DAPM_OUTPUT("BE_OUT"),
1176a8e1d46SRyan Lee 	SND_SOC_DAPM_AIF_OUT("Voltage Sense", "HiFi Capture", 0,
1186a8e1d46SRyan Lee 			     MAX98388_R20A7_IV_DATA_EN, 0, 0),
1196a8e1d46SRyan Lee 	SND_SOC_DAPM_AIF_OUT("Current Sense", "HiFi Capture", 0,
1206a8e1d46SRyan Lee 			     MAX98388_R20A7_IV_DATA_EN, 1, 0),
1216a8e1d46SRyan Lee 	SND_SOC_DAPM_ADC("ADC Voltage", NULL,
1226a8e1d46SRyan Lee 			 MAX98388_R205D_PCM_TX_SRC_EN, 0, 0),
1236a8e1d46SRyan Lee 	SND_SOC_DAPM_ADC("ADC Current", NULL,
1246a8e1d46SRyan Lee 			 MAX98388_R205D_PCM_TX_SRC_EN, 1, 0),
1256a8e1d46SRyan Lee 	SND_SOC_DAPM_SWITCH("VI Sense", SND_SOC_NOPM, 0, 0,
1266a8e1d46SRyan Lee 			    &max98388_vi_control),
1276a8e1d46SRyan Lee 	SND_SOC_DAPM_SIGGEN("VMON"),
1286a8e1d46SRyan Lee 	SND_SOC_DAPM_SIGGEN("IMON"),
1296a8e1d46SRyan Lee };
1306a8e1d46SRyan Lee 
1316a8e1d46SRyan Lee static DECLARE_TLV_DB_SCALE(max98388_digital_tlv, -6350, 50, 1);
1326a8e1d46SRyan Lee static DECLARE_TLV_DB_SCALE(max98388_amp_gain_tlv, -300, 300, 0);
1336a8e1d46SRyan Lee 
1346a8e1d46SRyan Lee static const char * const max98388_alc_max_atten_text[] = {
1356a8e1d46SRyan Lee 	"0dBFS", "-1dBFS", "-2dBFS", "-3dBFS", "-4dBFS", "-5dBFS",
1366a8e1d46SRyan Lee 	"-6dBFS", "-7dBFS", "-8dBFS", "-9dBFS", "-10dBFS", "-11dBFS",
1376a8e1d46SRyan Lee 	"-12dBFS", "-13dBFS", "-14dBFS", "-15dBFS"
1386a8e1d46SRyan Lee };
1396a8e1d46SRyan Lee 
1406a8e1d46SRyan Lee static SOC_ENUM_SINGLE_DECL(max98388_alc_max_atten_enum,
1416a8e1d46SRyan Lee 			    MAX98388_R20E2_BP_ALC_ATTEN,
1426a8e1d46SRyan Lee 			    MAX98388_ALC_MAX_ATTEN_SHIFT,
1436a8e1d46SRyan Lee 			    max98388_alc_max_atten_text);
1446a8e1d46SRyan Lee 
1456a8e1d46SRyan Lee static const char * const max98388_thermal_warn_text[] = {
1466a8e1d46SRyan Lee 	"95C", "105C", "115C", "125C"
1476a8e1d46SRyan Lee };
1486a8e1d46SRyan Lee 
1496a8e1d46SRyan Lee static SOC_ENUM_SINGLE_DECL(max98388_thermal_warning_thresh_enum,
1506a8e1d46SRyan Lee 			    MAX98388_R2020_THERM_WARN_THRESH,
1516a8e1d46SRyan Lee 			    MAX98388_THERM_WARN_THRESH_SHIFT,
1526a8e1d46SRyan Lee 			    max98388_thermal_warn_text);
1536a8e1d46SRyan Lee 
1546a8e1d46SRyan Lee static const char * const max98388_thermal_shutdown_text[] = {
1556a8e1d46SRyan Lee 	"135C", "145C", "155C", "165C"
1566a8e1d46SRyan Lee };
1576a8e1d46SRyan Lee 
1586a8e1d46SRyan Lee static SOC_ENUM_SINGLE_DECL(max98388_thermal_shutdown_thresh_enum,
1596a8e1d46SRyan Lee 			    MAX98388_R2020_THERM_WARN_THRESH,
1606a8e1d46SRyan Lee 			    MAX98388_THERM_SHDN_THRESH_SHIFT,
1616a8e1d46SRyan Lee 			    max98388_thermal_shutdown_text);
1626a8e1d46SRyan Lee 
1636a8e1d46SRyan Lee static const char * const max98388_alc_thresh_single_text[] = {
1646a8e1d46SRyan Lee 	"3.625V", "3.550V", "3.475V", "3.400V", "3.325V", "3.250V",
1656a8e1d46SRyan Lee 	"3.175V", "3.100V", "3.025V", "2.950V", "2.875V", "2.800V",
1666a8e1d46SRyan Lee 	"2.725V", "2.650V", "2.575V", "2.500V"
1676a8e1d46SRyan Lee };
1686a8e1d46SRyan Lee 
1696a8e1d46SRyan Lee static SOC_ENUM_SINGLE_DECL(max98388_alc_thresh_single_enum,
1706a8e1d46SRyan Lee 			    MAX98388_R20E0_BP_ALC_THRESH,
1716a8e1d46SRyan Lee 			    MAX98388_ALC_THRESH_SHIFT,
1726a8e1d46SRyan Lee 			    max98388_alc_thresh_single_text);
1736a8e1d46SRyan Lee 
1746a8e1d46SRyan Lee static const char * const max98388_alc_attack_rate_text[] = {
1756a8e1d46SRyan Lee 	"0", "10us", "20us", "40us", "80us", "160us",
1766a8e1d46SRyan Lee 	"320us", "640us", "1.28ms", "2.56ms", "5.12ms", "10.24ms",
1776a8e1d46SRyan Lee 	"20.48ms", "40.96ms", "81.92ms", "163.84ms"
1786a8e1d46SRyan Lee };
1796a8e1d46SRyan Lee 
1806a8e1d46SRyan Lee static SOC_ENUM_SINGLE_DECL(max98388_alc_attack_rate_enum,
1816a8e1d46SRyan Lee 			    MAX98388_R20E1_BP_ALC_RATES,
1826a8e1d46SRyan Lee 			    MAX98388_ALC_ATTACK_RATE_SHIFT,
1836a8e1d46SRyan Lee 			    max98388_alc_attack_rate_text);
1846a8e1d46SRyan Lee 
1856a8e1d46SRyan Lee static const char * const max98388_alc_release_rate_text[] = {
1866a8e1d46SRyan Lee 	"20us", "40us", "80us", "160us", "320us", "640us",
1876a8e1d46SRyan Lee 	"1.28ms", "2.56ms", "5.12ms", "10.24ms", "20.48ms", "40.96ms",
1886a8e1d46SRyan Lee 	"81.92ms", "163.84ms", "327.68ms", "655.36ms"
1896a8e1d46SRyan Lee };
1906a8e1d46SRyan Lee 
1916a8e1d46SRyan Lee static SOC_ENUM_SINGLE_DECL(max98388_alc_release_rate_enum,
1926a8e1d46SRyan Lee 			    MAX98388_R20E1_BP_ALC_RATES,
1936a8e1d46SRyan Lee 			    MAX98388_ALC_RELEASE_RATE_SHIFT,
1946a8e1d46SRyan Lee 			    max98388_alc_release_rate_text);
1956a8e1d46SRyan Lee 
1966a8e1d46SRyan Lee static const char * const max98388_alc_debounce_text[] = {
1976a8e1d46SRyan Lee 	"0.01ms", "0.1ms", "1ms", "10ms", "100ms", "250ms", "500ms", "hold"
1986a8e1d46SRyan Lee };
1996a8e1d46SRyan Lee 
2006a8e1d46SRyan Lee static SOC_ENUM_SINGLE_DECL(max98388_alc_debouce_enum,
2016a8e1d46SRyan Lee 			    MAX98388_R20E3_BP_ALC_REL,
2026a8e1d46SRyan Lee 			    MAX98388_ALC_DEBOUNCE_TIME_SHIFT,
2036a8e1d46SRyan Lee 			    max98388_alc_debounce_text);
2046a8e1d46SRyan Lee 
2056a8e1d46SRyan Lee static const char * const max98388_alc_mute_delay_text[] = {
2066a8e1d46SRyan Lee 	"0.01ms", "0.05ms", "0.1ms", "0.5ms", "1ms", "5ms", "25ms", "250ms"
2076a8e1d46SRyan Lee };
2086a8e1d46SRyan Lee 
2096a8e1d46SRyan Lee static SOC_ENUM_SINGLE_DECL(max98388_alc_mute_delay_enum,
2106a8e1d46SRyan Lee 			    MAX98388_R20E4_BP_ALC_MUTE,
2116a8e1d46SRyan Lee 			    MAX98388_ALC_MUTE_DELAY_SHIFT,
2126a8e1d46SRyan Lee 			    max98388_alc_mute_delay_text);
2136a8e1d46SRyan Lee 
2146a8e1d46SRyan Lee static const char * const max98388_spkmon_duration_text[] = {
2156a8e1d46SRyan Lee 	"10ms", "25ms", "50ms", "75ms", "100ms", "200ms", "300ms", "400ms",
2166a8e1d46SRyan Lee 	"500ms", "600ms", "700ms", "800ms", "900ms", "1000ms", "1100ms", "1200ms"
2176a8e1d46SRyan Lee };
2186a8e1d46SRyan Lee 
2196a8e1d46SRyan Lee static SOC_ENUM_SINGLE_DECL(max98388_spkmon_duration_enum,
2206a8e1d46SRyan Lee 			    MAX98388_R2033_SPK_MON_DURATION,
2216a8e1d46SRyan Lee 			    MAX98388_SPKMON_DURATION_SHIFT,
2226a8e1d46SRyan Lee 			    max98388_spkmon_duration_text);
2236a8e1d46SRyan Lee 
2246a8e1d46SRyan Lee static const char * const max98388_spkmon_thresh_text[] = {
2256a8e1d46SRyan Lee 	"0.03V", "0.06V", "0.09V", "0.12V", "0.15V", "0.18V", "0.20V", "0.23V",
2266a8e1d46SRyan Lee 	"0.26V", "0.29V", "0.32V", "0.35V", "0.38V", "0.41V", "0.44V", "0.47V",
2276a8e1d46SRyan Lee 	"0.50V", "0.53V", "0.56V", "0.58V", "0.61V", "0.64V", "0.67V", "0.70V",
2286a8e1d46SRyan Lee 	"0.73V", "0.76V", "0.79V", "0.82V", "0.85V", "0.88V", "0.91V", "0.94V",
2296a8e1d46SRyan Lee 	"0.96V", "0.99V", "1.02V", "1.05V", "1.08V", "1.11V", "1.14V", "1.17V",
2306a8e1d46SRyan Lee 	"1.20V", "1.23V", "1.26V", "1.29V", "1.32V", "1.35V", "1.37V", "1.40V",
2316a8e1d46SRyan Lee 	"1.43V", "1.46V", "1.49V", "1.52V", "1.55V", "1.58V", "1.61V", "1.64V",
2326a8e1d46SRyan Lee 	"1.67V", "1.70V", "1.73V", "1.75V", "1.78V", "1.81V", "1.84V", "1.87V",
2336a8e1d46SRyan Lee 	"1.90V", "1.93V", "1.96V", "1.99V", "2.02V", "2.05V", "2.08V", "2.11V",
2346a8e1d46SRyan Lee 	"2.13V", "2.16V", "2.19V", "2.22V", "2.25V", "2.28V", "2.31V", "2.34V",
2356a8e1d46SRyan Lee 	"2.37V", "2.40V", "2.43V", "2.46V", "2.49V", "2.51V", "2.54V", "2.57V",
2366a8e1d46SRyan Lee 	"2.60V", "2.63V", "2.66V", "2.69V", "2.72V", "2.75V", "2.78V", "2.81V",
2376a8e1d46SRyan Lee 	"2.84V", "2.87V", "2.89V", "2.92V", "2.95V", "2.98V", "3.01V", "3.04V",
2386a8e1d46SRyan Lee 	"3.07V", "3.10V", "3.13V", "3.16V", "3.19V", "3.22V", "3.25V", "3.27V",
2396a8e1d46SRyan Lee 	"3.30V", "3.33V", "3.36V", "3.39V", "3.42V", "3.45V", "3.48V", "3.51V",
2406a8e1d46SRyan Lee 	"3.54V", "3.57V", "3.60V", "3.63V", "3.66V", "3.68V", "3.71V", "3.74V"
2416a8e1d46SRyan Lee };
2426a8e1d46SRyan Lee 
2436a8e1d46SRyan Lee static SOC_ENUM_SINGLE_DECL(max98388_spkmon_thresh_enum,
2446a8e1d46SRyan Lee 			    MAX98388_R2031_SPK_MON_THRESH,
2456a8e1d46SRyan Lee 			    MAX98388_SPKMON_THRESH_SHIFT,
2466a8e1d46SRyan Lee 			    max98388_spkmon_thresh_text);
2476a8e1d46SRyan Lee 
2486a8e1d46SRyan Lee static const char * const max98388_spkmon_load_text[] = {
2496a8e1d46SRyan Lee 	"2.00ohm", "2.25ohm", "2.50ohm", "2.75ohm", "3.00ohm", "3.25ohm",
2506a8e1d46SRyan Lee 	"3.50ohm", "3.75ohm", "4.00ohm", "4.25ohm", "4.50ohm", "4.75ohm",
2516a8e1d46SRyan Lee 	"5.00ohm", "5.25ohm", "5.50ohm", "5.75ohm", "6.00ohm", "6.25ohm",
2526a8e1d46SRyan Lee 	"6.50ohm", "6.75ohm", "7.00ohm", "7.25ohm", "7.50ohm", "7.75ohm",
2536a8e1d46SRyan Lee 	"8.00ohm", "8.25ohm", "8.50ohm", "8.75ohm", "9.00ohm", "9.25ohm",
2546a8e1d46SRyan Lee 	"9.50ohm", "9.75ohm", "10.00ohm", "10.25ohm", "10.50ohm", "10.75ohm",
2556a8e1d46SRyan Lee 	"11.00ohm", "11.25ohm", "11.50ohm", "11.75ohm",	"12.00ohm", "12.25ohm",
2566a8e1d46SRyan Lee 	"12.50ohm", "12.75ohm", "13.00ohm", "13.25ohm", "13.50ohm", "13.75ohm",
2576a8e1d46SRyan Lee 	"14.00ohm", "14.25ohm", "14.50ohm", "14.75ohm", "15.00ohm", "15.25ohm",
2586a8e1d46SRyan Lee 	"15.50ohm", "15.75ohm", "16.00ohm", "16.25ohm", "16.50ohm", "16.75ohm",
2596a8e1d46SRyan Lee 	"17.00ohm", "17.25ohm", "17.50ohm", "17.75ohm", "18.00ohm", "18.25ohm",
2606a8e1d46SRyan Lee 	"18.50ohm", "18.75ohm", "19.00ohm", "19.25ohm", "19.50ohm", "19.75ohm",
2616a8e1d46SRyan Lee 	"20.00ohm", "20.25ohm", "20.50ohm", "20.75ohm", "21.00ohm", "21.25ohm",
2626a8e1d46SRyan Lee 	"21.50ohm", "21.75ohm",	"22.00ohm", "22.25ohm", "22.50ohm", "22.75ohm",
2636a8e1d46SRyan Lee 	"23.00ohm", "23.25ohm", "23.50ohm", "23.75ohm",	"24.00ohm", "24.25ohm",
2646a8e1d46SRyan Lee 	"24.50ohm", "24.75ohm", "25.00ohm", "25.25ohm", "25.50ohm", "25.75ohm",
2656a8e1d46SRyan Lee 	"26.00ohm", "26.25ohm", "26.50ohm", "26.75ohm", "27.00ohm", "27.25ohm",
2666a8e1d46SRyan Lee 	"27.50ohm", "27.75ohm",	"28.00ohm", "28.25ohm", "28.50ohm", "28.75ohm",
2676a8e1d46SRyan Lee 	"29.00ohm", "29.25ohm", "29.50ohm", "29.75ohm",	"30.00ohm", "30.25ohm",
2686a8e1d46SRyan Lee 	"30.50ohm", "30.75ohm", "31.00ohm", "31.25ohm", "31.50ohm", "31.75ohm",
2696a8e1d46SRyan Lee 	"32.00ohm", "32.25ohm", "32.50ohm", "32.75ohm", "33.00ohm", "33.25ohm",
2706a8e1d46SRyan Lee 	"33.50ohm", "33.75ohm"
2716a8e1d46SRyan Lee };
2726a8e1d46SRyan Lee 
2736a8e1d46SRyan Lee static SOC_ENUM_SINGLE_DECL(max98388_spkmon_load_enum,
2746a8e1d46SRyan Lee 			    MAX98388_R2032_SPK_MON_LD_SEL,
2756a8e1d46SRyan Lee 			    MAX98388_SPKMON_LOAD_SHIFT,
2766a8e1d46SRyan Lee 			    max98388_spkmon_load_text);
2776a8e1d46SRyan Lee 
2786a8e1d46SRyan Lee static const char * const max98388_edge_rate_text[] = {
2796a8e1d46SRyan Lee 	"Normal", "Reduced", "Maximum", "Increased",
2806a8e1d46SRyan Lee };
2816a8e1d46SRyan Lee 
2826a8e1d46SRyan Lee static SOC_ENUM_SINGLE_DECL(max98388_edge_rate_falling_enum,
2836a8e1d46SRyan Lee 			    MAX98388_R2094_SPK_AMP_ER_CTRL,
2846a8e1d46SRyan Lee 			    MAX98388_EDGE_RATE_FALL_SHIFT,
2856a8e1d46SRyan Lee 			    max98388_edge_rate_text);
2866a8e1d46SRyan Lee 
2876a8e1d46SRyan Lee static SOC_ENUM_SINGLE_DECL(max98388_edge_rate_rising_enum,
2886a8e1d46SRyan Lee 			    MAX98388_R2094_SPK_AMP_ER_CTRL,
2896a8e1d46SRyan Lee 			    MAX98388_EDGE_RATE_RISE_SHIFT,
2906a8e1d46SRyan Lee 			    max98388_edge_rate_text);
2916a8e1d46SRyan Lee 
2926a8e1d46SRyan Lee static const char * const max98388_ssm_mod_text[] = {
2936a8e1d46SRyan Lee 	"1.5%", "3.0%", "4.5%", "6.0%",
2946a8e1d46SRyan Lee };
2956a8e1d46SRyan Lee 
2966a8e1d46SRyan Lee static SOC_ENUM_SINGLE_DECL(max98388_ssm_mod_enum,
2976a8e1d46SRyan Lee 			    MAX98388_R2093_SPK_AMP_SSM_CFG,
2986a8e1d46SRyan Lee 			    MAX98388_SPK_AMP_SSM_MOD_SHIFT,
2996a8e1d46SRyan Lee 			    max98388_ssm_mod_text);
3006a8e1d46SRyan Lee 
3016a8e1d46SRyan Lee static const struct snd_kcontrol_new max98388_snd_controls[] = {
3026a8e1d46SRyan Lee 	SOC_SINGLE("Ramp Up Switch", MAX98388_R2091_SPK_CH_CFG,
3036a8e1d46SRyan Lee 		   MAX98388_SPK_CFG_VOL_RMPUP_SHIFT, 1, 0),
3046a8e1d46SRyan Lee 	SOC_SINGLE("Ramp Down Switch", MAX98388_R2091_SPK_CH_CFG,
3056a8e1d46SRyan Lee 		   MAX98388_SPK_CFG_VOL_RMPDN_SHIFT, 1, 0),
3066a8e1d46SRyan Lee 	/* Two Cell Mode Enable */
3076a8e1d46SRyan Lee 	SOC_SINGLE("OP Mode Switch", MAX98388_R2092_SPK_AMP_OUT_CFG,
3086a8e1d46SRyan Lee 		   MAX98388_SPK_AMP_OUT_MODE_SHIFT, 1, 0),
3096a8e1d46SRyan Lee 	/* Speaker Amplifier Overcurrent Automatic Restart Enable */
3106a8e1d46SRyan Lee 	SOC_SINGLE("OVC Autorestart Switch", MAX98388_R210E_AUTO_RESTART,
3116a8e1d46SRyan Lee 		   MAX98388_OVC_AUTORESTART_SHIFT, 1, 0),
3126a8e1d46SRyan Lee 	/* Thermal Shutdown Automatic Restart Enable */
3136a8e1d46SRyan Lee 	SOC_SINGLE("THERM Autorestart Switch", MAX98388_R210E_AUTO_RESTART,
3146a8e1d46SRyan Lee 		   MAX98388_THERM_AUTORESTART_SHIFT, 1, 0),
3156a8e1d46SRyan Lee 	/* PVDD UVLO Auto Restart */
3166a8e1d46SRyan Lee 	SOC_SINGLE("UVLO Autorestart Switch", MAX98388_R210E_AUTO_RESTART,
3176a8e1d46SRyan Lee 		   MAX98388_PVDD_UVLO_AUTORESTART_SHIFT, 1, 0),
3186a8e1d46SRyan Lee 	/* Clock Monitor Automatic Restart Enable */
3196a8e1d46SRyan Lee 	SOC_SINGLE("CMON Autorestart Switch", MAX98388_R210E_AUTO_RESTART,
3206a8e1d46SRyan Lee 		   MAX98388_CMON_AUTORESTART_SHIFT, 1, 0),
3216a8e1d46SRyan Lee 	SOC_SINGLE("CLK Monitor Switch", MAX98388_R2037_ERR_MON_CTRL,
3226a8e1d46SRyan Lee 		   MAX98388_CLOCK_MON_SHIFT, 1, 0),
3236a8e1d46SRyan Lee 	/* Pinknoise Generator Enable */
3246a8e1d46SRyan Lee 	SOC_SINGLE("Pinknoise Gen Switch", MAX98388_R209E_SPK_CH_PINK_NOISE_EN,
3256a8e1d46SRyan Lee 		   MAX98388_PINK_NOISE_GEN_SHIFT, 1, 0),
3266a8e1d46SRyan Lee 	/* Dither Enable */
3276a8e1d46SRyan Lee 	SOC_SINGLE("Dither Switch", MAX98388_R2091_SPK_CH_CFG,
3286a8e1d46SRyan Lee 		   MAX98388_SPK_CFG_DITH_EN_SHIFT, 1, 0),
3296a8e1d46SRyan Lee 	SOC_SINGLE("VI Dither Switch", MAX98388_R20A0_IV_DATA_DSP_CTRL,
3306a8e1d46SRyan Lee 		   MAX98388_AMP_DSP_CTRL_DITH_SHIFT, 1, 0),
3316a8e1d46SRyan Lee 	/* DC Blocker Enable */
3326a8e1d46SRyan Lee 	SOC_SINGLE("DC Blocker Switch", MAX98388_R2091_SPK_CH_CFG,
3336a8e1d46SRyan Lee 		   MAX98388_SPK_CFG_DCBLK_SHIFT, 1, 0),
3346a8e1d46SRyan Lee 	SOC_SINGLE("Voltage DC Blocker Switch", MAX98388_R20A0_IV_DATA_DSP_CTRL,
3356a8e1d46SRyan Lee 		   MAX98388_AMP_DSP_CTRL_VOL_DCBLK_SHIFT, 1, 0),
3366a8e1d46SRyan Lee 	SOC_SINGLE("Current DC Blocker Switch", MAX98388_R20A0_IV_DATA_DSP_CTRL,
3376a8e1d46SRyan Lee 		   MAX98388_AMP_DSP_CTRL_CUR_DCBLK_SHIFT, 1, 0),
3386a8e1d46SRyan Lee 	/* Digital Volume */
3396a8e1d46SRyan Lee 	SOC_SINGLE_TLV("Digital Volume", MAX98388_R2090_SPK_CH_VOL_CTRL,
3406a8e1d46SRyan Lee 		       0, 0x7F, 1, max98388_digital_tlv),
3416a8e1d46SRyan Lee 	/* Speaker Volume */
3426a8e1d46SRyan Lee 	SOC_SINGLE_TLV("Speaker Volume", MAX98388_R2092_SPK_AMP_OUT_CFG,
3436a8e1d46SRyan Lee 		       0, 5, 0, max98388_amp_gain_tlv),
3446a8e1d46SRyan Lee 	SOC_ENUM("Thermal Warn Thresh", max98388_thermal_warning_thresh_enum),
3456a8e1d46SRyan Lee 	SOC_ENUM("Thermal SHDN Thresh", max98388_thermal_shutdown_thresh_enum),
3466a8e1d46SRyan Lee 	/* Brownout Protection Automatic Level Control */
3476a8e1d46SRyan Lee 	SOC_SINGLE("ALC Switch", MAX98388_R20EF_BP_ALC_EN, 0, 1, 0),
3486a8e1d46SRyan Lee 	SOC_ENUM("ALC Thresh", max98388_alc_thresh_single_enum),
3496a8e1d46SRyan Lee 	SOC_ENUM("ALC Attack Rate", max98388_alc_attack_rate_enum),
3506a8e1d46SRyan Lee 	SOC_ENUM("ALC Release Rate", max98388_alc_release_rate_enum),
3516a8e1d46SRyan Lee 	SOC_ENUM("ALC Max Atten", max98388_alc_max_atten_enum),
3526a8e1d46SRyan Lee 	SOC_ENUM("ALC Debounce Time", max98388_alc_debouce_enum),
3536a8e1d46SRyan Lee 	SOC_SINGLE("ALC Unmute Ramp Switch", MAX98388_R20E4_BP_ALC_MUTE,
3546a8e1d46SRyan Lee 		   MAX98388_ALC_UNMUTE_RAMP_EN_SHIFT, 1, 0),
3556a8e1d46SRyan Lee 	SOC_SINGLE("ALC Mute Ramp Switch", MAX98388_R20E4_BP_ALC_MUTE,
3566a8e1d46SRyan Lee 		   MAX98388_ALC_MUTE_RAMP_EN_SHIFT, 1, 0),
3576a8e1d46SRyan Lee 	SOC_SINGLE("ALC Mute Switch", MAX98388_R20E4_BP_ALC_MUTE,
3586a8e1d46SRyan Lee 		   MAX98388_ALC_MUTE_EN_SHIFT, 1, 0),
3596a8e1d46SRyan Lee 	SOC_ENUM("ALC Mute Delay", max98388_alc_mute_delay_enum),
3606a8e1d46SRyan Lee 	/* Speaker Monitor */
3616a8e1d46SRyan Lee 	SOC_SINGLE("SPKMON Switch", MAX98388_R2037_ERR_MON_CTRL,
3626a8e1d46SRyan Lee 		   MAX98388_SPK_MON_SHIFT, 1, 0),
3636a8e1d46SRyan Lee 	SOC_ENUM("SPKMON Thresh", max98388_spkmon_thresh_enum),
3646a8e1d46SRyan Lee 	SOC_ENUM("SPKMON Load", max98388_spkmon_load_enum),
3656a8e1d46SRyan Lee 	SOC_ENUM("SPKMON Duration", max98388_spkmon_duration_enum),
3666a8e1d46SRyan Lee 	/* General Parameters */
3676a8e1d46SRyan Lee 	SOC_ENUM("Fall Slew Rate", max98388_edge_rate_falling_enum),
3686a8e1d46SRyan Lee 	SOC_ENUM("Rise Slew Rate", max98388_edge_rate_rising_enum),
3696a8e1d46SRyan Lee 	SOC_SINGLE("AMP SSM Switch", MAX98388_R2093_SPK_AMP_SSM_CFG,
3706a8e1d46SRyan Lee 		   MAX98388_SPK_AMP_SSM_EN_SHIFT, 1, 0),
3716a8e1d46SRyan Lee 	SOC_ENUM("AMP SSM Mod", max98388_ssm_mod_enum),
3726a8e1d46SRyan Lee };
3736a8e1d46SRyan Lee 
3746a8e1d46SRyan Lee static const struct snd_soc_dapm_route max98388_audio_map[] = {
3756a8e1d46SRyan Lee 	/* Plabyack */
3766a8e1d46SRyan Lee 	{"DAI Sel Mux", "Left", "Amp Enable"},
3776a8e1d46SRyan Lee 	{"DAI Sel Mux", "Right", "Amp Enable"},
3786a8e1d46SRyan Lee 	{"DAI Sel Mux", "LeftRight", "Amp Enable"},
3796a8e1d46SRyan Lee 	{"BE_OUT", NULL, "DAI Sel Mux"},
3806a8e1d46SRyan Lee 	/* Capture */
3816a8e1d46SRyan Lee 	{ "ADC Voltage", NULL, "VMON"},
3826a8e1d46SRyan Lee 	{ "ADC Current", NULL, "IMON"},
3836a8e1d46SRyan Lee 	{ "VI Sense", "Switch", "ADC Voltage"},
3846a8e1d46SRyan Lee 	{ "VI Sense", "Switch", "ADC Current"},
3856a8e1d46SRyan Lee 	{ "Voltage Sense", NULL, "VI Sense"},
3866a8e1d46SRyan Lee 	{ "Current Sense", NULL, "VI Sense"},
3876a8e1d46SRyan Lee };
3886a8e1d46SRyan Lee 
max98388_reset(struct max98388_priv * max98388,struct device * dev)3896a8e1d46SRyan Lee static void max98388_reset(struct max98388_priv *max98388, struct device *dev)
3906a8e1d46SRyan Lee {
3916a8e1d46SRyan Lee 	int ret, reg, count;
3926a8e1d46SRyan Lee 
3936a8e1d46SRyan Lee 	/* Software Reset */
3946a8e1d46SRyan Lee 	ret = regmap_update_bits(max98388->regmap,
3956a8e1d46SRyan Lee 				 MAX98388_R2000_SW_RESET,
3966a8e1d46SRyan Lee 				 MAX98388_SOFT_RESET,
3976a8e1d46SRyan Lee 				 MAX98388_SOFT_RESET);
3986a8e1d46SRyan Lee 	if (ret)
3996a8e1d46SRyan Lee 		dev_err(dev, "Reset command failed. (ret:%d)\n", ret);
4006a8e1d46SRyan Lee 
4016a8e1d46SRyan Lee 	count = 0;
4026a8e1d46SRyan Lee 	while (count < 3) {
4036a8e1d46SRyan Lee 		usleep_range(10000, 11000);
4046a8e1d46SRyan Lee 		/* Software Reset Verification */
4056a8e1d46SRyan Lee 		ret = regmap_read(max98388->regmap,
4066a8e1d46SRyan Lee 				  MAX98388_R22FF_REV_ID, &reg);
4076a8e1d46SRyan Lee 		if (!ret) {
4086a8e1d46SRyan Lee 			dev_info(dev, "Reset completed (retry:%d)\n", count);
4096a8e1d46SRyan Lee 			return;
4106a8e1d46SRyan Lee 		}
4116a8e1d46SRyan Lee 		count++;
4126a8e1d46SRyan Lee 	}
4136a8e1d46SRyan Lee 	dev_err(dev, "Reset failed. (ret:%d)\n", ret);
4146a8e1d46SRyan Lee }
4156a8e1d46SRyan Lee 
max98388_probe(struct snd_soc_component * component)4166a8e1d46SRyan Lee static int max98388_probe(struct snd_soc_component *component)
4176a8e1d46SRyan Lee {
4186a8e1d46SRyan Lee 	struct max98388_priv *max98388 = snd_soc_component_get_drvdata(component);
4196a8e1d46SRyan Lee 
4206a8e1d46SRyan Lee 	/* Software Reset */
4216a8e1d46SRyan Lee 	max98388_reset(max98388, component->dev);
4226a8e1d46SRyan Lee 
4236a8e1d46SRyan Lee 	/* General channel source configuration */
4246a8e1d46SRyan Lee 	regmap_write(max98388->regmap,
4256a8e1d46SRyan Lee 		     MAX98388_R2059_PCM_RX_SRC2,
4266a8e1d46SRyan Lee 		     0x10);
4276a8e1d46SRyan Lee 
4286a8e1d46SRyan Lee 	/* Enable DC blocker */
4296a8e1d46SRyan Lee 	regmap_write(max98388->regmap,
4306a8e1d46SRyan Lee 		     MAX98388_R2091_SPK_CH_CFG,
4316a8e1d46SRyan Lee 		     0x1);
4326a8e1d46SRyan Lee 	/* Enable IMON VMON DC blocker */
4336a8e1d46SRyan Lee 	regmap_write(max98388->regmap,
4346a8e1d46SRyan Lee 		     MAX98388_R20A0_IV_DATA_DSP_CTRL,
4356a8e1d46SRyan Lee 		     0x3);
4366a8e1d46SRyan Lee 	/* TX slot configuration */
4376a8e1d46SRyan Lee 	regmap_write(max98388->regmap,
4386a8e1d46SRyan Lee 		     MAX98388_R2044_PCM_TX_CTRL1,
4396a8e1d46SRyan Lee 		     max98388->v_slot);
4406a8e1d46SRyan Lee 
4416a8e1d46SRyan Lee 	regmap_write(max98388->regmap,
4426a8e1d46SRyan Lee 		     MAX98388_R2045_PCM_TX_CTRL2,
4436a8e1d46SRyan Lee 		     max98388->i_slot);
4446a8e1d46SRyan Lee 	/* Enable Auto-restart behavior by default */
4456a8e1d46SRyan Lee 	regmap_write(max98388->regmap,
4466a8e1d46SRyan Lee 		     MAX98388_R210E_AUTO_RESTART, 0xF);
4476a8e1d46SRyan Lee 	/* Set interleave mode */
4486a8e1d46SRyan Lee 	if (max98388->interleave_mode)
4496a8e1d46SRyan Lee 		regmap_update_bits(max98388->regmap,
4506a8e1d46SRyan Lee 				   MAX98388_R2040_PCM_MODE_CFG,
4516a8e1d46SRyan Lee 				   MAX98388_PCM_TX_CH_INTERLEAVE_MASK,
4526a8e1d46SRyan Lee 				   MAX98388_PCM_TX_CH_INTERLEAVE_MASK);
4536a8e1d46SRyan Lee 
4546a8e1d46SRyan Lee 	/* Speaker Amplifier Channel Enable */
4556a8e1d46SRyan Lee 	regmap_update_bits(max98388->regmap,
4566a8e1d46SRyan Lee 			   MAX98388_R209F_SPK_CH_AMP_EN,
4576a8e1d46SRyan Lee 			   MAX98388_SPK_EN_MASK, 1);
4586a8e1d46SRyan Lee 
4596a8e1d46SRyan Lee 	return 0;
4606a8e1d46SRyan Lee }
4616a8e1d46SRyan Lee 
max98388_dai_set_fmt(struct snd_soc_dai * codec_dai,unsigned int fmt)4626a8e1d46SRyan Lee static int max98388_dai_set_fmt(struct snd_soc_dai *codec_dai,
4636a8e1d46SRyan Lee 				unsigned int fmt)
4646a8e1d46SRyan Lee {
4656a8e1d46SRyan Lee 	struct snd_soc_component *component = codec_dai->component;
4666a8e1d46SRyan Lee 	struct max98388_priv *max98388 = snd_soc_component_get_drvdata(component);
4676a8e1d46SRyan Lee 	unsigned int format = 0;
4686a8e1d46SRyan Lee 	unsigned int invert = 0;
4696a8e1d46SRyan Lee 
4706a8e1d46SRyan Lee 	dev_dbg(component->dev, "%s: fmt 0x%08X\n", __func__, fmt);
4716a8e1d46SRyan Lee 
4726a8e1d46SRyan Lee 	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
4736a8e1d46SRyan Lee 	case SND_SOC_DAIFMT_NB_NF:
4746a8e1d46SRyan Lee 		break;
4756a8e1d46SRyan Lee 	case SND_SOC_DAIFMT_IB_NF:
4766a8e1d46SRyan Lee 		invert = MAX98388_PCM_MODE_CFG_PCM_BCLKEDGE;
4776a8e1d46SRyan Lee 		break;
4786a8e1d46SRyan Lee 	default:
4796a8e1d46SRyan Lee 		dev_err(component->dev, "DAI invert mode unsupported\n");
4806a8e1d46SRyan Lee 		return -EINVAL;
4816a8e1d46SRyan Lee 	}
4826a8e1d46SRyan Lee 
4836a8e1d46SRyan Lee 	regmap_update_bits(max98388->regmap,
4846a8e1d46SRyan Lee 			   MAX98388_R2041_PCM_CLK_SETUP,
4856a8e1d46SRyan Lee 			   MAX98388_PCM_MODE_CFG_PCM_BCLKEDGE,
4866a8e1d46SRyan Lee 			   invert);
4876a8e1d46SRyan Lee 
4886a8e1d46SRyan Lee 	/* interface format */
4896a8e1d46SRyan Lee 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
4906a8e1d46SRyan Lee 	case SND_SOC_DAIFMT_I2S:
4916a8e1d46SRyan Lee 		format = MAX98388_PCM_FORMAT_I2S;
4926a8e1d46SRyan Lee 		break;
4936a8e1d46SRyan Lee 	case SND_SOC_DAIFMT_LEFT_J:
4946a8e1d46SRyan Lee 		format = MAX98388_PCM_FORMAT_LJ;
4956a8e1d46SRyan Lee 		break;
4966a8e1d46SRyan Lee 	case SND_SOC_DAIFMT_DSP_A:
4976a8e1d46SRyan Lee 		format = MAX98388_PCM_FORMAT_TDM_MODE1;
4986a8e1d46SRyan Lee 		break;
4996a8e1d46SRyan Lee 	case SND_SOC_DAIFMT_DSP_B:
5006a8e1d46SRyan Lee 		format = MAX98388_PCM_FORMAT_TDM_MODE0;
5016a8e1d46SRyan Lee 		break;
5026a8e1d46SRyan Lee 	default:
5036a8e1d46SRyan Lee 		return -EINVAL;
5046a8e1d46SRyan Lee 	}
5056a8e1d46SRyan Lee 
5066a8e1d46SRyan Lee 	regmap_update_bits(max98388->regmap,
5076a8e1d46SRyan Lee 			   MAX98388_R2040_PCM_MODE_CFG,
5086a8e1d46SRyan Lee 			   MAX98388_PCM_MODE_CFG_FORMAT_MASK,
5096a8e1d46SRyan Lee 			   format << MAX98388_PCM_MODE_CFG_FORMAT_SHIFT);
5106a8e1d46SRyan Lee 
5116a8e1d46SRyan Lee 	return 0;
5126a8e1d46SRyan Lee }
5136a8e1d46SRyan Lee 
5146a8e1d46SRyan Lee /* BCLKs per LRCLK */
5156a8e1d46SRyan Lee static const int bclk_sel_table[] = {
5166a8e1d46SRyan Lee 	32, 48, 64, 96, 128, 192, 256, 384, 512, 320,
5176a8e1d46SRyan Lee };
5186a8e1d46SRyan Lee 
max98388_get_bclk_sel(int bclk)5196a8e1d46SRyan Lee static int max98388_get_bclk_sel(int bclk)
5206a8e1d46SRyan Lee {
5216a8e1d46SRyan Lee 	int i;
5226a8e1d46SRyan Lee 	/* match BCLKs per LRCLK */
5236a8e1d46SRyan Lee 	for (i = 0; i < ARRAY_SIZE(bclk_sel_table); i++) {
5246a8e1d46SRyan Lee 		if (bclk_sel_table[i] == bclk)
5256a8e1d46SRyan Lee 			return i + 2;
5266a8e1d46SRyan Lee 	}
5276a8e1d46SRyan Lee 	return 0;
5286a8e1d46SRyan Lee }
5296a8e1d46SRyan Lee 
max98388_set_clock(struct snd_soc_component * component,struct snd_pcm_hw_params * params)5306a8e1d46SRyan Lee static int max98388_set_clock(struct snd_soc_component *component,
5316a8e1d46SRyan Lee 			      struct snd_pcm_hw_params *params)
5326a8e1d46SRyan Lee {
5336a8e1d46SRyan Lee 	struct max98388_priv *max98388 = snd_soc_component_get_drvdata(component);
5346a8e1d46SRyan Lee 	/* BCLK/LRCLK ratio calculation */
5356a8e1d46SRyan Lee 	int blr_clk_ratio = params_channels(params) * max98388->ch_size;
5366a8e1d46SRyan Lee 	int value;
5376a8e1d46SRyan Lee 
5386a8e1d46SRyan Lee 	if (!max98388->tdm_mode) {
5396a8e1d46SRyan Lee 		/* BCLK configuration */
5406a8e1d46SRyan Lee 		value = max98388_get_bclk_sel(blr_clk_ratio);
5416a8e1d46SRyan Lee 		if (!value) {
5426a8e1d46SRyan Lee 			dev_err(component->dev, "format unsupported %d\n",
5436a8e1d46SRyan Lee 				params_format(params));
5446a8e1d46SRyan Lee 			return -EINVAL;
5456a8e1d46SRyan Lee 		}
5466a8e1d46SRyan Lee 
5476a8e1d46SRyan Lee 		regmap_update_bits(max98388->regmap,
5486a8e1d46SRyan Lee 				   MAX98388_R2041_PCM_CLK_SETUP,
5496a8e1d46SRyan Lee 				   MAX98388_PCM_CLK_SETUP_BSEL_MASK,
5506a8e1d46SRyan Lee 				   value);
5516a8e1d46SRyan Lee 	}
5526a8e1d46SRyan Lee 	return 0;
5536a8e1d46SRyan Lee }
5546a8e1d46SRyan Lee 
max98388_dai_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params,struct snd_soc_dai * dai)5556a8e1d46SRyan Lee static int max98388_dai_hw_params(struct snd_pcm_substream *substream,
5566a8e1d46SRyan Lee 				  struct snd_pcm_hw_params *params,
5576a8e1d46SRyan Lee 				  struct snd_soc_dai *dai)
5586a8e1d46SRyan Lee {
5596a8e1d46SRyan Lee 	struct snd_soc_component *component = dai->component;
5606a8e1d46SRyan Lee 	struct max98388_priv *max98388 = snd_soc_component_get_drvdata(component);
5616a8e1d46SRyan Lee 	unsigned int sampling_rate = 0;
5626a8e1d46SRyan Lee 	unsigned int chan_sz = 0;
5636a8e1d46SRyan Lee 	int ret, reg;
5646a8e1d46SRyan Lee 	int status = 0;
5656a8e1d46SRyan Lee 
5666a8e1d46SRyan Lee 	/* pcm mode configuration */
5676a8e1d46SRyan Lee 	switch (snd_pcm_format_width(params_format(params))) {
5686a8e1d46SRyan Lee 	case 16:
5696a8e1d46SRyan Lee 		chan_sz = MAX98388_PCM_MODE_CFG_CHANSZ_16;
5706a8e1d46SRyan Lee 		break;
5716a8e1d46SRyan Lee 	case 24:
5726a8e1d46SRyan Lee 		chan_sz = MAX98388_PCM_MODE_CFG_CHANSZ_24;
5736a8e1d46SRyan Lee 		break;
5746a8e1d46SRyan Lee 	case 32:
5756a8e1d46SRyan Lee 		chan_sz = MAX98388_PCM_MODE_CFG_CHANSZ_32;
5766a8e1d46SRyan Lee 		break;
5776a8e1d46SRyan Lee 	default:
5786a8e1d46SRyan Lee 		dev_err(component->dev, "format unsupported %d\n",
5796a8e1d46SRyan Lee 			params_format(params));
5806a8e1d46SRyan Lee 		goto err;
5816a8e1d46SRyan Lee 	}
5826a8e1d46SRyan Lee 
5836a8e1d46SRyan Lee 	max98388->ch_size = snd_pcm_format_width(params_format(params));
5846a8e1d46SRyan Lee 
5856a8e1d46SRyan Lee 	ret = regmap_read(max98388->regmap,
5866a8e1d46SRyan Lee 			  MAX98388_R2040_PCM_MODE_CFG, &reg);
5876a8e1d46SRyan Lee 	if (ret < 0)
5886a8e1d46SRyan Lee 		goto err;
5896a8e1d46SRyan Lee 
5906a8e1d46SRyan Lee 	/* GLOBAL_EN OFF prior to the channel size re-configure */
5916a8e1d46SRyan Lee 	if (chan_sz != (reg & MAX98388_PCM_MODE_CFG_CHANSZ_MASK))	{
5926a8e1d46SRyan Lee 		ret = regmap_read(max98388->regmap,
5936a8e1d46SRyan Lee 				  MAX98388_R210F_GLOBAL_EN, &status);
5946a8e1d46SRyan Lee 		if (ret < 0)
5956a8e1d46SRyan Lee 			goto err;
5966a8e1d46SRyan Lee 
5976a8e1d46SRyan Lee 		if (status) {
5986a8e1d46SRyan Lee 			regmap_write(max98388->regmap,
5996a8e1d46SRyan Lee 				     MAX98388_R210F_GLOBAL_EN, 0);
6006a8e1d46SRyan Lee 			usleep_range(30000, 31000);
6016a8e1d46SRyan Lee 		}
6026a8e1d46SRyan Lee 		regmap_update_bits(max98388->regmap,
6036a8e1d46SRyan Lee 				   MAX98388_R2040_PCM_MODE_CFG,
6046a8e1d46SRyan Lee 				   MAX98388_PCM_MODE_CFG_CHANSZ_MASK, chan_sz);
6056a8e1d46SRyan Lee 	}
6066a8e1d46SRyan Lee 	dev_dbg(component->dev, "format supported %d",
6076a8e1d46SRyan Lee 		params_format(params));
6086a8e1d46SRyan Lee 
6096a8e1d46SRyan Lee 	/* sampling rate configuration */
6106a8e1d46SRyan Lee 	switch (params_rate(params)) {
6116a8e1d46SRyan Lee 	case 8000:
6126a8e1d46SRyan Lee 		sampling_rate = MAX98388_PCM_SR_8000;
6136a8e1d46SRyan Lee 		break;
6146a8e1d46SRyan Lee 	case 11025:
6156a8e1d46SRyan Lee 		sampling_rate = MAX98388_PCM_SR_11025;
6166a8e1d46SRyan Lee 		break;
6176a8e1d46SRyan Lee 	case 12000:
6186a8e1d46SRyan Lee 		sampling_rate = MAX98388_PCM_SR_12000;
6196a8e1d46SRyan Lee 		break;
6206a8e1d46SRyan Lee 	case 16000:
6216a8e1d46SRyan Lee 		sampling_rate = MAX98388_PCM_SR_16000;
6226a8e1d46SRyan Lee 		break;
6236a8e1d46SRyan Lee 	case 22050:
6246a8e1d46SRyan Lee 		sampling_rate = MAX98388_PCM_SR_22050;
6256a8e1d46SRyan Lee 		break;
6266a8e1d46SRyan Lee 	case 24000:
6276a8e1d46SRyan Lee 		sampling_rate = MAX98388_PCM_SR_24000;
6286a8e1d46SRyan Lee 		break;
6296a8e1d46SRyan Lee 	case 32000:
6306a8e1d46SRyan Lee 		sampling_rate = MAX98388_PCM_SR_32000;
6316a8e1d46SRyan Lee 		break;
6326a8e1d46SRyan Lee 	case 44100:
6336a8e1d46SRyan Lee 		sampling_rate = MAX98388_PCM_SR_44100;
6346a8e1d46SRyan Lee 		break;
6356a8e1d46SRyan Lee 	case 48000:
6366a8e1d46SRyan Lee 		sampling_rate = MAX98388_PCM_SR_48000;
6376a8e1d46SRyan Lee 		break;
6386a8e1d46SRyan Lee 	case 88200:
6396a8e1d46SRyan Lee 		sampling_rate = MAX98388_PCM_SR_88200;
6406a8e1d46SRyan Lee 		break;
6416a8e1d46SRyan Lee 	case 96000:
6426a8e1d46SRyan Lee 		sampling_rate = MAX98388_PCM_SR_96000;
6436a8e1d46SRyan Lee 		break;
6446a8e1d46SRyan Lee 	default:
6456a8e1d46SRyan Lee 		dev_err(component->dev, "rate %d not supported\n",
6466a8e1d46SRyan Lee 			params_rate(params));
6476a8e1d46SRyan Lee 		goto err;
6486a8e1d46SRyan Lee 	}
6496a8e1d46SRyan Lee 
6506a8e1d46SRyan Lee 	/* set DAI_SR to correct LRCLK frequency */
6516a8e1d46SRyan Lee 	regmap_update_bits(max98388->regmap,
6526a8e1d46SRyan Lee 			   MAX98388_R2042_PCM_SR_SETUP,
6536a8e1d46SRyan Lee 			   MAX98388_PCM_SR_MASK,
6546a8e1d46SRyan Lee 			   sampling_rate);
6556a8e1d46SRyan Lee 
6566a8e1d46SRyan Lee 	/* set sampling rate of IV */
6576a8e1d46SRyan Lee 	if (max98388->interleave_mode &&
6586a8e1d46SRyan Lee 	    sampling_rate > MAX98388_PCM_SR_16000)
6596a8e1d46SRyan Lee 		regmap_update_bits(max98388->regmap,
6606a8e1d46SRyan Lee 				   MAX98388_R2042_PCM_SR_SETUP,
6616a8e1d46SRyan Lee 				   MAX98388_PCM_SR_IV_MASK,
6626a8e1d46SRyan Lee 				   (sampling_rate - 3) << MAX98388_PCM_SR_IV_SHIFT);
6636a8e1d46SRyan Lee 	else
6646a8e1d46SRyan Lee 		regmap_update_bits(max98388->regmap,
6656a8e1d46SRyan Lee 				   MAX98388_R2042_PCM_SR_SETUP,
6666a8e1d46SRyan Lee 				   MAX98388_PCM_SR_IV_MASK,
6676a8e1d46SRyan Lee 				   sampling_rate << MAX98388_PCM_SR_IV_SHIFT);
6686a8e1d46SRyan Lee 
6696a8e1d46SRyan Lee 	ret = max98388_set_clock(component, params);
6706a8e1d46SRyan Lee 
6716a8e1d46SRyan Lee 	if (status) {
6726a8e1d46SRyan Lee 		regmap_write(max98388->regmap,
6736a8e1d46SRyan Lee 			     MAX98388_R210F_GLOBAL_EN, 1);
6746a8e1d46SRyan Lee 		usleep_range(30000, 31000);
6756a8e1d46SRyan Lee 	}
6766a8e1d46SRyan Lee 
6776a8e1d46SRyan Lee 	return ret;
6786a8e1d46SRyan Lee 
6796a8e1d46SRyan Lee err:
6806a8e1d46SRyan Lee 	return -EINVAL;
6816a8e1d46SRyan Lee }
6826a8e1d46SRyan Lee 
6836a8e1d46SRyan Lee #define MAX_NUM_SLOTS 16
6846a8e1d46SRyan Lee #define MAX_NUM_CH 2
6856a8e1d46SRyan Lee 
max98388_dai_tdm_slot(struct snd_soc_dai * dai,unsigned int tx_mask,unsigned int rx_mask,int slots,int slot_width)6866a8e1d46SRyan Lee static int max98388_dai_tdm_slot(struct snd_soc_dai *dai,
6876a8e1d46SRyan Lee 				 unsigned int tx_mask, unsigned int rx_mask,
6886a8e1d46SRyan Lee 				 int slots, int slot_width)
6896a8e1d46SRyan Lee {
6906a8e1d46SRyan Lee 	struct snd_soc_component *component = dai->component;
6916a8e1d46SRyan Lee 	struct max98388_priv *max98388 = snd_soc_component_get_drvdata(component);
6926a8e1d46SRyan Lee 	int bsel = 0;
6936a8e1d46SRyan Lee 	unsigned int chan_sz = 0;
6946a8e1d46SRyan Lee 	unsigned int mask;
6956a8e1d46SRyan Lee 	int cnt, slot_found;
6966a8e1d46SRyan Lee 	int addr, bits;
6976a8e1d46SRyan Lee 
6986a8e1d46SRyan Lee 	if (!tx_mask && !rx_mask && !slots && !slot_width)
6996a8e1d46SRyan Lee 		max98388->tdm_mode = false;
7006a8e1d46SRyan Lee 	else
7016a8e1d46SRyan Lee 		max98388->tdm_mode = true;
7026a8e1d46SRyan Lee 
7036a8e1d46SRyan Lee 	/* BCLK configuration */
7046a8e1d46SRyan Lee 	bsel = max98388_get_bclk_sel(slots * slot_width);
7056a8e1d46SRyan Lee 	if (bsel == 0) {
7066a8e1d46SRyan Lee 		dev_err(component->dev, "BCLK %d not supported\n",
7076a8e1d46SRyan Lee 			slots * slot_width);
7086a8e1d46SRyan Lee 		return -EINVAL;
7096a8e1d46SRyan Lee 	}
7106a8e1d46SRyan Lee 
7116a8e1d46SRyan Lee 	regmap_update_bits(max98388->regmap,
7126a8e1d46SRyan Lee 			   MAX98388_R2041_PCM_CLK_SETUP,
7136a8e1d46SRyan Lee 			   MAX98388_PCM_CLK_SETUP_BSEL_MASK,
7146a8e1d46SRyan Lee 			   bsel);
7156a8e1d46SRyan Lee 
7166a8e1d46SRyan Lee 	/* Channel size configuration */
7176a8e1d46SRyan Lee 	switch (slot_width) {
7186a8e1d46SRyan Lee 	case 16:
7196a8e1d46SRyan Lee 		chan_sz = MAX98388_PCM_MODE_CFG_CHANSZ_16;
7206a8e1d46SRyan Lee 		break;
7216a8e1d46SRyan Lee 	case 24:
7226a8e1d46SRyan Lee 		chan_sz = MAX98388_PCM_MODE_CFG_CHANSZ_24;
7236a8e1d46SRyan Lee 		break;
7246a8e1d46SRyan Lee 	case 32:
7256a8e1d46SRyan Lee 		chan_sz = MAX98388_PCM_MODE_CFG_CHANSZ_32;
7266a8e1d46SRyan Lee 		break;
7276a8e1d46SRyan Lee 	default:
7286a8e1d46SRyan Lee 		dev_err(component->dev, "format unsupported %d\n",
7296a8e1d46SRyan Lee 			slot_width);
7306a8e1d46SRyan Lee 		return -EINVAL;
7316a8e1d46SRyan Lee 	}
7326a8e1d46SRyan Lee 
7336a8e1d46SRyan Lee 	regmap_update_bits(max98388->regmap,
7346a8e1d46SRyan Lee 			   MAX98388_R2040_PCM_MODE_CFG,
7356a8e1d46SRyan Lee 			   MAX98388_PCM_MODE_CFG_CHANSZ_MASK, chan_sz);
7366a8e1d46SRyan Lee 
7376a8e1d46SRyan Lee 	/* Rx slot configuration */
7386a8e1d46SRyan Lee 	slot_found = 0;
7396a8e1d46SRyan Lee 	mask = rx_mask;
7406a8e1d46SRyan Lee 	for (cnt = 0 ; cnt < MAX_NUM_SLOTS ; cnt++, mask >>= 1) {
7416a8e1d46SRyan Lee 		if (mask & 0x1) {
7426a8e1d46SRyan Lee 			if (slot_found == 0)
7436a8e1d46SRyan Lee 				regmap_update_bits(max98388->regmap,
7446a8e1d46SRyan Lee 						   MAX98388_R2059_PCM_RX_SRC2,
7456a8e1d46SRyan Lee 						   MAX98388_RX_SRC_CH0_SHIFT,
7466a8e1d46SRyan Lee 						   cnt);
7476a8e1d46SRyan Lee 			else
7486a8e1d46SRyan Lee 				regmap_update_bits(max98388->regmap,
7496a8e1d46SRyan Lee 						   MAX98388_R2059_PCM_RX_SRC2,
7506a8e1d46SRyan Lee 						   MAX98388_RX_SRC_CH1_SHIFT,
7516a8e1d46SRyan Lee 						   cnt);
7526a8e1d46SRyan Lee 			slot_found++;
7536a8e1d46SRyan Lee 			if (slot_found >= MAX_NUM_CH)
7546a8e1d46SRyan Lee 				break;
7556a8e1d46SRyan Lee 		}
7566a8e1d46SRyan Lee 	}
7576a8e1d46SRyan Lee 
7586a8e1d46SRyan Lee 	/* speaker feedback slot configuration */
7596a8e1d46SRyan Lee 	slot_found = 0;
7606a8e1d46SRyan Lee 	mask = tx_mask;
7616a8e1d46SRyan Lee 	for (cnt = 0 ; cnt < MAX_NUM_SLOTS ; cnt++, mask >>= 1) {
7626a8e1d46SRyan Lee 		if (mask & 0x1) {
7636a8e1d46SRyan Lee 			addr = MAX98388_R2044_PCM_TX_CTRL1 + (cnt / 8);
7646a8e1d46SRyan Lee 			bits = cnt % 8;
7656a8e1d46SRyan Lee 			regmap_update_bits(max98388->regmap, addr, bits, bits);
7666a8e1d46SRyan Lee 			if (slot_found >= MAX_NUM_CH)
7676a8e1d46SRyan Lee 				break;
7686a8e1d46SRyan Lee 		}
7696a8e1d46SRyan Lee 	}
7706a8e1d46SRyan Lee 
7716a8e1d46SRyan Lee 	return 0;
7726a8e1d46SRyan Lee }
7736a8e1d46SRyan Lee 
7746a8e1d46SRyan Lee #define MAX98388_RATES SNDRV_PCM_RATE_8000_96000
7756a8e1d46SRyan Lee 
7766a8e1d46SRyan Lee #define MAX98388_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
7776a8e1d46SRyan Lee 	SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
7786a8e1d46SRyan Lee 
7796a8e1d46SRyan Lee static const struct snd_soc_dai_ops max98388_dai_ops = {
7806a8e1d46SRyan Lee 	.set_fmt = max98388_dai_set_fmt,
7816a8e1d46SRyan Lee 	.hw_params = max98388_dai_hw_params,
7826a8e1d46SRyan Lee 	.set_tdm_slot = max98388_dai_tdm_slot,
7836a8e1d46SRyan Lee };
7846a8e1d46SRyan Lee 
max98388_readable_register(struct device * dev,unsigned int reg)7856a8e1d46SRyan Lee static bool max98388_readable_register(struct device *dev,
7866a8e1d46SRyan Lee 				       unsigned int reg)
7876a8e1d46SRyan Lee {
7886a8e1d46SRyan Lee 	switch (reg) {
7896a8e1d46SRyan Lee 	case MAX98388_R2001_INT_RAW1 ... MAX98388_R2002_INT_RAW2:
7906a8e1d46SRyan Lee 	case MAX98388_R2004_INT_STATE1... MAX98388_R2005_INT_STATE2:
7916a8e1d46SRyan Lee 	case MAX98388_R2020_THERM_WARN_THRESH:
7926a8e1d46SRyan Lee 	case MAX98388_R2031_SPK_MON_THRESH
7936a8e1d46SRyan Lee 		... MAX98388_R2033_SPK_MON_DURATION:
7946a8e1d46SRyan Lee 	case MAX98388_R2037_ERR_MON_CTRL:
7956a8e1d46SRyan Lee 	case MAX98388_R2040_PCM_MODE_CFG
7966a8e1d46SRyan Lee 		... MAX98388_R2042_PCM_SR_SETUP:
7976a8e1d46SRyan Lee 	case MAX98388_R2044_PCM_TX_CTRL1
7986a8e1d46SRyan Lee 		... MAX98388_R2045_PCM_TX_CTRL2:
7996a8e1d46SRyan Lee 	case MAX98388_R2050_PCM_TX_HIZ_CTRL1
8006a8e1d46SRyan Lee 		... MAX98388_R2059_PCM_RX_SRC2:
8016a8e1d46SRyan Lee 	case MAX98388_R205C_PCM_TX_DRIVE_STRENGTH
8026a8e1d46SRyan Lee 		... MAX98388_R205F_PCM_TX_EN:
8036a8e1d46SRyan Lee 	case MAX98388_R2090_SPK_CH_VOL_CTRL
8046a8e1d46SRyan Lee 		... MAX98388_R2094_SPK_AMP_ER_CTRL:
8056a8e1d46SRyan Lee 	case MAX98388_R209E_SPK_CH_PINK_NOISE_EN
8066a8e1d46SRyan Lee 		... MAX98388_R209F_SPK_CH_AMP_EN:
8076a8e1d46SRyan Lee 	case MAX98388_R20A0_IV_DATA_DSP_CTRL:
8086a8e1d46SRyan Lee 	case MAX98388_R20A7_IV_DATA_EN:
8096a8e1d46SRyan Lee 	case MAX98388_R20E0_BP_ALC_THRESH ... MAX98388_R20E4_BP_ALC_MUTE:
8106a8e1d46SRyan Lee 	case MAX98388_R20EE_BP_INF_HOLD_REL ... MAX98388_R20EF_BP_ALC_EN:
8116a8e1d46SRyan Lee 	case MAX98388_R210E_AUTO_RESTART:
8126a8e1d46SRyan Lee 	case MAX98388_R210F_GLOBAL_EN:
8136a8e1d46SRyan Lee 	case MAX98388_R22FF_REV_ID:
8146a8e1d46SRyan Lee 		return true;
8156a8e1d46SRyan Lee 	default:
8166a8e1d46SRyan Lee 		return false;
8176a8e1d46SRyan Lee 	}
8186a8e1d46SRyan Lee };
8196a8e1d46SRyan Lee 
max98388_volatile_reg(struct device * dev,unsigned int reg)8206a8e1d46SRyan Lee static bool max98388_volatile_reg(struct device *dev, unsigned int reg)
8216a8e1d46SRyan Lee {
8226a8e1d46SRyan Lee 	switch (reg) {
8236a8e1d46SRyan Lee 	case MAX98388_R2001_INT_RAW1 ... MAX98388_R2005_INT_STATE2:
8246a8e1d46SRyan Lee 	case MAX98388_R210F_GLOBAL_EN:
8256a8e1d46SRyan Lee 	case MAX98388_R22FF_REV_ID:
8266a8e1d46SRyan Lee 		return true;
8276a8e1d46SRyan Lee 	default:
8286a8e1d46SRyan Lee 		return false;
8296a8e1d46SRyan Lee 	}
8306a8e1d46SRyan Lee }
8316a8e1d46SRyan Lee 
8326a8e1d46SRyan Lee static struct snd_soc_dai_driver max98388_dai[] = {
8336a8e1d46SRyan Lee 	{
8346a8e1d46SRyan Lee 		.name = "max98388-aif1",
8356a8e1d46SRyan Lee 		.playback = {
8366a8e1d46SRyan Lee 			.stream_name = "HiFi Playback",
8376a8e1d46SRyan Lee 			.channels_min = 1,
8386a8e1d46SRyan Lee 			.channels_max = 2,
8396a8e1d46SRyan Lee 			.rates = MAX98388_RATES,
8406a8e1d46SRyan Lee 			.formats = MAX98388_FORMATS,
8416a8e1d46SRyan Lee 		},
8426a8e1d46SRyan Lee 		.capture = {
8436a8e1d46SRyan Lee 			.stream_name = "HiFi Capture",
8446a8e1d46SRyan Lee 			.channels_min = 1,
8456a8e1d46SRyan Lee 			.channels_max = 2,
8466a8e1d46SRyan Lee 			.rates = MAX98388_RATES,
8476a8e1d46SRyan Lee 			.formats = MAX98388_FORMATS,
8486a8e1d46SRyan Lee 		},
8496a8e1d46SRyan Lee 		.ops = &max98388_dai_ops,
8506a8e1d46SRyan Lee 	}
8516a8e1d46SRyan Lee };
8526a8e1d46SRyan Lee 
max98388_suspend(struct device * dev)8536a8e1d46SRyan Lee static int max98388_suspend(struct device *dev)
8546a8e1d46SRyan Lee {
8556a8e1d46SRyan Lee 	struct max98388_priv *max98388 = dev_get_drvdata(dev);
8566a8e1d46SRyan Lee 
8576a8e1d46SRyan Lee 	regcache_cache_only(max98388->regmap, true);
8586a8e1d46SRyan Lee 	regcache_mark_dirty(max98388->regmap);
8596a8e1d46SRyan Lee 
8606a8e1d46SRyan Lee 	return 0;
8616a8e1d46SRyan Lee }
8626a8e1d46SRyan Lee 
max98388_resume(struct device * dev)8636a8e1d46SRyan Lee static int max98388_resume(struct device *dev)
8646a8e1d46SRyan Lee {
8656a8e1d46SRyan Lee 	struct max98388_priv *max98388 = dev_get_drvdata(dev);
8666a8e1d46SRyan Lee 
8676a8e1d46SRyan Lee 	regcache_cache_only(max98388->regmap, false);
8686a8e1d46SRyan Lee 	max98388_reset(max98388, dev);
8696a8e1d46SRyan Lee 	regcache_sync(max98388->regmap);
8706a8e1d46SRyan Lee 
8716a8e1d46SRyan Lee 	return 0;
8726a8e1d46SRyan Lee }
8736a8e1d46SRyan Lee 
8746a8e1d46SRyan Lee static const struct dev_pm_ops max98388_pm = {
8750c340ba0SArnd Bergmann 	SYSTEM_SLEEP_PM_OPS(max98388_suspend, max98388_resume)
8766a8e1d46SRyan Lee };
8776a8e1d46SRyan Lee 
8786a8e1d46SRyan Lee static const struct regmap_config max98388_regmap = {
8796a8e1d46SRyan Lee 	.reg_bits = 16,
8806a8e1d46SRyan Lee 	.val_bits = 8,
8816a8e1d46SRyan Lee 	.max_register = MAX98388_R22FF_REV_ID,
8826a8e1d46SRyan Lee 	.reg_defaults  = max98388_reg,
8836a8e1d46SRyan Lee 	.num_reg_defaults = ARRAY_SIZE(max98388_reg),
8846a8e1d46SRyan Lee 	.readable_reg = max98388_readable_register,
8856a8e1d46SRyan Lee 	.volatile_reg = max98388_volatile_reg,
8866a8e1d46SRyan Lee 	.cache_type = REGCACHE_RBTREE,
8876a8e1d46SRyan Lee };
8886a8e1d46SRyan Lee 
889320d0e2dSTom Rix static const struct snd_soc_component_driver soc_codec_dev_max98388 = {
8906a8e1d46SRyan Lee 	.probe			= max98388_probe,
8916a8e1d46SRyan Lee 	.controls		= max98388_snd_controls,
8926a8e1d46SRyan Lee 	.num_controls		= ARRAY_SIZE(max98388_snd_controls),
8936a8e1d46SRyan Lee 	.dapm_widgets		= max98388_dapm_widgets,
8946a8e1d46SRyan Lee 	.num_dapm_widgets	= ARRAY_SIZE(max98388_dapm_widgets),
8956a8e1d46SRyan Lee 	.dapm_routes		= max98388_audio_map,
8966a8e1d46SRyan Lee 	.num_dapm_routes	= ARRAY_SIZE(max98388_audio_map),
8976a8e1d46SRyan Lee 	.use_pmdown_time	= 1,
8986a8e1d46SRyan Lee 	.endianness		= 1,
8996a8e1d46SRyan Lee };
9006a8e1d46SRyan Lee 
max98388_read_deveice_property(struct device * dev,struct max98388_priv * max98388)9016a8e1d46SRyan Lee static void max98388_read_deveice_property(struct device *dev,
9026a8e1d46SRyan Lee 					   struct max98388_priv *max98388)
9036a8e1d46SRyan Lee {
9046a8e1d46SRyan Lee 	int value;
9056a8e1d46SRyan Lee 
9066a8e1d46SRyan Lee 	if (!device_property_read_u32(dev, "adi,vmon-slot-no", &value))
9076a8e1d46SRyan Lee 		max98388->v_slot = value & 0xF;
9086a8e1d46SRyan Lee 	else
9096a8e1d46SRyan Lee 		max98388->v_slot = 0;
9106a8e1d46SRyan Lee 
9116a8e1d46SRyan Lee 	if (!device_property_read_u32(dev, "adi,imon-slot-no", &value))
9126a8e1d46SRyan Lee 		max98388->i_slot = value & 0xF;
9136a8e1d46SRyan Lee 	else
9146a8e1d46SRyan Lee 		max98388->i_slot = 1;
9156a8e1d46SRyan Lee 
9166a8e1d46SRyan Lee 	if (device_property_read_bool(dev, "adi,interleave-mode"))
9176a8e1d46SRyan Lee 		max98388->interleave_mode = true;
9186a8e1d46SRyan Lee 	else
9196a8e1d46SRyan Lee 		max98388->interleave_mode = false;
9206a8e1d46SRyan Lee }
9216a8e1d46SRyan Lee 
max98388_i2c_probe(struct i2c_client * i2c)9226a8e1d46SRyan Lee static int max98388_i2c_probe(struct i2c_client *i2c)
9236a8e1d46SRyan Lee {
9246a8e1d46SRyan Lee 	int ret = 0;
9256a8e1d46SRyan Lee 	int reg = 0;
9266a8e1d46SRyan Lee 
9276a8e1d46SRyan Lee 	struct max98388_priv *max98388 = NULL;
9286a8e1d46SRyan Lee 
9296a8e1d46SRyan Lee 	max98388 = devm_kzalloc(&i2c->dev, sizeof(*max98388), GFP_KERNEL);
9306a8e1d46SRyan Lee 	if (!max98388)
9316a8e1d46SRyan Lee 		return -ENOMEM;
9326a8e1d46SRyan Lee 
9336a8e1d46SRyan Lee 	i2c_set_clientdata(i2c, max98388);
9346a8e1d46SRyan Lee 
9356a8e1d46SRyan Lee 	/* regmap initialization */
9366a8e1d46SRyan Lee 	max98388->regmap = devm_regmap_init_i2c(i2c, &max98388_regmap);
9376a8e1d46SRyan Lee 	if (IS_ERR(max98388->regmap))
9386a8e1d46SRyan Lee 		return dev_err_probe(&i2c->dev, PTR_ERR(max98388->regmap),
9396a8e1d46SRyan Lee 				     "Failed to allocate register map.\n");
9406a8e1d46SRyan Lee 
9416a8e1d46SRyan Lee 	/* voltage/current slot & gpio configuration */
9426a8e1d46SRyan Lee 	max98388_read_deveice_property(&i2c->dev, max98388);
9436a8e1d46SRyan Lee 
9446a8e1d46SRyan Lee 	/* Device Reset */
9456a8e1d46SRyan Lee 	max98388->reset_gpio = devm_gpiod_get_optional(&i2c->dev,
9466a8e1d46SRyan Lee 						       "reset", GPIOD_OUT_HIGH);
9476a8e1d46SRyan Lee 	if (IS_ERR(max98388->reset_gpio))
9486a8e1d46SRyan Lee 		return dev_err_probe(&i2c->dev, PTR_ERR(max98388->reset_gpio),
9496a8e1d46SRyan Lee 				     "Unable to request GPIO\n");
9506a8e1d46SRyan Lee 
9516a8e1d46SRyan Lee 	if (max98388->reset_gpio) {
9526a8e1d46SRyan Lee 		usleep_range(5000, 6000);
9536a8e1d46SRyan Lee 		gpiod_set_value_cansleep(max98388->reset_gpio, 0);
9546a8e1d46SRyan Lee 		/* Wait for the hw reset done */
9556a8e1d46SRyan Lee 		usleep_range(5000, 6000);
9566a8e1d46SRyan Lee 	}
9576a8e1d46SRyan Lee 
9586a8e1d46SRyan Lee 	/* Read Revision ID */
9596a8e1d46SRyan Lee 	ret = regmap_read(max98388->regmap,
9606a8e1d46SRyan Lee 			  MAX98388_R22FF_REV_ID, &reg);
9616a8e1d46SRyan Lee 	if (ret < 0)
96202474880SDan Carpenter 		return dev_err_probe(&i2c->dev, ret,
9636a8e1d46SRyan Lee 				     "Failed to read the revision ID\n");
9646a8e1d46SRyan Lee 
9656a8e1d46SRyan Lee 	dev_info(&i2c->dev, "MAX98388 revisionID: 0x%02X\n", reg);
9666a8e1d46SRyan Lee 
9676a8e1d46SRyan Lee 	/* codec registration */
9686a8e1d46SRyan Lee 	ret = devm_snd_soc_register_component(&i2c->dev,
9696a8e1d46SRyan Lee 					      &soc_codec_dev_max98388,
9706a8e1d46SRyan Lee 					      max98388_dai,
9716a8e1d46SRyan Lee 					      ARRAY_SIZE(max98388_dai));
9726a8e1d46SRyan Lee 	if (ret < 0)
9736a8e1d46SRyan Lee 		dev_err(&i2c->dev, "Failed to register codec: %d\n", ret);
9746a8e1d46SRyan Lee 
9756a8e1d46SRyan Lee 	return ret;
9766a8e1d46SRyan Lee }
9776a8e1d46SRyan Lee 
9786a8e1d46SRyan Lee static const struct i2c_device_id max98388_i2c_id[] = {
979*ba2a2c37SUwe Kleine-König 	{ "max98388"},
9806a8e1d46SRyan Lee 	{ },
9816a8e1d46SRyan Lee };
9826a8e1d46SRyan Lee 
9836a8e1d46SRyan Lee MODULE_DEVICE_TABLE(i2c, max98388_i2c_id);
9846a8e1d46SRyan Lee 
9856a8e1d46SRyan Lee static const struct of_device_id max98388_of_match[] = {
9866a8e1d46SRyan Lee 	{ .compatible = "adi,max98388", },
9876a8e1d46SRyan Lee 	{ }
9886a8e1d46SRyan Lee };
9896a8e1d46SRyan Lee MODULE_DEVICE_TABLE(of, max98388_of_match);
9906a8e1d46SRyan Lee 
9916a8e1d46SRyan Lee static const struct acpi_device_id max98388_acpi_match[] = {
9926a8e1d46SRyan Lee 	{ "ADS8388", 0 },
9936a8e1d46SRyan Lee 	{},
9946a8e1d46SRyan Lee };
9956a8e1d46SRyan Lee MODULE_DEVICE_TABLE(acpi, max98388_acpi_match);
9966a8e1d46SRyan Lee 
9976a8e1d46SRyan Lee static struct i2c_driver max98388_i2c_driver = {
9986a8e1d46SRyan Lee 	.driver = {
9996a8e1d46SRyan Lee 		.name = "max98388",
10000c340ba0SArnd Bergmann 		.of_match_table = max98388_of_match,
10010c340ba0SArnd Bergmann 		.acpi_match_table = max98388_acpi_match,
10020c340ba0SArnd Bergmann 		.pm = pm_sleep_ptr(&max98388_pm),
10036a8e1d46SRyan Lee 	},
10046a8e1d46SRyan Lee 	.probe = max98388_i2c_probe,
10056a8e1d46SRyan Lee 	.id_table = max98388_i2c_id,
10066a8e1d46SRyan Lee };
10076a8e1d46SRyan Lee 
10086a8e1d46SRyan Lee module_i2c_driver(max98388_i2c_driver)
10096a8e1d46SRyan Lee 
10106a8e1d46SRyan Lee MODULE_DESCRIPTION("ALSA SoC MAX98388 driver");
10116a8e1d46SRyan Lee MODULE_AUTHOR("Ryan Lee <ryans.lee@analog.com>");
10126a8e1d46SRyan Lee MODULE_LICENSE("GPL");
1013