1b5858113SRyan Lee // SPDX-License-Identifier: GPL-2.0 2b5858113SRyan Lee // Copyright (c) 2022, Analog Devices Inc. 3b5858113SRyan Lee 40b7f644fSHui Tang #include <linux/gpio/consumer.h> 5b5858113SRyan Lee #include <linux/i2c.h> 6b5858113SRyan Lee #include <linux/module.h> 7b5858113SRyan Lee #include <sound/pcm_params.h> 8703ee055SDaniel Mack #include <linux/regulator/consumer.h> 9b5858113SRyan Lee #include <sound/soc.h> 10b5858113SRyan Lee #include <linux/gpio.h> 11b5858113SRyan Lee #include <sound/tlv.h> 12b5858113SRyan Lee #include "max98396.h" 13b5858113SRyan Lee 14703ee055SDaniel Mack static const char * const max98396_core_supplies[MAX98396_NUM_CORE_SUPPLIES] = { 15703ee055SDaniel Mack "avdd", 16703ee055SDaniel Mack "dvdd", 17703ee055SDaniel Mack "dvddio", 18703ee055SDaniel Mack }; 19703ee055SDaniel Mack 20b5858113SRyan Lee static struct reg_default max98396_reg[] = { 21b5858113SRyan Lee {MAX98396_R2000_SW_RESET, 0x00}, 22b5858113SRyan Lee {MAX98396_R2001_INT_RAW1, 0x00}, 23b5858113SRyan Lee {MAX98396_R2002_INT_RAW2, 0x00}, 24b5858113SRyan Lee {MAX98396_R2003_INT_RAW3, 0x00}, 25b5858113SRyan Lee {MAX98396_R2004_INT_RAW4, 0x00}, 26b5858113SRyan Lee {MAX98396_R2006_INT_STATE1, 0x00}, 27b5858113SRyan Lee {MAX98396_R2007_INT_STATE2, 0x00}, 28b5858113SRyan Lee {MAX98396_R2008_INT_STATE3, 0x00}, 29b5858113SRyan Lee {MAX98396_R2009_INT_STATE4, 0x00}, 30b5858113SRyan Lee {MAX98396_R200B_INT_FLAG1, 0x00}, 31b5858113SRyan Lee {MAX98396_R200C_INT_FLAG2, 0x00}, 32b5858113SRyan Lee {MAX98396_R200D_INT_FLAG3, 0x00}, 33b5858113SRyan Lee {MAX98396_R200E_INT_FLAG4, 0x00}, 34b5858113SRyan Lee {MAX98396_R2010_INT_EN1, 0x02}, 35b5858113SRyan Lee {MAX98396_R2011_INT_EN2, 0x00}, 36b5858113SRyan Lee {MAX98396_R2012_INT_EN3, 0x00}, 37b5858113SRyan Lee {MAX98396_R2013_INT_EN4, 0x00}, 38b5858113SRyan Lee {MAX98396_R2015_INT_FLAG_CLR1, 0x00}, 39b5858113SRyan Lee {MAX98396_R2016_INT_FLAG_CLR2, 0x00}, 40b5858113SRyan Lee {MAX98396_R2017_INT_FLAG_CLR3, 0x00}, 41b5858113SRyan Lee {MAX98396_R2018_INT_FLAG_CLR4, 0x00}, 42b5858113SRyan Lee {MAX98396_R201F_IRQ_CTRL, 0x00}, 43b5858113SRyan Lee {MAX98396_R2020_THERM_WARN_THRESH, 0x46}, 44b5858113SRyan Lee {MAX98396_R2021_THERM_WARN_THRESH2, 0x46}, 45b5858113SRyan Lee {MAX98396_R2022_THERM_SHDN_THRESH, 0x64}, 46b5858113SRyan Lee {MAX98396_R2023_THERM_HYSTERESIS, 0x02}, 47b5858113SRyan Lee {MAX98396_R2024_THERM_FOLDBACK_SET, 0xC5}, 48b5858113SRyan Lee {MAX98396_R2027_THERM_FOLDBACK_EN, 0x01}, 49b5858113SRyan Lee {MAX98396_R2030_NOISEGATE_MODE_CTRL, 0x32}, 50b5858113SRyan Lee {MAX98396_R2033_NOISEGATE_MODE_EN, 0x00}, 51b5858113SRyan Lee {MAX98396_R2038_CLK_MON_CTRL, 0x00}, 52b5858113SRyan Lee {MAX98396_R2039_DATA_MON_CTRL, 0x00}, 53b5858113SRyan Lee {MAX98396_R203F_ENABLE_CTRLS, 0x0F}, 54b5858113SRyan Lee {MAX98396_R2040_PIN_CFG, 0x55}, 55b5858113SRyan Lee {MAX98396_R2041_PCM_MODE_CFG, 0xC0}, 56b5858113SRyan Lee {MAX98396_R2042_PCM_CLK_SETUP, 0x04}, 57b5858113SRyan Lee {MAX98396_R2043_PCM_SR_SETUP, 0x88}, 58b5858113SRyan Lee {MAX98396_R2044_PCM_TX_CTRL_1, 0x00}, 59b5858113SRyan Lee {MAX98396_R2045_PCM_TX_CTRL_2, 0x00}, 60b5858113SRyan Lee {MAX98396_R2046_PCM_TX_CTRL_3, 0x00}, 61b5858113SRyan Lee {MAX98396_R2047_PCM_TX_CTRL_4, 0x00}, 62b5858113SRyan Lee {MAX98396_R2048_PCM_TX_CTRL_5, 0x00}, 63b5858113SRyan Lee {MAX98396_R2049_PCM_TX_CTRL_6, 0x00}, 64b5858113SRyan Lee {MAX98396_R204A_PCM_TX_CTRL_7, 0x00}, 65b5858113SRyan Lee {MAX98396_R204B_PCM_TX_CTRL_8, 0x00}, 66b5858113SRyan Lee {MAX98396_R204C_PCM_TX_HIZ_CTRL_1, 0xFF}, 67b5858113SRyan Lee {MAX98396_R204D_PCM_TX_HIZ_CTRL_2, 0xFF}, 68b5858113SRyan Lee {MAX98396_R204E_PCM_TX_HIZ_CTRL_3, 0xFF}, 69b5858113SRyan Lee {MAX98396_R204F_PCM_TX_HIZ_CTRL_4, 0xFF}, 70b5858113SRyan Lee {MAX98396_R2050_PCM_TX_HIZ_CTRL_5, 0xFF}, 71b5858113SRyan Lee {MAX98396_R2051_PCM_TX_HIZ_CTRL_6, 0xFF}, 72b5858113SRyan Lee {MAX98396_R2052_PCM_TX_HIZ_CTRL_7, 0xFF}, 73b5858113SRyan Lee {MAX98396_R2053_PCM_TX_HIZ_CTRL_8, 0xFF}, 74b5858113SRyan Lee {MAX98396_R2055_PCM_RX_SRC1, 0x00}, 75b5858113SRyan Lee {MAX98396_R2056_PCM_RX_SRC2, 0x00}, 76b5858113SRyan Lee {MAX98396_R2058_PCM_BYPASS_SRC, 0x00}, 77b5858113SRyan Lee {MAX98396_R205D_PCM_TX_SRC_EN, 0x00}, 78b5858113SRyan Lee {MAX98396_R205E_PCM_RX_EN, 0x00}, 79b5858113SRyan Lee {MAX98396_R205F_PCM_TX_EN, 0x00}, 80b5858113SRyan Lee {MAX98396_R2070_ICC_RX_EN_A, 0x00}, 81b5858113SRyan Lee {MAX98396_R2071_ICC_RX_EN_B, 0x00}, 82b5858113SRyan Lee {MAX98396_R2072_ICC_TX_CTRL, 0x00}, 83b5858113SRyan Lee {MAX98396_R207F_ICC_EN, 0x00}, 84b5858113SRyan Lee {MAX98396_R2083_TONE_GEN_DC_CFG, 0x04}, 85b5858113SRyan Lee {MAX98396_R2084_TONE_GEN_DC_LVL1, 0x00}, 86b5858113SRyan Lee {MAX98396_R2085_TONE_GEN_DC_LVL2, 0x00}, 87b5858113SRyan Lee {MAX98396_R2086_TONE_GEN_DC_LVL3, 0x00}, 88b5858113SRyan Lee {MAX98396_R208F_TONE_GEN_EN, 0x00}, 89b5858113SRyan Lee {MAX98396_R2090_AMP_VOL_CTRL, 0x00}, 90b5858113SRyan Lee {MAX98396_R2091_AMP_PATH_GAIN, 0x0B}, 91b5858113SRyan Lee {MAX98396_R2092_AMP_DSP_CFG, 0x23}, 92b5858113SRyan Lee {MAX98396_R2093_SSM_CFG, 0x0D}, 93b5858113SRyan Lee {MAX98396_R2094_SPK_CLS_DG_THRESH, 0x12}, 94b5858113SRyan Lee {MAX98396_R2095_SPK_CLS_DG_HDR, 0x17}, 95b5858113SRyan Lee {MAX98396_R2096_SPK_CLS_DG_HOLD_TIME, 0x17}, 96b5858113SRyan Lee {MAX98396_R2097_SPK_CLS_DG_DELAY, 0x00}, 97b5858113SRyan Lee {MAX98396_R2098_SPK_CLS_DG_MODE, 0x00}, 98b5858113SRyan Lee {MAX98396_R2099_SPK_CLS_DG_VBAT_LVL, 0x03}, 99b5858113SRyan Lee {MAX98396_R209A_SPK_EDGE_CTRL, 0x00}, 100b5858113SRyan Lee {MAX98396_R209C_SPK_EDGE_CTRL1, 0x0A}, 101b5858113SRyan Lee {MAX98396_R209D_SPK_EDGE_CTRL2, 0xAA}, 102b5858113SRyan Lee {MAX98396_R209E_AMP_CLIP_GAIN, 0x00}, 103b5858113SRyan Lee {MAX98396_R209F_BYPASS_PATH_CFG, 0x00}, 104b5858113SRyan Lee {MAX98396_R20A0_AMP_SUPPLY_CTL, 0x00}, 105b5858113SRyan Lee {MAX98396_R20AF_AMP_EN, 0x00}, 106b5858113SRyan Lee {MAX98396_R20B0_ADC_SR, 0x30}, 107b5858113SRyan Lee {MAX98396_R20B1_ADC_PVDD_CFG, 0x00}, 108b5858113SRyan Lee {MAX98396_R20B2_ADC_VBAT_CFG, 0x00}, 109b5858113SRyan Lee {MAX98396_R20B3_ADC_THERMAL_CFG, 0x00}, 110b5858113SRyan Lee {MAX98396_R20B4_ADC_READBACK_CTRL1, 0x00}, 111b5858113SRyan Lee {MAX98396_R20B5_ADC_READBACK_CTRL2, 0x00}, 112b5858113SRyan Lee {MAX98396_R20B6_ADC_PVDD_READBACK_MSB, 0x00}, 113b5858113SRyan Lee {MAX98396_R20B7_ADC_PVDD_READBACK_LSB, 0x00}, 114b5858113SRyan Lee {MAX98396_R20B8_ADC_VBAT_READBACK_MSB, 0x00}, 115b5858113SRyan Lee {MAX98396_R20B9_ADC_VBAT_READBACK_LSB, 0x00}, 116b5858113SRyan Lee {MAX98396_R20BA_ADC_TEMP_READBACK_MSB, 0x00}, 117b5858113SRyan Lee {MAX98396_R20BB_ADC_TEMP_READBACK_LSB, 0x00}, 118b5858113SRyan Lee {MAX98396_R20BC_ADC_LO_PVDD_READBACK_MSB, 0x00}, 119b5858113SRyan Lee {MAX98396_R20BD_ADC_LO_PVDD_READBACK_LSB, 0x00}, 120b5858113SRyan Lee {MAX98396_R20BE_ADC_LO_VBAT_READBACK_MSB, 0x00}, 121b5858113SRyan Lee {MAX98396_R20BF_ADC_LO_VBAT_READBACK_LSB, 0x00}, 122b5858113SRyan Lee {MAX98396_R20C7_ADC_CFG, 0x00}, 123b5858113SRyan Lee {MAX98396_R20D0_DHT_CFG1, 0x00}, 124b5858113SRyan Lee {MAX98396_R20D1_LIMITER_CFG1, 0x08}, 125b5858113SRyan Lee {MAX98396_R20D2_LIMITER_CFG2, 0x00}, 126b5858113SRyan Lee {MAX98396_R20D3_DHT_CFG2, 0x14}, 127b5858113SRyan Lee {MAX98396_R20D4_DHT_CFG3, 0x02}, 128b5858113SRyan Lee {MAX98396_R20D5_DHT_CFG4, 0x04}, 129b5858113SRyan Lee {MAX98396_R20D6_DHT_HYSTERESIS_CFG, 0x07}, 130b5858113SRyan Lee {MAX98396_R20DF_DHT_EN, 0x00}, 131b5858113SRyan Lee {MAX98396_R20E0_IV_SENSE_PATH_CFG, 0x04}, 132b5858113SRyan Lee {MAX98396_R20E4_IV_SENSE_PATH_EN, 0x00}, 133b5858113SRyan Lee {MAX98396_R20E5_BPE_STATE, 0x00}, 134b5858113SRyan Lee {MAX98396_R20E6_BPE_L3_THRESH_MSB, 0x00}, 135b5858113SRyan Lee {MAX98396_R20E7_BPE_L3_THRESH_LSB, 0x00}, 136b5858113SRyan Lee {MAX98396_R20E8_BPE_L2_THRESH_MSB, 0x00}, 137b5858113SRyan Lee {MAX98396_R20E9_BPE_L2_THRESH_LSB, 0x00}, 138b5858113SRyan Lee {MAX98396_R20EA_BPE_L1_THRESH_MSB, 0x00}, 139b5858113SRyan Lee {MAX98396_R20EB_BPE_L1_THRESH_LSB, 0x00}, 140b5858113SRyan Lee {MAX98396_R20EC_BPE_L0_THRESH_MSB, 0x00}, 141b5858113SRyan Lee {MAX98396_R20ED_BPE_L0_THRESH_LSB, 0x00}, 142b5858113SRyan Lee {MAX98396_R20EE_BPE_L3_DWELL_HOLD_TIME, 0x00}, 143b5858113SRyan Lee {MAX98396_R20EF_BPE_L2_DWELL_HOLD_TIME, 0x00}, 144b5858113SRyan Lee {MAX98396_R20F0_BPE_L1_DWELL_HOLD_TIME, 0x00}, 145b5858113SRyan Lee {MAX98396_R20F1_BPE_L0_HOLD_TIME, 0x00}, 146b5858113SRyan Lee {MAX98396_R20F2_BPE_L3_ATTACK_REL_STEP, 0x00}, 147b5858113SRyan Lee {MAX98396_R20F3_BPE_L2_ATTACK_REL_STEP, 0x00}, 148b5858113SRyan Lee {MAX98396_R20F4_BPE_L1_ATTACK_REL_STEP, 0x00}, 149b5858113SRyan Lee {MAX98396_R20F5_BPE_L0_ATTACK_REL_STEP, 0x00}, 150b5858113SRyan Lee {MAX98396_R20F6_BPE_L3_MAX_GAIN_ATTN, 0x00}, 151b5858113SRyan Lee {MAX98396_R20F7_BPE_L2_MAX_GAIN_ATTN, 0x00}, 152b5858113SRyan Lee {MAX98396_R20F8_BPE_L1_MAX_GAIN_ATTN, 0x00}, 153b5858113SRyan Lee {MAX98396_R20F9_BPE_L0_MAX_GAIN_ATTN, 0x00}, 154b5858113SRyan Lee {MAX98396_R20FA_BPE_L3_ATT_REL_RATE, 0x00}, 155b5858113SRyan Lee {MAX98396_R20FB_BPE_L2_ATT_REL_RATE, 0x00}, 156b5858113SRyan Lee {MAX98396_R20FC_BPE_L1_ATT_REL_RATE, 0x00}, 157b5858113SRyan Lee {MAX98396_R20FD_BPE_L0_ATT_REL_RATE, 0x00}, 158b5858113SRyan Lee {MAX98396_R20FE_BPE_L3_LIMITER_CFG, 0x00}, 159b5858113SRyan Lee {MAX98396_R20FF_BPE_L2_LIMITER_CFG, 0x00}, 160b5858113SRyan Lee {MAX98396_R2100_BPE_L1_LIMITER_CFG, 0x00}, 161b5858113SRyan Lee {MAX98396_R2101_BPE_L0_LIMITER_CFG, 0x00}, 162b5858113SRyan Lee {MAX98396_R2102_BPE_L3_LIM_ATT_REL_RATE, 0x00}, 163b5858113SRyan Lee {MAX98396_R2103_BPE_L2_LIM_ATT_REL_RATE, 0x00}, 164b5858113SRyan Lee {MAX98396_R2104_BPE_L1_LIM_ATT_REL_RATE, 0x00}, 165b5858113SRyan Lee {MAX98396_R2105_BPE_L0_LIM_ATT_REL_RATE, 0x00}, 166b5858113SRyan Lee {MAX98396_R2106_BPE_THRESH_HYSTERESIS, 0x00}, 167b5858113SRyan Lee {MAX98396_R2107_BPE_INFINITE_HOLD_CLR, 0x00}, 168b5858113SRyan Lee {MAX98396_R2108_BPE_SUPPLY_SRC, 0x00}, 169b5858113SRyan Lee {MAX98396_R2109_BPE_LOW_STATE, 0x00}, 170b5858113SRyan Lee {MAX98396_R210A_BPE_LOW_GAIN, 0x00}, 171b5858113SRyan Lee {MAX98396_R210B_BPE_LOW_LIMITER, 0x00}, 172b5858113SRyan Lee {MAX98396_R210D_BPE_EN, 0x00}, 173b5858113SRyan Lee {MAX98396_R210E_AUTO_RESTART, 0x00}, 174b5858113SRyan Lee {MAX98396_R210F_GLOBAL_EN, 0x00}, 175b5858113SRyan Lee {MAX98396_R21FF_REVISION_ID, 0x00}, 176b5858113SRyan Lee }; 177b5858113SRyan Lee 178b5858113SRyan Lee static struct reg_default max98397_reg[] = { 179b5858113SRyan Lee {MAX98396_R2000_SW_RESET, 0x00}, 180b5858113SRyan Lee {MAX98396_R2001_INT_RAW1, 0x00}, 181b5858113SRyan Lee {MAX98396_R2002_INT_RAW2, 0x00}, 182b5858113SRyan Lee {MAX98396_R2003_INT_RAW3, 0x00}, 183b5858113SRyan Lee {MAX98396_R2004_INT_RAW4, 0x00}, 184b5858113SRyan Lee {MAX98396_R2006_INT_STATE1, 0x00}, 185b5858113SRyan Lee {MAX98396_R2007_INT_STATE2, 0x00}, 186b5858113SRyan Lee {MAX98396_R2008_INT_STATE3, 0x00}, 187b5858113SRyan Lee {MAX98396_R2009_INT_STATE4, 0x00}, 188b5858113SRyan Lee {MAX98396_R200B_INT_FLAG1, 0x00}, 189b5858113SRyan Lee {MAX98396_R200C_INT_FLAG2, 0x00}, 190b5858113SRyan Lee {MAX98396_R200D_INT_FLAG3, 0x00}, 191b5858113SRyan Lee {MAX98396_R200E_INT_FLAG4, 0x00}, 192b5858113SRyan Lee {MAX98396_R2010_INT_EN1, 0x02}, 193b5858113SRyan Lee {MAX98396_R2011_INT_EN2, 0x00}, 194b5858113SRyan Lee {MAX98396_R2012_INT_EN3, 0x00}, 195b5858113SRyan Lee {MAX98396_R2013_INT_EN4, 0x00}, 196b5858113SRyan Lee {MAX98396_R2015_INT_FLAG_CLR1, 0x00}, 197b5858113SRyan Lee {MAX98396_R2016_INT_FLAG_CLR2, 0x00}, 198b5858113SRyan Lee {MAX98396_R2017_INT_FLAG_CLR3, 0x00}, 199b5858113SRyan Lee {MAX98396_R2018_INT_FLAG_CLR4, 0x00}, 200b5858113SRyan Lee {MAX98396_R201F_IRQ_CTRL, 0x00}, 201b5858113SRyan Lee {MAX98396_R2020_THERM_WARN_THRESH, 0x46}, 202b5858113SRyan Lee {MAX98396_R2021_THERM_WARN_THRESH2, 0x46}, 203b5858113SRyan Lee {MAX98396_R2022_THERM_SHDN_THRESH, 0x64}, 204b5858113SRyan Lee {MAX98396_R2023_THERM_HYSTERESIS, 0x02}, 205b5858113SRyan Lee {MAX98396_R2024_THERM_FOLDBACK_SET, 0xC5}, 206b5858113SRyan Lee {MAX98396_R2027_THERM_FOLDBACK_EN, 0x01}, 207b5858113SRyan Lee {MAX98396_R2030_NOISEGATE_MODE_CTRL, 0x32}, 208b5858113SRyan Lee {MAX98396_R2033_NOISEGATE_MODE_EN, 0x00}, 209b5858113SRyan Lee {MAX98396_R2038_CLK_MON_CTRL, 0x00}, 210b5858113SRyan Lee {MAX98396_R2039_DATA_MON_CTRL, 0x00}, 211b5858113SRyan Lee {MAX98397_R203A_SPK_MON_THRESH, 0x03}, 212b5858113SRyan Lee {MAX98396_R203F_ENABLE_CTRLS, 0x0F}, 213b5858113SRyan Lee {MAX98396_R2040_PIN_CFG, 0x55}, 214b5858113SRyan Lee {MAX98396_R2041_PCM_MODE_CFG, 0xC0}, 215b5858113SRyan Lee {MAX98396_R2042_PCM_CLK_SETUP, 0x04}, 216b5858113SRyan Lee {MAX98396_R2043_PCM_SR_SETUP, 0x88}, 217b5858113SRyan Lee {MAX98396_R2044_PCM_TX_CTRL_1, 0x00}, 218b5858113SRyan Lee {MAX98396_R2045_PCM_TX_CTRL_2, 0x00}, 219b5858113SRyan Lee {MAX98396_R2046_PCM_TX_CTRL_3, 0x00}, 220b5858113SRyan Lee {MAX98396_R2047_PCM_TX_CTRL_4, 0x00}, 221b5858113SRyan Lee {MAX98396_R2048_PCM_TX_CTRL_5, 0x00}, 222b5858113SRyan Lee {MAX98396_R2049_PCM_TX_CTRL_6, 0x00}, 223b5858113SRyan Lee {MAX98396_R204A_PCM_TX_CTRL_7, 0x00}, 224b5858113SRyan Lee {MAX98396_R204B_PCM_TX_CTRL_8, 0x00}, 225b5858113SRyan Lee {MAX98397_R204C_PCM_TX_CTRL_9, 0x00}, 226b5858113SRyan Lee {MAX98397_R204D_PCM_TX_HIZ_CTRL_1, 0xFF}, 227b5858113SRyan Lee {MAX98397_R204E_PCM_TX_HIZ_CTRL_2, 0xFF}, 228b5858113SRyan Lee {MAX98397_R204F_PCM_TX_HIZ_CTRL_3, 0xFF}, 229b5858113SRyan Lee {MAX98397_R2050_PCM_TX_HIZ_CTRL_4, 0xFF}, 230b5858113SRyan Lee {MAX98397_R2051_PCM_TX_HIZ_CTRL_5, 0xFF}, 231b5858113SRyan Lee {MAX98397_R2052_PCM_TX_HIZ_CTRL_6, 0xFF}, 232b5858113SRyan Lee {MAX98397_R2053_PCM_TX_HIZ_CTRL_7, 0xFF}, 233b5858113SRyan Lee {MAX98397_R2054_PCM_TX_HIZ_CTRL_8, 0xFF}, 234b5858113SRyan Lee {MAX98397_R2056_PCM_RX_SRC1, 0x00}, 235b5858113SRyan Lee {MAX98397_R2057_PCM_RX_SRC2, 0x00}, 236b5858113SRyan Lee {MAX98396_R2058_PCM_BYPASS_SRC, 0x00}, 237b5858113SRyan Lee {MAX98396_R205D_PCM_TX_SRC_EN, 0x00}, 238b5858113SRyan Lee {MAX98396_R205E_PCM_RX_EN, 0x00}, 239b5858113SRyan Lee {MAX98396_R205F_PCM_TX_EN, 0x00}, 240b5858113SRyan Lee {MAX98397_R2060_PCM_TX_SUPPLY_SEL, 0x00}, 241b5858113SRyan Lee {MAX98396_R2070_ICC_RX_EN_A, 0x00}, 242b5858113SRyan Lee {MAX98396_R2071_ICC_RX_EN_B, 0x00}, 243b5858113SRyan Lee {MAX98396_R2072_ICC_TX_CTRL, 0x00}, 244b5858113SRyan Lee {MAX98396_R207F_ICC_EN, 0x00}, 245b5858113SRyan Lee {MAX98396_R2083_TONE_GEN_DC_CFG, 0x04}, 246b5858113SRyan Lee {MAX98396_R2084_TONE_GEN_DC_LVL1, 0x00}, 247b5858113SRyan Lee {MAX98396_R2085_TONE_GEN_DC_LVL2, 0x00}, 248b5858113SRyan Lee {MAX98396_R2086_TONE_GEN_DC_LVL3, 0x00}, 249b5858113SRyan Lee {MAX98396_R208F_TONE_GEN_EN, 0x00}, 250b5858113SRyan Lee {MAX98396_R2090_AMP_VOL_CTRL, 0x00}, 251b5858113SRyan Lee {MAX98396_R2091_AMP_PATH_GAIN, 0x12}, 252b5858113SRyan Lee {MAX98396_R2092_AMP_DSP_CFG, 0x22}, 253b5858113SRyan Lee {MAX98396_R2093_SSM_CFG, 0x08}, 254b5858113SRyan Lee {MAX98396_R2094_SPK_CLS_DG_THRESH, 0x12}, 255b5858113SRyan Lee {MAX98396_R2095_SPK_CLS_DG_HDR, 0x17}, 256b5858113SRyan Lee {MAX98396_R2096_SPK_CLS_DG_HOLD_TIME, 0x17}, 257b5858113SRyan Lee {MAX98396_R2097_SPK_CLS_DG_DELAY, 0x00}, 258b5858113SRyan Lee {MAX98396_R2098_SPK_CLS_DG_MODE, 0x00}, 259b5858113SRyan Lee {MAX98396_R2099_SPK_CLS_DG_VBAT_LVL, 0x03}, 260b5858113SRyan Lee {MAX98396_R209A_SPK_EDGE_CTRL, 0x00}, 261b5858113SRyan Lee {MAX98397_R209B_SPK_PATH_WB_ONLY, 0x00}, 262b5858113SRyan Lee {MAX98396_R209C_SPK_EDGE_CTRL1, 0x03}, 263b5858113SRyan Lee {MAX98396_R209D_SPK_EDGE_CTRL2, 0xFC}, 264b5858113SRyan Lee {MAX98396_R209E_AMP_CLIP_GAIN, 0x00}, 265b5858113SRyan Lee {MAX98396_R209F_BYPASS_PATH_CFG, 0x00}, 266b5858113SRyan Lee {MAX98396_R20AF_AMP_EN, 0x00}, 267b5858113SRyan Lee {MAX98396_R20B0_ADC_SR, 0x30}, 268b5858113SRyan Lee {MAX98396_R20B1_ADC_PVDD_CFG, 0x00}, 269b5858113SRyan Lee {MAX98396_R20B2_ADC_VBAT_CFG, 0x00}, 270b5858113SRyan Lee {MAX98396_R20B3_ADC_THERMAL_CFG, 0x00}, 271b5858113SRyan Lee {MAX98397_R20B4_ADC_VDDH_CFG, 0x00}, 272b5858113SRyan Lee {MAX98397_R20B5_ADC_READBACK_CTRL1, 0x00}, 273b5858113SRyan Lee {MAX98397_R20B6_ADC_READBACK_CTRL2, 0x00}, 274b5858113SRyan Lee {MAX98397_R20B7_ADC_PVDD_READBACK_MSB, 0x00}, 275b5858113SRyan Lee {MAX98397_R20B8_ADC_PVDD_READBACK_LSB, 0x00}, 276b5858113SRyan Lee {MAX98397_R20B9_ADC_VBAT_READBACK_MSB, 0x00}, 277b5858113SRyan Lee {MAX98397_R20BA_ADC_VBAT_READBACK_LSB, 0x00}, 278b5858113SRyan Lee {MAX98397_R20BB_ADC_TEMP_READBACK_MSB, 0x00}, 279b5858113SRyan Lee {MAX98397_R20BC_ADC_TEMP_READBACK_LSB, 0x00}, 280b5858113SRyan Lee {MAX98397_R20BD_ADC_VDDH__READBACK_MSB, 0x00}, 281b5858113SRyan Lee {MAX98397_R20BE_ADC_VDDH_READBACK_LSB, 0x00}, 282b5858113SRyan Lee {MAX98396_R20BF_ADC_LO_VBAT_READBACK_LSB, 0x00}, 283b5858113SRyan Lee {MAX98397_R20C3_ADC_LO_VDDH_READBACK_MSB, 0x00}, 284b5858113SRyan Lee {MAX98397_R20C4_ADC_LO_VDDH_READBACK_LSB, 0x00}, 285b5858113SRyan Lee {MAX98397_R20C5_MEAS_ADC_OPTIMAL_MODE, 0x04}, 286b5858113SRyan Lee {MAX98396_R20C7_ADC_CFG, 0x00}, 287b5858113SRyan Lee {MAX98396_R20D0_DHT_CFG1, 0x00}, 288b5858113SRyan Lee {MAX98396_R20D1_LIMITER_CFG1, 0x08}, 289b5858113SRyan Lee {MAX98396_R20D2_LIMITER_CFG2, 0x00}, 290b5858113SRyan Lee {MAX98396_R20D3_DHT_CFG2, 0x14}, 291b5858113SRyan Lee {MAX98396_R20D4_DHT_CFG3, 0x02}, 292b5858113SRyan Lee {MAX98396_R20D5_DHT_CFG4, 0x04}, 293b5858113SRyan Lee {MAX98396_R20D6_DHT_HYSTERESIS_CFG, 0x07}, 294b5858113SRyan Lee {MAX98396_R20DF_DHT_EN, 0x00}, 295b5858113SRyan Lee {MAX98396_R20E0_IV_SENSE_PATH_CFG, 0x04}, 296b5858113SRyan Lee {MAX98396_R20E4_IV_SENSE_PATH_EN, 0x00}, 297b5858113SRyan Lee {MAX98396_R20E5_BPE_STATE, 0x00}, 298b5858113SRyan Lee {MAX98396_R20E6_BPE_L3_THRESH_MSB, 0x00}, 299b5858113SRyan Lee {MAX98396_R20E7_BPE_L3_THRESH_LSB, 0x00}, 300b5858113SRyan Lee {MAX98396_R20E8_BPE_L2_THRESH_MSB, 0x00}, 301b5858113SRyan Lee {MAX98396_R20E9_BPE_L2_THRESH_LSB, 0x00}, 302b5858113SRyan Lee {MAX98396_R20EA_BPE_L1_THRESH_MSB, 0x00}, 303b5858113SRyan Lee {MAX98396_R20EB_BPE_L1_THRESH_LSB, 0x00}, 304b5858113SRyan Lee {MAX98396_R20EC_BPE_L0_THRESH_MSB, 0x00}, 305b5858113SRyan Lee {MAX98396_R20ED_BPE_L0_THRESH_LSB, 0x00}, 306b5858113SRyan Lee {MAX98396_R20EE_BPE_L3_DWELL_HOLD_TIME, 0x00}, 307b5858113SRyan Lee {MAX98396_R20EF_BPE_L2_DWELL_HOLD_TIME, 0x00}, 308b5858113SRyan Lee {MAX98396_R20F0_BPE_L1_DWELL_HOLD_TIME, 0x00}, 309b5858113SRyan Lee {MAX98396_R20F1_BPE_L0_HOLD_TIME, 0x00}, 310b5858113SRyan Lee {MAX98396_R20F2_BPE_L3_ATTACK_REL_STEP, 0x00}, 311b5858113SRyan Lee {MAX98396_R20F3_BPE_L2_ATTACK_REL_STEP, 0x00}, 312b5858113SRyan Lee {MAX98396_R20F4_BPE_L1_ATTACK_REL_STEP, 0x00}, 313b5858113SRyan Lee {MAX98396_R20F5_BPE_L0_ATTACK_REL_STEP, 0x00}, 314b5858113SRyan Lee {MAX98396_R20F6_BPE_L3_MAX_GAIN_ATTN, 0x00}, 315b5858113SRyan Lee {MAX98396_R20F7_BPE_L2_MAX_GAIN_ATTN, 0x00}, 316b5858113SRyan Lee {MAX98396_R20F8_BPE_L1_MAX_GAIN_ATTN, 0x00}, 317b5858113SRyan Lee {MAX98396_R20F9_BPE_L0_MAX_GAIN_ATTN, 0x00}, 318b5858113SRyan Lee {MAX98396_R20FA_BPE_L3_ATT_REL_RATE, 0x00}, 319b5858113SRyan Lee {MAX98396_R20FB_BPE_L2_ATT_REL_RATE, 0x00}, 320b5858113SRyan Lee {MAX98396_R20FC_BPE_L1_ATT_REL_RATE, 0x00}, 321b5858113SRyan Lee {MAX98396_R20FD_BPE_L0_ATT_REL_RATE, 0x00}, 322b5858113SRyan Lee {MAX98396_R20FE_BPE_L3_LIMITER_CFG, 0x00}, 323b5858113SRyan Lee {MAX98396_R20FF_BPE_L2_LIMITER_CFG, 0x00}, 324b5858113SRyan Lee {MAX98396_R2100_BPE_L1_LIMITER_CFG, 0x00}, 325b5858113SRyan Lee {MAX98396_R2101_BPE_L0_LIMITER_CFG, 0x00}, 326b5858113SRyan Lee {MAX98396_R2102_BPE_L3_LIM_ATT_REL_RATE, 0x00}, 327b5858113SRyan Lee {MAX98396_R2103_BPE_L2_LIM_ATT_REL_RATE, 0x00}, 328b5858113SRyan Lee {MAX98396_R2104_BPE_L1_LIM_ATT_REL_RATE, 0x00}, 329b5858113SRyan Lee {MAX98396_R2105_BPE_L0_LIM_ATT_REL_RATE, 0x00}, 330b5858113SRyan Lee {MAX98396_R2106_BPE_THRESH_HYSTERESIS, 0x00}, 331b5858113SRyan Lee {MAX98396_R2107_BPE_INFINITE_HOLD_CLR, 0x00}, 332b5858113SRyan Lee {MAX98396_R2108_BPE_SUPPLY_SRC, 0x00}, 333b5858113SRyan Lee {MAX98396_R2109_BPE_LOW_STATE, 0x00}, 334b5858113SRyan Lee {MAX98396_R210A_BPE_LOW_GAIN, 0x00}, 335b5858113SRyan Lee {MAX98396_R210B_BPE_LOW_LIMITER, 0x00}, 336b5858113SRyan Lee {MAX98396_R210D_BPE_EN, 0x00}, 337b5858113SRyan Lee {MAX98396_R210E_AUTO_RESTART, 0x00}, 338b5858113SRyan Lee {MAX98396_R210F_GLOBAL_EN, 0x00}, 339b5858113SRyan Lee {MAX98397_R22FF_REVISION_ID, 0x00}, 340b5858113SRyan Lee }; 341b5858113SRyan Lee 342b5858113SRyan Lee static void max98396_global_enable_onoff(struct regmap *regmap, bool onoff) 343b5858113SRyan Lee { 344b5858113SRyan Lee regmap_write(regmap, MAX98396_R210F_GLOBAL_EN, onoff ? 1 : 0); 345b5858113SRyan Lee usleep_range(11000, 12000); 346b5858113SRyan Lee } 347b5858113SRyan Lee 348b5858113SRyan Lee static int max98396_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) 349b5858113SRyan Lee { 350b5858113SRyan Lee struct snd_soc_component *component = codec_dai->component; 351b5858113SRyan Lee struct max98396_priv *max98396 = snd_soc_component_get_drvdata(component); 352c529fd62SDaniel Mack unsigned int format_mask, format = 0; 353b5858113SRyan Lee unsigned int bclk_pol = 0; 354b5858113SRyan Lee int ret, status; 355b5858113SRyan Lee int reg; 356b5858113SRyan Lee bool update = false; 357b5858113SRyan Lee 358c529fd62SDaniel Mack format_mask = MAX98396_PCM_MODE_CFG_FORMAT_MASK | 359c529fd62SDaniel Mack MAX98396_PCM_MODE_CFG_LRCLKEDGE; 360c529fd62SDaniel Mack 361b5858113SRyan Lee dev_dbg(component->dev, "%s: fmt 0x%08X\n", __func__, fmt); 362b5858113SRyan Lee 363b5858113SRyan Lee switch (fmt & SND_SOC_DAIFMT_INV_MASK) { 364b5858113SRyan Lee case SND_SOC_DAIFMT_NB_NF: 365b5858113SRyan Lee break; 366b5858113SRyan Lee case SND_SOC_DAIFMT_NB_IF: 367b5858113SRyan Lee format = MAX98396_PCM_MODE_CFG_LRCLKEDGE; 368b5858113SRyan Lee break; 369b5858113SRyan Lee case SND_SOC_DAIFMT_IB_NF: 370b5858113SRyan Lee bclk_pol = MAX98396_PCM_MODE_CFG_BCLKEDGE; 371b5858113SRyan Lee break; 372b5858113SRyan Lee case SND_SOC_DAIFMT_IB_IF: 373b5858113SRyan Lee bclk_pol = MAX98396_PCM_MODE_CFG_BCLKEDGE; 374b5858113SRyan Lee format = MAX98396_PCM_MODE_CFG_LRCLKEDGE; 375b5858113SRyan Lee break; 376b5858113SRyan Lee 377b5858113SRyan Lee default: 378a8c1dc9eSDaniel Mack dev_err(component->dev, "DAI invert mode %d unsupported\n", 379a8c1dc9eSDaniel Mack fmt & SND_SOC_DAIFMT_INV_MASK); 380b5858113SRyan Lee return -EINVAL; 381b5858113SRyan Lee } 382b5858113SRyan Lee 383b5858113SRyan Lee /* interface format */ 384b5858113SRyan Lee switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 385b5858113SRyan Lee case SND_SOC_DAIFMT_I2S: 386b5858113SRyan Lee format |= MAX98396_PCM_FORMAT_I2S; 387b5858113SRyan Lee break; 388b5858113SRyan Lee case SND_SOC_DAIFMT_LEFT_J: 389b5858113SRyan Lee format |= MAX98396_PCM_FORMAT_LJ; 390b5858113SRyan Lee break; 391b5858113SRyan Lee case SND_SOC_DAIFMT_DSP_A: 392b5858113SRyan Lee format |= MAX98396_PCM_FORMAT_TDM_MODE1; 393b5858113SRyan Lee break; 394b5858113SRyan Lee case SND_SOC_DAIFMT_DSP_B: 395b5858113SRyan Lee format |= MAX98396_PCM_FORMAT_TDM_MODE0; 396b5858113SRyan Lee break; 397b5858113SRyan Lee default: 398a8c1dc9eSDaniel Mack dev_err(component->dev, "DAI format %d unsupported\n", 399a8c1dc9eSDaniel Mack fmt & SND_SOC_DAIFMT_FORMAT_MASK); 400b5858113SRyan Lee return -EINVAL; 401b5858113SRyan Lee } 402b5858113SRyan Lee 403b5858113SRyan Lee ret = regmap_read(max98396->regmap, MAX98396_R210F_GLOBAL_EN, &status); 404b5858113SRyan Lee if (ret < 0) 405b5858113SRyan Lee return -EINVAL; 406b5858113SRyan Lee 407b5858113SRyan Lee if (status) { 408b5858113SRyan Lee ret = regmap_read(max98396->regmap, MAX98396_R2041_PCM_MODE_CFG, ®); 409b5858113SRyan Lee if (ret < 0) 410b5858113SRyan Lee return -EINVAL; 411c529fd62SDaniel Mack if (format != (reg & format_mask)) { 412b5858113SRyan Lee update = true; 413b5858113SRyan Lee } else { 414b5858113SRyan Lee ret = regmap_read(max98396->regmap, 415b5858113SRyan Lee MAX98396_R2042_PCM_CLK_SETUP, ®); 416b5858113SRyan Lee if (ret < 0) 417b5858113SRyan Lee return -EINVAL; 418b5858113SRyan Lee if (bclk_pol != (reg & MAX98396_PCM_MODE_CFG_BCLKEDGE)) 419b5858113SRyan Lee update = true; 420b5858113SRyan Lee } 421b5858113SRyan Lee /* GLOBAL_EN OFF prior to pcm mode, clock configuration change */ 422b5858113SRyan Lee if (update) 423b5858113SRyan Lee max98396_global_enable_onoff(max98396->regmap, false); 424b5858113SRyan Lee } 425b5858113SRyan Lee 426b5858113SRyan Lee regmap_update_bits(max98396->regmap, 427b5858113SRyan Lee MAX98396_R2041_PCM_MODE_CFG, 428c529fd62SDaniel Mack format_mask, format); 429b5858113SRyan Lee 430b5858113SRyan Lee regmap_update_bits(max98396->regmap, 431b5858113SRyan Lee MAX98396_R2042_PCM_CLK_SETUP, 432b5858113SRyan Lee MAX98396_PCM_MODE_CFG_BCLKEDGE, 433b5858113SRyan Lee bclk_pol); 434b5858113SRyan Lee 435b5858113SRyan Lee if (status && update) 436b5858113SRyan Lee max98396_global_enable_onoff(max98396->regmap, true); 437b5858113SRyan Lee 438b5858113SRyan Lee return 0; 439b5858113SRyan Lee } 440b5858113SRyan Lee 441*d29e0a6eSDaniel Mack #define MAX98396_BSEL_32 0x2 442*d29e0a6eSDaniel Mack #define MAX98396_BSEL_48 0x3 443*d29e0a6eSDaniel Mack #define MAX98396_BSEL_64 0x4 444*d29e0a6eSDaniel Mack #define MAX98396_BSEL_96 0x5 445*d29e0a6eSDaniel Mack #define MAX98396_BSEL_128 0x6 446*d29e0a6eSDaniel Mack #define MAX98396_BSEL_192 0x7 447*d29e0a6eSDaniel Mack #define MAX98396_BSEL_256 0x8 448*d29e0a6eSDaniel Mack #define MAX98396_BSEL_384 0x9 449*d29e0a6eSDaniel Mack #define MAX98396_BSEL_512 0xa 450*d29e0a6eSDaniel Mack #define MAX98396_BSEL_320 0xb 451*d29e0a6eSDaniel Mack #define MAX98396_BSEL_250 0xc 452*d29e0a6eSDaniel Mack #define MAX98396_BSEL_125 0xd 453*d29e0a6eSDaniel Mack 454*d29e0a6eSDaniel Mack /* Refer to table 5 in the datasheet */ 455*d29e0a6eSDaniel Mack static const struct max98396_pcm_config { 456*d29e0a6eSDaniel Mack int in, out, width, bsel, max_sr; 457*d29e0a6eSDaniel Mack } max98396_pcm_configs[] = { 458*d29e0a6eSDaniel Mack { .in = 2, .out = 4, .width = 16, .bsel = MAX98396_BSEL_32, .max_sr = 192000 }, 459*d29e0a6eSDaniel Mack { .in = 2, .out = 6, .width = 24, .bsel = MAX98396_BSEL_48, .max_sr = 192000 }, 460*d29e0a6eSDaniel Mack { .in = 2, .out = 8, .width = 32, .bsel = MAX98396_BSEL_64, .max_sr = 192000 }, 461*d29e0a6eSDaniel Mack { .in = 3, .out = 15, .width = 32, .bsel = MAX98396_BSEL_125, .max_sr = 192000 }, 462*d29e0a6eSDaniel Mack { .in = 4, .out = 8, .width = 16, .bsel = MAX98396_BSEL_64, .max_sr = 192000 }, 463*d29e0a6eSDaniel Mack { .in = 4, .out = 12, .width = 24, .bsel = MAX98396_BSEL_96, .max_sr = 192000 }, 464*d29e0a6eSDaniel Mack { .in = 4, .out = 16, .width = 32, .bsel = MAX98396_BSEL_128, .max_sr = 192000 }, 465*d29e0a6eSDaniel Mack { .in = 5, .out = 15, .width = 24, .bsel = MAX98396_BSEL_125, .max_sr = 192000 }, 466*d29e0a6eSDaniel Mack { .in = 7, .out = 15, .width = 16, .bsel = MAX98396_BSEL_125, .max_sr = 192000 }, 467*d29e0a6eSDaniel Mack { .in = 2, .out = 4, .width = 16, .bsel = MAX98396_BSEL_32, .max_sr = 96000 }, 468*d29e0a6eSDaniel Mack { .in = 2, .out = 6, .width = 24, .bsel = MAX98396_BSEL_48, .max_sr = 96000 }, 469*d29e0a6eSDaniel Mack { .in = 2, .out = 8, .width = 32, .bsel = MAX98396_BSEL_64, .max_sr = 96000 }, 470*d29e0a6eSDaniel Mack { .in = 3, .out = 15, .width = 32, .bsel = MAX98396_BSEL_125, .max_sr = 96000 }, 471*d29e0a6eSDaniel Mack { .in = 4, .out = 8, .width = 16, .bsel = MAX98396_BSEL_64, .max_sr = 96000 }, 472*d29e0a6eSDaniel Mack { .in = 4, .out = 12, .width = 24, .bsel = MAX98396_BSEL_96, .max_sr = 96000 }, 473*d29e0a6eSDaniel Mack { .in = 4, .out = 16, .width = 32, .bsel = MAX98396_BSEL_128, .max_sr = 96000 }, 474*d29e0a6eSDaniel Mack { .in = 5, .out = 15, .width = 24, .bsel = MAX98396_BSEL_125, .max_sr = 96000 }, 475*d29e0a6eSDaniel Mack { .in = 7, .out = 15, .width = 16, .bsel = MAX98396_BSEL_125, .max_sr = 96000 }, 476*d29e0a6eSDaniel Mack { .in = 7, .out = 31, .width = 32, .bsel = MAX98396_BSEL_250, .max_sr = 96000 }, 477*d29e0a6eSDaniel Mack { .in = 8, .out = 16, .width = 16, .bsel = MAX98396_BSEL_128, .max_sr = 96000 }, 478*d29e0a6eSDaniel Mack { .in = 8, .out = 24, .width = 24, .bsel = MAX98396_BSEL_192, .max_sr = 96000 }, 479*d29e0a6eSDaniel Mack { .in = 8, .out = 32, .width = 32, .bsel = MAX98396_BSEL_256, .max_sr = 96000 }, 480*d29e0a6eSDaniel Mack { .in = 10, .out = 31, .width = 24, .bsel = MAX98396_BSEL_250, .max_sr = 96000 }, 481*d29e0a6eSDaniel Mack { .in = 15, .out = 31, .width = 16, .bsel = MAX98396_BSEL_250, .max_sr = 96000 }, 482*d29e0a6eSDaniel Mack { .in = 16, .out = 32, .width = 16, .bsel = MAX98396_BSEL_256, .max_sr = 96000 }, 483*d29e0a6eSDaniel Mack { .in = 7, .out = 31, .width = 32, .bsel = MAX98396_BSEL_250, .max_sr = 48000 }, 484*d29e0a6eSDaniel Mack { .in = 10, .out = 31, .width = 24, .bsel = MAX98396_BSEL_250, .max_sr = 48000 }, 485*d29e0a6eSDaniel Mack { .in = 10, .out = 40, .width = 32, .bsel = MAX98396_BSEL_320, .max_sr = 48000 }, 486*d29e0a6eSDaniel Mack { .in = 15, .out = 31, .width = 16, .bsel = MAX98396_BSEL_250, .max_sr = 48000 }, 487*d29e0a6eSDaniel Mack { .in = 16, .out = 48, .width = 24, .bsel = MAX98396_BSEL_384, .max_sr = 48000 }, 488*d29e0a6eSDaniel Mack { .in = 16, .out = 64, .width = 32, .bsel = MAX98396_BSEL_512, .max_sr = 48000 }, 489b5858113SRyan Lee }; 490b5858113SRyan Lee 491*d29e0a6eSDaniel Mack static int max98396_pcm_config_index(int in_slots, int out_slots, int width) 492b5858113SRyan Lee { 493b5858113SRyan Lee int i; 494*d29e0a6eSDaniel Mack 495*d29e0a6eSDaniel Mack for (i = 0; i < ARRAY_SIZE(max98396_pcm_configs); i++) { 496*d29e0a6eSDaniel Mack const struct max98396_pcm_config *c = &max98396_pcm_configs[i]; 497*d29e0a6eSDaniel Mack 498*d29e0a6eSDaniel Mack if (in_slots == c->in && out_slots <= c->out && width == c->width) 499*d29e0a6eSDaniel Mack return i; 500b5858113SRyan Lee } 501b5858113SRyan Lee 502*d29e0a6eSDaniel Mack return -1; 503b5858113SRyan Lee } 504b5858113SRyan Lee 505b5858113SRyan Lee static int max98396_dai_hw_params(struct snd_pcm_substream *substream, 506b5858113SRyan Lee struct snd_pcm_hw_params *params, 507b5858113SRyan Lee struct snd_soc_dai *dai) 508b5858113SRyan Lee { 509b5858113SRyan Lee struct snd_soc_component *component = dai->component; 510b5858113SRyan Lee struct max98396_priv *max98396 = snd_soc_component_get_drvdata(component); 511b5858113SRyan Lee unsigned int sampling_rate = 0; 512b5858113SRyan Lee unsigned int chan_sz = 0; 513*d29e0a6eSDaniel Mack int ret, reg, status, bsel = 0; 514b5858113SRyan Lee bool update = false; 515b5858113SRyan Lee 516b5858113SRyan Lee /* pcm mode configuration */ 517b5858113SRyan Lee switch (snd_pcm_format_width(params_format(params))) { 518b5858113SRyan Lee case 16: 519b5858113SRyan Lee chan_sz = MAX98396_PCM_MODE_CFG_CHANSZ_16; 520b5858113SRyan Lee break; 521b5858113SRyan Lee case 24: 522b5858113SRyan Lee chan_sz = MAX98396_PCM_MODE_CFG_CHANSZ_24; 523b5858113SRyan Lee break; 524b5858113SRyan Lee case 32: 525b5858113SRyan Lee chan_sz = MAX98396_PCM_MODE_CFG_CHANSZ_32; 526b5858113SRyan Lee break; 527b5858113SRyan Lee default: 528b5858113SRyan Lee dev_err(component->dev, "format unsupported %d\n", 529b5858113SRyan Lee params_format(params)); 530b5858113SRyan Lee goto err; 531b5858113SRyan Lee } 532b5858113SRyan Lee 533b5858113SRyan Lee dev_dbg(component->dev, "format supported %d", 534b5858113SRyan Lee params_format(params)); 535b5858113SRyan Lee 536b5858113SRyan Lee /* sampling rate configuration */ 537b5858113SRyan Lee switch (params_rate(params)) { 538b5858113SRyan Lee case 8000: 539b5858113SRyan Lee sampling_rate = MAX98396_PCM_SR_8000; 540b5858113SRyan Lee break; 541b5858113SRyan Lee case 11025: 542b5858113SRyan Lee sampling_rate = MAX98396_PCM_SR_11025; 543b5858113SRyan Lee break; 544b5858113SRyan Lee case 12000: 545b5858113SRyan Lee sampling_rate = MAX98396_PCM_SR_12000; 546b5858113SRyan Lee break; 547b5858113SRyan Lee case 16000: 548b5858113SRyan Lee sampling_rate = MAX98396_PCM_SR_16000; 549b5858113SRyan Lee break; 550b5858113SRyan Lee case 22050: 551b5858113SRyan Lee sampling_rate = MAX98396_PCM_SR_22050; 552b5858113SRyan Lee break; 553b5858113SRyan Lee case 24000: 554b5858113SRyan Lee sampling_rate = MAX98396_PCM_SR_24000; 555b5858113SRyan Lee break; 556b5858113SRyan Lee case 32000: 557b5858113SRyan Lee sampling_rate = MAX98396_PCM_SR_32000; 558b5858113SRyan Lee break; 559b5858113SRyan Lee case 44100: 560b5858113SRyan Lee sampling_rate = MAX98396_PCM_SR_44100; 561b5858113SRyan Lee break; 562b5858113SRyan Lee case 48000: 563b5858113SRyan Lee sampling_rate = MAX98396_PCM_SR_48000; 564b5858113SRyan Lee break; 565b5858113SRyan Lee case 88200: 566b5858113SRyan Lee sampling_rate = MAX98396_PCM_SR_88200; 567b5858113SRyan Lee break; 568b5858113SRyan Lee case 96000: 569b5858113SRyan Lee sampling_rate = MAX98396_PCM_SR_96000; 570b5858113SRyan Lee break; 571b5858113SRyan Lee case 192000: 572b5858113SRyan Lee sampling_rate = MAX98396_PCM_SR_192000; 573b5858113SRyan Lee break; 574b5858113SRyan Lee default: 575b5858113SRyan Lee dev_err(component->dev, "rate %d not supported\n", 576b5858113SRyan Lee params_rate(params)); 577b5858113SRyan Lee goto err; 578b5858113SRyan Lee } 579b5858113SRyan Lee 580*d29e0a6eSDaniel Mack if (max98396->tdm_mode) { 581*d29e0a6eSDaniel Mack if (params_rate(params) > max98396->tdm_max_samplerate) { 582*d29e0a6eSDaniel Mack dev_err(component->dev, "TDM sample rate %d too high", 583*d29e0a6eSDaniel Mack params_rate(params)); 584*d29e0a6eSDaniel Mack goto err; 585*d29e0a6eSDaniel Mack } 586*d29e0a6eSDaniel Mack } else { 587*d29e0a6eSDaniel Mack /* BCLK configuration */ 588*d29e0a6eSDaniel Mack ret = max98396_pcm_config_index(params_channels(params), 589*d29e0a6eSDaniel Mack params_channels(params), 590*d29e0a6eSDaniel Mack snd_pcm_format_width(params_format(params))); 591*d29e0a6eSDaniel Mack if (ret < 0) { 592*d29e0a6eSDaniel Mack dev_err(component->dev, 593*d29e0a6eSDaniel Mack "no PCM config for %d channels, format %d\n", 594*d29e0a6eSDaniel Mack params_channels(params), params_format(params)); 595*d29e0a6eSDaniel Mack goto err; 596*d29e0a6eSDaniel Mack } 597*d29e0a6eSDaniel Mack 598*d29e0a6eSDaniel Mack bsel = max98396_pcm_configs[ret].bsel; 599*d29e0a6eSDaniel Mack 600*d29e0a6eSDaniel Mack if (params_rate(params) > max98396_pcm_configs[ret].max_sr) { 601*d29e0a6eSDaniel Mack dev_err(component->dev, "sample rate %d too high", 602*d29e0a6eSDaniel Mack params_rate(params)); 603*d29e0a6eSDaniel Mack goto err; 604*d29e0a6eSDaniel Mack } 605*d29e0a6eSDaniel Mack } 606*d29e0a6eSDaniel Mack 607b5858113SRyan Lee ret = regmap_read(max98396->regmap, MAX98396_R210F_GLOBAL_EN, &status); 608b5858113SRyan Lee if (ret < 0) 609b5858113SRyan Lee goto err; 610b5858113SRyan Lee 611b5858113SRyan Lee if (status) { 612b5858113SRyan Lee ret = regmap_read(max98396->regmap, MAX98396_R2041_PCM_MODE_CFG, ®); 613b5858113SRyan Lee if (ret < 0) 614b5858113SRyan Lee goto err; 615b5858113SRyan Lee if (chan_sz != (reg & MAX98396_PCM_MODE_CFG_CHANSZ_MASK)) { 616b5858113SRyan Lee update = true; 617b5858113SRyan Lee } else { 618b5858113SRyan Lee ret = regmap_read(max98396->regmap, MAX98396_R2043_PCM_SR_SETUP, ®); 619b5858113SRyan Lee if (ret < 0) 620b5858113SRyan Lee goto err; 621b5858113SRyan Lee if (sampling_rate != (reg & MAX98396_PCM_SR_MASK)) 622b5858113SRyan Lee update = true; 623b5858113SRyan Lee } 624b5858113SRyan Lee 625b5858113SRyan Lee /* GLOBAL_EN OFF prior to channel size and sampling rate change */ 626b5858113SRyan Lee if (update) 627b5858113SRyan Lee max98396_global_enable_onoff(max98396->regmap, false); 628b5858113SRyan Lee } 629b5858113SRyan Lee 630b5858113SRyan Lee /* set channel size */ 631b5858113SRyan Lee regmap_update_bits(max98396->regmap, MAX98396_R2041_PCM_MODE_CFG, 632b5858113SRyan Lee MAX98396_PCM_MODE_CFG_CHANSZ_MASK, chan_sz); 633b5858113SRyan Lee 634b5858113SRyan Lee /* set DAI_SR to correct LRCLK frequency */ 635b5858113SRyan Lee regmap_update_bits(max98396->regmap, MAX98396_R2043_PCM_SR_SETUP, 636b5858113SRyan Lee MAX98396_PCM_SR_MASK, sampling_rate); 637b5858113SRyan Lee 638b5858113SRyan Lee /* set sampling rate of IV */ 639b5858113SRyan Lee if (max98396->interleave_mode && 640b5858113SRyan Lee sampling_rate > MAX98396_PCM_SR_16000) 641b5858113SRyan Lee regmap_update_bits(max98396->regmap, 642b5858113SRyan Lee MAX98396_R2043_PCM_SR_SETUP, 643b5858113SRyan Lee MAX98396_IVADC_SR_MASK, 644b5858113SRyan Lee (sampling_rate - 3) 645b5858113SRyan Lee << MAX98396_IVADC_SR_SHIFT); 646b5858113SRyan Lee else 647b5858113SRyan Lee regmap_update_bits(max98396->regmap, 648b5858113SRyan Lee MAX98396_R2043_PCM_SR_SETUP, 649b5858113SRyan Lee MAX98396_IVADC_SR_MASK, 650b5858113SRyan Lee sampling_rate << MAX98396_IVADC_SR_SHIFT); 651b5858113SRyan Lee 652*d29e0a6eSDaniel Mack if (bsel) 653*d29e0a6eSDaniel Mack regmap_update_bits(max98396->regmap, 654*d29e0a6eSDaniel Mack MAX98396_R2042_PCM_CLK_SETUP, 655*d29e0a6eSDaniel Mack MAX98396_PCM_CLK_SETUP_BSEL_MASK, 656*d29e0a6eSDaniel Mack bsel); 657b5858113SRyan Lee 658b5858113SRyan Lee if (status && update) 659b5858113SRyan Lee max98396_global_enable_onoff(max98396->regmap, true); 660b5858113SRyan Lee 661*d29e0a6eSDaniel Mack return 0; 662b5858113SRyan Lee 663b5858113SRyan Lee err: 664b5858113SRyan Lee return -EINVAL; 665b5858113SRyan Lee } 666b5858113SRyan Lee 667b5858113SRyan Lee static int max98396_dai_tdm_slot(struct snd_soc_dai *dai, 668b5858113SRyan Lee unsigned int tx_mask, unsigned int rx_mask, 669b5858113SRyan Lee int slots, int slot_width) 670b5858113SRyan Lee { 671b5858113SRyan Lee struct snd_soc_component *component = dai->component; 672b5858113SRyan Lee struct max98396_priv *max98396 = 673b5858113SRyan Lee snd_soc_component_get_drvdata(component); 674b5858113SRyan Lee int bsel; 675b5858113SRyan Lee unsigned int chan_sz = 0; 676b5858113SRyan Lee int ret, status; 677b5858113SRyan Lee int reg; 678b5858113SRyan Lee bool update = false; 679b5858113SRyan Lee 680b5858113SRyan Lee if (!tx_mask && !rx_mask && !slots && !slot_width) 681b5858113SRyan Lee max98396->tdm_mode = false; 682b5858113SRyan Lee else 683b5858113SRyan Lee max98396->tdm_mode = true; 684b5858113SRyan Lee 685b5858113SRyan Lee /* BCLK configuration */ 686*d29e0a6eSDaniel Mack ret = max98396_pcm_config_index(slots, slots, slot_width); 687*d29e0a6eSDaniel Mack if (ret < 0) { 688*d29e0a6eSDaniel Mack dev_err(component->dev, "no TDM config for %d slots %d bits\n", 689*d29e0a6eSDaniel Mack slots, slot_width); 690b5858113SRyan Lee return -EINVAL; 691b5858113SRyan Lee } 692b5858113SRyan Lee 693*d29e0a6eSDaniel Mack bsel = max98396_pcm_configs[ret].bsel; 694*d29e0a6eSDaniel Mack max98396->tdm_max_samplerate = max98396_pcm_configs[ret].max_sr; 695*d29e0a6eSDaniel Mack 696b5858113SRyan Lee /* Channel size configuration */ 697b5858113SRyan Lee switch (slot_width) { 698b5858113SRyan Lee case 16: 699b5858113SRyan Lee chan_sz = MAX98396_PCM_MODE_CFG_CHANSZ_16; 700b5858113SRyan Lee break; 701b5858113SRyan Lee case 24: 702b5858113SRyan Lee chan_sz = MAX98396_PCM_MODE_CFG_CHANSZ_24; 703b5858113SRyan Lee break; 704b5858113SRyan Lee case 32: 705b5858113SRyan Lee chan_sz = MAX98396_PCM_MODE_CFG_CHANSZ_32; 706b5858113SRyan Lee break; 707b5858113SRyan Lee default: 708a8c1dc9eSDaniel Mack dev_err(component->dev, "slot width %d unsupported\n", 709b5858113SRyan Lee slot_width); 710b5858113SRyan Lee return -EINVAL; 711b5858113SRyan Lee } 712b5858113SRyan Lee 713b5858113SRyan Lee ret = regmap_read(max98396->regmap, MAX98396_R210F_GLOBAL_EN, &status); 714b5858113SRyan Lee if (ret < 0) 715b5858113SRyan Lee return -EINVAL; 716b5858113SRyan Lee 717b5858113SRyan Lee if (status) { 718b5858113SRyan Lee ret = regmap_read(max98396->regmap, MAX98396_R2042_PCM_CLK_SETUP, ®); 719b5858113SRyan Lee if (ret < 0) 720b5858113SRyan Lee return -EINVAL; 721b5858113SRyan Lee if (bsel != (reg & MAX98396_PCM_CLK_SETUP_BSEL_MASK)) { 722b5858113SRyan Lee update = true; 723b5858113SRyan Lee } else { 724b5858113SRyan Lee ret = regmap_read(max98396->regmap, MAX98396_R2041_PCM_MODE_CFG, ®); 725b5858113SRyan Lee if (ret < 0) 726b5858113SRyan Lee return -EINVAL; 727b5858113SRyan Lee if (chan_sz != (reg & MAX98396_PCM_MODE_CFG_CHANSZ_MASK)) 728b5858113SRyan Lee update = true; 729b5858113SRyan Lee } 730b5858113SRyan Lee 731b5858113SRyan Lee /* GLOBAL_EN OFF prior to channel size and BCLK per LRCLK change */ 732b5858113SRyan Lee if (update) 733b5858113SRyan Lee max98396_global_enable_onoff(max98396->regmap, false); 734b5858113SRyan Lee } 735b5858113SRyan Lee 736b5858113SRyan Lee regmap_update_bits(max98396->regmap, 737b5858113SRyan Lee MAX98396_R2042_PCM_CLK_SETUP, 738b5858113SRyan Lee MAX98396_PCM_CLK_SETUP_BSEL_MASK, 739b5858113SRyan Lee bsel); 740b5858113SRyan Lee 741b5858113SRyan Lee regmap_update_bits(max98396->regmap, 742b5858113SRyan Lee MAX98396_R2041_PCM_MODE_CFG, 743b5858113SRyan Lee MAX98396_PCM_MODE_CFG_CHANSZ_MASK, chan_sz); 744b5858113SRyan Lee 745b5858113SRyan Lee /* Rx slot configuration */ 746b5858113SRyan Lee if (max98396->device_id == CODEC_TYPE_MAX98396) { 747b5858113SRyan Lee regmap_update_bits(max98396->regmap, 748b5858113SRyan Lee MAX98396_R2056_PCM_RX_SRC2, 749b5858113SRyan Lee MAX98396_PCM_DMIX_CH0_SRC_MASK, 750b5858113SRyan Lee rx_mask); 751b5858113SRyan Lee regmap_update_bits(max98396->regmap, 752b5858113SRyan Lee MAX98396_R2056_PCM_RX_SRC2, 753b5858113SRyan Lee MAX98396_PCM_DMIX_CH1_SRC_MASK, 754b5858113SRyan Lee rx_mask << MAX98396_PCM_DMIX_CH1_SHIFT); 755b5858113SRyan Lee } else { 756b5858113SRyan Lee regmap_update_bits(max98396->regmap, 757b5858113SRyan Lee MAX98397_R2057_PCM_RX_SRC2, 758b5858113SRyan Lee MAX98396_PCM_DMIX_CH0_SRC_MASK, 759b5858113SRyan Lee rx_mask); 760b5858113SRyan Lee regmap_update_bits(max98396->regmap, 761b5858113SRyan Lee MAX98397_R2057_PCM_RX_SRC2, 762b5858113SRyan Lee MAX98396_PCM_DMIX_CH1_SRC_MASK, 763b5858113SRyan Lee rx_mask << MAX98396_PCM_DMIX_CH1_SHIFT); 764b5858113SRyan Lee } 765b5858113SRyan Lee 766b5858113SRyan Lee /* Tx slot Hi-Z configuration */ 767b5858113SRyan Lee if (max98396->device_id == CODEC_TYPE_MAX98396) { 768b5858113SRyan Lee regmap_write(max98396->regmap, 769b5858113SRyan Lee MAX98396_R2053_PCM_TX_HIZ_CTRL_8, 770b5858113SRyan Lee ~tx_mask & 0xFF); 771b5858113SRyan Lee regmap_write(max98396->regmap, 772b5858113SRyan Lee MAX98396_R2052_PCM_TX_HIZ_CTRL_7, 773b5858113SRyan Lee (~tx_mask & 0xFF00) >> 8); 774b5858113SRyan Lee } else { 775b5858113SRyan Lee regmap_write(max98396->regmap, 776b5858113SRyan Lee MAX98397_R2054_PCM_TX_HIZ_CTRL_8, 777b5858113SRyan Lee ~tx_mask & 0xFF); 778b5858113SRyan Lee regmap_write(max98396->regmap, 779b5858113SRyan Lee MAX98397_R2053_PCM_TX_HIZ_CTRL_7, 780b5858113SRyan Lee (~tx_mask & 0xFF00) >> 8); 781b5858113SRyan Lee } 782b5858113SRyan Lee 783b5858113SRyan Lee if (status && update) 784b5858113SRyan Lee max98396_global_enable_onoff(max98396->regmap, true); 785b5858113SRyan Lee 786b5858113SRyan Lee return 0; 787b5858113SRyan Lee } 788b5858113SRyan Lee 789b5858113SRyan Lee #define MAX98396_RATES SNDRV_PCM_RATE_8000_192000 790b5858113SRyan Lee 791b5858113SRyan Lee #define MAX98396_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ 792b5858113SRyan Lee SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) 793b5858113SRyan Lee 794b5858113SRyan Lee static const struct snd_soc_dai_ops max98396_dai_ops = { 795b5858113SRyan Lee .set_fmt = max98396_dai_set_fmt, 796b5858113SRyan Lee .hw_params = max98396_dai_hw_params, 797b5858113SRyan Lee .set_tdm_slot = max98396_dai_tdm_slot, 798b5858113SRyan Lee }; 799b5858113SRyan Lee 800b5858113SRyan Lee static int max98396_dac_event(struct snd_soc_dapm_widget *w, 801b5858113SRyan Lee struct snd_kcontrol *kcontrol, int event) 802b5858113SRyan Lee { 803b5858113SRyan Lee struct snd_soc_component *component = 804b5858113SRyan Lee snd_soc_dapm_to_component(w->dapm); 805b5858113SRyan Lee struct max98396_priv *max98396 = 806b5858113SRyan Lee snd_soc_component_get_drvdata(component); 807b5858113SRyan Lee 808b5858113SRyan Lee switch (event) { 809b5858113SRyan Lee case SND_SOC_DAPM_POST_PMU: 810b5858113SRyan Lee max98396_global_enable_onoff(max98396->regmap, true); 811b5858113SRyan Lee break; 812b5858113SRyan Lee case SND_SOC_DAPM_PRE_PMD: 813b5858113SRyan Lee max98396_global_enable_onoff(max98396->regmap, false); 814b5858113SRyan Lee 815b5858113SRyan Lee max98396->tdm_mode = false; 816b5858113SRyan Lee break; 817b5858113SRyan Lee default: 818b5858113SRyan Lee return 0; 819b5858113SRyan Lee } 820b5858113SRyan Lee return 0; 821b5858113SRyan Lee } 822b5858113SRyan Lee 823b5858113SRyan Lee static bool max98396_readable_register(struct device *dev, unsigned int reg) 824b5858113SRyan Lee { 825b5858113SRyan Lee switch (reg) { 826b5858113SRyan Lee case MAX98396_R2001_INT_RAW1 ... MAX98396_R2004_INT_RAW4: 827b5858113SRyan Lee case MAX98396_R2006_INT_STATE1 ... MAX98396_R2009_INT_STATE4: 828b5858113SRyan Lee case MAX98396_R200B_INT_FLAG1 ... MAX98396_R200E_INT_FLAG4: 829b5858113SRyan Lee case MAX98396_R2010_INT_EN1 ... MAX98396_R2013_INT_EN4: 830b5858113SRyan Lee case MAX98396_R2015_INT_FLAG_CLR1 ... MAX98396_R2018_INT_FLAG_CLR4: 831b5858113SRyan Lee case MAX98396_R201F_IRQ_CTRL ... MAX98396_R2024_THERM_FOLDBACK_SET: 832b5858113SRyan Lee case MAX98396_R2027_THERM_FOLDBACK_EN: 833b5858113SRyan Lee case MAX98396_R2030_NOISEGATE_MODE_CTRL: 834b5858113SRyan Lee case MAX98396_R2033_NOISEGATE_MODE_EN: 835b5858113SRyan Lee case MAX98396_R2038_CLK_MON_CTRL ... MAX98396_R2039_DATA_MON_CTRL: 836b5858113SRyan Lee case MAX98396_R203F_ENABLE_CTRLS ... MAX98396_R2053_PCM_TX_HIZ_CTRL_8: 837b5858113SRyan Lee case MAX98396_R2055_PCM_RX_SRC1 ... MAX98396_R2056_PCM_RX_SRC2: 838b5858113SRyan Lee case MAX98396_R2058_PCM_BYPASS_SRC: 839b5858113SRyan Lee case MAX98396_R205D_PCM_TX_SRC_EN ... MAX98396_R205F_PCM_TX_EN: 840b5858113SRyan Lee case MAX98396_R2070_ICC_RX_EN_A... MAX98396_R2072_ICC_TX_CTRL: 841b5858113SRyan Lee case MAX98396_R207F_ICC_EN: 842b5858113SRyan Lee case MAX98396_R2083_TONE_GEN_DC_CFG ... MAX98396_R2086_TONE_GEN_DC_LVL3: 843b5858113SRyan Lee case MAX98396_R208F_TONE_GEN_EN ... MAX98396_R209A_SPK_EDGE_CTRL: 844b5858113SRyan Lee case MAX98396_R209C_SPK_EDGE_CTRL1 ... MAX98396_R20A0_AMP_SUPPLY_CTL: 845b5858113SRyan Lee case MAX98396_R20AF_AMP_EN ... MAX98396_R20BF_ADC_LO_VBAT_READBACK_LSB: 846b5858113SRyan Lee case MAX98396_R20C7_ADC_CFG: 847b5858113SRyan Lee case MAX98396_R20D0_DHT_CFG1 ... MAX98396_R20D6_DHT_HYSTERESIS_CFG: 848b5858113SRyan Lee case MAX98396_R20DF_DHT_EN: 849b5858113SRyan Lee case MAX98396_R20E0_IV_SENSE_PATH_CFG: 850b5858113SRyan Lee case MAX98396_R20E4_IV_SENSE_PATH_EN 851b5858113SRyan Lee ... MAX98396_R2106_BPE_THRESH_HYSTERESIS: 852b5858113SRyan Lee case MAX98396_R2108_BPE_SUPPLY_SRC ... MAX98396_R210B_BPE_LOW_LIMITER: 853b5858113SRyan Lee case MAX98396_R210D_BPE_EN ... MAX98396_R210F_GLOBAL_EN: 854b5858113SRyan Lee case MAX98396_R21FF_REVISION_ID: 855b5858113SRyan Lee return true; 856b5858113SRyan Lee default: 857b5858113SRyan Lee return false; 858b5858113SRyan Lee } 859b5858113SRyan Lee }; 860b5858113SRyan Lee 861b5858113SRyan Lee static bool max98396_volatile_reg(struct device *dev, unsigned int reg) 862b5858113SRyan Lee { 863b5858113SRyan Lee switch (reg) { 864b5858113SRyan Lee case MAX98396_R2000_SW_RESET: 865b5858113SRyan Lee case MAX98396_R2001_INT_RAW1 ... MAX98396_R200E_INT_FLAG4: 866b5858113SRyan Lee case MAX98396_R2041_PCM_MODE_CFG: 867b5858113SRyan Lee case MAX98396_R20B6_ADC_PVDD_READBACK_MSB 868b5858113SRyan Lee ... MAX98396_R20BF_ADC_LO_VBAT_READBACK_LSB: 869b5858113SRyan Lee case MAX98396_R20E5_BPE_STATE: 870b5858113SRyan Lee case MAX98396_R2109_BPE_LOW_STATE 871b5858113SRyan Lee ... MAX98396_R210B_BPE_LOW_LIMITER: 872b5858113SRyan Lee case MAX98396_R210F_GLOBAL_EN: 873b5858113SRyan Lee case MAX98396_R21FF_REVISION_ID: 874b5858113SRyan Lee return true; 875b5858113SRyan Lee default: 876b5858113SRyan Lee return false; 877b5858113SRyan Lee } 878b5858113SRyan Lee } 879b5858113SRyan Lee 880b5858113SRyan Lee static bool max98397_readable_register(struct device *dev, unsigned int reg) 881b5858113SRyan Lee { 882b5858113SRyan Lee switch (reg) { 883b5858113SRyan Lee case MAX98396_R2001_INT_RAW1 ... MAX98396_R2004_INT_RAW4: 884b5858113SRyan Lee case MAX98396_R2006_INT_STATE1 ... MAX98396_R2009_INT_STATE4: 885b5858113SRyan Lee case MAX98396_R200B_INT_FLAG1 ... MAX98396_R200E_INT_FLAG4: 886b5858113SRyan Lee case MAX98396_R2010_INT_EN1 ... MAX98396_R2013_INT_EN4: 887b5858113SRyan Lee case MAX98396_R2015_INT_FLAG_CLR1 ... MAX98396_R2018_INT_FLAG_CLR4: 888b5858113SRyan Lee case MAX98396_R201F_IRQ_CTRL ... MAX98396_R2024_THERM_FOLDBACK_SET: 889b5858113SRyan Lee case MAX98396_R2027_THERM_FOLDBACK_EN: 890b5858113SRyan Lee case MAX98396_R2030_NOISEGATE_MODE_CTRL: 891b5858113SRyan Lee case MAX98396_R2033_NOISEGATE_MODE_EN: 892b5858113SRyan Lee case MAX98396_R2038_CLK_MON_CTRL ... MAX98397_R203A_SPK_MON_THRESH: 893b5858113SRyan Lee case MAX98396_R203F_ENABLE_CTRLS ... MAX98397_R2054_PCM_TX_HIZ_CTRL_8: 894b5858113SRyan Lee case MAX98397_R2056_PCM_RX_SRC1... MAX98396_R2058_PCM_BYPASS_SRC: 895b5858113SRyan Lee case MAX98396_R205D_PCM_TX_SRC_EN ... MAX98397_R2060_PCM_TX_SUPPLY_SEL: 896b5858113SRyan Lee case MAX98396_R2070_ICC_RX_EN_A... MAX98396_R2072_ICC_TX_CTRL: 897b5858113SRyan Lee case MAX98396_R207F_ICC_EN: 898b5858113SRyan Lee case MAX98396_R2083_TONE_GEN_DC_CFG ... MAX98396_R2086_TONE_GEN_DC_LVL3: 899b5858113SRyan Lee case MAX98396_R208F_TONE_GEN_EN ... MAX98396_R209F_BYPASS_PATH_CFG: 900b5858113SRyan Lee case MAX98396_R20AF_AMP_EN ... MAX98397_R20C5_MEAS_ADC_OPTIMAL_MODE: 901b5858113SRyan Lee case MAX98396_R20C7_ADC_CFG: 902b5858113SRyan Lee case MAX98396_R20D0_DHT_CFG1 ... MAX98396_R20D6_DHT_HYSTERESIS_CFG: 903b5858113SRyan Lee case MAX98396_R20DF_DHT_EN: 904b5858113SRyan Lee case MAX98396_R20E0_IV_SENSE_PATH_CFG: 905b5858113SRyan Lee case MAX98396_R20E4_IV_SENSE_PATH_EN 906b5858113SRyan Lee ... MAX98396_R2106_BPE_THRESH_HYSTERESIS: 907b5858113SRyan Lee case MAX98396_R2108_BPE_SUPPLY_SRC ... MAX98396_R210B_BPE_LOW_LIMITER: 908b5858113SRyan Lee case MAX98396_R210D_BPE_EN ... MAX98396_R210F_GLOBAL_EN: 909b5858113SRyan Lee case MAX98397_R22FF_REVISION_ID: 910b5858113SRyan Lee return true; 911b5858113SRyan Lee default: 912b5858113SRyan Lee return false; 913b5858113SRyan Lee } 914b5858113SRyan Lee }; 915b5858113SRyan Lee 916b5858113SRyan Lee static bool max98397_volatile_reg(struct device *dev, unsigned int reg) 917b5858113SRyan Lee { 918b5858113SRyan Lee switch (reg) { 919b5858113SRyan Lee case MAX98396_R2001_INT_RAW1 ... MAX98396_R200E_INT_FLAG4: 920b5858113SRyan Lee case MAX98396_R2041_PCM_MODE_CFG: 921b5858113SRyan Lee case MAX98397_R20B7_ADC_PVDD_READBACK_MSB 922b5858113SRyan Lee ... MAX98397_R20C4_ADC_LO_VDDH_READBACK_LSB: 923b5858113SRyan Lee case MAX98396_R20E5_BPE_STATE: 924b5858113SRyan Lee case MAX98396_R2109_BPE_LOW_STATE 925b5858113SRyan Lee ... MAX98396_R210B_BPE_LOW_LIMITER: 926b5858113SRyan Lee case MAX98396_R210F_GLOBAL_EN: 927b5858113SRyan Lee case MAX98397_R22FF_REVISION_ID: 928b5858113SRyan Lee return true; 929b5858113SRyan Lee default: 930b5858113SRyan Lee return false; 931b5858113SRyan Lee } 932b5858113SRyan Lee } 933b5858113SRyan Lee 934b5858113SRyan Lee static const char * const max98396_op_mod_text[] = { 935b5858113SRyan Lee "DG", "PVDD", "VBAT", 936b5858113SRyan Lee }; 937b5858113SRyan Lee 938b5858113SRyan Lee static SOC_ENUM_SINGLE_DECL(max98396_op_mod_enum, 939b5858113SRyan Lee MAX98396_R2098_SPK_CLS_DG_MODE, 940b5858113SRyan Lee 0, max98396_op_mod_text); 941b5858113SRyan Lee 942b5858113SRyan Lee static DECLARE_TLV_DB_SCALE(max98396_digital_tlv, -6350, 50, 1); 943b5858113SRyan Lee static const DECLARE_TLV_DB_RANGE(max98396_spk_tlv, 944b5858113SRyan Lee 0, 0x11, TLV_DB_SCALE_ITEM(400, 100, 0), 945b5858113SRyan Lee ); 946b5858113SRyan Lee static DECLARE_TLV_DB_RANGE(max98397_digital_tlv, 947b5858113SRyan Lee 0, 0x4A, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 1), 948b5858113SRyan Lee 0x4B, 0xFF, TLV_DB_SCALE_ITEM(-9000, 50, 0), 949b5858113SRyan Lee ); 950b5858113SRyan Lee static const DECLARE_TLV_DB_RANGE(max98397_spk_tlv, 951b5858113SRyan Lee 0, 0x15, TLV_DB_SCALE_ITEM(600, 100, 0), 952b5858113SRyan Lee ); 953b5858113SRyan Lee 954b5858113SRyan Lee static int max98396_mux_get(struct snd_kcontrol *kcontrol, 955b5858113SRyan Lee struct snd_ctl_elem_value *ucontrol) 956b5858113SRyan Lee { 957b5858113SRyan Lee struct snd_soc_component *component = 958b5858113SRyan Lee snd_soc_dapm_kcontrol_component(kcontrol); 959b5858113SRyan Lee struct max98396_priv *max98396 = snd_soc_component_get_drvdata(component); 960b5858113SRyan Lee int reg, val; 961b5858113SRyan Lee 962b5858113SRyan Lee if (max98396->device_id == CODEC_TYPE_MAX98396) 963b5858113SRyan Lee reg = MAX98396_R2055_PCM_RX_SRC1; 964b5858113SRyan Lee else 965b5858113SRyan Lee reg = MAX98397_R2056_PCM_RX_SRC1; 966b5858113SRyan Lee 967b5858113SRyan Lee regmap_read(max98396->regmap, reg, &val); 968b5858113SRyan Lee 969b5858113SRyan Lee ucontrol->value.enumerated.item[0] = val; 970b5858113SRyan Lee 971b5858113SRyan Lee return 0; 972b5858113SRyan Lee } 973b5858113SRyan Lee 974b5858113SRyan Lee static int max98396_mux_put(struct snd_kcontrol *kcontrol, 975b5858113SRyan Lee struct snd_ctl_elem_value *ucontrol) 976b5858113SRyan Lee { 977b5858113SRyan Lee struct snd_soc_component *component = 978b5858113SRyan Lee snd_soc_dapm_kcontrol_component(kcontrol); 979b5858113SRyan Lee struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol); 980b5858113SRyan Lee struct max98396_priv *max98396 = snd_soc_component_get_drvdata(component); 981b5858113SRyan Lee struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; 982b5858113SRyan Lee unsigned int *item = ucontrol->value.enumerated.item; 983b5858113SRyan Lee int reg, val; 984b5858113SRyan Lee int change; 985b5858113SRyan Lee 986b5858113SRyan Lee if (item[0] >= e->items) 987b5858113SRyan Lee return -EINVAL; 988b5858113SRyan Lee 989b5858113SRyan Lee val = snd_soc_enum_item_to_val(e, item[0]) << e->shift_l; 990b5858113SRyan Lee 991b5858113SRyan Lee if (max98396->device_id == CODEC_TYPE_MAX98396) 992b5858113SRyan Lee reg = MAX98396_R2055_PCM_RX_SRC1; 993b5858113SRyan Lee else 994b5858113SRyan Lee reg = MAX98397_R2056_PCM_RX_SRC1; 995b5858113SRyan Lee 996b5858113SRyan Lee change = snd_soc_component_test_bits(component, reg, 997b5858113SRyan Lee MAX98396_PCM_RX_MASK, val); 998b5858113SRyan Lee 999b5858113SRyan Lee if (change) 1000b5858113SRyan Lee regmap_update_bits(max98396->regmap, reg, 1001b5858113SRyan Lee MAX98396_PCM_RX_MASK, val); 1002b5858113SRyan Lee 1003b5858113SRyan Lee snd_soc_dapm_mux_update_power(dapm, kcontrol, item[0], e, NULL); 1004b5858113SRyan Lee 1005b5858113SRyan Lee return change; 1006b5858113SRyan Lee } 1007b5858113SRyan Lee 1008b5858113SRyan Lee static const char * const max98396_switch_text[] = { 1009b5858113SRyan Lee "Left", "Right", "LeftRight"}; 1010b5858113SRyan Lee 1011b5858113SRyan Lee static SOC_ENUM_SINGLE_DECL(dai_sel_enum, SND_SOC_NOPM, 0, 1012b5858113SRyan Lee max98396_switch_text); 1013b5858113SRyan Lee 1014b5858113SRyan Lee static const struct snd_kcontrol_new max98396_dai_mux = 1015b5858113SRyan Lee SOC_DAPM_ENUM_EXT("DAI Sel Mux", dai_sel_enum, 1016b5858113SRyan Lee max98396_mux_get, max98396_mux_put); 1017b5858113SRyan Lee 1018b5858113SRyan Lee static const struct snd_kcontrol_new max98396_vi_control = 1019b5858113SRyan Lee SOC_DAPM_SINGLE("Switch", MAX98396_R205F_PCM_TX_EN, 0, 1, 0); 1020b5858113SRyan Lee 1021b5858113SRyan Lee static const struct snd_soc_dapm_widget max98396_dapm_widgets[] = { 1022b5858113SRyan Lee SND_SOC_DAPM_DAC_E("Amp Enable", "HiFi Playback", 1023b5858113SRyan Lee MAX98396_R20AF_AMP_EN, 0, 0, max98396_dac_event, 1024b5858113SRyan Lee SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), 1025b5858113SRyan Lee SND_SOC_DAPM_MUX("DAI Sel Mux", SND_SOC_NOPM, 0, 0, 1026b5858113SRyan Lee &max98396_dai_mux), 1027b5858113SRyan Lee SND_SOC_DAPM_OUTPUT("BE_OUT"), 1028b5858113SRyan Lee SND_SOC_DAPM_AIF_OUT("Voltage Sense", "HiFi Capture", 0, 1029b5858113SRyan Lee MAX98396_R20E4_IV_SENSE_PATH_EN, 0, 0), 1030b5858113SRyan Lee SND_SOC_DAPM_AIF_OUT("Current Sense", "HiFi Capture", 0, 1031b5858113SRyan Lee MAX98396_R20E4_IV_SENSE_PATH_EN, 1, 0), 1032b5858113SRyan Lee SND_SOC_DAPM_SWITCH("VI Sense", SND_SOC_NOPM, 0, 0, 1033b5858113SRyan Lee &max98396_vi_control), 1034b5858113SRyan Lee SND_SOC_DAPM_SIGGEN("VMON"), 1035b5858113SRyan Lee SND_SOC_DAPM_SIGGEN("IMON"), 1036b5858113SRyan Lee SND_SOC_DAPM_SIGGEN("FBMON"), 1037b5858113SRyan Lee }; 1038b5858113SRyan Lee 1039b5858113SRyan Lee static const char * const max98396_thermal_thresh_text[] = { 1040b5858113SRyan Lee "50C", "51C", "52C", "53C", "54C", "55C", "56C", "57C", 1041b5858113SRyan Lee "58C", "59C", "60C", "61C", "62C", "63C", "64C", "65C", 1042b5858113SRyan Lee "66C", "67C", "68C", "69C", "70C", "71C", "72C", "73C", 1043b5858113SRyan Lee "74C", "75C", "76C", "77C", "78C", "79C", "80C", "81C", 1044b5858113SRyan Lee "82C", "83C", "84C", "85C", "86C", "87C", "88C", "89C", 1045b5858113SRyan Lee "90C", "91C", "92C", "93C", "94C", "95C", "96C", "97C", 1046b5858113SRyan Lee "98C", "99C", "100C", "101C", "102C", "103C", "104C", "105C", 1047b5858113SRyan Lee "106C", "107C", "108C", "109C", "110C", "111C", "112C", "113C", 1048b5858113SRyan Lee "114C", "115C", "116C", "117C", "118C", "119C", "120C", "121C", 1049b5858113SRyan Lee "122C", "123C", "124C", "125C", "126C", "127C", "128C", "129C", 1050b5858113SRyan Lee "130C", "131C", "132C", "133C", "134C", "135C", "136C", "137C", 1051b5858113SRyan Lee "138C", "139C", "140C", "141C", "142C", "143C", "144C", "145C", 1052b5858113SRyan Lee "146C", "147C", "148C", "149C", "150C" 1053b5858113SRyan Lee }; 1054b5858113SRyan Lee 1055b5858113SRyan Lee static SOC_ENUM_SINGLE_DECL(max98396_thermal_warn_thresh1_enum, 1056b5858113SRyan Lee MAX98396_R2020_THERM_WARN_THRESH, 0, 1057b5858113SRyan Lee max98396_thermal_thresh_text); 1058b5858113SRyan Lee 1059b5858113SRyan Lee static SOC_ENUM_SINGLE_DECL(max98396_thermal_warn_thresh2_enum, 1060b5858113SRyan Lee MAX98396_R2021_THERM_WARN_THRESH2, 0, 1061b5858113SRyan Lee max98396_thermal_thresh_text); 1062b5858113SRyan Lee 1063b5858113SRyan Lee static SOC_ENUM_SINGLE_DECL(max98396_thermal_shdn_thresh_enum, 1064b5858113SRyan Lee MAX98396_R2022_THERM_SHDN_THRESH, 0, 1065b5858113SRyan Lee max98396_thermal_thresh_text); 1066b5858113SRyan Lee 1067b5858113SRyan Lee static const char * const max98396_thermal_hyteresis_text[] = { 1068b5858113SRyan Lee "2C", "5C", "7C", "10C" 1069b5858113SRyan Lee }; 1070b5858113SRyan Lee 1071b5858113SRyan Lee static SOC_ENUM_SINGLE_DECL(max98396_thermal_hysteresis_enum, 1072b5858113SRyan Lee MAX98396_R2023_THERM_HYSTERESIS, 0, 1073b5858113SRyan Lee max98396_thermal_hyteresis_text); 1074b5858113SRyan Lee 1075b5858113SRyan Lee static const char * const max98396_foldback_slope_text[] = { 1076b5858113SRyan Lee "0.25", "0.5", "1.0", "2.0" 1077b5858113SRyan Lee }; 1078b5858113SRyan Lee 1079b5858113SRyan Lee static SOC_ENUM_SINGLE_DECL(max98396_thermal_fb_slope1_enum, 1080b5858113SRyan Lee MAX98396_R2024_THERM_FOLDBACK_SET, 1081b5858113SRyan Lee MAX98396_THERM_FB_SLOPE1_SHIFT, 1082b5858113SRyan Lee max98396_foldback_slope_text); 1083b5858113SRyan Lee 1084b5858113SRyan Lee static SOC_ENUM_SINGLE_DECL(max98396_thermal_fb_slope2_enum, 1085b5858113SRyan Lee MAX98396_R2024_THERM_FOLDBACK_SET, 1086b5858113SRyan Lee MAX98396_THERM_FB_SLOPE2_SHIFT, 1087b5858113SRyan Lee max98396_foldback_slope_text); 1088b5858113SRyan Lee 1089b5858113SRyan Lee static const char * const max98396_foldback_reltime_text[] = { 1090b5858113SRyan Lee "3ms", "10ms", "100ms", "300ms" 1091b5858113SRyan Lee }; 1092b5858113SRyan Lee 1093b5858113SRyan Lee static SOC_ENUM_SINGLE_DECL(max98396_thermal_fb_reltime_enum, 1094b5858113SRyan Lee MAX98396_R2024_THERM_FOLDBACK_SET, 1095b5858113SRyan Lee MAX98396_THERM_FB_REL_SHIFT, 1096b5858113SRyan Lee max98396_foldback_reltime_text); 1097b5858113SRyan Lee 1098b5858113SRyan Lee static const char * const max98396_foldback_holdtime_text[] = { 1099b5858113SRyan Lee "0ms", "20ms", "40ms", "80ms" 1100b5858113SRyan Lee }; 1101b5858113SRyan Lee 1102b5858113SRyan Lee static SOC_ENUM_SINGLE_DECL(max98396_thermal_fb_holdtime_enum, 1103b5858113SRyan Lee MAX98396_R2024_THERM_FOLDBACK_SET, 1104b5858113SRyan Lee MAX98396_THERM_FB_HOLD_SHIFT, 1105b5858113SRyan Lee max98396_foldback_holdtime_text); 1106b5858113SRyan Lee 1107b5858113SRyan Lee static int max98396_adc_value_get(struct snd_kcontrol *kcontrol, 1108b5858113SRyan Lee struct snd_ctl_elem_value *ucontrol) 1109b5858113SRyan Lee { 1110b5858113SRyan Lee struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); 1111b5858113SRyan Lee struct soc_mixer_control *mc = 1112b5858113SRyan Lee (struct soc_mixer_control *)kcontrol->private_value; 1113b5858113SRyan Lee struct max98396_priv *max98396 = snd_soc_component_get_drvdata(component); 1114b5858113SRyan Lee int ret; 1115b5858113SRyan Lee u8 val[2]; 1116b5858113SRyan Lee int reg = mc->reg; 1117b5858113SRyan Lee 1118b5858113SRyan Lee /* ADC value is not available if the device is powered down */ 1119b5858113SRyan Lee if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) 1120b5858113SRyan Lee goto exit; 1121b5858113SRyan Lee 1122b5858113SRyan Lee if (max98396->device_id == CODEC_TYPE_MAX98397) { 1123b5858113SRyan Lee switch (mc->reg) { 1124b5858113SRyan Lee case MAX98396_R20B6_ADC_PVDD_READBACK_MSB: 1125b5858113SRyan Lee reg = MAX98397_R20B7_ADC_PVDD_READBACK_MSB; 1126b5858113SRyan Lee break; 1127b5858113SRyan Lee case MAX98396_R20B8_ADC_VBAT_READBACK_MSB: 1128b5858113SRyan Lee reg = MAX98397_R20B9_ADC_VBAT_READBACK_MSB; 1129b5858113SRyan Lee break; 1130b5858113SRyan Lee case MAX98396_R20BA_ADC_TEMP_READBACK_MSB: 1131b5858113SRyan Lee reg = MAX98397_R20BB_ADC_TEMP_READBACK_MSB; 1132b5858113SRyan Lee break; 1133b5858113SRyan Lee default: 1134b5858113SRyan Lee goto exit; 1135b5858113SRyan Lee } 1136b5858113SRyan Lee } 1137b5858113SRyan Lee 1138b5858113SRyan Lee ret = regmap_raw_read(max98396->regmap, reg, &val, 2); 1139b5858113SRyan Lee if (ret) 1140b5858113SRyan Lee goto exit; 1141b5858113SRyan Lee 1142b5858113SRyan Lee /* ADC readback bits[8:0] rearrangement */ 1143b5858113SRyan Lee ucontrol->value.integer.value[0] = (val[0] << 1) | (val[1] & 1); 1144b5858113SRyan Lee return 0; 1145b5858113SRyan Lee 1146b5858113SRyan Lee exit: 1147b5858113SRyan Lee ucontrol->value.integer.value[0] = 0; 1148b5858113SRyan Lee return 0; 1149b5858113SRyan Lee } 1150b5858113SRyan Lee 1151b5858113SRyan Lee static const struct snd_kcontrol_new max98396_snd_controls[] = { 1152b5858113SRyan Lee /* Volume */ 1153b5858113SRyan Lee SOC_SINGLE_TLV("Digital Volume", MAX98396_R2090_AMP_VOL_CTRL, 1154b5858113SRyan Lee 0, 0x7F, 1, max98396_digital_tlv), 1155b5858113SRyan Lee SOC_SINGLE_TLV("Speaker Volume", MAX98396_R2091_AMP_PATH_GAIN, 1156b5858113SRyan Lee 0, 0x11, 0, max98396_spk_tlv), 1157b5858113SRyan Lee /* Volume Ramp Up/Down Enable*/ 1158b5858113SRyan Lee SOC_SINGLE("Ramp Up Switch", MAX98396_R2092_AMP_DSP_CFG, 1159b5858113SRyan Lee MAX98396_DSP_SPK_VOL_RMPUP_SHIFT, 1, 0), 1160b5858113SRyan Lee SOC_SINGLE("Ramp Down Switch", MAX98396_R2092_AMP_DSP_CFG, 1161b5858113SRyan Lee MAX98396_DSP_SPK_VOL_RMPDN_SHIFT, 1, 0), 1162b5858113SRyan Lee /* Clock Monitor Enable */ 1163b5858113SRyan Lee SOC_SINGLE("CLK Monitor Switch", MAX98396_R203F_ENABLE_CTRLS, 1164b5858113SRyan Lee MAX98396_CTRL_CMON_EN_SHIFT, 1, 0), 1165b5858113SRyan Lee /* Dither Enable */ 1166b5858113SRyan Lee SOC_SINGLE("Dither Switch", MAX98396_R2092_AMP_DSP_CFG, 1167b5858113SRyan Lee MAX98396_DSP_SPK_DITH_EN_SHIFT, 1, 0), 1168b5858113SRyan Lee SOC_SINGLE("IV Dither Switch", MAX98396_R20E0_IV_SENSE_PATH_CFG, 1169b5858113SRyan Lee MAX98396_IV_SENSE_DITH_EN_SHIFT, 1, 0), 1170b5858113SRyan Lee /* DC Blocker Enable */ 1171b5858113SRyan Lee SOC_SINGLE("DC Blocker Switch", MAX98396_R2092_AMP_DSP_CFG, 1172b5858113SRyan Lee MAX98396_DSP_SPK_DCBLK_EN_SHIFT, 1, 0), 1173b5858113SRyan Lee SOC_SINGLE("IV DC Blocker Switch", MAX98396_R20E0_IV_SENSE_PATH_CFG, 1174b5858113SRyan Lee MAX98396_IV_SENSE_DCBLK_EN_SHIFT, 3, 0), 1175b5858113SRyan Lee /* Speaker Safe Mode Enable */ 1176b5858113SRyan Lee SOC_SINGLE("Safe Mode Switch", MAX98396_R2092_AMP_DSP_CFG, 1177b5858113SRyan Lee MAX98396_DSP_SPK_SAFE_EN_SHIFT, 1, 0), 1178b5858113SRyan Lee /* Wideband Filter Enable */ 1179b5858113SRyan Lee SOC_SINGLE("WB Filter Switch", MAX98396_R2092_AMP_DSP_CFG, 1180b5858113SRyan Lee MAX98396_DSP_SPK_WB_FLT_EN_SHIFT, 1, 0), 1181b5858113SRyan Lee SOC_SINGLE("IV WB Filter Switch", MAX98396_R20E0_IV_SENSE_PATH_CFG, 1182b5858113SRyan Lee MAX98396_IV_SENSE_WB_FLT_EN_SHIFT, 1, 0), 1183b5858113SRyan Lee /* Dynamic Headroom Tracking */ 1184b5858113SRyan Lee SOC_SINGLE("DHT Switch", MAX98396_R20DF_DHT_EN, 0, 1, 0), 1185b5858113SRyan Lee /* Brownout Protection Engine */ 1186b5858113SRyan Lee SOC_SINGLE("BPE Switch", MAX98396_R210D_BPE_EN, 0, 1, 0), 1187b5858113SRyan Lee SOC_SINGLE("BPE Limiter Switch", MAX98396_R210D_BPE_EN, 1, 1, 0), 1188b5858113SRyan Lee /* Bypass Path Enable */ 1189b5858113SRyan Lee SOC_SINGLE("Bypass Path Switch", 1190b5858113SRyan Lee MAX98396_R205E_PCM_RX_EN, 1, 1, 0), 1191b5858113SRyan Lee /* Speaker Operation Mode */ 1192b5858113SRyan Lee SOC_ENUM("OP Mode", max98396_op_mod_enum), 1193b5858113SRyan Lee /* Auto Restart functions */ 1194b5858113SRyan Lee SOC_SINGLE("CMON Auto Restart Switch", MAX98396_R2038_CLK_MON_CTRL, 1195b5858113SRyan Lee MAX98396_CLK_MON_AUTO_RESTART_SHIFT, 1, 0), 1196b5858113SRyan Lee SOC_SINGLE("PVDD Auto Restart Switch", MAX98396_R210E_AUTO_RESTART, 1197b5858113SRyan Lee MAX98396_PVDD_UVLO_RESTART_SHFT, 1, 0), 1198b5858113SRyan Lee SOC_SINGLE("VBAT Auto Restart Switch", MAX98396_R210E_AUTO_RESTART, 1199b5858113SRyan Lee MAX98396_VBAT_UVLO_RESTART_SHFT, 1, 0), 1200b5858113SRyan Lee SOC_SINGLE("THERM Auto Restart Switch", MAX98396_R210E_AUTO_RESTART, 1201b5858113SRyan Lee MAX98396_THEM_SHDN_RESTART_SHFT, 1, 0), 1202b5858113SRyan Lee SOC_SINGLE("OVC Auto Restart Switch", MAX98396_R210E_AUTO_RESTART, 1203b5858113SRyan Lee MAX98396_OVC_RESTART_SHFT, 1, 0), 1204b5858113SRyan Lee /* Thermal Threshold */ 1205b5858113SRyan Lee SOC_ENUM("THERM Thresh1", max98396_thermal_warn_thresh1_enum), 1206b5858113SRyan Lee SOC_ENUM("THERM Thresh2", max98396_thermal_warn_thresh2_enum), 1207b5858113SRyan Lee SOC_ENUM("THERM SHDN Thresh", max98396_thermal_shdn_thresh_enum), 1208b5858113SRyan Lee SOC_ENUM("THERM Hysteresis", max98396_thermal_hysteresis_enum), 1209b5858113SRyan Lee SOC_SINGLE("THERM Foldback Switch", 1210b5858113SRyan Lee MAX98396_R2027_THERM_FOLDBACK_EN, 0, 1, 0), 1211b5858113SRyan Lee SOC_ENUM("THERM Slope1", max98396_thermal_fb_slope1_enum), 1212b5858113SRyan Lee SOC_ENUM("THERM Slope2", max98396_thermal_fb_slope2_enum), 1213b5858113SRyan Lee SOC_ENUM("THERM Release", max98396_thermal_fb_reltime_enum), 1214b5858113SRyan Lee SOC_ENUM("THERM Hold", max98396_thermal_fb_holdtime_enum), 1215b5858113SRyan Lee /* ADC */ 1216b5858113SRyan Lee SOC_SINGLE_EXT("ADC PVDD", MAX98396_R20B6_ADC_PVDD_READBACK_MSB, 0, 0x1FF, 0, 1217b5858113SRyan Lee max98396_adc_value_get, NULL), 1218b5858113SRyan Lee SOC_SINGLE_EXT("ADC VBAT", MAX98396_R20B8_ADC_VBAT_READBACK_MSB, 0, 0x1FF, 0, 1219b5858113SRyan Lee max98396_adc_value_get, NULL), 1220b5858113SRyan Lee SOC_SINGLE_EXT("ADC TEMP", MAX98396_R20BA_ADC_TEMP_READBACK_MSB, 0, 0x1FF, 0, 1221b5858113SRyan Lee max98396_adc_value_get, NULL), 1222b5858113SRyan Lee }; 1223b5858113SRyan Lee 1224b5858113SRyan Lee static const struct snd_kcontrol_new max98397_snd_controls[] = { 1225b5858113SRyan Lee /* Volume */ 1226b5858113SRyan Lee SOC_SINGLE_TLV("Digital Volume", MAX98396_R2090_AMP_VOL_CTRL, 1227b5858113SRyan Lee 0, 0xFF, 1, max98397_digital_tlv), 1228b5858113SRyan Lee SOC_SINGLE_TLV("Speaker Volume", MAX98396_R2091_AMP_PATH_GAIN, 1229b5858113SRyan Lee 0, 0x15, 0, max98397_spk_tlv), 1230b5858113SRyan Lee /* Volume Ramp Up/Down Enable*/ 1231b5858113SRyan Lee SOC_SINGLE("Ramp Up Switch", MAX98396_R2092_AMP_DSP_CFG, 1232b5858113SRyan Lee MAX98396_DSP_SPK_VOL_RMPUP_SHIFT, 1, 0), 1233b5858113SRyan Lee SOC_SINGLE("Ramp Down Switch", MAX98396_R2092_AMP_DSP_CFG, 1234b5858113SRyan Lee MAX98396_DSP_SPK_VOL_RMPDN_SHIFT, 1, 0), 1235b5858113SRyan Lee /* Clock Monitor Enable */ 1236b5858113SRyan Lee SOC_SINGLE("CLK Monitor Switch", MAX98396_R203F_ENABLE_CTRLS, 1237b5858113SRyan Lee MAX98396_CTRL_CMON_EN_SHIFT, 1, 0), 1238b5858113SRyan Lee /* Dither Enable */ 1239b5858113SRyan Lee SOC_SINGLE("Dither Switch", MAX98396_R2092_AMP_DSP_CFG, 1240b5858113SRyan Lee MAX98396_DSP_SPK_DITH_EN_SHIFT, 1, 0), 1241b5858113SRyan Lee SOC_SINGLE("IV Dither Switch", MAX98396_R20E0_IV_SENSE_PATH_CFG, 1242b5858113SRyan Lee MAX98396_IV_SENSE_DITH_EN_SHIFT, 1, 0), 1243b5858113SRyan Lee /* DC Blocker Enable */ 1244b5858113SRyan Lee SOC_SINGLE("DC Blocker Switch", MAX98396_R2092_AMP_DSP_CFG, 1245b5858113SRyan Lee MAX98396_DSP_SPK_DCBLK_EN_SHIFT, 1, 0), 1246b5858113SRyan Lee SOC_SINGLE("IV DC Blocker Switch", MAX98396_R20E0_IV_SENSE_PATH_CFG, 1247b5858113SRyan Lee MAX98396_IV_SENSE_DCBLK_EN_SHIFT, 3, 0), 1248b5858113SRyan Lee /* Speaker Safe Mode Enable */ 1249b5858113SRyan Lee SOC_SINGLE("Safe Mode Switch", MAX98396_R2092_AMP_DSP_CFG, 1250b5858113SRyan Lee MAX98396_DSP_SPK_SAFE_EN_SHIFT, 1, 0), 1251b5858113SRyan Lee /* Wideband Filter Enable */ 1252b5858113SRyan Lee SOC_SINGLE("WB Filter Switch", MAX98396_R2092_AMP_DSP_CFG, 1253b5858113SRyan Lee MAX98396_DSP_SPK_WB_FLT_EN_SHIFT, 1, 0), 1254b5858113SRyan Lee SOC_SINGLE("IV WB Filter Switch", MAX98396_R20E0_IV_SENSE_PATH_CFG, 1255b5858113SRyan Lee MAX98396_IV_SENSE_WB_FLT_EN_SHIFT, 1, 0), 1256b5858113SRyan Lee /* Dynamic Headroom Tracking */ 1257b5858113SRyan Lee SOC_SINGLE("DHT Switch", MAX98396_R20DF_DHT_EN, 0, 1, 0), 1258b5858113SRyan Lee /* Brownout Protection Engine */ 1259b5858113SRyan Lee SOC_SINGLE("BPE Switch", MAX98396_R210D_BPE_EN, 0, 1, 0), 1260b5858113SRyan Lee SOC_SINGLE("BPE Limiter Switch", MAX98396_R210D_BPE_EN, 1, 1, 0), 1261b5858113SRyan Lee /* Bypass Path Enable */ 1262b5858113SRyan Lee SOC_SINGLE("Bypass Path Switch", 1263b5858113SRyan Lee MAX98396_R205E_PCM_RX_EN, 1, 1, 0), 1264b5858113SRyan Lee /* Speaker Operation Mode */ 1265b5858113SRyan Lee SOC_ENUM("OP Mode", max98396_op_mod_enum), 1266b5858113SRyan Lee /* Auto Restart functions */ 1267b5858113SRyan Lee SOC_SINGLE("CMON Auto Restart Switch", MAX98396_R2038_CLK_MON_CTRL, 1268b5858113SRyan Lee MAX98396_CLK_MON_AUTO_RESTART_SHIFT, 1, 0), 1269b5858113SRyan Lee SOC_SINGLE("PVDD Auto Restart Switch", MAX98396_R210E_AUTO_RESTART, 1270b5858113SRyan Lee MAX98396_PVDD_UVLO_RESTART_SHFT, 1, 0), 1271b5858113SRyan Lee SOC_SINGLE("VBAT Auto Restart Switch", MAX98396_R210E_AUTO_RESTART, 1272b5858113SRyan Lee MAX98396_VBAT_UVLO_RESTART_SHFT, 1, 0), 1273b5858113SRyan Lee SOC_SINGLE("THERM Auto Restart Switch", MAX98396_R210E_AUTO_RESTART, 1274b5858113SRyan Lee MAX98396_THEM_SHDN_RESTART_SHFT, 1, 0), 1275b5858113SRyan Lee SOC_SINGLE("OVC Auto Restart Switch", MAX98396_R210E_AUTO_RESTART, 1276b5858113SRyan Lee MAX98396_OVC_RESTART_SHFT, 1, 0), 1277b5858113SRyan Lee /* Thermal Threshold */ 1278b5858113SRyan Lee SOC_ENUM("THERM Thresh1", max98396_thermal_warn_thresh1_enum), 1279b5858113SRyan Lee SOC_ENUM("THERM Thresh2", max98396_thermal_warn_thresh2_enum), 1280b5858113SRyan Lee SOC_ENUM("THERM SHDN Thresh", max98396_thermal_shdn_thresh_enum), 1281b5858113SRyan Lee SOC_ENUM("THERM Hysteresis", max98396_thermal_hysteresis_enum), 1282b5858113SRyan Lee SOC_SINGLE("THERM Foldback Switch", 1283b5858113SRyan Lee MAX98396_R2027_THERM_FOLDBACK_EN, 0, 1, 0), 1284b5858113SRyan Lee SOC_ENUM("THERM Slope1", max98396_thermal_fb_slope1_enum), 1285b5858113SRyan Lee SOC_ENUM("THERM Slope2", max98396_thermal_fb_slope2_enum), 1286b5858113SRyan Lee SOC_ENUM("THERM Release", max98396_thermal_fb_reltime_enum), 1287b5858113SRyan Lee SOC_ENUM("THERM Hold", max98396_thermal_fb_holdtime_enum), 1288b5858113SRyan Lee /* ADC */ 1289b5858113SRyan Lee SOC_SINGLE_EXT("ADC PVDD", MAX98396_R20B6_ADC_PVDD_READBACK_MSB, 0, 0x1FF, 0, 1290b5858113SRyan Lee max98396_adc_value_get, NULL), 1291b5858113SRyan Lee SOC_SINGLE_EXT("ADC VBAT", MAX98396_R20B8_ADC_VBAT_READBACK_MSB, 0, 0x1FF, 0, 1292b5858113SRyan Lee max98396_adc_value_get, NULL), 1293b5858113SRyan Lee SOC_SINGLE_EXT("ADC TEMP", MAX98396_R20BA_ADC_TEMP_READBACK_MSB, 0, 0x1FF, 0, 1294b5858113SRyan Lee max98396_adc_value_get, NULL), 1295b5858113SRyan Lee }; 1296b5858113SRyan Lee 1297b5858113SRyan Lee static const struct snd_soc_dapm_route max98396_audio_map[] = { 1298b5858113SRyan Lee /* Plabyack */ 1299b5858113SRyan Lee {"DAI Sel Mux", "Left", "Amp Enable"}, 1300b5858113SRyan Lee {"DAI Sel Mux", "Right", "Amp Enable"}, 1301b5858113SRyan Lee {"DAI Sel Mux", "LeftRight", "Amp Enable"}, 1302b5858113SRyan Lee {"BE_OUT", NULL, "DAI Sel Mux"}, 1303b5858113SRyan Lee /* Capture */ 1304b5858113SRyan Lee { "VI Sense", "Switch", "VMON" }, 1305b5858113SRyan Lee { "VI Sense", "Switch", "IMON" }, 1306b5858113SRyan Lee { "Voltage Sense", NULL, "VI Sense" }, 1307b5858113SRyan Lee { "Current Sense", NULL, "VI Sense" }, 1308b5858113SRyan Lee }; 1309b5858113SRyan Lee 1310b5858113SRyan Lee static struct snd_soc_dai_driver max98396_dai[] = { 1311b5858113SRyan Lee { 1312b5858113SRyan Lee .name = "max98396-aif1", 1313b5858113SRyan Lee .playback = { 1314b5858113SRyan Lee .stream_name = "HiFi Playback", 1315b5858113SRyan Lee .channels_min = 1, 1316b5858113SRyan Lee .channels_max = 2, 1317b5858113SRyan Lee .rates = MAX98396_RATES, 1318b5858113SRyan Lee .formats = MAX98396_FORMATS, 1319b5858113SRyan Lee }, 1320b5858113SRyan Lee .capture = { 1321b5858113SRyan Lee .stream_name = "HiFi Capture", 1322b5858113SRyan Lee .channels_min = 1, 1323b5858113SRyan Lee .channels_max = 2, 1324b5858113SRyan Lee .rates = MAX98396_RATES, 1325b5858113SRyan Lee .formats = MAX98396_FORMATS, 1326b5858113SRyan Lee }, 1327b5858113SRyan Lee .ops = &max98396_dai_ops, 1328b5858113SRyan Lee } 1329b5858113SRyan Lee }; 1330b5858113SRyan Lee 1331b5858113SRyan Lee static struct snd_soc_dai_driver max98397_dai[] = { 1332b5858113SRyan Lee { 1333b5858113SRyan Lee .name = "max98397-aif1", 1334b5858113SRyan Lee .playback = { 1335b5858113SRyan Lee .stream_name = "HiFi Playback", 1336b5858113SRyan Lee .channels_min = 1, 1337b5858113SRyan Lee .channels_max = 2, 1338b5858113SRyan Lee .rates = MAX98396_RATES, 1339b5858113SRyan Lee .formats = MAX98396_FORMATS, 1340b5858113SRyan Lee }, 1341b5858113SRyan Lee .capture = { 1342b5858113SRyan Lee .stream_name = "HiFi Capture", 1343b5858113SRyan Lee .channels_min = 1, 1344b5858113SRyan Lee .channels_max = 2, 1345b5858113SRyan Lee .rates = MAX98396_RATES, 1346b5858113SRyan Lee .formats = MAX98396_FORMATS, 1347b5858113SRyan Lee }, 1348b5858113SRyan Lee .ops = &max98396_dai_ops, 1349b5858113SRyan Lee } 1350b5858113SRyan Lee }; 1351b5858113SRyan Lee 1352b5858113SRyan Lee static void max98396_reset(struct max98396_priv *max98396, struct device *dev) 1353b5858113SRyan Lee { 1354b5858113SRyan Lee int ret, reg, count; 1355b5858113SRyan Lee 1356b5858113SRyan Lee /* Software Reset */ 1357b5858113SRyan Lee ret = regmap_write(max98396->regmap, 1358b5858113SRyan Lee MAX98396_R2000_SW_RESET, 1); 1359b5858113SRyan Lee if (ret) 1360b5858113SRyan Lee dev_err(dev, "Reset command failed. (ret:%d)\n", ret); 1361b5858113SRyan Lee 1362b5858113SRyan Lee count = 0; 1363b5858113SRyan Lee while (count < 3) { 1364b5858113SRyan Lee usleep_range(5000, 6000); 1365b5858113SRyan Lee /* Software Reset Verification */ 1366b5858113SRyan Lee ret = regmap_read(max98396->regmap, 1367b5858113SRyan Lee GET_REG_ADDR_REV_ID(max98396->device_id), ®); 1368b5858113SRyan Lee if (!ret) { 1369b5858113SRyan Lee dev_info(dev, "Reset completed (retry:%d)\n", count); 1370b5858113SRyan Lee return; 1371b5858113SRyan Lee } 1372b5858113SRyan Lee count++; 1373b5858113SRyan Lee } 1374b5858113SRyan Lee dev_err(dev, "Reset failed. (ret:%d)\n", ret); 1375b5858113SRyan Lee } 1376b5858113SRyan Lee 1377b5858113SRyan Lee static int max98396_probe(struct snd_soc_component *component) 1378b5858113SRyan Lee { 1379b5858113SRyan Lee struct max98396_priv *max98396 = 1380b5858113SRyan Lee snd_soc_component_get_drvdata(component); 1381b5858113SRyan Lee 1382b5858113SRyan Lee /* Software Reset */ 1383b5858113SRyan Lee max98396_reset(max98396, component->dev); 1384b5858113SRyan Lee 1385b5858113SRyan Lee /* L/R mix configuration */ 1386b5858113SRyan Lee if (max98396->device_id == CODEC_TYPE_MAX98396) { 1387b5858113SRyan Lee regmap_write(max98396->regmap, 1388b5858113SRyan Lee MAX98396_R2055_PCM_RX_SRC1, 0x02); 1389b5858113SRyan Lee regmap_write(max98396->regmap, 1390b5858113SRyan Lee MAX98396_R2056_PCM_RX_SRC2, 0x10); 1391b5858113SRyan Lee } else { 1392b5858113SRyan Lee regmap_write(max98396->regmap, 1393b5858113SRyan Lee MAX98397_R2056_PCM_RX_SRC1, 0x02); 1394b5858113SRyan Lee regmap_write(max98396->regmap, 1395b5858113SRyan Lee MAX98397_R2057_PCM_RX_SRC2, 0x10); 1396b5858113SRyan Lee } 1397703ee055SDaniel Mack /* Supply control */ 1398703ee055SDaniel Mack regmap_update_bits(max98396->regmap, 1399703ee055SDaniel Mack MAX98396_R20A0_AMP_SUPPLY_CTL, 1400703ee055SDaniel Mack MAX98396_AMP_SUPPLY_NOVBAT, 1401703ee055SDaniel Mack (max98396->vbat == NULL) ? 1402703ee055SDaniel Mack MAX98396_AMP_SUPPLY_NOVBAT : 0); 1403b5858113SRyan Lee /* Enable DC blocker */ 1404b5858113SRyan Lee regmap_update_bits(max98396->regmap, 1405b5858113SRyan Lee MAX98396_R2092_AMP_DSP_CFG, 1, 1); 1406b5858113SRyan Lee /* Enable IV Monitor DC blocker */ 1407b5858113SRyan Lee regmap_update_bits(max98396->regmap, 1408b5858113SRyan Lee MAX98396_R20E0_IV_SENSE_PATH_CFG, 1409b5858113SRyan Lee MAX98396_IV_SENSE_DCBLK_EN_MASK, 1410b5858113SRyan Lee MAX98396_IV_SENSE_DCBLK_EN_MASK); 1411b5858113SRyan Lee /* Configure default data output sources */ 1412b5858113SRyan Lee regmap_write(max98396->regmap, 1413b5858113SRyan Lee MAX98396_R205D_PCM_TX_SRC_EN, 3); 1414b5858113SRyan Lee /* Enable Wideband Filter */ 1415b5858113SRyan Lee regmap_update_bits(max98396->regmap, 1416b5858113SRyan Lee MAX98396_R2092_AMP_DSP_CFG, 0x40, 0x40); 1417b5858113SRyan Lee /* Enable IV Wideband Filter */ 1418b5858113SRyan Lee regmap_update_bits(max98396->regmap, 1419b5858113SRyan Lee MAX98396_R20E0_IV_SENSE_PATH_CFG, 8, 8); 1420b5858113SRyan Lee 1421b5858113SRyan Lee /* Enable Bypass Source */ 1422b5858113SRyan Lee regmap_write(max98396->regmap, 1423b5858113SRyan Lee MAX98396_R2058_PCM_BYPASS_SRC, 1424b5858113SRyan Lee max98396->bypass_slot); 1425b5858113SRyan Lee /* Voltage, current slot configuration */ 1426b5858113SRyan Lee regmap_write(max98396->regmap, 1427b5858113SRyan Lee MAX98396_R2044_PCM_TX_CTRL_1, 1428b5858113SRyan Lee max98396->v_slot); 1429b5858113SRyan Lee regmap_write(max98396->regmap, 1430b5858113SRyan Lee MAX98396_R2045_PCM_TX_CTRL_2, 1431b5858113SRyan Lee max98396->i_slot); 1432f42924b4SDaniel Mack regmap_write(max98396->regmap, 1433f42924b4SDaniel Mack MAX98396_R204A_PCM_TX_CTRL_7, 1434f42924b4SDaniel Mack max98396->spkfb_slot); 1435b5858113SRyan Lee 1436b5858113SRyan Lee if (max98396->v_slot < 8) 1437b5858113SRyan Lee if (max98396->device_id == CODEC_TYPE_MAX98396) 1438b5858113SRyan Lee regmap_update_bits(max98396->regmap, 1439b5858113SRyan Lee MAX98396_R2053_PCM_TX_HIZ_CTRL_8, 1440b5858113SRyan Lee 1 << max98396->v_slot, 0); 1441b5858113SRyan Lee else 1442b5858113SRyan Lee regmap_update_bits(max98396->regmap, 1443b5858113SRyan Lee MAX98397_R2054_PCM_TX_HIZ_CTRL_8, 1444b5858113SRyan Lee 1 << max98396->v_slot, 0); 1445b5858113SRyan Lee else 1446b5858113SRyan Lee if (max98396->device_id == CODEC_TYPE_MAX98396) 1447b5858113SRyan Lee regmap_update_bits(max98396->regmap, 1448b5858113SRyan Lee MAX98396_R2052_PCM_TX_HIZ_CTRL_7, 1449b5858113SRyan Lee 1 << (max98396->v_slot - 8), 0); 1450b5858113SRyan Lee else 1451b5858113SRyan Lee regmap_update_bits(max98396->regmap, 1452b5858113SRyan Lee MAX98397_R2053_PCM_TX_HIZ_CTRL_7, 1453b5858113SRyan Lee 1 << (max98396->v_slot - 8), 0); 1454b5858113SRyan Lee 1455b5858113SRyan Lee if (max98396->i_slot < 8) 1456b5858113SRyan Lee if (max98396->device_id == CODEC_TYPE_MAX98396) 1457b5858113SRyan Lee regmap_update_bits(max98396->regmap, 1458b5858113SRyan Lee MAX98396_R2053_PCM_TX_HIZ_CTRL_8, 1459b5858113SRyan Lee 1 << max98396->i_slot, 0); 1460b5858113SRyan Lee else 1461b5858113SRyan Lee regmap_update_bits(max98396->regmap, 1462b5858113SRyan Lee MAX98397_R2054_PCM_TX_HIZ_CTRL_8, 1463b5858113SRyan Lee 1 << max98396->i_slot, 0); 1464b5858113SRyan Lee else 1465b5858113SRyan Lee if (max98396->device_id == CODEC_TYPE_MAX98396) 1466b5858113SRyan Lee regmap_update_bits(max98396->regmap, 1467b5858113SRyan Lee MAX98396_R2052_PCM_TX_HIZ_CTRL_7, 1468b5858113SRyan Lee 1 << (max98396->i_slot - 8), 0); 1469b5858113SRyan Lee else 1470b5858113SRyan Lee regmap_update_bits(max98396->regmap, 1471b5858113SRyan Lee MAX98397_R2053_PCM_TX_HIZ_CTRL_7, 1472b5858113SRyan Lee 1 << (max98396->i_slot - 8), 0); 1473b5858113SRyan Lee 1474b5858113SRyan Lee /* Set interleave mode */ 1475b5858113SRyan Lee if (max98396->interleave_mode) 1476b5858113SRyan Lee regmap_update_bits(max98396->regmap, 1477b5858113SRyan Lee MAX98396_R2041_PCM_MODE_CFG, 1478b5858113SRyan Lee MAX98396_PCM_TX_CH_INTERLEAVE_MASK, 1479b5858113SRyan Lee MAX98396_PCM_TX_CH_INTERLEAVE_MASK); 1480b5858113SRyan Lee 1481b5858113SRyan Lee regmap_update_bits(max98396->regmap, 1482b5858113SRyan Lee MAX98396_R2038_CLK_MON_CTRL, 1483b5858113SRyan Lee MAX98396_CLK_MON_AUTO_RESTART_MASK, 1484b5858113SRyan Lee MAX98396_CLK_MON_AUTO_RESTART_MASK); 1485b5858113SRyan Lee 1486b5858113SRyan Lee /* Speaker Amplifier PCM RX Enable by default */ 1487b5858113SRyan Lee regmap_update_bits(max98396->regmap, 1488b5858113SRyan Lee MAX98396_R205E_PCM_RX_EN, 1489b5858113SRyan Lee MAX98396_PCM_RX_EN_MASK, 1); 1490b5858113SRyan Lee 1491b5858113SRyan Lee return 0; 1492b5858113SRyan Lee } 1493b5858113SRyan Lee 1494b5858113SRyan Lee #ifdef CONFIG_PM_SLEEP 1495b5858113SRyan Lee static int max98396_suspend(struct device *dev) 1496b5858113SRyan Lee { 1497b5858113SRyan Lee struct max98396_priv *max98396 = dev_get_drvdata(dev); 1498b5858113SRyan Lee 1499b5858113SRyan Lee regcache_cache_only(max98396->regmap, true); 1500b5858113SRyan Lee regcache_mark_dirty(max98396->regmap); 1501703ee055SDaniel Mack regulator_bulk_disable(MAX98396_NUM_CORE_SUPPLIES, 1502703ee055SDaniel Mack max98396->core_supplies); 1503703ee055SDaniel Mack if (max98396->pvdd) 1504703ee055SDaniel Mack regulator_disable(max98396->pvdd); 1505703ee055SDaniel Mack 1506703ee055SDaniel Mack if (max98396->vbat) 1507703ee055SDaniel Mack regulator_disable(max98396->vbat); 1508703ee055SDaniel Mack 1509b5858113SRyan Lee return 0; 1510b5858113SRyan Lee } 1511b5858113SRyan Lee 1512b5858113SRyan Lee static int max98396_resume(struct device *dev) 1513b5858113SRyan Lee { 1514b5858113SRyan Lee struct max98396_priv *max98396 = dev_get_drvdata(dev); 1515703ee055SDaniel Mack int ret; 1516703ee055SDaniel Mack 1517703ee055SDaniel Mack ret = regulator_bulk_enable(MAX98396_NUM_CORE_SUPPLIES, 1518703ee055SDaniel Mack max98396->core_supplies); 1519703ee055SDaniel Mack if (ret < 0) 1520703ee055SDaniel Mack return ret; 1521703ee055SDaniel Mack 1522703ee055SDaniel Mack if (max98396->pvdd) { 1523703ee055SDaniel Mack ret = regulator_enable(max98396->pvdd); 1524703ee055SDaniel Mack if (ret < 0) 1525703ee055SDaniel Mack return ret; 1526703ee055SDaniel Mack } 1527703ee055SDaniel Mack 1528703ee055SDaniel Mack if (max98396->vbat) { 1529703ee055SDaniel Mack ret = regulator_enable(max98396->vbat); 1530703ee055SDaniel Mack if (ret < 0) 1531703ee055SDaniel Mack return ret; 1532703ee055SDaniel Mack } 1533b5858113SRyan Lee 1534b5858113SRyan Lee regcache_cache_only(max98396->regmap, false); 1535b5858113SRyan Lee max98396_reset(max98396, dev); 1536b5858113SRyan Lee regcache_sync(max98396->regmap); 1537b5858113SRyan Lee return 0; 1538b5858113SRyan Lee } 1539b5858113SRyan Lee #endif 1540b5858113SRyan Lee 1541b5858113SRyan Lee static const struct dev_pm_ops max98396_pm = { 1542b5858113SRyan Lee SET_SYSTEM_SLEEP_PM_OPS(max98396_suspend, max98396_resume) 1543b5858113SRyan Lee }; 1544b5858113SRyan Lee 1545b5858113SRyan Lee static const struct snd_soc_component_driver soc_codec_dev_max98396 = { 1546b5858113SRyan Lee .probe = max98396_probe, 1547b5858113SRyan Lee .controls = max98396_snd_controls, 1548b5858113SRyan Lee .num_controls = ARRAY_SIZE(max98396_snd_controls), 1549b5858113SRyan Lee .dapm_widgets = max98396_dapm_widgets, 1550b5858113SRyan Lee .num_dapm_widgets = ARRAY_SIZE(max98396_dapm_widgets), 1551b5858113SRyan Lee .dapm_routes = max98396_audio_map, 1552b5858113SRyan Lee .num_dapm_routes = ARRAY_SIZE(max98396_audio_map), 1553b5858113SRyan Lee .idle_bias_on = 1, 1554b5858113SRyan Lee .use_pmdown_time = 1, 1555b5858113SRyan Lee .endianness = 1, 1556b5858113SRyan Lee .non_legacy_dai_naming = 1, 1557b5858113SRyan Lee }; 1558b5858113SRyan Lee 1559b5858113SRyan Lee static const struct snd_soc_component_driver soc_codec_dev_max98397 = { 1560b5858113SRyan Lee .probe = max98396_probe, 1561b5858113SRyan Lee .controls = max98397_snd_controls, 1562b5858113SRyan Lee .num_controls = ARRAY_SIZE(max98397_snd_controls), 1563b5858113SRyan Lee .dapm_widgets = max98396_dapm_widgets, 1564b5858113SRyan Lee .num_dapm_widgets = ARRAY_SIZE(max98396_dapm_widgets), 1565b5858113SRyan Lee .dapm_routes = max98396_audio_map, 1566b5858113SRyan Lee .num_dapm_routes = ARRAY_SIZE(max98396_audio_map), 1567b5858113SRyan Lee .idle_bias_on = 1, 1568b5858113SRyan Lee .use_pmdown_time = 1, 1569b5858113SRyan Lee .endianness = 1, 1570b5858113SRyan Lee .non_legacy_dai_naming = 1, 1571b5858113SRyan Lee }; 1572b5858113SRyan Lee 1573b5858113SRyan Lee static const struct regmap_config max98396_regmap = { 1574b5858113SRyan Lee .reg_bits = 16, 1575b5858113SRyan Lee .val_bits = 8, 1576b5858113SRyan Lee .max_register = MAX98396_R21FF_REVISION_ID, 1577b5858113SRyan Lee .reg_defaults = max98396_reg, 1578b5858113SRyan Lee .num_reg_defaults = ARRAY_SIZE(max98396_reg), 1579b5858113SRyan Lee .readable_reg = max98396_readable_register, 1580b5858113SRyan Lee .volatile_reg = max98396_volatile_reg, 1581b5858113SRyan Lee .cache_type = REGCACHE_RBTREE, 1582b5858113SRyan Lee }; 1583b5858113SRyan Lee 1584b5858113SRyan Lee static const struct regmap_config max98397_regmap = { 1585b5858113SRyan Lee .reg_bits = 16, 1586b5858113SRyan Lee .val_bits = 8, 1587b5858113SRyan Lee .max_register = MAX98397_R22FF_REVISION_ID, 1588b5858113SRyan Lee .reg_defaults = max98397_reg, 1589b5858113SRyan Lee .num_reg_defaults = ARRAY_SIZE(max98397_reg), 1590b5858113SRyan Lee .readable_reg = max98397_readable_register, 1591b5858113SRyan Lee .volatile_reg = max98397_volatile_reg, 1592b5858113SRyan Lee .cache_type = REGCACHE_RBTREE, 1593b5858113SRyan Lee }; 1594b5858113SRyan Lee 1595b5858113SRyan Lee static void max98396_read_device_property(struct device *dev, 1596b5858113SRyan Lee struct max98396_priv *max98396) 1597b5858113SRyan Lee { 1598b5858113SRyan Lee int value; 1599b5858113SRyan Lee 1600b5858113SRyan Lee if (!device_property_read_u32(dev, "adi,vmon-slot-no", &value)) 1601b5858113SRyan Lee max98396->v_slot = value & 0xF; 1602b5858113SRyan Lee else 1603b5858113SRyan Lee max98396->v_slot = 0; 1604b5858113SRyan Lee 1605b5858113SRyan Lee if (!device_property_read_u32(dev, "adi,imon-slot-no", &value)) 1606b5858113SRyan Lee max98396->i_slot = value & 0xF; 1607b5858113SRyan Lee else 1608b5858113SRyan Lee max98396->i_slot = 1; 1609b5858113SRyan Lee 1610f42924b4SDaniel Mack if (!device_property_read_u32(dev, "adi,spkfb-slot-no", &value)) 1611f42924b4SDaniel Mack max98396->spkfb_slot = value & 0xF; 1612f42924b4SDaniel Mack else 1613f42924b4SDaniel Mack max98396->spkfb_slot = 2; 1614f42924b4SDaniel Mack 1615b5858113SRyan Lee if (!device_property_read_u32(dev, "adi,bypass-slot-no", &value)) 1616b5858113SRyan Lee max98396->bypass_slot = value & 0xF; 1617b5858113SRyan Lee else 1618b5858113SRyan Lee max98396->bypass_slot = 0; 1619b5858113SRyan Lee } 1620b5858113SRyan Lee 1621703ee055SDaniel Mack static void max98396_core_supplies_disable(void *priv) 1622703ee055SDaniel Mack { 1623703ee055SDaniel Mack struct max98396_priv *max98396 = priv; 1624703ee055SDaniel Mack 1625703ee055SDaniel Mack regulator_bulk_disable(MAX98396_NUM_CORE_SUPPLIES, 1626703ee055SDaniel Mack max98396->core_supplies); 1627703ee055SDaniel Mack } 1628703ee055SDaniel Mack 1629703ee055SDaniel Mack static void max98396_supply_disable(void *r) 1630703ee055SDaniel Mack { 1631703ee055SDaniel Mack regulator_disable((struct regulator *) r); 1632703ee055SDaniel Mack } 1633703ee055SDaniel Mack 1634b5858113SRyan Lee static int max98396_i2c_probe(struct i2c_client *i2c, 1635b5858113SRyan Lee const struct i2c_device_id *id) 1636b5858113SRyan Lee { 1637b5858113SRyan Lee struct max98396_priv *max98396 = NULL; 1638703ee055SDaniel Mack int i, ret, reg; 1639b5858113SRyan Lee 1640b5858113SRyan Lee max98396 = devm_kzalloc(&i2c->dev, sizeof(*max98396), GFP_KERNEL); 1641b5858113SRyan Lee 1642b5858113SRyan Lee if (!max98396) { 1643b5858113SRyan Lee ret = -ENOMEM; 1644b5858113SRyan Lee return ret; 1645b5858113SRyan Lee } 1646b5858113SRyan Lee i2c_set_clientdata(i2c, max98396); 1647b5858113SRyan Lee 1648b5858113SRyan Lee max98396->device_id = id->driver_data; 1649b5858113SRyan Lee 1650b5858113SRyan Lee /* regmap initialization */ 1651b5858113SRyan Lee if (max98396->device_id == CODEC_TYPE_MAX98396) 1652b5858113SRyan Lee max98396->regmap = devm_regmap_init_i2c(i2c, &max98396_regmap); 1653b5858113SRyan Lee 1654b5858113SRyan Lee else 1655b5858113SRyan Lee max98396->regmap = devm_regmap_init_i2c(i2c, &max98397_regmap); 1656b5858113SRyan Lee 1657b5858113SRyan Lee if (IS_ERR(max98396->regmap)) { 1658b5858113SRyan Lee ret = PTR_ERR(max98396->regmap); 1659b5858113SRyan Lee dev_err(&i2c->dev, 1660b5858113SRyan Lee "Failed to allocate regmap: %d\n", ret); 1661b5858113SRyan Lee return ret; 1662b5858113SRyan Lee } 1663b5858113SRyan Lee 1664703ee055SDaniel Mack /* Obtain regulator supplies */ 1665703ee055SDaniel Mack for (i = 0; i < MAX98396_NUM_CORE_SUPPLIES; i++) 1666703ee055SDaniel Mack max98396->core_supplies[i].supply = max98396_core_supplies[i]; 1667703ee055SDaniel Mack 1668703ee055SDaniel Mack ret = devm_regulator_bulk_get(&i2c->dev, MAX98396_NUM_CORE_SUPPLIES, 1669703ee055SDaniel Mack max98396->core_supplies); 1670703ee055SDaniel Mack if (ret < 0) { 1671703ee055SDaniel Mack dev_err(&i2c->dev, "Failed to request core supplies: %d\n", ret); 1672703ee055SDaniel Mack return ret; 1673703ee055SDaniel Mack } 1674703ee055SDaniel Mack 1675703ee055SDaniel Mack max98396->vbat = devm_regulator_get_optional(&i2c->dev, "vbat"); 1676703ee055SDaniel Mack if (IS_ERR(max98396->vbat)) { 1677703ee055SDaniel Mack if (PTR_ERR(max98396->vbat) == -EPROBE_DEFER) 1678703ee055SDaniel Mack return -EPROBE_DEFER; 1679703ee055SDaniel Mack 1680703ee055SDaniel Mack max98396->vbat = NULL; 1681703ee055SDaniel Mack } 1682703ee055SDaniel Mack 1683703ee055SDaniel Mack max98396->pvdd = devm_regulator_get_optional(&i2c->dev, "pvdd"); 1684703ee055SDaniel Mack if (IS_ERR(max98396->pvdd)) { 1685703ee055SDaniel Mack if (PTR_ERR(max98396->pvdd) == -EPROBE_DEFER) 1686703ee055SDaniel Mack return -EPROBE_DEFER; 1687703ee055SDaniel Mack 1688703ee055SDaniel Mack max98396->pvdd = NULL; 1689703ee055SDaniel Mack } 1690703ee055SDaniel Mack 1691703ee055SDaniel Mack ret = regulator_bulk_enable(MAX98396_NUM_CORE_SUPPLIES, 1692703ee055SDaniel Mack max98396->core_supplies); 1693703ee055SDaniel Mack if (ret < 0) { 1694703ee055SDaniel Mack dev_err(&i2c->dev, "Unable to enable core supplies: %d", ret); 1695703ee055SDaniel Mack return ret; 1696703ee055SDaniel Mack } 1697703ee055SDaniel Mack 1698703ee055SDaniel Mack ret = devm_add_action_or_reset(&i2c->dev, max98396_core_supplies_disable, 1699703ee055SDaniel Mack max98396); 1700703ee055SDaniel Mack if (ret < 0) 1701703ee055SDaniel Mack return ret; 1702703ee055SDaniel Mack 1703703ee055SDaniel Mack if (max98396->pvdd) { 1704703ee055SDaniel Mack ret = regulator_enable(max98396->pvdd); 1705703ee055SDaniel Mack if (ret < 0) 1706703ee055SDaniel Mack return ret; 1707703ee055SDaniel Mack 1708703ee055SDaniel Mack ret = devm_add_action_or_reset(&i2c->dev, 1709703ee055SDaniel Mack max98396_supply_disable, 1710703ee055SDaniel Mack max98396->pvdd); 1711703ee055SDaniel Mack if (ret < 0) 1712703ee055SDaniel Mack return ret; 1713703ee055SDaniel Mack } 1714703ee055SDaniel Mack 1715703ee055SDaniel Mack if (max98396->vbat) { 1716703ee055SDaniel Mack ret = regulator_enable(max98396->vbat); 1717703ee055SDaniel Mack if (ret < 0) 1718703ee055SDaniel Mack return ret; 1719703ee055SDaniel Mack 1720703ee055SDaniel Mack ret = devm_add_action_or_reset(&i2c->dev, 1721703ee055SDaniel Mack max98396_supply_disable, 1722703ee055SDaniel Mack max98396->vbat); 1723703ee055SDaniel Mack if (ret < 0) 1724703ee055SDaniel Mack return ret; 1725703ee055SDaniel Mack } 1726703ee055SDaniel Mack 1727b5858113SRyan Lee /* update interleave mode info */ 1728b5858113SRyan Lee if (device_property_read_bool(&i2c->dev, "adi,interleave_mode")) 1729b5858113SRyan Lee max98396->interleave_mode = true; 1730b5858113SRyan Lee else 1731b5858113SRyan Lee max98396->interleave_mode = false; 1732b5858113SRyan Lee 1733b5858113SRyan Lee /* voltage/current slot & gpio configuration */ 1734b5858113SRyan Lee max98396_read_device_property(&i2c->dev, max98396); 1735b5858113SRyan Lee 1736b5858113SRyan Lee /* Reset the Device */ 1737b5858113SRyan Lee max98396->reset_gpio = devm_gpiod_get_optional(&i2c->dev, 1738b5858113SRyan Lee "reset", GPIOD_OUT_HIGH); 1739b5858113SRyan Lee if (IS_ERR(max98396->reset_gpio)) { 1740b5858113SRyan Lee ret = PTR_ERR(max98396->reset_gpio); 1741b5858113SRyan Lee dev_err(&i2c->dev, "Unable to request GPIO pin: %d.\n", ret); 1742b5858113SRyan Lee return ret; 1743b5858113SRyan Lee } 1744b5858113SRyan Lee 1745b5858113SRyan Lee if (max98396->reset_gpio) { 1746b5858113SRyan Lee usleep_range(5000, 6000); 1747b5858113SRyan Lee gpiod_set_value_cansleep(max98396->reset_gpio, 0); 1748b5858113SRyan Lee /* Wait for the hw reset done */ 1749b5858113SRyan Lee usleep_range(5000, 6000); 1750b5858113SRyan Lee } 1751b5858113SRyan Lee 1752b5858113SRyan Lee ret = regmap_read(max98396->regmap, 1753b5858113SRyan Lee GET_REG_ADDR_REV_ID(max98396->device_id), ®); 1754b5858113SRyan Lee if (ret < 0) { 1755b5858113SRyan Lee dev_err(&i2c->dev, "%s: failed to read revision of the device.\n", id->name); 1756b5858113SRyan Lee return ret; 1757b5858113SRyan Lee } 1758b5858113SRyan Lee dev_info(&i2c->dev, "%s revision ID: 0x%02X\n", id->name, reg); 1759b5858113SRyan Lee 1760b5858113SRyan Lee /* codec registration */ 1761b5858113SRyan Lee if (max98396->device_id == CODEC_TYPE_MAX98396) 1762b5858113SRyan Lee ret = devm_snd_soc_register_component(&i2c->dev, 1763b5858113SRyan Lee &soc_codec_dev_max98396, 1764b5858113SRyan Lee max98396_dai, 1765b5858113SRyan Lee ARRAY_SIZE(max98396_dai)); 1766b5858113SRyan Lee else 1767b5858113SRyan Lee ret = devm_snd_soc_register_component(&i2c->dev, 1768b5858113SRyan Lee &soc_codec_dev_max98397, 1769b5858113SRyan Lee max98397_dai, 1770b5858113SRyan Lee ARRAY_SIZE(max98397_dai)); 1771b5858113SRyan Lee if (ret < 0) 1772b5858113SRyan Lee dev_err(&i2c->dev, "Failed to register codec: %d\n", ret); 1773b5858113SRyan Lee 1774b5858113SRyan Lee return ret; 1775b5858113SRyan Lee } 1776b5858113SRyan Lee 1777b5858113SRyan Lee static const struct i2c_device_id max98396_i2c_id[] = { 1778b5858113SRyan Lee { "max98396", CODEC_TYPE_MAX98396}, 1779b5858113SRyan Lee { "max98397", CODEC_TYPE_MAX98397}, 1780b5858113SRyan Lee { }, 1781b5858113SRyan Lee }; 1782b5858113SRyan Lee 1783b5858113SRyan Lee MODULE_DEVICE_TABLE(i2c, max98396_i2c_id); 1784b5858113SRyan Lee 1785b5858113SRyan Lee #if defined(CONFIG_OF) 1786b5858113SRyan Lee static const struct of_device_id max98396_of_match[] = { 1787b5858113SRyan Lee { .compatible = "adi,max98396", }, 1788b5858113SRyan Lee { .compatible = "adi,max98397", }, 1789b5858113SRyan Lee { } 1790b5858113SRyan Lee }; 1791b5858113SRyan Lee MODULE_DEVICE_TABLE(of, max98396_of_match); 1792b5858113SRyan Lee #endif 1793b5858113SRyan Lee 1794b5858113SRyan Lee #ifdef CONFIG_ACPI 1795b5858113SRyan Lee static const struct acpi_device_id max98396_acpi_match[] = { 1796b5858113SRyan Lee { "ADS8396", 0 }, 1797b5858113SRyan Lee { "ADS8397", 0 }, 1798b5858113SRyan Lee {}, 1799b5858113SRyan Lee }; 1800b5858113SRyan Lee MODULE_DEVICE_TABLE(acpi, max98396_acpi_match); 1801b5858113SRyan Lee #endif 1802b5858113SRyan Lee 1803b5858113SRyan Lee static struct i2c_driver max98396_i2c_driver = { 1804b5858113SRyan Lee .driver = { 1805b5858113SRyan Lee .name = "max98396", 1806b5858113SRyan Lee .of_match_table = of_match_ptr(max98396_of_match), 1807b5858113SRyan Lee .acpi_match_table = ACPI_PTR(max98396_acpi_match), 1808b5858113SRyan Lee .pm = &max98396_pm, 1809b5858113SRyan Lee }, 1810b5858113SRyan Lee .probe = max98396_i2c_probe, 1811b5858113SRyan Lee .id_table = max98396_i2c_id, 1812b5858113SRyan Lee }; 1813b5858113SRyan Lee 1814b5858113SRyan Lee module_i2c_driver(max98396_i2c_driver) 1815b5858113SRyan Lee 1816b5858113SRyan Lee MODULE_DESCRIPTION("ALSA SoC MAX98396 driver"); 1817b5858113SRyan Lee MODULE_AUTHOR("Ryan Lee <ryans.lee@analog.com>"); 1818b5858113SRyan Lee MODULE_LICENSE("GPL"); 1819