Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

ASoC: max98388: add amplifier driver

Added Analog Devices MAX98388 amplifier driver.
MAX98388 provides a PCM interface for audio data and a standard I2C
interface for control data communication.

Signed-off-by: Ryan Lee <ryans.lee@analog.com>
Link: https://lore.kernel.org/r/20230613060945.183128-2-ryan.lee.analog@gmail.com
Signed-off-by: Mark Brown <broonie@kernel.org>

authored by

Ryan Lee and committed by
Mark Brown
6a8e1d46 4cab2d5f

+1259
+10
sound/soc/codecs/Kconfig
··· 137 137 imply SND_SOC_MAX98363 138 138 imply SND_SOC_MAX98373_I2C 139 139 imply SND_SOC_MAX98373_SDW 140 + imply SND_SOC_MAX98388 140 141 imply SND_SOC_MAX98390 141 142 imply SND_SOC_MAX98396 142 143 imply SND_SOC_MAX9850 ··· 1175 1174 the PCM interface for audio data and a standard I2C 1176 1175 interface for control data. Select this if MAX98373 is 1177 1176 connected via soundwire. 1177 + 1178 + config SND_SOC_MAX98388 1179 + tristate "Analog Devices MAX98388 Speaker Amplifier" 1180 + depends on I2C 1181 + help 1182 + Enable support for Analog Devices MAX98388 audio 1183 + amplifier. The device provides a PCM interface for 1184 + audio data and a standard I2C interface for control 1185 + data communication. 1178 1186 1179 1187 config SND_SOC_MAX98390 1180 1188 tristate "Maxim Integrated MAX98390 Speaker Amplifier"
+2
sound/soc/codecs/Makefile
··· 153 153 snd-soc-max98373-objs := max98373.o 154 154 snd-soc-max98373-i2c-objs := max98373-i2c.o 155 155 snd-soc-max98373-sdw-objs := max98373-sdw.o 156 + snd-soc-max98388-objs := max98388.o 156 157 snd-soc-max98390-objs := max98390.o 157 158 snd-soc-max98396-objs := max98396.o 158 159 snd-soc-max9850-objs := max9850.o ··· 526 525 obj-$(CONFIG_SND_SOC_MAX98373) += snd-soc-max98373.o 527 526 obj-$(CONFIG_SND_SOC_MAX98373_I2C) += snd-soc-max98373-i2c.o 528 527 obj-$(CONFIG_SND_SOC_MAX98373_SDW) += snd-soc-max98373-sdw.o 528 + obj-$(CONFIG_SND_SOC_MAX98388) += snd-soc-max98388.o 529 529 obj-$(CONFIG_SND_SOC_MAX98390) += snd-soc-max98390.o 530 530 obj-$(CONFIG_SND_SOC_MAX98396) += snd-soc-max98396.o 531 531 obj-$(CONFIG_SND_SOC_MAX9850) += snd-soc-max9850.o
+1013
sound/soc/codecs/max98388.c
··· 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.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/of_gpio.h> 12 + #include <linux/pm_runtime.h> 13 + #include <linux/regmap.h> 14 + #include <linux/slab.h> 15 + #include <linux/cdev.h> 16 + #include <sound/pcm.h> 17 + #include <sound/pcm_params.h> 18 + #include <sound/soc.h> 19 + #include <sound/tlv.h> 20 + #include "max98388.h" 21 + 22 + static struct reg_default max98388_reg[] = { 23 + {MAX98388_R2000_SW_RESET, 0x00}, 24 + {MAX98388_R2001_INT_RAW1, 0x00}, 25 + {MAX98388_R2002_INT_RAW2, 0x00}, 26 + {MAX98388_R2004_INT_STATE1, 0x00}, 27 + {MAX98388_R2005_INT_STATE2, 0x00}, 28 + {MAX98388_R2020_THERM_WARN_THRESH, 0x0A}, 29 + {MAX98388_R2031_SPK_MON_THRESH, 0x58}, 30 + {MAX98388_R2032_SPK_MON_LD_SEL, 0x08}, 31 + {MAX98388_R2033_SPK_MON_DURATION, 0x02}, 32 + {MAX98388_R2037_ERR_MON_CTRL, 0x01}, 33 + {MAX98388_R2040_PCM_MODE_CFG, 0xC0}, 34 + {MAX98388_R2041_PCM_CLK_SETUP, 0x04}, 35 + {MAX98388_R2042_PCM_SR_SETUP, 0x88}, 36 + {MAX98388_R2044_PCM_TX_CTRL1, 0x00}, 37 + {MAX98388_R2045_PCM_TX_CTRL2, 0x00}, 38 + {MAX98388_R2050_PCM_TX_HIZ_CTRL1, 0xFF}, 39 + {MAX98388_R2051_PCM_TX_HIZ_CTRL2, 0xFF}, 40 + {MAX98388_R2052_PCM_TX_HIZ_CTRL3, 0xFF}, 41 + {MAX98388_R2053_PCM_TX_HIZ_CTRL4, 0xFF}, 42 + {MAX98388_R2054_PCM_TX_HIZ_CTRL5, 0xFF}, 43 + {MAX98388_R2055_PCM_TX_HIZ_CTRL6, 0xFF}, 44 + {MAX98388_R2056_PCM_TX_HIZ_CTRL7, 0xFF}, 45 + {MAX98388_R2057_PCM_TX_HIZ_CTRL8, 0xFF}, 46 + {MAX98388_R2058_PCM_RX_SRC1, 0x00}, 47 + {MAX98388_R2059_PCM_RX_SRC2, 0x01}, 48 + {MAX98388_R205C_PCM_TX_DRIVE_STRENGTH, 0x00}, 49 + {MAX98388_R205D_PCM_TX_SRC_EN, 0x00}, 50 + {MAX98388_R205E_PCM_RX_EN, 0x00}, 51 + {MAX98388_R205F_PCM_TX_EN, 0x00}, 52 + {MAX98388_R2090_SPK_CH_VOL_CTRL, 0x00}, 53 + {MAX98388_R2091_SPK_CH_CFG, 0x02}, 54 + {MAX98388_R2092_SPK_AMP_OUT_CFG, 0x03}, 55 + {MAX98388_R2093_SPK_AMP_SSM_CFG, 0x01}, 56 + {MAX98388_R2094_SPK_AMP_ER_CTRL, 0x00}, 57 + {MAX98388_R209E_SPK_CH_PINK_NOISE_EN, 0x00}, 58 + {MAX98388_R209F_SPK_CH_AMP_EN, 0x00}, 59 + {MAX98388_R20A0_IV_DATA_DSP_CTRL, 0x10}, 60 + {MAX98388_R20A7_IV_DATA_EN, 0x00}, 61 + {MAX98388_R20E0_BP_ALC_THRESH, 0x04}, 62 + {MAX98388_R20E1_BP_ALC_RATES, 0x20}, 63 + {MAX98388_R20E2_BP_ALC_ATTEN, 0x06}, 64 + {MAX98388_R20E3_BP_ALC_REL, 0x02}, 65 + {MAX98388_R20E4_BP_ALC_MUTE, 0x33}, 66 + {MAX98388_R20EE_BP_INF_HOLD_REL, 0x00}, 67 + {MAX98388_R20EF_BP_ALC_EN, 0x00}, 68 + {MAX98388_R210E_AUTO_RESTART, 0x00}, 69 + {MAX98388_R210F_GLOBAL_EN, 0x00}, 70 + {MAX98388_R22FF_REV_ID, 0x00}, 71 + }; 72 + 73 + static int max98388_dac_event(struct snd_soc_dapm_widget *w, 74 + struct snd_kcontrol *kcontrol, int event) 75 + { 76 + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); 77 + struct max98388_priv *max98388 = snd_soc_component_get_drvdata(component); 78 + 79 + switch (event) { 80 + case SND_SOC_DAPM_POST_PMU: 81 + regmap_write(max98388->regmap, 82 + MAX98388_R210F_GLOBAL_EN, 1); 83 + usleep_range(30000, 31000); 84 + break; 85 + case SND_SOC_DAPM_PRE_PMD: 86 + regmap_write(max98388->regmap, 87 + MAX98388_R210F_GLOBAL_EN, 0); 88 + usleep_range(30000, 31000); 89 + max98388->tdm_mode = false; 90 + break; 91 + default: 92 + return 0; 93 + } 94 + return 0; 95 + } 96 + 97 + static const char * const max98388_monomix_switch_text[] = { 98 + "Left", "Right", "LeftRight"}; 99 + 100 + static const struct soc_enum dai_sel_enum = 101 + SOC_ENUM_SINGLE(MAX98388_R2058_PCM_RX_SRC1, 102 + MAX98388_PCM_TO_SPK_MONOMIX_CFG_SHIFT, 103 + 3, max98388_monomix_switch_text); 104 + 105 + static const struct snd_kcontrol_new max98388_dai_controls = 106 + SOC_DAPM_ENUM("DAI Sel", dai_sel_enum); 107 + 108 + static const struct snd_kcontrol_new max98388_vi_control = 109 + SOC_DAPM_SINGLE("Switch", MAX98388_R205F_PCM_TX_EN, 0, 1, 0); 110 + 111 + static const struct snd_soc_dapm_widget max98388_dapm_widgets[] = { 112 + SND_SOC_DAPM_DAC_E("Amp Enable", "HiFi Playback", 113 + MAX98388_R205E_PCM_RX_EN, 0, 0, max98388_dac_event, 114 + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), 115 + SND_SOC_DAPM_MUX("DAI Sel Mux", SND_SOC_NOPM, 0, 0, 116 + &max98388_dai_controls), 117 + SND_SOC_DAPM_OUTPUT("BE_OUT"), 118 + SND_SOC_DAPM_AIF_OUT("Voltage Sense", "HiFi Capture", 0, 119 + MAX98388_R20A7_IV_DATA_EN, 0, 0), 120 + SND_SOC_DAPM_AIF_OUT("Current Sense", "HiFi Capture", 0, 121 + MAX98388_R20A7_IV_DATA_EN, 1, 0), 122 + SND_SOC_DAPM_ADC("ADC Voltage", NULL, 123 + MAX98388_R205D_PCM_TX_SRC_EN, 0, 0), 124 + SND_SOC_DAPM_ADC("ADC Current", NULL, 125 + MAX98388_R205D_PCM_TX_SRC_EN, 1, 0), 126 + SND_SOC_DAPM_SWITCH("VI Sense", SND_SOC_NOPM, 0, 0, 127 + &max98388_vi_control), 128 + SND_SOC_DAPM_SIGGEN("VMON"), 129 + SND_SOC_DAPM_SIGGEN("IMON"), 130 + }; 131 + 132 + static DECLARE_TLV_DB_SCALE(max98388_digital_tlv, -6350, 50, 1); 133 + static DECLARE_TLV_DB_SCALE(max98388_amp_gain_tlv, -300, 300, 0); 134 + 135 + static const char * const max98388_alc_max_atten_text[] = { 136 + "0dBFS", "-1dBFS", "-2dBFS", "-3dBFS", "-4dBFS", "-5dBFS", 137 + "-6dBFS", "-7dBFS", "-8dBFS", "-9dBFS", "-10dBFS", "-11dBFS", 138 + "-12dBFS", "-13dBFS", "-14dBFS", "-15dBFS" 139 + }; 140 + 141 + static SOC_ENUM_SINGLE_DECL(max98388_alc_max_atten_enum, 142 + MAX98388_R20E2_BP_ALC_ATTEN, 143 + MAX98388_ALC_MAX_ATTEN_SHIFT, 144 + max98388_alc_max_atten_text); 145 + 146 + static const char * const max98388_thermal_warn_text[] = { 147 + "95C", "105C", "115C", "125C" 148 + }; 149 + 150 + static SOC_ENUM_SINGLE_DECL(max98388_thermal_warning_thresh_enum, 151 + MAX98388_R2020_THERM_WARN_THRESH, 152 + MAX98388_THERM_WARN_THRESH_SHIFT, 153 + max98388_thermal_warn_text); 154 + 155 + static const char * const max98388_thermal_shutdown_text[] = { 156 + "135C", "145C", "155C", "165C" 157 + }; 158 + 159 + static SOC_ENUM_SINGLE_DECL(max98388_thermal_shutdown_thresh_enum, 160 + MAX98388_R2020_THERM_WARN_THRESH, 161 + MAX98388_THERM_SHDN_THRESH_SHIFT, 162 + max98388_thermal_shutdown_text); 163 + 164 + static const char * const max98388_alc_thresh_single_text[] = { 165 + "3.625V", "3.550V", "3.475V", "3.400V", "3.325V", "3.250V", 166 + "3.175V", "3.100V", "3.025V", "2.950V", "2.875V", "2.800V", 167 + "2.725V", "2.650V", "2.575V", "2.500V" 168 + }; 169 + 170 + static SOC_ENUM_SINGLE_DECL(max98388_alc_thresh_single_enum, 171 + MAX98388_R20E0_BP_ALC_THRESH, 172 + MAX98388_ALC_THRESH_SHIFT, 173 + max98388_alc_thresh_single_text); 174 + 175 + static const char * const max98388_alc_attack_rate_text[] = { 176 + "0", "10us", "20us", "40us", "80us", "160us", 177 + "320us", "640us", "1.28ms", "2.56ms", "5.12ms", "10.24ms", 178 + "20.48ms", "40.96ms", "81.92ms", "163.84ms" 179 + }; 180 + 181 + static SOC_ENUM_SINGLE_DECL(max98388_alc_attack_rate_enum, 182 + MAX98388_R20E1_BP_ALC_RATES, 183 + MAX98388_ALC_ATTACK_RATE_SHIFT, 184 + max98388_alc_attack_rate_text); 185 + 186 + static const char * const max98388_alc_release_rate_text[] = { 187 + "20us", "40us", "80us", "160us", "320us", "640us", 188 + "1.28ms", "2.56ms", "5.12ms", "10.24ms", "20.48ms", "40.96ms", 189 + "81.92ms", "163.84ms", "327.68ms", "655.36ms" 190 + }; 191 + 192 + static SOC_ENUM_SINGLE_DECL(max98388_alc_release_rate_enum, 193 + MAX98388_R20E1_BP_ALC_RATES, 194 + MAX98388_ALC_RELEASE_RATE_SHIFT, 195 + max98388_alc_release_rate_text); 196 + 197 + static const char * const max98388_alc_debounce_text[] = { 198 + "0.01ms", "0.1ms", "1ms", "10ms", "100ms", "250ms", "500ms", "hold" 199 + }; 200 + 201 + static SOC_ENUM_SINGLE_DECL(max98388_alc_debouce_enum, 202 + MAX98388_R20E3_BP_ALC_REL, 203 + MAX98388_ALC_DEBOUNCE_TIME_SHIFT, 204 + max98388_alc_debounce_text); 205 + 206 + static const char * const max98388_alc_mute_delay_text[] = { 207 + "0.01ms", "0.05ms", "0.1ms", "0.5ms", "1ms", "5ms", "25ms", "250ms" 208 + }; 209 + 210 + static SOC_ENUM_SINGLE_DECL(max98388_alc_mute_delay_enum, 211 + MAX98388_R20E4_BP_ALC_MUTE, 212 + MAX98388_ALC_MUTE_DELAY_SHIFT, 213 + max98388_alc_mute_delay_text); 214 + 215 + static const char * const max98388_spkmon_duration_text[] = { 216 + "10ms", "25ms", "50ms", "75ms", "100ms", "200ms", "300ms", "400ms", 217 + "500ms", "600ms", "700ms", "800ms", "900ms", "1000ms", "1100ms", "1200ms" 218 + }; 219 + 220 + static SOC_ENUM_SINGLE_DECL(max98388_spkmon_duration_enum, 221 + MAX98388_R2033_SPK_MON_DURATION, 222 + MAX98388_SPKMON_DURATION_SHIFT, 223 + max98388_spkmon_duration_text); 224 + 225 + static const char * const max98388_spkmon_thresh_text[] = { 226 + "0.03V", "0.06V", "0.09V", "0.12V", "0.15V", "0.18V", "0.20V", "0.23V", 227 + "0.26V", "0.29V", "0.32V", "0.35V", "0.38V", "0.41V", "0.44V", "0.47V", 228 + "0.50V", "0.53V", "0.56V", "0.58V", "0.61V", "0.64V", "0.67V", "0.70V", 229 + "0.73V", "0.76V", "0.79V", "0.82V", "0.85V", "0.88V", "0.91V", "0.94V", 230 + "0.96V", "0.99V", "1.02V", "1.05V", "1.08V", "1.11V", "1.14V", "1.17V", 231 + "1.20V", "1.23V", "1.26V", "1.29V", "1.32V", "1.35V", "1.37V", "1.40V", 232 + "1.43V", "1.46V", "1.49V", "1.52V", "1.55V", "1.58V", "1.61V", "1.64V", 233 + "1.67V", "1.70V", "1.73V", "1.75V", "1.78V", "1.81V", "1.84V", "1.87V", 234 + "1.90V", "1.93V", "1.96V", "1.99V", "2.02V", "2.05V", "2.08V", "2.11V", 235 + "2.13V", "2.16V", "2.19V", "2.22V", "2.25V", "2.28V", "2.31V", "2.34V", 236 + "2.37V", "2.40V", "2.43V", "2.46V", "2.49V", "2.51V", "2.54V", "2.57V", 237 + "2.60V", "2.63V", "2.66V", "2.69V", "2.72V", "2.75V", "2.78V", "2.81V", 238 + "2.84V", "2.87V", "2.89V", "2.92V", "2.95V", "2.98V", "3.01V", "3.04V", 239 + "3.07V", "3.10V", "3.13V", "3.16V", "3.19V", "3.22V", "3.25V", "3.27V", 240 + "3.30V", "3.33V", "3.36V", "3.39V", "3.42V", "3.45V", "3.48V", "3.51V", 241 + "3.54V", "3.57V", "3.60V", "3.63V", "3.66V", "3.68V", "3.71V", "3.74V" 242 + }; 243 + 244 + static SOC_ENUM_SINGLE_DECL(max98388_spkmon_thresh_enum, 245 + MAX98388_R2031_SPK_MON_THRESH, 246 + MAX98388_SPKMON_THRESH_SHIFT, 247 + max98388_spkmon_thresh_text); 248 + 249 + static const char * const max98388_spkmon_load_text[] = { 250 + "2.00ohm", "2.25ohm", "2.50ohm", "2.75ohm", "3.00ohm", "3.25ohm", 251 + "3.50ohm", "3.75ohm", "4.00ohm", "4.25ohm", "4.50ohm", "4.75ohm", 252 + "5.00ohm", "5.25ohm", "5.50ohm", "5.75ohm", "6.00ohm", "6.25ohm", 253 + "6.50ohm", "6.75ohm", "7.00ohm", "7.25ohm", "7.50ohm", "7.75ohm", 254 + "8.00ohm", "8.25ohm", "8.50ohm", "8.75ohm", "9.00ohm", "9.25ohm", 255 + "9.50ohm", "9.75ohm", "10.00ohm", "10.25ohm", "10.50ohm", "10.75ohm", 256 + "11.00ohm", "11.25ohm", "11.50ohm", "11.75ohm", "12.00ohm", "12.25ohm", 257 + "12.50ohm", "12.75ohm", "13.00ohm", "13.25ohm", "13.50ohm", "13.75ohm", 258 + "14.00ohm", "14.25ohm", "14.50ohm", "14.75ohm", "15.00ohm", "15.25ohm", 259 + "15.50ohm", "15.75ohm", "16.00ohm", "16.25ohm", "16.50ohm", "16.75ohm", 260 + "17.00ohm", "17.25ohm", "17.50ohm", "17.75ohm", "18.00ohm", "18.25ohm", 261 + "18.50ohm", "18.75ohm", "19.00ohm", "19.25ohm", "19.50ohm", "19.75ohm", 262 + "20.00ohm", "20.25ohm", "20.50ohm", "20.75ohm", "21.00ohm", "21.25ohm", 263 + "21.50ohm", "21.75ohm", "22.00ohm", "22.25ohm", "22.50ohm", "22.75ohm", 264 + "23.00ohm", "23.25ohm", "23.50ohm", "23.75ohm", "24.00ohm", "24.25ohm", 265 + "24.50ohm", "24.75ohm", "25.00ohm", "25.25ohm", "25.50ohm", "25.75ohm", 266 + "26.00ohm", "26.25ohm", "26.50ohm", "26.75ohm", "27.00ohm", "27.25ohm", 267 + "27.50ohm", "27.75ohm", "28.00ohm", "28.25ohm", "28.50ohm", "28.75ohm", 268 + "29.00ohm", "29.25ohm", "29.50ohm", "29.75ohm", "30.00ohm", "30.25ohm", 269 + "30.50ohm", "30.75ohm", "31.00ohm", "31.25ohm", "31.50ohm", "31.75ohm", 270 + "32.00ohm", "32.25ohm", "32.50ohm", "32.75ohm", "33.00ohm", "33.25ohm", 271 + "33.50ohm", "33.75ohm" 272 + }; 273 + 274 + static SOC_ENUM_SINGLE_DECL(max98388_spkmon_load_enum, 275 + MAX98388_R2032_SPK_MON_LD_SEL, 276 + MAX98388_SPKMON_LOAD_SHIFT, 277 + max98388_spkmon_load_text); 278 + 279 + static const char * const max98388_edge_rate_text[] = { 280 + "Normal", "Reduced", "Maximum", "Increased", 281 + }; 282 + 283 + static SOC_ENUM_SINGLE_DECL(max98388_edge_rate_falling_enum, 284 + MAX98388_R2094_SPK_AMP_ER_CTRL, 285 + MAX98388_EDGE_RATE_FALL_SHIFT, 286 + max98388_edge_rate_text); 287 + 288 + static SOC_ENUM_SINGLE_DECL(max98388_edge_rate_rising_enum, 289 + MAX98388_R2094_SPK_AMP_ER_CTRL, 290 + MAX98388_EDGE_RATE_RISE_SHIFT, 291 + max98388_edge_rate_text); 292 + 293 + static const char * const max98388_ssm_mod_text[] = { 294 + "1.5%", "3.0%", "4.5%", "6.0%", 295 + }; 296 + 297 + static SOC_ENUM_SINGLE_DECL(max98388_ssm_mod_enum, 298 + MAX98388_R2093_SPK_AMP_SSM_CFG, 299 + MAX98388_SPK_AMP_SSM_MOD_SHIFT, 300 + max98388_ssm_mod_text); 301 + 302 + static const struct snd_kcontrol_new max98388_snd_controls[] = { 303 + SOC_SINGLE("Ramp Up Switch", MAX98388_R2091_SPK_CH_CFG, 304 + MAX98388_SPK_CFG_VOL_RMPUP_SHIFT, 1, 0), 305 + SOC_SINGLE("Ramp Down Switch", MAX98388_R2091_SPK_CH_CFG, 306 + MAX98388_SPK_CFG_VOL_RMPDN_SHIFT, 1, 0), 307 + /* Two Cell Mode Enable */ 308 + SOC_SINGLE("OP Mode Switch", MAX98388_R2092_SPK_AMP_OUT_CFG, 309 + MAX98388_SPK_AMP_OUT_MODE_SHIFT, 1, 0), 310 + /* Speaker Amplifier Overcurrent Automatic Restart Enable */ 311 + SOC_SINGLE("OVC Autorestart Switch", MAX98388_R210E_AUTO_RESTART, 312 + MAX98388_OVC_AUTORESTART_SHIFT, 1, 0), 313 + /* Thermal Shutdown Automatic Restart Enable */ 314 + SOC_SINGLE("THERM Autorestart Switch", MAX98388_R210E_AUTO_RESTART, 315 + MAX98388_THERM_AUTORESTART_SHIFT, 1, 0), 316 + /* PVDD UVLO Auto Restart */ 317 + SOC_SINGLE("UVLO Autorestart Switch", MAX98388_R210E_AUTO_RESTART, 318 + MAX98388_PVDD_UVLO_AUTORESTART_SHIFT, 1, 0), 319 + /* Clock Monitor Automatic Restart Enable */ 320 + SOC_SINGLE("CMON Autorestart Switch", MAX98388_R210E_AUTO_RESTART, 321 + MAX98388_CMON_AUTORESTART_SHIFT, 1, 0), 322 + SOC_SINGLE("CLK Monitor Switch", MAX98388_R2037_ERR_MON_CTRL, 323 + MAX98388_CLOCK_MON_SHIFT, 1, 0), 324 + /* Pinknoise Generator Enable */ 325 + SOC_SINGLE("Pinknoise Gen Switch", MAX98388_R209E_SPK_CH_PINK_NOISE_EN, 326 + MAX98388_PINK_NOISE_GEN_SHIFT, 1, 0), 327 + /* Dither Enable */ 328 + SOC_SINGLE("Dither Switch", MAX98388_R2091_SPK_CH_CFG, 329 + MAX98388_SPK_CFG_DITH_EN_SHIFT, 1, 0), 330 + SOC_SINGLE("VI Dither Switch", MAX98388_R20A0_IV_DATA_DSP_CTRL, 331 + MAX98388_AMP_DSP_CTRL_DITH_SHIFT, 1, 0), 332 + /* DC Blocker Enable */ 333 + SOC_SINGLE("DC Blocker Switch", MAX98388_R2091_SPK_CH_CFG, 334 + MAX98388_SPK_CFG_DCBLK_SHIFT, 1, 0), 335 + SOC_SINGLE("Voltage DC Blocker Switch", MAX98388_R20A0_IV_DATA_DSP_CTRL, 336 + MAX98388_AMP_DSP_CTRL_VOL_DCBLK_SHIFT, 1, 0), 337 + SOC_SINGLE("Current DC Blocker Switch", MAX98388_R20A0_IV_DATA_DSP_CTRL, 338 + MAX98388_AMP_DSP_CTRL_CUR_DCBLK_SHIFT, 1, 0), 339 + /* Digital Volume */ 340 + SOC_SINGLE_TLV("Digital Volume", MAX98388_R2090_SPK_CH_VOL_CTRL, 341 + 0, 0x7F, 1, max98388_digital_tlv), 342 + /* Speaker Volume */ 343 + SOC_SINGLE_TLV("Speaker Volume", MAX98388_R2092_SPK_AMP_OUT_CFG, 344 + 0, 5, 0, max98388_amp_gain_tlv), 345 + SOC_ENUM("Thermal Warn Thresh", max98388_thermal_warning_thresh_enum), 346 + SOC_ENUM("Thermal SHDN Thresh", max98388_thermal_shutdown_thresh_enum), 347 + /* Brownout Protection Automatic Level Control */ 348 + SOC_SINGLE("ALC Switch", MAX98388_R20EF_BP_ALC_EN, 0, 1, 0), 349 + SOC_ENUM("ALC Thresh", max98388_alc_thresh_single_enum), 350 + SOC_ENUM("ALC Attack Rate", max98388_alc_attack_rate_enum), 351 + SOC_ENUM("ALC Release Rate", max98388_alc_release_rate_enum), 352 + SOC_ENUM("ALC Max Atten", max98388_alc_max_atten_enum), 353 + SOC_ENUM("ALC Debounce Time", max98388_alc_debouce_enum), 354 + SOC_SINGLE("ALC Unmute Ramp Switch", MAX98388_R20E4_BP_ALC_MUTE, 355 + MAX98388_ALC_UNMUTE_RAMP_EN_SHIFT, 1, 0), 356 + SOC_SINGLE("ALC Mute Ramp Switch", MAX98388_R20E4_BP_ALC_MUTE, 357 + MAX98388_ALC_MUTE_RAMP_EN_SHIFT, 1, 0), 358 + SOC_SINGLE("ALC Mute Switch", MAX98388_R20E4_BP_ALC_MUTE, 359 + MAX98388_ALC_MUTE_EN_SHIFT, 1, 0), 360 + SOC_ENUM("ALC Mute Delay", max98388_alc_mute_delay_enum), 361 + /* Speaker Monitor */ 362 + SOC_SINGLE("SPKMON Switch", MAX98388_R2037_ERR_MON_CTRL, 363 + MAX98388_SPK_MON_SHIFT, 1, 0), 364 + SOC_ENUM("SPKMON Thresh", max98388_spkmon_thresh_enum), 365 + SOC_ENUM("SPKMON Load", max98388_spkmon_load_enum), 366 + SOC_ENUM("SPKMON Duration", max98388_spkmon_duration_enum), 367 + /* General Parameters */ 368 + SOC_ENUM("Fall Slew Rate", max98388_edge_rate_falling_enum), 369 + SOC_ENUM("Rise Slew Rate", max98388_edge_rate_rising_enum), 370 + SOC_SINGLE("AMP SSM Switch", MAX98388_R2093_SPK_AMP_SSM_CFG, 371 + MAX98388_SPK_AMP_SSM_EN_SHIFT, 1, 0), 372 + SOC_ENUM("AMP SSM Mod", max98388_ssm_mod_enum), 373 + }; 374 + 375 + static const struct snd_soc_dapm_route max98388_audio_map[] = { 376 + /* Plabyack */ 377 + {"DAI Sel Mux", "Left", "Amp Enable"}, 378 + {"DAI Sel Mux", "Right", "Amp Enable"}, 379 + {"DAI Sel Mux", "LeftRight", "Amp Enable"}, 380 + {"BE_OUT", NULL, "DAI Sel Mux"}, 381 + /* Capture */ 382 + { "ADC Voltage", NULL, "VMON"}, 383 + { "ADC Current", NULL, "IMON"}, 384 + { "VI Sense", "Switch", "ADC Voltage"}, 385 + { "VI Sense", "Switch", "ADC Current"}, 386 + { "Voltage Sense", NULL, "VI Sense"}, 387 + { "Current Sense", NULL, "VI Sense"}, 388 + }; 389 + 390 + static void max98388_reset(struct max98388_priv *max98388, struct device *dev) 391 + { 392 + int ret, reg, count; 393 + 394 + /* Software Reset */ 395 + ret = regmap_update_bits(max98388->regmap, 396 + MAX98388_R2000_SW_RESET, 397 + MAX98388_SOFT_RESET, 398 + MAX98388_SOFT_RESET); 399 + if (ret) 400 + dev_err(dev, "Reset command failed. (ret:%d)\n", ret); 401 + 402 + count = 0; 403 + while (count < 3) { 404 + usleep_range(10000, 11000); 405 + /* Software Reset Verification */ 406 + ret = regmap_read(max98388->regmap, 407 + MAX98388_R22FF_REV_ID, &reg); 408 + if (!ret) { 409 + dev_info(dev, "Reset completed (retry:%d)\n", count); 410 + return; 411 + } 412 + count++; 413 + } 414 + dev_err(dev, "Reset failed. (ret:%d)\n", ret); 415 + } 416 + 417 + static int max98388_probe(struct snd_soc_component *component) 418 + { 419 + struct max98388_priv *max98388 = snd_soc_component_get_drvdata(component); 420 + 421 + /* Software Reset */ 422 + max98388_reset(max98388, component->dev); 423 + 424 + /* General channel source configuration */ 425 + regmap_write(max98388->regmap, 426 + MAX98388_R2059_PCM_RX_SRC2, 427 + 0x10); 428 + 429 + /* Enable DC blocker */ 430 + regmap_write(max98388->regmap, 431 + MAX98388_R2091_SPK_CH_CFG, 432 + 0x1); 433 + /* Enable IMON VMON DC blocker */ 434 + regmap_write(max98388->regmap, 435 + MAX98388_R20A0_IV_DATA_DSP_CTRL, 436 + 0x3); 437 + /* TX slot configuration */ 438 + regmap_write(max98388->regmap, 439 + MAX98388_R2044_PCM_TX_CTRL1, 440 + max98388->v_slot); 441 + 442 + regmap_write(max98388->regmap, 443 + MAX98388_R2045_PCM_TX_CTRL2, 444 + max98388->i_slot); 445 + /* Enable Auto-restart behavior by default */ 446 + regmap_write(max98388->regmap, 447 + MAX98388_R210E_AUTO_RESTART, 0xF); 448 + /* Set interleave mode */ 449 + if (max98388->interleave_mode) 450 + regmap_update_bits(max98388->regmap, 451 + MAX98388_R2040_PCM_MODE_CFG, 452 + MAX98388_PCM_TX_CH_INTERLEAVE_MASK, 453 + MAX98388_PCM_TX_CH_INTERLEAVE_MASK); 454 + 455 + /* Speaker Amplifier Channel Enable */ 456 + regmap_update_bits(max98388->regmap, 457 + MAX98388_R209F_SPK_CH_AMP_EN, 458 + MAX98388_SPK_EN_MASK, 1); 459 + 460 + return 0; 461 + } 462 + 463 + static int max98388_dai_set_fmt(struct snd_soc_dai *codec_dai, 464 + unsigned int fmt) 465 + { 466 + struct snd_soc_component *component = codec_dai->component; 467 + struct max98388_priv *max98388 = snd_soc_component_get_drvdata(component); 468 + unsigned int format = 0; 469 + unsigned int invert = 0; 470 + 471 + dev_dbg(component->dev, "%s: fmt 0x%08X\n", __func__, fmt); 472 + 473 + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { 474 + case SND_SOC_DAIFMT_NB_NF: 475 + break; 476 + case SND_SOC_DAIFMT_IB_NF: 477 + invert = MAX98388_PCM_MODE_CFG_PCM_BCLKEDGE; 478 + break; 479 + default: 480 + dev_err(component->dev, "DAI invert mode unsupported\n"); 481 + return -EINVAL; 482 + } 483 + 484 + regmap_update_bits(max98388->regmap, 485 + MAX98388_R2041_PCM_CLK_SETUP, 486 + MAX98388_PCM_MODE_CFG_PCM_BCLKEDGE, 487 + invert); 488 + 489 + /* interface format */ 490 + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 491 + case SND_SOC_DAIFMT_I2S: 492 + format = MAX98388_PCM_FORMAT_I2S; 493 + break; 494 + case SND_SOC_DAIFMT_LEFT_J: 495 + format = MAX98388_PCM_FORMAT_LJ; 496 + break; 497 + case SND_SOC_DAIFMT_DSP_A: 498 + format = MAX98388_PCM_FORMAT_TDM_MODE1; 499 + break; 500 + case SND_SOC_DAIFMT_DSP_B: 501 + format = MAX98388_PCM_FORMAT_TDM_MODE0; 502 + break; 503 + default: 504 + return -EINVAL; 505 + } 506 + 507 + regmap_update_bits(max98388->regmap, 508 + MAX98388_R2040_PCM_MODE_CFG, 509 + MAX98388_PCM_MODE_CFG_FORMAT_MASK, 510 + format << MAX98388_PCM_MODE_CFG_FORMAT_SHIFT); 511 + 512 + return 0; 513 + } 514 + 515 + /* BCLKs per LRCLK */ 516 + static const int bclk_sel_table[] = { 517 + 32, 48, 64, 96, 128, 192, 256, 384, 512, 320, 518 + }; 519 + 520 + static int max98388_get_bclk_sel(int bclk) 521 + { 522 + int i; 523 + /* match BCLKs per LRCLK */ 524 + for (i = 0; i < ARRAY_SIZE(bclk_sel_table); i++) { 525 + if (bclk_sel_table[i] == bclk) 526 + return i + 2; 527 + } 528 + return 0; 529 + } 530 + 531 + static int max98388_set_clock(struct snd_soc_component *component, 532 + struct snd_pcm_hw_params *params) 533 + { 534 + struct max98388_priv *max98388 = snd_soc_component_get_drvdata(component); 535 + /* BCLK/LRCLK ratio calculation */ 536 + int blr_clk_ratio = params_channels(params) * max98388->ch_size; 537 + int value; 538 + 539 + if (!max98388->tdm_mode) { 540 + /* BCLK configuration */ 541 + value = max98388_get_bclk_sel(blr_clk_ratio); 542 + if (!value) { 543 + dev_err(component->dev, "format unsupported %d\n", 544 + params_format(params)); 545 + return -EINVAL; 546 + } 547 + 548 + regmap_update_bits(max98388->regmap, 549 + MAX98388_R2041_PCM_CLK_SETUP, 550 + MAX98388_PCM_CLK_SETUP_BSEL_MASK, 551 + value); 552 + } 553 + return 0; 554 + } 555 + 556 + static int max98388_dai_hw_params(struct snd_pcm_substream *substream, 557 + struct snd_pcm_hw_params *params, 558 + struct snd_soc_dai *dai) 559 + { 560 + struct snd_soc_component *component = dai->component; 561 + struct max98388_priv *max98388 = snd_soc_component_get_drvdata(component); 562 + unsigned int sampling_rate = 0; 563 + unsigned int chan_sz = 0; 564 + int ret, reg; 565 + int status = 0; 566 + 567 + /* pcm mode configuration */ 568 + switch (snd_pcm_format_width(params_format(params))) { 569 + case 16: 570 + chan_sz = MAX98388_PCM_MODE_CFG_CHANSZ_16; 571 + break; 572 + case 24: 573 + chan_sz = MAX98388_PCM_MODE_CFG_CHANSZ_24; 574 + break; 575 + case 32: 576 + chan_sz = MAX98388_PCM_MODE_CFG_CHANSZ_32; 577 + break; 578 + default: 579 + dev_err(component->dev, "format unsupported %d\n", 580 + params_format(params)); 581 + goto err; 582 + } 583 + 584 + max98388->ch_size = snd_pcm_format_width(params_format(params)); 585 + 586 + ret = regmap_read(max98388->regmap, 587 + MAX98388_R2040_PCM_MODE_CFG, &reg); 588 + if (ret < 0) 589 + goto err; 590 + 591 + /* GLOBAL_EN OFF prior to the channel size re-configure */ 592 + if (chan_sz != (reg & MAX98388_PCM_MODE_CFG_CHANSZ_MASK)) { 593 + ret = regmap_read(max98388->regmap, 594 + MAX98388_R210F_GLOBAL_EN, &status); 595 + if (ret < 0) 596 + goto err; 597 + 598 + if (status) { 599 + regmap_write(max98388->regmap, 600 + MAX98388_R210F_GLOBAL_EN, 0); 601 + usleep_range(30000, 31000); 602 + } 603 + regmap_update_bits(max98388->regmap, 604 + MAX98388_R2040_PCM_MODE_CFG, 605 + MAX98388_PCM_MODE_CFG_CHANSZ_MASK, chan_sz); 606 + } 607 + dev_dbg(component->dev, "format supported %d", 608 + params_format(params)); 609 + 610 + /* sampling rate configuration */ 611 + switch (params_rate(params)) { 612 + case 8000: 613 + sampling_rate = MAX98388_PCM_SR_8000; 614 + break; 615 + case 11025: 616 + sampling_rate = MAX98388_PCM_SR_11025; 617 + break; 618 + case 12000: 619 + sampling_rate = MAX98388_PCM_SR_12000; 620 + break; 621 + case 16000: 622 + sampling_rate = MAX98388_PCM_SR_16000; 623 + break; 624 + case 22050: 625 + sampling_rate = MAX98388_PCM_SR_22050; 626 + break; 627 + case 24000: 628 + sampling_rate = MAX98388_PCM_SR_24000; 629 + break; 630 + case 32000: 631 + sampling_rate = MAX98388_PCM_SR_32000; 632 + break; 633 + case 44100: 634 + sampling_rate = MAX98388_PCM_SR_44100; 635 + break; 636 + case 48000: 637 + sampling_rate = MAX98388_PCM_SR_48000; 638 + break; 639 + case 88200: 640 + sampling_rate = MAX98388_PCM_SR_88200; 641 + break; 642 + case 96000: 643 + sampling_rate = MAX98388_PCM_SR_96000; 644 + break; 645 + default: 646 + dev_err(component->dev, "rate %d not supported\n", 647 + params_rate(params)); 648 + goto err; 649 + } 650 + 651 + /* set DAI_SR to correct LRCLK frequency */ 652 + regmap_update_bits(max98388->regmap, 653 + MAX98388_R2042_PCM_SR_SETUP, 654 + MAX98388_PCM_SR_MASK, 655 + sampling_rate); 656 + 657 + /* set sampling rate of IV */ 658 + if (max98388->interleave_mode && 659 + sampling_rate > MAX98388_PCM_SR_16000) 660 + regmap_update_bits(max98388->regmap, 661 + MAX98388_R2042_PCM_SR_SETUP, 662 + MAX98388_PCM_SR_IV_MASK, 663 + (sampling_rate - 3) << MAX98388_PCM_SR_IV_SHIFT); 664 + else 665 + regmap_update_bits(max98388->regmap, 666 + MAX98388_R2042_PCM_SR_SETUP, 667 + MAX98388_PCM_SR_IV_MASK, 668 + sampling_rate << MAX98388_PCM_SR_IV_SHIFT); 669 + 670 + ret = max98388_set_clock(component, params); 671 + 672 + if (status) { 673 + regmap_write(max98388->regmap, 674 + MAX98388_R210F_GLOBAL_EN, 1); 675 + usleep_range(30000, 31000); 676 + } 677 + 678 + return ret; 679 + 680 + err: 681 + return -EINVAL; 682 + } 683 + 684 + #define MAX_NUM_SLOTS 16 685 + #define MAX_NUM_CH 2 686 + 687 + static int max98388_dai_tdm_slot(struct snd_soc_dai *dai, 688 + unsigned int tx_mask, unsigned int rx_mask, 689 + int slots, int slot_width) 690 + { 691 + struct snd_soc_component *component = dai->component; 692 + struct max98388_priv *max98388 = snd_soc_component_get_drvdata(component); 693 + int bsel = 0; 694 + unsigned int chan_sz = 0; 695 + unsigned int mask; 696 + int cnt, slot_found; 697 + int addr, bits; 698 + 699 + if (!tx_mask && !rx_mask && !slots && !slot_width) 700 + max98388->tdm_mode = false; 701 + else 702 + max98388->tdm_mode = true; 703 + 704 + /* BCLK configuration */ 705 + bsel = max98388_get_bclk_sel(slots * slot_width); 706 + if (bsel == 0) { 707 + dev_err(component->dev, "BCLK %d not supported\n", 708 + slots * slot_width); 709 + return -EINVAL; 710 + } 711 + 712 + regmap_update_bits(max98388->regmap, 713 + MAX98388_R2041_PCM_CLK_SETUP, 714 + MAX98388_PCM_CLK_SETUP_BSEL_MASK, 715 + bsel); 716 + 717 + /* Channel size configuration */ 718 + switch (slot_width) { 719 + case 16: 720 + chan_sz = MAX98388_PCM_MODE_CFG_CHANSZ_16; 721 + break; 722 + case 24: 723 + chan_sz = MAX98388_PCM_MODE_CFG_CHANSZ_24; 724 + break; 725 + case 32: 726 + chan_sz = MAX98388_PCM_MODE_CFG_CHANSZ_32; 727 + break; 728 + default: 729 + dev_err(component->dev, "format unsupported %d\n", 730 + slot_width); 731 + return -EINVAL; 732 + } 733 + 734 + regmap_update_bits(max98388->regmap, 735 + MAX98388_R2040_PCM_MODE_CFG, 736 + MAX98388_PCM_MODE_CFG_CHANSZ_MASK, chan_sz); 737 + 738 + /* Rx slot configuration */ 739 + slot_found = 0; 740 + mask = rx_mask; 741 + for (cnt = 0 ; cnt < MAX_NUM_SLOTS ; cnt++, mask >>= 1) { 742 + if (mask & 0x1) { 743 + if (slot_found == 0) 744 + regmap_update_bits(max98388->regmap, 745 + MAX98388_R2059_PCM_RX_SRC2, 746 + MAX98388_RX_SRC_CH0_SHIFT, 747 + cnt); 748 + else 749 + regmap_update_bits(max98388->regmap, 750 + MAX98388_R2059_PCM_RX_SRC2, 751 + MAX98388_RX_SRC_CH1_SHIFT, 752 + cnt); 753 + slot_found++; 754 + if (slot_found >= MAX_NUM_CH) 755 + break; 756 + } 757 + } 758 + 759 + /* speaker feedback slot configuration */ 760 + slot_found = 0; 761 + mask = tx_mask; 762 + for (cnt = 0 ; cnt < MAX_NUM_SLOTS ; cnt++, mask >>= 1) { 763 + if (mask & 0x1) { 764 + addr = MAX98388_R2044_PCM_TX_CTRL1 + (cnt / 8); 765 + bits = cnt % 8; 766 + regmap_update_bits(max98388->regmap, addr, bits, bits); 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(max98388->regmap, true); 859 + regcache_mark_dirty(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(max98388->regmap, false); 869 + max98388_reset(max98388, dev); 870 + regcache_sync(max98388->regmap); 871 + 872 + return 0; 873 + } 874 + 875 + static const struct dev_pm_ops max98388_pm = { 876 + SET_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 + 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, "adi,vmon-slot-no", &value)) 908 + max98388->v_slot = value & 0xF; 909 + else 910 + max98388->v_slot = 0; 911 + 912 + if (!device_property_read_u32(dev, "adi,imon-slot-no", &value)) 913 + max98388->i_slot = value & 0xF; 914 + else 915 + max98388->i_slot = 1; 916 + 917 + if (device_property_read_bool(dev, "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(&i2c->dev, sizeof(*max98388), GFP_KERNEL); 931 + if (!max98388) 932 + return -ENOMEM; 933 + 934 + i2c_set_clientdata(i2c, max98388); 935 + 936 + /* regmap initialization */ 937 + max98388->regmap = devm_regmap_init_i2c(i2c, &max98388_regmap); 938 + if (IS_ERR(max98388->regmap)) 939 + return dev_err_probe(&i2c->dev, PTR_ERR(max98388->regmap), 940 + "Failed to allocate register map.\n"); 941 + 942 + /* voltage/current slot & gpio configuration */ 943 + max98388_read_deveice_property(&i2c->dev, max98388); 944 + 945 + /* Device Reset */ 946 + max98388->reset_gpio = devm_gpiod_get_optional(&i2c->dev, 947 + "reset", GPIOD_OUT_HIGH); 948 + if (IS_ERR(max98388->reset_gpio)) 949 + return dev_err_probe(&i2c->dev, PTR_ERR(max98388->reset_gpio), 950 + "Unable to request GPIO\n"); 951 + 952 + if (max98388->reset_gpio) { 953 + usleep_range(5000, 6000); 954 + gpiod_set_value_cansleep(max98388->reset_gpio, 0); 955 + /* Wait for the hw reset done */ 956 + usleep_range(5000, 6000); 957 + } 958 + 959 + /* Read Revision ID */ 960 + ret = regmap_read(max98388->regmap, 961 + MAX98388_R22FF_REV_ID, &reg); 962 + if (ret < 0) 963 + return dev_err_probe(&i2c->dev, PTR_ERR(max98388->regmap), 964 + "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(&i2c->dev, 970 + &soc_codec_dev_max98388, 971 + 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", 0}, 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 = of_match_ptr(max98388_of_match), 1002 + .acpi_match_table = ACPI_PTR(max98388_acpi_match), 1003 + .pm = &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");
+234
sound/soc/codecs/max98388.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* 3 + * max98388.h -- MAX98388 ALSA SoC audio driver header 4 + * 5 + * Copyright(c) 2022, Analog Devices Inc. 6 + */ 7 + 8 + #ifndef _MAX98388_H 9 + #define _MAX98388_H 10 + 11 + /* Device Status Registers */ 12 + #define MAX98388_R2000_SW_RESET 0x2000 13 + #define MAX98388_R2001_INT_RAW1 0x2001 14 + #define MAX98388_R2002_INT_RAW2 0x2002 15 + #define MAX98388_R2004_INT_STATE1 0x2004 16 + #define MAX98388_R2005_INT_STATE2 0x2005 17 + /* Thermal Protection Registers */ 18 + #define MAX98388_R2020_THERM_WARN_THRESH 0x2020 19 + /* Error Monitor */ 20 + #define MAX98388_R2031_SPK_MON_THRESH 0x2031 21 + #define MAX98388_R2032_SPK_MON_LD_SEL 0x2032 22 + #define MAX98388_R2033_SPK_MON_DURATION 0x2033 23 + #define MAX98388_R2037_ERR_MON_CTRL 0x2037 24 + /* PCM Registers */ 25 + #define MAX98388_R2040_PCM_MODE_CFG 0x2040 26 + #define MAX98388_R2041_PCM_CLK_SETUP 0x2041 27 + #define MAX98388_R2042_PCM_SR_SETUP 0x2042 28 + #define MAX98388_R2044_PCM_TX_CTRL1 0x2044 29 + #define MAX98388_R2045_PCM_TX_CTRL2 0x2045 30 + #define MAX98388_R2050_PCM_TX_HIZ_CTRL1 0x2050 31 + #define MAX98388_R2051_PCM_TX_HIZ_CTRL2 0x2051 32 + #define MAX98388_R2052_PCM_TX_HIZ_CTRL3 0x2052 33 + #define MAX98388_R2053_PCM_TX_HIZ_CTRL4 0x2053 34 + #define MAX98388_R2054_PCM_TX_HIZ_CTRL5 0x2054 35 + #define MAX98388_R2055_PCM_TX_HIZ_CTRL6 0x2055 36 + #define MAX98388_R2056_PCM_TX_HIZ_CTRL7 0x2056 37 + #define MAX98388_R2057_PCM_TX_HIZ_CTRL8 0x2057 38 + #define MAX98388_R2058_PCM_RX_SRC1 0x2058 39 + #define MAX98388_R2059_PCM_RX_SRC2 0x2059 40 + #define MAX98388_R205C_PCM_TX_DRIVE_STRENGTH 0x205C 41 + #define MAX98388_R205D_PCM_TX_SRC_EN 0x205D 42 + #define MAX98388_R205E_PCM_RX_EN 0x205E 43 + #define MAX98388_R205F_PCM_TX_EN 0x205F 44 + /* Speaker Channel Control */ 45 + #define MAX98388_R2090_SPK_CH_VOL_CTRL 0x2090 46 + #define MAX98388_R2091_SPK_CH_CFG 0x2091 47 + #define MAX98388_R2092_SPK_AMP_OUT_CFG 0x2092 48 + #define MAX98388_R2093_SPK_AMP_SSM_CFG 0x2093 49 + #define MAX98388_R2094_SPK_AMP_ER_CTRL 0x2094 50 + #define MAX98388_R209E_SPK_CH_PINK_NOISE_EN 0x209E 51 + #define MAX98388_R209F_SPK_CH_AMP_EN 0x209F 52 + #define MAX98388_R20A0_IV_DATA_DSP_CTRL 0x20A0 53 + #define MAX98388_R20A7_IV_DATA_EN 0x20A7 54 + #define MAX98388_R20E0_BP_ALC_THRESH 0x20E0 55 + #define MAX98388_R20E1_BP_ALC_RATES 0x20E1 56 + #define MAX98388_R20E2_BP_ALC_ATTEN 0x20E2 57 + #define MAX98388_R20E3_BP_ALC_REL 0x20E3 58 + #define MAX98388_R20E4_BP_ALC_MUTE 0x20E4 59 + #define MAX98388_R20EE_BP_INF_HOLD_REL 0x20EE 60 + #define MAX98388_R20EF_BP_ALC_EN 0x20EF 61 + #define MAX98388_R210E_AUTO_RESTART 0x210E 62 + #define MAX98388_R210F_GLOBAL_EN 0x210F 63 + #define MAX98388_R22FF_REV_ID 0x22FF 64 + 65 + /* MAX98388_R2000_SW_RESET */ 66 + #define MAX98388_SOFT_RESET (0x1 << 0) 67 + 68 + /* MAX98388_R2020_THERM_WARN_THRESH */ 69 + #define MAX98388_THERM_SHDN_THRESH_SHIFT (0) 70 + #define MAX98388_THERM_WARN_THRESH_SHIFT (2) 71 + 72 + /* MAX98388_R2022_PCM_TX_SRC_1 */ 73 + #define MAX98388_PCM_TX_CH_SRC_A_V_SHIFT (0) 74 + #define MAX98388_PCM_TX_CH_SRC_A_I_SHIFT (4) 75 + 76 + /* MAX98388_R2024_PCM_DATA_FMT_CFG */ 77 + #define MAX98388_PCM_MODE_CFG_FORMAT_MASK (0x7 << 3) 78 + #define MAX98388_PCM_MODE_CFG_FORMAT_SHIFT (3) 79 + #define MAX98388_PCM_TX_CH_INTERLEAVE_MASK (0x1 << 2) 80 + #define MAX98388_PCM_FORMAT_I2S (0x0 << 0) 81 + #define MAX98388_PCM_FORMAT_LJ (0x1 << 0) 82 + #define MAX98388_PCM_FORMAT_TDM_MODE0 (0x3 << 0) 83 + #define MAX98388_PCM_FORMAT_TDM_MODE1 (0x4 << 0) 84 + #define MAX98388_PCM_FORMAT_TDM_MODE2 (0x5 << 0) 85 + #define MAX98388_PCM_MODE_CFG_CHANSZ_MASK (0x3 << 6) 86 + #define MAX98388_PCM_MODE_CFG_CHANSZ_16 (0x1 << 6) 87 + #define MAX98388_PCM_MODE_CFG_CHANSZ_24 (0x2 << 6) 88 + #define MAX98388_PCM_MODE_CFG_CHANSZ_32 (0x3 << 6) 89 + 90 + /* MAX98388_R2031_SPK_MON_THRESH */ 91 + #define MAX98388_SPKMON_THRESH_SHIFT (0) 92 + 93 + /* MAX98388_R2032_SPK_MON_LD_SEL */ 94 + #define MAX98388_SPKMON_LOAD_SHIFT (0) 95 + 96 + /* MAX98388_R2033_SPK_MON_DURATION */ 97 + #define MAX98388_SPKMON_DURATION_SHIFT (0) 98 + 99 + /* MAX98388_R2037_ERR_MON_CTRL */ 100 + #define MAX98388_CLOCK_MON_SHIFT (0) 101 + #define MAX98388_SPK_MON_SHIFT (1) 102 + 103 + /* MAX98388_R203E_AMP_PATH_GAIN */ 104 + #define MAX98388_SPK_DIGI_GAIN_MASK (0xF << 4) 105 + #define MAX98388_SPK_DIGI_GAIN_SHIFT (4) 106 + #define MAX98388_FS_GAIN_MAX_MASK (0xF << 0) 107 + #define MAX98388_FS_GAIN_MAX_SHIFT (0) 108 + 109 + /* MAX98388_R2041_PCM_CLK_SETUP */ 110 + #define MAX98388_PCM_MODE_CFG_PCM_BCLKEDGE (0x1 << 4) 111 + #define MAX98388_PCM_CLK_SETUP_BSEL_MASK (0xF << 0) 112 + 113 + /* MAX98388_R2042_PCM_SR_SETUP */ 114 + #define MAX98388_PCM_SR_MASK (0xF << 0) 115 + #define MAX98388_PCM_SR_IV_MASK (0xF << 4) 116 + #define MAX98388_PCM_SR_IV_SHIFT (4) 117 + #define MAX98388_PCM_SR_8000 (0x0 << 0) 118 + #define MAX98388_PCM_SR_11025 (0x1 << 0) 119 + #define MAX98388_PCM_SR_12000 (0x2 << 0) 120 + #define MAX98388_PCM_SR_16000 (0x3 << 0) 121 + #define MAX98388_PCM_SR_22050 (0x4 << 0) 122 + #define MAX98388_PCM_SR_24000 (0x5 << 0) 123 + #define MAX98388_PCM_SR_32000 (0x6 << 0) 124 + #define MAX98388_PCM_SR_44100 (0x7 << 0) 125 + #define MAX98388_PCM_SR_48000 (0x8 << 0) 126 + #define MAX98388_PCM_SR_88200 (0x9 << 0) 127 + #define MAX98388_PCM_SR_96000 (0xA << 0) 128 + 129 + /* MAX98388_R2043_AMP_EN */ 130 + #define MAX98388_SPK_EN_MASK (0x1 << 0) 131 + #define MAX98388_SPKFB_EN_MASK (0x1 << 1) 132 + #define MAX98388_SPKFB_EN_SHIFT (1) 133 + 134 + /* MAX98388_R2052_MEAS_ADC_PVDD_FLT_CFG */ 135 + #define MAX98388_FLT_EN_SHIFT (4) 136 + 137 + /* MAX98388_R2058_PCM_RX_SRC1 */ 138 + #define MAX98388_PCM_TO_SPK_MONOMIX_CFG_SHIFT (0) 139 + 140 + /* MAX98388_R2059_PCM_RX_SRC2 */ 141 + #define MAX98388_RX_SRC_CH0_SHIFT (0) 142 + #define MAX98388_RX_SRC_CH1_SHIFT (4) 143 + 144 + /* MAX98388_R2091_SPK_CH_CFG */ 145 + #define MAX98388_SPK_CFG_DCBLK_SHIFT (0) 146 + #define MAX98388_SPK_CFG_DITH_EN_SHIFT (1) 147 + #define MAX98388_SPK_CFG_INV_SHIFT (2) 148 + #define MAX98388_SPK_CFG_VOL_RMPUP_SHIFT (3) 149 + #define MAX98388_SPK_CFG_VOL_RMPDN_SHIFT (4) 150 + 151 + /* MAX98388_R2092_SPK_AMP_OUT_CFG */ 152 + #define MAX98388_SPK_AMP_OUT_GAIN_SHIFT (0) 153 + #define MAX98388_SPK_AMP_OUT_MODE_SHIFT (3) 154 + 155 + /* MAX98388_R2093_SPK_AMP_SSM_CFG */ 156 + #define MAX98388_SPK_AMP_SSM_EN_SHIFT (0) 157 + #define MAX98388_SPK_AMP_SSM_MOD_SHIFT (1) 158 + 159 + /* MAX98388_R2094_SPK_AMP_ER_CTRL */ 160 + #define MAX98388_EDGE_RATE_RISE_SHIFT (0) 161 + #define MAX98388_EDGE_RATE_FALL_SHIFT (2) 162 + 163 + /* MAX98388_R209E_SPK_CH_PINK_NOISE_EN */ 164 + #define MAX98388_PINK_NOISE_GEN_SHIFT (0) 165 + 166 + /* MAX98388_R20A0_IV_DATA_DSP_CTRL */ 167 + #define MAX98388_AMP_DSP_CTRL_VOL_DCBLK_SHIFT (0) 168 + #define MAX98388_AMP_DSP_CTRL_CUR_DCBLK_SHIFT (1) 169 + #define MAX98388_AMP_DSP_CTRL_VOL_INV_SHIFT (2) 170 + #define MAX98388_AMP_DSP_CTRL_CUR_INV_SHIFT (3) 171 + #define MAX98388_AMP_DSP_CTRL_DITH_SHIFT (4) 172 + 173 + /* MAX98388_R20B2_BDE_L4_CFG_2 */ 174 + #define MAX98388_LVL4_HOLD_EN_SHIFT (6) 175 + #define MAX98388_LVL4_MUTE_EN_SHIFT (7) 176 + 177 + /* MAX98388_R20B5_BDE_EN */ 178 + #define MAX98388_BDE_EN_SHIFT (0) 179 + 180 + /* MAX98388_R20D1_DHT_CFG */ 181 + #define MAX98388_DHT_ROT_PNT_SHIFT (0) 182 + #define MAX98388_DHT_SPK_GAIN_MIN_SHIFT (4) 183 + 184 + /* MAX98388_R20D2_DHT_ATTACK_CFG */ 185 + #define MAX98388_DHT_ATTACK_RATE_SHIFT (0) 186 + #define MAX98388_DHT_ATTACK_STEP_SHIFT (3) 187 + 188 + /* MAX98388_R20D3_DHT_RELEASE_CFG */ 189 + #define MAX98388_DHT_RELEASE_RATE_SHIFT (0) 190 + #define MAX98388_DHT_RELEASE_STEP_SHIFT (3) 191 + 192 + /* MAX98388_R20D4_DHT_EN */ 193 + #define MAX98388_DHT_EN_SHIFT (0) 194 + 195 + /* MAX98388_R20E0_BP_ALC_THRESH */ 196 + #define MAX98388_ALC_THRESH_SHIFT (0) 197 + 198 + /* MAX98388_R20E1_BP_ALC_RATES */ 199 + #define MAX98388_ALC_RELEASE_RATE_SHIFT (0) 200 + #define MAX98388_ALC_ATTACK_RATE_SHIFT (4) 201 + 202 + /* MAX98388_R20E2_BP_ALC_ATTEN */ 203 + #define MAX98388_ALC_MAX_ATTEN_SHIFT (0) 204 + 205 + /* MAX98388_R20E3_BP_ALC_REL */ 206 + #define MAX98388_ALC_DEBOUNCE_TIME_SHIFT (0) 207 + 208 + /* MAX98388_R20E4_BP_ALC_MUTE */ 209 + #define MAX98388_ALC_MUTE_EN_SHIFT (0) 210 + #define MAX98388_ALC_MUTE_DELAY_SHIFT (1) 211 + #define MAX98388_ALC_MUTE_RAMP_EN_SHIFT (4) 212 + #define MAX98388_ALC_UNMUTE_RAMP_EN_SHIFT (5) 213 + 214 + /* MAX98388_R210E_AUTO_RESTART */ 215 + #define MAX98388_PVDD_UVLO_AUTORESTART_SHIFT (0) 216 + #define MAX98388_THERM_AUTORESTART_SHIFT (1) 217 + #define MAX98388_OVC_AUTORESTART_SHIFT (2) 218 + #define MAX98388_CMON_AUTORESTART_SHIFT (3) 219 + 220 + /* MAX98388_R210F_GLOBAL_EN */ 221 + #define MAX98388_GLOBAL_EN_MASK (0x1 << 0) 222 + 223 + struct max98388_priv { 224 + struct regmap *regmap; 225 + struct gpio_desc *reset_gpio; 226 + unsigned int v_slot; 227 + unsigned int i_slot; 228 + unsigned int spkfb_slot; 229 + bool interleave_mode; 230 + unsigned int ch_size; 231 + bool tdm_mode; 232 + }; 233 + 234 + #endif