xref: /linux/sound/soc/codecs/max98396.c (revision a8c1dc9e8f01811b0c3fee65b9bc4773b2d00d96)
1b5858113SRyan Lee // SPDX-License-Identifier: GPL-2.0
2b5858113SRyan Lee // Copyright (c) 2022, Analog Devices Inc.
3b5858113SRyan Lee 
40b7f644fSHui Tang #include <linux/gpio/consumer.h>
5b5858113SRyan Lee #include <linux/i2c.h>
6b5858113SRyan Lee #include <linux/module.h>
7b5858113SRyan Lee #include <sound/pcm_params.h>
8703ee055SDaniel Mack #include <linux/regulator/consumer.h>
9b5858113SRyan Lee #include <sound/soc.h>
10b5858113SRyan Lee #include <linux/gpio.h>
11b5858113SRyan Lee #include <sound/tlv.h>
12b5858113SRyan Lee #include "max98396.h"
13b5858113SRyan Lee 
14703ee055SDaniel Mack static const char * const max98396_core_supplies[MAX98396_NUM_CORE_SUPPLIES] = {
15703ee055SDaniel Mack 	"avdd",
16703ee055SDaniel Mack 	"dvdd",
17703ee055SDaniel Mack 	"dvddio",
18703ee055SDaniel Mack };
19703ee055SDaniel Mack 
20b5858113SRyan Lee static struct reg_default max98396_reg[] = {
21b5858113SRyan Lee 	{MAX98396_R2000_SW_RESET, 0x00},
22b5858113SRyan Lee 	{MAX98396_R2001_INT_RAW1, 0x00},
23b5858113SRyan Lee 	{MAX98396_R2002_INT_RAW2, 0x00},
24b5858113SRyan Lee 	{MAX98396_R2003_INT_RAW3, 0x00},
25b5858113SRyan Lee 	{MAX98396_R2004_INT_RAW4, 0x00},
26b5858113SRyan Lee 	{MAX98396_R2006_INT_STATE1, 0x00},
27b5858113SRyan Lee 	{MAX98396_R2007_INT_STATE2, 0x00},
28b5858113SRyan Lee 	{MAX98396_R2008_INT_STATE3, 0x00},
29b5858113SRyan Lee 	{MAX98396_R2009_INT_STATE4, 0x00},
30b5858113SRyan Lee 	{MAX98396_R200B_INT_FLAG1, 0x00},
31b5858113SRyan Lee 	{MAX98396_R200C_INT_FLAG2, 0x00},
32b5858113SRyan Lee 	{MAX98396_R200D_INT_FLAG3, 0x00},
33b5858113SRyan Lee 	{MAX98396_R200E_INT_FLAG4, 0x00},
34b5858113SRyan Lee 	{MAX98396_R2010_INT_EN1, 0x02},
35b5858113SRyan Lee 	{MAX98396_R2011_INT_EN2, 0x00},
36b5858113SRyan Lee 	{MAX98396_R2012_INT_EN3, 0x00},
37b5858113SRyan Lee 	{MAX98396_R2013_INT_EN4, 0x00},
38b5858113SRyan Lee 	{MAX98396_R2015_INT_FLAG_CLR1, 0x00},
39b5858113SRyan Lee 	{MAX98396_R2016_INT_FLAG_CLR2, 0x00},
40b5858113SRyan Lee 	{MAX98396_R2017_INT_FLAG_CLR3, 0x00},
41b5858113SRyan Lee 	{MAX98396_R2018_INT_FLAG_CLR4, 0x00},
42b5858113SRyan Lee 	{MAX98396_R201F_IRQ_CTRL, 0x00},
43b5858113SRyan Lee 	{MAX98396_R2020_THERM_WARN_THRESH, 0x46},
44b5858113SRyan Lee 	{MAX98396_R2021_THERM_WARN_THRESH2, 0x46},
45b5858113SRyan Lee 	{MAX98396_R2022_THERM_SHDN_THRESH, 0x64},
46b5858113SRyan Lee 	{MAX98396_R2023_THERM_HYSTERESIS, 0x02},
47b5858113SRyan Lee 	{MAX98396_R2024_THERM_FOLDBACK_SET, 0xC5},
48b5858113SRyan Lee 	{MAX98396_R2027_THERM_FOLDBACK_EN, 0x01},
49b5858113SRyan Lee 	{MAX98396_R2030_NOISEGATE_MODE_CTRL, 0x32},
50b5858113SRyan Lee 	{MAX98396_R2033_NOISEGATE_MODE_EN, 0x00},
51b5858113SRyan Lee 	{MAX98396_R2038_CLK_MON_CTRL, 0x00},
52b5858113SRyan Lee 	{MAX98396_R2039_DATA_MON_CTRL, 0x00},
53b5858113SRyan Lee 	{MAX98396_R203F_ENABLE_CTRLS, 0x0F},
54b5858113SRyan Lee 	{MAX98396_R2040_PIN_CFG, 0x55},
55b5858113SRyan Lee 	{MAX98396_R2041_PCM_MODE_CFG, 0xC0},
56b5858113SRyan Lee 	{MAX98396_R2042_PCM_CLK_SETUP, 0x04},
57b5858113SRyan Lee 	{MAX98396_R2043_PCM_SR_SETUP, 0x88},
58b5858113SRyan Lee 	{MAX98396_R2044_PCM_TX_CTRL_1, 0x00},
59b5858113SRyan Lee 	{MAX98396_R2045_PCM_TX_CTRL_2, 0x00},
60b5858113SRyan Lee 	{MAX98396_R2046_PCM_TX_CTRL_3, 0x00},
61b5858113SRyan Lee 	{MAX98396_R2047_PCM_TX_CTRL_4, 0x00},
62b5858113SRyan Lee 	{MAX98396_R2048_PCM_TX_CTRL_5, 0x00},
63b5858113SRyan Lee 	{MAX98396_R2049_PCM_TX_CTRL_6, 0x00},
64b5858113SRyan Lee 	{MAX98396_R204A_PCM_TX_CTRL_7, 0x00},
65b5858113SRyan Lee 	{MAX98396_R204B_PCM_TX_CTRL_8, 0x00},
66b5858113SRyan Lee 	{MAX98396_R204C_PCM_TX_HIZ_CTRL_1, 0xFF},
67b5858113SRyan Lee 	{MAX98396_R204D_PCM_TX_HIZ_CTRL_2, 0xFF},
68b5858113SRyan Lee 	{MAX98396_R204E_PCM_TX_HIZ_CTRL_3, 0xFF},
69b5858113SRyan Lee 	{MAX98396_R204F_PCM_TX_HIZ_CTRL_4, 0xFF},
70b5858113SRyan Lee 	{MAX98396_R2050_PCM_TX_HIZ_CTRL_5, 0xFF},
71b5858113SRyan Lee 	{MAX98396_R2051_PCM_TX_HIZ_CTRL_6, 0xFF},
72b5858113SRyan Lee 	{MAX98396_R2052_PCM_TX_HIZ_CTRL_7, 0xFF},
73b5858113SRyan Lee 	{MAX98396_R2053_PCM_TX_HIZ_CTRL_8, 0xFF},
74b5858113SRyan Lee 	{MAX98396_R2055_PCM_RX_SRC1, 0x00},
75b5858113SRyan Lee 	{MAX98396_R2056_PCM_RX_SRC2, 0x00},
76b5858113SRyan Lee 	{MAX98396_R2058_PCM_BYPASS_SRC, 0x00},
77b5858113SRyan Lee 	{MAX98396_R205D_PCM_TX_SRC_EN, 0x00},
78b5858113SRyan Lee 	{MAX98396_R205E_PCM_RX_EN, 0x00},
79b5858113SRyan Lee 	{MAX98396_R205F_PCM_TX_EN, 0x00},
80b5858113SRyan Lee 	{MAX98396_R2070_ICC_RX_EN_A, 0x00},
81b5858113SRyan Lee 	{MAX98396_R2071_ICC_RX_EN_B, 0x00},
82b5858113SRyan Lee 	{MAX98396_R2072_ICC_TX_CTRL, 0x00},
83b5858113SRyan Lee 	{MAX98396_R207F_ICC_EN, 0x00},
84b5858113SRyan Lee 	{MAX98396_R2083_TONE_GEN_DC_CFG, 0x04},
85b5858113SRyan Lee 	{MAX98396_R2084_TONE_GEN_DC_LVL1, 0x00},
86b5858113SRyan Lee 	{MAX98396_R2085_TONE_GEN_DC_LVL2, 0x00},
87b5858113SRyan Lee 	{MAX98396_R2086_TONE_GEN_DC_LVL3, 0x00},
88b5858113SRyan Lee 	{MAX98396_R208F_TONE_GEN_EN, 0x00},
89b5858113SRyan Lee 	{MAX98396_R2090_AMP_VOL_CTRL, 0x00},
90b5858113SRyan Lee 	{MAX98396_R2091_AMP_PATH_GAIN, 0x0B},
91b5858113SRyan Lee 	{MAX98396_R2092_AMP_DSP_CFG, 0x23},
92b5858113SRyan Lee 	{MAX98396_R2093_SSM_CFG, 0x0D},
93b5858113SRyan Lee 	{MAX98396_R2094_SPK_CLS_DG_THRESH, 0x12},
94b5858113SRyan Lee 	{MAX98396_R2095_SPK_CLS_DG_HDR, 0x17},
95b5858113SRyan Lee 	{MAX98396_R2096_SPK_CLS_DG_HOLD_TIME, 0x17},
96b5858113SRyan Lee 	{MAX98396_R2097_SPK_CLS_DG_DELAY, 0x00},
97b5858113SRyan Lee 	{MAX98396_R2098_SPK_CLS_DG_MODE, 0x00},
98b5858113SRyan Lee 	{MAX98396_R2099_SPK_CLS_DG_VBAT_LVL, 0x03},
99b5858113SRyan Lee 	{MAX98396_R209A_SPK_EDGE_CTRL, 0x00},
100b5858113SRyan Lee 	{MAX98396_R209C_SPK_EDGE_CTRL1, 0x0A},
101b5858113SRyan Lee 	{MAX98396_R209D_SPK_EDGE_CTRL2, 0xAA},
102b5858113SRyan Lee 	{MAX98396_R209E_AMP_CLIP_GAIN, 0x00},
103b5858113SRyan Lee 	{MAX98396_R209F_BYPASS_PATH_CFG, 0x00},
104b5858113SRyan Lee 	{MAX98396_R20A0_AMP_SUPPLY_CTL, 0x00},
105b5858113SRyan Lee 	{MAX98396_R20AF_AMP_EN, 0x00},
106b5858113SRyan Lee 	{MAX98396_R20B0_ADC_SR, 0x30},
107b5858113SRyan Lee 	{MAX98396_R20B1_ADC_PVDD_CFG, 0x00},
108b5858113SRyan Lee 	{MAX98396_R20B2_ADC_VBAT_CFG, 0x00},
109b5858113SRyan Lee 	{MAX98396_R20B3_ADC_THERMAL_CFG, 0x00},
110b5858113SRyan Lee 	{MAX98396_R20B4_ADC_READBACK_CTRL1, 0x00},
111b5858113SRyan Lee 	{MAX98396_R20B5_ADC_READBACK_CTRL2, 0x00},
112b5858113SRyan Lee 	{MAX98396_R20B6_ADC_PVDD_READBACK_MSB, 0x00},
113b5858113SRyan Lee 	{MAX98396_R20B7_ADC_PVDD_READBACK_LSB, 0x00},
114b5858113SRyan Lee 	{MAX98396_R20B8_ADC_VBAT_READBACK_MSB, 0x00},
115b5858113SRyan Lee 	{MAX98396_R20B9_ADC_VBAT_READBACK_LSB, 0x00},
116b5858113SRyan Lee 	{MAX98396_R20BA_ADC_TEMP_READBACK_MSB, 0x00},
117b5858113SRyan Lee 	{MAX98396_R20BB_ADC_TEMP_READBACK_LSB, 0x00},
118b5858113SRyan Lee 	{MAX98396_R20BC_ADC_LO_PVDD_READBACK_MSB, 0x00},
119b5858113SRyan Lee 	{MAX98396_R20BD_ADC_LO_PVDD_READBACK_LSB, 0x00},
120b5858113SRyan Lee 	{MAX98396_R20BE_ADC_LO_VBAT_READBACK_MSB, 0x00},
121b5858113SRyan Lee 	{MAX98396_R20BF_ADC_LO_VBAT_READBACK_LSB, 0x00},
122b5858113SRyan Lee 	{MAX98396_R20C7_ADC_CFG, 0x00},
123b5858113SRyan Lee 	{MAX98396_R20D0_DHT_CFG1, 0x00},
124b5858113SRyan Lee 	{MAX98396_R20D1_LIMITER_CFG1, 0x08},
125b5858113SRyan Lee 	{MAX98396_R20D2_LIMITER_CFG2, 0x00},
126b5858113SRyan Lee 	{MAX98396_R20D3_DHT_CFG2, 0x14},
127b5858113SRyan Lee 	{MAX98396_R20D4_DHT_CFG3, 0x02},
128b5858113SRyan Lee 	{MAX98396_R20D5_DHT_CFG4, 0x04},
129b5858113SRyan Lee 	{MAX98396_R20D6_DHT_HYSTERESIS_CFG, 0x07},
130b5858113SRyan Lee 	{MAX98396_R20DF_DHT_EN, 0x00},
131b5858113SRyan Lee 	{MAX98396_R20E0_IV_SENSE_PATH_CFG, 0x04},
132b5858113SRyan Lee 	{MAX98396_R20E4_IV_SENSE_PATH_EN, 0x00},
133b5858113SRyan Lee 	{MAX98396_R20E5_BPE_STATE, 0x00},
134b5858113SRyan Lee 	{MAX98396_R20E6_BPE_L3_THRESH_MSB, 0x00},
135b5858113SRyan Lee 	{MAX98396_R20E7_BPE_L3_THRESH_LSB, 0x00},
136b5858113SRyan Lee 	{MAX98396_R20E8_BPE_L2_THRESH_MSB, 0x00},
137b5858113SRyan Lee 	{MAX98396_R20E9_BPE_L2_THRESH_LSB, 0x00},
138b5858113SRyan Lee 	{MAX98396_R20EA_BPE_L1_THRESH_MSB, 0x00},
139b5858113SRyan Lee 	{MAX98396_R20EB_BPE_L1_THRESH_LSB, 0x00},
140b5858113SRyan Lee 	{MAX98396_R20EC_BPE_L0_THRESH_MSB, 0x00},
141b5858113SRyan Lee 	{MAX98396_R20ED_BPE_L0_THRESH_LSB, 0x00},
142b5858113SRyan Lee 	{MAX98396_R20EE_BPE_L3_DWELL_HOLD_TIME, 0x00},
143b5858113SRyan Lee 	{MAX98396_R20EF_BPE_L2_DWELL_HOLD_TIME, 0x00},
144b5858113SRyan Lee 	{MAX98396_R20F0_BPE_L1_DWELL_HOLD_TIME, 0x00},
145b5858113SRyan Lee 	{MAX98396_R20F1_BPE_L0_HOLD_TIME, 0x00},
146b5858113SRyan Lee 	{MAX98396_R20F2_BPE_L3_ATTACK_REL_STEP, 0x00},
147b5858113SRyan Lee 	{MAX98396_R20F3_BPE_L2_ATTACK_REL_STEP, 0x00},
148b5858113SRyan Lee 	{MAX98396_R20F4_BPE_L1_ATTACK_REL_STEP, 0x00},
149b5858113SRyan Lee 	{MAX98396_R20F5_BPE_L0_ATTACK_REL_STEP, 0x00},
150b5858113SRyan Lee 	{MAX98396_R20F6_BPE_L3_MAX_GAIN_ATTN, 0x00},
151b5858113SRyan Lee 	{MAX98396_R20F7_BPE_L2_MAX_GAIN_ATTN, 0x00},
152b5858113SRyan Lee 	{MAX98396_R20F8_BPE_L1_MAX_GAIN_ATTN, 0x00},
153b5858113SRyan Lee 	{MAX98396_R20F9_BPE_L0_MAX_GAIN_ATTN, 0x00},
154b5858113SRyan Lee 	{MAX98396_R20FA_BPE_L3_ATT_REL_RATE, 0x00},
155b5858113SRyan Lee 	{MAX98396_R20FB_BPE_L2_ATT_REL_RATE, 0x00},
156b5858113SRyan Lee 	{MAX98396_R20FC_BPE_L1_ATT_REL_RATE, 0x00},
157b5858113SRyan Lee 	{MAX98396_R20FD_BPE_L0_ATT_REL_RATE, 0x00},
158b5858113SRyan Lee 	{MAX98396_R20FE_BPE_L3_LIMITER_CFG, 0x00},
159b5858113SRyan Lee 	{MAX98396_R20FF_BPE_L2_LIMITER_CFG, 0x00},
160b5858113SRyan Lee 	{MAX98396_R2100_BPE_L1_LIMITER_CFG, 0x00},
161b5858113SRyan Lee 	{MAX98396_R2101_BPE_L0_LIMITER_CFG, 0x00},
162b5858113SRyan Lee 	{MAX98396_R2102_BPE_L3_LIM_ATT_REL_RATE, 0x00},
163b5858113SRyan Lee 	{MAX98396_R2103_BPE_L2_LIM_ATT_REL_RATE, 0x00},
164b5858113SRyan Lee 	{MAX98396_R2104_BPE_L1_LIM_ATT_REL_RATE, 0x00},
165b5858113SRyan Lee 	{MAX98396_R2105_BPE_L0_LIM_ATT_REL_RATE, 0x00},
166b5858113SRyan Lee 	{MAX98396_R2106_BPE_THRESH_HYSTERESIS, 0x00},
167b5858113SRyan Lee 	{MAX98396_R2107_BPE_INFINITE_HOLD_CLR, 0x00},
168b5858113SRyan Lee 	{MAX98396_R2108_BPE_SUPPLY_SRC, 0x00},
169b5858113SRyan Lee 	{MAX98396_R2109_BPE_LOW_STATE, 0x00},
170b5858113SRyan Lee 	{MAX98396_R210A_BPE_LOW_GAIN, 0x00},
171b5858113SRyan Lee 	{MAX98396_R210B_BPE_LOW_LIMITER, 0x00},
172b5858113SRyan Lee 	{MAX98396_R210D_BPE_EN, 0x00},
173b5858113SRyan Lee 	{MAX98396_R210E_AUTO_RESTART, 0x00},
174b5858113SRyan Lee 	{MAX98396_R210F_GLOBAL_EN, 0x00},
175b5858113SRyan Lee 	{MAX98396_R21FF_REVISION_ID, 0x00},
176b5858113SRyan Lee };
177b5858113SRyan Lee 
178b5858113SRyan Lee static struct reg_default max98397_reg[] = {
179b5858113SRyan Lee 	{MAX98396_R2000_SW_RESET, 0x00},
180b5858113SRyan Lee 	{MAX98396_R2001_INT_RAW1, 0x00},
181b5858113SRyan Lee 	{MAX98396_R2002_INT_RAW2, 0x00},
182b5858113SRyan Lee 	{MAX98396_R2003_INT_RAW3, 0x00},
183b5858113SRyan Lee 	{MAX98396_R2004_INT_RAW4, 0x00},
184b5858113SRyan Lee 	{MAX98396_R2006_INT_STATE1, 0x00},
185b5858113SRyan Lee 	{MAX98396_R2007_INT_STATE2, 0x00},
186b5858113SRyan Lee 	{MAX98396_R2008_INT_STATE3, 0x00},
187b5858113SRyan Lee 	{MAX98396_R2009_INT_STATE4, 0x00},
188b5858113SRyan Lee 	{MAX98396_R200B_INT_FLAG1, 0x00},
189b5858113SRyan Lee 	{MAX98396_R200C_INT_FLAG2, 0x00},
190b5858113SRyan Lee 	{MAX98396_R200D_INT_FLAG3, 0x00},
191b5858113SRyan Lee 	{MAX98396_R200E_INT_FLAG4, 0x00},
192b5858113SRyan Lee 	{MAX98396_R2010_INT_EN1, 0x02},
193b5858113SRyan Lee 	{MAX98396_R2011_INT_EN2, 0x00},
194b5858113SRyan Lee 	{MAX98396_R2012_INT_EN3, 0x00},
195b5858113SRyan Lee 	{MAX98396_R2013_INT_EN4, 0x00},
196b5858113SRyan Lee 	{MAX98396_R2015_INT_FLAG_CLR1, 0x00},
197b5858113SRyan Lee 	{MAX98396_R2016_INT_FLAG_CLR2, 0x00},
198b5858113SRyan Lee 	{MAX98396_R2017_INT_FLAG_CLR3, 0x00},
199b5858113SRyan Lee 	{MAX98396_R2018_INT_FLAG_CLR4, 0x00},
200b5858113SRyan Lee 	{MAX98396_R201F_IRQ_CTRL, 0x00},
201b5858113SRyan Lee 	{MAX98396_R2020_THERM_WARN_THRESH, 0x46},
202b5858113SRyan Lee 	{MAX98396_R2021_THERM_WARN_THRESH2, 0x46},
203b5858113SRyan Lee 	{MAX98396_R2022_THERM_SHDN_THRESH, 0x64},
204b5858113SRyan Lee 	{MAX98396_R2023_THERM_HYSTERESIS, 0x02},
205b5858113SRyan Lee 	{MAX98396_R2024_THERM_FOLDBACK_SET, 0xC5},
206b5858113SRyan Lee 	{MAX98396_R2027_THERM_FOLDBACK_EN, 0x01},
207b5858113SRyan Lee 	{MAX98396_R2030_NOISEGATE_MODE_CTRL, 0x32},
208b5858113SRyan Lee 	{MAX98396_R2033_NOISEGATE_MODE_EN, 0x00},
209b5858113SRyan Lee 	{MAX98396_R2038_CLK_MON_CTRL, 0x00},
210b5858113SRyan Lee 	{MAX98396_R2039_DATA_MON_CTRL, 0x00},
211b5858113SRyan Lee 	{MAX98397_R203A_SPK_MON_THRESH, 0x03},
212b5858113SRyan Lee 	{MAX98396_R203F_ENABLE_CTRLS, 0x0F},
213b5858113SRyan Lee 	{MAX98396_R2040_PIN_CFG, 0x55},
214b5858113SRyan Lee 	{MAX98396_R2041_PCM_MODE_CFG, 0xC0},
215b5858113SRyan Lee 	{MAX98396_R2042_PCM_CLK_SETUP, 0x04},
216b5858113SRyan Lee 	{MAX98396_R2043_PCM_SR_SETUP, 0x88},
217b5858113SRyan Lee 	{MAX98396_R2044_PCM_TX_CTRL_1, 0x00},
218b5858113SRyan Lee 	{MAX98396_R2045_PCM_TX_CTRL_2, 0x00},
219b5858113SRyan Lee 	{MAX98396_R2046_PCM_TX_CTRL_3, 0x00},
220b5858113SRyan Lee 	{MAX98396_R2047_PCM_TX_CTRL_4, 0x00},
221b5858113SRyan Lee 	{MAX98396_R2048_PCM_TX_CTRL_5, 0x00},
222b5858113SRyan Lee 	{MAX98396_R2049_PCM_TX_CTRL_6, 0x00},
223b5858113SRyan Lee 	{MAX98396_R204A_PCM_TX_CTRL_7, 0x00},
224b5858113SRyan Lee 	{MAX98396_R204B_PCM_TX_CTRL_8, 0x00},
225b5858113SRyan Lee 	{MAX98397_R204C_PCM_TX_CTRL_9, 0x00},
226b5858113SRyan Lee 	{MAX98397_R204D_PCM_TX_HIZ_CTRL_1, 0xFF},
227b5858113SRyan Lee 	{MAX98397_R204E_PCM_TX_HIZ_CTRL_2, 0xFF},
228b5858113SRyan Lee 	{MAX98397_R204F_PCM_TX_HIZ_CTRL_3, 0xFF},
229b5858113SRyan Lee 	{MAX98397_R2050_PCM_TX_HIZ_CTRL_4, 0xFF},
230b5858113SRyan Lee 	{MAX98397_R2051_PCM_TX_HIZ_CTRL_5, 0xFF},
231b5858113SRyan Lee 	{MAX98397_R2052_PCM_TX_HIZ_CTRL_6, 0xFF},
232b5858113SRyan Lee 	{MAX98397_R2053_PCM_TX_HIZ_CTRL_7, 0xFF},
233b5858113SRyan Lee 	{MAX98397_R2054_PCM_TX_HIZ_CTRL_8, 0xFF},
234b5858113SRyan Lee 	{MAX98397_R2056_PCM_RX_SRC1, 0x00},
235b5858113SRyan Lee 	{MAX98397_R2057_PCM_RX_SRC2, 0x00},
236b5858113SRyan Lee 	{MAX98396_R2058_PCM_BYPASS_SRC, 0x00},
237b5858113SRyan Lee 	{MAX98396_R205D_PCM_TX_SRC_EN, 0x00},
238b5858113SRyan Lee 	{MAX98396_R205E_PCM_RX_EN, 0x00},
239b5858113SRyan Lee 	{MAX98396_R205F_PCM_TX_EN, 0x00},
240b5858113SRyan Lee 	{MAX98397_R2060_PCM_TX_SUPPLY_SEL, 0x00},
241b5858113SRyan Lee 	{MAX98396_R2070_ICC_RX_EN_A, 0x00},
242b5858113SRyan Lee 	{MAX98396_R2071_ICC_RX_EN_B, 0x00},
243b5858113SRyan Lee 	{MAX98396_R2072_ICC_TX_CTRL, 0x00},
244b5858113SRyan Lee 	{MAX98396_R207F_ICC_EN, 0x00},
245b5858113SRyan Lee 	{MAX98396_R2083_TONE_GEN_DC_CFG, 0x04},
246b5858113SRyan Lee 	{MAX98396_R2084_TONE_GEN_DC_LVL1, 0x00},
247b5858113SRyan Lee 	{MAX98396_R2085_TONE_GEN_DC_LVL2, 0x00},
248b5858113SRyan Lee 	{MAX98396_R2086_TONE_GEN_DC_LVL3, 0x00},
249b5858113SRyan Lee 	{MAX98396_R208F_TONE_GEN_EN, 0x00},
250b5858113SRyan Lee 	{MAX98396_R2090_AMP_VOL_CTRL, 0x00},
251b5858113SRyan Lee 	{MAX98396_R2091_AMP_PATH_GAIN, 0x12},
252b5858113SRyan Lee 	{MAX98396_R2092_AMP_DSP_CFG, 0x22},
253b5858113SRyan Lee 	{MAX98396_R2093_SSM_CFG, 0x08},
254b5858113SRyan Lee 	{MAX98396_R2094_SPK_CLS_DG_THRESH, 0x12},
255b5858113SRyan Lee 	{MAX98396_R2095_SPK_CLS_DG_HDR, 0x17},
256b5858113SRyan Lee 	{MAX98396_R2096_SPK_CLS_DG_HOLD_TIME, 0x17},
257b5858113SRyan Lee 	{MAX98396_R2097_SPK_CLS_DG_DELAY, 0x00},
258b5858113SRyan Lee 	{MAX98396_R2098_SPK_CLS_DG_MODE, 0x00},
259b5858113SRyan Lee 	{MAX98396_R2099_SPK_CLS_DG_VBAT_LVL, 0x03},
260b5858113SRyan Lee 	{MAX98396_R209A_SPK_EDGE_CTRL, 0x00},
261b5858113SRyan Lee 	{MAX98397_R209B_SPK_PATH_WB_ONLY, 0x00},
262b5858113SRyan Lee 	{MAX98396_R209C_SPK_EDGE_CTRL1, 0x03},
263b5858113SRyan Lee 	{MAX98396_R209D_SPK_EDGE_CTRL2, 0xFC},
264b5858113SRyan Lee 	{MAX98396_R209E_AMP_CLIP_GAIN, 0x00},
265b5858113SRyan Lee 	{MAX98396_R209F_BYPASS_PATH_CFG, 0x00},
266b5858113SRyan Lee 	{MAX98396_R20AF_AMP_EN, 0x00},
267b5858113SRyan Lee 	{MAX98396_R20B0_ADC_SR, 0x30},
268b5858113SRyan Lee 	{MAX98396_R20B1_ADC_PVDD_CFG, 0x00},
269b5858113SRyan Lee 	{MAX98396_R20B2_ADC_VBAT_CFG, 0x00},
270b5858113SRyan Lee 	{MAX98396_R20B3_ADC_THERMAL_CFG, 0x00},
271b5858113SRyan Lee 	{MAX98397_R20B4_ADC_VDDH_CFG, 0x00},
272b5858113SRyan Lee 	{MAX98397_R20B5_ADC_READBACK_CTRL1, 0x00},
273b5858113SRyan Lee 	{MAX98397_R20B6_ADC_READBACK_CTRL2, 0x00},
274b5858113SRyan Lee 	{MAX98397_R20B7_ADC_PVDD_READBACK_MSB, 0x00},
275b5858113SRyan Lee 	{MAX98397_R20B8_ADC_PVDD_READBACK_LSB, 0x00},
276b5858113SRyan Lee 	{MAX98397_R20B9_ADC_VBAT_READBACK_MSB, 0x00},
277b5858113SRyan Lee 	{MAX98397_R20BA_ADC_VBAT_READBACK_LSB, 0x00},
278b5858113SRyan Lee 	{MAX98397_R20BB_ADC_TEMP_READBACK_MSB, 0x00},
279b5858113SRyan Lee 	{MAX98397_R20BC_ADC_TEMP_READBACK_LSB, 0x00},
280b5858113SRyan Lee 	{MAX98397_R20BD_ADC_VDDH__READBACK_MSB, 0x00},
281b5858113SRyan Lee 	{MAX98397_R20BE_ADC_VDDH_READBACK_LSB, 0x00},
282b5858113SRyan Lee 	{MAX98396_R20BF_ADC_LO_VBAT_READBACK_LSB, 0x00},
283b5858113SRyan Lee 	{MAX98397_R20C3_ADC_LO_VDDH_READBACK_MSB, 0x00},
284b5858113SRyan Lee 	{MAX98397_R20C4_ADC_LO_VDDH_READBACK_LSB, 0x00},
285b5858113SRyan Lee 	{MAX98397_R20C5_MEAS_ADC_OPTIMAL_MODE, 0x04},
286b5858113SRyan Lee 	{MAX98396_R20C7_ADC_CFG, 0x00},
287b5858113SRyan Lee 	{MAX98396_R20D0_DHT_CFG1, 0x00},
288b5858113SRyan Lee 	{MAX98396_R20D1_LIMITER_CFG1, 0x08},
289b5858113SRyan Lee 	{MAX98396_R20D2_LIMITER_CFG2, 0x00},
290b5858113SRyan Lee 	{MAX98396_R20D3_DHT_CFG2, 0x14},
291b5858113SRyan Lee 	{MAX98396_R20D4_DHT_CFG3, 0x02},
292b5858113SRyan Lee 	{MAX98396_R20D5_DHT_CFG4, 0x04},
293b5858113SRyan Lee 	{MAX98396_R20D6_DHT_HYSTERESIS_CFG, 0x07},
294b5858113SRyan Lee 	{MAX98396_R20DF_DHT_EN, 0x00},
295b5858113SRyan Lee 	{MAX98396_R20E0_IV_SENSE_PATH_CFG, 0x04},
296b5858113SRyan Lee 	{MAX98396_R20E4_IV_SENSE_PATH_EN, 0x00},
297b5858113SRyan Lee 	{MAX98396_R20E5_BPE_STATE, 0x00},
298b5858113SRyan Lee 	{MAX98396_R20E6_BPE_L3_THRESH_MSB, 0x00},
299b5858113SRyan Lee 	{MAX98396_R20E7_BPE_L3_THRESH_LSB, 0x00},
300b5858113SRyan Lee 	{MAX98396_R20E8_BPE_L2_THRESH_MSB, 0x00},
301b5858113SRyan Lee 	{MAX98396_R20E9_BPE_L2_THRESH_LSB, 0x00},
302b5858113SRyan Lee 	{MAX98396_R20EA_BPE_L1_THRESH_MSB, 0x00},
303b5858113SRyan Lee 	{MAX98396_R20EB_BPE_L1_THRESH_LSB, 0x00},
304b5858113SRyan Lee 	{MAX98396_R20EC_BPE_L0_THRESH_MSB, 0x00},
305b5858113SRyan Lee 	{MAX98396_R20ED_BPE_L0_THRESH_LSB, 0x00},
306b5858113SRyan Lee 	{MAX98396_R20EE_BPE_L3_DWELL_HOLD_TIME, 0x00},
307b5858113SRyan Lee 	{MAX98396_R20EF_BPE_L2_DWELL_HOLD_TIME, 0x00},
308b5858113SRyan Lee 	{MAX98396_R20F0_BPE_L1_DWELL_HOLD_TIME, 0x00},
309b5858113SRyan Lee 	{MAX98396_R20F1_BPE_L0_HOLD_TIME, 0x00},
310b5858113SRyan Lee 	{MAX98396_R20F2_BPE_L3_ATTACK_REL_STEP, 0x00},
311b5858113SRyan Lee 	{MAX98396_R20F3_BPE_L2_ATTACK_REL_STEP, 0x00},
312b5858113SRyan Lee 	{MAX98396_R20F4_BPE_L1_ATTACK_REL_STEP, 0x00},
313b5858113SRyan Lee 	{MAX98396_R20F5_BPE_L0_ATTACK_REL_STEP, 0x00},
314b5858113SRyan Lee 	{MAX98396_R20F6_BPE_L3_MAX_GAIN_ATTN, 0x00},
315b5858113SRyan Lee 	{MAX98396_R20F7_BPE_L2_MAX_GAIN_ATTN, 0x00},
316b5858113SRyan Lee 	{MAX98396_R20F8_BPE_L1_MAX_GAIN_ATTN, 0x00},
317b5858113SRyan Lee 	{MAX98396_R20F9_BPE_L0_MAX_GAIN_ATTN, 0x00},
318b5858113SRyan Lee 	{MAX98396_R20FA_BPE_L3_ATT_REL_RATE, 0x00},
319b5858113SRyan Lee 	{MAX98396_R20FB_BPE_L2_ATT_REL_RATE, 0x00},
320b5858113SRyan Lee 	{MAX98396_R20FC_BPE_L1_ATT_REL_RATE, 0x00},
321b5858113SRyan Lee 	{MAX98396_R20FD_BPE_L0_ATT_REL_RATE, 0x00},
322b5858113SRyan Lee 	{MAX98396_R20FE_BPE_L3_LIMITER_CFG, 0x00},
323b5858113SRyan Lee 	{MAX98396_R20FF_BPE_L2_LIMITER_CFG, 0x00},
324b5858113SRyan Lee 	{MAX98396_R2100_BPE_L1_LIMITER_CFG, 0x00},
325b5858113SRyan Lee 	{MAX98396_R2101_BPE_L0_LIMITER_CFG, 0x00},
326b5858113SRyan Lee 	{MAX98396_R2102_BPE_L3_LIM_ATT_REL_RATE, 0x00},
327b5858113SRyan Lee 	{MAX98396_R2103_BPE_L2_LIM_ATT_REL_RATE, 0x00},
328b5858113SRyan Lee 	{MAX98396_R2104_BPE_L1_LIM_ATT_REL_RATE, 0x00},
329b5858113SRyan Lee 	{MAX98396_R2105_BPE_L0_LIM_ATT_REL_RATE, 0x00},
330b5858113SRyan Lee 	{MAX98396_R2106_BPE_THRESH_HYSTERESIS, 0x00},
331b5858113SRyan Lee 	{MAX98396_R2107_BPE_INFINITE_HOLD_CLR, 0x00},
332b5858113SRyan Lee 	{MAX98396_R2108_BPE_SUPPLY_SRC, 0x00},
333b5858113SRyan Lee 	{MAX98396_R2109_BPE_LOW_STATE, 0x00},
334b5858113SRyan Lee 	{MAX98396_R210A_BPE_LOW_GAIN, 0x00},
335b5858113SRyan Lee 	{MAX98396_R210B_BPE_LOW_LIMITER, 0x00},
336b5858113SRyan Lee 	{MAX98396_R210D_BPE_EN, 0x00},
337b5858113SRyan Lee 	{MAX98396_R210E_AUTO_RESTART, 0x00},
338b5858113SRyan Lee 	{MAX98396_R210F_GLOBAL_EN, 0x00},
339b5858113SRyan Lee 	{MAX98397_R22FF_REVISION_ID, 0x00},
340b5858113SRyan Lee };
341b5858113SRyan Lee 
342b5858113SRyan Lee static void max98396_global_enable_onoff(struct regmap *regmap, bool onoff)
343b5858113SRyan Lee {
344b5858113SRyan Lee 	regmap_write(regmap, MAX98396_R210F_GLOBAL_EN, onoff ? 1 : 0);
345b5858113SRyan Lee 	usleep_range(11000, 12000);
346b5858113SRyan Lee }
347b5858113SRyan Lee 
348b5858113SRyan Lee static int max98396_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
349b5858113SRyan Lee {
350b5858113SRyan Lee 	struct snd_soc_component *component = codec_dai->component;
351b5858113SRyan Lee 	struct max98396_priv *max98396 = snd_soc_component_get_drvdata(component);
352b5858113SRyan Lee 	unsigned int format = 0;
353b5858113SRyan Lee 	unsigned int bclk_pol = 0;
354b5858113SRyan Lee 	int ret, status;
355b5858113SRyan Lee 	int reg;
356b5858113SRyan Lee 	bool update = false;
357b5858113SRyan Lee 
358b5858113SRyan Lee 	dev_dbg(component->dev, "%s: fmt 0x%08X\n", __func__, fmt);
359b5858113SRyan Lee 
360b5858113SRyan Lee 	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
361b5858113SRyan Lee 	case SND_SOC_DAIFMT_NB_NF:
362b5858113SRyan Lee 		break;
363b5858113SRyan Lee 	case SND_SOC_DAIFMT_NB_IF:
364b5858113SRyan Lee 		format = MAX98396_PCM_MODE_CFG_LRCLKEDGE;
365b5858113SRyan Lee 		break;
366b5858113SRyan Lee 	case SND_SOC_DAIFMT_IB_NF:
367b5858113SRyan Lee 		bclk_pol = MAX98396_PCM_MODE_CFG_BCLKEDGE;
368b5858113SRyan Lee 		break;
369b5858113SRyan Lee 	case SND_SOC_DAIFMT_IB_IF:
370b5858113SRyan Lee 		bclk_pol = MAX98396_PCM_MODE_CFG_BCLKEDGE;
371b5858113SRyan Lee 		format = MAX98396_PCM_MODE_CFG_LRCLKEDGE;
372b5858113SRyan Lee 		break;
373b5858113SRyan Lee 
374b5858113SRyan Lee 	default:
375*a8c1dc9eSDaniel Mack 		dev_err(component->dev, "DAI invert mode %d unsupported\n",
376*a8c1dc9eSDaniel Mack 			fmt & SND_SOC_DAIFMT_INV_MASK);
377b5858113SRyan Lee 		return -EINVAL;
378b5858113SRyan Lee 	}
379b5858113SRyan Lee 
380b5858113SRyan Lee 	/* interface format */
381b5858113SRyan Lee 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
382b5858113SRyan Lee 	case SND_SOC_DAIFMT_I2S:
383b5858113SRyan Lee 		format |= MAX98396_PCM_FORMAT_I2S;
384b5858113SRyan Lee 		break;
385b5858113SRyan Lee 	case SND_SOC_DAIFMT_LEFT_J:
386b5858113SRyan Lee 		format |= MAX98396_PCM_FORMAT_LJ;
387b5858113SRyan Lee 		break;
388b5858113SRyan Lee 	case SND_SOC_DAIFMT_DSP_A:
389b5858113SRyan Lee 		format |= MAX98396_PCM_FORMAT_TDM_MODE1;
390b5858113SRyan Lee 		break;
391b5858113SRyan Lee 	case SND_SOC_DAIFMT_DSP_B:
392b5858113SRyan Lee 		format |= MAX98396_PCM_FORMAT_TDM_MODE0;
393b5858113SRyan Lee 		break;
394b5858113SRyan Lee 	default:
395*a8c1dc9eSDaniel Mack 		dev_err(component->dev, "DAI format %d unsupported\n",
396*a8c1dc9eSDaniel Mack 			fmt & SND_SOC_DAIFMT_FORMAT_MASK);
397b5858113SRyan Lee 		return -EINVAL;
398b5858113SRyan Lee 	}
399b5858113SRyan Lee 
400b5858113SRyan Lee 	ret = regmap_read(max98396->regmap, MAX98396_R210F_GLOBAL_EN, &status);
401b5858113SRyan Lee 	if (ret < 0)
402b5858113SRyan Lee 		return -EINVAL;
403b5858113SRyan Lee 
404b5858113SRyan Lee 	if (status) {
405b5858113SRyan Lee 		ret = regmap_read(max98396->regmap, MAX98396_R2041_PCM_MODE_CFG, &reg);
406b5858113SRyan Lee 		if (ret < 0)
407b5858113SRyan Lee 			return -EINVAL;
408b5858113SRyan Lee 		if (format != (reg & MAX98396_PCM_BCLKEDGE_BSEL_MASK)) {
409b5858113SRyan Lee 			update = true;
410b5858113SRyan Lee 		} else {
411b5858113SRyan Lee 			ret = regmap_read(max98396->regmap,
412b5858113SRyan Lee 					  MAX98396_R2042_PCM_CLK_SETUP, &reg);
413b5858113SRyan Lee 			if (ret < 0)
414b5858113SRyan Lee 				return -EINVAL;
415b5858113SRyan Lee 			if (bclk_pol != (reg & MAX98396_PCM_MODE_CFG_BCLKEDGE))
416b5858113SRyan Lee 				update = true;
417b5858113SRyan Lee 		}
418b5858113SRyan Lee 		/* GLOBAL_EN OFF prior to pcm mode, clock configuration change */
419b5858113SRyan Lee 		if (update)
420b5858113SRyan Lee 			max98396_global_enable_onoff(max98396->regmap, false);
421b5858113SRyan Lee 	}
422b5858113SRyan Lee 
423b5858113SRyan Lee 	regmap_update_bits(max98396->regmap,
424b5858113SRyan Lee 			   MAX98396_R2041_PCM_MODE_CFG,
425b5858113SRyan Lee 			   MAX98396_PCM_BCLKEDGE_BSEL_MASK,
426b5858113SRyan Lee 			   format);
427b5858113SRyan Lee 
428b5858113SRyan Lee 	regmap_update_bits(max98396->regmap,
429b5858113SRyan Lee 			   MAX98396_R2042_PCM_CLK_SETUP,
430b5858113SRyan Lee 			   MAX98396_PCM_MODE_CFG_BCLKEDGE,
431b5858113SRyan Lee 			   bclk_pol);
432b5858113SRyan Lee 
433b5858113SRyan Lee 	if (status && update)
434b5858113SRyan Lee 		max98396_global_enable_onoff(max98396->regmap, true);
435b5858113SRyan Lee 
436b5858113SRyan Lee 	return 0;
437b5858113SRyan Lee }
438b5858113SRyan Lee 
439b5858113SRyan Lee /* BCLKs per LRCLK */
440b5858113SRyan Lee static const int bclk_sel_table[] = {
441b5858113SRyan Lee 	32, 48, 64, 96, 128, 192, 256, 384, 512, 320,
442b5858113SRyan Lee };
443b5858113SRyan Lee 
444b5858113SRyan Lee static int max98396_get_bclk_sel(int bclk)
445b5858113SRyan Lee {
446b5858113SRyan Lee 	int i;
447b5858113SRyan Lee 	/* match BCLKs per LRCLK */
448b5858113SRyan Lee 	for (i = 0; i < ARRAY_SIZE(bclk_sel_table); i++) {
449b5858113SRyan Lee 		if (bclk_sel_table[i] == bclk)
450b5858113SRyan Lee 			return i + 2;
451b5858113SRyan Lee 	}
452b5858113SRyan Lee 	return 0;
453b5858113SRyan Lee }
454b5858113SRyan Lee 
455b5858113SRyan Lee static int max98396_set_clock(struct snd_soc_component *component,
456b5858113SRyan Lee 			      struct snd_pcm_hw_params *params)
457b5858113SRyan Lee {
458b5858113SRyan Lee 	struct max98396_priv *max98396 = snd_soc_component_get_drvdata(component);
459b5858113SRyan Lee 	/* BCLK/LRCLK ratio calculation */
460b5858113SRyan Lee 	int blr_clk_ratio = params_channels(params) * max98396->ch_size;
461b5858113SRyan Lee 	int value;
462b5858113SRyan Lee 
463b5858113SRyan Lee 	if (!max98396->tdm_mode) {
464b5858113SRyan Lee 		/* BCLK configuration */
465b5858113SRyan Lee 		value = max98396_get_bclk_sel(blr_clk_ratio);
466b5858113SRyan Lee 		if (!value) {
467*a8c1dc9eSDaniel Mack 			dev_err(component->dev,
468*a8c1dc9eSDaniel Mack 				"blr_clk_ratio %d unsupported, format %d\n",
469*a8c1dc9eSDaniel Mack 				blr_clk_ratio, params_format(params));
470b5858113SRyan Lee 			return -EINVAL;
471b5858113SRyan Lee 		}
472b5858113SRyan Lee 
473b5858113SRyan Lee 		regmap_update_bits(max98396->regmap,
474b5858113SRyan Lee 				   MAX98396_R2042_PCM_CLK_SETUP,
475b5858113SRyan Lee 				   MAX98396_PCM_CLK_SETUP_BSEL_MASK,
476b5858113SRyan Lee 				   value);
477b5858113SRyan Lee 	}
478b5858113SRyan Lee 
479b5858113SRyan Lee 	return 0;
480b5858113SRyan Lee }
481b5858113SRyan Lee 
482b5858113SRyan Lee static int max98396_dai_hw_params(struct snd_pcm_substream *substream,
483b5858113SRyan Lee 				  struct snd_pcm_hw_params *params,
484b5858113SRyan Lee 				  struct snd_soc_dai *dai)
485b5858113SRyan Lee {
486b5858113SRyan Lee 	struct snd_soc_component *component = dai->component;
487b5858113SRyan Lee 	struct max98396_priv *max98396 = snd_soc_component_get_drvdata(component);
488b5858113SRyan Lee 	unsigned int sampling_rate = 0;
489b5858113SRyan Lee 	unsigned int chan_sz = 0;
490b5858113SRyan Lee 	int ret, reg;
491b5858113SRyan Lee 	int status;
492b5858113SRyan Lee 	bool update = false;
493b5858113SRyan Lee 
494b5858113SRyan Lee 	/* pcm mode configuration */
495b5858113SRyan Lee 	switch (snd_pcm_format_width(params_format(params))) {
496b5858113SRyan Lee 	case 16:
497b5858113SRyan Lee 		chan_sz = MAX98396_PCM_MODE_CFG_CHANSZ_16;
498b5858113SRyan Lee 		break;
499b5858113SRyan Lee 	case 24:
500b5858113SRyan Lee 		chan_sz = MAX98396_PCM_MODE_CFG_CHANSZ_24;
501b5858113SRyan Lee 		break;
502b5858113SRyan Lee 	case 32:
503b5858113SRyan Lee 		chan_sz = MAX98396_PCM_MODE_CFG_CHANSZ_32;
504b5858113SRyan Lee 		break;
505b5858113SRyan Lee 	default:
506b5858113SRyan Lee 		dev_err(component->dev, "format unsupported %d\n",
507b5858113SRyan Lee 			params_format(params));
508b5858113SRyan Lee 		goto err;
509b5858113SRyan Lee 	}
510b5858113SRyan Lee 
511b5858113SRyan Lee 	max98396->ch_size = snd_pcm_format_width(params_format(params));
512b5858113SRyan Lee 
513b5858113SRyan Lee 	dev_dbg(component->dev, "format supported %d",
514b5858113SRyan Lee 		params_format(params));
515b5858113SRyan Lee 
516b5858113SRyan Lee 	/* sampling rate configuration */
517b5858113SRyan Lee 	switch (params_rate(params)) {
518b5858113SRyan Lee 	case 8000:
519b5858113SRyan Lee 		sampling_rate = MAX98396_PCM_SR_8000;
520b5858113SRyan Lee 		break;
521b5858113SRyan Lee 	case 11025:
522b5858113SRyan Lee 		sampling_rate = MAX98396_PCM_SR_11025;
523b5858113SRyan Lee 		break;
524b5858113SRyan Lee 	case 12000:
525b5858113SRyan Lee 		sampling_rate = MAX98396_PCM_SR_12000;
526b5858113SRyan Lee 		break;
527b5858113SRyan Lee 	case 16000:
528b5858113SRyan Lee 		sampling_rate = MAX98396_PCM_SR_16000;
529b5858113SRyan Lee 		break;
530b5858113SRyan Lee 	case 22050:
531b5858113SRyan Lee 		sampling_rate = MAX98396_PCM_SR_22050;
532b5858113SRyan Lee 		break;
533b5858113SRyan Lee 	case 24000:
534b5858113SRyan Lee 		sampling_rate = MAX98396_PCM_SR_24000;
535b5858113SRyan Lee 		break;
536b5858113SRyan Lee 	case 32000:
537b5858113SRyan Lee 		sampling_rate = MAX98396_PCM_SR_32000;
538b5858113SRyan Lee 		break;
539b5858113SRyan Lee 	case 44100:
540b5858113SRyan Lee 		sampling_rate = MAX98396_PCM_SR_44100;
541b5858113SRyan Lee 		break;
542b5858113SRyan Lee 	case 48000:
543b5858113SRyan Lee 		sampling_rate = MAX98396_PCM_SR_48000;
544b5858113SRyan Lee 		break;
545b5858113SRyan Lee 	case 88200:
546b5858113SRyan Lee 		sampling_rate = MAX98396_PCM_SR_88200;
547b5858113SRyan Lee 		break;
548b5858113SRyan Lee 	case 96000:
549b5858113SRyan Lee 		sampling_rate = MAX98396_PCM_SR_96000;
550b5858113SRyan Lee 		break;
551b5858113SRyan Lee 	case 192000:
552b5858113SRyan Lee 		sampling_rate = MAX98396_PCM_SR_192000;
553b5858113SRyan Lee 		break;
554b5858113SRyan Lee 	default:
555b5858113SRyan Lee 		dev_err(component->dev, "rate %d not supported\n",
556b5858113SRyan Lee 			params_rate(params));
557b5858113SRyan Lee 		goto err;
558b5858113SRyan Lee 	}
559b5858113SRyan Lee 
560b5858113SRyan Lee 	ret = regmap_read(max98396->regmap, MAX98396_R210F_GLOBAL_EN, &status);
561b5858113SRyan Lee 	if (ret < 0)
562b5858113SRyan Lee 		goto err;
563b5858113SRyan Lee 
564b5858113SRyan Lee 	if (status) {
565b5858113SRyan Lee 		ret = regmap_read(max98396->regmap, MAX98396_R2041_PCM_MODE_CFG, &reg);
566b5858113SRyan Lee 		if (ret < 0)
567b5858113SRyan Lee 			goto err;
568b5858113SRyan Lee 		if (chan_sz != (reg & MAX98396_PCM_MODE_CFG_CHANSZ_MASK)) {
569b5858113SRyan Lee 			update = true;
570b5858113SRyan Lee 		} else {
571b5858113SRyan Lee 			ret = regmap_read(max98396->regmap, MAX98396_R2043_PCM_SR_SETUP, &reg);
572b5858113SRyan Lee 			if (ret < 0)
573b5858113SRyan Lee 				goto err;
574b5858113SRyan Lee 			if (sampling_rate != (reg & MAX98396_PCM_SR_MASK))
575b5858113SRyan Lee 				update = true;
576b5858113SRyan Lee 		}
577b5858113SRyan Lee 
578b5858113SRyan Lee 		/* GLOBAL_EN OFF prior to channel size and sampling rate change */
579b5858113SRyan Lee 		if (update)
580b5858113SRyan Lee 			max98396_global_enable_onoff(max98396->regmap, false);
581b5858113SRyan Lee 	}
582b5858113SRyan Lee 
583b5858113SRyan Lee 	/* set channel size */
584b5858113SRyan Lee 	regmap_update_bits(max98396->regmap, MAX98396_R2041_PCM_MODE_CFG,
585b5858113SRyan Lee 			   MAX98396_PCM_MODE_CFG_CHANSZ_MASK, chan_sz);
586b5858113SRyan Lee 
587b5858113SRyan Lee 	/* set DAI_SR to correct LRCLK frequency */
588b5858113SRyan Lee 	regmap_update_bits(max98396->regmap, MAX98396_R2043_PCM_SR_SETUP,
589b5858113SRyan Lee 			   MAX98396_PCM_SR_MASK, sampling_rate);
590b5858113SRyan Lee 
591b5858113SRyan Lee 	/* set sampling rate of IV */
592b5858113SRyan Lee 	if (max98396->interleave_mode &&
593b5858113SRyan Lee 	    sampling_rate > MAX98396_PCM_SR_16000)
594b5858113SRyan Lee 		regmap_update_bits(max98396->regmap,
595b5858113SRyan Lee 				   MAX98396_R2043_PCM_SR_SETUP,
596b5858113SRyan Lee 				   MAX98396_IVADC_SR_MASK,
597b5858113SRyan Lee 				   (sampling_rate - 3)
598b5858113SRyan Lee 				   << MAX98396_IVADC_SR_SHIFT);
599b5858113SRyan Lee 	else
600b5858113SRyan Lee 		regmap_update_bits(max98396->regmap,
601b5858113SRyan Lee 				   MAX98396_R2043_PCM_SR_SETUP,
602b5858113SRyan Lee 				   MAX98396_IVADC_SR_MASK,
603b5858113SRyan Lee 				   sampling_rate << MAX98396_IVADC_SR_SHIFT);
604b5858113SRyan Lee 
605b5858113SRyan Lee 	ret = max98396_set_clock(component, params);
606b5858113SRyan Lee 
607b5858113SRyan Lee 	if (status && update)
608b5858113SRyan Lee 		max98396_global_enable_onoff(max98396->regmap, true);
609b5858113SRyan Lee 
610b5858113SRyan Lee 	return ret;
611b5858113SRyan Lee 
612b5858113SRyan Lee err:
613b5858113SRyan Lee 	return -EINVAL;
614b5858113SRyan Lee }
615b5858113SRyan Lee 
616b5858113SRyan Lee static int max98396_dai_tdm_slot(struct snd_soc_dai *dai,
617b5858113SRyan Lee 				 unsigned int tx_mask, unsigned int rx_mask,
618b5858113SRyan Lee 				 int slots, int slot_width)
619b5858113SRyan Lee {
620b5858113SRyan Lee 	struct snd_soc_component *component = dai->component;
621b5858113SRyan Lee 	struct max98396_priv *max98396 =
622b5858113SRyan Lee 		snd_soc_component_get_drvdata(component);
623b5858113SRyan Lee 	int bsel;
624b5858113SRyan Lee 	unsigned int chan_sz = 0;
625b5858113SRyan Lee 	int ret, status;
626b5858113SRyan Lee 	int reg;
627b5858113SRyan Lee 	bool update = false;
628b5858113SRyan Lee 
629b5858113SRyan Lee 	if (!tx_mask && !rx_mask && !slots && !slot_width)
630b5858113SRyan Lee 		max98396->tdm_mode = false;
631b5858113SRyan Lee 	else
632b5858113SRyan Lee 		max98396->tdm_mode = true;
633b5858113SRyan Lee 
634b5858113SRyan Lee 	/* BCLK configuration */
635b5858113SRyan Lee 	bsel = max98396_get_bclk_sel(slots * slot_width);
636b5858113SRyan Lee 	if (bsel == 0) {
637b5858113SRyan Lee 		dev_err(component->dev, "BCLK %d not supported\n",
638b5858113SRyan Lee 			slots * slot_width);
639b5858113SRyan Lee 		return -EINVAL;
640b5858113SRyan Lee 	}
641b5858113SRyan Lee 
642b5858113SRyan Lee 	/* Channel size configuration */
643b5858113SRyan Lee 	switch (slot_width) {
644b5858113SRyan Lee 	case 16:
645b5858113SRyan Lee 		chan_sz = MAX98396_PCM_MODE_CFG_CHANSZ_16;
646b5858113SRyan Lee 		break;
647b5858113SRyan Lee 	case 24:
648b5858113SRyan Lee 		chan_sz = MAX98396_PCM_MODE_CFG_CHANSZ_24;
649b5858113SRyan Lee 		break;
650b5858113SRyan Lee 	case 32:
651b5858113SRyan Lee 		chan_sz = MAX98396_PCM_MODE_CFG_CHANSZ_32;
652b5858113SRyan Lee 		break;
653b5858113SRyan Lee 	default:
654*a8c1dc9eSDaniel Mack 		dev_err(component->dev, "slot width %d unsupported\n",
655b5858113SRyan Lee 			slot_width);
656b5858113SRyan Lee 		return -EINVAL;
657b5858113SRyan Lee 	}
658b5858113SRyan Lee 
659b5858113SRyan Lee 	ret = regmap_read(max98396->regmap, MAX98396_R210F_GLOBAL_EN, &status);
660b5858113SRyan Lee 	if (ret < 0)
661b5858113SRyan Lee 		return -EINVAL;
662b5858113SRyan Lee 
663b5858113SRyan Lee 	if (status) {
664b5858113SRyan Lee 		ret = regmap_read(max98396->regmap, MAX98396_R2042_PCM_CLK_SETUP, &reg);
665b5858113SRyan Lee 		if (ret < 0)
666b5858113SRyan Lee 			return -EINVAL;
667b5858113SRyan Lee 		if (bsel != (reg & MAX98396_PCM_CLK_SETUP_BSEL_MASK)) {
668b5858113SRyan Lee 			update = true;
669b5858113SRyan Lee 		} else {
670b5858113SRyan Lee 			ret = regmap_read(max98396->regmap, MAX98396_R2041_PCM_MODE_CFG, &reg);
671b5858113SRyan Lee 			if (ret < 0)
672b5858113SRyan Lee 				return -EINVAL;
673b5858113SRyan Lee 			if (chan_sz != (reg & MAX98396_PCM_MODE_CFG_CHANSZ_MASK))
674b5858113SRyan Lee 				update = true;
675b5858113SRyan Lee 		}
676b5858113SRyan Lee 
677b5858113SRyan Lee 		/* GLOBAL_EN OFF prior to channel size and BCLK per LRCLK change */
678b5858113SRyan Lee 		if (update)
679b5858113SRyan Lee 			max98396_global_enable_onoff(max98396->regmap, false);
680b5858113SRyan Lee 	}
681b5858113SRyan Lee 
682b5858113SRyan Lee 	regmap_update_bits(max98396->regmap,
683b5858113SRyan Lee 			   MAX98396_R2042_PCM_CLK_SETUP,
684b5858113SRyan Lee 			   MAX98396_PCM_CLK_SETUP_BSEL_MASK,
685b5858113SRyan Lee 			   bsel);
686b5858113SRyan Lee 
687b5858113SRyan Lee 	regmap_update_bits(max98396->regmap,
688b5858113SRyan Lee 			   MAX98396_R2041_PCM_MODE_CFG,
689b5858113SRyan Lee 			   MAX98396_PCM_MODE_CFG_CHANSZ_MASK, chan_sz);
690b5858113SRyan Lee 
691b5858113SRyan Lee 	/* Rx slot configuration */
692b5858113SRyan Lee 	if (max98396->device_id == CODEC_TYPE_MAX98396) {
693b5858113SRyan Lee 		regmap_update_bits(max98396->regmap,
694b5858113SRyan Lee 				   MAX98396_R2056_PCM_RX_SRC2,
695b5858113SRyan Lee 				   MAX98396_PCM_DMIX_CH0_SRC_MASK,
696b5858113SRyan Lee 				   rx_mask);
697b5858113SRyan Lee 		regmap_update_bits(max98396->regmap,
698b5858113SRyan Lee 				   MAX98396_R2056_PCM_RX_SRC2,
699b5858113SRyan Lee 				   MAX98396_PCM_DMIX_CH1_SRC_MASK,
700b5858113SRyan Lee 				   rx_mask << MAX98396_PCM_DMIX_CH1_SHIFT);
701b5858113SRyan Lee 	} else {
702b5858113SRyan Lee 		regmap_update_bits(max98396->regmap,
703b5858113SRyan Lee 				   MAX98397_R2057_PCM_RX_SRC2,
704b5858113SRyan Lee 				   MAX98396_PCM_DMIX_CH0_SRC_MASK,
705b5858113SRyan Lee 				   rx_mask);
706b5858113SRyan Lee 		regmap_update_bits(max98396->regmap,
707b5858113SRyan Lee 				   MAX98397_R2057_PCM_RX_SRC2,
708b5858113SRyan Lee 				   MAX98396_PCM_DMIX_CH1_SRC_MASK,
709b5858113SRyan Lee 				   rx_mask << MAX98396_PCM_DMIX_CH1_SHIFT);
710b5858113SRyan Lee 	}
711b5858113SRyan Lee 
712b5858113SRyan Lee 	/* Tx slot Hi-Z configuration */
713b5858113SRyan Lee 	if (max98396->device_id == CODEC_TYPE_MAX98396) {
714b5858113SRyan Lee 		regmap_write(max98396->regmap,
715b5858113SRyan Lee 			     MAX98396_R2053_PCM_TX_HIZ_CTRL_8,
716b5858113SRyan Lee 			     ~tx_mask & 0xFF);
717b5858113SRyan Lee 		regmap_write(max98396->regmap,
718b5858113SRyan Lee 			     MAX98396_R2052_PCM_TX_HIZ_CTRL_7,
719b5858113SRyan Lee 			     (~tx_mask & 0xFF00) >> 8);
720b5858113SRyan Lee 	} else {
721b5858113SRyan Lee 		regmap_write(max98396->regmap,
722b5858113SRyan Lee 			     MAX98397_R2054_PCM_TX_HIZ_CTRL_8,
723b5858113SRyan Lee 			     ~tx_mask & 0xFF);
724b5858113SRyan Lee 		regmap_write(max98396->regmap,
725b5858113SRyan Lee 			     MAX98397_R2053_PCM_TX_HIZ_CTRL_7,
726b5858113SRyan Lee 			     (~tx_mask & 0xFF00) >> 8);
727b5858113SRyan Lee 	}
728b5858113SRyan Lee 
729b5858113SRyan Lee 	if (status && update)
730b5858113SRyan Lee 		max98396_global_enable_onoff(max98396->regmap, true);
731b5858113SRyan Lee 
732b5858113SRyan Lee 	return 0;
733b5858113SRyan Lee }
734b5858113SRyan Lee 
735b5858113SRyan Lee #define MAX98396_RATES SNDRV_PCM_RATE_8000_192000
736b5858113SRyan Lee 
737b5858113SRyan Lee #define MAX98396_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
738b5858113SRyan Lee 	SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
739b5858113SRyan Lee 
740b5858113SRyan Lee static const struct snd_soc_dai_ops max98396_dai_ops = {
741b5858113SRyan Lee 	.set_fmt = max98396_dai_set_fmt,
742b5858113SRyan Lee 	.hw_params = max98396_dai_hw_params,
743b5858113SRyan Lee 	.set_tdm_slot = max98396_dai_tdm_slot,
744b5858113SRyan Lee };
745b5858113SRyan Lee 
746b5858113SRyan Lee static int max98396_dac_event(struct snd_soc_dapm_widget *w,
747b5858113SRyan Lee 			      struct snd_kcontrol *kcontrol, int event)
748b5858113SRyan Lee {
749b5858113SRyan Lee 	struct snd_soc_component *component =
750b5858113SRyan Lee 		snd_soc_dapm_to_component(w->dapm);
751b5858113SRyan Lee 	struct max98396_priv *max98396 =
752b5858113SRyan Lee 		snd_soc_component_get_drvdata(component);
753b5858113SRyan Lee 
754b5858113SRyan Lee 	switch (event) {
755b5858113SRyan Lee 	case SND_SOC_DAPM_POST_PMU:
756b5858113SRyan Lee 		max98396_global_enable_onoff(max98396->regmap, true);
757b5858113SRyan Lee 		break;
758b5858113SRyan Lee 	case SND_SOC_DAPM_PRE_PMD:
759b5858113SRyan Lee 		max98396_global_enable_onoff(max98396->regmap, false);
760b5858113SRyan Lee 
761b5858113SRyan Lee 		max98396->tdm_mode = false;
762b5858113SRyan Lee 		break;
763b5858113SRyan Lee 	default:
764b5858113SRyan Lee 		return 0;
765b5858113SRyan Lee 	}
766b5858113SRyan Lee 	return 0;
767b5858113SRyan Lee }
768b5858113SRyan Lee 
769b5858113SRyan Lee static bool max98396_readable_register(struct device *dev, unsigned int reg)
770b5858113SRyan Lee {
771b5858113SRyan Lee 	switch (reg) {
772b5858113SRyan Lee 	case MAX98396_R2001_INT_RAW1 ... MAX98396_R2004_INT_RAW4:
773b5858113SRyan Lee 	case MAX98396_R2006_INT_STATE1 ... MAX98396_R2009_INT_STATE4:
774b5858113SRyan Lee 	case MAX98396_R200B_INT_FLAG1 ... MAX98396_R200E_INT_FLAG4:
775b5858113SRyan Lee 	case MAX98396_R2010_INT_EN1 ... MAX98396_R2013_INT_EN4:
776b5858113SRyan Lee 	case MAX98396_R2015_INT_FLAG_CLR1 ... MAX98396_R2018_INT_FLAG_CLR4:
777b5858113SRyan Lee 	case MAX98396_R201F_IRQ_CTRL ... MAX98396_R2024_THERM_FOLDBACK_SET:
778b5858113SRyan Lee 	case MAX98396_R2027_THERM_FOLDBACK_EN:
779b5858113SRyan Lee 	case MAX98396_R2030_NOISEGATE_MODE_CTRL:
780b5858113SRyan Lee 	case MAX98396_R2033_NOISEGATE_MODE_EN:
781b5858113SRyan Lee 	case MAX98396_R2038_CLK_MON_CTRL ... MAX98396_R2039_DATA_MON_CTRL:
782b5858113SRyan Lee 	case MAX98396_R203F_ENABLE_CTRLS ... MAX98396_R2053_PCM_TX_HIZ_CTRL_8:
783b5858113SRyan Lee 	case MAX98396_R2055_PCM_RX_SRC1 ... MAX98396_R2056_PCM_RX_SRC2:
784b5858113SRyan Lee 	case MAX98396_R2058_PCM_BYPASS_SRC:
785b5858113SRyan Lee 	case MAX98396_R205D_PCM_TX_SRC_EN ... MAX98396_R205F_PCM_TX_EN:
786b5858113SRyan Lee 	case MAX98396_R2070_ICC_RX_EN_A... MAX98396_R2072_ICC_TX_CTRL:
787b5858113SRyan Lee 	case MAX98396_R207F_ICC_EN:
788b5858113SRyan Lee 	case MAX98396_R2083_TONE_GEN_DC_CFG ... MAX98396_R2086_TONE_GEN_DC_LVL3:
789b5858113SRyan Lee 	case MAX98396_R208F_TONE_GEN_EN ... MAX98396_R209A_SPK_EDGE_CTRL:
790b5858113SRyan Lee 	case MAX98396_R209C_SPK_EDGE_CTRL1 ... MAX98396_R20A0_AMP_SUPPLY_CTL:
791b5858113SRyan Lee 	case MAX98396_R20AF_AMP_EN ... MAX98396_R20BF_ADC_LO_VBAT_READBACK_LSB:
792b5858113SRyan Lee 	case MAX98396_R20C7_ADC_CFG:
793b5858113SRyan Lee 	case MAX98396_R20D0_DHT_CFG1 ... MAX98396_R20D6_DHT_HYSTERESIS_CFG:
794b5858113SRyan Lee 	case MAX98396_R20DF_DHT_EN:
795b5858113SRyan Lee 	case MAX98396_R20E0_IV_SENSE_PATH_CFG:
796b5858113SRyan Lee 	case MAX98396_R20E4_IV_SENSE_PATH_EN
797b5858113SRyan Lee 		... MAX98396_R2106_BPE_THRESH_HYSTERESIS:
798b5858113SRyan Lee 	case MAX98396_R2108_BPE_SUPPLY_SRC ... MAX98396_R210B_BPE_LOW_LIMITER:
799b5858113SRyan Lee 	case MAX98396_R210D_BPE_EN ... MAX98396_R210F_GLOBAL_EN:
800b5858113SRyan Lee 	case MAX98396_R21FF_REVISION_ID:
801b5858113SRyan Lee 		return true;
802b5858113SRyan Lee 	default:
803b5858113SRyan Lee 		return false;
804b5858113SRyan Lee 	}
805b5858113SRyan Lee };
806b5858113SRyan Lee 
807b5858113SRyan Lee static bool max98396_volatile_reg(struct device *dev, unsigned int reg)
808b5858113SRyan Lee {
809b5858113SRyan Lee 	switch (reg) {
810b5858113SRyan Lee 	case MAX98396_R2000_SW_RESET:
811b5858113SRyan Lee 	case MAX98396_R2001_INT_RAW1 ... MAX98396_R200E_INT_FLAG4:
812b5858113SRyan Lee 	case MAX98396_R2041_PCM_MODE_CFG:
813b5858113SRyan Lee 	case MAX98396_R20B6_ADC_PVDD_READBACK_MSB
814b5858113SRyan Lee 		... MAX98396_R20BF_ADC_LO_VBAT_READBACK_LSB:
815b5858113SRyan Lee 	case MAX98396_R20E5_BPE_STATE:
816b5858113SRyan Lee 	case MAX98396_R2109_BPE_LOW_STATE
817b5858113SRyan Lee 		... MAX98396_R210B_BPE_LOW_LIMITER:
818b5858113SRyan Lee 	case MAX98396_R210F_GLOBAL_EN:
819b5858113SRyan Lee 	case MAX98396_R21FF_REVISION_ID:
820b5858113SRyan Lee 		return true;
821b5858113SRyan Lee 	default:
822b5858113SRyan Lee 		return false;
823b5858113SRyan Lee 	}
824b5858113SRyan Lee }
825b5858113SRyan Lee 
826b5858113SRyan Lee static bool max98397_readable_register(struct device *dev, unsigned int reg)
827b5858113SRyan Lee {
828b5858113SRyan Lee 	switch (reg) {
829b5858113SRyan Lee 	case MAX98396_R2001_INT_RAW1 ... MAX98396_R2004_INT_RAW4:
830b5858113SRyan Lee 	case MAX98396_R2006_INT_STATE1 ... MAX98396_R2009_INT_STATE4:
831b5858113SRyan Lee 	case MAX98396_R200B_INT_FLAG1 ... MAX98396_R200E_INT_FLAG4:
832b5858113SRyan Lee 	case MAX98396_R2010_INT_EN1 ... MAX98396_R2013_INT_EN4:
833b5858113SRyan Lee 	case MAX98396_R2015_INT_FLAG_CLR1 ... MAX98396_R2018_INT_FLAG_CLR4:
834b5858113SRyan Lee 	case MAX98396_R201F_IRQ_CTRL ... MAX98396_R2024_THERM_FOLDBACK_SET:
835b5858113SRyan Lee 	case MAX98396_R2027_THERM_FOLDBACK_EN:
836b5858113SRyan Lee 	case MAX98396_R2030_NOISEGATE_MODE_CTRL:
837b5858113SRyan Lee 	case MAX98396_R2033_NOISEGATE_MODE_EN:
838b5858113SRyan Lee 	case MAX98396_R2038_CLK_MON_CTRL ... MAX98397_R203A_SPK_MON_THRESH:
839b5858113SRyan Lee 	case MAX98396_R203F_ENABLE_CTRLS ... MAX98397_R2054_PCM_TX_HIZ_CTRL_8:
840b5858113SRyan Lee 	case MAX98397_R2056_PCM_RX_SRC1... MAX98396_R2058_PCM_BYPASS_SRC:
841b5858113SRyan Lee 	case MAX98396_R205D_PCM_TX_SRC_EN ... MAX98397_R2060_PCM_TX_SUPPLY_SEL:
842b5858113SRyan Lee 	case MAX98396_R2070_ICC_RX_EN_A... MAX98396_R2072_ICC_TX_CTRL:
843b5858113SRyan Lee 	case MAX98396_R207F_ICC_EN:
844b5858113SRyan Lee 	case MAX98396_R2083_TONE_GEN_DC_CFG ... MAX98396_R2086_TONE_GEN_DC_LVL3:
845b5858113SRyan Lee 	case MAX98396_R208F_TONE_GEN_EN ... MAX98396_R209F_BYPASS_PATH_CFG:
846b5858113SRyan Lee 	case MAX98396_R20AF_AMP_EN ... MAX98397_R20C5_MEAS_ADC_OPTIMAL_MODE:
847b5858113SRyan Lee 	case MAX98396_R20C7_ADC_CFG:
848b5858113SRyan Lee 	case MAX98396_R20D0_DHT_CFG1 ... MAX98396_R20D6_DHT_HYSTERESIS_CFG:
849b5858113SRyan Lee 	case MAX98396_R20DF_DHT_EN:
850b5858113SRyan Lee 	case MAX98396_R20E0_IV_SENSE_PATH_CFG:
851b5858113SRyan Lee 	case MAX98396_R20E4_IV_SENSE_PATH_EN
852b5858113SRyan Lee 		... MAX98396_R2106_BPE_THRESH_HYSTERESIS:
853b5858113SRyan Lee 	case MAX98396_R2108_BPE_SUPPLY_SRC ... MAX98396_R210B_BPE_LOW_LIMITER:
854b5858113SRyan Lee 	case MAX98396_R210D_BPE_EN ... MAX98396_R210F_GLOBAL_EN:
855b5858113SRyan Lee 	case MAX98397_R22FF_REVISION_ID:
856b5858113SRyan Lee 		return true;
857b5858113SRyan Lee 	default:
858b5858113SRyan Lee 		return false;
859b5858113SRyan Lee 	}
860b5858113SRyan Lee };
861b5858113SRyan Lee 
862b5858113SRyan Lee static bool max98397_volatile_reg(struct device *dev, unsigned int reg)
863b5858113SRyan Lee {
864b5858113SRyan Lee 	switch (reg) {
865b5858113SRyan Lee 	case MAX98396_R2001_INT_RAW1 ... MAX98396_R200E_INT_FLAG4:
866b5858113SRyan Lee 	case MAX98396_R2041_PCM_MODE_CFG:
867b5858113SRyan Lee 	case MAX98397_R20B7_ADC_PVDD_READBACK_MSB
868b5858113SRyan Lee 		... MAX98397_R20C4_ADC_LO_VDDH_READBACK_LSB:
869b5858113SRyan Lee 	case MAX98396_R20E5_BPE_STATE:
870b5858113SRyan Lee 	case MAX98396_R2109_BPE_LOW_STATE
871b5858113SRyan Lee 		... MAX98396_R210B_BPE_LOW_LIMITER:
872b5858113SRyan Lee 	case MAX98396_R210F_GLOBAL_EN:
873b5858113SRyan Lee 	case MAX98397_R22FF_REVISION_ID:
874b5858113SRyan Lee 		return true;
875b5858113SRyan Lee 	default:
876b5858113SRyan Lee 		return false;
877b5858113SRyan Lee 	}
878b5858113SRyan Lee }
879b5858113SRyan Lee 
880b5858113SRyan Lee static const char * const max98396_op_mod_text[] = {
881b5858113SRyan Lee 	"DG", "PVDD", "VBAT",
882b5858113SRyan Lee };
883b5858113SRyan Lee 
884b5858113SRyan Lee static SOC_ENUM_SINGLE_DECL(max98396_op_mod_enum,
885b5858113SRyan Lee 			    MAX98396_R2098_SPK_CLS_DG_MODE,
886b5858113SRyan Lee 			    0, max98396_op_mod_text);
887b5858113SRyan Lee 
888b5858113SRyan Lee static DECLARE_TLV_DB_SCALE(max98396_digital_tlv, -6350, 50, 1);
889b5858113SRyan Lee static const DECLARE_TLV_DB_RANGE(max98396_spk_tlv,
890b5858113SRyan Lee 	0, 0x11, TLV_DB_SCALE_ITEM(400, 100, 0),
891b5858113SRyan Lee );
892b5858113SRyan Lee static DECLARE_TLV_DB_RANGE(max98397_digital_tlv,
893b5858113SRyan Lee 	0, 0x4A, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 1),
894b5858113SRyan Lee 	0x4B, 0xFF, TLV_DB_SCALE_ITEM(-9000, 50, 0),
895b5858113SRyan Lee );
896b5858113SRyan Lee static const DECLARE_TLV_DB_RANGE(max98397_spk_tlv,
897b5858113SRyan Lee 	0, 0x15, TLV_DB_SCALE_ITEM(600, 100, 0),
898b5858113SRyan Lee );
899b5858113SRyan Lee 
900b5858113SRyan Lee static int max98396_mux_get(struct snd_kcontrol *kcontrol,
901b5858113SRyan Lee 			    struct snd_ctl_elem_value *ucontrol)
902b5858113SRyan Lee {
903b5858113SRyan Lee 	struct snd_soc_component *component =
904b5858113SRyan Lee 		snd_soc_dapm_kcontrol_component(kcontrol);
905b5858113SRyan Lee 	struct max98396_priv *max98396 = snd_soc_component_get_drvdata(component);
906b5858113SRyan Lee 	int reg, val;
907b5858113SRyan Lee 
908b5858113SRyan Lee 	if (max98396->device_id == CODEC_TYPE_MAX98396)
909b5858113SRyan Lee 		reg = MAX98396_R2055_PCM_RX_SRC1;
910b5858113SRyan Lee 	else
911b5858113SRyan Lee 		reg = MAX98397_R2056_PCM_RX_SRC1;
912b5858113SRyan Lee 
913b5858113SRyan Lee 	regmap_read(max98396->regmap, reg, &val);
914b5858113SRyan Lee 
915b5858113SRyan Lee 	ucontrol->value.enumerated.item[0] = val;
916b5858113SRyan Lee 
917b5858113SRyan Lee 	return 0;
918b5858113SRyan Lee }
919b5858113SRyan Lee 
920b5858113SRyan Lee static int max98396_mux_put(struct snd_kcontrol *kcontrol,
921b5858113SRyan Lee 			    struct snd_ctl_elem_value *ucontrol)
922b5858113SRyan Lee {
923b5858113SRyan Lee 	struct snd_soc_component *component =
924b5858113SRyan Lee 		snd_soc_dapm_kcontrol_component(kcontrol);
925b5858113SRyan Lee 	struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
926b5858113SRyan Lee 	struct max98396_priv *max98396 = snd_soc_component_get_drvdata(component);
927b5858113SRyan Lee 	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
928b5858113SRyan Lee 	unsigned int *item = ucontrol->value.enumerated.item;
929b5858113SRyan Lee 	int reg, val;
930b5858113SRyan Lee 	int change;
931b5858113SRyan Lee 
932b5858113SRyan Lee 	if (item[0] >= e->items)
933b5858113SRyan Lee 		return -EINVAL;
934b5858113SRyan Lee 
935b5858113SRyan Lee 	val = snd_soc_enum_item_to_val(e, item[0]) << e->shift_l;
936b5858113SRyan Lee 
937b5858113SRyan Lee 	if (max98396->device_id == CODEC_TYPE_MAX98396)
938b5858113SRyan Lee 		reg = MAX98396_R2055_PCM_RX_SRC1;
939b5858113SRyan Lee 	else
940b5858113SRyan Lee 		reg = MAX98397_R2056_PCM_RX_SRC1;
941b5858113SRyan Lee 
942b5858113SRyan Lee 	change = snd_soc_component_test_bits(component, reg,
943b5858113SRyan Lee 					     MAX98396_PCM_RX_MASK, val);
944b5858113SRyan Lee 
945b5858113SRyan Lee 	if (change)
946b5858113SRyan Lee 		regmap_update_bits(max98396->regmap, reg,
947b5858113SRyan Lee 				   MAX98396_PCM_RX_MASK, val);
948b5858113SRyan Lee 
949b5858113SRyan Lee 	snd_soc_dapm_mux_update_power(dapm, kcontrol, item[0], e, NULL);
950b5858113SRyan Lee 
951b5858113SRyan Lee 	return change;
952b5858113SRyan Lee }
953b5858113SRyan Lee 
954b5858113SRyan Lee static const char * const max98396_switch_text[] = {
955b5858113SRyan Lee 	"Left", "Right", "LeftRight"};
956b5858113SRyan Lee 
957b5858113SRyan Lee static SOC_ENUM_SINGLE_DECL(dai_sel_enum, SND_SOC_NOPM, 0,
958b5858113SRyan Lee 			    max98396_switch_text);
959b5858113SRyan Lee 
960b5858113SRyan Lee static const struct snd_kcontrol_new max98396_dai_mux =
961b5858113SRyan Lee 	SOC_DAPM_ENUM_EXT("DAI Sel Mux", dai_sel_enum,
962b5858113SRyan Lee 			  max98396_mux_get, max98396_mux_put);
963b5858113SRyan Lee 
964b5858113SRyan Lee static const struct snd_kcontrol_new max98396_vi_control =
965b5858113SRyan Lee 	SOC_DAPM_SINGLE("Switch", MAX98396_R205F_PCM_TX_EN, 0, 1, 0);
966b5858113SRyan Lee 
967b5858113SRyan Lee static const struct snd_soc_dapm_widget max98396_dapm_widgets[] = {
968b5858113SRyan Lee 	SND_SOC_DAPM_DAC_E("Amp Enable", "HiFi Playback",
969b5858113SRyan Lee 			   MAX98396_R20AF_AMP_EN, 0, 0, max98396_dac_event,
970b5858113SRyan Lee 			   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
971b5858113SRyan Lee 	SND_SOC_DAPM_MUX("DAI Sel Mux", SND_SOC_NOPM, 0, 0,
972b5858113SRyan Lee 			 &max98396_dai_mux),
973b5858113SRyan Lee 	SND_SOC_DAPM_OUTPUT("BE_OUT"),
974b5858113SRyan Lee 	SND_SOC_DAPM_AIF_OUT("Voltage Sense", "HiFi Capture", 0,
975b5858113SRyan Lee 			     MAX98396_R20E4_IV_SENSE_PATH_EN, 0, 0),
976b5858113SRyan Lee 	SND_SOC_DAPM_AIF_OUT("Current Sense", "HiFi Capture", 0,
977b5858113SRyan Lee 			     MAX98396_R20E4_IV_SENSE_PATH_EN, 1, 0),
978b5858113SRyan Lee 	SND_SOC_DAPM_SWITCH("VI Sense", SND_SOC_NOPM, 0, 0,
979b5858113SRyan Lee 			    &max98396_vi_control),
980b5858113SRyan Lee 	SND_SOC_DAPM_SIGGEN("VMON"),
981b5858113SRyan Lee 	SND_SOC_DAPM_SIGGEN("IMON"),
982b5858113SRyan Lee 	SND_SOC_DAPM_SIGGEN("FBMON"),
983b5858113SRyan Lee };
984b5858113SRyan Lee 
985b5858113SRyan Lee static const char * const max98396_thermal_thresh_text[] = {
986b5858113SRyan Lee 	"50C", "51C", "52C", "53C", "54C", "55C", "56C", "57C",
987b5858113SRyan Lee 	"58C", "59C", "60C", "61C", "62C", "63C", "64C", "65C",
988b5858113SRyan Lee 	"66C", "67C", "68C", "69C", "70C", "71C", "72C", "73C",
989b5858113SRyan Lee 	"74C", "75C", "76C", "77C", "78C", "79C", "80C", "81C",
990b5858113SRyan Lee 	"82C", "83C", "84C", "85C", "86C", "87C", "88C", "89C",
991b5858113SRyan Lee 	"90C", "91C", "92C", "93C", "94C", "95C", "96C", "97C",
992b5858113SRyan Lee 	"98C", "99C", "100C", "101C", "102C", "103C", "104C", "105C",
993b5858113SRyan Lee 	"106C", "107C", "108C", "109C", "110C", "111C", "112C", "113C",
994b5858113SRyan Lee 	"114C", "115C", "116C", "117C", "118C", "119C", "120C", "121C",
995b5858113SRyan Lee 	"122C", "123C", "124C", "125C", "126C", "127C", "128C", "129C",
996b5858113SRyan Lee 	"130C", "131C", "132C", "133C", "134C", "135C", "136C", "137C",
997b5858113SRyan Lee 	"138C", "139C", "140C", "141C", "142C", "143C", "144C", "145C",
998b5858113SRyan Lee 	"146C", "147C", "148C", "149C", "150C"
999b5858113SRyan Lee };
1000b5858113SRyan Lee 
1001b5858113SRyan Lee static SOC_ENUM_SINGLE_DECL(max98396_thermal_warn_thresh1_enum,
1002b5858113SRyan Lee 			    MAX98396_R2020_THERM_WARN_THRESH, 0,
1003b5858113SRyan Lee 			    max98396_thermal_thresh_text);
1004b5858113SRyan Lee 
1005b5858113SRyan Lee static SOC_ENUM_SINGLE_DECL(max98396_thermal_warn_thresh2_enum,
1006b5858113SRyan Lee 			    MAX98396_R2021_THERM_WARN_THRESH2, 0,
1007b5858113SRyan Lee 			    max98396_thermal_thresh_text);
1008b5858113SRyan Lee 
1009b5858113SRyan Lee static SOC_ENUM_SINGLE_DECL(max98396_thermal_shdn_thresh_enum,
1010b5858113SRyan Lee 			    MAX98396_R2022_THERM_SHDN_THRESH, 0,
1011b5858113SRyan Lee 			    max98396_thermal_thresh_text);
1012b5858113SRyan Lee 
1013b5858113SRyan Lee static const char * const max98396_thermal_hyteresis_text[] = {
1014b5858113SRyan Lee 	"2C", "5C", "7C", "10C"
1015b5858113SRyan Lee };
1016b5858113SRyan Lee 
1017b5858113SRyan Lee static SOC_ENUM_SINGLE_DECL(max98396_thermal_hysteresis_enum,
1018b5858113SRyan Lee 			    MAX98396_R2023_THERM_HYSTERESIS, 0,
1019b5858113SRyan Lee 			    max98396_thermal_hyteresis_text);
1020b5858113SRyan Lee 
1021b5858113SRyan Lee static const char * const max98396_foldback_slope_text[] = {
1022b5858113SRyan Lee 	"0.25", "0.5", "1.0", "2.0"
1023b5858113SRyan Lee };
1024b5858113SRyan Lee 
1025b5858113SRyan Lee static SOC_ENUM_SINGLE_DECL(max98396_thermal_fb_slope1_enum,
1026b5858113SRyan Lee 			    MAX98396_R2024_THERM_FOLDBACK_SET,
1027b5858113SRyan Lee 			    MAX98396_THERM_FB_SLOPE1_SHIFT,
1028b5858113SRyan Lee 			    max98396_foldback_slope_text);
1029b5858113SRyan Lee 
1030b5858113SRyan Lee static SOC_ENUM_SINGLE_DECL(max98396_thermal_fb_slope2_enum,
1031b5858113SRyan Lee 			    MAX98396_R2024_THERM_FOLDBACK_SET,
1032b5858113SRyan Lee 			    MAX98396_THERM_FB_SLOPE2_SHIFT,
1033b5858113SRyan Lee 			    max98396_foldback_slope_text);
1034b5858113SRyan Lee 
1035b5858113SRyan Lee static const char * const max98396_foldback_reltime_text[] = {
1036b5858113SRyan Lee 	"3ms", "10ms", "100ms", "300ms"
1037b5858113SRyan Lee };
1038b5858113SRyan Lee 
1039b5858113SRyan Lee static SOC_ENUM_SINGLE_DECL(max98396_thermal_fb_reltime_enum,
1040b5858113SRyan Lee 			    MAX98396_R2024_THERM_FOLDBACK_SET,
1041b5858113SRyan Lee 			    MAX98396_THERM_FB_REL_SHIFT,
1042b5858113SRyan Lee 			    max98396_foldback_reltime_text);
1043b5858113SRyan Lee 
1044b5858113SRyan Lee static const char * const max98396_foldback_holdtime_text[] = {
1045b5858113SRyan Lee 	"0ms", "20ms", "40ms", "80ms"
1046b5858113SRyan Lee };
1047b5858113SRyan Lee 
1048b5858113SRyan Lee static SOC_ENUM_SINGLE_DECL(max98396_thermal_fb_holdtime_enum,
1049b5858113SRyan Lee 			    MAX98396_R2024_THERM_FOLDBACK_SET,
1050b5858113SRyan Lee 			    MAX98396_THERM_FB_HOLD_SHIFT,
1051b5858113SRyan Lee 			    max98396_foldback_holdtime_text);
1052b5858113SRyan Lee 
1053b5858113SRyan Lee static int max98396_adc_value_get(struct snd_kcontrol *kcontrol,
1054b5858113SRyan Lee 				  struct snd_ctl_elem_value *ucontrol)
1055b5858113SRyan Lee {
1056b5858113SRyan Lee 	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
1057b5858113SRyan Lee 	struct soc_mixer_control *mc =
1058b5858113SRyan Lee 		(struct soc_mixer_control *)kcontrol->private_value;
1059b5858113SRyan Lee 	struct max98396_priv *max98396 = snd_soc_component_get_drvdata(component);
1060b5858113SRyan Lee 	int ret;
1061b5858113SRyan Lee 	u8 val[2];
1062b5858113SRyan Lee 	int reg = mc->reg;
1063b5858113SRyan Lee 
1064b5858113SRyan Lee 	/* ADC value is not available if the device is powered down */
1065b5858113SRyan Lee 	if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF)
1066b5858113SRyan Lee 		goto exit;
1067b5858113SRyan Lee 
1068b5858113SRyan Lee 	if (max98396->device_id == CODEC_TYPE_MAX98397) {
1069b5858113SRyan Lee 		switch (mc->reg) {
1070b5858113SRyan Lee 		case MAX98396_R20B6_ADC_PVDD_READBACK_MSB:
1071b5858113SRyan Lee 			reg = MAX98397_R20B7_ADC_PVDD_READBACK_MSB;
1072b5858113SRyan Lee 			break;
1073b5858113SRyan Lee 		case MAX98396_R20B8_ADC_VBAT_READBACK_MSB:
1074b5858113SRyan Lee 			reg = MAX98397_R20B9_ADC_VBAT_READBACK_MSB;
1075b5858113SRyan Lee 			break;
1076b5858113SRyan Lee 		case MAX98396_R20BA_ADC_TEMP_READBACK_MSB:
1077b5858113SRyan Lee 			reg = MAX98397_R20BB_ADC_TEMP_READBACK_MSB;
1078b5858113SRyan Lee 			break;
1079b5858113SRyan Lee 		default:
1080b5858113SRyan Lee 			goto exit;
1081b5858113SRyan Lee 		}
1082b5858113SRyan Lee 	}
1083b5858113SRyan Lee 
1084b5858113SRyan Lee 	ret = regmap_raw_read(max98396->regmap, reg, &val, 2);
1085b5858113SRyan Lee 	if (ret)
1086b5858113SRyan Lee 		goto exit;
1087b5858113SRyan Lee 
1088b5858113SRyan Lee 	/* ADC readback bits[8:0] rearrangement */
1089b5858113SRyan Lee 	ucontrol->value.integer.value[0] = (val[0] << 1) | (val[1] & 1);
1090b5858113SRyan Lee 	return 0;
1091b5858113SRyan Lee 
1092b5858113SRyan Lee exit:
1093b5858113SRyan Lee 	ucontrol->value.integer.value[0] = 0;
1094b5858113SRyan Lee 	return 0;
1095b5858113SRyan Lee }
1096b5858113SRyan Lee 
1097b5858113SRyan Lee static const struct snd_kcontrol_new max98396_snd_controls[] = {
1098b5858113SRyan Lee 	/* Volume */
1099b5858113SRyan Lee 	SOC_SINGLE_TLV("Digital Volume", MAX98396_R2090_AMP_VOL_CTRL,
1100b5858113SRyan Lee 		       0, 0x7F, 1, max98396_digital_tlv),
1101b5858113SRyan Lee 	SOC_SINGLE_TLV("Speaker Volume", MAX98396_R2091_AMP_PATH_GAIN,
1102b5858113SRyan Lee 		       0, 0x11, 0, max98396_spk_tlv),
1103b5858113SRyan Lee 	/* Volume Ramp Up/Down Enable*/
1104b5858113SRyan Lee 	SOC_SINGLE("Ramp Up Switch", MAX98396_R2092_AMP_DSP_CFG,
1105b5858113SRyan Lee 		   MAX98396_DSP_SPK_VOL_RMPUP_SHIFT, 1, 0),
1106b5858113SRyan Lee 	SOC_SINGLE("Ramp Down Switch", MAX98396_R2092_AMP_DSP_CFG,
1107b5858113SRyan Lee 		   MAX98396_DSP_SPK_VOL_RMPDN_SHIFT, 1, 0),
1108b5858113SRyan Lee 	/* Clock Monitor Enable */
1109b5858113SRyan Lee 	SOC_SINGLE("CLK Monitor Switch", MAX98396_R203F_ENABLE_CTRLS,
1110b5858113SRyan Lee 		   MAX98396_CTRL_CMON_EN_SHIFT, 1, 0),
1111b5858113SRyan Lee 	/* Dither Enable */
1112b5858113SRyan Lee 	SOC_SINGLE("Dither Switch", MAX98396_R2092_AMP_DSP_CFG,
1113b5858113SRyan Lee 		   MAX98396_DSP_SPK_DITH_EN_SHIFT, 1, 0),
1114b5858113SRyan Lee 	SOC_SINGLE("IV Dither Switch", MAX98396_R20E0_IV_SENSE_PATH_CFG,
1115b5858113SRyan Lee 		   MAX98396_IV_SENSE_DITH_EN_SHIFT, 1, 0),
1116b5858113SRyan Lee 	/* DC Blocker Enable */
1117b5858113SRyan Lee 	SOC_SINGLE("DC Blocker Switch", MAX98396_R2092_AMP_DSP_CFG,
1118b5858113SRyan Lee 		   MAX98396_DSP_SPK_DCBLK_EN_SHIFT, 1, 0),
1119b5858113SRyan Lee 	SOC_SINGLE("IV DC Blocker Switch", MAX98396_R20E0_IV_SENSE_PATH_CFG,
1120b5858113SRyan Lee 		   MAX98396_IV_SENSE_DCBLK_EN_SHIFT, 3, 0),
1121b5858113SRyan Lee 	/* Speaker Safe Mode Enable */
1122b5858113SRyan Lee 	SOC_SINGLE("Safe Mode Switch", MAX98396_R2092_AMP_DSP_CFG,
1123b5858113SRyan Lee 		   MAX98396_DSP_SPK_SAFE_EN_SHIFT, 1, 0),
1124b5858113SRyan Lee 	/* Wideband Filter Enable */
1125b5858113SRyan Lee 	SOC_SINGLE("WB Filter Switch", MAX98396_R2092_AMP_DSP_CFG,
1126b5858113SRyan Lee 		   MAX98396_DSP_SPK_WB_FLT_EN_SHIFT, 1, 0),
1127b5858113SRyan Lee 	SOC_SINGLE("IV WB Filter Switch", MAX98396_R20E0_IV_SENSE_PATH_CFG,
1128b5858113SRyan Lee 		   MAX98396_IV_SENSE_WB_FLT_EN_SHIFT, 1, 0),
1129b5858113SRyan Lee 	/* Dynamic Headroom Tracking */
1130b5858113SRyan Lee 	SOC_SINGLE("DHT Switch", MAX98396_R20DF_DHT_EN, 0, 1, 0),
1131b5858113SRyan Lee 	/* Brownout Protection Engine */
1132b5858113SRyan Lee 	SOC_SINGLE("BPE Switch", MAX98396_R210D_BPE_EN, 0, 1, 0),
1133b5858113SRyan Lee 	SOC_SINGLE("BPE Limiter Switch", MAX98396_R210D_BPE_EN, 1, 1, 0),
1134b5858113SRyan Lee 	/* Bypass Path Enable */
1135b5858113SRyan Lee 	SOC_SINGLE("Bypass Path Switch",
1136b5858113SRyan Lee 		   MAX98396_R205E_PCM_RX_EN, 1, 1, 0),
1137b5858113SRyan Lee 	/* Speaker Operation Mode */
1138b5858113SRyan Lee 	SOC_ENUM("OP Mode", max98396_op_mod_enum),
1139b5858113SRyan Lee 	/* Auto Restart functions */
1140b5858113SRyan Lee 	SOC_SINGLE("CMON Auto Restart Switch", MAX98396_R2038_CLK_MON_CTRL,
1141b5858113SRyan Lee 		   MAX98396_CLK_MON_AUTO_RESTART_SHIFT, 1, 0),
1142b5858113SRyan Lee 	SOC_SINGLE("PVDD Auto Restart Switch", MAX98396_R210E_AUTO_RESTART,
1143b5858113SRyan Lee 		   MAX98396_PVDD_UVLO_RESTART_SHFT, 1, 0),
1144b5858113SRyan Lee 	SOC_SINGLE("VBAT Auto Restart Switch", MAX98396_R210E_AUTO_RESTART,
1145b5858113SRyan Lee 		   MAX98396_VBAT_UVLO_RESTART_SHFT, 1, 0),
1146b5858113SRyan Lee 	SOC_SINGLE("THERM Auto Restart Switch", MAX98396_R210E_AUTO_RESTART,
1147b5858113SRyan Lee 		   MAX98396_THEM_SHDN_RESTART_SHFT, 1, 0),
1148b5858113SRyan Lee 	SOC_SINGLE("OVC Auto Restart Switch", MAX98396_R210E_AUTO_RESTART,
1149b5858113SRyan Lee 		   MAX98396_OVC_RESTART_SHFT, 1, 0),
1150b5858113SRyan Lee 	/* Thermal Threshold */
1151b5858113SRyan Lee 	SOC_ENUM("THERM Thresh1", max98396_thermal_warn_thresh1_enum),
1152b5858113SRyan Lee 	SOC_ENUM("THERM Thresh2", max98396_thermal_warn_thresh2_enum),
1153b5858113SRyan Lee 	SOC_ENUM("THERM SHDN Thresh", max98396_thermal_shdn_thresh_enum),
1154b5858113SRyan Lee 	SOC_ENUM("THERM Hysteresis", max98396_thermal_hysteresis_enum),
1155b5858113SRyan Lee 	SOC_SINGLE("THERM Foldback Switch",
1156b5858113SRyan Lee 		   MAX98396_R2027_THERM_FOLDBACK_EN, 0, 1, 0),
1157b5858113SRyan Lee 	SOC_ENUM("THERM Slope1", max98396_thermal_fb_slope1_enum),
1158b5858113SRyan Lee 	SOC_ENUM("THERM Slope2", max98396_thermal_fb_slope2_enum),
1159b5858113SRyan Lee 	SOC_ENUM("THERM Release", max98396_thermal_fb_reltime_enum),
1160b5858113SRyan Lee 	SOC_ENUM("THERM Hold", max98396_thermal_fb_holdtime_enum),
1161b5858113SRyan Lee 	/* ADC */
1162b5858113SRyan Lee 	SOC_SINGLE_EXT("ADC PVDD", MAX98396_R20B6_ADC_PVDD_READBACK_MSB, 0, 0x1FF, 0,
1163b5858113SRyan Lee 		       max98396_adc_value_get, NULL),
1164b5858113SRyan Lee 	SOC_SINGLE_EXT("ADC VBAT", MAX98396_R20B8_ADC_VBAT_READBACK_MSB, 0, 0x1FF, 0,
1165b5858113SRyan Lee 		       max98396_adc_value_get, NULL),
1166b5858113SRyan Lee 	SOC_SINGLE_EXT("ADC TEMP", MAX98396_R20BA_ADC_TEMP_READBACK_MSB, 0, 0x1FF, 0,
1167b5858113SRyan Lee 		       max98396_adc_value_get, NULL),
1168b5858113SRyan Lee };
1169b5858113SRyan Lee 
1170b5858113SRyan Lee static const struct snd_kcontrol_new max98397_snd_controls[] = {
1171b5858113SRyan Lee 	/* Volume */
1172b5858113SRyan Lee 	SOC_SINGLE_TLV("Digital Volume", MAX98396_R2090_AMP_VOL_CTRL,
1173b5858113SRyan Lee 		       0, 0xFF, 1, max98397_digital_tlv),
1174b5858113SRyan Lee 	SOC_SINGLE_TLV("Speaker Volume", MAX98396_R2091_AMP_PATH_GAIN,
1175b5858113SRyan Lee 		       0, 0x15, 0, max98397_spk_tlv),
1176b5858113SRyan Lee 	/* Volume Ramp Up/Down Enable*/
1177b5858113SRyan Lee 	SOC_SINGLE("Ramp Up Switch", MAX98396_R2092_AMP_DSP_CFG,
1178b5858113SRyan Lee 		   MAX98396_DSP_SPK_VOL_RMPUP_SHIFT, 1, 0),
1179b5858113SRyan Lee 	SOC_SINGLE("Ramp Down Switch", MAX98396_R2092_AMP_DSP_CFG,
1180b5858113SRyan Lee 		   MAX98396_DSP_SPK_VOL_RMPDN_SHIFT, 1, 0),
1181b5858113SRyan Lee 	/* Clock Monitor Enable */
1182b5858113SRyan Lee 	SOC_SINGLE("CLK Monitor Switch", MAX98396_R203F_ENABLE_CTRLS,
1183b5858113SRyan Lee 		   MAX98396_CTRL_CMON_EN_SHIFT, 1, 0),
1184b5858113SRyan Lee 	/* Dither Enable */
1185b5858113SRyan Lee 	SOC_SINGLE("Dither Switch", MAX98396_R2092_AMP_DSP_CFG,
1186b5858113SRyan Lee 		   MAX98396_DSP_SPK_DITH_EN_SHIFT, 1, 0),
1187b5858113SRyan Lee 	SOC_SINGLE("IV Dither Switch", MAX98396_R20E0_IV_SENSE_PATH_CFG,
1188b5858113SRyan Lee 		   MAX98396_IV_SENSE_DITH_EN_SHIFT, 1, 0),
1189b5858113SRyan Lee 	/* DC Blocker Enable */
1190b5858113SRyan Lee 	SOC_SINGLE("DC Blocker Switch", MAX98396_R2092_AMP_DSP_CFG,
1191b5858113SRyan Lee 		   MAX98396_DSP_SPK_DCBLK_EN_SHIFT, 1, 0),
1192b5858113SRyan Lee 	SOC_SINGLE("IV DC Blocker Switch", MAX98396_R20E0_IV_SENSE_PATH_CFG,
1193b5858113SRyan Lee 		   MAX98396_IV_SENSE_DCBLK_EN_SHIFT, 3, 0),
1194b5858113SRyan Lee 	/* Speaker Safe Mode Enable */
1195b5858113SRyan Lee 	SOC_SINGLE("Safe Mode Switch", MAX98396_R2092_AMP_DSP_CFG,
1196b5858113SRyan Lee 		   MAX98396_DSP_SPK_SAFE_EN_SHIFT, 1, 0),
1197b5858113SRyan Lee 	/* Wideband Filter Enable */
1198b5858113SRyan Lee 	SOC_SINGLE("WB Filter Switch", MAX98396_R2092_AMP_DSP_CFG,
1199b5858113SRyan Lee 		   MAX98396_DSP_SPK_WB_FLT_EN_SHIFT, 1, 0),
1200b5858113SRyan Lee 	SOC_SINGLE("IV WB Filter Switch", MAX98396_R20E0_IV_SENSE_PATH_CFG,
1201b5858113SRyan Lee 		   MAX98396_IV_SENSE_WB_FLT_EN_SHIFT, 1, 0),
1202b5858113SRyan Lee 	/* Dynamic Headroom Tracking */
1203b5858113SRyan Lee 	SOC_SINGLE("DHT Switch", MAX98396_R20DF_DHT_EN, 0, 1, 0),
1204b5858113SRyan Lee 	/* Brownout Protection Engine */
1205b5858113SRyan Lee 	SOC_SINGLE("BPE Switch", MAX98396_R210D_BPE_EN, 0, 1, 0),
1206b5858113SRyan Lee 	SOC_SINGLE("BPE Limiter Switch", MAX98396_R210D_BPE_EN, 1, 1, 0),
1207b5858113SRyan Lee 	/* Bypass Path Enable */
1208b5858113SRyan Lee 	SOC_SINGLE("Bypass Path Switch",
1209b5858113SRyan Lee 		   MAX98396_R205E_PCM_RX_EN, 1, 1, 0),
1210b5858113SRyan Lee 	/* Speaker Operation Mode */
1211b5858113SRyan Lee 	SOC_ENUM("OP Mode", max98396_op_mod_enum),
1212b5858113SRyan Lee 	/* Auto Restart functions */
1213b5858113SRyan Lee 	SOC_SINGLE("CMON Auto Restart Switch", MAX98396_R2038_CLK_MON_CTRL,
1214b5858113SRyan Lee 		   MAX98396_CLK_MON_AUTO_RESTART_SHIFT, 1, 0),
1215b5858113SRyan Lee 	SOC_SINGLE("PVDD Auto Restart Switch", MAX98396_R210E_AUTO_RESTART,
1216b5858113SRyan Lee 		   MAX98396_PVDD_UVLO_RESTART_SHFT, 1, 0),
1217b5858113SRyan Lee 	SOC_SINGLE("VBAT Auto Restart Switch", MAX98396_R210E_AUTO_RESTART,
1218b5858113SRyan Lee 		   MAX98396_VBAT_UVLO_RESTART_SHFT, 1, 0),
1219b5858113SRyan Lee 	SOC_SINGLE("THERM Auto Restart Switch", MAX98396_R210E_AUTO_RESTART,
1220b5858113SRyan Lee 		   MAX98396_THEM_SHDN_RESTART_SHFT, 1, 0),
1221b5858113SRyan Lee 	SOC_SINGLE("OVC Auto Restart Switch", MAX98396_R210E_AUTO_RESTART,
1222b5858113SRyan Lee 		   MAX98396_OVC_RESTART_SHFT, 1, 0),
1223b5858113SRyan Lee 	/* Thermal Threshold */
1224b5858113SRyan Lee 	SOC_ENUM("THERM Thresh1", max98396_thermal_warn_thresh1_enum),
1225b5858113SRyan Lee 	SOC_ENUM("THERM Thresh2", max98396_thermal_warn_thresh2_enum),
1226b5858113SRyan Lee 	SOC_ENUM("THERM SHDN Thresh", max98396_thermal_shdn_thresh_enum),
1227b5858113SRyan Lee 	SOC_ENUM("THERM Hysteresis", max98396_thermal_hysteresis_enum),
1228b5858113SRyan Lee 	SOC_SINGLE("THERM Foldback Switch",
1229b5858113SRyan Lee 		   MAX98396_R2027_THERM_FOLDBACK_EN, 0, 1, 0),
1230b5858113SRyan Lee 	SOC_ENUM("THERM Slope1", max98396_thermal_fb_slope1_enum),
1231b5858113SRyan Lee 	SOC_ENUM("THERM Slope2", max98396_thermal_fb_slope2_enum),
1232b5858113SRyan Lee 	SOC_ENUM("THERM Release", max98396_thermal_fb_reltime_enum),
1233b5858113SRyan Lee 	SOC_ENUM("THERM Hold", max98396_thermal_fb_holdtime_enum),
1234b5858113SRyan Lee 	/* ADC */
1235b5858113SRyan Lee 	SOC_SINGLE_EXT("ADC PVDD", MAX98396_R20B6_ADC_PVDD_READBACK_MSB, 0, 0x1FF, 0,
1236b5858113SRyan Lee 		       max98396_adc_value_get, NULL),
1237b5858113SRyan Lee 	SOC_SINGLE_EXT("ADC VBAT", MAX98396_R20B8_ADC_VBAT_READBACK_MSB, 0, 0x1FF, 0,
1238b5858113SRyan Lee 		       max98396_adc_value_get, NULL),
1239b5858113SRyan Lee 	SOC_SINGLE_EXT("ADC TEMP", MAX98396_R20BA_ADC_TEMP_READBACK_MSB, 0, 0x1FF, 0,
1240b5858113SRyan Lee 		       max98396_adc_value_get, NULL),
1241b5858113SRyan Lee };
1242b5858113SRyan Lee 
1243b5858113SRyan Lee static const struct snd_soc_dapm_route max98396_audio_map[] = {
1244b5858113SRyan Lee 	/* Plabyack */
1245b5858113SRyan Lee 	{"DAI Sel Mux", "Left", "Amp Enable"},
1246b5858113SRyan Lee 	{"DAI Sel Mux", "Right", "Amp Enable"},
1247b5858113SRyan Lee 	{"DAI Sel Mux", "LeftRight", "Amp Enable"},
1248b5858113SRyan Lee 	{"BE_OUT", NULL, "DAI Sel Mux"},
1249b5858113SRyan Lee 	/* Capture */
1250b5858113SRyan Lee 	{ "VI Sense", "Switch", "VMON" },
1251b5858113SRyan Lee 	{ "VI Sense", "Switch", "IMON" },
1252b5858113SRyan Lee 	{ "Voltage Sense", NULL, "VI Sense" },
1253b5858113SRyan Lee 	{ "Current Sense", NULL, "VI Sense" },
1254b5858113SRyan Lee };
1255b5858113SRyan Lee 
1256b5858113SRyan Lee static struct snd_soc_dai_driver max98396_dai[] = {
1257b5858113SRyan Lee 	{
1258b5858113SRyan Lee 		.name = "max98396-aif1",
1259b5858113SRyan Lee 		.playback = {
1260b5858113SRyan Lee 			.stream_name = "HiFi Playback",
1261b5858113SRyan Lee 			.channels_min = 1,
1262b5858113SRyan Lee 			.channels_max = 2,
1263b5858113SRyan Lee 			.rates = MAX98396_RATES,
1264b5858113SRyan Lee 			.formats = MAX98396_FORMATS,
1265b5858113SRyan Lee 		},
1266b5858113SRyan Lee 		.capture = {
1267b5858113SRyan Lee 			.stream_name = "HiFi Capture",
1268b5858113SRyan Lee 			.channels_min = 1,
1269b5858113SRyan Lee 			.channels_max = 2,
1270b5858113SRyan Lee 			.rates = MAX98396_RATES,
1271b5858113SRyan Lee 			.formats = MAX98396_FORMATS,
1272b5858113SRyan Lee 		},
1273b5858113SRyan Lee 		.ops = &max98396_dai_ops,
1274b5858113SRyan Lee 	}
1275b5858113SRyan Lee };
1276b5858113SRyan Lee 
1277b5858113SRyan Lee static struct snd_soc_dai_driver max98397_dai[] = {
1278b5858113SRyan Lee 	{
1279b5858113SRyan Lee 		.name = "max98397-aif1",
1280b5858113SRyan Lee 		.playback = {
1281b5858113SRyan Lee 			.stream_name = "HiFi Playback",
1282b5858113SRyan Lee 			.channels_min = 1,
1283b5858113SRyan Lee 			.channels_max = 2,
1284b5858113SRyan Lee 			.rates = MAX98396_RATES,
1285b5858113SRyan Lee 			.formats = MAX98396_FORMATS,
1286b5858113SRyan Lee 		},
1287b5858113SRyan Lee 		.capture = {
1288b5858113SRyan Lee 			.stream_name = "HiFi Capture",
1289b5858113SRyan Lee 			.channels_min = 1,
1290b5858113SRyan Lee 			.channels_max = 2,
1291b5858113SRyan Lee 			.rates = MAX98396_RATES,
1292b5858113SRyan Lee 			.formats = MAX98396_FORMATS,
1293b5858113SRyan Lee 		},
1294b5858113SRyan Lee 		.ops = &max98396_dai_ops,
1295b5858113SRyan Lee 	}
1296b5858113SRyan Lee };
1297b5858113SRyan Lee 
1298b5858113SRyan Lee static void max98396_reset(struct max98396_priv *max98396, struct device *dev)
1299b5858113SRyan Lee {
1300b5858113SRyan Lee 	int ret, reg, count;
1301b5858113SRyan Lee 
1302b5858113SRyan Lee 	/* Software Reset */
1303b5858113SRyan Lee 	ret = regmap_write(max98396->regmap,
1304b5858113SRyan Lee 			   MAX98396_R2000_SW_RESET, 1);
1305b5858113SRyan Lee 	if (ret)
1306b5858113SRyan Lee 		dev_err(dev, "Reset command failed. (ret:%d)\n", ret);
1307b5858113SRyan Lee 
1308b5858113SRyan Lee 	count = 0;
1309b5858113SRyan Lee 	while (count < 3) {
1310b5858113SRyan Lee 		usleep_range(5000, 6000);
1311b5858113SRyan Lee 		/* Software Reset Verification */
1312b5858113SRyan Lee 		ret = regmap_read(max98396->regmap,
1313b5858113SRyan Lee 				  GET_REG_ADDR_REV_ID(max98396->device_id), &reg);
1314b5858113SRyan Lee 		if (!ret) {
1315b5858113SRyan Lee 			dev_info(dev, "Reset completed (retry:%d)\n", count);
1316b5858113SRyan Lee 			return;
1317b5858113SRyan Lee 		}
1318b5858113SRyan Lee 		count++;
1319b5858113SRyan Lee 	}
1320b5858113SRyan Lee 	dev_err(dev, "Reset failed. (ret:%d)\n", ret);
1321b5858113SRyan Lee }
1322b5858113SRyan Lee 
1323b5858113SRyan Lee static int max98396_probe(struct snd_soc_component *component)
1324b5858113SRyan Lee {
1325b5858113SRyan Lee 	struct max98396_priv *max98396 =
1326b5858113SRyan Lee 		snd_soc_component_get_drvdata(component);
1327b5858113SRyan Lee 
1328b5858113SRyan Lee 	/* Software Reset */
1329b5858113SRyan Lee 	max98396_reset(max98396, component->dev);
1330b5858113SRyan Lee 
1331b5858113SRyan Lee 	/* L/R mix configuration */
1332b5858113SRyan Lee 	if (max98396->device_id == CODEC_TYPE_MAX98396) {
1333b5858113SRyan Lee 		regmap_write(max98396->regmap,
1334b5858113SRyan Lee 			     MAX98396_R2055_PCM_RX_SRC1, 0x02);
1335b5858113SRyan Lee 		regmap_write(max98396->regmap,
1336b5858113SRyan Lee 			     MAX98396_R2056_PCM_RX_SRC2, 0x10);
1337b5858113SRyan Lee 	} else {
1338b5858113SRyan Lee 		regmap_write(max98396->regmap,
1339b5858113SRyan Lee 			     MAX98397_R2056_PCM_RX_SRC1, 0x02);
1340b5858113SRyan Lee 		regmap_write(max98396->regmap,
1341b5858113SRyan Lee 			     MAX98397_R2057_PCM_RX_SRC2, 0x10);
1342b5858113SRyan Lee 	}
1343703ee055SDaniel Mack 	/* Supply control */
1344703ee055SDaniel Mack 	regmap_update_bits(max98396->regmap,
1345703ee055SDaniel Mack 			   MAX98396_R20A0_AMP_SUPPLY_CTL,
1346703ee055SDaniel Mack 			   MAX98396_AMP_SUPPLY_NOVBAT,
1347703ee055SDaniel Mack 			   (max98396->vbat == NULL) ?
1348703ee055SDaniel Mack 				MAX98396_AMP_SUPPLY_NOVBAT : 0);
1349b5858113SRyan Lee 	/* Enable DC blocker */
1350b5858113SRyan Lee 	regmap_update_bits(max98396->regmap,
1351b5858113SRyan Lee 			   MAX98396_R2092_AMP_DSP_CFG, 1, 1);
1352b5858113SRyan Lee 	/* Enable IV Monitor DC blocker */
1353b5858113SRyan Lee 	regmap_update_bits(max98396->regmap,
1354b5858113SRyan Lee 			   MAX98396_R20E0_IV_SENSE_PATH_CFG,
1355b5858113SRyan Lee 			   MAX98396_IV_SENSE_DCBLK_EN_MASK,
1356b5858113SRyan Lee 			   MAX98396_IV_SENSE_DCBLK_EN_MASK);
1357b5858113SRyan Lee 	/* Configure default data output sources */
1358b5858113SRyan Lee 	regmap_write(max98396->regmap,
1359b5858113SRyan Lee 		     MAX98396_R205D_PCM_TX_SRC_EN, 3);
1360b5858113SRyan Lee 	/* Enable Wideband Filter */
1361b5858113SRyan Lee 	regmap_update_bits(max98396->regmap,
1362b5858113SRyan Lee 			   MAX98396_R2092_AMP_DSP_CFG, 0x40, 0x40);
1363b5858113SRyan Lee 	/* Enable IV Wideband Filter */
1364b5858113SRyan Lee 	regmap_update_bits(max98396->regmap,
1365b5858113SRyan Lee 			   MAX98396_R20E0_IV_SENSE_PATH_CFG, 8, 8);
1366b5858113SRyan Lee 
1367b5858113SRyan Lee 	/* Enable Bypass Source */
1368b5858113SRyan Lee 	regmap_write(max98396->regmap,
1369b5858113SRyan Lee 		     MAX98396_R2058_PCM_BYPASS_SRC,
1370b5858113SRyan Lee 		     max98396->bypass_slot);
1371b5858113SRyan Lee 	/* Voltage, current slot configuration */
1372b5858113SRyan Lee 	regmap_write(max98396->regmap,
1373b5858113SRyan Lee 		     MAX98396_R2044_PCM_TX_CTRL_1,
1374b5858113SRyan Lee 		     max98396->v_slot);
1375b5858113SRyan Lee 	regmap_write(max98396->regmap,
1376b5858113SRyan Lee 		     MAX98396_R2045_PCM_TX_CTRL_2,
1377b5858113SRyan Lee 		     max98396->i_slot);
1378b5858113SRyan Lee 
1379b5858113SRyan Lee 	if (max98396->v_slot < 8)
1380b5858113SRyan Lee 		if (max98396->device_id == CODEC_TYPE_MAX98396)
1381b5858113SRyan Lee 			regmap_update_bits(max98396->regmap,
1382b5858113SRyan Lee 					   MAX98396_R2053_PCM_TX_HIZ_CTRL_8,
1383b5858113SRyan Lee 					   1 << max98396->v_slot, 0);
1384b5858113SRyan Lee 		else
1385b5858113SRyan Lee 			regmap_update_bits(max98396->regmap,
1386b5858113SRyan Lee 					   MAX98397_R2054_PCM_TX_HIZ_CTRL_8,
1387b5858113SRyan Lee 					   1 << max98396->v_slot, 0);
1388b5858113SRyan Lee 	else
1389b5858113SRyan Lee 		if (max98396->device_id == CODEC_TYPE_MAX98396)
1390b5858113SRyan Lee 			regmap_update_bits(max98396->regmap,
1391b5858113SRyan Lee 					   MAX98396_R2052_PCM_TX_HIZ_CTRL_7,
1392b5858113SRyan Lee 					   1 << (max98396->v_slot - 8), 0);
1393b5858113SRyan Lee 		else
1394b5858113SRyan Lee 			regmap_update_bits(max98396->regmap,
1395b5858113SRyan Lee 					   MAX98397_R2053_PCM_TX_HIZ_CTRL_7,
1396b5858113SRyan Lee 					   1 << (max98396->v_slot - 8), 0);
1397b5858113SRyan Lee 
1398b5858113SRyan Lee 	if (max98396->i_slot < 8)
1399b5858113SRyan Lee 		if (max98396->device_id == CODEC_TYPE_MAX98396)
1400b5858113SRyan Lee 			regmap_update_bits(max98396->regmap,
1401b5858113SRyan Lee 					   MAX98396_R2053_PCM_TX_HIZ_CTRL_8,
1402b5858113SRyan Lee 					   1 << max98396->i_slot, 0);
1403b5858113SRyan Lee 		else
1404b5858113SRyan Lee 			regmap_update_bits(max98396->regmap,
1405b5858113SRyan Lee 					   MAX98397_R2054_PCM_TX_HIZ_CTRL_8,
1406b5858113SRyan Lee 					   1 << max98396->i_slot, 0);
1407b5858113SRyan Lee 	else
1408b5858113SRyan Lee 		if (max98396->device_id == CODEC_TYPE_MAX98396)
1409b5858113SRyan Lee 			regmap_update_bits(max98396->regmap,
1410b5858113SRyan Lee 					   MAX98396_R2052_PCM_TX_HIZ_CTRL_7,
1411b5858113SRyan Lee 					   1 << (max98396->i_slot - 8), 0);
1412b5858113SRyan Lee 		else
1413b5858113SRyan Lee 			regmap_update_bits(max98396->regmap,
1414b5858113SRyan Lee 					   MAX98397_R2053_PCM_TX_HIZ_CTRL_7,
1415b5858113SRyan Lee 					   1 << (max98396->i_slot - 8), 0);
1416b5858113SRyan Lee 
1417b5858113SRyan Lee 	/* Set interleave mode */
1418b5858113SRyan Lee 	if (max98396->interleave_mode)
1419b5858113SRyan Lee 		regmap_update_bits(max98396->regmap,
1420b5858113SRyan Lee 				   MAX98396_R2041_PCM_MODE_CFG,
1421b5858113SRyan Lee 				   MAX98396_PCM_TX_CH_INTERLEAVE_MASK,
1422b5858113SRyan Lee 				   MAX98396_PCM_TX_CH_INTERLEAVE_MASK);
1423b5858113SRyan Lee 
1424b5858113SRyan Lee 	regmap_update_bits(max98396->regmap,
1425b5858113SRyan Lee 			   MAX98396_R2038_CLK_MON_CTRL,
1426b5858113SRyan Lee 			   MAX98396_CLK_MON_AUTO_RESTART_MASK,
1427b5858113SRyan Lee 			   MAX98396_CLK_MON_AUTO_RESTART_MASK);
1428b5858113SRyan Lee 
1429b5858113SRyan Lee 	/* Speaker Amplifier PCM RX Enable by default */
1430b5858113SRyan Lee 	regmap_update_bits(max98396->regmap,
1431b5858113SRyan Lee 			   MAX98396_R205E_PCM_RX_EN,
1432b5858113SRyan Lee 			   MAX98396_PCM_RX_EN_MASK, 1);
1433b5858113SRyan Lee 
1434b5858113SRyan Lee 	return 0;
1435b5858113SRyan Lee }
1436b5858113SRyan Lee 
1437b5858113SRyan Lee #ifdef CONFIG_PM_SLEEP
1438b5858113SRyan Lee static int max98396_suspend(struct device *dev)
1439b5858113SRyan Lee {
1440b5858113SRyan Lee 	struct max98396_priv *max98396 = dev_get_drvdata(dev);
1441b5858113SRyan Lee 
1442b5858113SRyan Lee 	regcache_cache_only(max98396->regmap, true);
1443b5858113SRyan Lee 	regcache_mark_dirty(max98396->regmap);
1444703ee055SDaniel Mack 	regulator_bulk_disable(MAX98396_NUM_CORE_SUPPLIES,
1445703ee055SDaniel Mack 			       max98396->core_supplies);
1446703ee055SDaniel Mack 	if (max98396->pvdd)
1447703ee055SDaniel Mack 		regulator_disable(max98396->pvdd);
1448703ee055SDaniel Mack 
1449703ee055SDaniel Mack 	if (max98396->vbat)
1450703ee055SDaniel Mack 		regulator_disable(max98396->vbat);
1451703ee055SDaniel Mack 
1452b5858113SRyan Lee 	return 0;
1453b5858113SRyan Lee }
1454b5858113SRyan Lee 
1455b5858113SRyan Lee static int max98396_resume(struct device *dev)
1456b5858113SRyan Lee {
1457b5858113SRyan Lee 	struct max98396_priv *max98396 = dev_get_drvdata(dev);
1458703ee055SDaniel Mack 	int ret;
1459703ee055SDaniel Mack 
1460703ee055SDaniel Mack 	ret = regulator_bulk_enable(MAX98396_NUM_CORE_SUPPLIES,
1461703ee055SDaniel Mack 				    max98396->core_supplies);
1462703ee055SDaniel Mack 	if (ret < 0)
1463703ee055SDaniel Mack 		return ret;
1464703ee055SDaniel Mack 
1465703ee055SDaniel Mack 	if (max98396->pvdd) {
1466703ee055SDaniel Mack 		ret = regulator_enable(max98396->pvdd);
1467703ee055SDaniel Mack 		if (ret < 0)
1468703ee055SDaniel Mack 			return ret;
1469703ee055SDaniel Mack 	}
1470703ee055SDaniel Mack 
1471703ee055SDaniel Mack 	if (max98396->vbat) {
1472703ee055SDaniel Mack 		ret = regulator_enable(max98396->vbat);
1473703ee055SDaniel Mack 		if (ret < 0)
1474703ee055SDaniel Mack 			return ret;
1475703ee055SDaniel Mack 	}
1476b5858113SRyan Lee 
1477b5858113SRyan Lee 	regcache_cache_only(max98396->regmap, false);
1478b5858113SRyan Lee 	max98396_reset(max98396, dev);
1479b5858113SRyan Lee 	regcache_sync(max98396->regmap);
1480b5858113SRyan Lee 	return 0;
1481b5858113SRyan Lee }
1482b5858113SRyan Lee #endif
1483b5858113SRyan Lee 
1484b5858113SRyan Lee static const struct dev_pm_ops max98396_pm = {
1485b5858113SRyan Lee 	SET_SYSTEM_SLEEP_PM_OPS(max98396_suspend, max98396_resume)
1486b5858113SRyan Lee };
1487b5858113SRyan Lee 
1488b5858113SRyan Lee static const struct snd_soc_component_driver soc_codec_dev_max98396 = {
1489b5858113SRyan Lee 	.probe			= max98396_probe,
1490b5858113SRyan Lee 	.controls		= max98396_snd_controls,
1491b5858113SRyan Lee 	.num_controls		= ARRAY_SIZE(max98396_snd_controls),
1492b5858113SRyan Lee 	.dapm_widgets		= max98396_dapm_widgets,
1493b5858113SRyan Lee 	.num_dapm_widgets	= ARRAY_SIZE(max98396_dapm_widgets),
1494b5858113SRyan Lee 	.dapm_routes		= max98396_audio_map,
1495b5858113SRyan Lee 	.num_dapm_routes	= ARRAY_SIZE(max98396_audio_map),
1496b5858113SRyan Lee 	.idle_bias_on		= 1,
1497b5858113SRyan Lee 	.use_pmdown_time	= 1,
1498b5858113SRyan Lee 	.endianness		= 1,
1499b5858113SRyan Lee 	.non_legacy_dai_naming	= 1,
1500b5858113SRyan Lee };
1501b5858113SRyan Lee 
1502b5858113SRyan Lee static const struct snd_soc_component_driver soc_codec_dev_max98397 = {
1503b5858113SRyan Lee 	.probe			= max98396_probe,
1504b5858113SRyan Lee 	.controls		= max98397_snd_controls,
1505b5858113SRyan Lee 	.num_controls		= ARRAY_SIZE(max98397_snd_controls),
1506b5858113SRyan Lee 	.dapm_widgets		= max98396_dapm_widgets,
1507b5858113SRyan Lee 	.num_dapm_widgets	= ARRAY_SIZE(max98396_dapm_widgets),
1508b5858113SRyan Lee 	.dapm_routes		= max98396_audio_map,
1509b5858113SRyan Lee 	.num_dapm_routes	= ARRAY_SIZE(max98396_audio_map),
1510b5858113SRyan Lee 	.idle_bias_on		= 1,
1511b5858113SRyan Lee 	.use_pmdown_time	= 1,
1512b5858113SRyan Lee 	.endianness		= 1,
1513b5858113SRyan Lee 	.non_legacy_dai_naming	= 1,
1514b5858113SRyan Lee };
1515b5858113SRyan Lee 
1516b5858113SRyan Lee static const struct regmap_config max98396_regmap = {
1517b5858113SRyan Lee 	.reg_bits = 16,
1518b5858113SRyan Lee 	.val_bits = 8,
1519b5858113SRyan Lee 	.max_register = MAX98396_R21FF_REVISION_ID,
1520b5858113SRyan Lee 	.reg_defaults  = max98396_reg,
1521b5858113SRyan Lee 	.num_reg_defaults = ARRAY_SIZE(max98396_reg),
1522b5858113SRyan Lee 	.readable_reg = max98396_readable_register,
1523b5858113SRyan Lee 	.volatile_reg = max98396_volatile_reg,
1524b5858113SRyan Lee 	.cache_type = REGCACHE_RBTREE,
1525b5858113SRyan Lee };
1526b5858113SRyan Lee 
1527b5858113SRyan Lee static const struct regmap_config max98397_regmap = {
1528b5858113SRyan Lee 	.reg_bits = 16,
1529b5858113SRyan Lee 	.val_bits = 8,
1530b5858113SRyan Lee 	.max_register = MAX98397_R22FF_REVISION_ID,
1531b5858113SRyan Lee 	.reg_defaults  = max98397_reg,
1532b5858113SRyan Lee 	.num_reg_defaults = ARRAY_SIZE(max98397_reg),
1533b5858113SRyan Lee 	.readable_reg = max98397_readable_register,
1534b5858113SRyan Lee 	.volatile_reg = max98397_volatile_reg,
1535b5858113SRyan Lee 	.cache_type = REGCACHE_RBTREE,
1536b5858113SRyan Lee };
1537b5858113SRyan Lee 
1538b5858113SRyan Lee static void max98396_read_device_property(struct device *dev,
1539b5858113SRyan Lee 					  struct max98396_priv *max98396)
1540b5858113SRyan Lee {
1541b5858113SRyan Lee 	int value;
1542b5858113SRyan Lee 
1543b5858113SRyan Lee 	if (!device_property_read_u32(dev, "adi,vmon-slot-no", &value))
1544b5858113SRyan Lee 		max98396->v_slot = value & 0xF;
1545b5858113SRyan Lee 	else
1546b5858113SRyan Lee 		max98396->v_slot = 0;
1547b5858113SRyan Lee 
1548b5858113SRyan Lee 	if (!device_property_read_u32(dev, "adi,imon-slot-no", &value))
1549b5858113SRyan Lee 		max98396->i_slot = value & 0xF;
1550b5858113SRyan Lee 	else
1551b5858113SRyan Lee 		max98396->i_slot = 1;
1552b5858113SRyan Lee 
1553b5858113SRyan Lee 	if (!device_property_read_u32(dev, "adi,bypass-slot-no", &value))
1554b5858113SRyan Lee 		max98396->bypass_slot = value & 0xF;
1555b5858113SRyan Lee 	else
1556b5858113SRyan Lee 		max98396->bypass_slot = 0;
1557b5858113SRyan Lee }
1558b5858113SRyan Lee 
1559703ee055SDaniel Mack static void max98396_core_supplies_disable(void *priv)
1560703ee055SDaniel Mack {
1561703ee055SDaniel Mack 	struct max98396_priv *max98396 = priv;
1562703ee055SDaniel Mack 
1563703ee055SDaniel Mack 	regulator_bulk_disable(MAX98396_NUM_CORE_SUPPLIES,
1564703ee055SDaniel Mack 			       max98396->core_supplies);
1565703ee055SDaniel Mack }
1566703ee055SDaniel Mack 
1567703ee055SDaniel Mack static void max98396_supply_disable(void *r)
1568703ee055SDaniel Mack {
1569703ee055SDaniel Mack 	regulator_disable((struct regulator *) r);
1570703ee055SDaniel Mack }
1571703ee055SDaniel Mack 
1572b5858113SRyan Lee static int max98396_i2c_probe(struct i2c_client *i2c,
1573b5858113SRyan Lee 			      const struct i2c_device_id *id)
1574b5858113SRyan Lee {
1575b5858113SRyan Lee 	struct max98396_priv *max98396 = NULL;
1576703ee055SDaniel Mack 	int i, ret, reg;
1577b5858113SRyan Lee 
1578b5858113SRyan Lee 	max98396 = devm_kzalloc(&i2c->dev, sizeof(*max98396), GFP_KERNEL);
1579b5858113SRyan Lee 
1580b5858113SRyan Lee 	if (!max98396) {
1581b5858113SRyan Lee 		ret = -ENOMEM;
1582b5858113SRyan Lee 		return ret;
1583b5858113SRyan Lee 	}
1584b5858113SRyan Lee 	i2c_set_clientdata(i2c, max98396);
1585b5858113SRyan Lee 
1586b5858113SRyan Lee 	max98396->device_id =  id->driver_data;
1587b5858113SRyan Lee 
1588b5858113SRyan Lee 	/* regmap initialization */
1589b5858113SRyan Lee 	if (max98396->device_id == CODEC_TYPE_MAX98396)
1590b5858113SRyan Lee 		max98396->regmap = devm_regmap_init_i2c(i2c, &max98396_regmap);
1591b5858113SRyan Lee 
1592b5858113SRyan Lee 	else
1593b5858113SRyan Lee 		max98396->regmap = devm_regmap_init_i2c(i2c, &max98397_regmap);
1594b5858113SRyan Lee 
1595b5858113SRyan Lee 	if (IS_ERR(max98396->regmap)) {
1596b5858113SRyan Lee 		ret = PTR_ERR(max98396->regmap);
1597b5858113SRyan Lee 		dev_err(&i2c->dev,
1598b5858113SRyan Lee 			"Failed to allocate regmap: %d\n", ret);
1599b5858113SRyan Lee 		return ret;
1600b5858113SRyan Lee 	}
1601b5858113SRyan Lee 
1602703ee055SDaniel Mack 	/* Obtain regulator supplies */
1603703ee055SDaniel Mack 	for (i = 0; i < MAX98396_NUM_CORE_SUPPLIES; i++)
1604703ee055SDaniel Mack 		max98396->core_supplies[i].supply = max98396_core_supplies[i];
1605703ee055SDaniel Mack 
1606703ee055SDaniel Mack 	ret = devm_regulator_bulk_get(&i2c->dev, MAX98396_NUM_CORE_SUPPLIES,
1607703ee055SDaniel Mack 				      max98396->core_supplies);
1608703ee055SDaniel Mack 	if (ret < 0) {
1609703ee055SDaniel Mack 		dev_err(&i2c->dev, "Failed to request core supplies: %d\n", ret);
1610703ee055SDaniel Mack 		return ret;
1611703ee055SDaniel Mack 	}
1612703ee055SDaniel Mack 
1613703ee055SDaniel Mack 	max98396->vbat = devm_regulator_get_optional(&i2c->dev, "vbat");
1614703ee055SDaniel Mack 	if (IS_ERR(max98396->vbat)) {
1615703ee055SDaniel Mack 		if (PTR_ERR(max98396->vbat) == -EPROBE_DEFER)
1616703ee055SDaniel Mack 			return -EPROBE_DEFER;
1617703ee055SDaniel Mack 
1618703ee055SDaniel Mack 		max98396->vbat = NULL;
1619703ee055SDaniel Mack 	}
1620703ee055SDaniel Mack 
1621703ee055SDaniel Mack 	max98396->pvdd = devm_regulator_get_optional(&i2c->dev, "pvdd");
1622703ee055SDaniel Mack 	if (IS_ERR(max98396->pvdd)) {
1623703ee055SDaniel Mack 		if (PTR_ERR(max98396->pvdd) == -EPROBE_DEFER)
1624703ee055SDaniel Mack 			return -EPROBE_DEFER;
1625703ee055SDaniel Mack 
1626703ee055SDaniel Mack 		max98396->pvdd = NULL;
1627703ee055SDaniel Mack 	}
1628703ee055SDaniel Mack 
1629703ee055SDaniel Mack 	ret = regulator_bulk_enable(MAX98396_NUM_CORE_SUPPLIES,
1630703ee055SDaniel Mack 				    max98396->core_supplies);
1631703ee055SDaniel Mack 	if (ret < 0) {
1632703ee055SDaniel Mack 		dev_err(&i2c->dev, "Unable to enable core supplies: %d", ret);
1633703ee055SDaniel Mack 		return ret;
1634703ee055SDaniel Mack 	}
1635703ee055SDaniel Mack 
1636703ee055SDaniel Mack 	ret = devm_add_action_or_reset(&i2c->dev, max98396_core_supplies_disable,
1637703ee055SDaniel Mack 				       max98396);
1638703ee055SDaniel Mack 	if (ret < 0)
1639703ee055SDaniel Mack 		return ret;
1640703ee055SDaniel Mack 
1641703ee055SDaniel Mack 	if (max98396->pvdd) {
1642703ee055SDaniel Mack 		ret = regulator_enable(max98396->pvdd);
1643703ee055SDaniel Mack 		if (ret < 0)
1644703ee055SDaniel Mack 			return ret;
1645703ee055SDaniel Mack 
1646703ee055SDaniel Mack 		ret = devm_add_action_or_reset(&i2c->dev,
1647703ee055SDaniel Mack 					       max98396_supply_disable,
1648703ee055SDaniel Mack 					       max98396->pvdd);
1649703ee055SDaniel Mack 		if (ret < 0)
1650703ee055SDaniel Mack 			return ret;
1651703ee055SDaniel Mack 	}
1652703ee055SDaniel Mack 
1653703ee055SDaniel Mack 	if (max98396->vbat) {
1654703ee055SDaniel Mack 		ret = regulator_enable(max98396->vbat);
1655703ee055SDaniel Mack 		if (ret < 0)
1656703ee055SDaniel Mack 			return ret;
1657703ee055SDaniel Mack 
1658703ee055SDaniel Mack 		ret = devm_add_action_or_reset(&i2c->dev,
1659703ee055SDaniel Mack 					       max98396_supply_disable,
1660703ee055SDaniel Mack 					       max98396->vbat);
1661703ee055SDaniel Mack 		if (ret < 0)
1662703ee055SDaniel Mack 			return ret;
1663703ee055SDaniel Mack 	}
1664703ee055SDaniel Mack 
1665b5858113SRyan Lee 	/* update interleave mode info */
1666b5858113SRyan Lee 	if (device_property_read_bool(&i2c->dev, "adi,interleave_mode"))
1667b5858113SRyan Lee 		max98396->interleave_mode = true;
1668b5858113SRyan Lee 	else
1669b5858113SRyan Lee 		max98396->interleave_mode = false;
1670b5858113SRyan Lee 
1671b5858113SRyan Lee 	/* voltage/current slot & gpio configuration */
1672b5858113SRyan Lee 	max98396_read_device_property(&i2c->dev, max98396);
1673b5858113SRyan Lee 
1674b5858113SRyan Lee 	/* Reset the Device */
1675b5858113SRyan Lee 	max98396->reset_gpio = devm_gpiod_get_optional(&i2c->dev,
1676b5858113SRyan Lee 						       "reset", GPIOD_OUT_HIGH);
1677b5858113SRyan Lee 	if (IS_ERR(max98396->reset_gpio)) {
1678b5858113SRyan Lee 		ret = PTR_ERR(max98396->reset_gpio);
1679b5858113SRyan Lee 		dev_err(&i2c->dev, "Unable to request GPIO pin: %d.\n", ret);
1680b5858113SRyan Lee 		return ret;
1681b5858113SRyan Lee 	}
1682b5858113SRyan Lee 
1683b5858113SRyan Lee 	if (max98396->reset_gpio) {
1684b5858113SRyan Lee 		usleep_range(5000, 6000);
1685b5858113SRyan Lee 		gpiod_set_value_cansleep(max98396->reset_gpio, 0);
1686b5858113SRyan Lee 		/* Wait for the hw reset done */
1687b5858113SRyan Lee 		usleep_range(5000, 6000);
1688b5858113SRyan Lee 	}
1689b5858113SRyan Lee 
1690b5858113SRyan Lee 	ret = regmap_read(max98396->regmap,
1691b5858113SRyan Lee 			  GET_REG_ADDR_REV_ID(max98396->device_id), &reg);
1692b5858113SRyan Lee 	if (ret < 0) {
1693b5858113SRyan Lee 		dev_err(&i2c->dev, "%s: failed to read revision of the device.\n",  id->name);
1694b5858113SRyan Lee 		return ret;
1695b5858113SRyan Lee 	}
1696b5858113SRyan Lee 	dev_info(&i2c->dev, "%s revision ID: 0x%02X\n", id->name, reg);
1697b5858113SRyan Lee 
1698b5858113SRyan Lee 	/* codec registration */
1699b5858113SRyan Lee 	if (max98396->device_id == CODEC_TYPE_MAX98396)
1700b5858113SRyan Lee 		ret = devm_snd_soc_register_component(&i2c->dev,
1701b5858113SRyan Lee 						      &soc_codec_dev_max98396,
1702b5858113SRyan Lee 						      max98396_dai,
1703b5858113SRyan Lee 						      ARRAY_SIZE(max98396_dai));
1704b5858113SRyan Lee 	else
1705b5858113SRyan Lee 		ret = devm_snd_soc_register_component(&i2c->dev,
1706b5858113SRyan Lee 						      &soc_codec_dev_max98397,
1707b5858113SRyan Lee 						      max98397_dai,
1708b5858113SRyan Lee 						      ARRAY_SIZE(max98397_dai));
1709b5858113SRyan Lee 	if (ret < 0)
1710b5858113SRyan Lee 		dev_err(&i2c->dev, "Failed to register codec: %d\n", ret);
1711b5858113SRyan Lee 
1712b5858113SRyan Lee 	return ret;
1713b5858113SRyan Lee }
1714b5858113SRyan Lee 
1715b5858113SRyan Lee static const struct i2c_device_id max98396_i2c_id[] = {
1716b5858113SRyan Lee 	{ "max98396", CODEC_TYPE_MAX98396},
1717b5858113SRyan Lee 	{ "max98397", CODEC_TYPE_MAX98397},
1718b5858113SRyan Lee 	{ },
1719b5858113SRyan Lee };
1720b5858113SRyan Lee 
1721b5858113SRyan Lee MODULE_DEVICE_TABLE(i2c, max98396_i2c_id);
1722b5858113SRyan Lee 
1723b5858113SRyan Lee #if defined(CONFIG_OF)
1724b5858113SRyan Lee static const struct of_device_id max98396_of_match[] = {
1725b5858113SRyan Lee 	{ .compatible = "adi,max98396", },
1726b5858113SRyan Lee 	{ .compatible = "adi,max98397", },
1727b5858113SRyan Lee 	{ }
1728b5858113SRyan Lee };
1729b5858113SRyan Lee MODULE_DEVICE_TABLE(of, max98396_of_match);
1730b5858113SRyan Lee #endif
1731b5858113SRyan Lee 
1732b5858113SRyan Lee #ifdef CONFIG_ACPI
1733b5858113SRyan Lee static const struct acpi_device_id max98396_acpi_match[] = {
1734b5858113SRyan Lee 	{ "ADS8396", 0 },
1735b5858113SRyan Lee 	{ "ADS8397", 0 },
1736b5858113SRyan Lee 	{},
1737b5858113SRyan Lee };
1738b5858113SRyan Lee MODULE_DEVICE_TABLE(acpi, max98396_acpi_match);
1739b5858113SRyan Lee #endif
1740b5858113SRyan Lee 
1741b5858113SRyan Lee static struct i2c_driver max98396_i2c_driver = {
1742b5858113SRyan Lee 	.driver = {
1743b5858113SRyan Lee 		.name = "max98396",
1744b5858113SRyan Lee 		.of_match_table = of_match_ptr(max98396_of_match),
1745b5858113SRyan Lee 		.acpi_match_table = ACPI_PTR(max98396_acpi_match),
1746b5858113SRyan Lee 		.pm = &max98396_pm,
1747b5858113SRyan Lee 	},
1748b5858113SRyan Lee 	.probe = max98396_i2c_probe,
1749b5858113SRyan Lee 	.id_table = max98396_i2c_id,
1750b5858113SRyan Lee };
1751b5858113SRyan Lee 
1752b5858113SRyan Lee module_i2c_driver(max98396_i2c_driver)
1753b5858113SRyan Lee 
1754b5858113SRyan Lee MODULE_DESCRIPTION("ALSA SoC MAX98396 driver");
1755b5858113SRyan Lee MODULE_AUTHOR("Ryan Lee <ryans.lee@analog.com>");
1756b5858113SRyan Lee MODULE_LICENSE("GPL");
1757