linux/sound/soc/codecs/max98373.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2// Copyright (c) 2017, 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.h>
  15#include <linux/of.h>
  16#include <linux/of_gpio.h>
  17#include <sound/tlv.h>
  18#include "max98373.h"
  19
  20static int max98373_dac_event(struct snd_soc_dapm_widget *w,
  21        struct snd_kcontrol *kcontrol, int event)
  22{
  23        struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
  24        struct max98373_priv *max98373 = snd_soc_component_get_drvdata(component);
  25
  26        switch (event) {
  27        case SND_SOC_DAPM_POST_PMU:
  28                regmap_update_bits(max98373->regmap,
  29                        MAX98373_R20FF_GLOBAL_SHDN,
  30                        MAX98373_GLOBAL_EN_MASK, 1);
  31                usleep_range(30000, 31000);
  32                break;
  33        case SND_SOC_DAPM_POST_PMD:
  34                regmap_update_bits(max98373->regmap,
  35                        MAX98373_R20FF_GLOBAL_SHDN,
  36                        MAX98373_GLOBAL_EN_MASK, 0);
  37                usleep_range(30000, 31000);
  38                max98373->tdm_mode = false;
  39                break;
  40        default:
  41                return 0;
  42        }
  43        return 0;
  44}
  45
  46static const char * const max98373_switch_text[] = {
  47        "Left", "Right", "LeftRight"};
  48
  49static const struct soc_enum dai_sel_enum =
  50        SOC_ENUM_SINGLE(MAX98373_R2029_PCM_TO_SPK_MONO_MIX_1,
  51                MAX98373_PCM_TO_SPK_MONOMIX_CFG_SHIFT,
  52                3, max98373_switch_text);
  53
  54static const struct snd_kcontrol_new max98373_dai_controls =
  55        SOC_DAPM_ENUM("DAI Sel", dai_sel_enum);
  56
  57static const struct snd_kcontrol_new max98373_vi_control =
  58        SOC_DAPM_SINGLE("Switch", MAX98373_R202C_PCM_TX_EN, 0, 1, 0);
  59
  60static const struct snd_kcontrol_new max98373_spkfb_control =
  61        SOC_DAPM_SINGLE("Switch", MAX98373_R2043_AMP_EN, 1, 1, 0);
  62
  63static const struct snd_soc_dapm_widget max98373_dapm_widgets[] = {
  64SND_SOC_DAPM_DAC_E("Amp Enable", "HiFi Playback",
  65        MAX98373_R202B_PCM_RX_EN, 0, 0, max98373_dac_event,
  66        SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
  67SND_SOC_DAPM_MUX("DAI Sel Mux", SND_SOC_NOPM, 0, 0,
  68        &max98373_dai_controls),
  69SND_SOC_DAPM_OUTPUT("BE_OUT"),
  70SND_SOC_DAPM_AIF_OUT("Voltage Sense", "HiFi Capture", 0,
  71        MAX98373_R2047_IV_SENSE_ADC_EN, 0, 0),
  72SND_SOC_DAPM_AIF_OUT("Current Sense", "HiFi Capture", 0,
  73        MAX98373_R2047_IV_SENSE_ADC_EN, 1, 0),
  74SND_SOC_DAPM_AIF_OUT("Speaker FB Sense", "HiFi Capture", 0,
  75        SND_SOC_NOPM, 0, 0),
  76SND_SOC_DAPM_SWITCH("VI Sense", SND_SOC_NOPM, 0, 0,
  77        &max98373_vi_control),
  78SND_SOC_DAPM_SWITCH("SpkFB Sense", SND_SOC_NOPM, 0, 0,
  79        &max98373_spkfb_control),
  80SND_SOC_DAPM_SIGGEN("VMON"),
  81SND_SOC_DAPM_SIGGEN("IMON"),
  82SND_SOC_DAPM_SIGGEN("FBMON"),
  83};
  84
  85static DECLARE_TLV_DB_SCALE(max98373_digital_tlv, -6350, 50, 1);
  86static const DECLARE_TLV_DB_RANGE(max98373_spk_tlv,
  87        0, 8, TLV_DB_SCALE_ITEM(0, 50, 0),
  88        9, 10, TLV_DB_SCALE_ITEM(500, 100, 0),
  89);
  90static const DECLARE_TLV_DB_RANGE(max98373_spkgain_max_tlv,
  91        0, 9, TLV_DB_SCALE_ITEM(800, 100, 0),
  92);
  93static const DECLARE_TLV_DB_RANGE(max98373_dht_step_size_tlv,
  94        0, 1, TLV_DB_SCALE_ITEM(25, 25, 0),
  95        2, 4, TLV_DB_SCALE_ITEM(100, 100, 0),
  96);
  97static const DECLARE_TLV_DB_RANGE(max98373_dht_spkgain_min_tlv,
  98        0, 9, TLV_DB_SCALE_ITEM(800, 100, 0),
  99);
 100static const DECLARE_TLV_DB_RANGE(max98373_dht_rotation_point_tlv,
 101        0, 1, TLV_DB_SCALE_ITEM(-3000, 500, 0),
 102        2, 4, TLV_DB_SCALE_ITEM(-2200, 200, 0),
 103        5, 6, TLV_DB_SCALE_ITEM(-1500, 300, 0),
 104        7, 9, TLV_DB_SCALE_ITEM(-1000, 200, 0),
 105        10, 13, TLV_DB_SCALE_ITEM(-500, 100, 0),
 106        14, 15, TLV_DB_SCALE_ITEM(-100, 50, 0),
 107);
 108static const DECLARE_TLV_DB_RANGE(max98373_limiter_thresh_tlv,
 109        0, 15, TLV_DB_SCALE_ITEM(-1500, 100, 0),
 110);
 111
 112static const DECLARE_TLV_DB_RANGE(max98373_bde_gain_tlv,
 113        0, 60, TLV_DB_SCALE_ITEM(-1500, 25, 0),
 114);
 115
 116static const char * const max98373_output_voltage_lvl_text[] = {
 117        "5.43V", "6.09V", "6.83V", "7.67V", "8.60V",
 118        "9.65V", "10.83V", "12.15V", "13.63V", "15.29V"
 119};
 120
 121static SOC_ENUM_SINGLE_DECL(max98373_out_volt_enum,
 122                            MAX98373_R203E_AMP_PATH_GAIN, 0,
 123                            max98373_output_voltage_lvl_text);
 124
 125static const char * const max98373_dht_attack_rate_text[] = {
 126        "17.5us", "35us", "70us", "140us",
 127        "280us", "560us", "1120us", "2240us"
 128};
 129
 130static SOC_ENUM_SINGLE_DECL(max98373_dht_attack_rate_enum,
 131                            MAX98373_R20D2_DHT_ATTACK_CFG, 0,
 132                            max98373_dht_attack_rate_text);
 133
 134static const char * const max98373_dht_release_rate_text[] = {
 135        "45ms", "225ms", "450ms", "1150ms",
 136        "2250ms", "3100ms", "4500ms", "6750ms"
 137};
 138
 139static SOC_ENUM_SINGLE_DECL(max98373_dht_release_rate_enum,
 140                            MAX98373_R20D3_DHT_RELEASE_CFG, 0,
 141                            max98373_dht_release_rate_text);
 142
 143static const char * const max98373_limiter_attack_rate_text[] = {
 144        "10us", "20us", "40us", "80us",
 145        "160us", "320us", "640us", "1.28ms",
 146        "2.56ms", "5.12ms", "10.24ms", "20.48ms",
 147        "40.96ms", "81.92ms", "16.384ms", "32.768ms"
 148};
 149
 150static SOC_ENUM_SINGLE_DECL(max98373_limiter_attack_rate_enum,
 151                            MAX98373_R20E1_LIMITER_ATK_REL_RATES, 4,
 152                            max98373_limiter_attack_rate_text);
 153
 154static const char * const max98373_limiter_release_rate_text[] = {
 155        "40us", "80us", "160us", "320us",
 156        "640us", "1.28ms", "2.56ms", "5.120ms",
 157        "10.24ms", "20.48ms", "40.96ms", "81.92ms",
 158        "163.84ms", "327.68ms", "655.36ms", "1310.72ms"
 159};
 160
 161static SOC_ENUM_SINGLE_DECL(max98373_limiter_release_rate_enum,
 162                            MAX98373_R20E1_LIMITER_ATK_REL_RATES, 0,
 163                            max98373_limiter_release_rate_text);
 164
 165static const char * const max98373_ADC_samplerate_text[] = {
 166        "333kHz", "192kHz", "64kHz", "48kHz"
 167};
 168
 169static SOC_ENUM_SINGLE_DECL(max98373_adc_samplerate_enum,
 170                            MAX98373_R2051_MEAS_ADC_SAMPLING_RATE, 0,
 171                            max98373_ADC_samplerate_text);
 172
 173static int max98373_feedback_get(struct snd_kcontrol *kcontrol,
 174                                 struct snd_ctl_elem_value *ucontrol)
 175{
 176        struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
 177        struct soc_mixer_control *mc =
 178                (struct soc_mixer_control *)kcontrol->private_value;
 179        struct max98373_priv *max98373 = snd_soc_component_get_drvdata(component);
 180        int i;
 181
 182        if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
 183                /*
 184                 * Register values will be cached before suspend. The cached value
 185                 * will be a valid value and userspace will happy with that.
 186                 */
 187                for (i = 0; i < max98373->cache_num; i++) {
 188                        if (mc->reg == max98373->cache[i].reg) {
 189                                ucontrol->value.integer.value[0] = max98373->cache[i].val;
 190                                return 0;
 191                        }
 192                }
 193        }
 194
 195        return snd_soc_get_volsw(kcontrol, ucontrol);
 196}
 197
 198static const struct snd_kcontrol_new max98373_snd_controls[] = {
 199SOC_SINGLE("Digital Vol Sel Switch", MAX98373_R203F_AMP_DSP_CFG,
 200        MAX98373_AMP_VOL_SEL_SHIFT, 1, 0),
 201SOC_SINGLE("Volume Location Switch", MAX98373_R203F_AMP_DSP_CFG,
 202        MAX98373_AMP_VOL_SEL_SHIFT, 1, 0),
 203SOC_SINGLE("Ramp Up Switch", MAX98373_R203F_AMP_DSP_CFG,
 204        MAX98373_AMP_DSP_CFG_RMP_UP_SHIFT, 1, 0),
 205SOC_SINGLE("Ramp Down Switch", MAX98373_R203F_AMP_DSP_CFG,
 206        MAX98373_AMP_DSP_CFG_RMP_DN_SHIFT, 1, 0),
 207/* Speaker Amplifier Overcurrent Automatic Restart Enable */
 208SOC_SINGLE("OVC Autorestart Switch", MAX98373_R20FE_DEVICE_AUTO_RESTART_CFG,
 209        MAX98373_OVC_AUTORESTART_SHIFT, 1, 0),
 210/* Thermal Shutdown Automatic Restart Enable */
 211SOC_SINGLE("THERM Autorestart Switch", MAX98373_R20FE_DEVICE_AUTO_RESTART_CFG,
 212        MAX98373_THERM_AUTORESTART_SHIFT, 1, 0),
 213/* Clock Monitor Automatic Restart Enable */
 214SOC_SINGLE("CMON Autorestart Switch", MAX98373_R20FE_DEVICE_AUTO_RESTART_CFG,
 215        MAX98373_CMON_AUTORESTART_SHIFT, 1, 0),
 216SOC_SINGLE("CLK Monitor Switch", MAX98373_R20FE_DEVICE_AUTO_RESTART_CFG,
 217        MAX98373_CLOCK_MON_SHIFT, 1, 0),
 218SOC_SINGLE("Dither Switch", MAX98373_R203F_AMP_DSP_CFG,
 219        MAX98373_AMP_DSP_CFG_DITH_SHIFT, 1, 0),
 220SOC_SINGLE("DC Blocker Switch", MAX98373_R203F_AMP_DSP_CFG,
 221        MAX98373_AMP_DSP_CFG_DCBLK_SHIFT, 1, 0),
 222SOC_SINGLE_TLV("Digital Volume", MAX98373_R203D_AMP_DIG_VOL_CTRL,
 223        0, 0x7F, 1, max98373_digital_tlv),
 224SOC_SINGLE_TLV("Speaker Volume", MAX98373_R203E_AMP_PATH_GAIN,
 225        MAX98373_SPK_DIGI_GAIN_SHIFT, 10, 0, max98373_spk_tlv),
 226SOC_SINGLE_TLV("FS Max Volume", MAX98373_R203E_AMP_PATH_GAIN,
 227        MAX98373_FS_GAIN_MAX_SHIFT, 9, 0, max98373_spkgain_max_tlv),
 228SOC_ENUM("Output Voltage", max98373_out_volt_enum),
 229/* Dynamic Headroom Tracking */
 230SOC_SINGLE("DHT Switch", MAX98373_R20D4_DHT_EN,
 231        MAX98373_DHT_EN_SHIFT, 1, 0),
 232SOC_SINGLE_TLV("DHT Min Volume", MAX98373_R20D1_DHT_CFG,
 233        MAX98373_DHT_SPK_GAIN_MIN_SHIFT, 9, 0, max98373_dht_spkgain_min_tlv),
 234SOC_SINGLE_TLV("DHT Rot Pnt Volume", MAX98373_R20D1_DHT_CFG,
 235        MAX98373_DHT_ROT_PNT_SHIFT, 15, 1, max98373_dht_rotation_point_tlv),
 236SOC_SINGLE_TLV("DHT Attack Step Volume", MAX98373_R20D2_DHT_ATTACK_CFG,
 237        MAX98373_DHT_ATTACK_STEP_SHIFT, 4, 0, max98373_dht_step_size_tlv),
 238SOC_SINGLE_TLV("DHT Release Step Volume", MAX98373_R20D3_DHT_RELEASE_CFG,
 239        MAX98373_DHT_RELEASE_STEP_SHIFT, 4, 0, max98373_dht_step_size_tlv),
 240SOC_ENUM("DHT Attack Rate", max98373_dht_attack_rate_enum),
 241SOC_ENUM("DHT Release Rate", max98373_dht_release_rate_enum),
 242/* ADC configuration */
 243SOC_SINGLE("ADC PVDD CH Switch", MAX98373_R2056_MEAS_ADC_PVDD_CH_EN, 0, 1, 0),
 244SOC_SINGLE("ADC PVDD FLT Switch", MAX98373_R2052_MEAS_ADC_PVDD_FLT_CFG,
 245        MAX98373_FLT_EN_SHIFT, 1, 0),
 246SOC_SINGLE("ADC TEMP FLT Switch", MAX98373_R2053_MEAS_ADC_THERM_FLT_CFG,
 247        MAX98373_FLT_EN_SHIFT, 1, 0),
 248SOC_SINGLE_EXT("ADC PVDD", MAX98373_R2054_MEAS_ADC_PVDD_CH_READBACK, 0, 0xFF, 0,
 249        max98373_feedback_get, NULL),
 250SOC_SINGLE_EXT("ADC TEMP", MAX98373_R2055_MEAS_ADC_THERM_CH_READBACK, 0, 0xFF, 0,
 251        max98373_feedback_get, NULL),
 252SOC_SINGLE("ADC PVDD FLT Coeff", MAX98373_R2052_MEAS_ADC_PVDD_FLT_CFG,
 253        0, 0x3, 0),
 254SOC_SINGLE("ADC TEMP FLT Coeff", MAX98373_R2053_MEAS_ADC_THERM_FLT_CFG,
 255        0, 0x3, 0),
 256SOC_ENUM("ADC SampleRate", max98373_adc_samplerate_enum),
 257/* Brownout Detection Engine */
 258SOC_SINGLE("BDE Switch", MAX98373_R20B5_BDE_EN, MAX98373_BDE_EN_SHIFT, 1, 0),
 259SOC_SINGLE("BDE LVL4 Mute Switch", MAX98373_R20B2_BDE_L4_CFG_2,
 260        MAX98373_LVL4_MUTE_EN_SHIFT, 1, 0),
 261SOC_SINGLE("BDE LVL4 Hold Switch", MAX98373_R20B2_BDE_L4_CFG_2,
 262        MAX98373_LVL4_HOLD_EN_SHIFT, 1, 0),
 263SOC_SINGLE("BDE LVL1 Thresh", MAX98373_R2097_BDE_L1_THRESH, 0, 0xFF, 0),
 264SOC_SINGLE("BDE LVL2 Thresh", MAX98373_R2098_BDE_L2_THRESH, 0, 0xFF, 0),
 265SOC_SINGLE("BDE LVL3 Thresh", MAX98373_R2099_BDE_L3_THRESH, 0, 0xFF, 0),
 266SOC_SINGLE("BDE LVL4 Thresh", MAX98373_R209A_BDE_L4_THRESH, 0, 0xFF, 0),
 267SOC_SINGLE_EXT("BDE Active Level", MAX98373_R20B6_BDE_CUR_STATE_READBACK, 0, 8, 0,
 268        max98373_feedback_get, NULL),
 269SOC_SINGLE("BDE Clip Mode Switch", MAX98373_R2092_BDE_CLIPPER_MODE, 0, 1, 0),
 270SOC_SINGLE("BDE Thresh Hysteresis", MAX98373_R209B_BDE_THRESH_HYST, 0, 0xFF, 0),
 271SOC_SINGLE("BDE Hold Time", MAX98373_R2090_BDE_LVL_HOLD, 0, 0xFF, 0),
 272SOC_SINGLE("BDE Attack Rate", MAX98373_R2091_BDE_GAIN_ATK_REL_RATE, 4, 0xF, 0),
 273SOC_SINGLE("BDE Release Rate", MAX98373_R2091_BDE_GAIN_ATK_REL_RATE, 0, 0xF, 0),
 274SOC_SINGLE_TLV("BDE LVL1 Clip Thresh Volume", MAX98373_R20A9_BDE_L1_CFG_2,
 275        0, 0x3C, 1, max98373_bde_gain_tlv),
 276SOC_SINGLE_TLV("BDE LVL2 Clip Thresh Volume", MAX98373_R20AC_BDE_L2_CFG_2,
 277        0, 0x3C, 1, max98373_bde_gain_tlv),
 278SOC_SINGLE_TLV("BDE LVL3 Clip Thresh Volume", MAX98373_R20AF_BDE_L3_CFG_2,
 279        0, 0x3C, 1, max98373_bde_gain_tlv),
 280SOC_SINGLE_TLV("BDE LVL4 Clip Thresh Volume", MAX98373_R20B2_BDE_L4_CFG_2,
 281        0, 0x3C, 1, max98373_bde_gain_tlv),
 282SOC_SINGLE_TLV("BDE LVL1 Clip Reduction Volume", MAX98373_R20AA_BDE_L1_CFG_3,
 283        0, 0x3C, 1, max98373_bde_gain_tlv),
 284SOC_SINGLE_TLV("BDE LVL2 Clip Reduction Volume", MAX98373_R20AD_BDE_L2_CFG_3,
 285        0, 0x3C, 1, max98373_bde_gain_tlv),
 286SOC_SINGLE_TLV("BDE LVL3 Clip Reduction Volume", MAX98373_R20B0_BDE_L3_CFG_3,
 287        0, 0x3C, 1, max98373_bde_gain_tlv),
 288SOC_SINGLE_TLV("BDE LVL4 Clip Reduction Volume", MAX98373_R20B3_BDE_L4_CFG_3,
 289        0, 0x3C, 1, max98373_bde_gain_tlv),
 290SOC_SINGLE_TLV("BDE LVL1 Limiter Thresh Volume", MAX98373_R20A8_BDE_L1_CFG_1,
 291        0, 0xF, 1, max98373_limiter_thresh_tlv),
 292SOC_SINGLE_TLV("BDE LVL2 Limiter Thresh Volume", MAX98373_R20AB_BDE_L2_CFG_1,
 293        0, 0xF, 1, max98373_limiter_thresh_tlv),
 294SOC_SINGLE_TLV("BDE LVL3 Limiter Thresh Volume", MAX98373_R20AE_BDE_L3_CFG_1,
 295        0, 0xF, 1, max98373_limiter_thresh_tlv),
 296SOC_SINGLE_TLV("BDE LVL4 Limiter Thresh Volume", MAX98373_R20B1_BDE_L4_CFG_1,
 297        0, 0xF, 1, max98373_limiter_thresh_tlv),
 298/* Limiter */
 299SOC_SINGLE("Limiter Switch", MAX98373_R20E2_LIMITER_EN,
 300        MAX98373_LIMITER_EN_SHIFT, 1, 0),
 301SOC_SINGLE("Limiter Src Switch", MAX98373_R20E0_LIMITER_THRESH_CFG,
 302        MAX98373_LIMITER_THRESH_SRC_SHIFT, 1, 0),
 303SOC_SINGLE_TLV("Limiter Thresh Volume", MAX98373_R20E0_LIMITER_THRESH_CFG,
 304        MAX98373_LIMITER_THRESH_SHIFT, 15, 0, max98373_limiter_thresh_tlv),
 305SOC_ENUM("Limiter Attack Rate", max98373_limiter_attack_rate_enum),
 306SOC_ENUM("Limiter Release Rate", max98373_limiter_release_rate_enum),
 307};
 308
 309static const struct snd_soc_dapm_route max98373_audio_map[] = {
 310        /* Plabyack */
 311        {"DAI Sel Mux", "Left", "Amp Enable"},
 312        {"DAI Sel Mux", "Right", "Amp Enable"},
 313        {"DAI Sel Mux", "LeftRight", "Amp Enable"},
 314        {"BE_OUT", NULL, "DAI Sel Mux"},
 315        /* Capture */
 316        { "VI Sense", "Switch", "VMON" },
 317        { "VI Sense", "Switch", "IMON" },
 318        { "SpkFB Sense", "Switch", "FBMON" },
 319        { "Voltage Sense", NULL, "VI Sense" },
 320        { "Current Sense", NULL, "VI Sense" },
 321        { "Speaker FB Sense", NULL, "SpkFB Sense" },
 322};
 323
 324void max98373_reset(struct max98373_priv *max98373, struct device *dev)
 325{
 326        int ret, reg, count;
 327
 328        /* Software Reset */
 329        ret = regmap_update_bits(max98373->regmap,
 330                MAX98373_R2000_SW_RESET,
 331                MAX98373_SOFT_RESET,
 332                MAX98373_SOFT_RESET);
 333        if (ret)
 334                dev_err(dev, "Reset command failed. (ret:%d)\n", ret);
 335
 336        count = 0;
 337        while (count < 3) {
 338                usleep_range(10000, 11000);
 339                /* Software Reset Verification */
 340                ret = regmap_read(max98373->regmap,
 341                        MAX98373_R21FF_REV_ID, &reg);
 342                if (!ret) {
 343                        dev_info(dev, "Reset completed (retry:%d)\n", count);
 344                        return;
 345                }
 346                count++;
 347        }
 348        dev_err(dev, "Reset failed. (ret:%d)\n", ret);
 349}
 350EXPORT_SYMBOL_GPL(max98373_reset);
 351
 352static int max98373_probe(struct snd_soc_component *component)
 353{
 354        struct max98373_priv *max98373 = snd_soc_component_get_drvdata(component);
 355
 356        /* Software Reset */
 357        max98373_reset(max98373, component->dev);
 358
 359        /* IV default slot configuration */
 360        regmap_write(max98373->regmap,
 361                MAX98373_R2020_PCM_TX_HIZ_EN_1,
 362                0xFF);
 363        regmap_write(max98373->regmap,
 364                MAX98373_R2021_PCM_TX_HIZ_EN_2,
 365                0xFF);
 366        /* L/R mix configuration */
 367        regmap_write(max98373->regmap,
 368                MAX98373_R2029_PCM_TO_SPK_MONO_MIX_1,
 369                0x80);
 370        regmap_write(max98373->regmap,
 371                MAX98373_R202A_PCM_TO_SPK_MONO_MIX_2,
 372                0x1);
 373        /* Enable DC blocker */
 374        regmap_write(max98373->regmap,
 375                MAX98373_R203F_AMP_DSP_CFG,
 376                0x3);
 377        /* Enable IMON VMON DC blocker */
 378        regmap_write(max98373->regmap,
 379                MAX98373_R2046_IV_SENSE_ADC_DSP_CFG,
 380                0x7);
 381        /* voltage, current slot configuration */
 382        regmap_write(max98373->regmap,
 383                MAX98373_R2022_PCM_TX_SRC_1,
 384                (max98373->i_slot << MAX98373_PCM_TX_CH_SRC_A_I_SHIFT |
 385                max98373->v_slot) & 0xFF);
 386        if (max98373->v_slot < 8)
 387                regmap_update_bits(max98373->regmap,
 388                        MAX98373_R2020_PCM_TX_HIZ_EN_1,
 389                        1 << max98373->v_slot, 0);
 390        else
 391                regmap_update_bits(max98373->regmap,
 392                        MAX98373_R2021_PCM_TX_HIZ_EN_2,
 393                        1 << (max98373->v_slot - 8), 0);
 394
 395        if (max98373->i_slot < 8)
 396                regmap_update_bits(max98373->regmap,
 397                        MAX98373_R2020_PCM_TX_HIZ_EN_1,
 398                        1 << max98373->i_slot, 0);
 399        else
 400                regmap_update_bits(max98373->regmap,
 401                        MAX98373_R2021_PCM_TX_HIZ_EN_2,
 402                        1 << (max98373->i_slot - 8), 0);
 403
 404        /* enable auto restart function by default */
 405        regmap_write(max98373->regmap,
 406                MAX98373_R20FE_DEVICE_AUTO_RESTART_CFG,
 407                0xF);
 408
 409        /* speaker feedback slot configuration */
 410        regmap_write(max98373->regmap,
 411                MAX98373_R2023_PCM_TX_SRC_2,
 412                max98373->spkfb_slot & 0xFF);
 413
 414        /* Set interleave mode */
 415        if (max98373->interleave_mode)
 416                regmap_update_bits(max98373->regmap,
 417                        MAX98373_R2024_PCM_DATA_FMT_CFG,
 418                        MAX98373_PCM_TX_CH_INTERLEAVE_MASK,
 419                        MAX98373_PCM_TX_CH_INTERLEAVE_MASK);
 420
 421        /* Speaker enable */
 422        regmap_update_bits(max98373->regmap,
 423                MAX98373_R2043_AMP_EN,
 424                MAX98373_SPK_EN_MASK, 1);
 425
 426        return 0;
 427}
 428
 429const struct snd_soc_component_driver soc_codec_dev_max98373 = {
 430        .probe                  = max98373_probe,
 431        .controls               = max98373_snd_controls,
 432        .num_controls           = ARRAY_SIZE(max98373_snd_controls),
 433        .dapm_widgets           = max98373_dapm_widgets,
 434        .num_dapm_widgets       = ARRAY_SIZE(max98373_dapm_widgets),
 435        .dapm_routes            = max98373_audio_map,
 436        .num_dapm_routes        = ARRAY_SIZE(max98373_audio_map),
 437        .use_pmdown_time        = 1,
 438        .endianness             = 1,
 439        .non_legacy_dai_naming  = 1,
 440};
 441EXPORT_SYMBOL_GPL(soc_codec_dev_max98373);
 442
 443const struct snd_soc_component_driver soc_codec_dev_max98373_sdw = {
 444        .probe                  = NULL,
 445        .controls               = max98373_snd_controls,
 446        .num_controls           = ARRAY_SIZE(max98373_snd_controls),
 447        .dapm_widgets           = max98373_dapm_widgets,
 448        .num_dapm_widgets       = ARRAY_SIZE(max98373_dapm_widgets),
 449        .dapm_routes            = max98373_audio_map,
 450        .num_dapm_routes        = ARRAY_SIZE(max98373_audio_map),
 451        .use_pmdown_time        = 1,
 452        .endianness             = 1,
 453        .non_legacy_dai_naming  = 1,
 454};
 455EXPORT_SYMBOL_GPL(soc_codec_dev_max98373_sdw);
 456
 457void max98373_slot_config(struct device *dev,
 458                          struct max98373_priv *max98373)
 459{
 460        int value;
 461
 462        if (!device_property_read_u32(dev, "maxim,vmon-slot-no", &value))
 463                max98373->v_slot = value & 0xF;
 464        else
 465                max98373->v_slot = 0;
 466
 467        if (!device_property_read_u32(dev, "maxim,imon-slot-no", &value))
 468                max98373->i_slot = value & 0xF;
 469        else
 470                max98373->i_slot = 1;
 471        if (dev->of_node) {
 472                max98373->reset_gpio = of_get_named_gpio(dev->of_node,
 473                                                "maxim,reset-gpio", 0);
 474                if (!gpio_is_valid(max98373->reset_gpio)) {
 475                        dev_err(dev, "Looking up %s property in node %s failed %d\n",
 476                                "maxim,reset-gpio", dev->of_node->full_name,
 477                                max98373->reset_gpio);
 478                } else {
 479                        dev_dbg(dev, "maxim,reset-gpio=%d",
 480                                max98373->reset_gpio);
 481                }
 482        } else {
 483                /* this makes reset_gpio as invalid */
 484                max98373->reset_gpio = -1;
 485        }
 486
 487        if (!device_property_read_u32(dev, "maxim,spkfb-slot-no", &value))
 488                max98373->spkfb_slot = value & 0xF;
 489        else
 490                max98373->spkfb_slot = 2;
 491}
 492EXPORT_SYMBOL_GPL(max98373_slot_config);
 493
 494MODULE_DESCRIPTION("ALSA SoC MAX98373 driver");
 495MODULE_AUTHOR("Ryan Lee <ryans.lee@maximintegrated.com>");
 496MODULE_LICENSE("GPL");
 497