| 1 | // SPDX-License-Identifier: GPL-2.0 |
| 2 | // Copyright (c) 2022, Analog Devices Inc. |
| 3 | |
| 4 | #include <linux/acpi.h> |
| 5 | #include <linux/delay.h> |
| 6 | #include <linux/gpio/consumer.h> |
| 7 | #include <linux/i2c.h> |
| 8 | #include <linux/module.h> |
| 9 | #include <linux/mod_devicetable.h> |
| 10 | #include <linux/of.h> |
| 11 | #include <linux/pm_runtime.h> |
| 12 | #include <linux/regmap.h> |
| 13 | #include <linux/slab.h> |
| 14 | #include <linux/cdev.h> |
| 15 | #include <sound/pcm.h> |
| 16 | #include <sound/pcm_params.h> |
| 17 | #include <sound/soc.h> |
| 18 | #include <sound/tlv.h> |
| 19 | #include "max98388.h" |
| 20 | |
| 21 | static const struct reg_default max98388_reg[] = { |
| 22 | {MAX98388_R2000_SW_RESET, 0x00}, |
| 23 | {MAX98388_R2001_INT_RAW1, 0x00}, |
| 24 | {MAX98388_R2002_INT_RAW2, 0x00}, |
| 25 | {MAX98388_R2004_INT_STATE1, 0x00}, |
| 26 | {MAX98388_R2005_INT_STATE2, 0x00}, |
| 27 | {MAX98388_R2020_THERM_WARN_THRESH, 0x0A}, |
| 28 | {MAX98388_R2031_SPK_MON_THRESH, 0x58}, |
| 29 | {MAX98388_R2032_SPK_MON_LD_SEL, 0x08}, |
| 30 | {MAX98388_R2033_SPK_MON_DURATION, 0x02}, |
| 31 | {MAX98388_R2037_ERR_MON_CTRL, 0x01}, |
| 32 | {MAX98388_R2040_PCM_MODE_CFG, 0xC0}, |
| 33 | {MAX98388_R2041_PCM_CLK_SETUP, 0x04}, |
| 34 | {MAX98388_R2042_PCM_SR_SETUP, 0x88}, |
| 35 | {MAX98388_R2044_PCM_TX_CTRL1, 0x00}, |
| 36 | {MAX98388_R2045_PCM_TX_CTRL2, 0x00}, |
| 37 | {MAX98388_R2050_PCM_TX_HIZ_CTRL1, 0xFF}, |
| 38 | {MAX98388_R2051_PCM_TX_HIZ_CTRL2, 0xFF}, |
| 39 | {MAX98388_R2052_PCM_TX_HIZ_CTRL3, 0xFF}, |
| 40 | {MAX98388_R2053_PCM_TX_HIZ_CTRL4, 0xFF}, |
| 41 | {MAX98388_R2054_PCM_TX_HIZ_CTRL5, 0xFF}, |
| 42 | {MAX98388_R2055_PCM_TX_HIZ_CTRL6, 0xFF}, |
| 43 | {MAX98388_R2056_PCM_TX_HIZ_CTRL7, 0xFF}, |
| 44 | {MAX98388_R2057_PCM_TX_HIZ_CTRL8, 0xFF}, |
| 45 | {MAX98388_R2058_PCM_RX_SRC1, 0x00}, |
| 46 | {MAX98388_R2059_PCM_RX_SRC2, 0x01}, |
| 47 | {MAX98388_R205C_PCM_TX_DRIVE_STRENGTH, 0x00}, |
| 48 | {MAX98388_R205D_PCM_TX_SRC_EN, 0x00}, |
| 49 | {MAX98388_R205E_PCM_RX_EN, 0x00}, |
| 50 | {MAX98388_R205F_PCM_TX_EN, 0x00}, |
| 51 | {MAX98388_R2090_SPK_CH_VOL_CTRL, 0x00}, |
| 52 | {MAX98388_R2091_SPK_CH_CFG, 0x02}, |
| 53 | {MAX98388_R2092_SPK_AMP_OUT_CFG, 0x03}, |
| 54 | {MAX98388_R2093_SPK_AMP_SSM_CFG, 0x01}, |
| 55 | {MAX98388_R2094_SPK_AMP_ER_CTRL, 0x00}, |
| 56 | {MAX98388_R209E_SPK_CH_PINK_NOISE_EN, 0x00}, |
| 57 | {MAX98388_R209F_SPK_CH_AMP_EN, 0x00}, |
| 58 | {MAX98388_R20A0_IV_DATA_DSP_CTRL, 0x10}, |
| 59 | {MAX98388_R20A7_IV_DATA_EN, 0x00}, |
| 60 | {MAX98388_R20E0_BP_ALC_THRESH, 0x04}, |
| 61 | {MAX98388_R20E1_BP_ALC_RATES, 0x20}, |
| 62 | {MAX98388_R20E2_BP_ALC_ATTEN, 0x06}, |
| 63 | {MAX98388_R20E3_BP_ALC_REL, 0x02}, |
| 64 | {MAX98388_R20E4_BP_ALC_MUTE, 0x33}, |
| 65 | {MAX98388_R20EE_BP_INF_HOLD_REL, 0x00}, |
| 66 | {MAX98388_R20EF_BP_ALC_EN, 0x00}, |
| 67 | {MAX98388_R210E_AUTO_RESTART, 0x00}, |
| 68 | {MAX98388_R210F_GLOBAL_EN, 0x00}, |
| 69 | {MAX98388_R22FF_REV_ID, 0x00}, |
| 70 | }; |
| 71 | |
| 72 | static int max98388_dac_event(struct snd_soc_dapm_widget *w, |
| 73 | struct snd_kcontrol *kcontrol, int event) |
| 74 | { |
| 75 | struct snd_soc_component *component = snd_soc_dapm_to_component(dapm: w->dapm); |
| 76 | struct max98388_priv *max98388 = snd_soc_component_get_drvdata(c: component); |
| 77 | |
| 78 | switch (event) { |
| 79 | case SND_SOC_DAPM_POST_PMU: |
| 80 | regmap_write(map: max98388->regmap, |
| 81 | MAX98388_R210F_GLOBAL_EN, val: 1); |
| 82 | usleep_range(min: 30000, max: 31000); |
| 83 | break; |
| 84 | case SND_SOC_DAPM_PRE_PMD: |
| 85 | regmap_write(map: max98388->regmap, |
| 86 | MAX98388_R210F_GLOBAL_EN, val: 0); |
| 87 | usleep_range(min: 30000, max: 31000); |
| 88 | max98388->tdm_mode = false; |
| 89 | break; |
| 90 | default: |
| 91 | return 0; |
| 92 | } |
| 93 | return 0; |
| 94 | } |
| 95 | |
| 96 | static const char * const max98388_monomix_switch_text[] = { |
| 97 | "Left" , "Right" , "LeftRight" }; |
| 98 | |
| 99 | static const struct soc_enum dai_sel_enum = |
| 100 | SOC_ENUM_SINGLE(MAX98388_R2058_PCM_RX_SRC1, |
| 101 | MAX98388_PCM_TO_SPK_MONOMIX_CFG_SHIFT, |
| 102 | 3, max98388_monomix_switch_text); |
| 103 | |
| 104 | static const struct snd_kcontrol_new max98388_dai_controls = |
| 105 | SOC_DAPM_ENUM("DAI Sel" , dai_sel_enum); |
| 106 | |
| 107 | static const struct snd_kcontrol_new max98388_vi_control = |
| 108 | SOC_DAPM_SINGLE("Switch" , MAX98388_R205F_PCM_TX_EN, 0, 1, 0); |
| 109 | |
| 110 | static const struct snd_soc_dapm_widget max98388_dapm_widgets[] = { |
| 111 | SND_SOC_DAPM_DAC_E("Amp Enable" , "HiFi Playback" , |
| 112 | MAX98388_R205E_PCM_RX_EN, 0, 0, max98388_dac_event, |
| 113 | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), |
| 114 | SND_SOC_DAPM_MUX("DAI Sel Mux" , SND_SOC_NOPM, 0, 0, |
| 115 | &max98388_dai_controls), |
| 116 | SND_SOC_DAPM_OUTPUT("BE_OUT" ), |
| 117 | SND_SOC_DAPM_AIF_OUT("Voltage Sense" , "HiFi Capture" , 0, |
| 118 | MAX98388_R20A7_IV_DATA_EN, 0, 0), |
| 119 | SND_SOC_DAPM_AIF_OUT("Current Sense" , "HiFi Capture" , 0, |
| 120 | MAX98388_R20A7_IV_DATA_EN, 1, 0), |
| 121 | SND_SOC_DAPM_ADC("ADC Voltage" , NULL, |
| 122 | MAX98388_R205D_PCM_TX_SRC_EN, 0, 0), |
| 123 | SND_SOC_DAPM_ADC("ADC Current" , NULL, |
| 124 | MAX98388_R205D_PCM_TX_SRC_EN, 1, 0), |
| 125 | SND_SOC_DAPM_SWITCH("VI Sense" , SND_SOC_NOPM, 0, 0, |
| 126 | &max98388_vi_control), |
| 127 | SND_SOC_DAPM_SIGGEN("VMON" ), |
| 128 | SND_SOC_DAPM_SIGGEN("IMON" ), |
| 129 | }; |
| 130 | |
| 131 | static DECLARE_TLV_DB_SCALE(max98388_digital_tlv, -6350, 50, 1); |
| 132 | static DECLARE_TLV_DB_SCALE(max98388_amp_gain_tlv, -300, 300, 0); |
| 133 | |
| 134 | static const char * const max98388_alc_max_atten_text[] = { |
| 135 | "0dBFS" , "-1dBFS" , "-2dBFS" , "-3dBFS" , "-4dBFS" , "-5dBFS" , |
| 136 | "-6dBFS" , "-7dBFS" , "-8dBFS" , "-9dBFS" , "-10dBFS" , "-11dBFS" , |
| 137 | "-12dBFS" , "-13dBFS" , "-14dBFS" , "-15dBFS" |
| 138 | }; |
| 139 | |
| 140 | static SOC_ENUM_SINGLE_DECL(max98388_alc_max_atten_enum, |
| 141 | MAX98388_R20E2_BP_ALC_ATTEN, |
| 142 | MAX98388_ALC_MAX_ATTEN_SHIFT, |
| 143 | max98388_alc_max_atten_text); |
| 144 | |
| 145 | static const char * const max98388_thermal_warn_text[] = { |
| 146 | "95C" , "105C" , "115C" , "125C" |
| 147 | }; |
| 148 | |
| 149 | static SOC_ENUM_SINGLE_DECL(max98388_thermal_warning_thresh_enum, |
| 150 | MAX98388_R2020_THERM_WARN_THRESH, |
| 151 | MAX98388_THERM_WARN_THRESH_SHIFT, |
| 152 | max98388_thermal_warn_text); |
| 153 | |
| 154 | static const char * const max98388_thermal_shutdown_text[] = { |
| 155 | "135C" , "145C" , "155C" , "165C" |
| 156 | }; |
| 157 | |
| 158 | static SOC_ENUM_SINGLE_DECL(max98388_thermal_shutdown_thresh_enum, |
| 159 | MAX98388_R2020_THERM_WARN_THRESH, |
| 160 | MAX98388_THERM_SHDN_THRESH_SHIFT, |
| 161 | max98388_thermal_shutdown_text); |
| 162 | |
| 163 | static const char * const max98388_alc_thresh_single_text[] = { |
| 164 | "3.625V" , "3.550V" , "3.475V" , "3.400V" , "3.325V" , "3.250V" , |
| 165 | "3.175V" , "3.100V" , "3.025V" , "2.950V" , "2.875V" , "2.800V" , |
| 166 | "2.725V" , "2.650V" , "2.575V" , "2.500V" |
| 167 | }; |
| 168 | |
| 169 | static SOC_ENUM_SINGLE_DECL(max98388_alc_thresh_single_enum, |
| 170 | MAX98388_R20E0_BP_ALC_THRESH, |
| 171 | MAX98388_ALC_THRESH_SHIFT, |
| 172 | max98388_alc_thresh_single_text); |
| 173 | |
| 174 | static const char * const max98388_alc_attack_rate_text[] = { |
| 175 | "0" , "10us" , "20us" , "40us" , "80us" , "160us" , |
| 176 | "320us" , "640us" , "1.28ms" , "2.56ms" , "5.12ms" , "10.24ms" , |
| 177 | "20.48ms" , "40.96ms" , "81.92ms" , "163.84ms" |
| 178 | }; |
| 179 | |
| 180 | static SOC_ENUM_SINGLE_DECL(max98388_alc_attack_rate_enum, |
| 181 | MAX98388_R20E1_BP_ALC_RATES, |
| 182 | MAX98388_ALC_ATTACK_RATE_SHIFT, |
| 183 | max98388_alc_attack_rate_text); |
| 184 | |
| 185 | static const char * const max98388_alc_release_rate_text[] = { |
| 186 | "20us" , "40us" , "80us" , "160us" , "320us" , "640us" , |
| 187 | "1.28ms" , "2.56ms" , "5.12ms" , "10.24ms" , "20.48ms" , "40.96ms" , |
| 188 | "81.92ms" , "163.84ms" , "327.68ms" , "655.36ms" |
| 189 | }; |
| 190 | |
| 191 | static SOC_ENUM_SINGLE_DECL(max98388_alc_release_rate_enum, |
| 192 | MAX98388_R20E1_BP_ALC_RATES, |
| 193 | MAX98388_ALC_RELEASE_RATE_SHIFT, |
| 194 | max98388_alc_release_rate_text); |
| 195 | |
| 196 | static const char * const max98388_alc_debounce_text[] = { |
| 197 | "0.01ms" , "0.1ms" , "1ms" , "10ms" , "100ms" , "250ms" , "500ms" , "hold" |
| 198 | }; |
| 199 | |
| 200 | static SOC_ENUM_SINGLE_DECL(max98388_alc_debouce_enum, |
| 201 | MAX98388_R20E3_BP_ALC_REL, |
| 202 | MAX98388_ALC_DEBOUNCE_TIME_SHIFT, |
| 203 | max98388_alc_debounce_text); |
| 204 | |
| 205 | static const char * const max98388_alc_mute_delay_text[] = { |
| 206 | "0.01ms" , "0.05ms" , "0.1ms" , "0.5ms" , "1ms" , "5ms" , "25ms" , "250ms" |
| 207 | }; |
| 208 | |
| 209 | static SOC_ENUM_SINGLE_DECL(max98388_alc_mute_delay_enum, |
| 210 | MAX98388_R20E4_BP_ALC_MUTE, |
| 211 | MAX98388_ALC_MUTE_DELAY_SHIFT, |
| 212 | max98388_alc_mute_delay_text); |
| 213 | |
| 214 | static const char * const max98388_spkmon_duration_text[] = { |
| 215 | "10ms" , "25ms" , "50ms" , "75ms" , "100ms" , "200ms" , "300ms" , "400ms" , |
| 216 | "500ms" , "600ms" , "700ms" , "800ms" , "900ms" , "1000ms" , "1100ms" , "1200ms" |
| 217 | }; |
| 218 | |
| 219 | static SOC_ENUM_SINGLE_DECL(max98388_spkmon_duration_enum, |
| 220 | MAX98388_R2033_SPK_MON_DURATION, |
| 221 | MAX98388_SPKMON_DURATION_SHIFT, |
| 222 | max98388_spkmon_duration_text); |
| 223 | |
| 224 | static const char * const max98388_spkmon_thresh_text[] = { |
| 225 | "0.03V" , "0.06V" , "0.09V" , "0.12V" , "0.15V" , "0.18V" , "0.20V" , "0.23V" , |
| 226 | "0.26V" , "0.29V" , "0.32V" , "0.35V" , "0.38V" , "0.41V" , "0.44V" , "0.47V" , |
| 227 | "0.50V" , "0.53V" , "0.56V" , "0.58V" , "0.61V" , "0.64V" , "0.67V" , "0.70V" , |
| 228 | "0.73V" , "0.76V" , "0.79V" , "0.82V" , "0.85V" , "0.88V" , "0.91V" , "0.94V" , |
| 229 | "0.96V" , "0.99V" , "1.02V" , "1.05V" , "1.08V" , "1.11V" , "1.14V" , "1.17V" , |
| 230 | "1.20V" , "1.23V" , "1.26V" , "1.29V" , "1.32V" , "1.35V" , "1.37V" , "1.40V" , |
| 231 | "1.43V" , "1.46V" , "1.49V" , "1.52V" , "1.55V" , "1.58V" , "1.61V" , "1.64V" , |
| 232 | "1.67V" , "1.70V" , "1.73V" , "1.75V" , "1.78V" , "1.81V" , "1.84V" , "1.87V" , |
| 233 | "1.90V" , "1.93V" , "1.96V" , "1.99V" , "2.02V" , "2.05V" , "2.08V" , "2.11V" , |
| 234 | "2.13V" , "2.16V" , "2.19V" , "2.22V" , "2.25V" , "2.28V" , "2.31V" , "2.34V" , |
| 235 | "2.37V" , "2.40V" , "2.43V" , "2.46V" , "2.49V" , "2.51V" , "2.54V" , "2.57V" , |
| 236 | "2.60V" , "2.63V" , "2.66V" , "2.69V" , "2.72V" , "2.75V" , "2.78V" , "2.81V" , |
| 237 | "2.84V" , "2.87V" , "2.89V" , "2.92V" , "2.95V" , "2.98V" , "3.01V" , "3.04V" , |
| 238 | "3.07V" , "3.10V" , "3.13V" , "3.16V" , "3.19V" , "3.22V" , "3.25V" , "3.27V" , |
| 239 | "3.30V" , "3.33V" , "3.36V" , "3.39V" , "3.42V" , "3.45V" , "3.48V" , "3.51V" , |
| 240 | "3.54V" , "3.57V" , "3.60V" , "3.63V" , "3.66V" , "3.68V" , "3.71V" , "3.74V" |
| 241 | }; |
| 242 | |
| 243 | static SOC_ENUM_SINGLE_DECL(max98388_spkmon_thresh_enum, |
| 244 | MAX98388_R2031_SPK_MON_THRESH, |
| 245 | MAX98388_SPKMON_THRESH_SHIFT, |
| 246 | max98388_spkmon_thresh_text); |
| 247 | |
| 248 | static const char * const max98388_spkmon_load_text[] = { |
| 249 | "2.00ohm" , "2.25ohm" , "2.50ohm" , "2.75ohm" , "3.00ohm" , "3.25ohm" , |
| 250 | "3.50ohm" , "3.75ohm" , "4.00ohm" , "4.25ohm" , "4.50ohm" , "4.75ohm" , |
| 251 | "5.00ohm" , "5.25ohm" , "5.50ohm" , "5.75ohm" , "6.00ohm" , "6.25ohm" , |
| 252 | "6.50ohm" , "6.75ohm" , "7.00ohm" , "7.25ohm" , "7.50ohm" , "7.75ohm" , |
| 253 | "8.00ohm" , "8.25ohm" , "8.50ohm" , "8.75ohm" , "9.00ohm" , "9.25ohm" , |
| 254 | "9.50ohm" , "9.75ohm" , "10.00ohm" , "10.25ohm" , "10.50ohm" , "10.75ohm" , |
| 255 | "11.00ohm" , "11.25ohm" , "11.50ohm" , "11.75ohm" , "12.00ohm" , "12.25ohm" , |
| 256 | "12.50ohm" , "12.75ohm" , "13.00ohm" , "13.25ohm" , "13.50ohm" , "13.75ohm" , |
| 257 | "14.00ohm" , "14.25ohm" , "14.50ohm" , "14.75ohm" , "15.00ohm" , "15.25ohm" , |
| 258 | "15.50ohm" , "15.75ohm" , "16.00ohm" , "16.25ohm" , "16.50ohm" , "16.75ohm" , |
| 259 | "17.00ohm" , "17.25ohm" , "17.50ohm" , "17.75ohm" , "18.00ohm" , "18.25ohm" , |
| 260 | "18.50ohm" , "18.75ohm" , "19.00ohm" , "19.25ohm" , "19.50ohm" , "19.75ohm" , |
| 261 | "20.00ohm" , "20.25ohm" , "20.50ohm" , "20.75ohm" , "21.00ohm" , "21.25ohm" , |
| 262 | "21.50ohm" , "21.75ohm" , "22.00ohm" , "22.25ohm" , "22.50ohm" , "22.75ohm" , |
| 263 | "23.00ohm" , "23.25ohm" , "23.50ohm" , "23.75ohm" , "24.00ohm" , "24.25ohm" , |
| 264 | "24.50ohm" , "24.75ohm" , "25.00ohm" , "25.25ohm" , "25.50ohm" , "25.75ohm" , |
| 265 | "26.00ohm" , "26.25ohm" , "26.50ohm" , "26.75ohm" , "27.00ohm" , "27.25ohm" , |
| 266 | "27.50ohm" , "27.75ohm" , "28.00ohm" , "28.25ohm" , "28.50ohm" , "28.75ohm" , |
| 267 | "29.00ohm" , "29.25ohm" , "29.50ohm" , "29.75ohm" , "30.00ohm" , "30.25ohm" , |
| 268 | "30.50ohm" , "30.75ohm" , "31.00ohm" , "31.25ohm" , "31.50ohm" , "31.75ohm" , |
| 269 | "32.00ohm" , "32.25ohm" , "32.50ohm" , "32.75ohm" , "33.00ohm" , "33.25ohm" , |
| 270 | "33.50ohm" , "33.75ohm" |
| 271 | }; |
| 272 | |
| 273 | static SOC_ENUM_SINGLE_DECL(max98388_spkmon_load_enum, |
| 274 | MAX98388_R2032_SPK_MON_LD_SEL, |
| 275 | MAX98388_SPKMON_LOAD_SHIFT, |
| 276 | max98388_spkmon_load_text); |
| 277 | |
| 278 | static const char * const max98388_edge_rate_text[] = { |
| 279 | "Normal" , "Reduced" , "Maximum" , "Increased" , |
| 280 | }; |
| 281 | |
| 282 | static SOC_ENUM_SINGLE_DECL(max98388_edge_rate_falling_enum, |
| 283 | MAX98388_R2094_SPK_AMP_ER_CTRL, |
| 284 | MAX98388_EDGE_RATE_FALL_SHIFT, |
| 285 | max98388_edge_rate_text); |
| 286 | |
| 287 | static SOC_ENUM_SINGLE_DECL(max98388_edge_rate_rising_enum, |
| 288 | MAX98388_R2094_SPK_AMP_ER_CTRL, |
| 289 | MAX98388_EDGE_RATE_RISE_SHIFT, |
| 290 | max98388_edge_rate_text); |
| 291 | |
| 292 | static const char * const max98388_ssm_mod_text[] = { |
| 293 | "1.5%" , "3.0%" , "4.5%" , "6.0%" , |
| 294 | }; |
| 295 | |
| 296 | static SOC_ENUM_SINGLE_DECL(max98388_ssm_mod_enum, |
| 297 | MAX98388_R2093_SPK_AMP_SSM_CFG, |
| 298 | MAX98388_SPK_AMP_SSM_MOD_SHIFT, |
| 299 | max98388_ssm_mod_text); |
| 300 | |
| 301 | static const struct snd_kcontrol_new max98388_snd_controls[] = { |
| 302 | SOC_SINGLE("Ramp Up Switch" , MAX98388_R2091_SPK_CH_CFG, |
| 303 | MAX98388_SPK_CFG_VOL_RMPUP_SHIFT, 1, 0), |
| 304 | SOC_SINGLE("Ramp Down Switch" , MAX98388_R2091_SPK_CH_CFG, |
| 305 | MAX98388_SPK_CFG_VOL_RMPDN_SHIFT, 1, 0), |
| 306 | /* Two Cell Mode Enable */ |
| 307 | SOC_SINGLE("OP Mode Switch" , MAX98388_R2092_SPK_AMP_OUT_CFG, |
| 308 | MAX98388_SPK_AMP_OUT_MODE_SHIFT, 1, 0), |
| 309 | /* Speaker Amplifier Overcurrent Automatic Restart Enable */ |
| 310 | SOC_SINGLE("OVC Autorestart Switch" , MAX98388_R210E_AUTO_RESTART, |
| 311 | MAX98388_OVC_AUTORESTART_SHIFT, 1, 0), |
| 312 | /* Thermal Shutdown Automatic Restart Enable */ |
| 313 | SOC_SINGLE("THERM Autorestart Switch" , MAX98388_R210E_AUTO_RESTART, |
| 314 | MAX98388_THERM_AUTORESTART_SHIFT, 1, 0), |
| 315 | /* PVDD UVLO Auto Restart */ |
| 316 | SOC_SINGLE("UVLO Autorestart Switch" , MAX98388_R210E_AUTO_RESTART, |
| 317 | MAX98388_PVDD_UVLO_AUTORESTART_SHIFT, 1, 0), |
| 318 | /* Clock Monitor Automatic Restart Enable */ |
| 319 | SOC_SINGLE("CMON Autorestart Switch" , MAX98388_R210E_AUTO_RESTART, |
| 320 | MAX98388_CMON_AUTORESTART_SHIFT, 1, 0), |
| 321 | SOC_SINGLE("CLK Monitor Switch" , MAX98388_R2037_ERR_MON_CTRL, |
| 322 | MAX98388_CLOCK_MON_SHIFT, 1, 0), |
| 323 | /* Pinknoise Generator Enable */ |
| 324 | SOC_SINGLE("Pinknoise Gen Switch" , MAX98388_R209E_SPK_CH_PINK_NOISE_EN, |
| 325 | MAX98388_PINK_NOISE_GEN_SHIFT, 1, 0), |
| 326 | /* Dither Enable */ |
| 327 | SOC_SINGLE("Dither Switch" , MAX98388_R2091_SPK_CH_CFG, |
| 328 | MAX98388_SPK_CFG_DITH_EN_SHIFT, 1, 0), |
| 329 | SOC_SINGLE("VI Dither Switch" , MAX98388_R20A0_IV_DATA_DSP_CTRL, |
| 330 | MAX98388_AMP_DSP_CTRL_DITH_SHIFT, 1, 0), |
| 331 | /* DC Blocker Enable */ |
| 332 | SOC_SINGLE("DC Blocker Switch" , MAX98388_R2091_SPK_CH_CFG, |
| 333 | MAX98388_SPK_CFG_DCBLK_SHIFT, 1, 0), |
| 334 | SOC_SINGLE("Voltage DC Blocker Switch" , MAX98388_R20A0_IV_DATA_DSP_CTRL, |
| 335 | MAX98388_AMP_DSP_CTRL_VOL_DCBLK_SHIFT, 1, 0), |
| 336 | SOC_SINGLE("Current DC Blocker Switch" , MAX98388_R20A0_IV_DATA_DSP_CTRL, |
| 337 | MAX98388_AMP_DSP_CTRL_CUR_DCBLK_SHIFT, 1, 0), |
| 338 | /* Digital Volume */ |
| 339 | SOC_SINGLE_TLV("Digital Volume" , MAX98388_R2090_SPK_CH_VOL_CTRL, |
| 340 | 0, 0x7F, 1, max98388_digital_tlv), |
| 341 | /* Speaker Volume */ |
| 342 | SOC_SINGLE_TLV("Speaker Volume" , MAX98388_R2092_SPK_AMP_OUT_CFG, |
| 343 | 0, 5, 0, max98388_amp_gain_tlv), |
| 344 | SOC_ENUM("Thermal Warn Thresh" , max98388_thermal_warning_thresh_enum), |
| 345 | SOC_ENUM("Thermal SHDN Thresh" , max98388_thermal_shutdown_thresh_enum), |
| 346 | /* Brownout Protection Automatic Level Control */ |
| 347 | SOC_SINGLE("ALC Switch" , MAX98388_R20EF_BP_ALC_EN, 0, 1, 0), |
| 348 | SOC_ENUM("ALC Thresh" , max98388_alc_thresh_single_enum), |
| 349 | SOC_ENUM("ALC Attack Rate" , max98388_alc_attack_rate_enum), |
| 350 | SOC_ENUM("ALC Release Rate" , max98388_alc_release_rate_enum), |
| 351 | SOC_ENUM("ALC Max Atten" , max98388_alc_max_atten_enum), |
| 352 | SOC_ENUM("ALC Debounce Time" , max98388_alc_debouce_enum), |
| 353 | SOC_SINGLE("ALC Unmute Ramp Switch" , MAX98388_R20E4_BP_ALC_MUTE, |
| 354 | MAX98388_ALC_UNMUTE_RAMP_EN_SHIFT, 1, 0), |
| 355 | SOC_SINGLE("ALC Mute Ramp Switch" , MAX98388_R20E4_BP_ALC_MUTE, |
| 356 | MAX98388_ALC_MUTE_RAMP_EN_SHIFT, 1, 0), |
| 357 | SOC_SINGLE("ALC Mute Switch" , MAX98388_R20E4_BP_ALC_MUTE, |
| 358 | MAX98388_ALC_MUTE_EN_SHIFT, 1, 0), |
| 359 | SOC_ENUM("ALC Mute Delay" , max98388_alc_mute_delay_enum), |
| 360 | /* Speaker Monitor */ |
| 361 | SOC_SINGLE("SPKMON Switch" , MAX98388_R2037_ERR_MON_CTRL, |
| 362 | MAX98388_SPK_MON_SHIFT, 1, 0), |
| 363 | SOC_ENUM("SPKMON Thresh" , max98388_spkmon_thresh_enum), |
| 364 | SOC_ENUM("SPKMON Load" , max98388_spkmon_load_enum), |
| 365 | SOC_ENUM("SPKMON Duration" , max98388_spkmon_duration_enum), |
| 366 | /* General Parameters */ |
| 367 | SOC_ENUM("Fall Slew Rate" , max98388_edge_rate_falling_enum), |
| 368 | SOC_ENUM("Rise Slew Rate" , max98388_edge_rate_rising_enum), |
| 369 | SOC_SINGLE("AMP SSM Switch" , MAX98388_R2093_SPK_AMP_SSM_CFG, |
| 370 | MAX98388_SPK_AMP_SSM_EN_SHIFT, 1, 0), |
| 371 | SOC_ENUM("AMP SSM Mod" , max98388_ssm_mod_enum), |
| 372 | }; |
| 373 | |
| 374 | static const struct snd_soc_dapm_route max98388_audio_map[] = { |
| 375 | /* Plabyack */ |
| 376 | {"DAI Sel Mux" , "Left" , "Amp Enable" }, |
| 377 | {"DAI Sel Mux" , "Right" , "Amp Enable" }, |
| 378 | {"DAI Sel Mux" , "LeftRight" , "Amp Enable" }, |
| 379 | {"BE_OUT" , NULL, "DAI Sel Mux" }, |
| 380 | /* Capture */ |
| 381 | { "ADC Voltage" , NULL, "VMON" }, |
| 382 | { "ADC Current" , NULL, "IMON" }, |
| 383 | { "VI Sense" , "Switch" , "ADC Voltage" }, |
| 384 | { "VI Sense" , "Switch" , "ADC Current" }, |
| 385 | { "Voltage Sense" , NULL, "VI Sense" }, |
| 386 | { "Current Sense" , NULL, "VI Sense" }, |
| 387 | }; |
| 388 | |
| 389 | static void max98388_reset(struct max98388_priv *max98388, struct device *dev) |
| 390 | { |
| 391 | int ret, reg, count; |
| 392 | |
| 393 | /* Software Reset */ |
| 394 | ret = regmap_update_bits(map: max98388->regmap, |
| 395 | MAX98388_R2000_SW_RESET, |
| 396 | MAX98388_SOFT_RESET, |
| 397 | MAX98388_SOFT_RESET); |
| 398 | if (ret) |
| 399 | dev_err(dev, "Reset command failed. (ret:%d)\n" , ret); |
| 400 | |
| 401 | count = 0; |
| 402 | while (count < 3) { |
| 403 | usleep_range(min: 10000, max: 11000); |
| 404 | /* Software Reset Verification */ |
| 405 | ret = regmap_read(map: max98388->regmap, |
| 406 | MAX98388_R22FF_REV_ID, val: ®); |
| 407 | if (!ret) { |
| 408 | dev_info(dev, "Reset completed (retry:%d)\n" , count); |
| 409 | return; |
| 410 | } |
| 411 | count++; |
| 412 | } |
| 413 | dev_err(dev, "Reset failed. (ret:%d)\n" , ret); |
| 414 | } |
| 415 | |
| 416 | static int max98388_probe(struct snd_soc_component *component) |
| 417 | { |
| 418 | struct max98388_priv *max98388 = snd_soc_component_get_drvdata(c: component); |
| 419 | |
| 420 | /* Software Reset */ |
| 421 | max98388_reset(max98388, dev: component->dev); |
| 422 | |
| 423 | /* General channel source configuration */ |
| 424 | regmap_write(map: max98388->regmap, |
| 425 | MAX98388_R2059_PCM_RX_SRC2, |
| 426 | val: 0x10); |
| 427 | |
| 428 | /* Enable DC blocker */ |
| 429 | regmap_write(map: max98388->regmap, |
| 430 | MAX98388_R2091_SPK_CH_CFG, |
| 431 | val: 0x1); |
| 432 | /* Enable IMON VMON DC blocker */ |
| 433 | regmap_write(map: max98388->regmap, |
| 434 | MAX98388_R20A0_IV_DATA_DSP_CTRL, |
| 435 | val: 0x3); |
| 436 | /* TX slot configuration */ |
| 437 | regmap_write(map: max98388->regmap, |
| 438 | MAX98388_R2044_PCM_TX_CTRL1, |
| 439 | val: max98388->v_slot); |
| 440 | |
| 441 | regmap_write(map: max98388->regmap, |
| 442 | MAX98388_R2045_PCM_TX_CTRL2, |
| 443 | val: max98388->i_slot); |
| 444 | /* Enable Auto-restart behavior by default */ |
| 445 | regmap_write(map: max98388->regmap, |
| 446 | MAX98388_R210E_AUTO_RESTART, val: 0xF); |
| 447 | /* Set interleave mode */ |
| 448 | if (max98388->interleave_mode) |
| 449 | regmap_update_bits(map: max98388->regmap, |
| 450 | MAX98388_R2040_PCM_MODE_CFG, |
| 451 | MAX98388_PCM_TX_CH_INTERLEAVE_MASK, |
| 452 | MAX98388_PCM_TX_CH_INTERLEAVE_MASK); |
| 453 | |
| 454 | /* Speaker Amplifier Channel Enable */ |
| 455 | regmap_update_bits(map: max98388->regmap, |
| 456 | MAX98388_R209F_SPK_CH_AMP_EN, |
| 457 | MAX98388_SPK_EN_MASK, val: 1); |
| 458 | |
| 459 | return 0; |
| 460 | } |
| 461 | |
| 462 | static int max98388_dai_set_fmt(struct snd_soc_dai *codec_dai, |
| 463 | unsigned int fmt) |
| 464 | { |
| 465 | struct snd_soc_component *component = codec_dai->component; |
| 466 | struct max98388_priv *max98388 = snd_soc_component_get_drvdata(c: component); |
| 467 | unsigned int format = 0; |
| 468 | unsigned int invert = 0; |
| 469 | |
| 470 | dev_dbg(component->dev, "%s: fmt 0x%08X\n" , __func__, fmt); |
| 471 | |
| 472 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { |
| 473 | case SND_SOC_DAIFMT_NB_NF: |
| 474 | break; |
| 475 | case SND_SOC_DAIFMT_IB_NF: |
| 476 | invert = MAX98388_PCM_MODE_CFG_PCM_BCLKEDGE; |
| 477 | break; |
| 478 | default: |
| 479 | dev_err(component->dev, "DAI invert mode unsupported\n" ); |
| 480 | return -EINVAL; |
| 481 | } |
| 482 | |
| 483 | regmap_update_bits(map: max98388->regmap, |
| 484 | MAX98388_R2041_PCM_CLK_SETUP, |
| 485 | MAX98388_PCM_MODE_CFG_PCM_BCLKEDGE, |
| 486 | val: invert); |
| 487 | |
| 488 | /* interface format */ |
| 489 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { |
| 490 | case SND_SOC_DAIFMT_I2S: |
| 491 | format = MAX98388_PCM_FORMAT_I2S; |
| 492 | break; |
| 493 | case SND_SOC_DAIFMT_LEFT_J: |
| 494 | format = MAX98388_PCM_FORMAT_LJ; |
| 495 | break; |
| 496 | case SND_SOC_DAIFMT_DSP_A: |
| 497 | format = MAX98388_PCM_FORMAT_TDM_MODE1; |
| 498 | break; |
| 499 | case SND_SOC_DAIFMT_DSP_B: |
| 500 | format = MAX98388_PCM_FORMAT_TDM_MODE0; |
| 501 | break; |
| 502 | default: |
| 503 | return -EINVAL; |
| 504 | } |
| 505 | |
| 506 | regmap_update_bits(map: max98388->regmap, |
| 507 | MAX98388_R2040_PCM_MODE_CFG, |
| 508 | MAX98388_PCM_MODE_CFG_FORMAT_MASK, |
| 509 | val: format << MAX98388_PCM_MODE_CFG_FORMAT_SHIFT); |
| 510 | |
| 511 | return 0; |
| 512 | } |
| 513 | |
| 514 | /* BCLKs per LRCLK */ |
| 515 | static const int bclk_sel_table[] = { |
| 516 | 32, 48, 64, 96, 128, 192, 256, 384, 512, 320, |
| 517 | }; |
| 518 | |
| 519 | static int max98388_get_bclk_sel(int bclk) |
| 520 | { |
| 521 | int i; |
| 522 | /* match BCLKs per LRCLK */ |
| 523 | for (i = 0; i < ARRAY_SIZE(bclk_sel_table); i++) { |
| 524 | if (bclk_sel_table[i] == bclk) |
| 525 | return i + 2; |
| 526 | } |
| 527 | return 0; |
| 528 | } |
| 529 | |
| 530 | static int max98388_set_clock(struct snd_soc_component *component, |
| 531 | struct snd_pcm_hw_params *params) |
| 532 | { |
| 533 | struct max98388_priv *max98388 = snd_soc_component_get_drvdata(c: component); |
| 534 | /* BCLK/LRCLK ratio calculation */ |
| 535 | int blr_clk_ratio = params_channels(p: params) * max98388->ch_size; |
| 536 | int value; |
| 537 | |
| 538 | if (!max98388->tdm_mode) { |
| 539 | /* BCLK configuration */ |
| 540 | value = max98388_get_bclk_sel(bclk: blr_clk_ratio); |
| 541 | if (!value) { |
| 542 | dev_err(component->dev, "format unsupported %d\n" , |
| 543 | params_format(params)); |
| 544 | return -EINVAL; |
| 545 | } |
| 546 | |
| 547 | regmap_update_bits(map: max98388->regmap, |
| 548 | MAX98388_R2041_PCM_CLK_SETUP, |
| 549 | MAX98388_PCM_CLK_SETUP_BSEL_MASK, |
| 550 | val: value); |
| 551 | } |
| 552 | return 0; |
| 553 | } |
| 554 | |
| 555 | static int max98388_dai_hw_params(struct snd_pcm_substream *substream, |
| 556 | struct snd_pcm_hw_params *params, |
| 557 | struct snd_soc_dai *dai) |
| 558 | { |
| 559 | struct snd_soc_component *component = dai->component; |
| 560 | struct max98388_priv *max98388 = snd_soc_component_get_drvdata(c: component); |
| 561 | unsigned int sampling_rate = 0; |
| 562 | unsigned int chan_sz = 0; |
| 563 | int ret, reg; |
| 564 | int status = 0; |
| 565 | |
| 566 | /* pcm mode configuration */ |
| 567 | switch (snd_pcm_format_width(format: params_format(p: params))) { |
| 568 | case 16: |
| 569 | chan_sz = MAX98388_PCM_MODE_CFG_CHANSZ_16; |
| 570 | break; |
| 571 | case 24: |
| 572 | chan_sz = MAX98388_PCM_MODE_CFG_CHANSZ_24; |
| 573 | break; |
| 574 | case 32: |
| 575 | chan_sz = MAX98388_PCM_MODE_CFG_CHANSZ_32; |
| 576 | break; |
| 577 | default: |
| 578 | dev_err(component->dev, "format unsupported %d\n" , |
| 579 | params_format(params)); |
| 580 | goto err; |
| 581 | } |
| 582 | |
| 583 | max98388->ch_size = snd_pcm_format_width(format: params_format(p: params)); |
| 584 | |
| 585 | ret = regmap_read(map: max98388->regmap, |
| 586 | MAX98388_R2040_PCM_MODE_CFG, val: ®); |
| 587 | if (ret < 0) |
| 588 | goto err; |
| 589 | |
| 590 | /* GLOBAL_EN OFF prior to the channel size re-configure */ |
| 591 | if (chan_sz != (reg & MAX98388_PCM_MODE_CFG_CHANSZ_MASK)) { |
| 592 | ret = regmap_read(map: max98388->regmap, |
| 593 | MAX98388_R210F_GLOBAL_EN, val: &status); |
| 594 | if (ret < 0) |
| 595 | goto err; |
| 596 | |
| 597 | if (status) { |
| 598 | regmap_write(map: max98388->regmap, |
| 599 | MAX98388_R210F_GLOBAL_EN, val: 0); |
| 600 | usleep_range(min: 30000, max: 31000); |
| 601 | } |
| 602 | regmap_update_bits(map: max98388->regmap, |
| 603 | MAX98388_R2040_PCM_MODE_CFG, |
| 604 | MAX98388_PCM_MODE_CFG_CHANSZ_MASK, val: chan_sz); |
| 605 | } |
| 606 | dev_dbg(component->dev, "format supported %d" , |
| 607 | params_format(params)); |
| 608 | |
| 609 | /* sampling rate configuration */ |
| 610 | switch (params_rate(p: params)) { |
| 611 | case 8000: |
| 612 | sampling_rate = MAX98388_PCM_SR_8000; |
| 613 | break; |
| 614 | case 11025: |
| 615 | sampling_rate = MAX98388_PCM_SR_11025; |
| 616 | break; |
| 617 | case 12000: |
| 618 | sampling_rate = MAX98388_PCM_SR_12000; |
| 619 | break; |
| 620 | case 16000: |
| 621 | sampling_rate = MAX98388_PCM_SR_16000; |
| 622 | break; |
| 623 | case 22050: |
| 624 | sampling_rate = MAX98388_PCM_SR_22050; |
| 625 | break; |
| 626 | case 24000: |
| 627 | sampling_rate = MAX98388_PCM_SR_24000; |
| 628 | break; |
| 629 | case 32000: |
| 630 | sampling_rate = MAX98388_PCM_SR_32000; |
| 631 | break; |
| 632 | case 44100: |
| 633 | sampling_rate = MAX98388_PCM_SR_44100; |
| 634 | break; |
| 635 | case 48000: |
| 636 | sampling_rate = MAX98388_PCM_SR_48000; |
| 637 | break; |
| 638 | case 88200: |
| 639 | sampling_rate = MAX98388_PCM_SR_88200; |
| 640 | break; |
| 641 | case 96000: |
| 642 | sampling_rate = MAX98388_PCM_SR_96000; |
| 643 | break; |
| 644 | default: |
| 645 | dev_err(component->dev, "rate %d not supported\n" , |
| 646 | params_rate(params)); |
| 647 | goto err; |
| 648 | } |
| 649 | |
| 650 | /* set DAI_SR to correct LRCLK frequency */ |
| 651 | regmap_update_bits(map: max98388->regmap, |
| 652 | MAX98388_R2042_PCM_SR_SETUP, |
| 653 | MAX98388_PCM_SR_MASK, |
| 654 | val: sampling_rate); |
| 655 | |
| 656 | /* set sampling rate of IV */ |
| 657 | if (max98388->interleave_mode && |
| 658 | sampling_rate > MAX98388_PCM_SR_16000) |
| 659 | regmap_update_bits(map: max98388->regmap, |
| 660 | MAX98388_R2042_PCM_SR_SETUP, |
| 661 | MAX98388_PCM_SR_IV_MASK, |
| 662 | val: (sampling_rate - 3) << MAX98388_PCM_SR_IV_SHIFT); |
| 663 | else |
| 664 | regmap_update_bits(map: max98388->regmap, |
| 665 | MAX98388_R2042_PCM_SR_SETUP, |
| 666 | MAX98388_PCM_SR_IV_MASK, |
| 667 | val: sampling_rate << MAX98388_PCM_SR_IV_SHIFT); |
| 668 | |
| 669 | ret = max98388_set_clock(component, params); |
| 670 | |
| 671 | if (status) { |
| 672 | regmap_write(map: max98388->regmap, |
| 673 | MAX98388_R210F_GLOBAL_EN, val: 1); |
| 674 | usleep_range(min: 30000, max: 31000); |
| 675 | } |
| 676 | |
| 677 | return ret; |
| 678 | |
| 679 | err: |
| 680 | return -EINVAL; |
| 681 | } |
| 682 | |
| 683 | #define MAX_NUM_SLOTS 16 |
| 684 | #define MAX_NUM_CH 2 |
| 685 | |
| 686 | static int max98388_dai_tdm_slot(struct snd_soc_dai *dai, |
| 687 | unsigned int tx_mask, unsigned int rx_mask, |
| 688 | int slots, int slot_width) |
| 689 | { |
| 690 | struct snd_soc_component *component = dai->component; |
| 691 | struct max98388_priv *max98388 = snd_soc_component_get_drvdata(c: component); |
| 692 | int bsel = 0; |
| 693 | unsigned int chan_sz = 0; |
| 694 | unsigned int mask; |
| 695 | int cnt, slot_found; |
| 696 | int addr, bits; |
| 697 | |
| 698 | if (!tx_mask && !rx_mask && !slots && !slot_width) |
| 699 | max98388->tdm_mode = false; |
| 700 | else |
| 701 | max98388->tdm_mode = true; |
| 702 | |
| 703 | /* BCLK configuration */ |
| 704 | bsel = max98388_get_bclk_sel(bclk: slots * slot_width); |
| 705 | if (bsel == 0) { |
| 706 | dev_err(component->dev, "BCLK %d not supported\n" , |
| 707 | slots * slot_width); |
| 708 | return -EINVAL; |
| 709 | } |
| 710 | |
| 711 | regmap_update_bits(map: max98388->regmap, |
| 712 | MAX98388_R2041_PCM_CLK_SETUP, |
| 713 | MAX98388_PCM_CLK_SETUP_BSEL_MASK, |
| 714 | val: bsel); |
| 715 | |
| 716 | /* Channel size configuration */ |
| 717 | switch (slot_width) { |
| 718 | case 16: |
| 719 | chan_sz = MAX98388_PCM_MODE_CFG_CHANSZ_16; |
| 720 | break; |
| 721 | case 24: |
| 722 | chan_sz = MAX98388_PCM_MODE_CFG_CHANSZ_24; |
| 723 | break; |
| 724 | case 32: |
| 725 | chan_sz = MAX98388_PCM_MODE_CFG_CHANSZ_32; |
| 726 | break; |
| 727 | default: |
| 728 | dev_err(component->dev, "format unsupported %d\n" , |
| 729 | slot_width); |
| 730 | return -EINVAL; |
| 731 | } |
| 732 | |
| 733 | regmap_update_bits(map: max98388->regmap, |
| 734 | MAX98388_R2040_PCM_MODE_CFG, |
| 735 | MAX98388_PCM_MODE_CFG_CHANSZ_MASK, val: chan_sz); |
| 736 | |
| 737 | /* Rx slot configuration */ |
| 738 | slot_found = 0; |
| 739 | mask = rx_mask; |
| 740 | for (cnt = 0 ; cnt < MAX_NUM_SLOTS ; cnt++, mask >>= 1) { |
| 741 | if (mask & 0x1) { |
| 742 | if (slot_found == 0) |
| 743 | regmap_update_bits(map: max98388->regmap, |
| 744 | MAX98388_R2059_PCM_RX_SRC2, |
| 745 | MAX98388_RX_SRC_CH0_SHIFT, |
| 746 | val: cnt); |
| 747 | else |
| 748 | regmap_update_bits(map: max98388->regmap, |
| 749 | MAX98388_R2059_PCM_RX_SRC2, |
| 750 | MAX98388_RX_SRC_CH1_SHIFT, |
| 751 | val: cnt); |
| 752 | slot_found++; |
| 753 | if (slot_found >= MAX_NUM_CH) |
| 754 | break; |
| 755 | } |
| 756 | } |
| 757 | |
| 758 | /* speaker feedback slot configuration */ |
| 759 | slot_found = 0; |
| 760 | mask = tx_mask; |
| 761 | for (cnt = 0 ; cnt < MAX_NUM_SLOTS ; cnt++, mask >>= 1) { |
| 762 | if (mask & 0x1) { |
| 763 | addr = MAX98388_R2044_PCM_TX_CTRL1 + (cnt / 8); |
| 764 | bits = cnt % 8; |
| 765 | regmap_update_bits(map: max98388->regmap, reg: addr, mask: bits, val: bits); |
| 766 | slot_found++; |
| 767 | if (slot_found >= MAX_NUM_CH) |
| 768 | break; |
| 769 | } |
| 770 | } |
| 771 | |
| 772 | return 0; |
| 773 | } |
| 774 | |
| 775 | #define MAX98388_RATES SNDRV_PCM_RATE_8000_96000 |
| 776 | |
| 777 | #define MAX98388_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ |
| 778 | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) |
| 779 | |
| 780 | static const struct snd_soc_dai_ops max98388_dai_ops = { |
| 781 | .set_fmt = max98388_dai_set_fmt, |
| 782 | .hw_params = max98388_dai_hw_params, |
| 783 | .set_tdm_slot = max98388_dai_tdm_slot, |
| 784 | }; |
| 785 | |
| 786 | static bool max98388_readable_register(struct device *dev, |
| 787 | unsigned int reg) |
| 788 | { |
| 789 | switch (reg) { |
| 790 | case MAX98388_R2001_INT_RAW1 ... MAX98388_R2002_INT_RAW2: |
| 791 | case MAX98388_R2004_INT_STATE1... MAX98388_R2005_INT_STATE2: |
| 792 | case MAX98388_R2020_THERM_WARN_THRESH: |
| 793 | case MAX98388_R2031_SPK_MON_THRESH |
| 794 | ... MAX98388_R2033_SPK_MON_DURATION: |
| 795 | case MAX98388_R2037_ERR_MON_CTRL: |
| 796 | case MAX98388_R2040_PCM_MODE_CFG |
| 797 | ... MAX98388_R2042_PCM_SR_SETUP: |
| 798 | case MAX98388_R2044_PCM_TX_CTRL1 |
| 799 | ... MAX98388_R2045_PCM_TX_CTRL2: |
| 800 | case MAX98388_R2050_PCM_TX_HIZ_CTRL1 |
| 801 | ... MAX98388_R2059_PCM_RX_SRC2: |
| 802 | case MAX98388_R205C_PCM_TX_DRIVE_STRENGTH |
| 803 | ... MAX98388_R205F_PCM_TX_EN: |
| 804 | case MAX98388_R2090_SPK_CH_VOL_CTRL |
| 805 | ... MAX98388_R2094_SPK_AMP_ER_CTRL: |
| 806 | case MAX98388_R209E_SPK_CH_PINK_NOISE_EN |
| 807 | ... MAX98388_R209F_SPK_CH_AMP_EN: |
| 808 | case MAX98388_R20A0_IV_DATA_DSP_CTRL: |
| 809 | case MAX98388_R20A7_IV_DATA_EN: |
| 810 | case MAX98388_R20E0_BP_ALC_THRESH ... MAX98388_R20E4_BP_ALC_MUTE: |
| 811 | case MAX98388_R20EE_BP_INF_HOLD_REL ... MAX98388_R20EF_BP_ALC_EN: |
| 812 | case MAX98388_R210E_AUTO_RESTART: |
| 813 | case MAX98388_R210F_GLOBAL_EN: |
| 814 | case MAX98388_R22FF_REV_ID: |
| 815 | return true; |
| 816 | default: |
| 817 | return false; |
| 818 | } |
| 819 | }; |
| 820 | |
| 821 | static bool max98388_volatile_reg(struct device *dev, unsigned int reg) |
| 822 | { |
| 823 | switch (reg) { |
| 824 | case MAX98388_R2001_INT_RAW1 ... MAX98388_R2005_INT_STATE2: |
| 825 | case MAX98388_R210F_GLOBAL_EN: |
| 826 | case MAX98388_R22FF_REV_ID: |
| 827 | return true; |
| 828 | default: |
| 829 | return false; |
| 830 | } |
| 831 | } |
| 832 | |
| 833 | static struct snd_soc_dai_driver max98388_dai[] = { |
| 834 | { |
| 835 | .name = "max98388-aif1" , |
| 836 | .playback = { |
| 837 | .stream_name = "HiFi Playback" , |
| 838 | .channels_min = 1, |
| 839 | .channels_max = 2, |
| 840 | .rates = MAX98388_RATES, |
| 841 | .formats = MAX98388_FORMATS, |
| 842 | }, |
| 843 | .capture = { |
| 844 | .stream_name = "HiFi Capture" , |
| 845 | .channels_min = 1, |
| 846 | .channels_max = 2, |
| 847 | .rates = MAX98388_RATES, |
| 848 | .formats = MAX98388_FORMATS, |
| 849 | }, |
| 850 | .ops = &max98388_dai_ops, |
| 851 | } |
| 852 | }; |
| 853 | |
| 854 | static int max98388_suspend(struct device *dev) |
| 855 | { |
| 856 | struct max98388_priv *max98388 = dev_get_drvdata(dev); |
| 857 | |
| 858 | regcache_cache_only(map: max98388->regmap, enable: true); |
| 859 | regcache_mark_dirty(map: max98388->regmap); |
| 860 | |
| 861 | return 0; |
| 862 | } |
| 863 | |
| 864 | static int max98388_resume(struct device *dev) |
| 865 | { |
| 866 | struct max98388_priv *max98388 = dev_get_drvdata(dev); |
| 867 | |
| 868 | regcache_cache_only(map: max98388->regmap, enable: false); |
| 869 | max98388_reset(max98388, dev); |
| 870 | regcache_sync(map: max98388->regmap); |
| 871 | |
| 872 | return 0; |
| 873 | } |
| 874 | |
| 875 | static const struct dev_pm_ops max98388_pm = { |
| 876 | SYSTEM_SLEEP_PM_OPS(max98388_suspend, max98388_resume) |
| 877 | }; |
| 878 | |
| 879 | static const struct regmap_config max98388_regmap = { |
| 880 | .reg_bits = 16, |
| 881 | .val_bits = 8, |
| 882 | .max_register = MAX98388_R22FF_REV_ID, |
| 883 | .reg_defaults = max98388_reg, |
| 884 | .num_reg_defaults = ARRAY_SIZE(max98388_reg), |
| 885 | .readable_reg = max98388_readable_register, |
| 886 | .volatile_reg = max98388_volatile_reg, |
| 887 | .cache_type = REGCACHE_RBTREE, |
| 888 | }; |
| 889 | |
| 890 | static const struct snd_soc_component_driver soc_codec_dev_max98388 = { |
| 891 | .probe = max98388_probe, |
| 892 | .controls = max98388_snd_controls, |
| 893 | .num_controls = ARRAY_SIZE(max98388_snd_controls), |
| 894 | .dapm_widgets = max98388_dapm_widgets, |
| 895 | .num_dapm_widgets = ARRAY_SIZE(max98388_dapm_widgets), |
| 896 | .dapm_routes = max98388_audio_map, |
| 897 | .num_dapm_routes = ARRAY_SIZE(max98388_audio_map), |
| 898 | .use_pmdown_time = 1, |
| 899 | .endianness = 1, |
| 900 | }; |
| 901 | |
| 902 | static void max98388_read_deveice_property(struct device *dev, |
| 903 | struct max98388_priv *max98388) |
| 904 | { |
| 905 | int value; |
| 906 | |
| 907 | if (!device_property_read_u32(dev, propname: "adi,vmon-slot-no" , val: &value)) |
| 908 | max98388->v_slot = value & 0xF; |
| 909 | else |
| 910 | max98388->v_slot = 0; |
| 911 | |
| 912 | if (!device_property_read_u32(dev, propname: "adi,imon-slot-no" , val: &value)) |
| 913 | max98388->i_slot = value & 0xF; |
| 914 | else |
| 915 | max98388->i_slot = 1; |
| 916 | |
| 917 | if (device_property_read_bool(dev, propname: "adi,interleave-mode" )) |
| 918 | max98388->interleave_mode = true; |
| 919 | else |
| 920 | max98388->interleave_mode = false; |
| 921 | } |
| 922 | |
| 923 | static int max98388_i2c_probe(struct i2c_client *i2c) |
| 924 | { |
| 925 | int ret = 0; |
| 926 | int reg = 0; |
| 927 | |
| 928 | struct max98388_priv *max98388 = NULL; |
| 929 | |
| 930 | max98388 = devm_kzalloc(dev: &i2c->dev, size: sizeof(*max98388), GFP_KERNEL); |
| 931 | if (!max98388) |
| 932 | return -ENOMEM; |
| 933 | |
| 934 | i2c_set_clientdata(client: i2c, data: max98388); |
| 935 | |
| 936 | /* regmap initialization */ |
| 937 | max98388->regmap = devm_regmap_init_i2c(i2c, &max98388_regmap); |
| 938 | if (IS_ERR(ptr: max98388->regmap)) |
| 939 | return dev_err_probe(dev: &i2c->dev, err: PTR_ERR(ptr: max98388->regmap), |
| 940 | fmt: "Failed to allocate register map.\n" ); |
| 941 | |
| 942 | /* voltage/current slot & gpio configuration */ |
| 943 | max98388_read_deveice_property(dev: &i2c->dev, max98388); |
| 944 | |
| 945 | /* Device Reset */ |
| 946 | max98388->reset_gpio = devm_gpiod_get_optional(dev: &i2c->dev, |
| 947 | con_id: "reset" , flags: GPIOD_OUT_HIGH); |
| 948 | if (IS_ERR(ptr: max98388->reset_gpio)) |
| 949 | return dev_err_probe(dev: &i2c->dev, err: PTR_ERR(ptr: max98388->reset_gpio), |
| 950 | fmt: "Unable to request GPIO\n" ); |
| 951 | |
| 952 | if (max98388->reset_gpio) { |
| 953 | usleep_range(min: 5000, max: 6000); |
| 954 | gpiod_set_value_cansleep(desc: max98388->reset_gpio, value: 0); |
| 955 | /* Wait for the hw reset done */ |
| 956 | usleep_range(min: 5000, max: 6000); |
| 957 | } |
| 958 | |
| 959 | /* Read Revision ID */ |
| 960 | ret = regmap_read(map: max98388->regmap, |
| 961 | MAX98388_R22FF_REV_ID, val: ®); |
| 962 | if (ret < 0) |
| 963 | return dev_err_probe(dev: &i2c->dev, err: ret, |
| 964 | fmt: "Failed to read the revision ID\n" ); |
| 965 | |
| 966 | dev_info(&i2c->dev, "MAX98388 revisionID: 0x%02X\n" , reg); |
| 967 | |
| 968 | /* codec registration */ |
| 969 | ret = devm_snd_soc_register_component(dev: &i2c->dev, |
| 970 | component_driver: &soc_codec_dev_max98388, |
| 971 | dai_drv: max98388_dai, |
| 972 | ARRAY_SIZE(max98388_dai)); |
| 973 | if (ret < 0) |
| 974 | dev_err(&i2c->dev, "Failed to register codec: %d\n" , ret); |
| 975 | |
| 976 | return ret; |
| 977 | } |
| 978 | |
| 979 | static const struct i2c_device_id max98388_i2c_id[] = { |
| 980 | { "max98388" }, |
| 981 | { }, |
| 982 | }; |
| 983 | |
| 984 | MODULE_DEVICE_TABLE(i2c, max98388_i2c_id); |
| 985 | |
| 986 | static const struct of_device_id max98388_of_match[] = { |
| 987 | { .compatible = "adi,max98388" , }, |
| 988 | { } |
| 989 | }; |
| 990 | MODULE_DEVICE_TABLE(of, max98388_of_match); |
| 991 | |
| 992 | static const struct acpi_device_id max98388_acpi_match[] = { |
| 993 | { "ADS8388" , 0 }, |
| 994 | {}, |
| 995 | }; |
| 996 | MODULE_DEVICE_TABLE(acpi, max98388_acpi_match); |
| 997 | |
| 998 | static struct i2c_driver max98388_i2c_driver = { |
| 999 | .driver = { |
| 1000 | .name = "max98388" , |
| 1001 | .of_match_table = max98388_of_match, |
| 1002 | .acpi_match_table = max98388_acpi_match, |
| 1003 | .pm = pm_sleep_ptr(&max98388_pm), |
| 1004 | }, |
| 1005 | .probe = max98388_i2c_probe, |
| 1006 | .id_table = max98388_i2c_id, |
| 1007 | }; |
| 1008 | |
| 1009 | module_i2c_driver(max98388_i2c_driver) |
| 1010 | |
| 1011 | MODULE_DESCRIPTION("ALSA SoC MAX98388 driver" ); |
| 1012 | MODULE_AUTHOR("Ryan Lee <ryans.lee@analog.com>" ); |
| 1013 | MODULE_LICENSE("GPL" ); |
| 1014 | |