xref: /linux/sound/soc/codecs/max98390.c (revision a1ff5a7d78a036d6c2178ee5acd6ba4946243800)
1a6e3f4f3SSteve Lee // SPDX-License-Identifier: GPL-2.0-or-later
2a6e3f4f3SSteve Lee /*
3a6e3f4f3SSteve Lee  * max98390.c  --  MAX98390 ALSA Soc Audio driver
4a6e3f4f3SSteve Lee  *
5a6e3f4f3SSteve Lee  * Copyright (C) 2020 Maxim Integrated Products
6a6e3f4f3SSteve Lee  *
7a6e3f4f3SSteve Lee  */
8a6e3f4f3SSteve Lee 
9a6e3f4f3SSteve Lee #include <linux/acpi.h>
10a6e3f4f3SSteve Lee #include <linux/cdev.h>
11a6e3f4f3SSteve Lee #include <linux/dmi.h>
12a6e3f4f3SSteve Lee #include <linux/firmware.h>
13aa7407f8SRandy Dunlap #include <linux/gpio/consumer.h>
14a6e3f4f3SSteve Lee #include <linux/i2c.h>
15a6e3f4f3SSteve Lee #include <linux/module.h>
16a6e3f4f3SSteve Lee #include <linux/regmap.h>
17a6e3f4f3SSteve Lee #include <linux/slab.h>
18a6e3f4f3SSteve Lee #include <linux/time.h>
19a6e3f4f3SSteve Lee #include <sound/pcm.h>
20a6e3f4f3SSteve Lee #include <sound/pcm_params.h>
21a6e3f4f3SSteve Lee #include <sound/soc.h>
22a6e3f4f3SSteve Lee #include <sound/tlv.h>
23a6e3f4f3SSteve Lee 
24a6e3f4f3SSteve Lee #include "max98390.h"
25a6e3f4f3SSteve Lee 
26a6e3f4f3SSteve Lee static struct reg_default max98390_reg_defaults[] = {
27a6e3f4f3SSteve Lee 	{MAX98390_INT_EN1, 0xf0},
28a6e3f4f3SSteve Lee 	{MAX98390_INT_EN2, 0x00},
29a6e3f4f3SSteve Lee 	{MAX98390_INT_EN3, 0x00},
30a6e3f4f3SSteve Lee 	{MAX98390_INT_FLAG_CLR1, 0x00},
31a6e3f4f3SSteve Lee 	{MAX98390_INT_FLAG_CLR2, 0x00},
32a6e3f4f3SSteve Lee 	{MAX98390_INT_FLAG_CLR3, 0x00},
33a6e3f4f3SSteve Lee 	{MAX98390_IRQ_CTRL, 0x01},
34a6e3f4f3SSteve Lee 	{MAX98390_CLK_MON, 0x6d},
35a6e3f4f3SSteve Lee 	{MAX98390_DAT_MON, 0x03},
36a6e3f4f3SSteve Lee 	{MAX98390_WDOG_CTRL, 0x00},
37a6e3f4f3SSteve Lee 	{MAX98390_WDOG_RST, 0x00},
38a6e3f4f3SSteve Lee 	{MAX98390_MEAS_ADC_THERM_WARN_THRESH, 0x75},
39a6e3f4f3SSteve Lee 	{MAX98390_MEAS_ADC_THERM_SHDN_THRESH, 0x8c},
40a6e3f4f3SSteve Lee 	{MAX98390_MEAS_ADC_THERM_HYSTERESIS, 0x08},
41a6e3f4f3SSteve Lee 	{MAX98390_PIN_CFG, 0x55},
42a6e3f4f3SSteve Lee 	{MAX98390_PCM_RX_EN_A, 0x00},
43a6e3f4f3SSteve Lee 	{MAX98390_PCM_RX_EN_B, 0x00},
44a6e3f4f3SSteve Lee 	{MAX98390_PCM_TX_EN_A, 0x00},
45a6e3f4f3SSteve Lee 	{MAX98390_PCM_TX_EN_B, 0x00},
46a6e3f4f3SSteve Lee 	{MAX98390_PCM_TX_HIZ_CTRL_A, 0xff},
47a6e3f4f3SSteve Lee 	{MAX98390_PCM_TX_HIZ_CTRL_B, 0xff},
48a6e3f4f3SSteve Lee 	{MAX98390_PCM_CH_SRC_1, 0x00},
49a6e3f4f3SSteve Lee 	{MAX98390_PCM_CH_SRC_2, 0x00},
50a6e3f4f3SSteve Lee 	{MAX98390_PCM_CH_SRC_3, 0x00},
51a6e3f4f3SSteve Lee 	{MAX98390_PCM_MODE_CFG, 0xc0},
52a6e3f4f3SSteve Lee 	{MAX98390_PCM_MASTER_MODE, 0x1c},
53a6e3f4f3SSteve Lee 	{MAX98390_PCM_CLK_SETUP, 0x44},
54a6e3f4f3SSteve Lee 	{MAX98390_PCM_SR_SETUP, 0x08},
55a6e3f4f3SSteve Lee 	{MAX98390_ICC_RX_EN_A, 0x00},
56a6e3f4f3SSteve Lee 	{MAX98390_ICC_RX_EN_B, 0x00},
57a6e3f4f3SSteve Lee 	{MAX98390_ICC_TX_EN_A, 0x00},
58a6e3f4f3SSteve Lee 	{MAX98390_ICC_TX_EN_B, 0x00},
59a6e3f4f3SSteve Lee 	{MAX98390_ICC_HIZ_MANUAL_MODE, 0x00},
60a6e3f4f3SSteve Lee 	{MAX98390_ICC_TX_HIZ_EN_A, 0x00},
61a6e3f4f3SSteve Lee 	{MAX98390_ICC_TX_HIZ_EN_B, 0x00},
62a6e3f4f3SSteve Lee 	{MAX98390_ICC_LNK_EN, 0x00},
63a6e3f4f3SSteve Lee 	{MAX98390_R2039_AMP_DSP_CFG, 0x0f},
64a6e3f4f3SSteve Lee 	{MAX98390_R203A_AMP_EN, 0x81},
65a6e3f4f3SSteve Lee 	{MAX98390_TONE_GEN_DC_CFG, 0x00},
66a6e3f4f3SSteve Lee 	{MAX98390_SPK_SRC_SEL, 0x00},
67a6e3f4f3SSteve Lee 	{MAX98390_SSM_CFG, 0x85},
68a6e3f4f3SSteve Lee 	{MAX98390_MEAS_EN, 0x03},
69a6e3f4f3SSteve Lee 	{MAX98390_MEAS_DSP_CFG, 0x0f},
70a6e3f4f3SSteve Lee 	{MAX98390_BOOST_CTRL0, 0x1c},
71a6e3f4f3SSteve Lee 	{MAX98390_BOOST_CTRL3, 0x01},
72a6e3f4f3SSteve Lee 	{MAX98390_BOOST_CTRL1, 0x40},
73a6e3f4f3SSteve Lee 	{MAX98390_MEAS_ADC_CFG, 0x07},
74a6e3f4f3SSteve Lee 	{MAX98390_MEAS_ADC_BASE_MSB, 0x00},
75a6e3f4f3SSteve Lee 	{MAX98390_MEAS_ADC_BASE_LSB, 0x23},
76a6e3f4f3SSteve Lee 	{MAX98390_ADC_CH0_DIVIDE, 0x00},
77a6e3f4f3SSteve Lee 	{MAX98390_ADC_CH1_DIVIDE, 0x00},
78a6e3f4f3SSteve Lee 	{MAX98390_ADC_CH2_DIVIDE, 0x00},
79a6e3f4f3SSteve Lee 	{MAX98390_ADC_CH0_FILT_CFG, 0x00},
80a6e3f4f3SSteve Lee 	{MAX98390_ADC_CH1_FILT_CFG, 0x00},
81a6e3f4f3SSteve Lee 	{MAX98390_ADC_CH2_FILT_CFG, 0x00},
82a6e3f4f3SSteve Lee 	{MAX98390_PWR_GATE_CTL, 0x2c},
83a6e3f4f3SSteve Lee 	{MAX98390_BROWNOUT_EN, 0x00},
84a6e3f4f3SSteve Lee 	{MAX98390_BROWNOUT_INFINITE_HOLD, 0x00},
85a6e3f4f3SSteve Lee 	{MAX98390_BROWNOUT_INFINITE_HOLD_CLR, 0x00},
86a6e3f4f3SSteve Lee 	{MAX98390_BROWNOUT_LVL_HOLD, 0x00},
87a6e3f4f3SSteve Lee 	{MAX98390_BROWNOUT_LVL1_THRESH, 0x00},
88a6e3f4f3SSteve Lee 	{MAX98390_BROWNOUT_LVL2_THRESH, 0x00},
89a6e3f4f3SSteve Lee 	{MAX98390_BROWNOUT_LVL3_THRESH, 0x00},
90a6e3f4f3SSteve Lee 	{MAX98390_BROWNOUT_LVL4_THRESH, 0x00},
91a6e3f4f3SSteve Lee 	{MAX98390_BROWNOUT_THRESH_HYSTERYSIS, 0x00},
92a6e3f4f3SSteve Lee 	{MAX98390_BROWNOUT_AMP_LIMITER_ATK_REL, 0x1f},
93a6e3f4f3SSteve Lee 	{MAX98390_BROWNOUT_AMP_GAIN_ATK_REL, 0x00},
94a6e3f4f3SSteve Lee 	{MAX98390_BROWNOUT_AMP1_CLIP_MODE, 0x00},
95a6e3f4f3SSteve Lee 	{MAX98390_BROWNOUT_LVL1_CUR_LIMIT, 0x00},
96a6e3f4f3SSteve Lee 	{MAX98390_BROWNOUT_LVL1_AMP1_CTRL1, 0x00},
97a6e3f4f3SSteve Lee 	{MAX98390_BROWNOUT_LVL1_AMP1_CTRL2, 0x00},
98a6e3f4f3SSteve Lee 	{MAX98390_BROWNOUT_LVL1_AMP1_CTRL3, 0x00},
99a6e3f4f3SSteve Lee 	{MAX98390_BROWNOUT_LVL2_CUR_LIMIT, 0x00},
100a6e3f4f3SSteve Lee 	{MAX98390_BROWNOUT_LVL2_AMP1_CTRL1, 0x00},
101a6e3f4f3SSteve Lee 	{MAX98390_BROWNOUT_LVL2_AMP1_CTRL2, 0x00},
102a6e3f4f3SSteve Lee 	{MAX98390_BROWNOUT_LVL2_AMP1_CTRL3, 0x00},
103a6e3f4f3SSteve Lee 	{MAX98390_BROWNOUT_LVL3_CUR_LIMIT, 0x00},
104a6e3f4f3SSteve Lee 	{MAX98390_BROWNOUT_LVL3_AMP1_CTRL1, 0x00},
105a6e3f4f3SSteve Lee 	{MAX98390_BROWNOUT_LVL3_AMP1_CTRL2, 0x00},
106a6e3f4f3SSteve Lee 	{MAX98390_BROWNOUT_LVL3_AMP1_CTRL3, 0x00},
107a6e3f4f3SSteve Lee 	{MAX98390_BROWNOUT_LVL4_CUR_LIMIT, 0x00},
108a6e3f4f3SSteve Lee 	{MAX98390_BROWNOUT_LVL4_AMP1_CTRL1, 0x00},
109a6e3f4f3SSteve Lee 	{MAX98390_BROWNOUT_LVL4_AMP1_CTRL2, 0x00},
110a6e3f4f3SSteve Lee 	{MAX98390_BROWNOUT_LVL4_AMP1_CTRL3, 0x00},
111a6e3f4f3SSteve Lee 	{MAX98390_BROWNOUT_ILIM_HLD, 0x00},
112a6e3f4f3SSteve Lee 	{MAX98390_BROWNOUT_LIM_HLD, 0x00},
113a6e3f4f3SSteve Lee 	{MAX98390_BROWNOUT_CLIP_HLD, 0x00},
114a6e3f4f3SSteve Lee 	{MAX98390_BROWNOUT_GAIN_HLD, 0x00},
115a6e3f4f3SSteve Lee 	{MAX98390_ENV_TRACK_VOUT_HEADROOM, 0x0f},
116a6e3f4f3SSteve Lee 	{MAX98390_ENV_TRACK_BOOST_VOUT_DELAY, 0x80},
117a6e3f4f3SSteve Lee 	{MAX98390_ENV_TRACK_REL_RATE, 0x07},
118a6e3f4f3SSteve Lee 	{MAX98390_ENV_TRACK_HOLD_RATE, 0x07},
119a6e3f4f3SSteve Lee 	{MAX98390_ENV_TRACK_CTRL, 0x01},
120a6e3f4f3SSteve Lee 	{MAX98390_BOOST_BYPASS1, 0x49},
121a6e3f4f3SSteve Lee 	{MAX98390_BOOST_BYPASS2, 0x2b},
122a6e3f4f3SSteve Lee 	{MAX98390_BOOST_BYPASS3, 0x08},
123a6e3f4f3SSteve Lee 	{MAX98390_FET_SCALING1, 0x00},
124a6e3f4f3SSteve Lee 	{MAX98390_FET_SCALING2, 0x03},
125a6e3f4f3SSteve Lee 	{MAX98390_FET_SCALING3, 0x00},
126a6e3f4f3SSteve Lee 	{MAX98390_FET_SCALING4, 0x07},
127a6e3f4f3SSteve Lee 	{MAX98390_SPK_SPEEDUP, 0x00},
128a6e3f4f3SSteve Lee 	{DSMIG_WB_DRC_RELEASE_TIME_1, 0x00},
129a6e3f4f3SSteve Lee 	{DSMIG_WB_DRC_RELEASE_TIME_2, 0x00},
130a6e3f4f3SSteve Lee 	{DSMIG_WB_DRC_ATTACK_TIME_1, 0x00},
131a6e3f4f3SSteve Lee 	{DSMIG_WB_DRC_ATTACK_TIME_2, 0x00},
132a6e3f4f3SSteve Lee 	{DSMIG_WB_DRC_COMPRESSION_RATIO, 0x00},
133a6e3f4f3SSteve Lee 	{DSMIG_WB_DRC_COMPRESSION_THRESHOLD, 0x00},
134a6e3f4f3SSteve Lee 	{DSMIG_WB_DRC_MAKEUPGAIN, 0x00},
135a6e3f4f3SSteve Lee 	{DSMIG_WB_DRC_NOISE_GATE_THRESHOLD, 0x00},
136a6e3f4f3SSteve Lee 	{DSMIG_WBDRC_HPF_ENABLE, 0x00},
137a6e3f4f3SSteve Lee 	{DSMIG_WB_DRC_TEST_SMOOTHER_OUT_EN, 0x00},
138a6e3f4f3SSteve Lee 	{DSMIG_PPR_THRESHOLD, 0x00},
139a6e3f4f3SSteve Lee 	{DSM_STEREO_BASS_CHANNEL_SELECT, 0x00},
140a6e3f4f3SSteve Lee 	{DSM_TPROT_THRESHOLD_BYTE0, 0x00},
141a6e3f4f3SSteve Lee 	{DSM_TPROT_THRESHOLD_BYTE1, 0x00},
142a6e3f4f3SSteve Lee 	{DSM_TPROT_ROOM_TEMPERATURE_BYTE0, 0x00},
143a6e3f4f3SSteve Lee 	{DSM_TPROT_ROOM_TEMPERATURE_BYTE1, 0x00},
144a6e3f4f3SSteve Lee 	{DSM_TPROT_RECIP_RDC_ROOM_BYTE0, 0x00},
145a6e3f4f3SSteve Lee 	{DSM_TPROT_RECIP_RDC_ROOM_BYTE1, 0x00},
146a6e3f4f3SSteve Lee 	{DSM_TPROT_RECIP_RDC_ROOM_BYTE2, 0x00},
147a6e3f4f3SSteve Lee 	{DSM_TPROT_RECIP_TCONST_BYTE0, 0x00},
148a6e3f4f3SSteve Lee 	{DSM_TPROT_RECIP_TCONST_BYTE1, 0x00},
149a6e3f4f3SSteve Lee 	{DSM_TPROT_RECIP_TCONST_BYTE2, 0x00},
150a6e3f4f3SSteve Lee 	{DSM_THERMAL_ATTENUATION_SETTINGS, 0x00},
151a6e3f4f3SSteve Lee 	{DSM_THERMAL_PILOT_TONE_ATTENUATION, 0x00},
152a6e3f4f3SSteve Lee 	{DSM_TPROT_PG_TEMP_THRESH_BYTE0, 0x00},
153a6e3f4f3SSteve Lee 	{DSM_TPROT_PG_TEMP_THRESH_BYTE1, 0x00},
154a6e3f4f3SSteve Lee 	{DSMIG_DEBUZZER_THRESHOLD, 0x00},
155a6e3f4f3SSteve Lee 	{DSMIG_DEBUZZER_ALPHA_COEF_TEST_ONLY, 0x08},
156a6e3f4f3SSteve Lee 	{DSM_VOL_ENA, 0x20},
157a6e3f4f3SSteve Lee 	{DSM_VOL_CTRL, 0xa0},
158a6e3f4f3SSteve Lee 	{DSMIG_EN, 0x00},
159a6e3f4f3SSteve Lee 	{MAX98390_R23E1_DSP_GLOBAL_EN, 0x00},
160a6e3f4f3SSteve Lee 	{MAX98390_R23FF_GLOBAL_EN, 0x00},
161a6e3f4f3SSteve Lee };
162a6e3f4f3SSteve Lee 
max98390_dai_set_fmt(struct snd_soc_dai * codec_dai,unsigned int fmt)163a6e3f4f3SSteve Lee static int max98390_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
164a6e3f4f3SSteve Lee {
165a6e3f4f3SSteve Lee 	struct snd_soc_component *component = codec_dai->component;
166a6e3f4f3SSteve Lee 	struct max98390_priv *max98390 =
167a6e3f4f3SSteve Lee 		snd_soc_component_get_drvdata(component);
168a6e3f4f3SSteve Lee 	unsigned int mode;
169a6e3f4f3SSteve Lee 	unsigned int format;
170a6e3f4f3SSteve Lee 	unsigned int invert = 0;
171a6e3f4f3SSteve Lee 
172a6e3f4f3SSteve Lee 	dev_dbg(component->dev, "%s: fmt 0x%08X\n", __func__, fmt);
173a6e3f4f3SSteve Lee 
174c536d745SMark Brown 	switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
175c536d745SMark Brown 	case SND_SOC_DAIFMT_CBC_CFC:
176a6e3f4f3SSteve Lee 		mode = MAX98390_PCM_MASTER_MODE_SLAVE;
177a6e3f4f3SSteve Lee 		break;
178c536d745SMark Brown 	case SND_SOC_DAIFMT_CBP_CFP:
179c536d745SMark Brown 		max98390->provider = true;
180a6e3f4f3SSteve Lee 		mode = MAX98390_PCM_MASTER_MODE_MASTER;
181a6e3f4f3SSteve Lee 		break;
182a6e3f4f3SSteve Lee 	default:
183a6e3f4f3SSteve Lee 		dev_err(component->dev, "DAI clock mode unsupported\n");
184a6e3f4f3SSteve Lee 		return -EINVAL;
185a6e3f4f3SSteve Lee 	}
186a6e3f4f3SSteve Lee 
187a6e3f4f3SSteve Lee 	regmap_update_bits(max98390->regmap,
188a6e3f4f3SSteve Lee 		MAX98390_PCM_MASTER_MODE,
189a6e3f4f3SSteve Lee 		MAX98390_PCM_MASTER_MODE_MASK,
190a6e3f4f3SSteve Lee 		mode);
191a6e3f4f3SSteve Lee 
192a6e3f4f3SSteve Lee 	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
193a6e3f4f3SSteve Lee 	case SND_SOC_DAIFMT_NB_NF:
194a6e3f4f3SSteve Lee 		break;
195a6e3f4f3SSteve Lee 	case SND_SOC_DAIFMT_IB_NF:
196a6e3f4f3SSteve Lee 		invert = MAX98390_PCM_MODE_CFG_PCM_BCLKEDGE;
197a6e3f4f3SSteve Lee 		break;
198a6e3f4f3SSteve Lee 	default:
199a6e3f4f3SSteve Lee 		dev_err(component->dev, "DAI invert mode unsupported\n");
200a6e3f4f3SSteve Lee 		return -EINVAL;
201a6e3f4f3SSteve Lee 	}
202a6e3f4f3SSteve Lee 
203a6e3f4f3SSteve Lee 	regmap_update_bits(max98390->regmap,
204a6e3f4f3SSteve Lee 		MAX98390_PCM_MODE_CFG,
205a6e3f4f3SSteve Lee 		MAX98390_PCM_MODE_CFG_PCM_BCLKEDGE,
206a6e3f4f3SSteve Lee 		invert);
207a6e3f4f3SSteve Lee 
208a6e3f4f3SSteve Lee 	/* interface format */
209a6e3f4f3SSteve Lee 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
210a6e3f4f3SSteve Lee 	case SND_SOC_DAIFMT_I2S:
211a6e3f4f3SSteve Lee 		format = MAX98390_PCM_FORMAT_I2S;
212a6e3f4f3SSteve Lee 		break;
213a6e3f4f3SSteve Lee 	case SND_SOC_DAIFMT_LEFT_J:
214a6e3f4f3SSteve Lee 		format = MAX98390_PCM_FORMAT_LJ;
215a6e3f4f3SSteve Lee 		break;
216a6e3f4f3SSteve Lee 	case SND_SOC_DAIFMT_DSP_A:
217a6e3f4f3SSteve Lee 		format = MAX98390_PCM_FORMAT_TDM_MODE1;
218a6e3f4f3SSteve Lee 		break;
219a6e3f4f3SSteve Lee 	case SND_SOC_DAIFMT_DSP_B:
220a6e3f4f3SSteve Lee 		format = MAX98390_PCM_FORMAT_TDM_MODE0;
221a6e3f4f3SSteve Lee 		break;
222a6e3f4f3SSteve Lee 	default:
223a6e3f4f3SSteve Lee 		return -EINVAL;
224a6e3f4f3SSteve Lee 	}
225a6e3f4f3SSteve Lee 
226a6e3f4f3SSteve Lee 	regmap_update_bits(max98390->regmap,
227a6e3f4f3SSteve Lee 		MAX98390_PCM_MODE_CFG,
228a6e3f4f3SSteve Lee 		MAX98390_PCM_MODE_CFG_FORMAT_MASK,
229a6e3f4f3SSteve Lee 		format << MAX98390_PCM_MODE_CFG_FORMAT_SHIFT);
230a6e3f4f3SSteve Lee 
231a6e3f4f3SSteve Lee 	return 0;
232a6e3f4f3SSteve Lee }
233a6e3f4f3SSteve Lee 
max98390_get_bclk_sel(int bclk)234a6e3f4f3SSteve Lee static int max98390_get_bclk_sel(int bclk)
235a6e3f4f3SSteve Lee {
236a6e3f4f3SSteve Lee 	int i;
237a6e3f4f3SSteve Lee 	/* BCLKs per LRCLK */
238a6e3f4f3SSteve Lee 	static int bclk_sel_table[] = {
239a6e3f4f3SSteve Lee 		32, 48, 64, 96, 128, 192, 256, 320, 384, 512,
240a6e3f4f3SSteve Lee 	};
241a6e3f4f3SSteve Lee 	/* match BCLKs per LRCLK */
242a6e3f4f3SSteve Lee 	for (i = 0; i < ARRAY_SIZE(bclk_sel_table); i++) {
243a6e3f4f3SSteve Lee 		if (bclk_sel_table[i] == bclk)
244a6e3f4f3SSteve Lee 			return i + 2;
245a6e3f4f3SSteve Lee 	}
246a6e3f4f3SSteve Lee 	return 0;
247a6e3f4f3SSteve Lee }
248a6e3f4f3SSteve Lee 
max98390_set_clock(struct snd_soc_component * component,struct snd_pcm_hw_params * params)249a6e3f4f3SSteve Lee static int max98390_set_clock(struct snd_soc_component *component,
250a6e3f4f3SSteve Lee 		struct snd_pcm_hw_params *params)
251a6e3f4f3SSteve Lee {
252a6e3f4f3SSteve Lee 	struct max98390_priv *max98390 =
253a6e3f4f3SSteve Lee 		snd_soc_component_get_drvdata(component);
254a6e3f4f3SSteve Lee 	/* codec MCLK rate in master mode */
255a6e3f4f3SSteve Lee 	static int rate_table[] = {
256a6e3f4f3SSteve Lee 		5644800, 6000000, 6144000, 6500000,
257a6e3f4f3SSteve Lee 		9600000, 11289600, 12000000, 12288000,
258a6e3f4f3SSteve Lee 		13000000, 19200000,
259a6e3f4f3SSteve Lee 	};
260a6e3f4f3SSteve Lee 	/* BCLK/LRCLK ratio calculation */
261a6e3f4f3SSteve Lee 	int blr_clk_ratio = params_channels(params)
262a6e3f4f3SSteve Lee 		* snd_pcm_format_width(params_format(params));
263a6e3f4f3SSteve Lee 	int value;
264a6e3f4f3SSteve Lee 
265c536d745SMark Brown 	if (max98390->provider) {
266a6e3f4f3SSteve Lee 		int i;
267a6e3f4f3SSteve Lee 		/* match rate to closest value */
268a6e3f4f3SSteve Lee 		for (i = 0; i < ARRAY_SIZE(rate_table); i++) {
269a6e3f4f3SSteve Lee 			if (rate_table[i] >= max98390->sysclk)
270a6e3f4f3SSteve Lee 				break;
271a6e3f4f3SSteve Lee 		}
272a6e3f4f3SSteve Lee 		if (i == ARRAY_SIZE(rate_table)) {
273a6e3f4f3SSteve Lee 			dev_err(component->dev, "failed to find proper clock rate.\n");
274a6e3f4f3SSteve Lee 			return -EINVAL;
275a6e3f4f3SSteve Lee 		}
276a6e3f4f3SSteve Lee 
277a6e3f4f3SSteve Lee 		regmap_update_bits(max98390->regmap,
278a6e3f4f3SSteve Lee 			MAX98390_PCM_MASTER_MODE,
279a6e3f4f3SSteve Lee 			MAX98390_PCM_MASTER_MODE_MCLK_MASK,
280a6e3f4f3SSteve Lee 			i << MAX98390_PCM_MASTER_MODE_MCLK_RATE_SHIFT);
281a6e3f4f3SSteve Lee 	}
282a6e3f4f3SSteve Lee 
283a6e3f4f3SSteve Lee 	if (!max98390->tdm_mode) {
284a6e3f4f3SSteve Lee 		/* BCLK configuration */
285a6e3f4f3SSteve Lee 		value = max98390_get_bclk_sel(blr_clk_ratio);
286a6e3f4f3SSteve Lee 		if (!value) {
287a6e3f4f3SSteve Lee 			dev_err(component->dev, "format unsupported %d\n",
288a6e3f4f3SSteve Lee 				params_format(params));
289a6e3f4f3SSteve Lee 			return -EINVAL;
290a6e3f4f3SSteve Lee 		}
291a6e3f4f3SSteve Lee 
292a6e3f4f3SSteve Lee 		regmap_update_bits(max98390->regmap,
293a6e3f4f3SSteve Lee 			MAX98390_PCM_CLK_SETUP,
294a6e3f4f3SSteve Lee 			MAX98390_PCM_CLK_SETUP_BSEL_MASK,
295a6e3f4f3SSteve Lee 			value);
296a6e3f4f3SSteve Lee 	}
297a6e3f4f3SSteve Lee 	return 0;
298a6e3f4f3SSteve Lee }
299a6e3f4f3SSteve Lee 
max98390_dai_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params,struct snd_soc_dai * dai)300a6e3f4f3SSteve Lee static int max98390_dai_hw_params(struct snd_pcm_substream *substream,
301a6e3f4f3SSteve Lee 		struct snd_pcm_hw_params *params,
302a6e3f4f3SSteve Lee 		struct snd_soc_dai *dai)
303a6e3f4f3SSteve Lee {
304a6e3f4f3SSteve Lee 	struct snd_soc_component *component =
305a6e3f4f3SSteve Lee 		dai->component;
306a6e3f4f3SSteve Lee 	struct max98390_priv *max98390 =
307a6e3f4f3SSteve Lee 		snd_soc_component_get_drvdata(component);
308a6e3f4f3SSteve Lee 
309a6e3f4f3SSteve Lee 	unsigned int sampling_rate;
310a6e3f4f3SSteve Lee 	unsigned int chan_sz;
311a6e3f4f3SSteve Lee 
312a6e3f4f3SSteve Lee 	/* pcm mode configuration */
313a6e3f4f3SSteve Lee 	switch (snd_pcm_format_width(params_format(params))) {
314a6e3f4f3SSteve Lee 	case 16:
315a6e3f4f3SSteve Lee 		chan_sz = MAX98390_PCM_MODE_CFG_CHANSZ_16;
316a6e3f4f3SSteve Lee 		break;
317a6e3f4f3SSteve Lee 	case 24:
318a6e3f4f3SSteve Lee 		chan_sz = MAX98390_PCM_MODE_CFG_CHANSZ_24;
319a6e3f4f3SSteve Lee 		break;
320a6e3f4f3SSteve Lee 	case 32:
321a6e3f4f3SSteve Lee 		chan_sz = MAX98390_PCM_MODE_CFG_CHANSZ_32;
322a6e3f4f3SSteve Lee 		break;
323a6e3f4f3SSteve Lee 	default:
324a6e3f4f3SSteve Lee 		dev_err(component->dev, "format unsupported %d\n",
325a6e3f4f3SSteve Lee 			params_format(params));
326a6e3f4f3SSteve Lee 		goto err;
327a6e3f4f3SSteve Lee 	}
328a6e3f4f3SSteve Lee 
329a6e3f4f3SSteve Lee 	regmap_update_bits(max98390->regmap,
330a6e3f4f3SSteve Lee 		MAX98390_PCM_MODE_CFG,
331a6e3f4f3SSteve Lee 		MAX98390_PCM_MODE_CFG_CHANSZ_MASK, chan_sz);
332a6e3f4f3SSteve Lee 
333a6e3f4f3SSteve Lee 	dev_dbg(component->dev, "format supported %d",
334a6e3f4f3SSteve Lee 		params_format(params));
335a6e3f4f3SSteve Lee 
336a6e3f4f3SSteve Lee 	/* sampling rate configuration */
337a6e3f4f3SSteve Lee 	switch (params_rate(params)) {
338a6e3f4f3SSteve Lee 	case 8000:
339a6e3f4f3SSteve Lee 		sampling_rate = MAX98390_PCM_SR_SET1_SR_8000;
340a6e3f4f3SSteve Lee 		break;
341a6e3f4f3SSteve Lee 	case 11025:
342a6e3f4f3SSteve Lee 		sampling_rate = MAX98390_PCM_SR_SET1_SR_11025;
343a6e3f4f3SSteve Lee 		break;
344a6e3f4f3SSteve Lee 	case 12000:
345a6e3f4f3SSteve Lee 		sampling_rate = MAX98390_PCM_SR_SET1_SR_12000;
346a6e3f4f3SSteve Lee 		break;
347a6e3f4f3SSteve Lee 	case 16000:
348a6e3f4f3SSteve Lee 		sampling_rate = MAX98390_PCM_SR_SET1_SR_16000;
349a6e3f4f3SSteve Lee 		break;
350a6e3f4f3SSteve Lee 	case 22050:
351a6e3f4f3SSteve Lee 		sampling_rate = MAX98390_PCM_SR_SET1_SR_22050;
352a6e3f4f3SSteve Lee 		break;
353a6e3f4f3SSteve Lee 	case 24000:
354a6e3f4f3SSteve Lee 		sampling_rate = MAX98390_PCM_SR_SET1_SR_24000;
355a6e3f4f3SSteve Lee 		break;
356a6e3f4f3SSteve Lee 	case 32000:
357a6e3f4f3SSteve Lee 		sampling_rate = MAX98390_PCM_SR_SET1_SR_32000;
358a6e3f4f3SSteve Lee 		break;
359a6e3f4f3SSteve Lee 	case 44100:
360a6e3f4f3SSteve Lee 		sampling_rate = MAX98390_PCM_SR_SET1_SR_44100;
361a6e3f4f3SSteve Lee 		break;
362a6e3f4f3SSteve Lee 	case 48000:
363a6e3f4f3SSteve Lee 		sampling_rate = MAX98390_PCM_SR_SET1_SR_48000;
364a6e3f4f3SSteve Lee 		break;
365a6e3f4f3SSteve Lee 	default:
366a6e3f4f3SSteve Lee 		dev_err(component->dev, "rate %d not supported\n",
367a6e3f4f3SSteve Lee 			params_rate(params));
368a6e3f4f3SSteve Lee 		goto err;
369a6e3f4f3SSteve Lee 	}
370a6e3f4f3SSteve Lee 
371a6e3f4f3SSteve Lee 	/* set DAI_SR to correct LRCLK frequency */
372a6e3f4f3SSteve Lee 	regmap_update_bits(max98390->regmap,
373a6e3f4f3SSteve Lee 		MAX98390_PCM_SR_SETUP,
374a6e3f4f3SSteve Lee 		MAX98390_PCM_SR_SET1_SR_MASK,
375a6e3f4f3SSteve Lee 		sampling_rate);
376a6e3f4f3SSteve Lee 
377a6e3f4f3SSteve Lee 	return max98390_set_clock(component, params);
378a6e3f4f3SSteve Lee err:
379a6e3f4f3SSteve Lee 	return -EINVAL;
380a6e3f4f3SSteve Lee }
381a6e3f4f3SSteve Lee 
max98390_dai_tdm_slot(struct snd_soc_dai * dai,unsigned int tx_mask,unsigned int rx_mask,int slots,int slot_width)382a6e3f4f3SSteve Lee static int max98390_dai_tdm_slot(struct snd_soc_dai *dai,
383a6e3f4f3SSteve Lee 		unsigned int tx_mask, unsigned int rx_mask,
384a6e3f4f3SSteve Lee 		int slots, int slot_width)
385a6e3f4f3SSteve Lee {
386a6e3f4f3SSteve Lee 	struct snd_soc_component *component = dai->component;
387a6e3f4f3SSteve Lee 	struct max98390_priv *max98390 =
388a6e3f4f3SSteve Lee 		snd_soc_component_get_drvdata(component);
389a6e3f4f3SSteve Lee 
390a6e3f4f3SSteve Lee 	int bsel;
391a6e3f4f3SSteve Lee 	unsigned int chan_sz;
392a6e3f4f3SSteve Lee 
393a6e3f4f3SSteve Lee 	if (!tx_mask && !rx_mask && !slots && !slot_width)
394a6e3f4f3SSteve Lee 		max98390->tdm_mode = false;
395a6e3f4f3SSteve Lee 	else
396a6e3f4f3SSteve Lee 		max98390->tdm_mode = true;
397a6e3f4f3SSteve Lee 
398a6e3f4f3SSteve Lee 	dev_dbg(component->dev,
399a6e3f4f3SSteve Lee 		"Tdm mode : %d\n", max98390->tdm_mode);
400a6e3f4f3SSteve Lee 
401a6e3f4f3SSteve Lee 	/* BCLK configuration */
402a6e3f4f3SSteve Lee 	bsel = max98390_get_bclk_sel(slots * slot_width);
403a6e3f4f3SSteve Lee 	if (!bsel) {
404a6e3f4f3SSteve Lee 		dev_err(component->dev, "BCLK %d not supported\n",
405a6e3f4f3SSteve Lee 			slots * slot_width);
406a6e3f4f3SSteve Lee 		return -EINVAL;
407a6e3f4f3SSteve Lee 	}
408a6e3f4f3SSteve Lee 
409a6e3f4f3SSteve Lee 	regmap_update_bits(max98390->regmap,
410a6e3f4f3SSteve Lee 		MAX98390_PCM_CLK_SETUP,
411a6e3f4f3SSteve Lee 		MAX98390_PCM_CLK_SETUP_BSEL_MASK,
412a6e3f4f3SSteve Lee 		bsel);
413a6e3f4f3SSteve Lee 
414a6e3f4f3SSteve Lee 	/* Channel size configuration */
415a6e3f4f3SSteve Lee 	switch (slot_width) {
416a6e3f4f3SSteve Lee 	case 16:
417a6e3f4f3SSteve Lee 		chan_sz = MAX98390_PCM_MODE_CFG_CHANSZ_16;
418a6e3f4f3SSteve Lee 		break;
419a6e3f4f3SSteve Lee 	case 24:
420a6e3f4f3SSteve Lee 		chan_sz = MAX98390_PCM_MODE_CFG_CHANSZ_24;
421a6e3f4f3SSteve Lee 		break;
422a6e3f4f3SSteve Lee 	case 32:
423a6e3f4f3SSteve Lee 		chan_sz = MAX98390_PCM_MODE_CFG_CHANSZ_32;
424a6e3f4f3SSteve Lee 		break;
425a6e3f4f3SSteve Lee 	default:
426a6e3f4f3SSteve Lee 		dev_err(component->dev, "format unsupported %d\n",
427a6e3f4f3SSteve Lee 			slot_width);
428a6e3f4f3SSteve Lee 		return -EINVAL;
429a6e3f4f3SSteve Lee 	}
430a6e3f4f3SSteve Lee 
431a6e3f4f3SSteve Lee 	regmap_update_bits(max98390->regmap,
432a6e3f4f3SSteve Lee 		MAX98390_PCM_MODE_CFG,
433a6e3f4f3SSteve Lee 		MAX98390_PCM_MODE_CFG_CHANSZ_MASK, chan_sz);
434a6e3f4f3SSteve Lee 
435a6e3f4f3SSteve Lee 	/* Rx slot configuration */
436a6e3f4f3SSteve Lee 	regmap_write(max98390->regmap,
437a6e3f4f3SSteve Lee 		MAX98390_PCM_RX_EN_A,
438a6e3f4f3SSteve Lee 		rx_mask & 0xFF);
439a6e3f4f3SSteve Lee 	regmap_write(max98390->regmap,
440a6e3f4f3SSteve Lee 		MAX98390_PCM_RX_EN_B,
441a6e3f4f3SSteve Lee 		(rx_mask & 0xFF00) >> 8);
442a6e3f4f3SSteve Lee 
443a6e3f4f3SSteve Lee 	/* Tx slot Hi-Z configuration */
444a6e3f4f3SSteve Lee 	regmap_write(max98390->regmap,
445a6e3f4f3SSteve Lee 		MAX98390_PCM_TX_HIZ_CTRL_A,
446a6e3f4f3SSteve Lee 		~tx_mask & 0xFF);
447a6e3f4f3SSteve Lee 	regmap_write(max98390->regmap,
448a6e3f4f3SSteve Lee 		MAX98390_PCM_TX_HIZ_CTRL_B,
449a6e3f4f3SSteve Lee 		(~tx_mask & 0xFF00) >> 8);
450a6e3f4f3SSteve Lee 
451a6e3f4f3SSteve Lee 	return 0;
452a6e3f4f3SSteve Lee }
453a6e3f4f3SSteve Lee 
max98390_dai_set_sysclk(struct snd_soc_dai * dai,int clk_id,unsigned int freq,int dir)454a6e3f4f3SSteve Lee static int max98390_dai_set_sysclk(struct snd_soc_dai *dai,
455a6e3f4f3SSteve Lee 		int clk_id, unsigned int freq, int dir)
456a6e3f4f3SSteve Lee {
457a6e3f4f3SSteve Lee 	struct snd_soc_component *component = dai->component;
458a6e3f4f3SSteve Lee 	struct max98390_priv *max98390 =
459a6e3f4f3SSteve Lee 		snd_soc_component_get_drvdata(component);
460a6e3f4f3SSteve Lee 
461a6e3f4f3SSteve Lee 	max98390->sysclk = freq;
462a6e3f4f3SSteve Lee 	return 0;
463a6e3f4f3SSteve Lee }
464a6e3f4f3SSteve Lee 
465a6e3f4f3SSteve Lee static const struct snd_soc_dai_ops max98390_dai_ops = {
466a6e3f4f3SSteve Lee 	.set_sysclk = max98390_dai_set_sysclk,
467a6e3f4f3SSteve Lee 	.set_fmt = max98390_dai_set_fmt,
468a6e3f4f3SSteve Lee 	.hw_params = max98390_dai_hw_params,
469a6e3f4f3SSteve Lee 	.set_tdm_slot = max98390_dai_tdm_slot,
470a6e3f4f3SSteve Lee };
471a6e3f4f3SSteve Lee 
max98390_dac_event(struct snd_soc_dapm_widget * w,struct snd_kcontrol * kcontrol,int event)472a6e3f4f3SSteve Lee static int max98390_dac_event(struct snd_soc_dapm_widget *w,
473a6e3f4f3SSteve Lee 		struct snd_kcontrol *kcontrol, int event)
474a6e3f4f3SSteve Lee {
475a6e3f4f3SSteve Lee 	struct snd_soc_component *component =
476a6e3f4f3SSteve Lee 		snd_soc_dapm_to_component(w->dapm);
477a6e3f4f3SSteve Lee 	struct max98390_priv *max98390 =
478a6e3f4f3SSteve Lee 		snd_soc_component_get_drvdata(component);
479a6e3f4f3SSteve Lee 
480a6e3f4f3SSteve Lee 	switch (event) {
481a6e3f4f3SSteve Lee 	case SND_SOC_DAPM_POST_PMU:
482a6e3f4f3SSteve Lee 		regmap_update_bits(max98390->regmap,
483a6e3f4f3SSteve Lee 			MAX98390_R203A_AMP_EN,
484a6e3f4f3SSteve Lee 			MAX98390_AMP_EN_MASK, 1);
485a6e3f4f3SSteve Lee 		regmap_update_bits(max98390->regmap,
486a6e3f4f3SSteve Lee 			MAX98390_R23FF_GLOBAL_EN,
487a6e3f4f3SSteve Lee 			MAX98390_GLOBAL_EN_MASK, 1);
488a6e3f4f3SSteve Lee 		break;
489a6e3f4f3SSteve Lee 	case SND_SOC_DAPM_POST_PMD:
490a6e3f4f3SSteve Lee 		regmap_update_bits(max98390->regmap,
491a6e3f4f3SSteve Lee 			MAX98390_R23FF_GLOBAL_EN,
492a6e3f4f3SSteve Lee 			MAX98390_GLOBAL_EN_MASK, 0);
493a6e3f4f3SSteve Lee 		regmap_update_bits(max98390->regmap,
494a6e3f4f3SSteve Lee 			MAX98390_R203A_AMP_EN,
495a6e3f4f3SSteve Lee 			MAX98390_AMP_EN_MASK, 0);
496a6e3f4f3SSteve Lee 		break;
497a6e3f4f3SSteve Lee 	}
498a6e3f4f3SSteve Lee 	return 0;
499a6e3f4f3SSteve Lee }
500a6e3f4f3SSteve Lee 
501a6e3f4f3SSteve Lee static const char * const max98390_switch_text[] = {
502a6e3f4f3SSteve Lee 	"Left", "Right", "LeftRight"};
503a6e3f4f3SSteve Lee 
504a6e3f4f3SSteve Lee static const char * const max98390_boost_voltage_text[] = {
505a6e3f4f3SSteve Lee 	"6.5V", "6.625V", "6.75V", "6.875V", "7V", "7.125V", "7.25V", "7.375V",
506a6e3f4f3SSteve Lee 	"7.5V", "7.625V", "7.75V", "7.875V", "8V", "8.125V", "8.25V", "8.375V",
507a6e3f4f3SSteve Lee 	"8.5V", "8.625V", "8.75V", "8.875V", "9V", "9.125V", "9.25V", "9.375V",
508a6e3f4f3SSteve Lee 	"9.5V", "9.625V", "9.75V", "9.875V", "10V"
509a6e3f4f3SSteve Lee };
510a6e3f4f3SSteve Lee 
511a6e3f4f3SSteve Lee static SOC_ENUM_SINGLE_DECL(max98390_boost_voltage,
512a6e3f4f3SSteve Lee 		MAX98390_BOOST_CTRL0, 0,
513a6e3f4f3SSteve Lee 		max98390_boost_voltage_text);
514a6e3f4f3SSteve Lee 
515a6e3f4f3SSteve Lee static DECLARE_TLV_DB_SCALE(max98390_spk_tlv, 300, 300, 0);
516a6e3f4f3SSteve Lee static DECLARE_TLV_DB_SCALE(max98390_digital_tlv, -8000, 50, 0);
517a6e3f4f3SSteve Lee 
518a6e3f4f3SSteve Lee static const char * const max98390_current_limit_text[] = {
519a6e3f4f3SSteve Lee 	"0.00A", "0.50A", "1.00A", "1.05A", "1.10A", "1.15A", "1.20A", "1.25A",
520a6e3f4f3SSteve Lee 	"1.30A", "1.35A", "1.40A", "1.45A", "1.50A", "1.55A", "1.60A", "1.65A",
521a6e3f4f3SSteve Lee 	"1.70A", "1.75A", "1.80A", "1.85A", "1.90A", "1.95A", "2.00A", "2.05A",
522a6e3f4f3SSteve Lee 	"2.10A", "2.15A", "2.20A", "2.25A", "2.30A", "2.35A", "2.40A", "2.45A",
523a6e3f4f3SSteve Lee 	"2.50A", "2.55A", "2.60A", "2.65A", "2.70A", "2.75A", "2.80A", "2.85A",
524a6e3f4f3SSteve Lee 	"2.90A", "2.95A", "3.00A", "3.05A", "3.10A", "3.15A", "3.20A", "3.25A",
525a6e3f4f3SSteve Lee 	"3.30A", "3.35A", "3.40A", "3.45A", "3.50A", "3.55A", "3.60A", "3.65A",
526a6e3f4f3SSteve Lee 	"3.70A", "3.75A", "3.80A", "3.85A", "3.90A", "3.95A", "4.00A", "4.05A",
527a6e3f4f3SSteve Lee 	"4.10A"
528a6e3f4f3SSteve Lee };
529a6e3f4f3SSteve Lee 
530a6e3f4f3SSteve Lee static SOC_ENUM_SINGLE_DECL(max98390_current_limit,
531a6e3f4f3SSteve Lee 		MAX98390_BOOST_CTRL1, 0,
532a6e3f4f3SSteve Lee 		max98390_current_limit_text);
533a6e3f4f3SSteve Lee 
max98390_ref_rdc_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)534a6e3f4f3SSteve Lee static int max98390_ref_rdc_put(struct snd_kcontrol *kcontrol,
535a6e3f4f3SSteve Lee 		struct snd_ctl_elem_value *ucontrol)
536a6e3f4f3SSteve Lee {
537a6e3f4f3SSteve Lee 	struct snd_soc_component *component =
538a6e3f4f3SSteve Lee 		snd_soc_kcontrol_component(kcontrol);
539a6e3f4f3SSteve Lee 	struct max98390_priv *max98390 =
540a6e3f4f3SSteve Lee 		snd_soc_component_get_drvdata(component);
541a6e3f4f3SSteve Lee 
542a6e3f4f3SSteve Lee 	max98390->ref_rdc_value = ucontrol->value.integer.value[0];
543a6e3f4f3SSteve Lee 
544a6e3f4f3SSteve Lee 	regmap_write(max98390->regmap, DSM_TPROT_RECIP_RDC_ROOM_BYTE0,
545a6e3f4f3SSteve Lee 		max98390->ref_rdc_value & 0x000000ff);
546a6e3f4f3SSteve Lee 	regmap_write(max98390->regmap, DSM_TPROT_RECIP_RDC_ROOM_BYTE1,
547a6e3f4f3SSteve Lee 		(max98390->ref_rdc_value >> 8) & 0x000000ff);
548a6e3f4f3SSteve Lee 	regmap_write(max98390->regmap, DSM_TPROT_RECIP_RDC_ROOM_BYTE2,
549a6e3f4f3SSteve Lee 		(max98390->ref_rdc_value >> 16) & 0x000000ff);
550a6e3f4f3SSteve Lee 
551a6e3f4f3SSteve Lee 	return 0;
552a6e3f4f3SSteve Lee }
553a6e3f4f3SSteve Lee 
max98390_ref_rdc_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)554a6e3f4f3SSteve Lee static int max98390_ref_rdc_get(struct snd_kcontrol *kcontrol,
555a6e3f4f3SSteve Lee 		struct snd_ctl_elem_value *ucontrol)
556a6e3f4f3SSteve Lee {
557a6e3f4f3SSteve Lee 	struct snd_soc_component *component =
558a6e3f4f3SSteve Lee 		snd_soc_kcontrol_component(kcontrol);
559a6e3f4f3SSteve Lee 	struct max98390_priv *max98390 =
560a6e3f4f3SSteve Lee 		snd_soc_component_get_drvdata(component);
561a6e3f4f3SSteve Lee 
562a6e3f4f3SSteve Lee 	ucontrol->value.integer.value[0] = max98390->ref_rdc_value;
563a6e3f4f3SSteve Lee 
564a6e3f4f3SSteve Lee 	return 0;
565a6e3f4f3SSteve Lee }
566a6e3f4f3SSteve Lee 
max98390_ambient_temp_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)567a6e3f4f3SSteve Lee static int max98390_ambient_temp_put(struct snd_kcontrol *kcontrol,
568a6e3f4f3SSteve Lee 		struct snd_ctl_elem_value *ucontrol)
569a6e3f4f3SSteve Lee {
570a6e3f4f3SSteve Lee 	struct snd_soc_component *component =
571a6e3f4f3SSteve Lee 		snd_soc_kcontrol_component(kcontrol);
572a6e3f4f3SSteve Lee 	struct max98390_priv *max98390 =
573a6e3f4f3SSteve Lee 		snd_soc_component_get_drvdata(component);
574a6e3f4f3SSteve Lee 
575a6e3f4f3SSteve Lee 	max98390->ambient_temp_value = ucontrol->value.integer.value[0];
576a6e3f4f3SSteve Lee 
577a6e3f4f3SSteve Lee 	regmap_write(max98390->regmap, DSM_TPROT_ROOM_TEMPERATURE_BYTE1,
578a6e3f4f3SSteve Lee 		(max98390->ambient_temp_value >> 8) & 0x000000ff);
579a6e3f4f3SSteve Lee 	regmap_write(max98390->regmap, DSM_TPROT_ROOM_TEMPERATURE_BYTE0,
580a6e3f4f3SSteve Lee 		(max98390->ambient_temp_value) & 0x000000ff);
581a6e3f4f3SSteve Lee 
582a6e3f4f3SSteve Lee 	return 0;
583a6e3f4f3SSteve Lee }
584a6e3f4f3SSteve Lee 
max98390_ambient_temp_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)585a6e3f4f3SSteve Lee static int max98390_ambient_temp_get(struct snd_kcontrol *kcontrol,
586a6e3f4f3SSteve Lee 		struct snd_ctl_elem_value *ucontrol)
587a6e3f4f3SSteve Lee {
588a6e3f4f3SSteve Lee 	struct snd_soc_component *component =
589a6e3f4f3SSteve Lee 		snd_soc_kcontrol_component(kcontrol);
590a6e3f4f3SSteve Lee 	struct max98390_priv *max98390 =
591a6e3f4f3SSteve Lee 		snd_soc_component_get_drvdata(component);
592a6e3f4f3SSteve Lee 
593a6e3f4f3SSteve Lee 	ucontrol->value.integer.value[0] = max98390->ambient_temp_value;
594a6e3f4f3SSteve Lee 
595a6e3f4f3SSteve Lee 	return 0;
596a6e3f4f3SSteve Lee }
597a6e3f4f3SSteve Lee 
max98390_adaptive_rdc_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)598a6e3f4f3SSteve Lee static int max98390_adaptive_rdc_put(struct snd_kcontrol *kcontrol,
599a6e3f4f3SSteve Lee 		struct snd_ctl_elem_value *ucontrol)
600a6e3f4f3SSteve Lee {
601a6e3f4f3SSteve Lee 	struct snd_soc_component *component =
602a6e3f4f3SSteve Lee 		snd_soc_kcontrol_component(kcontrol);
603a6e3f4f3SSteve Lee 
604a6e3f4f3SSteve Lee 	dev_warn(component->dev, "Put adaptive rdc not supported\n");
605a6e3f4f3SSteve Lee 
606a6e3f4f3SSteve Lee 	return 0;
607a6e3f4f3SSteve Lee }
608a6e3f4f3SSteve Lee 
max98390_adaptive_rdc_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)609a6e3f4f3SSteve Lee static int max98390_adaptive_rdc_get(struct snd_kcontrol *kcontrol,
610a6e3f4f3SSteve Lee 		struct snd_ctl_elem_value *ucontrol)
611a6e3f4f3SSteve Lee {
612a6e3f4f3SSteve Lee 	int rdc, rdc0;
613a6e3f4f3SSteve Lee 	struct snd_soc_component *component =
614a6e3f4f3SSteve Lee 		snd_soc_kcontrol_component(kcontrol);
615a6e3f4f3SSteve Lee 	struct max98390_priv *max98390 =
616a6e3f4f3SSteve Lee 		snd_soc_component_get_drvdata(component);
617a6e3f4f3SSteve Lee 
618a6e3f4f3SSteve Lee 	regmap_read(max98390->regmap, THERMAL_RDC_RD_BACK_BYTE1, &rdc);
619a6e3f4f3SSteve Lee 	regmap_read(max98390->regmap, THERMAL_RDC_RD_BACK_BYTE0, &rdc0);
620a6e3f4f3SSteve Lee 	ucontrol->value.integer.value[0] = rdc0 | rdc << 8;
621a6e3f4f3SSteve Lee 
622a6e3f4f3SSteve Lee 	return 0;
623a6e3f4f3SSteve Lee }
624a6e3f4f3SSteve Lee 
max98390_dsm_calib_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)625a6e3f4f3SSteve Lee static int max98390_dsm_calib_get(struct snd_kcontrol *kcontrol,
626a6e3f4f3SSteve Lee 		struct snd_ctl_elem_value *ucontrol)
627a6e3f4f3SSteve Lee {
628a6e3f4f3SSteve Lee 	/* Do nothing */
629a6e3f4f3SSteve Lee 	return 0;
630a6e3f4f3SSteve Lee }
631a6e3f4f3SSteve Lee 
max98390_dsm_calib_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)632a6e3f4f3SSteve Lee static int max98390_dsm_calib_put(struct snd_kcontrol *kcontrol,
633a6e3f4f3SSteve Lee 		struct snd_ctl_elem_value *ucontrol)
634a6e3f4f3SSteve Lee {
6359dd28b46SPeter Ujfalusi 	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
6369dd28b46SPeter Ujfalusi 	struct max98390_priv *max98390 = snd_soc_component_get_drvdata(component);
6379dd28b46SPeter Ujfalusi 	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
6389dd28b46SPeter Ujfalusi 	unsigned int rdc, rdc_cal_result, rdc_integer, rdc_factor, temp, val;
6399dd28b46SPeter Ujfalusi 
6409dd28b46SPeter Ujfalusi 	snd_soc_dapm_mutex_lock(dapm);
641a6e3f4f3SSteve Lee 
6426ac24610SSteve Lee 	regmap_read(max98390->regmap, MAX98390_R23FF_GLOBAL_EN, &val);
6439dd28b46SPeter Ujfalusi 	if (!val) {
6449dd28b46SPeter Ujfalusi 		/* Enable the codec for the duration of calibration readout */
6459dd28b46SPeter Ujfalusi 		regmap_update_bits(max98390->regmap, MAX98390_R203A_AMP_EN,
6469dd28b46SPeter Ujfalusi 				   MAX98390_AMP_EN_MASK, 1);
6479dd28b46SPeter Ujfalusi 		regmap_update_bits(max98390->regmap, MAX98390_R23FF_GLOBAL_EN,
6489dd28b46SPeter Ujfalusi 				   MAX98390_GLOBAL_EN_MASK, 1);
6496ac24610SSteve Lee 	}
650a6e3f4f3SSteve Lee 
6519dd28b46SPeter Ujfalusi 	regmap_read(max98390->regmap, THERMAL_RDC_RD_BACK_BYTE1, &rdc);
6529dd28b46SPeter Ujfalusi 	regmap_read(max98390->regmap, THERMAL_RDC_RD_BACK_BYTE0, &rdc_cal_result);
6539dd28b46SPeter Ujfalusi 	regmap_read(max98390->regmap, MAX98390_MEAS_ADC_CH2_READ, &temp);
6549dd28b46SPeter Ujfalusi 
6559dd28b46SPeter Ujfalusi 	if (!val) {
6569dd28b46SPeter Ujfalusi 		/* Disable the codec if it was disabled */
6579dd28b46SPeter Ujfalusi 		regmap_update_bits(max98390->regmap, MAX98390_R23FF_GLOBAL_EN,
6589dd28b46SPeter Ujfalusi 				   MAX98390_GLOBAL_EN_MASK, 0);
6599dd28b46SPeter Ujfalusi 		regmap_update_bits(max98390->regmap, MAX98390_R203A_AMP_EN,
6609dd28b46SPeter Ujfalusi 				   MAX98390_AMP_EN_MASK, 0);
6619dd28b46SPeter Ujfalusi 	}
6629dd28b46SPeter Ujfalusi 
6639dd28b46SPeter Ujfalusi 	snd_soc_dapm_mutex_unlock(dapm);
6649dd28b46SPeter Ujfalusi 
6659dd28b46SPeter Ujfalusi 	rdc_cal_result |= (rdc << 8) & 0x0000FFFF;
6669dd28b46SPeter Ujfalusi 	if (rdc_cal_result)
6679dd28b46SPeter Ujfalusi 		max98390->ref_rdc_value = 268435456U / rdc_cal_result;
6689dd28b46SPeter Ujfalusi 
6699dd28b46SPeter Ujfalusi 	max98390->ambient_temp_value = temp * 52 - 1188;
6709dd28b46SPeter Ujfalusi 
6719dd28b46SPeter Ujfalusi 	rdc_integer =  rdc_cal_result * 937  / 65536;
6729dd28b46SPeter Ujfalusi 	rdc_factor = ((rdc_cal_result * 937 * 100) / 65536) - (rdc_integer * 100);
6739dd28b46SPeter Ujfalusi 
6749dd28b46SPeter Ujfalusi 	dev_info(component->dev,
6759dd28b46SPeter Ujfalusi 		 "rdc resistance about %d.%02d ohm, reg=0x%X temp reg=0x%X\n",
6769dd28b46SPeter Ujfalusi 		 rdc_integer, rdc_factor, rdc_cal_result, temp);
6779dd28b46SPeter Ujfalusi 
678a6e3f4f3SSteve Lee 	return 0;
679a6e3f4f3SSteve Lee }
680a6e3f4f3SSteve Lee 
681a6e3f4f3SSteve Lee static const struct snd_kcontrol_new max98390_snd_controls[] = {
682a6e3f4f3SSteve Lee 	SOC_SINGLE_TLV("Digital Volume", DSM_VOL_CTRL,
683a6e3f4f3SSteve Lee 		0, 184, 0,
684a6e3f4f3SSteve Lee 		max98390_digital_tlv),
685a6e3f4f3SSteve Lee 	SOC_SINGLE_TLV("Speaker Volume", MAX98390_R203D_SPK_GAIN,
686a6e3f4f3SSteve Lee 		0, 6, 0,
687a6e3f4f3SSteve Lee 		max98390_spk_tlv),
688a6e3f4f3SSteve Lee 	SOC_SINGLE("Ramp Up Bypass Switch", MAX98390_R2039_AMP_DSP_CFG,
689a6e3f4f3SSteve Lee 		MAX98390_AMP_DSP_CFG_RMP_UP_SHIFT, 1, 0),
690a6e3f4f3SSteve Lee 	SOC_SINGLE("Ramp Down Bypass Switch", MAX98390_R2039_AMP_DSP_CFG,
691a6e3f4f3SSteve Lee 		MAX98390_AMP_DSP_CFG_RMP_DN_SHIFT, 1, 0),
692a6e3f4f3SSteve Lee 	SOC_SINGLE("Boost Clock Phase", MAX98390_BOOST_CTRL3,
693a6e3f4f3SSteve Lee 		MAX98390_BOOST_CLK_PHASE_CFG_SHIFT, 3, 0),
694a6e3f4f3SSteve Lee 	SOC_ENUM("Boost Output Voltage", max98390_boost_voltage),
695a6e3f4f3SSteve Lee 	SOC_ENUM("Current Limit", max98390_current_limit),
696a6e3f4f3SSteve Lee 	SOC_SINGLE_EXT("DSM Rdc", SND_SOC_NOPM, 0, 0xffffff, 0,
697a6e3f4f3SSteve Lee 		max98390_ref_rdc_get, max98390_ref_rdc_put),
698a6e3f4f3SSteve Lee 	SOC_SINGLE_EXT("DSM Ambient Temp", SND_SOC_NOPM, 0, 0xffff, 0,
699a6e3f4f3SSteve Lee 		max98390_ambient_temp_get, max98390_ambient_temp_put),
700a6e3f4f3SSteve Lee 	SOC_SINGLE_EXT("DSM Adaptive Rdc", SND_SOC_NOPM, 0, 0xffff, 0,
701a6e3f4f3SSteve Lee 		max98390_adaptive_rdc_get, max98390_adaptive_rdc_put),
702a6e3f4f3SSteve Lee 	SOC_SINGLE_EXT("DSM Calibration", SND_SOC_NOPM, 0, 1, 0,
703a6e3f4f3SSteve Lee 		max98390_dsm_calib_get, max98390_dsm_calib_put),
704a6e3f4f3SSteve Lee };
705a6e3f4f3SSteve Lee 
706a6e3f4f3SSteve Lee static const struct soc_enum dai_sel_enum =
707a6e3f4f3SSteve Lee 	SOC_ENUM_SINGLE(MAX98390_PCM_CH_SRC_1,
708a6e3f4f3SSteve Lee 		MAX98390_PCM_RX_CH_SRC_SHIFT,
709a6e3f4f3SSteve Lee 		3, max98390_switch_text);
710a6e3f4f3SSteve Lee 
711a6e3f4f3SSteve Lee static const struct snd_kcontrol_new max98390_dai_controls =
712a6e3f4f3SSteve Lee 	SOC_DAPM_ENUM("DAI Sel", dai_sel_enum);
713a6e3f4f3SSteve Lee 
714a6e3f4f3SSteve Lee static const struct snd_soc_dapm_widget max98390_dapm_widgets[] = {
715a6e3f4f3SSteve Lee 	SND_SOC_DAPM_DAC_E("Amp Enable", "HiFi Playback",
716dc5fb6d2SSteve Lee 		SND_SOC_NOPM, 0, 0, max98390_dac_event,
717a6e3f4f3SSteve Lee 		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
718a6e3f4f3SSteve Lee 	SND_SOC_DAPM_MUX("DAI Sel Mux", SND_SOC_NOPM, 0, 0,
719a6e3f4f3SSteve Lee 		&max98390_dai_controls),
720a6e3f4f3SSteve Lee 	SND_SOC_DAPM_OUTPUT("BE_OUT"),
721a6e3f4f3SSteve Lee };
722a6e3f4f3SSteve Lee 
723a6e3f4f3SSteve Lee static const struct snd_soc_dapm_route max98390_audio_map[] = {
724a6e3f4f3SSteve Lee 	/* Plabyack */
725a6e3f4f3SSteve Lee 	{"DAI Sel Mux", "Left", "Amp Enable"},
726a6e3f4f3SSteve Lee 	{"DAI Sel Mux", "Right", "Amp Enable"},
727a6e3f4f3SSteve Lee 	{"DAI Sel Mux", "LeftRight", "Amp Enable"},
728a6e3f4f3SSteve Lee 	{"BE_OUT", NULL, "DAI Sel Mux"},
729a6e3f4f3SSteve Lee };
730a6e3f4f3SSteve Lee 
max98390_readable_register(struct device * dev,unsigned int reg)731a6e3f4f3SSteve Lee static bool max98390_readable_register(struct device *dev, unsigned int reg)
732a6e3f4f3SSteve Lee {
733a6e3f4f3SSteve Lee 	switch (reg) {
734a6e3f4f3SSteve Lee 	case MAX98390_SOFTWARE_RESET ... MAX98390_INT_EN3:
735a6e3f4f3SSteve Lee 	case MAX98390_IRQ_CTRL ... MAX98390_WDOG_CTRL:
736a6e3f4f3SSteve Lee 	case MAX98390_MEAS_ADC_THERM_WARN_THRESH
737a6e3f4f3SSteve Lee 		... MAX98390_BROWNOUT_INFINITE_HOLD:
7384008b29eSSteve Lee 	case MAX98390_BROWNOUT_LVL_HOLD ... DSMIG_DEBUZZER_THRESHOLD:
7394008b29eSSteve Lee 	case DSM_VOL_ENA ... MAX98390_R24FF_REV_ID:
740a6e3f4f3SSteve Lee 		return true;
741a6e3f4f3SSteve Lee 	default:
742a6e3f4f3SSteve Lee 		return false;
743a6e3f4f3SSteve Lee 	}
744a6e3f4f3SSteve Lee };
745a6e3f4f3SSteve Lee 
max98390_volatile_reg(struct device * dev,unsigned int reg)746a6e3f4f3SSteve Lee static bool max98390_volatile_reg(struct device *dev, unsigned int reg)
747a6e3f4f3SSteve Lee {
748a6e3f4f3SSteve Lee 	switch (reg) {
749a6e3f4f3SSteve Lee 	case MAX98390_SOFTWARE_RESET ... MAX98390_INT_EN3:
750a6e3f4f3SSteve Lee 	case MAX98390_MEAS_ADC_CH0_READ ... MAX98390_MEAS_ADC_CH2_READ:
751a6e3f4f3SSteve Lee 	case MAX98390_PWR_GATE_STATUS ... MAX98390_BROWNOUT_STATUS:
752a6e3f4f3SSteve Lee 	case MAX98390_BROWNOUT_LOWEST_STATUS:
753a6e3f4f3SSteve Lee 	case MAX98390_ENV_TRACK_BOOST_VOUT_READ:
754a6e3f4f3SSteve Lee 	case DSM_STBASS_HPF_B0_BYTE0 ... DSM_DEBUZZER_ATTACK_TIME_BYTE2:
7554008b29eSSteve Lee 	case THERMAL_RDC_RD_BACK_BYTE1 ... DSMIG_DEBUZZER_THRESHOLD:
756a6e3f4f3SSteve Lee 	case DSM_THERMAL_GAIN ... DSM_WBDRC_GAIN:
757a6e3f4f3SSteve Lee 		return true;
758a6e3f4f3SSteve Lee 	default:
759a6e3f4f3SSteve Lee 		return false;
760a6e3f4f3SSteve Lee 	}
761a6e3f4f3SSteve Lee }
762a6e3f4f3SSteve Lee 
763a6e3f4f3SSteve Lee #define MAX98390_RATES SNDRV_PCM_RATE_8000_48000
764a6e3f4f3SSteve Lee 
765a6e3f4f3SSteve Lee #define MAX98390_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
766a6e3f4f3SSteve Lee 	SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
767a6e3f4f3SSteve Lee 
768a6e3f4f3SSteve Lee static struct snd_soc_dai_driver max98390_dai[] = {
769a6e3f4f3SSteve Lee 	{
770a6e3f4f3SSteve Lee 		.name = "max98390-aif1",
771a6e3f4f3SSteve Lee 		.playback = {
772a6e3f4f3SSteve Lee 			.stream_name = "HiFi Playback",
773a6e3f4f3SSteve Lee 			.channels_min = 1,
774a6e3f4f3SSteve Lee 			.channels_max = 2,
775a6e3f4f3SSteve Lee 			.rates = MAX98390_RATES,
776a6e3f4f3SSteve Lee 			.formats = MAX98390_FORMATS,
777a6e3f4f3SSteve Lee 		},
778a6e3f4f3SSteve Lee 		.capture = {
779a6e3f4f3SSteve Lee 			.stream_name = "HiFi Capture",
780a6e3f4f3SSteve Lee 			.channels_min = 1,
781a6e3f4f3SSteve Lee 			.channels_max = 2,
782a6e3f4f3SSteve Lee 			.rates = MAX98390_RATES,
783a6e3f4f3SSteve Lee 			.formats = MAX98390_FORMATS,
784a6e3f4f3SSteve Lee 		},
785a6e3f4f3SSteve Lee 		.ops = &max98390_dai_ops,
786a6e3f4f3SSteve Lee 	}
787a6e3f4f3SSteve Lee };
788a6e3f4f3SSteve Lee 
max98390_dsm_init(struct snd_soc_component * component)789a6e3f4f3SSteve Lee static int max98390_dsm_init(struct snd_soc_component *component)
790a6e3f4f3SSteve Lee {
791a6e3f4f3SSteve Lee 	int ret;
79297ed3e50SSteve Lee 	int param_size, param_start_addr;
793a6e3f4f3SSteve Lee 	char filename[128];
794a6e3f4f3SSteve Lee 	const char *vendor, *product;
795a6e3f4f3SSteve Lee 	struct max98390_priv *max98390 =
796a6e3f4f3SSteve Lee 		snd_soc_component_get_drvdata(component);
797a6e3f4f3SSteve Lee 	const struct firmware *fw;
798a6e3f4f3SSteve Lee 	char *dsm_param;
799a6e3f4f3SSteve Lee 
800a6e3f4f3SSteve Lee 	vendor = dmi_get_system_info(DMI_SYS_VENDOR);
801a6e3f4f3SSteve Lee 	product = dmi_get_system_info(DMI_PRODUCT_NAME);
802a6e3f4f3SSteve Lee 
803a10facb7SSteve Lee 	if (!strcmp(max98390->dsm_param_name, "default")) {
804a6e3f4f3SSteve Lee 		if (vendor && product) {
805a10facb7SSteve Lee 			snprintf(filename, sizeof(filename),
806a10facb7SSteve Lee 				"dsm_param_%s_%s.bin", vendor, product);
807a6e3f4f3SSteve Lee 		} else {
808a6e3f4f3SSteve Lee 			sprintf(filename, "dsm_param.bin");
809a6e3f4f3SSteve Lee 		}
810a10facb7SSteve Lee 	} else {
811a10facb7SSteve Lee 		snprintf(filename, sizeof(filename), "%s",
812a10facb7SSteve Lee 			max98390->dsm_param_name);
813a10facb7SSteve Lee 	}
814a6e3f4f3SSteve Lee 	ret = request_firmware(&fw, filename, component->dev);
815a6e3f4f3SSteve Lee 	if (ret) {
816a6e3f4f3SSteve Lee 		ret = request_firmware(&fw, "dsm_param.bin", component->dev);
817a10facb7SSteve Lee 		if (ret) {
818a10facb7SSteve Lee 			ret = request_firmware(&fw, "dsmparam.bin",
819a10facb7SSteve Lee 				component->dev);
820a6e3f4f3SSteve Lee 			if (ret)
821a6e3f4f3SSteve Lee 				goto err;
822a6e3f4f3SSteve Lee 		}
823a10facb7SSteve Lee 	}
824a6e3f4f3SSteve Lee 
825a6e3f4f3SSteve Lee 	dev_dbg(component->dev,
826678916ecSTakashi Iwai 		"max98390: param fw size %zd\n",
827a6e3f4f3SSteve Lee 		fw->size);
82897ed3e50SSteve Lee 	if (fw->size < MAX98390_DSM_PARAM_MIN_SIZE) {
82997ed3e50SSteve Lee 		dev_err(component->dev,
83097ed3e50SSteve Lee 			"param fw is invalid.\n");
8313cea33b6SDan Carpenter 		ret = -EINVAL;
83297ed3e50SSteve Lee 		goto err_alloc;
83397ed3e50SSteve Lee 	}
834a6e3f4f3SSteve Lee 	dsm_param = (char *)fw->data;
83597ed3e50SSteve Lee 	param_start_addr = (dsm_param[0] & 0xff) | (dsm_param[1] & 0xff) << 8;
83697ed3e50SSteve Lee 	param_size = (dsm_param[2] & 0xff) | (dsm_param[3] & 0xff) << 8;
83797ed3e50SSteve Lee 	if (param_size > MAX98390_DSM_PARAM_MAX_SIZE ||
838aa785705SSteve Lee 		param_start_addr < MAX98390_IRQ_CTRL ||
83997ed3e50SSteve Lee 		fw->size < param_size + MAX98390_DSM_PAYLOAD_OFFSET) {
84097ed3e50SSteve Lee 		dev_err(component->dev,
84197ed3e50SSteve Lee 			"param fw is invalid.\n");
8423cea33b6SDan Carpenter 		ret = -EINVAL;
84397ed3e50SSteve Lee 		goto err_alloc;
84497ed3e50SSteve Lee 	}
84597ed3e50SSteve Lee 	regmap_write(max98390->regmap, MAX98390_R203A_AMP_EN, 0x80);
846a6e3f4f3SSteve Lee 	dsm_param += MAX98390_DSM_PAYLOAD_OFFSET;
84797ed3e50SSteve Lee 	regmap_bulk_write(max98390->regmap, param_start_addr,
84897ed3e50SSteve Lee 		dsm_param, param_size);
849a6e3f4f3SSteve Lee 	regmap_write(max98390->regmap, MAX98390_R23E1_DSP_GLOBAL_EN, 0x01);
850a6e3f4f3SSteve Lee 
85197ed3e50SSteve Lee err_alloc:
85297ed3e50SSteve Lee 	release_firmware(fw);
853a6e3f4f3SSteve Lee err:
854a6e3f4f3SSteve Lee 	return ret;
855a6e3f4f3SSteve Lee }
856a6e3f4f3SSteve Lee 
max98390_init_regs(struct snd_soc_component * component)8579ba4af79SSteve Lee static void max98390_init_regs(struct snd_soc_component *component)
8589ba4af79SSteve Lee {
8599ba4af79SSteve Lee 	struct max98390_priv *max98390 =
8609ba4af79SSteve Lee 		snd_soc_component_get_drvdata(component);
8619ba4af79SSteve Lee 
8629ba4af79SSteve Lee 	regmap_write(max98390->regmap, MAX98390_CLK_MON, 0x6f);
8639ba4af79SSteve Lee 	regmap_write(max98390->regmap, MAX98390_DAT_MON, 0x00);
8649ba4af79SSteve Lee 	regmap_write(max98390->regmap, MAX98390_PWR_GATE_CTL, 0x00);
8659ba4af79SSteve Lee 	regmap_write(max98390->regmap, MAX98390_PCM_RX_EN_A, 0x03);
8669ba4af79SSteve Lee 	regmap_write(max98390->regmap, MAX98390_ENV_TRACK_VOUT_HEADROOM, 0x0e);
8679ba4af79SSteve Lee 	regmap_write(max98390->regmap, MAX98390_BOOST_BYPASS1, 0x46);
8689ba4af79SSteve Lee 	regmap_write(max98390->regmap, MAX98390_FET_SCALING3, 0x03);
869e5870bd0SSteve Lee 
870e5870bd0SSteve Lee 	/* voltage, current slot configuration */
871e5870bd0SSteve Lee 	regmap_write(max98390->regmap,
872e5870bd0SSteve Lee 		MAX98390_PCM_CH_SRC_2,
873e5870bd0SSteve Lee 		(max98390->i_l_slot << 4 |
874e5870bd0SSteve Lee 		max98390->v_l_slot)&0xFF);
875e5870bd0SSteve Lee 
876e5870bd0SSteve Lee 	if (max98390->v_l_slot < 8) {
877e5870bd0SSteve Lee 		regmap_update_bits(max98390->regmap,
878e5870bd0SSteve Lee 			MAX98390_PCM_TX_HIZ_CTRL_A,
879e5870bd0SSteve Lee 			1 << max98390->v_l_slot, 0);
880e5870bd0SSteve Lee 		regmap_update_bits(max98390->regmap,
881e5870bd0SSteve Lee 			MAX98390_PCM_TX_EN_A,
882e5870bd0SSteve Lee 			1 << max98390->v_l_slot,
883e5870bd0SSteve Lee 			1 << max98390->v_l_slot);
884e5870bd0SSteve Lee 	} else {
885e5870bd0SSteve Lee 		regmap_update_bits(max98390->regmap,
886e5870bd0SSteve Lee 			MAX98390_PCM_TX_HIZ_CTRL_B,
887e5870bd0SSteve Lee 			1 << (max98390->v_l_slot - 8), 0);
888e5870bd0SSteve Lee 		regmap_update_bits(max98390->regmap,
889e5870bd0SSteve Lee 			MAX98390_PCM_TX_EN_B,
890e5870bd0SSteve Lee 			1 << (max98390->v_l_slot - 8),
891e5870bd0SSteve Lee 			1 << (max98390->v_l_slot - 8));
892e5870bd0SSteve Lee 	}
893e5870bd0SSteve Lee 
894e5870bd0SSteve Lee 	if (max98390->i_l_slot < 8) {
895e5870bd0SSteve Lee 		regmap_update_bits(max98390->regmap,
896e5870bd0SSteve Lee 			MAX98390_PCM_TX_HIZ_CTRL_A,
897e5870bd0SSteve Lee 			1 << max98390->i_l_slot, 0);
898e5870bd0SSteve Lee 		regmap_update_bits(max98390->regmap,
899e5870bd0SSteve Lee 			MAX98390_PCM_TX_EN_A,
900e5870bd0SSteve Lee 			1 << max98390->i_l_slot,
901e5870bd0SSteve Lee 			1 << max98390->i_l_slot);
902e5870bd0SSteve Lee 	} else {
903e5870bd0SSteve Lee 		regmap_update_bits(max98390->regmap,
904e5870bd0SSteve Lee 			MAX98390_PCM_TX_HIZ_CTRL_B,
905e5870bd0SSteve Lee 			1 << (max98390->i_l_slot - 8), 0);
906e5870bd0SSteve Lee 		regmap_update_bits(max98390->regmap,
907e5870bd0SSteve Lee 			MAX98390_PCM_TX_EN_B,
908e5870bd0SSteve Lee 			1 << (max98390->i_l_slot - 8),
909e5870bd0SSteve Lee 			1 << (max98390->i_l_slot - 8));
910e5870bd0SSteve Lee 	}
9119ba4af79SSteve Lee }
9129ba4af79SSteve Lee 
max98390_probe(struct snd_soc_component * component)913a6e3f4f3SSteve Lee static int max98390_probe(struct snd_soc_component *component)
914a6e3f4f3SSteve Lee {
915a6e3f4f3SSteve Lee 	struct max98390_priv *max98390 =
916a6e3f4f3SSteve Lee 		snd_soc_component_get_drvdata(component);
917a6e3f4f3SSteve Lee 
918a6e3f4f3SSteve Lee 	regmap_write(max98390->regmap, MAX98390_SOFTWARE_RESET, 0x01);
919a6e3f4f3SSteve Lee 	/* Sleep reset settle time */
920a6e3f4f3SSteve Lee 	msleep(20);
921a6e3f4f3SSteve Lee 
9229ba4af79SSteve Lee 	/* Amp init setting */
9239ba4af79SSteve Lee 	max98390_init_regs(component);
924aa785705SSteve Lee 	/* Update dsm bin param */
925aa785705SSteve Lee 	max98390_dsm_init(component);
926a6e3f4f3SSteve Lee 
927a6e3f4f3SSteve Lee 	/* Dsm Setting */
928a6e3f4f3SSteve Lee 	if (max98390->ref_rdc_value) {
929a6e3f4f3SSteve Lee 		regmap_write(max98390->regmap, DSM_TPROT_RECIP_RDC_ROOM_BYTE0,
930a6e3f4f3SSteve Lee 			max98390->ref_rdc_value & 0x000000ff);
931a6e3f4f3SSteve Lee 		regmap_write(max98390->regmap, DSM_TPROT_RECIP_RDC_ROOM_BYTE1,
932a6e3f4f3SSteve Lee 			(max98390->ref_rdc_value >> 8) & 0x000000ff);
933a6e3f4f3SSteve Lee 		regmap_write(max98390->regmap, DSM_TPROT_RECIP_RDC_ROOM_BYTE2,
934a6e3f4f3SSteve Lee 			(max98390->ref_rdc_value >> 16) & 0x000000ff);
935a6e3f4f3SSteve Lee 	}
936a6e3f4f3SSteve Lee 	if (max98390->ambient_temp_value) {
937a6e3f4f3SSteve Lee 		regmap_write(max98390->regmap, DSM_TPROT_ROOM_TEMPERATURE_BYTE1,
938a6e3f4f3SSteve Lee 			(max98390->ambient_temp_value >> 8) & 0x000000ff);
939a6e3f4f3SSteve Lee 		regmap_write(max98390->regmap, DSM_TPROT_ROOM_TEMPERATURE_BYTE0,
940a6e3f4f3SSteve Lee 			(max98390->ambient_temp_value) & 0x000000ff);
941a6e3f4f3SSteve Lee 	}
942a6e3f4f3SSteve Lee 
943a6e3f4f3SSteve Lee 	return 0;
944a6e3f4f3SSteve Lee }
945a6e3f4f3SSteve Lee 
946a6e3f4f3SSteve Lee #ifdef CONFIG_PM_SLEEP
max98390_suspend(struct device * dev)947a6e3f4f3SSteve Lee static int max98390_suspend(struct device *dev)
948a6e3f4f3SSteve Lee {
949a6e3f4f3SSteve Lee 	struct max98390_priv *max98390 = dev_get_drvdata(dev);
950a6e3f4f3SSteve Lee 
951a6e3f4f3SSteve Lee 	dev_dbg(dev, "%s:Enter\n", __func__);
952a6e3f4f3SSteve Lee 
953a6e3f4f3SSteve Lee 	regcache_cache_only(max98390->regmap, true);
954a6e3f4f3SSteve Lee 	regcache_mark_dirty(max98390->regmap);
955a6e3f4f3SSteve Lee 
956a6e3f4f3SSteve Lee 	return 0;
957a6e3f4f3SSteve Lee }
958a6e3f4f3SSteve Lee 
max98390_resume(struct device * dev)959a6e3f4f3SSteve Lee static int max98390_resume(struct device *dev)
960a6e3f4f3SSteve Lee {
961a6e3f4f3SSteve Lee 	struct max98390_priv *max98390 = dev_get_drvdata(dev);
962a6e3f4f3SSteve Lee 
963a6e3f4f3SSteve Lee 	dev_dbg(dev, "%s:Enter\n", __func__);
964a6e3f4f3SSteve Lee 
965a6e3f4f3SSteve Lee 	regcache_cache_only(max98390->regmap, false);
966a6e3f4f3SSteve Lee 	regcache_sync(max98390->regmap);
967a6e3f4f3SSteve Lee 
968a6e3f4f3SSteve Lee 	return 0;
969a6e3f4f3SSteve Lee }
970a6e3f4f3SSteve Lee #endif
971a6e3f4f3SSteve Lee 
972a6e3f4f3SSteve Lee static const struct dev_pm_ops max98390_pm = {
973a6e3f4f3SSteve Lee 	SET_SYSTEM_SLEEP_PM_OPS(max98390_suspend, max98390_resume)
974a6e3f4f3SSteve Lee };
975a6e3f4f3SSteve Lee 
976a6e3f4f3SSteve Lee static const struct snd_soc_component_driver soc_codec_dev_max98390 = {
977a6e3f4f3SSteve Lee 	.probe			= max98390_probe,
978a6e3f4f3SSteve Lee 	.controls		= max98390_snd_controls,
979a6e3f4f3SSteve Lee 	.num_controls		= ARRAY_SIZE(max98390_snd_controls),
980a6e3f4f3SSteve Lee 	.dapm_widgets		= max98390_dapm_widgets,
981a6e3f4f3SSteve Lee 	.num_dapm_widgets	= ARRAY_SIZE(max98390_dapm_widgets),
982a6e3f4f3SSteve Lee 	.dapm_routes		= max98390_audio_map,
983a6e3f4f3SSteve Lee 	.num_dapm_routes	= ARRAY_SIZE(max98390_audio_map),
984a6e3f4f3SSteve Lee 	.idle_bias_on		= 1,
985a6e3f4f3SSteve Lee 	.use_pmdown_time	= 1,
986a6e3f4f3SSteve Lee 	.endianness		= 1,
987a6e3f4f3SSteve Lee };
988a6e3f4f3SSteve Lee 
989a6e3f4f3SSteve Lee static const struct regmap_config max98390_regmap = {
990a6e3f4f3SSteve Lee 	.reg_bits         = 16,
991a6e3f4f3SSteve Lee 	.val_bits         = 8,
992a6e3f4f3SSteve Lee 	.max_register     = MAX98390_R24FF_REV_ID,
993a6e3f4f3SSteve Lee 	.reg_defaults     = max98390_reg_defaults,
994a6e3f4f3SSteve Lee 	.num_reg_defaults = ARRAY_SIZE(max98390_reg_defaults),
995a6e3f4f3SSteve Lee 	.readable_reg	  = max98390_readable_register,
996a6e3f4f3SSteve Lee 	.volatile_reg	  = max98390_volatile_reg,
997a6e3f4f3SSteve Lee 	.cache_type       = REGCACHE_RBTREE,
998a6e3f4f3SSteve Lee };
999a6e3f4f3SSteve Lee 
max98390_slot_config(struct i2c_client * i2c,struct max98390_priv * max98390)1000e5870bd0SSteve Lee static void max98390_slot_config(struct i2c_client *i2c,
1001e5870bd0SSteve Lee 	struct max98390_priv *max98390)
1002e5870bd0SSteve Lee {
1003e5870bd0SSteve Lee 	int value;
1004e5870bd0SSteve Lee 	struct device *dev = &i2c->dev;
1005e5870bd0SSteve Lee 
1006e5870bd0SSteve Lee 	if (!device_property_read_u32(dev, "maxim,vmon-slot-no", &value))
1007e5870bd0SSteve Lee 		max98390->v_l_slot = value & 0xF;
1008e5870bd0SSteve Lee 	else
1009e5870bd0SSteve Lee 		max98390->v_l_slot = 0;
1010e5870bd0SSteve Lee 
1011e5870bd0SSteve Lee 	if (!device_property_read_u32(dev, "maxim,imon-slot-no", &value))
1012e5870bd0SSteve Lee 		max98390->i_l_slot = value & 0xF;
1013e5870bd0SSteve Lee 	else
1014e5870bd0SSteve Lee 		max98390->i_l_slot = 1;
1015e5870bd0SSteve Lee }
1016e5870bd0SSteve Lee 
max98390_i2c_probe(struct i2c_client * i2c)1017fead49e3SStephen Kitt static int max98390_i2c_probe(struct i2c_client *i2c)
1018a6e3f4f3SSteve Lee {
1019a6e3f4f3SSteve Lee 	int ret = 0;
1020a6e3f4f3SSteve Lee 	int reg = 0;
1021a6e3f4f3SSteve Lee 
1022a6e3f4f3SSteve Lee 	struct max98390_priv *max98390 = NULL;
10230f9a84b2SWolfram Sang 	struct i2c_adapter *adapter = i2c->adapter;
1024397ff024SSteve Lee 	struct gpio_desc *reset_gpio;
1025a6e3f4f3SSteve Lee 
1026a6e3f4f3SSteve Lee 	ret = i2c_check_functionality(adapter,
1027a6e3f4f3SSteve Lee 		I2C_FUNC_SMBUS_BYTE
1028a6e3f4f3SSteve Lee 		| I2C_FUNC_SMBUS_BYTE_DATA);
1029a6e3f4f3SSteve Lee 	if (!ret) {
1030a6e3f4f3SSteve Lee 		dev_err(&i2c->dev, "I2C check functionality failed\n");
1031a6e3f4f3SSteve Lee 		return -ENXIO;
1032a6e3f4f3SSteve Lee 	}
1033a6e3f4f3SSteve Lee 
1034a6e3f4f3SSteve Lee 	max98390 = devm_kzalloc(&i2c->dev, sizeof(*max98390), GFP_KERNEL);
1035a6e3f4f3SSteve Lee 	if (!max98390) {
1036a6e3f4f3SSteve Lee 		ret = -ENOMEM;
1037a6e3f4f3SSteve Lee 		return ret;
1038a6e3f4f3SSteve Lee 	}
1039a6e3f4f3SSteve Lee 	i2c_set_clientdata(i2c, max98390);
1040a6e3f4f3SSteve Lee 
1041a6e3f4f3SSteve Lee 	ret = device_property_read_u32(&i2c->dev, "maxim,temperature_calib",
1042a6e3f4f3SSteve Lee 				       &max98390->ambient_temp_value);
1043a6e3f4f3SSteve Lee 	if (ret) {
1044a6e3f4f3SSteve Lee 		dev_info(&i2c->dev,
1045a6e3f4f3SSteve Lee 			 "no optional property 'temperature_calib' found, default:\n");
1046a6e3f4f3SSteve Lee 	}
1047a6e3f4f3SSteve Lee 	ret = device_property_read_u32(&i2c->dev, "maxim,r0_calib",
1048a6e3f4f3SSteve Lee 				       &max98390->ref_rdc_value);
1049a6e3f4f3SSteve Lee 	if (ret) {
1050a6e3f4f3SSteve Lee 		dev_info(&i2c->dev,
1051a6e3f4f3SSteve Lee 			 "no optional property 'r0_calib' found, default:\n");
1052a6e3f4f3SSteve Lee 	}
1053a6e3f4f3SSteve Lee 
1054a6e3f4f3SSteve Lee 	dev_info(&i2c->dev,
1055a6e3f4f3SSteve Lee 		"%s: r0_calib: 0x%x,temperature_calib: 0x%x",
1056a6e3f4f3SSteve Lee 		__func__, max98390->ref_rdc_value,
1057a6e3f4f3SSteve Lee 		max98390->ambient_temp_value);
1058a6e3f4f3SSteve Lee 
1059a10facb7SSteve Lee 	ret = device_property_read_string(&i2c->dev, "maxim,dsm_param_name",
1060a10facb7SSteve Lee 				       &max98390->dsm_param_name);
1061a10facb7SSteve Lee 	if (ret)
1062a10facb7SSteve Lee 		max98390->dsm_param_name = "default";
1063a10facb7SSteve Lee 
1064e5870bd0SSteve Lee 	/* voltage/current slot configuration */
1065e5870bd0SSteve Lee 	max98390_slot_config(i2c, max98390);
1066e5870bd0SSteve Lee 
1067a6e3f4f3SSteve Lee 	/* regmap initialization */
1068a6e3f4f3SSteve Lee 	max98390->regmap = devm_regmap_init_i2c(i2c, &max98390_regmap);
1069a6e3f4f3SSteve Lee 	if (IS_ERR(max98390->regmap)) {
1070a6e3f4f3SSteve Lee 		ret = PTR_ERR(max98390->regmap);
1071a6e3f4f3SSteve Lee 		dev_err(&i2c->dev,
1072a6e3f4f3SSteve Lee 			"Failed to allocate regmap: %d\n", ret);
1073a6e3f4f3SSteve Lee 		return ret;
1074a6e3f4f3SSteve Lee 	}
1075a6e3f4f3SSteve Lee 
1076397ff024SSteve Lee 	reset_gpio = devm_gpiod_get_optional(&i2c->dev,
1077397ff024SSteve Lee 					     "reset", GPIOD_OUT_HIGH);
1078397ff024SSteve Lee 
1079397ff024SSteve Lee 	/* Power on device */
1080397ff024SSteve Lee 	if (reset_gpio) {
1081397ff024SSteve Lee 		usleep_range(1000, 2000);
1082397ff024SSteve Lee 		/* bring out of reset */
1083397ff024SSteve Lee 		gpiod_set_value_cansleep(reset_gpio, 0);
1084397ff024SSteve Lee 		usleep_range(1000, 2000);
1085397ff024SSteve Lee 	}
1086397ff024SSteve Lee 
1087a6e3f4f3SSteve Lee 	/* Check Revision ID */
1088a6e3f4f3SSteve Lee 	ret = regmap_read(max98390->regmap,
1089a6e3f4f3SSteve Lee 		MAX98390_R24FF_REV_ID, &reg);
1090a6e3f4f3SSteve Lee 	if (ret) {
1091a6e3f4f3SSteve Lee 		dev_err(&i2c->dev,
1092a6e3f4f3SSteve Lee 			"ret=%d, Failed to read: 0x%02X\n",
1093a6e3f4f3SSteve Lee 			ret, MAX98390_R24FF_REV_ID);
1094a6e3f4f3SSteve Lee 		return ret;
1095a6e3f4f3SSteve Lee 	}
1096a6e3f4f3SSteve Lee 	dev_info(&i2c->dev, "MAX98390 revisionID: 0x%02X\n", reg);
1097a6e3f4f3SSteve Lee 
1098a6e3f4f3SSteve Lee 	ret = devm_snd_soc_register_component(&i2c->dev,
1099a6e3f4f3SSteve Lee 			&soc_codec_dev_max98390,
1100a6e3f4f3SSteve Lee 			max98390_dai, ARRAY_SIZE(max98390_dai));
1101a6e3f4f3SSteve Lee 
1102a6e3f4f3SSteve Lee 	return ret;
1103a6e3f4f3SSteve Lee }
1104a6e3f4f3SSteve Lee 
1105a6e3f4f3SSteve Lee static const struct i2c_device_id max98390_i2c_id[] = {
1106*ba2a2c37SUwe Kleine-König 	{ "max98390"},
1107a6e3f4f3SSteve Lee 	{},
1108a6e3f4f3SSteve Lee };
1109a6e3f4f3SSteve Lee 
1110a6e3f4f3SSteve Lee MODULE_DEVICE_TABLE(i2c, max98390_i2c_id);
1111a6e3f4f3SSteve Lee 
1112a6e3f4f3SSteve Lee #if defined(CONFIG_OF)
1113a6e3f4f3SSteve Lee static const struct of_device_id max98390_of_match[] = {
1114a6e3f4f3SSteve Lee 	{ .compatible = "maxim,max98390", },
1115a6e3f4f3SSteve Lee 	{}
1116a6e3f4f3SSteve Lee };
1117a6e3f4f3SSteve Lee MODULE_DEVICE_TABLE(of, max98390_of_match);
1118a6e3f4f3SSteve Lee #endif
1119a6e3f4f3SSteve Lee 
1120a6e3f4f3SSteve Lee #ifdef CONFIG_ACPI
1121a6e3f4f3SSteve Lee static const struct acpi_device_id max98390_acpi_match[] = {
1122a6e3f4f3SSteve Lee 	{ "MX98390", 0 },
1123a6e3f4f3SSteve Lee 	{},
1124a6e3f4f3SSteve Lee };
1125a6e3f4f3SSteve Lee MODULE_DEVICE_TABLE(acpi, max98390_acpi_match);
1126a6e3f4f3SSteve Lee #endif
1127a6e3f4f3SSteve Lee 
1128a6e3f4f3SSteve Lee static struct i2c_driver max98390_i2c_driver = {
1129a6e3f4f3SSteve Lee 	.driver = {
1130a6e3f4f3SSteve Lee 		.name = "max98390",
1131a6e3f4f3SSteve Lee 		.of_match_table = of_match_ptr(max98390_of_match),
1132a6e3f4f3SSteve Lee 		.acpi_match_table = ACPI_PTR(max98390_acpi_match),
1133a6e3f4f3SSteve Lee 		.pm = &max98390_pm,
1134a6e3f4f3SSteve Lee 	},
11359abcd240SUwe Kleine-König 	.probe = max98390_i2c_probe,
1136a6e3f4f3SSteve Lee 	.id_table = max98390_i2c_id,
1137a6e3f4f3SSteve Lee };
1138a6e3f4f3SSteve Lee 
1139a6e3f4f3SSteve Lee module_i2c_driver(max98390_i2c_driver)
1140a6e3f4f3SSteve Lee 
1141a6e3f4f3SSteve Lee MODULE_DESCRIPTION("ALSA SoC MAX98390 driver");
1142a6e3f4f3SSteve Lee MODULE_AUTHOR("Steve Lee <steves.lee@maximintegrated.com>");
1143a6e3f4f3SSteve Lee MODULE_LICENSE("GPL");
1144