~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/sound/soc/codecs/max98520.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0
  2 // Copyright (c) 2021, Maxim Integrated
  3 
  4 #include <linux/acpi.h>
  5 #include <linux/delay.h>
  6 #include <linux/i2c.h>
  7 #include <linux/module.h>
  8 #include <linux/regmap.h>
  9 #include <linux/slab.h>
 10 #include <linux/cdev.h>
 11 #include <sound/pcm.h>
 12 #include <sound/pcm_params.h>
 13 #include <sound/soc.h>
 14 #include <linux/gpio/consumer.h>
 15 #include <linux/of.h>
 16 #include <sound/tlv.h>
 17 #include "max98520.h"
 18 
 19 static struct reg_default max98520_reg[] = {
 20         {MAX98520_R2000_SW_RESET, 0x00},
 21         {MAX98520_R2001_STATUS_1, 0x00},
 22         {MAX98520_R2002_STATUS_2, 0x00},
 23         {MAX98520_R2020_THERM_WARN_THRESH, 0x46},
 24         {MAX98520_R2021_THERM_SHDN_THRESH, 0x64},
 25         {MAX98520_R2022_THERM_HYSTERESIS, 0x02},
 26         {MAX98520_R2023_THERM_FOLDBACK_SET, 0x31},
 27         {MAX98520_R2027_THERM_FOLDBACK_EN, 0x01},
 28         {MAX98520_R2030_CLK_MON_CTRL, 0x00},
 29         {MAX98520_R2037_ERR_MON_CTRL, 0x01},
 30         {MAX98520_R2040_PCM_MODE_CFG, 0xC0},
 31         {MAX98520_R2041_PCM_CLK_SETUP, 0x04},
 32         {MAX98520_R2042_PCM_SR_SETUP, 0x08},
 33         {MAX98520_R2043_PCM_RX_SRC1, 0x00},
 34         {MAX98520_R2044_PCM_RX_SRC2, 0x00},
 35         {MAX98520_R204F_PCM_RX_EN, 0x00},
 36         {MAX98520_R2090_AMP_VOL_CTRL, 0x00},
 37         {MAX98520_R2091_AMP_PATH_GAIN, 0x03},
 38         {MAX98520_R2092_AMP_DSP_CFG, 0x02},
 39         {MAX98520_R2094_SSM_CFG, 0x01},
 40         {MAX98520_R2095_AMP_CFG, 0xF0},
 41         {MAX98520_R209F_AMP_EN, 0x00},
 42         {MAX98520_R20B0_ADC_SR, 0x00},
 43         {MAX98520_R20B1_ADC_RESOLUTION, 0x00},
 44         {MAX98520_R20B2_ADC_PVDD0_CFG, 0x02},
 45         {MAX98520_R20B3_ADC_THERMAL_CFG, 0x02},
 46         {MAX98520_R20B4_ADC_READBACK_CTRL, 0x00},
 47         {MAX98520_R20B5_ADC_READBACK_UPDATE, 0x00},
 48         {MAX98520_R20B6_ADC_PVDD_READBACK_MSB, 0x00},
 49         {MAX98520_R20B7_ADC_PVDD_READBACK_LSB, 0x00},
 50         {MAX98520_R20B8_ADC_TEMP_READBACK_MSB, 0x00},
 51         {MAX98520_R20B9_ADC_TEMP_READBACK_LSB, 0x00},
 52         {MAX98520_R20BA_ADC_LOW_PVDD_READBACK_MSB, 0xFF},
 53         {MAX98520_R20BB_ADC_LOW_READBACK_LSB, 0x01},
 54         {MAX98520_R20BC_ADC_HIGH_TEMP_READBACK_MSB, 0x00},
 55         {MAX98520_R20BD_ADC_HIGH_TEMP_READBACK_LSB, 0x00},
 56         {MAX98520_R20CF_MEAS_ADC_CFG, 0x00},
 57         {MAX98520_R20D0_DHT_CFG1, 0x00},
 58         {MAX98520_R20D1_LIMITER_CFG1, 0x08},
 59         {MAX98520_R20D2_LIMITER_CFG2, 0x00},
 60         {MAX98520_R20D3_DHT_CFG2, 0x14},
 61         {MAX98520_R20D4_DHT_CFG3, 0x02},
 62         {MAX98520_R20D5_DHT_CFG4, 0x04},
 63         {MAX98520_R20D6_DHT_HYSTERESIS_CFG, 0x07},
 64         {MAX98520_R20D8_DHT_EN, 0x00},
 65         {MAX98520_R210E_AUTO_RESTART_BEHAVIOR, 0x00},
 66         {MAX98520_R210F_GLOBAL_EN, 0x00},
 67         {MAX98520_R21FF_REVISION_ID, 0x00},
 68 };
 69 
 70 static int max98520_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
 71 {
 72         struct snd_soc_component *component = codec_dai->component;
 73         struct max98520_priv *max98520 =
 74                 snd_soc_component_get_drvdata(component);
 75         unsigned int format = 0;
 76         unsigned int invert = 0;
 77 
 78         dev_dbg(component->dev, "%s: fmt 0x%08X\n", __func__, fmt);
 79 
 80         switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
 81         case SND_SOC_DAIFMT_NB_NF:
 82                 break;
 83         case SND_SOC_DAIFMT_IB_NF:
 84                 invert = MAX98520_PCM_MODE_CFG_PCM_BCLKEDGE;
 85                 break;
 86         default:
 87                 dev_err(component->dev, "DAI invert mode unsupported\n");
 88                 return -EINVAL;
 89         }
 90 
 91         regmap_update_bits(max98520->regmap,
 92                            MAX98520_R2041_PCM_CLK_SETUP,
 93                            MAX98520_PCM_MODE_CFG_PCM_BCLKEDGE,
 94                            invert);
 95 
 96         /* interface format */
 97         switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
 98         case SND_SOC_DAIFMT_I2S:
 99                 format = MAX98520_PCM_FORMAT_I2S;
100                 break;
101         case SND_SOC_DAIFMT_LEFT_J:
102                 format = MAX98520_PCM_FORMAT_LJ;
103                 break;
104         case SND_SOC_DAIFMT_DSP_A:
105                 format = MAX98520_PCM_FORMAT_TDM_MODE1;
106                 break;
107         case SND_SOC_DAIFMT_DSP_B:
108                 format = MAX98520_PCM_FORMAT_TDM_MODE0;
109                 break;
110         default:
111                 return -EINVAL;
112         }
113 
114         regmap_update_bits(max98520->regmap,
115                            MAX98520_R2040_PCM_MODE_CFG,
116                            MAX98520_PCM_MODE_CFG_FORMAT_MASK,
117                            format << MAX98520_PCM_MODE_CFG_FORMAT_SHIFT);
118 
119         return 0;
120 }
121 
122 /* BCLKs per LRCLK */
123 static const int bclk_sel_table[] = {
124         32, 48, 64, 96, 128, 192, 256, 384, 512, 320,
125 };
126 
127 static int max98520_get_bclk_sel(int bclk)
128 {
129         int i;
130         /* match BCLKs per LRCLK */
131         for (i = 0; i < ARRAY_SIZE(bclk_sel_table); i++) {
132                 if (bclk_sel_table[i] == bclk)
133                         return i + 2;
134         }
135         return 0;
136 }
137 
138 static int max98520_set_clock(struct snd_soc_component *component,
139                               struct snd_pcm_hw_params *params)
140 {
141         struct max98520_priv *max98520 =
142                 snd_soc_component_get_drvdata(component);
143         /* BCLK/LRCLK ratio calculation */
144         int blr_clk_ratio = params_channels(params) * max98520->ch_size;
145         int value;
146 
147         if (!max98520->tdm_mode) {
148                 /* BCLK configuration */
149                 value = max98520_get_bclk_sel(blr_clk_ratio);
150                 if (!value) {
151                         dev_err(component->dev, "format unsupported %d\n",
152                                 params_format(params));
153                         return -EINVAL;
154                 }
155 
156                 regmap_update_bits(max98520->regmap,
157                                    MAX98520_R2041_PCM_CLK_SETUP,
158                                    MAX98520_PCM_CLK_SETUP_BSEL_MASK,
159                                    value);
160         }
161         dev_dbg(component->dev, "%s tdm_mode:%d out\n", __func__, max98520->tdm_mode);
162         return 0;
163 }
164 
165 static int max98520_dai_hw_params(struct snd_pcm_substream *substream,
166                                   struct snd_pcm_hw_params *params,
167                                   struct snd_soc_dai *dai)
168 {
169         struct snd_soc_component *component = dai->component;
170         struct max98520_priv *max98520 =
171                 snd_soc_component_get_drvdata(component);
172         unsigned int sampling_rate = 0;
173         unsigned int chan_sz = 0;
174 
175         /* pcm mode configuration */
176         switch (snd_pcm_format_width(params_format(params))) {
177         case 16:
178                 chan_sz = MAX98520_PCM_MODE_CFG_CHANSZ_16;
179                 break;
180         case 24:
181                 chan_sz = MAX98520_PCM_MODE_CFG_CHANSZ_24;
182                 break;
183         case 32:
184                 chan_sz = MAX98520_PCM_MODE_CFG_CHANSZ_32;
185                 break;
186         default:
187                 dev_err(component->dev, "format unsupported %d\n",
188                         params_format(params));
189                 goto err;
190         }
191 
192         max98520->ch_size = snd_pcm_format_width(params_format(params));
193 
194         regmap_update_bits(max98520->regmap,
195                            MAX98520_R2040_PCM_MODE_CFG,
196                            MAX98520_PCM_MODE_CFG_CHANSZ_MASK, chan_sz);
197 
198         dev_dbg(component->dev, "format supported %d",
199                 params_format(params));
200 
201         /* sampling rate configuration */
202         switch (params_rate(params)) {
203         case 8000:
204                 sampling_rate = MAX98520_PCM_SR_8000;
205                 break;
206         case 11025:
207                 sampling_rate = MAX98520_PCM_SR_11025;
208                 break;
209         case 12000:
210                 sampling_rate = MAX98520_PCM_SR_12000;
211                 break;
212         case 16000:
213                 sampling_rate = MAX98520_PCM_SR_16000;
214                 break;
215         case 22050:
216                 sampling_rate = MAX98520_PCM_SR_22050;
217                 break;
218         case 24000:
219                 sampling_rate = MAX98520_PCM_SR_24000;
220                 break;
221         case 32000:
222                 sampling_rate = MAX98520_PCM_SR_32000;
223                 break;
224         case 44100:
225                 sampling_rate = MAX98520_PCM_SR_44100;
226                 break;
227         case 48000:
228                 sampling_rate = MAX98520_PCM_SR_48000;
229                 break;
230         case 88200:
231                 sampling_rate = MAX98520_PCM_SR_88200;
232                 break;
233         case 96000:
234                 sampling_rate = MAX98520_PCM_SR_96000;
235                 break;
236         case 176400:
237                 sampling_rate = MAX98520_PCM_SR_176400;
238                 break;
239         case 192000:
240                 sampling_rate = MAX98520_PCM_SR_192000;
241                 break;
242         default:
243                 dev_err(component->dev, "rate %d not supported\n",
244                         params_rate(params));
245                 goto err;
246         }
247 
248         dev_dbg(component->dev, " %s ch_size: %d, sampling rate : %d out\n", __func__,
249                 snd_pcm_format_width(params_format(params)), params_rate(params));
250         /* set DAI_SR to correct LRCLK frequency */
251         regmap_update_bits(max98520->regmap,
252                            MAX98520_R2042_PCM_SR_SETUP,
253                            MAX98520_PCM_SR_MASK,
254                            sampling_rate);
255 
256         return max98520_set_clock(component, params);
257 err:
258         dev_dbg(component->dev, "%s out error", __func__);
259         return -EINVAL;
260 }
261 
262 static int max98520_dai_tdm_slot(struct snd_soc_dai *dai,
263                                  unsigned int tx_mask, unsigned int rx_mask,
264                                  int slots, int slot_width)
265 {
266         struct snd_soc_component *component = dai->component;
267         struct max98520_priv *max98520 =
268                 snd_soc_component_get_drvdata(component);
269         int bsel;
270         unsigned int chan_sz = 0;
271 
272         if (!tx_mask && !rx_mask && !slots && !slot_width)
273                 max98520->tdm_mode = false;
274         else
275                 max98520->tdm_mode = true;
276 
277         /* BCLK configuration */
278         bsel = max98520_get_bclk_sel(slots * slot_width);
279         if (bsel == 0) {
280                 dev_err(component->dev, "BCLK %d not supported\n",
281                         slots * slot_width);
282                 return -EINVAL;
283         }
284 
285         regmap_update_bits(max98520->regmap,
286                            MAX98520_R2041_PCM_CLK_SETUP,
287                            MAX98520_PCM_CLK_SETUP_BSEL_MASK,
288                            bsel);
289 
290         /* Channel size configuration */
291         switch (slot_width) {
292         case 16:
293                 chan_sz = MAX98520_PCM_MODE_CFG_CHANSZ_16;
294                 break;
295         case 24:
296                 chan_sz = MAX98520_PCM_MODE_CFG_CHANSZ_24;
297                 break;
298         case 32:
299                 chan_sz = MAX98520_PCM_MODE_CFG_CHANSZ_32;
300                 break;
301         default:
302                 dev_err(component->dev, "format unsupported %d\n",
303                         slot_width);
304                 return -EINVAL;
305         }
306 
307         regmap_update_bits(max98520->regmap,
308                            MAX98520_R2040_PCM_MODE_CFG,
309                            MAX98520_PCM_MODE_CFG_CHANSZ_MASK, chan_sz);
310 
311         /* Rx slot configuration */
312         regmap_update_bits(max98520->regmap,
313                            MAX98520_R2044_PCM_RX_SRC2,
314                            MAX98520_PCM_DMIX_CH0_SRC_MASK,
315                            rx_mask);
316         regmap_update_bits(max98520->regmap,
317                            MAX98520_R2044_PCM_RX_SRC2,
318                            MAX98520_PCM_DMIX_CH1_SRC_MASK,
319                            rx_mask << MAX98520_PCM_DMIX_CH1_SHIFT);
320 
321         return 0;
322 }
323 
324 #define MAX98520_RATES SNDRV_PCM_RATE_8000_192000
325 
326 #define MAX98520_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
327         SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
328 
329 static const struct snd_soc_dai_ops max98520_dai_ops = {
330         .set_fmt = max98520_dai_set_fmt,
331         .hw_params = max98520_dai_hw_params,
332         .set_tdm_slot = max98520_dai_tdm_slot,
333 };
334 
335 static int max98520_dac_event(struct snd_soc_dapm_widget *w,
336                               struct snd_kcontrol *kcontrol, int event)
337 {
338         struct snd_soc_component *component =
339                 snd_soc_dapm_to_component(w->dapm);
340         struct max98520_priv *max98520 =
341                 snd_soc_component_get_drvdata(component);
342 
343         switch (event) {
344         case SND_SOC_DAPM_POST_PMU:
345                 dev_dbg(component->dev, " AMP ON\n");
346 
347                 regmap_write(max98520->regmap, MAX98520_R209F_AMP_EN, 1);
348                 regmap_write(max98520->regmap, MAX98520_R210F_GLOBAL_EN, 1);
349                 usleep_range(30000, 31000);
350                 break;
351         case SND_SOC_DAPM_POST_PMD:
352                 dev_dbg(component->dev, " AMP OFF\n");
353 
354                 regmap_write(max98520->regmap, MAX98520_R210F_GLOBAL_EN, 0);
355                 regmap_write(max98520->regmap, MAX98520_R209F_AMP_EN, 0);
356                 usleep_range(30000, 31000);
357                 break;
358         default:
359                 return 0;
360         }
361         return 0;
362 }
363 
364 static const char * const max98520_switch_text[] = {
365         "Left", "Right", "LeftRight"};
366 
367 static const struct soc_enum dai_sel_enum =
368         SOC_ENUM_SINGLE(MAX98520_R2043_PCM_RX_SRC1,
369                         0, 3, max98520_switch_text);
370 
371 static const struct snd_kcontrol_new max98520_dai_controls =
372         SOC_DAPM_ENUM("DAI Sel", dai_sel_enum);
373 
374 static const struct snd_kcontrol_new max98520_left_input_mixer_controls[] = {
375         SOC_DAPM_SINGLE("PCM_INPUT_CH0", MAX98520_R2044_PCM_RX_SRC2, 0, 0x0, 0),
376         SOC_DAPM_SINGLE("PCM_INPUT_CH1", MAX98520_R2044_PCM_RX_SRC2, 0, 0x1, 0),
377         SOC_DAPM_SINGLE("PCM_INPUT_CH2", MAX98520_R2044_PCM_RX_SRC2, 0, 0x2, 0),
378         SOC_DAPM_SINGLE("PCM_INPUT_CH3", MAX98520_R2044_PCM_RX_SRC2, 0, 0x3, 0),
379         SOC_DAPM_SINGLE("PCM_INPUT_CH4", MAX98520_R2044_PCM_RX_SRC2, 0, 0x4, 0),
380         SOC_DAPM_SINGLE("PCM_INPUT_CH5", MAX98520_R2044_PCM_RX_SRC2, 0, 0x5, 0),
381         SOC_DAPM_SINGLE("PCM_INPUT_CH6", MAX98520_R2044_PCM_RX_SRC2, 0, 0x6, 0),
382         SOC_DAPM_SINGLE("PCM_INPUT_CH7", MAX98520_R2044_PCM_RX_SRC2, 0, 0x7, 0),
383         SOC_DAPM_SINGLE("PCM_INPUT_CH8", MAX98520_R2044_PCM_RX_SRC2, 0, 0x8, 0),
384         SOC_DAPM_SINGLE("PCM_INPUT_CH9", MAX98520_R2044_PCM_RX_SRC2, 0, 0x9, 0),
385         SOC_DAPM_SINGLE("PCM_INPUT_CH10", MAX98520_R2044_PCM_RX_SRC2, 0, 0xa, 0),
386         SOC_DAPM_SINGLE("PCM_INPUT_CH11", MAX98520_R2044_PCM_RX_SRC2, 0, 0xb, 0),
387         SOC_DAPM_SINGLE("PCM_INPUT_CH12", MAX98520_R2044_PCM_RX_SRC2, 0, 0xc, 0),
388         SOC_DAPM_SINGLE("PCM_INPUT_CH13", MAX98520_R2044_PCM_RX_SRC2, 0, 0xd, 0),
389         SOC_DAPM_SINGLE("PCM_INPUT_CH14", MAX98520_R2044_PCM_RX_SRC2, 0, 0xe, 0),
390         SOC_DAPM_SINGLE("PCM_INPUT_CH15", MAX98520_R2044_PCM_RX_SRC2, 0, 0xf, 0),
391 };
392 
393 static const struct snd_kcontrol_new max98520_right_input_mixer_controls[] = {
394         SOC_DAPM_SINGLE("PCM_INPUT_CH0", MAX98520_R2044_PCM_RX_SRC2, 4, 0x0, 0),
395         SOC_DAPM_SINGLE("PCM_INPUT_CH1", MAX98520_R2044_PCM_RX_SRC2, 4, 0x1, 0),
396         SOC_DAPM_SINGLE("PCM_INPUT_CH2", MAX98520_R2044_PCM_RX_SRC2, 4, 0x2, 0),
397         SOC_DAPM_SINGLE("PCM_INPUT_CH3", MAX98520_R2044_PCM_RX_SRC2, 4, 0x3, 0),
398         SOC_DAPM_SINGLE("PCM_INPUT_CH4", MAX98520_R2044_PCM_RX_SRC2, 4, 0x4, 0),
399         SOC_DAPM_SINGLE("PCM_INPUT_CH5", MAX98520_R2044_PCM_RX_SRC2, 4, 0x5, 0),
400         SOC_DAPM_SINGLE("PCM_INPUT_CH6", MAX98520_R2044_PCM_RX_SRC2, 4, 0x6, 0),
401         SOC_DAPM_SINGLE("PCM_INPUT_CH7", MAX98520_R2044_PCM_RX_SRC2, 4, 0x7, 0),
402         SOC_DAPM_SINGLE("PCM_INPUT_CH8", MAX98520_R2044_PCM_RX_SRC2, 4, 0x8, 0),
403         SOC_DAPM_SINGLE("PCM_INPUT_CH9", MAX98520_R2044_PCM_RX_SRC2, 4, 0x9, 0),
404         SOC_DAPM_SINGLE("PCM_INPUT_CH10", MAX98520_R2044_PCM_RX_SRC2, 4, 0xa, 0),
405         SOC_DAPM_SINGLE("PCM_INPUT_CH11", MAX98520_R2044_PCM_RX_SRC2, 4, 0xb, 0),
406         SOC_DAPM_SINGLE("PCM_INPUT_CH12", MAX98520_R2044_PCM_RX_SRC2, 4, 0xc, 0),
407         SOC_DAPM_SINGLE("PCM_INPUT_CH13", MAX98520_R2044_PCM_RX_SRC2, 4, 0xd, 0),
408         SOC_DAPM_SINGLE("PCM_INPUT_CH14", MAX98520_R2044_PCM_RX_SRC2, 4, 0xe, 0),
409         SOC_DAPM_SINGLE("PCM_INPUT_CH15", MAX98520_R2044_PCM_RX_SRC2, 4, 0xf, 0),
410 };
411 
412 static const struct snd_soc_dapm_widget max98520_dapm_widgets[] = {
413         SND_SOC_DAPM_DAC_E("Amp Enable", "HiFi Playback",
414                            SND_SOC_NOPM, 0, 0, max98520_dac_event,
415         SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
416         SND_SOC_DAPM_MUX("DAI Sel Mux", SND_SOC_NOPM, 0, 0,     &max98520_dai_controls),
417         SND_SOC_DAPM_OUTPUT("BE_OUT"),
418         /* Left Input Selection */
419         SND_SOC_DAPM_MIXER("Left Input Selection", SND_SOC_NOPM, 0, 0,
420                            &max98520_left_input_mixer_controls[0],
421                            ARRAY_SIZE(max98520_left_input_mixer_controls)),
422         /* Right Input Selection */
423         SND_SOC_DAPM_MIXER("Right Input Selection", SND_SOC_NOPM, 0, 0,
424                            &max98520_right_input_mixer_controls[0],
425                            ARRAY_SIZE(max98520_right_input_mixer_controls)),
426 };
427 
428 static const DECLARE_TLV_DB_SCALE(max98520_digital_tlv, -6300, 50, 1);
429 static const DECLARE_TLV_DB_SCALE(max98520_spk_tlv, -600, 300, 0);
430 
431 static const DECLARE_TLV_DB_RANGE(max98520_dht_lim_thresh_tlv,
432         0, 15, TLV_DB_SCALE_ITEM(-1500, 100, 0),
433 );
434 
435 static const DECLARE_TLV_DB_RANGE(max98520_dht_hysteresis_tlv,
436         0, 3, TLV_DB_SCALE_ITEM(100, 100, 0),
437         4, 7, TLV_DB_SCALE_ITEM(600, 200, 0),
438 );
439 
440 static const DECLARE_TLV_DB_RANGE(max98520_dht_rotation_point_tlv,
441         0, 1, TLV_DB_SCALE_ITEM(-1500, 300, 0),
442         2, 4, TLV_DB_SCALE_ITEM(-1000, 200, 0),
443         5, 10, TLV_DB_SCALE_ITEM(-500, 100, 0),
444 );
445 
446 static const DECLARE_TLV_DB_RANGE(max98520_dht_supply_hr_tlv,
447         0, 16, TLV_DB_SCALE_ITEM(-2000, 250, 0),
448 );
449 
450 static const DECLARE_TLV_DB_RANGE(max98520_dht_max_atten_tlv,
451         1, 20, TLV_DB_SCALE_ITEM(-2000, 100, 0),
452 );
453 
454 static const char * const max98520_dht_attack_rate_text[] = {
455         "20us", "40us", "80us", "160us", "320us", "640us",
456         "1.28ms", "2.56ms",     "5.12ms", "10.24ms", "20.48ms", "40.96ms",
457         "81.92ms", "163.84ms"
458 };
459 
460 static SOC_ENUM_SINGLE_DECL(max98520_dht_attack_rate_enum,
461                             MAX98520_R20D4_DHT_CFG3, 0,
462                             max98520_dht_attack_rate_text);
463 
464 static const char * const max98520_dht_release_rate_text[] = {
465         "2ms", "4ms", "8ms", "16ms", "32ms", "64ms", "128ms", "256ms", "512ms",
466         "1.024s", "2.048s", "4.096s", "8.192s", "16.384s"
467 };
468 
469 static SOC_ENUM_SINGLE_DECL(max98520_dht_release_rate_enum,
470                             MAX98520_R20D5_DHT_CFG4, 0,
471                             max98520_dht_release_rate_text);
472 
473 static bool max98520_readable_register(struct device *dev, unsigned int reg)
474 {
475         switch (reg) {
476         case MAX98520_R2000_SW_RESET:
477         case MAX98520_R2027_THERM_FOLDBACK_EN:
478         case MAX98520_R2030_CLK_MON_CTRL:
479         case MAX98520_R2037_ERR_MON_CTRL:
480         case MAX98520_R204F_PCM_RX_EN:
481         case MAX98520_R209F_AMP_EN:
482         case MAX98520_R20CF_MEAS_ADC_CFG:
483         case MAX98520_R20D8_DHT_EN:
484         case MAX98520_R21FF_REVISION_ID:
485         case MAX98520_R2001_STATUS_1... MAX98520_R2002_STATUS_2:
486         case MAX98520_R2020_THERM_WARN_THRESH... MAX98520_R2023_THERM_FOLDBACK_SET:
487         case MAX98520_R2040_PCM_MODE_CFG... MAX98520_R2044_PCM_RX_SRC2:
488         case MAX98520_R2090_AMP_VOL_CTRL... MAX98520_R2092_AMP_DSP_CFG:
489         case MAX98520_R2094_SSM_CFG... MAX98520_R2095_AMP_CFG:
490         case MAX98520_R20B0_ADC_SR... MAX98520_R20BD_ADC_HIGH_TEMP_READBACK_LSB:
491         case MAX98520_R20D0_DHT_CFG1... MAX98520_R20D6_DHT_HYSTERESIS_CFG:
492         case MAX98520_R210E_AUTO_RESTART_BEHAVIOR... MAX98520_R210F_GLOBAL_EN:
493         case MAX98520_R2161_BOOST_TM1... MAX98520_R2163_BOOST_TM3:
494                 return true;
495         default:
496                 return false;
497         }
498 };
499 
500 static bool max98520_volatile_reg(struct device *dev, unsigned int reg)
501 {
502         switch (reg) {
503         case MAX98520_R210F_GLOBAL_EN:
504         case MAX98520_R21FF_REVISION_ID:
505         case MAX98520_R2000_SW_RESET:
506         case MAX98520_R2001_STATUS_1 ... MAX98520_R2002_STATUS_2:
507         case MAX98520_R20B4_ADC_READBACK_CTRL
508                 ... MAX98520_R20BD_ADC_HIGH_TEMP_READBACK_LSB:
509                 return true;
510         default:
511                 return false;
512         }
513 }
514 
515 static const struct snd_kcontrol_new max98520_snd_controls[] = {
516 /* Volume */
517 SOC_SINGLE_TLV("Digital Volume", MAX98520_R2090_AMP_VOL_CTRL,
518                0, 0x7F, 1, max98520_digital_tlv),
519 SOC_SINGLE_TLV("Speaker Volume", MAX98520_R2091_AMP_PATH_GAIN,
520                0, 0x5, 0, max98520_spk_tlv),
521 /* Volume Ramp Up/Down Enable*/
522 SOC_SINGLE("Ramp Up Switch", MAX98520_R2092_AMP_DSP_CFG,
523            MAX98520_DSP_SPK_VOL_RMPUP_SHIFT, 1, 0),
524 SOC_SINGLE("Ramp Down Switch", MAX98520_R2092_AMP_DSP_CFG,
525            MAX98520_DSP_SPK_VOL_RMPDN_SHIFT, 1, 0),
526 /* Clock Monitor Enable */
527 SOC_SINGLE("CLK Monitor Switch", MAX98520_R2037_ERR_MON_CTRL,
528            MAX98520_CTRL_CMON_EN_SHIFT, 1, 0),
529 /* Clock Monitor Config */
530 SOC_SINGLE("CLKMON Autorestart Switch", MAX98520_R2030_CLK_MON_CTRL,
531            MAX98520_CMON_AUTORESTART_SHIFT, 1, 0),
532 /* Dither Enable */
533 SOC_SINGLE("Dither Switch", MAX98520_R2092_AMP_DSP_CFG,
534            MAX98520_DSP_SPK_DITH_EN_SHIFT, 1, 0),
535 /* DC Blocker Enable */
536 SOC_SINGLE("DC Blocker Switch", MAX98520_R2092_AMP_DSP_CFG,
537            MAX98520_DSP_SPK_DCBLK_EN_SHIFT, 1, 0),
538 /* Speaker Safe Mode Enable */
539 SOC_SINGLE("Speaker Safemode Switch", MAX98520_R2092_AMP_DSP_CFG,
540            MAX98520_DSP_SPK_SAFE_EN_SHIFT, 1, 0),
541 /* AMP SSM Enable */
542 SOC_SINGLE("CP Bypass Switch", MAX98520_R2094_SSM_CFG,
543            MAX98520_SSM_RCVR_MODE_SHIFT, 1, 0),
544 /* Dynamic Headroom Tracking */
545 SOC_SINGLE("DHT Switch", MAX98520_R20D8_DHT_EN, 0, 1, 0),
546 SOC_SINGLE("DHT Limiter Mode", MAX98520_R20D2_LIMITER_CFG2,
547            MAX98520_DHT_LIMITER_MODE_SHIFT, 1, 0),
548 SOC_SINGLE("DHT Hysteresis Switch", MAX98520_R20D6_DHT_HYSTERESIS_CFG,
549            MAX98520_DHT_HYSTERESIS_SWITCH_SHIFT, 1, 0),
550 SOC_SINGLE_TLV("DHT Rot Pnt", MAX98520_R20D0_DHT_CFG1,
551                MAX98520_DHT_VROT_PNT_SHIFT, 10, 1, max98520_dht_rotation_point_tlv),
552 SOC_SINGLE_TLV("DHT Supply Headroom", MAX98520_R20D1_LIMITER_CFG1,
553                MAX98520_DHT_SUPPLY_HR_SHIFT, 16, 0, max98520_dht_supply_hr_tlv),
554 SOC_SINGLE_TLV("DHT Limiter Threshold", MAX98520_R20D2_LIMITER_CFG2,
555                MAX98520_DHT_LIMITER_THRESHOLD_SHIFT, 0xF, 1, max98520_dht_lim_thresh_tlv),
556 SOC_SINGLE_TLV("DHT Max Attenuation", MAX98520_R20D3_DHT_CFG2,
557                MAX98520_DHT_MAX_ATTEN_SHIFT, 20, 1, max98520_dht_max_atten_tlv),
558 SOC_SINGLE_TLV("DHT Hysteresis", MAX98520_R20D6_DHT_HYSTERESIS_CFG,
559                MAX98520_DHT_HYSTERESIS_SHIFT, 0x7, 0, max98520_dht_hysteresis_tlv),
560 SOC_ENUM("DHT Attack Rate", max98520_dht_attack_rate_enum),
561 SOC_ENUM("DHT Release Rate", max98520_dht_release_rate_enum),
562 /* ADC configuration */
563 SOC_SINGLE("ADC PVDD CH Switch", MAX98520_R20CF_MEAS_ADC_CFG, 0, 1, 0),
564 SOC_SINGLE("ADC PVDD FLT Switch", MAX98520_R20B2_ADC_PVDD0_CFG, MAX98520_FLT_EN_SHIFT, 1, 0),
565 SOC_SINGLE("ADC TEMP FLT Switch", MAX98520_R20B3_ADC_THERMAL_CFG, MAX98520_FLT_EN_SHIFT, 1, 0),
566 SOC_SINGLE("ADC PVDD MSB", MAX98520_R20B6_ADC_PVDD_READBACK_MSB, 0, 0xFF, 0),
567 SOC_SINGLE("ADC PVDD LSB", MAX98520_R20B7_ADC_PVDD_READBACK_LSB, 0, 0x01, 0),
568 SOC_SINGLE("ADC TEMP MSB", MAX98520_R20B8_ADC_TEMP_READBACK_MSB, 0, 0xFF, 0),
569 SOC_SINGLE("ADC TEMP LSB", MAX98520_R20B9_ADC_TEMP_READBACK_LSB, 0, 0x01, 0),
570 };
571 
572 static const struct snd_soc_dapm_route max98520_audio_map[] = {
573         /* Plabyack */
574         {"DAI Sel Mux", "Left", "Amp Enable"},
575         {"DAI Sel Mux", "Right", "Amp Enable"},
576         {"DAI Sel Mux", "LeftRight", "Amp Enable"},
577         {"BE_OUT", NULL, "DAI Sel Mux"},
578 };
579 
580 static struct snd_soc_dai_driver max98520_dai[] = {
581         {
582                 .name = "max98520-aif1",
583                 .playback = {
584                         .stream_name = "HiFi Playback",
585                         .channels_min = 1,
586                         .channels_max = 2,
587                         .rates = MAX98520_RATES,
588                         .formats = MAX98520_FORMATS,
589                 },
590                 .ops = &max98520_dai_ops,
591         }
592 
593 };
594 
595 static int max98520_probe(struct snd_soc_component *component)
596 {
597         struct max98520_priv *max98520 =
598                 snd_soc_component_get_drvdata(component);
599 
600         /* Software Reset */
601         regmap_write(max98520->regmap, MAX98520_R2000_SW_RESET, 1);
602 
603         /* L/R mono mix configuration : "DAI Sel" for 0x2043 */
604         regmap_write(max98520->regmap, MAX98520_R2043_PCM_RX_SRC1, 0x2);
605 
606         /* PCM input channles configuration : "Left Input Selection" for 0x2044 */
607         /* PCM input channles configuration : "Right Input Selection" for 0x2044 */
608         regmap_write(max98520->regmap, MAX98520_R2044_PCM_RX_SRC2, 0x10);
609 
610         /* Enable DC blocker */
611         regmap_update_bits(max98520->regmap, MAX98520_R2092_AMP_DSP_CFG, 1, 1);
612         /* Enable Clock Monitor Auto-restart */
613         regmap_write(max98520->regmap, MAX98520_R2030_CLK_MON_CTRL, 0x1);
614 
615         /* set Rx Enable */
616         regmap_update_bits(max98520->regmap,
617                            MAX98520_R204F_PCM_RX_EN,
618                            MAX98520_PCM_RX_EN_MASK,
619                            1);
620 
621         return 0;
622 }
623 
624 static int __maybe_unused max98520_suspend(struct device *dev)
625 {
626         struct max98520_priv *max98520 = dev_get_drvdata(dev);
627 
628         regcache_cache_only(max98520->regmap, true);
629         regcache_mark_dirty(max98520->regmap);
630         return 0;
631 }
632 
633 static int __maybe_unused max98520_resume(struct device *dev)
634 {
635         struct max98520_priv *max98520 = dev_get_drvdata(dev);
636 
637         regcache_cache_only(max98520->regmap, false);
638         regmap_write(max98520->regmap, MAX98520_R2000_SW_RESET, 1);
639         regcache_sync(max98520->regmap);
640         return 0;
641 }
642 
643 static const struct dev_pm_ops max98520_pm = {
644         SET_SYSTEM_SLEEP_PM_OPS(max98520_suspend, max98520_resume)
645 };
646 
647 static const struct snd_soc_component_driver soc_codec_dev_max98520 = {
648         .probe                  = max98520_probe,
649         .controls               = max98520_snd_controls,
650         .num_controls           = ARRAY_SIZE(max98520_snd_controls),
651         .dapm_widgets           = max98520_dapm_widgets,
652         .num_dapm_widgets       = ARRAY_SIZE(max98520_dapm_widgets),
653         .dapm_routes            = max98520_audio_map,
654         .num_dapm_routes        = ARRAY_SIZE(max98520_audio_map),
655         .idle_bias_on           = 1,
656         .use_pmdown_time        = 1,
657         .endianness             = 1,
658 };
659 
660 static const struct regmap_config max98520_regmap = {
661         .reg_bits = 16,
662         .val_bits = 8,
663         .max_register = MAX98520_R21FF_REVISION_ID,
664         .reg_defaults  = max98520_reg,
665         .num_reg_defaults = ARRAY_SIZE(max98520_reg),
666         .readable_reg = max98520_readable_register,
667         .volatile_reg = max98520_volatile_reg,
668         .cache_type = REGCACHE_RBTREE,
669 };
670 
671 static void max98520_power_on(struct max98520_priv *max98520, bool poweron)
672 {
673         if (max98520->reset_gpio)
674                 gpiod_set_value_cansleep(max98520->reset_gpio, !poweron);
675 }
676 
677 static int max98520_i2c_probe(struct i2c_client *i2c)
678 {
679         int ret;
680         int reg = 0;
681         struct max98520_priv *max98520;
682         struct i2c_adapter *adapter = to_i2c_adapter(i2c->dev.parent);
683 
684         ret = i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA);
685         if (!ret) {
686                 dev_err(&i2c->dev, "I2C check functionality failed\n");
687                 return -ENXIO;
688         }
689 
690         max98520 = devm_kzalloc(&i2c->dev, sizeof(*max98520), GFP_KERNEL);
691 
692         if (!max98520)
693                 return -ENOMEM;
694 
695         i2c_set_clientdata(i2c, max98520);
696 
697         /* regmap initialization */
698         max98520->regmap = devm_regmap_init_i2c(i2c, &max98520_regmap);
699         if (IS_ERR(max98520->regmap)) {
700                 ret = PTR_ERR(max98520->regmap);
701                 dev_err(&i2c->dev, "Failed to allocate regmap: %d\n", ret);
702                 return ret;
703         }
704 
705         /* Power on device */
706         max98520->reset_gpio = devm_gpiod_get_optional(&i2c->dev, "reset", GPIOD_OUT_HIGH);
707         if (max98520->reset_gpio) {
708                 if (IS_ERR(max98520->reset_gpio)) {
709                         ret = PTR_ERR(max98520->reset_gpio);
710                         dev_err(&i2c->dev, "Unable to request GPIO pin: %d.\n", ret);
711                         return ret;
712                 }
713 
714                 max98520_power_on(max98520, 1);
715         }
716 
717         /* Check Revision ID */
718         ret = regmap_read(max98520->regmap, MAX98520_R21FF_REVISION_ID, &reg);
719         if (ret < 0) {
720                 dev_err(&i2c->dev,
721                         "Failed to read: 0x%02X\n", MAX98520_R21FF_REVISION_ID);
722                 return ret;
723         }
724         dev_info(&i2c->dev, "MAX98520 revisionID: 0x%02X\n", reg);
725 
726         /* codec registration */
727         ret = devm_snd_soc_register_component(&i2c->dev,
728                                               &soc_codec_dev_max98520,
729                                                   max98520_dai, ARRAY_SIZE(max98520_dai));
730         if (ret < 0)
731                 dev_err(&i2c->dev, "Failed to register codec: %d\n", ret);
732 
733         return ret;
734 }
735 
736 static const struct i2c_device_id max98520_i2c_id[] = {
737         { "max98520"},
738         { },
739 };
740 
741 MODULE_DEVICE_TABLE(i2c, max98520_i2c_id);
742 
743 #if defined(CONFIG_OF)
744 static const struct of_device_id max98520_of_match[] = {
745         { .compatible = "maxim,max98520", },
746         { }
747 };
748 MODULE_DEVICE_TABLE(of, max98520_of_match);
749 #endif
750 
751 static struct i2c_driver max98520_i2c_driver = {
752         .driver = {
753                 .name = "max98520",
754                 .of_match_table = of_match_ptr(max98520_of_match),
755                 .pm = &max98520_pm,
756         },
757         .probe = max98520_i2c_probe,
758         .id_table = max98520_i2c_id,
759 };
760 
761 module_i2c_driver(max98520_i2c_driver)
762 
763 MODULE_DESCRIPTION("ALSA SoC MAX98520 driver");
764 MODULE_AUTHOR("George Song <george.song@maximintegrated.com>");
765 MODULE_LICENSE("GPL");
766 
767 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php